diff --git a/src/server/scripts/EasternKingdoms/zone_hillsbrad_foothills.cpp b/src/server/scripts/EasternKingdoms/zone_hillsbrad_foothills.cpp
new file mode 100644
index 00000000000..c1c67aca6a7
--- /dev/null
+++ b/src/server/scripts/EasternKingdoms/zone_hillsbrad_foothills.cpp
@@ -0,0 +1,1414 @@
+/*
+* Copyright (C) 2008-2018 TrinityCore
+*
+* 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 .
+*/
+
+#include "ScriptMgr.h"
+#include "CellImpl.h"
+#include "CreatureAIImpl.h"
+#include "CombatAI.h"
+#include "GridNotifiersImpl.h"
+#include "MotionMaster.h"
+#include "Player.h"
+#include "PassiveAI.h"
+#include "PhasingHandler.h"
+#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "SpellMgr.h"
+#include "SpellHistory.h"
+#include "Vehicle.h"
+
+enum PlansVsZombies
+{
+ // Quest related
+ QUEST_BASIC_BOTANY = 28733,
+ CREDIT_BASIC_BOTANY = 49189,
+
+ QUEST_FLOWER_POWER = 28617,
+ CREDIT_FLOWER_POWER = 49542,
+
+ // Brazie Vehicle
+ SPELL_PROGRESS_BAR = 92259,
+ SPELL_50_POWER = 91987,
+ SPELL_CREATE_LAWMOWER = 91680,
+ SPELL_CREATE_EMPTY_SPOT = 91676,
+ SPELL_CREATE_SPITTER_TARGET = 91988,
+ SPELL_CREATE_GOAL_STALKER = 91740,
+ SPELL_CREATE_BATTERY = 92816,
+ SPELL_CREATE_RANDOM_SUN_POWER = 91741,
+ SPELL_SPITTER_HIGHLIGHT = 92276,
+ SPELL_SUNFLOWER_HIGHLIGHT = 94032,
+ SPELL_EJECT_ALL_PASSENGERS = 68576,
+
+ SPELL_PLANT_SPITTER = 91649,
+ SPELL_PLANT_SUNFLOWER = 91646,
+ SPELL_PLANT_FREEZYA = 92440,
+
+ // Player Spells
+ SPELL_CREATE_BOTANISTS_VEHICLE = 91683,
+ SPELL_CREATE_ZOMBIE = 91739,
+ SPELL_CREATE_GHOUL = 91834,
+ SPELL_CREATE_RANDOM_FREEZYA_SACK = 92435,
+ SPELL_GET_FREEZYA_SEEDS = 92434,
+
+ NPC_SPITTER_TARGET = 49385,
+ NPC_EMPTY_SPOT = 49190,
+ NPC_PLACE_IT_HERE = 51098,
+ NPC_SOLAR_POWER = 49194,
+ NPC_SPITTER = 49200,
+ NPC_SUNFLOWER = 49193,
+ NPC_ZOMBIE = 49209,
+ NPC_GHOUL = 49232,
+ NPC_FREEZYA_SEEDS = 49604,
+ NPC_FREEZYA = 49618,
+ NPC_GOAL_STALKER = 49210,
+ NPC_FERTILITIZE_O_TRON_2000 = 49192,
+
+ // Empty Spot
+ SPELL_HEALTH_TRIGGER = 93006,
+ SPELL_VENOM_SPIT = 91748,
+ SPELL_SUNLIGHT = 93968,
+ SPELL_FREEZYA_BLAST = 92441,
+
+ // Solar Power
+ SPELL_GAIN_SOLAR_POWER_SPELLCLICK = 91687,
+ SPELL_GAIN_SOLAR_POWER_ENERGIZE = 94068,
+
+ // Zombie
+ SPELL_ZOMBIE_GROWL = 93961,
+ // SPELL_HEALTH_TRIGGER = 93006,
+ SPELL_LEAKING_GUTS = 93244,
+ SPELL_GHOUL_GROWL = 93962,
+ SPELL_BUCKET_HEAD = 93230,
+ SPELL_BUCKET = 93236,
+
+ // Fertilitize-o-tron 2000
+ SPELL_LAWNMOWER_STARTUP_SOUND = 93969,
+ SPELL_DAZED = 1604,
+ SPELL_PLAGUE_GAS = 92084,
+
+ // Texts
+ SAY_ANNOUNCE_TUTORIAL_1 = 49559,
+ SAY_ANNOUNCE_TUTORIAL_2 = 49553,
+ SAY_ANNOUNCE_TUTORIAL_3 = 49558,
+ SAY_ANNOUNCE_TUTORIAL_4 = 49552,
+ SAY_ANNOUNCE_MASSIVE_WAVE = 49409,
+ SAY_ANNOUNCE_PLANT_SUNFLOWER = 49566,
+ SAY_ANNOUNCE_PLANT_MORE_SUNFLOWERS = 49567,
+ SAY_ANNOUNCE_DROPPED_SEED = 49685,
+ SAY_ANNOUNCE_LEVEL_1_COMPLETE = 49551,
+
+ SAY_ANNOUNCE_GAINED_FREEZYA_SEEDS = 0,
+ SAY_ANNOUNCE_GAINED_STRANGLER_SEEDS = 1,
+ SAY_ANNOUNCE_ZOMBIES_ATE_BRAIN = 2,
+
+ // Events
+ EVENT_SPITTER_HIGHLIGHT = 1,
+ EVENT_SUMMON_SOLAR_POWER = 2,
+ EVENT_CREATE_ZOMBIE = 3,
+ EVENT_MOVE_TO_GOAL_POSITION = 4,
+ EVENT_CHECK_VICTIM_STATE = 5,
+ EVENT_ANNOUNCE_GOOD_JOB = 6,
+ EVENT_ANNOUNCE_PLACING_SPITTERS = 7,
+ EVENT_ANNOUNCE_MASSIVE_WAVE = 8,
+ EVENT_ANNOUNCE_TUTORIAL_COMPLETED = 9,
+ EVENT_EJECT_PASSENGER = 10,
+ EVENT_SUNFLOWER_HIGHLIGHT = 11,
+ EVENT_ANNOUNCE_PLANT_MORE_FLOWERS = 12,
+ EVENT_SUNLIGHT = 13,
+ EVENT_CREATE_GHOUL = 14,
+ EVENT_KILL_LANE = 15,
+ EVENT_PLAGUE_GAS = 16,
+ EVENT_ANNOUNCE_LEVEL_1_COMPLETED = 17,
+
+ // Actions
+ ACTION_FIRST_SPITTER_PLANTED = 1,
+ ACTION_ZOMBIE_DAMAGED = 2,
+ ACTION_ZOMBIE_DIED = 3,
+ ACTION_GHOUL_DAMAGED = 4,
+ ACTION_QUEST_FAILED = 5,
+
+ // Misc
+ SEAT_0 = 0,
+
+ MAX_TARGET_POSITIONS = 5,
+ MAX_EMPTY_SPOT_POSITIONS = 40,
+ CENTER_ZOMBIE_LANE_INDEX = 2,
+
+ POINT_GOAL_STALKER = 1,
+ POINT_SPITTER_TARGET = 2,
+
+ DATA_CURRENT_ENTRY = 1,
+
+ PHASE_ID_QUEST = 365,
+
+ // Levels
+ LEVEL_TUTORIAL = 0,
+ LEVEL_1 = 1,
+};
+
+Position const LawnMowerPositions[MAX_TARGET_POSITIONS]
+{
+ { -116.5816f, 237.6823f, 53.2755f },
+ { -116.2934f, 228.9896f, 53.2755f },
+ { -116.0833f, 220.7691f, 53.2755f },
+ { -116.2674f, 213.0243f, 53.2755f },
+ { -115.9132f, 204.6198f, 53.2755f }
+};
+
+Position const GoalStalkerPositions[MAX_TARGET_POSITIONS]
+{
+ { -116.5816f, 237.6823f, 53.2755f },
+ { -116.2934f, 228.9896f, 53.2755f },
+ { -116.0833f, 220.7691f, 53.2755f },
+ { -116.2674f, 213.0243f, 53.2755f },
+ { -115.9132f, 204.6198f, 53.2755f }
+};
+
+Position const SpitterTargetPositions[MAX_TARGET_POSITIONS]
+{
+ { -39.83333f, 237.441f, 53.27685f },
+ { -40.13715f, 229.6163f, 53.33047f },
+ { -40.10764f, 221.4618f, 53.27604f },
+ { -40.06424f, 212.9444f, 53.3602f },
+ { -40.14236f, 205.0538f, 53.27604f }
+};
+
+Position const EmptySpotPositions[MAX_EMPTY_SPOT_POSITIONS]
+{
+ { -108.7604f, 221.0226f, 53.35883f },
+ { -108.3733f, 212.9219f, 53.35883f },
+ { -108.3108f, 229.2309f, 53.35883f },
+ { -107.9792f, 203.8629f, 53.35883f },
+ { -100.1684f, 220.6615f, 53.35883f },
+ { -99.92188f, 212.1406f, 53.35883f },
+ { -99.9375f, 204.8385f, 53.35883f },
+ { -100.0399f, 229.7882f, 53.35883f },
+ { -108.5486f, 237.4844f, 53.35883f },
+ { -91.59549f, 220.8715f, 53.35883f },
+ { -91.51563f, 212.7379f, 53.35883f },
+ { -100.3385f, 237.2656f, 53.35883f },
+ { -91.68056f, 229.1997f, 53.35883f },
+ { -91.32291f, 204.5434f, 53.35883f },
+ { -91.77604f, 237.5816f, 53.35883f },
+ { -83.93403f, 213.066f, 53.35883f },
+ { -83.21354f, 220.8542f, 53.35883f },
+ { -83.61459f, 204.592f, 53.35883f },
+ { -83.80903f, 229.6788f, 53.35883f },
+ { -83.52257f, 237.217f, 53.35883f },
+ { -75.24827f, 213.3108f, 53.35883f },
+ { -75.00174f, 220.9861f, 53.35883f },
+ { -75.34375f, 204.5382f, 53.35883f },
+ { -75.25521f, 229.5278f, 53.35883f },
+ { -75.10416f, 238.0816f, 53.35883f },
+ { -66.7934f, 213.071f, 53.35883f },
+ { -66.5469f, 220.747f, 53.35883f },
+ { -66.8889f, 204.299f, 53.35883f },
+ { -66.8003f, 229.288f, 53.35883f },
+ { -66.6493f, 237.842f, 53.35883f },
+ { -58.4965f, 212.372f, 53.35883f },
+ { -58.25f, 220.047f, 53.35883f },
+ { -58.5035f, 228.589f, 53.35883f },
+ { -58.592f, 203.599f, 53.35883f },
+ { -58.3524f, 237.142f, 53.35883f },
+ { -49.6059f, 212.569f, 53.35883f },
+ { -49.3594f, 220.245f, 53.35883f },
+ { -49.6128f, 228.786f, 53.35883f },
+ { -49.7014f, 203.797f, 53.35883f },
+ { -49.4618f, 237.34f, 53.35883f }
+};
+
+float const EmptySpotOrientation = 6.143559f;
+float const LawnmowerOrientation = 6.178465f;
+float const SpitterTargetOrientation = 6.232892f;
+float const GoalStalkerOrientation = 6.178465f;
+
+Position const SolarPowerJumpPos = { -64.24827f, 181.3004f, 53.97961f };
+
+Position const FreezyaSeedSummonPos = { -49.3594f, 220.245f, 56.35883f, 0.01745329f };
+Position const FreezyaSeedJumpPos = { -116.2847f, 216.7865f, 53.2755f };
+
+class npc_brazie_the_bonatist_vehicle : public CreatureScript
+{
+ public:
+ npc_brazie_the_bonatist_vehicle() : CreatureScript("npc_brazie_the_bonatist_vehicle") { }
+
+ struct npc_brazie_the_bonatist_vehicleAI : public VehicleAI
+ {
+ npc_brazie_the_bonatist_vehicleAI(Creature* creature) : VehicleAI(creature), _summons(me)
+ {
+ Inizialize();
+ }
+
+ void Inizialize()
+ {
+ _currentLevel = 1;
+ _deadZombieCount = 0;
+ _damagedZombieCount = 0;
+ _damagedGhoulCount = 0;
+ _currentStage = 0;
+
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ {
+ if (Player* player = charmer->ToPlayer())
+ {
+ if (player->GetQuestStatus(QUEST_BASIC_BOTANY) != QUEST_STATUS_REWARDED)
+ _currentLevel = LEVEL_TUTORIAL;
+ else if (player->GetQuestStatus(QUEST_BASIC_BOTANY) == QUEST_STATUS_REWARDED
+ && player->GetQuestStatus(QUEST_FLOWER_POWER) != QUEST_STATUS_REWARDED)
+ _currentLevel = LEVEL_1;
+ }
+ }
+ SetupActionBar();
+ }
+
+ void Reset() override
+ {
+ Inizialize();
+ }
+
+ void JustSummoned(Creature* summon) override
+ {
+ _summons.Summon(summon);
+
+ if (summon->GetEntry() == NPC_EMPTY_SPOT)
+ _spotGUIDs.push_back(summon->GetGUID());
+ }
+
+ void PassengerBoarded(Unit* passenger, int8 /*seatId*/, bool apply) override
+ {
+ if (!passenger)
+ return;
+
+ if (apply)
+ {
+ PhasingHandler::AddPhase(passenger, PHASE_ID_QUEST, true);
+ passenger->CastSpell(passenger, SPELL_PROGRESS_BAR, true);
+ SetupSpawns();
+
+ me->SetPower(POWER_ENERGY, 0);
+
+ // Scheduling first events
+ if (_currentLevel == LEVEL_TUTORIAL)
+ {
+ _events.ScheduleEvent(EVENT_SPITTER_HIGHLIGHT, Seconds(1));
+ _events.ScheduleEvent(EVENT_SUMMON_SOLAR_POWER, Seconds(1));
+ }
+ else if (_currentLevel == LEVEL_1)
+ {
+ _events.ScheduleEvent(EVENT_SUNFLOWER_HIGHLIGHT, Seconds(1));
+ _nextSolarPowerSeconds = Seconds(5);
+ _events.ScheduleEvent(EVENT_SUMMON_SOLAR_POWER, _nextSolarPowerSeconds + Milliseconds(500));
+ _events.ScheduleEvent(EVENT_CREATE_ZOMBIE, Seconds(41));
+
+ }
+
+ }
+ else
+ {
+ _events.Reset();
+ passenger->RemoveAurasDueToSpell(SPELL_PROGRESS_BAR);
+ passenger->RemoveAurasDueToSpell(SPELL_CREATE_BOTANISTS_VEHICLE);
+ PhasingHandler::RemovePhase(passenger, PHASE_ID_QUEST, true);
+ _summons.DespawnAll();
+ me->DespawnOrUnsummon(Milliseconds(100));
+ }
+ }
+
+ void SpellHit(Unit* caster, SpellInfo const* spell) override
+ {
+ switch (spell->Id)
+ {
+ case SPELL_GET_FREEZYA_SEEDS:
+ me->m_spells[2] = SPELL_PLANT_FREEZYA;
+ if (Player* player = caster->ToPlayer())
+ {
+ Talk(SAY_ANNOUNCE_GAINED_FREEZYA_SEEDS, player);
+ player->VehicleSpellInitialize();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_FIRST_SPITTER_PLANTED:
+ _events.ScheduleEvent(EVENT_CREATE_ZOMBIE, Milliseconds(500));
+ break;
+ case ACTION_ZOMBIE_DAMAGED:
+ _damagedZombieCount++;
+ if (_currentLevel == LEVEL_TUTORIAL && _currentStage < 2)
+ EnterNextStage();
+ if (_currentLevel == LEVEL_1)
+ {
+ if (_currentStage == 0 && _damagedZombieCount == 1)
+ EnterNextStage();
+ if (_currentStage == 1 && _damagedZombieCount == 2)
+ EnterNextStage();
+ }
+ break;
+ case ACTION_ZOMBIE_DIED:
+ _deadZombieCount++;
+ if (_currentLevel == LEVEL_TUTORIAL)
+ {
+ if (_deadZombieCount == 3)
+ EnterNextStage();
+ if (_deadZombieCount == 8)
+ EnterNextStage();
+ }
+
+ if (_currentLevel == LEVEL_1)
+ {
+ if (_deadZombieCount == 4 && _currentStage == 2)
+ EnterNextStage();
+ if (_deadZombieCount == 11 && _currentStage == 3)
+ EnterNextStage();
+ if (_deadZombieCount == 27 && _currentStage == 4)
+ EnterNextStage();
+ }
+ break;
+ case ACTION_GHOUL_DAMAGED:
+ _damagedGhoulCount++;
+ if (_currentLevel == LEVEL_1)
+ {
+ if (_damagedGhoulCount == 1)
+ {
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ {
+ if (Player* player = charmer->ToPlayer())
+ {
+ player->Whisper(SAY_ANNOUNCE_DROPPED_SEED, player, true);
+ player->CastSpell(player, SPELL_CREATE_RANDOM_FREEZYA_SACK, true);
+ }
+ }
+ }
+ }
+ break;
+ case ACTION_QUEST_FAILED:
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ {
+ if (Player* player = charmer->ToPlayer())
+ {
+ if (_currentLevel == LEVEL_TUTORIAL)
+ player->FailQuest(QUEST_BASIC_BOTANY);
+ else if (_currentLevel == LEVEL_1)
+ player->FailQuest(QUEST_FLOWER_POWER);
+ }
+ }
+
+ Talk(SAY_ANNOUNCE_ZOMBIES_ATE_BRAIN);
+ _summons.DespawnEntry(NPC_ZOMBIE);
+ _summons.DespawnEntry(NPC_GHOUL);
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_EJECT_PASSENGER, Seconds(2) + Milliseconds(300));
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SPITTER_HIGHLIGHT:
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ {
+ if (Player* player = charmer->ToPlayer())
+ player->Whisper(SAY_ANNOUNCE_TUTORIAL_1, player, true);
+
+ charmer->CastSpell(charmer, SPELL_SPITTER_HIGHLIGHT, true);
+ }
+ break;
+ case EVENT_SUMMON_SOLAR_POWER:
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ {
+ uint8 randomPositionIndex = urand(0, MAX_EMPTY_SPOT_POSITIONS - 1);
+ Position pos = EmptySpotPositions[randomPositionIndex];
+ float angle = frand(0, float(M_PI * 2));
+ float x = pos.GetPositionX() + cos(angle) * 3;
+ float y = pos.GetPositionY() + sin(angle) * 3;
+
+ charmer->CastSpell(x, y, pos.GetPositionZ() + 50.0f, SPELL_CREATE_RANDOM_SUN_POWER, true);
+
+ if (_currentLevel == LEVEL_TUTORIAL)
+ _events.Repeat(Seconds(4));
+ else if (_currentLevel == LEVEL_1)
+ {
+ if (_nextSolarPowerSeconds == Seconds(5))
+ {
+ _nextSolarPowerSeconds = Seconds(10);
+ _events.Repeat(_nextSolarPowerSeconds);
+ }
+ else
+ {
+ _nextSolarPowerSeconds = Seconds(5);
+ _events.Repeat(_nextSolarPowerSeconds);
+ }
+ }
+ }
+ break;
+ case EVENT_CREATE_ZOMBIE:
+ {
+ uint8 index = urand(0, MAX_TARGET_POSITIONS - 1);
+
+ if (_currentLevel == LEVEL_TUTORIAL)
+ index = CENTER_ZOMBIE_LANE_INDEX;
+
+ Position pos = SpitterTargetPositions[index];
+ float angle = pos.GetAngle(GoalStalkerPositions[index]);
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ charmer->CastSpell(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), angle, SPELL_CREATE_ZOMBIE, true);
+ break;
+ }
+ case EVENT_ANNOUNCE_GOOD_JOB:
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ {
+ if (Player* player = charmer->ToPlayer())
+ player->Whisper(SAY_ANNOUNCE_TUTORIAL_2, player, true);
+ }
+ _events.ScheduleEvent(EVENT_CREATE_ZOMBIE, Milliseconds(1));
+ break;
+ case EVENT_ANNOUNCE_PLACING_SPITTERS:
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ {
+ if (Player* player = charmer->ToPlayer())
+ {
+ player->Whisper(SAY_ANNOUNCE_TUTORIAL_3, player, true);
+ player->SetPower(POWER_ALTERNATE_POWER, 1);
+ }
+ }
+ _events.ScheduleEvent(EVENT_CREATE_ZOMBIE, Milliseconds(1));
+ break;
+ case EVENT_ANNOUNCE_MASSIVE_WAVE:
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ {
+ if (Player* player = charmer->ToPlayer())
+ {
+ player->Whisper(SAY_ANNOUNCE_MASSIVE_WAVE, player, true);
+
+ if (_currentLevel == LEVEL_TUTORIAL)
+ player->SetPower(POWER_ALTERNATE_POWER, 3);
+ if (_currentLevel == LEVEL_1)
+ player->SetPower(POWER_ALTERNATE_POWER, 4);
+ }
+ }
+ break;
+ case EVENT_ANNOUNCE_TUTORIAL_COMPLETED:
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ {
+ if (Player* player = charmer->ToPlayer())
+ {
+ player->Whisper(SAY_ANNOUNCE_TUTORIAL_4, player, true);
+ player->RemoveAurasDueToSpell(SPELL_PROGRESS_BAR);
+ player->KilledMonsterCredit(CREDIT_BASIC_BOTANY);
+ }
+ }
+ break;
+ case EVENT_EJECT_PASSENGER:
+ DoCastSelf(SPELL_EJECT_ALL_PASSENGERS, true);
+ break;
+ case EVENT_SUNFLOWER_HIGHLIGHT:
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ {
+ if (Player* player = charmer->ToPlayer())
+ player->Whisper(SAY_ANNOUNCE_PLANT_SUNFLOWER, player, true);
+
+ charmer->CastSpell(charmer, SPELL_SUNFLOWER_HIGHLIGHT, true);
+ }
+ _events.ScheduleEvent(EVENT_ANNOUNCE_PLANT_MORE_FLOWERS, Seconds(1));
+ break;
+ case EVENT_ANNOUNCE_PLANT_MORE_FLOWERS:
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ if (Player* player = charmer->ToPlayer())
+ player->Whisper(SAY_ANNOUNCE_PLANT_MORE_SUNFLOWERS, player, true);
+ break;
+ case EVENT_CREATE_GHOUL:
+ {
+ uint8 index = urand(0, MAX_TARGET_POSITIONS - 1);
+
+ Position pos = SpitterTargetPositions[index];
+ float angle = pos.GetAngle(GoalStalkerPositions[index]);
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ charmer->CastSpell(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), angle, SPELL_CREATE_GHOUL, true);
+ break;
+ }
+ case EVENT_ANNOUNCE_LEVEL_1_COMPLETED:
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ {
+ if (Player* player = charmer->ToPlayer())
+ {
+ player->Whisper(SAY_ANNOUNCE_LEVEL_1_COMPLETE, player, true);
+ player->RemoveAurasDueToSpell(SPELL_PROGRESS_BAR);
+ player->KilledMonsterCredit(CREDIT_FLOWER_POWER);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+
+ bool IsSpotFree(Position const* pos)
+ {
+ for (ObjectGuid guid : _spotGUIDs)
+ {
+ if (Creature* spot = ObjectAccessor::GetCreature(*me, guid))
+ if (spot->GetDistance(*pos) <= 5.0f)
+ if (spot->IsAIEnabled)
+ if (spot->AI()->GetData(DATA_CURRENT_ENTRY) == NPC_EMPTY_SPOT)
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ void SetupSpawns()
+ {
+ Unit* charmer = me->GetCharmerOrOwner();
+ if (!charmer)
+ return;
+
+ for (uint8 i = 0; i < MAX_TARGET_POSITIONS; i++)
+ {
+ Position pos = LawnMowerPositions[i];
+ charmer->CastSpell(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), LawnmowerOrientation, SPELL_CREATE_LAWMOWER, true);
+
+ pos = GoalStalkerPositions[i];
+ charmer->CastSpell(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), GoalStalkerOrientation, SPELL_CREATE_GOAL_STALKER, true);
+
+ pos = SpitterTargetPositions[i];
+ charmer->CastSpell(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), SpitterTargetOrientation, SPELL_CREATE_SPITTER_TARGET, true);
+ }
+
+ for (uint8 i = 0; i < MAX_EMPTY_SPOT_POSITIONS; i++)
+ {
+ Position pos = EmptySpotPositions[i];
+ charmer->CastSpell(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), EmptySpotOrientation, SPELL_CREATE_EMPTY_SPOT, true);
+ }
+ }
+
+ void SetupActionBar()
+ {
+ if (_currentLevel == LEVEL_TUTORIAL)
+ me->m_spells[0] = SPELL_PLANT_SPITTER;
+ else if (_currentLevel == LEVEL_1)
+ {
+ me->m_spells[0] = SPELL_PLANT_SUNFLOWER;
+ me->m_spells[1] = SPELL_PLANT_SPITTER;
+ }
+ }
+
+ void EnterNextStage()
+ {
+ _currentStage++;
+
+ // Tutorial Stages
+ if (_currentLevel == LEVEL_TUTORIAL)
+ {
+ if (_currentStage == 1)
+ _events.ScheduleEvent(EVENT_ANNOUNCE_GOOD_JOB, Milliseconds(1));
+
+ if (_currentStage == 2)
+ _events.ScheduleEvent(EVENT_ANNOUNCE_PLACING_SPITTERS, Milliseconds(1));
+
+ if (_currentStage == 3)
+ {
+ _events.ScheduleEvent(EVENT_ANNOUNCE_MASSIVE_WAVE, Milliseconds(1));
+ CreateZombies(5, Seconds(1) + Milliseconds(800), Seconds(3));
+ }
+
+ if (_currentStage == 4)
+ {
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_ANNOUNCE_TUTORIAL_COMPLETED, Milliseconds(1));
+ _events.ScheduleEvent(EVENT_EJECT_PASSENGER, Seconds(1) + Milliseconds(600));
+ }
+ }
+
+ // Level 1 Stages
+ if (_currentLevel == LEVEL_1)
+ {
+ if (_currentStage == 1)
+ {
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ if (Player* player = charmer->ToPlayer())
+ player->SetPower(POWER_ALTERNATE_POWER, 1);
+
+ CreateZombies(2, Seconds(5), Seconds(7));
+ }
+
+ if (_currentStage == 2)
+ {
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ if (Player* player = charmer->ToPlayer())
+ player->SetPower(POWER_ALTERNATE_POWER, 2);
+
+
+ CreateZombies(3, Seconds(8), Seconds(7));
+ }
+
+ if (_currentStage == 3)
+ {
+ if (Unit* charmer = me->GetCharmerOrOwner())
+ if (Player* player = charmer->ToPlayer())
+ player->SetPower(POWER_ALTERNATE_POWER, 3);
+
+ CreateZombies(3, Seconds(35), Seconds(5));
+ CreateGhouls(2, Seconds(6), Seconds(39));
+ }
+
+ if (_currentStage == 4)
+ {
+ _events.ScheduleEvent(EVENT_ANNOUNCE_MASSIVE_WAVE, Milliseconds(500));
+ CreateZombies(2, Seconds(2), Seconds(3));
+ CreateZombies(5, Seconds(2), Seconds(3));
+ CreateZombies(1, Seconds(20), Seconds(0));
+ CreateZombies(2, Seconds(20), Seconds(2));
+ CreateZombies(1, Seconds(29), Seconds(0));
+ CreateZombies(1, Seconds(29), Seconds(0));
+
+ CreateGhouls(2, Seconds(8), Seconds(3));
+ CreateGhouls(1, Seconds(26), Seconds(0));
+ CreateGhouls(1, Seconds(26), Seconds(0));
+ }
+
+ if (_currentStage == 5)
+ {
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_ANNOUNCE_LEVEL_1_COMPLETED, Milliseconds(1));
+ _events.ScheduleEvent(EVENT_EJECT_PASSENGER, Seconds(1) + Milliseconds(600));
+ }
+ }
+ }
+
+ void CreateZombies(uint8 amount, Milliseconds const& delay, Milliseconds const& repeatTimer)
+ {
+ for (uint8 i = 0; i < amount; i++)
+ _events.ScheduleEvent(EVENT_CREATE_ZOMBIE, delay + (repeatTimer * i));
+ }
+
+ void CreateGhouls(uint8 amount, Milliseconds const& delay, Milliseconds const& repeatTimer)
+ {
+ for (uint8 i = 0; i < amount; i++)
+ _events.ScheduleEvent(EVENT_CREATE_GHOUL, delay + (repeatTimer * i));
+ }
+
+ EventMap _events;
+ SummonList _summons;
+ GuidVector _spotGUIDs;
+ uint8 _currentLevel;
+ uint8 _deadZombieCount;
+ uint8 _damagedZombieCount;
+ uint8 _damagedGhoulCount;
+ uint8 _currentStage;
+ Seconds _nextSolarPowerSeconds;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_brazie_the_bonatist_vehicleAI(creature);
+ }
+};
+
+class npc_brazie_fertilitize_o_tron_2000 : public CreatureScript
+{
+ public:
+ npc_brazie_fertilitize_o_tron_2000() : CreatureScript("npc_brazie_fertilitize_o_tron_2000") { }
+
+ struct npc_brazie_fertilitize_o_tron_2000AI : public ScriptedAI
+ {
+ npc_brazie_fertilitize_o_tron_2000AI(Creature* creature) : ScriptedAI(creature) { }
+
+ void IsSummonedBy(Unit* summoner) override
+ {
+ me->m_CombatDistance = 4.0f;
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid2);
+
+ if (Creature* vehicle = summoner->GetVehicleCreatureBase())
+ if (vehicle->IsAIEnabled)
+ vehicle->AI()->JustSummoned(me);
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ if (me->GetPosition().GetExactDist(who->GetPosition()) > 4.0f)
+ return;
+
+ if (Creature* spitterTarget = me->FindNearestCreature(NPC_SPITTER_TARGET, 150.0f, true))
+ {
+ Position pos = me->GetPosition();
+ pos.SetOrientation(pos.GetAngle(spitterTarget));
+
+ if (pos.HasInLine(who, 5.0f))
+ CreatureAI::AttackStart(who);
+ }
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ DoCast(who, SPELL_DAZED, true);
+ DoCastSelf(SPELL_LAWNMOWER_STARTUP_SOUND, true);
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ _events.ScheduleEvent(EVENT_KILL_LANE, Milliseconds(300));
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE)
+ return;
+
+ if (id == POINT_SPITTER_TARGET)
+ me->DespawnOrUnsummon();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_KILL_LANE:
+ if (Creature* spitterTarget = me->FindNearestCreature(NPC_SPITTER_TARGET, 150.0f, true))
+ me->GetMotionMaster()->MovePoint(POINT_SPITTER_TARGET, spitterTarget->GetPosition(), false);
+ _events.ScheduleEvent(EVENT_PLAGUE_GAS, Milliseconds(200));
+ break;
+ case EVENT_PLAGUE_GAS:
+ DoCastAOE(SPELL_PLAGUE_GAS, true);
+ _events.Repeat(Milliseconds(500));
+ break;
+ default:
+ break;
+ }
+ }
+
+ }
+ private:
+ EventMap _events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_brazie_fertilitize_o_tron_2000AI(creature);
+ }
+};
+
+class npc_brazie_spot : public CreatureScript
+{
+ public:
+ npc_brazie_spot() : CreatureScript("npc_brazie_spot") { }
+
+ struct npc_brazie_spotAI : public ScriptedAI
+ {
+ npc_brazie_spotAI(Creature* creature) : ScriptedAI(creature)
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ _currentEntry = me->GetEntry();
+ }
+
+ void DamageTaken(Unit* attacker, uint32& damage) override
+ {
+ if (damage >= me->GetHealth())
+ {
+ damage = 0;
+
+ me->SetFullHealth();
+ me->UpdateEntry(NPC_EMPTY_SPOT);
+ _currentEntry = NPC_EMPTY_SPOT;
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid1);
+ me->AttackStop();
+ me->SetFacingTo(me->GetHomePosition().GetOrientation());
+ _events.Reset();
+ }
+ }
+
+ void IsSummonedBy(Unit* summoner) override
+ {
+ me->m_SightDistance = 150.0f;
+ me->m_CombatDistance = 150.0f;
+
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid1);
+
+ if (Creature* vehicle = summoner->GetVehicleCreatureBase())
+ if (vehicle->IsAIEnabled)
+ vehicle->AI()->JustSummoned(me);
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ if (_currentEntry == NPC_EMPTY_SPOT || _currentEntry == NPC_SUNFLOWER)
+ return;
+
+ if (who->GetEntry() != NPC_ZOMBIE && who->GetEntry() != NPC_GHOUL)
+ return;
+
+ if (Creature* spitterTarget = me->FindNearestCreature(NPC_SPITTER_TARGET, 150.0f, true))
+ {
+ Position pos = me->GetPosition();
+ pos.SetOrientation(pos.GetAngle(spitterTarget));
+
+ if (pos.HasInLine(who, 5.0f))
+ {
+ me->SetFacingToObject(spitterTarget);
+ CreatureAI::AttackStart(who);
+ }
+ }
+ }
+
+ uint32 GetData(uint32 type) const override
+ {
+ if (type == DATA_CURRENT_ENTRY)
+ return _currentEntry;
+
+ return 0;
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ switch (spell->Id)
+ {
+ case SPELL_PLANT_SPITTER:
+ me->UpdateEntry(NPC_SPITTER);
+ _currentEntry = NPC_SPITTER;
+ break;
+ case SPELL_PLANT_SUNFLOWER:
+ me->UpdateEntry(NPC_SUNFLOWER);
+ _currentEntry = NPC_SUNFLOWER;
+ _events.ScheduleEvent(EVENT_SUNLIGHT, Seconds(16));
+ break;
+ case SPELL_PLANT_FREEZYA:
+ me->UpdateEntry(NPC_FREEZYA);
+ _currentEntry = NPC_FREEZYA;
+ break;
+ default:
+ break;
+ }
+
+ if (spell->Id != SPELL_PLAGUE_GAS)
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid2);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SUNLIGHT:
+ DoCastSelf(SPELL_SUNLIGHT, true);
+ if (TempSummon* summon = me->ToTempSummon())
+ {
+ if (Unit* summoner = summon->GetSummoner())
+ {
+ uint8 randomPositionIndex = urand(0, MAX_EMPTY_SPOT_POSITIONS - 1);
+ Position pos = EmptySpotPositions[randomPositionIndex];
+ float angle = frand(0, float(M_PI * 2));
+ float x = pos.GetPositionX() + cos(angle) * 3;
+ float y = pos.GetPositionY() + sin(angle) * 3;
+
+ summoner->CastSpell(x, y, pos.GetPositionZ() + 50.0f, SPELL_CREATE_RANDOM_SUN_POWER, true);
+ }
+ }
+ _events.Repeat(Seconds(17));
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (_currentEntry == NPC_SPITTER)
+ DoSpellAttackIfReady(SPELL_VENOM_SPIT);
+ else if (_currentEntry == NPC_FREEZYA)
+ DoSpellAttackIfReady(SPELL_FREEZYA_BLAST);
+ }
+
+ private:
+ EventMap _events;
+ uint32 _currentEntry;
+ GuidVector _zombieGuids;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_brazie_spotAI(creature);
+ }
+};
+
+class npc_brazie_zombie : public CreatureScript
+{
+ public:
+ npc_brazie_zombie() : CreatureScript("npc_brazie_zombie") { }
+
+ struct npc_brazie_zombieAI : public ScriptedAI
+ {
+ npc_brazie_zombieAI(Creature* creature) : ScriptedAI(creature)
+ {
+ Inizialize();
+ }
+
+ void Inizialize()
+ {
+ _pathIndex = 0;
+ _notifiedLowHealth = false;
+ }
+
+ void IsSummonedBy(Unit* summoner) override
+ {
+ me->m_SightDistance = 3.0f;
+ me->m_CombatDistance = 3.0f;
+
+ me->SetWalk(true);
+
+ if (Creature* vehicle = summoner->GetVehicleCreatureBase())
+ if (vehicle->IsAIEnabled)
+ vehicle->AI()->JustSummoned(me);
+
+ for (uint8 i = 0; i < MAX_TARGET_POSITIONS; i++)
+ if (me->GetPosition().GetExactDist(SpitterTargetPositions[i]) <= 1.0f)
+ _pathIndex = i;
+
+ if (me->GetEntry() == NPC_ZOMBIE)
+ DoCastSelf(SPELL_ZOMBIE_GROWL);
+ else if (me->GetEntry() == NPC_GHOUL)
+ {
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid4);
+ DoCastSelf(SPELL_GHOUL_GROWL, true);
+ DoCastSelf(SPELL_BUCKET_HEAD, true);
+ }
+
+ _events.ScheduleEvent(EVENT_MOVE_TO_GOAL_POSITION, Seconds(2) + Milliseconds(400));
+ }
+
+ void AttackStart(Unit* who) override
+ {
+ // Just to make sure that a zombie wont call nearby zombies for aid
+ if (who->GetDistance(me) > 3.0f)
+ return;
+
+ // If we have a plant very close to us we assume that this plant has been added afterwards
+ if (me->GetPosition().GetExactDist(who) < 3.0f)
+ return;
+
+ // Do not attack plants behind me if they got replanted
+ if (!who->isInFront(me, 1.8f))
+ return;
+
+
+ Position pos = me->GetPosition();
+ pos.SetOrientation(pos.GetAngle(GoalStalkerPositions[_pathIndex]));
+
+ if (pos.HasInLine(who, 4.7f))
+ {
+ if (Creature* target = who->ToCreature())
+ {
+ if (target->IsAIEnabled)
+ {
+ if (target->AI()->GetData(DATA_CURRENT_ENTRY) != NPC_EMPTY_SPOT || target->GetEntry() == NPC_FERTILITIZE_O_TRON_2000)
+ {
+ me->StopMoving();
+ CreatureAI::AttackStart(who);
+ }
+ }
+ }
+ }
+ }
+
+ void JustDied(Unit* /*killer*/)
+ {
+ if (TempSummon* summon = me->ToTempSummon())
+ if (Unit* summoner = summon->GetSummoner())
+ if (Creature* vehicle = summoner->GetVehicleCreatureBase())
+ if (vehicle->IsAIEnabled)
+ vehicle->AI()->DoAction(ACTION_ZOMBIE_DIED);
+
+ me->DespawnOrUnsummon(Seconds(4));
+ }
+
+ void DamageTaken(Unit* /*attacker*/, uint32& damage) override
+ {
+ if (me->HealthBelowPctDamaged(50, damage) && !_notifiedLowHealth)
+ {
+ if (me->GetEntry() == NPC_ZOMBIE)
+ DoCastSelf(SPELL_LEAKING_GUTS, true);
+ else if (me->GetEntry() == NPC_GHOUL)
+ {
+ me->RemoveAurasDueToSpell(SPELL_BUCKET_HEAD);
+ DoCastSelf(SPELL_BUCKET, true);
+ }
+
+ if (TempSummon* summon = me->ToTempSummon())
+ {
+ if (Unit* summoner = summon->GetSummoner())
+ {
+ if (Creature* vehicle = summoner->GetVehicleCreatureBase())
+ {
+ if (vehicle->IsAIEnabled)
+ {
+ if (me->GetEntry() == NPC_ZOMBIE)
+ vehicle->AI()->DoAction(ACTION_ZOMBIE_DAMAGED);
+ else if (me->GetEntry() == NPC_GHOUL)
+ vehicle->AI()->DoAction(ACTION_GHOUL_DAMAGED);
+ }
+ }
+ }
+ }
+
+ _notifiedLowHealth = true;
+ }
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE)
+ return;
+
+ if (id == POINT_GOAL_STALKER)
+ if (me->GetPosition().GetExactDist(GoalStalkerPositions[_pathIndex]) <= 0.1f)
+ if (TempSummon* summon = me->ToTempSummon())
+ if (Unit* summoner = summon->GetSummoner())
+ if (Creature* vehicle = summoner->GetVehicleCreatureBase())
+ if (vehicle->IsAIEnabled)
+ vehicle->AI()->DoAction(ACTION_QUEST_FAILED);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_MOVE_TO_GOAL_POSITION:
+ me->GetMotionMaster()->MovePoint(POINT_GOAL_STALKER, GoalStalkerPositions[_pathIndex], false);
+ _events.ScheduleEvent(EVENT_CHECK_VICTIM_STATE, Seconds(1));
+ break;
+ case EVENT_CHECK_VICTIM_STATE:
+ if (Unit* victim = me->GetVictim())
+ {
+ if (Creature* target = victim->ToCreature())
+ {
+ if (target->IsAIEnabled)
+ {
+ if (target->AI()->GetData(DATA_CURRENT_ENTRY) == NPC_EMPTY_SPOT)
+ {
+ me->AttackStop();
+ me->SetWalk(true);
+ me->GetMotionMaster()->MovePoint(POINT_GOAL_STALKER, GoalStalkerPositions[_pathIndex], false);
+ }
+ }
+ }
+ }
+
+ _events.Repeat(Seconds(1));
+ break;
+ default:
+ break;
+ }
+ }
+ DoMeleeAttackIfReady();
+
+ }
+ private:
+ EventMap _events;
+ uint8 _pathIndex;
+ bool _notifiedLowHealth;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_brazie_zombieAI(creature);
+ }
+};
+
+class npc_brazie_vehicle_notifier : public CreatureScript
+{
+ public:
+ npc_brazie_vehicle_notifier() : CreatureScript("npc_brazie_vehicle_notifier") { }
+
+ struct npc_brazie_vehicle_notifierAI : public ScriptedAI
+ {
+ npc_brazie_vehicle_notifierAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void IsSummonedBy(Unit* summoner) override
+ {
+ switch (me->GetEntry())
+ {
+ case NPC_SOLAR_POWER:
+ case NPC_FREEZYA_SEEDS:
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid2);
+ me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+ break;
+ case NPC_PLACE_IT_HERE:
+ me->Relocate(EmptySpotPositions[0]);
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid2);
+ break;
+ default:
+ me->SetDisplayId(me->GetCreatureTemplate()->Modelid1);
+ break;
+ }
+
+ if (Creature* vehicle = summoner->GetVehicleCreatureBase())
+ if (vehicle->IsAIEnabled)
+ vehicle->AI()->JustSummoned(me);
+ }
+
+ void SpellHit(Unit* caster, SpellInfo const* spell) override
+ {
+ if (!caster)
+ return;
+
+ switch (spell->Id)
+ {
+ case SPELL_GAIN_SOLAR_POWER_SPELLCLICK:
+ if (Unit* vehicle = caster->GetVehicleCreatureBase())
+ DoCast(vehicle, SPELL_GAIN_SOLAR_POWER_ENERGIZE, true);
+ me->GetMotionMaster()->MoveJump(SolarPowerJumpPos, 45.0f, 20.0f);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
+ me->DespawnOrUnsummon(Seconds(2));
+ break;
+ case SPELL_GET_FREEZYA_SEEDS:
+ me->GetMotionMaster()->MoveJump(FreezyaSeedJumpPos, 45.0f, 20.0f);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
+ me->DespawnOrUnsummon(Seconds(2));
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return new npc_brazie_vehicle_notifierAI(creature);
+ }
+};
+
+class spell_brazie_summon_plant : public SpellScriptLoader
+{
+ public:
+ spell_brazie_summon_plant() : SpellScriptLoader("spell_brazie_summon_plant") { }
+
+ class spell_brazie_summon_plant_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_brazie_summon_plant_SpellScript);
+
+ SpellCastResult CheckLocation()
+ {
+ if (Creature* creature = GetCaster()->ToCreature())
+ if (CAST_AI(npc_brazie_the_bonatist_vehicle::npc_brazie_the_bonatist_vehicleAI,
+ creature->AI())->IsSpotFree(&GetExplTargetDest()->GetPosition()))
+ return SPELL_CAST_OK;
+
+ return SPELL_FAILED_BAD_TARGETS;
+ }
+
+ void PreventEffect(SpellEffIndex effIndex)
+ {
+ PreventHitEffect(effIndex);
+ }
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ Unit* caster = GetCaster();
+ if (!caster)
+ return;
+
+ Creature* creature = caster->ToCreature();
+ if (!creature)
+ return;
+
+ Unit* target = GetHitUnit();
+ if (!target)
+ return;
+
+ if (Creature* dummy = target->FindNearestCreature(NPC_PLACE_IT_HERE, 150.0f, true))
+ {
+ dummy->DespawnOrUnsummon();
+
+ switch (GetSpellInfo()->Id)
+ {
+ case SPELL_PLANT_SPITTER:
+ if (creature->HasAura(SPELL_SPITTER_HIGHLIGHT))
+ {
+ creature->RemoveAurasDueToSpell(SPELL_SPITTER_HIGHLIGHT);
+ if (creature->IsAIEnabled)
+ creature->AI()->DoAction(ACTION_FIRST_SPITTER_PLANTED);
+ }
+ break;
+ case SPELL_PLANT_SUNFLOWER:
+ if (creature->HasAura(SPELL_SUNFLOWER_HIGHLIGHT))
+ creature->RemoveAurasDueToSpell(SPELL_SUNFLOWER_HIGHLIGHT);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ void Register() override
+ {
+ OnCheckCast += SpellCheckCastFn(spell_brazie_summon_plant_SpellScript::CheckLocation);
+ OnEffectHitTarget += SpellEffectFn(spell_brazie_summon_plant_SpellScript::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY);
+ OnEffectHit += SpellEffectFn(spell_brazie_summon_plant_SpellScript::PreventEffect, EFFECT_0, SPELL_EFFECT_TRANS_DOOR);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_brazie_summon_plant_SpellScript();
+ }
+};
+
+class spell_brazie_highlight : public SpellScriptLoader
+{
+ public:
+ spell_brazie_highlight() : SpellScriptLoader("spell_brazie_highlight") { }
+
+ class spell_brazie_highlight_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_brazie_highlight_SpellScript);
+
+ void SetDestPosition(SpellEffIndex /*effIndex*/)
+ {
+ const_cast(GetExplTargetDest())->Relocate(EmptySpotPositions[0]);
+ GetHitDest()->Relocate(EmptySpotPositions[0]);
+ }
+
+ void Register()
+ {
+ OnEffectLaunch += SpellEffectFn(spell_brazie_highlight_SpellScript::SetDestPosition, EFFECT_1, SPELL_EFFECT_SUMMON);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_brazie_highlight_SpellScript();
+ }
+};
+
+class spell_brazie_create_random_seed_sack : public SpellScriptLoader
+{
+ public:
+ spell_brazie_create_random_seed_sack() : SpellScriptLoader("spell_brazie_create_random_seed_sack") { }
+
+ class spell_brazie_create_random_seed_sack_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_brazie_create_random_seed_sack_SpellScript);
+
+ void SetDestPosition(SpellEffIndex /*effIndex*/)
+ {
+ Position const pos = GetSpellInfo()->Id == SPELL_CREATE_RANDOM_FREEZYA_SACK ? FreezyaSeedSummonPos : GetExplTargetDest()->GetPosition();
+
+ const_cast(GetExplTargetDest())->Relocate(pos);
+ GetHitDest()->Relocate(pos);
+ }
+
+ void Register()
+ {
+ OnEffectLaunch += SpellEffectFn(spell_brazie_create_random_seed_sack_SpellScript::SetDestPosition, EFFECT_0, SPELL_EFFECT_SUMMON);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_brazie_create_random_seed_sack_SpellScript();
+ }
+};
+
+class spell_brazie_spit : public SpellScriptLoader
+{
+ public:
+ spell_brazie_spit() : SpellScriptLoader("spell_brazie_spit") { }
+
+ class spell_brazie_spit_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_brazie_spit_SpellScript);
+
+ void FilterTargets(std::list& targets)
+ {
+ if (targets.empty())
+ return;
+
+ if (GetSpellInfo()->Id == SPELL_VENOM_SPIT)
+ {
+ targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), true));
+ targets.resize(1);
+ }
+ else
+ {
+ std::list targetsBackup = targets;
+ targetsBackup.remove_if(Trinity::UnitAuraCheck(true, SPELL_FREEZYA_BLAST));
+ if (targetsBackup.empty())
+ {
+ targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), true));
+ targets.resize(1);
+ }
+ else
+ {
+ targets = targetsBackup;
+ targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), true));
+ targets.resize(1);
+ }
+ }
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_brazie_spit_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_CONE_ENEMY_104);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_brazie_spit_SpellScript();
+ }
+};
+
+void AddSC_hillsbrad_foothills()
+{
+ new npc_brazie_the_bonatist_vehicle();
+ new npc_brazie_fertilitize_o_tron_2000();
+ new npc_brazie_spot();
+ new npc_brazie_zombie();
+ new npc_brazie_vehicle_notifier();
+ new spell_brazie_summon_plant();
+ new spell_brazie_highlight();
+ new spell_brazie_create_random_seed_sack();
+ new spell_brazie_spit();
+}