OregonCore  revision fb2a440-git
Your Favourite TBC server
CreatureAI.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "CreatureAI.h"
19 #include "CreatureAIImpl.h"
20 #include "Creature.h"
21 #include "World.h"
22 #include "SpellMgr.h"
23 #include "MapRefManager.h"
24 #include "Player.h"
25 
26 //Disable CreatureAI when charmed
28 {
29  me->NeedChangeAI = true;
30 
32  me->IsAIEnabled = !apply;
33 }
34 
37 {
38  return &CreatureAI::AISpellInfo[i];
39 }
40 
42 {
43  Map* map = me->GetMap();
44 
45  if (!map->IsDungeon())
46  {
47  sLog.outError("CreatureAI::DoZoneInCombatWithPlayers called on a map that is not an instance (creature entry = %u)", me->GetEntry());
48  return;
49  }
50 
51  if (!force)
52  {
54  {
55  error_log("CreatureAI::DoZoneInCombatWithPlayers called for a creature that either cannot have a threat list or has empty threat list (creature entry = %u)", me->GetEntry());
56  return;
57  }
58  }
59 
60  Map::PlayerList const &PlayerList = map->GetPlayers();
61  for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
62  {
63  if (Player* pPlayer = i->GetSource())
64  {
65  if (pPlayer->IsGameMaster())
66  continue;
67 
68  if (pPlayer->IsAlive())
69  {
70  me->SetInCombatWith(pPlayer);
71  pPlayer->SetInCombatWith(me);
72  me->AddThreat(pPlayer, 0.0f);
73  }
74  }
75  }
76 }
77 
78 void CreatureAI::DoZoneInCombat(Creature* creature /*= NULL*/, float maxRangeToNearestTarget /* = 50.0f*/)
79 {
80  if (!creature)
81  creature = me;
82 
83  if (!creature->CanHaveThreatList())
84  return;
85 
86  Map* map = creature->GetMap();
87  if (!map->IsDungeon()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated
88  {
89  sLog.outError("DoZoneInCombat call for map that isn't an instance (creature entry = %d)", creature->GetTypeId() == TYPEID_UNIT ? creature->ToCreature()->GetEntry() : 0);
90  return;
91  }
92 
93  if (!creature->HasReactState(REACT_PASSIVE) && !creature->GetVictim())
94  {
95  if (Unit* nearTarget = creature->SelectNearestTarget(maxRangeToNearestTarget))
96  creature->AI()->AttackStart(nearTarget);
97  else if (creature->IsSummon())
98  {
99  if (Unit* summoner = ((TempSummon*)creature)->GetSummoner())
100  {
101  Unit* target = summoner->getAttackerForHelper();
102  if (!target && summoner->CanHaveThreatList() && !summoner->getThreatManager().isThreatListEmpty())
103  target = summoner->getThreatManager().getHostileTarget();
104  if (target && (creature->IsFriendlyTo(summoner) || creature->IsHostileTo(target)))
105  creature->AI()->AttackStart(target);
106  }
107  }
108  }
109 
110  // Intended duplicated check, the code above this should select a victim
111  // If it can't find a suitable attack target then we should error out.
112  if (!creature->HasReactState(REACT_PASSIVE) && !creature->GetVictim())
113  {
114  sLog.outError("DoZoneInCombat called for creature that has empty threat list (creature entry = %u)", creature->GetEntry());
115  return;
116  }
117 
118  Map::PlayerList const& PlList = map->GetPlayers();
119 
120  if (PlList.isEmpty())
121  return;
122 
123  for (Map::PlayerList::const_iterator i = PlList.begin(); i != PlList.end(); ++i)
124  {
125  if (Player* pPlayer = i->GetSource())
126  {
127  if (pPlayer->IsGameMaster())
128  continue;
129 
130  if (pPlayer->IsAlive())
131  {
132  creature->SetInCombatWith(pPlayer);
133  pPlayer->SetInCombatWith(creature);
134  creature->AddThreat(pPlayer, 0.0f);
135  }
136 
137  /* Causes certain things to never leave the threat list (Priest Lightwell, etc):
138  for (Unit::ControlList::const_iterator itr = pPlayer->m_Controlled.begin(); itr != pPlayer->m_Controlled.end(); ++itr)
139  {
140  creature->SetInCombatWith(*itr);
141  (*itr)->SetInCombatWith(creature);
142  creature->AddThreat(*itr, 0.0f);
143  }*/
144  }
145  }
146 }
147 
148 // scripts does not take care about MoveInLineOfSight loops
149 // MoveInLineOfSight can be called inside another MoveInLineOfSight and cause stack overflow
151 {
152  if (m_MoveInLineOfSight_locked == true)
153  return;
155  MoveInLineOfSight(who);
157 }
158 
160 {
161  if (me->GetVictim())
162  return;
163 
164  if (me->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET) // non-combat pets should just stand there and look good;)
165  return;
166 
167  if (me->HasReactState(REACT_AGGRESSIVE) && me->canStartAttack(who, false))
168  AttackStart(who);
169  //else if (who->GetVictim() && me->IsFriendlyTo(who)
170  // && me->IsWithinDistInMap(who, sWorld.getConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS))
171  // && me->canAttack(who->GetVictim()))
172  // AttackStart(who->GetVictim());
173 }
174 
175 // Distract creature, if player gets too close while stealthed/prowling
176 void CreatureAI::TriggerAlert(Unit const* who) const
177 {
178  // If there's no target, or target isn't a player do nothing
179  if (!who || who->GetTypeId() != TYPEID_PLAYER)
180  return;
181 
182  // If this unit isn't an NPC, is already distracted, is in combat, is confused, stunned or fleeing, do nothing
184  return;
185 
186  // Only alert for hostiles!
187  if (me->IsCivilian() || me->HasReactState(REACT_PASSIVE) || !me->IsHostileTo(who))
188  return;
189 
190  // Send alert sound (if any) for this creature
192 
193  // Face the unit (stealthed player) and set distracted state for 5 seconds
194  me->SetFacingTo(me->GetAngle(who->GetPositionX(), who->GetPositionY()));
195  me->StopMoving();
197 }
198 
200 {
201  if (!me->IsInCombat())
202  return false;
203 
205  {
206  if (Unit* victim = me->SelectVictim())
207  AttackStart(victim);
208  return me->GetVictim();
209  }
210  else if (me->getThreatManager().isThreatListEmpty())
211  {
212  EnterEvadeMode();
213  return false;
214  }
215 
216  return true;
217 }
218 
220 {
221  if (!_EnterEvadeMode())
222  return;
223 
224  sLog.outDebug("Creature %u enters evade mode.", me->GetEntry());
225 
226  if (Unit* owner = me->GetCharmerOrOwner())
227  {
228  me->GetMotionMaster()->Clear(false);
230  }
231  else
232  {
233  // Required to prevent attacking creatures that are evading and cause them to reenter combat
234  // Does not apply to MoveFollow
237  }
238 
239  Reset();
240 }
241 
242 /*void CreatureAI::AttackedBy(Unit* attacker)
243 {
244  if (!me->GetVictim())
245  AttackStart(attacker);
246 }*/
247 
248 
250 {
251  if (me->IsValidAttackTarget(target))
252  {
253  AttackStart(target);
255  }
256 }
257 
259 {
260  if (!me->IsInCombat())
261  return false;
262 
264  {
265  if (me->GetVictim())
266  return true;
267  else
269  }
270 
271  if (Unit* victim = me->SelectVictim())
272  AttackStart(victim);
273  return me->GetVictim();
274 }
275 
277 {
278  if (!me->IsInCombat())
279  return false;
280 
282  {
283  if (Unit* victim = me->SelectVictim())
284  AttackStart(victim);
285  return me->GetVictim();
286  }
287  else if (me->getThreatManager().isThreatListEmpty())
288  {
289  EnterEvadeMode();
290  return false;
291  }
292 
293  return true;
294 }
295 
297 {
298  if (!me->IsAlive())
299  return false;
300 
301  // sometimes bosses stuck in combat?
302  me->DeleteThreatList();
303  me->CombatStopWithPets(true);
304  me->SetLootRecipient(nullptr);
305  me->SetPlayerDamaged(false);
307 
308  if (me->IsInEvadeMode())
309  return false;
310 
311  me->RemoveAllAuras();
313 
314  return true;
315 }
316 
318 {
319  if (CombatMovementEnabled == enable)
320  return;
321 
322  CombatMovementEnabled = enable;
323 
324  if (enable && me->GetVictim())
325  {
327  {
329  me->CastStop();
330  }
331  }
332 }
333 
334 Creature* CreatureAI::DoSummon(uint32 entry, const Position& pos, uint32 despawnTime, TempSummonType summonType)
335 {
336  return me->SummonCreature(entry, pos, summonType, despawnTime);
337 }
338 
339 Creature* CreatureAI::DoSummon(uint32 entry, WorldObject* obj, float radius, uint32 despawnTime, TempSummonType summonType)
340 {
341  Position pos = obj->GetRandomNearPosition(radius);
342  return me->SummonCreature(entry, pos, summonType, despawnTime);
343 }
344 
345 Creature* CreatureAI::DoSummonFlyer(uint32 entry, WorldObject* obj, float flightZ, float radius, uint32 despawnTime, TempSummonType summonType)
346 {
347  Position pos = obj->GetRandomNearPosition(radius);
348  pos.m_positionZ += flightZ;
349  return me->SummonCreature(entry, pos, summonType, despawnTime);
350 }
static AISpellInfoType * AISpellInfo
Definition: UnitAI.h:121
virtual void EnterEvadeMode()
Definition: CreatureAI.cpp:219
void RemoveAllAuras()
Definition: Unit.cpp:4577
bool UpdateVictim()
Definition: CreatureAI.cpp:276
Map * GetMap() const
Definition: Object.h:841
void Clear(bool reset=true)
Definition: MotionMaster.h:145
void AddUnitState(uint32 f)
Definition: Unit.h:1026
pet will not attack
Definition: Unit.h:760
void AddThreat(Unit *victim, float threat, SpellSchoolMask schoolMask=SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *threatSpell=NULL)
Definition: Unit.cpp:10208
void MoveChase(Unit *target, float dist=0.0f, float angle=0.0f)
Unit * SelectNearestTarget(float dist=0, bool playerOnly=false) const
Definition: Creature.cpp:1864
void SetCombatMovement(bool enable)
Set combat movement (on/off)
Definition: CreatureAI.cpp:317
void DoZoneInCombat(Creature *creature=NULL, float maxRangeToNearestTarget=50.0f)
Definition: CreatureAI.cpp:78
MotionMaster * GetMotionMaster()
Definition: Unit.h:1890
TempSummon * SummonCreature(uint32 id, const Position &pos, TempSummonType spwtype=TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime=0)
Definition: Object.cpp:2091
Creature * DoSummon(uint32 uiEntry, const Position &pos, uint32 uiDespawntime=30000, TempSummonType uiType=TEMPSUMMON_CORPSE_TIMED_DESPAWN)
Definition: CreatureAI.cpp:334
bool IsInCombat() const
Definition: Unit.h:1243
void OnCharmed(bool apply) override
Definition: CreatureAI.cpp:27
bool IsValidAttackTarget(Unit const *target) const
Definition: Unit.cpp:9510
void CombatStopWithPets(bool cast=false)
Definition: Unit.cpp:7535
#define sLog
Log class singleton.
Definition: Log.h:187
void MoveTargetedHome()
MovementGeneratorType GetCurrentMovementGeneratorType() const
#define PET_FOLLOW_DIST
bool HasReactState(ReactStates state) const
Definition: Creature.h:497
bool IsInEvadeMode() const
Definition: Creature.cpp:2298
bool IsDungeon() const
Definition: Map.h:427
void SetGazeOn(Unit *target)
Definition: CreatureAI.cpp:249
void CastStop(uint32 except_spellid=0)
Definition: Unit.cpp:1216
bool isThreatListEmpty() const
uint32 GetCreatureType() const
Definition: Unit.cpp:10686
iterator begin()
Definition: MapRefManager.h:48
void apply(T *val)
Definition: ByteConverter.h:41
bool IsAIEnabled
Definition: Unit.h:1990
bool canStartAttack(Unit const *u, bool force) const
Definition: Creature.cpp:1499
bool m_MoveInLineOfSight_locked
Definition: CreatureAI.h:215
void SetLootRecipient(Unit *unit)
Definition: Creature.cpp:1012
uint32 flags_extra
Definition: Creature.h:195
void DoZoneInCombatWithPlayers(bool force=false)
Definition: CreatureAI.cpp:41
Creature *const me
Definition: CreatureAI.h:68
uint8 GetTypeId() const
Definition: Object.h:210
void TriggerAlert(Unit const *who) const
Definition: CreatureAI.cpp:176
bool IsAlive() const
Definition: Unit.h:1336
Unit * GetVictim() const
Definition: Unit.h:1013
float GetPositionY() const
Definition: Position.h:98
void SetLastDamagedTime(time_t val)
Definition: Unit.h:1996
Position GetRandomNearPosition(float radius)
Definition: Object.cpp:2375
CreatureAI * AI() const
Definition: Creature.h:517
Unit * getHostileTarget()
float GetAngle(Position const *pos) const
TempSummonType
bool IsFriendlyTo(Unit const *unit) const
Definition: Unit.cpp:7339
void SetFacingTo(float ori)
Definition: Unit.cpp:3625
bool _EnterEvadeMode()
Definition: CreatureAI.cpp:296
bool CombatMovementEnabled
Combat movement currently enabled.
Definition: CreatureAI.h:209
float m_positionZ
Definition: Position.h:52
bool isEmpty() const
Definition: LinkedList.h:97
bool NeedChangeAI
Definition: Unit.h:1990
void MoveInLineOfSight_Safe(Unit *who)
Definition: CreatureAI.cpp:150
Definition: Map.h:266
Creature * DoSummonFlyer(uint32 uiEntry, WorldObject *obj, float fZ, float fRadius=5.0f, uint32 uiDespawntime=30000, TempSummonType uiType=TEMPSUMMON_CORPSE_TIMED_DESPAWN)
Definition: CreatureAI.cpp:345
void SetPlayerDamaged(bool set)
Definition: Creature.cpp:1230
PlayerList const & GetPlayers() const
Definition: Map.h:491
void SendAIReaction(AiReaction reactionType)
Definition: Creature.cpp:1913
#define error_log
Definition: Log.h:202
CreatureInfo const * GetCreatureTemplate() const
Definition: Creature.h:557
Unit * GetCharmerOrOwner() const
Definition: Unit.h:1410
bool IsCivilian() const
Definition: Creature.h:488
void DeleteThreatList()
Definition: Unit.cpp:10226
Unit * SelectVictim()
Definition: Unit.cpp:10299
Creature * ToCreature()
Definition: Object.h:395
bool UpdateVictimByReact()
Definition: CreatureAI.cpp:199
ThreatManager & getThreatManager()
Definition: Unit.h:1721
bool IsHostileTo(Unit const *unit) const
Definition: Unit.cpp:7334
Unit * getAttackerForHelper() const
Definition: Unit.cpp:7370
bool HasUnitState(const uint32 f) const
Definition: Unit.h:1030
AISpellInfoType * GetAISpellInfo(uint32 i)
Definition: CreatureAI.cpp:36
virtual void MoveInLineOfSight(Unit *)
Definition: CreatureAI.cpp:159
bool CanHaveThreatList() const
Definition: Unit.cpp:10169
uint32 GetEntry() const
Definition: Object.h:192
bool LoadCreaturesAddon(bool reload=false)
Definition: Creature.cpp:2140
ACE_UINT32 uint32
Definition: Define.h:71
float GetPositionX() const
Definition: Position.h:97
void MoveDistract(uint32 time)
bool IsSummon() const
Definition: Unit.h:1046
virtual void Reset()
Definition: UnitAI.h:61
Definition: Unit.h:908
bool UpdateVictimWithGaze()
Definition: CreatureAI.cpp:258
void StopMoving()
Definition: Unit.cpp:11917
void SetReactState(ReactStates st)
Definition: Creature.h:495
Definition: Player.h:922
virtual void AttackStart(Unit *)
Definition: UnitAI.cpp:25
iterator end()
Definition: MapRefManager.h:52
void SetInCombatWith(Unit *enemy)
Definition: Unit.cpp:9329
virtual float GetFollowAngle() const
Definition: Unit.h:1971
void MoveFollow(Unit *target, float dist, float angle, MovementSlot slot=MOTION_SLOT_ACTIVE)