mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-17 03:08:26 +00:00
2dacb523fc
Hopefully resolves issues with toons on Titanium spawning out of bounds when starting in tutorial. Resolves setting home bind to tutorial and being out of bounds.
1768 lines
45 KiB
C++
1768 lines
45 KiB
C++
#include "../debug.h"
|
|
#include "titanium.h"
|
|
#include "../opcodemgr.h"
|
|
#include "../logsys.h"
|
|
#include "../eq_stream_ident.h"
|
|
#include "../crc32.h"
|
|
#include "../races.h"
|
|
|
|
#include "../eq_packet_structs.h"
|
|
#include "../string_util.h"
|
|
#include "../item.h"
|
|
#include "titanium_structs.h"
|
|
#include <sstream>
|
|
|
|
namespace Titanium
|
|
{
|
|
static const char *name = "Titanium";
|
|
static OpcodeManager *opcodes = nullptr;
|
|
static Strategy struct_strategy;
|
|
|
|
char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth);
|
|
|
|
// server to client inventory location converters
|
|
static inline int16 ServerToTitaniumSlot(uint32 ServerSlot);
|
|
static inline int16 ServerToTitaniumCorpseSlot(uint32 ServerCorpse);
|
|
|
|
// client to server inventory location converters
|
|
static inline uint32 TitaniumToServerSlot(int16 TitaniumSlot);
|
|
static inline uint32 TitaniumToServerCorpseSlot(int16 TitaniumCorpse);
|
|
|
|
void Register(EQStreamIdentifier &into)
|
|
{
|
|
//create our opcode manager if we havent already
|
|
if (opcodes == nullptr) {
|
|
//TODO: get this file name from the config file
|
|
std::string opfile = "patch_";
|
|
opfile += name;
|
|
opfile += ".conf";
|
|
//load up the opcode manager.
|
|
//TODO: figure out how to support shared memory with multiple patches...
|
|
opcodes = new RegularOpcodeManager();
|
|
if (!opcodes->LoadOpcodes(opfile.c_str())) {
|
|
_log(NET__OPCODES, "Error loading opcodes file %s. Not registering patch %s.", opfile.c_str(), name);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//ok, now we have what we need to register.
|
|
|
|
EQStream::Signature signature;
|
|
std::string pname;
|
|
|
|
//register our world signature.
|
|
pname = std::string(name) + "_world";
|
|
signature.ignore_eq_opcode = 0;
|
|
signature.first_length = sizeof(structs::LoginInfo_Struct);
|
|
signature.first_eq_opcode = opcodes->EmuToEQ(OP_SendLoginInfo);
|
|
into.RegisterPatch(signature, pname.c_str(), &opcodes, &struct_strategy);
|
|
|
|
//register our zone signature.
|
|
pname = std::string(name) + "_zone";
|
|
signature.ignore_eq_opcode = opcodes->EmuToEQ(OP_AckPacket);
|
|
signature.first_length = sizeof(structs::ClientZoneEntry_Struct);
|
|
signature.first_eq_opcode = opcodes->EmuToEQ(OP_ZoneEntry);
|
|
into.RegisterPatch(signature, pname.c_str(), &opcodes, &struct_strategy);
|
|
|
|
|
|
|
|
_log(NET__IDENTIFY, "Registered patch %s", name);
|
|
}
|
|
|
|
void Reload()
|
|
{
|
|
//we have a big problem to solve here when we switch back to shared memory
|
|
//opcode managers because we need to change the manager pointer, which means
|
|
//we need to go to every stream and replace it's manager.
|
|
|
|
if (opcodes != nullptr) {
|
|
//TODO: get this file name from the config file
|
|
std::string opfile = "patch_";
|
|
opfile += name;
|
|
opfile += ".conf";
|
|
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
|
|
_log(NET__OPCODES, "Error reloading opcodes file %s for patch %s.", opfile.c_str(), name);
|
|
return;
|
|
}
|
|
_log(NET__OPCODES, "Reloaded opcodes for patch %s", name);
|
|
}
|
|
}
|
|
|
|
Strategy::Strategy() : StructStrategy()
|
|
{
|
|
//all opcodes default to passthrough.
|
|
#include "ss_register.h"
|
|
#include "titanium_ops.h"
|
|
}
|
|
|
|
std::string Strategy::Describe() const
|
|
{
|
|
std::string r;
|
|
r += "Patch ";
|
|
r += name;
|
|
return(r);
|
|
}
|
|
|
|
const EQClientVersion Strategy::ClientVersion() const
|
|
{
|
|
return EQClientTitanium;
|
|
}
|
|
|
|
#include "ss_define.h"
|
|
|
|
// ENCODE methods
|
|
EAT_ENCODE(OP_GuildMemberLevelUpdate); // added ;
|
|
|
|
EAT_ENCODE(OP_ZoneServerReady); // added ;
|
|
|
|
ENCODE(OP_Action)
|
|
{
|
|
ENCODE_LENGTH_EXACT(Action_Struct);
|
|
SETUP_DIRECT_ENCODE(Action_Struct, structs::Action_Struct);
|
|
|
|
OUT(target);
|
|
OUT(source);
|
|
OUT(level);
|
|
OUT(instrument_mod);
|
|
OUT(sequence);
|
|
OUT(type);
|
|
//OUT(damage);
|
|
OUT(spell);
|
|
OUT(buff_unknown); // if this is 4, a buff icon is made
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_AdventureMerchantSell)
|
|
{
|
|
ENCODE_LENGTH_EXACT(Adventure_Sell_Struct);
|
|
SETUP_DIRECT_ENCODE(Adventure_Sell_Struct, structs::Adventure_Sell_Struct);
|
|
|
|
eq->unknown000 = 1;
|
|
OUT(npcid);
|
|
eq->slot = ServerToTitaniumSlot(emu->slot);
|
|
OUT(charges);
|
|
OUT(sell_price);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_ApplyPoison)
|
|
{
|
|
ENCODE_LENGTH_EXACT(ApplyPoison_Struct);
|
|
SETUP_DIRECT_ENCODE(ApplyPoison_Struct, structs::ApplyPoison_Struct);
|
|
|
|
eq->inventorySlot = ServerToTitaniumSlot(emu->inventorySlot);
|
|
OUT(success);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_BazaarSearch)
|
|
{
|
|
if (((*p)->size == sizeof(BazaarReturnDone_Struct)) || ((*p)->size == sizeof(BazaarWelcome_Struct))) {
|
|
|
|
EQApplicationPacket *in = *p;
|
|
*p = nullptr;
|
|
dest->FastQueuePacket(&in, ack_req);
|
|
return;
|
|
}
|
|
|
|
//consume the packet
|
|
EQApplicationPacket *in = *p;
|
|
*p = nullptr;
|
|
|
|
//store away the emu struct
|
|
unsigned char *__emu_buffer = in->pBuffer;
|
|
BazaarSearchResults_Struct *emu = (BazaarSearchResults_Struct *)__emu_buffer;
|
|
|
|
//determine and verify length
|
|
int entrycount = in->size / sizeof(BazaarSearchResults_Struct);
|
|
if (entrycount == 0 || (in->size % sizeof(BazaarSearchResults_Struct)) != 0) {
|
|
_log(NET__STRUCTS, "Wrong size on outbound %s: Got %d, expected multiple of %d",
|
|
opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(BazaarSearchResults_Struct));
|
|
delete in;
|
|
return;
|
|
}
|
|
|
|
//make the EQ struct.
|
|
in->size = sizeof(structs::BazaarSearchResults_Struct)*entrycount;
|
|
in->pBuffer = new unsigned char[in->size];
|
|
structs::BazaarSearchResults_Struct *eq = (structs::BazaarSearchResults_Struct *) in->pBuffer;
|
|
|
|
//zero out the packet. We could avoid this memset by setting all fields (including unknowns) in the loop.
|
|
memset(in->pBuffer, 0, in->size);
|
|
|
|
for (int i = 0; i < entrycount; i++, eq++, emu++) {
|
|
eq->Beginning.Action = emu->Beginning.Action;
|
|
eq->Beginning.Unknown001 = emu->Beginning.Unknown001;
|
|
eq->Beginning.Unknown002 = emu->Beginning.Unknown002;
|
|
eq->NumItems = emu->NumItems;
|
|
eq->SerialNumber = emu->SerialNumber;
|
|
eq->SellerID = emu->SellerID;
|
|
eq->Cost = emu->Cost;
|
|
eq->ItemStat = emu->ItemStat;
|
|
strcpy(eq->ItemName, emu->ItemName);
|
|
}
|
|
|
|
delete[] __emu_buffer;
|
|
dest->FastQueuePacket(&in, ack_req);
|
|
}
|
|
|
|
ENCODE(OP_BecomeTrader)
|
|
{
|
|
ENCODE_LENGTH_EXACT(BecomeTrader_Struct);
|
|
SETUP_DIRECT_ENCODE(BecomeTrader_Struct, structs::BecomeTrader_Struct);
|
|
|
|
OUT(ID);
|
|
OUT(Code);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_CharInventory)
|
|
{
|
|
//consume the packet
|
|
EQApplicationPacket *in = *p;
|
|
*p = nullptr;
|
|
|
|
//store away the emu struct
|
|
unsigned char *__emu_buffer = in->pBuffer;
|
|
|
|
int itemcount = in->size / sizeof(InternalSerializedItem_Struct);
|
|
if (itemcount == 0 || (in->size % sizeof(InternalSerializedItem_Struct)) != 0) {
|
|
_log(NET__STRUCTS, "Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(InternalSerializedItem_Struct));
|
|
delete in;
|
|
return;
|
|
}
|
|
InternalSerializedItem_Struct *eq = (InternalSerializedItem_Struct *)in->pBuffer;
|
|
|
|
//do the transform...
|
|
int r;
|
|
std::string serial_string;
|
|
for (r = 0; r < itemcount; r++, eq++) {
|
|
uint32 length;
|
|
char *serialized = SerializeItem((const ItemInst*)eq->inst, eq->slot_id, &length, 0);
|
|
if (serialized) {
|
|
serial_string.append(serialized, length + 1);
|
|
safe_delete_array(serialized);
|
|
}
|
|
else {
|
|
_log(NET__STRUCTS, "Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
|
}
|
|
|
|
}
|
|
|
|
in->size = serial_string.length();
|
|
in->pBuffer = new unsigned char[in->size];
|
|
memcpy(in->pBuffer, serial_string.c_str(), serial_string.length());
|
|
|
|
delete[] __emu_buffer;
|
|
|
|
dest->FastQueuePacket(&in, ack_req);
|
|
}
|
|
|
|
ENCODE(OP_DeleteCharge) { ENCODE_FORWARD(OP_MoveItem); }
|
|
|
|
ENCODE(OP_DeleteItem)
|
|
{
|
|
ENCODE_LENGTH_EXACT(DeleteItem_Struct);
|
|
SETUP_DIRECT_ENCODE(DeleteItem_Struct, structs::DeleteItem_Struct);
|
|
|
|
eq->from_slot = ServerToTitaniumSlot(emu->from_slot);
|
|
eq->to_slot = ServerToTitaniumSlot(emu->to_slot);
|
|
OUT(number_in_stack);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_DeleteSpawn)
|
|
{
|
|
SETUP_DIRECT_ENCODE(DeleteSpawn_Struct, structs::DeleteSpawn_Struct);
|
|
|
|
OUT(spawn_id);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_DzCompass)
|
|
{
|
|
SETUP_VAR_ENCODE(ExpeditionCompass_Struct);
|
|
ALLOC_VAR_ENCODE(structs::ExpeditionCompass_Struct, sizeof(structs::ExpeditionInfo_Struct) + sizeof(structs::ExpeditionCompassEntry_Struct) * emu->count);
|
|
|
|
OUT(count);
|
|
|
|
for (uint32 i = 0; i < emu->count; ++i)
|
|
{
|
|
OUT(entries[i].x);
|
|
OUT(entries[i].y);
|
|
OUT(entries[i].z);
|
|
}
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_DzExpeditionEndsWarning)
|
|
{
|
|
ENCODE_LENGTH_EXACT(ExpeditionExpireWarning);
|
|
SETUP_DIRECT_ENCODE(ExpeditionExpireWarning, structs::ExpeditionExpireWarning);
|
|
|
|
OUT(minutes_remaining);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_DzExpeditionInfo)
|
|
{
|
|
ENCODE_LENGTH_EXACT(ExpeditionInfo_Struct);
|
|
SETUP_DIRECT_ENCODE(ExpeditionInfo_Struct, structs::ExpeditionInfo_Struct);
|
|
|
|
OUT(max_players);
|
|
eq->enabled_max = 1;
|
|
strcpy(eq->expedition_name, emu->expedition_name);
|
|
strcpy(eq->leader_name, emu->leader_name);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_DzExpeditionList)
|
|
{
|
|
SETUP_VAR_ENCODE(ExpeditionLockoutList_Struct);
|
|
|
|
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
|
uint32 client_id = 0;
|
|
uint8 null_term = 0;
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write((const char*)&emu->count, sizeof(uint32));
|
|
for (uint32 i = 0; i < emu->count; ++i)
|
|
{
|
|
ss.write(emu->entries[i].expedition, strlen(emu->entries[i].expedition));
|
|
ss.write((const char*)&null_term, sizeof(char));
|
|
ss.write((const char*)&emu->entries[i].time_left, sizeof(uint32));
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write(emu->entries[i].expedition_event, strlen(emu->entries[i].expedition_event));
|
|
ss.write((const char*)&null_term, sizeof(char));
|
|
}
|
|
|
|
__packet->size = ss.str().length();
|
|
__packet->pBuffer = new unsigned char[__packet->size];
|
|
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_DzJoinExpeditionConfirm)
|
|
{
|
|
ENCODE_LENGTH_EXACT(ExpeditionJoinPrompt_Struct);
|
|
SETUP_DIRECT_ENCODE(ExpeditionJoinPrompt_Struct, structs::ExpeditionJoinPrompt_Struct);
|
|
|
|
strcpy(eq->expedition_name, emu->expedition_name);
|
|
strcpy(eq->player_name, emu->player_name);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_DzLeaderStatus)
|
|
{
|
|
SETUP_VAR_ENCODE(ExpeditionLeaderSet_Struct);
|
|
|
|
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
|
uint32 client_id = 0;
|
|
uint8 null_term = 0;
|
|
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
//ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write(emu->leader_name, strlen(emu->leader_name));
|
|
ss.write((const char*)&null_term, sizeof(char));
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write((const char*)&client_id, sizeof(uint32));//0xffffffff
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write((const char*)&client_id, sizeof(uint32));//1
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
|
|
__packet->size = ss.str().length();
|
|
__packet->pBuffer = new unsigned char[__packet->size];
|
|
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_DzMemberList)
|
|
{
|
|
SETUP_VAR_ENCODE(ExpeditionMemberList_Struct);
|
|
|
|
std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary);
|
|
|
|
uint32 client_id = 0;
|
|
uint8 null_term = 0;
|
|
ss.write((const char*)&client_id, sizeof(uint32));
|
|
ss.write((const char*)&emu->count, sizeof(uint32));
|
|
for (uint32 i = 0; i < emu->count; ++i)
|
|
{
|
|
ss.write(emu->entries[i].name, strlen(emu->entries[i].name));
|
|
ss.write((const char*)&null_term, sizeof(char));
|
|
ss.write((const char*)&emu->entries[i].status, sizeof(char));
|
|
}
|
|
|
|
__packet->size = ss.str().length();
|
|
__packet->pBuffer = new unsigned char[__packet->size];
|
|
memcpy(__packet->pBuffer, ss.str().c_str(), __packet->size);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_GuildMemberList)
|
|
{
|
|
//consume the packet
|
|
EQApplicationPacket *in = *p;
|
|
*p = nullptr;
|
|
|
|
//store away the emu struct
|
|
unsigned char *__emu_buffer = in->pBuffer;
|
|
Internal_GuildMembers_Struct *emu = (Internal_GuildMembers_Struct *)in->pBuffer;
|
|
|
|
//make a new EQ buffer.
|
|
uint32 pnl = strlen(emu->player_name);
|
|
uint32 length = sizeof(structs::GuildMembers_Struct) + pnl +
|
|
emu->count*sizeof(structs::GuildMemberEntry_Struct)
|
|
+ emu->name_length + emu->note_length;
|
|
in->pBuffer = new uint8[length];
|
|
in->size = length;
|
|
//no memset since we fill every byte.
|
|
|
|
uint8 *buffer;
|
|
buffer = in->pBuffer;
|
|
|
|
//easier way to setup GuildMembers_Struct
|
|
//set prefix name
|
|
strcpy((char *)buffer, emu->player_name);
|
|
buffer += pnl;
|
|
*buffer = '\0';
|
|
buffer++;
|
|
|
|
//add member count.
|
|
*((uint32 *)buffer) = htonl(emu->count);
|
|
buffer += sizeof(uint32);
|
|
|
|
if (emu->count > 0) {
|
|
Internal_GuildMemberEntry_Struct *emu_e = emu->member;
|
|
const char *emu_name = (const char *)(__emu_buffer +
|
|
sizeof(Internal_GuildMembers_Struct)+ //skip header
|
|
emu->count * sizeof(Internal_GuildMemberEntry_Struct) //skip static length member data
|
|
);
|
|
const char *emu_note = (emu_name +
|
|
emu->name_length + //skip name contents
|
|
emu->count //skip string terminators
|
|
);
|
|
|
|
structs::GuildMemberEntry_Struct *e = (structs::GuildMemberEntry_Struct *) buffer;
|
|
|
|
uint32 r;
|
|
for (r = 0; r < emu->count; r++, emu_e++) {
|
|
|
|
//the order we set things here must match the struct
|
|
|
|
//nice helper macro
|
|
/*#define SlideStructString(field, str) \
|
|
strcpy(e->field, str.c_str()); \
|
|
e = (GuildMemberEntry_Struct *) ( ((uint8 *)e) + str.length() )*/
|
|
#define SlideStructString(field, str) \
|
|
{ \
|
|
int sl = strlen(str); \
|
|
memcpy(e->field, str, sl+1); \
|
|
e = (structs::GuildMemberEntry_Struct *) ( ((uint8 *)e) + sl ); \
|
|
str += sl + 1; \
|
|
}
|
|
#define PutFieldN(field) e->field = htonl(emu_e->field)
|
|
|
|
SlideStructString(name, emu_name);
|
|
PutFieldN(level);
|
|
PutFieldN(banker);
|
|
PutFieldN(class_);
|
|
PutFieldN(rank);
|
|
PutFieldN(time_last_on);
|
|
PutFieldN(tribute_enable);
|
|
PutFieldN(total_tribute);
|
|
PutFieldN(last_tribute);
|
|
e->unknown_one = htonl(1);
|
|
SlideStructString(public_note, emu_note);
|
|
e->zoneinstance = 0;
|
|
e->zone_id = htons(emu_e->zone_id);
|
|
|
|
#undef SlideStructString
|
|
#undef PutFieldN
|
|
|
|
e++;
|
|
}
|
|
}
|
|
|
|
delete[] __emu_buffer;
|
|
dest->FastQueuePacket(&in, ack_req);
|
|
}
|
|
|
|
ENCODE(OP_Illusion)
|
|
{
|
|
ENCODE_LENGTH_EXACT(Illusion_Struct);
|
|
SETUP_DIRECT_ENCODE(Illusion_Struct, structs::Illusion_Struct);
|
|
|
|
OUT(spawnid);
|
|
OUT_str(charname);
|
|
|
|
if (emu->race > 473)
|
|
eq->race = 1;
|
|
else
|
|
OUT(race);
|
|
|
|
OUT(gender);
|
|
OUT(texture);
|
|
OUT(helmtexture);
|
|
OUT(face);
|
|
OUT(hairstyle);
|
|
OUT(haircolor);
|
|
OUT(beard);
|
|
OUT(beardcolor);
|
|
OUT(size);
|
|
/*
|
|
//Test code for identifying the structure
|
|
uint8 ofs;
|
|
uint8 val;
|
|
ofs = emu->texture;
|
|
val = emu->face;
|
|
((uint8*)eq)[ofs % 168] = val;
|
|
*/
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_InspectAnswer)
|
|
{
|
|
ENCODE_LENGTH_EXACT(InspectResponse_Struct);
|
|
SETUP_DIRECT_ENCODE(InspectResponse_Struct, structs::InspectResponse_Struct);
|
|
|
|
OUT(TargetID);
|
|
OUT(playerid);
|
|
|
|
int r;
|
|
for (r = 0; r <= 20; r++) {
|
|
strn0cpy(eq->itemnames[r], emu->itemnames[r], sizeof(eq->itemnames[r]));
|
|
}
|
|
|
|
// move arrow item down to last element in titanium array
|
|
strn0cpy(eq->itemnames[21], emu->itemnames[22], sizeof(eq->itemnames[21]));
|
|
|
|
int k;
|
|
for (k = 0; k <= 20; k++) {
|
|
OUT(itemicons[k]);
|
|
}
|
|
|
|
// move arrow icon down to last element in titanium array
|
|
eq->itemicons[21] = emu->itemicons[22];
|
|
strn0cpy(eq->text, emu->text, sizeof(eq->text));
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_InspectRequest)
|
|
{
|
|
ENCODE_LENGTH_EXACT(Inspect_Struct);
|
|
SETUP_DIRECT_ENCODE(Inspect_Struct, structs::Inspect_Struct);
|
|
|
|
OUT(TargetID);
|
|
OUT(PlayerID);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_ItemLinkResponse) { ENCODE_FORWARD(OP_ItemPacket); }
|
|
|
|
ENCODE(OP_ItemPacket)
|
|
{
|
|
//consume the packet
|
|
EQApplicationPacket *in = *p;
|
|
*p = nullptr;
|
|
|
|
//store away the emu struct
|
|
unsigned char *__emu_buffer = in->pBuffer;
|
|
ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer;
|
|
InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem);
|
|
|
|
uint32 length;
|
|
char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0);
|
|
|
|
if (!serialized) {
|
|
_log(NET__STRUCTS, "Serialization failed on item slot %d.", int_struct->slot_id);
|
|
delete in;
|
|
return;
|
|
}
|
|
in->size = length + 5; // ItemPacketType + Serialization + \0
|
|
in->pBuffer = new unsigned char[in->size];
|
|
ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer;
|
|
new_item_pkt->PacketType = old_item_pkt->PacketType;
|
|
memcpy(new_item_pkt->SerializedItem, serialized, length + 1);
|
|
|
|
delete[] __emu_buffer;
|
|
safe_delete_array(serialized);
|
|
|
|
dest->FastQueuePacket(&in, ack_req);
|
|
}
|
|
|
|
ENCODE(OP_LeadershipExpUpdate)
|
|
{
|
|
SETUP_DIRECT_ENCODE(LeadershipExpUpdate_Struct, structs::LeadershipExpUpdate_Struct);
|
|
|
|
OUT(group_leadership_exp);
|
|
OUT(group_leadership_points);
|
|
OUT(raid_leadership_exp);
|
|
OUT(raid_leadership_points);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_LFGuild)
|
|
{
|
|
EQApplicationPacket *in = *p;
|
|
*p = nullptr;
|
|
|
|
uint32 Command = in->ReadUInt32();
|
|
|
|
if (Command != 0)
|
|
{
|
|
dest->FastQueuePacket(&in, ack_req);
|
|
return;
|
|
}
|
|
|
|
EQApplicationPacket *outapp = new EQApplicationPacket(OP_LFGuild, sizeof(structs::LFGuild_PlayerToggle_Struct));
|
|
|
|
memcpy(outapp->pBuffer, in->pBuffer, sizeof(structs::LFGuild_PlayerToggle_Struct));
|
|
|
|
dest->FastQueuePacket(&outapp, ack_req);
|
|
delete in;
|
|
}
|
|
|
|
ENCODE(OP_LootItem)
|
|
{
|
|
ENCODE_LENGTH_EXACT(LootingItem_Struct);
|
|
SETUP_DIRECT_ENCODE(LootingItem_Struct, structs::LootingItem_Struct);
|
|
|
|
OUT(lootee);
|
|
OUT(looter);
|
|
eq->slot_id = ServerToTitaniumCorpseSlot(emu->slot_id);
|
|
OUT(auto_loot);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_MoveItem)
|
|
{
|
|
ENCODE_LENGTH_EXACT(MoveItem_Struct);
|
|
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
|
|
|
|
eq->from_slot = ServerToTitaniumSlot(emu->from_slot);
|
|
eq->to_slot = ServerToTitaniumSlot(emu->to_slot);
|
|
OUT(number_in_stack);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_NewSpawn) { ENCODE_FORWARD(OP_ZoneSpawns); }
|
|
|
|
ENCODE(OP_OnLevelMessage)
|
|
{
|
|
ENCODE_LENGTH_EXACT(OnLevelMessage_Struct);
|
|
SETUP_DIRECT_ENCODE(OnLevelMessage_Struct, structs::OnLevelMessage_Struct);
|
|
|
|
OUT_str(Title);
|
|
OUT_str(Text);
|
|
OUT(Buttons);
|
|
OUT(Duration);
|
|
OUT(PopupID);
|
|
|
|
eq->unknown4236 = 0x00000000;
|
|
eq->unknown4240 = 0xffffffff;
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_PetBuffWindow)
|
|
{
|
|
ENCODE_LENGTH_EXACT(PetBuff_Struct);
|
|
SETUP_DIRECT_ENCODE(PetBuff_Struct, PetBuff_Struct);
|
|
|
|
OUT(petid);
|
|
OUT(buffcount);
|
|
|
|
int EQBuffSlot = 0;
|
|
|
|
for (uint32 EmuBuffSlot = 0; EmuBuffSlot < BUFF_COUNT; ++EmuBuffSlot)
|
|
{
|
|
if (emu->spellid[EmuBuffSlot])
|
|
{
|
|
eq->spellid[EQBuffSlot] = emu->spellid[EmuBuffSlot];
|
|
eq->ticsremaining[EQBuffSlot++] = emu->ticsremaining[EmuBuffSlot];
|
|
}
|
|
}
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_PlayerProfile)
|
|
{
|
|
SETUP_DIRECT_ENCODE(PlayerProfile_Struct, structs::PlayerProfile_Struct);
|
|
|
|
uint32 r;
|
|
|
|
eq->available_slots = 0xffffffff;
|
|
memset(eq->unknown4184, 0xff, sizeof(eq->unknown4184));
|
|
memset(eq->unknown04396, 0xff, sizeof(eq->unknown04396));
|
|
|
|
// OUT(checksum);
|
|
OUT(gender);
|
|
OUT(race);
|
|
OUT(class_);
|
|
// OUT(unknown00016);
|
|
OUT(level);
|
|
eq->level1 = emu->level;
|
|
// OUT(unknown00022[2]);
|
|
for (r = 0; r < 5; r++) {
|
|
OUT(binds[r].zoneId);
|
|
OUT(binds[r].x);
|
|
OUT(binds[r].y);
|
|
OUT(binds[r].z);
|
|
OUT(binds[r].heading);
|
|
}
|
|
OUT(deity);
|
|
OUT(intoxication);
|
|
OUT_array(spellSlotRefresh, structs::MAX_PP_MEMSPELL);
|
|
OUT(abilitySlotRefresh);
|
|
OUT(haircolor);
|
|
OUT(beardcolor);
|
|
OUT(eyecolor1);
|
|
OUT(eyecolor2);
|
|
OUT(hairstyle);
|
|
OUT(beard);
|
|
// OUT(unknown00178[10]);
|
|
for (r = 0; r < 9; r++) {
|
|
OUT(item_material[r]);
|
|
OUT(item_tint[r].color);
|
|
}
|
|
// OUT(unknown00224[48]);
|
|
for (r = 0; r < structs::MAX_PP_AA_ARRAY; r++) {
|
|
OUT(aa_array[r].AA);
|
|
OUT(aa_array[r].value);
|
|
}
|
|
// OUT(unknown02220[4]);
|
|
OUT(points);
|
|
OUT(mana);
|
|
OUT(cur_hp);
|
|
OUT(STR);
|
|
OUT(STA);
|
|
OUT(CHA);
|
|
OUT(DEX);
|
|
OUT(INT);
|
|
OUT(AGI);
|
|
OUT(WIS);
|
|
OUT(face);
|
|
// OUT(unknown02264[47]);
|
|
OUT_array(spell_book, structs::MAX_PP_SPELLBOOK);
|
|
// OUT(unknown4184[448]);
|
|
OUT_array(mem_spells, structs::MAX_PP_MEMSPELL);
|
|
// OUT(unknown04396[32]);
|
|
OUT(platinum);
|
|
OUT(gold);
|
|
OUT(silver);
|
|
OUT(copper);
|
|
OUT(platinum_cursor);
|
|
OUT(gold_cursor);
|
|
OUT(silver_cursor);
|
|
OUT(copper_cursor);
|
|
|
|
OUT_array(skills, structs::MAX_PP_SKILL); // 1:1 direct copy (100 dword)
|
|
|
|
// OUT(unknown04760[236]);
|
|
OUT(toxicity);
|
|
OUT(thirst_level);
|
|
OUT(hunger_level);
|
|
for (r = 0; r < structs::BUFF_COUNT; r++) {
|
|
OUT(buffs[r].slotid);
|
|
OUT(buffs[r].level);
|
|
OUT(buffs[r].bard_modifier);
|
|
OUT(buffs[r].effect);
|
|
OUT(buffs[r].spellid);
|
|
OUT(buffs[r].duration);
|
|
OUT(buffs[r].counters);
|
|
OUT(buffs[r].player_id);
|
|
}
|
|
for (r = 0; r < structs::MAX_PP_DISCIPLINES; r++) {
|
|
OUT(disciplines.values[r]);
|
|
}
|
|
// OUT(unknown05008[360]);
|
|
// OUT_array(recastTimers, structs::MAX_RECAST_TYPES);
|
|
OUT(endurance);
|
|
OUT(aapoints_spent);
|
|
OUT(aapoints);
|
|
// OUT(unknown06160[4]);
|
|
for (r = 0; r < structs::MAX_PLAYER_BANDOLIER; r++) {
|
|
OUT_str(bandoliers[r].name);
|
|
uint32 k;
|
|
for (k = 0; k < structs::MAX_PLAYER_BANDOLIER_ITEMS; k++) {
|
|
OUT(bandoliers[r].items[k].item_id);
|
|
OUT(bandoliers[r].items[k].icon);
|
|
OUT_str(bandoliers[r].items[k].item_name);
|
|
}
|
|
}
|
|
// OUT(unknown07444[5120]);
|
|
for (r = 0; r < structs::MAX_PLAYER_BANDOLIER_ITEMS; r++) {
|
|
OUT(potionbelt.items[r].item_id);
|
|
OUT(potionbelt.items[r].icon);
|
|
OUT_str(potionbelt.items[r].item_name);
|
|
}
|
|
// OUT(unknown12852[8]);
|
|
// OUT(unknown12864[76]);
|
|
OUT_str(name);
|
|
OUT_str(last_name);
|
|
OUT(guild_id);
|
|
OUT(birthday);
|
|
OUT(lastlogin);
|
|
OUT(timePlayedMin);
|
|
OUT(pvp);
|
|
OUT(anon);
|
|
OUT(gm);
|
|
OUT(guildrank);
|
|
OUT(guildbanker);
|
|
// OUT(unknown13054[8]);
|
|
OUT(exp);
|
|
// OUT(unknown13072[12]);
|
|
OUT(timeentitledonaccount);
|
|
OUT_array(languages, structs::MAX_PP_LANGUAGE);
|
|
// OUT(unknown13109[7]);
|
|
OUT(x);
|
|
OUT(y);
|
|
OUT(z);
|
|
OUT(heading);
|
|
// OUT(unknown13132[4]);
|
|
OUT(platinum_bank);
|
|
OUT(gold_bank);
|
|
OUT(silver_bank);
|
|
OUT(copper_bank);
|
|
OUT(platinum_shared);
|
|
// OUT(unknown13156[84]);
|
|
OUT(expansions);
|
|
// OUT(unknown13244[12]);
|
|
OUT(autosplit);
|
|
// OUT(unknown13260[16]);
|
|
OUT(zone_id);
|
|
OUT(zoneInstance);
|
|
for (r = 0; r < structs::MAX_GROUP_MEMBERS; r++) {
|
|
OUT_str(groupMembers[r]);
|
|
}
|
|
strcpy(eq->groupLeader, emu->groupMembers[0]);
|
|
// OUT_str(groupLeader);
|
|
// OUT(unknown13728[660]);
|
|
OUT(entityid);
|
|
OUT(leadAAActive);
|
|
// OUT(unknown14392[4]);
|
|
OUT(ldon_points_guk);
|
|
OUT(ldon_points_mir);
|
|
OUT(ldon_points_mmc);
|
|
OUT(ldon_points_ruj);
|
|
OUT(ldon_points_tak);
|
|
OUT(ldon_points_available);
|
|
// OUT(unknown14420[132]);
|
|
OUT(tribute_time_remaining);
|
|
OUT(career_tribute_points);
|
|
// OUT(unknown7208);
|
|
OUT(tribute_points);
|
|
// OUT(unknown7216);
|
|
OUT(tribute_active);
|
|
for (r = 0; r < structs::MAX_PLAYER_TRIBUTES; r++) {
|
|
OUT(tributes[r].tribute);
|
|
OUT(tributes[r].tier);
|
|
}
|
|
// OUT(unknown14616[8]);
|
|
OUT(group_leadership_exp);
|
|
OUT(raid_leadership_exp);
|
|
OUT(group_leadership_points);
|
|
OUT(raid_leadership_points);
|
|
OUT_array(leader_abilities.ranks, structs::MAX_LEADERSHIP_AA_ARRAY);
|
|
// OUT(unknown14772[128]);
|
|
OUT(air_remaining);
|
|
OUT(PVPKills);
|
|
OUT(PVPDeaths);
|
|
OUT(PVPCurrentPoints);
|
|
OUT(PVPCareerPoints);
|
|
OUT(PVPBestKillStreak);
|
|
OUT(PVPWorstDeathStreak);
|
|
OUT(PVPCurrentKillStreak);
|
|
// OUT(unknown14932[4580]);
|
|
OUT(expAA);
|
|
// OUT(unknown19516[40]);
|
|
OUT(currentRadCrystals);
|
|
OUT(careerRadCrystals);
|
|
OUT(currentEbonCrystals);
|
|
OUT(careerEbonCrystals);
|
|
OUT(groupAutoconsent);
|
|
OUT(raidAutoconsent);
|
|
OUT(guildAutoconsent);
|
|
// OUT(unknown19575[5]);
|
|
eq->level3 = emu->level;
|
|
eq->showhelm = emu->showhelm;
|
|
// OUT(unknown19584[4]);
|
|
// OUT(unknown19588);
|
|
|
|
|
|
const uint8 bytes[] = {
|
|
0x78, 0x03, 0x00, 0x00, 0x1A, 0x04, 0x00, 0x00, 0x1A, 0x04, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
|
|
0x19, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00,
|
|
0x0F, 0x00, 0x00, 0x00, 0x1F, 0x85, 0xEB, 0x3E, 0x33, 0x33, 0x33, 0x3F, 0x09, 0x00, 0x00, 0x00,
|
|
0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14
|
|
};
|
|
memcpy(eq->unknown12864, bytes, sizeof(bytes));
|
|
|
|
//set the checksum...
|
|
CRC32::SetEQChecksum(__packet->pBuffer, sizeof(structs::PlayerProfile_Struct) - 4);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_ReadBook)
|
|
{
|
|
// no apparent slot translation needed -U
|
|
EQApplicationPacket *in = *p;
|
|
*p = nullptr;
|
|
|
|
unsigned char *__emu_buffer = in->pBuffer;
|
|
|
|
BookText_Struct *emu_BookText_Struct = (BookText_Struct *)__emu_buffer;
|
|
|
|
in->size = sizeof(structs::BookText_Struct) + strlen(emu_BookText_Struct->booktext);
|
|
in->pBuffer = new unsigned char[in->size];
|
|
|
|
structs::BookText_Struct *eq_BookText_Struct = (structs::BookText_Struct*)in->pBuffer;
|
|
|
|
eq_BookText_Struct->window = emu_BookText_Struct->window;
|
|
eq_BookText_Struct->type = emu_BookText_Struct->type;
|
|
strcpy(eq_BookText_Struct->booktext, emu_BookText_Struct->booktext);
|
|
|
|
delete[] __emu_buffer;
|
|
dest->FastQueuePacket(&in, ack_req);
|
|
}
|
|
|
|
ENCODE(OP_RespondAA)
|
|
{
|
|
ENCODE_LENGTH_EXACT(AATable_Struct);
|
|
SETUP_DIRECT_ENCODE(AATable_Struct, structs::AATable_Struct);
|
|
|
|
unsigned int r;
|
|
for (r = 0; r < structs::MAX_PP_AA_ARRAY; r++) {
|
|
OUT(aa_list[r].aa_skill);
|
|
OUT(aa_list[r].aa_value);
|
|
}
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_SendAATable)
|
|
{
|
|
ENCODE_LENGTH_ATLEAST(SendAA_Struct);
|
|
|
|
SETUP_VAR_ENCODE(SendAA_Struct);
|
|
ALLOC_VAR_ENCODE(structs::SendAA_Struct, sizeof(structs::SendAA_Struct) + emu->total_abilities*sizeof(structs::AA_Ability));
|
|
|
|
// Check clientver field to verify this AA should be sent for Titanium
|
|
// clientver 1 is for all clients and 3 is for Titanium
|
|
if (emu->clientver <= 3)
|
|
{
|
|
OUT(id);
|
|
eq->unknown004 = 1;
|
|
eq->hotkey_sid = (emu->hotkey_sid == 4294967295UL) ? 0 : (emu->id - emu->current_level + 1);
|
|
eq->hotkey_sid2 = (emu->hotkey_sid2 == 4294967295UL) ? 0 : (emu->id - emu->current_level + 1);
|
|
eq->title_sid = emu->id - emu->current_level + 1;
|
|
eq->desc_sid = emu->id - emu->current_level + 1;
|
|
OUT(class_type);
|
|
OUT(cost);
|
|
OUT(seq);
|
|
OUT(current_level);
|
|
OUT(prereq_skill);
|
|
OUT(prereq_minpoints);
|
|
OUT(type);
|
|
OUT(spellid);
|
|
OUT(spell_type);
|
|
OUT(spell_refresh);
|
|
OUT(classes);
|
|
OUT(berserker);
|
|
OUT(max_level);
|
|
OUT(last_id);
|
|
OUT(next_id);
|
|
OUT(cost2);
|
|
OUT(unknown80[0]);
|
|
OUT(unknown80[1]);
|
|
OUT(total_abilities);
|
|
unsigned int r;
|
|
for (r = 0; r < emu->total_abilities; r++) {
|
|
OUT(abilities[r].skill_id);
|
|
OUT(abilities[r].base1);
|
|
OUT(abilities[r].base2);
|
|
OUT(abilities[r].slot);
|
|
}
|
|
}
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_SendCharInfo)
|
|
{
|
|
ENCODE_LENGTH_EXACT(CharacterSelect_Struct);
|
|
SETUP_DIRECT_ENCODE(CharacterSelect_Struct, structs::CharacterSelect_Struct);
|
|
|
|
int r;
|
|
for (r = 0; r < 10; r++) {
|
|
OUT(zone[r]);
|
|
OUT(eyecolor1[r]);
|
|
OUT(eyecolor2[r]);
|
|
OUT(hairstyle[r]);
|
|
OUT(primary[r]);
|
|
if (emu->race[r] > 473)
|
|
eq->race[r] = 1;
|
|
else
|
|
eq->race[r] = emu->race[r];
|
|
OUT(class_[r]);
|
|
OUT_str(name[r]);
|
|
OUT(gender[r]);
|
|
OUT(level[r]);
|
|
OUT(secondary[r]);
|
|
OUT(face[r]);
|
|
OUT(beard[r]);
|
|
int k;
|
|
for (k = 0; k < 9; k++) {
|
|
OUT(equip[r][k]);
|
|
OUT(cs_colors[r][k].color);
|
|
}
|
|
OUT(haircolor[r]);
|
|
OUT(gohome[r]);
|
|
OUT(tutorial[r]);
|
|
OUT(deity[r]);
|
|
OUT(beardcolor[r]);
|
|
eq->unknown820[r] = 0xFF;
|
|
eq->unknown902[r] = 0xFF;
|
|
}
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_ShopPlayerSell)
|
|
{
|
|
ENCODE_LENGTH_EXACT(Merchant_Purchase_Struct);
|
|
SETUP_DIRECT_ENCODE(Merchant_Purchase_Struct, structs::Merchant_Purchase_Struct);
|
|
|
|
OUT(npcid);
|
|
eq->itemslot = ServerToTitaniumSlot(emu->itemslot);
|
|
OUT(quantity);
|
|
OUT(price);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_Track)
|
|
{
|
|
EQApplicationPacket *in = *p;
|
|
*p = nullptr;
|
|
|
|
unsigned char *__emu_buffer = in->pBuffer;
|
|
Track_Struct *emu = (Track_Struct *)__emu_buffer;
|
|
|
|
int EntryCount = in->size / sizeof(Track_Struct);
|
|
|
|
if (EntryCount == 0 || ((in->size % sizeof(Track_Struct))) != 0)
|
|
{
|
|
_log(NET__STRUCTS, "Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Track_Struct));
|
|
delete in;
|
|
return;
|
|
}
|
|
|
|
in->size = sizeof(structs::Track_Struct) * EntryCount;
|
|
in->pBuffer = new unsigned char[in->size];
|
|
structs::Track_Struct *eq = (structs::Track_Struct *) in->pBuffer;
|
|
|
|
for (int i = 0; i < EntryCount; ++i, ++eq, ++emu)
|
|
{
|
|
OUT(entityid);
|
|
OUT(padding002);
|
|
OUT(distance);
|
|
}
|
|
|
|
delete[] __emu_buffer;
|
|
dest->FastQueuePacket(&in, ack_req);
|
|
}
|
|
|
|
ENCODE(OP_Trader)
|
|
{
|
|
if ((*p)->size != sizeof(TraderBuy_Struct)) {
|
|
EQApplicationPacket *in = *p;
|
|
*p = nullptr;
|
|
dest->FastQueuePacket(&in, ack_req);
|
|
return;
|
|
}
|
|
|
|
ENCODE_FORWARD(OP_TraderBuy);
|
|
}
|
|
|
|
ENCODE(OP_TraderBuy)
|
|
{
|
|
ENCODE_LENGTH_EXACT(TraderBuy_Struct);
|
|
SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
|
|
|
OUT(Action);
|
|
OUT(Price);
|
|
OUT(TraderID);
|
|
memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName));
|
|
OUT(ItemID);
|
|
OUT(Quantity);
|
|
OUT(AlreadySold);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_TributeItem)
|
|
{
|
|
ENCODE_LENGTH_EXACT(TributeItem_Struct);
|
|
SETUP_DIRECT_ENCODE(TributeItem_Struct, structs::TributeItem_Struct);
|
|
|
|
eq->slot = ServerToTitaniumSlot(emu->slot);
|
|
OUT(quantity);
|
|
OUT(tribute_master_id);
|
|
OUT(tribute_points);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_VetRewardsAvaliable)
|
|
{
|
|
EQApplicationPacket *inapp = *p;
|
|
unsigned char * __emu_buffer = inapp->pBuffer;
|
|
|
|
uint32 count = ((*p)->Size() / sizeof(InternalVeteranReward));
|
|
*p = nullptr;
|
|
|
|
EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward)*count));
|
|
uchar *old_data = __emu_buffer;
|
|
uchar *data = outapp_create->pBuffer;
|
|
for (uint32 i = 0; i < count; ++i)
|
|
{
|
|
structs::VeteranReward *vr = (structs::VeteranReward*)data;
|
|
InternalVeteranReward *ivr = (InternalVeteranReward*)old_data;
|
|
|
|
vr->claim_id = ivr->claim_id;
|
|
vr->item.item_id = ivr->items[0].item_id;
|
|
strcpy(vr->item.item_name, ivr->items[0].item_name);
|
|
|
|
old_data += sizeof(InternalVeteranReward);
|
|
data += sizeof(structs::VeteranReward);
|
|
}
|
|
|
|
dest->FastQueuePacket(&outapp_create);
|
|
delete inapp;
|
|
}
|
|
|
|
ENCODE(OP_WearChange)
|
|
{
|
|
ENCODE_LENGTH_EXACT(WearChange_Struct);
|
|
SETUP_DIRECT_ENCODE(WearChange_Struct, structs::WearChange_Struct);
|
|
|
|
OUT(spawn_id);
|
|
OUT(material);
|
|
OUT(color.color);
|
|
OUT(wear_slot_id);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_ZoneEntry) { ENCODE_FORWARD(OP_ZoneSpawns); }
|
|
|
|
ENCODE(OP_ZoneSpawns)
|
|
{
|
|
//consume the packet
|
|
EQApplicationPacket *in = *p;
|
|
*p = nullptr;
|
|
|
|
//store away the emu struct
|
|
unsigned char *__emu_buffer = in->pBuffer;
|
|
Spawn_Struct *emu = (Spawn_Struct *)__emu_buffer;
|
|
|
|
//determine and verify length
|
|
int entrycount = in->size / sizeof(Spawn_Struct);
|
|
if (entrycount == 0 || (in->size % sizeof(Spawn_Struct)) != 0) {
|
|
_log(NET__STRUCTS, "Wrong size on outbound %s: Got %d, expected multiple of %d", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
|
delete in;
|
|
return;
|
|
}
|
|
|
|
//make the EQ struct.
|
|
in->size = sizeof(structs::Spawn_Struct)*entrycount;
|
|
in->pBuffer = new unsigned char[in->size];
|
|
structs::Spawn_Struct *eq = (structs::Spawn_Struct *) in->pBuffer;
|
|
|
|
//zero out the packet. We could avoid this memset by setting all fields (including unknowns)
|
|
//in the loop.
|
|
memset(in->pBuffer, 0, in->size);
|
|
|
|
//do the transform...
|
|
int r;
|
|
int k;
|
|
for (r = 0; r < entrycount; r++, eq++, emu++) {
|
|
// eq->unknown0000 = emu->unknown0000;
|
|
eq->gm = emu->gm;
|
|
// eq->unknown0003 = emu->unknown0003;
|
|
eq->aaitle = emu->aaitle;
|
|
// eq->unknown0004 = emu->unknown0004;
|
|
eq->anon = emu->anon;
|
|
eq->face = emu->face;
|
|
strcpy(eq->name, emu->name);
|
|
eq->deity = emu->deity;
|
|
// eq->unknown0073 = emu->unknown0073;
|
|
eq->size = emu->size;
|
|
// eq->unknown0079 = emu->unknown0079;
|
|
eq->NPC = emu->NPC;
|
|
eq->invis = emu->invis;
|
|
eq->haircolor = emu->haircolor;
|
|
eq->curHp = emu->curHp;
|
|
eq->max_hp = emu->max_hp;
|
|
eq->findable = emu->findable;
|
|
// eq->unknown0089[5] = emu->unknown0089[5];
|
|
eq->deltaHeading = emu->deltaHeading;
|
|
eq->x = emu->x;
|
|
// eq->padding0054 = emu->padding0054;
|
|
eq->y = emu->y;
|
|
eq->animation = emu->animation;
|
|
// eq->padding0058 = emu->padding0058;
|
|
eq->z = emu->z;
|
|
eq->deltaY = emu->deltaY;
|
|
eq->deltaX = emu->deltaX;
|
|
eq->heading = emu->heading;
|
|
// eq->padding0066 = emu->padding0066;
|
|
eq->deltaZ = emu->deltaZ;
|
|
// eq->padding0070 = emu->padding0070;
|
|
eq->eyecolor1 = emu->eyecolor1;
|
|
// eq->unknown0115[24] = emu->unknown0115[24];
|
|
eq->showhelm = emu->showhelm;
|
|
// eq->unknown0140[4] = emu->unknown0140[4];
|
|
eq->is_npc = emu->is_npc;
|
|
eq->hairstyle = emu->hairstyle;
|
|
|
|
//if(emu->gender == 1){
|
|
// eq->hairstyle = eq->hairstyle == 0xFF ? 0 : eq->hairstyle;
|
|
//}
|
|
|
|
eq->beardcolor = emu->beardcolor;
|
|
// eq->unknown0147[4] = emu->unknown0147[4];
|
|
eq->level = emu->level;
|
|
// eq->unknown0259[4] = emu->unknown0259[4];
|
|
eq->beard = emu->beard;
|
|
strcpy(eq->suffix, emu->suffix);
|
|
eq->petOwnerId = emu->petOwnerId;
|
|
eq->guildrank = emu->guildrank;
|
|
// eq->unknown0194[3] = emu->unknown0194[3];
|
|
for (k = 0; k < 9; k++) {
|
|
eq->equipment[k] = emu->equipment[k];
|
|
eq->colors[k].color = emu->colors[k].color;
|
|
}
|
|
for (k = 0; k < 8; k++) {
|
|
eq->set_to_0xFF[k] = 0xFF;
|
|
}
|
|
|
|
eq->runspeed = emu->runspeed;
|
|
eq->afk = emu->afk;
|
|
eq->guildID = emu->guildID;
|
|
strcpy(eq->title, emu->title);
|
|
// eq->unknown0274 = emu->unknown0274;
|
|
eq->helm = emu->helm;
|
|
if (emu->race > 473)
|
|
eq->race = 1;
|
|
else
|
|
eq->race = emu->race;
|
|
// eq->unknown0288 = emu->unknown0288;
|
|
strcpy(eq->lastName, emu->lastName);
|
|
eq->walkspeed = emu->walkspeed;
|
|
// eq->unknown0328 = emu->unknown0328;
|
|
eq->is_pet = emu->is_pet;
|
|
eq->light = emu->light;
|
|
eq->class_ = emu->class_;
|
|
eq->eyecolor2 = emu->eyecolor2;
|
|
// eq->unknown0333 = emu->unknown0333;
|
|
eq->flymode = emu->flymode;
|
|
eq->gender = emu->gender;
|
|
eq->bodytype = emu->bodytype;
|
|
// eq->unknown0336[3] = emu->unknown0336[3];
|
|
eq->equip_chest2 = emu->equip_chest2;
|
|
eq->spawnId = emu->spawnId;
|
|
// eq->unknown0344[4] = emu->unknown0344[4];
|
|
eq->lfg = emu->lfg;
|
|
|
|
/*
|
|
if (emu->face == 99) {eq->face = 0;}
|
|
if (emu->eyecolor1 == 99) {eq->eyecolor1 = 0;}
|
|
if (emu->eyecolor2 == 99) {eq->eyecolor2 = 0;}
|
|
if (emu->hairstyle == 99) {eq->hairstyle = 0;}
|
|
if (emu->haircolor == 99) {eq->haircolor = 0;}
|
|
if (emu->beard == 99) {eq->beard = 0;}
|
|
if (emu->beardcolor == 99) {eq->beardcolor = 0;}
|
|
*/
|
|
|
|
}
|
|
|
|
//kill off the emu structure and send the eq packet.
|
|
delete[] __emu_buffer;
|
|
dest->FastQueuePacket(&in, ack_req);
|
|
}
|
|
|
|
// DECODE methods
|
|
DECODE(OP_AdventureMerchantSell)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::Adventure_Sell_Struct);
|
|
SETUP_DIRECT_DECODE(Adventure_Sell_Struct, structs::Adventure_Sell_Struct);
|
|
|
|
IN(npcid);
|
|
emu->slot = TitaniumToServerSlot(eq->slot);
|
|
IN(charges);
|
|
IN(sell_price);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_ApplyPoison)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::ApplyPoison_Struct);
|
|
SETUP_DIRECT_DECODE(ApplyPoison_Struct, structs::ApplyPoison_Struct);
|
|
|
|
emu->inventorySlot = TitaniumToServerSlot(eq->inventorySlot);
|
|
IN(success);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_AugmentItem)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::AugmentItem_Struct);
|
|
SETUP_DIRECT_DECODE(AugmentItem_Struct, structs::AugmentItem_Struct);
|
|
|
|
emu->container_slot = TitaniumToServerSlot(eq->container_slot);
|
|
emu->augment_slot = eq->augment_slot;
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_CastSpell)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::CastSpell_Struct);
|
|
SETUP_DIRECT_DECODE(CastSpell_Struct, structs::CastSpell_Struct);
|
|
|
|
IN(slot);
|
|
IN(spell_id);
|
|
emu->inventoryslot = TitaniumToServerSlot(eq->inventoryslot);
|
|
IN(target_id);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_CharacterCreate)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::CharCreate_Struct);
|
|
SETUP_DIRECT_DECODE(CharCreate_Struct, structs::CharCreate_Struct);
|
|
|
|
IN(class_);
|
|
IN(beardcolor);
|
|
IN(beard);
|
|
IN(haircolor);
|
|
IN(gender);
|
|
IN(race);
|
|
IN(start_zone);
|
|
IN(hairstyle);
|
|
IN(deity);
|
|
IN(STR);
|
|
IN(STA);
|
|
IN(AGI);
|
|
IN(DEX);
|
|
IN(WIS);
|
|
IN(INT);
|
|
IN(CHA);
|
|
IN(face);
|
|
IN(eyecolor1);
|
|
IN(eyecolor2);
|
|
IN(tutorial);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_Consume)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::Consume_Struct);
|
|
SETUP_DIRECT_DECODE(Consume_Struct, structs::Consume_Struct);
|
|
|
|
emu->slot = TitaniumToServerSlot(eq->slot);
|
|
IN(auto_consumed);
|
|
IN(type);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_DeleteItem)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::DeleteItem_Struct);
|
|
SETUP_DIRECT_DECODE(DeleteItem_Struct, structs::DeleteItem_Struct);
|
|
|
|
emu->from_slot = TitaniumToServerSlot(eq->from_slot);
|
|
emu->to_slot =TitaniumToServerSlot(eq->to_slot);
|
|
IN(number_in_stack);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_FaceChange)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::FaceChange_Struct);
|
|
SETUP_DIRECT_DECODE(FaceChange_Struct, structs::FaceChange_Struct);
|
|
IN(haircolor);
|
|
IN(beardcolor);
|
|
IN(eyecolor1);
|
|
IN(eyecolor2);
|
|
IN(hairstyle);
|
|
IN(beard);
|
|
IN(face);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_InspectAnswer)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::InspectResponse_Struct);
|
|
SETUP_DIRECT_DECODE(InspectResponse_Struct, structs::InspectResponse_Struct);
|
|
|
|
IN(TargetID);
|
|
IN(playerid);
|
|
|
|
int r;
|
|
for (r = 0; r <= 20; r++) {
|
|
strn0cpy(emu->itemnames[r], eq->itemnames[r], sizeof(emu->itemnames[r]));
|
|
}
|
|
|
|
// move arrow item up to last element in server array
|
|
strn0cpy(emu->itemnames[21], "", sizeof(emu->itemnames[21]));
|
|
strn0cpy(emu->itemnames[22], eq->itemnames[21], sizeof(emu->itemnames[22]));
|
|
|
|
int k;
|
|
for (k = 0; k <= 20; k++) {
|
|
IN(itemicons[k]);
|
|
}
|
|
|
|
// move arrow icon up to last element in server array
|
|
emu->itemicons[21] = 0xFFFFFFFF;
|
|
emu->itemicons[22] = eq->itemicons[21];
|
|
|
|
strn0cpy(emu->text, eq->text, sizeof(emu->text));
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_InspectRequest)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::Inspect_Struct);
|
|
SETUP_DIRECT_DECODE(Inspect_Struct, structs::Inspect_Struct);
|
|
|
|
IN(TargetID);
|
|
IN(PlayerID);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_ItemLinkClick)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::ItemViewRequest_Struct);
|
|
SETUP_DIRECT_DECODE(ItemViewRequest_Struct, structs::ItemViewRequest_Struct);
|
|
MEMSET_IN(ItemViewRequest_Struct);
|
|
|
|
IN(item_id);
|
|
int r;
|
|
for (r = 0; r < 5; r++) {
|
|
IN(augments[r]);
|
|
}
|
|
IN(link_hash);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_LFGuild)
|
|
{
|
|
uint32 Command = __packet->ReadUInt32();
|
|
|
|
if (Command != 0)
|
|
return;
|
|
|
|
SETUP_DIRECT_DECODE(LFGuild_PlayerToggle_Struct, structs::LFGuild_PlayerToggle_Struct);
|
|
memcpy(emu, eq, sizeof(structs::LFGuild_PlayerToggle_Struct));
|
|
memset(emu->Unknown612, 0, sizeof(emu->Unknown612));
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_LootItem)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
|
|
SETUP_DIRECT_DECODE(LootingItem_Struct, structs::LootingItem_Struct);
|
|
|
|
IN(lootee);
|
|
IN(looter);
|
|
emu->slot_id = TitaniumToServerCorpseSlot(eq->slot_id);
|
|
IN(auto_loot);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_MoveItem)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
|
|
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
|
|
|
|
_log(NET__ERROR, "Moved item from %u to %u", eq->from_slot, eq->to_slot);
|
|
|
|
emu->from_slot = TitaniumToServerSlot(eq->from_slot);
|
|
emu->to_slot = TitaniumToServerSlot(eq->to_slot);
|
|
IN(number_in_stack);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_ReadBook)
|
|
{
|
|
// no apparent slot translation needed -U
|
|
DECODE_LENGTH_ATLEAST(structs::BookRequest_Struct);
|
|
SETUP_DIRECT_DECODE(BookRequest_Struct, structs::BookRequest_Struct);
|
|
|
|
IN(window);
|
|
IN(type);
|
|
strn0cpy(emu->txtfile, eq->txtfile, sizeof(emu->txtfile));
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_SetServerFilter)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::SetServerFilter_Struct);
|
|
SETUP_DIRECT_DECODE(SetServerFilter_Struct, structs::SetServerFilter_Struct);
|
|
|
|
int r;
|
|
for (r = 0; r < 29; r++) {
|
|
IN(filters[r]);
|
|
}
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_ShopPlayerSell)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::Merchant_Purchase_Struct);
|
|
SETUP_DIRECT_DECODE(Merchant_Purchase_Struct, structs::Merchant_Purchase_Struct);
|
|
|
|
IN(npcid);
|
|
emu->itemslot = TitaniumToServerSlot(eq->itemslot);
|
|
IN(quantity);
|
|
IN(price);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_TraderBuy)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::TraderBuy_Struct);
|
|
SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct);
|
|
MEMSET_IN(TraderBuy_Struct);
|
|
|
|
IN(Action);
|
|
IN(Price);
|
|
IN(TraderID);
|
|
memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName));
|
|
IN(ItemID);
|
|
IN(Quantity);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_TradeSkillCombine)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::NewCombine_Struct);
|
|
SETUP_DIRECT_DECODE(NewCombine_Struct, structs::NewCombine_Struct);
|
|
|
|
emu->container_slot = TitaniumToServerSlot(eq->container_slot);
|
|
IN(guildtribute_slot);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_TributeItem)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::TributeItem_Struct);
|
|
SETUP_DIRECT_DECODE(TributeItem_Struct, structs::TributeItem_Struct);
|
|
|
|
emu->slot = TitaniumToServerSlot(eq->slot);
|
|
IN(quantity);
|
|
IN(tribute_master_id);
|
|
IN(tribute_points);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_WearChange)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::WearChange_Struct);
|
|
SETUP_DIRECT_DECODE(WearChange_Struct, structs::WearChange_Struct);
|
|
|
|
IN(spawn_id);
|
|
IN(material);
|
|
IN(color.color);
|
|
IN(wear_slot_id);
|
|
emu->unknown06 = 0;
|
|
emu->elite_material = 0;
|
|
emu->hero_forge_model = 0;
|
|
emu->unknown18 = 0;
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_WhoAllRequest)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::Who_All_Struct);
|
|
SETUP_DIRECT_DECODE(Who_All_Struct, structs::Who_All_Struct);
|
|
|
|
memcpy(emu->whom, eq->whom, sizeof(emu->whom));
|
|
IN(wrace);
|
|
IN(wclass);
|
|
IN(lvllow);
|
|
IN(lvlhigh);
|
|
IN(gmlookup);
|
|
emu->type = 3;
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
// file scope helper methods
|
|
char *SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint8 depth)
|
|
{
|
|
char *serialization = nullptr;
|
|
char *instance = nullptr;
|
|
const char *protection = (const char *)"\\\\\\\\\\";
|
|
char *sub_items[10] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
|
|
bool stackable = inst->IsStackable();
|
|
int16 slot_id = ServerToTitaniumSlot(slot_id_in);
|
|
uint32 merchant_slot = inst->GetMerchantSlot();
|
|
int16 charges = inst->GetCharges();
|
|
const Item_Struct *item = inst->GetItem();
|
|
int i;
|
|
uint32 sub_length;
|
|
|
|
MakeAnyLenString(&instance,
|
|
"%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|%i|",
|
|
stackable ? charges : 0,
|
|
0,
|
|
//(merchant_slot == 0) ? slot_id : merchant_slot, // change when translator activated
|
|
(merchant_slot == 0) ? slot_id_in : merchant_slot,
|
|
inst->GetPrice(),
|
|
(merchant_slot == 0) ? 1 : inst->GetMerchantCount(),
|
|
0,
|
|
//merchant_slot, //instance ID, bullshit for now
|
|
(merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot,
|
|
0, // item recast timer timestamp field (aka..last_cast_time field in SoF+ clients)
|
|
(stackable ? ((inst->GetItem()->ItemType == ItemTypePotion) ? 1 : 0) : charges),
|
|
inst->IsInstNoDrop() ? 1 : 0,
|
|
0
|
|
);
|
|
|
|
for (i = 0; i<10; i++) {
|
|
ItemInst *sub = inst->GetItem(i);
|
|
if (sub) {
|
|
sub_items[i] = SerializeItem(sub, 0, &sub_length, depth + 1);
|
|
}
|
|
}
|
|
|
|
*length = MakeAnyLenString(&serialization,
|
|
"%.*s%s" // For leading quotes (and protection) if a subitem;
|
|
"%s" // Instance data
|
|
"%.*s\"" // Quotes (and protection, if needed) around static data
|
|
"%i" // item->ItemClass so we can do |%s instead of %s|
|
|
#define I(field) "|%i"
|
|
#define C(field) "|%s"
|
|
#define S(field) "|%s"
|
|
#define F(field) "|%f"
|
|
#include "titanium_itemfields.h"
|
|
"%.*s\"" // Quotes (and protection, if needed) around static data
|
|
"|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s" // Sub items
|
|
"%.*s%s" // For trailing quotes (and protection) if a subitem;
|
|
, depth ? depth - 1 : 0, protection, (depth) ? "\"" : ""
|
|
, instance
|
|
, depth, protection
|
|
, item->ItemClass
|
|
#define I(field) ,item->field
|
|
#define C(field) ,field
|
|
#define S(field) ,item->field
|
|
#define F(field) ,item->field
|
|
#include "titanium_itemfields.h"
|
|
, depth, protection
|
|
, sub_items[0] ? sub_items[0] : ""
|
|
, sub_items[1] ? sub_items[1] : ""
|
|
, sub_items[2] ? sub_items[2] : ""
|
|
, sub_items[3] ? sub_items[3] : ""
|
|
, sub_items[4] ? sub_items[4] : ""
|
|
, sub_items[5] ? sub_items[5] : ""
|
|
, sub_items[6] ? sub_items[6] : ""
|
|
, sub_items[7] ? sub_items[7] : ""
|
|
, sub_items[8] ? sub_items[8] : ""
|
|
, sub_items[9] ? sub_items[9] : ""
|
|
, (depth) ? depth - 1 : 0, protection, (depth) ? "\"" : ""
|
|
);
|
|
|
|
for (i = 0; i<10; i++) {
|
|
if (sub_items[i])
|
|
safe_delete_array(sub_items[i]);
|
|
}
|
|
|
|
safe_delete_array(instance);
|
|
return serialization;
|
|
}
|
|
|
|
static inline int16 ServerToTitaniumSlot(uint32 ServerSlot)
|
|
{
|
|
//int16 TitaniumSlot;
|
|
if (ServerSlot == INVALID_INDEX)
|
|
return INVALID_INDEX;
|
|
|
|
return ServerSlot; // deprecated
|
|
}
|
|
|
|
static inline int16 ServerToTitaniumCorpseSlot(uint32 ServerCorpse)
|
|
{
|
|
//int16 TitaniumCorpse;
|
|
return ServerCorpse;
|
|
}
|
|
|
|
static inline uint32 TitaniumToServerSlot(int16 TitaniumSlot)
|
|
{
|
|
//uint32 ServerSlot;
|
|
if (TitaniumSlot == INVALID_INDEX)
|
|
return INVALID_INDEX;
|
|
|
|
return TitaniumSlot; // deprecated
|
|
}
|
|
|
|
static inline uint32 TitaniumToServerCorpseSlot(int16 TitaniumCorpse)
|
|
{
|
|
//uint32 ServerCorpse;
|
|
return TitaniumCorpse;
|
|
}
|
|
}
|
|
// end namespace Titanium
|