mirror of
https://github.com/liyunfan1223/azerothcore-wotlk.git
synced 2026-08-04 22:07:52 +00:00
Merge branch 'azerothcore:master' into Playerbot
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -67,7 +67,7 @@ nbproject/
|
||||
.idea
|
||||
cmake-build-debug/*
|
||||
cmake-build-debug-coverage/*
|
||||
cmake-build-debug-event-trace
|
||||
cmake-build-debug-event-trace/*
|
||||
coverage-report/
|
||||
|
||||
#
|
||||
|
||||
5
data/sql/updates/db_world/2022_06_26_00.sql
Normal file
5
data/sql/updates/db_world/2022_06_26_00.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- DB update 2022_06_22_03 -> 2022_06_26_00
|
||||
--
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id`=24315;
|
||||
INSERT INTO `spell_script_names` VALUES
|
||||
(24315,'spell_threatening_gaze_charge');
|
||||
10
data/sql/updates/db_world/2022_06_26_01.sql
Normal file
10
data/sql/updates/db_world/2022_06_26_01.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
-- DB update 2022_06_26_00 -> 2022_06_26_01
|
||||
--
|
||||
SET @ENTRY := 14517;
|
||||
SET @PATH := @ENTRY*10;
|
||||
UPDATE `creature_template_movement` SET `Flight` = 2 WHERE `CreatureId` = @ENTRY;
|
||||
|
||||
DELETE FROM `waypoint_data` WHERE `id` = @PATH;
|
||||
INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `move_type`, `action`, `action_chance`, `wpguid`) VALUES
|
||||
(@PATH, 1, -12291.88, -1380.0778, 144.90173, 2.286381244659423828, 0, 2, 0, 100, 0),
|
||||
(@PATH, 2, -12273.857, -1407.774, 132.22281, 0, 0, 2, 0, 100, 0);
|
||||
5
data/sql/updates/db_world/2022_06_26_02.sql
Normal file
5
data/sql/updates/db_world/2022_06_26_02.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
-- DB update 2022_06_26_01 -> 2022_06_26_02
|
||||
--
|
||||
DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_hakkar_blood_siphon');
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(24324, 'spell_hakkar_blood_siphon');
|
||||
6
data/sql/updates/db_world/2022_06_26_03.sql
Normal file
6
data/sql/updates/db_world/2022_06_26_03.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
-- DB update 2022_06_26_02 -> 2022_06_26_03
|
||||
|
||||
DELETE FROM `creature_template_movement` WHERE `CreatureId`=11502;
|
||||
INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`, `Chase`, `Random`, `InteractionPauseTimer`) VALUES
|
||||
(11502, 0, 0, 0, 1, 0, 0, NULL);
|
||||
|
||||
3
data/sql/updates/db_world/2022_06_26_04.sql
Normal file
3
data/sql/updates/db_world/2022_06_26_04.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
-- DB update 2022_06_26_03 -> 2022_06_26_04
|
||||
--
|
||||
UPDATE `quest_offer_reward` SET `RewardText` = 'Your tenacity and courage are astounding, $G priest:priestess;. You have earned the right to hold the Splinter of Nordrassil. Only one task remains: The Eye of Shadow must be recovered. Scour the world.' WHERE `ID` = 7622;
|
||||
7
data/sql/updates/db_world/2022_06_26_05.sql
Normal file
7
data/sql/updates/db_world/2022_06_26_05.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
-- DB update 2022_06_26_04 -> 2022_06_26_05
|
||||
--
|
||||
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 14605;
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 14605) AND (`source_type` = 0) AND (`id` IN (0));
|
||||
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
|
||||
(14605, 0, 0, 0, 67, 0, 100, 0, 3000, 10000, 0, 0, 0, 11, 8355, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Bone Construct - On Behind Target - Cast \'Exploit Weakness\'');
|
||||
3
data/sql/updates/db_world/2022_06_27_00.sql
Normal file
3
data/sql/updates/db_world/2022_06_27_00.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
-- DB update 2022_06_26_05 -> 2022_06_27_00
|
||||
-- fix Woodlands Walker gossip
|
||||
UPDATE `creature_template` SET `npcflag`=`npcflag` |1 WHERE `entry` = 26421;
|
||||
9
data/sql/updates/db_world/2022_06_27_01.sql
Normal file
9
data/sql/updates/db_world/2022_06_27_01.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
-- DB update 2022_06_27_00 -> 2022_06_27_01
|
||||
--
|
||||
DELETE FROM `areatrigger_scripts` WHERE `entry`=3956;
|
||||
INSERT INTO `areatrigger_scripts` VALUES
|
||||
(3956,'at_zulgurub_bridge_speech');
|
||||
|
||||
DELETE FROM `creature_text` WHERE `CreatureID`=14834 AND `GroupId`=4;
|
||||
INSERT INTO `creature_text` VALUES
|
||||
(14834,4,0,'Your callous disregard for the sovereign might of the Gurubashi Empire has been noted. The inhabitants of Zul\'Gurub have been alerted to your presence.',16,0,100,0,0,0,10550,3,'Hakkar SAY_PROTECT_GURUBASHI_EMPIRE');
|
||||
@@ -207,6 +207,9 @@ public:
|
||||
|
||||
static bool IsInBounds(CreatureBoundary const& boundary, Position const* who);
|
||||
bool IsInBoundary(Position const* who = nullptr) const;
|
||||
|
||||
virtual void CalculateThreat(Unit* /*hatedUnit*/, float& /*threat*/, SpellInfo const* /*threatSpell*/) { }
|
||||
|
||||
protected:
|
||||
virtual void MoveInLineOfSight(Unit* /*who*/);
|
||||
|
||||
|
||||
@@ -38,12 +38,23 @@ void HostileRefMgr::threatAssist(Unit* victim, float baseThreat, SpellInfo const
|
||||
return;
|
||||
|
||||
HostileReference* ref = getFirst();
|
||||
float threat = ThreatCalcHelper::calcThreat(victim, iOwner, baseThreat, (threatSpell ? threatSpell->GetSchoolMask() : SPELL_SCHOOL_MASK_NORMAL), threatSpell);
|
||||
float threat = ThreatCalcHelper::calcThreat(victim, baseThreat, (threatSpell ? threatSpell->GetSchoolMask() : SPELL_SCHOOL_MASK_NORMAL), threatSpell);
|
||||
threat /= getSize();
|
||||
while (ref)
|
||||
{
|
||||
if (ThreatCalcHelper::isValidProcess(victim, ref->GetSource()->GetOwner(), threatSpell))
|
||||
Unit* refOwner = ref->GetSource()->GetOwner();
|
||||
if (ThreatCalcHelper::isValidProcess(victim, refOwner, threatSpell))
|
||||
{
|
||||
if (Creature* hatingCreature = refOwner->ToCreature())
|
||||
{
|
||||
if (hatingCreature->IsAIEnabled)
|
||||
{
|
||||
hatingCreature->AI()->CalculateThreat(victim, threat, threatSpell);
|
||||
}
|
||||
}
|
||||
|
||||
ref->GetSource()->doAddThreat(victim, threat);
|
||||
}
|
||||
|
||||
ref = ref->next();
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
//==============================================================
|
||||
|
||||
// The hatingUnit is not used yet
|
||||
float ThreatCalcHelper::calcThreat(Unit* hatedUnit, Unit* /*hatingUnit*/, float threat, SpellSchoolMask schoolMask, SpellInfo const* threatSpell)
|
||||
float ThreatCalcHelper::calcThreat(Unit* hatedUnit, float threat, SpellSchoolMask schoolMask, SpellInfo const* threatSpell)
|
||||
{
|
||||
if (threatSpell)
|
||||
{
|
||||
if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(threatSpell->Id))
|
||||
if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(threatSpell->Id))
|
||||
if (threatEntry->pctMod != 1.0f)
|
||||
threat *= threatEntry->pctMod;
|
||||
|
||||
@@ -427,10 +427,19 @@ void ThreatMgr::clearReferences()
|
||||
|
||||
void ThreatMgr::addThreat(Unit* victim, float threat, SpellSchoolMask schoolMask, SpellInfo const* threatSpell)
|
||||
{
|
||||
if (!ThreatCalcHelper::isValidProcess(victim, GetOwner(), threatSpell))
|
||||
if (!ThreatCalcHelper::isValidProcess(victim, iOwner, threatSpell))
|
||||
return;
|
||||
|
||||
doAddThreat(victim, ThreatCalcHelper::calcThreat(victim, iOwner, threat, schoolMask, threatSpell));
|
||||
threat = ThreatCalcHelper::calcThreat(victim, threat, schoolMask, threatSpell);
|
||||
if (Creature* hatingCreature = iOwner->ToCreature())
|
||||
{
|
||||
if (hatingCreature->IsAIEnabled)
|
||||
{
|
||||
hatingCreature->AI()->CalculateThreat(victim, threat, threatSpell);
|
||||
}
|
||||
}
|
||||
|
||||
doAddThreat(victim, threat);
|
||||
}
|
||||
|
||||
void ThreatMgr::doAddThreat(Unit* victim, float threat)
|
||||
|
||||
@@ -39,7 +39,7 @@ class SpellInfo;
|
||||
|
||||
struct ThreatCalcHelper
|
||||
{
|
||||
static float calcThreat(Unit* hatedUnit, Unit* hatingUnit, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* threatSpell = nullptr);
|
||||
static float calcThreat(Unit* hatedUnit, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* threatSpell = nullptr);
|
||||
static bool isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellInfo const* threatSpell = nullptr);
|
||||
};
|
||||
|
||||
|
||||
@@ -487,7 +487,7 @@ bool Creature::InitEntry(uint32 Entry, const CreatureData* data)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changelevel)
|
||||
bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changelevel, bool updateAI)
|
||||
{
|
||||
if (!InitEntry(Entry, data))
|
||||
return false;
|
||||
@@ -596,6 +596,12 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
|
||||
SetDetectionDistance(cInfo->detection_range);
|
||||
|
||||
LoadSpellTemplateImmunity();
|
||||
|
||||
if (updateAI)
|
||||
{
|
||||
AIM_Initialize();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -169,7 +169,8 @@ public:
|
||||
|
||||
void UpdateMovementFlags();
|
||||
uint32 GetRandomId(uint32 id1, uint32 id2, uint32 id3);
|
||||
bool UpdateEntry(uint32 entry, const CreatureData* data = nullptr, bool changelevel = true );
|
||||
bool UpdateEntry(uint32 entry, const CreatureData* data = nullptr, bool changelevel = true, bool updateAI = false);
|
||||
bool UpdateEntry(uint32 entry, bool updateAI) { return UpdateEntry(entry, nullptr, true, updateAI); }
|
||||
bool UpdateStats(Stats stat) override;
|
||||
bool UpdateAllStats() override;
|
||||
void UpdateResistances(uint32 school) override;
|
||||
|
||||
@@ -553,8 +553,10 @@ void Pet::SavePetToDB(PetSaveMode mode)
|
||||
// save pet
|
||||
std::string actionBar = GenerateActionBarData();
|
||||
|
||||
ASSERT(owner->GetPetStable()->CurrentPet && owner->GetPetStable()->CurrentPet->PetNumber == m_charmInfo->GetPetNumber());
|
||||
FillPetInfo(&owner->GetPetStable()->CurrentPet.value());
|
||||
if (owner->GetPetStable()->CurrentPet && owner->GetPetStable()->CurrentPet->PetNumber == m_charmInfo->GetPetNumber())
|
||||
{
|
||||
FillPetInfo(&owner->GetPetStable()->CurrentPet.value());
|
||||
}
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_PET);
|
||||
stmt->SetData(0, m_charmInfo->GetPetNumber());
|
||||
|
||||
@@ -8975,16 +8975,18 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
|
||||
// only if current pet in slot
|
||||
pet->SavePetToDB(mode);
|
||||
|
||||
ASSERT(m_petStable->CurrentPet && m_petStable->CurrentPet->PetNumber == pet->GetCharmInfo()->GetPetNumber());
|
||||
if (mode == PET_SAVE_NOT_IN_SLOT)
|
||||
if (m_petStable->CurrentPet && m_petStable->CurrentPet->PetNumber == pet->GetCharmInfo()->GetPetNumber())
|
||||
{
|
||||
m_petStable->UnslottedPets.push_back(std::move(*m_petStable->CurrentPet));
|
||||
m_petStable->CurrentPet.reset();
|
||||
if (mode == PET_SAVE_NOT_IN_SLOT)
|
||||
{
|
||||
m_petStable->UnslottedPets.push_back(std::move(*m_petStable->CurrentPet));
|
||||
m_petStable->CurrentPet.reset();
|
||||
}
|
||||
else if (mode == PET_SAVE_AS_DELETED)
|
||||
m_petStable->CurrentPet.reset();
|
||||
// else if (stable slots) handled in opcode handlers due to required swaps
|
||||
// else (current pet) doesnt need to do anything
|
||||
}
|
||||
else if (mode == PET_SAVE_AS_DELETED)
|
||||
m_petStable->CurrentPet.reset();
|
||||
// else if (stable slots) handled in opcode handlers due to required swaps
|
||||
// else (current pet) doesnt need to do anything
|
||||
|
||||
SetMinion(pet, false);
|
||||
|
||||
@@ -10594,7 +10596,7 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite
|
||||
// cooldown information stored in item prototype
|
||||
// This used in same way in WorldSession::HandleItemQuerySingleOpcode data sending to client.
|
||||
|
||||
bool useSpellCooldown = false;
|
||||
bool useSpellCooldown = spellInfo->HasAttribute(SPELL_ATTR7_CAN_BE_MULTI_CAST);
|
||||
if (itemId)
|
||||
{
|
||||
if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId))
|
||||
|
||||
@@ -2330,14 +2330,14 @@ void Unit::CalcHealAbsorb(HealInfo& healInfo)
|
||||
healInfo.AbsorbHeal(absorbAmount);
|
||||
}
|
||||
|
||||
void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra)
|
||||
void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType /*= BASE_ATTACK*/, bool extra /*= false*/, bool ignoreCasting /*= false*/)
|
||||
{
|
||||
if (HasUnitFlag(UNIT_FLAG_PACIFIED))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) && !extra)
|
||||
if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) && !extra && !ignoreCasting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -7845,13 +7845,9 @@ bool Unit::HandleDummyAuraProc(Unit* victim, uint32 damage, AuraEffect* triggere
|
||||
if (AuraEffect const* aurEff = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, 0x10000000, 0x0, 0x0, GetGUID()))
|
||||
{
|
||||
Aura* flameShock = aurEff->GetBase();
|
||||
int32 maxDuration = flameShock->GetMaxDuration();
|
||||
int32 newDuration = flameShock->GetDuration() + 2 * aurEff->GetAmplitude();
|
||||
|
||||
flameShock->SetDuration(newDuration);
|
||||
// is it blizzlike to change max duration for FS?
|
||||
if (newDuration > maxDuration)
|
||||
flameShock->SetMaxDuration(newDuration);
|
||||
int32 extraTime = 2 * aurEff->GetAmplitude();
|
||||
flameShock->SetMaxDuration(flameShock->GetMaxDuration() + extraTime);
|
||||
flameShock->SetDuration(flameShock->GetDuration() + extraTime);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -17994,8 +17990,7 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
|
||||
GetMotionMaster()->MoveIdle();
|
||||
StopMoving();
|
||||
|
||||
if (charmer->GetTypeId() == TYPEID_PLAYER &&
|
||||
charmer->getClass() == CLASS_WARLOCK)
|
||||
if (charmer->GetTypeId() == TYPEID_PLAYER && charmer->getClass() == CLASS_WARLOCK && ToCreature()->GetCreatureTemplate()->type == CREATURE_TYPE_DEMON)
|
||||
{
|
||||
// Disable CreatureAI/SmartAI and switch to CharmAI when charmed by warlock
|
||||
Creature* charmed = ToCreature();
|
||||
@@ -18649,23 +18644,38 @@ void Unit::SetPhaseMask(uint32 newPhaseMask, bool update)
|
||||
}
|
||||
}
|
||||
|
||||
WorldObject::SetPhaseMask(newPhaseMask, update);
|
||||
WorldObject::SetPhaseMask(newPhaseMask, false);
|
||||
|
||||
if (!IsInWorld())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (ControlSet::const_iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); )
|
||||
{
|
||||
Unit* controlled = *itr;
|
||||
++itr;
|
||||
if (controlled->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
controlled->SetPhaseMask(newPhaseMask, true);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < MAX_SUMMON_SLOT; ++i)
|
||||
{
|
||||
if (m_SummonSlot[i])
|
||||
{
|
||||
if (Creature* summon = GetMap()->GetCreature(m_SummonSlot[i]))
|
||||
{
|
||||
summon->SetPhaseMask(newPhaseMask, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (update)
|
||||
{
|
||||
UpdateObjectVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::UpdateObjectVisibility(bool forced, bool /*fromUpdate*/)
|
||||
|
||||
@@ -1534,7 +1534,7 @@ public:
|
||||
void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, std::list<AuraApplication*>& procAuras);
|
||||
|
||||
void HandleEmoteCommand(uint32 emoteId);
|
||||
void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false);
|
||||
void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false, bool ignoreCasting = false);
|
||||
|
||||
void CalculateMeleeDamage(Unit* victim, uint32 damage, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK, const bool sittingVictim = false);
|
||||
void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss);
|
||||
|
||||
@@ -48,7 +48,7 @@ void BuildPartyLockDungeonBlock(WorldPacket& data, const lfg::LfgLockPartyMap& l
|
||||
|
||||
void WorldSession::HandleLfgJoinOpcode(WorldPackets::LFG::LFGJoin& packet)
|
||||
{
|
||||
if (!sLFGMgr->isOptionEnabled(lfg::LFG_OPTION_ENABLE_DUNGEON_FINDER | lfg::LFG_OPTION_ENABLE_RAID_BROWSER) ||
|
||||
if (!sLFGMgr->isOptionEnabled(lfg::LFG_OPTION_ENABLE_DUNGEON_FINDER | lfg::LFG_OPTION_ENABLE_RAID_BROWSER | lfg::LFG_OPTION_ENABLE_SEASONAL_BOSSES) ||
|
||||
(GetPlayer()->GetGroup() && GetPlayer()->GetGroup()->GetLeaderGUID() != GetPlayer()->GetGUID() &&
|
||||
(GetPlayer()->GetGroup()->GetMembersCount() == MAXGROUPSIZE || !GetPlayer()->GetGroup()->isLFGGroup())))
|
||||
return;
|
||||
|
||||
@@ -1363,12 +1363,6 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->Effects[EFFECT_0].Amplitude = 15000;
|
||||
});
|
||||
|
||||
// Threatening Gaze
|
||||
ApplySpellFix({ 24314 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CAST;
|
||||
});
|
||||
|
||||
// Frightening Shout
|
||||
ApplySpellFix({ 19134 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
@@ -4295,6 +4289,12 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->Effects[EFFECT_0].MiscValueB = 844;
|
||||
});
|
||||
|
||||
// Hakkar Cause Insanity
|
||||
ApplySpellFix({ 24327 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Dispel = DISPEL_NONE;
|
||||
});
|
||||
|
||||
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||
|
||||
@@ -982,7 +982,7 @@ struct npc_drakonid_spawner : public ScriptedAI
|
||||
{
|
||||
if (Creature* construct = ObjectAccessor::GetCreature(*me, summonGuid))
|
||||
{
|
||||
construct->UpdateEntry(NPC_BONE_CONSTRUCT);
|
||||
construct->UpdateEntry(NPC_BONE_CONSTRUCT, true);
|
||||
construct->SetReactState(REACT_PASSIVE);
|
||||
construct->SetStandState(UNIT_STAND_STATE_DEAD);
|
||||
construct->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
|
||||
@@ -105,7 +105,8 @@ public:
|
||||
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_DAGGER));
|
||||
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(WEAPON_DAGGER));
|
||||
me->SetWalk(false);
|
||||
me->GetMotionMaster()->MovePoint(0, PosMoveOnSpawn[0]);
|
||||
me->SetHomePosition(PosMoveOnSpawn[0]);
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
@@ -131,31 +132,37 @@ public:
|
||||
{
|
||||
uint8 sideA = 0;
|
||||
uint8 sideB = 0;
|
||||
for (std::list<Creature*>::const_iterator itr = triggerList.begin(); itr != triggerList.end(); ++itr)
|
||||
for (auto const& trigger : triggerList)
|
||||
{
|
||||
if (Creature* trigger = *itr)
|
||||
if (trigger->GetPositionY() < -1625.0f)
|
||||
{
|
||||
if (trigger->GetPositionY() < -1625.0f)
|
||||
{
|
||||
_triggersSideAGUID[sideA] = trigger->GetGUID();
|
||||
++sideA;
|
||||
}
|
||||
else
|
||||
{
|
||||
_triggersSideBGUID[sideB] = trigger->GetGUID();
|
||||
++sideB;
|
||||
}
|
||||
_triggersSideAGUID[sideA] = trigger->GetGUID();
|
||||
++sideA;
|
||||
}
|
||||
else
|
||||
{
|
||||
_triggersSideBGUID[sideB] = trigger->GetGUID();
|
||||
++sideB;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JustReachedHome() override
|
||||
{
|
||||
if (GameObject* object = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_GONG_OF_BETHEKK)))
|
||||
object->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
BossAI::EnterEvadeMode(why);
|
||||
if (GameObject* object = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(GO_GONG_OF_BETHEKK)))
|
||||
object->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
|
||||
me->DespawnOrUnsummon(4000);
|
||||
|
||||
std::list<Creature*> panthers;
|
||||
GetCreatureListWithEntryInGrid(panthers, me, NPC_ZULIAN_PROWLER, 200.f);
|
||||
for (auto const& panther : panthers)
|
||||
panther->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void SetData(uint32 id, uint32 /*value*/) override
|
||||
@@ -221,33 +228,27 @@ public:
|
||||
}
|
||||
case EVENT_TRANSFORM:
|
||||
{
|
||||
DoCast(me, SPELL_PANTHER_TRANSFORM); // SPELL_AURA_TRANSFORM
|
||||
DoCastSelf(SPELL_PANTHER_TRANSFORM); // SPELL_AURA_TRANSFORM
|
||||
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(EQUIP_UNEQUIP));
|
||||
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(EQUIP_UNEQUIP));
|
||||
/*
|
||||
const CreatureTemplate* cinfo = me->GetCreatureTemplate();
|
||||
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 35)));
|
||||
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 35)));
|
||||
me->UpdateDamagePhysical(BASE_ATTACK);
|
||||
*/
|
||||
me->AttackStop();
|
||||
DoResetThreat();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
|
||||
DoCast(me, SPELL_VANISH_VISUAL);
|
||||
DoCast(me, SPELL_VANISH);
|
||||
DoCastSelf(SPELL_VANISH_VISUAL);
|
||||
DoCastSelf(SPELL_VANISH);
|
||||
events.ScheduleEvent(EVENT_VANISH, 1000, 0, PHASE_ONE);
|
||||
break;
|
||||
}
|
||||
case EVENT_VANISH:
|
||||
DoCast(me, SPELL_SUPER_INVIS);
|
||||
DoCastSelf(SPELL_SUPER_INVIS);
|
||||
me->SetWalk(false);
|
||||
me->GetMotionMaster()->MovePoint(0, frand(-11551.0f, -11508.0f), frand(-1638.0f, -1617.0f), me->GetPositionZ());
|
||||
events.ScheduleEvent(EVENT_VANISH_2, 9000, 0, PHASE_ONE);
|
||||
break;
|
||||
case EVENT_VANISH_2:
|
||||
DoCast(me, SPELL_VANISH);
|
||||
DoCast(me, SPELL_SUPER_INVIS);
|
||||
DoCastSelf(SPELL_VANISH);
|
||||
DoCastSelf(SPELL_SUPER_INVIS);
|
||||
events.ScheduleEvent(EVENT_VISIBLE, urand(7000, 10000), 0, PHASE_ONE);
|
||||
break;
|
||||
case EVENT_VISIBLE:
|
||||
@@ -272,12 +273,6 @@ public:
|
||||
DoCast(me, SPELL_VANISH_VISUAL);
|
||||
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 0, uint32(WEAPON_DAGGER));
|
||||
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, uint32(WEAPON_DAGGER));
|
||||
/*
|
||||
const CreatureTemplate* cinfo = me->GetCreatureTemplate();
|
||||
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg));
|
||||
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg));
|
||||
me->UpdateDamagePhysical(BASE_ATTACK);
|
||||
*/
|
||||
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
|
||||
events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, urand(4000, 7000), 0, PHASE_ONE);
|
||||
events.ScheduleEvent(EVENT_GOUGE, urand(12000, 15000), 0, PHASE_ONE);
|
||||
@@ -322,11 +317,6 @@ enum ZulianProwlerEvents
|
||||
EVENT_ATTACK = 1
|
||||
};
|
||||
|
||||
/*Position const PosProwlerCenter[1] =
|
||||
{
|
||||
{ -11556.7f, -1631.344f, 41.2994f, 0.0f }
|
||||
};*/
|
||||
|
||||
class npc_zulian_prowler : public CreatureScript
|
||||
{
|
||||
public:
|
||||
@@ -361,7 +351,9 @@ public:
|
||||
void SpellHit(Unit* caster, SpellInfo const* spell) override
|
||||
{
|
||||
if (spell->Id == SPELL_MARK_OF_ARLOKK_TRIGGER) // Should only hit if line of sight
|
||||
me->Attack(caster, true);
|
||||
{
|
||||
AttackStart(caster);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
@@ -390,7 +382,9 @@ public:
|
||||
{
|
||||
case EVENT_ATTACK:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0.0f, 100, false))
|
||||
me->Attack(target, true);
|
||||
{
|
||||
AttackStart(target);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -38,7 +38,8 @@ enum Events
|
||||
EVENT_AVATAR = 1,
|
||||
EVENT_GROUND_TREMOR = 2,
|
||||
EVENT_START_PURSUIT = 3,
|
||||
EVENT_ENTANGLING_ROOTS = 4
|
||||
EVENT_STOP_PURSUIT = 4,
|
||||
EVENT_ENTANGLING_ROOTS = 5
|
||||
};
|
||||
|
||||
class boss_grilek : public CreatureScript // grilek
|
||||
@@ -52,6 +53,12 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_pursuitTargetGUID.Clear();
|
||||
BossAI::Reset();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
@@ -75,10 +82,15 @@ public:
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_AVATAR:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
{
|
||||
_pursuitTargetGUID = target->GetGUID();
|
||||
}
|
||||
DoCast(me, SPELL_AVATAR);
|
||||
DoResetThreat();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
DoResetThreat();
|
||||
events.ScheduleEvent(EVENT_START_PURSUIT, 2s);
|
||||
events.ScheduleEvent(EVENT_STOP_PURSUIT, 15s);
|
||||
events.ScheduleEvent(EVENT_AVATAR, 45s, 50s);
|
||||
break;
|
||||
case EVENT_GROUND_TREMOR:
|
||||
@@ -87,6 +99,17 @@ public:
|
||||
break;
|
||||
case EVENT_START_PURSUIT:
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
if (Unit* pursuitTarget = ObjectAccessor::GetUnit(*me, _pursuitTargetGUID))
|
||||
{
|
||||
me->GetThreatMgr().addThreat(pursuitTarget, 1000000.f);
|
||||
}
|
||||
break;
|
||||
case EVENT_STOP_PURSUIT:
|
||||
if (Unit* pursuitTarget = ObjectAccessor::GetUnit(*me, _pursuitTargetGUID))
|
||||
{
|
||||
_pursuitTargetGUID.Clear();
|
||||
me->GetThreatMgr().addThreat(pursuitTarget, -1000000.f);
|
||||
}
|
||||
break;
|
||||
case EVENT_ENTANGLING_ROOTS:
|
||||
DoCastVictim(SPELL_ENTANGLING_ROOTS);
|
||||
@@ -99,6 +122,9 @@ public:
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectGuid _pursuitTargetGUID;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
|
||||
@@ -25,22 +25,26 @@ Category: Zul'Gurub
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "zulgurub.h"
|
||||
|
||||
enum Says
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_FLEEING = 1,
|
||||
SAY_MINION_DESTROY = 2,
|
||||
SAY_PROTECT_ALTAR = 3
|
||||
SAY_AGGRO = 0,
|
||||
SAY_FLEEING = 1,
|
||||
SAY_MINION_DESTROY = 2,
|
||||
SAY_PROTECT_ALTAR = 3,
|
||||
SAY_PROTECT_GURUBASHI_EMPIRE = 4
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_BLOOD_SIPHON = 24322, // Buggy ?
|
||||
SPELL_POISONOUS_BLOOD = 24321,
|
||||
SPELL_BLOOD_SIPHON_HEAL = 24322,
|
||||
SPELL_BLOOD_SIPHON_DMG = 24323,
|
||||
SPELL_BLOOD_SIPHON = 24324,
|
||||
SPELL_CORRUPTED_BLOOD = 24328,
|
||||
SPELL_CAUSE_INSANITY = 24327,
|
||||
SPELL_WILL_OF_HAKKAR = 24178,
|
||||
SPELL_ENRAGE = 24318,
|
||||
// The Aspects of all High Priests spells
|
||||
SPELL_ASPECT_OF_JEKLIK = 24687,
|
||||
@@ -55,14 +59,13 @@ enum Events
|
||||
EVENT_BLOOD_SIPHON = 1,
|
||||
EVENT_CORRUPTED_BLOOD = 2,
|
||||
EVENT_CAUSE_INSANITY = 3,
|
||||
EVENT_WILL_OF_HAKKAR = 4,
|
||||
EVENT_ENRAGE = 5,
|
||||
EVENT_ENRAGE = 4,
|
||||
// The Aspects of all High Priests events
|
||||
EVENT_ASPECT_OF_JEKLIK = 6,
|
||||
EVENT_ASPECT_OF_VENOXIS = 7,
|
||||
EVENT_ASPECT_OF_MARLI = 8,
|
||||
EVENT_ASPECT_OF_THEKAL = 9,
|
||||
EVENT_ASPECT_OF_ARLOKK = 10
|
||||
EVENT_ASPECT_OF_JEKLIK = 5,
|
||||
EVENT_ASPECT_OF_VENOXIS = 6,
|
||||
EVENT_ASPECT_OF_MARLI = 7,
|
||||
EVENT_ASPECT_OF_THEKAL = 8,
|
||||
EVENT_ASPECT_OF_ARLOKK = 9
|
||||
};
|
||||
|
||||
class boss_hakkar : public CreatureScript
|
||||
@@ -74,6 +77,16 @@ public:
|
||||
{
|
||||
boss_hakkarAI(Creature* creature) : BossAI(creature, DATA_HAKKAR) { }
|
||||
|
||||
bool CheckInRoom() override
|
||||
{
|
||||
if (me->GetPositionZ() < 52.f || me->GetPositionZ() > 57.28f)
|
||||
{
|
||||
BossAI::EnterEvadeMode(EVADE_REASON_BOUNDARY);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
@@ -90,7 +103,6 @@ public:
|
||||
events.ScheduleEvent(EVENT_BLOOD_SIPHON, 90000);
|
||||
events.ScheduleEvent(EVENT_CORRUPTED_BLOOD, 25000);
|
||||
events.ScheduleEvent(EVENT_CAUSE_INSANITY, 17000);
|
||||
events.ScheduleEvent(EVENT_WILL_OF_HAKKAR, 17000);
|
||||
events.ScheduleEvent(EVENT_ENRAGE, 600000);
|
||||
if (instance->GetBossState(DATA_JEKLIK) != DONE)
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_JEKLIK, 4000);
|
||||
@@ -107,7 +119,7 @@ public:
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
if (!UpdateVictim() || !CheckInRoom())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
@@ -120,7 +132,7 @@ public:
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_BLOOD_SIPHON:
|
||||
DoCastVictim(SPELL_BLOOD_SIPHON, true);
|
||||
DoCastAOE(SPELL_BLOOD_SIPHON, true);
|
||||
events.ScheduleEvent(EVENT_BLOOD_SIPHON, 90000);
|
||||
break;
|
||||
case EVENT_CORRUPTED_BLOOD:
|
||||
@@ -128,20 +140,15 @@ public:
|
||||
events.ScheduleEvent(EVENT_CORRUPTED_BLOOD, urand(30000, 45000));
|
||||
break;
|
||||
case EVENT_CAUSE_INSANITY:
|
||||
if (Unit* victim = SelectTarget(SelectTargetMethod::MaxThreat, 0))
|
||||
if (Unit* victim = SelectTarget(SelectTargetMethod::MaxThreat, 0, 30.f, true))
|
||||
{
|
||||
DoCast(victim, SPELL_CAUSE_INSANITY, true);
|
||||
DoCast(victim, SPELL_CAUSE_INSANITY);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CAUSE_INSANITY, urand(35000, 45000));
|
||||
break;
|
||||
case EVENT_WILL_OF_HAKKAR:
|
||||
// Xinef: Skip Tank
|
||||
DoCast(SelectTarget(SelectTargetMethod::Random, 1, 100, true), SPELL_WILL_OF_HAKKAR);
|
||||
events.ScheduleEvent(EVENT_WILL_OF_HAKKAR, urand(25000, 35000));
|
||||
break;
|
||||
case EVENT_ENRAGE:
|
||||
if (!me->HasAura(SPELL_ENRAGE))
|
||||
DoCast(me, SPELL_ENRAGE);
|
||||
DoCastSelf(SPELL_ENRAGE);
|
||||
events.ScheduleEvent(EVENT_ENRAGE, 90000);
|
||||
break;
|
||||
case EVENT_ASPECT_OF_JEKLIK:
|
||||
@@ -153,7 +160,11 @@ public:
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_VENOXIS, 8000);
|
||||
break;
|
||||
case EVENT_ASPECT_OF_MARLI:
|
||||
DoCastVictim(SPELL_ASPECT_OF_MARLI, true);
|
||||
if (Unit* victim = SelectTarget(SelectTargetMethod::MaxThreat, 0, 5.f, true))
|
||||
{
|
||||
DoCast(victim, SPELL_ASPECT_OF_MARLI, true);
|
||||
me->GetThreatMgr().modifyThreatPercent(victim, -100.f);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 10000);
|
||||
break;
|
||||
case EVENT_ASPECT_OF_THEKAL:
|
||||
@@ -161,7 +172,11 @@ public:
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_THEKAL, 15000);
|
||||
break;
|
||||
case EVENT_ASPECT_OF_ARLOKK:
|
||||
DoCastVictim(SPELL_ASPECT_OF_ARLOKK, true);
|
||||
if (Unit* victim = SelectTarget(SelectTargetMethod::MaxThreat, 0, 5.f, true))
|
||||
{
|
||||
DoCast(victim, SPELL_ASPECT_OF_ARLOKK, true);
|
||||
me->GetThreatMgr().modifyThreatPercent(victim, -100.f);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_ASPECT_OF_ARLOKK, urand(10000, 15000));
|
||||
break;
|
||||
default:
|
||||
@@ -195,6 +210,28 @@ public:
|
||||
if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR)))
|
||||
{
|
||||
hakkar->setActive(true);
|
||||
if (hakkar->GetAI())
|
||||
{
|
||||
hakkar->AI()->Talk(SAY_PROTECT_GURUBASHI_EMPIRE);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class at_zulgurub_bridge_speech : public OnlyOnceAreaTriggerScript
|
||||
{
|
||||
public:
|
||||
at_zulgurub_bridge_speech() : OnlyOnceAreaTriggerScript("at_zulgurub_bridge_speech") {}
|
||||
|
||||
bool _OnTrigger(Player* player, const AreaTrigger* /*at*/) override
|
||||
{
|
||||
if (InstanceScript* instance = player->GetInstanceScript())
|
||||
{
|
||||
if (Creature* hakkar = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_HAKKAR)))
|
||||
{
|
||||
if (hakkar->GetAI())
|
||||
{
|
||||
hakkar->AI()->Talk(SAY_PROTECT_ALTAR);
|
||||
@@ -228,9 +265,39 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class spell_hakkar_blood_siphon : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_hakkar_blood_siphon);
|
||||
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_BLOOD_SIPHON_HEAL, SPELL_BLOOD_SIPHON_DMG });
|
||||
}
|
||||
|
||||
void OnSpellHit()
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
Unit* target = GetHitUnit();
|
||||
if (!caster || !target)
|
||||
return;
|
||||
|
||||
if (target->HasAura(SPELL_POISONOUS_BLOOD))
|
||||
target->CastSpell(caster, SPELL_BLOOD_SIPHON_DMG, true);
|
||||
else
|
||||
target->CastSpell(caster, SPELL_BLOOD_SIPHON_HEAL, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnHit += SpellHitFn(spell_hakkar_blood_siphon::OnSpellHit);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_hakkar()
|
||||
{
|
||||
new boss_hakkar();
|
||||
new at_zulgurub_entrance_speech();
|
||||
new at_zulgurub_bridge_speech();
|
||||
new at_zulgurub_temple_speech();
|
||||
RegisterSpellScript(spell_hakkar_blood_siphon);
|
||||
}
|
||||
|
||||
@@ -97,6 +97,13 @@ Position const SpawnBat[6] =
|
||||
{ -12293.6220f, -1380.2640f, 144.8304f, 5.483f }
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
PATH_JEKLIK_INTRO = 145170
|
||||
};
|
||||
|
||||
Position const homePosition = { -12291.9f, -1380.08f, 144.902f, 2.28638f };
|
||||
|
||||
struct boss_jeklik : public BossAI
|
||||
{
|
||||
boss_jeklik(Creature* creature) : BossAI(creature, DATA_JEKLIK) { }
|
||||
@@ -106,7 +113,9 @@ struct boss_jeklik : public BossAI
|
||||
DoCastSelf(SPELL_GREEN_CHANNELING);
|
||||
me->SetHover(false);
|
||||
me->SetDisableGravity(false);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
_Reset();
|
||||
SetCombatMovement(false);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
@@ -117,22 +126,31 @@ struct boss_jeklik : public BossAI
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
const Position homePos = me->GetHomePosition();
|
||||
me->NearTeleportTo(homePos.GetPositionX(), homePos.GetPositionY(), homePos.GetPositionZ(), homePos.GetOrientation());
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->SetHomePosition(homePosition);
|
||||
me->NearTeleportTo(homePosition.GetPositionX(), homePosition.GetPositionY(), homePosition.GetPositionZ(), homePosition.GetOrientation());
|
||||
BossAI::EnterEvadeMode(why);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
Talk(SAY_AGGRO);
|
||||
me->RemoveAurasDueToSpell(SPELL_GREEN_CHANNELING);
|
||||
me->SetHover(true);
|
||||
me->SetDisableGravity(true);
|
||||
me->AddUnitState(UNIT_STATE_IGNORE_PATHFINDING);
|
||||
DoCastSelf(SPELL_BAT_FORM);
|
||||
events.SetPhase(PHASE_ONE);
|
||||
DoCastSelf(SPELL_BAT_FORM, true);
|
||||
|
||||
me->GetMotionMaster()->MovePath(PATH_JEKLIK_INTRO, false);
|
||||
}
|
||||
|
||||
void PathEndReached(uint32 /*pathId*/) override
|
||||
{
|
||||
me->SetHover(false);
|
||||
me->SetDisableGravity(false);
|
||||
_EnterCombat();
|
||||
SetCombatMovement(true);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
events.SetPhase(PHASE_ONE);
|
||||
events.ScheduleEvent(EVENT_CHARGE_JEKLIK, urand(10000, 20000), PHASE_ONE);
|
||||
events.ScheduleEvent(EVENT_PIERCE_ARMOR, urand(5000, 15000), PHASE_ONE);
|
||||
events.ScheduleEvent(EVENT_BLOOD_LEECH, urand(5000, 15000), PHASE_ONE);
|
||||
@@ -146,8 +164,6 @@ struct boss_jeklik : public BossAI
|
||||
if (events.IsInPhase(PHASE_ONE) && !HealthAbovePct(50))
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_BAT_FORM);
|
||||
me->SetHover(false);
|
||||
me->SetDisableGravity(false);
|
||||
DoResetThreat();
|
||||
events.SetPhase(PHASE_TWO);
|
||||
events.CancelEventGroup(PHASE_ONE);
|
||||
|
||||
@@ -80,7 +80,8 @@ enum Misc
|
||||
MODEL_OHGAN_MOUNT = 15271,
|
||||
PATH_MANDOKIR = 492861,
|
||||
POINT_MANDOKIR_END = 24,
|
||||
CHAINED_SPIRIT_COUNT = 20
|
||||
CHAINED_SPIRIT_COUNT = 20,
|
||||
ACTION_CHARGE = 1
|
||||
};
|
||||
|
||||
Position const PosSummonChainedSpirits[CHAINED_SPIRIT_COUNT] =
|
||||
@@ -169,6 +170,7 @@ public:
|
||||
me->Mount(MODEL_OHGAN_MOUNT);
|
||||
reviveGUID.Clear();
|
||||
_useExecute = false;
|
||||
_chargeTarget.first.Clear();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
@@ -226,9 +228,44 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void SetGUID(ObjectGuid const guid, int32 /*type = 0 */) override
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
reviveGUID = guid;
|
||||
if (action == ACTION_START_REVIVE)
|
||||
{
|
||||
std::list<Creature*> creatures;
|
||||
GetCreatureListWithEntryInGrid(creatures, me, NPC_CHAINED_SPIRIT, 200.0f);
|
||||
if (creatures.empty())
|
||||
return;
|
||||
|
||||
for (std::list<Creature*>::iterator itr = creatures.begin(); itr != creatures.end(); ++itr)
|
||||
{
|
||||
if (Creature* chainedSpirit = ObjectAccessor::GetCreature(*me, (*itr)->GetGUID()))
|
||||
{
|
||||
chainedSpirit->AI()->SetGUID(reviveGUID);
|
||||
chainedSpirit->AI()->DoAction(ACTION_REVIVE);
|
||||
reviveGUID.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetGUID(ObjectGuid const guid, int32 type) override
|
||||
{
|
||||
if (type == ACTION_CHARGE)
|
||||
{
|
||||
if (_chargeTarget.first == guid && _chargeTarget.second > 0.f)
|
||||
{
|
||||
if (Unit* target = ObjectAccessor::GetUnit(*me, _chargeTarget.first))
|
||||
{
|
||||
me->RemoveAurasDueToSpell(SPELL_WHIRLWIND);
|
||||
DoCast(target, SPELL_WATCH_CHARGE, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reviveGUID = guid;
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
@@ -244,6 +281,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void CalculateThreat(Unit* hatedUnit, float& threat, SpellInfo const* threatSpell) override
|
||||
{
|
||||
if (_chargeTarget.first == hatedUnit->GetGUID())
|
||||
{
|
||||
// Do not count DOTs/HOTs
|
||||
if (!threatSpell || !threatSpell->HasAttribute(SPELL_ATTR0_CU_NO_INITIAL_THREAT))
|
||||
{
|
||||
_chargeTarget.second += threat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DamageDealt(Unit* doneTo, uint32& damage, DamageEffectType /*damagetype*/) override
|
||||
{
|
||||
if (doneTo && doneTo == me->GetVictim())
|
||||
@@ -264,6 +313,43 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void DoMeleeAttackIfReady(bool ignoreCasting)
|
||||
{
|
||||
if (!ignoreCasting && me->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Unit* victim = me->GetVictim();
|
||||
if (!victim || !victim->IsInWorld())
|
||||
return;
|
||||
|
||||
if (!me->IsWithinMeleeRange(victim))
|
||||
return;
|
||||
|
||||
//Make sure our attack is ready and we aren't currently casting before checking distance
|
||||
if (me->isAttackReady())
|
||||
{
|
||||
// xinef: prevent base and off attack in same time, delay attack at 0.2 sec
|
||||
if (me->haveOffhandWeapon())
|
||||
if (me->getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY)
|
||||
me->setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY);
|
||||
|
||||
me->AttackerStateUpdate(victim, BASE_ATTACK, false, ignoreCasting);
|
||||
me->resetAttackTimer();
|
||||
}
|
||||
|
||||
if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK))
|
||||
{
|
||||
// xinef: delay main hand attack if both will hit at the same time (players code)
|
||||
if (me->getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY)
|
||||
me->setAttackTimer(BASE_ATTACK, ATTACK_DISPLAY_DELAY);
|
||||
|
||||
me->AttackerStateUpdate(victim, OFF_ATTACK, false, ignoreCasting);
|
||||
me->resetAttackTimer(OFF_ATTACK);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events.Update(diff);
|
||||
@@ -299,7 +385,14 @@ public:
|
||||
}
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasUnitState(UNIT_STATE_CHARGING))
|
||||
{
|
||||
if (me->GetCurrentSpellCastTime(SPELL_WATCH) >= 0)
|
||||
{
|
||||
DoMeleeAttackIfReady(true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
@@ -339,6 +432,7 @@ public:
|
||||
{
|
||||
DoCast(player, SPELL_WATCH);
|
||||
Talk(SAY_WATCH, player);
|
||||
_chargeTarget = std::make_pair(player->GetGUID(), 0.f);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 24000));
|
||||
break;
|
||||
@@ -393,13 +487,14 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
DoMeleeAttackIfReady(false);
|
||||
}
|
||||
|
||||
private:
|
||||
uint8 killCount;
|
||||
ObjectGuid reviveGUID;
|
||||
bool _useExecute;
|
||||
std::pair<ObjectGuid, float> _chargeTarget;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
@@ -614,13 +709,16 @@ public:
|
||||
|
||||
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
|
||||
{
|
||||
if (Unit* target = GetTarget())
|
||||
{
|
||||
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE && GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH)
|
||||
if (Creature* caster = GetCaster()->ToCreature())
|
||||
{
|
||||
caster->CastSpell(target, SPELL_WATCH_CHARGE, true);
|
||||
if (caster->IsAIEnabled)
|
||||
{
|
||||
caster->AI()->SetGUID(target->GetGUID(), ACTION_CHARGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -656,6 +754,29 @@ class spell_mandokir_charge : public SpellScript
|
||||
}
|
||||
};
|
||||
|
||||
class spell_threatening_gaze_charge : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_threatening_gaze_charge)
|
||||
|
||||
void PreventLaunchHit(SpellEffIndex effIndex)
|
||||
{
|
||||
PreventHitDefaultEffect(effIndex);
|
||||
}
|
||||
|
||||
void LaunchHit(SpellEffIndex effIndex)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
if (Unit* target = GetHitUnit())
|
||||
caster->CastSpell(target, GetSpellInfo()->Effects[effIndex].TriggerSpell, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectLaunchTarget += SpellEffectFn(spell_threatening_gaze_charge::PreventLaunchHit, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
|
||||
OnEffectHitTarget += SpellEffectFn(spell_threatening_gaze_charge::LaunchHit, EFFECT_1, SPELL_EFFECT_TRIGGER_SPELL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_mandokir()
|
||||
{
|
||||
new boss_mandokir();
|
||||
@@ -664,4 +785,5 @@ void AddSC_boss_mandokir()
|
||||
RegisterZulGurubCreatureAI(npc_vilebranch_speaker);
|
||||
new spell_threatening_gaze();
|
||||
RegisterSpellScript(spell_mandokir_charge);
|
||||
RegisterSpellScript(spell_threatening_gaze_charge);
|
||||
}
|
||||
|
||||
@@ -212,9 +212,15 @@ public:
|
||||
DoCast(target, SPELL_THOUSAND_BLADES, false);
|
||||
}
|
||||
|
||||
_thousandBladesTargets.erase(itr);
|
||||
|
||||
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 500ms);
|
||||
if (_thousandBladesTargets.erase(itr) != _thousandBladesTargets.end())
|
||||
{
|
||||
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 500ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
_thousandBladesCount = urand(2, 5);
|
||||
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 15s, 22s);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -15,12 +15,18 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AreaBoundary.h"
|
||||
#include "CreatureAIImpl.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "obsidian_sanctum.h"
|
||||
|
||||
BossBoundaryData const boundaries =
|
||||
{
|
||||
{ DATA_SARTHARION, new RectangleBoundary(3218.86f, 3275.69f, 484.68f, 572.4f) }
|
||||
};
|
||||
|
||||
class instance_obsidian_sanctum : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -36,6 +42,7 @@ public:
|
||||
instance_obsidian_sanctum_InstanceMapScript(Map* pMap) : InstanceScript(pMap), portalCount(0)
|
||||
{
|
||||
SetBossNumber(MAX_ENCOUNTERS);
|
||||
LoadBossBoundaries(boundaries);
|
||||
}
|
||||
|
||||
bool IsEncounterInProgress() const override
|
||||
|
||||
Reference in New Issue
Block a user