From 7fed01ddeae172b0e1e82f47ba682860fc9f3c6d Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 27 Sep 2014 19:57:45 -0700 Subject: [PATCH 001/114] initial rewrite of loot code --- zone/loottables.cpp | 194 ++++++++++++++++++++++---------------------- zone/mob.h | 2 +- zone/npc.h | 2 +- zone/perl_npc.cpp | 4 +- 4 files changed, 103 insertions(+), 99 deletions(-) diff --git a/zone/loottables.cpp b/zone/loottables.cpp index b2ebec5ff..1a3abe513 100644 --- a/zone/loottables.cpp +++ b/zone/loottables.cpp @@ -23,13 +23,11 @@ #include "masterentity.h" #include "zonedb.h" #include "../common/misc_functions.h" -#ifdef _WINDOWS -#define snprintf _snprintf -#endif +#include "../common/data_verification.h" // Queries the loottable: adds item & coin to the npc void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* itemlist, uint32* copper, uint32* silver, uint32* gold, uint32* plat) { - const LootTable_Struct* lts = 0; + const LootTable_Struct* lts = nullptr; *copper = 0; *silver = 0; *gold = 0; @@ -39,44 +37,37 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite if (!lts) return; - // do coin - if (lts->mincash > lts->maxcash) { - std::cerr << "Error in loottable #" << loottable_id << ": mincash > maxcash" << std::endl; + uint32 min_cash = lts->mincash; + uint32 max_cash = lts->maxcash; + if(min_cash > max_cash) { + uint32 t = min_cash; + min_cash = max_cash; + max_cash = t; } - else if (lts->maxcash != 0) { - uint32 cash = 0; - if (lts->mincash == lts->maxcash) - cash = lts->mincash; - else - cash = MakeRandomInt(lts->mincash, lts->maxcash); - if (cash != 0) { - if (lts->avgcoin != 0) { - //this is some crazy ass stuff... and makes very little sense... dont use it, k? - uint32 mincoin = (uint32) (lts->avgcoin * 0.75 + 1); - uint32 maxcoin = (uint32) (lts->avgcoin * 1.25 + 1); - *copper = MakeRandomInt(mincoin, maxcoin); - *silver = MakeRandomInt(mincoin, maxcoin); - *gold = MakeRandomInt(mincoin, maxcoin); - if(*copper > cash) { *copper = cash; } - cash -= *copper; - if(*silver>(cash/10)) { *silver = (cash/10); } - cash -= *silver*10; - if(*gold > (cash/100)) { *gold = (cash/100); } - cash -= *gold*100; - } - if (cash < 0) { - cash = 0; - } - *plat = cash / 1000; - cash -= *plat * 1000; - uint32 gold2 = cash / 100; - cash -= gold2 * 100; - uint32 silver2 = cash / 10; - cash -= silver2 * 10; - *gold += gold2; - *silver += silver2; - *copper += cash; + + uint32 cash = 0; + if(max_cash > 0 && EQEmu::ValueWithin(lts->avgcoin, min_cash, max_cash)) { + int avg_cash_roll = MakeRandomInt(1, 100); + if(avg_cash_roll > 50) { + cash = MakeRandomInt(lts->avgcoin, max_cash); + } else { + cash = MakeRandomInt(min_cash, lts->avgcoin); } + } else { + cash = MakeRandomInt(min_cash, max_cash); + } + + if(cash != 0) { + *plat = cash / 1000; + cash -= *plat * 1000; + + *gold = cash / 100; + cash -= *gold * 100; + + *silver = cash / 10; + cash -= *silver * 10; + + *copper = cash; } // Do items @@ -91,11 +82,11 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite float drop_chance = 0.0f; if(ltchance > 0.0 && ltchance < 100.0) { - drop_chance = MakeRandomFloat(0.0, 100.0); + drop_chance = (float)MakeRandomFloat(0.0, 100.0); } - if (ltchance != 0.0 && (ltchance == 100.0 || drop_chance < ltchance)) { - AddLootDropToNPC(npc,lts->Entries[i].lootdrop_id, itemlist, droplimit, mindrop); + if (ltchance != 0.0 && (ltchance == 100.0 || drop_chance <= ltchance)) { + AddLootDropToNPC(npc, lts->Entries[i].lootdrop_id, itemlist, droplimit, mindrop); } } } @@ -108,66 +99,79 @@ void ZoneDatabase::AddLootDropToNPC(NPC* npc,uint32 lootdrop_id, ItemList* iteml if (!lds) { return; } - if(lds->NumEntries == 0) //nothing possible to add + + if(lds->NumEntries == 0) return; - // Too long a list needs to be limited. - if(lds->NumEntries > 99 && droplimit < 1) - droplimit = lds->NumEntries/100; - - uint8 limit = 0; - // Start at a random point in itemlist. - uint32 item = MakeRandomInt(0, lds->NumEntries-1); - // Main loop. - for (uint32 i=0; iNumEntries;) - { - //Force the itemlist back to beginning. - if (item > (lds->NumEntries-1)) - item = 0; - - uint8 charges = lds->Entries[item].multiplier; - uint8 pickedcharges = 0; - // Loop to check multipliers. - for (uint32 x=1; x<=charges; x++) - { - // Actual roll. - float thischance = 0.0; - thischance = lds->Entries[item].chance; - - float drop_chance = 0.0; - if(thischance != 100.0) - drop_chance = MakeRandomFloat(0.0, 100.0); - -#if EQDEBUG>=11 - LogFile->write(EQEMuLog::Debug, "Drop chance for npc: %s, this chance:%f, drop roll:%f", npc->GetName(), thischance, drop_chance); -#endif - if (thischance == 100.0 || drop_chance < thischance) - { - uint32 itemid = lds->Entries[item].item_id; - - const Item_Struct* dbitem = GetItem(itemid); - npc->AddLootDrop(dbitem, itemlist, lds->Entries[item].item_charges, lds->Entries[item].minlevel, lds->Entries[item].maxlevel, lds->Entries[item].equip_item, false); - pickedcharges++; + if(droplimit == 0 && mindrop == 0) { + for(uint32 i = 0; i < lds->NumEntries; ++i) { + int charges = lds->Entries[i].multiplier; + for(int j = 0; j < charges; ++j) { + if(MakeRandomFloat(0.0, 100.0) <= lds->Entries[i].chance) { + const Item_Struct* dbitem = GetItem(lds->Entries[i].item_id); + npc->AddLootDrop(dbitem, itemlist, lds->Entries[i].item_charges, lds->Entries[i].minlevel, + lds->Entries[i].maxlevel, lds->Entries[i].equip_item > 0 ? true : false, false); + } } } - // Items with multipliers only count as 1 towards the limit. - if(pickedcharges > 0) - limit++; + return; + } - // If true, limit reached. - if(limit >= droplimit && droplimit > 0) - break; + if(lds->NumEntries > 100 && droplimit == 0) { + droplimit = 10; + } - item++; - i++; + if(droplimit < mindrop) { + droplimit = mindrop; + } - // We didn't reach our minimium, run loop again. - if(i == lds->NumEntries){ - if(limit < mindrop){ - i = 0; + float roll_t = 0.0f; + bool active_item_list = false; + for(uint32 i = 0; i < lds->NumEntries; ++i) { + const Item_Struct* db_item = GetItem(lds->Entries[i].item_id); + if(db_item) { + roll_t += lds->Entries[i].chance; + active_item_list = true; + } + } + + roll_t = EQEmu::ClampLower(roll_t, 100.0f); + + if(!active_item_list) { + return; + } + + mindrop = EQEmu::ClampLower(mindrop, (uint8)1); + int item_count = MakeRandomInt(mindrop, droplimit); + for(int i = 0; i < item_count; ++i) { + float roll = (float)MakeRandomFloat(0.0, roll_t); + for(uint32 j = 0; j < lds->NumEntries; ++j) { + const Item_Struct* db_item = GetItem(lds->Entries[j].item_id); + if(db_item) { + if(roll < lds->Entries[j].chance) { + npc->AddLootDrop(db_item, itemlist, lds->Entries[j].item_charges, lds->Entries[j].minlevel, + lds->Entries[j].maxlevel, lds->Entries[j].equip_item > 0 ? true : false, false); + + int charges = (int)lds->Entries[i].multiplier; + charges = EQEmu::ClampLower(charges, 1); + + for(int k = 1; k < charges; ++k) { + float c_roll = (float)MakeRandomFloat(0.0, 100.0); + if(c_roll <= lds->Entries[i].chance) { + npc->AddLootDrop(db_item, itemlist, lds->Entries[j].item_charges, lds->Entries[j].minlevel, + lds->Entries[j].maxlevel, lds->Entries[j].equip_item > 0 ? true : false, false); + } + } + + j = lds->NumEntries; + break; + } + else { + roll -= lds->Entries[j].chance; + } } } - } // We either ran out of items or reached our limit. + } } //if itemlist is null, just send wear changes @@ -194,7 +198,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge } item->item_id = item2->ID; - item->charges = charges; + item->charges = (uint8)charges; item->aug1 = 0; item->aug2 = 0; item->aug3 = 0; diff --git a/zone/mob.h b/zone/mob.h index 2617e98e2..d76fe5a8c 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -616,7 +616,7 @@ public: bool PassCastRestriction(bool UseCastRestriction = true, int16 value = 0, bool IsDamage = true); bool ImprovedTaunt(); bool TryRootFadeByDamage(int buffslot, Mob* attacker); - int16 GetSlowMitigation() const {return slow_mitigation;} + float GetSlowMitigation() const { return slow_mitigation; } void CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster = nullptr); inline int16 GetSpellPowerDistanceMod() const { return SpellPowerDistanceMod; }; inline void SetSpellPowerDistanceMod(int16 value) { SpellPowerDistanceMod = value; }; diff --git a/zone/npc.h b/zone/npc.h index f1e4c790c..945bad250 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -257,7 +257,7 @@ public: uint32 GetMaxDMG() const {return max_dmg;} uint32 GetMinDMG() const {return min_dmg;} - int16 GetSlowMitigation() const {return slow_mitigation;} + float GetSlowMitigation() const { return slow_mitigation; } float GetAttackSpeed() const {return attack_speed;} bool IsAnimal() const { return(bodytype == BT_Animal); } uint16 GetPetSpellID() const {return pet_spell_id;} diff --git a/zone/perl_npc.cpp b/zone/perl_npc.cpp index c1f8d8828..fe71b1f0b 100644 --- a/zone/perl_npc.cpp +++ b/zone/perl_npc.cpp @@ -2075,7 +2075,7 @@ XS(XS_NPC_GetSlowMitigation) Perl_croak(aTHX_ "Usage: NPC::GetSlowMitigation(THIS)"); { NPC * THIS; - int16 RETVAL; + float RETVAL; dXSTARG; if (sv_derived_from(ST(0), "NPC")) { @@ -2088,7 +2088,7 @@ XS(XS_NPC_GetSlowMitigation) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); RETVAL = THIS->GetSlowMitigation(); - XSprePUSH; PUSHn((UV)RETVAL); + XSprePUSH; PUSHn((double)RETVAL); } XSRETURN(1); } From 725c5633f685a2e33c3c27e6a9f69cfd2177160e Mon Sep 17 00:00:00 2001 From: KimLS Date: Mon, 29 Sep 2014 17:13:32 -0700 Subject: [PATCH 002/114] Fix for avg_coin --- zone/loottables.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/zone/loottables.cpp b/zone/loottables.cpp index 1a3abe513..22d3cc452 100644 --- a/zone/loottables.cpp +++ b/zone/loottables.cpp @@ -47,8 +47,10 @@ void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* ite uint32 cash = 0; if(max_cash > 0 && EQEmu::ValueWithin(lts->avgcoin, min_cash, max_cash)) { - int avg_cash_roll = MakeRandomInt(1, 100); - if(avg_cash_roll > 50) { + float upper_chance = (float)(lts->avgcoin - min_cash) / (float)(max_cash - min_cash); + float avg_cash_roll = (float)MakeRandomFloat(0.0, 1.0); + + if(avg_cash_roll <= upper_chance) { cash = MakeRandomInt(lts->avgcoin, max_cash); } else { cash = MakeRandomInt(min_cash, lts->avgcoin); From a6b95aeceb874f0764e6d6ea7268712d29137de8 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sat, 31 Jan 2015 02:23:58 -0600 Subject: [PATCH 003/114] At point in which Client -> Server packet logging is working, will do more prechecking to declare that anything actually is subscribed to this category before outputting --- common/eq_packet.cpp | 10 +++++++++ common/eq_packet.h | 3 ++- common/eq_stream.cpp | 4 ++++ common/eqemu_logsys.h | 2 +- common/packet_dump.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++ common/packet_dump.h | 1 + common/string_util.cpp | 2 +- zone/client_packet.cpp | 3 +++ zone/zone.h | 24 ++++++++++++---------- 9 files changed, 81 insertions(+), 14 deletions(-) diff --git a/common/eq_packet.cpp b/common/eq_packet.cpp index ffc3666cb..45eccb7de 100644 --- a/common/eq_packet.cpp +++ b/common/eq_packet.cpp @@ -24,6 +24,7 @@ #include "platform.h" #include #include +#include #include #ifndef STATIC_OPCODE @@ -510,3 +511,12 @@ void DumpPacket(const EQApplicationPacket* app, bool iShowInfo) { // DumpPacketAscii(app->pBuffer, app->size); } +std::string DumpPacketToString(const EQApplicationPacket* app, bool iShowInfo){ + std::ostringstream out; + if (iShowInfo) { + out << "Dumping Applayer: 0x" << std::hex << std::setfill('0') << std::setw(4) << app->GetOpcode() << std::dec; + out << " size:" << app->size << std::endl; + } + out << DumpPacketHexToString(app->pBuffer, app->size); + return out.str(); +} \ No newline at end of file diff --git a/common/eq_packet.h b/common/eq_packet.h index dcd3747a0..e3c8182c6 100644 --- a/common/eq_packet.h +++ b/common/eq_packet.h @@ -20,6 +20,7 @@ #include "base_packet.h" #include "platform.h" +#include #ifdef STATIC_OPCODE typedef unsigned short EmuOpcode; @@ -146,6 +147,6 @@ protected: }; extern void DumpPacket(const EQApplicationPacket* app, bool iShowInfo = false); - +extern std::string DumpPacketToString(const EQApplicationPacket* app, bool iShowInfo = false); #endif diff --git a/common/eq_stream.cpp b/common/eq_stream.cpp index 15a494471..506be72d1 100644 --- a/common/eq_stream.cpp +++ b/common/eq_stream.cpp @@ -23,6 +23,7 @@ #include "op_codes.h" #include "crc16.h" #include "platform.h" +#include "string_util.h" #include #include @@ -558,6 +559,9 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p) uint32 chunksize,used; uint32 length; + // std::cout << "[Server -> Client] " << StringFormat("[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size()) << std::endl; + // DumpPacket(p); + // Convert the EQApplicationPacket to 1 or more EQProtocolPackets if (p->size>(MaxLen-8)) { // proto-op(2), seq(2), app-op(2) ... data ... crc(2) Log.Out(Logs::Detail, Logs::Netcode, _L "Making oversized packet, len %d" __L, p->size); diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index 1bd63d5b5..7adad1a3c 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -88,7 +88,7 @@ namespace Logs{ "AI", "Aggro", "Attack", - "Client Server Packet", + "Packet: [Client -> Server]", "Combat", "Commands", "Crash", diff --git a/common/packet_dump.cpp b/common/packet_dump.cpp index 3c9dfab4f..4f1c2f5f5 100644 --- a/common/packet_dump.cpp +++ b/common/packet_dump.cpp @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -89,6 +90,51 @@ void DumpPacketHex(const uchar* buf, uint32 size, uint32 cols, uint32 skip) { safe_delete_array(ascii); } +std::string DumpPacketHexToString(const uchar* buf, uint32 size, uint32 cols, uint32 skip) { + std::ostringstream out; + if (size == 0 || size > 39565) + return ""; + // Output as HEX + char output[4]; + int j = 0; + char* ascii = new char[cols + 1]; + memset(ascii, 0, cols + 1); + uint32 i; + for (i = skip; i < size; i++) + { + if ((i - skip) % cols == 0) { + if (i != skip) + out << " | " << ascii << std::endl; + out << std::setw(4) << std::setfill(' ') << i - skip << ": "; + memset(ascii, 0, cols + 1); + j = 0; + } + else if ((i - skip) % (cols / 2) == 0) { + out << "- "; + } + sprintf(output, "%02X ", (unsigned char)buf[i]); + out << output; + + if (buf[i] >= 32 && buf[i] < 127) { + ascii[j++] = buf[i]; + } + else { + ascii[j++] = '.'; + } + // std::cout << std::setfill(0) << std::setw(2) << std::hex << (int)buf[i] << " "; // unknown intent [CODEBUG] + } + uint32 k = ((i - skip) - 1) % cols; + if (k < 8) + out << " "; + for (uint32 h = k + 1; h < cols; h++) { + out << " "; + } + out << " | " << ascii << std::endl; + safe_delete_array(ascii); + + return out.str(); +} + void DumpPacket(const uchar* buf, uint32 size) { DumpPacketHex(buf, size); diff --git a/common/packet_dump.h b/common/packet_dump.h index 7a57597f7..db6e485a4 100644 --- a/common/packet_dump.h +++ b/common/packet_dump.h @@ -24,6 +24,7 @@ class ServerPacket; void DumpPacketAscii(const uchar* buf, uint32 size, uint32 cols=16, uint32 skip=0); void DumpPacketHex(const uchar* buf, uint32 size, uint32 cols=16, uint32 skip=0); +std::string DumpPacketHexToString(const uchar* buf, uint32 size, uint32 cols = 16, uint32 skip = 0); void DumpPacketBin(const void* data, uint32 len); void DumpPacket(const uchar* buf, uint32 size); void DumpPacket(const ServerPacket* pack, bool iShowInfo = false); diff --git a/common/string_util.cpp b/common/string_util.cpp index eb1f333f0..89cad4f67 100644 --- a/common/string_util.cpp +++ b/common/string_util.cpp @@ -71,7 +71,6 @@ const std::string StringFormat(const char* format, ...) return output; } - // normal strncpy doesnt put a null term on copied strings, this one does // ref: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcecrt/htm/_wcecrt_strncpy_wcsncpy.asp char* strn0cpy(char* dest, const char* source, uint32 size) { @@ -408,3 +407,4 @@ bool isAlphaNumeric(const char *text) return true; } + diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index ea919f344..bca549925 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -404,6 +404,9 @@ int Client::HandlePacket(const EQApplicationPacket *app) Log.Out(Logs::Detail, Logs::Client_Server_Packet, "Dispatch opcode: %s", buffer); } + // std::cout << "[Client -> Server] " << StringFormat("[%s - 0x%04x] [Size: %u] \n %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()) << std::endl; + Log.Out(Logs::General, Logs::Client_Server_Packet, "[%s - 0x%04x] [Size: %u] \n %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()); + EmuOpcode opcode = app->GetOpcode(); if (opcode == OP_AckPacket) { return true; diff --git a/zone/zone.h b/zone/zone.h index 3d1775718..28d25b5de 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -23,6 +23,7 @@ #include "../common/rulesys.h" #include "../common/types.h" #include "../common/random.h" +#include "../common/string_util.h" #include "qglobals.h" #include "spawn2.h" #include "spawngroup.h" @@ -67,16 +68,6 @@ struct item_tick_struct { std::string qglobal; }; -// static uint32 gmsay_log_message_colors[EQEmuLogSys::MaxLogID] = { -// 15, // "Status", - Yellow -// 15, // "Normal", - Yellow -// 3, // "Error", - Red -// 14, // "Debug", - Light Green -// 4, // "Quest", -// 5, // "Command", -// 3 // "Crash" -// }; - class Client; class Map; class Mob; @@ -266,7 +257,18 @@ public: // random object that provides random values for the zone EQEmu::Random random; - static void GMSayHookCallBackProcess(uint16 log_category, const std::string& message){ entity_list.MessageStatus(0, 80, Log.GetGMSayColorFromCategory(log_category), "%s", message.c_str()); } + static void GMSayHookCallBackProcess(uint16 log_category, const std::string& message){ + if (message.find("\n") != std::string::npos){ + auto message_split = SplitString(message, '\n'); + entity_list.MessageStatus(0, 80, Log.GetGMSayColorFromCategory(log_category), "%s", message_split[0].c_str()); + for (size_t iter = 1; iter < message_split.size(); ++iter) { + entity_list.MessageStatus(0, 80, Log.GetGMSayColorFromCategory(log_category), "--- %s", message_split[iter].c_str()); + } + } + else{ + entity_list.MessageStatus(0, 80, Log.GetGMSayColorFromCategory(log_category), "%s", message.c_str()); + } + } //MODDING HOOKS void mod_init(); From ed9bdaf60c12fc252ce01f18f1ad36d62dae2eae Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 01:00:05 -0600 Subject: [PATCH 004/114] Add to string_util.h void find_replace(std::string& string_subject, std::string& search_string, std::string& replace_string) { --- common/string_util.cpp | 7 +++++++ common/string_util.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/common/string_util.cpp b/common/string_util.cpp index 89cad4f67..7101b54e5 100644 --- a/common/string_util.cpp +++ b/common/string_util.cpp @@ -408,3 +408,10 @@ bool isAlphaNumeric(const char *text) return true; } +void find_replace(std::string& string_subject, std::string& search_string, std::string& replace_string) { + auto index = string_subject.find_first_of(search_string); + while (index != std::string::npos) { + string_subject.replace(index, index + 1, replace_string); + index = string_subject.find_first_of(search_string); + } +} \ No newline at end of file diff --git a/common/string_util.h b/common/string_util.h index 70e888bdf..ae6b433cb 100644 --- a/common/string_util.h +++ b/common/string_util.h @@ -56,4 +56,6 @@ std::vector SplitString(const std::string &s, char delim); bool isAlphaNumeric(const char *text); +void find_replace(std::string& string_subject, std::string& search_string, std::string& replace_string); + #endif From 4f4eee2b16e3967d38e2a0fbc916abfa264a69ab Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 01:03:30 -0600 Subject: [PATCH 005/114] Re-Order string_util.h --- common/string_util.h | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/common/string_util.h b/common/string_util.h index ae6b433cb..3d2db3f8d 100644 --- a/common/string_util.h +++ b/common/string_util.h @@ -23,39 +23,34 @@ #include "types.h" - -const std::string vStringFormat(const char* format, va_list args); -const std::string StringFormat(const char* format, ...); -std::string EscapeString(const std::string &s); -std::string EscapeString(const char *src, size_t sz); - -const char *MakeLowerString(const char *source); - -void MakeLowerString(const char *source, char *target); - -int MakeAnyLenString(char** ret, const char* format, ...); -uint32 AppendAnyLenString(char** ret, uint32* bufsize, uint32* strlen, const char* format, ...); - -uint32 hextoi(const char* num); -uint64 hextoi64(const char* num); bool atobool(const char* iBool); - -char* strn0cpy(char* dest, const char* source, uint32 size); - // return value =true if entire string(source) fit, false if it was truncated +bool isAlphaNumeric(const char *text); bool strn0cpyt(char* dest, const char* source, uint32 size); char *CleanMobName(const char *in, char *out); +char *RemoveApostrophes(const char *s); +char* strn0cpy(char* dest, const char* source, uint32 size); const char *ConvertArray(int input, char *returnchar); const char *ConvertArrayF(float input, char *returnchar); +const char *MakeLowerString(const char *source); +const std::string StringFormat(const char* format, ...); +const std::string vStringFormat(const char* format, va_list args); -void RemoveApostrophes(std::string &s); -char *RemoveApostrophes(const char *s); +int MakeAnyLenString(char** ret, const char* format, ...); + +std::string EscapeString(const char *src, size_t sz); +std::string EscapeString(const std::string &s); std::vector SplitString(const std::string &s, char delim); -bool isAlphaNumeric(const char *text); +uint32 AppendAnyLenString(char** ret, uint32* bufsize, uint32* strlen, const char* format, ...); +uint32 hextoi(const char* num); +uint64 hextoi64(const char* num); + +void MakeLowerString(const char *source, char *target); +void RemoveApostrophes(std::string &s); void find_replace(std::string& string_subject, std::string& search_string, std::string& replace_string); #endif From 5c729e65c91932249cffd27fc99d198fbb4b365d Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 01:05:39 -0600 Subject: [PATCH 006/114] Add sanity checks to GMSayHookCallBackProcess --- zone/zone.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/zone/zone.h b/zone/zone.h index 28d25b5de..80e0473f2 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -257,7 +257,14 @@ public: // random object that provides random values for the zone EQEmu::Random random; - static void GMSayHookCallBackProcess(uint16 log_category, const std::string& message){ + static void GMSayHookCallBackProcess(uint16 log_category, std::string message){ + /* Cut messages down to 4000 max to prevent client crash */ + if (!message.empty()) + message = message.substr(0, 4000); + + /* Replace Occurrences of % or MessageStatus will crash */ + find_replace(message, std::string("%"), std::string(".")); + if (message.find("\n") != std::string::npos){ auto message_split = SplitString(message, '\n'); entity_list.MessageStatus(0, 80, Log.GetGMSayColorFromCategory(log_category), "%s", message_split[0].c_str()); From 5f64b1e1c8b876b9400c0b5b20dd19050c69d6aa Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 01:06:19 -0600 Subject: [PATCH 007/114] Modify category descriptor Packet :: Client -> Server --- common/eqemu_logsys.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index 7adad1a3c..38fbea68b 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -88,7 +88,7 @@ namespace Logs{ "AI", "Aggro", "Attack", - "Packet: [Client -> Server]", + "Packet :: Client -> Server", "Combat", "Commands", "Crash", From 46ac254b3a931100492afb9f922261ec4f63cda8 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 01:58:10 -0600 Subject: [PATCH 008/114] Add struct member LogSettings::is_category_enabled so that it can be used for fast checking in intense portions of code --- common/database.cpp | 10 ++++++++++ common/eqemu_logsys.h | 1 + queryserv/database.cpp | 10 ++++++++++ ucs/database.cpp | 10 ++++++++++ 4 files changed, 31 insertions(+) diff --git a/common/database.cpp b/common/database.cpp index 98639c6af..d632977e0 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -2154,6 +2154,16 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) log_settings[log_category].log_to_file = atoi(row[3]); log_settings[log_category].log_to_gmsay = atoi(row[4]); + /* Determine if any output method is enabled for the category + and set it to 1 so it can used to check if category is enabled */ + const bool log_to_console = log_settings[log_category].log_to_console > 0; + const bool log_to_file = log_settings[log_category].log_to_file > 0; + const bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0; + const bool is_category_enabled = !log_to_console && !log_to_file && !log_to_gmsay; + + if (is_category_enabled) + log_settings[log_category].is_category_enabled = 1; + /* This determines whether or not the process needs to actually file log anything. If we go through this whole loop and nothing is set to any debug level, there is no point to create a file or keep anything open diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index 38fbea68b..a29b163c9 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -160,6 +160,7 @@ public: uint8 log_to_file; uint8 log_to_console; uint8 log_to_gmsay; + uint8 is_category_enabled; /* When any log output in a category > 0, set this to 1 as (Enabled) */ }; /* Internally used memory reference for all log settings per category. diff --git a/queryserv/database.cpp b/queryserv/database.cpp index e788c801c..d0730d097 100644 --- a/queryserv/database.cpp +++ b/queryserv/database.cpp @@ -386,6 +386,16 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings){ log_settings[log_category].log_to_file = atoi(row[3]); log_settings[log_category].log_to_gmsay = atoi(row[4]); + /* Determine if any output method is enabled for the category + and set it to 1 so it can used to check if category is enabled */ + const bool log_to_console = log_settings[log_category].log_to_console > 0; + const bool log_to_file = log_settings[log_category].log_to_file > 0; + const bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0; + const bool is_category_enabled = !log_to_console && !log_to_file && !log_to_gmsay; + + if (is_category_enabled) + log_settings[log_category].is_category_enabled = 1; + /* This determines whether or not the process needs to actually file log anything. If we go through this whole loop and nothing is set to any debug level, there is no point to create a file or keep anything open diff --git a/ucs/database.cpp b/ucs/database.cpp index b80b4fb78..51dd4ecd5 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -600,6 +600,16 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings){ log_settings[log_category].log_to_file = atoi(row[3]); log_settings[log_category].log_to_gmsay = atoi(row[4]); + /* Determine if any output method is enabled for the category + and set it to 1 so it can used to check if category is enabled */ + const bool log_to_console = log_settings[log_category].log_to_console > 0; + const bool log_to_file = log_settings[log_category].log_to_file > 0; + const bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0; + const bool is_category_enabled = !log_to_console && !log_to_file && !log_to_gmsay; + + if (is_category_enabled) + log_settings[log_category].is_category_enabled = 1; + /* This determines whether or not the process needs to actually file log anything. If we go through this whole loop and nothing is set to any debug level, there is no point to create a file or keep anything open From 387b445685d35aaf5ad19d3c0f0cf203ea45b07a Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 02:08:46 -0600 Subject: [PATCH 009/114] Fix the 'is_category_enabled' in each of the database loaders --- common/database.cpp | 2 +- queryserv/database.cpp | 2 +- ucs/database.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/database.cpp b/common/database.cpp index d632977e0..736104f6e 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -2159,7 +2159,7 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) const bool log_to_console = log_settings[log_category].log_to_console > 0; const bool log_to_file = log_settings[log_category].log_to_file > 0; const bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0; - const bool is_category_enabled = !log_to_console && !log_to_file && !log_to_gmsay; + const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay; if (is_category_enabled) log_settings[log_category].is_category_enabled = 1; diff --git a/queryserv/database.cpp b/queryserv/database.cpp index d0730d097..231e100cf 100644 --- a/queryserv/database.cpp +++ b/queryserv/database.cpp @@ -391,7 +391,7 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings){ const bool log_to_console = log_settings[log_category].log_to_console > 0; const bool log_to_file = log_settings[log_category].log_to_file > 0; const bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0; - const bool is_category_enabled = !log_to_console && !log_to_file && !log_to_gmsay; + const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay; if (is_category_enabled) log_settings[log_category].is_category_enabled = 1; diff --git a/ucs/database.cpp b/ucs/database.cpp index 51dd4ecd5..8cd1b73f5 100644 --- a/ucs/database.cpp +++ b/ucs/database.cpp @@ -605,7 +605,7 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings){ const bool log_to_console = log_settings[log_category].log_to_console > 0; const bool log_to_file = log_settings[log_category].log_to_file > 0; const bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0; - const bool is_category_enabled = !log_to_console && !log_to_file && !log_to_gmsay; + const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay; if (is_category_enabled) log_settings[log_category].is_category_enabled = 1; From d9c47fcd41710685817fc35aba02f3263ed1e22b Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 02:09:24 -0600 Subject: [PATCH 010/114] Add a category check pre Logs::Client_Server_Packet trigger --- zone/client_packet.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index bca549925..0d4b76985 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -404,9 +404,9 @@ int Client::HandlePacket(const EQApplicationPacket *app) Log.Out(Logs::Detail, Logs::Client_Server_Packet, "Dispatch opcode: %s", buffer); } - // std::cout << "[Client -> Server] " << StringFormat("[%s - 0x%04x] [Size: %u] \n %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()) << std::endl; - Log.Out(Logs::General, Logs::Client_Server_Packet, "[%s - 0x%04x] [Size: %u] \n %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()); - + if (Log.log_settings[Logs::Client_Server_Packet].is_category_enabled == 1) + Log.Out(Logs::General, Logs::Client_Server_Packet, "[%s - 0x%04x] [Size: %u] \n %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()); + EmuOpcode opcode = app->GetOpcode(); if (opcode == OP_AckPacket) { return true; From d75c632d73044e7c4b01ba95e6b3f9755748920e Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 02:10:18 -0600 Subject: [PATCH 011/114] Chnage netcode logging check to use is_category_enabled instead of just checking for console --- zone/client_packet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 0d4b76985..7f1ceaf2a 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -398,7 +398,7 @@ void ClearMappedOpcode(EmuOpcode op) // client methods int Client::HandlePacket(const EQApplicationPacket *app) { - if(Log.log_settings[Logs::LogCategory::Netcode].log_to_console > 0) { + if (Log.log_settings[Logs::LogCategory::Netcode].is_category_enabled == 1) { char buffer[64]; app->build_header_dump(buffer); Log.Out(Logs::Detail, Logs::Client_Server_Packet, "Dispatch opcode: %s", buffer); From 081a61a948449ba929e2c457342dc54c1aa1698c Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 02:11:58 -0600 Subject: [PATCH 012/114] Add Packet :: Server -> Client category --- common/eq_stream.cpp | 3 +++ common/eqemu_logsys.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/common/eq_stream.cpp b/common/eq_stream.cpp index 506be72d1..ae36bba90 100644 --- a/common/eq_stream.cpp +++ b/common/eq_stream.cpp @@ -561,6 +561,9 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p) // std::cout << "[Server -> Client] " << StringFormat("[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size()) << std::endl; // DumpPacket(p); + if (Log.log_settings[Logs::Client_Server_Packet].is_category_enabled == 1) + Log.Out(Logs::General, Logs::Client_Server_Packet, "[%s - 0x%04x] [Size: %u] \n %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()); + // Convert the EQApplicationPacket to 1 or more EQProtocolPackets if (p->size>(MaxLen-8)) { // proto-op(2), seq(2), app-op(2) ... data ... crc(2) diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index a29b163c9..8c2d4cbe2 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -78,6 +78,7 @@ namespace Logs{ MySQLQuery, Mercenaries, QuestDebug, + Server_Client_Packet, MaxCategoryID /* Don't Remove this*/ }; @@ -122,6 +123,7 @@ namespace Logs{ "MySQL Query", "Mercenaries", "Quest Debug", + "Packet :: Server -> Client", }; } From e35205eaf4c715f5bc6c136a2e67f00d2aa08981 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 02:13:47 -0600 Subject: [PATCH 013/114] Add Packet :: Server -> Client logging --- common/eq_stream.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/common/eq_stream.cpp b/common/eq_stream.cpp index ae36bba90..97c40c3c2 100644 --- a/common/eq_stream.cpp +++ b/common/eq_stream.cpp @@ -559,10 +559,8 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p) uint32 chunksize,used; uint32 length; - // std::cout << "[Server -> Client] " << StringFormat("[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size()) << std::endl; - // DumpPacket(p); - if (Log.log_settings[Logs::Client_Server_Packet].is_category_enabled == 1) - Log.Out(Logs::General, Logs::Client_Server_Packet, "[%s - 0x%04x] [Size: %u] \n %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()); + if (Log.log_settings[Logs::Server_Client_Packet].is_category_enabled == 1) + Log.Out(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u] \n %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str()); // Convert the EQApplicationPacket to 1 or more EQProtocolPackets From 5fcd3eb38edd6d2b2df111e114c1487ed986538d Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 03:25:16 -0600 Subject: [PATCH 014/114] Implement stable Server -> Client packet logging --- common/eq_stream.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/common/eq_stream.cpp b/common/eq_stream.cpp index 97c40c3c2..63e7cafb7 100644 --- a/common/eq_stream.cpp +++ b/common/eq_stream.cpp @@ -559,9 +559,13 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p) uint32 chunksize,used; uint32 length; - if (Log.log_settings[Logs::Server_Client_Packet].is_category_enabled == 1) - Log.Out(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u] \n %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str()); + // DumpPacket(p); + if (Log.log_settings[Logs::Server_Client_Packet].is_category_enabled == 1){ + if (p->GetOpcode() != OP_SpecialMesg){ + Log.Out(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u] \n %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str()); + } + } // Convert the EQApplicationPacket to 1 or more EQProtocolPackets if (p->size>(MaxLen-8)) { // proto-op(2), seq(2), app-op(2) ... data ... crc(2) From b3ea1a9da74e7b8950536a3ec0565c4fa33876ec Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 04:05:32 -0600 Subject: [PATCH 015/114] Some changes --- common/eqemu_logsys.h | 2 ++ zone/client_packet.cpp | 13 ++----------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index 8c2d4cbe2..9cdc162a7 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -79,6 +79,7 @@ namespace Logs{ Mercenaries, QuestDebug, Server_Client_Packet, + Client_Server_Packet_Unhandled, MaxCategoryID /* Don't Remove this*/ }; @@ -124,6 +125,7 @@ namespace Logs{ "Mercenaries", "Quest Debug", "Packet :: Server -> Client", + "Packet :: Client -> Server Unhandled", }; } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 7f1ceaf2a..cc9c77286 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -462,17 +462,8 @@ int Client::HandlePacket(const EQApplicationPacket *app) args.push_back(const_cast(app)); parse->EventPlayer(EVENT_UNHANDLED_OPCODE, this, "", 0, &args); - char buffer[64]; - Log.Out(Logs::Detail, Logs::Client_Server_Packet, "Unhandled incoming opcode: %s - 0x%04x", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode()); - if (Log.log_settings[Logs::Client_Server_Packet].log_to_console > 0){ - app->build_header_dump(buffer); - if (app->size < 1000) - DumpPacket(app, app->size); - else{ - std::cout << "Dump limited to 1000 characters:\n"; - DumpPacket(app, 1000); - } - } + if (Log.log_settings[Logs::Client_Server_Packet_Unhandled].is_category_enabled == 1) + Log.Out(Logs::General, Logs::Client_Server_Packet_Unhandled, "Incoming OpCode :: [%s - 0x%04x] [Size: %u] \n%s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()); break; } From cced57f56a542a741b50e33fd05784145b7506f2 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 1 Feb 2015 15:11:27 -0500 Subject: [PATCH 016/114] Fix lua events --- zone/lua_parser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index cf6d356dc..7f6412b0f 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -35,14 +35,13 @@ #include "zone.h" #include "lua_parser.h" -const char *LuaEvents[_LargestEventID] = { +const char *LuaEvents[_LargestEventID] = { "event_say", "event_trade", "event_death", "event_spawn", "event_attack", "event_combat", - "event_environmental_damage", "event_aggro", "event_slay", "event_npc_slay", @@ -68,6 +67,7 @@ const char *LuaEvents[_LargestEventID] = { "event_aggro_say", "event_player_pickup", "event_popup_response", + "event_environmental_damage", "event_proximity_say", "event_cast", "event_cast_begin", From 8649ed1dcb3b49bcd89a15051d70f573638abd27 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 1 Feb 2015 17:25:16 -0500 Subject: [PATCH 017/114] Add quest debugging to lua --- changelog.txt | 7 +++++++ zone/lua_general.cpp | 17 +++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 88180df59..c6b13dbaa 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,12 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/01/2015 == +demonstar55: Add quest debugging to lua + eq.debug("Test debug level implicit 1") + eq.debug("Test debug level explicit 1", 1) + eq.debug("Test debug level explicit 2", 2) + eq.debug("Test debug level explicit 3", 3) + == 01/31/2015 == Trevius: Fixed FindGroundZ() and GetGroundZ() to once again utilize the X and Y arguments that are passed to them. diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index cdf42005d..50afdb6e9 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -17,6 +17,7 @@ #include "questmgr.h" #include "qglobals.h" #include "../common/timer.h" +#include "../common/eqemu_logsys.h" struct Events { }; struct Factions { }; @@ -1221,7 +1222,6 @@ std::string lua_get_encounter() { return quest_manager.GetEncounter(); } - void lua_map_opcodes() { MapOpcodes(); } @@ -1249,6 +1249,17 @@ double lua_clock() { return static_cast(t) / 1000.0; } +void lua_debug(std::string message) { + Log.Out(Logs::General, Logs::QuestDebug, message); +} + +void lua_debug(std::string message, int level) { + if (level < Logs::General || level > Logs::Detail) + return; + + Log.Out(static_cast(level), Logs::QuestDebug, message); +} + #define LuaCreateNPCParse(name, c_type, default_value) do { \ cur = table[#name]; \ if(luabind::type(cur) != LUA_TNIL) { \ @@ -1582,7 +1593,9 @@ luabind::scope lua_register_general() { luabind::def("disable_recipe", &lua_disable_recipe), luabind::def("clear_npctype_cache", &lua_clear_npctype_cache), luabind::def("clock", &lua_clock), - luabind::def("create_npc", &lua_create_npc) + luabind::def("create_npc", &lua_create_npc), + luabind::def("debug", (void(*)(std::string))&lua_debug), + luabind::def("debug", (void(*)(std::string, int))&lua_debug) ]; } From 180612bb21e61c1a279dc03d50666f2fedc372e0 Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Sun, 1 Feb 2015 18:57:26 -0500 Subject: [PATCH 018/114] Added new rule to make the UnmemSpellAll on death optional. - New Rule: Character:UnmemSpellsOnDeath (default true) --- common/ruletypes.h | 1 + zone/attack.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 136f55026..18fb3ba3e 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -102,6 +102,7 @@ RULE_INT ( Character, BaseInstrumentSoftCap, 36) // Softcap for instrument mods, RULE_INT ( Character, BaseRunSpeedCap, 158) // Base Run Speed Cap, on live it's 158% which will give you a runspeed of 1.580 hard capped to 225. RULE_INT ( Character, OrnamentationAugmentType, 20) //Ornamentation Augment Type RULE_REAL(Character, EnvironmentDamageMulipliter, 1) +RULE_BOOL(Character, UnmemSpellsOnDeath, true) RULE_CATEGORY_END() RULE_CATEGORY( Mercs ) diff --git a/zone/attack.cpp b/zone/attack.cpp index 25dc88688..bfd4a5cc2 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1584,10 +1584,12 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att //this generates a lot of 'updates' to the client that the client does not need BuffFadeNonPersistDeath(); - if((GetClientVersionBit() & BIT_SoFAndLater) && RuleB(Character, RespawnFromHover)) - UnmemSpellAll(true); - else - UnmemSpellAll(false); + if (RuleB(Character, UnmemSpellsOnDeath)) { + if((GetClientVersionBit() & BIT_SoFAndLater) && RuleB(Character, RespawnFromHover)) + UnmemSpellAll(true); + else + UnmemSpellAll(false); + } if((RuleB(Character, LeaveCorpses) && GetLevel() >= RuleI(Character, DeathItemLossLevel)) || RuleB(Character, LeaveNakedCorpses)) { From 774e429d87bee600af27529a65e8d04352b00fbf Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 19:56:32 -0600 Subject: [PATCH 019/114] Get Logs::Client_Server_Packet_Unhandled to show raw opcodes --- common/eq_stream.cpp | 17 +++++++++-------- common/packet_dump.cpp | 3 +++ zone/client_packet.cpp | 12 +++++++----- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/common/eq_stream.cpp b/common/eq_stream.cpp index 63e7cafb7..3f88d1a2b 100644 --- a/common/eq_stream.cpp +++ b/common/eq_stream.cpp @@ -563,7 +563,7 @@ void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p) if (Log.log_settings[Logs::Server_Client_Packet].is_category_enabled == 1){ if (p->GetOpcode() != OP_SpecialMesg){ - Log.Out(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u] \n %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str()); + Log.Out(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str()); } } @@ -961,14 +961,15 @@ EQRawApplicationPacket *p=nullptr; MInboundQueue.unlock(); //resolve the opcode if we can. - if(p) { - if(OpMgr != nullptr && *OpMgr != nullptr) { - EmuOpcode emu_op = (*OpMgr)->EQToEmu(p->opcode); - if (emu_op == OP_Unknown) { - Log.Out(Logs::General, Logs::Netcode, "[ERROR] Unable to convert EQ opcode 0x%.4x to an Application opcode.", p->opcode); + if (Log.log_settings[Logs::Client_Server_Packet_Unhandled].is_category_enabled == 1){ + if (p) { + if (OpMgr != nullptr && *OpMgr != nullptr) { + EmuOpcode emu_op = (*OpMgr)->EQToEmu(p->opcode); + if (emu_op == OP_Unknown) { + // Log.Out(Logs::General, Logs::Client_Server_Packet_Unhandled, "Unknown :: [%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->opcode, p->Size(), DumpPacketToString(p).c_str()); + } + p->SetOpcode(emu_op); } - - p->SetOpcode(emu_op); } } diff --git a/common/packet_dump.cpp b/common/packet_dump.cpp index 4f1c2f5f5..4ab1fcbef 100644 --- a/common/packet_dump.cpp +++ b/common/packet_dump.cpp @@ -94,6 +94,9 @@ std::string DumpPacketHexToString(const uchar* buf, uint32 size, uint32 cols, ui std::ostringstream out; if (size == 0 || size > 39565) return ""; + + out << "\n"; + // Output as HEX char output[4]; int j = 0; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 1aece578f..6558b6dee 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -405,7 +405,7 @@ int Client::HandlePacket(const EQApplicationPacket *app) } if (Log.log_settings[Logs::Client_Server_Packet].is_category_enabled == 1) - Log.Out(Logs::General, Logs::Client_Server_Packet, "[%s - 0x%04x] [Size: %u] \n %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()); + Log.Out(Logs::General, Logs::Client_Server_Packet, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()); EmuOpcode opcode = app->GetOpcode(); if (opcode == OP_AckPacket) { @@ -448,14 +448,16 @@ int Client::HandlePacket(const EQApplicationPacket *app) case CLIENT_CONNECTED: { ClientPacketProc p; p = ConnectedOpcodes[opcode]; - if(p == nullptr) { + if(p == nullptr) { std::vector args; args.push_back(const_cast(app)); parse->EventPlayer(EVENT_UNHANDLED_OPCODE, this, "", 0, &args); - if (Log.log_settings[Logs::Client_Server_Packet_Unhandled].is_category_enabled == 1) - Log.Out(Logs::General, Logs::Client_Server_Packet_Unhandled, "Incoming OpCode :: [%s - 0x%04x] [Size: %u] \n%s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()); - + if (Log.log_settings[Logs::Client_Server_Packet_Unhandled].is_category_enabled == 1){ + char buffer[64]; + app->build_header_dump(buffer); + Log.Out(Logs::General, Logs::Client_Server_Packet_Unhandled, "%s %s", buffer, DumpPacketToString(app).c_str()); + } break; } From 02e56331ecad1832e8a3d5f6e0f719b72cf4fd2f Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 19:57:02 -0600 Subject: [PATCH 020/114] Have is_category_enabled update appropriately when settings are set via #logs --- zone/command.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/zone/command.cpp b/zone/command.cpp index f54db9a75..c34bc1b9d 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -10605,6 +10605,15 @@ void command_logs(Client *c, const Seperator *sep){ c->Message(15, "Your Log Settings have been applied"); c->Message(15, "Output Method: %s :: Debug Level: %i - Category: %s", sep->arg[2], atoi(sep->arg[4]), Logs::LogCategoryName[atoi(sep->arg[3])]); } + /* We use a general 'is_category_enabled' now, let's update when we update any output settings + This is used in hot places of code to check if its enabled in any way before triggering logs + */ + if (sep->arg[4] > 0){ + Log.log_settings[atoi(sep->arg[3])].is_category_enabled = 1; + } + else{ + Log.log_settings[atoi(sep->arg[3])].is_category_enabled = 0; + } } } else { From 75c48e58002b94f2c2b48b54a67a13f43ca57b27 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 21:42:43 -0600 Subject: [PATCH 021/114] Add category prefix in file based log messages --- common/eq_stream.cpp | 17 +++++++---------- common/eqemu_logsys.cpp | 2 +- common/eqemu_logsys.h | 1 - 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/common/eq_stream.cpp b/common/eq_stream.cpp index 3f88d1a2b..402d3d90b 100644 --- a/common/eq_stream.cpp +++ b/common/eq_stream.cpp @@ -960,16 +960,13 @@ EQRawApplicationPacket *p=nullptr; } MInboundQueue.unlock(); - //resolve the opcode if we can. - if (Log.log_settings[Logs::Client_Server_Packet_Unhandled].is_category_enabled == 1){ - if (p) { - if (OpMgr != nullptr && *OpMgr != nullptr) { - EmuOpcode emu_op = (*OpMgr)->EQToEmu(p->opcode); - if (emu_op == OP_Unknown) { - // Log.Out(Logs::General, Logs::Client_Server_Packet_Unhandled, "Unknown :: [%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->opcode, p->Size(), DumpPacketToString(p).c_str()); - } - p->SetOpcode(emu_op); - } + if (p) { + if (OpMgr != nullptr && *OpMgr != nullptr) { + EmuOpcode emu_op = (*OpMgr)->EQToEmu(p->opcode); + if (emu_op == OP_Unknown) { + // Log.Out(Logs::General, Logs::Client_Server_Packet_Unhandled, "Unknown :: [%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->opcode, p->Size(), DumpPacketToString(p).c_str()); + } + p->SetOpcode(emu_op); } } diff --git a/common/eqemu_logsys.cpp b/common/eqemu_logsys.cpp index 51b069f28..36176c399 100644 --- a/common/eqemu_logsys.cpp +++ b/common/eqemu_logsys.cpp @@ -288,7 +288,7 @@ void EQEmuLogSys::Out(Logs::DebugLevel debug_level, uint16 log_category, std::st if (log_to_console) EQEmuLogSys::ProcessConsoleMessage(debug_level, log_category, output_debug_message); if (log_to_gmsay) EQEmuLogSys::ProcessGMSay(debug_level, log_category, output_debug_message); - if (log_to_file) EQEmuLogSys::ProcessLogWrite(debug_level, log_category, output_message); + if (log_to_file) EQEmuLogSys::ProcessLogWrite(debug_level, log_category, output_debug_message); } void EQEmuLogSys::SetCurrentTimeStamp(char* time_stamp) diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index 72e434a87..5cd110c01 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -124,7 +124,6 @@ namespace Logs { "MySQL Query", "Mercenaries", "Quest Debug", - "Quest Debug" "Packet :: Server -> Client", "Packet :: Client -> Server Unhandled", }; From 8aa8982b66251061ae5937a9a20bbcb7fec02de4 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 21:43:50 -0600 Subject: [PATCH 022/114] Add File 2015_02_01_logsys_packet_logs.sql --- utils/sql/git/required/2015_02_01_logsys_packet_logs.sql | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 utils/sql/git/required/2015_02_01_logsys_packet_logs.sql diff --git a/utils/sql/git/required/2015_02_01_logsys_packet_logs.sql b/utils/sql/git/required/2015_02_01_logsys_packet_logs.sql new file mode 100644 index 000000000..ba00ee607 --- /dev/null +++ b/utils/sql/git/required/2015_02_01_logsys_packet_logs.sql @@ -0,0 +1,3 @@ +REPLACE INTO `logsys_categories` (`log_category_id`, `log_category_description`) VALUES ('39', 'Packet: Server -> Client'); +REPLACE INTO `logsys_categories` (`log_category_id`, `log_category_description`) VALUES ('5', 'Packet: Client -> Server'); +REPLACE INTO `logsys_categories` (`log_category_id`, `log_category_description`) VALUES ('40', 'Packet: Client -> Server Unhandled'); \ No newline at end of file From 4b08c7552729e8a8ca1e2b217ddd9948a2078b2b Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 21:47:41 -0600 Subject: [PATCH 023/114] Add some 'is_category_enabled' before some more core logging function calls --- common/dbcore.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/common/dbcore.cpp b/common/dbcore.cpp index 4f95fba3f..d256f7b42 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -110,7 +110,8 @@ MySQLRequestResult DBcore::QueryDatabase(const char* query, uint32 querylen, boo /* Implement Logging at the Root */ if (mysql_errno(&mysql) > 0 && strlen(query) > 0){ - Log.Out(Logs::General, Logs::MySQLError, "%i: %s \n %s", mysql_errno(&mysql), mysql_error(&mysql), query); + if (Log.log_settings[Logs::MySQLError].is_category_enabled == 1) + Log.Out(Logs::General, Logs::MySQLError, "%i: %s \n %s", mysql_errno(&mysql), mysql_error(&mysql), query); } return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql),errorBuffer); @@ -125,8 +126,9 @@ MySQLRequestResult DBcore::QueryDatabase(const char* query, uint32 querylen, boo rowCount = (uint32)mysql_num_rows(res); MySQLRequestResult requestResult(res, (uint32)mysql_affected_rows(&mysql), rowCount, (uint32)mysql_field_count(&mysql), (uint32)mysql_insert_id(&mysql)); - - Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u rows returned)", query, rowCount, requestResult.RowCount()); + + if (Log.log_settings[Logs::MySQLQuery].is_category_enabled == 1) + Log.Out(Logs::General, Logs::MySQLQuery, "%s (%u rows returned)", query, rowCount, requestResult.RowCount()); return requestResult; } From 10e3c31ad68e32ab8e1a3b62982e1de5ee573147 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 21:56:45 -0600 Subject: [PATCH 024/114] Packet Logging database version update --- common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/common/version.h b/common/version.h index 5841a4119..05ce3a53e 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9073 +#define CURRENT_BINARY_DATABASE_VERSION 9074 #define COMPILE_DATE __DATE__ #define COMPILE_TIME __TIME__ #ifndef WIN32 diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index be99178a3..f72b90aff 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -327,6 +327,7 @@ 9071|2015_01_29_merc_stats_table_update.sql|SHOW COLUMNS FROM `merc_stats` LIKE 'statscale'|empty| 9072|2015_01_30_merc_attack_delay.sql|SHOW COLUMNS FROM `merc_stats` LIKE 'attack_delay'|empty| 9073|2015_01_31_character_item_recast.sql|SHOW TABLES LIKE 'character_item_recast'|empty| +9074|2015_02_01_logsys_packet_logs.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not From 3ec39ce06b138b142c9c6c162392e789f3cf1420 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 22:00:21 -0600 Subject: [PATCH 025/114] Changelog --- changelog.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index c6b13dbaa..279e28418 100644 --- a/changelog.txt +++ b/changelog.txt @@ -6,7 +6,12 @@ demonstar55: Add quest debugging to lua eq.debug("Test debug level explicit 1", 1) eq.debug("Test debug level explicit 2", 2) eq.debug("Test debug level explicit 3", 3) - +Akkadius: Add Packet Logging Categories + - 5 - Packet: Client -> Server - Logs::Client_Server_Packet + - 39 - Packet: Server -> Client - Logs::Server_Client_Packet + - 40 - Packet: Client -> Server Unhandled - Logs::Client_Server_Packet_Unhandled + See: http://wiki.eqemulator.org/p?Logging_System_Overhaul#packet-logging + == 01/31/2015 == Trevius: Fixed FindGroundZ() and GetGroundZ() to once again utilize the X and Y arguments that are passed to them. From 20c99e36d8d2478c8768cd0ef919f1c05968a2f4 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 22:29:04 -0600 Subject: [PATCH 026/114] find_replace fix --- common/string_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/string_util.h b/common/string_util.h index 3d2db3f8d..c69f01456 100644 --- a/common/string_util.h +++ b/common/string_util.h @@ -51,6 +51,6 @@ uint64 hextoi64(const char* num); void MakeLowerString(const char *source, char *target); void RemoveApostrophes(std::string &s); -void find_replace(std::string& string_subject, std::string& search_string, std::string& replace_string); +void find_replace(std::string& string_subject, const std::string& search_string, const std::string& replace_string); #endif From d2b9d4ab203f04bb9c79647aea6c3ed556a6027c Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 22:40:56 -0600 Subject: [PATCH 027/114] find_replace fix for real --- common/string_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/string_util.cpp b/common/string_util.cpp index 1ce84dcfb..e791eb7f6 100644 --- a/common/string_util.cpp +++ b/common/string_util.cpp @@ -408,7 +408,7 @@ bool isAlphaNumeric(const char *text) return true; } -void find_replace(std::string& string_subject, std::string& search_string, std::string& replace_string) { +void find_replace(std::string& string_subject, const std::string& search_string, const std::string& replace_string) { auto index = string_subject.find_first_of(search_string); while (index != std::string::npos) { string_subject.replace(index, index + 1, replace_string); From e1c49f93e29924cf3c9d324cac0293176c08e179 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Mon, 2 Feb 2015 00:18:29 -0500 Subject: [PATCH 028/114] Out of bounds bandoleer fix --- zone/zonedb.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index e90016dfb..07fe67679 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1118,11 +1118,9 @@ bool ZoneDatabase::LoadCharacterMaterialColor(uint32 character_id, PlayerProfile bool ZoneDatabase::LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp){ std::string query = StringFormat("SELECT `bandolier_id`, `bandolier_slot`, `item_id`, `icon`, `bandolier_name` FROM `character_bandolier` WHERE `id` = %u LIMIT 16", character_id); auto results = database.QueryDatabase(query); int i = 0; int r = 0; int si = 0; - for (i = 0; i <= EmuConstants::BANDOLIERS_COUNT; i++){ - for (int si = 0; si < EmuConstants::BANDOLIER_SIZE; si++){ + for (i = 0; i < EmuConstants::BANDOLIERS_COUNT; i++) + for (int si = 0; si < EmuConstants::BANDOLIER_SIZE; si++) pp->bandoliers[i].items[si].icon = 0; - } - } for (auto row = results.begin(); row != results.end(); ++row) { r = 0; From f2667cee23b909a27b743241438f91bc47141adc Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 2 Feb 2015 00:10:22 -0600 Subject: [PATCH 029/114] Implement Packet logs with dumps - Category: 41: Packet: Server -> Client With Dump - Category: 42: Packet: Server -> Client With Dump See: http://wiki.eqemulator.org/p?Logging_System_Overhaul#packet-logging-levels --- changelog.txt | 7 +++++++ common/eq_packet.cpp | 6 +----- common/eq_packet.h | 2 +- common/eq_stream.cpp | 12 ++++++++---- common/eqemu_logsys.h | 4 ++++ common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + .../2015_02_02_logsys_packet_logs_with_dump.sql | 2 ++ zone/client_packet.cpp | 5 ++++- 9 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 utils/sql/git/required/2015_02_02_logsys_packet_logs_with_dump.sql diff --git a/changelog.txt b/changelog.txt index 279e28418..d5312dd4e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,12 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- + +== 02/02/2015 == +Akkadius: Implement Packet logs with dumps + - Category: 41: Packet: Server -> Client With Dump + - Category: 42: Packet: Server -> Client With Dump + See: http://wiki.eqemulator.org/p?Logging_System_Overhaul#packet-logging-levels + == 02/01/2015 == demonstar55: Add quest debugging to lua eq.debug("Test debug level implicit 1") diff --git a/common/eq_packet.cpp b/common/eq_packet.cpp index 45eccb7de..e01f6a3f8 100644 --- a/common/eq_packet.cpp +++ b/common/eq_packet.cpp @@ -511,12 +511,8 @@ void DumpPacket(const EQApplicationPacket* app, bool iShowInfo) { // DumpPacketAscii(app->pBuffer, app->size); } -std::string DumpPacketToString(const EQApplicationPacket* app, bool iShowInfo){ +std::string DumpPacketToString(const EQApplicationPacket* app){ std::ostringstream out; - if (iShowInfo) { - out << "Dumping Applayer: 0x" << std::hex << std::setfill('0') << std::setw(4) << app->GetOpcode() << std::dec; - out << " size:" << app->size << std::endl; - } out << DumpPacketHexToString(app->pBuffer, app->size); return out.str(); } \ No newline at end of file diff --git a/common/eq_packet.h b/common/eq_packet.h index e3c8182c6..ed90d132a 100644 --- a/common/eq_packet.h +++ b/common/eq_packet.h @@ -147,6 +147,6 @@ protected: }; extern void DumpPacket(const EQApplicationPacket* app, bool iShowInfo = false); -extern std::string DumpPacketToString(const EQApplicationPacket* app, bool iShowInfo = false); +extern std::string DumpPacketToString(const EQApplicationPacket* app); #endif diff --git a/common/eq_stream.cpp b/common/eq_stream.cpp index 402d3d90b..be1ae50d4 100644 --- a/common/eq_stream.cpp +++ b/common/eq_stream.cpp @@ -556,14 +556,18 @@ void EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req) void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p) { - uint32 chunksize,used; + uint32 chunksize, used; uint32 length; - // DumpPacket(p); - if (Log.log_settings[Logs::Server_Client_Packet].is_category_enabled == 1){ if (p->GetOpcode() != OP_SpecialMesg){ - Log.Out(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str()); + Log.Out(Logs::General, Logs::Server_Client_Packet, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size()); + } + } + + if (Log.log_settings[Logs::Server_Client_Packet_With_Dump].is_category_enabled == 1){ + if (p->GetOpcode() != OP_SpecialMesg){ + Log.Out(Logs::General, Logs::Server_Client_Packet_With_Dump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(p->GetOpcode()), p->GetOpcode(), p->Size(), DumpPacketToString(p).c_str()); } } diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index 5cd110c01..a99b3b439 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -80,6 +80,8 @@ namespace Logs { QuestDebug, Server_Client_Packet, Client_Server_Packet_Unhandled, + Server_Client_Packet_With_Dump, + Client_Server_Packet_With_Dump, MaxCategoryID /* Don't Remove this*/ }; @@ -126,6 +128,8 @@ namespace Logs { "Quest Debug", "Packet :: Server -> Client", "Packet :: Client -> Server Unhandled", + "Packet :: Server -> Client (Dump)", + "Packet :: Client -> Server (Dump)", }; } diff --git a/common/version.h b/common/version.h index 05ce3a53e..ee9196985 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9074 +#define CURRENT_BINARY_DATABASE_VERSION 9075 #define COMPILE_DATE __DATE__ #define COMPILE_TIME __TIME__ #ifndef WIN32 diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index f72b90aff..9d370c5fa 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -328,6 +328,7 @@ 9072|2015_01_30_merc_attack_delay.sql|SHOW COLUMNS FROM `merc_stats` LIKE 'attack_delay'|empty| 9073|2015_01_31_character_item_recast.sql|SHOW TABLES LIKE 'character_item_recast'|empty| 9074|2015_02_01_logsys_packet_logs.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client'|empty| +9075|2015_02_02_logsys_packet_logs_with_dump.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client With Dump'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2015_02_02_logsys_packet_logs_with_dump.sql b/utils/sql/git/required/2015_02_02_logsys_packet_logs_with_dump.sql new file mode 100644 index 000000000..7da9af532 --- /dev/null +++ b/utils/sql/git/required/2015_02_02_logsys_packet_logs_with_dump.sql @@ -0,0 +1,2 @@ +REPLACE INTO `logsys_categories` (`log_category_id`, `log_category_description`) VALUES ('41', 'Packet: Server -> Client With Dump'); +REPLACE INTO `logsys_categories` (`log_category_id`, `log_category_description`) VALUES ('42', 'Packet: Server -> Client With Dump'); \ No newline at end of file diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 6558b6dee..199e37356 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -405,7 +405,10 @@ int Client::HandlePacket(const EQApplicationPacket *app) } if (Log.log_settings[Logs::Client_Server_Packet].is_category_enabled == 1) - Log.Out(Logs::General, Logs::Client_Server_Packet, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()); + Log.Out(Logs::General, Logs::Client_Server_Packet, "[%s - 0x%04x] [Size: %u]", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size()); + + if (Log.log_settings[Logs::Client_Server_Packet_With_Dump].is_category_enabled == 1) + Log.Out(Logs::General, Logs::Client_Server_Packet_With_Dump, "[%s - 0x%04x] [Size: %u] %s", OpcodeManager::EmuToName(app->GetOpcode()), app->GetOpcode(), app->Size(), DumpPacketToString(app).c_str()); EmuOpcode opcode = app->GetOpcode(); if (opcode == OP_AckPacket) { From aed3d9ef8516792f422a03aaa10a4ead3c9c0a58 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Mon, 2 Feb 2015 03:01:37 -0500 Subject: [PATCH 030/114] Fix to allow for PBAE/Targeted AE spells to check the 'npc_no_los' field in spell file to disable LOS checks. --- zone/effects.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/effects.cpp b/zone/effects.cpp index 802fce796..5cc024ce2 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -749,9 +749,9 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_ if (bad) { if (!caster->IsAttackAllowed(curmob, true)) continue; - if (center && !center->CheckLosFN(curmob)) + if (center && !spells[spell_id].npc_no_los && !center->CheckLosFN(curmob)) continue; - if (!center && !caster->CheckLosFN(caster->GetTargetRingX(), caster->GetTargetRingY(), caster->GetTargetRingZ(), curmob->GetSize())) + if (!center && !spells[spell_id].npc_no_los && !caster->CheckLosFN(caster->GetTargetRingX(), caster->GetTargetRingY(), caster->GetTargetRingZ(), curmob->GetSize())) continue; } else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies... // This does not check faction for beneficial AE buffs..only agro and attackable. From 379219aff162b75eed8e98fed926bd5c5aec10b3 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 3 Feb 2015 06:40:51 -0500 Subject: [PATCH 031/114] Implemented new pet type (5) which summons a regular pet that locks onto the casters target exclusively until the target dies, when target dies the pet is killed. (Pets don't respond to commands except get lost). This does not stack with regular pets. Note: On live these pets cast an actual spell (Unsummon) that kills them for 20k damage, due to how limiting that is to be hard coded, the pets will simply just kill themselves instead. Pending, will needd to add an optional SQL to update pet tables to convert known live spells that use this. --- zone/attack.cpp | 6 ++++++ zone/client_packet.cpp | 3 +++ zone/common.h | 2 +- zone/mob.h | 1 + zone/pets.cpp | 13 +++++++++++++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index 25dc88688..280eda918 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1508,6 +1508,9 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att } } } + + if (killerMob && killerMob->IsPet() && killerMob->GetPetType() == petTargetLock && killerMob->GetID() != GetID()) + killerMob->Kill(); } entity_list.RemoveFromTargets(this); @@ -2378,6 +2381,9 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack } } + if (killerMob && killerMob->IsPet() && killerMob->GetPetType() == petTargetLock && killerMob->GetID() != GetID()) + killerMob->Kill(); + WipeHateList(); p_depop = true; if(killerMob && killerMob->GetTarget() == this) //we can kill things without having them targeted diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index a3062891b..6f307c2d9 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -9863,6 +9863,9 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) return; } + if (mypet->GetPetType() == petTargetLock && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST)) + return; + if (mypet->GetPetType() == petAnimation && (pet->command != PET_HEALTHREPORT && pet->command != PET_GETLOST) && !GetAA(aaAnimationEmpathy)) return; diff --git a/zone/common.h b/zone/common.h index 19237d99c..20d19e94d 100644 --- a/zone/common.h +++ b/zone/common.h @@ -505,7 +505,7 @@ typedef enum { petOther, petCharmed, petNPCFollow, - petHatelist //remain active as long something is on the hatelist. Don't listen to any commands + petTargetLock //remain active as long something is on the hatelist. Don't listen to any commands } PetType; typedef enum { diff --git a/zone/mob.h b/zone/mob.h index 9641a2ffb..c2f57ff9c 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -675,6 +675,7 @@ public: bool IsFamiliar() const { return(typeofpet == petFamiliar); } bool IsAnimation() const { return(typeofpet == petAnimation); } bool IsCharmed() const { return(typeofpet == petCharmed); } + bool IsTargetLockPet() const { return(typeofpet == petTargetLock); } void SetOwnerID(uint16 NewOwnerID); inline uint16 GetOwnerID() const { return ownerid; } inline virtual bool HasOwner() { if(GetOwnerID()==0){return false;} return( entity_list.GetMob(GetOwnerID()) != 0); } diff --git a/zone/pets.cpp b/zone/pets.cpp index 117b466a7..38cd16a2a 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -426,6 +426,19 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, entity_list.AddNPC(npc, true, true); SetPetID(npc->GetID()); // We need to handle PetType 5 (petHatelist), add the current target to the hatelist of the pet + + + if (record.petcontrol == petTargetLock) + { + Mob* target = GetTarget(); + + if (target){ + npc->AddToHateList(target, 1); + npc->SetSpecialAbility(IMMUNE_AGGRO, 1); + } + else + npc->Kill(); //On live casts spell 892 Unsummon (Kayen - Too limiting to use that for emu since pet can have more than 20k HP) + } } /* This is why the pets ghost - pets were being spawned too far away from its npc owner and some into walls or objects (+10), this sometimes creates the "ghost" effect. I changed to +2 (as close as I From 356316db8483f65be0b4a197e9039a7fce1007bf Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 3 Feb 2015 07:09:24 -0500 Subject: [PATCH 032/114] Optional SQL to convert all(?) live pets that should use the new pet type (5). --- .../optional/2015_02_15_UpdatePetTypes.sql | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 utils/sql/git/optional/2015_02_15_UpdatePetTypes.sql diff --git a/utils/sql/git/optional/2015_02_15_UpdatePetTypes.sql b/utils/sql/git/optional/2015_02_15_UpdatePetTypes.sql new file mode 100644 index 000000000..29ba3b03e --- /dev/null +++ b/utils/sql/git/optional/2015_02_15_UpdatePetTypes.sql @@ -0,0 +1,50 @@ +-- Updates live pets who should be type (5) - Pet locks onto target until dead. +UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword99Rk3"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword99Rk2"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword99Rk1"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword94Rk3"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword94Rk2"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword94Rk1"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword89Rk3"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword89Rk2"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "WizSwarmSword89Rk1"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk3"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk2"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk1"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_79_Rk3"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_79_Rk2"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_79_Rk1"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_74_"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_67_"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "SumSword"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "SUMHammer4"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "SUMHammer3"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "SUMHammer2"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "SUMHammer1"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "SumHammer"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "Burnout"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "SumSword"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "SumHammer"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_67_"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_73_"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_73_Rk1"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_73_Rk2"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_73_Rk3"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_78_Rk1"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_78_Rk2"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_78_Rk3"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_83_Rk1"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_83_Rk2"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_83_Rk3"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk1"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk2"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "wizard_sword_84_Rk3"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_88_Rk1"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_88_Rk2"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_88_Rk3"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_94_Rk1"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_94_Rk2"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_94_Rk3"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_99_Rk1"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_99_Rk2"; +UPDATE pets SET petcontrol = 5 WHERE type LIKE "cleric_hammer_99_Rk3"; From 33767aeb912f9234b5eb8f1426865275f9c8dcd9 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 3 Feb 2015 07:59:29 -0500 Subject: [PATCH 033/114] Improvements to the pet type (5) code. --- zone/attack.cpp | 6 ------ zone/mob.cpp | 1 + zone/mob.h | 3 +++ zone/npc.cpp | 10 ++++++++++ zone/pets.cpp | 1 + 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index 280eda918..25dc88688 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1508,9 +1508,6 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att } } } - - if (killerMob && killerMob->IsPet() && killerMob->GetPetType() == petTargetLock && killerMob->GetID() != GetID()) - killerMob->Kill(); } entity_list.RemoveFromTargets(this); @@ -2381,9 +2378,6 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack } } - if (killerMob && killerMob->IsPet() && killerMob->GetPetType() == petTargetLock && killerMob->GetID() != GetID()) - killerMob->Kill(); - WipeHateList(); p_depop = true; if(killerMob && killerMob->GetTarget() == this) //we can kill things without having them targeted diff --git a/zone/mob.cpp b/zone/mob.cpp index a54881298..68ed1e35d 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -300,6 +300,7 @@ Mob::Mob(const char* in_name, focused = false; _IsTempPet = false; pet_owner_client = false; + pet_targetlock_id = 0; attacked_count = 0; mezzed = false; diff --git a/zone/mob.h b/zone/mob.h index c2f57ff9c..c37eae706 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -676,6 +676,8 @@ public: bool IsAnimation() const { return(typeofpet == petAnimation); } bool IsCharmed() const { return(typeofpet == petCharmed); } bool IsTargetLockPet() const { return(typeofpet == petTargetLock); } + inline uint32 GetPetTargetLockID() { return pet_targetlock_id; }; + inline void SetPetTargetLockID(uint32 value) { pet_targetlock_id = value; }; void SetOwnerID(uint16 NewOwnerID); inline uint16 GetOwnerID() const { return ownerid; } inline virtual bool HasOwner() { if(GetOwnerID()==0){return false;} return( entity_list.GetMob(GetOwnerID()) != 0); } @@ -1245,6 +1247,7 @@ protected: bool _IsTempPet; int16 count_TempPet; bool pet_owner_client; //Flags regular and pets as belonging to a client + uint32 pet_targetlock_id; EGNode *_egnode; //the EG node we are in glm::vec3 m_TargetLocation; diff --git a/zone/npc.cpp b/zone/npc.cpp index 9a142f128..5d180e994 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -2419,4 +2419,14 @@ void NPC::DepopSwarmPets() } } } + + if (IsPet() && GetPetType() == petTargetLock && GetPetTargetLockID()){ + + Mob *targMob = entity_list.GetMob(GetPetTargetLockID()); + + if(!targMob || (targMob && targMob->IsCorpse())){ + Kill(); + return; + } + } } diff --git a/zone/pets.cpp b/zone/pets.cpp index 38cd16a2a..871e9bc6c 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -434,6 +434,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, if (target){ npc->AddToHateList(target, 1); + npc->SetPetTargetLockID(target->GetID()); npc->SetSpecialAbility(IMMUNE_AGGRO, 1); } else From 8bc5e5eee1b58a795829d4eb89636b53bf98b998 Mon Sep 17 00:00:00 2001 From: Trevius Date: Tue, 3 Feb 2015 17:23:29 -0600 Subject: [PATCH 034/114] Crashfix for TempName() when numbers are passed at the end of the name. --- changelog.txt | 2 ++ zone/mob.cpp | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index d5312dd4e..7ed3f35a7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/03/2015 == +Trevius: Crashfix for TempName() when numbers are passed at the end of the name. == 02/02/2015 == Akkadius: Implement Packet logs with dumps diff --git a/zone/mob.cpp b/zone/mob.cpp index 68ed1e35d..68e18c0db 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -1982,9 +1982,10 @@ void Mob::TempName(const char *newname) strn0cpy(temp_name, GetCleanName(), 64); } + // Remove Numbers before making name unique + EntityList::RemoveNumbers(temp_name); // Make the new name unique and set it - strn0cpy(temp_name, entity_list.MakeNameUnique(temp_name), 64); - + entity_list.MakeNameUnique(temp_name); // Send the new name to all clients EQApplicationPacket* outapp = new EQApplicationPacket(OP_MobRename, sizeof(MobRename_Struct)); From facd7d357db905392010353b553ae82e5640d8eb Mon Sep 17 00:00:00 2001 From: Uleat Date: Tue, 3 Feb 2015 22:43:03 -0500 Subject: [PATCH 035/114] Light source exclusion tweak (helps with strobing effects) --- changelog.txt | 1 + common/item.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 7ed3f35a7..9494adfce 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- == 02/03/2015 == Trevius: Crashfix for TempName() when numbers are passed at the end of the name. +Uleat: Tweaking of item type exclusions to alleviate strobing conditions with light sources == 02/02/2015 == Akkadius: Implement Packet logs with dumps diff --git a/common/item.cpp b/common/item.cpp index a43b5d12b..82da305f1 100644 --- a/common/item.cpp +++ b/common/item.cpp @@ -1011,7 +1011,8 @@ uint8 Inventory::FindHighestLightValue() if (inst == nullptr) { continue; } auto item = inst->GetItem(); if (item == nullptr) { continue; } - if (item->ItemType != ItemTypeMisc && item->ItemType != ItemTypeLight) { continue; } + // 'Gloomingdeep lantern' is ItemTypeArmor in the database..there may be others instances and/or types that need to be handled + if (item->ItemType != ItemTypeMisc && item->ItemType != ItemTypeLight && item->ItemType != ItemTypeArmor) { continue; } if (item->Light & 0xF0) { continue; } if (item->Light > light_value) { light_value = item->Light; } } From cafd0eaba140714dd2f22248fb4aa7fc90b45024 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 4 Feb 2015 22:46:02 -0500 Subject: [PATCH 036/114] Added perl function function: CanClassEquipItem(item_id) Returns a bool if can equip or not. --- zone/mob.cpp | 23 +++++++++++++++++++++++ zone/mob.h | 1 + zone/perl_mob.cpp | 28 ++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/zone/mob.cpp b/zone/mob.cpp index 68ed1e35d..5af690a64 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -5363,3 +5363,26 @@ int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot) return stat; } +bool Mob::CanClassEquipItem(uint32 item_id) +{ + const Item_Struct* itm = nullptr; + itm = database.GetItem(item_id); + + if (!itm) + return false; + + if(itm->Classes == 65535 ) + return true; + + if (GetClass() > 16) + return false; + + int bitmask = 1; + bitmask = bitmask << (GetClass() - 1); + + if(!(itm->Classes & bitmask)) + return false; + else + return true; +} + diff --git a/zone/mob.h b/zone/mob.h index c37eae706..330e8160e 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -315,6 +315,7 @@ public: virtual int32 GetHerosForgeModel(uint8 material_slot) const; virtual uint32 GetEquipmentColor(uint8 material_slot) const; virtual uint32 IsEliteMaterialItem(uint8 material_slot) const; + bool CanClassEquipItem(uint32 item_id); bool AffectedBySpellExcludingSlot(int slot, int effect); virtual bool Death(Mob* killerMob, int32 damage, uint16 spell_id, SkillUseTypes attack_skill) = 0; virtual void Damage(Mob* from, int32 damage, uint16 spell_id, SkillUseTypes attack_skill, diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index f72e98e43..a28d51376 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -8367,6 +8367,33 @@ XS(XS_Mob_ProcessSpecialAbilities) XSRETURN_EMPTY; } +XS(XS_Mob_CanClassEquipItem); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_CanClassEquipItem) +{ + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: Mob::CanClassEquipItem(THIS, item_id)"); + { + Mob * THIS; + bool RETVAL; + uint32 item_id = (uint32)SvUV(ST(1)); + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->CanClassEquipItem(item_id); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + #ifdef __cplusplus extern "C" #endif @@ -8675,6 +8702,7 @@ XS(boot_Mob) newXSproto(strcpy(buf, "SetSpecialAbilityParam"), XS_Mob_SetSpecialAbilityParam, file, "$$$$"); newXSproto(strcpy(buf, "ClearSpecialAbilities"), XS_Mob_ClearSpecialAbilities, file, "$"); newXSproto(strcpy(buf, "ProcessSpecialAbilities"), XS_Mob_ProcessSpecialAbilities, file, "$$"); + newXSproto(strcpy(buf, "CanClassEquipItem"), XS_Mob_CanClassEquipItem, file, "$$"); XSRETURN_YES; } From dd17597c923b48a3a6753d1a51715e5fcd6b53e2 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 5 Feb 2015 04:27:33 -0500 Subject: [PATCH 037/114] Implemented non-live like feature to allow focus effects to be placed in worn slot to provide an additive focus bonus that stacks with regular focus effects. This is opposed to how regular focus effects work in which the highest value is always taken. Please note, focus calculated from worn slot will only use only the focuses base value (ie ignores all limit checks). Example (Hypothetical). Improved Heal I (10 pct focus) in Helm Worn Slot Improved Heal I (10 pct focus) in Glove Worn Slot Improved Heal V (50 pct focus) in Glove Focus Slot Total Heal Focus would be 50 + 10 + 10 Added optional rule which is OFF by default. UseAdditiveFocusFromWornSlot --- common/ruletypes.h | 1 + zone/bonuses.cpp | 17 +++++++++++------ zone/common.h | 3 ++- zone/mob.h | 2 +- zone/spell_effects.cpp | 7 ++++++- 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 18fb3ba3e..ff88115e2 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -329,6 +329,7 @@ RULE_BOOL ( Spells, Jun182014HundredHandsRevamp, false) // this should be true f RULE_BOOL ( Spells, SwarmPetTargetLock, false) // Use old method of swarm pets target locking till target dies then despawning. RULE_BOOL ( Spells, NPC_UseFocusFromSpells, true) // Allow npcs to use most spell derived focus effects. RULE_BOOL ( Spells, NPC_UseFocusFromItems, false) // Allow npcs to use most item derived focus effects. +RULE_BOOL ( Spells, UseAdditiveFocusFromWornSlot, false) // Allows an additive focus effect to be calculated from worn slot. RULE_CATEGORY_END() RULE_CATEGORY( Combat ) diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 8cceb5023..4aa13519b 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -411,11 +411,11 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu newbon->DSMitigation += item->DSMitigation; } if (item->Worn.Effect>0 && (item->Worn.Type == ET_WornEffect)) { // latent effects - ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, true); + ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, true, true); } if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects - ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0, true); + ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0, true, false); } switch(item->BardType) @@ -639,7 +639,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) uint8 focus = IsFocusEffect(0, 0, true,effect); if (focus) { - newbon->FocusEffects[focus] = effect; + newbon->FocusEffects[focus] = static_cast(effect); continue; } @@ -1393,7 +1393,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon) int buff_count = GetMaxTotalSlots(); for(i = 0; i < buff_count; i++) { if(buffs[i].spellid != SPELL_UNKNOWN){ - ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, false, buffs[i].ticsremaining,i); + ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, false, false, buffs[i].ticsremaining,i); if (buffs[i].numhits > 0) Numhits(true); @@ -1416,7 +1416,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon) if (GetClass() == BARD) newbon->ManaRegen = 0; // Bards do not get mana regen from spells. } -void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, bool item_bonus, uint32 ticsremaining, int buffslot, +void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, bool item_bonus, bool IsWornEffect, uint32 ticsremaining, int buffslot, bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max) { int i, effect_value, base2, max, effectid; @@ -1439,7 +1439,12 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne uint8 focus = IsFocusEffect(spell_id, i); if (focus) { - new_bonus->FocusEffects[focus] = spells[spell_id].effectid[i]; + if (!IsWornEffect) + new_bonus->FocusEffects[focus] = static_cast(spells[spell_id].effectid[i]); + + else if (RuleB(Spells, UseAdditiveFocusFromWornSlot)) + new_bonus->FocusEffectsWorn[focus] += spells[spell_id].base[i]; + continue; } diff --git a/zone/common.h b/zone/common.h index 20d19e94d..639eee91e 100644 --- a/zone/common.h +++ b/zone/common.h @@ -350,7 +350,8 @@ struct StatBonuses { int32 CharmBreakChance; // chance to break charm int32 SongRange; // increases range of beneficial bard songs uint32 HPToManaConvert; // Uses HP to cast spells at specific conversion - uint32 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have. + uint8 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have. + int16 FocusEffectsWorn[HIGHEST_FOCUS+1]; // Optional to allow focus effects to be applied additively from worn slot bool NegateEffects; // Check if you contain a buff with negate effect. (only spellbonuses) int32 SkillDamageAmount2[HIGHEST_SKILL+2]; // Adds skill specific damage uint32 NegateAttacks[3]; // 0 = bool HasEffect 1 = Buff Slot 2 = Max damage absorbed per hit diff --git a/zone/mob.h b/zone/mob.h index 330e8160e..41aa5783b 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -194,7 +194,7 @@ public: bool IsBeneficialAllowed(Mob *target); virtual int GetCasterLevel(uint16 spell_id); void ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* newbon, uint16 casterID = 0, - bool item_bonus = false, uint32 ticsremaining = 0, int buffslot = -1, + bool item_bonus = false, bool IsWornEffect = false, uint32 ticsremaining = 0, int buffslot = -1, bool IsAISpellEffect = false, uint16 effect_id = 0, int32 se_base = 0, int32 se_limit = 0, int32 se_max = 0); void NegateSpellsBonuses(uint16 spell_id); virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index a6725b296..24eac51ee 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -5527,7 +5527,12 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) { //Summon Spells that require reagents are typically imbue type spells, enchant metal, sacrifice and shouldn't be affected //by reagent conservation for obvious reasons. - return realTotal + realTotal2 + realTotal3; + //Non-Live like feature to allow for an additive focus bonus to be applied from foci that are placed in worn slot. (No limit checks) + int16 worneffect_bonus = 0; + if (RuleB(Spells, UseAdditiveFocusFromWornSlot)) + worneffect_bonus = itembonuses.FocusEffectsWorn[type]; + + return realTotal + realTotal2 + realTotal3 + worneffect_bonus; } int16 NPC::GetFocusEffect(focusType type, uint16 spell_id) { From 1495eb42a34b402f01e31a97815e2f466ce28c6c Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 5 Feb 2015 04:27:52 -0500 Subject: [PATCH 038/114] sql --- utils/sql/git/optional/2015_2_5_UseAdditiveFocusFromWornSlot.sql | 1 + 1 file changed, 1 insertion(+) create mode 100644 utils/sql/git/optional/2015_2_5_UseAdditiveFocusFromWornSlot.sql diff --git a/utils/sql/git/optional/2015_2_5_UseAdditiveFocusFromWornSlot.sql b/utils/sql/git/optional/2015_2_5_UseAdditiveFocusFromWornSlot.sql new file mode 100644 index 000000000..905dcc163 --- /dev/null +++ b/utils/sql/git/optional/2015_2_5_UseAdditiveFocusFromWornSlot.sql @@ -0,0 +1 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:UseAdditiveFocusFromWornSlot', 'false', '[Not live like] If a focus effect is placed in a worn slot the base value will calculated as an additive bonus to regular focus effects.'); From dce6ccf4dee09f6108fb63915c74c079cfed82b6 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Thu, 5 Feb 2015 05:43:36 -0600 Subject: [PATCH 039/114] GetTaskActivityDoneCountFromTaskID crash fix --- zone/tasks.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/zone/tasks.cpp b/zone/tasks.cpp index 59c6f50eb..98a0ec4c5 100644 --- a/zone/tasks.cpp +++ b/zone/tasks.cpp @@ -2872,7 +2872,13 @@ int ClientTaskState::GetTaskActivityDoneCountFromTaskID(int TaskID, int Activity break; } } - return ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount; + + if (ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount){ + return ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount; + } + else{ + return 0; + } } int ClientTaskState::GetTaskStartTime(int index) { From ef5d4759786b15bd39c286de3589b1d50f5275b4 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Thu, 5 Feb 2015 06:05:49 -0600 Subject: [PATCH 040/114] Correct db manifest [skip ci] --- utils/sql/db_update_manifest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index dee4a4a12..f23638a07 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -329,7 +329,7 @@ 9073|2015_01_31_character_item_recast.sql|SHOW TABLES LIKE 'character_item_recast'|empty| 9074|2015_02_01_logsys_packet_logs.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client'|empty| 9075|2015_02_02_logsys_packet_logs_with_dump.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client With Dump'|empty| -9076|2014_10_30_special_abilities_null.sql|SHOW COLUMNS FROM `loottable` WHERE Field = 'avgcoin'|contains|smallint +9076|2015_02_04_average_coin.sql|SHOW COLUMNS FROM `loottable` WHERE Field = 'avgcoin'|contains|smallint # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not From 36d53f69d66f169b6d1b4e9c73a12f2b394a8a45 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 5 Feb 2015 18:11:38 -0500 Subject: [PATCH 041/114] Fix query in Database::SetRaidGroupLeaderInfo --- common/database.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/database.cpp b/common/database.cpp index 736104f6e..31566d82f 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -1984,7 +1984,7 @@ void Database::GetRaidLeadershipInfo(uint32 rid, char *maintank, void Database::SetRaidGroupLeaderInfo(uint32 gid, uint32 rid) { - std::string query = StringFormat("UPDATE raid_leaders SET leadershipaa = '', WHERE gid = %lu AND rid = %lu", + std::string query = StringFormat("UPDATE raid_leaders SET leadershipaa = '' WHERE gid = %lu AND rid = %lu", (unsigned long)gid, (unsigned long)rid); auto results = QueryDatabase(query); @@ -2172,4 +2172,4 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) Log.file_logs_enabled = true; } } -} \ No newline at end of file +} From b96e5a7f4d0087d98e186c45ee05b5aa5bf4dba0 Mon Sep 17 00:00:00 2001 From: JJ Date: Thu, 5 Feb 2015 19:18:51 -0500 Subject: [PATCH 042/114] Group leader is not always member 0. --- zone/groups.h | 4 ++-- zone/perl_groups.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/zone/groups.h b/zone/groups.h index 909a9dd53..71935bf81 100644 --- a/zone/groups.h +++ b/zone/groups.h @@ -72,8 +72,8 @@ public: uint32 GetTotalGroupDamage(Mob* other); void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr); inline void SetLeader(Mob* newleader){ leader=newleader; }; - inline Mob* GetLeader(){ return leader; }; - char* GetLeaderName() { return membername[0]; }; + inline Mob* GetLeader() { return leader; }; + const char* GetLeaderName() { return leader->GetName(); }; void SendHPPacketsTo(Mob* newmember); void SendHPPacketsFrom(Mob* newmember); bool UpdatePlayer(Mob* update); diff --git a/zone/perl_groups.cpp b/zone/perl_groups.cpp index 6960d14df..cdbffdd1c 100644 --- a/zone/perl_groups.cpp +++ b/zone/perl_groups.cpp @@ -342,8 +342,8 @@ XS(XS_Group_GetLeaderName) if (items != 1) Perl_croak(aTHX_ "Usage: Group::GetLeaderName(THIS)"); { - Group * THIS; - char * RETVAL; + Group * THIS; + const char * RETVAL; dXSTARG; if (sv_derived_from(ST(0), "Group")) { From f26d303ee1824e5a2099cff4abaa3a21c52d21ac Mon Sep 17 00:00:00 2001 From: Trevius Date: Thu, 5 Feb 2015 22:34:55 -0600 Subject: [PATCH 043/114] Fixed Environmental Damage for RoF2. --- changelog.txt | 3 +++ common/patches/rof2_structs.h | 5 +++-- zone/client_packet.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9494adfce..6e37c6513 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/05/2015 == +Trevius: Fixed Environmental Damage for RoF2. + == 02/03/2015 == Trevius: Crashfix for TempName() when numbers are passed at the end of the name. Uleat: Tweaking of item type exclusions to alleviate strobing conditions with light sources diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index dd9bfb587..9ef524f55 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -2865,7 +2865,7 @@ struct SetRunMode_Struct { }; // EnvDamage is EnvDamage2 without a few bytes at the end. -// Size: 37 bytes +// Size: 39 bytes struct EnvDamage2_Struct { /*0000*/ uint32 id; /*0004*/ uint16 unknown4; @@ -2877,7 +2877,8 @@ struct EnvDamage2_Struct { /*0031*/ uint16 unknown31; // New to Underfoot - Seen 66 /*0033*/ uint16 constant; // Always FFFF /*0035*/ uint16 unknown35; -/*0037*/ +/*0037*/ uint16 unknown37; +/*0039*/ }; //Bazaar Stuff diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 331c50435..95475f1ca 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -5516,7 +5516,7 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app) if (damage < 0) damage = 31337; - if (admin >= minStatusToAvoidFalling && GetGM()){ + if (admin >= minStatusToAvoidFalling && GetGM()) { Message(13, "Your GM status protects you from %i points of type %i environmental damage.", ed->damage, ed->dmgtype); SetHP(GetHP() - 1);//needed or else the client wont acknowledge return; @@ -5526,11 +5526,11 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app) SetHP(GetHP() - 1);//needed or else the client wont acknowledge return; } - - else if (zone->GetZoneID() == 183 || zone->GetZoneID() == 184){ + else if (zone->GetZoneID() == 183 || zone->GetZoneID() == 184) { + // Hard coded tutorial and load zones for no fall damage return; } - else{ + else { SetHP(GetHP() - (damage * RuleR(Character, EnvironmentDamageMulipliter))); /* EVENT_ENVIRONMENTAL_DAMAGE */ From bc6199a86f6cf2f5b51a1783ec2686bb4a6c889e Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Fri, 6 Feb 2015 02:49:42 -0500 Subject: [PATCH 044/114] Implemented a better method for developers who want to have additivie worn bonuses than what was prior implemented. Removed old rule RuleB(Spells, AdditiveBonusValues) Replaced with new rule RuleI(AdditiveBonusWornType) The rule value denotes a specific 'worntype' that is to be checked on items. If the items 'worntype' matches the rules worntype then any worn effect on that item will be cacluated additively instead of taking the highest value. This will also stack with regular worn effects that take highest value. Unless the value is set to (2) which is what all live items use. If set to 2 then all worn effects will be calculated additively (same as what the old rule did). In laymans terms. You can take 3 Cleave I items and put them on a character and they will all add together if you set the worn type = 3 and the rule = 3. Which would also add to any regular cleave set to worn type = 2. Hope you enjoyed the novel. --- common/ruletypes.h | 2 +- .../2015_2_6_AdditiveBonusWornType.sql | 4 + zone/bonuses.cpp | 106 +++++++++++++----- zone/bot.cpp | 4 +- zone/client.h | 1 + zone/merc.cpp | 4 +- zone/mob.h | 2 +- zone/mob_ai.cpp | 2 +- 8 files changed, 92 insertions(+), 33 deletions(-) create mode 100644 utils/sql/git/optional/2015_2_6_AdditiveBonusWornType.sql diff --git a/common/ruletypes.h b/common/ruletypes.h index ff88115e2..12a8a0737 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -300,7 +300,7 @@ RULE_INT ( Spells, MaxCastTimeReduction, 50) //Max percent your spell cast time RULE_INT ( Spells, RootBreakFromSpells, 55) //Chance for root to break when cast on. RULE_INT ( Spells, DeathSaveCharismaMod, 3) //Determines how much charisma effects chance of death save firing. RULE_INT ( Spells, DivineInterventionHeal, 8000) //Divine intervention heal amount. -RULE_BOOL ( Spells, AdditiveBonusValues, false) //Allow certain bonuses to be calculated by adding together the value from each item, instead of taking the highest value. (ie Add together all Cleave Effects) +RULE_INT ( Spells, AdditiveBonusWornType, 0) //Calc worn bonuses to add together (instead of taking highest) if set to THIS worn type. (2=Will covert live items automatically) RULE_BOOL ( Spells, UseCHAScribeHack, false) //ScribeSpells and TrainDiscs quest functions will ignore entries where field 12 is CHA. What's the best way to do this? RULE_BOOL ( Spells, BuffLevelRestrictions, true) //Buffs will not land on low level toons like live RULE_INT ( Spells, RootBreakCheckChance, 70) //Determines chance for a root break check to occur each buff tick. diff --git a/utils/sql/git/optional/2015_2_6_AdditiveBonusWornType.sql b/utils/sql/git/optional/2015_2_6_AdditiveBonusWornType.sql new file mode 100644 index 000000000..aab88bd9f --- /dev/null +++ b/utils/sql/git/optional/2015_2_6_AdditiveBonusWornType.sql @@ -0,0 +1,4 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:AdditiveBonusWornType', '0', 'Calcs worn bonuses to add together (instead of taking highest) if item set to THIS worn type. Will stack with regular worn bonuses. (2=Will cause all live items to use this behavior)'); + +-- This is no longer used - Set the above value equal to 2 to achieve the same effect. +DELETE FROM `rule_values` WHERE rule_name LIKE "Spells:AdditiveBonusValues"; diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 4aa13519b..ea3174a54 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -169,6 +169,17 @@ void Client::CalcItemBonuses(StatBonuses* newbon) { continue; AddItemBonuses(inst, newbon, false, true); } + + //Optional ability to have worn effects calculate as an addititive bonus instead of highest value + if (RuleI(Spells, AdditiveBonusWornType) && RuleI(Spells, AdditiveBonusWornType) != ET_WornEffect){ + for (i = MainCharm; i < MainAmmo; i++) { + const ItemInst* inst = m_inv[i]; + if(inst == 0) + continue; + AdditiveWornBonuses(inst, newbon); + } + } + // Caps if(newbon->HPRegen > CalcHPRegenCap()) newbon->HPRegen = CalcHPRegenCap(); @@ -410,12 +421,12 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu else newbon->DSMitigation += item->DSMitigation; } - if (item->Worn.Effect>0 && (item->Worn.Type == ET_WornEffect)) { // latent effects - ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, true, true); + if (item->Worn.Effect > 0 && item->Worn.Type == ET_WornEffect) {// latent effects + ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type); } if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects - ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0, true, false); + ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0); } switch(item->BardType) @@ -537,6 +548,45 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu } +void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug) { + + /* + Powerful Non-live like option allows developers to add worn effects on items that + can stack with other worn effects of the same spell effect type, instead of only taking the highest value. + Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120 pct cleave bonus. + To enable use RuleI(Spells, AdditiveBonusWornType) + Setting value = 2 Will force all live items to automatically be calculated additivily + Setting value to anything else will indicate the item 'worntype' that if set to the same, will cause the bonuses to use this calculation + which will also stack with regular (worntype 2) effects. [Ie set rule = 3 and item worntype = 3] + */ + + if(!inst || !inst->IsType(ItemClassCommon)) + return; + + if(inst->GetAugmentType()==0 && isAug == true) + return; + + const Item_Struct *item = inst->GetItem(); + + if(!inst->IsEquipable(GetBaseRace(),GetClass())) + return; + + if(GetLevel() < item->ReqLevel) + return; + + if (item->Worn.Effect > 0 && item->Worn.Type == RuleI(Spells, AdditiveBonusWornType)) + ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);// Non-live like - Addititive latent effects + + + if (!isAug) + { + int i; + for (i = 0; i < EmuConstants::ITEM_COMMON_SIZE; i++) { + AdditiveWornBonuses(inst->GetAugment(i),newbon,true); + } + } +} + void Client::CalcEdibleBonuses(StatBonuses* newbon) { uint32 i; @@ -1393,7 +1443,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon) int buff_count = GetMaxTotalSlots(); for(i = 0; i < buff_count; i++) { if(buffs[i].spellid != SPELL_UNKNOWN){ - ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, false, false, buffs[i].ticsremaining,i); + ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, false,0, buffs[i].ticsremaining,i); if (buffs[i].numhits > 0) Numhits(true); @@ -1416,10 +1466,11 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon) if (GetClass() == BARD) newbon->ManaRegen = 0; // Bards do not get mana regen from spells. } -void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, bool item_bonus, bool IsWornEffect, uint32 ticsremaining, int buffslot, +void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, uint8 WornType, uint32 ticsremaining, int buffslot, bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max) { int i, effect_value, base2, max, effectid; + bool AdditiveWornBonus = false; Mob *caster = nullptr; if(!IsAISpellEffect && !IsValidSpell(spell_id)) @@ -1439,15 +1490,19 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne uint8 focus = IsFocusEffect(spell_id, i); if (focus) { - if (!IsWornEffect) - new_bonus->FocusEffects[focus] = static_cast(spells[spell_id].effectid[i]); + if (WornType){ + if (RuleB(Spells, UseAdditiveFocusFromWornSlot)) + new_bonus->FocusEffectsWorn[focus] += spells[spell_id].base[i]; + } - else if (RuleB(Spells, UseAdditiveFocusFromWornSlot)) - new_bonus->FocusEffectsWorn[focus] += spells[spell_id].base[i]; + else + new_bonus->FocusEffects[focus] = static_cast(spells[spell_id].effectid[i]); continue; } + if (WornType && (RuleI(Spells, AdditiveBonusWornType) == WornType)) + AdditiveWornBonus = true; effectid = spells[spell_id].effectid[i]; effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, caster, ticsremaining); @@ -1813,7 +1868,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_CriticalHitChance: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus) { + if (AdditiveWornBonus) { if(base2 == -1) new_bonus->CriticalHitChance[HIGHEST_SKILL+1] += effect_value; else @@ -1839,7 +1894,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_CrippBlowChance: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus) + if (AdditiveWornBonus) new_bonus->CrippBlowChance += effect_value; else if((effect_value < 0) && (new_bonus->CrippBlowChance > effect_value)) @@ -1853,7 +1908,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_AvoidMeleeChance: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus) + if (AdditiveWornBonus) new_bonus->AvoidMeleeChanceEffect += effect_value; else if((effect_value < 0) && (new_bonus->AvoidMeleeChanceEffect > effect_value)) @@ -1866,7 +1921,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_RiposteChance: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus) + if (AdditiveWornBonus) new_bonus->RiposteChance += effect_value; else if((effect_value < 0) && (new_bonus->RiposteChance > effect_value)) @@ -1879,7 +1934,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_DodgeChance: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus) + if (AdditiveWornBonus) new_bonus->DodgeChance += effect_value; else if((effect_value < 0) && (new_bonus->DodgeChance > effect_value)) @@ -1892,7 +1947,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_ParryChance: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus) + if (AdditiveWornBonus) new_bonus->ParryChance += effect_value; else if((effect_value < 0) && (new_bonus->ParryChance > effect_value)) @@ -1905,7 +1960,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_DualWieldChance: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus) + if (AdditiveWornBonus) new_bonus->DualWieldChance += effect_value; else if((effect_value < 0) && (new_bonus->DualWieldChance > effect_value)) @@ -1919,7 +1974,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_DoubleAttackChance: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus) + if (AdditiveWornBonus) new_bonus->DoubleAttackChance += effect_value; else if((effect_value < 0) && (new_bonus->DoubleAttackChance > effect_value)) @@ -1933,7 +1988,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_TripleAttackChance: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus) + if (AdditiveWornBonus) new_bonus->TripleAttackChance += effect_value; else if((effect_value < 0) && (new_bonus->TripleAttackChance > effect_value)) @@ -1946,7 +2001,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_MeleeLifetap: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus) + if (AdditiveWornBonus) new_bonus->MeleeLifetap += spells[spell_id].base[i]; else if((effect_value < 0) && (new_bonus->MeleeLifetap > effect_value)) @@ -1995,7 +2050,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_HundredHands: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus) + if (AdditiveWornBonus) new_bonus->HundredHands += effect_value; if (effect_value > 0 && effect_value > new_bonus->HundredHands) @@ -2017,7 +2072,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_HitChance: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus){ + if (AdditiveWornBonus){ if(base2 == -1) new_bonus->HitChanceEffect[HIGHEST_SKILL+1] += effect_value; else @@ -2084,7 +2139,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_ProcChance: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus) + if (AdditiveWornBonus) new_bonus->ProcChanceSPA += effect_value; else if((effect_value < 0) && (new_bonus->ProcChanceSPA > effect_value)) @@ -2122,7 +2177,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_DivineSave: { - if (RuleB(Spells, AdditiveBonusValues) && item_bonus) { + if (AdditiveWornBonus) { new_bonus->DivineSaveChance[0] += effect_value; new_bonus->DivineSaveChance[1] = 0; } @@ -2131,7 +2186,6 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne { new_bonus->DivineSaveChance[0] = effect_value; new_bonus->DivineSaveChance[1] = base2; - //SetDeathSaveChance(true); } break; } @@ -3051,12 +3105,12 @@ void NPC::CalcItemBonuses(StatBonuses *newbon) newbon->ProcChance += cur->CombatEffects; } if (cur->Worn.Effect>0 && (cur->Worn.Type == ET_WornEffect)) { // latent effects - ApplySpellsBonuses(cur->Worn.Effect, cur->Worn.Level, newbon); + ApplySpellsBonuses(cur->Worn.Effect, cur->Worn.Level, newbon, cur->Worn.Type); } if (RuleB(Spells, NPC_UseFocusFromItems)){ if (cur->Focus.Effect>0 && (cur->Focus.Type == ET_Focus)){ // focus effects - ApplySpellsBonuses(cur->Focus.Effect, cur->Focus.Level, newbon, 0, true); + ApplySpellsBonuses(cur->Focus.Effect, cur->Focus.Level, newbon); } } diff --git a/zone/bot.cpp b/zone/bot.cpp index c39696576..4b42fac37 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -10959,7 +10959,7 @@ void Bot::CalcItemBonuses() } } if ((itemtmp->Worn.Effect != 0) && (itemtmp->Worn.Type == ET_WornEffect)) { // latent effects - ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses); + ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses,0,itemtmp->Worn.Type); } } } @@ -11043,7 +11043,7 @@ void Bot::CalcItemBonuses() } } if ((itemtmp->Worn.Effect != 0) && (itemtmp->Worn.Type == ET_WornEffect)) { // latent effects - ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses); + ApplySpellsBonuses(itemtmp->Worn.Effect, itemtmp->Worn.Level, &itembonuses,0,itemtmp->Worn.Type); } } } diff --git a/zone/client.h b/zone/client.h index 9248fb742..a2cb823f1 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1257,6 +1257,7 @@ protected: friend class Mob; void CalcItemBonuses(StatBonuses* newbon); void AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false); + void AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false); int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat); void CalcEdibleBonuses(StatBonuses* newbon); void CalcAABonuses(StatBonuses* newbon); diff --git a/zone/merc.cpp b/zone/merc.cpp index 2fea4aba4..059ccb316 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -449,11 +449,11 @@ void Merc::AddItemBonuses(const Item_Struct *item, StatBonuses* newbon) { newbon->DSMitigation += item->DSMitigation; } if (item->Worn.Effect>0 && (item->Worn.Type == ET_WornEffect)) { // latent effects - ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, true); + ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type); } if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects - ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0, true); + ApplySpellsBonuses(item->Focus.Effect, item->Focus.Level, newbon, 0); } switch(item->BardType) diff --git a/zone/mob.h b/zone/mob.h index 46531b819..e7318007e 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -194,7 +194,7 @@ public: bool IsBeneficialAllowed(Mob *target); virtual int GetCasterLevel(uint16 spell_id); void ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* newbon, uint16 casterID = 0, - bool item_bonus = false, bool IsWornEffect = false, uint32 ticsremaining = 0, int buffslot = -1, + uint8 WornType = 0, uint32 ticsremaining = 0, int buffslot = -1, bool IsAISpellEffect = false, uint16 effect_id = 0, int32 se_base = 0, int32 se_limit = 0, int32 se_max = 0); void NegateSpellsBonuses(uint16 spell_id); virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false); diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 371a8e523..452ca71fd 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -2559,7 +2559,7 @@ void NPC::ApplyAISpellEffects(StatBonuses* newbon) for(int i=0; i < AIspellsEffects.size(); i++) { - ApplySpellsBonuses(0, 0, newbon, 0, false, 0,-1, + ApplySpellsBonuses(0, 0, newbon, 0, 0, 0,-1, true, AIspellsEffects[i].spelleffectid, AIspellsEffects[i].base, AIspellsEffects[i].limit,AIspellsEffects[i].max); } From 2bf2485b4c66ae9e6a8e7e35bf93fcdac09b3cea Mon Sep 17 00:00:00 2001 From: Uleat Date: Fri, 6 Feb 2015 07:57:15 -0500 Subject: [PATCH 045/114] Enforced const_interator returns on const_iterator return types in Inventory and ItemInst --- changelog.txt | 3 +++ common/item.cpp | 22 +++++++++++----------- common/item.h | 12 ++++++------ zone/client_packet.cpp | 4 ++-- zone/command.cpp | 2 +- zone/corpse.cpp | 4 ++-- zone/inventory.cpp | 26 +++++++++++++------------- 7 files changed, 38 insertions(+), 35 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9494adfce..8d28ad3de 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/06/2015 == +Uleat: Updated returns for Inventory and ItemInst const iterators. (const == const) + == 02/03/2015 == Trevius: Crashfix for TempName() when numbers are passed at the end of the name. Uleat: Tweaking of item type exclusions to alleviate strobing conditions with light sources diff --git a/common/item.cpp b/common/item.cpp index 82da305f1..4119c7058 100644 --- a/common/item.cpp +++ b/common/item.cpp @@ -1060,7 +1060,7 @@ int Inventory::GetSlotByItemInstCollection(const std::map &col } if (t_inst && !t_inst->IsType(ItemClassContainer)) { - for (auto b_iter = t_inst->_begin(); b_iter != t_inst->_end(); ++b_iter) { + for (auto b_iter = t_inst->_cbegin(); b_iter != t_inst->_cend(); ++b_iter) { if (b_iter->second == inst) { return Inventory::CalcSlotId(iter->first, b_iter->first); } @@ -1095,7 +1095,7 @@ void Inventory::dumpBagContents(ItemInst *inst, iter_inst *it) { return; // Go through bag, if bag - for (itb = inst->_begin(); itb != inst->_end(); ++itb) { + for (itb = inst->_cbegin(); itb != inst->_cend(); ++itb) { ItemInst* baginst = itb->second; if (!baginst || !baginst->GetItem()) continue; @@ -1204,7 +1204,7 @@ int16 Inventory::_HasItem(std::map& bucket, uint32 item_id, ui if (!inst->IsType(ItemClassContainer)) { continue; } - for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) { + for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) { auto bag_inst = bag_iter->second; if (bag_inst == nullptr) { continue; } @@ -1235,7 +1235,7 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity) uint8 quantity_found = 0; - for (auto iter = iqueue.begin(); iter != iqueue.end(); ++iter) { + for (auto iter = iqueue.cbegin(); iter != iqueue.cend(); ++iter) { auto inst = *iter; if (inst == nullptr) { continue; } @@ -1252,7 +1252,7 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity) if (!inst->IsType(ItemClassContainer)) { continue; } - for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) { + for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) { auto bag_inst = bag_iter->second; if (bag_inst == nullptr) { continue; } @@ -1289,7 +1289,7 @@ int16 Inventory::_HasItemByUse(std::map& bucket, uint8 use, ui if (!inst->IsType(ItemClassContainer)) { continue; } - for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) { + for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) { auto bag_inst = bag_iter->second; if (bag_inst == nullptr) { continue; } @@ -1309,7 +1309,7 @@ int16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity) { uint8 quantity_found = 0; - for (auto iter = iqueue.begin(); iter != iqueue.end(); ++iter) { + for (auto iter = iqueue.cbegin(); iter != iqueue.cend(); ++iter) { auto inst = *iter; if (inst == nullptr) { continue; } @@ -1321,7 +1321,7 @@ int16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity) if (!inst->IsType(ItemClassContainer)) { continue; } - for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) { + for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) { auto bag_inst = bag_iter->second; if (bag_inst == nullptr) { continue; } @@ -1355,7 +1355,7 @@ int16 Inventory::_HasItemByLoreGroup(std::map& bucket, uint32 if (!inst->IsType(ItemClassContainer)) { continue; } - for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) { + for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) { auto bag_inst = bag_iter->second; if (bag_inst == nullptr) { continue; } @@ -1378,7 +1378,7 @@ int16 Inventory::_HasItemByLoreGroup(std::map& bucket, uint32 // Internal Method: Checks an inventory queue type bucket for a particular item int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup) { - for (auto iter = iqueue.begin(); iter != iqueue.end(); ++iter) { + for (auto iter = iqueue.cbegin(); iter != iqueue.cend(); ++iter) { auto inst = *iter; if (inst == nullptr) { continue; } @@ -1395,7 +1395,7 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup) if (!inst->IsType(ItemClassContainer)) { continue; } - for (auto bag_iter = inst->_begin(); bag_iter != inst->_end(); ++bag_iter) { + for (auto bag_iter = inst->_cbegin(); bag_iter != inst->_cend(); ++bag_iter) { auto bag_inst = bag_iter->second; if (bag_inst == nullptr) { continue; } diff --git a/common/item.h b/common/item.h index fd30b5ea0..8554d1c55 100644 --- a/common/item.h +++ b/common/item.h @@ -86,8 +86,8 @@ public: // Public Methods ///////////////////////// - inline std::list::const_iterator begin() { return m_list.begin(); } - inline std::list::const_iterator end() { return m_list.end(); } + inline std::list::const_iterator cbegin() { return m_list.cbegin(); } + inline std::list::const_iterator cend() { return m_list.cend(); } inline int size() { return static_cast(m_list.size()); } // TODO: change to size_t inline bool empty() { return m_list.empty(); } @@ -140,8 +140,8 @@ public: ItemInst* GetItem(int16 slot_id) const; ItemInst* GetItem(int16 slot_id, uint8 bagidx) const; - inline std::list::const_iterator cursor_begin() { return m_cursor.begin(); } - inline std::list::const_iterator cursor_end() { return m_cursor.end(); } + inline std::list::const_iterator cursor_cbegin() { return m_cursor.cbegin(); } + inline std::list::const_iterator cursor_cend() { return m_cursor.cend(); } inline int CursorSize() { return m_cursor.size(); } inline bool CursorEmpty() { return m_cursor.empty(); } @@ -425,8 +425,8 @@ protected: ////////////////////////// // Protected Members ////////////////////////// - iter_contents _begin() { return m_contents.begin(); } - iter_contents _end() { return m_contents.end(); } + iter_contents _cbegin() { return m_contents.cbegin(); } + iter_contents _cend() { return m_contents.cend(); } friend class Inventory; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 331c50435..40dc0e35a 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1838,9 +1838,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) if (loaditems) { /* Dont load if a length error occurs */ BulkSendInventoryItems(); /* Send stuff on the cursor which isnt sent in bulk */ - for (auto iter = m_inv.cursor_begin(); iter != m_inv.cursor_end(); ++iter) { + for (auto iter = m_inv.cursor_cbegin(); iter != m_inv.cursor_cend(); ++iter) { /* First item cursor is sent in bulk inventory packet */ - if (iter == m_inv.cursor_begin()) + if (iter == m_inv.cursor_cbegin()) continue; const ItemInst *inst = *iter; SendItemPacket(MainCursor, inst, ItemPacketSummonItem); diff --git a/zone/command.cpp b/zone/command.cpp index c34bc1b9d..622f1d973 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -2618,7 +2618,7 @@ void command_peekinv(Client *c, const Seperator *sep) } else { int cursorDepth = 0; - for (auto it = targetClient->GetInv().cursor_begin(); (it != targetClient->GetInv().cursor_end()); ++it, ++cursorDepth) { + for (auto it = targetClient->GetInv().cursor_cbegin(); (it != targetClient->GetInv().cursor_cend()); ++it, ++cursorDepth) { inst_main = *it; item_data = (inst_main == nullptr) ? nullptr : inst_main->GetItem(); linker.SetItemInst(inst_main); diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 0dd4ed1f3..9f91b584b 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -361,8 +361,8 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob ( database.QueryDatabase(ss.str().c_str()); } - auto start = client->GetInv().cursor_begin(); - auto finish = client->GetInv().cursor_end(); + auto start = client->GetInv().cursor_cbegin(); + auto finish = client->GetInv().cursor_cend(); database.SaveCursor(client->CharacterID(), start, finish); client->CalcBonuses(); diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 1da2fb13d..94138fbe5 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -619,7 +619,7 @@ void Client::DropItem(int16 slot_id) // Save client inventory change to database if (slot_id == MainCursor) { SendCursorBuffer(); - auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); database.SaveCursor(CharacterID(), s, e); } else { database.SaveInventory(CharacterID(), nullptr, slot_id); @@ -772,7 +772,7 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd const ItemInst* inst = nullptr; if (slot_id == MainCursor) { - auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); if(update_db) database.SaveCursor(character_id, s, e); } @@ -826,7 +826,7 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update) SendItemPacket(MainCursor, &inst, ItemPacketSummonItem); } - auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); return database.SaveCursor(CharacterID(), s, e); } @@ -851,7 +851,7 @@ bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client } if (slot_id == MainCursor) { - auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); return database.SaveCursor(this->CharacterID(), s, e); } else { @@ -870,7 +870,7 @@ void Client::PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootI SendLootItemInPacket(&inst, slot_id); if (slot_id == MainCursor) { - auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); database.SaveCursor(this->CharacterID(), s, e); } else { @@ -1009,7 +1009,7 @@ void Client::MoveItemCharges(ItemInst &from, int16 to_slot, uint8 type) from.SetCharges(from.GetCharges() - charges_to_move); SendLootItemInPacket(tmp_inst, to_slot); if (to_slot == MainCursor) { - auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); database.SaveCursor(this->CharacterID(), s, e); } else { @@ -1567,7 +1567,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { { SendCursorBuffer(); } - auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); database.SaveCursor(character_id, s, e); } else @@ -1726,7 +1726,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { { SendCursorBuffer(); } - auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); database.SaveCursor(character_id, s, e); } else { @@ -1734,7 +1734,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { } if (dst_slot_id == MainCursor) { - auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); database.SaveCursor(character_id, s, e); } else { @@ -2170,7 +2170,7 @@ void Client::RemoveNoRent(bool client_update) } local.clear(); - auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); database.SaveCursor(this->CharacterID(), s, e); } } @@ -2298,7 +2298,7 @@ void Client::RemoveDuplicateLore(bool client_update) } local_2.clear(); - auto s = m_inv.cursor_begin(), e = m_inv.cursor_end(); + auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend(); database.SaveCursor(this->CharacterID(), s, e); } } @@ -2826,9 +2826,9 @@ bool Client::InterrogateInventory(Client* requester, bool log, bool silent, bool } int limbo = 0; - for (auto cursor_itr = m_inv.cursor_begin(); cursor_itr != m_inv.cursor_end(); ++cursor_itr, ++limbo) { + for (auto cursor_itr = m_inv.cursor_cbegin(); cursor_itr != m_inv.cursor_cend(); ++cursor_itr, ++limbo) { // m_inv.cursor_begin() is referenced as MainCursor in MapPossessions above - if (cursor_itr == m_inv.cursor_begin()) + if (cursor_itr == m_inv.cursor_cbegin()) continue; instmap[8000 + limbo] = *cursor_itr; From 5d64012d74df20e26ce25f481f9b3ce1055c54e6 Mon Sep 17 00:00:00 2001 From: Uleat Date: Fri, 6 Feb 2015 08:52:41 -0500 Subject: [PATCH 046/114] Removed iter_inst and iter_contents typedefs --- changelog.txt | 1 + common/item.cpp | 27 +++++++++++---------------- common/item.h | 9 +++------ 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/changelog.txt b/changelog.txt index 8d28ad3de..47aa7016f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- == 02/06/2015 == Uleat: Updated returns for Inventory and ItemInst const iterators. (const == const) +Uleat: Replaced 'iter_inst' and 'iter_contents' typedefs with their stl definitions == 02/03/2015 == Trevius: Crashfix for TempName() when numbers are passed at the end of the name. diff --git a/common/item.cpp b/common/item.cpp index 4119c7058..40fc98474 100644 --- a/common/item.cpp +++ b/common/item.cpp @@ -1071,13 +1071,10 @@ int Inventory::GetSlotByItemInstCollection(const std::map &col return -1; } -void Inventory::dumpItemCollection(const std::map &collection) { - iter_inst it; - iter_contents itb; - ItemInst* inst = nullptr; - - for (it = collection.begin(); it != collection.end(); ++it) { - inst = it->second; +void Inventory::dumpItemCollection(const std::map &collection) +{ + for (auto it = collection.cbegin(); it != collection.cend(); ++it) { + auto inst = it->second; if (!inst || !inst->GetItem()) continue; @@ -1088,14 +1085,13 @@ void Inventory::dumpItemCollection(const std::map &collection) } } -void Inventory::dumpBagContents(ItemInst *inst, iter_inst *it) { - iter_contents itb; - +void Inventory::dumpBagContents(ItemInst *inst, std::map::const_iterator *it) +{ if (!inst || !inst->IsType(ItemClassContainer)) return; // Go through bag, if bag - for (itb = inst->_cbegin(); itb != inst->_cend(); ++itb) { + for (auto itb = inst->_cbegin(); itb != inst->_cend(); ++itb) { ItemInst* baginst = itb->second; if (!baginst || !baginst->GetItem()) continue; @@ -1110,7 +1106,7 @@ void Inventory::dumpBagContents(ItemInst *inst, iter_inst *it) { // Internal Method: Retrieves item within an inventory bucket ItemInst* Inventory::_GetItem(const std::map& bucket, int16 slot_id) const { - iter_inst it = bucket.find(slot_id); + auto it = bucket.find(slot_id); if (it != bucket.end()) { return it->second; } @@ -1505,8 +1501,7 @@ ItemInst::ItemInst(const ItemInst& copy) m_attuned=copy.m_attuned; m_merchantcount=copy.m_merchantcount; // Copy container contents - iter_contents it; - for (it=copy.m_contents.begin(); it!=copy.m_contents.end(); ++it) { + for (auto it = copy.m_contents.begin(); it != copy.m_contents.end(); ++it) { ItemInst* inst_old = it->second; ItemInst* inst_new = nullptr; @@ -1676,7 +1671,7 @@ bool ItemInst::IsAugmentSlotAvailable(int32 augtype, uint8 slot) const // Retrieve item inside container ItemInst* ItemInst::GetItem(uint8 index) const { - iter_contents it = m_contents.find(index); + auto it = m_contents.find(index); if (it != m_contents.end()) { return it->second; } @@ -1739,7 +1734,7 @@ void ItemInst::ClearByFlags(byFlagSetting is_nodrop, byFlagSetting is_norent) // TODO: This needs work... // Destroy container contents - iter_contents cur, end, del; + std::map::const_iterator cur, end, del; cur = m_contents.begin(); end = m_contents.end(); for (; cur != end;) { diff --git a/common/item.h b/common/item.h index 8554d1c55..906e00313 100644 --- a/common/item.h +++ b/common/item.h @@ -33,9 +33,6 @@ class EvolveInfo; // Stores information about an evolving item family #include #include -// Helper typedefs -typedef std::map::const_iterator iter_inst; -typedef std::map::const_iterator iter_contents; namespace ItemField { @@ -227,7 +224,7 @@ protected: int GetSlotByItemInstCollection(const std::map &collection, ItemInst *inst); void dumpItemCollection(const std::map &collection); - void dumpBagContents(ItemInst *inst, iter_inst *it); + void dumpBagContents(ItemInst *inst, std::map::const_iterator *it); // Retrieves item within an inventory bucket ItemInst* _GetItem(const std::map& bucket, int16 slot_id) const; @@ -425,8 +422,8 @@ protected: ////////////////////////// // Protected Members ////////////////////////// - iter_contents _cbegin() { return m_contents.cbegin(); } - iter_contents _cend() { return m_contents.cend(); } + std::map::const_iterator _cbegin() { return m_contents.cbegin(); } + std::map::const_iterator _cend() { return m_contents.cend(); } friend class Inventory; From 5a619bddaf2b6e8033df2592c8be1e60b8ab7538 Mon Sep 17 00:00:00 2001 From: Uleat Date: Fri, 6 Feb 2015 09:58:57 -0500 Subject: [PATCH 047/114] Excluded limbo (cursor buffer) from HasItem checks --- changelog.txt | 1 + common/item.cpp | 14 ++++++++ zone/inventory.cpp | 80 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 75 insertions(+), 20 deletions(-) diff --git a/changelog.txt b/changelog.txt index 47aa7016f..8dd4b77ec 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) == 02/06/2015 == Uleat: Updated returns for Inventory and ItemInst const iterators. (const == const) Uleat: Replaced 'iter_inst' and 'iter_contents' typedefs with their stl definitions +Uleat: Removed 'limbo' from the 'HasItem' series of checks - including lore checks. The client excludes this range and it causes issues when performing item searches - dupe lore checks were added to account for this. == 02/03/2015 == Trevius: Crashfix for TempName() when numbers are passed at the end of the name. diff --git a/common/item.cpp b/common/item.cpp index 40fc98474..0e2f0f574 100644 --- a/common/item.cpp +++ b/common/item.cpp @@ -506,6 +506,7 @@ int16 Inventory::HasItem(uint32 item_id, uint8 quantity, uint8 where) return slot_id; } + // Behavioral change - Limbo is no longer checked due to improper handling of return value if (where & invWhereCursor) { // Check cursor queue slot_id = _HasItem(m_cursor, item_id, quantity); @@ -552,6 +553,7 @@ int16 Inventory::HasItemByUse(uint8 use, uint8 quantity, uint8 where) return slot_id; } + // Behavioral change - Limbo is no longer checked due to improper handling of return value if (where & invWhereCursor) { // Check cursor queue slot_id = _HasItemByUse(m_cursor, use, quantity); @@ -597,6 +599,7 @@ int16 Inventory::HasItemByLoreGroup(uint32 loregroup, uint8 where) return slot_id; } + // Behavioral change - Limbo is no longer checked due to improper handling of return value if (where & invWhereCursor) { // Check cursor queue slot_id = _HasItemByLoreGroup(m_cursor, loregroup); @@ -1119,6 +1122,8 @@ ItemInst* Inventory::_GetItem(const std::map& bucket, int16 sl // Assumes item has already been allocated int16 Inventory::_PutItem(int16 slot_id, ItemInst* inst) { + // What happens here when we _PutItem(MainCursor)? Bad things..really bad things... + // // If putting a nullptr into slot, we need to remove slot without memory delete if (inst == nullptr) { //Why do we not delete the poped item here???? @@ -1263,6 +1268,9 @@ int16 Inventory::_HasItem(ItemInstQueue& iqueue, uint32 item_id, uint8 quantity) return legacy::SLOT_AUGMENT; } } + + // We only check the visible cursor due to lack of queue processing ability (client allows duplicate in limbo) + break; } return INVALID_INDEX; @@ -1327,6 +1335,9 @@ int16 Inventory::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, uint8 quantity) return Inventory::CalcSlotId(MainCursor, bag_iter->first); } } + + // We only check the visible cursor due to lack of queue processing ability (client allows duplicate in limbo) + break; } return INVALID_INDEX; @@ -1406,6 +1417,9 @@ int16 Inventory::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32 loregroup) return legacy::SLOT_AUGMENT; } } + + // We only check the visible cursor due to lack of queue processing ability (client allows duplicate in limbo) + break; } return INVALID_INDEX; diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 94138fbe5..69f1de882 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -177,16 +177,16 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) { } -bool Client::CheckLoreConflict(const Item_Struct* item) { - if (!item) - return false; - if (!(item->LoreFlag)) - return false; +bool Client::CheckLoreConflict(const Item_Struct* item) +{ + if (!item) { return false; } + if (!item->LoreFlag) { return false; } + if (item->LoreGroup == 0) { return false; } - if (item->LoreGroup == -1) // Standard lore items; look everywhere except the shared bank, return the result + if (item->LoreGroup == 0xFFFFFFFF) // Standard lore items; look everywhere except the shared bank, return the result return (m_inv.HasItem(item->ID, 0, ~invWhereSharedBank) != INVALID_INDEX); - //If the item has a lore group, we check for other items with the same group and return the result + // If the item has a lore group, we check for other items with the same group and return the result return (m_inv.HasItemByLoreGroup(item->LoreGroup, ~invWhereSharedBank) != INVALID_INDEX); } @@ -680,20 +680,37 @@ int32 Client::GetAugmentIDAt(int16 slot_id, uint8 augslot) { return INVALID_ID; } -void Client::SendCursorBuffer() { +void Client::SendCursorBuffer() +{ // Temporary work-around for the RoF+ Client Buffer // Instead of dealing with client moving items in cursor buffer, // we can just send the next item in the cursor buffer to the cursor. - if (GetClientVersion() >= ClientVersion::RoF) - { - if (!GetInv().CursorEmpty()) - { - const ItemInst* inst = GetInv().GetCursorItem(); - if (inst) - { - SendItemPacket(MainCursor, inst, ItemPacketSummonItem); - } - } + if (GetClientVersion() < ClientVersion::RoF) { return; } + if (GetInv().CursorEmpty()) { return; } + + auto test_inst = GetInv().GetCursorItem(); + if (test_inst == nullptr) { return; } + auto test_item = test_inst->GetItem(); + if (test_item == nullptr) { return; } + + bool lore_pass = true; + if (test_item->LoreGroup == 0xFFFFFFFF) { + lore_pass = (m_inv.HasItem(test_item->ID, 0, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX); + } + else if (test_item->LoreGroup != 0) { + lore_pass = (m_inv.HasItemByLoreGroup(test_item->LoreGroup, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX); + } + + if (!lore_pass) { + Log.Out(Logs::General, Logs::Inventory, "(%s) Duplicate lore items are not allowed - destroying item %s(id:%u) on cursor", + GetName(), test_item->Name, test_item->ID); + Message_StringID(MT_LootMessages, 290); + parse->EventItem(EVENT_DESTROY_ITEM, this, test_inst, nullptr, "", 0); + DeleteItemInInventory(MainCursor); + SendCursorBuffer(); + } + else { + SendItemPacket(MainCursor, test_inst, ItemPacketSummonItem); } } @@ -1320,10 +1337,33 @@ bool Client::SwapItem(MoveItem_Struct* move_in) { return false; } - // This could be expounded upon at some point to let the server know that - // the client has moved a buffered cursor item onto the active cursor -U if (move_in->from_slot == move_in->to_slot) { // Item summon, no further processing needed if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit + if (GetClientVersion() >= ClientVersion::RoF) { return true; } // Can't do RoF+ + + if (move_in->to_slot == MainCursor) { + auto test_inst = m_inv.GetItem(MainCursor); + if (test_inst == nullptr) { return true; } + auto test_item = test_inst->GetItem(); + if (test_item == nullptr) { return true; } + if (!test_item->LoreFlag) { return true; } + + bool lore_pass = true; + if (test_item->LoreGroup == 0xFFFFFFFF) { + lore_pass = (m_inv.HasItem(test_item->ID, 0, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX); + } + else if (test_item->LoreGroup != 0) { + lore_pass = (m_inv.HasItemByLoreGroup(test_item->LoreGroup, ~(invWhereSharedBank | invWhereCursor)) == INVALID_INDEX); + } + + if (!lore_pass) { + Log.Out(Logs::General, Logs::Inventory, "(%s) Duplicate lore items are not allowed - destroying item %s(id:%u) on cursor", + GetName(), test_item->Name, test_item->ID); + Message_StringID(MT_LootMessages, 290); + parse->EventItem(EVENT_DESTROY_ITEM, this, test_inst, nullptr, "", 0); + DeleteItemInInventory(MainCursor, 0, true); + } + } return true; } From c9cd733d9a1a23ed71ce8c14a6ef3b6a8c25b521 Mon Sep 17 00:00:00 2001 From: Uleat Date: Fri, 6 Feb 2015 12:09:26 -0500 Subject: [PATCH 048/114] Updated command #iteminfo --- changelog.txt | 1 + zone/command.cpp | 66 ++++++++++++++++++++++++++++++------------------ 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/changelog.txt b/changelog.txt index 8dd4b77ec..f0d5fc722 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) Uleat: Updated returns for Inventory and ItemInst const iterators. (const == const) Uleat: Replaced 'iter_inst' and 'iter_contents' typedefs with their stl definitions Uleat: Removed 'limbo' from the 'HasItem' series of checks - including lore checks. The client excludes this range and it causes issues when performing item searches - dupe lore checks were added to account for this. +Uleat: Updated command #iteminfo to show light source information and a few other things == 02/03/2015 == Trevius: Crashfix for TempName() when numbers are passed at the end of the name. diff --git a/zone/command.cpp b/zone/command.cpp index 622f1d973..96a43d17a 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -4284,31 +4284,49 @@ void command_goto(Client *c, const Seperator *sep) void command_iteminfo(Client *c, const Seperator *sep) { - const ItemInst* inst = c->GetInv()[MainCursor]; - - if (!inst) - c->Message(13, "Error: You need an item on your cursor for this command"); - else { - const Item_Struct* item = inst->GetItem(); - c->Message(0, "ID: %i Name: %s", item->ID, item->Name); - c->Message(0, " Lore: %s ND: %i NS: %i Type: %i", (item->LoreFlag) ? "true":"false", item->NoDrop, item->NoRent, item->ItemClass); - c->Message(0, " IDF: %s Size: %i Weight: %i icon_id: %i Price: %i", item->IDFile, item->Size, item->Weight, item->Icon, item->Price); - if (c->Admin() >= 200) - c->Message(0, "MinStatus: %i", item->MinStatus); - if (item->ItemClass==ItemClassBook) - c->Message(0, " This item is a Book: %s", item->Filename); - else if (item->ItemClass==ItemClassContainer) - c->Message(0, " This item is a container with %i slots", item->BagSlots); - else { - c->Message(0, " equipableSlots: %u equipable Classes: %u", item->Slots, item->Classes); - c->Message(0, " Magic: %i SpellID: %i Proc Level: %i DBCharges: %i CurCharges: %i", item->Magic, item->Click.Effect, item->Click.Level, item->MaxCharges, inst->GetCharges()); - c->Message(0, " EffectType: 0x%02x CastTime: %.2f", (uint8) item->Click.Type, (double) item->CastTime/1000); - c->Message(0, " Material: 0x%02x Color: 0x%08x Skill: %i", item->Material, item->Color, item->ItemType); - c->Message(0, " Required level: %i Required skill: %i Recommended level:%i", item->ReqLevel, item->RecSkill, item->RecLevel); - c->Message(0, " Skill mod: %i percent: %i", item->SkillModType, item->SkillModValue); - c->Message(0, " BaneRace: %i BaneBody: %i BaneDMG: %i", item->BaneDmgRace, item->BaneDmgBody, item->BaneDmgAmt); - } + auto inst = c->GetInv()[MainCursor]; + if (!inst) { c->Message(13, "Error: You need an item on your cursor for this command"); } + auto item = inst->GetItem(); + if (!item) { + Log.Out(Logs::General, Logs::Inventory, "(%s) Command #iteminfo processed an item with no data pointer"); + c->Message(13, "Error: This item has no data reference"); } + + Client::TextLink linker; + linker.SetLinkType(linker.linkItemInst); + linker.SetItemInst(inst); + + auto item_link = linker.GenerateLink(); + + c->Message(0, "*** Item Info for [%s] ***", item_link.c_str()); + c->Message(0, ">> ID: %u, ItemUseType: %u, ItemClassType: %u", item->ID, item->ItemType, item->ItemClass); + c->Message(0, ">> IDFile: '%s', IconID: %u", item->IDFile, item->Icon); + c->Message(0, ">> Size: %u, Weight: %u, Price: %u, LDoNPrice: %u", item->Size, item->Weight, item->Price, item->LDoNPrice); + c->Message(0, ">> Material: 0x%02X, Color: 0x%08X, Tint: 0x%08X, Light: 0x%02X", item->Material, item->Color, inst->GetColor(), item->Light); + c->Message(0, ">> IsLore: %s, LoreGroup: %u, Lore: '%s'", (item->LoreFlag ? "TRUE" : "FALSE"), item->LoreGroup, item->Lore); + c->Message(0, ">> NoDrop: %u, NoRent: %u, NoPet: %u, NoTransfer: %u, FVNoDrop: %u", + item->NoDrop, item->NoRent, (uint8)item->NoPet, (uint8)item->NoTransfer, item->FVNoDrop); + + if (item->ItemClass == ItemClassBook) { + c->Message(0, "*** This item is a Book (filename:'%s') ***", item->Filename); + } + else if (item->ItemClass == ItemClassContainer) { + c->Message(0, "*** This item is a Container (%u slots) ***", item->BagSlots); + } + else { + c->Message(0, "*** This item is Common ***"); + c->Message(0, ">> Classes: %u, Races: %u, Slots: %u", item->Classes, item->Races, item->Slots); + c->Message(0, ">> ReqSkill: %u, ReqLevel: %u, RecLevel: %u", item->RecSkill, item->ReqLevel, item->RecLevel); + c->Message(0, ">> SkillModType: %u, SkillModValue: %i", item->SkillModType, item->SkillModValue); + c->Message(0, ">> BaneRaceType: %u, BaneRaceDamage: %u, BaneBodyType: %u, BaneBodyDamage: %i", + item->BaneDmgRace, item->BaneDmgRaceAmt, item->BaneDmgBody, item->BaneDmgAmt); + c->Message(0, ">> Magic: %s, SpellID: %i, ProcLevel: %u, Charges: %u, MaxCharges: %u", + (item->Magic ? "TRUE" : "FALSE"), item->Click.Effect, item->Click.Level, inst->GetCharges(), item->MaxCharges); + c->Message(0, ">> EffectType: 0x%02X, CastTime: %.2f", (uint8)item->Click.Type, ((double)item->CastTime / 1000)); + } + + if (c->Admin() >= 200) + c->Message(0, ">> MinStatus: %u", item->MinStatus); } void command_uptime(Client *c, const Seperator *sep) From d5047da637e1825cd31079d1e259e30906550ff0 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 6 Feb 2015 19:55:00 -0600 Subject: [PATCH 049/114] Fix an issue that is slowing repops down and unecessarily causing more work for respawn timer code --- zone/zonedb.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 07fe67679..cfde2ff19 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -195,11 +195,9 @@ void ZoneDatabase::UpdateSpawn2Timeleft(uint32 id, uint16 instance_id, uint32 ti //if we pass timeleft as 0 that means we clear from respawn time //otherwise we update with a REPLACE INTO if(timeleft == 0) { - std::string query = StringFormat("DELETE FROM respawn_times WHERE id=%lu " - "AND instance_id = %lu",(unsigned long)id, (unsigned long)instance_id); + std::string query = StringFormat("DELETE FROM respawn_times WHERE id=%lu AND instance_id = %lu",(unsigned long)id, (unsigned long)instance_id); auto results = QueryDatabase(query); - if (!results.Success()) - + return; } From 63810d5c1b8ffdcbeff60e7981df36a708b51b9b Mon Sep 17 00:00:00 2001 From: JohnsonAskot Date: Sat, 7 Feb 2015 12:34:50 -0500 Subject: [PATCH 050/114] Exploit fixes Bind Wound was spammable via packet sending. You could buy a larger stack than the max StackSize of an item from merchants that had unlimited of those stackable items. --- zone/client.cpp | 10 +++++++--- zone/client_packet.cpp | 5 +++++ zone/client_process.cpp | 3 ++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index 5cc5ae309..1889ecbf9 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -2471,11 +2471,13 @@ void Client::LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 bool Client::BindWound(Mob* bindmob, bool start, bool fail){ EQApplicationPacket* outapp = 0; - if(!fail) { + if(!fail) + { outapp = new EQApplicationPacket(OP_Bind_Wound, sizeof(BindWound_Struct)); BindWound_Struct* bind_out = (BindWound_Struct*) outapp->pBuffer; // Start bind - if(!bindwound_timer.Enabled()) { + if(!bindwound_timer.Enabled()) + { //make sure we actually have a bandage... and consume it. int16 bslot = m_inv.HasItemByUse(ItemTypeBandage, 1, invWhereWorn|invWherePersonal); if (bslot == INVALID_INDEX) { @@ -2521,7 +2523,9 @@ bool Client::BindWound(Mob* bindmob, bool start, bool fail){ ; // Binding self } } - } else { + } + else if (bindwound_timer.Check()) // Did the timer finish? No? Then why the hell do they get free hpz?! -Lecht + { // finish bind // disable complete timer bindwound_timer.Disable(); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 8ade0bc55..abc5734bd 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -12145,6 +12145,10 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app) mp->quantity = prevcharges; } + // Item's stackable, but the quantity they want to buy exceeds the max stackable quantity. -Lecht + if (item->Stackable && mp->quantity > item->StackSize) + mp->quantity = item->StackSize; + EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopPlayerBuy, sizeof(Merchant_Sell_Struct)); Merchant_Sell_Struct* mpo = (Merchant_Sell_Struct*)outapp->pBuffer; mpo->quantity = mp->quantity; @@ -12171,6 +12175,7 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app) mpo->price = SinglePrice; else mpo->price = SinglePrice * mp->quantity; + if (mpo->price < 0) { safe_delete(outapp); diff --git a/zone/client_process.cpp b/zone/client_process.cpp index bddc874c2..4c1475c95 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -239,7 +239,8 @@ bool Client::Process() { if(IsAIControlled()) AI_Process(); - if (bindwound_timer.Check() && bindwound_target != 0) { + // Don't reset the bindwound timer so we can check it in BindWound as well. -Lecht + if (bindwound_timer.Check(false) && bindwound_target != 0) { BindWound(bindwound_target, false); } From 67ee327f5b2ffbff7accebff0473ed0c2fdb4392 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 7 Feb 2015 12:39:46 -0500 Subject: [PATCH 051/114] Better sanity checking in Client::BuyTraderItem to prevent potential exploits --- zone/trading.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/zone/trading.cpp b/zone/trading.cpp index 4d30691f5..4874716ae 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -1479,8 +1479,6 @@ static void BazaarAuditTrail(const char *seller, const char *buyer, const char * database.QueryDatabase(query); } - - void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicationPacket* app){ if(!Trader) return; @@ -1509,15 +1507,15 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat BuyItem->GetItem()->Name, BuyItem->IsStackable(), tbs->Quantity, BuyItem->GetCharges()); // If the item is not stackable, then we can only be buying one of them. if(!BuyItem->IsStackable()) - outtbs->Quantity = tbs->Quantity; + outtbs->Quantity = 1; // normally you can't send more than 1 here else { // Stackable items, arrows, diamonds, etc - int ItemCharges = BuyItem->GetCharges(); + int32 ItemCharges = BuyItem->GetCharges(); // ItemCharges for stackables should not be <= 0 if(ItemCharges <= 0) outtbs->Quantity = 1; // If the purchaser requested more than is in the stack, just sell them how many are actually in the stack. - else if(ItemCharges < (int16)tbs->Quantity) + else if(static_cast(ItemCharges) < tbs->Quantity) outtbs->Quantity = ItemCharges; else outtbs->Quantity = tbs->Quantity; @@ -1609,7 +1607,6 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat safe_delete(outapp); safe_delete(outapp2); - } void Client::SendBazaarWelcome() From 7bf054bd58e8e99fb757c49502c4d752be578cea Mon Sep 17 00:00:00 2001 From: JohnsonAskot Date: Sat, 7 Feb 2015 14:35:43 -0500 Subject: [PATCH 052/114] Name removed from comments --- zone/client.cpp | 2 +- zone/client_packet.cpp | 2 +- zone/client_process.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index 1889ecbf9..80942527a 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -2524,7 +2524,7 @@ bool Client::BindWound(Mob* bindmob, bool start, bool fail){ } } } - else if (bindwound_timer.Check()) // Did the timer finish? No? Then why the hell do they get free hpz?! -Lecht + else if (bindwound_timer.Check()) // Did the timer finish? { // finish bind // disable complete timer diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index abc5734bd..55a6e9fcd 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -12145,7 +12145,7 @@ void Client::Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app) mp->quantity = prevcharges; } - // Item's stackable, but the quantity they want to buy exceeds the max stackable quantity. -Lecht + // Item's stackable, but the quantity they want to buy exceeds the max stackable quantity. if (item->Stackable && mp->quantity > item->StackSize) mp->quantity = item->StackSize; diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 4c1475c95..ef21013e8 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -239,7 +239,7 @@ bool Client::Process() { if(IsAIControlled()) AI_Process(); - // Don't reset the bindwound timer so we can check it in BindWound as well. -Lecht + // Don't reset the bindwound timer so we can check it in BindWound as well. if (bindwound_timer.Check(false) && bindwound_target != 0) { BindWound(bindwound_target, false); } From edbd0552773343fd2dc47292874e946d5133d3c8 Mon Sep 17 00:00:00 2001 From: JJ Date: Sat, 7 Feb 2015 17:27:48 -0500 Subject: [PATCH 053/114] Revert b96e5a7f4d0087d98e186c45ee05b5aa5bf4dba0 to search for better fix. --- zone/groups.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/groups.h b/zone/groups.h index 71935bf81..7dcbd848b 100644 --- a/zone/groups.h +++ b/zone/groups.h @@ -73,7 +73,7 @@ public: void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr); inline void SetLeader(Mob* newleader){ leader=newleader; }; inline Mob* GetLeader() { return leader; }; - const char* GetLeaderName() { return leader->GetName(); }; + const char* GetLeaderName() { return membername[0]; }; void SendHPPacketsTo(Mob* newmember); void SendHPPacketsFrom(Mob* newmember); bool UpdatePlayer(Mob* update); From 452b1a1eae3aa627080a4f421f4f8469ae37f398 Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 7 Feb 2015 15:54:42 -0800 Subject: [PATCH 054/114] Added throttling to some appearance packets, also removed responding to client light packets. With the new light code we'll tell the client when the light has changed not the other way around. --- zone/client.cpp | 5 +++++ zone/client.h | 5 +++++ zone/client_packet.cpp | 36 +++++++++++++++++++++--------------- zone/client_process.cpp | 7 +++++++ 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index 5cc5ae309..6adffd471 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -141,6 +141,11 @@ Client::Client(EQStreamInterface* ieqs) merc_timer(RuleI(Mercs, UpkeepIntervalMS)), ItemTickTimer(10000), ItemQuestTimer(500), + anim_change_timer(100), + anon_toggle_timer(250), + afk_toggle_timer(250), + helm_toggle_timer(250), + light_update_timer(250), m_Proximity(FLT_MAX, FLT_MAX, FLT_MAX), //arbitrary large number m_ZoneSummonLocation(-2.0f,-2.0f,-2.0f), m_AutoAttackPosition(0.0f, 0.0f, 0.0f, 0.0f), diff --git a/zone/client.h b/zone/client.h index a2cb823f1..3d5bc8e4b 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1465,6 +1465,11 @@ private: Timer TrackingTimer; Timer RespawnFromHoverTimer; Timer merc_timer; + Timer anim_change_timer; + Timer anon_toggle_timer; + Timer afk_toggle_timer; + Timer helm_toggle_timer; + Timer light_update_timer; glm::vec3 m_Proximity; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 8ade0bc55..24a811016 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -12640,6 +12640,10 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) else if (sa->type == AT_Anim) { if (IsAIControlled()) return; + + if(!anim_change_timer.Check()) + return; + if (sa->parameter == ANIM_STAND) { SetAppearance(eaStanding); playeraction = 0; @@ -12673,15 +12677,6 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) SetFeigned(false); } - // This is from old code - // I have no clue what it's for - /* - else if (sa->parameter == 0x05) { - // Illusion - std::cout << "Illusion packet recv'd:" << std::endl; - DumpPacket(app); - } - */ else { std::cerr << "Client " << name << " unknown apperance " << (int)sa->parameter << std::endl; return; @@ -12690,6 +12685,10 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) entity_list.QueueClients(this, app, true); } else if (sa->type == AT_Anon) { + if(!anon_toggle_timer.Check()) { + return; + } + // For Anon/Roleplay if (sa->parameter == 1) { // Anon m_pp.anon = 1; @@ -12711,13 +12710,18 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) return; } else if (sa->type == AT_AFK) { - this->AFK = (sa->parameter == 1); - entity_list.QueueClients(this, app, true); + if(afk_toggle_timer.Check()) { + AFK = (sa->parameter == 1); + entity_list.QueueClients(this, app, true); + } } else if (sa->type == AT_Split) { m_pp.autosplit = (sa->parameter == 1); } else if (sa->type == AT_Sneak) { + if(sneaking == 0) + return; + if (sa->parameter != 0) { if (!HasSkill(SkillSneak)) @@ -12729,7 +12733,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) } return; } - this->sneaking = 0; + sneaking = 0; entity_list.QueueClients(this, app, true); } else if (sa->type == AT_Size) @@ -12741,7 +12745,7 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) } else if (sa->type == AT_Light) // client emitting light (lightstone, shiny shield) { - entity_list.QueueClients(this, app, false); + //don't do anything with this } else if (sa->type == AT_Levitate) { @@ -12750,8 +12754,10 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) } else if (sa->type == AT_ShowHelm) { - m_pp.showhelm = (sa->parameter == 1); - entity_list.QueueClients(this, app, true); + if(helm_toggle_timer.Check()) { + m_pp.showhelm = (sa->parameter == 1); + entity_list.QueueClients(this, app, true); + } } else { std::cout << "Unknown SpawnAppearance type: 0x" << std::hex << std::setw(4) << std::setfill('0') << sa->type << std::dec diff --git a/zone/client_process.cpp b/zone/client_process.cpp index bddc874c2..e978552e8 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -260,6 +260,13 @@ bool Client::Process() { } } + if(light_update_timer.Check()) { + UpdateEquipLightValue(); + if(UpdateActiveLightValue()) { + SendAppearancePacket(AT_Light, GetActiveLightValue()); + } + } + bool may_use_attacks = false; /* Things which prevent us from attacking: From 9a15361e9345134c490ee954b5535872863eb582 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sat, 7 Feb 2015 20:07:46 -0500 Subject: [PATCH 055/114] Should fix spell bonuses not being applied properly --- zone/bonuses.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index ea3174a54..9ff05fb53 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1443,7 +1443,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon) int buff_count = GetMaxTotalSlots(); for(i = 0; i < buff_count; i++) { if(buffs[i].spellid != SPELL_UNKNOWN){ - ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, false,0, buffs[i].ticsremaining,i); + ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining,i); if (buffs[i].numhits > 0) Numhits(true); From 3392f4b1c3ec07f63eef7770376ad6025c2d3286 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sat, 7 Feb 2015 20:16:27 -0500 Subject: [PATCH 056/114] bonus fix --- zone/bonuses.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 9ff05fb53..8e99f9b23 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -3105,7 +3105,7 @@ void NPC::CalcItemBonuses(StatBonuses *newbon) newbon->ProcChance += cur->CombatEffects; } if (cur->Worn.Effect>0 && (cur->Worn.Type == ET_WornEffect)) { // latent effects - ApplySpellsBonuses(cur->Worn.Effect, cur->Worn.Level, newbon, cur->Worn.Type); + ApplySpellsBonuses(cur->Worn.Effect, cur->Worn.Level, newbon, 0, cur->Worn.Type); } if (RuleB(Spells, NPC_UseFocusFromItems)){ From cb81d956f62b75cf6cfbb7e5e9e328a24ea52d65 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 8 Feb 2015 05:01:58 -0600 Subject: [PATCH 057/114] Reduced #repop time dramatically by taking down hundreds of individual SELECT/DELETE/INSERT queries in routines and bringing it down to very few See: https://www.youtube.com/watch?v=9kSFbyTBuAk --- changelog.txt | 4 ++ zone/questmgr.cpp | 4 +- zone/spawn2.cpp | 105 ++++++++++++++++++++++++++++++++++++---------- zone/zone.cpp | 3 ++ zone/zonedb.cpp | 42 ++++++++++++------- zone/zonedb.h | 2 +- 6 files changed, 119 insertions(+), 41 deletions(-) diff --git a/changelog.txt b/changelog.txt index 65941f885..38b9d5719 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,9 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/06/2015 == +Akkadius: Reduced #repop time dramatically by taking down hundreds of individual SELECT/DELETE/INSERT queries in routines and bringing it down to very few + See: https://www.youtube.com/watch?v=9kSFbyTBuAk + == 02/06/2015 == Uleat: Updated returns for Inventory and ItemInst const iterators. (const == const) Uleat: Replaced 'iter_inst' and 'iter_contents' typedefs with their stl definitions diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 6c181bf1e..7dcb4e457 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -297,7 +297,7 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id) } } - database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), 0); + database.UpdateRespawnTime(spawn2_id, zone->GetInstanceID(), 0); found_spawn->SetCurrentNPCID(npcid); auto position = glm::vec4(found_spawn->GetX(), found_spawn->GetY(), found_spawn->GetZ(), found_spawn->GetHeading()); @@ -2388,7 +2388,7 @@ void QuestManager::UpdateSpawnTimer(uint32 id, uint32 newTime) { bool found = false; - database.UpdateSpawn2Timeleft(id, 0, (newTime/1000)); + database.UpdateRespawnTime(id, 0, (newTime/1000)); LinkedListIterator iterator(zone->spawn2_list); iterator.Reset(); while (iterator.MoreElements()) diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index f3440f127..068774091 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -214,9 +214,6 @@ bool Spawn2::Process() { if(IsDespawned) return true; - if(spawn2_id) - database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), 0); - currentnpcid = npcid; NPC* npc = new NPC(tmp, this, glm::vec4(x, y, z, heading), FlyMode3); @@ -348,7 +345,7 @@ void Spawn2::DeathReset(bool realdeath) //if we have a valid spawn id if(spawn2_id) { - database.UpdateSpawn2Timeleft(spawn2_id, zone->GetInstanceID(), (cur/1000)); + database.UpdateRespawnTime(spawn2_id, zone->GetInstanceID(), (cur/1000)); Log.Out(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn reset by death, repop in %d ms", spawn2_id, timer.GetRemainingTime()); //store it to database too } @@ -356,28 +353,92 @@ void Spawn2::DeathReset(bool realdeath) bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version, uint32 repopdelay) { + std::unordered_map spawn_times; + + timeval tv; + gettimeofday(&tv, nullptr); + + std::string spawn_query = StringFormat( + "SELECT " + "respawn_times.id, " + "respawn_times.`start`, " + "respawn_times.duration " + "FROM " + "respawn_times " + "WHERE instance_id = %u", + zone->GetInstanceID() + ); + auto results = QueryDatabase(spawn_query); + for (auto row = results.begin(); row != results.end(); ++row) { + uint32 start_duration = atoi(row[1]) > 0 ? atoi(row[1]) : 0; + uint32 end_duration = atoi(row[2]) > 0 ? atoi(row[2]) : 0; + + /* Our current time was expired */ + if ((start_duration + end_duration) <= tv.tv_sec) { + spawn_times[atoi(row[0])] = 0; + } + /* We still have time left on this timer */ + else { + spawn_times[atoi(row[0])] = ((start_duration + end_duration) - tv.tv_sec) * 1000; + } + } + const char *zone_name = database.GetZoneName(zoneid); - std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, " - "respawntime, variance, pathgrid, _condition, " - "cond_value, enabled, animation FROM spawn2 " - "WHERE zone = '%s' AND version = %u", - zone_name, version); - auto results = QueryDatabase(query); - if (!results.Success()) { + std::string query = StringFormat( + "SELECT " + "id, " + "spawngroupID, " + "x, " + "y, " + "z, " + "heading, " + "respawntime, " + "variance, " + "pathgrid, " + "_condition, " + "cond_value, " + "enabled, " + "animation " + "FROM " + "spawn2 " + "WHERE zone = '%s' AND version = %u", + zone_name, + version + ); + results = QueryDatabase(query); + + if (!results.Success()) { return false; - } + } - for (auto row = results.begin(); row != results.end(); ++row) { - Spawn2* newSpawn = 0; + for (auto row = results.begin(); row != results.end(); ++row) { - bool perl_enabled = atoi(row[11]) == 1? true: false; - uint32 spawnLeft = (GetSpawnTimeLeft(atoi(row[0]), zone->GetInstanceID()) * 1000); - newSpawn = new Spawn2(atoi(row[0]), atoi(row[1]), atof(row[2]), atof(row[3]), atof(row[4]), - atof(row[5]), atoi(row[6]), atoi(row[7]), spawnLeft, atoi(row[8]), - atoi(row[9]), atoi(row[10]), perl_enabled, (EmuAppearance)atoi(row[12])); + uint32 spawn_time_left = 0; + Spawn2* new_spawn = 0; + bool perl_enabled = atoi(row[11]) == 1 ? true : false; - spawn2_list.Insert(newSpawn); - } + if (spawn_times.count(atoi(row[0])) != 0) + spawn_time_left = spawn_times[atoi(row[0])]; + + new_spawn = new Spawn2( // + atoi(row[0]), // uint32 in_spawn2_id + atoi(row[1]), // uint32 spawngroup_id + atof(row[2]), // float in_x + atof(row[3]), // float in_y + atof(row[4]), // float in_z + atof(row[5]), // float in_heading + atoi(row[6]), // uint32 respawn + atoi(row[7]), // uint32 variance + spawn_time_left, // uint32 timeleft + atoi(row[8]), // uint32 grid + atoi(row[9]), // uint16 in_cond_id + atoi(row[10]), // int16 in_min_value + perl_enabled, // bool in_enabled + (EmuAppearance)atoi(row[12]) // EmuAppearance anim + ); + + spawn2_list.Insert(new_spawn); + } return true; } @@ -427,8 +488,6 @@ bool ZoneDatabase::CreateSpawn2(Client *client, uint32 spawngroup, const char* z if (results.RowsAffected() != 1) return false; - if(client) - return true; } diff --git a/zone/zone.cpp b/zone/zone.cpp index 444e217da..e79a9f9af 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -931,6 +931,9 @@ bool Zone::Init(bool iStaticZone) { Log.Out(Logs::General, Logs::Error, "Loading World Objects failed. continuing."); } + Log.Out(Logs::General, Logs::Status, "Flushing old respawn timers..."); + database.QueryDatabase("DELETE FROM `respawn_times` WHERE (`start` + `duration`) < UNIX_TIMESTAMP(NOW())"); + //load up the zone's doors (prints inside) zone->LoadZoneDoors(zone->GetShortName(), zone->GetInstanceVersion()); zone->LoadBlockedSpells(zone->GetZoneID()); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index cfde2ff19..165282f3d 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -185,28 +185,40 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct return true; } -//updates or clears the respawn time in the database for the current spawn id -void ZoneDatabase::UpdateSpawn2Timeleft(uint32 id, uint16 instance_id, uint32 timeleft) +void ZoneDatabase::UpdateRespawnTime(uint32 spawn2_id, uint16 instance_id, uint32 time_left) { + timeval tv; gettimeofday(&tv, nullptr); - uint32 cur = tv.tv_sec; + uint32 current_time = tv.tv_sec; - //if we pass timeleft as 0 that means we clear from respawn time - //otherwise we update with a REPLACE INTO - if(timeleft == 0) { - std::string query = StringFormat("DELETE FROM respawn_times WHERE id=%lu AND instance_id = %lu",(unsigned long)id, (unsigned long)instance_id); - auto results = QueryDatabase(query); - + /* If we pass timeleft as 0 that means we clear from respawn time + otherwise we update with a REPLACE INTO + */ + + if(time_left == 0) { + std::string query = StringFormat("DELETE FROM `respawn_times` WHERE `id` = %u AND `instance_id` = %u", spawn2_id, instance_id); + QueryDatabase(query); return; } - std::string query = StringFormat("REPLACE INTO respawn_times (id, start, duration, instance_id) " - "VALUES (%lu, %lu, %lu, %lu)", - (unsigned long)id, (unsigned long)cur, - (unsigned long)timeleft, (unsigned long)instance_id); - auto results = QueryDatabase(query); - if (!results.Success()) + std::string query = StringFormat( + "REPLACE INTO `respawn_times` " + "(id, " + "start, " + "duration, " + "instance_id) " + "VALUES " + "(%u, " + "%u, " + "%u, " + "%u)", + spawn2_id, + current_time, + time_left, + instance_id + ); + QueryDatabase(query); return; } diff --git a/zone/zonedb.h b/zone/zonedb.h index 5e1a55248..70c732878 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -365,7 +365,7 @@ public: bool PopulateZoneSpawnList(uint32 zoneid, LinkedList &spawn2_list, int16 version, uint32 repopdelay = 0); Spawn2* LoadSpawn2(LinkedList &spawn2_list, uint32 spawn2id, uint32 timeleft); bool CreateSpawn2(Client *c, uint32 spawngroup, const char* zone, const glm::vec4& position, uint32 respawn, uint32 variance, uint16 condition, int16 cond_value); - void UpdateSpawn2Timeleft(uint32 id, uint16 instance_id,uint32 timeleft); + void UpdateRespawnTime(uint32 id, uint16 instance_id,uint32 timeleft); uint32 GetSpawnTimeLeft(uint32 id, uint16 instance_id); void UpdateSpawn2Status(uint32 id, uint8 new_status); From 8b925f549b902dedfe9f4083b734af218129030a Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 8 Feb 2015 06:19:14 -0600 Subject: [PATCH 058/114] derp [skip ci] --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 38b9d5719..0204c266b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,6 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- -== 02/06/2015 == +== 02/07/2015 == Akkadius: Reduced #repop time dramatically by taking down hundreds of individual SELECT/DELETE/INSERT queries in routines and bringing it down to very few See: https://www.youtube.com/watch?v=9kSFbyTBuAk From 0521cae8d0c6f13ba18e1e9d84fdaf4833518c0c Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 8 Feb 2015 20:17:51 -0500 Subject: [PATCH 059/114] Implemented npc specialability (44) COUNTER_AVOID_DAMAGE which when applied to the ATTACKING NPC will make their attacks more difficult to be avoided by riposte/dodge/parry/block. Parama0: Negative modifer value that affects ALL avoid damage types dodge/parry/riposte/block) chance on defender. Ie (44,50 = 50 pct reduction to ALL) Parama1: Negative modifer value that affects RIPOSTE chance on defender. Ie (44,1,0,50 = 50 pct reduction to riposte chance) Parama2: Negative modifer value that affects PARRY chance on defender. Ie (44,1,0,0,50 = 50 pct reduction to parry chance) Parama3: Negative modifer value that affects BLOCK chance on defender. Ie (44,1,0,0,0,50 = 50 pct reduction to block chance) Parama4: Negative modifer value that affects DODGE chance on defender. e (44,1,0,0,0,0,50 = 50 pct reduction to dodge chance) Example of usage: Player has Improved Dodge V (+50 pct dodge chance), you want to negate this bonus you would set 44,1,0,0,0,0,50 on your NPC. Clean up and minor fixes to AvoidDamage function. Added support to a few AA bonuses there. --- changelog.txt | 9 +++++ zone/attack.cpp | 99 ++++++++++++++++++++++++++---------------------- zone/bonuses.cpp | 12 ++++-- zone/common.h | 3 +- zone/mob.cpp | 1 + zone/mob.h | 5 ++- 6 files changed, 78 insertions(+), 51 deletions(-) diff --git a/changelog.txt b/changelog.txt index 0204c266b..40a933c56 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,14 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/08/2015 == +Kayen: Implemented npc specialability (44) COUNTER_AVOID_DAMAGE which when applied to the ATTACKING NPC will make their attacks more difficult to be avoided by riposte/dodge/parry/block. +Parama0: Negative modifer value that affects ALL avoid damage types dodge/parry/riposte/block) chance on defender. Ie (44,50 = 50 pct reduction to ALL) +Parama1: Negative modifer value that affects RIPOSTE chance on defender. Ie (44,1,0,50 = 50 pct reduction to riposte chance) +Parama2: Negative modifer value that affects PARRY chance on defender. Ie (44,1,0,0,50 = 50 pct reduction to parry chance) +Parama3: Negative modifer value that affects BLOCK chance on defender. Ie (44,1,0,0,0,50 = 50 pct reduction to block chance) +Parama4: Negative modifer value that affects DODGE chance on defender. e (44,1,0,0,0,0,50 = 50 pct reduction to dodge chance) +Example of usage: Player has Improved Dodge V (+50 pct dodge chance), you want to negate this bonus you would set 44,1,0,0,0,0,50 on your NPC. + == 02/07/2015 == Akkadius: Reduced #repop time dramatically by taking down hundreds of individual SELECT/DELETE/INSERT queries in routines and bringing it down to very few See: https://www.youtube.com/watch?v=9kSFbyTBuAk diff --git a/zone/attack.cpp b/zone/attack.cpp index bfd4a5cc2..ef57b4b6b 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -362,13 +362,40 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) //garunteed hit bool ghit = false; - if((attacker->spellbonuses.MeleeSkillCheck + attacker->itembonuses.MeleeSkillCheck) > 500) + if((attacker->aabonuses.MeleeSkillCheck + attacker->spellbonuses.MeleeSkillCheck + attacker->itembonuses.MeleeSkillCheck) > 500) ghit = true; + bool InFront = false; + + if (attacker->InFrontMob(this, attacker->GetX(), attacker->GetY())) + InFront = true; + + /* + This special ability adds a negative modifer to the defenders riposte/block/parry/chance + therefore reducing the defenders chance to successfully avoid the melee attack. At present + time this is the only way to fine tune counter these mods on players. This may + ultimately end up being more useful as fields in npc_types. + */ + + int counter_all = 0; + int counter_riposte = 0; + int counter_block = 0; + int counter_parry = 0; + int counter_dodge = 0; + + if (attacker->GetSpecialAbility(COUNTER_AVOID_DAMAGE)){ + + counter_all = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 0); + counter_riposte = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE,1); + counter_block = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 2); + counter_parry = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 3); + counter_dodge = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 4); + } + ////////////////////////////////////////////////////////// // make enrage same as riposte ///////////////////////////////////////////////////////// - if (IsEnraged() && other->InFrontMob(this, other->GetX(), other->GetY())) { + if (IsEnraged() && InFront) { damage = -3; Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack."); } @@ -377,9 +404,10 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) // riposte ///////////////////////////////////////////////////////// float riposte_chance = 0.0f; - if (CanRiposte && damage > 0 && CanThisClassRiposte() && other->InFrontMob(this, other->GetX(), other->GetY())) + if (CanRiposte && damage > 0 && CanThisClassRiposte() && InFront) { - riposte_chance = (100.0f + (float)defender->aabonuses.RiposteChance + (float)defender->spellbonuses.RiposteChance + (float)defender->itembonuses.RiposteChance) / 100.0f; + riposte_chance = (100.0f + static_cast(aabonuses.RiposteChance + spellbonuses.RiposteChance + + itembonuses.RiposteChance - counter_riposte - counter_all)) / 100.0f; skill = GetSkill(SkillRiposte); if (IsClient()) { CastToClient()->CheckIncreaseSkill(SkillRiposte, other, -10); @@ -398,28 +426,19 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) /////////////////////////////////////////////////////// bool bBlockFromRear = false; - bool bShieldBlockFromRear = false; - if (this->IsClient()) { - int aaChance = 0; + // a successful roll on this does not mean a successful block is forthcoming. only that a chance to block + // from a direction other than the rear is granted. - // a successful roll on this does not mean a successful block is forthcoming. only that a chance to block - // from a direction other than the rear is granted. + int BlockBehindChance = aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind; - //Live AA - HightenedAwareness - int BlockBehindChance = aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind; - - if (BlockBehindChance && zone->random.Roll(BlockBehindChance)) { - bBlockFromRear = true; - - if (spellbonuses.BlockBehind || itembonuses.BlockBehind) - bShieldBlockFromRear = true; //This bonus should allow a chance to Shield Block from behind. - } - } + if (BlockBehindChance && zone->random.Roll(BlockBehindChance)) + bBlockFromRear = true; float block_chance = 0.0f; - if (damage > 0 && CanThisClassBlock() && (other->InFrontMob(this, other->GetX(), other->GetY()) || bBlockFromRear)) { - block_chance = (100.0f + (float)spellbonuses.IncreaseBlockChance + (float)itembonuses.IncreaseBlockChance) / 100.0f; + if (damage > 0 && CanThisClassBlock() && (InFront || bBlockFromRear)) { + block_chance = (100.0f + static_cast(aabonuses.IncreaseBlockChance + spellbonuses.IncreaseBlockChance + + itembonuses.IncreaseBlockChance - counter_block - counter_all)) / 100.0f; skill = CastToClient()->GetSkill(SkillBlock); if (IsClient()) { CastToClient()->CheckIncreaseSkill(SkillBlock, other, -10); @@ -435,32 +454,20 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) RollTable[1] = RollTable[0]; } - if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) - && (other->InFrontMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) { - - float bonusShieldBlock = 0.0f; - bonusShieldBlock = static_cast(aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock); - RollTable[1] += bonusShieldBlock; - } - - if(IsClient() && damage > 0 && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) - && (other->InFrontMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) { - if(CastToClient()->m_inv.GetItem(MainPrimary)) { - float bonusStaffBlock = 0.0f; - if (CastToClient()->m_inv.GetItem(MainPrimary)->GetItem()->ItemType == ItemType2HBlunt){ - bonusStaffBlock = static_cast(aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock); - RollTable[1] += bonusStaffBlock; - } - } - } + //Try Shield Block OR TwoHandBluntBlockCheck + if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) && (InFront || bBlockFromRear)) + RollTable[1] += static_cast(aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock - counter_block - counter_all); + else if(damage > 0 && HasTwoHandBluntEquiped() && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) && (InFront || bBlockFromRear)) + RollTable[1] += static_cast(aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock - counter_block - counter_all); + ////////////////////////////////////////////////////// // parry ////////////////////////////////////////////////////// float parry_chance = 0.0f; - if (damage > 0 && CanThisClassParry() && other->InFrontMob(this, other->GetX(), other->GetY())) - { - parry_chance = (100.0f + (float)defender->spellbonuses.ParryChance + (float)defender->itembonuses.ParryChance) / 100.0f; + if (damage > 0 && CanThisClassParry() && InFront){ + parry_chance = (100.0f + static_cast(aabonuses.ParryChance + itembonuses.ParryChance + + itembonuses.ParryChance - counter_parry - counter_all)) / 100.0f; skill = CastToClient()->GetSkill(SkillParry); if (IsClient()) { CastToClient()->CheckIncreaseSkill(SkillParry, other, -10); @@ -481,9 +488,11 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) // dodge //////////////////////////////////////////////////////// float dodge_chance = 0.0f; - if (damage > 0 && CanThisClassDodge() && other->InFrontMob(this, other->GetX(), other->GetY())) - { - dodge_chance = (100.0f + (float)defender->spellbonuses.DodgeChance + (float)defender->itembonuses.DodgeChance) / 100.0f; + if (damage > 0 && CanThisClassDodge() && InFront){ + + dodge_chance = (100.0f + static_cast(aabonuses.DodgeChance + spellbonuses.DodgeChance + + itembonuses.DodgeChance - counter_dodge - counter_all)) / 100.0f; + skill = CastToClient()->GetSkill(SkillDodge); if (IsClient()) { CastToClient()->CheckIncreaseSkill(SkillDodge, other, -10); diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 8e99f9b23..a76860ce4 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -139,7 +139,8 @@ void Client::CalcItemBonuses(StatBonuses* newbon) { // Clear item faction mods ClearItemFactionBonuses(); - ShieldEquiped(false); + SetShieldEquiped(false); + SetTwoHandBluntEquiped(false); unsigned int i; //should not include 21 (SLOT_AMMO) @@ -149,9 +150,12 @@ void Client::CalcItemBonuses(StatBonuses* newbon) { continue; AddItemBonuses(inst, newbon); - //Check if item is secondary slot is a 'shield'. Required for multiple spelll effects. - if (i == MainSecondary && (m_inv.GetItem(MainSecondary)->GetItem()->ItemType == ItemTypeShield)) - ShieldEquiped(true); + //These are given special flags due to how often they are checked for various spell effects. + const Item_Struct *item = inst->GetItem(); + if (i == MainSecondary && (item && item->ItemType == ItemTypeShield)) + SetShieldEquiped(true); + else if (i == MainPrimary && (item && item->ItemType == ItemType2HBlunt)) + SetTwoHandBluntEquiped(true); } //Power Source Slot diff --git a/zone/common.h b/zone/common.h index 639eee91e..56ab6f819 100644 --- a/zone/common.h +++ b/zone/common.h @@ -136,7 +136,8 @@ enum { ALLOW_TO_TANK = 41, IGNORE_ROOT_AGGRO_RULES = 42, CASTING_RESIST_DIFF = 43, - MAX_SPECIAL_ATTACK = 44 + COUNTER_AVOID_DAMAGE = 44, + MAX_SPECIAL_ATTACK = 45 }; typedef enum { //fear states diff --git a/zone/mob.cpp b/zone/mob.cpp index e9cee33e4..ea86ff4dc 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -170,6 +170,7 @@ Mob::Mob(const char* in_name, findable = false; trackable = true; has_shieldequiped = false; + has_twohandbluntequiped = false; has_numhits = false; has_MGB = false; has_ProjectIllusion = false; diff --git a/zone/mob.h b/zone/mob.h index e7318007e..fb8148713 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -308,7 +308,9 @@ public: void SetTargetable(bool on); bool IsTargetable() const { return m_targetable; } bool HasShieldEquiped() const { return has_shieldequiped; } - inline void ShieldEquiped(bool val) { has_shieldequiped = val; } + inline void SetShieldEquiped(bool val) { has_shieldequiped = val; } + bool HasTwoHandBluntEquiped() const { return has_twohandbluntequiped; } + inline void SetTwoHandBluntEquiped(bool val) { has_twohandbluntequiped = val; } virtual uint16 GetSkill(SkillUseTypes skill_num) const { return 0; } virtual uint32 GetEquipment(uint8 material_slot) const { return(0); } virtual int32 GetEquipmentMaterial(uint8 material_slot) const; @@ -1150,6 +1152,7 @@ protected: uint16 viral_spells[MAX_SPELL_TRIGGER*2]; // Stores the spell ids of the viruses on target and caster ids bool offhand; bool has_shieldequiped; + bool has_twohandbluntequiped; bool has_numhits; bool has_MGB; bool has_ProjectIllusion; From 45e7ff91935de1eece1b6cfceb8931a6606b0f54 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Mon, 9 Feb 2015 03:02:25 -0500 Subject: [PATCH 060/114] Fix RoF2 item hotkeys This string thing needs to be longer! Still no idea what it is --- common/patches/rof2.cpp | 2 +- common/patches/rof2_structs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 6947ded15..d0189e56a 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -5053,7 +5053,7 @@ namespace RoF2 //sprintf(hdr.unknown000, "06e0002Y1W00"); - snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%012d", item->ID); + snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID); hdr.stacksize = stackable ? charges : 1; hdr.unknown004 = 0; diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 9ef524f55..95f5c31e6 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -4353,7 +4353,7 @@ struct RoF2SlotStruct struct ItemSerializationHeader { -/*000*/ char unknown000[13]; // New for HoT. Looks like a string. +/*000*/ char unknown000[17]; // New for HoT. Looks like a string. /*017*/ uint32 stacksize; /*021*/ uint32 unknown004; /*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ? From e6eb4e16d1c9a7c5fa04161f1455f3ca0585226c Mon Sep 17 00:00:00 2001 From: Trevius Date: Mon, 9 Feb 2015 17:23:43 -0600 Subject: [PATCH 061/114] (SoF+) Removed duplicate packets being sent to client on zone. --- zone/client_packet.cpp | 66 ++---------------------------------------- 1 file changed, 2 insertions(+), 64 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 41c707287..fc05605c5 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1216,73 +1216,11 @@ void Client::Handle_Connect_OP_WearChange(const EQApplicationPacket *app) void Client::Handle_Connect_OP_WorldObjectsSent(const EQApplicationPacket *app) { - //This is a copy of SendExpZonein created for SoF+ due to packet order change - - ////////////////////////////////////////////////////// - // Spawn Appearance Packet - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); - SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer; - sa->type = AT_SpawnID; // Is 0x10 used to set the player id? - sa->parameter = GetID(); // Four bytes for this parameter... - outapp->priority = 6; + // New for Secrets of Faydwer+ + EQApplicationPacket* outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0); QueuePacket(outapp); safe_delete(outapp); - // Inform the world about the client - outapp = new EQApplicationPacket(); - - CreateSpawnPacket(outapp); - outapp->priority = 6; - if (!GetHideMe()) entity_list.QueueClients(this, outapp, true); - safe_delete(outapp); - if (GetPVP()) //force a PVP update until we fix the spawn struct - SendAppearancePacket(AT_PVP, GetPVP(), true, false); - - //Send AA Exp packet: - if (GetLevel() >= 51) - SendAAStats(); - - // Send exp packets - outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct)); - ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer; - uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1); - uint32 tmpxp2 = GetEXPForLevel(GetLevel()); - - // Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc) - if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) { - float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2); - eu->exp = (uint32)(330.0f * tmpxp); - outapp->priority = 6; - QueuePacket(outapp); - } - safe_delete(outapp); - - SendAATimers(); - - // New for Secrets of Faydwer - Used in Place of OP_SendExpZonein - outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0); - QueuePacket(outapp); - safe_delete(outapp); - - outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct)); - ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer; - strcpy(zonesendname->name, m_pp.name); - strcpy(zonesendname->name2, m_pp.name); - zonesendname->unknown0 = 0x0A; - QueuePacket(outapp); - safe_delete(outapp); - - if (IsInAGuild()) { - SendGuildMembers(); - SendGuildURL(); - SendGuildChannel(); - SendGuildLFGuildStatus(); - } - SendLFGuildStatus(); - - //No idea why live sends this if even were not in a guild - SendGuildMOTD(); - if (RuleB(Mercs, AllowMercs)) { SpawnMercOnZone(); From c4eb6e2881c7ed9238a2fdf3efa9e1963b1071e9 Mon Sep 17 00:00:00 2001 From: Trevius Date: Mon, 9 Feb 2015 18:52:17 -0600 Subject: [PATCH 062/114] (RoF+) Setting Alt flag on characters in the Guild Management Window is now saved and functional for filtering. --- changelog.txt | 3 +++ utils/patches/patch_RoF.conf | 2 +- utils/patches/patch_RoF2.conf | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 40a933c56..fdfc74944 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/09/2015 == +Trevius: (RoF+) Setting Alt flag on characters in the Guild Management Window is now saved and functional for filtering. + == 02/08/2015 == Kayen: Implemented npc specialability (44) COUNTER_AVOID_DAMAGE which when applied to the ATTACKING NPC will make their attacks more difficult to be avoided by riposte/dodge/parry/block. Parama0: Negative modifer value that affects ALL avoid damage types dodge/parry/riposte/block) chance on defender. Ie (44,50 = 50 pct reduction to ALL) diff --git a/utils/patches/patch_RoF.conf b/utils/patches/patch_RoF.conf index 05a3a4a76..d144b040e 100644 --- a/utils/patches/patch_RoF.conf +++ b/utils/patches/patch_RoF.conf @@ -129,7 +129,7 @@ OP_GuildInviteAccept=0x78a5 OP_GuildDemote=0x3100 OP_GuildPromote=0x2945 OP_GuildPublicNote=0x3c2c -OP_GuildManageBanker=0x096d # Was 0x0737 +OP_GuildManageBanker=0x389c # Was 0x096d OP_GuildBank=0x2ab0 # Was 0x10c3 OP_SetGuildRank=0x3599 OP_GuildUpdateURLAndChannel=0x7851 diff --git a/utils/patches/patch_RoF2.conf b/utils/patches/patch_RoF2.conf index 7159dcce5..e032d917d 100644 --- a/utils/patches/patch_RoF2.conf +++ b/utils/patches/patch_RoF2.conf @@ -128,7 +128,7 @@ OP_GuildInviteAccept=0x7053 OP_GuildDemote=0x2d4e OP_GuildPromote=0x6a98 OP_GuildPublicNote=0x5053 -OP_GuildManageBanker=0x748f +OP_GuildManageBanker=0x3f35 OP_GuildBank=0x5134 OP_SetGuildRank=0x0b9c OP_GuildUpdateURLAndChannel=0x2958 From 543e265b0a91c8c172abe01615ee286a46684a6c Mon Sep 17 00:00:00 2001 From: KimLS Date: Mon, 9 Feb 2015 17:48:07 -0800 Subject: [PATCH 063/114] Adjustments to OP_SpawnAppearance, as well as updating import client files to handle newer spell files --- client_files/import/main.cpp | 32 ++++++++++++++++++++++++++++++-- zone/client.cpp | 3 +-- zone/client.h | 1 - zone/client_packet.cpp | 3 --- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/client_files/import/main.cpp b/client_files/import/main.cpp index a8477f77a..3a2f4154f 100644 --- a/client_files/import/main.cpp +++ b/client_files/import/main.cpp @@ -76,6 +76,24 @@ int GetSpellColumns(SharedDatabase *db) { return results.RowCount(); } +bool IsStringField(int i) { + switch(i) + { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + return true; + break; + default: + return false; + } +} + void ImportSpells(SharedDatabase *db) { Log.Out(Logs::General, Logs::Status, "Importing Spells..."); FILE *f = fopen("import/spells_us.txt", "r"); @@ -113,7 +131,12 @@ void ImportSpells(SharedDatabase *db) { sql += "'"; } - sql += split[i]; + if(split[i].compare("") == 0 && !IsStringField(i)) { + sql += "0"; + } + else { + sql += split[i]; + } sql += "'"; } @@ -128,7 +151,12 @@ void ImportSpells(SharedDatabase *db) { sql += "'"; } - sql += split[i]; + if(split[i].compare("") == 0 && !IsStringField(i)) { + sql += "0"; + } else { + sql += split[i]; + } + sql += "'"; } diff --git a/zone/client.cpp b/zone/client.cpp index e9983ad48..e2158cd54 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -141,11 +141,10 @@ Client::Client(EQStreamInterface* ieqs) merc_timer(RuleI(Mercs, UpkeepIntervalMS)), ItemTickTimer(10000), ItemQuestTimer(500), - anim_change_timer(100), anon_toggle_timer(250), afk_toggle_timer(250), helm_toggle_timer(250), - light_update_timer(250), + light_update_timer(600), m_Proximity(FLT_MAX, FLT_MAX, FLT_MAX), //arbitrary large number m_ZoneSummonLocation(-2.0f,-2.0f,-2.0f), m_AutoAttackPosition(0.0f, 0.0f, 0.0f, 0.0f), diff --git a/zone/client.h b/zone/client.h index 3d5bc8e4b..263aecf3e 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1465,7 +1465,6 @@ private: Timer TrackingTimer; Timer RespawnFromHoverTimer; Timer merc_timer; - Timer anim_change_timer; Timer anon_toggle_timer; Timer afk_toggle_timer; Timer helm_toggle_timer; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index fc05605c5..71c7ca7e4 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -12584,9 +12584,6 @@ void Client::Handle_OP_SpawnAppearance(const EQApplicationPacket *app) if (IsAIControlled()) return; - if(!anim_change_timer.Check()) - return; - if (sa->parameter == ANIM_STAND) { SetAppearance(eaStanding); playeraction = 0; From 82b9af395618808f7d0f4ce154ed45f06d65a370 Mon Sep 17 00:00:00 2001 From: Trevius Date: Mon, 9 Feb 2015 19:54:14 -0600 Subject: [PATCH 064/114] (RoF+) Guild Invites between RoF+ and previous Clients is now functional. --- changelog.txt | 1 + zone/client_packet.cpp | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index fdfc74944..a7a1127dd 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- == 02/09/2015 == Trevius: (RoF+) Setting Alt flag on characters in the Guild Management Window is now saved and functional for filtering. +Trevius: (RoF+) Guild Invites between RoF+ and previous Clients is now functional. == 02/08/2015 == Kayen: Implemented npc specialability (44) COUNTER_AVOID_DAMAGE which when applied to the ATTACKING NPC will make their attacks more difficult to be avoided by riposte/dodge/parry/block. diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 71c7ca7e4..f0fefaf9e 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -7298,6 +7298,16 @@ void Client::Handle_OP_GuildInvite(const EQApplicationPacket *app) if (gc->guildeqid == 0) gc->guildeqid = GuildID(); + // Convert Membership Level between RoF and previous clients. + if (client->GetClientVersion() < ClientVersion::RoF && GetClientVersion() >= ClientVersion::RoF) + { + gc->officer = 0; + } + if (client->GetClientVersion() >= ClientVersion::RoF && GetClientVersion() < ClientVersion::RoF) + { + gc->officer = 8; + } + Log.Out(Logs::Detail, Logs::Guilds, "Sending OP_GuildInvite for invite to %s, length %d", client->GetName(), app->size); client->SetPendingGuildInvitation(true); client->QueuePacket(app); @@ -7332,6 +7342,8 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app) GuildInviteAccept_Struct* gj = (GuildInviteAccept_Struct*)app->pBuffer; + uint32 guildrank = gj->response; + if (GetClientVersion() >= ClientVersion::RoF) { if (gj->response > 9) @@ -7360,9 +7372,25 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app) Log.Out(Logs::Detail, Logs::Guilds, "Guild Invite Accept: guild %d, response %d, inviter %s, person %s", gj->guildeqid, gj->response, gj->inviter, gj->newmember); + //ok, the invite is also used for changing rank as well. + Mob* inviter = entity_list.GetMob(gj->inviter); + + if (inviter && inviter->IsClient()) + { + Client* client = inviter->CastToClient(); + // Convert Membership Level between RoF and previous clients. + if (client->GetClientVersion() < ClientVersion::RoF && GetClientVersion() >= ClientVersion::RoF) + { + guildrank = 0; + } + if (client->GetClientVersion() >= ClientVersion::RoF && GetClientVersion() < ClientVersion::RoF) + { + guildrank = 8; + } + } //we dont really care a lot about what this packet means, as long as //it has been authorized with the guild manager - if (!guild_mgr.VerifyAndClearInvite(CharacterID(), gj->guildeqid, gj->response)) { + if (!guild_mgr.VerifyAndClearInvite(CharacterID(), gj->guildeqid, guildrank)) { worldserver.SendEmoteMessage(gj->inviter, 0, 0, "%s has sent an invalid response to your invite!", GetName()); Message(13, "Invalid invite response packet!"); return; @@ -7390,7 +7418,7 @@ void Client::Handle_OP_GuildInviteAccept(const EQApplicationPacket *app) //change guild and rank - uint32 guildrank = gj->response; + guildrank = gj->response; if (GetClientVersion() >= ClientVersion::RoF) { From 927e4f83ff2094482f6c966f0f3b6ac40047c181 Mon Sep 17 00:00:00 2001 From: Trevius Date: Mon, 9 Feb 2015 20:07:04 -0600 Subject: [PATCH 065/114] (RoF2) Updated Expedition Opcodes --- utils/patches/patch_RoF2.conf | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/utils/patches/patch_RoF2.conf b/utils/patches/patch_RoF2.conf index e032d917d..189edc8b3 100644 --- a/utils/patches/patch_RoF2.conf +++ b/utils/patches/patch_RoF2.conf @@ -353,21 +353,22 @@ OP_Marquee=0x502e OP_ItemRecastDelay=0x15a9 #OP_OpenInventory=0x0000 # Likely does not exist in RoF -U -OP_DzQuit=0x205f -OP_DzListTimers=0x0398 -OP_DzAddPlayer=0x59ca -OP_DzRemovePlayer=0x4701 -OP_DzSwapPlayer=0x1abc -OP_DzMakeLeader=0x405b -OP_DzPlayerList=0x543d -OP_DzJoinExpeditionConfirm=0x14c6 -OP_DzJoinExpeditionReply=0x7f4b -OP_DzExpeditionInfo=0x4f7e -OP_DzExpeditionList=0x9119 -OP_DzMemberStatus=0xb2e3 -OP_DzLeaderStatus=0x32f0 +# Expeditions +OP_DzAddPlayer=0x4701 +OP_DzRemovePlayer=0x1abc +OP_DzSwapPlayer=0x405b +OP_DzMakeLeader=0x543d +OP_DzPlayerList=0x14c6 +OP_DzJoinExpeditionConfirm=0x7f4b +OP_DzJoinExpeditionReply=0x1950 +OP_DzListTimers=0x7b68 +OP_DzExpeditionInfo=0x9119 +OP_DzExpeditionList=0x205f +OP_DzQuit=0xb2e3 +OP_DzMemberStatus=0x32f0 +OP_DzLeaderStatus=0x3de9 +OP_DzMemberList=0x5ae4 OP_DzExpeditionEndsWarning=0x383c -OP_DzMemberList=0x3de9 OP_DzCompass=0x3e0e OP_DzChooseZone=0x0b7d From f613d12c619249ce990f6976186624edb13ed34d Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 10 Feb 2015 12:49:32 -0500 Subject: [PATCH 066/114] Revert "(SoF+) Removed duplicate packets being sent to client on zone." This reverts commit e6eb4e16d1c9a7c5fa04161f1455f3ca0585226c. --- zone/client_packet.cpp | 66 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index f0fefaf9e..c37e6dc86 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1216,11 +1216,73 @@ void Client::Handle_Connect_OP_WearChange(const EQApplicationPacket *app) void Client::Handle_Connect_OP_WorldObjectsSent(const EQApplicationPacket *app) { - // New for Secrets of Faydwer+ - EQApplicationPacket* outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0); + //This is a copy of SendExpZonein created for SoF+ due to packet order change + + ////////////////////////////////////////////////////// + // Spawn Appearance Packet + EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); + SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer; + sa->type = AT_SpawnID; // Is 0x10 used to set the player id? + sa->parameter = GetID(); // Four bytes for this parameter... + outapp->priority = 6; QueuePacket(outapp); safe_delete(outapp); + // Inform the world about the client + outapp = new EQApplicationPacket(); + + CreateSpawnPacket(outapp); + outapp->priority = 6; + if (!GetHideMe()) entity_list.QueueClients(this, outapp, true); + safe_delete(outapp); + if (GetPVP()) //force a PVP update until we fix the spawn struct + SendAppearancePacket(AT_PVP, GetPVP(), true, false); + + //Send AA Exp packet: + if (GetLevel() >= 51) + SendAAStats(); + + // Send exp packets + outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct)); + ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer; + uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1); + uint32 tmpxp2 = GetEXPForLevel(GetLevel()); + + // Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc) + if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) { + float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2); + eu->exp = (uint32)(330.0f * tmpxp); + outapp->priority = 6; + QueuePacket(outapp); + } + safe_delete(outapp); + + SendAATimers(); + + // New for Secrets of Faydwer - Used in Place of OP_SendExpZonein + outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0); + QueuePacket(outapp); + safe_delete(outapp); + + outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct)); + ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer; + strcpy(zonesendname->name, m_pp.name); + strcpy(zonesendname->name2, m_pp.name); + zonesendname->unknown0 = 0x0A; + QueuePacket(outapp); + safe_delete(outapp); + + if (IsInAGuild()) { + SendGuildMembers(); + SendGuildURL(); + SendGuildChannel(); + SendGuildLFGuildStatus(); + } + SendLFGuildStatus(); + + //No idea why live sends this if even were not in a guild + SendGuildMOTD(); + if (RuleB(Mercs, AllowMercs)) { SpawnMercOnZone(); From 9daf572ea78394e6f909031030c159dd628508cb Mon Sep 17 00:00:00 2001 From: KimLS Date: Tue, 10 Feb 2015 11:53:16 -0800 Subject: [PATCH 067/114] Fix for no factions in database crashing the server and shared memory --- common/shareddb.cpp | 9 +++------ shared_memory/npc_faction.cpp | 3 --- zone/zonedb.cpp | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 13ae065be..0e057812d 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -1158,7 +1158,7 @@ void SharedDatabase::GetFactionListInfo(uint32 &list_count, uint32 &max_lists) { auto row = results.begin(); list_count = static_cast(atoul(row[0])); - max_lists = static_cast(atoul(row[1])); + max_lists = static_cast(atoul(row[1] ? row[1] : "0")); } const NPCFactionList* SharedDatabase::GetNPCFactionEntry(uint32 id) { @@ -1235,9 +1235,6 @@ bool SharedDatabase::LoadNPCFactionLists() { uint32 list_count = 0; uint32 max_lists = 0; GetFactionListInfo(list_count, max_lists); - if(list_count == 0) { - EQ_EXCEPT("SharedDatabase", "Database returned no result"); - } uint32 size = static_cast(EQEmu::FixedMemoryHashSet::estimated_size( list_count, max_lists)); @@ -1837,7 +1834,7 @@ void SharedDatabase::GetLootTableInfo(uint32 &loot_table_count, uint32 &max_loot auto row = results.begin(); loot_table_count = static_cast(atoul(row[0])); - max_loot_table = static_cast(atoul(row[1])); + max_loot_table = static_cast(atoul(row[1] ? row[1] : "0")); loot_table_entries = static_cast(atoul(row[2])); } @@ -1858,7 +1855,7 @@ void SharedDatabase::GetLootDropInfo(uint32 &loot_drop_count, uint32 &max_loot_d auto row =results.begin(); loot_drop_count = static_cast(atoul(row[0])); - max_loot_drop = static_cast(atoul(row[1])); + max_loot_drop = static_cast(atoul(row[1] ? row[1] : "0")); loot_drop_entries = static_cast(atoul(row[2])); } diff --git a/shared_memory/npc_faction.cpp b/shared_memory/npc_faction.cpp index df33b7368..ebaeb3457 100644 --- a/shared_memory/npc_faction.cpp +++ b/shared_memory/npc_faction.cpp @@ -31,9 +31,6 @@ void LoadFactions(SharedDatabase *database) { uint32 lists = 0; uint32 max_list = 0; database->GetFactionListInfo(lists, max_list); - if(lists == 0) { - EQ_EXCEPT("Shared Memory", "Unable to get any factions from the database."); - } uint32 size = static_cast(EQEmu::FixedMemoryHashSet::estimated_size(lists, max_list)); EQEmu::MemoryMappedFile mmf("shared/faction", size); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 165282f3d..6cb15d16e 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -3256,7 +3256,7 @@ bool ZoneDatabase::LoadFactionData() auto row = results.begin(); - max_faction = atoi(row[0]); + max_faction = row[0] ? atoi(row[0]) : 0; faction_array = new Faction*[max_faction+1]; for(unsigned int index=0; index Date: Tue, 10 Feb 2015 19:22:42 -0600 Subject: [PATCH 068/114] (SoF+) Removed duplicate packets being sent to client on zone (Take #2)! --- zone/client.cpp | 63 +++++++++++++++++++ zone/client.h | 1 + zone/client_packet.cpp | 138 +++-------------------------------------- 3 files changed, 73 insertions(+), 129 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index e2158cd54..b5575a307 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -413,6 +413,69 @@ Client::~Client() { UninitializeBuffSlots(); } +void Client::SendZoneInPackets() +{ + ////////////////////////////////////////////////////// + // Spawn Appearance Packet + EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); + SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer; + sa->type = AT_SpawnID; // Is 0x10 used to set the player id? + sa->parameter = GetID(); // Four bytes for this parameter... + outapp->priority = 6; + QueuePacket(outapp); + safe_delete(outapp); + + // Inform the world about the client + outapp = new EQApplicationPacket(); + + CreateSpawnPacket(outapp); + outapp->priority = 6; + if (!GetHideMe()) entity_list.QueueClients(this, outapp, true); + safe_delete(outapp); + if (GetPVP()) //force a PVP update until we fix the spawn struct + SendAppearancePacket(AT_PVP, GetPVP(), true, false); + + //Send AA Exp packet: + if (GetLevel() >= 51) + SendAAStats(); + + // Send exp packets + outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct)); + ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer; + uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1); + uint32 tmpxp2 = GetEXPForLevel(GetLevel()); + + // Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc) + if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) { + float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2); + eu->exp = (uint32)(330.0f * tmpxp); + outapp->priority = 6; + QueuePacket(outapp); + } + safe_delete(outapp); + + SendAATimers(); + + outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct)); + ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer; + strcpy(zonesendname->name, m_pp.name); + strcpy(zonesendname->name2, m_pp.name); + zonesendname->unknown0 = 0x0A; + QueuePacket(outapp); + safe_delete(outapp); + + if (IsInAGuild()) { + SendGuildMembers(); + SendGuildURL(); + SendGuildChannel(); + SendGuildLFGuildStatus(); + } + SendLFGuildStatus(); + + //No idea why live sends this if even were not in a guild + SendGuildMOTD(); +} + void Client::SendLogoutPackets() { EQApplicationPacket* outapp = new EQApplicationPacket(OP_CancelTrade, sizeof(CancelTrade_Struct)); diff --git a/zone/client.h b/zone/client.h index 263aecf3e..53d3c0428 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1415,6 +1415,7 @@ private: bool CanBeInZone(); void SendLogoutPackets(); + void SendZoneInPackets(); bool AddPacket(const EQApplicationPacket *, bool); bool AddPacket(EQApplicationPacket**, bool); bool SendAllPackets(); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index c37e6dc86..db7f65781 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1089,76 +1089,15 @@ void Client::Handle_Connect_OP_SendAATable(const EQApplicationPacket *app) void Client::Handle_Connect_OP_SendExpZonein(const EQApplicationPacket *app) { - ////////////////////////////////////////////////////// - // Spawn Appearance Packet - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); - SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer; - sa->type = AT_SpawnID; // Is 0x10 used to set the player id? - sa->parameter = GetID(); // Four bytes for this parameter... - outapp->priority = 6; + EQApplicationPacket* outapp = new EQApplicationPacket(OP_SendExpZonein, 0); QueuePacket(outapp); safe_delete(outapp); - // Inform the world about the client - outapp = new EQApplicationPacket(); - - CreateSpawnPacket(outapp); - outapp->priority = 6; - if (!GetHideMe()) entity_list.QueueClients(this, outapp, true); - safe_delete(outapp); - if (GetPVP()) //force a PVP update until we fix the spawn struct - SendAppearancePacket(AT_PVP, GetPVP(), true, false); - - //Send AA Exp packet: - if (GetLevel() >= 51) - SendAAStats(); - - // Send exp packets - outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct)); - ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer; - uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1); - uint32 tmpxp2 = GetEXPForLevel(GetLevel()); - - // Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc) - if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) { - float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2); - eu->exp = (uint32)(330.0f * tmpxp); - outapp->priority = 6; - QueuePacket(outapp); + // SoF+ Gets Zone-In packets after sending OP_WorldObjectsSent + if (GetClientVersion() < ClientVersion::SoF) + { + SendZoneInPackets(); } - safe_delete(outapp); - - SendAATimers(); - - outapp = new EQApplicationPacket(OP_SendExpZonein, 0); - QueuePacket(outapp); - safe_delete(outapp); - - outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct)); - ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer; - strcpy(zonesendname->name, m_pp.name); - strcpy(zonesendname->name2, m_pp.name); - zonesendname->unknown0 = 0x0A; - QueuePacket(outapp); - safe_delete(outapp); - - /* this is actually the guild MOTD - outapp = new EQApplicationPacket(OP_ZoneInSendName2, sizeof(ZoneInSendName_Struct2)); - ZoneInSendName_Struct2* zonesendname2=(ZoneInSendName_Struct2*)outapp->pBuffer; - strcpy(zonesendname2->name,m_pp.name); - QueuePacket(outapp); - safe_delete(outapp);*/ - - if (IsInAGuild()) { - SendGuildMembers(); - SendGuildURL(); - SendGuildChannel(); - SendGuildLFGuildStatus(); - } - SendLFGuildStatus(); - - //No idea why live sends this if even were not in a guild - SendGuildMOTD(); return; } @@ -1216,72 +1155,13 @@ void Client::Handle_Connect_OP_WearChange(const EQApplicationPacket *app) void Client::Handle_Connect_OP_WorldObjectsSent(const EQApplicationPacket *app) { - //This is a copy of SendExpZonein created for SoF+ due to packet order change - - ////////////////////////////////////////////////////// - // Spawn Appearance Packet - EQApplicationPacket* outapp = new EQApplicationPacket(OP_SpawnAppearance, sizeof(SpawnAppearance_Struct)); - SpawnAppearance_Struct* sa = (SpawnAppearance_Struct*)outapp->pBuffer; - sa->type = AT_SpawnID; // Is 0x10 used to set the player id? - sa->parameter = GetID(); // Four bytes for this parameter... - outapp->priority = 6; + // New for SoF+ + EQApplicationPacket* outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0); QueuePacket(outapp); safe_delete(outapp); - // Inform the world about the client - outapp = new EQApplicationPacket(); - - CreateSpawnPacket(outapp); - outapp->priority = 6; - if (!GetHideMe()) entity_list.QueueClients(this, outapp, true); - safe_delete(outapp); - if (GetPVP()) //force a PVP update until we fix the spawn struct - SendAppearancePacket(AT_PVP, GetPVP(), true, false); - - //Send AA Exp packet: - if (GetLevel() >= 51) - SendAAStats(); - - // Send exp packets - outapp = new EQApplicationPacket(OP_ExpUpdate, sizeof(ExpUpdate_Struct)); - ExpUpdate_Struct* eu = (ExpUpdate_Struct*)outapp->pBuffer; - uint32 tmpxp1 = GetEXPForLevel(GetLevel() + 1); - uint32 tmpxp2 = GetEXPForLevel(GetLevel()); - - // Crash bug fix... Divide by zero when tmpxp1 and 2 equalled each other, most likely the error case from GetEXPForLevel() (invalid class, etc) - if (tmpxp1 != tmpxp2 && tmpxp1 != 0xFFFFFFFF && tmpxp2 != 0xFFFFFFFF) { - float tmpxp = (float)((float)m_pp.exp - tmpxp2) / ((float)tmpxp1 - tmpxp2); - eu->exp = (uint32)(330.0f * tmpxp); - outapp->priority = 6; - QueuePacket(outapp); - } - safe_delete(outapp); - - SendAATimers(); - - // New for Secrets of Faydwer - Used in Place of OP_SendExpZonein - outapp = new EQApplicationPacket(OP_WorldObjectsSent, 0); - QueuePacket(outapp); - safe_delete(outapp); - - outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(ZoneInSendName_Struct)); - ZoneInSendName_Struct* zonesendname = (ZoneInSendName_Struct*)outapp->pBuffer; - strcpy(zonesendname->name, m_pp.name); - strcpy(zonesendname->name2, m_pp.name); - zonesendname->unknown0 = 0x0A; - QueuePacket(outapp); - safe_delete(outapp); - - if (IsInAGuild()) { - SendGuildMembers(); - SendGuildURL(); - SendGuildChannel(); - SendGuildLFGuildStatus(); - } - SendLFGuildStatus(); - - //No idea why live sends this if even were not in a guild - SendGuildMOTD(); + // Packet order changed for SoF+, so below is sent here instead of OP_SendExpLogin + SendZoneInPackets(); if (RuleB(Mercs, AllowMercs)) { From c8acb7bd434edafae8711e26812dc5a74359bcfa Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 10 Feb 2015 23:24:41 -0500 Subject: [PATCH 069/114] numhits issue fix --- zone/attack.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index ef57b4b6b..b98fa1c3e 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3530,6 +3530,10 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons Log.Out(Logs::Detail, Logs::Combat, "Melee Damage reduced to %d", damage); damage = ReduceAllDamage(damage); TryTriggerThreshHold(damage, SE_TriggerMeleeThreshold, attacker); + + if (skill_used) + CheckNumHitsRemaining(NumHit::IncomingHitSuccess); + } else { int32 origdmg = damage; damage = AffectMagicalDamage(damage, spell_id, iBuffTic, attacker); @@ -3545,9 +3549,6 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons TryTriggerThreshHold(damage, SE_TriggerSpellThreshold, attacker); } - if (skill_used) - CheckNumHitsRemaining(NumHit::IncomingHitSuccess); - if(IsClient() && CastToClient()->sneaking){ CastToClient()->sneaking = false; SendAppearancePacket(AT_Sneak, 0); From cefff6506f4446f58bd06a6413af09b86349c07f Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 11 Feb 2015 13:20:32 -0500 Subject: [PATCH 070/114] Fix issue with corpse spawn packets Historically PC corpses used 3; it doesn't appear true with Tit+ Test case target a corpse and /ttell it :P --- zone/corpse.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 9f91b584b..767159ce7 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -1271,11 +1271,7 @@ void Corpse::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { Mob::FillSpawnStruct(ns, ForWho); ns->spawn.max_hp = 120; - - if (IsPlayerCorpse()) - ns->spawn.NPC = 3; - else - ns->spawn.NPC = 2; + ns->spawn.NPC = 2; UpdateActiveLightValue(); ns->spawn.light = active_light; From 2c31b348c3e2dca1744b81f66672968afab880da Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 11 Feb 2015 16:26:55 -0500 Subject: [PATCH 071/114] RoF2 shared bank plat --- common/patches/rof2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index d0189e56a..ab00d8889 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -2493,7 +2493,7 @@ namespace RoF2 outapp->WriteUInt32(emu->silver_bank); outapp->WriteUInt32(emu->copper_bank); - outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(emu->platinum_shared); outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown From 9f400c8d145d5bf6e7090a64c2e04408f1dbc547 Mon Sep 17 00:00:00 2001 From: Uleat Date: Wed, 11 Feb 2015 17:10:45 -0500 Subject: [PATCH 072/114] SharedBank Plat and Item HotKey fixes for RoF --- common/patches/rof.cpp | 4 ++-- common/patches/rof_structs.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 772e60517..0906e9915 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -2418,7 +2418,7 @@ namespace RoF outapp->WriteUInt32(emu->silver_bank); outapp->WriteUInt32(emu->copper_bank); - outapp->WriteUInt32(0); // Unknown + outapp->WriteUInt32(emu->platinum_shared); outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown outapp->WriteUInt32(0); // Unknown @@ -4983,7 +4983,7 @@ namespace RoF //sprintf(hdr.unknown000, "06e0002Y1W00"); - snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%012d", item->ID); + snprintf(hdr.unknown000, sizeof(hdr.unknown000), "%016d", item->ID); hdr.stacksize = stackable ? charges : 1; hdr.unknown004 = 0; diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index eb531e4d5..417ff2e64 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -4378,7 +4378,7 @@ struct RoFSlotStruct struct ItemSerializationHeader { -/*000*/ char unknown000[13]; // New for HoT. Looks like a string. +/*000*/ char unknown000[17]; // New for HoT. Looks like a string. /*017*/ uint32 stacksize; /*021*/ uint32 unknown004; /*025*/ uint8 slot_type; // 0 = normal, 1 = bank, 2 = shared bank, 9 = merchant, 20 = ? From e07704e36b35ab8ce1bc336e00a8d4fb69836415 Mon Sep 17 00:00:00 2001 From: Trevius Date: Wed, 11 Feb 2015 19:02:52 -0600 Subject: [PATCH 073/114] (RoF+) Bandolier no longer displays a Treasure Chest Icon when no Bandoliers are set. --- changelog.txt | 3 +++ common/patches/rof.cpp | 23 +++++++++++++++++++---- common/patches/rof2.cpp | 23 +++++++++++++++++++---- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/changelog.txt b/changelog.txt index a7a1127dd..af5018313 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/11/2015 == +Trevius: (RoF+) Bandolier no longer displays a Treasure Chest Icon when no Bandoliers are set. + == 02/09/2015 == Trevius: (RoF+) Setting Alt flag on characters in the Guild Management Window is now saved and functional for filtering. Trevius: (RoF+) Guild Invites between RoF+ and previous Clients is now functional. diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 0906e9915..d632fdebd 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -2296,7 +2296,15 @@ namespace RoF { outapp->WriteString(emu->bandoliers[r].items[j].item_name); outapp->WriteUInt32(emu->bandoliers[r].items[j].item_id); - outapp->WriteUInt32(emu->bandoliers[r].items[j].icon); + if (emu->bandoliers[r].items[j].icon) + { + outapp->WriteSInt32(emu->bandoliers[r].items[j].icon); + } + else + { + // If no icon, it must send -1 or Treasure Chest Icon (836) is displayed + outapp->WriteSInt32(-1); + } } } @@ -2308,7 +2316,7 @@ namespace RoF { outapp->WriteString(""); outapp->WriteUInt32(0); - outapp->WriteUInt32(0); + outapp->WriteSInt32(-1); } } @@ -2318,14 +2326,21 @@ namespace RoF { outapp->WriteString(emu->potionbelt.items[r].item_name); outapp->WriteUInt32(emu->potionbelt.items[r].item_id); - outapp->WriteUInt32(emu->potionbelt.items[r].icon); + if (emu->potionbelt.items[r].icon) + { + outapp->WriteSInt32(emu->potionbelt.items[r].icon); + } + else + { + outapp->WriteSInt32(-1); + } } for (uint32 r = 0; r < structs::MAX_POTIONS_IN_BELT - EmuConstants::POTION_BELT_SIZE; r++) { outapp->WriteString(""); outapp->WriteUInt32(0); - outapp->WriteUInt32(0); + outapp->WriteSInt32(-1); } outapp->WriteSInt32(-1); // Unknown; diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index ab00d8889..25c63c52b 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -2370,7 +2370,15 @@ namespace RoF2 { outapp->WriteString(emu->bandoliers[r].items[j].item_name); outapp->WriteUInt32(emu->bandoliers[r].items[j].item_id); - outapp->WriteUInt32(emu->bandoliers[r].items[j].icon); + if (emu->bandoliers[r].items[j].icon) + { + outapp->WriteSInt32(emu->bandoliers[r].items[j].icon); + } + else + { + // If no icon, it must send -1 or Treasure Chest Icon (836) is displayed + outapp->WriteSInt32(-1); + } } } @@ -2382,7 +2390,7 @@ namespace RoF2 { outapp->WriteString(""); outapp->WriteUInt32(0); - outapp->WriteUInt32(0); + outapp->WriteSInt32(-1); } } @@ -2392,14 +2400,21 @@ namespace RoF2 { outapp->WriteString(emu->potionbelt.items[r].item_name); outapp->WriteUInt32(emu->potionbelt.items[r].item_id); - outapp->WriteUInt32(emu->potionbelt.items[r].icon); + if (emu->potionbelt.items[r].icon) + { + outapp->WriteSInt32(emu->potionbelt.items[r].icon); + } + else + { + outapp->WriteSInt32(-1); + } } for (uint32 r = 0; r < structs::MAX_POTIONS_IN_BELT - EmuConstants::POTION_BELT_SIZE; r++) { outapp->WriteString(""); outapp->WriteUInt32(0); - outapp->WriteUInt32(0); + outapp->WriteSInt32(-1); } outapp->WriteSInt32(-1); // Unknown; From 2774d8e7618333f48c1f6c625b9a80919bb4a390 Mon Sep 17 00:00:00 2001 From: KimLS Date: Wed, 11 Feb 2015 21:56:58 -0800 Subject: [PATCH 074/114] AddToHateList will no longer assert on other = nullptr, it will now just do nothing. Since the function can be called from perl/lua it's inapprops to let them just crash the server with an abort() from assert. --- zone/attack.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index b98fa1c3e..814a474e8 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -2404,8 +2404,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/) { - - assert(other != nullptr); + if(!other) + return; if (other == this) return; From 16002eb62eb450bdcb029ea940b4d75704727be8 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Thu, 12 Feb 2015 01:54:41 -0600 Subject: [PATCH 075/114] ClientTaskState::GetTaskActivityDoneCountFromTaskID invalid Index return (Crash fix) --- zone/tasks.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zone/tasks.cpp b/zone/tasks.cpp index 98a0ec4c5..4f3fe8124 100644 --- a/zone/tasks.cpp +++ b/zone/tasks.cpp @@ -2873,6 +2873,9 @@ int ClientTaskState::GetTaskActivityDoneCountFromTaskID(int TaskID, int Activity } } + if (ActiveTaskIndex == -1) + return 0; + if (ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount){ return ActiveTasks[ActiveTaskIndex].Activity[ActivityID].DoneCount; } From d1be53bef2650ca80b2fc67025187a84498f65b5 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 12 Feb 2015 13:57:10 -0500 Subject: [PATCH 076/114] Fix RoF2 disc stuff --- common/patches/rof2_structs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 95f5c31e6..0935517c1 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -114,7 +114,7 @@ static const uint32 MAX_PP_SPELLBOOK = 720; // was 480 static const uint32 MAX_PP_MEMSPELL = 16; // was 12 static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE; // 100 - actual skills buffer size static const uint32 MAX_PP_AA_ARRAY = 300; -static const uint32 MAX_PP_DISCIPLINES = 200; // was 100 +static const uint32 MAX_PP_DISCIPLINES = 300; // was 200 static const uint32 MAX_GROUP_MEMBERS = 6; static const uint32 MAX_RECAST_TYPES = 20; From 196632411245173a02e82bc5f8697847e2a2610f Mon Sep 17 00:00:00 2001 From: Akkadius Date: Thu, 12 Feb 2015 19:57:24 -0600 Subject: [PATCH 077/114] Changed NPCTypes Data to bulk load when the zone loads or Repops, this bulk loading is stored in the npc_types cache --- zone/aa.cpp | 6 +- zone/client.cpp | 2 +- zone/command.cpp | 6 +- zone/forage.cpp | 2 +- zone/pets.cpp | 4 +- zone/quest_parser_collection.cpp | 2 +- zone/questmgr.cpp | 8 +- zone/spawn2.cpp | 5 +- zone/trap.cpp | 6 +- zone/zone.cpp | 10 +- zone/zonedb.cpp | 409 ++++++++++++++++++------------- zone/zonedb.h | 2 +- 12 files changed, 268 insertions(+), 194 deletions(-) diff --git a/zone/aa.cpp b/zone/aa.cpp index 238c4e52e..b0208326a 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -525,7 +525,7 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u NPCType *made_npc = nullptr; - const NPCType *npc_type = database.GetNPCType(pet.npc_id); + const NPCType *npc_type = database.LoadNPCTypesData(pet.npc_id); if(npc_type == nullptr) { //log write Log.Out(Logs::General, Logs::Error, "Unknown npc type for swarm pet spell id: %d", spell_id); @@ -622,7 +622,7 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid NPCType *made_npc = nullptr; - const NPCType *npc_type = database.GetNPCType(typesid); + const NPCType *npc_type = database.LoadNPCTypesData(typesid); if(npc_type == nullptr) { //log write Log.Out(Logs::General, Logs::Error, "Unknown npc type for swarm pet type id: %d", typesid); @@ -715,7 +715,7 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration) return; //assuming we have pets in our table; we take the first pet as a base type. - const NPCType *base_type = database.GetNPCType(500); + const NPCType *base_type = database.LoadNPCTypesData(500); NPCType *make_npc = new NPCType; memcpy(make_npc, base_type, sizeof(NPCType)); diff --git a/zone/client.cpp b/zone/client.cpp index b5575a307..9af91988c 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -6244,7 +6244,7 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid NPCType *made_npc = nullptr; - const NPCType *npc_type = database.GetNPCType(pet.npc_id); + const NPCType *npc_type = database.LoadNPCTypesData(pet.npc_id); if(npc_type == nullptr) { Log.Out(Logs::General, Logs::Error, "Unknown npc type for doppelganger spell id: %d", spell_id); Message(0,"Unable to find pet!"); diff --git a/zone/command.cpp b/zone/command.cpp index 96a43d17a..ff81e73ed 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -2461,7 +2461,7 @@ void command_npctypespawn(Client *c, const Seperator *sep) { if (sep->IsNumber(1)) { const NPCType* tmp = 0; - if ((tmp = database.GetNPCType(atoi(sep->arg[1])))) { + if ((tmp = database.LoadNPCTypesData(atoi(sep->arg[1])))) { //tmp->fixedZ = 1; NPC* npc = new NPC(tmp, 0, c->GetPosition(), FlyMode3); if (npc && sep->IsNumber(2)) @@ -2923,7 +2923,7 @@ void command_viewnpctype(Client *c, const Seperator *sep) else { uint32 npctypeid=atoi(sep->arg[1]); - const NPCType* npct = database.GetNPCType(npctypeid); + const NPCType* npct = database.LoadNPCTypesData(npctypeid); if (npct) { c->Message(0, " NPCType Info, "); c->Message(0, " NPCTypeID: %u", npct->npc_id); @@ -6687,7 +6687,7 @@ void command_qglobal(Client *c, const Seperator *sep) { } if(!strcasecmp(sep->arg[1], "view")) { - const NPCType *type = database.GetNPCType(target->GetNPCTypeID()); + const NPCType *type = database.LoadNPCTypesData(target->GetNPCTypeID()); if(!type) c->Message(15, "Invalid NPC type."); else if(type->qglobal) diff --git a/zone/forage.cpp b/zone/forage.cpp index 7e82aa5d3..96b0efcdc 100644 --- a/zone/forage.cpp +++ b/zone/forage.cpp @@ -270,7 +270,7 @@ void Client::GoFish() //check for add NPC if(npc_chance > 0 && npc_id) { if(npc_chance < zone->random.Int(0, 99)) { - const NPCType* tmp = database.GetNPCType(npc_id); + const NPCType* tmp = database.LoadNPCTypesData(npc_id); if(tmp != nullptr) { auto positionNPC = GetPosition(); positionNPC.x = positionNPC.x + 3; diff --git a/zone/pets.cpp b/zone/pets.cpp index 871e9bc6c..aaec461d4 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -248,7 +248,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, } //find the NPC data for the specified NPC type - const NPCType *base = database.GetNPCType(record.npc_type); + const NPCType *base = database.LoadNPCTypesData(record.npc_type); if(base == nullptr) { Message(13, "Unable to load NPC data for pet %s", pettype); Log.Out(Logs::General, Logs::Error, "Unable to load NPC data for pet %s (NPC ID %d), check pets and npc_types tables.", pettype, record.npc_type); @@ -384,7 +384,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, monsterid = 567; // give the summoned pet the attributes of the monster we found - const NPCType* monster = database.GetNPCType(monsterid); + const NPCType* monster = database.LoadNPCTypesData(monsterid); if(monster) { npc_type->race = monster->race; npc_type->size = monster->size; diff --git a/zone/quest_parser_collection.cpp b/zone/quest_parser_collection.cpp index 3351e6cc4..37e518c24 100644 --- a/zone/quest_parser_collection.cpp +++ b/zone/quest_parser_collection.cpp @@ -483,7 +483,7 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string } //second look for /quests/zone/npcname.ext (precedence) - const NPCType *npc_type = database.GetNPCType(npcid); + const NPCType *npc_type = database.LoadNPCTypesData(npcid); if(!npc_type) { return nullptr; } diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 7dcb4e457..97992e0bc 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -203,7 +203,7 @@ void QuestManager::write(const char *file, const char *str) { Mob* QuestManager::spawn2(int npc_type, int grid, int unused, const glm::vec4& position) { const NPCType* tmp = 0; - if (tmp = database.GetNPCType(npc_type)) + if (tmp = database.LoadNPCTypesData(npc_type)) { NPC* npc = new NPC(tmp, nullptr, position, FlyMode3); npc->AddLootTable(); @@ -225,7 +225,7 @@ Mob* QuestManager::unique_spawn(int npc_type, int grid, int unused, const glm::v } const NPCType* tmp = 0; - if (tmp = database.GetNPCType(npc_type)) + if (tmp = database.LoadNPCTypesData(npc_type)) { NPC* npc = new NPC(tmp, nullptr, position, FlyMode3); npc->AddLootTable(); @@ -275,7 +275,7 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id) return nullptr; } - const NPCType* tmp = database.GetNPCType(npcid); + const NPCType* tmp = database.LoadNPCTypesData(npcid); if(!tmp) { return nullptr; @@ -1574,7 +1574,7 @@ void QuestManager::respawn(int npcTypeID, int grid) { quests_running_.push(e); const NPCType* npcType = nullptr; - if ((npcType = database.GetNPCType(npcTypeID))) + if ((npcType = database.LoadNPCTypesData(npcTypeID))) { owner = new NPC(npcType, nullptr, owner->GetPosition(), FlyMode3); owner->CastToNPC()->AddLootTable(); diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index 068774091..c0eafea80 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -183,7 +183,7 @@ bool Spawn2::Process() { } //try to find our NPC type. - const NPCType* tmp = database.GetNPCType(npcid); + const NPCType* tmp = database.LoadNPCTypesData(npcid); if (tmp == nullptr) { Log.Out(Logs::Detail, Logs::Spawns, "Spawn2 %d: Spawn group %d yeilded an invalid NPC type %d", spawn2_id, spawngroup_id_, npcid); Reset(); //try again later @@ -358,6 +358,9 @@ bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList &spa timeval tv; gettimeofday(&tv, nullptr); + /* Bulk Load NPC Types Data into the cache */ + database.LoadNPCTypesData(0, true); + std::string spawn_query = StringFormat( "SELECT " "respawn_times.id, " diff --git a/zone/trap.cpp b/zone/trap.cpp index 2c940cae7..9462e658a 100644 --- a/zone/trap.cpp +++ b/zone/trap.cpp @@ -142,7 +142,7 @@ void Trap::Trigger(Mob* trigger) for (i = 0; i < effectvalue2; i++) { - if ((tmp = database.GetNPCType(effectvalue))) + if ((tmp = database.LoadNPCTypesData(effectvalue))) { auto randomOffset = glm::vec4(zone->random.Int(-5, 5),zone->random.Int(-5, 5),zone->random.Int(-5, 5), zone->random.Int(0, 249)); auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f); @@ -165,7 +165,7 @@ void Trap::Trigger(Mob* trigger) for (i = 0; i < effectvalue2; i++) { - if ((tmp = database.GetNPCType(effectvalue))) + if ((tmp = database.LoadNPCTypesData(effectvalue))) { auto randomOffset = glm::vec4(zone->random.Int(-2, 2), zone->random.Int(-2, 2), zone->random.Int(-2, 2), zone->random.Int(0, 249)); auto spawnPosition = randomOffset + glm::vec4(m_Position, 0.0f); @@ -294,7 +294,7 @@ void Trap::CreateHiddenTrigger() if(hiddenTrigger) return; - const NPCType *base_type = database.GetNPCType(500); + const NPCType *base_type = database.LoadNPCTypesData(500); NPCType *make_npc = new NPCType; memcpy(make_npc, base_type, sizeof(NPCType)); make_npc->max_hp = 100000; diff --git a/zone/zone.cpp b/zone/zone.cpp index e79a9f9af..b8fb3c752 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -1426,14 +1426,12 @@ bool Zone::Depop(bool StartSpawnTimer) { std::map::iterator itr; entity_list.Depop(StartSpawnTimer); -#ifdef DEPOP_INVALIDATES_NPC_TYPES_CACHE - // Refresh npctable, getting current info from database. - while(npctable.size()) { - itr=npctable.begin(); + /* Refresh npctable (cache), getting current info from database. */ + while(npctable.size()) { + itr = npctable.begin(); delete itr->second; npctable.erase(itr); } -#endif return true; } @@ -2165,7 +2163,7 @@ void Zone::DoAdventureActions() { if(ds->assa_count >= RuleI(Adventure, NumberKillsForBossSpawn)) { - const NPCType* tmp = database.GetNPCType(ds->data_id); + const NPCType* tmp = database.LoadNPCTypesData(ds->data_id); if(tmp) { NPC* npc = new NPC(tmp, nullptr, glm::vec4(ds->assa_x, ds->assa_y, ds->assa_z, ds->assa_h), FlyMode3); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 6cb15d16e..4d815b192 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1719,166 +1719,240 @@ bool ZoneDatabase::NoRentExpired(const char* name){ return (seconds>1800); } -/* Searches npctable for matching id, and returns the item if found, - * or nullptr otherwise. If id passed is 0, loads all npc_types for - * the current zone, returning the last item added. - */ -const NPCType* ZoneDatabase::GetNPCType (uint32 id) { - const NPCType *npc=nullptr; +const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load /*= false*/) +{ + const NPCType *npc = nullptr; - // If NPC is already in tree, return it. - auto itr = zone->npctable.find(id); + /* If there is a cached NPC entry, load it */ + auto itr = zone->npctable.find(npc_type_id); if(itr != zone->npctable.end()) return itr->second; - // Otherwise, get NPCs from database. + std::string where_condition = ""; + if (bulk_load){ + Log.Out(Logs::General, Logs::Debug, "Performing bulk NPC Types load"); + where_condition = StringFormat( + "INNER JOIN spawnentry ON npc_types.id = spawnentry.npcID " + "INNER JOIN spawn2 ON spawnentry.spawngroupID = spawn2.spawngroupID " + "WHERE spawn2.zone = '%s' and spawn2.version = %u GROUP BY npc_types.id", zone->GetShortName(), zone->GetInstanceVersion()); + } + else{ + where_condition = StringFormat("WHERE id = %u", npc_type_id); + } - // If id is 0, load all npc_types for the current zone, - // according to spawn2. - std::string query = StringFormat("SELECT npc_types.id, npc_types.name, npc_types.level, npc_types.race, " - "npc_types.class, npc_types.hp, npc_types.mana, npc_types.gender, " - "npc_types.texture, npc_types.helmtexture, npc_types.herosforgemodel, npc_types.size, " - "npc_types.loottable_id, npc_types.merchant_id, npc_types.alt_currency_id, " - "npc_types.adventure_template_id, npc_types.trap_template, npc_types.attack_speed, " - "npc_types.STR, npc_types.STA, npc_types.DEX, npc_types.AGI, npc_types._INT, " - "npc_types.WIS, npc_types.CHA, npc_types.MR, npc_types.CR, npc_types.DR, " - "npc_types.FR, npc_types.PR, npc_types.Corrup, npc_types.PhR, " - "npc_types.mindmg, npc_types.maxdmg, npc_types.attack_count, npc_types.special_abilities, " - "npc_types.npc_spells_id, npc_types.npc_spells_effects_id, npc_types.d_melee_texture1, " - "npc_types.d_melee_texture2, npc_types.ammo_idfile, npc_types.prim_melee_type, " - "npc_types.sec_melee_type, npc_types.ranged_type, npc_types.runspeed, npc_types.findable, " - "npc_types.trackable, npc_types.hp_regen_rate, npc_types.mana_regen_rate, " - "npc_types.aggroradius, npc_types.assistradius, npc_types.bodytype, npc_types.npc_faction_id, " - "npc_types.face, npc_types.luclin_hairstyle, npc_types.luclin_haircolor, " - "npc_types.luclin_eyecolor, npc_types.luclin_eyecolor2, npc_types.luclin_beardcolor," - "npc_types.luclin_beard, npc_types.drakkin_heritage, npc_types.drakkin_tattoo, " - "npc_types.drakkin_details, npc_types.armortint_id, " - "npc_types.armortint_red, npc_types.armortint_green, npc_types.armortint_blue, " - "npc_types.see_invis, npc_types.see_invis_undead, npc_types.lastname, " - "npc_types.qglobal, npc_types.AC, npc_types.npc_aggro, npc_types.spawn_limit, " - "npc_types.see_hide, npc_types.see_improved_hide, npc_types.ATK, npc_types.Accuracy, " - "npc_types.Avoidance, npc_types.slow_mitigation, npc_types.maxlevel, npc_types.scalerate, " - "npc_types.private_corpse, npc_types.unique_spawn_by_name, npc_types.underwater, " - "npc_types.emoteid, npc_types.spellscale, npc_types.healscale, npc_types.no_target_hotkey, " - "npc_types.raid_target, npc_types.attack_delay, npc_types.light FROM npc_types WHERE id = %d", id); + std::string query = StringFormat("SELECT " + "npc_types.id, " + "npc_types.name, " + "npc_types.level, " + "npc_types.race, " + "npc_types.class, " + "npc_types.hp, " + "npc_types.mana, " + "npc_types.gender, " + "npc_types.texture, " + "npc_types.helmtexture, " + "npc_types.herosforgemodel, " + "npc_types.size, " + "npc_types.loottable_id, " + "npc_types.merchant_id, " + "npc_types.alt_currency_id, " + "npc_types.adventure_template_id, " + "npc_types.trap_template, " + "npc_types.attack_speed, " + "npc_types.STR, " + "npc_types.STA, " + "npc_types.DEX, " + "npc_types.AGI, " + "npc_types._INT, " + "npc_types.WIS, " + "npc_types.CHA, " + "npc_types.MR, " + "npc_types.CR, " + "npc_types.DR, " + "npc_types.FR, " + "npc_types.PR, " + "npc_types.Corrup, " + "npc_types.PhR, " + "npc_types.mindmg, " + "npc_types.maxdmg, " + "npc_types.attack_count, " + "npc_types.special_abilities, " + "npc_types.npc_spells_id, " + "npc_types.npc_spells_effects_id, " + "npc_types.d_melee_texture1, " + "npc_types.d_melee_texture2, " + "npc_types.ammo_idfile, " + "npc_types.prim_melee_type, " + "npc_types.sec_melee_type, " + "npc_types.ranged_type, " + "npc_types.runspeed, " + "npc_types.findable, " + "npc_types.trackable, " + "npc_types.hp_regen_rate, " + "npc_types.mana_regen_rate, " + "npc_types.aggroradius, " + "npc_types.assistradius, " + "npc_types.bodytype, " + "npc_types.npc_faction_id, " + "npc_types.face, " + "npc_types.luclin_hairstyle, " + "npc_types.luclin_haircolor, " + "npc_types.luclin_eyecolor, " + "npc_types.luclin_eyecolor2, " + "npc_types.luclin_beardcolor, " + "npc_types.luclin_beard, " + "npc_types.drakkin_heritage, " + "npc_types.drakkin_tattoo, " + "npc_types.drakkin_details, " + "npc_types.armortint_id, " + "npc_types.armortint_red, " + "npc_types.armortint_green, " + "npc_types.armortint_blue, " + "npc_types.see_invis, " + "npc_types.see_invis_undead, " + "npc_types.lastname, " + "npc_types.qglobal, " + "npc_types.AC, " + "npc_types.npc_aggro, " + "npc_types.spawn_limit, " + "npc_types.see_hide, " + "npc_types.see_improved_hide, " + "npc_types.ATK, " + "npc_types.Accuracy, " + "npc_types.Avoidance, " + "npc_types.slow_mitigation, " + "npc_types.maxlevel, " + "npc_types.scalerate, " + "npc_types.private_corpse, " + "npc_types.unique_spawn_by_name, " + "npc_types.underwater, " + "npc_types.emoteid, " + "npc_types.spellscale, " + "npc_types.healscale, " + "npc_types.no_target_hotkey, " + "npc_types.raid_target, " + "npc_types.attack_delay, " + "npc_types.light " + "FROM npc_types %s", + where_condition.c_str() + ); auto results = QueryDatabase(query); if (!results.Success()) { return nullptr; } - for (auto row = results.begin(); row != results.end(); ++row) { - NPCType *tmpNPCType; - tmpNPCType = new NPCType; - memset (tmpNPCType, 0, sizeof *tmpNPCType); + NPCType *temp_npctype_data; + temp_npctype_data = new NPCType; + memset (temp_npctype_data, 0, sizeof *temp_npctype_data); - tmpNPCType->npc_id = atoi(row[0]); + temp_npctype_data->npc_id = atoi(row[0]); - strn0cpy(tmpNPCType->name, row[1], 50); + strn0cpy(temp_npctype_data->name, row[1], 50); - tmpNPCType->level = atoi(row[2]); - tmpNPCType->race = atoi(row[3]); - tmpNPCType->class_ = atoi(row[4]); - tmpNPCType->max_hp = atoi(row[5]); - tmpNPCType->cur_hp = tmpNPCType->max_hp; - tmpNPCType->Mana = atoi(row[6]); - tmpNPCType->gender = atoi(row[7]); - tmpNPCType->texture = atoi(row[8]); - tmpNPCType->helmtexture = atoi(row[9]); - tmpNPCType->herosforgemodel = atoul(row[10]); - tmpNPCType->size = atof(row[11]); - tmpNPCType->loottable_id = atoi(row[12]); - tmpNPCType->merchanttype = atoi(row[13]); - tmpNPCType->alt_currency_type = atoi(row[14]); - tmpNPCType->adventure_template = atoi(row[15]); - tmpNPCType->trap_template = atoi(row[16]); - tmpNPCType->attack_speed = atof(row[17]); - tmpNPCType->STR = atoi(row[18]); - tmpNPCType->STA = atoi(row[19]); - tmpNPCType->DEX = atoi(row[20]); - tmpNPCType->AGI = atoi(row[21]); - tmpNPCType->INT = atoi(row[22]); - tmpNPCType->WIS = atoi(row[23]); - tmpNPCType->CHA = atoi(row[24]); - tmpNPCType->MR = atoi(row[25]); - tmpNPCType->CR = atoi(row[26]); - tmpNPCType->DR = atoi(row[27]); - tmpNPCType->FR = atoi(row[28]); - tmpNPCType->PR = atoi(row[29]); - tmpNPCType->Corrup = atoi(row[30]); - tmpNPCType->PhR = atoi(row[31]); - tmpNPCType->min_dmg = atoi(row[32]); - tmpNPCType->max_dmg = atoi(row[33]); - tmpNPCType->attack_count = atoi(row[34]); + temp_npctype_data->level = atoi(row[2]); + temp_npctype_data->race = atoi(row[3]); + temp_npctype_data->class_ = atoi(row[4]); + temp_npctype_data->max_hp = atoi(row[5]); + temp_npctype_data->cur_hp = temp_npctype_data->max_hp; + temp_npctype_data->Mana = atoi(row[6]); + temp_npctype_data->gender = atoi(row[7]); + temp_npctype_data->texture = atoi(row[8]); + temp_npctype_data->helmtexture = atoi(row[9]); + temp_npctype_data->herosforgemodel = atoul(row[10]); + temp_npctype_data->size = atof(row[11]); + temp_npctype_data->loottable_id = atoi(row[12]); + temp_npctype_data->merchanttype = atoi(row[13]); + temp_npctype_data->alt_currency_type = atoi(row[14]); + temp_npctype_data->adventure_template = atoi(row[15]); + temp_npctype_data->trap_template = atoi(row[16]); + temp_npctype_data->attack_speed = atof(row[17]); + temp_npctype_data->STR = atoi(row[18]); + temp_npctype_data->STA = atoi(row[19]); + temp_npctype_data->DEX = atoi(row[20]); + temp_npctype_data->AGI = atoi(row[21]); + temp_npctype_data->INT = atoi(row[22]); + temp_npctype_data->WIS = atoi(row[23]); + temp_npctype_data->CHA = atoi(row[24]); + temp_npctype_data->MR = atoi(row[25]); + temp_npctype_data->CR = atoi(row[26]); + temp_npctype_data->DR = atoi(row[27]); + temp_npctype_data->FR = atoi(row[28]); + temp_npctype_data->PR = atoi(row[29]); + temp_npctype_data->Corrup = atoi(row[30]); + temp_npctype_data->PhR = atoi(row[31]); + temp_npctype_data->min_dmg = atoi(row[32]); + temp_npctype_data->max_dmg = atoi(row[33]); + temp_npctype_data->attack_count = atoi(row[34]); if (row[35] != nullptr) - strn0cpy(tmpNPCType->special_abilities, row[35], 512); + strn0cpy(temp_npctype_data->special_abilities, row[35], 512); else - tmpNPCType->special_abilities[0] = '\0'; + temp_npctype_data->special_abilities[0] = '\0'; - tmpNPCType->npc_spells_id = atoi(row[36]); - tmpNPCType->npc_spells_effects_id = atoi(row[37]); - tmpNPCType->d_melee_texture1 = atoi(row[38]); - tmpNPCType->d_melee_texture2 = atoi(row[39]); - strn0cpy(tmpNPCType->ammo_idfile, row[40], 30); - tmpNPCType->prim_melee_type = atoi(row[41]); - tmpNPCType->sec_melee_type = atoi(row[42]); - tmpNPCType->ranged_type = atoi(row[43]); - tmpNPCType->runspeed= atof(row[44]); - tmpNPCType->findable = atoi(row[45]) == 0? false : true; - tmpNPCType->trackable = atoi(row[46]) == 0? false : true; - tmpNPCType->hp_regen = atoi(row[47]); - tmpNPCType->mana_regen = atoi(row[48]); + temp_npctype_data->npc_spells_id = atoi(row[36]); + temp_npctype_data->npc_spells_effects_id = atoi(row[37]); + temp_npctype_data->d_melee_texture1 = atoi(row[38]); + temp_npctype_data->d_melee_texture2 = atoi(row[39]); + strn0cpy(temp_npctype_data->ammo_idfile, row[40], 30); + temp_npctype_data->prim_melee_type = atoi(row[41]); + temp_npctype_data->sec_melee_type = atoi(row[42]); + temp_npctype_data->ranged_type = atoi(row[43]); + temp_npctype_data->runspeed= atof(row[44]); + temp_npctype_data->findable = atoi(row[45]) == 0? false : true; + temp_npctype_data->trackable = atoi(row[46]) == 0? false : true; + temp_npctype_data->hp_regen = atoi(row[47]); + temp_npctype_data->mana_regen = atoi(row[48]); // set default value for aggroradius - tmpNPCType->aggroradius = (int32)atoi(row[49]); - if (tmpNPCType->aggroradius <= 0) - tmpNPCType->aggroradius = 70; + temp_npctype_data->aggroradius = (int32)atoi(row[49]); + if (temp_npctype_data->aggroradius <= 0) + temp_npctype_data->aggroradius = 70; - tmpNPCType->assistradius = (int32)atoi(row[50]); - if (tmpNPCType->assistradius <= 0) - tmpNPCType->assistradius = tmpNPCType->aggroradius; + temp_npctype_data->assistradius = (int32)atoi(row[50]); + if (temp_npctype_data->assistradius <= 0) + temp_npctype_data->assistradius = temp_npctype_data->aggroradius; if (row[51] && strlen(row[51])) - tmpNPCType->bodytype = (uint8)atoi(row[51]); + temp_npctype_data->bodytype = (uint8)atoi(row[51]); else - tmpNPCType->bodytype = 0; + temp_npctype_data->bodytype = 0; - tmpNPCType->npc_faction_id = atoi(row[52]); + temp_npctype_data->npc_faction_id = atoi(row[52]); - tmpNPCType->luclinface = atoi(row[53]); - tmpNPCType->hairstyle = atoi(row[54]); - tmpNPCType->haircolor = atoi(row[55]); - tmpNPCType->eyecolor1 = atoi(row[56]); - tmpNPCType->eyecolor2 = atoi(row[57]); - tmpNPCType->beardcolor = atoi(row[58]); - tmpNPCType->beard = atoi(row[59]); - tmpNPCType->drakkin_heritage = atoi(row[60]); - tmpNPCType->drakkin_tattoo = atoi(row[61]); - tmpNPCType->drakkin_details = atoi(row[62]); + temp_npctype_data->luclinface = atoi(row[53]); + temp_npctype_data->hairstyle = atoi(row[54]); + temp_npctype_data->haircolor = atoi(row[55]); + temp_npctype_data->eyecolor1 = atoi(row[56]); + temp_npctype_data->eyecolor2 = atoi(row[57]); + temp_npctype_data->beardcolor = atoi(row[58]); + temp_npctype_data->beard = atoi(row[59]); + temp_npctype_data->drakkin_heritage = atoi(row[60]); + temp_npctype_data->drakkin_tattoo = atoi(row[61]); + temp_npctype_data->drakkin_details = atoi(row[62]); uint32 armor_tint_id = atoi(row[63]); - tmpNPCType->armor_tint[0] = (atoi(row[64]) & 0xFF) << 16; - tmpNPCType->armor_tint[0] |= (atoi(row[65]) & 0xFF) << 8; - tmpNPCType->armor_tint[0] |= (atoi(row[66]) & 0xFF); - tmpNPCType->armor_tint[0] |= (tmpNPCType->armor_tint[0]) ? (0xFF << 24) : 0; + temp_npctype_data->armor_tint[0] = (atoi(row[64]) & 0xFF) << 16; + temp_npctype_data->armor_tint[0] |= (atoi(row[65]) & 0xFF) << 8; + temp_npctype_data->armor_tint[0] |= (atoi(row[66]) & 0xFF); + temp_npctype_data->armor_tint[0] |= (temp_npctype_data->armor_tint[0]) ? (0xFF << 24) : 0; - if (armor_tint_id != 0) - { - std::string armortint_query = StringFormat("SELECT red1h, grn1h, blu1h, " - "red2c, grn2c, blu2c, " - "red3a, grn3a, blu3a, " - "red4b, grn4b, blu4b, " - "red5g, grn5g, blu5g, " - "red6l, grn6l, blu6l, " - "red7f, grn7f, blu7f, " - "red8x, grn8x, blu8x, " - "red9x, grn9x, blu9x " - "FROM npc_types_tint WHERE id = %d", - armor_tint_id); + if (armor_tint_id != 0) { + std::string armortint_query = StringFormat( + "SELECT red1h, grn1h, blu1h, " + "red2c, grn2c, blu2c, " + "red3a, grn3a, blu3a, " + "red4b, grn4b, blu4b, " + "red5g, grn5g, blu5g, " + "red6l, grn6l, blu6l, " + "red7f, grn7f, blu7f, " + "red8x, grn8x, blu8x, " + "red9x, grn9x, blu9x " + "FROM npc_types_tint WHERE id = %d", + armor_tint_id); auto armortint_results = QueryDatabase(armortint_query); if (!armortint_results.Success() || armortint_results.RowCount() == 0) armor_tint_id = 0; @@ -1886,60 +1960,59 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { auto armorTint_row = armortint_results.begin(); for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++) { - tmpNPCType->armor_tint[index] = atoi(armorTint_row[index * 3]) << 16; - tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 1]) << 8; - tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 2]); - tmpNPCType->armor_tint[index] |= (tmpNPCType->armor_tint[index]) ? (0xFF << 24) : 0; + temp_npctype_data->armor_tint[index] = atoi(armorTint_row[index * 3]) << 16; + temp_npctype_data->armor_tint[index] |= atoi(armorTint_row[index * 3 + 1]) << 8; + temp_npctype_data->armor_tint[index] |= atoi(armorTint_row[index * 3 + 2]); + temp_npctype_data->armor_tint[index] |= (temp_npctype_data->armor_tint[index]) ? (0xFF << 24) : 0; } } } // Try loading npc_types tint fields if armor tint is 0 or query failed to get results - if (armor_tint_id == 0) - { - for (int index = MaterialChest; index < _MaterialCount; index++) - { - tmpNPCType->armor_tint[index] = tmpNPCType->armor_tint[0]; + if (armor_tint_id == 0) { + for (int index = MaterialChest; index < _MaterialCount; index++) { + temp_npctype_data->armor_tint[index] = temp_npctype_data->armor_tint[0]; } } - tmpNPCType->see_invis = atoi(row[67]); - tmpNPCType->see_invis_undead = atoi(row[68]) == 0? false: true; // Set see_invis_undead flag - if (row[69] != nullptr) - strn0cpy(tmpNPCType->lastname, row[69], 32); + temp_npctype_data->see_invis = atoi(row[67]); + temp_npctype_data->see_invis_undead = atoi(row[68]) == 0? false: true; // Set see_invis_undead flag - tmpNPCType->qglobal = atoi(row[70]) == 0? false: true; // qglobal - tmpNPCType->AC = atoi(row[71]); - tmpNPCType->npc_aggro = atoi(row[72]) == 0? false: true; - tmpNPCType->spawn_limit = atoi(row[73]); - tmpNPCType->see_hide = atoi(row[74]) == 0? false: true; - tmpNPCType->see_improved_hide = atoi(row[75]) == 0? false: true; - tmpNPCType->ATK = atoi(row[76]); - tmpNPCType->accuracy_rating = atoi(row[77]); - tmpNPCType->avoidance_rating = atoi(row[78]); - tmpNPCType->slow_mitigation = atoi(row[79]); - tmpNPCType->maxlevel = atoi(row[80]); - tmpNPCType->scalerate = atoi(row[81]); - tmpNPCType->private_corpse = atoi(row[82]) == 1 ? true: false; - tmpNPCType->unique_spawn_by_name = atoi(row[83]) == 1 ? true: false; - tmpNPCType->underwater = atoi(row[84]) == 1 ? true: false; - tmpNPCType->emoteid = atoi(row[85]); - tmpNPCType->spellscale = atoi(row[86]); - tmpNPCType->healscale = atoi(row[87]); - tmpNPCType->no_target_hotkey = atoi(row[88]) == 1 ? true: false; - tmpNPCType->raid_target = atoi(row[89]) == 0 ? false: true; - tmpNPCType->attack_delay = atoi(row[90]); - tmpNPCType->light = (atoi(row[91]) & 0x0F); + if (row[69] != nullptr) + strn0cpy(temp_npctype_data->lastname, row[69], 32); + + temp_npctype_data->qglobal = atoi(row[70]) == 0? false: true; // qglobal + temp_npctype_data->AC = atoi(row[71]); + temp_npctype_data->npc_aggro = atoi(row[72]) == 0? false: true; + temp_npctype_data->spawn_limit = atoi(row[73]); + temp_npctype_data->see_hide = atoi(row[74]) == 0? false: true; + temp_npctype_data->see_improved_hide = atoi(row[75]) == 0? false: true; + temp_npctype_data->ATK = atoi(row[76]); + temp_npctype_data->accuracy_rating = atoi(row[77]); + temp_npctype_data->avoidance_rating = atoi(row[78]); + temp_npctype_data->slow_mitigation = atoi(row[79]); + temp_npctype_data->maxlevel = atoi(row[80]); + temp_npctype_data->scalerate = atoi(row[81]); + temp_npctype_data->private_corpse = atoi(row[82]) == 1 ? true: false; + temp_npctype_data->unique_spawn_by_name = atoi(row[83]) == 1 ? true: false; + temp_npctype_data->underwater = atoi(row[84]) == 1 ? true: false; + temp_npctype_data->emoteid = atoi(row[85]); + temp_npctype_data->spellscale = atoi(row[86]); + temp_npctype_data->healscale = atoi(row[87]); + temp_npctype_data->no_target_hotkey = atoi(row[88]) == 1 ? true: false; + temp_npctype_data->raid_target = atoi(row[89]) == 0 ? false: true; + temp_npctype_data->attack_delay = atoi(row[90]); + temp_npctype_data->light = (atoi(row[91]) & 0x0F); // If NPC with duplicate NPC id already in table, // free item we attempted to add. - if (zone->npctable.find(tmpNPCType->npc_id) != zone->npctable.end()) { - std::cerr << "Error loading duplicate NPC " << tmpNPCType->npc_id << std::endl; - delete tmpNPCType; + if (zone->npctable.find(temp_npctype_data->npc_id) != zone->npctable.end()) { + std::cerr << "Error loading duplicate NPC " << temp_npctype_data->npc_id << std::endl; + delete temp_npctype_data; return nullptr; } - zone->npctable[tmpNPCType->npc_id]=tmpNPCType; - npc = tmpNPCType; + zone->npctable[temp_npctype_data->npc_id] = temp_npctype_data; + npc = temp_npctype_data; } return npc; diff --git a/zone/zonedb.h b/zone/zonedb.h index 70c732878..cac380a96 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -405,7 +405,7 @@ public: DBnpcspells_Struct* GetNPCSpells(uint32 iDBSpellsID); DBnpcspellseffects_Struct* GetNPCSpellsEffects(uint32 iDBSpellsEffectsID); - const NPCType* GetNPCType(uint32 id); + const NPCType* LoadNPCTypesData(uint32 id, bool bulk_load = false); /* Mercs */ const NPCType* GetMercType(uint32 id, uint16 raceid, uint32 clientlevel); From a544c681c77077432df2b41f85d0486472670af6 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Thu, 12 Feb 2015 22:09:17 -0600 Subject: [PATCH 078/114] Implement zone based gravity, required SQL DB change - To test `zone` table `gravity` values, change the value and use #zheader to test --- changelog.txt | 4 + common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + zone/doors.cpp | 2 + zone/zone.cpp | 1 + zone/zonedb.cpp | 184 ++++++++++++++++++++----------- 6 files changed, 126 insertions(+), 68 deletions(-) diff --git a/changelog.txt b/changelog.txt index af5018313..f1ff71c90 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,9 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/12/2015 == +Akkadius: Implement zone based gravity, required SQL DB change + - To test `zone` table `gravity` values, change the value and use #zheader to test + == 02/11/2015 == Trevius: (RoF+) Bandolier no longer displays a Treasure Chest Icon when no Bandoliers are set. diff --git a/common/version.h b/common/version.h index 85dd86b46..7b8cfd78c 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9076 +#define CURRENT_BINARY_DATABASE_VERSION 9077 #define COMPILE_DATE __DATE__ #define COMPILE_TIME __TIME__ #ifndef WIN32 diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index f23638a07..2ad0b647c 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -330,6 +330,7 @@ 9074|2015_02_01_logsys_packet_logs.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client'|empty| 9075|2015_02_02_logsys_packet_logs_with_dump.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client With Dump'|empty| 9076|2015_02_04_average_coin.sql|SHOW COLUMNS FROM `loottable` WHERE Field = 'avgcoin'|contains|smallint +9077|2015_02_12_zone_gravity.sql|SHOW COLUMNS FROM `zone` LIKE 'gravity'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/zone/doors.cpp b/zone/doors.cpp index cf08c509d..4bf2edbe3 100644 --- a/zone/doors.cpp +++ b/zone/doors.cpp @@ -655,6 +655,8 @@ bool ZoneDatabase::LoadDoors(int32 iDoorCount, Door *into, const char *zone_name into[rowIndex].db_id = atoi(row[0]); into[rowIndex].door_id = atoi(row[1]); + Log.Out(Logs::Detail, Logs::Doors, "Door Load: db id: %u, door_id %u", into[rowIndex].db_id, into[rowIndex].door_id); + strn0cpy(into[rowIndex].zone_name,row[2],32); strn0cpy(into[rowIndex].door_name,row[3],32); diff --git a/zone/zone.cpp b/zone/zone.cpp index b8fb3c752..6cd81929f 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -735,6 +735,7 @@ void Zone::LoadZoneDoors(const char* zone, int16 version) for(r = 0; r < count; r++, d++) { Doors* newdoor = new Doors(d); entity_list.AddDoor(newdoor); + Log.Out(Logs::Detail, Logs::Doors, "Door Add to Entity List, index: %u db id: %u, door_id %u", r, dlist[r].db_id, dlist[r].door_id); } delete[] dlist; } diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 4d815b192..b99024c5c 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -97,90 +97,140 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct *map_filename = new char[100]; zone_data->zone_id = zoneid; - std::string query = StringFormat("SELECT ztype, fog_red, fog_green, fog_blue, fog_minclip, fog_maxclip, " // 5 - "fog_red2, fog_green2, fog_blue2, fog_minclip2, fog_maxclip2, " // 5 - "fog_red3, fog_green3, fog_blue3, fog_minclip3, fog_maxclip3, " // 5 - "fog_red4, fog_green4, fog_blue4, fog_minclip4, fog_maxclip4, " // 5 - "fog_density, sky, zone_exp_multiplier, safe_x, safe_y, safe_z, underworld, " // 7 - "minclip, maxclip, time_type, canbind, cancombat, canlevitate, " // 6 - "castoutdoor, hotzone, ruleset, suspendbuffs, map_file_name, short_name, " // 6 - "rain_chance1, rain_chance2, rain_chance3, rain_chance4, " // 4 - "rain_duration1, rain_duration2, rain_duration3, rain_duration4, " // 4 - "snow_chance1, snow_chance2, snow_chance3, snow_chance4, " // 4 - "snow_duration1, snow_duration2, snow_duration3, snow_duration4 " // 4 - "FROM zone WHERE zoneidnumber = %i AND version = %i", zoneid, instance_id); - auto results = QueryDatabase(query); - if (!results.Success()) { - strcpy(*map_filename, "default"); + std::string query = StringFormat( + "SELECT " + "ztype, " // 0 + "fog_red, " // 1 + "fog_green, " // 2 + "fog_blue, " // 3 + "fog_minclip, " // 4 + "fog_maxclip, " // 5 + "fog_red2, " // 6 + "fog_green2, " // 7 + "fog_blue2, " // 8 + "fog_minclip2, " // 9 + "fog_maxclip2, " // 10 + "fog_red3, " // 11 + "fog_green3, " // 12 + "fog_blue3, " // 13 + "fog_minclip3, " // 14 + "fog_maxclip3, " // 15 + "fog_red4, " // 16 + "fog_green4, " // 17 + "fog_blue4, " // 18 + "fog_minclip4, " // 19 + "fog_maxclip4, " // 20 + "fog_density, " // 21 + "sky, " // 22 + "zone_exp_multiplier, " // 23 + "safe_x, " // 24 + "safe_y, " // 25 + "safe_z, " // 26 + "underworld, " // 27 + "minclip, " // 28 + "maxclip, " // 29 + "time_type, " // 30 + "canbind, " // 31 + "cancombat, " // 32 + "canlevitate, " // 33 + "castoutdoor, " // 34 + "hotzone, " // 35 + "ruleset, " // 36 + "suspendbuffs, " // 37 + "map_file_name, " // 38 + "short_name, " // 39 + "rain_chance1, " // 40 + "rain_chance2, " // 41 + "rain_chance3, " // 42 + "rain_chance4, " // 43 + "rain_duration1, " // 44 + "rain_duration2, " // 45 + "rain_duration3, " // 46 + "rain_duration4, " // 47 + "snow_chance1, " // 48 + "snow_chance2, " // 49 + "snow_chance3, " // 50 + "snow_chance4, " // 51 + "snow_duration1, " // 52 + "snow_duration2, " // 53 + "snow_duration3, " // 54 + "snow_duration4, " // 55 + "gravity " // 56 + "FROM zone WHERE zoneidnumber = %i AND version = %i", + zoneid, instance_id); + auto results = QueryDatabase(query); + if (!results.Success()) { + strcpy(*map_filename, "default"); return false; - } + } if (results.RowCount() == 0) { - strcpy(*map_filename, "default"); - return false; - } + strcpy(*map_filename, "default"); + return false; + } - auto row = results.begin(); + auto row = results.begin(); - memset(zone_data, 0, sizeof(NewZone_Struct)); - zone_data->ztype = atoi(row[0]); - zone_type = zone_data->ztype; + memset(zone_data, 0, sizeof(NewZone_Struct)); + zone_data->ztype = atoi(row[0]); + zone_type = zone_data->ztype; - int index; - for(index = 0; index < 4; index++) { - zone_data->fog_red[index]=atoi(row[1 + index * 5]); - zone_data->fog_green[index]=atoi(row[2 + index * 5]); - zone_data->fog_blue[index]=atoi(row[3 + index * 5]); - zone_data->fog_minclip[index]=atof(row[4 + index * 5]); - zone_data->fog_maxclip[index]=atof(row[5 + index * 5]); - } + int index; + for (index = 0; index < 4; index++) { + zone_data->fog_red[index] = atoi(row[1 + index * 5]); + zone_data->fog_green[index] = atoi(row[2 + index * 5]); + zone_data->fog_blue[index] = atoi(row[3 + index * 5]); + zone_data->fog_minclip[index] = atof(row[4 + index * 5]); + zone_data->fog_maxclip[index] = atof(row[5 + index * 5]); + } - zone_data->fog_density = atof(row[21]); - zone_data->sky=atoi(row[22]); - zone_data->zone_exp_multiplier=atof(row[23]); - zone_data->safe_x=atof(row[24]); - zone_data->safe_y=atof(row[25]); - zone_data->safe_z=atof(row[26]); - zone_data->underworld=atof(row[27]); - zone_data->minclip=atof(row[28]); - zone_data->maxclip=atof(row[29]); - zone_data->time_type=atoi(row[30]); + zone_data->fog_density = atof(row[21]); + zone_data->sky = atoi(row[22]); + zone_data->zone_exp_multiplier = atof(row[23]); + zone_data->safe_x = atof(row[24]); + zone_data->safe_y = atof(row[25]); + zone_data->safe_z = atof(row[26]); + zone_data->underworld = atof(row[27]); + zone_data->minclip = atof(row[28]); + zone_data->maxclip = atof(row[29]); + zone_data->time_type = atoi(row[30]); - //not in the DB yet: - zone_data->gravity = 0.4; - allow_mercs = true; + //not in the DB yet: + zone_data->gravity = atof(row[56]); + Log.Out(Logs::General, Logs::Debug, "Zone Gravity is %f", zone_data->gravity); + allow_mercs = true; - int bindable = 0; - bindable = atoi(row[31]); + int bindable = 0; + bindable = atoi(row[31]); - can_bind = bindable == 0? false: true; - is_city = bindable == 2? true: false; - can_combat = atoi(row[32]) == 0? false: true; - can_levitate = atoi(row[33]) == 0? false: true; - can_castoutdoor = atoi(row[34]) == 0? false: true; - is_hotzone = atoi(row[35]) == 0? false: true; + can_bind = bindable == 0 ? false : true; + is_city = bindable == 2 ? true : false; + can_combat = atoi(row[32]) == 0 ? false : true; + can_levitate = atoi(row[33]) == 0 ? false : true; + can_castoutdoor = atoi(row[34]) == 0 ? false : true; + is_hotzone = atoi(row[35]) == 0 ? false : true; - ruleset = atoi(row[36]); - zone_data->SuspendBuffs = atoi(row[37]); + ruleset = atoi(row[36]); + zone_data->SuspendBuffs = atoi(row[37]); - char *file = row[38]; - if(file) - strcpy(*map_filename, file); - else - strcpy(*map_filename, row[39]); + char *file = row[38]; + if (file) + strcpy(*map_filename, file); + else + strcpy(*map_filename, row[39]); - for(index = 0; index < 4; index++) - zone_data->rain_chance[index]=atoi(row[40 + index]); + for (index = 0; index < 4; index++) + zone_data->rain_chance[index] = atoi(row[40 + index]); - for(index = 0; index < 4; index++) - zone_data->rain_duration[index]=atoi(row[44 + index]); + for (index = 0; index < 4; index++) + zone_data->rain_duration[index] = atoi(row[44 + index]); - for(index = 0; index < 4; index++) - zone_data->snow_chance[index]=atoi(row[48 + index]); + for (index = 0; index < 4; index++) + zone_data->snow_chance[index] = atoi(row[48 + index]); - for(index = 0; index < 4; index++) - zone_data->snow_duration[index]=atof(row[52 + index]); + for (index = 0; index < 4; index++) + zone_data->snow_duration[index] = atof(row[52 + index]); return true; } From da425195f91831ccbc862564af24412785cde86c Mon Sep 17 00:00:00 2001 From: Akkadius Date: Thu, 12 Feb 2015 22:32:36 -0600 Subject: [PATCH 079/114] Missed .sql file [skip ci] --- utils/sql/git/required/2015_02_12_zone_gravity.sql | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 utils/sql/git/required/2015_02_12_zone_gravity.sql diff --git a/utils/sql/git/required/2015_02_12_zone_gravity.sql b/utils/sql/git/required/2015_02_12_zone_gravity.sql new file mode 100644 index 000000000..cb475dfe5 --- /dev/null +++ b/utils/sql/git/required/2015_02_12_zone_gravity.sql @@ -0,0 +1,2 @@ +ALTER TABLE `zone` +ADD COLUMN `gravity` float NOT NULL DEFAULT .4 AFTER `snow_duration4`; \ No newline at end of file From 7ac7914f33c9325bde3c59eafbc2f50d30970e98 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 13 Feb 2015 03:50:01 -0600 Subject: [PATCH 080/114] Set door zone to 32 bytes for consistency in copy [skip ci] --- zone/doors.cpp | 28 ++++++++++++++-------------- zone/zonedump.h | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/zone/doors.cpp b/zone/doors.cpp index 4bf2edbe3..d5ad8064d 100644 --- a/zone/doors.cpp +++ b/zone/doors.cpp @@ -41,14 +41,14 @@ extern EntityList entity_list; extern WorldServer worldserver; Doors::Doors(const Door* door) : - close_timer(5000), - m_Position(door->pos_x, door->pos_y, door->pos_z, door->heading), - m_Destination(door->dest_x, door->dest_y, door->dest_z, door->dest_heading) +close_timer(5000), +m_Position(door->pos_x, door->pos_y, door->pos_z, door->heading), +m_Destination(door->dest_x, door->dest_y, door->dest_z, door->dest_heading) { db_id = door->db_id; door_id = door->door_id; - strn0cpy(zone_name,door->zone_name,32); - strn0cpy(door_name,door->door_name,32); + strn0cpy(zone_name, door->zone_name, 32); + strn0cpy(door_name, door->door_name, 32); incline = door->incline; opentype = door->opentype; guild_id = door->guild_id; @@ -57,7 +57,7 @@ Doors::Doors(const Door* door) : nokeyring = door->nokeyring; trigger_door = door->trigger_door; trigger_type = door->trigger_type; - triggered=false; + triggered = false; door_param = door->door_param; size = door->size; invert_state = door->invert_state; @@ -65,7 +65,7 @@ Doors::Doors(const Door* door) : close_timer.Disable(); - strn0cpy(dest_zone,door->dest_zone,16); + strn0cpy(dest_zone, door->dest_zone, 16); dest_instance_id = door->dest_instance_id; is_ldon_door = door->is_ldon_door; @@ -73,14 +73,14 @@ Doors::Doors(const Door* door) : } Doors::Doors(const char *dmodel, const glm::vec4& position, uint8 dopentype, uint16 dsize) : - close_timer(5000), - m_Position(position), - m_Destination(glm::vec4()) +close_timer(5000), +m_Position(position), +m_Destination(glm::vec4()) { db_id = database.GetDoorsCountPlusOne(zone->GetShortName(), zone->GetInstanceVersion()); door_id = database.GetDoorsDBCountPlusOne(zone->GetShortName(), zone->GetInstanceVersion()); - strn0cpy(zone_name,zone->GetShortName(),32); - strn0cpy(door_name,dmodel,32); + strn0cpy(zone_name, zone->GetShortName(), 32); + strn0cpy(door_name, dmodel, 32); incline = 0; opentype = dopentype; guild_id = 0; @@ -89,7 +89,7 @@ Doors::Doors(const char *dmodel, const glm::vec4& position, uint8 dopentype, uin nokeyring = 0; trigger_door = 0; trigger_type = 0; - triggered=false; + triggered = false; door_param = 0; size = dsize; invert_state = 0; @@ -97,7 +97,7 @@ Doors::Doors(const char *dmodel, const glm::vec4& position, uint8 dopentype, uin close_timer.Disable(); - strn0cpy(dest_zone,"NONE",32); + strn0cpy(dest_zone, "NONE", 32); dest_instance_id = 0; is_ldon_door = 0; diff --git a/zone/zonedump.h b/zone/zonedump.h index de10443cb..dc13300e3 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -182,7 +182,7 @@ struct PlayerCorpse_Struct { struct Door { uint32 db_id; uint8 door_id; - char zone_name[16]; + char zone_name[32]; char door_name[32]; float pos_x; float pos_y; From 811e8809ccd60fbdbd542e8635681064cbc95f5a Mon Sep 17 00:00:00 2001 From: Trevius Date: Sat, 14 Feb 2015 11:09:36 -0600 Subject: [PATCH 081/114] (RoF2) Bazaar is now partially functional. RoF2 clients can start/end trader mode and other clients can purchase from them. No other functionality yet. --- changelog.txt | 3 ++ common/eq_packet_structs.h | 2 + common/opcode_dispatch.h | 6 +-- common/patches/rof2.cpp | 53 ++++++++++++++++++++----- common/patches/rof2_ops.h | 3 ++ common/patches/rof2_structs.h | 14 +++++-- common/patches/ss_define.h | 4 +- zone/client_packet.cpp | 75 ++++++++++++++++++++++++----------- zone/trading.cpp | 1 - 9 files changed, 119 insertions(+), 42 deletions(-) diff --git a/changelog.txt b/changelog.txt index f1ff71c90..99da395d8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/14/2015 == +Trevius: (RoF2) Bazaar is now partially functional. RoF2 clients can start/end trader mode and other clients can purchase from them. No other functionality yet. + == 02/12/2015 == Akkadius: Implement zone based gravity, required SQL DB change - To test `zone` table `gravity` values, change the value and use #zheader to test diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 62f6072b3..cd30cf3d1 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -3146,6 +3146,7 @@ struct Trader_ShowItems_Struct{ /*000*/ uint32 Code; /*004*/ uint32 TraderID; /*008*/ uint32 Unknown08[3]; +/*020*/ }; struct TraderBuy_Struct{ @@ -3194,6 +3195,7 @@ struct TraderClick_Struct{ /*004*/ uint32 Unknown004; /*008*/ uint32 Unknown008; /*012*/ uint32 Approval; +/*016*/ }; struct FormattedMessage_Struct{ diff --git a/common/opcode_dispatch.h b/common/opcode_dispatch.h index 46e8b9099..657d9a525 100644 --- a/common/opcode_dispatch.h +++ b/common/opcode_dispatch.h @@ -180,7 +180,7 @@ IN(OP_GMLastName, GMLastName_Struct); IN(OP_GMToggle, GMToggle_Struct); IN(OP_LFGCommand, LFG_Struct); IN(OP_GMGoto, GMSummon_Struct); -IN(OP_TraderShop, TraderClick_Struct); +INv(OP_TraderShop, TraderClick_Struct); IN(OP_ShopRequest, Merchant_Click_Struct); IN(OP_Bazaar, BazaarSearch_Struct); //alt:IN(OP_Bazaar, BazaarWelcome_Struct); //alternate structure for OP_Bazaar @@ -399,7 +399,7 @@ OUT(OP_Weather, Weather_Struct); OUT(OP_ZoneChange, ZoneChange_Struct); OUT(OP_ZoneInUnknown, ZoneInUnknown_Struct); -//this is the set of opcodes which are allready listed +//this is the set of opcodes which are already listed //in the IN section above, but are also sent OUT #ifdef DISJOINT_DIRECTIONS OUTz(OP_ClientReady); //follows OP_SetServerFilter @@ -449,7 +449,7 @@ OUT(OP_Trader, TraderBuy_Struct); //3 possible lengths //alt:OUT(OP_Trader, Trader_ShowItems_Struct); //alt:OUT(OP_Trader, Trader_Struct); OUT(OP_TraderBuy, TraderBuy_Struct); -OUT(OP_TraderShop, TraderClick_Struct); +OUTv(OP_TraderShop, TraderClick_Struct); OUT(OP_WearChange, WearChange_Struct); OUT(OP_ZoneEntry, ServerZoneEntry_Struct); #endif diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 25c63c52b..f1c89ff2f 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -3578,7 +3578,9 @@ namespace RoF2 // Live actually has 200 items now, but 80 is the most our internal struct supports for (uint32 i = 0; i < 200; i++) { - strncpy(eq->items[i].SerialNumber, "0000000000000000", sizeof(eq->items[i].SerialNumber)); + //strncpy(eq->items[i].SerialNumber, "0000000000000000", sizeof(eq->items[i].SerialNumber)); + //snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", emu->SerialNumber[i]); + snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", 0); eq->items[i].Unknown18 = 0; if (i < 80) { eq->ItemCost[i] = emu->ItemCost[i]; @@ -3596,10 +3598,11 @@ namespace RoF2 SETUP_DIRECT_ENCODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct); eq->Code = emu->Code; - strncpy(eq->SerialNumber, "0000000000000000", sizeof(eq->SerialNumber)); + //strncpy(eq->SerialNumber, "0000000000000000", sizeof(eq->SerialNumber)); + //snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", 0); eq->TraderID = emu->TraderID; - eq->Stacksize = 0; - eq->Price = 0; + //eq->Stacksize = 0; + //eq->Price = 0; FINISH_ENCODE(); } @@ -3634,6 +3637,18 @@ namespace RoF2 FINISH_ENCODE(); } + ENCODE(OP_TraderShop) + { + ENCODE_LENGTH_EXACT(TraderClick_Struct); + SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct); + + //eq->Code = emu->Unknown004; + OUT(TraderID); + OUT(Approval); + + FINISH_ENCODE(); + } + ENCODE(OP_TributeInfo) { ENCODE_LENGTH_ATLEAST(TributeAbility_Struct); @@ -4215,7 +4230,6 @@ namespace RoF2 return; SETUP_DIRECT_DECODE(NewBazaarInspect_Struct, structs::NewBazaarInspect_Struct); - MEMSET_IN(structs::NewBazaarInspect_Struct); IN(Beginning.Action); memcpy(emu->Name, eq->Name, sizeof(emu->Name)); @@ -4912,7 +4926,6 @@ namespace RoF2 { DECODE_LENGTH_EXACT(structs::ClickTrader_Struct); SETUP_DIRECT_DECODE(ClickTrader_Struct, structs::ClickTrader_Struct); - MEMSET_IN(ClickTrader_Struct); emu->Code = eq->Code; // Live actually has 200 items now, but 80 is the most our internal struct supports @@ -4928,7 +4941,6 @@ namespace RoF2 { DECODE_LENGTH_EXACT(structs::Trader_ShowItems_Struct); SETUP_DIRECT_DECODE(Trader_ShowItems_Struct, structs::Trader_ShowItems_Struct); - MEMSET_IN(Trader_ShowItems_Struct); emu->Code = eq->Code; emu->TraderID = eq->TraderID; @@ -4939,9 +4951,8 @@ namespace RoF2 { DECODE_LENGTH_EXACT(structs::TraderStatus_Struct); SETUP_DIRECT_DECODE(TraderStatus_Struct, structs::TraderStatus_Struct); - MEMSET_IN(TraderStatus_Struct); - emu->Code = eq->Code; + emu->Code = eq->Code; // 11 = Start Trader, 2 = End Trader, 22 = ? - Guessing FINISH_DIRECT_DECODE(); } @@ -4951,7 +4962,6 @@ namespace RoF2 { DECODE_LENGTH_EXACT(structs::TraderBuy_Struct); SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct); - MEMSET_IN(TraderBuy_Struct); IN(Action); IN(Price); @@ -4963,6 +4973,29 @@ namespace RoF2 FINISH_DIRECT_DECODE(); } + DECODE(OP_TraderShop) + { + uint32 psize = __packet->size; + if (psize == sizeof(structs::TraderClick_Struct)) + { + DECODE_LENGTH_EXACT(structs::TraderClick_Struct); + SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct); + //MEMSET_IN(TraderClick_Struct); + + //emu->Unknown004 = eq->Code; + IN(TraderID); + IN(Approval); + + Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Decoded packet size (%d) to size (%d)", sizeof(structs::TraderClick_Struct), sizeof(TraderClick_Struct)); + + FINISH_DIRECT_DECODE(); + } + else + { + Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Decode Size Mismatch (%d), expected (%d)", psize, sizeof(structs::TraderClick_Struct)); + } + } + DECODE(OP_TradeSkillCombine) { DECODE_LENGTH_EXACT(structs::NewCombine_Struct); diff --git a/common/patches/rof2_ops.h b/common/patches/rof2_ops.h index aa5656f2b..0a85855f1 100644 --- a/common/patches/rof2_ops.h +++ b/common/patches/rof2_ops.h @@ -2,10 +2,13 @@ // Begin RoF2 Encodes E(OP_SendMembershipDetails) +E(OP_TraderShop) // incoming packets that require a DECODE translation: // Begin RoF2 Decodes +D(OP_TraderShop) + // End RoF2 Encodes/Decodes // These require Encodes/Decodes for RoF, so they do for RoF2 as well diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 0935517c1..8bab425a4 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -3200,6 +3200,13 @@ struct BecomeTrader_Struct { }; struct Trader_ShowItems_Struct { + /*000*/ uint32 Code; + /*004*/ uint16 TraderID; + /*008*/ uint32 Unknown08; + /*012*/ +}; + +struct Trader_ShowItems_Struct_WIP { /*000*/ uint32 Code; /*004*/ char SerialNumber[17]; /*021*/ uint8 Unknown21; @@ -3262,9 +3269,10 @@ struct TraderDelItem_Struct{ }; struct TraderClick_Struct{ - uint32 traderid; - uint32 unknown4[2]; - uint32 approval; + /*000*/ uint32 Code; + /*004*/ uint32 TraderID; + /*008*/ uint32 Approval; + /*012*/ }; struct FormattedMessage_Struct{ diff --git a/common/patches/ss_define.h b/common/patches/ss_define.h index 3198820b6..cac116c1a 100644 --- a/common/patches/ss_define.h +++ b/common/patches/ss_define.h @@ -124,14 +124,14 @@ //check length of packet before decoding. Call before setup. #define DECODE_LENGTH_EXACT(struct_) \ if(__packet->size != sizeof(struct_)) { \ - __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \ Log.Out(Logs::Detail, Logs::Netcode, "Wrong size on incoming %s (" #struct_ "): Got %d, expected %d", opcodes->EmuToName(__packet->GetOpcode()), __packet->size, sizeof(struct_)); \ + __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \ return; \ } #define DECODE_LENGTH_ATLEAST(struct_) \ if(__packet->size < sizeof(struct_)) { \ - __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \ Log.Out(Logs::Detail, Logs::Netcode, "Wrong size on incoming %s (" #struct_ "): Got %d, expected at least %d", opcodes->EmuToName(__packet->GetOpcode()), __packet->size, sizeof(struct_)); \ + __packet->SetOpcode(OP_Unknown); /* invalidate the packet */ \ return; \ } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index db7f65781..f602bf75d 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -13278,7 +13278,7 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) /* if (GetClientVersion() >= EQClientRoF) - max_items = 200; + max_items = 200; */ //Show Items @@ -13290,20 +13290,25 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) { case BazaarTrader_EndTraderMode: { Trader_EndTrader(); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Trader Session"); break; } case BazaarTrader_EndTransaction: { Client* c = entity_list.GetClientByID(sis->TraderID); if (c) + { c->WithCustomer(0); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Transaction"); + } else - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Null Client Pointer"); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Null Client Pointer"); break; } case BazaarTrader_ShowItems: { Trader_ShowItems(); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Show Trader Items"); break; } default: { @@ -13326,6 +13331,7 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) { GetItems_Struct* gis = GetTraderItems(); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Start Trader Mode"); // Verify there are no NODROP or items with a zero price bool TradeItemsValid = true; @@ -13372,7 +13378,8 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) safe_delete(gis); this->Trader_StartTrader(); - + + // This refreshes the Trader window to display the End Trader button if (GetClientVersion() >= ClientVersion::RoF) { EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderStatus_Struct)); @@ -13382,15 +13389,6 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) safe_delete(outapp); } } - else if (app->size == sizeof(TraderStatus_Struct)) - { - TraderStatus_Struct* tss = (TraderStatus_Struct*)app->pBuffer; - - if (tss->Code == BazaarTrader_ShowItems) - { - Trader_ShowItems(); - } - } else { Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Unknown TraderStruct code of: %i\n", ints->Code); @@ -13398,9 +13396,35 @@ void Client::Handle_OP_Trader(const EQApplicationPacket *app) Log.Out(Logs::General, Logs::Error, "Unknown TraderStruct code of: %i\n", ints->Code); } } + else if (app->size == sizeof(TraderStatus_Struct)) + { + TraderStatus_Struct* tss = (TraderStatus_Struct*)app->pBuffer; + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Trader Status Code: %d", tss->Code); + + switch (tss->Code) + { + case BazaarTrader_EndTraderMode: { + Trader_EndTrader(); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Trader Session"); + break; + } + case BazaarTrader_ShowItems: { + Trader_ShowItems(); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Show Trader Items"); + break; + } + default: { + Log.Out(Logs::Detail, Logs::Trading, "Unhandled action code in OP_Trader ShowItems_Struct"); + break; + } + } + + + } else if (app->size == sizeof(TraderPriceUpdate_Struct)) { + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Trader Price Update"); HandleTraderPriceUpdate(app); } else { @@ -13425,8 +13449,8 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app) TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer; if (Client* Trader = entity_list.GetClientByID(tbs->TraderID)){ - BuyTraderItem(tbs, Trader, app); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Buy Trader Item "); } else { Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Null Client Pointer"); @@ -13502,23 +13526,24 @@ void Client::Handle_OP_TraderShop(const EQApplicationPacket *app) // browse their goods. // - TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer; - if (app->size != sizeof(TraderClick_Struct)) { - - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Returning due to struct size mismatch"); - + Log.Out(Logs::General, Logs::Error, "Wrong size: OP_TraderShop, size=%i, expected %i", app->size, sizeof(TraderClick_Struct)); return; } + TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer; + EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct)); TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer; - Client* Customer = entity_list.GetClientByID(tcs->TraderID); + Client* Trader = entity_list.GetClientByID(tcs->TraderID); - if (Customer) - outtcs->Approval = Customer->WithCustomer(GetID()); + if (Trader) + { + outtcs->Approval = Trader->WithCustomer(GetID()); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Shop Request (%s) to (%s) with Approval: %d", GetCleanName(), Trader->GetCleanName(), outtcs->Approval); + } else { Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)" " returned a nullptr pointer"); @@ -13533,11 +13558,15 @@ void Client::Handle_OP_TraderShop(const EQApplicationPacket *app) if (outtcs->Approval) { - this->BulkSendTraderInventory(Customer->CharacterID()); - Customer->Trader_CustomerBrowsing(this); + this->BulkSendTraderInventory(Trader->CharacterID()); + Trader->Trader_CustomerBrowsing(this); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Inventory Sent"); } else + { Message_StringID(clientMessageYellow, TRADER_BUSY); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Busy"); + } safe_delete(outapp); diff --git a/zone/trading.cpp b/zone/trading.cpp index 4874716ae..292f31713 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -1138,7 +1138,6 @@ void Client::Trader_EndTrader() { QueuePacket(outapp); - safe_delete(outapp); WithCustomer(0); From 75809fc3bbeb4c8413bf20c3d3fe66f6161cff31 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 14 Feb 2015 14:21:50 -0500 Subject: [PATCH 082/114] Fix RoF2 Strategy --- common/patches/rof2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index f1c89ff2f..a8b30d43a 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -104,7 +104,7 @@ namespace RoF2 { //all opcodes default to passthrough. #include "ss_register.h" -#include "rof_ops.h" +#include "rof2_ops.h" } std::string Strategy::Describe() const From f95e211d9bfc42fbec4fb5582647d13f085e42a7 Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 14 Feb 2015 18:32:29 -0800 Subject: [PATCH 083/114] Fixes to OP_ZonePlayerToBind code, esp for RoF clients. --- common/patches/rof.cpp | 49 ++++++++++++-------------------------- common/patches/rof2.cpp | 49 ++++++++++++-------------------------- common/patches/sod.cpp | 49 ++++++++++++-------------------------- common/patches/sof.cpp | 49 ++++++++++++-------------------------- common/patches/ss_define.h | 5 ++++ common/patches/uf.cpp | 49 ++++++++++++-------------------------- zone/zoning.cpp | 6 +---- 7 files changed, 81 insertions(+), 175 deletions(-) diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index d632fdebd..dba4eecfa 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -3739,42 +3739,23 @@ namespace RoF ENCODE(OP_ZonePlayerToBind) { - ENCODE_LENGTH_ATLEAST(ZonePlayerToBind_Struct); + SETUP_VAR_ENCODE(ZonePlayerToBind_Struct); + ALLOC_LEN_ENCODE(sizeof(structs::ZonePlayerToBind_Struct) + strlen(emu->zone_name)); - ZonePlayerToBind_Struct *zps = (ZonePlayerToBind_Struct*)(*p)->pBuffer; + __packet->SetWritePosition(0); + __packet->WriteUInt16(emu->bind_zone_id); + __packet->WriteUInt16(emu->bind_instance_id); + __packet->WriteFloat(emu->x); + __packet->WriteFloat(emu->y); + __packet->WriteFloat(emu->z); + __packet->WriteFloat(emu->heading); + __packet->WriteString(emu->zone_name); + __packet->WriteUInt8(0); // save items + __packet->WriteUInt32(0); // hp + __packet->WriteUInt32(0); // mana + __packet->WriteUInt32(0); // endurance - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - unsigned char *buffer1 = new unsigned char[sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)]; - structs::ZonePlayerToBindHeader_Struct *zph = (structs::ZonePlayerToBindHeader_Struct*)buffer1; - unsigned char *buffer2 = new unsigned char[sizeof(structs::ZonePlayerToBindFooter_Struct)]; - structs::ZonePlayerToBindFooter_Struct *zpf = (structs::ZonePlayerToBindFooter_Struct*)buffer2; - - zph->x = zps->x; - zph->y = zps->y; - zph->z = zps->z; - zph->heading = zps->heading; - zph->bind_zone_id = 0; - zph->bind_instance_id = zps->bind_instance_id; - strncpy(zph->zone_name, zps->zone_name, sizeof(zph->zone_name)); - - zpf->unknown021 = 1; - zpf->unknown022 = 0; - zpf->unknown023 = 0; - zpf->unknown024 = 0; - - ss.write((const char*)buffer1, (sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name))); - ss.write((const char*)buffer2, sizeof(structs::ZonePlayerToBindFooter_Struct)); - - delete[] buffer1; - delete[] buffer2; - delete[](*p)->pBuffer; - - (*p)->pBuffer = new unsigned char[ss.str().size()]; - (*p)->size = ss.str().size(); - - memcpy((*p)->pBuffer, ss.str().c_str(), ss.str().size()); - dest->FastQueuePacket(&(*p)); + FINISH_ENCODE(); } ENCODE(OP_ZoneServerInfo) diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index a8b30d43a..cd9f99a14 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -3821,42 +3821,23 @@ namespace RoF2 ENCODE(OP_ZonePlayerToBind) { - ENCODE_LENGTH_ATLEAST(ZonePlayerToBind_Struct); + SETUP_VAR_ENCODE(ZonePlayerToBind_Struct); + ALLOC_LEN_ENCODE(sizeof(structs::ZonePlayerToBind_Struct) + strlen(emu->zone_name)); - ZonePlayerToBind_Struct *zps = (ZonePlayerToBind_Struct*)(*p)->pBuffer; + __packet->SetWritePosition(0); + __packet->WriteUInt16(emu->bind_zone_id); + __packet->WriteUInt16(emu->bind_instance_id); + __packet->WriteFloat(emu->x); + __packet->WriteFloat(emu->y); + __packet->WriteFloat(emu->z); + __packet->WriteFloat(emu->heading); + __packet->WriteString(emu->zone_name); + __packet->WriteUInt8(0); // save items + __packet->WriteUInt32(0); // hp + __packet->WriteUInt32(0); // mana + __packet->WriteUInt32(0); // endurance - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - unsigned char *buffer1 = new unsigned char[sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)]; - structs::ZonePlayerToBindHeader_Struct *zph = (structs::ZonePlayerToBindHeader_Struct*)buffer1; - unsigned char *buffer2 = new unsigned char[sizeof(structs::ZonePlayerToBindFooter_Struct)]; - structs::ZonePlayerToBindFooter_Struct *zpf = (structs::ZonePlayerToBindFooter_Struct*)buffer2; - - zph->x = zps->x; - zph->y = zps->y; - zph->z = zps->z; - zph->heading = zps->heading; - zph->bind_zone_id = 0; - zph->bind_instance_id = zps->bind_instance_id; - strncpy(zph->zone_name, zps->zone_name, sizeof(zph->zone_name)); - - zpf->unknown021 = 1; - zpf->unknown022 = 0; - zpf->unknown023 = 0; - zpf->unknown024 = 0; - - ss.write((const char*)buffer1, (sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name))); - ss.write((const char*)buffer2, sizeof(structs::ZonePlayerToBindFooter_Struct)); - - delete[] buffer1; - delete[] buffer2; - delete[](*p)->pBuffer; - - (*p)->pBuffer = new unsigned char[ss.str().size()]; - (*p)->size = ss.str().size(); - - memcpy((*p)->pBuffer, ss.str().c_str(), ss.str().size()); - dest->FastQueuePacket(&(*p)); + FINISH_ENCODE(); } ENCODE(OP_ZoneServerInfo) diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index 98f7faccd..69a01cbfb 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -2427,42 +2427,23 @@ namespace SoD ENCODE(OP_ZonePlayerToBind) { - ENCODE_LENGTH_ATLEAST(ZonePlayerToBind_Struct); + SETUP_VAR_ENCODE(ZonePlayerToBind_Struct); + ALLOC_LEN_ENCODE(sizeof(structs::ZonePlayerToBind_Struct) + strlen(emu->zone_name)); - ZonePlayerToBind_Struct *zps = (ZonePlayerToBind_Struct*)(*p)->pBuffer; + __packet->SetWritePosition(0); + __packet->WriteUInt16(emu->bind_zone_id); + __packet->WriteUInt16(emu->bind_instance_id); + __packet->WriteFloat(emu->x); + __packet->WriteFloat(emu->y); + __packet->WriteFloat(emu->z); + __packet->WriteFloat(emu->heading); + __packet->WriteString(emu->zone_name); + __packet->WriteUInt8(0); // save items + __packet->WriteUInt32(0); // hp + __packet->WriteUInt32(0); // mana + __packet->WriteUInt32(0); // endurance - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - unsigned char *buffer1 = new unsigned char[sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)]; - structs::ZonePlayerToBindHeader_Struct *zph = (structs::ZonePlayerToBindHeader_Struct*)buffer1; - unsigned char *buffer2 = new unsigned char[sizeof(structs::ZonePlayerToBindFooter_Struct)]; - structs::ZonePlayerToBindFooter_Struct *zpf = (structs::ZonePlayerToBindFooter_Struct*)buffer2; - - zph->x = zps->x; - zph->y = zps->y; - zph->z = zps->z; - zph->heading = zps->heading; - zph->bind_zone_id = zps->bind_zone_id; - zph->bind_instance_id = zps->bind_instance_id; - strcpy(zph->zone_name, zps->zone_name); - - zpf->unknown021 = 1; - zpf->unknown022 = 0; - zpf->unknown023 = 0; - zpf->unknown024 = 0; - - ss.write((const char*)buffer1, (sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name))); - ss.write((const char*)buffer2, sizeof(structs::ZonePlayerToBindFooter_Struct)); - - delete[] buffer1; - delete[] buffer2; - delete[](*p)->pBuffer; - - (*p)->pBuffer = new unsigned char[ss.str().size()]; - (*p)->size = ss.str().size(); - - memcpy((*p)->pBuffer, ss.str().c_str(), ss.str().size()); - dest->FastQueuePacket(&(*p)); + FINISH_ENCODE(); } ENCODE(OP_ZoneServerInfo) diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index b8a84d993..b951bf401 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1951,42 +1951,23 @@ namespace SoF ENCODE(OP_ZonePlayerToBind) { - ENCODE_LENGTH_ATLEAST(ZonePlayerToBind_Struct); + SETUP_VAR_ENCODE(ZonePlayerToBind_Struct); + ALLOC_LEN_ENCODE(sizeof(structs::ZonePlayerToBind_Struct) + strlen(emu->zone_name)); - ZonePlayerToBind_Struct *zps = (ZonePlayerToBind_Struct*)(*p)->pBuffer; + __packet->SetWritePosition(0); + __packet->WriteUInt16(emu->bind_zone_id); + __packet->WriteUInt16(emu->bind_instance_id); + __packet->WriteFloat(emu->x); + __packet->WriteFloat(emu->y); + __packet->WriteFloat(emu->z); + __packet->WriteFloat(emu->heading); + __packet->WriteString(emu->zone_name); + __packet->WriteUInt8(0); // save items + __packet->WriteUInt32(0); // hp + __packet->WriteUInt32(0); // mana + __packet->WriteUInt32(0); // endurance - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - unsigned char *buffer1 = new unsigned char[sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)]; - structs::ZonePlayerToBindHeader_Struct *zph = (structs::ZonePlayerToBindHeader_Struct*)buffer1; - unsigned char *buffer2 = new unsigned char[sizeof(structs::ZonePlayerToBindFooter_Struct)]; - structs::ZonePlayerToBindFooter_Struct *zpf = (structs::ZonePlayerToBindFooter_Struct*)buffer2; - - zph->x = zps->x; - zph->y = zps->y; - zph->z = zps->z; - zph->heading = zps->heading; - zph->bind_zone_id = zps->bind_zone_id; - zph->bind_instance_id = zps->bind_instance_id; - strcpy(zph->zone_name, zps->zone_name); - - zpf->unknown021 = 1; - zpf->unknown022 = 0; - zpf->unknown023 = 0; - zpf->unknown024 = 0; - - ss.write((const char*)buffer1, (sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name))); - ss.write((const char*)buffer2, sizeof(structs::ZonePlayerToBindFooter_Struct)); - - delete[] buffer1; - delete[] buffer2; - delete[](*p)->pBuffer; - - (*p)->pBuffer = new unsigned char[ss.str().size()]; - (*p)->size = ss.str().size(); - - memcpy((*p)->pBuffer, ss.str().c_str(), ss.str().size()); - dest->FastQueuePacket(&(*p)); + FINISH_ENCODE(); } ENCODE(OP_ZoneServerInfo) diff --git a/common/patches/ss_define.h b/common/patches/ss_define.h index cac116c1a..8502d02dd 100644 --- a/common/patches/ss_define.h +++ b/common/patches/ss_define.h @@ -41,6 +41,11 @@ memset(__packet->pBuffer, 0, len); \ eq_struct *eq = (eq_struct *) __packet->pBuffer; \ +#define ALLOC_LEN_ENCODE(len) \ + __packet->pBuffer = new unsigned char[len]; \ + __packet->size = len; \ + memset(__packet->pBuffer, 0, len); \ + //a shorter assignment for direct mode #undef OUT #define OUT(x) eq->x = emu->x; diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index f772509d0..3bf249246 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -2693,42 +2693,23 @@ namespace UF ENCODE(OP_ZonePlayerToBind) { - ENCODE_LENGTH_ATLEAST(ZonePlayerToBind_Struct); + SETUP_VAR_ENCODE(ZonePlayerToBind_Struct); + ALLOC_LEN_ENCODE(sizeof(structs::ZonePlayerToBind_Struct) + strlen(emu->zone_name)); - ZonePlayerToBind_Struct *zps = (ZonePlayerToBind_Struct*)(*p)->pBuffer; + __packet->SetWritePosition(0); + __packet->WriteUInt16(emu->bind_zone_id); + __packet->WriteUInt16(emu->bind_instance_id); + __packet->WriteFloat(emu->x); + __packet->WriteFloat(emu->y); + __packet->WriteFloat(emu->z); + __packet->WriteFloat(emu->heading); + __packet->WriteString(emu->zone_name); + __packet->WriteUInt8(0); // save items + __packet->WriteUInt32(0); // hp + __packet->WriteUInt32(0); // mana + __packet->WriteUInt32(0); // endurance - std::stringstream ss(std::stringstream::in | std::stringstream::out | std::stringstream::binary); - - unsigned char *buffer1 = new unsigned char[sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name)]; - structs::ZonePlayerToBindHeader_Struct *zph = (structs::ZonePlayerToBindHeader_Struct*)buffer1; - unsigned char *buffer2 = new unsigned char[sizeof(structs::ZonePlayerToBindFooter_Struct)]; - structs::ZonePlayerToBindFooter_Struct *zpf = (structs::ZonePlayerToBindFooter_Struct*)buffer2; - - zph->x = zps->x; - zph->y = zps->y; - zph->z = zps->z; - zph->heading = zps->heading; - zph->bind_zone_id = zps->bind_zone_id; - zph->bind_instance_id = zps->bind_instance_id; - strcpy(zph->zone_name, zps->zone_name); - - zpf->unknown021 = 1; - zpf->unknown022 = 0; - zpf->unknown023 = 0; - zpf->unknown024 = 0; - - ss.write((const char*)buffer1, (sizeof(structs::ZonePlayerToBindHeader_Struct) + strlen(zps->zone_name))); - ss.write((const char*)buffer2, sizeof(structs::ZonePlayerToBindFooter_Struct)); - - delete[] buffer1; - delete[] buffer2; - delete[](*p)->pBuffer; - - (*p)->pBuffer = new unsigned char[ss.str().size()]; - (*p)->size = ss.str().size(); - - memcpy((*p)->pBuffer, ss.str().c_str(), ss.str().size()); - dest->FastQueuePacket(&(*p)); + FINISH_ENCODE(); } ENCODE(OP_ZoneServerInfo) diff --git a/zone/zoning.cpp b/zone/zoning.cpp index e765561ce..cebe2bfea 100644 --- a/zone/zoning.cpp +++ b/zone/zoning.cpp @@ -587,11 +587,7 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z // If we are SoF and later and are respawning from hover, we want the real zone ID, else zero to use the old hack. // - if((GetClientVersionBit() & BIT_SoFAndLater) && (!RuleB(Character, RespawnFromHover) || !IsHoveringForRespawn())) - gmg->bind_zone_id = 0; - else - gmg->bind_zone_id = zoneID; - + gmg->bind_zone_id = zoneID; gmg->x = x; gmg->y = y; gmg->z = z; From 9a78bac0d0122f5908918e5bef638059c017f570 Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 14 Feb 2015 18:46:03 -0800 Subject: [PATCH 084/114] Changed save items back to true to be like old encode, no point tempting fate on that not breaking anything --- common/patches/rof.cpp | 2 +- common/patches/rof2.cpp | 2 +- common/patches/sod.cpp | 2 +- common/patches/sof.cpp | 2 +- common/patches/uf.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index dba4eecfa..cb95bfdb1 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -3750,7 +3750,7 @@ namespace RoF __packet->WriteFloat(emu->z); __packet->WriteFloat(emu->heading); __packet->WriteString(emu->zone_name); - __packet->WriteUInt8(0); // save items + __packet->WriteUInt8(1); // save items __packet->WriteUInt32(0); // hp __packet->WriteUInt32(0); // mana __packet->WriteUInt32(0); // endurance diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index cd9f99a14..6ba1adbc7 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -3832,7 +3832,7 @@ namespace RoF2 __packet->WriteFloat(emu->z); __packet->WriteFloat(emu->heading); __packet->WriteString(emu->zone_name); - __packet->WriteUInt8(0); // save items + __packet->WriteUInt8(1); // save items __packet->WriteUInt32(0); // hp __packet->WriteUInt32(0); // mana __packet->WriteUInt32(0); // endurance diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index 69a01cbfb..488f51e87 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -2438,7 +2438,7 @@ namespace SoD __packet->WriteFloat(emu->z); __packet->WriteFloat(emu->heading); __packet->WriteString(emu->zone_name); - __packet->WriteUInt8(0); // save items + __packet->WriteUInt8(1); // save items __packet->WriteUInt32(0); // hp __packet->WriteUInt32(0); // mana __packet->WriteUInt32(0); // endurance diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index b951bf401..ab956a28d 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1962,7 +1962,7 @@ namespace SoF __packet->WriteFloat(emu->z); __packet->WriteFloat(emu->heading); __packet->WriteString(emu->zone_name); - __packet->WriteUInt8(0); // save items + __packet->WriteUInt8(1); // save items __packet->WriteUInt32(0); // hp __packet->WriteUInt32(0); // mana __packet->WriteUInt32(0); // endurance diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 3bf249246..11fdb3c7b 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -2704,7 +2704,7 @@ namespace UF __packet->WriteFloat(emu->z); __packet->WriteFloat(emu->heading); __packet->WriteString(emu->zone_name); - __packet->WriteUInt8(0); // save items + __packet->WriteUInt8(1); // save items __packet->WriteUInt32(0); // hp __packet->WriteUInt32(0); // mana __packet->WriteUInt32(0); // endurance From db3feafe4874614416f1481ab28b22543e250b04 Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 14 Feb 2015 20:05:54 -0800 Subject: [PATCH 085/114] Fix for returning to bound zone you're already in --- zone/zoning.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/zone/zoning.cpp b/zone/zoning.cpp index cebe2bfea..5b60448ec 100644 --- a/zone/zoning.cpp +++ b/zone/zoning.cpp @@ -587,7 +587,15 @@ void Client::ZonePC(uint32 zoneID, uint32 instance_id, float x, float y, float z // If we are SoF and later and are respawning from hover, we want the real zone ID, else zero to use the old hack. // - gmg->bind_zone_id = zoneID; + if(zone->GetZoneID() == zoneID) { + if((GetClientVersionBit() & BIT_SoFAndLater) && (!RuleB(Character, RespawnFromHover) || !IsHoveringForRespawn())) + gmg->bind_zone_id = 0; + else + gmg->bind_zone_id = zoneID; + } else { + gmg->bind_zone_id = zoneID; + } + gmg->x = x; gmg->y = y; gmg->z = z; From 28be3b87b7798479d59cc66bb7ca6328e265aba0 Mon Sep 17 00:00:00 2001 From: Trevius Date: Mon, 16 Feb 2015 11:56:23 -0600 Subject: [PATCH 086/114] (RoF2) Bazaar Trading (Buying/Selling) is now fully functional. Bazaar (/bazaar) search is not yet functional. --- changelog.txt | 3 + common/patches/rof2.cpp | 85 ++++++++++-- common/patches/rof2_ops.h | 1 + common/patches/rof2_structs.h | 37 ++++-- utils/patches/patch_RoF2.conf | 4 +- zone/client.cpp | 1 + zone/client.h | 6 +- zone/client_packet.cpp | 156 ++++++++++++++-------- zone/trading.cpp | 239 ++++++++++++++++++++++++---------- 9 files changed, 375 insertions(+), 157 deletions(-) diff --git a/changelog.txt b/changelog.txt index 99da395d8..6fcdf69a8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/16/2015 == +Trevius: (RoF2) Bazaar Trading (Buying/Selling) is now fully functional. Bazaar (/bazaar) search is not yet functional. + == 02/14/2015 == Trevius: (RoF2) Bazaar is now partially functional. RoF2 clients can start/end trader mode and other clients can purchase from them. No other functionality yet. diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 6ba1adbc7..28e845a0a 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -3578,14 +3578,13 @@ namespace RoF2 // Live actually has 200 items now, but 80 is the most our internal struct supports for (uint32 i = 0; i < 200; i++) { - //strncpy(eq->items[i].SerialNumber, "0000000000000000", sizeof(eq->items[i].SerialNumber)); - //snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", emu->SerialNumber[i]); - snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", 0); eq->items[i].Unknown18 = 0; if (i < 80) { + snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", emu->SerialNumber[i]); eq->ItemCost[i] = emu->ItemCost[i]; } else { + snprintf(eq->items[i].SerialNumber, sizeof(eq->items[i].SerialNumber), "%016d", 0); eq->ItemCost[i] = 0; } } @@ -3637,18 +3636,61 @@ namespace RoF2 FINISH_ENCODE(); } - ENCODE(OP_TraderShop) + ENCODE(OP_TraderDelItem) { - ENCODE_LENGTH_EXACT(TraderClick_Struct); - SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct); + ENCODE_LENGTH_EXACT(TraderDelItem_Struct); + SETUP_DIRECT_ENCODE(TraderDelItem_Struct, structs::TraderDelItem_Struct); - //eq->Code = emu->Unknown004; OUT(TraderID); - OUT(Approval); + snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", emu->ItemID); + Log.Out(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderDelItem): TraderID %d, SerialNumber: %d", emu->TraderID, emu->ItemID); FINISH_ENCODE(); } + ENCODE(OP_TraderShop) + { + uint32 psize = (*p)->size; + if (psize == sizeof(TraderClick_Struct)) + { + ENCODE_LENGTH_EXACT(TraderClick_Struct); + SETUP_DIRECT_ENCODE(TraderClick_Struct, structs::TraderClick_Struct); + + eq->Code = 28; // Seen on Live + OUT(TraderID); + OUT(Approval); + + FINISH_ENCODE(); + } + else if (psize == sizeof(TraderBuy_Struct)) + { + ENCODE_LENGTH_EXACT(TraderBuy_Struct); + SETUP_DIRECT_ENCODE(TraderBuy_Struct, structs::TraderBuy_Struct); + + OUT(Action); + OUT(TraderID); + + //memcpy(eq->BuyerName, emu->BuyerName, sizeof(eq->BuyerName)); + //memcpy(eq->SellerName, emu->SellerName, sizeof(eq->SellerName)); + + memcpy(eq->ItemName, emu->ItemName, sizeof(eq->ItemName)); + OUT(ItemID); + OUT(AlreadySold); + OUT(Price); + OUT(Quantity); + snprintf(eq->SerialNumber, sizeof(eq->SerialNumber), "%016d", emu->ItemID); + + Log.Out(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderShop): Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s", + eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, emu->ItemName); + + FINISH_ENCODE(); + } + else + { + Log.Out(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderShop): Encode Size Unknown (%d)", psize); + } + } + ENCODE(OP_TributeInfo) { ENCODE_LENGTH_ATLEAST(TributeAbility_Struct); @@ -4961,19 +5003,38 @@ namespace RoF2 { DECODE_LENGTH_EXACT(structs::TraderClick_Struct); SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct); - //MEMSET_IN(TraderClick_Struct); - //emu->Unknown004 = eq->Code; IN(TraderID); IN(Approval); - Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Decoded packet size (%d) to size (%d)", sizeof(structs::TraderClick_Struct), sizeof(TraderClick_Struct)); + FINISH_DIRECT_DECODE(); + } + else if (psize == sizeof(structs::TraderBuy_Struct)) + { + + DECODE_LENGTH_EXACT(structs::TraderBuy_Struct); + SETUP_DIRECT_DECODE(TraderBuy_Struct, structs::TraderBuy_Struct); + + IN(Action); + IN(Price); + IN(TraderID); + memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName)); + IN(ItemID); + IN(Quantity); + Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): (Unknowns) Unknown004 %d, Unknown008 %d, Unknown012 %d, Unknown076 %d, Unknown276 %d", + eq->Unknown004, eq->Unknown008, eq->Unknown012, eq->Unknown076, eq->Unknown276); + Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s", + eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, eq->ItemName); FINISH_DIRECT_DECODE(); } + else if (psize == 4) + { + Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Forwarding packet as-is with size 4"); + } else { - Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Decode Size Mismatch (%d), expected (%d)", psize, sizeof(structs::TraderClick_Struct)); + Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Decode Size Unknown (%d)", psize); } } diff --git a/common/patches/rof2_ops.h b/common/patches/rof2_ops.h index 0a85855f1..3edcac459 100644 --- a/common/patches/rof2_ops.h +++ b/common/patches/rof2_ops.h @@ -3,6 +3,7 @@ E(OP_SendMembershipDetails) E(OP_TraderShop) +E(OP_TraderDelItem) // incoming packets that require a DECODE translation: // Begin RoF2 Decodes diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 8bab425a4..e4e11ae8b 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -3224,6 +3224,26 @@ struct TraderStatus_Struct { }; struct TraderBuy_Struct { + /*000*/ uint32 Action; + /*004*/ uint32 Unknown004; + /*008*/ uint32 Unknown008; + /*012*/ uint32 Unknown012; + /*016*/ uint32 TraderID; + /*020*/ char BuyerName[64]; + /*084*/ char SellerName[64]; + /*148*/ char Unknown148[32]; + /*180*/ char ItemName[64]; + /*244*/ char SerialNumber[16]; + /*260*/ uint32 Unknown076; + /*264*/ uint32 ItemID; + /*268*/ uint32 Price; + /*272*/ uint32 AlreadySold; + /*276*/ uint32 Unknown276; + /*280*/ uint32 Quantity; + /*284*/ +}; + +struct TraderBuy_Struct_OLD { /*000*/ uint32 Action; /*004*/ uint32 Unknown004; /*008*/ uint32 Price; @@ -3253,19 +3273,12 @@ struct MoneyUpdate_Struct{ int32 copper; }; -//struct MoneyUpdate_Struct -//{ -//*0000*/ uint32 spawn_id; // ***Placeholder -//*0004*/ uint32 cointype; // Coin Type -//*0008*/ uint32 amount; // Amount -//*0012*/ -//}; - - struct TraderDelItem_Struct{ - uint32 slotid; - uint32 quantity; - uint32 unknown; + /*000*/ uint32 Unknown000; + /*004*/ uint32 TraderID; + /*008*/ char SerialNumber[16]; + /*024*/ uint32 Unknown012; + /*028*/ }; struct TraderClick_Struct{ diff --git a/utils/patches/patch_RoF2.conf b/utils/patches/patch_RoF2.conf index 189edc8b3..0cc0c69d0 100644 --- a/utils/patches/patch_RoF2.conf +++ b/utils/patches/patch_RoF2.conf @@ -402,12 +402,12 @@ OP_LootComplete=0x55c4 # bazaar trader stuff: OP_BazaarSearch=0x39d6 -OP_TraderDelItem=0x0000 +OP_TraderDelItem=0x5829 OP_BecomeTrader=0x61b3 OP_TraderShop=0x31df OP_Trader=0x4ef5 -OP_TraderBuy=0x0000 OP_Barter=0x243a +OP_TraderBuy=0x0000 OP_ShopItem=0x0000 OP_BazaarInspect=0x0000 OP_Bazaar=0x0000 diff --git a/zone/client.cpp b/zone/client.cpp index 9af91988c..63a9b5073 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -165,6 +165,7 @@ Client::Client(EQStreamInterface* ieqs) Trader=false; Buyer = false; CustomerID = 0; + TraderID = 0; TrackingID = 0; WID = 0; account_id = 0; diff --git a/zone/client.h b/zone/client.h index 53d3c0428..f2325ccca 100644 --- a/zone/client.h +++ b/zone/client.h @@ -266,10 +266,11 @@ public: void SendBazaarResults(uint32 trader_id,uint32 class_,uint32 race,uint32 stat,uint32 slot,uint32 type,char name[64],uint32 minprice,uint32 maxprice); void SendTraderItem(uint32 item_id,uint16 quantity); uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity); + uint32 FindTraderItemSerialNumber(int32 ItemID); ItemInst* FindTraderItemBySerialNumber(int32 SerialNumber); void FindAndNukeTraderItem(int32 item_id,uint16 quantity,Client* customer,uint16 traderslot); - void NukeTraderItem(uint16 slot,int16 charges,uint16 quantity,Client* customer,uint16 traderslot, int uniqueid); - void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges); + void NukeTraderItem(uint16 slot, int16 charges, uint16 quantity, Client* customer, uint16 traderslot, int32 uniqueid, int32 itemid = 0); + void ReturnTraderReq(const EQApplicationPacket* app,int16 traderitemcharges, uint32 itemid = 0); void TradeRequestFailed(const EQApplicationPacket* app); void BuyTraderItem(TraderBuy_Struct* tbs,Client* trader,const EQApplicationPacket* app); void TraderUpdate(uint16 slot_id,uint32 trader_id); @@ -1388,6 +1389,7 @@ private: uint16 BoatID; uint16 TrackingID; uint16 CustomerID; + uint16 TraderID; uint32 account_creation; uint8 firstlogon; uint32 mercid; // current merc diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index f602bf75d..2d60b444e 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11952,12 +11952,6 @@ void Client::Handle_OP_ShopEnd(const EQApplicationPacket *app) { EQApplicationPacket empty(OP_ShopEndConfirm); QueuePacket(&empty); - //EQApplicationPacket* outapp = new EQApplicationPacket(OP_ShopEndConfirm, 2); - //outapp->pBuffer[0] = 0x0a; - //outapp->pBuffer[1] = 0x66; - //QueuePacket(outapp); - //safe_delete(outapp); - //Save(); return; } @@ -13443,23 +13437,22 @@ void Client::Handle_OP_TraderBuy(const EQApplicationPacket *app) // // Client has elected to buy an item from a Trader // + if (app->size != sizeof(TraderBuy_Struct)) { + Log.Out(Logs::General, Logs::Error, "Wrong size: OP_TraderBuy, size=%i, expected %i", app->size, sizeof(TraderBuy_Struct)); + return; + } - if (app->size == sizeof(TraderBuy_Struct)){ + TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer; - TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer; - - if (Client* Trader = entity_list.GetClientByID(tbs->TraderID)){ - BuyTraderItem(tbs, Trader, app); - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Buy Trader Item "); - } - else { - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Null Client Pointer"); - } + if (Client* Trader = entity_list.GetClientByID(tbs->TraderID)){ + BuyTraderItem(tbs, Trader, app); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Buy Trader Item "); } else { - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Struct size mismatch"); - + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderBuy: Null Client Pointer"); } + + return; } @@ -13521,56 +13514,105 @@ void Client::Handle_OP_TradeRequestAck(const EQApplicationPacket *app) void Client::Handle_OP_TraderShop(const EQApplicationPacket *app) { // Bazaar Trader: - // - // This is when a potential purchaser right clicks on this client who is in Trader mode to - // browse their goods. - // - if (app->size != sizeof(TraderClick_Struct)) { - Log.Out(Logs::General, Logs::Error, "Wrong size: OP_TraderShop, size=%i, expected %i", app->size, sizeof(TraderClick_Struct)); - return; - } - - TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer; - - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct)); - - TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer; - - Client* Trader = entity_list.GetClientByID(tcs->TraderID); - - if (Trader) + if (app->size == sizeof(TraderClick_Struct)) { - outtcs->Approval = Trader->WithCustomer(GetID()); - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Shop Request (%s) to (%s) with Approval: %d", GetCleanName(), Trader->GetCleanName(), outtcs->Approval); - } - else { - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)" - " returned a nullptr pointer"); + // This is when a potential purchaser right clicks on this client who is in Trader mode to + // browse their goods. + TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer; + + EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct)); + + TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer; + + Client* Trader = entity_list.GetClientByID(tcs->TraderID); + + if (Trader) + { + outtcs->Approval = Trader->WithCustomer(GetID()); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Shop Request (%s) to (%s) with Approval: %d", GetCleanName(), Trader->GetCleanName(), outtcs->Approval); + } + else { + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)" + " returned a nullptr pointer"); + return; + } + + outtcs->TraderID = tcs->TraderID; + + outtcs->Unknown008 = 0x3f800000; + + QueuePacket(outapp); + + + if (outtcs->Approval) { + this->BulkSendTraderInventory(Trader->CharacterID()); + Trader->Trader_CustomerBrowsing(this); + TraderID = tcs->TraderID; + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Inventory Sent"); + } + else + { + Message_StringID(clientMessageYellow, TRADER_BUSY); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Busy"); + } + + safe_delete(outapp); + return; } + else if (app->size == sizeof(TraderBuy_Struct)) + { + // RoF+ + // Customer has purchased an item from the Trader - outtcs->TraderID = tcs->TraderID; + TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer; - outtcs->Unknown008 = 0x3f800000; + if (Client* Trader = entity_list.GetClientByID(tbs->TraderID)) + { + BuyTraderItem(tbs, Trader, app); + Log.Out(Logs::Detail, Logs::Trading, "Handle_OP_TraderShop: Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s", + tbs->Action, tbs->Price, tbs->TraderID, tbs->ItemID, tbs->Quantity, tbs->ItemName); + } + else + { + Log.Out(Logs::Detail, Logs::Trading, "OP_TraderShop: Null Client Pointer"); + } + } + else if (app->size == 4) + { + // RoF+ + // Customer has closed the trade window + uint32 Command = *((uint32 *)app->pBuffer); - QueuePacket(outapp); - - - if (outtcs->Approval) { - this->BulkSendTraderInventory(Trader->CharacterID()); - Trader->Trader_CustomerBrowsing(this); - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Inventory Sent"); + if (Command == 4) + { + Client* c = entity_list.GetClientByID(TraderID); + TraderID = 0; + if (c) + { + c->WithCustomer(0); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: End Transaction - Code %d", Command); + } + else + { + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Null Client Pointer for Trader - Code %d", Command); + } + EQApplicationPacket empty(OP_ShopEndConfirm); + QueuePacket(&empty); + } + else + { + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_Trader: Unhandled Code %d", Command); + } } else { - Message_StringID(clientMessageYellow, TRADER_BUSY); - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Busy"); + Log.Out(Logs::Detail, Logs::Trading, "Unknown size for OP_TraderShop: %i\n", app->size); + Log.Out(Logs::General, Logs::Error, "Unknown size for OP_TraderShop: %i\n", app->size); + DumpPacket(app); + return; } - - safe_delete(outapp); - - return; } void Client::Handle_OP_TradeSkillCombine(const EQApplicationPacket *app) diff --git a/zone/trading.cpp b/zone/trading.cpp index 292f31713..047aa3a6a 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -1098,7 +1098,15 @@ void Client::Trader_EndTrader() { for(int i = 0; i < 80; i++) { if(gis->Items[i] != 0) { - tdis->ItemID = gis->SerialNumber[i]; + if (Customer->GetClientVersion() >= ClientVersion::RoF) + { + // RoF+ use Item IDs for now + tdis->ItemID = gis->Items[i]; + } + else + { + tdis->ItemID = gis->SerialNumber[i]; + } Customer->QueuePacket(outapp); } @@ -1220,6 +1228,29 @@ void Client::BulkSendTraderInventory(uint32 char_id) { safe_delete(TraderItems); } +uint32 Client::FindTraderItemSerialNumber(int32 ItemID) { + + ItemInst* item = nullptr; + uint16 SlotID = 0; + for (int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; i++){ + item = this->GetInv().GetItem(i); + if (item && item->GetItem()->ID == 17899){ //Traders Satchel + for (int x = SUB_BEGIN; x < EmuConstants::ITEM_CONTAINER_SIZE; x++) { + // we already have the parent bag and a contents iterator..why not just iterate the bag!?? + SlotID = Inventory::CalcSlotId(i, x); + item = this->GetInv().GetItem(SlotID); + if (item) { + if (item->GetID() == ItemID) + return item->GetSerialNumber(); + } + } + } + } + Log.Out(Logs::Detail, Logs::Trading, "Client::FindTraderItemSerialNumber Couldn't find item! Item ID %i", ItemID); + + return 0; +} + ItemInst* Client::FindTraderItemBySerialNumber(int32 SerialNumber){ ItemInst* item = nullptr; @@ -1287,9 +1318,9 @@ uint16 Client::FindTraderItem(int32 SerialNumber, uint16 Quantity){ item = this->GetInv().GetItem(SlotID); - if(item && item->GetSerialNumber() == SerialNumber && - (item->GetCharges() >= Quantity || (item->GetCharges() <= 0 && Quantity == 1))){ - + if (item && item->GetSerialNumber() == SerialNumber && + (item->GetCharges() >= Quantity || (item->GetCharges() <= 0 && Quantity == 1))) + { return SlotID; } } @@ -1301,21 +1332,34 @@ uint16 Client::FindTraderItem(int32 SerialNumber, uint16 Quantity){ return 0; } -void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Customer,uint16 TraderSlot, int SerialNumber) { +void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Customer,uint16 TraderSlot, int32 SerialNumber, int32 itemid) { + + if(!Customer) + return; - if(!Customer) return; Log.Out(Logs::Detail, Logs::Trading, "NukeTraderItem(Slot %i, Charges %i, Quantity %i", Slot, Charges, Quantity); - if(Quantity < Charges) { + + if(Quantity < Charges) + { Customer->SendSingleTraderItem(this->CharacterID(), SerialNumber); m_inv.DeleteItem(Slot, Quantity); } - else { + else + { EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderDelItem,sizeof(TraderDelItem_Struct)); TraderDelItem_Struct* tdis = (TraderDelItem_Struct*)outapp->pBuffer; tdis->Unknown000 = 0; tdis->TraderID = Customer->GetID(); - tdis->ItemID = SerialNumber; + if (Customer->GetClientVersion() >= ClientVersion::RoF) + { + // RoF+ use Item IDs for now + tdis->ItemID = itemid; + } + else + { + tdis->ItemID = SerialNumber; + } tdis->Unknown012 = 0; @@ -1323,7 +1367,6 @@ void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Cu safe_delete(outapp); m_inv.DeleteItem(Slot); - } // This updates the trader. Removes it from his trading bags. // @@ -1374,49 +1417,61 @@ void Client::FindAndNukeTraderItem(int32 SerialNumber, uint16 Quantity, Client* int16 Charges=0; uint16 SlotID = FindTraderItem(SerialNumber, Quantity); - if(SlotID > 0){ + + if(SlotID > 0) { item = this->GetInv().GetItem(SlotID); - if(item) { - Charges = this->GetInv().GetItem(SlotID)->GetCharges(); - - Stackable = item->IsStackable(); - - if(!Stackable) - Quantity = (Charges > 0) ? Charges : 1; - - Log.Out(Logs::Detail, Logs::Trading, "FindAndNuke %s, Charges %i, Quantity %i", item->GetItem()->Name, Charges, Quantity); + if (!item) + { + Log.Out(Logs::Detail, Logs::Trading, "Could not find Item: %i on Trader: %s", SerialNumber, Quantity, this->GetName()); + return; } - if(item && (Charges <= Quantity || (Charges <= 0 && Quantity==1) || !Stackable)){ + + Charges = this->GetInv().GetItem(SlotID)->GetCharges(); + + Stackable = item->IsStackable(); + + if (!Stackable) + Quantity = (Charges > 0) ? Charges : 1; + + Log.Out(Logs::Detail, Logs::Trading, "FindAndNuke %s, Charges %i, Quantity %i", item->GetItem()->Name, Charges, Quantity); + + if (Charges <= Quantity || (Charges <= 0 && Quantity==1) || !Stackable) + { this->DeleteItemInInventory(SlotID, Quantity); - TraderCharges_Struct* GetSlot = database.LoadTraderItemWithCharges(this->CharacterID()); + TraderCharges_Struct* TraderItems = database.LoadTraderItemWithCharges(this->CharacterID()); uint8 Count = 0; bool TestSlot = true; - for(int y = 0;y < 80;y++){ + for(int i = 0;i < 80;i++){ - if(TestSlot && GetSlot->SerialNumber[y] == SerialNumber){ - - database.DeleteTraderItem(this->CharacterID(),y); - NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, GetSlot->SerialNumber[y]); + if(TestSlot && TraderItems->SerialNumber[i] == SerialNumber) + { + database.DeleteTraderItem(this->CharacterID(),i); + NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, TraderItems->SerialNumber[i], TraderItems->ItemID[i]); TestSlot=false; } - else if(GetSlot->ItemID[y] > 0) + else if (TraderItems->ItemID[i] > 0) + { Count++; + } } - if(Count == 0) + if (Count == 0) + { Trader_EndTrader(); + } return; } - else if(item) { + else + { database.UpdateTraderItemCharges(this->CharacterID(), item->GetSerialNumber(), Charges-Quantity); - NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, item->GetSerialNumber()); + NukeTraderItem(SlotID, Charges, Quantity, Customer, TraderSlot, item->GetSerialNumber(), item->GetID()); return; @@ -1426,22 +1481,38 @@ void Client::FindAndNukeTraderItem(int32 SerialNumber, uint16 Quantity, Client* Quantity,this->GetName()); } -void Client::ReturnTraderReq(const EQApplicationPacket* app, int16 TraderItemCharges){ +void Client::ReturnTraderReq(const EQApplicationPacket* app, int16 TraderItemCharges, uint32 itemid){ TraderBuy_Struct* tbs = (TraderBuy_Struct*)app->pBuffer; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderBuy, sizeof(TraderBuy_Struct)); + EQApplicationPacket* outapp = nullptr; + + if (GetClientVersion() >= ClientVersion::RoF) + { + outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderBuy_Struct)); + } + else + { + outapp = new EQApplicationPacket(OP_TraderBuy, sizeof(TraderBuy_Struct)); + } TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer; - memcpy(outtbs, tbs, app->size); - outtbs->Price = (tbs->Price * static_cast(TraderItemCharges)); + if (GetClientVersion() >= ClientVersion::RoF) + { + // Convert Serial Number back to Item ID for RoF+ + outtbs->ItemID = itemid; + } + else + { + // RoF+ requires individual price, but older clients require total price + outtbs->Price = (tbs->Price * static_cast(TraderItemCharges)); + } outtbs->Quantity = TraderItemCharges; - + // This should probably be trader ID, not customer ID as it is below. outtbs->TraderID = this->GetID(); - outtbs->AlreadySold = 0; QueuePacket(outapp); @@ -1478,7 +1549,7 @@ static void BazaarAuditTrail(const char *seller, const char *buyer, const char * database.QueryDatabase(query); } -void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicationPacket* app){ +void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplicationPacket* app){ if(!Trader) return; @@ -1487,13 +1558,34 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat return; } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader,sizeof(TraderBuy_Struct)); + EQApplicationPacket* outapp = nullptr; + + if (Trader->GetClientVersion() >= ClientVersion::RoF) + { + //outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderBuy_Struct)); + } + else + { + //outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderBuy_Struct)); + } + + outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderBuy_Struct)); TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer; outtbs->ItemID = tbs->ItemID; - const ItemInst* BuyItem = Trader->FindTraderItemBySerialNumber(tbs->ItemID); + const ItemInst* BuyItem = nullptr; + uint32 ItemID = 0; + + if (GetClientVersion() >= ClientVersion::RoF) + { + // Convert Item ID to Serial Number for RoF+ + ItemID = tbs->ItemID; + tbs->ItemID = Trader->FindTraderItemSerialNumber(tbs->ItemID); + } + + BuyItem = Trader->FindTraderItemBySerialNumber(tbs->ItemID); if(!BuyItem) { Log.Out(Logs::Detail, Logs::Trading, "Unable to find item on trader."); @@ -1543,12 +1635,10 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat return; } - ReturnTraderReq(app, outtbs->Quantity); + ReturnTraderReq(app, outtbs->Quantity, ItemID); outtbs->TraderID = this->GetID(); - outtbs->Action = BazaarBuyItem; - strn0cpy(outtbs->ItemName, BuyItem->GetItem()->Name, 64); int TraderSlot = 0; @@ -1558,54 +1648,50 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat else SendTraderItem(BuyItem->GetItem()->ID, BuyItem->GetCharges()); - - EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoneyUpdate,sizeof(MoneyUpdate_Struct)); - - MoneyUpdate_Struct* mus= (MoneyUpdate_Struct*)outapp2->pBuffer; - // This cannot overflow assuming MAX_TRANSACTION_VALUE, checked above, is the default of 2000000000 uint32 TotalCost = tbs->Price * outtbs->Quantity; - outtbs->Price = TotalCost; + if (Trader->GetClientVersion() >= ClientVersion::RoF) + { + // RoF+ uses individual item price where older clients use total price + outtbs->Price = tbs->Price; + } + else + { + outtbs->Price = TotalCost; + } this->TakeMoneyFromPP(TotalCost); - mus->platinum = TotalCost / 1000; + Log.Out(Logs::Detail, Logs::Trading, "Customer Paid: %d in Copper", TotalCost); - TotalCost -= (mus->platinum * 1000); + uint32 platinum = TotalCost / 1000; + TotalCost -= (platinum * 1000); + uint32 gold = TotalCost / 100; + TotalCost -= (gold * 100); + uint32 silver = TotalCost / 10; + TotalCost -= (silver * 10); + uint32 copper = TotalCost; - mus->gold = TotalCost / 100; + Trader->AddMoneyToPP(copper, silver, gold, platinum, true); - TotalCost -= (mus->gold * 100); - - mus->silver = TotalCost / 10; - - TotalCost -= (mus->silver * 10); - - mus->copper = TotalCost; - - Trader->AddMoneyToPP(mus->copper,mus->silver,mus->gold,mus->platinum,false); - - mus->platinum = Trader->GetPlatinum(); - mus->gold = Trader->GetGold(); - mus->silver = Trader->GetSilver(); - mus->copper = Trader->GetCopper(); + Log.Out(Logs::Detail, Logs::Trading, "Trader Received: %d Platinum, %d Gold, %d Silver, %d Copper", platinum, gold, silver, copper); TraderSlot = Trader->FindTraderItem(tbs->ItemID, outtbs->Quantity); - Trader->QueuePacket(outapp2); - - if(RuleB(Bazaar, AuditTrail)) BazaarAuditTrail(Trader->GetName(), GetName(), BuyItem->GetItem()->Name, outtbs->Quantity, outtbs->Price, 0); Trader->FindAndNukeTraderItem(tbs->ItemID, outtbs->Quantity, this, 0); + if (ItemID > 0 && Trader->GetClientVersion() >= ClientVersion::RoF) + { + // Convert Serial Number back to ItemID for RoF+ + outtbs->ItemID = ItemID; + } + Trader->QueuePacket(outapp); - - safe_delete(outapp); - safe_delete(outapp2); } void Client::SendBazaarWelcome() @@ -1996,6 +2082,15 @@ static void UpdateTraderCustomerPriceChanged(uint32 CustomerID, TraderCharges_St for(int i = 0; i < 80; i++) { if(gis->ItemID[i] == ItemID) { + if (Customer->GetClientVersion() >= ClientVersion::RoF) + { + // RoF+ use Item IDs for now + tdis->ItemID = gis->ItemID[i]; + } + else + { + tdis->ItemID = gis->SerialNumber[i]; + } tdis->ItemID = gis->SerialNumber[i]; Log.Out(Logs::Detail, Logs::Trading, "Telling customer to remove item %i with %i charges and S/N %i", ItemID, Charges, gis->SerialNumber[i]); From b48a712887b71e26e61e970c0fe1fa7bfda1c28b Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Mon, 16 Feb 2015 15:40:44 -0500 Subject: [PATCH 087/114] Send bard effect stuff for RoF2 Server side we still use the old system Servers will need to update their items, PEQ's DB appears fine RoF2 wasn't show anything, so we have to send it for them --- changelog.txt | 1 + common/patches/rof2.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 6fcdf69a8..6d50f235e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- == 02/16/2015 == Trevius: (RoF2) Bazaar Trading (Buying/Selling) is now fully functional. Bazaar (/bazaar) search is not yet functional. +demonstar55: (RoF2) Send the bard focus effects, note custom servers will need to fix their items, server side we still use the old system, but RoF2 wasn't showing anything with not sending focus, so send them == 02/14/2015 == Trevius: (RoF2) Bazaar is now partially functional. RoF2 clients can start/end trader mode and other clients can purchase from them. No other functionality yet. diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 28e845a0a..5cab22a60 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -5554,10 +5554,10 @@ namespace RoF2 RoF2::structs::WornEffectStruct ibes; memset(&ibes, 0, sizeof(RoF2::structs::WornEffectStruct)); - ibes.effect = 0xffffffff; - ibes.level2 = 0; - ibes.type = 0; - ibes.level = 0; + ibes.effect = item->Bard.Effect; + ibes.level2 = item->Bard.Level2; + ibes.type = item->Bard.Type; + ibes.level = item->Bard.Level; //ibes.unknown6 = 0xffffffff; ss.write((const char*)&ibes, sizeof(RoF2::structs::WornEffectStruct)); From f1a25da06522dc96348e70c25a595615e8b7b07a Mon Sep 17 00:00:00 2001 From: Uleat Date: Sat, 14 Feb 2015 16:36:30 -0500 Subject: [PATCH 088/114] Pre-purposed clean-up --- common/clientversions.h | 45 +++++++--- common/database_conversions.cpp | 34 ++++--- common/eq_dictionary.cpp | 144 ++++++++++++++++++------------ common/eq_dictionary.h | 16 ++-- common/eq_packet_structs.h | 95 ++++++++++++-------- common/patches/rof.cpp | 18 ++-- common/patches/rof2.cpp | 18 ++-- common/patches/rof2_structs.h | 119 +++++++++++++++--------- common/patches/rof_structs.h | 119 +++++++++++++++--------- common/patches/sod.cpp | 14 +-- common/patches/sod_structs.h | 89 +++++++++++------- common/patches/sof.cpp | 14 +-- common/patches/sof_structs.h | 89 +++++++++++------- common/patches/titanium.cpp | 14 +-- common/patches/titanium_structs.h | 89 +++++++++++------- common/patches/uf.cpp | 14 +-- common/patches/uf_structs.h | 89 +++++++++++------- zone/client_packet.cpp | 27 +++--- zone/inventory.cpp | 84 ++++++++--------- zone/zonedb.cpp | 32 ++++--- 20 files changed, 697 insertions(+), 466 deletions(-) diff --git a/common/clientversions.h b/common/clientversions.h index d0b5f7c41..040e5dc12 100644 --- a/common/clientversions.h +++ b/common/clientversions.h @@ -1,3 +1,24 @@ +/* +EQEMu: Everquest Server Emulator + +Copyright (C) 2001-2015 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 + +*/ + #ifndef CLIENTVERSIONS_H #define CLIENTVERSIONS_H @@ -46,29 +67,29 @@ static const char* ClientVersionName(ClientVersion version) switch (version) { case ClientVersion::Unknown: - return "ClientVersion::Unknown"; + return "Unknown"; case ClientVersion::Client62: - return "ClientVersion::Client62"; + return "Client62"; case ClientVersion::Titanium: - return "ClientVersion::Titanium"; + return "Titanium"; case ClientVersion::SoF: - return "ClientVersion::SoF"; + return "SoF"; case ClientVersion::SoD: - return "ClientVersion::SoD"; + return "SoD"; case ClientVersion::UF: - return "ClientVersion::UF"; + return "UF"; case ClientVersion::RoF: - return "ClientVersion::RoF"; + return "RoF"; case ClientVersion::RoF2: - return "ClientVersion::RoF2"; + return "RoF2"; case ClientVersion::MobNPC: - return "ClientVersion::MobNPC"; + return "MobNPC"; case ClientVersion::MobMerc: - return "ClientVersion::MobMerc"; + return "MobMerc"; case ClientVersion::MobBot: - return "ClientVersion::MobBot"; + return "MobBot"; case ClientVersion::MobPet: - return "ClientVersion::MobPet"; + return "MobPet"; default: return " Invalid ClientVersion"; }; diff --git a/common/database_conversions.cpp b/common/database_conversions.cpp index 8a938e8b5..7d49522a3 100644 --- a/common/database_conversions.cpp +++ b/common/database_conversions.cpp @@ -157,18 +157,26 @@ namespace Convert { /*84*/ uint32 Points; /*88*/ } PVPStatsEntry_Struct; + struct BandolierItem_Struct { - uint32 item_id; - uint32 icon; - char item_name[64]; + uint32 ID; + uint32 Icon; + char Name[64]; }; struct Bandolier_Struct { - char name[32]; - Convert::BandolierItem_Struct items[EmuConstants::BANDOLIER_SIZE]; + char Name[32]; + Convert::BandolierItem_Struct Items[EmuConstants::BANDOLIER_SIZE]; + }; + + struct PotionBeltItem_Struct { + uint32 ID; + uint32 Icon; + char Name[64]; }; struct PotionBelt_Struct { - Convert::BandolierItem_Struct items[EmuConstants::POTION_BELT_SIZE]; + Convert::PotionBeltItem_Struct Items[EmuConstants::POTION_BELT_SIZE]; }; + struct SuspendedMinion_Struct { /*000*/ uint16 SpellID; @@ -1431,14 +1439,14 @@ bool Database::CheckDatabaseConvertPPDeblob(){ /* Run Bandolier Convert */ first_entry = 0; rquery = ""; for (i = 0; i < EmuConstants::BANDOLIERS_COUNT; i++){ - if (strlen(pp->bandoliers[i].name) < 32) { + if (strlen(pp->bandoliers[i].Name) < 32) { for (int si = 0; si < EmuConstants::BANDOLIER_SIZE; si++){ - if (pp->bandoliers[i].items[si].item_id > 0){ + if (pp->bandoliers[i].Items[si].ID > 0){ if (first_entry != 1) { - rquery = StringFormat("REPLACE INTO `character_bandolier` (id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name) VALUES (%i, %u, %i, %u, %u, '%s')", character_id, i, si, pp->bandoliers[i].items[si].item_id, pp->bandoliers[i].items[si].icon, pp->bandoliers[i].name); + rquery = StringFormat("REPLACE INTO `character_bandolier` (id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name) VALUES (%i, %u, %i, %u, %u, '%s')", character_id, i, si, pp->bandoliers[i].Items[si].ID, pp->bandoliers[i].Items[si].Icon, pp->bandoliers[i].Name); first_entry = 1; } - rquery = rquery + StringFormat(", (%i, %u, %i, %u, %u, '%s')", character_id, i, si, pp->bandoliers[i].items[si].item_id, pp->bandoliers[i].items[si].icon, pp->bandoliers[i].name); + rquery = rquery + StringFormat(", (%i, %u, %i, %u, %u, '%s')", character_id, i, si, pp->bandoliers[i].Items[si].ID, pp->bandoliers[i].Items[si].Icon, pp->bandoliers[i].Name); } } } @@ -1447,12 +1455,12 @@ bool Database::CheckDatabaseConvertPPDeblob(){ /* Run Potion Belt Convert */ first_entry = 0; rquery = ""; for (i = 0; i < EmuConstants::POTION_BELT_SIZE; i++){ - if (pp->potionbelt.items[i].item_id > 0){ + if (pp->potionbelt.Items[i].ID > 0){ if (first_entry != 1){ - rquery = StringFormat("REPLACE INTO `character_potionbelt` (id, potion_id, item_id, icon) VALUES (%i, %u, %u, %u)", character_id, i, pp->potionbelt.items[i].item_id, pp->potionbelt.items[i].icon); + rquery = StringFormat("REPLACE INTO `character_potionbelt` (id, potion_id, item_id, icon) VALUES (%i, %u, %u, %u)", character_id, i, pp->potionbelt.Items[i].ID, pp->potionbelt.Items[i].Icon); first_entry = 1; } - rquery = rquery + StringFormat(", (%i, %u, %u, %u)", character_id, i, pp->potionbelt.items[i].item_id, pp->potionbelt.items[i].icon); + rquery = rquery + StringFormat(", (%i, %u, %u, %u)", character_id, i, pp->potionbelt.Items[i].ID, pp->potionbelt.Items[i].Icon); } } diff --git a/common/eq_dictionary.cpp b/common/eq_dictionary.cpp index ed3253260..026d84a31 100644 --- a/common/eq_dictionary.cpp +++ b/common/eq_dictionary.cpp @@ -1,7 +1,7 @@ /* EQEMu: Everquest Server Emulator -Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) +Copyright (C) 2001-2015 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 @@ -25,8 +25,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // class EmuConstants // -uint16 EmuConstants::InventoryMapSize(int16 indexMap) { - switch (indexMap) { +uint16 EmuConstants::InventoryMapSize(int16 indexMap) +{ + switch (indexMap) + { case MapPossessions: return MAP_POSSESSIONS_SIZE; case MapBank: @@ -83,7 +85,8 @@ uint16 EmuConstants::InventoryMapSize(int16 indexMap) { } /* -std::string EmuConstants::InventoryLocationName(Location_Struct location) { +std::string EmuConstants::InventoryLocationName(Location_Struct location) +{ // not ready for implementation... std::string ret_str; StringFormat(ret_str, "%s, %s, %s, %s", InventoryMapName(location.map), InventoryMainName(location.main), InventorySubName(location.sub), InventoryAugName(location.aug)); @@ -91,8 +94,10 @@ std::string EmuConstants::InventoryLocationName(Location_Struct location) { } */ -std::string EmuConstants::InventoryMapName(int16 indexMap) { - switch (indexMap) { +std::string EmuConstants::InventoryMapName(int16 indexMap) +{ + switch (indexMap) + { case INVALID_INDEX: return "Invalid Map"; case MapPossessions: @@ -100,7 +105,7 @@ std::string EmuConstants::InventoryMapName(int16 indexMap) { case MapBank: return "Bank"; case MapSharedBank: - return "Shared Bank"; + return "SharedBank"; case MapTrade: return "Trade"; case MapWorld: @@ -110,9 +115,9 @@ std::string EmuConstants::InventoryMapName(int16 indexMap) { case MapTribute: return "Tribute"; case MapTrophyTribute: - return "Trophy Tribute"; + return "TrophyTribute"; case MapGuildTribute: - return "Guild Tribute"; + return "GuildTribute"; case MapMerchant: return "Merchant"; case MapDeleted: @@ -124,23 +129,23 @@ std::string EmuConstants::InventoryMapName(int16 indexMap) { case MapInspect: return "Inspect"; case MapRealEstate: - return "Real Estate"; + return "RealEstate"; case MapViewMODPC: - return "View MOD PC"; + return "ViewMODPC"; case MapViewMODBank: - return "View MOD Bank"; + return "ViewMODBank"; case MapViewMODSharedBank: - return "View MOD Shared Bank"; + return "ViewMODSharedBank"; case MapViewMODLimbo: - return "View MOD Limbo"; + return "ViewMODLimbo"; case MapAltStorage: - return "Alt Storage"; + return "AltStorage"; case MapArchived: return "Archived"; case MapMail: return "Mail"; case MapGuildTrophyTribute: - return "Guild Trophy Tribute"; + return "GuildTrophyTribute"; case MapKrono: return "Krono"; case MapOther: @@ -150,20 +155,22 @@ std::string EmuConstants::InventoryMapName(int16 indexMap) { } } -std::string EmuConstants::InventoryMainName(int16 indexMain) { - switch (indexMain) { +std::string EmuConstants::InventoryMainName(int16 indexMain) +{ + switch (indexMain) + { case INVALID_INDEX: return "Invalid Main"; case MainCharm: return "Charm"; case MainEar1: - return "Ear 1"; + return "Ear1"; case MainHead: return "Head"; case MainFace: return "Face"; case MainEar2: - return "Ear 2"; + return "Ear2"; case MainNeck: return "Neck"; case MainShoulders: @@ -173,9 +180,9 @@ std::string EmuConstants::InventoryMainName(int16 indexMain) { case MainBack: return "Back"; case MainWrist1: - return "Wrist 1"; + return "Wrist1"; case MainWrist2: - return "Wrist 2"; + return "Wrist2"; case MainRange: return "Range"; case MainHands: @@ -185,9 +192,9 @@ std::string EmuConstants::InventoryMainName(int16 indexMain) { case MainSecondary: return "Secondary"; case MainFinger1: - return "Finger 1"; + return "Finger1"; case MainFinger2: - return "Finger 2"; + return "Finger2"; case MainChest: return "Chest"; case MainLegs: @@ -197,30 +204,30 @@ std::string EmuConstants::InventoryMainName(int16 indexMain) { case MainWaist: return "Waist"; case MainPowerSource: - return "Power Source"; + return "PowerSource"; case MainAmmo: return "Ammo"; case MainGeneral1: - return "General 1"; + return "General1"; case MainGeneral2: - return "General 2"; + return "General2"; case MainGeneral3: - return "General 3"; + return "General3"; case MainGeneral4: - return "General 4"; + return "General4"; case MainGeneral5: - return "General 5"; + return "General5"; case MainGeneral6: - return "General 6"; + return "General6"; case MainGeneral7: - return "General 7"; + return "General7"; case MainGeneral8: - return "General 8"; + return "General8"; /* case MainGeneral9: - return "General 9"; + return "General9"; case MainGeneral10: - return "General 10"; + return "General10"; */ case MainCursor: return "Cursor"; @@ -229,7 +236,8 @@ std::string EmuConstants::InventoryMainName(int16 indexMain) { } } -std::string EmuConstants::InventorySubName(int16 indexSub) { +std::string EmuConstants::InventorySubName(int16 indexSub) +{ if (indexSub == INVALID_INDEX) return "Invalid Sub"; @@ -237,12 +245,13 @@ std::string EmuConstants::InventorySubName(int16 indexSub) { return "Unknown Sub"; std::string ret_str; - ret_str = StringFormat("Container %i", (indexSub + 1)); // zero-based index..but, count starts at one + ret_str = StringFormat("Container%i", (indexSub + 1)); // zero-based index..but, count starts at one return ret_str; } -std::string EmuConstants::InventoryAugName(int16 indexAug) { +std::string EmuConstants::InventoryAugName(int16 indexAug) +{ if (indexAug == INVALID_INDEX) return "Invalid Aug"; @@ -250,7 +259,7 @@ std::string EmuConstants::InventoryAugName(int16 indexAug) { return "Unknown Aug"; std::string ret_str; - ret_str = StringFormat("Augment %i", (indexAug + 1)); // zero-based index..but, count starts at one + ret_str = StringFormat("Augment%i", (indexAug + 1)); // zero-based index..but, count starts at one return ret_str; } @@ -260,14 +269,16 @@ std::string EmuConstants::InventoryAugName(int16 indexAug) { // class EQLimits // // client validation -bool EQLimits::IsValidPCClientVersion(ClientVersion clientVersion) { +bool EQLimits::IsValidPCClientVersion(ClientVersion clientVersion) +{ if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_PC_CLIENT) return true; return false; } -ClientVersion EQLimits::ValidatePCClientVersion(ClientVersion clientVersion) { +ClientVersion EQLimits::ValidatePCClientVersion(ClientVersion clientVersion) +{ if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_PC_CLIENT) return clientVersion; @@ -275,14 +286,16 @@ ClientVersion EQLimits::ValidatePCClientVersion(ClientVersion clientVersion) { } // npc validation -bool EQLimits::IsValidNPCClientVersion(ClientVersion clientVersion) { +bool EQLimits::IsValidNPCClientVersion(ClientVersion clientVersion) +{ if (clientVersion > LAST_PC_CLIENT && clientVersion <= LAST_NPC_CLIENT) return true; return false; } -ClientVersion EQLimits::ValidateNPCClientVersion(ClientVersion clientVersion) { +ClientVersion EQLimits::ValidateNPCClientVersion(ClientVersion clientVersion) +{ if (clientVersion > LAST_PC_CLIENT && clientVersion <= LAST_NPC_CLIENT) return clientVersion; @@ -290,14 +303,16 @@ ClientVersion EQLimits::ValidateNPCClientVersion(ClientVersion clientVersion) { } // mob validation -bool EQLimits::IsValidMobClientVersion(ClientVersion clientVersion) { +bool EQLimits::IsValidMobClientVersion(ClientVersion clientVersion) +{ if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_NPC_CLIENT) return true; return false; } -ClientVersion EQLimits::ValidateMobClientVersion(ClientVersion clientVersion) { +ClientVersion EQLimits::ValidateMobClientVersion(ClientVersion clientVersion) +{ if (clientVersion > ClientVersion::Unknown && clientVersion <= LAST_NPC_CLIENT) return clientVersion; @@ -305,7 +320,8 @@ ClientVersion EQLimits::ValidateMobClientVersion(ClientVersion clientVersion) { } // inventory -uint16 EQLimits::InventoryMapSize(int16 indexMap, ClientVersion clientVersion) { +uint16 EQLimits::InventoryMapSize(int16 indexMap, ClientVersion clientVersion) +{ // not all maps will have an instantiated container..some are references for queue generators (i.e., bazaar, mail, etc...) // a zero '0' indicates a needed value..otherwise, change to '_NOTUSED' for a null value so indices requiring research can be identified // ALL of these values need to be verified before pushing to live @@ -704,7 +720,8 @@ uint16 EQLimits::InventoryMapSize(int16 indexMap, ClientVersion clientVersion) { return NOT_USED; } -uint64 EQLimits::PossessionsBitmask(ClientVersion clientVersion) { +uint64 EQLimits::PossessionsBitmask(ClientVersion clientVersion) +{ // these are for the new inventory system (RoF)..not the current (Ti) one... // 0x0000000000200000 is SlotPowerSource (SoF+) // 0x0000000080000000 is SlotGeneral9 (RoF+) @@ -730,7 +747,8 @@ uint64 EQLimits::PossessionsBitmask(ClientVersion clientVersion) { //return local[static_cast(ValidateMobClientVersion(clientVersion))]; } -uint64 EQLimits::EquipmentBitmask(ClientVersion clientVersion) { +uint64 EQLimits::EquipmentBitmask(ClientVersion clientVersion) +{ static const uint64 local[CLIENT_VERSION_COUNT] = { /*Unknown*/ NOT_USED, /*62*/ 0x00000000005FFFFF, @@ -751,7 +769,8 @@ uint64 EQLimits::EquipmentBitmask(ClientVersion clientVersion) { //return local[static_cast(ValidateMobClientVersion(clientVersion))]; } -uint64 EQLimits::GeneralBitmask(ClientVersion clientVersion) { +uint64 EQLimits::GeneralBitmask(ClientVersion clientVersion) +{ static const uint64 local[CLIENT_VERSION_COUNT] = { /*Unknown*/ NOT_USED, /*62*/ 0x000000007F800000, @@ -772,7 +791,8 @@ uint64 EQLimits::GeneralBitmask(ClientVersion clientVersion) { //return local[static_cast(ValidateMobClientVersion(clientVersion))]; } -uint64 EQLimits::CursorBitmask(ClientVersion clientVersion) { +uint64 EQLimits::CursorBitmask(ClientVersion clientVersion) +{ static const uint64 local[CLIENT_VERSION_COUNT] = { /*Unknown*/ NOT_USED, /*62*/ 0x0000000200000000, @@ -793,7 +813,8 @@ uint64 EQLimits::CursorBitmask(ClientVersion clientVersion) { //return local[static_cast(ValidateMobClientVersion(clientVersion))]; } -bool EQLimits::AllowsEmptyBagInBag(ClientVersion clientVersion) { +bool EQLimits::AllowsEmptyBagInBag(ClientVersion clientVersion) +{ static const bool local[CLIENT_VERSION_COUNT] = { /*Unknown*/ false, /*62*/ false, @@ -814,7 +835,8 @@ bool EQLimits::AllowsEmptyBagInBag(ClientVersion clientVersion) { //return local[static_cast(ValidateMobClientVersion(clientVersion))]; } -bool EQLimits::AllowsClickCastFromBag(ClientVersion clientVersion) { +bool EQLimits::AllowsClickCastFromBag(ClientVersion clientVersion) +{ static const bool local[CLIENT_VERSION_COUNT] = { /*Unknown*/ false, /*62*/ false, @@ -835,7 +857,8 @@ bool EQLimits::AllowsClickCastFromBag(ClientVersion clientVersion) { } // items -uint16 EQLimits::ItemCommonSize(ClientVersion clientVersion) { +uint16 EQLimits::ItemCommonSize(ClientVersion clientVersion) +{ static const uint16 local[CLIENT_VERSION_COUNT] = { /*Unknown*/ NOT_USED, /*62*/ EmuConstants::ITEM_COMMON_SIZE, @@ -855,7 +878,8 @@ uint16 EQLimits::ItemCommonSize(ClientVersion clientVersion) { return local[static_cast(ValidateMobClientVersion(clientVersion))]; } -uint16 EQLimits::ItemContainerSize(ClientVersion clientVersion) { +uint16 EQLimits::ItemContainerSize(ClientVersion clientVersion) +{ static const uint16 local[CLIENT_VERSION_COUNT] = { /*Unknown*/ NOT_USED, /*62*/ EmuConstants::ITEM_CONTAINER_SIZE, @@ -875,7 +899,8 @@ uint16 EQLimits::ItemContainerSize(ClientVersion clientVersion) { return local[static_cast(ValidateMobClientVersion(clientVersion))]; } -bool EQLimits::CoinHasWeight(ClientVersion clientVersion) { +bool EQLimits::CoinHasWeight(ClientVersion clientVersion) +{ static const bool local[CLIENT_VERSION_COUNT] = { /*Unknown*/ true, /*62*/ true, @@ -895,7 +920,8 @@ bool EQLimits::CoinHasWeight(ClientVersion clientVersion) { return local[static_cast(ValidateMobClientVersion(clientVersion))]; } -uint32 EQLimits::BandoliersCount(ClientVersion clientVersion) { +uint32 EQLimits::BandoliersCount(ClientVersion clientVersion) +{ static const uint32 local[CLIENT_VERSION_COUNT] = { /*Unknown*/ NOT_USED, /*62*/ EmuConstants::BANDOLIERS_COUNT, @@ -915,7 +941,8 @@ uint32 EQLimits::BandoliersCount(ClientVersion clientVersion) { return local[static_cast(ValidateMobClientVersion(clientVersion))]; } -uint32 EQLimits::BandolierSize(ClientVersion clientVersion) { +uint32 EQLimits::BandolierSize(ClientVersion clientVersion) +{ static const uint32 local[CLIENT_VERSION_COUNT] = { /*Unknown*/ NOT_USED, /*62*/ EmuConstants::BANDOLIER_SIZE, @@ -935,7 +962,8 @@ uint32 EQLimits::BandolierSize(ClientVersion clientVersion) { return local[static_cast(ValidateMobClientVersion(clientVersion))]; } -uint32 EQLimits::PotionBeltSize(ClientVersion clientVersion) { +uint32 EQLimits::PotionBeltSize(ClientVersion clientVersion) +{ static const uint32 local[CLIENT_VERSION_COUNT] = { /*Unknown*/ NOT_USED, /*62*/ EmuConstants::POTION_BELT_SIZE, diff --git a/common/eq_dictionary.h b/common/eq_dictionary.h index d1337856e..151397dd4 100644 --- a/common/eq_dictionary.h +++ b/common/eq_dictionary.h @@ -1,7 +1,7 @@ /* EQEMu: Everquest Server Emulator -Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net) +Copyright (C) 2001-2015 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 @@ -42,7 +42,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //using namespace RoF2::maps; // server inventory maps enumeration (code and database sync'd to reference) //using namespace RoF::slots; // server possessions slots enumeration (code and database sync'd to reference) -class EmuConstants { +class EmuConstants +{ // an immutable value is required to initialize arrays, etc... use this class as a repository for those public: // database @@ -140,23 +141,16 @@ public: static const uint16 ITEM_COMMON_SIZE = RoF::consts::ITEM_COMMON_SIZE; static const uint16 ITEM_CONTAINER_SIZE = Titanium::consts::ITEM_CONTAINER_SIZE; - // player profile - //static const uint32 CLASS_BITMASK = 0; // needs value - //static const uint32 RACE_BITMASK = 0; // needs value - // BANDOLIERS_COUNT sets maximum limit..active limit will need to be handled by the appropriate AA static const uint32 BANDOLIERS_COUNT = Titanium::consts::BANDOLIERS_COUNT; // count = number of bandolier instances static const uint32 BANDOLIER_SIZE = Titanium::consts::BANDOLIER_SIZE; // size = number of equipment slots in bandolier instance static const uint32 POTION_BELT_SIZE = Titanium::consts::POTION_BELT_SIZE; static const size_t TEXT_LINK_BODY_LENGTH = 56; - - // legacy-related functions - //static int ServerToPerlSlot(int slot); // encode - //static int PerlToServerSlot(int slot); // decode }; -class EQLimits { +class EQLimits +{ // values should default to a non-beneficial value..unless value conflicts with intended operation // // EmuConstants may be used as references..but, not every reference needs to be in EmuConstants (i.e., AllowsEmptyBagInBag(), CoinHasWeight(), etc...) diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index cd30cf3d1..9d49a3080 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -15,6 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifndef EQ_PACKET_STRUCTS_H #define EQ_PACKET_STRUCTS_H @@ -756,29 +757,46 @@ struct Tribute_Struct { uint32 tier; }; -//len = 72 -struct BandolierItem_Struct { - uint32 item_id; - uint32 icon; - char item_name[64]; -}; - -//len = 320 -enum { //bandolier item positions - bandolierMainHand = 0, - bandolierOffHand, +// Bandolier item positions +enum +{ + bandolierPrimary = 0, + bandolierSecondary, bandolierRange, bandolierAmmo }; -struct Bandolier_Struct { - char name[32]; - BandolierItem_Struct items[EmuConstants::BANDOLIER_SIZE]; -}; -struct PotionBelt_Struct { - BandolierItem_Struct items[EmuConstants::POTION_BELT_SIZE]; + +//len = 72 +struct BandolierItem_Struct +{ + uint32 ID; + uint32 Icon; + char Name[64]; }; -struct MovePotionToBelt_Struct { +//len = 320 +struct Bandolier_Struct +{ + char Name[32]; + BandolierItem_Struct Items[EmuConstants::BANDOLIER_SIZE]; +}; + +//len = 72 +struct PotionBeltItem_Struct +{ + uint32 ID; + uint32 Icon; + char Name[64]; +}; + +//len = 288 +struct PotionBelt_Struct +{ + PotionBeltItem_Struct Items[EmuConstants::POTION_BELT_SIZE]; +}; + +struct MovePotionToBelt_Struct +{ uint32 Action; uint32 SlotNumber; uint32 ItemID; @@ -4106,30 +4124,35 @@ struct DynamicWall_Struct { /*80*/ }; -enum { //bandolier actions - BandolierCreate = 0, - BandolierRemove = 1, - BandolierSet = 2 +// Bandolier actions +enum +{ + bandolierCreate = 0, + bandolierRemove, + bandolierSet }; -struct BandolierCreate_Struct { -/*00*/ uint32 action; //0 for create -/*04*/ uint8 number; -/*05*/ char name[32]; -/*37*/ uint16 unknown37; //seen 0x93FD -/*39*/ uint8 unknown39; //0 +struct BandolierCreate_Struct +{ +/*00*/ uint32 Action; //0 for create +/*04*/ uint8 Number; +/*05*/ char Name[32]; +/*37*/ uint16 Unknown37; //seen 0x93FD +/*39*/ uint8 Unknown39; //0 }; -struct BandolierDelete_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierDelete_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint8 Number; +/*05*/ uint8 Unknown05[35]; }; -struct BandolierSet_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierSet_Struct +{ +/*00*/ uint32 Action; +/*04*/ uint8 Number; +/*05*/ uint8 Unknown05[35]; }; struct Arrow_Struct { diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index cb95bfdb1..42b588ec3 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -2290,15 +2290,15 @@ namespace RoF for (uint32 r = 0; r < EmuConstants::BANDOLIERS_COUNT; r++) { - outapp->WriteString(emu->bandoliers[r].name); + outapp->WriteString(emu->bandoliers[r].Name); for (uint32 j = 0; j < EmuConstants::BANDOLIER_SIZE; ++j) { - outapp->WriteString(emu->bandoliers[r].items[j].item_name); - outapp->WriteUInt32(emu->bandoliers[r].items[j].item_id); - if (emu->bandoliers[r].items[j].icon) + outapp->WriteString(emu->bandoliers[r].Items[j].Name); + outapp->WriteUInt32(emu->bandoliers[r].Items[j].ID); + if (emu->bandoliers[r].Items[j].Icon) { - outapp->WriteSInt32(emu->bandoliers[r].items[j].icon); + outapp->WriteSInt32(emu->bandoliers[r].Items[j].Icon); } else { @@ -2324,11 +2324,11 @@ namespace RoF for (uint32 r = 0; r < EmuConstants::POTION_BELT_SIZE; r++) { - outapp->WriteString(emu->potionbelt.items[r].item_name); - outapp->WriteUInt32(emu->potionbelt.items[r].item_id); - if (emu->potionbelt.items[r].icon) + outapp->WriteString(emu->potionbelt.Items[r].Name); + outapp->WriteUInt32(emu->potionbelt.Items[r].ID); + if (emu->potionbelt.Items[r].Icon) { - outapp->WriteSInt32(emu->potionbelt.items[r].icon); + outapp->WriteSInt32(emu->potionbelt.Items[r].Icon); } else { diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 5cab22a60..4aec12ba1 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -2364,15 +2364,15 @@ namespace RoF2 for (uint32 r = 0; r < EmuConstants::BANDOLIERS_COUNT; r++) { - outapp->WriteString(emu->bandoliers[r].name); + outapp->WriteString(emu->bandoliers[r].Name); for (uint32 j = 0; j < EmuConstants::BANDOLIER_SIZE; ++j) { - outapp->WriteString(emu->bandoliers[r].items[j].item_name); - outapp->WriteUInt32(emu->bandoliers[r].items[j].item_id); - if (emu->bandoliers[r].items[j].icon) + outapp->WriteString(emu->bandoliers[r].Items[j].Name); + outapp->WriteUInt32(emu->bandoliers[r].Items[j].ID); + if (emu->bandoliers[r].Items[j].Icon) { - outapp->WriteSInt32(emu->bandoliers[r].items[j].icon); + outapp->WriteSInt32(emu->bandoliers[r].Items[j].Icon); } else { @@ -2398,11 +2398,11 @@ namespace RoF2 for (uint32 r = 0; r < EmuConstants::POTION_BELT_SIZE; r++) { - outapp->WriteString(emu->potionbelt.items[r].item_name); - outapp->WriteUInt32(emu->potionbelt.items[r].item_id); - if (emu->potionbelt.items[r].icon) + outapp->WriteString(emu->potionbelt.Items[r].Name); + outapp->WriteUInt32(emu->potionbelt.Items[r].ID); + if (emu->potionbelt.Items[r].Icon) { - outapp->WriteSInt32(emu->potionbelt.items[r].icon); + outapp->WriteSInt32(emu->potionbelt.Items[r].Icon); } else { diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index e4e11ae8b..092d12d76 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -896,38 +896,66 @@ struct Tribute_Struct { uint32 tier; }; -struct BandolierItem_Struct { - char item_name[1]; // Variable Length - uint32 item_id; - uint32 icon; -}; - -//len = 72 -struct BandolierItem_Struct_Old { - uint32 item_id; - uint32 icon; - char item_name[64]; -}; - -//len = 320 -enum { //bandolier item positions - bandolierMainHand = 0, - bandolierOffHand, +// Bandolier item positions +enum +{ + bandolierPrimary = 0, + bandolierSecondary, bandolierRange, bandolierAmmo }; -struct Bandolier_Struct { - char name[1]; // Variable Length - BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS]; + +struct BandolierItem_Struct +{ + char Name[1]; // Variable Length + uint32 ID; + uint32 Icon; }; -struct Bandolier_Struct_Old { - char name[32]; - BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS]; +//len = 72 +struct BandolierItem_Struct_Old +{ + uint32 ID; + uint32 Icon; + char Name[64]; }; -struct PotionBelt_Struct { - BandolierItem_Struct items[MAX_POTIONS_IN_BELT]; +//len = 320 +struct Bandolier_Struct +{ + char Name[1]; // Variable Length + BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; +}; + +struct Bandolier_Struct_Old +{ + char Name[32]; + BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; +}; + +struct PotionBeltItem_Struct +{ + char Name[1]; // Variable Length + uint32 ID; + uint32 Icon; +}; + +//len = 72 +struct PotionBeltItem_Struct_Old +{ + uint32 ID; + uint32 Icon; + char Name[64]; +}; + +struct PotionBelt_Struct +{ + PotionBeltItem_Struct Items[MAX_POTIONS_IN_BELT]; +}; + +struct PotionBelt_Struct_Old +{ + PotionBeltItem_Struct_Old Items[MAX_POTIONS_IN_BELT]; }; struct GroupLeadershipAA_Struct { @@ -4109,30 +4137,35 @@ struct DynamicWall_Struct { /*80*/ }; -enum { //bandolier actions - BandolierCreate = 0, - BandolierRemove = 1, - BandolierSet = 2 +// Bandolier actions +enum +{ + bandolierCreate = 0, + bandolierRemove, + bandolierSet }; -struct BandolierCreate_Struct { -/*00*/ uint32 action; //0 for create -/*04*/ uint8 number; -/*05*/ char name[32]; -/*37*/ uint16 unknown37; //seen 0x93FD -/*39*/ uint8 unknown39; //0 +struct BandolierCreate_Struct +{ + /*00*/ uint32 Action; //0 for create + /*04*/ uint8 Number; + /*05*/ char Name[32]; + /*37*/ uint16 Unknown37; //seen 0x93FD + /*39*/ uint8 Unknown39; //0 }; -struct BandolierDelete_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierDelete_Struct +{ + /*00*/ uint32 Action; + /*04*/ uint8 Number; + /*05*/ uint8 Unknown05[35]; }; -struct BandolierSet_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierSet_Struct +{ + /*00*/ uint32 Action; + /*04*/ uint8 Number; + /*05*/ uint8 Unknown05[35]; }; struct Arrow_Struct { diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 417ff2e64..770dd250f 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -880,38 +880,66 @@ struct Tribute_Struct { uint32 tier; }; -struct BandolierItem_Struct { - char item_name[1]; // Variable Length - uint32 item_id; - uint32 icon; -}; - -//len = 72 -struct BandolierItem_Struct_Old { - uint32 item_id; - uint32 icon; - char item_name[64]; -}; - -//len = 320 -enum { //bandolier item positions - bandolierMainHand = 0, - bandolierOffHand, +// Bandolier item positions +enum +{ + bandolierPrimary = 0, + bandolierSecondary, bandolierRange, bandolierAmmo }; -struct Bandolier_Struct { - char name[1]; // Variable Length - BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS]; + +struct BandolierItem_Struct +{ + char Name[1]; // Variable Length + uint32 ID; + uint32 Icon; }; -struct Bandolier_Struct_Old { - char name[32]; - BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS]; +//len = 72 +struct BandolierItem_Struct_Old +{ + uint32 ID; + uint32 Icon; + char Name[64]; }; -struct PotionBelt_Struct { - BandolierItem_Struct items[MAX_POTIONS_IN_BELT]; +//len = 320 +struct Bandolier_Struct +{ + char Name[1]; // Variable Length + BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; +}; + +struct Bandolier_Struct_Old +{ + char Name[32]; + BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; +}; + +struct PotionBeltItem_Struct +{ + char Name[1]; // Variable Length + uint32 ID; + uint32 Icon; +}; + +//len = 72 +struct PotionBeltItem_Struct_Old +{ + uint32 ID; + uint32 Icon; + char Name[64]; +}; + +struct PotionBelt_Struct +{ + PotionBeltItem_Struct Items[MAX_POTIONS_IN_BELT]; +}; + +struct PotionBelt_Struct_Old +{ + PotionBeltItem_Struct_Old Items[MAX_POTIONS_IN_BELT]; }; struct GroupLeadershipAA_Struct { @@ -4113,30 +4141,35 @@ struct DynamicWall_Struct { /*80*/ }; -enum { //bandolier actions - BandolierCreate = 0, - BandolierRemove = 1, - BandolierSet = 2 +// Bandolier actions +enum +{ + bandolierCreate = 0, + bandolierRemove, + bandolierSet }; -struct BandolierCreate_Struct { -/*00*/ uint32 action; //0 for create -/*04*/ uint8 number; -/*05*/ char name[32]; -/*37*/ uint16 unknown37; //seen 0x93FD -/*39*/ uint8 unknown39; //0 +struct BandolierCreate_Struct +{ + /*00*/ uint32 Action; //0 for create + /*04*/ uint8 Number; + /*05*/ char Name[32]; + /*37*/ uint16 Unknown37; //seen 0x93FD + /*39*/ uint8 Unknown39; //0 }; -struct BandolierDelete_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierDelete_Struct +{ + /*00*/ uint32 Action; + /*04*/ uint8 Number; + /*05*/ uint8 Unknown05[35]; }; -struct BandolierSet_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierSet_Struct +{ + /*00*/ uint32 Action; + /*04*/ uint8 Number; + /*05*/ uint8 Unknown05[35]; }; struct Arrow_Struct { diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index 488f51e87..c2a6eeaaa 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -1610,19 +1610,19 @@ namespace SoD //NOTE: new client supports 20 bandoliers, our internal rep //only supports 4.. for (r = 0; r < 4; r++) { - OUT_str(bandoliers[r].name); + OUT_str(bandoliers[r].Name); uint32 k; for (k = 0; k < structs::MAX_PLAYER_BANDOLIER_ITEMS; k++) { - OUT(bandoliers[r].items[k].item_id); - OUT(bandoliers[r].items[k].icon); - OUT_str(bandoliers[r].items[k].item_name); + OUT(bandoliers[r].Items[k].ID); + OUT(bandoliers[r].Items[k].Icon); + OUT_str(bandoliers[r].Items[k].Name); } } // OUT(unknown07444[5120]); for (r = 0; r < structs::MAX_POTIONS_IN_BELT; r++) { - OUT(potionbelt.items[r].item_id); - OUT(potionbelt.items[r].icon); - OUT_str(potionbelt.items[r].item_name); + OUT(potionbelt.Items[r].ID); + OUT(potionbelt.Items[r].Icon); + OUT_str(potionbelt.Items[r].Name); } // OUT(unknown12852[8]); // OUT(unknown12864[76]); diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index 810c59b1e..18f17ce62 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -686,26 +686,42 @@ struct Tribute_Struct { uint32 tier; }; -//len = 72 -struct BandolierItem_Struct { - uint32 item_id; - uint32 icon; - char item_name[64]; -}; - -//len = 320 -enum { //bandolier item positions - bandolierMainHand = 0, - bandolierOffHand, +// Bandolier item positions +enum +{ + bandolierPrimary = 0, + bandolierSecondary, bandolierRange, bandolierAmmo }; -struct Bandolier_Struct { - char name[32]; - BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS]; + +//len = 72 +struct BandolierItem_Struct +{ + uint32 ID; + uint32 Icon; + char Name[64]; }; -struct PotionBelt_Struct { - BandolierItem_Struct items[MAX_POTIONS_IN_BELT]; + +//len = 320 +struct Bandolier_Struct +{ + char Name[32]; + BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; +}; + +//len = 72 +struct PotionBeltItem_Struct +{ + uint32 ID; + uint32 Icon; + char Name[64]; +}; + +//len = 288 +struct PotionBelt_Struct +{ + PotionBeltItem_Struct Items[MAX_POTIONS_IN_BELT]; }; static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; @@ -3686,30 +3702,35 @@ struct DynamicWall_Struct { /*80*/ }; -enum { //bandolier actions - BandolierCreate = 0, - BandolierRemove = 1, - BandolierSet = 2 +// Bandolier actions +enum +{ + bandolierCreate = 0, + bandolierRemove, + bandolierSet }; -struct BandolierCreate_Struct { -/*00*/ uint32 action; //0 for create -/*04*/ uint8 number; -/*05*/ char name[32]; -/*37*/ uint16 unknown37; //seen 0x93FD -/*39*/ uint8 unknown39; //0 +struct BandolierCreate_Struct +{ + /*00*/ uint32 Action; //0 for create + /*04*/ uint8 Number; + /*05*/ char Name[32]; + /*37*/ uint16 Unknown37; //seen 0x93FD + /*39*/ uint8 Unknown39; //0 }; -struct BandolierDelete_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierDelete_Struct +{ + /*00*/ uint32 Action; + /*04*/ uint8 Number; + /*05*/ uint8 Unknown05[35]; }; -struct BandolierSet_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierSet_Struct +{ + /*00*/ uint32 Action; + /*04*/ uint8 Number; + /*05*/ uint8 Unknown05[35]; }; struct Arrow_Struct { diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index ab956a28d..cf19582b0 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1268,19 +1268,19 @@ namespace SoF //NOTE: new client supports 20 bandoliers, our internal rep //only supports 4.. for (r = 0; r < 4; r++) { - OUT_str(bandoliers[r].name); + OUT_str(bandoliers[r].Name); uint32 k; for (k = 0; k < structs::MAX_PLAYER_BANDOLIER_ITEMS; k++) { - OUT(bandoliers[r].items[k].item_id); - OUT(bandoliers[r].items[k].icon); - OUT_str(bandoliers[r].items[k].item_name); + OUT(bandoliers[r].Items[k].ID); + OUT(bandoliers[r].Items[k].Icon); + OUT_str(bandoliers[r].Items[k].Name); } } // OUT(unknown07444[5120]); for (r = 0; r < structs::MAX_POTIONS_IN_BELT; r++) { - OUT(potionbelt.items[r].item_id); - OUT(potionbelt.items[r].icon); - OUT_str(potionbelt.items[r].item_name); + OUT(potionbelt.Items[r].ID); + OUT(potionbelt.Items[r].Icon); + OUT_str(potionbelt.Items[r].Name); } // OUT(unknown12852[8]); // OUT(unknown12864[76]); diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index 32b275716..33773e91e 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -663,26 +663,42 @@ struct Tribute_Struct { uint32 tier; }; -//len = 72 -struct BandolierItem_Struct { - uint32 item_id; - uint32 icon; - char item_name[64]; -}; - -//len = 320 -enum { //bandolier item positions - bandolierMainHand = 0, - bandolierOffHand, +// Bandolier item positions +enum +{ + bandolierPrimary = 0, + bandolierSecondary, bandolierRange, bandolierAmmo }; -struct Bandolier_Struct { - char name[32]; - BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS]; + +//len = 72 +struct BandolierItem_Struct +{ + uint32 ID; + uint32 Icon; + char Name[64]; }; -struct PotionBelt_Struct { - BandolierItem_Struct items[MAX_POTIONS_IN_BELT]; + +//len = 320 +struct Bandolier_Struct +{ + char Name[32]; + BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; +}; + +//len = 72 +struct PotionBeltItem_Struct +{ + uint32 ID; + uint32 Icon; + char Name[64]; +}; + +//len = 288 +struct PotionBelt_Struct +{ + PotionBeltItem_Struct Items[MAX_POTIONS_IN_BELT]; }; static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; @@ -3548,30 +3564,35 @@ struct DynamicWall_Struct { /*80*/ }; -enum { //bandolier actions - BandolierCreate = 0, - BandolierRemove = 1, - BandolierSet = 2 +// Bandolier actions +enum +{ + bandolierCreate = 0, + bandolierRemove, + bandolierSet }; -struct BandolierCreate_Struct { -/*00*/ uint32 action; //0 for create -/*04*/ uint8 number; -/*05*/ char name[32]; -/*37*/ uint16 unknown37; //seen 0x93FD -/*39*/ uint8 unknown39; //0 +struct BandolierCreate_Struct +{ + /*00*/ uint32 Action; //0 for create + /*04*/ uint8 Number; + /*05*/ char Name[32]; + /*37*/ uint16 Unknown37; //seen 0x93FD + /*39*/ uint8 Unknown39; //0 }; -struct BandolierDelete_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierDelete_Struct +{ + /*00*/ uint32 Action; + /*04*/ uint8 Number; + /*05*/ uint8 Unknown05[35]; }; -struct BandolierSet_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierSet_Struct +{ + /*00*/ uint32 Action; + /*04*/ uint8 Number; + /*05*/ uint8 Unknown05[35]; }; struct Arrow_Struct { diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index 3be2d7d70..7528a378d 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -924,19 +924,19 @@ namespace Titanium OUT(aapoints); // OUT(unknown06160[4]); for (r = 0; r < structs::MAX_PLAYER_BANDOLIER; r++) { - OUT_str(bandoliers[r].name); + OUT_str(bandoliers[r].Name); uint32 k; for (k = 0; k < structs::MAX_PLAYER_BANDOLIER_ITEMS; k++) { - OUT(bandoliers[r].items[k].item_id); - OUT(bandoliers[r].items[k].icon); - OUT_str(bandoliers[r].items[k].item_name); + OUT(bandoliers[r].Items[k].ID); + OUT(bandoliers[r].Items[k].Icon); + OUT_str(bandoliers[r].Items[k].Name); } } // OUT(unknown07444[5120]); for (r = 0; r < structs::MAX_PLAYER_BANDOLIER_ITEMS; r++) { - OUT(potionbelt.items[r].item_id); - OUT(potionbelt.items[r].icon); - OUT_str(potionbelt.items[r].item_name); + OUT(potionbelt.Items[r].ID); + OUT(potionbelt.Items[r].Icon); + OUT_str(potionbelt.Items[r].Name); } // OUT(unknown12852[8]); // OUT(unknown12864[76]); diff --git a/common/patches/titanium_structs.h b/common/patches/titanium_structs.h index 19d82d6af..8286d125c 100644 --- a/common/patches/titanium_structs.h +++ b/common/patches/titanium_structs.h @@ -594,26 +594,42 @@ struct Tribute_Struct { uint32 tier; }; -//len = 72 -struct BandolierItem_Struct { - uint32 item_id; - uint32 icon; - char item_name[64]; -}; - -//len = 320 -enum { //bandolier item positions - bandolierMainHand = 0, - bandolierOffHand, +// Bandolier item positions +enum +{ + bandolierPrimary = 0, + bandolierSecondary, bandolierRange, bandolierAmmo }; -struct Bandolier_Struct { - char name[32]; - BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS]; + +//len = 72 +struct BandolierItem_Struct +{ + uint32 ID; + uint32 Icon; + char Name[64]; }; -struct PotionBelt_Struct { - BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS]; + +//len = 320 +struct Bandolier_Struct +{ + char Name[32]; + BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; +}; + +//len = 72 +struct PotionBeltItem_Struct +{ + uint32 ID; + uint32 Icon; + char Name[64]; +}; + +//len = 288 +struct PotionBelt_Struct +{ + PotionBeltItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; }; static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; @@ -3030,30 +3046,35 @@ struct DynamicWall_Struct { /*80*/ }; -enum { //bandolier actions - BandolierCreate = 0, - BandolierRemove = 1, - BandolierSet = 2 +// Bandolier actions +enum +{ + bandolierCreate = 0, + bandolierRemove, + bandolierSet }; -struct BandolierCreate_Struct { -/*00*/ uint32 action; //0 for create -/*04*/ uint8 number; -/*05*/ char name[32]; -/*37*/ uint16 unknown37; //seen 0x93FD -/*39*/ uint8 unknown39; //0 +struct BandolierCreate_Struct +{ + /*00*/ uint32 Action; //0 for create + /*04*/ uint8 Number; + /*05*/ char Name[32]; + /*37*/ uint16 Unknown37; //seen 0x93FD + /*39*/ uint8 Unknown39; //0 }; -struct BandolierDelete_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierDelete_Struct +{ + /*00*/ uint32 Action; + /*04*/ uint8 Number; + /*05*/ uint8 Unknown05[35]; }; -struct BandolierSet_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierSet_Struct +{ + /*00*/ uint32 Action; + /*04*/ uint8 Number; + /*05*/ uint8 Unknown05[35]; }; struct Arrow_Struct { diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 11fdb3c7b..334a6dc88 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -1872,19 +1872,19 @@ namespace UF //NOTE: new client supports 20 bandoliers, our internal rep //only supports 4.. for (r = 0; r < 4; r++) { - OUT_str(bandoliers[r].name); + OUT_str(bandoliers[r].Name); uint32 k; for (k = 0; k < structs::MAX_PLAYER_BANDOLIER_ITEMS; k++) { - OUT(bandoliers[r].items[k].item_id); - OUT(bandoliers[r].items[k].icon); - OUT_str(bandoliers[r].items[k].item_name); + OUT(bandoliers[r].Items[k].ID); + OUT(bandoliers[r].Items[k].Icon); + OUT_str(bandoliers[r].Items[k].Name); } } // OUT(unknown07444[5120]); for (r = 0; r < structs::MAX_POTIONS_IN_BELT; r++) { - OUT(potionbelt.items[r].item_id); - OUT(potionbelt.items[r].icon); - OUT_str(potionbelt.items[r].item_name); + OUT(potionbelt.Items[r].ID); + OUT(potionbelt.Items[r].Icon); + OUT_str(potionbelt.Items[r].Name); } // OUT(unknown12852[8]); // OUT(unknown12864[76]); diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index fb4d00de3..762419a67 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -732,26 +732,42 @@ struct Tribute_Struct { uint32 tier; }; -//len = 72 -struct BandolierItem_Struct { - uint32 item_id; - uint32 icon; - char item_name[64]; -}; - -//len = 320 -enum { //bandolier item positions - bandolierMainHand = 0, - bandolierOffHand, +// Bandolier item positions +enum +{ + bandolierPrimary = 0, + bandolierSecondary, bandolierRange, bandolierAmmo }; -struct Bandolier_Struct { - char name[32]; - BandolierItem_Struct items[MAX_PLAYER_BANDOLIER_ITEMS]; + +//len = 72 +struct BandolierItem_Struct +{ + uint32 ID; + uint32 Icon; + char Name[64]; }; -struct PotionBelt_Struct { - BandolierItem_Struct items[MAX_POTIONS_IN_BELT]; + +//len = 320 +struct Bandolier_Struct +{ + char Name[32]; + BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; +}; + +//len = 72 +struct PotionBeltItem_Struct +{ + uint32 ID; + uint32 Icon; + char Name[64]; +}; + +//len = 288 +struct PotionBelt_Struct +{ + PotionBeltItem_Struct Items[MAX_POTIONS_IN_BELT]; }; static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; @@ -3758,30 +3774,35 @@ struct DynamicWall_Struct { /*80*/ }; -enum { //bandolier actions - BandolierCreate = 0, - BandolierRemove = 1, - BandolierSet = 2 +// Bandolier actions +enum +{ + bandolierCreate = 0, + bandolierRemove, + bandolierSet }; -struct BandolierCreate_Struct { -/*00*/ uint32 action; //0 for create -/*04*/ uint8 number; -/*05*/ char name[32]; -/*37*/ uint16 unknown37; //seen 0x93FD -/*39*/ uint8 unknown39; //0 +struct BandolierCreate_Struct +{ + /*00*/ uint32 Action; //0 for create + /*04*/ uint8 Number; + /*05*/ char Name[32]; + /*37*/ uint16 Unknown37; //seen 0x93FD + /*39*/ uint8 Unknown39; //0 }; -struct BandolierDelete_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierDelete_Struct +{ + /*00*/ uint32 Action; + /*04*/ uint8 Number; + /*05*/ uint8 Unknown05[35]; }; -struct BandolierSet_Struct { -/*00*/ uint32 action; -/*04*/ uint8 number; -/*05*/ uint8 unknown05[35]; +struct BandolierSet_Struct +{ + /*00*/ uint32 Action; + /*04*/ uint8 Number; + /*05*/ uint8 Unknown05[35]; }; // Not 100% sure on this struct. Live as of 1/1/11 is different than UF. Seems to work 'OK' diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 2d60b444e..97b927352 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -3183,19 +3183,20 @@ void Client::Handle_OP_Bandolier(const EQApplicationPacket *app) BandolierCreate_Struct *bs = (BandolierCreate_Struct*)app->pBuffer; - switch (bs->action) { - case BandolierCreate: + switch (bs->Action) + { + case bandolierCreate: CreateBandolier(app); break; - case BandolierRemove: + case bandolierRemove: RemoveBandolier(app); break; - case BandolierSet: + case bandolierSet: SetBandolier(app); break; default: - Log.Out(Logs::General, Logs::None, "Uknown Bandolier action %i", bs->action); - + Log.Out(Logs::General, Logs::None, "Uknown Bandolier action %i", bs->Action); + break; } } @@ -10442,16 +10443,16 @@ void Client::Handle_OP_PotionBelt(const EQApplicationPacket *app) if (mptbs->Action == 0) { const Item_Struct *BaseItem = database.GetItem(mptbs->ItemID); if (BaseItem) { - m_pp.potionbelt.items[mptbs->SlotNumber].item_id = BaseItem->ID; - m_pp.potionbelt.items[mptbs->SlotNumber].icon = BaseItem->Icon; - strn0cpy(m_pp.potionbelt.items[mptbs->SlotNumber].item_name, BaseItem->Name, sizeof(BaseItem->Name)); - database.SaveCharacterPotionBelt(this->CharacterID(), mptbs->SlotNumber, m_pp.potionbelt.items[mptbs->SlotNumber].item_id, m_pp.potionbelt.items[mptbs->SlotNumber].icon); + m_pp.potionbelt.Items[mptbs->SlotNumber].ID = BaseItem->ID; + m_pp.potionbelt.Items[mptbs->SlotNumber].Icon = BaseItem->Icon; + strn0cpy(m_pp.potionbelt.Items[mptbs->SlotNumber].Name, BaseItem->Name, sizeof(BaseItem->Name)); + database.SaveCharacterPotionBelt(this->CharacterID(), mptbs->SlotNumber, m_pp.potionbelt.Items[mptbs->SlotNumber].ID, m_pp.potionbelt.Items[mptbs->SlotNumber].Icon); } } else { - m_pp.potionbelt.items[mptbs->SlotNumber].item_id = 0; - m_pp.potionbelt.items[mptbs->SlotNumber].icon = 0; - strncpy(m_pp.potionbelt.items[mptbs->SlotNumber].item_name, "\0", 1); + m_pp.potionbelt.Items[mptbs->SlotNumber].ID = 0; + m_pp.potionbelt.Items[mptbs->SlotNumber].Icon = 0; + strncpy(m_pp.potionbelt.Items[mptbs->SlotNumber].Name, "\0", 1); } } diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 69f1de882..7f2fa0173 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -2476,97 +2476,99 @@ EQApplicationPacket* Client::ReturnItemPacket(int16 slot_id, const ItemInst* ins return outapp; } -static int16 BandolierSlotToWeaponSlot(int BandolierSlot) { - - switch(BandolierSlot) { - case bandolierMainHand: - return MainPrimary; - case bandolierOffHand: - return MainSecondary; - case bandolierRange: - return MainRange; - default: - return MainAmmo; +static int16 BandolierSlotToWeaponSlot(int BandolierSlot) +{ + switch (BandolierSlot) + { + case bandolierPrimary: + return MainPrimary; + case bandolierSecondary: + return MainSecondary; + case bandolierRange: + return MainRange; + default: + return MainAmmo; } } -void Client::CreateBandolier(const EQApplicationPacket *app) { - +void Client::CreateBandolier(const EQApplicationPacket *app) +{ // Store bandolier set with the number and name passed by the client, along with the items that are currently // in the players weapon slots. BandolierCreate_Struct *bs = (BandolierCreate_Struct*)app->pBuffer; - Log.Out(Logs::Detail, Logs::Inventory, "Char: %s Creating Bandolier Set %i, Set Name: %s", GetName(), bs->number, bs->name); - strcpy(m_pp.bandoliers[bs->number].name, bs->name); + Log.Out(Logs::Detail, Logs::Inventory, "Char: %s Creating Bandolier Set %i, Set Name: %s", GetName(), bs->Number, bs->Name); + strcpy(m_pp.bandoliers[bs->Number].Name, bs->Name); const ItemInst* InvItem = nullptr; const Item_Struct *BaseItem = nullptr; - int16 WeaponSlot; + int16 WeaponSlot = 0; - for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) { + for(int BandolierSlot = bandolierPrimary; BandolierSlot <= bandolierAmmo; BandolierSlot++) { WeaponSlot = BandolierSlotToWeaponSlot(BandolierSlot); InvItem = GetInv()[WeaponSlot]; if(InvItem) { BaseItem = InvItem->GetItem(); Log.Out(Logs::Detail, Logs::Inventory, "Char: %s adding item %s to slot %i", GetName(),BaseItem->Name, WeaponSlot); - m_pp.bandoliers[bs->number].items[BandolierSlot].item_id = BaseItem->ID; - m_pp.bandoliers[bs->number].items[BandolierSlot].icon = BaseItem->Icon; - database.SaveCharacterBandolier(this->CharacterID(), bs->number, BandolierSlot, m_pp.bandoliers[bs->number].items[BandolierSlot].item_id, m_pp.bandoliers[bs->number].items[BandolierSlot].icon, bs->name); + m_pp.bandoliers[bs->Number].Items[BandolierSlot].ID = BaseItem->ID; + m_pp.bandoliers[bs->Number].Items[BandolierSlot].Icon = BaseItem->Icon; + database.SaveCharacterBandolier(this->CharacterID(), bs->Number, BandolierSlot, m_pp.bandoliers[bs->Number].Items[BandolierSlot].ID, m_pp.bandoliers[bs->Number].Items[BandolierSlot].Icon, bs->Name); } else { Log.Out(Logs::Detail, Logs::Inventory, "Char: %s no item in slot %i", GetName(), WeaponSlot); - m_pp.bandoliers[bs->number].items[BandolierSlot].item_id = 0; - m_pp.bandoliers[bs->number].items[BandolierSlot].icon = 0; + m_pp.bandoliers[bs->Number].Items[BandolierSlot].ID = 0; + m_pp.bandoliers[bs->Number].Items[BandolierSlot].Icon = 0; } } } -void Client::RemoveBandolier(const EQApplicationPacket *app) { +void Client::RemoveBandolier(const EQApplicationPacket *app) +{ BandolierDelete_Struct *bds = (BandolierDelete_Struct*)app->pBuffer; - Log.Out(Logs::Detail, Logs::Inventory, "Char: %s removing set", GetName(), bds->number); - memset(m_pp.bandoliers[bds->number].name, 0, 32); - for(int i = bandolierMainHand; i <= bandolierAmmo; i++) { - m_pp.bandoliers[bds->number].items[i].item_id = 0; - m_pp.bandoliers[bds->number].items[i].icon = 0; + Log.Out(Logs::Detail, Logs::Inventory, "Char: %s removing set", GetName(), bds->Number); + memset(m_pp.bandoliers[bds->Number].Name, 0, 32); + for(int i = bandolierPrimary; i <= bandolierAmmo; i++) { + m_pp.bandoliers[bds->Number].Items[i].ID = 0; + m_pp.bandoliers[bds->Number].Items[i].Icon = 0; } - database.DeleteCharacterBandolier(this->CharacterID(), bds->number); + database.DeleteCharacterBandolier(this->CharacterID(), bds->Number); } -void Client::SetBandolier(const EQApplicationPacket *app) { - +void Client::SetBandolier(const EQApplicationPacket *app) +{ // Swap the weapons in the given bandolier set into the character's weapon slots and return // any items currently in the weapon slots to inventory. BandolierSet_Struct *bss = (BandolierSet_Struct*)app->pBuffer; - Log.Out(Logs::Detail, Logs::Inventory, "Char: %s activating set %i", GetName(), bss->number); - int16 slot; - int16 WeaponSlot; + Log.Out(Logs::Detail, Logs::Inventory, "Char: %s activating set %i", GetName(), bss->Number); + int16 slot = 0; + int16 WeaponSlot = 0; ItemInst *BandolierItems[4]; // Temporary holding area for the weapons we pull out of their inventory // First we pull the items for this bandolier set out of their inventory, this makes space to put the // currently equipped items back. - for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) { + for(int BandolierSlot = bandolierPrimary; BandolierSlot <= bandolierAmmo; BandolierSlot++) { // If this bandolier set has an item in this position - if(m_pp.bandoliers[bss->number].items[BandolierSlot].item_id) { + if(m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID) { WeaponSlot = BandolierSlotToWeaponSlot(BandolierSlot); // Check if the player has the item specified in the bandolier set on them. // - slot = m_inv.HasItem(m_pp.bandoliers[bss->number].items[BandolierSlot].item_id, 1, + slot = m_inv.HasItem(m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID, 1, invWhereWorn|invWherePersonal); // removed 'invWhereCursor' argument from above and implemented slots 30, 331-340 checks here if (slot == INVALID_INDEX) { if (m_inv.GetItem(MainCursor)) { - if (m_inv.GetItem(MainCursor)->GetItem()->ID == m_pp.bandoliers[bss->number].items[BandolierSlot].item_id && + if (m_inv.GetItem(MainCursor)->GetItem()->ID == m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID && m_inv.GetItem(MainCursor)->GetCharges() >= 1) { // '> 0' the same, but this matches Inventory::_HasItem conditional check slot = MainCursor; } else if (m_inv.GetItem(MainCursor)->GetItem()->ItemClass == 1) { for(int16 CursorBagSlot = EmuConstants::CURSOR_BAG_BEGIN; CursorBagSlot <= EmuConstants::CURSOR_BAG_END; CursorBagSlot++) { if (m_inv.GetItem(CursorBagSlot)) { - if (m_inv.GetItem(CursorBagSlot)->GetItem()->ID == m_pp.bandoliers[bss->number].items[BandolierSlot].item_id && + if (m_inv.GetItem(CursorBagSlot)->GetItem()->ID == m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID && m_inv.GetItem(CursorBagSlot)->GetCharges() >= 1) { // ditto slot = CursorBagSlot; break; @@ -2630,14 +2632,14 @@ void Client::SetBandolier(const EQApplicationPacket *app) { // Now we move the required weapons into the character weapon slots, and return any items we are replacing // back to inventory. // - for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) { + for(int BandolierSlot = bandolierPrimary; BandolierSlot <= bandolierAmmo; BandolierSlot++) { // Find the inventory slot corresponding to this bandolier slot WeaponSlot = BandolierSlotToWeaponSlot(BandolierSlot); // if there is an item in this Bandolier slot ? - if(m_pp.bandoliers[bss->number].items[BandolierSlot].item_id) { + if(m_pp.bandoliers[bss->Number].Items[BandolierSlot].ID) { // if the player has this item in their inventory, and it is not already where it needs to be if(BandolierItems[BandolierSlot]) { // Pull the item that we are going to replace diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index b99024c5c..8a95de0f4 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1175,20 +1175,21 @@ bool ZoneDatabase::LoadCharacterMaterialColor(uint32 character_id, PlayerProfile return true; } -bool ZoneDatabase::LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp){ +bool ZoneDatabase::LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp) +{ std::string query = StringFormat("SELECT `bandolier_id`, `bandolier_slot`, `item_id`, `icon`, `bandolier_name` FROM `character_bandolier` WHERE `id` = %u LIMIT 16", character_id); auto results = database.QueryDatabase(query); int i = 0; int r = 0; int si = 0; for (i = 0; i < EmuConstants::BANDOLIERS_COUNT; i++) for (int si = 0; si < EmuConstants::BANDOLIER_SIZE; si++) - pp->bandoliers[i].items[si].icon = 0; + pp->bandoliers[i].Items[si].Icon = 0; for (auto row = results.begin(); row != results.end(); ++row) { r = 0; i = atoi(row[r]); /* Bandolier ID */ r++; si = atoi(row[r]); /* Bandolier Slot */ r++; - pp->bandoliers[i].items[si].item_id = atoi(row[r]); r++; - pp->bandoliers[i].items[si].icon = atoi(row[r]); r++; - strcpy(pp->bandoliers[i].name, row[r]); r++; + pp->bandoliers[i].Items[si].ID = atoi(row[r]); r++; + pp->bandoliers[i].Items[si].Icon = atoi(row[r]); r++; + strcpy(pp->bandoliers[i].Name, row[r]); r++; si++; } return true; @@ -1213,13 +1214,14 @@ bool ZoneDatabase::LoadCharacterTribute(uint32 character_id, PlayerProfile_Struc return true; } -bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp){ +bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp) +{ std::string query = StringFormat("SELECT `potion_id`, `item_id`, `icon` FROM `character_potionbelt` WHERE `id` = %u LIMIT 4", character_id); auto results = database.QueryDatabase(query); int i = 0; for (i = 0; i < EmuConstants::POTION_BELT_SIZE; i++){ - pp->potionbelt.items[i].icon = 0; - pp->potionbelt.items[i].item_id = 0; - strncpy(pp->potionbelt.items[i].item_name, "\0", 1); + pp->potionbelt.Items[i].Icon = 0; + pp->potionbelt.Items[i].ID = 0; + strncpy(pp->potionbelt.Items[i].Name, "\0", 1); } for (auto row = results.begin(); row != results.end(); ++row) { @@ -1230,9 +1232,9 @@ bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struc if(!item) continue; - pp->potionbelt.items[i].item_id = item_id; - pp->potionbelt.items[i].icon = atoi(row[2]); - strncpy(pp->potionbelt.items[i].item_name, item->Name, 64); + pp->potionbelt.Items[i].ID = item_id; + pp->potionbelt.Items[i].Icon = atoi(row[2]); + strncpy(pp->potionbelt.Items[i].Name, item->Name, 64); } return true; @@ -1326,7 +1328,8 @@ bool ZoneDatabase::SaveCharacterTribute(uint32 character_id, PlayerProfile_Struc return true; } -bool ZoneDatabase::SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name){ +bool ZoneDatabase::SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name) +{ char bandolier_name_esc[64]; DoEscapeString(bandolier_name_esc, bandolier_name, strlen(bandolier_name)); std::string query = StringFormat("REPLACE INTO `character_bandolier` (id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name) VALUES (%u, %u, %u, %u, %u,'%s')", character_id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name_esc); @@ -1335,7 +1338,8 @@ bool ZoneDatabase::SaveCharacterBandolier(uint32 character_id, uint8 bandolier_i return true; } -bool ZoneDatabase::SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon) { +bool ZoneDatabase::SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon) +{ std::string query = StringFormat("REPLACE INTO `character_potionbelt` (id, potion_id, item_id, icon) VALUES (%u, %u, %u, %u)", character_id, potion_id, item_id, icon); auto results = QueryDatabase(query); return true; From 5a3b10a11c3c2ee4fdcc8d0c02e0bb33096e5f2d Mon Sep 17 00:00:00 2001 From: Uleat Date: Sat, 14 Feb 2015 18:10:50 -0500 Subject: [PATCH 089/114] Constant name re-alignments prior to extended bandolier/potion belt activation --- common/database_conversions.cpp | 15 ++++++----- common/eq_dictionary.cpp | 42 ++++++++++++++--------------- common/eq_dictionary.h | 12 +++++---- common/eq_packet_structs.h | 6 ++--- common/patches/rof.cpp | 16 +++++------ common/patches/rof2.cpp | 16 +++++------ common/patches/rof2_constants.h | 7 ++--- common/patches/rof2_structs.h | 15 ++++------- common/patches/rof_constants.h | 7 ++--- common/patches/rof_structs.h | 15 ++++------- common/patches/sod.cpp | 4 +-- common/patches/sod_constants.h | 7 ++--- common/patches/sod_structs.h | 9 +++---- common/patches/sof.cpp | 4 +-- common/patches/sof_constants.h | 7 ++--- common/patches/sof_structs.h | 9 +++---- common/patches/titanium.cpp | 6 ++--- common/patches/titanium_constants.h | 7 ++--- common/patches/titanium_structs.h | 8 +++--- common/patches/uf.cpp | 4 +-- common/patches/uf_constants.h | 7 ++--- common/patches/uf_structs.h | 9 +++---- zone/zonedb.cpp | 6 ++--- 23 files changed, 114 insertions(+), 124 deletions(-) diff --git a/common/database_conversions.cpp b/common/database_conversions.cpp index 7d49522a3..f6c43687f 100644 --- a/common/database_conversions.cpp +++ b/common/database_conversions.cpp @@ -158,6 +158,8 @@ namespace Convert { /*88*/ } PVPStatsEntry_Struct; + static const size_t BANDOLIERS_SIZE = 4; + static const size_t BANDOLIER_ITEM_COUNT = 4; struct BandolierItem_Struct { uint32 ID; uint32 Icon; @@ -165,16 +167,17 @@ namespace Convert { }; struct Bandolier_Struct { char Name[32]; - Convert::BandolierItem_Struct Items[EmuConstants::BANDOLIER_SIZE]; + Convert::BandolierItem_Struct Items[Convert::BANDOLIER_ITEM_COUNT]; }; + static const size_t POTION_BELT_ITEM_COUNT = 4; struct PotionBeltItem_Struct { uint32 ID; uint32 Icon; char Name[64]; }; struct PotionBelt_Struct { - Convert::PotionBeltItem_Struct Items[EmuConstants::POTION_BELT_SIZE]; + Convert::PotionBeltItem_Struct Items[Convert::POTION_BELT_ITEM_COUNT]; }; struct SuspendedMinion_Struct @@ -354,7 +357,7 @@ namespace Convert { /*12800*/ uint32 expAA; /*12804*/ uint32 aapoints; //avaliable, unspent /*12808*/ uint8 unknown12844[36]; - /*12844*/ Convert::Bandolier_Struct bandoliers[EmuConstants::BANDOLIERS_COUNT]; + /*12844*/ Convert::Bandolier_Struct bandoliers[Convert::BANDOLIERS_SIZE]; /*14124*/ uint8 unknown14160[4506]; /*18630*/ Convert::SuspendedMinion_Struct SuspendedMinion; // No longer in use /*19240*/ uint32 timeentitledonaccount; @@ -1438,9 +1441,9 @@ bool Database::CheckDatabaseConvertPPDeblob(){ if (rquery != ""){ results = QueryDatabase(rquery); } /* Run Bandolier Convert */ first_entry = 0; rquery = ""; - for (i = 0; i < EmuConstants::BANDOLIERS_COUNT; i++){ + for (i = 0; i < Convert::BANDOLIERS_SIZE; i++){ if (strlen(pp->bandoliers[i].Name) < 32) { - for (int si = 0; si < EmuConstants::BANDOLIER_SIZE; si++){ + for (int si = 0; si < Convert::BANDOLIER_ITEM_COUNT; si++){ if (pp->bandoliers[i].Items[si].ID > 0){ if (first_entry != 1) { rquery = StringFormat("REPLACE INTO `character_bandolier` (id, bandolier_id, bandolier_slot, item_id, icon, bandolier_name) VALUES (%i, %u, %i, %u, %u, '%s')", character_id, i, si, pp->bandoliers[i].Items[si].ID, pp->bandoliers[i].Items[si].Icon, pp->bandoliers[i].Name); @@ -1454,7 +1457,7 @@ bool Database::CheckDatabaseConvertPPDeblob(){ if (rquery != ""){ results = QueryDatabase(rquery); } /* Run Potion Belt Convert */ first_entry = 0; rquery = ""; - for (i = 0; i < EmuConstants::POTION_BELT_SIZE; i++){ + for (i = 0; i < Convert::POTION_BELT_ITEM_COUNT; i++){ if (pp->potionbelt.Items[i].ID > 0){ if (first_entry != 1){ rquery = StringFormat("REPLACE INTO `character_potionbelt` (id, potion_id, item_id, icon) VALUES (%i, %u, %u, %u)", character_id, i, pp->potionbelt.Items[i].ID, pp->potionbelt.Items[i].Icon); diff --git a/common/eq_dictionary.cpp b/common/eq_dictionary.cpp index 026d84a31..a87ae569a 100644 --- a/common/eq_dictionary.cpp +++ b/common/eq_dictionary.cpp @@ -924,13 +924,13 @@ uint32 EQLimits::BandoliersCount(ClientVersion clientVersion) { static const uint32 local[CLIENT_VERSION_COUNT] = { /*Unknown*/ NOT_USED, -/*62*/ EmuConstants::BANDOLIERS_COUNT, -/*Titanium*/ EmuConstants::BANDOLIERS_COUNT, -/*SoF*/ EmuConstants::BANDOLIERS_COUNT, -/*SoD*/ EmuConstants::BANDOLIERS_COUNT, -/*Underfoot*/ EmuConstants::BANDOLIERS_COUNT, -/*RoF*/ EmuConstants::BANDOLIERS_COUNT, -/*RoF2*/ EmuConstants::BANDOLIERS_COUNT, +/*62*/ NOT_USED, +/*Titanium*/ EmuConstants::BANDOLIERS_SIZE, +/*SoF*/ EmuConstants::BANDOLIERS_SIZE, +/*SoD*/ EmuConstants::BANDOLIERS_SIZE, +/*Underfoot*/ EmuConstants::BANDOLIERS_SIZE, +/*RoF*/ EmuConstants::BANDOLIERS_SIZE, +/*RoF2*/ EmuConstants::BANDOLIERS_SIZE, /*NPC*/ NOT_USED, /*Merc*/ NOT_USED, @@ -945,13 +945,13 @@ uint32 EQLimits::BandolierSize(ClientVersion clientVersion) { static const uint32 local[CLIENT_VERSION_COUNT] = { /*Unknown*/ NOT_USED, -/*62*/ EmuConstants::BANDOLIER_SIZE, -/*Titanium*/ EmuConstants::BANDOLIER_SIZE, -/*SoF*/ EmuConstants::BANDOLIER_SIZE, -/*SoD*/ EmuConstants::BANDOLIER_SIZE, -/*Underfoot*/ EmuConstants::BANDOLIER_SIZE, -/*RoF*/ EmuConstants::BANDOLIER_SIZE, -/*RoF2*/ EmuConstants::BANDOLIER_SIZE, +/*62*/ NOT_USED, +/*Titanium*/ EmuConstants::BANDOLIER_ITEM_COUNT, +/*SoF*/ EmuConstants::BANDOLIER_ITEM_COUNT, +/*SoD*/ EmuConstants::BANDOLIER_ITEM_COUNT, +/*Underfoot*/ EmuConstants::BANDOLIER_ITEM_COUNT, +/*RoF*/ EmuConstants::BANDOLIER_ITEM_COUNT, +/*RoF2*/ EmuConstants::BANDOLIER_ITEM_COUNT, /*NPC*/ NOT_USED, /*Merc*/ NOT_USED, @@ -966,13 +966,13 @@ uint32 EQLimits::PotionBeltSize(ClientVersion clientVersion) { static const uint32 local[CLIENT_VERSION_COUNT] = { /*Unknown*/ NOT_USED, -/*62*/ EmuConstants::POTION_BELT_SIZE, -/*Titanium*/ EmuConstants::POTION_BELT_SIZE, -/*SoF*/ EmuConstants::POTION_BELT_SIZE, -/*SoD*/ EmuConstants::POTION_BELT_SIZE, -/*Underfoot*/ EmuConstants::POTION_BELT_SIZE, -/*RoF*/ EmuConstants::POTION_BELT_SIZE, -/*RoF2*/ EmuConstants::POTION_BELT_SIZE, +/*62*/ NOT_USED, +/*Titanium*/ EmuConstants::POTION_BELT_ITEM_COUNT, +/*SoF*/ EmuConstants::POTION_BELT_ITEM_COUNT, +/*SoD*/ EmuConstants::POTION_BELT_ITEM_COUNT, +/*Underfoot*/ EmuConstants::POTION_BELT_ITEM_COUNT, +/*RoF*/ EmuConstants::POTION_BELT_ITEM_COUNT, +/*RoF2*/ EmuConstants::POTION_BELT_ITEM_COUNT, /*NPC*/ NOT_USED, /*Merc*/ NOT_USED, diff --git a/common/eq_dictionary.h b/common/eq_dictionary.h index 151397dd4..501fd52cf 100644 --- a/common/eq_dictionary.h +++ b/common/eq_dictionary.h @@ -141,12 +141,14 @@ public: static const uint16 ITEM_COMMON_SIZE = RoF::consts::ITEM_COMMON_SIZE; static const uint16 ITEM_CONTAINER_SIZE = Titanium::consts::ITEM_CONTAINER_SIZE; - // BANDOLIERS_COUNT sets maximum limit..active limit will need to be handled by the appropriate AA - static const uint32 BANDOLIERS_COUNT = Titanium::consts::BANDOLIERS_COUNT; // count = number of bandolier instances - static const uint32 BANDOLIER_SIZE = Titanium::consts::BANDOLIER_SIZE; // size = number of equipment slots in bandolier instance - static const uint32 POTION_BELT_SIZE = Titanium::consts::POTION_BELT_SIZE; + // BANDOLIERS_SIZE sets maximum limit..active limit will need to be handled by the appropriate AA or spell (or item?) + static const size_t BANDOLIERS_SIZE = Titanium::consts::BANDOLIERS_SIZE; // number of bandolier instances + static const size_t BANDOLIER_ITEM_COUNT = Titanium::consts::BANDOLIER_ITEM_COUNT; // number of equipment slots in bandolier instance - static const size_t TEXT_LINK_BODY_LENGTH = 56; + // POTION_BELT_SIZE sets maximum limit..active limit will need to be handled by the appropriate AA or spell (or item?) + static const size_t POTION_BELT_ITEM_COUNT = Titanium::consts::POTION_BELT_ITEM_COUNT; + + static const size_t TEXT_LINK_BODY_LENGTH = RoF2::consts::TEXT_LINK_BODY_LENGTH; }; class EQLimits diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 9d49a3080..17fe7e913 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -778,7 +778,7 @@ struct BandolierItem_Struct struct Bandolier_Struct { char Name[32]; - BandolierItem_Struct Items[EmuConstants::BANDOLIER_SIZE]; + BandolierItem_Struct Items[EmuConstants::BANDOLIER_ITEM_COUNT]; }; //len = 72 @@ -792,7 +792,7 @@ struct PotionBeltItem_Struct //len = 288 struct PotionBelt_Struct { - PotionBeltItem_Struct Items[EmuConstants::POTION_BELT_SIZE]; + PotionBeltItem_Struct Items[EmuConstants::POTION_BELT_ITEM_COUNT]; }; struct MovePotionToBelt_Struct @@ -1121,7 +1121,7 @@ struct PlayerProfile_Struct /*12800*/ uint32 expAA; /*12804*/ uint32 aapoints; //avaliable, unspent /*12808*/ uint8 unknown12844[36]; -/*12844*/ Bandolier_Struct bandoliers[EmuConstants::BANDOLIERS_COUNT]; +/*12844*/ Bandolier_Struct bandoliers[EmuConstants::BANDOLIERS_SIZE]; /*14124*/ uint8 unknown14160[4506]; /*18630*/ SuspendedMinion_Struct SuspendedMinion; // No longer in use /*19240*/ uint32 timeentitledonaccount; diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 42b588ec3..86382e7b5 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -2286,13 +2286,13 @@ namespace RoF outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown - outapp->WriteUInt32(structs::MAX_PLAYER_BANDOLIER); + outapp->WriteUInt32(consts::BANDOLIERS_SIZE); - for (uint32 r = 0; r < EmuConstants::BANDOLIERS_COUNT; r++) + for (uint32 r = 0; r < EmuConstants::BANDOLIERS_SIZE; r++) { outapp->WriteString(emu->bandoliers[r].Name); - for (uint32 j = 0; j < EmuConstants::BANDOLIER_SIZE; ++j) + for (uint32 j = 0; j < EmuConstants::BANDOLIER_ITEM_COUNT; ++j) { outapp->WriteString(emu->bandoliers[r].Items[j].Name); outapp->WriteUInt32(emu->bandoliers[r].Items[j].ID); @@ -2308,11 +2308,11 @@ namespace RoF } } - for (uint32 r = 0; r < structs::MAX_PLAYER_BANDOLIER - EmuConstants::BANDOLIERS_COUNT; r++) + for (uint32 r = 0; r < consts::BANDOLIERS_SIZE - EmuConstants::BANDOLIERS_SIZE; r++) { outapp->WriteString(""); - for (uint32 j = 0; j < EmuConstants::BANDOLIER_SIZE; ++j) + for (uint32 j = 0; j < EmuConstants::BANDOLIER_ITEM_COUNT; ++j) { outapp->WriteString(""); outapp->WriteUInt32(0); @@ -2320,9 +2320,9 @@ namespace RoF } } - outapp->WriteUInt32(structs::MAX_POTIONS_IN_BELT); + outapp->WriteUInt32(consts::POTION_BELT_ITEM_COUNT); - for (uint32 r = 0; r < EmuConstants::POTION_BELT_SIZE; r++) + for (uint32 r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT; r++) { outapp->WriteString(emu->potionbelt.Items[r].Name); outapp->WriteUInt32(emu->potionbelt.Items[r].ID); @@ -2336,7 +2336,7 @@ namespace RoF } } - for (uint32 r = 0; r < structs::MAX_POTIONS_IN_BELT - EmuConstants::POTION_BELT_SIZE; r++) + for (uint32 r = 0; r < consts::POTION_BELT_ITEM_COUNT - EmuConstants::POTION_BELT_ITEM_COUNT; r++) { outapp->WriteString(""); outapp->WriteUInt32(0); diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 4aec12ba1..ba06c2742 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -2360,13 +2360,13 @@ namespace RoF2 outapp->WriteUInt8(0); // Unknown outapp->WriteUInt8(0); // Unknown - outapp->WriteUInt32(structs::MAX_PLAYER_BANDOLIER); + outapp->WriteUInt32(consts::BANDOLIERS_SIZE); - for (uint32 r = 0; r < EmuConstants::BANDOLIERS_COUNT; r++) + for (uint32 r = 0; r < EmuConstants::BANDOLIERS_SIZE; r++) { outapp->WriteString(emu->bandoliers[r].Name); - for (uint32 j = 0; j < EmuConstants::BANDOLIER_SIZE; ++j) + for (uint32 j = 0; j < EmuConstants::BANDOLIER_ITEM_COUNT; ++j) { outapp->WriteString(emu->bandoliers[r].Items[j].Name); outapp->WriteUInt32(emu->bandoliers[r].Items[j].ID); @@ -2382,11 +2382,11 @@ namespace RoF2 } } - for (uint32 r = 0; r < structs::MAX_PLAYER_BANDOLIER - EmuConstants::BANDOLIERS_COUNT; r++) + for (uint32 r = 0; r < consts::BANDOLIERS_SIZE - EmuConstants::BANDOLIERS_SIZE; r++) { outapp->WriteString(""); - for (uint32 j = 0; j < EmuConstants::BANDOLIER_SIZE; ++j) + for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) { outapp->WriteString(""); outapp->WriteUInt32(0); @@ -2394,9 +2394,9 @@ namespace RoF2 } } - outapp->WriteUInt32(structs::MAX_POTIONS_IN_BELT); + outapp->WriteUInt32(consts::POTION_BELT_ITEM_COUNT); - for (uint32 r = 0; r < EmuConstants::POTION_BELT_SIZE; r++) + for (uint32 r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT; r++) { outapp->WriteString(emu->potionbelt.Items[r].Name); outapp->WriteUInt32(emu->potionbelt.Items[r].ID); @@ -2410,7 +2410,7 @@ namespace RoF2 } } - for (uint32 r = 0; r < structs::MAX_POTIONS_IN_BELT - EmuConstants::POTION_BELT_SIZE; r++) + for (uint32 r = 0; r < consts::POTION_BELT_ITEM_COUNT - EmuConstants::POTION_BELT_ITEM_COUNT; r++) { outapp->WriteString(""); outapp->WriteUInt32(0); diff --git a/common/patches/rof2_constants.h b/common/patches/rof2_constants.h index ca59511a1..867574670 100644 --- a/common/patches/rof2_constants.h +++ b/common/patches/rof2_constants.h @@ -178,9 +178,10 @@ namespace RoF2 { static const uint16 ITEM_COMMON_SIZE = 6; static const uint16 ITEM_CONTAINER_SIZE = 255; // 255; (server max will be 255..unsure what actual client is - test) - static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances - static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance - static const uint32 POTION_BELT_SIZE = 5; + static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances + static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance + + static const size_t POTION_BELT_ITEM_COUNT = 5; static const size_t TEXT_LINK_BODY_LENGTH = 56; } diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 092d12d76..94f8bf4e7 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -97,11 +97,6 @@ static const uint32 MAX_PLAYER_TRIBUTES = 5; static const uint32 MAX_TRIBUTE_TIERS = 10; static const uint32 TRIBUTE_NONE = 0xFFFFFFFF; -static const uint32 MAX_PLAYER_BANDOLIER = 20; -static const uint32 MAX_PLAYER_BANDOLIER_ITEMS = 4; - -static const uint32 MAX_POTIONS_IN_BELT = 5; - static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_RAID_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_LEADERSHIP_AA_ARRAY = (MAX_GROUP_LEADERSHIP_AA_ARRAY+MAX_RAID_LEADERSHIP_AA_ARRAY); @@ -924,13 +919,13 @@ struct BandolierItem_Struct_Old struct Bandolier_Struct { char Name[1]; // Variable Length - BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; + BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; }; struct Bandolier_Struct_Old { char Name[32]; - BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; + BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; }; struct PotionBeltItem_Struct @@ -950,12 +945,12 @@ struct PotionBeltItem_Struct_Old struct PotionBelt_Struct { - PotionBeltItem_Struct Items[MAX_POTIONS_IN_BELT]; + PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT]; }; struct PotionBelt_Struct_Old { - PotionBeltItem_Struct_Old Items[MAX_POTIONS_IN_BELT]; + PotionBeltItem_Struct_Old Items[consts::POTION_BELT_ITEM_COUNT]; }; struct GroupLeadershipAA_Struct { @@ -1165,7 +1160,7 @@ union /*12949*/ uint32 aapoints; // Unspent AA points - Seen 1 /*12953*/ uint16 unknown_rof20; // /*12955*/ uint32 bandolier_count; // Seen 20 -/*12959*/ Bandolier_Struct bandoliers[MAX_PLAYER_BANDOLIER]; // [20] 740 bytes (Variable Name Sizes) - bandolier contents +/*12959*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [20] 740 bytes (Variable Name Sizes) - bandolier contents /*13699*/ uint32 potionbelt_count; // Seen 5 /*13703*/ PotionBelt_Struct potionbelt; // [5] 45 bytes potion belt - (Variable Name Sizes) /*13748*/ int32 unknown_rof21; // Seen -1 diff --git a/common/patches/rof_constants.h b/common/patches/rof_constants.h index 92c019bad..4fbf21d47 100644 --- a/common/patches/rof_constants.h +++ b/common/patches/rof_constants.h @@ -177,9 +177,10 @@ namespace RoF { static const uint16 ITEM_COMMON_SIZE = 6; static const uint16 ITEM_CONTAINER_SIZE = 255; // 255; (server max will be 255..unsure what actual client is - test) - static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances - static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance - static const uint32 POTION_BELT_SIZE = 5; + static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances + static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance + + static const size_t POTION_BELT_ITEM_COUNT = 5; static const size_t TEXT_LINK_BODY_LENGTH = 55; } diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 770dd250f..05cc5a346 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -97,11 +97,6 @@ static const uint32 MAX_PLAYER_TRIBUTES = 5; static const uint32 MAX_TRIBUTE_TIERS = 10; static const uint32 TRIBUTE_NONE = 0xFFFFFFFF; -static const uint32 MAX_PLAYER_BANDOLIER = 20; -static const uint32 MAX_PLAYER_BANDOLIER_ITEMS = 4; - -static const uint32 MAX_POTIONS_IN_BELT = 5; - static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_RAID_LEADERSHIP_AA_ARRAY = 16; static const uint32 MAX_LEADERSHIP_AA_ARRAY = (MAX_GROUP_LEADERSHIP_AA_ARRAY+MAX_RAID_LEADERSHIP_AA_ARRAY); @@ -908,13 +903,13 @@ struct BandolierItem_Struct_Old struct Bandolier_Struct { char Name[1]; // Variable Length - BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; + BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; }; struct Bandolier_Struct_Old { char Name[32]; - BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; + BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; }; struct PotionBeltItem_Struct @@ -934,12 +929,12 @@ struct PotionBeltItem_Struct_Old struct PotionBelt_Struct { - PotionBeltItem_Struct Items[MAX_POTIONS_IN_BELT]; + PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT]; }; struct PotionBelt_Struct_Old { - PotionBeltItem_Struct_Old Items[MAX_POTIONS_IN_BELT]; + PotionBeltItem_Struct_Old Items[consts::POTION_BELT_ITEM_COUNT]; }; struct GroupLeadershipAA_Struct { @@ -1149,7 +1144,7 @@ union /*12949*/ uint32 aapoints; // Unspent AA points - Seen 1 /*12953*/ uint16 unknown_rof20; // /*12955*/ uint32 bandolier_count; // Seen 20 -/*12959*/ Bandolier_Struct bandoliers[MAX_PLAYER_BANDOLIER]; // [20] 740 bytes (Variable Name Sizes) - bandolier contents +/*12959*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [20] 740 bytes (Variable Name Sizes) - bandolier contents /*13699*/ uint32 potionbelt_count; // Seen 5 /*13703*/ PotionBelt_Struct potionbelt; // [5] 45 bytes potion belt - (Variable Name Sizes) /*13748*/ int32 unknown_rof21; // Seen -1 diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index c2a6eeaaa..81cb49f1a 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -1612,14 +1612,14 @@ namespace SoD for (r = 0; r < 4; r++) { OUT_str(bandoliers[r].Name); uint32 k; - for (k = 0; k < structs::MAX_PLAYER_BANDOLIER_ITEMS; k++) { + for (k = 0; k < consts::BANDOLIER_ITEM_COUNT; k++) { OUT(bandoliers[r].Items[k].ID); OUT(bandoliers[r].Items[k].Icon); OUT_str(bandoliers[r].Items[k].Name); } } // OUT(unknown07444[5120]); - for (r = 0; r < structs::MAX_POTIONS_IN_BELT; r++) { + for (r = 0; r < consts::POTION_BELT_ITEM_COUNT; r++) { OUT(potionbelt.Items[r].ID); OUT(potionbelt.Items[r].Icon); OUT_str(potionbelt.Items[r].Name); diff --git a/common/patches/sod_constants.h b/common/patches/sod_constants.h index 7731d1d1f..6b587b7c4 100644 --- a/common/patches/sod_constants.h +++ b/common/patches/sod_constants.h @@ -174,9 +174,10 @@ namespace SoD { static const uint16 ITEM_COMMON_SIZE = 5; static const uint16 ITEM_CONTAINER_SIZE = 10; - static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances - static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance - static const uint32 POTION_BELT_SIZE = 5; + static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances + static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance + + static const size_t POTION_BELT_ITEM_COUNT = 5; static const size_t TEXT_LINK_BODY_LENGTH = 50; } diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index 18f17ce62..f929ec744 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -676,9 +676,6 @@ struct Disciplines_Struct { }; static const uint32 MAX_PLAYER_TRIBUTES = 5; -static const uint32 MAX_PLAYER_BANDOLIER = 20; -static const uint32 MAX_PLAYER_BANDOLIER_ITEMS = 4; -static const uint32 MAX_POTIONS_IN_BELT = 5; static const uint32 TRIBUTE_NONE = 0xFFFFFFFF; struct Tribute_Struct { @@ -707,7 +704,7 @@ struct BandolierItem_Struct struct Bandolier_Struct { char Name[32]; - BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; + BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; }; //len = 72 @@ -721,7 +718,7 @@ struct PotionBeltItem_Struct //len = 288 struct PotionBelt_Struct { - PotionBeltItem_Struct Items[MAX_POTIONS_IN_BELT]; + PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT]; }; static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; @@ -941,7 +938,7 @@ struct PlayerProfile_Struct /*08288*/ uint32 aapoints_spent; // Number of spent AA points /*08292*/ uint32 aapoints; // Unspent AA points /*08296*/ uint8 unknown06160[4]; -/*08300*/ Bandolier_Struct bandoliers[MAX_PLAYER_BANDOLIER]; // [6400] bandolier contents +/*08300*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [6400] bandolier contents /*14700*/ PotionBelt_Struct potionbelt; // [360] potion belt 72 extra octets by adding 1 more belt slot /*15060*/ uint8 unknown12852[8]; /*15068*/ uint32 available_slots; diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index cf19582b0..01b6abb55 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1270,14 +1270,14 @@ namespace SoF for (r = 0; r < 4; r++) { OUT_str(bandoliers[r].Name); uint32 k; - for (k = 0; k < structs::MAX_PLAYER_BANDOLIER_ITEMS; k++) { + for (k = 0; k < consts::BANDOLIER_ITEM_COUNT; k++) { OUT(bandoliers[r].Items[k].ID); OUT(bandoliers[r].Items[k].Icon); OUT_str(bandoliers[r].Items[k].Name); } } // OUT(unknown07444[5120]); - for (r = 0; r < structs::MAX_POTIONS_IN_BELT; r++) { + for (r = 0; r < consts::POTION_BELT_ITEM_COUNT; r++) { OUT(potionbelt.Items[r].ID); OUT(potionbelt.Items[r].Icon); OUT_str(potionbelt.Items[r].Name); diff --git a/common/patches/sof_constants.h b/common/patches/sof_constants.h index b20e57196..f5376cd13 100644 --- a/common/patches/sof_constants.h +++ b/common/patches/sof_constants.h @@ -174,9 +174,10 @@ namespace SoF { static const uint16 ITEM_COMMON_SIZE = 5; static const uint16 ITEM_CONTAINER_SIZE = 10; - static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances - static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance - static const uint32 POTION_BELT_SIZE = 5; + static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances + static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance + + static const size_t POTION_BELT_ITEM_COUNT = 5; static const size_t TEXT_LINK_BODY_LENGTH = 50; } diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index 33773e91e..1510ded59 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -653,9 +653,6 @@ struct Disciplines_Struct { }; static const uint32 MAX_PLAYER_TRIBUTES = 5; -static const uint32 MAX_PLAYER_BANDOLIER = 20; -static const uint32 MAX_PLAYER_BANDOLIER_ITEMS = 4; -static const uint32 MAX_POTIONS_IN_BELT = 5; static const uint32 TRIBUTE_NONE = 0xFFFFFFFF; struct Tribute_Struct { @@ -684,7 +681,7 @@ struct BandolierItem_Struct struct Bandolier_Struct { char Name[32]; - BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; + BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; }; //len = 72 @@ -698,7 +695,7 @@ struct PotionBeltItem_Struct //len = 288 struct PotionBelt_Struct { - PotionBeltItem_Struct Items[MAX_POTIONS_IN_BELT]; + PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT]; }; static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; @@ -917,7 +914,7 @@ struct PlayerProfile_Struct //23576 Octets /*08288*/ uint32 aapoints_spent; // Number of spent AA points /*08292*/ uint32 aapoints; // Unspent AA points /*08296*/ uint8 unknown06160[4]; -/*08300*/ Bandolier_Struct bandoliers[MAX_PLAYER_BANDOLIER]; // [6400] bandolier contents +/*08300*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [6400] bandolier contents /*14700*/ PotionBelt_Struct potionbelt; // [360] potion belt 72 extra octets by adding 1 more belt slot /*15060*/ uint8 unknown12852[8]; /*15068*/ uint32 available_slots; diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index 7528a378d..b242a48b7 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -923,17 +923,17 @@ namespace Titanium OUT(aapoints_spent); OUT(aapoints); // OUT(unknown06160[4]); - for (r = 0; r < structs::MAX_PLAYER_BANDOLIER; r++) { + for (r = 0; r < consts::BANDOLIERS_SIZE; r++) { OUT_str(bandoliers[r].Name); uint32 k; - for (k = 0; k < structs::MAX_PLAYER_BANDOLIER_ITEMS; k++) { + for (k = 0; k < consts::BANDOLIER_ITEM_COUNT; k++) { OUT(bandoliers[r].Items[k].ID); OUT(bandoliers[r].Items[k].Icon); OUT_str(bandoliers[r].Items[k].Name); } } // OUT(unknown07444[5120]); - for (r = 0; r < structs::MAX_PLAYER_BANDOLIER_ITEMS; r++) { + for (r = 0; r < consts::POTION_BELT_ITEM_COUNT; r++) { OUT(potionbelt.Items[r].ID); OUT(potionbelt.Items[r].Icon); OUT_str(potionbelt.Items[r].Name); diff --git a/common/patches/titanium_constants.h b/common/patches/titanium_constants.h index 15338e220..61da2ba59 100644 --- a/common/patches/titanium_constants.h +++ b/common/patches/titanium_constants.h @@ -173,9 +173,10 @@ namespace Titanium { static const uint16 ITEM_COMMON_SIZE = 5; static const uint16 ITEM_CONTAINER_SIZE = 10; - static const uint32 BANDOLIERS_COUNT = 4; // count = number of bandolier instances - static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance - static const uint32 POTION_BELT_SIZE = 4; + static const size_t BANDOLIERS_SIZE = 4; // number of bandolier instances + static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance + + static const size_t POTION_BELT_ITEM_COUNT = 4; static const size_t TEXT_LINK_BODY_LENGTH = 45; } diff --git a/common/patches/titanium_structs.h b/common/patches/titanium_structs.h index 8286d125c..9a165a33d 100644 --- a/common/patches/titanium_structs.h +++ b/common/patches/titanium_structs.h @@ -586,8 +586,6 @@ struct Disciplines_Struct { }; static const uint32 MAX_PLAYER_TRIBUTES = 5; -static const uint32 MAX_PLAYER_BANDOLIER = 4; -static const uint32 MAX_PLAYER_BANDOLIER_ITEMS = 4; static const uint32 TRIBUTE_NONE = 0xFFFFFFFF; struct Tribute_Struct { uint32 tribute; @@ -615,7 +613,7 @@ struct BandolierItem_Struct struct Bandolier_Struct { char Name[32]; - BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; + BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; }; //len = 72 @@ -629,7 +627,7 @@ struct PotionBeltItem_Struct //len = 288 struct PotionBelt_Struct { - PotionBeltItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; + PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT]; }; static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; @@ -833,7 +831,7 @@ struct PlayerProfile_Struct /*06152*/ uint32 aapoints_spent; // Number of spent AA points /*06156*/ uint32 aapoints; // Unspent AA points /*06160*/ uint8 unknown06160[4]; -/*06164*/ Bandolier_Struct bandoliers[MAX_PLAYER_BANDOLIER]; // bandolier contents +/*06164*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // bandolier contents /*07444*/ uint8 unknown07444[5120]; /*12564*/ PotionBelt_Struct potionbelt; // potion belt /*12852*/ uint8 unknown12852[8]; diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 334a6dc88..5827c652c 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -1874,14 +1874,14 @@ namespace UF for (r = 0; r < 4; r++) { OUT_str(bandoliers[r].Name); uint32 k; - for (k = 0; k < structs::MAX_PLAYER_BANDOLIER_ITEMS; k++) { + for (k = 0; k < consts::BANDOLIER_ITEM_COUNT; k++) { OUT(bandoliers[r].Items[k].ID); OUT(bandoliers[r].Items[k].Icon); OUT_str(bandoliers[r].Items[k].Name); } } // OUT(unknown07444[5120]); - for (r = 0; r < structs::MAX_POTIONS_IN_BELT; r++) { + for (r = 0; r < consts::POTION_BELT_ITEM_COUNT; r++) { OUT(potionbelt.Items[r].ID); OUT(potionbelt.Items[r].Icon); OUT_str(potionbelt.Items[r].Name); diff --git a/common/patches/uf_constants.h b/common/patches/uf_constants.h index 70b89df18..fc14af63f 100644 --- a/common/patches/uf_constants.h +++ b/common/patches/uf_constants.h @@ -174,9 +174,10 @@ namespace UF { static const uint16 ITEM_COMMON_SIZE = 5; static const uint16 ITEM_CONTAINER_SIZE = 10; - static const uint32 BANDOLIERS_COUNT = 20; // count = number of bandolier instances - static const uint32 BANDOLIER_SIZE = 4; // size = number of equipment slots in bandolier instance - static const uint32 POTION_BELT_SIZE = 5; + static const size_t BANDOLIERS_SIZE = 20; // number of bandolier instances + static const size_t BANDOLIER_ITEM_COUNT = 4; // number of equipment slots in bandolier instance + + static const size_t POTION_BELT_ITEM_COUNT = 5; static const size_t TEXT_LINK_BODY_LENGTH = 50; } diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index 762419a67..f33ab7b4c 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -722,9 +722,6 @@ struct Disciplines_Struct { }; static const uint32 MAX_PLAYER_TRIBUTES = 5; -static const uint32 MAX_PLAYER_BANDOLIER = 20; -static const uint32 MAX_PLAYER_BANDOLIER_ITEMS = 4; -static const uint32 MAX_POTIONS_IN_BELT = 5; static const uint32 TRIBUTE_NONE = 0xFFFFFFFF; struct Tribute_Struct { @@ -753,7 +750,7 @@ struct BandolierItem_Struct struct Bandolier_Struct { char Name[32]; - BandolierItem_Struct Items[MAX_PLAYER_BANDOLIER_ITEMS]; + BandolierItem_Struct Items[consts::BANDOLIER_ITEM_COUNT]; }; //len = 72 @@ -767,7 +764,7 @@ struct PotionBeltItem_Struct //len = 288 struct PotionBelt_Struct { - PotionBeltItem_Struct Items[MAX_POTIONS_IN_BELT]; + PotionBeltItem_Struct Items[consts::POTION_BELT_ITEM_COUNT]; }; static const uint32 MAX_GROUP_LEADERSHIP_AA_ARRAY = 16; @@ -990,7 +987,7 @@ struct PlayerProfile_Struct /*11236*/ uint32 aapoints_spent; // Number of spent AA points /*11240*/ uint32 aapoints; // Unspent AA points /*11244*/ uint8 unknown11244[4]; -/*11248*/ Bandolier_Struct bandoliers[MAX_PLAYER_BANDOLIER]; // [6400] bandolier contents +/*11248*/ Bandolier_Struct bandoliers[consts::BANDOLIERS_SIZE]; // [6400] bandolier contents /*17648*/ PotionBelt_Struct potionbelt; // [360] potion belt 72 extra octets by adding 1 more belt slot /*18008*/ uint8 unknown18008[8]; /*18016*/ uint32 available_slots; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 8a95de0f4..d409e270a 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1179,8 +1179,8 @@ bool ZoneDatabase::LoadCharacterBandolier(uint32 character_id, PlayerProfile_Str { std::string query = StringFormat("SELECT `bandolier_id`, `bandolier_slot`, `item_id`, `icon`, `bandolier_name` FROM `character_bandolier` WHERE `id` = %u LIMIT 16", character_id); auto results = database.QueryDatabase(query); int i = 0; int r = 0; int si = 0; - for (i = 0; i < EmuConstants::BANDOLIERS_COUNT; i++) - for (int si = 0; si < EmuConstants::BANDOLIER_SIZE; si++) + for (i = 0; i < EmuConstants::BANDOLIERS_SIZE; i++) + for (int si = 0; si < EmuConstants::BANDOLIER_ITEM_COUNT; si++) pp->bandoliers[i].Items[si].Icon = 0; for (auto row = results.begin(); row != results.end(); ++row) { @@ -1218,7 +1218,7 @@ bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struc { std::string query = StringFormat("SELECT `potion_id`, `item_id`, `icon` FROM `character_potionbelt` WHERE `id` = %u LIMIT 4", character_id); auto results = database.QueryDatabase(query); int i = 0; - for (i = 0; i < EmuConstants::POTION_BELT_SIZE; i++){ + for (i = 0; i < EmuConstants::POTION_BELT_ITEM_COUNT; i++){ pp->potionbelt.Items[i].Icon = 0; pp->potionbelt.Items[i].ID = 0; strncpy(pp->potionbelt.Items[i].Name, "\0", 1); From dedbb3f6c8546e9920940d4b5e79bdb784355dbf Mon Sep 17 00:00:00 2001 From: Uleat Date: Sat, 14 Feb 2015 20:52:20 -0500 Subject: [PATCH 090/114] Implemented higher bandolier and potion belt counts --- changelog.txt | 1 + common/eq_dictionary.cpp | 63 ------------------------------- common/eq_dictionary.h | 11 ++---- common/patches/rof.cpp | 39 ++++++++----------- common/patches/rof2.cpp | 75 ++++++++++++++++--------------------- common/patches/sod.cpp | 32 +++++++++++++--- common/patches/sof.cpp | 32 +++++++++++++--- common/patches/titanium.cpp | 30 +++++++++++++-- common/patches/uf.cpp | 32 +++++++++++++--- zone/client_packet.cpp | 5 +-- zone/zonedb.cpp | 47 ++++++++++++++--------- 11 files changed, 188 insertions(+), 179 deletions(-) diff --git a/changelog.txt b/changelog.txt index 6d50f235e..c04647bbc 100644 --- a/changelog.txt +++ b/changelog.txt @@ -6,6 +6,7 @@ demonstar55: (RoF2) Send the bard focus effects, note custom servers will need t == 02/14/2015 == Trevius: (RoF2) Bazaar is now partially functional. RoF2 clients can start/end trader mode and other clients can purchase from them. No other functionality yet. +Uleat: Implemented higher bandolier and potion belt counts for clients that support it..you will still need to activate them through the proper aa's, etc... == 02/12/2015 == Akkadius: Implement zone based gravity, required SQL DB change diff --git a/common/eq_dictionary.cpp b/common/eq_dictionary.cpp index a87ae569a..a6a0d806d 100644 --- a/common/eq_dictionary.cpp +++ b/common/eq_dictionary.cpp @@ -919,66 +919,3 @@ bool EQLimits::CoinHasWeight(ClientVersion clientVersion) return local[static_cast(ValidateMobClientVersion(clientVersion))]; } - -uint32 EQLimits::BandoliersCount(ClientVersion clientVersion) -{ - static const uint32 local[CLIENT_VERSION_COUNT] = { -/*Unknown*/ NOT_USED, -/*62*/ NOT_USED, -/*Titanium*/ EmuConstants::BANDOLIERS_SIZE, -/*SoF*/ EmuConstants::BANDOLIERS_SIZE, -/*SoD*/ EmuConstants::BANDOLIERS_SIZE, -/*Underfoot*/ EmuConstants::BANDOLIERS_SIZE, -/*RoF*/ EmuConstants::BANDOLIERS_SIZE, -/*RoF2*/ EmuConstants::BANDOLIERS_SIZE, - -/*NPC*/ NOT_USED, -/*Merc*/ NOT_USED, -/*Bot*/ NOT_USED, -/*Pet*/ NOT_USED - }; - - return local[static_cast(ValidateMobClientVersion(clientVersion))]; -} - -uint32 EQLimits::BandolierSize(ClientVersion clientVersion) -{ - static const uint32 local[CLIENT_VERSION_COUNT] = { -/*Unknown*/ NOT_USED, -/*62*/ NOT_USED, -/*Titanium*/ EmuConstants::BANDOLIER_ITEM_COUNT, -/*SoF*/ EmuConstants::BANDOLIER_ITEM_COUNT, -/*SoD*/ EmuConstants::BANDOLIER_ITEM_COUNT, -/*Underfoot*/ EmuConstants::BANDOLIER_ITEM_COUNT, -/*RoF*/ EmuConstants::BANDOLIER_ITEM_COUNT, -/*RoF2*/ EmuConstants::BANDOLIER_ITEM_COUNT, - -/*NPC*/ NOT_USED, -/*Merc*/ NOT_USED, -/*Bot*/ NOT_USED, -/*Pet*/ NOT_USED - }; - - return local[static_cast(ValidateMobClientVersion(clientVersion))]; -} - -uint32 EQLimits::PotionBeltSize(ClientVersion clientVersion) -{ - static const uint32 local[CLIENT_VERSION_COUNT] = { -/*Unknown*/ NOT_USED, -/*62*/ NOT_USED, -/*Titanium*/ EmuConstants::POTION_BELT_ITEM_COUNT, -/*SoF*/ EmuConstants::POTION_BELT_ITEM_COUNT, -/*SoD*/ EmuConstants::POTION_BELT_ITEM_COUNT, -/*Underfoot*/ EmuConstants::POTION_BELT_ITEM_COUNT, -/*RoF*/ EmuConstants::POTION_BELT_ITEM_COUNT, -/*RoF2*/ EmuConstants::POTION_BELT_ITEM_COUNT, - -/*NPC*/ NOT_USED, -/*Merc*/ NOT_USED, -/*Bot*/ NOT_USED, -/*Pet*/ NOT_USED - }; - - return local[static_cast(ValidateMobClientVersion(clientVersion))]; -} diff --git a/common/eq_dictionary.h b/common/eq_dictionary.h index 501fd52cf..16586f356 100644 --- a/common/eq_dictionary.h +++ b/common/eq_dictionary.h @@ -142,11 +142,11 @@ public: static const uint16 ITEM_CONTAINER_SIZE = Titanium::consts::ITEM_CONTAINER_SIZE; // BANDOLIERS_SIZE sets maximum limit..active limit will need to be handled by the appropriate AA or spell (or item?) - static const size_t BANDOLIERS_SIZE = Titanium::consts::BANDOLIERS_SIZE; // number of bandolier instances - static const size_t BANDOLIER_ITEM_COUNT = Titanium::consts::BANDOLIER_ITEM_COUNT; // number of equipment slots in bandolier instance + static const size_t BANDOLIERS_SIZE = RoF2::consts::BANDOLIERS_SIZE; // number of bandolier instances + static const size_t BANDOLIER_ITEM_COUNT = RoF2::consts::BANDOLIER_ITEM_COUNT; // number of equipment slots in bandolier instance // POTION_BELT_SIZE sets maximum limit..active limit will need to be handled by the appropriate AA or spell (or item?) - static const size_t POTION_BELT_ITEM_COUNT = Titanium::consts::POTION_BELT_ITEM_COUNT; + static const size_t POTION_BELT_ITEM_COUNT = RoF2::consts::POTION_BELT_ITEM_COUNT; static const size_t TEXT_LINK_BODY_LENGTH = RoF2::consts::TEXT_LINK_BODY_LENGTH; }; @@ -186,11 +186,6 @@ public: // player profile static bool CoinHasWeight(ClientVersion clientVersion); - - static uint32 BandoliersCount(ClientVersion clientVersion); - static uint32 BandolierSize(ClientVersion clientVersion); - - static uint32 PotionBeltSize(ClientVersion clientVersion); }; #endif /* EQ_DICTIONARY_H */ diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 86382e7b5..ed943db97 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -2288,32 +2288,25 @@ namespace RoF outapp->WriteUInt32(consts::BANDOLIERS_SIZE); - for (uint32 r = 0; r < EmuConstants::BANDOLIERS_SIZE; r++) - { + // Copy bandoliers where server and client indexes converge + for (uint32 r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) { outapp->WriteString(emu->bandoliers[r].Name); - - for (uint32 j = 0; j < EmuConstants::BANDOLIER_ITEM_COUNT; ++j) - { + for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) { // Will need adjusting if 'server != client' is ever true outapp->WriteString(emu->bandoliers[r].Items[j].Name); outapp->WriteUInt32(emu->bandoliers[r].Items[j].ID); - if (emu->bandoliers[r].Items[j].Icon) - { + if (emu->bandoliers[r].Items[j].Icon) { outapp->WriteSInt32(emu->bandoliers[r].Items[j].Icon); } - else - { + else { // If no icon, it must send -1 or Treasure Chest Icon (836) is displayed outapp->WriteSInt32(-1); } } } - - for (uint32 r = 0; r < consts::BANDOLIERS_SIZE - EmuConstants::BANDOLIERS_SIZE; r++) - { + // Nullify bandoliers where server and client indexes diverge, with a client bias + for (uint32 r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) { outapp->WriteString(""); - - for (uint32 j = 0; j < EmuConstants::BANDOLIER_ITEM_COUNT; ++j) - { + for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) { // Will need adjusting if 'server != client' is ever true outapp->WriteString(""); outapp->WriteUInt32(0); outapp->WriteSInt32(-1); @@ -2322,22 +2315,20 @@ namespace RoF outapp->WriteUInt32(consts::POTION_BELT_ITEM_COUNT); - for (uint32 r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT; r++) - { + // Copy potion belt where server and client indexes converge + for (uint32 r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) { outapp->WriteString(emu->potionbelt.Items[r].Name); outapp->WriteUInt32(emu->potionbelt.Items[r].ID); - if (emu->potionbelt.Items[r].Icon) - { + if (emu->potionbelt.Items[r].Icon) { outapp->WriteSInt32(emu->potionbelt.Items[r].Icon); } - else - { + else { + // If no icon, it must send -1 or Treasure Chest Icon (836) is displayed outapp->WriteSInt32(-1); } } - - for (uint32 r = 0; r < consts::POTION_BELT_ITEM_COUNT - EmuConstants::POTION_BELT_ITEM_COUNT; r++) - { + // Nullify potion belt where server and client indexes diverge, with a client bias + for (uint32 r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) { outapp->WriteString(""); outapp->WriteUInt32(0); outapp->WriteSInt32(-1); diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index ba06c2742..e6f4775ac 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -2362,56 +2362,47 @@ namespace RoF2 outapp->WriteUInt32(consts::BANDOLIERS_SIZE); - for (uint32 r = 0; r < EmuConstants::BANDOLIERS_SIZE; r++) - { + // Copy bandoliers where server and client indexes converge + for (uint32 r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) { outapp->WriteString(emu->bandoliers[r].Name); - - for (uint32 j = 0; j < EmuConstants::BANDOLIER_ITEM_COUNT; ++j) - { + for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) { // Will need adjusting if 'server != client' is ever true outapp->WriteString(emu->bandoliers[r].Items[j].Name); outapp->WriteUInt32(emu->bandoliers[r].Items[j].ID); - if (emu->bandoliers[r].Items[j].Icon) - { + if (emu->bandoliers[r].Items[j].Icon) { outapp->WriteSInt32(emu->bandoliers[r].Items[j].Icon); - } - else - { - // If no icon, it must send -1 or Treasure Chest Icon (836) is displayed - outapp->WriteSInt32(-1); - } - } - } - - for (uint32 r = 0; r < consts::BANDOLIERS_SIZE - EmuConstants::BANDOLIERS_SIZE; r++) - { - outapp->WriteString(""); - - for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) - { - outapp->WriteString(""); - outapp->WriteUInt32(0); - outapp->WriteSInt32(-1); - } - } - + } + else { + // If no icon, it must send -1 or Treasure Chest Icon (836) is displayed + outapp->WriteSInt32(-1); + } + } + } + // Nullify bandoliers where server and client indexes diverge, with a client bias + for (uint32 r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) { + outapp->WriteString(""); + for (uint32 j = 0; j < consts::BANDOLIER_ITEM_COUNT; ++j) { // Will need adjusting if 'server != client' is ever true + outapp->WriteString(""); + outapp->WriteUInt32(0); + outapp->WriteSInt32(-1); + } + } + outapp->WriteUInt32(consts::POTION_BELT_ITEM_COUNT); - - for (uint32 r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT; r++) - { + + // Copy potion belt where server and client indexes converge + for (uint32 r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) { outapp->WriteString(emu->potionbelt.Items[r].Name); outapp->WriteUInt32(emu->potionbelt.Items[r].ID); - if (emu->potionbelt.Items[r].Icon) - { + if (emu->potionbelt.Items[r].Icon) { outapp->WriteSInt32(emu->potionbelt.Items[r].Icon); - } - else - { - outapp->WriteSInt32(-1); - } - } - - for (uint32 r = 0; r < consts::POTION_BELT_ITEM_COUNT - EmuConstants::POTION_BELT_ITEM_COUNT; r++) - { + } + else { + // If no icon, it must send -1 or Treasure Chest Icon (836) is displayed + outapp->WriteSInt32(-1); + } + } + // Nullify potion belt where server and client indexes diverge, with a client bias + for (uint32 r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) { outapp->WriteString(""); outapp->WriteUInt32(0); outapp->WriteSInt32(-1); diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index 81cb49f1a..b1ae218ed 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -1606,26 +1606,46 @@ namespace SoD OUT(endurance); OUT(aapoints_spent); OUT(aapoints); + // OUT(unknown06160[4]); - //NOTE: new client supports 20 bandoliers, our internal rep - //only supports 4.. - for (r = 0; r < 4; r++) { + + // Copy bandoliers where server and client indexes converge + for (r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) { OUT_str(bandoliers[r].Name); - uint32 k; - for (k = 0; k < consts::BANDOLIER_ITEM_COUNT; k++) { + for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true OUT(bandoliers[r].Items[k].ID); OUT(bandoliers[r].Items[k].Icon); OUT_str(bandoliers[r].Items[k].Name); } } + // Nullify bandoliers where server and client indexes diverge, with a client bias + for (r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) { + eq->bandoliers[r].Name[0] = '\0'; + for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true + eq->bandoliers[r].Items[k].ID = 0; + eq->bandoliers[r].Items[k].Icon = 0; + eq->bandoliers[r].Items[k].Name[0] = '\0'; + } + } + // OUT(unknown07444[5120]); - for (r = 0; r < consts::POTION_BELT_ITEM_COUNT; r++) { + + // Copy potion belt where server and client indexes converge + for (r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) { OUT(potionbelt.Items[r].ID); OUT(potionbelt.Items[r].Icon); OUT_str(potionbelt.Items[r].Name); } + // Nullify potion belt where server and client indexes diverge, with a client bias + for (r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) { + eq->potionbelt.Items[r].ID = 0; + eq->potionbelt.Items[r].Icon = 0; + eq->potionbelt.Items[r].Name[0] = '\0'; + } + // OUT(unknown12852[8]); // OUT(unknown12864[76]); + OUT_str(name); OUT_str(last_name); OUT(guild_id); diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index 01b6abb55..4ba534ac7 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1264,26 +1264,46 @@ namespace SoF OUT(endurance); OUT(aapoints_spent); OUT(aapoints); + // OUT(unknown06160[4]); - //NOTE: new client supports 20 bandoliers, our internal rep - //only supports 4.. - for (r = 0; r < 4; r++) { + + // Copy bandoliers where server and client indexes converge + for (r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) { OUT_str(bandoliers[r].Name); - uint32 k; - for (k = 0; k < consts::BANDOLIER_ITEM_COUNT; k++) { + for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true OUT(bandoliers[r].Items[k].ID); OUT(bandoliers[r].Items[k].Icon); OUT_str(bandoliers[r].Items[k].Name); } } + // Nullify bandoliers where server and client indexes diverge, with a client bias + for (r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) { + eq->bandoliers[r].Name[0] = '\0'; + for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true + eq->bandoliers[r].Items[k].ID = 0; + eq->bandoliers[r].Items[k].Icon = 0; + eq->bandoliers[r].Items[k].Name[0] = '\0'; + } + } + // OUT(unknown07444[5120]); - for (r = 0; r < consts::POTION_BELT_ITEM_COUNT; r++) { + + // Copy potion belt where server and client indexes converge + for (r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) { OUT(potionbelt.Items[r].ID); OUT(potionbelt.Items[r].Icon); OUT_str(potionbelt.Items[r].Name); } + // Nullify potion belt where server and client indexes diverge, with a client bias + for (r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) { + eq->potionbelt.Items[r].ID = 0; + eq->potionbelt.Items[r].Icon = 0; + eq->potionbelt.Items[r].Name[0] = '\0'; + } + // OUT(unknown12852[8]); // OUT(unknown12864[76]); + OUT_str(name); OUT_str(last_name); OUT(guild_id); diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index b242a48b7..d048f0e5d 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -922,24 +922,46 @@ namespace Titanium OUT(endurance); OUT(aapoints_spent); OUT(aapoints); + // OUT(unknown06160[4]); - for (r = 0; r < consts::BANDOLIERS_SIZE; r++) { + + // Copy bandoliers where server and client indexes converge + for (r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) { OUT_str(bandoliers[r].Name); - uint32 k; - for (k = 0; k < consts::BANDOLIER_ITEM_COUNT; k++) { + for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true OUT(bandoliers[r].Items[k].ID); OUT(bandoliers[r].Items[k].Icon); OUT_str(bandoliers[r].Items[k].Name); } } + // Nullify bandoliers where server and client indexes diverge, with a client bias + for (r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) { + eq->bandoliers[r].Name[0] = '\0'; + for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true + eq->bandoliers[r].Items[k].ID = 0; + eq->bandoliers[r].Items[k].Icon = 0; + eq->bandoliers[r].Items[k].Name[0] = '\0'; + } + } + // OUT(unknown07444[5120]); - for (r = 0; r < consts::POTION_BELT_ITEM_COUNT; r++) { + + // Copy potion belt where server and client indexes converge + for (r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) { OUT(potionbelt.Items[r].ID); OUT(potionbelt.Items[r].Icon); OUT_str(potionbelt.Items[r].Name); } + // Nullify potion belt where server and client indexes diverge, with a client bias + for (r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) { + eq->potionbelt.Items[r].ID = 0; + eq->potionbelt.Items[r].Icon = 0; + eq->potionbelt.Items[r].Name[0] = '\0'; + } + // OUT(unknown12852[8]); // OUT(unknown12864[76]); + OUT_str(name); OUT_str(last_name); OUT(guild_id); diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 5827c652c..991b35aa4 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -1868,26 +1868,46 @@ namespace UF OUT(endurance); OUT(aapoints_spent); OUT(aapoints); + // OUT(unknown06160[4]); - //NOTE: new client supports 20 bandoliers, our internal rep - //only supports 4.. - for (r = 0; r < 4; r++) { + + // Copy bandoliers where server and client indexes converge + for (r = 0; r < EmuConstants::BANDOLIERS_SIZE && r < consts::BANDOLIERS_SIZE; ++r) { OUT_str(bandoliers[r].Name); - uint32 k; - for (k = 0; k < consts::BANDOLIER_ITEM_COUNT; k++) { + for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true OUT(bandoliers[r].Items[k].ID); OUT(bandoliers[r].Items[k].Icon); OUT_str(bandoliers[r].Items[k].Name); } } + // Nullify bandoliers where server and client indexes diverge, with a client bias + for (r = EmuConstants::BANDOLIERS_SIZE; r < consts::BANDOLIERS_SIZE; ++r) { + eq->bandoliers[r].Name[0] = '\0'; + for (uint32 k = 0; k < consts::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true + eq->bandoliers[r].Items[k].ID = 0; + eq->bandoliers[r].Items[k].Icon = 0; + eq->bandoliers[r].Items[k].Name[0] = '\0'; + } + } + // OUT(unknown07444[5120]); - for (r = 0; r < consts::POTION_BELT_ITEM_COUNT; r++) { + + // Copy potion belt where server and client indexes converge + for (r = 0; r < EmuConstants::POTION_BELT_ITEM_COUNT && r < consts::POTION_BELT_ITEM_COUNT; ++r) { OUT(potionbelt.Items[r].ID); OUT(potionbelt.Items[r].Icon); OUT_str(potionbelt.Items[r].Name); } + // Nullify potion belt where server and client indexes diverge, with a client bias + for (r = EmuConstants::POTION_BELT_ITEM_COUNT; r < consts::POTION_BELT_ITEM_COUNT; ++r) { + eq->potionbelt.Items[r].ID = 0; + eq->potionbelt.Items[r].Icon = 0; + eq->potionbelt.Items[r].Name[0] = '\0'; + } + // OUT(unknown12852[8]); // OUT(unknown12864[76]); + OUT_str(name); OUT_str(last_name); OUT(guild_id); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 97b927352..3fa28c891 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -3171,7 +3171,6 @@ void Client::Handle_OP_AutoFire(const EQApplicationPacket *app) void Client::Handle_OP_Bandolier(const EQApplicationPacket *app) { - // Although there are three different structs for OP_Bandolier, they are all the same size. // if (app->size != sizeof(BandolierCreate_Struct)) { @@ -3195,7 +3194,7 @@ void Client::Handle_OP_Bandolier(const EQApplicationPacket *app) SetBandolier(app); break; default: - Log.Out(Logs::General, Logs::None, "Uknown Bandolier action %i", bs->Action); + Log.Out(Logs::General, Logs::None, "Unknown Bandolier action %i", bs->Action); break; } } @@ -10452,7 +10451,7 @@ void Client::Handle_OP_PotionBelt(const EQApplicationPacket *app) else { m_pp.potionbelt.Items[mptbs->SlotNumber].ID = 0; m_pp.potionbelt.Items[mptbs->SlotNumber].Icon = 0; - strncpy(m_pp.potionbelt.Items[mptbs->SlotNumber].Name, "\0", 1); + m_pp.potionbelt.Items[mptbs->SlotNumber].Name[0] = '\0'; } } diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index d409e270a..d9e564e29 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1177,20 +1177,37 @@ bool ZoneDatabase::LoadCharacterMaterialColor(uint32 character_id, PlayerProfile bool ZoneDatabase::LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp) { - std::string query = StringFormat("SELECT `bandolier_id`, `bandolier_slot`, `item_id`, `icon`, `bandolier_name` FROM `character_bandolier` WHERE `id` = %u LIMIT 16", character_id); + std::string query = StringFormat("SELECT `bandolier_id`, `bandolier_slot`, `item_id`, `icon`, `bandolier_name` FROM `character_bandolier` WHERE `id` = %u LIMIT %u", + character_id, EmuConstants::BANDOLIERS_SIZE); auto results = database.QueryDatabase(query); int i = 0; int r = 0; int si = 0; - for (i = 0; i < EmuConstants::BANDOLIERS_SIZE; i++) - for (int si = 0; si < EmuConstants::BANDOLIER_ITEM_COUNT; si++) + for (i = 0; i < EmuConstants::BANDOLIERS_SIZE; i++) { + pp->bandoliers[i].Name[0] = '\0'; + for (int si = 0; si < EmuConstants::BANDOLIER_ITEM_COUNT; si++) { + pp->bandoliers[i].Items[si].ID = 0; pp->bandoliers[i].Items[si].Icon = 0; + pp->bandoliers[i].Items[si].Name[0] = '\0'; + } + } for (auto row = results.begin(); row != results.end(); ++row) { r = 0; i = atoi(row[r]); /* Bandolier ID */ r++; si = atoi(row[r]); /* Bandolier Slot */ r++; - pp->bandoliers[i].Items[si].ID = atoi(row[r]); r++; - pp->bandoliers[i].Items[si].Icon = atoi(row[r]); r++; + + const Item_Struct* item_data = database.GetItem(atoi(row[r])); + if (item_data) { + pp->bandoliers[i].Items[si].ID = item_data->ID; r++; + pp->bandoliers[i].Items[si].Icon = atoi(row[r]); r++; // Must use db value in case an Ornamentation is assigned + strncpy(pp->bandoliers[i].Items[si].Name, item_data->Name, 64); + } + else { + pp->bandoliers[i].Items[si].ID = 0; r++; + pp->bandoliers[i].Items[si].Icon = 0; r++; + pp->bandoliers[i].Items[si].Name[0] = '\0'; + } strcpy(pp->bandoliers[i].Name, row[r]); r++; - si++; + + si++; // What is this for!? } return true; } @@ -1216,25 +1233,21 @@ bool ZoneDatabase::LoadCharacterTribute(uint32 character_id, PlayerProfile_Struc bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp) { - std::string query = StringFormat("SELECT `potion_id`, `item_id`, `icon` FROM `character_potionbelt` WHERE `id` = %u LIMIT 4", character_id); + std::string query = StringFormat("SELECT `potion_id`, `item_id`, `icon` FROM `character_potionbelt` WHERE `id` = %u LIMIT %u", + character_id, EmuConstants::POTION_BELT_ITEM_COUNT); auto results = database.QueryDatabase(query); int i = 0; for (i = 0; i < EmuConstants::POTION_BELT_ITEM_COUNT; i++){ pp->potionbelt.Items[i].Icon = 0; pp->potionbelt.Items[i].ID = 0; - strncpy(pp->potionbelt.Items[i].Name, "\0", 1); + pp->potionbelt.Items[i].Name[0] = '\0'; } for (auto row = results.begin(); row != results.end(); ++row) { - i = atoi(row[0]); /* Potion belt slot number */ - uint32 item_id = atoi(row[1]); - const Item_Struct *item = database.GetItem(item_id); - - if(!item) - continue; - - pp->potionbelt.Items[i].ID = item_id; + const Item_Struct *item_data = database.GetItem(atoi(row[1])); + if (item_data == nullptr) { continue; } + pp->potionbelt.Items[i].ID = item_data->ID; pp->potionbelt.Items[i].Icon = atoi(row[2]); - strncpy(pp->potionbelt.Items[i].Name, item->Name, 64); + strncpy(pp->potionbelt.Items[i].Name, item_data->Name, 64); } return true; From 20249cec67999e2787686e6af8a228cb5fbc7336 Mon Sep 17 00:00:00 2001 From: Uleat Date: Sat, 14 Feb 2015 21:36:54 -0500 Subject: [PATCH 091/114] Pre-purposed prep-work --- common/clientversions.h | 55 +++++++++++++++++++++++++++++++++++++++++ world/client.cpp | 32 ++++++++++++------------ world/client.h | 3 ++- world/worlddb.cpp | 13 ++++------ zone/client.cpp | 4 +-- zone/client.h | 6 ++--- zone/client_packet.cpp | 5 ++-- zone/client_process.cpp | 2 +- 8 files changed, 86 insertions(+), 34 deletions(-) diff --git a/common/clientversions.h b/common/clientversions.h index 040e5dc12..675429eab 100644 --- a/common/clientversions.h +++ b/common/clientversions.h @@ -95,4 +95,59 @@ static const char* ClientVersionName(ClientVersion version) }; } +static uint32 ClientBitFromVersion(ClientVersion clientVersion) +{ + switch (clientVersion) + { + case ClientVersion::Unknown: + case ClientVersion::Client62: + return 0; + case ClientVersion::Titanium: + case ClientVersion::SoF: + case ClientVersion::SoD: + case ClientVersion::UF: + case ClientVersion::RoF: + case ClientVersion::RoF2: + case ClientVersion::MobNPC: + case ClientVersion::MobMerc: + case ClientVersion::MobBot: + case ClientVersion::MobPet: + return ((uint32)1 << (static_cast(clientVersion) - 1)); + default: + return 0; + } +} + +static ClientVersion ClientVersionFromBit(uint32 clientVersionBit) +{ + switch (clientVersionBit) + { + case (uint32)static_cast(ClientVersion::Unknown): + case ((uint32)1 << (static_cast(ClientVersion::Client62) - 1)): + return ClientVersion::Unknown; + case ((uint32)1 << (static_cast(ClientVersion::Titanium) - 1)): + return ClientVersion::Titanium; + case ((uint32)1 << (static_cast(ClientVersion::SoF) - 1)): + return ClientVersion::SoF; + case ((uint32)1 << (static_cast(ClientVersion::SoD) - 1)): + return ClientVersion::SoD; + case ((uint32)1 << (static_cast(ClientVersion::UF) - 1)): + return ClientVersion::UF; + case ((uint32)1 << (static_cast(ClientVersion::RoF) - 1)): + return ClientVersion::RoF; + case ((uint32)1 << (static_cast(ClientVersion::RoF2) - 1)): + return ClientVersion::RoF2; + case ((uint32)1 << (static_cast(ClientVersion::MobNPC) - 1)): + return ClientVersion::MobNPC; + case ((uint32)1 << (static_cast(ClientVersion::MobMerc) - 1)): + return ClientVersion::MobMerc; + case ((uint32)1 << (static_cast(ClientVersion::MobBot) - 1)): + return ClientVersion::MobBot; + case ((uint32)1 << (static_cast(ClientVersion::MobPet) - 1)): + return ClientVersion::MobPet; + default: + return ClientVersion::Unknown; + } +} + #endif /* CLIENTVERSIONS_H */ diff --git a/world/client.cpp b/world/client.cpp index ace58ffea..f26328e12 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -86,11 +86,11 @@ Client::Client(EQStreamInterface* ieqs) charid = 0; pwaitingforbootup = 0; StartInTutorial = false; - ClientVersionBit = 0; - numclients++; - if (eqs->GetClientVersion() != ClientVersion::Unknown) - ClientVersionBit = 1 << (static_cast(eqs->GetClientVersion()) - 1); + m_ClientVersion = eqs->GetClientVersion(); + m_ClientVersionBit = ClientBitFromVersion(m_ClientVersion); + + numclients++; } Client::~Client() { @@ -161,7 +161,7 @@ void Client::SendCharInfo() { cle->SetOnline(CLE_Status_CharSelect); } - if (ClientVersionBit & BIT_RoFAndLater) + if (m_ClientVersionBit & BIT_RoFAndLater) { // Can make max char per account into a rule - New to VoA SendMaxCharCreate(10); @@ -176,7 +176,7 @@ void Client::SendCharInfo() { auto outapp = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct)); CharacterSelect_Struct* cs = (CharacterSelect_Struct*)outapp->pBuffer; - database.GetCharSelectInfo(GetAccountID(), cs, ClientVersionBit); + database.GetCharSelectInfo(GetAccountID(), cs, m_ClientVersionBit); QueuePacket(outapp); safe_delete(outapp); @@ -671,7 +671,7 @@ bool Client::HandleCharacterCreatePacket(const EQApplicationPacket *app) { } else { - if(ClientVersionBit & BIT_TitaniumAndEarlier) + if (m_ClientVersionBit & BIT_TitaniumAndEarlier) StartInTutorial = true; SendCharInfo(); } @@ -719,7 +719,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { if(!pZoning && ew->return_home && !ew->tutorial) { auto cs = new CharacterSelect_Struct; memset(cs, 0, sizeof(CharacterSelect_Struct)); - database.GetCharSelectInfo(GetAccountID(), cs, ClientVersionBit); + database.GetCharSelectInfo(GetAccountID(), cs, m_ClientVersionBit); bool home_enabled = false; for(int x = 0; x < 10; ++x) @@ -749,7 +749,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { if(!pZoning && (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial))) { auto cs = new CharacterSelect_Struct; memset(cs, 0, sizeof(CharacterSelect_Struct)); - database.GetCharSelectInfo(GetAccountID(), cs, ClientVersionBit); + database.GetCharSelectInfo(GetAccountID(), cs, m_ClientVersionBit); bool tutorial_enabled = false; for(int x = 0; x < 10; ++x) @@ -846,9 +846,9 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { char ConnectionType; - if(ClientVersionBit & BIT_UFAndLater) + if (m_ClientVersionBit & BIT_UFAndLater) ConnectionType = 'U'; - else if(ClientVersionBit & BIT_SoFAndLater) + else if (m_ClientVersionBit & BIT_SoFAndLater) ConnectionType = 'S'; else ConnectionType = 'C'; @@ -872,7 +872,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { outapp2 = new EQApplicationPacket(OP_SetChatServer2); - if(ClientVersionBit & BIT_TitaniumAndEarlier) + if (m_ClientVersionBit & BIT_TitaniumAndEarlier) ConnectionType = 'M'; sprintf(buffer,"%s,%i,%s.%s,%c%08X", @@ -906,7 +906,7 @@ bool Client::HandleDeleteCharacterPacket(const EQApplicationPacket *app) { bool Client::HandleZoneChangePacket(const EQApplicationPacket *app) { // HoT sends this to world while zoning and wants it echoed back. - if(ClientVersionBit & BIT_RoFAndLater) + if (m_ClientVersionBit & BIT_RoFAndLater) { QueuePacket(app); } @@ -1370,7 +1370,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc) Log.Out(Logs::Detail, Logs::World_Server, "Beard: %d Beardcolor: %d", cc->beard, cc->beardcolor); /* Validate the char creation struct */ - if (ClientVersionBit & BIT_SoFAndLater) { + if (m_ClientVersionBit & BIT_SoFAndLater) { if (!CheckCharCreateInfoSoF(cc)) { Log.Out(Logs::Detail, Logs::World_Server,"CheckCharCreateInfo did not validate the request (bad race/class/stats)"); return false; @@ -1438,7 +1438,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc) pp.pvp = database.GetServerType() == 1 ? 1 : 0; /* If it is an SoF Client and the SoF Start Zone rule is set, send new chars there */ - if (ClientVersionBit & BIT_SoFAndLater) { + if (m_ClientVersionBit & BIT_SoFAndLater) { Log.Out(Logs::Detail, Logs::World_Server,"Found 'SoFStartZoneID' rule setting: %i", RuleI(World, SoFStartZoneID)); if (RuleI(World, SoFStartZoneID) > 0) { pp.zone_id = RuleI(World, SoFStartZoneID); @@ -1454,7 +1454,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc) } } /* use normal starting zone logic to either get defaults, or if startzone was set, load that from the db table.*/ - bool ValidStartZone = database.GetStartZone(&pp, cc, ClientVersionBit & BIT_TitaniumAndEarlier); + bool ValidStartZone = database.GetStartZone(&pp, cc, m_ClientVersionBit & BIT_TitaniumAndEarlier); if (!ValidStartZone){ return false; diff --git a/world/client.h b/world/client.h index c6b67f91d..ea1df42ba 100644 --- a/world/client.h +++ b/world/client.h @@ -84,7 +84,8 @@ private: uint32 pwaitingforbootup; bool StartInTutorial; - uint32 ClientVersionBit; + ClientVersion m_ClientVersion; + uint32 m_ClientVersionBit; bool OPCharCreate(char *name, CharCreate_Struct *cc); void SetClassStartingSkills( PlayerProfile_Struct *pp ); diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 223ae89d6..3409a1e17 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -33,8 +33,9 @@ extern std::vector character_create_race_class_combos; // the current stuff is at the bottom of this function -void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* cs, uint32 ClientVersion) { - Inventory *inv; +void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* cs, uint32 ClientVersion) +{ + Inventory *inv = nullptr; uint8 has_home = 0; uint8 has_bind = 0; @@ -74,7 +75,7 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* "character_data " "WHERE `account_id` = %i ORDER BY `name` LIMIT 10 ", account_id); auto results = database.QueryDatabase(cquery); int char_num = 0; - for (auto row = results.begin(); row != results.end(); ++row) { + for (auto row = results.begin(); row != results.end() && char_num < 10; ++row, ++char_num) { PlayerProfile_Struct pp; memset(&pp, 0, sizeof(PlayerProfile_Struct)); @@ -167,6 +168,7 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* } /* Load Inventory */ + // If we ensure that the material data is updated appropriately, we can do away with inventory loads inv = new Inventory; if (GetInventory(account_id, cs->name[char_num], inv)) { @@ -237,11 +239,6 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* } safe_delete(inv); - - if (++char_num > 10) - { - break; - } } return; diff --git a/zone/client.cpp b/zone/client.cpp index 63a9b5073..816b21e15 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -250,7 +250,7 @@ Client::Client(EQStreamInterface* ieqs) AttemptedMessages = 0; TotalKarma = 0; m_ClientVersion = ClientVersion::Unknown; - ClientVersionBit = 0; + m_ClientVersionBit = 0; AggroCount = 0; RestRegenHP = 0; RestRegenMana = 0; @@ -7468,7 +7468,7 @@ void Client::SendClearMercInfo() void Client::DuplicateLoreMessage(uint32 ItemID) { - if(!(ClientVersionBit & BIT_RoFAndLater)) + if (!(m_ClientVersionBit & BIT_RoFAndLater)) { Message_StringID(0, PICK_LORE); return; diff --git a/zone/client.h b/zone/client.h index f2325ccca..e49f39805 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1022,7 +1022,7 @@ public: inline int CompletedTasksInSet(int TaskSet) { return (taskstate ? taskstate->CompletedTasksInSet(TaskSet) :0); } inline const ClientVersion GetClientVersion() const { return m_ClientVersion; } - inline const uint32 GetClientVersionBit() const { return ClientVersionBit; } + inline const uint32 GetClientVersionBit() const { return m_ClientVersionBit; } inline void SetClientVersion(ClientVersion in) { m_ClientVersion = in; } /** Adventure Stuff **/ @@ -1140,7 +1140,7 @@ public: void HandleLFGuildResponse(ServerPacket *pack); void SendLFGuildStatus(); void SendGuildLFGuildStatus(); - inline bool XTargettingAvailable() const { return ((ClientVersionBit & BIT_UFAndLater) && RuleB(Character, EnableXTargetting)); } + inline bool XTargettingAvailable() const { return ((m_ClientVersionBit & BIT_UFAndLater) && RuleB(Character, EnableXTargetting)); } inline uint8 GetMaxXTargets() const { return MaxXTargets; } void SetMaxXTargets(uint8 NewMax); bool IsXTarget(const Mob *m) const; @@ -1517,7 +1517,7 @@ private: uint32 AttemptedMessages; ClientVersion m_ClientVersion; - uint32 ClientVersionBit; + uint32 m_ClientVersionBit; int XPRate; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 3fa28c891..1b866073b 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1191,8 +1191,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) conn_state = ReceivedZoneEntry; SetClientVersion(Connection()->GetClientVersion()); - if (m_ClientVersion != ClientVersion::Unknown) - ClientVersionBit = 1 << (static_cast(m_ClientVersion) - 1); + m_ClientVersionBit = ClientBitFromVersion(Connection()->GetClientVersion()); bool siv = m_inv.SetInventoryVersion(m_ClientVersion); Log.Out(Logs::General, Logs::None, "%s inventory version to %s(%i)", (siv ? "Succeeded in setting" : "Failed to set"), ClientVersionName(m_ClientVersion), m_ClientVersion); @@ -1736,7 +1735,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) safe_delete(outapp); } - if (ClientVersionBit & BIT_UFAndLater) { + if (m_ClientVersionBit & BIT_UFAndLater) { outapp = new EQApplicationPacket(OP_XTargetResponse, 8); outapp->WriteUInt32(GetMaxXTargets()); outapp->WriteUInt32(0); diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 3f9d0ee3a..4f228ba8a 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -968,7 +968,7 @@ void Client::BulkSendInventoryItems() void Client::BulkSendMerchantInventory(int merchant_id, int npcid) { const Item_Struct* handyitem = nullptr; uint32 numItemSlots = 80; //The max number of items passed in the transaction. - if (ClientVersionBit & BIT_RoFAndLater) { // RoF+ can send 200 items + if (m_ClientVersionBit & BIT_RoFAndLater) { // RoF+ can send 200 items numItemSlots = 200; } const Item_Struct *item; From 53a1faa36feb5a6e9253c79d6877fcee17488530 Mon Sep 17 00:00:00 2001 From: Uleat Date: Sat, 14 Feb 2015 22:57:47 -0500 Subject: [PATCH 092/114] Constant name and eqdictionary entry addition prior to per-client version limit activation --- common/eq_dictionary.cpp | 22 ++++++++++++++++++++++ common/eq_dictionary.h | 6 ++++++ common/patches/rof2_constants.h | 2 ++ common/patches/rof_constants.h | 2 ++ common/patches/sod_constants.h | 2 ++ common/patches/sof_constants.h | 2 ++ common/patches/titanium_constants.h | 2 ++ common/patches/uf_constants.h | 2 ++ 8 files changed, 40 insertions(+) diff --git a/common/eq_dictionary.cpp b/common/eq_dictionary.cpp index a6a0d806d..9bc602aa1 100644 --- a/common/eq_dictionary.cpp +++ b/common/eq_dictionary.cpp @@ -319,6 +319,28 @@ ClientVersion EQLimits::ValidateMobClientVersion(ClientVersion clientVersion) return ClientVersion::Unknown; } +// database +size_t EQLimits::CharacterCreationLimit(ClientVersion clientVersion) +{ + static const size_t local[CLIENT_VERSION_COUNT] = { +/*Unknown*/ NOT_USED, +/*Client62*/ NOT_USED, +/*Titanium*/ Titanium::consts::CHARACTER_CREATION_LIMIT, +/*SoF*/ SoF::consts::CHARACTER_CREATION_LIMIT, +/*SoD*/ SoD::consts::CHARACTER_CREATION_LIMIT, +/*UF*/ UF::consts::CHARACTER_CREATION_LIMIT, +/*RoF*/ RoF::consts::CHARACTER_CREATION_LIMIT, +/*RoF2*/ RoF2::consts::CHARACTER_CREATION_LIMIT, + +/*MobNPC*/ NOT_USED, +/*MobMerc*/ NOT_USED, +/*MobBot*/ NOT_USED, +/*MobPet*/ NOT_USED + }; + + return local[static_cast(ValidateMobClientVersion(clientVersion))]; +} + // inventory uint16 EQLimits::InventoryMapSize(int16 indexMap, ClientVersion clientVersion) { diff --git a/common/eq_dictionary.h b/common/eq_dictionary.h index 16586f356..84da53f63 100644 --- a/common/eq_dictionary.h +++ b/common/eq_dictionary.h @@ -49,6 +49,9 @@ public: // database static const ClientVersion CHARACTER_CREATION_CLIENT = ClientVersion::RoF2; // adjust according to starting item placement and target client + // This value should be at least 8 or Titanium will have issues (tested at 6) + static const size_t CHARACTER_CREATION_LIMIT = RoF2::consts::CHARACTER_CREATION_LIMIT; + // inventory static uint16 InventoryMapSize(int16 indexMap); //static std::string InventoryLocationName(Location_Struct location); @@ -170,6 +173,9 @@ public: static bool IsValidMobClientVersion(ClientVersion clientVersion); static ClientVersion ValidateMobClientVersion(ClientVersion clientVersion); + // database + static size_t CharacterCreationLimit(ClientVersion clientVersion); + // inventory static uint16 InventoryMapSize(int16 indexMap, ClientVersion clientVersion); static uint64 PossessionsBitmask(ClientVersion clientVersion); diff --git a/common/patches/rof2_constants.h b/common/patches/rof2_constants.h index 867574670..750a6fb3e 100644 --- a/common/patches/rof2_constants.h +++ b/common/patches/rof2_constants.h @@ -103,6 +103,8 @@ namespace RoF2 { } namespace consts { + static const size_t CHARACTER_CREATION_LIMIT = 10; + static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; static const uint16 MAP_BANK_SIZE = 24; static const uint16 MAP_SHARED_BANK_SIZE = 2; diff --git a/common/patches/rof_constants.h b/common/patches/rof_constants.h index 4fbf21d47..86367b3d9 100644 --- a/common/patches/rof_constants.h +++ b/common/patches/rof_constants.h @@ -102,6 +102,8 @@ namespace RoF { } namespace consts { + static const size_t CHARACTER_CREATION_LIMIT = 10; + static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; static const uint16 MAP_BANK_SIZE = 24; static const uint16 MAP_SHARED_BANK_SIZE = 2; diff --git a/common/patches/sod_constants.h b/common/patches/sod_constants.h index 6b587b7c4..5fdb89578 100644 --- a/common/patches/sod_constants.h +++ b/common/patches/sod_constants.h @@ -101,6 +101,8 @@ namespace SoD { } namespace consts { + static const size_t CHARACTER_CREATION_LIMIT = 10; + static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; static const uint16 MAP_BANK_SIZE = 24; static const uint16 MAP_SHARED_BANK_SIZE = 2; diff --git a/common/patches/sof_constants.h b/common/patches/sof_constants.h index f5376cd13..4729eb436 100644 --- a/common/patches/sof_constants.h +++ b/common/patches/sof_constants.h @@ -101,6 +101,8 @@ namespace SoF { } namespace consts { + static const size_t CHARACTER_CREATION_LIMIT = 10; + static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; static const uint16 MAP_BANK_SIZE = 24; static const uint16 MAP_SHARED_BANK_SIZE = 2; diff --git a/common/patches/titanium_constants.h b/common/patches/titanium_constants.h index 61da2ba59..c93de7666 100644 --- a/common/patches/titanium_constants.h +++ b/common/patches/titanium_constants.h @@ -100,6 +100,8 @@ namespace Titanium { } namespace consts { + static const size_t CHARACTER_CREATION_LIMIT = 8; + static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; static const uint16 MAP_BANK_SIZE = 16; static const uint16 MAP_SHARED_BANK_SIZE = 2; diff --git a/common/patches/uf_constants.h b/common/patches/uf_constants.h index fc14af63f..3320fee76 100644 --- a/common/patches/uf_constants.h +++ b/common/patches/uf_constants.h @@ -101,6 +101,8 @@ namespace UF { } namespace consts { + static const size_t CHARACTER_CREATION_LIMIT = 10; + static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; static const uint16 MAP_BANK_SIZE = 24; static const uint16 MAP_SHARED_BANK_SIZE = 2; From e4be4d6895a4f6db0748e8e36d3271b2ad76badf Mon Sep 17 00:00:00 2001 From: Uleat Date: Sun, 15 Feb 2015 10:30:43 -0500 Subject: [PATCH 093/114] Pre-purposed clean-up --- common/eq_packet_structs.h | 119 ++++++++++++--------------- common/patches/rof.cpp | 104 +++++++++++------------ common/patches/rof2.cpp | 104 +++++++++++------------ common/patches/rof2_structs.h | 131 ++++++++++++++--------------- common/patches/rof_structs.h | 132 +++++++++++++++--------------- common/patches/sod.cpp | 92 ++++++++++----------- common/patches/sod_structs.h | 103 +++++++++++------------ common/patches/sof.cpp | 90 ++++++++++---------- common/patches/sof_structs.h | 100 +++++++++++----------- common/patches/titanium.cpp | 58 ++++++------- common/patches/titanium_structs.h | 69 ++++++++-------- common/patches/uf.cpp | 92 ++++++++++----------- common/patches/uf_structs.h | 102 ++++++++++++----------- world/client.cpp | 8 +- world/worlddb.cpp | 82 +++++++++---------- zone/bot.cpp | 22 ++--- zone/client.cpp | 6 +- zone/client_packet.cpp | 4 +- zone/command.cpp | 2 +- zone/corpse.cpp | 22 ++--- zone/inventory.cpp | 22 ++--- zone/mob.cpp | 18 ++-- zone/zonedb.cpp | 50 +++++------ 23 files changed, 762 insertions(+), 770 deletions(-) diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 17fe7e913..0f1b63136 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -124,83 +124,66 @@ struct LDoNTrapTemplate /////////////////////////////////////////////////////////////////////////////// -/* -** Color_Struct -** Size: 4 bytes -** Used for convenience -** Merth: Gave struct a name so gcc 2.96 would compile -** -*/ +// All clients translate the character select information to some degree + struct Color_Struct { - union - { - struct - { - uint8 blue; - uint8 green; - uint8 red; - uint8 use_tint; // if there's a tint this is FF - } rgb; - uint32 color; + union { + struct { + uint8 Blue; + uint8 Green; + uint8 Red; + uint8 UseTint; // if there's a tint this is FF + } RGB; + uint32 Color; }; }; -/* -* Visible equiptment. -* Size: 20 Octets -*/ -struct EquipStruct { - /*00*/ uint32 material; - /*04*/ uint32 unknown1; - /*08*/ uint32 elitematerial; - /*12*/ uint32 heroforgemodel; - /*16*/ uint32 material2; // Same as material? - /*20*/ +struct EquipStruct +{ + uint32 Material; + uint32 Unknown1; + uint32 EliteMaterial; + uint32 HeroForgeModel; + uint32 Material2; // Same as material? }; -struct CharSelectEquip { - uint32 material; - uint32 unknown1; - uint32 elitematerial; - uint32 heroforgemodel; - uint32 material2; - Color_Struct color; +struct CharSelectEquip +{ + uint32 Material; + uint32 Unknown1; + uint32 EliteMaterial; + uint32 HeroForgeModel; + uint32 Material2; + Color_Struct Color; }; -/* -** Character Selection Struct -** Length: 1704 Bytes -** -*/ -struct CharacterSelect_Struct { -/*0000*/ uint32 race[10]; // Characters Race -/*0040*/ //Color_Struct cs_colors[10][9]; // Characters Equipment Colors -/*0400*/ uint8 beardcolor[10]; // Characters beard Color -/*0410*/ uint8 hairstyle[10]; // Characters hair style -/*0420*/ //uint32 equip[10][9]; // 0=helm, 1=chest, 2=arm, 3=bracer, 4=hand, 5=leg, 6=boot, 7=melee1, 8=melee2 (Might not be) -/*0000*/ CharSelectEquip equip[10][9]; -/*0780*/ uint32 secondary[10]; // Characters secondary IDFile number -/*0820*/ uint32 drakkin_heritage[10]; // added for SoF -/*0860*/ uint32 drakkin_tattoo[10]; // added for SoF -/*0900*/ uint32 drakkin_details[10]; // added for SoF -/*0940*/ uint32 deity[10]; // Characters Deity -/*0980*/ uint8 gohome[10]; // 1=Go Home available, 0=not -/*0990*/ uint8 tutorial[10]; // 1=Tutorial available, 0=not -/*1000*/ uint8 beard[10]; // Characters Beard Type -/*1010*/ uint8 unknown902[10]; // 10x ff -/*1020*/ uint32 primary[10]; // Characters primary IDFile number -/*1060*/ uint8 haircolor[10]; // Characters Hair Color -/*1070*/ uint8 unknown0962[2]; // 2x 00 -/*1072*/ uint32 zone[10]; // Characters Current Zone -/*1112*/ uint8 class_[10]; // Characters Classes -/*1022*/ uint8 face[10]; // Characters Face Type -/*1032*/ char name[10][64]; // Characters Names -/*1672*/ uint8 gender[10]; // Characters Gender -/*1682*/ uint8 eyecolor1[10]; // Characters Eye Color -/*1692*/ uint8 eyecolor2[10]; // Characters Eye 2 Color -/*1702*/ uint8 level[10]; // Characters Levels -/*1712*/ +struct CharacterSelect_Struct +{ + uint32 Race[10]; // Characters Race + uint8 BeardColor[10]; // Characters beard Color + uint8 HairStyle[10]; // Characters hair style + CharSelectEquip Equip[10][9]; + uint32 Secondary[10]; // Characters secondary IDFile number + uint32 DrakkinHeritage[10]; // added for SoF + uint32 DrakkinTattoo[10]; // added for SoF + uint32 DrakkinDetails[10]; // added for SoF + uint32 Deity[10]; // Characters Deity + uint8 GoHome[10]; // 1=Go Home available, 0=not + uint8 Tutorial[10]; // 1=Tutorial available, 0=not + uint8 Beard[10]; // Characters Beard Type + uint8 Unknown902[10]; // 10x ff + uint32 Primary[10]; // Characters primary IDFile number + uint8 HairColor[10]; // Characters Hair Color + uint8 Unknown0962[2]; // 2x 00 + uint32 Zone[10]; // Characters Current Zone + uint8 Class_[10]; // Characters Classes + uint8 Face[10]; // Characters Face Type + char Name[10][64]; // Characters Names + uint8 Gender[10]; // Characters Gender + uint8 EyeColor1[10]; // Characters Eye Color + uint8 EyeColor2[10]; // Characters Eye 2 Color + uint8 Level[10]; // Characters Levels }; /* diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index ed943db97..6e89f7d39 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -2043,7 +2043,7 @@ namespace RoF for (int r = 0; r < 7; r++) { - outapp->WriteUInt32(emu->item_tint[r].color); + outapp->WriteUInt32(emu->item_tint[r].Color); } // Write zeroes for extra two tint values outapp->WriteUInt32(0); @@ -2053,7 +2053,7 @@ namespace RoF for (int r = 0; r < 7; r++) { - outapp->WriteUInt32(emu->item_tint[r].color); + outapp->WriteUInt32(emu->item_tint[r].Color); } // Write zeroes for extra two tint values outapp->WriteUInt32(0); @@ -2906,11 +2906,11 @@ namespace RoF int char_count; int namelen = 0; for (char_count = 0; char_count < 10; char_count++) { - if (emu->name[char_count][0] == '\0') + if (emu->Name[char_count][0] == '\0') break; - if (strcmp(emu->name[char_count], "") == 0) + if (strcmp(emu->Name[char_count], "") == 0) break; - namelen += strlen(emu->name[char_count]); + namelen += strlen(emu->Name[char_count]); } int total_length = sizeof(structs::CharacterSelect_Struct) @@ -2922,58 +2922,58 @@ namespace RoF //unsigned char *eq_buffer = new unsigned char[total_length]; //structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer; - eq->char_count = char_count; + eq->CharCount = char_count; //eq->total_chars = 10; - unsigned char *bufptr = (unsigned char *)eq->entries; + unsigned char *bufptr = (unsigned char *)eq->Entries; int r; for (r = 0; r < char_count; r++) { { //pre-name section... structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - memcpy(eq2->name, emu->name[r], strlen(emu->name[r]) + 1); + memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1); } //adjust for name. - bufptr += strlen(emu->name[r]); + bufptr += strlen(emu->Name[r]); { //post-name section... structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->class_ = emu->class_[r]; - eq2->race = emu->race[r]; - eq2->level = emu->level[r]; - eq2->class_2 = emu->class_[r]; - eq2->race2 = emu->race[r]; - eq2->zone = emu->zone[r]; - eq2->instance = 0; - eq2->gender = emu->gender[r]; - eq2->face = emu->face[r]; + eq2->Class_ = emu->Class_[r]; + eq2->Race = emu->Race[r]; + eq2->Level = emu->Level[r]; + eq2->Class_2 = emu->Class_[r]; + eq2->Race2 = emu->Race[r]; + eq2->Zone = emu->Zone[r]; + eq2->Instance = 0; + eq2->Gender = emu->Gender[r]; + eq2->Face = emu->Face[r]; int k; for (k = 0; k < _MaterialCount; k++) { - eq2->equip[k].material = emu->equip[r][k].material; - eq2->equip[k].unknown1 = emu->equip[r][k].unknown1; - eq2->equip[k].elitematerial = emu->equip[r][k].elitematerial; - eq2->equip[k].heroforgemodel = emu->equip[r][k].heroforgemodel; - eq2->equip[k].material2 = emu->equip[r][k].material2; - eq2->equip[k].color.color = emu->equip[r][k].color.color; + eq2->Equip[k].Material = emu->Equip[r][k].Material; + eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1; + eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial; + eq2->Equip[k].HeroForgeModel = emu->Equip[r][k].HeroForgeModel; + eq2->Equip[k].Material2 = emu->Equip[r][k].Material2; + eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color; } - eq2->u15 = 0xff; - eq2->u19 = 0xFF; - eq2->drakkin_tattoo = emu->drakkin_tattoo[r]; - eq2->drakkin_details = emu->drakkin_details[r]; - eq2->deity = emu->deity[r]; - eq2->primary = emu->primary[r]; - eq2->secondary = emu->secondary[r]; - eq2->haircolor = emu->haircolor[r]; - eq2->beardcolor = emu->beardcolor[r]; - eq2->eyecolor1 = emu->eyecolor1[r]; - eq2->eyecolor2 = emu->eyecolor2[r]; - eq2->hairstyle = emu->hairstyle[r]; - eq2->beard = emu->beard[r]; - eq2->char_enabled = 1; - eq2->tutorial = emu->tutorial[r]; - eq2->drakkin_heritage = emu->drakkin_heritage[r]; - eq2->unknown1 = 0; - eq2->gohome = emu->gohome[r]; + eq2->Unknown15 = 0xFF; + eq2->Uknown19 = 0xFF; + eq2->DrakkinTattoo = emu->DrakkinTattoo[r]; + eq2->DrakkinDetails = emu->DrakkinDetails[r]; + eq2->Deity = emu->Deity[r]; + eq2->Primary = emu->Primary[r]; + eq2->Secondary = emu->Secondary[r]; + eq2->HairColor = emu->HairColor[r]; + eq2->BeardColor = emu->BeardColor[r]; + eq2->EyeColor1 = emu->EyeColor1[r]; + eq2->EyeColor2 = emu->EyeColor2[r]; + eq2->HairStyle = emu->HairStyle[r]; + eq2->Beard = emu->Beard[r]; + eq2->CharEnabled = 1; + eq2->Tutorial = emu->Tutorial[r]; + eq2->DrakkinHeritage = emu->DrakkinHeritage[r]; + eq2->Unknown1 = 0; + eq2->GoHome = emu->GoHome[r]; eq2->LastLogin = 1212696584; - eq2->unknown2 = 0; + eq2->Unknown2 = 0; } bufptr += sizeof(structs::CharacterSelectEntry_Struct); } @@ -3639,7 +3639,7 @@ namespace RoF OUT(elite_material); OUT(hero_forge_model); OUT(unknown18); - OUT(color.color); + OUT(color.Color); OUT(wear_slot_id); FINISH_ENCODE(); @@ -3950,18 +3950,18 @@ namespace RoF for (k = 0; k < 9; ++k) { { - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].color); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].Color); } } structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer; for (k = 0; k < 9; k++) { - Equipment[k].material = emu->equipment[k].material; - Equipment[k].unknown1 = emu->equipment[k].unknown1; - Equipment[k].elitematerial = emu->equipment[k].elitematerial; - Equipment[k].heroforgemodel = emu->equipment[k].heroforgemodel; - Equipment[k].material2 = emu->equipment[k].material2; + Equipment[k].Material = emu->equipment[k].Material; + Equipment[k].Unknown1 = emu->equipment[k].Unknown1; + Equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial; + Equipment[k].HeroForgeModel = emu->equipment[k].HeroForgeModel; + Equipment[k].Material2 = emu->equipment[k].Material2; } Buffer += (sizeof(structs::EquipStruct) * 9); @@ -3974,13 +3974,13 @@ namespace RoF VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index e6f4775ac..0215911e6 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -2118,7 +2118,7 @@ namespace RoF2 for (int r = 0; r < 7; r++) { - outapp->WriteUInt32(emu->item_tint[r].color); + outapp->WriteUInt32(emu->item_tint[r].Color); } // Write zeroes for extra two tint values outapp->WriteUInt32(0); @@ -2128,7 +2128,7 @@ namespace RoF2 for (int r = 0; r < 7; r++) { - outapp->WriteUInt32(emu->item_tint[r].color); + outapp->WriteUInt32(emu->item_tint[r].Color); } // Write zeroes for extra two tint values outapp->WriteUInt32(0); @@ -2990,11 +2990,11 @@ namespace RoF2 int char_count; int namelen = 0; for (char_count = 0; char_count < 10; char_count++) { - if (emu->name[char_count][0] == '\0') + if (emu->Name[char_count][0] == '\0') break; - if (strcmp(emu->name[char_count], "") == 0) + if (strcmp(emu->Name[char_count], "") == 0) break; - namelen += strlen(emu->name[char_count]); + namelen += strlen(emu->Name[char_count]); } int total_length = sizeof(structs::CharacterSelect_Struct) @@ -3006,58 +3006,58 @@ namespace RoF2 //unsigned char *eq_buffer = new unsigned char[total_length]; //structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer; - eq->char_count = char_count; + eq->CharCount = char_count; //eq->total_chars = 10; - unsigned char *bufptr = (unsigned char *)eq->entries; + unsigned char *bufptr = (unsigned char *)eq->Entries; int r; for (r = 0; r < char_count; r++) { { //pre-name section... structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - memcpy(eq2->name, emu->name[r], strlen(emu->name[r]) + 1); + memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1); } //adjust for name. - bufptr += strlen(emu->name[r]); + bufptr += strlen(emu->Name[r]); { //post-name section... structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->class_ = emu->class_[r]; - eq2->race = emu->race[r]; - eq2->level = emu->level[r]; - eq2->class_2 = emu->class_[r]; - eq2->race2 = emu->race[r]; - eq2->zone = emu->zone[r]; - eq2->instance = 0; - eq2->gender = emu->gender[r]; - eq2->face = emu->face[r]; + eq2->Class_ = emu->Class_[r]; + eq2->Race = emu->Race[r]; + eq2->Level = emu->Level[r]; + eq2->Class_2 = emu->Class_[r]; + eq2->Race2 = emu->Race[r]; + eq2->Zone = emu->Zone[r]; + eq2->Instance = 0; + eq2->Gender = emu->Gender[r]; + eq2->Face = emu->Face[r]; int k; for (k = 0; k < _MaterialCount; k++) { - eq2->equip[k].material = emu->equip[r][k].material; - eq2->equip[k].unknown1 = emu->equip[r][k].unknown1; - eq2->equip[k].elitematerial = emu->equip[r][k].elitematerial; - eq2->equip[k].heroforgemodel = emu->equip[r][k].heroforgemodel; - eq2->equip[k].material2 = emu->equip[r][k].material2; - eq2->equip[k].color.color = emu->equip[r][k].color.color; + eq2->Equip[k].Material = emu->Equip[r][k].Material; + eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1; + eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial; + eq2->Equip[k].HeroForgeModel = emu->Equip[r][k].HeroForgeModel; + eq2->Equip[k].Material2 = emu->Equip[r][k].Material2; + eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color; } - eq2->u15 = 0xff; - eq2->u19 = 0xFF; - eq2->drakkin_tattoo = emu->drakkin_tattoo[r]; - eq2->drakkin_details = emu->drakkin_details[r]; - eq2->deity = emu->deity[r]; - eq2->primary = emu->primary[r]; - eq2->secondary = emu->secondary[r]; - eq2->haircolor = emu->haircolor[r]; - eq2->beardcolor = emu->beardcolor[r]; - eq2->eyecolor1 = emu->eyecolor1[r]; - eq2->eyecolor2 = emu->eyecolor2[r]; - eq2->hairstyle = emu->hairstyle[r]; - eq2->beard = emu->beard[r]; - eq2->char_enabled = 1; - eq2->tutorial = emu->tutorial[r]; - eq2->drakkin_heritage = emu->drakkin_heritage[r]; - eq2->unknown1 = 0; - eq2->gohome = emu->gohome[r]; + eq2->Unknown15 = 0xFF; + eq2->Unknown19 = 0xFF; + eq2->DrakkinTattoo = emu->DrakkinTattoo[r]; + eq2->DrakkinDetails = emu->DrakkinDetails[r]; + eq2->Deity = emu->Deity[r]; + eq2->Primary = emu->Primary[r]; + eq2->Secondary = emu->Secondary[r]; + eq2->HairColor = emu->HairColor[r]; + eq2->BeardColor = emu->BeardColor[r]; + eq2->EyeColor1 = emu->EyeColor1[r]; + eq2->EyeColor2 = emu->EyeColor2[r]; + eq2->HairStyle = emu->HairStyle[r]; + eq2->Beard = emu->Beard[r]; + eq2->CharEnabled = 1; + eq2->Tutorial = emu->Tutorial[r]; + eq2->DrakkinHeritage = emu->DrakkinHeritage[r]; + eq2->Unknown1 = 0; + eq2->GoHome = emu->GoHome[r]; eq2->LastLogin = 1212696584; - eq2->unknown2 = 0; + eq2->Unknown2 = 0; } bufptr += sizeof(structs::CharacterSelectEntry_Struct); } @@ -3763,7 +3763,7 @@ namespace RoF2 OUT(elite_material); OUT(hero_forge_model); OUT(unknown18); - OUT(color.color); + OUT(color.Color); OUT(wear_slot_id); FINISH_ENCODE(); @@ -4078,18 +4078,18 @@ namespace RoF2 for (k = 0; k < 9; ++k) { { - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].color); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].Color); } } structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer; for (k = 0; k < 9; k++) { - Equipment[k].material = emu->equipment[k].material; - Equipment[k].unknown1 = emu->equipment[k].unknown1; - Equipment[k].elitematerial = emu->equipment[k].elitematerial; - Equipment[k].heroforgemodel = emu->equipment[k].heroforgemodel; - Equipment[k].material2 = emu->equipment[k].material2; + Equipment[k].Material = emu->equipment[k].Material; + Equipment[k].Unknown1 = emu->equipment[k].Unknown1; + Equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial; + Equipment[k].HeroForgeModel = emu->equipment[k].HeroForgeModel; + Equipment[k].Material2 = emu->equipment[k].Material2; } Buffer += (sizeof(structs::EquipStruct) * 9); @@ -4102,13 +4102,13 @@ namespace RoF2 VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 94f8bf4e7..7f8fc6978 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -142,84 +142,87 @@ struct AdventureInfo { */ struct Color_Struct { - union - { - struct - { - uint8 blue; - uint8 green; - uint8 red; - uint8 use_tint; // if there's a tint this is FF - } rgb; - uint32 color; + union { + struct { + uint8 Blue; + uint8 Green; + uint8 Red; + uint8 UseTint; // if there's a tint this is FF + } RGB; + uint32 Color; }; }; -/* -* Visible equiptment. -* Size: 20 Octets -*/ -struct EquipStruct { - /*00*/ uint32 material; - /*04*/ uint32 unknown1; - /*08*/ uint32 elitematerial; - /*12*/ uint32 heroforgemodel; - /*16*/ uint32 material2; // Same as material? - /*20*/ +struct CharSelectEquip +{ + uint32 Material; + uint32 Unknown1; + uint32 EliteMaterial; + uint32 HeroForgeModel; + uint32 Material2; + Color_Struct Color; }; -struct CharSelectEquip { - uint32 material; - uint32 unknown1; - uint32 elitematerial; - uint32 heroforgemodel; - uint32 material2; - Color_Struct color; -}; - -struct CharacterSelectEntry_Struct { -/*0000*/ char name[1]; // Name null terminated -/*0000*/ uint8 class_; -/*0000*/ uint32 race; -/*0000*/ uint8 level; -/*0000*/ uint8 class_2; -/*0000*/ uint32 race2; -/*0000*/ uint16 zone; -/*0000*/ uint16 instance; -/*0000*/ uint8 gender; -/*0000*/ uint8 face; -/*0000*/ CharSelectEquip equip[9]; -/*0000*/ uint8 u15; // Seen FF -/*0000*/ uint8 u19; // Seen FF -/*0000*/ uint32 drakkin_tattoo; -/*0000*/ uint32 drakkin_details; -/*0000*/ uint32 deity; -/*0000*/ uint32 primary; -/*0000*/ uint32 secondary; -/*0000*/ uint8 haircolor; -/*0000*/ uint8 beardcolor; -/*0000*/ uint8 eyecolor1; -/*0000*/ uint8 eyecolor2; -/*0000*/ uint8 hairstyle; -/*0000*/ uint8 beard; -/*0000*/ uint8 char_enabled; -/*0000*/ uint8 tutorial; // Seen 1 for new char or 0 for existing -/*0000*/ uint32 drakkin_heritage; -/*0000*/ uint8 unknown1; // Seen 0 -/*0000*/ uint8 gohome; // Seen 0 for new char and 1 for existing +struct CharacterSelectEntry_Struct +{ +/*0000*/ char Name[1]; // Name null terminated +/*0000*/ uint8 Class_; +/*0000*/ uint32 Race; +/*0000*/ uint8 Level; +/*0000*/ uint8 Class_2; +/*0000*/ uint32 Race2; +/*0000*/ uint16 Zone; +/*0000*/ uint16 Instance; +/*0000*/ uint8 Gender; +/*0000*/ uint8 Face; +/*0000*/ CharSelectEquip Equip[9]; +/*0000*/ uint8 Unknown15; // Seen FF +/*0000*/ uint8 Unknown19; // Seen FF +/*0000*/ uint32 DrakkinTattoo; +/*0000*/ uint32 DrakkinDetails; +/*0000*/ uint32 Deity; +/*0000*/ uint32 Primary; +/*0000*/ uint32 Secondary; +/*0000*/ uint8 HairColor; +/*0000*/ uint8 BeardColor; +/*0000*/ uint8 EyeColor1; +/*0000*/ uint8 EyeColor2; +/*0000*/ uint8 HairStyle; +/*0000*/ uint8 Beard; +/*0000*/ uint8 CharEnabled; +/*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing +/*0000*/ uint32 DrakkinHeritage; +/*0000*/ uint8 Unknown1; // Seen 0 +/*0000*/ uint8 GoHome; // Seen 0 for new char and 1 for existing /*0000*/ uint32 LastLogin; -/*0000*/ uint8 unknown2; // Seen 0 +/*0000*/ uint8 Unknown2; // Seen 0 }; /* ** Character Selection Struct ** */ -struct CharacterSelect_Struct { -/*000*/ uint32 char_count; //number of chars in this packet -/*004*/ CharacterSelectEntry_Struct entries[0]; +struct CharacterSelect_Struct +{ +/*000*/ uint32 CharCount; //number of chars in this packet +/*004*/ CharacterSelectEntry_Struct Entries[0]; }; +/* +* Visible equiptment. +* Size: 20 Octets +*/ +struct EquipStruct +{ + /*00*/ uint32 Material; + /*04*/ uint32 Unknown1; + /*08*/ uint32 EliteMaterial; + /*12*/ uint32 HeroForgeModel; + /*16*/ uint32 Material2; // Same as material? + /*20*/ +}; + + struct Membership_Entry_Struct { /*000*/ uint32 purchase_id; // Seen 1, then increments 90287 to 90300 diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 05cc5a346..a1260fe72 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -142,71 +142,87 @@ struct AdventureInfo { */ struct Color_Struct { - union - { - struct - { - uint8 blue; - uint8 green; - uint8 red; - uint8 use_tint; // if there's a tint this is FF - } rgb; - uint32 color; + union { + struct { + uint8 Blue; + uint8 Green; + uint8 Red; + uint8 UseTint; // if there's a tint this is FF + } RGB; + uint32 Color; }; }; -struct CharSelectEquip { - uint32 material; - uint32 unknown1; - uint32 elitematerial; - uint32 heroforgemodel; - uint32 material2; - Color_Struct color; +struct CharSelectEquip +{ + uint32 Material; + uint32 Unknown1; + uint32 EliteMaterial; + uint32 HeroForgeModel; + uint32 Material2; + Color_Struct Color; }; -struct CharacterSelectEntry_Struct { -/*0000*/ char name[1]; // Name null terminated -/*0000*/ uint8 class_; -/*0000*/ uint32 race; -/*0000*/ uint8 level; -/*0000*/ uint8 class_2; -/*0000*/ uint32 race2; -/*0000*/ uint16 zone; -/*0000*/ uint16 instance; -/*0000*/ uint8 gender; -/*0000*/ uint8 face; -/*0000*/ CharSelectEquip equip[9]; -/*0000*/ uint8 u15; // Seen FF -/*0000*/ uint8 u19; // Seen FF -/*0000*/ uint32 drakkin_tattoo; -/*0000*/ uint32 drakkin_details; -/*0000*/ uint32 deity; -/*0000*/ uint32 primary; -/*0000*/ uint32 secondary; -/*0000*/ uint8 haircolor; -/*0000*/ uint8 beardcolor; -/*0000*/ uint8 eyecolor1; -/*0000*/ uint8 eyecolor2; -/*0000*/ uint8 hairstyle; -/*0000*/ uint8 beard; -/*0000*/ uint8 char_enabled; -/*0000*/ uint8 tutorial; // Seen 1 for new char or 0 for existing -/*0000*/ uint32 drakkin_heritage; -/*0000*/ uint8 unknown1; // Seen 0 -/*0000*/ uint8 gohome; // Seen 0 for new char and 1 for existing +struct CharacterSelectEntry_Struct +{ +/*0000*/ char Name[1]; // Name null terminated +/*0000*/ uint8 Class_; +/*0000*/ uint32 Race; +/*0000*/ uint8 Level; +/*0000*/ uint8 Class_2; +/*0000*/ uint32 Race2; +/*0000*/ uint16 Zone; +/*0000*/ uint16 Instance; +/*0000*/ uint8 Gender; +/*0000*/ uint8 Face; +/*0000*/ CharSelectEquip Equip[9]; +/*0000*/ uint8 Unknown15; // Seen FF +/*0000*/ uint8 Uknown19; // Seen FF +/*0000*/ uint32 DrakkinTattoo; +/*0000*/ uint32 DrakkinDetails; +/*0000*/ uint32 Deity; +/*0000*/ uint32 Primary; +/*0000*/ uint32 Secondary; +/*0000*/ uint8 HairColor; +/*0000*/ uint8 BeardColor; +/*0000*/ uint8 EyeColor1; +/*0000*/ uint8 EyeColor2; +/*0000*/ uint8 HairStyle; +/*0000*/ uint8 Beard; +/*0000*/ uint8 CharEnabled; +/*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing +/*0000*/ uint32 DrakkinHeritage; +/*0000*/ uint8 Unknown1; // Seen 0 +/*0000*/ uint8 GoHome; // Seen 0 for new char and 1 for existing /*0000*/ uint32 LastLogin; -/*0000*/ uint8 unknown2; // Seen 0 +/*0000*/ uint8 Unknown2; // Seen 0 }; /* ** Character Selection Struct ** */ -struct CharacterSelect_Struct { -/*000*/ uint32 char_count; //number of chars in this packet -/*004*/ CharacterSelectEntry_Struct entries[0]; +struct CharacterSelect_Struct +{ +/*000*/ uint32 CharCount; //number of chars in this packet +/*004*/ CharacterSelectEntry_Struct Entries[0]; }; +/* +* Visible equiptment. +* Size: 20 Octets +*/ +struct EquipStruct +{ + /*00*/ uint32 Material; + /*04*/ uint32 Unknown1; + /*08*/ uint32 EliteMaterial; + /*12*/ uint32 HeroForgeModel; + /*16*/ uint32 Material2; // Same as material? + /*20*/ +}; + + struct Membership_Entry_Struct { /*000*/ uint32 purchase_id; // Seen 1, then increments 90287 to 90300 @@ -247,20 +263,6 @@ struct Membership_Struct }; -/* -* Visible equiptment. -* Size: 20 Octets -*/ -struct EquipStruct { -/*00*/ uint32 material; -/*04*/ uint32 unknown1; -/*08*/ uint32 elitematerial; -/*12*/ uint32 heroforgemodel; -/*16*/ uint32 material2; // Same as material? -/*20*/ -}; - - /* ** Generic Spawn Struct ** Length: 897 Octets diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index b1ae218ed..c2ac79d7d 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -1542,13 +1542,13 @@ namespace SoD OUT(beard); // OUT(unknown00178[10]); for (r = 0; r < 9; r++) { - eq->equipment[r].material = emu->item_material[r]; - eq->equipment[r].unknown1 = 0; - eq->equipment[r].elitematerial = 0; + eq->equipment[r].Material = emu->item_material[r]; + eq->equipment[r].Unknown1 = 0; + eq->equipment[r].EliteMaterial = 0; //eq->colors[r].color = emu->colors[r].color; } for (r = 0; r < 7; r++) { - OUT(item_tint[r].color); + OUT(item_tint[r].Color); } // OUT(unknown00224[48]); //NOTE: new client supports 300 AAs, our internal rep/PP @@ -1920,11 +1920,11 @@ namespace SoD int char_count; int namelen = 0; for (char_count = 0; char_count < 10; char_count++) { - if (emu->name[char_count][0] == '\0') + if (emu->Name[char_count][0] == '\0') break; - if (strcmp(emu->name[char_count], "") == 0) + if (strcmp(emu->Name[char_count], "") == 0) break; - namelen += strlen(emu->name[char_count]); + namelen += strlen(emu->Name[char_count]); } int total_length = sizeof(structs::CharacterSelect_Struct) @@ -1936,49 +1936,49 @@ namespace SoD //unsigned char *eq_buffer = new unsigned char[total_length]; //structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer; - eq->char_count = char_count; - eq->total_chars = 10; + eq->CharCount = char_count; + eq->TotalChars = 10; - unsigned char *bufptr = (unsigned char *)eq->entries; + unsigned char *bufptr = (unsigned char *)eq->Entries; int r; for (r = 0; r < char_count; r++) { { //pre-name section... structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->level = emu->level[r]; - eq2->hairstyle = emu->hairstyle[r]; - eq2->gender = emu->gender[r]; - memcpy(eq2->name, emu->name[r], strlen(emu->name[r]) + 1); + eq2->Level = emu->Level[r]; + eq2->HairStyle = emu->HairStyle[r]; + eq2->Gender = emu->Gender[r]; + memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1); } //adjust for name. - bufptr += strlen(emu->name[r]); + bufptr += strlen(emu->Name[r]); { //post-name section... structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->beard = emu->beard[r]; - eq2->haircolor = emu->haircolor[r]; - eq2->face = emu->face[r]; + eq2->Beard = emu->Beard[r]; + eq2->HairColor = emu->HairColor[r]; + eq2->Face = emu->Face[r]; int k; for (k = 0; k < _MaterialCount; k++) { - eq2->equip[k].material = emu->equip[r][k].material; - eq2->equip[k].unknown1 = emu->equip[r][k].unknown1; - eq2->equip[k].elitematerial = emu->equip[r][k].elitematerial; - eq2->equip[k].color.color = emu->equip[r][k].color.color; + eq2->Equip[k].Material = emu->Equip[r][k].Material; + eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1; + eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial; + eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color; } - eq2->primary = emu->primary[r]; - eq2->secondary = emu->secondary[r]; - eq2->tutorial = emu->tutorial[r]; // was u15 - eq2->u15 = 0xff; - eq2->deity = emu->deity[r]; - eq2->zone = emu->zone[r]; - eq2->u19 = 0xFF; - eq2->race = emu->race[r]; - eq2->gohome = emu->gohome[r]; - eq2->class_ = emu->class_[r]; - eq2->eyecolor1 = emu->eyecolor1[r]; - eq2->beardcolor = emu->beardcolor[r]; - eq2->eyecolor2 = emu->eyecolor2[r]; - eq2->drakkin_heritage = emu->drakkin_heritage[r]; - eq2->drakkin_tattoo = emu->drakkin_tattoo[r]; - eq2->drakkin_details = emu->drakkin_details[r]; + eq2->Primary = emu->Primary[r]; + eq2->Secondary = emu->Secondary[r]; + eq2->Tutorial = emu->Tutorial[r]; // was u15 + eq2->Unknown15 = 0xFF; + eq2->Deity = emu->Deity[r]; + eq2->Zone = emu->Zone[r]; + eq2->Unknown19 = 0xFF; + eq2->Race = emu->Race[r]; + eq2->GoHome = emu->GoHome[r]; + eq2->Class_ = emu->Class_[r]; + eq2->EyeColor1 = emu->EyeColor1[r]; + eq2->BeardColor = emu->BeardColor[r]; + eq2->EyeColor2 = emu->EyeColor2[r]; + eq2->DrakkinHeritage = emu->DrakkinHeritage[r]; + eq2->DrakkinTattoo = emu->DrakkinTattoo[r]; + eq2->DrakkinDetails = emu->DrakkinDetails[r]; } bufptr += sizeof(structs::CharacterSelectEntry_Struct); } @@ -2375,7 +2375,7 @@ namespace SoD OUT(material); OUT(unknown06); OUT(elite_material); - OUT(color.color); + OUT(color.Color); OUT(wear_slot_id); FINISH_ENCODE(); @@ -2743,7 +2743,7 @@ namespace SoD for (k = 0; k < 9; ++k) { { - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].color); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].Color); } } } @@ -2753,11 +2753,11 @@ namespace SoD VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); } @@ -2768,9 +2768,9 @@ namespace SoD structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer; for (k = 0; k < 9; k++) { - Equipment[k].material = emu->equipment[k].material; - Equipment[k].unknown1 = emu->equipment[k].unknown1; - Equipment[k].elitematerial = emu->equipment[k].elitematerial; + Equipment[k].Material = emu->equipment[k].Material; + Equipment[k].Unknown1 = emu->equipment[k].Unknown1; + Equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial; } Buffer += (sizeof(structs::EquipStruct) * 9); @@ -3485,7 +3485,7 @@ namespace SoD IN(material); IN(unknown06); IN(elite_material); - IN(color.color); + IN(color.Color); IN(wear_slot_id); emu->hero_forge_model = 0; emu->unknown18 = 0; diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index f929ec744..f18e3d2f6 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -103,54 +103,53 @@ struct AdventureInfo { */ struct Color_Struct { - union - { - struct - { - uint8 blue; - uint8 green; - uint8 red; - uint8 use_tint; // if there's a tint this is FF - } rgb; - uint32 color; + union { + struct { + uint8 Blue; + uint8 Green; + uint8 Red; + uint8 UseTint; // if there's a tint this is FF + } RGB; + uint32 Color; }; }; -struct CharSelectEquip { - //totally guessed; - uint32 material; - uint32 unknown1; - uint32 elitematerial; - Color_Struct color; +struct CharSelectEquip +{ + uint32 Material; + uint32 Unknown1; + uint32 EliteMaterial; + Color_Struct Color; }; -struct CharacterSelectEntry_Struct { -/*0000*/ uint8 level; // -/*0000*/ uint8 hairstyle; // -/*0002*/ uint8 gender; // -/*0003*/ char name[1]; //variable length, edi+0 -/*0000*/ uint8 beard; // -/*0001*/ uint8 haircolor; // -/*0000*/ uint8 face; // -/*0000*/ CharSelectEquip equip[9]; -/*0000*/ uint32 primary; // -/*0000*/ uint32 secondary; // -/*0000*/ uint8 u15; // 0xff -/*0000*/ uint32 deity; // -/*0000*/ uint16 zone; // -/*0000*/ uint16 instance; -/*0000*/ uint8 gohome; // -/*0000*/ uint8 u19; // 0xff -/*0000*/ uint32 race; // -/*0000*/ uint8 tutorial; // -/*0000*/ uint8 class_; // -/*0000*/ uint8 eyecolor1; // -/*0000*/ uint8 beardcolor; // -/*0000*/ uint8 eyecolor2; // -/*0000*/ uint32 drakkin_heritage; // Drakkin Heritage -/*0000*/ uint32 drakkin_tattoo; // Drakkin Tattoo -/*0000*/ uint32 drakkin_details; // Drakkin Details (Facial Spikes) -/*0000*/ uint8 unknown; // New field to SoD +struct CharacterSelectEntry_Struct +{ +/*0000*/ uint8 Level; // +/*0000*/ uint8 HairStyle; // +/*0002*/ uint8 Gender; // +/*0003*/ char Name[1]; // variable length, edi+0 +/*0000*/ uint8 Beard; // +/*0001*/ uint8 HairColor; // +/*0000*/ uint8 Face; // +/*0000*/ CharSelectEquip Equip[9]; +/*0000*/ uint32 Primary; // +/*0000*/ uint32 Secondary; // +/*0000*/ uint8 Unknown15; // 0xff +/*0000*/ uint32 Deity; // +/*0000*/ uint16 Zone; // +/*0000*/ uint16 Instance; +/*0000*/ uint8 GoHome; // +/*0000*/ uint8 Unknown19; // 0xff +/*0000*/ uint32 Race; // +/*0000*/ uint8 Tutorial; // +/*0000*/ uint8 Class_; // +/*0000*/ uint8 EyeColor1; // +/*0000*/ uint8 BeardColor; // +/*0000*/ uint8 EyeColor2; // +/*0000*/ uint32 DrakkinHeritage; // Drakkin Heritage +/*0000*/ uint32 DrakkinTattoo; // Drakkin Tattoo +/*0000*/ uint32 DrakkinDetails; // Drakkin Details (Facial Spikes) +/*0000*/ uint8 Unknown; // New field to SoD }; @@ -158,20 +157,22 @@ struct CharacterSelectEntry_Struct { ** Character Selection Struct ** */ -struct CharacterSelect_Struct { -/*0000*/ uint32 char_count; //number of chars in this packet -/*0004*/ uint32 total_chars; //total number of chars allowed? -/*0008*/ CharacterSelectEntry_Struct entries[0]; +struct CharacterSelect_Struct +{ +/*0000*/ uint32 CharCount; //number of chars in this packet +/*0004*/ uint32 TotalChars; //total number of chars allowed? +/*0008*/ CharacterSelectEntry_Struct Entries[0]; }; /* * Visible equiptment. * Size: 12 Octets */ -struct EquipStruct { -/*00*/ uint32 material; -/*04*/ uint32 unknown1; -/*08*/ uint32 elitematerial; +struct EquipStruct +{ +/*00*/ uint32 Material; +/*04*/ uint32 Unknown1; +/*08*/ uint32 EliteMaterial; /*12*/ }; diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index 4ba534ac7..5220a0a6e 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1200,13 +1200,13 @@ namespace SoF OUT(beard); // OUT(unknown00178[10]); for (r = 0; r < 9; r++) { - eq->equipment[r].material = emu->item_material[r]; - eq->equipment[r].unknown1 = 0; - eq->equipment[r].elitematerial = 0; + eq->equipment[r].Material = emu->item_material[r]; + eq->equipment[r].Unknown1 = 0; + eq->equipment[r].EliteMaterial = 0; //eq->colors[r].color = emu->colors[r].color; } for (r = 0; r < 7; r++) { - OUT(item_tint[r].color); + OUT(item_tint[r].Color); } // OUT(unknown00224[48]); //NOTE: new client supports 300 AAs, our internal rep/PP @@ -1579,11 +1579,11 @@ namespace SoF int char_count; int namelen = 0; for (char_count = 0; char_count < 10; char_count++) { - if (emu->name[char_count][0] == '\0') + if (emu->Name[char_count][0] == '\0') break; - if (strcmp(emu->name[char_count], "") == 0) + if (strcmp(emu->Name[char_count], "") == 0) break; - namelen += strlen(emu->name[char_count]); + namelen += strlen(emu->Name[char_count]); } int total_length = sizeof(structs::CharacterSelect_Struct) @@ -1595,49 +1595,49 @@ namespace SoF //unsigned char *eq_buffer = new unsigned char[total_length]; //structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer; - eq->char_count = char_count; - eq->total_chars = 10; + eq->CharCount = char_count; + eq->TotalChars = 10; - unsigned char *bufptr = (unsigned char *)eq->entries; + unsigned char *bufptr = (unsigned char *)eq->Entries; int r; for (r = 0; r < char_count; r++) { { //pre-name section... structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->level = emu->level[r]; - eq2->hairstyle = emu->hairstyle[r]; - eq2->gender = emu->gender[r]; - memcpy(eq2->name, emu->name[r], strlen(emu->name[r]) + 1); + eq2->Level = emu->Level[r]; + eq2->HairStyle = emu->HairStyle[r]; + eq2->Gender = emu->Gender[r]; + memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1); } //adjust for name. - bufptr += strlen(emu->name[r]); + bufptr += strlen(emu->Name[r]); { //post-name section... structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->beard = emu->beard[r]; - eq2->haircolor = emu->haircolor[r]; - eq2->face = emu->face[r]; + eq2->Beard = emu->Beard[r]; + eq2->HairColor = emu->HairColor[r]; + eq2->Face = emu->Face[r]; int k; for (k = 0; k < _MaterialCount; k++) { - eq2->equip[k].material = emu->equip[r][k].material; - eq2->equip[k].unknown1 = emu->equip[r][k].unknown1; - eq2->equip[k].elitematerial = emu->equip[r][k].elitematerial; - eq2->equip[k].color.color = emu->equip[r][k].color.color; + eq2->Equip[k].Material = emu->Equip[r][k].Material; + eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1; + eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial; + eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color; } - eq2->primary = emu->primary[r]; - eq2->secondary = emu->secondary[r]; - eq2->tutorial = emu->tutorial[r]; // was u15 - eq2->u15 = 0xff; - eq2->deity = emu->deity[r]; - eq2->zone = emu->zone[r]; - eq2->u19 = 0xFF; - eq2->race = emu->race[r]; - eq2->gohome = emu->gohome[r]; - eq2->class_ = emu->class_[r]; - eq2->eyecolor1 = emu->eyecolor1[r]; - eq2->beardcolor = emu->beardcolor[r]; - eq2->eyecolor2 = emu->eyecolor2[r]; - eq2->drakkin_heritage = emu->drakkin_heritage[r]; - eq2->drakkin_tattoo = emu->drakkin_tattoo[r]; - eq2->drakkin_details = emu->drakkin_details[r]; + eq2->Primary = emu->Primary[r]; + eq2->Secondary = emu->Secondary[r]; + eq2->Tutorial = emu->Tutorial[r]; // was u15 + eq2->Unknown15 = 0xff; + eq2->Deity = emu->Deity[r]; + eq2->Zone = emu->Zone[r]; + eq2->Unknown19 = 0xFF; + eq2->Race = emu->Race[r]; + eq2->GoHome = emu->GoHome[r]; + eq2->Class_ = emu->Class_[r]; + eq2->EyeColor1 = emu->EyeColor1[r]; + eq2->BeardColor = emu->BeardColor[r]; + eq2->EyeColor2 = emu->EyeColor2[r]; + eq2->DrakkinHeritage = emu->DrakkinHeritage[r]; + eq2->DrakkinTattoo = emu->DrakkinTattoo[r]; + eq2->DrakkinDetails = emu->DrakkinDetails[r]; } bufptr += sizeof(structs::CharacterSelectEntry_Struct); } @@ -1961,7 +1961,7 @@ namespace SoF OUT(material); OUT(unknown06); OUT(elite_material); - OUT(color.color); + OUT(color.Color); OUT(wear_slot_id); FINISH_ENCODE(); @@ -2045,10 +2045,10 @@ namespace SoF eq->drakkin_heritage = emu->drakkin_heritage; eq->gender = emu->gender; for (k = 0; k < 9; k++) { - eq->equipment[k].material = emu->equipment[k].material; - eq->equipment[k].unknown1 = emu->equipment[k].unknown1; - eq->equipment[k].elitematerial = emu->equipment[k].elitematerial; - eq->colors[k].color = emu->colors[k].color; + eq->equipment[k].Material = emu->equipment[k].Material; + eq->equipment[k].Unknown1 = emu->equipment[k].Unknown1; + eq->equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial; + eq->colors[k].Color = emu->colors[k].Color; } eq->StandState = emu->StandState; eq->guildID = emu->guildID; @@ -2110,7 +2110,7 @@ namespace SoF eq->petOwnerId = emu->petOwnerId; eq->pvp = 0; // 0 = non-pvp colored name, 1 = red pvp name for (k = 0; k < 9; k++) { - eq->colors[k].color = emu->colors[k].color; + eq->colors[k].Color = emu->colors[k].Color; } eq->anon = emu->anon; eq->face = emu->face; @@ -2809,7 +2809,7 @@ namespace SoF IN(material); IN(unknown06); IN(elite_material); - IN(color.color); + IN(color.Color); IN(wear_slot_id); emu->hero_forge_model = 0; emu->unknown18 = 0; diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index 1510ded59..e66ace468 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -103,72 +103,74 @@ struct AdventureInfo { */ struct Color_Struct { - union - { - struct - { - uint8 blue; - uint8 green; - uint8 red; - uint8 use_tint; // if there's a tint this is FF - } rgb; - uint32 color; + union { + struct { + uint8 Blue; + uint8 Green; + uint8 Red; + uint8 UseTint; // if there's a tint this is FF + } RGB; + uint32 Color; }; }; -struct CharSelectEquip { - uint32 material; - uint32 unknown1; - uint32 elitematerial; - Color_Struct color; +struct CharSelectEquip +{ + uint32 Material; + uint32 Unknown1; + uint32 EliteMaterial; + Color_Struct Color; }; -struct CharacterSelectEntry_Struct { -/*0000*/ uint8 level; // -/*0000*/ uint8 hairstyle; // -/*0002*/ uint8 gender; // -/*0003*/ char name[1]; //variable length, edi+0 -/*0000*/ uint8 beard; // -/*0001*/ uint8 haircolor; // -/*0000*/ uint8 face; // -/*0000*/ CharSelectEquip equip[9]; -/*0000*/ uint32 primary; // -/*0000*/ uint32 secondary; // -/*0000*/ uint8 u15; // 0xff -/*0000*/ uint32 deity; // -/*0000*/ uint16 zone; // -/*0000*/ uint16 instance; -/*0000*/ uint8 gohome; // -/*0000*/ uint8 u19; // 0xff -/*0000*/ uint32 race; // -/*0000*/ uint8 tutorial; // -/*0000*/ uint8 class_; // -/*0000*/ uint8 eyecolor1; // -/*0000*/ uint8 beardcolor; // -/*0000*/ uint8 eyecolor2; // -/*0000*/ uint32 drakkin_heritage; // Drakkin Heritage -/*0000*/ uint32 drakkin_tattoo; // Drakkin Tattoo -/*0000*/ uint32 drakkin_details; // Drakkin Details (Facial Spikes) +struct CharacterSelectEntry_Struct +{ +/*0000*/ uint8 Level; // +/*0000*/ uint8 HairStyle; // +/*0002*/ uint8 Gender; // +/*0003*/ char Name[1]; // variable length, edi+0 +/*0000*/ uint8 Beard; // +/*0001*/ uint8 HairColor; // +/*0000*/ uint8 Face; // +/*0000*/ CharSelectEquip Equip[9]; +/*0000*/ uint32 Primary; // +/*0000*/ uint32 Secondary; // +/*0000*/ uint8 Unknown15; // 0xff +/*0000*/ uint32 Deity; // +/*0000*/ uint16 Zone; // +/*0000*/ uint16 Instance; +/*0000*/ uint8 GoHome; // +/*0000*/ uint8 Unknown19; // 0xff +/*0000*/ uint32 Race; // +/*0000*/ uint8 Tutorial; // +/*0000*/ uint8 Class_; // +/*0000*/ uint8 EyeColor1; // +/*0000*/ uint8 BeardColor; // +/*0000*/ uint8 EyeColor2; // +/*0000*/ uint32 DrakkinHeritage; // Drakkin Heritage +/*0000*/ uint32 DrakkinTattoo; // Drakkin Tattoo +/*0000*/ uint32 DrakkinDetails; // Drakkin Details (Facial Spikes) }; /* ** Character Selection Struct ** */ -struct CharacterSelect_Struct { -/*0000*/ uint32 char_count; //number of chars in this packet -/*0004*/ uint32 total_chars; //total number of chars allowed? -/*0008*/ CharacterSelectEntry_Struct entries[0]; +struct CharacterSelect_Struct +{ +/*0000*/ uint32 CharCount; //number of chars in this packet +/*0004*/ uint32 TotalChars; //total number of chars allowed? +/*0008*/ CharacterSelectEntry_Struct Entries[0]; }; /* * Visible equiptment. * Size: 12 Octets */ -struct EquipStruct { -/*00*/ uint32 material; -/*04*/ uint32 unknown1; -/*08*/ uint32 elitematerial; +struct EquipStruct +{ +/*00*/ uint32 Material; +/*04*/ uint32 Unknown1; +/*08*/ uint32 EliteMaterial; /*12*/ }; diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index d048f0e5d..e636b6a9c 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -865,7 +865,7 @@ namespace Titanium // OUT(unknown00178[10]); for (r = 0; r < 9; r++) { OUT(item_material[r]); - OUT(item_tint[r].color); + OUT(item_tint[r].Color); } // OUT(unknown00224[48]); for (r = 0; r < structs::MAX_PP_AA_ARRAY; r++) { @@ -1160,34 +1160,34 @@ namespace Titanium int r; for (r = 0; r < 10; r++) { - OUT(zone[r]); - OUT(eyecolor1[r]); - OUT(eyecolor2[r]); - OUT(hairstyle[r]); - OUT(primary[r]); - if (emu->race[r] > 473) - eq->race[r] = 1; + OUT(Zone[r]); + OUT(EyeColor1[r]); + OUT(EyeColor2[r]); + OUT(HairStyle[r]); + OUT(Primary[r]); + if (emu->Race[r] > 473) + eq->Race[r] = 1; else - eq->race[r] = emu->race[r]; - OUT(class_[r]); - OUT_str(name[r]); - OUT(gender[r]); - OUT(level[r]); - OUT(secondary[r]); - OUT(face[r]); - OUT(beard[r]); + eq->Race[r] = emu->Race[r]; + OUT(Class_[r]); + OUT_str(Name[r]); + OUT(Gender[r]); + OUT(Level[r]); + OUT(Secondary[r]); + OUT(Face[r]); + OUT(Beard[r]); int k; for (k = 0; k < 9; k++) { - eq->equip[r][k] = emu->equip[r][k].material; - eq->cs_colors[r][k].color = emu->equip[r][k].color.color; + eq->Equip[r][k] = emu->Equip[r][k].Material; + eq->CS_Colors[r][k].Color = emu->Equip[r][k].Color.Color; } - OUT(haircolor[r]); - OUT(gohome[r]); - OUT(tutorial[r]); - OUT(deity[r]); - OUT(beardcolor[r]); - eq->unknown820[r] = 0xFF; - eq->unknown902[r] = 0xFF; + OUT(HairColor[r]); + OUT(GoHome[r]); + OUT(Tutorial[r]); + OUT(Deity[r]); + OUT(BeardColor[r]); + eq->Unknown820[r] = 0xFF; + eq->Unknown902[r] = 0xFF; } FINISH_ENCODE(); @@ -1405,7 +1405,7 @@ namespace Titanium OUT(spawn_id); OUT(material); - OUT(color.color); + OUT(color.Color); OUT(wear_slot_id); FINISH_ENCODE(); @@ -1497,8 +1497,8 @@ namespace Titanium eq->guildrank = emu->guildrank; // eq->unknown0194[3] = emu->unknown0194[3]; for (k = 0; k < 9; k++) { - eq->equipment[k] = emu->equipment[k].material; - eq->colors[k].color = emu->colors[k].color; + eq->equipment[k] = emu->equipment[k].Material; + eq->colors[k].Color = emu->colors[k].Color; } for (k = 0; k < 8; k++) { eq->set_to_0xFF[k] = 0xFF; @@ -1974,7 +1974,7 @@ namespace Titanium IN(spawn_id); IN(material); - IN(color.color); + IN(color.Color); IN(wear_slot_id); emu->unknown06 = 0; emu->elite_material = 0; diff --git a/common/patches/titanium_structs.h b/common/patches/titanium_structs.h index 9a165a33d..a61b96a94 100644 --- a/common/patches/titanium_structs.h +++ b/common/patches/titanium_structs.h @@ -99,16 +99,14 @@ struct AdventureInfo { */ struct Color_Struct { - union - { - struct - { - uint8 blue; - uint8 green; - uint8 red; - uint8 use_tint; // if there's a tint this is FF - } rgb; - uint32 color; + union { + struct { + uint8 Blue; + uint8 Green; + uint8 Red; + uint8 UseTint; // if there's a tint this is FF + } RGB; + uint32 Color; }; }; @@ -117,31 +115,32 @@ struct Color_Struct ** Length: 1704 Bytes ** */ -struct CharacterSelect_Struct { -/*0000*/ uint32 race[10]; // Characters Race -/*0040*/ Color_Struct cs_colors[10][9]; // Characters Equipment Colors -/*0400*/ uint8 beardcolor[10]; // Characters beard Color -/*0410*/ uint8 hairstyle[10]; // Characters hair style -/*0420*/ uint32 equip[10][9]; // 0=helm, 1=chest, 2=arm, 3=bracer, 4=hand, 5=leg, 6=boot, 7=melee1, 8=melee2 (Might not be) -/*0780*/ uint32 secondary[10]; // Characters secondary IDFile number -/*0820*/ uint8 unknown820[10]; // 10x ff -/*0830*/ uint8 unknown830[2]; // 2x 00 -/*0832*/ uint32 deity[10]; // Characters Deity -/*0872*/ uint8 gohome[10]; // 1=Go Home available, 0=not -/*0882*/ uint8 tutorial[10]; // 1=Tutorial available, 0=not -/*0892*/ uint8 beard[10]; // Characters Beard Type -/*0902*/ uint8 unknown902[10]; // 10x ff -/*0912*/ uint32 primary[10]; // Characters primary IDFile number -/*0952*/ uint8 haircolor[10]; // Characters Hair Color -/*0962*/ uint8 unknown0962[2]; // 2x 00 -/*0964*/ uint32 zone[10]; // Characters Current Zone -/*1004*/ uint8 class_[10]; // Characters Classes -/*1014*/ uint8 face[10]; // Characters Face Type -/*1024*/ char name[10][64]; // Characters Names -/*1664*/ uint8 gender[10]; // Characters Gender -/*1674*/ uint8 eyecolor1[10]; // Characters Eye Color -/*1684*/ uint8 eyecolor2[10]; // Characters Eye 2 Color -/*1694*/ uint8 level[10]; // Characters Levels +struct CharacterSelect_Struct +{ +/*0000*/ uint32 Race[10]; // Characters Race +/*0040*/ Color_Struct CS_Colors[10][9]; // Characters Equipment Colors +/*0400*/ uint8 BeardColor[10]; // Characters beard Color +/*0410*/ uint8 HairStyle[10]; // Characters hair style +/*0420*/ uint32 Equip[10][9]; // 0=helm, 1=chest, 2=arm, 3=bracer, 4=hand, 5=leg, 6=boot, 7=melee1, 8=melee2 (Might not be) +/*0780*/ uint32 Secondary[10]; // Characters secondary IDFile number +/*0820*/ uint8 Unknown820[10]; // 10x ff +/*0830*/ uint8 Unknown830[2]; // 2x 00 +/*0832*/ uint32 Deity[10]; // Characters Deity +/*0872*/ uint8 GoHome[10]; // 1=Go Home available, 0=not +/*0882*/ uint8 Tutorial[10]; // 1=Tutorial available, 0=not +/*0892*/ uint8 Beard[10]; // Characters Beard Type +/*0902*/ uint8 Unknown902[10]; // 10x ff +/*0912*/ uint32 Primary[10]; // Characters primary IDFile number +/*0952*/ uint8 HairColor[10]; // Characters Hair Color +/*0962*/ uint8 Unknown0962[2]; // 2x 00 +/*0964*/ uint32 Zone[10]; // Characters Current Zone +/*1004*/ uint8 Class_[10]; // Characters Classes +/*1014*/ uint8 Face[10]; // Characters Face Type +/*1024*/ char Name[10][64]; // Characters Names +/*1664*/ uint8 Gender[10]; // Characters Gender +/*1674*/ uint8 EyeColor1[10]; // Characters Eye Color +/*1684*/ uint8 EyeColor2[10]; // Characters Eye 2 Color +/*1694*/ uint8 Level[10]; // Characters Levels /*1704*/ }; diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 991b35aa4..18ea67af0 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -1791,13 +1791,13 @@ namespace UF OUT(beard); // OUT(unknown00178[10]); for (r = 0; r < 9; r++) { - eq->equipment[r].material = emu->item_material[r]; - eq->equipment[r].unknown1 = 0; - eq->equipment[r].elitematerial = 0; + eq->equipment[r].Material = emu->item_material[r]; + eq->equipment[r].Unknown1 = 0; + eq->equipment[r].EliteMaterial = 0; //eq->colors[r].color = emu->colors[r].color; } for (r = 0; r < 7; r++) { - OUT(item_tint[r].color); + OUT(item_tint[r].Color); } // OUT(unknown00224[48]); //NOTE: new client supports 300 AAs, our internal rep/PP @@ -2203,11 +2203,11 @@ namespace UF int char_count; int namelen = 0; for (char_count = 0; char_count < 10; char_count++) { - if (emu->name[char_count][0] == '\0') + if (emu->Name[char_count][0] == '\0') break; - if (strcmp(emu->name[char_count], "") == 0) + if (strcmp(emu->Name[char_count], "") == 0) break; - namelen += strlen(emu->name[char_count]); + namelen += strlen(emu->Name[char_count]); } int total_length = sizeof(structs::CharacterSelect_Struct) @@ -2219,49 +2219,49 @@ namespace UF //unsigned char *eq_buffer = new unsigned char[total_length]; //structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer; - eq->char_count = char_count; - eq->total_chars = 10; + eq->CharCount = char_count; + eq->TotalChars = 10; - unsigned char *bufptr = (unsigned char *)eq->entries; + unsigned char *bufptr = (unsigned char *)eq->Entries; int r; for (r = 0; r < char_count; r++) { { //pre-name section... structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->level = emu->level[r]; - eq2->hairstyle = emu->hairstyle[r]; - eq2->gender = emu->gender[r]; - memcpy(eq2->name, emu->name[r], strlen(emu->name[r]) + 1); + eq2->Level = emu->Level[r]; + eq2->HairStyle = emu->HairStyle[r]; + eq2->Gender = emu->Gender[r]; + memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1); } //adjust for name. - bufptr += strlen(emu->name[r]); + bufptr += strlen(emu->Name[r]); { //post-name section... structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->beard = emu->beard[r]; - eq2->haircolor = emu->haircolor[r]; - eq2->face = emu->face[r]; + eq2->Beard = emu->Beard[r]; + eq2->HairColor = emu->HairColor[r]; + eq2->Face = emu->Face[r]; int k; for (k = 0; k < _MaterialCount; k++) { - eq2->equip[k].material = emu->equip[r][k].material; - eq2->equip[k].unknown1 = emu->equip[r][k].unknown1; - eq2->equip[k].elitematerial = emu->equip[r][k].elitematerial; - eq2->equip[k].color.color = emu->equip[r][k].color.color; + eq2->Equip[k].Material = emu->Equip[r][k].Material; + eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1; + eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial; + eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color; } - eq2->primary = emu->primary[r]; - eq2->secondary = emu->secondary[r]; - eq2->tutorial = emu->tutorial[r]; // was u15 - eq2->u15 = 0xff; - eq2->deity = emu->deity[r]; - eq2->zone = emu->zone[r]; - eq2->u19 = 0xFF; - eq2->race = emu->race[r]; - eq2->gohome = emu->gohome[r]; - eq2->class_ = emu->class_[r]; - eq2->eyecolor1 = emu->eyecolor1[r]; - eq2->beardcolor = emu->beardcolor[r]; - eq2->eyecolor2 = emu->eyecolor2[r]; - eq2->drakkin_heritage = emu->drakkin_heritage[r]; - eq2->drakkin_tattoo = emu->drakkin_tattoo[r]; - eq2->drakkin_details = emu->drakkin_details[r]; + eq2->Primary = emu->Primary[r]; + eq2->Secondary = emu->Secondary[r]; + eq2->Tutorial = emu->Tutorial[r]; // was u15 + eq2->Unknown15 = 0xFF; + eq2->Deity = emu->Deity[r]; + eq2->Zone = emu->Zone[r]; + eq2->Unknown19 = 0xFF; + eq2->Race = emu->Race[r]; + eq2->GoHome = emu->GoHome[r]; + eq2->Class_ = emu->Class_[r]; + eq2->EyeColor1 = emu->EyeColor1[r]; + eq2->BeardColor = emu->BeardColor[r]; + eq2->EyeColor2 = emu->EyeColor2[r]; + eq2->DrakkinHeritage = emu->DrakkinHeritage[r]; + eq2->DrakkinTattoo = emu->DrakkinTattoo[r]; + eq2->DrakkinDetails = emu->DrakkinDetails[r]; } bufptr += sizeof(structs::CharacterSelectEntry_Struct); @@ -2641,7 +2641,7 @@ namespace UF OUT(material); OUT(unknown06); OUT(elite_material); - OUT(color.color); + OUT(color.Color); OUT(wear_slot_id); FINISH_ENCODE(); @@ -3003,7 +3003,7 @@ namespace UF for (k = 0; k < 9; ++k) { { - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].color); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->colors[k].Color); } } } @@ -3013,11 +3013,11 @@ namespace UF VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialPrimary].Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); - VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].material); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->equipment[MaterialSecondary].Material); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 0); } @@ -3027,9 +3027,9 @@ namespace UF structs::EquipStruct *Equipment = (structs::EquipStruct *)Buffer; for (k = 0; k < 9; k++) { - Equipment[k].material = emu->equipment[k].material; - Equipment[k].unknown1 = emu->equipment[k].unknown1; - Equipment[k].elitematerial = emu->equipment[k].elitematerial; + Equipment[k].Material = emu->equipment[k].Material; + Equipment[k].Unknown1 = emu->equipment[k].Unknown1; + Equipment[k].EliteMaterial = emu->equipment[k].EliteMaterial; } Buffer += (sizeof(structs::EquipStruct) * 9); @@ -3729,7 +3729,7 @@ namespace UF IN(material); IN(unknown06); IN(elite_material); - IN(color.color); + IN(color.Color); IN(wear_slot_id); emu->hero_forge_model = 0; emu->unknown18 = 0; diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index f33ab7b4c..ec912b681 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -103,53 +103,53 @@ struct AdventureInfo { */ struct Color_Struct { - union - { - struct - { - uint8 blue; - uint8 green; - uint8 red; - uint8 use_tint; // if there's a tint this is FF - } rgb; - uint32 color; + union { + struct { + uint8 blue; + uint8 Green; + uint8 Red; + uint8 UseTint; // if there's a tint this is FF + } RGB; + uint32 Color; }; }; -struct CharSelectEquip { - uint32 material; - uint32 unknown1; - uint32 elitematerial; - Color_Struct color; +struct CharSelectEquip +{ + uint32 Material; + uint32 Unknown1; + uint32 EliteMaterial; + Color_Struct Color; }; -struct CharacterSelectEntry_Struct { -/*0000*/ uint8 level; // -/*0000*/ uint8 hairstyle; // -/*0002*/ uint8 gender; // -/*0003*/ char name[1]; //variable length, edi+0 -/*0000*/ uint8 beard; // -/*0001*/ uint8 haircolor; // -/*0000*/ uint8 face; // -/*0000*/ CharSelectEquip equip[9]; -/*0000*/ uint32 primary; // -/*0000*/ uint32 secondary; // -/*0000*/ uint8 u15; // 0xff -/*0000*/ uint32 deity; // -/*0000*/ uint16 zone; // -/*0000*/ uint16 instance; -/*0000*/ uint8 gohome; // -/*0000*/ uint8 u19; // 0xff -/*0000*/ uint32 race; // -/*0000*/ uint8 tutorial; // -/*0000*/ uint8 class_; // -/*0000*/ uint8 eyecolor1; // -/*0000*/ uint8 beardcolor; // -/*0000*/ uint8 eyecolor2; // -/*0000*/ uint32 drakkin_heritage; // Drakkin Heritage -/*0000*/ uint32 drakkin_tattoo; // Drakkin Tattoo -/*0000*/ uint32 drakkin_details; // Drakkin Details (Facial Spikes) -/*0000*/ uint8 unknown; // New field to Underfoot +struct CharacterSelectEntry_Struct +{ +/*0000*/ uint8 Level; // +/*0000*/ uint8 HairStyle; // +/*0002*/ uint8 Gender; // +/*0003*/ char Name[1]; // variable length, edi+0 +/*0000*/ uint8 Beard; // +/*0001*/ uint8 HairColor; // +/*0000*/ uint8 Face; // +/*0000*/ CharSelectEquip Equip[9]; +/*0000*/ uint32 Primary; // +/*0000*/ uint32 Secondary; // +/*0000*/ uint8 Unknown15; // 0xff +/*0000*/ uint32 Deity; // +/*0000*/ uint16 Zone; // +/*0000*/ uint16 Instance; +/*0000*/ uint8 GoHome; // +/*0000*/ uint8 Unknown19; // 0xff +/*0000*/ uint32 Race; // +/*0000*/ uint8 Tutorial; // +/*0000*/ uint8 Class_; // +/*0000*/ uint8 EyeColor1; // +/*0000*/ uint8 BeardColor; // +/*0000*/ uint8 EyeColor2; // +/*0000*/ uint32 DrakkinHeritage; // Drakkin Heritage +/*0000*/ uint32 DrakkinTattoo; // Drakkin Tattoo +/*0000*/ uint32 DrakkinDetails; // Drakkin Details (Facial Spikes) +/*0000*/ uint8 Unknown; // New field to Underfoot }; @@ -157,20 +157,22 @@ struct CharacterSelectEntry_Struct { ** Character Selection Struct ** */ -struct CharacterSelect_Struct { -/*0000*/ uint32 char_count; //number of chars in this packet -/*0004*/ uint32 total_chars; //total number of chars allowed? -/*0008*/ CharacterSelectEntry_Struct entries[0]; +struct CharacterSelect_Struct +{ +/*0000*/ uint32 CharCount; //number of chars in this packet +/*0004*/ uint32 TotalChars; //total number of chars allowed? +/*0008*/ CharacterSelectEntry_Struct Entries[0]; }; /* * Visible equiptment. * Size: 12 Octets */ -struct EquipStruct { -/*00*/ uint32 material; -/*04*/ uint32 unknown1; -/*08*/ uint32 elitematerial; +struct EquipStruct +{ +/*00*/ uint32 Material; +/*04*/ uint32 Unknown1; +/*08*/ uint32 EliteMaterial; /*12*/ }; diff --git a/world/client.cpp b/world/client.cpp index f26328e12..55ca440cc 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -724,9 +724,9 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { for(int x = 0; x < 10; ++x) { - if(strcasecmp(cs->name[x], char_name) == 0) + if(strcasecmp(cs->Name[x], char_name) == 0) { - if(cs->gohome[x] == 1) + if(cs->GoHome[x] == 1) { home_enabled = true; break; @@ -754,9 +754,9 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { for(int x = 0; x < 10; ++x) { - if(strcasecmp(cs->name[x], char_name) == 0) + if(strcasecmp(cs->Name[x], char_name) == 0) { - if(cs->tutorial[x] == 1) + if(cs->Tutorial[x] == 1) { tutorial_enabled = true; break; diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 3409a1e17..e47d9d54a 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -41,11 +41,11 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* /* Initialize Variables */ for (int i=0; i<10; i++) { - strcpy(cs->name[i], ""); - cs->zone[i] = 0; - cs->level[i] = 0; - cs->tutorial[i] = 0; - cs->gohome[i] = 0; + strcpy(cs->Name[i], ""); + cs->Zone[i] = 0; + cs->Level[i] = 0; + cs->Tutorial[i] = 0; + cs->GoHome[i] = 0; } /* Get Character Info */ @@ -80,32 +80,32 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* memset(&pp, 0, sizeof(PlayerProfile_Struct)); uint32 character_id = atoi(row[0]); - strcpy(cs->name[char_num], row[1]); + strcpy(cs->Name[char_num], row[1]); uint8 lvl = atoi(row[5]); - cs->level[char_num] = lvl; - cs->class_[char_num] = atoi(row[4]); - cs->race[char_num] = atoi(row[3]); - cs->gender[char_num] = atoi(row[2]); - cs->deity[char_num] = atoi(row[6]); - cs->zone[char_num] = atoi(row[19]); - cs->face[char_num] = atoi(row[15]); - cs->haircolor[char_num] = atoi(row[9]); - cs->beardcolor[char_num] = atoi(row[10]); - cs->eyecolor2[char_num] = atoi(row[12]); - cs->eyecolor1[char_num] = atoi(row[11]); - cs->hairstyle[char_num] = atoi(row[13]); - cs->beard[char_num] = atoi(row[14]); - cs->drakkin_heritage[char_num] = atoi(row[16]); - cs->drakkin_tattoo[char_num] = atoi(row[17]); - cs->drakkin_details[char_num] = atoi(row[18]); + cs->Level[char_num] = lvl; + cs->Class_[char_num] = atoi(row[4]); + cs->Race[char_num] = atoi(row[3]); + cs->Gender[char_num] = atoi(row[2]); + cs->Deity[char_num] = atoi(row[6]); + cs->Zone[char_num] = atoi(row[19]); + cs->Face[char_num] = atoi(row[15]); + cs->HairColor[char_num] = atoi(row[9]); + cs->BeardColor[char_num] = atoi(row[10]); + cs->EyeColor2[char_num] = atoi(row[12]); + cs->EyeColor1[char_num] = atoi(row[11]); + cs->HairStyle[char_num] = atoi(row[13]); + cs->Beard[char_num] = atoi(row[14]); + cs->DrakkinHeritage[char_num] = atoi(row[16]); + cs->DrakkinTattoo[char_num] = atoi(row[17]); + cs->DrakkinDetails[char_num] = atoi(row[18]); if (RuleB(World, EnableTutorialButton) && (lvl <= RuleI(World, MaxLevelForTutorial))) - cs->tutorial[char_num] = 1; + cs->Tutorial[char_num] = 1; if (RuleB(World, EnableReturnHomeButton)) { int now = time(nullptr); if ((now - atoi(row[7])) >= RuleI(World, MinOfflineTimeToReturnHome)) - cs->gohome[char_num] = 1; + cs->GoHome[char_num] = 1; } /* Set Bind Point Data for any character that may possibly be missing it for any reason */ @@ -118,7 +118,7 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* if (has_home == 0 || has_bind == 0){ cquery = StringFormat("SELECT `zone_id`, `bind_id`, `x`, `y`, `z` FROM `start_zones` WHERE `player_class` = %i AND `player_deity` = %i AND `player_race` = %i", - cs->class_[char_num], cs->deity[char_num], cs->race[char_num]); + cs->Class_[char_num], cs->Deity[char_num], cs->Race[char_num]); auto results_bind = database.QueryDatabase(cquery); for (auto row_d = results_bind.begin(); row_d != results_bind.end(); ++row_d) { /* If a bind_id is specified, make them start there */ @@ -161,16 +161,16 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b) { slot = atoi(row_b[0]); - pp.item_tint[slot].rgb.red = atoi(row_b[1]); - pp.item_tint[slot].rgb.green = atoi(row_b[2]); - pp.item_tint[slot].rgb.blue = atoi(row_b[3]); - pp.item_tint[slot].rgb.use_tint = atoi(row_b[4]); + pp.item_tint[slot].RGB.Red = atoi(row_b[1]); + pp.item_tint[slot].RGB.Green = atoi(row_b[2]); + pp.item_tint[slot].RGB.Blue = atoi(row_b[3]); + pp.item_tint[slot].RGB.UseTint = atoi(row_b[4]); } /* Load Inventory */ // If we ensure that the material data is updated appropriately, we can do away with inventory loads inv = new Inventory; - if (GetInventory(account_id, cs->name[char_num], inv)) + if (GetInventory(account_id, cs->Name[char_num], inv)) { const Item_Struct* item = nullptr; const ItemInst* inst = nullptr; @@ -194,31 +194,31 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* if (inst->GetOrnamentationIDFile() != 0) { idfile = inst->GetOrnamentationIDFile(); - cs->equip[char_num][matslot].material = idfile; + cs->Equip[char_num][matslot].Material = idfile; } else { if (strlen(item->IDFile) > 2) { idfile = atoi(&item->IDFile[2]); - cs->equip[char_num][matslot].material = idfile; + cs->Equip[char_num][matslot].Material = idfile; } } if (matslot == MaterialPrimary) { - cs->primary[char_num] = idfile; + cs->Primary[char_num] = idfile; } else { - cs->secondary[char_num] = idfile; + cs->Secondary[char_num] = idfile; } } else { uint32 color = 0; - if (pp.item_tint[matslot].rgb.use_tint) + if (pp.item_tint[matslot].RGB.UseTint) { - color = pp.item_tint[matslot].color; + color = pp.item_tint[matslot].Color; } else { @@ -226,16 +226,16 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* } // Armor Materials/Models - cs->equip[char_num][matslot].material = item->Material; - cs->equip[char_num][matslot].elitematerial = item->EliteMaterial; - cs->equip[char_num][matslot].heroforgemodel = inst->GetOrnamentHeroModel(matslot); - cs->equip[char_num][matslot].color.color = color; + cs->Equip[char_num][matslot].Material = item->Material; + cs->Equip[char_num][matslot].EliteMaterial = item->EliteMaterial; + cs->Equip[char_num][matslot].HeroForgeModel = inst->GetOrnamentHeroModel(matslot); + cs->Equip[char_num][matslot].Color.Color = color; } } } else { - printf("Error loading inventory for %s\n", cs->name[char_num]); + printf("Error loading inventory for %s\n", cs->Name[char_num]); } safe_delete(inv); diff --git a/zone/bot.cpp b/zone/bot.cpp index 4b42fac37..6eb90551f 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -4395,24 +4395,24 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { item = inst->GetItem(); if (item != 0) { - ns->spawn.equipment[i].material = item->Material; - ns->spawn.equipment[i].elitematerial = item->EliteMaterial; - ns->spawn.equipment[i].heroforgemodel = item->HerosForgeModel; + ns->spawn.equipment[i].Material = item->Material; + ns->spawn.equipment[i].EliteMaterial = item->EliteMaterial; + ns->spawn.equipment[i].HeroForgeModel = item->HerosForgeModel; if (armor_tint[i]) { - ns->spawn.colors[i].color = armor_tint[i]; + ns->spawn.colors[i].Color = armor_tint[i]; } else { - ns->spawn.colors[i].color = item->Color; + ns->spawn.colors[i].Color = item->Color; } } else { if (armor_tint[i]) { - ns->spawn.colors[i].color = armor_tint[i]; + ns->spawn.colors[i].Color = armor_tint[i]; } } } @@ -4426,9 +4426,9 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { { if(strlen(item->IDFile) > 2) { - ns->spawn.equipment[MaterialPrimary].material = atoi(&item->IDFile[2]); + ns->spawn.equipment[MaterialPrimary].Material = atoi(&item->IDFile[2]); } - ns->spawn.colors[MaterialPrimary].color = GetEquipmentColor(MaterialPrimary); + ns->spawn.colors[MaterialPrimary].Color = GetEquipmentColor(MaterialPrimary); } } @@ -4440,9 +4440,9 @@ void Bot::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { { if(strlen(item->IDFile) > 2) { - ns->spawn.equipment[MaterialSecondary].material = atoi(&item->IDFile[2]); + ns->spawn.equipment[MaterialSecondary].Material = atoi(&item->IDFile[2]); } - ns->spawn.colors[MaterialSecondary].color = GetEquipmentColor(MaterialSecondary); + ns->spawn.colors[MaterialSecondary].Color = GetEquipmentColor(MaterialSecondary); } } } @@ -5061,7 +5061,7 @@ void Bot::SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 wc->spawn_id = GetID(); wc->material = material; - wc->color.color = color; + wc->color.Color = color; wc->wear_slot_id = material_slot; entity_list.QueueClients(this, outapp); diff --git a/zone/client.cpp b/zone/client.cpp index 816b21e15..227bb4083 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -3039,7 +3039,7 @@ void Client::Tell_StringID(uint32 string_id, const char *who, const char *messag void Client::SetTint(int16 in_slot, uint32 color) { Color_Struct new_color; - new_color.color = color; + new_color.Color = color; SetTint(in_slot, new_color); database.SaveCharacterMaterialColor(this->CharacterID(), in_slot, color); } @@ -3050,8 +3050,8 @@ void Client::SetTint(int16 in_slot, Color_Struct& color) { uint8 matslot = Inventory::CalcMaterialFromSlot(in_slot); if (matslot != _MaterialInvalid) { - m_pp.item_tint[matslot].color = color.color; - database.SaveCharacterMaterialColor(this->CharacterID(), in_slot, color.color); + m_pp.item_tint[matslot].Color = color.Color; + database.SaveCharacterMaterialColor(this->CharacterID(), in_slot, color.Color); } } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 1b866073b..789071848 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1306,9 +1306,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) /* Set item material tint */ for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++) { - if (m_pp.item_tint[i].rgb.use_tint == 1 || m_pp.item_tint[i].rgb.use_tint == 255) + if (m_pp.item_tint[i].RGB.UseTint == 1 || m_pp.item_tint[i].RGB.UseTint == 255) { - m_pp.item_tint[i].rgb.use_tint = 0xFF; + m_pp.item_tint[i].RGB.UseTint = 0xFF; } } diff --git a/zone/command.cpp b/zone/command.cpp index ff81e73ed..612228fde 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -7020,7 +7020,7 @@ void Client::Undye() { database.SaveInventory(CharacterID(), inst, slot2); } - m_pp.item_tint[cur_slot].color = 0; + m_pp.item_tint[cur_slot].Color = 0; SendWearChange(cur_slot); } diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 767159ce7..236128048 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -113,15 +113,15 @@ Corpse* Corpse::LoadCharacterCorpseEntity(uint32 in_dbid, uint32 in_charid, std: pc->Lock(); /* Load Item Tints */ - pc->item_tint[0].color = pcs->item_tint[0].color; - pc->item_tint[1].color = pcs->item_tint[1].color; - pc->item_tint[2].color = pcs->item_tint[2].color; - pc->item_tint[3].color = pcs->item_tint[3].color; - pc->item_tint[4].color = pcs->item_tint[4].color; - pc->item_tint[5].color = pcs->item_tint[5].color; - pc->item_tint[6].color = pcs->item_tint[6].color; - pc->item_tint[7].color = pcs->item_tint[7].color; - pc->item_tint[8].color = pcs->item_tint[8].color; + pc->item_tint[0].Color = pcs->item_tint[0].Color; + pc->item_tint[1].Color = pcs->item_tint[1].Color; + pc->item_tint[2].Color = pcs->item_tint[2].Color; + pc->item_tint[3].Color = pcs->item_tint[3].Color; + pc->item_tint[4].Color = pcs->item_tint[4].Color; + pc->item_tint[5].Color = pcs->item_tint[5].Color; + pc->item_tint[6].Color = pcs->item_tint[6].Color; + pc->item_tint[7].Color = pcs->item_tint[7].Color; + pc->item_tint[8].Color = pcs->item_tint[8].Color; /* Load Physical Appearance */ pc->haircolor = pcs->haircolor; @@ -1413,8 +1413,8 @@ uint32 Corpse::GetEquipmentColor(uint8 material_slot) const { item = database.GetItem(GetEquipment(material_slot)); if(item != NO_ITEM) { - return item_tint[material_slot].rgb.use_tint ? - item_tint[material_slot].color : + return item_tint[material_slot].RGB.UseTint ? + item_tint[material_slot].Color : item->Color; } diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 7f2fa0173..35053731c 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -1984,9 +1984,9 @@ void Client::QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call) { void Client::DyeArmor(DyeStruct* dye){ int16 slot=0; for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_TINT_END; i++) { - if (m_pp.item_tint[i].rgb.blue != dye->dye[i].rgb.blue || - m_pp.item_tint[i].rgb.red != dye->dye[i].rgb.red || - m_pp.item_tint[i].rgb.green != dye->dye[i].rgb.green + if (m_pp.item_tint[i].RGB.Blue != dye->dye[i].RGB.Blue || + m_pp.item_tint[i].RGB.Red != dye->dye[i].RGB.Red || + m_pp.item_tint[i].RGB.Green != dye->dye[i].RGB.Green ) { slot = m_inv.HasItem(32557, 1, invWherePersonal); if (slot != INVALID_INDEX){ @@ -1994,18 +1994,18 @@ void Client::DyeArmor(DyeStruct* dye){ uint8 slot2=SlotConvert(i); ItemInst* inst = this->m_inv.GetItem(slot2); if(inst){ - uint32 armor_color = ((uint32)dye->dye[i].rgb.red << 16) | ((uint32)dye->dye[i].rgb.green << 8) | ((uint32)dye->dye[i].rgb.blue); + uint32 armor_color = ((uint32)dye->dye[i].RGB.Red << 16) | ((uint32)dye->dye[i].RGB.Green << 8) | ((uint32)dye->dye[i].RGB.Blue); inst->SetColor(armor_color); database.SaveCharacterMaterialColor(this->CharacterID(), i, armor_color); database.SaveInventory(CharacterID(),inst,slot2); - if(dye->dye[i].rgb.use_tint) - m_pp.item_tint[i].rgb.use_tint = 0xFF; + if(dye->dye[i].RGB.UseTint) + m_pp.item_tint[i].RGB.UseTint = 0xFF; else - m_pp.item_tint[i].rgb.use_tint=0x00; + m_pp.item_tint[i].RGB.UseTint=0x00; } - m_pp.item_tint[i].rgb.blue=dye->dye[i].rgb.blue; - m_pp.item_tint[i].rgb.red=dye->dye[i].rgb.red; - m_pp.item_tint[i].rgb.green=dye->dye[i].rgb.green; + m_pp.item_tint[i].RGB.Blue=dye->dye[i].RGB.Blue; + m_pp.item_tint[i].RGB.Red=dye->dye[i].RGB.Red; + m_pp.item_tint[i].RGB.Green=dye->dye[i].RGB.Green; SendWearChange(i); } else{ @@ -2420,7 +2420,7 @@ uint32 Client::GetEquipmentColor(uint8 material_slot) const const Item_Struct *item = database.GetItem(GetEquipment(material_slot)); if(item != nullptr) - return ((m_pp.item_tint[material_slot].rgb.use_tint) ? m_pp.item_tint[material_slot].color : item->Color); + return ((m_pp.item_tint[material_slot].RGB.UseTint) ? m_pp.item_tint[material_slot].Color : item->Color); return 0; } diff --git a/zone/mob.cpp b/zone/mob.cpp index ea86ff4dc..57d04f344 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -961,10 +961,10 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) // Only Player Races Wear Armor if (Mob::IsPlayerRace(race) || i > 6) { - ns->spawn.equipment[i].material = GetEquipmentMaterial(i); - ns->spawn.equipment[i].elitematerial = IsEliteMaterialItem(i); - ns->spawn.equipment[i].heroforgemodel = GetHerosForgeModel(i); - ns->spawn.colors[i].color = GetEquipmentColor(i); + ns->spawn.equipment[i].Material = GetEquipmentMaterial(i); + ns->spawn.equipment[i].EliteMaterial = IsEliteMaterialItem(i); + ns->spawn.equipment[i].HeroForgeModel = GetHerosForgeModel(i); + ns->spawn.colors[i].Color = GetEquipmentColor(i); } } @@ -2562,7 +2562,7 @@ void Mob::SendWearChange(uint8 material_slot) wc->material = GetEquipmentMaterial(material_slot); wc->elite_material = IsEliteMaterialItem(material_slot); wc->hero_forge_model = GetHerosForgeModel(material_slot); - wc->color.color = GetEquipmentColor(material_slot); + wc->color.Color = GetEquipmentColor(material_slot); wc->wear_slot_id = material_slot; entity_list.QueueClients(this, outapp); @@ -2577,9 +2577,9 @@ void Mob::SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model, uin wc->spawn_id = this->GetID(); wc->material = texture; if (this->IsClient()) - wc->color.color = GetEquipmentColor(slot); + wc->color.Color = GetEquipmentColor(slot); else - wc->color.color = this->GetArmorTint(slot); + wc->color.Color = this->GetArmorTint(slot); wc->wear_slot_id = slot; wc->unknown06 = unknown06; @@ -2607,7 +2607,7 @@ void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uin wc->spawn_id = this->GetID(); wc->material = GetEquipmentMaterial(material_slot); wc->hero_forge_model = GetHerosForgeModel(material_slot); - wc->color.color = color; + wc->color.Color = color; wc->wear_slot_id = material_slot; entity_list.QueueClients(this, outapp); @@ -2624,7 +2624,7 @@ void Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 h wc->spawn_id = this->GetID(); wc->material = texture; wc->hero_forge_model = hero_forge_model; - wc->color.color = color; + wc->color.Color = color; wc->wear_slot_id = material_slot; entity_list.QueueClients(this, outapp); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index d9e564e29..07a3df930 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1167,10 +1167,10 @@ bool ZoneDatabase::LoadCharacterMaterialColor(uint32 character_id, PlayerProfile for (auto row = results.begin(); row != results.end(); ++row) { r = 0; i = atoi(row[r]); /* Slot */ r++; - pp->item_tint[i].rgb.blue = atoi(row[r]); r++; - pp->item_tint[i].rgb.green = atoi(row[r]); r++; - pp->item_tint[i].rgb.red = atoi(row[r]); r++; - pp->item_tint[i].rgb.use_tint = atoi(row[r]); + pp->item_tint[i].RGB.Blue = atoi(row[r]); r++; + pp->item_tint[i].RGB.Green = atoi(row[r]); r++; + pp->item_tint[i].RGB.Red = atoi(row[r]); r++; + pp->item_tint[i].RGB.UseTint = atoi(row[r]); } return true; } @@ -3546,9 +3546,9 @@ uint32 ZoneDatabase::UpdateCharacterCorpse(uint32 db_id, uint32 char_id, const c dbpc->plat, dbpc->haircolor, dbpc->beardcolor, dbpc->eyecolor1, dbpc->eyecolor2, dbpc->hairstyle, dbpc->face, dbpc->beard, dbpc->drakkin_heritage, dbpc->drakkin_tattoo, dbpc->drakkin_details, - dbpc->item_tint[0].color, dbpc->item_tint[1].color, dbpc->item_tint[2].color, - dbpc->item_tint[3].color, dbpc->item_tint[4].color, dbpc->item_tint[5].color, - dbpc->item_tint[6].color, dbpc->item_tint[7].color, dbpc->item_tint[8].color, + dbpc->item_tint[0].Color, dbpc->item_tint[1].Color, dbpc->item_tint[2].Color, + dbpc->item_tint[3].Color, dbpc->item_tint[4].Color, dbpc->item_tint[5].Color, + dbpc->item_tint[6].Color, dbpc->item_tint[7].Color, dbpc->item_tint[8].Color, db_id); auto results = QueryDatabase(query); @@ -3639,15 +3639,15 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui dbpc->drakkin_heritage, dbpc->drakkin_tattoo, dbpc->drakkin_details, - dbpc->item_tint[0].color, - dbpc->item_tint[1].color, - dbpc->item_tint[2].color, - dbpc->item_tint[3].color, - dbpc->item_tint[4].color, - dbpc->item_tint[5].color, - dbpc->item_tint[6].color, - dbpc->item_tint[7].color, - dbpc->item_tint[8].color + dbpc->item_tint[0].Color, + dbpc->item_tint[1].Color, + dbpc->item_tint[2].Color, + dbpc->item_tint[3].Color, + dbpc->item_tint[4].Color, + dbpc->item_tint[5].Color, + dbpc->item_tint[6].Color, + dbpc->item_tint[7].Color, + dbpc->item_tint[8].Color ); auto results = QueryDatabase(query); uint32 last_insert_id = results.LastInsertedID(); @@ -3819,15 +3819,15 @@ bool ZoneDatabase::LoadCharacterCorpseData(uint32 corpse_id, PlayerCorpse_Struct pcs->drakkin_heritage = atoul(row[i++]); // drakkin_heritage, pcs->drakkin_tattoo = atoul(row[i++]); // drakkin_tattoo, pcs->drakkin_details = atoul(row[i++]); // drakkin_details, - pcs->item_tint[0].color = atoul(row[i++]); // wc_1, - pcs->item_tint[1].color = atoul(row[i++]); // wc_2, - pcs->item_tint[2].color = atoul(row[i++]); // wc_3, - pcs->item_tint[3].color = atoul(row[i++]); // wc_4, - pcs->item_tint[4].color = atoul(row[i++]); // wc_5, - pcs->item_tint[5].color = atoul(row[i++]); // wc_6, - pcs->item_tint[6].color = atoul(row[i++]); // wc_7, - pcs->item_tint[7].color = atoul(row[i++]); // wc_8, - pcs->item_tint[8].color = atoul(row[i++]); // wc_9 + pcs->item_tint[0].Color = atoul(row[i++]); // wc_1, + pcs->item_tint[1].Color = atoul(row[i++]); // wc_2, + pcs->item_tint[2].Color = atoul(row[i++]); // wc_3, + pcs->item_tint[3].Color = atoul(row[i++]); // wc_4, + pcs->item_tint[4].Color = atoul(row[i++]); // wc_5, + pcs->item_tint[5].Color = atoul(row[i++]); // wc_6, + pcs->item_tint[6].Color = atoul(row[i++]); // wc_7, + pcs->item_tint[7].Color = atoul(row[i++]); // wc_8, + pcs->item_tint[8].Color = atoul(row[i++]); // wc_9 } query = StringFormat( "SELECT \n" From 766641cd15fbe20e6eba51445036a28f071c1a1f Mon Sep 17 00:00:00 2001 From: Uleat Date: Tue, 17 Feb 2015 13:56:58 -0500 Subject: [PATCH 094/114] Implemented per-client character creation limits --- common/eq_dictionary.h | 1 - common/eq_packet_structs.h | 62 ++++--- common/patches/rof.cpp | 150 +++++++++------- common/patches/rof2.cpp | 150 +++++++++------- common/patches/rof2_constants.h | 2 +- common/patches/rof2_structs.h | 12 +- common/patches/rof_constants.h | 2 +- common/patches/rof_structs.h | 26 +-- common/patches/sod.cpp | 137 ++++++++------ common/patches/sod_constants.h | 2 +- common/patches/sod_structs.h | 6 +- common/patches/sof.cpp | 137 ++++++++------ common/patches/sof_constants.h | 2 +- common/patches/sof_structs.h | 10 +- common/patches/titanium.cpp | 117 ++++++++---- common/patches/titanium_constants.h | 2 +- common/patches/titanium_structs.h | 6 +- common/patches/uf.cpp | 144 +++++++++------ common/patches/uf_constants.h | 2 +- common/patches/uf_structs.h | 6 +- world/client.cpp | 138 +++++++------- world/client.h | 2 +- world/worlddb.cpp | 268 +++++++++++++++------------- world/worlddb.h | 3 +- 24 files changed, 790 insertions(+), 597 deletions(-) diff --git a/common/eq_dictionary.h b/common/eq_dictionary.h index 84da53f63..7828dd5cc 100644 --- a/common/eq_dictionary.h +++ b/common/eq_dictionary.h @@ -49,7 +49,6 @@ public: // database static const ClientVersion CHARACTER_CREATION_CLIENT = ClientVersion::RoF2; // adjust according to starting item placement and target client - // This value should be at least 8 or Titanium will have issues (tested at 6) static const size_t CHARACTER_CREATION_LIMIT = RoF2::consts::CHARACTER_CREATION_LIMIT; // inventory diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 0f1b63136..188214dad 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -158,32 +158,46 @@ struct CharSelectEquip Color_Struct Color; }; +struct CharacterSelectEntry_Struct +{ + char Name[64]; + uint8 Class; + uint32 Race; + uint8 Level; + uint8 ShroudClass; + uint32 ShroudRace; + uint16 Zone; + uint16 Instance; + uint8 Gender; + uint8 Face; + CharSelectEquip Equip[9]; + uint8 Unknown15; // Seen FF + uint8 Unknown19; // Seen FF + uint32 DrakkinTattoo; + uint32 DrakkinDetails; + uint32 Deity; + uint32 PrimaryIDFile; + uint32 SecondaryIDFile; + uint8 HairColor; + uint8 BeardColor; + uint8 EyeColor1; + uint8 EyeColor2; + uint8 HairStyle; + uint8 Beard; + uint8 Enabled; + uint8 Tutorial; // Seen 1 for new char or 0 for existing + uint32 DrakkinHeritage; + uint8 Unknown1; // Seen 0 + uint8 GoHome; // Seen 0 for new char and 1 for existing + uint32 LastLogin; + uint8 Unknown2; // Seen 0 +}; + struct CharacterSelect_Struct { - uint32 Race[10]; // Characters Race - uint8 BeardColor[10]; // Characters beard Color - uint8 HairStyle[10]; // Characters hair style - CharSelectEquip Equip[10][9]; - uint32 Secondary[10]; // Characters secondary IDFile number - uint32 DrakkinHeritage[10]; // added for SoF - uint32 DrakkinTattoo[10]; // added for SoF - uint32 DrakkinDetails[10]; // added for SoF - uint32 Deity[10]; // Characters Deity - uint8 GoHome[10]; // 1=Go Home available, 0=not - uint8 Tutorial[10]; // 1=Tutorial available, 0=not - uint8 Beard[10]; // Characters Beard Type - uint8 Unknown902[10]; // 10x ff - uint32 Primary[10]; // Characters primary IDFile number - uint8 HairColor[10]; // Characters Hair Color - uint8 Unknown0962[2]; // 2x 00 - uint32 Zone[10]; // Characters Current Zone - uint8 Class_[10]; // Characters Classes - uint8 Face[10]; // Characters Face Type - char Name[10][64]; // Characters Names - uint8 Gender[10]; // Characters Gender - uint8 EyeColor1[10]; // Characters Eye Color - uint8 EyeColor2[10]; // Characters Eye 2 Color - uint8 Level[10]; // Characters Levels + uint32 CharCount; //number of chars in this packet + uint32 TotalChars; //total number of chars allowed? + CharacterSelectEntry_Struct Entries[0]; }; /* diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 6e89f7d39..485dc4118 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -2897,85 +2897,99 @@ namespace RoF ENCODE(OP_SendCharInfo) { - ENCODE_LENGTH_EXACT(CharacterSelect_Struct); + ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct); SETUP_VAR_ENCODE(CharacterSelect_Struct); - //EQApplicationPacket *packet = *p; - //const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer; + // Zero-character count shunt + if (emu->CharCount == 0) { + ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct)); + eq->CharCount = emu->CharCount; - int char_count; - int namelen = 0; - for (char_count = 0; char_count < 10; char_count++) { - if (emu->Name[char_count][0] == '\0') - break; - if (strcmp(emu->Name[char_count], "") == 0) - break; - namelen += strlen(emu->Name[char_count]); + FINISH_ENCODE(); + return; } - int total_length = sizeof(structs::CharacterSelect_Struct) - + char_count * sizeof(structs::CharacterSelectEntry_Struct) - + namelen; + 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 < consts::CHARACTER_CREATION_LIMIT; ++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; - //unsigned char *eq_buffer = new unsigned char[total_length]; - //structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer; + eq->CharCount = character_count; + //eq->TotalChars = emu->TotalChars; - eq->CharCount = char_count; - //eq->total_chars = 10; + //if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) + // eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; - unsigned char *bufptr = (unsigned char *)eq->Entries; - int r; - for (r = 0; r < char_count; r++) { - { //pre-name section... - structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1); + 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; + + strcpy(eq_cse->Name, emu_cse->Name); + eq_ptr += strlen(eq_cse->Name); + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + + 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 < _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].EliteMaterial; + eq_cse->Equip[equip_index].HeroForgeModel = emu_cse->Equip[equip_index].HeroForgeModel; + eq_cse->Equip[equip_index].Material2 = emu_cse->Equip[equip_index].Material2; + eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color; } - //adjust for name. - bufptr += strlen(emu->Name[r]); - { //post-name section... - structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->Class_ = emu->Class_[r]; - eq2->Race = emu->Race[r]; - eq2->Level = emu->Level[r]; - eq2->Class_2 = emu->Class_[r]; - eq2->Race2 = emu->Race[r]; - eq2->Zone = emu->Zone[r]; - eq2->Instance = 0; - eq2->Gender = emu->Gender[r]; - eq2->Face = emu->Face[r]; - int k; - for (k = 0; k < _MaterialCount; k++) { - eq2->Equip[k].Material = emu->Equip[r][k].Material; - eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1; - eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial; - eq2->Equip[k].HeroForgeModel = emu->Equip[r][k].HeroForgeModel; - eq2->Equip[k].Material2 = emu->Equip[r][k].Material2; - eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color; - } - eq2->Unknown15 = 0xFF; - eq2->Uknown19 = 0xFF; - eq2->DrakkinTattoo = emu->DrakkinTattoo[r]; - eq2->DrakkinDetails = emu->DrakkinDetails[r]; - eq2->Deity = emu->Deity[r]; - eq2->Primary = emu->Primary[r]; - eq2->Secondary = emu->Secondary[r]; - eq2->HairColor = emu->HairColor[r]; - eq2->BeardColor = emu->BeardColor[r]; - eq2->EyeColor1 = emu->EyeColor1[r]; - eq2->EyeColor2 = emu->EyeColor2[r]; - eq2->HairStyle = emu->HairStyle[r]; - eq2->Beard = emu->Beard[r]; - eq2->CharEnabled = 1; - eq2->Tutorial = emu->Tutorial[r]; - eq2->DrakkinHeritage = emu->DrakkinHeritage[r]; - eq2->Unknown1 = 0; - eq2->GoHome = emu->GoHome[r]; - eq2->LastLogin = 1212696584; - eq2->Unknown2 = 0; - } - bufptr += sizeof(structs::CharacterSelectEntry_Struct); + + eq_cse->Unknown15 = emu_cse->Unknown15; + eq_cse->Unknown19 = emu_cse->Unknown19; + 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->Enabled = emu_cse->Enabled; + eq_cse->Tutorial = emu_cse->Tutorial; + eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage; + eq_cse->Unknown1 = emu_cse->Unknown1; + eq_cse->GoHome = emu_cse->GoHome; + eq_cse->LastLogin = emu_cse->LastLogin; + eq_cse->Unknown2 = emu_cse->Unknown2; + + emu_ptr += sizeof(CharacterSelectEntry_Struct); + eq_ptr += sizeof(structs::CharacterSelectEntry_Struct); } FINISH_ENCODE(); diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 0215911e6..0ad31517e 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -2981,85 +2981,99 @@ namespace RoF2 ENCODE(OP_SendCharInfo) { - ENCODE_LENGTH_EXACT(CharacterSelect_Struct); + ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct); SETUP_VAR_ENCODE(CharacterSelect_Struct); - //EQApplicationPacket *packet = *p; - //const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer; + // Zero-character count shunt + if (emu->CharCount == 0) { + ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct)); + eq->CharCount = emu->CharCount; - int char_count; - int namelen = 0; - for (char_count = 0; char_count < 10; char_count++) { - if (emu->Name[char_count][0] == '\0') - break; - if (strcmp(emu->Name[char_count], "") == 0) - break; - namelen += strlen(emu->Name[char_count]); + FINISH_ENCODE(); + return; } - int total_length = sizeof(structs::CharacterSelect_Struct) - + char_count * sizeof(structs::CharacterSelectEntry_Struct) - + namelen; + 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 < consts::CHARACTER_CREATION_LIMIT; ++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; - //unsigned char *eq_buffer = new unsigned char[total_length]; - //structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer; + eq->CharCount = character_count; + //eq->TotalChars = emu->TotalChars; - eq->CharCount = char_count; - //eq->total_chars = 10; + //if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) + // eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; - unsigned char *bufptr = (unsigned char *)eq->Entries; - int r; - for (r = 0; r < char_count; r++) { - { //pre-name section... - structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1); + 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; + + strcpy(eq_cse->Name, emu_cse->Name); + eq_ptr += strlen(eq_cse->Name); + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + + 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 < _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].EliteMaterial; + eq_cse->Equip[equip_index].HeroForgeModel = emu_cse->Equip[equip_index].HeroForgeModel; + eq_cse->Equip[equip_index].Material2 = emu_cse->Equip[equip_index].Material2; + eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color; } - //adjust for name. - bufptr += strlen(emu->Name[r]); - { //post-name section... - structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->Class_ = emu->Class_[r]; - eq2->Race = emu->Race[r]; - eq2->Level = emu->Level[r]; - eq2->Class_2 = emu->Class_[r]; - eq2->Race2 = emu->Race[r]; - eq2->Zone = emu->Zone[r]; - eq2->Instance = 0; - eq2->Gender = emu->Gender[r]; - eq2->Face = emu->Face[r]; - int k; - for (k = 0; k < _MaterialCount; k++) { - eq2->Equip[k].Material = emu->Equip[r][k].Material; - eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1; - eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial; - eq2->Equip[k].HeroForgeModel = emu->Equip[r][k].HeroForgeModel; - eq2->Equip[k].Material2 = emu->Equip[r][k].Material2; - eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color; - } - eq2->Unknown15 = 0xFF; - eq2->Unknown19 = 0xFF; - eq2->DrakkinTattoo = emu->DrakkinTattoo[r]; - eq2->DrakkinDetails = emu->DrakkinDetails[r]; - eq2->Deity = emu->Deity[r]; - eq2->Primary = emu->Primary[r]; - eq2->Secondary = emu->Secondary[r]; - eq2->HairColor = emu->HairColor[r]; - eq2->BeardColor = emu->BeardColor[r]; - eq2->EyeColor1 = emu->EyeColor1[r]; - eq2->EyeColor2 = emu->EyeColor2[r]; - eq2->HairStyle = emu->HairStyle[r]; - eq2->Beard = emu->Beard[r]; - eq2->CharEnabled = 1; - eq2->Tutorial = emu->Tutorial[r]; - eq2->DrakkinHeritage = emu->DrakkinHeritage[r]; - eq2->Unknown1 = 0; - eq2->GoHome = emu->GoHome[r]; - eq2->LastLogin = 1212696584; - eq2->Unknown2 = 0; - } - bufptr += sizeof(structs::CharacterSelectEntry_Struct); + + eq_cse->Unknown15 = emu_cse->Unknown15; + eq_cse->Unknown19 = emu_cse->Unknown19; + 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->Enabled = emu_cse->Enabled; + eq_cse->Tutorial = emu_cse->Tutorial; + eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage; + eq_cse->Unknown1 = emu_cse->Unknown1; + eq_cse->GoHome = emu_cse->GoHome; + eq_cse->LastLogin = emu_cse->LastLogin; + eq_cse->Unknown2 = emu_cse->Unknown2; + + emu_ptr += sizeof(CharacterSelectEntry_Struct); + eq_ptr += sizeof(structs::CharacterSelectEntry_Struct); } FINISH_ENCODE(); diff --git a/common/patches/rof2_constants.h b/common/patches/rof2_constants.h index 750a6fb3e..4c8245737 100644 --- a/common/patches/rof2_constants.h +++ b/common/patches/rof2_constants.h @@ -103,7 +103,7 @@ namespace RoF2 { } namespace consts { - static const size_t CHARACTER_CREATION_LIMIT = 10; + static const size_t CHARACTER_CREATION_LIMIT = 12; static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; static const uint16 MAP_BANK_SIZE = 24; diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 7f8fc6978..fd6f0b2ea 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -166,11 +166,11 @@ struct CharSelectEquip struct CharacterSelectEntry_Struct { /*0000*/ char Name[1]; // Name null terminated -/*0000*/ uint8 Class_; +/*0000*/ uint8 Class; /*0000*/ uint32 Race; /*0000*/ uint8 Level; -/*0000*/ uint8 Class_2; -/*0000*/ uint32 Race2; +/*0000*/ uint8 ShroudClass; +/*0000*/ uint32 ShroudRace; /*0000*/ uint16 Zone; /*0000*/ uint16 Instance; /*0000*/ uint8 Gender; @@ -181,15 +181,15 @@ struct CharacterSelectEntry_Struct /*0000*/ uint32 DrakkinTattoo; /*0000*/ uint32 DrakkinDetails; /*0000*/ uint32 Deity; -/*0000*/ uint32 Primary; -/*0000*/ uint32 Secondary; +/*0000*/ uint32 PrimaryIDFile; +/*0000*/ uint32 SecondaryIDFile; /*0000*/ uint8 HairColor; /*0000*/ uint8 BeardColor; /*0000*/ uint8 EyeColor1; /*0000*/ uint8 EyeColor2; /*0000*/ uint8 HairStyle; /*0000*/ uint8 Beard; -/*0000*/ uint8 CharEnabled; +/*0000*/ uint8 Enabled; /*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing /*0000*/ uint32 DrakkinHeritage; /*0000*/ uint8 Unknown1; // Seen 0 diff --git a/common/patches/rof_constants.h b/common/patches/rof_constants.h index 86367b3d9..8b5fadbf2 100644 --- a/common/patches/rof_constants.h +++ b/common/patches/rof_constants.h @@ -102,7 +102,7 @@ namespace RoF { } namespace consts { - static const size_t CHARACTER_CREATION_LIMIT = 10; + static const size_t CHARACTER_CREATION_LIMIT = 12; static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; static const uint16 MAP_BANK_SIZE = 24; diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index a1260fe72..4b8fe3b01 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -165,37 +165,37 @@ struct CharSelectEquip struct CharacterSelectEntry_Struct { -/*0000*/ char Name[1]; // Name null terminated -/*0000*/ uint8 Class_; +/*0000*/ char Name[1]; // Name null terminated +/*0000*/ uint8 Class; /*0000*/ uint32 Race; /*0000*/ uint8 Level; -/*0000*/ uint8 Class_2; -/*0000*/ uint32 Race2; +/*0000*/ uint8 ShroudClass; +/*0000*/ uint32 ShroudRace; /*0000*/ uint16 Zone; /*0000*/ uint16 Instance; /*0000*/ uint8 Gender; /*0000*/ uint8 Face; /*0000*/ CharSelectEquip Equip[9]; -/*0000*/ uint8 Unknown15; // Seen FF -/*0000*/ uint8 Uknown19; // Seen FF +/*0000*/ uint8 Unknown15; // Seen FF +/*0000*/ uint8 Unknown19; // Seen FF /*0000*/ uint32 DrakkinTattoo; /*0000*/ uint32 DrakkinDetails; /*0000*/ uint32 Deity; -/*0000*/ uint32 Primary; -/*0000*/ uint32 Secondary; +/*0000*/ uint32 PrimaryIDFile; +/*0000*/ uint32 SecondaryIDFile; /*0000*/ uint8 HairColor; /*0000*/ uint8 BeardColor; /*0000*/ uint8 EyeColor1; /*0000*/ uint8 EyeColor2; /*0000*/ uint8 HairStyle; /*0000*/ uint8 Beard; -/*0000*/ uint8 CharEnabled; -/*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing +/*0000*/ uint8 Enabled; +/*0000*/ uint8 Tutorial; // Seen 1 for new char or 0 for existing /*0000*/ uint32 DrakkinHeritage; -/*0000*/ uint8 Unknown1; // Seen 0 -/*0000*/ uint8 GoHome; // Seen 0 for new char and 1 for existing +/*0000*/ uint8 Unknown1; // Seen 0 +/*0000*/ uint8 GoHome; // Seen 0 for new char and 1 for existing /*0000*/ uint32 LastLogin; -/*0000*/ uint8 Unknown2; // Seen 0 +/*0000*/ uint8 Unknown2; // Seen 0 }; /* diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index c2ac79d7d..a8b69556a 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -1911,76 +1911,95 @@ namespace SoD ENCODE(OP_SendCharInfo) { - ENCODE_LENGTH_EXACT(CharacterSelect_Struct); + ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct); SETUP_VAR_ENCODE(CharacterSelect_Struct); - //EQApplicationPacket *packet = *p; - //const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer; + // Zero-character count shunt + if (emu->CharCount == 0) { + ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct)); + eq->CharCount = emu->CharCount; + eq->TotalChars = eq->TotalChars; - int char_count; - int namelen = 0; - for (char_count = 0; char_count < 10; char_count++) { - if (emu->Name[char_count][0] == '\0') - break; - if (strcmp(emu->Name[char_count], "") == 0) - break; - namelen += strlen(emu->Name[char_count]); + if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) + eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; + + FINISH_ENCODE(); + return; } - int total_length = sizeof(structs::CharacterSelect_Struct) - + char_count * sizeof(structs::CharacterSelectEntry_Struct) - + namelen; + 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 < consts::CHARACTER_CREATION_LIMIT; ++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; - //unsigned char *eq_buffer = new unsigned char[total_length]; - //structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer; + eq->CharCount = character_count; + eq->TotalChars = emu->TotalChars; - eq->CharCount = char_count; - eq->TotalChars = 10; + if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) + eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; - unsigned char *bufptr = (unsigned char *)eq->Entries; - int r; - for (r = 0; r < char_count; r++) { - { //pre-name section... - structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->Level = emu->Level[r]; - eq2->HairStyle = emu->HairStyle[r]; - eq2->Gender = emu->Gender[r]; - memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1); + 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; + + eq_cse->Level = emu_cse->Level; + eq_cse->HairStyle = emu_cse->HairStyle; + eq_cse->Gender = emu_cse->Gender; + + strcpy(eq_cse->Name, emu_cse->Name); + eq_ptr += strlen(eq_cse->Name); + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + + eq_cse->Beard = emu_cse->Beard; + eq_cse->HairColor = emu_cse->HairColor; + eq_cse->Face = emu_cse->Face; + + for (int equip_index = 0; equip_index < _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].EliteMaterial; + eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color; } - //adjust for name. - bufptr += strlen(emu->Name[r]); - { //post-name section... - structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->Beard = emu->Beard[r]; - eq2->HairColor = emu->HairColor[r]; - eq2->Face = emu->Face[r]; - int k; - for (k = 0; k < _MaterialCount; k++) { - eq2->Equip[k].Material = emu->Equip[r][k].Material; - eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1; - eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial; - eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color; - } - eq2->Primary = emu->Primary[r]; - eq2->Secondary = emu->Secondary[r]; - eq2->Tutorial = emu->Tutorial[r]; // was u15 - eq2->Unknown15 = 0xFF; - eq2->Deity = emu->Deity[r]; - eq2->Zone = emu->Zone[r]; - eq2->Unknown19 = 0xFF; - eq2->Race = emu->Race[r]; - eq2->GoHome = emu->GoHome[r]; - eq2->Class_ = emu->Class_[r]; - eq2->EyeColor1 = emu->EyeColor1[r]; - eq2->BeardColor = emu->BeardColor[r]; - eq2->EyeColor2 = emu->EyeColor2[r]; - eq2->DrakkinHeritage = emu->DrakkinHeritage[r]; - eq2->DrakkinTattoo = emu->DrakkinTattoo[r]; - eq2->DrakkinDetails = emu->DrakkinDetails[r]; - } - bufptr += sizeof(structs::CharacterSelectEntry_Struct); + + eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile; + eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile; + eq_cse->Tutorial = emu_cse->Tutorial; + eq_cse->Unknown15 = emu_cse->Unknown15; + eq_cse->Deity = emu_cse->Deity; + eq_cse->Zone = emu_cse->Zone; + eq_cse->Unknown19 = emu_cse->Unknown19; + eq_cse->Race = emu_cse->Race; + eq_cse->GoHome = emu_cse->GoHome; + eq_cse->Class = emu_cse->Class; + eq_cse->EyeColor1 = emu_cse->EyeColor1; + eq_cse->BeardColor = emu_cse->BeardColor; + eq_cse->EyeColor2 = emu_cse->EyeColor2; + eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage; + eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo; + eq_cse->DrakkinDetails = emu_cse->DrakkinDetails; + + emu_ptr += sizeof(CharacterSelectEntry_Struct); + eq_ptr += sizeof(structs::CharacterSelectEntry_Struct); } FINISH_ENCODE(); diff --git a/common/patches/sod_constants.h b/common/patches/sod_constants.h index 5fdb89578..5dad9bb09 100644 --- a/common/patches/sod_constants.h +++ b/common/patches/sod_constants.h @@ -101,7 +101,7 @@ namespace SoD { } namespace consts { - static const size_t CHARACTER_CREATION_LIMIT = 10; + static const size_t CHARACTER_CREATION_LIMIT = 12; static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; static const uint16 MAP_BANK_SIZE = 24; diff --git a/common/patches/sod_structs.h b/common/patches/sod_structs.h index f18e3d2f6..274cfe876 100644 --- a/common/patches/sod_structs.h +++ b/common/patches/sod_structs.h @@ -132,8 +132,8 @@ struct CharacterSelectEntry_Struct /*0001*/ uint8 HairColor; // /*0000*/ uint8 Face; // /*0000*/ CharSelectEquip Equip[9]; -/*0000*/ uint32 Primary; // -/*0000*/ uint32 Secondary; // +/*0000*/ uint32 PrimaryIDFile; // +/*0000*/ uint32 SecondaryIDFile; // /*0000*/ uint8 Unknown15; // 0xff /*0000*/ uint32 Deity; // /*0000*/ uint16 Zone; // @@ -142,7 +142,7 @@ struct CharacterSelectEntry_Struct /*0000*/ uint8 Unknown19; // 0xff /*0000*/ uint32 Race; // /*0000*/ uint8 Tutorial; // -/*0000*/ uint8 Class_; // +/*0000*/ uint8 Class; // /*0000*/ uint8 EyeColor1; // /*0000*/ uint8 BeardColor; // /*0000*/ uint8 EyeColor2; // diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index 5220a0a6e..e0b24b393 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1570,76 +1570,95 @@ namespace SoF ENCODE(OP_SendCharInfo) { - ENCODE_LENGTH_EXACT(CharacterSelect_Struct); + ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct); SETUP_VAR_ENCODE(CharacterSelect_Struct); - //EQApplicationPacket *packet = *p; - //const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer; + // Zero-character count shunt + if (emu->CharCount == 0) { + ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct)); + eq->CharCount = emu->CharCount; + eq->TotalChars = eq->TotalChars; - int char_count; - int namelen = 0; - for (char_count = 0; char_count < 10; char_count++) { - if (emu->Name[char_count][0] == '\0') - break; - if (strcmp(emu->Name[char_count], "") == 0) - break; - namelen += strlen(emu->Name[char_count]); + if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) + eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; + + FINISH_ENCODE(); + return; } - int total_length = sizeof(structs::CharacterSelect_Struct) - + char_count * sizeof(structs::CharacterSelectEntry_Struct) - + namelen; + 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 < consts::CHARACTER_CREATION_LIMIT; ++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; - //unsigned char *eq_buffer = new unsigned char[total_length]; - //structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer; + eq->CharCount = character_count; + eq->TotalChars = emu->TotalChars; - eq->CharCount = char_count; - eq->TotalChars = 10; + if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) + eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; - unsigned char *bufptr = (unsigned char *)eq->Entries; - int r; - for (r = 0; r < char_count; r++) { - { //pre-name section... - structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->Level = emu->Level[r]; - eq2->HairStyle = emu->HairStyle[r]; - eq2->Gender = emu->Gender[r]; - memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1); + 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; + + eq_cse->Level = emu_cse->Level; + eq_cse->HairStyle = emu_cse->HairStyle; + eq_cse->Gender = emu_cse->Gender; + + strcpy(eq_cse->Name, emu_cse->Name); + eq_ptr += strlen(eq_cse->Name); + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + + eq_cse->Beard = emu_cse->Beard; + eq_cse->HairColor = emu_cse->HairColor; + eq_cse->Face = emu_cse->Face; + + for (int equip_index = 0; equip_index < _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].EliteMaterial; + eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color; } - //adjust for name. - bufptr += strlen(emu->Name[r]); - { //post-name section... - structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->Beard = emu->Beard[r]; - eq2->HairColor = emu->HairColor[r]; - eq2->Face = emu->Face[r]; - int k; - for (k = 0; k < _MaterialCount; k++) { - eq2->Equip[k].Material = emu->Equip[r][k].Material; - eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1; - eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial; - eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color; - } - eq2->Primary = emu->Primary[r]; - eq2->Secondary = emu->Secondary[r]; - eq2->Tutorial = emu->Tutorial[r]; // was u15 - eq2->Unknown15 = 0xff; - eq2->Deity = emu->Deity[r]; - eq2->Zone = emu->Zone[r]; - eq2->Unknown19 = 0xFF; - eq2->Race = emu->Race[r]; - eq2->GoHome = emu->GoHome[r]; - eq2->Class_ = emu->Class_[r]; - eq2->EyeColor1 = emu->EyeColor1[r]; - eq2->BeardColor = emu->BeardColor[r]; - eq2->EyeColor2 = emu->EyeColor2[r]; - eq2->DrakkinHeritage = emu->DrakkinHeritage[r]; - eq2->DrakkinTattoo = emu->DrakkinTattoo[r]; - eq2->DrakkinDetails = emu->DrakkinDetails[r]; - } - bufptr += sizeof(structs::CharacterSelectEntry_Struct); + + eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile; + eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile; + eq_cse->Tutorial = emu_cse->Tutorial; + eq_cse->Unknown15 = emu_cse->Unknown15; + eq_cse->Deity = emu_cse->Deity; + eq_cse->Zone = emu_cse->Zone; + eq_cse->Unknown19 = emu_cse->Unknown19; + eq_cse->Race = emu_cse->Race; + eq_cse->GoHome = emu_cse->GoHome; + eq_cse->Class = emu_cse->Class; + eq_cse->EyeColor1 = emu_cse->EyeColor1; + eq_cse->BeardColor = emu_cse->BeardColor; + eq_cse->EyeColor2 = emu_cse->EyeColor2; + eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage; + eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo; + eq_cse->DrakkinDetails = emu_cse->DrakkinDetails; + + emu_ptr += sizeof(CharacterSelectEntry_Struct); + eq_ptr += sizeof(structs::CharacterSelectEntry_Struct); } FINISH_ENCODE(); diff --git a/common/patches/sof_constants.h b/common/patches/sof_constants.h index 4729eb436..260722f00 100644 --- a/common/patches/sof_constants.h +++ b/common/patches/sof_constants.h @@ -101,7 +101,7 @@ namespace SoF { } namespace consts { - static const size_t CHARACTER_CREATION_LIMIT = 10; + static const size_t CHARACTER_CREATION_LIMIT = 12; static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; static const uint16 MAP_BANK_SIZE = 24; diff --git a/common/patches/sof_structs.h b/common/patches/sof_structs.h index e66ace468..23b080f0c 100644 --- a/common/patches/sof_structs.h +++ b/common/patches/sof_structs.h @@ -132,17 +132,17 @@ struct CharacterSelectEntry_Struct /*0001*/ uint8 HairColor; // /*0000*/ uint8 Face; // /*0000*/ CharSelectEquip Equip[9]; -/*0000*/ uint32 Primary; // -/*0000*/ uint32 Secondary; // -/*0000*/ uint8 Unknown15; // 0xff +/*0000*/ uint32 PrimaryIDFile; // +/*0000*/ uint32 SecondaryIDFile; // +/*0000*/ uint8 Unknown15; // 0xff /*0000*/ uint32 Deity; // /*0000*/ uint16 Zone; // /*0000*/ uint16 Instance; /*0000*/ uint8 GoHome; // -/*0000*/ uint8 Unknown19; // 0xff +/*0000*/ uint8 Unknown19; // 0xff /*0000*/ uint32 Race; // /*0000*/ uint8 Tutorial; // -/*0000*/ uint8 Class_; // +/*0000*/ uint8 Class; // /*0000*/ uint8 EyeColor1; // /*0000*/ uint8 BeardColor; // /*0000*/ uint8 EyeColor2; // diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index e636b6a9c..efacfe980 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -1155,39 +1155,96 @@ namespace Titanium ENCODE(OP_SendCharInfo) { - ENCODE_LENGTH_EXACT(CharacterSelect_Struct); + ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct); SETUP_DIRECT_ENCODE(CharacterSelect_Struct, structs::CharacterSelect_Struct); - int r; - for (r = 0; r < 10; r++) { - OUT(Zone[r]); - OUT(EyeColor1[r]); - OUT(EyeColor2[r]); - OUT(HairStyle[r]); - OUT(Primary[r]); - if (emu->Race[r] > 473) - eq->Race[r] = 1; - else - eq->Race[r] = emu->Race[r]; - OUT(Class_[r]); - OUT_str(Name[r]); - OUT(Gender[r]); - OUT(Level[r]); - OUT(Secondary[r]); - OUT(Face[r]); - OUT(Beard[r]); - int k; - for (k = 0; k < 9; k++) { - eq->Equip[r][k] = emu->Equip[r][k].Material; - eq->CS_Colors[r][k].Color = emu->Equip[r][k].Color.Color; + unsigned char *emu_ptr = __emu_buffer; + emu_ptr += sizeof(CharacterSelect_Struct); + CharacterSelectEntry_Struct *emu_cse = (CharacterSelectEntry_Struct *)nullptr; + + for (size_t index = 0; index < 10; ++index) { + memset(eq->Name[index], 0, 64); + } + + // Non character-indexed packet fields + eq->Unknown830[0] = 0; + eq->Unknown830[1] = 0; + eq->Unknown0962[0] = 0; + eq->Unknown0962[1] = 0; + + size_t char_index = 0; + for (; char_index < emu->CharCount && char_index < 8; ++char_index) { + emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; + + eq->Race[char_index] = emu_cse->Race; + if (eq->Race[char_index] > 473) + eq->Race[char_index] = 1; + + for (int index = 0; index < _MaterialCount; ++index) { + eq->CS_Colors[char_index][index].Color = emu_cse->Equip[index].Color.Color; } - OUT(HairColor[r]); - OUT(GoHome[r]); - OUT(Tutorial[r]); - OUT(Deity[r]); - OUT(BeardColor[r]); - eq->Unknown820[r] = 0xFF; - eq->Unknown902[r] = 0xFF; + + eq->BeardColor[char_index] = emu_cse->BeardColor; + eq->HairStyle[char_index] = emu_cse->HairStyle; + + for (int index = 0; index < _MaterialCount; ++index) { + eq->Equip[char_index][index] = emu_cse->Equip[index].Material; + } + + eq->SecondaryIDFile[char_index] = emu_cse->SecondaryIDFile; + eq->Unknown820[char_index] = 0xFF; + eq->Deity[char_index] = emu_cse->Deity; + eq->GoHome[char_index] = emu_cse->GoHome; + eq->Tutorial[char_index] = emu_cse->Tutorial; + eq->Beard[char_index] = emu_cse->Beard; + eq->Unknown902[char_index] = 0xFF; + eq->PrimaryIDFile[char_index] = emu_cse->PrimaryIDFile; + eq->HairColor[char_index] = emu_cse->HairColor; + eq->Zone[char_index] = emu_cse->Zone; + eq->Class[char_index] = emu_cse->Class; + eq->Face[char_index] = emu_cse->Face; + + memcpy(eq->Name[char_index], emu_cse->Name, 64); + + eq->Gender[char_index] = emu_cse->Gender; + eq->EyeColor1[char_index] = emu_cse->EyeColor1; + eq->EyeColor2[char_index] = emu_cse->EyeColor2; + eq->Level[char_index] = emu_cse->Level; + + emu_ptr += sizeof(CharacterSelectEntry_Struct); + } + + for (; char_index < 10; ++char_index) { + eq->Race[char_index] = 0; + + for (int index = 0; index < _MaterialCount; ++index) { + eq->CS_Colors[char_index][index].Color = 0; + } + + eq->BeardColor[char_index] = 0; + eq->HairStyle[char_index] = 0; + + for (int index = 0; index < _MaterialCount; ++index) { + eq->Equip[char_index][index] = 0; + } + + eq->SecondaryIDFile[char_index] = 0; + eq->Unknown820[char_index] = 0xFF; + eq->Deity[char_index] = 0; + eq->GoHome[char_index] = 0; + eq->Tutorial[char_index] = 0; + eq->Beard[char_index] = 0; + eq->Unknown902[char_index] = 0xFF; + eq->PrimaryIDFile[char_index] = 0; + eq->HairColor[char_index] = 0; + eq->Zone[char_index] = 0; + eq->Class[char_index] = 0; + eq->Face[char_index] = 0; + //eq->Name[char_index][0] = '\0'; // Cleared above + eq->Gender[char_index] = 0; + eq->EyeColor1[char_index] = 0; + eq->EyeColor2[char_index] = 0; + eq->Level[char_index] = 0; } FINISH_ENCODE(); diff --git a/common/patches/titanium_constants.h b/common/patches/titanium_constants.h index c93de7666..d7e2a4964 100644 --- a/common/patches/titanium_constants.h +++ b/common/patches/titanium_constants.h @@ -100,7 +100,7 @@ namespace Titanium { } namespace consts { - static const size_t CHARACTER_CREATION_LIMIT = 8; + static const size_t CHARACTER_CREATION_LIMIT = 8; // Hard-coded in client - DO NOT ALTER static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; static const uint16 MAP_BANK_SIZE = 16; diff --git a/common/patches/titanium_structs.h b/common/patches/titanium_structs.h index a61b96a94..60b764dfe 100644 --- a/common/patches/titanium_structs.h +++ b/common/patches/titanium_structs.h @@ -122,7 +122,7 @@ struct CharacterSelect_Struct /*0400*/ uint8 BeardColor[10]; // Characters beard Color /*0410*/ uint8 HairStyle[10]; // Characters hair style /*0420*/ uint32 Equip[10][9]; // 0=helm, 1=chest, 2=arm, 3=bracer, 4=hand, 5=leg, 6=boot, 7=melee1, 8=melee2 (Might not be) -/*0780*/ uint32 Secondary[10]; // Characters secondary IDFile number +/*0780*/ uint32 SecondaryIDFile[10]; // Characters secondary IDFile number /*0820*/ uint8 Unknown820[10]; // 10x ff /*0830*/ uint8 Unknown830[2]; // 2x 00 /*0832*/ uint32 Deity[10]; // Characters Deity @@ -130,11 +130,11 @@ struct CharacterSelect_Struct /*0882*/ uint8 Tutorial[10]; // 1=Tutorial available, 0=not /*0892*/ uint8 Beard[10]; // Characters Beard Type /*0902*/ uint8 Unknown902[10]; // 10x ff -/*0912*/ uint32 Primary[10]; // Characters primary IDFile number +/*0912*/ uint32 PrimaryIDFile[10]; // Characters primary IDFile number /*0952*/ uint8 HairColor[10]; // Characters Hair Color /*0962*/ uint8 Unknown0962[2]; // 2x 00 /*0964*/ uint32 Zone[10]; // Characters Current Zone -/*1004*/ uint8 Class_[10]; // Characters Classes +/*1004*/ uint8 Class[10]; // Characters Classes /*1014*/ uint8 Face[10]; // Characters Face Type /*1024*/ char Name[10][64]; // Characters Names /*1664*/ uint8 Gender[10]; // Characters Gender diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 18ea67af0..d8635485c 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -2194,77 +2194,103 @@ namespace UF ENCODE(OP_SendCharInfo) { - ENCODE_LENGTH_EXACT(CharacterSelect_Struct); + ENCODE_LENGTH_ATLEAST(CharacterSelect_Struct); SETUP_VAR_ENCODE(CharacterSelect_Struct); - //EQApplicationPacket *packet = *p; - //const CharacterSelect_Struct *emu = (CharacterSelect_Struct *) packet->pBuffer; + // Zero-character count shunt + if (emu->CharCount == 0) { + ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct)); + eq->CharCount = emu->CharCount; + eq->TotalChars = eq->TotalChars; - int char_count; - int namelen = 0; - for (char_count = 0; char_count < 10; char_count++) { - if (emu->Name[char_count][0] == '\0') - break; - if (strcmp(emu->Name[char_count], "") == 0) - break; - namelen += strlen(emu->Name[char_count]); + if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) + eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; + + // Special Underfoot adjustment - field should really be 'AdditionalChars' or 'BonusChars' + uint32 adjusted_total = eq->TotalChars - 8; // Yes, it rolls under for '< 8' - probably an int32 field + eq->TotalChars = adjusted_total; + + 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 < consts::CHARACTER_CREATION_LIMIT; ++character_count) { + emu_cse = (CharacterSelectEntry_Struct *)emu_ptr; + names_length += strlen(emu_cse->Name); + emu_ptr += sizeof(CharacterSelectEntry_Struct); } - int total_length = sizeof(structs::CharacterSelect_Struct) - + char_count * sizeof(structs::CharacterSelectEntry_Struct) - + namelen; + 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; - //unsigned char *eq_buffer = new unsigned char[total_length]; - //structs::CharacterSelect_Struct *eq_head = (structs::CharacterSelect_Struct *) eq_buffer; + eq->CharCount = character_count; + eq->TotalChars = emu->TotalChars; - eq->CharCount = char_count; - eq->TotalChars = 10; + if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) + eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; - unsigned char *bufptr = (unsigned char *)eq->Entries; - int r; - for (r = 0; r < char_count; r++) { - { //pre-name section... - structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->Level = emu->Level[r]; - eq2->HairStyle = emu->HairStyle[r]; - eq2->Gender = emu->Gender[r]; - memcpy(eq2->Name, emu->Name[r], strlen(emu->Name[r]) + 1); - } - //adjust for name. - bufptr += strlen(emu->Name[r]); - { //post-name section... - structs::CharacterSelectEntry_Struct *eq2 = (structs::CharacterSelectEntry_Struct *) bufptr; - eq2->Beard = emu->Beard[r]; - eq2->HairColor = emu->HairColor[r]; - eq2->Face = emu->Face[r]; - int k; - for (k = 0; k < _MaterialCount; k++) { - eq2->Equip[k].Material = emu->Equip[r][k].Material; - eq2->Equip[k].Unknown1 = emu->Equip[r][k].Unknown1; - eq2->Equip[k].EliteMaterial = emu->Equip[r][k].EliteMaterial; - eq2->Equip[k].Color.Color = emu->Equip[r][k].Color.Color; - } - eq2->Primary = emu->Primary[r]; - eq2->Secondary = emu->Secondary[r]; - eq2->Tutorial = emu->Tutorial[r]; // was u15 - eq2->Unknown15 = 0xFF; - eq2->Deity = emu->Deity[r]; - eq2->Zone = emu->Zone[r]; - eq2->Unknown19 = 0xFF; - eq2->Race = emu->Race[r]; - eq2->GoHome = emu->GoHome[r]; - eq2->Class_ = emu->Class_[r]; - eq2->EyeColor1 = emu->EyeColor1[r]; - eq2->BeardColor = emu->BeardColor[r]; - eq2->EyeColor2 = emu->EyeColor2[r]; - eq2->DrakkinHeritage = emu->DrakkinHeritage[r]; - eq2->DrakkinTattoo = emu->DrakkinTattoo[r]; - eq2->DrakkinDetails = emu->DrakkinDetails[r]; + // Special Underfoot adjustment - field should really be 'AdditionalChars' or 'BonusChars' in this client + uint32 adjusted_total = eq->TotalChars - 8; // Yes, it rolls under for '< 8' - probably an int32 field + eq->TotalChars = adjusted_total; + + 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; + + eq_cse->Level = emu_cse->Level; + eq_cse->HairStyle = emu_cse->HairStyle; + eq_cse->Gender = emu_cse->Gender; + + strcpy(eq_cse->Name, emu_cse->Name); + eq_ptr += strlen(eq_cse->Name); + eq_cse = (structs::CharacterSelectEntry_Struct *)eq_ptr; + + eq_cse->Beard = emu_cse->Beard; + eq_cse->HairColor = emu_cse->HairColor; + eq_cse->Face = emu_cse->Face; + + for (int equip_index = 0; equip_index < _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].EliteMaterial; + eq_cse->Equip[equip_index].Color.Color = emu_cse->Equip[equip_index].Color.Color; } - bufptr += sizeof(structs::CharacterSelectEntry_Struct); + eq_cse->PrimaryIDFile = emu_cse->PrimaryIDFile; + eq_cse->SecondaryIDFile = emu_cse->SecondaryIDFile; + eq_cse->Tutorial = emu_cse->Tutorial; + eq_cse->Unknown15 = emu_cse->Unknown15; + eq_cse->Deity = emu_cse->Deity; + eq_cse->Zone = emu_cse->Zone; + eq_cse->Unknown19 = emu_cse->Unknown19; + eq_cse->Race = emu_cse->Race; + eq_cse->GoHome = emu_cse->GoHome; + eq_cse->Class = emu_cse->Class; + eq_cse->EyeColor1 = emu_cse->EyeColor1; + eq_cse->BeardColor = emu_cse->BeardColor; + eq_cse->EyeColor2 = emu_cse->EyeColor2; + eq_cse->DrakkinHeritage = emu_cse->DrakkinHeritage; + eq_cse->DrakkinTattoo = emu_cse->DrakkinTattoo; + eq_cse->DrakkinDetails = emu_cse->DrakkinDetails; + + emu_ptr += sizeof(CharacterSelectEntry_Struct); + eq_ptr += sizeof(structs::CharacterSelectEntry_Struct); } FINISH_ENCODE(); diff --git a/common/patches/uf_constants.h b/common/patches/uf_constants.h index 3320fee76..1a5a4cc44 100644 --- a/common/patches/uf_constants.h +++ b/common/patches/uf_constants.h @@ -101,7 +101,7 @@ namespace UF { } namespace consts { - static const size_t CHARACTER_CREATION_LIMIT = 10; + static const size_t CHARACTER_CREATION_LIMIT = 12; static const uint16 MAP_POSSESSIONS_SIZE = slots::_MainCount; static const uint16 MAP_BANK_SIZE = 24; diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index ec912b681..2f5aa95b3 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -132,8 +132,8 @@ struct CharacterSelectEntry_Struct /*0001*/ uint8 HairColor; // /*0000*/ uint8 Face; // /*0000*/ CharSelectEquip Equip[9]; -/*0000*/ uint32 Primary; // -/*0000*/ uint32 Secondary; // +/*0000*/ uint32 PrimaryIDFile; // +/*0000*/ uint32 SecondaryIDFile; // /*0000*/ uint8 Unknown15; // 0xff /*0000*/ uint32 Deity; // /*0000*/ uint16 Zone; // @@ -142,7 +142,7 @@ struct CharacterSelectEntry_Struct /*0000*/ uint8 Unknown19; // 0xff /*0000*/ uint32 Race; // /*0000*/ uint8 Tutorial; // -/*0000*/ uint8 Class_; // +/*0000*/ uint8 Class; // /*0000*/ uint8 EyeColor1; // /*0000*/ uint8 BeardColor; // /*0000*/ uint8 EyeColor2; // diff --git a/world/client.cpp b/world/client.cpp index 55ca440cc..0393f0f65 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -16,6 +16,7 @@ #include "../common/string_util.h" #include "../common/clientversions.h" #include "../common/random.h" +#include "../common/shareddb.h" #include "client.h" #include "worlddb.h" @@ -161,32 +162,34 @@ void Client::SendCharInfo() { cle->SetOnline(CLE_Status_CharSelect); } - if (m_ClientVersionBit & BIT_RoFAndLater) - { - // Can make max char per account into a rule - New to VoA - SendMaxCharCreate(10); + if (m_ClientVersionBit & BIT_RoFAndLater) { + SendMaxCharCreate(); SendMembership(); SendMembershipSettings(); } seencharsel = true; - // Send OP_SendCharInfo - auto outapp = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct)); - CharacterSelect_Struct* cs = (CharacterSelect_Struct*)outapp->pBuffer; + EQApplicationPacket *outapp = nullptr; + database.GetCharSelectInfo(GetAccountID(), &outapp, m_ClientVersionBit); - database.GetCharSelectInfo(GetAccountID(), cs, m_ClientVersionBit); - - QueuePacket(outapp); + if (outapp) { + QueuePacket(outapp); + } + else { + Log.Out(Logs::General, Logs::World_Server, "[Error] Database did not return an OP_SendCharInfo packet for account %u", GetAccountID()); + } safe_delete(outapp); } -void Client::SendMaxCharCreate(int max_chars) { +void Client::SendMaxCharCreate() { auto outapp = new EQApplicationPacket(OP_SendMaxCharacters, sizeof(MaxCharacters_Struct)); MaxCharacters_Struct* mc = (MaxCharacters_Struct*)outapp->pBuffer; - mc->max_chars = max_chars; + mc->max_chars = EQLimits::CharacterCreationLimit(m_ClientVersion); + if (mc->max_chars > EmuConstants::CHARACTER_CREATION_LIMIT) + mc->max_chars = EmuConstants::CHARACTER_CREATION_LIMIT; QueuePacket(outapp); safe_delete(outapp); @@ -716,66 +719,71 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { return true; } - if(!pZoning && ew->return_home && !ew->tutorial) { - auto cs = new CharacterSelect_Struct; - memset(cs, 0, sizeof(CharacterSelect_Struct)); - database.GetCharSelectInfo(GetAccountID(), cs, m_ClientVersionBit); - bool home_enabled = false; + // This can probably be moved outside and have another method return requested info (don't forget to remove the #include "../common/shareddb.h" above) + if (!pZoning) { + size_t character_limit = EQLimits::CharacterCreationLimit(eqs->GetClientVersion()); + if (character_limit > EmuConstants::CHARACTER_CREATION_LIMIT) { character_limit = EmuConstants::CHARACTER_CREATION_LIMIT; } + if (eqs->GetClientVersion() == ClientVersion::Titanium) { character_limit = 8; } - for(int x = 0; x < 10; ++x) - { - if(strcasecmp(cs->Name[x], char_name) == 0) - { - if(cs->GoHome[x] == 1) - { - home_enabled = true; - break; + std::string tgh_query = StringFormat( + "SELECT " + "`id`, " + "name, " + "`level`, " + "last_login, " + "FROM " + "character_data " + "WHERE `account_id` = %i ORDER BY `name` LIMIT %u", GetAccountID(), character_limit); + auto tgh_results = database.QueryDatabase(tgh_query); + + /* Check GoHome */ + if (ew->return_home && !ew->tutorial) { + bool home_enabled = false; + for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) { + if (strcasecmp(row[1], char_name) == 0) { + if (RuleB(World, EnableTutorialButton) && ((uint8)atoi(row[2]) <= RuleI(World, MaxLevelForTutorial))) { + home_enabled = true; + break; + } } } - } - safe_delete(cs); - if(home_enabled) { - zoneID = database.MoveCharacterToBind(charid,4); - } - else { - Log.Out(Logs::Detail, Logs::World_Server,"'%s' is trying to go home before they're able...",char_name); - database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able."); - eqs->Close(); - return true; - } - } - - if(!pZoning && (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial))) { - auto cs = new CharacterSelect_Struct; - memset(cs, 0, sizeof(CharacterSelect_Struct)); - database.GetCharSelectInfo(GetAccountID(), cs, m_ClientVersionBit); - bool tutorial_enabled = false; - - for(int x = 0; x < 10; ++x) - { - if(strcasecmp(cs->Name[x], char_name) == 0) - { - if(cs->Tutorial[x] == 1) - { - tutorial_enabled = true; - break; - } + if (home_enabled) { + zoneID = database.MoveCharacterToBind(charid, 4); + } + else { + Log.Out(Logs::Detail, Logs::World_Server, "'%s' is trying to go home before they're able...", char_name); + database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able."); + eqs->Close(); + return true; } } - safe_delete(cs); - if(tutorial_enabled) - { - zoneID = RuleI(World, TutorialZoneID); - database.MoveCharacterToZone(charid, database.GetZoneName(zoneID)); - } - else - { - Log.Out(Logs::Detail, Logs::World_Server,"'%s' is trying to go to tutorial but are not allowed...",char_name); - database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character."); - eqs->Close(); - return true; + /* Check Tutorial*/ + if (RuleB(World, EnableTutorialButton) && (ew->tutorial || StartInTutorial)) { + bool tutorial_enabled = false; + for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) { + if (strcasecmp(row[1], char_name) == 0) { + if (RuleB(World, EnableReturnHomeButton)) { + int now = time(nullptr); + if ((now - atoi(row[3])) >= RuleI(World, MinOfflineTimeToReturnHome)) { + tutorial_enabled = true; + break; + } + } + } + } + + if (tutorial_enabled) { + zoneID = RuleI(World, TutorialZoneID); + database.MoveCharacterToZone(charid, database.GetZoneName(zoneID)); + } + else { + Log.Out(Logs::Detail, Logs::World_Server, "'%s' is trying to go to tutorial but are not allowed...", char_name); + database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character."); + eqs->Close(); + return true; + } } } diff --git a/world/client.h b/world/client.h index ea1df42ba..d7a42ab28 100644 --- a/world/client.h +++ b/world/client.h @@ -41,7 +41,7 @@ public: bool Process(); void ReceiveData(uchar* buf, int len); void SendCharInfo(); - void SendMaxCharCreate(int max_chars); + void SendMaxCharCreate(); void SendMembership(); void SendMembershipSettings(); void EnterWorld(bool TryBootup = true); diff --git a/world/worlddb.cpp b/world/worlddb.cpp index e47d9d54a..4ba21101c 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -33,21 +33,20 @@ extern std::vector character_create_race_class_combos; // the current stuff is at the bottom of this function -void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* cs, uint32 ClientVersion) +void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **outApp, uint32 clientVersionBit) { - Inventory *inv = nullptr; - uint8 has_home = 0; - uint8 has_bind = 0; - - /* Initialize Variables */ - for (int i=0; i<10; i++) { - strcpy(cs->Name[i], ""); - cs->Zone[i] = 0; - cs->Level[i] = 0; - cs->Tutorial[i] = 0; - cs->GoHome[i] = 0; - } + /* Set Character Creation Limit */ + ClientVersion client_version = ClientVersionFromBit(clientVersionBit); + size_t character_limit = EQLimits::CharacterCreationLimit(client_version); + + // Validate against absolute server max + if (character_limit > EmuConstants::CHARACTER_CREATION_LIMIT) + character_limit = EmuConstants::CHARACTER_CREATION_LIMIT; + // Force Titanium clients to use '8' + if (client_version == ClientVersion::Titanium) + character_limit = 8; + /* Get Character Info */ std::string cquery = StringFormat( "SELECT " @@ -73,52 +72,93 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* "zone_id " // 19 "FROM " "character_data " - "WHERE `account_id` = %i ORDER BY `name` LIMIT 10 ", account_id); - auto results = database.QueryDatabase(cquery); int char_num = 0; - for (auto row = results.begin(); row != results.end() && char_num < 10; ++row, ++char_num) { + "WHERE `account_id` = %i ORDER BY `name` LIMIT %u", accountID, character_limit); + auto results = database.QueryDatabase(cquery); + + size_t character_count = results.RowCount(); + if (character_count == 0) { + *outApp = new EQApplicationPacket(OP_SendCharInfo, sizeof(CharacterSelect_Struct)); + CharacterSelect_Struct *cs = (CharacterSelect_Struct *)(*outApp)->pBuffer; + cs->CharCount = 0; + cs->TotalChars = character_limit; + return; + } + + size_t packet_size = sizeof(CharacterSelect_Struct) + (sizeof(CharacterSelectEntry_Struct) * character_count); + *outApp = new EQApplicationPacket(OP_SendCharInfo, packet_size); + + unsigned char *buff_ptr = (*outApp)->pBuffer; + CharacterSelect_Struct *cs = (CharacterSelect_Struct *)buff_ptr; + + cs->CharCount = character_count; + cs->TotalChars = character_limit; + + buff_ptr += sizeof(CharacterSelect_Struct); + for (auto row = results.begin(); row != results.end(); ++row) { + CharacterSelectEntry_Struct *cse = (CharacterSelectEntry_Struct *)buff_ptr; PlayerProfile_Struct pp; + Inventory inv; + uint32 character_id = (uint32)atoi(row[0]); + uint8 has_home = 0; + uint8 has_bind = 0; + memset(&pp, 0, sizeof(PlayerProfile_Struct)); + + /* Fill CharacterSelectEntry_Struct */ + strcpy(cse->Name, row[1]); + cse->Class = (uint8)atoi(row[4]); + cse->Race = (uint32)atoi(row[3]); + cse->Level = (uint8)atoi(row[5]); + cse->ShroudClass = cse->Class; + cse->ShroudRace = cse->Race; + cse->Zone = (uint16)atoi(row[19]); + cse->Instance = 0; + cse->Gender = (uint8)atoi(row[2]); + cse->Face = (uint8)atoi(row[15]); + cse->Equip[0] = { 0 }; // Processed below + cse->Unknown15 = 0xFF; + cse->Unknown19 = 0xFF; + cse->DrakkinTattoo = (uint32)atoi(row[17]); + cse->DrakkinDetails = (uint32)atoi(row[18]); + cse->Deity = (uint32)atoi(row[6]); + cse->PrimaryIDFile = 0; // Processed Below + cse->SecondaryIDFile = 0; // Processed Below + cse->HairColor = (uint8)atoi(row[9]); + cse->BeardColor = (uint8)atoi(row[10]); + cse->EyeColor1 = (uint8)atoi(row[11]); + cse->EyeColor2 = (uint8)atoi(row[12]); + cse->HairStyle = (uint8)atoi(row[13]); + cse->Beard = (uint8)atoi(row[14]); + cse->Enabled = 1; + cse->Tutorial = 0; // Processed Below + cse->DrakkinHeritage = (uint32)atoi(row[16]); + cse->Unknown1 = 0; + cse->GoHome = 0; // Processed Below + cse->LastLogin = (uint32)atoi(row[7]); // RoF2 value: 1212696584 + cse->Unknown2 = 0; + /* Fill End */ - uint32 character_id = atoi(row[0]); - strcpy(cs->Name[char_num], row[1]); - uint8 lvl = atoi(row[5]); - cs->Level[char_num] = lvl; - cs->Class_[char_num] = atoi(row[4]); - cs->Race[char_num] = atoi(row[3]); - cs->Gender[char_num] = atoi(row[2]); - cs->Deity[char_num] = atoi(row[6]); - cs->Zone[char_num] = atoi(row[19]); - cs->Face[char_num] = atoi(row[15]); - cs->HairColor[char_num] = atoi(row[9]); - cs->BeardColor[char_num] = atoi(row[10]); - cs->EyeColor2[char_num] = atoi(row[12]); - cs->EyeColor1[char_num] = atoi(row[11]); - cs->HairStyle[char_num] = atoi(row[13]); - cs->Beard[char_num] = atoi(row[14]); - cs->DrakkinHeritage[char_num] = atoi(row[16]); - cs->DrakkinTattoo[char_num] = atoi(row[17]); - cs->DrakkinDetails[char_num] = atoi(row[18]); - - if (RuleB(World, EnableTutorialButton) && (lvl <= RuleI(World, MaxLevelForTutorial))) - cs->Tutorial[char_num] = 1; + if (RuleB(World, EnableTutorialButton) && (cse->Level <= RuleI(World, MaxLevelForTutorial))) { + cse->Tutorial = 1; + } if (RuleB(World, EnableReturnHomeButton)) { int now = time(nullptr); if ((now - atoi(row[7])) >= RuleI(World, MinOfflineTimeToReturnHome)) - cs->GoHome[char_num] = 1; + cse->GoHome = 1; } /* Set Bind Point Data for any character that may possibly be missing it for any reason */ cquery = StringFormat("SELECT `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `is_home` FROM `character_bind` WHERE `id` = %i LIMIT 2", character_id); - auto results_bind = database.QueryDatabase(cquery); has_home = 0; has_bind = 0; + auto results_bind = database.QueryDatabase(cquery); for (auto row_b = results_bind.begin(); row_b != results_bind.end(); ++row_b) { if (row_b[6] && atoi(row_b[6]) == 1){ has_home = 1; } if (row_b[6] && atoi(row_b[6]) == 0){ has_bind = 1; } } - if (has_home == 0 || has_bind == 0){ + if (has_home == 0 || has_bind == 0) { cquery = StringFormat("SELECT `zone_id`, `bind_id`, `x`, `y`, `z` FROM `start_zones` WHERE `player_class` = %i AND `player_deity` = %i AND `player_race` = %i", - cs->Class_[char_num], cs->Deity[char_num], cs->Race[char_num]); + cse->Class, cse->Deity, cse->Race); auto results_bind = database.QueryDatabase(cquery); for (auto row_d = results_bind.begin(); row_d != results_bind.end(); ++row_d) { /* If a bind_id is specified, make them start there */ @@ -134,32 +174,87 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* float z = atof(row_d[4]); if (x == 0 && y == 0 && z == 0){ GetSafePoints(pp.binds[4].zoneId, 0, &x, &y, &z); } pp.binds[4].x = x; pp.binds[4].y = y; pp.binds[4].z = z; - } } pp.binds[0] = pp.binds[4]; /* If no home bind set, set it */ - if (has_home == 0){ + if (has_home == 0) { std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)" " VALUES (%u, %u, %u, %f, %f, %f, %f, %i)", character_id, pp.binds[4].zoneId, 0, pp.binds[4].x, pp.binds[4].y, pp.binds[4].z, pp.binds[4].heading, 1); - auto results_bset = QueryDatabase(query); + auto results_bset = QueryDatabase(query); } /* If no regular bind set, set it */ - if (has_bind == 0){ + if (has_bind == 0) { std::string query = StringFormat("REPLACE INTO `character_bind` (id, zone_id, instance_id, x, y, z, heading, is_home)" " VALUES (%u, %u, %u, %f, %f, %f, %f, %i)", character_id, pp.binds[0].zoneId, 0, pp.binds[0].x, pp.binds[0].y, pp.binds[0].z, pp.binds[0].heading, 0); - auto results_bset = QueryDatabase(query); + auto results_bset = QueryDatabase(query); } } /* Bind End */ + /* Load Inventory */ + // If we ensure that the material data is updated appropriately, we can do away with inventory loads + if (GetInventory(accountID, cse->Name, &inv)) { + const Item_Struct* item = nullptr; + const ItemInst* inst = nullptr; + int16 invslot = 0; + + for (uint32 matslot = 0; matslot < _MaterialCount; matslot++) { + invslot = Inventory::CalcSlotFromMaterial(matslot); + if (invslot == INVALID_INDEX) { continue; } + inst = inv.GetItem(invslot); + if (inst == nullptr) { continue; } + item = inst->GetItem(); + if (item == nullptr) { continue; } + + if (matslot > 6) { + uint32 idfile = 0; + // Weapon Models + if (inst->GetOrnamentationIDFile() != 0) { + idfile = inst->GetOrnamentationIDFile(); + cse->Equip[matslot].Material = idfile; + } + else { + if (strlen(item->IDFile) > 2) { + idfile = atoi(&item->IDFile[2]); + cse->Equip[matslot].Material = idfile; + } + } + if (matslot == MaterialPrimary) { + cse->PrimaryIDFile = idfile; + } + else { + cse->SecondaryIDFile = idfile; + } + } + else { + uint32 color = 0; + if (pp.item_tint[matslot].RGB.UseTint) { + color = pp.item_tint[matslot].Color; + } + else { + color = inst->GetColor(); + } + + // Armor Materials/Models + cse->Equip[matslot].Material = item->Material; + cse->Equip[matslot].EliteMaterial = item->EliteMaterial; + cse->Equip[matslot].HeroForgeModel = inst->GetOrnamentHeroModel(matslot); + cse->Equip[matslot].Color.Color = color; + } + } + } + else { + printf("Error loading inventory for %s\n", cse->Name); + } + /* Load Inventory End */ + /* Load Character Material Data for Char Select */ cquery = StringFormat("SELECT slot, red, green, blue, use_tint, color FROM `character_material` WHERE `id` = %u", character_id); auto results_b = database.QueryDatabase(cquery); uint8 slot = 0; - for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b) - { + for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b) { slot = atoi(row_b[0]); pp.item_tint[slot].RGB.Red = atoi(row_b[1]); pp.item_tint[slot].RGB.Green = atoi(row_b[2]); @@ -167,81 +262,8 @@ void WorldDatabase::GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct* pp.item_tint[slot].RGB.UseTint = atoi(row_b[4]); } - /* Load Inventory */ - // If we ensure that the material data is updated appropriately, we can do away with inventory loads - inv = new Inventory; - if (GetInventory(account_id, cs->Name[char_num], inv)) - { - const Item_Struct* item = nullptr; - const ItemInst* inst = nullptr; - int16 invslot = 0; - - for (uint32 matslot = 0; matslot < _MaterialCount; matslot++) - { - invslot = Inventory::CalcSlotFromMaterial(matslot); - if (invslot == INVALID_INDEX) { continue; } - - inst = inv->GetItem(invslot); - if (inst == nullptr) { continue; } - - item = inst->GetItem(); - if (item == nullptr) { continue; } - - if (matslot > 6) - { - uint32 idfile = 0; - // Weapon Models - if (inst->GetOrnamentationIDFile() != 0) - { - idfile = inst->GetOrnamentationIDFile(); - cs->Equip[char_num][matslot].Material = idfile; - } - else - { - if (strlen(item->IDFile) > 2) - { - idfile = atoi(&item->IDFile[2]); - cs->Equip[char_num][matslot].Material = idfile; - } - } - if (matslot == MaterialPrimary) - { - cs->Primary[char_num] = idfile; - } - else - { - cs->Secondary[char_num] = idfile; - } - } - else - { - uint32 color = 0; - if (pp.item_tint[matslot].RGB.UseTint) - { - color = pp.item_tint[matslot].Color; - } - else - { - color = inst->GetColor(); - } - - // Armor Materials/Models - cs->Equip[char_num][matslot].Material = item->Material; - cs->Equip[char_num][matslot].EliteMaterial = item->EliteMaterial; - cs->Equip[char_num][matslot].HeroForgeModel = inst->GetOrnamentHeroModel(matslot); - cs->Equip[char_num][matslot].Color.Color = color; - } - } - } - else - { - printf("Error loading inventory for %s\n", cs->Name[char_num]); - } - - safe_delete(inv); + buff_ptr += sizeof(CharacterSelectEntry_Struct); } - - return; } int WorldDatabase::MoveCharacterToBind(int CharID, uint8 bindnum) { diff --git a/world/worlddb.h b/world/worlddb.h index 166248e72..b0c2ff221 100644 --- a/world/worlddb.h +++ b/world/worlddb.h @@ -20,6 +20,7 @@ #include "../common/shareddb.h" #include "../common/zone_numbers.h" +#include "../common/eq_packet.h" struct PlayerProfile_Struct; struct CharCreate_Struct; @@ -29,7 +30,7 @@ struct CharacterSelect_Struct; class WorldDatabase : public SharedDatabase { public: bool GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc, bool isTitanium); - void GetCharSelectInfo(uint32 account_id, CharacterSelect_Struct*, uint32 ClientVersion); + void GetCharSelectInfo(uint32 accountID, EQApplicationPacket **outApp, uint32 clientVersionBit); int MoveCharacterToBind(int CharID, uint8 bindnum = 0); void GetLauncherList(std::vector &result); From e7fc6420f2b60168ab2675d1bc88a6b1185379a4 Mon Sep 17 00:00:00 2001 From: Uleat Date: Tue, 17 Feb 2015 19:35:50 -0500 Subject: [PATCH 095/114] Added changelog entry for character limit --- changelog.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/changelog.txt b/changelog.txt index c04647bbc..393a954c8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,16 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/17/2015 == +Uleat: Implemented per-client character creation limiting. Caps are unknown atm..so, don't get over-zealous! +Notes: + - Titanium is hard-coded to min/max of 8 in both the server and client translator code (client doesn't support variations in available character count) + - SoF thru RoF2 have had their max characters raised to 12 from 10 + - Changing the number of characters per account is accomplished by: + 1) Setting consts::CHARACTER_CREATION_LIMIT to the desired count in the client's constants file in ../common/patches/ + 2) Ensuring that eq_dictionary's EmuConstants::CHARACTER_CREATION_LIMIT is equal-greater than the client's new value..referencing is good + 3) Recompiling the server code + - A rules-based qualifier may be added at some point + == 02/16/2015 == Trevius: (RoF2) Bazaar Trading (Buying/Selling) is now fully functional. Bazaar (/bazaar) search is not yet functional. demonstar55: (RoF2) Send the bard focus effects, note custom servers will need to fix their items, server side we still use the old system, but RoF2 wasn't showing anything with not sending focus, so send them From 911a515923f163cb641861948fd2fce19c5f2f8b Mon Sep 17 00:00:00 2001 From: Uleat Date: Wed, 18 Feb 2015 00:22:05 -0500 Subject: [PATCH 096/114] Fix for MySQL query failure --- world/client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/world/client.cpp b/world/client.cpp index 0393f0f65..c0492b7fd 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -730,7 +730,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { "`id`, " "name, " "`level`, " - "last_login, " + "last_login " "FROM " "character_data " "WHERE `account_id` = %i ORDER BY `name` LIMIT %u", GetAccountID(), character_limit); From b6dd604de23b6f0298b022bc39521028b3c955ee Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 18 Feb 2015 02:46:13 -0500 Subject: [PATCH 097/114] Fix for taunt. Added additional check to prevent recourse spells from recoursing themselves and crashing. --- zone/hate_list.cpp | 10 +++++----- zone/spells.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index dbc24296a..421e44304 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -282,14 +282,14 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center) return nullptr; Mob* top_hate = nullptr; - int32 hate = -1; + uint32 hate = 0; if (center == nullptr) return nullptr; if (RuleB(Aggro, SmartAggroList)){ Mob* top_client_type_in_range = nullptr; - int32 hate_client_type_in_range = -1; + uint32 hate_client_type_in_range = 0; int skipped_count = 0; auto iterator = list.begin(); @@ -337,7 +337,7 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center) continue; } - int32 current_hate = cur->stored_hate_amount; + uint32 current_hate = cur->stored_hate_amount; if (cur->entity_on_hatelist->IsClient()){ @@ -459,13 +459,13 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center) Mob *HateList::GetEntWithMostHateOnList(){ Mob* top = nullptr; - int32 hate = -1; + uint32 hate = 0; auto iterator = list.begin(); while (iterator != list.end()) { struct_HateList *cur = (*iterator); - if (cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate)) + if (cur && cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate)) { top = cur->entity_on_hatelist; hate = cur->stored_hate_amount; diff --git a/zone/spells.cpp b/zone/spells.cpp index 849dacfbe..b0ed519d9 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3742,7 +3742,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r return false; } - if (IsValidSpell(spells[spell_id].RecourseLink)) + if (IsValidSpell(spells[spell_id].RecourseLink) && spells[spell_id].RecourseLink != spell_id) SpellFinished(spells[spell_id].RecourseLink, this, 10, 0, -1, spells[spells[spell_id].RecourseLink].ResistDiff); if (IsDetrimentalSpell(spell_id)) { From 2d40adcf66ba88ec13b3e65964262a77f827bc08 Mon Sep 17 00:00:00 2001 From: KimLS Date: Wed, 18 Feb 2015 12:39:28 -0800 Subject: [PATCH 098/114] Partial revert/rewrite of b6dd604, should be possible to get things on a hate list that have zero hate again --- zone/hate_list.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index 421e44304..df76216ae 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -282,14 +282,14 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center) return nullptr; Mob* top_hate = nullptr; - uint32 hate = 0; + int64 hate = -1; if (center == nullptr) return nullptr; if (RuleB(Aggro, SmartAggroList)){ Mob* top_client_type_in_range = nullptr; - uint32 hate_client_type_in_range = 0; + int64 hate_client_type_in_range = -1; int skipped_count = 0; auto iterator = list.begin(); @@ -337,7 +337,7 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center) continue; } - uint32 current_hate = cur->stored_hate_amount; + int64 current_hate = cur->stored_hate_amount; if (cur->entity_on_hatelist->IsClient()){ @@ -459,7 +459,7 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center) Mob *HateList::GetEntWithMostHateOnList(){ Mob* top = nullptr; - uint32 hate = 0; + int64 hate = -1; auto iterator = list.begin(); while (iterator != list.end()) From 7deb4d5e789e53227f1bd1086f4be5c4adcb1176 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 18 Feb 2015 18:28:46 -0500 Subject: [PATCH 099/114] Fix potion belt loading --- zone/zonedb.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 07a3df930..685fbd3ca 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1231,20 +1231,24 @@ bool ZoneDatabase::LoadCharacterTribute(uint32 character_id, PlayerProfile_Struc return true; } -bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp) +bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct *pp) { - std::string query = StringFormat("SELECT `potion_id`, `item_id`, `icon` FROM `character_potionbelt` WHERE `id` = %u LIMIT %u", - character_id, EmuConstants::POTION_BELT_ITEM_COUNT); - auto results = database.QueryDatabase(query); int i = 0; - for (i = 0; i < EmuConstants::POTION_BELT_ITEM_COUNT; i++){ + std::string query = + StringFormat("SELECT `potion_id`, `item_id`, `icon` FROM `character_potionbelt` WHERE `id` = %u LIMIT %u", + character_id, EmuConstants::POTION_BELT_ITEM_COUNT); + auto results = database.QueryDatabase(query); + int i = 0; + for (i = 0; i < EmuConstants::POTION_BELT_ITEM_COUNT; i++) { pp->potionbelt.Items[i].Icon = 0; pp->potionbelt.Items[i].ID = 0; pp->potionbelt.Items[i].Name[0] = '\0'; } for (auto row = results.begin(); row != results.end(); ++row) { + i = atoi(row[0]); const Item_Struct *item_data = database.GetItem(atoi(row[1])); - if (item_data == nullptr) { continue; } + if (!item_data) + continue; pp->potionbelt.Items[i].ID = item_data->ID; pp->potionbelt.Items[i].Icon = atoi(row[2]); strncpy(pp->potionbelt.Items[i].Name, item_data->Name, 64); From 414db873b7de615ca8ad1154d20bc71070524342 Mon Sep 17 00:00:00 2001 From: Uleat Date: Wed, 18 Feb 2015 19:18:53 -0500 Subject: [PATCH 100/114] Fix for tints not showing up at character select (world server) --- world/worlddb.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 4ba21101c..8099b9ee2 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -194,6 +194,18 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou } /* Bind End */ + /* Load Character Material Data for Char Select */ + cquery = StringFormat("SELECT slot, red, green, blue, use_tint, color FROM `character_material` WHERE `id` = %u", character_id); + auto results_b = database.QueryDatabase(cquery); uint8 slot = 0; + for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b) { + slot = atoi(row_b[0]); + pp.item_tint[slot].RGB.Red = atoi(row_b[1]); + pp.item_tint[slot].RGB.Green = atoi(row_b[2]); + pp.item_tint[slot].RGB.Blue = atoi(row_b[3]); + pp.item_tint[slot].RGB.UseTint = atoi(row_b[4]); + } + /* Character Material Data End */ + /* Load Inventory */ // If we ensure that the material data is updated appropriately, we can do away with inventory loads if (GetInventory(accountID, cse->Name, &inv)) { @@ -251,17 +263,6 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou } /* Load Inventory End */ - /* Load Character Material Data for Char Select */ - cquery = StringFormat("SELECT slot, red, green, blue, use_tint, color FROM `character_material` WHERE `id` = %u", character_id); - auto results_b = database.QueryDatabase(cquery); uint8 slot = 0; - for (auto row_b = results_b.begin(); row_b != results_b.end(); ++row_b) { - slot = atoi(row_b[0]); - pp.item_tint[slot].RGB.Red = atoi(row_b[1]); - pp.item_tint[slot].RGB.Green = atoi(row_b[2]); - pp.item_tint[slot].RGB.Blue = atoi(row_b[3]); - pp.item_tint[slot].RGB.UseTint = atoi(row_b[4]); - } - buff_ptr += sizeof(CharacterSelectEntry_Struct); } } From 3b45a66498144b065d56c5725c74f8690deeb356 Mon Sep 17 00:00:00 2001 From: Trevius Date: Wed, 18 Feb 2015 21:32:18 -0600 Subject: [PATCH 101/114] Fix for potential recursive loops if using RemoveFromHateList() within EVENT_HATE_LIST. Some work on Bazaar searching, but not functional yet. --- changelog.txt | 3 ++ common/eq_packet_structs.h | 5 +- common/patches/rof2.cpp | 38 ++++++++++++++- common/patches/rof2_structs.h | 10 ++-- zone/client_packet.cpp | 87 +++++++++++++++++++++-------------- zone/hate_list.cpp | 6 +-- zone/trading.cpp | 28 +++++------ 7 files changed, 119 insertions(+), 58 deletions(-) diff --git a/changelog.txt b/changelog.txt index 393a954c8..60af1336d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/18/2015 == +Trevius: Fix for potential recursive loops if using RemoveFromHateList() within EVENT_HATE_LIST. + == 02/17/2015 == Uleat: Implemented per-client character creation limiting. Caps are unknown atm..so, don't get over-zealous! Notes: diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 188214dad..3f14e1cc9 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -2776,7 +2776,8 @@ struct BazaarWelcome_Struct { BazaarWindowStart_Struct Beginning; uint32 Traders; uint32 Items; - uint8 Unknown012[8]; + uint32 Unknown012; + uint32 Unknown016; }; struct BazaarSearch_Struct { @@ -3207,7 +3208,7 @@ struct TraderDelItem_Struct{ struct TraderClick_Struct{ /*000*/ uint32 TraderID; -/*004*/ uint32 Unknown004; +/*004*/ uint32 Code; /*008*/ uint32 Unknown008; /*012*/ uint32 Approval; /*016*/ diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index 0ad31517e..e1f3b071a 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -3667,6 +3667,23 @@ namespace RoF2 FINISH_ENCODE(); } + else if (psize == sizeof(BazaarWelcome_Struct)) + { + ENCODE_LENGTH_EXACT(BazaarWelcome_Struct); + SETUP_DIRECT_ENCODE(BazaarWelcome_Struct, structs::BazaarWelcome_Struct); + + eq->Code = emu->Beginning.Action; + eq->EntityID = emu->Unknown012; + OUT(Traders); + OUT(Items); + eq->Traders2 = emu->Traders; + eq->Items2 = emu->Items; + + Log.Out(Logs::Detail, Logs::Trading, "ENCODE(OP_TraderShop): BazaarWelcome_Struct Code %d, Traders %d, Items %d", + eq->Code, eq->Traders, eq->Items); + + FINISH_ENCODE(); + } else if (psize == sizeof(TraderBuy_Struct)) { ENCODE_LENGTH_EXACT(TraderBuy_Struct); @@ -5009,8 +5026,25 @@ namespace RoF2 DECODE_LENGTH_EXACT(structs::TraderClick_Struct); SETUP_DIRECT_DECODE(TraderClick_Struct, structs::TraderClick_Struct); + IN(Code); IN(TraderID); IN(Approval); + Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderClick_Struct Code %d, TraderID %d, Approval %d", + eq->Code, eq->TraderID, eq->Approval); + + FINISH_DIRECT_DECODE(); + } + else if (psize == sizeof(structs::BazaarWelcome_Struct)) + { + // Don't think this size gets used in RoF+ - Leaving for now... + DECODE_LENGTH_EXACT(structs::BazaarWelcome_Struct); + SETUP_DIRECT_DECODE(BazaarWelcome_Struct, structs::BazaarWelcome_Struct); + + emu->Beginning.Action = eq->Code; + IN(Traders); + IN(Items); + Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): BazaarWelcome_Struct Code %d, Traders %d, Items %d", + eq->Code, eq->Traders, eq->Items); FINISH_DIRECT_DECODE(); } @@ -5026,9 +5060,9 @@ namespace RoF2 memcpy(emu->ItemName, eq->ItemName, sizeof(emu->ItemName)); IN(ItemID); IN(Quantity); - Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): (Unknowns) Unknown004 %d, Unknown008 %d, Unknown012 %d, Unknown076 %d, Unknown276 %d", + Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderBuy_Struct (Unknowns) Unknown004 %d, Unknown008 %d, Unknown012 %d, Unknown076 %d, Unknown276 %d", eq->Unknown004, eq->Unknown008, eq->Unknown012, eq->Unknown076, eq->Unknown276); - Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s", + Log.Out(Logs::Detail, Logs::Trading, "DECODE(OP_TraderShop): TraderBuy_Struct Buy Action %d, Price %d, Trader %d, ItemID %d, Quantity %d, ItemName, %s", eq->Action, eq->Price, eq->TraderID, eq->ItemID, eq->Quantity, eq->ItemName); FINISH_DIRECT_DECODE(); diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index fd6f0b2ea..520e9066e 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -2940,10 +2940,12 @@ struct BazaarWindowStart_Struct { struct BazaarWelcome_Struct { - BazaarWindowStart_Struct Beginning; - uint32 Traders; - uint32 Items; - uint8 Unknown012[8]; + uint32 Code; + uint32 EntityID; + uint32 Traders; + uint32 Items; + uint32 Traders2; + uint32 Items2; }; struct BazaarSearch_Struct { diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 789071848..5205942b2 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -13516,49 +13516,68 @@ void Client::Handle_OP_TraderShop(const EQApplicationPacket *app) if (app->size == sizeof(TraderClick_Struct)) { - // This is when a potential purchaser right clicks on this client who is in Trader mode to - // browse their goods. + TraderClick_Struct* tcs = (TraderClick_Struct*)app->pBuffer; - EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct)); + Log.Out(Logs::Detail, Logs::Trading, "Handle_OP_TraderShop: TraderClick_Struct TraderID %d, Code %d, Unknown008 %d, Approval %d", + tcs->TraderID, tcs->Code, tcs->Unknown008, tcs->Approval); - TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer; - - Client* Trader = entity_list.GetClientByID(tcs->TraderID); - - if (Trader) + if (tcs->Code == BazaarWelcome) { - outtcs->Approval = Trader->WithCustomer(GetID()); - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Shop Request (%s) to (%s) with Approval: %d", GetCleanName(), Trader->GetCleanName(), outtcs->Approval); - } - else { - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)" - " returned a nullptr pointer"); - return; - } - - outtcs->TraderID = tcs->TraderID; - - outtcs->Unknown008 = 0x3f800000; - - QueuePacket(outapp); - - - if (outtcs->Approval) { - this->BulkSendTraderInventory(Trader->CharacterID()); - Trader->Trader_CustomerBrowsing(this); - TraderID = tcs->TraderID; - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Inventory Sent"); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Sent Bazaar Welcome Info"); + SendBazaarWelcome(); } else { - Message_StringID(clientMessageYellow, TRADER_BUSY); - Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Busy"); + // This is when a potential purchaser right clicks on this client who is in Trader mode to + // browse their goods. + EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderClick_Struct)); + + TraderClick_Struct* outtcs = (TraderClick_Struct*)outapp->pBuffer; + + Client* Trader = entity_list.GetClientByID(tcs->TraderID); + + if (Trader) + { + outtcs->Approval = Trader->WithCustomer(GetID()); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Shop Request (%s) to (%s) with Approval: %d", GetCleanName(), Trader->GetCleanName(), outtcs->Approval); + } + else { + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: entity_list.GetClientByID(tcs->traderid)" + " returned a nullptr pointer"); + return; + } + + outtcs->TraderID = tcs->TraderID; + + outtcs->Unknown008 = 0x3f800000; + + QueuePacket(outapp); + + + if (outtcs->Approval) { + this->BulkSendTraderInventory(Trader->CharacterID()); + Trader->Trader_CustomerBrowsing(this); + TraderID = tcs->TraderID; + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Inventory Sent"); + } + else + { + Message_StringID(clientMessageYellow, TRADER_BUSY); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Trader Busy"); + } + + safe_delete(outapp); + return; } - safe_delete(outapp); - - return; + } + else if (app->size == sizeof(BazaarWelcome_Struct)) + { + // RoF+ + // Client requested Bazaar Welcome Info (Trader and Item Total Counts) + SendBazaarWelcome(); + Log.Out(Logs::Detail, Logs::Trading, "Client::Handle_OP_TraderShop: Sent Bazaar Welcome Info"); } else if (app->size == sizeof(TraderBuy_Struct)) { diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index df76216ae..e68924844 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -219,17 +219,17 @@ bool HateList::RemoveEntFromHateList(Mob *in_entity) { if ((*iterator)->entity_on_hatelist == in_entity) { - if (in_entity) - parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "0", 0); is_found = true; - if (in_entity && in_entity->IsClient()) in_entity->CastToClient()->DecrementAggroCount(); delete (*iterator); iterator = list.erase(iterator); + if (in_entity) + parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "0", 0); + } else ++iterator; diff --git a/zone/trading.cpp b/zone/trading.cpp index 047aa3a6a..91d9c8a8a 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -1558,18 +1558,7 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplic return; } - EQApplicationPacket* outapp = nullptr; - - if (Trader->GetClientVersion() >= ClientVersion::RoF) - { - //outapp = new EQApplicationPacket(OP_TraderShop, sizeof(TraderBuy_Struct)); - } - else - { - //outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderBuy_Struct)); - } - - outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderBuy_Struct)); + EQApplicationPacket* outapp = new EQApplicationPacket(OP_Trader, sizeof(TraderBuy_Struct)); TraderBuy_Struct* outtbs = (TraderBuy_Struct*)outapp->pBuffer; @@ -1701,7 +1690,15 @@ void Client::SendBazaarWelcome() if (results.Success() && results.RowCount() == 1){ auto row = results.begin(); - EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarWelcome_Struct)); + EQApplicationPacket* outapp = nullptr; + if (GetClientVersion() >= ClientVersion::RoF) + { + outapp = new EQApplicationPacket(OP_TraderShop, sizeof(BazaarWelcome_Struct)); + } + else + { + outapp = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarWelcome_Struct)); + } memset(outapp->pBuffer,0,outapp->size); @@ -1712,6 +1709,11 @@ void Client::SendBazaarWelcome() bws->Traders = atoi(row[0]); bws->Items = atoi(row[1]); + if (GetClientVersion() >= ClientVersion::RoF) + { + bws->Unknown012 = GetID(); + } + QueuePacket(outapp); safe_delete(outapp); From 921a292f5bd021cec9dba5fe4f2b05c1be8ec9b4 Mon Sep 17 00:00:00 2001 From: Uleat Date: Thu, 19 Feb 2015 21:56:14 -0500 Subject: [PATCH 102/114] Fix for new Titanium to UF client accounts not allowing character creation --- common/patches/sod.cpp | 2 +- common/patches/sof.cpp | 2 +- common/patches/titanium.cpp | 12 +++++++----- common/patches/uf.cpp | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index a8b69556a..adf4ec06f 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -1918,7 +1918,7 @@ namespace SoD if (emu->CharCount == 0) { ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct)); eq->CharCount = emu->CharCount; - eq->TotalChars = eq->TotalChars; + eq->TotalChars = emu->TotalChars; if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index e0b24b393..a7553e7f9 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -1577,7 +1577,7 @@ namespace SoF if (emu->CharCount == 0) { ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct)); eq->CharCount = emu->CharCount; - eq->TotalChars = eq->TotalChars; + eq->TotalChars = emu->TotalChars; if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index efacfe980..b183acf4b 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -1192,12 +1192,12 @@ namespace Titanium } eq->SecondaryIDFile[char_index] = emu_cse->SecondaryIDFile; - eq->Unknown820[char_index] = 0xFF; + eq->Unknown820[char_index] = (uint8)0xFF; eq->Deity[char_index] = emu_cse->Deity; eq->GoHome[char_index] = emu_cse->GoHome; eq->Tutorial[char_index] = emu_cse->Tutorial; eq->Beard[char_index] = emu_cse->Beard; - eq->Unknown902[char_index] = 0xFF; + eq->Unknown902[char_index] = (uint8)0xFF; eq->PrimaryIDFile[char_index] = emu_cse->PrimaryIDFile; eq->HairColor[char_index] = emu_cse->HairColor; eq->Zone[char_index] = emu_cse->Zone; @@ -1229,18 +1229,20 @@ namespace Titanium } eq->SecondaryIDFile[char_index] = 0; - eq->Unknown820[char_index] = 0xFF; + eq->Unknown820[char_index] = (uint8)0xFF; eq->Deity[char_index] = 0; eq->GoHome[char_index] = 0; eq->Tutorial[char_index] = 0; eq->Beard[char_index] = 0; - eq->Unknown902[char_index] = 0xFF; + eq->Unknown902[char_index] = (uint8)0xFF; eq->PrimaryIDFile[char_index] = 0; eq->HairColor[char_index] = 0; eq->Zone[char_index] = 0; eq->Class[char_index] = 0; eq->Face[char_index] = 0; - //eq->Name[char_index][0] = '\0'; // Cleared above + + strncpy(eq->Name[char_index], "", 6); + eq->Gender[char_index] = 0; eq->EyeColor1[char_index] = 0; eq->EyeColor2[char_index] = 0; diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index d8635485c..aafef5896 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -2201,7 +2201,7 @@ namespace UF if (emu->CharCount == 0) { ALLOC_VAR_ENCODE(structs::CharacterSelect_Struct, sizeof(structs::CharacterSelect_Struct)); eq->CharCount = emu->CharCount; - eq->TotalChars = eq->TotalChars; + eq->TotalChars = emu->TotalChars; if (eq->TotalChars > consts::CHARACTER_CREATION_LIMIT) eq->TotalChars = consts::CHARACTER_CREATION_LIMIT; From c5a217842f5b725e96affc14926d1a3da0e9f06e Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 20 Feb 2015 16:29:56 -0500 Subject: [PATCH 103/114] Fix issues with claims and implement for RoF/RoF2 --- changelog.txt | 4 ++ common/base_packet.h | 1 + common/eq_packet_structs.h | 13 ++--- common/patches/rof.cpp | 86 ++++++++++++++++++++++++------- common/patches/rof2.cpp | 86 ++++++++++++++++++++++++------- common/patches/rof2_ops.h | 2 + common/patches/rof2_structs.h | 30 ++++++++--- common/patches/rof_ops.h | 2 + common/patches/rof_structs.h | 30 ++++++++--- utils/patches/patch_Titanium.conf | 2 +- zone/client.cpp | 69 ++++++++++++------------- zone/client_packet.cpp | 47 +++++++---------- 12 files changed, 243 insertions(+), 129 deletions(-) diff --git a/changelog.txt b/changelog.txt index 60af1336d..931ccf079 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,9 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/20/2015 == +demonstar55: Implement claims for RoF/RoF2 (should no longer crash the client!) + - fixed bugs related to claims for the rest of the clients (woo infinite loops) + == 02/18/2015 == Trevius: Fix for potential recursive loops if using RemoveFromHateList() within EVENT_HATE_LIST. diff --git a/common/base_packet.h b/common/base_packet.h index facd98809..027b8d2fb 100644 --- a/common/base_packet.h +++ b/common/base_packet.h @@ -63,6 +63,7 @@ public: void WriteFloat(float value) { *(float *)(pBuffer + _wpos) = value; _wpos += sizeof(float); } void WriteDouble(double value) { *(double *)(pBuffer + _wpos) = value; _wpos += sizeof(double); } void WriteString(const char * str) { uint32 len = static_cast(strlen(str)) + 1; memcpy(pBuffer + _wpos, str, len); _wpos += len; } + void WriteData(const void *ptr, size_t n) { memcpy(pBuffer + _wpos, ptr, n); _wpos += n; } uint8 ReadUInt8() { uint8 value = *(uint8 *)(pBuffer + _rpos); _rpos += sizeof(uint8); return value; } uint8 ReadUInt8(uint32 Offset) const { uint8 value = *(uint8 *)(pBuffer + Offset); return value; } diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 3f14e1cc9..27fe9bb2b 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -4553,19 +4553,12 @@ struct InternalVeteranReward /*012*/ InternalVeteranRewardItem items[8]; }; -struct VeteranClaimReply +struct VeteranClaim { -/*000*/ char name[64]; -/*064*/ uint32 claim_id; -/*068*/ uint32 reject_field; -/*072*/ uint32 unknown072; -}; - -struct VeteranClaimRequest -{ -/*000*/ char name_data[64]; //name + other data +/*000*/ char name[64]; //name + other data /*064*/ uint32 claim_id; /*068*/ uint32 unknown068; +/*072*/ uint32 action; }; struct GMSearchCorpse_Struct diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 485dc4118..d6723db4d 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -15,6 +15,8 @@ #include #include +#include +#include namespace RoF { @@ -3608,37 +3610,71 @@ namespace RoF FINISH_ENCODE(); } + ENCODE(OP_VetClaimReply) + { + ENCODE_LENGTH_EXACT(VeteranClaim); + SETUP_DIRECT_ENCODE(VeteranClaim, structs::VeteranClaim); + + memcpy(eq->name, emu->name, sizeof(emu->name)); + OUT(claim_id); + OUT(action); + + FINISH_ENCODE(); + } + ENCODE(OP_VetRewardsAvaliable) { EQApplicationPacket *inapp = *p; - unsigned char * __emu_buffer = inapp->pBuffer; + auto __emu_buffer = inapp->pBuffer; uint32 count = ((*p)->Size() / sizeof(InternalVeteranReward)); - *p = nullptr; - EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward)*count)); - uchar *old_data = __emu_buffer; - uchar *data = outapp_create->pBuffer; - for (unsigned int i = 0; i < count; ++i) - { - structs::VeteranReward *vr = (structs::VeteranReward*)data; - InternalVeteranReward *ivr = (InternalVeteranReward*)old_data; + // calculate size of names, note the packet DOES NOT have null termed c-strings + std::vector name_lengths; + for (int i = 0; i < count; ++i) { + InternalVeteranReward *ivr = (InternalVeteranReward *)__emu_buffer; - vr->claim_count = ivr->claim_count; - vr->claim_id = ivr->claim_id; - vr->number_available = ivr->number_available; - for (int x = 0; x < 8; ++x) - { - vr->items[x].item_id = ivr->items[x].item_id; - strncpy(vr->items[x].item_name, ivr->items[x].item_name, sizeof(vr->items[x].item_name)); - vr->items[x].charges = ivr->items[x].charges; + for (int i = 0; i < ivr->claim_count; i++) { + uint32 length = strnlen(ivr->items[i].item_name, 63); + if (length) + name_lengths.push_back(length); } - old_data += sizeof(InternalVeteranReward); - data += sizeof(structs::VeteranReward); + __emu_buffer += sizeof(InternalVeteranReward); } - dest->FastQueuePacket(&outapp_create); + uint32 packet_size = std::accumulate(name_lengths.begin(), name_lengths.end(), 0) + + sizeof(structs::VeteranReward) + (sizeof(structs::VeteranRewardEntry) * count) + + // size of name_lengths is the same as item count + (sizeof(structs::VeteranRewardItem) * name_lengths.size()); + + // build packet now! + auto outapp = new EQApplicationPacket(OP_VetRewardsAvaliable, packet_size); + __emu_buffer = inapp->pBuffer; + + outapp->WriteUInt32(count); + auto name_itr = name_lengths.begin(); + for (int i = 0; i < count; i++) { + InternalVeteranReward *ivr = (InternalVeteranReward *)__emu_buffer; + + outapp->WriteUInt32(ivr->claim_id); + outapp->WriteUInt32(ivr->number_available); + outapp->WriteUInt32(ivr->claim_count); + outapp->WriteUInt8(1); // enabled + + for (int j = 0; j < ivr->claim_count; j++) { + assert(name_itr != name_lengths.end()); // the way it's written, it should never happen, so just assert + outapp->WriteUInt32(*name_itr); + outapp->WriteData(ivr->items[j].item_name, *name_itr); + outapp->WriteUInt32(ivr->items[j].item_id); + outapp->WriteUInt32(ivr->items[j].charges); + ++name_itr; + } + + __emu_buffer += sizeof(InternalVeteranReward); + } + + dest->FastQueuePacket(&outapp); delete inapp; } @@ -4924,6 +4960,16 @@ namespace RoF FINISH_DIRECT_DECODE(); } + DECODE(OP_VetClaimRequest) + { + DECODE_LENGTH_EXACT(structs::VeteranClaim); + SETUP_DIRECT_DECODE(VeteranClaim, structs::VeteranClaim); + + IN(claim_id); + + FINISH_DIRECT_DECODE(); + } + DECODE(OP_ZoneChange) { DECODE_LENGTH_EXACT(structs::ZoneChange_Struct); diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index e1f3b071a..493f369e1 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -15,6 +15,8 @@ #include #include +#include +#include namespace RoF2 { @@ -3749,37 +3751,71 @@ namespace RoF2 FINISH_ENCODE(); } + ENCODE(OP_VetClaimReply) + { + ENCODE_LENGTH_EXACT(VeteranClaim); + SETUP_DIRECT_ENCODE(VeteranClaim, structs::VeteranClaim); + + memcpy(eq->name, emu->name, sizeof(emu->name)); + OUT(claim_id); + OUT(action); + + FINISH_ENCODE(); + } + ENCODE(OP_VetRewardsAvaliable) { EQApplicationPacket *inapp = *p; - unsigned char * __emu_buffer = inapp->pBuffer; + auto __emu_buffer = inapp->pBuffer; uint32 count = ((*p)->Size() / sizeof(InternalVeteranReward)); - *p = nullptr; - EQApplicationPacket *outapp_create = new EQApplicationPacket(OP_VetRewardsAvaliable, (sizeof(structs::VeteranReward)*count)); - uchar *old_data = __emu_buffer; - uchar *data = outapp_create->pBuffer; - for (unsigned int i = 0; i < count; ++i) - { - structs::VeteranReward *vr = (structs::VeteranReward*)data; - InternalVeteranReward *ivr = (InternalVeteranReward*)old_data; + // calculate size of names, note the packet DOES NOT have null termed c-strings + std::vector name_lengths; + for (int i = 0; i < count; ++i) { + InternalVeteranReward *ivr = (InternalVeteranReward *)__emu_buffer; - vr->claim_count = ivr->claim_count; - vr->claim_id = ivr->claim_id; - vr->number_available = ivr->number_available; - for (int x = 0; x < 8; ++x) - { - vr->items[x].item_id = ivr->items[x].item_id; - strncpy(vr->items[x].item_name, ivr->items[x].item_name, sizeof(vr->items[x].item_name)); - vr->items[x].charges = ivr->items[x].charges; + for (int i = 0; i < ivr->claim_count; i++) { + uint32 length = strnlen(ivr->items[i].item_name, 63); + if (length) + name_lengths.push_back(length); } - old_data += sizeof(InternalVeteranReward); - data += sizeof(structs::VeteranReward); + __emu_buffer += sizeof(InternalVeteranReward); } - dest->FastQueuePacket(&outapp_create); + uint32 packet_size = std::accumulate(name_lengths.begin(), name_lengths.end(), 0) + + sizeof(structs::VeteranReward) + (sizeof(structs::VeteranRewardEntry) * count) + + // size of name_lengths is the same as item count + (sizeof(structs::VeteranRewardItem) * name_lengths.size()); + + // build packet now! + auto outapp = new EQApplicationPacket(OP_VetRewardsAvaliable, packet_size); + __emu_buffer = inapp->pBuffer; + + outapp->WriteUInt32(count); + auto name_itr = name_lengths.begin(); + for (int i = 0; i < count; i++) { + InternalVeteranReward *ivr = (InternalVeteranReward *)__emu_buffer; + + outapp->WriteUInt32(ivr->claim_id); + outapp->WriteUInt32(ivr->number_available); + outapp->WriteUInt32(ivr->claim_count); + outapp->WriteUInt8(1); // enabled + + for (int j = 0; j < ivr->claim_count; j++) { + assert(name_itr != name_lengths.end()); // the way it's written, it should never happen, so just assert + outapp->WriteUInt32(*name_itr); + outapp->WriteData(ivr->items[j].item_name, *name_itr); + outapp->WriteUInt32(ivr->items[j].item_id); + outapp->WriteUInt32(ivr->items[j].charges); + ++name_itr; + } + + __emu_buffer += sizeof(InternalVeteranReward); + } + + dest->FastQueuePacket(&outapp); delete inapp; } @@ -5122,6 +5158,16 @@ namespace RoF2 FINISH_DIRECT_DECODE(); } + DECODE(OP_VetClaimRequest) + { + DECODE_LENGTH_EXACT(structs::VeteranClaim); + SETUP_DIRECT_DECODE(VeteranClaim, structs::VeteranClaim); + + IN(claim_id); + + FINISH_DIRECT_DECODE(); + } + DECODE(OP_ZoneChange) { DECODE_LENGTH_EXACT(structs::ZoneChange_Struct); diff --git a/common/patches/rof2_ops.h b/common/patches/rof2_ops.h index 3edcac459..4e4400cdf 100644 --- a/common/patches/rof2_ops.h +++ b/common/patches/rof2_ops.h @@ -111,6 +111,7 @@ E(OP_Trader) E(OP_TraderBuy) E(OP_TributeInfo) E(OP_TributeItem) +E(OP_VetClaimReply) E(OP_VetRewardsAvaliable) E(OP_WearChange) E(OP_WhoAllResponse) @@ -174,6 +175,7 @@ D(OP_Trader) D(OP_TraderBuy) D(OP_TradeSkillCombine) D(OP_TributeItem) +D(OP_VetClaimRequest) D(OP_WhoAllRequest) D(OP_ZoneChange) D(OP_ZoneEntry) diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 520e9066e..0f2e4548b 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -4727,17 +4727,33 @@ struct AugmentInfo_Struct struct VeteranRewardItem { -/*000*/ uint32 item_id; -/*004*/ uint32 charges; -/*008*/ char item_name[64]; +/*000*/ uint32 name_length; +/*004*/ char item_name[0]; // THIS IS NOT NULL TERMED +/*???*/ uint32 item_id; +/*???*/ uint32 charges; +}; + +struct VeteranRewardEntry +{ +/*000*/ uint32 claim_id; // guessed +/*004*/ uint32 avaliable_count; +/*008*/ uint32 claim_count; +/*012*/ char enabled; +/*013*/ VeteranRewardItem items[0]; }; struct VeteranReward { -/*000*/ uint32 claim_id; -/*004*/ uint32 number_available; -/*008*/ uint32 claim_count; -/*012*/ VeteranRewardItem items[8]; +/*000*/ uint32 claim_count; +/*004*/ VeteranRewardEntry entries[0]; +}; + +struct VeteranClaim +{ +/*000*/ char name[68]; //name + other data +/*068*/ uint32 claim_id; +/*072*/ uint32 unknown072; +/*076*/ uint32 action; }; struct ExpeditionEntryHeader_Struct diff --git a/common/patches/rof_ops.h b/common/patches/rof_ops.h index 8c55cd857..08e8647f3 100644 --- a/common/patches/rof_ops.h +++ b/common/patches/rof_ops.h @@ -96,6 +96,7 @@ E(OP_Trader) E(OP_TraderBuy) E(OP_TributeInfo) E(OP_TributeItem) +E(OP_VetClaimReply) E(OP_VetRewardsAvaliable) E(OP_WearChange) E(OP_WhoAllResponse) @@ -159,6 +160,7 @@ D(OP_Trader) D(OP_TraderBuy) D(OP_TradeSkillCombine) D(OP_TributeItem) +D(OP_VetClaimRequest) D(OP_WhoAllRequest) D(OP_ZoneChange) D(OP_ZoneEntry) diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 4b8fe3b01..05943d81a 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -4718,17 +4718,33 @@ struct AugmentInfo_Struct struct VeteranRewardItem { -/*000*/ uint32 item_id; -/*004*/ uint32 charges; -/*008*/ char item_name[64]; +/*000*/ uint32 name_length; +/*004*/ char item_name[0]; // THIS IS NOT NULL TERMED +/*???*/ uint32 item_id; +/*???*/ uint32 charges; +}; + +struct VeteranRewardEntry +{ +/*000*/ uint32 claim_id; // guessed +/*004*/ uint32 avaliable_count; +/*008*/ uint32 claim_count; +/*012*/ char enabled; +/*013*/ VeteranRewardItem items[0]; }; struct VeteranReward { -/*000*/ uint32 claim_id; -/*004*/ uint32 number_available; -/*008*/ uint32 claim_count; -/*012*/ VeteranRewardItem items[8]; +/*000*/ uint32 claim_count; +/*004*/ VeteranRewardEntry entries[0]; +}; + +struct VeteranClaim +{ +/*000*/ char name[68]; //name + other data +/*068*/ uint32 claim_id; +/*072*/ uint32 unknown072; +/*076*/ uint32 action; }; struct ExpeditionEntryHeader_Struct diff --git a/utils/patches/patch_Titanium.conf b/utils/patches/patch_Titanium.conf index 841f77bf5..2660738de 100644 --- a/utils/patches/patch_Titanium.conf +++ b/utils/patches/patch_Titanium.conf @@ -525,7 +525,7 @@ OP_KnowledgeBase=0x0000 OP_SlashAdventure=0x571a # /adventure OP_VetRewardsAvaliable=0x0557 OP_VetClaimRequest=0x6ba0 -OP_VetClaimReply=0x0000 +OP_VetClaimReply=0x407e OP_BecomePVPPrompt=0x36B2 #guessed from ASM OP_PVPStats=0x5cc0 OP_PVPLeaderBoardRequest=0x61d2 diff --git a/zone/client.cpp b/zone/client.cpp index 227bb4083..e72672369 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -5362,35 +5362,35 @@ void Client::SendRewards() FastQueuePacket(&vetapp); } -bool Client::TryReward(uint32 claim_id) { - //Make sure we have an open spot - //Make sure we have it in our acct and count > 0 - //Make sure the entry was found - //If we meet all the criteria: - //Decrement our count by 1 if it > 1 delete if it == 1 - //Create our item in bag if necessary at the free inv slot - //save +bool Client::TryReward(uint32 claim_id) +{ + // Make sure we have an open spot + // Make sure we have it in our acct and count > 0 + // Make sure the entry was found + // If we meet all the criteria: + // Decrement our count by 1 if it > 1 delete if it == 1 + // Create our item in bag if necessary at the free inv slot + // save uint32 free_slot = 0xFFFFFFFF; - for(int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; ++i) { + for (int i = EmuConstants::GENERAL_BEGIN; i <= EmuConstants::GENERAL_END; ++i) { ItemInst *item = GetInv().GetItem(i); - if(!item) { + if (!item) { free_slot = i; break; } } - if(free_slot == 0xFFFFFFFF) + if (free_slot == 0xFFFFFFFF) return false; char errbuf[MYSQL_ERRMSG_SIZE]; std::string query = StringFormat("SELECT amount FROM account_rewards " - "WHERE account_id = %i AND reward_id = %i", - AccountID(), claim_id); + "WHERE account_id = %i AND reward_id = %i", + AccountID(), claim_id); auto results = database.QueryDatabase(query); - if (!results.Success()) { + if (!results.Success()) return false; - } if (results.RowCount() == 0) return false; @@ -5398,52 +5398,49 @@ bool Client::TryReward(uint32 claim_id) { auto row = results.begin(); uint32 amt = atoi(row[0]); - if(amt == 0) + if (amt == 0) return false; - std::list::iterator iter = zone->VeteranRewards.begin(); - for (; iter != zone->VeteranRewards.end(); ++row) - if((*iter).claim_id == claim_id) - break; + auto iter = std::find_if(zone->VeteranRewards.begin(), zone->VeteranRewards.end(), + [claim_id](const InternalVeteranReward &a) { return a.claim_id == claim_id; }); - if(iter == zone->VeteranRewards.end()) + if (iter == zone->VeteranRewards.end()) return false; - if(amt == 1) { + if (amt == 1) { query = StringFormat("DELETE FROM account_rewards " - "WHERE account_id = %i AND reward_id = %i", - AccountID(), claim_id); + "WHERE account_id = %i AND reward_id = %i", + AccountID(), claim_id); auto results = database.QueryDatabase(query); - } - else { + } else { query = StringFormat("UPDATE account_rewards SET amount = (amount-1) " - "WHERE account_id = %i AND reward_id = %i", - AccountID(), claim_id); + "WHERE account_id = %i AND reward_id = %i", + AccountID(), claim_id); auto results = database.QueryDatabase(query); } - InternalVeteranReward ivr = (*iter); + auto &ivr = (*iter); ItemInst *claim = database.CreateItem(ivr.items[0].item_id, ivr.items[0].charges); - if(!claim) { + if (!claim) { Save(); return true; } bool lore_conflict = CheckLoreConflict(claim->GetItem()); - for(int y = 1; y < 8; y++) - if(ivr.items[y].item_id && claim->GetItem()->ItemClass == 1) { + for (int y = 1; y < 8; y++) + if (ivr.items[y].item_id && claim->GetItem()->ItemClass == 1) { ItemInst *item_temp = database.CreateItem(ivr.items[y].item_id, ivr.items[y].charges); - if(item_temp) { - if(CheckLoreConflict(item_temp->GetItem())) { + if (item_temp) { + if (CheckLoreConflict(item_temp->GetItem())) { lore_conflict = true; DuplicateLoreMessage(ivr.items[y].item_id); } - claim->PutItem(y-1, *item_temp); + claim->PutItem(y - 1, *item_temp); } } - if(lore_conflict) { + if (lore_conflict) { safe_delete(claim); return true; } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 5205942b2..f93f83018 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -13793,41 +13793,32 @@ void Client::Handle_OP_TributeUpdate(const EQApplicationPacket *app) void Client::Handle_OP_VetClaimRequest(const EQApplicationPacket *app) { - if (app->size < sizeof(VeteranClaimRequest)) - { - Log.Out(Logs::General, Logs::None, "OP_VetClaimRequest size lower than expected: got %u expected at least %u", app->size, sizeof(VeteranClaimRequest)); + if (app->size < sizeof(VeteranClaim)) { + Log.Out(Logs::General, Logs::None, + "OP_VetClaimRequest size lower than expected: got %u expected at least %u", app->size, + sizeof(VeteranClaim)); DumpPacket(app); return; } - VeteranClaimRequest *vcr = (VeteranClaimRequest*)app->pBuffer; + VeteranClaim *vcr = (VeteranClaim *)app->pBuffer; - if (vcr->claim_id == 0xFFFFFFFF) //request update packet - { + if (vcr->claim_id == 0xFFFFFFFF) { // request update packet SendRewards(); + return; } - else //try to claim something! - { - if (!TryReward(vcr->claim_id)) - { - Message(13, "Your claim has been rejected."); - EQApplicationPacket *vetapp = new EQApplicationPacket(OP_VetClaimReply, sizeof(VeteranClaimReply)); - VeteranClaimReply * cr = (VeteranClaimReply*)vetapp->pBuffer; - strcpy(cr->name, GetName()); - cr->claim_id = vcr->claim_id; - cr->reject_field = -1; - FastQueuePacket(&vetapp); - } - else - { - EQApplicationPacket *vetapp = new EQApplicationPacket(OP_VetClaimReply, sizeof(VeteranClaimReply)); - VeteranClaimReply * cr = (VeteranClaimReply*)vetapp->pBuffer; - strcpy(cr->name, GetName()); - cr->claim_id = vcr->claim_id; - cr->reject_field = 0; - FastQueuePacket(&vetapp); - } - } + // try to claim something! + EQApplicationPacket *vetapp = new EQApplicationPacket(OP_VetClaimReply, sizeof(VeteranClaim)); + VeteranClaim *cr = (VeteranClaim *)vetapp->pBuffer; + strcpy(cr->name, GetName()); + cr->claim_id = vcr->claim_id; + + if (!TryReward(vcr->claim_id)) + cr->action = 1; + else + cr->action = 0; + + FastQueuePacket(&vetapp); } void Client::Handle_OP_VoiceMacroIn(const EQApplicationPacket *app) From 9a19d59cf7f7aaf86d1385910662b95ae7bedc60 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 20 Feb 2015 18:47:46 -0500 Subject: [PATCH 104/114] Fix memory leak in Client::TryRewards --- zone/client.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/zone/client.cpp b/zone/client.cpp index e72672369..838b169c8 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -5437,6 +5437,7 @@ bool Client::TryReward(uint32 claim_id) DuplicateLoreMessage(ivr.items[y].item_id); } claim->PutItem(y - 1, *item_temp); + safe_delete(item_temp); } } From 0a351bf6e10a6447e388b46317e383a2ccee7f81 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 20 Feb 2015 20:51:21 -0500 Subject: [PATCH 105/114] VS didn't like this (it was illegal though, stupid gcc/clang) --- common/patches/rof2_structs.h | 2 +- common/patches/rof_structs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 0f2e4548b..3676e990f 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -4728,7 +4728,7 @@ struct AugmentInfo_Struct struct VeteranRewardItem { /*000*/ uint32 name_length; -/*004*/ char item_name[0]; // THIS IS NOT NULL TERMED +/*004*/ //char item_name[0]; // THIS IS NOT NULL TERMED /*???*/ uint32 item_id; /*???*/ uint32 charges; }; diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 05943d81a..1e75df0eb 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -4719,7 +4719,7 @@ struct AugmentInfo_Struct struct VeteranRewardItem { /*000*/ uint32 name_length; -/*004*/ char item_name[0]; // THIS IS NOT NULL TERMED +/*004*/ //char item_name[0]; // THIS IS NOT NULL TERMED /*???*/ uint32 item_id; /*???*/ uint32 charges; }; From 7afb29cf02452ede9ace512d72edc2be3e7dd972 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 20 Feb 2015 21:10:53 -0500 Subject: [PATCH 106/114] Fix another memleak in Client::TryReward --- zone/client.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/zone/client.cpp b/zone/client.cpp index 838b169c8..4b813c1b2 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -5448,6 +5448,7 @@ bool Client::TryReward(uint32 claim_id) PutItemInInventory(free_slot, *claim); SendItemPacket(free_slot, claim, ItemPacketTrade); + safe_delete(claim); Save(); return true; From e61f647bf2520e1d839e0519edc7c6fc8081f874 Mon Sep 17 00:00:00 2001 From: Uleat Date: Sat, 21 Feb 2015 01:20:13 -0500 Subject: [PATCH 107/114] Fix for non-compliant assignment of non-integral type array --- world/worlddb.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 8099b9ee2..8bcd03590 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -115,7 +115,16 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou cse->Instance = 0; cse->Gender = (uint8)atoi(row[2]); cse->Face = (uint8)atoi(row[15]); - cse->Equip[0] = { 0 }; // Processed below + + for (uint32 matslot = 0; matslot < _MaterialCount; matslot++) { // Processed below + cse->Equip[matslot].Material = 0; + cse->Equip[matslot].Unknown1 = 0; + cse->Equip[matslot].EliteMaterial = 0; + cse->Equip[matslot].HeroForgeModel = 0; + cse->Equip[matslot].Material2 = 0; + cse->Equip[matslot].Color.Color = 0; + } + cse->Unknown15 = 0xFF; cse->Unknown19 = 0xFF; cse->DrakkinTattoo = (uint32)atoi(row[17]); From 4f3360aa49ae9b191dd49b00a698bbf3e4e2e9c8 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 21 Feb 2015 01:50:40 -0500 Subject: [PATCH 108/114] More VS compile fixes (curse you clang/gcc!) --- common/patches/rof2_structs.h | 4 ++-- common/patches/rof_structs.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/patches/rof2_structs.h b/common/patches/rof2_structs.h index 3676e990f..d5ab87fb6 100644 --- a/common/patches/rof2_structs.h +++ b/common/patches/rof2_structs.h @@ -4739,13 +4739,13 @@ struct VeteranRewardEntry /*004*/ uint32 avaliable_count; /*008*/ uint32 claim_count; /*012*/ char enabled; -/*013*/ VeteranRewardItem items[0]; +/*013*/ //VeteranRewardItem items[0]; }; struct VeteranReward { /*000*/ uint32 claim_count; -/*004*/ VeteranRewardEntry entries[0]; +/*004*/ //VeteranRewardEntry entries[0]; }; struct VeteranClaim diff --git a/common/patches/rof_structs.h b/common/patches/rof_structs.h index 1e75df0eb..f773d422c 100644 --- a/common/patches/rof_structs.h +++ b/common/patches/rof_structs.h @@ -4730,13 +4730,13 @@ struct VeteranRewardEntry /*004*/ uint32 avaliable_count; /*008*/ uint32 claim_count; /*012*/ char enabled; -/*013*/ VeteranRewardItem items[0]; +/*013*/ //VeteranRewardItem items[0]; }; struct VeteranReward { /*000*/ uint32 claim_count; -/*004*/ VeteranRewardEntry entries[0]; +/*004*/ //VeteranRewardEntry entries[0]; }; struct VeteranClaim From 32cb219e64f28ea86ab0435c42c9838b3893698a Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sat, 21 Feb 2015 06:32:41 -0500 Subject: [PATCH 109/114] Fix to allow for mana drain spells to work if client is full mana. --- zone/client_process.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/client_process.cpp b/zone/client_process.cpp index 3f9d0ee3a..526b36712 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -1894,7 +1894,7 @@ void Client::DoHPRegen() { } void Client::DoManaRegen() { - if (GetMana() >= max_mana) + if (GetMana() >= max_mana && spellbonuses.ManaRegen >= 0) return; SetMana(GetMana() + CalcManaRegen() + RestRegenMana); From eff818ca424e5a7029ba9174067aa2e7748adaac Mon Sep 17 00:00:00 2001 From: JJ Date: Sat, 21 Feb 2015 20:46:19 -0500 Subject: [PATCH 110/114] Manual merge of #376 for Erudite starting zones. --- changelog.txt | 3 +++ world/worlddb.cpp | 28 ++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/changelog.txt b/changelog.txt index 931ccf079..f12dfd0ae 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/21/2015 == +Noudess: Starting erudites that were supposed to start in paineel were landing in erudin on Titanium. Fixed to be paineel. + == 02/20/2015 == demonstar55: Implement claims for RoF/RoF2 (should no longer crash the client!) - fixed bugs related to claims for the rest of the clients (woo infinite loops) diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 8bcd03590..9a2bb630a 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -276,7 +276,8 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou } } -int WorldDatabase::MoveCharacterToBind(int CharID, uint8 bindnum) { +int WorldDatabase::MoveCharacterToBind(int CharID, uint8 bindnum) +{ /* if an invalid bind point is specified, use the primary bind */ if (bindnum > 4) { @@ -359,6 +360,7 @@ bool WorldDatabase::GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* return true; } + void WorldDatabase::SetSoFDefaultStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc){ if (in_cc->start_zone == RuleI(World, TutorialZoneID)) { in_pp->zone_id = in_cc->start_zone; @@ -377,8 +379,16 @@ void WorldDatabase::SetTitaniumDefaultStartZone(PlayerProfile_Struct* in_pp, Cha { case 0: { - in_pp->zone_id = 24; // erudnext - in_pp->binds[0].zoneId = 38; // tox + if (in_cc->deity == 203) // Cazic-Thule Erudites go to Paineel + { + in_pp->zone_id = 75; // paineel + in_pp->binds[0].zoneId = 75; + } + else + { + in_pp->zone_id = 24; // erudnext + in_pp->binds[0].zoneId = 38; // tox + } break; } case 1: @@ -461,6 +471,7 @@ void WorldDatabase::SetTitaniumDefaultStartZone(PlayerProfile_Struct* in_pp, Cha } } } + void WorldDatabase::GetLauncherList(std::vector &rl) { rl.clear(); @@ -476,8 +487,8 @@ void WorldDatabase::GetLauncherList(std::vector &rl) { } -void WorldDatabase::SetMailKey(int CharID, int IPAddress, int MailKey) { - +void WorldDatabase::SetMailKey(int CharID, int IPAddress, int MailKey) +{ char MailKeyString[17]; if(RuleB(Chat, EnableMailKeyIPVerification) == true) @@ -511,7 +522,8 @@ bool WorldDatabase::GetCharacterLevel(const char *name, int &level) return true; } -bool WorldDatabase::LoadCharacterCreateAllocations() { +bool WorldDatabase::LoadCharacterCreateAllocations() +{ character_create_allocations.clear(); std::string query = "SELECT * FROM char_create_point_allocations ORDER BY id"; @@ -543,7 +555,8 @@ bool WorldDatabase::LoadCharacterCreateAllocations() { return true; } -bool WorldDatabase::LoadCharacterCreateCombos() { +bool WorldDatabase::LoadCharacterCreateCombos() +{ character_create_race_class_combos.clear(); std::string query = "SELECT * FROM char_create_combinations ORDER BY race, class, deity, start_zone"; @@ -565,4 +578,3 @@ bool WorldDatabase::LoadCharacterCreateCombos() { return true; } - From c8c2209617b2332240d8641d0fe43dfcba2b6817 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sat, 21 Feb 2015 23:04:24 -0500 Subject: [PATCH 111/114] Fix for perl defensive/ranged proc function Minor fix to NPC ranged attack. --- zone/perl_npc.cpp | 4 ++-- zone/special_attacks.cpp | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/zone/perl_npc.cpp b/zone/perl_npc.cpp index bbefef2ed..f06623f4a 100644 --- a/zone/perl_npc.cpp +++ b/zone/perl_npc.cpp @@ -2343,7 +2343,7 @@ XS(XS_NPC_AddRangedProc) { if(THIS == NULL) Perl_croak(aTHX_ "THIS is NULL, avoiding crash."); - THIS->AddDefensiveProc(spell_id,chance); + THIS->AddRangedProc(spell_id,chance); } XSRETURN_EMPTY; } @@ -2368,7 +2368,7 @@ XS(XS_NPC_AddDefensiveProc) { if(THIS == NULL) Perl_croak(aTHX_ "THIS is NULL, avoiding crash."); - THIS->AddProcToWeapon(spell_id, true, chance); + THIS->AddDefensiveProc(spell_id,chance); } XSRETURN_EMPTY; } diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index c0844c2ac..faae0e3b1 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -1186,7 +1186,6 @@ float Mob::GetRangeDistTargetSizeMod(Mob* other) void NPC::RangedAttack(Mob* other) { - if (!other) return; //make sure the attack and ranged timers are up @@ -1306,7 +1305,7 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha if (TotalDmg > 0) CommonOutgoingHitSuccess(other, TotalDmg, skillInUse); - else + else if (TotalDmg < -4) TotalDmg = -5; if (TotalDmg > 0) From 2bed1290370f3c321e687772a2ca60ec792791d5 Mon Sep 17 00:00:00 2001 From: Uleat Date: Sun, 22 Feb 2015 22:27:58 -0500 Subject: [PATCH 112/114] Fix for tutorial button kicking client when re-entering tutorial (return home button for RoF/RoF2 issue still at large) --- world/client.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/world/client.cpp b/world/client.cpp index c0492b7fd..540dfa683 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -741,9 +741,12 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { bool home_enabled = false; for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) { if (strcasecmp(row[1], char_name) == 0) { - if (RuleB(World, EnableTutorialButton) && ((uint8)atoi(row[2]) <= RuleI(World, MaxLevelForTutorial))) { - home_enabled = true; - break; + if (RuleB(World, EnableReturnHomeButton)) { + int now = time(nullptr); + if ((now - atoi(row[3])) >= RuleI(World, MinOfflineTimeToReturnHome)) { + home_enabled = true; + break; + } } } } @@ -764,12 +767,9 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) { bool tutorial_enabled = false; for (auto row = tgh_results.begin(); row != tgh_results.end(); ++row) { if (strcasecmp(row[1], char_name) == 0) { - if (RuleB(World, EnableReturnHomeButton)) { - int now = time(nullptr); - if ((now - atoi(row[3])) >= RuleI(World, MinOfflineTimeToReturnHome)) { - tutorial_enabled = true; - break; - } + if (RuleB(World, EnableTutorialButton) && ((uint8)atoi(row[2]) <= RuleI(World, MaxLevelForTutorial))) { + tutorial_enabled = true; + break; } } } From 167b6f5ebfe0b8c41c6522bfdf9d3f893a90461a Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Mon, 23 Feb 2015 00:39:06 -0500 Subject: [PATCH 113/114] perl NPC function RemoveFromHateList(mob) --- zone/perl_npc.cpp | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/zone/perl_npc.cpp b/zone/perl_npc.cpp index f06623f4a..e2d3fcdd9 100644 --- a/zone/perl_npc.cpp +++ b/zone/perl_npc.cpp @@ -795,6 +795,42 @@ XS(XS_NPC_IsOnHatelist) XSRETURN(1); } +XS(XS_NPC_RemoveFromHateList); /* prototype to pass -Wmissing-prototypes */ +XS(XS_NPC_RemoveFromHateList) +{ + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: NPC::RemoveFromHateList(THIS, ent)"); + { + NPC * THIS; + Mob* ent; + + if (sv_derived_from(ST(0), "NPC")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(NPC *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type NPC"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + if (sv_derived_from(ST(1), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(1))); + ent = INT2PTR(Mob *,tmp); + } + else + Perl_croak(aTHX_ "ent is not of type Mob"); + if(ent == nullptr) + Perl_croak(aTHX_ "ent is nullptr, avoiding crash."); + + THIS->RemoveFromHateList(ent); + + } + XSRETURN_EMPTY; +} + + + XS(XS_NPC_SetNPCFactionID); /* prototype to pass -Wmissing-prototypes */ XS(XS_NPC_SetNPCFactionID) { @@ -2420,6 +2456,7 @@ XS(boot_NPC) newXSproto(strcpy(buf, "GetPrimaryFaction"), XS_NPC_GetPrimaryFaction, file, "$"); newXSproto(strcpy(buf, "GetNPCHate"), XS_NPC_GetNPCHate, file, "$$"); newXSproto(strcpy(buf, "IsOnHatelist"), XS_NPC_IsOnHatelist, file, "$$"); + newXSproto(strcpy(buf, "RemoveFromHateList"), XS_NPC_RemoveFromHateList, file, "$$"); newXSproto(strcpy(buf, "SetNPCFactionID"), XS_NPC_SetNPCFactionID, file, "$$"); newXSproto(strcpy(buf, "GetMaxDMG"), XS_NPC_GetMaxDMG, file, "$"); newXSproto(strcpy(buf, "GetMinDMG"), XS_NPC_GetMinDMG, file, "$"); From 9d866c18897df30567b26901e96e19f161886953 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Mon, 23 Feb 2015 03:52:43 -0500 Subject: [PATCH 114/114] perl $npc->ChangeLastName(name) perl $npc->ClearLastName() Modifies NPC last names. --- zone/npc.cpp | 23 +++++++++++++++++++++ zone/npc.h | 3 +++ zone/perl_npc.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) diff --git a/zone/npc.cpp b/zone/npc.cpp index 5d180e994..c69b6499a 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -2394,6 +2394,29 @@ void NPC::DoQuestPause(Mob *other) { } +void NPC::ChangeLastName(const char* in_lastname) +{ + + EQApplicationPacket* outapp = new EQApplicationPacket(OP_GMLastName, sizeof(GMLastName_Struct)); + GMLastName_Struct* gmn = (GMLastName_Struct*)outapp->pBuffer; + strcpy(gmn->name, GetName()); + strcpy(gmn->gmname, GetName()); + strcpy(gmn->lastname, in_lastname); + gmn->unknown[0]=1; + gmn->unknown[1]=1; + gmn->unknown[2]=1; + gmn->unknown[3]=1; + entity_list.QueueClients(this, outapp, false); + safe_delete(outapp); +} + +void NPC::ClearLastName() +{ + std::string WT; + WT = '\0'; //Clear Last Name + ChangeLastName( WT.c_str()); +} + void NPC::DepopSwarmPets() { if (GetSwarmInfo()) { diff --git a/zone/npc.h b/zone/npc.h index ee3dedf62..8fb80e2a2 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -361,6 +361,9 @@ public: const bool IsUnderwaterOnly() const { return NPCTypedata->underwater; } const char* GetRawNPCTypeName() const { return NPCTypedata->name; } + void ChangeLastName(const char* in_lastname); + void ClearLastName(); + bool GetDepop() { return p_depop; } void NPCSlotTexture(uint8 slot, uint16 texture); // Sets new material values for slots diff --git a/zone/perl_npc.cpp b/zone/perl_npc.cpp index e2d3fcdd9..a2943d035 100644 --- a/zone/perl_npc.cpp +++ b/zone/perl_npc.cpp @@ -2409,6 +2409,55 @@ XS(XS_NPC_AddDefensiveProc) { XSRETURN_EMPTY; } +XS(XS_NPC_ChangeLastName); /* prototype to pass -Wmissing-prototypes */ +XS(XS_NPC_ChangeLastName) +{ + dXSARGS; + if (items < 1 || items > 2) + Perl_croak(aTHX_ "Usage: Mob::ChangeLastName(THIS, name)"); + { + NPC * THIS; + char * name = nullptr; + + if (sv_derived_from(ST(0), "NPC")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(NPC *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type NPC"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + if (items > 1) { name = (char *)SvPV_nolen(ST(1)); } + + THIS->ChangeLastName(name); + } + XSRETURN_EMPTY; +} + +XS(XS_NPC_ClearLastName); /* prototype to pass -Wmissing-prototypes */ +XS(XS_NPC_ClearLastName) +{ + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::ClearLastName(THIS)"); + { + NPC * THIS; + + if (sv_derived_from(ST(0), "NPC")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(NPC *,tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type NPC"); + if(THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + THIS->ClearLastName(); + } + XSRETURN_EMPTY; +} + #ifdef __cplusplus extern "C" #endif @@ -2517,6 +2566,8 @@ XS(boot_NPC) newXSproto(strcpy(buf, "AddMeleeProc"), XS_NPC_AddMeleeProc, file, "$$$"); newXSproto(strcpy(buf, "AddRangedProc"), XS_NPC_AddRangedProc, file, "$$$"); newXSproto(strcpy(buf, "AddDefensiveProc"), XS_NPC_AddDefensiveProc, file, "$$$"); + newXSproto(strcpy(buf, "ChangeLastName"), XS_NPC_ChangeLastName, file, "$:$"); + newXSproto(strcpy(buf, "ClearLastName"), XS_NPC_ClearLastName, file, "$"); XSRETURN_YES; }