aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bindings/scripts/base/follower_ai.cpp92
-rw-r--r--src/bindings/scripts/base/follower_ai.h25
-rw-r--r--src/bindings/scripts/scripts/kalimdor/darkshore.cpp75
-rw-r--r--src/bindings/scripts/scripts/kalimdor/tanaris.cpp6
-rw-r--r--src/bindings/scripts/scripts/kalimdor/teldrassil.cpp2
-rw-r--r--src/bindings/scripts/scripts/kalimdor/ungoro_crater.cpp4
-rw-r--r--src/bindings/scripts/scripts/world/guards.cpp1
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