mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-24 02:46:33 +01:00
Merge [SD2]
r1355 Implement use of bitmask states instead of boolean variables in followerAI.
Add function SetFollowPaused to temporary disable follow, with true/false argument to toggle the state on/off.
Scripts affected are updated accordingly with needed changes.
--HG--
branch : trunk
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@ EndScriptData */
|
||||
guard_azuremyst
|
||||
guard_bluffwatcher
|
||||
guard_contested
|
||||
guard_dalaran
|
||||
guard_darnassus
|
||||
guard_dunmorogh
|
||||
guard_durotar
|
||||
|
||||
Reference in New Issue
Block a user