Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-07-19 17:25:43 +08:00
141 changed files with 225779 additions and 226517 deletions

View File

@@ -42,7 +42,9 @@ public:
static ChatCommandTable ticketResponseCommandTable =
{
{ "append", HandleGMTicketResponseAppendCommand, SEC_GAMEMASTER, Console::Yes },
{ "appendln", HandleGMTicketResponseAppendLnCommand, SEC_GAMEMASTER, Console::Yes }
{ "appendln", HandleGMTicketResponseAppendLnCommand, SEC_GAMEMASTER, Console::Yes },
{ "delete", HandleGMTicketResponseDeleteCommand, SEC_GAMEMASTER, Console::Yes },
{ "show", HandleGMTicketResponseShowCommand, SEC_GAMEMASTER, Console::Yes }
};
static ChatCommandTable ticketCommandTable =
{
@@ -436,10 +438,9 @@ public:
return true;
}
static bool _HandleGMTicketResponseAppendCommand(uint32 ticketId, bool newLine, ChatHandler* handler)
static bool TicketResponseAppend(uint32 ticketId, bool newLine, ChatHandler* handler, std::string response)
{
char* response = strtok(nullptr, "\n");
if (!response)
if (response.empty())
return false;
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
@@ -459,22 +460,74 @@ public:
}
CharacterDatabaseTransaction trans = CharacterDatabaseTransaction(nullptr);
ticket->AppendResponse(response);
if (newLine)
ticket->AppendResponse("\n");
ticket->AppendResponse(response);
ticket->SaveToDB(trans);
sTicketMgr->UpdateLastChange();
std::string msg = ticket->FormatMessageString(*handler, nullptr, nullptr, nullptr, nullptr);
msg += handler->PGetParseString(LANG_COMMAND_TICKETRESPONSEAPPENDED, response);
handler->PSendSysMessage(msg.c_str());
return true;
}
static bool HandleGMTicketResponseAppendCommand(ChatHandler* handler, uint32 ticketId)
static bool HandleGMTicketResponseAppendCommand(ChatHandler* handler, uint32 ticketId, Tail res)
{
return _HandleGMTicketResponseAppendCommand(ticketId, false, handler);
return TicketResponseAppend(ticketId, false, handler, res.data());
}
static bool HandleGMTicketResponseAppendLnCommand(ChatHandler* handler, uint32 ticketId)
static bool HandleGMTicketResponseAppendLnCommand(ChatHandler* handler, uint32 ticketId, Tail res)
{
return _HandleGMTicketResponseAppendCommand(ticketId, true, handler);
return TicketResponseAppend(ticketId, true, handler, res.data());
}
static bool HandleGMTicketResponseDeleteCommand(ChatHandler* handler, uint32 ticketId)
{
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
// Don't allow deleting response for a closed ticket.
if (!ticket || ticket->IsClosed())
{
handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST);
return true;
}
// Cannot delete response for a ticket that is assigned to someone else.
//! Console excluded
Player* player = handler->GetSession() ? handler->GetSession()->GetPlayer() : nullptr;
if (player && ticket->IsAssignedNotTo(player->GetGUID()))
{
handler->PSendSysMessage(LANG_COMMAND_TICKETALREADYASSIGNED, ticket->GetId());
return true;
}
CharacterDatabaseTransaction trans = CharacterDatabaseTransaction(nullptr);
ticket->DeleteResponse();
ticket->SaveToDB(trans);
sTicketMgr->UpdateLastChange();
std::string msg = ticket->FormatMessageString(*handler, nullptr, nullptr, nullptr, nullptr);
msg += handler->PGetParseString(LANG_COMMAND_TICKETRESPONSEDELETED, player ? player->GetName() : "Console");
handler->SendGlobalGMSysMessage(msg.c_str());
return true;
}
static bool HandleGMTicketResponseShowCommand(ChatHandler* handler, uint32 ticketId)
{
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
if (!ticket)
{
handler->SendSysMessage(LANG_COMMAND_TICKETNOTEXIST);
return true;
}
std::string msg = ticket->FormatMessageString(*handler, nullptr, nullptr, nullptr, nullptr);
msg += handler->PGetParseString(LANG_COMMAND_TICKETLISTRESPONSE, ticket->GetResponse());
handler->PSendSysMessage(msg.c_str());
return true;
}
};

View File

@@ -81,6 +81,8 @@ enum Says
SAY_RAISE_SKELETONS = 1,
SAY_SLAY = 2,
SAY_DEATH = 3,
SAY_XHEALTH = 14,
SAY_SHADOWFLAME = 15,
SAY_MAGE = 4,
SAY_WARRIOR = 5,
@@ -109,6 +111,7 @@ enum Paths
enum GameObjects
{
GO_DRAKONID_BONES = 179804,
GO_PORTCULLIS_ACTIVE = 164726,
GO_PORTCULLIS_TOBOSSROOMS = 175186
};
@@ -136,6 +139,8 @@ enum Spells
SPELL_SHADOW_COMMAND = 22667,
SPELL_FEAR = 22678,
SPELL_SHADOWBLINK = 22664,
SPELL_RAISE_DRAKONID = 23362,
SPELL_SUMMON_DRAKONID_CORPSE = 23363,
SPELL_NEFARIANS_BARRIER = 22663,
@@ -273,6 +278,12 @@ public:
{
nefarian->DespawnOrUnsummon();
}
std::list<GameObject*> drakonidBones;
me->GetGameObjectListWithEntryInGrid(drakonidBones, GO_DRAKONID_BONES, DEFAULT_VISIBILITY_INSTANCE);
for (auto const& bones : drakonidBones)
{
bones->DespawnOrUnsummon();
}
}
else
{
@@ -521,19 +532,10 @@ public:
struct boss_nefarian : public BossAI
{
boss_nefarian(Creature* creature) : BossAI(creature, DATA_NEFARIAN), _introDone(false)
{
Initialize();
}
void Initialize()
{
Phase3 = false;
}
boss_nefarian(Creature* creature) : BossAI(creature, DATA_NEFARIAN), _introDone(false) { }
void Reset() override
{
Initialize();
me->SetReactState(REACT_PASSIVE);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetCanFly(true);
@@ -552,6 +554,16 @@ struct boss_nefarian : public BossAI
}
classesPresent.clear();
ScheduleHealthCheckEvent(20, [&]
{
DoCastSelf(SPELL_RAISE_DRAKONID, true);
Talk(SAY_RAISE_SKELETONS);
});
ScheduleHealthCheckEvent(5, [&]
{
Talk(SAY_XHEALTH);
});
}
void JustEngagedWith(Unit* /*who*/) override {}
@@ -587,6 +599,7 @@ struct boss_nefarian : public BossAI
if (id == 5)
{
DoCastAOE(SPELL_SHADOWFLAME_INITIAL);
Talk(SAY_SHADOWFLAME);
}
}
@@ -616,29 +629,6 @@ struct boss_nefarian : public BossAI
_introDone = true;
}
void DamageTaken(Unit* /*unit*/, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (me->HealthBelowPctDamaged(20, damage) && !Phase3)
{
std::list<Creature*> constructList;
me->GetCreatureListWithEntryInGrid(constructList, NPC_BONE_CONSTRUCT, 500.0f);
for (Creature* const& summon : constructList)
{
if (summon && !summon->IsAlive())
{
summon->Respawn();
summon->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
summon->SetReactState(REACT_AGGRESSIVE);
summon->SetStandState(UNIT_STAND_STATE_STAND);
DoZoneInCombat(summon);
}
}
Phase3 = true;
Talk(SAY_RAISE_SKELETONS);
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
@@ -762,7 +752,6 @@ struct boss_nefarian : public BossAI
}
private:
bool Phase3;
bool _introDone;
std::set<uint8> classesPresent;
};
@@ -797,7 +786,7 @@ struct npc_corrupted_totem : public ScriptedAI
}
me->AddAura(AURA_AVOIDANCE, me);
_scheduler.CancelAll();
scheduler.CancelAll();
}
void SetAura(bool apply) const
@@ -877,8 +866,7 @@ struct npc_corrupted_totem : public ScriptedAI
{
me->SetInCombatWithZone();
_scheduler
.Schedule(1ms, [this](TaskContext context)
scheduler.Schedule(1ms, [this](TaskContext context)
{
if (me->GetEntry() == NPC_TOTEM_C_FIRE_NOVA)
{
@@ -913,7 +901,7 @@ struct npc_corrupted_totem : public ScriptedAI
SetAura(false);
}
_scheduler.CancelAll();
scheduler.CancelAll();
}
void UpdateAI(uint32 diff) override
@@ -923,11 +911,10 @@ struct npc_corrupted_totem : public ScriptedAI
return;
}
_scheduler.Update(diff);
scheduler.Update(diff);
}
protected:
TaskScheduler _scheduler;
bool _auraAdded;
};
@@ -940,14 +927,14 @@ struct npc_drakonid_spawner : public ScriptedAI
if (action == ACTION_SPAWNER_STOP)
{
me->RemoveAurasDueToSpell(SPELL_SPAWN_DRAKONID_GEN);
_scheduler.CancelAll();
scheduler.CancelAll();
}
}
void IsSummonedBy(WorldObject* summoner) override
{
DoCastSelf(SPELL_SPAWN_DRAKONID_GEN);
_scheduler.Schedule(10s, 60s, [this](TaskContext /*context*/)
scheduler.Schedule(10s, 60s, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_SPAWN_CHROMATIC_DRAKONID);
});
@@ -957,46 +944,29 @@ struct npc_drakonid_spawner : public ScriptedAI
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
scheduler.Update(diff);
}
void SummonedCreatureDies(Creature* summon, Unit* /*unit*/) override
{
if (summon->GetEntry() != NPC_BONE_CONSTRUCT)
if (Creature* victor = ObjectAccessor::GetCreature(*me, _owner))
{
if (Creature* victor = ObjectAccessor::GetCreature(*me, _owner))
{
victor->AI()->DoAction(ACTION_NEFARIUS_ADD_KILLED);
}
ObjectGuid summonGuid = summon->GetGUID();
summon->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
summon->SetHomePosition(summon->GetPosition());
_scheduler.Schedule(1s, [this, summonGuid](TaskContext /*context*/)
{
if (Creature* construct = ObjectAccessor::GetCreature(*me, summonGuid))
{
construct->SetVisible(false);
}
}).Schedule(2s, [this, summonGuid](TaskContext /*context*/)
{
if (Creature* construct = ObjectAccessor::GetCreature(*me, summonGuid))
{
construct->UpdateEntry(NPC_BONE_CONSTRUCT, true);
construct->SetReactState(REACT_PASSIVE);
construct->SetStandState(UNIT_STAND_STATE_DEAD);
construct->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
construct->SetCorpseRemoveTime(DAY * IN_MILLISECONDS);
construct->SetVisible(true);
}
});
victor->AI()->DoAction(ACTION_NEFARIUS_ADD_KILLED);
}
ObjectGuid summonGuid = summon->GetGUID();
scheduler.Schedule(1s, [this, summonGuid](TaskContext /*context*/)
{
if (Creature* construct = ObjectAccessor::GetCreature(*me, summonGuid))
{
construct->SetVisible(false);
construct->CastSpell(construct, SPELL_SUMMON_DRAKONID_CORPSE, true);
}
});
}
protected:
TaskScheduler _scheduler;
ObjectGuid _owner;
};

View File

@@ -20,24 +20,27 @@
#include "PassiveAI.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "TaskScheduler.h"
#include "karazhan.h"
enum Spells
{
// Ground Phase
SPELL_RAIN_OF_BONES = 37098,
SPELL_SMOKING_BLAST = 37057,
SPELL_FIREBALL_BARRAGE = 30282,
SPELL_SEARING_CINDERS = 30127,
// Air Phase
SPELL_BELLOWING_ROAR = 39427,
SPELL_CLEAVE = 30131,
SPELL_CHARRED_EARTH = 30129,
SPELL_DISTRACTING_ASH = 30130,
SPELL_SMOLDERING_BREATH = 30210,
SPELL_TAIL_SWEEP = 25653,
SPELL_SUMMON_SKELETON = 30170
SPELL_SMOLDERING_BREATH = 30210,
SPELL_CHARRED_EARTH = 30129,
SPELL_BELLOWING_ROAR = 36922,
// Air Phase
SPELL_SMOKING_BLAST = 30128,
SPELL_SMOKING_BLAST_T = 37057,
SPELL_RAIN_OF_BONES = 37098,
SPELL_SUMMON_SKELETON = 30170,
SPELL_DISTRACTING_ASH = 30130,
// Both Phases
SPELL_FIREBALL_BARRAGE = 30282
};
enum Says
@@ -188,21 +191,21 @@ struct boss_nightbane : public BossAI
void ScheduleGround()
{
scheduler.Schedule(30s, GROUP_GROUND, [this](TaskContext context)
{
DoCastAOE(SPELL_BELLOWING_ROAR);
context.Repeat(30s, 40s);
}).Schedule(15s, GROUP_GROUND, [this](TaskContext context)
scheduler.Schedule(18s, 25s, GROUP_GROUND, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_CHARRED_EARTH, 0, 100.0f, true);
context.Repeat(20s);
}).Schedule(10s, GROUP_GROUND, [this](TaskContext context)
}).Schedule(25s, 35s, GROUP_GROUND, [this](TaskContext context)
{
DoCastVictim(SPELL_SMOLDERING_BREATH);
context.Repeat(20s);
}).Schedule(45s, GROUP_GROUND, [this](TaskContext context)
{
DoCastAOE(SPELL_BELLOWING_ROAR);
context.Repeat(32s, 40s);
}).Schedule(12s, GROUP_GROUND, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
{
if (!me->HasInArc(M_PI, target))
{
@@ -210,14 +213,17 @@ struct boss_nightbane : public BossAI
}
}
context.Repeat(15s);
}).Schedule(14s, GROUP_GROUND, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_SEARING_CINDERS);
context.Repeat(10s);
}).Schedule(1500ms, GROUP_GROUND, [this](TaskContext context)
}).Schedule(5s, GROUP_GROUND, [this](TaskContext context)
{
DoCastVictim(SPELL_CLEAVE);
context.Repeat(1500ms, 45s);
context.Repeat(6s, 12s);
}).Schedule(25s, GROUP_GROUND, [this](TaskContext context)
{
if (SelectTarget(SelectTargetMethod::MinDistance, 0, -40.0f, true))
{
DoCastAOE(SPELL_FIREBALL_BARRAGE);
}
context.Repeat(3s);
});
}
@@ -225,7 +231,7 @@ struct boss_nightbane : public BossAI
{
_skeletonSpawnCounter = 0;
scheduler.Schedule(2s, GROUP_AIR, [this](TaskContext)
scheduler.Schedule(2s, GROUP_AIR, [this](TaskContext /*context*/)
{
DoResetThreatList();
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f))
@@ -244,26 +250,31 @@ struct boss_nightbane : public BossAI
}
});
}
}).Schedule(20s, GROUP_AIR, [this](TaskContext context)
}).Schedule(15s, GROUP_AIR, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random))
{
me->SetFacingToObject(target);
DoCast(target, SPELL_DISTRACTING_ASH);
DoCast(target, SPELL_SMOKING_BLAST_T);
}
context.Repeat(2s); //timer wrong?
}).Schedule(25s, GROUP_AIR, [this](TaskContext context)
context.Repeat(6s);
}).Schedule(15500ms, GROUP_AIR, [this](TaskContext context)
{
//5 seconds added due to double trigger?
//trigger for timer in original + in rain of bones
//timers need some investigation
me->SetFacingToObject(me->GetVictim());
DoCastVictim(SPELL_SMOKING_BLAST);
context.Repeat(1500ms); //timer wrong?
}).Schedule(13s, GROUP_AIR, [this](TaskContext context)
context.Repeat(1500ms);
}).Schedule(20s, GROUP_AIR, [this](TaskContext /*context*/)
{
DoCastOnFarAwayPlayers(SPELL_FIREBALL_BARRAGE, false, 80.0f);
context.Repeat(20s);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100.0f, true))
{
DoCast(target, SPELL_DISTRACTING_ASH);
}
}).Schedule(14s, GROUP_AIR, [this](TaskContext context)
{
if (SelectTarget(SelectTargetMethod::MinDistance, 0, -40.0f, true))
{
DoCastAOE(SPELL_FIREBALL_BARRAGE);
}
context.Repeat(3s);
});
}
@@ -407,22 +418,6 @@ struct boss_nightbane : public BossAI
summons.Summon(summon);
}
void DoCastOnFarAwayPlayers(uint32 spellid, bool triggered, float tresholddistance)
{
//resembles DoCastToAllHostilePlayers a bit/lot
ThreatContainer::StorageType targets = me->GetThreatMgr().GetThreatList();
for (ThreatContainer::StorageType::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
{
if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
{
if (unit->IsPlayer() && !unit->IsWithinDist(me, tresholddistance, false))
{
me->CastSpell(unit, spellid, triggered);
}
}
}
}
void TriggerHealthTakeOff()
{
if (_phase != PHASE_GROUND)
@@ -465,7 +460,7 @@ struct boss_nightbane : public BossAI
void ScheduleLand()
{
scheduler.Schedule(30s, GROUP_LAND, [this](TaskContext) /*context*/
scheduler.Schedule(35s, GROUP_LAND, [this](TaskContext) /*context*/
{
Talk(YELL_LAND_PHASE);
scheduler.CancelGroup(GROUP_AIR);
@@ -510,7 +505,6 @@ public:
{
if (InstanceScript* instance = go->GetInstanceScript())
{
// if (instance->GetBossState(DATA_NIGHTBANE) == NOT_STARTED || instance->GetBossState(DATA_NIGHTBANE) == FAIL)
if (instance->GetBossState(DATA_NIGHTBANE) == NOT_STARTED)
{
if (Creature* nightbane = instance->GetCreature(DATA_NIGHTBANE))
@@ -532,9 +526,30 @@ struct npc_nightbane_helper_target : public NullCreatureAI
npc_nightbane_helper_target(Creature* creature) : NullCreatureAI(creature) { me->SetDisableGravity(true); }
};
// 30282 - Fireball Barrage
class spell_nightbane_fireball_barrage : public SpellScript
{
PrepareSpellScript(spell_nightbane_fireball_barrage);
void FilterTargets(std::list<WorldObject*>& targets)
{
Unit* caster = GetCaster();
targets.remove_if([&](WorldObject* target) -> bool
{
return !target->IsPlayer() || caster->IsWithinCombatRange(target->ToUnit(), 40.0f);
});
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_nightbane_fireball_barrage::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
void AddSC_boss_nightbane()
{
RegisterKarazhanCreatureAI(boss_nightbane);
new go_blackened_urn();
RegisterKarazhanCreatureAI(npc_nightbane_helper_target);
RegisterSpellScript(spell_nightbane_fireball_barrage);
}

View File

@@ -31,7 +31,7 @@ enum Spells
{
SPELL_BRAIN_WASH_TOTEM = 24262,
SPELL_POWERFULL_HEALING_WARD = 24309,
SPELL_HEX = 24053,
SPELL_HEX = 17172,
SPELL_DELUSIONS_OF_JINDO = 24306,
SPELL_SUMMON_SHADE_OF_JINDO = 24308,
SPELL_BANISH = 24466,

View File

@@ -164,7 +164,7 @@ struct go_firework_show : public GameObjectAI
uint32 posIdx = _show->schedule.entries[_curIdx].spawnIndex;
if (posIdx < _show->spawns.size)
{
me->SummonGameObject(_show->schedule.entries[_curIdx].gameobjectId,
GameObject* go = me->SummonGameObject(_show->schedule.entries[_curIdx].gameobjectId,
_show->spawns.entries[posIdx].x,
_show->spawns.entries[posIdx].y,
_show->spawns.entries[posIdx].z,
@@ -174,6 +174,13 @@ struct go_firework_show : public GameObjectAI
_show->spawns.entries[posIdx].rot2,
_show->spawns.entries[posIdx].rot3,
0);
// trigger despawn animation for firework explosion
if (go)
{
go->DespawnOrUnsummon();
go->AddObjectToRemoveList();
}
}
uint32 ts = _show->schedule.entries[_curIdx].timestamp;

View File

@@ -243,6 +243,7 @@ struct npc_midsummer_bonfire : public ScriptedAI
if (_spellFocus)
{
_spellFocus->DespawnOrUnsummon();
_spellFocus->AddObjectToRemoveList();
_spellFocus = nullptr;
}
@@ -378,7 +379,10 @@ struct npc_midsummer_bonfire_despawner : public ScriptedAI
{
// spawnID is 0 for temp spawns
if (0 == (*itr)->GetSpawnId())
{
(*itr)->DespawnOrUnsummon();
(*itr)->AddObjectToRemoveList();
}
}
me->DespawnOrUnsummon();

View File

@@ -60,10 +60,10 @@ public:
{
DoCastVictim(SPELL_CLEAVE);
context.Repeat(8s, 16s);
}).Schedule(25s, [this](TaskContext context)
}).Schedule(20s, 25s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_RAIN_OF_FIRE, 0, 40.f, false);
context.Repeat(15s);
context.Repeat(12s, 35s);
}).Schedule(30s, [this](TaskContext context)
{
DoCastAOE(SPELL_HOWL_OF_AZGALOR);

View File

@@ -83,6 +83,5 @@ inline AI* GetAhnKahetAI(T* obj)
}
#define RegisterAhnKahetCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetAhnKahetAI)
#define RegisterAhnKahetGameObjectAI(ai_name) RegisterGameObjectAIWithFactory(ai_name, GetAhnKahetAI)
#endif // DEF_AHNKAHET_H

View File

@@ -331,11 +331,12 @@ class spell_ioc_repair_turret_aura : public AuraScript
enum blastCriteria
{
SPELL_SEAFORIUM_BLAST = 66676,
SPELL_HUGE_SEAFORIUM_BLAST = 66672,
SPELL_BOMB_INABLE_CREDIT = 68366,
SPELL_BOMB_INATION_CREDIT = 68367,
SPELL_SEAFORIUM_BLAST = 66676,
SPELL_SEAFORIUM_BLAST_H = 67814,
SPELL_HUGE_SEAFORIUM_BLAST = 66672,
SPELL_HUGE_SEAFORIUM_BLAST_H = 67813,
SPELL_BOMB_INABLE_CREDIT = 68366,
SPELL_BOMB_INATION_CREDIT = 68367
};
class spell_ioc_bomb_blast_criteria : public SpellScript
@@ -347,16 +348,20 @@ class spell_ioc_bomb_blast_criteria : public SpellScript
return ValidateSpellInfo({ SPELL_BOMB_INABLE_CREDIT, SPELL_BOMB_INATION_CREDIT });
}
void HandleGameObjectDamage(SpellEffIndex /*effIndex*/)
void HandleGameObjectDamage(SpellEffIndex /*effIndex*/)
{
uint32 creditSpell = 0;
Unit* owner = GetCaster()->GetOwner();
if (!owner)
return;
if (GetSpellInfo()->Id == SPELL_SEAFORIUM_BLAST)
owner->CastSpell(owner, SPELL_BOMB_INABLE_CREDIT, true);
else if (GetSpellInfo()->Id == SPELL_HUGE_SEAFORIUM_BLAST)
owner->CastSpell(owner, SPELL_BOMB_INATION_CREDIT, true);
uint32 spellId = GetSpellInfo()->Id;
if (spellId == SPELL_SEAFORIUM_BLAST || spellId == SPELL_SEAFORIUM_BLAST_H)
creditSpell = SPELL_BOMB_INABLE_CREDIT;
else if (spellId == SPELL_HUGE_SEAFORIUM_BLAST || spellId == SPELL_HUGE_SEAFORIUM_BLAST_H)
creditSpell = SPELL_BOMB_INATION_CREDIT;
owner->CastSpell(owner, creditSpell, true);
}
void Register() override

View File

@@ -115,7 +115,8 @@ enum MiscIds
SPELL_SHADOW_INFERNO_DAMAGE = 39646,
SPELL_CHAOTIC_CHARGE = 41033,
SPELL_DEMENTIA1 = 41406,
SPELL_DEMENTIA2 = 41409
SPELL_DEMENTIA2 = 41409,
SPELL_SUMMON_SHADOWFIENDS = 41159
};
template <class AI, class T>

View File

@@ -458,6 +458,32 @@ class spell_black_temple_dementia_aura : public AuraScript
}
};
// 39649 - Summon Shadowfiends
class spell_black_temple_summon_shadowfiends : public SpellScript
{
PrepareSpellScript(spell_black_temple_summon_shadowfiends);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SUMMON_SHADOWFIENDS });
}
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster)
return;
for (uint8 i = 0; i < 11; i++)
caster->CastSpell(caster, SPELL_SUMMON_SHADOWFIENDS, true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_black_temple_summon_shadowfiends::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_instance_black_temple()
{
new instance_black_temple();
@@ -473,5 +499,6 @@ void AddSC_instance_black_temple()
RegisterSpellScript(spell_black_temple_consuming_strikes_aura);
RegisterSpellScript(spell_black_temple_curse_of_vitality_aura);
RegisterSpellScript(spell_black_temple_dementia_aura);
RegisterSpellScript(spell_black_temple_summon_shadowfiends);
}

View File

@@ -1140,7 +1140,14 @@ class spell_kaelthas_mind_control : public SpellScript
{
targets.remove_if(Acore::ObjectGUIDCheck(victim->GetGUID(), true));
}
targets.remove_if(Acore::ObjectTypeIdCheck(TYPEID_PLAYER, false));
targets.remove_if([&](WorldObject const* target) -> bool
{
if (!target->ToPlayer())
return true;
return (!GetCaster()->IsWithinLOSInMap(target));
});
}
void HandleEffect(SpellEffIndex /*effIndex*/)

View File

@@ -79,37 +79,8 @@ struct boss_zereketh_the_unbound : public BossAI
}
};
// 36123, 39367 -- Seed of Corruption
class spell_zereketh_seed_of_corruption: public AuraScript
{
PrepareAuraScript(spell_zereketh_seed_of_corruption);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_CORRUPTION_PROC });
}
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
{
PreventDefaultAction();
uint32 val = GetSpellInfo()->GetEffect(EFFECT_1).BasePoints;
GetTarget()->RemoveAurasDueToSpell(GetSpellInfo()->Id);
if (GetCaster())
{
GetCaster()->CastCustomSpell(SPELL_CORRUPTION_PROC, SPELLVALUE_BASE_POINT0, val, GetTarget(), true);
}
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_zereketh_seed_of_corruption::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
}
};
void AddSC_boss_zereketh_the_unbound()
{
RegisterArcatrazCreatureAI(boss_zereketh_the_unbound);
RegisterSpellScript(spell_zereketh_seed_of_corruption);
}

View File

@@ -580,137 +580,6 @@ public:
}
};
/*######
## npc_phase_hunter
######*/
enum PhaseHunterData
{
QUEST_RECHARGING_THE_BATTERIES = 10190,
NPC_PHASE_HUNTER_ENTRY = 18879,
NPC_DRAINED_PHASE_HUNTER_ENTRY = 19595,
EMOTE_WEAK = 0,
// Spells
SPELL_RECHARGING_BATTERY = 34219,
SPELL_PHASE_SLIP = 36574,
SPELL_MANA_BURN = 13321,
SPELL_MATERIALIZE = 34804,
SPELL_DE_MATERIALIZE = 34814,
};
class npc_phase_hunter : public CreatureScript
{
public:
npc_phase_hunter() : CreatureScript("npc_phase_hunter") { }
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_phase_hunterAI(creature);
}
struct npc_phase_hunterAI : public ScriptedAI
{
npc_phase_hunterAI(Creature* creature) : ScriptedAI(creature) { }
bool Weak;
bool Materialize;
bool Drained;
uint8 WeakPercent;
ObjectGuid PlayerGUID;
uint32 ManaBurnTimer;
void Reset() override
{
Weak = false;
Materialize = false;
Drained = false;
WeakPercent = 25 + (rand() % 16); // 25-40
PlayerGUID.Clear();
ManaBurnTimer = 5000 + (rand() % 3 * 1000); // 5-8 sec cd
if (me->GetEntry() == NPC_DRAINED_PHASE_HUNTER_ENTRY)
me->UpdateEntry(NPC_PHASE_HUNTER_ENTRY);
}
void JustEngagedWith(Unit* who) override
{
if (who->GetTypeId() == TYPEID_PLAYER)
PlayerGUID = who->GetGUID();
}
//void SpellHit(Unit* /*caster*/, SpellInfo const* /*spell*/)
//{
// DoCast(me, SPELL_DE_MATERIALIZE);
//}
void UpdateAI(uint32 diff) override
{
if (!Materialize)
{
DoCast(me, SPELL_MATERIALIZE);
Materialize = true;
}
if (me->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED) || me->HasUnitState(UNIT_STATE_ROOT)) // if the mob is rooted/slowed by spells eg.: Entangling Roots, Frost Nova, Hamstring, Crippling Poison, etc. => remove it
DoCast(me, SPELL_PHASE_SLIP);
if (!UpdateVictim())
return;
// some code to cast spell Mana Burn on random target which has mana
if (ManaBurnTimer <= diff)
{
std::list<HostileReference*> AggroList = me->GetThreatMgr().GetThreatList();
std::list<Unit*> UnitsWithMana;
for (std::list<HostileReference*>::const_iterator itr = AggroList.begin(); itr != AggroList.end(); ++itr)
{
if (Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
{
if (unit->GetCreateMana() > 0)
UnitsWithMana.push_back(unit);
}
}
if (!UnitsWithMana.empty())
{
DoCast(Acore::Containers::SelectRandomContainerElement(UnitsWithMana), SPELL_MANA_BURN);
ManaBurnTimer = 8000 + (rand() % 10 * 1000); // 8-18 sec cd
}
else
ManaBurnTimer = 3500;
}
else ManaBurnTimer -= diff;
if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID)) // start: support for quest 10190
{
if (!Weak && HealthBelowPct(WeakPercent)
&& player->GetQuestStatus(QUEST_RECHARGING_THE_BATTERIES) == QUEST_STATUS_INCOMPLETE)
{
Talk(EMOTE_WEAK);
Weak = true;
}
if (Weak && !Drained && me->HasAura(SPELL_RECHARGING_BATTERY))
{
Drained = true;
int32 uHpPct = int32(me->GetHealthPct());
me->SetHealth(me->CountPctFromMaxHealth(uHpPct));
me->LowerPlayerDamageReq(me->GetMaxHealth() - me->GetHealth());
me->SetInCombatWith(player);
}
} // end: support for quest 10190
DoMeleeAttackIfReady();
}
};
};
/*######
## npc_bessy
######*/
@@ -911,6 +780,12 @@ public:
}
};
enum PhaseHunterData
{
NPC_PHASE_HUNTER_ENTRY = 18879,
NPC_DRAINED_PHASE_HUNTER_ENTRY = 19595
};
class spell_q10190_battery_recharging_blaster : public SpellScript
{
PrepareSpellScript(spell_q10190_battery_recharging_blaster);
@@ -918,7 +793,7 @@ class spell_q10190_battery_recharging_blaster : public SpellScript
SpellCastResult CheckCast()
{
if (Unit* target = GetExplTargetUnit())
if (target->GetHealthPct() <= 25.0f)
if (target->GetHealthPct() <= 35.0f)
return SPELL_CAST_OK;
return SPELL_FAILED_BAD_TARGETS;
@@ -941,7 +816,7 @@ class spell_q10190_battery_recharging_blaster_aura : public AuraScript
if (Creature* phasehunter = GetTarget()->ToCreature())
if (phasehunter->GetEntry() == NPC_PHASE_HUNTER_ENTRY)
phasehunter->UpdateEntry(NPC_DRAINED_PHASE_HUNTER_ENTRY);
phasehunter->UpdateEntry(NPC_DRAINED_PHASE_HUNTER_ENTRY, nullptr, false);
}
void Register() override
@@ -989,7 +864,6 @@ void AddSC_netherstorm()
// Theirs
new npc_commander_dawnforge();
new at_commander_dawnforge();
new npc_phase_hunter();
new npc_bessy();
new npc_maxx_a_million_escort();
RegisterSpellAndAuraScriptPair(spell_q10190_battery_recharging_blaster, spell_q10190_battery_recharging_blaster_aura);

View File

@@ -1702,10 +1702,8 @@ class spell_gen_pet_summoned : public SpellScript
{
PetType newPetType = (player->IsClass(CLASS_HUNTER, CLASS_CONTEXT_PET)) ? HUNTER_PET : SUMMON_PET;
Pet* newPet = new Pet(player, newPetType);
if (newPet->LoadPetFromDB(player, 0, player->GetLastPetNumber(), true, 100))
if (newPet->LoadPetFromDB(player, 0, player->GetLastPetNumber(), true, 100, true))
{
newPet->SetPower(newPet->getPowerType(), newPet->GetMaxPower(newPet->getPowerType()));
switch (newPet->GetEntry())
{
case NPC_DOOMGUARD:
@@ -5252,6 +5250,77 @@ class spell_gen_sober_up : public AuraScript
}
};
enum StealWeapon
{
SPELL_STEAL_WEAPON = 36207, // in 36208 as script_effect
NPC_GLUMDOR = 20730,
SAY_GLUMDOR_STEAL = 0 // Stupid, squishy $r. That weapon mine now! Give!
};
// 36208 - Steal Weapon
class spell_gen_steal_weapon : public AuraScript
{
PrepareAuraScript(spell_gen_steal_weapon);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_STEAL_WEAPON });
}
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* caster = GetCaster();
Unit* target = GetTarget();
if (!caster || !target)
return;
if (Creature* stealer = caster->ToCreature())
{
if (Player* player = target->ToPlayer())
{
if (Item* mainItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND))
{
stealer->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, mainItem->GetEntry());
stealer->CastSpell(stealer, SPELL_STEAL_WEAPON, true);
if (stealer->GetEntry() == NPC_GLUMDOR)
{
stealer->AI()->Talk(SAY_GLUMDOR_STEAL, player);
}
}
}
// He can steal creature weapons too
if (Creature* creature = target->ToCreature())
{
int8 mainhand = 1;
if (EquipmentInfo const* eInfo = sObjectMgr->GetEquipmentInfo(creature->GetEntry(), mainhand))
{
stealer->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, eInfo->ItemEntry[0]);
stealer->CastSpell(stealer, SPELL_STEAL_WEAPON, true);
}
}
}
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* caster = GetCaster();
if (!caster)
return;
if (Creature* stealer = caster->ToCreature())
{
stealer->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, 0);
}
}
void Register() override
{
AfterEffectApply += AuraEffectApplyFn(spell_gen_steal_weapon::OnApply, EFFECT_1, SPELL_AURA_MOD_DISARM, AURA_EFFECT_HANDLE_REAL);
AfterEffectRemove += AuraEffectRemoveFn(spell_gen_steal_weapon::OnRemove, EFFECT_1, SPELL_AURA_MOD_DISARM, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_generic_spell_scripts()
{
RegisterSpellScript(spell_silithyst);
@@ -5408,5 +5477,6 @@ void AddSC_generic_spell_scripts()
RegisterSpellScript(spell_gen_choking_vines);
RegisterSpellScript(spell_gen_consumption);
RegisterSpellScript(spell_gen_sober_up);
RegisterSpellScript(spell_gen_steal_weapon);
}

View File

@@ -4021,6 +4021,36 @@ class spell_item_fel_mana_potion : public AuraScript
}
};
// 32578 - Gor'drek's Ointment
enum DreksOintment
{
NPC_THUNDERLORD_DIRE_WOLF = 20748,
SPELL_GOR_DREKS_OINTMENT = 32578
};
class spell_item_gor_dreks_ointment : public SpellScript
{
PrepareSpellScript(spell_item_gor_dreks_ointment)
SpellCastResult CheckCast()
{
if (Unit* target = GetExplTargetUnit())
{
if (target->GetEntry() == NPC_THUNDERLORD_DIRE_WOLF && !target->HasAura(SPELL_GOR_DREKS_OINTMENT))
return SPELL_CAST_OK;
if (target->GetEntry() != NPC_THUNDERLORD_DIRE_WOLF)
return SPELL_FAILED_BAD_TARGETS;
}
return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW;
}
void Register() override
{
OnCheckCast += SpellCheckCastFn(spell_item_gor_dreks_ointment::CheckCast);
}
};
void AddSC_item_spell_scripts()
{
RegisterSpellScript(spell_item_massive_seaforium_charge);
@@ -4144,5 +4174,6 @@ void AddSC_item_spell_scripts()
RegisterSpellScript(spell_item_scroll_of_retribution);
RegisterSpellAndAuraScriptPair(spell_item_eye_of_grillok, spell_item_eye_of_grillok_aura);
RegisterSpellScript(spell_item_fel_mana_potion);
RegisterSpellScript(spell_item_gor_dreks_ointment);
}

View File

@@ -58,6 +58,12 @@ enum WarlockSpells
SPELL_WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R2 = 60956,
SPELL_WARLOCK_LIFE_TAP_ENERGIZE = 31818,
SPELL_WARLOCK_LIFE_TAP_ENERGIZE_2 = 32553,
SPELL_WARLOCK_SEED_OF_CORRUPTION_R1 = 27243,
SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1 = 27285,
SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R2 = 47833,
SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R3 = 47834,
SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_GENERIC = 32865,
SPELL_WARLOCK_SEED_OF_CORRUPTION_VISUAL = 37826,
SPELL_WARLOCK_SOULSHATTER = 32835,
SPELL_WARLOCK_SIPHON_LIFE_HEAL = 63106,
SPELL_WARLOCK_UNSTABLE_AFFLICTION_DISPEL = 31117,
@@ -65,12 +71,14 @@ enum WarlockSpells
SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC = 18371,
SPELL_WARLOCK_EYE_OF_KILROGG_FLY = 58083,
SPELL_WARLOCK_PET_VOID_STAR_TALISMAN = 37386, // Void Star Talisman
SPELL_WARLOCK_DEMONIC_PACT_PROC = 48090,
};
enum WarlockSpellIcons
{
WARLOCK_ICON_ID_IMPROVED_LIFE_TAP = 208,
WARLOCK_ICON_ID_MANA_FEED = 1982
WARLOCK_ICON_ID_MANA_FEED = 1982,
WARLOCK_ICON_ID_DEMONIC_PACT = 3220
};
class spell_warl_eye_of_kilrogg : public AuraScript
@@ -670,9 +678,10 @@ class spell_warl_ritual_of_doom_effect : public SpellScript
};
// -27285 - Seed of Corruption
class spell_warl_seed_of_corruption : public SpellScript
// 32865 - Seed of Corruption
class spell_warl_seed_of_corruption_damage : public SpellScript
{
PrepareSpellScript(spell_warl_seed_of_corruption);
PrepareSpellScript(spell_warl_seed_of_corruption_damage);
void FilterTargets(std::list<WorldObject*>& targets)
{
@@ -695,7 +704,124 @@ class spell_warl_seed_of_corruption : public SpellScript
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_warl_seed_of_corruption::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_warl_seed_of_corruption_damage::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY);
}
};
// -27243 - Seed of Corruption
class spell_warl_seed_of_corruption_aura: public AuraScript
{
PrepareAuraScript(spell_warl_seed_of_corruption_aura);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({
SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1,
SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R2,
SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R3,
SPELL_WARLOCK_SEED_OF_CORRUPTION_VISUAL
});
}
void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
{
if (!GetCaster())
return;
// effect 1 scales with 14% of caster's SP (DBC data)
amount = GetCaster()->SpellDamageBonusDone(GetUnitOwner(), GetSpellInfo(), amount, DOT, aurEff->GetEffIndex(), aurEff->GetPctMods());
}
void Detonate(AuraEffect const* aurEff)
{
if (!GetCaster() || !GetTarget())
return;
GetTarget()->CastSpell(GetTarget(), SPELL_WARLOCK_SEED_OF_CORRUPTION_VISUAL, true, nullptr, aurEff);
GetCaster()->CastSpell(GetTarget(), sSpellMgr->GetSpellWithRank(SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_R1, GetSpellInfo()->GetRank()), true, nullptr, aurEff);
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo || !damageInfo->GetDamage())
return;
int32 remainingDamage = aurEff->GetAmount() - damageInfo->GetDamage();
if (remainingDamage > 0)
{
GetAura()->GetEffect(EFFECT_1)->SetAmount(remainingDamage);
}
else // damage threshold has been reached
{
Remove(AURA_REMOVE_BY_DEFAULT);
Detonate(aurEff);
}
}
void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/)
{
AuraRemoveMode removeMode = GetTargetApplication()->GetRemoveMode();
if (removeMode == AURA_REMOVE_BY_DEATH)
Detonate(aurEff);
}
void Register() override
{
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_warl_seed_of_corruption_aura::CalculateAmount, EFFECT_1, SPELL_AURA_DUMMY);
AfterEffectRemove += AuraEffectRemoveFn(spell_warl_seed_of_corruption_aura::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL);
OnEffectProc += AuraEffectProcFn(spell_warl_seed_of_corruption_aura::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
}
};
// Monster spells, triggered only on detonation threshold reached (not on death)
// 32863 - Seed of Corruption
// 36123 - Seed of Corruption
// 38252 - Seed of Corruption
// 39367 - Seed of Corruption
// 44141 - Seed of Corruption
// 70388 - Seed of Corruption
class spell_warl_seed_of_corruption_generic_aura: public AuraScript
{
PrepareAuraScript(spell_warl_seed_of_corruption_generic_aura);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_GENERIC, SPELL_WARLOCK_SEED_OF_CORRUPTION_VISUAL });
}
void Detonate(AuraEffect const* aurEff)
{
if (!GetCaster() || !GetTarget())
return;
GetTarget()->CastSpell(GetTarget(), SPELL_WARLOCK_SEED_OF_CORRUPTION_VISUAL, true, nullptr, aurEff);
GetCaster()->CastCustomSpell(SPELL_WARLOCK_SEED_OF_CORRUPTION_DAMAGE_GENERIC, SPELLVALUE_BASE_POINT0, GetSpellInfo()->GetEffect(EFFECT_1).CalcValue(), GetTarget(), true, nullptr, aurEff);
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo || !damageInfo->GetDamage())
return;
int32 remainingDamage = aurEff->GetAmount() - damageInfo->GetDamage();
if (remainingDamage > 0)
{
GetAura()->GetEffect(EFFECT_1)->SetAmount(remainingDamage);
}
else // damage threshold has been reached
{
Remove(AURA_REMOVE_BY_DEFAULT);
Detonate(aurEff);
}
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_warl_seed_of_corruption_generic_aura::HandleProc, EFFECT_1, SPELL_AURA_DUMMY);
}
};
@@ -1321,6 +1447,54 @@ class spell_warl_glyph_of_voidwalker : public AuraScript
}
};
// 54909, 53646 - Demonic Pact
class spell_warl_demonic_pact_aura : public AuraScript
{
PrepareAuraScript(spell_warl_demonic_pact_aura);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WARLOCK_DEMONIC_PACT_PROC });
}
bool AfterCheckProc(ProcEventInfo& eventInfo, bool isTriggeredAtSpellProcEvent)
{
return isTriggeredAtSpellProcEvent && eventInfo.GetActor() && eventInfo.GetActor()->IsPet();
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
if (eventInfo.GetActor()->HasSpellCooldown(aurEff->GetId()))
return;
if (Unit* owner = eventInfo.GetActor()->GetOwner())
{
int32 currentBonus = 0;
if (AuraEffect* demonicAurEff = owner->GetAuraEffect(SPELL_WARLOCK_DEMONIC_PACT_PROC, EFFECT_0))
{
currentBonus = demonicAurEff->GetAmount();
}
if (AuraEffect* talentAurEff = owner->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, WARLOCK_ICON_ID_DEMONIC_PACT, EFFECT_0))
{
int32 spellDamageMinusBonus = owner->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_MAGIC) - currentBonus;
if (spellDamageMinusBonus < 0)
return;
int32 bp = int32((talentAurEff->GetAmount() / 100.0f) * spellDamageMinusBonus);
owner->CastCustomSpell((Unit*)nullptr, SPELL_WARLOCK_DEMONIC_PACT_PROC, &bp, &bp, 0, true, nullptr, talentAurEff);
eventInfo.GetActor()->AddSpellCooldown(aurEff->GetId(), 0, eventInfo.GetProcCooldown());
}
}
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_warl_demonic_pact_aura::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
void AddSC_warlock_spell_scripts()
{
RegisterSpellScript(spell_warl_eye_of_kilrogg);
@@ -1345,7 +1519,9 @@ void AddSC_warlock_spell_scripts()
RegisterSpellScript(spell_warl_health_funnel);
RegisterSpellScript(spell_warl_life_tap);
RegisterSpellScript(spell_warl_ritual_of_doom_effect);
RegisterSpellScript(spell_warl_seed_of_corruption);
RegisterSpellScript(spell_warl_seed_of_corruption_damage);
RegisterSpellScript(spell_warl_seed_of_corruption_aura);
RegisterSpellScript(spell_warl_seed_of_corruption_generic_aura);
RegisterSpellScript(spell_warl_shadow_ward);
RegisterSpellScript(spell_warl_siphon_life);
RegisterSpellScript(spell_warl_soulshatter);
@@ -1354,5 +1530,6 @@ void AddSC_warlock_spell_scripts()
RegisterSpellScript(spell_warl_shadowburn);
RegisterSpellScript(spell_warl_glyph_of_felguard);
RegisterSpellScript(spell_warl_glyph_of_voidwalker);
RegisterSpellScript(spell_warl_demonic_pact_aura);
}

View File

@@ -39,23 +39,29 @@ public:
void OnChat(Player* player, uint32 type, uint32 lang, std::string& msg) override
{
std::string logType = "";
std::string chatType = "";
switch (type)
{
case CHAT_MSG_SAY:
LOG_INFO("chat.say", "Player {} says (language {}): {}",
player->GetName(), lang, msg);
logType = "chat.say";
chatType = "says";
break;
case CHAT_MSG_EMOTE:
LOG_INFO("chat.emote", "Player {} emotes: {}",
player->GetName(), msg);
logType = "chat.emote";
chatType = "emotes";
break;
case CHAT_MSG_YELL:
LOG_INFO("chat.yell", "Player {} yells (language {}): {}",
player->GetName(), lang, msg);
logType = "chat.yell";
chatType = "yells";
break;
default:
return;
}
LOG_INFO(logType, "Player {} {} (language {}): {}",
player->GetName(), chatType, lang, msg);
}
void OnChat(Player* player, uint32 /*type*/, uint32 /*lang*/, std::string& msg, Player* receiver) override
@@ -66,63 +72,59 @@ public:
void OnChat(Player* player, uint32 type, uint32 lang, std::string& msg, Group* group) override
{
std::string str = lang != LANG_ADDON ? "chat." : "chat.addon.";
//! NOTE:
//! LANG_ADDON can only be sent by client in "PARTY", "RAID", "GUILD", "BATTLEGROUND", "WHISPER"
std::string logType = (lang != LANG_ADDON) ? "chat." : "chat.addon.";
std::string msgType = "";
switch (type)
{
case CHAT_MSG_PARTY:
LOG_INFO(str + "party", "Player {} tells group with leader {}: {}",
player->GetName(), group ? group->GetLeaderName() : "<unknown>", msg);
break;
case CHAT_MSG_PARTY_LEADER:
LOG_INFO(str + "party", "Leader {} tells group: {}",
player->GetName(), msg);
msgType = "party";
break;
case CHAT_MSG_RAID:
LOG_INFO(str + "raid", "Player {} tells raid with leader {}: {}",
player->GetName(), group ? group->GetLeaderName() : "<unknown>", msg);
break;
case CHAT_MSG_RAID_LEADER:
LOG_INFO(str + "raid", "Leader player {} tells raid: {}",
player->GetName(), msg);
break;
case CHAT_MSG_RAID_WARNING:
LOG_INFO(str + "raid", "Leader player {} sends raid warning: {}",
player->GetName(), msg);
msgType = "raid";
break;
case CHAT_MSG_BATTLEGROUND:
LOG_INFO(str + "bg", "Player {} tells battleground with leader {}: {}",
player->GetName(), group ? group->GetLeaderName() : "<unknown>", msg);
break;
case CHAT_MSG_BATTLEGROUND_LEADER:
LOG_INFO(str + "bg", "Leader player {} tells battleground: {}",
player->GetName(), msg);
msgType = "bg";
break;
default:
return;
}
std::string role = (type == CHAT_MSG_PARTY_LEADER || type == CHAT_MSG_RAID_LEADER || type == CHAT_MSG_BATTLEGROUND_LEADER) ? "Leader player" : "Player";
std::string action = (type == CHAT_MSG_RAID_WARNING) ? "sends raid warning" : "tells";
std::string targetGroup = group ? group->GetLeaderName() : "<unknown>";
LOG_INFO(logType + msgType, "{} {} {} {} with leader {}: {}",
role, player->GetName(), action, msgType, targetGroup, msg);
}
void OnChat(Player* player, uint32 type, uint32 lang, std::string& msg, Guild* guild) override
{
std::string str = lang != LANG_ADDON ? "chat." : "chat.addon.";
//! NOTE:
//! LANG_ADDON can only be sent by client in "PARTY", "RAID", "GUILD", "BATTLEGROUND", "WHISPER"
std::string logType = (lang != LANG_ADDON) ? "chat." : "chat.addon.";
std::string msgType = "";
switch (type)
{
case CHAT_MSG_GUILD:
LOG_INFO(str + "guild", "Player {} tells guild {}: {}",
player->GetName(), guild ? guild->GetName() : "<unknown>", msg);
msgType = "guild";
break;
case CHAT_MSG_OFFICER:
LOG_INFO(str + "guild.officer", "Player {} tells guild {} officers: {}",
player->GetName(), guild ? guild->GetName() : "<unknown>", msg);
msgType = "guild.officer";
break;
default:
return;
}
LOG_INFO(logType + msgType, "Player {} tells {} \"{}\": {}",
player->GetName(), msgType, guild ? guild->GetName() : "<unknown>", msg);
}
void OnChat(Player* player, uint32 /*type*/, uint32 /*lang*/, std::string& msg, Channel* channel) override

View File

@@ -20,18 +20,6 @@
#include "Player.h"
#include "ScriptedCreature.h"
#include "Spell.h"
/* ScriptData
SDName: Item_Scripts
SD%Complete: 100
SDComment: Items for a range of different items. See content below (in script)
SDCategory: Items
EndScriptData */
/* ContentData
item_flying_machine(i34060, i34061) Engineering crafted flying machines
item_gor_dreks_ointment(i30175) Protecting Our Own(q10488)
item_only_for_flight Items which should only useable while flying
EndContentData */
/*#####
# item_only_for_flight
@@ -79,26 +67,6 @@ public:
}
};
/*#####
# item_gor_dreks_ointment
#####*/
class item_gor_dreks_ointment : public ItemScript
{
public:
item_gor_dreks_ointment() : ItemScript("item_gor_dreks_ointment") { }
bool OnUse(Player* player, Item* item, SpellCastTargets const& targets) override
{
if (targets.GetUnitTarget() && targets.GetUnitTarget()->GetTypeId() == TYPEID_UNIT &&
targets.GetUnitTarget()->GetEntry() == 20748 && !targets.GetUnitTarget()->HasAura(32578))
return false;
player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, item, nullptr);
return true;
}
};
/*#####
# item_incendiary_explosives
#####*/
@@ -248,7 +216,6 @@ public:
void AddSC_item_scripts()
{
new item_only_for_flight();
new item_gor_dreks_ointment();
new item_incendiary_explosives();
new item_mysterious_egg();
new item_disgusting_jar();

View File

@@ -29,19 +29,48 @@ public:
// CHARACTER_LOGIN = 8
void OnLogin(Player* player) override
{
for (auto const& servMail : sObjectMgr->GetAllServerMailStore())
// Retrieve all server mail records and session only once
auto const& serverMailStore = sObjectMgr->GetAllServerMailStore();
WorldSession* session = player->GetSession();
// We should always have a session, just incase
if (!session)
return;
uint32 playerGUID = player->GetGUID().GetCounter();
for (auto const& [mailId, servMail] : serverMailStore)
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL_SERVER_CHARACTER);
stmt->SetData(0, player->GetGUID().GetCounter());
stmt->SetData(1, servMail.second.id);
stmt->SetData(0, playerGUID);
stmt->SetData(1, mailId);
WorldSession* mySess = player->GetSession();
mySess->GetQueryProcessor().AddCallback(CharacterDatabase.AsyncQuery(stmt)
.WithPreparedCallback([mySess, servMail](PreparedQueryResult result)
// Capture servMail by value
auto callback = [session, servMailWrapper = std::reference_wrapper<ServerMail const>(servMail)](PreparedQueryResult result)
{
ServerMail const& servMail = servMailWrapper.get(); // Dereference the wrapper to get the original object
if (!result)
{
if (!result)
sObjectMgr->SendServerMail(mySess->GetPlayer(), servMail.second.id, servMail.second.reqLevel, servMail.second.reqPlayTime, servMail.second.moneyA, servMail.second.moneyH, servMail.second.itemA, servMail.second.itemCountA, servMail.second.itemH, servMail.second.itemCountH, servMail.second.subject, servMail.second.body, servMail.second.active);
}));
sObjectMgr->SendServerMail(
session->GetPlayer(),
servMail.id,
servMail.reqLevel,
servMail.reqPlayTime,
servMail.moneyA,
servMail.moneyH,
servMail.itemA,
servMail.itemCountA,
servMail.itemH,
servMail.itemCountH,
servMail.subject,
servMail.body,
servMail.active
);
}
};
// Execute the query asynchronously and add the callback
session->GetQueryProcessor().AddCallback(CharacterDatabase.AsyncQuery(stmt).WithPreparedCallback(callback));
}
}
};