Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-03-03 11:58:01 +08:00
59 changed files with 3523 additions and 450 deletions

View File

@@ -2769,15 +2769,6 @@ Rate.RewardBonusMoney = 1
MonsterSight = 50.000000
#
# ThreatRadius
# Description: Distance for creatures to evade after being pulled away from the combat
# starting point. If ThreatRadius is less than creature aggro radius then aggro
# radius will be used.
# Default: 60
ThreatRadius = 60
#
# Rate.Creature.Aggro
# Description: Aggro radius percentage.

View File

@@ -348,7 +348,7 @@ void CreatureAI::MoveCircleChecks()
!victim ||
!me->IsFreeToMove() || me->HasUnitMovementFlag(MOVEMENTFLAG_ROOT) ||
!me->IsWithinMeleeRange(victim) || me == victim->GetVictim() ||
(victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet()) // only player & pets to save CPU
(!victim->IsPlayer() && !victim->IsPet()) // only player & pets to save CPU
)
{
return;
@@ -357,14 +357,12 @@ void CreatureAI::MoveCircleChecks()
me->GetMotionMaster()->MoveCircleTarget(me->GetVictim());
}
void CreatureAI::MoveBackwardsChecks() {
void CreatureAI::MoveBackwardsChecks()
{
Unit *victim = me->GetVictim();
if (
!victim ||
!me->IsFreeToMove() || me->HasUnitMovementFlag(MOVEMENTFLAG_ROOT) ||
(victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet())
)
if (!victim || !me->IsFreeToMove() || me->HasUnitMovementFlag(MOVEMENTFLAG_ROOT) ||
(!victim->IsPlayer() && !victim->IsPet()))
{
return;
}

View File

@@ -191,8 +191,7 @@ bool SummonList::IsAnyCreatureInCombat() const
ScriptedAI::ScriptedAI(Creature* creature) : CreatureAI(creature),
me(creature),
IsFleeing(false),
_isCombatMovementAllowed(true)
IsFleeing(false)
{
_isHeroic = me->GetMap()->IsHeroic();
_difficulty = Difficulty(me->GetMap()->GetSpawnMode());
@@ -209,7 +208,7 @@ void ScriptedAI::AttackStartNoMove(Unit* who)
void ScriptedAI::AttackStart(Unit* who)
{
if (IsCombatMovementAllowed())
if (me->IsCombatMovementAllowed())
CreatureAI::AttackStart(who);
else
AttackStartNoMove(who);
@@ -537,11 +536,6 @@ void ScriptedAI::SetEquipmentSlots(bool loadDefault, int32 mainHand /*= EQUIP_NO
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, uint32(ranged));
}
void ScriptedAI::SetCombatMovement(bool allowMovement)
{
_isCombatMovementAllowed = allowMovement;
}
enum eNPCs
{
NPC_BROODLORD = 12017,

View File

@@ -373,14 +373,6 @@ struct ScriptedAI : public CreatureAI
void SetEquipmentSlots(bool loadDefault, int32 mainHand = EQUIP_NO_CHANGE, int32 offHand = EQUIP_NO_CHANGE, int32 ranged = EQUIP_NO_CHANGE);
// Used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims
// NOTE: If you use SetCombatMovement while the creature is in combat, it will do NOTHING - This only affects AttackStart
// You should make the necessary to make it happen so.
// Remember that if you modified _isCombatMovementAllowed (e.g: using SetCombatMovement) it will not be reset at Reset().
// It will keep the last value you set.
void SetCombatMovement(bool allowMovement);
bool IsCombatMovementAllowed() const { return _isCombatMovementAllowed; }
virtual bool CheckEvadeIfOutOfCombatArea() const { return false; }
// return true for heroic mode. i.e.
@@ -452,7 +444,6 @@ struct ScriptedAI : public CreatureAI
private:
Difficulty _difficulty;
bool _isCombatMovementAllowed;
bool _isHeroic;
std::unordered_set<uint32> _uniqueTimedEvents;
};

View File

@@ -64,7 +64,7 @@ void npc_escortAI::AttackStart(Unit* who)
me->StopMoving();
}
if (IsCombatMovementAllowed())
if (me->IsCombatMovementAllowed())
me->GetMotionMaster()->MoveChase(who);
}
}
@@ -178,8 +178,8 @@ void npc_escortAI::JustRespawned()
{
RemoveEscortState(STATE_ESCORT_ESCORTING | STATE_ESCORT_RETURNING | STATE_ESCORT_PAUSED);
if (!IsCombatMovementAllowed())
SetCombatMovement(true);
if (!me->IsCombatMovementAllowed())
me->SetCombatMovement(true);
//add a small delay before going to first waypoint, normal in near all cases
m_uiWPWaitTimer = 1000;

View File

@@ -55,7 +55,7 @@ void FollowerAI::AttackStart(Unit* who)
if (me->HasUnitState(UNIT_STATE_FOLLOW))
me->ClearUnitState(UNIT_STATE_FOLLOW);
if (IsCombatMovementAllowed())
if (me->IsCombatMovementAllowed())
me->GetMotionMaster()->MoveChase(who);
}
}
@@ -141,8 +141,8 @@ void FollowerAI::JustRespawned()
{
m_uiFollowState = STATE_FOLLOW_NONE;
if (!IsCombatMovementAllowed())
SetCombatMovement(true);
if (!me->IsCombatMovementAllowed())
me->SetCombatMovement(true);
if (me->GetFaction() != me->GetCreatureTemplate()->faction)
me->SetFaction(me->GetCreatureTemplate()->faction);

View File

@@ -3456,6 +3456,8 @@ void SmartScript::GetTargets(ObjectVector& targets, SmartScriptHolder const& e,
for (WorldObject* unit : units)
if (IsPlayer(unit) && baseObject->IsInRange(unit, float(e.target.playerRange.minDist), float(e.target.playerRange.maxDist)))
targets.push_back(unit);
if (e.target.playerRange.maxCount)
Acore::Containers::RandomResize(targets, e.target.playerRange.maxCount);
break;
}
case SMART_TARGET_PLAYER_DISTANCE:

View File

@@ -220,7 +220,7 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(),
m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_regenPower(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false),
m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTimer(0),
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false)
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false), _isCombatMovementAllowed(true)
{
m_regenTimer = CREATURE_REGEN_INTERVAL;
m_valuesCount = UNIT_END;
@@ -877,7 +877,7 @@ bool Creature::IsFreeToMove()
{
uint32 moveFlags = m_movementInfo.GetMovementFlags();
// Do not reposition ourself when we are not allowed to move
if ((IsMovementPreventedByCasting() || isMoving() || !CanFreeMove()) &&
if ((IsMovementPreventedByCasting() || isMoving() || !CanFreeMove() || !IsCombatMovementAllowed()) &&
(GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE ||
moveFlags & MOVEMENTFLAG_SPLINE_ENABLED))
{
@@ -3739,6 +3739,11 @@ bool Creature::CanCastSpell(uint32 spellID) const
return true;
}
void Creature::SetCombatMovement(bool allowMovement)
{
_isCombatMovementAllowed = allowMovement;
}
ObjectGuid Creature::GetSummonerGUID() const
{
if (TempSummon const* temp = ToTempSummon())

View File

@@ -413,6 +413,14 @@ public:
* */
[[nodiscard]] ObjectGuid GetSummonerGUID() const;
// Used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims
// NOTE: If you use SetCombatMovement while the creature is in combat, it will do NOTHING - This only affects AttackStart
// You should make the necessary to make it happen so.
// Remember that if you modified _isCombatMovementAllowed (e.g: using SetCombatMovement) it will not be reset at Reset().
// It will keep the last value you set.
void SetCombatMovement(bool allowMovement);
bool IsCombatMovementAllowed() const { return _isCombatMovementAllowed; }
std::string GetDebugInfo() const override;
protected:
@@ -501,6 +509,7 @@ private:
uint32 _playerDamageReq;
bool _damagedByPlayer;
bool _isCombatMovementAllowed;
};
class AssistDelayEvent : public BasicEvent

View File

@@ -19,6 +19,8 @@
#include "Config.h"
#include "Log.h"
#include "Timer.h"
#include <algorithm>
#include <iterator>
// create instance
WorldUpdateTime sWorldUpdateTime;
@@ -71,8 +73,34 @@ uint32 UpdateTime::GetLastUpdateTime() const
return _updateTimeDataTable[_updateTimeTableIndex != 0 ? _updateTimeTableIndex - 1 : _updateTimeDataTable.size() - 1];
}
uint32 UpdateTime::GetDatasetSize() const
{
return _updateTimeDataTable[_updateTimeDataTable.size() - 1] == 0 ? _updateTimeTableIndex : _orderedUpdateTimeDataTable.size();
}
uint32 UpdateTime::GetPercentile(uint8 p)
{
if (_needsReorder)
SortUpdateTimeDataTable();
// Calculate the index of the element corresponding to the percentile
double index = (double(p) / 100.0) * (GetDatasetSize() - 1);
// If the index is an integer, return the value at that index
if (index == floor(index))
return _orderedUpdateTimeDataTable[index];
// Otherwise, perform linear interpolation
int lowerIndex = floor(index);
int upperIndex = ceil(index);
double fraction = index - lowerIndex;
return _orderedUpdateTimeDataTable[lowerIndex] * (1 - fraction) + _orderedUpdateTimeDataTable[upperIndex] * fraction;
}
void UpdateTime::UpdateWithDiff(uint32 diff)
{
_needsReorder = true;
_totalUpdateTime = _totalUpdateTime - _updateTimeDataTable[_updateTimeTableIndex] + diff;
_updateTimeDataTable[_updateTimeTableIndex] = diff;
@@ -100,6 +128,26 @@ void UpdateTime::RecordUpdateTimeReset()
_recordedTime = GetTimeMS();
}
void UpdateTime::SortUpdateTimeDataTable()
{
if (!_needsReorder)
return;
auto endUpdateTable = _updateTimeDataTable.end();
if (!_updateTimeDataTable[_updateTimeDataTable.size() - 1])
endUpdateTable = std::next(_updateTimeDataTable.begin(), _updateTimeTableIndex);
std::copy(_updateTimeDataTable.begin(), endUpdateTable, _orderedUpdateTimeDataTable.begin());
auto endOrderedUpdateTable = _orderedUpdateTimeDataTable.end();
if (!_updateTimeDataTable[_updateTimeDataTable.size() - 1])
endOrderedUpdateTable = std::next(_orderedUpdateTimeDataTable.begin(), _updateTimeTableIndex);
std::sort(_orderedUpdateTimeDataTable.begin(), endOrderedUpdateTable);
_needsReorder = false;
}
void WorldUpdateTime::LoadFromConfig()
{
_recordUpdateTimeInverval = Milliseconds(sConfigMgr->GetOption<uint32>("RecordUpdateTimeDiffInterval", 60000));
@@ -117,7 +165,10 @@ void WorldUpdateTime::RecordUpdateTime(Milliseconds gameTimeMs, uint32 diff, uin
{
if (GetMSTimeDiff(_lastRecordTime, gameTimeMs) > _recordUpdateTimeInverval)
{
LOG_INFO("time.update", "Update time diff: {}. Players online: {}.", GetAverageUpdateTime(), sessionCount);
LOG_INFO("time.update", "Last {} diffs summary with {} players online:", GetDatasetSize(), sessionCount);
LOG_INFO("time.update", " - Mean: {};", GetAverageUpdateTime());
LOG_INFO("time.update", " - Median: {};", GetPercentile(50));
LOG_INFO("time.update", " - Percentiles (95, 99, max): {}, {}, {}.", GetPercentile(95), GetPercentile(99), GetPercentile(100));
_lastRecordTime = gameTimeMs;
}
}

View File

@@ -35,6 +35,8 @@ public:
uint32 GetMaxUpdateTime() const;
uint32 GetMaxUpdateTimeOfCurrentTable() const;
uint32 GetLastUpdateTime() const;
uint32 GetDatasetSize() const;
uint32 GetPercentile(uint8 p);
void UpdateWithDiff(uint32 diff);
@@ -43,6 +45,8 @@ public:
protected:
UpdateTime();
void SortUpdateTimeDataTable();
private:
DiffTableArray _updateTimeDataTable;
uint32 _averageUpdateTime;
@@ -52,6 +56,9 @@ private:
uint32 _maxUpdateTimeOfLastTable;
uint32 _maxUpdateTimeOfCurrentTable;
DiffTableArray _orderedUpdateTimeDataTable;
bool _needsReorder;
Milliseconds _recordedTime;
};

View File

@@ -282,7 +282,13 @@ public:
handler->PSendSysMessage("Connection peak: %u.", connPeak);
handler->PSendSysMessage(LANG_UPTIME, secsToTimeString(GameTime::GetUptime().count()).c_str());
handler->PSendSysMessage("Update time diff: %ums, average: %ums.", sWorldUpdateTime.GetLastUpdateTime(), sWorldUpdateTime.GetAverageUpdateTime());
handler->PSendSysMessage("Update time diff: %ums. Last %d diffs summary:", sWorldUpdateTime.GetLastUpdateTime(), sWorldUpdateTime.GetDatasetSize());
handler->PSendSysMessage("- Mean: %ums", sWorldUpdateTime.GetAverageUpdateTime());
handler->PSendSysMessage("- Median: %ums", sWorldUpdateTime.GetPercentile(50));
handler->PSendSysMessage("- Percentiles (95, 99, max): %ums, %ums, %ums",
sWorldUpdateTime.GetPercentile(95),
sWorldUpdateTime.GetPercentile(99),
sWorldUpdateTime.GetPercentile(100));
//! Can't use sWorld->ShutdownMsg here in case of console command
if (sWorld->IsShuttingDown())

View File

@@ -45,7 +45,7 @@ struct boss_quartermaster_zigris : public BossAI
void Reset() override
{
_Reset();
SetCombatMovement(false);
me->SetCombatMovement(false);
_hasDrunkPotion = false;
}
@@ -120,11 +120,11 @@ struct boss_quartermaster_zigris : public BossAI
{
DoCastVictim(SPELL_SHOOT);
me->GetMotionMaster()->Clear();
SetCombatMovement(false);
me->SetCombatMovement(false);
}
else if (!me->IsWithinLOSInMap(me->GetVictim()))
{
SetCombatMovement(true);
me->SetCombatMovement(true);
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveChase(me->GetVictim());
}

View File

@@ -359,7 +359,7 @@ public:
Talk(SAY_GAMESBEGIN_2);
DoCast(me, SPELL_NEFARIANS_BARRIER);
SetCombatMovement(false);
me->SetCombatMovement(false);
me->SetImmuneToPC(false);
AttackStart(SelectTarget(SelectTargetMethod::Random, 0, 200.f, true));
events.ScheduleEvent(EVENT_SHADOWBLINK, 500ms);

View File

@@ -159,7 +159,7 @@ struct boss_dorothee : public ScriptedAI
{
boss_dorothee(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
//this is kinda a big no-no. but it will prevent her from moving to chase targets. she should just cast her spells. in this case, since there is not really something to LOS her with or get out of range this would work. but a more elegant solution would be better
instance = creature->GetInstanceScript();

View File

@@ -123,7 +123,7 @@ struct boss_jeklik : public BossAI
me->SetDisableGravity(false);
me->SetReactState(REACT_PASSIVE);
BossAI::SetCombatMovement(false);
BossAI::me->SetCombatMovement(false);
batRidersCount = 0;
DoCastSelf(SPELL_GREEN_CHANNELING, true);
@@ -148,7 +148,7 @@ struct boss_jeklik : public BossAI
BossAI::PathEndReached(pathId);
me->SetDisableGravity(false);
SetCombatMovement(true);
me->SetCombatMovement(true);
me->SetReactState(REACT_AGGRESSIVE);
//

View File

@@ -2168,7 +2168,7 @@ public:
{
boss_blight_wormAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void Reset() override

View File

@@ -134,7 +134,7 @@ public:
{
npc_andorhal_towerAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void MoveInLineOfSight(Unit* who) override

View File

@@ -1411,7 +1411,7 @@ public:
{
alliance_riflemanAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
uint32 ExplodeTimer;

View File

@@ -84,7 +84,7 @@ struct boss_ayamiss : public BossAI
void Reset() override
{
BossAI::Reset();
SetCombatMovement(false);
me->SetCombatMovement(false);
me->SetReactState(REACT_AGGRESSIVE);
ScheduleHealthCheckEvent(70, [&] {
@@ -127,7 +127,7 @@ struct boss_ayamiss : public BossAI
}
else if (type == WAYPOINT_MOTION_TYPE && id == POINT_GROUND)
{
SetCombatMovement(true);
me->SetCombatMovement(true);
me->SetDisableGravity(false);
me->m_Events.AddEventAtOffset([this]()

View File

@@ -188,7 +188,7 @@ struct npc_buru_egg : public ScriptedAI
npc_buru_egg(Creature* creature) : ScriptedAI(creature)
{
_instance = me->GetInstanceScript();
SetCombatMovement(false);
me->SetCombatMovement(false);
me->SetReactState(REACT_PASSIVE);
me->SetControlled(true, UNIT_STATE_STUNNED);
}

View File

@@ -147,7 +147,7 @@ struct boss_eye_of_cthun : public BossAI
{
boss_eye_of_cthun(Creature* creature) : BossAI(creature, DATA_CTHUN)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
me->m_SightDistance = 90.f;
}
@@ -377,7 +377,7 @@ struct boss_cthun : public BossAI
{
boss_cthun(Creature* creature) : BossAI(creature, DATA_CTHUN)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void Reset() override
@@ -597,7 +597,7 @@ struct npc_eye_tentacle : public ScriptedAI
}
}
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void JustDied(Unit* /*killer*/) override
@@ -651,7 +651,7 @@ struct npc_claw_tentacle : public ScriptedAI
{
npc_claw_tentacle(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{
@@ -720,7 +720,7 @@ struct npc_giant_claw_tentacle : public ScriptedAI
{
npc_giant_claw_tentacle(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{
@@ -870,7 +870,7 @@ struct npc_giant_eye_tentacle : public ScriptedAI
{
npc_giant_eye_tentacle(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{

View File

@@ -106,7 +106,7 @@ struct boss_ouro : public BossAI
{
boss_ouro(Creature* creature) : BossAI(creature, DATA_OURO)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
me->SetControlled(true, UNIT_STATE_ROOT);
}

View File

@@ -366,7 +366,7 @@ struct npc_toxic_slime : public ScriptedAI
void InitializeAI() override
{
SetCombatMovement(false);
me->SetCombatMovement(false);
DoCastSelf(SPELL_TOXIN);
InstanceScript* instance = me->GetInstanceScript();

View File

@@ -99,7 +99,7 @@ public:
{
npc_tiger_matriarch_creditAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
events.ScheduleEvent(EVENT_CHECK_SUMMON_AURA, 2s);
}

View File

@@ -235,7 +235,7 @@ struct npc_amanitar_mushrooms : public ScriptedAI
{
npc_amanitar_mushrooms(Creature* pCreature) : ScriptedAI(pCreature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
//TODO: this prolly needs to be done in database
pCreature->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);

View File

@@ -295,7 +295,7 @@ struct boss_jedoga_shadowseeker : public BossAI
{
if (!ritualTriggered && me->HealthBelowPctDamaged(55, damage) && events.IsInPhase(PHASE_NORMAL))
{
SetCombatMovement(false);
me->SetCombatMovement(false);
me->InterruptNonMeleeSpells(false);
me->AttackStop();
me->SetReactState(REACT_PASSIVE);
@@ -368,7 +368,7 @@ struct boss_jedoga_shadowseeker : public BossAI
me->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL);
me->RemoveAurasDueToSpell(SPELL_LIGHTNING_BOLTS);
me->RemoveAurasDueToSpell(SPELL_HOVER_FALL);
SetCombatMovement(true);
me->SetCombatMovement(true);
me->SetDisableGravity(false);
me->SetHover(false);

View File

@@ -606,14 +606,14 @@ struct boss_jormungarAI : public ScriptedAI
if( bIsStationary )
{
me->SetNativeDisplayId(_MODEL_MOBILE);
SetCombatMovement(true);
me->SetCombatMovement(true);
if( Unit* victim = me->GetVictim() )
me->GetMotionMaster()->MoveChase(victim);
}
else
{
me->SetNativeDisplayId(_MODEL_STATIONARY);
SetCombatMovement(false);
me->SetCombatMovement(false);
}
me->RemoveAurasDueToSpell(SPELL_SUBMERGE_0);
me->CastSpell(me, SPELL_EMERGE_0, false);
@@ -692,7 +692,7 @@ public:
_MODEL_STATIONARY = MODEL_ACIDMAW_STATIONARY;
_MODEL_MOBILE = MODEL_ACIDMAW_MOBILE;
_TYPE_OTHER = TYPE_DREADSCALE;
SetCombatMovement(false);
me->SetCombatMovement(false);
}
};

View File

@@ -1525,7 +1525,7 @@ public:
{
boss_yoggsaron_crusher_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
me->CastSpell(me, SPELL_CRUSH, true);
me->CastSpell(me, SPELL_FOCUSED_ANGER, true);
me->CastSpell(me, SPELL_DIMINISH_POWER, false);
@@ -1587,7 +1587,7 @@ public:
{
boss_yoggsaron_corruptor_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void DoAction(int32 param) override
@@ -1644,7 +1644,7 @@ public:
{
boss_yoggsaron_constrictor_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
_checkTimer = 1;
_playerGUID.Clear();
}

View File

@@ -1049,7 +1049,7 @@ public:
{
npc_warmage_coldarraAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
uint32 m_uiTimer; //Timer until recast

View File

@@ -147,7 +147,7 @@ struct npc_warmage_violetstand : public ScriptedAI
{
npc_warmage_violetstand(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
ObjectGuid targetGUID;

View File

@@ -1532,7 +1532,7 @@ public:
{
npc_guardian_pavilionAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void MoveInLineOfSight(Unit* who) override
@@ -1596,7 +1596,7 @@ public:
{
npc_tournament_training_dummyAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);
}
@@ -1816,7 +1816,7 @@ public:
PhaseCount = 0;
Summons.DespawnAll();
SetCombatMovement(false);
me->SetCombatMovement(false);
}
EventMap events;

View File

@@ -57,7 +57,7 @@ struct boss_murmur : public BossAI
{
boss_murmur(Creature* creature) : BossAI(creature, DATA_MURMUR)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);

View File

@@ -149,6 +149,23 @@ class spell_morogrim_tidewalker_watery_grave : public SpellScript
return true;
}
void FilterTargets(std::list<WorldObject*>& targets)
{
uint8 maxSize = 4;
Unit* caster = GetCaster();
targets.remove_if([caster](WorldObject const* target) -> bool
{
// Should not target current victim.
return caster->GetVictim() == target;
});
if (targets.size() > maxSize)
{
Acore::Containers::RandomResize(targets, maxSize);
}
}
void HandleDummy(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
@@ -159,6 +176,7 @@ class spell_morogrim_tidewalker_watery_grave : public SpellScript
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_morogrim_tidewalker_watery_grave::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
OnEffectHitTarget += SpellEffectFn(spell_morogrim_tidewalker_watery_grave::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}

View File

@@ -98,7 +98,7 @@ struct boss_ahune : public ScriptedAI
{
boss_ahune(Creature* c) : ScriptedAI(c), summons(me)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
SetEquipmentSlots(false, 54806, EQUIP_UNEQUIP, EQUIP_UNEQUIP);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
InvokerGUID.Clear();

View File

@@ -41,7 +41,7 @@ struct boss_omor_the_unscarred : public BossAI
{
boss_omor_the_unscarred(Creature* creature) : BossAI(creature, DATA_OMOR_THE_UNSCARRED)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);

View File

@@ -69,7 +69,8 @@ enum Misc
EVENT_SPELL_BERSERK = 3,
EVENT_MOVE_TO_PHASE_2 = 4,
EVENT_FINISH_DIVE = 5
EVENT_FINISH_DIVE = 5,
EVENT_INVISIBLE = 6
};
enum GroupAlar
@@ -89,7 +90,7 @@ struct boss_alar : public BossAI
boss_alar(Creature* creature) : BossAI(creature, DATA_ALAR)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void JustReachedHome() override
@@ -172,22 +173,25 @@ struct boss_alar : public BossAI
if (damage >= me->GetHealth() && _platform < POINT_MIDDLE)
{
damage = 0;
me->SetReactState(REACT_PASSIVE);
scheduler.CancelAll();
me->CastStop();
me->SetHealth(me->GetMaxHealth());
DoCastSelf(SPELL_EMBER_BLAST, true); //spellscript doesn't trigger
DoCastSelf(SPELL_EMBER_BLAST, true);
PretendToDie(me);
ScheduleUniqueTimedEvent(1s, [&]{
me->SetVisible(false);
}, EVENT_INVISIBLE);
ScheduleUniqueTimedEvent(8s, [&]{
me->SetPosition(alarPoints[POINT_MIDDLE]);
}, EVENT_RELOCATE_MIDDLE);
ScheduleUniqueTimedEvent(12s, [&]
{
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetVisible(true);
DoCastSelf(SPELL_CLEAR_ALL_DEBUFFS, true);
DoCastSelf(SPELL_REBIRTH_PHASE2);
}, EVENT_MOVE_TO_PHASE_2);
ScheduleUniqueTimedEvent(16001ms, [&]{
me->SetHealth(me->GetMaxHealth());
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
_platform = POINT_MIDDLE;
me->GetMotionMaster()->MoveChase(me->GetVictim());
ScheduleAbilities();
@@ -195,6 +199,18 @@ struct boss_alar : public BossAI
}
}
void PretendToDie(Creature* creature)
{
scheduler.CancelAll();
creature->InterruptNonMeleeSpells(true);
creature->RemoveAllAuras();
creature->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
creature->SetReactState(REACT_PASSIVE);
creature->GetMotionMaster()->MovementExpired(false);
creature->GetMotionMaster()->MoveIdle();
creature->SetStandState(UNIT_STAND_STATE_DEAD);
}
void ScheduleAbilities()
{
ScheduleTimedEvent(57s, [&]
@@ -394,37 +410,6 @@ class spell_alar_ember_blast : public SpellScript
}
};
class spell_alar_ember_blast_death : public AuraScript
{
PrepareAuraScript(spell_alar_ember_blast_death);
void OnApply(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
{
PreventDefaultAction(); // xinef: prevent default action after change that invisibility in instances is executed instantly even for creatures
Unit* target = GetTarget();
InvisibilityType type = InvisibilityType(aurEff->GetMiscValue());
target->m_invisibility.AddFlag(type);
target->m_invisibility.AddValue(type, aurEff->GetAmount());
GetUnitOwner()->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
GetUnitOwner()->SetStandState(UNIT_STAND_STATE_DEAD);
GetUnitOwner()->m_last_notify_position.Relocate(0.0f, 0.0f, 0.0f);
GetUnitOwner()->m_delayed_unit_relocation_timer = 1000;
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetUnitOwner()->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
GetUnitOwner()->SetStandState(UNIT_STAND_STATE_STAND);
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_alar_ember_blast_death::OnApply, EFFECT_2, SPELL_AURA_MOD_INVISIBILITY, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_alar_ember_blast_death::OnRemove, EFFECT_2, SPELL_AURA_MOD_INVISIBILITY, AURA_EFFECT_HANDLE_REAL);
}
};
class spell_alar_dive_bomb : public AuraScript
{
PrepareAuraScript(spell_alar_dive_bomb);
@@ -446,7 +431,6 @@ void AddSC_boss_alar()
RegisterTheEyeAI(boss_alar);
RegisterSpellScript(spell_alar_flame_quills);
RegisterSpellScript(spell_alar_ember_blast);
RegisterSpellScript(spell_alar_ember_blast_death);
RegisterSpellScript(spell_alar_dive_bomb);
}

View File

@@ -145,6 +145,8 @@ enum Misc
DATA_RESURRECT_CAST = 1,
NPC_WORLD_TRIGGER = 19871,
NPC_NETHER_VAPOR = 21002,
NPC_NETHERSTRAND_LONGBOW = 21268,
NPC_STAFF_OF_DISINTEGRATION = 21274,
PHASE_NONE = 0,
PHASE_SINGLE_ADVISOR = 1,
@@ -207,14 +209,16 @@ enum KaelActions
ACTION_START_SANGUINAR = 0,
ACTION_START_CAPERNIAN = 1,
ACTION_START_TELONICUS = 2,
ACTION_START_WEAPONS = 3
ACTION_START_WEAPONS = 3,
ACTION_PROGRESS_PHASE_CHECK = 4
};
enum SpellGroups
{
GROUP_PYROBLAST = 0,
GROUP_SHOCK_BARRIER = 1,
GROUP_NETHER_BEAM = 2
GROUP_PROGRESS_PHASE = 0,
GROUP_PYROBLAST = 1,
GROUP_SHOCK_BARRIER = 2,
GROUP_NETHER_BEAM = 3
};
const Position triggersPos[6] =
@@ -253,9 +257,12 @@ struct boss_kaelthas : public BossAI
summons.DoForAllSummons([&](WorldObject* summon){
if (Creature* summonedCreature = summon->ToCreature())
{
summonedCreature->SetReactState(REACT_PASSIVE);
summonedCreature->setDeathState(DeathState::JustRespawned);
summonedCreature->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
if (summonedCreature->GetEntry() >= NPC_LORD_SANGUINAR && summonedCreature->GetEntry() <= NPC_THALADRED)
{
summonedCreature->SetReactState(REACT_PASSIVE);
summonedCreature->setDeathState(DeathState::JustRespawned);
summonedCreature->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
}
});
}
@@ -382,11 +389,53 @@ struct boss_kaelthas : public BossAI
}
}
});
ScheduleUniqueTimedEvent(2min, [&]{
scheduler.Schedule(2min, GROUP_PROGRESS_PHASE, [this](TaskContext)
{
PhaseAllAdvisorsExecute();
}, EVENT_PREFIGHT_PHASE61);
});
}, EVENT_PREFIGHT_PHASE52);
break;
case ACTION_PROGRESS_PHASE_CHECK:
if (_phase == PHASE_WEAPONS)
{
bool aliveWeapon = false;
summons.DoForAllSummons([&aliveWeapon](WorldObject* summon)
{
if (Creature* summonedCreature = summon->ToCreature())
{
if (summonedCreature->IsAlive())
{
if (summonedCreature->GetEntry() >= NPC_NETHERSTRAND_LONGBOW && summonedCreature->GetEntry() <= NPC_STAFF_OF_DISINTEGRATION)
{
aliveWeapon = true;
return;
}
}
}
});
if (!aliveWeapon)
PhaseAllAdvisorsExecute();
}
else if (_phase == PHASE_ALL_ADVISORS)
{
bool advisorAlive = false;
summons.DoForAllSummons([&advisorAlive](WorldObject* summon)
{
if (Creature* summonedCreature = summon->ToCreature())
{
if (summonedCreature->IsAlive())
{
if (summonedCreature->GetEntry() >= NPC_LORD_SANGUINAR && summonedCreature->GetEntry() <= NPC_THALADRED)
{
advisorAlive = true;
return;
}
}
}
});
if (!advisorAlive)
PhaseKaelExecute();
}
default:
break;
}
@@ -629,17 +678,7 @@ struct boss_kaelthas : public BossAI
void PhaseAllAdvisorsExecute()
{
//remove all weapons so they don't get revived
summons.DoForAllSummons([&](WorldObject* summon)
{
if (Creature* summonedCreature = summon->ToCreature())
{
if (summonedCreature->GetEntry() >= 21268 && summonedCreature->GetEntry() <= 21274)
{
summonedCreature->DespawnOrUnsummon();
}
}
});
scheduler.CancelGroup(GROUP_PROGRESS_PHASE);
_phase = PHASE_ALL_ADVISORS;
Talk(SAY_PHASE3_ADVANCE);
ScheduleUniqueTimedEvent(6s, [&]{
@@ -662,9 +701,10 @@ struct boss_kaelthas : public BossAI
}
}
});
ScheduleUniqueTimedEvent(3min, [&]{
scheduler.Schedule(3min, GROUP_PROGRESS_PHASE, [this](TaskContext)
{
PhaseKaelExecute();
}, EVENT_PREFIGHT_PHASE71);
});
}, EVENT_PREFIGHT_PHASE63);
}
@@ -778,15 +818,16 @@ struct npc_lord_sanguinar : public ScriptedAI
void JustDied(Unit* /*killer*/) override
{
if (!_hasDied)
if (Creature* kael = _instance->GetCreature(DATA_KAELTHAS))
{
Talk(SAY_SANGUINAR_DEATH);
DoCastSelf(SPELL_KAEL_PHASE_TWO, true);
if (Creature* kael = _instance->GetCreature(DATA_KAELTHAS))
kael->AI()->DoAction(ACTION_PROGRESS_PHASE_CHECK);
if (!_hasDied)
{
Talk(SAY_SANGUINAR_DEATH);
DoCastSelf(SPELL_KAEL_PHASE_TWO, true);
kael->AI()->DoAction(ACTION_START_CAPERNIAN);
_hasDied = true;
}
_hasDied = true;
}
}
@@ -830,7 +871,7 @@ struct npc_capernian : public ScriptedAI
{
if (me->Attack(who, false))
{
me->GetMotionMaster()->MoveChase(who, 45.0f, 0);
me->GetMotionMaster()->MoveChase(who, 30.0f, 0);
me->AddThreat(who, 0.0f);
}
}
@@ -850,7 +891,7 @@ struct npc_capernian : public ScriptedAI
}
else
{
me->GetMotionMaster()->MoveChase(me->GetVictim(), 45.0f);
me->GetMotionMaster()->MoveChase(me->GetVictim(), 30.0f);
DoCastVictim(SPELL_CAPERNIAN_FIREBALL);
}
@@ -865,15 +906,16 @@ struct npc_capernian : public ScriptedAI
void JustDied(Unit* /*killer*/) override
{
if (!_hasDied)
if (Creature* kael = _instance->GetCreature(DATA_KAELTHAS))
{
Talk(SAY_CAPERNIAN_DEATH);
DoCastSelf(SPELL_KAEL_PHASE_TWO, true);
if (Creature* kael = _instance->GetCreature(DATA_KAELTHAS))
kael->AI()->DoAction(ACTION_PROGRESS_PHASE_CHECK);
if (!_hasDied)
{
Talk(SAY_CAPERNIAN_DEATH);
DoCastSelf(SPELL_KAEL_PHASE_TWO, true);
kael->AI()->DoAction(ACTION_START_TELONICUS);
_hasDied = true;
}
_hasDied = true;
}
}
@@ -927,15 +969,16 @@ struct npc_telonicus : public ScriptedAI
void JustDied(Unit* /*killer*/) override
{
if (!_hasDied)
if (Creature* kael = _instance->GetCreature(DATA_KAELTHAS))
{
Talk(SAY_TELONICUS_DEATH);
DoCastSelf(SPELL_KAEL_PHASE_TWO, true);
if (Creature* kael = _instance->GetCreature(DATA_KAELTHAS))
kael->AI()->DoAction(ACTION_PROGRESS_PHASE_CHECK);
if (!_hasDied)
{
Talk(SAY_TELONICUS_DEATH);
DoCastSelf(SPELL_KAEL_PHASE_TWO, true);
kael->AI()->DoAction(ACTION_START_WEAPONS);
_hasDied = true;
}
_hasDied = true;
}
}
@@ -1011,15 +1054,16 @@ struct npc_thaladred : public ScriptedAI
void JustDied(Unit* /*killer*/) override
{
if (!_hasDied)
if (Creature* kael = _instance->GetCreature(DATA_KAELTHAS))
{
Talk(SAY_THALADRED_DEATH);
DoCastSelf(SPELL_KAEL_PHASE_TWO, true);
if (Creature* kael = _instance->GetCreature(DATA_KAELTHAS))
kael->AI()->DoAction(ACTION_PROGRESS_PHASE_CHECK);
if (!_hasDied)
{
Talk(SAY_THALADRED_DEATH);
DoCastSelf(SPELL_KAEL_PHASE_TWO, true);
kael->AI()->DoAction(ACTION_START_SANGUINAR);
_hasDied = true;
}
_hasDied = true;
}
}
@@ -1040,200 +1084,123 @@ private:
bool _hasDied;
};
class spell_kaelthas_kael_phase_two : public SpellScriptLoader
class spell_kaelthas_kael_phase_two : public SpellScript
{
public:
spell_kaelthas_kael_phase_two() : SpellScriptLoader("spell_kaelthas_kael_phase_two") { }
PrepareSpellScript(spell_kaelthas_kael_phase_two);
class spell_kaelthas_kael_phase_two_SpellScript : public SpellScript
bool Load() override
{
PrepareSpellScript(spell_kaelthas_kael_phase_two_SpellScript);
if (GetCaster()->GetTypeId() == TYPEID_UNIT)
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
if (Creature* kael = instance->GetCreature(DATA_KAELTHAS))
kael->AI()->SummonedCreatureDies(GetCaster()->ToCreature(), nullptr);
return true;
}
bool Load() override
{
if (GetCaster()->GetTypeId() == TYPEID_UNIT)
if (InstanceScript* instance = GetCaster()->GetInstanceScript())
if (Creature* kael = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(NPC_KAELTHAS)))
kael->AI()->SummonedCreatureDies(GetCaster()->ToCreature(), nullptr);
return true;
}
void Register() override
{
}
};
SpellScript* GetSpellScript() const override
void Register() override
{
return new spell_kaelthas_kael_phase_two_SpellScript();
}
};
class spell_kaelthas_remote_toy : public SpellScriptLoader
class spell_kaelthas_remote_toy : public AuraScript
{
public:
spell_kaelthas_remote_toy() : SpellScriptLoader("spell_kaelthas_remote_toy") { }
PrepareAuraScript(spell_kaelthas_remote_toy);
class spell_kaelthas_remote_toy_AuraScript : public AuraScript
void HandlePeriodic(AuraEffect const* /*aurEff*/)
{
PrepareAuraScript(spell_kaelthas_remote_toy_AuraScript);
PreventDefaultAction();
if (roll_chance_i(66))
GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_REMOTE_TOY_STUN, true);
}
void HandlePeriodic(AuraEffect const* /*aurEff*/)
{
PreventDefaultAction();
if (roll_chance_i(66))
GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_REMOTE_TOY_STUN, true);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_kaelthas_remote_toy_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
void Register() override
{
return new spell_kaelthas_remote_toy_AuraScript();
OnEffectPeriodic += AuraEffectPeriodicFn(spell_kaelthas_remote_toy::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
class spell_kaelthas_summon_weapons : public SpellScriptLoader
class spell_kaelthas_summon_weapons : public SpellScript
{
public:
spell_kaelthas_summon_weapons() : SpellScriptLoader("spell_kaelthas_summon_weapons") { }
PrepareSpellScript(spell_kaelthas_summon_weapons);
class spell_kaelthas_summon_weapons_SpellScript : public SpellScript
void HandleScriptEffect(SpellEffIndex effIndex)
{
PrepareSpellScript(spell_kaelthas_summon_weapons_SpellScript);
PreventHitEffect(effIndex);
for (uint32 i = SPELL_SUMMON_WEAPONA; i <= SPELL_SUMMON_WEAPONG; ++i)
GetCaster()->CastSpell(GetCaster(), i, true);
}
void HandleScriptEffect(SpellEffIndex effIndex)
{
PreventHitEffect(effIndex);
for (uint32 i = SPELL_SUMMON_WEAPONA; i <= SPELL_SUMMON_WEAPONG; ++i)
GetCaster()->CastSpell(GetCaster(), i, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_kaelthas_summon_weapons_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
void Register() override
{
return new spell_kaelthas_summon_weapons_SpellScript();
OnEffectHitTarget += SpellEffectFn(spell_kaelthas_summon_weapons::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
class spell_kaelthas_resurrection : public SpellScriptLoader
class spell_kaelthas_resurrection : public SpellScript
{
public:
spell_kaelthas_resurrection() : SpellScriptLoader("spell_kaelthas_resurrection") { }
PrepareSpellScript(spell_kaelthas_resurrection);
class spell_kaelthas_resurrection_SpellScript : public SpellScript
void HandleBeforeCast()
{
PrepareSpellScript(spell_kaelthas_resurrection_SpellScript);
GetCaster()->GetAI()->SetData(DATA_RESURRECT_CAST, DATA_RESURRECT_CAST);
}
void HandleBeforeCast()
{
GetCaster()->GetAI()->SetData(DATA_RESURRECT_CAST, DATA_RESURRECT_CAST);
}
void Register() override
{
BeforeCast += SpellCastFn(spell_kaelthas_resurrection_SpellScript::HandleBeforeCast);
}
};
SpellScript* GetSpellScript() const override
void Register() override
{
return new spell_kaelthas_resurrection_SpellScript();
BeforeCast += SpellCastFn(spell_kaelthas_resurrection::HandleBeforeCast);
}
};
class spell_kaelthas_mind_control : public SpellScriptLoader
class spell_kaelthas_mind_control : public SpellScript
{
public:
spell_kaelthas_mind_control() : SpellScriptLoader("spell_kaelthas_mind_control") { }
PrepareSpellScript(spell_kaelthas_mind_control);
class spell_kaelthas_mind_control_SpellScript : public SpellScript
void SelectTarget(std::list<WorldObject*>& targets)
{
PrepareSpellScript(spell_kaelthas_mind_control_SpellScript);
if (Unit* victim = GetCaster()->GetVictim())
targets.remove_if(Acore::ObjectGUIDCheck(victim->GetGUID(), true));
}
void SelectTarget(std::list<WorldObject*>& targets)
{
if (Unit* victim = GetCaster()->GetVictim())
targets.remove_if(Acore::ObjectGUIDCheck(victim->GetGUID(), true));
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kaelthas_mind_control_SpellScript::SelectTarget, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
void Register() override
{
return new spell_kaelthas_mind_control_SpellScript();
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kaelthas_mind_control::SelectTarget, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
class spell_kaelthas_burn : public SpellScriptLoader
class spell_kaelthas_burn : public AuraScript
{
public:
spell_kaelthas_burn() : SpellScriptLoader("spell_kaelthas_burn") { }
PrepareAuraScript(spell_kaelthas_burn);
class spell_kaelthas_burn_AuraScript : public AuraScript
void HandlePeriodic(AuraEffect const* /*aurEff*/)
{
PrepareAuraScript(spell_kaelthas_burn_AuraScript);
Unit::DealDamage(GetUnitOwner(), GetUnitOwner(), GetUnitOwner()->CountPctFromMaxHealth(5) + 1);
}
void HandlePeriodic(AuraEffect const* /*aurEff*/)
{
Unit::DealDamage(GetUnitOwner(), GetUnitOwner(), GetUnitOwner()->CountPctFromMaxHealth(5) + 1);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_kaelthas_burn_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
AuraScript* GetAuraScript() const override
void Register() override
{
return new spell_kaelthas_burn_AuraScript();
OnEffectPeriodic += AuraEffectPeriodicFn(spell_kaelthas_burn::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
class spell_kaelthas_flame_strike : public SpellScriptLoader
class spell_kaelthas_flame_strike : public AuraScript
{
public:
spell_kaelthas_flame_strike() : SpellScriptLoader("spell_kaelthas_flame_strike") { }
PrepareAuraScript(spell_kaelthas_flame_strike);
class spell_kaelthas_flame_strike_AuraScript : public AuraScript
bool Load() override
{
PrepareAuraScript(spell_kaelthas_flame_strike_AuraScript);
return GetUnitOwner()->GetTypeId() == TYPEID_UNIT;
}
bool Load() override
{
return GetUnitOwner()->GetTypeId() == TYPEID_UNIT;
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
GetUnitOwner()->RemoveAllAuras();
GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_FLAME_STRIKE_DAMAGE, true);
GetUnitOwner()->ToCreature()->DespawnOrUnsummon(2000);
}
void Register() override
{
OnEffectRemove += AuraEffectRemoveFn(spell_kaelthas_flame_strike_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
AuraScript* GetAuraScript() const override
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
return new spell_kaelthas_flame_strike_AuraScript();
GetUnitOwner()->RemoveAllAuras();
GetUnitOwner()->CastSpell(GetUnitOwner(), SPELL_FLAME_STRIKE_DAMAGE, true);
GetUnitOwner()->ToCreature()->DespawnOrUnsummon(2000);
}
void Register() override
{
OnEffectRemove += AuraEffectRemoveFn(spell_kaelthas_flame_strike::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
@@ -1260,111 +1227,78 @@ private:
Player* _owner;
};
class spell_kaelthas_gravity_lapse : public SpellScriptLoader
class spell_kaelthas_gravity_lapse : public SpellScript
{
public:
spell_kaelthas_gravity_lapse() : SpellScriptLoader("spell_kaelthas_gravity_lapse") { }
PrepareSpellScript(spell_kaelthas_gravity_lapse);
class spell_kaelthas_gravity_lapse_SpellScript : public SpellScript
bool Load() override
{
PrepareSpellScript(spell_kaelthas_gravity_lapse_SpellScript);
bool Load() override
{
_currentSpellId = SPELL_GRAVITY_LAPSE_TELEPORT1;
return true;
}
void HandleScriptEffect(SpellEffIndex effIndex)
{
PreventHitEffect(effIndex);
if (_currentSpellId < SPELL_GRAVITY_LAPSE_TELEPORT1 + 25)
if (Player* target = GetHitPlayer())
{
GetCaster()->CastSpell(target, _currentSpellId++, true);
target->m_Events.AddEvent(new lapseTeleport(target), target->m_Events.CalculateTime(1));
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_kaelthas_gravity_lapse_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
private:
uint32 _currentSpellId;
};
SpellScript* GetSpellScript() const override
{
return new spell_kaelthas_gravity_lapse_SpellScript();
_currentSpellId = SPELL_GRAVITY_LAPSE_TELEPORT1;
return true;
}
};
class spell_kaelthas_nether_beam : public SpellScriptLoader
{
public:
spell_kaelthas_nether_beam() : SpellScriptLoader("spell_kaelthas_nether_beam") { }
class spell_kaelthas_nether_beam_SpellScript : public SpellScript
void HandleScriptEffect(SpellEffIndex effIndex)
{
PrepareSpellScript(spell_kaelthas_nether_beam_SpellScript);
void HandleScriptEffect(SpellEffIndex effIndex)
{
PreventHitEffect(effIndex);
ThreatContainer::StorageType const& ThreatList = GetCaster()-> GetThreatMgr().GetThreatList();
std::list<Unit*> targetList;
for (ThreatContainer::StorageType::const_iterator itr = ThreatList.begin(); itr != ThreatList.end(); ++itr)
PreventHitEffect(effIndex);
if (_currentSpellId < SPELL_GRAVITY_LAPSE_TELEPORT1 + 25)
if (Player* target = GetHitPlayer())
{
Unit* target = ObjectAccessor::GetUnit(*GetCaster(), (*itr)->getUnitGuid());
if (target && target->GetTypeId() == TYPEID_PLAYER)
targetList.push_back(target);
GetCaster()->CastSpell(target, _currentSpellId++, true);
target->m_Events.AddEvent(new lapseTeleport(target), target->m_Events.CalculateTime(1));
}
}
Acore::Containers::RandomResize(targetList, 5);
for (std::list<Unit*>::const_iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
GetCaster()->CastSpell(*itr, SPELL_NETHER_BEAM_DAMAGE, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_kaelthas_nether_beam_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
void Register() override
{
return new spell_kaelthas_nether_beam_SpellScript();
OnEffectHitTarget += SpellEffectFn(spell_kaelthas_gravity_lapse::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
private:
uint32 _currentSpellId;
};
class spell_kaelthas_nether_beam : public SpellScript
{
PrepareSpellScript(spell_kaelthas_nether_beam);
void HandleScriptEffect(SpellEffIndex effIndex)
{
PreventHitEffect(effIndex);
ThreatContainer::StorageType const& ThreatList = GetCaster()-> GetThreatMgr().GetThreatList();
std::list<Unit*> targetList;
for (ThreatContainer::StorageType::const_iterator itr = ThreatList.begin(); itr != ThreatList.end(); ++itr)
{
Unit* target = ObjectAccessor::GetUnit(*GetCaster(), (*itr)->getUnitGuid());
if (target && target->GetTypeId() == TYPEID_PLAYER)
targetList.push_back(target);
}
Acore::Containers::RandomResize(targetList, 5);
for (std::list<Unit*>::const_iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
GetCaster()->CastSpell(*itr, SPELL_NETHER_BEAM_DAMAGE, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_kaelthas_nether_beam::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
class spell_kaelthas_summon_nether_vapor : public SpellScriptLoader
class spell_kaelthas_summon_nether_vapor : public SpellScript
{
public:
spell_kaelthas_summon_nether_vapor() : SpellScriptLoader("spell_kaelthas_summon_nether_vapor") { }
PrepareSpellScript(spell_kaelthas_summon_nether_vapor);
class spell_kaelthas_summon_nether_vapor_SpellScript : public SpellScript
void HandleScriptEffect(SpellEffIndex effIndex)
{
PrepareSpellScript(spell_kaelthas_summon_nether_vapor_SpellScript);
PreventHitEffect(effIndex);
for (uint32 i = 0; i < 5; ++i)
GetCaster()->SummonCreature(NPC_NETHER_VAPOR, GetCaster()->GetPositionX() + 6 * cos(i / 5.0f * 2 * M_PI), GetCaster()->GetPositionY() + 6 * std::sin(i / 5.0f * 2 * M_PI), GetCaster()->GetPositionZ() + 7.0f + i, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 30000);
}
void HandleScriptEffect(SpellEffIndex effIndex)
{
PreventHitEffect(effIndex);
for (uint32 i = 0; i < 5; ++i)
GetCaster()->SummonCreature(NPC_NETHER_VAPOR, GetCaster()->GetPositionX() + 6 * cos(i / 5.0f * 2 * M_PI), GetCaster()->GetPositionY() + 6 * std::sin(i / 5.0f * 2 * M_PI), GetCaster()->GetPositionZ() + 7.0f + i, 0.0f, TEMPSUMMON_TIMED_DESPAWN, 30000);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_kaelthas_summon_nether_vapor_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
SpellScript* GetSpellScript() const override
void Register() override
{
return new spell_kaelthas_summon_nether_vapor_SpellScript();
OnEffectHitTarget += SpellEffectFn(spell_kaelthas_summon_nether_vapor::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
@@ -1375,15 +1309,15 @@ void AddSC_boss_kaelthas()
RegisterTheEyeAI(npc_capernian);
RegisterTheEyeAI(npc_telonicus);
RegisterTheEyeAI(npc_thaladred);
new spell_kaelthas_kael_phase_two();
new spell_kaelthas_remote_toy();
new spell_kaelthas_summon_weapons();
new spell_kaelthas_resurrection();
new spell_kaelthas_mind_control();
new spell_kaelthas_burn();
new spell_kaelthas_flame_strike();
new spell_kaelthas_gravity_lapse();
new spell_kaelthas_nether_beam();
new spell_kaelthas_summon_nether_vapor();
RegisterSpellScript(spell_kaelthas_kael_phase_two);
RegisterSpellScript(spell_kaelthas_remote_toy);
RegisterSpellScript(spell_kaelthas_summon_weapons);
RegisterSpellScript(spell_kaelthas_resurrection);
RegisterSpellScript(spell_kaelthas_mind_control);
RegisterSpellScript(spell_kaelthas_burn);
RegisterSpellScript(spell_kaelthas_flame_strike);
RegisterSpellScript(spell_kaelthas_gravity_lapse);
RegisterSpellScript(spell_kaelthas_nether_beam);
RegisterSpellScript(spell_kaelthas_summon_nether_vapor);
}

View File

@@ -768,13 +768,12 @@ class spell_gen_proc_not_self : public AuraScript
if (Unit* caster = GetCaster())
if (Unit* target = eventInfo.GetActionTarget())
{
ObjectGuid targetGUID = target->GetGUID();
uint32 spellID = aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].TriggerSpell;
caster->m_Events.AddEventAtOffset([caster, target, spellID]()
caster->m_Events.AddEventAtOffset([caster, targetGUID, spellID]()
{
if (target)
{
if (Unit *target = ObjectAccessor::GetUnit(*caster, targetGUID))
caster->CastSpell(target, spellID, true);
}
}, 100ms);
}
}

View File

@@ -334,7 +334,7 @@ public:
{
npc_training_dummyAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); //imune to knock aways like blast wave
}
@@ -392,7 +392,7 @@ public:
{
npc_target_dummyAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
deathTimer = 15000;
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); //imune to knock aways like blast wave
}

View File

@@ -38,7 +38,7 @@ char* DBCDatabaseLoader::Load(uint32& records, char**& indexTable)
std::string query = Acore::StringFormat("SELECT * FROM `%s` ORDER BY `ID` DESC", _sqlTableName);
// no error if empty set
QueryResult result = WorldDatabase.Query(query.c_str());
QueryResult result = WorldDatabase.Query(query);
if (!result)
return nullptr;

View File

@@ -21,20 +21,12 @@
#include "Define.h"
#pragma pack(push, 1)
struct DBCPosition2D
{
float X;
float Y;
};
struct DBCPosition3D
{
float X;
float Y;
float Z;
};
#pragma pack(pop)
// Client expected level limitation, like as used in DBC item max levels for "until max player level"

View File

@@ -27,11 +27,7 @@
using boost::asio::ip::tcp;
#if BOOST_VERSION >= 106600
#define ACORE_MAX_LISTEN_CONNECTIONS boost::asio::socket_base::max_listen_connections
#else
#define ACORE_MAX_LISTEN_CONNECTIONS boost::asio::socket_base::max_connections
#endif
constexpr auto ACORE_MAX_LISTEN_CONNECTIONS = boost::asio::socket_base::max_listen_connections;
class AsyncAcceptor
{
@@ -40,7 +36,7 @@ public:
AsyncAcceptor(Acore::Asio::IoContext& ioContext, std::string const& bindIp, uint16 port) :
_acceptor(ioContext), _endpoint(Acore::Net::make_address(bindIp), port),
_socket(ioContext), _closed(false), _socketFactory(std::bind(&AsyncAcceptor::DefeaultSocketFactory, this))
_socket(ioContext), _closed(false), _socketFactory([this](){ return DefaultSocketFactory(); })
{
}
@@ -122,7 +118,7 @@ public:
void SetSocketFactory(std::function<std::pair<tcp::socket*, uint32>()> func) { _socketFactory = func; }
private:
std::pair<tcp::socket*, uint32> DefeaultSocketFactory() { return std::make_pair(&_socket, 0); }
std::pair<tcp::socket*, uint32> DefaultSocketFactory() { return std::make_pair(&_socket, 0); }
tcp::acceptor _acceptor;
tcp::endpoint _endpoint;
@@ -155,4 +151,4 @@ void AsyncAcceptor::AsyncAccept()
});
}
#endif /* __ASYNCACCEPT_H_ */
#endif /* __ASYNC ACCEPT_H_ */

View File

@@ -73,12 +73,12 @@ public:
return true;
}
boost::asio::ip::address GetRemoteIpAddress() const
[[nodiscard]] boost::asio::ip::address GetRemoteIpAddress() const
{
return _remoteAddress;
}
uint16 GetRemotePort() const
[[nodiscard]] uint16 GetRemotePort() const
{
return _remotePort;
}
@@ -120,7 +120,7 @@ public:
#endif
}
bool IsOpen() const { return !_closed && !_closing; }
[[nodiscard]] bool IsOpen() const { return !_closed && !_closing; }
void CloseSocket()
{
@@ -146,7 +146,7 @@ protected:
virtual void OnClose() { }
virtual void ReadHandler() = 0;
bool AsyncProcessQueue()
[[nodiscard]] bool AsyncProcessQueue()
{
if (_isWritingAsync)
return false;

View File

@@ -104,9 +104,9 @@ public:
}
}
int32 GetNetworkThreadCount() const { return _threadCount; }
[[nodiscard]] int32 GetNetworkThreadCount() const { return _threadCount; }
uint32 SelectThreadWithMinConnections() const
[[nodiscard]] uint32 SelectThreadWithMinConnections() const
{
uint32 min = 0;

View File

@@ -78,7 +78,7 @@ std::string ByteBuffer::ReadCString(bool requireValidUtf8 /*= true*/)
{
std::string value;
while (rpos() < size()) // prevent crash at wrong string format in packet
while (rpos() < size()) // prevent crash the wrong string format in a packet
{
char c = read<char>();
if (c == 0)
@@ -94,7 +94,7 @@ std::string ByteBuffer::ReadCString(bool requireValidUtf8 /*= true*/)
uint32 ByteBuffer::ReadPackedTime()
{
uint32 packedDate = read<uint32>();
auto packedDate = read<uint32>();
tm lt = tm();
lt.tm_min = packedDate & 0x3F;

View File

@@ -69,7 +69,7 @@ public:
class AC_SHARED_API ByteBuffer
{
public:
constexpr static size_t DEFAULT_SIZE = 0x1000;
constexpr static std::size_t DEFAULT_SIZE = 0x1000;
// constructor
ByteBuffer()
@@ -77,7 +77,7 @@ public:
_storage.reserve(DEFAULT_SIZE);
}
ByteBuffer(size_t reserve) : _rpos(0), _wpos(0)
explicit ByteBuffer(std::size_t reserve) : _rpos(0), _wpos(0)
{
_storage.reserve(reserve);
}
@@ -90,7 +90,7 @@ public:
}
ByteBuffer(ByteBuffer const& right) = default;
ByteBuffer(MessageBuffer&& buffer);
explicit ByteBuffer(MessageBuffer&& buffer);
virtual ~ByteBuffer() = default;
ByteBuffer& operator=(ByteBuffer const& right)

View File

@@ -24,7 +24,7 @@ boost::asio::ip::tcp_endpoint Realm::GetAddressForClient(boost::asio::ip::addres
{
boost::asio::ip::address realmIp;
// Attempt to send best address for client
// Attempt to send best address for a client
if (clientAddr.is_loopback())
{
// Try guessing if realm is also connected locally
@@ -52,5 +52,5 @@ boost::asio::ip::tcp_endpoint Realm::GetAddressForClient(boost::asio::ip::addres
}
// Return external IP
return boost::asio::ip::tcp_endpoint(realmIp, Port);
return { realmIp, Port };
}

View File

@@ -92,7 +92,7 @@ void RealmList::LoadBuildInfo()
void RealmList::UpdateRealm(RealmHandle const& id, uint32 build, std::string const& name,
boost::asio::ip::address&& address, boost::asio::ip::address&& localAddr, boost::asio::ip::address&& localSubmask,
uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population)
uint16 port, uint8 icon, RealmFlags flag, uint8 realmTimezone, AccountTypes allowedSecurityLevel, float population)
{
// Create new if not exist or update existed
Realm& realm = _realms[id];
@@ -102,7 +102,7 @@ void RealmList::UpdateRealm(RealmHandle const& id, uint32 build, std::string con
realm.Name = name;
realm.Type = icon;
realm.Flags = flag;
realm.Timezone = timezone;
realm.Timezone = realmTimezone;
realm.AllowedSecurityLevel = allowedSecurityLevel;
realm.PopulationLevel = population;
@@ -192,8 +192,8 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
icon = REALM_TYPE_NORMAL;
}
RealmFlags flag = RealmFlags(fields[7].Get<uint8>());
uint8 timezone = fields[8].Get<uint8>();
auto flag = RealmFlags(fields[7].Get<uint8>());
uint8 realmTimezone = fields[8].Get<uint8>();
uint8 allowedSecurityLevel = fields[9].Get<uint8>();
float pop = fields[10].Get<float>();
uint32 build = fields[11].Get<uint32>();
@@ -201,7 +201,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
RealmHandle id{ realmId };
UpdateRealm(id, build, name, externalAddress->address(), localAddress->address(), localSubmask->address(), port, icon, flag,
timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop);
realmTimezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop);
if (!existingRealms.count(id))
{
@@ -228,7 +228,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
if (_updateInterval)
{
_updateTimer->expires_from_now(boost::posix_time::seconds(_updateInterval));
_updateTimer->async_wait(std::bind(&RealmList::UpdateRealms, this, std::placeholders::_1));
_updateTimer->async_wait([this](boost::system::error_code const& errorCode){ UpdateRealms(errorCode); });
}
}

View File

@@ -65,7 +65,7 @@ private:
void UpdateRealms(boost::system::error_code const& error);
void UpdateRealm(RealmHandle const& id, uint32 build, std::string const& name,
boost::asio::ip::address&& address, boost::asio::ip::address&& localAddr, boost::asio::ip::address&& localSubmask,
uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population);
uint16 port, uint8 icon, RealmFlags flag, uint8 realmTimezone, AccountTypes allowedSecurityLevel, float population);
std::vector<RealmBuildInfo> _builds;
RealmMap _realms;