Merge branch 'master' into Playerbot
This commit is contained in:
@@ -2267,7 +2267,20 @@ Rate.Drop.Item.Artifact = 1
|
||||
Rate.Drop.Item.Referenced = 1
|
||||
Rate.Drop.Money = 1
|
||||
|
||||
# RewardBonusMoney
|
||||
# Rate.Drop.Item.ReferencedAmount
|
||||
# Description: Multiplier for referenced loot amount. Makes many raid bosses (and others) drop additional loot.
|
||||
# Default: 1
|
||||
|
||||
Rate.Drop.Item.ReferencedAmount = 1
|
||||
|
||||
#
|
||||
# Rate.Drop.Item.GroupAmount
|
||||
# Description: Multiplier for grouped items. Makes many dungeon bosses (and others) drop additional loot.
|
||||
# Default: 1
|
||||
|
||||
Rate.Drop.Item.GroupAmount = 1
|
||||
|
||||
# Rate.RewardBonusMoney
|
||||
# Description: Allows to further tweak the amount of extra money rewarded by quests when the player
|
||||
# is at MaxPlayerLevel (this amount is specified in quest_template.RewardBonusMoney).
|
||||
# NOTE: the final amount will also affected by Rate.Drop.Money
|
||||
@@ -2331,13 +2344,6 @@ Rate.BuyValue.Item.Legendary = 1
|
||||
Rate.BuyValue.Item.Artifact = 1
|
||||
Rate.BuyValue.Item.Heirloom = 1
|
||||
|
||||
#
|
||||
# Rate.Drop.Item.ReferencedAmount
|
||||
# Description: Multiplier for referenced loot amount.
|
||||
# Default: 1
|
||||
|
||||
Rate.Drop.Item.ReferencedAmount = 1
|
||||
|
||||
#
|
||||
# Rate.XP.Kill
|
||||
# Rate.XP.Quest
|
||||
|
||||
@@ -640,12 +640,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
|
||||
me->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlags);
|
||||
LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST: Unit {} casts spell {} on target {} with castflags {}",
|
||||
me->GetGUID().ToString().c_str(), e.action.cast.spell, target->GetGUID().ToString().c_str(), e.action.cast.castFlags);
|
||||
me->GetGUID().ToString(), e.action.cast.spell, target->GetGUID().ToString(), e.action.cast.castFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("scripts.ai", "Spell {} not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target {} already has the aura",
|
||||
e.action.cast.spell, target->GetGUID().ToString().c_str());
|
||||
e.action.cast.spell, target->GetGUID().ToString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -729,12 +729,12 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
|
||||
tempLastInvoker->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlags);
|
||||
LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_INVOKER_CAST: Invoker {} casts spell {} on target {} with castflags {}",
|
||||
tempLastInvoker->GetGUID().ToString().c_str(), e.action.cast.spell, target->GetGUID().ToString().c_str(), e.action.cast.castFlags);
|
||||
tempLastInvoker->GetGUID().ToString(), e.action.cast.spell, target->GetGUID().ToString(), e.action.cast.castFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("scripts.ai", "Spell {} not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target {} already has the aura",
|
||||
e.action.cast.spell, target->GetGUID().ToString().c_str());
|
||||
e.action.cast.spell, target->GetGUID().ToString());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -2797,6 +2797,18 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_DISABLE:
|
||||
{
|
||||
for (WorldObject* target : targets)
|
||||
{
|
||||
if (IsUnit(target))
|
||||
{
|
||||
target->ToUnit()->SetImmuneToAll(!e.action.disable.state);
|
||||
target->ToUnit()->SetVisible(e.action.disable.state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
break;
|
||||
|
||||
@@ -762,6 +762,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
|
||||
case SMART_ACTION_LOAD_GRID: return NO_PARAMS;
|
||||
case SMART_ACTION_MUSIC: return sizeof(SmartAction::music);
|
||||
case SMART_ACTION_SET_GUID: return sizeof(SmartAction::setGuid);
|
||||
case SMART_ACTION_DISABLE: return sizeof(SmartAction::disable);
|
||||
default:
|
||||
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
@@ -1918,6 +1919,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_ACTION_ATTACK_STOP:
|
||||
case SMART_ACTION_PLAY_CINEMATIC:
|
||||
case SMART_ACTION_SET_GUID:
|
||||
case SMART_ACTION_DISABLE:
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
|
||||
|
||||
@@ -693,8 +693,9 @@ enum SMART_ACTION
|
||||
SMART_ACTION_DO_ACTION = 223, // ActionId
|
||||
SMART_ACTION_ATTACK_STOP = 224, //
|
||||
SMART_ACTION_SET_GUID = 225, // Sends the invoker's or the base object's own ObjectGuid to target
|
||||
SMART_ACTION_DISABLE = 226, // Disable the targeted creatures, setting them Invisible and Immune to All
|
||||
|
||||
SMART_ACTION_AC_END = 226, // placeholder
|
||||
SMART_ACTION_AC_END = 227, // placeholder
|
||||
};
|
||||
|
||||
enum class SmartActionSummonCreatureFlags
|
||||
@@ -1365,6 +1366,11 @@ struct SmartAction
|
||||
SAIBool invokerGUID;
|
||||
uint32 index;
|
||||
} setGuid;
|
||||
|
||||
struct
|
||||
{
|
||||
SAIBool state;
|
||||
} disable;
|
||||
//! Note for any new future actions
|
||||
//! All parameters must have type uint32
|
||||
|
||||
|
||||
@@ -2683,7 +2683,7 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
|
||||
if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT)
|
||||
LOG_ERROR("sql.sql", "Table `achievement_criteria_data` has ScriptName set for non-scripted data type (Entry: {}, type {}), useless data.", criteria_id, dataType);
|
||||
else
|
||||
scriptId = sObjectMgr->GetScriptId(scriptName.c_str());
|
||||
scriptId = sObjectMgr->GetScriptId(scriptName);
|
||||
}
|
||||
|
||||
AchievementCriteriaData data(dataType, fields[2].Get<uint32>(), fields[3].Get<uint32>(), scriptId);
|
||||
|
||||
@@ -459,7 +459,7 @@ uint32 CalendarMgr::GetPlayerNumPending(ObjectGuid guid)
|
||||
std::string CalendarEvent::BuildCalendarMailSubject(ObjectGuid remover) const
|
||||
{
|
||||
std::ostringstream strm;
|
||||
strm << remover.ToString().c_str() << ':' << _title;
|
||||
strm << remover.ToString() << ':' << _title;
|
||||
return strm.str();
|
||||
}
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ void LoadM2Cameras(std::string const& dataPath)
|
||||
// Reject if not at least the size of the header
|
||||
if (static_cast<uint32>(fileSize) < sizeof(M2Header))
|
||||
{
|
||||
LOG_ERROR("server.loading", "Camera file {} is damaged. File is smaller than header size", filename.string().c_str());
|
||||
LOG_ERROR("server.loading", "Camera file {} is damaged. File is smaller than header size", filename.string());
|
||||
m2file.close();
|
||||
continue;
|
||||
}
|
||||
@@ -220,7 +220,7 @@ void LoadM2Cameras(std::string const& dataPath)
|
||||
// Check file has correct magic (MD20)
|
||||
if (strcmp(fileCheck, "MD20"))
|
||||
{
|
||||
LOG_ERROR("server.loading", "Camera file {} is damaged. File identifier not found", filename.string().c_str());
|
||||
LOG_ERROR("server.loading", "Camera file {} is damaged. File identifier not found", filename.string());
|
||||
m2file.close();
|
||||
continue;
|
||||
}
|
||||
@@ -240,14 +240,14 @@ void LoadM2Cameras(std::string const& dataPath)
|
||||
|
||||
if (header->ofsCameras + sizeof(M2Camera) > static_cast<uint32>(fileSize))
|
||||
{
|
||||
LOG_ERROR("server.loading", "Camera file {} is damaged. Camera references position beyond file end", filename.string().c_str());
|
||||
LOG_ERROR("server.loading", "Camera file {} is damaged. Camera references position beyond file end", filename.string());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get camera(s) - Main header, then dump them.
|
||||
M2Camera const* cam = reinterpret_cast<M2Camera const*>(buffer.data() + header->ofsCameras);
|
||||
if (!readCamera(cam, fileSize, header, dbcentry))
|
||||
LOG_ERROR("server.loading", "Camera file {} is damaged. Camera references position beyond file end", filename.string().c_str());
|
||||
LOG_ERROR("server.loading", "Camera file {} is damaged. Camera references position beyond file end", filename.string());
|
||||
}
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} Cinematic Waypoint Sets in {} ms", (uint32)sFlyByCameraStore.size(), GetMSTimeDiffToNow(oldMSTime));
|
||||
|
||||
@@ -484,7 +484,7 @@ namespace lfg
|
||||
[[nodiscard]] std::string toString() const // for debugging
|
||||
{
|
||||
std::ostringstream o;
|
||||
o << guids[0].ToString().c_str() << "," << guids[1].ToString().c_str() << "," << guids[2].ToString().c_str() << "," << guids[3].ToString().c_str() << "," << guids[4].ToString().c_str() << ":" << (roles ? 1 : 0);
|
||||
o << guids[0].ToString() << "," << guids[1].ToString() << "," << guids[2].ToString() << "," << guids[3].ToString() << "," << guids[4].ToString() << ":" << (roles ? 1 : 0);
|
||||
return o.str();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1124,11 +1124,11 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, GetCreateMana());
|
||||
|
||||
// xinef: added some multipliers so debuffs can affect pets in any way...
|
||||
SetCreateStat(STAT_STRENGTH, 22 + 2 * petlevel);
|
||||
SetCreateStat(STAT_AGILITY, 22 + 1.5f * petlevel);
|
||||
SetCreateStat(STAT_STAMINA, 25 + 2 * petlevel);
|
||||
SetCreateStat(STAT_INTELLECT, 28 + 2 * petlevel);
|
||||
SetCreateStat(STAT_SPIRIT, 27 + 1.5f * petlevel);
|
||||
SetCreateStat(STAT_STRENGTH, 22);
|
||||
SetCreateStat(STAT_AGILITY, 22);
|
||||
SetCreateStat(STAT_STAMINA, 25);
|
||||
SetCreateStat(STAT_INTELLECT, 28);
|
||||
SetCreateStat(STAT_SPIRIT, 27);
|
||||
}
|
||||
|
||||
switch (petType)
|
||||
@@ -1348,6 +1348,14 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
|
||||
break;
|
||||
}
|
||||
case NPC_VENOMOUS_SNAKE:
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel * 0.7 - 38));
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel * 0.8 - 40));
|
||||
break;
|
||||
case NPC_VIPER:
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(1.3 * petlevel - 64));
|
||||
SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(1.5 * petlevel - 68));
|
||||
break;
|
||||
case NPC_GENERIC_IMP:
|
||||
case NPC_GENERIC_VOIDWALKER:
|
||||
{
|
||||
|
||||
@@ -122,6 +122,10 @@ enum NPCEntries
|
||||
NPC_ARMY_OF_THE_DEAD = 24207,
|
||||
NPC_EBON_GARGOYLE = 27829,
|
||||
|
||||
// Hunter
|
||||
NPC_VENOMOUS_SNAKE = 19833,
|
||||
NPC_VIPER = 19921,
|
||||
|
||||
// Generic
|
||||
NPC_GENERIC_IMP = 12922,
|
||||
NPC_GENERIC_VOIDWALKER = 8996
|
||||
|
||||
@@ -166,6 +166,7 @@ void KillRewarder::_RewardXP(Player* player, float rate)
|
||||
AddPct(xp, (*i)->GetAmount());
|
||||
|
||||
// 4.2.3. Give XP to player.
|
||||
sScriptMgr->OnGivePlayerXP(player, xp, _victim, PlayerXPSource::XPSOURCE_KILL);
|
||||
player->GiveXP(xp, _victim, _groupRate);
|
||||
if (Pet* pet = player->GetPet())
|
||||
// 4.2.4. If player has pet, reward pet with XP (100% for single player, 50% for group case).
|
||||
|
||||
@@ -2372,8 +2372,6 @@ void Player::GiveXP(uint32 xp, Unit* victim, float group_rate, bool isLFGReward)
|
||||
|
||||
uint8 level = GetLevel();
|
||||
|
||||
sScriptMgr->OnGivePlayerXP(this, xp, victim);
|
||||
|
||||
// Favored experience increase START
|
||||
uint32 zone = GetZoneId();
|
||||
float favored_exp_mult = 0;
|
||||
@@ -5147,7 +5145,7 @@ float Player::OCTRegenHPPerSpirit()
|
||||
if (baseSpirit > 50)
|
||||
baseSpirit = 50;
|
||||
float moreSpirit = spirit - baseSpirit;
|
||||
float regen = baseSpirit * baseRatio->ratio + moreSpirit * moreRatio->ratio;
|
||||
float regen = (baseSpirit * baseRatio->ratio + moreSpirit * moreRatio->ratio) * 2;
|
||||
return regen;
|
||||
}
|
||||
|
||||
@@ -5732,6 +5730,7 @@ void Player::CheckAreaExploreAndOutdoor()
|
||||
XP = uint32(sObjectMgr->GetBaseXP(areaEntry->area_level) * sWorld->getRate(RATE_XP_EXPLORE));
|
||||
}
|
||||
|
||||
sScriptMgr->OnGivePlayerXP(this, XP, nullptr, PlayerXPSource::XPSOURCE_EXPLORE);
|
||||
GiveXP(XP, nullptr);
|
||||
SendExplorationExperience(areaId, XP);
|
||||
}
|
||||
@@ -6121,7 +6120,11 @@ bool Player::RewardHonor(Unit* uVictim, uint32 groupsize, int32 honor, bool awar
|
||||
bg->UpdatePlayerScore(this, SCORE_BONUS_HONOR, honor, false); //false: prevent looping
|
||||
// Xinef: Only for BG activities
|
||||
if (!uVictim)
|
||||
GiveXP(uint32(honor * (3 + GetLevel() * 0.30f)), nullptr);
|
||||
{
|
||||
uint32 xp = uint32(honor * (3 + GetLevel() * 0.30f));
|
||||
sScriptMgr->OnGivePlayerXP(this, xp, nullptr, PlayerXPSource::XPSOURCE_BATTLEGROUND);
|
||||
GiveXP(xp, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_PVP_TOKEN_ENABLE))
|
||||
@@ -7074,7 +7077,8 @@ void Player::ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply,
|
||||
|
||||
LOG_DEBUG("entities.player", "WORLD: cast {} Equip spellId - {}", (item ? "item" : "itemset"), spellInfo->Id);
|
||||
|
||||
CastSpell(this, spellInfo, true, item);
|
||||
//Ignore spellInfo->DurationEntry, cast with -1 duration
|
||||
CastCustomSpell(spellInfo->Id, SPELLVALUE_AURA_DURATION, -1, this, true, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -995,6 +995,16 @@ enum PlayerCommandStates
|
||||
CHEAT_WATERWALK = 0x10
|
||||
};
|
||||
|
||||
// Used for OnGiveXP PlayerScript hook
|
||||
enum PlayerXPSource
|
||||
{
|
||||
XPSOURCE_KILL = 0,
|
||||
XPSOURCE_QUEST = 1,
|
||||
XPSOURCE_QUEST_DF = 2,
|
||||
XPSOURCE_EXPLORE = 3,
|
||||
XPSOURCE_BATTLEGROUND = 4
|
||||
};
|
||||
|
||||
enum InstantFlightGossipAction
|
||||
{
|
||||
GOSSIP_ACTION_TOGGLE_INSTANT_FLIGHT = 500
|
||||
|
||||
@@ -756,6 +756,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
|
||||
}
|
||||
else
|
||||
{
|
||||
sScriptMgr->OnGivePlayerXP(this, XP, nullptr, isLFGReward ? PlayerXPSource::XPSOURCE_QUEST_DF : PlayerXPSource::XPSOURCE_QUEST);
|
||||
GiveXP(XP, nullptr, isLFGReward);
|
||||
}
|
||||
|
||||
|
||||
@@ -6978,7 +6978,7 @@ bool Player::CheckInstanceLoginValid()
|
||||
if (GetMap()->IsRaid())
|
||||
{
|
||||
// cannot be in raid instance without a group
|
||||
if (!GetGroup())
|
||||
if (!GetGroup() && !sWorld->getBoolConfig(CONFIG_INSTANCE_IGNORE_RAID))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -812,14 +812,8 @@ void Unit::DealDamageMods(Unit const* victim, uint32& damage, uint32* absorb)
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss, bool /*allowGM*/, Spell const* damageSpell /*= nullptr*/, bool delayed)
|
||||
uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss, bool /*allowGM*/, Spell const* damageSpell /*= nullptr*/)
|
||||
{
|
||||
if (delayed && attacker->GetTypeId() == TYPEID_PLAYER && attacker->GetGUID() != victim->GetGUID())
|
||||
{
|
||||
sWorld->AddDelayedDamage(attacker, victim, damage, cleanDamage, damagetype, damageSchoolMask, spellProto, durabilityLoss);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Xinef: initialize damage done for rage calculations
|
||||
// Xinef: its rare to modify damage in hooks, however training dummy's sets damage to 0
|
||||
uint32 rage_damage = damage + ((cleanDamage != nullptr) ? cleanDamage->absorbed_damage : 0);
|
||||
@@ -1460,7 +1454,7 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage* damageInfo, bool durabilityLoss,
|
||||
|
||||
// Call default DealDamage
|
||||
CleanDamage cleanDamage(damageInfo->cleanDamage, damageInfo->absorb, BASE_ATTACK, MELEE_HIT_NORMAL);
|
||||
Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss, false, spell, true);
|
||||
Unit::DealDamage(this, victim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss, false, spell);
|
||||
}
|
||||
|
||||
// @todo for melee need create structure as in
|
||||
@@ -10392,7 +10386,7 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
|
||||
creature->SendAIReaction(AI_REACTION_HOSTILE);
|
||||
|
||||
/// @todo: Implement aggro range, detection range and assistance range templates
|
||||
if (!(creature->ToCreature()->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE))
|
||||
if (!(creature->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE))
|
||||
{
|
||||
creature->CallAssistance();
|
||||
}
|
||||
@@ -20081,6 +20075,9 @@ void Unit::_ExitVehicle(Position const* exitPosition)
|
||||
Unit* vehicleBase = m_vehicle->GetBase();
|
||||
m_vehicle = nullptr;
|
||||
|
||||
if (!vehicleBase)
|
||||
return;
|
||||
|
||||
SetControlled(false, UNIT_STATE_ROOT); // SMSG_MOVE_FORCE_UNROOT, ~MOVEMENTFLAG_ROOT
|
||||
|
||||
Position pos;
|
||||
|
||||
@@ -757,18 +757,6 @@ struct CleanDamage
|
||||
struct CalcDamageInfo;
|
||||
struct SpellNonMeleeDamage;
|
||||
|
||||
struct DelayedDamage
|
||||
{
|
||||
Unit* attacker;
|
||||
Unit* victim;
|
||||
uint32 damage;
|
||||
CleanDamage const* cleanDamage;
|
||||
DamageEffectType damagetype;
|
||||
SpellSchoolMask damageSchoolMask;
|
||||
SpellInfo const* spellProto;
|
||||
bool durabilityLoss;
|
||||
};
|
||||
|
||||
class DamageInfo
|
||||
{
|
||||
private:
|
||||
@@ -1571,7 +1559,7 @@ public:
|
||||
|
||||
uint16 GetMaxSkillValueForLevel(Unit const* target = nullptr) const { return (target ? getLevelForTarget(target) : GetLevel()) * 5; }
|
||||
static void DealDamageMods(Unit const* victim, uint32& damage, uint32* absorb);
|
||||
static uint32 DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage = nullptr, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = nullptr, bool durabilityLoss = true, bool allowGM = false, Spell const* spell = nullptr, bool delayed = false);
|
||||
static uint32 DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage = nullptr, DamageEffectType damagetype = DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* spellProto = nullptr, bool durabilityLoss = true, bool allowGM = false, Spell const* spell = nullptr);
|
||||
static void Kill(Unit* killer, Unit* victim, bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr, Spell const* spell = nullptr);
|
||||
void KillSelf(bool durabilityLoss = true, WeaponAttackType attackType = BASE_ATTACK, SpellInfo const* spellProto = nullptr, Spell const* spell = nullptr) { Kill(this, this, durabilityLoss, attackType, spellProto, spell); };
|
||||
static int32 DealHeal(Unit* healer, Unit* victim, uint32 addhealth);
|
||||
|
||||
@@ -2885,7 +2885,7 @@ void ObjectMgr::LoadItemTemplates()
|
||||
}
|
||||
if (itemTemplate.Material != dbcitem->Material)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {%u}}) does not have a correct material ({}), must be {}.", entry, itemTemplate.Material, dbcitem->Material);
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct material ({}), must be {}.", entry, itemTemplate.Material, dbcitem->Material);
|
||||
if (enforceDBCAttributes)
|
||||
itemTemplate.Material = dbcitem->Material;
|
||||
}
|
||||
@@ -2897,7 +2897,7 @@ void ObjectMgr::LoadItemTemplates()
|
||||
}
|
||||
if (itemTemplate.DisplayInfoID != dbcitem->DisplayInfoID)
|
||||
{
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {%u}}) does not have a correct display id ({}), must be {}.", entry, itemTemplate.DisplayInfoID, dbcitem->DisplayInfoID);
|
||||
LOG_ERROR("sql.sql", "Item (Entry: {}) does not have a correct display id ({}), must be {}.", entry, itemTemplate.DisplayInfoID, dbcitem->DisplayInfoID);
|
||||
if (enforceDBCAttributes)
|
||||
itemTemplate.DisplayInfoID = dbcitem->DisplayInfoID;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ void WorldSession::HandleLfgJoinOpcode(WorldPackets::LFG::LFGJoin& packet)
|
||||
|
||||
if (packet.Slots.empty())
|
||||
{
|
||||
LOG_DEBUG("lfg", "CMSG_LFG_JOIN {} no dungeons selected", GetPlayerInfo().c_str());
|
||||
LOG_DEBUG("lfg", "CMSG_LFG_JOIN {} no dungeons selected", GetPlayerInfo());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -953,21 +953,21 @@ void WorldSession::HandlePetSpellAutocastOpcode(WorldPackets::Pet::PetSpellAutoc
|
||||
Creature* checkPet = ObjectAccessor::GetCreatureOrPetOrVehicle(*_player, packet.PetGUID);
|
||||
if (!checkPet)
|
||||
{
|
||||
LOG_ERROR("entities.pet", "WorldSession::HandlePetSpellAutocastOpcode: Pet {} not found.", packet.PetGUID.ToString().c_str());
|
||||
LOG_ERROR("entities.pet", "WorldSession::HandlePetSpellAutocastOpcode: Pet {} not found.", packet.PetGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(packet.SpellID);
|
||||
if (!spellInfo)
|
||||
{
|
||||
LOG_ERROR("spells.pet", "WorldSession::HandlePetSpellAutocastOpcode: Unknown spell id {} used by {}.", packet.SpellID, packet.PetGUID.ToString().c_str());
|
||||
LOG_ERROR("spells.pet", "WorldSession::HandlePetSpellAutocastOpcode: Unknown spell id {} used by {}.", packet.SpellID, packet.PetGUID.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkPet != _player->GetGuardianPet() && checkPet != _player->GetCharm())
|
||||
{
|
||||
LOG_ERROR("entities.pet", "WorldSession::HandlePetSpellAutocastOpcode: {} isn't pet of player {} ({}).",
|
||||
packet.PetGUID.ToString().c_str(), GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str());
|
||||
packet.PetGUID.ToString(), GetPlayer()->GetName(), GetPlayer()->GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
bool HasQuestDrop(LootTemplateMap const& store) const; // True if group includes at least 1 quest drop entry
|
||||
bool HasQuestDropForPlayer(Player const* player, LootTemplateMap const& store) const;
|
||||
// The same for active quests of the player
|
||||
void Process(Loot& loot, Player const* player, LootStore const& lootstore, uint16 lootMode) const; // Rolls an item from the group (if any) and adds the item to the loot
|
||||
void Process(Loot& loot, Player const* player, LootStore const& lootstore, uint16 lootMode, uint16 nonRefIterationsLeft) const; // Rolls an item from the group (if any) and adds the item to the loot
|
||||
float RawTotalChance() const; // Overall chance for the group (without equal chanced items)
|
||||
float TotalChance() const; // Overall chance for the group
|
||||
|
||||
@@ -570,7 +570,8 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo
|
||||
items.reserve(MAX_NR_LOOT_ITEMS);
|
||||
quest_items.reserve(MAX_NR_QUEST_ITEMS);
|
||||
|
||||
tab->Process(*this, store, lootMode, lootOwner); // Processing is done there, callback via Loot::AddItem()
|
||||
// Initial group is 0, top level set to True
|
||||
tab->Process(*this, store, lootMode, lootOwner, 0, true); // Processing is done there, callback via Loot::AddItem()
|
||||
|
||||
sScriptMgr->OnAfterLootTemplateProcess(this, tab, store, lootOwner, personal, noEmptyError, lootMode);
|
||||
|
||||
@@ -1413,7 +1414,7 @@ void LootTemplate::LootGroup::CopyConditions(ConditionList /*conditions*/)
|
||||
}
|
||||
|
||||
// Rolls an item from the group (if any takes its chance) and adds the item to the loot
|
||||
void LootTemplate::LootGroup::Process(Loot& loot, Player const* player, LootStore const& store, uint16 lootMode) const
|
||||
void LootTemplate::LootGroup::Process(Loot& loot, Player const* player, LootStore const& store, uint16 lootMode, uint16 nonRefIterationsLeft) const
|
||||
{
|
||||
if (LootStoreItem const* item = Roll(loot, player, store, lootMode))
|
||||
{
|
||||
@@ -1426,7 +1427,9 @@ void LootTemplate::LootGroup::Process(Loot& loot, Player const* player, LootStor
|
||||
uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT));
|
||||
sScriptMgr->OnAfterRefCount(player, loot, rate, lootMode, const_cast<LootStoreItem*>(item), maxcount, store);
|
||||
for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator
|
||||
Referenced->Process(loot, store, lootMode, player, item->groupid);
|
||||
// This reference needs to be processed further, but it is marked isTopLevel=false so that any groups inside
|
||||
// the reference are not multiplied by Rate.Drop.Item.GroupAmount
|
||||
Referenced->Process(loot, store, lootMode, player, item->groupid, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1434,6 +1437,14 @@ void LootTemplate::LootGroup::Process(Loot& loot, Player const* player, LootStor
|
||||
// Plain entries (not a reference, not grouped)
|
||||
sScriptMgr->OnBeforeDropAddItem(player, loot, rate, lootMode, const_cast<LootStoreItem*>(item), store);
|
||||
loot.AddItem(*item); // Chance is already checked, just add
|
||||
|
||||
// If we still have non-ref runs to do for this group AND this item wasn't a reference,
|
||||
// recursively call this function to produce more items for this group.
|
||||
// However, if this is a quest item we shouldn't multiply this group.
|
||||
if (nonRefIterationsLeft > 1 && !item->needs_quest)
|
||||
{
|
||||
this->Process(loot, player, store, lootMode, nonRefIterationsLeft-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1665,7 +1676,7 @@ bool LootTemplate::CopyConditions(LootItem* li, uint32 conditionLootId) const
|
||||
}
|
||||
|
||||
// Rolls for every item in the template and adds the rolled items the the loot
|
||||
void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId) const
|
||||
void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId, bool isTopLevel) const
|
||||
{
|
||||
bool rate = store.IsRatesAllowed();
|
||||
|
||||
@@ -1677,7 +1688,15 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode,
|
||||
if (!Groups[groupId - 1])
|
||||
return;
|
||||
|
||||
Groups[groupId - 1]->Process(loot, player, store, lootMode);
|
||||
// Rate.Drop.Item.GroupAmount is only in effect for the top loot template level
|
||||
if (isTopLevel)
|
||||
{
|
||||
Groups[groupId - 1]->Process(loot, player, store, lootMode, sWorld->getRate(RATE_DROP_ITEM_GROUP_AMOUNT));
|
||||
}
|
||||
else
|
||||
{
|
||||
Groups[groupId - 1]->Process(loot, player, store, lootMode, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1687,7 +1706,6 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode,
|
||||
LootStoreItem* item = *i;
|
||||
if (!(item->lootmode & lootMode)) // Do not add if mode mismatch
|
||||
continue;
|
||||
|
||||
if (!item->Roll(rate, player, loot, store))
|
||||
continue; // Bad luck for the entry
|
||||
|
||||
@@ -1700,7 +1718,8 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode,
|
||||
uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT));
|
||||
sScriptMgr->OnAfterRefCount(player, loot, rate, lootMode, item, maxcount, store);
|
||||
for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator
|
||||
Referenced->Process(loot, store, lootMode, player, item->groupid);
|
||||
// we're no longer in the top level, so isTopLevel is false
|
||||
Referenced->Process(loot, store, lootMode, player, item->groupid, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1713,7 +1732,17 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode,
|
||||
// Now processing groups
|
||||
for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i)
|
||||
if (LootGroup* group = *i)
|
||||
group->Process(loot, player, store, lootMode);
|
||||
{
|
||||
// Rate.Drop.Item.GroupAmount is only in effect for the top loot template level
|
||||
if (isTopLevel)
|
||||
{
|
||||
group->Process(loot, player, store, lootMode, sWorld->getRate(RATE_DROP_ITEM_GROUP_AMOUNT));
|
||||
}
|
||||
else
|
||||
{
|
||||
group->Process(loot, player, store, lootMode, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// True if template includes at least 1 quest drop entry
|
||||
|
||||
@@ -253,7 +253,7 @@ public:
|
||||
// Adds an entry to the group (at loading stage)
|
||||
void AddEntry(LootStoreItem* item);
|
||||
// Rolls for every item in the template and adds the rolled items the the loot
|
||||
void Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId = 0) const;
|
||||
void Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId = 0, bool isTopLevel = true) const;
|
||||
void CopyConditions(ConditionList conditions);
|
||||
bool CopyConditions(LootItem* li, uint32 conditionLootId = 0) const;
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ class Item;
|
||||
class Object;
|
||||
class Player;
|
||||
|
||||
#define MAIL_BODY_ITEM_TEMPLATE 8383 // - plain letter, A Dusty Unsent Letter: 889
|
||||
#define MAIL_BODY_ITEM_TEMPLATE 9311 // - plain letter, A Dusty Unsent Letter: 889
|
||||
#define MAX_MAIL_ITEMS 12
|
||||
|
||||
enum MailMessageType
|
||||
|
||||
@@ -375,7 +375,7 @@ void FlightPathMovementGenerator::DoReset(Player* player)
|
||||
|
||||
if (currentNodeId == end)
|
||||
{
|
||||
LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::DoReset: trying to start a flypath from the end point. {}", player->GetGUID().ToString().c_str());
|
||||
LOG_DEBUG("movement.flightpath", "FlightPathMovementGenerator::DoReset: trying to start a flypath from the end point. {}", player->GetGUID().ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -406,7 +406,7 @@ bool FlightPathMovementGenerator::DoUpdate(Player* player, uint32 /*diff*/)
|
||||
bool departureEvent = true;
|
||||
do
|
||||
{
|
||||
ASSERT(i_currentNode < i_path.size(), "Point Id: {}\n{}", pointId, player->GetGUID().ToString().c_str());
|
||||
ASSERT(i_currentNode < i_path.size(), "Point Id: {}\n{}", pointId, player->GetGUID().ToString());
|
||||
|
||||
DoEventIfAny(player, i_path[i_currentNode], departureEvent);
|
||||
while (!_pointsForPathSwitch.empty() && _pointsForPathSwitch.front().PathIndex <= i_currentNode)
|
||||
@@ -460,7 +460,7 @@ void FlightPathMovementGenerator::DoEventIfAny(Player* player, TaxiPathNodeEntry
|
||||
{
|
||||
if (uint32 eventid = departure ? node->departureEventID : node->arrivalEventID)
|
||||
{
|
||||
LOG_DEBUG("maps.script", "Taxi {} event {} of node {} of path {} for player {}", departure ? "departure" : "arrival", eventid, node->index, node->path, player->GetName().c_str());
|
||||
LOG_DEBUG("maps.script", "Taxi {} event {} of node {} of path {} for player {}", departure ? "departure" : "arrival", eventid, node->index, node->path, player->GetName());
|
||||
player->GetMap()->ScriptsStart(sEventScripts, eventid, player, player);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,9 +113,9 @@ inline Player* Map::_GetScriptPlayerSourceOrTarget(Object* source, Object* targe
|
||||
|
||||
if (!player)
|
||||
LOG_ERROR("maps.script", "{} neither source nor target object is player (source: TypeId: {}, Entry: {}, GUID: {}; target: TypeId: {}, Entry: {}, GUID: {}), skipping.",
|
||||
scriptInfo->GetDebugInfo().c_str(),
|
||||
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUID().ToString().c_str() : "",
|
||||
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUID().ToString().c_str() : "");
|
||||
scriptInfo->GetDebugInfo(),
|
||||
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUID().ToString() : "",
|
||||
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUID().ToString() : "");
|
||||
}
|
||||
return player;
|
||||
}
|
||||
@@ -146,9 +146,9 @@ inline Creature* Map::_GetScriptCreatureSourceOrTarget(Object* source, Object* t
|
||||
|
||||
if (!creature)
|
||||
LOG_ERROR("maps.script", "{} neither source nor target are creatures (source: TypeId: {}, Entry: {}, GUID: {}; target: TypeId: {}, Entry: {}, GUID: {}), skipping.",
|
||||
scriptInfo->GetDebugInfo().c_str(),
|
||||
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUID().ToString().c_str() : "",
|
||||
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUID().ToString().c_str() : "");
|
||||
scriptInfo->GetDebugInfo(),
|
||||
source ? source->GetTypeId() : 0, source ? source->GetEntry() : 0, source ? source->GetGUID().ToString() : "",
|
||||
target ? target->GetTypeId() : 0, target ? target->GetEntry() : 0, target ? target->GetGUID().ToString() : "");
|
||||
}
|
||||
return creature;
|
||||
}
|
||||
@@ -533,7 +533,7 @@ void Map::ScriptsProcess()
|
||||
else
|
||||
{
|
||||
LOG_ERROR("maps.script", "{} neither source nor target is player (source: {}; target: {}), skipping.",
|
||||
step.script->GetDebugInfo().c_str(), source->GetGUID().ToString().c_str(), target->GetGUID().ToString().c_str());
|
||||
step.script->GetDebugInfo(), source->GetGUID().ToString(), target->GetGUID().ToString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,11 +154,11 @@ void ScriptMgr::OnBeforeLootMoney(Player* player, Loot* loot)
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptMgr::OnGivePlayerXP(Player* player, uint32& amount, Unit* victim)
|
||||
void ScriptMgr::OnGivePlayerXP(Player* player, uint32& amount, Unit* victim, uint8 xpSource)
|
||||
{
|
||||
ExecuteScript<PlayerScript>([&](PlayerScript* script)
|
||||
{
|
||||
script->OnGiveXP(player, amount, victim);
|
||||
script->OnGiveXP(player, amount, victim, xpSource);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ void ScriptMgr::CheckIfScriptsInDatabaseExist()
|
||||
{
|
||||
for (auto const& scriptName : sObjectMgr->GetScriptNames())
|
||||
{
|
||||
if (uint32 sid = sObjectMgr->GetScriptId(scriptName.c_str()))
|
||||
if (uint32 sid = sObjectMgr->GetScriptId(scriptName))
|
||||
{
|
||||
if (!ScriptRegistry<SpellScriptLoader>::GetScriptById(sid) &&
|
||||
!ScriptRegistry<ServerScript>::GetScriptById(sid) &&
|
||||
|
||||
@@ -1037,7 +1037,7 @@ public:
|
||||
virtual void OnBeforeLootMoney(Player* /*player*/, Loot* /*loot*/) {}
|
||||
|
||||
// Called when a player gains XP (before anything is given)
|
||||
virtual void OnGiveXP(Player* /*player*/, uint32& /*amount*/, Unit* /*victim*/) { }
|
||||
virtual void OnGiveXP(Player* /*player*/, uint32& /*amount*/, Unit* /*victim*/, uint8 /*xpSource*/) { }
|
||||
|
||||
// Called when a player's reputation changes (before it is actually changed)
|
||||
virtual bool OnReputationChange(Player* /*player*/, uint32 /*factionID*/, int32& /*standing*/, bool /*incremental*/) { return true; }
|
||||
@@ -2281,7 +2281,7 @@ public: /* PlayerScript */
|
||||
void OnPlayerTalentsReset(Player* player, bool noCost);
|
||||
void OnPlayerMoneyChanged(Player* player, int32& amount);
|
||||
void OnBeforeLootMoney(Player* player, Loot* loot);
|
||||
void OnGivePlayerXP(Player* player, uint32& amount, Unit* victim);
|
||||
void OnGivePlayerXP(Player* player, uint32& amount, Unit* victim, uint8 xpSource);
|
||||
bool OnPlayerReputationChange(Player* player, uint32 factionID, int32& standing, bool incremental);
|
||||
void OnPlayerReputationRankChange(Player* player, uint32 factionID, ReputationRank newRank, ReputationRank oldRank, bool increased);
|
||||
void OnPlayerLearnSpell(Player* player, uint32 spellID);
|
||||
|
||||
@@ -6387,7 +6387,7 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const
|
||||
SpellPeriodicAuraLogInfo pInfo(this, damage, overkill, absorb, resist, 0.0f, crit);
|
||||
target->SendPeriodicAuraLog(&pInfo);
|
||||
|
||||
Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true, false);
|
||||
Unit::DealDamage(caster, target, damage, &cleanDamage, DOT, GetSpellInfo()->GetSchoolMask(), GetSpellInfo(), true);
|
||||
|
||||
Unit::ProcDamageAndSpell(caster, target, caster ? procAttacker : 0, procVictim, procEx, damage, BASE_ATTACK, GetSpellInfo(), nullptr, GetEffIndex(), nullptr, &dmgInfo);
|
||||
}
|
||||
|
||||
@@ -3430,19 +3430,13 @@ void Spell::EffectWeaponDmg(SpellEffIndex effIndex)
|
||||
}
|
||||
case SPELLFAMILY_PALADIN:
|
||||
{
|
||||
// Seal of Command Unleashed
|
||||
if (m_spellInfo->Id == 20467)
|
||||
{
|
||||
spell_bonus += int32(0.08f * m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
|
||||
spell_bonus += int32(0.13f * m_caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()));
|
||||
}
|
||||
|
||||
switch (m_spellInfo->Id)
|
||||
{
|
||||
case 20424: // Seal of Command
|
||||
case 42463: // Seal of Vengeance
|
||||
case 53739: // Seal of Corruption
|
||||
case 53385: // Divine Storm
|
||||
case 20467: // Seal of Command Unleashed
|
||||
spell_bonus += int32(0.08f * m_caster->GetTotalAttackPowerValue(BASE_ATTACK));
|
||||
spell_bonus += int32(0.13f * m_caster->SpellBaseDamageBonusDone(m_spellInfo->GetSchoolMask()));
|
||||
break;
|
||||
case 53385: // Divine Storm deals normalized damage
|
||||
normalized = true;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -2104,6 +2104,7 @@ AuraStateType SpellInfo::LoadAuraState() const
|
||||
case 35331: // Black Blood
|
||||
case 9806: // Phantom Strike
|
||||
case 35325: // Glowing Blood
|
||||
case 35328: // Lambent Blood
|
||||
case 16498: // Faerie Fire
|
||||
case 6950:
|
||||
case 20656:
|
||||
|
||||
@@ -213,6 +213,15 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->MaxAffectedTargets = 4;
|
||||
});
|
||||
|
||||
ApplySpellFix({
|
||||
20424, // Seal of Command
|
||||
42463, // Seal of Vengeance
|
||||
53739 // Seal of Corruption
|
||||
}, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_IGNORE_CASTER_MODIFIERS;
|
||||
});
|
||||
|
||||
// Spitfire Totem
|
||||
ApplySpellFix({ 38296 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
@@ -4500,6 +4509,31 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->AttributesEx3 |= SPELL_ATTR3_DOT_STACKING_RULE;
|
||||
});
|
||||
|
||||
// Absorb Life
|
||||
ApplySpellFix({ 34239 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].ValueMultiplier = 1;
|
||||
});
|
||||
|
||||
// Summon a Warp Rift in Void Ridge
|
||||
ApplySpellFix({ 35036 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->CastTimeEntry = sSpellCastTimesStore.LookupEntry(1); // 0s
|
||||
});
|
||||
|
||||
// Hit Rating (Dungeon T3 - 2P Bonus - Wastewalker, Doomplate)
|
||||
ApplySpellFix({ 37608, 37610 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(0);
|
||||
spellInfo->Effects[EFFECT_0].MiscValue = 224;
|
||||
});
|
||||
|
||||
// Target Fissures
|
||||
ApplySpellFix({ 30745 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->MaxAffectedTargets = 1;
|
||||
});
|
||||
|
||||
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
|
||||
{
|
||||
SpellInfo* spellInfo = mSpellInfoMap[i];
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "IWorld.h"
|
||||
|
||||
class Unit;
|
||||
class IWorld;
|
||||
|
||||
void IWorld::AddDelayedDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
|
||||
{
|
||||
DelayedDamage delayedDamage;
|
||||
delayedDamage.attacker = attacker;
|
||||
delayedDamage.victim = victim;
|
||||
delayedDamage.damage = damage;
|
||||
delayedDamage.cleanDamage = cleanDamage;
|
||||
delayedDamage.damagetype = damagetype;
|
||||
delayedDamage.damageSchoolMask = damageSchoolMask;
|
||||
delayedDamage.spellProto = spellProto;
|
||||
delayedDamage.durabilityLoss = durabilityLoss;
|
||||
_delayedDamages.push_back(delayedDamage);
|
||||
}
|
||||
@@ -24,17 +24,15 @@
|
||||
#include "ObjectGuid.h"
|
||||
#include "QueryResult.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Unit.h"
|
||||
#include <atomic>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
|
||||
class IWorld;
|
||||
class Player;
|
||||
class WorldPacket;
|
||||
class WorldSession;
|
||||
class Player;
|
||||
|
||||
/// Storage class for commands issued for delayed execution
|
||||
struct AC_GAME_API CliCommandHolder
|
||||
@@ -438,8 +436,8 @@ enum Rates
|
||||
RATE_DROP_ITEM_LEGENDARY,
|
||||
RATE_DROP_ITEM_ARTIFACT,
|
||||
RATE_DROP_ITEM_REFERENCED,
|
||||
|
||||
RATE_DROP_ITEM_REFERENCED_AMOUNT,
|
||||
RATE_DROP_ITEM_GROUP_AMOUNT,
|
||||
RATE_SELLVALUE_ITEM_POOR,
|
||||
RATE_SELLVALUE_ITEM_NORMAL,
|
||||
RATE_SELLVALUE_ITEM_UNCOMMON,
|
||||
@@ -518,13 +516,10 @@ enum Rates
|
||||
class IWorld
|
||||
{
|
||||
public:
|
||||
std::list<DelayedDamage> _delayedDamages;
|
||||
|
||||
virtual ~IWorld() = default;
|
||||
[[nodiscard]] virtual WorldSession* FindSession(uint32 id) const = 0;
|
||||
[[nodiscard]] virtual WorldSession* FindOfflineSession(uint32 id) const = 0;
|
||||
[[nodiscard]] virtual WorldSession* FindOfflineSessionForCharacterGUID(ObjectGuid::LowType guidLow) const = 0;
|
||||
virtual void AddDelayedDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss);
|
||||
virtual void AddSession(WorldSession* s) = 0;
|
||||
virtual bool KickSession(uint32 id) = 0;
|
||||
virtual void UpdateMaxSessionCounters() = 0;
|
||||
|
||||
@@ -493,7 +493,9 @@ void World::LoadConfigSettings(bool reload)
|
||||
_rate_values[RATE_DROP_ITEM_ARTIFACT] = sConfigMgr->GetOption<float>("Rate.Drop.Item.Artifact", 1.0f);
|
||||
_rate_values[RATE_DROP_ITEM_REFERENCED] = sConfigMgr->GetOption<float>("Rate.Drop.Item.Referenced", 1.0f);
|
||||
_rate_values[RATE_DROP_ITEM_REFERENCED_AMOUNT] = sConfigMgr->GetOption<float>("Rate.Drop.Item.ReferencedAmount", 1.0f);
|
||||
_rate_values[RATE_DROP_ITEM_GROUP_AMOUNT] = sConfigMgr->GetOption<float>("Rate.Drop.Item.GroupAmount", 1.0f);
|
||||
_rate_values[RATE_DROP_MONEY] = sConfigMgr->GetOption<float>("Rate.Drop.Money", 1.0f);
|
||||
|
||||
_rate_values[RATE_REWARD_BONUS_MONEY] = sConfigMgr->GetOption<float>("Rate.RewardBonusMoney", 1.0f);
|
||||
_rate_values[RATE_XP_KILL] = sConfigMgr->GetOption<float>("Rate.XP.Kill", 1.0f);
|
||||
_rate_values[RATE_XP_BG_KILL_AV] = sConfigMgr->GetOption<float>("Rate.XP.BattlegroundKillAV", 1.0f);
|
||||
@@ -2065,8 +2067,6 @@ void World::SetInitialWorldSettings()
|
||||
|
||||
_mail_expire_check_timer = GameTime::GetGameTime() + 6h;
|
||||
|
||||
_timers[WUPDATE_DELAYED_DAMAGES].SetInterval(400);
|
||||
|
||||
///- Initialize MapMgr
|
||||
LOG_INFO("server.loading", "Starting Map System");
|
||||
LOG_INFO("server.loading", " ");
|
||||
@@ -2313,12 +2313,6 @@ void World::Update(uint32 diff)
|
||||
{
|
||||
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Check quest reset times"));
|
||||
|
||||
if (_timers[WUPDATE_DELAYED_DAMAGES].Passed())
|
||||
{
|
||||
_timers[WUPDATE_DELAYED_DAMAGES].Reset();
|
||||
ProcessDelayedDamages();
|
||||
}
|
||||
|
||||
/// Handle daily quests reset time
|
||||
if (currentGameTime > _nextDailyQuestReset)
|
||||
{
|
||||
@@ -3351,24 +3345,3 @@ CliCommandHolder::~CliCommandHolder()
|
||||
{
|
||||
free(m_command);
|
||||
}
|
||||
|
||||
void World::AddDelayedDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss)
|
||||
{
|
||||
DelayedDamage delayedDamage;
|
||||
delayedDamage.attacker = attacker;
|
||||
delayedDamage.victim = victim;
|
||||
delayedDamage.damage = damage;
|
||||
delayedDamage.cleanDamage = cleanDamage;
|
||||
delayedDamage.damagetype = damagetype;
|
||||
delayedDamage.damageSchoolMask = damageSchoolMask;
|
||||
delayedDamage.spellProto = spellProto;
|
||||
delayedDamage.durabilityLoss = durabilityLoss;
|
||||
_delayedDamages.push_back(delayedDamage);
|
||||
}
|
||||
|
||||
void World::ProcessDelayedDamages()
|
||||
{
|
||||
for (auto& damage : _delayedDamages)
|
||||
Unit::DealDamage(damage.attacker, damage.victim, damage.damage, damage.cleanDamage, damage.damagetype, damage.damageSchoolMask, damage.spellProto, damage.durabilityLoss);
|
||||
_delayedDamages.clear();
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include "QueryResult.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Timer.h"
|
||||
#include "Unit.h"
|
||||
#include <atomic>
|
||||
#include <list>
|
||||
#include <map>
|
||||
@@ -71,7 +70,6 @@ enum WorldTimers
|
||||
WUPDATE_PINGDB,
|
||||
WUPDATE_5_SECS,
|
||||
WUPDATE_WHO_LIST,
|
||||
WUPDATE_DELAYED_DAMAGES,
|
||||
WUPDATE_COUNT
|
||||
};
|
||||
|
||||
@@ -155,8 +153,6 @@ public:
|
||||
World();
|
||||
~World() override;
|
||||
|
||||
std::list<DelayedDamage> _delayedDamages;
|
||||
|
||||
static World* instance();
|
||||
|
||||
static uint32 m_worldLoopCounter;
|
||||
@@ -357,10 +353,6 @@ public:
|
||||
|
||||
void RemoveOldCorpses() override;
|
||||
|
||||
void AddDelayedDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellInfo const* spellProto, bool durabilityLoss) override;
|
||||
|
||||
void ProcessDelayedDamages();
|
||||
|
||||
protected:
|
||||
void _UpdateGameTime();
|
||||
// callback for UpdateRealmCharacters
|
||||
|
||||
@@ -50,8 +50,9 @@ public:
|
||||
break;
|
||||
case GO_FACTORY_DOOR:
|
||||
gameobject->UpdateSaveToDb(true);
|
||||
// GoState (Door opened) is restored during GO creation, but we need to set LootState to prevent Lever from closing it again
|
||||
if (_encounters[TYPE_RHAHK_ZOR] == DONE)
|
||||
gameobject->SetGoState(GO_STATE_ACTIVE);
|
||||
gameobject->SetLootState(GO_ACTIVATED);
|
||||
break;
|
||||
case GO_IRON_CLAD_DOOR:
|
||||
gameobject->UpdateSaveToDb(true);
|
||||
|
||||
@@ -301,7 +301,7 @@ public:
|
||||
|
||||
void JustEngagedWith(Unit*)
|
||||
{
|
||||
events.ScheduleEvent(EVENT_POISON, 8ms);
|
||||
events.ScheduleEvent(EVENT_POISON, 8s);
|
||||
|
||||
if (Creature* Venoxis = GetVenoxis())
|
||||
{
|
||||
@@ -331,7 +331,7 @@ public:
|
||||
case EVENT_POISON:
|
||||
{
|
||||
me->CastSpell(me->GetVictim(), SPELL_POISON);
|
||||
events.ScheduleEvent(EVENT_POISON, 15ms);
|
||||
events.ScheduleEvent(EVENT_POISON, 15s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+637
-366
File diff suppressed because it is too large
Load Diff
@@ -50,6 +50,7 @@ enum Data
|
||||
ACTION_STOP_LK_FIGHT,
|
||||
ACTION_DELETE_ICE_WALL,
|
||||
DATA_WAVE_NUMBER,
|
||||
DATA_LK_BATTLE,// in progress
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
@@ -84,6 +85,7 @@ enum Creatures
|
||||
NPC_SKY_REAVER_KORM_BLACKSKAR = 30824,
|
||||
NPC_ALTAR_BUNNY = 37704,
|
||||
NPC_QUEL_DELAR = 37158,
|
||||
|
||||
};
|
||||
|
||||
enum GameObjects
|
||||
@@ -263,8 +265,14 @@ enum hMisc
|
||||
SPELL_HOR_START_QUEST_ALLY = 71351,
|
||||
SPELL_HOR_START_QUEST_HORDE = 71542,
|
||||
SPELL_SHADOWMOURNE_VISUAL = 72523,
|
||||
SPELL_ARCANE_CAST_VISUAL = 65633,
|
||||
SPELL_UTHER_DESPAWN = 70693, //Sniffed
|
||||
SPELL_WELL_OF_SOULS_VISUAL = 72630,
|
||||
SPELL_SUMMON_SOULS = 72711, //Sniffed Sylvanas
|
||||
|
||||
//Battle of LK
|
||||
SPELL_BLIDING_RETREAT = 70199, //Sniffed LK
|
||||
SPELL_SOUL_REAPER = 69410, //Sniffed LK
|
||||
SPELL_EVASION = 70190, //Sniffed Sylvanas
|
||||
|
||||
// Frostsworn General
|
||||
EVENT_ACTIVATE_REFLECTIONS = 1,
|
||||
@@ -310,18 +318,24 @@ const uint32 allowedCompositions[8][5] =
|
||||
{NPC_WAVE_MERCENARY, NPC_WAVE_MAGE, NPC_WAVE_PRIEST, NPC_WAVE_FOOTMAN, NPC_WAVE_FOOTMAN}
|
||||
};
|
||||
|
||||
const Position CenterPos = {5309.459473f, 2006.478516f, 711.595459f, 0.0f};
|
||||
const Position SpawnPos = {5262.540527f, 1949.693726f, 707.695007f, 0.808736f}; // Jaina/Sylvanas Beginning Position
|
||||
const Position LoralenFollowPos = {5283.234863f, 1990.946777f, 707.695679f, 0.929097f};
|
||||
const Position MoveThronePos = {5306.952148f, 1998.499023f, 709.341431f, 1.277278f}; // Jaina/Sylvanas walks to throne
|
||||
const Position UtherSpawnPos = {5308.310059f, 2003.857178f, 709.341431f, 4.650315f};
|
||||
const Position CenterPos = {5309.459473f, 2006.478516f, 711.595459f, 0.0f};
|
||||
const Position SpawnPos = {5263.22412f, 1950.95544f, 707.695862f, 0.808736f}; // Jaina/Sylvanas Beginning Position
|
||||
const Position LoralenMidleFollowPos = {5274.25634f, 1976.04760f, 707.694763f, 0.929097f}; // Sniffed
|
||||
const Position LoralenFollowPos = {5283.29296f, 1992.43078f, 707.694763f, 0.549238f}; // Sniffed
|
||||
const Position LoralenFollowLk1 = {5292.94921f, 2008.25451f, 707.695801f, 1.047967f}; // Sniffed
|
||||
const Position LoralenFollowLk2 = {5298.94335f, 2016.37097f, 707.695801f, 0.694538f}; // Sniffed
|
||||
const Position LoralenFollowLk3 = {5336.94044f, 2040.21814f, 707.695801f, 0.439284f}; // Sniffed
|
||||
const Position LoralenFollowLkFinal = {5361.96777f, 2065.68310f, 707.693848f, 0.831989f}; // Sniffed
|
||||
const Position LoralenDeadPos = {5369.71289f, 2083.6330f, 707.695129f, 0.188739f}; // Sniffed
|
||||
const Position MoveThronePos = {5306.98535f, 1998.10302f, 709.341187f, 1.277278f}; // Jaina/Sylvanas walks to throne
|
||||
const Position UtherSpawnPos = {5308.310059f, 2003.857178f, 709.341431f, 4.650315f}; // Uther starting position
|
||||
const Position LichKingSpawnPos = {5362.917480f, 2062.307129f, 707.695374f, 3.945812f};
|
||||
const Position LichKingMoveThronePos = {5312.080566f, 2009.172119f, 709.341431f, 3.973301f}; // Lich King walks to throne
|
||||
const Position LichKingMoveAwayPos = {5400.069824f, 2102.7131689f, 707.69525f, 0.843803f}; // Lich King walks away
|
||||
const Position LichKingMoveMidlelThronePos = {5333.48437f, 2032.02648f, 707.695679f, 3.973301f}; // Lich King moves and hits Uther [sniff]
|
||||
const Position LichKingMoveThronePos = {5312.79638f, 2010.07141f, 709.3942183f, 3.973301f}; // Lich King walks to throne [sniff]
|
||||
const Position LichKingMoveAwayPos = {5400.069824f, 2102.7131689f, 707.69525f, 0.843803f}; // Lich King walks away [sniff]
|
||||
const Position FalricMovePos = {5284.161133f, 2030.691650f, 709.319336f, 5.489386f};
|
||||
const Position MarwynMovePos = {5335.330078f, 1982.376221f, 709.319580f, 2.339942f};
|
||||
const Position SylvanasFightPos = {5557.508301f, 2263.920654f, 733.011230f, 3.624075f};
|
||||
const Position LeaderEscapePos = {5577.654785f, 2235.347412f, 733.011230f, 2.359576f};
|
||||
const Position LeaderEscapePos = {5576.80566f, 2235.55004f, 733.012268f, 2.782125f}; //Sniff
|
||||
const Position ShipMasterSummonPos = {5262.773926f, 1669.980103f, 715.000000f, 0.000000f};
|
||||
const Position WalkCaveInPos = {5267.594238f, 1678.750000f, 784.302856f, 1.041739f};
|
||||
const Position AllyPortalPos = {5205.015625f, 1605.680298f, 806.444458f, 0.884375f};
|
||||
|
||||
+15
-22
@@ -230,6 +230,7 @@ public:
|
||||
{
|
||||
case NPC_SYLVANAS_PART1:
|
||||
creature->SetVisible(false);
|
||||
creature->SetSpeed(MOVE_RUN, 1.1);
|
||||
NPC_LeaderIntroGUID = creature->GetGUID();
|
||||
if (TeamIdInInstance == TEAM_ALLIANCE)
|
||||
creature->UpdateEntry(NPC_JAINA_PART1);
|
||||
@@ -296,12 +297,8 @@ public:
|
||||
creature->SetVisible(false);
|
||||
if (!(EncounterMask & (1 << DATA_LK_INTRO)))
|
||||
{
|
||||
creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK2HTIGHT);
|
||||
if (TeamIdInInstance != TEAM_ALLIANCE)
|
||||
{
|
||||
creature->StopMoving();
|
||||
creature->SetFacingTo(creature->GetAngle(&SylvanasFightPos));
|
||||
}
|
||||
creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_ATTACK2HTIGHT); //the fight cannot be in the form of an emote, it is causing bugs
|
||||
creature->CastSpell(creature, SPELL_SOUL_REAPER, true);
|
||||
}
|
||||
else if (!(EncounterMask & (1 << DATA_LICH_KING)))
|
||||
creature->AddAura(TeamIdInInstance == TEAM_ALLIANCE ? SPELL_JAINA_ICE_PRISON : SPELL_SYLVANAS_DARK_BINDING, creature);
|
||||
@@ -316,22 +313,20 @@ public:
|
||||
if (!creature->IsAlive())
|
||||
creature->Respawn();
|
||||
NPC_LeaderGUID = creature->GetGUID();
|
||||
creature->SetWalk(false);
|
||||
creature->SetSheath(SHEATH_STATE_MELEE);
|
||||
if (TeamIdInInstance == TEAM_ALLIANCE)
|
||||
creature->UpdateEntry(NPC_JAINA_PART2);
|
||||
creature->SetWalk(false);
|
||||
creature->SetHealth(creature->GetMaxHealth() / 20);
|
||||
|
||||
if (!(EncounterMask & (1 << DATA_FROSTSWORN_GENERAL)))
|
||||
creature->SetVisible(false);
|
||||
if (!(EncounterMask & (1 << DATA_LK_INTRO)))
|
||||
{
|
||||
creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, TeamIdInInstance == TEAM_ALLIANCE ? EMOTE_ONESHOT_ATTACK2HTIGHT : EMOTE_ONESHOT_ATTACK1H);
|
||||
creature->SetSheath(SHEATH_STATE_MELEE);
|
||||
creature->SetUInt32Value(UNIT_NPC_EMOTESTATE, TeamIdInInstance == TEAM_ALLIANCE ? EMOTE_ONESHOT_ATTACK2HTIGHT : EMOTE_ONESHOT_ATTACK1H); //the fight cannot be in the form of an emote, it is causing bugs.
|
||||
creature->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
|
||||
creature->CastSpell(creature, TeamIdInInstance == TEAM_ALLIANCE ? SPELL_JAINA_ICE_BARRIER : SPELL_SYLVANAS_CLOAK_OF_DARKNESS, true);
|
||||
if (TeamIdInInstance != TEAM_ALLIANCE)
|
||||
{
|
||||
creature->UpdatePosition(SylvanasFightPos, true);
|
||||
creature->StopMovingOnCurrentPos();
|
||||
}
|
||||
}
|
||||
else if (!(EncounterMask & (1 << DATA_LICH_KING)))
|
||||
{
|
||||
@@ -346,6 +341,7 @@ public:
|
||||
creature->UpdatePosition(PathWaypoints[PATH_WP_COUNT - 1], true);
|
||||
creature->StopMovingOnCurrentPos();
|
||||
}
|
||||
creature->SetSheath(SHEATH_STATE_MELEE);
|
||||
creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
break;
|
||||
case NPC_ICE_WALL_TARGET:
|
||||
@@ -444,8 +440,13 @@ public:
|
||||
if (Creature* c = instance->GetCreature(NPC_FrostswornGeneralGUID))
|
||||
{
|
||||
c->SetVisible(true);
|
||||
c->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
|
||||
c->SetReactState(REACT_AGGRESSIVE);
|
||||
}
|
||||
if (Creature* c = instance->GetCreature(NPC_FrostswornGeneralGUID))
|
||||
{
|
||||
c->HandleEmoteCommand(EMOTE_ONESHOT_EMERGE);
|
||||
}
|
||||
WaveNumber = 0;
|
||||
DoUpdateWorldState(WORLD_STATE_HOR_COUNTER, 0);
|
||||
|
||||
@@ -712,7 +713,6 @@ public:
|
||||
case GO_FRONT_DOOR:
|
||||
return GO_FrontDoorGUID;
|
||||
}
|
||||
|
||||
return ObjectGuid::Empty;
|
||||
}
|
||||
|
||||
@@ -772,7 +772,6 @@ public:
|
||||
++ur;
|
||||
}
|
||||
}
|
||||
|
||||
if (bFinished5Waves)
|
||||
{
|
||||
for (; WaveNumber < 4; ++WaveNumber)
|
||||
@@ -860,9 +859,7 @@ public:
|
||||
num_to_activate = 3;
|
||||
else if (WaveNumber <= 4)
|
||||
num_to_activate = 4;
|
||||
|
||||
reqKillCount += num_to_activate;
|
||||
|
||||
for (uint8 i = 0; i < num_to_activate; ++i)
|
||||
{
|
||||
uint32 entry = chosenComposition[WaveNumber - (WaveNumber > 5 ? 2 : 1)][i];
|
||||
@@ -910,7 +907,6 @@ public:
|
||||
c->StopMovingOnCurrentPos();
|
||||
}
|
||||
memset(&TrashActive, 0, sizeof(TrashActive));
|
||||
|
||||
if (Creature* falric = instance->GetCreature(NPC_FalricGUID))
|
||||
falric->AI()->EnterEvadeMode();
|
||||
if (Creature* marwyn = instance->GetCreature(NPC_MarwynGUID))
|
||||
@@ -1014,7 +1010,6 @@ public:
|
||||
if (Aura* a = pMarwyn->AddAura(SPELL_SHADOWMOURNE_VISUAL, pMarwyn))
|
||||
a->SetDuration(8000);
|
||||
}
|
||||
|
||||
pMarwyn->AI()->Talk(EMOTE_MARWYN_INTRO_SPIRIT);
|
||||
}
|
||||
++ResumeFirstEventStep;
|
||||
@@ -1035,7 +1030,6 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetData(ACTION_SHOW_TRASH, 1);
|
||||
ResumeFirstEventStep = 0;
|
||||
ResumeFirstEventTimer = 0;
|
||||
@@ -1057,7 +1051,6 @@ public:
|
||||
else
|
||||
ResumeFirstEventTimer -= diff;
|
||||
}
|
||||
|
||||
if (outroStep)
|
||||
{
|
||||
if (outroTimer <= diff)
|
||||
@@ -1153,7 +1146,6 @@ public:
|
||||
if (StairsPos[index][i].GetPositionX())
|
||||
if (GameObject* go = leader->SummonGameObject(TeamIdInInstance == TEAM_ALLIANCE ? GO_STAIRS_ALLIANCE : GO_STAIRS_HORDE, StairsPos[index][i].GetPositionX(), StairsPos[index][i].GetPositionY(), StairsPos[index][i].GetPositionZ(), StairsPos[index][i].GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400, false))
|
||||
go->SetGameObjectFlag(GO_FLAG_INTERACT_COND | GO_FLAG_NOT_SELECTABLE);
|
||||
|
||||
//Position pos = TeamIdInInstance == TEAM_ALLIANCE ? AllyPortalPos : HordePortalPos;
|
||||
//leader->SummonGameObject(GO_PORTAL_TO_DALARAN, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 86400);
|
||||
//pos = TeamIdInInstance == TEAM_ALLIANCE ? AllyChestPos : HordeChestPos;
|
||||
@@ -1169,6 +1161,7 @@ public:
|
||||
{
|
||||
c->AddUnitMovementFlag(MOVEMENTFLAG_WALKING);
|
||||
c->GetMotionMaster()->MovePoint(0, WalkCaveInPos);
|
||||
c->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP); // need gossip ID 10931
|
||||
}
|
||||
++outroStep;
|
||||
outroTimer = 6000;
|
||||
|
||||
@@ -1184,6 +1184,36 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct npc_violet_hold_defense_system : public ScriptedAI
|
||||
{
|
||||
npc_violet_hold_defense_system(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
DoCast(RAND(SPELL_DEFENSE_SYSTEM_SPAWN_EFFECT, SPELL_DEFENSE_SYSTEM_VISUAL));
|
||||
events.ScheduleEvent(EVENT_ARCANE_LIGHTNING, 4s);
|
||||
events.ScheduleEvent(EVENT_ARCANE_LIGHTNING_INSTAKILL, 4s);
|
||||
me->DespawnOrUnsummon(7s, 0s);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events.Update(diff);
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_ARCANE_LIGHTNING:
|
||||
DoCastAOE(RAND(SPELL_ARCANE_LIGHTNING, SPELL_ARCANE_LIGHTNING_VISUAL));
|
||||
events.RepeatEvent(2000);
|
||||
break;
|
||||
case EVENT_ARCANE_LIGHTNING_INSTAKILL:
|
||||
DoCastAOE(SPELL_ARCANE_LIGHTNING_INSTAKILL);
|
||||
events.RepeatEvent(1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_violet_hold()
|
||||
{
|
||||
new go_vh_activation_crystal();
|
||||
@@ -1201,4 +1231,5 @@ void AddSC_violet_hold()
|
||||
new npc_azure_stalker();
|
||||
|
||||
new spell_destroy_door_seal();
|
||||
RegisterCreatureAI(npc_violet_hold_defense_system);
|
||||
}
|
||||
|
||||
@@ -98,13 +98,16 @@ enum VHWorldStates
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CONTROL_CRYSTAL_ACTIVATION = 57804,
|
||||
SPELL_ARCANE_LIGHTNING = 57912,
|
||||
SPELL_ARCANE_LIGHTNING_VISUAL = 57930,
|
||||
SPELL_PORTAL_CHANNEL = 58012,
|
||||
SPELL_DESTROY_DOOR_SEAL = 58040,
|
||||
SPELL_CYANIGOSA_TRANSFORM = 58668,
|
||||
SPELL_CYANIGOSA_BLUE_AURA = 45870,
|
||||
SPELL_CONTROL_CRYSTAL_ACTIVATION = 57804,
|
||||
SPELL_DEFENSE_SYSTEM_SPAWN_EFFECT = 57886,
|
||||
SPELL_DEFENSE_SYSTEM_VISUAL = 57887,
|
||||
SPELL_ARCANE_LIGHTNING = 57912,
|
||||
SPELL_ARCANE_LIGHTNING_VISUAL = 57930,
|
||||
SPELL_ARCANE_LIGHTNING_INSTAKILL = 58152,
|
||||
SPELL_PORTAL_CHANNEL = 58012,
|
||||
SPELL_DESTROY_DOOR_SEAL = 58040,
|
||||
SPELL_CYANIGOSA_TRANSFORM = 58668,
|
||||
SPELL_CYANIGOSA_BLUE_AURA = 45870
|
||||
};
|
||||
|
||||
enum Events
|
||||
@@ -117,6 +120,10 @@ enum Events
|
||||
EVENT_SUMMON_PORTAL,
|
||||
EVENT_CYANIGOSSA_TRANSFORM,
|
||||
EVENT_CYANIGOSA_ATTACK,
|
||||
|
||||
// Event defense system
|
||||
EVENT_ARCANE_LIGHTNING,
|
||||
EVENT_ARCANE_LIGHTNING_INSTAKILL
|
||||
};
|
||||
|
||||
enum Data
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "mana_tombs.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_EARTHQUAKE = 33919,
|
||||
SPELL_CRYSTAL_PRISON = 32361,
|
||||
SPELL_ARCING_SMASH_N = 8374,
|
||||
SPELL_ARCING_SMASH_H = 38761
|
||||
};
|
||||
|
||||
struct boss_tavarok : public BossAI
|
||||
{
|
||||
boss_tavarok(Creature* creature) : BossAI(creature, DATA_TAVAROK)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_JustEngagedWith();
|
||||
|
||||
scheduler.Schedule(10s, 14200ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_EARTHQUAKE);
|
||||
context.Repeat(20s, 31s);
|
||||
}).Schedule(12s, 22s, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_CRYSTAL_PRISON);
|
||||
context.Repeat(15s, 22s);
|
||||
}).Schedule(5900ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(DUNGEON_MODE(SPELL_ARCING_SMASH_N, SPELL_ARCING_SMASH_H));
|
||||
context.Repeat(8s, 12s);
|
||||
});
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_tavarok()
|
||||
{
|
||||
RegisterManaTombsCreatureAI(boss_tavarok);
|
||||
}
|
||||
@@ -40,4 +40,6 @@ inline AI* GetManaTombsAI(T* obj)
|
||||
return GetInstanceAI<AI>(obj, MTScriptName);
|
||||
}
|
||||
|
||||
#define RegisterManaTombsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetManaTombsAI)
|
||||
|
||||
#endif // MANA_TOMBS_H_
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "sethekk_halls.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_FLAME_SHOCK_N = 15039,
|
||||
SPELL_FLAME_SHOCK_H = 15616,
|
||||
SPELL_ARCANE_SHOCK_N = 33534,
|
||||
SPELL_ARCANE_SHOCK_H = 38135,
|
||||
SPELL_FROST_SHOCK_N = 12548,
|
||||
SPELL_FROST_SHOCK_H = 21401,
|
||||
SPELL_SHADOW_SHOCK_N = 33620,
|
||||
SPELL_SHADOW_SHOCK_H = 38137,
|
||||
SPELL_CHAIN_LIGHTNING_N = 15659,
|
||||
SPELL_CHAIN_LIGHTNING_H = 15305,
|
||||
SPELL_SUMMON_ARC_ELE = 33538,
|
||||
SPELL_SUMMON_FIRE_ELE = 33537,
|
||||
SPELL_SUMMON_FROST_ELE = 33539,
|
||||
SPELL_SUMMON_SHADOW_ELE = 33540
|
||||
};
|
||||
|
||||
enum Text
|
||||
{
|
||||
SAY_SUMMON = 0,
|
||||
SAY_AGGRO = 1,
|
||||
SAY_SLAY = 2,
|
||||
SAY_DEATH = 3
|
||||
};
|
||||
|
||||
struct boss_darkweaver_syth : public BossAI
|
||||
{
|
||||
boss_darkweaver_syth(Creature* creature) : BossAI(creature, DATA_DARKWEAVER_SYTH)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
|
||||
ScheduleHealthCheckEvent({90, 50, 10}, [&] {
|
||||
Talk(SAY_SUMMON);
|
||||
DoCastSelf(SPELL_SUMMON_ARC_ELE);
|
||||
DoCastSelf(SPELL_SUMMON_FIRE_ELE);
|
||||
DoCastSelf(SPELL_SUMMON_FROST_ELE);
|
||||
DoCastSelf(SPELL_SUMMON_SHADOW_ELE);
|
||||
});
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_JustEngagedWith();
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
scheduler.Schedule(2s, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(DUNGEON_MODE(SPELL_FLAME_SHOCK_N, SPELL_FLAME_SHOCK_H));
|
||||
context.Repeat(10s, 15s);
|
||||
}).Schedule(4s, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(DUNGEON_MODE(SPELL_ARCANE_SHOCK_N, SPELL_ARCANE_SHOCK_H));
|
||||
context.Repeat(10s, 15s);
|
||||
}).Schedule(6s, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(DUNGEON_MODE(SPELL_FROST_SHOCK_N, SPELL_FROST_SHOCK_H));
|
||||
context.Repeat(10s, 15s);
|
||||
}).Schedule(8s, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(DUNGEON_MODE(SPELL_SHADOW_SHOCK_N, SPELL_SHADOW_SHOCK_H));
|
||||
context.Repeat(10s, 15s);
|
||||
}).Schedule(15s, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(DUNGEON_MODE(SPELL_CHAIN_LIGHTNING_N, SPELL_CHAIN_LIGHTNING_H));
|
||||
context.Repeat(10s, 15s);
|
||||
});
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
|
||||
Talk(SAY_DEATH);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_darkweaver_syth()
|
||||
{
|
||||
RegisterSethekkHallsCreatureAI(boss_darkweaver_syth);
|
||||
}
|
||||
@@ -28,8 +28,7 @@ enum GrandmasterVorpil
|
||||
SAY_SLAY = 3,
|
||||
SAY_DEATH = 4,
|
||||
|
||||
SPELL_RAIN_OF_FIRE_N = 33617,
|
||||
SPELL_RAIN_OF_FIRE_H = 39363,
|
||||
SPELL_RAIN_OF_FIRE = 33617,
|
||||
|
||||
SPELL_DRAW_SHADOWS = 33563,
|
||||
SPELL_SHADOWBOLT_VOLLEY = 33841,
|
||||
@@ -38,8 +37,7 @@ enum GrandmasterVorpil
|
||||
NPC_VOID_TRAVELER = 19226,
|
||||
SPELL_SACRIFICE = 33587,
|
||||
SPELL_SHADOW_NOVA = 33846,
|
||||
SPELL_EMPOWERING_SHADOWS_N = 33783,
|
||||
SPELL_EMPOWERING_SHADOWS_H = 39364,
|
||||
SPELL_EMPOWERING_SHADOWS = 33783,
|
||||
|
||||
NPC_VOID_PORTAL = 19224,
|
||||
SPELL_VOID_PORTAL_VISUAL = 33569,
|
||||
@@ -155,22 +153,17 @@ struct boss_grandmaster_vorpil : public BossAI
|
||||
context.Repeat();
|
||||
}).Schedule(36400ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_DRAW_SHADOWS, true);
|
||||
DoCastAOE(SPELL_DRAW_SHADOWS, true);
|
||||
|
||||
me->GetMap()->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->IsAlive() && !player->HasAura(SPELL_BANISH))
|
||||
{
|
||||
player->TeleportTo(me->GetMapId(), VorpilPosition[0], VorpilPosition[1], VorpilPosition[2], 0, TELE_TO_NOT_LEAVE_COMBAT);
|
||||
}
|
||||
});
|
||||
me->NearTeleportTo(VorpilPosition[0], VorpilPosition[1], VorpilPosition[2], 0.0f);
|
||||
me->GetMotionMaster()->Clear();
|
||||
|
||||
scheduler.Schedule(1s, [this](TaskContext /*context*/)
|
||||
{
|
||||
DoCastSelf(DUNGEON_MODE(SPELL_RAIN_OF_FIRE_N, SPELL_RAIN_OF_FIRE_H));
|
||||
DoCastSelf(SPELL_RAIN_OF_FIRE);
|
||||
me->ResumeChasingVictim();
|
||||
});
|
||||
|
||||
me->NearTeleportTo(VorpilPosition[0], VorpilPosition[1], VorpilPosition[2], 0.0f);
|
||||
context.Repeat(36400ms, 44950ms);
|
||||
}).Schedule(10900ms, [this](TaskContext context)
|
||||
{
|
||||
@@ -203,52 +196,59 @@ struct npc_voidtraveler : public ScriptedAI
|
||||
{
|
||||
npc_voidtraveler(Creature* creature) : ScriptedAI(creature) {}
|
||||
|
||||
ObjectGuid VorpilGUID;
|
||||
uint32 moveTimer;
|
||||
bool sacrificed;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
moveTimer = 1000;
|
||||
sacrificed = false;
|
||||
}
|
||||
if (TempSummon* summon = me->ToTempSummon())
|
||||
{
|
||||
if (Unit* vorpil = summon->GetSummonerUnit())
|
||||
{
|
||||
me->GetMotionMaster()->MoveFollow(vorpil, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void SetGUID(ObjectGuid guid, int32) override
|
||||
{
|
||||
VorpilGUID = guid;
|
||||
_scheduler.Schedule(1s, [this](TaskContext context)
|
||||
{
|
||||
if (TempSummon* summon = me->ToTempSummon())
|
||||
{
|
||||
if (Unit* vorpil = summon->GetSummonerUnit())
|
||||
{
|
||||
if (me->IsWithinMeleeRange(vorpil))
|
||||
{
|
||||
DoCastSelf(SPELL_SACRIFICE);
|
||||
_scheduler.Schedule(1200ms, [this](TaskContext /*context*/)
|
||||
{
|
||||
if (TempSummon* summon = me->ToTempSummon())
|
||||
{
|
||||
if (Unit* vorpil = summon->GetSummonerUnit())
|
||||
{
|
||||
DoCastAOE(SPELL_SHADOW_NOVA, true);
|
||||
me->CastSpell(vorpil, SPELL_EMPOWERING_SHADOWS, true, nullptr, nullptr, vorpil->GetGUID());
|
||||
vorpil->ModifyHealth(int32(vorpil->CountPctFromMaxHealth(4)));
|
||||
}
|
||||
}
|
||||
|
||||
_scheduler.Schedule(100ms, [this](TaskContext /*context*/)
|
||||
{
|
||||
me->KillSelf();
|
||||
});
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Repeat();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
moveTimer += diff;
|
||||
if (moveTimer >= 1000)
|
||||
{
|
||||
moveTimer = 0;
|
||||
Creature* Vorpil = ObjectAccessor::GetCreature(*me, VorpilGUID);
|
||||
if (!Vorpil)
|
||||
{
|
||||
me->DespawnOrUnsummon();
|
||||
return;
|
||||
}
|
||||
me->GetMotionMaster()->MoveFollow(Vorpil, 0.0f, 0.0f);
|
||||
|
||||
if (sacrificed)
|
||||
{
|
||||
Vorpil->AddAura(DUNGEON_MODE(SPELL_EMPOWERING_SHADOWS_N, SPELL_EMPOWERING_SHADOWS_H), Vorpil);
|
||||
Vorpil->ModifyHealth(int32(Vorpil->CountPctFromMaxHealth(4)));
|
||||
DoCastAOE(SPELL_SHADOW_NOVA, true);
|
||||
me->KillSelf();
|
||||
return;
|
||||
}
|
||||
|
||||
if (me->IsWithinDist(Vorpil, 3.0f))
|
||||
{
|
||||
DoCastSelf(SPELL_SACRIFICE);
|
||||
sacrificed = true;
|
||||
moveTimer = 500;
|
||||
}
|
||||
}
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
void AddSC_boss_grandmaster_vorpil()
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "the_slave_pens.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_LIGHTNING_BOLT = 35010,
|
||||
SPELL_HEALING_WARD = 34980,
|
||||
SPELL_EARTHGRAB_TOTEM = 31981,
|
||||
SPELL_STONESKIN_TOTEM = 31985,
|
||||
SPELL_NOVA_TOTEM = 31991
|
||||
};
|
||||
|
||||
enum Text
|
||||
{
|
||||
SAY_AGGRO = 1,
|
||||
SAY_KILL = 2,
|
||||
SAY_JUST_DIED = 3
|
||||
};
|
||||
|
||||
struct boss_mennu_the_betrayer : public BossAI
|
||||
{
|
||||
boss_mennu_the_betrayer(Creature* creature) : BossAI(creature, DATA_MENNU_THE_BETRAYER)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
|
||||
ScheduleHealthCheckEvent(60, [&] {
|
||||
DoCastSelf(SPELL_HEALING_WARD);
|
||||
});
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summon->GetMotionMaster()->Clear();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_JustEngagedWith();
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
scheduler.Schedule(5s, 8s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_LIGHTNING_BOLT);
|
||||
context.Repeat(7s, 10s);
|
||||
}).Schedule(20s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_NOVA_TOTEM);
|
||||
context.Repeat(26s);
|
||||
}).Schedule(19200ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_EARTHGRAB_TOTEM);
|
||||
context.Repeat(26s);
|
||||
}).Schedule(18s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_STONESKIN_TOTEM);
|
||||
context.Repeat(26s);
|
||||
});
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
Talk(SAY_JUST_DIED);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_mennu_the_betrayer()
|
||||
{
|
||||
RegisterTheSlavePensCreatureAI(boss_mennu_the_betrayer);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "the_slave_pens.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_ACID_SPRAY = 38153,
|
||||
SPELL_CLEAVE = 40504,
|
||||
SPELL_POISON_BOLT_VOLLEY_N = 34780,
|
||||
SPELL_POISON_BOLT_VOLLEY_H = 39340,
|
||||
SPELL_UPPERCUT = 32055
|
||||
};
|
||||
|
||||
struct boss_quagmirran : public BossAI
|
||||
{
|
||||
boss_quagmirran(Creature* creature) : BossAI(creature, DATA_QUAGMIRRAN)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_JustEngagedWith();
|
||||
|
||||
scheduler.Schedule(9100ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
context.Repeat(18800ms, 24800ms);
|
||||
}).Schedule(20300ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_UPPERCUT);
|
||||
context.Repeat(21800ms);
|
||||
}).Schedule(25200ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_ACID_SPRAY);
|
||||
context.Repeat(25s);
|
||||
}).Schedule(31800ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(DUNGEON_MODE(SPELL_POISON_BOLT_VOLLEY_N, SPELL_POISON_BOLT_VOLLEY_H));
|
||||
context.Repeat(24400ms);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_quagmirran()
|
||||
{
|
||||
RegisterTheSlavePensCreatureAI(boss_quagmirran);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "the_slave_pens.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_ENSNARING_MOSS = 31948,
|
||||
SPELL_FRENZY = 34970,
|
||||
SPELL_GRIEVOUS_WOUND_N = 31956,
|
||||
SPELL_GRIEVOUS_WOUND_H = 38801,
|
||||
SPELL_WATER_SPIT = 35008
|
||||
};
|
||||
|
||||
struct boss_rokmar_the_crackler : public BossAI
|
||||
{
|
||||
boss_rokmar_the_crackler(Creature* creature) : BossAI(creature, DATA_ROKMAR_THE_CRACKLER)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
|
||||
ScheduleHealthCheckEvent(20, [&] {
|
||||
DoCastSelf(SPELL_FRENZY);
|
||||
});
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_JustEngagedWith();
|
||||
|
||||
scheduler.Schedule(8s, [this] (TaskContext context)
|
||||
{
|
||||
DoCastVictim(DUNGEON_MODE(SPELL_GRIEVOUS_WOUND_N, SPELL_GRIEVOUS_WOUND_H));
|
||||
context.Repeat(20700ms);
|
||||
}).Schedule(15300ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_ENSNARING_MOSS);
|
||||
context.Repeat(26s);
|
||||
}).Schedule(10700ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_WATER_SPIT);
|
||||
context.Repeat(19s);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_rokmar_the_crackler()
|
||||
{
|
||||
RegisterTheSlavePensCreatureAI(boss_rokmar_the_crackler);
|
||||
}
|
||||
@@ -27,10 +27,11 @@ uint32 const EncounterCount = 3;
|
||||
|
||||
enum SPDataTypes
|
||||
{
|
||||
DATA_MENNU_THE_BETRAYER = 1,
|
||||
DATA_ROKMAR_THE_CRACKLER = 2,
|
||||
DATA_QUAGMIRRAN = 3,
|
||||
DATA_AHUNE = 4,
|
||||
DATA_MENNU_THE_BETRAYER = 0,
|
||||
DATA_ROKMAR_THE_CRACKLER = 1,
|
||||
DATA_QUAGMIRRAN = 2,
|
||||
DATA_AHUNE = 3,
|
||||
MAX_ENCOUNTER = 4,
|
||||
DATA_AHUNE_BUNNY = 5,
|
||||
DATA_FROZEN_CORE = 6,
|
||||
DATA_FLAMECALLER_000 = 7,
|
||||
@@ -65,6 +66,8 @@ enum SPCreaturesIds
|
||||
NPC_SHAMAN_BEAM_BUNNY_002 = 25966,
|
||||
NPC_WHISP_DEST_BUNNY = 26120,
|
||||
NPC_WHISP_SOURCE_BUNNY = 26121,
|
||||
NPC_MENNU_THE_BETRAYER = 17941,
|
||||
NPC_ROKMAR_THE_CRACKLER = 17991,
|
||||
NPC_QUAGMIRRAN = 17942
|
||||
};
|
||||
|
||||
@@ -80,4 +83,6 @@ inline AI* GetTheSlavePensAI(T* obj)
|
||||
return GetInstanceAI<AI>(obj, SPScriptName);
|
||||
}
|
||||
|
||||
#define RegisterTheSlavePensCreatureAI(ai_name) RegisterCreatureAIWithFactory (ai_name, GetTheSlavePensAI)
|
||||
|
||||
#endif // SLAVE_PENS_H
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "the_underbog.h"
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_SHOOT = 22907,
|
||||
SPELL_KNOCKAWAY = 18813,
|
||||
SPELL_RAPTOR_STRIKE = 31566,
|
||||
SPELL_MULTISHOT = 34974,
|
||||
SPELL_THROW_FREEZING_TRAP = 31946,
|
||||
SPELL_AIMED_SHOT = 31623,
|
||||
SPELL_HUNTERS_MARK = 31615
|
||||
};
|
||||
|
||||
enum Text
|
||||
{
|
||||
SAY_AGGRO = 1,
|
||||
SAY_KILL = 2,
|
||||
SAY_JUST_DIED = 3
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
RANGED_GROUP = 1,
|
||||
RANGE_CHECK = 2
|
||||
};
|
||||
|
||||
struct boss_swamplord_muselek : public BossAI
|
||||
{
|
||||
boss_swamplord_muselek(Creature* creature) : BossAI(creature, DATA_MUSELEK)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
_canChase = true;
|
||||
}
|
||||
|
||||
void AttackStart(Unit* victim) override
|
||||
{
|
||||
if (victim && me->Attack(victim, true) && me->IsWithinMeleeRange(victim))
|
||||
{
|
||||
me->GetMotionMaster()->MoveChase(victim);
|
||||
}
|
||||
else
|
||||
{
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
Talk(SAY_JUST_DIED);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
|
||||
bool CanShootVictim()
|
||||
{
|
||||
return me->GetVictim() && !me->IsWithinRange(me->GetVictim(), 10.0f) && me->IsWithinLOSInMap(me->GetVictim());
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_JustEngagedWith();
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
scheduler.Schedule(3s, [this](TaskContext context)
|
||||
{
|
||||
if (CanShootVictim())
|
||||
{
|
||||
me->LoadEquipment(1, true);
|
||||
DoCastVictim(SPELL_SHOOT);
|
||||
me->GetMotionMaster()->Clear();
|
||||
}
|
||||
else if (_canChase)
|
||||
{
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
}
|
||||
|
||||
context.Repeat();
|
||||
}).Schedule(15s, 30s, [this](TaskContext context)
|
||||
{
|
||||
if (me->GetVictim() && me->IsWithinMeleeRange(me->GetVictim()))
|
||||
{
|
||||
DoCastVictim(SPELL_KNOCKAWAY);
|
||||
}
|
||||
|
||||
context.Repeat();
|
||||
}).Schedule(10s, 15s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_MULTISHOT);
|
||||
context.Repeat(20s, 30s);
|
||||
}).Schedule(30s, 40s, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, false, true))
|
||||
{
|
||||
_markTarget = target->GetGUID();
|
||||
_canChase = false;
|
||||
DoCastVictim(SPELL_THROW_FREEZING_TRAP);
|
||||
|
||||
scheduler.Schedule(3s, [this, target](TaskContext)
|
||||
{
|
||||
if (target && me->GetVictim())
|
||||
{
|
||||
if (me->IsWithinMeleeRange(me->GetVictim()))
|
||||
{
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveBackwards(me->GetVictim(), 10.0f);
|
||||
}
|
||||
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
if (Unit* marktarget = ObjectAccessor::GetUnit(*me, _markTarget))
|
||||
{
|
||||
DoCast(marktarget, SPELL_HUNTERS_MARK);
|
||||
}
|
||||
}, 3s);
|
||||
}
|
||||
});
|
||||
|
||||
scheduler.Schedule(5s, [this, target](TaskContext)
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
me->m_Events.AddEventAtOffset([this]()
|
||||
{
|
||||
if (Unit* marktarget = ObjectAccessor::GetUnit(*me, _markTarget))
|
||||
{
|
||||
scheduler.DelayAll(5s);
|
||||
DoCast(marktarget, SPELL_AIMED_SHOT);
|
||||
_canChase = true;
|
||||
}
|
||||
}, 3s);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
context.Repeat(12s, 16s);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectGuid _markTarget;
|
||||
bool _canChase;
|
||||
};
|
||||
|
||||
void AddSC_boss_swamplord_muselek()
|
||||
{
|
||||
RegisterUnderbogCreatureAI(boss_swamplord_muselek);
|
||||
}
|
||||
@@ -16,9 +16,55 @@
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "TaskScheduler.h"
|
||||
#include "the_underbog.h"
|
||||
|
||||
enum UnderbatSpells
|
||||
{
|
||||
SPELL_TENTACLE_LASH = 34171
|
||||
};
|
||||
|
||||
struct npc_underbat : public ScriptedAI
|
||||
{
|
||||
npc_underbat(Creature* c) : ScriptedAI(c) {}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_scheduler.CancelAll();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_scheduler.Schedule(2200ms, 6900ms, [this](TaskContext context)
|
||||
{
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* u)
|
||||
{
|
||||
return u->IsAlive() && !u->IsPet() && me->IsWithinCombatRange(u, 20.f) && !me->HasInArc(M_PI, u);
|
||||
}))
|
||||
{
|
||||
DoCast(target, SPELL_TENTACLE_LASH);
|
||||
}
|
||||
context.Repeat(5700ms, 9700ms);
|
||||
});
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
_scheduler.Update(diff, [this]
|
||||
{
|
||||
DoMeleeAttackIfReady();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
class spell_fungal_decay : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_fungal_decay);
|
||||
@@ -72,6 +118,7 @@ class spell_allergies : public AuraScript
|
||||
|
||||
void AddSC_underbog()
|
||||
{
|
||||
RegisterUnderbogCreatureAI(npc_underbat);
|
||||
RegisterSpellScript(spell_fungal_decay);
|
||||
RegisterSpellScript(spell_allergies);
|
||||
}
|
||||
|
||||
@@ -29,41 +29,41 @@ constexpr uint32 EncounterCount = 4;
|
||||
|
||||
enum bloodFurnace
|
||||
{
|
||||
DATA_THE_MAKER = 0,
|
||||
DATA_BROGGOK = 1,
|
||||
DATA_KELIDAN = 2,
|
||||
MAX_ENCOUNTER = 3,
|
||||
DATA_THE_MAKER = 0,
|
||||
DATA_BROGGOK = 1,
|
||||
DATA_KELIDAN = 2,
|
||||
MAX_ENCOUNTER = 3,
|
||||
|
||||
DATA_DOOR1 = 10,
|
||||
DATA_DOOR2 = 11,
|
||||
DATA_DOOR3 = 12,
|
||||
DATA_BROGGOK_REAR_DOOR = 13,
|
||||
DATA_BROGGOK_LEVER = 14,
|
||||
DATA_DOOR6 = 15,
|
||||
DATA_DOOR1 = 10,
|
||||
DATA_DOOR2 = 11,
|
||||
DATA_DOOR3 = 12,
|
||||
DATA_BROGGOK_REAR_DOOR = 13,
|
||||
DATA_BROGGOK_LEVER = 14,
|
||||
DATA_DOOR6 = 15,
|
||||
|
||||
DATA_PRISON_CELL1 = 20,
|
||||
DATA_PRISON_CELL2 = 21,
|
||||
DATA_PRISON_CELL3 = 22,
|
||||
DATA_PRISON_CELL4 = 23,
|
||||
DATA_PRISON_CELL1 = 20,
|
||||
DATA_PRISON_CELL2 = 21,
|
||||
DATA_PRISON_CELL3 = 22,
|
||||
DATA_PRISON_CELL4 = 23,
|
||||
|
||||
ACTION_ACTIVATE_BROGGOK = 30,
|
||||
ACTION_PREPARE_BROGGOK = 31
|
||||
ACTION_ACTIVATE_BROGGOK = 30,
|
||||
ACTION_PREPARE_BROGGOK = 31
|
||||
};
|
||||
|
||||
enum bloodFurnaceNPC
|
||||
{
|
||||
NPC_THE_MAKER = 17381,
|
||||
NPC_BROGGOK = 17380,
|
||||
NPC_KELIDAN = 17377,
|
||||
NPC_NASCENT_FEL_ORC = 17398,
|
||||
NPC_CHANNELER = 17653
|
||||
NPC_THE_MAKER = 17381,
|
||||
NPC_BROGGOK = 17380,
|
||||
NPC_KELIDAN = 17377,
|
||||
NPC_NASCENT_FEL_ORC = 17398,
|
||||
NPC_CHANNELER = 17653
|
||||
};
|
||||
|
||||
enum BloodFurnaceGO
|
||||
{
|
||||
GO_BROGGOK_DOOR_FRONT = 181822,
|
||||
GO_BROGGOK_DOOR_REAR = 181819,
|
||||
GO_BROGGOK_LEVER = 181982
|
||||
GO_BROGGOK_DOOR_FRONT = 181822,
|
||||
GO_BROGGOK_DOOR_REAR = 181819,
|
||||
GO_BROGGOK_LEVER = 181982
|
||||
};
|
||||
|
||||
template <class AI, class T>
|
||||
|
||||
@@ -21,14 +21,17 @@
|
||||
#include "SpellScript.h"
|
||||
#include "blood_furnace.h"
|
||||
|
||||
enum eEnums
|
||||
enum Say
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_AGGRO = 0
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_SLIME_SPRAY = 30913,
|
||||
SPELL_POISON_CLOUD = 30916,
|
||||
SPELL_POISON_BOLT = 30917,
|
||||
SPELL_POISON = 30914,
|
||||
SPELL_POISON = 30914
|
||||
};
|
||||
|
||||
struct boss_broggok : public BossAI
|
||||
@@ -52,7 +55,6 @@ struct boss_broggok : public BossAI
|
||||
void JustSummoned(Creature* summoned) override
|
||||
{
|
||||
summons.Summon(summoned);
|
||||
|
||||
summoned->SetFaction(FACTION_MONSTER_2);
|
||||
summoned->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
|
||||
summoned->CastSpell(summoned, SPELL_POISON, true, 0, 0, me->GetGUID());
|
||||
@@ -80,7 +82,6 @@ struct boss_broggok : public BossAI
|
||||
DoCastSelf(SPELL_POISON_CLOUD);
|
||||
context.Repeat(20s);
|
||||
});
|
||||
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetImmuneToAll(false);
|
||||
@@ -106,7 +107,6 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
go->UseDoorOrButton();
|
||||
return false;
|
||||
}
|
||||
@@ -121,6 +121,7 @@ class spell_broggok_poison_cloud : public AuraScript
|
||||
{
|
||||
if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_0].TriggerSpell))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -142,6 +143,6 @@ class spell_broggok_poison_cloud : public AuraScript
|
||||
void AddSC_boss_broggok()
|
||||
{
|
||||
RegisterBloodFurnaceCreatureAI(boss_broggok);
|
||||
new go_broggok_lever();
|
||||
RegisterSpellScript(spell_broggok_poison_cloud);
|
||||
new go_broggok_lever();
|
||||
}
|
||||
|
||||
+117
-300
@@ -20,343 +20,160 @@
|
||||
#include "SpellAuras.h"
|
||||
#include "blood_furnace.h"
|
||||
|
||||
enum eKelidan
|
||||
enum Says
|
||||
{
|
||||
SAY_WAKE = 0,
|
||||
SAY_ADD_AGGRO = 1,
|
||||
SAY_KILL = 2,
|
||||
SAY_NOVA = 3,
|
||||
SAY_DIE = 4,
|
||||
SAY_DIE = 4
|
||||
};
|
||||
|
||||
// Keldian spells
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CORRUPTION = 30938,
|
||||
SPELL_EVOCATION = 30935,
|
||||
SPELL_FIRE_NOVA = 33132,
|
||||
SPELL_SHADOW_BOLT_VOLLEY = 28599,
|
||||
SPELL_BURNING_NOVA = 30940,
|
||||
SPELL_VORTEX = 37370,
|
||||
|
||||
// Channelers spells
|
||||
SPELL_SHADOW_BOLT = 12739,
|
||||
SPELL_SHADOW_BOLT_H = 15472,
|
||||
SPELL_MARK_OF_SHADOW = 30937,
|
||||
SPELL_CHANNELING = 39123,
|
||||
|
||||
// Events
|
||||
EVENT_SPELL_VOLLEY = 1,
|
||||
EVENT_SPELL_CORRUPTION = 2,
|
||||
EVENT_SPELL_BURNING_NOVA = 3,
|
||||
EVENT_SPELL_FIRE_NOVA = 4,
|
||||
EVENT_SPELL_SHADOW_BOLT = 5,
|
||||
EVENT_SPELL_MARK = 6,
|
||||
|
||||
// Actions
|
||||
ACTION_CHANNELER_ENGAGED = 1,
|
||||
ACTION_CHANNELER_DIED = 2,
|
||||
SPELL_VORTEX = 37370
|
||||
};
|
||||
|
||||
const float ShadowmoonChannelers[5][4] =
|
||||
enum Misc
|
||||
{
|
||||
{302.0f, -87.0f, -24.4f, 0.157f},
|
||||
{321.0f, -63.5f, -24.6f, 4.887f},
|
||||
{346.0f, -74.5f, -24.6f, 3.595f},
|
||||
{344.0f, -103.5f, -24.5f, 2.356f},
|
||||
{316.0f, -109.0f, -24.6f, 1.257f}
|
||||
NPC_SHADOWMOON_CHANNELER = 17653
|
||||
};
|
||||
|
||||
class boss_kelidan_the_breaker : public CreatureScript
|
||||
enum Actions
|
||||
{
|
||||
public:
|
||||
boss_kelidan_the_breaker() : CreatureScript("boss_kelidan_the_breaker")
|
||||
ACTION_CHANNELER_DIED = 1,
|
||||
ACTION_CHANNELER_AGGRO = 2
|
||||
};
|
||||
|
||||
struct boss_kelidan_the_breaker : public BossAI
|
||||
{
|
||||
boss_kelidan_the_breaker(Creature* creature) : BossAI(creature, DATA_KELIDAN)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
struct boss_kelidan_the_breakerAI : public ScriptedAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_kelidan_the_breakerAI(Creature* creature) : ScriptedAI(creature)
|
||||
_Reset();
|
||||
ApplyImmunities(true);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
DoCastSelf(SPELL_EVOCATION);
|
||||
if (instance)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
instance->SetData(DATA_KELIDAN, NOT_STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
EventMap events;
|
||||
ObjectGuid channelers[5];
|
||||
uint32 checkTimer;
|
||||
bool addYell;
|
||||
|
||||
void Reset() override
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_WAKE);
|
||||
_JustEngagedWith();
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
if (instance)
|
||||
{
|
||||
addYell = false;
|
||||
checkTimer = 5000;
|
||||
|
||||
events.Reset();
|
||||
instance->SetData(DATA_KELIDAN, IN_PROGRESS);
|
||||
}
|
||||
scheduler.Schedule(1s, [this](TaskContext context)
|
||||
{
|
||||
DoCastAOE(SPELL_SHADOW_BOLT_VOLLEY);
|
||||
context.Repeat(8s, 13s);
|
||||
}).Schedule(5s, [this](TaskContext context)
|
||||
{
|
||||
DoCastAOE(SPELL_CORRUPTION);
|
||||
context.Repeat(30s, 50s);
|
||||
}).Schedule(15s, [this](TaskContext context)
|
||||
{
|
||||
Talk(SAY_NOVA);
|
||||
ApplyImmunities(false);
|
||||
me->AddAura(SPELL_BURNING_NOVA, me);
|
||||
ApplyImmunities(true);
|
||||
SummonChannelers();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetImmuneToAll(true);
|
||||
if (instance)
|
||||
instance->SetData(DATA_KELIDAN, NOT_STARTED);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_SPELL_VOLLEY, 1000);
|
||||
events.ScheduleEvent(EVENT_SPELL_CORRUPTION, 5000);
|
||||
events.ScheduleEvent(EVENT_SPELL_BURNING_NOVA, 15000);
|
||||
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
Talk(SAY_WAKE);
|
||||
|
||||
if (instance)
|
||||
instance->SetData(DATA_KELIDAN, IN_PROGRESS);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
if (urand(0, 1))
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_CHANNELER_ENGAGED)
|
||||
if (IsHeroic())
|
||||
{
|
||||
if (!addYell)
|
||||
{
|
||||
addYell = true;
|
||||
Talk(SAY_ADD_AGGRO);
|
||||
|
||||
for (uint8 i = 0; i < 5; ++i)
|
||||
{
|
||||
Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]);
|
||||
if (channeler && !channeler->IsInCombat())
|
||||
channeler->SetInCombatWithZone();
|
||||
}
|
||||
}
|
||||
DoCastAOE(SPELL_VORTEX);
|
||||
}
|
||||
else if (param == ACTION_CHANNELER_DIED)
|
||||
scheduler.DelayGroup(0, 6s);
|
||||
scheduler.Schedule(5s, [this](TaskContext /*context*/)
|
||||
{
|
||||
for (uint8 i = 0; i < 5; ++i)
|
||||
{
|
||||
Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]);
|
||||
if (channeler && channeler->IsAlive())
|
||||
return;
|
||||
}
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetImmuneToAll(false);
|
||||
if (Unit* target = me->SelectNearestPlayer(100.0f))
|
||||
AttackStart(target);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckChannelers()
|
||||
{
|
||||
if (addYell)
|
||||
{
|
||||
if (!SelectTargetFromPlayerList(100.0f))
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
|
||||
SummonChannelers();
|
||||
for (uint8 i = 0; i < 5; ++i)
|
||||
{
|
||||
Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]);
|
||||
if (channeler && !channeler->HasUnitState(UNIT_STATE_CASTING) && !channeler->IsInCombat())
|
||||
{
|
||||
Creature* target = ObjectAccessor::GetCreature(*me, channelers[(i + 2) % 5]);
|
||||
if (target)
|
||||
channeler->CastSpell(target, SPELL_CHANNELING, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SummonChannelers()
|
||||
{
|
||||
for (uint8 i = 0; i < 5; ++i)
|
||||
{
|
||||
Creature* channeler = ObjectAccessor::GetCreature(*me, channelers[i]);
|
||||
if (channeler && channeler->isDead())
|
||||
{
|
||||
channeler->DespawnOrUnsummon(1);
|
||||
channeler = nullptr;
|
||||
}
|
||||
if (!channeler)
|
||||
channeler = me->SummonCreature(NPC_CHANNELER, ShadowmoonChannelers[i][0], ShadowmoonChannelers[i][1], ShadowmoonChannelers[i][2], ShadowmoonChannelers[i][3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 300000);
|
||||
|
||||
channelers[i] = channeler ? channeler->GetGUID() : ObjectGuid::Empty;
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DIE);
|
||||
if (instance)
|
||||
{
|
||||
// Xinef: load grid with start doors
|
||||
me->GetMap()->LoadGrid(0, -111.0f);
|
||||
instance->SetData(DATA_KELIDAN, DONE);
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR1), true);
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR6), true);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyImmunities(bool apply)
|
||||
{
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISTRACT, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_KNOCKOUT, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHACKLE, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
checkTimer += diff;
|
||||
if (checkTimer >= 5000)
|
||||
{
|
||||
checkTimer = 0;
|
||||
CheckChannelers();
|
||||
if (!me->HasUnitState(UNIT_STATE_CASTING))
|
||||
me->CastSpell(me, SPELL_EVOCATION, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_VOLLEY:
|
||||
me->CastSpell(me, SPELL_SHADOW_BOLT_VOLLEY, false);
|
||||
events.RepeatEvent(urand(8000, 13000));
|
||||
break;
|
||||
case EVENT_SPELL_CORRUPTION:
|
||||
me->CastSpell(me, SPELL_CORRUPTION, false);
|
||||
events.RepeatEvent(urand(30000, 50000));
|
||||
break;
|
||||
case EVENT_SPELL_BURNING_NOVA:
|
||||
Talk(SAY_NOVA);
|
||||
|
||||
ApplyImmunities(false);
|
||||
me->AddAura(SPELL_BURNING_NOVA, me);
|
||||
ApplyImmunities(true);
|
||||
|
||||
if (IsHeroic())
|
||||
DoTeleportAll(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
|
||||
|
||||
events.DelayEvents(6000, 0);
|
||||
events.RepeatEvent(urand(25000, 32000));
|
||||
events.ScheduleEvent(EVENT_SPELL_FIRE_NOVA, 5000);
|
||||
break;
|
||||
case EVENT_SPELL_FIRE_NOVA:
|
||||
me->CastSpell(me, SPELL_FIRE_NOVA, true);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetBloodFurnaceAI<boss_kelidan_the_breakerAI>(creature);
|
||||
DoCastSelf(SPELL_FIRE_NOVA, true);
|
||||
});
|
||||
context.Repeat(25s, 32s);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
class npc_shadowmoon_channeler : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_shadowmoon_channeler() : CreatureScript("npc_shadowmoon_channeler") {}
|
||||
|
||||
struct npc_shadowmoon_channelerAI : public ScriptedAI
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
npc_shadowmoon_channelerAI(Creature* creature) : ScriptedAI(creature) {}
|
||||
|
||||
EventMap events;
|
||||
|
||||
void Reset() override
|
||||
if (urand(0, 1))
|
||||
{
|
||||
events.Reset();
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
|
||||
Creature* GetKelidan()
|
||||
{
|
||||
if (InstanceScript* instance = me->GetInstanceScript())
|
||||
return instance->GetCreature(DATA_KELIDAN);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
if (Creature* kelidan = GetKelidan())
|
||||
kelidan->AI()->DoAction(ACTION_CHANNELER_ENGAGED);
|
||||
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
events.ScheduleEvent(EVENT_SPELL_SHADOW_BOLT, urand(1500, 3500));
|
||||
events.ScheduleEvent(EVENT_SPELL_MARK, urand(5000, 6500));
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
if (Creature* kelidan = GetKelidan())
|
||||
kelidan->AI()->DoAction(ACTION_CHANNELER_DIED);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_SHADOW_BOLT:
|
||||
me->CastSpell(me->GetVictim(), IsHeroic() ? SPELL_SHADOW_BOLT_H : SPELL_SHADOW_BOLT, false);
|
||||
events.RepeatEvent(urand(6000, 7500));
|
||||
break;
|
||||
case EVENT_SPELL_MARK:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
me->CastSpell(target, SPELL_MARK_OF_SHADOW, false);
|
||||
events.RepeatEvent(urand(16000, 17500));
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetBloodFurnaceAI<npc_shadowmoon_channelerAI>(creature);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_CHANNELER_DIED)
|
||||
{
|
||||
if (me->FindNearestCreature(NPC_SHADOWMOON_CHANNELER, 100.0f))
|
||||
{
|
||||
return;
|
||||
}
|
||||
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
me->SetInCombatWithZone();
|
||||
}
|
||||
|
||||
else if (param == ACTION_CHANNELER_AGGRO)
|
||||
{
|
||||
Talk(SAY_ADD_AGGRO);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DIE);
|
||||
_JustDied();
|
||||
if (instance)
|
||||
{
|
||||
me->GetMap()->LoadGrid(0, -111.0f);
|
||||
instance->SetData(DATA_KELIDAN, DONE);
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR1), true);
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR6), true);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyImmunities(bool apply)
|
||||
{
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_CHARM, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISORIENTED, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DISTRACT, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FEAR, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_ROOT, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SILENCE, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SLEEP, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SNARE, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_STUN, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_FREEZE, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_KNOCKOUT, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_POLYMORPH, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SHACKLE, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_TURN, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_HORROR, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_DAZE, apply);
|
||||
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_SAPPED, apply);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void AddSC_boss_kelidan_the_breaker()
|
||||
{
|
||||
new boss_kelidan_the_breaker();
|
||||
new npc_shadowmoon_channeler();
|
||||
RegisterBloodFurnaceCreatureAI(boss_kelidan_the_breaker);
|
||||
}
|
||||
|
||||
@@ -19,111 +19,87 @@
|
||||
#include "ScriptedCreature.h"
|
||||
#include "blood_furnace.h"
|
||||
|
||||
enum eEnums
|
||||
enum Says
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_KILL = 1,
|
||||
SAY_DIE = 2,
|
||||
|
||||
SPELL_EXPLODING_BREAKER = 30925,
|
||||
SPELL_DOMINATION = 30923,
|
||||
|
||||
EVENT_SPELL_EXPLODING = 1,
|
||||
EVENT_SPELL_DOMINATION = 2
|
||||
SAY_AGGRO = 0,
|
||||
SAY_KILL = 1,
|
||||
SAY_DIE = 2
|
||||
};
|
||||
|
||||
class boss_the_maker : public CreatureScript
|
||||
enum Spells
|
||||
{
|
||||
public:
|
||||
boss_the_maker() : CreatureScript("boss_the_maker")
|
||||
SPELL_EXPLODING_BEAKER = 30925,
|
||||
SPELL_DOMINATION = 30923
|
||||
};
|
||||
|
||||
struct boss_the_maker : public BossAI
|
||||
{
|
||||
boss_the_maker(Creature* creature) : BossAI(creature, DATA_THE_MAKER)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
struct boss_the_makerAI : public ScriptedAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_the_makerAI(Creature* creature) : ScriptedAI(creature)
|
||||
_Reset();
|
||||
if (instance)
|
||||
{
|
||||
instance = creature->GetInstanceScript();
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
EventMap events;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
if (!instance)
|
||||
return;
|
||||
|
||||
instance->SetData(DATA_THE_MAKER, NOT_STARTED);
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), true);
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
events.ScheduleEvent(EVENT_SPELL_EXPLODING, 6000);
|
||||
events.ScheduleEvent(EVENT_SPELL_DOMINATION, 120000);
|
||||
|
||||
if (!instance)
|
||||
return;
|
||||
|
||||
instance->SetData(DATA_THE_MAKER, IN_PROGRESS);
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), false);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER && urand(0, 1))
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DIE);
|
||||
|
||||
if (!instance)
|
||||
return;
|
||||
|
||||
instance->SetData(DATA_THE_MAKER, DONE);
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), true);
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR3), true);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_EXPLODING:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
me->CastSpell(target, SPELL_EXPLODING_BREAKER, false);
|
||||
events.RepeatEvent(urand(7000, 11000));
|
||||
break;
|
||||
case EVENT_SPELL_DOMINATION:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
me->CastSpell(target, SPELL_DOMINATION, false);
|
||||
events.RepeatEvent(120000);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
return GetBloodFurnaceAI<boss_the_makerAI>(creature);
|
||||
Talk(SAY_AGGRO);
|
||||
_JustEngagedWith();
|
||||
instance->SetData(DATA_THE_MAKER, IN_PROGRESS);
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), false);
|
||||
scheduler.Schedule(6s, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_EXPLODING_BEAKER);
|
||||
context.Repeat(7s, 11s);
|
||||
}).Schedule(2min, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_DOMINATION);
|
||||
context.Repeat(2min);
|
||||
});
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER && urand(0, 1))
|
||||
{
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DIE);
|
||||
_JustDied();
|
||||
instance->SetData(DATA_THE_MAKER, DONE);
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR2), true);
|
||||
instance->HandleGameObject(instance->GetGuidData(DATA_DOOR3), true);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_the_maker()
|
||||
{
|
||||
new boss_the_maker();
|
||||
RegisterBloodFurnaceCreatureAI(boss_the_maker);
|
||||
}
|
||||
|
||||
+100
-120
@@ -34,134 +34,114 @@ enum Spells
|
||||
SPELL_SHADOW_BOLT = 30686,
|
||||
SPELL_SUMMON_FIENDISH_HOUND = 30707,
|
||||
SPELL_TREACHEROUS_AURA = 30695,
|
||||
SPELL_DEMONIC_SHIELD = 31901,
|
||||
SPELL_DEMONIC_SHIELD = 31901
|
||||
};
|
||||
|
||||
enum Misc
|
||||
struct boss_omor_the_unscarred : public BossAI
|
||||
{
|
||||
EVENT_SUMMON1 = 1,
|
||||
EVENT_SUMMON2 = 2,
|
||||
EVENT_TREACHEROUS_AURA = 3,
|
||||
EVENT_DEMONIC_SHIELD = 4,
|
||||
EVENT_KILL_TALK = 5
|
||||
};
|
||||
|
||||
class boss_omor_the_unscarred : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_omor_the_unscarred() : CreatureScript("boss_omor_the_unscarred") { }
|
||||
|
||||
struct boss_omor_the_unscarredAI : public BossAI
|
||||
boss_omor_the_unscarred(Creature* creature) : BossAI(creature, DATA_OMOR_THE_UNSCARRED)
|
||||
{
|
||||
boss_omor_the_unscarredAI(Creature* creature) : BossAI(creature, DATA_OMOR_THE_UNSCARRED)
|
||||
SetCombatMovement(false);
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
SetCombatMovement(false);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Talk(SAY_WIPE);
|
||||
BossAI::Reset();
|
||||
_targetGUID.Clear();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
BossAI::JustEngagedWith(who);
|
||||
|
||||
events.ScheduleEvent(EVENT_SUMMON1, 10000);
|
||||
events.ScheduleEvent(EVENT_SUMMON2, 25000);
|
||||
events.ScheduleEvent(EVENT_TREACHEROUS_AURA, 6000);
|
||||
events.ScheduleEvent(EVENT_DEMONIC_SHIELD, 1000);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit*) override
|
||||
{
|
||||
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
|
||||
{
|
||||
Talk(SAY_KILL);
|
||||
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
Talk(SAY_SUMMON);
|
||||
summons.Summon(summon);
|
||||
summon->SetInCombatWithZone();
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
Talk(SAY_DIE);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SUMMON1:
|
||||
Talk(SAY_SUMMON);
|
||||
me->CastSpell(me, SPELL_SUMMON_FIENDISH_HOUND, false);
|
||||
break;
|
||||
case EVENT_SUMMON2:
|
||||
me->CastSpell(me, SPELL_SUMMON_FIENDISH_HOUND, false);
|
||||
events.ScheduleEvent(EVENT_SUMMON2, 15000);
|
||||
break;
|
||||
case EVENT_TREACHEROUS_AURA:
|
||||
if (roll_chance_i(33))
|
||||
Talk(SAY_CURSE);
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
me->CastSpell(target, SPELL_TREACHEROUS_AURA, false);
|
||||
events.ScheduleEvent(EVENT_TREACHEROUS_AURA, urand(12000, 18000));
|
||||
break;
|
||||
case EVENT_DEMONIC_SHIELD:
|
||||
if (me->HealthBelowPct(21))
|
||||
{
|
||||
me->CastSpell(me, SPELL_DEMONIC_SHIELD, false);
|
||||
events.ScheduleEvent(EVENT_DEMONIC_SHIELD, 15000);
|
||||
}
|
||||
else
|
||||
events.ScheduleEvent(EVENT_DEMONIC_SHIELD, 1000);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!me->GetVictim() || !me->isAttackReady())
|
||||
return;
|
||||
|
||||
if (me->IsWithinMeleeRange(me->GetVictim()))
|
||||
{
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
else
|
||||
{
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false);
|
||||
me->resetAttackTimer();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectGuid _targetGUID;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHellfireRampartsAI<boss_omor_the_unscarredAI>(creature);
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Talk(SAY_WIPE);
|
||||
_Reset();
|
||||
_targetGUID.Clear();
|
||||
ScheduleHealthCheckEvent(21, [&]{
|
||||
DoCastSelf(SPELL_DEMONIC_SHIELD);
|
||||
scheduler.Schedule(15s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_DEMONIC_SHIELD);
|
||||
context.Repeat(15s);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
_JustEngagedWith();
|
||||
scheduler.Schedule(6s, [this](TaskContext context)
|
||||
{
|
||||
if (roll_chance_i(33))
|
||||
{
|
||||
Talk(SAY_CURSE);
|
||||
}
|
||||
DoCastRandomTarget(SPELL_TREACHEROUS_AURA);
|
||||
context.Repeat(12s, 18s);
|
||||
}).Schedule(10s, [this](TaskContext /*context*/)
|
||||
{
|
||||
DoCastSelf(SPELL_SUMMON_FIENDISH_HOUND);
|
||||
}).Schedule(25s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_SUMMON_FIENDISH_HOUND);
|
||||
context.Repeat(15s);
|
||||
});
|
||||
}
|
||||
|
||||
void KilledUnit(Unit*) override
|
||||
{
|
||||
if(!_hasSpoken)
|
||||
{
|
||||
_hasSpoken = true;
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
scheduler.Schedule(6s, [this](TaskContext /*context*/)
|
||||
{
|
||||
_hasSpoken = false;
|
||||
});
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
Talk(SAY_SUMMON);
|
||||
summons.Summon(summon);
|
||||
summon->SetInCombatWithZone();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DIE);
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
if (!me->GetVictim() || !me->isAttackReady())
|
||||
return;
|
||||
|
||||
if (me->IsWithinMeleeRange(me->GetVictim()))
|
||||
{
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
else
|
||||
{
|
||||
me->GetMotionMaster()->Clear();
|
||||
DoCastVictim(SPELL_SHADOW_BOLT);
|
||||
me->resetAttackTimer();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ObjectGuid _targetGUID;
|
||||
bool _hasSpoken;
|
||||
};
|
||||
|
||||
void AddSC_boss_omor_the_unscarred()
|
||||
{
|
||||
new boss_omor_the_unscarred();
|
||||
RegisterHellfireRampartsCreatureAI(boss_omor_the_unscarred);
|
||||
}
|
||||
|
||||
+275
-325
@@ -21,40 +21,35 @@
|
||||
|
||||
enum Says
|
||||
{
|
||||
SAY_INTRO = 0,
|
||||
SAY_WIPE = 0,
|
||||
SAY_AGGRO = 1,
|
||||
SAY_KILL = 2,
|
||||
SAY_DIE = 3,
|
||||
EMOTE_NAZAN = 0
|
||||
SAY_INTRO = 0,
|
||||
SAY_WIPE = 0,
|
||||
SAY_AGGRO = 1,
|
||||
SAY_KILL = 2,
|
||||
SAY_DIE = 3,
|
||||
EMOTE_NAZAN = 0
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_FIREBALL = 33793,
|
||||
SPELL_SUMMON_LIQUID_FIRE = 31706,
|
||||
SPELL_REVENGE = 19130,
|
||||
SPELL_REVENGE_H = 40392,
|
||||
SPELL_CALL_NAZAN = 30693,
|
||||
SPELL_BELLOWING_ROAR = 39427,
|
||||
SPELL_CONE_OF_FIRE = 30926
|
||||
SPELL_FIREBALL = 33793,
|
||||
SPELL_SUMMON_LIQUID_FIRE = 31706,
|
||||
SPELL_REVENGE = 19130,
|
||||
SPELL_CALL_NAZAN = 30693,
|
||||
SPELL_BELLOWING_ROAR = 39427,
|
||||
SPELL_CONE_OF_FIRE = 30926
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
ACTION_FLY_DOWN = 0,
|
||||
ACTION_FLY_DOWN = 0,
|
||||
POINT_MIDDLE = 0,
|
||||
POINT_FLIGHT = 1
|
||||
};
|
||||
|
||||
POINT_MIDDLE = 0,
|
||||
POINT_FLIGHT = 1,
|
||||
|
||||
EVENT_SPELL_REVENGE = 1,
|
||||
EVENT_KILL_TALK = 2,
|
||||
EVENT_AGGRO_TALK = 3,
|
||||
EVENT_SPELL_FIREBALL = 4,
|
||||
EVENT_SPELL_CONE_OF_FIRE = 5,
|
||||
EVENT_SPELL_BELLOWING_ROAR = 6,
|
||||
EVENT_CHANGE_POS = 7,
|
||||
EVENT_RESTORE_COMBAT = 8
|
||||
enum GroupPhase
|
||||
{
|
||||
GROUP_PHASE_1 = 0,
|
||||
GROUP_PHASE_2 = 1
|
||||
};
|
||||
|
||||
const Position NazanPos[3] =
|
||||
@@ -64,347 +59,302 @@ const Position NazanPos[3] =
|
||||
{-1373.84f, 1771.57f, 111.0f, 0.0f}
|
||||
};
|
||||
|
||||
class boss_vazruden_the_herald : public CreatureScript
|
||||
struct boss_vazruden_the_herald : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_vazruden_the_herald() : CreatureScript("boss_vazruden_the_herald") { }
|
||||
boss_vazruden_the_herald(Creature* creature) : BossAI(creature, DATA_VAZRUDEN) {}
|
||||
|
||||
struct boss_vazruden_the_heraldAI : public BossAI
|
||||
void Reset() override
|
||||
{
|
||||
boss_vazruden_the_heraldAI(Creature* creature) : BossAI(creature, DATA_VAZRUDEN)
|
||||
{
|
||||
}
|
||||
BossAI::Reset();
|
||||
me->SetVisible(true);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SummonCreature(NPC_HELLFIRE_SENTRY, -1372.56f, 1724.31f, 82.967f, 5.3058f);
|
||||
me->SummonCreature(NPC_HELLFIRE_SENTRY, -1383.39f, 1711.82f, 82.7961f, 5.67232f);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
void AttackStart(Unit*) override {}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
if (summon->GetEntry() != NPC_HELLFIRE_SENTRY)
|
||||
{
|
||||
BossAI::Reset();
|
||||
me->SetVisible(true);
|
||||
summon->SetInCombatWithZone();
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit*) override
|
||||
{
|
||||
instance->SetBossState(DATA_VAZRUDEN, DONE);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE && id == POINT_MIDDLE)
|
||||
{
|
||||
me->SetVisible(false);
|
||||
me->SummonCreature(NPC_VAZRUDEN, me->GetPositionX(), me->GetPositionY(), 81.2f, 5.46f);
|
||||
me->SummonCreature(NPC_NAZAN, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 5.46f);
|
||||
}
|
||||
}
|
||||
|
||||
void SummonedCreatureDies(Creature* summon, Unit*) override
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
if (summon->GetEntry() == NPC_HELLFIRE_SENTRY && summons.size() == 0)
|
||||
{
|
||||
Talk(SAY_INTRO);
|
||||
me->GetMotionMaster()->MovePoint(POINT_MIDDLE, -1406.5f, 1746.5f, 85.0f, false);
|
||||
me->setActive(true);
|
||||
}
|
||||
else if (summons.size() == 0)
|
||||
{
|
||||
me->KillSelf();
|
||||
}
|
||||
}
|
||||
|
||||
void SummonedCreatureDespawn(Creature* summon) override
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
if (summon->GetEntry() != NPC_HELLFIRE_SENTRY)
|
||||
{
|
||||
BossAI::EnterEvadeMode();
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data) override
|
||||
{
|
||||
if (type == 0 && data == 1)
|
||||
{
|
||||
summons.DoZoneInCombat(NPC_HELLFIRE_SENTRY);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 /*diff*/) override
|
||||
{
|
||||
if (!me->IsVisible() && summons.size() == 0)
|
||||
{
|
||||
BossAI::EnterEvadeMode();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct boss_nazan : public BossAI
|
||||
{
|
||||
boss_nazan(Creature* creature) : BossAI(creature, DATA_VAZRUDEN)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->SetCanFly(true);
|
||||
me->SetDisableGravity(true);
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
{
|
||||
me->DespawnOrUnsummon(1);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit*) override
|
||||
{
|
||||
scheduler.CancelGroup(GROUP_PHASE_2);
|
||||
scheduler.Schedule(5ms, GROUP_PHASE_1, [this](TaskContext context)
|
||||
{
|
||||
me->GetMotionMaster()->MovePoint(POINT_FLIGHT, NazanPos[urand(0, 2)], false);
|
||||
scheduler.DelayAll(7s);
|
||||
context.Repeat(30s);
|
||||
}).Schedule(5s, GROUP_PHASE_1, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_FIREBALL);
|
||||
context.Repeat(4s, 6s);
|
||||
});
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (me->IsLevitating())
|
||||
{
|
||||
me->Attack(who, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptedAI::AttackStart(who);
|
||||
}
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_FLY_DOWN)
|
||||
{
|
||||
Talk(EMOTE_NAZAN);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SummonCreature(NPC_HELLFIRE_SENTRY, -1372.56f, 1724.31f, 82.967f, 5.3058f);
|
||||
me->SummonCreature(NPC_HELLFIRE_SENTRY, -1383.39f, 1711.82f, 82.7961f, 5.67232f);
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
me->GetMotionMaster()->MovePoint(POINT_MIDDLE, -1406.5f, 1746.5f, 81.2f, false);
|
||||
}
|
||||
|
||||
void AttackStart(Unit*) override
|
||||
{
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
if (summon->GetEntry() != NPC_HELLFIRE_SENTRY)
|
||||
summon->SetInCombatWithZone();
|
||||
}
|
||||
|
||||
void JustDied(Unit*) override
|
||||
{
|
||||
instance->SetBossState(DATA_VAZRUDEN, DONE);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE && id == POINT_MIDDLE)
|
||||
{
|
||||
me->SetVisible(false);
|
||||
me->SummonCreature(NPC_VAZRUDEN, me->GetPositionX(), me->GetPositionY(), 81.2f, 5.46f);
|
||||
me->SummonCreature(NPC_NAZAN, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 5.46f);
|
||||
}
|
||||
}
|
||||
|
||||
void SummonedCreatureDies(Creature* summon, Unit*) override
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
if (summon->GetEntry() == NPC_HELLFIRE_SENTRY && summons.size() == 0)
|
||||
{
|
||||
Talk(SAY_INTRO);
|
||||
me->GetMotionMaster()->MovePoint(POINT_MIDDLE, -1406.5f, 1746.5f, 85.0f, false);
|
||||
me->setActive(true);
|
||||
}
|
||||
else if (summons.size() == 0)
|
||||
{
|
||||
me->KillSelf();
|
||||
}
|
||||
}
|
||||
|
||||
void SummonedCreatureDespawn(Creature* summon) override
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
if (summon->GetEntry() != NPC_HELLFIRE_SENTRY)
|
||||
BossAI::EnterEvadeMode();
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data) override
|
||||
{
|
||||
if (type == 0 && data == 1)
|
||||
{
|
||||
summons.DoZoneInCombat(NPC_HELLFIRE_SENTRY);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 /*diff*/) override
|
||||
{
|
||||
if (!me->IsVisible() && summons.size() == 0)
|
||||
BossAI::EnterEvadeMode();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHellfireRampartsAI<boss_vazruden_the_heraldAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class boss_nazan : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_nazan() : CreatureScript("boss_nazan") { }
|
||||
|
||||
struct boss_nazanAI : public ScriptedAI
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
boss_nazanAI(Creature* creature) : ScriptedAI(creature)
|
||||
if (type == POINT_MOTION_TYPE && id == POINT_MIDDLE)
|
||||
{
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->SetCanFly(true);
|
||||
me->SetDisableGravity(true);
|
||||
events.Reset();
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
{
|
||||
me->DespawnOrUnsummon(1);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit*) override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_CHANGE_POS, 0);
|
||||
events.ScheduleEvent(EVENT_SPELL_FIREBALL, 5000);
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (me->IsLevitating())
|
||||
me->Attack(who, true);
|
||||
else
|
||||
ScriptedAI::AttackStart(who);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == ACTION_FLY_DOWN)
|
||||
me->SetCanFly(false);
|
||||
me->SetDisableGravity(false);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
scheduler.CancelGroup(GROUP_PHASE_1);
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
scheduler.Schedule(5s, GROUP_PHASE_2, [this](TaskContext context)
|
||||
{
|
||||
Talk(EMOTE_NAZAN);
|
||||
events.Reset();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->InterruptNonMeleeSpells(true);
|
||||
me->GetMotionMaster()->MovePoint(POINT_MIDDLE, -1406.5f, 1746.5f, 81.2f, false);
|
||||
DoCastVictim(SPELL_CONE_OF_FIRE);
|
||||
context.Repeat(12s);
|
||||
}).Schedule(6s, GROUP_PHASE_2, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_FIREBALL);
|
||||
context.Repeat(4s, 6s);
|
||||
});
|
||||
if (IsHeroic())
|
||||
{
|
||||
scheduler.Schedule(10s, GROUP_PHASE_2, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_BELLOWING_ROAR);
|
||||
context.Repeat(30s);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == POINT_MOTION_TYPE && id == POINT_MIDDLE)
|
||||
{
|
||||
me->SetCanFly(false);
|
||||
me->SetDisableGravity(false);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
events.ScheduleEvent(EVENT_RESTORE_COMBAT, 1);
|
||||
events.ScheduleEvent(EVENT_SPELL_CONE_OF_FIRE, 5000);
|
||||
events.ScheduleEvent(EVENT_SPELL_FIREBALL, 6000);
|
||||
if (IsHeroic())
|
||||
events.ScheduleEvent(EVENT_SPELL_BELLOWING_ROAR, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_FIREBALL:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
me->CastSpell(target, SPELL_FIREBALL, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_FIREBALL, urand(4000, 6000));
|
||||
break;
|
||||
case EVENT_CHANGE_POS:
|
||||
me->GetMotionMaster()->MovePoint(POINT_FLIGHT, NazanPos[urand(0, 2)], false);
|
||||
events.DelayEvents(7000);
|
||||
events.ScheduleEvent(EVENT_CHANGE_POS, 30000);
|
||||
break;
|
||||
case EVENT_RESTORE_COMBAT:
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
break;
|
||||
case EVENT_SPELL_CONE_OF_FIRE:
|
||||
me->CastSpell(me->GetVictim(), SPELL_CONE_OF_FIRE, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_CONE_OF_FIRE, 12000);
|
||||
break;
|
||||
case EVENT_SPELL_BELLOWING_ROAR:
|
||||
me->CastSpell(me, SPELL_BELLOWING_ROAR, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_BELLOWING_ROAR, 30000);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!me->IsLevitating())
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap events;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHellfireRampartsAI<boss_nazanAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class boss_vazruden : public CreatureScript
|
||||
{
|
||||
public:
|
||||
boss_vazruden() : CreatureScript("boss_vazruden") { }
|
||||
|
||||
struct boss_vazrudenAI : public ScriptedAI
|
||||
void UpdateAI(uint32 /*diff*/) override
|
||||
{
|
||||
boss_vazrudenAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
events.Reset();
|
||||
_nazanCalled = false;
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
{
|
||||
Talk(SAY_WIPE);
|
||||
me->DespawnOrUnsummon(1);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit*) override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_AGGRO_TALK, 5000);
|
||||
events.ScheduleEvent(EVENT_SPELL_REVENGE, 4000);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit*) override
|
||||
{
|
||||
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
|
||||
{
|
||||
Talk(SAY_KILL);
|
||||
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
|
||||
}
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
|
||||
{
|
||||
if (!_nazanCalled && me->HealthBelowPctDamaged(35, damage))
|
||||
{
|
||||
_nazanCalled = true;
|
||||
me->CastSpell(me, SPELL_CALL_NAZAN, true);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit*) override
|
||||
{
|
||||
Talk(SAY_DIE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_AGGRO_TALK:
|
||||
Talk(SAY_AGGRO);
|
||||
break;
|
||||
case EVENT_SPELL_REVENGE:
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_REVENGE, SPELL_REVENGE_H), false);
|
||||
events.ScheduleEvent(EVENT_SPELL_REVENGE, 6000);
|
||||
break;
|
||||
}
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
if (!me->IsLevitating())
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
EventMap events;
|
||||
bool _nazanCalled;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHellfireRampartsAI<boss_vazrudenAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_vazruden_fireball : public SpellScriptLoader
|
||||
struct boss_vazruden : public BossAI
|
||||
{
|
||||
public:
|
||||
spell_vazruden_fireball() : SpellScriptLoader("spell_vazruden_fireball") { }
|
||||
|
||||
class spell_vazruden_fireball_SpellScript : public SpellScript
|
||||
boss_vazruden(Creature* creature) : BossAI(creature, DATA_VAZRUDEN)
|
||||
{
|
||||
PrepareSpellScript(spell_vazruden_fireball_SpellScript);
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
if (Unit* target = GetHitUnit())
|
||||
target->CastSpell(target, SPELL_SUMMON_LIQUID_FIRE, true);
|
||||
}
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_vazruden_fireball_SpellScript::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
void Reset() override
|
||||
{
|
||||
return new spell_vazruden_fireball_SpellScript();
|
||||
_nazanCalled = false;
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override
|
||||
{
|
||||
Talk(SAY_WIPE);
|
||||
me->DespawnOrUnsummon(1);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit*) override
|
||||
{
|
||||
scheduler.Schedule(5s, [this](TaskContext /*context*/)
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
}).Schedule(4s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_REVENGE);
|
||||
context.Repeat(6s);
|
||||
});
|
||||
}
|
||||
|
||||
void KilledUnit(Unit*) override
|
||||
{
|
||||
if (!_hasSpoken)
|
||||
{
|
||||
_hasSpoken = true;
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
scheduler.Schedule(6s, [this](TaskContext /*context*/)
|
||||
{
|
||||
_hasSpoken = false;
|
||||
});
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*type*/, SpellSchoolMask /*school*/) override
|
||||
{
|
||||
if (!_nazanCalled && me->HealthBelowPctDamaged(35, damage))
|
||||
{
|
||||
_nazanCalled = true;
|
||||
DoCastSelf(SPELL_CALL_NAZAN, true);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit*) override
|
||||
{
|
||||
Talk(SAY_DIE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff);
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
bool _hasSpoken;
|
||||
bool _nazanCalled;
|
||||
};
|
||||
|
||||
class spell_vazruden_fireball : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_vazruden_fireball);
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* target = GetHitUnit())
|
||||
{
|
||||
target->CastSpell(target, SPELL_SUMMON_LIQUID_FIRE, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_vazruden_fireball::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_vazruden_call_nazan : public SpellScriptLoader
|
||||
class spell_vazruden_call_nazan : public SpellScript
|
||||
{
|
||||
public:
|
||||
spell_vazruden_call_nazan() : SpellScriptLoader("spell_vazruden_call_nazan") { }
|
||||
PrepareSpellScript(spell_vazruden_call_nazan);
|
||||
|
||||
class spell_vazruden_call_nazan_SpellScript : public SpellScript
|
||||
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
PrepareSpellScript(spell_vazruden_call_nazan_SpellScript);
|
||||
|
||||
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
|
||||
if (Unit* target = GetHitUnit())
|
||||
{
|
||||
if (Unit* target = GetHitUnit())
|
||||
target->GetAI()->DoAction(ACTION_FLY_DOWN);
|
||||
target->GetAI()->DoAction(ACTION_FLY_DOWN);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_vazruden_call_nazan_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
void Register() override
|
||||
{
|
||||
return new spell_vazruden_call_nazan_SpellScript();
|
||||
OnEffectHitTarget += SpellEffectFn(spell_vazruden_call_nazan::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_vazruden_the_herald()
|
||||
{
|
||||
new boss_vazruden_the_herald();
|
||||
new boss_vazruden();
|
||||
new boss_nazan();
|
||||
new spell_vazruden_fireball();
|
||||
new spell_vazruden_call_nazan();
|
||||
RegisterHellfireRampartsCreatureAI(boss_vazruden_the_herald);
|
||||
RegisterHellfireRampartsCreatureAI(boss_vazruden);
|
||||
RegisterHellfireRampartsCreatureAI(boss_nazan);
|
||||
RegisterSpellScript(spell_vazruden_fireball);
|
||||
RegisterSpellScript(spell_vazruden_call_nazan);
|
||||
}
|
||||
|
||||
+99
-115
@@ -38,129 +38,113 @@ enum Spells
|
||||
|
||||
enum Misc
|
||||
{
|
||||
NPC_HELLFIRE_WATCHER = 17309,
|
||||
|
||||
EVENT_MORTAL_WOUND = 1,
|
||||
EVENT_SURGE = 2,
|
||||
EVENT_RETALIATION = 3,
|
||||
EVENT_KILL_TALK = 4,
|
||||
EVENT_CHECK_HEALTH = 5
|
||||
NPC_HELLFIRE_WATCHER = 17309
|
||||
};
|
||||
|
||||
class boss_watchkeeper_gargolmar : public CreatureScript
|
||||
struct boss_watchkeeper_gargolmar : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_watchkeeper_gargolmar() : CreatureScript("boss_watchkeeper_gargolmar") { }
|
||||
|
||||
struct boss_watchkeeper_gargolmarAI : public BossAI
|
||||
boss_watchkeeper_gargolmar(Creature* creature) : BossAI(creature, DATA_WATCHKEEPER_GARGOLMAR)
|
||||
{
|
||||
boss_watchkeeper_gargolmarAI(Creature* creature) : BossAI(creature, DATA_WATCHKEEPER_GARGOLMAR)
|
||||
_taunted = false;
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
_taunted = false;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
BossAI::JustEngagedWith(who);
|
||||
events.ScheduleEvent(EVENT_MORTAL_WOUND, 5000);
|
||||
events.ScheduleEvent(EVENT_SURGE, 3000);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
events.ScheduleEvent(EVENT_RETALIATION, 1000);
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
if (!_taunted)
|
||||
{
|
||||
if (who->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
_taunted = true;
|
||||
Talk(SAY_TAUNT);
|
||||
}
|
||||
}
|
||||
|
||||
BossAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit*) override
|
||||
{
|
||||
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
|
||||
{
|
||||
Talk(SAY_KILL);
|
||||
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
Talk(SAY_DIE);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_MORTAL_WOUND:
|
||||
me->CastSpell(me->GetVictim(), SPELL_MORTAL_WOUND, false);
|
||||
events.ScheduleEvent(EVENT_MORTAL_WOUND, 8000);
|
||||
break;
|
||||
case EVENT_SURGE:
|
||||
Talk(SAY_SURGE);
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0))
|
||||
me->CastSpell(target, SPELL_SURGE, false);
|
||||
events.ScheduleEvent(EVENT_SURGE, 11000);
|
||||
break;
|
||||
case EVENT_RETALIATION:
|
||||
if (me->HealthBelowPct(20))
|
||||
{
|
||||
me->CastSpell(me, SPELL_RETALIATION, false);
|
||||
events.ScheduleEvent(EVENT_RETALIATION, 30000);
|
||||
}
|
||||
else
|
||||
events.ScheduleEvent(EVENT_RETALIATION, 500);
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH:
|
||||
if (me->HealthBelowPct(50))
|
||||
{
|
||||
Talk(SAY_HEAL);
|
||||
std::list<Creature*> clist;
|
||||
me->GetCreaturesWithEntryInRange(clist, 100.0f, NPC_HELLFIRE_WATCHER);
|
||||
for (std::list<Creature*>::const_iterator itr = clist.begin(); itr != clist.end(); ++itr)
|
||||
(*itr)->AI()->SetData(NPC_HELLFIRE_WATCHER, 0);
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 500);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
bool _taunted;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetHellfireRampartsAI<boss_watchkeeper_gargolmarAI>(creature);
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
ScheduleHealthCheckEvent(50, [&]{
|
||||
Talk(SAY_HEAL);
|
||||
std::list<Creature*> clist;
|
||||
me->GetCreaturesWithEntryInRange(clist, 100.0f, NPC_HELLFIRE_WATCHER);
|
||||
for (std::list<Creature*>::const_iterator itr = clist.begin(); itr != clist.end(); ++itr)
|
||||
{
|
||||
(*itr)->AI()->SetData(NPC_HELLFIRE_WATCHER, 0);
|
||||
}
|
||||
});
|
||||
|
||||
ScheduleHealthCheckEvent(20, [&]{
|
||||
DoCastSelf(SPELL_RETALIATION);
|
||||
scheduler.Schedule(30s, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_RETALIATION);
|
||||
context.Repeat(30s);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
_JustEngagedWith();
|
||||
scheduler.Schedule(5s, [this] (TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_MORTAL_WOUND);
|
||||
context.Repeat(8s);
|
||||
}).Schedule(3s, [this](TaskContext context)
|
||||
{
|
||||
Talk(SAY_SURGE);
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::MinDistance, 0))
|
||||
{
|
||||
me->CastSpell(target, SPELL_SURGE);
|
||||
}
|
||||
context.Repeat(11s);
|
||||
});
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
if (!_taunted)
|
||||
{
|
||||
if (who->GetTypeId() == TYPEID_PLAYER)
|
||||
{
|
||||
_taunted = true;
|
||||
Talk(SAY_TAUNT);
|
||||
}
|
||||
}
|
||||
BossAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit*) override
|
||||
{
|
||||
if (!_hasSpoken)
|
||||
{
|
||||
_hasSpoken = true;
|
||||
Talk(SAY_KILL);
|
||||
}
|
||||
scheduler.Schedule(6s, [this](TaskContext /*context*/)
|
||||
{
|
||||
_hasSpoken = false;
|
||||
});
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DIE);
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
bool _taunted;
|
||||
bool _hasSpoken;
|
||||
|
||||
};
|
||||
|
||||
void AddSC_boss_watchkeeper_gargolmar()
|
||||
{
|
||||
new boss_watchkeeper_gargolmar();
|
||||
RegisterHellfireRampartsCreatureAI(boss_watchkeeper_gargolmar);
|
||||
}
|
||||
|
||||
@@ -52,4 +52,6 @@ inline AI* GetHellfireRampartsAI(T* obj)
|
||||
return GetInstanceAI<AI>(obj, HellfireRampartsScriptName);
|
||||
}
|
||||
|
||||
#define RegisterHellfireRampartsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetHellfireRampartsAI)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,292 +20,295 @@
|
||||
#include "ScriptedCreature.h"
|
||||
#include "shattered_halls.h"
|
||||
|
||||
enum eGrandWarlockNethekurse
|
||||
enum Texts
|
||||
{
|
||||
SAY_INTRO = 0,
|
||||
SAY_PEON_ATTACKED = 1,
|
||||
SAY_PEON_DIES = 2,
|
||||
SAY_TAUNT = 3,
|
||||
SAY_AGGRO = 4,
|
||||
SAY_SLAY = 5,
|
||||
SAY_DIE = 6,
|
||||
SAY_SKIP_INTRO = 0,
|
||||
SAY_INTRO_2 = 1,
|
||||
SAY_PEON_ATTACKED = 2,
|
||||
SAY_PEON_DIES = 3,
|
||||
SAY_SHADOW_SEAR = 4,
|
||||
SAY_SHADOW_FISSURE = 5,
|
||||
SAY_DEATH_COIL = 6,
|
||||
SAY_SLAY = 7,
|
||||
SAY_DIE = 8
|
||||
};
|
||||
|
||||
SPELL_DEATH_COIL_N = 30500,
|
||||
SPELL_DEATH_COIL_H = 35954,
|
||||
SPELL_DARK_SPIN = 30502,
|
||||
SPELL_SHADOW_FISSURE = 30496,
|
||||
SPELL_SHADOW_CLEAVE_N = 30495,
|
||||
SPELL_SHADOW_SLAM_H = 35953,
|
||||
enum Spells
|
||||
{
|
||||
SPELL_DEATH_COIL = 30500,
|
||||
SPELL_DARK_SPIN = 30502,
|
||||
SPELL_SHADOW_FISSURE = 30496,
|
||||
SPELL_SHADOW_CLEAVE = 30495,
|
||||
|
||||
// Spells used exclusively in RP
|
||||
SPELL_SHADOW_SEAR = 30735,
|
||||
SPELL_DEATH_COIL = 30741,
|
||||
SPELL_SHADOW_SEAR = 30735,
|
||||
SPELL_DEATH_COIL_RP = 30741,
|
||||
SPELL_SHADOW_FISSURE_RP = 30745,
|
||||
SPELL_LESSER_SHADOW_FISSURE = 30744
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_INTRO = 1,
|
||||
EVENT_SPELL_DEATH_COIL = 2,
|
||||
EVENT_SPELL_SHADOW_FISSURE = 3,
|
||||
EVENT_SPELL_CLEAVE = 4,
|
||||
EVENT_CHECK_HEALTH = 5,
|
||||
EVENT_START_ATTACK = 6,
|
||||
EVENT_START_ATTACK = 2,
|
||||
|
||||
EVENT_STAGE_NONE = 0,
|
||||
EVENT_STAGE_INTRO = 1,
|
||||
EVENT_STAGE_TAUNT = 2,
|
||||
EVENT_STAGE_MAIN = 3,
|
||||
EVENT_STAGE_MAIN = 3
|
||||
};
|
||||
|
||||
enum Data
|
||||
{
|
||||
SETDATA_DATA = 1,
|
||||
SETDATA_PEON_AGGRO = 1,
|
||||
SETDATA_PEON_DEATH = 2
|
||||
};
|
||||
|
||||
// ########################################################
|
||||
// Grand Warlock Nethekurse
|
||||
// ########################################################
|
||||
|
||||
class boss_grand_warlock_nethekurse : public CreatureScript
|
||||
enum Groups
|
||||
{
|
||||
public:
|
||||
boss_grand_warlock_nethekurse() : CreatureScript("boss_grand_warlock_nethekurse") { }
|
||||
GROUP_RP = 0
|
||||
};
|
||||
|
||||
struct boss_grand_warlock_nethekurseAI : public BossAI
|
||||
enum Actions
|
||||
{
|
||||
ACTION_START_INTRO = 0,
|
||||
ACTION_CANCEL_INTRO = 1,
|
||||
ACTION_START_COMBAT = 2,
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
{
|
||||
NPC_PEON = 17083
|
||||
};
|
||||
|
||||
struct PeonRoleplay
|
||||
{
|
||||
uint32 spellId;
|
||||
uint8 textId;
|
||||
};
|
||||
|
||||
PeonRoleplay PeonRoleplayData[3] =
|
||||
{
|
||||
{ SPELL_DEATH_COIL_RP, SAY_DEATH_COIL },
|
||||
{ SPELL_SHADOW_FISSURE_RP, SAY_SHADOW_FISSURE },
|
||||
{ SPELL_SHADOW_SEAR, SAY_SHADOW_SEAR }
|
||||
};
|
||||
|
||||
struct boss_grand_warlock_nethekurse : public BossAI
|
||||
{
|
||||
boss_grand_warlock_nethekurse(Creature* creature) : BossAI(creature, DATA_NETHEKURSE)
|
||||
{
|
||||
boss_grand_warlock_nethekurseAI(Creature* creature) : BossAI(creature, DATA_NETHEKURSE) { }
|
||||
|
||||
EventMap events2;
|
||||
void Reset() override
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
EventStage = EVENT_STAGE_NONE;
|
||||
_Reset();
|
||||
events2.Reset();
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
ScheduleHealthCheckEvent(25, [&] {
|
||||
DoCastSelf(SPELL_DARK_SPIN);
|
||||
});
|
||||
|
||||
instance->SetBossState(DATA_NETHEKURSE, NOT_STARTED);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Talk(SAY_DIE);
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void SetData(uint32 data, uint32 value) override
|
||||
{
|
||||
if (data != SETDATA_DATA)
|
||||
return;
|
||||
|
||||
if (value == SETDATA_PEON_AGGRO && PeonEngagedCount <= 4)
|
||||
{
|
||||
Talk(SAY_PEON_ATTACKED);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
else if (value == SETDATA_PEON_DEATH && PeonKilledCount <= 4)
|
||||
{
|
||||
Talk(SAY_DIE);
|
||||
_JustDied();
|
||||
}
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
me->SetFacingTo(4.572762489318847656f);
|
||||
|
||||
void SetData(uint32 data, uint32 value) override
|
||||
{
|
||||
if (data != SETDATA_DATA)
|
||||
return;
|
||||
|
||||
switch (value)
|
||||
scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext /*context*/)
|
||||
{
|
||||
case SETDATA_PEON_AGGRO:
|
||||
if (PeonEngagedCount >= 4)
|
||||
return;
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_APPLAUD);
|
||||
me->GetMotionMaster()->Initialize();
|
||||
Talk(SAY_PEON_DIES);
|
||||
|
||||
if (EventStage < EVENT_STAGE_TAUNT)
|
||||
Talk(SAY_PEON_ATTACKED);
|
||||
break;
|
||||
case SETDATA_PEON_DEATH:
|
||||
if (PeonKilledCount >= 4)
|
||||
return;
|
||||
|
||||
if (EventStage < EVENT_STAGE_TAUNT)
|
||||
Talk(SAY_PEON_DIES);
|
||||
|
||||
if (++PeonKilledCount == 4)
|
||||
events2.ScheduleEvent(EVENT_START_ATTACK, 5000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AttackStart(Unit* who) override
|
||||
{
|
||||
if (EventStage < EVENT_STAGE_MAIN)
|
||||
return;
|
||||
|
||||
if (me->Attack(who, true))
|
||||
{
|
||||
DoStartMovement(who);
|
||||
}
|
||||
}
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override
|
||||
{
|
||||
if (me->IsWithinDistInMap(who, 30.0f))
|
||||
{
|
||||
if (who->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
if (EventStage == EVENT_STAGE_NONE && PeonKilledCount < 4)
|
||||
if (++PeonKilledCount == 4)
|
||||
{
|
||||
events2.ScheduleEvent(EVENT_INTRO, 90000);
|
||||
Talk(SAY_INTRO);
|
||||
EventStage = EVENT_STAGE_INTRO;
|
||||
instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS);
|
||||
me->SetInCombatWithZone();
|
||||
}
|
||||
else if (PeonKilledCount >= 4)
|
||||
{
|
||||
events2.ScheduleEvent(EVENT_START_ATTACK, 1000);
|
||||
instance->SetBossState(DATA_NETHEKURSE, IN_PROGRESS);
|
||||
me->SetInCombatWithZone();
|
||||
}
|
||||
}
|
||||
|
||||
if (EventStage < EVENT_STAGE_MAIN)
|
||||
return;
|
||||
|
||||
ScriptedAI::MoveInLineOfSight(who);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events2.Update(diff);
|
||||
uint32 eventId = events2.ExecuteEvent();
|
||||
|
||||
if (EventStage < EVENT_STAGE_MAIN && instance->GetBossState(DATA_NETHEKURSE) == IN_PROGRESS)
|
||||
{
|
||||
if (eventId == EVENT_INTRO)
|
||||
{
|
||||
Talk(SAY_TAUNT);
|
||||
EventStage = EVENT_STAGE_TAUNT;
|
||||
me->CastSpell(me, SPELL_SHADOW_SEAR, false);
|
||||
}
|
||||
else if (eventId == EVENT_START_ATTACK)
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
EventStage = EVENT_STAGE_MAIN;
|
||||
if (Unit* target = me->SelectNearestPlayer(50.0f))
|
||||
Talk(SAY_INTRO_2);
|
||||
DoAction(ACTION_CANCEL_INTRO);
|
||||
if (Unit* target = me->SelectNearestPlayer(80.0f))
|
||||
{
|
||||
AttackStart(target);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
events.ScheduleEvent(EVENT_SPELL_DEATH_COIL, 20000);
|
||||
events.ScheduleEvent(EVENT_SPELL_SHADOW_FISSURE, 8000);
|
||||
events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
return;
|
||||
void IntroRP()
|
||||
{
|
||||
scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext context)
|
||||
{
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
me->SetFacingTo(4.572762489318847656f);
|
||||
|
||||
scheduler.Schedule(500ms, GROUP_RP, [this](TaskContext /*context*/)
|
||||
{
|
||||
scheduler.Schedule(2500ms, GROUP_RP, [this](TaskContext /*context*/)
|
||||
{
|
||||
PeonRoleplay roleplayData = Acore::Containers::SelectRandomContainerElement(PeonRoleplayData);
|
||||
DoCast(me, roleplayData.spellId);
|
||||
Talk(roleplayData.textId);
|
||||
me->GetMotionMaster()->Initialize();
|
||||
});
|
||||
});
|
||||
context.Repeat(16400ms, 28500ms);
|
||||
});
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
if (who->GetEntry() == NPC_PEON)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_JustEngagedWith();
|
||||
DoAction(ACTION_CANCEL_INTRO);
|
||||
|
||||
scheduler.CancelAll();
|
||||
|
||||
scheduler.Schedule(12150ms, 19850ms, [this](TaskContext context)
|
||||
{
|
||||
if (me->HealthBelowPct(90))
|
||||
{
|
||||
DoCastRandomTarget(SPELL_DEATH_COIL, 0, 30.0f, true);
|
||||
}
|
||||
context.Repeat();
|
||||
}).Schedule(8100ms, 17300ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastRandomTarget(SPELL_SHADOW_FISSURE, 0, 60.0f, true);
|
||||
context.Repeat(8450ms, 9450ms);
|
||||
}).Schedule(10950ms, 21850ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_SHADOW_CLEAVE);
|
||||
context.Repeat(1200ms, 23900ms);
|
||||
});
|
||||
|
||||
if (PeonKilledCount < 4)
|
||||
{
|
||||
Talk(SAY_SKIP_INTRO);
|
||||
}
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_CANCEL_INTRO)
|
||||
{
|
||||
scheduler.CancelGroup(GROUP_RP);
|
||||
me->SetInCombatWithZone();
|
||||
return;
|
||||
}
|
||||
else if (action == ACTION_START_INTRO)
|
||||
{
|
||||
IntroRP();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
scheduler.Update(diff);
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
if (!me->HealthBelowPct(25))
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
uint8 PeonEngagedCount = 0;
|
||||
uint8 PeonKilledCount = 0;
|
||||
};
|
||||
|
||||
class spell_tsh_shadow_bolt : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_tsh_shadow_bolt);
|
||||
|
||||
void SelectRandomPlayer(WorldObject*& target)
|
||||
{
|
||||
if (Creature* caster = GetCaster()->ToCreature())
|
||||
{
|
||||
if (Unit* randomTarget = caster->AI()->SelectTarget(SelectTargetMethod::Random, 0, 100.0f))
|
||||
{
|
||||
target = randomTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_tsh_shadow_bolt::SelectRandomPlayer, EFFECT_0, TARGET_UNIT_TARGET_ENEMY);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_target_fissures : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_target_fissures);
|
||||
|
||||
void HandleEffect(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
GetCaster()->CastSpell(GetHitUnit(), SPELL_LESSER_SHADOW_FISSURE, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_target_fissures::HandleEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
class at_rp_nethekurse : public OnlyOnceAreaTriggerScript
|
||||
{
|
||||
public:
|
||||
at_rp_nethekurse() : OnlyOnceAreaTriggerScript("at_rp_nethekurse") { }
|
||||
|
||||
bool _OnTrigger(Player* player, AreaTrigger const* /*at*/) override
|
||||
{
|
||||
if (InstanceScript* instance = player->GetInstanceScript())
|
||||
{
|
||||
if (instance->GetBossState(DATA_NETHEKURSE) != DONE && instance->GetBossState(DATA_NETHEKURSE) != IN_PROGRESS)
|
||||
{
|
||||
if (Creature* nethekurse = instance->GetCreature(DATA_NETHEKURSE))
|
||||
{
|
||||
nethekurse->AI()->DoAction(ACTION_START_INTRO);
|
||||
}
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (EventStage < EVENT_STAGE_MAIN || me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_SHADOW_FISSURE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
me->CastSpell(target, SPELL_SHADOW_FISSURE, false);
|
||||
events.RescheduleEvent(EVENT_SPELL_SHADOW_FISSURE, urand(7500, 10000));
|
||||
break;
|
||||
case EVENT_SPELL_DEATH_COIL:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
me->CastSpell(target, DUNGEON_MODE(SPELL_DEATH_COIL_N, SPELL_DEATH_COIL_H), false);
|
||||
events.RescheduleEvent(EVENT_SPELL_DEATH_COIL, urand(15000, 20000));
|
||||
break;
|
||||
case EVENT_SPELL_CLEAVE:
|
||||
me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_SHADOW_CLEAVE_N, SPELL_SHADOW_SLAM_H), false);
|
||||
events.RescheduleEvent(EVENT_SPELL_CLEAVE, urand(6000, 8000));
|
||||
break;
|
||||
case EVENT_CHECK_HEALTH:
|
||||
if (me->HealthBelowPct(21))
|
||||
{
|
||||
events.Reset();
|
||||
me->CastSpell(me, SPELL_DARK_SPIN, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
events.RescheduleEvent(EVENT_CHECK_HEALTH, 1000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!me->HealthBelowPct(21))
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
uint8 PeonEngagedCount = 0;
|
||||
uint8 PeonKilledCount = 0;
|
||||
uint8 EventStage;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetShatteredHallsAI<boss_grand_warlock_nethekurseAI>(creature);
|
||||
}
|
||||
};
|
||||
|
||||
class spell_tsh_shadow_sear : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_tsh_shadow_sear() : SpellScriptLoader("spell_tsh_shadow_sear") { }
|
||||
|
||||
class spell_tsh_shadow_sear_AuraScript : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_tsh_shadow_sear_AuraScript);
|
||||
|
||||
void CalculateDamageAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
|
||||
{
|
||||
amount = 1000;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_tsh_shadow_sear_AuraScript::CalculateDamageAmount, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE);
|
||||
}
|
||||
};
|
||||
|
||||
AuraScript* GetAuraScript() const override
|
||||
{
|
||||
return new spell_tsh_shadow_sear_AuraScript();
|
||||
}
|
||||
};
|
||||
|
||||
class spell_tsh_shadow_bolt : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_tsh_shadow_bolt() : SpellScriptLoader("spell_tsh_shadow_bolt") { }
|
||||
|
||||
class spell_tsh_shadow_bolt_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_tsh_shadow_bolt_SpellScript);
|
||||
|
||||
void SelectRandomPlayer(WorldObject*& target)
|
||||
{
|
||||
if (Creature* caster = GetCaster()->ToCreature())
|
||||
{
|
||||
std::list<Player*> playerList;
|
||||
Map::PlayerList const& players = caster->GetMap()->GetPlayers();
|
||||
for (auto itr = players.begin(); itr != players.end(); ++itr)
|
||||
if (Player* player = itr->GetSource()->ToPlayer())
|
||||
if (player->IsWithinDist(caster, 100.0f) && player->IsAlive())
|
||||
playerList.push_back(player);
|
||||
|
||||
if (!playerList.empty())
|
||||
target = Acore::Containers::SelectRandomContainerElement(playerList);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_tsh_shadow_bolt_SpellScript::SelectRandomPlayer, EFFECT_0, TARGET_UNIT_TARGET_ENEMY);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_tsh_shadow_bolt_SpellScript();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_grand_warlock_nethekurse()
|
||||
{
|
||||
new boss_grand_warlock_nethekurse();
|
||||
new spell_tsh_shadow_sear();
|
||||
new spell_tsh_shadow_bolt();
|
||||
RegisterShatteredHallsCreatureAI(boss_grand_warlock_nethekurse);
|
||||
RegisterSpellScript(spell_tsh_shadow_bolt);
|
||||
RegisterSpellScript(spell_target_fissures);
|
||||
new at_rp_nethekurse();
|
||||
}
|
||||
|
||||
+230
-213
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "TaskScheduler.h"
|
||||
#include "shattered_halls.h"
|
||||
|
||||
enum Spells
|
||||
@@ -24,249 +26,264 @@ enum Spells
|
||||
SPELL_BLAST_WAVE = 30600,
|
||||
SPELL_FEAR = 30584,
|
||||
SPELL_THUNDERCLAP = 30633,
|
||||
SPELL_BURNING_MAUL_N = 30598,
|
||||
SPELL_BURNING_MAUL_H = 36056,
|
||||
SPELL_BEATDOWN = 30618,
|
||||
SPELL_BURNING_MAUL = 30598
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
enum Equip
|
||||
{
|
||||
NPC_LEFT_HEAD = 19523,
|
||||
NPC_RIGHT_HEAD = 19524
|
||||
EQUIP_STANDARD = 1,
|
||||
EQUIP_BURNING_MAUL = 2
|
||||
};
|
||||
|
||||
enum HeadYells
|
||||
{
|
||||
SAY_ON_AGGRO = 0,
|
||||
SAY_ON_AGGRO_2,
|
||||
SAY_ON_AGGRO_3,
|
||||
SAY_ON_BEATDOWN,
|
||||
SAY_ON_BEATDOWN_2,
|
||||
SAY_ON_BEATDOWN_3,
|
||||
SAY_ON_KILL,
|
||||
SAY_ON_KILL_2,
|
||||
SAY_ON_DEATH
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
EMOTE_ENRAGE = 0,
|
||||
|
||||
SETDATA_DATA = 1,
|
||||
SETDATA_YELL = 1
|
||||
EMOTE_BURNING_MAUL = 0,
|
||||
DATA_BURNING_MAUL_END = 1
|
||||
};
|
||||
|
||||
enum Events
|
||||
enum Phase
|
||||
{
|
||||
EVENT_AGGRO_YELL_1 = 1,
|
||||
EVENT_AGGRO_YELL_2 = 2,
|
||||
EVENT_AGGRO_YELL_3 = 3,
|
||||
|
||||
EVENT_THREAT_YELL_L_1 = 4,
|
||||
EVENT_THREAT_YELL_L_2 = 5,
|
||||
EVENT_THREAT_YELL_L_3 = 6,
|
||||
|
||||
EVENT_THREAT_YELL_R_1 = 7,
|
||||
|
||||
EVENT_KILL_YELL_LEFT = 8,
|
||||
EVENT_KILL_YELL_RIGHT = 9,
|
||||
EVENT_DEATH_YELL = 10,
|
||||
|
||||
EVENT_SPELL_FEAR = 20,
|
||||
EVENT_SPELL_BURNING_MAUL = 21,
|
||||
EVENT_SPELL_THUNDER_CLAP = 22,
|
||||
EVENT_RESET_THREAT = 23,
|
||||
EVENT_SPELL_BLAST_WAVE = 24
|
||||
GROUP_NON_BURNING_PHASE = 0,
|
||||
GROUP_BURNING_PHASE = 1,
|
||||
GROUP_FULL_PHASE = 2
|
||||
};
|
||||
|
||||
// ########################################################
|
||||
// Warbringer_Omrogg
|
||||
// ########################################################
|
||||
|
||||
class boss_warbringer_omrogg : public CreatureScript
|
||||
struct boss_warbringer_omrogg : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_warbringer_omrogg() : CreatureScript("boss_warbringer_omrogg") { }
|
||||
|
||||
struct boss_warbringer_omroggAI : public BossAI
|
||||
boss_warbringer_omrogg(Creature* creature) : BossAI(creature, DATA_OMROGG)
|
||||
{
|
||||
boss_warbringer_omroggAI(Creature* creature) : BossAI(creature, DATA_OMROGG)
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
}
|
||||
|
||||
EventMap events2;
|
||||
|
||||
Creature* GetLeftHead()
|
||||
{
|
||||
return summons.GetCreatureWithEntry(NPC_LEFT_HEAD);
|
||||
}
|
||||
|
||||
Creature* GetRightHead()
|
||||
{
|
||||
return summons.GetCreatureWithEntry(NPC_RIGHT_HEAD);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
me->SummonCreature(NPC_LEFT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0);
|
||||
me->SummonCreature(NPC_RIGHT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_DEAD_DESPAWN, 0);
|
||||
|
||||
if (Creature* LeftHead = GetLeftHead())
|
||||
{
|
||||
uint8 aggroYell = urand(EVENT_AGGRO_YELL_1, EVENT_AGGRO_YELL_3);
|
||||
LeftHead->AI()->Talk(aggroYell - 1);
|
||||
events2.ScheduleEvent(aggroYell, 3000);
|
||||
}
|
||||
|
||||
_JustEngagedWith();
|
||||
|
||||
events.ScheduleEvent(EVENT_SPELL_FEAR, 8000);
|
||||
events.ScheduleEvent(EVENT_SPELL_BURNING_MAUL, 25000);
|
||||
events.ScheduleEvent(EVENT_SPELL_THUNDER_CLAP, 15000);
|
||||
events.ScheduleEvent(EVENT_RESET_THREAT, 30000);
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summoned) override
|
||||
{
|
||||
summons.Summon(summoned);
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
{
|
||||
Creature* head = nullptr;
|
||||
uint32 eventId = EVENT_KILL_YELL_LEFT;
|
||||
if (urand(0, 1))
|
||||
{
|
||||
head = GetLeftHead();
|
||||
eventId = EVENT_KILL_YELL_LEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
head = GetRightHead();
|
||||
eventId = EVENT_KILL_YELL_RIGHT;
|
||||
}
|
||||
|
||||
if (head)
|
||||
head->AI()->Talk(eventId - 1);
|
||||
|
||||
events2.ScheduleEvent(eventId, 3000);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Creature* LeftHead = GetLeftHead();
|
||||
Creature* RightHead = GetRightHead();
|
||||
if (!LeftHead || !RightHead)
|
||||
return;
|
||||
|
||||
LeftHead->DespawnOrUnsummon(5000);
|
||||
RightHead->DespawnOrUnsummon(5000);
|
||||
|
||||
LeftHead->AI()->Talk(EVENT_DEATH_YELL - 1);
|
||||
RightHead->AI()->SetData(SETDATA_DATA, SETDATA_YELL);
|
||||
|
||||
instance->SetBossState(DATA_OMROGG, DONE);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
events2.Update(diff);
|
||||
switch (uint32 eventId = events2.ExecuteEvent())
|
||||
{
|
||||
case EVENT_AGGRO_YELL_1:
|
||||
case EVENT_AGGRO_YELL_2:
|
||||
case EVENT_AGGRO_YELL_3:
|
||||
case EVENT_KILL_YELL_LEFT:
|
||||
case EVENT_THREAT_YELL_L_1:
|
||||
case EVENT_THREAT_YELL_L_2:
|
||||
case EVENT_THREAT_YELL_L_3:
|
||||
if (Creature* RightHead = GetRightHead())
|
||||
RightHead->AI()->Talk(eventId - 1);
|
||||
break;
|
||||
case EVENT_KILL_YELL_RIGHT:
|
||||
case EVENT_THREAT_YELL_R_1:
|
||||
if (Creature* LeftHead = GetLeftHead())
|
||||
LeftHead->AI()->Talk(eventId - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
if (me->HasUnitState(UNIT_STATE_CASTING))
|
||||
return;
|
||||
|
||||
switch (events.ExecuteEvent())
|
||||
{
|
||||
case EVENT_SPELL_FEAR:
|
||||
me->CastSpell(me, SPELL_FEAR, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_FEAR, 22000);
|
||||
break;
|
||||
case EVENT_SPELL_THUNDER_CLAP:
|
||||
me->CastSpell(me, SPELL_THUNDERCLAP, false);
|
||||
events.ScheduleEvent(EVENT_SPELL_THUNDER_CLAP, 25000);
|
||||
break;
|
||||
case EVENT_RESET_THREAT:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
{
|
||||
uint8 threatYell = urand(EVENT_THREAT_YELL_L_1, EVENT_THREAT_YELL_R_1);
|
||||
if (Creature* head = threatYell == EVENT_THREAT_YELL_R_1 ? GetRightHead() : GetLeftHead())
|
||||
head->AI()->Talk(threatYell - 1);
|
||||
events.ScheduleEvent(threatYell, 3000);
|
||||
|
||||
DoResetThreatList();
|
||||
me->AddThreat(target, 10.0f);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_RESET_THREAT, 30000);
|
||||
break;
|
||||
case EVENT_SPELL_BURNING_MAUL:
|
||||
Talk(EMOTE_ENRAGE);
|
||||
me->CastSpell(me, DUNGEON_MODE(SPELL_BURNING_MAUL_N, SPELL_BURNING_MAUL_H), false);
|
||||
events.ScheduleEvent(EVENT_SPELL_BURNING_MAUL, 40000);
|
||||
events.ScheduleEvent(EVENT_SPELL_BLAST_WAVE, 15000);
|
||||
events.ScheduleEvent(EVENT_SPELL_BLAST_WAVE, 20000);
|
||||
break;
|
||||
case EVENT_SPELL_BLAST_WAVE:
|
||||
me->CastSpell(me, SPELL_BLAST_WAVE, false);
|
||||
break;
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return GetShatteredHallsAI<boss_warbringer_omroggAI>(creature);
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void HandleHeadTalk(HeadYells yell)
|
||||
{
|
||||
switch (yell)
|
||||
{
|
||||
case SAY_ON_AGGRO:
|
||||
{
|
||||
uint8 group = urand(SAY_ON_AGGRO, SAY_ON_AGGRO_3);
|
||||
if (Creature* leftHead = instance->GetCreature(DATA_OMROGG_LEFT_HEAD))
|
||||
{
|
||||
leftHead->AI()->Talk(group);
|
||||
_headTalk.Schedule(3600ms, [this, group](TaskContext /*context*/)
|
||||
{
|
||||
if (Creature* rightHead = instance->GetCreature(DATA_OMROGG_RIGHT_HEAD))
|
||||
rightHead->AI()->Talk(group);
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SAY_ON_BEATDOWN:
|
||||
{
|
||||
if (Creature* leftHead = instance->GetCreature(DATA_OMROGG_LEFT_HEAD))
|
||||
{
|
||||
leftHead->AI()->Talk(SAY_ON_BEATDOWN);
|
||||
_headTalk.Schedule(3600ms, [this](TaskContext context)
|
||||
{
|
||||
if (Creature* rightHead = instance->GetCreature(DATA_OMROGG_RIGHT_HEAD))
|
||||
rightHead->AI()->Talk(SAY_ON_BEATDOWN);
|
||||
context.Schedule(3600ms, [this](TaskContext context)
|
||||
{
|
||||
uint8 group = urand(SAY_ON_BEATDOWN_2, SAY_ON_BEATDOWN_3);
|
||||
if (Creature* leftHead = instance->GetCreature(DATA_OMROGG_LEFT_HEAD))
|
||||
leftHead->AI()->Talk(group);
|
||||
context.Schedule(3600ms, [this, group](TaskContext /*context*/)
|
||||
{
|
||||
if (Creature* rightHead = instance->GetCreature(DATA_OMROGG_RIGHT_HEAD))
|
||||
rightHead->AI()->Talk(group);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SAY_ON_KILL:
|
||||
{
|
||||
uint8 group = urand(SAY_ON_KILL, SAY_ON_KILL_2);
|
||||
if (Creature* leftHead = instance->GetCreature(DATA_OMROGG_LEFT_HEAD))
|
||||
leftHead->AI()->Talk(group);
|
||||
_headTalk.Schedule(3600ms, [this, group](TaskContext /*context*/)
|
||||
{
|
||||
if (Creature* rightHead = instance->GetCreature(DATA_OMROGG_RIGHT_HEAD))
|
||||
rightHead->AI()->Talk(group);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case SAY_ON_DEATH:
|
||||
{
|
||||
if (Creature* leftHead = instance->GetCreature(DATA_OMROGG_LEFT_HEAD))
|
||||
leftHead->AI()->Talk(SAY_ON_DEATH);
|
||||
_headTalk.Schedule(3600ms, [this](TaskContext /*context*/)
|
||||
{
|
||||
if (Creature* rightHead = instance->GetCreature(DATA_OMROGG_RIGHT_HEAD))
|
||||
rightHead->AI()->Talk(SAY_ON_DEATH);
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetData(uint32 data, uint32) override
|
||||
{
|
||||
if (data != DATA_BURNING_MAUL_END)
|
||||
return;
|
||||
|
||||
scheduler.CancelGroup(GROUP_BURNING_PHASE);
|
||||
ScheduleNonBurningPhase();
|
||||
ScheduleBurningPhase();
|
||||
}
|
||||
|
||||
void ScheduleNonBurningPhase()
|
||||
{
|
||||
scheduler.
|
||||
Schedule(12100ms, 17300ms, GROUP_NON_BURNING_PHASE, [this](TaskContext context)
|
||||
{
|
||||
DoCastAOE(SPELL_THUNDERCLAP);
|
||||
context.Repeat(17200ms, 24200ms);
|
||||
})
|
||||
.Schedule(20s, 30s, GROUP_NON_BURNING_PHASE, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(SPELL_BEATDOWN);
|
||||
me->AttackStop();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
context.Schedule(200ms, GROUP_NON_BURNING_PHASE, [this](TaskContext context)
|
||||
{
|
||||
DoResetThreatList();
|
||||
if (Unit* newTarget = SelectTarget(SelectTargetMethod::Random, 1))
|
||||
me->AddThreat(newTarget, 2250.f);
|
||||
HandleHeadTalk(SAY_ON_BEATDOWN);
|
||||
context.Schedule(1200ms, GROUP_NON_BURNING_PHASE, [this](TaskContext /*context*/)
|
||||
{
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
});
|
||||
});
|
||||
context.Repeat();
|
||||
});
|
||||
}
|
||||
|
||||
void ScheduleBurningPhase()
|
||||
{
|
||||
scheduler.
|
||||
Schedule(45s, 60s, GROUP_BURNING_PHASE, [this](TaskContext context)
|
||||
{
|
||||
me->AttackStop();
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
context.CancelGroup(GROUP_NON_BURNING_PHASE);
|
||||
context.Schedule(1200ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastAOE(SPELL_FEAR);
|
||||
DoCast(SPELL_BURNING_MAUL);
|
||||
context.Schedule(200ms, [this](TaskContext context)
|
||||
{
|
||||
Talk(EMOTE_BURNING_MAUL);
|
||||
context.Schedule(2200ms, [this](TaskContext context)
|
||||
{
|
||||
DoResetThreatList();
|
||||
if (Unit* newTarget = SelectTarget(SelectTargetMethod::Random, 1))
|
||||
me->AddThreat(newTarget, 2250.f);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
context.Schedule(4850ms, 8500ms, GROUP_BURNING_PHASE, [this](TaskContext context)
|
||||
{
|
||||
DoCastAOE(SPELL_BLAST_WAVE);
|
||||
context.Repeat();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
_headTalk.CancelAll();
|
||||
HandleHeadTalk(SAY_ON_AGGRO);
|
||||
|
||||
ScheduleNonBurningPhase();
|
||||
ScheduleBurningPhase();
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim && victim->GetTypeId() == TYPEID_PLAYER)
|
||||
HandleHeadTalk(SAY_ON_KILL);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
HandleHeadTalk(SAY_ON_DEATH);
|
||||
BossAI::JustDied(killer);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
_headTalk.Update(diff);
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff, [this]
|
||||
{
|
||||
DoMeleeAttackIfReady();
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
TaskScheduler _headTalk;
|
||||
};
|
||||
|
||||
class npc_omrogg_heads : public CreatureScript
|
||||
class spell_burning_maul : public AuraScript
|
||||
{
|
||||
public:
|
||||
npc_omrogg_heads() : CreatureScript("npc_omrogg_heads") { }
|
||||
PrepareAuraScript(spell_burning_maul);
|
||||
|
||||
struct npc_omrogg_headsAI : public NullCreatureAI
|
||||
void HandleOnRemove(AuraEffect const* /* aurEff */, AuraEffectHandleModes /* mode */)
|
||||
{
|
||||
npc_omrogg_headsAI(Creature* creature) : NullCreatureAI(creature) { timer = 0; }
|
||||
|
||||
void SetData(uint32 data, uint32 value) override
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
if (data == SETDATA_DATA && value == SETDATA_YELL)
|
||||
timer = 1;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (timer)
|
||||
if (Creature* omrogg = caster->ToCreature())
|
||||
{
|
||||
timer += diff;
|
||||
if (timer >= 3000)
|
||||
{
|
||||
timer = 0;
|
||||
Talk(EVENT_DEATH_YELL - 1);
|
||||
}
|
||||
omrogg->LoadEquipment(EQUIP_STANDARD);
|
||||
omrogg->AI()->SetData(DATA_BURNING_MAUL_END, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 timer;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
void HandleOnApply(AuraEffect const* /* aurEff */, AuraEffectHandleModes /* mode */)
|
||||
{
|
||||
return GetShatteredHallsAI<npc_omrogg_headsAI>(creature);
|
||||
if (Unit* caster = GetCaster())
|
||||
if (Creature* omrogg = caster->ToCreature())
|
||||
omrogg->LoadEquipment(EQUIP_BURNING_MAUL);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectRemove += AuraEffectRemoveFn(spell_burning_maul::HandleOnRemove, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
|
||||
OnEffectApply += AuraEffectApplyFn(spell_burning_maul::HandleOnApply, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_warbringer_omrogg()
|
||||
{
|
||||
new boss_warbringer_omrogg();
|
||||
new npc_omrogg_heads();
|
||||
RegisterShatteredHallsCreatureAI(boss_warbringer_omrogg);
|
||||
RegisterSpellScript(spell_burning_maul);
|
||||
}
|
||||
|
||||
+258
-127
@@ -17,174 +17,305 @@
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "TaskScheduler.h"
|
||||
#include "shattered_halls.h"
|
||||
|
||||
enum Says
|
||||
{
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SLAY = 1,
|
||||
SAY_DEATH = 2
|
||||
SAY_AGGRO = 0,
|
||||
SAY_SLAY = 1,
|
||||
SAY_DEATH = 2,
|
||||
SAY_EVADE = 5
|
||||
};
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_BLADE_DANCE = 30739,
|
||||
SPELL_CHARGE = 25821,
|
||||
SPELL_SPRINT = 32720,
|
||||
// Blade dance
|
||||
SPELL_BLADE_DANCE_TARGETING = 30738,
|
||||
SPELL_BLADE_DANCE_DMG = 30739,
|
||||
SPELL_BLADE_DANCE_CHARGE = 30751,
|
||||
|
||||
// Warchief portal
|
||||
SPELL_SUMMON_HEATHEN = 30737,
|
||||
SPELL_SUMMON_REAVER = 30785,
|
||||
SPELL_SUMMON_SHARPSHOOTER = 30786
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
{
|
||||
NPC_SHATTERED_ASSASSIN = 17695,
|
||||
NPC_HEARTHEN_GUARD = 17621,
|
||||
NPC_SHARPSHOOTER_GUARD = 17622,
|
||||
NPC_REAVER_GUARD = 17623
|
||||
NPC_SHATTERED_ASSASSIN = 17695,
|
||||
NPC_BLADE_DANCE_TARGET = 20709
|
||||
};
|
||||
|
||||
float AssassEntrance[3] = { 275.136f, -84.29f, 2.3f }; // y -8
|
||||
float AssassExit[3] = { 184.233f, -84.29f, 2.3f }; // y -8
|
||||
float AddsEntrance[3] = { 306.036f, -84.29f, 1.93f };
|
||||
|
||||
enum Misc
|
||||
enum PortalData
|
||||
{
|
||||
EVENT_CHECK_ROOM = 1,
|
||||
EVENT_SUMMON_ADDS = 2,
|
||||
EVENT_SUMMON_ASSASSINS = 3,
|
||||
EVENT_SPELL_CHARGE = 4,
|
||||
EVENT_MOVE_TO_NEXT_POINT = 5,
|
||||
EVENT_BLADE_DANCE = 6,
|
||||
EVENT_FINISH_BLADE_DANCE = 7
|
||||
DATA_START_FIGHT = 1,
|
||||
DATA_RESET_FIGHT = 2
|
||||
};
|
||||
|
||||
class boss_warchief_kargath_bladefist : public CreatureScript
|
||||
std::array<uint32, 3> const summonSpells = { SPELL_SUMMON_HEATHEN, SPELL_SUMMON_REAVER, SPELL_SUMMON_SHARPSHOOTER };
|
||||
std::vector<Position> const assassinsPos =
|
||||
{
|
||||
{ 172.68164f, -80.65692f, 2.0834563f, 5.4279f },
|
||||
{ 167.8295f, -86.55783f, 1.9949634f, 0.8118f },
|
||||
{ 287.0375f, -88.17879f, 2.0663502f, 3.2490f },
|
||||
{ 292.1491f, -82.25267f, 1.9973913f, 5.8568f }
|
||||
};
|
||||
|
||||
Position const kargathRespawnPos = { 231.25f, -83.6449f, 5.02341f };
|
||||
|
||||
struct boss_warchief_kargath_bladefist : public BossAI
|
||||
{
|
||||
boss_warchief_kargath_bladefist(Creature* creature) : BossAI(creature, DATA_KARGATH)
|
||||
{
|
||||
scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
}
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
BossAI::InitializeAI();
|
||||
if (instance)
|
||||
{
|
||||
if (Creature* executioner = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXECUTIONER)))
|
||||
{
|
||||
executioner->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
}
|
||||
|
||||
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
|
||||
{
|
||||
if (summon)
|
||||
{
|
||||
summon->SetVisible(false);
|
||||
scheduler.Schedule(20s, [summon](TaskContext /*context*/)
|
||||
{
|
||||
if (summon)
|
||||
{
|
||||
summon->Respawn(true);
|
||||
summon->SetVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RespawnAssassins()
|
||||
{
|
||||
for (Position const& summonPos : assassinsPos)
|
||||
me->SummonCreature(NPC_SHATTERED_ASSASSIN, summonPos);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
if (Creature* warchiefPortal = instance->GetCreature(DATA_WARCHIEF_PORTAL))
|
||||
warchiefPortal->AI()->SetData(DATA_RESET_FIGHT, 0);
|
||||
_danceCount = 0;
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
BossAI::JustDied(killer);
|
||||
if (instance)
|
||||
{
|
||||
if (Creature* executioner = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXECUTIONER)))
|
||||
{
|
||||
executioner->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
BossAI::JustEngagedWith(who);
|
||||
if (Creature* warchiefPortal = instance->GetCreature(DATA_WARCHIEF_PORTAL))
|
||||
warchiefPortal->AI()->SetData(DATA_START_FIGHT, 0);
|
||||
RespawnAssassins();
|
||||
scheduler
|
||||
.Schedule(30s, [this](TaskContext context)
|
||||
{
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
_danceCount = 0;
|
||||
DoCastAOE(SPELL_BLADE_DANCE_TARGETING);
|
||||
context.Repeat(32850ms, 41350ms);
|
||||
});
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim && victim->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 /*id*/) override
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE)
|
||||
return;
|
||||
|
||||
if (_danceCount < 8)
|
||||
{
|
||||
_danceCount++;
|
||||
scheduler.Schedule(100ms, [this](TaskContext /*context*/)
|
||||
{
|
||||
DoCastAOE(SPELL_BLADE_DANCE_TARGETING);
|
||||
});
|
||||
}
|
||||
else
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
}
|
||||
|
||||
bool IsInRoom()
|
||||
{
|
||||
if (me->GetExactDist2d(kargathRespawnPos) >= 42.f)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!IsInRoom())
|
||||
{
|
||||
Talk(SAY_EVADE);
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
scheduler.Update(diff, [this]
|
||||
{
|
||||
DoMeleeAttackIfReady();
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8 _danceCount;
|
||||
};
|
||||
|
||||
struct npc_warchief_portal : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
boss_warchief_kargath_bladefist() : CreatureScript("boss_warchief_kargath_bladefist") { }
|
||||
npc_warchief_portal(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
struct boss_warchief_kargath_bladefistAI : public BossAI
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
boss_warchief_kargath_bladefistAI(Creature* creature) : BossAI(creature, DATA_KARGATH) { }
|
||||
_scheduler.Update(diff);
|
||||
}
|
||||
|
||||
void InitializeAI() override
|
||||
void JustSummoned(Creature* creature) override
|
||||
{
|
||||
InstanceScript* instance = me->GetInstanceScript();
|
||||
if (!instance)
|
||||
return;
|
||||
|
||||
if (Creature* kargath = instance->GetCreature(DATA_KARGATH))
|
||||
kargath->AI()->JustSummoned(creature);
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 /*data*/) override
|
||||
{
|
||||
if (type == DATA_START_FIGHT)
|
||||
{
|
||||
BossAI::InitializeAI();
|
||||
if (instance)
|
||||
if (Creature* executioner = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXECUTIONER)))
|
||||
executioner->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
_scheduler.Schedule(20600ms, [this](TaskContext context)
|
||||
{
|
||||
DoCastSelf(summonSpells[context.GetRepeatCounter() % 3]);
|
||||
context.Repeat();
|
||||
});
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
if (type == DATA_RESET_FIGHT)
|
||||
{
|
||||
Talk(SAY_DEATH);
|
||||
_JustDied();
|
||||
|
||||
if (instance)
|
||||
if (Creature* executioner = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_EXECUTIONER)))
|
||||
executioner->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
|
||||
_scheduler.CancelAll();
|
||||
}
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
Talk(SAY_AGGRO);
|
||||
_JustEngagedWith();
|
||||
protected:
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
events.ScheduleEvent(EVENT_CHECK_ROOM, 5000);
|
||||
events.ScheduleEvent(EVENT_SUMMON_ADDS, 30000);
|
||||
events.ScheduleEvent(EVENT_SUMMON_ASSASSINS, 5000);
|
||||
events.ScheduleEvent(EVENT_BLADE_DANCE, 30000);
|
||||
events.ScheduleEvent(EVENT_SPELL_CHARGE, 0);
|
||||
}
|
||||
class spell_blade_dance_targeting : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_blade_dance_targeting);
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
if (summon->GetEntry() != NPC_SHATTERED_ASSASSIN)
|
||||
summon->AI()->AttackStart(SelectTarget(SelectTargetMethod::Random, 0));
|
||||
bool Validate(SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
return ValidateSpellInfo({ SPELL_BLADE_DANCE_CHARGE, SPELL_BLADE_DANCE_DMG });
|
||||
}
|
||||
|
||||
summons.Summon(summon);
|
||||
}
|
||||
void FilterTargets(std::list<WorldObject*>& targets)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
if (!caster)
|
||||
return;
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE || id != 1)
|
||||
return;
|
||||
|
||||
me->CastSpell(me, SPELL_BLADE_DANCE, true);
|
||||
events.ScheduleEvent(EVENT_MOVE_TO_NEXT_POINT, 0);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
switch (events.ExecuteEvent())
|
||||
targets.remove_if([&](WorldObject* target) -> bool
|
||||
{
|
||||
case EVENT_CHECK_ROOM:
|
||||
if (me->GetPositionX() > 255 || me->GetPositionX() < 205)
|
||||
{
|
||||
EnterEvadeMode();
|
||||
return;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHECK_ROOM, 5000);
|
||||
break;
|
||||
case EVENT_SUMMON_ASSASSINS:
|
||||
me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1] + 8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
|
||||
me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassEntrance[0], AssassEntrance[1] - 8, AssassEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
|
||||
me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1] + 8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
|
||||
me->SummonCreature(NPC_SHATTERED_ASSASSIN, AssassExit[0], AssassExit[1] - 8, AssassExit[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
|
||||
break;
|
||||
case EVENT_SUMMON_ADDS:
|
||||
for (uint8 i = 0; i < 2; ++i)
|
||||
me->SummonCreature(NPC_HEARTHEN_GUARD + urand(0, 2), AddsEntrance[0], AddsEntrance[1], AddsEntrance[2], 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
|
||||
float dist = caster->GetDistance2d(target);
|
||||
// Do not target dummies that are too close or too far away
|
||||
if (dist < 5.f || dist > 16.f)
|
||||
return true;
|
||||
// Do not target anything that is not a target dummy
|
||||
if (target->GetEntry() != NPC_BLADE_DANCE_TARGET)
|
||||
return true;
|
||||
|
||||
events.ScheduleEvent(EVENT_SUMMON_ADDS, 30000);
|
||||
break;
|
||||
case EVENT_BLADE_DANCE:
|
||||
events.DelayEvents(10001);
|
||||
events.ScheduleEvent(EVENT_BLADE_DANCE, 40000);
|
||||
events.ScheduleEvent(EVENT_MOVE_TO_NEXT_POINT, 0);
|
||||
events.ScheduleEvent(EVENT_FINISH_BLADE_DANCE, 10000);
|
||||
events.SetPhase(1);
|
||||
me->CastSpell(me, SPELL_SPRINT, true);
|
||||
break;
|
||||
case EVENT_MOVE_TO_NEXT_POINT:
|
||||
{
|
||||
float x = 210 + frand(0.0f, 35.0f);
|
||||
float y = -65.0f - frand(0.0f, 35.0f);
|
||||
me->GetMotionMaster()->MovePoint(1, x, y, me->GetPositionZ());
|
||||
break;
|
||||
}
|
||||
case EVENT_FINISH_BLADE_DANCE:
|
||||
events.SetPhase(0);
|
||||
me->GetMotionMaster()->Clear();
|
||||
me->GetMotionMaster()->MoveChase(me->GetVictim());
|
||||
if (IsHeroic())
|
||||
events.ScheduleEvent(EVENT_SPELL_CHARGE, 3000);
|
||||
break;
|
||||
case EVENT_SPELL_CHARGE:
|
||||
me->CastSpell(me->GetVictim(), SPELL_CHARGE, false);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!events.IsInPhase(1))
|
||||
DoMeleeAttackIfReady();
|
||||
std::list<WorldObject*> targets2 = targets;
|
||||
|
||||
targets.remove_if([&](WorldObject* target) -> bool
|
||||
{
|
||||
if (target->SelectNearestPlayer(15.f))
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
Acore::Containers::RandomResize(targets2, 1);
|
||||
|
||||
if (urand(0, 2))
|
||||
{
|
||||
if (targets.empty())
|
||||
targets = targets2;
|
||||
else
|
||||
Acore::Containers::RandomResize(targets, 1);
|
||||
}
|
||||
};
|
||||
else
|
||||
targets = targets2;
|
||||
}
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
void HandleOnHit()
|
||||
{
|
||||
return GetShatteredHallsAI<boss_warchief_kargath_bladefistAI>(creature);
|
||||
Unit* caster = GetCaster();
|
||||
Unit* target = GetHitUnit();
|
||||
if (!caster || !target)
|
||||
return;
|
||||
|
||||
caster->CastSpell(target, SPELL_BLADE_DANCE_CHARGE, true);
|
||||
caster->CastSpell(target, SPELL_BLADE_DANCE_DMG, true);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_blade_dance_targeting::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
|
||||
OnHit += SpellHitFn(spell_blade_dance_targeting::HandleOnHit);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_warchief_kargath_bladefist()
|
||||
{
|
||||
new boss_warchief_kargath_bladefist();
|
||||
RegisterShatteredHallsCreatureAI(boss_warchief_kargath_bladefist);
|
||||
RegisterShatteredHallsCreatureAI(npc_warchief_portal);
|
||||
RegisterSpellScript(spell_blade_dance_targeting);
|
||||
}
|
||||
|
||||
+21
-48
@@ -20,6 +20,23 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "shattered_halls.h"
|
||||
|
||||
ObjectData const creatureData[] =
|
||||
{
|
||||
{ NPC_GRAND_WARLOCK_NETHEKURSE , DATA_NETHEKURSE },
|
||||
{ NPC_WARCHIEF_KARGATH , DATA_KARGATH },
|
||||
{ NPC_OMROGG_LEFT_HEAD , DATA_OMROGG_LEFT_HEAD },
|
||||
{ NPC_OMROGG_RIGHT_HEAD , DATA_OMROGG_RIGHT_HEAD },
|
||||
{ NPC_WARCHIEF_PORTAL , DATA_WARCHIEF_PORTAL },
|
||||
{ 0 , 0 }
|
||||
};
|
||||
|
||||
DoorData const doorData[] =
|
||||
{
|
||||
{ GO_GRAND_WARLOCK_CHAMBER_DOOR_1, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE },
|
||||
{ GO_GRAND_WARLOCK_CHAMBER_DOOR_2, DATA_NETHEKURSE, DOOR_TYPE_PASSAGE },
|
||||
{ 0, 0, DOOR_TYPE_ROOM } // END
|
||||
};
|
||||
|
||||
class instance_shattered_halls : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -37,6 +54,8 @@ public:
|
||||
void Initialize() override
|
||||
{
|
||||
SetBossNumber(ENCOUNTER_COUNT);
|
||||
LoadObjectData(creatureData, nullptr);
|
||||
LoadDoorData(doorData);
|
||||
|
||||
TeamIdInInstance = TEAM_NEUTRAL;
|
||||
RescueTimer = 100 * MINUTE * IN_MILLISECONDS;
|
||||
@@ -48,23 +67,6 @@ public:
|
||||
TeamIdInInstance = player->GetTeamId();
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go) override
|
||||
{
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_GRAND_WARLOCK_CHAMBER_DOOR_1:
|
||||
nethekurseDoor1GUID = go->GetGUID();
|
||||
if (GetBossState(DATA_NETHEKURSE) == DONE)
|
||||
HandleGameObject(ObjectGuid::Empty, true, go);
|
||||
break;
|
||||
case GO_GRAND_WARLOCK_CHAMBER_DOOR_2:
|
||||
nethekurseDoor2GUID = go->GetGUID();
|
||||
if (GetBossState(DATA_NETHEKURSE) == DONE)
|
||||
HandleGameObject(ObjectGuid::Empty, true, go);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnCreatureCreate(Creature* creature) override
|
||||
{
|
||||
if (TeamIdInInstance == TEAM_NEUTRAL)
|
||||
@@ -77,9 +79,6 @@ public:
|
||||
|
||||
switch (creature->GetEntry())
|
||||
{
|
||||
case NPC_WARCHIEF_KARGATH:
|
||||
warchiefKargathGUID = creature->GetGUID();
|
||||
break;
|
||||
case NPC_SHATTERED_EXECUTIONER:
|
||||
if (RescueTimer > 25 * MINUTE * IN_MILLISECONDS)
|
||||
creature->AddLootMode(2);
|
||||
@@ -101,29 +100,7 @@ public:
|
||||
prisonerGUID[2] = creature->GetGUID();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SetBossState(uint32 type, EncounterState state) override
|
||||
{
|
||||
if (!InstanceScript::SetBossState(type, state))
|
||||
return false;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DATA_NETHEKURSE:
|
||||
if (state == IN_PROGRESS)
|
||||
{
|
||||
HandleGameObject(nethekurseDoor1GUID, false);
|
||||
HandleGameObject(nethekurseDoor2GUID, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleGameObject(nethekurseDoor1GUID, true);
|
||||
HandleGameObject(nethekurseDoor2GUID, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
InstanceScript::OnCreatureCreate(creature);
|
||||
}
|
||||
|
||||
void SetData(uint32 type, uint32 data) override
|
||||
@@ -133,7 +110,7 @@ public:
|
||||
DoCastSpellOnPlayers(SPELL_KARGATHS_EXECUTIONER_1);
|
||||
instance->LoadGrid(230, -80);
|
||||
|
||||
if (Creature* kargath = instance->GetCreature(warchiefKargathGUID))
|
||||
if (Creature* kargath = GetCreature(DATA_KARGATH))
|
||||
sCreatureTextMgr->SendChat(kargath, TeamIdInInstance == TEAM_ALLIANCE ? 3 : 4, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_MAP);
|
||||
|
||||
RescueTimer = 80 * MINUTE * IN_MILLISECONDS;
|
||||
@@ -197,10 +174,6 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
ObjectGuid warchiefKargathGUID;
|
||||
ObjectGuid nethekurseDoor1GUID;
|
||||
ObjectGuid nethekurseDoor2GUID;
|
||||
|
||||
ObjectGuid executionerGUID;
|
||||
ObjectGuid prisonerGUID[3];
|
||||
uint32 RescueTimer;
|
||||
|
||||
@@ -35,14 +35,23 @@ enum DataTypes
|
||||
DATA_PRISONER_1 = 11,
|
||||
DATA_PRISONER_2 = 12,
|
||||
DATA_PRISONER_3 = 13,
|
||||
DATA_EXECUTIONER = 14
|
||||
DATA_EXECUTIONER = 14,
|
||||
DATA_OMROGG_LEFT_HEAD = 15,
|
||||
DATA_OMROGG_RIGHT_HEAD = 16,
|
||||
DATA_WARCHIEF_PORTAL = 17
|
||||
};
|
||||
|
||||
enum CreatureIds
|
||||
{
|
||||
NPC_GRAND_WARLOCK_NETHEKURSE = 16807,
|
||||
NPC_WARCHIEF_KARGATH = 16808,
|
||||
NPC_FEL_ORC_CONVERT = 17083,
|
||||
// Warchief Kargath
|
||||
NPC_WARCHIEF_KARGATH = 16808,
|
||||
NPC_WARCHIEF_PORTAL = 17611,
|
||||
|
||||
// O'MROGG
|
||||
NPC_OMROGG_LEFT_HEAD = 19523,
|
||||
NPC_OMROGG_RIGHT_HEAD = 19524,
|
||||
|
||||
// Trial of the Naaru: Mercy
|
||||
NPC_SHATTERED_EXECUTIONER = 17301,
|
||||
@@ -73,4 +82,6 @@ inline AI* GetShatteredHallsAI(T* obj)
|
||||
return GetInstanceAI<AI>(obj, ShatteredHallsLairScriptName);
|
||||
}
|
||||
|
||||
#define RegisterShatteredHallsCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetShatteredHallsAI)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -46,11 +46,6 @@ enum Yells
|
||||
SAY_DEATH = 4
|
||||
};
|
||||
|
||||
enum Creatures
|
||||
{
|
||||
NPC_NETHER_CHARGE = 20405
|
||||
};
|
||||
|
||||
struct boss_mechano_lord_capacitus : public BossAI
|
||||
{
|
||||
boss_mechano_lord_capacitus(Creature* creature) : BossAI(creature, DATA_MECHANOLORD_CAPACITUS)
|
||||
@@ -127,7 +122,6 @@ struct boss_mechano_lord_capacitus : public BossAI
|
||||
|
||||
void JustSummoned(Creature* summon) override
|
||||
{
|
||||
summons.Summon(summon);
|
||||
summon->GetMotionMaster()->MoveRandom(30.0f);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -21,9 +21,11 @@ void AddSC_instance_auchenai_crypts();
|
||||
void AddSC_boss_shirrak_the_dead_watcher();
|
||||
void AddSC_boss_nexusprince_shaffar(); //Auchindoun Mana Tombs
|
||||
void AddSC_boss_pandemonius();
|
||||
void AddSC_boss_tavarok();
|
||||
void AddSC_instance_mana_tombs();
|
||||
void AddSC_boss_talon_king_ikiss(); //Auchindoun Sekketh Halls
|
||||
void AddSC_boss_anzu();
|
||||
void AddSC_boss_darkweaver_syth();
|
||||
void AddSC_instance_sethekk_halls();
|
||||
void AddSC_instance_shadow_labyrinth(); //Auchindoun Shadow Labyrinth
|
||||
void AddSC_boss_ambassador_hellmaw();
|
||||
@@ -54,10 +56,14 @@ void AddSC_instance_steam_vault();
|
||||
void AddSC_underbog(); //CR Underbog
|
||||
void AddSC_boss_hungarfen();
|
||||
void AddSC_boss_ghazan();
|
||||
void AddSC_boss_swamplord_muselek();
|
||||
void AddSC_boss_the_black_stalker();
|
||||
void AddSC_instance_the_underbog();
|
||||
void AddSC_the_slave_pens(); // The Slave Pens
|
||||
void AddSC_boss_ahune();
|
||||
void AddSC_boss_mennu_the_betrayer();
|
||||
void AddSC_boss_rokmar_the_crackler();
|
||||
void AddSC_boss_quagmirran();
|
||||
void AddSC_instance_the_slave_pens();
|
||||
void AddSC_boss_gruul(); //Gruul's Lair
|
||||
void AddSC_boss_high_king_maulgar();
|
||||
@@ -119,9 +125,11 @@ void AddOutlandScripts()
|
||||
AddSC_boss_shirrak_the_dead_watcher();
|
||||
AddSC_boss_nexusprince_shaffar(); //Auchindoun Mana Tombs
|
||||
AddSC_boss_pandemonius();
|
||||
AddSC_boss_tavarok();
|
||||
AddSC_instance_mana_tombs();
|
||||
AddSC_boss_talon_king_ikiss(); //Auchindoun Sekketh Halls
|
||||
AddSC_boss_anzu();
|
||||
AddSC_boss_darkweaver_syth();
|
||||
AddSC_instance_sethekk_halls();
|
||||
AddSC_instance_shadow_labyrinth(); //Auchindoun Shadow Labyrinth
|
||||
AddSC_boss_ambassador_hellmaw();
|
||||
@@ -152,10 +160,14 @@ void AddOutlandScripts()
|
||||
AddSC_underbog(); //CR Underbog
|
||||
AddSC_boss_hungarfen();
|
||||
AddSC_boss_ghazan();
|
||||
AddSC_boss_swamplord_muselek();
|
||||
AddSC_boss_the_black_stalker();
|
||||
AddSC_instance_the_underbog();
|
||||
AddSC_the_slave_pens(); // The Slave Pens
|
||||
AddSC_the_slave_pens(); //CR The Slave Pens
|
||||
AddSC_boss_ahune();
|
||||
AddSC_boss_mennu_the_betrayer();
|
||||
AddSC_boss_rokmar_the_crackler();
|
||||
AddSC_boss_quagmirran();
|
||||
AddSC_instance_the_slave_pens();
|
||||
AddSC_boss_gruul(); //Gruul's Lair
|
||||
AddSC_boss_high_king_maulgar();
|
||||
@@ -207,4 +219,4 @@ void AddOutlandScripts()
|
||||
AddSC_shattrath_city();
|
||||
AddSC_terokkar_forest();
|
||||
//AddSC_zangarmarsh();
|
||||
}
|
||||
}
|
||||
@@ -15,21 +15,6 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Shattrath_City
|
||||
SD%Complete: 100
|
||||
SDComment: Quest support: 10004, 10009, 10211. Flask vendors, Teleport to Caverns of Time
|
||||
SDCategory: Shattrath City
|
||||
EndScriptData */
|
||||
|
||||
/* ContentData
|
||||
npc_raliq_the_drunk
|
||||
npc_salsalabim
|
||||
npc_shattrathflaskvendors
|
||||
npc_zephyr
|
||||
npc_kservant
|
||||
EndContentData */
|
||||
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
@@ -37,176 +22,6 @@ EndContentData */
|
||||
#include "ScriptedGossip.h"
|
||||
#include "TaskScheduler.h"
|
||||
|
||||
/*######
|
||||
## npc_raliq_the_drunk
|
||||
######*/
|
||||
|
||||
#define GOSSIP_RALIQ "You owe Sim'salabim money. Hand them over or die!"
|
||||
|
||||
enum Raliq
|
||||
{
|
||||
SPELL_UPPERCUT = 10966,
|
||||
QUEST_CRACK_SKULLS = 10009,
|
||||
EMOTE_DRINK = 7,
|
||||
};
|
||||
|
||||
class npc_raliq_the_drunk : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_raliq_the_drunk() : CreatureScript("npc_raliq_the_drunk") { }
|
||||
|
||||
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
|
||||
{
|
||||
ClearGossipMenuFor(player);
|
||||
if (action == GOSSIP_ACTION_INFO_DEF + 1)
|
||||
{
|
||||
CloseGossipMenuFor(player);
|
||||
creature->SetFaction(FACTION_OGRE);
|
||||
creature->AI()->AttackStart(player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature) override
|
||||
{
|
||||
if (player->GetQuestStatus(QUEST_CRACK_SKULLS) == QUEST_STATUS_INCOMPLETE)
|
||||
AddGossipItemFor(player, GOSSIP_ICON_VENDOR, GOSSIP_RALIQ, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
|
||||
SendGossipMenuFor(player, 9440, creature->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_raliq_the_drunkAI(creature);
|
||||
}
|
||||
|
||||
struct npc_raliq_the_drunkAI : public ScriptedAI
|
||||
{
|
||||
npc_raliq_the_drunkAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
m_uiNormFaction = creature->GetFaction();
|
||||
}
|
||||
|
||||
uint32 m_uiNormFaction;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->RestoreFaction();
|
||||
_scheduler.CancelAll();
|
||||
_scheduler.Schedule(5s, [this](TaskContext context)
|
||||
{
|
||||
me->HandleEmoteCommand(EMOTE_DRINK);
|
||||
context.Repeat(5s);
|
||||
});
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
_scheduler
|
||||
.Schedule(5s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_UPPERCUT);
|
||||
context.Repeat(15s);
|
||||
});
|
||||
};
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
|
||||
_scheduler.Update(diff);
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
private:
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
};
|
||||
|
||||
/*######
|
||||
# npc_salsalabim
|
||||
######*/
|
||||
|
||||
enum Salsalabim
|
||||
{
|
||||
// Quests
|
||||
QUEST_10004 = 10004,
|
||||
|
||||
// Spells
|
||||
SPELL_MAGNETIC_PULL = 31705
|
||||
};
|
||||
|
||||
class npc_salsalabim : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_salsalabim() : CreatureScript("npc_salsalabim") { }
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature) override
|
||||
{
|
||||
if (player->GetQuestStatus(QUEST_10004) == QUEST_STATUS_INCOMPLETE)
|
||||
{
|
||||
creature->SetFaction(FACTION_DEMON);
|
||||
creature->AI()->AttackStart(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (creature->IsQuestGiver())
|
||||
player->PrepareQuestMenu(creature->GetGUID());
|
||||
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_salsalabimAI(creature);
|
||||
}
|
||||
|
||||
struct npc_salsalabimAI : public ScriptedAI
|
||||
{
|
||||
npc_salsalabimAI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
uint32 MagneticPull_Timer;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
MagneticPull_Timer = 15000;
|
||||
me->RestoreFaction();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* done_by, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
// xinef: some corrections
|
||||
if (done_by)
|
||||
if (Player* player = done_by->GetCharmerOrOwnerPlayerOrPlayerItself())
|
||||
if (me->HealthBelowPctDamaged(20, damage))
|
||||
{
|
||||
player->GroupEventHappens(QUEST_10004, me);
|
||||
damage = 0;
|
||||
EnterEvadeMode();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (MagneticPull_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_MAGNETIC_PULL);
|
||||
MagneticPull_Timer = 15000;
|
||||
}
|
||||
else MagneticPull_Timer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
##################################################
|
||||
Shattrath City Flask Vendors provides flasks to people exalted with 3 fActions:
|
||||
@@ -436,8 +251,6 @@ public:
|
||||
|
||||
void AddSC_shattrath_city()
|
||||
{
|
||||
new npc_raliq_the_drunk();
|
||||
new npc_salsalabim();
|
||||
new npc_shattrathflaskvendors();
|
||||
new npc_zephyr();
|
||||
new npc_kservant();
|
||||
|
||||
@@ -15,22 +15,6 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Terokkar_Forest
|
||||
SD%Complete: 85
|
||||
SDComment: Quest support: 9889, 10009, 10873, 10896, 10898, 11096, 10052, 10051. Skettis->Ogri'la Flight
|
||||
SDCategory: Terokkar Forest
|
||||
EndScriptData */
|
||||
|
||||
/* ContentData
|
||||
npc_unkor_the_ruthless
|
||||
npc_rotting_forest_rager
|
||||
npc_netherweb_victim
|
||||
npc_floon
|
||||
npc_isla_starmane
|
||||
npc_slim
|
||||
EndContentData */
|
||||
|
||||
#include "Group.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
@@ -477,115 +461,6 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
/*######
|
||||
## npc_floon
|
||||
######*/
|
||||
|
||||
#define GOSSIP_FLOON1 "You owe Sim'salabim money. Hand them over or die!"
|
||||
#define GOSSIP_FLOON2 "Hand over the money or die...again!"
|
||||
|
||||
enum Floon
|
||||
{
|
||||
SAY_FLOON_ATTACK = 0,
|
||||
|
||||
SPELL_SILENCE = 6726,
|
||||
SPELL_FROSTBOLT = 9672,
|
||||
SPELL_FROST_NOVA = 11831,
|
||||
|
||||
QUEST_CRACK_SKULLS = 10009
|
||||
};
|
||||
|
||||
class npc_floon : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_floon() : CreatureScript("npc_floon") { }
|
||||
|
||||
bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override
|
||||
{
|
||||
ClearGossipMenuFor(player);
|
||||
if (action == GOSSIP_ACTION_INFO_DEF)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_FLOON2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
|
||||
SendGossipMenuFor(player, 9443, creature->GetGUID());
|
||||
}
|
||||
if (action == GOSSIP_ACTION_INFO_DEF + 1)
|
||||
{
|
||||
CloseGossipMenuFor(player);
|
||||
creature->SetFaction(FACTION_ARAKKOA);
|
||||
creature->AI()->Talk(SAY_FLOON_ATTACK, player);
|
||||
creature->AI()->AttackStart(player);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnGossipHello(Player* player, Creature* creature) override
|
||||
{
|
||||
if (player->GetQuestStatus(QUEST_CRACK_SKULLS) == QUEST_STATUS_INCOMPLETE)
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_FLOON1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF);
|
||||
|
||||
SendGossipMenuFor(player, 9442, creature->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_floonAI(creature);
|
||||
}
|
||||
|
||||
struct npc_floonAI : public ScriptedAI
|
||||
{
|
||||
npc_floonAI(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
m_uiNormFaction = creature->GetFaction();
|
||||
}
|
||||
|
||||
uint32 m_uiNormFaction;
|
||||
uint32 Silence_Timer;
|
||||
uint32 Frostbolt_Timer;
|
||||
uint32 FrostNova_Timer;
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
Silence_Timer = 2000;
|
||||
Frostbolt_Timer = 4000;
|
||||
FrostNova_Timer = 9000;
|
||||
if (me->GetFaction() != m_uiNormFaction)
|
||||
me->SetFaction(m_uiNormFaction);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override { }
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
|
||||
if (Silence_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_SILENCE);
|
||||
Silence_Timer = 30000;
|
||||
}
|
||||
else Silence_Timer -= diff;
|
||||
|
||||
if (FrostNova_Timer <= diff)
|
||||
{
|
||||
DoCast(me, SPELL_FROST_NOVA);
|
||||
FrostNova_Timer = 20000;
|
||||
}
|
||||
else FrostNova_Timer -= diff;
|
||||
|
||||
if (Frostbolt_Timer <= diff)
|
||||
{
|
||||
DoCastVictim(SPELL_FROSTBOLT);
|
||||
Frostbolt_Timer = 5000;
|
||||
}
|
||||
else Frostbolt_Timer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/*######
|
||||
## npc_isla_starmane
|
||||
######*/
|
||||
@@ -840,7 +715,6 @@ void AddSC_terokkar_forest()
|
||||
// Theirs
|
||||
new npc_unkor_the_ruthless();
|
||||
new npc_rotting_forest_rager();
|
||||
new npc_floon();
|
||||
new npc_isla_starmane();
|
||||
new go_skull_pile();
|
||||
new npc_slim();
|
||||
|
||||
@@ -96,24 +96,17 @@ struct npc_pet_hunter_snake_trap : public ScriptedAI
|
||||
{
|
||||
_init = true;
|
||||
|
||||
CreatureTemplate const* Info = me->GetCreatureTemplate();
|
||||
CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(me->GetLevel(), Info->unit_class);
|
||||
uint32 health = uint32(107 * (me->GetLevel() - 40) * 0.025f);
|
||||
me->SetCreateHealth(health);
|
||||
|
||||
for (uint8 stat = 0; stat < MAX_STATS; ++stat)
|
||||
{
|
||||
me->SetStat(Stats(stat), 0);
|
||||
me->SetCreateStat(Stats(stat), 0);
|
||||
}
|
||||
|
||||
me->SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
|
||||
me->SetMaxHealth(health);
|
||||
|
||||
//Add delta to make them not all hit the same time
|
||||
uint32 delta = urand(0, 700);
|
||||
me->SetAttackTime(BASE_ATTACK, Info->BaseAttackTime + delta);
|
||||
me->SetStatFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER, float(stats->AttackPower));
|
||||
me->CastSpell(me, SPELL_HUNTER_DEADLY_POISON_PASSIVE, true);
|
||||
me->SetAttackTime(BASE_ATTACK, me->GetAttackTime(BASE_ATTACK) + delta);
|
||||
|
||||
if (me->GetEntry() == NPC_VENOMOUS_SNAKE)
|
||||
DoCastSelf(SPELL_HUNTER_DEADLY_POISON_PASSIVE, true);
|
||||
|
||||
// Glyph of Snake Trap
|
||||
if (Unit* owner = me->GetOwner())
|
||||
|
||||
Reference in New Issue
Block a user