Scripts/RedridgeMountains: Implement Quest "Saving Foreman Oslow" (#30947)

This commit is contained in:
Jason Dove
2025-05-30 04:04:07 -05:00
committed by GitHub
parent e39dddec0b
commit a50e1c7ab3
2 changed files with 684 additions and 131 deletions

View File

@@ -0,0 +1,122 @@
# fix respawn times for bridge workers, foreman oslow, and huge boulder
UPDATE `creature` SET `spawntimesecs` = 30 WHERE `guid` IN (334925, 334930, 334929, 334928, 334931, 334927, 334926, 334924);
# move script from alex to boulder
UPDATE `creature_template` SET `ScriptName`='npc_redridge_huge_boulder' WHERE `entry` = 43196; -- Huge Boulder
UPDATE `creature_template` SET `ScriptName`='' WHERE `entry` = 653; -- Bridge Worker Alex
UPDATE `creature_template` SET `unit_flags2`=0x800 WHERE `entry`=43094; -- Canyon Ettin
UPDATE `creature_template` SET `faction`=35, `unit_flags`=0x40, `VehicleId`=938, `ScriptName`='npc_redridge_subdued_canyon_ettin' WHERE `entry`=43197; -- Subdued Canyon Ettin
UPDATE `creature_template` SET `unit_flags3`=0x1000000 WHERE `entry`=43196; -- Huge Boulder
DELETE FROM `creature_template_addon` WHERE `entry` IN (43197 /*43197 (Subdued Canyon Ettin) - Detect: Quest Invis Zone 1*/);
INSERT INTO `creature_template_addon` (`entry`, `PathId`, `mount`, `StandState`, `AnimTier`, `VisFlags`, `SheathState`, `PvpFlags`, `emote`, `aiAnimKit`, `movementAnimKit`, `meleeAnimKit`, `visibilityDistanceType`, `auras`) VALUES
(43197, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, '81299'); -- 43197 (Subdued Canyon Ettin) - Detect: Quest Invis Zone 1
UPDATE `creature_template_difficulty` SET `StaticFlags1`=0x0, `VerifiedBuild`=60822 WHERE (`Entry`=341 AND `DifficultyID`=0); -- 341 (Foreman Oslow) -
UPDATE `creature_template_difficulty` SET `StaticFlags1`=0x0, `VerifiedBuild`=60822 WHERE (`Entry`=648 AND `DifficultyID`=0); -- 648 (Bridge Worker Trent) -
UPDATE `creature_template_difficulty` SET `StaticFlags1`=0x0, `VerifiedBuild`=60822 WHERE (`Entry`=649 AND `DifficultyID`=0); -- 649 (Bridge Worker Dmitri) -
UPDATE `creature_template_difficulty` SET `StaticFlags1`=0x0, `VerifiedBuild`=60822 WHERE (`Entry`=650 AND `DifficultyID`=0); -- 650 (Bridge Worker Jess) -
UPDATE `creature_template_difficulty` SET `StaticFlags1`=0x0, `VerifiedBuild`=60822 WHERE (`Entry`=651 AND `DifficultyID`=0); -- 651 (Bridge Worker Daniel) -
UPDATE `creature_template_difficulty` SET `StaticFlags1`=0x0, `VerifiedBuild`=60822 WHERE (`Entry`=652 AND `DifficultyID`=0); -- 652 (Bridge Worker Matthew) -
UPDATE `creature_template_difficulty` SET `StaticFlags1`=0x0, `VerifiedBuild`=60822 WHERE (`Entry`=653 AND `DifficultyID`=0); -- 653 (Bridge Worker Alex) -
UPDATE `creature_template_difficulty` SET `StaticFlags1`=0x0, `VerifiedBuild`=60822 WHERE (`Entry`=43094 AND `DifficultyID`=0); -- 43094 (Canyon Ettin) -
UPDATE `creature_template_difficulty` SET `StaticFlags1`=0x0, `VerifiedBuild`=60822 WHERE (`Entry`=43197 AND `DifficultyID`=0); -- 43197 (Subdued Canyon Ettin) -
DELETE FROM `spell_script_names` WHERE `spell_id` IN (80704, 80702, 80739, 80707);
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(80704, 'spell_redridge_control_ettin'),
(80702, 'spell_redridge_control_ettin_2'),
(80739, 'spell_gen_reverse_cast_target_to_caster_triggered'),
(80707, 'spell_gen_despawn_target');
# exit location for thrown boulder
DELETE FROM `vehicle_seat_addon` WHERE `SeatEntry` = 8161;
INSERT INTO `vehicle_seat_addon` (`SeatEntry`, `SeatOrientation`, `ExitParamX`, `ExitParamY`, `ExitParamZ`, `ExitParamO`, `ExitParamValue`) VALUES
(8161, 0, -9310.855, -2366.367, 67.17842, 0, 2);
DELETE FROM `creature_text` WHERE `CreatureID` = 43197 AND `GroupID` IN (0, 1, 2, 3);
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(43197, 0, 0, 'ROCK NOT SO HEAVY! PUNY HUMIES!', 12, 0, 100, 0, 0, 0, 43218, 0, 'Subdued Canyon Ettin to Huge Boulder'),
(43197, 1, 0, 'Where trow? TROW ON BRIDGE??', 12, 0, 100, 0, 0, 0, 43220, 0, 'Subdued Canyon Ettin to Huge Boulder'),
(43197, 2, 0, 'OK! Me trow in water!', 12, 0, 100, 0, 0, 0, 43222, 0, 'Subdued Canyon Ettin to Huge Boulder'),
(43197, 3, 0, 'BYE, BYE, DADDY!', 14, 0, 100, 0, 0, 0, 43226, 0, 'Subdued Canyon Ettin to Huge Boulder');
DELETE FROM `creature_text` WHERE `CreatureID` = 648 AND `GroupID` = 1;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(648, 1, 0, 'NO, NO, NO! Please!', 12, 0, 100, 0, 0, 0, 43230, 0, 'Bridge Worker Trent - Scared'),
(648, 1, 1, 'NOOOOOO!!!', 12, 0, 100, 0, 0, 0, 43231, 0, 'Bridge Worker Trent - Scared'),
(648, 1, 2, 'ANYWHERE BUT THE BRIDGE!', 12, 0, 100, 0, 0, 0, 43232, 0, 'Bridge Worker Trent - Scared');
DELETE FROM `creature_text` WHERE `CreatureID` = 649 AND `GroupID` = 1;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(649, 1, 0, 'NO, NO, NO! Please!', 12, 0, 100, 0, 0, 0, 43230, 0, 'Bridge Worker Dmitri - Scared'),
(649, 1, 1, 'NOOOOOO!!!', 12, 0, 100, 0, 0, 0, 43231, 0, 'Bridge Worker Dmitri - Scared'),
(649, 1, 2, 'ANYWHERE BUT THE BRIDGE!', 12, 0, 100, 0, 0, 0, 43232, 0, 'Bridge Worker Dmitri - Scared');
DELETE FROM `creature_text` WHERE `CreatureID` = 650 AND `GroupID` = 1;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(650, 1, 0, 'NO, NO, NO! Please!', 12, 0, 100, 0, 0, 0, 43230, 0, 'Bridge Worker Jess - Scared'),
(650, 1, 1, 'NOOOOOO!!!', 12, 0, 100, 0, 0, 0, 43231, 0, 'Bridge Worker Jess - Scared'),
(650, 1, 2, 'ANYWHERE BUT THE BRIDGE!', 12, 0, 100, 0, 0, 0, 43232, 0, 'Bridge Worker Jess - Scared');
DELETE FROM `creature_text` WHERE `CreatureID` = 651 AND `GroupID` = 1;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(651, 1, 0, 'NO, NO, NO! Please!', 12, 0, 100, 0, 0, 0, 43230, 0, 'Bridge Worker Daniel - Scared'),
(651, 1, 1, 'NOOOOOO!!!', 12, 0, 100, 0, 0, 0, 43231, 0, 'Bridge Worker Daniel - Scared'),
(651, 1, 2, 'ANYWHERE BUT THE BRIDGE!', 12, 0, 100, 0, 0, 0, 43232, 0, 'Bridge Worker Daniel - Scared');
DELETE FROM `creature_text` WHERE `CreatureID` = 652 AND `GroupID` = 2;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(652, 2, 0, 'NO, NO, NO! Please!', 12, 0, 100, 0, 0, 0, 43230, 0, 'Bridge Worker Matthew - Scared'),
(652, 2, 1, 'NOOOOOO!!!', 12, 0, 100, 0, 0, 0, 43231, 0, 'Bridge Worker Matthew - Scared'),
(652, 2, 2, 'ANYWHERE BUT THE BRIDGE!', 12, 0, 100, 0, 0, 0, 43232, 0, 'Bridge Worker Matthew - Scared');
DELETE FROM `creature_text` WHERE `CreatureID` = 653 AND `GroupID` = 5;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(653, 5, 0, 'NO, NO, NO! Please!', 12, 0, 100, 0, 0, 0, 43230, 0, 'Bridge Worker Alex - Scared'),
(653, 5, 1, 'NOOOOOO!!!', 12, 0, 100, 0, 0, 0, 43231, 0, 'Bridge Worker Alex - Scared'),
(653, 5, 2, 'ANYWHERE BUT THE BRIDGE!', 12, 0, 100, 0, 0, 0, 43232, 0, 'Bridge Worker Alex - Scared');
-- Path 1 for Subdued Canyon Ettin
SET @ENTRY := 43197;
SET @PATHOFFSET := 0;
SET @PATH := @ENTRY * 100 + @PATHOFFSET;
DELETE FROM `waypoint_path` WHERE `PathId`= @PATH;
INSERT INTO `waypoint_path` (`PathId`, `MoveType`, `Flags`, `Velocity`, `Comment`) VALUES
(@PATH, 1, 0x0, NULL, 'Subdued Canyon Ettin - Scripted Path - Path To Water');
DELETE FROM `waypoint_path_node` WHERE `PathId`= @PATH;
INSERT INTO `waypoint_path_node` (`PathId`, `NodeId`, `PositionX`, `PositionY`, `PositionZ`, `Orientation`, `Delay`) VALUES
(@PATH, 0, -9270.707, -2299.5933, 69.642654, NULL, 0),
(@PATH, 1, -9271.457, -2309.5933, 69.892654, NULL, 0),
(@PATH, 2, -9279.707, -2319.0933, 66.892654, NULL, 0),
(@PATH, 3, -9303.957, -2330.5933, 61.642654, NULL, 0),
(@PATH, 4, -9324.86, -2338.94, 61.2445, 5.0614, 0);
-- Path 2 for Subdued Canyon Ettin
SET @ENTRY := 43197;
SET @PATHOFFSET := 1;
SET @PATH := @ENTRY * 100 + @PATHOFFSET;
DELETE FROM `waypoint_path` WHERE `PathId`= @PATH;
INSERT INTO `waypoint_path` (`PathId`, `MoveType`, `Flags`, `Velocity`, `Comment`) VALUES
(@PATH, 1, 0x0, NULL, 'Subdued Canyon Ettin - Scripted Path - Path Up Hill');
DELETE FROM `waypoint_path_node` WHERE `PathId`= @PATH;
INSERT INTO `waypoint_path_node` (`PathId`, `NodeId`, `PositionX`, `PositionY`, `PositionZ`, `Orientation`, `Delay`) VALUES
(@PATH, 0, -9308.439, -2330.975, 61.716003, NULL, 0),
(@PATH, 1, -9292.939, -2325.475, 62.716003, NULL, 0),
(@PATH, 2, -9276.939, -2316.725, 68.966, NULL, 0),
(@PATH, 3, -9260.689, -2312.725, 75.216, NULL, 0),
(@PATH, 4, -9237.689, -2313.225, 78.716, NULL, 0),
(@PATH, 5, -9214.52, -2334.01, 83.6875, NULL, 0);
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceEntry` IN (80739));
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `ConditionStringValue1`, `NegativeCondition`, `Comment`) VALUES
(13, 1, 80739, 0, 0, 51, 0, 5, 43196, 0, '', 0, 'Potential target of the spell is TYPEID_UNIT, entry is 43196');
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceEntry` IN (80704));
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `ConditionStringValue1`, `NegativeCondition`, `Comment`) VALUES
(13, 2, 80704, 0, 0, 51, 0, 5, 43197, 0, '', 0, 'Potential target of the spell is TYPEID_UNIT, entry is 43197'),
(13, 2, 80704, 0, 0, 33, 0, 1, 3, 0, '', 0, 'Potential target of the spell is TYPEID_UNIT, entry is 43197, if owned by spell caster'),
(13, 2, 80704, 0, 1, 51, 0, 5, 43094, 0, '', 0, 'Otherwise, potential target of the spell is TYPEID_UNIT, entry is 43094');

View File

@@ -22,17 +22,82 @@ SDComment:
Script Data End */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "Containers.h"
#include "G3DPosition.hpp"
#include "MotionMaster.h"
#include "MoveSplineInit.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "ScriptedCreature.h"
#include "SpellAuras.h"
#include "SpellInfo.h"
#include "SpellScript.h"
#include "TemporarySummon.h"
#include "WaypointDefines.h"
#include "World.h"
#include <algorithm>
enum DumpyKeeshan
enum RedridgeSpellData
{
NPC_BIGEARL = 43248,
SPELL_APPLY_QUEST_INVIS_ZONE_3 = 80815, // Used by npc's in Lakeshire Inn
SPELL_APPLY_QUEST_INVIS_ZONE_4 = 80816, // Used by npc's in Lakeshire Inn
SPELL_APPLY_QUEST_INVIS_ZONE_3 = 80815, // Used by npc's in Lakeshire Inn
SPELL_APPLY_QUEST_INVIS_ZONE_4 = 80816 // Used by npc's in Lakeshire Inn
SPELL_APPLY_QUEST_INVIS_ZONE_19 = 82099, // Used by npc's in Lakeshire Townhall
SPELL_CONTROL_ETTIN = 80704,
SPELL_CONTROL_ETTIN_2 = 80702,
SPELL_LIFT_HUGE_BOULDER = 80739,
SPELL_LIFT_BOULDER_RIDE = 82566,
SPELL_CANYON_ETTIN_SPAWN_SPELL = 82558,
SPELL_BOULDER_AURA = 82556,
SPELL_DESPAWN_KILL_CREDIT = 228623,
SPELL_EJECT_PASSENGER_1 = 80743,
SPELL_CANYON_ETTIN_DESPAWN = 82561,
SPELL_DESPAWN_ETTIN = 80707,
};
enum RedridgeCreatureData
{
NPC_FOREMAN_OSLOW = 341,
NPC_BRIDGE_WORKER_ALEX = 653,
NPC_BRIDGE_WORKER_TRENT = 648,
NPC_BRIDGE_WORKER_DMITRI = 649,
NPC_BRIDGE_WORKER_JESS = 650,
NPC_BRIDGE_WORKER_DANIEL = 651,
NPC_BRIDGE_WORKER_MATTHEW = 652,
NPC_CANYON_ETTIN = 43094,
NPC_SUBDUED_CANYON_ETTIN = 43197,
NPC_HUGE_BOULDER = 43196,
NPC_BIGEARL = 43248,
};
enum RedridgeTalks
{
TALK_OSLOW_IDLE = 0,
TALK_ALEX_HEAVE = 1,
TALK_ALEX_DAMN = 2,
TALK_ALEX_PUSH = 4,
TALK_ALEX_SCARED = 5,
TALK_WORKERS_HO = 0,
TALK_MATTHEW_IM_PUSHING = 1,
TALK_MATTHEW_SCARED = 2,
TALK_TRENT_SCARED = 1,
TALK_DMITRI_SCARED = 1,
TALK_JESS_SCARED = 1,
TALK_DANIEL_SCARED = 1,
TALK_NOT_SO_HEAVY = 0,
TALK_WHERE_THROW = 1,
TALK_THROW_IN_WATER = 2,
TALK_BYE = 3
};
/*######
@@ -112,148 +177,513 @@ public:
}
};
/*######
# npc_bridge_worker_alex "Used by entry 653" "Script not fully complete. Needs scripting added for move rock will be updated in future."
######*/
enum BridgeWorkerAlex
enum RedridgeHugeBoulder
{
EVENT_STORE_GUIDS = 1,
EVENT_OSLOW_SAY = 2,
EVENT_ALEX_SAY = 3,
EVENT_WORKERS_SAY = 4,
EVENT_ALEX_SAY_PUSH = 5,
EVENT_MATTHEW_SAY = 6,
EVENT_STORE_GUIDS = 1,
EVENT_OSLOW_IDLE_TALK = 2,
EVENT_ALEX_IDLE_TALK = 3,
EVENT_WORKERS_RESPONSE = 4,
EVENT_ALEX_SAY_PUSH = 5,
EVENT_MATTHEW_PUSH_RESPONSE = 6,
EVENT_REPOSITION = 7,
EVENT_BRIDGE_WORKERS_COWER = 8,
EVENT_OSLOW_GET_UP = 9,
EVENT_OSLOW_STUN = 10,
EVENT_ETTIN_LINE_1 = 11,
EVENT_ETTIN_LINE_2 = 12,
EVENT_MOVE_TO_WATER = 13,
EVENT_THROW_BOULDER = 14,
EVENT_PATH_AWAY = 15,
EVENT_DONE,
NPC_OSLOW = 341,
NPC_TRENT = 648,
NPC_DIMITRI = 649,
NPC_JESS = 650,
NPC_DANIEL = 651,
NPC_MATTHEW = 652,
ACTION_OSLOW_GET_UP = 0,
ACTION_COWER = 1,
ACTION_DONE,
SAY_OSLOW = 0,
SAY_ALEX_PUT = 0,
SAY_ALEX_HEAVE = 1,
SAY_ALEX_DAMN = 2,
SAY_ALEX_HANGON = 3,
SAY_ALEX_PUSH = 4,
SAY_WORKERS_HO = 0,
SAY_MATTHEW_IM_PUSHING = 1
PATH_ETTIN_TO_WATER = 4319700,
PATH_ETTIN_UP_HILL = 4319701,
POINT_NEAR_BOULDER = 1,
POINT_NEAR_WATER = 2,
POINT_UP_PATH = 3,
};
class npc_bridge_worker_alex : public CreatureScript
constexpr Position TrentRepositionPos = { -9281.44f, -2285.27f, 67.5123f, 6.0213f };
constexpr Position DmitriRepositionPos = { -9282.8f, -2293.28f, 67.5089f, 6.2657f };
constexpr Position JessRepositionPos = { -9282.27f, -2290.95f, 67.5319f, 6.0737f };
constexpr Position DanielRepositionPos = { -9281.77f, -2287.55f, 67.5869f, 6.0911f };
constexpr Position MatthewRepositionPos = { -9280.71f, -2283.21f, 67.5747f, 6.0737f };
constexpr Position AlexRepositionPos = { -9279.86f, -2281.42f, 67.5854f, 5.7421f };
// 43196 - Huge Boulder
struct npc_redridge_huge_boulder : public CreatureAI
{
public:
npc_bridge_worker_alex() : CreatureScript("npc_bridge_worker_alex") { }
npc_redridge_huge_boulder(Creature* creature) : CreatureAI(creature) { }
struct npc_bridge_worker_alexAI : public ScriptedAI
void Reset() override
{
npc_bridge_worker_alexAI(Creature* creature) : ScriptedAI(creature) { }
_events.Reset();
_oslowGUID.Clear();
_alexGUID.Clear();
_trentGUID.Clear();
_dmitriGUID.Clear();
_jessGUID.Clear();
_danielGUID.Clear();
_matthewGUID.Clear();
_events.ScheduleEvent(EVENT_STORE_GUIDS, 5s);
}
void Reset() override
void SpellHit(WorldObject* /*caster*/, SpellInfo const* spell) override
{
if (spell->Id != SPELL_LIFT_BOULDER_RIDE)
return;
_events.Reset();
_events.ScheduleEvent(EVENT_REPOSITION, 0ms);
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
_events.Reset();
_oslowGUID.Clear();
_trentGUID.Clear();
_dimitriGUID.Clear();
_jessGUID.Clear();
_danielGUID.Clear();
_matthewGUID.Clear();
_events.ScheduleEvent(EVENT_STORE_GUIDS, Seconds(5));
_events.ScheduleEvent(EVENT_OSLOW_SAY, Seconds(40), Seconds(50));
_events.ScheduleEvent(EVENT_ALEX_SAY, Seconds(22), Seconds(30));
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
if (!UpdateVictim())
switch (eventId)
{
while (uint32 eventId = _events.ExecuteEvent())
case EVENT_STORE_GUIDS:
{
switch (eventId)
if (Creature const* oslow = me->FindNearestCreature(NPC_FOREMAN_OSLOW, 10.0f, true))
_oslowGUID = oslow->GetGUID();
if (Creature const* alex = me->FindNearestCreature(NPC_BRIDGE_WORKER_ALEX, 10.0f, true))
_alexGUID = alex->GetGUID();
if (Creature const* trent = me->FindNearestCreature(NPC_BRIDGE_WORKER_TRENT, 10.0f, true))
_trentGUID = trent->GetGUID();
if (Creature const* dimitri = me->FindNearestCreature(NPC_BRIDGE_WORKER_DMITRI, 10.0f, true))
_dmitriGUID = dimitri->GetGUID();
if (Creature const* jess = me->FindNearestCreature(NPC_BRIDGE_WORKER_JESS, 10.0f, true))
_jessGUID = jess->GetGUID();
if (Creature const* daniel = me->FindNearestCreature(NPC_BRIDGE_WORKER_DANIEL, 10.0f, true))
_danielGUID = daniel->GetGUID();
if (Creature const* matthew = me->FindNearestCreature(NPC_BRIDGE_WORKER_MATTHEW, 10.0f, true))
_matthewGUID = matthew->GetGUID();
if (!_oslowGUID || !_alexGUID || !_trentGUID || !_dmitriGUID || !_jessGUID || !_danielGUID || !_matthewGUID)
_events.Repeat(1s);
else
{
case EVENT_STORE_GUIDS:
if (Creature* oslow = me->FindNearestCreature(NPC_OSLOW, 5.0f, true))
_oslowGUID = oslow->GetGUID();
if (Creature* trent = me->FindNearestCreature(NPC_TRENT, 5.0f, true))
_trentGUID = trent->GetGUID();
if (Creature* dimitri = me->FindNearestCreature(NPC_DIMITRI, 5.0f, true))
_dimitriGUID = dimitri->GetGUID();
if (Creature* jess = me->FindNearestCreature(NPC_JESS, 5.0f, true))
_jessGUID = jess->GetGUID();
if (Creature* daniel = me->FindNearestCreature(NPC_DANIEL, 5.0f, true))
_danielGUID = daniel->GetGUID();
if (Creature* matthew = me->FindNearestCreature(NPC_MATTHEW, 5.0f, true))
_matthewGUID = matthew->GetGUID();
break;
case EVENT_OSLOW_SAY:
if (Creature* oslow = ObjectAccessor::GetCreature(*me, _oslowGUID))
oslow->AI()->Talk(SAY_OSLOW);
_events.Repeat(Seconds(40), Seconds(50));
break;
case EVENT_ALEX_SAY:
switch (urand(0, 3))
{
case 0:
Talk(SAY_ALEX_PUT);
break;
case 1:
Talk(SAY_ALEX_HEAVE);
_events.ScheduleEvent(EVENT_WORKERS_SAY, Seconds(2));
break;
case 2:
Talk(SAY_ALEX_DAMN);
_events.ScheduleEvent(EVENT_ALEX_SAY_PUSH, Seconds(4));
break;
case 3:
Talk(SAY_ALEX_HANGON);
break;
}
_events.Repeat(Seconds(22), Seconds(30));
break;
case EVENT_WORKERS_SAY:
if (Creature* trent = ObjectAccessor::GetCreature(*me, _trentGUID))
trent->AI()->Talk(SAY_WORKERS_HO);
if (Creature* dimitri = ObjectAccessor::GetCreature(*me, _dimitriGUID))
dimitri->AI()->Talk(SAY_WORKERS_HO);
if (Creature* jess = ObjectAccessor::GetCreature(*me, _jessGUID))
jess->AI()->Talk(SAY_WORKERS_HO);
if (Creature* daniel = ObjectAccessor::GetCreature(*me, _danielGUID))
daniel->AI()->Talk(SAY_WORKERS_HO);
if (Creature* matthew = ObjectAccessor::GetCreature(*me, _matthewGUID))
matthew->AI()->Talk(SAY_WORKERS_HO);
break;
case EVENT_ALEX_SAY_PUSH:
Talk(SAY_ALEX_PUSH);
_events.ScheduleEvent(EVENT_MATTHEW_SAY, Seconds(4));
break;
case EVENT_MATTHEW_SAY:
if (Creature* matthew = ObjectAccessor::GetCreature(*me, _matthewGUID))
matthew->AI()->Talk(SAY_MATTHEW_IM_PUSHING);
break;
default:
break;
_events.ScheduleEvent(EVENT_OSLOW_IDLE_TALK, 45s, 60s);
_events.ScheduleEvent(EVENT_ALEX_IDLE_TALK, 20s, 30s);
}
break;
}
case EVENT_OSLOW_IDLE_TALK:
{
if (Creature const* oslow = ObjectAccessor::GetCreature(*me, _oslowGUID))
oslow->AI()->Talk(TALK_OSLOW_IDLE);
_events.Repeat(45s, 60s);
break;
}
case EVENT_ALEX_IDLE_TALK:
{
if (Creature const* alex = ObjectAccessor::GetCreature(*me, _alexGUID))
{
switch (uint32 text = urand(0, 3))
{
case TALK_ALEX_HEAVE:
alex->AI()->Talk(TALK_ALEX_HEAVE);
_events.ScheduleEvent(EVENT_WORKERS_RESPONSE, 1s);
break;
case TALK_ALEX_DAMN:
alex->AI()->Talk(TALK_ALEX_DAMN);
_events.ScheduleEvent(EVENT_ALEX_SAY_PUSH, 3s);
break;
default:
alex->AI()->Talk(text);
_events.Repeat(10s);
break;
}
}
break;
}
case EVENT_WORKERS_RESPONSE:
{
if (Creature const* alex = ObjectAccessor::GetCreature(*me, _alexGUID))
{
if (Creature const* trent = ObjectAccessor::GetCreature(*me, _trentGUID))
trent->AI()->Talk(TALK_WORKERS_HO, alex);
if (Creature const* dmitri = ObjectAccessor::GetCreature(*me, _dmitriGUID))
dmitri->AI()->Talk(TALK_WORKERS_HO, alex);
if (Creature const* jess = ObjectAccessor::GetCreature(*me, _jessGUID))
jess->AI()->Talk(TALK_WORKERS_HO, alex);
if (Creature const* daniel = ObjectAccessor::GetCreature(*me, _danielGUID))
daniel->AI()->Talk(TALK_WORKERS_HO, alex);
if (Creature const* matthew = ObjectAccessor::GetCreature(*me, _matthewGUID))
matthew->AI()->Talk(TALK_WORKERS_HO, alex);
}
_events.ScheduleEvent(EVENT_ALEX_IDLE_TALK, 20s, 30s);
break;
}
case EVENT_ALEX_SAY_PUSH:
{
if (Creature const* alex = ObjectAccessor::GetCreature(*me, _alexGUID))
alex->AI()->Talk(TALK_ALEX_PUSH);
_events.ScheduleEvent(EVENT_MATTHEW_PUSH_RESPONSE, 4s);
break;
}
case EVENT_MATTHEW_PUSH_RESPONSE:
{
if (Creature const* matthew = ObjectAccessor::GetCreature(*me, _matthewGUID))
{
if (Creature const* alex = ObjectAccessor::GetCreature(*me, _alexGUID))
matthew->AI()->Talk(TALK_MATTHEW_IM_PUSHING, alex);
}
_events.ScheduleEvent(EVENT_ALEX_IDLE_TALK, 20s, 30s);
break;
}
case EVENT_REPOSITION:
{
if (Creature* trent = ObjectAccessor::GetCreature(*me, _trentGUID))
{
trent->SetAIAnimKitId(0);
trent->GetMotionMaster()->MovePoint(0, TrentRepositionPos, true, TrentRepositionPos.GetOrientation());
}
if (Creature* dmitri = ObjectAccessor::GetCreature(*me, _dmitriGUID))
{
dmitri->SetAIAnimKitId(0);
dmitri->GetMotionMaster()->MovePoint(0, DmitriRepositionPos, true, DmitriRepositionPos.GetOrientation());
}
if (Creature* jess = ObjectAccessor::GetCreature(*me, _jessGUID))
{
jess->SetAIAnimKitId(0);
jess->GetMotionMaster()->MovePoint(0, JessRepositionPos, true, JessRepositionPos.GetOrientation());
}
if (Creature* daniel = ObjectAccessor::GetCreature(*me, _danielGUID))
{
daniel->SetAIAnimKitId(0);
daniel->GetMotionMaster()->MovePoint(0, DanielRepositionPos, true, DanielRepositionPos.GetOrientation());
}
if (Creature* matthew = ObjectAccessor::GetCreature(*me, _matthewGUID))
{
matthew->SetAIAnimKitId(0);
matthew->GetMotionMaster()->MovePoint(0, MatthewRepositionPos, true, MatthewRepositionPos.GetOrientation());
}
if (Creature* alex = ObjectAccessor::GetCreature(*me, _alexGUID))
{
alex->SetAIAnimKitId(0);
alex->GetMotionMaster()->MovePoint(0, AlexRepositionPos, true, AlexRepositionPos.GetOrientation());
}
break;
}
case EVENT_BRIDGE_WORKERS_COWER:
{
// all workers should cower
std::vector<ObjectGuid> allWorkers = { _alexGUID, _matthewGUID, _trentGUID, _dmitriGUID, _jessGUID, _danielGUID };
for (ObjectGuid const& workerGUID : allWorkers)
if (Creature* worker = ObjectAccessor::GetCreature(*me, workerGUID))
worker->SetEmoteState(EMOTE_STATE_COWER);
// pick two random workers to say random scared things
Trinity::Containers::RandomResize(allWorkers, 2);
for (ObjectGuid const workerGUID : allWorkers)
{
Creature* worker = ObjectAccessor::GetCreature(*me, workerGUID);
if (!worker)
continue;
switch (worker->GetEntry())
{
case NPC_BRIDGE_WORKER_ALEX:
worker->AI()->Talk(TALK_ALEX_SCARED, me);
break;
case NPC_BRIDGE_WORKER_MATTHEW:
worker->AI()->Talk(TALK_MATTHEW_SCARED, me);
break;
case NPC_BRIDGE_WORKER_TRENT:
worker->AI()->Talk(TALK_TRENT_SCARED, me);
break;
case NPC_BRIDGE_WORKER_DMITRI:
worker->AI()->Talk(TALK_DMITRI_SCARED, me);
break;
case NPC_BRIDGE_WORKER_JESS:
worker->AI()->Talk(TALK_JESS_SCARED, me);
break;
case NPC_BRIDGE_WORKER_DANIEL:
worker->AI()->Talk(TALK_DANIEL_SCARED, me);
break;
default:
break;
}
}
break;
}
case EVENT_OSLOW_GET_UP:
{
if (Creature* oslow = ObjectAccessor::GetCreature(*me, _oslowGUID))
oslow->SetStandState(UNIT_STAND_STATE_STAND);
_events.ScheduleEvent(EVENT_OSLOW_STUN, 2s);
break;
}
case EVENT_OSLOW_STUN:
{
if (Creature* oslow = ObjectAccessor::GetCreature(*me, _oslowGUID))
oslow->SetEmoteState(EMOTE_STATE_STUN);
break;
}
case EVENT_DONE:
{
if (Creature* alex = ObjectAccessor::GetCreature(*me, _alexGUID))
alex->DespawnOrUnsummon();
if (Creature* matthew = ObjectAccessor::GetCreature(*me, _matthewGUID))
matthew->DespawnOrUnsummon();
if (Creature* trent = ObjectAccessor::GetCreature(*me, _trentGUID))
trent->DespawnOrUnsummon();
if (Creature* dmitri = ObjectAccessor::GetCreature(*me, _dmitriGUID))
dmitri->DespawnOrUnsummon();
if (Creature* jess = ObjectAccessor::GetCreature(*me, _jessGUID))
jess->DespawnOrUnsummon();
if (Creature* daniel = ObjectAccessor::GetCreature(*me, _danielGUID))
daniel->DespawnOrUnsummon();
if (Creature* oslow = ObjectAccessor::GetCreature(*me, _oslowGUID))
oslow->DespawnOrUnsummon();
_events.Reset();
me->DespawnOrUnsummon();
break;
}
default:
break;
}
}
}
private:
EventMap _events;
ObjectGuid _oslowGUID;
ObjectGuid _trentGUID;
ObjectGuid _dimitriGUID;
ObjectGuid _jessGUID;
ObjectGuid _danielGUID;
ObjectGuid _matthewGUID;
};
CreatureAI* GetAI(Creature* creature) const override
void DoAction(int32 const param) override
{
return new npc_bridge_worker_alexAI(creature);
switch (param)
{
case ACTION_OSLOW_GET_UP:
_events.ScheduleEvent(EVENT_OSLOW_GET_UP, 500ms);
// in case player who started event disconnects
_events.ScheduleEvent(EVENT_DONE, 120s);
break;
case ACTION_COWER:
_events.ScheduleEvent(EVENT_BRIDGE_WORKERS_COWER, 3s);
break;
case ACTION_DONE:
_events.ScheduleEvent(EVENT_DONE, 0s);
break;
default:
break;
}
}
private:
EventMap _events;
ObjectGuid _oslowGUID;
ObjectGuid _alexGUID;
ObjectGuid _trentGUID;
ObjectGuid _dmitriGUID;
ObjectGuid _jessGUID;
ObjectGuid _danielGUID;
ObjectGuid _matthewGUID;
};
constexpr Position EttinNearBoulderPosition = { -9272.053f, -2291.7463f, 68.54081f };
// 43197 - Subdued Canyon Ettin
struct npc_redridge_subdued_canyon_ettin : public CreatureAI
{
npc_redridge_subdued_canyon_ettin(Creature* creature) : CreatureAI(creature) { }
void Reset() override
{
me->SetReactState(REACT_PASSIVE);
_events.Reset();
}
void OnDespawn() override
{
Unit* owner = me->GetOwner();
if (!owner)
return;
owner->RemoveAurasDueToSpell(SPELL_CANYON_ETTIN_SPAWN_SPELL);
}
void SpellHit(WorldObject* caster, SpellInfo const* spell) override
{
if (!caster || !caster->IsPlayer())
return;
switch (spell->Id)
{
case SPELL_BOULDER_AURA:
me->GetMotionMaster()->MovePoint(POINT_NEAR_BOULDER, EttinNearBoulderPosition, true, {}, {}, MovementWalkRunSpeedSelectionMode::ForceWalk);
break;
case SPELL_DESPAWN_KILL_CREDIT:
if (Player* player = ObjectAccessor::GetPlayer(*me, caster->GetGUID()))
player->RewardPlayerAndGroupAtEvent(NPC_FOREMAN_OSLOW, player);
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_ETTIN_LINE_1:
Talk(TALK_NOT_SO_HEAVY);
_events.ScheduleEvent(EVENT_ETTIN_LINE_2, 3s);
break;
case EVENT_ETTIN_LINE_2:
Talk(TALK_WHERE_THROW);
if (Creature* boulder = ObjectAccessor::GetCreature(*me, _boulderGUID))
boulder->AI()->DoAction(ACTION_COWER);
_events.ScheduleEvent(EVENT_MOVE_TO_WATER, 9s);
break;
case EVENT_MOVE_TO_WATER:
me->GetMotionMaster()->MovePath(PATH_ETTIN_TO_WATER, false);
Talk(TALK_THROW_IN_WATER);
break;
case EVENT_THROW_BOULDER:
me->CastSpell(nullptr, SPELL_EJECT_PASSENGER_1);
_events.ScheduleEvent(EVENT_PATH_AWAY, 6s);
break;
case EVENT_PATH_AWAY:
Talk(TALK_BYE);
if (Creature* boulder = ObjectAccessor::GetCreature(*me, _boulderGUID))
boulder->AI()->DoAction(ACTION_DONE);
me->GetMotionMaster()->MovePath(PATH_ETTIN_UP_HILL, false);
break;
default:
break;
}
}
}
void MovementInform(uint32 movementType, uint32 pointId) override
{
if (movementType != POINT_MOTION_TYPE)
return;
if (pointId == POINT_NEAR_BOULDER)
{
if (Creature const* boulder = me->FindNearestCreature(NPC_HUGE_BOULDER, 5.0f, true))
{
_boulderGUID = boulder->GetGUID();
me->CastSpell(nullptr, SPELL_LIFT_HUGE_BOULDER, false);
if (Creature const* daniel = me->FindNearestCreature(NPC_BRIDGE_WORKER_DANIEL, 20.0f, true))
me->SetFacingToObject(daniel);
_events.ScheduleEvent(EVENT_ETTIN_LINE_1, 2500ms);
boulder->AI()->DoAction(ACTION_OSLOW_GET_UP);
}
}
}
void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override
{
if (pathId == PATH_ETTIN_TO_WATER)
{
_events.ScheduleEvent(EVENT_THROW_BOULDER, 0s);
}
else if (pathId == PATH_ETTIN_UP_HILL)
{
me->CastSpell(nullptr, SPELL_CANYON_ETTIN_DESPAWN);
me->CastSpell(nullptr, SPELL_DESPAWN_ETTIN);
}
}
private:
EventMap _events;
ObjectGuid _boulderGUID;
};
// 80704 - Control Ettin
class spell_redridge_control_ettin : public SpellScript
{
SpellCastResult CheckCast()
{
// check for a spawn spell with a valid caster (subdued ettin)
Aura const* spawnAura = GetCaster()->GetAura(SPELL_CANYON_ETTIN_SPAWN_SPELL, [](Aura const* aura)
{
return aura->GetCaster() != nullptr;
});
if (spawnAura != nullptr)
{
// fail if the subdued ettin is no longer alive
if (!spawnAura->GetCaster()->IsAlive())
return SPELL_FAILED_BAD_IMPLICIT_TARGETS;
}
else
{
// no spawn spell, so require nearby canyon ettin
if (!GetCaster()->FindNearestCreature(NPC_CANYON_ETTIN, GetSpellInfo()->GetMaxRange(), true))
return SPELL_FAILED_OUT_OF_RANGE;
}
return SPELL_CAST_OK;
}
void HandleScriptEffect(SpellEffIndex /*effIndex*/) const
{
if (Unit const* target = GetHitUnit())
{
// conditions ensure this ettin is owned by player
if (target->GetEntry() == NPC_SUBDUED_CANYON_ETTIN)
{
GetCaster()->CastSpell(nullptr, SPELL_BOULDER_AURA, false);
GetCaster()->CastSpell(nullptr, SPELL_DESPAWN_KILL_CREDIT, false);
}
else
GetCaster()->CastSpell(nullptr, SPELL_CONTROL_ETTIN_2, false);
}
}
void Register() override
{
OnCheckCast += SpellCheckCastFn(spell_redridge_control_ettin::CheckCast);
OnEffectHitTarget += SpellEffectFn(spell_redridge_control_ettin::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_DUMMY);
}
};
// 80702 - Control Ettin
class spell_redridge_control_ettin_2 : public SpellScript
{
void HandleScriptEffect(SpellEffIndex /*effIndex*/) const
{
if (Creature* target = GetHitCreature())
target->DespawnOrUnsummon();
// subdued ettin minion casts 82558 to player
std::list<TempSummon*> minionList;
GetCaster()->GetAllMinionsByEntry(minionList, NPC_SUBDUED_CANYON_ETTIN);
if (TempSummon* ettin = minionList.front())
ettin->CastSpell(GetCaster(), SPELL_CANYON_ETTIN_SPAWN_SPELL, false);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_redridge_control_ettin_2::HandleScriptEffect, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
@@ -270,8 +700,6 @@ enum RedridgeCitizen
SAY_IN_TOWNHALL = 0, // Used by npc's in Lakeshire Townhall
SAY_LEAVE_TOWNHALL = 1, // Used by npc's in Lakeshire Townhall
SPELL_APPLY_QUEST_INVIS_ZONE_19 = 82099 // Used by npc's in Lakeshire Townhall
};
const Emote EmoteID[6] =
@@ -370,6 +798,9 @@ void AddSC_redridge_mountains()
{
new npc_big_earl();
new npc_dumpy_and_keeshan();
new npc_bridge_worker_alex();
RegisterCreatureAI(npc_redridge_huge_boulder);
RegisterCreatureAI(npc_redridge_subdued_canyon_ettin);
RegisterSpellScript(spell_redridge_control_ettin);
RegisterSpellScript(spell_redridge_control_ettin_2);
new npc_redridge_citizen();
}