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 "Map.h"
24#include "MotionMaster.h"
25#include "ObjectAccessor.h"
26#include "Player.h"
27#include "SpellInfo.h"
28#include "SpellMgr.h"
29#include "Vehicle.h"
30
32// AggressorAI
34
36{
37 // have some hostile factions, it will be selected by IsHostileTo check at MoveInLineOfSight
38 if (!creature->IsCivilian() && !creature->IsNeutralToAll())
40
41 return PERMIT_BASE_NO;
42}
43
45{
47}
48
50// CombatAI
52
54{
55 for (uint32 spell : me->m_spells)
56 if (spell && sSpellMgr->GetSpellInfo(spell, me->GetMap()->GetDifficultyID()))
57 _spells.push_back(spell);
58
60}
61
63{
64 _events.Reset();
65}
66
68{
69 for (uint32 spell : _spells)
70 {
71 if (AISpellInfoType const* info = GetAISpellInfo(spell, me->GetMap()->GetDifficultyID()))
72 if (info->condition == AICOND_DIE)
73 me->CastSpell(killer, spell, true);
74 }
75}
76
78{
79 for (uint32 spell : _spells)
80 {
81 if (AISpellInfoType const* info = GetAISpellInfo(spell, me->GetMap()->GetDifficultyID()))
82 {
83 if (info->condition == AICOND_AGGRO)
84 me->CastSpell(who, spell, false);
85 else if (info->condition == AICOND_COMBAT)
86 _events.ScheduleEvent(spell, info->cooldown, info->cooldown * 2);
87 }
88 }
89}
90
92{
93 if (!UpdateVictim())
94 return;
95
96 _events.Update(diff);
97
99 return;
100
101 if (uint32 spellId = _events.ExecuteEvent())
102 {
103 DoCast(spellId);
104 if (AISpellInfoType const* info = GetAISpellInfo(spellId, me->GetMap()->GetDifficultyID()))
105 _events.ScheduleEvent(spellId, info->cooldown, info->cooldown * 2);
106 }
107}
108
110{
111 _events.RescheduleEvent(spellId, Milliseconds(unTimeMs));
112}
113
115// CasterAI
117
119{
121
122 _attackDistance = 30.0f;
123
124 for (uint32 spell : _spells)
125 {
126 if (AISpellInfoType const* info = GetAISpellInfo(spell, me->GetMap()->GetDifficultyID()))
127 if (info->condition == AICOND_COMBAT && _attackDistance > info->maxRange)
128 _attackDistance = info->maxRange;
129 }
130
131 if (_attackDistance == 30.0f)
133}
134
136{
137 if (_spells.empty())
138 return;
139
140 uint32 spell = rand32() % _spells.size();
141 uint32 count = 0;
142 for (auto itr = _spells.begin(); itr != _spells.end(); ++itr, ++count)
143 {
144 if (AISpellInfoType const* info = GetAISpellInfo(*itr, me->GetMap()->GetDifficultyID()))
145 {
146 if (info->condition == AICOND_AGGRO)
147 me->CastSpell(who, *itr, false);
148 else if (info->condition == AICOND_COMBAT)
149 {
150 Milliseconds cooldown = info->realCooldown;
151 if (count == spell)
152 {
153 DoCast(_spells[spell]);
154 cooldown += Milliseconds(me->GetCurrentSpellCastTime(*itr));
155 }
156 _events.ScheduleEvent(*itr, cooldown);
157 }
158 }
159 }
160}
161
163{
164 if (!UpdateVictim())
165 return;
166
167 _events.Update(diff);
168
170 {
172 return;
173 }
174
176 return;
177
178 if (uint32 spellId = _events.ExecuteEvent())
179 {
180 DoCast(spellId);
181 uint32 casttime = me->GetCurrentSpellCastTime(spellId);
182 if (AISpellInfoType const* info = GetAISpellInfo(spellId, me->GetMap()->GetDifficultyID()))
183 _events.ScheduleEvent(spellId, Milliseconds(casttime ? casttime : 500) + info->realCooldown);
184 }
185}
186
188// TurretAI
190
191TurretAI::TurretAI(Creature* creature, uint32 scriptId) noexcept : CreatureAI(creature, scriptId), _minimumRange(0.0f)
192{
193 if (!creature->m_spells[0])
194 TC_LOG_ERROR("scripts.ai", "TurretAI set for creature with spell1 = 0. AI will do nothing ({})", creature->GetGUID().ToString());
195
196 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(creature->m_spells[0], creature->GetMap()->GetDifficultyID()))
197 {
198 auto [minRange, maxRange] = spellInfo->GetMinMaxRange(false);
199 _minimumRange = minRange;
200 creature->m_CombatDistance = maxRange;
201 }
202 creature->m_SightDistance = creature->m_CombatDistance;
203 creature->SetCanMelee(false);
204}
205
206bool TurretAI::CanAIAttack(Unit const* who) const
207{
210 return false;
211 return true;
212}
213
215{
216 if (who)
217 me->Attack(who, false);
218}
219
221{
222 if (!UpdateVictim())
223 return;
224
226}
227
229// VehicleAI
231
232VehicleAI::VehicleAI(Creature* creature, uint32 scriptId) noexcept : CreatureAI(creature, scriptId), _hasConditions(false), _conditionsTimer(VEHICLE_CONDITION_CHECK_TIME)
233{
234 LoadConditions();
235 _dismiss = false;
236 _dismissTimer = VEHICLE_DISMISS_TIME;
237 me->SetCanMelee(false);
238}
239
240// NOTE: VehicleAI::UpdateAI runs even while the vehicle is mounted
242{
243 CheckConditions(diff);
244
245 if (_dismiss)
246 {
247 if (_dismissTimer < diff)
248 {
249 _dismiss = false;
251 }
252 else
253 _dismissTimer -= diff;
254 }
255}
256
257void VehicleAI::OnCharmed(bool /*isNew*/)
258{
259 bool const charmed = me->IsCharmed();
260 if (!me->GetVehicleKit()->IsVehicleInUse() && !charmed && _hasConditions) // was used and has conditions
261 {
262 _dismiss = true; // needs reset
263 }
264 else if (charmed)
265 _dismiss = false; // in use again
266
267 _dismissTimer = VEHICLE_DISMISS_TIME; // reset timer
268}
269
274
276{
277 if (!_hasConditions)
278 return;
279
280 if (_conditionsTimer <= diff)
281 {
282 if (Vehicle * vehicleKit = me->GetVehicleKit())
283 {
284 for (auto const& [i, vehicleSeat] : vehicleKit->Seats)
285 {
286 if (Unit* passenger = ObjectAccessor::GetUnit(*me, vehicleSeat.Passenger.Guid))
287 {
288 if (Player * player = passenger->ToPlayer())
289 {
290 if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE, me->GetEntry(), player, me))
291 {
292 player->ExitVehicle();
293 return; // check other pessanger in next tick
294 }
295 }
296 }
297 }
298 }
299
301 }
302 else
303 _conditionsTimer -= diff;
304}
305
307{
308 if (creature->IsVehicle())
309 return PERMIT_BASE_SPECIAL;
310
311 return PERMIT_BASE_NO;
312}
#define VEHICLE_CONDITION_CHECK_TIME
Definition CombatAI.h:82
#define VEHICLE_DISMISS_TIME
Definition CombatAI.h:83
#define sConditionMgr
@ CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE
@ AICOND_COMBAT
@ AICOND_AGGRO
@ AICOND_DIE
AISpellInfoType * GetAISpellInfo(uint32 spellId, Difficulty difficulty)
@ PERMIT_BASE_SPECIAL
Definition CreatureAI.h:51
@ PERMIT_BASE_NO
Definition CreatureAI.h:46
@ PERMIT_BASE_REACTIVE
Definition CreatureAI.h:48
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define MELEE_RANGE
uint32 rand32()
Definition Random.cpp:70
#define sSpellMgr
Definition SpellMgr.h:812
@ UNIT_STATE_CASTING
Definition Unit.h:276
static int32 Permissible(Creature const *creature)
Definition CombatAI.cpp:35
void UpdateAI(uint32) override
Definition CombatAI.cpp:44
void UpdateAI(uint32 diff) override
Definition CombatAI.cpp:162
void InitializeAI() override
Definition CombatAI.cpp:118
void JustEngagedWith(Unit *) override
Definition CombatAI.cpp:135
float _attackDistance
Definition CombatAI.h:65
SpellVector _spells
Definition CombatAI.h:53
void SpellInterrupted(uint32 spellId, uint32 unTimeMs) override
Definition CombatAI.cpp:109
void InitializeAI() override
Definition CombatAI.cpp:53
void Reset() override
Definition CombatAI.cpp:62
void JustDied(Unit *killer) override
Definition CombatAI.cpp:67
void JustEngagedWith(Unit *who) override
Definition CombatAI.cpp:77
EventMap _events
Definition CombatAI.h:52
void UpdateAI(uint32 diff) override
Definition CombatAI.cpp:91
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:63
bool IsCivilian() const
Definition Creature.h:126
uint32 m_spells[MAX_CREATURE_SPELLS]
Definition Creature.h:324
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
float m_CombatDistance
Definition Creature.h:427
uint32 ExecuteEvent()
Definition EventMap.cpp:77
void Update(uint32 time)
Definition EventMap.h:61
void ScheduleEvent(uint32 eventId, Milliseconds time, uint32 group=0, uint8 phase=0)
Definition EventMap.cpp:40
void RescheduleEvent(uint32 eventId, Milliseconds time, uint32 group=0, uint8 phase=0)
Definition EventMap.cpp:56
void Reset()
Definition EventMap.cpp:25
Difficulty GetDifficultyID() const
Definition Map.h:360
Player * ToPlayer()
Definition Object.h:126
uint32 GetEntry() const
Definition Object.h:89
bool DoSpellAttackIfReady(uint32 spellId)
Definition UnitAI.cpp:61
virtual void InitializeAI()
Definition UnitAI.cpp:43
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:89
Definition Unit.h:635
bool IsVehicle() const
Definition Unit.h:754
bool IsCharmed() const
Definition Unit.h:1236
bool IsWithinCombatRange(Unit const *obj, float dist2compare) const
Definition Unit.cpp:670
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:3231
Unit * EnsureVictim() const
Definition Unit.h:728
bool Attack(Unit *victim, bool meleeAttack)
Definition Unit.cpp:5853
Unit * GetVictim() const
Definition Unit.h:726
bool HasUnitState(const uint32 f) const
Definition Unit.h:743
bool HasBreakableByDamageCrowdControlAura(Unit const *excludeCasterChannel=nullptr) const
Definition Unit.cpp:778
Vehicle * GetVehicleKit() const
Definition Unit.h:1782
int32 GetCurrentSpellCastTime(uint32 spell_id) const
Definition Unit.cpp:3254
bool IsVehicleInUse() const
Returns information whether the vehicle is currently used by any unit.
Definition Vehicle.cpp:612
Map * GetMap() const
Definition Object.h:411
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2217
bool IsNeutralToAll() const
Definition Object.cpp:2204
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
float _minimumRange
Definition CombatAI.h:79
bool CanAIAttack(Unit const *who) const override
Definition CombatAI.cpp:206
TurretAI(Creature *creature, uint32 scriptId={}) noexcept
Definition CombatAI.cpp:191
void UpdateAI(uint32 diff) override
Definition CombatAI.cpp:220
void AttackStart(Unit *who) override
== Triggered Actions Requested ==================
Definition CombatAI.cpp:214
VehicleAI(Creature *creature, uint32 scriptId={}) noexcept
Definition CombatAI.cpp:232
void LoadConditions()
Definition CombatAI.cpp:270
bool _hasConditions
Definition CombatAI.h:101
static int32 Permissible(Creature const *creature)
Definition CombatAI.cpp:306
void UpdateAI(uint32 diff) override
Definition CombatAI.cpp:241
bool _dismiss
Definition CombatAI.h:103
uint32 _dismissTimer
Definition CombatAI.h:104
void OnCharmed(bool isNew) override
Definition CombatAI.cpp:257
uint32 _conditionsTimer
Definition CombatAI.h:102
void CheckConditions(uint32 diff)
Definition CombatAI.cpp:275