Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
SpellEffectsMovement.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 "AccountMgr.h"
7#include "AreaTrigger.h"
8#include "Battleground.h"
9#include "BattlegroundMgr.h"
10#include "BattlePetMgr.h"
11#include "CellImpl.h"
12#include "Common.h"
13#include "Creature.h"
14#include "CreatureAI.h"
15#include "DatabaseEnv.h"
16#include "DynamicObject.h"
17#include "Formulas.h"
18#include "GameObject.h"
19#include "GameObjectAI.h"
20#include "GossipDef.h"
21#include "GridNotifiers.h"
22#include "GridNotifiersImpl.h"
23#include "Group.h"
24#include "Guild.h"
25#include "GuildMgr.h"
26#include "InstanceScript.h"
27#include "Language.h"
28#include "Log.h"
29#include "MapManager.h"
30#include "ObjectAccessor.h"
31#include "ObjectMgr.h"
32#include "Opcodes.h"
33#include "OutdoorPvPMgr.h"
34#include "PathGenerator.h"
35#include "Pet.h"
36#include "Player.h"
37#include "ReputationMgr.h"
38#include "ScriptMgr.h"
39#include "SharedDefines.h"
40#include "SkillDiscovery.h"
41#include "SkillExtraItems.h"
42#include "SocialMgr.h"
43#include "Spell.h"
44#include "SpellAuraEffects.h"
45#include "SpellAuras.h"
46#include "SpellMgr.h"
48#include "SpellValidation.h"
49#include "TemporarySummon.h"
50#include "Totem.h"
51#include "Unit.h"
52#include "UpdateData.h"
53#include "UpdateMask.h"
54#include "Util.h"
55#include "Vehicle.h"
56#include "VMapFactory.h"
57#include "World.h"
58#include "WorldPacket.h"
59
61{
63 return;
64
65 if (m_caster->IsInFlight())
66 return;
67
68 if (!unitTarget)
69 return;
70
71 float x, y, z;
72 unitTarget->GetContactPoint(m_caster, x, y, z, CONTACT_DISTANCE);
73
74 // Use 3D distance: near-vertical jumps (e.g. a creature pouncing down from a
75 // ledge) have almost no 2D distance, which yields a horizontal speed below the
76 // spline validation minimum (velocity > 0.1f) and silently aborts the jump.
77 float speedXY, speedZ;
78 CalculateJumpSpeeds(effIndex, m_caster->GetExactDist(x, y, z), speedXY, speedZ);
79 m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ);
80}
81
83{
85 return;
86
87 if (m_caster->IsInFlight())
88 return;
89
90 if (!m_targets.HasDst())
91 return;
92
93 // Init dest coordinates
94 float x, y, z;
95 destTarget->GetPosition(x, y, z);
96
97 if (Skyfire::Spells::JumpDestOverride const* jumpDestOverride =
99 {
100 m_caster->GetMotionMaster()->MoveJump(x, y, z + jumpDestOverride->ZOffset,
101 jumpDestOverride->SpeedXY, jumpDestOverride->SpeedZ);
102 return;
103 }
104
105 float speedXY, speedZ;
106 CalculateJumpSpeeds(effIndex, m_caster->GetExactDist(x, y, z), speedXY, speedZ);
107 m_caster->GetMotionMaster()->MoveJump(x, y, z, speedXY, speedZ);
108}
109
110void Spell::CalculateJumpSpeeds(uint8 i, float dist, float& speedXY, float& speedZ)
111{
112 if (m_spellInfo->Effects[i].MiscValue)
113 speedZ = float(m_spellInfo->Effects[i].MiscValue) / 10;
114 else if (m_spellInfo->Effects[i].MiscValueB)
115 speedZ = float(m_spellInfo->Effects[i].MiscValueB) / 10;
116 else
117 speedZ = 10.0f;
118 speedXY = dist * 10.0f / speedZ;
119
120 // Keep above the spline validation minimum (velocity > 0.1f) for very short jumps.
121 if (speedXY < 2.0f)
122 speedXY = 2.0f;
123}
124
126{
128 return;
129
130 if (!unitTarget || unitTarget->IsInFlight())
131 return;
132
133 // If not exist data for dest location - return
134 if (!m_targets.HasDst())
135 {
136 SF_LOG_ERROR("spells", "Spell::EffectTeleportUnits - does not have destination for spellId %u.", m_spellInfo->Id);
137 return;
138 }
139
140 // Init dest coordinates
141 uint32 mapid = destTarget->GetMapId();
142 if (mapid == MAPID_INVALID)
143 mapid = unitTarget->GetMapId();
144 float x, y, z, orientation;
145 destTarget->GetPosition(x, y, z, orientation);
146 if (!orientation && m_targets.GetUnitTarget())
147 orientation = m_targets.GetUnitTarget()->GetOrientation();
148 SF_LOG_DEBUG("spells", "Spell::EffectTeleportUnits - teleport unit to %u %f %f %f %f\n", mapid, x, y, z, orientation);
149
150 if (unitTarget->GetTypeId() == TypeID::TYPEID_PLAYER)
151 unitTarget->ToPlayer()->TeleportTo(mapid, x, y, z, orientation, unitTarget == m_caster ? TELE_TO_SPELL : 0);
152 else if (mapid == unitTarget->GetMapId())
153 unitTarget->NearTeleportTo(x, y, z, orientation, unitTarget == m_caster);
154 else
155 {
156 SF_LOG_ERROR("spells", "Spell::EffectTeleportUnits - spellId %u attempted to teleport creature to a different map.", m_spellInfo->Id);
157 return;
158 }
159
160 if (Skyfire::Spells::TeleportPostEffect const* teleportPostEffect =
162 {
163 switch (teleportPostEffect->Kind)
164 {
166 {
168 std::rand() % teleportPostEffect->RandomEffectCount);
169 if (spellId)
170 m_caster->CastSpell(m_caster, spellId, true);
171 return;
172 }
174 {
175 if (roll_chance_i(teleportPostEffect->SuccessChancePct))
176 {
177 uint32 randomEffect = std::rand() % teleportPostEffect->RandomEffectCount + 1;
178 uint32 spellId = 0;
179 if (randomEffect == 5)
180 {
181 if (Player* player = m_caster->ToPlayer())
183 randomEffect, player->GetTeam());
184 }
185 else
187
188 if (spellId)
189 m_caster->CastSpell(m_caster, spellId, true);
190 }
191 return;
192 }
194 {
195 if (roll_chance_i(teleportPostEffect->SuccessChancePct))
196 {
197 uint32 randomEffect = std::rand() % teleportPostEffect->RandomEffectCount + 1;
198 uint32 spellId = 0;
199 if (randomEffect == 4)
200 {
201 if (Player* player = m_caster->ToPlayer())
203 randomEffect, player->GetTeam());
204 }
205 else
206 spellId = Skyfire::Spells::GetArea52RipperPostEffectSpellId(randomEffect, 0);
207
208 if (spellId)
209 m_caster->CastSpell(m_caster, spellId, true);
210 }
211 return;
212 }
213 default:
214 return;
215 }
216 }
217}
218
220{
222 EffectNULL(effIndex);
223}
224
226{
228 return;
229
230 // Check for possible target
231 if (!unitTarget || unitTarget->IsInCombat())
232 return;
233
234 // target must be OK to do this
236 return;
237
238 unitTarget->SetFacingTo(unitTarget->GetAngle(destTarget));
239 unitTarget->ClearUnitState(UNIT_STATE_MOVING);
240
241 if (unitTarget->GetTypeId() == TypeID::TYPEID_UNIT)
242 unitTarget->GetMotionMaster()->MoveDistract(damage * IN_MILLISECONDS);
243}
244
246{
248 return;
249
250 if (m_caster->GetTypeId() != TypeID::TYPEID_PLAYER)
251 return;
252
253 float radius = m_spellInfo->Effects[effIndex].CalcRadius();
254 int32 duration = m_spellInfo->GetDuration();
255 // Caster not in world, might be spell triggered from aura removal
256 if (!m_caster->IsInWorld())
257 return;
258
259 DynamicObject* dynObj = new DynamicObject(true);
261 {
262 delete dynObj;
263 return;
264 }
265
266 dynObj->SetDuration(duration);
267 dynObj->SetCasterViewpoint();
268}
269
271{
273 return;
274
275 if (!unitTarget)
276 return;
277
278 if (unitTarget->IsInFlight())
279 return;
280
281 float dis = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);
282
283 float fx, fy, fz;
284 m_caster->GetClosePoint(fx, fy, fz, unitTarget->GetObjectSize(), dis);
285
286 unitTarget->NearTeleportTo(fx, fy, fz, -m_caster->GetOrientation(), unitTarget == m_caster);
287}
288
290{
292 return;
293
295 return;
296
297 Player* player = m_caster->ToPlayer();
298 if (!player)
299 return;
300
301 SF_LOG_DEBUG("spells", "Spell Effect: Stuck");
302 SF_LOG_INFO("spells", "Player %s (guid %u) used auto-unstuck future at map %u (%f, %f, %f)", player->GetName().c_str(), player->GetGUIDLow(), player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
303
304 if (player->IsInFlight())
305 return;
306
307 player->TeleportTo(player->GetStartPosition(), TELE_TO_SPELL);
308 // homebind location is loaded always
309 // target->TeleportTo(target->m_homebindMapId, target->m_homebindX, target->m_homebindY, target->m_homebindZ, target->GetOrientation(), (m_caster == m_caster ? TELE_TO_SPELL : 0));
310
311 // Stuck spell trigger Hearthstone cooldown
312 SpellInfo const* spellInfo =
314 if (!spellInfo)
315 return;
316 Spell spell(player, spellInfo, TRIGGERED_FULL_MASK);
317 spell.SendSpellCooldown();
318}
319
321{
323 return;
324
325 if (!unitTarget || unitTarget->IsInFlight())
326 return;
327
328 if (!m_targets.HasDst())
329 return;
330
331 Position pos;
332 destTarget->GetPosition(&pos);
333 unitTarget->GetFirstCollisionPosition(pos, unitTarget->GetDistance(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() + 2.0f), 0.0f);
334 unitTarget->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), unitTarget == m_caster);
335}
336
338{
339 if (!unitTarget)
340 return;
341
343 {
344 // Spell is not using explicit target - no generated path
345 if (m_preGeneratedPath.GetPathType() == PATHFIND_BLANK)
346 {
347 Position pos;
348 unitTarget->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ);
349 unitTarget->GetFirstCollisionPosition(pos, unitTarget->GetObjectSize(), unitTarget->GetRelativeAngle(m_caster));
350 m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ);
351 }
352 else
353 m_caster->GetMotionMaster()->MoveCharge(m_preGeneratedPath);
354 }
355
357 {
358 // not all charge effects used in negative spells
359 if (!m_spellInfo->IsPositive() && m_caster->GetTypeId() == TypeID::TYPEID_PLAYER)
360 m_caster->Attack(unitTarget, true);
361 }
362}
363
365{
367 return;
368
369 if (m_targets.HasDst())
370 {
371 Position pos;
372 destTarget->GetPosition(&pos);
373 float angle = m_caster->GetRelativeAngle(pos.GetPositionX(), pos.GetPositionY());
374 float dist = m_caster->GetDistance(pos);
375 m_caster->GetFirstCollisionPosition(pos, dist, angle);
376
377 m_caster->GetMotionMaster()->MoveCharge(pos.m_positionX, pos.m_positionY, pos.m_positionZ);
378 }
379}
380
382{
384 return;
385
386 if (!unitTarget)
387 return;
388
389 if (Creature* creatureTarget = unitTarget->ToCreature())
390 if (creatureTarget->isWorldBoss() || creatureTarget->IsDungeonBoss())
391 return;
392
393 // Spells with SPELL_EFFECT_KNOCK_BACK (like Thunderstorm) can't knockback target if target has ROOT/STUN
394 if (unitTarget->HasUnitState(UNIT_STATE_ROOT | UNIT_STATE_STUNNED))
395 return;
396
397 // Instantly interrupt non melee spells being casted
398 if (unitTarget->IsNonMeleeSpellCasted(true))
399 unitTarget->InterruptNonMeleeSpells(true);
400
401 float ratio = 0.1f;
402 float speedxy = float(m_spellInfo->Effects[effIndex].MiscValue) * ratio;
403 float speedz = float(damage) * ratio;
404 if (speedxy < 0.1f && speedz < 0.1f)
405 return;
406
407 float x, y;
408 if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_KNOCK_BACK_DEST)
409 {
410 if (m_targets.HasDst())
411 destTarget->GetPosition(x, y);
412 else
413 return;
414 }
415 else //if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_KNOCK_BACK)
416 {
417 m_caster->GetPosition(x, y);
418 }
419
420 unitTarget->KnockbackFrom(x, y, speedxy, speedz);
421}
422
424{
426 return;
427
428 if (!unitTarget)
429 return;
430
431 float speedxy = float(m_spellInfo->Effects[effIndex].MiscValue) / 10;
432 float speedz = float(damage / 10);
433 //1891: Disengage
434 m_caster->JumpTo(speedxy, speedz, m_spellInfo->SpellIconID != 1891);
435}
436
438{
440 return;
441
442 if (!unitTarget || unitTarget->GetTypeId() != TypeID::TYPEID_PLAYER)
443 return;
444
445 unitTarget->ToPlayer()->ActivateTaxiPathTo(m_spellInfo->Effects[effIndex].MiscValue, m_spellInfo->Id);
446}
447
449{
451 return;
452
453 if (!unitTarget)
454 return;
455
456 float speedZ = (float)(m_spellInfo->Effects[effIndex].CalcValue() / 10);
457 float speedXY = (float)(m_spellInfo->Effects[effIndex].MiscValue / 10);
458 Position pos;
459 if (m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_PULL_TOWARDS_DEST)
460 {
461 if (m_targets.HasDst())
462 pos.Relocate(*destTarget);
463 else
464 return;
465 }
466 else //if (m_spellInfo->Effects[i].Effect == SPELL_EFFECT_PULL_TOWARDS)
467 {
468 pos.Relocate(m_caster);
469 }
470
471 unitTarget->GetMotionMaster()->MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), speedXY, speedZ);
472}
473
475{
477 return;
478
479 if (!unitTarget || unitTarget->GetTypeId() != TypeID::TYPEID_PLAYER)
480 return;
481 uint32 nodeid = m_spellInfo->Effects[effIndex].MiscValue;
482 if (sTaxiNodesStore.LookupEntry(nodeid))
483 unitTarget->ToPlayer()->GetSession()->SendDiscoverNewTaxiNode(nodeid);
484}
485
487{
489 return;
490
491 if (!unitTarget || unitTarget->GetTypeId() != TypeID::TYPEID_PLAYER)
492 return;
493
494 Player* player = unitTarget->ToPlayer();
495
496 WorldLocation homeLoc;
497 uint32 areaId = player->GetAreaId();
498
499 if (m_spellInfo->Effects[effIndex].MiscValue)
500 areaId = m_spellInfo->Effects[effIndex].MiscValue;
501
502 if (m_targets.HasDst())
503 homeLoc.WorldRelocate(*destTarget);
504 else
505 {
506 player->GetPosition(&homeLoc);
507 homeLoc.m_mapId = player->GetMapId();
508 }
509
510 player->SetHomebind(homeLoc, areaId);
511
512 // binding
513 WorldPacket data(SMSG_BIND_POINT_UPDATE, 4 + 4 + 4 + 4 + 4);
514 data << float(homeLoc.GetPositionX());
515 data << float(homeLoc.GetPositionY());
516 data << float(homeLoc.GetPositionZ());
517 data << uint32(areaId);
518 data << uint32(homeLoc.GetMapId());
519
520 player->SendDirectMessage(&data);
521
522 SF_LOG_DEBUG("spells", "EffectBind: New homebind X: %f, Y: %f, Z: %f, MapId: %u, AreaId: %u",
523 homeLoc.GetPositionX(), homeLoc.GetPositionY(), homeLoc.GetPositionZ(), homeLoc.GetMapId(), areaId);
524
525 ObjectGuid guid = m_caster->GetGUID();
526
527 // zone update
528 data.Initialize(SMSG_PLAYERBOUND, 1 + 8 + 4);
529 data.WriteGuidMask(guid, 2, 4, 0, 3, 6, 7, 5, 1);
530 data.WriteGuidMask(guid, 6, 1, 2, 3, 4, 5, 7, 0);
531 data << uint32(areaId);
532 player->SendDirectMessage(&data);
533}
@ IN_MILLISECONDS
Definition Common.h:125
DBCStorage< TaxiNodesEntry > sTaxiNodesStore(TaxiNodesEntryfmt)
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
@ DYNAMIC_OBJECT_FARSIGHT_FOCUS
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
#define SF_LOG_INFO(filterType__,...)
Definition Log.h:137
@ TYPEID_PLAYER
Definition Object.h:55
@ TYPEID_UNIT
Definition Object.h:54
#define CONTACT_DISTANCE
Definition Object.h:20
#define MAPID_INVALID
Definition Object.h:531
@ HIGHGUID_DYNAMICOBJECT
#define sObjectMgr
Definition ObjectMgr.h:1617
@ PATHFIND_BLANK
@ TELE_TO_SPELL
Definition Player.h:833
SpellEffIndex
@ SPELL_EFFECT_PULL_TOWARDS_DEST
@ SPELL_EFFECT_KNOCK_BACK_DEST
@ SPELL_EFFECT_HANDLE_LAUNCH_TARGET
Definition Spell.h:275
@ SPELL_EFFECT_HANDLE_LAUNCH
Definition Spell.h:274
@ SPELL_EFFECT_HANDLE_HIT
Definition Spell.h:276
@ SPELL_EFFECT_HANDLE_HIT_TARGET
Definition Spell.h:277
#define sSpellMgr
Definition SpellMgr.h:744
@ TRIGGERED_FULL_MASK
Will ignore most target checks (mostly DBC target checks).
Definition Unit.h:435
@ UNIT_STATE_CONFUSED
Definition Unit.h:523
@ UNIT_STATE_ROOT
Definition Unit.h:522
@ UNIT_STATE_FLEEING
Definition Unit.h:519
@ UNIT_STATE_MOVING
Definition Unit.h:542
@ UNIT_STATE_STUNNED
Definition Unit.h:515
bool roll_chance_i(int chance)
Definition Util.h:89
void WriteGuidMask(const ObjectGuid &guid, Offsets... offsets)
Definition ByteBuffer.h:248
bool CreateDynamicObject(uint32 guidlow, Unit *caster, SpellInfo const *spell, Position const &pos, float radius, DynamicObjectType type)
void SetCasterViewpoint()
void SetDuration(int32 newDuration)
uint32 GetGUIDLow() const
Definition Object.h:120
void SendDirectMessage(WorldPacket *data)
Definition Player.cpp:6904
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options=0)
Definition Player.cpp:2090
void SetHomebind(WorldLocation const &loc, uint32 areaId)
Definition Player.cpp:12141
WorldLocation GetStartPosition() const
Definition Player.cpp:18057
void EffectJump(SpellEffIndex effIndex)
SpellCastTargets m_targets
Definition Spell.h:535
void EffectNULL(SpellEffIndex effIndex)
void EffectAddFarsight(SpellEffIndex effIndex)
void EffectStuck(SpellEffIndex effIndex)
int32 damage
Definition Spell.h:630
void EffectJumpDest(SpellEffIndex effIndex)
SpellEffectHandleMode effectHandleMode
Definition Spell.h:631
void EffectPullTowards(SpellEffIndex effIndex)
Unit *const m_caster
Definition Spell.h:581
Spell(Unit *caster, SpellInfo const *info, TriggerCastFlags triggerFlags, uint64 originalCasterGUID=0, bool skipCheck=false)
Definition Spell.cpp:500
void EffectChargeDest(SpellEffIndex effIndex)
void EffectTeleportUnits(SpellEffIndex effIndex)
void EffectCharge(SpellEffIndex effIndex)
void SendSpellCooldown()
Definition Spell.cpp:3650
void EffectDiscoverTaxi(SpellEffIndex effIndex)
void EffectLeap(SpellEffIndex effIndex)
void EffectTeleUnitsFaceCaster(SpellEffIndex effIndex)
PathGenerator m_preGeneratedPath
Definition Spell.h:761
Unit * unitTarget
Definition Spell.h:626
void EffectLeapBack(SpellEffIndex effIndex)
void EffectPull(SpellEffIndex effIndex)
void CalculateJumpSpeeds(uint8 i, float dist, float &speedxy, float &speedz)
WorldLocation * destTarget
Definition Spell.h:629
void EffectSendTaxi(SpellEffIndex effIndex)
void EffectKnockBack(SpellEffIndex effIndex)
void EffectBind(SpellEffIndex effIndex)
void EffectDistract(SpellEffIndex effIndex)
SpellInfo const *const m_spellInfo
Definition Spell.h:530
bool IsInFlight() const
Definition Unit.h:1891
uint32 GetMapId() const
Definition Object.h:546
void WorldRelocate(const WorldLocation &loc)
Definition Object.h:542
uint32 m_mapId
Definition Object.h:548
std::string const & GetName() const
Definition Object.h:664
uint32 GetAreaId() const
Definition Object.cpp:1602
void Initialize(Opcodes opcode, size_t newres=200)
Definition WorldPacket.h:31
@ SMSG_BIND_POINT_UPDATE
Definition Opcodes.h:563
@ SMSG_PLAYERBOUND
Definition Opcodes.h:877
#define sWorld
Definition World.h:910
@ CONFIG_CAST_UNSTUCK
Definition World.h:106
uint32 GetStuckHearthstoneCooldownSpellId()
uint32 GetArea52RipperPostEffectSpellId(uint32 randomEffect, uint32 team)
uint32 GetToshleysTransporterPostEffectSpellId(uint32 randomEffect, uint32 team)
JumpDestOverride const * GetJumpDestOverride(uint32 spellId)
uint32 GetEverlookRipperPostEffectSpellId(uint32 roll)
TeleportPostEffect const * GetTeleportPostEffect(uint32 spellId)
float m_positionZ
Definition Object.h:289
float m_positionX
Definition Object.h:287
float GetPositionZ() const
Definition Object.h:330
float m_positionY
Definition Object.h:288
float GetOrientation() const
Definition Object.h:331
float GetPositionX() const
Definition Object.h:328
void GetPosition(float &x, float &y) const
Definition Object.h:333
float GetPositionY() const
Definition Object.h:329
void Relocate(float x, float y)
Definition Object.h:302