mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 10:31:29 +00:00
3951 lines
100 KiB
C++
3951 lines
100 KiB
C++
/* EQEMu: Everquest Server Emulator
|
|
|
|
Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net)
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
are required to give you total support for your newly bought product;
|
|
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "../global_define.h"
|
|
#include "../eqemu_config.h"
|
|
#include "../eqemu_logsys.h"
|
|
#include "laurion.h"
|
|
#include "../opcodemgr.h"
|
|
|
|
#include "../eq_stream_ident.h"
|
|
#include "../crc32.h"
|
|
|
|
#include "../eq_packet_structs.h"
|
|
#include "../misc_functions.h"
|
|
#include "../strings.h"
|
|
#include "../inventory_profile.h"
|
|
#include "laurion_structs.h"
|
|
#include "../rulesys.h"
|
|
#include "../path_manager.h"
|
|
#include "../classes.h"
|
|
#include "../races.h"
|
|
#include "../raid.h"
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <numeric>
|
|
#include <cassert>
|
|
#include <cinttypes>
|
|
|
|
namespace Laurion
|
|
{
|
|
static const char* name = "Laurion";
|
|
static OpcodeManager* opcodes = nullptr;
|
|
static Strategy struct_strategy;
|
|
|
|
void SerializeItem(SerializeBuffer &buffer, const EQ::ItemInstance* inst, int16 slot_id, uint8 depth, ItemPacketType packet_type);
|
|
|
|
// server to client inventory location converters
|
|
static inline structs::InventorySlot_Struct ServerToLaurionSlot(uint32 server_slot);
|
|
static inline structs::InventorySlot_Struct ServerToLaurionCorpseSlot(uint32 server_corpse_slot);
|
|
static inline uint32 ServerToLaurionCorpseMainSlot(uint32 server_corpse_slot);
|
|
static inline structs::TypelessInventorySlot_Struct ServerToLaurionTypelessSlot(uint32 server_slot, int16 server_type);
|
|
|
|
// client to server inventory location converters
|
|
static inline uint32 LaurionToServerSlot(structs::InventorySlot_Struct laurion_slot);
|
|
static inline uint32 LaurionToServerCorpseSlot(structs::InventorySlot_Struct laurion_corpse_slot);
|
|
static inline uint32 LaurionToServerCorpseMainSlot(uint32 laurion_corpse_slot);
|
|
static inline uint32 LaurionToServerTypelessSlot(structs::TypelessInventorySlot_Struct laurion_slot, int16 laurion_type);
|
|
|
|
void Register(EQStreamIdentifier& into)
|
|
{
|
|
//create our opcode manager if we havent already
|
|
if (opcodes == nullptr) {
|
|
|
|
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
|
|
|
|
//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())) {
|
|
LogNetcode("[OPCODES] Error loading opcodes file [{}]. Not registering patch [{}]", opfile.c_str(), name);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//ok, now we have what we need to register.
|
|
|
|
EQStreamInterface::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);
|
|
LogNetcode("[StreamIdentify] Registered patch [{}]", 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) {
|
|
std::string opfile = fmt::format("{}/patch_{}.conf", path.GetPatchPath(), name);
|
|
if (!opcodes->ReloadOpcodes(opfile.c_str())) {
|
|
LogNetcode("[OPCODES] Error reloading opcodes file [{}] for patch [{}]", opfile.c_str(), name);
|
|
return;
|
|
}
|
|
LogNetcode("[OPCODES] Reloaded opcodes for patch [{}]", name);
|
|
}
|
|
}
|
|
|
|
Strategy::Strategy() : StructStrategy()
|
|
{
|
|
//all opcodes default to passthrough.
|
|
#include "ss_register.h"
|
|
#include "laurion_ops.h"
|
|
}
|
|
|
|
std::string Strategy::Describe() const
|
|
{
|
|
std::string r;
|
|
r += "Patch ";
|
|
r += name;
|
|
return(r);
|
|
}
|
|
|
|
const EQ::versions::ClientVersion Strategy::ClientVersion() const
|
|
{
|
|
return EQ::versions::ClientVersion::Laurion;
|
|
}
|
|
|
|
#include "ss_define.h"
|
|
|
|
// ENCODE methods
|
|
ENCODE(OP_LogServer) {
|
|
SETUP_VAR_ENCODE(LogServer_Struct);
|
|
ALLOC_LEN_ENCODE(1840);
|
|
|
|
//pvp
|
|
if (emu->enable_pvp) {
|
|
*(char*)&__packet->pBuffer[0x04] = 1;
|
|
}
|
|
|
|
if (emu->enable_FV) {
|
|
//FV sets these both to 1
|
|
//one appears to enable the no drop flag the other just marks the server as special?
|
|
*(char*)&__packet->pBuffer[0x08] = 1;
|
|
*(char*)&__packet->pBuffer[0x0a] = 1;
|
|
}
|
|
|
|
//This has something to do with heirloom and prestige items but im not sure what it does
|
|
//Seems to sit at 0
|
|
*(char*)&__packet->pBuffer[0x71d] = 0;
|
|
|
|
//not sure what this does, something to do with server select
|
|
*(char*)&__packet->pBuffer[0x09] = 0;
|
|
|
|
//this appears to have some effect on the tradeskill system; disabling made by tags perhaps?
|
|
*(char*)&__packet->pBuffer[0x0b] = 0;
|
|
|
|
//not sure, setting it to the value ive seen
|
|
*(char*)&__packet->pBuffer[0x0c] = 1;
|
|
|
|
//Something to do with languages
|
|
*(char*)&__packet->pBuffer[0x0d] = 1;
|
|
|
|
//These seem to affect if server has betabuff enabled
|
|
*(char*)&__packet->pBuffer[0x5c0] = 0;
|
|
*(char*)&__packet->pBuffer[0x5c1] = 0;
|
|
//This is set on test so it's probably indicating this is a test server
|
|
*(char*)&__packet->pBuffer[0x5c2] = 0;
|
|
|
|
//not sure, but it's grouped with the beta and test stuff
|
|
*(char*)&__packet->pBuffer[0x5c3] = 0;
|
|
|
|
//world short name
|
|
strncpy((char*)&__packet->pBuffer[0x15], emu->worldshortname, 32);
|
|
|
|
//not sure, affects some player calculation but didn't care to look more
|
|
*(char*)&__packet->pBuffer[0x5c2] = 0;
|
|
|
|
//Looks right
|
|
if (emu->enablemail) {
|
|
*(char*)&__packet->pBuffer[0x5b5] = 1;
|
|
}
|
|
|
|
//Looks right
|
|
if (emu->enablevoicemacros) {
|
|
*(char*)&__packet->pBuffer[0x5b4] = 1;
|
|
}
|
|
|
|
//Not sure, sending what we've seen
|
|
*(char*)&__packet->pBuffer[0x5b6] = 0;
|
|
|
|
//Not sure sending what we've seen
|
|
*(char*)&__packet->pBuffer[0x5b8] = 1;
|
|
|
|
//Not sure sending what we've seen
|
|
*(int32_t*)&__packet->pBuffer[0x5fc] = -1;
|
|
|
|
//Test sets this to 1, everyone else seems to set it to 0
|
|
*(int32_t*)&__packet->pBuffer[0x600] = 0;
|
|
|
|
//Disassembly puts it next to code dealing with commands, ive not seen anyone send anything but 0
|
|
*(char*)&__packet->pBuffer[0x705] = 0;
|
|
|
|
//Something about item restrictions, seems to always be set to 1
|
|
*(char*)&__packet->pBuffer[0x710] = 1;
|
|
|
|
//This and 0x724 are often multiplied together in guild favor calcs, live and test send 1.0f
|
|
*(float*)&__packet->pBuffer[0x720] = 1.0f;
|
|
*(float*)&__packet->pBuffer[0x724] = 1.0f;
|
|
|
|
//This and 0x72c are often multiplied together in non-guild favor calcs, live and test send 1.0f
|
|
*(float*)&__packet->pBuffer[0x728] = 1.0f;
|
|
*(float*)&__packet->pBuffer[0x72c] = 1.0f;
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_SendMembership) {
|
|
ENCODE_LENGTH_EXACT(Membership_Struct);
|
|
SETUP_DIRECT_ENCODE(Membership_Struct, structs::Membership_Struct);
|
|
|
|
eq->membership = emu->membership;
|
|
eq->races = emu->races;
|
|
eq->classes = emu->classes;
|
|
eq->entrysize = 33;
|
|
eq->entries[0] = -1; // Max AA Restriction
|
|
eq->entries[1] = -1; // Max Level Restriction
|
|
eq->entries[2] = -1; // Max Char Slots per Account (not used by client?)
|
|
eq->entries[3] = -1; // 1 for Silver
|
|
eq->entries[4] = -1; // Main Inventory Size
|
|
eq->entries[5] = -1; // Max Platinum per level
|
|
eq->entries[6] = 1; // Send Mail
|
|
eq->entries[7] = 1; // Use Parcels?
|
|
eq->entries[8] = 1; // Voice Chat
|
|
eq->entries[9] = -1; // Merc Tiers
|
|
eq->entries[10] = 1; // Create Guilds
|
|
eq->entries[11] = -1; // Shared Bank Slots
|
|
eq->entries[12] = -1; // Max Journal Quests
|
|
eq->entries[13] = 1; // Housing Enabled
|
|
eq->entries[14] = 1; // Prestiege
|
|
eq->entries[15] = 1; // Broker System
|
|
eq->entries[16] = 1; // Chat
|
|
eq->entries[17] = 1; // Progression Server Access
|
|
eq->entries[18] = 1; // Customer Support
|
|
eq->entries[19] = -1; // Popup reminders?
|
|
eq->entries[20] = -1; // Exit Popup?
|
|
eq->entries[21] = 0;
|
|
eq->entries[22] = 0;
|
|
eq->entries[23] = 0; // This is the highest we actually see in detail entries
|
|
eq->entries[24] = 0;
|
|
eq->entries[25] = 0;
|
|
eq->entries[26] = 0;
|
|
eq->entries[27] = 0;
|
|
eq->entries[28] = 0;
|
|
eq->entries[29] = 0;
|
|
eq->entries[30] = 0;
|
|
eq->entries[31] = 0;
|
|
eq->entries[32] = 0;
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_SendMembershipDetails) {
|
|
ENCODE_LENGTH_EXACT(Membership_Details_Struct);
|
|
SETUP_DIRECT_ENCODE(Membership_Details_Struct, structs::Membership_Details_Struct);
|
|
|
|
int32 settings[96][3] = {
|
|
{ 0, 0, 250 }, { 1, 0, 1000 }, { 0, 1, -1 }, { 1, 1, -1 },
|
|
{ 0, 2, 2 }, { 2, 0, -1 }, { 3, 0, -1 }, { 1, 2, 4 },
|
|
{ 0, 3, 1 }, { 2, 1, -1 }, { 3, 1, -1 }, { 1, 3, 1 },
|
|
{ 0, 4, -1 }, { 2, 2, -1 }, { 3, 2, -1 }, { 1, 4, -1 },
|
|
{ 0, 5, -1 }, { 2, 3, -1 }, { 3, 3, -1 }, { 1, 5, -1 },
|
|
{ 0, 6, 0 }, { 2, 4, -1 }, { 3, 4, -1 }, { 1, 6, 0 },
|
|
{ 0, 7, 1 }, { 2, 5, -1 }, { 3, 5, -1 }, { 1, 7, 1 },
|
|
{ 0, 8, 1 }, { 2, 6, 1 }, { 3, 6, 1 }, { 1, 8, 1 },
|
|
{ 0, 9, 5 }, { 2, 7, 1 }, { 3, 7, 1 }, { 1, 9, 5 },
|
|
{ 0, 10, 0 }, { 2, 8, 1 }, { 3, 8, 1 }, { 0, 11, -1 },
|
|
{ 1, 10, 1 }, { 2, 9, -1 }, { 3, 9, -1 }, { 0, 12, -1 },
|
|
{ 1, 11, -1 }, { 2, 10, 1 }, { 3, 10, 1 }, { 0, 13, 0 },
|
|
{ 1, 12, -1 }, { 2, 11, -1 }, { 3, 11, -1 }, { 0, 14, 0 },
|
|
{ 1, 13, 1 }, { 2, 12, -1 }, { 3, 12, -1 }, { 0, 15, 0 },
|
|
{ 1, 14, 0 }, { 2, 13, 1 }, { 3, 13, 1 }, { 0, 16, 0 },
|
|
{ 1, 15, 0 }, { 2, 14, 1 }, { 3, 14, 1 }, { 0, 17, 0 },
|
|
{ 1, 16, 1 }, { 2, 15, 1 }, { 3, 15, 1 }, { 0, 18, 0 },
|
|
{ 1, 17, 0 }, { 2, 16, 1 }, { 3, 16, 1 }, { 0, 19, 0 },
|
|
{ 1, 18, 0 }, { 2, 17, 1 }, { 3, 17, 1 }, { 0, 20, 0 },
|
|
{ 1, 19, 0 }, { 2, 18, 1 }, { 3, 18, 1 }, { 0, 21, 0 },
|
|
{ 1, 20, 0 }, { 2, 19, -1 }, { 3, 19, -1 }, { 0, 22, 0 },
|
|
{ 1, 21, 0 }, { 2, 20, -1 }, { 3, 20, -1 }, { 2, 21, 0 },
|
|
{ 0, 23, 0 }, { 1, 22, 0 }, { 3, 21, 0 }, { 2, 22, 0 },
|
|
{ 1, 23, 0 }, { 3, 22, 0 }, { 2, 23, 0 }, { 3, 23, 0 }
|
|
};
|
|
|
|
uint32 races[17][2] = {
|
|
{ 1, 131071 },
|
|
{ 333, 131071 },
|
|
{ 90287, 131071 },
|
|
{ 90289, 16 },
|
|
{ 90290, 32 },
|
|
{ 90291, 64 },
|
|
{ 90292, 128 },
|
|
{ 90293, 256 },
|
|
{ 90294, 512 },
|
|
{ 90295, 1024 },
|
|
{ 90296, 2048 },
|
|
{ 90297, 8192 },
|
|
{ 90298, 16384 },
|
|
{ 90299, 32768 },
|
|
{ 90300, 65536 },
|
|
{ 2012271, 131071 },
|
|
{ 2012277, 131071 }
|
|
};
|
|
|
|
uint32 classes[17][2] = {
|
|
{ 1, 131071 },
|
|
{ 333, 131071 },
|
|
{ 90287, 131071 },
|
|
{ 90301, 8 },
|
|
{ 90302, 16 },
|
|
{ 90303, 32 },
|
|
{ 90304, 64 },
|
|
{ 90305, 128 },
|
|
{ 90306, 256 },
|
|
{ 90307, 1024 },
|
|
{ 90308, 2048 },
|
|
{ 90309, 8192 },
|
|
{ 90310, 16384 },
|
|
{ 90311, 32768 },
|
|
{ 90312, 65536 },
|
|
{ 2012271, 131071 },
|
|
{ 2012277, 131071 }
|
|
};
|
|
|
|
eq->membership_setting_count = 96;
|
|
|
|
for (int i = 0; i < 96; ++i) {
|
|
eq->settings[i].setting_index = (int8)settings[i][0];
|
|
eq->settings[i].setting_id = settings[i][1];
|
|
eq->settings[i].setting_value = settings[i][2];
|
|
}
|
|
|
|
eq->class_entry_count = 17;
|
|
for (int i = 0; i < 17; ++i) {
|
|
eq->membership_classes[i].purchase_id = classes[i][0];
|
|
eq->membership_classes[i].bitwise_entry = classes[i][1];
|
|
}
|
|
|
|
eq->race_entry_count = 17;
|
|
for (int i = 0; i < 17; ++i) {
|
|
eq->membership_races[i].purchase_id = races[i][0];
|
|
eq->membership_races[i].bitwise_entry = races[i][1];
|
|
}
|
|
|
|
eq->exit_url_length = 0;
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_SendMaxCharacters) {
|
|
ENCODE_LENGTH_EXACT(MaxCharacters_Struct);
|
|
SETUP_DIRECT_ENCODE(MaxCharacters_Struct, structs::MaxCharacters_Struct);
|
|
|
|
//OUT(max_chars);
|
|
eq->max_chars = 8; //needs to be fixed
|
|
eq->marketplace_chars = 0;
|
|
eq->unknown008 = -1;
|
|
eq->unknown00c = 196608;
|
|
eq->unknown010 = 0;
|
|
eq->unknown014 = 0;
|
|
eq->unknown018 = 0;
|
|
eq->unknown01c = 0;
|
|
eq->unknown020 = -1;
|
|
eq->unknown024 = 0;
|
|
eq->unknown028 = 0;
|
|
eq->unknown02c = 0;
|
|
eq->unknown030 = 0;
|
|
eq->unknown034 = 0;
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_SendCharInfo) {
|
|
ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct);
|
|
SETUP_VAR_ENCODE(CharacterSelect_Struct);
|
|
|
|
// Zero-character count shunt
|
|
if (emu->CharCount == 0) {
|
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct));
|
|
eq->CharCount = emu->CharCount;
|
|
|
|
FINISH_ENCODE();
|
|
return;
|
|
}
|
|
|
|
unsigned char* emu_ptr = __emu_buffer;
|
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
|
CharacterSelectEntry_Struct* emu_cse = (CharacterSelectEntry_Struct*)nullptr;
|
|
|
|
size_t names_length = 0;
|
|
size_t character_count = 0;
|
|
for (; character_count < emu->CharCount; ++character_count) {
|
|
emu_cse = (CharacterSelectEntry_Struct*)emu_ptr;
|
|
names_length += strlen(emu_cse->Name);
|
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
|
}
|
|
|
|
size_t total_length = sizeof(structs::CharacterSelect_Struct)
|
|
+ character_count * sizeof(structs::CharacterSelectEntry_Struct)
|
|
+ names_length;
|
|
|
|
ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, total_length);
|
|
structs::CharacterSelectEntry_Struct* eq_cse = (structs::CharacterSelectEntry_Struct*)nullptr;
|
|
|
|
eq->CharCount = character_count;
|
|
|
|
emu_ptr = __emu_buffer;
|
|
emu_ptr += sizeof(CharacterSelect_Struct);
|
|
|
|
unsigned char* eq_ptr = __packet->pBuffer;
|
|
eq_ptr += sizeof(structs::CharacterSelect_Struct);
|
|
|
|
for (int counter = 0; counter < character_count; ++counter) {
|
|
emu_cse = (CharacterSelectEntry_Struct*)emu_ptr;
|
|
eq_cse = (structs::CharacterSelectEntry_Struct*)eq_ptr; // base address
|
|
|
|
strcpy(eq_cse->Name, emu_cse->Name);
|
|
eq_ptr += strlen(emu_cse->Name);
|
|
|
|
eq_cse = (structs::CharacterSelectEntry_Struct*)eq_ptr;
|
|
eq_cse->Name[0] = '\0';
|
|
|
|
eq_cse->Class = emu_cse->Class;
|
|
eq_cse->Race = emu_cse->Race;
|
|
eq_cse->Level = emu_cse->Level;
|
|
eq_cse->ShroudClass = emu_cse->ShroudClass;
|
|
eq_cse->ShroudRace = emu_cse->ShroudRace;
|
|
eq_cse->Zone = emu_cse->Zone;
|
|
eq_cse->Instance = emu_cse->Instance;
|
|
eq_cse->Gender = emu_cse->Gender;
|
|
eq_cse->Face = emu_cse->Face;
|
|
|
|
for (int equip_index = 0; equip_index < EQ::textures::materialCount; equip_index++) {
|
|
eq_cse->Equip[equip_index].Material = emu_cse->Equip[equip_index].Material;
|
|
eq_cse->Equip[equip_index].Unknown1 = emu_cse->Equip[equip_index].Unknown1;
|
|
eq_cse->Equip[equip_index].EliteMaterial = emu_cse->Equip[equip_index].EliteModel;
|
|
eq_cse->Equip[equip_index].HeroForgeModel = emu_cse->Equip[equip_index].HerosForgeModel;
|
|
eq_cse->Equip[equip_index].Material2 = emu_cse->Equip[equip_index].Unknown2;
|
|
eq_cse->Equip[equip_index].Color = emu_cse->Equip[equip_index].Color;
|
|
}
|
|
|
|
eq_cse->Unknown1 = 255;
|
|
eq_cse->Unknown2 = 0;
|
|
eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo;
|
|
eq_cse->DrakkinDetails = emu_cse->DrakkinDetails;
|
|
eq_cse->Deity = emu_cse->Deity;
|
|
eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile;
|
|
eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile;
|
|
eq_cse->HairColor = emu_cse->HairColor;
|
|
eq_cse->BeardColor = emu_cse->BeardColor;
|
|
eq_cse->EyeColor1 = emu_cse->EyeColor1;
|
|
eq_cse->EyeColor2 = emu_cse->EyeColor2;
|
|
eq_cse->HairStyle = emu_cse->HairStyle;
|
|
eq_cse->Beard = emu_cse->Beard;
|
|
eq_cse->GoHome = emu_cse->GoHome;
|
|
eq_cse->Tutorial = emu_cse->Tutorial;
|
|
eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage;
|
|
eq_cse->Enabled = emu_cse->Enabled;
|
|
eq_cse->LastLogin = emu_cse->LastLogin;
|
|
eq_cse->Unknown3 = 0;
|
|
eq_cse->Unknown4 = 0;
|
|
eq_cse->Unknown5 = 0;
|
|
eq_cse->Unknown6 = 0;
|
|
eq_cse->Unknown7 = 0;
|
|
eq_cse->CharacterId = 0;
|
|
eq_cse->Unknown8 = 1;
|
|
|
|
emu_ptr += sizeof(CharacterSelectEntry_Struct);
|
|
eq_ptr += sizeof(structs::CharacterSelectEntry_Struct);
|
|
}
|
|
|
|
DumpPacket(__packet);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_ExpansionInfo)
|
|
{
|
|
ENCODE_LENGTH_EXACT(ExpansionInfo_Struct);
|
|
SETUP_DIRECT_ENCODE(ExpansionInfo_Struct, structs::ExpansionInfo_Struct);
|
|
|
|
OUT(Expansions);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_SpawnAppearance)
|
|
{
|
|
EQApplicationPacket* in = *p;
|
|
*p = nullptr;
|
|
|
|
unsigned char* emu_buffer = in->pBuffer;
|
|
|
|
SpawnAppearance_Struct* sas = (SpawnAppearance_Struct*)emu_buffer;
|
|
|
|
if (sas->type != AppearanceType::Size)
|
|
{
|
|
//laurion struct is different than rof2's but the idea is the same
|
|
auto outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(structs::SpawnAppearance_Struct));
|
|
structs::SpawnAppearance_Struct *eq = (structs::SpawnAppearance_Struct*)outapp->pBuffer;
|
|
|
|
eq->spawn_id = sas->spawn_id;
|
|
eq->type = sas->type;
|
|
eq->parameter = sas->parameter;
|
|
|
|
dest->FastQueuePacket(&outapp, ack_req);
|
|
delete in;
|
|
return;
|
|
}
|
|
|
|
auto outapp = new EQApplicationPacket(OP_ChangeSize, sizeof(ChangeSize_Struct));
|
|
|
|
ChangeSize_Struct* css = (ChangeSize_Struct*)outapp->pBuffer;
|
|
|
|
css->EntityID = sas->spawn_id;
|
|
css->Size = (float)sas->parameter;
|
|
css->Unknown08 = 0;
|
|
css->Unknown12 = 1.0f;
|
|
|
|
dest->FastQueuePacket(&outapp, ack_req);
|
|
delete in;
|
|
}
|
|
|
|
ENCODE(OP_PlayerProfile) {
|
|
EQApplicationPacket* in = *p;
|
|
*p = nullptr;
|
|
|
|
unsigned char* __emu_buffer = in->pBuffer;
|
|
PlayerProfile_Struct* emu = (PlayerProfile_Struct*)__emu_buffer;
|
|
|
|
SerializeBuffer out;
|
|
|
|
/*
|
|
u32 crc;
|
|
u32 length;
|
|
*/
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
|
|
//PcProfile begin
|
|
/*
|
|
u32 profile_type;
|
|
u32 profile_id;
|
|
u32 shroud_template_id;
|
|
*/
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
|
|
/*
|
|
u8 gender;
|
|
u32 race;
|
|
u32 class;
|
|
u8 level;
|
|
u8 level1;
|
|
*/
|
|
out.WriteUInt8(emu->gender);
|
|
out.WriteUInt32(emu->race);
|
|
out.WriteUInt32(emu->class_);
|
|
out.WriteUInt8(emu->level);
|
|
out.WriteUInt8(emu->level);
|
|
|
|
//u32 bind_count;
|
|
out.WriteUInt32(5);
|
|
|
|
for (int r = 0; r < 5; r++)
|
|
{
|
|
/*
|
|
u32 zoneid;
|
|
float x;
|
|
float y;
|
|
float z;
|
|
float heading;
|
|
*/
|
|
out.WriteUInt32(emu->binds[r].zone_id);
|
|
out.WriteFloat(emu->binds[r].x);
|
|
out.WriteFloat(emu->binds[r].y);
|
|
out.WriteFloat(emu->binds[r].z);
|
|
out.WriteFloat(emu->binds[r].heading);
|
|
}
|
|
|
|
/*
|
|
u32 deity;
|
|
u32 intoxication;
|
|
*/
|
|
out.WriteUInt32(emu->deity);
|
|
out.WriteUInt32(emu->intoxication);
|
|
|
|
//u32 property_count;
|
|
out.WriteUInt32(10); // properties count
|
|
|
|
//u32 properties[property_count];
|
|
for (int i = 0; i < 10; i++) {
|
|
out.WriteUInt32(0);
|
|
}
|
|
|
|
//u32 armor_prop_count;
|
|
out.WriteUInt32(22); //armor count
|
|
for (int i = 0; i < 22; ++i) {
|
|
/*
|
|
s32 type;
|
|
s32 variation;
|
|
s32 material;
|
|
s32 newArmorId;
|
|
s32 newArmorType;
|
|
*/
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
}
|
|
|
|
//u32 base_armor_prop_count;
|
|
out.WriteUInt32(9); //base armor count
|
|
for (int i = 0; i < 9; ++i) {
|
|
/*
|
|
s32 type;
|
|
s32 variation;
|
|
s32 material;
|
|
s32 newArmorId;
|
|
s32 newArmorType;
|
|
*/
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
}
|
|
|
|
//u32 body_tint_count;
|
|
out.WriteUInt32(9); //body_tint_count
|
|
//u32 body_tints[body_tint_count];
|
|
for (int i = 0; i < 9; ++i) {
|
|
out.WriteUInt32(0);
|
|
}
|
|
|
|
//u32 equip_tint_count;
|
|
out.WriteUInt32(9); //equip_tint_count
|
|
//u32 equip_tints[equip_tint_count];
|
|
for (int i = 0; i < 9; ++i) {
|
|
out.WriteUInt32(0);
|
|
}
|
|
|
|
/*
|
|
u8 hair_color;
|
|
u8 facial_hair_color;
|
|
u32 npc_tint_index;
|
|
u8 eye_color1;
|
|
u8 eye_color2;
|
|
u8 hair_style;
|
|
u8 facial_hair;
|
|
u8 face;
|
|
u8 old_face;
|
|
u32 heritage;
|
|
u32 tattoo;
|
|
u32 details;
|
|
*/
|
|
out.WriteUInt8(emu->haircolor);
|
|
out.WriteUInt8(emu->beardcolor);
|
|
out.WriteUInt32(0); //npc tint index
|
|
out.WriteUInt8(emu->eyecolor1);
|
|
out.WriteUInt8(emu->eyecolor2);
|
|
out.WriteUInt8(emu->hairstyle);
|
|
out.WriteUInt8(emu->beard);
|
|
out.WriteUInt8(emu->face);
|
|
out.WriteUInt8(0); //old face
|
|
out.WriteUInt32(emu->drakkin_heritage);
|
|
out.WriteUInt32(emu->drakkin_tattoo);
|
|
out.WriteUInt32(emu->drakkin_details);
|
|
|
|
/*
|
|
u8 texture_type;
|
|
u8 material;
|
|
u8 variation;
|
|
*/
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt8(0);
|
|
|
|
/*
|
|
float height;
|
|
float width;
|
|
float length;
|
|
float view_height;
|
|
*/
|
|
out.WriteFloat(5.0f);
|
|
out.WriteFloat(3.0f);
|
|
out.WriteFloat(2.5f);
|
|
out.WriteFloat(5.5f);
|
|
|
|
/*
|
|
u32 primary;
|
|
u32 secondary;
|
|
*/
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
|
|
/*
|
|
u32 practices;
|
|
u32 base_mana;
|
|
u32 base_hp;
|
|
u32 base_str;
|
|
u32 base_sta;
|
|
u32 base_cha;
|
|
u32 base_dex;
|
|
u32 base_int;
|
|
u32 base_agi;
|
|
u32 base_wis;
|
|
u32 base_heroic_str;
|
|
u32 base_heroic_sta;
|
|
u32 base_heroic_cha;
|
|
u32 base_heroic_dex;
|
|
u32 base_heroic_int;
|
|
u32 base_heroic_agi;
|
|
u32 base_heroic_wis;
|
|
*/
|
|
out.WriteUInt32(emu->points);
|
|
out.WriteUInt32(emu->mana);
|
|
out.WriteUInt32(emu->cur_hp);
|
|
out.WriteUInt32(emu->STR);
|
|
out.WriteUInt32(emu->STA);
|
|
out.WriteUInt32(emu->CHA);
|
|
out.WriteUInt32(emu->DEX);
|
|
out.WriteUInt32(emu->INT);
|
|
out.WriteUInt32(emu->AGI);
|
|
out.WriteUInt32(emu->WIS);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
|
|
//u32 aa_count;
|
|
out.WriteUInt32(300);
|
|
for (int i = 0; i < 240; ++i) {
|
|
/*
|
|
s32 index;
|
|
s32 points_spent;
|
|
s32 charges_spent;
|
|
u8 unknown1;
|
|
*/
|
|
out.WriteUInt32(emu->aa_array[i].AA);
|
|
out.WriteUInt32(emu->aa_array[i].value);
|
|
out.WriteUInt32(emu->aa_array[i].charges);
|
|
out.WriteUInt8(0);
|
|
}
|
|
|
|
for (int i = 0; i < 60; ++i) {
|
|
/*
|
|
s32 index;
|
|
s32 points_spent;
|
|
s32 charges_spent;
|
|
u8 unknown1; //not sure about this one
|
|
*/
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt8(0);
|
|
}
|
|
|
|
/*u32 skill_count;*/
|
|
out.WriteUInt32(100);
|
|
//s32 skills[skill_count];
|
|
for (int i = 0; i < 100; ++i) {
|
|
out.WriteUInt32(emu->skills[i]);
|
|
}
|
|
|
|
//u32 innate_skill_count;
|
|
out.WriteUInt32(25);
|
|
//s32 innate_skills[innate_skill_count];
|
|
for (int i = 0; i < 25; ++i) {
|
|
out.WriteUInt32(emu->InnateSkills[i]);
|
|
}
|
|
|
|
/*
|
|
u32 combat_ability_count;
|
|
*/
|
|
out.WriteUInt32(300);
|
|
//s32 combat_abilities[combat_ability_count];
|
|
for (int i = 0; i < 100; ++i) {
|
|
out.WriteUInt32(emu->disciplines.values[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 200; ++i) {
|
|
out.WriteUInt32(0);
|
|
}
|
|
|
|
//u32 combat_ability_timer_count;
|
|
out.WriteUInt32(25);
|
|
//s32 combat_ability_timers[combat_ability_timer_count];
|
|
for (int i = 0; i < 20; ++i) {
|
|
out.WriteUInt32(emu->disciplines.values[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
out.WriteUInt32(0);
|
|
}
|
|
|
|
//u32 unk_ability_count;
|
|
out.WriteUInt32(0);
|
|
|
|
//u32 linked_spell_timer_count;
|
|
out.WriteUInt32(25);
|
|
//s32 linked_spell_timers[linked_spell_timer_count];
|
|
for (int i = 0; i < 25; ++i) {
|
|
out.WriteUInt32(0);
|
|
}
|
|
|
|
//u32 item_recast_timer_count;
|
|
out.WriteUInt32(100);
|
|
//s32 item_recast_timers[item_recast_timer_count];
|
|
for (int i = 0; i < 100; ++i) {
|
|
out.WriteUInt32(0);
|
|
}
|
|
|
|
//u32 spell_book_slot_count;
|
|
out.WriteUInt32(1120);
|
|
|
|
//s32 spell_book_slots[spell_book_slot_count];
|
|
for (int i = 0; i < 720; ++i) {
|
|
out.WriteUInt32(emu->spell_book[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 400; ++i) {
|
|
out.WriteUInt32(0xFFFFFFFF);
|
|
}
|
|
|
|
//u32 spell_gem_count;
|
|
out.WriteUInt32(18);
|
|
//s32 spell_gems[spell_gem_count];
|
|
for (int i = 0; i < 12; ++i) {
|
|
out.WriteUInt32(emu->mem_spells[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 6; ++i) {
|
|
out.WriteUInt32(0xFFFFFFFF);
|
|
}
|
|
|
|
/*
|
|
u32 spell_recast_timer_count;
|
|
*/
|
|
out.WriteUInt32(15);
|
|
|
|
//s32 spell_recast_timers[spell_recast_timer_count];
|
|
for (int i = 0; i < 12; ++i) {
|
|
out.WriteUInt32(emu->spellSlotRefresh[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
out.WriteUInt32(0);
|
|
}
|
|
|
|
//u8 max_allowed_spell_slots;
|
|
out.WriteUInt8(0);
|
|
|
|
//u32 buff_count;
|
|
out.WriteUInt32(42);
|
|
|
|
//PackedEQAffect buffs[buff_count];
|
|
for (int i = 0; i < 42; ++i) {
|
|
/*
|
|
float modifier;
|
|
u32 caster;
|
|
u32 flags;
|
|
u32 duration;
|
|
u32 max_duration;
|
|
u8 level;
|
|
s32 spell_id;
|
|
s32 hitcount;
|
|
u8 unknown1;
|
|
u32 unknown2;
|
|
u32 unknown3;
|
|
*/
|
|
out.WriteFloat(1.0f);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt32(0xFFFFFFFF);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
//SlotData slots[6];
|
|
for (int j = 0; j < 6; ++j) {
|
|
/*
|
|
s32 slot_id;
|
|
s64 value;
|
|
*/
|
|
out.WriteInt32(-1);
|
|
out.WriteUInt64(0);
|
|
}
|
|
}
|
|
|
|
//Coin coin;
|
|
/*
|
|
u32 platinum;
|
|
u32 gold;
|
|
u32 silver;
|
|
u32 copper;
|
|
*/
|
|
out.WriteUInt32(emu->platinum);
|
|
out.WriteUInt32(emu->gold);
|
|
out.WriteUInt32(emu->silver);
|
|
out.WriteUInt32(emu->copper);
|
|
|
|
//Coin cursor_coin;
|
|
/*
|
|
u32 platinum;
|
|
u32 gold;
|
|
u32 silver;
|
|
u32 copper;
|
|
*/
|
|
out.WriteUInt32(emu->platinum_cursor);
|
|
out.WriteUInt32(emu->gold_cursor);
|
|
out.WriteUInt32(emu->silver_cursor);
|
|
out.WriteUInt32(emu->copper_cursor);
|
|
|
|
/*
|
|
u32 disc_timer;
|
|
u32 mend_timer;
|
|
u32 forage_timer;
|
|
u32 thirst;
|
|
u32 hunger;
|
|
*/
|
|
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(emu->thirst_level);
|
|
out.WriteUInt32(emu->hunger_level);
|
|
|
|
//u32 aa_spent;
|
|
out.WriteUInt32(emu->aapoints_spent);
|
|
|
|
//u32 aa_window_count;
|
|
out.WriteUInt32(6);
|
|
//u32 aa_window_stats[aa_window_count];
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
|
|
//u32 aa_points_unspent;
|
|
out.WriteUInt32(emu->aapoints);
|
|
|
|
/*
|
|
u8 sneak;
|
|
u8 hide;
|
|
*/
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt8(0);
|
|
|
|
//u32 bandolier_count;
|
|
out.WriteUInt32(20);
|
|
|
|
//BandolierSet bandolier_sets[bandolier_count];
|
|
for (int i = 0; i < 20; ++i) {
|
|
//char name[];
|
|
out.WriteString(emu->bandoliers[i].Name);
|
|
|
|
//BandolierItemInfo items[4];
|
|
for (int j = 0; j < 4; ++j) {
|
|
//char name[];
|
|
out.WriteString(emu->bandoliers[i].Items[j].Name);
|
|
//s32 item_id;
|
|
out.WriteUInt32(emu->bandoliers[i].Items[j].ID);
|
|
//s32 icon;
|
|
out.WriteUInt32(emu->bandoliers[i].Items[j].Icon);
|
|
}
|
|
}
|
|
|
|
//u32 invslot_bitmask;
|
|
out.WriteUInt32(0xFFFFFFFF);
|
|
|
|
/*
|
|
u32 basedata_hp;
|
|
u32 basedata_mana;
|
|
u32 basedata_endur;
|
|
u32 basedata_mr;
|
|
u32 basedata_fr;
|
|
u32 basedata_cr;
|
|
u32 basedata_pr;
|
|
u32 basedata_dr;
|
|
u32 basedata_corrupt;
|
|
u32 basedata_phr;
|
|
*/
|
|
|
|
out.WriteUInt32(5);
|
|
out.WriteUInt32(5);
|
|
out.WriteUInt32(5);
|
|
out.WriteUInt32(25);
|
|
out.WriteUInt32(25);
|
|
out.WriteUInt32(25);
|
|
out.WriteUInt32(15);
|
|
out.WriteUInt32(15);
|
|
out.WriteUInt32(15);
|
|
out.WriteUInt32(15);
|
|
|
|
/*
|
|
float basedata_walkspeed;
|
|
float basedata_runspeed;
|
|
*/
|
|
|
|
out.WriteFloat(0.46f);
|
|
out.WriteFloat(0.7f);
|
|
|
|
/*
|
|
u32 basedata_hpregen;
|
|
u32 basedata_manaregen;
|
|
u32 basedata_mountmanaregen;
|
|
u32 basedata_endurregen;
|
|
u32 basedata_ac;
|
|
u32 basedata_atk;
|
|
u32 basedata_dmg;
|
|
u32 basedata_delay;
|
|
u32 endurance;
|
|
u32 heroic_type;
|
|
*/
|
|
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(emu->endurance);
|
|
out.WriteUInt32(0);
|
|
|
|
//ItemIndex keyring_item_index[5];
|
|
for (int i = 0; i < 5; ++i) {
|
|
/*
|
|
s16 slot1;
|
|
s16 slot2;
|
|
s16 slot3;
|
|
*/
|
|
|
|
out.WriteInt16(-1);
|
|
out.WriteInt16(-1);
|
|
out.WriteInt16(-1);
|
|
}
|
|
|
|
/*
|
|
u64 exp;
|
|
u32 aa_exp;
|
|
*/
|
|
out.WriteUInt64(emu->exp);
|
|
out.WriteUInt32(emu->expAA);
|
|
|
|
//PcClient begin
|
|
/*
|
|
u32 character_id;
|
|
u16 world_id;
|
|
u16 reserved;
|
|
*/
|
|
out.WriteUInt32(emu->char_id);
|
|
out.WriteUInt16(RuleI(World, Id));
|
|
out.WriteUInt16(0);
|
|
|
|
/*u32 name_length;*/
|
|
/*char name[name_length];*/
|
|
out.WriteLengthString(64, emu->name);
|
|
|
|
//u32 last_name_length;
|
|
//char last_name[last_name_length];
|
|
out.WriteLengthString(32, emu->last_name);
|
|
|
|
/*
|
|
u32 creation_time;
|
|
u32 account_creation_time;
|
|
u32 last_played_time;
|
|
u32 played_minutes;
|
|
u32 entitled_days;
|
|
u32 expansion_flags;
|
|
*/
|
|
|
|
out.WriteUInt32(emu->birthday);
|
|
out.WriteUInt32(emu->birthday);
|
|
out.WriteUInt32(emu->lastlogin);
|
|
out.WriteUInt32(5000);
|
|
out.WriteUInt32(6000);
|
|
out.WriteUInt32(0x3FFFFFFF);
|
|
|
|
//u32 language_count;
|
|
out.WriteUInt32(32);
|
|
for (int i = 0; i < 28; i++)
|
|
{
|
|
//u8 languages[language_count];
|
|
out.WriteUInt8(emu->languages[i]);
|
|
}
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
out.WriteUInt8(0);
|
|
}
|
|
|
|
/*
|
|
u32 current_zone;
|
|
float current_x;
|
|
float current_y;
|
|
float current_z;
|
|
float current_heading;
|
|
*/
|
|
out.WriteUInt16(emu->zone_id);
|
|
out.WriteUInt16(emu->zoneInstance);
|
|
out.WriteFloat(emu->x);
|
|
out.WriteFloat(emu->y);
|
|
out.WriteFloat(emu->z);
|
|
out.WriteFloat(emu->heading);
|
|
|
|
/*
|
|
u8 animation;
|
|
u8 pvp;
|
|
u8 anon;
|
|
u8 gm;
|
|
*/
|
|
out.WriteUInt8(100);
|
|
out.WriteUInt8(emu->pvp);
|
|
out.WriteUInt8(emu->anon);
|
|
out.WriteUInt8(emu->gm);
|
|
|
|
/*
|
|
u64 guild_id;
|
|
u8 guild_show_sprite;
|
|
u8 status;
|
|
*/
|
|
|
|
out.WriteUInt64(0);
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt8(5);
|
|
|
|
//Coin coin;
|
|
out.WriteUInt32(emu->platinum);
|
|
out.WriteUInt32(emu->gold);
|
|
out.WriteUInt32(emu->silver);
|
|
out.WriteUInt32(emu->copper);
|
|
|
|
//Coin bank;
|
|
out.WriteUInt32(emu->platinum_bank);
|
|
out.WriteUInt32(emu->gold_bank);
|
|
out.WriteUInt32(emu->silver_bank);
|
|
out.WriteUInt32(emu->copper_bank);
|
|
|
|
//u32 bank_shared_plat;
|
|
out.WriteUInt32(emu->platinum_shared);
|
|
|
|
//u32 claim_count;
|
|
out.WriteUInt32(0);
|
|
//Claim claims[claim_count];
|
|
|
|
//Tribute tribute;
|
|
/*
|
|
u32 BenefitTimer;
|
|
s32 unknown1;
|
|
s32 current_favor;
|
|
s32 unknown2;
|
|
s32 all_time_favor;
|
|
s32 unknown3; //some of these are probably the bools on the pcclient;
|
|
u16 unknown4;
|
|
*/
|
|
out.WriteUInt32(600000);
|
|
out.WriteInt32(-1);
|
|
out.WriteUInt32(emu->tribute_points);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(emu->career_tribute_points);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt16(0);
|
|
|
|
//u32 tribute_benefit_count
|
|
out.WriteUInt32(5);
|
|
|
|
//TributeBenefit tribute_benefits[tribute_benefit_count];
|
|
for (int i = 0; i < 5; ++i) {
|
|
/*
|
|
s32 benefit_id;
|
|
s32 benefit_tier;
|
|
*/
|
|
|
|
out.WriteUInt32(emu->tributes[i].tribute);
|
|
out.WriteUInt32(emu->tributes[i].tier);
|
|
}
|
|
|
|
//u32 trophy_tribute_benefit_count;
|
|
out.WriteUInt32(10);
|
|
|
|
//TributeBenefit trophy_tribute_benefit[trophy_tribute_benefit_count];
|
|
for (int i = 0; i < 10; ++i) {
|
|
/*
|
|
s32 benefit_id;
|
|
s32 benefit_tier;
|
|
*/
|
|
|
|
out.WriteUInt32(0xFFFFFFFF);
|
|
out.WriteUInt32(0);
|
|
}
|
|
const uint8_t task_data[137] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
//u8 tasks[137]; //on live and on xac's capture from 12/28/23 these both are the same size;
|
|
for (int i = 0; i < 137; i++)
|
|
{
|
|
out.WriteUInt8(task_data[i]);
|
|
}
|
|
|
|
/*
|
|
u32 good_points_available;
|
|
u32 good_points_earned;
|
|
u32 bad_points_available;
|
|
u32 bad_points_earned;
|
|
*/
|
|
|
|
out.WriteUInt32(emu->currentRadCrystals);
|
|
out.WriteUInt32(emu->careerRadCrystals);
|
|
out.WriteUInt32(emu->currentEbonCrystals);
|
|
out.WriteUInt32(emu->careerEbonCrystals);
|
|
|
|
/*
|
|
u32 momentum_balance;
|
|
u32 loyalty_reward_balance;
|
|
u32 parcel_status;
|
|
*/
|
|
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
|
|
/*
|
|
u32 vehicle_name_length;
|
|
char vehicle_name[vehicle_name_length];
|
|
*/
|
|
|
|
out.WriteUInt32(64);
|
|
for (int i = 0; i < 64; ++i) {
|
|
out.WriteUInt8(0);
|
|
}
|
|
|
|
/*
|
|
u8 super_pkill;
|
|
u8 unclone;
|
|
u8 dead;
|
|
*/
|
|
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt8(0);
|
|
|
|
/*
|
|
u32 ld_timer;
|
|
u32 spell_interrupt_count;
|
|
u8 autosplit;
|
|
u8 tells_off;
|
|
*/
|
|
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt8(emu->autosplit);
|
|
out.WriteUInt8(0);
|
|
|
|
/*
|
|
u8 gm_invis;
|
|
u32 kill_me;
|
|
u8 cheater_ld_flag;
|
|
u8 norent;
|
|
u8 corpse;
|
|
u8 client_gm_flag_set;
|
|
u32 mentor_pct;
|
|
*/
|
|
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt32(0);
|
|
|
|
//RaidData raid;
|
|
/*
|
|
u32 main_assist1;
|
|
u32 main_assist2;
|
|
u32 main_assist3;
|
|
char main_assist_name1[];
|
|
char main_assist_name2[];
|
|
char main_assist_name3[];
|
|
u32 main_marker1;
|
|
u32 main_marker2;
|
|
u32 main_marker3;
|
|
u32 master_looter;
|
|
*/
|
|
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt8(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
|
|
//u32 unique_player_id;
|
|
out.WriteUInt32(emu->char_id);
|
|
|
|
//LdonData ldon_data;
|
|
/*
|
|
u32 count;
|
|
u32 ldon_categories[count];
|
|
u32 ldon_points_available;
|
|
*/
|
|
|
|
out.WriteUInt32(6);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(emu->ldon_points_guk);
|
|
out.WriteUInt32(emu->ldon_points_mir);
|
|
out.WriteUInt32(emu->ldon_points_mmc);
|
|
out.WriteUInt32(emu->ldon_points_ruj);
|
|
out.WriteUInt32(emu->ldon_points_tak);
|
|
out.WriteUInt32(emu->ldon_points_available);
|
|
|
|
//u32 air_supply;
|
|
out.WriteUInt32(emu->air_remaining);
|
|
|
|
//PvPData pvp_data;
|
|
/*
|
|
u32 kills;
|
|
u32 deaths;
|
|
u32 current_points;
|
|
u32 career_points;
|
|
u32 best_kill_streak;
|
|
u32 worst_death_streak;
|
|
u32 current_kill_streak;
|
|
*/
|
|
|
|
out.WriteUInt32(emu->PVPKills);
|
|
out.WriteUInt32(emu->PVPDeaths);
|
|
out.WriteUInt32(emu->PVPCurrentPoints);
|
|
out.WriteUInt32(emu->PVPCareerPoints);
|
|
out.WriteUInt32(emu->PVPBestKillStreak);
|
|
out.WriteUInt32(emu->PVPWorstDeathStreak);
|
|
out.WriteUInt32(emu->PVPCurrentKillStreak);
|
|
|
|
//PvPKill last_kill;
|
|
/*
|
|
char name[];
|
|
u32 level;
|
|
u32 unknown1; //not sure
|
|
u32 unknown2; //not sure
|
|
u32 race;
|
|
u32 class;
|
|
u32 zone;
|
|
u32 time;
|
|
u32 points;
|
|
*/
|
|
out.WriteString(emu->PVPLastKill.Name);
|
|
out.WriteUInt32(emu->PVPLastKill.Level);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(emu->PVPLastKill.Race);
|
|
out.WriteUInt32(emu->PVPLastKill.Class);
|
|
out.WriteUInt32(emu->PVPLastKill.Zone);
|
|
out.WriteUInt32(emu->PVPLastKill.Time);
|
|
out.WriteUInt32(emu->PVPLastKill.Points);
|
|
|
|
//PvPDeath last_death;
|
|
/*
|
|
char name[];
|
|
u32 level;
|
|
u32 race;
|
|
u32 class;
|
|
u32 zone;
|
|
u32 time;
|
|
u32 points;
|
|
*/
|
|
|
|
out.WriteString(emu->PVPLastDeath.Name);
|
|
out.WriteUInt32(emu->PVPLastDeath.Level);
|
|
out.WriteUInt32(emu->PVPLastDeath.Race);
|
|
out.WriteUInt32(emu->PVPLastDeath.Class);
|
|
out.WriteUInt32(emu->PVPLastDeath.Zone);
|
|
out.WriteUInt32(emu->PVPLastDeath.Time);
|
|
out.WriteUInt32(emu->PVPLastDeath.Points);
|
|
|
|
/*
|
|
u32 kills_in_past_24_hours;
|
|
*/
|
|
|
|
out.WriteUInt32(emu->PVPNumberOfKillsInLast24Hours);
|
|
|
|
//u32 kill_list_count;
|
|
out.WriteUInt32(50);
|
|
|
|
//PvPKill kill_list[kill_list_count];
|
|
for (int i = 0; i < 50; ++i) {
|
|
/*
|
|
char name[];
|
|
u32 level;
|
|
u32 unknown1; //not sure
|
|
u32 unknown2; //not sure
|
|
u32 race;
|
|
u32 class;
|
|
u32 zone;
|
|
u32 time;
|
|
u32 points;
|
|
*/
|
|
out.WriteString(emu->PVPRecentKills[i].Name);
|
|
out.WriteUInt32(emu->PVPRecentKills[i].Level);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(emu->PVPRecentKills[i].Race);
|
|
out.WriteUInt32(emu->PVPRecentKills[i].Class);
|
|
out.WriteUInt32(emu->PVPRecentKills[i].Zone);
|
|
out.WriteUInt32(emu->PVPRecentKills[i].Time);
|
|
out.WriteUInt32(emu->PVPRecentKills[i].Points);
|
|
}
|
|
|
|
/*
|
|
u32 pvp_infamy_level;
|
|
u32 pvp_vitality;
|
|
*/
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
|
|
/*
|
|
u32 cursor_krono;
|
|
u32 krono;
|
|
*/
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
|
|
/*
|
|
u8 autoconsent_group;
|
|
u8 autoconsent_raid;
|
|
u8 autoconsent_guild;
|
|
u8 autoconsent_fellowship;
|
|
*/
|
|
|
|
out.WriteUInt8(emu->groupAutoconsent);
|
|
out.WriteUInt8(emu->raidAutoconsent);
|
|
out.WriteUInt8(emu->guildAutoconsent);
|
|
out.WriteUInt8(1);
|
|
|
|
/*
|
|
u8 private_for_eq_players;
|
|
u32 main_level;
|
|
u8 show_helm;
|
|
u32 downtime;
|
|
*/
|
|
out.WriteUInt8(1);
|
|
out.WriteUInt32(emu->level);
|
|
out.WriteUInt8(emu->showhelm);
|
|
out.WriteUInt32(emu->RestTimer);
|
|
|
|
//AltCurrency alt_currency;
|
|
/*
|
|
u32 alt_currency_str_length;
|
|
u32 unknown1;
|
|
char alt_currency_string[alt_currency_str_length];
|
|
*/
|
|
out.WriteUInt32(1);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt8(0x31);
|
|
|
|
//u32 completed_event_subcomponent_count;
|
|
out.WriteUInt32(0);
|
|
//AchivementSubComponentData completed_event_subcomponents[completed_event_subcomponent_count];
|
|
|
|
//u32 inprogress_event_subcomponent_count;
|
|
out.WriteUInt32(0);
|
|
//AchivementSubComponentData inprogress_event_subcomponents[inprogress_event_subcomponent_count];
|
|
|
|
/*
|
|
u64 merc_aa_exp;
|
|
u32 merc_aa_points;
|
|
u32 merc_aa_spent;
|
|
*/
|
|
out.WriteUInt64(0);
|
|
out.WriteUInt32(0);
|
|
out.WriteUInt32(0);
|
|
|
|
//u32 starting_city_zone_id;
|
|
//we don't actually support this yet
|
|
out.WriteUInt32(394);
|
|
|
|
/*
|
|
u8 use_advanced_looting;
|
|
u8 is_master_loot_candidate;
|
|
*/
|
|
|
|
out.WriteUInt8(1);
|
|
out.WriteUInt8(1);
|
|
|
|
//alchemy_bonus_list_count
|
|
out.WriteUInt32(0);
|
|
//AlchemyBonusSkillData alchemy_bonus_list[alchemy_bonus_list_count];
|
|
|
|
//u32 persona_count;
|
|
out.WriteUInt32(0);
|
|
//PersonaEquipmentSet persona_equipment_set[persona_count];
|
|
|
|
//u8 term;
|
|
out.WriteUInt8(0);
|
|
|
|
auto outapp = new EQApplicationPacket(OP_PlayerProfile, out.length());
|
|
outapp->WriteData(out.buffer(), out.length());
|
|
outapp->SetWritePosition(4);
|
|
outapp->WriteUInt32(outapp->size - 9);
|
|
CRC32::SetEQChecksum(outapp->pBuffer, outapp->size - 1, 8);
|
|
dest->FastQueuePacket(&outapp, ack_req);
|
|
delete in;
|
|
}
|
|
|
|
ENCODE(OP_ZoneEntry) { ENCODE_FORWARD(OP_ZoneSpawns); }
|
|
|
|
ENCODE(OP_ZoneSpawns)
|
|
{
|
|
EQApplicationPacket* in = *p;
|
|
*p = nullptr;
|
|
|
|
//store away the emu struct
|
|
unsigned char* __emu_buffer = in->pBuffer;
|
|
Spawn_Struct* emu = (Spawn_Struct*)__emu_buffer;
|
|
|
|
int entrycount = in->size / sizeof(Spawn_Struct);
|
|
if (entrycount == 0 || (in->size % sizeof(Spawn_Struct)) != 0) {
|
|
LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct));
|
|
delete in;
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < entrycount; i++, emu++) {
|
|
SerializeBuffer buffer;
|
|
|
|
auto SpawnSize = emu->size;
|
|
if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
|
|
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin))
|
|
)
|
|
{
|
|
if (emu->size == 0)
|
|
{
|
|
emu->size = 6;
|
|
SpawnSize = 6;
|
|
}
|
|
}
|
|
|
|
if (SpawnSize == 0)
|
|
{
|
|
SpawnSize = 3;
|
|
}
|
|
|
|
/*
|
|
char Name[];
|
|
u32 SpawnId;
|
|
u8 Level;
|
|
float MeleeRadius;
|
|
*/
|
|
buffer.WriteString(emu->name);
|
|
buffer.WriteUInt32(emu->spawnId);
|
|
buffer.WriteUInt8(emu->level);
|
|
if (emu->DestructibleObject) //bounding radius: we should consider supporting this officially in the future
|
|
{
|
|
buffer.WriteFloat(10.0f);
|
|
}
|
|
else
|
|
{
|
|
|
|
buffer.WriteFloat(SpawnSize - 0.7f);
|
|
}
|
|
|
|
/*
|
|
EqGuid HashKey;
|
|
*/
|
|
buffer.WriteUInt32(emu->CharacterGuid.Id);
|
|
buffer.WriteUInt16(emu->CharacterGuid.WorldId);
|
|
buffer.WriteUInt16(0);
|
|
|
|
/*
|
|
u8 Type;
|
|
ActorFlags Flags;
|
|
*/
|
|
buffer.WriteUInt8(emu->NPC);
|
|
|
|
structs::Spawn_Struct_Bitfields flags;
|
|
memset(&flags, 0, sizeof(structs::Spawn_Struct_Bitfields));
|
|
|
|
flags.gender = emu->gender;
|
|
flags.ispet = emu->is_pet;
|
|
flags.afk = emu->afk;
|
|
flags.anon = emu->anon;
|
|
flags.gm = emu->gm;
|
|
flags.sneak = 0;
|
|
flags.lfg = emu->lfg;
|
|
flags.invis = emu->invis; //we need to implement this
|
|
flags.linkdead = 0; //on live I often see this as 1 for npcs, maybe consider adding this in the future
|
|
flags.showhelm = emu->showhelm;
|
|
flags.trader = emu->trader ? 1 : 0;
|
|
flags.targetable = 1;
|
|
flags.targetable_with_hotkey = emu->targetable_with_hotkey ? 1 : 0;
|
|
flags.showname = emu->show_name;
|
|
flags.buyer = emu->buyer ? 1 : 0;
|
|
flags.title = strlen(emu->title) > 0 ? 1 : 0;
|
|
flags.suffix = strlen(emu->suffix) > 0 ? 1 : 0;
|
|
|
|
if (emu->DestructibleObject || emu->class_ == Class::LDoNTreasure) {
|
|
flags.interactiveobject = 1;
|
|
}
|
|
|
|
//write flags
|
|
//buffer.WriteStructure(flags);
|
|
for (int j = 0; j < 5; ++j) {
|
|
buffer.WriteUInt8(flags.raw[j]);
|
|
}
|
|
|
|
/*
|
|
float EmitterScalingRadius;
|
|
s32 DefaultEmitterID;
|
|
*/
|
|
|
|
//we don't support this atm; wouldn't be hard to add I don't think
|
|
//RoF also supports this so might be worth implementing.
|
|
buffer.WriteFloat(1.0f);
|
|
buffer.WriteInt32(-1);
|
|
|
|
if (emu->DestructibleObject || emu->class_ == Class::LDoNTreasure)
|
|
{
|
|
/*
|
|
char InteractiveObjectModelName[];
|
|
char InteractiveObjectName[];
|
|
char InteractiveObjectOtherName[];
|
|
*/
|
|
|
|
buffer.WriteString(emu->DestructibleModel);
|
|
buffer.WriteString(emu->DestructibleName2);
|
|
buffer.WriteString(emu->DestructibleString);
|
|
|
|
/*
|
|
s32 CurrIOState;
|
|
s32 ObjectAnimationID;
|
|
*/
|
|
buffer.WriteUInt32(emu->DestructibleAppearance);
|
|
buffer.WriteUInt32(emu->DestructibleUnk1);
|
|
|
|
/*
|
|
s32 SoundId[10];
|
|
*/
|
|
buffer.WriteUInt32(emu->DestructibleID1);
|
|
buffer.WriteUInt32(emu->DestructibleID2);
|
|
buffer.WriteUInt32(emu->DestructibleID3);
|
|
buffer.WriteUInt32(emu->DestructibleID4);
|
|
buffer.WriteUInt32(emu->DestructibleUnk2);
|
|
buffer.WriteUInt32(emu->DestructibleUnk3);
|
|
buffer.WriteUInt32(emu->DestructibleUnk4);
|
|
buffer.WriteUInt32(emu->DestructibleUnk5);
|
|
buffer.WriteUInt32(emu->DestructibleUnk6);
|
|
buffer.WriteUInt32(emu->DestructibleUnk7);
|
|
/*
|
|
s8 Collidable;
|
|
s8 ObjectType;
|
|
*/
|
|
buffer.WriteUInt8(emu->DestructibleUnk8);
|
|
buffer.WriteUInt8(emu->DestructibleUnk9);
|
|
}
|
|
|
|
/*
|
|
u8 PropertyCount;
|
|
u32 Properties[PropertyCount];
|
|
*/
|
|
//We don't actually support multiple body types yet, but we should consider it in the future
|
|
|
|
if (!emu->DestructibleObject)
|
|
{
|
|
buffer.WriteUInt8(1);
|
|
buffer.WriteUInt32(emu->bodytype);
|
|
}
|
|
else
|
|
{
|
|
buffer.WriteUInt8(0);
|
|
}
|
|
|
|
/*
|
|
u8 HPCurrentPct;
|
|
*/
|
|
buffer.WriteUInt8(emu->curHp);
|
|
|
|
/*
|
|
s8 HairColor;
|
|
s8 FacialHairColor;
|
|
s8 EyeColor1;
|
|
s8 EyeColor2;
|
|
s8 HairStyle;
|
|
s8 FacialHair;
|
|
s32 Heritage;
|
|
s32 Tattoo;
|
|
s32 Details;
|
|
*/
|
|
|
|
buffer.WriteUInt8(emu->haircolor);
|
|
buffer.WriteUInt8(emu->beardcolor);
|
|
buffer.WriteUInt8(emu->eyecolor1);
|
|
buffer.WriteUInt8(emu->eyecolor2);
|
|
buffer.WriteUInt8(emu->hairstyle);
|
|
buffer.WriteUInt8(emu->beard);
|
|
buffer.WriteUInt32(emu->drakkin_heritage);
|
|
buffer.WriteUInt32(emu->drakkin_tattoo);
|
|
buffer.WriteUInt32(emu->drakkin_details);
|
|
|
|
/*
|
|
s8 TextureType;
|
|
s8 Material;
|
|
s8 Variation;
|
|
s8 HeadType;
|
|
*/
|
|
buffer.WriteUInt8(emu->equip_chest2);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(emu->helm);
|
|
|
|
/*
|
|
float Height;
|
|
s8 FaceStyle;
|
|
float MyWalkSpeed;
|
|
float RunSpeed;
|
|
s32 Race;
|
|
*/
|
|
|
|
buffer.WriteFloat(emu->size);
|
|
buffer.WriteInt8(emu->face);
|
|
buffer.WriteFloat(emu->walkspeed);
|
|
buffer.WriteFloat(emu->runspeed);
|
|
buffer.WriteInt32(emu->race);
|
|
|
|
/*
|
|
u8 HoldingAnimation;
|
|
u32 Deity;
|
|
EqGuid GuildID;
|
|
u32 Class;
|
|
*/
|
|
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt32(emu->deity);
|
|
if (emu->NPC) {
|
|
buffer.WriteInt32(-1);
|
|
buffer.WriteUInt32(0);
|
|
}
|
|
else { //guilds will probably need a ton of work
|
|
buffer.WriteUInt32(emu->guildID);
|
|
buffer.WriteUInt32(0);
|
|
}
|
|
buffer.WriteUInt32(emu->class_);
|
|
|
|
/*
|
|
u8 PvP;
|
|
u8 StandState;
|
|
u8 Light;
|
|
u8 GravityBehavior;
|
|
*/
|
|
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(emu->StandState);
|
|
buffer.WriteUInt8(emu->light);
|
|
buffer.WriteUInt8(emu->flymode);
|
|
|
|
/*
|
|
char LastName[];
|
|
*/
|
|
buffer.WriteString(emu->lastName);
|
|
|
|
/*
|
|
u8 bGuildShowAnim;
|
|
u8 bTempPet;
|
|
u32 MasterID;
|
|
u8 FindBits;
|
|
*/
|
|
|
|
buffer.WriteUInt8(emu->guild_show);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt32(emu->petOwnerId);
|
|
buffer.WriteUInt8(0);
|
|
|
|
/*
|
|
u32 PlayerState;
|
|
u32 NpcTintIndex;
|
|
u32 PrimaryTintIndex;
|
|
u32 SecondaryTintIndex;
|
|
*/
|
|
|
|
buffer.WriteUInt32(emu->PlayerState);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
|
|
/*
|
|
u32 EncounterLockState;
|
|
u64 LockID;
|
|
*/
|
|
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt64(0);
|
|
|
|
//u32 SeeInvis[3];
|
|
if (emu->NPC) {
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
}
|
|
|
|
/*
|
|
s32 Primary;
|
|
s32 Secondary;
|
|
*/
|
|
buffer.WriteUInt32(0xffffffff);
|
|
buffer.WriteUInt32(0xffffffff);
|
|
|
|
if ((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) ||
|
|
(emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)
|
|
)
|
|
{
|
|
/*
|
|
u32 ArmorColor[9];
|
|
*/
|
|
for (int k = EQ::textures::textureBegin; k < EQ::textures::materialCount; ++k)
|
|
{
|
|
buffer.WriteUInt32(emu->equipment_tint.Slot[k].Color);
|
|
}
|
|
|
|
/*
|
|
Armor Armor[9];
|
|
*/
|
|
for (int k = EQ::textures::textureBegin; k < EQ::textures::materialCount; k++) {
|
|
buffer.WriteUInt32(emu->equipment.Slot[k].Material);
|
|
buffer.WriteUInt32(emu->equipment.Slot[k].Unknown1);
|
|
buffer.WriteUInt32(emu->equipment.Slot[k].EliteModel);
|
|
buffer.WriteUInt32(emu->equipment.Slot[k].HerosForgeModel);
|
|
buffer.WriteUInt32(emu->equipment.Slot[k].Unknown2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Armor Armor[3];
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
|
|
buffer.WriteUInt32(emu->equipment.Primary.Material);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
|
|
buffer.WriteUInt32(emu->equipment.Secondary.Material);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
}
|
|
|
|
//u8 CPhysicsData[20];
|
|
structs::Spawn_Struct_Position position;
|
|
memset(&position, 0, sizeof(structs::Spawn_Struct_Position));
|
|
|
|
position.y = emu->y;
|
|
position.deltaZ = emu->deltaZ;
|
|
position.deltaX = emu->deltaX;
|
|
position.x = emu->x;
|
|
position.heading = emu->heading;
|
|
position.deltaHeading = emu->deltaHeading;
|
|
position.z = emu->z;
|
|
position.animation = emu->animation;
|
|
position.deltaY = emu->deltaY;
|
|
|
|
//buffer.WriteStructure(position);
|
|
for (int j = 0; j < 5; ++j) {
|
|
buffer.WriteUInt32(position.raw[j]);
|
|
}
|
|
|
|
/*
|
|
if(Flags.title) {
|
|
char Title[];
|
|
}
|
|
*/
|
|
if (flags.title) {
|
|
buffer.WriteString(emu->title);
|
|
}
|
|
|
|
/*
|
|
if(Flags.suffix) {
|
|
char Suffix[];
|
|
}
|
|
*/
|
|
if (flags.suffix) {
|
|
buffer.WriteString(emu->suffix);
|
|
}
|
|
|
|
/*
|
|
u32 Unknown0x0164;
|
|
s32 SplineID;
|
|
*/
|
|
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
|
|
/*
|
|
u8 Mercenary;
|
|
*/
|
|
buffer.WriteUInt8(emu->IsMercenary);
|
|
|
|
/*
|
|
char realEstateItemGuid[];
|
|
s32 RealEstateID;
|
|
s32 RealEstateItemId;
|
|
*/
|
|
|
|
buffer.WriteString("0000000000000000");
|
|
buffer.WriteInt32(-1);
|
|
buffer.WriteInt32(-1);
|
|
|
|
/*
|
|
s32 MercId;
|
|
s32 ContractorID;
|
|
u32 Birthdate;
|
|
u8 bAlwaysShowAura;
|
|
*/
|
|
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt8(0);
|
|
|
|
/*
|
|
u32 physicsEffectCount;
|
|
PhysicsEffect physicsEffects[physicsEffectCount];
|
|
*/
|
|
buffer.WriteUInt32(0);
|
|
|
|
//s32 SpawnStatus[6];
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
|
|
if (flags.interactiveobject && emu->DestructibleUnk9 == 4) {
|
|
/*
|
|
s32 BannerIndex0;
|
|
s32 BannerIndex1;
|
|
s32 BannerTint0;
|
|
s32 BannerTint1;
|
|
*/
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
buffer.WriteUInt32(0);
|
|
}
|
|
|
|
auto outapp = new EQApplicationPacket(OP_ZoneEntry, buffer.size());
|
|
outapp->WriteData(buffer.buffer(), buffer.size());
|
|
dest->FastQueuePacket(&outapp, ack_req);
|
|
}
|
|
|
|
delete in;
|
|
}
|
|
|
|
ENCODE(OP_CharInventory) {
|
|
//consume the packet
|
|
EQApplicationPacket* in = *p;
|
|
*p = nullptr;
|
|
|
|
if (!in->size) {
|
|
in->size = 4;
|
|
in->pBuffer = new uchar[in->size];
|
|
memset(in->pBuffer, 0, in->size);
|
|
|
|
dest->FastQueuePacket(&in, ack_req);
|
|
return;
|
|
}
|
|
|
|
//store away the emu struct
|
|
uchar* __emu_buffer = in->pBuffer;
|
|
|
|
int item_count = in->size / sizeof(EQ::InternalSerializedItem_Struct);
|
|
if (!item_count || (in->size % sizeof(EQ::InternalSerializedItem_Struct)) != 0) {
|
|
Log(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d",
|
|
opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(EQ::InternalSerializedItem_Struct));
|
|
|
|
delete in;
|
|
return;
|
|
}
|
|
|
|
EQ::InternalSerializedItem_Struct* eq = (EQ::InternalSerializedItem_Struct*)in->pBuffer;
|
|
SerializeBuffer buffer;
|
|
buffer.WriteUInt32(item_count);
|
|
|
|
for (int index = 0; index < item_count; ++index, ++eq) {
|
|
SerializeItem(buffer, (const EQ::ItemInstance*)eq->inst, eq->slot_id, 0, ItemPacketCharInventory);
|
|
}
|
|
|
|
in->size = buffer.size();
|
|
in->pBuffer = new unsigned char[buffer.size()];
|
|
memcpy(in->pBuffer, buffer.buffer(), buffer.size());
|
|
|
|
delete[] __emu_buffer;
|
|
|
|
dest->FastQueuePacket(&in, ack_req);
|
|
}
|
|
|
|
ENCODE(OP_NewSpawn) { ENCODE_FORWARD(OP_ZoneSpawns); }
|
|
|
|
ENCODE(OP_NewZone) {
|
|
EQApplicationPacket* in = *p;
|
|
*p = nullptr;
|
|
|
|
unsigned char* __emu_buffer = in->pBuffer;
|
|
NewZone_Struct* emu = (NewZone_Struct*)__emu_buffer;
|
|
|
|
SerializeBuffer buffer;
|
|
/*
|
|
char Shortname[];
|
|
char Longname[];
|
|
char WeatherType[];
|
|
char WeatherTypeOverride[];
|
|
char SkyType[];
|
|
char SkyTypeOverride[];
|
|
*/
|
|
buffer.WriteString(emu->zone_short_name);
|
|
buffer.WriteString(emu->zone_long_name);
|
|
buffer.WriteString("");
|
|
buffer.WriteString("");
|
|
buffer.WriteString("");
|
|
buffer.WriteString("");
|
|
|
|
/*
|
|
s32 ZoneType;
|
|
s16 ZoneId;
|
|
s16 ZoneInstance;
|
|
float ZoneExpModifier;
|
|
s32 GroupLvlExpRelated;
|
|
s32 FilterID;
|
|
s32 Unknown1;
|
|
*/
|
|
buffer.WriteInt32(emu->ztype);
|
|
buffer.WriteInt16(emu->zone_id);
|
|
buffer.WriteInt16(emu->zone_instance);
|
|
buffer.WriteFloat(emu->zone_exp_multiplier);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
|
|
//float FogDensity;
|
|
buffer.WriteFloat(emu->fog_density);
|
|
|
|
//WeatherState state[4];
|
|
for (int i = 0; i < 4; ++i) {
|
|
/*
|
|
float FogStart;
|
|
float FogEnd;
|
|
u8 FogRed;
|
|
u8 FogGreen;
|
|
u8 FogBlue;
|
|
u8 RainChance;
|
|
u8 RainDuration;
|
|
u8 SnowChance;
|
|
u8 SnowDuration;
|
|
*/
|
|
|
|
buffer.WriteFloat(emu->fog_minclip[i]);
|
|
buffer.WriteFloat(emu->fog_maxclip[i]);
|
|
buffer.WriteUInt8(emu->fog_red[i]);
|
|
buffer.WriteUInt8(emu->fog_green[i]);
|
|
buffer.WriteUInt8(emu->fog_blue[i]);
|
|
buffer.WriteUInt8(emu->rain_chance[i]);
|
|
buffer.WriteUInt8(emu->rain_duration[i]);
|
|
buffer.WriteUInt8(emu->snow_chance[i]);
|
|
buffer.WriteUInt8(emu->snow_duration[i]);
|
|
|
|
}
|
|
|
|
/*
|
|
u8 PrecipitationType;
|
|
float BloomIntensity;
|
|
float ZoneGravity;
|
|
s32 LavaDamage;
|
|
s32 MinLavaDamage;
|
|
*/
|
|
buffer.WriteUInt8(emu->sky);
|
|
buffer.WriteFloat(1.0f);
|
|
buffer.WriteFloat(emu->gravity);
|
|
buffer.WriteInt32(emu->lava_damage);
|
|
buffer.WriteInt32(emu->min_lava_damage);
|
|
|
|
/*
|
|
s32 TimeStringID;
|
|
s32 Unknown3;
|
|
s32 SkyLock;
|
|
s32 SkyLockOverride;
|
|
*/
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(1);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(-1);
|
|
|
|
/*
|
|
float SafeY;
|
|
float SafeX;
|
|
float SafeZ;
|
|
float SafeHeading;
|
|
float Ceiling;
|
|
float Floor;
|
|
*/
|
|
|
|
buffer.WriteFloat(emu->safe_y);
|
|
buffer.WriteFloat(emu->safe_x);
|
|
buffer.WriteFloat(emu->safe_z);
|
|
buffer.WriteFloat(emu->safe_heading);
|
|
buffer.WriteFloat(emu->max_z);
|
|
buffer.WriteFloat(emu->underworld);
|
|
|
|
/*
|
|
float MinClip;
|
|
float MaxClip;
|
|
s32 FallThroughWorldTeleportID;
|
|
*/
|
|
buffer.WriteFloat(emu->minclip);
|
|
buffer.WriteFloat(emu->maxclip);
|
|
buffer.WriteInt32(emu->underworld_teleport_index);
|
|
|
|
/*
|
|
s32 Unknown4;
|
|
s32 ScriptIDHour;
|
|
s32 ScriptIDMinute;
|
|
s32 ScriptIDTick;
|
|
s32 ScriptIDOnPlayerDeath;
|
|
s32 ScriptIDOnNPCDeath;
|
|
s32 ScriptIDPlayerEnteringZone;
|
|
s32 ScriptIDOnZonePop;
|
|
s32 ScriptIDNPCLoot;
|
|
s32 Unknown4b;
|
|
s32 ScriptIDOnFishing;
|
|
s32 ScriptIDOnForage;
|
|
s32 Unknown4c;
|
|
*/
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
|
|
/*
|
|
s32 NPCAgroMaxDist;
|
|
*/
|
|
buffer.WriteInt32(600);
|
|
|
|
/*
|
|
s32 ForageLow;
|
|
s32 ForageMedium;
|
|
s32 ForageHigh;
|
|
s32 ForageSpecial;
|
|
s32 FishingLow;
|
|
s32 FishingMedium;
|
|
s32 FishingHigh;
|
|
s32 FishingRelated;
|
|
*/
|
|
buffer.WriteInt32(-1);
|
|
buffer.WriteInt32(-1);
|
|
buffer.WriteInt32(-1);
|
|
buffer.WriteInt32(-1);
|
|
buffer.WriteInt32(-1);
|
|
buffer.WriteInt32(-1);
|
|
buffer.WriteInt32(-1);
|
|
buffer.WriteInt32(-1);
|
|
|
|
/*
|
|
s32 CanPlaceCampsite;
|
|
s32 CanPlaceGuildBanner;
|
|
s32 Unknown4d;
|
|
*/
|
|
|
|
buffer.WriteInt32(2);
|
|
buffer.WriteInt32(2);
|
|
buffer.WriteInt32(0);
|
|
|
|
/*
|
|
s32 FastRegenHP;
|
|
s32 FastRegenMana;
|
|
s32 FastRegenEndurance;
|
|
*/
|
|
buffer.WriteInt32(emu->fast_regen_hp);
|
|
buffer.WriteInt32(emu->fast_regen_mana);
|
|
buffer.WriteInt32(emu->fast_regen_endurance);
|
|
|
|
/*
|
|
u8 NewEngineZone;
|
|
u8 SkyEnabled;
|
|
u8 FogOnOff;
|
|
u8 ClimateType;
|
|
u8 bNoPlayerLight;
|
|
*/
|
|
buffer.WriteUInt8(0); //not sure what happens if we set this incorrectly but we probably need to add this to the zone database
|
|
buffer.WriteUInt8(1);
|
|
buffer.WriteUInt8(1);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(0);
|
|
|
|
/*
|
|
u8 bUnknown5;
|
|
u8 bNoAttack;
|
|
u8 bAllowPVP;
|
|
u8 bNoEncumber;
|
|
u8 Unknown6;
|
|
u8 Unknown7;
|
|
*/
|
|
buffer.WriteUInt8(1);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(1);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(0);
|
|
|
|
/*
|
|
u8 bNoLevitate;
|
|
u8 bNoBuffExpiration;
|
|
u8 bDisallowManaStone;
|
|
u8 bNoBind;
|
|
u8 bNoCallOfTheHero;
|
|
u8 bUnknown8;
|
|
u8 bNoFear;
|
|
u8 bUnknown9;
|
|
*/
|
|
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(emu->suspend_buffs);
|
|
buffer.WriteUInt8(1);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(0);
|
|
|
|
auto outapp = new EQApplicationPacket(OP_NewZone, buffer.size());
|
|
outapp->WriteData(buffer.buffer(), buffer.size());
|
|
dest->FastQueuePacket(&outapp, ack_req);
|
|
|
|
delete in;
|
|
}
|
|
|
|
ENCODE(OP_SpawnDoor)
|
|
{
|
|
SETUP_VAR_ENCODE(Door_Struct);
|
|
int door_count = __packet->size / sizeof(Door_Struct);
|
|
int total_length = door_count * sizeof(structs::Door_Struct);
|
|
ALLOC_VAR_ENCODE(structs::Door_Struct, total_length);
|
|
|
|
int r;
|
|
for (r = 0; r < door_count; r++) {
|
|
strncpy(eq[r].name, emu[r].name, 32);
|
|
eq[r].DefaultY = emu[r].yPos;
|
|
eq[r].DefaultX = emu[r].xPos;
|
|
eq[r].DefaultZ = emu[r].zPos;
|
|
eq[r].DefaultHeading = emu[r].heading;
|
|
eq[r].DefaultDoorAngle = emu[r].incline;
|
|
eq[r].Y = emu[r].yPos;
|
|
eq[r].X = emu[r].xPos;
|
|
eq[r].Z = emu[r].zPos;
|
|
eq[r].Heading = emu[r].heading;
|
|
//there's a door angle here but im not sure if / what we set it to since ive literally never seen it as anything but 0 on live
|
|
//based on pattern it probably is supposed to match the default angle?
|
|
//I'm not 100% sure this is a float it might be a uint32
|
|
eq[r].DoorAngle = emu[r].incline;
|
|
eq[r].ScaleFactor = emu[r].size;
|
|
eq[r].Id = emu[r].doorId;
|
|
eq[r].Type = emu[r].opentype;
|
|
eq[r].State = emu[r].state_at_spawn;
|
|
eq[r].DefaultState = emu[r].invert_state;
|
|
eq[r].Param = emu[r].door_param;
|
|
eq[r].bVisible = 1;
|
|
eq[r].bUsable = 1;
|
|
}
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_GroundSpawn)
|
|
{
|
|
EQApplicationPacket* in = *p;
|
|
*p = nullptr;
|
|
Object_Struct* emu = (Object_Struct*)in->pBuffer;
|
|
|
|
SerializeBuffer buffer;
|
|
buffer.WriteUInt32(emu->drop_id);
|
|
buffer.WriteString(emu->object_name);
|
|
buffer.WriteUInt16(emu->zone_id);
|
|
buffer.WriteUInt16(emu->zone_instance);
|
|
buffer.WriteUInt32(emu->drop_id); //this is some other sub but it's okay to duplicate
|
|
buffer.WriteUInt32(0); //expires
|
|
buffer.WriteFloat(emu->heading);
|
|
buffer.WriteFloat(emu->tilt_x);
|
|
buffer.WriteFloat(emu->tilt_y);
|
|
buffer.WriteFloat(emu->size != 0 && (float)emu->size < 5000.f ? (float)((float)emu->size / 100.0f) : 1.f); //size, with weird peq hack
|
|
buffer.WriteFloat(emu->y);
|
|
buffer.WriteFloat(emu->x);
|
|
buffer.WriteFloat(emu->z);
|
|
buffer.WriteFloat(emu->object_type); //weight
|
|
|
|
auto outapp = new EQApplicationPacket(OP_GroundSpawn, buffer.size());
|
|
outapp->WriteData(buffer.buffer(), buffer.size());
|
|
dest->FastQueuePacket(&outapp, ack_req);
|
|
|
|
delete in;
|
|
}
|
|
|
|
ENCODE(OP_SendZonepoints)
|
|
{
|
|
SETUP_VAR_ENCODE(ZonePoints);
|
|
ALLOC_VAR_ENCODE(structs::ZonePoints, sizeof(structs::ZonePoints) + sizeof(structs::ZonePoint_Entry) * (emu->count + 1));
|
|
|
|
eq->count = emu->count;
|
|
for (uint32 i = 0; i < emu->count; ++i)
|
|
{
|
|
eq->zpe[i].iterator = emu->zpe[i].iterator;
|
|
eq->zpe[i].x = emu->zpe[i].x;
|
|
eq->zpe[i].y = emu->zpe[i].y;
|
|
eq->zpe[i].z = emu->zpe[i].z;
|
|
eq->zpe[i].heading = emu->zpe[i].heading;
|
|
eq->zpe[i].zoneid = emu->zpe[i].zoneid;
|
|
eq->zpe[i].zoneinstance = emu->zpe[i].zoneinstance;
|
|
}
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_RequestClientZoneChange)
|
|
{
|
|
ENCODE_LENGTH_EXACT(RequestClientZoneChange_Struct);
|
|
SETUP_DIRECT_ENCODE(RequestClientZoneChange_Struct, structs::RequestClientZoneChange_Struct);
|
|
|
|
OUT(zone_id);
|
|
OUT(instance_id);
|
|
OUT(y);
|
|
OUT(x);
|
|
OUT(z);
|
|
OUT(heading);
|
|
eq->type = 0x0b;
|
|
eq->unknown004 = 0xffffffff;
|
|
eq->unknown172 = 0x0168b500;
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_ZoneChange)
|
|
{
|
|
ENCODE_LENGTH_EXACT(ZoneChange_Struct);
|
|
SETUP_DIRECT_ENCODE(ZoneChange_Struct, structs::ZoneChange_Struct);
|
|
|
|
memcpy(eq->char_name, emu->char_name, sizeof(emu->char_name));
|
|
OUT(zoneID);
|
|
OUT(instanceID);
|
|
OUT(y);
|
|
OUT(x);
|
|
OUT(z)
|
|
OUT(zone_reason);
|
|
OUT(success);
|
|
|
|
if (eq->success < 0)
|
|
eq->success -= 1;
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_ClientUpdate)
|
|
{
|
|
ENCODE_LENGTH_EXACT(PlayerPositionUpdateServer_Struct);
|
|
SETUP_DIRECT_ENCODE(PlayerPositionUpdateServer_Struct, structs::PlayerPositionUpdateServer_Struct);
|
|
|
|
OUT(spawn_id);
|
|
OUT(vehicle_id);
|
|
eq->position.x = emu->x_pos;
|
|
eq->position.y = emu->y_pos;
|
|
eq->position.z = emu->z_pos;
|
|
eq->position.heading = emu->heading;
|
|
eq->position.deltaX = emu->delta_x;
|
|
eq->position.deltaY = emu->delta_y;
|
|
eq->position.deltaZ = emu->delta_z;
|
|
eq->position.deltaHeading = emu->delta_heading;
|
|
eq->position.animation = emu->animation;
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_WearChange)
|
|
{
|
|
ENCODE_LENGTH_EXACT(WearChange_Struct);
|
|
SETUP_DIRECT_ENCODE(WearChange_Struct, structs::WearChange_Struct);
|
|
|
|
OUT(spawn_id);
|
|
eq->wear_slot_id = emu->wear_slot_id;
|
|
eq->armor_id = emu->material;
|
|
eq->variation = emu->unknown06;
|
|
eq->material = emu->elite_material;
|
|
eq->new_armor_id = emu->hero_forge_model;
|
|
eq->new_armor_type = emu->unknown18;
|
|
eq->color = emu->color.Color;
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_ChannelMessage)
|
|
{
|
|
EQApplicationPacket* in = *p;
|
|
*p = nullptr;
|
|
|
|
ChannelMessage_Struct* emu = (ChannelMessage_Struct*)in->pBuffer;
|
|
|
|
unsigned char* __emu_buffer = in->pBuffer;
|
|
|
|
std::string old_message = emu->message;
|
|
std::string new_message = old_message;
|
|
//ServerToRoF2SayLink(new_message, old_message);
|
|
|
|
in->size = strlen(emu->sender) + strlen(emu->targetname) + new_message.length() + 43;
|
|
|
|
in->pBuffer = new unsigned char[in->size];
|
|
|
|
char* OutBuffer = (char*)in->pBuffer;
|
|
|
|
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->sender);
|
|
VARSTRUCT_ENCODE_STRING(OutBuffer, emu->targetname);
|
|
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
|
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
|
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->language);
|
|
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->chan_num);
|
|
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
|
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); // Unknown
|
|
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, emu->skill_in_language);
|
|
VARSTRUCT_ENCODE_STRING(OutBuffer, new_message.c_str());
|
|
|
|
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
|
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
|
VARSTRUCT_ENCODE_TYPE(uint32, OutBuffer, 0); // Unknown
|
|
VARSTRUCT_ENCODE_TYPE(uint16, OutBuffer, 0); // Unknown
|
|
VARSTRUCT_ENCODE_TYPE(uint8, OutBuffer, 0); // Unknown
|
|
|
|
delete[] __emu_buffer;
|
|
dest->FastQueuePacket(&in, ack_req);
|
|
}
|
|
|
|
ENCODE(OP_SpecialMesg)
|
|
{
|
|
EQApplicationPacket* in = *p;
|
|
*p = nullptr;
|
|
|
|
SerializeBuffer buf(in->size);
|
|
buf.WriteInt8(in->ReadUInt8()); // speak mode
|
|
buf.WriteInt8(in->ReadUInt8()); // journal mode
|
|
buf.WriteInt8(in->ReadUInt8()); // language
|
|
buf.WriteInt32(in->ReadUInt32()); // message type
|
|
buf.WriteInt32(in->ReadUInt32()); // target spawn id
|
|
|
|
std::string name;
|
|
in->ReadString(name); // NPC names max out at 63 chars
|
|
|
|
buf.WriteString(name);
|
|
|
|
buf.WriteInt32(in->ReadUInt32()); // loc
|
|
buf.WriteInt32(in->ReadUInt32());
|
|
buf.WriteInt32(in->ReadUInt32());
|
|
|
|
std::string old_message;
|
|
std::string new_message;
|
|
|
|
in->ReadString(old_message);
|
|
|
|
//ServerToRoF2SayLink(new_message, old_message);
|
|
new_message = old_message;
|
|
|
|
buf.WriteString(new_message);
|
|
|
|
auto outapp = new EQApplicationPacket(OP_SpecialMesg, buf);
|
|
|
|
dest->FastQueuePacket(&outapp, ack_req);
|
|
delete in;
|
|
}
|
|
|
|
ENCODE(OP_DeleteSpawn)
|
|
{
|
|
ENCODE_LENGTH_EXACT(DeleteSpawn_Struct);
|
|
SETUP_DIRECT_ENCODE(DeleteSpawn_Struct, structs::DeleteSpawn_Struct);
|
|
|
|
OUT(spawn_id);
|
|
eq->unknown04 = 1; // Observed
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_FormattedMessage)
|
|
{
|
|
EQApplicationPacket* in = *p;
|
|
*p = nullptr;
|
|
|
|
FormattedMessage_Struct* emu = (FormattedMessage_Struct*)in->pBuffer;
|
|
|
|
char* old_message_ptr = (char*)in->pBuffer;
|
|
old_message_ptr += sizeof(FormattedMessage_Struct);
|
|
|
|
std::string old_message_array[9];
|
|
|
|
for (int i = 0; i < 9; ++i) {
|
|
if (*old_message_ptr == 0) { break; }
|
|
old_message_array[i] = old_message_ptr;
|
|
old_message_ptr += old_message_array[i].length() + 1;
|
|
}
|
|
|
|
SerializeBuffer buffer;
|
|
buffer.WriteUInt32(emu->unknown0);
|
|
buffer.WriteUInt8(0); // Observed
|
|
buffer.WriteUInt32(emu->string_id);
|
|
buffer.WriteUInt32(emu->type);
|
|
|
|
for (int i = 0; i < 9; ++i) {
|
|
buffer.WriteLengthString(old_message_array[i]);
|
|
}
|
|
|
|
auto outapp = new EQApplicationPacket(OP_FormattedMessage, buffer.size());
|
|
outapp->WriteData(buffer.buffer(), buffer.size());
|
|
dest->FastQueuePacket(&outapp, ack_req);
|
|
|
|
delete in;
|
|
}
|
|
|
|
ENCODE(OP_Consider)
|
|
{
|
|
ENCODE_LENGTH_EXACT(Consider_Struct);
|
|
SETUP_DIRECT_ENCODE(Consider_Struct, structs::Consider_Struct);
|
|
|
|
OUT(playerid);
|
|
OUT(targetid);
|
|
OUT(faction);
|
|
OUT(level);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
ENCODE(OP_HPUpdate)
|
|
{
|
|
SETUP_DIRECT_ENCODE(SpawnHPUpdate_Struct, structs::SpawnHPUpdate_Struct);
|
|
|
|
OUT(spawn_id);
|
|
OUT(cur_hp);
|
|
OUT(max_hp);
|
|
|
|
FINISH_ENCODE();
|
|
}
|
|
|
|
// DECODE methods
|
|
|
|
DECODE(OP_EnterWorld)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::EnterWorld_Struct);
|
|
SETUP_DIRECT_DECODE(EnterWorld_Struct, structs::EnterWorld_Struct);
|
|
|
|
memcpy(emu->name, eq->name, sizeof(emu->name));
|
|
emu->return_home = 0;
|
|
emu->tutorial = 0;
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_ZoneEntry)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::ClientZoneEntry_Struct);
|
|
SETUP_DIRECT_DECODE(ClientZoneEntry_Struct, structs::ClientZoneEntry_Struct);
|
|
|
|
memcpy(emu->char_name, eq->char_name, sizeof(emu->char_name));
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_ZoneChange)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::ZoneChange_Struct);
|
|
SETUP_DIRECT_DECODE(ZoneChange_Struct, structs::ZoneChange_Struct);
|
|
|
|
memcpy(emu->char_name, eq->char_name, sizeof(emu->char_name));
|
|
IN(zoneID);
|
|
IN(instanceID);
|
|
IN(y);
|
|
IN(x);
|
|
IN(z)
|
|
IN(zone_reason);
|
|
IN(success);
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_ClientUpdate)
|
|
{
|
|
// for some odd reason, there is an extra byte on the end of this on occasion..
|
|
DECODE_LENGTH_ATLEAST(structs::PlayerPositionUpdateClient_Struct);
|
|
SETUP_DIRECT_DECODE(PlayerPositionUpdateClient_Struct, structs::PlayerPositionUpdateClient_Struct);
|
|
|
|
IN(spawn_id);
|
|
IN(vehicle_id);
|
|
IN(sequence);
|
|
emu->x_pos = eq->position.x;
|
|
emu->y_pos = eq->position.y;
|
|
emu->z_pos = eq->position.z;
|
|
emu->heading = eq->position.heading;
|
|
emu->delta_x = eq->position.delta_x;
|
|
emu->delta_y = eq->position.delta_y;
|
|
emu->delta_z = eq->position.delta_z;
|
|
emu->delta_heading = eq->position.delta_heading;
|
|
emu->animation = eq->position.animation;
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_WearChange)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::WearChange_Struct);
|
|
SETUP_DIRECT_DECODE(WearChange_Struct, structs::WearChange_Struct);
|
|
|
|
IN(spawn_id);
|
|
emu->wear_slot_id = eq->wear_slot_id;
|
|
emu->material = eq->armor_id;
|
|
emu->unknown06 = eq->variation;
|
|
emu->elite_material = eq->material;
|
|
emu->hero_forge_model = eq->new_armor_id;
|
|
emu->unknown18 = eq->new_armor_type;
|
|
emu->color.Color = eq->color;
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_ChannelMessage)
|
|
{
|
|
unsigned char* __eq_buffer = __packet->pBuffer;
|
|
|
|
char* InBuffer = (char*)__eq_buffer;
|
|
|
|
char Sender[64];
|
|
char Target[64];
|
|
|
|
VARSTRUCT_DECODE_STRING(Sender, InBuffer);
|
|
VARSTRUCT_DECODE_STRING(Target, InBuffer);
|
|
|
|
//packet seems the same as rof2 with 4 more empty bytes before language
|
|
InBuffer += 8;
|
|
|
|
uint32 Language = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
|
|
uint32 Channel = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
|
|
|
|
InBuffer += 5;
|
|
|
|
uint32 Skill = VARSTRUCT_DECODE_TYPE(uint32, InBuffer);
|
|
|
|
std::string old_message = InBuffer;
|
|
std::string new_message = old_message;
|
|
//RoF2ToServerSayLink(new_message, old_message);
|
|
|
|
__packet->size = sizeof(ChannelMessage_Struct) + new_message.length() + 1;
|
|
__packet->pBuffer = new unsigned char[__packet->size];
|
|
ChannelMessage_Struct* emu = (ChannelMessage_Struct*)__packet->pBuffer;
|
|
|
|
strn0cpy(emu->targetname, Target, sizeof(emu->targetname));
|
|
strn0cpy(emu->sender, Target, sizeof(emu->sender));
|
|
emu->language = Language;
|
|
emu->chan_num = Channel;
|
|
emu->skill_in_language = Skill;
|
|
strcpy(emu->message, new_message.c_str());
|
|
|
|
delete[] __eq_buffer;
|
|
}
|
|
|
|
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++) {
|
|
// Size 68 in Laurion
|
|
IN(filters[r]);
|
|
}
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_Consider)
|
|
{
|
|
DECODE_LENGTH_EXACT(structs::Consider_Struct);
|
|
SETUP_DIRECT_DECODE(Consider_Struct, structs::Consider_Struct);
|
|
|
|
IN(playerid);
|
|
IN(targetid);
|
|
IN(faction);
|
|
IN(level);
|
|
//emu->cur_hp = 1;
|
|
//emu->max_hp = 2;
|
|
//emu->pvpcon = 0;
|
|
|
|
FINISH_DIRECT_DECODE();
|
|
}
|
|
|
|
DECODE(OP_ConsiderCorpse) { DECODE_FORWARD(OP_Consider); }
|
|
|
|
//Naive version but should work well enough for now
|
|
int ExtractIDFile(const std::string& input) {
|
|
std::string number;
|
|
for (char ch : input) {
|
|
if (std::isdigit(static_cast<unsigned char>(ch))) {
|
|
number += ch;
|
|
}
|
|
}
|
|
|
|
if (number.empty()) {
|
|
return 0;
|
|
}
|
|
|
|
return std::stoi(number);
|
|
}
|
|
|
|
// Helper Functions
|
|
void SerializeItemDefinition(SerializeBuffer& buffer, const EQ::ItemData* item) {
|
|
//u8 Type;
|
|
buffer.WriteUInt8(item->ItemClass);
|
|
//char Name[];
|
|
buffer.WriteString(item->Name);
|
|
|
|
//char LoreName[];
|
|
buffer.WriteString(item->Lore);
|
|
|
|
//we need to parse id file
|
|
//s32 IDFile;
|
|
int32 idfile = ExtractIDFile(item->IDFile);
|
|
buffer.WriteUInt32(idfile);
|
|
|
|
//s32 IDFile2;
|
|
buffer.WriteUInt32(0); //unsupported atm
|
|
|
|
/*
|
|
ibs.id = item->ID;
|
|
ibs.weight = item->Weight;
|
|
ibs.norent = item->NoRent;
|
|
ibs.nodrop = item->NoDrop;
|
|
ibs.attune = item->Attuneable;
|
|
ibs.size = item->Size;
|
|
ibs.slots = item->Slots;
|
|
ibs.price = item->Price;
|
|
ibs.icon = item->Icon;
|
|
*/
|
|
|
|
//s32 ItemNumber;
|
|
buffer.WriteUInt32(item->ID);
|
|
|
|
//s32 Weight;
|
|
buffer.WriteInt32(item->Weight);
|
|
|
|
//bool NoRent;
|
|
buffer.WriteUInt8(item->NoRent);
|
|
|
|
//bool IsDroppable;
|
|
buffer.WriteUInt8(item->NoDrop);
|
|
|
|
//bool Attuneable;
|
|
buffer.WriteUInt8(item->Attuneable);
|
|
|
|
//u8 Size;
|
|
buffer.WriteUInt8(item->Size);
|
|
|
|
//u32 EquipSlots;
|
|
buffer.WriteUInt32(item->Slots);
|
|
|
|
//u32 Cost;
|
|
buffer.WriteUInt32(item->Price);
|
|
|
|
//s32 IconNumber;
|
|
buffer.WriteInt32(item->Icon);
|
|
|
|
//bool eGMRequirement;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//bool Tradeskills;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//s8 SvCold;
|
|
//s8 SvDisease;
|
|
//s8 SvPoison;
|
|
//s8 SvMagic;
|
|
//s8 SvFire;
|
|
//s8 SvCorruption;
|
|
buffer.WriteInt8(item->CR);
|
|
buffer.WriteInt8(item->DR);
|
|
buffer.WriteInt8(item->PR);
|
|
buffer.WriteInt8(item->MR);
|
|
buffer.WriteInt8(item->FR);
|
|
buffer.WriteInt8(item->SVCorruption);
|
|
|
|
//s8 STR;
|
|
//s8 STA;
|
|
//s8 AGI;
|
|
//s8 DEX;
|
|
//s8 CHA;
|
|
//s8 INT;
|
|
//s8 WIS;
|
|
buffer.WriteInt8(item->AStr);
|
|
buffer.WriteInt8(item->ASta);
|
|
buffer.WriteInt8(item->AAgi);
|
|
buffer.WriteInt8(item->ADex);
|
|
buffer.WriteInt8(item->ACha);
|
|
buffer.WriteInt8(item->AInt);
|
|
buffer.WriteInt8(item->AWis);
|
|
|
|
//s32 HP;
|
|
//s32 Mana;
|
|
//s32 Endurance;
|
|
//s32 AC;
|
|
buffer.WriteInt32(item->HP);
|
|
buffer.WriteInt32(item->Mana);
|
|
buffer.WriteInt32(item->Endur);
|
|
buffer.WriteInt32(item->AC);
|
|
|
|
//s32 HPRegen;
|
|
//s32 ManaRegen;
|
|
//s32 EnduranceRegen;
|
|
buffer.WriteInt32(item->Regen);
|
|
buffer.WriteInt32(item->ManaRegen);
|
|
buffer.WriteInt32(item->EnduranceRegen);
|
|
|
|
//u32 Classes;
|
|
//u32 Races;
|
|
//u32 Deity;
|
|
buffer.WriteUInt32(item->Classes);
|
|
buffer.WriteUInt32(item->Races);
|
|
buffer.WriteUInt32(item->Deity);
|
|
|
|
//u32 SkillModValue;
|
|
//u32 SkillModMax;
|
|
//s32 SkillModType;
|
|
//s32 SkillModBonus;
|
|
buffer.WriteInt32(item->SkillModValue);
|
|
buffer.WriteUInt32(item->SkillModMax);
|
|
buffer.WriteInt32(item->SkillModType);
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//s32 BaneDMGRace;
|
|
//s32 BaneDMGBodyType;
|
|
//s32 BaneDMGRaceValue;
|
|
//s32 BaneDMGBodyTypeValue;
|
|
buffer.WriteInt32(item->BaneDmgRace);
|
|
buffer.WriteInt32(item->BaneDmgBody);
|
|
buffer.WriteInt32(item->BaneDmgRaceAmt);
|
|
buffer.WriteInt32(item->BaneDmgAmt);
|
|
|
|
//bool Magic;
|
|
buffer.WriteUInt8(item->Magic);
|
|
|
|
//s32 FoodDuration;
|
|
buffer.WriteInt32(item->CastTime_);
|
|
|
|
//s32 RequiredLevel;
|
|
buffer.WriteInt32(item->ReqLevel > 125 ? 125 : item->ReqLevel);
|
|
|
|
//s32 RecommendedLevel;
|
|
buffer.WriteInt32(item->RecLevel > 125 ? 125 : item->RecLevel);
|
|
|
|
//s32 InstrumentType;
|
|
//s32 InstrumentMod;
|
|
buffer.WriteInt32(item->BardType);
|
|
buffer.WriteInt32(item->BardValue);
|
|
|
|
//u8 Light;
|
|
buffer.WriteUInt8(item->Light);
|
|
|
|
//u8 Delay;
|
|
buffer.WriteUInt8(item->Delay);
|
|
|
|
//u8 ElementalFlag;
|
|
//u8 ElementalDamage;
|
|
buffer.WriteUInt8(item->ElemDmgType);
|
|
buffer.WriteUInt8(item->ElemDmgAmt);
|
|
|
|
//u8 Range;
|
|
buffer.WriteUInt8(item->Range);
|
|
|
|
//u32 Damage;
|
|
buffer.WriteUInt32(item->Damage);
|
|
|
|
//u32 MaterialTintIndex;
|
|
//u32 Prestige;
|
|
buffer.WriteUInt32(item->Color);
|
|
buffer.WriteUInt32(0); //unsupported atm
|
|
|
|
//u8 ItemClass;
|
|
buffer.WriteUInt8(item->ItemType);
|
|
|
|
//ArmorProperties properties;
|
|
//s32 Type;
|
|
//s32 Material;
|
|
//s32 Variation;
|
|
//s32 NewArmorId;
|
|
//s32 NewArmorType;
|
|
buffer.WriteUInt32(item->Material);
|
|
buffer.WriteUInt32(0); //unsupported atm
|
|
buffer.WriteUInt32(item->EliteMaterial);
|
|
buffer.WriteUInt32(item->HerosForgeModel);
|
|
buffer.WriteUInt32(0); //unsupported atm
|
|
|
|
//float MerchantGreedMod;
|
|
buffer.WriteFloat(item->SellRate);
|
|
|
|
//s32 DmgBonusSkill;
|
|
//s32 DmgBonusValue;
|
|
buffer.WriteInt32(item->ExtraDmgSkill);
|
|
buffer.WriteInt32(item->ExtraDmgAmt);
|
|
|
|
//s32 ScriptID;
|
|
//char CharmFile[];
|
|
buffer.WriteUInt32(item->CharmFileID);
|
|
buffer.WriteString(item->CharmFile);
|
|
|
|
//s32 AugType;
|
|
//u32 AugSkinTypeMask;
|
|
//u32 AugRestrictions;
|
|
buffer.WriteUInt32(item->AugType);
|
|
buffer.WriteInt32(-1); //unsupported atm
|
|
buffer.WriteUInt32(item->AugRestrict);
|
|
|
|
//ItemAugmentationSocket AugData[6];
|
|
for (int j = 0; j < 6; ++j) {
|
|
/*
|
|
s32 Type;
|
|
bool Visible;
|
|
bool Infusible;
|
|
*/
|
|
|
|
buffer.WriteInt32(item->AugSlotType[j]);
|
|
buffer.WriteUInt8(item->AugSlotVisible[j]);
|
|
buffer.WriteUInt8(item->AugSlotUnk2[j]); //not entirely supported atm
|
|
}
|
|
|
|
//s32 LDType;
|
|
//s32 LDTheme;
|
|
//s32 LDCost;
|
|
//s32 PointBuyBackPercent;
|
|
//s32 NeedAdventureCompleted;
|
|
buffer.WriteUInt32(item->PointType);
|
|
buffer.WriteUInt32(item->LDoNTheme);
|
|
buffer.WriteUInt32(item->LDoNPrice);
|
|
buffer.WriteUInt32(item->LDoNSellBackRate);
|
|
buffer.WriteUInt32(item->LDoNSold);
|
|
|
|
//u8 ContainerType;
|
|
//u8 Slots;
|
|
//u8 SizeCapacity;
|
|
//u8 WeightReduction;
|
|
buffer.WriteUInt8(item->BagType);
|
|
buffer.WriteUInt8(item->BagSlots);
|
|
buffer.WriteUInt8(item->BagSize);
|
|
buffer.WriteUInt8(item->BagWR);
|
|
|
|
//u8 BookType;
|
|
//u8 BookLang;
|
|
//char BookFile[];
|
|
buffer.WriteUInt8(item->Book);
|
|
buffer.WriteUInt8(item->BookType); //doesn't match the name for eqlib
|
|
buffer.WriteString(item->Filename);
|
|
|
|
//s32 Lore;
|
|
buffer.WriteInt32(item->LoreGroup);
|
|
|
|
//bool Artifact;
|
|
buffer.WriteUInt8(item->ArtifactFlag);
|
|
|
|
//s32 Favor;
|
|
buffer.WriteUInt32(item->Favor);
|
|
|
|
//bool bIsFVNoDrop;
|
|
buffer.WriteUInt8(item->FVNoDrop);
|
|
|
|
//s32 Attack;
|
|
//s32 Haste;
|
|
buffer.WriteInt32(item->Attack);
|
|
buffer.WriteInt32(item->Haste);
|
|
|
|
//s32 GuildFavor;
|
|
buffer.WriteUInt32(item->GuildFavor);
|
|
|
|
//s32 SolventItemID;
|
|
buffer.WriteUInt32(item->AugDistiller);
|
|
|
|
//s32 AnimationOverride;
|
|
buffer.WriteInt32(-1); //unsupported atm
|
|
|
|
//u32 PaletteTintIndex;
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//bool bNoPetGive;
|
|
buffer.WriteUInt8(item->NoPet);
|
|
|
|
//bool bSomeProfile;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//u32 StackSize;
|
|
buffer.WriteUInt32(item->ID == PARCEL_MONEY_ITEM_ID ? 0x7FFFFFFF : ((item->Stackable ? item->StackSize : 0)));
|
|
|
|
//bool bNoStorage;
|
|
buffer.WriteUInt8(item->NoTransfer);
|
|
|
|
//bool Expendable;
|
|
uint8 expendable = item->ExpendableArrow;
|
|
|
|
if (item->ItemType == EQ::item::ItemTypeFishingPole && item->SubType == 0) {
|
|
expendable = 1;
|
|
}
|
|
|
|
buffer.WriteUInt8(expendable);
|
|
|
|
//u8 SpellDataSkillMask[78];
|
|
for (int j = 0; j < 78; ++j) {
|
|
buffer.WriteUInt8(0); //unsure what this is exactly
|
|
}
|
|
|
|
/* SpellData:
|
|
s32 SpellId;
|
|
u8 RequiredLevel;
|
|
u8 EffectType;
|
|
s32 EffectiveCasterLevel;
|
|
s32 MaxCharges;
|
|
s32 CastTime;
|
|
s32 RecastTime;
|
|
s32 RecastType;
|
|
s32 ProcRate;
|
|
char OverrideName[];
|
|
s32 OverrideDesc;
|
|
*/
|
|
|
|
//SpellData SpellDataClicky;
|
|
buffer.WriteInt32(item->Click.Effect);
|
|
buffer.WriteUInt8(item->Click.Level2);
|
|
buffer.WriteUInt8(item->Click.Type);
|
|
buffer.WriteInt32(item->Click.Level);
|
|
buffer.WriteInt32(item->MaxCharges);
|
|
buffer.WriteInt32(item->CastTime);
|
|
buffer.WriteInt32(item->RecastDelay);
|
|
buffer.WriteInt32(item->RecastType);
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
if (strlen(item->ClickName) > 0) {
|
|
buffer.WriteString(item->ClickName);
|
|
}
|
|
else {
|
|
buffer.WriteString("");
|
|
}
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//SpellData SpellDataProc;
|
|
buffer.WriteInt32(item->Proc.Effect);
|
|
buffer.WriteUInt8(item->Proc.Level2);
|
|
buffer.WriteUInt8(item->Proc.Type);
|
|
buffer.WriteInt32(item->Proc.Level);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0); //unsupported atm; even live sets this to 0 for procs
|
|
if (strlen(item->ProcName) > 0) {
|
|
buffer.WriteString(item->ProcName);
|
|
}
|
|
else {
|
|
buffer.WriteString("");
|
|
}
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//SpellData SpellDataWorn;
|
|
buffer.WriteInt32(item->Worn.Effect);
|
|
buffer.WriteUInt8(item->Worn.Level2);
|
|
buffer.WriteUInt8(item->Worn.Type);
|
|
buffer.WriteInt32(item->Worn.Level);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
if (strlen(item->WornName) > 0) {
|
|
buffer.WriteString(item->WornName);
|
|
}
|
|
else {
|
|
buffer.WriteString("");
|
|
}
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//SpellData SpellDataFocus;
|
|
buffer.WriteInt32(item->Focus.Effect);
|
|
buffer.WriteUInt8(item->Focus.Level2);
|
|
buffer.WriteUInt8(item->Focus.Type);
|
|
buffer.WriteInt32(item->Focus.Level);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
if (strlen(item->FocusName) > 0) {
|
|
buffer.WriteString(item->FocusName);
|
|
}
|
|
else {
|
|
buffer.WriteString("");
|
|
}
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//SpellData SpellDataScroll;
|
|
buffer.WriteInt32(item->Scroll.Effect);
|
|
buffer.WriteUInt8(item->Scroll.Level2);
|
|
buffer.WriteUInt8(item->Scroll.Type);
|
|
buffer.WriteInt32(item->Scroll.Level);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
if (strlen(item->ScrollName) > 0) {
|
|
buffer.WriteString(item->ScrollName);
|
|
}
|
|
else {
|
|
buffer.WriteString("");
|
|
}
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//SpellData SpellDataFocus2; //unsupported atm
|
|
buffer.WriteInt32(-1);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteString("");
|
|
buffer.WriteInt32(0);
|
|
|
|
//SpellData SpellDataBlessing; //unsupported atm
|
|
buffer.WriteInt32(-1);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteUInt8(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteString("");
|
|
buffer.WriteInt32(0);
|
|
|
|
//s32 RightClickScriptID;
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//bool QuestItem;
|
|
buffer.WriteInt8(item->QuestItemFlag);
|
|
|
|
//s32 MaxPower;
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//s32 Purity;
|
|
buffer.WriteInt32(item->Purity);
|
|
|
|
//s32 BackstabDamage;
|
|
buffer.WriteInt32(item->BackstabDmg);
|
|
|
|
//s32 HeroicSTR;
|
|
//s32 HeroicINT;
|
|
//s32 HeroicWIS;
|
|
//s32 HeroicAGI;
|
|
//s32 HeroicDEX;
|
|
//s32 HeroicSTA;
|
|
//s32 HeroicCHA;
|
|
buffer.WriteInt32(item->HeroicStr);
|
|
buffer.WriteInt32(item->HeroicInt);
|
|
buffer.WriteInt32(item->HeroicWis);
|
|
buffer.WriteInt32(item->HeroicAgi);
|
|
buffer.WriteInt32(item->HeroicDex);
|
|
buffer.WriteInt32(item->HeroicSta);
|
|
buffer.WriteInt32(item->HeroicCha);
|
|
|
|
//s32 HealAmount;
|
|
//s32 SpellDamage;
|
|
//s32 Clairvoyance;
|
|
buffer.WriteInt32(item->HealAmt);
|
|
buffer.WriteInt32(item->SpellDmg);
|
|
buffer.WriteInt32(item->Clairvoyance);
|
|
|
|
//s32 SubClass;
|
|
buffer.WriteInt32(item->SubType);
|
|
|
|
//bool bLoginRegReqItem;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//s32 ItemLaunchScriptID;
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//bool Heirloom;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//s32 Placeable;
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//bool bPlaceableIgnoreCollisions;
|
|
buffer.WriteUInt8(0);
|
|
|
|
//s32 PlacementType;
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//s32 RealEstateDefID;
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//float PlaceableScaleRangeMin;
|
|
//float PlaceableScaleRangeMax;
|
|
buffer.WriteFloat(0.0f); //unsupported atm
|
|
buffer.WriteFloat(0.0f); //unsupported atm
|
|
|
|
//s32 RealEstateUpkeepID;
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//s32 MaxPerRealEstate;
|
|
buffer.WriteInt32(-1); //unsupported atm
|
|
|
|
//char HousepetFileName[];
|
|
buffer.WriteString(""); //unsupported atm
|
|
|
|
//bool bInteractiveObject;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//s32 TrophyBenefitID;
|
|
buffer.WriteInt32(-1); //unsupported atm
|
|
|
|
//bool bDisablePlacementRotation;
|
|
//bool bDisableFreePlacement;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//s32 NpcRespawnInterval;
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//float PlaceableDefScale;
|
|
//float PlaceableDefHeading;
|
|
//float PlaceableDefPitch;
|
|
//float PlaceableDefRoll;
|
|
buffer.WriteFloat(0.0f);
|
|
buffer.WriteFloat(0.0f);
|
|
buffer.WriteFloat(0.0f);
|
|
buffer.WriteFloat(0.0f);
|
|
|
|
//u8 SocketSubClassCount;
|
|
//s32 SocketSubClass[SocketSubClassCount];
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//bool Collectible;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//bool NoDestroy;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//bool bNoNPC;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//bool NoZone;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//s32 MakerId;
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
|
|
//bool NoGround;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//bool bNoLoot;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//bool MarketPlace;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//bool bFreeSlot;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//bool bAutoUse;
|
|
buffer.WriteUInt8(0); //unsupported atm
|
|
|
|
//s32 Unknown0x0e4;
|
|
buffer.WriteInt32(-1); //unsupported atm
|
|
|
|
//s32 MinLuck;
|
|
//s32 MaxLuck;
|
|
buffer.WriteUInt32(0); //unsupported atm
|
|
buffer.WriteUInt32(0); //unsupported atm
|
|
|
|
//s32 LoreEquipped;
|
|
buffer.WriteUInt32(0); //unsupported atm
|
|
}
|
|
|
|
void SerializeItem(SerializeBuffer& buffer, const EQ::ItemInstance* inst, int16 slot_id_in, uint8 depth, ItemPacketType packet_type) {
|
|
const EQ::ItemData* item = inst->GetUnscaledItem();
|
|
|
|
//char ItemGUID[];
|
|
auto item_guid = fmt::format("{:016}", inst->GetSerialNumber());
|
|
buffer.WriteString(item_guid);
|
|
|
|
//u32 StackCount;
|
|
auto stacksize =
|
|
item->ID == PARCEL_MONEY_ITEM_ID ? inst->GetPrice() : (inst->IsStackable() ? ((inst->GetCharges() > 1000)
|
|
? 0xFFFFFFFF : inst->GetCharges()) : 1);
|
|
buffer.WriteUInt32(stacksize);
|
|
|
|
structs::InventorySlot_Struct slot_id{};
|
|
switch (packet_type) {
|
|
case ItemPacketLoot:
|
|
slot_id = ServerToLaurionCorpseSlot(slot_id_in);
|
|
break;
|
|
default:
|
|
slot_id = ServerToLaurionSlot(slot_id_in);
|
|
break;
|
|
}
|
|
|
|
//u32 slot_type;
|
|
buffer.WriteUInt32(inst->GetMerchantSlot() ? invtype::typeMerchant : slot_id.Type);
|
|
//s16 main_slot;
|
|
//s16 sub_slot;
|
|
//s16 aug_slot;
|
|
buffer.WriteInt16(inst->GetMerchantSlot() ? inst->GetMerchantSlot() : slot_id.Slot);
|
|
buffer.WriteInt16(inst->GetMerchantSlot() ? 0xffff : slot_id.SubIndex);
|
|
buffer.WriteInt16(inst->GetMerchantSlot() ? 0xffff : slot_id.AugIndex);
|
|
|
|
//u64 price;
|
|
buffer.WriteUInt64(inst->GetPrice());
|
|
|
|
//u32 MerchantQuantity;
|
|
buffer.WriteUInt32(inst->GetMerchantSlot() ? inst->GetMerchantCount() : 1);
|
|
|
|
//u32 ScriptIndex;
|
|
buffer.WriteUInt32(inst->IsScaling() ? (inst->GetExp() / 100) : 0);
|
|
|
|
//u64 MerchantSlot;
|
|
buffer.WriteUInt64(inst->GetMerchantSlot() ? inst->GetMerchantSlot() : inst->GetSerialNumber());
|
|
|
|
//u32 LastCastTime;
|
|
buffer.WriteUInt32(inst->GetRecastTimestamp());
|
|
|
|
//s32 Charges;
|
|
auto charges = (inst->IsStackable() ? (item->MaxCharges ? 1 : 0) : ((inst->GetCharges() > 254)
|
|
? -1
|
|
: inst->GetCharges()));
|
|
|
|
buffer.WriteInt32(charges);
|
|
|
|
//s32 NoDropFlag;
|
|
buffer.WriteInt32(inst->IsAttuned() ? 1 : 0);
|
|
|
|
//s32 Power;
|
|
buffer.WriteInt32(0);
|
|
|
|
//s32 AugFlag;
|
|
buffer.WriteInt32(0);
|
|
|
|
//bool bConvertable;
|
|
buffer.WriteInt8(0);
|
|
|
|
//u32 ConvertItemNameLength;
|
|
buffer.WriteInt32(0);
|
|
|
|
//char ConvertItemName[ConvertItemNameLength];
|
|
|
|
//u32 ConvertItemID;
|
|
buffer.WriteInt32(0);
|
|
|
|
//u32 Open;
|
|
buffer.WriteInt32(0);
|
|
|
|
//bool EvolvingItem;
|
|
buffer.WriteInt8(item->EvolvingItem);
|
|
|
|
//EvoData evoData;
|
|
if (item->EvolvingItem > 0) {
|
|
//s32 GroupId;
|
|
buffer.WriteInt32(0);
|
|
|
|
//s32 EvolvingCurrentLevel;
|
|
buffer.WriteInt32(item->EvolvingLevel);
|
|
|
|
//double EvolvingExpPct;
|
|
buffer.WriteDouble(0.0);
|
|
|
|
//s32 EvolvingMaxLevel;
|
|
buffer.WriteInt32(item->EvolvingMax);
|
|
|
|
//s32 LastEquipped;
|
|
buffer.WriteInt32(0);
|
|
}
|
|
|
|
uint32 ornamentation_icon = (inst->GetOrnamentationIcon() ? inst->GetOrnamentationIcon() : 0);
|
|
uint32 hero_model = 0;
|
|
|
|
//s32 ActorTag1;
|
|
//s32 ActorTag2;
|
|
if (inst->GetOrnamentationIDFile()) {
|
|
hero_model = inst->GetOrnamentHeroModel(EQ::InventoryProfile::CalcMaterialFromSlot(slot_id_in));
|
|
|
|
buffer.WriteInt32(inst->GetOrnamentationIDFile());
|
|
buffer.WriteInt32(inst->GetOrnamentationIDFile());
|
|
}
|
|
else {
|
|
buffer.WriteInt32(0);
|
|
buffer.WriteInt32(0);
|
|
}
|
|
|
|
//s32 OrnamentationIcon;
|
|
//s32 ArmorType;
|
|
//s32 NewArmorID;
|
|
//u32 Tint;
|
|
buffer.WriteInt32(ornamentation_icon);
|
|
buffer.WriteInt32(-1);
|
|
buffer.WriteInt32(hero_model);
|
|
buffer.WriteInt32(0);
|
|
|
|
//bool bCopied;
|
|
buffer.WriteUInt8(0);
|
|
|
|
//s32 RealEstateID;
|
|
buffer.WriteInt32(-1);
|
|
//s32 RespawnTime;
|
|
buffer.WriteInt32(0);
|
|
|
|
//ItemDefinition Item;
|
|
SerializeItemDefinition(buffer, item);
|
|
|
|
//u32 RealEstateArrayCount;
|
|
buffer.WriteInt32(0);
|
|
//s32 RealEstateArray[RealEstateArrayCount];
|
|
|
|
//bool bRealEstateItemPlaceable;
|
|
buffer.WriteInt8(0);
|
|
|
|
//u32 SubContentSize;
|
|
uint32 subitem_count = 0;
|
|
|
|
int16 SubSlotNumber = EQ::invbag::SLOT_INVALID;
|
|
|
|
if (slot_id_in <= EQ::invslot::GENERAL_END && slot_id_in >= EQ::invslot::GENERAL_BEGIN)
|
|
SubSlotNumber = EQ::invbag::GENERAL_BAGS_BEGIN + ((slot_id_in - EQ::invslot::GENERAL_BEGIN) * EQ::invbag::SLOT_COUNT);
|
|
else if (slot_id_in == EQ::invslot::slotCursor)
|
|
SubSlotNumber = EQ::invbag::CURSOR_BAG_BEGIN;
|
|
else if (slot_id_in <= EQ::invslot::BANK_END && slot_id_in >= EQ::invslot::BANK_BEGIN)
|
|
SubSlotNumber = EQ::invbag::BANK_BAGS_BEGIN + ((slot_id_in - EQ::invslot::BANK_BEGIN) * EQ::invbag::SLOT_COUNT);
|
|
else if (slot_id_in <= EQ::invslot::SHARED_BANK_END && slot_id_in >= EQ::invslot::SHARED_BANK_BEGIN)
|
|
SubSlotNumber = EQ::invbag::SHARED_BANK_BAGS_BEGIN + ((slot_id_in - EQ::invslot::SHARED_BANK_BEGIN) * EQ::invbag::SLOT_COUNT);
|
|
else
|
|
SubSlotNumber = slot_id_in; // not sure if this is the best way to handle this..leaving for now
|
|
|
|
if (SubSlotNumber != EQ::invbag::SLOT_INVALID) {
|
|
for (uint32 index = EQ::invbag::SLOT_BEGIN; index <= EQ::invbag::SLOT_END; ++index) {
|
|
EQ::ItemInstance* sub = inst->GetItem(index);
|
|
if (!sub)
|
|
continue;
|
|
|
|
++subitem_count;
|
|
}
|
|
|
|
buffer.WriteUInt32(subitem_count);
|
|
|
|
for (uint32 index = EQ::invbag::SLOT_BEGIN; index <= EQ::invbag::SLOT_END; ++index) {
|
|
EQ::ItemInstance* sub = inst->GetItem(index);
|
|
if (!sub)
|
|
continue;
|
|
|
|
buffer.WriteUInt32(index);
|
|
|
|
SerializeItem(buffer, sub, SubSlotNumber, (depth + 1), packet_type);
|
|
}
|
|
}
|
|
|
|
//bool bCollected;
|
|
buffer.WriteInt8(0); //unsupported atm
|
|
//u64 DontKnow;
|
|
buffer.WriteUInt64(0); //unsupported atm
|
|
//s32 Luck;
|
|
buffer.WriteInt32(0); //unsupported atm
|
|
}
|
|
|
|
static inline structs::InventorySlot_Struct ServerToLaurionSlot(uint32 server_slot)
|
|
{
|
|
structs::InventorySlot_Struct LaurionSlot;
|
|
LaurionSlot.Type = invtype::TYPE_INVALID;
|
|
LaurionSlot.Slot = invslot::SLOT_INVALID;
|
|
LaurionSlot.SubIndex = invbag::SLOT_INVALID;
|
|
LaurionSlot.AugIndex = invaug::SOCKET_INVALID;
|
|
|
|
uint32 TempSlot = EQ::invslot::SLOT_INVALID;
|
|
|
|
if (server_slot < EQ::invtype::POSSESSIONS_SIZE) {
|
|
LaurionSlot.Type = invtype::typePossessions;
|
|
LaurionSlot.Slot = server_slot;
|
|
}
|
|
|
|
else if (server_slot <= EQ::invbag::CURSOR_BAG_END && server_slot >= EQ::invbag::GENERAL_BAGS_BEGIN) {
|
|
TempSlot = server_slot - EQ::invbag::GENERAL_BAGS_BEGIN;
|
|
|
|
LaurionSlot.Type = invtype::typePossessions;
|
|
LaurionSlot.Slot = invslot::GENERAL_BEGIN + (TempSlot / EQ::invbag::SLOT_COUNT);
|
|
LaurionSlot.SubIndex = TempSlot - ((LaurionSlot.Slot - invslot::GENERAL_BEGIN) * EQ::invbag::SLOT_COUNT);
|
|
}
|
|
|
|
else if (server_slot <= EQ::invslot::TRIBUTE_END && server_slot >= EQ::invslot::TRIBUTE_BEGIN) {
|
|
LaurionSlot.Type = invtype::typeTribute;
|
|
LaurionSlot.Slot = server_slot - EQ::invslot::TRIBUTE_BEGIN;
|
|
}
|
|
|
|
else if (server_slot <= EQ::invslot::GUILD_TRIBUTE_END && server_slot >= EQ::invslot::GUILD_TRIBUTE_BEGIN) {
|
|
LaurionSlot.Type = invtype::typeGuildTribute;
|
|
LaurionSlot.Slot = server_slot - EQ::invslot::GUILD_TRIBUTE_BEGIN;
|
|
}
|
|
|
|
else if (server_slot == EQ::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE) {
|
|
LaurionSlot.Type = invtype::typeWorld;
|
|
}
|
|
|
|
else if (server_slot <= EQ::invslot::BANK_END && server_slot >= EQ::invslot::BANK_BEGIN) {
|
|
LaurionSlot.Type = invtype::typeBank;
|
|
LaurionSlot.Slot = server_slot - EQ::invslot::BANK_BEGIN;
|
|
}
|
|
|
|
else if (server_slot <= EQ::invbag::BANK_BAGS_END && server_slot >= EQ::invbag::BANK_BAGS_BEGIN) {
|
|
TempSlot = server_slot - EQ::invbag::BANK_BAGS_BEGIN;
|
|
|
|
LaurionSlot.Type = invtype::typeBank;
|
|
LaurionSlot.Slot = TempSlot / EQ::invbag::SLOT_COUNT;
|
|
LaurionSlot.SubIndex = TempSlot - (LaurionSlot.Slot * EQ::invbag::SLOT_COUNT);
|
|
}
|
|
|
|
else if (server_slot <= EQ::invslot::SHARED_BANK_END && server_slot >= EQ::invslot::SHARED_BANK_BEGIN) {
|
|
LaurionSlot.Type = invtype::typeSharedBank;
|
|
LaurionSlot.Slot = server_slot - EQ::invslot::SHARED_BANK_BEGIN;
|
|
}
|
|
|
|
else if (server_slot <= EQ::invbag::SHARED_BANK_BAGS_END && server_slot >= EQ::invbag::SHARED_BANK_BAGS_BEGIN) {
|
|
TempSlot = server_slot - EQ::invbag::SHARED_BANK_BAGS_BEGIN;
|
|
|
|
LaurionSlot.Type = invtype::typeSharedBank;
|
|
LaurionSlot.Slot = TempSlot / EQ::invbag::SLOT_COUNT;
|
|
LaurionSlot.SubIndex = TempSlot - (LaurionSlot.Slot * EQ::invbag::SLOT_COUNT);
|
|
}
|
|
|
|
else if (server_slot <= EQ::invslot::TRADE_END && server_slot >= EQ::invslot::TRADE_BEGIN) {
|
|
LaurionSlot.Type = invtype::typeTrade;
|
|
LaurionSlot.Slot = server_slot - EQ::invslot::TRADE_BEGIN;
|
|
}
|
|
|
|
else if (server_slot <= EQ::invbag::TRADE_BAGS_END && server_slot >= EQ::invbag::TRADE_BAGS_BEGIN) {
|
|
TempSlot = server_slot - EQ::invbag::TRADE_BAGS_BEGIN;
|
|
|
|
LaurionSlot.Type = invtype::typeTrade;
|
|
LaurionSlot.Slot = TempSlot / EQ::invbag::SLOT_COUNT;
|
|
LaurionSlot.SubIndex = TempSlot - (LaurionSlot.Slot * EQ::invbag::SLOT_COUNT);
|
|
}
|
|
|
|
else if (server_slot <= EQ::invslot::WORLD_END && server_slot >= EQ::invslot::WORLD_BEGIN) {
|
|
LaurionSlot.Type = invtype::typeWorld;
|
|
LaurionSlot.Slot = server_slot - EQ::invslot::WORLD_BEGIN;
|
|
}
|
|
|
|
Log(Logs::Detail, Logs::Netcode, "Convert Server Slot %i to Laurion Slot [%i, %i, %i, %i]",
|
|
server_slot, LaurionSlot.Type, LaurionSlot.Slot, LaurionSlot.SubIndex, LaurionSlot.AugIndex);
|
|
|
|
return LaurionSlot;
|
|
}
|
|
|
|
static inline structs::InventorySlot_Struct ServerToLaurionCorpseSlot(uint32 server_corpse_slot)
|
|
{
|
|
structs::InventorySlot_Struct LaurionSlot;
|
|
LaurionSlot.Type = invtype::TYPE_INVALID;
|
|
LaurionSlot.Slot = ServerToLaurionCorpseMainSlot(server_corpse_slot);
|
|
LaurionSlot.SubIndex = invbag::SLOT_INVALID;
|
|
LaurionSlot.AugIndex = invaug::SOCKET_INVALID;
|
|
|
|
if (LaurionSlot.Slot != invslot::SLOT_INVALID)
|
|
LaurionSlot.Type = invtype::typeCorpse;
|
|
|
|
Log(Logs::Detail, Logs::Netcode, "Convert Server Corpse Slot %i to Laurion Corpse Slot [%i, %i, %i, %i]",
|
|
server_corpse_slot, LaurionSlot.Type, LaurionSlot.Slot, LaurionSlot.SubIndex, LaurionSlot.AugIndex);
|
|
|
|
return LaurionSlot;
|
|
}
|
|
|
|
static inline uint32 ServerToLaurionCorpseMainSlot(uint32 server_corpse_slot)
|
|
{
|
|
uint32 LaurionSlot = invslot::SLOT_INVALID;
|
|
|
|
if (server_corpse_slot <= EQ::invslot::CORPSE_END && server_corpse_slot >= EQ::invslot::CORPSE_BEGIN) {
|
|
LaurionSlot = server_corpse_slot;
|
|
}
|
|
|
|
LogNetcode("Convert Server Corpse Slot [{}] to Laurion Corpse Main Slot [{}]", server_corpse_slot, LaurionSlot);
|
|
|
|
return LaurionSlot;
|
|
}
|
|
|
|
static inline structs::TypelessInventorySlot_Struct ServerToLaurionTypelessSlot(uint32 server_slot, int16 server_type)
|
|
{
|
|
structs::TypelessInventorySlot_Struct LaurionSlot;
|
|
LaurionSlot.Slot = invslot::SLOT_INVALID;
|
|
LaurionSlot.SubIndex = invbag::SLOT_INVALID;
|
|
LaurionSlot.AugIndex = invaug::SOCKET_INVALID;
|
|
|
|
uint32 TempSlot = EQ::invslot::SLOT_INVALID;
|
|
|
|
if (server_type == EQ::invtype::typePossessions) {
|
|
if (server_slot < EQ::invtype::POSSESSIONS_SIZE) {
|
|
LaurionSlot.Slot = server_slot;
|
|
}
|
|
|
|
else if (server_slot <= EQ::invbag::CURSOR_BAG_END && server_slot >= EQ::invbag::GENERAL_BAGS_BEGIN) {
|
|
TempSlot = server_slot - EQ::invbag::GENERAL_BAGS_BEGIN;
|
|
|
|
LaurionSlot.Slot = invslot::GENERAL_BEGIN + (TempSlot / EQ::invbag::SLOT_COUNT);
|
|
LaurionSlot.SubIndex = TempSlot - ((LaurionSlot.Slot - invslot::GENERAL_BEGIN) * EQ::invbag::SLOT_COUNT);
|
|
}
|
|
}
|
|
|
|
Log(Logs::Detail, Logs::Netcode, "Convert Server Slot %i to Laurion Typeless Slot [%i, %i, %i] (implied type: %i)",
|
|
server_slot, LaurionSlot.Slot, LaurionSlot.SubIndex, LaurionSlot.AugIndex, server_type);
|
|
|
|
return LaurionSlot;
|
|
}
|
|
|
|
static inline uint32 LaurionToServerSlot(structs::InventorySlot_Struct laurion_slot)
|
|
{
|
|
if (laurion_slot.AugIndex < invaug::SOCKET_INVALID || laurion_slot.AugIndex >= invaug::SOCKET_COUNT) {
|
|
Log(Logs::Detail, Logs::Netcode, "Convert Laurion Slot [%i, %i, %i, %i] to Server Slot %i",
|
|
laurion_slot.Type, laurion_slot.Slot, laurion_slot.SubIndex, laurion_slot.AugIndex, EQ::invslot::SLOT_INVALID);
|
|
|
|
return EQ::invslot::SLOT_INVALID;
|
|
}
|
|
|
|
uint32 server_slot = EQ::invslot::SLOT_INVALID;
|
|
uint32 temp_slot = invslot::SLOT_INVALID;
|
|
|
|
switch (laurion_slot.Type) {
|
|
case invtype::typePossessions: {
|
|
if (laurion_slot.Slot >= invslot::POSSESSIONS_BEGIN && laurion_slot.Slot <= invslot::POSSESSIONS_END) {
|
|
if (laurion_slot.SubIndex == invbag::SLOT_INVALID) {
|
|
server_slot = laurion_slot.Slot;
|
|
}
|
|
|
|
else if (laurion_slot.SubIndex >= invbag::SLOT_BEGIN && laurion_slot.SubIndex <= invbag::SLOT_END) {
|
|
if (laurion_slot.Slot < invslot::GENERAL_BEGIN)
|
|
return EQ::invslot::SLOT_INVALID;
|
|
|
|
temp_slot = (laurion_slot.Slot - invslot::GENERAL_BEGIN) * invbag::SLOT_COUNT;
|
|
server_slot = EQ::invbag::GENERAL_BAGS_BEGIN + temp_slot + laurion_slot.SubIndex;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeBank: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::BANK_SIZE) {
|
|
if (laurion_slot.SubIndex == invbag::SLOT_INVALID) {
|
|
server_slot = EQ::invslot::BANK_BEGIN + laurion_slot.Slot;
|
|
}
|
|
|
|
else if (laurion_slot.SubIndex >= invbag::SLOT_BEGIN && laurion_slot.SubIndex <= invbag::SLOT_END) {
|
|
temp_slot = laurion_slot.Slot * invbag::SLOT_COUNT;
|
|
server_slot = EQ::invbag::BANK_BAGS_BEGIN + temp_slot + laurion_slot.SubIndex;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeSharedBank: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::SHARED_BANK_SIZE) {
|
|
if (laurion_slot.SubIndex == invbag::SLOT_INVALID) {
|
|
server_slot = EQ::invslot::SHARED_BANK_BEGIN + laurion_slot.Slot;
|
|
}
|
|
|
|
else if (laurion_slot.SubIndex >= invbag::SLOT_BEGIN && laurion_slot.SubIndex <= invbag::SLOT_END) {
|
|
temp_slot = laurion_slot.Slot * invbag::SLOT_COUNT;
|
|
server_slot = EQ::invbag::SHARED_BANK_BAGS_BEGIN + temp_slot + laurion_slot.SubIndex;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeTrade: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::TRADE_SIZE) {
|
|
if (laurion_slot.SubIndex == invbag::SLOT_INVALID) {
|
|
server_slot = EQ::invslot::TRADE_BEGIN + laurion_slot.Slot;
|
|
}
|
|
|
|
else if (laurion_slot.SubIndex >= invbag::SLOT_BEGIN && laurion_slot.SubIndex <= invbag::SLOT_END) {
|
|
temp_slot = laurion_slot.Slot * invbag::SLOT_COUNT;
|
|
server_slot = EQ::invbag::TRADE_BAGS_BEGIN + temp_slot + laurion_slot.SubIndex;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeWorld: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::WORLD_SIZE) {
|
|
server_slot = EQ::invslot::WORLD_BEGIN + laurion_slot.Slot;
|
|
}
|
|
|
|
else if (laurion_slot.Slot == invslot::SLOT_INVALID) {
|
|
server_slot = EQ::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeLimbo: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::LIMBO_SIZE) {
|
|
server_slot = EQ::invslot::slotCursor;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeTribute: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::TRIBUTE_SIZE) {
|
|
server_slot = EQ::invslot::TRIBUTE_BEGIN + laurion_slot.Slot;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeGuildTribute: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::GUILD_TRIBUTE_SIZE) {
|
|
server_slot = EQ::invslot::GUILD_TRIBUTE_BEGIN + laurion_slot.Slot;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeCorpse: {
|
|
if (laurion_slot.Slot >= invslot::CORPSE_BEGIN && laurion_slot.Slot <= invslot::CORPSE_END) {
|
|
server_slot = laurion_slot.Slot;
|
|
}
|
|
|
|
break;
|
|
}
|
|
default: {
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
Log(Logs::Detail, Logs::Netcode, "Convert Laurion Slot [%i, %i, %i, %i] to Server Slot %i",
|
|
laurion_slot.Type, laurion_slot.Slot, laurion_slot.SubIndex, laurion_slot.AugIndex, server_slot);
|
|
|
|
return server_slot;
|
|
}
|
|
|
|
static inline uint32 LaurionToServerCorpseSlot(structs::InventorySlot_Struct laurion_corpse_slot)
|
|
{
|
|
uint32 ServerSlot = EQ::invslot::SLOT_INVALID;
|
|
|
|
if (laurion_corpse_slot.Type != invtype::typeCorpse || laurion_corpse_slot.SubIndex != invbag::SLOT_INVALID || laurion_corpse_slot.AugIndex != invaug::SOCKET_INVALID) {
|
|
ServerSlot = EQ::invslot::SLOT_INVALID;
|
|
}
|
|
|
|
else {
|
|
ServerSlot = LaurionToServerCorpseMainSlot(laurion_corpse_slot.Slot);
|
|
}
|
|
|
|
Log(Logs::Detail, Logs::Netcode, "Convert Laurion Slot [%i, %i, %i, %i] to Server Slot %i",
|
|
laurion_corpse_slot.Type, laurion_corpse_slot.Slot, laurion_corpse_slot.SubIndex, laurion_corpse_slot.AugIndex, ServerSlot);
|
|
|
|
return ServerSlot;
|
|
}
|
|
|
|
static inline uint32 LaurionToServerCorpseMainSlot(uint32 laurion_corpse_slot)
|
|
{
|
|
uint32 ServerSlot = EQ::invslot::SLOT_INVALID;
|
|
|
|
if (laurion_corpse_slot <= invslot::CORPSE_END && laurion_corpse_slot >= invslot::CORPSE_BEGIN) {
|
|
ServerSlot = laurion_corpse_slot;
|
|
}
|
|
|
|
LogNetcode("Convert Laurion Corpse Main Slot [{}] to Server Corpse Slot [{}]", laurion_corpse_slot, ServerSlot);
|
|
|
|
return ServerSlot;
|
|
}
|
|
|
|
static inline uint32 LaurionToServerTypelessSlot(structs::TypelessInventorySlot_Struct laurion_slot, int16 laurion_type)
|
|
{
|
|
if (laurion_slot.AugIndex < invaug::SOCKET_INVALID || laurion_slot.AugIndex >= invaug::SOCKET_COUNT) {
|
|
Log(Logs::Detail, Logs::Netcode, "Convert Laurion Typeless Slot [%i, %i, %i] (implied type: %i) to Server Slot %i",
|
|
laurion_slot.Slot, laurion_slot.SubIndex, laurion_slot.AugIndex, laurion_type, EQ::invslot::SLOT_INVALID);
|
|
|
|
return EQ::invslot::SLOT_INVALID;
|
|
}
|
|
|
|
uint32 ServerSlot = EQ::invslot::SLOT_INVALID;
|
|
uint32 TempSlot = invslot::SLOT_INVALID;
|
|
|
|
switch (laurion_type) {
|
|
case invtype::typePossessions: {
|
|
if (laurion_slot.Slot >= invslot::POSSESSIONS_BEGIN && laurion_slot.Slot <= invslot::POSSESSIONS_END) {
|
|
if (laurion_slot.SubIndex == invbag::SLOT_INVALID) {
|
|
ServerSlot = laurion_slot.Slot;
|
|
}
|
|
|
|
else if (laurion_slot.SubIndex >= invbag::SLOT_BEGIN && laurion_slot.SubIndex <= invbag::SLOT_END) {
|
|
if (laurion_slot.Slot < invslot::GENERAL_BEGIN)
|
|
return EQ::invslot::SLOT_INVALID;
|
|
|
|
TempSlot = (laurion_slot.Slot - invslot::GENERAL_BEGIN) * invbag::SLOT_COUNT;
|
|
ServerSlot = EQ::invbag::GENERAL_BAGS_BEGIN + TempSlot + laurion_slot.SubIndex;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeBank: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::BANK_SIZE) {
|
|
if (laurion_slot.SubIndex == invbag::SLOT_INVALID) {
|
|
ServerSlot = EQ::invslot::BANK_BEGIN + laurion_slot.Slot;
|
|
}
|
|
|
|
else if (laurion_slot.SubIndex >= invbag::SLOT_BEGIN && laurion_slot.SubIndex <= invbag::SLOT_END) {
|
|
TempSlot = laurion_slot.Slot * invbag::SLOT_COUNT;
|
|
ServerSlot = EQ::invbag::BANK_BAGS_BEGIN + TempSlot + laurion_slot.SubIndex;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeSharedBank: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::SHARED_BANK_SIZE) {
|
|
if (laurion_slot.SubIndex == invbag::SLOT_INVALID) {
|
|
ServerSlot = EQ::invslot::SHARED_BANK_BEGIN + laurion_slot.Slot;
|
|
}
|
|
|
|
else if (laurion_slot.SubIndex >= invbag::SLOT_BEGIN && laurion_slot.SubIndex <= invbag::SLOT_END) {
|
|
TempSlot = laurion_slot.Slot * invbag::SLOT_COUNT;
|
|
ServerSlot = EQ::invbag::SHARED_BANK_BAGS_BEGIN + TempSlot + laurion_slot.SubIndex;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeTrade: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::TRADE_SIZE) {
|
|
if (laurion_slot.SubIndex == invbag::SLOT_INVALID) {
|
|
ServerSlot = EQ::invslot::TRADE_BEGIN + laurion_slot.Slot;
|
|
}
|
|
|
|
else if (laurion_slot.SubIndex >= invbag::SLOT_BEGIN && laurion_slot.SubIndex <= invbag::SLOT_END) {
|
|
TempSlot = laurion_slot.Slot * invbag::SLOT_COUNT;
|
|
ServerSlot = EQ::invbag::TRADE_BAGS_BEGIN + TempSlot + laurion_slot.SubIndex;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeWorld: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::WORLD_SIZE) {
|
|
ServerSlot = EQ::invslot::WORLD_BEGIN + laurion_slot.Slot;
|
|
}
|
|
|
|
else if (laurion_slot.Slot == invslot::SLOT_INVALID) {
|
|
ServerSlot = EQ::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeLimbo: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::LIMBO_SIZE) {
|
|
ServerSlot = EQ::invslot::slotCursor;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeTribute: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::TRIBUTE_SIZE) {
|
|
ServerSlot = EQ::invslot::TRIBUTE_BEGIN + laurion_slot.Slot;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeGuildTribute: {
|
|
if (laurion_slot.Slot >= invslot::SLOT_BEGIN && laurion_slot.Slot < invtype::GUILD_TRIBUTE_SIZE) {
|
|
ServerSlot = EQ::invslot::GUILD_TRIBUTE_BEGIN + laurion_slot.Slot;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case invtype::typeCorpse: {
|
|
if (laurion_slot.Slot >= invslot::CORPSE_BEGIN && laurion_slot.Slot <= invslot::CORPSE_END) {
|
|
ServerSlot = laurion_slot.Slot;
|
|
}
|
|
|
|
break;
|
|
}
|
|
default: {
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
Log(Logs::Detail, Logs::Netcode, "Convert Laurion Typeless Slot [%i, %i, %i] (implied type: %i) to Server Slot %i",
|
|
laurion_slot.Slot, laurion_slot.SubIndex, laurion_slot.AugIndex, laurion_type, ServerSlot);
|
|
|
|
return ServerSlot;
|
|
}
|
|
} /*Laurion*/
|