uox3/source/mapstuff.cpp
Xoduz f5545bf224 Additional string handling updates, a few other fixes
Fixed some missing icons in dfndata/creatures/creatures.dfn
	Updated server status HTML template page (dfndata/html/online.htf) to match other templates
	Additional string handling modernization in magic.cpp, JSEncapsulate.cpp, jail.cpp, house.cpp, fileio.cpp, network.cpp, msgboard.cpp and mapstuff.cpp (punt)

Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
2021-04-27 00:26:38 +08:00

2196 lines
75 KiB
C++

#include "uox3.h"
#include "regions.h"
#include "townregion.h"
#include "fileio.h"
#include "cServerDefinitions.h"
#include "ssection.h"
#include "scriptc.h"
CMulHandler *Map = NULL;
const UI16 LANDDATA_SIZE = 0x4000; //(512 * 32)
//! these are the fixed record lengths as determined by the .mul files from OSI
//! i made them longs because they are used to calculate offsets into the files
const UI32 MultiRecordSize = 12L;
const UI32 MultiRecordSizeHS = 16L;
const UI32 TileRecordSize = 26L;
const UI32 TileRecordSizeHS = 41L;
const UI32 MapRecordSize = 3L;
//const UI32 MapRecordSizeHS = 4L;
const UI32 MultiIndexRecordSize = 12L;
const UI32 StaticRecordSize = 7L;
const UI32 StaticIndexRecordSize = 12L;
const UI32 MapBlockSize = 196L;
/*! New Notes: 11/3/1999
** I changed all of the places where z was handled as a signed char and
** upped them to an int. While the basic terrain never goes above 127,
** calculations sure can. For example, if you are at a piece of land at 100
** and put a 50 high static object, its going to roll over.
*/
/*!
** New rewrite plans, its way confusing having every function in here using 'Height' to mean
** elevation or actual height of a tile. Here's the new renaming plan:
** Elevation - the z value of the bottom edge of an item
** Height - the height of the item, it is independant of the elevation, like a person is 6ft tall
** Top - the z value of the top edge of an item, is always Elevation + Height of item
*/
/*!
** I thought it might be helpful to others to include a quick guide to what things
** meant in this code.
** Tile - a single item in the game, maybe static or dynamic
** Land - a single square from the map, the ground/water
** Static - a single item that comes as part of the basic map. NOTE: Land and Statics are both
** saved in the same .mul file! A lot of statics look like land as well.
** Dynamic - any item added that doesn't come as part of the basic map
** Single - an item in the game that will fit in a single cell
** Multi - any item in the game that is composed of multiple single items across multiple cells
** maybe static or dynamic, may have multiple singles within same cell
**
*/
MapData_st::~MapData_st()
{
if( mapObj != NULL )
{
delete mapObj;
mapObj = NULL;
}
if( staticsObj != NULL )
{
delete staticsObj;
staticsObj = NULL;
}
if( staidxObj != NULL )
{
delete staidxObj;
staidxObj = NULL;
}
if( mapDiffObj != NULL )
{
delete mapDiffObj;
mapDiffObj = NULL;
}
if( staticsDiffObj != NULL )
{
delete staticsDiffObj;
staticsDiffObj = NULL;
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void MultiItemsIndex_st::Include( SI16 x, SI16 y, SI08 z )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Compute new bounding box, by include the new point. < High Seas version
//o-----------------------------------------------------------------------------------------------o
void CMulHandler::MultiItemsIndex_st::Include( SI16 x, SI16 y, SI08 z )
{
if( x < lx )
lx = x;
if( x > hx )
hx = x;
if( y < ly )
ly = y;
if( y > hy )
hy = y;
if( z < lz )
lz = z;
if( z > hz )
hz = z;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void MultiItemsIndexHS_st::Include( SI16 x, SI16 y, SI08 z )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Compute new bounding box, by include the new point. > High Seas version
//o-----------------------------------------------------------------------------------------------o
void CMulHandler::MultiItemsIndexHS_st::Include( SI16 x, SI16 y, SI08 z )
{
if( x < lx )
lx = x;
if( x > hx )
hx = x;
if( y < ly )
ly = y;
if( y > hy )
hy = y;
if( z < lz )
lz = z;
if( z > hz )
hz = z;
}
/*! Use Memory-Mapped file to do caching instead
** 'verdata.mul', 'tiledata.mul', 'multis.mul' and 'multi.idx' is changed so
** it will reads into main memory and access directly. 'map*.mul', 'statics*.mul' and
** 'staidx.mul' is being managed by memory-mapped files, it faster than manual caching
** and less susceptible to bugs.
*/
CMulHandler::CMulHandler() : landTile( 0 ), landTileHS( 0 ), staticTile( 0 ), staticTileHS( 0 ), multiItems( 0 ), multiItemsHS( 0 ), multiIndex( 0 ), multiIndexHS( 0 ), multiIndexSize( 0 ), multiSize( 0 ), tileDataSize( 0 )
{
LoadMapsDFN();
}
CMulHandler::~CMulHandler()
{
if ( landTile )
delete[] landTile;
if ( landTileHS )
delete[] landTileHS;
if ( staticTile )
delete[] staticTile;
if ( staticTileHS )
delete[] staticTileHS;
if ( multiItems )
delete[] multiItems;
if( multiItemsHS )
delete[] multiItemsHS;
if ( multiIndex )
delete[] multiIndex;
if( multiIndexHS )
delete[] multiIndexHS;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void LoadMapsDFN( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Loads maps.dfn to see which map files to actually load into memory later
//o-----------------------------------------------------------------------------------------------o
void CMulHandler::LoadMapsDFN( void )
{
std::string tag, data, UTag;
const UI08 NumberOfWorlds = static_cast<UI08>(FileLookup->CountOfEntries( maps_def ));
MapList.reserve( NumberOfWorlds );
for( UI08 i = 0; i < NumberOfWorlds; ++i )
{
ScriptSection *toFind = FileLookup->FindEntry( "MAP " + str_number( i ), maps_def );
if( toFind == NULL )
break;
MapData_st toAdd;
for( tag = toFind->First(); !toFind->AtEnd(); tag = toFind->Next() )
{
UTag = str_toupper( tag );
data = toFind->GrabData();
data = stripTrim( data );
switch( (UTag.data()[0]) )
{
case 'M':
if( UTag == "MAP" )
{
toAdd.mapFile = data;
}
else if( UTag == "MAPUOPWRAP" )
{
toAdd.mapFileUOPWrap = data;
}
else if( cwmWorldState->ServerData()->MapDiffsEnabled() )
{
if( UTag == "MAPDIFF" )
{
toAdd.mapDiffFile = data;
}
else if( UTag == "MAPDIFFLIST" )
{
toAdd.mapDiffListFile = data;
}
}
break;
case 'S':
if( UTag == "STATICS" )
{
toAdd.staticsFile = data;
}
else if( UTag == "STAIDX" )
{
toAdd.staidxFile = data;
}
else if( cwmWorldState->ServerData()->MapDiffsEnabled() )
{
if( UTag == "STATICSDIFF" )
{
toAdd.staticsDiffFile = data;
}
else if( UTag == "STATICSDIFFLIST" )
{
toAdd.staticsDiffListFile = data;
}
else if( UTag == "STATICSDIFFINDEX" )
{
toAdd.staticsDiffIndexFile = data;
}
}
break;
case 'X':
if( UTag == "X" )
{
toAdd.xBlock = static_cast<UI16>(std::stoul(data, nullptr, 0));
}
break;
case 'Y':
if( UTag == "Y" )
{
toAdd.yBlock = static_cast<UI16>(std::stoul(data, nullptr, 0));
}
break;
}
}
MapList.push_back( toAdd );
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - UOXFile * loadFile( const std::string& fullName )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Prints status of loading a file in UOX3 console
//o-----------------------------------------------------------------------------------------------o
UOXFile * loadFile( const std::string& fullName )
{
UOXFile *toLoad = new UOXFile( fullName.c_str(), "rb" );
Console << "\t" << fullName << "\t\t";
if( toLoad != NULL && toLoad->ready() )
Console.PrintDone();
else
Console.PrintSpecial( CBLUE, "not found" );
return toLoad;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void LoadMapAndStatics( MapData_st& mMap, const std::string& basePath, UI08 &totalMaps )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Loads map and statics files into memory
//o-----------------------------------------------------------------------------------------------o
void CMulHandler::LoadMapAndStatics( MapData_st& mMap, const std::string& basePath, UI08 &totalMaps )
{
std::string mapMUL = mMap.mapFile;
std::string mapUOPWrap = mMap.mapFileUOPWrap;
std::string lName = basePath + mapMUL;
mMap.mapObj = new UOXFile( lName.c_str(), "rb" );
Console << "\t" << lName << "(/" << mapUOPWrap << ")\t\t";
//if no map0.mul was found, check if there's a map#LegacyMul.uop
if(( mMap.mapObj == NULL || !mMap.mapObj->ready() ) && !mapUOPWrap.empty() )
{
std::string lName = basePath + mapUOPWrap;
mMap.mapObj = new UOXFile( lName.c_str(), "rb" );
}
if( mMap.mapObj != NULL && mMap.mapObj->ready() )
{
SI32 checkSize = static_cast<SI32>(mMap.mapObj->getLength() / MapBlockSize);
if( checkSize / (mMap.xBlock/8) == (mMap.yBlock/8) )
{
++totalMaps;
Console.PrintDone();
}
else
{
Console.PrintFailed();
}
}
else
{
Console.PrintSpecial( CRED, "not found" );
}
mMap.staticsObj = loadFile( basePath + mMap.staticsFile );
mMap.staidxObj = loadFile( basePath + mMap.staidxFile );
if( !mMap.mapDiffFile.empty() )
mMap.mapDiffObj = loadFile( basePath + mMap.mapDiffFile );
if( !mMap.staticsDiffFile.empty() )
mMap.staticsDiffObj = loadFile( basePath + mMap.staticsDiffFile );
if( !mMap.mapDiffListFile.empty() )
{
lName = basePath + mMap.mapDiffListFile;
Console << "\t" << lName << "\t\t";
std::ifstream mdlFile ( lName.c_str(), std::ios::in | std::ios::binary );
if( mdlFile.is_open() )
{
size_t offset = 0;
size_t blockID = 0;
mdlFile.seekg( 0, std::ios::beg );
while( !mdlFile.fail() )
{
mdlFile.read( (char *)&blockID, 4 );
if( !mdlFile.fail() )
{
mMap.mapDiffList[blockID] = offset;
}
offset += MapBlockSize;
}
mdlFile.close();
Console.PrintDone();
}
else
Console.PrintSpecial( CBLUE, "not found" );
}
if( !mMap.staticsDiffIndexFile.empty() && !mMap.staticsDiffListFile.empty() )
{
lName = basePath + mMap.staticsDiffIndexFile;
Console << "\t" << lName << "\t\t";
std::ifstream sdiFile ( lName.c_str(), std::ios::in | std::ios::binary );
if( sdiFile.is_open() )
{
Console.PrintDone();
lName = basePath + mMap.staticsDiffListFile;
Console << "\t" << lName << "\t\t";
std::ifstream sdlFile ( lName.c_str(), std::ios::in | std::ios::binary );
if( sdlFile.is_open() )
{
size_t blockID = 0;
sdiFile.seekg( 0, std::ios::beg );
sdlFile.seekg( 0, std::ios::beg );
while( !sdiFile.fail() && !sdlFile.fail() )
{
sdlFile.read( (char *)&blockID, 4 );
sdiFile.read( (char *)&mMap.staticsDiffIndex[blockID].offset, 4 );
sdiFile.read( (char *)&mMap.staticsDiffIndex[blockID].length, 4 );
sdiFile.read( (char *)&mMap.staticsDiffIndex[blockID].unknown, 4 );
}
sdlFile.close();
Console.PrintDone();
}
else
Console.PrintSpecial( CBLUE, "not found" );
sdiFile.close();
}
else
Console.PrintSpecial( CBLUE, "not found" );
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void LoadTileData( const std::string& basePath )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Loads tiledata file into memory
//o-----------------------------------------------------------------------------------------------o
void CMulHandler::LoadTileData( const std::string& basePath )
{
UI08 j = 0;
// tiledata.mul is to be cached.
std::string lName = basePath + "tiledata.mul";
Console << "\t" << lName << "\t";
UOXFile tileFile( lName.c_str(), "rb" );
if( !tileFile.ready() )
{
Console.PrintFailed();
Shutdown( FATAL_UOX3_TILEDATA_NOT_FOUND );
}
//Grab length of tileFile to determine version of datafiles used
size_t tileFileLength = tileFile.getLength();
if( tileFileLength >= 3188736 )
{
// 7.0.9.0 tiledata and above
cwmWorldState->ServerData()->ServerUsingHSTiles( true );
landTileHS = new CLandHS[LANDDATA_SIZE];
CLandHS *landPtr = landTileHS;
for( UI16 i = 0; i < 512; ++i )
{
tileFile.seek(4, SEEK_CUR); // skip the dummy header
for( j = 0; j < 32; ++j )
landPtr[j].Read( &tileFile );
landPtr += 32;
}
tileDataSize = (((tileFile.getLength() - (((32 * TileRecordSizeHS) + 4) * 512)) / 1188) * 32);
staticTileHS = new CTileHS[tileDataSize];
CTileHS *tilePtr = staticTileHS;
while( !tileFile.eof() )
{
tileFile.seek(4, SEEK_CUR); // skip the dummy header
for( j = 0; j < 32; ++j )
tilePtr[j].Read( &tileFile );
tilePtr += 32;
}
}
else
{
// 7.0.8.2 tiledata and below
cwmWorldState->ServerData()->ServerUsingHSTiles( false );
landTile = new CLand[LANDDATA_SIZE];
CLand *landPtr = landTile;
for( UI16 i = 0; i < 512; ++i )
{
tileFile.seek(4, SEEK_CUR); // skip the dummy header
for( j = 0; j < 32; ++j )
landPtr[j].Read( &tileFile );
landPtr += 32;
}
tileDataSize = (((tileFile.getLength() - (((32 * TileRecordSize) + 4) * 512)) / 1188) * 32);
staticTile = new CTile[tileDataSize];
CTile *tilePtr = staticTile;
while( !tileFile.eof() )
{
tileFile.seek(4, SEEK_CUR); // skip the dummy header
for( j = 0; j < 32; ++j )
tilePtr[j].Read( &tileFile );
tilePtr += 32;
}
}
Console.PrintDone();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void Load( void )
//| Date - 03/12/2002
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Prepare access streams to the server required mul files. This function basicaly
//| just opens the streams and validates that the file is open and available
//o-----------------------------------------------------------------------------------------------o
void CMulHandler::Load( void )
{
Console.PrintSectionBegin();
Console << "Preparing to open *.mul files..." << myendl << "(If they don't open, fix your paths in uox.ini or filenames in maps.dfn)" << myendl;
const std::string basePath = cwmWorldState->ServerData()->Directory( CSDDP_DATA );
UI08 totalMaps = 0;
for( MAPLIST_ITERATOR mlIter = MapList.begin(); mlIter != MapList.end(); ++mlIter )
{
LoadMapAndStatics( (*mlIter), basePath, totalMaps );
}
if( totalMaps == 0 )
{
// Hmm, no maps were valid, so not much sense in continuing
Console.error( " Fatal Error: No maps found" );
Console.error( " Check the settings for DATADIRECTORY in uox.ini" );
Shutdown( FATAL_UOX3_MAP_NOT_FOUND );
}
LoadTileData( basePath );
LoadMultis( basePath );
LoadDFNOverrides();
FileLookup->Dispose( maps_def );
Console.PrintSectionBegin();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void LoadMultis( const std::string& basePath )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Loads multi files into memory
//o-----------------------------------------------------------------------------------------------o
void CMulHandler::LoadMultis( const std::string& basePath )
{
// now main memory multiItems
Console << "Caching Multis.... ";
// only turn it off for now because we are trying to fill the cache.
std::string lName = basePath + "multi.idx";
UOXFile multiIDX( lName.c_str(), "rb" );
if( !multiIDX.ready() )
{
Console.PrintFailed();
Console.error( format("Can't cache %s! File cannot be opened", lName.c_str()) );
return;
}
lName = basePath + "multi.mul";
UOXFile multis( lName.c_str(), "rb" );
if( !multis.ready() )
{
Console.PrintFailed();
Console.error( format("Can't cache %s! File cannot be opened", lName.c_str()) );
return;
}
// multiLength determines version of datafiles used by server
// 994832 - 7.0.85.15 - possibly earlier
// 962928 - 7.0.15.1 to 7.0.23.1 - Additional SI32 unknown1 property added
// 908592 - 7.0.9.0
// 596976 - 7.0.8.2
// 593616 - 5.0.9.1 to 6.1.14.1
// 592560 - 4.0.11c
size_t multiLength = multis.getLength();
multiSize = multis.getLength() / (( multiLength >= 908592 ) ? MultiRecordSizeHS : MultiRecordSize );
//! first reads in Multi_st completely
if( multiLength >= 908592 )
{
cwmWorldState->ServerData()->ServerUsingHSMultis( true );
multiItemsHS = new MultiHS_st[multiSize];
for( size_t i = 0; i < multiSize; ++i )
{
multis.getUShort( &multiItemsHS[i].tile );
multis.getShort( &multiItemsHS[i].x );
multis.getShort( &multiItemsHS[i].y );
multis.getChar( &multiItemsHS[i].z );
multis.getChar( &multiItemsHS[i].empty );
multis.getLong( &multiItemsHS[i].visible );
multis.getLong( &multiItemsHS[i].unknown1 );
}
multiIndexSize = multiIDX.getLength() / MultiIndexRecordSize;
multiIndexHS = new MultiItemsIndexHS_st[multiIndexSize];
// now rejig the multiIDX to point to the cache directly, and calculate the size
for( MultiItemsIndexHS_st *ptr = multiIndexHS; ptr != (multiIndexHS+multiIndexSize); ++ptr )
{
MultiIndex_st multiidx;
multiIDX.getLong( &multiidx.start );
multiIDX.getLong( &multiidx.length );
multiIDX.getLong( &multiidx.unknown );
ptr->size = multiidx.length;
if( ptr->size != -1 )
{
ptr->size /= MultiRecordSizeHS; // convert byte size to record size
ptr->items = (MultiHS_st*)((char*)multiItemsHS + multiidx.start);
for( MultiHS_st* items = ptr->items; items != (ptr->items+ptr->size); ++items )
{
ptr->Include( items->x, items->y, items->z );
}
}
}
}
else
{
cwmWorldState->ServerData()->ServerUsingHSMultis( false );
multiItems = new Multi_st[multiSize];
for( size_t i = 0; i < multiSize; ++i )
{
multis.getUShort( &multiItems[i].tile );
multis.getShort( &multiItems[i].x );
multis.getShort( &multiItems[i].y );
multis.getChar( &multiItems[i].z );
multis.getChar( &multiItems[i].empty );
multis.getLong( &multiItems[i].visible );
}
multiIndexSize = multiIDX.getLength() / MultiIndexRecordSize;
multiIndex = new MultiItemsIndex_st[multiIndexSize];
// now rejig the multiIDX to point to the cache directly, and calculate the size
for( MultiItemsIndex_st *ptr = multiIndex; ptr != (multiIndex+multiIndexSize); ++ptr )
{
MultiIndex_st multiidx;
multiIDX.getLong( &multiidx.start );
multiIDX.getLong( &multiidx.length );
multiIDX.getLong( &multiidx.unknown );
ptr->size = multiidx.length;
if( ptr->size != -1 )
{
ptr->size /= MultiRecordSize; // convert byte size to record size
ptr->items = (Multi_st*)((char*)multiItems + multiidx.start);
for( Multi_st* items = ptr->items; items != (ptr->items+ptr->size); ++items )
{
ptr->Include( items->x, items->y, items->z );
}
}
}
}
Console.PrintDone();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - size_t GetTileMem( void ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns amount of memory used to load tiledata
//o-----------------------------------------------------------------------------------------------o
size_t CMulHandler::GetTileMem( void ) const
{
if( cwmWorldState->ServerData()->ServerUsingHSTiles() ) //7.0.9.0 tiledata and later
return (LANDDATA_SIZE * sizeof( CLandHS ) + tileDataSize * sizeof( CTileHS ));
else //7.0.8.2 tiledata and earlier
return (LANDDATA_SIZE * sizeof( CLand ) + tileDataSize * sizeof( CTile ));
}
//o-----------------------------------------------------------------------------------------------o
//| Function - size_t GetMultisMem( void ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns amount of memory used to load multis
//o-----------------------------------------------------------------------------------------------o
size_t CMulHandler::GetMultisMem( void ) const
{
if( cwmWorldState->ServerData()->ServerUsingHSMultis() ) //7.0.9.0 tiledata and later
return (multiSize * sizeof( MultiHS_st ) + multiIndexSize * sizeof( MultiItemsIndexHS_st ) );
else //7.0.8.2 tiledata and earlier
return (multiSize * sizeof( Multi_st ) + multiIndexSize * sizeof( MultiItemsIndex_st ) );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SI08 TileHeight( UI16 tilenum )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Height of a given tile (If climbable we return 1/2 its height).
//o-----------------------------------------------------------------------------------------------o
SI08 CMulHandler::TileHeight( UI16 tilenum )
{
if( cwmWorldState->ServerData()->ServerUsingHSTiles() )
{
//7.0.9.0 tiledata and later
CTileHS& tile = SeekTileHS( tilenum );
// For Stairs+Ladders
if( tile.CheckFlag( TF_CLIMBABLE ) )
return static_cast<SI08>(tile.Height()/2);
return tile.Height();
}
else
{
//7.0.8.2 tiledata and earlier
CTile& tile = SeekTile( tilenum );
// For Stairs+Ladders
if( tile.CheckFlag( TF_CLIMBABLE ) )
return static_cast<SI08>(tile.Height()/2);
return tile.Height();
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SI08 StaticTop( SI16 x, SI16 y, SI08 oldz, UI08 worldNumber, SI08 maxZ )
//| Date - Unknown Touched: Dec 21, 1998
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Top of statics at/above given coordinates
//o-----------------------------------------------------------------------------------------------o
SI08 CMulHandler::StaticTop( SI16 x, SI16 y, SI08 oldz, UI08 worldNumber, SI08 maxZ )
{
SI08 top = ILLEGAL_Z;
CStaticIterator msi( x, y, worldNumber );
for( Static_st *stat = msi.First(); stat != NULL; stat = msi.Next() )
{
SI08 tempTop = (SI08)(stat->zoff + TileHeight(stat->itemid));
if( ( tempTop <= oldz + maxZ ) && ( tempTop > top ) )
top = tempTop;
}
return top;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SI32 SeekMulti( UI16 multinum )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Checks if multinum/id can be found in multi data. Non-High Seas version
//o-----------------------------------------------------------------------------------------------o
SI32 CMulHandler::SeekMulti( UI16 multinum )
{
SI32 retVal = -1;
if( multinum < multiIndexSize )
retVal = multiIndex[multinum].size;
return retVal;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SI32 SeekMultiHS( UI16 multinum )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Checks if multinum/id can be found in multi data. High Seas version
//o-----------------------------------------------------------------------------------------------o
SI32 CMulHandler::SeekMultiHS( UI16 multinum )
{
SI32 retVal = -1;
if( multinum < multiIndexSize )
retVal = multiIndexHS[multinum].size;
return retVal;
}
Multi_st& CMulHandler::SeekIntoMulti( UI16 multinum, SI32 number )
{
return *(multiIndex[multinum].items + number);
}
MultiHS_st& CMulHandler::SeekIntoMultiHS( UI16 multinum, SI32 number )
{
return *(multiIndexHS[multinum].items + number);
}
//o--------------------------------------------------------------------------
//| Function - void MultiArea( CMultiObj *i, SI16 &x1, SI16 &y1, SI16 &x2, SI16 &y2 )
//| Date - 6th September, 1999
//| Changes - 26th September, 2001 - fetches from cache
//o--------------------------------------------------------------------------
//| Purpose - Finds the corners of a multi object
//o--------------------------------------------------------------------------
void CMulHandler::MultiArea( CMultiObj *i, SI16 &x1, SI16 &y1, SI16 &x2, SI16 &y2 )
{
if( !ValidateObject( i ) )
return;
const SI16 xAdd = i->GetX();
const SI16 yAdd = i->GetY();
const UI16 multiNum = static_cast<UI16>(i->GetID() - 0x4000);
if( multiNum >= multiIndexSize )
return;
if( cwmWorldState->ServerData()->ServerUsingHSMultis() )
{
//7.0.9.0 tiledata and later
x1 = static_cast<SI16>(multiIndexHS[multiNum].lx + xAdd);
x2 = static_cast<SI16>(multiIndexHS[multiNum].hx + xAdd);
y1 = static_cast<SI16>(multiIndexHS[multiNum].ly + yAdd);
y2 = static_cast<SI16>(multiIndexHS[multiNum].hy + yAdd);
}
else
{
//7.0.8.2 tiledata and earlier
x1 = static_cast<SI16>(multiIndex[multiNum].lx + xAdd);
x2 = static_cast<SI16>(multiIndex[multiNum].hx + xAdd);
y1 = static_cast<SI16>(multiIndex[multiNum].ly + yAdd);
y2 = static_cast<SI16>(multiIndex[multiNum].hy + yAdd);
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SI08 MultiHeight( CItem *i, SI16 x, SI16 y, SI08 oldz, SI08 maxZ )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Return the height of a multi item at the given x, y.
//| This seems to actually return a height
//o-----------------------------------------------------------------------------------------------o
SI08 CMulHandler::MultiHeight( CItem *i, SI16 x, SI16 y, SI08 oldZ, SI08 maxZ, bool checkHeight )
{
UI16 multiID = static_cast<UI16>(i->GetID() - 0x4000);
SI32 length = 0;
if( cwmWorldState->ServerData()->ServerUsingHSMultis() )
length = SeekMultiHS( multiID ); //7.0.9.0 tiledata and later
else
length = SeekMulti( multiID ); //7.0.8.2 tiledata and earlier
if( length == -1 || length >= 17000000 ) //Too big... bug fix hopefully (13 Sept 1999)
length = 0;
const SI16 baseX = i->GetX();
const SI16 baseY = i->GetY();
const SI08 baseZ = i->GetZ();
SI08 mHeight = ILLEGAL_Z;
SI08 tmpTop = ILLEGAL_Z;
if( cwmWorldState->ServerData()->ServerUsingHSMultis() )
{
for( SI32 j = 0; j < length; ++j )
{
MultiHS_st& multi = SeekIntoMultiHS( multiID, j );
if(( checkHeight || multi.visible ) && ( baseX + multi.x ) == x && ( baseY + multi.y ) == y )
{
if( checkHeight )
{
// Returns height of highest point of multi
tmpTop = static_cast<SI08>(baseZ + multi.z);
if( ( tmpTop <= oldZ + maxZ ) && tmpTop > oldZ && tmpTop > mHeight )
mHeight = tmpTop;
}
else
{
tmpTop = static_cast<SI08>( baseZ + multi.z );
if( abs( tmpTop - oldZ ) <= maxZ )
return tmpTop + TileHeight( multi.tile );
}
}
}
}
else
{
for( SI32 j = 0; j < length; ++j )
{
Multi_st& multi = SeekIntoMulti( multiID, j );
if(( checkHeight || multi.visible ) && ( baseX + multi.x ) == x && ( baseY + multi.y ) == y )
{
if( checkHeight )
{
// Returns height of highest point of multi
tmpTop = static_cast<SI08>(baseZ + multi.z);
if( ( tmpTop <= oldZ + maxZ ) && tmpTop > oldZ && tmpTop > mHeight )
mHeight = tmpTop;
}
else
{
tmpTop = static_cast<SI08>( baseZ + multi.z );
if( abs( tmpTop - oldZ ) <= maxZ )
return tmpTop + TileHeight( multi.tile );
}
}
}
}
return mHeight;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SI08 DynamicElevation( SI16 x, SI16 y, SI08 oldz, UI08 worldNumber, SI08 maxZ, UI16 instanceID )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - This was fixed to actually return the *elevation* of dynamic items at/above given coordinates
//o-----------------------------------------------------------------------------------------------o
SI08 CMulHandler::DynamicElevation( SI16 x, SI16 y, SI08 oldz, UI08 worldNumber, SI08 maxZ, UI16 instanceID )
{
SI08 z = ILLEGAL_Z;
CMapRegion *MapArea = MapRegion->GetMapRegion( MapRegion->GetGridX( x ), MapRegion->GetGridY( y ), worldNumber );
if( MapArea == NULL ) // no valid region
return z;
CDataList< CItem * > *regItems = MapArea->GetItemList();
regItems->Push();
for( CItem *tempItem = regItems->First(); !regItems->Finished(); tempItem = regItems->Next() )
{
if( !ValidateObject( tempItem ) || tempItem->GetInstanceID() != instanceID )
continue;
if( tempItem->GetID( 1 ) >= 0x40 && tempItem->CanBeObjType( OT_MULTI ))
z = MultiHeight( tempItem, x, y, oldz, maxZ );
else if( tempItem->GetX() == x && tempItem->GetY() == y )
{
SI08 ztemp = (SI08)(tempItem->GetZ() + TileHeight( tempItem->GetID() ));
if( ( ztemp <= oldz + maxZ ) && ztemp > z )
z = ztemp;
}
}
regItems->Pop();
return z;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - UI16 MultiTile( CItem *i, SI16 x, SI16 y, SI08 oldz )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns ID of tile in multi at specified coordinates
//o-----------------------------------------------------------------------------------------------o
UI16 CMulHandler::MultiTile( CItem *i, SI16 x, SI16 y, SI08 oldz, bool checkVisible )
{
if( !i->CanBeObjType( OT_MULTI ) )
return 0;
UI16 multiID = static_cast<UI16>(i->GetID() - 0x4000);
SI32 length = 0;
if( cwmWorldState->ServerData()->ServerUsingHSTiles() )
length = SeekMultiHS( multiID ); //7.0.9.0 tiledata and later
else
length = SeekMulti( multiID ); //7.0.8.2 tiledata and earlier
if( length == -1 || length >= 17000000 )//Too big... bug fix hopefully (13 Sept 1999)
{
Console << "CMulHandler::MultiTile->Bad length in multi file. Avoiding stall." << myendl;
const map_st map1 = Map->SeekMap( i->GetX(), i->GetY(), i->WorldNumber() );
if( cwmWorldState->ServerData()->ServerUsingHSTiles() )
{
//7.0.9.0 tiledata and later
CLandHS& land = Map->SeekLandHS( map1.id );
if( land.CheckFlag( TF_WET ) ) // is it water?
i->SetID( 0x4001 );
else
i->SetID( 0x4064 );
}
else
{
//7.0.8.2 tiledata and earlier
CLand& land = Map->SeekLand( map1.id );
if( land.CheckFlag( TF_WET ) ) // is it water?
i->SetID( 0x4001 );
else
i->SetID( 0x4064 );
}
length = 0;
}
if( cwmWorldState->ServerData()->ServerUsingHSMultis() )
{
// Loop through each item that makes up the multi
// If any of those items intersect with area were are checking, return the ID of that tile
for( SI32 j = 0; j < length; ++j )
{
MultiHS_st& multi = SeekIntoMultiHS( multiID, j );
if( !checkVisible )
{
if( ( i->GetX() + multi.x == x ) && ( i->GetY() + multi.y == y ) )
{
return multi.tile;
}
}
else if( multi.visible > 0 && ( abs( i->GetZ() + multi.z - oldz ) <= 1 ) )
{
if( ( i->GetX() + multi.x == x ) && ( i->GetY() + multi.y == y ) )
{
return multi.tile;
}
}
}
}
else
{
for( SI32 j = 0; j < length; ++j )
{
Multi_st& multi = SeekIntoMulti( multiID, j );
if(( !checkVisible || ( multi.visible > 0 && ( abs( i->GetZ() + multi.z - oldz ) <= 1 )))
&& (( i->GetX() + multi.x == x ) && ( i->GetY() + multi.y == y )))
return multi.tile;
}
}
return 0;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - UI16 DynTile( SI16 x, SI16 y, SI08 oldz, UI08 worldNumber, UI16 instanceID, bool checkOnlyMultis )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns which dynamic tile is present at (x,y) or -1 if no tile exists
//o-----------------------------------------------------------------------------------------------o
CItem *CMulHandler::DynTile( SI16 x, SI16 y, SI08 oldz, UI08 worldNumber, UI16 instanceID, bool checkOnlyMultis, bool checkOnlyNonMultis )
{
REGIONLIST nearbyRegions = MapRegion->PopulateList( x, y, worldNumber );
for( REGIONLIST_CITERATOR rIter = nearbyRegions.begin(); rIter != nearbyRegions.end(); ++rIter )
{
CMapRegion *CellResponse = (*rIter);
if( CellResponse == NULL )
continue;
CDataList< CItem * > *regItems = CellResponse->GetItemList();
regItems->Push();
for( CItem *Item = regItems->First(); !regItems->Finished(); Item = regItems->Next() )
{
if( !ValidateObject( Item ) || Item->GetInstanceID() != instanceID )
continue;
if( !checkOnlyNonMultis && Item->GetID( 1 ) >= 0x40 && Item->GetObjType() == OT_MULTI )
{
auto deetee = MultiTile( Item, x, y, oldz, false );
if( deetee > 0 )
{
regItems->Pop();
return Item;
}
else
continue;
}
else if( !checkOnlyMultis && Item->GetX() == x && Item->GetY() == y )
{
regItems->Pop();
return Item;
}
}
regItems->Pop();
}
return NULL;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SI08 MapElevation( SI16 x, SI16 y, UI08 worldNumber )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the map elevation at given coordinates, we'll assume since its land
//| the height is inherently 0
//o-----------------------------------------------------------------------------------------------o
SI08 CMulHandler::MapElevation( SI16 x, SI16 y, UI08 worldNumber )
{
const map_st map = SeekMap( x, y, worldNumber );
// make sure nothing can move into black areas
if( 430 == map.id || 431 == map.id || 432 == map.id ||
433 == map.id || 434 == map.id || 475 == map.id ||
580 == map.id || 610 == map.id || 611 == map.id ||
612 == map.id || 613 == map.id )
return ILLEGAL_Z;
return map.z;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool IsValidTile( UI16 tileNum )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Checks if a given tile number falls within the range of tiles loaded in memory
//o-----------------------------------------------------------------------------------------------o
bool CMulHandler::IsValidTile( UI16 tileNum )
{
bool retVal = true;
if( tileNum == INVALIDID || tileNum >= tileDataSize )
retVal = false;
return retVal;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - CTile& SeekTile( UI16 tileNum )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Fetches data about a specific tile from memory. Non-High Seas version
//o-----------------------------------------------------------------------------------------------o
CTile& CMulHandler::SeekTile( UI16 tileNum )
{
//7.0.8.2 tiledata and earlier
if( !IsValidTile( tileNum ) )
{
Console.warning( format("Invalid tile access, the offending tile number is %u", tileNum) );
static CTile emptyTile;
return emptyTile;
}
else
return staticTile[tileNum];
}
//o-----------------------------------------------------------------------------------------------o
//| Function - CTileHS& SeekTileHS( UI16 tileNum )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Fetches data about a specific tile from memory. High Seas version
//o-----------------------------------------------------------------------------------------------o
CTileHS& CMulHandler::SeekTileHS( UI16 tileNum )
{
//7.0.9.2 tiledata and later
if( !IsValidTile( tileNum ) )
{
Console.warning( format("Invalid tile access, the offending tile number is %u", tileNum ));
static CTileHS emptyTile;
return emptyTile;
}
else
return staticTileHS[tileNum];
}
//o-----------------------------------------------------------------------------------------------o
//| Function - CLand& SeekLand( UI16 landNum )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Fetches data about a specific land tile from memory. Non-High Seas version
//o-----------------------------------------------------------------------------------------------o
CLand& CMulHandler::SeekLand( UI16 landNum )
{
if( landNum == INVALIDID || landNum >= LANDDATA_SIZE )
{
Console.warning( format("Invalid land access, the offending land number is %u", landNum) );
static CLand emptyTile;
return emptyTile;
}
else
return landTile[landNum];
}
//o-----------------------------------------------------------------------------------------------o
//| Function - CLandHS& SeekLandHS( UI16 landNum )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Fetches data about a specific land tile from memory. High Seas version
//o-----------------------------------------------------------------------------------------------o
CLandHS& CMulHandler::SeekLandHS( UI16 landNum )
{
if( landNum == INVALIDID || landNum >= LANDDATA_SIZE )
{
Console.warning( format("Invalid land access, the offending land number is %u", landNum) );
static CLandHS emptyTile;
return emptyTile;
}
else
return landTileHS[landNum];
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool InsideValidWorld( SI16 x, SI16 y, UI08 worldNumber )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Checks if a given location is within the bounds of the specified world
//o-----------------------------------------------------------------------------------------------o
bool CMulHandler::InsideValidWorld( SI16 x, SI16 y, UI08 worldNumber )
{
if( worldNumber >= MapList.size() )
return false;
return ( ( x >= 0 && x < MapList[worldNumber].xBlock ) && ( y >= 0 && y < MapList[worldNumber].yBlock ) );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - CStaticIterator( SI16 x, SI16 y, UI08 world, bool exact ) : baseX( static_cast<SI16>(x / 8) ),
//| baseY( static_cast<SI16>(y / 8) ), pos( 0 ), remainX( static_cast<UI08>(x % 8) ), remainY( static_cast<UI08>(y % 8) ),
//| index( 0 ), length( 0 ), exactCoords( exact ), worldNumber( world ), useDiffs( false )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Use this iterator class anywhere you would have used SeekInit() and SeekStatic()
//| Unlike those functions however, it will only return the location of tiles that match your
//| (x,y) EXACTLY. They also should be significantly faster since the iterator saves
//| a lot of info that was recomputed over and over and it returns a pointer instead
//| of an entire structure on the stack. You can call First() if you need to reset it.
//| This iterator hides all of the map implementation from other parts of the program.
//| If you supply the exact variable, it tells it whether to iterate over those items
//| with your exact (x,y) otherwise it will loop over all items in the same cell as you.
//| (Thats normally only used for filling the cache)
//|
//| Usage:
//| CStaticIterator msi( x, y, worldNumber );
//|
//| for( Static_st *stat = msi.First(); stat != NULL; stat = msi.Next() )
//| {
//| CTile& tile = Map->SeekTile( stat->itemid );
//| ... your code here...
//| }
//o-----------------------------------------------------------------------------------------------o
CStaticIterator::CStaticIterator( SI16 x, SI16 y, UI08 world, bool exact ) : baseX( static_cast<SI16>(x / 8) ),
baseY( static_cast<SI16>(y / 8) ), pos( 0 ), remainX( static_cast<UI08>(x % 8) ), remainY( static_cast<UI08>(y % 8) ),
index( 0 ), length( 0 ), exactCoords( exact ), worldNumber( world ), useDiffs( false )
{
if( !Map->InsideValidWorld( x, y, world ) )
{
Console.error( "ASSERT: CStaticIterator(); Not inside a valid world" );
return;
}
MapData_st& mMap = Map->GetMapData( world );
const size_t indexPos = ( static_cast<size_t>(baseX) * ( static_cast<size_t>(mMap.yBlock) / 8 ) + static_cast<size_t>(baseY) );
std::map< UI32, StaticsIndex_st >::const_iterator diffIter = mMap.staticsDiffIndex.find( indexPos );
if( diffIter != mMap.staticsDiffIndex.end() )
{
const StaticsIndex_st &sdiRecord = diffIter->second;
if( sdiRecord.offset == INVALIDSERIAL )
{
length = 0;
return;
}
useDiffs = true;
pos = sdiRecord.offset;
length = (sdiRecord.length / StaticRecordSize);
}
else
{
UOXFile *toRead = mMap.staidxObj;
if( toRead == NULL )
{
length = 0;
return;
}
toRead->seek( (indexPos * StaticIndexRecordSize), SEEK_SET );
if( !toRead->eof() )
{
toRead->getULong( &pos );
if( pos != INVALIDSERIAL )
{
toRead->getULong( &length );
length /= StaticRecordSize;
useDiffs = false;
}
}
}
}
Static_st *CStaticIterator::First( void )
{
index = 0;
return Next();
}
Static_st *CStaticIterator::Next( void )
{
if( index >= length )
return NULL;
MapData_st& mMap = Map->GetMapData( worldNumber );
UOXFile *mFile = NULL;
if( useDiffs )
mFile = mMap.staticsDiffObj;
else
mFile = mMap.staticsObj;
if( mFile == NULL )
return NULL;
const size_t pos2 = static_cast<size_t>(pos) + static_cast<size_t>(StaticRecordSize) * static_cast<size_t>(index); // skip over all the ones we've read so far
mFile->seek( pos2, SEEK_SET );
do
{
if( mFile->eof() )
return NULL;
mFile->getUShort( &staticArray.itemid );
mFile->getUChar( &staticArray.xoff );
mFile->getUChar( &staticArray.yoff );
mFile->getChar( &staticArray.zoff );
mFile->seek( 2, SEEK_CUR ); // Skip past the unused data
++index;
// if these are ever larger than 7 we've gotten out of sync
assert( staticArray.xoff < 0x08 );
assert( staticArray.yoff < 0x08 );
if( !exactCoords || ( staticArray.xoff == remainX && staticArray.yoff == remainY ) )
{
#ifdef DEBUG_MAP_STUFF
Console << "Found static at index: " << index << ", Length: " << length << ", indepos: " << pos2 << myendl;
Console << "item is " << (SI32)staticArray.itemid << ", x" << (SI32)staticArray.xoff << ", y: " << (SI32) staticArray.yoff << myendl;
#endif
return &staticArray;
}
} while( index < length );
return NULL;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - map_st SeekMap( SI16 x, SI16 y, UI08 worldNumber )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Fetches map data for a specific map/world
//o-----------------------------------------------------------------------------------------------o
map_st CMulHandler::SeekMap( SI16 x, SI16 y, UI08 worldNumber )
{
map_st map = {0, 0};
if( worldNumber >= MapList.size() )
return map;
MapData_st& mMap = MapList[worldNumber];
size_t pos = 0;
UOXFile *mFile = NULL;
const SI16 x1 = static_cast<SI16>(x >> 3), y1 = static_cast<SI16>(y >> 3);
const UI08 x2 = static_cast<UI08>(x % 8), y2 = static_cast<UI08>(y % 8);
const size_t blockID = static_cast<size_t>(x1) * ( static_cast<size_t>(mMap.yBlock) >> 3) + static_cast<size_t>(y1);
const size_t cellOffset = (4 + (static_cast<size_t>(y2) * 8 + static_cast<size_t>(x2)) * static_cast<size_t>(MapRecordSize) );
std::map< UI32, UI32 >::const_iterator diffIter = mMap.mapDiffList.find( blockID );
if( diffIter != mMap.mapDiffList.end() )
{
mFile = mMap.mapDiffObj;
pos = (diffIter->second + cellOffset);
}
else
{
mFile = mMap.mapObj;
pos = (blockID * MapBlockSize + cellOffset);
}
mFile->seek( pos, SEEK_SET );
if( mFile->eof() )
{
#if defined( UOX_DEBUG_MODE )
Console.warning( format("SeekMap: Invalid map tile index %u at: X %i, Y %i", pos, x, y ));
#endif
}
else
{
mFile->getUShort( &map.id );
mFile->getChar( &map.z );
}
return map;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool DoesStaticBlock( SI16 x, SI16 y, SI08 oldz, UI08 worldNumber, bool checkWater )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Checks if statics at/above given coordinates blocks movement, etc
//o-----------------------------------------------------------------------------------------------o
bool CMulHandler::DoesStaticBlock( SI16 x, SI16 y, SI08 oldz, UI08 worldNumber, bool checkWater )
{
CStaticIterator msi( x, y, worldNumber );
for( Static_st *stat = msi.First(); stat != NULL; stat = msi.Next() )
{
const SI08 elev = static_cast<SI08>(stat->zoff + TileHeight( stat->itemid ));
if( cwmWorldState->ServerData()->ServerUsingHSTiles() )
{
//7.0.9.0 data and later
CTileHS& tile = SeekTileHS( stat->itemid );
if( checkWater )
{
if( elev >= oldz && stat->zoff <= oldz && ( tile.CheckFlag( TF_BLOCKING ) || tile.CheckFlag( TF_WET ) ))
return true;
}
else
{
if( elev >= oldz && stat->zoff <= oldz && ( tile.CheckFlag( TF_BLOCKING ) && !tile.CheckFlag( TF_WET ) ))
return true;
}
}
else
{
//7.0.8.2 data and earlier
CTile& tile = SeekTile( stat->itemid );
if( checkWater )
{
if( elev >= oldz && stat->zoff <= oldz && ( tile.CheckFlag( TF_BLOCKING ) || tile.CheckFlag( TF_WET ) ))
return true;
}
else
{
if( elev >= oldz && stat->zoff <= oldz && ( tile.CheckFlag( TF_BLOCKING ) && !tile.CheckFlag( TF_WET ) ))
return true;
}
}
}
return false;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool CheckStaticFlag( SI16 x, SI16 y, SI08 z, UI08 worldNumber, TileFlags toCheck, bool checkSpawnSurface )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Checks to see whether any statics at given coordinates has a specific flag
//o-----------------------------------------------------------------------------------------------o
bool CMulHandler::CheckStaticFlag( SI16 x, SI16 y, SI08 z, UI08 worldNumber, TileFlags toCheck, bool checkSpawnSurface )
{
CStaticIterator msi( x, y, worldNumber );
for( Static_st *stat = msi.First(); stat != NULL; stat = msi.Next() )
{
const SI08 elev = static_cast<SI08>( stat->zoff );
const SI08 tileHeight = static_cast<SI08>( TileHeight( stat->itemid ) );
if( cwmWorldState->ServerData()->ServerUsingHSTiles() )
{
//7.0.9.0 data and later
if( checkSpawnSurface )
{
// Special case used when checking for spawn surfaces
if(( z >= elev && z <= ( elev + tileHeight )) && !SeekTileHS( stat->itemid ).CheckFlag( toCheck ) )
return false;
}
else
{
// Generic check exposed to JS
if(( z >= elev && z <= ( elev + tileHeight )) && SeekTileHS( stat->itemid ).CheckFlag( toCheck ) )
return true; // Found static with specified flag
}
}
else
{
//7.0.8.2 data and earlier
if( checkSpawnSurface )
{
// Special case used when checking for spawn surfaces
if( ( z >= elev && z <= ( elev + tileHeight ) ) && !SeekTile( stat->itemid ).CheckFlag( toCheck ) )
return false;
}
else
{
// Generic check exposed to JS
if( ( z >= elev && z <= ( elev + tileHeight ) ) && SeekTile( stat->itemid ).CheckFlag( toCheck ) )
return true; // Found static with specified flag
}
}
}
return checkSpawnSurface;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool CheckTileFlag( UI16 itemID, TileFlags flagToCheck )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Checks to see whether given tile ID has a specified flag
//o-----------------------------------------------------------------------------------------------o
bool CMulHandler::CheckTileFlag( UI16 itemID, TileFlags flagToCheck )
{
if( cwmWorldState->ServerData()->ServerUsingHSTiles() )
{
//7.0.9.0 data and later
if( !SeekTileHS( itemID ).CheckFlag( flagToCheck ))
return false;
}
else
{
//7.0.8.2 data and earlier
if(!SeekTile( itemID ).CheckFlag( flagToCheck ))
return false;
}
return true;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SI08 Height( SI16 x, SI16 y, SI08 oldz, UI08 worldNumber, UI16 instanceID )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns new height of player who walked to X/Y but from OLDZ
//o-----------------------------------------------------------------------------------------------o
SI08 CMulHandler::Height( SI16 x, SI16 y, SI08 oldz, UI08 worldNumber, UI16 instanceID )
{
// let's check in this order.. dynamic, static, then the map
const SI08 dynz = DynamicElevation( x, y, oldz, worldNumber, MAX_Z_STEP, instanceID );
if( ILLEGAL_Z != dynz )
return dynz;
const SI08 staticz = StaticTop( x, y, oldz, worldNumber, MAX_Z_STEP );
if( ILLEGAL_Z != staticz )
return staticz;
return MapElevation( x, y, worldNumber );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool inBuilding( SI16 x, SI16 y, SI08 z, UI08 worldNumber, UI16 instanceID )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns whether give coordinates are inside a building by checking if there is
//| a multi or static above them
//o-----------------------------------------------------------------------------------------------o
bool CMulHandler::inBuilding( SI16 x, SI16 y, SI08 z, UI08 worldNumber, UI16 instanceID )
{
const SI08 dynz = Map->DynamicElevation( x, y, z, worldNumber, (SI08)127, instanceID );
if( dynz > ( z + 10))
return true;
else
{
const SI08 staticz = Map->StaticTop( x, y, z, worldNumber, (SI08)127 );
if( staticz > ( z + 10))
return true;
}
return false;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool DoesDynamicBlock( SI16 x, SI16 y, SI08 z, UI08 worldNumber, UI16 instanceID,
//| bool checkWater, bool waterWalk, bool checkOnlyMultis )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Checks if there are any dynamic tiles at given coordinates that block movement
//o-----------------------------------------------------------------------------------------------o
bool CMulHandler::DoesDynamicBlock( SI16 x, SI16 y, SI08 z, UI08 worldNumber, UI16 instanceID,
bool checkWater, bool waterWalk, bool checkOnlyMultis, bool checkOnlyNonMultis )
{
// get the tile id of any dynamic tiles at this spot
CItem * dtItem = DynTile( x, y, z, worldNumber, instanceID, checkOnlyMultis, checkOnlyNonMultis );
if( ValidateObject( dtItem ))
{
// Don't allow placing houses on top of immovable, visible dynamic items
if( dtItem->GetMovable() == 2 && dtItem->GetVisible() == 0 )
return true;
// Ignore items that are permanently invisible or visible to GMs only
if( dtItem->GetVisible() == 1 || dtItem->GetVisible() == 3 )
return false;
const UI16 dt = dtItem->GetID();
if( IsValidTile( dt ) && dt != 0 )
{
if( cwmWorldState->ServerData()->ServerUsingHSTiles() )
{
//7.0.9.0 data and later
CTileHS &tile = SeekTileHS( dt );
if( waterWalk )
{
if( !tile.CheckFlag( TF_WET ) )
return true;
}
else
{
if( tile.CheckFlag( TF_ROOF ) || tile.CheckFlag( TF_BLOCKING ) || (checkWater && tile.CheckFlag( TF_WET ) ) /*|| !tile.CheckFlag( TF_SURFACE ) */ )
return true;
}
}
else
{
//7.0.8.2 data and earlier
CTile &tile = SeekTile( dt );
if( waterWalk )
{
if( !tile.CheckFlag( TF_WET ) )
return true;
}
else
{
if( tile.CheckFlag( TF_ROOF ) || tile.CheckFlag( TF_BLOCKING ) || (checkWater && tile.CheckFlag( TF_WET ) ) /*|| !tile.CheckFlag( TF_SURFACE ) */ )
return true;
}
}
}
}
return false;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool DoesMapBlock( SI16 x, SI16 y, SI08 z, UI08 worldNumber, bool checkWater, bool waterWalk, bool checkMultiPlacement )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Checks if the map tile at the given coordinates block movement
//o-----------------------------------------------------------------------------------------------o
bool CMulHandler::DoesMapBlock( SI16 x, SI16 y, SI08 z, UI08 worldNumber, bool checkWater, bool waterWalk, bool checkMultiPlacement, bool checkForRoad )
{
if( checkWater || waterWalk )
{
const map_st map = SeekMap( x, y, worldNumber );
if( checkMultiPlacement && map.z == z || ( !checkMultiPlacement && map.z > z && map.z - z < 16 ))
{
if( z == ILLEGAL_Z )
return true;
UI16 landID;
if( cwmWorldState->ServerData()->ServerUsingHSTiles() )
{
//7.0.9.0 tiledata and later
CLandHS& land = SeekLandHS( map.id );
if( land.CheckFlag( TF_BLOCKING ) ) // is it impassable?
return true;
if( waterWalk )
{
if( !land.CheckFlag( TF_WET ) )
return true;
}
else
{
if( land.CheckFlag( TF_WET ) )
return true;
}
landID = land.TextureID();
}
else
{
//7.0.8.2 tiledata and earlier
CLand& land = SeekLand( map.id );
if( land.CheckFlag( TF_BLOCKING ) ) // is it impassable?
return true;
if( waterWalk )
{
if( !land.CheckFlag( TF_WET ) )
return true;
}
else
{
if( land.CheckFlag( TF_WET ) )
return true;
}
landID = land.TextureID();
}
// Check that player is not attempting to place a multi on a road
if( checkWater && checkMultiPlacement && checkForRoad )
{
// List of road tiles, or road-related tiles, on which houses cannot be placed
std::vector<UI16> roadIDs = {
0x0009, 0x0015, // furrows
0x0071, 0x0078, // dirt
0x00E8, 0x00EB, // dirt
0x0150, 0x015C, // furrows
0x0442, 0x0479, // sand stone
0x0501, 0x0510, // sand stone
0x07AE, 0x07B1, // dirt
0x3FF4, 0x3FF4, // dirt
0x3FF8, 0x3FFB // dirt
};
for( int i = 0; i < roadIDs.size(); i += 2 )
{
if( landID >= roadIDs[i] && landID <= roadIDs[static_cast<size_t>(i) + 1] )
return true;
}
}
}
}
return false;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool ValidSpawnLocation( SI16 x, SI16 y, SI08 z, UI08 worldNumber, UI16 instanceID, bool checkWater )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Checks if location at given coordinates is considered valid for spawning objects
//| Also used to verify teleport location for NPCs teleporting back to bounding box
//o-----------------------------------------------------------------------------------------------o
bool CMulHandler::ValidSpawnLocation( SI16 x, SI16 y, SI08 z, UI08 worldNumber, UI16 instanceID, bool checkWater )
{
if( !InsideValidWorld( x, y, worldNumber ) )
return false;
// get the tile id of any dynamic tiles at this spot
if( DoesDynamicBlock( x, y, z, worldNumber, instanceID, checkWater, !checkWater, false, false ) )
return false;
// if there's a static block here in our way, return false
if( DoesStaticBlock( x, y, z, worldNumber, checkWater ) )
return false;
// if the static isn't a surface return false
if( !CheckStaticFlag( x, y, z, worldNumber, ( checkWater ? TF_SURFACE : TF_WET ), true ) )
return false;
if( DoesMapBlock( x, y, z, worldNumber, checkWater, !checkWater, false, false ) )
return false;
return true;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool ValidMultiLocation( SI16 x, SI16 y, SI08 oldz, UI08 worldNumber, UI16 instanceID, bool checkWater, bool checkOnlyMultis )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Checks whether given location is valid for house/boat placement
//o-----------------------------------------------------------------------------------------------o
UI08 CMulHandler::ValidMultiLocation( SI16 x, SI16 y, SI08 oldz, UI08 worldNumber, UI16 instanceID,
bool checkWater, bool checkOnlyMultis, bool checkOnlyNonMultis, bool checkForRoad )
{
if( !InsideValidWorld( x, y, worldNumber ) )
return 0;
const SI08 elev = Height( x, y, oldz, worldNumber, instanceID );
if( ILLEGAL_Z == elev )
return 0;
// We don't want the house to be halfway embedded in a hill... or hanging off one for that matter.
if( oldz != ILLEGAL_Z )
{
if( elev - oldz > MAX_Z_STEP )
{
return 0;
}
else if( oldz - elev > MAX_Z_FALL )
{
return 0;
}
}
// get the tile id of any dynamic tiles at this spot
if( !checkOnlyNonMultis && DoesDynamicBlock( x, y, elev, worldNumber, instanceID, checkWater, false, checkOnlyMultis, checkOnlyNonMultis ) )
{
return 2;
}
// if there's a static block here in our way, return false
if( !checkOnlyMultis && DoesStaticBlock( x, y, elev, worldNumber, checkWater ) )
{
return 2;
}
if( DoesMapBlock( x, y, elev, worldNumber, checkWater, false, true, checkForRoad ) )
{
return 0;
}
// Check if house placement is allowed in region
CTownRegion *calcReg = calcRegionFromXY( x, y, worldNumber, instanceID );
if(( !calcReg->CanPlaceHouse() && checkWater) || calcReg->IsDungeon() || ( calcReg->IsGuarded() && checkWater ))
return 3;
// Else, all good!
return 1;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool MapExists( UI08 worldNumber )
//| Date - 27th September, 2001
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns true if the server has that map in memory
//o-----------------------------------------------------------------------------------------------o
bool CMulHandler::MapExists( UI08 worldNumber )
{
return ( (worldNumber < MapList.size()) && (MapList[worldNumber].mapObj != NULL) );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - MapData_st& GetMapData( UI08 worldNumber )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns map data for given world number
//o-----------------------------------------------------------------------------------------------o
MapData_st& CMulHandler::GetMapData( UI08 worldNumber )
{
return MapList[worldNumber];
}
//o-----------------------------------------------------------------------------------------------o
//| Function - UI08 MapCount( void ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns count of how many maps have been loaded
//o-----------------------------------------------------------------------------------------------o
UI08 CMulHandler::MapCount( void ) const
{
return static_cast<UI08>(MapList.size());
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void LoadDFNOverrides( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Override flags/properties for tiles based on DFNDATA/MAPS/tiles.dfn
//o-----------------------------------------------------------------------------------------------o
void CMulHandler::LoadDFNOverrides( void )
{
std::string data, UTag, entryName, titlePart;
size_t entryNum;
for( Script *mapScp = FileLookup->FirstScript( maps_def ); !FileLookup->FinishedScripts( maps_def ); mapScp = FileLookup->NextScript( maps_def ) )
{
if( mapScp == NULL )
continue;
for( ScriptSection *toScan = mapScp->FirstEntry(); toScan != nullptr; toScan = mapScp->NextEntry() )
{
if( toScan == NULL )
{
continue;
}
entryName = mapScp->EntryName();
entryNum = str_value<std::uint16_t>(extractSection(entryName," ", 1, 1 ));
titlePart = str_toupper(extractSection(entryName, " ", 0, 0 ));
// have we got an entry starting with TILE ?
if( titlePart == "TILE" && entryNum )
{
if( entryNum == INVALIDID || entryNum >= tileDataSize )
{
continue;
}
if( cwmWorldState->ServerData()->ServerUsingHSTiles() )
{
//7.0.9.0 data and later
CTileHS *tile = &staticTileHS[entryNum];
if( tile != nullptr )
{
for( std::string tag = toScan->First(); !toScan->AtEnd(); tag = toScan->Next() )
{
data = toScan->GrabData();
data = stripTrim( data );
UTag = str_toupper( tag );
// CTile properties
if( UTag == "WEIGHT" )
{
tile->Weight( static_cast<UI08>(std::stoul(data, nullptr, 0)) );
}
else if( UTag == "HEIGHT" )
{
tile->Height( static_cast<SI08>(std::stoi(data, nullptr, 0))) ;
}
else if( UTag == "LAYER" )
{
tile->Layer( static_cast<SI08>(std::stoi(data, nullptr, 0))) ;
}
else if( UTag == "HUE" )
{
tile->Hue( static_cast<UI08>(std::stoul(data, nullptr, 0)) );
}
else if( UTag == "QUANTITY" )
{
tile->Quantity( static_cast<UI08>(std::stoul(data, nullptr, 0)) );
}
else if( UTag == "ANIMATION" )
{
tile->Animation( static_cast<UI16>(std::stoul(data, nullptr, 0)) );
}
else if( UTag == "NAME" )
{
tile->Name( data.c_str() );
}
// BaseTile Flag 1
else if( UTag == "ATFLOORLEVEL" )
{
tile->SetFlag( TF_FLOORLEVEL, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "HOLDABLE" )
{
tile->SetFlag( TF_HOLDABLE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "SIGNGUILDBANNER" )
{
tile->SetFlag( TF_TRANSPARENT, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "WEBDIRTBLOOD" )
{
tile->SetFlag( TF_TRANSLUCENT, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "WALLVERTTILE" )
{
tile->SetFlag( TF_WALL, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "DAMAGING" )
{
tile->SetFlag( TF_DAMAGING, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "BLOCKING" )
{
tile->SetFlag( TF_BLOCKING, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "LIQUIDWET" )
{
tile->SetFlag( TF_WET, (std::stoi(data, nullptr, 0) != 0) );
}
// BaseTile Flag 2
else if( UTag == "UNKNOWNFLAG1" )
{
tile->SetFlag( TF_UNKNOWN1, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "STANDABLE" )
{
tile->SetFlag( TF_SURFACE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "CLIMBABLE" )
{
tile->SetFlag( TF_CLIMBABLE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "STACKABLE" )
{
tile->SetFlag( TF_STACKABLE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "WINDOWARCHDOOR" ) {
tile->SetFlag( TF_WINDOW, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "CANNOTSHOOTTHRU" )
{
tile->SetFlag( TF_NOSHOOT, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "DISPLAYASA" )
{
tile->SetFlag( TF_DISPLAYA, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "DISPLAYASAN" )
{
tile->SetFlag( TF_DISPLAYAN, (std::stoi(data, nullptr, 0) != 0) );
}
// BaseTile Flag 3
else if( UTag == "DESCRIPTIONTILE" )
{
tile->SetFlag( TF_DESCRIPTION, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "FADEWITHTRANS" )
{
tile->SetFlag( TF_FOLIAGE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "PARTIALHUE" )
{
tile->SetFlag( TF_PARTIALHUE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "UNKNOWNFLAG2" )
{
tile->SetFlag( TF_UNKNOWN2, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "MAP" )
{
tile->SetFlag( TF_MAP, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "CONTAINER" )
{
tile->SetFlag( TF_CONTAINER, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "EQUIPABLE" )
{
tile->SetFlag( TF_WEARABLE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "LIGHTSOURCE" )
{
tile->SetFlag( TF_LIGHT, (std::stoi(data, nullptr, 0) != 0) );
}
// BaseTile Flag 4
else if( UTag == "ANIMATED" )
{
tile->SetFlag( TF_ANIMATED, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "NODIAGONAL" )
{
tile->SetFlag( TF_NODIAGONAL, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "UNKNOWNFLAG3" )
{
tile->SetFlag( TF_UNKNOWN3, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "WHOLEBODYITEM" )
{
tile->SetFlag( TF_ARMOR, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "WALLROOFWEAP" )
{
tile->SetFlag( TF_ROOF, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "DOOR" )
{
tile->SetFlag( TF_DOOR, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "CLIMBABLEBIT1" )
{
tile->SetFlag( TF_STAIRBACK, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "CLIMBABLEBIT2" )
{
tile->SetFlag( TF_STAIRRIGHT, (std::stoi(data, nullptr, 0) != 0) );
}
}
}
}
else
{
//7.0.8.2 data and earlier
CTile *tile = &staticTile[entryNum];
if( tile != nullptr )
{
for( std::string tag = toScan->First(); !toScan->AtEnd(); tag = toScan->Next() )
{
data = toScan->GrabData();
data = stripTrim( data );
UTag = str_toupper( tag );
// CTile properties
if( UTag == "WEIGHT" )
{
tile->Weight( static_cast<UI08>(std::stoul(data, nullptr, 0)) );
}
else if( UTag == "HEIGHT" )
{
tile->Height( static_cast<SI08>(std::stoi(data, nullptr, 0))) ;
}
else if( UTag == "LAYER" )
{
tile->Layer( static_cast<SI08>(std::stoi(data, nullptr, 0))) ;
}
else if( UTag == "HUE" )
{
tile->Hue( static_cast<UI08>(std::stoul(data, nullptr, 0)) );
}
else if( UTag == "QUANTITY" )
{
tile->Quantity( static_cast<UI08>(std::stoul(data, nullptr, 0)) );
}
else if( UTag == "ANIMATION" )
{
tile->Animation( static_cast<UI16>(std::stoul(data, nullptr, 0)) );
}
else if( UTag == "NAME" )
{
tile->Name( data.c_str() );
}
// BaseTile Flag 1
else if( UTag == "ATFLOORLEVEL" )
{
tile->SetFlag( TF_FLOORLEVEL, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "HOLDABLE" )
{
tile->SetFlag( TF_HOLDABLE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "SIGNGUILDBANNER" )
{
tile->SetFlag( TF_TRANSPARENT, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "WEBDIRTBLOOD" )
{
tile->SetFlag( TF_TRANSLUCENT, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "WALLVERTTILE" )
{
tile->SetFlag( TF_WALL, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "DAMAGING" )
{
tile->SetFlag( TF_DAMAGING, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "BLOCKING" )
{
tile->SetFlag( TF_BLOCKING, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "LIQUIDWET" )
{
tile->SetFlag( TF_WET, (std::stoi(data, nullptr, 0) != 0) );
}
// BaseTile Flag 2
else if( UTag == "UNKNOWNFLAG1" )
{
tile->SetFlag( TF_UNKNOWN1, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "STANDABLE" )
{
tile->SetFlag( TF_SURFACE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "CLIMBABLE" )
{
tile->SetFlag( TF_CLIMBABLE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "STACKABLE" )
{
tile->SetFlag( TF_STACKABLE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "WINDOWARCHDOOR" )
{
tile->SetFlag( TF_WINDOW, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "CANNOTSHOOTTHRU" )
{
tile->SetFlag( TF_NOSHOOT, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "DISPLAYASA" )
{
tile->SetFlag( TF_DISPLAYA, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "DISPLAYASAN" )
{
tile->SetFlag( TF_DISPLAYAN, (std::stoi(data, nullptr, 0) != 0) );
}
// BaseTile Flag 3
else if( UTag == "DESCRIPTIONTILE" )
{
tile->SetFlag( TF_DESCRIPTION, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "FADEWITHTRANS" )
{
tile->SetFlag( TF_FOLIAGE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "PARTIALHUE" )
{
tile->SetFlag( TF_PARTIALHUE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "UNKNOWNFLAG2" )
{
tile->SetFlag( TF_UNKNOWN2, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "MAP" )
{
tile->SetFlag( TF_MAP, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "CONTAINER" )
{
tile->SetFlag( TF_CONTAINER, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "EQUIPABLE" )
{
tile->SetFlag( TF_WEARABLE, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "LIGHTSOURCE" )
{
tile->SetFlag( TF_LIGHT, (std::stoi(data, nullptr, 0) != 0) );
}
// BaseTile Flag 4
else if( UTag == "ANIMATED" )
{
tile->SetFlag( TF_ANIMATED, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "NODIAGONAL" )
{
tile->SetFlag( TF_NODIAGONAL, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "UNKNOWNFLAG3" )
{
tile->SetFlag( TF_UNKNOWN3, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "WHOLEBODYITEM" )
{
tile->SetFlag( TF_ARMOR, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "WALLROOFWEAP" )
{
tile->SetFlag( TF_ROOF, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "DOOR" )
{
tile->SetFlag( TF_DOOR, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "CLIMBABLEBIT1" )
{
tile->SetFlag( TF_STAIRBACK, (std::stoi(data, nullptr, 0) != 0) );
}
else if( UTag == "CLIMBABLEBIT2" )
{
tile->SetFlag( TF_STAIRRIGHT, (std::stoi(data, nullptr, 0) != 0) );
}
}
}
}
}
else if( titlePart == "LAND" && entryNum )
{ // let's not deal with this just yet
}
}
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void CTile::Read( UOXFile *toRead )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Reads and stores tiledata flags as part of loading tiledata into memory
//| Non-High Seas version
//|
//| Notes - BYTE[4] Flags (See BaseTile)
//| BYTE Weight Weight of the item, 255 means not movable)
//| BYTE Quality If Wearable, this is a Layer. If Light Source, this is Light ID.
//| BYTE[2] Unknown1
//| BYTE Unknown2
//| BYTE Quantity If Weapon, Quantity is Weapon Class. If Armor, Quantity is Armor Class.
//| BYTE[2] Animation
//| BYTE Unknown3
//| BYTE Hue
//| BYTE Unknown4
//| BYTE Unknown5
//| BYTE Height If Container, Height is "Contains" (Something determining how much the container can hold?)
//| BYTE[20] Name
//o-----------------------------------------------------------------------------------------------o
void CTile::Read( UOXFile *toRead )
{
UI32 flagsRead;
toRead->getULong( &flagsRead );
flags = flagsRead;
toRead->getUChar( &weight );
toRead->getChar( &layer );
toRead->getUShort( &unknown1 );
toRead->getUChar( &unknown2 );
toRead->getUChar( &quantity );
toRead->getUShort( &animation );
toRead->getUChar( &unknown3 );
toRead->getUChar( &hue );
toRead->getUChar( &unknown4 );
toRead->getUChar( &unknown5 );
toRead->getChar( &height );
toRead->getChar( name, 20 );
name[20] = '\0';
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void CTileHS::Read( UOXFile *toRead )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Reads and stores tiledata flags as part of loading tiledata into memory
//| High Seas version
//|
//| Notes - BYTE[4] Flags (See BaseTile)
//| BYTE[4] Unknown0
//| BYTE Weight Weight of the item, 255 means not movable)
//| BYTE Quality If Wearable, this is a Layer. If Light Source, this is Light ID.
//| BYTE[2] Unknown1
//| BYTE Unknown2
//| BYTE Quantity If Weapon, Quantity is Weapon Class. If Armor, Quantity is Armor Class.
//| BYTE[2] Animation
//| BYTE Unknown3
//| BYTE Hue
//| BYTE Unknown4
//| BYTE Unknown5
//| BYTE Height If Container, Height is "Contains" (Something determining how much the container can hold?)
//| BYTE[20] Name
//o-----------------------------------------------------------------------------------------------o
void CTileHS::Read( UOXFile *toRead )
{
UI32 flagsRead;
toRead->getULong( &flagsRead );
flags = flagsRead;
toRead->getULong( &unknown0 );
toRead->getUChar( &weight );
toRead->getChar( &layer );
toRead->getUShort( &unknown1 );
toRead->getUChar( &unknown2 );
toRead->getUChar( &quantity );
toRead->getUShort( &animation );
toRead->getUChar( &unknown3 );
toRead->getUChar( &hue );
toRead->getUChar( &unknown4 );
toRead->getUChar( &unknown5 );
toRead->getChar( &height );
toRead->getChar( name, 20 );
name[20] = '\0';
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void CLand::Read( UOXFile *toRead )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Reads and stores land tile data as part of loading tiledata into memory
//| Non-High Seas version
//|
//| Notes - BYTE[4] Flags
//| BYTE[2] TextureID
//| BYTE[20] Name
//o-----------------------------------------------------------------------------------------------o
void CLand::Read( UOXFile *toRead )
{
UI32 flagsRead;
toRead->getULong( &flagsRead );
flags = flagsRead;
toRead->getUShort( &textureID );
toRead->getChar( name, 20 );
name[20] = '\0';
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void Read( UOXFile *toRead )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Reads and stores land tile data as part of loading tiledata into memory
//| High Seas version
//|
//| Notes - BYTE[4] Flags
//| BYTE[4] Unknown
//| BYTE[2] TextureID
//| BYTE[20] Name
//o-----------------------------------------------------------------------------------------------o
void CLandHS::Read( UOXFile *toRead )
{
UI32 flagsRead;
toRead->getULong( &flagsRead );
flags = flagsRead;
toRead->getULong( &unknown1 );
toRead->getUShort( &textureID );
toRead->getChar( name, 20 );
name[20] = '\0';
}