uox3/source/mapclasses.h
Xoduz da4a32c7bd Misc fixes
Fixed an issue where casting Wall of Stone inside a multi would lead to the wall of stone never expiring, because it was not correctly marked as a field spell
Reduced combat message spam; attacking messages now only appear when attacking targets who are not already fighting the attacker
Added a new character state - "passive combat mode" - primarily used by players when they tab out of combat. Tabbing out of combat will prevent the character from retaliating in combat if they're already fighting someone
Fixed several issues with dropping items through floors, tables and generally not being placed correctly when dropped inside multis
Hard-defined the Z-level at which some jewellers in Britain spawn to deny them rooftop access (spawn_felucca_town_britain.dfn and spawn_trammel_town_britain.dfn)
Added system messages informing shard staff with elevated command privileges why they are getting 100% skill check success, and no spellcast delay
2023-03-17 16:01:22 +08:00

310 lines
8.7 KiB
C++

#ifndef __UOXMAP_CLASSES_H__
#define __UOXMAP_CLASSES_H__
#include <cstdint>
#include <sstream>
#include <array>
#include <bitset>
#include <algorithm>
#include "power.h"
#include "MultiMul.hpp"
#include "osunique.hpp"
//o------------------------------------------------------------------------------------------------o
enum TileFlags
{
// Flag: Also known as:
TF_FLOORLEVEL = 0, // "Background"
TF_HOLDABLE, // "Weapon"
TF_TRANSPARENT, // "SignGuildBanner"
TF_TRANSLUCENT, // "WebDirtBlood"
TF_WALL, // "WallVertTile"
TF_DAMAGING,
TF_BLOCKING, // "Impassable"
TF_WET, // "LiquidWet"
TF_UNKNOWN1, // "Ignored"
TF_SURFACE, // "Standable"
TF_CLIMBABLE, // "Bridge"
TF_STACKABLE, // "Generic"
TF_WINDOW, // "WindowArchDoor"
TF_NOSHOOT, // "CannotShootThru"
TF_DISPLAYA, // "Prefix A"
TF_DISPLAYAN, // "Prefix An"
TF_DESCRIPTION, // "Internal"
TF_FOLIAGE, // "FadeWithTrans"
TF_PARTIALHUE,
TF_UNKNOWN2,
TF_MAP,
TF_CONTAINER,
TF_WEARABLE, // "Equipable"
TF_LIGHT, // "LightSource"
TF_ANIMATED,
TF_NODIAGONAL, // "HoverOver" in SA clients and later, to determine if tiles can be moved on by flying gargoyles
TF_UNKNOWN3, // "NoDiagonal" in SA clients and later?
TF_ARMOR, // "WholeBodyItem"
TF_ROOF, // "WallRoofWeap"
TF_DOOR,
TF_STAIRBACK, // "ClimbableBit1"
TF_STAIRRIGHT, // "ClimbableBit2"
// Following flags were added in HS expansion? Purpose unknown
TF_ALPHABLEND,
TF_USENEWART,
TF_ARTUSED,
TF_NOSHADOW,
TF_PIXELBLEED,
TF_PLAYANIMONCE,
TF_MULTIMOVABLE,
TF_COUNT
};
//o------------------------------------------------------------------------------------------------o
// Pre declare tileinfo so we can make it a friend of CBaseTile, CTile, and CLand
class TileInfo;
//o------------------------------------------------------------------------------------------------o
// Frankly, these chould/should have been structures, There really isn't a reason to make the
// data private, and then expose everything with accessors. Just adds a lot of verbage,
// that can clutter when maintaining. Oh well, we stay compatable for now.
class CBaseTile
{
friend TileInfo;
protected:
std::bitset<64> flags; // We are going to use a 64 bit value here, so specify 64 bit.
// This one day may be changed to a vector of bools, but for now
std::string name;
public:
CBaseTile()
{
flags.reset();
}
virtual ~CBaseTile() = default;
// This doesnt seem to be used, but I wonder about DFN overloads?
//
/*
auto Flag( UI08 part ) const -> std::uint8_t
{
auto mFlags = static_cast<std::uint32_t>( flags.to_ulong() );
auto retVal = std::uint8_t( 0 );
switch( part )
{
case 0: retVal = static_cast<std::uint8_t>( mFlags >> 24 ); break;
case 1: retVal = static_cast<std::uint8_t>( mFlags >> 16 ); break;
case 2: retVal = static_cast<std::uint8_t>( mFlags >> 8 ); break;
case 3: retVal = static_cast<std::uint8_t>( mFlags % 256 ); break;
}
return retVal;
}
*/
auto Name() const -> const std::string& { return name; }
auto Name( const std::string &value ) -> void { name = value; }
auto FlagsNum() const -> std::uint32_t { return static_cast<std::uint32_t>( flags.to_ulong() ); }
auto Flags() const -> std::bitset<64> { return flags; }
void Flags( std::bitset<64> newVal ) { flags = newVal; }
bool CheckFlag( TileFlags toCheck ) const
{
if( toCheck >= TF_COUNT )
{
return false;
}
return flags.test( toCheck );
}
void SetFlag( TileFlags toSet, bool newVal )
{
if( toSet >= TF_COUNT )
{
return;
}
flags.set( toSet, newVal );
}
};
//o------------------------------------------------------------------------------------------------o
class CTile : public CBaseTile
{
private:
friend TileInfo;
std::uint8_t weight;
std::int8_t layer;
std::uint16_t unknown1;
std::uint8_t unknown2;
std::uint8_t quantity;
std::uint16_t animation;
std::uint8_t unknown3;
std::uint8_t hue;
std::uint8_t unknown4;
std::uint8_t unknown5;
std::int8_t height;
public:
CTile() :CBaseTile(), weight( 0 ), layer( 0 ), unknown1( 0 ), unknown2( 0 ), quantity( 0 ), animation( 0 ), unknown3( 0 ), hue( 0 ), unknown4( 0 ), unknown5( 0 ), height( 0 )
{
}
~CTile() = default;
auto Unknown1() const -> std::uint16_t { return unknown1; }
auto Unknown2() const -> std::uint8_t { return unknown2; }
auto Unknown3() const -> std::uint8_t { return unknown3; }
auto Unknown4() const -> std::uint8_t { return unknown4; }
auto Unknown5() const -> std::uint8_t { return unknown5; }
auto Hue() const -> std::uint8_t { return hue; }
auto Quantity() const -> std::uint8_t { return quantity; }
auto Animation() const -> std::uint16_t { return animation; }
auto Weight() const -> std::uint8_t { return weight; }
auto Layer() const -> std::int8_t { return layer; }
auto Height() const -> std::int8_t { return height; }
auto ClimbHeight( bool trueHeight = false ) const -> std::int8_t
{
if( CheckFlag( TF_CLIMBABLE ) && !trueHeight )
{
return height / 2;
}
return height;
}
void Unknown1( std::uint16_t newVal ) { unknown1 = newVal; }
void Unknown2( std::uint8_t newVal ) { unknown2 = newVal; }
void Unknown3( std::uint8_t newVal ) { unknown3 = newVal; }
void Unknown4( std::uint8_t newVal ) { unknown4 = newVal; }
void Unknown5( std::uint8_t newVal ) { unknown5 = newVal; }
void Animation( std::uint16_t newVal ) { animation = newVal; }
void Weight( std::uint8_t newVal ) { weight = newVal; }
void Layer( std::int8_t newVal ) { layer = newVal; }
void Height( std::int8_t newVal ) { height = newVal; }
void Hue( std::uint8_t newVal ) { hue = newVal; }
void Quantity( std::uint8_t newVal ) { quantity = newVal; }
};
//o------------------------------------------------------------------------------------------------o
class CLand : public CBaseTile
{
friend TileInfo;
private:
std::uint16_t textureId;
// List of road tiles, or road-related tiles, on which houses cannot be placed
constexpr static
std::array<std::uint16_t, 18> 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
};
public:
CLand() :CBaseTile(), textureId( 0 )
{
}
~CLand() = default;
auto TextureId() const -> std::uint16_t { return textureId; }
auto TextureId( std::uint16_t newVal ) -> void { textureId = newVal; }
auto IsRoadId() const -> bool
{
auto rValue = false;
for( size_t j = 0; j < roadIds.size(); j += 2 )
{
if( textureId >= roadIds[j] && textureId <= roadIds[j + 1] )
{
rValue = true;
break;
}
}
return rValue;
}
};
enum TileType_t { terrain, art, dyn };
// A structure that holds tile information. Type, id, information, altitude (if in a map), hue (if a static tile)
struct Tile_st
{
TileType_t type;
std::uint16_t tileId; // for instance, this should be a tileid_t , that would make sense!
std::int8_t altitude;
std::uint16_t staticHue;
union
{
const CTile *artInfo;
const CLand *terrainInfo;
};
constexpr static std::array<std::uint16_t, 11> terrainVoids
{
430, 431, 432,
433, 434, 475,
580, 610, 611,
612, 613
};
auto CheckFlag( TileFlags toCheck ) const -> bool
{
if( type != TileType_t::terrain )
{
return artInfo->CheckFlag( toCheck );
}
return terrainInfo->CheckFlag( toCheck );
}
Tile_st( TileType_t type = TileType_t::terrain ) :type( type ), tileId( 0 ), altitude( 0 ), staticHue( 0 ), artInfo( nullptr ) {}
auto isVoid() const -> bool
{
auto rValue = false;
if( type == TileType_t::terrain )
{
auto iter = std::find_if( terrainVoids.begin(), terrainVoids.end(), [this]( const std::uint16_t &value )
{
return tileId == value;
});
rValue = iter != terrainVoids.end();
}
return rValue;
}
auto IsMountain() const -> bool
{
auto rValue = false;
if( type != TileType_t::terrain )
{
rValue = (( tileId >= 431 ) && ( tileId <= 432 )) || (( tileId >= 467 ) && ( tileId <= 474 )) ||
(( tileId >= 543 ) && ( tileId <= 560 )) || (( tileId >= 1754 ) && ( tileId <= 1757 )) ||
(( tileId >= 1787 ) && ( tileId <= 1789 )) || (( tileId >= 1821 ) && ( tileId <= 1824 )) ||
(( tileId >= 1851 ) && ( tileId <= 1854 )) || (( tileId >= 1881 ) && ( tileId <= 1884 ));
}
return rValue;
}
auto top() -> std::int16_t
{
auto value = static_cast<int16_t>( altitude );
if( type != TileType_t::terrain )
{
auto temp = artInfo->Height();
temp = ( temp & 0x8 ? ( temp & 0xF ) >> 1 : temp & 0xF );
value += temp;
}
return value;
}
auto height() -> std::uint8_t
{
if( type != TileType_t::terrain )
{
return artInfo->Height();
}
return 0;
}
auto name() const -> std::string
{
if( type != TileType_t::terrain )
{
return artInfo->Name();
}
return terrainInfo->Name();
}
};
#endif