2019-07-07 20:56:15 +00:00
|
|
|
#include <StdAfx.h>
|
2018-03-29 17:01:57 -04:00
|
|
|
#include "WeenieObject.h"
|
|
|
|
|
#include "PhysicsObj.h"
|
|
|
|
|
#include "Monster.h"
|
|
|
|
|
#include "Player.h"
|
|
|
|
|
#include "Appraisal.h"
|
|
|
|
|
#include "PartArray.h"
|
|
|
|
|
|
|
|
|
|
//Network access.
|
|
|
|
|
#include "Client.h"
|
|
|
|
|
#include "BinaryWriter.h"
|
|
|
|
|
#include "ObjectMsgs.h"
|
|
|
|
|
#include "ClientCommands.h"
|
|
|
|
|
|
|
|
|
|
#define MESSAGE_BEGIN(x) BinaryWriter *x = new BinaryWriter
|
|
|
|
|
#define MESSAGE_END(x) return x
|
|
|
|
|
|
2020-04-29 04:05:02 +00:00
|
|
|
float roundtwodec(float var)
|
|
|
|
|
{
|
|
|
|
|
float value = (int)(var * 100 + .5);
|
|
|
|
|
return (float)value / 100;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-12 14:41:21 -07:00
|
|
|
BinaryWriter *GetWeenieObjData(CWeenieObject *pEntity)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
BinaryWriter *pWriter = new BinaryWriter;
|
|
|
|
|
|
|
|
|
|
PublicWeenieDesc *pDesc = PublicWeenieDesc::CreateFromWeenie(pEntity);
|
|
|
|
|
pDesc->Pack(pWriter);
|
|
|
|
|
delete pDesc;
|
|
|
|
|
|
|
|
|
|
return pWriter;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
BinaryWriter OptionalWeenieObjData;
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t dwSections = 0;
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
if (pEntity->Container_HasContents())
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_ItemsCapacity;
|
|
|
|
|
OptionalWeenieObjData.Write<BYTE>(pEntity->Container_MaxInventorySlots()); // item capacity
|
|
|
|
|
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_ContainersCapacity;
|
|
|
|
|
OptionalWeenieObjData.Write<BYTE>(pEntity->Container_MaxContainerSlots()); // container capacity
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int value = 0;
|
|
|
|
|
if (pEntity->m_Qualities.InqInt(VALUE_INT, value, FALSE, FALSE))
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_Value;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalWeenieObjData.Write<uint32_t>(value);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int useability = 0;
|
|
|
|
|
if (pEntity->m_Qualities.InqInt(ITEM_USEABLE_INT, useability))
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_Useability;
|
|
|
|
|
OptionalWeenieObjData.Write<int>(useability);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double useRadius;
|
|
|
|
|
if (pEntity->m_Qualities.InqFloat(USE_RADIUS_FLOAT, useRadius))
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_UseRadius;
|
|
|
|
|
OptionalWeenieObjData.Write<float>(useRadius);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_TargetType != 0)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_TargetType;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalWeenieObjData.Write<uint32_t>(pEntity->m_TargetType);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_UIEffects)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_UIEffects;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalWeenieObjData.Write<uint32_t>(pEntity->m_UIEffects);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->HasEquipType())
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_CombatUse;
|
|
|
|
|
OptionalWeenieObjData.Write<BYTE>((BYTE)pEntity->GetEquipType());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->IsContained())
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_ContainerID;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalWeenieObjData.Write<uint32_t>(pEntity->GetContainerID());
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->HasCoverage())
|
|
|
|
|
{
|
|
|
|
|
CBaseItem *pItem = (CBaseItem*)pEntity;
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t dwCoverage1 = pItem->GetCoverage1();
|
|
|
|
|
uint32_t dwCoverage2 = pItem->GetCoverage2();
|
|
|
|
|
uint32_t dwCoverage3 = pItem->GetCoverage3();
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
if (dwCoverage1)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_ValidLocations;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalWeenieObjData.Write<uint32_t>(dwCoverage1);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
if (dwCoverage2)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_Location;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalWeenieObjData.Write<uint32_t>(dwCoverage2);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
if (dwCoverage3)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_Priority;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalWeenieObjData.Write<uint32_t>(dwCoverage3);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int blipColor = 0;
|
|
|
|
|
if (pEntity->m_Qualities.InqInt(RADARBLIP_COLOR_INT, blipColor))
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_BlipColor;
|
|
|
|
|
OptionalWeenieObjData.Write<BYTE>(blipColor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int showRadar;
|
|
|
|
|
if (pEntity->m_Qualities.InqInt(SHOWABLE_ON_RADAR_INT, showRadar))
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_RadarEnum;
|
|
|
|
|
OptionalWeenieObjData.Write<BYTE>((BYTE)showRadar);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int burden = 0;
|
|
|
|
|
if (pEntity->m_Qualities.InqInt(ENCUMB_VAL_INT, value, FALSE, FALSE))
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_Burden;
|
|
|
|
|
OptionalWeenieObjData.Write<WORD>(burden);
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-30 19:57:04 -07:00
|
|
|
WORD spell_id = (WORD)pEntity->GetSpellID();
|
2018-03-29 17:01:57 -04:00
|
|
|
if (spell_id)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PublicWeenieDescPackHeader::PWD_Packed_SpellID;
|
|
|
|
|
OptionalWeenieObjData.Write<WORD>(spell_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BinaryWriter *WeenieObjData = new BinaryWriter;
|
2019-07-07 20:56:15 +00:00
|
|
|
WeenieObjData->Write<uint32_t>(dwSections);
|
2018-03-29 17:01:57 -04:00
|
|
|
WeenieObjData->WriteString(pEntity->GetName().c_str());
|
2019-07-07 20:56:15 +00:00
|
|
|
WeenieObjData->WritePackeduint32_t(pEntity->m_Qualities.id);
|
2018-04-30 19:57:04 -07:00
|
|
|
WeenieObjData->Pack_AsDataIDOfKnownType(0x06000000, 0x06000000 | pEntity->GetIcon());
|
2019-07-07 20:56:15 +00:00
|
|
|
WeenieObjData->Write<uint32_t>(pEntity->GetItemType());
|
|
|
|
|
WeenieObjData->Write<uint32_t>(pEntity->m_WeenieBitfield);
|
2018-03-29 17:01:57 -04:00
|
|
|
WeenieObjData->Align();
|
|
|
|
|
|
|
|
|
|
WeenieObjData->Write(&OptionalWeenieObjData);
|
|
|
|
|
|
|
|
|
|
return WeenieObjData;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-12 14:41:21 -07:00
|
|
|
BinaryWriter *GetPhysicsObjData(CWeenieObject *pEntity)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
BinaryWriter OptionalPhysicsObjData;
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t dwSections = 0; //0x019803
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
if (pEntity->movement_manager)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::MOVEMENT;
|
|
|
|
|
|
|
|
|
|
BinaryWriter *AnimInfo = pEntity->Animation_GetAnimationInfo();
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalPhysicsObjData.Write<uint32_t>(AnimInfo->GetSize());
|
2018-03-29 17:01:57 -04:00
|
|
|
OptionalPhysicsObjData.Write(AnimInfo);
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalPhysicsObjData.Write<uint32_t>(pEntity->last_move_was_autonomous); // autonomous movement?
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
delete AnimInfo;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::ANIMFRAME_ID;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalPhysicsObjData.Write<uint32_t>(pEntity->GetPlacementFrameID());
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!pEntity->HasOwner())
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::POSITION;
|
|
|
|
|
OptionalPhysicsObjData.Write(&pEntity->m_Position);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t motion_table = 0;
|
2018-05-21 23:20:21 +01:00
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
if (pEntity->m_Qualities.InqDataID(MOTION_TABLE_DID, motion_table) && motion_table)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::MTABLE;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalPhysicsObjData.Write<uint32_t>(motion_table);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t sound_table = 0;
|
2018-03-29 17:01:57 -04:00
|
|
|
if (pEntity->m_Qualities.InqDataID(SOUND_TABLE_DID, sound_table) && sound_table)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::STABLE;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalPhysicsObjData.Write<uint32_t>(sound_table);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t pe_table = 0;
|
2018-03-29 17:01:57 -04:00
|
|
|
if (pEntity->m_Qualities.InqDataID(PHYSICS_EFFECT_TABLE_DID, pe_table) && pe_table)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::PETABLE;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalPhysicsObjData.Write<uint32_t>(pe_table);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t setup_id = 0;
|
2018-03-29 17:01:57 -04:00
|
|
|
if (pEntity->m_Qualities.InqDataID(SETUP_DID, setup_id) && setup_id)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::CSETUP;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalPhysicsObjData.Write<uint32_t>(setup_id);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
2018-07-12 14:41:21 -07:00
|
|
|
if (pEntity->parent)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::PARENT;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalPhysicsObjData.Write<uint32_t>(pEntity->parent->id);
|
|
|
|
|
OptionalPhysicsObjData.Write<uint32_t>(pEntity->InqIntQuality(PARENT_LOCATION_INT, 0));
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->children && pEntity->children->num_objects)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::CHILDREN;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalPhysicsObjData.Write<uint32_t>(pEntity->children->num_objects);
|
2018-03-29 17:01:57 -04:00
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
for (uint32_t i = 0; i < pEntity->children->num_objects; i++)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalPhysicsObjData.Write<uint32_t>(pEntity->children->objects.array_data[i]->id);
|
|
|
|
|
OptionalPhysicsObjData.Write<uint32_t>(pEntity->children->location_ids.array_data[i]);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_scale != 0.0f && pEntity->m_scale != 1.0f)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::OBJSCALE;
|
|
|
|
|
OptionalPhysicsObjData.Write<float>(pEntity->m_scale);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_fFriction != CWeenieObject::DEFAULT_FRICTION)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::FRICTION;
|
|
|
|
|
OptionalPhysicsObjData.Write<float>(pEntity->m_fFriction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_fElasticity != CWeenieObject::DEFAULT_ELASTICITY)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::ELASTICITY;
|
|
|
|
|
OptionalPhysicsObjData.Write<float>(pEntity->m_fElasticity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_fTranslucency != CWeenieObject::DEFAULT_TRANSLUCENCY)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::TRANSLUCENCY;
|
|
|
|
|
OptionalPhysicsObjData.Write<float>(pEntity->m_fTranslucency);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_velocityVector != Vector(0, 0, 0))
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::VELOCITY;
|
|
|
|
|
pEntity->m_velocityVector.Pack(&OptionalPhysicsObjData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_Acceleration != Vector(0, 0, 0))
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::ACCELERATION;
|
|
|
|
|
pEntity->m_Acceleration.Pack(&OptionalPhysicsObjData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_Omega != Vector(0, 0, 0))
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::OMEGA;
|
|
|
|
|
pEntity->m_Omega.Pack(&OptionalPhysicsObjData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_DefaultScript != 0)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::DEFAULT_SCRIPT;
|
2019-07-07 20:56:15 +00:00
|
|
|
OptionalPhysicsObjData.Write<uint32_t>(pEntity->m_DefaultScript);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_DefaultScriptIntensity != 0)
|
|
|
|
|
{
|
|
|
|
|
dwSections |= PhysicsDescInfo::DEFAULT_SCRIPT_INTENSITY;
|
|
|
|
|
OptionalPhysicsObjData.Write<float>(pEntity->m_DefaultScriptIntensity);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BinaryWriter *PhysicsObjData = new BinaryWriter;
|
2019-07-07 20:56:15 +00:00
|
|
|
PhysicsObjData->Write<uint32_t>(dwSections);
|
|
|
|
|
PhysicsObjData->Write<uint32_t>(pEntity->m_PhysicsState); //VIS flags
|
2018-03-29 17:01:57 -04:00
|
|
|
PhysicsObjData->Write(&OptionalPhysicsObjData);
|
|
|
|
|
|
|
|
|
|
//Moved from CO
|
|
|
|
|
PhysicsObjData->Write<WORD>(pEntity->_position_timestamp);
|
|
|
|
|
PhysicsObjData->Write<WORD>(pEntity->_movement_timestamp);
|
|
|
|
|
PhysicsObjData->Write<WORD>(pEntity->_state_timestamp);
|
|
|
|
|
PhysicsObjData->Write<WORD>(pEntity->_vector_timestamp);
|
|
|
|
|
PhysicsObjData->Write<WORD>(pEntity->_teleport_timestamp);
|
|
|
|
|
PhysicsObjData->Write<WORD>(pEntity->_server_control_timestamp);
|
|
|
|
|
PhysicsObjData->Write<WORD>(pEntity->_force_position_timestamp);
|
|
|
|
|
PhysicsObjData->Write<WORD>(pEntity->_objdesc_timestamp);
|
|
|
|
|
PhysicsObjData->Write<WORD>(pEntity->_instance_timestamp);
|
|
|
|
|
|
|
|
|
|
PhysicsObjData->Align();
|
|
|
|
|
|
|
|
|
|
return PhysicsObjData;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-12 14:41:21 -07:00
|
|
|
BinaryWriter *CreateObject(CWeenieObject *pEntity)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
BinaryWriter *CO = new BinaryWriter;
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
CO->Write<uint32_t>(0xF745);
|
|
|
|
|
CO->Write<uint32_t>(pEntity->GetID());
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
ObjDesc objDesc;
|
|
|
|
|
pEntity->GetObjDesc(objDesc);
|
|
|
|
|
objDesc.Pack(CO);
|
|
|
|
|
|
|
|
|
|
BinaryWriter *PhysicsObjData = GetPhysicsObjData(pEntity);
|
|
|
|
|
CO->Write(PhysicsObjData);
|
|
|
|
|
delete PhysicsObjData;
|
|
|
|
|
|
|
|
|
|
BinaryWriter *WeenieObjData = GetWeenieObjData(pEntity);
|
|
|
|
|
CO->Write(WeenieObjData);
|
|
|
|
|
delete WeenieObjData;
|
|
|
|
|
|
|
|
|
|
CO->Align();
|
|
|
|
|
return CO;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-12 14:41:21 -07:00
|
|
|
BinaryWriter *UpdateObject(CWeenieObject *pEntity)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
BinaryWriter *UO = new BinaryWriter;
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
UO->Write<uint32_t>(0xF7DB);
|
|
|
|
|
UO->Write<uint32_t>(pEntity->GetID());
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
ObjDesc objDesc;
|
|
|
|
|
pEntity->GetObjDesc(objDesc);
|
|
|
|
|
objDesc.Pack(UO);
|
|
|
|
|
|
|
|
|
|
pEntity->_objdesc_timestamp++;
|
|
|
|
|
pEntity->_teleport_timestamp++;
|
|
|
|
|
pEntity->_movement_timestamp++;
|
|
|
|
|
pEntity->_state_timestamp++;
|
|
|
|
|
pEntity->_vector_timestamp++;
|
|
|
|
|
pEntity->_position_timestamp++;
|
|
|
|
|
pEntity->_server_control_timestamp++;
|
|
|
|
|
pEntity->_force_position_timestamp++;
|
|
|
|
|
pEntity->_objdesc_timestamp++;
|
|
|
|
|
|
|
|
|
|
BinaryWriter *PhysicsObjData = GetPhysicsObjData(pEntity);
|
|
|
|
|
UO->Write(PhysicsObjData);
|
|
|
|
|
delete PhysicsObjData;
|
|
|
|
|
|
|
|
|
|
BinaryWriter *WeenieObjData = GetWeenieObjData(pEntity);
|
|
|
|
|
UO->Write(WeenieObjData);
|
|
|
|
|
delete WeenieObjData;
|
|
|
|
|
|
|
|
|
|
UO->Align();
|
|
|
|
|
return UO;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-12 14:41:21 -07:00
|
|
|
BinaryWriter *IdentifyObjectFail(CWeenieObject *pEntity, bool bShowLevel)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
BinaryWriter *pWriter = new BinaryWriter;
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
pWriter->Write<uint32_t>(0xC9); // message ID
|
|
|
|
|
pWriter->Write<uint32_t>(pEntity->GetID());
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
AppraisalProfile profile;
|
|
|
|
|
profile.success_flag = FALSE;
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_Qualities.m_IntStats)
|
|
|
|
|
{
|
|
|
|
|
profile._intStatsTable = new PackableHashTableWithJson<STypeInt, int>();
|
|
|
|
|
*profile._intStatsTable = *pEntity->m_Qualities.m_IntStats;
|
|
|
|
|
|
|
|
|
|
for (PackableHashTableWithJson<STypeInt, int>::iterator i = profile._intStatsTable->begin(); i != profile._intStatsTable->end(); )
|
|
|
|
|
{
|
|
|
|
|
switch (i->first)
|
|
|
|
|
{
|
|
|
|
|
case CREATURE_TYPE_INT:
|
|
|
|
|
case ENCUMB_VAL_INT:
|
|
|
|
|
case PLAYER_KILLER_STATUS_INT:
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i->first == LEVEL_INT && bShowLevel)
|
|
|
|
|
{
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i = profile._intStatsTable->erase(i);
|
|
|
|
|
}
|
2018-04-30 19:57:04 -07:00
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
if (pEntity->m_Qualities._enchantment_reg)
|
|
|
|
|
{
|
|
|
|
|
for (auto &entry : *profile._intStatsTable)
|
|
|
|
|
{
|
|
|
|
|
pEntity->m_Qualities._enchantment_reg->EnchantInt(entry.first, &entry.second, FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (profile._intStatsTable->empty())
|
|
|
|
|
{
|
|
|
|
|
delete profile._intStatsTable;
|
|
|
|
|
profile._intStatsTable = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-04-30 19:57:04 -07:00
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
if (pEntity->m_Qualities.m_BoolStats)
|
|
|
|
|
{
|
|
|
|
|
profile._boolStatsTable = new PackableHashTableWithJson<STypeBool, BOOL>();
|
|
|
|
|
*profile._boolStatsTable = *pEntity->m_Qualities.m_BoolStats;
|
|
|
|
|
|
|
|
|
|
for (PackableHashTableWithJson<STypeBool, BOOL>::iterator i = profile._boolStatsTable->begin(); i != profile._boolStatsTable->end(); )
|
|
|
|
|
{
|
|
|
|
|
switch (i->first)
|
|
|
|
|
{
|
|
|
|
|
case OPEN_BOOL:
|
|
|
|
|
case LOCKED_BOOL:
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i = profile._boolStatsTable->erase(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (profile._boolStatsTable->empty())
|
|
|
|
|
{
|
|
|
|
|
delete profile._boolStatsTable;
|
|
|
|
|
profile._boolStatsTable = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_Qualities.m_StringStats)
|
|
|
|
|
{
|
|
|
|
|
profile._strStatsTable = new PackableHashTableWithJson<STypeString, std::string>();
|
|
|
|
|
*profile._strStatsTable = *pEntity->m_Qualities.m_StringStats;
|
|
|
|
|
|
|
|
|
|
for (PackableHashTableWithJson<STypeString, std::string>::iterator i = profile._strStatsTable->begin(); i != profile._strStatsTable->end(); )
|
|
|
|
|
{
|
|
|
|
|
switch (i->first)
|
|
|
|
|
{
|
|
|
|
|
case USE_STRING:
|
|
|
|
|
case TEMPLATE_STRING:
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i = profile._strStatsTable->erase(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (profile._strStatsTable->empty())
|
|
|
|
|
{
|
|
|
|
|
delete profile._strStatsTable;
|
|
|
|
|
profile._strStatsTable = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_Qualities.m_DIDStats)
|
|
|
|
|
{
|
2019-07-07 20:56:15 +00:00
|
|
|
profile._didStatsTable = new PackableHashTableWithJson<STypeDID, uint32_t>();
|
2018-03-29 17:01:57 -04:00
|
|
|
*profile._didStatsTable = *pEntity->m_Qualities.m_DIDStats;
|
2018-04-30 19:57:04 -07:00
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
for (PackableHashTableWithJson<STypeDID, uint32_t>::iterator i = profile._didStatsTable->begin(); i != profile._didStatsTable->end(); )
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
switch (i->first)
|
|
|
|
|
{
|
|
|
|
|
case EYES_PALETTE_DID:
|
|
|
|
|
case EYES_TEXTURE_DID:
|
|
|
|
|
case HAIR_PALETTE_DID:
|
|
|
|
|
case NOSE_TEXTURE_DID:
|
|
|
|
|
case SKIN_PALETTE_DID:
|
|
|
|
|
case MOUTH_TEXTURE_DID:
|
|
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i = profile._didStatsTable->erase(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (profile._didStatsTable->empty())
|
|
|
|
|
{
|
|
|
|
|
delete profile._didStatsTable;
|
|
|
|
|
profile._didStatsTable = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->IsCreature())
|
|
|
|
|
{
|
|
|
|
|
profile.creature_profile = new CreatureAppraisalProfile();
|
2018-04-30 19:57:04 -07:00
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
auto setCreatureProfileAttribute2nd = [&](STypeAttribute2nd attrib2nd, uint32_t &value, uint32_t &bitfield)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t raw = 0;
|
2018-03-29 17:01:57 -04:00
|
|
|
pEntity->m_Qualities.InqAttribute2nd(attrib2nd, raw, TRUE);
|
|
|
|
|
pEntity->m_Qualities.InqAttribute2nd(attrib2nd, value, FALSE);
|
|
|
|
|
|
|
|
|
|
if (raw != value)
|
|
|
|
|
{
|
|
|
|
|
switch (attrib2nd)
|
|
|
|
|
{
|
|
|
|
|
case MAX_HEALTH_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_HEALTH; break;
|
|
|
|
|
case MAX_STAMINA_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_STAMINA; break;
|
|
|
|
|
case MAX_MANA_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_MANA; break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value > raw)
|
|
|
|
|
{
|
|
|
|
|
switch (attrib2nd)
|
|
|
|
|
{
|
|
|
|
|
case MAX_HEALTH_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_HEALTH_HI; break;
|
|
|
|
|
case MAX_STAMINA_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_STAMINA_HI; break;
|
|
|
|
|
case MAX_MANA_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_MANA_HI; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
setCreatureProfileAttribute2nd(HEALTH_ATTRIBUTE_2ND, profile.creature_profile->health, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
setCreatureProfileAttribute2nd(MAX_HEALTH_ATTRIBUTE_2ND, profile.creature_profile->max_health, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pWriter->Write(&profile);
|
|
|
|
|
|
|
|
|
|
return pWriter;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
BinaryWriter *IdentifyObject(CWeenieObject *pSource, CWeenieObject *pEntity, uint32_t overrideId)
|
2018-04-30 19:57:04 -07:00
|
|
|
{
|
2018-03-29 17:01:57 -04:00
|
|
|
BinaryWriter *pWriter = new BinaryWriter;
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
pWriter->Write<uint32_t>(0xC9); // message ID
|
2018-04-30 19:57:04 -07:00
|
|
|
if (overrideId)
|
2019-07-07 20:56:15 +00:00
|
|
|
pWriter->Write<uint32_t>(overrideId);
|
2018-03-29 17:01:57 -04:00
|
|
|
else
|
2019-07-07 20:56:15 +00:00
|
|
|
pWriter->Write<uint32_t>(pEntity->GetID());
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
AppraisalProfile profile;
|
|
|
|
|
|
|
|
|
|
// always true for now
|
|
|
|
|
profile.success_flag = TRUE;
|
|
|
|
|
|
|
|
|
|
BOOL bIsSourceAdmin = FALSE;
|
|
|
|
|
BOOL bIsPlayer = FALSE;
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t characterOptions;
|
|
|
|
|
uint32_t characterOptions2;
|
2018-03-29 17:01:57 -04:00
|
|
|
|
2018-07-12 14:41:21 -07:00
|
|
|
if (CPlayerWeenie *pPlayerSource = pSource->AsPlayer())
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
bIsSourceAdmin = pPlayerSource->GetAccessLevel() >= ADMIN_ACCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-12 14:41:21 -07:00
|
|
|
if (CPlayerWeenie *pPlayer = pEntity->AsPlayer())
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
bIsPlayer = true;
|
|
|
|
|
characterOptions = pPlayer->GetCharacterOptions();
|
|
|
|
|
characterOptions2 = pPlayer->GetCharacterOptions2();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_Qualities.m_IntStats)
|
|
|
|
|
{
|
|
|
|
|
profile._intStatsTable = new PackableHashTableWithJson<STypeInt, int>();
|
|
|
|
|
*profile._intStatsTable = *pEntity->m_Qualities.m_IntStats;
|
2018-04-30 19:57:04 -07:00
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
profile._intStatsTable->remove(PHYSICS_STATE_INT);
|
|
|
|
|
profile._intStatsTable->remove(XP_OVERRIDE_INT);
|
|
|
|
|
profile._intStatsTable->remove(MAX_GENERATED_OBJECTS_INT);
|
2018-11-23 11:38:02 -06:00
|
|
|
profile._intStatsTable->remove(ITEM_TYPE_INT);
|
|
|
|
|
profile._intStatsTable->remove(MASS_INT);
|
|
|
|
|
profile._intStatsTable->remove(ITEM_USEABLE_INT);
|
2020-03-21 09:23:59 -07:00
|
|
|
profile._intStatsTable->remove(STACK_UNIT_MASS_INT);
|
|
|
|
|
profile._intStatsTable->remove(ARMOR_TYPE_INT);
|
|
|
|
|
profile._intStatsTable->remove(TSYS_MUTATION_DATA_INT);
|
|
|
|
|
profile._intStatsTable->remove(RESIST_ITEM_APPRAISAL_INT);
|
|
|
|
|
profile._intStatsTable->remove(GENERATOR_TYPE_INT);
|
|
|
|
|
profile._intStatsTable->remove(GENERATOR_DESTRUCTION_TYPE_INT);
|
|
|
|
|
profile._intStatsTable->remove(GENERATOR_TIME_TYPE_INT);
|
|
|
|
|
profile._intStatsTable->remove(GENERATOR_START_TIME_INT);
|
|
|
|
|
profile._intStatsTable->remove(GENERATOR_END_TIME_INT);
|
|
|
|
|
profile._intStatsTable->remove(GENERATOR_END_DESTRUCTION_TYPE_INT);
|
|
|
|
|
profile._intStatsTable->remove(INIT_GENERATED_OBJECTS_INT);
|
|
|
|
|
profile._intStatsTable->remove(ACTIVATION_CREATE_CLASS_INT);
|
|
|
|
|
profile._intStatsTable->remove(ACTIVATION_RESPONSE_INT);
|
|
|
|
|
profile._intStatsTable->remove(ACTIVE_INT);
|
|
|
|
|
profile._intStatsTable->remove(VENDOR_HAPPY_MEAN_INT);
|
|
|
|
|
profile._intStatsTable->remove(VENDOR_HAPPY_VARIANCE_INT);
|
|
|
|
|
profile._intStatsTable->remove(VENDOR_HAPPY_MAX_ITEMS_INT);
|
|
|
|
|
profile._intStatsTable->remove(AI_OPTIONS_INT);
|
|
|
|
|
profile._intStatsTable->remove(TOLERANCE_INT);
|
|
|
|
|
profile._intStatsTable->remove(TARGETING_TACTIC_INT);
|
|
|
|
|
profile._intStatsTable->remove(AI_ALLOWED_COMBAT_STYLE_INT);
|
|
|
|
|
profile._intStatsTable->remove(COMBAT_MODE_INT);
|
|
|
|
|
profile._intStatsTable->remove(FRIEND_TYPE_INT);
|
|
|
|
|
profile._intStatsTable->remove(FOE_TYPE_INT);
|
|
|
|
|
profile._intStatsTable->remove(HOUSE_MAX_HOOKS_USABLE_INT);
|
|
|
|
|
profile._intStatsTable->remove(HOUSE_CURRENT_HOOKS_USABLE_INT);
|
|
|
|
|
profile._intStatsTable->remove(HOUSE_TYPE_INT);
|
|
|
|
|
profile._intStatsTable->remove(PK_LEVEL_MODIFIER_INT);
|
|
|
|
|
|
2018-09-13 20:35:46 -05:00
|
|
|
if (pEntity->m_Qualities.GetInt(ITEM_TYPE_INT, 0) == ITEM_TYPE::TYPE_TINKERING_MATERIAL)
|
|
|
|
|
{
|
|
|
|
|
profile._intStatsTable->remove(STRUCTURE_INT);
|
|
|
|
|
profile._intStatsTable->remove(MAX_STRUCTURE_INT);
|
|
|
|
|
}
|
2018-04-03 21:38:10 -04:00
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
if (bIsPlayer)
|
|
|
|
|
{
|
|
|
|
|
if (!(characterOptions2 & DisplayAge_CharacterOptions2))
|
|
|
|
|
profile._intStatsTable->remove(AGE_INT);
|
|
|
|
|
if (!(characterOptions2 & DisplayNumberDeaths_CharacterOptions2))
|
|
|
|
|
profile._intStatsTable->remove(NUM_DEATHS_INT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->AsCaster())
|
|
|
|
|
{
|
|
|
|
|
profile._intStatsTable->remove(DAMAGE_INT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_Qualities._enchantment_reg)
|
|
|
|
|
{
|
|
|
|
|
for (auto &entry : *profile._intStatsTable)
|
|
|
|
|
{
|
|
|
|
|
pEntity->m_Qualities._enchantment_reg->EnchantInt(entry.first, &entry.second, FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-30 19:57:04 -07:00
|
|
|
if (int skillActivationType = (int)pEntity->m_Qualities.GetDID(ITEM_SKILL_LIMIT_DID, 0))
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
profile._intStatsTable->add(APPRAISAL_ITEM_SKILL_INT, &skillActivationType);
|
|
|
|
|
}
|
2018-04-30 19:57:04 -07:00
|
|
|
|
|
|
|
|
int* shieldLoc = profile._intStatsTable->lookup(LOCATIONS_INT);
|
|
|
|
|
|
|
|
|
|
if (shieldLoc && *shieldLoc == static_cast<int>(INVENTORY_LOC::SHIELD_LOC))
|
|
|
|
|
{
|
|
|
|
|
SKILL_ADVANCEMENT_CLASS sac = SKILL_ADVANCEMENT_CLASS::UNTRAINED_SKILL_ADVANCEMENT_CLASS;
|
|
|
|
|
pSource->m_Qualities.InqSkillAdvancementClass(SHIELD_SKILL, sac);
|
|
|
|
|
|
2019-02-09 19:12:30 +00:00
|
|
|
int *armorLevel = profile._intStatsTable->lookup(ARMOR_LEVEL_INT);
|
|
|
|
|
if (armorLevel)
|
2018-04-30 19:57:04 -07:00
|
|
|
{
|
2019-02-09 19:12:30 +00:00
|
|
|
|
|
|
|
|
if (sac == SPECIALIZED_SKILL_ADVANCEMENT_CLASS)
|
|
|
|
|
{
|
|
|
|
|
profile._intStatsTable->add(SHIELD_VALUE_INT, armorLevel);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int *halfShieldValue = armorLevel;
|
|
|
|
|
int halfTrueValue = *halfShieldValue;
|
|
|
|
|
halfTrueValue /= 2;
|
|
|
|
|
profile._intStatsTable->add(SHIELD_VALUE_INT, &halfTrueValue);
|
|
|
|
|
}
|
2018-04-30 19:57:04 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-09 00:21:21 +00:00
|
|
|
if (pEntity->m_Qualities.GetInt(LIFESPAN_INT, 0) && pEntity->_timeToRot)
|
|
|
|
|
{
|
|
|
|
|
int newLifespan = (int)(pEntity->_timeToRot - Timer::cur_time);
|
|
|
|
|
profile._intStatsTable->add(REMAINING_LIFESPAN_INT, &newLifespan); // Update the remaining_lifespan_int for inspect window.
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:38:02 -06:00
|
|
|
if (pEntity->InqBoolQuality(LOCKED_BOOL, 0))
|
|
|
|
|
{
|
|
|
|
|
Skill skill;
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t lockpickSkill = 0;
|
2018-11-23 11:38:02 -06:00
|
|
|
|
|
|
|
|
pSource->m_Qualities.InqSkill(LOCKPICK_SKILL, skill);
|
2020-07-24 18:51:30 +00:00
|
|
|
pSource->InqSkill(LOCKPICK_SKILL, lockpickSkill, FALSE);
|
2018-11-23 11:38:02 -06:00
|
|
|
|
|
|
|
|
if (skill._sac >= TRAINED_SKILL_ADVANCEMENT_CLASS)
|
|
|
|
|
{
|
2020-07-24 18:51:30 +00:00
|
|
|
int success = (int)(100.0 * GetSkillChance(lockpickSkill, pEntity->InqIntQuality(RESIST_LOCKPICK_INT, 0)));
|
2018-11-23 11:38:02 -06:00
|
|
|
profile._intStatsTable->add(APPRAISAL_LOCKPICK_SUCCESS_PERCENT_INT, &success); // Update the lockpick success chance for inspect window.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_Qualities.m_Int64Stats)
|
|
|
|
|
{
|
2019-07-07 20:56:15 +00:00
|
|
|
profile._int64StatsTable = new PackableHashTableWithJson<STypeInt64, int64_t>();
|
2018-03-29 17:01:57 -04:00
|
|
|
*profile._int64StatsTable = *pEntity->m_Qualities.m_Int64Stats;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_Qualities.m_BoolStats)
|
|
|
|
|
{
|
|
|
|
|
profile._boolStatsTable = new PackableHashTableWithJson<STypeBool, int>();
|
|
|
|
|
*profile._boolStatsTable = *pEntity->m_Qualities.m_BoolStats;
|
2018-04-30 19:57:04 -07:00
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
profile._boolStatsTable->remove(REPORT_COLLISIONS_AS_ENVIRONMENT_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(ATTACKABLE_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(IS_HOT_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(AFFECTS_AIS_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(UI_HIDDEN_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(GRAVITY_STATUS_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(ETHEREAL_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(IGNORE_COLLISIONS_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(REPORT_COLLISIONS_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(STUCK_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(VISIBILITY_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(LIGHTS_STATUS_BOOL);
|
2018-09-27 22:06:01 -05:00
|
|
|
profile._boolStatsTable->remove(CORPSE_GENERATED_RARE_BOOL);
|
2018-11-23 11:38:02 -06:00
|
|
|
profile._boolStatsTable->remove(RESET_MESSAGE_PENDING_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(DEFAULT_LOCKED_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(DEFAULT_OPEN_BOOL);
|
2020-03-21 09:23:59 -07:00
|
|
|
profile._boolStatsTable->remove(AI_USES_MANA_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(NEVER_FAIL_CASTING_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(VENDOR_SERVICE_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(AI_IMMOBILE_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(IGNORE_MAGIC_RESIST_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(IGNORE_MAGIC_ARMOR_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(DONT_TURN_OR_MOVE_WHEN_GIVING_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(NPC_LOOKS_LIKE_OBJECT_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(NO_CORPSE_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(AI_IMMOBILE_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(ALLOW_GIVE_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(ALLOW_EDGE_SLIDE_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(IS_DYNAMIC_BOOL);
|
|
|
|
|
profile._boolStatsTable->remove(NODRAW_BOOL);
|
|
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_Qualities.m_FloatStats)
|
|
|
|
|
{
|
|
|
|
|
profile._floatStatsTable = new PackableHashTableWithJson<STypeFloat, double>();
|
|
|
|
|
*profile._floatStatsTable = *pEntity->m_Qualities.m_FloatStats;
|
|
|
|
|
|
|
|
|
|
profile._floatStatsTable->remove(HEARTBEAT_INTERVAL_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(HEARTBEAT_TIMESTAMP_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(OBVIOUS_RADAR_RANGE_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(HOTSPOT_CYCLE_TIME_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(HOTSPOT_CYCLE_TIME_VARIANCE_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(DEFAULT_SCALE_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(RESET_INTERVAL_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(REGENERATION_INTERVAL_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(USE_RADIUS_FLOAT);
|
2018-11-23 11:38:02 -06:00
|
|
|
profile._floatStatsTable->remove(CREATION_TIMESTAMP_FLOAT);
|
2020-03-21 09:23:59 -07:00
|
|
|
profile._floatStatsTable->remove(START_TIME_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(STOP_TIME_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(GENERATOR_RADIUS_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(GENERATOR_INITIAL_DELAY_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(LOCKPICK_MOD_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(BULK_MOD_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(SIZE_MOD_FLOAT);
|
|
|
|
|
profile._floatStatsTable->remove(MINIMUM_TIME_SINCE_PK_FLOAT);
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
double *weapon_defense = profile._floatStatsTable->lookup(WEAPON_DEFENSE_FLOAT);
|
|
|
|
|
double old_weapon_defense = weapon_defense ? *weapon_defense : 1.0;
|
2018-08-05 22:50:43 -05:00
|
|
|
double *mana_con = profile._floatStatsTable->lookup(MANA_CONVERSION_MOD_FLOAT);
|
|
|
|
|
double old_mana_con = mana_con ? *mana_con : 0.0;
|
|
|
|
|
double *elemental_dmg = profile._floatStatsTable->lookup(ELEMENTAL_DAMAGE_MOD_FLOAT);
|
|
|
|
|
double old_elemental_dmg = elemental_dmg ? *elemental_dmg : 0.0;
|
|
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
if (pEntity->m_Qualities._enchantment_reg)
|
|
|
|
|
{
|
|
|
|
|
for (auto &entry : *profile._floatStatsTable)
|
|
|
|
|
{
|
|
|
|
|
pEntity->m_Qualities._enchantment_reg->EnchantFloat(entry.first, &entry.second);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// special case scenarios for item buffs...
|
|
|
|
|
if (weapon_defense)
|
|
|
|
|
{
|
2020-07-18 20:23:53 -07:00
|
|
|
*weapon_defense = pEntity->GetMeleeDefenseMod();
|
2018-03-29 17:01:57 -04:00
|
|
|
|
2018-08-24 02:35:14 -05:00
|
|
|
// Don't enchant Ammunition
|
|
|
|
|
if ((fabs(*weapon_defense - old_weapon_defense) >= F_EPSILON) && pEntity->m_Qualities.m_WeenieType != Ammunition_WeenieType)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
profile.weapon_ench_bitfield |= BF_WEAPON_DEFENSE;
|
|
|
|
|
if (*weapon_defense > old_weapon_defense)
|
|
|
|
|
profile.weapon_ench_bitfield |= BF_WEAPON_DEFENSE_HI;
|
|
|
|
|
}
|
2020-07-18 11:17:01 -07:00
|
|
|
*weapon_defense = roundtwodec(*weapon_defense);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
2018-08-05 22:50:43 -05:00
|
|
|
if (mana_con)
|
|
|
|
|
{
|
2020-07-15 16:29:27 -07:00
|
|
|
*mana_con = pEntity->GetManaConversionMod();
|
2018-08-05 22:50:43 -05:00
|
|
|
|
|
|
|
|
if (fabs(*mana_con - old_mana_con) >= F_EPSILON)
|
|
|
|
|
{
|
|
|
|
|
profile.resist_ench_bitfield |= BF_MANA_CON_MOD;
|
|
|
|
|
if (*mana_con > old_mana_con)
|
|
|
|
|
profile.resist_ench_bitfield |= BF_MANA_CON_MOD_HI;
|
|
|
|
|
}
|
2020-07-18 11:17:01 -07:00
|
|
|
*mana_con = roundtwodec(*mana_con);
|
2018-08-05 22:50:43 -05:00
|
|
|
}
|
|
|
|
|
if (elemental_dmg)
|
|
|
|
|
{
|
2020-07-18 11:17:01 -07:00
|
|
|
*elemental_dmg = pEntity->GetElementalDamageMod();
|
2018-08-05 22:50:43 -05:00
|
|
|
if (fabs(*elemental_dmg - old_elemental_dmg) >= F_EPSILON)
|
|
|
|
|
{
|
|
|
|
|
profile.resist_ench_bitfield |= BF_ELE_DAMAGE_MOD;
|
|
|
|
|
if (*elemental_dmg > old_elemental_dmg)
|
|
|
|
|
profile.resist_ench_bitfield |= BF_ELE_DAMAGE_MOD_HI;
|
|
|
|
|
}
|
2020-07-18 11:17:01 -07:00
|
|
|
*elemental_dmg = roundtwodec(*elemental_dmg);
|
2018-08-05 22:50:43 -05:00
|
|
|
}
|
2020-05-04 16:12:27 -07:00
|
|
|
|
|
|
|
|
if (pEntity->AsMissileLauncher() && (pEntity->GetImbueEffects() & ImbuedEffectType::IgnoreSomeMagicProjectileDamage_ImbuedEffectType))
|
|
|
|
|
{
|
|
|
|
|
double absorb = 1.0;
|
|
|
|
|
profile._floatStatsTable->add(ABSORB_MAGIC_DAMAGE_FLOAT, &absorb);
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_Qualities.m_StringStats)
|
|
|
|
|
{
|
|
|
|
|
profile._strStatsTable = new PackableHashTableWithJson<STypeString, std::string>();
|
|
|
|
|
*profile._strStatsTable = *pEntity->m_Qualities.m_StringStats;
|
|
|
|
|
|
|
|
|
|
if (bIsPlayer)
|
|
|
|
|
{
|
|
|
|
|
if (!(characterOptions2 & DisplayDateOfBirth_CharacterOptions2))
|
|
|
|
|
profile._strStatsTable->remove(DATE_OF_BIRTH_STRING);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
profile._strStatsTable->remove(KEY_CODE_STRING);
|
|
|
|
|
profile._strStatsTable->remove(LOCK_CODE_STRING);
|
|
|
|
|
profile._strStatsTable->remove(QUEST_STRING);
|
|
|
|
|
profile._strStatsTable->remove(QUEST_RESTRICTION_STRING);
|
|
|
|
|
profile._strStatsTable->remove(ACTIVATION_TALK_STRING);
|
|
|
|
|
profile._strStatsTable->remove(ACTIVATION_FAILURE_STRING);
|
|
|
|
|
profile._strStatsTable->remove(USE_MESSAGE_STRING);
|
|
|
|
|
profile._strStatsTable->remove(GENERATOR_EVENT_STRING);
|
|
|
|
|
profile._strStatsTable->remove(KILL_QUEST_STRING);
|
2018-11-23 11:38:02 -06:00
|
|
|
profile._strStatsTable->remove(NAME_STRING);
|
|
|
|
|
|
2020-08-08 10:45:39 -07:00
|
|
|
if (pEntity->m_Qualities.GetInt(HERITAGE_SPECIFIC_ARMOR_INT, 0) == 0)
|
|
|
|
|
{
|
|
|
|
|
profile._intStatsTable->remove(HERITAGE_SPECIFIC_ARMOR_INT);
|
|
|
|
|
profile._strStatsTable->remove(GEAR_PLATING_NAME_STRING);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-23 11:38:02 -06:00
|
|
|
if (pEntity->InqBoolQuality(PORTAL_SHOW_DESTINATION_BOOL, 0))
|
|
|
|
|
{
|
|
|
|
|
string dest = pEntity->InqStringQuality(APPRAISAL_PORTAL_DESTINATION_STRING, "");
|
|
|
|
|
profile._strStatsTable->add(APPRAISAL_PORTAL_DESTINATION_STRING, &dest);
|
|
|
|
|
}
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
if (false) // bIsSourceAdmin)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
profile._strStatsTable->add(LONG_DESC_STRING, csprintf(
|
2018-04-30 19:57:04 -07:00
|
|
|
"For debug purposes: 0x%08X %u\nWT: %d\n%d",
|
|
|
|
|
pEntity->GetID(),
|
|
|
|
|
pEntity->m_Qualities.GetID(),
|
|
|
|
|
pEntity->m_Qualities.m_WeenieType,
|
|
|
|
|
pEntity->m_Qualities.GetInt(ITEM_TYPE_INT, 0)));
|
|
|
|
|
*/
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->m_Qualities.m_DIDStats)
|
|
|
|
|
{
|
2019-07-07 20:56:15 +00:00
|
|
|
profile._didStatsTable = new PackableHashTableWithJson<STypeDID, uint32_t>();
|
2018-03-29 17:01:57 -04:00
|
|
|
*profile._didStatsTable = *pEntity->m_Qualities.m_DIDStats;
|
2018-04-30 19:57:04 -07:00
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
/*
|
|
|
|
|
profile._didStatsTable->remove(SETUP_DID);
|
|
|
|
|
profile._didStatsTable->remove(MOTION_TABLE_DID);
|
|
|
|
|
profile._didStatsTable->remove(COMBAT_TABLE_DID);
|
|
|
|
|
profile._didStatsTable->remove(SOUND_TABLE_DID);
|
|
|
|
|
profile._didStatsTable->remove(PALETTE_BASE_DID);
|
|
|
|
|
profile._didStatsTable->remove(CLOTHINGBASE_DID);
|
|
|
|
|
profile._didStatsTable->remove(ICON_DID);
|
|
|
|
|
profile._didStatsTable->remove(PHYSICS_EFFECT_TABLE_DID);
|
|
|
|
|
profile._didStatsTable->remove(DEATH_TREASURE_TYPE_DID);
|
|
|
|
|
profile._didStatsTable->remove(TSYS_MUTATION_FILTER_DID);
|
|
|
|
|
profile._didStatsTable->remove(MUTATE_FILTER_DID);
|
|
|
|
|
*/
|
|
|
|
|
|
2020-03-21 09:23:59 -07:00
|
|
|
profile._didStatsTable->remove(COMBAT_TABLE_DID);
|
|
|
|
|
profile._didStatsTable->remove(TSYS_MUTATION_FILTER_DID);
|
|
|
|
|
profile._didStatsTable->remove(MUTATE_FILTER_DID);
|
|
|
|
|
profile._didStatsTable->remove(DEATH_TREASURE_TYPE_DID);
|
|
|
|
|
profile._didStatsTable->remove(USE_TARGET_ANIMATION_DID);
|
|
|
|
|
profile._didStatsTable->remove(USE_TARGET_SUCCESS_ANIMATION_DID);
|
|
|
|
|
profile._didStatsTable->remove(USE_TARGET_FAILURE_ANIMATION_DID);
|
|
|
|
|
profile._didStatsTable->remove(USE_USER_ANIMATION_DID);
|
|
|
|
|
profile._didStatsTable->remove(LINKED_PORTAL_ONE_DID);
|
|
|
|
|
profile._didStatsTable->remove(LINKED_PORTAL_TWO_DID);
|
|
|
|
|
profile._didStatsTable->remove(WIELDED_TREASURE_TYPE_DID);
|
|
|
|
|
profile._didStatsTable->remove(INVENTORY_TREASURE_TYPE_DID);
|
|
|
|
|
profile._didStatsTable->remove(SHOP_TREASURE_TYPE_DID);
|
|
|
|
|
profile._didStatsTable->remove(HOUSEID_DID);
|
|
|
|
|
profile._didStatsTable->remove(RESTRICTION_EFFECT_DID);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
for (PackableHashTable<STypeDID, uint32_t>::iterator i = profile._didStatsTable->begin(); i != profile._didStatsTable->end(); )
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
switch (i->first)
|
|
|
|
|
{
|
|
|
|
|
case EYES_PALETTE_DID:
|
|
|
|
|
case EYES_TEXTURE_DID:
|
|
|
|
|
case HAIR_PALETTE_DID:
|
|
|
|
|
case NOSE_TEXTURE_DID:
|
|
|
|
|
case SKIN_PALETTE_DID:
|
|
|
|
|
case MOUTH_TEXTURE_DID:
|
|
|
|
|
case ITEM_SKILL_LIMIT_DID:
|
|
|
|
|
case SPELL_DID:
|
|
|
|
|
case SPELL_COMPONENT_DID:
|
|
|
|
|
case DEATH_SPELL_DID:
|
2018-09-07 23:00:34 -05:00
|
|
|
case PROC_SPELL_DID:
|
2018-03-29 17:01:57 -04:00
|
|
|
i++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
i = profile._didStatsTable->erase(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t spelldid = 0;
|
2019-01-17 12:20:50 -06:00
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
if (!pEntity->IsCreature() && pEntity->m_Qualities._spell_book)
|
|
|
|
|
{
|
2019-07-07 20:56:15 +00:00
|
|
|
profile._spellBook = new SmartArray<uint32_t>();
|
|
|
|
|
profile._spellBook->grow((uint32_t)pEntity->m_Qualities._spell_book->_spellbook.size());
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
for (auto &spell : pEntity->m_Qualities._spell_book->_spellbook)
|
2019-07-07 20:56:15 +00:00
|
|
|
profile._spellBook->add((uint32_t *)&spell.first);
|
2019-01-16 21:05:23 -05:00
|
|
|
|
2019-01-17 12:20:50 -06:00
|
|
|
// Has spellbook, check if spell_did exists, if not, add.
|
|
|
|
|
if (pEntity->m_Qualities.InqDataID(SPELL_DID, spelldid))
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
|
|
while (i < profile._spellBook->num_used)
|
|
|
|
|
{
|
|
|
|
|
if (profile._spellBook->array_data[i] == spelldid)
|
|
|
|
|
break;
|
2019-01-16 21:05:23 -05:00
|
|
|
|
2019-01-17 12:20:50 -06:00
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i == profile._spellBook->num_used)
|
|
|
|
|
profile._spellBook->add(&spelldid);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-07-11 09:35:09 -07:00
|
|
|
else if (pEntity->m_Qualities.InqDataID(SPELL_DID, spelldid) && !pEntity->AsScroll())
|
2019-01-17 12:20:50 -06:00
|
|
|
{
|
|
|
|
|
// Does not have spellbook, add spell_did
|
2019-07-07 20:56:15 +00:00
|
|
|
profile._spellBook = new SmartArray<uint32_t>();
|
2019-01-17 12:20:50 -06:00
|
|
|
profile._spellBook->grow(spelldid);
|
|
|
|
|
profile._spellBook->add(&spelldid);
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
2018-08-13 18:46:54 -04:00
|
|
|
if (pEntity->IsCreature() && !pEntity->m_Qualities.GetBool(NPC_LOOKS_LIKE_OBJECT_BOOL, false))
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
profile.creature_profile = new CreatureAppraisalProfile();
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
auto setCreatureProfileAttribute = [&](STypeAttribute attrib, uint32_t &value, uint32_t &bitfield)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t raw = 0;
|
2018-03-29 17:01:57 -04:00
|
|
|
pEntity->m_Qualities.InqAttribute(attrib, raw, TRUE);
|
|
|
|
|
pEntity->m_Qualities.InqAttribute(attrib, value, FALSE);
|
|
|
|
|
|
|
|
|
|
if (raw != value)
|
|
|
|
|
{
|
|
|
|
|
switch (attrib)
|
|
|
|
|
{
|
2018-04-30 19:57:04 -07:00
|
|
|
case STRENGTH_ATTRIBUTE: bitfield |= CreatureAppraisalProfile::BF_STRENGTH; break;
|
|
|
|
|
case ENDURANCE_ATTRIBUTE: bitfield |= CreatureAppraisalProfile::BF_ENDURANCE; break;
|
|
|
|
|
case QUICKNESS_ATTRIBUTE: bitfield |= CreatureAppraisalProfile::BF_QUICKNESS; break;
|
|
|
|
|
case COORDINATION_ATTRIBUTE: bitfield |= CreatureAppraisalProfile::BF_COORDINATION; break;
|
|
|
|
|
case FOCUS_ATTRIBUTE: bitfield |= CreatureAppraisalProfile::BF_FOCUS; break;
|
|
|
|
|
case SELF_ATTRIBUTE: bitfield |= CreatureAppraisalProfile::BF_SELF; break;
|
2018-03-29 17:01:57 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value > raw)
|
|
|
|
|
{
|
|
|
|
|
switch (attrib)
|
|
|
|
|
{
|
|
|
|
|
case STRENGTH_ATTRIBUTE: bitfield |= CreatureAppraisalProfile::BF_STRENGTH_HI; break;
|
|
|
|
|
case ENDURANCE_ATTRIBUTE: bitfield |= CreatureAppraisalProfile::BF_ENDURANCE_HI; break;
|
|
|
|
|
case QUICKNESS_ATTRIBUTE: bitfield |= CreatureAppraisalProfile::BF_QUICKNESS_HI; break;
|
|
|
|
|
case COORDINATION_ATTRIBUTE: bitfield |= CreatureAppraisalProfile::BF_COORDINATION_HI; break;
|
|
|
|
|
case FOCUS_ATTRIBUTE: bitfield |= CreatureAppraisalProfile::BF_FOCUS_HI; break;
|
|
|
|
|
case SELF_ATTRIBUTE: bitfield |= CreatureAppraisalProfile::BF_SELF_HI; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
auto setCreatureProfileAttribute2nd = [&](STypeAttribute2nd attrib2nd, uint32_t &value, uint32_t &bitfield)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t raw = 0;
|
2018-03-29 17:01:57 -04:00
|
|
|
pEntity->m_Qualities.InqAttribute2nd(attrib2nd, raw, TRUE);
|
|
|
|
|
pEntity->m_Qualities.InqAttribute2nd(attrib2nd, value, FALSE);
|
|
|
|
|
|
|
|
|
|
if (raw != value)
|
|
|
|
|
{
|
|
|
|
|
switch (attrib2nd)
|
|
|
|
|
{
|
|
|
|
|
case MAX_HEALTH_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_HEALTH; break;
|
|
|
|
|
case MAX_STAMINA_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_STAMINA; break;
|
|
|
|
|
case MAX_MANA_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_MANA; break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value > raw)
|
|
|
|
|
{
|
|
|
|
|
switch (attrib2nd)
|
|
|
|
|
{
|
|
|
|
|
case MAX_HEALTH_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_HEALTH_HI; break;
|
|
|
|
|
case MAX_STAMINA_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_STAMINA_HI; break;
|
|
|
|
|
case MAX_MANA_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_MANA_HI; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
setCreatureProfileAttribute(STRENGTH_ATTRIBUTE, profile.creature_profile->strength, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
setCreatureProfileAttribute(ENDURANCE_ATTRIBUTE, profile.creature_profile->endurance, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
setCreatureProfileAttribute(QUICKNESS_ATTRIBUTE, profile.creature_profile->quickness, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
setCreatureProfileAttribute(COORDINATION_ATTRIBUTE, profile.creature_profile->coordination, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
setCreatureProfileAttribute(FOCUS_ATTRIBUTE, profile.creature_profile->focus, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
setCreatureProfileAttribute(SELF_ATTRIBUTE, profile.creature_profile->self, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
setCreatureProfileAttribute2nd(HEALTH_ATTRIBUTE_2ND, profile.creature_profile->health, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
setCreatureProfileAttribute2nd(MAX_HEALTH_ATTRIBUTE_2ND, profile.creature_profile->max_health, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
setCreatureProfileAttribute2nd(STAMINA_ATTRIBUTE_2ND, profile.creature_profile->stamina, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
setCreatureProfileAttribute2nd(MAX_STAMINA_ATTRIBUTE_2ND, profile.creature_profile->max_stamina, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
setCreatureProfileAttribute2nd(MANA_ATTRIBUTE_2ND, profile.creature_profile->mana, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
setCreatureProfileAttribute2nd(MAX_MANA_ATTRIBUTE_2ND, profile.creature_profile->max_mana, profile.creature_profile->enchantment_bitfield);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->InqType() & TYPE_WEAPON)
|
|
|
|
|
{
|
|
|
|
|
profile.weapon_profile = new WeaponProfile();
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
auto setCreatureProfileAttribute2nd = [&](STypeAttribute2nd attrib2nd, uint32_t &value, uint32_t &bitfield)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t raw = 0;
|
2018-03-29 17:01:57 -04:00
|
|
|
pEntity->m_Qualities.InqAttribute2nd(attrib2nd, raw, TRUE);
|
|
|
|
|
pEntity->m_Qualities.InqAttribute2nd(attrib2nd, value, FALSE);
|
|
|
|
|
|
|
|
|
|
if (raw != value)
|
|
|
|
|
{
|
|
|
|
|
switch (attrib2nd)
|
|
|
|
|
{
|
|
|
|
|
case MAX_HEALTH_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_HEALTH; break;
|
|
|
|
|
case MAX_STAMINA_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_STAMINA; break;
|
|
|
|
|
case MAX_MANA_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_MANA; break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value > raw)
|
|
|
|
|
{
|
|
|
|
|
switch (attrib2nd)
|
|
|
|
|
{
|
|
|
|
|
case MAX_HEALTH_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_HEALTH_HI; break;
|
|
|
|
|
case MAX_STAMINA_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_STAMINA_HI; break;
|
|
|
|
|
case MAX_MANA_ATTRIBUTE_2ND: bitfield |= CreatureAppraisalProfile::BF_MAX_MANA_HI; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2018-04-30 19:57:04 -07:00
|
|
|
profile.weapon_profile->damage_type = (DAMAGE_TYPE)pEntity->InqIntQuality(DAMAGE_TYPE_INT, 0);
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
int baseWeaponTime = max(0, min(200, pEntity->InqIntQuality(WEAPON_TIME_INT, 0, TRUE)));
|
|
|
|
|
profile.weapon_profile->weapon_time = max(0, min(200, pEntity->GetAttackTime()));
|
|
|
|
|
|
|
|
|
|
if (baseWeaponTime != profile.weapon_profile->weapon_time)
|
|
|
|
|
{
|
|
|
|
|
profile.weapon_ench_bitfield |= WeaponEnchantment_BFIndex::BF_WEAPON_TIME;
|
|
|
|
|
if (profile.weapon_profile->weapon_time < baseWeaponTime)
|
|
|
|
|
profile.weapon_ench_bitfield |= WeaponEnchantment_BFIndex::BF_WEAPON_TIME_HI;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
profile.weapon_profile->weapon_skill = pEntity->InqIntQuality(WEAPON_SKILL_INT, 0);
|
|
|
|
|
|
|
|
|
|
if (!pEntity->AsCaster())
|
|
|
|
|
{
|
|
|
|
|
int baseWeaponDamage = pEntity->InqIntQuality(DAMAGE_INT, 0, TRUE);
|
2020-07-20 12:17:16 -07:00
|
|
|
profile.weapon_profile->weapon_damage = pEntity->m_Qualities.m_WeenieType == Ammunition_WeenieType ? baseWeaponDamage : pEntity->GetAttackDamage(true);
|
2018-03-29 17:01:57 -04:00
|
|
|
|
2018-08-24 02:35:14 -05:00
|
|
|
// Don't enchant Ammunition
|
|
|
|
|
if ((baseWeaponDamage != profile.weapon_profile->weapon_damage) && pEntity->m_Qualities.m_WeenieType != Ammunition_WeenieType)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
profile.weapon_ench_bitfield |= WeaponEnchantment_BFIndex::BF_DAMAGE;
|
|
|
|
|
if (profile.weapon_profile->weapon_damage > baseWeaponDamage)
|
|
|
|
|
profile.weapon_ench_bitfield |= WeaponEnchantment_BFIndex::BF_DAMAGE_HI;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
profile.weapon_profile->damage_variance = pEntity->InqFloatQuality(DAMAGE_VARIANCE_FLOAT, 0.0);
|
|
|
|
|
profile.weapon_profile->damage_mod = pEntity->InqFloatQuality(DAMAGE_MOD_FLOAT, 1.0);
|
|
|
|
|
profile.weapon_profile->weapon_length = pEntity->InqFloatQuality(WEAPON_LENGTH_FLOAT, 0);
|
|
|
|
|
|
|
|
|
|
double baseWeaponOffense = pEntity->InqFloatQuality(WEAPON_OFFENSE_FLOAT, 0, TRUE);
|
2020-07-18 20:23:53 -07:00
|
|
|
profile.weapon_profile->weapon_offense = pEntity->GetOffenseMod();
|
2018-03-29 17:01:57 -04:00
|
|
|
|
2018-08-24 02:35:14 -05:00
|
|
|
// Don't enchant Ammunition
|
|
|
|
|
if ((fabs(baseWeaponOffense - profile.weapon_profile->weapon_offense) >= F_EPSILON) && pEntity->m_Qualities.m_WeenieType != Ammunition_WeenieType)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
profile.weapon_ench_bitfield |= WeaponEnchantment_BFIndex::BF_WEAPON_OFFENSE;
|
|
|
|
|
if (profile.weapon_profile->weapon_offense > baseWeaponOffense)
|
|
|
|
|
profile.weapon_ench_bitfield |= WeaponEnchantment_BFIndex::BF_WEAPON_OFFENSE_HI;
|
|
|
|
|
}
|
2020-07-18 11:17:01 -07:00
|
|
|
profile.weapon_profile->weapon_offense = roundtwodec(profile.weapon_profile->weapon_offense);
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
profile.weapon_profile->max_velocity = pEntity->InqFloatQuality(MAXIMUM_VELOCITY_FLOAT, 0, TRUE);
|
|
|
|
|
profile.weapon_profile->max_velocity_estimated = (int)0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
profile.weapon_profile->weapon_damage = 0;
|
|
|
|
|
profile.weapon_profile->damage_variance = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pEntity->InqType() & TYPE_VESTEMENTS)
|
|
|
|
|
{
|
2019-07-07 20:56:15 +00:00
|
|
|
auto setArmorProfileMod = [&](STypeFloat floatStat, float &value, uint32_t &bitfield, float &mod)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
double raw = 0.0;
|
|
|
|
|
double dbl_value = 0.0;
|
|
|
|
|
pEntity->m_Qualities.InqFloat(floatStat, raw, TRUE);
|
|
|
|
|
pEntity->m_Qualities.InqFloat(floatStat, dbl_value, FALSE);
|
2018-04-30 19:57:04 -07:00
|
|
|
value = (float)dbl_value * mod;
|
|
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
if (abs(raw - dbl_value) > F_EPSILON)
|
|
|
|
|
{
|
|
|
|
|
switch (floatStat)
|
|
|
|
|
{
|
|
|
|
|
case ARMOR_MOD_VS_SLASH_FLOAT: bitfield |= BF_ARMOR_MOD_VS_SLASH; break;
|
|
|
|
|
case ARMOR_MOD_VS_PIERCE_FLOAT: bitfield |= BF_ARMOR_MOD_VS_PIERCE; break;
|
2018-04-30 19:57:04 -07:00
|
|
|
case ARMOR_MOD_VS_BLUDGEON_FLOAT: bitfield |= BF_ARMOR_MOD_VS_BLUDGEON; break;
|
2018-03-29 17:01:57 -04:00
|
|
|
case ARMOR_MOD_VS_COLD_FLOAT: bitfield |= BF_ARMOR_MOD_VS_COLD; break;
|
|
|
|
|
case ARMOR_MOD_VS_FIRE_FLOAT: bitfield |= BF_ARMOR_MOD_VS_FIRE; break;
|
|
|
|
|
case ARMOR_MOD_VS_ACID_FLOAT: bitfield |= BF_ARMOR_MOD_VS_ACID; break;
|
|
|
|
|
case ARMOR_MOD_VS_ELECTRIC_FLOAT: bitfield |= BF_ARMOR_MOD_VS_ELECTRIC; break;
|
|
|
|
|
case ARMOR_MOD_VS_NETHER_FLOAT: bitfield |= BF_ARMOR_MOD_VS_NETHER; break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dbl_value > raw)
|
|
|
|
|
{
|
|
|
|
|
switch (floatStat)
|
|
|
|
|
{
|
|
|
|
|
case ARMOR_MOD_VS_SLASH_FLOAT: bitfield |= BF_ARMOR_MOD_VS_SLASH_HI; break;
|
|
|
|
|
case ARMOR_MOD_VS_PIERCE_FLOAT: bitfield |= BF_ARMOR_MOD_VS_PIERCE_HI; break;
|
|
|
|
|
case ARMOR_MOD_VS_BLUDGEON_FLOAT: bitfield |= BF_ARMOR_MOD_VS_BLUDGEON_HI; break;
|
|
|
|
|
case ARMOR_MOD_VS_COLD_FLOAT: bitfield |= BF_ARMOR_MOD_VS_COLD_HI; break;
|
|
|
|
|
case ARMOR_MOD_VS_FIRE_FLOAT: bitfield |= BF_ARMOR_MOD_VS_FIRE_HI; break;
|
|
|
|
|
case ARMOR_MOD_VS_ACID_FLOAT: bitfield |= BF_ARMOR_MOD_VS_ACID_HI; break;
|
|
|
|
|
case ARMOR_MOD_VS_ELECTRIC_FLOAT: bitfield |= BF_ARMOR_MOD_VS_ELECTRIC_HI; break;
|
|
|
|
|
case ARMOR_MOD_VS_NETHER_FLOAT: bitfield |= BF_ARMOR_MOD_VS_NETHER_HI; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
2018-04-30 19:57:04 -07:00
|
|
|
|
|
|
|
|
int* shieldLoc = profile._intStatsTable->lookup(LOCATIONS_INT);
|
|
|
|
|
float shieldMod = 1;
|
|
|
|
|
if (shieldLoc && *shieldLoc == static_cast<int>(INVENTORY_LOC::SHIELD_LOC))
|
|
|
|
|
{
|
|
|
|
|
SKILL_ADVANCEMENT_CLASS sac = SKILL_ADVANCEMENT_CLASS::UNTRAINED_SKILL_ADVANCEMENT_CLASS;
|
|
|
|
|
pSource->m_Qualities.InqSkillAdvancementClass(SHIELD_SKILL, sac);
|
|
|
|
|
|
|
|
|
|
if (sac != SPECIALIZED_SKILL_ADVANCEMENT_CLASS)
|
|
|
|
|
shieldMod = .5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
profile.armor_profile = new ArmorProfile();
|
|
|
|
|
setArmorProfileMod(ARMOR_MOD_VS_SLASH_FLOAT, profile.armor_profile->mod_vs_slash, profile.armor_ench_bitfield, shieldMod);
|
|
|
|
|
setArmorProfileMod(ARMOR_MOD_VS_PIERCE_FLOAT, profile.armor_profile->mod_vs_pierce, profile.armor_ench_bitfield, shieldMod);
|
|
|
|
|
setArmorProfileMod(ARMOR_MOD_VS_BLUDGEON_FLOAT, profile.armor_profile->mod_vs_bludgeon, profile.armor_ench_bitfield, shieldMod);
|
|
|
|
|
setArmorProfileMod(ARMOR_MOD_VS_COLD_FLOAT, profile.armor_profile->mod_vs_cold, profile.armor_ench_bitfield, shieldMod);
|
|
|
|
|
setArmorProfileMod(ARMOR_MOD_VS_FIRE_FLOAT, profile.armor_profile->mod_vs_fire, profile.armor_ench_bitfield, shieldMod);
|
|
|
|
|
setArmorProfileMod(ARMOR_MOD_VS_ACID_FLOAT, profile.armor_profile->mod_vs_acid, profile.armor_ench_bitfield, shieldMod);
|
|
|
|
|
setArmorProfileMod(ARMOR_MOD_VS_ELECTRIC_FLOAT, profile.armor_profile->mod_vs_electric, profile.armor_ench_bitfield, shieldMod);
|
|
|
|
|
setArmorProfileMod(ARMOR_MOD_VS_NETHER_FLOAT, profile.armor_profile->mod_vs_nether, profile.armor_ench_bitfield, shieldMod);
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
int *enchanted_armor_level = NULL;
|
|
|
|
|
if (profile._intStatsTable && (enchanted_armor_level = profile._intStatsTable->lookup(ARMOR_LEVEL_INT)))
|
|
|
|
|
{
|
|
|
|
|
int raw_armor_level = pEntity->InqIntQuality(ARMOR_LEVEL_INT, 0, TRUE);
|
|
|
|
|
if (raw_armor_level != *enchanted_armor_level)
|
|
|
|
|
{
|
|
|
|
|
profile.armor_ench_bitfield |= BF_ARMOR_LEVEL;
|
|
|
|
|
if (*enchanted_armor_level > raw_armor_level)
|
|
|
|
|
profile.armor_ench_bitfield |= BF_ARMOR_LEVEL_HI;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-23 12:52:28 -06:00
|
|
|
if (pEntity->_IsPlayer())
|
|
|
|
|
{
|
|
|
|
|
int coverage = 0;
|
|
|
|
|
int armorLevel = 0;
|
|
|
|
|
|
|
|
|
|
for (auto wielded : pEntity->AsPlayer()->m_Wielded)
|
|
|
|
|
{
|
|
|
|
|
coverage = wielded->m_Qualities.GetInt(CLOTHING_PRIORITY_INT, 0);
|
|
|
|
|
armorLevel = wielded->m_Qualities.GetInt(ARMOR_LEVEL_INT, 0);
|
|
|
|
|
|
|
|
|
|
if (armorLevel > 0)
|
|
|
|
|
{
|
|
|
|
|
if (coverage & CLOTHING_PRIORITY::HEAD_WEAR_CLOTHING_PRIORITY)
|
|
|
|
|
{
|
|
|
|
|
profile.base_armor_head += armorLevel;
|
|
|
|
|
}
|
|
|
|
|
if (coverage & CLOTHING_PRIORITY::HAND_WEAR_CLOTHING_PRIORITY)
|
|
|
|
|
{
|
|
|
|
|
profile.base_armor_hand += armorLevel;
|
|
|
|
|
}
|
|
|
|
|
if (coverage & CLOTHING_PRIORITY::FOOT_WEAR_CLOTHING_PRIORITY)
|
|
|
|
|
{
|
|
|
|
|
profile.base_armor_foot += armorLevel;
|
|
|
|
|
}
|
|
|
|
|
if (coverage & CLOTHING_PRIORITY::CHEST_ARMOR_CLOTHING_PRIORITY || coverage & CLOTHING_PRIORITY::CHEST_WEAR_CLOTHING_PRIORITY)
|
|
|
|
|
{
|
|
|
|
|
profile.base_armor_chest += armorLevel;
|
|
|
|
|
}
|
|
|
|
|
if (coverage & CLOTHING_PRIORITY::ABDOMEN_ARMOR_CLOTHING_PRIORITY || coverage & CLOTHING_PRIORITY::ABDOMEN_WEAR_CLOTHING_PRIORITY)
|
|
|
|
|
{
|
|
|
|
|
profile.base_armor_groin += armorLevel;
|
|
|
|
|
}
|
|
|
|
|
if (coverage & CLOTHING_PRIORITY::UPPER_ARM_ARMOR_CLOTHING_PRIORITY || coverage & CLOTHING_PRIORITY::UPPER_ARM_WEAR_CLOTHING_PRIORITY)
|
|
|
|
|
{
|
|
|
|
|
profile.base_armor_bicep += armorLevel;
|
|
|
|
|
}
|
|
|
|
|
if (coverage & CLOTHING_PRIORITY::LOWER_ARM_ARMOR_CLOTHING_PRIORITY || coverage & CLOTHING_PRIORITY::LOWER_ARM_WEAR_CLOTHING_PRIORITY)
|
|
|
|
|
{
|
|
|
|
|
profile.base_armor_wrist += armorLevel;
|
|
|
|
|
}
|
|
|
|
|
if (coverage & CLOTHING_PRIORITY::UPPER_LEG_ARMOR_CLOTHING_PRIORITY || coverage & CLOTHING_PRIORITY::UPPER_LEG_WEAR_CLOTHING_PRIORITY)
|
|
|
|
|
{
|
|
|
|
|
profile.base_armor_thigh += armorLevel;
|
|
|
|
|
}
|
|
|
|
|
if (coverage & CLOTHING_PRIORITY::LOWER_LEG_ARMOR_CLOTHING_PRIORITY || coverage & CLOTHING_PRIORITY::LOWER_LEG_WEAR_CLOTHING_PRIORITY)
|
|
|
|
|
{
|
|
|
|
|
profile.base_armor_shin += armorLevel;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-29 17:01:57 -04:00
|
|
|
pWriter->Write(&profile);
|
|
|
|
|
|
|
|
|
|
return pWriter;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-12 14:41:21 -07:00
|
|
|
BinaryWriter *LoginCharacter(CPlayerWeenie *pPlayer)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
BinaryWriter *LC = new BinaryWriter;
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
LC->Write<uint32_t>(0x13);
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
CACQualities loginQualities;
|
|
|
|
|
loginQualities.CopyFrom(&pPlayer->m_Qualities);
|
|
|
|
|
SafeDelete(loginQualities._body);
|
|
|
|
|
SafeDelete(loginQualities._generator_table);
|
|
|
|
|
SafeDelete(loginQualities._generator_registry);
|
|
|
|
|
SafeDelete(loginQualities._generator_queue);
|
|
|
|
|
SafeDelete(loginQualities._emote_table);
|
|
|
|
|
SafeDelete(loginQualities._create_list);
|
|
|
|
|
SafeDelete(loginQualities._event_filter);
|
|
|
|
|
|
|
|
|
|
LC->Write(&loginQualities);
|
|
|
|
|
|
2020-02-28 19:11:41 +00:00
|
|
|
pPlayer->_playerModule.Pack(LC);
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
PackableList<ContentProfile> inventoryList;
|
|
|
|
|
for (auto item : pPlayer->m_Items)
|
|
|
|
|
{
|
|
|
|
|
ContentProfile prof;
|
2018-07-12 14:41:21 -07:00
|
|
|
prof.m_iid = item->GetID();
|
2018-03-29 17:01:57 -04:00
|
|
|
prof.m_uContainerProperties = 0;
|
|
|
|
|
inventoryList.push_back(prof);
|
|
|
|
|
}
|
|
|
|
|
for (auto item : pPlayer->m_Packs)
|
|
|
|
|
{
|
|
|
|
|
ContentProfile prof;
|
2018-07-12 14:41:21 -07:00
|
|
|
prof.m_iid = item->GetID();
|
|
|
|
|
prof.m_uContainerProperties = item->AsContainer() ? 1 : 2;
|
2018-03-29 17:01:57 -04:00
|
|
|
inventoryList.push_back(prof);
|
|
|
|
|
}
|
|
|
|
|
inventoryList.Pack(LC);
|
|
|
|
|
|
|
|
|
|
PackableList<InventoryPlacement> wieldedList;
|
|
|
|
|
for (auto wielded : pPlayer->m_Wielded)
|
|
|
|
|
{
|
|
|
|
|
InventoryPlacement place;
|
2018-07-12 14:41:21 -07:00
|
|
|
place.iid_ = wielded->GetID();
|
|
|
|
|
place.loc_ = wielded->InqIntQuality(CURRENT_WIELDED_LOCATION_INT, 0);
|
|
|
|
|
place.priority_ = wielded->InqIntQuality(CLOTHING_PRIORITY_INT, 0);
|
2018-03-29 17:01:57 -04:00
|
|
|
wieldedList.push_back(place);
|
|
|
|
|
}
|
|
|
|
|
wieldedList.Pack(LC);
|
|
|
|
|
|
|
|
|
|
return LC;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-12 14:41:21 -07:00
|
|
|
BinaryWriter *HealthUpdate(CWeenieObject *pWeenie)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
MESSAGE_BEGIN(HealthUpdate);
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
HealthUpdate->Write<uint32_t>(0x1C0);
|
|
|
|
|
HealthUpdate->Write<uint32_t>(pWeenie->GetID());
|
2018-03-29 17:01:57 -04:00
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t health = 0, maxHealth = 1;
|
2018-03-29 17:01:57 -04:00
|
|
|
pWeenie->m_Qualities.InqAttribute2nd(HEALTH_ATTRIBUTE_2ND, health, FALSE);
|
|
|
|
|
pWeenie->m_Qualities.InqAttribute2nd(MAX_HEALTH_ATTRIBUTE_2ND, maxHealth, FALSE);
|
|
|
|
|
|
|
|
|
|
double fraction = min(1.0, max(0.0, maxHealth != 0 ? health / (double)maxHealth : 0.0));
|
|
|
|
|
HealthUpdate->Write<float>((float)fraction);
|
|
|
|
|
|
|
|
|
|
MESSAGE_END(HealthUpdate);
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-12 14:41:21 -07:00
|
|
|
BinaryWriter *ItemManaUpdate(CWeenieObject *item)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
MESSAGE_BEGIN(ItemManaUpdate);
|
|
|
|
|
|
|
|
|
|
int currentMana = item->InqIntQuality(ITEM_CUR_MANA_INT, -1, TRUE);
|
|
|
|
|
int maxMana = item->InqIntQuality(ITEM_MAX_MANA_INT, -1, TRUE);
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
uint32_t hasMana;
|
2018-03-29 17:01:57 -04:00
|
|
|
float manaFraction;
|
|
|
|
|
if (maxMana < 0 || currentMana < 0)
|
|
|
|
|
{
|
|
|
|
|
hasMana = 0;
|
|
|
|
|
manaFraction = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
hasMana = 1;
|
|
|
|
|
manaFraction = (float)currentMana / (float)maxMana;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-27 15:47:05 -05:00
|
|
|
manaFraction = min(max(manaFraction, 0.0f), 1.0f);
|
2019-07-07 20:56:15 +00:00
|
|
|
ItemManaUpdate->Write<uint32_t>(0x0264);
|
|
|
|
|
ItemManaUpdate->Write<uint32_t>(item->GetID());
|
2018-03-29 17:01:57 -04:00
|
|
|
ItemManaUpdate->Write<float>(manaFraction);
|
2019-07-07 20:56:15 +00:00
|
|
|
ItemManaUpdate->Write<uint32_t>(hasMana);
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
MESSAGE_END(ItemManaUpdate);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
BinaryWriter *InventoryEquip(uint32_t dwItemID, uint32_t dwCoverage)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
MESSAGE_BEGIN(InventoryEquip);
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
InventoryEquip->Write<uint32_t>(0x23);
|
|
|
|
|
InventoryEquip->Write<uint32_t>(dwItemID);
|
|
|
|
|
InventoryEquip->Write<uint32_t>(dwCoverage);
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
MESSAGE_END(InventoryEquip);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
BinaryWriter *InventoryMove(uint32_t dwItemID, uint32_t dwContainerID, uint32_t dwSlot, uint32_t dwType)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
MESSAGE_BEGIN(InventoryMove);
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
InventoryMove->Write<uint32_t>(0x22);
|
|
|
|
|
InventoryMove->Write<uint32_t>(dwItemID);
|
|
|
|
|
InventoryMove->Write<uint32_t>(dwContainerID);
|
|
|
|
|
InventoryMove->Write<uint32_t>(dwSlot);
|
|
|
|
|
InventoryMove->Write<uint32_t>(dwType);
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
MESSAGE_END(InventoryMove);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
BinaryWriter *InventoryDrop(uint32_t dwItemID)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
MESSAGE_BEGIN(InventoryDrop);
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
InventoryDrop->Write<uint32_t>(0x19A);
|
|
|
|
|
InventoryDrop->Write<uint32_t>(dwItemID);
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
MESSAGE_END(InventoryDrop);
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-12 14:41:21 -07:00
|
|
|
BinaryWriter *MoveUpdate(CWeenieObject *pEntity)
|
2018-03-29 17:01:57 -04:00
|
|
|
{
|
|
|
|
|
BinaryWriter *pWriter = new BinaryWriter();
|
|
|
|
|
|
2019-07-07 20:56:15 +00:00
|
|
|
pWriter->Write<uint32_t>(0xF748);
|
|
|
|
|
pWriter->Write<uint32_t>(pEntity->GetID());
|
2018-03-29 17:01:57 -04:00
|
|
|
|
|
|
|
|
PositionPack position;
|
|
|
|
|
position.position = pEntity->m_Position;
|
|
|
|
|
position.has_contact = (pEntity->transient_state & CONTACT_TS && pEntity->transient_state & ON_WALKABLE_TS) ? TRUE : FALSE;
|
|
|
|
|
position.placement_id = pEntity->GetActivePlacementFrameID();
|
|
|
|
|
position.instance_timestamp = pEntity->_instance_timestamp;
|
|
|
|
|
position.position_timestamp = pEntity->_position_timestamp;
|
|
|
|
|
position.teleport_timestamp = pEntity->_teleport_timestamp;
|
|
|
|
|
// position.velocity = pEntity->m_velocityVector;
|
|
|
|
|
position.force_position_timestamp = pEntity->_force_position_timestamp;
|
|
|
|
|
|
|
|
|
|
position.Pack(pWriter);
|
|
|
|
|
|
|
|
|
|
return pWriter;
|
|
|
|
|
}
|