diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/AI/CreatureAI.h | 4 | ||||
-rw-r--r-- | src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp | 21 | ||||
-rw-r--r-- | src/server/game/AI/ScriptedAI/ScriptedEscortAI.h | 3 | ||||
-rw-r--r-- | src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp | 140 | ||||
-rw-r--r-- | src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h | 27 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.h | 2 | ||||
-rw-r--r-- | src/server/game/Maps/Map.cpp | 2 | ||||
-rw-r--r-- | src/server/scripts/Kalimdor/zone_darkshore.cpp | 2 | ||||
-rw-r--r-- | src/server/scripts/Kalimdor/zone_tanaris.cpp | 9 | ||||
-rw-r--r-- | src/server/scripts/Kalimdor/zone_ungoro_crater.cpp | 2 |
11 files changed, 73 insertions, 145 deletions
diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index 1d3f7736d17..ea021f44347 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -146,6 +146,7 @@ class TC_GAME_API CreatureAI : public UnitAI virtual void SpellHitTarget(Unit* /*target*/, SpellInfo const* /*spellInfo*/) { } virtual void SpellHitTargetGameObject(GameObject* /*target*/, SpellInfo const* /*spellInfo*/) { } + // Should return true if the NPC is currently being escorted virtual bool IsEscorted() const { return false; } // Called when creature appears in the world (spawn, respawn, grid load etc...) @@ -228,9 +229,6 @@ class TC_GAME_API CreatureAI : public UnitAI // If a PlayerAI* is returned, that AI is placed on the player instead of the default charm AI // Object destruction is handled by Unit::RemoveCharmedBy virtual PlayerAI* GetAIForCharmedPlayer(Player* /*who*/) { return nullptr; } - // Should return true if the NPC is target of an escort quest - // If onlyIfActive is set, should return true only if the escort quest is currently active - virtual bool IsEscortNPC(bool /*onlyIfActive*/) const { return false; } // intended for encounter design/debugging. do not use for other purposes. expensive. int32 VisualizeBoundary(uint32 duration, Unit* owner = nullptr, bool fill = false) const; diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp index cd42ffa5157..d591450f4f6 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp @@ -283,14 +283,8 @@ void EscortAI::Start(bool isActiveAttacker /* = true*/, bool run /* = false */, { if (CreatureData const* cdata = me->GetCreatureData()) { - if (SpawnGroupTemplateData const* groupdata = cdata->spawnGroupData) - { - if (sWorld->getBoolConfig(CONFIG_RESPAWN_DYNAMIC_ESCORTNPC) && (groupdata->flags & SPAWNGROUP_FLAG_ESCORTQUESTNPC) && !map->GetCreatureRespawnTime(me->GetSpawnId())) - { - me->SetRespawnTime(me->GetRespawnDelay()); - me->SaveRespawnTime(); - } - } + if (sWorld->getBoolConfig(CONFIG_RESPAWN_DYNAMIC_ESCORTNPC) && (cdata->spawnGroupData->flags & SPAWNGROUP_FLAG_ESCORTQUESTNPC)) + me->SaveRespawnTime(me->GetRespawnDelay()); } } @@ -378,17 +372,6 @@ void EscortAI::SetEscortPaused(bool on) } } -bool EscortAI::IsEscortNPC(bool onlyIfActive) const -{ - if (!onlyIfActive) - return true; - - if (GetEventStarterGUID()) - return true; - - return false; -} - Player* EscortAI::GetPlayerForEscort() { return ObjectAccessor::GetPlayer(*me, _playerGUID); diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h index d24c94bfb78..5da71eecccb 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.h @@ -56,7 +56,7 @@ struct TC_GAME_API EscortAI : public ScriptedAI void SetEscortPaused(bool on); void SetPauseTimer(uint32 Timer) { _pauseTimer = Timer; } bool HasEscortState(uint32 escortState) { return (_escortState & escortState) != 0; } - virtual bool IsEscorted() const override { return (_escortState & STATE_ESCORT_ESCORTING); } + bool IsEscorted() const override { return !_playerGUID.IsEmpty(); } void SetMaxPlayerDistance(float newMax) { _maxPlayerDistance = newMax; } float GetMaxPlayerDistance() const { return _maxPlayerDistance; } void SetDespawnAtEnd(bool despawn) { _despawnAtEnd = despawn; } @@ -64,7 +64,6 @@ struct TC_GAME_API EscortAI : public ScriptedAI bool IsActiveAttacker() const { return _activeAttacker; } // obsolete void SetActiveAttacker(bool enable) { _activeAttacker = enable; } ObjectGuid GetEventStarterGUID() const { return _playerGUID; } - virtual bool IsEscortNPC(bool isEscorting) const override; protected: Player* GetPlayerForEscort(); diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp index 6d9c9d6fe69..73fdf3af997 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp @@ -32,37 +32,11 @@ enum Points POINT_COMBAT_START = 0xFFFFFF }; -FollowerAI::FollowerAI(Creature* creature) : ScriptedAI(creature), _updateFollowTimer(2500), _followState(STATE_FOLLOW_NONE), _questForFollow(nullptr) { } - -void FollowerAI::MovementInform(uint32 type, uint32 id) -{ - if (type != POINT_MOTION_TYPE || !HasFollowState(STATE_FOLLOW_INPROGRESS)) - return; - - if (id == POINT_COMBAT_START) - { - if (GetLeaderForFollower()) - { - if (!HasFollowState(STATE_FOLLOW_PAUSED)) - AddFollowState(STATE_FOLLOW_RETURNING); - } - else - me->DespawnOrUnsummon(); - } -} - -void FollowerAI::AttackStart(Unit* who) -{ - ScriptedAI::AttackStart(who); -} +FollowerAI::FollowerAI(Creature* creature) : ScriptedAI(creature), _updateFollowTimer(2500), _followState(STATE_FOLLOW_NONE), _questForFollow(0) { } void FollowerAI::MoveInLineOfSight(Unit* who) { - // TODO: what in the world is this? - if (me->HasReactState(REACT_AGGRESSIVE) && !me->HasUnitState(UNIT_STATE_STUNNED) && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(me)) - return; - - if (HasFollowState(STATE_FOLLOW_INPROGRESS) && AssistPlayerInCombatAgainst(who)) + if (HasFollowState(STATE_FOLLOW_INPROGRESS) && !ShouldAssistPlayerInCombatAgainst(who)) return; ScriptedAI::MoveInLineOfSight(who); @@ -81,53 +55,32 @@ void FollowerAI::JustDied(Unit* /*killer*/) for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next()) if (Player* member = groupRef->GetSource()) if (member->IsInMap(player)) - member->FailQuest(_questForFollow->GetQuestId()); + member->FailQuest(_questForFollow); } else - player->FailQuest(_questForFollow->GetQuestId()); + player->FailQuest(_questForFollow); } } -void FollowerAI::JustAppeared() -{ - _followState = STATE_FOLLOW_NONE; - - if (!IsCombatMovementAllowed()) - SetCombatMovement(true); - - if (me->GetFaction() != me->GetCreatureTemplate()->faction) - me->SetFaction(me->GetCreatureTemplate()->faction); - - Reset(); -} - -void FollowerAI::EnterEvadeMode(EvadeReason /*why*/) +void FollowerAI::JustReachedHome() { - if (!me->IsAlive()) - { - EngagementOver(); + if (!HasFollowState(STATE_FOLLOW_INPROGRESS)) return; - } - - me->RemoveAllAuras(); - me->CombatStop(true); - me->SetLootRecipient(nullptr); - me->SetCannotReachTarget(false); - me->DoNotReacquireTarget(); - - EngagementOver(); - if (HasFollowState(STATE_FOLLOW_INPROGRESS)) + if (Player* player = GetLeaderForFollower()) { - TC_LOG_DEBUG("scripts.ai.followerai", "FollowerAI::EnterEvadeMode: left combat, returning to CombatStartPosition. (%s)", me->GetGUID().ToString().c_str()); - - if (me->HasUnitState(UNIT_STATE_CHASE)) - me->GetMotionMaster()->Remove(CHASE_MOTION_TYPE); + if (HasFollowState(STATE_FOLLOW_PAUSED)) + return; + me->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); } else - me->GetMotionMaster()->MoveTargetedHome(); + me->DespawnOrUnsummon(); +} - Reset(); +void FollowerAI::OwnerAttackedBy(Unit* other) +{ + if (!me->HasReactState(REACT_PASSIVE) && ShouldAssistPlayerInCombatAgainst(other)) + me->EngageWithTarget(other); } void FollowerAI::UpdateAI(uint32 uiDiff) @@ -144,27 +97,23 @@ void FollowerAI::UpdateAI(uint32 uiDiff) } bool maxRangeExceeded = true; - + bool questAbandoned = (_questForFollow != 0); if (Player* player = GetLeaderForFollower()) { - if (HasFollowState(STATE_FOLLOW_RETURNING)) - { - TC_LOG_DEBUG("scripts.ai.followerai", "FollowerAI::UpdateAI: is returning to leader. (%s)", me->GetGUID().ToString().c_str()); - - RemoveFollowState(STATE_FOLLOW_RETURNING); - me->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); - return; - } - if (Group* group = player->GetGroup()) { - for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next()) + for (GroupReference* groupRef = group->GetFirstMember(); groupRef && (maxRangeExceeded || questAbandoned); groupRef = groupRef->next()) { Player* member = groupRef->GetSource(); - if (member && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE)) - { + if (!member) + continue; + if (maxRangeExceeded && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE)) maxRangeExceeded = false; - break; + if (questAbandoned) + { + QuestStatus status = member->GetQuestStatus(_questForFollow); + if ((status == QUEST_STATUS_COMPLETE) || (status == QUEST_STATUS_INCOMPLETE)) + questAbandoned = false; } } } @@ -172,10 +121,16 @@ void FollowerAI::UpdateAI(uint32 uiDiff) { if (me->IsWithinDistInMap(player, MAX_PLAYER_DISTANCE)) maxRangeExceeded = false; + if (questAbandoned) + { + QuestStatus status = player->GetQuestStatus(_questForFollow); + if ((status == QUEST_STATUS_COMPLETE) || (status == QUEST_STATUS_INCOMPLETE)) + questAbandoned = false; + } } } - if (maxRangeExceeded) + if (maxRangeExceeded || questAbandoned) { TC_LOG_DEBUG("scripts.ai.followerai", "FollowerAI::UpdateAI: failed because player/group was to far away or not found (%s)", me->GetGUID().ToString().c_str()); me->DespawnOrUnsummon(); @@ -199,8 +154,17 @@ void FollowerAI::UpdateFollowerAI(uint32 /*uiDiff*/) DoMeleeAttackIfReady(); } -void FollowerAI::StartFollow(Player* player, uint32 factionForFollower, Quest const* quest) +void FollowerAI::StartFollow(Player* player, uint32 factionForFollower, uint32 quest) { + if (Map* map = me->GetMap()) + { + if (CreatureData const* cdata = me->GetCreatureData()) + { + if (sWorld->getBoolConfig(CONFIG_RESPAWN_DYNAMIC_ESCORTNPC) && (cdata->spawnGroupData->flags & SPAWNGROUP_FLAG_ESCORTQUESTNPC)) + me->SaveRespawnTime(me->GetRespawnDelay()); + } + } + if (me->IsEngaged()) { TC_LOG_DEBUG("scripts.ai.followerai", "FollowerAI::StartFollow: attempt to StartFollow while in combat. (%s)", me->GetGUID().ToString().c_str()); @@ -301,22 +265,15 @@ Player* FollowerAI::GetLeaderForFollower() // This part provides assistance to a player that are attacked by who, even if out of normal aggro range // It will cause me to attack who that are attacking _any_ player (which has been confirmed may happen also on offi) // The flag (type_flag) is unconfirmed, but used here for further research and is a good candidate. -bool FollowerAI::AssistPlayerInCombatAgainst(Unit* who) +bool FollowerAI::ShouldAssistPlayerInCombatAgainst(Unit* who) const { if (!who || !who->GetVictim()) return false; - if (me->HasReactState(REACT_PASSIVE)) - return false; - // experimental (unknown) flag not present if (!(me->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_CAN_ASSIST)) return false; - // not a player - if (!who->EnsureVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()) - return false; - if (!who->isInAccessiblePlaceFor(me)) return false; @@ -336,11 +293,8 @@ bool FollowerAI::AssistPlayerInCombatAgainst(Unit* who) return false; // too far away and no free sight - if (me->IsWithinDistInMap(who, MAX_PLAYER_DISTANCE) && me->IsWithinLOSInMap(who)) - { - me->EngageWithTarget(who); - return true; - } + if (!me->IsWithinDistInMap(who, MAX_PLAYER_DISTANCE) || !me->IsWithinLOSInMap(who)) + return false; - return false; + return true; } diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h index f099caefe39..52b56d83934 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.h @@ -27,11 +27,10 @@ enum FollowerState : uint32 { STATE_FOLLOW_NONE = 0x000, STATE_FOLLOW_INPROGRESS = 0x001, // must always have this state for any follow - STATE_FOLLOW_RETURNING = 0x002, // when returning to combat start after being in combat - STATE_FOLLOW_PAUSED = 0x004, // disables following - STATE_FOLLOW_COMPLETE = 0x008, // follow is completed and may end - STATE_FOLLOW_PREEVENT = 0x010, // not implemented (allow pre event to run, before follow is initiated) - STATE_FOLLOW_POSTEVENT = 0x020 // can be set at complete and allow post event to run + STATE_FOLLOW_PAUSED = 0x002, // disables following + STATE_FOLLOW_COMPLETE = 0x004, // follow is completed and may end + STATE_FOLLOW_PREEVENT = 0x008, // not implemented (allow pre event to run, before follow is initiated) + STATE_FOLLOW_POSTEVENT = 0x010 // can be set at complete and allow post event to run }; class TC_GAME_API FollowerAI : public ScriptedAI @@ -40,24 +39,23 @@ class TC_GAME_API FollowerAI : public ScriptedAI explicit FollowerAI(Creature* creature); ~FollowerAI() { } - void MovementInform(uint32 type, uint32 id) override; - void AttackStart(Unit*) override; void MoveInLineOfSight(Unit*) override; - void EnterEvadeMode(EvadeReason /*why*/ = EVADE_REASON_OTHER) override; void JustDied(Unit*) override; - void JustAppeared() override; + void JustReachedHome() override; + void OwnerAttackedBy(Unit* other) override; + // the "internal" update, calls UpdateFollowerAI() void UpdateAI(uint32) override; - // used when it's needed to add code in update (abilities, scripted events, etc) virtual void UpdateFollowerAI(uint32); - void StartFollow(Player* player, uint32 factionForFollower = 0, Quest const* quest = nullptr); + void StartFollow(Player* player, uint32 factionForFollower = 0, uint32 quest = 0); // if special event require follow mode to hold/resume during the follow void SetFollowPaused(bool paused); void SetFollowComplete(bool withEndEvent = false); - bool HasFollowState(uint32 uiFollowState) { return (_followState & uiFollowState) != 0; } + bool IsEscorted() const override { return HasFollowState(STATE_FOLLOW_INPROGRESS); } + bool HasFollowState(uint32 uiFollowState) const { return (_followState & uiFollowState) != 0; } protected: Player* GetLeaderForFollower(); @@ -65,13 +63,12 @@ class TC_GAME_API FollowerAI : public ScriptedAI private: void AddFollowState(uint32 followState) { _followState |= followState; } void RemoveFollowState(uint32 followState) { _followState &= ~followState; } - bool AssistPlayerInCombatAgainst(Unit* who); + bool ShouldAssistPlayerInCombatAgainst(Unit* who) const; ObjectGuid _leaderGUID; uint32 _updateFollowTimer; uint32 _followState; - - Quest const* _questForFollow; + uint32 _questForFollow; }; #endif diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 9457b8bfde7..6d708476b96 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -3285,10 +3285,10 @@ void Creature::AtDisengage() } } -bool Creature::IsEscortNPC(bool onlyIfActive) +bool Creature::IsEscorted() const { - if (CreatureAI* ai = AI()) - return ai->IsEscortNPC(onlyIfActive); + if (CreatureAI const* ai = AI()) + return ai->IsEscorted(); return false; } diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index e2016f09cc4..90f69dcb5a1 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -355,7 +355,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma CreatureTextRepeatIds GetTextRepeatGroup(uint8 textGroup); void SetTextRepeatId(uint8 textGroup, uint8 id); void ClearTextRepeatGroup(uint8 textGroup); - bool IsEscortNPC(bool onlyIfActive = true); + bool IsEscorted() const; bool CanGiveExperience() const; diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 78f8c2e1ed3..6abf49b81b0 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2964,7 +2964,7 @@ bool Map::CheckRespawn(RespawnInfo* info) if (!creature->IsAlive()) continue; // escort NPCs are allowed to respawn as long as all other instances are already escorting - if (isEscort && creature->IsEscortNPC(true)) + if (isEscort && creature->IsEscorted()) continue; doDelete = true; break; diff --git a/src/server/scripts/Kalimdor/zone_darkshore.cpp b/src/server/scripts/Kalimdor/zone_darkshore.cpp index 9ff9a03b3e1..f7c936fe873 100644 --- a/src/server/scripts/Kalimdor/zone_darkshore.cpp +++ b/src/server/scripts/Kalimdor/zone_darkshore.cpp @@ -161,7 +161,7 @@ public: { me->SetStandState(UNIT_STAND_STATE_STAND); Talk(SAY_KER_START, player); - StartFollow(player, FACTION_ESCORTEE_N_NEUTRAL_PASSIVE, quest); + StartFollow(player, FACTION_ESCORTEE_N_NEUTRAL_PASSIVE, QUEST_SLEEPER_AWAKENED); } } }; diff --git a/src/server/scripts/Kalimdor/zone_tanaris.cpp b/src/server/scripts/Kalimdor/zone_tanaris.cpp index 728aef81fef..97a2e31beba 100644 --- a/src/server/scripts/Kalimdor/zone_tanaris.cpp +++ b/src/server/scripts/Kalimdor/zone_tanaris.cpp @@ -326,7 +326,7 @@ public: if (me->IsWithinDistInMap(who, INTERACTION_DISTANCE)) { Player* player = GetLeaderForFollower(); - if (player && player->GetQuestStatus(QUEST_TOOGA) == QUEST_STATUS_INCOMPLETE) + if (player) player->GroupEventHappens(QUEST_TOOGA, me); TortaGUID = who->GetGUID(); @@ -339,10 +339,7 @@ public: { FollowerAI::MovementInform(MotionType, PointId); - if (MotionType != POINT_MOTION_TYPE) - return; - - if (PointId == POINT_ID_TO_WATER) + if ((MotionType == POINT_MOTION_TYPE) && (PointId == POINT_ID_TO_WATER)) SetFollowComplete(); } @@ -416,7 +413,7 @@ public: void QuestAccept(Player* player, Quest const* quest) override { if (quest->GetQuestId() == QUEST_TOOGA) - StartFollow(player, FACTION_ESCORTEE_N_NEUTRAL_PASSIVE, quest); + StartFollow(player, FACTION_ESCORTEE_N_NEUTRAL_PASSIVE, QUEST_TOOGA); } }; diff --git a/src/server/scripts/Kalimdor/zone_ungoro_crater.cpp b/src/server/scripts/Kalimdor/zone_ungoro_crater.cpp index 41401fb8c7c..2e06e92f285 100644 --- a/src/server/scripts/Kalimdor/zone_ungoro_crater.cpp +++ b/src/server/scripts/Kalimdor/zone_ungoro_crater.cpp @@ -340,7 +340,7 @@ public: if (quest->GetQuestId() == QUEST_A_LITTLE_HELP) { me->SetStandState(UNIT_STAND_STATE_STAND); - StartFollow(player, FACTION_ESCORTEE_N_NEUTRAL_PASSIVE, quest); + StartFollow(player, FACTION_ESCORTEE_N_NEUTRAL_PASSIVE, QUEST_A_LITTLE_HELP); } } }; |