Files
Viano-Core/src/server/scripts/EasternKingdoms/zone_westfall.cpp
T

535 lines
16 KiB
C++

/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Player.h"
#include "ScriptMgr.h"
#include "SpellScript.h"
#include "CombatAI.h"
#include "CreatureAIImpl.h"
#include "ObjectAccessor.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "SpellInfo.h"
#include "SharedDefines.h"
class spell_westfall_unbound_energy : public SpellScript
{
void FilterTargets(std::list<WorldObject*>& targets)
{
if (targets.empty())
return;
Unit* caster = GetCaster();
targets.remove_if([caster](WorldObject const* target)->bool
{
return caster == target;
});
if (targets.size() > 1)
Trinity::Containers::RandomResize(targets, 1);
}
void Register() override
{
OnObjectAreaTargetSelect.Register(&spell_westfall_unbound_energy::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
}
};
enum ItsAlive
{
// Events
EVENT_CHECK_AREA = 1,
EVENT_DESPAWN_HARVESTER = 2,
// Texts
SAY_ANNOUNCE_OUT_OF_AREA = 0,
// Area Ids
AREA_ID_THE_MOEST_FARM = 918,
// Creatures
NPC_ENERGIZED_HARVEST_REAPER = 42342,
NPC_OVERLOADED_HARVEST_GOLEM = 42601
};
struct npc_westfall_overloaded_harvest_golem : public VehicleAI
{
npc_westfall_overloaded_harvest_golem(Creature* creature) : VehicleAI(creature) { }
void JustAppeared() override
{
_events.ScheduleEvent(EVENT_CHECK_AREA, 1s);
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_CHECK_AREA:
if (me->GetAreaId() != AREA_ID_THE_MOEST_FARM)
{
if (Unit* owner = me->GetCharmerOrOwner())
Talk(SAY_ANNOUNCE_OUT_OF_AREA, owner);
_events.ScheduleEvent(EVENT_DESPAWN_HARVESTER, 8s);
}
else
_events.Repeat(1s);
break;
case EVENT_DESPAWN_HARVESTER:
if (me->GetAreaId() != AREA_ID_THE_MOEST_FARM)
me->DespawnOrUnsummon();
else
_events.ScheduleEvent(EVENT_CHECK_AREA, 1s);
break;
default:
break;
}
}
}
private:
EventMap _events;
};
class spell_westfall_reaping_blows : public AuraScript
{
void HandlePeriodic(AuraEffect const* /*aurEff*/)
{
PreventDefaultAction();
if (Creature* reaper = GetTarget()->FindNearestCreature(NPC_ENERGIZED_HARVEST_REAPER, 5.f, true))
GetTarget()->CastSpell(reaper, GetSpellInfo()->Effects[EFFECT_1].TriggerSpell, true);
}
void Register() override
{
OnEffectPeriodic.Register(&spell_westfall_reaping_blows::HandlePeriodic, EFFECT_1, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
class spell_westfall_wake_harvest_golem : public SpellScript
{
SpellCastResult CheckTarget()
{
Unit* target = GetExplTargetUnit();
if (!target || !target->IsCreature())
return SPELL_FAILED_BAD_TARGETS;
return SPELL_CAST_OK;
}
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster || !caster->IsPlayer())
return;
if (Creature* target = GetHitCreature())
{
caster->ToPlayer()->KilledMonsterCredit(NPC_OVERLOADED_HARVEST_GOLEM);
target->DespawnOrUnsummon(100ms);
}
}
void Register() override
{
OnCheckCast.Register(&spell_westfall_wake_harvest_golem::CheckTarget);
OnEffectHitTarget.Register(&spell_westfall_wake_harvest_golem::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
class spell_westfall_quest_credit_jangolode_event : public SpellScript
{
void HandleScriptEffect(SpellEffIndex /*effIndex*/)
{
GetHitUnit()->ExitVehicle();
}
void Register() override
{
OnEffectHitTarget.Register(&spell_westfall_quest_credit_jangolode_event::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
enum HoboGossip
{
GOSSIP_MENU_ID_HOBO = 11635
};
enum HoboGossipOption
{
OPTION_QUESTION = 0,
OPTION_PAY = 1,
};
enum HoboQuest
{
QUEST_MURDER_WAS_THE_CASE_THAT_THEY_GAVE_ME = 26209
};
enum HoboQuestObjective
{
CLUE1 = 0,
CLUE2 = 1,
CLUE3 = 2,
CLUE4 = 3
};
enum HoboSpell
{
SPELL_HOBO_INFORMATION_1 = 79181,
SPELL_HOBO_INFORMATION_2 = 79182,
SPELL_HOBO_INFORMATION_3 = 79183,
SPELL_HOBO_INFORMATION_4 = 79184,
SPELL_SUMMON_RAGAMUFFIN_LOOTER = 79169,
SPELL_SUMMON_RAGAMUFFIN_LOOTER_1 = 79170,
SPELL_SUMMON_RAGAMUFFIN_LOOTER_2 = 79171,
SPELL_SUMMON_RAGAMUFFIN_LOOTER_3 = 79172,
SPELL_SUMMON_RAGAMUFFIN_LOOTER_4 = 79173,
SPELL_AGGRO_HOBO = 79168
};
enum HoboText
{
SAY_CLUE1 = 0,
SAY_CLUE2 = 1,
SAY_CLUE3 = 2,
SAY_CLUE4 = 3,
SAY_AGGRO_BRIBE = 4,
SAY_AGGRO_CONVINCE = 5,
SAY_EVENT = 6,
SAY_JACKPOT_INTRO = 7,
SAY_JACKPOT_END = 8,
SAY_PROPERTY_RAGE = 9,
SAY_FLEE = 10
};
enum HoboEvent
{
EVENT_TALK = 1,
EVENT_JACKPOT_INTRO = 2,
EVENT_CRY = 3,
EVENT_PROPERTY_RAGE = 4,
EVENT_JACKPOT_MIDDLE = 5,
EVENT_JACKPOT_END = 6,
EVENT_RESUME_MOVE = 7,
EVENT_GROUP_OOC = 1
};
enum HoboCreature
{
NPC_HOMELESS_STORMWIND_CITIZEN_1 = 42386,
NPC_HOMELESS_STORMWIND_CITIZEN_2 = 42384,
NPC_WEST_PLAINS_DRIFTER = 42391,
NPC_TRANSIENT = 42383
};
enum HoboAction
{
ACTION_AGGRO_HOBO = 1,
ACTION_AGGRO_HOBO_DONE = 2
};
struct npc_westfall_hobo_witness : public ScriptedAI
{
npc_westfall_hobo_witness(Creature* creature) : ScriptedAI(creature), _bribeFailed(false), _hoboRage(false), _flee(false) { }
bool GossipSelect(Player* player, uint32 /*menuId*/, uint32 gossipListId) override
{
uint8 clueGainChance = 0;
switch (gossipListId)
{
case OPTION_QUESTION:
{
clueGainChance = 25;
break;
}
case OPTION_PAY:
{
clueGainChance = 75;
_bribeFailed = true;
break;
}
default:
return true;
}
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
CloseGossipMenuFor(player);
if (roll_chance_i(clueGainChance))
GiveClue(player);
else
{
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
AttackStart(player);
}
return false;
}
void GiveClue(Player* player)
{
if (!player)
return;
_events.CancelEventGroup(EVENT_GROUP_OOC);
me->SetFacingToObject(player);
uint16 slot = player->FindQuestSlot(QUEST_MURDER_WAS_THE_CASE_THAT_THEY_GAVE_ME);
if (player->GetQuestSlotCounter(slot, CLUE1) == 0)
{
player->CastSpell(player, SPELL_HOBO_INFORMATION_1);
Talk(SAY_CLUE1, player);
me->DespawnOrUnsummon(12s);
return;
}
if (player->GetQuestSlotCounter(slot, CLUE2) == 0)
{
player->CastSpell(player, SPELL_HOBO_INFORMATION_2);
Talk(SAY_CLUE2, player);
me->DespawnOrUnsummon(12s);
return;
}
if (player->GetQuestSlotCounter(slot, CLUE3) == 0)
{
player->CastSpell(player, SPELL_HOBO_INFORMATION_3);
Talk(SAY_CLUE3, player);
me->DespawnOrUnsummon(12s);
return;
}
if (player->GetQuestSlotCounter(slot, CLUE4) == 0)
{
player->CastSpell(player, SPELL_HOBO_INFORMATION_4);
Talk(SAY_CLUE4, player);
me->DespawnOrUnsummon(12s);
return;
}
}
void JustEngagedWith(Unit* who) override
{
me->SetAIAnimKitId(0);
_events.CancelEventGroup(EVENT_GROUP_OOC);
if (!who->IsPlayer())
return;
Talk(_bribeFailed ? SAY_AGGRO_BRIBE : SAY_AGGRO_CONVINCE, who);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (!_flee && me->HealthBelowPctDamaged(20, damage))
{
_flee = true;
me->DoFleeToGetAssistance();
Talk(SAY_FLEE);
}
}
void JustDied(Unit* who) override
{
if (who->IsCreature() && who->ToCreature()->IsAIEnabled)
who->ToCreature()->AI()->DoAction(ACTION_AGGRO_HOBO_DONE);
me->CastSpell(me, SPELL_SUMMON_RAGAMUFFIN_LOOTER);
}
void Reset() override
{
ScriptedAI::Reset();
_events.Reset();
_bribeFailed = false;
_hoboRage = false;
_flee = false;
me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
_events.ScheduleEvent(EVENT_RESUME_MOVE, 0, EVENT_GROUP_OOC);
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_AGGRO_HOBO:
if (Unit* target = ObjectAccessor::GetUnit(*me, _targetGUID))
{
_hoboRage = true;
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
me->PauseMovement();
me->SetFacingToObject(target);
AttackStart(target);
}
break;
case ACTION_AGGRO_HOBO_DONE:
_hoboRage = false;
break;
default:
return;
}
}
void SetGUID(ObjectGuid const& guid, int32 /*id*/) override
{
_targetGUID = guid;
DoAction(ACTION_AGGRO_HOBO);
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_TALK:
me->PauseMovement();
Talk(SAY_EVENT);
_events.ScheduleEvent(EVENT_RESUME_MOVE, 6s, EVENT_GROUP_OOC);
break;
case EVENT_JACKPOT_INTRO:
me->PauseMovement();
Talk(SAY_JACKPOT_INTRO);
_events.ScheduleEvent(EVENT_JACKPOT_MIDDLE, 2s + 500ms, EVENT_GROUP_OOC);
break;
case EVENT_JACKPOT_MIDDLE:
me->SetAIAnimKitId(648);
Talk(SAY_JACKPOT_END);
_events.ScheduleEvent(EVENT_JACKPOT_END, 6s, EVENT_GROUP_OOC);
break;
case EVENT_JACKPOT_END:
me->SetAIAnimKitId(0);
_events.ScheduleEvent(EVENT_RESUME_MOVE, 4s, EVENT_GROUP_OOC);
break;
case EVENT_CRY:
me->HandleEmoteCommand(EMOTE_ONESHOT_CRY);
me->PauseMovement();
_events.ScheduleEvent(EVENT_RESUME_MOVE, 2s, EVENT_GROUP_OOC);
break;
case EVENT_PROPERTY_RAGE:
{
uint32 creatureId = RAND(NPC_HOMELESS_STORMWIND_CITIZEN_1, NPC_HOMELESS_STORMWIND_CITIZEN_2, NPC_WEST_PLAINS_DRIFTER, NPC_TRANSIENT);
if (Creature* creature = GetClosestCreatureWithEntry(me, creatureId, 25.0f))
{
if (!creature->IsAlive() || creature->IsInCombat())
{
_events.ScheduleEvent(EVENT_RESUME_MOVE, 0, EVENT_GROUP_OOC);
return;
}
_hoboRage = true;
Talk(SAY_PROPERTY_RAGE);
me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
me->PauseMovement();
me->CastSpell(creature, SPELL_AGGRO_HOBO, true);
me->SetFacingToObject(creature);
}
else
_events.ScheduleEvent(EVENT_RESUME_MOVE, 0, EVENT_GROUP_OOC);
break;
}
case EVENT_RESUME_MOVE:
me->ResumeMovement();
if (roll_chance_i(50)) // prevent spam
{
if (roll_chance_i(70)) // chance to trigger simple talk event
_events.ScheduleEvent(EVENT_TALK, 30s, 80s, EVENT_GROUP_OOC);
else
_events.ScheduleEvent(urand(EVENT_JACKPOT_INTRO, EVENT_PROPERTY_RAGE), 30s, 80s, EVENT_GROUP_OOC);
}
else
_events.Repeat(30s, 80s);
break;
default:
break;
}
}
if (!_hoboRage)
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
}
private:
EventMap _events;
ObjectGuid _targetGUID;
bool _bribeFailed;
bool _hoboRage;
bool _flee;
};
class spell_westfall_summon_ragamuffin_looter : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_SUMMON_RAGAMUFFIN_LOOTER_1,
SPELL_SUMMON_RAGAMUFFIN_LOOTER_2,
SPELL_SUMMON_RAGAMUFFIN_LOOTER_3,
SPELL_SUMMON_RAGAMUFFIN_LOOTER_4
});
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
caster->CastSpell(caster, SPELL_SUMMON_RAGAMUFFIN_LOOTER_1, true);
caster->CastSpell(caster, SPELL_SUMMON_RAGAMUFFIN_LOOTER_2, true);
caster->CastSpell(caster, SPELL_SUMMON_RAGAMUFFIN_LOOTER_3, true);
caster->CastSpell(caster, SPELL_SUMMON_RAGAMUFFIN_LOOTER_4, true);
}
void Register() override
{
OnEffectLaunch.Register(&spell_westfall_summon_ragamuffin_looter::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
class spell_westfall_aggro_hobo : public SpellScript
{
void HandleDummy(SpellEffIndex /*effIndex*/)
{
if (Creature* creature = GetHitCreature())
if (creature->IsAIEnabled)
creature->AI()->SetGUID(GetCaster()->GetGUID(), 0);
}
void Register() override
{
OnEffectHitTarget.Register(&spell_westfall_aggro_hobo::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
void AddSC_westfall()
{
RegisterSpellScript(spell_westfall_unbound_energy);
RegisterCreatureAI(npc_westfall_overloaded_harvest_golem);
RegisterSpellScript(spell_westfall_reaping_blows);
RegisterSpellScript(spell_westfall_wake_harvest_golem);
RegisterSpellScript(spell_westfall_quest_credit_jangolode_event);
RegisterCreatureAI(npc_westfall_hobo_witness);
RegisterSpellScript(spell_westfall_summon_ragamuffin_looter);
RegisterSpellScript(spell_westfall_aggro_hobo);
}