Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2025-03-14 21:37:02 +08:00
45 changed files with 2300 additions and 269 deletions
+2 -1
View File
@@ -38,6 +38,7 @@ EndScriptData */
#include "MotdMgr.h"
#include "ObjectMgr.h"
#include "ScriptMgr.h"
#include "ServerMailMgr.h"
#include "SkillDiscovery.h"
#include "SkillExtraItems.h"
#include "SmartAI.h"
@@ -1196,7 +1197,7 @@ public:
static bool HandleReloadMailServerTemplateCommand(ChatHandler* handler)
{
LOG_INFO("server.loading", "Reloading `server_mail_template` table");
sObjectMgr->LoadMailServerTemplates();
sServerMailMgr->LoadMailServerTemplates();
handler->SendGlobalGMSysMessage("DB table `server_mail_template` reloaded.");
return true;
}
+2 -3
View File
@@ -199,7 +199,7 @@ public:
return true;
}
static bool HandleGMTicketCompleteCommand(ChatHandler* handler, uint32 ticketId)
static bool HandleGMTicketCompleteCommand(ChatHandler* handler, uint32 ticketId, std::optional<std::string> response)
{
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
if (!ticket || ticket->IsClosed() || ticket->IsCompleted())
@@ -217,9 +217,8 @@ public:
return true;
}
char* response = strtok(nullptr, "\n");
if (response)
ticket->AppendResponse(response);
ticket->AppendResponse(response.value());
if (Player* player2 = ticket->GetPlayer())
{
@@ -84,7 +84,7 @@ struct boss_brutallus : public BossAI
ScheduleTimedEvent(11s, [&] {
DoCastVictim(SPELL_METEOR_SLASH);
}, 10s);
}, 12s);
ScheduleTimedEvent(30s, [&] {
DoCastVictim(SPELL_STOMP);
@@ -137,6 +137,7 @@ enum eMadrigosa
EVENT_MAD_6 = 6,
EVENT_MAD_7 = 7,
EVENT_MAD_8 = 8,
EVENT_MAD_8_1 = 800,
EVENT_MAD_9 = 9,
EVENT_MAD_10 = 10,
EVENT_MAD_11 = 11,
@@ -166,7 +167,7 @@ enum eMadrigosa
SPELL_BRUTALLUS_CHARGE = 44884,
SPELL_BRUTALLUS_FEL_FIREBALL = 44844,
SPELL_BRUTALLUS_FLAME_RING = 44874,
SPELL_BRUTALLUS_FLAME_RING = 44873,
SPELL_BRUTALLUS_BREAK_ICE = 46637,
};
@@ -261,6 +262,7 @@ struct npc_madrigosa : public NullCreatureAI
me->CastSpell(me, SPELL_MADRIGOSA_FROST_BLAST, false);
events.ScheduleEvent(EVENT_MAD_8, 3000);
events.ScheduleEvent(EVENT_MAD_8, 5000);
events.ScheduleEvent(EVENT_MAD_8_1, 6000);
events.ScheduleEvent(EVENT_MAD_8, 6500);
events.ScheduleEvent(EVENT_MAD_8, 7500);
events.ScheduleEvent(EVENT_MAD_8, 8500);
@@ -273,10 +275,13 @@ struct npc_madrigosa : public NullCreatureAI
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
me->CastSpell(brutallus, SPELL_MADRIGOSA_FROSTBOLT, false);
break;
case EVENT_MAD_8_1:
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
brutallus->CastSpell(brutallus, SPELL_BRUTALLUS_FLAME_RING, false);
break;
case EVENT_MAD_9:
if (Creature* brutallus = instance->GetCreature(DATA_BRUTALLUS))
{
brutallus->CastSpell(brutallus, SPELL_BRUTALLUS_FLAME_RING, true);
brutallus->RemoveAllAuras();
brutallus->CastSpell(brutallus, SPELL_BRUTALLUS_FEL_FIREBALL, false);
brutallus->AI()->Talk(YELL_INTRO_BREAK_ICE);
@@ -394,6 +394,7 @@ struct npc_demonic_vapor_trail : public NullCreatureAI
void Reset() override
{
me->CastSpell(me, SPELL_DEMONIC_VAPOR_TRAIL_PERIODIC, true);
me->DespawnOrUnsummon(20000);
}
void SpellHitTarget(Unit*, SpellInfo const* spellInfo) override
@@ -224,7 +224,7 @@ struct boss_kalecgos : public BossAI
{
BossAI::JustEngagedWith(who);
ScheduleTimedEvent(6s, [&] {
ScheduleTimedEvent(8s, [&] {
DoCastAOE(SPELL_ARCANE_BUFFET);
}, 8s);
@@ -232,17 +232,17 @@ struct boss_kalecgos : public BossAI
DoCastVictim(SPELL_FROST_BREATH);
}, 15s);
ScheduleTimedEvent(10s, [&] {
ScheduleTimedEvent(6s, [&] {
me->CastCustomSpell(RAND(44978, 45001, 45002, 45004, 45006, 45010), SPELLVALUE_MAX_TARGETS, 1, me, false);
}, 20s);
}, 6s, 7s);
ScheduleTimedEvent(25s, [&] {
DoCastVictim(SPELL_TAIL_LASH);
}, 15s);
ScheduleTimedEvent(20s, [&] {
ScheduleTimedEvent(13s, [&] {
DoCastAOE(SPELL_SPECTRAL_BLAST);
}, 15s, 25s);
}, 20s, 30s);
scheduler.Schedule(16s, [this](TaskContext)
{
@@ -345,9 +345,9 @@ struct boss_sathrovarr : public ScriptedAI
DoCastVictim(SPELL_SHADOW_BOLT);
}, 9s);
ScheduleTimedEvent(20s, [&] {
ScheduleTimedEvent(40s, [&] {
me->CastCustomSpell(SPELL_CURSE_OF_BOUNDLESS_AGONY, SPELLVALUE_MAX_TARGETS, 1, me, false);
}, 30s);
}, 40s);
ScheduleTimedEvent(20s, [&] {
if (roll_chance_i(20))
@@ -15,9 +15,11 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CreatureScript.h"
#include "InstanceMapScript.h"
#include "InstanceScript.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "sunwell_plateau.h"
@@ -148,8 +150,106 @@ class spell_cataclysm_breath : public SpellScript
}
};
enum SunbladeScout
{
NPC_SUNBLADE_PROTECTOR = 25507,
SAY_AGGRO = 0, // Enemies spotted! Attack while I try to activate a Protector!
SPELL_ACTIVATE_SUNBLADE_PROTECTOR = 46475,
SPELL_COSMETIC_STUN_IMMUNE_PERMANENT = 59123,
SPELL_FELBLOOD_CHANNEL = 46319,
SPELL_SINISTER_STRIKE = 46558,
};
struct npc_sunblade_scout : public ScriptedAI
{
npc_sunblade_scout(Creature* creature) : ScriptedAI(creature) { }
void Reset() override
{
scheduler.CancelAll();
ScheduleOOC();
me->SetCombatMovement(false);
me->SetReactState(REACT_AGGRESSIVE);
_protectorGUID.Clear();
}
void JustEngagedWith(Unit* /*who*/) override
{
scheduler.CancelAll();
me->CallForHelp(30.0f);
Talk(SAY_AGGRO);
std::list<Creature*> protectors;
GetCreatureListWithEntryInGrid(protectors, me, NPC_SUNBLADE_PROTECTOR, 100.0f); // range unknown
// Skip already activated protectors
protectors.remove_if([](Creature* trigger) {return !trigger->HasAura(SPELL_COSMETIC_STUN_IMMUNE_PERMANENT);});
protectors.sort(Acore::ObjectDistanceOrderPred(me));
if (protectors.empty())
ScheduleCombat();
Creature* closestProtector = protectors.front();
me->GetMotionMaster()->MoveFollow(closestProtector, 0.0f, 0.0f);
_protectorGUID = closestProtector->GetGUID();
me->ClearTarget();
me->SetReactState(REACT_PASSIVE);
scheduler.Schedule(1s, [this](TaskContext context)
{
if (_protectorGUID)
if (Creature* protector = ObjectAccessor::GetCreature(*me, _protectorGUID))
{
if (me->IsWithinRange(protector, 25.0f))
{
me->SetFacingToObject(protector);
DoCastSelf(SPELL_ACTIVATE_SUNBLADE_PROTECTOR);
scheduler.Schedule(5s, [this](TaskContext /*context*/)
{
ScheduleCombat();
});
return;
}
context.Repeat(1s);
return;
}
ScheduleCombat();
});
}
void ScheduleCombat()
{
me->SetReactState(REACT_AGGRESSIVE);
me->SetCombatMovement(true);
if (Unit* victim = me->GetVictim())
me->GetMotionMaster()->MoveChase(victim);
scheduler.Schedule(2s, 5s, [this](TaskContext context)
{
DoCastVictim(SPELL_SINISTER_STRIKE);
context.Repeat(7s, 8s);
});
}
void ScheduleOOC()
{
scheduler.Schedule(45s, [this](TaskContext context)
{
DoCastAOE(SPELL_FELBLOOD_CHANNEL);
context.Repeat();
});
}
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
if (!me->IsCombatMovementAllowed() || !UpdateVictim())
return;
DoMeleeAttackIfReady();
}
private:
ObjectGuid _protectorGUID;
};
void AddSC_instance_sunwell_plateau()
{
new instance_sunwell_plateau();
RegisterSpellScript(spell_cataclysm_breath);
RegisterSunwellPlateauCreatureAI(npc_sunblade_scout);
}
@@ -44,16 +44,12 @@ enum DataTypes
DATA_SATHROVARR = 10,
DATA_KJ_CONTROLLER = 11,
DATA_ANVEENA = 12,
DATA_KALECGOS_KJ = 13
};
enum DataTypesObjects
{
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_1 = 0,
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_2 = 1,
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_3 = 2,
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_4 = 3,
DATA_ICEBARRIER = 4,
DATA_KALECGOS_KJ = 13,
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_1 = 14,
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_2 = 15,
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_3 = 16,
DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_4 = 17,
DATA_ICEBARRIER = 18,
};
enum CreatureIds
@@ -86,6 +86,12 @@ struct npc_forest_frog : public ScriptedAI
if (eventTimer)
{
Player* player = ObjectAccessor::GetPlayer(me->GetMap(), PlayerGUID);
if (!player)
{
events.CancelEvent(eventTimer);
eventTimer = 0;
return;
}
switch (events.ExecuteEvent())
{
case 1:
@@ -141,7 +147,7 @@ struct npc_forest_frog : public ScriptedAI
if (me->GetEntry() == NPC_ADARRAH)
Talk(SAY_CHEST_TALK + 1, player);
else
Talk(SAY_CHEST_TALK);
Talk(SAY_CHEST_TALK, player);
eventTimer = 4;
if (me->GetEntry() == NPC_GUNTER || me->GetEntry() == NPC_KYREN)
@@ -155,7 +161,7 @@ struct npc_forest_frog : public ScriptedAI
if (me->GetEntry() == NPC_ADARRAH)
Talk(SAY_GOODBYE + 1, player);
else
Talk(SAY_GOODBYE);
Talk(SAY_GOODBYE, player);
eventTimer = 5;
events.ScheduleEvent(eventTimer, 2000);
@@ -201,6 +207,9 @@ struct npc_forest_frog : public ScriptedAI
events.ScheduleEvent(eventTimer, 3000);
me->UpdateEntry(cEntry);
if (Player* player = ObjectAccessor::GetPlayer(me->GetMap(), PlayerGUID))
me->SetFacingToObject(player);
}
void SpellHit(Unit* caster, SpellInfo const* spell) override
@@ -208,7 +217,6 @@ struct npc_forest_frog : public ScriptedAI
if (spell->Id == SPELL_REMOVE_AMANI_CURSE && caster->IsPlayer() && me->GetEntry() == NPC_FOREST_FROG)
{
me->GetMotionMaster()->MoveIdle();
me->SetFacingToObject(caster);
PlayerGUID = caster->GetGUID();
if (roll_chance_i(2))
@@ -223,7 +231,6 @@ struct npc_forest_frog : public ScriptedAI
private:
InstanceScript* instance;
EventMap events;
uint8 eventTimer;
ObjectGuid PlayerGUID;
};
@@ -92,8 +92,9 @@ public:
{
_bossWave = TO_BE_DECIDED;
_retreat = 0;
trash = 0;
_trash = 0;
_currentWave = 0;
_initialWaves = false;
_encounterNPCs.clear();
_summonedNPCs.clear();
_baseAlliance.clear();
@@ -190,9 +191,9 @@ public:
if (creature->IsSummon() && _bossWave != TO_BE_DECIDED)
{
if (_currentWave == 0)
if (_currentWave == 0 && _initialWaves)
creature->SetReputationRewardDisabled(true);
DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, ++trash); // Update the instance wave count on new trash spawn
DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, ++_trash); // Update the instance wave count on new trash spawn
_encounterNPCs.insert(creature->GetGUID()); // Used for despawning on wipe
}
break;
@@ -230,10 +231,10 @@ public:
{
if (_bossWave != TO_BE_DECIDED)
{
DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, --trash); // Update the instance wave count on new trash death
DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, --_trash); // Update the instance wave count on new trash death
_encounterNPCs.erase(creature->GetGUID()); // Used for despawning on wipe
if (trash == 0) // It can reach negatives if trash spawned after a retreat are killed, it shouldn't affect anything. Also happens on retail
if (_trash == 0) // It can reach negatives if trash spawned after a retreat are killed, it shouldn't affect anything. Also happens on retail
SetData(DATA_SPAWN_WAVES, 1);
}
}
@@ -245,14 +246,12 @@ public:
_summonedNPCs.erase(creature->GetGUID());
break;
case NPC_WINTERCHILL:
_initialWaves = false;
[[fallthrough]];
case NPC_ANETHERON:
case NPC_KAZROGAL:
case NPC_AZGALOR:
if (Creature* jaina = GetCreature(DATA_JAINA))
jaina->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
if (Creature* thrall = GetCreature(DATA_THRALL))
thrall->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
SetData(DATA_RESET_WAVES, 1);
ResetWaves();
break;
}
}
@@ -364,6 +363,7 @@ public:
_retreat = 0;
if (GetBossState(DATA_WINTERCHILL) != DONE)
{
_initialWaves = true;
if (_bossWave == TO_BE_DECIDED)
for (ObjectGuid const& guid : _baseAlliance)
if (Creature* creature = instance->GetCreature(guid))
@@ -481,16 +481,19 @@ public:
SetData(DATA_RESET_WAVES, 0);
break;
case DATA_RESET_WAVES:
if (GetBossState(DATA_WINTERCHILL) != DONE)
_initialWaves = true;
scheduler.CancelGroup(CONTEXT_GROUP_WAVES);
_encounterNPCs.clear();
_summonedNPCs.clear();
_currentWave = 0;
trash = 0;
_trash = 0;
_bossWave = TO_BE_DECIDED;
_retreat = 0;
DoUpdateWorldState(WORLD_STATE_WAVES, _currentWave);
DoUpdateWorldState(WORLD_STATE_ENEMY, trash);
DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, trash);
DoUpdateWorldState(WORLD_STATE_ENEMY, _trash);
DoUpdateWorldState(WORLD_STATE_ENEMYCOUNT, _trash);
break;
}
@@ -517,7 +520,7 @@ public:
{
// No overlapping!
scheduler.CancelGroup(CONTEXT_GROUP_WAVES);
trash = 0; // Reset counter here to avoid resetting the counter from scheduled waves. Required because creatures killed for RP events counts towards the kill counter as well, confirmed in Retail.
_trash = 0; // Reset counter here to avoid resetting the counter from scheduled waves. Required because creatures killed for RP events counts towards the kill counter as well, confirmed in Retail.
scheduler.Schedule(1ms, [this, startWaves, maxWaves, timerptr](TaskContext context)
{
@@ -566,8 +569,8 @@ public:
}
}
protected:
int32 trash;
private:
int32 _trash;
uint8 _currentWave;
uint8 _bossWave;
uint8 _retreat;
@@ -581,6 +584,16 @@ public:
GuidSet _ancientGemHorde;
GuidSet _roaringFlameAlliance;
GuidSet _roaringFlameHorde;
bool _initialWaves;
void ResetWaves()
{
if (Creature* jaina = GetCreature(DATA_JAINA))
jaina->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
if (Creature* thrall = GetCreature(DATA_THRALL))
thrall->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
SetData(DATA_RESET_WAVES, 1);
}
};
};
@@ -155,7 +155,6 @@ public:
boss_kologarnAI(Creature* pCreature) : ScriptedAI(pCreature), vehicle(me->GetVehicleKit()), summons(me), breathReady(false)
{
m_pInstance = me->GetInstanceScript();
eyebeamTarget = nullptr;
assert(vehicle);
me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
}
@@ -167,8 +166,6 @@ public:
EventMap events;
SummonList summons;
Unit* eyebeamTarget;
bool _looksAchievement, breathReady;
uint8 _rubbleAchievement;
@@ -236,6 +233,7 @@ public:
_rubbleAchievement = 0;
_looksAchievement = true;
me->GetMotionMaster()->MoveTargetedHome();
me->SetDisableGravity(true);
me->DisableRotate(true);
@@ -295,6 +293,24 @@ public:
summons.Summon(cr);
}
void SummonedCreatureDespawn(Creature* cr) override
{
if (m_pInstance->GetData(TYPE_KOLOGARN) > NOT_STARTED)
return;
if (cr->GetEntry() == NPC_LEFT_ARM)
{
_left.Clear();
AttachLeftArm();
}
if (cr->GetEntry() == NPC_RIGHT_ARM)
{
_right.Clear();
AttachRightArm();
}
}
void JustDied(Unit*) override
{
summons.DespawnAll();
@@ -340,7 +356,7 @@ public:
void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
{
if (!me->IsAlive())
if (!me->IsAlive() || m_pInstance->GetData(TYPE_KOLOGARN) != IN_PROGRESS)
return;
if (!apply)
@@ -408,10 +424,7 @@ public:
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
EnterEvadeMode(EVADE_REASON_OTHER);
return;
}
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
@@ -465,12 +478,7 @@ public:
case EVENT_FOCUSED_EYEBEAM:
{
events.ScheduleEvent(EVENT_FOCUSED_EYEBEAM, 20s);
if ((eyebeamTarget = SelectTarget(SelectTargetMethod::MinDistance, 0, 0, true)))
{
me->CastSpell(eyebeamTarget, SPELL_FOCUSED_EYEBEAM_SUMMON, false);
}
me->CastSpell(me, SPELL_FOCUSED_EYEBEAM_SUMMON, false);
Talk(EMOTE_EYES);
return;
}
@@ -621,14 +629,14 @@ public:
}
struct boss_kologarn_eyebeamAI : public ScriptedAI
{
boss_kologarn_eyebeamAI(Creature* c) : ScriptedAI(c), _timer(1), _damaged(false), justSpawned(true)
boss_kologarn_eyebeamAI(Creature* c) : ScriptedAI(c), _timer(1), _damaged(false)
{
m_pInstance = (InstanceScript*)c->GetInstanceScript();
}
InstanceScript* m_pInstance;
uint32 _timer;
bool _damaged, justSpawned;
bool _damaged;
void DamageDealt(Unit* /*victim*/, uint32& damage, DamageEffectType /*damageType*/, SpellSchoolMask /*damageSchoolMask*/) override
{
@@ -640,24 +648,34 @@ public:
}
}
void UpdateAI(uint32 diff) override
void IsSummonedBy(WorldObject* summoner) override
{
if (justSpawned)
if (!summoner)
{
me->DespawnOrUnsummon(10000);
return;
}
// Should only work on playable characters
if (Player* player = summoner->ToPlayer())
{
me->Attack(player, false);
me->GetMotionMaster()->MoveChase(player);
if (Creature* cr = ObjectAccessor::GetCreature(*me, m_pInstance->GetGuidData(TYPE_KOLOGARN)))
{
me->CastSpell(cr, me->GetEntry() == NPC_EYE_LEFT ? SPELL_FOCUSED_EYEBEAM_LEFT : SPELL_FOCUSED_EYEBEAM_RIGHT, true);
}
me->CastSpell(me, SPELL_FOCUSED_EYEBEAM, true);
justSpawned = false;
}
}
void UpdateAI(uint32 diff) override
{
if (_timer)
{
_timer += diff;
if (_timer >= 2000)
{
me->CastSpell(me, (me->GetMap()->Is25ManRaid() ? SPELL_FOCUSED_EYEBEAM_25 : SPELL_FOCUSED_EYEBEAM_10), true);
me->CastSpell(me, SPELL_FOCUSED_EYEBEAM, true);
_timer = 0;
}
}
@@ -665,6 +683,52 @@ public:
};
};
class spell_kologarn_focused_eyebeam : public SpellScript
{
PrepareSpellScript(spell_kologarn_focused_eyebeam);
bool Load() override
{
return GetCaster()->IsCreature();
}
void FilterTargetsInitial(std::list<WorldObject*>& targets)
{
std::list<Unit*> newTargets;
Creature* creature = GetCaster()->ToCreature();
// Select 3 most distant targets
GetCaster()->GetAI()->SelectTargetList(newTargets, 3, SelectTargetMethod::MaxDistance, 0, NonTankTargetSelector(creature, true));
// If no distant targets available, get 1 target from original list
if (newTargets.empty())
{
if (!targets.empty())
{
while (1 < targets.size())
{
std::list<WorldObject*>::iterator itr = targets.begin();
advance(itr, urand(0, targets.size() - 1));
targets.erase(itr);
}
}
return;
}
// Clear original targets
targets.clear();
// Select a random target
std::list<Unit*>::iterator head = newTargets.begin();
advance(head, urand(0, newTargets.size() - 1));
targets.push_back(*head);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kologarn_focused_eyebeam::FilterTargetsInitial, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
struct boss_kologarn_pit_kill_bunny : public NullCreatureAI
{
boss_kologarn_pit_kill_bunny(Creature* creature) : NullCreatureAI(creature) { }
@@ -724,18 +788,16 @@ class spell_ulduar_stone_grip_cast_target : public SpellScript
bool Load() override
{
if (!GetCaster()->IsCreature())
return false;
return true;
return GetCaster()->IsCreature();
}
void FilterTargetsInitial(std::list<WorldObject*>& targets)
{
// Remove "main tank" and non-player targets
targets.remove_if (StoneGripTargetSelector(GetCaster()->ToCreature(), GetCaster()->GetVictim()));
targets.remove_if(StoneGripTargetSelector(GetCaster()->ToCreature(), GetCaster()->GetVictim()));
// Maximum affected targets per difficulty mode
uint32 maxTargets = 1;
if (GetSpellInfo()->Id == 63981)
if (GetSpellInfo()->Id == SPELL_STONE_GRIP_25)
maxTargets = 3;
// Return a random amount of targets based on maxTargets
@@ -882,6 +944,7 @@ void AddSC_boss_kologarn()
RegisterSpellScript(spell_ulduar_stone_grip_cast_target);
RegisterSpellScript(spell_ulduar_stone_grip_aura);
RegisterSpellScript(spell_ulduar_squeezed_lifeless);
RegisterSpellScript(spell_kologarn_focused_eyebeam);
RegisterSpellAndAuraScriptPair(spell_kologarn_stone_shout, spell_kologarn_stone_shout_aura);
// Achievements
@@ -338,8 +338,7 @@ void OPvPCapturePointZM_Graveyard::SetBeaconState(TeamId controlling_factionId)
bool OPvPCapturePointZM_Graveyard::CanTalkTo(Player* player, Creature* c, GossipMenuItems const& /*gso*/)
{
ObjectGuid guid = c->GetGUID();
auto itr = _creatureTypes.find(guid.GetCounter());
auto itr = _creatureTypes.find(c->GetSpawnId());
if (itr != _creatureTypes.end())
{
if (itr->second == ZM_ALLIANCE_FIELD_SCOUT && player->GetTeamId() == TEAM_ALLIANCE && m_BothControllingFactionId == TEAM_ALLIANCE && !m_FlagCarrierGUID && m_GraveyardState != ZM_GRAVEYARD_A)
+14 -15
View File
@@ -16,10 +16,10 @@
*/
#include "CreatureScript.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "PlayerScript.h"
#include "QueryResult.h"
#include "ServerMailMgr.h"
class ServerMailReward : public PlayerScript
{
@@ -30,13 +30,14 @@ public:
void OnPlayerLogin(Player* player) override
{
// Retrieve all server mail records and session only once
auto const& serverMailStore = sObjectMgr->GetAllServerMailStore();
auto const& serverMailStore = sServerMailMgr->GetAllServerMailStore();
WorldSession* session = player->GetSession();
// We should always have a session, just incase
if (!session)
return;
uint32 playerGUID = player->GetGUID().GetCounter();
bool isAlliance = player->GetTeamId() == TEAM_ALLIANCE;
for (auto const& [mailId, servMail] : serverMailStore)
{
@@ -45,26 +46,24 @@ public:
stmt->SetData(1, mailId);
// Capture servMail by value
auto callback = [session, servMailWrapper = std::reference_wrapper<ServerMail const>(servMail)](PreparedQueryResult result)
auto callback = [session, servMailWrapper = std::reference_wrapper<ServerMail const>(servMail), isAlliance](PreparedQueryResult result)
{
ServerMail const& servMail = servMailWrapper.get(); // Dereference the wrapper to get the original object
ServerMail const& servMail = servMailWrapper.get(); // Dereference the wrapper to get the original object
if (!result)
{
sObjectMgr->SendServerMail(
uint32 money = isAlliance ? servMail.moneyA : servMail.moneyH;
std::vector<ServerMailItems> const& items = isAlliance ? servMail.itemsA : servMail.itemsH;
std::vector<ServerMailCondition> const& conditions = servMail.conditions;
sServerMailMgr->SendServerMail(
session->GetPlayer(),
servMail.id,
servMail.reqLevel,
servMail.reqPlayTime,
servMail.moneyA,
servMail.moneyH,
servMail.itemA,
servMail.itemCountA,
servMail.itemH,
servMail.itemCountH,
money,
items,
conditions,
servMail.subject,
servMail.body,
servMail.active
servMail.body
);
}
};