summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/installer/includes/functions.sh2
-rw-r--r--data/sql/updates/db_world/2025_12_01_05.sql (renamed from data/sql/updates/pending_db_world/rev_1764203353826128556.sql)1
-rw-r--r--data/sql/updates/db_world/2025_12_02_00.sql4
-rw-r--r--data/sql/updates/db_world/2025_12_02_01.sql38
-rw-r--r--data/sql/updates/db_world/2025_12_02_02.sql66
-rw-r--r--data/sql/updates/db_world/2025_12_02_03.sql3
-rw-r--r--data/sql/updates/db_world/2025_12_02_04.sql23
-rw-r--r--data/sql/updates/db_world/2025_12_04_00.sql4
-rw-r--r--src/common/Collision/Maps/MapDefines.h2
-rw-r--r--src/common/Collision/VMapDefinitions.h4
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp47
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.h1
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp8
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h2
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h21
-rw-r--r--src/server/game/DungeonFinding/LFGMgr.cpp11
-rw-r--r--src/server/game/DungeonFinding/LFGMgr.h2
-rw-r--r--src/server/scripts/Northrend/zone_storm_peaks.cpp84
-rw-r--r--src/tools/mmaps_generator/mmaps-config.yaml5
-rw-r--r--src/tools/vmap4_extractor/vmapexport.cpp7
-rw-r--r--src/tools/vmap4_extractor/vmapexport.h4
-rw-r--r--src/tools/vmap4_extractor/wmo.cpp21
-rw-r--r--src/tools/vmap4_extractor/wmo.h2
23 files changed, 274 insertions, 88 deletions
diff --git a/apps/installer/includes/functions.sh b/apps/installer/includes/functions.sh
index 3c9b2edba2..79fbb355d9 100644
--- a/apps/installer/includes/functions.sh
+++ b/apps/installer/includes/functions.sh
@@ -155,7 +155,7 @@ function inst_simple_restarter {
function inst_download_client_data {
# change the following version when needed
- local VERSION=v18.0
+ local VERSION=v19
echo "#######################"
echo "Client data downloader"
diff --git a/data/sql/updates/pending_db_world/rev_1764203353826128556.sql b/data/sql/updates/db_world/2025_12_01_05.sql
index d0c3ed0532..81ce9a5adb 100644
--- a/data/sql/updates/pending_db_world/rev_1764203353826128556.sql
+++ b/data/sql/updates/db_world/2025_12_01_05.sql
@@ -1,3 +1,4 @@
+-- DB update 2025_12_01_04 -> 2025_12_01_05
--
-- Wolfsbane Root (189313) - Despawn on use via SmartAI
-- Closes https://github.com/azerothcore/azerothcore-wotlk/issues/23904
diff --git a/data/sql/updates/db_world/2025_12_02_00.sql b/data/sql/updates/db_world/2025_12_02_00.sql
new file mode 100644
index 0000000000..ca9e7aea3a
--- /dev/null
+++ b/data/sql/updates/db_world/2025_12_02_00.sql
@@ -0,0 +1,4 @@
+-- DB update 2025_12_01_05 -> 2025_12_02_00
+
+-- Remove double spawn point
+DELETE FROM `creature` WHERE (`id1` = 32250) AND (`guid` IN (125031));
diff --git a/data/sql/updates/db_world/2025_12_02_01.sql b/data/sql/updates/db_world/2025_12_02_01.sql
new file mode 100644
index 0000000000..63705b3fcf
--- /dev/null
+++ b/data/sql/updates/db_world/2025_12_02_01.sql
@@ -0,0 +1,38 @@
+-- DB update 2025_12_02_00 -> 2025_12_02_01
+--
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 29796) AND (`source_type` = 0) AND (`id` IN (0));
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(29796, 0, 0, 0, 19, 0, 100, 0, 12886, 0, 0, 0, 0, 0, 11, 55253, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Gretta the Arbiter - On Quest \'The Drakkensryd\' Taken - Cast \'Force Cast Initial Proto-Drake\'');
+
+UPDATE `creature_template` SET `speed_run` = 3.2 WHERE (`entry` = 29679);
+
+-- 55971 Eagle Flight
+UPDATE `creature_template_addon` SET `auras` = '55971' WHERE (`entry` = 29679);
+
+-- Update comments, Exit vehicle on death
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 29694) AND (`source_type` = 0) AND (`id` IN (0, 1, 2));
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(29694, 0, 0, 0, 0, 0, 100, 0, 2000, 5000, 5000, 9000, 0, 0, 11, 32736, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Hyldsmeet Drakerider - In Combat - Cast \'Mortal Strike\''),
+(29694, 0, 1, 2, 6, 0, 100, 512, 0, 0, 0, 0, 0, 0, 33, 29800, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Hyldsmeet Drakerider - On Just Died - Quest Credit \'null\''),
+(29694, 0, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 203, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hyldsmeet Drakerider - On Just Died - Exit vehicle');
+
+-- Hyldsmeet Drakerider eject NPC passenger vertically
+DELETE FROM `vehicle_seat_addon` WHERE (`SeatEntry` = 2101);
+INSERT INTO `vehicle_seat_addon` (`SeatEntry`, `SeatOrientation`, `ExitParamX`, `ExitParamY`, `ExitParamZ`, `ExitParamO`, `ExitParamValue`) VALUES
+(2101, 0, 0, 0, 4, 0, 1);
+
+-- Update Comments, Reduce despawn time from 2s to 1s
+DELETE FROM `smart_scripts` WHERE (`entryorguid` = 29679) AND (`source_type` = 0) AND (`id` IN (0, 1, 2));
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
+(29679, 0, 0, 0, 60, 0, 100, 513, 1000, 1000, 0, 0, 0, 0, 53, 2, 29679, 0, 0, 1000, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hyldsmeet Proto-Drake - On Update - Start Waypoint Path 29679 (No Repeat)'),
+(29679, 0, 1, 0, 60, 0, 100, 513, 500, 500, 0, 0, 0, 0, 60, 1, 500, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hyldsmeet Proto-Drake - On Update - Set Fly On (No Repeat)'),
+(29679, 0, 2, 0, 28, 0, 100, 512, 0, 0, 0, 0, 0, 0, 41, 1000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Hyldsmeet Proto-Drake - On Passenger Removed - Despawn In 1000 ms');
+
+DELETE FROM `spell_area` WHERE `spell` IN (55012, 72914) AND `area` IN (4430, 4431, 4432) AND `quest_start` = 12886;
+INSERT INTO `spell_area` (`spell`, `area`, `quest_start`, `quest_end`, `aura_spell`, `racemask`, `gender`, `autocast`, `quest_start_status`, `quest_end_status`) VALUES
+(55012, 4430, 12886, 0, 0, 0, 2, 1, 10, 0),
+(55012, 4431, 12886, 0, 0, 0, 2, 1, 10, 0),
+(55012, 4432, 12886, 0, 0, 0, 2, 1, 10, 0),
+(72914, 4430, 12886, 0, 0, 0, 2, 1, 10, 0),
+(72914, 4431, 12886, 0, 0, 0, 2, 1, 10, 0),
+(72914, 4432, 12886, 0, 0, 0, 2, 1, 10, 0);
diff --git a/data/sql/updates/db_world/2025_12_02_02.sql b/data/sql/updates/db_world/2025_12_02_02.sql
new file mode 100644
index 0000000000..e2f4488bda
--- /dev/null
+++ b/data/sql/updates/db_world/2025_12_02_02.sql
@@ -0,0 +1,66 @@
+-- DB update 2025_12_02_01 -> 2025_12_02_02
+-- Makes all Everfrost Chips spawns 45 minutes (before 30 and 1 hour).
+UPDATE `gameobject` SET `spawntimesecs` = 2700 WHERE `id` = 193997;
+
+DELETE FROM `pool_template` WHERE `entry` IN (150, 151, 152);
+INSERT INTO `pool_template` (`entry`, `max_limit`, `description`) VALUES
+(150, 8, "Everfrost Chip - Valley of Ancient Winters"), -- Total 30 / 4 = 7.5 rounded to 8
+(151, 4, "Everfrost Chip - Frostfield Lake"), -- Total 16 / 4 = 4
+(152, 2, "Everfrost Chip - Dun Niffelem"); -- Total 08 / 4 = 2
+
+DELETE FROM `pool_gameobject` WHERE `pool_entry` IN (150, 151, 152) AND `guid` IN (221000, 221002, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 3721, 3722, 3723, 3724, 3725, 3726, 3727, 3728, 3729, 3730, 3731, 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, 3740, 3741, 3742, 3743, 3744, 3745, 3746, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, 3756, 3757, 3758, 3759, 3760, 3761, 221001);
+INSERT INTO `pool_gameobject` (`guid`, `pool_entry`, `chance`, `description`) VALUES
+(3728, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3751, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3761, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3721, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3734, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3755, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3724, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(1170, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3732, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3723, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3729, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3746, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3752, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(1161, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3722, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3756, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3731, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(1162, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(1163, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3737, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3730, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3726, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3727, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(1169, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3736, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(221002, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3749, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(221000, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3743, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3725, 150, 0, "Everfrost Chip - Valley of Ancient Winters"),
+(3759, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(3733, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(3753, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(3758, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(221001, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(3735, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(1168, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(1167, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(3760, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(3745, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(3741, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(3744, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(1166, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(3739, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(3757, 151, 0, "Everfrost Chip - Frostfield Lake"),
+(3748, 152, 0, "Everfrost Chip - Dun Niffelem"),
+(3740, 152, 0, "Everfrost Chip - Dun Niffelem"),
+(3738, 152, 0, "Everfrost Chip - Dun Niffelem"),
+(3750, 152, 0, "Everfrost Chip - Dun Niffelem"),
+(1164, 152, 0, "Everfrost Chip - Dun Niffelem"),
+(3747, 152, 0, "Everfrost Chip - Dun Niffelem"),
+(1165, 152, 0, "Everfrost Chip - Dun Niffelem"),
+(3742, 152, 0, "Everfrost Chip - Dun Niffelem"),
+(3754, 152, 0, "Everfrost Chip - Dun Niffelem");
diff --git a/data/sql/updates/db_world/2025_12_02_03.sql b/data/sql/updates/db_world/2025_12_02_03.sql
new file mode 100644
index 0000000000..7dc7171969
--- /dev/null
+++ b/data/sql/updates/db_world/2025_12_02_03.sql
@@ -0,0 +1,3 @@
+-- DB update 2025_12_02_02 -> 2025_12_02_03
+-- From: "from that $r" to "from that troll" as refers to the troll (Drakkari prisoner) and not the player's race.
+UPDATE `quest_offer_reward` SET `RewardText` = 'You\'ve done it!$B$BThe intelligence gathered from that troll will undoubtedly be of great value. I\'ll be certain to make mention of your efforts in my report to the commander.$B$BThank you, $N.' WHERE `ID` = 12541;
diff --git a/data/sql/updates/db_world/2025_12_02_04.sql b/data/sql/updates/db_world/2025_12_02_04.sql
new file mode 100644
index 0000000000..d4388331db
--- /dev/null
+++ b/data/sql/updates/db_world/2025_12_02_04.sql
@@ -0,0 +1,23 @@
+-- DB update 2025_12_02_03 -> 2025_12_02_04
+-- Seething Revenant (30387) - Add missing loot
+-- Closes https://github.com/azerothcore/azerothcore-wotlk/issues/23807
+
+UPDATE `creature_loot_template` SET `Chance` = 0.04 WHERE `Entry` = 30387 AND `Item` = 45912;
+
+DELETE FROM `creature_loot_template` WHERE `Entry` = 30387 AND `Item` IN (39512, 42780, 37702, 39513, 43624, 42173, 42175, 26001, 26002, 26013, 26014, 26015, 26027, 26028, 35074);
+INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(30387, 39512, 0, 56, 0, 1, 0, 1, 1, 'Seething Revenant - Hoary Crystals'),
+(30387, 42780, 0, 26, 0, 1, 0, 1, 1, 'Seething Revenant - Relic of Ulduar'),
+(30387, 37702, 0, 19, 0, 1, 0, 1, 2, 'Seething Revenant - Crystallized Fire'),
+(30387, 39513, 0, 14, 0, 1, 0, 1, 1, 'Seething Revenant - Efflorescing Shards'),
+(30387, 43624, 0, 0.01, 0, 1, 0, 1, 1, 'Seething Revenant - Titanium Lockbox'),
+(30387, 42173, 0, 0.005, 0, 1, 0, 1, 1, 'Seething Revenant - Pattern: Blue Lumberjack Shirt'),
+(30387, 42175, 0, 0.005, 0, 1, 0, 1, 1, 'Seething Revenant - Pattern: Green Lumberjack Shirt'),
+(30387, 26001, 26001, 3, 0, 1, 1, 1, 1, 'Seething Revenant - (ReferenceTable)'),
+(30387, 26002, 26002, 3, 0, 1, 1, 1, 1, 'Seething Revenant - (ReferenceTable)'),
+(30387, 26013, 26013, 1, 0, 1, 1, 1, 1, 'Seething Revenant - (ReferenceTable)'),
+(30387, 26014, 26014, 1, 0, 1, 1, 1, 1, 'Seething Revenant - (ReferenceTable)'),
+(30387, 26015, 26015, 1, 0, 1, 1, 1, 1, 'Seething Revenant - (ReferenceTable)'),
+(30387, 26027, 26027, 0.5, 0, 1, 1, 1, 1, 'Seething Revenant - (ReferenceTable)'),
+(30387, 26028, 26028, 0.5, 0, 1, 1, 1, 1, 'Seething Revenant - (ReferenceTable)'),
+(30387, 35074, 35074, 0.1, 0, 1, 1, 1, 1, 'Seething Revenant - (ReferenceTable)');
diff --git a/data/sql/updates/db_world/2025_12_04_00.sql b/data/sql/updates/db_world/2025_12_04_00.sql
new file mode 100644
index 0000000000..a57036c8ae
--- /dev/null
+++ b/data/sql/updates/db_world/2025_12_04_00.sql
@@ -0,0 +1,4 @@
+-- DB update 2025_12_02_04 -> 2025_12_04_00
+
+UPDATE `creature_template` SET `exp` = 2 WHERE (`entry` = 32263);
+UPDATE `creature` SET `curhealth` = 10080 WHERE (`id1` = 32263) AND `guid` = 85056;
diff --git a/src/common/Collision/Maps/MapDefines.h b/src/common/Collision/Maps/MapDefines.h
index d928c51721..a3527f16c2 100644
--- a/src/common/Collision/Maps/MapDefines.h
+++ b/src/common/Collision/Maps/MapDefines.h
@@ -26,7 +26,7 @@
#define SIZE_OF_GRIDS 533.3333f
#define MMAP_MAGIC 0x4d4d4150 // 'MMAP'
-#define MMAP_VERSION 18
+#define MMAP_VERSION 19
struct MmapTileRecastConfig
{
diff --git a/src/common/Collision/VMapDefinitions.h b/src/common/Collision/VMapDefinitions.h
index 623dea5020..b8026d9496 100644
--- a/src/common/Collision/VMapDefinitions.h
+++ b/src/common/Collision/VMapDefinitions.h
@@ -22,8 +22,8 @@
namespace VMAP
{
- const char VMAP_MAGIC[] = "VMAP_4.7";
- const char RAW_VMAP_MAGIC[] = "VMAP047"; // used in extracted vmap files with raw data
+ const char VMAP_MAGIC[] = "VMAP_4.8";
+ const char RAW_VMAP_MAGIC[] = "VMAP048"; // used in extracted vmap files with raw data
const char GAMEOBJECT_MODELS[] = "GameObjectModels.dtree";
// defined in TileAssembler.cpp currently...
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index f888403491..3c952a42d9 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -858,7 +858,7 @@ void SmartAI::AttackStart(Unit* who)
return;
}
- if (who && me->Attack(who, me->IsWithinMeleeRange(who)))
+ if (who && me->Attack(who, me->IsWithinMeleeRange(who) || _currentRangeMode))
{
if (!me->HasUnitState(UNIT_STATE_NO_COMBAT_MOVEMENT))
{
@@ -870,7 +870,7 @@ void SmartAI::AttackStart(Unit* who)
me->GetMotionMaster()->Clear(false);
}
- me->GetMotionMaster()->MoveChase(who);
+ me->GetMotionMaster()->MoveChase(who, _attackDistance);
}
}
}
@@ -941,6 +941,35 @@ void SmartAI::PassengerBoarded(Unit* who, int8 seatId, bool apply)
void SmartAI::InitializeAI()
{
GetScript()->OnInitialize(me);
+
+ for (SmartScriptHolder const& event : GetScript()->GetEvents())
+ {
+ if (event.GetActionType() != SMART_ACTION_CAST)
+ continue;
+
+ if (!(event.action.cast.castFlags & SMARTCAST_MAIN_SPELL))
+ continue;
+
+ SetMainSpell(event.action.cast.spell);
+ break;
+ }
+
+ // Fallback: use first SMARTCAST_COMBAT_MOVE if no MAIN_SPELL found
+ if (!_currentRangeMode)
+ {
+ for (SmartScriptHolder const& event : GetScript()->GetEvents())
+ {
+ if (event.GetActionType() != SMART_ACTION_CAST)
+ continue;
+
+ if (!(event.action.cast.castFlags & SMARTCAST_COMBAT_MOVE))
+ continue;
+
+ SetMainSpell(event.action.cast.spell);
+ break;
+ }
+ }
+
if (!me->isDead())
{
mJustReset = true;
@@ -1083,6 +1112,20 @@ void SmartAI::SetCurrentRangeMode(bool on, float range)
me->GetMotionMaster()->MoveChase(victim, _attackDistance);
}
+void SmartAI::SetMainSpell(uint32 spellId)
+{
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
+ if (!spellInfo)
+ return;
+
+ float maxRange = spellInfo->GetMaxRange(false);
+ if (maxRange <= NOMINAL_MELEE_RANGE)
+ return;
+
+ _attackDistance = std::max(maxRange - NOMINAL_MELEE_RANGE, 0.0f);
+ _currentRangeMode = true;
+}
+
void SmartAI::DistanceYourself(float range)
{
Unit* victim = me->GetVictim();
diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h
index d6b957cc00..0876336458 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.h
+++ b/src/server/game/AI/SmartScripts/SmartAI.h
@@ -67,6 +67,7 @@ public:
void SetAutoAttack(bool on) { mCanAutoAttack = on; }
void SetCombatMovement(bool on, bool stopOrStartMovement);
void SetCurrentRangeMode(bool on, float range = 0.f);
+ void SetMainSpell(uint32 spellId);
void DistanceYourself(float range);
void SetFollow(Unit* target, float dist = 0.0f, float angle = 0.0f, uint32 credit = 0, uint32 end = 0, uint32 creditType = 0, bool aliveState = true);
void StopFollow(bool complete);
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index e7a5c4fd84..2f66b4ac11 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -707,7 +707,6 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
continue;
}
- // Let us not try to cast spell if we know it is going to fail anyway. Stick to chasing and continue.
if (distanceToTarget > spellMaxRange && isWithinLOSInMap)
{
failedSpellCast = true;
@@ -745,12 +744,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (e.action.cast.castFlags & SMARTCAST_COMBAT_MOVE)
{
- // If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed unless target is outside spell range, out of mana, or LOS.
- if (result == SPELL_FAILED_OUT_OF_RANGE || result == SPELL_CAST_OK)
- // if we are just out of range, we only chase until we are back in spell range.
+ if (result == SPELL_FAILED_OUT_OF_RANGE)
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(true, std::max(spellMaxRange - NOMINAL_MELEE_RANGE, 0.0f));
- else // move into melee on any other fail
- // if spell fail for any other reason, we chase to melee range, or stay where we are if spellcast was successful.
+ else if (result != SPELL_CAST_OK)
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(false, 0.f);
}
diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h
index e0f32438c8..250fdd775a 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.h
+++ b/src/server/game/AI/SmartScripts/SmartScript.h
@@ -207,6 +207,8 @@ public:
void AddCreatureSummon(ObjectGuid const& guid);
void RemoveCreatureSummon(ObjectGuid const& guid);
+ SmartAIEventList const& GetEvents() const { return mEvents; }
+
private:
void IncPhase(uint32 p);
void DecPhase(uint32 p);
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index 5e8e5e9e0c..8dd177dfa6 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -1932,16 +1932,17 @@ enum SmartEventFlags
enum SmartCastFlags
{
- SMARTCAST_INTERRUPT_PREVIOUS = 0x001, // Interrupt any spell casting
- SMARTCAST_TRIGGERED = 0x002, // Triggered (this makes spell cost zero mana and have no cast time)
- //CAST_FORCE_CAST = 0x004, // Forces cast even if creature is out of mana or out of range
- //CAST_NO_MELEE_IF_OOM = 0x008, // Prevents creature from entering melee if out of mana or out of range
- //CAST_FORCE_TARGET_SELF = 0x010, // Forces the target to cast this spell on itself
- SMARTCAST_AURA_NOT_PRESENT = 0x020, // Only casts the spell if the target does not have an aura from the spell
- SMARTCAST_COMBAT_MOVE = 0x040, // Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
- SMARTCAST_THREATLIST_NOT_SINGLE = 0x080, // Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment)
- SMARTCAST_TARGET_POWER_MANA = 0x100, // Only cast if the target has power type mana (e.g. Mana Drain)
- SMARTCAST_ENABLE_COMBAT_MOVE_ON_LOS = 0x200,
+ SMARTCAST_INTERRUPT_PREVIOUS = 0x001, // Interrupt any spell casting
+ SMARTCAST_TRIGGERED = 0x002, // Triggered (this makes spell cost zero mana and have no cast time)
+ //CAST_FORCE_CAST = 0x004, // Forces cast even if creature is out of mana or out of range
+ //CAST_NO_MELEE_IF_OOM = 0x008, // Prevents creature from entering melee if out of mana or out of range
+ //CAST_FORCE_TARGET_SELF = 0x010, // Forces the target to cast this spell on itself
+ SMARTCAST_AURA_NOT_PRESENT = 0x020, // Only casts the spell if the target does not have an aura from the spell
+ SMARTCAST_COMBAT_MOVE = 0x040, // Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
+ SMARTCAST_THREATLIST_NOT_SINGLE = 0x080, // Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment)
+ SMARTCAST_TARGET_POWER_MANA = 0x100, // Only cast if the target has power type mana (e.g. Mana Drain)
+ SMARTCAST_ENABLE_COMBAT_MOVE_ON_LOS = 0x200, // Allows combat movement when not in line of sight
+ SMARTCAST_MAIN_SPELL = 0x400, // Sets this spell's max range as the creature's chase distance on spawn
};
enum SmartFollowType
diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp
index b88d04c65e..b48138a8ba 100644
--- a/src/server/game/DungeonFinding/LFGMgr.cpp
+++ b/src/server/game/DungeonFinding/LFGMgr.cpp
@@ -688,7 +688,7 @@ namespace lfg
// xinef: dont check compatibile dungeons for already running group (bind problems)
if (!isContinue)
{
- GetCompatibleDungeons(dungeons, players, joinData.lockmap);
+ GetCompatibleDungeons(dungeons, players, joinData.lockmap, rDungeonId);
if (dungeons.empty())
joinData.result = grp ? LFG_JOIN_PARTY_NOT_MEET_REQS : LFG_JOIN_NOT_MEET_REQS;
}
@@ -1485,7 +1485,7 @@ namespace lfg
@param[in] players Set of players to check their dungeon restrictions
@param[out] lockMap Map of players Lock status info of given dungeons (Empty if dungeons is not empty)
*/
- void LFGMgr::GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap)
+ void LFGMgr::GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap, bool isRDF)
{
lockMap.clear();
for (LfgGuidSet::const_iterator it = players.begin(); it != players.end() && !dungeons.empty(); ++it)
@@ -1496,6 +1496,9 @@ namespace lfg
{
uint32 dungeonId = (it2->first & 0x00FFFFFF); // Compare dungeon ids
+ if (it2->second == LFG_LOCKSTATUS_RAID_LOCKED && isRDF)
+ continue;
+
LfgDungeonSet::iterator itDungeon = dungeons.find(dungeonId);
if (itDungeon != dungeons.end())
{
@@ -1762,10 +1765,8 @@ namespace lfg
else
{
// RDF removes all binds to that map
- if (randomDungeon && !sInstanceSaveMgr->PlayerIsPermBoundToInstance(player->GetGUID(), dungeon->map, player->GetDungeonDifficulty()))
- {
+ if (randomDungeon)
sInstanceSaveMgr->PlayerUnbindInstance(player->GetGUID(), dungeon->map, player->GetDungeonDifficulty(), true);
- }
}
playersTeleported.push_back(player);
diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h
index 426f0c679a..e52bbda7dd 100644
--- a/src/server/game/DungeonFinding/LFGMgr.h
+++ b/src/server/game/DungeonFinding/LFGMgr.h
@@ -589,7 +589,7 @@ namespace lfg
void DecreaseKicksLeft(ObjectGuid guid);
void SetState(ObjectGuid guid, LfgState state);
void SetCanOverrideRBState(ObjectGuid guid, bool val);
- void GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap);
+ void GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap, bool isRDF = false);
void _SaveToDB(ObjectGuid guid);
LFGDungeonData const* GetLFGDungeon(uint32 id);
diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp
index 5c208f1187..836469a3e8 100644
--- a/src/server/scripts/Northrend/zone_storm_peaks.cpp
+++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp
@@ -915,72 +915,40 @@ public:
}
};
-class npc_hyldsmeet_protodrake : public CreatureScript
+enum HyldsmeetProtoDrake
{
- enum NPCs
- {
- NPC_HYLDSMEET_DRAKERIDER = 29694
- };
+ NPC_HYLDSMEET_DRAKERIDER = 29694
+};
-public:
- npc_hyldsmeet_protodrake() : CreatureScript("npc_hyldsmeet_protodrake") { }
+struct npc_hyldsmeet_protodrake : public CreatureAI
+{
+ explicit npc_hyldsmeet_protodrake(Creature* creature) : CreatureAI(creature), _accessoryRespawnTimer(0) { }
- class npc_hyldsmeet_protodrakeAI : public CreatureAI
+ void PassengerBoarded(Unit* who, int8 /*seat*/, bool apply) override
{
- public:
- npc_hyldsmeet_protodrakeAI(Creature* creature) : CreatureAI(creature), _accessoryRespawnTimer(0), _vehicleKit(creature->GetVehicleKit()) { }
-
- void PassengerBoarded(Unit* who, int8 /*seat*/, bool apply) override
- {
- if (apply)
- {
- class DelayedTransportPositionOffsets : public BasicEvent
- {
- public:
- DelayedTransportPositionOffsets(Unit* owner) : _owner(owner) { }
-
- bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override
- {
- _owner->m_movementInfo.transport.pos.Relocate(-3.5f, 0.f, -0.2f, 0.f);
- return true;
- }
-
- private:
- Unit* _owner;
- };
-
- if (who->IsPlayer())
- who->m_Events.AddEventAtOffset(new DelayedTransportPositionOffsets(who), 500ms);
-
- return;
- }
+ if (apply)
+ return;
- if (who->GetEntry() == NPC_HYLDSMEET_DRAKERIDER)
- _accessoryRespawnTimer = 5 * MINUTE * IN_MILLISECONDS;
- }
+ if (who->GetEntry() == NPC_HYLDSMEET_DRAKERIDER)
+ _accessoryRespawnTimer = 5 * MINUTE * IN_MILLISECONDS;
+ }
- void UpdateAI(uint32 diff) override
+ void UpdateAI(uint32 diff) override
+ {
+ //! We need to manually reinstall accessories because the vehicle itself is friendly to players,
+ //! so EnterEvadeMode is never triggered. The accessory on the other hand is hostile and killable.
+ Vehicle* vehicleKit = me->GetVehicleKit();
+ if (_accessoryRespawnTimer && _accessoryRespawnTimer <= diff && vehicleKit)
{
- //! We need to manually reinstall accessories because the vehicle itself is friendly to players,
- //! so EnterEvadeMode is never triggered. The accessory on the other hand is hostile and killable.
- if (_accessoryRespawnTimer && _accessoryRespawnTimer <= diff && _vehicleKit)
- {
- _vehicleKit->InstallAllAccessories(true);
- _accessoryRespawnTimer = 0;
- }
- else
- _accessoryRespawnTimer -= diff;
+ vehicleKit->InstallAllAccessories(true);
+ _accessoryRespawnTimer = 0;
}
-
- private:
- uint32 _accessoryRespawnTimer;
- Vehicle* _vehicleKit;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return new npc_hyldsmeet_protodrakeAI(creature);
+ else
+ _accessoryRespawnTimer -= diff;
}
+
+private:
+ uint32 _accessoryRespawnTimer;
};
enum CloseRift
@@ -1215,7 +1183,7 @@ void AddSC_storm_peaks()
new npc_brunnhildar_prisoner();
new npc_freed_protodrake();
new npc_icefang();
- new npc_hyldsmeet_protodrake();
+ RegisterCreatureAI(npc_hyldsmeet_protodrake);
RegisterSpellScript(spell_close_rift_aura);
new npc_vehicle_d16_propelled_delivery();
RegisterSpellScript(spell_q12823_remove_collapsing_cave_aura);
diff --git a/src/tools/mmaps_generator/mmaps-config.yaml b/src/tools/mmaps_generator/mmaps-config.yaml
index 2a0aba1fc9..7adcee64cf 100644
--- a/src/tools/mmaps_generator/mmaps-config.yaml
+++ b/src/tools/mmaps_generator/mmaps-config.yaml
@@ -119,6 +119,11 @@ mmapsConfig:
# https://github.com/azerothcore/azerothcore-wotlk/pull/22462#issuecomment-3067024680
walkableSlopeAngle: 45
+ "530": # Outland
+ tilesOverrides:
+ "32,30": # Dark portal
+ walkableSlopeAngle: 45 # https://github.com/chromiecraft/chromiecraft/issues/8404#issuecomment-3476012660
+
# debugOutput generates debug files in the `meshes` directory for use with RecastDemo.
# This is useful for inspecting and debugging mmap generation visually.
#
diff --git a/src/tools/vmap4_extractor/vmapexport.cpp b/src/tools/vmap4_extractor/vmapexport.cpp
index 3b6e5a5be4..52f4983f8d 100644
--- a/src/tools/vmap4_extractor/vmapexport.cpp
+++ b/src/tools/vmap4_extractor/vmapexport.cpp
@@ -144,6 +144,7 @@ bool ExtractSingleWmo(std::string& fname)
WMODoodadData& doodads = WmoDoodads[plain_name];
std::swap(doodads, froot.DoodadData);
int Wmo_nVertices = 0;
+ uint32 groupCount = 0;
//printf("root has %d groups\n", froot->nGroups);
if (froot.nGroups != 0)
{
@@ -170,7 +171,11 @@ bool ExtractSingleWmo(std::string& fname)
break;
}
+ if (fgroup.ShouldSkip(&froot))
+ continue;
+
Wmo_nVertices += fgroup.ConvertToVMAPGroupWmo(output, preciseVectorData);
+ ++groupCount;
for (uint16 groupReference : fgroup.DoodadReferences)
{
if (groupReference >= doodads.Spawns.size())
@@ -187,6 +192,8 @@ bool ExtractSingleWmo(std::string& fname)
fseek(output, 8, SEEK_SET); // store the correct no of vertices
fwrite(&Wmo_nVertices, sizeof(int), 1, output);
+ // store the correct no of groups
+ fwrite(&groupCount, sizeof(uint32), 1, output);
fclose(output);
// Delete the extracted file in the case of an error
diff --git a/src/tools/vmap4_extractor/vmapexport.h b/src/tools/vmap4_extractor/vmapexport.h
index bf0872bfa9..fc84339968 100644
--- a/src/tools/vmap4_extractor/vmapexport.h
+++ b/src/tools/vmap4_extractor/vmapexport.h
@@ -24,8 +24,8 @@
namespace VMAP
{
- const char VMAP_MAGIC[] = "VMAP_4.7";
- const char RAW_VMAP_MAGIC[] = "VMAP047"; // used in extracted vmap files with raw data
+ const char VMAP_MAGIC[] = "VMAP_4.8";
+ const char RAW_VMAP_MAGIC[] = "VMAP048"; // used in extracted vmap files with raw data
}
enum ModelFlags
diff --git a/src/tools/vmap4_extractor/wmo.cpp b/src/tools/vmap4_extractor/wmo.cpp
index 0a25367949..ed20db1196 100644
--- a/src/tools/vmap4_extractor/wmo.cpp
+++ b/src/tools/vmap4_extractor/wmo.cpp
@@ -103,6 +103,11 @@ bool WMORoot::open()
DoodadData.Spawns.resize(size / sizeof(WMO::MODD));
f.read(DoodadData.Spawns.data(), size);
}
+ else if (!strcmp(fourcc, "MOGN"))
+ {
+ GroupNames.resize(size);
+ f.read(GroupNames.data(), size);
+ }
/*
else if (!strcmp(fourcc,"MOTX"))
{
@@ -497,6 +502,22 @@ uint32 WMOGroup::GetLiquidTypeId(uint32 liquidTypeId)
return liquidTypeId;
}
+bool WMOGroup::ShouldSkip(WMORoot const* root) const
+{
+ // skip unreachable
+ if (mogpFlags & 0x80)
+ return true;
+
+ // skip antiportals
+ if (mogpFlags & 0x4000000)
+ return true;
+
+ if (groupName < int32(root->GroupNames.size()) && !strcmp(&root->GroupNames[groupName], "antiportal"))
+ return true;
+
+ return false;
+}
+
WMOGroup::~WMOGroup()
{
delete [] MOPY;
diff --git a/src/tools/vmap4_extractor/wmo.h b/src/tools/vmap4_extractor/wmo.h
index dc44331e32..4d00b11cea 100644
--- a/src/tools/vmap4_extractor/wmo.h
+++ b/src/tools/vmap4_extractor/wmo.h
@@ -85,6 +85,7 @@ public:
float bbcorn1[3];
float bbcorn2[3];
+ std::vector<char> GroupNames;
WMODoodadData DoodadData;
std::unordered_set<uint32> ValidDoodadNames;
@@ -154,6 +155,7 @@ public:
bool open(WMORoot* rootWMO);
int ConvertToVMAPGroupWmo(FILE* output, bool preciseVectorData);
uint32 GetLiquidTypeId(uint32 liquidTypeId);
+ bool ShouldSkip(WMORoot const* root) const;
};
namespace MapObject