From 95e4d8a423d1a36eeadd71f0e3d7a9261a6265b3 Mon Sep 17 00:00:00 2001 From: sogladev Date: Wed, 6 May 2026 05:26:30 +0200 Subject: [PATCH] fix(Scripts/World): Precious and Simone use safer calls (#25728) --- .../scripts/World/npc_stave_of_ancients.cpp | 135 ++++++++++-------- .../scripts/World/npc_stave_of_ancients.h | 17 ++- 2 files changed, 90 insertions(+), 62 deletions(-) diff --git a/src/server/scripts/World/npc_stave_of_ancients.cpp b/src/server/scripts/World/npc_stave_of_ancients.cpp index 2d45d2e7ba..56d89382fc 100644 --- a/src/server/scripts/World/npc_stave_of_ancients.cpp +++ b/src/server/scripts/World/npc_stave_of_ancients.cpp @@ -70,14 +70,14 @@ Player* NPCStaveQuestAI::GetGossipPlayer() return ObjectAccessor::GetPlayer(*me, gossipPlayerGUID); } -bool NPCStaveQuestAI::IsAllowedEntry(uint32 entry) +bool NPCStaveQuestAI::IsAllowedEntry(uint32 entry) const { uint32 allowedEntries[4] = { 0, 12999, 19833, 19921 }; //player, World Invisible Trigger(traps) and snake trap snakes bool isAllowed = std::find(std::begin(allowedEntries), std::end(allowedEntries), entry) != std::end(allowedEntries); return isAllowed; } -bool NPCStaveQuestAI::UnitIsUnfair(Unit* unit) +bool NPCStaveQuestAI::UnitIsUnfair(Unit* unit) const { if (!unit || playerGUID.IsEmpty()) { @@ -108,7 +108,7 @@ bool NPCStaveQuestAI::UnitIsUnfair(Unit* unit) return false; } -bool NPCStaveQuestAI::IsFairFight() +bool NPCStaveQuestAI::IsFairFight() const { for (ThreatReference const* ref : me->GetThreatMgr().GetUnsortedThreatList()) { @@ -128,12 +128,10 @@ bool NPCStaveQuestAI::IsFairFight() return true; } -bool NPCStaveQuestAI::ValidThreatlist() +bool NPCStaveQuestAI::ValidThreatlist() const { if (me->GetThreatMgr().GetThreatListSize() == 1) - { return true; - } bool isFair = IsFairFight(); @@ -463,10 +461,10 @@ public: struct npc_preciousAI : public NPCStaveQuestAI { - npc_preciousAI(Creature *creature) : NPCStaveQuestAI(creature) { } + explicit npc_preciousAI(Creature *creature) : NPCStaveQuestAI(creature) { } EventMap events; - bool flaggedForDespawn; + bool flaggedForDespawn{}; void InitializeAI() override { @@ -512,6 +510,37 @@ public: { flaggedForDespawn = true; } + + uint32 GetData(uint32 type) const override + { + if (type == DATA_SIMONE_VALID_THREATLIST) + return ValidThreatlist() ? 1 : 0; + + return 0; + } + + void SetData(uint32 type, uint32 data) override + { + switch (type) + { + case DATA_SIMONE_REVEAL: + if (data) + RevealForm(); + break; + case DATA_SIMONE_PREPARE_ENCOUNTER: + PrepareForEncounter(); + break; + case DATA_SIMONE_SET_HOME: + SetHomePosition(); + break; + case DATA_SIMONE_CORPSE_REMOVED: + EnterEvadeMode(); + FlagForDespawn(); + break; + default: + break; + } + } }; }; @@ -527,7 +556,7 @@ public: struct npc_simoneAI : public NPCStaveQuestAI { - npc_simoneAI(Creature *creature) : NPCStaveQuestAI(creature) { } + explicit npc_simoneAI(Creature *creature) : NPCStaveQuestAI(creature) { } EventMap events; ObjectGuid preciousGUID; @@ -535,39 +564,18 @@ public: void SetPreciousGUID() { if (CreatureGroup* formation = me->GetFormation()) - { - const CreatureGroup::CreatureGroupMemberType& members = formation->GetMembers(); - for (CreatureGroup::CreatureGroupMemberType::const_iterator itr = members.begin(); itr != members.end(); ++itr) - { - if (itr->first && itr->first->GetOriginalEntry() == PRECIOUS_NORMAL_ENTRY) - { - preciousGUID = itr->first->GetGUID(); - } - } - } + for ([[maybe_unused]] auto const& [member, info] : formation->GetMembers()) + if (member && member->GetOriginalEntry() == PRECIOUS_NORMAL_ENTRY) + preciousGUID = member->GetGUID(); } Creature* Precious() { if (preciousGUID.IsEmpty()) - { SetPreciousGUID(); - } if (!preciousGUID.IsEmpty()) - { return ObjectAccessor::GetCreature(*me, preciousGUID); - } - - return nullptr; - } - - npc_precious::npc_preciousAI* PreciousAI() - { - if (Precious()) - { - return CAST_AI(npc_precious::npc_preciousAI, Precious()->AI()); - } return nullptr; } @@ -632,21 +640,20 @@ public: void CorpseRemoved(uint32& /*respawnDelay*/) override { - if (!Precious()) - { + Creature* creature = Precious(); + if (!creature) return; - } - if (Precious()->IsInCombat()) + if (creature->IsInCombat()) { - // If Simone corpse is removed but pet is InCombat, EnterEvadeMode and auto despawn on pet reaching home - PreciousAI()->EnterEvadeMode(); - PreciousAI()->FlagForDespawn(); + // If Simone corpse is removed but pet is InCombat, ask pet AI to enter evade and flag for despawn + if (creature->AI()) + creature->AI()->SetData(DATA_SIMONE_CORPSE_REMOVED, 1); + else + creature->DespawnOrUnsummon(0ms); } else - { - Precious()->DespawnOrUnsummon(0ms); - } + creature->DespawnOrUnsummon(0ms); } void Reset() override @@ -704,10 +711,9 @@ public: break; case EVENT_REVEAL: RevealForm(); - if (PreciousAI()) - { - PreciousAI()->RevealForm(); - } + if (Creature* creature = Precious()) + if (creature->AI()) + creature->AI()->SetData(DATA_SIMONE_REVEAL, 1); break; // Prevent hunters from figthing Simone alone case SIMONE_EVENT_CHECK_PET_STATE: @@ -721,6 +727,8 @@ public: events.ScheduleEvent(SIMONE_EVENT_CHECK_PET_STATE, 1s); } break; + default: + break; } if (UpdateVictim()) @@ -760,23 +768,32 @@ public: } break; case EVENT_UNFAIR_FIGHT: - if (!ValidThreatlist() || (PreciousAI() && !PreciousAI()->ValidThreatlist())) + { + Creature* creature = Precious(); + bool isPreciousThreatListValid = creature && creature->AI() && creature->AI()->GetData(DATA_SIMONE_VALID_THREATLIST) == 1; + + if (!ValidThreatlist() || !isPreciousThreatListValid) { SetHomePosition(); - PreciousAI()->SetHomePosition(); - - Precious()->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1); - Precious()->SetImmuneToAll(true); + me->DespawnOrUnsummon(5s); me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1); me->SetImmuneToAll(true); - Precious()->DespawnOrUnsummon(5s); + if (creature) + { + if (creature->AI()) + creature->AI()->SetData(DATA_SIMONE_SET_HOME, 1); + + creature->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1); + creature->SetImmuneToAll(true); + creature->DespawnOrUnsummon(5s); + } - me->DespawnOrUnsummon(5s); break; } events.Repeat(2s); break; + } case SIMONE_EVENT_CHAIN_LIGHTNING: me->CastSpell(me->GetVictim(), SIMONE_SPELL_CHAIN_LIGHTNING, false); events.Repeat(7s); @@ -785,6 +802,8 @@ public: me->CastSpell(me->GetVictim(), SIMONE_SPELL_TEMPTRESS_KISS, false); events.Repeat(45s); break; + default: + break; } DoMeleeAttackIfReady(); @@ -805,10 +824,10 @@ public: void ScheduleEncounterStart(ObjectGuid playerGUID) { PrepareForEncounter(); - if (PreciousAI()) - { - PreciousAI()->PrepareForEncounter(); - } + if (Creature* creature = Precious()) + if (creature->AI()) + creature->AI()->SetData(DATA_SIMONE_PREPARE_ENCOUNTER, 1); + gossipPlayerGUID = playerGUID; events.ScheduleEvent(EVENT_ENCOUNTER_START, 1s); } diff --git a/src/server/scripts/World/npc_stave_of_ancients.h b/src/server/scripts/World/npc_stave_of_ancients.h index cb4ab6e2d6..b391c69dfc 100644 --- a/src/server/scripts/World/npc_stave_of_ancients.h +++ b/src/server/scripts/World/npc_stave_of_ancients.h @@ -88,6 +88,15 @@ enum NPCPrecious PRECIOUS_EVIL_ENTRY = 14538 }; +enum SimoneAIData +{ + DATA_SIMONE_REVEAL = 1, + DATA_SIMONE_PREPARE_ENCOUNTER = 2, + DATA_SIMONE_VALID_THREATLIST = 3, + DATA_SIMONE_SET_HOME = 4, + DATA_SIMONE_CORPSE_REMOVED = 5 +}; + enum NPCNelson { NELSON_EVENT_DREADFUL_FRIGHT = 6, @@ -189,10 +198,10 @@ struct NPCStaveQuestAI : public ScriptedAI void RevealForm(); void StorePlayerGUID(); Player* GetGossipPlayer(); - bool IsAllowedEntry(uint32 /*entry*/); - bool UnitIsUnfair(Unit* unit); - bool IsFairFight(); - bool ValidThreatlist(); + bool IsAllowedEntry(uint32 /*entry*/) const; + bool UnitIsUnfair(Unit* unit) const; + bool IsFairFight() const; + bool ValidThreatlist() const; void SetHomePosition(); void PrepareForEncounter(); void ClearLootIfUnfair(Unit* killer);