Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-06-03 23:16:28 +08:00
40 changed files with 555 additions and 243 deletions
@@ -2383,20 +2383,45 @@ public:
return GetCaster()->GetTypeId() == TYPEID_UNIT;
}
void CheckEnergy()
void CalculatePower()
{
if (GetCaster()->GetPower(POWER_ENERGY) >= 100)
Unit* caster = GetCaster();
if (!caster)
return;
SpellInfo const* spellInfo = GetSpellInfo();
if (!spellInfo)
return;
// Check if the effect is energize
if (spellInfo->Effects[EFFECT_1].Effect == SPELL_EFFECT_ENERGIZE)
{
GetCaster()->CastSpell(GetCaster(), SPELL_OVERHEAT, true);
if (Vehicle* vehicle = GetCaster()->GetVehicleKit())
if (Unit* passenger = vehicle->GetPassenger(0))
sCreatureTextMgr->SendChat(GetCaster()->ToCreature(), SAY_OVERHEAT, passenger);
int32 energizeAmount = spellInfo->Effects[EFFECT_1].CalcValue(caster);
// Apply the power gain directly to the caster
caster->ModifyPower(POWER_ENERGY, energizeAmount);
}
if (caster->GetPower(POWER_ENERGY) >= 100)
{
caster->CastSpell(caster, SPELL_OVERHEAT, true);
if (Vehicle* vehicle = caster->GetVehicleKit())
if (Unit* passenger = vehicle->GetPassenger(0))
sCreatureTextMgr->SendChat(caster->ToCreature(), SAY_OVERHEAT, passenger);
}
}
void PreventPowerGainOnHit(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
}
void Register() override
{
AfterHit += SpellHitFn(spell_igb_cannon_blast_SpellScript::CheckEnergy);
OnCast += SpellCastFn(spell_igb_cannon_blast_SpellScript::CalculatePower);
OnEffectHitTarget += SpellEffectFn(spell_igb_cannon_blast_SpellScript::PreventPowerGainOnHit, EFFECT_1, SPELL_EFFECT_ENERGIZE);
}
};
@@ -869,85 +869,29 @@ private:
bool _removeHealers;
};
class spell_sindragosa_unchained_magic : public SpellScriptLoader
class spell_sindragosa_unchained_magic : public SpellScript
{
public:
spell_sindragosa_unchained_magic() : SpellScriptLoader("spell_sindragosa_unchained_magic") { }
PrepareSpellScript(spell_sindragosa_unchained_magic);
class spell_sindragosa_unchained_magic_SpellScript : public SpellScript
void FilterTargets(std::list<WorldObject*>& unitList)
{
PrepareSpellScript(spell_sindragosa_unchained_magic_SpellScript);
void FilterTargets(std::list<WorldObject*>& unitList)
{
std::list<WorldObject*> healList = unitList;
std::list<WorldObject*> dpsList = unitList;
unitList.clear();
uint32 maxSize = uint32(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 3 : 1);
healList.remove_if(UnchainedMagicTargetSelector(false));
if (healList.size() > maxSize)
Acore::Containers::RandomResize(healList, maxSize);
dpsList.remove_if(UnchainedMagicTargetSelector(true));
if (dpsList.size() > maxSize)
Acore::Containers::RandomResize(dpsList, maxSize);
unitList.splice(unitList.begin(), healList);
unitList.splice(unitList.begin(), dpsList);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sindragosa_unchained_magic_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sindragosa_unchained_magic_SpellScript();
std::list<WorldObject*> healList = unitList;
std::list<WorldObject*> dpsList = unitList;
unitList.clear();
uint32 maxSize = uint32(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 3 : 1);
healList.remove_if(UnchainedMagicTargetSelector(false));
if (healList.size() > maxSize)
Acore::Containers::RandomResize(healList, maxSize);
dpsList.remove_if(UnchainedMagicTargetSelector(true));
if (dpsList.size() > maxSize)
Acore::Containers::RandomResize(dpsList, maxSize);
unitList.splice(unitList.begin(), healList);
unitList.splice(unitList.begin(), dpsList);
}
class spell_sindragosa_unchained_magic_AuraScript : public AuraScript
void Register() override
{
PrepareAuraScript(spell_sindragosa_unchained_magic_AuraScript);
std::map<uint32, uint32> _lastMSTimeForSpell;
bool Validate(SpellInfo const* /*spellInfo*/) override
{
_lastMSTimeForSpell.clear();
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return false;
uint32 currMSTime = GameTime::GetGameTimeMS().count();
std::map<uint32, uint32>::iterator itr = _lastMSTimeForSpell.find(spellInfo->Id);
if (itr != _lastMSTimeForSpell.end())
{
uint32 lastMSTime = itr->second;
itr->second = currMSTime;
if (getMSTimeDiff(lastMSTime, currMSTime) < 600)
return false;
return true;
}
_lastMSTimeForSpell[spellInfo->Id] = currMSTime;
return true;
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_sindragosa_unchained_magic_AuraScript::CheckProc);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_sindragosa_unchained_magic_AuraScript();
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sindragosa_unchained_magic::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
@@ -2012,7 +1956,7 @@ void AddSC_boss_sindragosa()
new boss_sindragosa();
new npc_ice_tomb();
new spell_sindragosa_s_fury();
new spell_sindragosa_unchained_magic();
RegisterSpellScript(spell_sindragosa_unchained_magic);
new spell_sindragosa_permeating_chill();
new spell_sindragosa_instability();
new spell_sindragosa_icy_grip();
@@ -665,6 +665,37 @@ public:
};
};
struct boss_kologarn_pit_kill_bunny : public NullCreatureAI
{
boss_kologarn_pit_kill_bunny(Creature* creature) : NullCreatureAI(creature) { }
void Reset() override
{
RectangleBoundary* _boundaryXY = new RectangleBoundary(1782.0f, 1832.0f, -56.0f, 8.0f);
ZRangeBoundary* _boundaryZ = new ZRangeBoundary(400.0f, 439.0f);
_boundaryIntersect = new BoundaryIntersectBoundary(_boundaryXY, _boundaryZ);
scheduler.Schedule(0s, [this](TaskContext context)
{
me->GetMap()->DoForAllPlayers([&](Player* player)
{
if (_boundaryIntersect->IsWithinBoundary(player->GetPosition()) && !player->IsGameMaster())
{
player->KillSelf(false);
}
});
context.Repeat(1s);
});
}
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
}
private:
BoundaryIntersectBoundary const* _boundaryIntersect;
};
// predicate function to select non main tank target
class StoneGripTargetSelector
{
@@ -894,6 +925,7 @@ void AddSC_boss_kologarn()
new boss_kologarn();
new boss_kologarn_arms();
new boss_kologarn_eyebeam();
RegisterUlduarCreatureAI(boss_kologarn_pit_kill_bunny);
// Spells
new spell_ulduar_stone_grip_cast_target();
@@ -86,7 +86,8 @@ enum SpellData
SPELL_HAND_PULSE_25_L = 64536,
SPELL_SELF_REPAIR = 64383,
SPELL_SLEEP = 64394,
SPELL_SLEEP_VISUAL_1 = 64393,
SPELL_SLEEP_VISUAL_2 = 64394,
};
enum NPCs
@@ -172,10 +173,11 @@ enum EVENTS
EVENT_JOIN_ACU = 35,
EVENT_START_PHASE4 = 36,
EVENT_FINISH = 50,
EVENT_SAY_VOLTRON_DEAD = 51,
EVENT_DISAPPEAR = 52,
EVENT_BERSERK = 53,
EVENT_BERSERK_2 = 54,
EVENT_STAND_UP_FRIENDLY = 51,
EVENT_SAY_VOLTRON_DEAD = 52,
EVENT_DISAPPEAR = 53,
EVENT_BERSERK = 54,
EVENT_BERSERK_2 = 55,
// Leviathan:
EVENT_SPELL_NAPALM_SHELL = 3,
@@ -754,17 +756,20 @@ public:
Position exitPos = me->GetPosition();
me->_ExitVehicle(&exitPos);
me->AttackStop();
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK);
me->GetMotionMaster()->Clear();
summons.DoAction(1337); // despawn summons of summons
summons.DespawnEntry(NPC_FLAMES_INITIAL);
summons.DespawnEntry(33576);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
float angle = VX001->GetOrientation();
float v_x = me->GetPositionX() + cos(angle) * 10.0f;
float v_y = me->GetPositionY() + std::sin(angle) * 10.0f;
me->GetMotionMaster()->MoveJump(v_x, v_y, 364.32f, 7.0f, 7.0f);
DoCastSelf(SPELL_SLEEP_VISUAL_1);
if( pInstance )
for( uint16 i = 0; i < 3; ++i )
if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) )
@@ -783,11 +788,20 @@ public:
computer->AI()->Talk(TALK_COMPUTER_TERMINATED);
events.Reset();
events.ScheduleEvent(EVENT_SAY_VOLTRON_DEAD, 6s);
events.ScheduleEvent(EVENT_STAND_UP_FRIENDLY, 6s);
}
break;
case EVENT_STAND_UP_FRIENDLY:
me->RemoveAurasDueToSpell(SPELL_SLEEP_VISUAL_1);
DoCastSelf(SPELL_SLEEP_VISUAL_2);
me->SetFaction(FACTION_FRIENDLY);
events.ScheduleEvent(EVENT_SAY_VOLTRON_DEAD, 4s);
break;
case EVENT_SAY_VOLTRON_DEAD:
Talk(SAY_V07TRON_DEATH);
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
if (pInstance)
pInstance->SetData(TYPE_MIMIRON, DONE);
// spawn chest
if (uint32 chestId = (hardmode ? RAID_MODE(GO_MIMIRON_CHEST_HARD, GO_MIMIRON_CHEST_HERO_HARD) : RAID_MODE(GO_MIMIRON_CHEST, GO_MIMIRON_CHEST_HERO)))
{
@@ -797,11 +811,9 @@ public:
go->SetLootRecipient(me->GetMap());
}
}
events.ScheduleEvent(EVENT_DISAPPEAR, 15s);
events.ScheduleEvent(EVENT_DISAPPEAR, 9s);
break;
case EVENT_DISAPPEAR:
if( pInstance )
pInstance->SetData(TYPE_MIMIRON, DONE);
DoCastSelf(SPELL_TELEPORT);
summons.DespawnAll();
break;
@@ -100,6 +100,15 @@ public:
Position normalChestPosition = { 1967.152588f, -204.188461f, 432.686951f, 5.50957f };
Position hardChestPosition = { 2035.94600f, -202.084885f, 432.686859f, 3.164077f };
// Mimiron Tram
ObjectGuid m_mimironTramGUID;
ObjectGuid m_mimironActivateTramGUID;
ObjectGuid m_mimironTramRocketBoosterGUID;
ObjectGuid m_mimironTramTurnaround1GUID;
ObjectGuid m_mimironTramTurnaround2GUID;
ObjectGuid m_mimironCallTramCenterGUID;
ObjectGuid m_mimironCallTramMimironGUID;
// Mimiron
ObjectGuid m_MimironDoor[3];
ObjectGuid m_MimironLeviathanMKIIguid;
@@ -124,10 +133,12 @@ public:
ObjectGuid m_brannBronzebeardBaseCamp;
uint32 m_algalonTimer;
// Ancient Gate
const Position triggerAncientGatePosition = { 1883.65f, 269.272f, 418.406f };
// Shared
EventMap _events;
bool m_mimironTramUsed;
ObjectGuid m_mimironTramGUID;
ObjectGuid m_keepersgateGUID;
ObjectGuid m_keepersGossipGUID[4];
@@ -170,7 +181,18 @@ public:
// mimiron tram:
instance->LoadGrid(2307.0f, 284.632f);
if (GameObject* MimironTram = instance->GetGameObject(m_mimironTramGUID))
{
player->UpdateVisibilityOf(MimironTram);
if (StaticTransport* t = MimironTram->ToStaticTransport())
{
if (GameObject* go = instance->GetGameObject(m_mimironTramRocketBoosterGUID))
if (!go->GetTransport())
t->AddPassenger(go, true);
if (GameObject* go = instance->GetGameObject(m_mimironActivateTramGUID))
if (!go->GetTransport())
t->AddPassenger(go, true);
}
}
if (!m_uiAlgalonGUID && m_algalonTimer && (m_algalonTimer <= 60 || m_algalonTimer == TIMER_ALGALON_TO_SUMMON))
{
@@ -553,11 +575,30 @@ public:
case GO_SNOW_MOUND:
gameObject->EnableCollision(false);
break;
// Mimiron Tram
case GO_MIMIRON_TRAM:
if (GetData(TYPE_MIMIRON) == DONE)
m_mimironTramUsed = true;
m_mimironTramGUID = gameObject->GetGUID();
break;
case GO_MIMIRON_TRAM_ROCKET_BOOSTER:
m_mimironTramRocketBoosterGUID = gameObject->GetGUID();
break;
case GO_MIMIRON_ACTIVATE_TRAM:
m_mimironActivateTramGUID = gameObject->GetGUID();
break;
case GO_MIMIRON_CALL_TRAM_CENTER:
m_mimironCallTramCenterGUID = gameObject->GetGUID();
break;
case GO_MIMIRON_CALL_TRAM_MIMIRON:
m_mimironCallTramMimironGUID = gameObject->GetGUID();
break;
case GO_DOODAD_UL_TRAIN_TURNAROUND01:
m_mimironTramTurnaround1GUID = gameObject->GetGUID();
break;
case GO_DOODAD_UL_TRAIN_TURNAROUND02:
m_mimironTramTurnaround2GUID = gameObject->GetGUID();
break;
// Algalon the Observer
case GO_CELESTIAL_PLANETARIUM_ACCESS_10:
case GO_CELESTIAL_PLANETARIUM_ACCESS_25:
@@ -668,8 +709,17 @@ public:
m_auiEncounter[type] = data;
if (GetData(TYPE_MIMIRON) == DONE && GetData(TYPE_FREYA) == DONE && GetData(TYPE_HODIR) == DONE && GetData(TYPE_THORIM) == DONE)
{
if (GameObject* go = instance->GetGameObject(m_keepersgateGUID))
go->RemoveGameObjectFlag(GO_FLAG_LOCKED);
scheduler.Schedule(45s, [this](TaskContext /*context*/)
{
if (GameObject* go = instance->GetGameObject(m_keepersgateGUID))
{
go->RemoveGameObjectFlag(GO_FLAG_LOCKED);
if (Creature* trigger = instance->SummonCreature(NPC_ANCIENT_GATE_WORLD_TRIGGER, triggerAncientGatePosition, nullptr, 10*IN_MILLISECONDS))
{
trigger->AI()->Talk(EMOTE_ANCIENT_GATE_UNLOCKED);
}
}
});
}
if (type == TYPE_MIMIRON && data == IN_PROGRESS) // after reaching him without tram and starting the fight
m_mimironTramUsed = true;
@@ -785,9 +835,51 @@ public:
if (StaticTransport* t = MimironTram->ToStaticTransport())
{
if (data == 0 && t->GetGoState() == GO_STATE_ACTIVE && t->GetPathProgress() == t->GetPauseTime())
{
MimironTram->SetGoState(GO_STATE_READY);
if (GameObject* rocketBooster = instance->GetGameObject(m_mimironTramRocketBoosterGUID))
rocketBooster->SetGoState(GO_STATE_ACTIVE);
if (GameObject* activateTramButton = instance->GetGameObject(m_mimironActivateTramGUID))
activateTramButton->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
if (GameObject* callTramCenterButton = instance->GetGameObject(m_mimironCallTramCenterGUID))
callTramCenterButton->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
scheduler.Schedule(30s, [this](TaskContext /*context*/)
{
if (GameObject* turnaround1 = instance->GetGameObject(m_mimironTramTurnaround1GUID))
turnaround1->UseDoorOrButton();
if (GameObject* rocketBooster = instance->GetGameObject(m_mimironTramRocketBoosterGUID))
rocketBooster->SetGoState(GO_STATE_READY);
}).Schedule(60s, [this](TaskContext /*context*/)
{
if (GameObject* activateTramButton = instance->GetGameObject(m_mimironActivateTramGUID))
activateTramButton->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
if (GameObject* callTramMimironButton = instance->GetGameObject(m_mimironCallTramMimironGUID))
callTramMimironButton->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
});
}
if (data == 1 && t->GetGoState() == GO_STATE_READY && t->GetPathProgress() == 0)
{
MimironTram->SetGoState(GO_STATE_ACTIVE);
if (GameObject* rocketBooster = instance->GetGameObject(m_mimironTramRocketBoosterGUID))
rocketBooster->SetGoState(GO_STATE_ACTIVE);
if (GameObject* activateTramButton = instance->GetGameObject(m_mimironActivateTramGUID))
activateTramButton->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
if (GameObject* callTramMimironButton = instance->GetGameObject(m_mimironCallTramMimironGUID))
callTramMimironButton->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
scheduler.Schedule(33s, [this](TaskContext /*context*/)
{
if (GameObject* turnaround2 = instance->GetGameObject(m_mimironTramTurnaround2GUID))
turnaround2->UseDoorOrButton();
if (GameObject* rocketBooster = instance->GetGameObject(m_mimironTramRocketBoosterGUID))
rocketBooster->SetGoState(GO_STATE_READY);
}).Schedule(63s, [this](TaskContext /*context*/)
{
if (GameObject* activateTramButton = instance->GetGameObject(m_mimironActivateTramGUID))
activateTramButton->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
if (GameObject* callTramCenterButton = instance->GetGameObject(m_mimironCallTramCenterGUID))
callTramCenterButton->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
});
}
}
break;
case DATA_BRANN_MEMOTESAY:
@@ -545,33 +545,6 @@ public:
}
};
class go_call_tram : public GameObjectScript
{
public:
go_call_tram() : GameObjectScript("go_call_tram") { }
bool OnGossipHello(Player* /*player*/, GameObject* go) override
{
InstanceScript* pInstance = go->GetInstanceScript();
if (!pInstance)
return false;
switch(go->GetEntry())
{
case 194914:
case 194438:
pInstance->SetData(DATA_CALL_TRAM, 0);
break;
case 194912:
case 194437:
pInstance->SetData(DATA_CALL_TRAM, 1);
break;
}
return true;
}
};
struct npc_salvaged_siege_engine : public VehicleAI
{
npc_salvaged_siege_engine(Creature* creature) : VehicleAI(creature) { }
@@ -609,7 +582,5 @@ void AddSC_ulduar()
new npc_ulduar_arachnopod_destroyer();
new spell_ulduar_arachnopod_damaged();
new AreaTrigger_at_celestial_planetarium_enterance();
new go_call_tram();
RegisterCreatureAI(npc_salvaged_siege_engine);
}
@@ -215,7 +215,15 @@ enum UlduarGameObjects
GO_KOLOGARN_DOORS = 194553,
GO_KEEPERS_GATE = 194255,
GO_XT002_DOORS = 194631,
// Tram
GO_MIMIRON_TRAM = 194675,
GO_MIMIRON_ACTIVATE_TRAM = 194437,
GO_MIMIRON_CALL_TRAM_CENTER = 194914,
GO_MIMIRON_CALL_TRAM_MIMIRON = 194912,
GO_MIMIRON_TRAM_ROCKET_BOOSTER = 194904,
GO_DOODAD_UL_TRAIN_TURNAROUND01 = 194915, // center
GO_DOODAD_UL_TRAIN_TURNAROUND02 = 194913, // mimiron
// Mimiron, Hodir, Vezax
GO_MIMIRON_ELEVATOR = 194749,
@@ -290,6 +298,10 @@ enum UlduarMisc
// Freya, Hodir, Mimiron, Thorim
EVENT_KEEPER_TELEPORTED = 62941,
// Ancient Gate
NPC_ANCIENT_GATE_WORLD_TRIGGER = 22515,
EMOTE_ANCIENT_GATE_UNLOCKED = 19,
// Yogg-Saron
ACTION_SARA_UPDATE_SUMMON_KEEPERS = 4,
KEEPER_FREYA = 0,