TrinityCore
Loading...
Searching...
No Matches
CombatAI.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore 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 "CombatAI.h"
19#include "ConditionMgr.h"
20#include "Creature.h"
21#include "CreatureAIImpl.h"
22#include "Log.h"
23#include "MotionMaster.h"
24#include "ObjectAccessor.h"
25#include "Player.h"
26#include "SpellInfo.h"
27#include "SpellMgr.h"
28#include "Vehicle.h"
29
31// AggressorAI
33
35{
36 // have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight
37 if (!creature->IsCivilian() && !creature->IsNeutralToAll())
39
40 return PERMIT_BASE_NO;
41}
42
44{
45 if (!UpdateVictim())
46 return;
47
49}
50
52// CombatAI
54
56{
57 for (uint32 spell : me->m_spells)
58 if (spell && sSpellMgr->GetSpellInfo(spell))
59 _spells.push_back(spell);
60
62}
63
65{
66 _events.Reset();
67}
68
70{
71 for (uint32 spell : _spells)
72 {
73 if (AISpellInfo[spell].condition == AICOND_DIE)
74 me->CastSpell(killer, spell, true);
75 }
76}
77
79{
80 for (uint32 spell : _spells)
81 {
82 if (AISpellInfo[spell].condition == AICOND_AGGRO)
83 me->CastSpell(who, spell, false);
84 else if (AISpellInfo[spell].condition == AICOND_COMBAT)
85 _events.ScheduleEvent(spell, Milliseconds(AISpellInfo[spell].cooldown + rand32() % AISpellInfo[spell].cooldown));
86 }
87}
88
90{
91 if (!UpdateVictim())
92 return;
93
94 _events.Update(diff);
95
97 return;
98
99 if (uint32 spellId = _events.ExecuteEvent())
100 {
101 DoCast(spellId);
102 _events.ScheduleEvent(spellId, Milliseconds(AISpellInfo[spellId].cooldown + rand32() % AISpellInfo[spellId].cooldown));
103 }
104 else
106}
107
109{
110 _events.RescheduleEvent(spellId, Milliseconds(unTimeMs));
111}
112
114// CasterAI
116
118{
120
121 _attackDistance = 30.0f;
122
123 for (uint32 spell : _spells)
124 {
125 if (AISpellInfo[spell].condition == AICOND_COMBAT && _attackDistance > GetAISpellInfo(spell)->maxRange)
127 }
128
129 if (_attackDistance == 30.0f)
131}
132
134{
135 if (_spells.empty())
136 return;
137
138 uint32 spell = rand32() % _spells.size();
139 uint32 count = 0;
140 for (auto itr = _spells.begin(); itr != _spells.end(); ++itr, ++count)
141 {
142 if (AISpellInfo[*itr].condition == AICOND_AGGRO)
143 me->CastSpell(who, *itr, false);
144 else if (AISpellInfo[*itr].condition == AICOND_COMBAT)
145 {
146 uint32 cooldown = GetAISpellInfo(*itr)->realCooldown;
147 if (count == spell)
148 {
149 DoCast(_spells[spell]);
150 cooldown += me->GetCurrentSpellCastTime(*itr);
151 }
152 _events.ScheduleEvent(*itr, Milliseconds(cooldown));
153 }
154 }
155}
156
158{
159 if (!UpdateVictim())
160 return;
161
162 _events.Update(diff);
163
165 {
167 return;
168 }
169
171 return;
172
173 if (uint32 spellId = _events.ExecuteEvent())
174 {
175 DoCast(spellId);
176 uint32 casttime = me->GetCurrentSpellCastTime(spellId);
177 _events.ScheduleEvent(spellId, (casttime ? Milliseconds(casttime) : 500ms) + Milliseconds(GetAISpellInfo(spellId)->realCooldown));
178 }
179}
180
182// ArcherAI
184
186{
187 if (!creature->m_spells[0])
188 TC_LOG_ERROR("scripts.ai", "ArcherAI set for creature with spell1 = 0. AI will do nothing ({})", creature->GetGUID().ToString());
189
190 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(creature->m_spells[0]);
191 _minimumRange = spellInfo ? spellInfo->GetMinRange(false) : 0;
192
193 if (!_minimumRange)
195 creature->m_CombatDistance = spellInfo ? spellInfo->GetMaxRange(false) : 0;
196 creature->m_SightDistance = creature->m_CombatDistance;
197}
198
200{
201 if (!who)
202 return;
203
205 {
206 if (me->Attack(who, true) && !who->IsFlying())
208 }
209 else
210 {
211 if (me->Attack(who, false) && !who->IsFlying())
213 }
214
215 if (who->IsFlying())
217}
218
220{
221 if (!UpdateVictim())
222 return;
223
226 else
228}
229
231// TurretAI
233
235{
236 if (!creature->m_spells[0])
237 TC_LOG_ERROR("scripts.ai", "TurretAI set for creature with spell1 = 0. AI will do nothing ({})", creature->GetGUID().ToString());
238
239 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(creature->m_spells[0]);
240 _minimumRange = spellInfo ? spellInfo->GetMinRange(false) : 0;
241 creature->m_CombatDistance = spellInfo ? spellInfo->GetMaxRange(false) : 0;
242 creature->m_SightDistance = creature->m_CombatDistance;
243}
244
245bool TurretAI::CanAIAttack(Unit const* who) const
246{
249 return false;
250 return true;
251}
252
254{
255 if (who)
256 me->Attack(who, false);
257}
258
260{
261 if (!UpdateVictim())
262 return;
263
265}
266
268// VehicleAI
270
271VehicleAI::VehicleAI(Creature* creature) : CreatureAI(creature), _hasConditions(false), _conditionsTimer(VEHICLE_CONDITION_CHECK_TIME)
272{
274 _dismiss = false;
276}
277
278// NOTE: VehicleAI::UpdateAI runs even while the vehicle is mounted
280{
281 CheckConditions(diff);
282
283 if (_dismiss)
284 {
285 if (_dismissTimer < diff)
286 {
287 _dismiss = false;
289 }
290 else
291 _dismissTimer -= diff;
292 }
293}
294
295void VehicleAI::OnCharmed(bool /*isNew*/)
296{
297 bool const charmed = me->IsCharmed();
298 if (!me->GetVehicleKit()->IsVehicleInUse() && !charmed && _hasConditions) // was used and has conditions
299 {
300 _dismiss = true; // needs reset
301 }
302 else if (charmed)
303 _dismiss = false; // in use again
304
305 _dismissTimer = VEHICLE_DISMISS_TIME; // reset timer
306}
307
312
314{
315 if (!_hasConditions)
316 return;
317
318 if (_conditionsTimer <= diff)
319 {
320 if (Vehicle* vehicleKit = me->GetVehicleKit())
321 {
322 for (auto const& [i, vehicleSeat] : vehicleKit->Seats)
323 {
324 if (Unit* passenger = ObjectAccessor::GetUnit(*me, vehicleSeat.Passenger.Guid))
325 {
326 if (Player* player = passenger->ToPlayer())
327 {
328 if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, me->GetEntry(), player, me))
329 {
330 player->ExitVehicle();
331 return; // check other pessanger in next tick
332 }
333 }
334 }
335 }
336 }
337
339 }
340 else
341 _conditionsTimer -= diff;
342}
343
345{
346 if (creature->IsVehicle())
347 return PERMIT_BASE_SPECIAL;
348
349 return PERMIT_BASE_NO;
350}
#define VEHICLE_CONDITION_CHECK_TIME
Definition CombatAI.h:94
#define VEHICLE_DISMISS_TIME
Definition CombatAI.h:95
#define sConditionMgr
@ CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE
@ AICOND_COMBAT
@ AICOND_AGGRO
@ AICOND_DIE
AISpellInfoType * GetAISpellInfo(uint32 i)
@ PERMIT_BASE_SPECIAL
Definition CreatureAI.h:48
@ PERMIT_BASE_NO
Definition CreatureAI.h:43
@ PERMIT_BASE_REACTIVE
Definition CreatureAI.h:45
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define MELEE_RANGE
uint32 rand32()
Definition Random.cpp:70
#define sSpellMgr
Definition SpellMgr.h:738
@ UNIT_STATE_CASTING
Definition Unit.h:235
static int32 Permissible(Creature const *creature)
Definition CombatAI.cpp:34
void UpdateAI(uint32) override
Definition CombatAI.cpp:43
void UpdateAI(uint32 diff) override
Definition CombatAI.cpp:157
void InitializeAI() override
Definition CombatAI.cpp:117
void JustEngagedWith(Unit *) override
Definition CombatAI.cpp:133
float _attackDistance
Definition CombatAI.h:64
SpellVector _spells
Definition CombatAI.h:52
void SpellInterrupted(uint32 spellId, uint32 unTimeMs) override
Definition CombatAI.cpp:108
void InitializeAI() override
Definition CombatAI.cpp:55
void Reset() override
Definition CombatAI.cpp:64
void JustDied(Unit *killer) override
Definition CombatAI.cpp:69
void JustEngagedWith(Unit *who) override
Definition CombatAI.cpp:78
EventMap _events
Definition CombatAI.h:51
void UpdateAI(uint32 diff) override
Definition CombatAI.cpp:89
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:82
bool IsCivilian() const
Definition Creature.h:97
uint32 m_spells[MAX_CREATURE_SPELLS]
Definition Creature.h:229
float m_SightDistance
Definition Creature.h:335
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
float m_CombatDistance
Definition Creature.h:335
void Update(uint32 time)
Definition EventMap.h:67
EventId ExecuteEvent()
Definition EventMap.cpp:73
void RescheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:52
void ScheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:36
void Reset()
Definition EventMap.cpp:21
void MoveChase(Unit *target, Optional< ChaseRange > dist={}, Optional< ChaseAngle > angle={})
std::string ToString() const
uint32 GetEntry() const
Definition Object.h:81
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
static Player * ToPlayer(Object *o)
Definition Object.h:180
float GetMaxRange(bool positive=false, WorldObject *caster=nullptr, Spell *spell=nullptr) const
float GetMinRange(bool positive=false) const
void DoMeleeAttackIfReady()
Definition UnitAI.cpp:54
virtual void InitializeAI()
Definition UnitAI.cpp:36
bool DoSpellAttackIfReady(uint32 spell)
Definition UnitAI.cpp:78
static AISpellInfoType * AISpellInfo
Definition UnitAI.h:252
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:106
Definition Unit.h:769
bool IsVehicle() const
Definition Unit.h:887
bool IsCharmed() const
Definition Unit.h:1280
bool HasBreakableByDamageCrowdControlAura(Unit *excludeCasterChannel=nullptr) const
Definition Unit.cpp:693
bool IsWithinCombatRange(Unit const *obj, float dist2compare) const
Definition Unit.cpp:603
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:3093
MotionMaster * GetMotionMaster()
Definition Unit.h:1667
Unit * EnsureVictim() const
Definition Unit.h:861
bool Attack(Unit *victim, bool meleeAttack)
Definition Unit.cpp:5535
Unit * GetVictim() const
Definition Unit.h:859
bool HasUnitState(const uint32 f) const
Definition Unit.h:876
bool IsFlying() const
Definition Unit.h:1762
Vehicle * GetVehicleKit() const
Definition Unit.h:1735
int32 GetCurrentSpellCastTime(uint32 spell_id) const
Definition Unit.cpp:3116
bool IsVehicleInUse() const
Returns information whether the vehicle is currently used by any unit.
Definition Vehicle.cpp:590
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2832
bool IsNeutralToAll() const
Definition Object.cpp:2819
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
ArcherAI(Creature *creature)
Definition CombatAI.cpp:185
void UpdateAI(uint32 diff) override
Definition CombatAI.cpp:219
void AttackStart(Unit *who) override
Definition CombatAI.cpp:199
float _minimumRange
Definition CombatAI.h:77
TurretAI(Creature *creature)
Definition CombatAI.cpp:234
float _minimumRange
Definition CombatAI.h:91
bool CanAIAttack(Unit const *who) const override
Definition CombatAI.cpp:245
void UpdateAI(uint32 diff) override
Definition CombatAI.cpp:259
void AttackStart(Unit *who) override
Definition CombatAI.cpp:253
void LoadConditions()
Definition CombatAI.cpp:308
bool _hasConditions
Definition CombatAI.h:113
static int32 Permissible(Creature const *creature)
Definition CombatAI.cpp:344
void UpdateAI(uint32 diff) override
Definition CombatAI.cpp:279
bool _dismiss
Definition CombatAI.h:115
uint32 _dismissTimer
Definition CombatAI.h:116
void OnCharmed(bool isNew) override
Definition CombatAI.cpp:295
uint32 _conditionsTimer
Definition CombatAI.h:114
VehicleAI(Creature *creature)
Definition CombatAI.cpp:271
void CheckConditions(uint32 diff)
Definition CombatAI.cpp:313