uox3/source/MultiMul.cpp
Xoduz 667f948be3 0.99.6-RC6x
Added dummy context restore function to additional scripts
Updated 'go command to support specifying location to teleport to by name, mapped to locations from locations.dfn (Thanks Dragon Slayer!)
Updated Smart Turn script for furniture (js/server/misc/furniture_smartturn.js) with more optimized code (Humility)
Fixed latitude/longitude output of GetMapCoordinates helper function (js/server/data/map_coordinates.js), and updated scripts that relied on it
Fixed an issue where trying to craft fletching tools would produce hatchets instead (js/skill/craft/fletching.js)
Updated js/item/bankcheck.js to display value of checks using onTooltip JS Event, or onNameRequest JS Event if tooltips are disabled
Fixed a couple of DFN formatting issues (thanks, punt)
Fixed an issue where blank deeds (and bank checks) would be pileable if dropped on the same container (dfndata/items/tools/inscription.dfn)
Added dedicated [bankcheck] DFN item (dfndata/items/misc/money.dfn)
Updated Banker AI script (js/npc/ai/banker.js) to use dedicated [bankcheck] item instead of blank deeds as base for bank checks, and to have banker NPCs pause and turn towards player when talked to
Fixed an issue with script for Healing/Veterinary (js/skill/healing.js) which incorrectly used Anatomy as supplementary skill for Veterinary instead of Animal Lore, and which checked dex of wrong character when calculating healing slips
Added two missing tile flags to tileflag enum that threw order of such flags added with HS expansion out of order (thanks, punt)
Fixed an issue with travel-commands in GM menu which handled travelling between facets incorrectly
Added region spawners for dungeons, towns and overworld in Ilshenar facet
Enabled Trammel and Ilshenar facet decorations/spawns by default in admin welcome script (js/server/misc/admin_welcome.js)
Reworked portions of admin welcome gump to display optional "addon" decorations per facet, which might be client/era-specific (js/server/misc/admin_welcome.js)
Added new NPCs to dfndata/npc/femalehuman.dfn: f_executioner, f_chaosdragoon, f_chaosdragoonelite, f_gypsybanker
Added new NPCs to dfndata/npc/femalevendors.dfn: f_gypsymaiden, f_gypsyanimaltrainer, f_gypsyfortuneteller, f_vagabond, f_ironworker
Added new NPCs to dfndata/npc/malehuman.dfn: m_executioner, m_chaosdragoon, m_chaosdragoonelite, m_gypsybanker
Added new NPCs to dfndata/npc/malevendors.dfn: m_gypsyanimaltrainer, m_vagabond, m_ironworker
Added new NPC to dfndata/npc/miscmonsters.dfn: darkwisp
Added new NPC to dfndata/npc/undead.dfn: ancientlich
Added new Item DFNs for "camps" that when spawned will create a camp with specific decorations ([ilsh_orc_camp], [ilsh_healer_camp], [ilsh_mage_camp], [ilsh_banker_camp])
Added scripts for camps (js/item/camps/ilsh_banker_camp.js, js/item/camps/ilsh_healer_camp.js, js/item/camps/ilsh_mage_camp.js, js/item/camps/ilsh_orc_camp.js)
Added new colorlist to dfndata/colors/colors.dfn: [RANDOMCOLOR 33] (Bright Primary Colors)
Fixed an issue with gargish cloth chest DFN which prevented LBR version from working properly (dfndata/items/gear/armor/gargish_armor/gargish_cloth.dfn)
Added a bunch of new NPCLISTS in various npclist DFN files to support regional spawns in Ilshenar
Added missing BACKPACK tag to [golem] NPC DFN (dfndata/npc/clockwork.dfn)
Fixed misspelled section header for Fire Elemental NPC - from firele to fireele (dfndata/npc/elementals.dfn)
Murderous brigand NPCs are no longer willing to teach players skills (dfndata/npc/femalehuman.dfn, dfndata/npc/malehuman.dfn)
Corrected coordinates of Rock Dungeon region (dfndata/regions/regions.dfn)
Added regions for Sea Market (Felucca/Trammel), Blackthorn Dungeon (Felucca/Trammel) and Lakeshire (Ilshenar) (dfndata/regions/regions.dfn)
Fixed an issue with 'radditem and 'raddspawner GM commands which would not correctly set the Z of the added item/spawner to match target location (js/commands/custom/repeatingcmds.js)
Added two new repeating commands (js/commands/custom/repeatingcmds.js):
	'rmovable #	// Repeats bringing up targeting cursor to set movable property on multiple objects
	'rnodecay	// Repeats bringing up targeting cursor to set decayable property to false on multiple objects
Added new areacommand (js/commands/targeting/areacommand.js):
	'areacommand name [string]	// Sets name of all objects within targeted area to [string]
Updated 'decorate command script to better handle flags passed in via admin welcome script for things like facet addons (js/commands/decorate.js)
Updated fire breath script (js/npc/special/fire_breath.js) to get fire breath info per NPC based on their sectionID rather than their base body ID
Updated facet ruleset script (js/server/misc/facetRuleset.js) with an override for GMs trying to snoop players even in places where snooping is disallowed
Updated facet ruleset script (js/server/misc/facetRuleset.js) to allow damage that's not coming from a player/NPC source even in Trammel/Ilshenar
Added teleport locations for entering/leaving Blackthorn Dungeon in Felucca/Trammel (js/teleport.scp)
Updated 'remove and 'rremove commands to release any targeted objects from potential multis they are locked in to properly update lockdown count (js/commands/targeting/remove.js, js/commands/custom/repeatingcmds.js)
Updated felucca/ilshenar world templates with decorations (js/jsdata/worldtemplates/felucca_*/ilshenar_*)
Added world templates with decorations for Trammel (js/jsdata/worldtemplates/trammel_*)
Added DFN entry for Power Generators, and spawn entries for these in Ilshenar (dfndata/item/puzzles/puzzles.dfn, dfndata/spawn/ilshenar/spawn_ilshenar_world_general.dfn)
Added script for Power Generators, which initializes random puzzles on creation and rewards player with diamonds/arcane gems/shadow iron ore when solved, or lightning when failing to solve (js/item/power_generator.js)
Added support for overriding newbie-state of items added to players via dfndata/newbie/newbie.dfn. Supported syntax:
	PACKITEM=sectionID[, amount[, newbieFlag]] 	// To use newbieFlag with PACKITEM, amount must also be specified. Flag can be 0/1
	EQUIPITEM=sectionID[, itemHue[, newbieFlag]	// To use newbieFlag with EQUIPITEM, itemHue must also be specified. Flag can be 0/1
Casting the Earthquake spell will no longer affect the caster, or cause them to become criminal when cast out of town with no impacted targets
Fixed a bug where caster would remain frozen after finishing casting targetless spells like Earthquake
Fixed a bug where caster would remain frozen if spellcast was cancelled half-ways through by picking up or equipping an item
Fixed a bug where caster would remain frozen if spellcast was interrupted by losing concentration from taking melee damage in combat
Fixed a bug where a paralyzed player would remain frozen even if taking magic or poison damage, which releases them from paralyzis
Fixed a bug where target of Paralyze spell would not visually be shown as frozen in target's client
Fixed a bug where a caster frozen while casting a spell could become unfrozen mid-cast because of incoming magic damage
Address overflow issue in MultiMul.cpp (punt)
Address various cast issues (punt)
Corrected jscript project, to not include two files that where for stand alone programs (and resulted in main being added twice in the library (and once was incorrect all ready). (punt)
Replaced RoundNumber with std::round (punt)
The original physical appearance of characters targeted by 'make admin/gm/cns is now kept track of, and restored upon being targeted by 'make player
Fixed an issue where the .HasSpell JS Method was off by 1 when looking for specific spells in player's spellbook, due to 0-based array indexing in code vs 1-based indexing for Spells in DFNs
2023-10-14 05:03:53 +08:00

543 lines
22 KiB
C++

//
// Created on: 4/30/21
#include "MultiMul.hpp"
#include <cstdint>
#include <iostream>
#include <stdexcept>
#include <fstream>
#include <filesystem>
#include <algorithm>
#include <unordered_map>
#include "mapstuff.h"
using namespace std::string_literals;
//o------------------------------------------------------------------------------------------------o
// MultiItem_st
//o------------------------------------------------------------------------------------------------o
MultiItem_st::MultiItem_st() : tileId( 0xFFFF ), altitude( 0 ), offsetX( 0 ), offsetY( 0 ), flag( 0 )
{
info = nullptr;
}
//o------------------------------------------------------------------------------------------------o
// CollectionItem_st
//o------------------------------------------------------------------------------------------------o
//o------------------------------------------------------------------------------------------------o
//| Function - CollectionItem_st::ItemsAt()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Returns collection of items at given coordinates
//o------------------------------------------------------------------------------------------------o
auto CollectionItem_st::ItemsAt( int offsetX, int offsetY ) -> std::vector<MultiItem_st>
{
std::vector<MultiItem_st> rValue;
for( auto &item : items )
{
if(( item.offsetX == static_cast<std::int16_t>( offsetX )) && ( item.offsetY == static_cast<std::int16_t>( offsetY )))
{
rValue.push_back( item );
}
}
return rValue;
}
//o------------------------------------------------------------------------------------------------o
CollectionItem_st::CollectionItem_st() :minX( 0 ), minY( 0 ), maxX( 0 ), maxY( 0 ), minAlt( 0 ), maxAlt( 0 )
{
}
//o------------------------------------------------------------------------------------------------o
//| Function - CollectionItem_st::Name()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Return name of item in collection
//o------------------------------------------------------------------------------------------------o
auto CollectionItem_st::Name( int multi_id ) -> std::string
{
try
{
auto name = collectionNames.at( multi_id );
return name;
}
catch(...)
{
return "unknown - "s + std::to_string( multi_id );
}
}
//=========================================================
const std::unordered_map<int, std::string> CollectionItem_st::collectionNames = {
{ 0, "Small Boat [north]"s }, { 1, "Small Boat [east]"s },
{ 2, "Small Boat [south]"s }, { 3, "Small Boat [west]"s },
{ 4, "Small Dragon Boat [north]"s }, { 5, "Small Dragon Boat [east]"s },
{ 6, "Small Dragon Boat [south]"s }, { 7, "Small Dragon Boat [west]"s },
{ 8, "Medium Boat [north]"s }, { 9, "Medium Boat [east]"s },
{ 10, "Medium Boat [south]"s }, { 11, "Medium Boat [west]"s },
{ 12, "Medium Dragon Boat [north]"s }, { 13, "Medium Dragon Boat [east]"s },
{ 14, "Medium Dragon Boat [south]"s }, { 15, "Medium Dragon Boat [west]"s },
{ 16, "Large Boat [north]"s }, { 17, "Large Boat [east]"s },
{ 18, "Large Boat [soutch]"s }, { 19, "Large Boat [west]"s },
{ 20, "Large Dragon Boat [north]"s }, { 21, "Large Dragon Boat [east]"s },
{ 22, "Large Dragon Boat [south]"s }, { 23, "Large Dragon Boat [west]"s },
{ 24, "Orcish Galleon [north]"s }, { 25, "Orcish Galleon [east]"s },
{ 26, "Orcish Galleon [south]"s }, { 27, "Orcish Galleon [west]"s },
{ 28, "Orcish Galleon [damaged][north]"s }, { 29, "Orcish Galleon [damaged][east]"s },
{ 30, "Orcish Galleon [damaged][south]"s }, { 31, "Orcish Galleon [damaged][west]"s },
{ 32, "Orcish Galleon [destroyed][north]"s }, { 33, "Orcish Galleon [destroyed][east]"s },
{ 34, "Orcish Galleon [destroyed][south]"s }, { 35, "Orcish Galleon [destroyed][west]"s },
{ 36, "Gargish Galleon [north]"s }, { 37, "Gargish Galleon [east]"s },
{ 38, "Gargish Galleon [south]"s }, { 39, "Gargish Galleon [west]"s },
{ 40, "Gargish Galleon [damaged][north]"s }, { 41, "Gargish Galleon [damaged][east]"s },
{ 42, "Gargish Galleon [damaged][south]"s }, { 43, "Gargish Galleon [damaged][west]"s },
{ 44, "Gargish Galleon [destroyed][north]"s }, { 45, "Gargish Galleon [destroyed][east]"s },
{ 46, "Gargish Galleon [destroyed][south]"s }, { 47, "Gargish Galleon [destroyed][west]"s },
{ 48, "Tokuno Galleon [north]"s }, { 49, "Tokuno Galleon [east]"s },
{ 50, "Tokuno Galleon [south]"s }, { 51, "Tokuno Galleon [west]"s },
{ 52, "Tokuno Galleon [damaged][north]"s }, { 53, "Tokuno Galleon [damaged][east]"s },
{ 54, "Tokuno Galleon [damaged][south]"s }, { 55, "Tokuno Galleon [damaged][west]"s },
{ 56, "Tokuno Galleon [destroyed][north]"s }, { 57, "Tokuno Galleon [destroyed][east]"s },
{ 58, "Tokuno Galleon [destroyed][south]"s }, { 59, "Tokuno Galleon [destroyed][west]"s },
{ 60, "Rowboat [north]"s }, { 61, "Rowboat [east]"s },
{ 62, "Rowboat [south]"s }, { 63, "Rowboat [west]"s },
{ 64, "British Galleon [north]"s }, { 65, "British Galleon [east]"s },
{ 66, "British Galleon [south]"s }, { 67, "British Galleon [west]"s },
{ 68, "British Galleon [damaged][north]"s }, { 69, "British Galleon [damaged][east]"s },
{ 70, "British Galleon [damaged][south]"s }, { 71, "British Galleon [damaged][west]"s },
{ 100, "Small Stone and Plaster House"s }, { 101, "Small Stone and Plaster House"s },
{ 102, "Small Fieldstone House"s }, { 103, "Small Fieldstone House"s },
{ 104, "Small Brick House"s }, { 105, "Small Brick House"s },
{ 106, "Small Wood House"s }, { 107, "Small Wood House"s },
{ 108, "Small Wood and Plaster House"s }, { 109, "Small Wood and Plaster House"s },
{ 110, "Small Thatched Roof Cottage"s }, { 111, "Small Thatched Roof Cottage"s },
{ 112, "Tent [blue]"s }, { 113, "Tent [blue]"s },
{ 114, "Tent [green]"s }, { 115, "Tent [green]"s },
{ 116, "Large Brick House"s }, { 117, "Large Brick House"s },
{ 118, "Two Story Wood and Plaster House"s }, { 119, "Two Story Wood and Plaster House"s },
{ 120, "Two Story Stone and Plaster House"s }, { 121, "Two Story Stone and Plaster House"s },
{ 122, "Large Tower"s }, { 123, "Large Tower"s },
{ 124, "Stone Keep"s }, { 125, "Stone Keep"s },
{ 126, "Castle"s }, { 127, "Castle"s },
{ 128, "Large Patio House"s }, { 129, "Large Patio House"s },
{ 141, "Large Patio House"s }, { 150, "Large Marble Patio House"s },
{ 152, "Small Tower"s }, { 154, "Log Cabin"s },
{ 156, "Sandstone Patio House"s }, { 158, "Two-Story Villa"s },
{ 160, "Small Stone Workshop"s }, { 162, "Small Marble Workshop"s },
{ 201, "Mine's Elevator"s }, { 202, "Lifting Bridge"s },
{ 500, "Wandering Healer Camp"s }, { 501, "Wandering Mage Camp"s },
{ 502, "Wandering Bank Camp"s },
{ 1000, "Treasure Pile"s }, { 1001, "Treasure Pile"s },
{ 1002, "Treasure Pile"s }, { 1003, "Treasure Pile"s },
{ 2000, "Wooden Supports"s }, { 2001, "Wooden Supports"s },
{ 2002, "Wooden Supports"s }, { 2003, "Wooden Supports"s },
{ 2004, "Wooden Supports"s }, { 2005, "Wooden Supports"s },
{ 2006, "Wooden Supports"s }, { 2007, "Wooden Supports"s },
{ 3000, "Farmer's Cabin"s },
{ 4000, "Exodus Generator"s }, { 4001, "Exodus Generator"s },
{ 4002, "Exodus Control Pylon"s },
{ 4003, "Nystul's Tower (stage 1)"s }, { 4004, "Nystul's Tower (stage 2)"s },
{ 4005, "Nystul's Tower (stage 3)"s }, { 4006, "Nystul's Tower (stage 4)"s },
{ 4007, "Nystul's Tower (stage 5)"s }, { 4008, "Nystul's Tower (stage 6)"s },
{ 4009, "Scaffold and Trailer"s }, { 4010, "Exodus Energy Tower"s },
{ 4011, "Exodus Barrier"s }, { 4012, "Exodus Control Device"s },
{ 5000, "Minax Stronghold"s },
{ 5100, "Foundation [7x7]"s }, { 5101, "Foundation [7x8]"s },
{ 5102, "Foundation [7x9]"s }, { 5103, "Foundation [7x10]"s },
{ 5104, "Foundation [7x11]"s }, { 5105, "Foundation [7x12]"s },
{ 5112, "Foundation [8x7]"s }, { 5113, "Foundation [8x8]"s },
{ 5114, "Foundation [8x9]"s }, { 5115, "Foundation [8x10]"s },
{ 5116, "Foundation [8x11]"s }, { 5117, "Foundation [8x12]"s },
{ 5118, "Foundation [8x13]"s },
{ 5124, "Foundation [9x7]"s }, { 5125, "Foundation [9x8]"s },
{ 5126, "Foundation [9x9]"s }, { 5127, "Foundation [9x10]"s },
{ 5128, "Foundation [9x11]"s }, { 5129, "Foundation [9x12]"s },
{ 5130, "Foundation [9x13]"s }, { 5131, "Foundation [9x14]"s },
{ 5136, "Foundation [10x7]"s }, { 5137, "Foundation [10x8]"s },
{ 5138, "Foundation [10x9]"s }, { 5139, "Foundation [10x10]"s },
{ 5140, "Foundation [10x11]"s }, { 5141, "Foundation [10x12]"s },
{ 5142, "Foundation [10x13]"s }, { 5143, "Foundation [10x14]"s },
{ 5144, "Foundation [10x15]"s },
{ 5148, "Foundation [11x7]"s }, { 5149, "Foundation [11x8]"s },
{ 5150, "Foundation [11x9]"s }, { 5151, "Foundation [11x10]"s },
{ 5152, "Foundation [11x11]"s }, { 5153, "Foundation [11x12]"s },
{ 5154, "Foundation [11x13]"s }, { 5155, "Foundation [11x14]"s },
{ 5156, "Foundation [11x15]"s }, { 5157, "Foundation [11x16]"s },
{ 5160, "Foundation [12x7]"s }, { 5161, "Foundation [12x8]"s },
{ 5162, "Foundation [12x9]"s }, { 5163, "Foundation [12x10]"s },
{ 5164, "Foundation [12x11]"s }, { 5165, "Foundation [12x12]"s },
{ 5166, "Foundation [12x13]"s }, { 5167, "Foundation [12x14]"s },
{ 5168, "Foundation [12x15]"s }, { 5169, "Foundation [12x16]"s },
{ 5170, "Foundation [12x17]"s },
{ 5173, "Foundation [13x8]"s }, { 5174, "Foundation [13x9]"s },
{ 5175, "Foundation [13x10]"s }, { 5176, "Foundation [13x11]"s },
{ 5177, "Foundation [13x12]"s }, { 5178, "Foundation [13x13]"s },
{ 5179, "Foundation [13x14]"s }, { 5180, "Foundation [13x15]"s },
{ 5181, "Foundation [13x16]"s }, { 5182, "Foundation [13x17]"s },
{ 5183, "Foundation [13x18]"s },
{ 5186, "Foundation [14x9]"s }, { 5187, "Foundation [14x10]"s },
{ 5188, "Foundation [14x11]"s }, { 5189, "Foundation [14x12]"s },
{ 5190, "Foundation [14x13]"s }, { 5191, "Foundation [14x14]"s },
{ 5192, "Foundation [14x15]"s }, { 5193, "Foundation [14x16]"s },
{ 5194, "Foundation [14x17]"s }, { 5195, "Foundation [14x18]"s },
{ 5199, "Foundation [15x10]"s }, { 5200, "Foundation [15x11]"s },
{ 5201, "Foundation [15x12]"s }, { 5202, "Foundation [15x13]"s },
{ 5203, "Foundation [15x14]"s }, { 5204, "Foundation [15x15]"s },
{ 5205, "Foundation [15x16]"s }, { 5206, "Foundation [15x17]"s },
{ 5207, "Foundation [15x18]"s },
{ 5212, "Foundation [16x11]"s }, { 5213, "Foundation [16x12]"s },
{ 5214, "Foundation [16x13]"s }, { 5215, "Foundation [16x14]"s },
{ 5216, "Foundation [16x15]"s }, { 5217, "Foundation [16x16]"s },
{ 5218, "Foundation [16x17]"s }, { 5219, "Foundation [16x18]"s },
{ 5225, "Foundation [17x12]"s }, { 5226, "Foundation [17x13]"s },
{ 5227, "Foundation [17x14]"s }, { 5228, "Foundation [17x15]"s },
{ 5229, "Foundation [17x16]"s }, { 5230, "Foundation [17x17]"s },
{ 5231, "Foundation [17x18]"s },
{ 5238, "Foundation [18x13]"s }, { 5239, "Foundation [18x14]"s },
{ 5240, "Foundation [18x15]"s }, { 5241, "Foundation [18x16]"s },
{ 5242, "Foundation [18x17]"s }, { 5243, "Foundation [18x18]"s },
{ 7500, "New Player Quest Camp"s }
};
//o------------------------------------------------------------------------------------------------o
//| Function - MultiCollection::MultiCollection()
//o------------------------------------------------------------------------------------------------o
MultiCollection::MultiCollection( const std::filesystem::path &uodir, TileInfo *info )
{
this->info = info;
if( !uodir.empty() )
{
LoadMultiCollection( uodir, info );
}
}
//o------------------------------------------------------------------------------------------------o
//| Function - MultiCollection::LoadMultiCollection()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Load Multi MUL data from disk
//o------------------------------------------------------------------------------------------------o
auto MultiCollection::LoadMultiCollection( const std::filesystem::path &uodir, const std::string &housingbin, TileInfo *info ) -> bool
{
_multis.clear();
auto multifile = uodir / std::filesystem::path( "MultiCollection.uop" );
auto hash = "build/multicollection/%.6u.bin"s;
_housingBin = housingbin;
this->info = info;
return LoadUop( multifile.string(), 0x10000, hash );
}
//o------------------------------------------------------------------------------------------------o
//| Function - MultiCollection::LoadMul()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Load Multi MUL data from disk
//o------------------------------------------------------------------------------------------------o
auto MultiCollection::LoadMul( const std::filesystem::path &uodir, TileInfo *info ) -> bool
{
_multis.clear();
this->info = info;
auto rValue = false;
auto idxfile = uodir / std::filesystem::path( "multi.idx" );
auto mulfile = uodir / std::filesystem::path( "multi.mul" );
auto isHS = true;
if( std::filesystem::exists( mulfile ))
{
isHS = ( std::filesystem::file_size( mulfile) >= hsSize ? true : false );
}
auto idx = std::ifstream( idxfile, std::ios::binary );
auto mul = std::ifstream( mulfile, std::ios::binary );
if( mul.is_open() && idx.is_open() )
{
rValue = true;
auto offset = std::uint32_t( 0 );
auto length = std::uint32_t( 0 );
auto mulid = 0;
while( idx.good() && !idx.eof() )
{
idx.read( reinterpret_cast<char*>( &offset ), 4 );
idx.read( reinterpret_cast<char*>( &length ), 4 );
if( idx.gcount() == 4 )
{
idx.seekg( 4, std::ios::cur );
if(( offset <= 0xFFFFFFFE ) && ( length > 0 ) && ( length < 0xFFFFFFFF ))
{
// This is a valid entry;
mul.seekg( offset, std::ios::beg );
auto data = std::vector<std::uint8_t>( length, 0 );
mul.read( reinterpret_cast<char*>( data.data() ), length );
ProcessData( isHS, mulid, data );
}
}
mulid += 1;
}
}
return rValue;
}
//o------------------------------------------------------------------------------------------------o
//| Function - MultiCollection::LoadMultiCollection()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Load Multi UOP data from disk
//o------------------------------------------------------------------------------------------------o
auto MultiCollection::LoadMultiCollection( const std::filesystem::path &uodir, TileInfo *info ) -> bool
{
auto rValue = false;
// First, see if the uop exists?
auto multifile = uodir / std::filesystem::path( "MultiCollection.uop" );
if( std::filesystem::exists( multifile ))
{
// It does, so lets load the uop
Console << "\t" << uodir.string() << "MultiCollection.uop" << "\t\t";
rValue = LoadMultiCollection( uodir, "", info );
}
else
{
Console << "\t" << uodir.string() << "multi.mul" << " / multi.idx" << "\t\t";
rValue = LoadMul( uodir, info );
}
return rValue;
}
//o------------------------------------------------------------------------------------------------o
//| Function - MultiCollection::ProcessHash()
//o------------------------------------------------------------------------------------------------o
//| Purpose - ???
//o------------------------------------------------------------------------------------------------o
auto MultiCollection::ProcessHash( std::uint64_t hash, [[maybe_unused]] std::size_t entry, std::vector<std::uint8_t> &data ) -> bool
{
if( hash == 0x126D1E99DDEDEE0ALL )
{
if( !_housingBin.empty() )
{
auto output = std::ofstream( _housingBin, std::ios::binary );
if( output.is_open() )
{
output.write( reinterpret_cast<char*>( data.data() ), data.size() );
}
}
return false; // This is the hash for the housing.bin file
}
return true;
}
//o------------------------------------------------------------------------------------------------o
//| Function - MultiCollection::ProcessEntry()
//o------------------------------------------------------------------------------------------------o
//| Purpose - ???
//o------------------------------------------------------------------------------------------------o
auto MultiCollection::ProcessEntry( [[maybe_unused]] std::size_t entry, std::size_t index, std::vector<std::uint8_t> &data ) -> bool
{
if( data.size() > 8 )
{
auto offset = std::uint32_t( 4 );
// We skip the first 32 bit word (why offset is 4).
// The next 32 bit word is the number of entries in this data;
auto count = std::int32_t( 0 );
std::copy( data.data() + offset, data.data() + offset + 4, reinterpret_cast<std::uint8_t*>( &count ));
offset += 4;;
// we increment offfset now that we have read the count
// at this point,we are now looking at the data for each entry;
// before we start looping, make some dummy read space we can get data
// out of the vector
auto flag = std::int16_t( 0 );
auto clilocs = std::uint32_t( 0 );
auto multi = CollectionItem_st();
multi.items.resize( count );
auto first = true;
for( auto entry = 0; entry < count; ++entry )
{
auto item = MultiItem_st();
// Get the tileId
std::copy( data.begin() + offset, data.begin() + offset + 2, reinterpret_cast<unsigned char*>( &item.tileId ));
offset += 2;
if( info )
{
item.info = &info->ArtInfo( item.tileId );
}
// Now get the xoffset --
std::copy( data.begin()+offset, data.begin() + offset + 2, reinterpret_cast<unsigned char*>( &flag ));
item.offsetX = static_cast<int>(flag);
offset += 2;
// Now get the yoffset
std::copy( data.begin()+offset, data.begin() + offset + 2, reinterpret_cast<unsigned char*>( &flag ));
item.offsetY = static_cast<int>(flag);
offset += 2;
// Now get the z
std::copy( data.begin()+offset, data.begin() + offset + 2, reinterpret_cast<unsigned char*>( &flag ));
item.altitude = static_cast<int>(flag);
offset += 2;
// now we need to get the flag
std::copy( data.begin()+offset, data.begin() + offset + 2, reinterpret_cast<unsigned char*>( &flag ));
offset += 2;
switch( flag )
{
default:
case 0:
item.flag = 1;
break;
case 1:
break;
case 257:
item.flag = 0x800;
break;
}
if( flag == 0 )
{
if( first )
{
multi.maxY = item.offsetY;
multi.minY = item.offsetY;
multi.maxX = item.offsetX;
multi.minX = item.offsetX;
multi.maxAlt = item.altitude;
multi.minAlt = item.altitude;
first = false;
}
else
{
multi.maxY = std::max( item.offsetY, multi.maxY );
multi.minY = std::max( item.offsetY, multi.minY );
multi.maxX = std::max( item.offsetX, multi.maxX );
multi.minX = std::max( item.offsetX, multi.minX );
multi.maxAlt = std::max( item.altitude, multi.maxAlt );
multi.minAlt = std::max( item.altitude, multi.minAlt );
}
}
// we now have some clilocs to read past, have to find out how many
std::copy( data.begin() + offset, data.begin() + offset + 4, reinterpret_cast<unsigned char*>( &clilocs ));
offset += 4;
// Now skip past them;
offset += ( clilocs * 4 );
multi.items[entry] = std::move( item );
}
_multis.insert_or_assign( static_cast<int>( index ), std::move( multi ));
}
return true;
}
//o------------------------------------------------------------------------------------------------o
//| Function - MultiCollection::ProcessData()
//o------------------------------------------------------------------------------------------------o
//| Purpose - ???
//o------------------------------------------------------------------------------------------------o
auto MultiCollection::ProcessData( bool isHS, int index, std::vector<std::uint8_t> &data ) -> void
{
auto size = ( isHS ? 16 : 12 );
auto count = static_cast<int>( data.size() ) / size;
auto multi = CollectionItem_st();
auto first = true;
for( auto entry = 0; entry < count; ++entry )
{
auto item = MultiItem_st();
std::copy( data.data() + ( entry * size ), data.data() + ( entry * size ) + 2, reinterpret_cast<std::uint8_t*>( &item.tileId ));
if( info )
{
item.info = &( info->ArtInfo( item.tileId ));
}
auto value = std::int16_t( 0 );
std::copy( data.data() + ( entry * size ) + 2, data.data() + ( entry * size ) + 2 + 2, reinterpret_cast<std::uint8_t*>( &value ));
item.offsetX = value;
std::copy( data.data() + ( entry * size ) + 4, data.data() + ( entry * size ) + 4 + 2, reinterpret_cast<std::uint8_t*>( &value ));
item.offsetY = value;
std::copy( data.data() + ( entry * size ) + 6, data.data() + ( entry * size ) + 6 + 2, reinterpret_cast<std::uint8_t*>( &value ));
item.altitude = value;
if( isHS )
{
auto flag = std::uint64_t( 0 );
std::copy( data.data() + ( entry * size ) + 8, data.data() + ( entry * size ) + 8 + 8, reinterpret_cast<std::uint8_t*>( &flag ));
item.flag = static_cast<std::uint16_t>( flag );
}
else
{
auto flag = std::uint32_t( 0 );
std::copy( data.data() + ( entry * size ) + 4, data.data() + ( entry * size ) + 4 + 4, reinterpret_cast<std::uint8_t*>( &flag ));
item.flag = static_cast<std::uint16_t>( flag );
}
if( first )
{
multi.maxY = item.offsetY;
multi.minY = item.offsetY;
multi.maxX = item.offsetX;
multi.minX = item.offsetX;
multi.maxAlt = item.altitude;
multi.minAlt = item.altitude;
first = false;
}
else
{
multi.maxY = std::max( item.offsetY, multi.maxY );
multi.minY = std::max( item.offsetY, multi.minY );
multi.maxX = std::max( item.offsetX, multi.maxX );
multi.minX = std::max( item.offsetX, multi.minX );
multi.maxAlt = std::max( item.altitude, multi.maxAlt );
multi.minAlt = std::max( item.altitude, multi.minAlt );
}
multi.items.push_back( item );
}
_multis.insert_or_assign( static_cast<int>( index ), std::move( multi ));
}
auto MultiCollection::Size() const -> size_t
{
return _multis.size();
}
auto MultiCollection::Multis() const -> const std::unordered_map<int, CollectionItem_st>&
{
return _multis;
}
auto MultiCollection::Multis() -> std::unordered_map<int, CollectionItem_st>&
{
return _multis;
}
auto MultiCollection::Multi( std::uint16_t multiId ) -> CollectionItem_st&
{
return _multis.at( static_cast<int>( multiId ));
}
auto MultiCollection::Multi( std::uint16_t multiId ) const -> const CollectionItem_st&
{
return _multis.at( static_cast<int>( multiId ));
}
auto MultiCollection::Exists( std::uint16_t multiId ) const -> bool
{
auto rValue = false;
auto iter = _multis.find( multiId );
if( iter != _multis.end() )
{
rValue = true;;
}
return rValue;
}