Skip to content

Commit ed09f56

Browse files
author
NoFantasy
committed
[1355] Implement use of bitmask states instead of boolean variables in followerAI.
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. git-svn-id: https://scriptdev2.svn.sourceforge.net/svnroot/scriptdev2@1355 5f9c896b-1e26-0410-94da-f77f675e2462
1 parent 29fbe97 commit ed09f56

6 files changed

Lines changed: 162 additions & 42 deletions

File tree

base/follower_ai.cpp

Lines changed: 67 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@ FollowerAI::FollowerAI(Creature* pCreature) : ScriptedAI(pCreature),
2323
m_uiLeaderGUID(0),
2424
m_pQuestForFollow(NULL),
2525
m_uiUpdateFollowTimer(2500),
26-
m_bIsFollowing(false),
27-
m_bIsReturnToLeader(false),
28-
m_bIsFollowComplete(false),
29-
m_bIsEndEvent(false)
26+
m_uiFollowState(STATE_FOLLOW_NONE)
3027
{}
3128

3229
void FollowerAI::AttackStart(Unit* pWho)
@@ -60,14 +57,21 @@ void FollowerAI::MoveInLineOfSight(Unit* pWho)
6057
//It will cause m_creature to attack pWho that are attacking _any_ player (which has been confirmed may happen also on offi)
6158
//The flag (type_flag) is unconfirmed, but used here for further research and is a good candidate.
6259
if (m_creature->hasUnitState(UNIT_STAT_FOLLOW) &&
63-
m_creature->GetCreatureInfo()->type_flags & 0x01000 &&
60+
m_creature->GetCreatureInfo()->type_flags & CREATURE_TYPEFLAGS_UNK13 &&
6461
pWho->getVictim() &&
6562
pWho->getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself() &&
6663
m_creature->IsWithinDistInMap(pWho, MAX_PLAYER_DISTANCE) &&
6764
m_creature->IsWithinLOSInMap(pWho))
6865
{
69-
pWho->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
70-
AttackStart(pWho);
66+
if (!m_creature->getVictim())
67+
{
68+
AttackStart(pWho);
69+
}
70+
else
71+
{
72+
pWho->SetInCombatWith(m_creature);
73+
m_creature->AddThreat(pWho, 0.0f);
74+
}
7175
}
7276
else
7377
{
@@ -91,7 +95,7 @@ void FollowerAI::MoveInLineOfSight(Unit* pWho)
9195

9296
void FollowerAI::JustDied(Unit* pKiller)
9397
{
94-
if (!m_bIsFollowing || !m_uiLeaderGUID || !m_pQuestForFollow)
98+
if (!HasFollowState(STATE_FOLLOW_INPROGRESS) || !m_uiLeaderGUID || !m_pQuestForFollow)
9599
return;
96100

97101
//TODO: need a better check for quests with time limit.
@@ -118,10 +122,7 @@ void FollowerAI::JustDied(Unit* pKiller)
118122

119123
void FollowerAI::JustRespawned()
120124
{
121-
m_bIsFollowing = false;
122-
m_bIsReturnToLeader = false;
123-
m_bIsFollowComplete = false;
124-
m_bIsEndEvent = false;
125+
m_uiFollowState = STATE_FOLLOW_NONE;
125126

126127
if (!IsCombatMovement())
127128
SetCombatMovement(true);
@@ -139,7 +140,7 @@ void FollowerAI::EnterEvadeMode()
139140
m_creature->CombatStop(true);
140141
m_creature->SetLootRecipient(NULL);
141142

142-
if (m_bIsFollowing)
143+
if (HasFollowState(STATE_FOLLOW_INPROGRESS))
143144
{
144145
debug_log("SD2: FollowerAI left combat, returning to CombatStartPosition.");
145146

@@ -161,11 +162,13 @@ void FollowerAI::EnterEvadeMode()
161162

162163
void FollowerAI::UpdateAI(const uint32 uiDiff)
163164
{
164-
if (m_bIsFollowing && !m_creature->getVictim())
165+
Unit* pUnit = m_creature->getVictim();
166+
167+
if (HasFollowState(STATE_FOLLOW_INPROGRESS) && !m_creature->getVictim())
165168
{
166169
if (m_uiUpdateFollowTimer < uiDiff)
167170
{
168-
if (m_bIsFollowComplete && !m_bIsEndEvent)
171+
if (HasFollowState(STATE_FOLLOW_COMPLETE) && !HasFollowState(STATE_FOLLOW_POSTEVENT))
169172
{
170173
debug_log("SD2: FollowerAI is set completed, despawns.");
171174
m_creature->ForcedDespawn();
@@ -176,11 +179,12 @@ void FollowerAI::UpdateAI(const uint32 uiDiff)
176179

177180
if (Player* pPlayer = GetLeaderForFollower())
178181
{
179-
if (m_bIsReturnToLeader)
182+
if (HasFollowState(STATE_FOLLOW_RETURNING))
180183
{
181184
debug_log("SD2: FollowerAI is returning to leader.");
185+
186+
RemoveFollowState(STATE_FOLLOW_RETURNING);
182187
m_creature->GetMotionMaster()->MoveFollow(pPlayer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
183-
m_bIsReturnToLeader = false;
184188
return;
185189
}
186190

@@ -230,13 +234,16 @@ void FollowerAI::UpdateFollowerAI(const uint32 uiDiff)
230234

231235
void FollowerAI::MovementInform(uint32 uiMotionType, uint32 uiPointId)
232236
{
233-
if (uiMotionType != POINT_MOTION_TYPE || !m_bIsFollowing)
237+
if (uiMotionType != POINT_MOTION_TYPE || !HasFollowState(STATE_FOLLOW_INPROGRESS))
234238
return;
235239

236240
if (uiPointId == POINT_COMBAT_START)
237241
{
238242
if (GetLeaderForFollower())
239-
m_bIsReturnToLeader = true;
243+
{
244+
if (!HasFollowState(STATE_FOLLOW_PAUSED))
245+
AddFollowState(STATE_FOLLOW_RETURNING);
246+
}
240247
else
241248
m_creature->ForcedDespawn();
242249
}
@@ -250,7 +257,7 @@ void FollowerAI::StartFollow(Player* pLeader, uint32 uiFactionForFollower, const
250257
return;
251258
}
252259

253-
if (m_bIsFollowing)
260+
if (HasFollowState(STATE_FOLLOW_INPROGRESS))
254261
{
255262
error_log("SD2: FollowerAI attempt to StartFollow while already following.");
256263
return;
@@ -273,9 +280,9 @@ void FollowerAI::StartFollow(Player* pLeader, uint32 uiFactionForFollower, const
273280

274281
m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
275282

276-
m_creature->GetMotionMaster()->MoveFollow(pLeader, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
283+
AddFollowState(STATE_FOLLOW_INPROGRESS);
277284

278-
m_bIsFollowing = true;
285+
m_creature->GetMotionMaster()->MoveFollow(pLeader, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
279286

280287
debug_log("SD2: FollowerAI start follow %s (GUID %u)", pLeader->GetName(), m_uiLeaderGUID);
281288
}
@@ -316,10 +323,45 @@ void FollowerAI::SetFollowComplete(bool bWithEndEvent)
316323
{
317324
m_creature->clearUnitState(UNIT_STAT_FOLLOW);
318325

319-
m_creature->GetMotionMaster()->MovementExpired();
326+
m_creature->StopMoving();
327+
m_creature->GetMotionMaster()->Clear();
320328
m_creature->GetMotionMaster()->MoveIdle();
321329
}
322330

323-
m_bIsEndEvent = bWithEndEvent;
324-
m_bIsFollowComplete = true;
331+
if (bWithEndEvent)
332+
AddFollowState(STATE_FOLLOW_POSTEVENT);
333+
else
334+
{
335+
if (HasFollowState(STATE_FOLLOW_POSTEVENT))
336+
RemoveFollowState(STATE_FOLLOW_POSTEVENT);
337+
}
338+
339+
AddFollowState(STATE_FOLLOW_COMPLETE);
340+
}
341+
342+
void FollowerAI::SetFollowPaused(bool bPaused)
343+
{
344+
if (!HasFollowState(STATE_FOLLOW_INPROGRESS) || HasFollowState(STATE_FOLLOW_COMPLETE))
345+
return;
346+
347+
if (bPaused)
348+
{
349+
AddFollowState(STATE_FOLLOW_PAUSED);
350+
351+
if (m_creature->hasUnitState(UNIT_STAT_FOLLOW))
352+
{
353+
m_creature->clearUnitState(UNIT_STAT_FOLLOW);
354+
355+
m_creature->StopMoving();
356+
m_creature->GetMotionMaster()->Clear();
357+
m_creature->GetMotionMaster()->MoveIdle();
358+
}
359+
}
360+
else
361+
{
362+
RemoveFollowState(STATE_FOLLOW_PAUSED);
363+
364+
if (Player* pLeader = GetLeaderForFollower())
365+
m_creature->GetMotionMaster()->MoveFollow(pLeader, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
366+
}
325367
}

base/follower_ai.h

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@
55
#ifndef SC_FOLLOWERAI_H
66
#define SC_FOLLOWERAI_H
77

8+
enum eFollowState
9+
{
10+
STATE_FOLLOW_NONE = 0x000,
11+
STATE_FOLLOW_INPROGRESS = 0x001, //must always have this state for any follow
12+
STATE_FOLLOW_RETURNING = 0x002, //when returning to combat start after being in combat
13+
STATE_FOLLOW_PAUSED = 0x004, //disables following
14+
STATE_FOLLOW_COMPLETE = 0x008, //follow is completed and may end
15+
STATE_FOLLOW_PREEVENT = 0x010, //not implemented (allow pre event to run, before follow is initiated)
16+
STATE_FOLLOW_POSTEVENT = 0x020 //can be set at complete and allow post event to run
17+
};
18+
819
class MANGOS_DLL_DECL FollowerAI : public ScriptedAI
920
{
1021
public:
@@ -30,21 +41,21 @@ class MANGOS_DLL_DECL FollowerAI : public ScriptedAI
3041

3142
void StartFollow(Player* pPlayer, uint32 uiFactionForFollower = 0, const Quest* pQuest = NULL);
3243

44+
void SetFollowPaused(bool bPaused); //if special event require follow mode to hold/resume during the follow
45+
3346
protected:
47+
bool HasFollowState(uint32 uiFollowState) { return (m_uiFollowState & uiFollowState); }
48+
void AddFollowState(uint32 uiFollowState) { m_uiFollowState |= uiFollowState; }
49+
void RemoveFollowState(uint32 uiFollowState) { m_uiFollowState &= ~uiFollowState; }
50+
3451
void SetFollowComplete(bool bWithEndEvent = false);
35-
bool IsFollowComplete() { return m_bIsFollowComplete; }
36-
bool IsEndEventInProgress() { return m_bIsEndEvent; }
3752

3853
Player* GetLeaderForFollower();
3954

4055
private:
4156
uint64 m_uiLeaderGUID;
4257
uint32 m_uiUpdateFollowTimer;
43-
44-
bool m_bIsFollowing;
45-
bool m_bIsReturnToLeader;
46-
bool m_bIsFollowComplete;
47-
bool m_bIsEndEvent;
58+
uint32 m_uiFollowState;
4859

4960
const Quest* m_pQuestForFollow; //normally we have a quest
5061
};

scripts/kalimdor/darkshore.cpp

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ enum
5555

5656
SAY_KER_END = -1000444,
5757

58+
SPELL_SLEEP_VISUAL = 25148,
5859
SPELL_AWAKEN = 17536,
5960
QUEST_SLEEPER_AWAKENED = 5321,
6061
NPC_LILADRIS = 11219, //attackers entries unknown
@@ -66,17 +67,20 @@ struct MANGOS_DLL_DECL npc_kerlonianAI : public FollowerAI
6667
{
6768
npc_kerlonianAI(Creature* pCreature) : FollowerAI(pCreature) { Reset(); }
6869

70+
uint32 m_uiFallAsleepTimer;
71+
6972
void Reset()
7073
{
74+
m_uiFallAsleepTimer = urand(10000, 45000);
7175
}
7276

7377
void MoveInLineOfSight(Unit *pWho)
7478
{
7579
FollowerAI::MoveInLineOfSight(pWho);
7680

77-
if (!m_creature->getVictim() && !IsFollowComplete() && pWho->GetEntry() == NPC_LILADRIS)
81+
if (!m_creature->getVictim() && !HasFollowState(STATE_FOLLOW_COMPLETE) && pWho->GetEntry() == NPC_LILADRIS)
7882
{
79-
if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE*2))
83+
if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE*5))
8084
{
8185
if (Player* pPlayer = GetLeaderForFollower())
8286
{
@@ -90,6 +94,69 @@ struct MANGOS_DLL_DECL npc_kerlonianAI : public FollowerAI
9094
}
9195
}
9296
}
97+
98+
void SpellHit(Unit* pCaster, const SpellEntry* pSpell)
99+
{
100+
if (HasFollowState(STATE_FOLLOW_INPROGRESS | STATE_FOLLOW_PAUSED) && pSpell->Id == SPELL_AWAKEN)
101+
ClearSleeping();
102+
}
103+
104+
void SetSleeping()
105+
{
106+
SetFollowPaused(true);
107+
108+
switch(rand()%3)
109+
{
110+
case 0: DoScriptText(EMOTE_KER_SLEEP_1, m_creature); break;
111+
case 1: DoScriptText(EMOTE_KER_SLEEP_2, m_creature); break;
112+
case 2: DoScriptText(EMOTE_KER_SLEEP_3, m_creature); break;
113+
}
114+
115+
switch(rand()%4)
116+
{
117+
case 0: DoScriptText(SAY_KER_SLEEP_1, m_creature); break;
118+
case 1: DoScriptText(SAY_KER_SLEEP_2, m_creature); break;
119+
case 2: DoScriptText(SAY_KER_SLEEP_3, m_creature); break;
120+
case 3: DoScriptText(SAY_KER_SLEEP_4, m_creature); break;
121+
}
122+
123+
m_creature->SetStandState(UNIT_STAND_STATE_SLEEP);
124+
m_creature->CastSpell(m_creature, SPELL_SLEEP_VISUAL, false);
125+
}
126+
127+
void ClearSleeping()
128+
{
129+
m_creature->RemoveAurasDueToSpell(SPELL_SLEEP_VISUAL);
130+
m_creature->SetStandState(UNIT_STAND_STATE_STAND);
131+
132+
DoScriptText(EMOTE_KER_AWAKEN, m_creature);
133+
134+
SetFollowPaused(false);
135+
}
136+
137+
void UpdateFollowerAI(const uint32 uiDiff)
138+
{
139+
if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())
140+
{
141+
if (!HasFollowState(STATE_FOLLOW_INPROGRESS))
142+
return;
143+
144+
if (!HasFollowState(STATE_FOLLOW_PAUSED))
145+
{
146+
if (m_uiFallAsleepTimer < uiDiff)
147+
{
148+
SetSleeping();
149+
m_uiFallAsleepTimer = urand(25000, 90000);
150+
}
151+
else
152+
m_uiFallAsleepTimer -= uiDiff;
153+
}
154+
155+
return;
156+
}
157+
158+
DoMeleeAttackIfReady();
159+
}
93160
};
94161

95162
CreatureAI* GetAI_npc_kerlonian(Creature* pCreature)
@@ -104,7 +171,7 @@ bool QuestAccept_npc_kerlonian(Player* pPlayer, Creature* pCreature, const Quest
104171
if (npc_kerlonianAI* pKerlonianAI = dynamic_cast<npc_kerlonianAI*>(pCreature->AI()))
105172
{
106173
pCreature->SetStandState(UNIT_STAND_STATE_STAND);
107-
DoScriptText(SAY_KER_START, pCreature);
174+
DoScriptText(SAY_KER_START, pCreature, pPlayer);
108175
pKerlonianAI->StartFollow(pPlayer, FACTION_KER_ESCORTEE, pQuest);
109176
}
110177
}
@@ -264,7 +331,7 @@ struct MANGOS_DLL_DECL npc_threshwackonatorAI : public FollowerAI
264331
{
265332
FollowerAI::MoveInLineOfSight(pWho);
266333

267-
if (!m_creature->getVictim() && !IsFollowComplete() && pWho->GetEntry() == NPC_GELKAK)
334+
if (!m_creature->getVictim() && !HasFollowState(STATE_FOLLOW_COMPLETE) && pWho->GetEntry() == NPC_GELKAK)
268335
{
269336
if (m_creature->IsWithinDistInMap(pWho, 10.0f))
270337
{

scripts/kalimdor/tanaris.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ struct MANGOS_DLL_DECL npc_toogaAI : public FollowerAI
482482
{
483483
FollowerAI::MoveInLineOfSight(pWho);
484484

485-
if (!m_creature->getVictim() && !IsFollowComplete() && !IsEndEventInProgress() && pWho->GetEntry() == NPC_TORTA)
485+
if (!m_creature->getVictim() && !HasFollowState(STATE_FOLLOW_COMPLETE | STATE_FOLLOW_POSTEVENT) && pWho->GetEntry() == NPC_TORTA)
486486
{
487487
if (m_creature->IsWithinDistInMap(pWho, INTERACTION_DISTANCE))
488488
{
@@ -514,7 +514,7 @@ struct MANGOS_DLL_DECL npc_toogaAI : public FollowerAI
514514
if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())
515515
{
516516
//we are doing the post-event, or...
517-
if (IsEndEventInProgress())
517+
if (HasFollowState(STATE_FOLLOW_POSTEVENT))
518518
{
519519
if (m_uiPostEventTimer < uiDiff)
520520
{
@@ -556,7 +556,7 @@ struct MANGOS_DLL_DECL npc_toogaAI : public FollowerAI
556556
m_uiPostEventTimer -= uiDiff;
557557
}
558558
//...we are doing regular speech check
559-
else if (!IsFollowComplete())
559+
else if (HasFollowState(STATE_FOLLOW_INPROGRESS))
560560
{
561561
if (m_uiCheckSpeechTimer < uiDiff)
562562
{

scripts/kalimdor/teldrassil.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ struct MANGOS_DLL_DECL npc_mistAI : public FollowerAI
5151
{
5252
FollowerAI::MoveInLineOfSight(pWho);
5353

54-
if (!m_creature->getVictim() && !IsFollowComplete() && pWho->GetEntry() == NPC_ARYNIA)
54+
if (!m_creature->getVictim() && !HasFollowState(STATE_FOLLOW_COMPLETE) && pWho->GetEntry() == NPC_ARYNIA)
5555
{
5656
if (m_creature->IsWithinDistInMap(pWho, 10.0f))
5757
{

0 commit comments

Comments
 (0)