From 68a34565f9803ad83810c1b5072106ca2edd3455 Mon Sep 17 00:00:00 2001 From: Natedog2012 Date: Fri, 27 Jan 2023 17:31:14 -0600 Subject: [PATCH] [Bugfix] Add SetItemCooldown to tell client exact timer of item when clicked and export to perl and lua (#2795) Items that are on cooldown but client doesn't show.. clicking item will fix the timer in client --- zone/client.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++ zone/client.h | 1 + zone/client_packet.cpp | 3 +- zone/lua_client.cpp | 7 +++++ zone/lua_client.h | 1 + zone/perl_client.cpp | 6 ++++ 6 files changed, 82 insertions(+), 1 deletion(-) diff --git a/zone/client.cpp b/zone/client.cpp index c549378d3..e3452d29b 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -10498,6 +10498,71 @@ void Client::ResetItemCooldown(uint32 item_id) } } +void Client::SetItemCooldown(uint32 item_id, bool use_saved_timer, uint32 in_seconds) +{ + EQ::ItemInstance *item = nullptr; + const EQ::ItemData* item_d = database.GetItem(item_id); + if (!item_d) { + return; + } + int recast_type = item_d->RecastType; + auto timestamps = database.GetItemRecastTimestamps(CharacterID()); + uint32 total_time = 0; + uint32 current_time = static_cast(std::time(nullptr)); + uint32 final_time = 0; + const auto timer_type = item_d->RecastType != RECAST_TYPE_UNLINKED_ITEM ? item_d->RecastType : item_id; + const int timer_id = recast_type != RECAST_TYPE_UNLINKED_ITEM ? (pTimerItemStart + recast_type) : (pTimerNegativeItemReuse * item_id); + + if (use_saved_timer) { + if (item_d->RecastType != RECAST_TYPE_UNLINKED_ITEM) { + total_time = timestamps.count(item_d->RecastType) ? timestamps.at(item_d->RecastType) : 0; + } else { + total_time = timestamps.count(item_id) ? timestamps.at(item_id) : 0; + } + } else { + total_time = current_time + in_seconds; + } + + if (total_time > current_time) { + final_time = total_time - current_time; + } + + static const int16 slots[][2] = { + { EQ::invslot::POSSESSIONS_BEGIN, EQ::invslot::POSSESSIONS_END }, + { EQ::invbag::GENERAL_BAGS_BEGIN, EQ::invbag::GENERAL_BAGS_END }, + { EQ::invbag::CURSOR_BAG_BEGIN, EQ::invbag::CURSOR_BAG_END}, + { EQ::invslot::BANK_BEGIN, EQ::invslot::BANK_END }, + { EQ::invbag::BANK_BAGS_BEGIN, EQ::invbag::BANK_BAGS_END }, + { EQ::invslot::SHARED_BANK_BEGIN, EQ::invslot::SHARED_BANK_END }, + { EQ::invbag::SHARED_BANK_BAGS_BEGIN, EQ::invbag::SHARED_BANK_BAGS_END }, + }; + const size_t slot_index_count = sizeof(slots) / sizeof(slots[0]); + for (int slot_index = 0; slot_index < slot_index_count; ++slot_index) { + for (int slot_id = slots[slot_index][0]; slot_id <= slots[slot_index][1]; ++slot_id) { + item = GetInv().GetItem(slot_id); + if (item) { + item_d = item->GetItem(); + if (item_d && item->GetID() == item_id || (item_d->RecastType != RECAST_TYPE_UNLINKED_ITEM && item_d->RecastType == recast_type)) { + item->SetRecastTimestamp(total_time); + SendItemPacket(slot_id, item, ItemPacketCharmUpdate); + } + } + } + } + + //Start timers and update in database only when timer is changed + if (!use_saved_timer) { + GetPTimers().Clear(&database, timer_id); + GetPTimers().Start((timer_id), in_seconds); + database.UpdateItemRecast( + CharacterID(), + timer_type, + GetPTimers().Get(timer_id)->GetReadyTimestamp() + ); + } + SendItemRecastTimer(recast_type, final_time, true); +} + void Client::RemoveItem(uint32 item_id, uint32 quantity) { EQ::ItemInstance *item = nullptr; diff --git a/zone/client.h b/zone/client.h index 627624726..17f1bc871 100644 --- a/zone/client.h +++ b/zone/client.h @@ -967,6 +967,7 @@ public: void DeleteItemInInventory(int16 slot_id, int16 quantity = 0, bool client_update = false, bool update_db = true); int CountItem(uint32 item_id); void ResetItemCooldown(uint32 item_id); + void SetItemCooldown(uint32 item_id, bool use_saved_timer = false, uint32 in_seconds = 1); void RemoveItem(uint32 item_id, uint32 quantity = 1); bool SwapItem(MoveItem_Struct* move_in); void SwapItemResync(MoveItem_Struct* move_slots); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 7aa3d435b..007cbc6a6 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -8928,11 +8928,12 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app) if (item->RecastDelay > 0) { if (item->RecastType != RECAST_TYPE_UNLINKED_ITEM && !GetPTimers().Expired(&database, (pTimerItemStart + item->RecastType), false)) { - SendItemRecastTimer(item->RecastType); //Problem: When you loot corpse, recast display is not present. This causes it to display again. Could not get to display when sending from looting. + SetItemCooldown(item->ID, true); SendSpellBarEnable(item->Click.Effect); LogSpells("Casting of [{}] canceled: item spell reuse timer not expired", spell_id); return; } else if (item->RecastType == RECAST_TYPE_UNLINKED_ITEM && !GetPTimers().Expired(&database, (pTimerNegativeItemReuse * item->ID), false)) { + SetItemCooldown(item->ID, true); SendSpellBarEnable(item->Click.Effect); LogSpells("Casting of [{}] canceled: item spell reuse timer not expired", spell_id); return; diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index 242fc6e71..c1a8ee9da 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -3020,6 +3020,12 @@ void Lua_Client::ResetItemCooldown(uint32 item_id) self->ResetItemCooldown(item_id); } +void Lua_Client::SetItemCooldown(uint32 item_id, uint32 in_time) +{ + Lua_Safe_Call_Void(); + self->SetItemCooldown(item_id, false, in_time); +} + luabind::scope lua_register_client() { return luabind::class_("Client") .def(luabind::constructor<>()) @@ -3454,6 +3460,7 @@ luabind::scope lua_register_client() { .def("SetHunger", (void(Lua_Client::*)(int))&Lua_Client::SetHunger) .def("SetInvulnerableEnvironmentDamage", (void(Lua_Client::*)(int))&Lua_Client::SetInvulnerableEnvironmentDamage) .def("SetIPExemption", (void(Lua_Client::*)(int))&Lua_Client::SetIPExemption) + .def("SetItemCooldown", (void(Lua_Client::*)(uint32,uint32))&Lua_Client::SetItemCooldown) .def("SetLanguageSkill", (void(Lua_Client::*)(int,int))&Lua_Client::SetLanguageSkill) .def("SetMaterial", (void(Lua_Client::*)(int,uint32))&Lua_Client::SetMaterial) .def("SetPEQZoneFlag", (void(Lua_Client::*)(uint32))&Lua_Client::SetPEQZoneFlag) diff --git a/zone/lua_client.h b/zone/lua_client.h index efba961c7..8faa2242f 100644 --- a/zone/lua_client.h +++ b/zone/lua_client.h @@ -463,6 +463,7 @@ public: bool CanEnterZone(std::string zone_short_name, int16 instance_version); void SendPath(Lua_Mob target); void ResetItemCooldown(uint32 item_id); + void SetItemCooldown(uint32 item_id, uint32 in_time); void ApplySpell(int spell_id); void ApplySpell(int spell_id, int duration); diff --git a/zone/perl_client.cpp b/zone/perl_client.cpp index 856f000a1..18c2ed80d 100644 --- a/zone/perl_client.cpp +++ b/zone/perl_client.cpp @@ -2877,6 +2877,11 @@ void Perl_Client_ResetItemCooldown(Client* self, uint32 item_id) self->ResetItemCooldown(item_id); } +void Perl_Client_SetItemCooldown(Client* self, uint32 item_id, uint32 in_time) +{ + self->SetItemCooldown(item_id, false, in_time); +} + void perl_register_client() { perl::interpreter perl(PERL_GET_THX); @@ -3313,6 +3318,7 @@ void perl_register_client() package.add("SetHunger", &Perl_Client_SetHunger); package.add("SetIPExemption", &Perl_Client_SetIPExemption); package.add("SetInvulnerableEnvironmentDamage", &Perl_Client_SetInvulnerableEnvironmentDamage); + package.add("SetItemCooldown", &Perl_Client_SetItemCooldown); package.add("SetLanguageSkill", &Perl_Client_SetLanguageSkill); package.add("SetMaterial", &Perl_Client_SetMaterial); package.add("SetPEQZoneFlag", &Perl_Client_SetPEQZoneFlag);