Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
CombatAI.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "CombatAI.h"
7#include "ObjectAccessor.h"
8#include "Player.h"
9#include "SpellInfo.h"
10#include "SpellMgr.h"
11#include "Vehicle.h"
12
14{
15 // have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight
16 if (!creature->IsCivilian() && !creature->IsNeutralToAll())
18
19 return PERMIT_BASE_NO;
20}
21
23{
24 if (!UpdateVictim())
25 return;
26
28}
29
30// some day we will delete these useless things
31int CombatAI::Permissible(const Creature* /*creature*/)
32{
33 return PERMIT_BASE_NO;
34}
35
36int ArcherAI::Permissible(const Creature* /*creature*/)
37{
38 return PERMIT_BASE_NO;
39}
40
41int TurretAI::Permissible(const Creature* /*creature*/)
42{
43 return PERMIT_BASE_NO;
44}
45
46int VehicleAI::Permissible(const Creature* /*creature*/)
47{
48 return PERMIT_BASE_NO;
49}
50
52{
53 for (uint32 i = 0; i < CREATURE_MAX_SPELLS; ++i)
54 if (me->m_spells[i] && sSpellMgr->GetSpellInfo(me->m_spells[i]))
55 spells.push_back(me->m_spells[i]);
56
58}
59
61{
62 events.Reset();
63}
64
66{
67 for (SpellVct::iterator i = spells.begin(); i != spells.end(); ++i)
68 if (AISpellInfo[*i].condition == AICOND_DIE)
69 me->CastSpell(killer, *i, true);
70}
71
73{
74 for (SpellVct::iterator i = spells.begin(); i != spells.end(); ++i)
75 {
76 if (AISpellInfo[*i].condition == AICOND_AGGRO)
77 me->CastSpell(who, *i, false);
78 else if (AISpellInfo[*i].condition == AICOND_COMBAT)
79 events.ScheduleEvent(*i, AISpellInfo[*i].cooldown + rand() % AISpellInfo[*i].cooldown);
80 }
81}
82
84{
85 if (!UpdateVictim())
86 return;
87
88 events.Update(diff);
89
90 if (me->HasUnitState(UNIT_STATE_CASTING))
91 return;
92
93 if (uint32 spellId = events.ExecuteEvent())
94 {
95 DoCast(spellId);
96 events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + rand() % AISpellInfo[spellId].cooldown);
97 }
98 else
100}
101
103{
104 events.RescheduleEvent(spellId, unTimeMs);
105}
106
108//CasterAI
110
112{
114
115 m_attackDist = 30.0f;
116 for (SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr)
117 if (AISpellInfo[*itr].condition == AICOND_COMBAT && m_attackDist > GetAISpellInfo(*itr)->maxRange)
119 if (m_attackDist == 30.0f)
121}
122
124{
125 if (spells.empty())
126 return;
127
128 uint32 spell = rand() % spells.size();
129 uint32 count = 0;
130 for (SpellVct::iterator itr = spells.begin(); itr != spells.end(); ++itr, ++count)
131 {
132 if (AISpellInfo[*itr].condition == AICOND_AGGRO)
133 me->CastSpell(who, *itr, false);
134 else if (AISpellInfo[*itr].condition == AICOND_COMBAT)
135 {
136 uint32 cooldown = GetAISpellInfo(*itr)->realCooldown;
137 if (count == spell)
138 {
139 DoCast(spells[spell]);
140 cooldown += me->GetCurrentSpellCastTime(*itr);
141 }
142 events.ScheduleEvent(*itr, cooldown);
143 }
144 }
145}
146
148{
149 if (!UpdateVictim())
150 return;
151
152 events.Update(diff);
153
154 if (me->GetVictim()->HasBreakableByDamageCrowdControlAura(me))
155 {
156 me->InterruptNonMeleeSpells(false);
157 return;
158 }
159
160 if (me->HasUnitState(UNIT_STATE_CASTING))
161 return;
162
163 if (uint32 spellId = events.ExecuteEvent())
164 {
165 DoCast(spellId);
166 uint32 casttime = me->GetCurrentSpellCastTime(spellId);
167 events.ScheduleEvent(spellId, (casttime ? casttime : 500) + GetAISpellInfo(spellId)->realCooldown);
168 }
169}
170
172//ArcherAI
174
176{
177 if (!me->m_spells[0])
178 SF_LOG_ERROR("misc", "ArcherAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry());
179
180 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(me->m_spells[0]);
181 m_minRange = spellInfo ? spellInfo->GetMinRange(false) : 0;
182
183 if (!m_minRange)
185 me->m_CombatDistance = spellInfo ? spellInfo->GetMaxRange(false) : 0;
186 me->m_SightDistance = me->m_CombatDistance;
187}
188
190{
191 if (!who)
192 return;
193
194 if (me->IsWithinCombatRange(who, m_minRange))
195 {
196 if (me->Attack(who, true) && !who->IsFlying())
197 me->GetMotionMaster()->MoveChase(who);
198 }
199 else
200 {
201 if (me->Attack(who, false) && !who->IsFlying())
202 me->GetMotionMaster()->MoveChase(who, me->m_CombatDistance);
203 }
204
205 if (who->IsFlying())
206 me->GetMotionMaster()->MoveIdle();
207}
208
210{
211 if (!UpdateVictim())
212 return;
213
214 if (!me->IsWithinCombatRange(me->GetVictim(), m_minRange))
215 DoSpellAttackIfReady(me->m_spells[0]);
216 else
218}
219
221//TurretAI
223
225{
226 if (!me->m_spells[0])
227 SF_LOG_ERROR("misc", "TurretAI set for creature (entry = %u) with spell1=0. AI will do nothing", me->GetEntry());
228
229 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(me->m_spells[0]);
230 m_minRange = spellInfo ? spellInfo->GetMinRange(false) : 0;
231 me->m_CombatDistance = spellInfo ? spellInfo->GetMaxRange(false) : 0;
232 me->m_SightDistance = me->m_CombatDistance;
233}
234
235bool TurretAI::CanAIAttack(const Unit* /*who*/) const
236{
238 if (!me->IsWithinCombatRange(me->GetVictim(), me->m_CombatDistance)
239 || (m_minRange && me->IsWithinCombatRange(me->GetVictim(), m_minRange)))
240 return false;
241 return true;
242}
243
245{
246 if (who)
247 me->Attack(who, false);
248}
249
251{
252 if (!UpdateVictim())
253 return;
254
255 DoSpellAttackIfReady(me->m_spells[0]);
256}
257
259//VehicleAI
261
268
269//NOTE: VehicleAI::UpdateAI runs even while the vehicle is mounted
271{
272 CheckConditions(diff);
273
274 if (m_DoDismiss)
275 {
276 if (m_DismissTimer < diff)
277 {
278 m_DoDismiss = false;
279 me->SetVisible(false);
280 me->DespawnOrUnsummon();
281 }
282 else
283 m_DismissTimer -= diff;
284 }
285}
286
288{
289 me->SetVisible(true);
290}
291
292void VehicleAI::OnCharmed(bool apply)
293{
294 if (m_IsVehicleInUse && !apply && !conditions.empty())//was used and has conditions
295 {
296 m_DoDismiss = true;//needs reset
299 }
300 else if (apply)
301 m_DoDismiss = false;//in use again
302
304 m_IsVehicleInUse = apply;
305}
306
308{
309 conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, me->GetEntry());
310 if (!conditions.empty())
311 SF_LOG_DEBUG("condition", "VehicleAI::LoadConditions: loaded %u conditions", uint32(conditions.size()));
312}
313
315{
316 if (m_ConditionsTimer < diff)
317 {
318 if (!conditions.empty())
319 {
320 if (Vehicle* vehicleKit = me->GetVehicleKit())
321 for (SeatMap::iterator itr = vehicleKit->Seats.begin(); itr != vehicleKit->Seats.end(); ++itr)
322 if (Unit* passenger = ObjectAccessor::GetUnit(*me, itr->second.Passenger.Guid))
323 {
324 if (Player* player = passenger->ToPlayer())
325 {
326 if (!sConditionMgr->IsObjectMeetToConditions(player, me, conditions))
327 {
328 player->ExitVehicle();
329 return;//check other pessanger in next tick
330 }
331 }
332 }
333 }
335 }
336 else
337 m_ConditionsTimer -= diff;
338}
#define VEHICLE_CONDITION_CHECK_TIME
Definition CombatAI.h:80
#define VEHICLE_DISMISS_TIME
Definition CombatAI.h:81
#define sConditionMgr
@ CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE
AISpellInfoType * GetAISpellInfo(uint32 i)
@ PERMIT_BASE_PROACTIVE
Definition CreatureAI.h:183
@ PERMIT_BASE_NO
Definition CreatureAI.h:180
@ AICOND_COMBAT
@ AICOND_AGGRO
@ AICOND_DIE
std::uint32_t uint32
Definition Define.h:77
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
#define MELEE_RANGE
Definition Object.h:33
#define sSpellMgr
Definition SpellMgr.h:744
@ UNIT_NPC_FLAG_SPELLCLICK
Definition Unit.h:711
@ UNIT_NPC_FLAG_PLAYER_VEHICLE
Definition Unit.h:712
#define CREATURE_MAX_SPELLS
Definition Unit.h:272
@ UNIT_STATE_CASTING
Definition Unit.h:527
@ UNIT_FIELD_NPC_FLAGS
static int Permissible(const Creature *)
Definition CombatAI.cpp:13
void UpdateAI(uint32) OVERRIDE
== Triggered Actions Requested ==================
Definition CombatAI.cpp:22
void EnterCombat(Unit *) OVERRIDE
Definition CombatAI.cpp:123
void InitializeAI() OVERRIDE
Definition CombatAI.cpp:111
float m_attackDist
Definition CombatAI.h:52
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
Definition CombatAI.cpp:147
void JustDied(Unit *killer) OVERRIDE
Definition CombatAI.cpp:65
void EnterCombat(Unit *who) OVERRIDE
Definition CombatAI.cpp:72
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
Definition CombatAI.cpp:83
void SpellInterrupted(uint32 spellId, uint32 unTimeMs) OVERRIDE
Definition CombatAI.cpp:102
void InitializeAI() OVERRIDE
Definition CombatAI.cpp:51
static int Permissible(const Creature *)
Definition CombatAI.cpp:31
void Reset() OVERRIDE
Definition CombatAI.cpp:60
SpellVct spells
Definition CombatAI.h:40
EventMap events
Definition CombatAI.h:39
CreatureAI(Creature *creature)
Definition CreatureAI.h:69
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:56
bool IsCivilian() const
Definition Creature.h:453
static Unit * GetUnit(WorldObject const &, uint64 guid)
Player * ToPlayer()
Definition Object.h:204
void DoMeleeAttackIfReady()
Definition UnitAI.cpp:28
void DoCast(uint32 spellId)
Definition UnitAI.cpp:110
virtual void InitializeAI()
Definition UnitAI.h:118
bool DoSpellAttackIfReady(uint32 spell)
Definition UnitAI.cpp:48
static AISpellInfoType * AISpellInfo
Definition UnitAI.h:242
Definition Unit.h:1367
bool IsNeutralToAll() const
Definition Unit.cpp:2301
bool IsFlying() const
Definition Unit.h:2780
ArcherAI(Creature *c)
Definition CombatAI.cpp:175
void AttackStart(Unit *who) OVERRIDE
Definition CombatAI.cpp:189
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
Definition CombatAI.cpp:209
float m_minRange
Definition CombatAI.h:64
static int Permissible(const Creature *)
Definition CombatAI.cpp:36
TurretAI(Creature *c)
Definition CombatAI.cpp:224
float m_minRange
Definition CombatAI.h:77
void AttackStart(Unit *who) OVERRIDE
Definition CombatAI.cpp:244
bool CanAIAttack(const Unit *who) const
Definition CombatAI.cpp:235
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
Definition CombatAI.cpp:250
static int Permissible(const Creature *)
Definition CombatAI.cpp:41
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
Definition CombatAI.cpp:270
void LoadConditions()
Definition CombatAI.cpp:307
uint32 m_DismissTimer
Definition CombatAI.h:101
bool m_IsVehicleInUse
Definition CombatAI.h:95
uint32 m_ConditionsTimer
Definition CombatAI.h:99
void CheckConditions(const uint32 diff)
Definition CombatAI.cpp:314
VehicleAI(Creature *c)
Definition CombatAI.cpp:262
static int Permissible(const Creature *)
Definition CombatAI.cpp:46
bool m_DoDismiss
Definition CombatAI.h:100
void Reset() OVERRIDE
Definition CombatAI.cpp:287
void OnCharmed(bool apply) OVERRIDE
Definition CombatAI.cpp:292
ConditionList conditions
Definition CombatAI.h:98