Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
ZhengPeiRu21
2022-08-29 09:30:33 -06:00
committed by GitHub
32 changed files with 885 additions and 53 deletions

View File

@@ -499,7 +499,7 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos
std::string const& password, std::string const& port_or_socket, std::string const& database, std::string const& ssl, Path const& path)
{
std::vector<std::string> args;
args.reserve(7);
args.reserve(9);
// CLI Client connection info
args.emplace_back("-h" + host);
@@ -549,13 +549,17 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos
#endif
// Execute sql file
args.emplace_back("-e");
args.emplace_back(Acore::StringFormat("BEGIN; SOURCE %s; COMMIT;", path.generic_string().c_str()));
// Database
if (!database.empty())
args.emplace_back(database);
// Invokes a mysql process which doesn't leak credentials to logs
int const ret = Acore::StartProcess(DBUpdaterUtil::GetCorrectedMySQLExecutable(), args,
"sql.updates", path.generic_string(), true);
"sql.updates", "", true);
if (ret != EXIT_SUCCESS)
{

View File

@@ -60,8 +60,23 @@ void TotemAI::UpdateAI(uint32 /*diff*/)
if (me->ToTotem()->GetTotemType() != TOTEM_ACTIVE)
return;
if (!me->IsAlive() || me->IsNonMeleeSpellCast(false))
if (!me->IsAlive())
{
return;
}
if (me->IsNonMeleeSpellCast(false))
{
if (Unit* victim = ObjectAccessor::GetUnit(*me, i_victimGuid))
{
if (!victim || !victim->IsAlive())
{
me->InterruptNonMeleeSpells(false);
}
}
return;
}
// Search spell
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(me->ToTotem()->GetSpell());

View File

@@ -32,7 +32,7 @@
#include "Formulas.h"
#include "GameGraveyard.h"
#include "GridNotifiersImpl.h"
#include "Group.h"
#include "GroupMgr.h"
#include "MapMgr.h"
#include "MiscPackets.h"
#include "Object.h"
@@ -1151,6 +1151,7 @@ void Battleground::AddOrSetPlayerToCorrectBgGroup(Player* player, TeamId teamId)
group = new Group;
SetBgRaid(teamId, group);
group->Create(player);
sGroupMgr->AddGroup(group);
}
else if (group->IsMember(playerGuid))
{

View File

@@ -12062,6 +12062,8 @@ uint32 Unit::SpellHealingBonusDone(Unit* victim, SpellInfo const* spellProto, ui
{
case 4415: // Increased Rejuvenation Healing
case 4953:
DoneTotal += (*i)->GetAmount() / 5; // 5 ticks of Rejuvenation
break;
case 3736: // Hateful Totem of the Third Wind / Increased Lesser Healing Wave / LK Arena (4/5/6) Totem of the Third Wind / Savage Totem of the Third Wind
DoneTotal += (*i)->GetAmount();
break;
@@ -16143,9 +16145,13 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u
{
if (SpellModifier* mod = triggeredByAura->GetSpellModifier())
{
if (mod->op == SPELLMOD_CASTING_TIME && procSpell && (procSpell->GetTriggeredCastFlags() & TRIGGERED_CAST_DIRECTLY) != 0)
if (mod->op == SPELLMOD_CASTING_TIME && mod->value < 0 && procSpell)
{
break;
// Skip instant spells
if (procSpellInfo->CalcCastTime() <= 0 || (procSpell->GetTriggeredCastFlags() & TRIGGERED_CAST_DIRECTLY) != 0)
{
break;
}
}
}
takeCharges = true;

View File

@@ -4361,6 +4361,24 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->AttributesEx3 |= SPELL_ATTR3_ALWAYS_HIT;
});
// Death's Respite
ApplySpellFix({ 67731, 68305 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPRESS_TARGET_PROCS;
});
// Wyvern Sting DoT
ApplySpellFix({ 24131, 24134, 24135 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ENEMY);
});
// Feed Pet
ApplySpellFix({ 1539, 51284 }, [](SpellInfo* spellInfo)
{
spellInfo->Attributes |= SPELL_ATTR0_ALLOW_WHILE_SITTING;
});
for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
{
SpellInfo* spellInfo = mSpellInfoMap[i];

View File

@@ -126,6 +126,15 @@ struct boss_ayamiss : public BossAI
}
}, 1s);
_scheduler.Schedule(5s, 8s, [this](TaskContext context) {
DoCastVictim(SPELL_LASH);
context.Repeat(8s, 15s);
}).Schedule(16s, [this](TaskContext context)
{
DoCastSelf(SPELL_THRASH);
context.Repeat();
});
}
}
@@ -210,17 +219,6 @@ struct boss_ayamiss : public BossAI
me->SetDisableGravity(false);
me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
DoResetThreat();
_scheduler.Schedule(5s, 8s, [this](TaskContext context) {
DoCastVictim(SPELL_LASH);
context.Repeat(8s, 15s);
}).Schedule(16s, [this](TaskContext context)
{
DoCastSelf(SPELL_THRASH);
context.Repeat();
});
_scheduler.DelayAll(5s);
_scheduler.CancelGroup(PHASE_AIR);
}
@@ -271,6 +269,7 @@ struct npc_hive_zara_larva : public ScriptedAI
if (Creature* ayamiss = _instance->GetCreature(DATA_AYAMISS))
{
ayamiss->AI()->JustSummoned(summon);
summon->SetInCombatWithZone();
}
}

View File

@@ -129,7 +129,7 @@ struct boss_buru : public BossAI
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (attacker->GetEntry() == NPC_BURU_EGG)
if (attacker && attacker->GetEntry() == NPC_BURU_EGG)
{
me->LowerPlayerDamageReq(damage);
}

View File

@@ -35,9 +35,12 @@ enum Yells
enum Spells
{
SPELL_DISARM = 6713,
SPELL_FRENZY = 8269,
SPELL_THUNDERCRASH = 25599
SPELL_DISARM = 6713,
SPELL_FRENZY = 8269,
SPELL_THUNDERCRASH = 25599,
// Server-side
SPELL_CENARION_REPUTATION = 26342
};
enum Events
@@ -51,12 +54,6 @@ struct boss_rajaxx : public BossAI
{
boss_rajaxx(Creature* creature) : BossAI(creature, DATA_RAJAXX) { }
void Reset() override
{
BossAI::Reset();
enraged = false;
}
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
@@ -67,6 +64,26 @@ struct boss_rajaxx : public BossAI
andorov->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_VENDOR);
andorov->ForceValuesUpdateAtIndex(UNIT_NPC_FLAGS);
}
std::list<Creature*> creatureList;
me->GetCreatureListWithEntryInGrid(creatureList, NPC_KALDOREI_ELITE, 200.0f);
creatureList.remove_if([&](Creature* creature) -> bool { return !creature->IsAlive(); });
me->GetMap()->DoForAllPlayers([&, creatureList](Player* player)
{
for (uint8 i = 0; i < creatureList.size(); ++i)
{
player->CastSpell(player, SPELL_CENARION_REPUTATION, true);
}
if (Creature* andorov = instance->instance->GetCreature(instance->GetGuidData(DATA_ANDOROV)))
{
if (andorov->IsAlive())
{
player->CastSpell(player, SPELL_CENARION_REPUTATION, true);
}
}
});
}
void EnterCombat(Unit* /*victim*/) override
@@ -105,8 +122,6 @@ struct boss_rajaxx : public BossAI
DoMeleeAttackIfReady();
}
private:
bool enraged;
};
class spell_rajaxx_thundercrash : public SpellScript
@@ -183,7 +198,6 @@ struct npc_general_andorov : public npc_escortAI
kaldoreielitist->SetImmuneToNPC(true);
kaldoreielitist->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
kaldoreielitist->SetReactState(REACT_PASSIVE);
kaldoreielitist->SetFaction(FACTION_ESCORT_H_ACTIVE);
CAST_AI(SmartAI, kaldoreielitist->AI())->SetFollow(me, 2.5f, 0.f + i * (M_PI / 2));
}
}
@@ -246,13 +260,16 @@ struct npc_general_andorov : public npc_escortAI
}
}
void JustDied(Unit* /*killer*/) override
void JustDied(Unit* killer) override
{
_summons.DespawnAll();
if (Creature* rajaxx = instance->GetCreature(DATA_RAJAXX))
if (killer->GetEntry() == NPC_RAJAXX)
{
rajaxx->AI()->Talk(SAY_KILLS_ANDOROV);
if (Creature* rajaxx = instance->GetCreature(DATA_RAJAXX))
{
rajaxx->AI()->Talk(SAY_KILLS_ANDOROV);
}
}
}
@@ -330,7 +347,7 @@ struct npc_general_andorov : public npc_escortAI
{
case EVENT_BASH:
DoCastVictim(SPELL_BASH);
events.ScheduleEvent(EVENT_BASH, urand(12, 15) * IN_MILLISECONDS);
events.ScheduleEvent(EVENT_BASH, urand(25, 38) * IN_MILLISECONDS);
break;
case EVENT_COMMAND_AURA:
DoCastSelf(SPELL_AURA_OF_COMMAND, true);

View File

@@ -28,22 +28,6 @@ EndScriptData */
#include "TaskScheduler.h"
#include "temple_of_ahnqiraj.h"
enum Phases
{
PHASE_NOT_STARTED = 0,
// Main Phase 1 - EYE
PHASE_EYE_GREEN_BEAM = 1,
PHASE_EYE_RED_BEAM = 2,
// Main Phase 2 - CTHUN
PHASE_CTHUN_TRANSITION = 3,
PHASE_CTHUN_STOMACH = 4,
PHASE_CTHUN_WEAK = 5,
PHASE_CTHUN_DONE = 6,
};
enum Spells
{
// ***** Main Phase 1 ********

View File

@@ -148,8 +148,30 @@ class spell_huhuran_wyvern_sting : public AuraScript
}
};
// 26052 - Poison Bolt
class spell_huhuran_poison_bolt : public SpellScript
{
PrepareSpellScript(spell_huhuran_poison_bolt);
void FilterTargets(std::list<WorldObject*>& targets)
{
uint32 const maxTargets = GetSpellInfo()->MaxAffectedTargets;
if (targets.size() > maxTargets)
{
targets.sort(Acore::ObjectDistanceOrderPred(GetCaster()));
targets.resize(maxTargets);
}
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_huhuran_poison_bolt::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
void AddSC_boss_huhuran()
{
RegisterTempleOfAhnQirajCreatureAI(boss_huhuran);
RegisterSpellScript(spell_huhuran_wyvern_sting);
RegisterSpellScript(spell_huhuran_poison_bolt);
}

View File

@@ -112,6 +112,8 @@ struct boss_skeram : public BossAI
{
_JustDied();
Talk(SAY_DEATH);
instance->HandleGameObject(instance->GetGuidData(AQ40_DOOR_3), true);
}
else
me->RemoveCorpse();
@@ -146,9 +148,7 @@ struct boss_skeram : public BossAI
events.ScheduleEvent(EVENT_ARCANE_EXPLOSION, 8s, 18s);
break;
case EVENT_FULLFILMENT:
/// @todo For some weird reason boss does not cast this
// Spell actually works, tested in duel
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true), SPELL_TRUE_FULFILLMENT, false);
DoCast(SelectTarget(SelectTargetMethod::MinDistance, 1, 0.0f, true), SPELL_TRUE_FULFILLMENT, false);
events.ScheduleEvent(EVENT_FULLFILMENT, 20s, 30s);
break;
case EVENT_BLINK:

View File

@@ -91,6 +91,8 @@ struct boss_twinemperorsAI : public BossAI
me->ClearUnitState(UNIT_STATE_STUNNED);
DontYellWhenDead = false;
EnrageTimer = 15 * 60000;
instance->HandleGameObject(instance->GetGuidData(AQ40_DOOR_1), true);
}
Creature* GetOtherBoss()
@@ -127,6 +129,9 @@ struct boss_twinemperorsAI : public BossAI
}
if (!DontYellWhenDead) // I hope AI is not threaded
DoPlaySoundToSet(me, IAmVeklor() ? SOUND_VL_DEATH : SOUND_VN_DEATH);
instance->HandleGameObject(instance->GetGuidData(AQ40_DOOR_1), true);
instance->HandleGameObject(instance->GetGuidData(AQ40_DOOR_2), true);
}
void KilledUnit(Unit* /*victim*/) override
@@ -150,6 +155,8 @@ struct boss_twinemperorsAI : public BossAI
otherAI->DoZoneInCombat();
}
}
instance->HandleGameObject(instance->GetGuidData(AQ40_DOOR_1), false);
}
void SpellHit(Unit* caster, SpellInfo const* entry) override

View File

@@ -42,6 +42,7 @@ public:
instance_temple_of_ahnqiraj_InstanceMapScript(Map* map) : InstanceScript(map)
{
LoadObjectData(creatureData, nullptr);
doorGUIDs.fill(ObjectGuid::Empty);
SetBossNumber(MAX_BOSS_NUMBER);
}
@@ -55,6 +56,10 @@ public:
ObjectGuid VeklorGUID;
ObjectGuid VeknilashGUID;
ObjectGuid ViscidusGUID;
ObjectGuid CThunGUID;
GuidVector CThunGraspGUIDs;
std::array<ObjectGuid, 3> doorGUIDs;
uint32 BugTrioDeathCount;
uint32 CthunPhase;
@@ -73,6 +78,10 @@ public:
{
case NPC_SKERAM:
SkeramGUID = creature->GetGUID();
if (!creature->IsAlive())
{
HandleGameObject(doorGUIDs[2], true);
}
break;
case NPC_VEM:
VemGUID = creature->GetGUID();
@@ -85,6 +94,10 @@ public:
break;
case NPC_VEKLOR:
VeklorGUID = creature->GetGUID();
if (!creature->IsAlive())
{
HandleGameObject(doorGUIDs[1], true);
}
break;
case NPC_VEKNILASH:
VeknilashGUID = creature->GetGUID();
@@ -96,11 +109,70 @@ public:
if (GetBossState(DATA_OURO) != DONE)
creature->Respawn();
break;
case NPC_CTHUN:
CThunGUID = creature->GetGUID();
if (!creature->IsAlive())
{
for (ObjectGuid const& guid : CThunGraspGUIDs)
{
if (GameObject* cthunGrasp = instance->GetGameObject(guid))
{
cthunGrasp->DespawnOrUnsummon(1s);
}
}
}
break;
default:
break;
}
InstanceScript::OnCreatureCreate(creature);
}
void OnGameObjectCreate(GameObject* go) override
{
switch (go->GetEntry())
{
case AQ40_DOOR_1:
doorGUIDs[0] = go->GetGUID();
break;
case AQ40_DOOR_2:
doorGUIDs[1] = go->GetGUID();
if (Creature* veklor = instance->GetCreature(VeklorGUID))
{
if (!veklor->IsAlive())
{
HandleGameObject(go->GetGUID(), true);
}
}
break;
case AQ40_DOOR_3:
doorGUIDs[2] = go->GetGUID();
if (Creature* skeram = instance->GetCreature(SkeramGUID))
{
if (!skeram->IsAlive())
{
HandleGameObject(go->GetGUID(), true);
}
}
break;
case GO_CTHUN_GRASP:
CThunGraspGUIDs.push_back(go->GetGUID());
if (Creature* CThun = instance->GetCreature(CThunGUID))
{
if (!CThun->IsAlive())
{
go->DespawnOrUnsummon(1s);
}
}
break;
default:
break;
}
InstanceScript::OnGameObjectCreate(go);
}
uint32 GetData(uint32 type) const override
{
switch (type)
@@ -142,6 +214,12 @@ public:
return VeknilashGUID;
case DATA_VISCIDUS:
return ViscidusGUID;
case AQ40_DOOR_1:
return doorGUIDs[0];
case AQ40_DOOR_2:
return doorGUIDs[1];
case AQ40_DOOR_3:
return doorGUIDs[2];
}
return ObjectGuid::Empty;
}
@@ -164,6 +242,16 @@ public:
break;
case DATA_CTHUN_PHASE:
CthunPhase = data;
if (data == PHASE_CTHUN_DONE)
{
for (ObjectGuid const& guid : CThunGraspGUIDs)
{
if (GameObject* cthunGrasp = instance->GetGameObject(guid))
{
cthunGrasp->DespawnOrUnsummon(1s);
}
}
}
break;
}
}

View File

@@ -17,6 +17,7 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "temple_of_ahnqiraj.h"
#include "TaskScheduler.h"
@@ -150,7 +151,40 @@ private:
bool _enraged;
};
enum NPCs
{
NPC_VEKNISS_DRONE = 15300
};
class spell_aggro_drones : public SpellScript
{
PrepareSpellScript(spell_aggro_drones);
void HandleDummy(SpellEffIndex /*effIndex*/)
{
if (Unit* caster = GetCaster())
{
if (Creature* target = GetHitCreature())
{
if (target->GetEntry() == NPC_VEKNISS_DRONE)
{
if (Unit* victim = caster->GetVictim())
{
target->AI()->AttackStart(victim);
}
}
}
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_aggro_drones::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
void AddSC_temple_of_ahnqiraj()
{
RegisterTempleOfAhnQirajCreatureAI(npc_anubisath_defender);
RegisterSpellScript(spell_aggro_drones);
}

View File

@@ -53,6 +53,7 @@ enum DataTypes
enum Creatures
{
NPC_CTHUN = 15727,
NPC_EYE_OF_CTHUN = 15589,
NPC_CTHUN_PORTAL = 15896,
NPC_CLAW_TENTACLE = 15725,
@@ -79,6 +80,30 @@ enum Creatures
NPC_SARTURA = 15516
};
enum ObjectsAQ40
{
AQ40_DOOR_1 = 180634,
AQ40_DOOR_2 = 180635,
AQ40_DOOR_3 = 180636,
GO_CTHUN_GRASP = 180745
};
enum CThunPhases
{
PHASE_NOT_STARTED = 0,
// Main Phase 1 - EYE
PHASE_EYE_GREEN_BEAM = 1,
PHASE_EYE_RED_BEAM = 2,
// Main Phase 2 - CTHUN
PHASE_CTHUN_TRANSITION = 3,
PHASE_CTHUN_STOMACH = 4,
PHASE_CTHUN_WEAK = 5,
PHASE_CTHUN_DONE = 6
};
template <class AI, class T>
inline AI* GetTempleOfAhnQirajAI(T* obj)
{

View File

@@ -633,6 +633,264 @@ public:
};
};
enum WintergardeGryphon
{
SPELL_RESCUE_VILLAGER = 48363,
SPELL_DROP_OFF_VILLAGER = 48397,
SPELL_RIDE_VEHICLE = 43671,
NPC_HELPLESS_VILLAGER_A = 27315,
NPC_HELPLESS_VILLAGER_B = 27336,
EVENT_VEHICLE_GET = 1,
EVENT_TAKE_OFF = 2,
EVENT_GET_VILLAGER = 3,
EVENT_PHASE_FEAR = 1,
EVENT_PHASE_VEHICLE = 2,
POINT_LAND = 1,
POINT_TAKE_OFF = 2,
QUEST_FLIGHT_OF_THE_WINTERGARDE_DEFENDER = 12237,
GO_TEMP_GRYPHON_STATION = 188679,
AREA_WINTERGARDE_KEEP = 4177
};
class npc_wintergarde_gryphon : public VehicleAI
{
public:
npc_wintergarde_gryphon(Creature* creature) : VehicleAI(creature)
{
creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
}
void JustDied(Unit* /*killer*/) override
{
me->DespawnOrUnsummon(3s, 0s);
}
void IsSummonedBy(Unit* summoner) override
{
me->SetFacingToObject(summoner);
Position pos = summoner->GetPosition();
me->GetMotionMaster()->MovePoint(POINT_LAND, pos);
}
void MovementInform(uint32 type, uint32 id) override
{
if (type == POINT_MOTION_TYPE && id == POINT_LAND)
events.ScheduleEvent(EVENT_VEHICLE_GET, 0s);
}
void PassengerBoarded(Unit* passenger, int8 seatId, bool apply) override
{
if (!apply && seatId == 0)
{
// left the vehicle with a passenger will result in despawn
if (Vehicle* gryphon = me->GetVehicleKit())
if (Unit* villager = gryphon->GetPassenger(1))
{
if (villager->GetTypeId() != TYPEID_UNIT)
return;
if (Creature* seat = villager->ToCreature())
{
seat->ExitVehicle();
seat->DespawnOrUnsummon();
}
}
me->RemoveVehicleKit(); // not Crash (;
events.ScheduleEvent(EVENT_TAKE_OFF, 2s);
me->CastSpell(passenger, VEHICLE_SPELL_PARACHUTE, true);
}
}
Creature* getVillager() { return ObjectAccessor::GetCreature(*me, villagerGUID); }
void UpdateAI(uint32 diff) override
{
events.Update(diff);
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_VEHICLE_GET:
{
me->SetDisableGravity(false);
me->SetHover(false);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
break;
}
case EVENT_TAKE_OFF:
{
me->DespawnOrUnsummon(4050);
me->SetOrientation(2.5f);
me->SetSpeedRate(MOVE_FLIGHT, 1.0f);
Position pos = me->GetPosition();
Position offset = { 14.0f, 14.0f, 16.0f, 0.0f };
pos.RelocateOffset(offset);
me->GetMotionMaster()->MovePoint(POINT_TAKE_OFF, pos);
break;
}
case EVENT_GET_VILLAGER:
{
if (getVillager())
{
getVillager()->GetMotionMaster()->MovePoint(0, 3660.0f, -706.4f, 215.0f);
getVillager()->DespawnOrUnsummon(7s, 0s);
}
break;
}
}
}
}
void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
{
if (spell->Id != SPELL_DROP_OFF_VILLAGER)
return;
if (Vehicle* gryphon = me->GetVehicleKit())
if (Unit* villager = gryphon->GetPassenger(1))
{
villager->ExitVehicle();
villager->GetMotionMaster()->Clear(false);
villager->GetMotionMaster()->MoveIdle();
villager->SetCanFly(false); // prevents movement in flight
villagerGUID = villager->GetGUID();
villager->HandleEmoteCommand(EMOTE_ONESHOT_CHEER);
events.ScheduleEvent(EVENT_GET_VILLAGER, 3s);
}
}
private:
ObjectGuid villagerGUID;
};
class spell_q12237_rescue_villager : public SpellScript
{
PrepareSpellScript(spell_q12237_rescue_villager);
SpellCastResult CheckCast()
{
Player* owner = GetCaster()->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!owner)
return SPELL_FAILED_DONT_REPORT;
SpellCustomErrors extension = SPELL_CUSTOM_ERROR_NONE;
SpellCastResult result = SPELL_CAST_OK;
if (GetCaster()->GetAreaId() == AREA_WINTERGARDE_KEEP)
{
extension = SPELL_CUSTOM_ERROR_MUST_BE_NEAR_HELPLESS_VILLAGER;
result = SPELL_FAILED_CUSTOM_ERROR;
}
if (!GetCaster()->FindNearestCreature(NPC_HELPLESS_VILLAGER_A, 5.0f) && !GetCaster()->FindNearestCreature(NPC_HELPLESS_VILLAGER_B, 5.0f))
{
extension = SPELL_CUSTOM_ERROR_MUST_BE_NEAR_HELPLESS_VILLAGER;
result = SPELL_FAILED_CUSTOM_ERROR;
}
if (GetCaster()->FindNearestGameObject(GO_TEMP_GRYPHON_STATION, 15.0f))
{
extension = SPELL_CUSTOM_ERROR_NEED_HELPLESS_VILLAGER;
result = SPELL_FAILED_CUSTOM_ERROR;
}
if (GetCaster()->HasAura(SPELL_RIDE_VEHICLE))
result = SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW;
if (result != SPELL_CAST_OK)
{
Spell::SendCastResult(owner, GetSpellInfo(), 0, result, extension);
return result;
}
return SPELL_CAST_OK;
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (Unit* target = GetHitUnit())
target->CastSpell(GetCaster(), uint32(GetEffectValue()), true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_q12237_rescue_villager::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
OnCheckCast += SpellCheckCastFn(spell_q12237_rescue_villager::CheckCast);
}
};
class spell_q12237_drop_off_villager : public SpellScript
{
PrepareSpellScript(spell_q12237_drop_off_villager);
SpellCastResult CheckCast()
{
Player* master = GetCaster()->GetCharmerOrOwnerPlayerOrPlayerItself();
if (!master)
return SPELL_FAILED_DONT_REPORT;
SpellCustomErrors extension = SPELL_CUSTOM_ERROR_NONE;
SpellCastResult result = SPELL_CAST_OK;
if (!GetCaster()->FindNearestGameObject(GO_TEMP_GRYPHON_STATION, 10.0f))
result = SPELL_FAILED_REQUIRES_SPELL_FOCUS;
if (!GetCaster()->HasAura(SPELL_RIDE_VEHICLE))
{
extension = SPELL_CUSTOM_ERROR_NO_PASSENGER;
result = SPELL_FAILED_CUSTOM_ERROR;
}
if (result != SPELL_CAST_OK)
{
Spell::SendCastResult(master, GetSpellInfo(), 0, result, extension);
return result;
}
return SPELL_CAST_OK;
}
void Register() override
{
OnCheckCast += SpellCheckCastFn(spell_q12237_drop_off_villager::CheckCast);
}
};
class spell_call_wintergarde_gryphon : public SpellScript
{
PrepareSpellScript(spell_call_wintergarde_gryphon);
void SetDest(SpellDestination& dest)
{
// Adjust effect summon position
Position const offset = { 0.0f, 0.0f, 9.0f, 0.0f };
dest.RelocateOffset(offset);
}
SpellCastResult CheckRequirement()
{
if (Player* playerCaster = GetCaster()->ToPlayer())
{
if (playerCaster->GetQuestStatus(QUEST_FLIGHT_OF_THE_WINTERGARDE_DEFENDER) == QUEST_STATUS_INCOMPLETE)
return SPELL_CAST_OK;
}
return SPELL_FAILED_DONT_REPORT;
}
void Register() override
{
OnCheckCast += SpellCheckCastFn(spell_call_wintergarde_gryphon::CheckRequirement);
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_call_wintergarde_gryphon::SetDest, EFFECT_0, TARGET_DEST_CASTER_FRONT);
}
};
class npc_heated_battle : public CreatureScript
{
public:
@@ -2009,6 +2267,10 @@ void AddSC_dragonblight()
new npc_future_you();
new npc_mindless_ghoul();
new npc_injured_7th_legion_soldier();
RegisterCreatureAI(npc_wintergarde_gryphon);
RegisterSpellScript(spell_q12237_rescue_villager);
RegisterSpellScript(spell_q12237_drop_off_villager);
RegisterSpellScript(spell_call_wintergarde_gryphon);
new npc_heated_battle();
new spell_q12478_frostmourne_cavern();
new spell_q12243_fire_upon_the_waters();

View File

@@ -1150,6 +1150,27 @@ class spell_dru_berserk : public SpellScript
}
};
// 24905 - Moonkin Form (Passive)
class spell_dru_moonkin_form_passive_proc : public AuraScript
{
PrepareAuraScript(spell_dru_moonkin_form_passive_proc);
bool CheckProc(ProcEventInfo& eventInfo)
{
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
{
return !spellInfo->IsAffectingArea();
}
return false;
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_dru_moonkin_form_passive_proc::CheckProc);
}
};
void AddSC_druid_spell_scripts()
{
RegisterSpellScript(spell_dru_bear_form_passive);
@@ -1185,4 +1206,5 @@ void AddSC_druid_spell_scripts()
RegisterSpellScript(spell_dru_typhoon);
RegisterSpellScript(spell_dru_t10_restoration_4p_bonus);
RegisterSpellScript(spell_dru_wild_growth);
RegisterSpellScript(spell_dru_moonkin_form_passive_proc);
}