uox3/source/MultiMul.cpp
Xoduz fa2aae242e UOX3 0.99.6-RC4
Fixed an issue that prevented onBuyFromVendor() and onBoughtFromVendor() JS Events from triggering when attached to NPC shopkeepers
Fixed an issue with help gump that prevented password management section from working as intended (js/server/misc/helpgump.js)
Fixed an issue where UOX3 would fail to load pre-HS multi.mul files
Added chess board to Misc->Games add menu (dfndata/items/ItemMenu.bulk.dfn)
Fixed an issue with 'move (alias for 'telestuff) command that referenced the wrong variable name (js/commands/targeting/tele.js)
When a player is teleported via the GM 'wholist menu, any pets within range are now also brought along for the ride
Consolidated error-reporting for JS Functions, Object Methods and Object Properties to provide more context (scriptID, filename, line number) when something goes wrong
Added some missing shield IDs (0xA649, 0xA64A, 0xA831, 0xA832) to IsShieldType() function
MAXRANGE item property previously only worked for ranged weapons; now it works for melee weapons too, and potentially allows melee weapons with combat range longer than 1 tile
MAXRANGE item property can now be used to define max combat range for melee weapons
Fixed an issue (non-critical) with .PlaceInPack() JS Method that would cause UOX3 to try adding items marked for deletion to refreshQueue and spam console with errors
Added missing AI scripts to summoned Blade Spirits and Energy Vortexes (dfndata/npc/magicsummon.dfn)
Fixed an issue with weight calculation for hireling backpacks (js/npc/ai/hireling.js)
Fixed an issue with the 'fix command, which would in most cases set character's Z to -1 regardless of location, but now adheres to map elevation instead
Fixed an issue with Pack AI (js/npc/ai/pack_ai.js) that prevented pack members from attacking target correctly (thanks Dragon Slayer)
Fixed an issue with DoesMapBlock JS Function that incorrectly checked for 6 function arguments, when it actually requires 8
Fixed an issue with DoesDynamicBlock JS Function that incorrectly checked for 8 function arguments, when it actually requires 9
Fixed an issue with runebook script (js/item/runebook.js) that prevented players from being able to use recall charges without having spellbook with spell in inventory
Fixed issues with placement of tall items on ground/floor, and with stacking of items in houses
Fixed incorrect alias for woodland armor (dfndata/items/gear/armor/other/armor/wood.dfn - thanks Dragon Slayer)
Fixed a critical issue with script context sometimes changing while executing a script, because of events in other scripts being triggered. Affected scripts can be safeguarded against this by the addition of a dummy callback function anywhere in the script: function _restorecontext_() {}
Fixed an issue with non-animal pets not gaining loyalty when being fed (thanks Dragon Slayer)
Added new JS Object Methods for Chars/Items/Multis to fetch list of custom tags associated with object:
	.GetTagMap()		// Gets list of persistent custom tags associated with object
	.GetTempTagMap()	// Gets list of temporary custom tags associated with object
Added new JS commands ('GETTAGMAP and 'GETTEMPTAGMAP) that spits out details of custom tags associated with targeted object (js/commands/custom/misc-cmd.js)
Added new JS command ('USEITEM) that acts as a short-cut for double-clicking on targeted item (js/commands/custom/misc-cmd.js)
Updated 'ADD # and 'ADD ITEM # JS commands to support targeting a container directly and adding the new item inside (js/commands/targeting/add.js)
Updated axe script to only perform lumberjacking skill-check when there's still wood available in a given area, and to play appropriate animations for Gargoyle players (js/item/axe.js)
Updated script for gameboards to make generated pieces newbiefied so they won't appear on ground if board decays (js/item/gameboards.js)
Updated script for stablemasters to avoid relying on global variables (js/npc/ai/stablemaster.js)
Updated names of items crafted with runic hammers to include the material name of the hammers used to craft them (js/skill/craft/crafting_complete.js)
Fixed a small issue with Detect Hidden skill that would return the wrong message if players found anyone hiding nearby (js/skill/detecthidden.js)
Fixed an issue that prevented tile overrides in dfndata/maps/tiles.dfn from loading properly
Added entries for a couple of walls with missing no-shoot flags to tile overrides in dfndata/maps/tiles.dfn
Updated JS Method .SoundEffect() to support optional third argument (creatureSoundNum) to play creature-defined sounds from dfndata/creatures/creatures.dfn. New syntax:
	.SoundEffect( soundID, allHear[, creatureSoundNum] ) // 0=SOUND_STARTATTACK, 1=SOUND_IDLE, 2=SOUND_ATTACK, 3=SOUND_DEFEND, 4=SOUND_DIE
Added new Character JS Methods:
	.SetRandomName( nameListID ) 	// apply a random name from specified namelist to character
	.FindItemSection( sectionID ) 	// find item in player's backpack with specified sectionID
Added new Socket JS Method:
	.OpenContainer()	// Opens specified container for socket
2023-05-30 01:47:26 +08:00

541 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
rValue = LoadMultiCollection( uodir, "", info );
}
else
{
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 ) + 8 + 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;
}