From cc0171dfe1d77393afd1b7b77029d9e5e8a48990 Mon Sep 17 00:00:00 2001 From: fuzzlecutter <164541008+fuzzlecutter@users.noreply.github.com> Date: Thu, 12 Sep 2024 14:42:44 -0500 Subject: [PATCH] [Feature] Allow NPCs to cast Sacrifice (#4470) * [Feature] Teach npcs how to cast sacrifice * [Feature] Teach npcs how to cast sacrifice - Remove the hardcoded limit preventing npcs from casting sacrifice. The npc will receive as loot an emerald essence as expected. * Update client.cpp * Update client_packet.cpp * Update spell_effects.cpp * rename Client::SacrificeCaster to Client::sacrifice_caster_id --- zone/client.cpp | 16 ++++++++++------ zone/client.h | 6 +++--- zone/client_packet.cpp | 4 ++-- zone/spell_effects.cpp | 4 ++-- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index 14bef0930..aca80c8b7 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -286,6 +286,7 @@ Client::Client(EQStreamInterface *ieqs) : Mob( memset(&m_epp, 0, sizeof(m_epp)); PendingTranslocate = false; PendingSacrifice = false; + sacrifice_caster_id = 0; controlling_boat_id = 0; controlled_mob_id = 0; qGlobals = nullptr; @@ -3971,7 +3972,7 @@ void Client::SetEndurance(int32 newEnd) CheckManaEndUpdate(); } -void Client::SacrificeConfirm(Client *caster) +void Client::SacrificeConfirm(Mob *caster) { auto outapp = new EQApplicationPacket(OP_Sacrifice, sizeof(Sacrifice_Struct)); Sacrifice_Struct *ss = (Sacrifice_Struct *)outapp->pBuffer; @@ -3998,14 +3999,14 @@ void Client::SacrificeConfirm(Client *caster) ss->Confirm = 0; QueuePacket(outapp); safe_delete(outapp); - // We store the Caster's name, because when the packet comes back, it only has the victim's entityID in it, + // We store the Caster's id, because when the packet comes back, it only has the victim's entityID in it, // not the caster. - SacrificeCaster += caster->GetName(); + sacrifice_caster_id = caster->GetID(); PendingSacrifice = true; } //Essentially a special case death function -void Client::Sacrifice(Client *caster) +void Client::Sacrifice(Mob *caster) { if (GetLevel() >= RuleI(Spells, SacrificeMinLevel) && GetLevel() <= RuleI(Spells, SacrificeMaxLevel)) { int exploss = (int)(GetLevel() * (GetLevel() / 18.0) * 12000); @@ -4053,8 +4054,11 @@ void Client::Sacrifice(Client *caster) } Save(); GoToDeath(); - if (caster) // I guess it's possible? - caster->SummonItem(RuleI(Spells, SacrificeItemID)); + if (caster && caster->IsClient()) { + caster->CastToClient()->SummonItem(RuleI(Spells, SacrificeItemID)); + } else if (caster && caster->IsNPC()) { + caster->CastToNPC()->AddItem(RuleI(Spells, SacrificeItemID), 1, false); + } } } else { caster->MessageString(Chat::Red, SAC_TOO_LOW); // This being is not a worthy sacrifice. diff --git a/zone/client.h b/zone/client.h index b79d8b5cd..231630887 100644 --- a/zone/client.h +++ b/zone/client.h @@ -762,8 +762,8 @@ public: void GetRaidAAs(RaidLeadershipAA_Struct *into) const; void ClearGroupAAs(); void UpdateGroupAAs(int32 points, uint32 type); - void SacrificeConfirm(Client* caster); - void Sacrifice(Client* caster); + void SacrificeConfirm(Mob* caster); + void Sacrifice(Mob* caster); void GoToDeath(); inline const int32 GetInstanceID() const { return zone->GetInstanceID(); } void SetZoning(bool in) { bZoning = in; } @@ -1245,7 +1245,7 @@ public: bool PendingTranslocate; time_t TranslocateTime; bool PendingSacrifice; - std::string SacrificeCaster; + uint16 sacrifice_caster_id; PendingTranslocate_Struct PendingTranslocateData; void SendOPTranslocateConfirm(Mob *Caster, uint16 SpellID); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index a222e5e93..03feabbc5 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -13681,11 +13681,11 @@ void Client::Handle_OP_Sacrifice(const EQApplicationPacket *app) } if (ss->Confirm) { - Client *Caster = entity_list.GetClientByName(SacrificeCaster.c_str()); + Mob *Caster = entity_list.GetMob(sacrifice_caster_id); if (Caster) Sacrifice(Caster); } PendingSacrifice = false; - SacrificeCaster.clear(); + sacrifice_caster_id = 0; } void Client::Handle_OP_SafeFallSuccess(const EQApplicationPacket *app) // bit of a misnomer, sent whenever safe fall is used (success of fail) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 2db06b0c2..93721f8c9 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2202,10 +2202,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Sacrifice"); #endif - if(!caster || !IsClient() || !caster->IsClient()){ + if(!caster || !IsClient() ){ break; } - CastToClient()->SacrificeConfirm(caster->CastToClient()); + CastToClient()->SacrificeConfirm(caster); break; }