From 53610c2f0fdf0279a590cd89c480437adaf865dc Mon Sep 17 00:00:00 2001 From: Mitch Freeman <65987027+neckkola@users.noreply.github.com> Date: Sat, 8 Mar 2025 01:00:11 -0400 Subject: [PATCH] [Feature] Add Rule for dealing with augments when an item evolves (#4758) --- common/ruletypes.h | 1 + zone/client.h | 3 ++- zone/client_evolving_items.cpp | 46 ++++++++++++++++++++++++++++++++-- zone/parcels.cpp | 18 ++++++++++++- 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index f053656ec..f3413e827 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -1163,6 +1163,7 @@ RULE_REAL(EvolvingItems, PercentOfSoloExperience, 0.1, "Percentage of solo exper RULE_REAL(EvolvingItems, PercentOfGroupExperience, 0.1, "Percentage of group experience allocated to evolving items that require experience.") RULE_REAL(EvolvingItems, PercentOfRaidExperience, 0.1, "Percentage of raid experience allocated to evolving items that require experience.") RULE_INT(EvolvingItems, DelayUponEquipping, 30000, "Delay in ms before an evolving item will earn rewards after equipping. Default is 30000ms or 30s.") +RULE_BOOL(EvolvingItems, DestroyAugmentsOnEvolve, false, "If this is enabled, any augments in an item will be destroyed when the item evolves. Otherwise, send augments to the player via the parcel system (requires that the Parcel System be enabled).") RULE_CATEGORY_END() #undef RULE_CATEGORY diff --git a/zone/client.h b/zone/client.h index c6a4edfb1..7deab6e83 100644 --- a/zone/client.h +++ b/zone/client.h @@ -404,6 +404,7 @@ public: void LoadParcels(); std::map GetParcels() { return m_parcels; } int32 FindNextFreeParcelSlot(uint32 char_id); + int32 FindNextFreeParcelSlotUsingMemory(); void SendParcelIconStatus(); void SendBecomeTraderToWorld(Client *trader, BazaarTraderBarterActions action); @@ -1900,7 +1901,7 @@ public: void SendEvolvingPacket(int8 action, const CharacterEvolvingItemsRepository::CharacterEvolvingItems &item); void DoEvolveItemToggle(const EQApplicationPacket* app); void DoEvolveItemDisplayFinalResult(const EQApplicationPacket* app); - bool DoEvolveCheckProgression(const EQ::ItemInstance &inst); + bool DoEvolveCheckProgression(EQ::ItemInstance &inst); void SendEvolveXPWindowDetails(const EQApplicationPacket* app); void DoEvolveTransferXP(const EQApplicationPacket* app); void SendEvolveXPTransferWindow(); diff --git a/zone/client_evolving_items.cpp b/zone/client_evolving_items.cpp index 72488405a..aea86689d 100644 --- a/zone/client_evolving_items.cpp +++ b/zone/client_evolving_items.cpp @@ -71,7 +71,7 @@ void Client::SendEvolvingPacket(const int8 action, const CharacterEvolvingItemsR void Client::ProcessEvolvingItem(const uint64 exp, const Mob *mob) { - std::vector queue{}; + std::vector queue{}; for (auto &[key, inst]: GetInv().GetWorn()) { LogEvolveItemDetail( @@ -298,7 +298,7 @@ void Client::DoEvolveItemDisplayFinalResult(const EQApplicationPacket *app) } } -bool Client::DoEvolveCheckProgression(const EQ::ItemInstance &inst) +bool Client::DoEvolveCheckProgression(EQ::ItemInstance &inst) { if (inst.GetEvolveProgression() < 100 || inst.GetEvolveLvl() == inst.GetMaxEvolveLvl()) { return false; @@ -315,6 +315,48 @@ bool Client::DoEvolveCheckProgression(const EQ::ItemInstance &inst) return false; } + if (RuleB(EvolvingItems, EnableParcelMerchants) && + !RuleB(EvolvingItems, DestroyAugmentsOnEvolve) && + inst.IsAugmented() + ) { + auto const augs = inst.GetAugmentIDs(); + std::vector parcels; + for (auto const &item_id: augs) { + if (!item_id) { + continue; + } + + CharacterParcelsRepository::CharacterParcels p{}; + p.char_id = CharacterID(); + p.from_name = "Evolving Item Sub-System"; + p.note = fmt::format( + "System automatically removed from {} which recently evolved.", + inst.GetItem()->Name + ); + p.slot_id = FindNextFreeParcelSlotUsingMemory(); + p.sent_date = time(nullptr); + p.item_id = item_id; + p.quantity = 1; + + if (player_event_logs.IsEventEnabled(PlayerEvent::PARCEL_SEND)) { + PlayerEvent::ParcelSend e{}; + e.from_player_name = p.from_name; + e.to_player_name = GetCleanName(); + e.item_id = p.item_id; + e.quantity = 1; + e.sent_date = p.sent_date; + + RecordPlayerEventLog(PlayerEvent::PARCEL_SEND, e); + } + + parcels.push_back(p); + } + + CharacterParcelsRepository::InsertMany(database, parcels); + SendParcelStatus(); + SendParcelIconStatus(); + } + CheckItemDiscoverability(new_inst->GetID()); PlayerEvent::EvolveItem e{}; diff --git a/zone/parcels.cpp b/zone/parcels.cpp index 49291d6e8..7d2c27429 100644 --- a/zone/parcels.cpp +++ b/zone/parcels.cpp @@ -888,6 +888,22 @@ void Client::AddParcel(CharacterParcelsRepository::CharacterParcels &parcel) "Unable to send parcel at this time. Please try again later." ); SendParcelAck(); - return; } } + +int32 Client::FindNextFreeParcelSlotUsingMemory() +{ + auto const results = GetParcels(); + + if (results.empty()) { + return PARCEL_BEGIN_SLOT; + } + + for (uint32 i = PARCEL_BEGIN_SLOT; i <= RuleI(Parcel, ParcelMaxItems); i++) { + if (!results.contains(i)) { + return i; + } + } + + return INVALID_INDEX; +} \ No newline at end of file