diff options
-rw-r--r-- | src/bindings/scripts/base/follower_ai.cpp | 92 | ||||
-rw-r--r-- | src/bindings/scripts/base/follower_ai.h | 25 | ||||
-rw-r--r-- | src/bindings/scripts/scripts/kalimdor/darkshore.cpp | 75 | ||||
-rw-r--r-- | src/bindings/scripts/scripts/kalimdor/tanaris.cpp | 6 | ||||
-rw-r--r-- | src/bindings/scripts/scripts/kalimdor/teldrassil.cpp | 2 | ||||
-rw-r--r-- | src/bindings/scripts/scripts/kalimdor/ungoro_crater.cpp | 4 | ||||
-rw-r--r-- | src/bindings/scripts/scripts/world/guards.cpp | 1 |
7 files changed, 163 insertions, 42 deletions
diff --git a/src/bindings/scripts/base/follower_ai.cpp b/src/bindings/scripts/base/follower_ai.cpp index b44b22a31be..9f362cc67af 100644 --- a/src/bindings/scripts/base/follower_ai.cpp +++ b/src/bindings/scripts/base/follower_ai.cpp @@ -23,10 +23,7 @@ FollowerAI::FollowerAI(Creature* pCreature) : ScriptedAI(pCreature), m_uiLeaderGUID(0), m_pQuestForFollow(NULL), m_uiUpdateFollowTimer(2500), - m_bIsFollowing(false), - m_bIsReturnToLeader(false), - m_bIsFollowComplete(false), - m_bIsEndEvent(false) + m_uiFollowState(STATE_FOLLOW_NONE) {} void FollowerAI::AttackStart(Unit* pWho) @@ -60,14 +57,21 @@ void FollowerAI::MoveInLineOfSight(Unit* pWho) //It will cause m_creature to attack pWho 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. if (m_creature->hasUnitState(UNIT_STAT_FOLLOW) && - m_creature->GetCreatureInfo()->type_flags & 0x01000 && + m_creature->GetCreatureInfo()->type_flags & CREATURE_TYPEFLAGS_UNK13 && pWho->getVictim() && pWho->getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself() && m_creature->IsWithinDistInMap(pWho, MAX_PLAYER_DISTANCE) && m_creature->IsWithinLOSInMap(pWho)) { - pWho->RemoveAurasDueToSpell(SPELL_AURA_MOD_STEALTH); - AttackStart(pWho); + if (!m_creature->getVictim()) + { + AttackStart(pWho); + } + else + { + pWho->SetInCombatWith(m_creature); + m_creature->AddThreat(pWho, 0.0f); + } } else { @@ -91,7 +95,7 @@ void FollowerAI::MoveInLineOfSight(Unit* pWho) void FollowerAI::JustDied(Unit* pKiller) { - if (!m_bIsFollowing || !m_uiLeaderGUID || !m_pQuestForFollow) + if (!HasFollowState(STATE_FOLLOW_INPROGRESS) || !m_uiLeaderGUID || !m_pQuestForFollow) return; //TODO: need a better check for quests with time limit. @@ -118,10 +122,7 @@ void FollowerAI::JustDied(Unit* pKiller) void FollowerAI::JustRespawned() { - m_bIsFollowing = false; - m_bIsReturnToLeader = false; - m_bIsFollowComplete = false; - m_bIsEndEvent = false; + m_uiFollowState = STATE_FOLLOW_NONE; if (!IsCombatMovement()) SetCombatMovement(true); @@ -139,7 +140,7 @@ void FollowerAI::EnterEvadeMode() m_creature->CombatStop(true); m_creature->SetLootRecipient(NULL); - if (m_bIsFollowing) + if (HasFollowState(STATE_FOLLOW_INPROGRESS)) { debug_log("TSCR: FollowerAI left combat, returning to CombatStartPosition."); @@ -161,11 +162,13 @@ void FollowerAI::EnterEvadeMode() void FollowerAI::UpdateAI(const uint32 uiDiff) { - if (m_bIsFollowing && !m_creature->getVictim()) + Unit* pUnit = m_creature->getVictim(); + + if (HasFollowState(STATE_FOLLOW_INPROGRESS) && !m_creature->getVictim()) { if (m_uiUpdateFollowTimer < uiDiff) { - if (m_bIsFollowComplete && !m_bIsEndEvent) + if (HasFollowState(STATE_FOLLOW_COMPLETE) && !HasFollowState(STATE_FOLLOW_POSTEVENT)) { debug_log("TSCR: FollowerAI is set completed, despawns."); m_creature->ForcedDespawn(); @@ -176,11 +179,12 @@ void FollowerAI::UpdateAI(const uint32 uiDiff) if (Player* pPlayer = GetLeaderForFollower()) { - if (m_bIsReturnToLeader) + if (HasFollowState(STATE_FOLLOW_RETURNING)) { debug_log("TSCR: FollowerAI is returning to leader."); + + RemoveFollowState(STATE_FOLLOW_RETURNING); m_creature->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); - m_bIsReturnToLeader = false; return; } @@ -230,13 +234,16 @@ void FollowerAI::UpdateFollowerAI(const uint32 uiDiff) void FollowerAI::MovementInform(uint32 uiMotionType, uint32 uiPointId) { - if (uiMotionType != POINT_MOTION_TYPE || !m_bIsFollowing) + if (uiMotionType != POINT_MOTION_TYPE || !HasFollowState(STATE_FOLLOW_INPROGRESS)) return; if (uiPointId == POINT_COMBAT_START) { if (GetLeaderForFollower()) - m_bIsReturnToLeader = true; + { + if (!HasFollowState(STATE_FOLLOW_PAUSED)) + AddFollowState(STATE_FOLLOW_RETURNING); + } else m_creature->ForcedDespawn(); } @@ -250,7 +257,7 @@ void FollowerAI::StartFollow(Player* pLeader, uint32 uiFactionForFollower, const return; } - if (m_bIsFollowing) + if (HasFollowState(STATE_FOLLOW_INPROGRESS)) { error_log("TSCR: FollowerAI attempt to StartFollow while already following."); return; @@ -273,9 +280,9 @@ void FollowerAI::StartFollow(Player* pLeader, uint32 uiFactionForFollower, const m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); - m_creature->GetMotionMaster()->MoveFollow(pLeader, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + AddFollowState(STATE_FOLLOW_INPROGRESS); - m_bIsFollowing = true; + m_creature->GetMotionMaster()->MoveFollow(pLeader, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); debug_log("TSCR: FollowerAI start follow %s (GUID %u)", pLeader->GetName(), m_uiLeaderGUID); } @@ -316,10 +323,45 @@ void FollowerAI::SetFollowComplete(bool bWithEndEvent) { m_creature->clearUnitState(UNIT_STAT_FOLLOW); - m_creature->GetMotionMaster()->MovementExpired(); + m_creature->StopMoving(); + m_creature->GetMotionMaster()->Clear(); m_creature->GetMotionMaster()->MoveIdle(); } - m_bIsEndEvent = bWithEndEvent; - m_bIsFollowComplete = true; + if (bWithEndEvent) + AddFollowState(STATE_FOLLOW_POSTEVENT); + else + { + if (HasFollowState(STATE_FOLLOW_POSTEVENT)) + RemoveFollowState(STATE_FOLLOW_POSTEVENT); + } + + AddFollowState(STATE_FOLLOW_COMPLETE); +} + +void FollowerAI::SetFollowPaused(bool bPaused) +{ + if (!HasFollowState(STATE_FOLLOW_INPROGRESS) || HasFollowState(STATE_FOLLOW_COMPLETE)) + return; + + if (bPaused) + { + AddFollowState(STATE_FOLLOW_PAUSED); + + if (m_creature->hasUnitState(UNIT_STAT_FOLLOW)) + { + m_creature->clearUnitState(UNIT_STAT_FOLLOW); + + m_creature->StopMoving(); + m_creature->GetMotionMaster()->Clear(); + m_creature->GetMotionMaster()->MoveIdle(); + } + } + else + { + RemoveFollowState(STATE_FOLLOW_PAUSED); + + if (Player* pLeader = GetLeaderForFollower()) + m_creature->GetMotionMaster()->MoveFollow(pLeader, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); + } } diff --git a/src/bindings/scripts/base/follower_ai.h b/src/bindings/scripts/base/follower_ai.h index 10ec5c9061e..1513cd4c49c 100644 --- a/src/bindings/scripts/base/follower_ai.h +++ b/src/bindings/scripts/base/follower_ai.h @@ -5,6 +5,17 @@ #ifndef SC_FOLLOWERAI_H #define SC_FOLLOWERAI_H +enum eFollowState +{ + 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 +}; + class TRINITY_DLL_DECL FollowerAI : public ScriptedAI { public: @@ -30,21 +41,21 @@ class TRINITY_DLL_DECL FollowerAI : public ScriptedAI void StartFollow(Player* pPlayer, uint32 uiFactionForFollower = 0, const Quest* pQuest = NULL); + void SetFollowPaused(bool bPaused); //if special event require follow mode to hold/resume during the follow + protected: + bool HasFollowState(uint32 uiFollowState) { return (m_uiFollowState & uiFollowState); } + void AddFollowState(uint32 uiFollowState) { m_uiFollowState |= uiFollowState; } + void RemoveFollowState(uint32 uiFollowState) { m_uiFollowState &= ~uiFollowState; } + void SetFollowComplete(bool bWithEndEvent = false); - bool IsFollowComplete() { return m_bIsFollowComplete; } - bool IsEndEventInProgress() { return m_bIsEndEvent; } Player* GetLeaderForFollower(); private: uint64 m_uiLeaderGUID; uint32 m_uiUpdateFollowTimer; - - bool m_bIsFollowing; - bool m_bIsReturnToLeader; - bool m_bIsFollowComplete; - bool m_bIsEndEvent; + uint32 m_uiFollowState; const Quest* m_pQuestForFollow; //normally we have a quest }; diff --git a/src/bindings/scripts/scripts/kalimdor/darkshore.cpp b/src/bindings/scripts/scripts/kalimdor/darkshore.cpp index 205d490bc81..4f799bd9e39 100644 --- a/src/bindings/scripts/scripts/kalimdor/darkshore.cpp +++ b/src/bindings/scripts/scripts/kalimdor/darkshore.cpp @@ -55,6 +55,7 @@ enum SAY_KER_END = -1000444, + SPELL_SLEEP_VISUAL = 25148, SPELL_AWAKEN = 17536, QUEST_SLEEPER_AWAKENED = 5321, NPC_LILADRIS = 11219, //attackers entries unknown @@ -66,17 +67,20 @@ struct TRINITY_DLL_DECL npc_kerlonianAI : public FollowerAI { npc_kerlonianAI(Creature* pCreature) : FollowerAI(pCreature) { } + uint32 m_uiFallAsleepTimer; + void Reset() { + m_uiFallAsleepTimer = urand(10000, 45000); } void MoveInLineOfSight(Unit *pWho) { FollowerAI::MoveInLineOfSight(pWho); - if (!m_creature->getVictim() && !IsFollowComplete() && pWho->GetEntry() == NPC_LILADRIS) + if (!m_creature->getVictim() && !HasFollowState(STATE_FOLLOW_COMPLETE) && pWho->GetEntry() == NPC_LILADRIS) { - if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE*2)) + if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE*5)) { if (Player* pPlayer = GetLeaderForFollower()) { @@ -90,6 +94,69 @@ struct TRINITY_DLL_DECL npc_kerlonianAI : public FollowerAI } } } + + void SpellHit(Unit* pCaster, const SpellEntry* pSpell) + { + if (HasFollowState(STATE_FOLLOW_INPROGRESS | STATE_FOLLOW_PAUSED) && pSpell->Id == SPELL_AWAKEN) + ClearSleeping(); + } + + void SetSleeping() + { + SetFollowPaused(true); + + switch(rand()%3) + { + case 0: DoScriptText(EMOTE_KER_SLEEP_1, m_creature); break; + case 1: DoScriptText(EMOTE_KER_SLEEP_2, m_creature); break; + case 2: DoScriptText(EMOTE_KER_SLEEP_3, m_creature); break; + } + + switch(rand()%4) + { + case 0: DoScriptText(SAY_KER_SLEEP_1, m_creature); break; + case 1: DoScriptText(SAY_KER_SLEEP_2, m_creature); break; + case 2: DoScriptText(SAY_KER_SLEEP_3, m_creature); break; + case 3: DoScriptText(SAY_KER_SLEEP_4, m_creature); break; + } + + m_creature->SetStandState(UNIT_STAND_STATE_SLEEP); + m_creature->CastSpell(m_creature, SPELL_SLEEP_VISUAL, false); + } + + void ClearSleeping() + { + m_creature->RemoveAurasDueToSpell(SPELL_SLEEP_VISUAL); + m_creature->SetStandState(UNIT_STAND_STATE_STAND); + + DoScriptText(EMOTE_KER_AWAKEN, m_creature); + + SetFollowPaused(false); + } + + void UpdateFollowerAI(const uint32 uiDiff) + { + if (!UpdateVictim()) + { + if (!HasFollowState(STATE_FOLLOW_INPROGRESS)) + return; + + if (!HasFollowState(STATE_FOLLOW_PAUSED)) + { + if (m_uiFallAsleepTimer < uiDiff) + { + SetSleeping(); + m_uiFallAsleepTimer = urand(25000, 90000); + } + else + m_uiFallAsleepTimer -= uiDiff; + } + + return; + } + + DoMeleeAttackIfReady(); + } }; CreatureAI* GetAI_npc_kerlonian(Creature* pCreature) @@ -104,7 +171,7 @@ bool QuestAccept_npc_kerlonian(Player* pPlayer, Creature* pCreature, const Quest if (npc_kerlonianAI* pKerlonianAI = CAST_AI(npc_kerlonianAI, pCreature->AI())) { pCreature->SetStandState(UNIT_STAND_STATE_STAND); - DoScriptText(SAY_KER_START, pCreature); + DoScriptText(SAY_KER_START, pCreature, pPlayer); pKerlonianAI->StartFollow(pPlayer, FACTION_KER_ESCORTEE, pQuest); } } @@ -264,7 +331,7 @@ struct TRINITY_DLL_DECL npc_threshwackonatorAI : public FollowerAI { FollowerAI::MoveInLineOfSight(pWho); - if (!m_creature->getVictim() && !IsFollowComplete() && pWho->GetEntry() == NPC_GELKAK) + if (!m_creature->getVictim() && !HasFollowState(STATE_FOLLOW_COMPLETE) && pWho->GetEntry() == NPC_GELKAK) { if (m_creature->IsWithinDistInMap(pWho, 10.0f)) { diff --git a/src/bindings/scripts/scripts/kalimdor/tanaris.cpp b/src/bindings/scripts/scripts/kalimdor/tanaris.cpp index bfc56c96cb3..3e5c3e4ac8b 100644 --- a/src/bindings/scripts/scripts/kalimdor/tanaris.cpp +++ b/src/bindings/scripts/scripts/kalimdor/tanaris.cpp @@ -479,7 +479,7 @@ struct TRINITY_DLL_DECL npc_toogaAI : public FollowerAI { FollowerAI::MoveInLineOfSight(pWho); - if (!m_creature->getVictim() && !IsFollowComplete() && !IsEndEventInProgress() && pWho->GetEntry() == NPC_TORTA) + if (!m_creature->getVictim() && !HasFollowState(STATE_FOLLOW_COMPLETE | STATE_FOLLOW_POSTEVENT) && pWho->GetEntry() == NPC_TORTA) { if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE)) { @@ -511,7 +511,7 @@ struct TRINITY_DLL_DECL npc_toogaAI : public FollowerAI if (!UpdateVictim()) { //we are doing the post-event, or... - if (IsEndEventInProgress()) + if (HasFollowState(STATE_FOLLOW_POSTEVENT)) { if (m_uiPostEventTimer < uiDiff) { @@ -553,7 +553,7 @@ struct TRINITY_DLL_DECL npc_toogaAI : public FollowerAI m_uiPostEventTimer -= uiDiff; } //...we are doing regular speech check - else if (!IsFollowComplete()) + else if (HasFollowState(STATE_FOLLOW_INPROGRESS)) { if (m_uiCheckSpeechTimer < uiDiff) { diff --git a/src/bindings/scripts/scripts/kalimdor/teldrassil.cpp b/src/bindings/scripts/scripts/kalimdor/teldrassil.cpp index cdd45826b4f..c5aee3248bf 100644 --- a/src/bindings/scripts/scripts/kalimdor/teldrassil.cpp +++ b/src/bindings/scripts/scripts/kalimdor/teldrassil.cpp @@ -51,7 +51,7 @@ struct TRINITY_DLL_DECL npc_mistAI : public FollowerAI { FollowerAI::MoveInLineOfSight(pWho); - if (!m_creature->getVictim() && !IsFollowComplete() && pWho->GetEntry() == NPC_ARYNIA) + if (!m_creature->getVictim() && !HasFollowState(STATE_FOLLOW_COMPLETE) && pWho->GetEntry() == NPC_ARYNIA) { if (m_creature->IsWithinDistInMap(pWho, 10.0f)) { diff --git a/src/bindings/scripts/scripts/kalimdor/ungoro_crater.cpp b/src/bindings/scripts/scripts/kalimdor/ungoro_crater.cpp index 957835bc9aa..8699023681a 100644 --- a/src/bindings/scripts/scripts/kalimdor/ungoro_crater.cpp +++ b/src/bindings/scripts/scripts/kalimdor/ungoro_crater.cpp @@ -189,7 +189,7 @@ struct TRINITY_DLL_DECL npc_ringoAI : public FollowerAI { FollowerAI::MoveInLineOfSight(pWho); - if (!m_creature->getVictim() && !IsFollowComplete() && pWho->GetEntry() == NPC_SPRAGGLE) + if (!m_creature->getVictim() && !HasFollowState(STATE_FOLLOW_COMPLETE) && pWho->GetEntry() == NPC_SPRAGGLE) { if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE)) { @@ -209,7 +209,7 @@ struct TRINITY_DLL_DECL npc_ringoAI : public FollowerAI { if (!UpdateVictim()) { - if (IsEndEventInProgress()) + if (HasFollowState(STATE_FOLLOW_POSTEVENT)) { if (m_uiEndEventTimer < uiDiff) { diff --git a/src/bindings/scripts/scripts/world/guards.cpp b/src/bindings/scripts/scripts/world/guards.cpp index fa5592f7c32..5c74e91369d 100644 --- a/src/bindings/scripts/scripts/world/guards.cpp +++ b/src/bindings/scripts/scripts/world/guards.cpp @@ -25,6 +25,7 @@ EndScriptData */ guard_azuremyst guard_bluffwatcher guard_contested +guard_dalaran guard_darnassus guard_dunmorogh guard_durotar |