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:
Kudlaty
2009-08-20 18:50:41 +02:00
parent c674463df4
commit f27fc3e939
7 changed files with 163 additions and 42 deletions

View File

@@ -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);
}
}

View File

@@ -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
};

View File

@@ -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))
{

View File

@@ -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)
{

View File

@@ -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))
{

View File

@@ -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)
{

View File

@@ -25,6 +25,7 @@ EndScriptData */
guard_azuremyst
guard_bluffwatcher
guard_contested
guard_dalaran
guard_darnassus
guard_dunmorogh
guard_durotar