Merge branch 'master' into ovv/systemd-socket-activation

This commit is contained in:
Quentin Dawans 2025-07-12 18:51:36 +02:00 committed by GitHub
commit 37e8e2102f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
43 changed files with 993 additions and 417 deletions

View File

@ -1,4 +1,4 @@
name: Codestyle
name: C++ Codestyle
on:
pull_request:
types:

View File

@ -1,4 +1,4 @@
name: Codestyle
name: SQL Codestyle
on:
pull_request:
types:

View File

@ -28,7 +28,8 @@ results = {
"INSERT & DELETE safety usage check": "Passed",
"Missing semicolon check": "Passed",
"Backtick check": "Passed",
"Directory check": "Passed"
"Directory check": "Passed",
"Table engine check": "Passed"
}
# Collect all files in all directories
@ -78,6 +79,7 @@ def parsing_file(files: list) -> None:
insert_delete_safety_check(file, file_path)
semicolon_check(file, file_path)
backtick_check(file, file_path)
non_innodb_engine_check(file, file_path)
except UnicodeDecodeError:
print(f"\n❌ Could not decode file {file_path}")
sys.exit(1)
@ -383,6 +385,25 @@ def directory_check(file: io, file_path: str) -> None:
error_handler = True
results["Directory check"] = "Failed"
def non_innodb_engine_check(file: io, file_path: str) -> None:
global error_handler, results
file.seek(0)
check_failed = False
engine_pattern = re.compile(r'ENGINE\s*=\s*([a-zA-Z0-9_]+)', re.IGNORECASE)
for line_number, line in enumerate(file, start=1):
match = engine_pattern.search(line)
if match:
engine = match.group(1).lower()
if engine != "innodb":
print(f"❌ Non-InnoDB engine found: '{engine}' in {file_path} at line {line_number}")
check_failed = True
if check_failed:
error_handler = True
results["Table engine check"] = "Failed"
# Collect all files from matching directories
all_files = collect_files_from_directories(src_directory) + collect_files_from_directories(base_directory) + collect_files_from_directories(archive_directory)

View File

@ -0,0 +1,3 @@
-- DB update 2025_03_09_00 -> 2025_07_11_00
--
ALTER TABLE `world_state` ENGINE = InnoDB;

View File

@ -0,0 +1,68 @@
-- DB update 2025_07_07_00 -> 2025_07_08_00
-- Set Spell Script
DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_chapter2_persuasive_strike';
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(52781, 'spell_chapter2_persuasive_strike');
-- Remove Flag Stunned from Scarlet Commanders
UPDATE `creature_template` SET `unit_flags` = `unit_flags` &~ 262144 WHERE (`entry` = 28936);
-- Remove c++ script and set SmartAI for Scarlet Crusaders/Preachers/Commanders/Marksmen
UPDATE `creature_template` SET `ScriptName` = '', `AIName` = 'SmartAI' WHERE `entry` IN (28610, 28936, 28939, 28940);
-- Scarlet Commander SmartAI
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 28936) 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
(28936, 0, 0, 0, 0, 0, 100, 0, 4000, 8000, 4000, 8000, 0, 0, 11, 52221, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Commander - In Combat - Cast \'Heroic Strike\'');
-- Scarlet Crusader SmartAI
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 28940) 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
(28940, 0, 0, 0, 0, 0, 100, 0, 4000, 8000, 4000, 8000, 0, 0, 11, 52221, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Crusader - In Combat - Cast \'Heroic Strike\'');
-- Scarlet Marksman SmartAI
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 28610) 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
(28610, 0, 0, 0, 0, 0, 100, 0, 4000, 8000, 4000, 8000, 0, 0, 11, 32915, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Marksman - In Combat - Cast \'Raptor Strike\'');
-- Scarlet Preacher SmartAI
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28939);
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
(28939, 0, 0, 0, 60, 0, 100, 0, 0, 0, 0, 0, 0, 0, 11, 34809, 32, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Preacher - On Update - Cast \'Holy Fury\''),
(28939, 0, 1, 0, 0, 0, 100, 0, 8000, 12000, 8000, 12000, 0, 0, 11, 34809, 33, 0, 1, 0, 0, 26, 10, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Preacher - In Combat - Cast \'Holy Fury\''),
(28939, 0, 2, 0, 0, 0, 100, 0, 0, 0, 2500, 2500, 0, 0, 11, 15498, 64, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Preacher - In Combat - Cast \'Holy Smite\''),
(28939, 0, 3, 0, 0, 0, 100, 0, 6000, 12000, 20000, 25000, 0, 0, 11, 19725, 32, 0, 1, 0, 0, 9, 28897, 0, 20, 1, 0, 0, 0, 0, 'Scarlet Preacher - In Combat - Cast \'Turn Undead\'');
-- Condition for Scarlet Commander
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 17) AND (`SourceGroup` = 0) AND (`SourceEntry` = 52781) AND (`SourceId` = 0) AND (`ElseGroup` = 3) AND (`ConditionTypeOrReference` = 31) AND (`ConditionTarget` = 1) AND (`ConditionValue1` = 3) AND (`ConditionValue2` = 28936) AND (`ConditionValue3` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(17, 0, 52781, 0, 3, 31, 1, 3, 28936, 0, 0, 27, 0, '', 'Persuasive Strike - Scarlet Commander');
-- Condition for Jesseriah McCree
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 17) AND (`SourceGroup` = 0) AND (`SourceEntry` = 52781) AND (`SourceId` = 0) AND (`ElseGroup` = 4) AND (`ConditionTypeOrReference` = 31) AND (`ConditionTarget` = 1) AND (`ConditionValue1` = 3) AND (`ConditionValue2` = 28964) AND (`ConditionValue3` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(17, 0, 52781, 0, 4, 31, 1, 3, 28964, 0, 0, 27, 0, '', 'Persuasive Strike - Scarlet Lord Jesseriah McCree');
-- Add Texts inside McCree's table (for a future implementation).
DELETE FROM `creature_text` WHERE (`CreatureID` = 28964);
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(28964, 1, 0, 'You\'ll be hanging in the gallows shortly, Scourge fiend!', 12, 0, 100, 0, 0, 0, 29160, 0, 'crusader SAY_CURSADER1'),
(28964, 1, 1, 'You\'ll have to kill me, monster. I will tell you NOTHING!', 12, 0, 100, 0, 0, 0, 29142, 0, 'crusader SAY_CURSADER2'),
(28964, 1, 2, 'You hit like a girl. Honestly. Is that the best you can do?', 12, 0, 100, 0, 0, 0, 29146, 0, 'crusader SAY_CURSADER3'),
(28964, 1, 3, 'ARGH! You burned my last good tabard!', 12, 0, 100, 0, 0, 0, 29162, 0, 'crusader SAY_CURSADER4'),
(28964, 1, 4, 'Argh... The pain... The pain is almost as unbearable as the lashings I received in grammar school when I was but a child.', 12, 0, 100, 0, 0, 0, 29143, 0, 'crusader SAY_CURSADER5'),
(28964, 1, 5, 'I used to work for Grand Inquisitor Isillien! Your idea of pain is a normal mid-afternoon for me!', 12, 0, 100, 0, 0, 0, 29161, 0, 'crusader SAY_CURSADER6'),
(28964, 2, 0, 'I\'ll tell you everything! STOP! PLEASE!', 12, 0, 100, 0, 0, 0, 29149, 0, 'break crusader SAY_PERSUADED1'),
(28964, 3, 0, 'We... We have only been told that the "Crimson Dawn" is an awakening. You... You see, the Light speaks to the High General. It is the Light...', 12, 0, 100, 0, 0, 0, 29150, 0, 'break crusader SAY_PERSUADED2'),
(28964, 4, 0, 'The Light that guides us. This movement was set in motion before you came... We... We do as we are told. It is what must be done.', 12, 0, 100, 0, 0, 0, 29151, 0, 'break crusader SAY_PERSUADED3'),
(28964, 5, 0, 'I know very litte else... The High General chooses who may go and who must stay behind. There\'s nothing else... You must believe me!', 12, 0, 100, 0, 0, 0, 29152, 0, 'break crusader SAY_PERSUADED4'),
(28964, 6, 0, 'LIES! The pain you are about to endure will be talked about for years to come!', 12, 0, 100, 0, 0, 0, 29163, 0, 'break crusader SAY_PERSUADED5'),
(28964, 7, 0, 'NO! PLEASE! There is one more thing that I forgot to mention... A courier comes soon... From Hearthglen. It...', 12, 0, 100, 0, 0, 0, 29153, 0, 'break crusader SAY_PERSUADED6'),
(28964, 8, 0, 'I\'ll tear the secrets from your soul! Tell me about the "Crimson Dawn" and your life may be spared!', 12, 0, 100, 0, 0, 0, 29138, 0, 'player SAY_PERSUADE1'),
(28964, 8, 1, 'Tell me what you know about "Crimson Dawn" or the beatings will continue!', 12, 0, 100, 0, 0, 0, 29134, 0, 'player SAY_PERSUADE2'),
(28964, 8, 2, 'I\'m through being courteous with your kind, human! What is the "Crimson Dawn?"', 12, 0, 100, 0, 0, 0, 29135, 0, 'player SAY_PERSUADE3'),
(28964, 8, 3, 'Is your life worth so little? Just tell me what I need to know about "Crimson Dawn" and I\'ll end your suffering quickly.', 12, 0, 100, 0, 0, 0, 29139, 0, 'player SAY_PERSUADE4'),
(28964, 8, 4, 'I can keep this up for a very long time, Scarlet dog! Tell me about the "Crimson Dawn!"', 12, 0, 100, 0, 0, 0, 29137, 0, 'player SAY_PERSUADE'),
(28964, 8, 5, 'What is the "Crimson Dawn?"', 12, 0, 100, 0, 0, 0, 29133, 0, 'player SAY_PERSUADE6'),
(28964, 8, 6, '"Crimson Dawn!" What is it! Speak!', 12, 0, 100, 0, 0, 0, 29136, 0, 'player SAY_PERSUADE7');

View File

@ -0,0 +1,97 @@
-- DB update 2025_07_08_00 -> 2025_07_08_01
DELETE FROM `creature_formations` WHERE `leaderGUID` IN (96764, 96786, 96763, 96776, 96775, 96828, 96825, 96831, 96778, 96777, 96824, 96780, 96767, 96769, 96773, 96779, 96771, 96781);
INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES
(96764, 96764, 0, 0, 3, 0, 0),
(96764, 96765, 0, 0, 3, 0, 0),
(96786, 96786, 0, 0, 515, 0, 0),
(96786, 96814, 2, 270, 515, 0, 0),
(96763, 96763, 0, 0, 3, 0, 0),
(96763, 96788, 0, 0, 3, 0, 0),
(96763, 96801, 0, 0, 3, 0, 0),
(96763, 96816, 0, 0, 3, 0, 0),
(96776, 96776, 0, 0, 3, 0, 0),
(96776, 96787, 0, 0, 3, 0, 0),
(96776, 96799, 0, 0, 3, 0, 0),
(96776, 96815, 0, 0, 3, 0, 0),
(96775, 96775, 0, 0, 3, 0, 0),
(96775, 96813, 0, 0, 3, 0, 0),
(96775, 96797, 0, 0, 3, 0, 0),
(96775, 96785, 0, 0, 3, 0, 0),
(96828, 96828, 0, 0, 3, 0, 0),
(96828, 96834, 0, 0, 3, 0, 0),
(96828, 96829, 0, 0, 3, 0, 0),
(96828, 96833, 0, 0, 3, 0, 0),
(96828, 96837, 0, 0, 3, 0, 0),
(96828, 96838, 0, 0, 3, 0, 0),
(96825, 96825, 0, 0, 3, 0, 0),
(96825, 96830, 0, 0, 3, 0, 0),
(96831, 96831, 0, 0, 3, 0, 0),
(96831, 96832, 0, 0, 3, 0, 0),
(96831, 96826, 0, 0, 3, 0, 0),
(96831, 96836, 0, 0, 3, 0, 0),
(96831, 96827, 0, 0, 3, 0, 0),
(96831, 96835, 0, 0, 3, 0, 0),
(96778, 96778, 0, 0, 3, 0, 0),
(96778, 96805, 0, 0, 3, 0, 0),
(96778, 96768, 0, 0, 3, 0, 0),
(96778, 96843, 0, 0, 3, 0, 0),
(96778, 96789, 0, 0, 3, 0, 0),
(96777, 96777, 0, 0, 3, 0, 0),
(96777, 96802, 0, 0, 3, 0, 0),
(96777, 96766, 0, 0, 3, 0, 0),
(96777, 96817, 0, 0, 3, 0, 0),
(96824, 96824, 0, 0, 3, 0, 0),
(96824, 96774, 0, 0, 3, 0, 0),
(96824, 96796, 0, 0, 3, 0, 0),
(96824, 96812, 0, 0, 3, 0, 0),
(96780, 96780, 0, 0, 3, 0, 0),
(96780, 96808, 0, 0, 3, 0, 0),
(96780, 96849, 0, 0, 3, 0, 0),
(96780, 96791, 0, 0, 3, 0, 0),
(96780, 96846, 0, 0, 3, 0, 0),
(96767, 96767, 0, 0, 3, 0, 0),
(96767, 96839, 0, 0, 3, 0, 0),
(96767, 96803, 0, 0, 3, 0, 0),
(96767, 96818, 0, 0, 3, 0, 0),
(96767, 96842, 0, 0, 3, 0, 0),
(96769, 96769, 0, 0, 3, 0, 0),
(96769, 96806, 0, 0, 3, 0, 0),
(96769, 96820, 0, 0, 3, 0, 0),
(96769, 96840, 0, 0, 3, 0, 0),
(96769, 96844, 0, 0, 3, 0, 0),
(96773, 96773, 0, 0, 3, 0, 0),
(96773, 96784, 0, 0, 3, 0, 0),
(96773, 96811, 0, 0, 3, 0, 0),
(96773, 96795, 0, 0, 3, 0, 0),
(96779, 96779, 0, 0, 3, 0, 0),
(96779, 96848, 0, 0, 3, 0, 0),
(96779, 96807, 0, 0, 3, 0, 0),
(96779, 96790, 0, 0, 3, 0, 0),
(96779, 96845, 0, 0, 3, 0, 0),
(96771, 96771, 0, 0, 3, 0, 0),
(96771, 96810, 0, 0, 3, 0, 0),
(96771, 96793, 0, 0, 3, 0, 0),
(96771, 96821, 0, 0, 3, 0, 0),
(96781, 96781, 0, 0, 3, 0, 0),
(96781, 96850, 0, 0, 3, 0, 0),
(96781, 96847, 0, 0, 3, 0, 0),
(96781, 96770, 0, 0, 3, 0, 0),
(96781, 96809, 0, 0, 3, 0, 0),
(96781, 96841, 0, 0, 3, 0, 0);

View File

@ -0,0 +1,9 @@
-- DB update 2025_07_08_01 -> 2025_07_09_00
-- Edit Spell_Area
UPDATE `spell_area` SET `quest_start` = 12801, `quest_start_status` = `quest_start_status` &~ 10 WHERE `spell` = 58354;
-- Add the second Darion Mograine quest starter
DELETE FROM `creature_queststarter` WHERE (`quest` = 13165) AND (`id` IN (31084));
INSERT INTO `creature_queststarter` (`id`, `quest`) VALUES
(31084, 13165);

View File

@ -0,0 +1,23 @@
-- DB update 2025_07_09_00 -> 2025_07_10_00
-- Set SmartAI
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE (`entry` IN (28610, 28936, 28940, 28939, 28964));
-- Scarlet Commander, Crusader and Marksman.
DELETE FROM `smart_scripts` WHERE (`entryorguid` IN (28610, 28936, 28940)) AND (`source_type` = 0) AND (`id` IN (1));
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
(28610, 0, 1, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 19, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Marksman - On Respawn - Remove Flags Not Attackable'),
(28940, 0, 1, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 19, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Crusader - On Respawn - Remove Flags Not Attackable'),
(28936, 0, 1, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 19, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Commander - On Respawn - Remove Flags Not Attackable');
-- Scarlet Preacher
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 28939) AND (`source_type` = 0) AND (`id` IN (4));
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
(28939, 0, 4, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 19, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Preacher - On Respawn - Remove Flags Not Attackable');
-- Scarlet Lord Jesseriah McCree.
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 28964) 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
(28964, 0, 0, 0, 0, 0, 100, 0, 4000, 8000, 8000, 12000, 0, 0, 11, 52835, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Lord Jesseriah McCree - In Combat - Cast \'Cleave\''),
(28964, 0, 1, 0, 0, 0, 100, 0, 12000, 18000, 30000, 35000, 0, 0, 11, 52836, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Lord Jesseriah McCree - In Combat - Cast \'Holy Wrath\''),
(28964, 0, 2, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 19, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Lord Jesseriah McCree - On Respawn - Remove Flags Not Attackable');

View File

@ -36,6 +36,7 @@ static const unsigned int DT_BUFFER_TOO_SMALL = 1 << 4; // Result buffer for the
static const unsigned int DT_OUT_OF_NODES = 1 << 5; // Query ran out of nodes during search.
static const unsigned int DT_PARTIAL_RESULT = 1 << 6; // Query did not reach the end location, returning best guess.
static const unsigned int DT_ALREADY_OCCUPIED = 1 << 7; // A tile has already been assigned to the given x,y coordinate
static const unsigned int DT_SLOPE_TOO_STEEP = 1 << 8; // Surface slope too steep to be walkable.
// Returns true of status is success.

View File

@ -1419,18 +1419,6 @@ CheckGameObjectLoS = 1
PreloadAllNonInstancedMapGrids = 0
#
# SetAllCreaturesWithWaypointMovementActive
# Description: Set all creatures with waypoint movement active. This means that they will start
# movement once they are loaded (which happens on grid load) and keep moving even
# when no player is near. This will increase CPU usage significantly and can be
# used with enabled "PreloadAllNonInstancedMapGrids" to start waypoint movement on
# server startup.
# Default: 0 - (Disabled)
# 1 - (Enabled)
SetAllCreaturesWithWaypointMovementActive = 0
#
# DontCacheRandomMovementPaths
# Description: Random movement paths (calculated using MoveMaps) can be cached to save cpu time,
@ -3856,11 +3844,18 @@ Arena.QueueAnnouncer.Detail = 3
#
# Arena.ArenaStartRating
# Description: Start rating for new arena teams.
# Description: Start rating for new arena teams. (Applies to season 6 and higher)
# Default: 0
Arena.ArenaStartRating = 0
#
# Arena.LegacyArenaStartRating
# Description: Start rating for new arena teams. (Only applies to season 1 - 5)
# Default: 1500
Arena.LegacyArenaStartRating = 1500
#
# Arena.ArenaStartPersonalRating
# Description: Start personal rating when joining a team.

View File

@ -36,7 +36,9 @@ ArenaTeam::ArenaTeam()
Stats.WeekGames = 0;
Stats.SeasonGames = 0;
Stats.Rank = 0;
Stats.Rating = sWorld->getIntConfig(CONFIG_ARENA_START_RATING);
Stats.Rating = (sArenaSeasonMgr->GetCurrentSeason() < 6)
? sWorld->getIntConfig(CONFIG_LEGACY_ARENA_START_RATING)
: sWorld->getIntConfig(CONFIG_ARENA_START_RATING);
Stats.WeekWins = 0;
Stats.SeasonWins = 0;
}

View File

@ -419,6 +419,9 @@ TeamId BattlegroundAB::GetPrematureWinner()
bool BattlegroundAB::SetupBattleground()
{
_honorTics = BattlegroundMgr::IsBGWeekend(GetBgTypeID(true)) ? BG_AB_HONOR_TICK_WEEKEND : BG_AB_HONOR_TICK_NORMAL;
_reputationTics = BattlegroundMgr::IsBGWeekend(GetBgTypeID(true)) ? BG_AB_REP_TICK_WEEKEND : BG_AB_REP_TICK_NORMAL;
for (uint32 i = 0; i < BG_AB_DYNAMIC_NODES_COUNT; ++i)
{
AddObject(BG_AB_OBJECT_BANNER_NEUTRAL + BG_AB_OBJECTS_PER_NODE * i, BG_AB_OBJECTID_NODE_BANNER_0 + i, BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, std::sin(BG_AB_NodePositions[i][3] / 2), cos(BG_AB_NodePositions[i][3] / 2), RESPAWN_ONE_DAY);
@ -468,9 +471,6 @@ void BattlegroundAB::Init()
_bgEvents.Reset();
_honorTics = BattlegroundMgr::IsBGWeekend(GetBgTypeID(true)) ? BG_AB_HONOR_TICK_WEEKEND : BG_AB_HONOR_TICK_NORMAL;
_reputationTics = BattlegroundMgr::IsBGWeekend(GetBgTypeID(true)) ? BG_AB_REP_TICK_WEEKEND : BG_AB_REP_TICK_NORMAL;
_capturePointInfo[BG_AB_NODE_STABLES]._iconNone = WORLD_STATE_BATTLEGROUND_AB_STABLE_ICON;
_capturePointInfo[BG_AB_NODE_FARM]._iconNone = WORLD_STATE_BATTLEGROUND_AB_FARM_ICON;
_capturePointInfo[BG_AB_NODE_BLACKSMITH]._iconNone = WORLD_STATE_BATTLEGROUND_AB_BLACKSMITH_ICON;

View File

@ -166,7 +166,7 @@ enum BG_AB_Misc
BG_AB_HONOR_TICK_NORMAL = 260,
BG_AB_HONOR_TICK_WEEKEND = 160,
BG_AB_REP_TICK_NORMAL = 160,
BG_AB_REP_TICK_WEEKEND = 120,
BG_AB_REP_TICK_WEEKEND = 150,
BG_AB_WARNING_NEAR_VICTORY_SCORE = 1400,
BG_AB_MAX_TEAM_SCORE = 1600,

View File

@ -16,6 +16,7 @@
*/
#include "BattlegroundAV.h"
#include "BattlegroundMgr.h"
#include "CreatureTextMgr.h"
#include "Formulas.h"
#include "GameEventMgr.h"
@ -56,6 +57,14 @@ BattlegroundAV::BattlegroundAV()
m_Mine_Timer = 0;
_reputationTower = 0;
_reputationCaptain = 0;
_reputationBoss = 0;
_reputationPerOwnedGraveyard = 0;
_reputationSurvivingCaptain = 0;
_reputationSurvivingTower = 0;
_reputationPerOwnedMine = 0;
for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i)
InitNode(i, TEAM_NEUTRAL, false);
@ -93,7 +102,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer)
if (entry == BG_AV_CreatureInfo[AV_NPC_A_BOSS])
{
CastSpellOnTeam(23658, TEAM_HORDE); //this is a spell which finishes a quest where a player has to kill the boss
RewardReputationToTeam(729, BG_AV_REP_BOSS, TEAM_HORDE);
RewardReputationToTeam(729, _reputationBoss, TEAM_HORDE);
RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_BOSS), TEAM_HORDE);
EndBattleground(TEAM_HORDE);
DelCreature(AV_CPLACE_TRIGGER17);
@ -101,7 +110,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer)
else if (entry == BG_AV_CreatureInfo[AV_NPC_H_BOSS])
{
CastSpellOnTeam(23658, TEAM_ALLIANCE); //this is a spell which finishes a quest where a player has to kill the boss
RewardReputationToTeam(730, BG_AV_REP_BOSS, TEAM_ALLIANCE);
RewardReputationToTeam(730, _reputationBoss, TEAM_ALLIANCE);
RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_BOSS), TEAM_ALLIANCE);
EndBattleground(TEAM_ALLIANCE);
DelCreature(AV_CPLACE_TRIGGER19);
@ -114,7 +123,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer)
return;
}
m_CaptainAlive[0] = false;
RewardReputationToTeam(729, BG_AV_REP_CAPTAIN, TEAM_HORDE);
RewardReputationToTeam(729, _reputationCaptain, TEAM_HORDE);
RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_CAPTAIN), TEAM_HORDE);
UpdateScore(TEAM_ALLIANCE, (-1)*BG_AV_RES_CAPTAIN);
//spawn destroyed aura
@ -132,7 +141,7 @@ void BattlegroundAV::HandleKillUnit(Creature* unit, Player* killer)
return;
}
m_CaptainAlive[1] = false;
RewardReputationToTeam(730, BG_AV_REP_CAPTAIN, TEAM_ALLIANCE);
RewardReputationToTeam(730, _reputationCaptain, TEAM_ALLIANCE);
RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_CAPTAIN), TEAM_ALLIANCE);
UpdateScore(TEAM_HORDE, (-1)*BG_AV_RES_CAPTAIN);
//spawn destroyed aura
@ -174,7 +183,7 @@ void BattlegroundAV::HandleQuestComplete(uint32 questid, Player* player)
{
LOG_DEBUG("bg.battleground", "BG_AV Quest {} completed starting with unit upgrading..", questid);
for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i)
if (m_Nodes[i].OwnerId == player->GetTeamId() && m_Nodes[i].State == POINT_CONTROLED)
if (m_Nodes[i].OwnerId == player->GetTeamId() && m_Nodes[i].State == POINT_CONTROLLED)
{
DePopulateNode(i);
PopulateNode(i);
@ -503,29 +512,49 @@ void BattlegroundAV::EndBattleground(TeamId winnerTeamId)
//first towers:
uint8 kills[2] = {0, 0}; // 0 = Alliance 1 = Horde
uint8 rep[2] = {0, 0}; // 0 = Alliance 1 = Horde
if (BattlegroundMgr::IsBGWeekend(GetBgTypeID(true)))
kills[winnerTeamId] += 4;
for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i)
{
if (m_Nodes[i].State == POINT_CONTROLED)
if (m_Nodes[i].State == POINT_CONTROLLED)
{
if (m_Nodes[i].OwnerId == TEAM_ALLIANCE)
{
rep[0] += BG_AV_REP_SURVIVING_TOWER;
kills[0] += BG_AV_KILL_SURVIVING_TOWER;
}
if (m_Nodes[i].OwnerId == TEAM_NEUTRAL)
continue;
else
{
rep[0] += BG_AV_KILL_SURVIVING_TOWER;
kills[1] += BG_AV_KILL_SURVIVING_TOWER;
rep[m_Nodes[i].OwnerId] += _reputationSurvivingTower;
kills[m_Nodes[i].OwnerId] += BG_AV_KILL_SURVIVING_TOWER;
}
}
}
for (uint8 i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i)
{
if (m_Nodes[i].State == POINT_CONTROLLED)
{
if (m_Nodes[i].OwnerId == TEAM_NEUTRAL)
continue;
else
rep[m_Nodes[i].OwnerId] += _reputationPerOwnedGraveyard;
}
}
for (uint8 mine = 0; mine < 2; mine++)
{
if (m_Mine_Owner[mine] == TEAM_NEUTRAL)
continue;
rep[m_Mine_Owner[mine]] += _reputationPerOwnedMine;
}
for (TeamId iTeamId = TEAM_ALLIANCE; iTeamId <= TEAM_HORDE; iTeamId = TeamId(iTeamId + 1))
{
if (m_CaptainAlive[iTeamId])
{
kills[iTeamId] += BG_AV_KILL_SURVIVING_CAPTAIN;
rep[iTeamId] += BG_AV_REP_SURVIVING_CAPTAIN;
rep[iTeamId] += _reputationSurvivingCaptain;
}
if (rep[iTeamId] != 0)
RewardReputationToTeam(iTeamId == TEAM_ALLIANCE ? 730 : 729, rep[iTeamId], iTeamId);
@ -629,7 +658,7 @@ void BattlegroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node)
SpawnBGObject(BG_AV_OBJECT_BURN_DUNBALDAR_SOUTH + i + (tmp * 10), RESPAWN_IMMEDIATELY);
UpdateScore((ownerId == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE, -1 * BG_AV_RES_TOWER);
RewardReputationToTeam(ownerId == TEAM_ALLIANCE ? 730 : 729, BG_AV_REP_TOWER, ownerId);
RewardReputationToTeam(ownerId == TEAM_ALLIANCE ? 730 : 729, _reputationTower, ownerId);
RewardHonorToTeam(GetBonusHonorFromKill(BG_AV_KILL_TOWER), ownerId);
SpawnBGObject(static_cast<uint8>(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH) + ownerId + (2 * tmp), RESPAWN_ONE_DAY);
@ -863,7 +892,7 @@ uint32 BattlegroundAV::GetObjectThroughNode(BG_AV_Nodes node)
if (node >= BG_AV_NODES_ICEBLOOD_TOWER && node <= BG_AV_NODES_FROSTWOLF_WTOWER)
return node + 7;
}
else if (m_Nodes[node].State == POINT_CONTROLED)
else if (m_Nodes[node].State == POINT_CONTROLLED)
if (node <= BG_AV_NODES_STONEHEART_BUNKER)
return node;
}
@ -874,7 +903,7 @@ uint32 BattlegroundAV::GetObjectThroughNode(BG_AV_Nodes node)
if (node <= BG_AV_NODES_STONEHEART_BUNKER)
return node + 22;
}
else if (m_Nodes[node].State == POINT_CONTROLED)
else if (m_Nodes[node].State == POINT_CONTROLLED)
{
if (node <= BG_AV_NODES_FROSTWOLF_HUT)
return node + 33;
@ -1010,7 +1039,7 @@ void BattlegroundAV::EventPlayerAssaultsPoint(Player* player, uint32 object)
}
else if (m_Nodes[node].TotalOwnerId == TEAM_NEUTRAL) //recapping, when no team owns this node realy
{
if (!(m_Nodes[node].State != POINT_CONTROLED))
if (!(m_Nodes[node].State != POINT_CONTROLLED))
return;
if (teamId == TEAM_ALLIANCE)
@ -1138,14 +1167,14 @@ uint8 BattlegroundAV::GetWorldStateType(uint8 state, TeamId teamId) //this is us
//a_c a_a h_c h_a the positions in worldstate-array
if (teamId == TEAM_ALLIANCE)
{
if (state == POINT_CONTROLED || state == POINT_DESTROYED)
if (state == POINT_CONTROLLED || state == POINT_DESTROYED)
return 0;
if (state == POINT_ASSAULTED)
return 1;
}
if (teamId == TEAM_HORDE)
{
if (state == POINT_DESTROYED || state == POINT_CONTROLED)
if (state == POINT_DESTROYED || state == POINT_CONTROLLED)
return 2;
if (state == POINT_ASSAULTED)
return 3;
@ -1193,7 +1222,7 @@ GraveyardStruct const* BattlegroundAV::GetClosestGraveyard(Player* player)
minDist = (pGraveyard->x - x) * (pGraveyard->x - x) + (pGraveyard->y - y) * (pGraveyard->y - y);
for (uint8 i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i)
if (m_Nodes[i].OwnerId == player->GetTeamId() && m_Nodes[i].State == POINT_CONTROLED)
if (m_Nodes[i].OwnerId == player->GetTeamId() && m_Nodes[i].State == POINT_CONTROLLED)
{
entry = sGraveyard->GetGraveyard(BG_AV_GraveyardIds[i]);
if (entry)
@ -1211,6 +1240,27 @@ GraveyardStruct const* BattlegroundAV::GetClosestGraveyard(Player* player)
bool BattlegroundAV::SetupBattleground()
{
if (sBattlegroundMgr->IsBGWeekend(GetBgTypeID(true)))
{
_reputationTower = 18;
_reputationCaptain = 185;
_reputationBoss = 525;
_reputationPerOwnedGraveyard = 18;
_reputationSurvivingCaptain = 175;
_reputationSurvivingTower = 18;
_reputationPerOwnedMine = 36;
}
else
{
_reputationTower = 12;
_reputationCaptain = 125;
_reputationBoss = sWorld->getIntConfig(CONFIG_BATTLEGROUND_ALTERAC_REP_ONBOSSDEATH);
_reputationPerOwnedGraveyard = 12;
_reputationSurvivingCaptain = 125;
_reputationSurvivingTower = 12;
_reputationPerOwnedMine = 24;
}
// Create starting objects
//spawn node-objects
@ -1735,7 +1785,7 @@ void BattlegroundAV::DestroyNode(BG_AV_Nodes node)
m_Nodes[node].TotalOwnerId = m_Nodes[node].OwnerId;
m_Nodes[node].PrevOwnerId = m_Nodes[node].OwnerId;
m_Nodes[node].PrevState = m_Nodes[node].State;
m_Nodes[node].State = (m_Nodes[node].Tower) ? POINT_DESTROYED : POINT_CONTROLED;
m_Nodes[node].State = (m_Nodes[node].Tower) ? POINT_DESTROYED : POINT_CONTROLLED;
m_Nodes[node].Timer = 0;
}
@ -1744,7 +1794,7 @@ void BattlegroundAV::InitNode(BG_AV_Nodes node, TeamId teamId, bool tower)
m_Nodes[node].TotalOwnerId = teamId;
m_Nodes[node].OwnerId = teamId;
m_Nodes[node].PrevOwnerId = TEAM_NEUTRAL;
m_Nodes[node].State = POINT_CONTROLED;
m_Nodes[node].State = POINT_CONTROLLED;
m_Nodes[node].PrevState = m_Nodes[node].State;
m_Nodes[node].Timer = 0;
m_Nodes[node].Tower = tower;
@ -1754,11 +1804,11 @@ void BattlegroundAV::DefendNode(BG_AV_Nodes node, TeamId teamId)
{
ASSERT(m_Nodes[node].TotalOwnerId == teamId);
ASSERT(m_Nodes[node].OwnerId != teamId);
ASSERT(m_Nodes[node].State != POINT_CONTROLED && m_Nodes[node].State != POINT_DESTROYED);
ASSERT(m_Nodes[node].State != POINT_CONTROLLED && m_Nodes[node].State != POINT_DESTROYED);
m_Nodes[node].PrevOwnerId = m_Nodes[node].OwnerId;
m_Nodes[node].OwnerId = teamId;
m_Nodes[node].PrevState = m_Nodes[node].State;
m_Nodes[node].State = POINT_CONTROLED;
m_Nodes[node].State = POINT_CONTROLLED;
m_Nodes[node].Timer = 0;
}
@ -1805,7 +1855,7 @@ bool BattlegroundAV::IsAllTowersControlledAndCaptainAlive(TeamId teamId) const
{
for (BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_STONEHEART_BUNKER; ++i) // alliance towers controlled
{
if (m_Nodes[i].State == POINT_CONTROLED)
if (m_Nodes[i].State == POINT_CONTROLLED)
{
if (m_Nodes[i].OwnerId != TEAM_ALLIANCE)
return false;
@ -1824,7 +1874,7 @@ bool BattlegroundAV::IsAllTowersControlledAndCaptainAlive(TeamId teamId) const
{
for (BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_TOWER; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) // horde towers controlled
{
if (m_Nodes[i].State == POINT_CONTROLED)
if (m_Nodes[i].State == POINT_CONTROLLED)
{
if (m_Nodes[i].OwnerId != TEAM_HORDE)
return false;

View File

@ -29,23 +29,18 @@
#define SEND_MSG_NEAR_LOSE 120
#define BG_AV_KILL_BOSS 4
#define BG_AV_REP_BOSS (sWorld->getIntConfig(CONFIG_BATTLEGROUND_ALTERAC_REP_ONBOSSDEATH)) // Blizzlike default is 350
#define BG_AV_KILL_CAPTAIN 3
#define BG_AV_REP_CAPTAIN 125
#define BG_AV_RES_CAPTAIN 100
#define BG_AV_KILL_TOWER 3
#define BG_AV_REP_TOWER 12
#define BG_AV_RES_TOWER 75
#define BG_AV_GET_COMMANDER 1 //for a safely returned wingcommander
//bonushonor at the end
#define BG_AV_KILL_SURVIVING_TOWER 2
#define BG_AV_REP_SURVIVING_TOWER 12
#define BG_AV_KILL_SURVIVING_CAPTAIN 2
#define BG_AV_REP_SURVIVING_CAPTAIN 125
#define AV_EVENT_START_BATTLE 9166 // Achievement: The Alterac Blitz
@ -1546,7 +1541,7 @@ enum BG_AV_States
POINT_NEUTRAL = 0,
POINT_ASSAULTED = 1,
POINT_DESTROYED = 2,
POINT_CONTROLED = 3
POINT_CONTROLLED = 3
};
//alliance_control neutral_control horde_control
@ -1844,6 +1839,14 @@ private:
uint32 m_CaptainBuffTimer[2] {};
bool m_CaptainAlive[2] {};
uint32 _reputationTower = 0; // 12, 18
uint32 _reputationCaptain = 0; // 125, 185
uint32 _reputationBoss = 0; // 350, 525
uint32 _reputationPerOwnedGraveyard = 0; // 12, 18
uint32 _reputationSurvivingCaptain = 0; // 125, 175
uint32 _reputationSurvivingTower = 0; // 12, 18
uint32 _reputationPerOwnedMine = 0; // 24, 36
bool m_IsInformedNearVictory[2] {};
};

View File

@ -263,6 +263,8 @@ void BattlegroundEY::HandleAreaTrigger(Player* player, uint32 trigger)
bool BattlegroundEY::SetupBattleground()
{
_honorTics = BattlegroundMgr::IsBGWeekend(GetBgTypeID(true)) ? BG_EY_HONOR_TICK_WEEKEND : BG_EY_HONOR_TICK_NORMAL;
// doors
AddObject(BG_EY_OBJECT_DOOR_A, BG_OBJECT_A_DOOR_EY_ENTRY, 2527.6f, 1596.91f, 1262.13f, -3.12414f, -0.173642f, -0.001515f, 0.98477f, -0.008594f, RESPAWN_IMMEDIATELY);
AddObject(BG_EY_OBJECT_DOOR_H, BG_OBJECT_H_DOOR_EY_ENTRY, 1803.21f, 1539.49f, 1261.09f, 3.14159f, 0.173648f, 0, 0.984808f, 0, RESPAWN_IMMEDIATELY);
@ -355,7 +357,6 @@ void BattlegroundEY::Init()
Battleground::Init();
_bgEvents.Reset();
_honorTics = BattlegroundMgr::IsBGWeekend(GetBgTypeID(true)) ? BG_EY_HONOR_TICK_WEEKEND : BG_EY_HONOR_TICK_NORMAL;
_ownedPointsCount[TEAM_ALLIANCE] = 0;
_ownedPointsCount[TEAM_HORDE] = 0;
_flagKeeperGUID.Clear();

View File

@ -426,6 +426,19 @@ void BattlegroundWS::HandleAreaTrigger(Player* player, uint32 trigger)
bool BattlegroundWS::SetupBattleground()
{
if (sBattlegroundMgr->IsBGWeekend(GetBgTypeID(true)))
{
_reputationCapture = 45;
_honorWinKills = 3;
_honorEndKills = 4;
}
else
{
_reputationCapture = 35;
_honorWinKills = 1;
_honorEndKills = 2;
}
// flags
AddObject(BG_WS_OBJECT_A_FLAG, BG_OBJECT_A_FLAG_WS_ENTRY, 1540.423f, 1481.325f, 351.8284f, 3.089233f, 0, 0, 0.9996573f, 0.02617699f, RESPAWN_IMMEDIATELY);
AddObject(BG_WS_OBJECT_H_FLAG, BG_OBJECT_H_FLAG_WS_ENTRY, 916.0226f, 1434.405f, 345.413f, 0.01745329f, 0, 0, 0.008726535f, 0.9999619f, RESPAWN_IMMEDIATELY);
@ -486,19 +499,6 @@ void BattlegroundWS::Init()
_flagState[TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE;
_lastFlagCaptureTeam = TEAM_NEUTRAL;
if (sBattlegroundMgr->IsBGWeekend(GetBgTypeID(true)))
{
_reputationCapture = 45;
_honorWinKills = 3;
_honorEndKills = 4;
}
else
{
_reputationCapture = 35;
_honorWinKills = 1;
_honorEndKills = 2;
}
uint32 bgWarsongFlagsConfig = sWorld->getIntConfig(CONFIG_BATTLEGROUND_WARSONG_FLAGS);
_configurableMaxTeamScore = bgWarsongFlagsConfig > 0
? bgWarsongFlagsConfig

View File

@ -1496,10 +1496,6 @@ namespace lfg
{
uint32 dungeonId = (it2->first & 0x00FFFFFF); // Compare dungeon ids
// Skip faction-specific locks if cross-faction is enabled
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && (it2->second == LFG_LOCKSTATUS_QUEST_NOT_COMPLETED || it2->second == LFG_LOCKSTATUS_MISSING_ITEM))
continue;
LfgDungeonSet::iterator itDungeon = dungeons.find(dungeonId);
if (itDungeon != dungeons.end())
{
@ -2687,24 +2683,17 @@ namespace lfg
LFGQueue& LFGMgr::GetQueue(ObjectGuid guid)
{
uint8 queueId = 0;
if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
if (guid.IsGroup())
{
queueId = TEAM_ALLIANCE;
LfgGuidSet const& players = GetPlayers(guid);
ObjectGuid pguid = players.empty() ? ObjectGuid::Empty : (*players.begin());
if (pguid)
queueId = GetTeam(pguid);
else
queueId = GetTeam(GetLeader(guid));
}
else
{
if (guid.IsGroup())
{
LfgGuidSet const& players = GetPlayers(guid);
ObjectGuid pguid = players.empty() ? ObjectGuid::Empty : (*players.begin());
if (pguid)
queueId = GetTeam(pguid);
else
queueId = GetTeam(GetLeader(guid));
}
else
queueId = GetTeam(guid);
}
queueId = GetTeam(guid);
return QueuesStore[queueId];
}

View File

@ -2772,11 +2772,7 @@ bool Creature::LoadCreaturesAddon(bool reload)
//Load Path
if (cainfo->path_id != 0)
{
if (sWorld->getBoolConfig(CONFIG_SET_ALL_CREATURES_WITH_WAYPOINT_MOVEMENT_ACTIVE))
setActive(true);
m_path_id = cainfo->path_id;
}
if (!cainfo->auras.empty())
{
@ -3896,3 +3892,27 @@ std::string Creature::GetDebugInfo() const
<< " WaypointPath: " << GetWaypointPath() << " SpawnId: " << GetSpawnId();
return sstr.str();
}
// Note: This is called in a tight (heavy) loop, is it critical that all checks are FAST and are hopefully only simple conditionals.
bool Creature::IsUpdateNeeded()
{
if (WorldObject::IsUpdateNeeded())
return true;
if (GetMap()->isCellMarked(GetCurrentCell().GetCellCoord().GetId()))
return true;
if (IsInCombat())
return true;
if (IsVisibilityOverridden())
return true;
if (GetMotionMaster()->HasMovementGeneratorType(WAYPOINT_MOTION_TYPE))
return true;
if (HasUnitState(UNIT_STATE_EVADE))
return true;
return false;
}

View File

@ -39,7 +39,7 @@ class CreatureGroup;
#define MAX_VENDOR_ITEMS 150 // Limitation in 3.x.x item count in SMSG_LIST_INVENTORY
class Creature : public Unit, public GridObject<Creature>, public MovableMapObject
class Creature : public Unit, public GridObject<Creature>, public MovableMapObject, public UpdatableMapObject
{
public:
explicit Creature(bool isWorldObject = false);
@ -436,6 +436,8 @@ public:
std::string GetDebugInfo() const override;
bool IsUpdateNeeded() override;
protected:
bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 Entry, uint32 vehId, const CreatureData* data = nullptr);
bool InitEntry(uint32 entry, const CreatureData* data = nullptr);

View File

@ -31,7 +31,7 @@ enum DynamicObjectType
DYNAMIC_OBJECT_FARSIGHT_FOCUS = 0x2,
};
class DynamicObject : public WorldObject, public GridObject<DynamicObject>, public MovableMapObject
class DynamicObject : public WorldObject, public GridObject<DynamicObject>, public MovableMapObject, public UpdatableMapObject
{
public:
DynamicObject(bool isWorldObject);

View File

@ -3076,3 +3076,21 @@ std::string GameObject::GetDebugInfo() const
<< "SpawnId: " << GetSpawnId() << " GoState: " << std::to_string(GetGoState()) << " ScriptId: " << GetScriptId() << " AIName: " << GetAIName();
return sstr.str();
}
// Note: This is called in a tight (heavy) loop, is it critical that all checks are FAST and are hopefully only simple conditionals.
bool GameObject::IsUpdateNeeded()
{
if (WorldObject::IsUpdateNeeded())
return true;
if (GetMap()->isCellMarked(GetCurrentCell().GetCellCoord().GetId()))
return true;
if (IsVisibilityOverridden())
return true;
if (IsTransport())
return true;
return false;
}

View File

@ -116,7 +116,7 @@ enum LootState
// 5 sec for bobber catch
#define FISHING_BOBBER_READY_TIME 5
class GameObject : public WorldObject, public GridObject<GameObject>, public MovableMapObject
class GameObject : public WorldObject, public GridObject<GameObject>, public MovableMapObject, public UpdatableMapObject
{
public:
explicit GameObject();
@ -362,6 +362,8 @@ public:
void SaveStateToDB();
std::string GetDebugInfo() const override;
bool IsUpdateNeeded() override;
protected:
bool AIM_Initialize();
GameObjectModel* CreateModel();

View File

@ -1188,6 +1188,7 @@ void WorldObject::AddToWorld()
{
Object::AddToWorld();
GetMap()->GetZoneAndAreaId(GetPhaseMask(), _zoneId, _areaId, GetPositionX(), GetPositionY(), GetPositionZ());
GetMap()->AddObjectToPendingUpdateList(this);
}
void WorldObject::RemoveFromWorld()
@ -3220,3 +3221,27 @@ void WorldObject::RemoveAllowedLooter(ObjectGuid guid)
{
_allowedLooters.erase(guid);
}
bool WorldObject::IsUpdateNeeded()
{
if (isActiveObject())
return true;
return false;
}
bool WorldObject::CanBeAddedToMapUpdateList()
{
switch (GetTypeId())
{
case TYPEID_UNIT:
return IsCreature();
case TYPEID_DYNAMICOBJECT:
case TYPEID_GAMEOBJECT:
return true;
default:
return false;
}
return false;
}

View File

@ -230,6 +230,12 @@ public:
DataMap CustomData;
template<typename... T>
[[nodiscard]] bool EntryEquals(T... entries) const
{
return ((GetEntry() == entries) || ...);
}
protected:
Object();
@ -399,14 +405,58 @@ class MovableMapObject
protected:
MovableMapObject() = default;
private:
[[nodiscard]] Cell const& GetCurrentCell() const { return _currentCell; }
private:
void SetCurrentCell(Cell const& cell) { _currentCell = cell; }
Cell _currentCell;
MapObjectCellMoveState _moveState{MAP_OBJECT_CELL_MOVE_NONE};
};
class UpdatableMapObject
{
friend class Map;
public:
enum UpdateState : uint8
{
NotUpdating,
PendingAdd,
Updating
};
protected:
UpdatableMapObject() : _mapUpdateListOffset(0), _mapUpdateState(NotUpdating) { }
private:
void SetMapUpdateListOffset(std::size_t const offset)
{
ASSERT(_mapUpdateState == Updating, "Attempted to set update list offset when object is not in map update list");
_mapUpdateListOffset = offset;
}
size_t GetMapUpdateListOffset() const
{
ASSERT(_mapUpdateState == Updating, "Attempted to get update list offset when object is not in map update list");
return _mapUpdateListOffset;
}
void SetUpdateState(UpdateState state)
{
_mapUpdateState = state;
}
UpdateState GetUpdateState() const
{
return _mapUpdateState;
}
private:
std::size_t _mapUpdateListOffset;
UpdateState _mapUpdateState;
};
class WorldObject : public Object, public WorldLocation
{
protected:
@ -633,6 +683,9 @@ public:
[[nodiscard]] GuidUnorderedSet const& GetAllowedLooters() const;
void RemoveAllowedLooter(ObjectGuid guid);
virtual bool IsUpdateNeeded();
bool CanBeAddedToMapUpdateList();
std::string GetDebugInfo() const override;
// Event handler

View File

@ -1683,6 +1683,8 @@ template <class T>
void Player::UpdateVisibilityOf(T* target, UpdateData& data,
std::vector<Unit*>& visibleNow)
{
GetMap()->AddObjectToPendingUpdateList(target);
if (HaveAtClient(target))
{
if (!CanSeeOrDetect(target, false, true))

View File

@ -13730,7 +13730,7 @@ void Unit::CombatStart(Unit* victim, bool initialAggro)
victim->SetInCombatWith(this);
// Update leash timer when attacking creatures
if (victim->IsCreature())
if (victim->IsCreature() && this != victim)
victim->ToCreature()->UpdateLeashExtensionTime();
// Xinef: If pet started combat - put owner in combat

View File

@ -116,6 +116,9 @@ void GridObjectUnloader::Visit(GridRefMgr<T>& m)
//Example: Flame Leviathan Turret 33139 is summoned when a creature is deleted
//TODO: Check if that script has the correct logic. Do we really need to summons something before deleting?
obj->CleanupsBeforeDelete();
obj->GetMap()->RemoveObjectFromMapUpdateList(obj);
///- object will get delinked from the manager when deleted
delete obj;
}

View File

@ -354,19 +354,6 @@ void MessageDistDelivererToHostile::Visit(DynamicObjectMapType& m)
}
}
template<class T>
void ObjectUpdater::Visit(GridRefMgr<T>& m)
{
T* obj;
for (typename GridRefMgr<T>::iterator iter = m.begin(); iter != m.end(); )
{
obj = iter->GetSource();
++iter;
if (obj->IsInWorld() && (i_largeOnly == obj->IsVisibilityOverridden()))
obj->Update(i_timeDiff);
}
}
bool AnyDeadUnitObjectInRangeCheck::operator()(Player* u)
{
return !u->IsAlive() && !u->HasGhostAura() && i_searchObj->IsWithinDistInMap(u, i_range);
@ -396,7 +383,3 @@ bool AnyDeadUnitSpellTargetInRangeCheck::operator()(Creature* u)
{
return AnyDeadUnitObjectInRangeCheck::operator()(u) && i_check(u);
}
template void ObjectUpdater::Visit<Creature>(CreatureMapType&);
template void ObjectUpdater::Visit<GameObject>(GameObjectMapType&);
template void ObjectUpdater::Visit<DynamicObject>(DynamicObjectMapType&);

View File

@ -154,16 +154,6 @@ namespace Acore
}
};
struct ObjectUpdater
{
uint32 i_timeDiff;
bool i_largeOnly;
explicit ObjectUpdater(const uint32 diff, bool largeOnly) : i_timeDiff(diff), i_largeOnly(largeOnly) {}
template<class T> void Visit(GridRefMgr<T>& m);
void Visit(PlayerMapType&) {}
void Visit(CorpseMapType&) {}
};
// SEARCHERS & LIST SEARCHERS & WORKERS
// WorldObject searchers & workers

View File

@ -51,7 +51,7 @@ void GroupMgr::InitGroupIds()
}
}
void GroupMgr::RegisterGroupId(uint32 groupId)
void GroupMgr::RegisterGroupId(ObjectGuid::LowType groupId)
{
// Allocation was done in InitGroupIds()
_groupIds[groupId] = true;

View File

@ -385,7 +385,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData)
bool senderIsPlayer = AccountMgr::IsPlayerAccount(GetSecurity());
bool receiverIsPlayer = AccountMgr::IsPlayerAccount(receiver ? receiver->GetSession()->GetSecurity() : SEC_PLAYER);
if (sender->GetLevel() < sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ) && receiver != sender)
if (sender->GetLevel() < sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ) && receiver != sender && receiver && !receiver->IsGameMaster())
{
ChatHandler(this).SendNotification(LANG_WHISPER_REQ, sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ));
return;

View File

@ -80,6 +80,7 @@ Map::Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent) :
m_parentMap = (_parent ? _parent : this);
_zonePlayerCountMap.clear();
_updatableObjectListRecheckTimer.SetInterval(UPDATABLE_OBJECT_LIST_RECHECK_TIMER);
//lets initialize visibility distance for map
Map::InitVisibilityDistance();
@ -492,45 +493,7 @@ bool Map::AddToMap(MotionTransport* obj, bool /*checkTransport*/)
return true;
}
void Map::VisitNearbyCellsOfPlayer(Player* player, TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& gridVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& worldVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& largeGridVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& largeWorldVisitor)
{
// check for valid position
if (!player->IsPositionValid())
return;
// check normal grid activation range of the player
VisitNearbyCellsOf(player, gridVisitor, worldVisitor, largeGridVisitor, largeWorldVisitor);
// check maximum visibility distance for large creatures
CellArea area = Cell::CalculateCellArea(player->GetPositionX(), player->GetPositionY(), MAX_VISIBILITY_DISTANCE);
for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
{
for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
{
// marked cells are those that have been visited
// don't visit the same cell twice
uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
if (isCellMarkedLarge(cell_id))
continue;
markCellLarge(cell_id);
CellCoord pair(x, y);
Cell cell(pair);
Visit(cell, largeGridVisitor);
Visit(cell, largeWorldVisitor);
}
}
}
void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& gridVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& worldVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& largeGridVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& largeWorldVisitor)
void Map::MarkNearbyCellsOf(WorldObject* obj)
{
// Check for valid position
if (!obj->IsPositionValid())
@ -538,30 +501,13 @@ void Map::VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Acore::Objec
// Update mobs/objects in ALL visible cells around object!
CellArea area = Cell::CalculateCellArea(obj->GetPositionX(), obj->GetPositionY(), obj->GetGridActivationRange());
for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
{
for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
{
// marked cells are those that have been visited
// don't visit the same cell twice
uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
if (isCellMarked(cell_id))
continue;
markCell(cell_id);
CellCoord pair(x, y);
Cell cell(pair);
Visit(cell, gridVisitor);
Visit(cell, worldVisitor);
if (!isCellMarkedLarge(cell_id))
{
markCellLarge(cell_id);
Visit(cell, largeGridVisitor);
Visit(cell, largeWorldVisitor);
}
}
}
}
@ -613,39 +559,10 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
return;
}
/// update active cells around players and active objects
_updatableObjectListRecheckTimer.Update(t_diff);
resetMarkedCells();
resetMarkedCellsLarge();
// Prepare object updaters
Acore::ObjectUpdater updater(t_diff, false);
// For creature
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer> grid_object_update(updater);
// For pets
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer> world_object_update(updater);
// For large creatures
Acore::ObjectUpdater largeObjectUpdater(t_diff, true);
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer> grid_large_object_update(largeObjectUpdater);
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer> world_large_object_update(largeObjectUpdater);
// pussywizard: container for far creatures in combat with players
std::vector<Creature*> updateList;
updateList.reserve(10);
// Update non-player active objects
for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end();)
{
WorldObject* obj = *m_activeNonPlayersIter;
++m_activeNonPlayersIter;
if (obj && obj->IsInWorld())
VisitNearbyCellsOf(obj, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
}
// Update players and their associated objects
// Update players
for (m_mapRefIter = m_mapRefMgr.begin(); m_mapRefIter != m_mapRefMgr.end(); ++m_mapRefIter)
{
Player* player = m_mapRefIter->GetSource();
@ -654,53 +571,37 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
continue;
player->Update(s_diff);
VisitNearbyCellsOfPlayer(player, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
// If player is using far sight, update viewpoint
if (WorldObject* viewPoint = player->GetViewpoint())
if (_updatableObjectListRecheckTimer.Passed())
{
if (Creature* viewCreature = viewPoint->ToCreature())
{
VisitNearbyCellsOf(viewCreature, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
}
else if (DynamicObject* viewObject = viewPoint->ToDynObject())
{
VisitNearbyCellsOf(viewObject, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
}
}
MarkNearbyCellsOf(player);
// handle updates for creatures in combat with player and are more than X yards away
if (player->IsInCombat())
{
updateList.clear();
float rangeSq = player->GetGridActivationRange() - 1.0f;
rangeSq *= rangeSq;
HostileReference* ref = player->getHostileRefMgr().getFirst();
while (ref)
// If player is using far sight, update viewpoint
if (WorldObject* viewPoint = player->GetViewpoint())
{
if (Unit* unit = ref->GetSource()->GetOwner())
if (Creature* cre = unit->ToCreature())
if (cre->FindMap() == player->FindMap() && cre->GetExactDist2dSq(player) > rangeSq)
updateList.push_back(cre);
ref = ref->next();
if (Creature* viewCreature = viewPoint->ToCreature())
MarkNearbyCellsOf(viewCreature);
else if (DynamicObject* viewObject = viewPoint->ToDynObject())
MarkNearbyCellsOf(viewObject);
}
for (Creature* cre : updateList)
VisitNearbyCellsOf(cre, grid_object_update, world_object_update, grid_large_object_update, world_large_object_update);
}
}
// Update transports - pussywizard: transports updated after VisitNearbyCellsOf, grids around are loaded, everything ok
for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();)
if (_updatableObjectListRecheckTimer.Passed())
{
MotionTransport* transport = *_transportsUpdateIter;
++_transportsUpdateIter;
// Mark all cells near active objects
for (m_activeNonPlayersIter = m_activeNonPlayers.begin(); m_activeNonPlayersIter != m_activeNonPlayers.end(); ++m_activeNonPlayersIter)
{
WorldObject* obj = *m_activeNonPlayersIter;
if (!obj || !obj->IsInWorld())
continue;
if (transport->IsInWorld())
transport->Update(t_diff);
MarkNearbyCellsOf(obj);
}
}
UpdateNonPlayerObjects(t_diff);
SendObjectUpdates();
///- Process necessary scripts
@ -728,6 +629,101 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
METRIC_TAG("map_instanceid", std::to_string(GetInstanceId())));
}
void Map::UpdateNonPlayerObjects(uint32 const diff)
{
for (WorldObject* obj : _pendingAddUpdatableObjectList)
_AddObjectToUpdateList(obj);
_pendingAddUpdatableObjectList.clear();
if (_updatableObjectListRecheckTimer.Passed())
{
for (uint32 i = 0; i < _updatableObjectList.size();)
{
WorldObject* obj = _updatableObjectList[i];
if (!obj->IsInWorld())
{
++i;
continue;
}
obj->Update(diff);
if (!obj->IsUpdateNeeded())
{
_RemoveObjectFromUpdateList(obj);
// Intentional no iteration here, obj is swapped with last element in
// _updatableObjectList so next loop will update that object at the same index
}
else
++i;
}
_updatableObjectListRecheckTimer.Reset();
}
else
{
for (uint32 i = 0; i < _updatableObjectList.size(); ++i)
{
WorldObject* obj = _updatableObjectList[i];
if (!obj->IsInWorld())
continue;
obj->Update(diff);
}
}
}
void Map::AddObjectToPendingUpdateList(WorldObject* obj)
{
if (!obj->CanBeAddedToMapUpdateList())
return;
UpdatableMapObject* mapUpdatableObject = dynamic_cast<UpdatableMapObject*>(obj);
if (mapUpdatableObject->GetUpdateState() != UpdatableMapObject::UpdateState::NotUpdating)
return;
_pendingAddUpdatableObjectList.insert(obj);
mapUpdatableObject->SetUpdateState(UpdatableMapObject::UpdateState::PendingAdd);
}
// Internal use only
void Map::_AddObjectToUpdateList(WorldObject* obj)
{
UpdatableMapObject* mapUpdatableObject = dynamic_cast<UpdatableMapObject*>(obj);
ASSERT(mapUpdatableObject && mapUpdatableObject->GetUpdateState() == UpdatableMapObject::UpdateState::PendingAdd);
mapUpdatableObject->SetUpdateState(UpdatableMapObject::UpdateState::Updating);
mapUpdatableObject->SetMapUpdateListOffset(_updatableObjectList.size());
_updatableObjectList.push_back(obj);
}
// Internal use only
void Map::_RemoveObjectFromUpdateList(WorldObject* obj)
{
UpdatableMapObject* mapUpdatableObject = dynamic_cast<UpdatableMapObject*>(obj);
ASSERT(mapUpdatableObject && mapUpdatableObject->GetUpdateState() == UpdatableMapObject::UpdateState::Updating);
if (obj != _updatableObjectList.back())
{
dynamic_cast<UpdatableMapObject*>(_updatableObjectList.back())->SetMapUpdateListOffset(mapUpdatableObject->GetMapUpdateListOffset());
std::swap(_updatableObjectList[mapUpdatableObject->GetMapUpdateListOffset()], _updatableObjectList.back());
}
_updatableObjectList.pop_back();
mapUpdatableObject->SetUpdateState(UpdatableMapObject::UpdateState::NotUpdating);
}
void Map::RemoveObjectFromMapUpdateList(WorldObject* obj)
{
if (!obj->CanBeAddedToMapUpdateList())
return;
UpdatableMapObject* mapUpdatableObject = dynamic_cast<UpdatableMapObject*>(obj);
if (mapUpdatableObject->GetUpdateState() == UpdatableMapObject::UpdateState::PendingAdd)
_pendingAddUpdatableObjectList.erase(obj);
else if (mapUpdatableObject->GetUpdateState() == UpdatableMapObject::UpdateState::Updating)
_RemoveObjectFromUpdateList(obj);
}
void Map::HandleDelayedVisibility()
{
if (i_objectsForDelayedVisibility.empty())
@ -795,7 +791,10 @@ void Map::RemoveFromMap(T* obj, bool remove)
obj->ResetMap();
if (remove)
{
RemoveObjectFromMapUpdateList(obj);
DeleteFromWorld(obj);
}
}
template<>
@ -831,6 +830,10 @@ void Map::RemoveFromMap(MotionTransport* obj, bool remove)
obj->ResetMap();
// Transports are never actually deleted, but it *should* be safe to clear
// from update list when removing from world
RemoveObjectFromMapUpdateList(obj);
if (remove)
{
// if option set then object already saved at this moment

View File

@ -34,6 +34,7 @@
#include "Position.h"
#include "SharedDefines.h"
#include "TaskScheduler.h"
#include "Timer.h"
#include "GridTerrainData.h"
#include <bitset>
#include <list>
@ -85,6 +86,7 @@ struct ScriptAction
#define DEFAULT_HEIGHT_SEARCH 50.0f // default search distance to find height at nearby locations
#define MIN_UNLOAD_DELAY 1 // immediate unload
#define UPDATABLE_OBJECT_LIST_RECHECK_TIMER 30 * IN_MILLISECONDS // Time to recheck update object list
struct PositionFullTerrainStatus
{
@ -181,14 +183,7 @@ public:
template<class T> bool AddToMap(T*, bool checkTransport = false);
template<class T> void RemoveFromMap(T*, bool);
void VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& gridVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& worldVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& largeGridVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& largeWorldVisitor);
void VisitNearbyCellsOfPlayer(Player* player, TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& gridVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& worldVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, GridTypeMapContainer>& largeGridVisitor,
TypeContainerVisitor<Acore::ObjectUpdater, WorldTypeMapContainer>& largeWorldVisitor);
void MarkNearbyCellsOf(WorldObject* obj);
virtual void Update(const uint32, const uint32, bool thread = true);
@ -317,9 +312,6 @@ public:
void resetMarkedCells() { marked_cells.reset(); }
bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); }
void markCell(uint32 pCellId) { marked_cells.set(pCellId); }
void resetMarkedCellsLarge() { marked_cells_large.reset(); }
bool isCellMarkedLarge(uint32 pCellId) { return marked_cells_large.test(pCellId); }
void markCellLarge(uint32 pCellId) { marked_cells_large.set(pCellId); }
[[nodiscard]] bool HavePlayers() const { return !m_mapRefMgr.IsEmpty(); }
[[nodiscard]] uint32 GetPlayersCountExceptGMs() const;
@ -512,6 +504,12 @@ public:
uint32 GetCreatedCellsInGridCount(uint16 const x, uint16 const y);
uint32 GetCreatedCellsInMapCount();
void AddObjectToPendingUpdateList(WorldObject* obj);
void RemoveObjectFromMapUpdateList(WorldObject* obj);
typedef std::vector<WorldObject*> UpdatableObjectList;
typedef std::unordered_set<WorldObject*> PendingAddUpdatableObjectList;
private:
template<class T> void InitializeObject(T* obj);
@ -576,7 +574,6 @@ private:
Map* m_parentMap;
std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP * TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells;
std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP * TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells_large;
bool i_scriptLock;
std::unordered_set<WorldObject*> i_objectsToRemove;
@ -610,6 +607,11 @@ private:
m_activeNonPlayers.erase(obj);
}
void UpdateNonPlayerObjects(uint32 const diff);
void _AddObjectToUpdateList(WorldObject* obj);
void _RemoveObjectFromUpdateList(WorldObject* obj);
std::unordered_map<ObjectGuid::LowType /*dbGUID*/, time_t> _creatureRespawnTimes;
std::unordered_map<ObjectGuid::LowType /*dbGUID*/, time_t> _goRespawnTimes;
@ -637,6 +639,10 @@ private:
std::unordered_set<Corpse*> _corpseBones;
std::unordered_set<Object*> _updateObjects;
UpdatableObjectList _updatableObjectList;
PendingAddUpdatableObjectList _pendingAddUpdatableObjectList;
IntervalTimer _updatableObjectListRecheckTimer;
};
enum InstanceResetMethod

View File

@ -926,6 +926,20 @@ MovementGeneratorType MotionMaster::GetMotionSlotType(int slot) const
return Impl[slot]->GetMovementGeneratorType();
}
bool MotionMaster::HasMovementGeneratorType(MovementGeneratorType type) const
{
if (empty() && type == IDLE_MOTION_TYPE)
return true;
for (int i = _top; i >= 0; --i)
{
if (Impl[i] && Impl[i]->GetMovementGeneratorType() == type)
return true;
}
return false;
}
// Xinef: Escort system
uint32 MotionMaster::GetCurrentSplineId() const
{

View File

@ -240,6 +240,7 @@ public:
[[nodiscard]] MovementGeneratorType GetCurrentMovementGeneratorType() const;
[[nodiscard]] MovementGeneratorType GetMotionSlotType(int slot) const;
bool HasMovementGeneratorType(MovementGeneratorType type) const;
[[nodiscard]] uint32 GetCurrentSplineId() const; // Xinef: Escort system
void propagateSpeedChange();

View File

@ -137,9 +137,12 @@ void FleeingMovementGenerator<T>::SetTargetLocation(T* owner)
_path->Clear();
}
if (owner->IsPlayer())
_path->SetSlopeCheck(true);
_path->SetPathLengthLimit(30.0f);
bool result = _path->CalculatePath(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ());
if (!result || (_path->GetPathType() & PathType(PATHFIND_NOPATH | PATHFIND_SHORTCUT | PATHFIND_FARFROMPOLY)))
if (!result || (_path->GetPathType() & PathType(PATHFIND_NOPATH | PATHFIND_SHORTCUT | PATHFIND_FARFROMPOLY | PATHFIND_NOT_USING_PATH)))
{
_timer.Reset(100);
return;

View File

@ -564,6 +564,22 @@ void PathGenerator::BuildPointPath(const float* startPoint, const float* endPoin
}
else if (pointCount < 2 || dtStatusFailed(dtResult))
{
// If its too steep, just return incomplete path.
if (pointCount > 0 && dtResult & DT_SLOPE_TOO_STEEP)
{
_pathPoints.resize(pointCount);
for (uint32 i = 0; i < pointCount; ++i)
_pathPoints[i] = G3D::Vector3(pathPoints[i * VERTEX_SIZE + 2], pathPoints[i * VERTEX_SIZE], pathPoints[i * VERTEX_SIZE + 1]);
NormalizePath();
// first point is always our current location - we need the next one
SetActualEndPosition(_pathPoints[pointCount - 1]);
_type = PathType(_type | PATHFIND_INCOMPLETE);
return;
}
// only happens if pass bad data to findStraightPath or navmesh is broken
// single point paths can be generated here
/// @todo check the exact cases
@ -884,7 +900,9 @@ dtStatus PathGenerator::FindSmoothPath(float const* startPos, float const* endPo
if (canCheckSlope && !IsSwimmableSegment(iterPos, steerPos) && !IsWalkableClimb(iterPos, steerPos))
{
return DT_FAILURE;
nsmoothPath--;
*smoothPathSize = nsmoothPath;
return DT_FAILURE | DT_SLOPE_TOO_STEEP;
}
// Handle end of path and off-mesh links when close enough.

View File

@ -443,6 +443,7 @@ void WorldConfig::BuildConfigCache()
SetConfigValue<uint32>(CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS, "Arena.AutoDistributeInterval", 7);
SetConfigValue<uint32>(CONFIG_ARENA_GAMES_REQUIRED, "Arena.GamesRequired", 10);
SetConfigValue<uint32>(CONFIG_ARENA_START_RATING, "Arena.ArenaStartRating", 0);
SetConfigValue<uint32>(CONFIG_LEGACY_ARENA_START_RATING, "Arena.LegacyArenaStartRating", 1500);
SetConfigValue<uint32>(CONFIG_LEGACY_ARENA_POINTS_CALC, "Arena.LegacyArenaPoints", 0);
SetConfigValue<uint32>(CONFIG_ARENA_START_PERSONAL_RATING, "Arena.ArenaStartPersonalRating", 0);
SetConfigValue<uint32>(CONFIG_ARENA_START_MATCHMAKER_RATING, "Arena.ArenaStartMatchmakerRating", 1500);

View File

@ -281,6 +281,7 @@ enum ServerConfigs
CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS,
CONFIG_ARENA_GAMES_REQUIRED,
CONFIG_ARENA_START_RATING,
CONFIG_LEGACY_ARENA_START_RATING,
CONFIG_LEGACY_ARENA_POINTS_CALC,
CONFIG_ARENA_START_PERSONAL_RATING,
CONFIG_ARENA_START_MATCHMAKER_RATING,

View File

@ -28,161 +28,6 @@
#include "ObjectAccessor.h"
#include <limits>
//How to win friends and influence enemies
// texts signed for creature 28939 but used for 28939, 28940, 28610
enum win_friends
{
SAY_AGGRO = 0,
SAY_CRUSADER = 1,
SAY_PERSUADED1 = 2,
SAY_PERSUADED2 = 3,
SAY_PERSUADED3 = 4,
SAY_PERSUADED4 = 5,
SAY_PERSUADED5 = 6,
SAY_PERSUADED6 = 7,
SAY_PERSUADE_RAND = 8,
SPELL_PERSUASIVE_STRIKE = 52781,
SPELL_THREAT_PULSE = 58111,
QUEST_HOW_TO_WIN_FRIENDS = 12720,
};
class npc_crusade_persuaded : public CreatureScript
{
public:
npc_crusade_persuaded() : CreatureScript("npc_crusade_persuaded") { }
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_crusade_persuadedAI(creature);
}
struct npc_crusade_persuadedAI : public CombatAI
{
npc_crusade_persuadedAI(Creature* creature) : CombatAI(creature) { }
const uint32 SAY_AGGRO_CHANCE = 33;
const uint32 PERSUADE_SUCCESS_CHANCE = 3; // 30% chance
const uint32 SPEECH_TIMER_DEFAULT = 1000;
const uint32 SPEECH_TIMER_FOR_ROLEPLAY = 8000;
const uint32 SPEECH_COUNTER_PREVENT_SUCCESS_ROLEPLAY = 0;
const uint32 SPEECH_COUNTER_START_SUCCESS_ROLEPLAY = 1;
uint32 speechTimer;
uint32 speechCounter;
ObjectGuid playerGUID;
bool persuaded;
void Reset() override
{
speechTimer = 0;
speechCounter = SPEECH_COUNTER_PREVENT_SUCCESS_ROLEPLAY;
playerGUID.Clear();
me->SetReactState(REACT_AGGRESSIVE);
me->RestoreFaction();
}
void JustEngagedWith(Unit*) override
{
if (roll_chance_i(SAY_AGGRO_CHANCE))
Talk(SAY_AGGRO);
}
void SpellHit(Unit* caster, SpellInfo const* spell) override
{
if (spell->Id == SPELL_PERSUASIVE_STRIKE && caster->IsPlayer() && me->IsAlive() && !speechCounter)
{
if (Player* player = caster->ToPlayer())
{
playerGUID = player->GetGUID();
speechTimer = SPEECH_TIMER_DEFAULT;
speechCounter = SPEECH_COUNTER_START_SUCCESS_ROLEPLAY;
uint32 persuadeRoll = urand(1, 10);
sCreatureTextMgr->SendChat(me, SAY_PERSUADE_RAND, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_NEUTRAL, false, player);
if (persuadeRoll <= PERSUADE_SUCCESS_CHANCE && player->GetQuestStatus(QUEST_HOW_TO_WIN_FRIENDS) == QUEST_STATUS_INCOMPLETE)
{
persuaded = true;
me->SetFaction(player->GetFaction());
me->CombatStop(true);
me->GetMotionMaster()->MoveIdle();
me->SetReactState(REACT_PASSIVE);
}
else
persuaded = false;
}
}
}
void UpdateAI(uint32 diff) override
{
if (speechCounter)
{
if (speechTimer <= diff)
{
Player* player = ObjectAccessor::GetPlayer(*me, playerGUID);
if (!player)
{
EnterEvadeMode();
return;
}
if (persuaded)
{
switch (speechCounter)
{
case 1:
Talk(SAY_PERSUADED1);
speechTimer = SPEECH_TIMER_FOR_ROLEPLAY;
break;
case 2:
Talk(SAY_PERSUADED2);
speechTimer = SPEECH_TIMER_FOR_ROLEPLAY;
break;
case 3:
Talk(SAY_PERSUADED3);
speechTimer = SPEECH_TIMER_FOR_ROLEPLAY;
break;
case 4:
Talk(SAY_PERSUADED4);
speechTimer = SPEECH_TIMER_FOR_ROLEPLAY;
break;
case 5:
sCreatureTextMgr->SendChat(me, SAY_PERSUADED5, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_NEUTRAL, false, player);
speechTimer = SPEECH_TIMER_FOR_ROLEPLAY;
break;
case 6:
Talk(SAY_PERSUADED6);
Unit::Kill(player, me);
speechCounter = SPEECH_COUNTER_PREVENT_SUCCESS_ROLEPLAY;
player->GroupEventHappens(QUEST_HOW_TO_WIN_FRIENDS, me);
return;
}
++speechCounter;
}
else
{
Talk(SAY_CRUSADER);
speechCounter = SPEECH_COUNTER_PREVENT_SUCCESS_ROLEPLAY;
}
}
else
speechTimer = (speechTimer > diff) ? (speechTimer - diff) : 0;
return;
}
CombatAI::UpdateAI(diff);
}
};
};
/*######
## npc_koltira_deathweaver
######*/
@ -1098,12 +943,96 @@ public:
}
};
//How to win friends and influence enemies
// texts signed for creature 28939 but used for 28939, 28940, 28610
enum win_friends
{
SAY_CRUSADER = 1,
SAY_PERSUADED1 = 2,
SAY_PERSUADED2 = 3,
SAY_PERSUADED3 = 4,
SAY_PERSUADED4 = 5,
SAY_PERSUADED5 = 6,
SAY_PERSUADED6 = 7,
SAY_PERSUADE_RAND = 8,
QUEST_HOW_TO_WIN_FRIENDS = 12720,
NPC_SCARLET_PREACHER = 28939,
NPC_SCARLET_COMMANDER = 28936,
NPC_SCARLET_CRUSADER = 28940,
NPC_SCARLET_MARKSMAN = 28610,
NPC_SCARLET_LORD_MCCREE = 28964
};
// 52781 - Persuasive Strike
class spell_chapter2_persuasive_strike : public SpellScript
{
PrepareSpellScript(spell_chapter2_persuasive_strike);
bool Load() override
{
return GetCaster() && GetCaster()->IsPlayer()
&& GetCaster()->ToPlayer()->GetQuestStatus(QUEST_HOW_TO_WIN_FRIENDS) == QUEST_STATUS_INCOMPLETE;
}
void HandleHit(SpellEffIndex /*effIndex*/)
{
Creature* creature = GetHitCreature();
Player* player = GetCaster()->ToPlayer();
if (!creature || !player)
return;
if (!creature->EntryEquals(NPC_SCARLET_PREACHER, NPC_SCARLET_COMMANDER, NPC_SCARLET_CRUSADER, NPC_SCARLET_MARKSMAN, NPC_SCARLET_LORD_MCCREE))
return;
sCreatureTextMgr->SendChat(creature, SAY_PERSUADE_RAND, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_NEUTRAL, false, player);
if (roll_chance_f(30.0f))
{
creature->CombatStop(true);
creature->GetMotionMaster()->MoveIdle();
creature->SetImmuneToPC(true);
creature->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
creature->SetReactState(REACT_PASSIVE);
creature->AI()->Talk(SAY_PERSUADED1, 8s);
creature->AI()->Talk(SAY_PERSUADED2, 16s);
creature->AI()->Talk(SAY_PERSUADED3, 24s);
creature->AI()->Talk(SAY_PERSUADED4, 32s);
creature->m_Events.AddEventAtOffset([creature, player]
{
if (player)
sCreatureTextMgr->SendChat(creature, SAY_PERSUADED5, nullptr, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_NEUTRAL, false, player);
}, 40s);
creature->m_Events.AddEventAtOffset([creature, player]
{
creature->AI()->Talk(SAY_PERSUADED6);
if (player)
{
Unit::Kill(player, creature);
player->GroupEventHappens(QUEST_HOW_TO_WIN_FRIENDS, creature);
}
}, 48s);
}
else
creature->AI()->Talk(SAY_CRUSADER, 1s);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_chapter2_persuasive_strike::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
void AddSC_the_scarlet_enclave_c2()
{
new npc_crusade_persuaded();
new npc_scarlet_courier();
new npc_koltira_deathweaver();
new npc_a_special_surprise();
new npc_acherus_necromancer();
new npc_gothik_the_harvester();
RegisterSpellScript(spell_chapter2_persuasive_strike);
}

View File

@ -548,6 +548,7 @@ public:
summons.DespawnAll();
me->SetImmuneToAll(true);
me->LoadEquipment(1, true);
me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_GOSSIP | UNIT_NPC_FLAG_QUESTGIVER);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetVisible(true);

View File

@ -2726,6 +2726,245 @@ enum CreatureTypeFlags
CREATURE_TYPE_FLAG_QUEST_BOSS = 0x80000000 // Not verified
};
enum class CreatureStaticFlags : uint32
{
MOUNTABLE = 0x00000001,
NO_XP = 0x00000002,
NO_LOOT = 0x00000004,
UNKILLABLE = 0x00000008,
TAMEABLE = 0x00000010, // CREATURE_TYPE_FLAG_TAMEABLE
IMMUNE_TO_PC = 0x00000020, // UNIT_FLAG_IMMUNE_TO_PC
IMMUNE_TO_NPC = 0x00000040, // UNIT_FLAG_IMMUNE_TO_NPC
CAN_WIELD_LOOT = 0x00000080,
SESSILE = 0x00000100, // creature_template_movement.Rooted = 1
UNINTERACTIBLE = 0x00000200, // UNIT_FLAG_UNINTERACTIBLE
NO_AUTOMATIC_REGEN = 0x00000400, // Creatures with that flag uses no UNIT_FLAG2_REGENERATE_POWER
DESPAWN_INSTANTLY = 0x00000800, // Creature instantly disappear when killed
CORPSE_RAID = 0x00001000,
CREATOR_LOOT = 0x00002000, // Lootable only by creator(engineering dummies)
NO_DEFENSE = 0x00004000,
NO_SPELL_DEFENSE = 0x00008000,
BOSS_MOB = 0x00010000, // CREATURE_TYPE_FLAG_BOSS_MOB, original description: Raid Boss Mob
COMBAT_PING = 0x00020000,
AQUATIC = 0x00040000, // aka Water Only, creature_template_movement.Ground = 0
AMPHIBIOUS = 0x00080000, // creature_template_movement.Swim = 1
NO_MELEE_FLEE = 0x00100000, // Prevents melee and makes npc flee if it enters combat - also misused to just prevent melee on npcs that cant move
VISIBLE_TO_GHOSTS = 0x00200000, // CREATURE_TYPE_FLAG_VISIBLE_TO_GHOSTS
PVP_ENABLING = 0x00400000, // Old UNIT_FLAG_PVP_ENABLING, now UNIT_BYTES_2_OFFSET_PVP_FLAG from UNIT_FIELD_BYTES_2
DO_NOT_PLAY_WOUND_ANIM = 0x00800000, // CREATURE_TYPE_FLAG_DO_NOT_PLAY_WOUND_ANIM
NO_FACTION_TOOLTIP = 0x01000000, // CREATURE_TYPE_FLAG_NO_FACTION_TOOLTIP
IGNORE_COMBAT = 0x02000000, // Actually only changes react state to passive
ONLY_ATTACK_PVP_ENABLING = 0x04000000, // "Only attack targets that are PvP enabling"
CALLS_GUARDS = 0x08000000, // Creature will summon a guard if player is within its aggro range (even if creature doesn't attack per se)
CAN_SWIM = 0x10000000, // UnitFlags 0x8000 UNIT_FLAG_CAN_SWIM
FLOATING = 0x20000000, // creature_template_movement.Flight = 1
MORE_AUDIBLE = 0x40000000, // CREATURE_TYPE_FLAG_MORE_AUDIBLE
LARGE_AOI = 0x80000000 // UnitFlags2 0x200000
};
enum class CreatureStaticFlags2 : uint32
{
NO_PET_SCALING = 0x00000001,
FORCE_PARTY_MEMBERS_INTO_COMBAT = 0x00000002, // Original description: Force Raid Combat
LOCK_TAPPERS_TO_RAID_ON_DEATH = 0x00000004, // "Lock Tappers To Raid On Death", toggleable by 'Set "RAID_LOCK_ON_DEATH" flag for unit(s)' action, CREATURE_FLAG_EXTRA_INSTANCE_BIND
SPELL_ATTACKABLE = 0x00000008, // CREATURE_TYPE_FLAG_SPELL_ATTACKABLE, original description(not valid anymore?): No Harmful Vertex Coloring
NO_CRUSHING_BLOWS = 0x00000010,
NO_OWNER_THREAT = 0x00000020,
NO_WOUNDED_SLOWDOWN = 0x00000040,
USE_CREATOR_BONUSES = 0x00000080,
IGNORE_FEIGN_DEATH = 0x00000100,
IGNORE_SANCTUARY = 0x00000200,
ACTION_TRIGGERS_WHILE_CHARMED = 0x00000400,
INTERACT_WHILE_DEAD = 0x00000800, // CREATURE_TYPE_FLAG_INTERACT_WHILE_DEAD
NO_INTERRUPT_SCHOOL_COOLDOWN = 0x00001000,
RETURN_SOUL_SHARD_TO_MASTER_OF_PET = 0x00002000,
SKIN_WITH_HERBALISM = 0x00004000, // CREATURE_TYPE_FLAG_SKIN_WITH_HERBALISM
SKIN_WITH_MINING = 0x00008000, // CREATURE_TYPE_FLAG_SKIN_WITH_MINING
ALERT_CONTENT_TEAM_ON_DEATH = 0x00010000,
ALERT_CONTENT_TEAM_AT_90_PCT_HP = 0x00020000,
ALLOW_MOUNTED_COMBAT = 0x00040000, // CREATURE_TYPE_FLAG_ALLOW_MOUNTED_COMBAT
PVP_ENABLING_OOC = 0x00080000,
NO_DEATH_MESSAGE = 0x00100000, // CREATURE_TYPE_FLAG_NO_DEATH_MESSAGE
IGNORE_PATHING_FAILURE = 0x00200000,
FULL_SPELL_LIST = 0x00400000,
DOES_NOT_REDUCE_REPUTATION_FOR_RAIDS = 0x00800000,
IGNORE_MISDIRECTION = 0x01000000,
HIDE_BODY = 0x02000000, // UNIT_FLAG2_HIDE_BODY
SPAWN_DEFENSIVE = 0x04000000,
SERVER_ONLY = 0x08000000,
CAN_SAFE_FALL = 0x10000000, // Original description: No Collision
CAN_ASSIST = 0x20000000, // CREATURE_TYPE_FLAG_CAN_ASSIST, original description: Player Can Heal/Buff
NO_SKILL_GAINS = 0x40000000,
NO_PET_BAR = 0x80000000 // CREATURE_TYPE_FLAG_NO_PET_BAR
};
enum class CreatureStaticFlags3 : uint32
{
NO_DAMAGE_HISTORY = 0x00000001,
DONT_PVP_ENABLE_OWNER = 0x00000002,
DO_NOT_FADE_IN = 0x00000004, // UNIT_FLAG2_DO_NOT_FADE_IN
MASK_UID = 0x00000008, // CREATURE_TYPE_FLAG_MASK_UID, original description: Non-Unique In Combat Log
SKIN_WITH_ENGINEERING = 0x00000010, // CREATURE_TYPE_FLAG_SKIN_WITH_ENGINEERING
NO_AGGRO_ON_LEASH = 0x00000020,
NO_FRIENDLY_AREA_AURAS = 0x00000040,
EXTENDED_CORPSE_DURATION = 0x00000080,
CANNOT_SWIM = 0x00000100, // UNIT_FLAG_CANNOT_SWIM
TAMEABLE_EXOTIC = 0x00000200, // CREATURE_TYPE_FLAG_TAMEABLE_EXOTIC
GIGANTIC_AOI = 0x00000400, // Since MoP, creatures with that flag have UnitFlags2 0x400000
INFINITE_AOI = 0x00000800, // Since MoP, creatures with that flag have UnitFlags2 0x40000000
CANNOT_PENETRATE_WATER = 0x00001000, // Waterwalking
NO_NAME_PLATE = 0x00002000, // CREATURE_TYPE_FLAG_NO_NAME_PLATE
CHECKS_LIQUIDS = 0x00004000,
NO_THREAT_FEEDBACK = 0x00008000,
USE_MODEL_COLLISION_SIZE = 0x00010000, // CREATURE_TYPE_FLAG_USE_MODEL_COLLISION_SIZE
ATTACKER_IGNORES_FACING = 0x00020000, // In 3.3.5 used only by Rocket Propelled Warhead
ALLOW_INTERACTION_WHILE_IN_COMBAT = 0x00040000, // CREATURE_TYPE_FLAG_ALLOW_INTERACTION_WHILE_IN_COMBAT
SPELL_CLICK_FOR_PARTY_ONLY = 0x00080000,
FACTION_LEADER = 0x00100000,
IMMUNE_TO_PLAYER_BUFFS = 0x00200000,
COLLIDE_WITH_MISSILES = 0x00400000, // CREATURE_TYPE_FLAG_COLLIDE_WITH_MISSILES
CAN_BE_MULTITAPPED = 0x00800000, // Original description: Do Not Tap (Credit to threat list)
DO_NOT_PLAY_MOUNTED_ANIMATIONS = 0x01000000, // CREATURE_TYPE_FLAG_DO_NOT_PLAY_MOUNTED_ANIMATIONS, original description: Disable Dodge, Parry and Block Animations
CANNOT_TURN = 0x02000000, // UNIT_FLAG2_CANNOT_TURN
ENEMY_CHECK_IGNORES_LOS = 0x04000000,
FOREVER_CORPSE_DURATION = 0x08000000, // 7 days
PETS_ATTACK_WITH_3D_PATHING = 0x10000000, // "Pets attack with 3d pathing (Kologarn)"
LINK_ALL = 0x20000000, // CREATURE_TYPE_FLAG_LINK_ALL
AI_CAN_AUTO_TAKEOFF_IN_COMBAT = 0x40000000,
AI_CAN_AUTO_LAND_IN_COMBAT = 0x80000000
};
enum class CreatureStaticFlags4 : uint32
{
NO_BIRTH_ANIM = 0x00000001, // SMSG_UPDATE_OBJECT's "NoBirthAnim"
TREAT_AS_PLAYER_FOR_DIMINISHING_RETURNS = 0x00000002, // Primarily used by ToC champions
TREAT_AS_PLAYER_FOR_PVP_DEBUFF_DURATION = 0x00000004, // Primarily used by ToC champions
INTERACT_ONLY_WITH_CREATOR = 0x00000008, // CREATURE_TYPE_FLAG_INTERACT_ONLY_WITH_CREATOR, original description: Only Display Gossip for Summoner
DO_NOT_PLAY_UNIT_EVENT_SOUNDS = 0x00000010, // CREATURE_TYPE_FLAG_DO_NOT_PLAY_UNIT_EVENT_SOUNDS, original description: No Death Scream
HAS_NO_SHADOW_BLOB = 0x00000020, // CREATURE_TYPE_FLAG_HAS_NO_SHADOW_BLOB, original description(wrongly linked type flag or behavior was changed?): Can be Healed by Enemies
DEALS_TRIPLE_DAMAGE_TO_PC_CONTROLLED_PETS = 0x00000040,
NO_NPC_DAMAGE_BELOW_85PTC = 0x00000080,
OBEYS_TAUNT_DIMINISHING_RETURNS = 0x00000100, // CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS
NO_MELEE_APPROACH = 0x00000200,
UPDATE_CREATURE_RECORD_WHEN_INSTANCE_CHANGES_DIFFICULTY = 0x00000400, // Used only by Snobold Vassal
CANNOT_DAZE = 0x00000800, // "Cannot Daze (Combat Stun)"
FLAT_HONOR_AWARD = 0x00001000,
IGNORE_LOS_WHEN_CASTING_ON_ME = 0x00002000, // "Other objects can ignore line of sight requirements when casting spells on me", used only by Ice Tomb in 3.3.5
GIVE_QUEST_KILL_CREDIT_WHILE_OFFLINE = 0x00004000,
TREAT_AS_RAID_UNIT_FOR_HELPFUL_SPELLS = 0x00008000, // CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT, "Treat as Raid Unit For Helpful Spells (Instances ONLY)", used by Valithria Dreamwalker
DONT_REPOSITION_IF_MELEE_TARGET_IS_TOO_CLOSE = 0x00010000, // "Don't reposition because melee target is too close"
PET_OR_GUARDIAN_AI_DONT_GO_BEHIND_TARGET = 0x00020000,
MINUTE_5_LOOT_ROLL_TIMER = 0x00040000, // Used by Lich King
FORCE_GOSSIP = 0x00080000, // CREATURE_TYPE_FLAG_FORCE_GOSSIP
DONT_REPOSITION_WITH_FRIENDS_IN_COMBAT = 0x00100000,
DO_NOT_SHEATHE = 0x00200000, // CREATURE_TYPE_FLAG_DO_NOT_SHEATHE, original description: Manual Sheathing control
IGNORE_SPELL_MIN_RANGE_RESTRICTIONS = 0x00400000, // UnitFlags2 0x8000000, original description: Attacker Ignores Minimum Ranges
SUPPRESS_INSTANCE_WIDE_RELEASE_IN_COMBAT = 0x00800000,
PREVENT_SWIM = 0x01000000, // UnitFlags2 0x1000000, original description: AI will only swim if target swims
HIDE_IN_COMBAT_LOG = 0x02000000, // UnitFlags2 0x2000000, original description: Don't generate combat log when engaged with NPC's
ALLOW_NPC_COMBAT_WHILE_UNINTERACTIBLE = 0x04000000,
PREFER_NPCS_WHEN_SEARCHING_FOR_ENEMIES = 0x08000000,
ONLY_GENERATE_INITIAL_THREAT = 0x10000000,
DO_NOT_TARGET_ON_INTERACTION = 0x20000000, // CREATURE_TYPE_FLAG_DO_NOT_TARGET_ON_INTERACTION, original description: Doesn't change target on right click
DO_NOT_RENDER_OBJECT_NAME = 0x40000000, // CREATURE_TYPE_FLAG_DO_NOT_RENDER_OBJECT_NAME, original description: Hide name in world frame
QUEST_BOSS = 0x80000000 // CREATURE_TYPE_FLAG_QUEST_BOSS
};
enum class CreatureStaticFlags5 : uint32
{
UNTARGETABLE_BY_CLIENT = 0x00000001, // UnitFlags2 0x4000000 UNIT_FLAG2_UNTARGETABLE_BY_CLIENT
FORCE_SELF_MOUNTING = 0x00000002,
UNINTERACTIBLE_IF_HOSTILE = 0x00000004, // UnitFlags2 0x10000000
DISABLES_XP_AWARD = 0x00000008,
DISABLE_AI_PREDICTION = 0x00000010,
NO_LEAVECOMBAT_STATE_RESTORE = 0x00000020,
BYPASS_INTERACT_INTERRUPTS = 0x00000040,
DEGREE_BACK_ARC_240 = 0x00000080,
INTERACT_WHILE_HOSTILE = 0x00000100, // UnitFlags2 0x4000 UNIT_FLAG2_INTERACT_WHILE_HOSTILE
DONT_DISMISS_ON_FLYING_MOUNT = 0x00000200,
PREDICTIVE_POWER_REGEN = 0x00000400, // CREATURE_TYPEFLAGS_2_UNK1
HIDE_LEVEL_INFO_IN_TOOLTIP = 0x00000800, // CREATURE_TYPEFLAGS_2_UNK2
HIDE_HEALTH_BAR_UNDER_TOOLTIP = 0x00001000, // CREATURE_TYPEFLAGS_2_UNK3
SUPPRESS_HIGHLIGHT_WHEN_TARGETED_OR_MOUSED_OVER = 0x00002000, // UnitFlags2 0x80000
AI_PREFER_PATHABLE_TARGETS = 0x00004000,
FREQUENT_AREA_TRIGGER_CHECKS = 0x00008000,
ASSIGN_KILL_CREDIT_TO_ENCOUNTER_LIST = 0x00010000,
NEVER_EVADE = 0x00020000,
AI_CANT_PATH_ON_STEEP_SLOPES = 0x00040000,
AI_IGNORE_LOS_TO_MELEE_TARGET = 0x00080000,
NO_TEXT_IN_CHAT_BUBBLE = 0x00100000, // "Never display emote or chat text in a chat bubble", CREATURE_TYPEFLAGS_2_UNK4
CLOSE_IN_ON_UNPATHABLE_TARGET = 0x00200000, // "AI Pets close in on unpathable target"
DONT_GO_BEHIND_ME = 0x00400000, // "Pet/Guardian AI Don't Go Behind Me (use on target)"
NO_DEATH_THUD = 0x00800000, // CREATURE_TYPEFLAGS_2_UNK5
CLIENT_LOCAL_CREATURE = 0x01000000,
CAN_DROP_LOOT_WHILE_IN_A_CHALLENGE_MODE_INSTANCE = 0x02000000,
HAS_SAFE_LOCATION = 0x04000000,
NO_HEALTH_REGEN = 0x08000000,
NO_POWER_REGEN = 0x10000000,
NO_PET_UNIT_FRAME = 0x20000000,
NO_INTERACT_ON_LEFT_CLICK = 0x40000000, // CREATURE_TYPEFLAGS_2_UNK6
GIVE_CRITERIA_KILL_CREDIT_WHEN_CHARMED = 0x80000000
};
enum class CreatureStaticFlags6 : uint32
{
DO_NOT_AUTO_RESUMMON = 0x00000001, // "Do not auto-resummon this companion creature"
REPLACE_VISIBLE_UNIT_IF_AVAILABLE = 0x00000002, // "Smooth Phasing: Replace visible unit if available"
IGNORE_REALM_COALESCING_HIDING_CODE = 0x00000004, // "Ignore the realm coalescing hiding code (always show)"
TAPS_TO_FACTION = 0x00000008,
ONLY_QUESTGIVER_FOR_SUMMONER = 0x00000010,
AI_COMBAT_RETURN_PRECISE = 0x00000020,
HOME_REALM_ONLY_LOOT = 0x00000040,
NO_INTERACT_RESPONSE = 0x00000080, // TFLAG2_UNK7
NO_INITIAL_POWER = 0x00000100,
DONT_CANCEL_CHANNEL_ON_MASTER_MOUNTING = 0x00000200,
CAN_TOGGLE_BETWEEN_DEATH_AND_PERSONAL_LOOT = 0x00000400,
ALWAYS_STAND_ON_TOP_OF_TARGET = 0x00000800, // "Always, ALWAYS tries to stand right on top of his move to target. ALWAYS!!", toggleable by 'Set "Always Stand on Target" flag for unit(s)' or not same?
UNCONSCIOUS_ON_DEATH = 0x00001000,
DONT_REPORT_TO_LOCAL_DEFENSE_CHANNEL_ON_DEATH = 0x00002000,
PREFER_UNENGAGED_MONSTERS = 0x00004000, // "Prefer unengaged monsters when picking a target"
USE_PVP_POWER_AND_RESILIENCE = 0x00008000, // "Use PVP power and resilience when players attack this creature"
DONT_CLEAR_DEBUFFS_ON_LEAVE_COMBAT = 0x00010000,
PERSONAL_LOOT_HAS_FULL_SECURITY = 0x00020000, // "Personal loot has full security (guaranteed push/mail delivery)"
TRIPLE_SPELL_VISUALS = 0x00040000,
USE_GARRISON_OWNER_LEVEL = 0x00080000,
IMMEDIATE_AOI_UPDATE_ON_SPAWN = 0x00100000,
UI_CAN_GET_POSITION = 0x00200000,
SEAMLESS_TRANSFER_PROHIBITED = 0x00400000,
ALWAYS_USE_GROUP_LOOT_METHOD = 0x00800000,
NO_BOSS_KILL_BANNER = 0x01000000,
FORCE_TRIGGERING_PLAYER_LOOT_ONLY = 0x02000000,
SHOW_BOSS_FRAME_WHILE_UNINTERACTABLE = 0x04000000,
SCALES_TO_PLAYER_LEVEL = 0x08000000,
AI_DONT_LEAVE_MELEE_FOR_RANGED_WHEN_TARGET_GETS_ROOTED = 0x10000000,
DONT_USE_COMBAT_REACH_FOR_CHAINING = 0x20000000,
DO_NOT_PLAY_PROCEDURAL_WOUND_ANIM = 0x40000000,
APPLY_PROCEDURAL_WOUND_ANIM_TO_BASE = 0x80000000 // TFLAG2_UNK14
};
enum class CreatureStaticFlags7 : uint32
{
IMPORTANT_NPC = 0x00000001,
IMPORTANT_QUEST_NPC = 0x00000002,
LARGE_NAMEPLATE = 0x00000004,
TRIVIAL_PET = 0x00000008,
AI_ENEMIES_DONT_BACKUP_WHEN_I_GET_ROOTED = 0x00000010,
NO_AUTOMATIC_COMBAT_ANCHOR = 0x00000020,
ONLY_TARGETABLE_BY_CREATOR = 0x00000040,
TREAT_AS_PLAYER_FOR_ISPLAYERCONTROLLED = 0x00000080,
GENERATE_NO_THREAT_OR_DAMAGE = 0x00000100,
INTERACT_ONLY_ON_QUEST = 0x00000200,
DISABLE_KILL_CREDIT_FOR_OFFLINE_PLAYERS = 0x00000400,
AI_ADDITIONAL_PATHING = 0x00080000,
};
enum class CreatureStaticFlags8 : uint32
{
FORCE_CLOSE_IN_ON_PATH_FAIL_BEHAVIOR = 0x00000002,
USE_2D_CHASING_CALCULATION = 0x00000020,
USE_FAST_CLASSIC_HEARTBEAT = 0x00000040,
};
enum CreatureEliteType
{
CREATURE_ELITE_NORMAL = 0,