Remove the extra Jainas after the crew is healed.

This commit is contained in:
luis
2026-09-23 17:09:15 -03:00
parent a20c8988e8
commit f58e739dcc
8 changed files with 109 additions and 40 deletions
@@ -269,6 +269,9 @@ void TempSummon::InitSummon(WorldObject* summoner)
{ {
if (summoner) if (summoner)
{ {
if (Unit* unitSummoner = summoner->ToUnit())
unitSummoner->RegisterSummonedCreature(this);
if (summoner->GetTypeId() == TYPEID_UNIT) if (summoner->GetTypeId() == TYPEID_UNIT)
{ {
if (summoner->ToCreature()->IsAIEnabled()) if (summoner->ToCreature()->IsAIEnabled())
@@ -368,6 +371,9 @@ void TempSummon::RemoveFromWorld()
if (!IsInWorld()) if (!IsInWorld())
return; return;
if (Unit* summoner = GetSummonerUnit())
summoner->UnregisterSummonedCreature(GetGUID());
if (m_Properties && m_Properties->Slot != 0) if (m_Properties && m_Properties->Slot != 0)
if (Unit* owner = GetSummonerUnit()) if (Unit* owner = GetSummonerUnit())
for (ObjectGuid& summonSlot : owner->m_SummonSlot) for (ObjectGuid& summonSlot : owner->m_SummonSlot)
+21 -3
View File
@@ -15544,11 +15544,29 @@ Creature* Unit::GetSummonedCreatureByEntry(uint32 entry)
return ObjectAccessor::GetCreature(*this, itr->first); return ObjectAccessor::GetCreature(*this, itr->first);
} }
void Unit::RegisterSummonedCreature(Creature* creature)
{
if (creature)
m_SummonedCreatures[creature->GetGUID()] = creature->GetEntry();
}
void Unit::UnregisterSummonedCreature(ObjectGuid guid)
{
m_SummonedCreatures.erase(guid);
}
void Unit::UnsummonCreatureByEntry(uint32 entry, uint32 ms/* = 0*/) void Unit::UnsummonCreatureByEntry(uint32 entry, uint32 ms/* = 0*/)
{ {
if (Creature* creature = GetSummonedCreatureByEntry(entry)) // A quest can leave more than one copy. Collect first: UnSummon removes them from this map.
if (TempSummon* tempSummon = creature->ToTempSummon()) std::vector<ObjectGuid> guids;
tempSummon->UnSummon(ms); for (auto const& summoned : m_SummonedCreatures)
if (summoned.second == entry)
guids.push_back(summoned.first);
for (ObjectGuid const& guid : guids)
if (Creature* creature = ObjectAccessor::GetCreature(*this, guid))
if (TempSummon* tempSummon = creature->ToTempSummon())
tempSummon->UnSummon(ms);
} }
void Unit::GetFriendlyUnitListInRange(std::list<Unit*>& list, float fMaxSearchRange, bool exceptSelf) const void Unit::GetFriendlyUnitListInRange(std::list<Unit*>& list, float fMaxSearchRange, bool exceptSelf) const
+2
View File
@@ -1911,6 +1911,8 @@ class TC_GAME_API Unit : public WorldObject
//WowCommunity //WowCommunity
TaskScheduler& GetScheduler() { return _scheduler; } TaskScheduler& GetScheduler() { return _scheduler; }
Creature* GetSummonedCreatureByEntry(uint32 entry); Creature* GetSummonedCreatureByEntry(uint32 entry);
void RegisterSummonedCreature(Creature* creature);
void UnregisterSummonedCreature(ObjectGuid guid);
void UnsummonCreatureByEntry(uint32 entry, uint32 ms = 0); void UnsummonCreatureByEntry(uint32 entry, uint32 ms = 0);
void GetFriendlyUnitListInRange(std::list<Unit*>& list, float fMaxSearchRange, bool exceptSelf = false) const; void GetFriendlyUnitListInRange(std::list<Unit*>& list, float fMaxSearchRange, bool exceptSelf = false) const;
void FollowTarget(Unit* target); void FollowTarget(Unit* target);
@@ -39,6 +39,7 @@
#include "Transport.h" #include "Transport.h"
#include "Vehicle.h" #include "Vehicle.h"
#include "WaypointDefines.h" #include "WaypointDefines.h"
#include "RaceMask.h"
#include "ZoneScript.h" #include "ZoneScript.h"
enum ExileReachHelpers enum ExileReachHelpers
@@ -131,7 +132,8 @@ enum ExileReachHelpers
SCENE_DEER_GO_UP = 2775, SCENE_DEER_GO_UP = 2775,
SCENE_HENRY_REUNION = 2717, SCENE_HENRY_REUNION = 2717,
SCENE_GRIMAXE_REUNION = 2905, SCENE_GRIMAXE_REUNION = 2905,
SCENE_REUNION = 2497, SCENE_REUNION = 2497, // spell 326678, Horde, The Re-Deather
SCENE_REUNION_ALLIANCE = 2341, // spell 305893, Alliance, Ride of the Scientifically Enhanced Boar
SCENE_OGRE_BEFORE_BIG_BOAR_ATTACK = 2932, SCENE_OGRE_BEFORE_BIG_BOAR_ATTACK = 2932,
SCENE_GORGROTHS_RITUAL_A = 2418, SCENE_GORGROTHS_RITUAL_A = 2418,
SCENE_GORGROTHS_RITUAL_H = 2496, SCENE_GORGROTHS_RITUAL_H = 2496,
@@ -48,7 +48,7 @@ public:
WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_15324 }, true); WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_15324 }, true);
WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_WONSA_STARVING }, !QuestRewarded(player, QUEST_H_COOKING_MEAT)); WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_WONSA_STARVING }, !QuestRewarded(player, QUEST_H_COOKING_MEAT));
WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_WONSA_EATEN }, QuestRewarded(player, QUEST_H_COOKING_MEAT)); WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_WONSA_EATEN }, QuestRewarded(player, QUEST_H_COOKING_MEAT));
WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_BREKA_PEACEFUL }, QuestCompletedOrRewarded(player, QUEST_H_FINDING_THE_LOST_EXPEDITION) && !player->GetSummonedCreatureByEntry(NPC_ABANDONED_CAMP_BREKA) && !player->GetSummonedCreatureByEntry(NPC_ABANDONED_CAMP_BREKA_WALKING) && !player->GetQuestStatus(QUEST_H_NORTHBOUND)); WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_BREKA_PEACEFUL }, QuestCompletedOrRewarded(player, QUEST_H_FINDING_THE_LOST_EXPEDITION) && !player->GetSummonedCreatureByEntry(NPC_ABANDONED_CAMP_BREKA) && !player->GetSummonedCreatureByEntry(NPC_ABANDONED_CAMP_BREKA_WALKING) && !player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_BREKA) && !player->GetQuestStatus(QUEST_H_NORTHBOUND));
WowCommunity::PhaseShift(player, { PHASE_HORDE_QUILBOAR_BRIARPATCH_MITHDRAN }, !QuestRewarded(player, QUEST_H_NORTHBOUND)); WowCommunity::PhaseShift(player, { PHASE_HORDE_QUILBOAR_BRIARPATCH_MITHDRAN }, !QuestRewarded(player, QUEST_H_NORTHBOUND));
} }
@@ -56,7 +56,7 @@ public:
{ {
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_ABANDONED_CAMP_ALARIA_STARVING }, !QuestRewarded(player, QUEST_COOKING_MEAT)); WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_ABANDONED_CAMP_ALARIA_STARVING }, !QuestRewarded(player, QUEST_COOKING_MEAT));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_ABANDONED_CAMP_ALARIA_EATEN }, QuestRewarded(player, QUEST_COOKING_MEAT)); WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_ABANDONED_CAMP_ALARIA_EATEN }, QuestRewarded(player, QUEST_COOKING_MEAT));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_ABANDONED_CAMP_GARRICK_PEACEFUL }, QuestRewarded(player, QUEST_FINDING_THE_LOST_EXPEDITION) && !player->GetSummonedCreatureByEntry(NPC_ABANDONED_CAMP_GARRICK) && !player->GetQuestStatus(QUEST_NORTHBOUND)); WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_ABANDONED_CAMP_GARRICK_PEACEFUL }, QuestCompletedOrRewarded(player, QUEST_FINDING_THE_LOST_EXPEDITION) && !player->GetSummonedCreatureByEntry(NPC_ABANDONED_CAMP_GARRICK) && !player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_GARRICK) && !player->GetQuestStatus(QUEST_NORTHBOUND));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_QUILBOAR_BRIARPATCH_AUSTIN }, !QuestRewarded(player, QUEST_NORTHBOUND)); WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_QUILBOAR_BRIARPATCH_AUSTIN }, !QuestRewarded(player, QUEST_NORTHBOUND));
} }
} }
@@ -70,7 +70,10 @@ public:
// Remove summons if player abandons or rewards a quest // Remove summons if player abandons or rewards a quest
if (player->GetMapId() == MAP_NPE) if (player->GetMapId() == MAP_NPE)
{ {
if (player->GetQuestStatus(questId) == QUEST_STATUS_NONE || player->GetQuestStatus(questId) == QUEST_STATUS_REWARDED) QuestStatus const status = player->GetQuestStatus(questId);
bool const escortDone = status == QUEST_STATUS_COMPLETE
&& (questId == QUEST_FINDING_THE_LOST_EXPEDITION || questId == QUEST_H_FINDING_THE_LOST_EXPEDITION);
if (status == QUEST_STATUS_NONE || status == QUEST_STATUS_REWARDED || escortDone)
{ {
std::vector<uint32> activeSummons; std::vector<uint32> activeSummons;
switch (questId) switch (questId)
@@ -173,12 +176,16 @@ struct npc_exiles_reach_abandoned_camp_166854_156607 : public ScriptedAI
void OnQuestReward(Player* player, Quest const* quest, LootItemType /*type*/, uint32 /*opt*/) override void OnQuestReward(Player* player, Quest const* quest, LootItemType /*type*/, uint32 /*opt*/) override
{ {
if (quest->GetQuestId() == QUEST_H_COOKING_MEAT && player->GetItemByEntry(ITEM_COOKED_MEAT)) if ((quest->GetQuestId() == QUEST_COOKING_MEAT || quest->GetQuestId() == QUEST_H_COOKING_MEAT) && player->GetItemByEntry(ITEM_COOKED_MEAT))
player->DestroyItemCount(ITEM_COOKED_MEAT, player->GetItemCount(ITEM_COOKED_MEAT), true, false); player->DestroyItemCount(ITEM_COOKED_MEAT, player->GetItemCount(ITEM_COOKED_MEAT), true, false);
if (quest->GetQuestId() == QUEST_H_FINDING_THE_LOST_EXPEDITION) if (quest->GetQuestId() == QUEST_FINDING_THE_LOST_EXPEDITION || quest->GetQuestId() == QUEST_H_FINDING_THE_LOST_EXPEDITION)
if (Creature* brekatemp = player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_BREKA)) {
brekatemp->DespawnOrUnsummon(); if (Creature* garrick = player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_GARRICK))
garrick->DespawnOrUnsummon();
if (Creature* breka = player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_BREKA))
breka->DespawnOrUnsummon();
}
me->CastSpell(player, SPELL_UPDATE_PHASESHIFT, true); me->CastSpell(player, SPELL_UPDATE_PHASESHIFT, true);
@@ -617,32 +624,31 @@ struct go_campfire_339769 : public GameObjectAI
{ {
uint32 const questId = player->IsInHorde() ? QUEST_H_COOKING_MEAT : QUEST_COOKING_MEAT; uint32 const questId = player->IsInHorde() ? QUEST_H_COOKING_MEAT : QUEST_COOKING_MEAT;
if (player->GetQuestStatus(questId) != QUEST_STATUS_INCOMPLETE) if (player->GetQuestStatus(questId) != QUEST_STATUS_INCOMPLETE)
return true; return false;
uint32 needRaw = 5; if (me->GetGOInfo()->GetLootId())
bool cookIsCriteria = false; return false;
if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
if (!quest)
return false;
bool handled = false;
for (QuestObjective const& obj : quest->GetObjectives())
{ {
for (QuestObjective const& obj : quest->GetObjectives()) if (obj.Type == QUEST_OBJECTIVE_ITEM && obj.ObjectID == ITEM_COOKED_MEAT)
{ {
if (obj.Type == QUEST_OBJECTIVE_ITEM && obj.ObjectID == ITEM_RAW_MEAT && obj.Amount > 0) player->AddItem(ITEM_COOKED_MEAT, 1);
needRaw = uint32(obj.Amount); handled = true;
if (obj.Type == QUEST_OBJECTIVE_CRITERIA_TREE || obj.Type == QUEST_OBJECTIVE_GAMEOBJECT) }
cookIsCriteria = true; else if (obj.Type == QUEST_OBJECTIVE_GAMEOBJECT && uint32(obj.ObjectID) == me->GetEntry())
{
player->KillCreditGO(me->GetEntry(), me->GetGUID());
handled = true;
} }
} }
if (player->GetItemCount(ITEM_RAW_MEAT) < needRaw) return handled;
return true;
player->KillCreditGO(me->GetEntry(), me->GetGUID());
if (cookIsCriteria)
CreditCriteriaTreeObjectives(player, questId);
if (!player->HasItemCount(ITEM_COOKED_MEAT))
player->AddItem(ITEM_COOKED_MEAT, 1);
return true;
} }
}; };
@@ -190,7 +190,8 @@ struct npc_exiles_reach_shore_166782_156626 : public ScriptedAI
std::list<Creature*> nearbyCreatures; std::list<Creature*> nearbyCreatures;
player->GetCreatureListInGrid(nearbyCreatures, 200.f); player->GetCreatureListInGrid(nearbyCreatures, 200.f);
if (Creature* captainClone = player->SummonCreature(me->GetEntry(), me->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID())) // Personal clone replaces the world copy for this player. A plain summon left both visible.
if (Creature* captainClone = me->SummonPersonalClone(me->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player))
{ {
for (Creature* subactor : nearbyCreatures) for (Creature* subactor : nearbyCreatures)
{ {
@@ -206,10 +207,8 @@ struct npc_exiles_reach_shore_166782_156626 : public ScriptedAI
case NPC_MURLOC_HIDEAWAY_JINHAKE: case NPC_MURLOC_HIDEAWAY_JINHAKE:
case NPC_MURLOC_HIDEAWAY_COLE: case NPC_MURLOC_HIDEAWAY_COLE:
case NPC_MURLOC_HIDEAWAY_RICHTER: case NPC_MURLOC_HIDEAWAY_RICHTER:
if (Creature* clone = player->SummonCreature(subactor->GetEntry(), subactor->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID())) if (Creature* clone = subactor->SummonPersonalClone(subactor->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player))
{ {
PhasingHandler::InheritPhaseShift(clone, player);
if (clone->GetEntry() == NPC_MURLOC_HIDEAWAY_COLE || clone->GetEntry() == NPC_MURLOC_HIDEAWAY_THROG) if (clone->GetEntry() == NPC_MURLOC_HIDEAWAY_COLE || clone->GetEntry() == NPC_MURLOC_HIDEAWAY_THROG)
captainClone->m_Events.AddEventAtOffset(new FirstAidEvent(captainClone, clone), 2s); captainClone->m_Events.AddEventAtOffset(new FirstAidEvent(captainClone, clone), 2s);
@@ -240,7 +239,7 @@ struct npc_exiles_reach_shore_166782_156626 : public ScriptedAI
case NPC_MURLOC_HIDEAWAY_KEELA_2: case NPC_MURLOC_HIDEAWAY_KEELA_2:
case NPC_MURLOC_HIDEAWAY_AUSTIN_2: case NPC_MURLOC_HIDEAWAY_AUSTIN_2:
case NPC_MURLOC_HIDEAWAY_BJORN_2: case NPC_MURLOC_HIDEAWAY_BJORN_2:
if (Creature* clone = player->SummonCreature(buddy->GetEntry(), buddy->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID())) if (Creature* clone = buddy->SummonPersonalClone(buddy->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player))
{ {
clone->SetStandState(UNIT_STAND_STATE_STAND); clone->SetStandState(UNIT_STAND_STATE_STAND);
clone->m_Events.AddEventAtOffset(new DelayedMoveEvent(player, clone, Position(-385.65f, -2594.42f, 3.2135f), 0, false, true), 3s); clone->m_Events.AddEventAtOffset(new DelayedMoveEvent(player, clone, Position(-385.65f, -2594.42f, 3.2135f), 0, false, true), 3s);
@@ -248,10 +247,9 @@ struct npc_exiles_reach_shore_166782_156626 : public ScriptedAI
break; break;
} }
} }
if (Creature* clone = player->SummonCreature(me->GetEntry(), me->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID())) if (Creature* clone = me->SummonPersonalClone(me->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player))
{ {
clone->CastSpell(player, SPELL_UPDATE_PHASESHIFT); clone->CastSpell(player, SPELL_UPDATE_PHASESHIFT);
PhasingHandler::InheritPhaseShift(clone, player);
clone->FollowTarget(player); clone->FollowTarget(player);
PlayExileConversation(player, player->IsInAlliance() ? CONVERSATION_ESCORT_SURVIVOR_A : CONVERSATION_ESCORT_SURVIVOR_H); PlayExileConversation(player, player->IsInAlliance() ? CONVERSATION_ESCORT_SURVIVOR_A : CONVERSATION_ESCORT_SURVIVOR_H);
@@ -34,7 +34,35 @@ public:
{ {
if (player->GetMapId() == MAP_EXILES_REACH) if (player->GetMapId() == MAP_EXILES_REACH)
{ {
switch (player->GetAreaId()) uint32 const area = player->GetAreaId();
if (area != AREA_NORTH_SEA_A && area != AREA_NORTH_SEA_H)
{
// The deck phases are only updated while the player is still on the ship.
// Leaving them on shows Jaina (and the Horde officers) a second time on the beach.
uint32 const shipPhases[] =
{
PHASE_GENERAL_SHIP,
PHASE_ALLIANCE_SHIP_CREW_OUTSIDE,
PHASE_ALLIANCE_SHIP_COLE,
PHASE_ALLIANCE_SHIP_GARRICK_1,
PHASE_ALLIANCE_SHIP_13619,
PHASE_ALLIANCE_SHIP_14350,
PHASE_ALLIANCE_SHIP_13454,
PHASE_ALLIANCE_SHIP_GARRICK_2,
PHASE_ALLIANCE_SHIP_CREW_INSIDE,
PHASE_HORDE_SHIP_THROG,
PHASE_HORDE_SHIP_15514,
PHASE_HORDE_SHIP_15287,
PHASE_HORDE_SHIP_15516,
};
for (uint32 phaseId : shipPhases)
if (player->GetPhaseShift().HasPhase(phaseId))
PhasingHandler::RemovePhase(player, phaseId, true);
return;
}
switch (area)
{ {
case AREA_NORTH_SEA_H: case AREA_NORTH_SEA_H:
{ {
@@ -35,7 +35,7 @@ public:
return; return;
// tele to the scene position after reunion scene // tele to the scene position after reunion scene
if (sceneTemplate->SceneId == SCENE_REUNION) if (sceneTemplate->SceneId == SCENE_REUNION || sceneTemplate->SceneId == SCENE_REUNION_ALLIANCE)
{ {
player->CastSpell(player, SPELL_TELEPORT_AFTER_REUNION_SCENE, true); player->CastSpell(player, SPELL_TELEPORT_AFTER_REUNION_SCENE, true);
} }
@@ -125,6 +125,15 @@ public:
// Remove summons if player abandons or rewards a quest // Remove summons if player abandons or rewards a quest
if (player->GetMapId() == MAP_NPE) if (player->GetMapId() == MAP_NPE)
{ {
if (player->GetQuestStatus(questId) == QUEST_STATUS_REWARDED)
{
// Reunion (DNT). The spell aura plays the scene; the ship movies are a different packet.
if (questId == QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR)
player->CastSpell(player, SPELL_REUNION_SCENE_A, true);
else if (questId == QUEST_H_THE_REDEATHER)
player->CastSpell(player, SPELL_REUNION_SCENE_H, true);
}
if (player->GetQuestStatus(questId) == QUEST_STATUS_NONE || player->GetQuestStatus(questId) == QUEST_STATUS_REWARDED) if (player->GetQuestStatus(questId) == QUEST_STATUS_NONE || player->GetQuestStatus(questId) == QUEST_STATUS_REWARDED)
{ {
std::vector<uint32> activeSummons; std::vector<uint32> activeSummons;