Author SHA1 Message Date
Jman a63829a130 Exiles Reach: bind boar ride scene 2338 to its SceneScript (works without core change)
Move the Giant Boar ride scene triggers ('Trampling Time', 'Big Kill Credit', 'Knockback') from exiles_reach_general_playerscript::OnSceneTriggerEvent into a new scene_exiles_reach_boar_ride SceneScript, bound via scene_template.ScriptName (SQL included). Core dispatches these events to the bound SceneScript on every branch, so the boar trample spell works without the ScriptMgr.cpp PlayerScript fan-out change. 'Teleport' triggers stay in the PlayerScript hook.
2026-09-17 08:06:54 +10:00
devbox a17899e921 Exiles Reach: remove duplicate Garrick script-summon (DB spawn 730202 now provides him) 2026-08-26 13:43:21 +10:00
devbox 55da003626 DB/Exiles Reach: fix Garrick camp spawn z-height (91.001 to match ground) 2026-08-26 11:56:57 +10:00
devbox 9fe909427c DB/Exiles Reach: make quest flow SQL idempotent (delete-before-insert) 2026-08-26 11:32:53 +10:00
devbox 651845916f DB/Exiles Reach: add DB spawn for post-Torgak Captain Garrick (245394) at the camp so he's reliably visible as quest-giver 2026-08-26 11:17:02 +10:00
devbox cebef91f24 DB/Exiles Reach: remove reverted Hrun display change (keep original 92803) 2026-08-26 09:48:15 +10:00
devbox 1de4ff7967 DB/Exiles Reach: use correct post-Torgak reunion scene package (4778 Alliance / 4779 Horde) 2026-08-26 09:38:36 +10:00
devbox ca9d636424 DB/Exiles Reach: add gossip flag to ritual Meredy/Herbert so the Bloodbeak event can start 2026-08-26 09:00:47 +10:00
devbox 944bc6e8b2 Exiles Reach: give KilledMonsterCredit for Bloodbeak to complete the save-Meredy objective 2026-08-26 08:57:42 +10:00
devbox 76d463d664 DB/Exiles Reach: add questgiver flag to post-Torgak custom NPCs (245397/245667/245686) 2026-08-26 08:45:35 +10:00
devbox fb1f200652 DB/Exiles Reach: align all Dark Ritual storyline quest starters/enders with retail (68 quests, both factions) 2026-08-26 08:30:06 +10:00
devbox 975591fa5b DB/Exiles Reach: 58915 ends at Private Cole, not Hjalmar (revert incorrect ender) 2026-08-25 19:34:51 +10:00
devbox 1633cd2093 DB/Exiles Reach: correct post-Torgak quest flow (Garrick turns in 55639/85678, Hjalmar turns in 58915, remove Wrathion 55196 starter) 2026-08-25 19:30:46 +10:00
devbox 014c9cc2d0 Exiles Reach: remove GARRICK_15017 debug log 2026-08-25 19:22:02 +10:00
devbox 8ac8a3527b DB/Exiles Reach: add Hrun actor to Hrun's Barrow conversations 12120/14540 (fix missing actor) 2026-08-25 16:14:16 +10:00
devbox 36108f76f7 Exiles Reach: remove [ExilesReach] phase check debug log from ogre ruins 2026-08-25 15:50:40 +10:00
devbox b9b49adf03 DB/Exiles Reach: fix Hrun the Exiled invisible - use working Darkmaul Ogre display 2026-08-25 15:36:12 +10:00
devbox 3ce7f17005 DB: make reunion conversation SQL idempotent (clear rows before insert) 2026-08-24 22:20:36 +10:00
devbox 89aae3dfa9 Exiles Reach: play the post-ride reunion conversation (Wrathion + Jaina) and fix conversation line chaining 2026-08-24 22:01:12 +10:00
devbox 01824cf222 Exiles Reach: Captain Garrick gives Stocking Up after the ride; move her off the campfire 2026-08-24 20:35:38 +10:00
devbox 8b8aaffd70 Exiles Reach: Jaina + Garrick are separate camp NPCs after the ride
Jaina (156807) stays by Austin Huxworth at the rock edging (quest-giver);
add Captain Garrick (245394) as a separate NPC by the campfire. Both are
summoned on the ride reward.
2026-08-24 18:02:07 +10:00
devbox a0203a632e Exiles Reach: post-Torgak quest-giver is Jaina at the camp; Richter gets repair
- Revert the quest-giver from Captain Garrick (245394) back to Jaina
  (156807); she belongs at the camp next to the campfire by Quartermaster
  Richter, not in front of Wrathion. The scripted summon now places Jaina
  there on the ride reward.
- Quartermaster Richter (156800) was missing UNIT_NPC_FLAG_REPAIR (0x1000),
  so Repair Yourself (85678) couldn't be completed. Add the flag.
2026-08-24 17:57:56 +10:00
devbox 988874e403 Exiles Reach: script Captain Garrick's summon after the ride + questgiver flag
The phase-15017 regular spawn wasn't reliably showing Garrick (245394) for
the player. Summon him on the ride quest reward in front of Wrathion with
the QUESTGIVER npcflag set, so Stocking Up (55194) / Repair Yourself (85678)
are offered. Also set npcflag=2 on 245394 in the DB (it had 0, so it never
presented as a quest giver).
2026-08-24 17:25:40 +10:00
devbox a4b6ec1100 Scene debug: log scene plays on Exiles Reach (map 2175)
Logs which scene (id + package) plays for the ride/cinematic, so the
post-ride scene can be matched against the expected one.
2026-08-24 17:09:02 +10:00
devbox ad87475cd5 Exiles Reach: diagnostic logs for post-ride phase check / Garrick 15017
Log the player's area and quest state each phase-check tick, and the
GARRICK_15017 phase evaluation, to see why Captain Garrick (245394) doesn't
appear after the boar ride is rewarded.
2026-08-24 17:03:35 +10:00
devbox 60546b974f Exiles Reach: show Captain Garrick (245394) after Torgak to grant the next quests
- The post-Torgak quest-giver was 156807, which wrongly reused Jaina's model
  (88316), so it read as a duplicate Jaina. Point the phase-15017 spawn and
  the Stocking Up (55194) / Repair Yourself (85678) quest starters+enders at
  245394 (Captain Garrick, model 109008).
- GARRICK_BEFORE_DARKMAUL_CITADEL phase was only shown after MESSAGE_TO_BASE +
  WESTWARD_BOUND were rewarded, so Garrick never appeared right after the ride.
  Show it once the boar ride is rewarded, until the player heads to the citadel.
2026-08-24 16:37:24 +10:00
devbox cfe74126f5 Exiles Reach: diagnostic logs for abandon respawn
Log when the ride abandon is detected, how many undead are tracked, and the
spawnIds being forced to respawn — to pinpoint why the mobs don't come back.
2026-08-24 15:10:25 +10:00
devbox 2317f0fe7d Exiles Reach: fix ride-giver Jaina on Darkmaul Plains + respawn on abandon
- The ride-giver the player actually talks to is on the Darkmaul Plains
  (phase 13779), and its phase was removed when the ride was accepted
  (!QuestAccepted) — so Jaina vanished on accept. Show it until the ride is
  rewarded (matches the ogre-ruins GARRICK_CAMP fix).
- OnQuestStatusChange does NOT fire on quest abandon (RemoveActiveQuest
  erases the entry without the hook), so the respawn-on-abandon never ran.
  Detect the active->gone transition in OnPlayerWorldObjectUpdate and force
  the mowed-down undead to respawn (Map::Respawn), while keeping them dead
  on completion.
2026-08-24 14:27:33 +10:00
devbox c354643e47 DB/World: bind Giant Boar Trample script (305557)
Adds the spell_script_names row for spell_giant_boar_trample_305557 so a
fresh DB also has the trample's despawn behavior for the boar ride.
2026-08-24 14:01:58 +10:00
devbox 71e005e10f Exiles Reach: keep Horde ride-giver Shuja visible while the quest is active
Same fix as the Alliance GARRICK_CAMP phase: Shuja's phase was only shown
after QUEST_H_THE_REDEATHER completed, so she vanished when the ride began.
Show it while accepted or completed.
2026-08-24 13:50:29 +10:00
devbox f72d0be912 Exiles Reach: no follower on the boar ride; keep quest-giver Jaina visible
- Remove the 156807 follower summon on ride accept (it reuses Jaina's
  model 88316, so it read as a duplicate Jaina following you). Ride alone.
- GARRICK_CAMP phase was only shown after the ride was rewarded, so Jaina
  phased out the moment she gave the quest. Show it while the ride is
  accepted too.
2026-08-24 13:48:10 +10:00
devbox 0e9b9f7db8 Exiles Reach: despawn the undead by faction, not phase
The mobs' phase desync made IsValidAttackTarget fail, so the despawn loop
skipped them (they stayed alive and killed the rider when the ride ended).
Use IsHostileTo (faction-based, no phase check) in both the trample and the
Big Kill Credit despawning.
2026-08-24 13:30:24 +10:00
devbox 7670e0eb91 Exiles Reach: respawn the mowed-down undead if the ride quest is abandoned
Track the undead spawnIds despawned by the boar (1h respawn delay). On
quest abandon, force their respawn (Map::Respawn sets the pending respawn
time to now) so the ride can be retried; clear tracking on completion.
2026-08-24 13:18:22 +10:00
devbox 48f5b7e124 Exiles Reach: undead stay dead after the trample/credit (1h respawn delay)
The ogre-ruins undead are regular spawns, so DespawnOrUnsummon removed them
briefly then the spawn timer respawned them. Force a 1h respawn delay on
both the trample and the Big Kill Credit despawning so the mowed-down mobs
don't pop back during the ride.
2026-08-24 13:11:00 +10:00
devbox c797c0c576 Exiles Reach: despawn the trampled undead on Big Kill Credit + fix rider immunity
The trample's own grid search didn't reliably despawn the undead (they stayed
alive and attacked the rider). Tie the despawn to the 'Big Kill Credit' scene
event (which reliably fires as the ride progresses): despawn all hostile mobs
within 50y (excluding Torgok). Also apply the rider's UNIT_FLAG_IMMUNE_TO_NPC
on EFFECT_0 (CONTROL_VEHICLE) as well as EFFECT_1 so the mobs can't damage the
player.
2026-08-24 12:16:43 +10:00
devbox 3cfb6d2c99 Exiles Reach: trample despawns the undead outright
Kill+DespawnOrUnsummon left the corpses visible (regular spawns). Just
DespawnOrUnsummon the targets — the scene's 'Big Kill Credit' grants the
quest credit, so the mobs simply vanish when trampled.
2026-08-24 11:52:28 +10:00
devbox 1b15337809 Exiles Reach: trample mows the undead down (kill + despawn)
Build (Windows x64) / build (push) Canceled after 0s
Build (Windows x64) / linux-build (push) Canceled after 0s
The trample only dealt 120 damage, leaving healthier zombies/ogres alive
and visible. Kill and despawn each hostile target so the trampled army
actually disappears.
2026-08-23 22:27:40 +10:00
devbox 07e78803e2 Exiles Reach: rider immune to NPC damage while on the giant boar
Build (Windows x64) / build (push) Canceled after 0s
Build (Windows x64) / linux-build (push) Canceled after 0s
Some undead still hit the player during the boar ride (mobs that aggro on
sight, not via the trample). Set UNIT_FLAG_IMMUNE_TO_NPC on the player for
the ride's duration so mob attacks can't reach the rider (IsValidAttackTarget
checks target->IsImmuneToNPC); the boar takes the hits and the trample kills
the cadavers.
2026-08-23 22:18:44 +10:00
devbox 23dc67639f Exiles Reach: trample damage from the boar, not the rider
Build (Windows x64) / build (push) Canceled after 0s
Build (Windows x64) / linux-build (push) Canceled after 0s
The trample script dealt damage from the player (GetCaster), so the undead
aggro'd the rider and chewed through the player's health during the boar
ride. Attribute the trample damage to the boar vehicle (GetVehicleBase) so
the mobs attack the boar instead.
2026-08-23 22:09:06 +10:00
devbox 371e06dab9 Core: dispatch scene events to PlayerScripts too
Build (Windows x64) / build (push) Canceled after 0s
Build (Windows x64) / linux-build (push) Canceled after 0s
ScriptMgr::OnSceneTrigger/Cancel/Complete only called the bound SceneScript
(via scene_template.ScriptName). The Thordekk Exiles Reach ride (and other
scene-driven content) registers its handlers as PlayerScript hooks
(OnSceneTriggerEvent/OnSceneComplete/OnSceneCancel), so 'Trampling Time' and
'Big Kill Credit' never fired -> the Giant Boar trample never cast and the
cadaver kill credit never granted. Add the FOREACH_SCRIPT(PlayerScript)
dispatch to all three.
2026-08-23 18:53:22 +10:00
devbox c7a4bf966e Exiles Reach: revert ship sparring leash + fix trample script compile
Build (Windows x64) / build (push) Canceled after 0s
Build (Windows x64) / linux-build (push) Canceled after 0s
- Revert the Cole/Throg sparring distance-leash (exiles_reach_north_sea.cpp):
  it fought the clone's position/LOS desync on the ship (map 2261), making
  the clone run away and clip; back to the original combat chase while we
  investigate the position/LOS root cause.
- Fix spell_giant_boar_trample_305557 compile: CalcRadius returns SpellRange
  (use .Max) and DealDamage is static (Unit::DealDamage, uint32 damage).
2026-08-23 18:41:45 +10:00
devbox ffaac9ece6 Exiles Reach: implement Giant Boar Trample (305557)
Build (Windows x64) / build (push) Canceled after 0s
Build (Windows x64) / linux-build (push) Canceled after 0s
The trample's Effect 1 is a SPELL_EFFECT_DUMMY (radius 13, targets the
caster) that was never scripted, so it did nothing to the Monstrous
Cadavers (157091) during Ride of the Scientifically Enhanced Boar. Add a
spell script that damages all hostile creatures within the effect radius
(caster->DealDamage, effect value). Registered + spell_script_names row.
2026-08-23 18:36:53 +10:00
devbox b47740c125 Exiles Reach (ship): replace boundary-evade with a distance leash for the sparring clone
Build (Windows x64) / build (push) Canceled after 0s
Build (Windows x64) / linux-build (push) Canceled after 0s
The SetBoundary approach made the sparring partner evade back to home with a
straight spline, clipping through the boat hull. Use a distance leash in
UpdateAI instead: stop chasing past 15y and walk back on the ship geometry.
2026-08-23 17:40:55 +10:00
devbox 5072ad8f6f Exiles Reach: keep Monstrous Cadavers in-phase during the boar ride
Build (Windows x64) / build (push) Canceled after 0s
Build (Windows x64) / linux-build (push) Canceled after 0s
The Alliance ride (Ride of the Scientifically Enhanced Boar, 55879) hides
phase 13783 (PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS) while the
player rides (HasAura(SPELL_RIDING_GIANT_BOAR) or quest accepted), so the
Monstrous Cadavers (157091, phase 13783) are server-side out of phase:
visible to the client but not valid attack targets -> the boar trample
deals 0 damage and the ride can't progress to Torgok. Keep the phase
active while the ride is incomplete (hidden only after it's rewarded).
Applied to the identical condition in ogre_ruins, darkmaul_plains and
hruns_barrow.
2026-08-23 17:36:56 +10:00
23 changed files with 419 additions and 40 deletions
@@ -0,0 +1,2 @@
-- Exiles Reach: bind the Giant Boar Trample script (mows the undead down)
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (305557, 'spell_giant_boar_trample_305557');
@@ -0,0 +1,6 @@
-- Exiles Reach: post-Torgak quest-giver is Captain Garrick (245394), not 156807
-- (which wrongly reused Jaina's model 88316). Point the spawn and the
-- Stocking Up / Repair Yourself quest starters+enders at 245394.
UPDATE `creature` SET `id`=245394 WHERE `guid`=42560 AND `id`=156807;
UPDATE `creature_queststarter` SET `id`=245394 WHERE `id`=156807 AND `quest` IN (55194, 85678);
UPDATE `creature_questender` SET `id`=245394 WHERE `id`=156807 AND `quest` IN (55194, 85678);
@@ -0,0 +1,2 @@
-- Exiles Reach: Captain Garrick (245394) must be a quest-giver (npcflag bit 0x2)
UPDATE `creature_template` SET `npcflag` = `npcflag` | 2 WHERE `entry` = 245394;
@@ -0,0 +1,8 @@
-- Exiles Reach post-Torgak: revert the quest-giver to Jaina (156807) and give
-- Quartermaster Richter the repair flag.
-- (Corrects 2026_08_24_01/02 which wrongly swapped in Captain Garrick 245394.)
UPDATE `creature` SET `id`=156807 WHERE `guid`=42560 AND `id`=245394;
UPDATE `creature_queststarter` SET `id`=156807 WHERE `id`=245394 AND `quest` IN (55194, 85678);
UPDATE `creature_questender` SET `id`=156807 WHERE `id`=245394 AND `quest` IN (55194, 85678);
UPDATE `creature_template` SET `npcflag`=0 WHERE `entry`=245394;
UPDATE `creature_template` SET `npcflag` = `npcflag` | 4096 WHERE `entry` = 156800;
@@ -0,0 +1,11 @@
-- Exiles Reach: after the ride, Captain Garrick (245394) is the quest-giver for
-- Stocking Up on Supplies (55194); Repair Yourself (85678) is no longer offered.
UPDATE `creature_template` SET `npcflag` = `npcflag` | 2 WHERE `entry` = 245394;
DELETE FROM `creature_queststarter` WHERE `id` = 156807 AND `quest` IN (55194, 85678);
DELETE FROM `creature_questender` WHERE `id` = 156807 AND `quest` IN (55194, 85678);
INSERT INTO `creature_queststarter` (`id`, `quest`, `VerifiedBuild`) VALUES
(245394, 55194, 0);
INSERT INTO `creature_questender` (`id`, `quest`, `VerifiedBuild`) VALUES
(245394, 55194, 0);
@@ -0,0 +1,29 @@
-- Exiles Reach: post-ride reunion dialogue (Wrathion + Jaina) as a server-driven conversation.
-- The scene (2341) references conversation lines 88006-88013; the Wrathion broadcasts
-- (302254-302258) already exist, Jaina's (302259-302261) were empty placeholders.
-- NOTE: the broadcast_text updates for 302259-302261 live in the hotfixes DB.
DELETE FROM `conversation_actors` WHERE `ConversationId` = 51000;
DELETE FROM `conversation_line_template` WHERE `Id` BETWEEN 88006 AND 88013;
DELETE FROM `conversation_template` WHERE `Id` = 51000;
INSERT INTO `conversation_template` (`Id`, `FirstLineId`, `TextureKitId`, `Flags`, `ScriptName`, `VerifiedBuild`) VALUES
(51000, 88006, 0, 0, '', 0);
INSERT INTO `conversation_line_template` (`Id`, `UiCameraID`, `ActorIdx`, `Flags`, `ChatType`, `VerifiedBuild`, `Unk`) VALUES
(88006, 0, 0, 0, 0, 0, 0),
(88007, 0, 0, 0, 0, 0, 0),
(88008, 0, 0, 0, 0, 0, 0),
(88009, 0, 0, 0, 0, 0, 0),
(88010, 0, 0, 0, 0, 0, 0),
(88011, 0, 1, 0, 0, 0, 0),
(88012, 0, 1, 0, 0, 0, 0),
(88013, 0, 1, 0, 0, 0, 0);
INSERT INTO `conversation_actors` (`ConversationId`, `ConversationActorId`, `ConversationActorGuid`, `ConversationActorNearId`, `Idx`, `CreatureId`, `CreatureDisplayInfoId`, `NoActorObject`, `ActivePlayerObject`, `VerifiedBuild`) VALUES
(51000, 80000, 0, 0, 0, 156799, 107146, 0, 0, 0),
(51000, 80001, 0, 0, 1, 156807, 88316, 0, 0, 0);
-- Hrun's Barrow conversations (Alliance 12120 / Horde 14540) were missing actors
INSERT INTO `conversation_actors` (`ConversationId`, `ConversationActorId`, `ConversationActorGuid`, `ConversationActorNearId`, `Idx`, `CreatureId`, `CreatureDisplayInfoId`, `NoActorObject`, `ActivePlayerObject`, `VerifiedBuild`) VALUES
(12120, 80002, 0, 0, 0, 156900, 92803, 0, 0, 0),
(14540, 80003, 0, 0, 0, 156900, 92803, 0, 0, 0);
@@ -0,0 +1,19 @@
-- Exiles Reach: correct post-Torgak quest flow (idempotent)
-- 1. 55196 The Harpy Problem: remove the Wrathion (156799) starter; keep Henry (156833 + 156887)
DELETE FROM `creature_queststarter` WHERE `id` = 156799 AND `quest` = 55196;
-- 4. 55639 Who Lurks in the Pit: turn in to Captain Garrick (245394), not Jaina (156807)
DELETE FROM `creature_questender` WHERE `id` = 156807 AND `quest` = 55639;
DELETE FROM `creature_questender` WHERE `id` = 245394 AND `quest` = 55639;
INSERT INTO `creature_questender` (`id`, `quest`, `VerifiedBuild`) VALUES
(245394, 55639, 0);
-- 4. 85678 Repair Yourself: start + turn in at Captain Garrick (245394)
DELETE FROM `creature_queststarter` WHERE `id` = 245394 AND `quest` = 85678;
DELETE FROM `creature_questender` WHERE `id` = 245394 AND `quest` = 85678;
INSERT INTO `creature_queststarter` (`id`, `quest`, `VerifiedBuild`) VALUES
(245394, 85678, 0);
INSERT INTO `creature_questender` (`id`, `quest`, `VerifiedBuild`) VALUES
(245394, 85678, 0);
-- 5. 58915 Hjalmar's Final Execution: starts at Hjalmar (162943), ends at Private Cole (156801) — no change needed
@@ -0,0 +1,44 @@
DELETE FROM `creature_queststarter` WHERE `id` = 156887 AND `quest` = 55196;
DELETE FROM `creature_questender` WHERE `id` = 156807 AND `quest` = 55882;
INSERT INTO `creature_questender` (`id`, `quest`, `VerifiedBuild`) VALUES (245394, 55882, 0);
DELETE FROM `creature_questender` WHERE `id` = 154300 AND `quest` = 55965;
DELETE FROM `creature_queststarter` WHERE `id` = 156941 AND `quest` = 55981;
INSERT INTO `creature_queststarter` (`id`, `quest`, `VerifiedBuild`) VALUES (245397, 55981, 0);
DELETE FROM `creature_questender` WHERE `id` = 156941 AND `quest` = 55981;
DELETE FROM `creature_queststarter` WHERE `id` = 156960 AND `quest` = 55989;
DELETE FROM `creature_queststarter` WHERE `id` = 156943 AND `quest` = 55989;
INSERT INTO `creature_queststarter` (`id`, `quest`, `VerifiedBuild`) VALUES (245667, 55989, 0);
DELETE FROM `creature_questender` WHERE `id` = 156960 AND `quest` = 55989;
DELETE FROM `creature_questender` WHERE `id` = 156943 AND `quest` = 55989;
INSERT INTO `creature_questender` (`id`, `quest`, `VerifiedBuild`) VALUES (245667, 55989, 0);
DELETE FROM `creature_queststarter` WHERE `id` = 156941 AND `quest` = 55990;
DELETE FROM `creature_questender` WHERE `id` = 156965 AND `quest` = 55990;
INSERT INTO `creature_questender` (`id`, `quest`, `VerifiedBuild`) VALUES (156961, 55990, 0);
DELETE FROM `creature_queststarter` WHERE `id` = 156961 AND `quest` = 55991;
DELETE FROM `creature_queststarter` WHERE `id` = 156941 AND `quest` = 55991;
INSERT INTO `creature_queststarter` (`id`, `quest`, `VerifiedBuild`) VALUES (245686, 55991, 0);
DELETE FROM `creature_questender` WHERE `id` = 238913 AND `quest` = 55991;
DELETE FROM `creature_questender` WHERE `id` = 154169 AND `quest` = 55991;
INSERT INTO `creature_questender` (`id`, `quest`, `VerifiedBuild`) VALUES (245686, 55991, 0);
DELETE FROM `creature_questender` WHERE `id` = 156941 AND `quest` = 55992;
DELETE FROM `creature_questender` WHERE `id` = 161350 AND `quest` = 55992;
DELETE FROM `creature_queststarter` WHERE `id` = 156807 AND `quest` = 56344;
INSERT INTO `creature_queststarter` (`id`, `quest`, `VerifiedBuild`) VALUES (245394, 56344, 0);
DELETE FROM `creature_questender` WHERE `id` = 156941 AND `quest` = 56344;
INSERT INTO `creature_questender` (`id`, `quest`, `VerifiedBuild`) VALUES (245397, 56344, 0);
DELETE FROM `creature_questender` WHERE `id` = 162972 AND `quest` = 58917;
INSERT INTO `creature_queststarter` (`id`, `quest`, `VerifiedBuild`) VALUES (156801, 58923, 0);
DELETE FROM `creature_queststarter` WHERE `id` = 162972 AND `quest` = 58933;
DELETE FROM `creature_questender` WHERE `id` = 156804 AND `quest` = 59347;
DELETE FROM `creature_queststarter` WHERE `id` = 156804 AND `quest` = 59349;
DELETE FROM `creature_questender` WHERE `id` = 156932 AND `quest` = 59350;
DELETE FROM `creature_queststarter` WHERE `id` = 167128 AND `quest` = 59943;
DELETE FROM `creature_questender` WHERE `id` = 167221 AND `quest` = 59948;
DELETE FROM `creature_questender` WHERE `id` = 162998 AND `quest` = 59958;
DELETE FROM `creature_queststarter` WHERE `id` = 167631 AND `quest` = 59980;
INSERT INTO `creature_queststarter` (`id`, `quest`, `VerifiedBuild`) VALUES (167630, 59980, 0);
DELETE FROM `creature_questender` WHERE `id` = 167631 AND `quest` = 59980;
DELETE FROM `creature_questender` WHERE `id` = 167633 AND `quest` = 59984;
DELETE FROM `creature_queststarter` WHERE `id` = 167633 AND `quest` = 59985;
DELETE FROM `creature_questender` WHERE `id` = 244496 AND `quest` = 59985;
DELETE FROM `creature_questender` WHERE `id` = 154169 AND `quest` = 59985;
@@ -0,0 +1,2 @@
-- Exiles Reach: post-Torgak quest givers (custom NPCs) need UNIT_NPC_FLAG_QUESTGIVER (0x2)
UPDATE `creature_template` SET `npcflag` = `npcflag` | 2 WHERE `entry` IN (245397, 245667, 245686);
@@ -0,0 +1,3 @@
-- Exiles Reach: the ritual Meredy/Herbert (153211/167298) need UNIT_NPC_FLAG_GOSSIP (0x1)
-- to start the Bloodbeak fight via OnGossipSelect (the event was unreachable with npcflag=0)
UPDATE `creature_template` SET `npcflag` = `npcflag` | 1 WHERE `entry` IN (153211, 167298);
@@ -0,0 +1,4 @@
-- Exiles Reach: correct the post-Torgak reunion scene packages.
-- 2341 (Alliance, cast by SPELL_REUNION_SCENE_A) -> 4778 (11.2.7 ExilesReach Alliance IGC)
-- 2497 (Horde) already correctly maps to 4779.
UPDATE `scene_template` SET `ScriptPackageID` = 4778 WHERE `SceneId` = 2341;
@@ -0,0 +1,6 @@
-- Exiles Reach: add a DB spawn for post-Torgak Captain Garrick (245394) at the camp,
-- so he's reliably present as quest-giver (55639/55194/85678) like Jaina (156807).
-- z = 91.001 matches the camp ground height (Jaina 42560 is also at 91.001).
SET @guid := 730202;
INSERT INTO `creature` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnDifficulties`, `phaseUseFlags`, `PhaseId`, `PhaseGroup`, `terrainSwapMap`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curHealthPct`, `MovementType`, `npcflag`, `unit_flags`, `unit_flags2`, `unit_flags3`, `ScriptName`, `StringId`, `VerifiedBuild`) VALUES
(@guid, 245394, 2175, 10424, 10424, 0, 0, 15017, 0, -1, 0, 0, 180.8, -2286.0, 91.001, 0.0, 180, 0, 0, NULL, 0, NULL, NULL, NULL, NULL, '', NULL, 0);
@@ -0,0 +1,6 @@
-- Exiles Reach: bind the Giant Boar ride scene (SceneId 2338, package 2712) to its SceneScript.
-- During the boar ride ("Ride of the Scientifically Enhanced Boar" / "The Redeather") the client
-- fires "Trampling Time", "Big Kill Credit" and "Knockback" trigger events; core only dispatches
-- those to a bound SceneScript via scene_template.ScriptName. The script itself lives in
-- src/server/scripts/ExilesReach/exiles_reach.cpp (scene_exiles_reach_boar_ride).
UPDATE `scene_template` SET `ScriptName` = 'scene_exiles_reach_boar_ride' WHERE `SceneId` = 2338;
@@ -48,6 +48,13 @@ uint32 SceneMgr::PlaySceneByTemplate(SceneTemplate const* sceneTemplate, Positio
if (!entry)
return 0;
// Scene debug (PlayerbotV2): log which scene plays on Exiles Reach (map 2175)
// so the post-ride cinematic can be matched against the expected one.
if (GetPlayer()->GetMapId() == 2175)
TC_LOG_ERROR("playerbot.v2", "[SceneDebug] {} playing sceneId={} package={} flags={}",
GetPlayer()->GetName(), sceneTemplate->SceneId, sceneTemplate->ScenePackageId,
sceneTemplate->PlaybackFlags.AsUnderlyingType());
// By default, take player position
if (!position)
position = GetPlayer();
@@ -205,8 +205,21 @@ void ConversationDataStore::LoadConversationTemplates()
{
static constexpr uint32 FirstLineId = 60000; // Arbitrary id to cover the affected rows
if (conversationLine->ID > FirstLineId && conversationLine->NextConversationLineID < (sConversationLineStore.GetNumRows() - USHRT_MAX - 1))
return (uint32)(USHRT_MAX + conversationLine->NextConversationLineID + 1);
// Line IDs above FirstLineId store NextConversationLineID as a uint16 offset into the high id
// space (real id = USHRT_MAX + stored + 1) when the real next line id does not fit in a uint16.
// The data is sparse, so GetNumRows() is not a reliable upper bound; resolve by checking which
// candidate actually exists, preferring the offset when it is the forward chain.
if (conversationLine->ID > FirstLineId)
{
uint32 stored = conversationLine->NextConversationLineID;
uint32 candidate = USHRT_MAX + stored + 1;
ConversationLineEntry const* rawEntry = sConversationLineStore.LookupEntry(stored);
ConversationLineEntry const* offsetEntry = sConversationLineStore.LookupEntry(candidate);
if (rawEntry && !offsetEntry)
return stored;
if (offsetEntry && (!rawEntry || candidate > conversationLine->ID))
return candidate;
}
return (uint32)conversationLine->NextConversationLineID;
}
+3
View File
@@ -2354,6 +2354,7 @@ void ScriptMgr::OnSceneTrigger(Player* player, uint32 sceneInstanceID, SceneTemp
ASSERT(player);
ASSERT(sceneTemplate);
FOREACH_SCRIPT(PlayerScript)->OnSceneTriggerEvent(player, sceneInstanceID, triggerName);
GET_SCRIPT(SceneScript, sceneTemplate->ScriptId, tmpscript);
tmpscript->OnSceneTriggerEvent(player, sceneInstanceID, sceneTemplate, triggerName);
}
@@ -2363,6 +2364,7 @@ void ScriptMgr::OnSceneCancel(Player* player, uint32 sceneInstanceID, SceneTempl
ASSERT(player);
ASSERT(sceneTemplate);
FOREACH_SCRIPT(PlayerScript)->OnSceneCancel(player, sceneInstanceID);
GET_SCRIPT(SceneScript, sceneTemplate->ScriptId, tmpscript);
tmpscript->OnSceneCancel(player, sceneInstanceID, sceneTemplate);
}
@@ -2372,6 +2374,7 @@ void ScriptMgr::OnSceneComplete(Player* player, uint32 sceneInstanceID, SceneTem
ASSERT(player);
ASSERT(sceneTemplate);
FOREACH_SCRIPT(PlayerScript)->OnSceneComplete(player, sceneInstanceID);
GET_SCRIPT(SceneScript, sceneTemplate->ScriptId, tmpscript);
tmpscript->OnSceneComplete(player, sceneInstanceID, sceneTemplate);
}
+162 -29
View File
@@ -24,12 +24,57 @@
#include "exiles_reach.h"
#include "MovementPackets.h"
#include "ScriptMgr.h"
#include "CellImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
class exiles_reach_general_playerscript : public PlayerScript
{
public:
exiles_reach_general_playerscript() : PlayerScript("exiles_reach_general_playerscript") {}
// Undead mowed down by the giant boar (spawnIds), so they can be respawned
// if the ride quest is abandoned.
static std::unordered_set<ObjectGuid::LowType> s_mowedDownUndead;
// Players currently on the boar ride, so an abandon can be detected (the
// OnQuestStatusChange hook does NOT fire for quest abandon).
static std::unordered_set<ObjectGuid> s_rideActivePlayers;
void CheckRideAbandon(Player* player)
{
ObjectGuid const guid = player->GetGUID();
bool active = false;
bool rewarded = false;
for (uint32 questId : { QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR, QUEST_H_THE_REDEATHER })
{
QuestStatus const status = player->GetQuestStatus(questId);
if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_COMPLETE)
active = true;
else if (status == QUEST_STATUS_REWARDED)
rewarded = true;
}
if (active)
s_rideActivePlayers.insert(guid);
else if (s_rideActivePlayers.erase(guid))
{
// Was riding and no longer is: abandoned (respawn the undead) or
// completed (let them stay mowed down).
if (!rewarded)
{
TC_LOG_ERROR("playerbot.v2", "[ExilesReach] ride abandoned; respawning {} tracked undead", s_mowedDownUndead.size());
if (Map* map = player->GetMap())
for (ObjectGuid::LowType spawnId : s_mowedDownUndead)
{
TC_LOG_ERROR("playerbot.v2", "[ExilesReach] respawn spawnId={}", spawnId);
map->Respawn(SPAWN_TYPE_CREATURE, spawnId);
}
}
s_mowedDownUndead.clear();
}
}
void OnLogin(Player* player, bool /*firstLogin*/) override
{
if (player->GetMapId() != MAP_NPE)
@@ -42,6 +87,7 @@ public:
void OnPlayerWorldObjectUpdate(Player* player, uint32 /*diff*/) override
{
CheckExilesReachSceneSpells(player);
CheckRideAbandon(player);
}
void OnSceneTriggerEvent(Player* player, uint32 sceneInstanceID, std::string sceneEvent) override
@@ -49,20 +95,11 @@ public:
if (player->GetMapId() != MAP_EXILES_REACH)
return;
if (sceneEvent == "Big Kill Credit")
{
player->CastSpell(player, SPELL_CADAVER_KILL_CREDIT);
if (player->GetQuestObjectiveProgress(QUEST_H_THE_REDEATHER, 2) == 8)
{
player->CastSpell(player, SPELL_CADAVER_CREDIT_CHECK_CHOPPY_MALFUNCTION, true);
}
if (player->GetQuestObjectiveProgress(QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR, 2) == 8)
{
player->CastSpell(player, SPELL_GIANT_BOAR_PING_VEHICLE, true);
}
}
// NOTE: The Giant Boar ride triggers ("Big Kill Credit", "Knockback",
// "Trampling Time") are handled in scene_exiles_reach_boar_ride below,
// bound to scene_template.SceneId = 2338 via SQL. SceneScripts are
// dispatched by core on every branch, so the ride works without any
// core changes and fires exactly once per event.
if (sceneEvent == "Teleport")
{
@@ -97,21 +134,6 @@ public:
player->CastSpell(player, SPELL_ORGRIMMAR_TELEPORT, true);
}
}
if (sceneEvent == "Knockback")
{
player->CastSpell(player, SPELL_GIANT_BOAR_RIDING_KNOCKBACK, true);
}
if (sceneEvent == "Trampling Time")
{
if (Creature* giantBoarVehicle = player->GetVehicleCreatureBase())
{
Position targetLoc = giantBoarVehicle->GetFirstCollisionPosition(20.f, 0.f);
giantBoarVehicle->GetMotionMaster()->MoveCharge(targetLoc.GetPositionX(), targetLoc.GetPositionY(), targetLoc.GetPositionZ());
player->CastSpell(player, SPELL_GIANT_BOAR_TRAMPLE, true);
}
}
}
void OnUpdateArea(Player* player, uint32 newArea, uint32 /*oldArea*/) override
@@ -154,6 +176,115 @@ public:
if (questId == QUEST_AN_END_TO_BEGINNINGS || questId == QUEST_H_AN_END_TO_BEGINNINGS)
CancelExilesReachSceneAuras(player);
// Ride of the Scientifically Enhanced Boar: clear the mowed-down tracking
// when the ride is completed (the mobs stay mowed down). Abandon is
// detected in CheckRideAbandon (OnQuestStatusChange doesn't fire for
// quest abandon).
if (questId == QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR || questId == QUEST_H_THE_REDEATHER)
if (player->GetQuestStatus(questId) == QUEST_STATUS_REWARDED)
s_mowedDownUndead.clear();
if (questId == QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR && player->GetQuestStatus(questId) == QUEST_STATUS_REWARDED)
{
player->CastSpell(player, SPELL_REUNION_SCENE_A, true);
Conversation::CreateConversation(CONVERSATION_OGRE_RUINS_REUNION, player, *player, player->GetGUID(), nullptr);
}
else if (questId == QUEST_H_THE_REDEATHER && player->GetQuestStatus(questId) == QUEST_STATUS_REWARDED)
player->CastSpell(player, SPELL_REUNION_SCENE_H, true);
// After the ride is handed in, the camp at the ogre ruins populates:
// Jaina near Austin Huxworth by the rock edging (grants Stocking Up /
// Repair Yourself), Captain Garrick by the campfire (DB spawn).
if (questId == QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR && player->GetQuestStatus(questId) == QUEST_STATUS_REWARDED)
{
if (!player->FindNearestCreature(NPC_OGRE_RUINS_POST_TORGOK_JAINA, 50.0f, true))
if (Creature* jaina = player->SummonCreature(NPC_OGRE_RUINS_POST_TORGOK_JAINA,
Position(186.572f, -2289.42f, 81.6354f, 2.31301f),
TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID()))
jaina->SetNpcFlag(UNIT_NPC_FLAG_QUESTGIVER);
}
}
};
std::unordered_set<ObjectGuid::LowType> exiles_reach_general_playerscript::s_mowedDownUndead;
std::unordered_set<ObjectGuid> exiles_reach_general_playerscript::s_rideActivePlayers;
/* ## SCENE SCRIPTS > ## */
// Giant Boar ride (scene_template.SceneId = 2338, package 2712) -
// "Ride of the Scientifically Enhanced Boar" / "The Redeather".
//
// The client fires these trigger events from scene package 2712 during the boar
// ride (verified against a retail 12.1 packet capture):
// Conversation, then repeating pairs of "Trampling Time" + "Big Kill Credit",
// plus "Knockback" and "Hint", until SMSG_CANCEL_SCENE.
//
// The logic is bound to the scene via scene_template.ScriptName (see SQL
// update) instead of living in the PlayerScript hook above: core dispatches
// scene trigger events to a bound SceneScript on every branch, while
// OnSceneTriggerEvent only reaches PlayerScripts when an extra core change is
// present. Keeping it here means each event fires exactly once on both.
class scene_exiles_reach_boar_ride : public SceneScript
{
public:
scene_exiles_reach_boar_ride() : SceneScript("scene_exiles_reach_boar_ride") {}
void OnSceneTriggerEvent(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/, std::string const& triggerName) override
{
if (player->GetMapId() != MAP_EXILES_REACH)
return;
if (triggerName == "Big Kill Credit")
{
player->CastSpell(player, SPELL_CADAVER_KILL_CREDIT);
if (player->GetQuestObjectiveProgress(QUEST_H_THE_REDEATHER, 2) == 8)
{
player->CastSpell(player, SPELL_CADAVER_CREDIT_CHECK_CHOPPY_MALFUNCTION, true);
}
if (player->GetQuestObjectiveProgress(QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR, 2) == 8)
{
player->CastSpell(player, SPELL_GIANT_BOAR_PING_VEHICLE, true);
}
// The boar mowed the undead down: despawn the hostile mobs around
// the rider so the trampled army actually vanishes (and stops
// attacking). Tied to the reliable scene credit rather than the
// trample's own grid search.
std::list<Creature*> mobs;
Trinity::AnyUnitInObjectRangeCheck u_check(player, 50.0f);
Trinity::CreatureListSearcher<Trinity::AnyUnitInObjectRangeCheck> searcher(player, mobs, u_check);
Cell::VisitGridObjects(player, searcher, 50.0f);
for (Creature* mob : mobs)
{
if (!player->IsHostileTo(mob))
continue;
if (mob->GetEntry() == NPC_OGRE_RUINS_TORGOK)
continue; // leave the boss for the fight
// Track so the undead can be respawned if the quest is abandoned.
exiles_reach_general_playerscript::s_mowedDownUndead.insert(mob->GetSpawnId());
// Long respawn delay so the mowed-down undead stay dead
// through the rest of the ride instead of popping back.
mob->DespawnOrUnsummon(0s, 1h);
}
}
if (triggerName == "Knockback")
{
player->CastSpell(player, SPELL_GIANT_BOAR_RIDING_KNOCKBACK, true);
}
if (triggerName == "Trampling Time")
{
if (Creature* giantBoarVehicle = player->GetVehicleCreatureBase())
{
Position targetLoc = giantBoarVehicle->GetFirstCollisionPosition(20.f, 0.f);
giantBoarVehicle->GetMotionMaster()->MoveCharge(targetLoc.GetPositionX(), targetLoc.GetPositionY(), targetLoc.GetPositionZ());
player->CastSpell(player, SPELL_GIANT_BOAR_TRAMPLE, true);
}
}
}
};
@@ -366,6 +497,8 @@ void AddSC_exiles_reach_general()
{
// Player Scripts
new exiles_reach_general_playerscript();
// Scene Scripts
new scene_exiles_reach_boar_ride();
// WorldMap Scripts
new map_exiles_reach();
// Spell Scripts
@@ -349,6 +349,9 @@ enum ExileReachHelpers
NPC_OGRE_RUINS_TORGOK_FIGHTER_H = 167145,
NPC_OGRE_RUINS_CADAVER_KILL_CREDIT = 165150,
NPC_OGRE_RUINS_TORGOK = 162817,
NPC_OGRE_RUINS_WRATHION = 156799,
NPC_OGRE_RUINS_POST_TORGOK_JAINA = 156807,
NPC_OGRE_RUINS_POST_TORGOK_GARRICK = 245394,
NPC_OGRE_RUINS_ALARIA = 156803,
NPC_OGRE_RUINS_BJORN = 154300,
NPC_OGRE_RUINS_KEELA_BEFORE_HARPY_ROOST = 156804,
@@ -573,6 +576,7 @@ enum ExileReachHelpers
PHASE_ALLIANCE_DARKMAUL_CITADEL_15612 = 15612,
CONVERSATION_BLOOD_BEAK_INCOMING_A = 11739,
CONVERSATION_OGRE_RUINS_REUNION = 51000,
CONVERSATION_BLOOD_BEAK_INCOMING_H = 14572,
CONVERSATION_GARRICK_OGRE_TRANSFORM_APPLY = 11511,
CONVERSATION_REACHED_DARKMAUL_CITADEL_ENTRANCE = 11511,
@@ -22,6 +22,9 @@
*/
#include "exiles_reach.h"
#include "CellImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
class exiles_reach_darkmaul_plains_playerscript : public PlayerScript
{
@@ -59,12 +62,12 @@ public:
if (player->IsInAlliance())
{
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !player->HasAura(SPELL_RIDING_GIANT_BOAR) && !player->GetQuestStatus(QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !QuestCompletedOrRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
WowCommunity::PhaseShift(player, { PHASE_GENERAL_OGRE_RUINS_TORGOK }, !QuestCompletedOrRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_HARPY_ROOST_MEREDY_RITUAL }, true);
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_QUILBOAR_BRIARPATCH_15276, PHASE_ALLIANCE_QUILBOAR_BRIARPATCH_16917 }, player->GetQuestStatus(QUEST_DOWN_WITH_THE_QUILBOAR) != QUEST_STATUS_REWARDED);
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_DARKMAUL_PLAINS_SPRINGSTOCK }, QuestCompletedOrRewarded(player, QUEST_DOWN_WITH_THE_QUILBOAR) && !player->GetSummonedCreatureByEntry(NPC_DARKMAUL_PLAINS_SPRINGSTOCK) && !player->GetSummonedCreatureByEntry(NPC_DARKMAUL_PLAINS_SPRINGSTOCK_RESIZING_SUMMON));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_DARKMAUL_PLAINS_GARRICK }, QuestCompletedOrRewarded(player, QUEST_DOWN_WITH_THE_QUILBOAR) && !QuestAccepted(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_DARKMAUL_PLAINS_GARRICK }, QuestCompletedOrRewarded(player, QUEST_DOWN_WITH_THE_QUILBOAR) && !QuestRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_DARKMAUL_PLAINS_AUSTIN }, QuestCompletedOrRewarded(player, QUEST_DOWN_WITH_THE_QUILBOAR));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_DARKMAUL_PLAINS_13394 }, QuestCompleted(player, QUEST_DOWN_WITH_THE_QUILBOAR));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_DARKMAUL_PLAINS_13780 }, QuestCompleted(player, QUEST_DOWN_WITH_THE_QUILBOAR));
@@ -887,6 +890,18 @@ public:
class spell_riding_giant_boar_305068_AuraScript : public AuraScript
{
void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* owner = GetUnitOwner();
if (!owner)
return;
// Riding the giant boar: the undead chew on the boar, not the rider.
// Block NPC attacks on the player (the trample/charge already pull
// threat onto the boar, so remaining direct hits shouldn't reach us).
owner->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
}
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* owner = GetUnitOwner();
@@ -894,12 +909,15 @@ public:
if (!owner || !player)
return;
owner->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_NPC);
player->RemoveAura(SPELL_RIDING_GIANT_BOAR2);
player->CastSpell(player, SPELL_KNOCKBACK_FOR_HACKFIX_GIANT_BOAR_LEAVE, true);
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_riding_giant_boar_305068_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_CONTROL_VEHICLE, AURA_EFFECT_HANDLE_REAL);
OnEffectApply += AuraEffectApplyFn(spell_riding_giant_boar_305068_AuraScript::HandleApply, EFFECT_1, SPELL_AURA_LINKED_SUMMON, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_riding_giant_boar_305068_AuraScript::HandleRemove, EFFECT_1, SPELL_AURA_LINKED_SUMMON, AURA_EFFECT_HANDLE_REAL);
}
};
@@ -982,6 +1000,61 @@ public:
}
};
// Giant Boar Trample (305557) — mows down the undead army / Monstrous Cadavers
// (157091) around the boar. The spell's Effect 1 is a DUMMY (radius 13) that
// targets the caster; the actual damage to nearby enemies is scripted here.
class spell_giant_boar_trample_305557 : public SpellScriptLoader
{
public:
spell_giant_boar_trample_305557() : SpellScriptLoader("spell_giant_boar_trample_305557") {}
class spell_giant_boar_trample_305557_SpellScript : public SpellScript
{
void HandleDummy(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster || !caster->IsInWorld())
return;
// Damage comes from the boar vehicle so the undead aggro the boar,
// not the rider (a player-cast trample would pull threat onto the
// player and the mobs would chew through the rider's health).
Unit* source = caster;
if (Player* player = caster->ToPlayer())
if (Unit* boar = player->GetVehicleBase())
source = boar;
float radius = GetEffectInfo().CalcRadius(source).Max;
std::list<Creature*> targets;
Trinity::AnyUnitInObjectRangeCheck u_check(source, radius);
Trinity::CreatureListSearcher<Trinity::AnyUnitInObjectRangeCheck> searcher(source, targets, u_check);
Cell::VisitGridObjects(source, searcher, radius);
for (Creature* target : targets)
{
if (!source->IsHostileTo(target))
continue;
// Mow the undead down: despawn them outright so the trampled
// army vanishes (the scene's "Big Kill Credit" grants the
// quest credit, so the mobs don't need to die through the
// normal damage/corpse path).
target->DespawnOrUnsummon(0s, 1h);
}
}
void Register() override
{
OnEffectHit += SpellEffectFn(spell_giant_boar_trample_305557_SpellScript::HandleDummy, EFFECT_1, SPELL_EFFECT_DUMMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_giant_boar_trample_305557_SpellScript();
}
};
class LeaveGiantBoarEvent : public BasicEvent
{
public:
@@ -1086,4 +1159,5 @@ void AddSC_exiles_reach_darkmaul_plains()
new spell_ride_vehicle_173426();
new spell_giant_boar_charge_321627();
new spell_giant_boar_ping_vehicle_305559();
new spell_giant_boar_trample_305557();
}
@@ -456,6 +456,8 @@ struct npc_exiles_reach_harpy_roost_153964 : public ScriptedAI
if (player->HasAura(SPELL_RITUAL_SCENE_HARPY_BEAM))
player->RemoveAura(SPELL_RITUAL_SCENE_HARPY_BEAM);
player->KilledMonsterCredit(NPC_HARPY_ROOST_BLOODBEAK);
std::vector<Creature*> ritualDoneGoHome = std::vector<Creature*>{};
if (Creature* meredy = player->GetSummonedCreatureByEntry(NPC_HARPY_ROOST_MEREDY_RITUAL))
@@ -72,7 +72,7 @@ public:
if (player->IsInAlliance())
{
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !player->HasAura(SPELL_RIDING_GIANT_BOAR) && !player->GetQuestStatus(QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !QuestCompletedOrRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_HENRY_RITUAL }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !QuestCompletedOrRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_HRUNS_BARROW_RALIA_RITUAL }, QuestCompleted(player, QUEST_THE_SCOUT_O_MATIC_5000));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_13395 }, QuestCompleted(player, QUEST_THE_SCOUT_O_MATIC_5000));
@@ -127,8 +127,9 @@ struct npc_exiles_reach_ship_166573_156280 : public ScriptedAI
Talk(0, player);
break;
case QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR:
if (Creature* clone = player->SummonCreature(NPC_OGRE_RUINS_TORGOK_FIGHTER_A, FindSummonPosition(player, NPC_DARKMAUL_PLAINS_GARRICK), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID()))
clone->FollowTarget(player);
// Ride the boar alone — no follower (156807 reuses Jaina's model,
// which read as a duplicate Jaina tagging along). The quest-giver
// stays in place.
break;
}
}
@@ -73,7 +73,7 @@ public:
{
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, !player->HasAura(SPELL_RESIZER_SLAUGHTER) && !player->HasAura(SPELL_RIDING_GIANT_BOAR) && !player->GetQuestStatus(QUEST_H_THE_REDEATHER));
WowCommunity::PhaseShift(player, { PHASE_HORDE_OGRE_RUINS_SHUJA_RITUAL }, QuestsRewarded(player, { QUEST_H_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_H_DOWN_WITH_THE_QUILBOAR }) && !QuestCompletedOrRewarded(player, QUEST_H_THE_REDEATHER));
WowCommunity::PhaseShift(player, { PHASE_HORDE_OGRE_RUINS_SHUJA_QUEST_REWARDER }, QuestCompleted(player, QUEST_H_THE_REDEATHER));
WowCommunity::PhaseShift(player, { PHASE_HORDE_OGRE_RUINS_SHUJA_QUEST_REWARDER }, QuestAcceptedOrCompleted(player, QUEST_H_THE_REDEATHER));
WowCommunity::PhaseShift(player, { PHASE_HORDE_OGRE_RUINS_CAMP_OBJECTS }, QuestCompletedOrRewarded(player, QUEST_H_THE_REDEATHER));
WowCommunity::PhaseShift(player, { PHASE_HORDE_HRUNS_BARROW_CRENNA_RITUAL }, QuestCompleted(player, QUEST_H_THE_REDEATHER));
WowCommunity::PhaseShift(player, { PHASE_HORDE_OGRE_RUINS_15330 }, QuestCompleted(player, QUEST_H_THE_REDEATHER));
@@ -92,7 +92,7 @@ public:
if (player->IsInAlliance())
{
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !player->HasAura(SPELL_RIDING_GIANT_BOAR) && !player->GetQuestStatus(QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !QuestCompletedOrRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_HENRY_RITUAL }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !QuestCompletedOrRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_HRUNS_BARROW_RALIA_RITUAL }, QuestCompleted(player, QUEST_THE_SCOUT_O_MATIC_5000));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_13395 }, QuestCompleted(player, QUEST_THE_SCOUT_O_MATIC_5000));
@@ -111,8 +111,8 @@ public:
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_HARPY_ROOST_TOTEMS }, true);
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_13836 }, true);
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_13815 }, true);
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_GARRICK_CAMP }, QuestRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR) && (!QuestRewarded(player, QUEST_MESSAGE_TO_BASE) || !QuestRewarded(player, QUEST_WESTWARD_BOUND)));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_GARRICK_BEFORE_DARKMAUL_CITADEL }, QuestRewarded(player, QUEST_MESSAGE_TO_BASE) && QuestRewarded(player, QUEST_WESTWARD_BOUND) && !QuestAcceptedOrCompleted(player, QUEST_TO_DARKMAUL_CITADEL));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_GARRICK_CAMP }, (QuestAccepted(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR) || QuestRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR)) && (!QuestRewarded(player, QUEST_MESSAGE_TO_BASE) || !QuestRewarded(player, QUEST_WESTWARD_BOUND)));
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_GARRICK_BEFORE_DARKMAUL_CITADEL }, QuestRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR) && !QuestAcceptedOrCompleted(player, QUEST_TO_DARKMAUL_CITADEL));
}
}
break;