mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-16 17:41:29 +00:00
2294 lines
53 KiB
C++
2294 lines
53 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 "larion.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 "larion_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 Larion
|
|
{
|
|
static const char* name = "Larion";
|
|
static OpcodeManager* opcodes = nullptr;
|
|
static Strategy struct_strategy;
|
|
|
|
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 "larion_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::Larion;
|
|
}
|
|
|
|
#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] = 0;
|
|
|
|
//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)
|
|
// {
|
|
// //larion 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);
|
|
}
|
|
|
|
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;
|
|
|
|
auto outapp = new EQApplicationPacket(OP_CharInventory, 4);
|
|
dest->FastQueuePacket(&outapp, ack_req);
|
|
|
|
delete in;
|
|
}
|
|
|
|
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_SpawnAppearance)
|
|
{
|
|
EQApplicationPacket* in = *p;
|
|
*p = nullptr;
|
|
delete in;
|
|
}
|
|
|
|
ENCODE(OP_SpawnDoor)
|
|
{
|
|
EQApplicationPacket* in = *p;
|
|
*p = nullptr;
|
|
delete in;
|
|
}
|
|
|
|
ENCODE(OP_GroundSpawn)
|
|
{
|
|
EQApplicationPacket* in = *p;
|
|
*p = nullptr;
|
|
delete in;
|
|
}
|
|
|
|
// DECODE methods
|
|
|
|
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();
|
|
}
|
|
|
|
} /*Larion*/
|