From 7fed01ddeae172b0e1e82f47ba682860fc9f3c6d Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 27 Sep 2014 19:57:45 -0700 Subject: [PATCH 01/50] 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 02/50] 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 03/50] 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 5be1bd2ffb4581927636561b6e2e8e844e4596f0 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 31 Jan 2015 17:53:50 -0500 Subject: [PATCH 04/50] Make items with long reuse timers show the timer after zone This adds a new table to store the timers in. This may seem odd but the timers are associated with the player, not the item, they're just included in the item header in the packet Currently trading still needs to be handled --- common/item.cpp | 4 +++ common/item.h | 3 ++ common/patches/rof.cpp | 2 +- common/patches/rof2.cpp | 2 +- common/patches/sod.cpp | 2 +- common/patches/sof.cpp | 2 +- common/patches/titanium.cpp | 2 +- common/patches/uf.cpp | 2 +- common/ptimer.h | 1 + common/shareddb.cpp | 30 +++++++++++++++++++ common/shareddb.h | 3 ++ common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + .../2015_01_31_character_item_recast.sql | 7 +++++ zone/client_packet.cpp | 1 + zone/corpse.cpp | 7 ++++- zone/spells.cpp | 10 +++++-- zone/zonedb.cpp | 8 +++++ zone/zonedb.h | 1 + 19 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 utils/sql/git/required/2015_01_31_character_item_recast.sql diff --git a/common/item.cpp b/common/item.cpp index 35de0e773..a43b5d12b 100644 --- a/common/item.cpp +++ b/common/item.cpp @@ -1441,6 +1441,7 @@ ItemInst::ItemInst(const Item_Struct* item, int16 charges) { m_ornamenticon = 0; m_ornamentidfile = 0; m_ornament_hero_model = 0; + m_recast_timestamp = 0; } ItemInst::ItemInst(SharedDatabase *db, uint32 item_id, int16 charges) { @@ -1466,6 +1467,7 @@ ItemInst::ItemInst(SharedDatabase *db, uint32 item_id, int16 charges) { m_ornamenticon = 0; m_ornamentidfile = 0; m_ornament_hero_model = 0; + m_recast_timestamp = 0; } ItemInst::ItemInst(ItemInstTypes use_type) { @@ -1486,6 +1488,7 @@ ItemInst::ItemInst(ItemInstTypes use_type) { m_ornamenticon = 0; m_ornamentidfile = 0; m_ornament_hero_model = 0; + m_recast_timestamp = 0; } // Make a copy of an ItemInst object @@ -1539,6 +1542,7 @@ ItemInst::ItemInst(const ItemInst& copy) m_ornamenticon = copy.m_ornamenticon; m_ornamentidfile = copy.m_ornamentidfile; m_ornament_hero_model = copy.m_ornament_hero_model; + m_recast_timestamp = copy.m_recast_timestamp; } // Clean up container contents diff --git a/common/item.h b/common/item.h index 0868e8c5f..fd30b5ea0 100644 --- a/common/item.h +++ b/common/item.h @@ -403,6 +403,8 @@ public: void SetOrnamentationIDFile(uint32 ornament_idfile) { m_ornamentidfile = ornament_idfile; } uint32 GetOrnamentHeroModel(int32 material_slot = -1) const; void SetOrnamentHeroModel(uint32 ornament_hero_model) { m_ornament_hero_model = ornament_hero_model; } + uint32 GetRecastTimestamp() const { return m_recast_timestamp; } + void SetRecastTimestamp(uint32 in) { m_recast_timestamp = in; } void Initialize(SharedDatabase *db = nullptr); void ScaleItem(); @@ -450,6 +452,7 @@ protected: uint32 m_ornamenticon; uint32 m_ornamentidfile; uint32 m_ornament_hero_model; + uint32 m_recast_timestamp; // // Items inside of this item (augs or contents); diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 9494c5048..772e60517 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -5000,7 +5000,7 @@ namespace RoF hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; hdr.unknown028 = 0; - hdr.last_cast_time = ((item->RecastDelay > 1) ? 1212693140 : 0); + hdr.last_cast_time = inst->GetRecastTimestamp(); hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; hdr.unknown044 = 0; diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index d4c619942..6947ded15 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -5069,7 +5069,7 @@ namespace RoF2 hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; hdr.unknown028 = 0; - hdr.last_cast_time = ((item->RecastDelay > 1) ? 1212693140 : 0); + hdr.last_cast_time = inst->GetRecastTimestamp(); hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; hdr.unknown044 = 0; diff --git a/common/patches/sod.cpp b/common/patches/sod.cpp index 2e96719be..98f7faccd 100644 --- a/common/patches/sod.cpp +++ b/common/patches/sod.cpp @@ -3548,7 +3548,7 @@ namespace SoD hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; hdr.unknown028 = 0; - hdr.last_cast_time = ((item->RecastDelay > 1) ? 1212693140 : 0); + hdr.last_cast_time = inst->GetRecastTimestamp(); hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; hdr.unknown044 = 0; diff --git a/common/patches/sof.cpp b/common/patches/sof.cpp index 44a87d3cc..b8a84d993 100644 --- a/common/patches/sof.cpp +++ b/common/patches/sof.cpp @@ -2872,7 +2872,7 @@ namespace SoF hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; hdr.unknown028 = 0; - hdr.last_cast_time = ((item->RecastDelay > 1) ? 1212693140 : 0); + hdr.last_cast_time = inst->GetRecastTimestamp(); hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; hdr.unknown044 = 0; diff --git a/common/patches/titanium.cpp b/common/patches/titanium.cpp index aa5d3d7fb..3be2d7d70 100644 --- a/common/patches/titanium.cpp +++ b/common/patches/titanium.cpp @@ -2004,7 +2004,7 @@ namespace Titanium inst->IsScaling() ? inst->GetExp() / 100 : 0, //merchant_slot, //instance ID, bullshit for now (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot, - 0, // item recast timer timestamp field (aka..last_cast_time field in SoF+ clients) + inst->GetRecastTimestamp(), (stackable ? ((inst->GetItem()->ItemType == ItemTypePotion) ? 1 : 0) : charges), inst->IsAttuned() ? 1 : 0, 0 diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 3f297534d..f772509d0 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -3793,7 +3793,7 @@ namespace UF hdr.scaled_value = inst->IsScaling() ? inst->GetExp() / 100 : 0; hdr.instance_id = (merchant_slot == 0) ? inst->GetSerialNumber() : merchant_slot; hdr.unknown028 = 0; - hdr.last_cast_time = ((item->RecastDelay > 1) ? 1212693140 : 0); + hdr.last_cast_time = inst->GetRecastTimestamp(); hdr.charges = (stackable ? (item->MaxCharges ? 1 : 0) : charges); hdr.inst_nodrop = inst->IsAttuned() ? 1 : 0; hdr.unknown044 = 0; diff --git a/common/ptimer.h b/common/ptimer.h index 829a015b2..d12b6779d 100644 --- a/common/ptimer.h +++ b/common/ptimer.h @@ -79,6 +79,7 @@ public: inline const uint32 GetTimerTime() const { return timer_time; } inline const uint32 GetStartTime() const { return start_time; } inline const pTimerType GetType() const { return _type; } + inline const uint32 GetReadyTimestamp() const { return start_time + timer_time; } inline bool Enabled() { return enabled; } diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 159ce13fc..08bb0103f 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -498,6 +498,8 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory *inv) return false; } + auto timestamps = GetItemRecastTimestamps(char_id); + for (auto row = results.begin(); row != results.end(); ++row) { int16 slot_id = atoi(row[0]); uint32 item_id = atoi(row[1]); @@ -582,6 +584,13 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory *inv) else inst->SetCharges(charges); + if (item->RecastDelay) { + if (timestamps.count(item->RecastType)) + inst->SetRecastTimestamp(timestamps.at(item->RecastType)); + else + inst->SetRecastTimestamp(0); + } + if (item->ItemClass == ItemClassCommon) { for (int i = AUG_BEGIN; i < EmuConstants::ITEM_COMMON_SIZE; i++) { if (aug[i]) @@ -725,6 +734,27 @@ bool SharedDatabase::GetInventory(uint32 account_id, char *name, Inventory *inv) return GetSharedBank(account_id, inv, false); } +std::map SharedDatabase::GetItemRecastTimestamps(uint32 char_id) +{ + std::map timers; + std::string query = StringFormat("SELECT recast_type,timestamp FROM character_item_recast WHERE id=%u", char_id); + auto results = QueryDatabase(query); + if (!results.Success() || results.RowCount() == 0) + return timers; + + for (auto row = results.begin(); row != results.end(); ++row) + timers[atoul(row[0])] = atoul(row[1]); + return timers; // RVO or move assigned +} + +void SharedDatabase::ClearOldRecastTimestamps(uint32 char_id) +{ + // This actually isn't strictly live-like. Live your recast timestamps are forever + std::string query = + StringFormat("DELETE FROM character_item_recast WHERE id = %u and timestamp < UNIX_TIMESTAMP()", char_id); + QueryDatabase(query); +} + void SharedDatabase::GetItemsCount(int32 &item_count, uint32 &max_id) { item_count = -1; diff --git a/common/shareddb.h b/common/shareddb.h index 073c385e8..99eba666a 100644 --- a/common/shareddb.h +++ b/common/shareddb.h @@ -11,6 +11,7 @@ #include "fixed_memory_variable_hash_set.h" #include +#include class EvolveInfo; class Inventory; @@ -69,6 +70,8 @@ class SharedDatabase : public Database bool SetSharedPlatinum(uint32 account_id, int32 amount_to_add); bool GetInventory(uint32 char_id, Inventory* inv); bool GetInventory(uint32 account_id, char* name, Inventory* inv); + std::map GetItemRecastTimestamps(uint32 char_id); + void ClearOldRecastTimestamps(uint32 char_id); bool SetStartingItems(PlayerProfile_Struct* pp, Inventory* inv, uint32 si_race, uint32 si_class, uint32 si_deity, uint32 si_current_zone, char* si_name, int admin); diff --git a/common/version.h b/common/version.h index 7044ba6e5..5841a4119 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 9072 +#define CURRENT_BINARY_DATABASE_VERSION 9073 #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 820a79bd4..be99178a3 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -326,6 +326,7 @@ 9070|2015_01_28_quest_debug_log_category.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Quest Debug'|empty| 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| # 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_01_31_character_item_recast.sql b/utils/sql/git/required/2015_01_31_character_item_recast.sql new file mode 100644 index 000000000..fbc222608 --- /dev/null +++ b/utils/sql/git/required/2015_01_31_character_item_recast.sql @@ -0,0 +1,7 @@ +CREATE TABLE `character_item_recast` ( + `id` int(11) UNSIGNED NOT NULL DEFAULT 0, + `recast_type` smallint(11) UNSIGNED NOT NULL DEFAULT 0, + `timestamp` int(11) UNSIGNED NOT NULL DEFAULT 0, + PRIMARY KEY(`id`, `recast_type`), + KEY `id` (`id`) +) ENGINE = InnoDB DEFAULT CHARSET = latin1; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index c4e449db5..a3062891b 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1392,6 +1392,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) if (RuleB(Character, SharedBankPlat)) m_pp.platinum_shared = database.GetSharedPlatinum(this->AccountID()); + database.ClearOldRecastTimestamps(cid); /* Clear out our old recast timestamps to keep the DB clean */ loaditems = database.GetInventory(cid, &m_inv); /* Load Character Inventory */ database.LoadCharacterBandolier(cid, &m_pp); /* Load Character Bandolier */ database.LoadCharacterBindPoint(cid, &m_pp); /* Load Character Bind */ diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 36e585ea2..0dd4ed1f3 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -965,6 +965,7 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a Save(); } + auto timestamps = database.GetItemRecastTimestamps(client->CharacterID()); outapp->priority = 6; client->QueuePacket(outapp); safe_delete(outapp); @@ -973,6 +974,8 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a const Item_Struct* item = database.GetItem(pkitem); ItemInst* inst = database.CreateItem(item, item->MaxCharges); if(inst) { + if (item->RecastDelay) + inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0); client->SendItemPacket(EmuConstants::CORPSE_BEGIN, inst, ItemPacketLoot); safe_delete(inst); } @@ -1004,6 +1007,8 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a if(client && item) { ItemInst* inst = database.CreateItem(item, item_data->charges, item_data->aug_1, item_data->aug_2, item_data->aug_3, item_data->aug_4, item_data->aug_5, item_data->aug_6, item_data->attuned); if(inst) { + if (item->RecastDelay) + inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0); // MainGeneral1 is the corpse inventory start offset for Ti(EMu) - CORPSE_END = MainGeneral1 + MainCursor client->SendItemPacket(i + EmuConstants::CORPSE_BEGIN, inst, ItemPacketLoot); safe_delete(inst); @@ -1460,4 +1465,4 @@ void Corpse::LoadPlayerCorpseDecayTime(uint32 corpse_db_id){ else { corpse_graveyard_timer.SetTimer(3000); } -} \ No newline at end of file +} diff --git a/zone/spells.cpp b/zone/spells.cpp index bf4da6688..1b1cb16f4 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -1242,6 +1242,8 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, { //Can we start the timer here? I don't see why not. CastToClient()->GetPTimers().Start((pTimerItemStart + recasttype), recastdelay); + database.UpdateItemRecastTimestamps(CastToClient()->CharacterID(), recasttype, + CastToClient()->GetPTimers().Get(pTimerItemStart + recasttype)->GetReadyTimestamp()); } } @@ -2270,11 +2272,15 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 { ItemInst *itm = CastToClient()->GetInv().GetItem(inventory_slot); if(itm && itm->GetItem()->RecastDelay > 0){ - CastToClient()->GetPTimers().Start((pTimerItemStart + itm->GetItem()->RecastType), itm->GetItem()->RecastDelay); + auto recast_type = itm->GetItem()->RecastType; + CastToClient()->GetPTimers().Start((pTimerItemStart + recast_type), itm->GetItem()->RecastDelay); + database.UpdateItemRecastTimestamps( + CastToClient()->CharacterID(), recast_type, + CastToClient()->GetPTimers().Get(pTimerItemStart + recast_type)->GetReadyTimestamp()); EQApplicationPacket *outapp = new EQApplicationPacket(OP_ItemRecastDelay, sizeof(ItemRecastDelay_Struct)); ItemRecastDelay_Struct *ird = (ItemRecastDelay_Struct *)outapp->pBuffer; ird->recast_delay = itm->GetItem()->RecastDelay; - ird->recast_type = itm->GetItem()->RecastType; + ird->recast_type = recast_type; CastToClient()->QueuePacket(outapp); safe_delete(outapp); } diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index bb81a0fc4..56236f1b8 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -2999,6 +2999,14 @@ void ZoneDatabase::RemoveTempFactions(Client *client) { QueryDatabase(query); } +void ZoneDatabase::UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type, uint32 timestamp) +{ + std::string query = + StringFormat("REPLACE INTO character_item_recast (id, recast_type, timestamp) VALUES (%u, %u, %u)", char_id, + recast_type, timestamp); + QueryDatabase(query); +} + void ZoneDatabase::LoadPetInfo(Client *client) { // Load current pet and suspended pet diff --git a/zone/zonedb.h b/zone/zonedb.h index 5c3ed3d0e..5e1a55248 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -256,6 +256,7 @@ public: void LoadPetInfo(Client *c); void SavePetInfo(Client *c); void RemoveTempFactions(Client *c); + void UpdateItemRecastTimestamps(uint32 char_id, uint32 recast_type, uint32 timestamp); /* Character Data Loaders */ bool LoadCharacterFactionValues(uint32 character_id, faction_map & val_list); From b590eb2dc4cd95d1128908392a6e151189f26382 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 31 Jan 2015 20:54:56 -0500 Subject: [PATCH 05/50] Send item recast timestamps picking up ground spawns --- common/shareddb.cpp | 12 ++++++++++++ common/shareddb.h | 1 + zone/object.cpp | 11 ++++++++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 08bb0103f..13ae065be 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -747,6 +747,18 @@ std::map SharedDatabase::GetItemRecastTimestamps(uint32 char_id) return timers; // RVO or move assigned } +uint32 SharedDatabase::GetItemRecastTimestamp(uint32 char_id, uint32 recast_type) +{ + std::string query = StringFormat("SELECT timestamp FROM character_item_recast WHERE id=%u AND recast_type=%u", + char_id, recast_type); + auto results = QueryDatabase(query); + if (!results.Success() || results.RowCount() == 0) + return 0; + + auto row = results.begin(); + return static_cast(atoul(row[0])); +} + void SharedDatabase::ClearOldRecastTimestamps(uint32 char_id) { // This actually isn't strictly live-like. Live your recast timestamps are forever diff --git a/common/shareddb.h b/common/shareddb.h index 99eba666a..aef325380 100644 --- a/common/shareddb.h +++ b/common/shareddb.h @@ -71,6 +71,7 @@ class SharedDatabase : public Database bool GetInventory(uint32 char_id, Inventory* inv); bool GetInventory(uint32 account_id, char* name, Inventory* inv); std::map GetItemRecastTimestamps(uint32 char_id); + uint32 GetItemRecastTimestamp(uint32 char_id, uint32 recast_type); void ClearOldRecastTimestamps(uint32 char_id); bool SetStartingItems(PlayerProfile_Struct* pp, Inventory* inv, uint32 si_race, uint32 si_class, uint32 si_deity, uint32 si_current_zone, char* si_name, int admin); diff --git a/zone/object.cpp b/zone/object.cpp index 38f4c67c4..7dd97d355 100644 --- a/zone/object.cpp +++ b/zone/object.cpp @@ -467,16 +467,21 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object) if (m_inst && sender) { // if there is a lore conflict, delete the offending item from the server inventory // the client updates itself and takes care of sending "duplicate lore item" messages - if(sender->CheckLoreConflict(m_inst->GetItem())) { - int16 loreslot = sender->GetInv().HasItem(m_inst->GetItem()->ID, 0, invWhereBank); + auto item = m_inst->GetItem(); + if(sender->CheckLoreConflict(item)) { + int16 loreslot = sender->GetInv().HasItem(item->ID, 0, invWhereBank); if (loreslot != INVALID_INDEX) // if the duplicate is in the bank, delete it. sender->DeleteItemInInventory(loreslot); else cursordelete = true; // otherwise, we delete the new one } + if (item->RecastDelay) + m_inst->SetRecastTimestamp( + database.GetItemRecastTimestamp(sender->CharacterID(), item->RecastType)); + char buf[10]; - snprintf(buf, 9, "%u", m_inst->GetItem()->ID); + snprintf(buf, 9, "%u", item->ID); buf[9] = '\0'; std::vector args; args.push_back(m_inst); From ed9bdaf60c12fc252ce01f18f1ad36d62dae2eae Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 1 Feb 2015 01:00:05 -0600 Subject: [PATCH 06/50] 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 07/50] 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 08/50] 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 09/50] 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 10/50] 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 11/50] 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 12/50] 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 13/50] 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 14/50] 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 15/50] 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 16/50] 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 17/50] 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 cc4c6b633913a1d4b48121a5054313d1079374aa Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 1 Feb 2015 06:31:53 -0500 Subject: [PATCH 18/50] Fix/Implemented - Pets who cast group spells (Target Type 43) will now have the spell affect entire group instead of just the pet. This used to work at some point, no clue when it broke... --- zone/spells.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/zone/spells.cpp b/zone/spells.cpp index 1b1cb16f4..8fbbfa6d5 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2025,6 +2025,9 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 // // Switch #2 - execute the spell // + + Shout("TEST %i %i", CastAction, spell_id); + switch(CastAction) { default: @@ -2148,6 +2151,15 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 // caster if they're not using TGB // NOTE: this will always hit the caster, plus the target's group so // it can affect up to 7 people if the targeted group is not our own + + // Allow pets who cast group spells to affect the group. + if (spell_target->IsPetOwnerClient()){ + Mob* owner = spell_target->GetOwner(); + + if (owner) + spell_target = owner; + } + if(spell_target->IsGrouped()) { Group *target_group = entity_list.GetGroupByMob(spell_target); From 73ac566c17358d79e163830eca1b4dad6808900e Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 1 Feb 2015 06:32:56 -0500 Subject: [PATCH 19/50] remove debug... --- zone/spells.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/zone/spells.cpp b/zone/spells.cpp index 8fbbfa6d5..849dacfbe 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2026,8 +2026,6 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 // Switch #2 - execute the spell // - Shout("TEST %i %i", CastAction, spell_id); - switch(CastAction) { default: From 115d0d14ac462ef1725d4f9e66f169646ec2a3e5 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Sun, 1 Feb 2015 09:31:07 -0500 Subject: [PATCH 20/50] Fix issues with faction where chars were not allowed to earn faction to offset starting faction values. --- zone/client.cpp | 85 +++++++++++++++++++++++++++++++++++++------------ zone/client.h | 4 +-- 2 files changed, 66 insertions(+), 23 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index 8246f9707..20263ff07 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -7522,19 +7522,38 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui { int32 faction_before_hit; int32 faction_to_use_for_messaging; + FactionMods fm; + int32 this_faction_max; + int32 this_faction_min; if (faction_id[i] <= 0) continue; + // Find out starting faction for this faction + // It needs to be used to adj max and min personal + // The range is still the same, 1200-3000(4200), but adjusted for base + database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(), + faction_id[i]); + + // Adjust the amount you can go up or down so the resulting range + // is PERSONAL_MAX - PERSONAL_MIN + // + // Adjust these values for cases where starting faction is below + // min or above max by not allowing any earn in those directions. + this_faction_min = MIN_PERSONAL_FACTION - fm.base; + this_faction_min = std::min(0, this_faction_min); + this_faction_max = MAX_PERSONAL_FACTION - fm.base; + this_faction_max = std::max(0, this_faction_max); + // Get the characters current value with that faction current_value = GetCharacterFactionLevel(faction_id[i]); faction_before_hit = current_value; - change = UpdatePersonalFaction(char_id, npc_value[i], faction_id[i], ¤t_value, temp[i]); + change = UpdatePersonalFaction(char_id, npc_value[i], faction_id[i], ¤t_value, temp[i], this_faction_min, this_faction_max); if (change) { - SendFactionMessage(npc_value[i], faction_id[i], faction_before_hit, current_value, temp[i]); + SendFactionMessage(npc_value[i], faction_id[i], faction_before_hit, current_value, temp[i], this_faction_min, this_faction_max); } } return; @@ -7548,16 +7567,37 @@ void Client::SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class //Get the npc faction list if(faction_id > 0 && value != 0) { int32 faction_before_hit; + FactionMods fm; + int32 this_faction_max; + int32 this_faction_min; + + // Find out starting faction for this faction + // It needs to be used to adj max and min personal + // The range is still the same, 1200-3000(4200), but adjusted for base + database.GetFactionData(&fm, GetClass(), GetRace(), GetDeity(), + faction_id); + + // Adjust the amount you can go up or down so the resulting range + // is PERSONAL_MAX - PERSONAL_MIN + // + // Adjust these values for cases where starting faction is below + // min or above max by not allowing any earn/loss in those directions. + // At least one faction starts out way below min, so we don't want + // to allow loses in those cases, just massive gains. + this_faction_min = MIN_PERSONAL_FACTION - fm.base; + this_faction_min = std::min(0, this_faction_min); + this_faction_max = MAX_PERSONAL_FACTION - fm.base; + this_faction_max = std::max(0, this_faction_max); //Get the faction modifiers current_value = GetCharacterFactionLevel(faction_id); faction_before_hit = current_value; - change = UpdatePersonalFaction(char_id, value, faction_id, ¤t_value, temp); + change = UpdatePersonalFaction(char_id, value, faction_id, ¤t_value, temp, this_faction_min, this_faction_max); if (change) { - SendFactionMessage(value, faction_id, faction_before_hit, current_value, temp); + SendFactionMessage(value, faction_id, faction_before_hit, current_value, temp, this_faction_min, this_faction_max); } } @@ -7580,7 +7620,7 @@ int32 Client::GetCharacterFactionLevel(int32 faction_id) // Checks for bottom out and max faction and old faction db entries // Updates the faction if we are not minned, maxed or we need to repair -bool Client::UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp) +bool Client::UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp, int32 this_faction_min, int32 this_faction_max) { bool repair = false; bool change = false; @@ -7598,26 +7638,29 @@ bool Client::UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction npc_value *= 2; } } + // Set flag when to update db - if (*current_value > MAX_PERSONAL_FACTION) + // Repair needed, as db changes could modify a base value for a faction + // and we need to auto correct when that happens. + if (*current_value > this_faction_max) { - *current_value = MAX_PERSONAL_FACTION; + *current_value = this_faction_max; repair = true; } - else if (*current_value < MIN_PERSONAL_FACTION) + else if (*current_value < this_faction_min) { - *current_value = MIN_PERSONAL_FACTION; + *current_value = this_faction_min; repair = true; } - else if ((m_pp.gm != 1) && (npc_value != 0) && ((*current_value != MAX_PERSONAL_FACTION) || (*current_value != MIN_PERSONAL_FACTION))) + else if ((m_pp.gm != 1) && (npc_value != 0) && ((*current_value != this_faction_max) || (*current_value != this_faction_min))) change = true; *current_value += npc_value; - if (*current_value > MAX_PERSONAL_FACTION) - *current_value = MAX_PERSONAL_FACTION; - else if (*current_value < MIN_PERSONAL_FACTION) - *current_value = MIN_PERSONAL_FACTION; + if (*current_value > this_faction_max) + *current_value = this_faction_max; + else if (*current_value < this_faction_min) + *current_value = this_faction_min; if (change || repair) { @@ -7705,7 +7748,7 @@ void Client::MerchantRejectMessage(Mob *merchant, int primaryfaction) //o-------------------------------------------------------------- //| Purpose: Send faction change message to client //o-------------------------------------------------------------- -void Client::SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp) +void Client::SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp, int32 this_faction_min, int32 this_faction_max) { char name[50]; int32 faction_value; @@ -7718,8 +7761,8 @@ void Client::SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_ // hit. For example, if we go from 1199 to 1200 which is the MAX // we still want to say faction got better this time around. - if ( (faction_before_hit == MAX_PERSONAL_FACTION) || - (faction_before_hit == MIN_PERSONAL_FACTION)) + if ( (faction_before_hit == this_faction_max) || + (faction_before_hit == this_faction_min)) faction_value = totalvalue; else faction_value = faction_before_hit; @@ -7730,13 +7773,13 @@ void Client::SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_ if (tmpvalue == 0 || temp == 1 || temp == 2) return; - else if (faction_value >= MAX_PERSONAL_FACTION) + else if (faction_value >= this_faction_max) Message_StringID(15, FACTION_BEST, name); - else if (faction_value <= MIN_PERSONAL_FACTION) + else if (faction_value <= this_faction_min) Message_StringID(15, FACTION_WORST, name); - else if (tmpvalue > 0 && faction_value < MAX_PERSONAL_FACTION && !RuleB(Client, UseLiveFactionMessage)) + else if (tmpvalue > 0 && faction_value < this_faction_max && !RuleB(Client, UseLiveFactionMessage)) Message_StringID(15, FACTION_BETTER, name); - else if (tmpvalue < 0 && faction_value > MIN_PERSONAL_FACTION && !RuleB(Client, UseLiveFactionMessage)) + else if (tmpvalue < 0 && faction_value > this_faction_min && !RuleB(Client, UseLiveFactionMessage)) Message_StringID(15, FACTION_WORSE, name); else if (RuleB(Client, UseLiveFactionMessage)) Message(15, "Your faction standing with %s has been adjusted by %i.", name, tmpvalue); //New Live faction message (14261) diff --git a/zone/client.h b/zone/client.h index f7fe0a2f6..84823085c 100644 --- a/zone/client.h +++ b/zone/client.h @@ -606,9 +606,9 @@ public: int32 GetCharacterFactionLevel(int32 faction_id); int32 GetModCharacterFactionLevel(int32 faction_id); void MerchantRejectMessage(Mob *merchant, int primaryfaction); - void SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp); + void SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp, int32 this_faction_min, int32 this_faction_max); - bool UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp); + bool UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp, int32 this_faction_min, int32 this_faction_max); void SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity); void SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class, uint8 char_race, uint8 char_deity, int32 value, uint8 temp); int32 GetRawItemAC(); From 614014a23814e95f644af724e934c9c43e97faa0 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Sun, 1 Feb 2015 15:02:14 -0500 Subject: [PATCH 21/50] Faction update --- zone/client.cpp | 52 ++++++++++++++++++++++++------------------------- zone/client.h | 2 +- zone/zonedb.cpp | 30 +++++++++++----------------- 3 files changed, 38 insertions(+), 46 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index 5ceafec49..9d159ce77 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -7516,7 +7516,6 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui int32 npc_value[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint8 temp[MAX_NPC_FACTIONS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int32 current_value; - bool change = false; // Get the npc faction list if (!database.GetNPCFactionList(npc_id, faction_id, npc_value, temp)) @@ -7552,20 +7551,19 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui current_value = GetCharacterFactionLevel(faction_id[i]); faction_before_hit = current_value; - change = UpdatePersonalFaction(char_id, npc_value[i], faction_id[i], ¤t_value, temp[i], this_faction_min, this_faction_max); + UpdatePersonalFaction(char_id, npc_value[i], faction_id[i], ¤t_value, temp[i], this_faction_min, this_faction_max); - if (change) - { - SendFactionMessage(npc_value[i], faction_id[i], faction_before_hit, current_value, temp[i], this_faction_min, this_faction_max); - } + //Message(14, "Min(%d) Max(%d) Before(%d), After(%d)\n", this_faction_min, this_faction_max, faction_before_hit, current_value); + + SendFactionMessage(npc_value[i], faction_id[i], faction_before_hit, current_value, temp[i], this_faction_min, this_faction_max); } + return; } void Client::SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class, uint8 char_race, uint8 char_deity, int32 value, uint8 temp) { int32 current_value; - bool change=false; //Get the npc faction list if(faction_id > 0 && value != 0) { @@ -7596,12 +7594,11 @@ void Client::SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class current_value = GetCharacterFactionLevel(faction_id); faction_before_hit = current_value; - change = UpdatePersonalFaction(char_id, value, faction_id, ¤t_value, temp, this_faction_min, this_faction_max); + UpdatePersonalFaction(char_id, value, faction_id, ¤t_value, temp, this_faction_min, this_faction_max); - if (change) - { - SendFactionMessage(value, faction_id, faction_before_hit, current_value, temp, this_faction_min, this_faction_max); - } + //Message(14, "Min(%d) Max(%d) Before(%d), After(%d)\n", this_faction_min, this_faction_max, faction_before_hit, current_value); + + SendFactionMessage(value, faction_id, faction_before_hit, current_value, temp, this_faction_min, this_faction_max); } return; @@ -7623,10 +7620,11 @@ int32 Client::GetCharacterFactionLevel(int32 faction_id) // Checks for bottom out and max faction and old faction db entries // Updates the faction if we are not minned, maxed or we need to repair -bool Client::UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp, int32 this_faction_min, int32 this_faction_max) +void Client::UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp, int32 this_faction_min, int32 this_faction_max) { bool repair = false; bool change = false; + int32 faction_before_hit = *current_value - npc_value; if (this->itembonuses.HeroicCHA) { @@ -7655,22 +7653,24 @@ bool Client::UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction *current_value = this_faction_min; repair = true; } - else if ((m_pp.gm != 1) && (npc_value != 0) && ((*current_value != this_faction_max) || (*current_value != this_faction_min))) + else if ((m_pp.gm != 1) && (npc_value != 0) && + ((npc_value > 0 && faction_before_hit != this_faction_max) || + ((npc_value < 0 && faction_before_hit != this_faction_min)))) change = true; - *current_value += npc_value; - - if (*current_value > this_faction_max) - *current_value = this_faction_max; - else if (*current_value < this_faction_min) - *current_value = this_faction_min; - if (change || repair) { + *current_value += npc_value; + + if (*current_value > this_faction_max) + *current_value = this_faction_max; + else if (*current_value < this_faction_min) + *current_value = this_faction_min; + database.SetCharacterFactionLevel(char_id, faction_id, *current_value, temp, factionvalues); } -return (repair || change); +return; } // returns the character's faction level, adjusted for racial, class, and deity modifiers @@ -7756,16 +7756,16 @@ void Client::SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_ char name[50]; int32 faction_value; - // If we're dropping from MAX or raising from MIN, we should - // base the message on the new updated value so we don't show + // If we're dropping from MAX or raising from MIN or repairing, + // we should base the message on the new updated value so we don't show // a min MAX message // // If we're changing any other place, we use the value before the // hit. For example, if we go from 1199 to 1200 which is the MAX // we still want to say faction got better this time around. - if ( (faction_before_hit == this_faction_max) || - (faction_before_hit == this_faction_min)) + if ( (faction_before_hit >= this_faction_max) || + (faction_before_hit <= this_faction_min)) faction_value = totalvalue; else faction_value = faction_before_hit; diff --git a/zone/client.h b/zone/client.h index fa7da0fc0..9248fb742 100644 --- a/zone/client.h +++ b/zone/client.h @@ -609,7 +609,7 @@ public: void MerchantRejectMessage(Mob *merchant, int primaryfaction); void SendFactionMessage(int32 tmpvalue, int32 faction_id, int32 faction_before_hit, int32 totalvalue, uint8 temp, int32 this_faction_min, int32 this_faction_max); - bool UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp, int32 this_faction_min, int32 this_faction_max); + void UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction_id, int32 *current_value, int32 temp, int32 this_faction_min, int32 this_faction_max); void SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, uint8 char_race, uint8 char_deity); void SetFactionLevel2(uint32 char_id, int32 faction_id, uint8 char_class, uint8 char_race, uint8 char_deity, int32 value, uint8 temp); int32 GetRawItemAC(); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 56236f1b8..e90016dfb 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -3212,16 +3212,7 @@ bool ZoneDatabase::GetNPCFactionList(uint32 npcfaction_id, int32* faction_id, in bool ZoneDatabase::SetCharacterFactionLevel(uint32 char_id, int32 faction_id, int32 value, uint8 temp, faction_map &val_list) { - std::string query = StringFormat("DELETE FROM faction_values " - "WHERE char_id=%i AND faction_id = %i", - char_id, faction_id); - auto results = QueryDatabase(query); - if (!results.Success()) { - return false; - } - - if(value == 0) - return true; + std::string query; if(temp == 2) temp = 0; @@ -3229,17 +3220,18 @@ bool ZoneDatabase::SetCharacterFactionLevel(uint32 char_id, int32 faction_id, in if(temp == 3) temp = 1; - query = StringFormat("INSERT INTO faction_values (char_id, faction_id, current_value, temp) " - "VALUES (%i, %i, %i, %i)", char_id, faction_id, value, temp); - results = QueryDatabase(query); - if (!results.Success()) { + query = StringFormat("INSERT INTO `faction_values` " + "(`char_id`, `faction_id`, `current_value`, `temp`) " + "VALUES (%i, %i, %i, %i) " + "ON DUPLICATE KEY UPDATE `current_value`=%i,`temp`=%i", + char_id, faction_id, value, temp, value, temp); + auto results = QueryDatabase(query); + + if (!results.Success()) return false; - } + else + val_list[faction_id] = value; - if (results.RowsAffected() == 0) - return false; - - val_list[faction_id] = value; return true; } From cced57f56a542a741b50e33fd05784145b7506f2 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 1 Feb 2015 15:11:27 -0500 Subject: [PATCH 22/50] 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 1d40f20da007ae37d8c068fa290b0b9883618ba9 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Sun, 1 Feb 2015 16:14:05 -0500 Subject: [PATCH 23/50] Remove incorrect use of before_hit --- zone/client.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index 9d159ce77..5cc5ae309 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -7624,7 +7624,6 @@ void Client::UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction { bool repair = false; bool change = false; - int32 faction_before_hit = *current_value - npc_value; if (this->itembonuses.HeroicCHA) { @@ -7654,8 +7653,8 @@ void Client::UpdatePersonalFaction(int32 char_id, int32 npc_value, int32 faction repair = true; } else if ((m_pp.gm != 1) && (npc_value != 0) && - ((npc_value > 0 && faction_before_hit != this_faction_max) || - ((npc_value < 0 && faction_before_hit != this_faction_min)))) + ((npc_value > 0 && *current_value != this_faction_max) || + ((npc_value < 0 && *current_value != this_faction_min)))) change = true; if (change || repair) From 8649ed1dcb3b49bcd89a15051d70f573638abd27 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 1 Feb 2015 17:25:16 -0500 Subject: [PATCH 24/50] 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 25/50] 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 26/50] 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 27/50] 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 28/50] 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 29/50] 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 30/50] 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 31/50] 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 32/50] 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 33/50] 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 34/50] 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 35/50] 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 36/50] 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 37/50] 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 38/50] 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 39/50] 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 40/50] 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 41/50] 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 42/50] 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 43/50] 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 44/50] 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 45/50] 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 46/50] 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 47/50] 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 48/50] 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 49/50] 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 50/50] 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 */