Merge branch 'azerothcore:master' into Playerbot
This commit is contained in:
@@ -177,6 +177,8 @@ public:
|
||||
/// == Fields =======================================
|
||||
virtual void PassengerBoarded(Unit* /*passenger*/, int8 /*seatId*/, bool /*apply*/) {}
|
||||
|
||||
virtual bool BeforeSpellClick(Unit* /*clicker*/) { return true; }
|
||||
|
||||
virtual void OnSpellClick(Unit* /*clicker*/, bool& /*result*/) { }
|
||||
|
||||
virtual bool CanSeeAlways(WorldObject const* /*obj*/) { return false; }
|
||||
|
||||
@@ -179,12 +179,6 @@ void SmartAI::GenerateWayPointArray(Movement::PointsArray* points)
|
||||
|
||||
void SmartAI::StartPath(bool run, uint32 path, bool repeat, Unit* invoker)
|
||||
{
|
||||
if (me->IsInCombat())// no wp movement in combat
|
||||
{
|
||||
LOG_ERROR("scripts.ai.sai", "SmartAI::StartPath: Creature entry {} wanted to start waypoint movement while in combat, ignoring.", me->GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasEscortState(SMART_ESCORT_ESCORTING))
|
||||
StopPath();
|
||||
|
||||
|
||||
@@ -4400,6 +4400,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
|
||||
{
|
||||
if (e.event.quest.quest && var0 != e.event.quest.quest)
|
||||
return;
|
||||
RecalcTimer(e, e.event.quest.cooldownMin, e.event.quest.cooldownMax);
|
||||
ProcessAction(e, unit, var0);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1009,7 +1009,14 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_EVENT_ACCEPTED_QUEST:
|
||||
case SMART_EVENT_REWARD_QUEST:
|
||||
if (e.event.quest.quest && !IsQuestValid(e, e.event.quest.quest))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsMinMaxValid(e, e.event.quest.cooldownMin, e.event.quest.cooldownMax))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SMART_EVENT_RECEIVE_EMOTE:
|
||||
{
|
||||
|
||||
@@ -123,8 +123,8 @@ enum SMART_EVENT
|
||||
SMART_EVENT_FRIENDLY_MISSING_BUFF = 16, // SpellId, Radius, RepeatMin, RepeatMax
|
||||
SMART_EVENT_SUMMONED_UNIT = 17, // CreatureId(0 all), CooldownMin, CooldownMax
|
||||
SMART_EVENT_TARGET_MANA_PCT = 18, // ManaMin%, ManaMax%, RepeatMin, RepeatMax
|
||||
SMART_EVENT_ACCEPTED_QUEST = 19, // QuestID(0any)
|
||||
SMART_EVENT_REWARD_QUEST = 20, // QuestID(0any)
|
||||
SMART_EVENT_ACCEPTED_QUEST = 19, // QuestID (0 = any), CooldownMin, CooldownMax
|
||||
SMART_EVENT_REWARD_QUEST = 20, // QuestID (0 = any), CooldownMin, CooldownMax
|
||||
SMART_EVENT_REACHED_HOME = 21, // NONE
|
||||
SMART_EVENT_RECEIVE_EMOTE = 22, // EmoteId, CooldownMin, CooldownMax, condition, val1, val2, val3
|
||||
SMART_EVENT_HAS_AURA = 23, // Param1 = SpellID, Param2 = Stack amount, Param3/4 RepeatMin, RepeatMax
|
||||
@@ -293,6 +293,8 @@ struct SmartEvent
|
||||
struct
|
||||
{
|
||||
uint32 quest;
|
||||
uint32 cooldownMin;
|
||||
uint32 cooldownMax;
|
||||
} quest;
|
||||
|
||||
struct
|
||||
|
||||
@@ -476,9 +476,19 @@ void BattlefieldWG::OnBattleEnd(bool endByTimer)
|
||||
m_PlayersInWar[TEAM_HORDE].clear();
|
||||
|
||||
if (!endByTimer) // win alli/horde
|
||||
{
|
||||
uint32 const worldStateId = GetDefenderTeam() == TEAM_ALLIANCE ? WORLDSTATE_ALLIANCE_KEEP_CAPTURED : WORLDSTATE_HORDE_KEEP_CAPTURED;
|
||||
sWorld->setWorldState(worldStateId, sWorld->getWorldState(worldStateId) + 1);
|
||||
|
||||
SendWarning((GetDefenderTeam() == TEAM_ALLIANCE) ? BATTLEFIELD_WG_TEXT_WIN_KEEP : (BATTLEFIELD_WG_TEXT_WIN_KEEP + 2));
|
||||
}
|
||||
else // defend alli/horde
|
||||
{
|
||||
uint32 const worldStateId = GetDefenderTeam() == TEAM_ALLIANCE ? WORLDSTATE_ALLIANCE_KEEP_DEFENDED : WORLDSTATE_HORDE_KEEP_DEFENDED;
|
||||
sWorld->setWorldState(worldStateId, sWorld->getWorldState(worldStateId) + 1);
|
||||
|
||||
SendWarning((GetDefenderTeam() == TEAM_ALLIANCE) ? BATTLEFIELD_WG_TEXT_DEFEND_KEEP : (BATTLEFIELD_WG_TEXT_DEFEND_KEEP + 2));
|
||||
}
|
||||
}
|
||||
|
||||
// *******************************************************
|
||||
@@ -898,6 +908,11 @@ void BattlefieldWG::FillInitialWorldStates(WorldPacket& data)
|
||||
data << uint32(BATTLEFIELD_WG_WORLD_STATE_VEHICLE_A) << uint32(GetData(BATTLEFIELD_WG_DATA_VEHICLE_A));
|
||||
data << uint32(BATTLEFIELD_WG_WORLD_STATE_MAX_VEHICLE_A) << GetData(BATTLEFIELD_WG_DATA_MAX_VEHICLE_A);
|
||||
|
||||
data << uint32(WORLDSTATE_HORDE_KEEP_CAPTURED) << uint32(sWorld->getWorldState(WORLDSTATE_HORDE_KEEP_CAPTURED));
|
||||
data << uint32(WORLDSTATE_HORDE_KEEP_DEFENDED) << uint32(sWorld->getWorldState(WORLDSTATE_HORDE_KEEP_DEFENDED));
|
||||
data << uint32(WORLDSTATE_ALLIANCE_KEEP_CAPTURED) << uint32(sWorld->getWorldState(WORLDSTATE_ALLIANCE_KEEP_CAPTURED));
|
||||
data << uint32(WORLDSTATE_ALLIANCE_KEEP_DEFENDED) << uint32(sWorld->getWorldState(WORLDSTATE_ALLIANCE_KEEP_DEFENDED));
|
||||
|
||||
for (GameObjectBuilding::const_iterator itr = BuildingsInZone.begin(); itr != BuildingsInZone.end(); ++itr)
|
||||
data << (*itr)->m_WorldState << (*itr)->m_State;
|
||||
|
||||
@@ -913,7 +928,7 @@ void BattlefieldWG::SendInitWorldStatesTo(Player* player)
|
||||
data << uint32(m_MapId);
|
||||
data << uint32(m_ZoneId);
|
||||
data << uint32(0);
|
||||
data << uint16(10 + BuildingsInZone.size() + WorkshopsList.size()); // Number of fields
|
||||
data << uint16(14 + BuildingsInZone.size() + WorkshopsList.size()); // Number of fields
|
||||
|
||||
FillInitialWorldStates(data);
|
||||
|
||||
|
||||
@@ -523,7 +523,11 @@ enum WintergraspWorldstates
|
||||
WORLDSTATE_WORKSHOP_SE = 3703,
|
||||
WORLDSTATE_WORKSHOP_SW = 3702,
|
||||
WORLDSTATE_WORKSHOP_K_W = 3698,
|
||||
WORLDSTATE_WORKSHOP_K_E = 3699
|
||||
WORLDSTATE_WORKSHOP_K_E = 3699,
|
||||
WORLDSTATE_HORDE_KEEP_CAPTURED = 4022,
|
||||
WORLDSTATE_HORDE_KEEP_DEFENDED = 4024,
|
||||
WORLDSTATE_ALLIANCE_KEEP_CAPTURED = 4023,
|
||||
WORLDSTATE_ALLIANCE_KEEP_DEFENDED = 4025,
|
||||
};
|
||||
|
||||
// TODO: Handle this with creature_text ?
|
||||
|
||||
@@ -1045,7 +1045,7 @@ void MovementInfo::OutDebug()
|
||||
}
|
||||
|
||||
WorldObject::WorldObject(bool isWorldObject) : WorldLocation(),
|
||||
LastUsedScriptID(0), m_name(""), m_isActive(false), m_visibilityDistanceOverride(false), m_isWorldObject(isWorldObject), m_zoneScript(nullptr),
|
||||
LastUsedScriptID(0), m_name(""), m_isActive(false), m_visibilityDistanceOverride(), m_isWorldObject(isWorldObject), m_zoneScript(nullptr),
|
||||
_zoneId(0), _areaId(0), _floorZ(INVALID_HEIGHT), _outdoors(false), _liquidData(), _updatePositionData(false), m_transport(nullptr),
|
||||
m_currMap(nullptr), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), m_useCombinedPhases(true), m_notifyflags(0), m_executed_notifies(0)
|
||||
{
|
||||
|
||||
@@ -737,22 +737,13 @@ void Player::SendMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 Curre
|
||||
StopMirrorTimer(Type);
|
||||
return;
|
||||
}
|
||||
WorldPacket data(SMSG_START_MIRROR_TIMER, (21));
|
||||
data << (uint32)Type;
|
||||
data << CurrentValue;
|
||||
data << MaxValue;
|
||||
data << Regen;
|
||||
data << (uint8)0;
|
||||
data << (uint32)0; // spell id
|
||||
GetSession()->SendPacket(&data);
|
||||
SendDirectMessage(WorldPackets::Misc::StartMirrorTimer(Type, CurrentValue, MaxValue, Regen, 0, 0).Write());
|
||||
}
|
||||
|
||||
void Player::StopMirrorTimer(MirrorTimerType Type)
|
||||
{
|
||||
m_MirrorTimer[Type] = DISABLED_MIRROR_TIMER;
|
||||
WorldPacket data(SMSG_STOP_MIRROR_TIMER, 4);
|
||||
data << (uint32)Type;
|
||||
GetSession()->SendPacket(&data);
|
||||
SendDirectMessage(WorldPackets::Misc::StopMirrorTimer(Type).Write());
|
||||
}
|
||||
|
||||
bool Player::IsImmuneToEnvironmentalDamage()
|
||||
@@ -7132,10 +7123,6 @@ void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32
|
||||
continue;
|
||||
}
|
||||
|
||||
// not allow proc extra attack spell at extra attack
|
||||
if (m_extraAttacks && spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
|
||||
return;
|
||||
|
||||
float chance = (float)spellInfo->ProcChance;
|
||||
|
||||
if (spellData.SpellPPMRate)
|
||||
|
||||
@@ -231,7 +231,6 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject),
|
||||
m_modAttackSpeedPct[OFF_ATTACK] = 1.0f;
|
||||
m_modAttackSpeedPct[RANGED_ATTACK] = 1.0f;
|
||||
|
||||
m_extraAttacks = 0;
|
||||
m_canDualWield = false;
|
||||
|
||||
m_rootTimes = 0;
|
||||
@@ -316,6 +315,8 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject),
|
||||
_lastLiquid = nullptr;
|
||||
|
||||
_oldFactionId = 0;
|
||||
|
||||
_lastExtraAttackSpell = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@@ -430,6 +431,23 @@ void Unit::Update(uint32 p_time)
|
||||
}
|
||||
}
|
||||
|
||||
_lastDamagedTargetGuid = ObjectGuid::Empty;
|
||||
if (_lastExtraAttackSpell)
|
||||
{
|
||||
while (!extraAttacksTargets.empty())
|
||||
{
|
||||
auto itr = extraAttacksTargets.begin();
|
||||
ObjectGuid targetGuid = itr->first;
|
||||
uint32 count = itr->second;
|
||||
extraAttacksTargets.erase(itr);
|
||||
if (Unit* victim = ObjectAccessor::GetUnit(*this, targetGuid))
|
||||
{
|
||||
HandleProcExtraAttackFor(victim, count);
|
||||
}
|
||||
}
|
||||
_lastExtraAttackSpell = 0;
|
||||
}
|
||||
|
||||
// not implemented before 3.0.2
|
||||
// xinef: if attack time > 0, reduce by diff
|
||||
// if on next update, attack time < 0 assume player didnt attack - set to 0
|
||||
@@ -2286,8 +2304,15 @@ void Unit::CalcHealAbsorb(HealInfo& healInfo)
|
||||
|
||||
void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra)
|
||||
{
|
||||
if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) || HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
|
||||
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) && !extra)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!victim->IsAlive())
|
||||
return;
|
||||
@@ -2304,6 +2329,11 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr
|
||||
if (attType != BASE_ATTACK && attType != OFF_ATTACK)
|
||||
return; // ignore ranged case
|
||||
|
||||
if (!extra && _lastExtraAttackSpell)
|
||||
{
|
||||
_lastExtraAttackSpell = 0;
|
||||
}
|
||||
|
||||
bool meleeAttack = true;
|
||||
|
||||
// melee attack spell casted at main hand attack only - no normal melee dmg dealt
|
||||
@@ -2345,6 +2375,8 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr
|
||||
|
||||
//TriggerAurasProcOnEvent(damageInfo);
|
||||
|
||||
_lastDamagedTargetGuid = victim->GetGUID();
|
||||
|
||||
DealMeleeDamage(&damageInfo, true);
|
||||
|
||||
DamageInfo dmgInfo(damageInfo);
|
||||
@@ -2457,15 +2489,31 @@ bool Unit::GetMeleeAttackPoint(Unit* attacker, Position& pos)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Unit::HandleProcExtraAttackFor(Unit* victim)
|
||||
void Unit::HandleProcExtraAttackFor(Unit* victim, uint32 count)
|
||||
{
|
||||
while (m_extraAttacks)
|
||||
while (count)
|
||||
{
|
||||
--count;
|
||||
AttackerStateUpdate(victim, BASE_ATTACK, true);
|
||||
--m_extraAttacks;
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::AddExtraAttacks(uint32 count)
|
||||
{
|
||||
ObjectGuid targetGUID = _lastDamagedTargetGuid;
|
||||
if (!targetGUID)
|
||||
{
|
||||
if (ObjectGuid selection = GetTarget())
|
||||
{
|
||||
targetGUID = selection; // Spell was cast directly (not triggered by aura)
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
extraAttacksTargets[targetGUID] += count;
|
||||
}
|
||||
|
||||
MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(Unit const* victim, WeaponAttackType attType) const
|
||||
{
|
||||
// This is only wrapper
|
||||
@@ -8418,7 +8466,7 @@ bool Unit::HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, Sp
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown, uint32 procPhase)
|
||||
bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown, uint32 procPhase, ProcEventInfo& eventInfo)
|
||||
{
|
||||
// Get triggered aura spell info
|
||||
SpellInfo const* auraSpellInfo = triggeredByAura->GetSpellInfo();
|
||||
@@ -8904,8 +8952,23 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
|
||||
}
|
||||
|
||||
// not allow proc extra attack spell at extra attack
|
||||
if (m_extraAttacks && triggerEntry->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
|
||||
return false;
|
||||
if (triggerEntry->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
|
||||
{
|
||||
uint32 lastExtraAttackSpell = eventInfo.GetActor()->GetLastExtraAttackSpell();
|
||||
|
||||
// Patch 1.12.0(?) extra attack abilities can no longer chain proc themselves
|
||||
if (lastExtraAttackSpell == trigger_spell_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Patch 2.2.0 Sword Specialization (Warrior, Rogue) extra attack can no longer proc additional extra attacks
|
||||
// 3.3.5 Sword Specialization (Warrior), Hack and Slash (Rogue)
|
||||
if (lastExtraAttackSpell == 16459 || lastExtraAttackSpell == 66923)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Custom requirements (not listed in procEx) Warning! damage dealing after this
|
||||
// Custom triggered spells
|
||||
@@ -10742,15 +10805,15 @@ void Unit::SendEnergizeSpellLog(Unit* victim, uint32 spellID, uint32 damage, Pow
|
||||
|
||||
void Unit::EnergizeBySpell(Unit* victim, uint32 spellID, uint32 damage, Powers powerType)
|
||||
{
|
||||
SendEnergizeSpellLog(victim, spellID, damage, powerType);
|
||||
// needs to be called after sending spell log
|
||||
victim->ModifyPower(powerType, damage);
|
||||
victim->ModifyPower(powerType, damage, false);
|
||||
|
||||
if (powerType != POWER_HAPPINESS)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID);
|
||||
victim->getHostileRefMgr().threatAssist(this, float(damage) * 0.5f, spellInfo);
|
||||
}
|
||||
|
||||
SendEnergizeSpellLog(victim, spellID, damage, powerType);
|
||||
}
|
||||
|
||||
float Unit::SpellPctDamageModsDone(Unit* victim, SpellInfo const* spellProto, DamageEffectType damagetype)
|
||||
@@ -13440,7 +13503,7 @@ int32 Unit::GetHealthGain(int32 dVal)
|
||||
}
|
||||
|
||||
// returns negative amount on power reduction
|
||||
int32 Unit::ModifyPower(Powers power, int32 dVal)
|
||||
int32 Unit::ModifyPower(Powers power, int32 dVal, bool withPowerUpdate /*= true*/)
|
||||
{
|
||||
if (dVal == 0)
|
||||
return 0;
|
||||
@@ -13452,7 +13515,7 @@ int32 Unit::ModifyPower(Powers power, int32 dVal)
|
||||
int32 val = dVal + curPower;
|
||||
if (val <= 0)
|
||||
{
|
||||
SetPower(power, 0);
|
||||
SetPower(power, 0, withPowerUpdate);
|
||||
return -curPower;
|
||||
}
|
||||
|
||||
@@ -13460,12 +13523,12 @@ int32 Unit::ModifyPower(Powers power, int32 dVal)
|
||||
|
||||
if (val < maxPower)
|
||||
{
|
||||
SetPower(power, val);
|
||||
SetPower(power, val, withPowerUpdate);
|
||||
gain = val - curPower;
|
||||
}
|
||||
else if (curPower != maxPower)
|
||||
{
|
||||
SetPower(power, maxPower);
|
||||
SetPower(power, maxPower, withPowerUpdate);
|
||||
gain = maxPower - curPower;
|
||||
}
|
||||
|
||||
@@ -14832,7 +14895,7 @@ void Unit::SetMaxHealth(uint32 val)
|
||||
SetHealth(val);
|
||||
}
|
||||
|
||||
void Unit::SetPower(Powers power, uint32 val)
|
||||
void Unit::SetPower(Powers power, uint32 val, bool withPowerUpdate /*= true*/)
|
||||
{
|
||||
if (GetPower(power) == val)
|
||||
return;
|
||||
@@ -14843,11 +14906,14 @@ void Unit::SetPower(Powers power, uint32 val)
|
||||
|
||||
SetStatInt32Value(static_cast<uint16>(UNIT_FIELD_POWER1) + power, val);
|
||||
|
||||
WorldPacket data(SMSG_POWER_UPDATE);
|
||||
data << GetPackGUID();
|
||||
data << uint8(power);
|
||||
data << uint32(val);
|
||||
SendMessageToSet(&data, GetTypeId() == TYPEID_PLAYER);
|
||||
if (withPowerUpdate)
|
||||
{
|
||||
WorldPacket data(SMSG_POWER_UPDATE);
|
||||
data << GetPackGUID();
|
||||
data << uint8(power);
|
||||
data << uint32(val);
|
||||
SendMessageToSet(&data, GetTypeId() == TYPEID_PLAYER);
|
||||
}
|
||||
|
||||
// group update
|
||||
if (GetTypeId() == TYPEID_PLAYER)
|
||||
@@ -15841,7 +15907,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
|
||||
{
|
||||
LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell {} (triggered by {} aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
|
||||
// Don`t drop charge or add cooldown for not started trigger
|
||||
if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procPhase))
|
||||
if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procPhase, eventInfo))
|
||||
takeCharges = true;
|
||||
break;
|
||||
}
|
||||
@@ -15900,7 +15966,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
|
||||
{
|
||||
LOG_DEBUG("spells.aura", "ProcDamageAndSpell: casting spell {} (triggered with value by {} aura of spell {})", spellInfo->Id, (isVictim ? "a victim's" : "an attacker's"), triggeredByAura->GetId());
|
||||
|
||||
if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procPhase))
|
||||
if (HandleProcTriggerSpell(target, damage, triggeredByAura, procSpellInfo, procFlag, procExtra, cooldown, procPhase, eventInfo))
|
||||
takeCharges = true;
|
||||
break;
|
||||
}
|
||||
@@ -16303,10 +16369,6 @@ void Unit::AddComboPoints(Unit* target, int8 count)
|
||||
return;
|
||||
}
|
||||
|
||||
// remove Premed-like effects
|
||||
// (NB: this Aura removes the already-added CP when it expires from duration - now that we've added CP, this shouldn't happen anymore)
|
||||
RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS);
|
||||
|
||||
if (target && target != m_comboTarget)
|
||||
{
|
||||
if (m_comboTarget)
|
||||
@@ -18931,6 +18993,15 @@ void Unit::JumpTo(WorldObject* obj, float speedZ)
|
||||
|
||||
bool Unit::HandleSpellClick(Unit* clicker, int8 seatId)
|
||||
{
|
||||
Creature* creature = ToCreature();
|
||||
if (creature && creature->IsAIEnabled)
|
||||
{
|
||||
if (!creature->AI()->BeforeSpellClick(clicker))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
uint32 spellClickEntry = GetVehicleKit() ? GetVehicleKit()->GetCreatureEntry() : GetEntry();
|
||||
SpellClickInfoMapBounds clickPair = sObjectMgr->GetSpellClickInfoMapBounds(spellClickEntry);
|
||||
@@ -18999,7 +19070,6 @@ bool Unit::HandleSpellClick(Unit* clicker, int8 seatId)
|
||||
result = true;
|
||||
}
|
||||
|
||||
Creature* creature = ToCreature();
|
||||
if (creature && creature->IsAIEnabled)
|
||||
creature->AI()->OnSpellClick(clicker, result);
|
||||
|
||||
|
||||
@@ -1416,10 +1416,10 @@ public:
|
||||
void setPowerType(Powers power);
|
||||
[[nodiscard]] uint32 GetPower(Powers power) const { return GetUInt32Value(static_cast<uint16>(UNIT_FIELD_POWER1) + power); }
|
||||
[[nodiscard]] uint32 GetMaxPower(Powers power) const { return GetUInt32Value(static_cast<uint16>(UNIT_FIELD_MAXPOWER1) + power); }
|
||||
void SetPower(Powers power, uint32 val);
|
||||
void SetPower(Powers power, uint32 val, bool withPowerUpdate = true);
|
||||
void SetMaxPower(Powers power, uint32 val);
|
||||
// returns the change in power
|
||||
int32 ModifyPower(Powers power, int32 val);
|
||||
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate = true);
|
||||
int32 ModifyPowerPct(Powers power, float pct, bool apply = true);
|
||||
|
||||
[[nodiscard]] uint32 GetAttackTime(WeaponAttackType att) const
|
||||
@@ -1507,7 +1507,13 @@ public:
|
||||
|
||||
void CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK, const bool sittingVictim = false);
|
||||
void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss);
|
||||
void HandleProcExtraAttackFor(Unit* victim);
|
||||
|
||||
void HandleProcExtraAttackFor(Unit* victim, uint32 count);
|
||||
void SetLastExtraAttackSpell(uint32 spellId) { _lastExtraAttackSpell = spellId; }
|
||||
[[nodiscard]] uint32 GetLastExtraAttackSpell() const { return _lastExtraAttackSpell; }
|
||||
void AddExtraAttacks(uint32 count);
|
||||
void SetLastDamagedTargetGuid(ObjectGuid const& guid) { _lastDamagedTargetGuid = guid; }
|
||||
[[nodiscard]] ObjectGuid const& GetLastDamagedTargetGuid() const { return _lastDamagedTargetGuid; }
|
||||
|
||||
void CalculateSpellDamageTaken(SpellNonMeleeDamage* damageInfo, int32 damage, SpellInfo const* spellInfo, WeaponAttackType attackType = BASE_ATTACK, bool crit = false);
|
||||
void DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss, Spell const* spell = nullptr);
|
||||
@@ -2474,7 +2480,7 @@ private:
|
||||
bool IsTriggeredAtSpellProcEvent(Unit* victim, Aura* aura, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent, ProcEventInfo const& eventInfo);
|
||||
bool HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
|
||||
bool HandleAuraProc(Unit* victim, uint32 damage, Aura* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, bool* handled);
|
||||
bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, uint32 procPhase);
|
||||
bool HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown, uint32 procPhase, ProcEventInfo& eventInfo);
|
||||
bool HandleOverrideClassScriptAuraProc(Unit* victim, uint32 damage, AuraEffect* triggeredByAura, SpellInfo const* procSpell, uint32 cooldown);
|
||||
bool HandleAuraRaidProcFromChargeWithValue(AuraEffect* triggeredByAura);
|
||||
bool HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura);
|
||||
@@ -2518,6 +2524,10 @@ private:
|
||||
uint32 _oldFactionId; ///< faction before charm
|
||||
|
||||
[[nodiscard]] float processDummyAuras(float TakenTotalMod) const;
|
||||
|
||||
uint32 _lastExtraAttackSpell;
|
||||
std::unordered_map<ObjectGuid /*guid*/, uint32 /*count*/> extraAttacksTargets;
|
||||
ObjectGuid _lastDamagedTargetGuid;
|
||||
};
|
||||
|
||||
namespace Acore
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "Log.h"
|
||||
#include "LootMgr.h"
|
||||
#include "MapMgr.h"
|
||||
#include "MiscPackets.h"
|
||||
#include "Object.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
@@ -1570,9 +1571,9 @@ void WorldSession::HandleWorldStateUITimerUpdate(WorldPacket& /*recv_data*/)
|
||||
// empty opcode
|
||||
LOG_DEBUG("network", "WORLD: CMSG_WORLD_STATE_UI_TIMER_UPDATE");
|
||||
|
||||
WorldPacket data(SMSG_WORLD_STATE_UI_TIMER_UPDATE, 4);
|
||||
data << uint32(GameTime::GetGameTime().count());
|
||||
SendPacket(&data);
|
||||
WorldPackets::Misc::UITime response;
|
||||
response.Time = GameTime::GetGameTime().count();
|
||||
SendPacket(response.Write());
|
||||
}
|
||||
|
||||
void WorldSession::HandleReadyForAccountDataTimes(WorldPacket& /*recv_data*/)
|
||||
|
||||
@@ -83,6 +83,33 @@ WorldPacket const* WorldPackets::Misc::RandomRoll::Write()
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Misc::StartMirrorTimer::Write()
|
||||
{
|
||||
_worldPacket << uint32(Timer);
|
||||
_worldPacket << uint32(Value);
|
||||
_worldPacket << uint32(MaxValue);
|
||||
_worldPacket << int32(Scale);
|
||||
_worldPacket << uint8(Paused);
|
||||
_worldPacket << uint32(SpellID);
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Misc::PauseMirrorTimer::Write()
|
||||
{
|
||||
_worldPacket << uint32(Timer);
|
||||
_worldPacket << uint8(Paused);
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Misc::StopMirrorTimer::Write()
|
||||
{
|
||||
_worldPacket << uint32(Timer);
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Misc::CrossedInebriationThreshold::Write()
|
||||
{
|
||||
_worldPacket << Guid;
|
||||
@@ -91,3 +118,10 @@ WorldPacket const* WorldPackets::Misc::CrossedInebriationThreshold::Write()
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
WorldPacket const* WorldPackets::Misc::UITime::Write()
|
||||
{
|
||||
_worldPacket << uint32(Time);
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
@@ -114,6 +114,46 @@ namespace WorldPackets
|
||||
ObjectGuid Roller;
|
||||
};
|
||||
|
||||
class StartMirrorTimer final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
StartMirrorTimer() : ServerPacket(SMSG_START_MIRROR_TIMER, 21) { }
|
||||
StartMirrorTimer(uint32 timer, uint32 value, uint32 maxValue, int32 scale, bool paused, uint32 spellID) :
|
||||
ServerPacket(SMSG_START_MIRROR_TIMER, 21), Timer(timer), Value(value), MaxValue(maxValue), Scale(scale), Paused(paused), SpellID(spellID) { }
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
uint32 Timer = 0;
|
||||
uint32 Value = 0;
|
||||
uint32 MaxValue = 0;
|
||||
int32 Scale = 0;
|
||||
bool Paused = false;
|
||||
uint32 SpellID = 0;
|
||||
};
|
||||
|
||||
class PauseMirrorTimer final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
PauseMirrorTimer() : ServerPacket(SMSG_PAUSE_MIRROR_TIMER, 5) { }
|
||||
PauseMirrorTimer(uint32 timer, bool paused) : ServerPacket(SMSG_PAUSE_MIRROR_TIMER, 5), Timer(timer), Paused(paused) { }
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
uint32 Timer = 0;
|
||||
bool Paused = true;
|
||||
};
|
||||
|
||||
class StopMirrorTimer final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
StopMirrorTimer() : ServerPacket(SMSG_STOP_MIRROR_TIMER, 4) { }
|
||||
StopMirrorTimer(uint32 timer) : ServerPacket(SMSG_STOP_MIRROR_TIMER, 4), Timer(timer) { }
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
uint32 Timer = 0;
|
||||
};
|
||||
|
||||
class DurabilityDamageDeath final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
@@ -134,6 +174,16 @@ namespace WorldPackets
|
||||
uint32 ItemID = 0;
|
||||
|
||||
};
|
||||
|
||||
class UITime final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
UITime() : ServerPacket(SMSG_WORLD_STATE_UI_TIMER_UPDATE, 4) { }
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
uint32 Time = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2605,6 +2605,8 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
|
||||
// Do damage and triggers
|
||||
else if (m_damage > 0)
|
||||
{
|
||||
caster->SetLastDamagedTargetGuid(unitTarget->GetGUID());
|
||||
|
||||
// Fill base damage struct (unitTarget - is real spell target)
|
||||
SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo, m_spellSchoolMask);
|
||||
|
||||
@@ -4039,11 +4041,20 @@ void Spell::_handle_finish_phase()
|
||||
// Real add combo points from effects
|
||||
if (m_comboTarget && m_comboPointGain)
|
||||
{
|
||||
// remove Premed-like effects unless they were caused by ourselves
|
||||
// (this Aura removes the already-added CP when it expires from duration - now that we've added CP, this shouldn't happen anymore!)
|
||||
if (!m_spellInfo->HasAura(SPELL_AURA_RETAIN_COMBO_POINTS))
|
||||
{
|
||||
m_caster->RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS);
|
||||
}
|
||||
|
||||
m_caster->AddComboPoints(m_comboTarget, m_comboPointGain);
|
||||
}
|
||||
|
||||
if (m_caster->m_extraAttacks && GetSpellInfo()->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
|
||||
m_caster->HandleProcExtraAttackFor(m_caster->GetVictim());
|
||||
if (m_spellInfo->HasEffect(SPELL_EFFECT_ADD_EXTRA_ATTACKS))
|
||||
{
|
||||
m_caster->SetLastExtraAttackSpell(m_spellInfo->Id);
|
||||
}
|
||||
|
||||
if (!IsAutoRepeat() && !IsNextMeleeSwingSpell())
|
||||
if (m_caster->GetCharmerOrOwnerPlayerOrPlayerItself())
|
||||
@@ -4461,10 +4472,12 @@ void Spell::SendSpellStart()
|
||||
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR0_USES_RANGED_SLOT) || m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NEEDS_AMMO_DATA))
|
||||
castFlags |= CAST_FLAG_PROJECTILE;
|
||||
if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
|
||||
(m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsPet()))
|
||||
&& m_spellInfo->PowerType != POWER_HEALTH)
|
||||
|
||||
if ((m_caster->GetTypeId() == TYPEID_PLAYER || (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsPet()))
|
||||
&& m_spellInfo->PowerType != POWER_HEALTH && m_powerCost != 0)
|
||||
{
|
||||
castFlags |= CAST_FLAG_POWER_LEFT_SELF;
|
||||
}
|
||||
|
||||
if (m_spellInfo->RuneCostID && m_spellInfo->PowerType == POWER_RUNE)
|
||||
castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
|
||||
@@ -4518,10 +4531,11 @@ void Spell::SendSpellGo()
|
||||
if (m_spellInfo->HasAttribute(SPELL_ATTR0_USES_RANGED_SLOT) || m_spellInfo->HasAttribute(SPELL_ATTR0_CU_NEEDS_AMMO_DATA))
|
||||
castFlags |= CAST_FLAG_PROJECTILE; // arrows/bullets visual
|
||||
|
||||
if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
|
||||
(m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsPet()))
|
||||
&& m_spellInfo->PowerType != POWER_HEALTH)
|
||||
castFlags |= CAST_FLAG_POWER_LEFT_SELF; // should only be sent to self, but the current messaging doesn't make that possible
|
||||
if ((m_caster->GetTypeId() == TYPEID_PLAYER || (m_caster->GetTypeId() == TYPEID_UNIT && m_caster->IsPet()))
|
||||
&& m_spellInfo->PowerType != POWER_HEALTH && m_powerCost != 0) // should only be sent to self, but the current messaging doesn't make that possible
|
||||
{
|
||||
castFlags |= CAST_FLAG_POWER_LEFT_SELF;
|
||||
}
|
||||
|
||||
if ((m_caster->GetTypeId() == TYPEID_PLAYER)
|
||||
&& (m_caster->getClass() == CLASS_DEATH_KNIGHT)
|
||||
@@ -5052,7 +5066,9 @@ void Spell::TakePower()
|
||||
|
||||
// Set the five second timer
|
||||
if (PowerType == POWER_MANA && m_powerCost > 0)
|
||||
{
|
||||
m_caster->SetLastManaUse(GameTime::GetGameTimeMS().count());
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::TakeAmmo()
|
||||
|
||||
@@ -1287,39 +1287,6 @@ void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/)
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Dimensional Ripper - Area 52
|
||||
case 36890:
|
||||
{
|
||||
if (roll_chance_i(50)) // 50% success
|
||||
{
|
||||
int32 rand_eff = urand(1, 4);
|
||||
switch (rand_eff)
|
||||
{
|
||||
case 1:
|
||||
// soul split - evil
|
||||
m_caster->CastSpell(m_caster, 36900, true);
|
||||
break;
|
||||
case 2:
|
||||
// soul split - good
|
||||
m_caster->CastSpell(m_caster, 36901, true);
|
||||
break;
|
||||
case 3:
|
||||
// Increase the size
|
||||
m_caster->CastSpell(m_caster, 36895, true);
|
||||
break;
|
||||
case 4:
|
||||
// Transform
|
||||
{
|
||||
if (m_caster->ToPlayer()->GetTeamId() == TEAM_ALLIANCE)
|
||||
m_caster->CastSpell(m_caster, 36897, true);
|
||||
else
|
||||
m_caster->CastSpell(m_caster, 36899, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1516,13 +1483,6 @@ void Spell::EffectHeal(SpellEffIndex /*effIndex*/)
|
||||
|
||||
addhealth += damageAmount;
|
||||
}
|
||||
// Runic Healing Injector (heal increased by 25% for engineers - 3.2.0 patch change)
|
||||
else if (m_spellInfo->Id == 67489)
|
||||
{
|
||||
if (Player* player = m_caster->ToPlayer())
|
||||
if (player->HasSkill(SKILL_ENGINEERING))
|
||||
AddPct(addhealth, 25);
|
||||
}
|
||||
// Swiftmend - consumes Regrowth or Rejuvenation
|
||||
else if (m_spellInfo->TargetAuraState == AURA_STATE_SWIFTMEND && unitTarget->HasAuraState(AURA_STATE_SWIFTMEND, m_spellInfo, m_caster))
|
||||
{
|
||||
@@ -3822,17 +3782,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
|
||||
{
|
||||
switch (m_spellInfo->Id)
|
||||
{
|
||||
// Bending Shinbone
|
||||
case 8856:
|
||||
{
|
||||
if (!itemTarget && m_caster->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
uint32 spell_id = roll_chance_i(20) ? 8854 : 8855;
|
||||
|
||||
m_caster->CastSpell(m_caster, spell_id, true, nullptr);
|
||||
return;
|
||||
}
|
||||
// Brittle Armor - need remove one 24575 Brittle Armor aura
|
||||
case 24590:
|
||||
unitTarget->RemoveAuraFromStack(24575);
|
||||
@@ -3974,84 +3923,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
|
||||
m_caster->TextEmote(buf);
|
||||
break;
|
||||
}
|
||||
// Death Knight Initiate Visual
|
||||
case 51519:
|
||||
{
|
||||
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
|
||||
return;
|
||||
|
||||
uint32 iTmpSpellId = 0;
|
||||
switch (unitTarget->GetDisplayId())
|
||||
{
|
||||
case 25369:
|
||||
iTmpSpellId = 51552;
|
||||
break; // bloodelf female
|
||||
case 25373:
|
||||
iTmpSpellId = 51551;
|
||||
break; // bloodelf male
|
||||
case 25363:
|
||||
iTmpSpellId = 51542;
|
||||
break; // draenei female
|
||||
case 25357:
|
||||
iTmpSpellId = 51541;
|
||||
break; // draenei male
|
||||
case 25361:
|
||||
iTmpSpellId = 51537;
|
||||
break; // dwarf female
|
||||
case 25356:
|
||||
iTmpSpellId = 51538;
|
||||
break; // dwarf male
|
||||
case 25372:
|
||||
iTmpSpellId = 51550;
|
||||
break; // forsaken female
|
||||
case 25367:
|
||||
iTmpSpellId = 51549;
|
||||
break; // forsaken male
|
||||
case 25362:
|
||||
iTmpSpellId = 51540;
|
||||
break; // gnome female
|
||||
case 25359:
|
||||
iTmpSpellId = 51539;
|
||||
break; // gnome male
|
||||
case 25355:
|
||||
iTmpSpellId = 51534;
|
||||
break; // human female
|
||||
case 25354:
|
||||
iTmpSpellId = 51520;
|
||||
break; // human male
|
||||
case 25360:
|
||||
iTmpSpellId = 51536;
|
||||
break; // nightelf female
|
||||
case 25358:
|
||||
iTmpSpellId = 51535;
|
||||
break; // nightelf male
|
||||
case 25368:
|
||||
iTmpSpellId = 51544;
|
||||
break; // orc female
|
||||
case 25364:
|
||||
iTmpSpellId = 51543;
|
||||
break; // orc male
|
||||
case 25371:
|
||||
iTmpSpellId = 51548;
|
||||
break; // tauren female
|
||||
case 25366:
|
||||
iTmpSpellId = 51547;
|
||||
break; // tauren male
|
||||
case 25370:
|
||||
iTmpSpellId = 51545;
|
||||
break; // troll female
|
||||
case 25365:
|
||||
iTmpSpellId = 51546;
|
||||
break; // troll male
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
unitTarget->CastSpell(unitTarget, iTmpSpellId, true);
|
||||
Creature* npc = unitTarget->ToCreature();
|
||||
npc->LoadEquipment();
|
||||
return;
|
||||
}
|
||||
// Deathbolt from Thalgran Blightbringer
|
||||
// reflected by Freya's Ward
|
||||
// Retribution by Sevenfold Retribution
|
||||
@@ -4121,48 +3992,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex)
|
||||
else
|
||||
unitTarget->CastSpell(unitTarget, 59314, true);
|
||||
|
||||
return;
|
||||
}
|
||||
case 60123: // Lightwell
|
||||
{
|
||||
if (m_caster->GetTypeId() != TYPEID_UNIT || !m_caster->ToCreature()->IsSummon())
|
||||
return;
|
||||
|
||||
uint32 spell_heal;
|
||||
|
||||
switch (m_caster->GetEntry())
|
||||
{
|
||||
case 31897:
|
||||
spell_heal = 7001;
|
||||
break;
|
||||
case 31896:
|
||||
spell_heal = 27873;
|
||||
break;
|
||||
case 31895:
|
||||
spell_heal = 27874;
|
||||
break;
|
||||
case 31894:
|
||||
spell_heal = 28276;
|
||||
break;
|
||||
case 31893:
|
||||
spell_heal = 48084;
|
||||
break;
|
||||
case 31883:
|
||||
spell_heal = 48085;
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("spells.effect", "Unknown Lightwell spell caster {}", m_caster->GetEntry());
|
||||
return;
|
||||
}
|
||||
|
||||
// proc a spellcast
|
||||
if (Aura* chargesAura = m_caster->GetAura(59907))
|
||||
{
|
||||
m_caster->CastSpell(unitTarget, spell_heal, true, nullptr, nullptr, m_caster->ToTempSummon()->GetSummonerGUID());
|
||||
if (chargesAura->ModCharges(-1))
|
||||
m_caster->ToTempSummon()->UnSummon();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
// Stoneclaw Totem
|
||||
@@ -4835,17 +4664,18 @@ void Spell::EffectResurrect(SpellEffIndex effIndex)
|
||||
void Spell::EffectAddExtraAttacks(SpellEffIndex effIndex)
|
||||
{
|
||||
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!unitTarget || !unitTarget->IsAlive() || !unitTarget->GetVictim())
|
||||
if (!unitTarget || !unitTarget->IsAlive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (unitTarget->m_extraAttacks)
|
||||
return;
|
||||
unitTarget->AddExtraAttacks(damage);
|
||||
|
||||
unitTarget->m_extraAttacks = damage;
|
||||
|
||||
ExecuteLogEffectExtraAttacks(effIndex, unitTarget->GetVictim(), damage);
|
||||
ExecuteLogEffectExtraAttacks(effIndex, unitTarget, damage);
|
||||
}
|
||||
|
||||
void Spell::EffectParry(SpellEffIndex /*effIndex*/)
|
||||
|
||||
@@ -4168,6 +4168,11 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->AttributesEx2 |= SPELL_ATTR2_IGNORE_LINE_OF_SIGHT;
|
||||
});
|
||||
|
||||
ApplySpellFix({ 22247 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AttributesCu |= SPELL_ATTR0_CU_DONT_BREAK_STEALTH;
|
||||
});
|
||||
|
||||
// Manastorm
|
||||
ApplySpellFix({ 21097 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
|
||||
+24
-3
@@ -51,7 +51,8 @@ enum Events
|
||||
|
||||
enum Actions
|
||||
{
|
||||
ACTION_DISARMED = 0
|
||||
ACTION_DEACTIVATE = 0,
|
||||
ACTION_DISARMED = 1
|
||||
};
|
||||
|
||||
class boss_broodlord : public CreatureScript
|
||||
@@ -75,6 +76,18 @@ public:
|
||||
events.ScheduleEvent(EVENT_CHECK, 1000);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
|
||||
std::list<GameObject*> _goList;
|
||||
GetGameObjectListWithEntryInGrid(_goList, me, GO_SUPPRESSION_DEVICE, 200.0f);
|
||||
for (std::list<GameObject*>::const_iterator itr = _goList.begin(); itr != _goList.end(); itr++)
|
||||
{
|
||||
((*itr)->AI()->DoAction(ACTION_DEACTIVATE));
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
@@ -183,11 +196,19 @@ class go_suppression_device : public GameObjectScript
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_DISARMED)
|
||||
if (action == ACTION_DEACTIVATE)
|
||||
{
|
||||
_events.CancelEvent(EVENT_SUPPRESSION_RESET);
|
||||
}
|
||||
else if (action == ACTION_DISARMED)
|
||||
{
|
||||
Deactivate();
|
||||
_events.CancelEvent(EVENT_SUPPRESSION_CAST);
|
||||
_events.ScheduleEvent(EVENT_SUPPRESSION_RESET, urand(30000, 120000));
|
||||
|
||||
if (_instance->GetBossState(DATA_BROODLORD_LASHLAYER) != DONE)
|
||||
{
|
||||
_events.ScheduleEvent(EVENT_SUPPRESSION_RESET, urand(30000, 120000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-13
@@ -34,6 +34,7 @@ enum Events
|
||||
EVENT_CHECK_PHASE_2,
|
||||
EVENT_START_EVENT,
|
||||
EVENT_SHADOW_BOLT,
|
||||
EVENT_SHADOW_BOLT_VOLLEY,
|
||||
EVENT_FEAR,
|
||||
EVENT_SILENCE,
|
||||
EVENT_MIND_CONTROL,
|
||||
@@ -298,7 +299,8 @@ public:
|
||||
SetCombatMovement(false);
|
||||
AttackStart(SelectTarget(SelectTargetMethod::Random, 0, 200.f, true));
|
||||
events.ScheduleEvent(EVENT_SHADOWBLINK, 500);
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, urand(3000, 10000));
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, 3000);
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, urand(13000, 15000));
|
||||
events.ScheduleEvent(EVENT_FEAR, urand(10000, 20000));
|
||||
events.ScheduleEvent(EVENT_SILENCE, urand(20000, 25000));
|
||||
events.ScheduleEvent(EVENT_MIND_CONTROL, urand(30000, 35000));
|
||||
@@ -388,17 +390,12 @@ public:
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SHADOW_BOLT:
|
||||
switch (urand(0, 1))
|
||||
{
|
||||
case 0:
|
||||
DoCastAOE(SPELL_SHADOWBOLT_VOLLEY);
|
||||
break;
|
||||
case 1:
|
||||
DoCastRandomTarget(SPELL_SHADOWBOLT, 0, 150.f);
|
||||
break;
|
||||
}
|
||||
DoResetThreat();
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, urand(3000, 10000));
|
||||
DoCastRandomTarget(SPELL_SHADOWBOLT, 0, 150.f);
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT, urand(2000, 4000));
|
||||
break;
|
||||
case EVENT_SHADOW_BOLT_VOLLEY:
|
||||
DoCastAOE(SPELL_SHADOWBOLT_VOLLEY);
|
||||
events.ScheduleEvent(EVENT_SHADOW_BOLT_VOLLEY, 19000, 25000);
|
||||
break;
|
||||
case EVENT_FEAR:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40, true))
|
||||
@@ -412,7 +409,7 @@ public:
|
||||
case EVENT_MIND_CONTROL:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40, true))
|
||||
DoCast(target, SPELL_SHADOW_COMMAND);
|
||||
events.ScheduleEvent(EVENT_MIND_CONTROL, urand(30000, 35000));
|
||||
events.ScheduleEvent(EVENT_MIND_CONTROL, urand(24000, 30000));
|
||||
break;
|
||||
case EVENT_SHADOWBLINK:
|
||||
DoCastSelf(SPELL_SHADOWBLINK);
|
||||
@@ -436,6 +433,7 @@ public:
|
||||
events.CancelEvent(EVENT_MIND_CONTROL);
|
||||
events.CancelEvent(EVENT_FEAR);
|
||||
events.CancelEvent(EVENT_SHADOW_BOLT);
|
||||
events.CancelEvent(EVENT_SHADOW_BOLT_VOLLEY);
|
||||
events.CancelEvent(EVENT_SILENCE);
|
||||
DoCastSelf(SPELL_ROOT_SELF, true);
|
||||
me->SetVisible(false);
|
||||
@@ -470,6 +468,8 @@ public:
|
||||
me->SetUInt32Value(UNIT_NPC_FLAGS, 0);
|
||||
me->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE);
|
||||
// Due to Nefarius despawning himself on Vael, we need to update the guid on instance to prevent unwanted behaviours as encounter not resetting at all.
|
||||
instance->SetGuidData(DATA_LORD_VICTOR_NEFARIUS, me->GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -124,7 +124,7 @@ public:
|
||||
|
||||
events.ScheduleEvent(EVENT_CLEAVE, 10000);
|
||||
events.ScheduleEvent(EVENT_FLAME_BREATH, 15000);
|
||||
events.ScheduleEvent(EVENT_FIRE_NOVA, 20000);
|
||||
events.ScheduleEvent(EVENT_FIRE_NOVA, 5000);
|
||||
events.ScheduleEvent(EVENT_TAIL_SWEEP, 11000);
|
||||
events.ScheduleEvent(EVENT_BURNING_ADRENALINE, 15000);
|
||||
}
|
||||
@@ -220,7 +220,7 @@ public:
|
||||
break;
|
||||
case EVENT_FIRE_NOVA:
|
||||
DoCastVictim(SPELL_FIRE_NOVA);
|
||||
events.ScheduleEvent(EVENT_FIRE_NOVA, 15000);
|
||||
events.ScheduleEvent(EVENT_FIRE_NOVA, urand(3000, 5000));
|
||||
break;
|
||||
case EVENT_TAIL_SWEEP:
|
||||
DoCastAOE(SPELL_TAIL_SWEEP);
|
||||
|
||||
+12
@@ -357,6 +357,18 @@ public:
|
||||
return ObjectGuid::Empty;
|
||||
}
|
||||
|
||||
void SetGuidData(uint32 type, ObjectGuid data) override
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DATA_LORD_VICTOR_NEFARIUS:
|
||||
victorNefariusGUID = data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnUnitDeath(Unit* unit) override
|
||||
{
|
||||
switch (unit->GetEntry())
|
||||
|
||||
@@ -1171,6 +1171,52 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class spell_death_knight_initiate_visual : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_death_knight_initiate_visual);
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /* effIndex */)
|
||||
{
|
||||
Creature* target = GetHitCreature();
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
uint32 spellId;
|
||||
switch (target->GetDisplayId())
|
||||
{
|
||||
case 25369: spellId = 51552; break; // bloodelf female
|
||||
case 25373: spellId = 51551; break; // bloodelf male
|
||||
case 25363: spellId = 51542; break; // draenei female
|
||||
case 25357: spellId = 51541; break; // draenei male
|
||||
case 25361: spellId = 51537; break; // dwarf female
|
||||
case 25356: spellId = 51538; break; // dwarf male
|
||||
case 25372: spellId = 51550; break; // forsaken female
|
||||
case 25367: spellId = 51549; break; // forsaken male
|
||||
case 25362: spellId = 51540; break; // gnome female
|
||||
case 25359: spellId = 51539; break; // gnome male
|
||||
case 25355: spellId = 51534; break; // human female
|
||||
case 25354: spellId = 51520; break; // human male
|
||||
case 25360: spellId = 51536; break; // nightelf female
|
||||
case 25358: spellId = 51535; break; // nightelf male
|
||||
case 25368: spellId = 51544; break; // orc female
|
||||
case 25364: spellId = 51543; break; // orc male
|
||||
case 25371: spellId = 51548; break; // tauren female
|
||||
case 25366: spellId = 51547; break; // tauren male
|
||||
case 25370: spellId = 51545; break; // troll female
|
||||
case 25365: spellId = 51546; break; // troll male
|
||||
default: return;
|
||||
}
|
||||
|
||||
target->CastSpell(target, spellId, true);
|
||||
target->LoadEquipment();
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_death_knight_initiate_visual::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_the_scarlet_enclave_c1()
|
||||
{
|
||||
// Ours
|
||||
@@ -1191,4 +1237,6 @@ void AddSC_the_scarlet_enclave_c1()
|
||||
new npc_scarlet_miner();
|
||||
new npc_scarlet_miner_cart();
|
||||
new go_inconspicuous_mine_car();
|
||||
|
||||
RegisterSpellScript(spell_death_knight_initiate_visual);
|
||||
}
|
||||
|
||||
@@ -268,6 +268,11 @@ public:
|
||||
|
||||
BindPlayers();
|
||||
me->SetInCombatWithZone();
|
||||
|
||||
if (!_startTimer)
|
||||
{
|
||||
TurnGates(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeAI() override
|
||||
|
||||
@@ -242,17 +242,19 @@ public:
|
||||
summons.DespawnAll();
|
||||
|
||||
if (m_pInstance)
|
||||
{
|
||||
m_pInstance->SetData(TYPE_KOLOGARN, NOT_STARTED);
|
||||
|
||||
// Open the door inside Kologarn chamber
|
||||
if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS)))
|
||||
door->SetGoState(GO_STATE_ACTIVE);
|
||||
}
|
||||
|
||||
AttachLeftArm();
|
||||
AttachRightArm();
|
||||
|
||||
// Reset breath on pull
|
||||
breathReady = false;
|
||||
|
||||
// Open the door inside Kologarn chamber
|
||||
if (GameObject* door = me->FindNearestGameObject(GO_KOLOGARN_DOORS, 100.0f))
|
||||
door->SetGoState(GO_STATE_ACTIVE);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
@@ -301,6 +303,13 @@ public:
|
||||
|
||||
Talk(SAY_DEATH);
|
||||
|
||||
if (m_pInstance)
|
||||
{
|
||||
// Open the door inside Kologarn chamber
|
||||
if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS)))
|
||||
door->SetGoState(GO_STATE_ACTIVE);
|
||||
}
|
||||
|
||||
if (GameObject* bridge = me->FindNearestGameObject(GO_KOLOGARN_BRIDGE, 100))
|
||||
bridge->SetGoState(GO_STATE_READY);
|
||||
|
||||
@@ -384,8 +393,13 @@ public:
|
||||
me->setActive(true);
|
||||
|
||||
// Close the door inside Kologarn chamber
|
||||
if (GameObject* door = me->FindNearestGameObject(GO_KOLOGARN_DOORS, 100.0f))
|
||||
door->SetGoState(GO_STATE_READY);
|
||||
if (m_pInstance)
|
||||
{
|
||||
if (GameObject* door = m_pInstance->instance->GetGameObject(m_pInstance->GetGuidData(GO_KOLOGARN_DOORS)))
|
||||
{
|
||||
door->SetGoState(GO_STATE_READY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
|
||||
@@ -16,12 +16,14 @@
|
||||
*/
|
||||
|
||||
#include "ulduar.h"
|
||||
#include "CombatAI.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptedGossip.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellScript.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
class npc_ulduar_keeper : public CreatureScript
|
||||
{
|
||||
@@ -423,6 +425,31 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct npc_salvaged_siege_engine : public VehicleAI
|
||||
{
|
||||
npc_salvaged_siege_engine(Creature* creature) : VehicleAI(creature) { }
|
||||
|
||||
bool BeforeSpellClick(Unit* clicker) override
|
||||
{
|
||||
if (Vehicle* vehicle = me->GetVehicleKit())
|
||||
{
|
||||
if (vehicle->IsVehicleInUse())
|
||||
{
|
||||
if (Unit* turret = vehicle->GetPassenger(7))
|
||||
{
|
||||
if (!turret->GetVehicleKit()->IsVehicleInUse())
|
||||
{
|
||||
turret->HandleSpellClick(clicker);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_ulduar()
|
||||
{
|
||||
new npc_ulduar_keeper();
|
||||
@@ -435,4 +462,6 @@ void AddSC_ulduar()
|
||||
|
||||
new AreaTrigger_at_celestial_planetarium_enterance();
|
||||
new go_call_tram();
|
||||
|
||||
RegisterCreatureAI(npc_salvaged_siege_engine);
|
||||
}
|
||||
|
||||
@@ -20,17 +20,18 @@
|
||||
#include "MapMgr.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "OutdoorPvP.h"
|
||||
#include "OutdoorPvPMgr.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "GameTime.h"
|
||||
|
||||
OutdoorPvPTF::OutdoorPvPTF()
|
||||
{
|
||||
m_TypeId = OUTDOOR_PVP_TF;
|
||||
|
||||
m_IsLocked = false;
|
||||
m_JustLocked = false;
|
||||
m_LockTimer = TF_LOCK_TIME;
|
||||
m_LockTimerUpdate = 0;
|
||||
|
||||
@@ -105,6 +106,71 @@ void OutdoorPvPTF::SendRemoveWorldStates(Player* player)
|
||||
}
|
||||
}
|
||||
|
||||
void OutdoorPvPTF::SaveRequiredWorldStates() const
|
||||
{
|
||||
sWorld->setWorldState(TF_UI_TOWER_COUNT_H, m_HordeTowersControlled);
|
||||
sWorld->setWorldState(TF_UI_TOWER_COUNT_A, m_AllianceTowersControlled);
|
||||
|
||||
sWorld->setWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, m_IsLocked);
|
||||
|
||||
// Save expiry as unix
|
||||
uint32 const lockExpireTime = GameTime::GetGameTime().count() + (m_LockTimer / IN_MILLISECONDS);
|
||||
sWorld->setWorldState(TF_UI_LOCKED_TIME_HOURS, lockExpireTime);
|
||||
}
|
||||
|
||||
void OutdoorPvPTF::ResetZoneToTeamControlled(TeamId team)
|
||||
{
|
||||
switch (team)
|
||||
{
|
||||
case TEAM_HORDE:
|
||||
m_HordeTowersControlled = TF_TOWER_NUM;
|
||||
m_AllianceTowersControlled = 0;
|
||||
break;
|
||||
case TEAM_ALLIANCE:
|
||||
m_HordeTowersControlled = 0;
|
||||
m_AllianceTowersControlled = TF_TOWER_NUM;
|
||||
break;
|
||||
case TEAM_NEUTRAL:
|
||||
m_HordeTowersControlled = 0;
|
||||
m_AllianceTowersControlled = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto& [guid, tower] : m_capturePoints)
|
||||
{
|
||||
dynamic_cast<OPvPCapturePointTF*>(tower)->ResetToTeamControlled(team);
|
||||
}
|
||||
|
||||
SendUpdateWorldState(TF_UI_TOWER_COUNT_H, m_HordeTowersControlled);
|
||||
SendUpdateWorldState(TF_UI_TOWER_COUNT_A, m_AllianceTowersControlled);
|
||||
}
|
||||
|
||||
void OPvPCapturePointTF::ResetToTeamControlled(TeamId team)
|
||||
{
|
||||
switch (team)
|
||||
{
|
||||
case TEAM_HORDE:
|
||||
m_State = OBJECTIVESTATE_HORDE;
|
||||
m_OldState = OBJECTIVESTATE_HORDE;
|
||||
m_team = TEAM_HORDE;
|
||||
break;
|
||||
case TEAM_ALLIANCE:
|
||||
m_State = OBJECTIVESTATE_ALLIANCE;
|
||||
m_OldState = OBJECTIVESTATE_ALLIANCE;
|
||||
m_team = TEAM_ALLIANCE;
|
||||
break;
|
||||
case TEAM_NEUTRAL:
|
||||
m_State = OBJECTIVESTATE_NEUTRAL;
|
||||
m_OldState = OBJECTIVESTATE_NEUTRAL;
|
||||
m_team = TEAM_NEUTRAL;
|
||||
break;
|
||||
}
|
||||
|
||||
m_value = 0.0f;
|
||||
ChangeState();
|
||||
SendChangePhase();
|
||||
}
|
||||
|
||||
void OPvPCapturePointTF::UpdateTowerState()
|
||||
{
|
||||
m_PvP->SendUpdateWorldState(uint32(TFTowerWorldStates[m_TowerType].n), uint32(bool(m_TowerState & TF_TOWERSTATE_N)));
|
||||
@@ -141,6 +207,7 @@ bool OutdoorPvPTF::Update(uint32 diff)
|
||||
{
|
||||
TeamApplyBuff(TEAM_ALLIANCE, TF_CAPTURE_BUFF);
|
||||
m_IsLocked = true;
|
||||
m_JustLocked = true;
|
||||
SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL, uint32(0));
|
||||
SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE, uint32(0));
|
||||
SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE, uint32(1));
|
||||
@@ -150,6 +217,7 @@ bool OutdoorPvPTF::Update(uint32 diff)
|
||||
{
|
||||
TeamApplyBuff(TEAM_HORDE, TF_CAPTURE_BUFF);
|
||||
m_IsLocked = true;
|
||||
m_JustLocked = true;
|
||||
SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL, uint32(0));
|
||||
SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE, uint32(1));
|
||||
SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_ALLIANCE, uint32(0));
|
||||
@@ -160,17 +228,29 @@ bool OutdoorPvPTF::Update(uint32 diff)
|
||||
TeamCastSpell(TEAM_ALLIANCE, -TF_CAPTURE_BUFF);
|
||||
TeamCastSpell(TEAM_HORDE, -TF_CAPTURE_BUFF);
|
||||
}
|
||||
|
||||
SendUpdateWorldState(TF_UI_TOWER_COUNT_A, m_AllianceTowersControlled);
|
||||
SendUpdateWorldState(TF_UI_TOWER_COUNT_H, m_HordeTowersControlled);
|
||||
}
|
||||
|
||||
if (m_IsLocked)
|
||||
{
|
||||
if (m_JustLocked)
|
||||
{
|
||||
m_JustLocked = false;
|
||||
SaveRequiredWorldStates();
|
||||
}
|
||||
|
||||
// lock timer is down, release lock
|
||||
if (m_LockTimer < diff)
|
||||
{
|
||||
m_LockTimer = TF_LOCK_TIME;
|
||||
m_LockTimerUpdate = 0;
|
||||
m_IsLocked = false;
|
||||
|
||||
ResetZoneToTeamControlled(TEAM_NEUTRAL);
|
||||
SaveRequiredWorldStates();
|
||||
|
||||
SendUpdateWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY, uint32(1));
|
||||
SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_NEUTRAL, uint32(0));
|
||||
SendUpdateWorldState(TF_UI_LOCKED_DISPLAY_HORDE, uint32(0));
|
||||
@@ -182,20 +262,21 @@ bool OutdoorPvPTF::Update(uint32 diff)
|
||||
if (m_LockTimerUpdate < diff)
|
||||
{
|
||||
m_LockTimerUpdate = TF_LOCK_TIME_UPDATE;
|
||||
uint32 minutes_left = m_LockTimer / 60000;
|
||||
hours_left = minutes_left / 60;
|
||||
minutes_left -= hours_left * 60;
|
||||
second_digit = minutes_left % 10;
|
||||
first_digit = minutes_left / 10;
|
||||
RecalculateClientUILockTime();
|
||||
|
||||
SendUpdateWorldState(TF_UI_LOCKED_TIME_MINUTES_FIRST_DIGIT, first_digit);
|
||||
SendUpdateWorldState(TF_UI_LOCKED_TIME_MINUTES_SECOND_DIGIT, second_digit);
|
||||
SendUpdateWorldState(TF_UI_LOCKED_TIME_HOURS, hours_left);
|
||||
}
|
||||
else m_LockTimerUpdate -= diff;
|
||||
else
|
||||
{
|
||||
m_LockTimerUpdate -= diff;
|
||||
}
|
||||
|
||||
m_LockTimer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -251,7 +332,8 @@ bool OutdoorPvPTF::SetupOutdoorPvP()
|
||||
m_AllianceTowersControlled = 0;
|
||||
m_HordeTowersControlled = 0;
|
||||
|
||||
m_IsLocked = false;
|
||||
m_IsLocked = bool(sWorld->getWorldState(TF_UI_TOWERS_CONTROLLED_DISPLAY));
|
||||
m_JustLocked = false;
|
||||
m_LockTimer = TF_LOCK_TIME;
|
||||
m_LockTimerUpdate = 0;
|
||||
hours_left = 6;
|
||||
@@ -270,6 +352,30 @@ bool OutdoorPvPTF::SetupOutdoorPvP()
|
||||
AddCapturePoint(new OPvPCapturePointTF(this, TF_TOWER_SE));
|
||||
AddCapturePoint(new OPvPCapturePointTF(this, TF_TOWER_S));
|
||||
|
||||
if (m_IsLocked)
|
||||
{
|
||||
// Core shutdown while locked -- init from latest known data in WorldState
|
||||
// Convert from unix
|
||||
int32 const lockRemainingTime = int32((sWorld->getWorldState(TF_UI_LOCKED_TIME_HOURS) - GameTime::GetGameTime().count()) * IN_MILLISECONDS);
|
||||
if (lockRemainingTime > 0)
|
||||
{
|
||||
m_LockTimer = lockRemainingTime;
|
||||
RecalculateClientUILockTime();
|
||||
|
||||
uint32 const hordeTowers = uint32(sWorld->getWorldState(TF_UI_TOWER_COUNT_H));
|
||||
uint32 const allianceTowers = uint32(sWorld->getWorldState(TF_UI_TOWER_COUNT_A));
|
||||
TeamId const controllingTeam = hordeTowers > allianceTowers ? TEAM_HORDE : TEAM_ALLIANCE;
|
||||
|
||||
ResetZoneToTeamControlled(controllingTeam);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Lock expired while core was offline
|
||||
m_IsLocked = false;
|
||||
SaveRequiredWorldStates();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,10 +32,10 @@ const uint32 OutdoorPvPTFBuffZones[OutdoorPvPTFBuffZonesNum] =
|
||||
};
|
||||
|
||||
// locked for 6 hours after capture
|
||||
const uint32 TF_LOCK_TIME = 3600 * 6 * 1000;
|
||||
const uint32 TF_LOCK_TIME = 6 * HOUR * IN_MILLISECONDS;
|
||||
|
||||
// update lock timer every 1/4 minute (overkill, but this way it's sure the timer won't "jump" 2 minutes at once.)
|
||||
const uint32 TF_LOCK_TIME_UPDATE = 15000;
|
||||
const uint32 TF_LOCK_TIME_UPDATE = 15 * IN_MILLISECONDS;
|
||||
|
||||
// blessing of auchindoun
|
||||
#define TF_CAPTURE_BUFF 33377
|
||||
@@ -138,6 +138,8 @@ public:
|
||||
bool HandlePlayerEnter(Player* player) override;
|
||||
void HandlePlayerLeave(Player* player) override;
|
||||
|
||||
void ResetToTeamControlled(TeamId team);
|
||||
|
||||
void UpdateTowerState();
|
||||
|
||||
protected:
|
||||
@@ -162,6 +164,19 @@ public:
|
||||
|
||||
void SendRemoveWorldStates(Player* player) override;
|
||||
|
||||
void SaveRequiredWorldStates() const;
|
||||
|
||||
void ResetZoneToTeamControlled(TeamId team);
|
||||
|
||||
void RecalculateClientUILockTime()
|
||||
{
|
||||
uint32 minutes_left = m_LockTimer / 60000;
|
||||
hours_left = minutes_left / 60;
|
||||
minutes_left -= hours_left * 60;
|
||||
second_digit = minutes_left % 10;
|
||||
first_digit = minutes_left / 10;
|
||||
}
|
||||
|
||||
uint32 GetAllianceTowersControlled() const;
|
||||
void SetAllianceTowersControlled(uint32 count);
|
||||
|
||||
@@ -172,6 +187,7 @@ public:
|
||||
|
||||
private:
|
||||
bool m_IsLocked;
|
||||
bool m_JustLocked;
|
||||
uint32 m_LockTimer;
|
||||
uint32 m_LockTimerUpdate;
|
||||
|
||||
|
||||
@@ -2101,6 +2101,61 @@ class spell_item_scroll_of_recall : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
// 36890 - Dimensional Ripper - Area 52
|
||||
enum DimensionalRipperArea52
|
||||
{
|
||||
SPELL_TRANSPORTER_MALFUNCTION = 36895,
|
||||
SPELL_TRANSFORM_HORDE = 36897,
|
||||
SPELL_TRANSFORM_ALLIANCE = 36899,
|
||||
SPELL_SOUL_SPLIT_EVIL = 36900,
|
||||
SPELL_SOUL_SPLIT_GOOD = 36901
|
||||
};
|
||||
|
||||
class spell_item_dimensional_ripper_area52 : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_item_dimensional_ripper_area52);
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->GetTypeId() == TYPEID_PLAYER;
|
||||
}
|
||||
|
||||
void HandleScript(SpellEffIndex /* effIndex */)
|
||||
{
|
||||
if (!roll_chance_i(50)) // 50% success
|
||||
return;
|
||||
|
||||
Unit* caster = GetCaster();
|
||||
|
||||
uint32 spellId = 0;
|
||||
switch (urand(0, 3))
|
||||
{
|
||||
case 0:
|
||||
spellId = SPELL_TRANSPORTER_MALFUNCTION;
|
||||
break;
|
||||
case 1:
|
||||
spellId = SPELL_SOUL_SPLIT_EVIL;
|
||||
break;
|
||||
case 2:
|
||||
spellId = SPELL_SOUL_SPLIT_GOOD;
|
||||
break;
|
||||
case 3:
|
||||
if (caster->ToPlayer()->GetTeamId() == TEAM_ALLIANCE)
|
||||
spellId = SPELL_TRANSFORM_HORDE;
|
||||
else
|
||||
spellId = SPELL_TRANSFORM_ALLIANCE;
|
||||
break;
|
||||
}
|
||||
|
||||
caster->CastSpell(caster, spellId, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_item_dimensional_ripper_area52::HandleScript, EFFECT_0, SPELL_EFFECT_TELEPORT_UNITS);
|
||||
}
|
||||
};
|
||||
|
||||
// 71169 - Shadow's Fate (Shadowmourne questline)
|
||||
enum ShadowsFate
|
||||
{
|
||||
@@ -3184,6 +3239,28 @@ class spell_item_rocket_boots : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
class spell_item_runic_healing_injector : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_item_runic_healing_injector);
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->GetTypeId() == TYPEID_PLAYER;
|
||||
}
|
||||
|
||||
void HandleHeal(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Player* caster = GetCaster()->ToPlayer())
|
||||
if (caster->HasSkill(SKILL_ENGINEERING))
|
||||
SetHitHeal(GetHitHeal() * 1.25f);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_item_runic_healing_injector::HandleHeal, EFFECT_0, SPELL_EFFECT_HEAL);
|
||||
}
|
||||
};
|
||||
|
||||
enum PygmyOil
|
||||
{
|
||||
SPELL_PYGMY_OIL_PYGMY_AURA = 53806,
|
||||
@@ -3585,6 +3662,7 @@ void AddSC_item_spell_scripts()
|
||||
RegisterSpellScript(spell_item_piccolo_of_the_flaming_fire);
|
||||
RegisterSpellScript(spell_item_savory_deviate_delight);
|
||||
RegisterSpellScript(spell_item_scroll_of_recall);
|
||||
RegisterSpellScript(spell_item_dimensional_ripper_area52);
|
||||
RegisterSpellScript(spell_item_unsated_craving);
|
||||
RegisterSpellScript(spell_item_shadows_fate);
|
||||
RegisterSpellScript(spell_item_shadowmourne);
|
||||
@@ -3612,6 +3690,7 @@ void AddSC_item_spell_scripts()
|
||||
RegisterSpellScript(spell_item_nitro_boots);
|
||||
RegisterSpellScript(spell_item_teach_language);
|
||||
RegisterSpellScript(spell_item_rocket_boots);
|
||||
RegisterSpellScript(spell_item_runic_healing_injector);
|
||||
RegisterSpellScript(spell_item_pygmy_oil);
|
||||
RegisterSpellScript(spell_item_unusual_compass);
|
||||
RegisterSpellScript(spell_item_chicken_cover);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "SpellScript.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
enum PriestSpells
|
||||
{
|
||||
@@ -37,6 +38,7 @@ enum PriestSpells
|
||||
SPELL_PRIEST_GLYPH_OF_PRAYER_OF_HEALING_HEAL = 56161,
|
||||
SPELL_PRIEST_GUARDIAN_SPIRIT_HEAL = 48153,
|
||||
SPELL_PRIEST_ITEM_EFFICIENCY = 37595,
|
||||
SPELL_PRIEST_LIGHTWELL_CHARGES = 59907,
|
||||
SPELL_PRIEST_MANA_LEECH_PROC = 34650,
|
||||
SPELL_PRIEST_PENANCE_R1 = 47540,
|
||||
SPELL_PRIEST_PENANCE_R1_DAMAGE = 47758,
|
||||
@@ -61,6 +63,16 @@ enum PriestSpellIcons
|
||||
PRIEST_ICON_ID_PAIN_AND_SUFFERING = 2874,
|
||||
};
|
||||
|
||||
enum Mics
|
||||
{
|
||||
PRIEST_LIGHTWELL_NPC_1 = 31897,
|
||||
PRIEST_LIGHTWELL_NPC_2 = 31896,
|
||||
PRIEST_LIGHTWELL_NPC_3 = 31895,
|
||||
PRIEST_LIGHTWELL_NPC_4 = 31894,
|
||||
PRIEST_LIGHTWELL_NPC_5 = 31893,
|
||||
PRIEST_LIGHTWELL_NPC_6 = 31883
|
||||
};
|
||||
|
||||
class spell_pri_shadowfiend_scaling : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_pri_shadowfiend_scaling);
|
||||
@@ -359,6 +371,48 @@ class spell_pri_item_greater_heal_refund : public AuraScript
|
||||
}
|
||||
};
|
||||
|
||||
// 60123 - Lightwell
|
||||
class spell_pri_lightwell : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_pri_lightwell);
|
||||
|
||||
bool Load() override
|
||||
{
|
||||
return GetCaster()->GetTypeId() == TYPEID_UNIT;
|
||||
}
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /* effIndex */)
|
||||
{
|
||||
Creature* caster = GetCaster()->ToCreature();
|
||||
if (!caster || !caster->IsSummon())
|
||||
return;
|
||||
|
||||
uint32 lightwellRenew = 0;
|
||||
switch (caster->GetEntry())
|
||||
{
|
||||
case PRIEST_LIGHTWELL_NPC_1: lightwellRenew = 7001; break;
|
||||
case PRIEST_LIGHTWELL_NPC_2: lightwellRenew = 27873; break;
|
||||
case PRIEST_LIGHTWELL_NPC_3: lightwellRenew = 27874; break;
|
||||
case PRIEST_LIGHTWELL_NPC_4: lightwellRenew = 28276; break;
|
||||
case PRIEST_LIGHTWELL_NPC_5: lightwellRenew = 48084; break;
|
||||
case PRIEST_LIGHTWELL_NPC_6: lightwellRenew = 48085; break;
|
||||
}
|
||||
|
||||
// proc a spellcast
|
||||
if (Aura* chargesAura = caster->GetAura(SPELL_PRIEST_LIGHTWELL_CHARGES))
|
||||
{
|
||||
caster->CastSpell(GetHitUnit(), lightwellRenew, caster->ToTempSummon()->GetSummonerGUID());
|
||||
if (chargesAura->ModCharges(-1))
|
||||
caster->ToTempSummon()->UnSummon();
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_pri_lightwell::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
// -7001 - Lightwell Renew
|
||||
class spell_pri_lightwell_renew : public AuraScript
|
||||
{
|
||||
@@ -854,6 +908,7 @@ void AddSC_priest_spell_scripts()
|
||||
RegisterSpellScript(spell_pri_guardian_spirit);
|
||||
RegisterSpellScript(spell_pri_hymn_of_hope);
|
||||
RegisterSpellScript(spell_pri_item_greater_heal_refund);
|
||||
RegisterSpellScript(spell_pri_lightwell);
|
||||
RegisterSpellScript(spell_pri_lightwell_renew);
|
||||
RegisterSpellScript(spell_pri_mana_burn);
|
||||
RegisterSpellScript(spell_pri_mana_leech);
|
||||
|
||||
@@ -840,6 +840,33 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum BendingShinbone
|
||||
{
|
||||
SPELL_BENDING_SHINBONE1 = 8854,
|
||||
SPELL_BENDING_SHINBONE2 = 8855
|
||||
};
|
||||
|
||||
class spell_q1846_bending_shinbone : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_q1846_bending_shinbone);
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /* effIndex */)
|
||||
{
|
||||
Item* target = GetHitItem();
|
||||
Unit* caster = GetCaster();
|
||||
if (!target && caster->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
uint32 const spellId = roll_chance_i(20) ? SPELL_BENDING_SHINBONE1 : SPELL_BENDING_SHINBONE2;
|
||||
caster->CastSpell(caster, spellId, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_q1846_bending_shinbone::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
// 9712 - Thaumaturgy Channel
|
||||
enum ThaumaturgyChannel
|
||||
{
|
||||
@@ -2400,6 +2427,7 @@ void AddSC_quest_spell_scripts()
|
||||
RegisterSpellScript(spell_q10985_light_of_the_naaru);
|
||||
RegisterSpellScript(spell_q9718_crow_transform);
|
||||
new spell_q55_sacred_cleansing();
|
||||
RegisterSpellScript(spell_q1846_bending_shinbone);
|
||||
RegisterSpellScript(spell_q2203_thaumaturgy_channel);
|
||||
RegisterSpellScript(spell_q5206_test_fetid_skull);
|
||||
RegisterSpellScript(spell_q6124_6129_apply_salve);
|
||||
|
||||
Reference in New Issue
Block a user