├── .editorconfig ├── .git_commit_template.txt ├── .gitattributes ├── .github └── workflows │ └── core-build.yml ├── .gitignore ├── LICENSE ├── README.md ├── conf ├── conf.sh.dist └── hardmode.conf.dist ├── data └── sql │ ├── db-characters │ ├── base │ │ └── hardmode_world_2023_04_29_01.sql │ └── updates │ │ └── hardmode_world_2023_05_01_01.sql │ └── db-world │ ├── base │ └── hardmode_world_2023_03_31_01.sql │ └── updates │ ├── hardmode_world_2023_04_02_01.sql │ ├── hardmode_world_2023_04_02_02.sql │ ├── hardmode_world_2023_04_02_03.sql │ ├── hardmode_world_2023_04_03_01.sql │ ├── hardmode_world_2023_04_11_01.sql │ ├── hardmode_world_2023_04_18_01.sql │ └── hardmode_world_2023_06_03_01.sql ├── docs ├── bitmask.js ├── index.html ├── logo.png └── style.css ├── include.sh ├── mode-restrictions.txt └── src ├── HardMode.cpp ├── HardMode.h ├── HardModeCommands.cpp ├── HardModeCommands.h ├── HardModeHandler.cpp ├── HardModeHandler.h ├── HardModeHooks ├── HardModeHooksGlobal.cpp ├── HardModeHooksGlobal.h ├── HardModeHooksGuild.cpp ├── HardModeHooksGuild.h ├── HardModeHooksMisc.cpp ├── HardModeHooksMisc.h ├── HardModeHooksPlayer.cpp ├── HardModeHooksPlayer.h ├── HardModeHooksServer.cpp ├── HardModeHooksServer.h ├── HardModeHooksUnit.cpp ├── HardModeHooksUnit.h ├── HardModeHooksWorld.cpp └── HardModeHooksWorld.h ├── HardModeShrineObject.cpp ├── HardModeShrineObject.h ├── HardModeTypes.h └── HardMode_Loader.cpp /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | indent_style = space 4 | indent_size = 4 5 | tab_width = 4 6 | insert_final_newline = true 7 | trim_trailing_whitespace = true 8 | max_line_length = 80 9 | -------------------------------------------------------------------------------- /.git_commit_template.txt: -------------------------------------------------------------------------------- 1 | ### TITLE 2 | ## Type(Scope/Subscope): Commit ultra short explanation 3 | ## |---- Write below the examples with a maximum of 50 characters ----| 4 | ## Example 1: fix(DB/SAI): Missing spell to NPC Hogger 5 | ## Example 2: fix(CORE/Raid): Phase 2 of Ragnaros 6 | ## Example 3: feat(CORE/Commands): New GM command to do something 7 | 8 | ### DESCRIPTION 9 | ## Explain why this change is being made, what does it fix etc... 10 | ## |---- Write below the examples with a maximum of 72 characters per lines ----| 11 | ## Example: Hogger (id: 492) was not charging player when being engaged. 12 | 13 | ## Provide links to any issue, commit, pull request or other resource 14 | ## Example 1: Closes issue #23 15 | ## Example 2: Ported from other project's commit (link) 16 | ## Example 3: References taken from wowpedia / wowhead / wowwiki / https://wowgaming.altervista.org/aowow/ 17 | 18 | ## ======================================================= 19 | ## EXTRA INFOS 20 | ## ======================================================= 21 | ## "Type" can be: 22 | ## feat (new feature) 23 | ## fix (bug fix) 24 | ## refactor (refactoring production code) 25 | ## style (formatting, missing semi colons, etc; no code change) 26 | ## docs (changes to documentation) 27 | ## test (adding or refactoring tests; no production code change) 28 | ## chore (updating bash scripts, git files etc; no production code change) 29 | ## -------------------- 30 | ## Remember to 31 | ## Capitalize the subject line 32 | ## Use the imperative mood in the subject line 33 | ## Do not end the subject line with a period 34 | ## Separate subject from body with a blank line 35 | ## Use the body to explain what and why rather than how 36 | ## Can use multiple lines with "-" for bullet points in body 37 | ## -------------------- 38 | ## More info here https://www.conventionalcommits.org/en/v1.0.0-beta.2/ 39 | ## ======================================================= 40 | ## "Scope" can be: 41 | ## CORE (core related, c++) 42 | ## DB (database related, sql) 43 | ## ======================================================= 44 | ## "Subscope" is optional and depends on the nature of the commit. 45 | ## ======================================================= 46 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ## AUTO-DETECT 2 | ## Handle line endings automatically for files detected as 3 | ## text and leave all files detected as binary untouched. 4 | ## This will handle all files NOT defined below. 5 | * text=auto eol=lf 6 | 7 | # Text 8 | *.conf text 9 | *.conf.dist text 10 | *.cmake text 11 | 12 | ## Scripts 13 | *.sh text 14 | *.fish text 15 | *.lua text 16 | 17 | ## SQL 18 | *.sql text 19 | 20 | ## C++ 21 | *.c text 22 | *.cc text 23 | *.cxx text 24 | *.cpp text 25 | *.c++ text 26 | *.hpp text 27 | *.h text 28 | *.h++ text 29 | *.hh text 30 | 31 | 32 | ## For documentation 33 | 34 | # Documents 35 | *.doc diff=astextplain 36 | *.DOC diff=astextplain 37 | *.docx diff=astextplain 38 | *.DOCX diff=astextplain 39 | *.dot diff=astextplain 40 | *.DOT diff=astextplain 41 | *.pdf diff=astextplain 42 | *.PDF diff=astextplain 43 | *.rtf diff=astextplain 44 | *.RTF diff=astextplain 45 | 46 | ## DOCUMENTATION 47 | *.markdown text 48 | *.md text 49 | *.mdwn text 50 | *.mdown text 51 | *.mkd text 52 | *.mkdn text 53 | *.mdtxt text 54 | *.mdtext text 55 | *.txt text 56 | AUTHORS text 57 | CHANGELOG text 58 | CHANGES text 59 | CONTRIBUTING text 60 | COPYING text 61 | copyright text 62 | *COPYRIGHT* text 63 | INSTALL text 64 | license text 65 | LICENSE text 66 | NEWS text 67 | readme text 68 | *README* text 69 | TODO text 70 | 71 | ## GRAPHICS 72 | *.ai binary 73 | *.bmp binary 74 | *.eps binary 75 | *.gif binary 76 | *.ico binary 77 | *.jng binary 78 | *.jp2 binary 79 | *.jpg binary 80 | *.jpeg binary 81 | *.jpx binary 82 | *.jxr binary 83 | *.pdf binary 84 | *.png binary 85 | *.psb binary 86 | *.psd binary 87 | *.svg text 88 | *.svgz binary 89 | *.tif binary 90 | *.tiff binary 91 | *.wbmp binary 92 | *.webp binary 93 | 94 | 95 | ## ARCHIVES 96 | *.7z binary 97 | *.gz binary 98 | *.jar binary 99 | *.rar binary 100 | *.tar binary 101 | *.zip binary 102 | 103 | ## EXECUTABLES 104 | *.exe binary 105 | *.pyc binary 106 | -------------------------------------------------------------------------------- /.github/workflows/core-build.yml: -------------------------------------------------------------------------------- 1 | name: core-build 2 | on: 3 | push: 4 | pull_request: 5 | workflow_dispatch: 6 | 7 | jobs: 8 | build: 9 | uses: azerothcore/reusable-workflows/.github/workflows/core_build_modules.yml@main 10 | with: 11 | module_repo: ${{ github.event.repository.name }} 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | 3 | # 4 | #Generic 5 | # 6 | 7 | .directory 8 | .mailmap 9 | *.orig 10 | *.rej 11 | *.*~ 12 | .hg/ 13 | *.kdev* 14 | .DS_Store 15 | CMakeLists.txt.user 16 | *.bak 17 | *.patch 18 | *.diff 19 | *.REMOTE.* 20 | *.BACKUP.* 21 | *.BASE.* 22 | *.LOCAL.* 23 | 24 | # 25 | # IDE & other softwares 26 | # 27 | /.settings/ 28 | /.externalToolBuilders/* 29 | # exclude in all levels 30 | nbproject/ 31 | .sync.ffs_db 32 | *.kate-swp 33 | 34 | # 35 | # Eclipse 36 | # 37 | *.pydevproject 38 | .metadata 39 | .gradle 40 | tmp/ 41 | *.tmp 42 | *.swp 43 | *~.nib 44 | local.properties 45 | .settings/ 46 | .loadpath 47 | .project 48 | .cproject 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 AzerothCore 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HardMode 2 | HardMode is a module heavily inspired by [mod-challenge-modes](https://github.com/ZhengPeiRu21/mod-challenge-modes). The purpose of this module is to develop extra functionality with a difference in code architecture. This makes it easier for me to develop on existing or expanding modes. 3 | 4 | This module is still a WIP. 5 | 6 | ## How to add rewards 7 | To add rewards, run mysql and use the world database. 8 | Run the following command and take note of the hardmode_modes id: `SELECT * FROM hardmode_modes;` 9 | Then with each reward you want to give, run the following command: `INSERT INTO hardmode_rewards (mode, reward_level, reward_type, reward_id, reward_count, comment) VALUES (, , , , 'this comment is not used in the game, so suggest to make it the name of the item, title, spell for future reference');` 10 | 11 | example: 12 | ![image](https://github.com/user-attachments/assets/539e6b38-db23-4d91-9cb6-adfd46b5cd87) 13 | ```INSERT INTO hardmode_rewards (mode, reward_level, reward_type, reward_id, reward_count, comment) VALUES (4, 80, 0, 46708, 1, 'Deadly Gladiators Frost Wyrm');``` 14 | ```INSERT INTO hardmode_rewards (mode, reward_level, reward_type, reward_id, reward_count, comment) VALUES (5, 80, 0, 46171, 1, 'Furious Gladiators Frost Wyrm');``` 15 | ```INSERT INTO hardmode_rewards (mode, reward_level, reward_type, reward_id, reward_count, comment) VALUES (6, 80, 0, 47840, 1, 'Relentless Gladiators Frost Wyrm');``` 16 | 17 | ## Features 18 | - Build your own HardModes using the [restriction builder](https://anchydev.github.io/HardMode/#mode-editor). 19 | - Level based rewards for each mode you have created. 20 | - Dynamic auras for each mode. 21 | 22 | ## Database 23 | Head over to my HardMode editor to create your first mode: https://anchydev.github.io/HardMode/#mode-editor 24 | 25 | ## Credits 26 | Thanks to [ZhengPeiRu21](https://github.com/ZhengPeiRu21) for creating the original module which inspired this one. 27 | -------------------------------------------------------------------------------- /conf/conf.sh.dist: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## CUSTOM SQL - Important file used by the db_assembler.sh 4 | ## Keep only the required variables (base sql files or updates, depending on the DB) 5 | 6 | ## BASE SQL 7 | 8 | DB_AUTH_CUSTOM_PATHS+=( 9 | "$MOD_SKELETON_ROOT/sql/auth/base/" 10 | ) 11 | 12 | DB_CHARACTERS_CUSTOM_PATHS+=( 13 | "$MOD_SKELETON_ROOT/sql/characters/base/" 14 | ) 15 | 16 | DB_WORLD_CUSTOM_PATHS+=( 17 | "$MOD_SKELETON_ROOT/sql/world/base/" 18 | ) 19 | 20 | ## UPDATES 21 | 22 | DB_AUTH_UPDATES_PATHS+=( 23 | "$MOD_SKELETON_ROOT/sql/auth/updates/" 24 | ) 25 | 26 | DB_CHARACTERS_UPDATES_PATHS+=( 27 | "$MOD_SKELETON_ROOT/sql/characters/updates/" 28 | ) 29 | 30 | DB_WORLD_UPDATES_PATHS+=( 31 | "$MOD_SKELETON_ROOT/sql/world/updates/" 32 | ) 33 | -------------------------------------------------------------------------------- /conf/hardmode.conf.dist: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 3 | # 4 | 5 | [worldserver] 6 | 7 | ######################################## 8 | # HardMode configuration 9 | ######################################## 10 | # 11 | # HardMode.Enable 12 | # Description: Enables/disables the HardMode modes. 13 | # Default: 0 - Disabled 14 | # 1 - Enabled 15 | # Type: bool 16 | # 17 | 18 | HardMode.Enable = 0 19 | 20 | # 21 | # HardMode.Inspect.Alert 22 | # Description: Alerts the inspecting player of what modes the target has enabled. 23 | # 0 - Disabled 24 | # Default: 1 - Enabled 25 | # Type: bool 26 | # 27 | 28 | HardMode.Inspect.Alert = 1 29 | 30 | # 31 | # HardMode.Restrict.Interact.Group.Range 32 | # Description: The level range that players can group together when under this restriction. 33 | # Default: 3 34 | # Type: uint32 35 | # 36 | 37 | HardMode.Restrict.Interact.Group.Range = 3 38 | 39 | # 40 | # HardMode.Restrict.BadLuck.Chance 41 | # Description: The chance that an item is deleted when under this restriction. 42 | # Note: When an item drops in BadLuck, there is another internal roll, if you fail this roll 43 | # the item is deleted from the loot table. This is what this config is responsible for. 44 | # Default: 10 45 | # Type: uint32 46 | # Range: 0 - 100 47 | # 48 | 49 | HardMode.Restrict.BadLuck.Chance = 10 50 | 51 | # 52 | # HardMode.Restrict.SelfCrafted.CreatedBy 53 | # Description: Items crafted by the player like potions and food with gain a created by tag, allowing self crafted players to use them. 54 | # Note: This will only let players use their own items. 55 | # 0 - Disabled 56 | # Default: 1 - Enabled 57 | # Type: bool 58 | # 59 | 60 | HardMode.Restrict.SelfCrafted.CreatedBy = 1 61 | 62 | # 63 | # HardMode.Restrict.Permadeath.Announce 64 | # Description: Enables the announcement when a permadeath player dies. 65 | # 0 - Disabled 66 | # Default: 1 - Enabled 67 | # Type: bool 68 | # 69 | 70 | HardMode.Restrict.Permadeath.Announce = 1 -------------------------------------------------------------------------------- /data/sql/db-characters/base/hardmode_world_2023_04_29_01.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `hardmode_player_settings`; 2 | CREATE TABLE IF NOT EXISTS `hardmode_player_settings` ( 3 | `guid` int unsigned DEFAULT NULL, 4 | `modes` text COLLATE utf8mb4_general_ci, 5 | `tainted` tinyint DEFAULT NULL, 6 | `shadowban` tinyint DEFAULT NULL 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; 8 | 9 | DELETE FROM `hardmode_player_settings`; -------------------------------------------------------------------------------- /data/sql/db-characters/updates/hardmode_world_2023_05_01_01.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `hardmode_player_settings`; 2 | CREATE TABLE IF NOT EXISTS `hardmode_player_settings` ( 3 | `guid` int unsigned NOT NULL, 4 | `modes` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci, 5 | `tainted` tinyint DEFAULT NULL, 6 | `shadowban` tinyint DEFAULT NULL, 7 | PRIMARY KEY (`guid`) 8 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; 9 | 10 | DELETE FROM `hardmode_player_settings`; 11 | -------------------------------------------------------------------------------- /data/sql/db-world/base/hardmode_world_2023_03_31_01.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `hardmode_rewards`; 2 | CREATE TABLE IF NOT EXISTS `hardmode_rewards` ( 3 | `mode` int(11) NOT NULL, 4 | `reward_type` int(11) NOT NULL, 5 | `reward_id` int(11) NOT NULL, 6 | `reward_count` int(11) DEFAULT NULL, 7 | `comment` varchar(50) DEFAULT NULL, 8 | PRIMARY KEY (`mode`,`reward_type`,`reward_id`) 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; 10 | 11 | -- Prize Handler 12 | -- Used as the sender of the above rewards, you can rename this NPC to change the reward senders name. 13 | DELETE FROM `creature_template` WHERE `entry`=441102; 14 | INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES (441102, 0, 0, 0, 0, 0, 'Prize Handler', '', '', 0, 1, 1, 0, 35, 0, 1, 1.14286, 1, 1, 20, 1, 0, 0, 1, 2000, 2000, 1, 1, 1, 0, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 10314); 15 | 16 | DELETE FROM `creature_template_model` WHERE `CreatureID`=441102 AND `Idx`=0; 17 | INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES (441102, 0, 27104, 1, 1, 1); 18 | 19 | DROP TABLE IF EXISTS `hardmode_selfcraft_exclude`; 20 | CREATE TABLE IF NOT EXISTS `hardmode_selfcraft_exclude` ( 21 | `id` int(11) NOT NULL, 22 | `comment` varchar(50) DEFAULT NULL, 23 | PRIMARY KEY (`id`) 24 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; 25 | 26 | 27 | -- Shrine of Hard Mode 28 | DELETE FROM `gameobject_template` WHERE `entry`=441101; 29 | INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `AIName`, `ScriptName`, `VerifiedBuild`) VALUES (441101, 2, 6925, 'Challenge Shrine', '', '', '', 1.2, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 'HardModeGameObjectScript', 0); 30 | 31 | DELETE FROM `npc_text` WHERE `ID`=441102; 32 | INSERT INTO `npc_text` (`ID`, `text0_0`, `text0_1`, `BroadcastTextID0`, `lang0`, `Probability0`, `em0_0`, `em0_1`, `em0_2`, `em0_3`, `em0_4`, `em0_5`, `text1_0`, `text1_1`, `BroadcastTextID1`, `lang1`, `Probability1`, `em1_0`, `em1_1`, `em1_2`, `em1_3`, `em1_4`, `em1_5`, `text2_0`, `text2_1`, `BroadcastTextID2`, `lang2`, `Probability2`, `em2_0`, `em2_1`, `em2_2`, `em2_3`, `em2_4`, `em2_5`, `text3_0`, `text3_1`, `BroadcastTextID3`, `lang3`, `Probability3`, `em3_0`, `em3_1`, `em3_2`, `em3_3`, `em3_4`, `em3_5`, `text4_0`, `text4_1`, `BroadcastTextID4`, `lang4`, `Probability4`, `em4_0`, `em4_1`, `em4_2`, `em4_3`, `em4_4`, `em4_5`, `text5_0`, `text5_1`, `BroadcastTextID5`, `lang5`, `Probability5`, `em5_0`, `em5_1`, `em5_2`, `em5_3`, `em5_4`, `em5_5`, `text6_0`, `text6_1`, `BroadcastTextID6`, `lang6`, `Probability6`, `em6_0`, `em6_1`, `em6_2`, `em6_3`, `em6_4`, `em6_5`, `text7_0`, `text7_1`, `BroadcastTextID7`, `lang7`, `Probability7`, `em7_0`, `em7_1`, `em7_2`, `em7_3`, `em7_4`, `em7_5`, `VerifiedBuild`) VALUES (441102, 'You are tainted, you can only disable hard modes.', 'You are tainted, you can only disable hard modes.', 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 33 | DELETE FROM `npc_text` WHERE `ID`=441101; 34 | INSERT INTO `npc_text` (`ID`, `text0_0`, `text0_1`, `BroadcastTextID0`, `lang0`, `Probability0`, `em0_0`, `em0_1`, `em0_2`, `em0_3`, `em0_4`, `em0_5`, `text1_0`, `text1_1`, `BroadcastTextID1`, `lang1`, `Probability1`, `em1_0`, `em1_1`, `em1_2`, `em1_3`, `em1_4`, `em1_5`, `text2_0`, `text2_1`, `BroadcastTextID2`, `lang2`, `Probability2`, `em2_0`, `em2_1`, `em2_2`, `em2_3`, `em2_4`, `em2_5`, `text3_0`, `text3_1`, `BroadcastTextID3`, `lang3`, `Probability3`, `em3_0`, `em3_1`, `em3_2`, `em3_3`, `em3_4`, `em3_5`, `text4_0`, `text4_1`, `BroadcastTextID4`, `lang4`, `Probability4`, `em4_0`, `em4_1`, `em4_2`, `em4_3`, `em4_4`, `em4_5`, `text5_0`, `text5_1`, `BroadcastTextID5`, `lang5`, `Probability5`, `em5_0`, `em5_1`, `em5_2`, `em5_3`, `em5_4`, `em5_5`, `text6_0`, `text6_1`, `BroadcastTextID6`, `lang6`, `Probability6`, `em6_0`, `em6_1`, `em6_2`, `em6_3`, `em6_4`, `em6_5`, `text7_0`, `text7_1`, `BroadcastTextID7`, `lang7`, `Probability7`, `em7_0`, `em7_1`, `em7_2`, `em7_3`, `em7_4`, `em7_5`, `VerifiedBuild`) VALUES (441101, 'Choose from the modes below to enable hard mode.', 'Choose from the modes below to enable hard mode.', 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 35 | 36 | 37 | -- Shadow Realm Ghost Gate 38 | DELETE FROM `gameobject` WHERE `guid`=5530619; 39 | INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`) VALUES (5530619, 180322, 37, 0, 0, 1, 1, -593.628, -222.814, 354.97, 0.677429, -0, -0, -0.332275, -0.943183, 300, 0, 1, '', NULL); 40 | 41 | 42 | DELETE FROM `command` WHERE `name`='hardmode setmode'; 43 | INSERT INTO `command` (`name`, `security`, `help`) VALUES ('hardmode setmode', 3, 'Syntax: .hardmode setmode '); 44 | DELETE FROM `command` WHERE `name`='hardmode settaint'; 45 | INSERT INTO `command` (`name`, `security`, `help`) VALUES ('hardmode settaint', 3, 'Syntax: .hardmode settaint '); 46 | DELETE FROM `command` WHERE `name`='hardmode setshadowban'; 47 | INSERT INTO `command` (`name`, `security`, `help`) VALUES ('hardmode setshadowban', 3, 'Syntax: .hardmode setshadowban '); 48 | -------------------------------------------------------------------------------- /data/sql/db-world/updates/hardmode_world_2023_04_02_01.sql: -------------------------------------------------------------------------------- 1 | DELETE FROM `hardmode_selfcraft_exclude`; 2 | INSERT INTO `hardmode_selfcraft_exclude` (`id`, `comment`) VALUES 3 | (-433, 'Spell - Level 1 Food'), 4 | (-430, 'Spell - Level 1 Drink'), 5 | (35, 'Bent Staff'), 6 | (36, 'Worn mace'), 7 | (43, 'Squire\'s Boots'), 8 | (47, 'Footpad\'s Shoes'), 9 | (48, 'Footpad\'s Pants'), 10 | (49, 'Foodpad\'s Shirt'), 11 | (51, 'Neophyte\'s Boots'), 12 | (52, 'Neophyte\'s Pants'), 13 | (53, 'Neophyte\'s Shirt'), 14 | (55, 'Apprentice\'s Boots'), 15 | (59, 'Acolyte\'s SHoes'), 16 | (120, 'Thug Pants'), 17 | (121, 'Thug Boots'), 18 | (127, 'Trapper\'s Shirt'), 19 | (129, 'Rugged Trapper\'s Boots'), 20 | (139, 'Brawler\'s Pants'), 21 | (140, 'Brawler\'s Boots'), 22 | (147, 'Rugged Trapper\'s Pants'), 23 | (148, 'Rugged Trapper\'s Shirt'), 24 | (153, 'Primitive Kilt'), 25 | (154, 'Primitive Mantle'), 26 | (1395, 'Apprentice\'s Pants'), 27 | (1396, 'Acolyte\'s Pants'), 28 | (2092, 'Worn Dagger'), 29 | (2105, 'Thug Shirt'), 30 | (2361, 'Battleworn Hammer'), 31 | (2362, 'Worn Wooden Shield'), 32 | (2504, 'Worn Shortbow'), 33 | (2508, 'Old Blunderbuss'), 34 | (3661, 'Handcrafted Staff'), 35 | (6096, 'Apprentice\'s Shirt'), 36 | (6117, 'Squire\'s Shirt'), 37 | (6118, 'Squire\'s Pants'), 38 | (6124, 'Novice\'s Pants'), 39 | (6125, 'Brawler\'s Harness'), 40 | (6126, 'Trapper\'s Pants'), 41 | (6127, 'Trapper\'s Boots'), 42 | (6129, 'Acolyte\'s Robe'), 43 | (6139, 'Novice\'s Robe'), 44 | (6140, 'Apprentice\'s Robe'), 45 | (12282, 'Worn Battleaxe'), 46 | (20891, 'Neophyte\'s Robe'), 47 | (20978, 'Apprentice\'s Staff'), 48 | (23344, 'Scout\'s Pants'), 49 | (23345, 'Scout\'s Shirt'), 50 | (23346, 'Battleworn Claymore'), 51 | (23348, 'Scout\'s Boots'), 52 | (23473, 'Recruit\'s Shirt'), 53 | (23474, 'Recruit\'s Pants'), 54 | (23475, 'Recruit\'s Boots'), 55 | (24143, 'Initiate\'s Shirt'), 56 | (24145, 'Initiate\'s Pants'), 57 | (24146, 'Initiate\'s Boots'), 58 | (25861, 'Crude Throwing Axe'), 59 | (28979, 'Light Throwing Knife'), 60 | (34648, 'Acherus Knight\'s Greaves'), 61 | (34649, 'Acherus Knight\'s Gauntlets'), 62 | (34650, 'Acherus Knight\'s Tunic'), 63 | (34651, 'Acherus Knight\'s Girdle'), 64 | (34652, 'Acherus Knight\'s Hood'), 65 | (34653, 'Acherus Knight\'s Wristguard'), 66 | (34655, 'Acherus Knight\'s Pauldrons'), 67 | (34656, 'Acherus Knight\'s Legplates'), 68 | (34657, 'Choker of Damnation'), 69 | (34658, 'Plague Band'), 70 | (34659, 'Acherus Knight\'s Shroud'), 71 | (38145, 'Deathweave Bag'), 72 | (38147, 'Corrupted Band'), 73 | (50055, 'Worn Dirk'); -------------------------------------------------------------------------------- /data/sql/db-world/updates/hardmode_world_2023_04_02_02.sql: -------------------------------------------------------------------------------- 1 | DELETE FROM `command` WHERE `name`='hardmode setmode'; 2 | DELETE FROM `command` WHERE `name`='hardmode set mode'; 3 | INSERT INTO `command` (`name`, `security`, `help`) VALUES ('hardmode set mode', 3, 'Syntax: .hardmode setmode '); 4 | 5 | DELETE FROM `command` WHERE `name`='hardmode settaint'; 6 | DELETE FROM `command` WHERE `name`='hardmode set taint'; 7 | INSERT INTO `command` (`name`, `security`, `help`) VALUES ('hardmode set taint', 3, 'Syntax: .hardmode settaint '); 8 | 9 | DELETE FROM `command` WHERE `name`='hardmode setshadowban'; 10 | DELETE FROM `command` WHERE `name`='hardmode set shadowban'; 11 | INSERT INTO `command` (`name`, `security`, `help`) VALUES ('hardmode set shadowban', 3, 'Syntax: .hardmode setshadowban '); 12 | -------------------------------------------------------------------------------- /data/sql/db-world/updates/hardmode_world_2023_04_02_03.sql: -------------------------------------------------------------------------------- 1 | -- Orc starting zone campfire, Shrine sits in its position. 2 | DELETE FROM `gameobject` WHERE `guid`=14; 3 | 4 | DELETE FROM `gameobject` WHERE `guid`=5530697; 5 | INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`) VALUES (5530697, 441101, 0, 0, 0, 1, 1, -8922.74, -145.884, 81.2733, 2.71394, -0, -0, -0.977226, -0.212199, 300, 0, 1, '', NULL); 6 | DELETE FROM `gameobject` WHERE `guid`=5530698; 7 | INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`) VALUES (5530698, 441101, 0, 0, 0, 1, 1, -6213.57, 329.541, 383.707, 3.03243, -0, -0, -0.998511, -0.0545558, 300, 0, 1, '', NULL); 8 | DELETE FROM `gameobject` WHERE `guid`=5530699; 9 | INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`) VALUES (5530699, 441101, 1, 0, 0, 1, 1, 10326.4, 821.202, 1326.45, 2.42121, -0, -0, -0.935829, -0.352454, 300, 0, 1, '', NULL); 10 | DELETE FROM `gameobject` WHERE `guid`=5530700; 11 | INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`) VALUES (5530700, 441101, 530, 0, 0, 1, 1, -3974.18, -13927.5, 100.722, 0.176695, -0, -0, -0.0882326, -0.9961, 300, 0, 1, '', NULL); 12 | DELETE FROM `gameobject` WHERE `guid`=5530702; 13 | INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`) VALUES (5530702, 441101, 1, 0, 0, 1, 1, -602.815, -4250.92, 38.9564, 3.34502, -0, -0, -0.994832, 0.101536, 300, 0, 1, '', NULL); 14 | DELETE FROM `gameobject` WHERE `guid`=5530703; 15 | INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`) VALUES (5530703, 441101, 0, 0, 0, 1, 1, 1656.79, 1673.79, 120.719, 0.22419, -0, -0, -0.11186, -0.993724, 300, 0, 1, '', NULL); 16 | DELETE FROM `gameobject` WHERE `guid`=5530704; 17 | INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`) VALUES (5530704, 441101, 1, 0, 0, 1, 1, -2923.65, -239.7, 53.9153, 4.73752, -0, -0, -0.698165, 0.715937, 300, 0, 1, '', NULL); 18 | DELETE FROM `gameobject` WHERE `guid`=5530705; 19 | INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`) VALUES (5530705, 441101, 530, 0, 0, 1, 1, 10355.7, -6353.75, 32.6743, 5.22416, -0, -0, -0.505114, 0.863053, 300, 0, 1, '', NULL); 20 | DELETE FROM `gameobject` WHERE `guid`=5530706; 21 | INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `ScriptName`, `VerifiedBuild`) VALUES (5530706, 441101, 609, 0, 0, 1, 1, 2372.47, -5674.58, 426.082, 2.4104, -0, -0, -0.933911, -0.357505, 300, 0, 1, '', NULL); 22 | -------------------------------------------------------------------------------- /data/sql/db-world/updates/hardmode_world_2023_04_03_01.sql: -------------------------------------------------------------------------------- 1 | DELETE FROM `command` WHERE `name`='hardmode set mode'; 2 | INSERT INTO `command` (`name`, `security`, `help`) VALUES ('hardmode set mode', 2, 'Syntax: .hardmode setmode '); 3 | DELETE FROM `command` WHERE `name`='hardmode set taint'; 4 | INSERT INTO `command` (`name`, `security`, `help`) VALUES ('hardmode set taint', 2, 'Syntax: .hardmode settaint '); 5 | DELETE FROM `command` WHERE `name`='hardmode set shadowban'; 6 | INSERT INTO `command` (`name`, `security`, `help`) VALUES ('hardmode set shadowban', 2, 'Syntax: .hardmode setshadowban '); 7 | -------------------------------------------------------------------------------- /data/sql/db-world/updates/hardmode_world_2023_04_11_01.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `hardmode_modes`; 2 | CREATE TABLE IF NOT EXISTS `hardmode_modes` ( 3 | `id` tinyint unsigned NOT NULL DEFAULT '0', 4 | `name` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, 5 | `description` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, 6 | `restrictions` bigint unsigned DEFAULT NULL, 7 | `enabled` tinyint DEFAULT NULL, 8 | PRIMARY KEY (`id`) 9 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; 10 | 11 | UPDATE gameobject_template SET ScriptName = "HardModeShrineObject" WHERE entry = 441101; 12 | 13 | DROP TABLE IF EXISTS `hardmode_rewards`; 14 | CREATE TABLE IF NOT EXISTS `hardmode_rewards` ( 15 | `mode` int NOT NULL, 16 | `reward_level` int NOT NULL, 17 | `reward_type` int NOT NULL, 18 | `reward_id` int NOT NULL, 19 | `reward_count` int DEFAULT NULL, 20 | `comment` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, 21 | PRIMARY KEY (`mode`,`reward_level`,`reward_type`,`reward_id`) 22 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; 23 | 24 | DROP TABLE IF EXISTS `hardmode_auras`; 25 | CREATE TABLE IF NOT EXISTS `hardmode_auras` ( 26 | `mode` int NOT NULL, 27 | `aura` int NOT NULL, 28 | `description` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL, 29 | PRIMARY KEY (`mode`,`aura`) 30 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; -------------------------------------------------------------------------------- /data/sql/db-world/updates/hardmode_world_2023_04_18_01.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `hardmode_modes`; 2 | CREATE TABLE IF NOT EXISTS `hardmode_modes` ( 3 | `id` tinyint unsigned NOT NULL AUTO_INCREMENT, 4 | `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, 5 | `description` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, 6 | `restrictions` bigint unsigned DEFAULT NULL, 7 | `enabled` tinyint DEFAULT NULL, 8 | PRIMARY KEY (`id`) 9 | ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; 10 | -------------------------------------------------------------------------------- /data/sql/db-world/updates/hardmode_world_2023_06_03_01.sql: -------------------------------------------------------------------------------- 1 | DELETE FROM `command` WHERE `name`='hardmode set mode'; 2 | INSERT INTO `command` (`name`, `security`, `help`) VALUES ('hardmode set mode', 3, 'Syntax: .hardmode set mode '); 3 | 4 | DELETE FROM `command` WHERE `name`='hardmode set taint'; 5 | INSERT INTO `command` (`name`, `security`, `help`) VALUES ('hardmode set taint', 3, 'Syntax: .hardmode set taint '); 6 | 7 | DELETE FROM `command` WHERE `name`='hardmode set shadowban'; 8 | INSERT INTO `command` (`name`, `security`, `help`) VALUES ('hardmode set shadowban', 3, 'Syntax: .hardmode set shadowban '); -------------------------------------------------------------------------------- /docs/bitmask.js: -------------------------------------------------------------------------------- 1 | const maskInputs = [ 2 | "hmr_retailxp", 3 | "hmr_selfcrafted", 4 | "hmr_int_auction", 5 | "hmr_int_gbank", 6 | "hmr_int_msend", 7 | "hmr_int_mrec", 8 | "hmr_int_trade", 9 | "hmr_permadeath", 10 | "hmr_hide_who", 11 | "hmr_hide_friends", 12 | "hmr_hide_guild", 13 | "hmr_int_lfg", 14 | "hmr_int_grp", 15 | "hmr_int_crossplay", 16 | "hmr_unlucky", 17 | "hmr_pacifist", 18 | "hmr_int_grp_range", 19 | "hmr_int_talent", 20 | "hmr_smallfish", 21 | "hmr_block_crosspvp" 22 | ]; 23 | 24 | var modeName = ""; 25 | var modeDesc = ""; 26 | var modeColor = "#ffffff"; 27 | var modeMask = 0; 28 | var modeEnabled = false; 29 | 30 | function openColorPicker() 31 | { 32 | let colorPickerElement = document.getElementById("mode-color"); 33 | let colorPickerButtonElement = document.getElementById("mode-color-button"); 34 | colorPickerElement.addEventListener("change", () => { 35 | modeColor = colorPickerElement.value; 36 | colorPickerButtonElement.style.backgroundColor = modeColor; 37 | }); 38 | colorPickerElement.click(); 39 | } 40 | 41 | function loadMask() 42 | { 43 | let editMaskInputElement = document.getElementById("bitmask-edit"); 44 | if(!editMaskInputElement) 45 | { 46 | console.log("An unexpected error occurred when trying to get element bitmask-edit."); 47 | return; 48 | } 49 | 50 | let editMaskInputValue = editMaskInputElement.value; 51 | if(!editMaskInputValue) 52 | { 53 | return; 54 | } 55 | 56 | let i = 1; // Start at 1 because of an internal enum we are skipping. HARDMODE_RESTRICT_NONE 57 | 58 | for(let maskIndex in maskInputs) 59 | { 60 | let maskInput = maskInputs[maskIndex]; 61 | 62 | let maskInputElement = document.getElementById(maskInput); 63 | 64 | if(editMaskInputValue & (1 << i)) 65 | { 66 | maskInputElement.checked = true; 67 | } 68 | else 69 | { 70 | maskInputElement.checked = false; 71 | } 72 | 73 | i += 1; 74 | } 75 | } 76 | 77 | function generateSQL() 78 | { 79 | generateMask(); 80 | document.getElementById("bitmask-edit").value = modeMask; 81 | modeName = document.getElementById("mode-name").value; 82 | modeDesc = document.getElementById("mode-desc").value; 83 | modeEnabled = document.getElementById("hm-enabled").checked; 84 | let strippedColor = modeColor.substring(1); 85 | let modeSqlElement = document.getElementById("sql-result"); 86 | modeSqlElement.innerHTML = `INSERT INTO hardmode_modes (name, description, restrictions, enabled) VALUES ('|cff${strippedColor}${modeName}|r', '${modeDesc}', ${modeMask}, ${modeEnabled ? 1 : 0});`; 87 | } 88 | 89 | function generateMask() 90 | { 91 | let bitmask = 0; 92 | let i = 1; // Start at 1 because of an internal enum we are skipping. HARDMODE_RESTRICT_NONE 93 | 94 | for(let maskIndex in maskInputs) 95 | { 96 | let maskInput = maskInputs[maskIndex]; 97 | 98 | let maskInputElement = document.getElementById(maskInput); 99 | 100 | if(maskInputElement.checked) 101 | { 102 | bitmask += 1 << i; 103 | } 104 | 105 | i += 1; 106 | } 107 | 108 | modeMask = bitmask; 109 | } -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Hardmode Documentation 7 | 8 | 9 | 10 | 11 |
12 | 16 | 21 |
22 |
23 |
24 |
25 | About 26 |
27 |
28 | The HardMode module gives server owners the tools to create their own HardModes without writing a line of C++/Lua, and is entirely possible within the database. 29 |
30 |
31 |
32 |
33 | Mode Editor 34 |
35 |
36 | This section will help you create your first hard mode, before you can create a mode you need to come up with a name, choose a color, description & restrictions.
37 |
38 | 39 |
40 |
41 | 42 | 43 | 44 |
45 |
46 | 47 |
48 |
49 | 50 |
51 |
52 | Restrictions 53 |
54 | To enable restrictions for your modes you need to create a bitmask to store in the
restrictions
column of the
hardmode_modes
table.

55 | Tick the restrictions you would like to use below and copy the bitmask result into the
restrictions
table column for your mode, or generate the SQL and apply it yourself. 56 |
57 |
58 | 59 |
60 |
61 |
62 | 63 | 64 |
65 | Enables 1x rates for kill, quest, exploration. 66 |
67 |
68 | 69 |
70 | 71 | 72 |
73 | Disables the use of items/equipment that are not crafted by the player. 74 |
75 |
76 | 77 |
78 | 79 | 80 |
81 | Disables the interaction with the auction house NPC. 82 |
83 |
84 | 85 |
86 | 87 | 88 |
89 | Disables the interaction with the guild bank. 90 |
91 |
92 | 93 |
94 | 95 | 96 |
97 | Disables sending of mail to other players. 98 |
99 |
100 | 101 |
102 | 103 | 104 |
105 | Disables receiving of mail from other players. 106 |
107 |
108 | 109 |
110 | 111 | 112 |
113 | Disables trading to/from other players. 114 |
115 |
116 | 117 |
118 | 119 | 120 |
121 | The player is sent to the shadow realm on death (you cannot leave the shadow realm). 122 |
123 |
124 | 125 |
126 | 127 | 128 |
129 | The player is hidden from the who list (shows unknown location). 130 |
131 |
132 | 133 |
134 | 135 | 136 |
137 | The player is hidden from the friends list (shows unknown location). 138 |
139 |
140 | 141 |
142 | 143 | 144 |
145 | The player is hidden from the guild member roster (shows unknown location). 146 |
147 |
148 | 149 |
150 | 151 | 152 |
153 | The player cannot queue for looking for group. 154 |
155 |
156 | 157 |
158 | 159 | 160 |
161 | The player cannot group with other players. 162 |
163 |
164 | 165 |
166 | 167 | 168 |
169 | The player can only group with other players with the same cross-play modes as them (all the modes with this flag enabled). 170 |
171 |
172 | 173 |
174 | 175 | 176 |
177 | The player is unlucky with loot drops (there is a configurable chance for items to drop, quest items are unaffected). 178 |
179 |
180 | 181 |
182 | 183 | 184 |
185 | The player loses the mode if they damage or kill units (they are covered in blood to show other players what a monster they are). 186 |
187 |
188 | 189 |
190 | 191 | 192 |
193 | The player can only group with other players within x (default 3) levels from themself (configurable). 194 |
195 |
196 | 197 |
198 | 199 | 200 |
201 | The player cannot use talent points. 202 |
203 |
204 | 205 |
206 | 207 | 208 |
209 | The player is half the size, speed and deals half as much damage. 210 |
211 |
212 | 213 |
214 | 215 | 216 |
217 | Blocks damage done to a player if the hard modes are not matching between players. 218 |
219 |
220 |

221 |
222 |
223 | 224 | 225 |
226 | The mode is enabled by default in the table entry (it will show up in the HardMode gossip). 227 |
228 |
229 |

230 |
231 |
232 |
233 |
234 |
235 | Contact 236 |
237 |
238 | If you are having difficulty with this module or want to speak to me you can join the Discord. If you want to report a bug you can open an issue on the repository. 239 |
240 |
241 |
242 |
243 |
244 | 245 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnchyDev/HardMode/611c76c512e50cdbefef5bbb282dc76c738ec691/docs/logo.png -------------------------------------------------------------------------------- /docs/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0px; 3 | padding: 0px; 4 | 5 | font-family: Arial; 6 | text-decoration: none; 7 | 8 | scroll-behavior: smooth; 9 | } 10 | 11 | body { 12 | display: flex; 13 | 14 | width: 100vw; 15 | height: 100vh; 16 | 17 | justify-content: center; 18 | align-items: center; 19 | 20 | flex-wrap: wrap; 21 | 22 | background-color: white; 23 | } 24 | 25 | .container { 26 | display: flex; 27 | flex-direction: column; 28 | } 29 | 30 | .logo { 31 | display: flex; 32 | flex-direction: row; 33 | 34 | justify-content: center; 35 | align-items: center; 36 | 37 | gap: 10px; 38 | margin-bottom: 10px; 39 | } 40 | .logo img{ 41 | max-height: 64px; 42 | } 43 | 44 | .menu { 45 | display: flex; 46 | flex-direction: row; 47 | 48 | justify-content: center; 49 | 50 | gap: 20px; 51 | } 52 | .menu a{ 53 | color: black; 54 | transition: color 0.25s; 55 | } 56 | .menu a:hover{ 57 | color: red; 58 | } 59 | 60 | .content { 61 | display: flex; 62 | flex-direction: column; 63 | 64 | max-width: 800px; 65 | 66 | margin: 10px; 67 | } 68 | 69 | .sections{ 70 | display: flex; 71 | flex-direction: column; 72 | 73 | justify-content: left; 74 | } 75 | 76 | .header { 77 | font-size: 1.5rem; 78 | font-weight: bold; 79 | 80 | margin: 5px; 81 | margin-left: 0px; 82 | margin-right: 0px; 83 | } 84 | .sub-header { 85 | font-size: 1.25rem; 86 | font-weight: bold; 87 | margin: 10px; 88 | margin-left: 0px; 89 | margin-right: 0px; 90 | } 91 | .body { 92 | font-size: 1rem; 93 | 94 | margin: 5px; 95 | margin-left: 0px; 96 | margin-right: 0px; 97 | } 98 | .sub-body { 99 | font-size: 0.75rem; 100 | margin-bottom: 5px; 101 | } 102 | .body-item { 103 | display: flex; 104 | gap: 5px; 105 | margin: 5px 0px; 106 | } 107 | 108 | .bitmask-options { 109 | display: flex; 110 | flex-direction: row; 111 | flex-wrap: wrap; 112 | gap: 5px; 113 | } 114 | .bitmask-option { 115 | border: solid 1px; 116 | border-color: rgb(200, 200, 200); 117 | border-radius: 5px; 118 | 119 | padding: 5px; 120 | 121 | min-width: 250px; 122 | max-width: 250px; 123 | } 124 | 125 | .highlight-dark { 126 | display: inline-flex; 127 | color: rgb(53, 53, 53); 128 | background-color: rgb(223, 223, 223); 129 | border-radius: 2px; 130 | padding: 3px; 131 | } 132 | 133 | .nice-button { 134 | color: rgb(53, 53, 53); 135 | background-color: rgb(209, 209, 209); 136 | 137 | border: 0px; 138 | border-radius: 4px; 139 | padding: 5px; 140 | 141 | transition: color 0.25s, background-color 0.25s, transform 0.25s; 142 | } 143 | .nice-button:hover { 144 | color: white; 145 | background-color: red; 146 | } 147 | .nice-button:active { 148 | background-color: rgb(255, 119, 119); 149 | } 150 | 151 | .color-picker { 152 | min-width: 20px; 153 | min-height: 20px; 154 | 155 | border: solid black 1px; 156 | border-radius: 5px; 157 | 158 | background-color: white; 159 | } 160 | 161 | .name-picker { 162 | display: flex; 163 | flex-direction: row; 164 | 165 | gap: 5px; 166 | } -------------------------------------------------------------------------------- /include.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## GETS THE CURRENT MODULE ROOT DIRECTORY 4 | MOD_SKELETON_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" && pwd )" 5 | 6 | source $MOD_SKELETON_ROOT"/conf/conf.sh.dist" 7 | 8 | if [ -f $MOD_SKELETON_ROOT"/conf/conf.sh" ]; then 9 | source $MOD_SKELETON_ROOT"/conf/conf.sh" 10 | fi 11 | -------------------------------------------------------------------------------- /mode-restrictions.txt: -------------------------------------------------------------------------------- 1 | AllModes 2 | - Can't group with other players unless they have matching modes (excluding SlowXP). 3 | - Can't group with other players with matching modes unless they are in level range (default: 3). 4 | 5 | SelfCrafted: 6 | - Can't use auction house. 7 | - Can't use guild bank. 8 | - Can't trade other players. 9 | - Can't send or receive mail. 10 | - Can't equip items that aren't self crafted. 11 | - Can't eat food that is not self crafted. 12 | - Can't drink potions that are not self crafted. 13 | 14 | HardCore: 15 | - Can't use auction house. 16 | - Can't use guild bank. 17 | - Can't trade other players. 18 | - Can't send or receive mail. 19 | - Teleported to shadow realm on death. 20 | - Can't teleport while shadow banned. 21 | - Gains a red aura, notifying players of hardcore. 22 | - Location shows as Unknown on who list. 23 | - Cannot use LFG to queue for dungeons (you have to run there). 24 | 25 | SlowXP: 26 | - Exp scaled back to 1x (may be futher reduced if configured). 27 | - Can group with normal players. -------------------------------------------------------------------------------- /src/HardMode.cpp: -------------------------------------------------------------------------------- 1 | #include "HardMode.h" 2 | #include "HardModeCommands.h" 3 | #include "HardModeHandler.h" 4 | #include "HardModeShrineObject.h" 5 | #include "HardModeTypes.h" 6 | 7 | #include "HardModeHooks/HardModeHooksGlobal.h" 8 | #include "HardModeHooks/HardModeHooksGuild.h" 9 | #include "HardModeHooks/HardModeHooksMisc.h" 10 | #include "HardModeHooks/HardModeHooksPlayer.h" 11 | #include "HardModeHooks/HardModeHooksServer.h" 12 | #include "HardModeHooks/HardModeHooksUnit.h" 13 | #include "HardModeHooks/HardModeHooksWorld.h" 14 | 15 | void HardModePlayerScript::OnLevelChanged(Player* player, uint8 /*oldLevel*/) 16 | { 17 | if (!sHardModeHandler->IsHardModeEnabled()) 18 | { 19 | return; 20 | } 21 | 22 | if (!player) 23 | { 24 | return; 25 | } 26 | 27 | uint32 level = player->GetLevel(); 28 | 29 | auto modes = sHardModeHandler->GetHardModes(); 30 | for (auto it = modes->begin(); it != modes->end(); ++it) 31 | { 32 | auto mode = it->second; 33 | 34 | if (!sHardModeHandler->IsModeEnabledForPlayer(player->GetGUID(), mode.Id)) 35 | { 36 | continue; 37 | } 38 | 39 | auto rewards = sHardModeHandler->GetRewardsForMode(mode.Id); 40 | 41 | if (!rewards || rewards->size() < 1) 42 | { 43 | continue; 44 | } 45 | 46 | std::vector newRewards; 47 | bool hasItemRewards = false; 48 | for (auto reward = rewards->begin(); reward != rewards->end(); ++reward) 49 | { 50 | if (level == reward->Level) 51 | { 52 | newRewards.push_back(*reward); 53 | 54 | if (reward->Type == HARDMODE_REWARD_TYPE_ITEM) 55 | { 56 | hasItemRewards = true; 57 | } 58 | } 59 | } 60 | 61 | if (newRewards.size() > 0) 62 | { 63 | sHardModeHandler->TryRewardPlayer(player, newRewards); 64 | 65 | if (hasItemRewards) 66 | { 67 | sHardModeHandler->SendAlert(player, "Congratulations for reaching a challenge milestone, your rewards are in your mailbox."); 68 | } 69 | } 70 | } 71 | } 72 | 73 | void HardModePlayerScript::OnLogout(Player* player) 74 | { 75 | if (!sHardModeHandler->IsHardModeEnabled()) 76 | { 77 | return; 78 | } 79 | 80 | auto guid = player->GetGUID(); 81 | if (auto setting = sHardModeHandler->GetPlayerSetting(guid)) 82 | { 83 | sHardModeHandler->SavePlayerSetting(player->GetGUID().GetRawValue(), setting); 84 | } 85 | } 86 | 87 | void HardModeWorldScript::OnAfterConfigLoad(bool reload) 88 | { 89 | if (!sHardModeHandler->IsHardModeEnabled()) 90 | { 91 | return; 92 | } 93 | 94 | if (reload) 95 | { 96 | sHardModeHandler->SavePlayerSettings(); 97 | 98 | sHardModeHandler->ClearHardModes(); 99 | sHardModeHandler->ClearPlayerSettings(); 100 | sHardModeHandler->ClearSelfCraftExcludeIds(); 101 | sHardModeHandler->ClearRewards(); 102 | sHardModeHandler->ClearAuras(); 103 | } 104 | 105 | sHardModeHandler->LoadHardModes(); 106 | sHardModeHandler->LoadPlayerSettings(); 107 | sHardModeHandler->LoadSelfCraftExcludeIds(); 108 | sHardModeHandler->LoadRewards(); 109 | sHardModeHandler->LoadAuras(); 110 | } 111 | 112 | void HardModeWorldScript::OnShutdown() 113 | { 114 | if (!sHardModeHandler->IsHardModeEnabled()) 115 | { 116 | return; 117 | } 118 | 119 | sHardModeHandler->SavePlayerSettings(); 120 | } 121 | 122 | void SC_AddHardModeScripts() 123 | { 124 | new HardModePlayerScript(); 125 | new HardModeWorldScript(); 126 | new HardModeShrineObject(); 127 | new HardModeCommandsScript(); 128 | 129 | new HardModeHooksGlobalScript(); 130 | new HardModeHooksGuildScript(); 131 | new HardModeHooksMiscScript(); 132 | new HardModeHooksPlayerScript(); 133 | new HardModeHooksServerScript(); 134 | new HardModeHooksUnitScript(); 135 | new HardModeHooksWorldScript(); 136 | } 137 | -------------------------------------------------------------------------------- /src/HardMode.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_HARDMODE_H 2 | #define MODULE_HARDMODE_H 3 | 4 | #include "ScriptMgr.h" 5 | 6 | class HardModePlayerScript : PlayerScript 7 | { 8 | public: 9 | HardModePlayerScript() : PlayerScript("HardModePlayerScript") { } 10 | 11 | private: 12 | void OnLevelChanged(Player* player, uint8 oldLevel) override; 13 | void OnLogout(Player* player) override; 14 | }; 15 | 16 | class HardModeWorldScript : WorldScript 17 | { 18 | public: 19 | HardModeWorldScript() : WorldScript("HardModeWorldScript") { } 20 | 21 | private: 22 | void OnAfterConfigLoad(bool reload) override; 23 | void OnShutdown() override; 24 | }; 25 | 26 | #endif // MODULE_HARDMODE_H 27 | -------------------------------------------------------------------------------- /src/HardModeCommands.cpp: -------------------------------------------------------------------------------- 1 | #include "HardModeCommands.h" 2 | #include "HardModeHandler.h" 3 | 4 | #include "Chat.h" 5 | 6 | ChatCommandTable HardModeCommandsScript::GetCommands() const 7 | { 8 | static ChatCommandTable hmSetCommandTable = 9 | { 10 | { "mode", HandleHardModeSetModeCommand, SEC_MODERATOR, Console::No }, 11 | { "taint", HandleHardModeSetTaintCommand, SEC_MODERATOR, Console::No }, 12 | { "shadowban", HandleHardModeSetShadowBanCommand, SEC_MODERATOR, Console::No } 13 | }; 14 | static ChatCommandTable hmCommandTable = 15 | { 16 | { "info", HandleHardModeInfoCommand, SEC_MODERATOR, Console::No }, 17 | { "set", hmSetCommandTable } 18 | }; 19 | 20 | static ChatCommandTable commandTable = 21 | { 22 | { "hardmode", hmCommandTable } 23 | }; 24 | 25 | return commandTable; 26 | } 27 | 28 | bool HardModeCommandsScript::HandleHardModeInfoCommand(ChatHandler* handler, Optional target) 29 | { 30 | if (!target) 31 | { 32 | target = PlayerIdentifier::FromTargetOrSelf(handler); 33 | } 34 | 35 | if (!target) 36 | { 37 | return false; 38 | } 39 | 40 | if (!target->IsConnected()) 41 | { 42 | return false; 43 | } 44 | 45 | auto targetPlayer = target->GetConnectedPlayer(); 46 | 47 | handler->SendSysMessage(Acore::StringFormat("Enabled Difficulty Modes: {}", sHardModeHandler->GetNamesFromEnabledModes(targetPlayer))); 48 | handler->SendSysMessage(Acore::StringFormat("IsTainted: {}", sHardModeHandler->IsPlayerTainted(targetPlayer->GetGUID()))); 49 | handler->SendSysMessage(Acore::StringFormat("IsShadowBanned: {}", sHardModeHandler->IsPlayerShadowBanned(targetPlayer->GetGUID()))); 50 | 51 | return true; 52 | } 53 | 54 | bool HardModeCommandsScript::HandleHardModeSetModeCommand(ChatHandler* handler, Optional target, uint8 mode, uint8 value) 55 | { 56 | if (!target) 57 | { 58 | target = PlayerIdentifier::FromTargetOrSelf(handler); 59 | } 60 | 61 | if (!target) 62 | { 63 | return false; 64 | } 65 | 66 | if (!target->IsConnected()) 67 | { 68 | return false; 69 | } 70 | 71 | if (!sHardModeHandler->GetHardModeFromId(mode)) 72 | { 73 | return false; 74 | } 75 | 76 | auto targetPlayer = target->GetConnectedPlayer(); 77 | sHardModeHandler->UpdateModeForPlayer(targetPlayer->GetGUID(), mode, value); 78 | 79 | handler->SendSysMessage(Acore::StringFormat("Updated mode '{}' for player '{}' to '{}'.", sHardModeHandler->GetNameFromMode(mode), targetPlayer->GetName(), value)); 80 | 81 | return true; 82 | } 83 | 84 | bool HardModeCommandsScript::HandleHardModeSetTaintCommand(ChatHandler* handler, Optional target, uint8 value) 85 | { 86 | if (!target) 87 | { 88 | target = PlayerIdentifier::FromTargetOrSelf(handler); 89 | } 90 | 91 | if (!target) 92 | { 93 | return false; 94 | } 95 | 96 | if (!target->IsConnected()) 97 | { 98 | return false; 99 | } 100 | 101 | auto targetPlayer = target->GetConnectedPlayer(); 102 | 103 | if (!sHardModeHandler->CanTaintPlayer(targetPlayer->GetGUID())) 104 | { 105 | return false; 106 | } 107 | 108 | sHardModeHandler->UpdatePlayerTainted(targetPlayer->GetGUID(), value); 109 | 110 | handler->SendSysMessage(Acore::StringFormat("Updated taint for player '{}' to '{}'.", targetPlayer->GetName(), value)); 111 | 112 | return true; 113 | } 114 | 115 | bool HardModeCommandsScript::HandleHardModeSetShadowBanCommand(ChatHandler* handler, Optional target, uint8 value) 116 | { 117 | if (!target) 118 | { 119 | target = PlayerIdentifier::FromTargetOrSelf(handler); 120 | } 121 | 122 | if (!target) 123 | { 124 | return false; 125 | } 126 | 127 | if (!target->IsConnected()) 128 | { 129 | return false; 130 | } 131 | 132 | auto targetPlayer = target->GetConnectedPlayer(); 133 | sHardModeHandler->UpdatePlayerShadowBanned(targetPlayer->GetGUID(), value); 134 | 135 | handler->SendSysMessage(Acore::StringFormat("Updated shadow ban for player '{}' to '{}'.", targetPlayer->GetName(), value)); 136 | 137 | return true; 138 | } 139 | -------------------------------------------------------------------------------- /src/HardModeCommands.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_HARDMODE_COMMANDS_H 2 | #define MODULE_HARDMODE_COMMANDS_H 3 | 4 | #include "ChatCommand.h" 5 | #include "ScriptMgr.h" 6 | 7 | using namespace Acore::ChatCommands; 8 | 9 | class HardModeCommandsScript : public CommandScript 10 | { 11 | public: 12 | HardModeCommandsScript() : CommandScript("HardModeCommandsScript") { } 13 | 14 | ChatCommandTable GetCommands() const override; 15 | static bool HandleHardModeInfoCommand(ChatHandler* handler, Optional target); 16 | static bool HandleHardModeSetModeCommand(ChatHandler* handler, Optional target, uint8 mode, uint8 value); 17 | static bool HandleHardModeSetTaintCommand(ChatHandler* handler, Optional target, uint8 value); 18 | static bool HandleHardModeSetShadowBanCommand(ChatHandler* handler, Optional target, uint8 value); 19 | }; 20 | 21 | 22 | #endif // MODULE_HARDMODE_COMMANDS_H 23 | -------------------------------------------------------------------------------- /src/HardModeHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "HardModeHandler.h" 2 | #include "HardModeTypes.h" 3 | 4 | #include "DatabaseEnv.h" 5 | #include "Log.h" 6 | #include "Player.h" 7 | #include "StringConvert.h" 8 | #include "Tokenize.h" 9 | 10 | #include 11 | 12 | #include 13 | 14 | bool HardModeHandler::IsHardModeEnabled() 15 | { 16 | return sConfigMgr->GetOption("HardMode.Enable", false); 17 | } 18 | 19 | void HardModeHandler::LoadHardModes() 20 | { 21 | QueryResult qResult = WorldDatabase.Query("SELECT * FROM `hardmode_modes` ORDER BY id ASC"); 22 | 23 | if (qResult) 24 | { 25 | uint32 count = 0; 26 | 27 | do 28 | { 29 | Field* fields = qResult->Fetch(); 30 | 31 | uint32 id = fields[0].Get(); 32 | std::string name = fields[1].Get(); 33 | std::string description = fields[2].Get(); 34 | uint64 restrictions = fields[3].Get(); 35 | bool enabled = fields[4].Get(); 36 | 37 | HardModeInfo mode; 38 | mode.Id = id; 39 | mode.Name = name; 40 | mode.Description = description; 41 | mode.Restrictions = restrictions; 42 | mode.Enabled = enabled; 43 | 44 | _hardModes.emplace(id, mode); 45 | 46 | count++; 47 | } while (qResult->NextRow()); 48 | 49 | LOG_INFO("module", "Loaded '{}' rows from 'hardmode_modes' table.", count); 50 | } 51 | else 52 | { 53 | LOG_INFO("module", "Loaded '0' rows from 'hardmode_modes' table."); 54 | } 55 | } 56 | 57 | void HardModeHandler::ClearHardModes() 58 | { 59 | _hardModes.clear(); 60 | } 61 | 62 | std::map* HardModeHandler::GetHardModes() 63 | { 64 | return &_hardModes; 65 | } 66 | 67 | HardModeInfo* HardModeHandler::GetHardModeFromId(uint8 id) 68 | { 69 | auto modes = sHardModeHandler->GetHardModes(); 70 | 71 | for (auto it = modes->begin(); it != modes->end(); ++it) 72 | { 73 | auto mode = it->second; 74 | 75 | if (mode.Id == id) 76 | { 77 | return &it->second; 78 | } 79 | } 80 | 81 | return nullptr; 82 | } 83 | 84 | void HardModeHandler::LoadPlayerSettings() 85 | { 86 | QueryResult qResult = CharacterDatabase.Query("SELECT * FROM `hardmode_player_settings`"); 87 | 88 | if (qResult) 89 | { 90 | uint32 count = 0; 91 | 92 | do 93 | { 94 | Field* fields = qResult->Fetch(); 95 | 96 | uint32 guid = fields[0].Get(); 97 | std::string modes = fields[1].Get(); 98 | bool tainted = fields[2].Get(); 99 | bool shadowban = fields[3].Get(); 100 | 101 | std::vector tokens = Acore::Tokenize(modes, ' ', false); 102 | HardModePlayerSettings playerSettings; 103 | std::vector playerModes; 104 | 105 | for (auto token : tokens) 106 | { 107 | try 108 | { 109 | uint32 modeId = boost::lexical_cast(token); 110 | 111 | auto hardMode = sHardModeHandler->GetHardModeFromId(modeId); 112 | if (!hardMode) 113 | { 114 | continue; 115 | } 116 | 117 | playerModes.push_back(hardMode->Id); 118 | } 119 | catch (const boost::bad_lexical_cast&) 120 | { 121 | LOG_ERROR("module", "Detected bad mode settings format for column 'mode' and guid '{}' in 'hardmode_player_settings' table.", guid); 122 | } 123 | } 124 | 125 | playerSettings.Modes = playerModes; 126 | playerSettings.Tainted = tainted; 127 | playerSettings.ShadowBanned = shadowban; 128 | 129 | sHardModeHandler->GetPlayerSettings()->emplace(guid, playerSettings); 130 | 131 | count++; 132 | } while (qResult->NextRow()); 133 | 134 | LOG_INFO("module", "Loaded '{}' rows from 'hardmode_player_settings' table.", count); 135 | } 136 | else 137 | { 138 | LOG_INFO("module", "Loaded '0' rows from 'hardmode_player_settings' table."); 139 | } 140 | } 141 | 142 | void HardModeHandler::LoadPlayerSettings(ObjectGuid player) 143 | { 144 | QueryResult qResult = CharacterDatabase.Query("SELECT * FROM `hardmode_player_settings` WHERE guid = {}", player.GetRawValue()); 145 | 146 | if (qResult) 147 | { 148 | Field* fields = qResult->Fetch(); 149 | 150 | uint32 guid = fields[0].Get(); 151 | std::string modes = fields[1].Get(); 152 | bool tainted = fields[2].Get(); 153 | bool shadowban = fields[3].Get(); 154 | 155 | std::vector tokens = Acore::Tokenize(modes, ' ', false); 156 | HardModePlayerSettings playerSettings; 157 | std::vector playerModes; 158 | 159 | for (auto token : tokens) 160 | { 161 | try 162 | { 163 | uint32 modeId = boost::lexical_cast(token); 164 | 165 | auto hardMode = sHardModeHandler->GetHardModeFromId(modeId); 166 | if (!hardMode) 167 | { 168 | continue; 169 | } 170 | 171 | playerModes.push_back(hardMode->Id); 172 | } 173 | catch (const boost::bad_lexical_cast&) 174 | { 175 | LOG_ERROR("module", "Detected bad mode settings format for column 'mode' and guid '{}' in 'hardmode_player_settings' table.", guid); 176 | } 177 | } 178 | 179 | playerSettings.Modes = playerModes; 180 | playerSettings.Tainted = tainted; 181 | playerSettings.ShadowBanned = shadowban; 182 | 183 | sHardModeHandler->UpdatePlayerSettings(player, &playerSettings); 184 | } 185 | } 186 | 187 | void HardModeHandler::DeletePlayerSetting(uint64 guid) 188 | { 189 | auto settings = sHardModeHandler->GetPlayerSettings(); 190 | auto it = settings->find(guid); 191 | if (it == settings->end()) 192 | { 193 | return; 194 | } 195 | 196 | settings->erase(it); 197 | 198 | CharacterDatabase.Execute("DELETE FROM hardmode_player_settings WHERE guid = {}", guid); 199 | } 200 | 201 | void HardModeHandler::ClearPlayerSettings() 202 | { 203 | _playerSettings.clear(); 204 | } 205 | 206 | void HardModeHandler::SavePlayerSettings() 207 | { 208 | auto settings = sHardModeHandler->GetPlayerSettings(); 209 | for (auto it = settings->begin(); it != settings->end(); ++it) 210 | { 211 | auto guid = it->first; 212 | auto setting = it->second; 213 | 214 | sHardModeHandler->SavePlayerSetting(guid, &setting); 215 | } 216 | } 217 | 218 | void HardModeHandler::SavePlayerSetting(uint64 guid, HardModePlayerSettings* settings) 219 | { 220 | std::stringstream ss; 221 | for (const uint8& mode : settings->Modes) 222 | { 223 | ss << std::to_string(mode); 224 | ss << " "; 225 | } 226 | 227 | std::string sModes = ss.str(); 228 | 229 | CharacterDatabase.Execute("INSERT INTO hardmode_player_settings (guid, modes, tainted, shadowban) VALUES ({}, '{}', {}, {}) ON DUPLICATE KEY UPDATE modes = '{}', tainted = {}, shadowban = {}", 230 | guid, sModes, settings->Tainted, settings->ShadowBanned, 231 | sModes, settings->Tainted, settings->ShadowBanned); 232 | } 233 | 234 | void HardModeHandler::UpdatePlayerSettings(ObjectGuid guid, HardModePlayerSettings* settings) 235 | { 236 | auto settingsMap = sHardModeHandler->GetPlayerSettings(); 237 | 238 | if (!settingsMap) 239 | { 240 | return; 241 | } 242 | 243 | auto it = settingsMap->find(guid.GetRawValue()); 244 | if (it != settingsMap->end()) 245 | { 246 | settingsMap->erase(it); 247 | } 248 | 249 | settingsMap->emplace(guid.GetRawValue(), *settings); 250 | } 251 | 252 | std::map* HardModeHandler::GetPlayerSettings() 253 | { 254 | return &_playerSettings; 255 | } 256 | 257 | HardModePlayerSettings* HardModeHandler::GetPlayerSetting(ObjectGuid guid) 258 | { 259 | auto playerSettings = sHardModeHandler->GetPlayerSettings(); 260 | 261 | auto it = playerSettings->find(guid.GetRawValue()); 262 | if (it == playerSettings->end()) 263 | { 264 | HardModePlayerSettings _settings; 265 | std::vector _modes; 266 | _settings.Modes = _modes; 267 | _settings.Tainted = false; 268 | _settings.ShadowBanned = false; 269 | 270 | it = playerSettings->emplace(guid.GetRawValue(), _settings).first; 271 | } 272 | 273 | return &it->second; 274 | } 275 | 276 | void HardModeHandler::LoadSelfCraftExcludeIds() 277 | { 278 | QueryResult qResult = WorldDatabase.Query("SELECT `id` FROM `hardmode_selfcraft_exclude`"); 279 | 280 | if (qResult) 281 | { 282 | uint32 count = 0; 283 | 284 | do 285 | { 286 | Field* fields = qResult->Fetch(); 287 | int32 id = fields[0].Get(); 288 | 289 | _selfCraftExcludeIds.push_back(id); 290 | count++; 291 | } while (qResult->NextRow()); 292 | 293 | LOG_INFO("module", "Loaded '{}' rows from 'hardmode_selfcraft_exclude' table.", count); 294 | } 295 | else 296 | { 297 | LOG_INFO("module", "Loaded '0' rows from 'hardmode_selfcraft_exclude' table."); 298 | } 299 | } 300 | 301 | void HardModeHandler::ClearSelfCraftExcludeIds() 302 | { 303 | _selfCraftExcludeIds.clear(); 304 | } 305 | 306 | std::vector* HardModeHandler::GetSelfCraftedExcludeIds() 307 | { 308 | return &_selfCraftExcludeIds; 309 | } 310 | 311 | bool HardModeHandler::IsSelfCraftExcluded(int32 id) 312 | { 313 | for (uint32 i = 0; i < _selfCraftExcludeIds.size(); ++i) 314 | { 315 | if (_selfCraftExcludeIds[i] == id) 316 | { 317 | return true; 318 | } 319 | } 320 | 321 | return false; 322 | } 323 | 324 | bool HardModeHandler::IsSelfCraftSpellExcluded(uint32 spellId) 325 | { 326 | return IsSelfCraftExcluded(-spellId); 327 | 328 | return false; 329 | } 330 | 331 | bool HardModeHandler::IsSelfCraftItemExcluded(uint32 itemId) 332 | { 333 | return IsSelfCraftExcluded(itemId); 334 | 335 | return false; 336 | } 337 | 338 | void HardModeHandler::LoadAuras() 339 | { 340 | QueryResult qResult = WorldDatabase.Query("SELECT `mode`, `aura` FROM `hardmode_auras`"); 341 | 342 | if (qResult) 343 | { 344 | uint32 count = 0; 345 | 346 | do 347 | { 348 | Field* fields = qResult->Fetch(); 349 | 350 | uint32 mode = fields[0].Get(); 351 | uint32 aura = fields[1].Get(); 352 | 353 | auto it = _auras.find(mode); 354 | if (it == _auras.end()) 355 | { 356 | std::vector auras; 357 | _auras.emplace(mode, auras); 358 | 359 | it = _auras.find(mode); 360 | if (it == _auras.end()) 361 | { 362 | LOG_ERROR("module", "An error occurred when trying to populate auras map!"); 363 | return; 364 | } 365 | } 366 | 367 | it->second.push_back(aura); 368 | count++; 369 | } while (qResult->NextRow()); 370 | 371 | LOG_INFO("module", "Loaded '{}' rows from 'hardmode_auras' table.", count); 372 | } 373 | else 374 | { 375 | LOG_INFO("module", "Loaded '0' rows from 'hardmode_auras' table."); 376 | } 377 | } 378 | 379 | void HardModeHandler::ClearAuras() 380 | { 381 | _auras.clear(); 382 | } 383 | 384 | std::map>* HardModeHandler::GetAuras() 385 | { 386 | return &_auras; 387 | } 388 | 389 | std::vector* HardModeHandler::GetAurasForMode(uint8 mode) 390 | { 391 | auto auras = sHardModeHandler->GetAuras(); 392 | 393 | auto auraIt = auras->find(mode); 394 | if (auraIt != auras->end()) 395 | { 396 | return &(auraIt->second); 397 | } 398 | 399 | return nullptr; 400 | } 401 | 402 | void HardModeHandler::ValidatePlayerAuras(Player* player) 403 | { 404 | if (!player) 405 | { 406 | return; 407 | } 408 | 409 | auto modes = sHardModeHandler->GetHardModes(); 410 | 411 | if (!modes) 412 | { 413 | return; 414 | } 415 | 416 | if (modes->size() < 1) 417 | { 418 | return; 419 | } 420 | 421 | for (auto modeIt = modes->begin(); modeIt != modes->end(); ++modeIt) 422 | { 423 | auto mode = modeIt->second.Id; 424 | auto auras = sHardModeHandler->GetAurasForMode(mode); 425 | 426 | if (!auras) 427 | { 428 | continue; 429 | } 430 | 431 | for (auto aura : *auras) 432 | { 433 | if (sHardModeHandler->IsModeEnabledForPlayer(player->GetGUID(), mode)) 434 | { 435 | if (!player->HasAura(aura)) 436 | { 437 | _scheduler.Schedule(1s, [aura, player](TaskContext /*task*/) 438 | { 439 | if (!player || 440 | !player->IsInWorld() || 441 | !aura) 442 | { 443 | return; 444 | } 445 | 446 | player->AddAura(aura, player); 447 | }); 448 | } 449 | } 450 | else 451 | { 452 | if (player->HasAura(aura)) 453 | { 454 | _scheduler.Schedule(1s, [aura, player](TaskContext /*task*/) 455 | { 456 | if (!player || !aura) 457 | { 458 | return; 459 | } 460 | 461 | player->RemoveAura(aura); 462 | }); 463 | } 464 | } 465 | } 466 | } 467 | } 468 | 469 | void HardModeHandler::UpdatePlayerScaleSpeed(Player* player, float scaleSpeed) 470 | { 471 | if (!player || !player->IsInWorld()) 472 | { 473 | return; 474 | } 475 | 476 | float scale = scaleSpeed; 477 | float move = scaleSpeed; 478 | bool forced = true; 479 | 480 | player->SetObjectScale(scale); 481 | 482 | for (auto i = 0; i < MAX_MOVE_TYPE; ++i) 483 | { 484 | // Slow rotation is cancer, so skip adjusting these. 485 | if (i == UnitMoveType::MOVE_TURN_RATE || i == UnitMoveType::MOVE_PITCH_RATE) 486 | { 487 | continue; 488 | } 489 | 490 | auto moveType = static_cast(i); 491 | 492 | player->UpdateSpeed(moveType, forced); 493 | player->SetSpeed(moveType, player->GetSpeedRate(moveType) * move, forced); 494 | } 495 | } 496 | 497 | void HardModeHandler::LoadRewards() 498 | { 499 | QueryResult qResult = WorldDatabase.Query("SELECT `mode`, `reward_level`, `reward_type`, `reward_id`, `reward_count` FROM `hardmode_rewards`"); 500 | 501 | if (qResult) 502 | { 503 | uint32 count = 0; 504 | 505 | do 506 | { 507 | Field* fields = qResult->Fetch(); 508 | 509 | uint32 mode = fields[0].Get(); 510 | uint32 level = fields[1].Get(); 511 | uint32 rewardType = fields[2].Get(); 512 | uint32 rewardId = fields[3].Get(); 513 | uint32 rewardCount = fields[4].Get(); 514 | 515 | HardModeReward reward; 516 | 517 | reward.Mode = mode; 518 | reward.Level = level; 519 | reward.Type = rewardType; 520 | reward.RewardId = rewardId; 521 | reward.RewardCount = rewardCount; 522 | 523 | auto it = _rewards.find(mode); 524 | if (it == _rewards.end()) 525 | { 526 | std::vector rewards; 527 | _rewards.emplace(mode, rewards); 528 | 529 | it = _rewards.find(mode); 530 | if (it == _rewards.end()) 531 | { 532 | LOG_ERROR("module", "An error occurred when trying to populate rewards map!"); 533 | return; 534 | } 535 | } 536 | 537 | it->second.push_back(reward); 538 | count++; 539 | } while (qResult->NextRow()); 540 | 541 | LOG_INFO("module", "Loaded '{}' rows from 'hardmode_rewards' table.", count); 542 | } 543 | else 544 | { 545 | LOG_INFO("module", "Loaded '0' rows from 'hardmode_rewards' table."); 546 | } 547 | } 548 | 549 | void HardModeHandler::ClearRewards() 550 | { 551 | _rewards.clear(); 552 | } 553 | 554 | std::map>* HardModeHandler::GetRewards() 555 | { 556 | return &_rewards; 557 | } 558 | 559 | std::vector* HardModeHandler::GetRewardsForMode(uint8 mode) 560 | { 561 | auto it = _rewards.find(mode); 562 | if (it != _rewards.end()) 563 | { 564 | return &it->second; 565 | } 566 | 567 | return nullptr; 568 | } 569 | 570 | void HardModeHandler::TryRewardPlayer(Player* player, std::vector rewards) 571 | { 572 | for (auto reward : rewards) 573 | { 574 | switch (reward.Type) 575 | { 576 | case HardModeRewardType::HARDMODE_REWARD_TYPE_TITLE: 577 | RewardTitle(player, reward.RewardId); 578 | break; 579 | 580 | case HardModeRewardType::HARDMODE_REWARD_TYPE_SPELL: 581 | RewardSpell(player, reward.RewardId); 582 | break; 583 | } 584 | } 585 | 586 | RewardItems(player, rewards); 587 | } 588 | 589 | void HardModeHandler::RewardItems(Player* player, std::vector rewards) 590 | { 591 | std::vector> mailItems; 592 | uint8 mode = 0; 593 | 594 | for (auto const& reward : rewards) 595 | { 596 | if (reward.Type == HardModeRewardType::HARDMODE_REWARD_TYPE_ITEM) 597 | { 598 | mailItems.push_back(std::make_pair(reward.RewardId, reward.RewardCount)); 599 | mode = reward.Mode; 600 | } 601 | } 602 | 603 | if (mailItems.size() < 1) 604 | { 605 | return; 606 | } 607 | 608 | std::string hardModeName = sHardModeHandler->GetNameFromMode(mode); 609 | std::string header = Acore::StringFormat("{} Rewards", hardModeName); 610 | std::string body = Acore::StringFormat("Congratulations on reaching level {} on {} mode, enjoy your rewards!", player->GetLevel(), hardModeName); 611 | 612 | SendMailItems(player, mailItems, header, body); 613 | } 614 | 615 | void HardModeHandler::RewardTitle(Player* player, uint32 titleId) 616 | { 617 | auto titleEntry = sCharTitlesStore.LookupEntry(titleId); 618 | 619 | if (!titleEntry) 620 | { 621 | LOG_ERROR("module", "No title with entry '{}' found while rewarding player '{}'.", titleId, player->GetName()); 622 | return; 623 | } 624 | 625 | player->SetTitle(titleEntry); 626 | } 627 | 628 | void HardModeHandler::RewardSpell(Player* player, uint32 spellId) 629 | { 630 | auto spellEntry = sSpellStore.LookupEntry(spellId); 631 | 632 | if (!spellEntry) 633 | { 634 | LOG_ERROR("module", "No spell with entry '{}' found while rewarding player '{}'.", spellId, player->GetName()); 635 | return; 636 | } 637 | 638 | player->learnSpell(spellId); 639 | } 640 | 641 | void HardModeHandler::SendMailItems(Player* player, std::vector>& mailItems, std::string header, std::string body) 642 | { 643 | using SendMailTempateVector = std::vector>; 644 | 645 | std::vector allItems; 646 | 647 | auto AddMailItem = [&allItems](uint32 itemEntry, uint32 itemCount) 648 | { 649 | SendMailTempateVector toSendItems; 650 | 651 | ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemEntry); 652 | if (!itemTemplate) 653 | { 654 | LOG_ERROR("entities.player.items", "> HardModeHandler::SendMailItems: Item id {} is invalid", itemEntry); 655 | return; 656 | } 657 | 658 | if (itemCount < 1 || (itemTemplate->MaxCount > 0 && itemCount > static_cast(itemTemplate->MaxCount))) 659 | { 660 | LOG_ERROR("entities.player.items", "> HardModeHandler::SendMailItems: Incorrect item count ({}) for item id {}", itemCount, itemEntry); 661 | return; 662 | } 663 | 664 | while (itemCount > itemTemplate->GetMaxStackSize()) 665 | { 666 | if (toSendItems.size() <= MAX_MAIL_ITEMS) 667 | { 668 | toSendItems.emplace_back(itemEntry, itemTemplate->GetMaxStackSize()); 669 | itemCount -= itemTemplate->GetMaxStackSize(); 670 | } 671 | else 672 | { 673 | allItems.emplace_back(toSendItems); 674 | toSendItems.clear(); 675 | } 676 | } 677 | 678 | toSendItems.emplace_back(itemEntry, itemCount); 679 | allItems.emplace_back(toSendItems); 680 | }; 681 | 682 | for (auto& [itemEntry, itemCount] : mailItems) 683 | { 684 | AddMailItem(itemEntry, itemCount); 685 | } 686 | 687 | CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); 688 | 689 | MailSender sender(MAIL_CREATURE, HARDMODE_MAIL_SENDER); 690 | MailDraft draft(header, body); 691 | 692 | for (auto const& items : allItems) 693 | { 694 | for (auto const& [itemEntry, itemCount] : items) 695 | { 696 | if (Item* mailItem = Item::CreateItem(itemEntry, itemCount)) 697 | { 698 | mailItem->SaveToDB(trans); 699 | draft.AddItem(mailItem); 700 | } 701 | } 702 | } 703 | 704 | draft.SendMailTo(trans, MailReceiver(player, player->GetGUID().GetCounter()), sender); 705 | 706 | CharacterDatabase.CommitTransaction(trans); 707 | } 708 | 709 | void HardModeHandler::SendAlert(Player* player, std::string message) 710 | { 711 | WorldPacket data(SMSG_NOTIFICATION, (message.size() + 1)); 712 | data << message; 713 | 714 | player->SendDirectMessage(&data); 715 | } 716 | 717 | bool HardModeHandler::IsModeEnabledForPlayer(ObjectGuid guid, uint8 mode) 718 | { 719 | if (!guid) 720 | { 721 | return false; 722 | } 723 | 724 | auto playerModes = sHardModeHandler->GetPlayerSetting(guid)->Modes; 725 | if (playerModes.size() < 1) 726 | { 727 | return false; 728 | } 729 | 730 | for (auto it = playerModes.begin(); it != playerModes.end(); ++it) 731 | { 732 | auto pMode = *it; 733 | if (pMode == mode) 734 | { 735 | return true; 736 | } 737 | } 738 | 739 | return false; 740 | } 741 | 742 | void HardModeHandler::UpdateModeForPlayer(ObjectGuid guid, uint8 mode, bool state) 743 | { 744 | if (!guid) 745 | { 746 | return; 747 | } 748 | 749 | auto modes = &sHardModeHandler->GetPlayerSetting(guid)->Modes; 750 | 751 | auto it = std::find(modes->begin(), modes->end(), mode); 752 | 753 | if (state) 754 | { 755 | if (it == modes->end()) 756 | { 757 | modes->push_back(mode); 758 | } 759 | } 760 | else 761 | { 762 | if (it != modes->end()) 763 | { 764 | modes->erase(it); 765 | } 766 | } 767 | 768 | auto player = ObjectAccessor::FindPlayer(guid); 769 | 770 | if (player) 771 | { 772 | sHardModeHandler->ValidatePlayerAuras(player); 773 | 774 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_SMALLFISH)) 775 | { 776 | sHardModeHandler->UpdatePlayerScaleSpeed(player, SMALLFISH_SCALE); 777 | } 778 | else 779 | { 780 | sHardModeHandler->UpdatePlayerScaleSpeed(player, 1); 781 | } 782 | } 783 | } 784 | 785 | bool HardModeHandler::PlayerHasRestriction(ObjectGuid guid, uint32 restriction) 786 | { 787 | auto modes = sHardModeHandler->GetHardModes(); 788 | 789 | for (auto it = modes->begin(); it != modes->end(); ++it) 790 | { 791 | auto mode = it->second; 792 | 793 | if (!mode.Enabled) 794 | { 795 | continue; 796 | } 797 | 798 | if (mode.Restrictions == HARDMODE_RESTRICT_NONE) 799 | { 800 | continue; 801 | } 802 | 803 | if (!sHardModeHandler->IsModeEnabledForPlayer(guid, mode.Id)) 804 | { 805 | continue; 806 | } 807 | 808 | auto rMask = (1 << restriction); 809 | bool hasRestriction = (mode.Restrictions & rMask) == rMask; 810 | 811 | if (hasRestriction) 812 | { 813 | return true; 814 | } 815 | } 816 | 817 | return false; 818 | } 819 | 820 | std::vector HardModeHandler::GetPlayerModesFromRestriction(ObjectGuid guid, uint32 restriction) 821 | { 822 | auto modes = sHardModeHandler->GetHardModes(); 823 | std::vector enabledModes; 824 | 825 | for (auto it = modes->begin(); it != modes->end(); ++it) 826 | { 827 | auto mode = it->second; 828 | 829 | if (!mode.Enabled) 830 | { 831 | continue; 832 | } 833 | 834 | if (mode.Restrictions == HARDMODE_RESTRICT_NONE) 835 | { 836 | continue; 837 | } 838 | 839 | if (!sHardModeHandler->IsModeEnabledForPlayer(guid, mode.Id)) 840 | { 841 | continue; 842 | } 843 | 844 | auto rMask = (1 << restriction); 845 | bool hasRestriction = (mode.Restrictions & rMask) == rMask; 846 | 847 | if (hasRestriction) 848 | { 849 | enabledModes.push_back(mode); 850 | } 851 | } 852 | 853 | return enabledModes; 854 | } 855 | 856 | std::string HardModeHandler::GetDelimitedModes(std::vector modes, std::string delimiter) 857 | { 858 | std::stringstream ss; 859 | 860 | for (uint8 i = 0; i < modes.size(); ++i) 861 | { 862 | ss << modes[i].Name; 863 | 864 | if (i != modes.size() - 1) 865 | { 866 | ss << delimiter; 867 | } 868 | } 869 | 870 | return ss.str(); 871 | } 872 | 873 | bool HardModeHandler::HasMatchingModesWithRestriction(Player* player, Player* target, uint32 restriction) 874 | { 875 | auto hardModes = sHardModeHandler->GetHardModes(); 876 | 877 | for (auto it = hardModes->begin(); it != hardModes->end(); ++it) 878 | { 879 | auto mode = it->second; 880 | 881 | if (!mode.Enabled) 882 | { 883 | continue; 884 | } 885 | 886 | if (!sHardModeHandler->ModeHasRestriction(mode.Id, restriction)) 887 | { 888 | continue; 889 | } 890 | 891 | bool flag1 = (sHardModeHandler->IsModeEnabledForPlayer(player->GetGUID(), mode.Id)); 892 | bool flag2 = (sHardModeHandler->IsModeEnabledForPlayer(target->GetGUID(), mode.Id)); 893 | 894 | if (flag1 != flag2) 895 | { 896 | return false; 897 | } 898 | } 899 | 900 | return true; 901 | } 902 | 903 | bool HardModeHandler::ModeHasRestriction(uint8 mode, uint32 restriction) 904 | { 905 | auto modes = sHardModeHandler->GetHardModes(); 906 | auto modeIt = modes->find(mode); 907 | 908 | if (modeIt == modes->end()) 909 | { 910 | return false; 911 | } 912 | 913 | auto rMask = (1 << restriction); 914 | bool hasRestriction = (modeIt->second.Restrictions & rMask) == rMask; 915 | 916 | return hasRestriction; 917 | } 918 | 919 | bool HardModeHandler::IsPlayerTainted(ObjectGuid guid) 920 | { 921 | auto playerSettings = sHardModeHandler->GetPlayerSetting(guid); 922 | if (!playerSettings) 923 | { 924 | return false; 925 | } 926 | 927 | return playerSettings->Tainted; 928 | } 929 | 930 | void HardModeHandler::UpdatePlayerTainted(ObjectGuid guid, bool state) 931 | { 932 | auto playerSettings = sHardModeHandler->GetPlayerSetting(guid); 933 | if (!playerSettings) 934 | { 935 | return; 936 | } 937 | 938 | playerSettings->Tainted = state; 939 | } 940 | 941 | bool HardModeHandler::CanTaintPlayer(ObjectGuid guid) 942 | { 943 | auto player = ObjectAccessor::FindPlayer(guid); 944 | if (player && player->getClass() == CLASS_DEATH_KNIGHT && player->GetMapId() == HARDMODE_AREA_EBONHOLD) 945 | { 946 | if (!player->IsQuestRewarded(HARDMODE_QUEST_DK_INITIAL)) 947 | { 948 | return false; 949 | } 950 | } 951 | 952 | return true; 953 | } 954 | 955 | bool HardModeHandler::IsPlayerShadowBanned(ObjectGuid guid) 956 | { 957 | auto playerSettings = sHardModeHandler->GetPlayerSetting(guid); 958 | if (!playerSettings) 959 | { 960 | return false; 961 | } 962 | 963 | return playerSettings->ShadowBanned; 964 | } 965 | 966 | void HardModeHandler::UpdatePlayerShadowBanned(ObjectGuid guid, bool state) 967 | { 968 | auto playerSettings = sHardModeHandler->GetPlayerSetting(guid); 969 | if (!playerSettings) 970 | { 971 | return; 972 | } 973 | 974 | playerSettings->ShadowBanned = state; 975 | 976 | auto player = ObjectAccessor::FindPlayer(guid); 977 | 978 | if (player) 979 | { 980 | if (state) 981 | { 982 | if (!player->HasAura(HARDMODE_AURA_SHADOWBAN)) 983 | { 984 | player->AddAura(HARDMODE_AURA_SHADOWBAN, player); 985 | } 986 | } 987 | else 988 | { 989 | if (player->HasAura(HARDMODE_AURA_SHADOWBAN)) 990 | { 991 | player->RemoveAura(HARDMODE_AURA_SHADOWBAN); 992 | } 993 | } 994 | } 995 | } 996 | 997 | void HardModeHandler::TryShadowBanPlayer(ObjectGuid guid) 998 | { 999 | sHardModeHandler->UpdatePlayerShadowBanned(guid, true); 1000 | 1001 | auto player = ObjectAccessor::FindPlayer(guid); 1002 | 1003 | if (player) 1004 | { 1005 | WorldLocation worldLoc(HARDMODE_AREA_AZSHARACRATER, -614.38, -239.69, 379.35, 0.69); // Azshara Crater / Shadow Tomb 1006 | player->TeleportTo(worldLoc); 1007 | player->SetHomebind(worldLoc, HARDMODE_AREA_SHADOWTOMB); 1008 | 1009 | if (!player->IsAlive()) 1010 | { 1011 | player->ResurrectPlayer(100, false); 1012 | player->RemoveCorpse(); 1013 | } 1014 | } 1015 | } 1016 | 1017 | std::string HardModeHandler::GetNamesFromEnabledModes(Player* player) 1018 | { 1019 | std::stringstream ss; 1020 | std::vector modes; 1021 | 1022 | auto hardModes = sHardModeHandler->GetHardModes(); 1023 | for (auto mode = hardModes->begin(); mode != hardModes->end(); ++mode) 1024 | { 1025 | if (sHardModeHandler->IsModeEnabledForPlayer(player->GetGUID(), mode->second.Id)) 1026 | { 1027 | modes.push_back(mode->second); 1028 | } 1029 | } 1030 | 1031 | for (uint8 i = 0; i < modes.size(); ++i) 1032 | { 1033 | ss << modes[i].Name; 1034 | 1035 | if (i != modes.size() - 1) 1036 | { 1037 | ss << ", "; 1038 | } 1039 | } 1040 | 1041 | return ss.str(); 1042 | } 1043 | 1044 | std::string HardModeHandler::GetNameFromMode(uint8 id) 1045 | { 1046 | auto hardModes = sHardModeHandler->GetHardModes(); 1047 | 1048 | auto mode = hardModes->find(id); 1049 | 1050 | if (mode != hardModes->end()) 1051 | { 1052 | return mode->second.Name; 1053 | } 1054 | 1055 | return "Unknown"; 1056 | } 1057 | 1058 | ObjectGuid* HardModeHandler::GetGUIDFromPlayerName(std::string playerName) 1059 | { 1060 | QueryResult qResult = CharacterDatabase.Query("SELECT guid FROM characters WHERE name = '{}'", playerName); 1061 | 1062 | if (qResult) 1063 | { 1064 | Field* fields = qResult->Fetch(); 1065 | uint64 guid = fields[0].Get(); 1066 | 1067 | return new ObjectGuid(guid); 1068 | } 1069 | 1070 | return nullptr; 1071 | } 1072 | 1073 | PlayerSettingMap* HardModeHandler::GetPlayerSettingsFromDatabase(ObjectGuid guid) 1074 | { 1075 | PlayerSettingMap* settingMap = new PlayerSettingMap(); 1076 | 1077 | auto result = CharacterDatabase.Query("SELECT source, data FROM character_settings WHERE guid = {}", guid.GetRawValue()); 1078 | 1079 | if (result) 1080 | { 1081 | do 1082 | { 1083 | Field* fields = result->Fetch(); 1084 | 1085 | std::string source = fields[0].Get(); 1086 | std::string data = fields[1].Get(); 1087 | 1088 | std::vector tokens = Acore::Tokenize(data, ' ', false); 1089 | 1090 | PlayerSettingVector setting; 1091 | setting.resize(tokens.size()); 1092 | 1093 | uint32 count = 0; 1094 | 1095 | for (auto token : tokens) 1096 | { 1097 | if (token.empty()) 1098 | { 1099 | continue; 1100 | } 1101 | 1102 | PlayerSetting set; 1103 | set.value = Acore::StringTo(token).value(); 1104 | setting[count] = set; 1105 | ++count; 1106 | } 1107 | 1108 | (*settingMap)[source] = setting; 1109 | 1110 | } while (result->NextRow()); 1111 | } 1112 | 1113 | return settingMap; 1114 | } 1115 | 1116 | TaskScheduler* HardModeHandler::GetScheduler() 1117 | { 1118 | return &_scheduler; 1119 | } 1120 | -------------------------------------------------------------------------------- /src/HardModeHandler.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_HARDMODE_HANDLER_H 2 | #define MODULE_HARDMODE_HANDLER_H 3 | 4 | #include "HardModeTypes.h" 5 | 6 | #include "Config.h" 7 | #include "Player.h" 8 | #include "TaskScheduler.h" 9 | 10 | #include 11 | #include 12 | 13 | class HardModeHandler 14 | { 15 | private: 16 | HardModeHandler() { } 17 | 18 | public: 19 | bool IsHardModeEnabled(); 20 | 21 | void LoadHardModes(); 22 | void ClearHardModes(); 23 | std::map* GetHardModes(); 24 | HardModeInfo* GetHardModeFromId(uint8 id); 25 | 26 | void LoadPlayerSettings(); 27 | void LoadPlayerSettings(ObjectGuid guid); 28 | void DeletePlayerSetting(uint64 guid); 29 | void ClearPlayerSettings(); 30 | void SavePlayerSettings(); 31 | void SavePlayerSetting(uint64 guid, HardModePlayerSettings* settings); 32 | void UpdatePlayerSettings(ObjectGuid guid, HardModePlayerSettings* settings); 33 | std::map* GetPlayerSettings(); 34 | HardModePlayerSettings* GetPlayerSetting(ObjectGuid guid); 35 | 36 | void LoadSelfCraftExcludeIds(); 37 | void ClearSelfCraftExcludeIds(); 38 | std::vector* GetSelfCraftedExcludeIds(); 39 | bool IsSelfCraftExcluded(int32 id); 40 | bool IsSelfCraftSpellExcluded(uint32 spellId); 41 | bool IsSelfCraftItemExcluded(uint32 itemId); 42 | 43 | void LoadAuras(); 44 | void ClearAuras(); 45 | std::map>* GetAuras(); 46 | std::vector* GetAurasForMode(uint8 mode); 47 | void ValidatePlayerAuras(Player* player); 48 | 49 | void UpdatePlayerScaleSpeed(Player* player, float scaleSpeed); 50 | 51 | void LoadRewards(); 52 | void ClearRewards(); 53 | std::map>* GetRewards(); 54 | std::vector* GetRewardsForMode(uint8 mode); 55 | void TryRewardPlayer(Player* player, std::vector rewards); 56 | void RewardItems(Player* player, std::vector rewards); 57 | void RewardTitle(Player* player, uint32 titleId); 58 | void RewardSpell(Player* player, uint32 spellId); 59 | void SendMailItems(Player* player, std::vector>& mailItems, std::string header, std::string body); 60 | 61 | void SendAlert(Player* player, std::string message); 62 | 63 | bool IsModeEnabledForPlayer(ObjectGuid guid, uint8 mode); 64 | void UpdateModeForPlayer(ObjectGuid guid, uint8 mode, bool state); 65 | bool PlayerHasRestriction(ObjectGuid guid, uint32 restriction); 66 | std::vector GetPlayerModesFromRestriction(ObjectGuid guid, uint32 restriction); 67 | std::string GetDelimitedModes(std::vector modes, std::string delimiter); 68 | bool HasMatchingModesWithRestriction(Player* player, Player* target, uint32 restriction); 69 | bool ModeHasRestriction(uint8 mode, uint32 restriction); 70 | 71 | bool IsPlayerTainted(ObjectGuid guid); 72 | void UpdatePlayerTainted(ObjectGuid guid, bool state); 73 | bool CanTaintPlayer(ObjectGuid guid); 74 | 75 | bool IsPlayerShadowBanned(ObjectGuid guid); 76 | void UpdatePlayerShadowBanned(ObjectGuid guid, bool state); 77 | void TryShadowBanPlayer(ObjectGuid guid); 78 | 79 | std::string GetNamesFromEnabledModes(Player* player); 80 | std::string GetNameFromMode(uint8 mode); 81 | ObjectGuid* GetGUIDFromPlayerName(std::string playerName); 82 | 83 | PlayerSettingMap* GetPlayerSettingsFromDatabase(ObjectGuid guid); 84 | TaskScheduler* GetScheduler(); 85 | 86 | private: 87 | std::map _hardModes; 88 | std::map _playerSettings; 89 | std::vector _selfCraftExcludeIds; 90 | std::map> _rewards; 91 | std::map> _auras; 92 | TaskScheduler _scheduler; 93 | 94 | public: 95 | static HardModeHandler* GetInstance() 96 | { 97 | static HardModeHandler instance; 98 | 99 | return &instance; 100 | } 101 | }; 102 | 103 | #define sHardModeHandler HardModeHandler::GetInstance() 104 | 105 | #endif // MODULE_HARDMODE_HANDLER_H 106 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksGlobal.cpp: -------------------------------------------------------------------------------- 1 | #include "HardModeHooks/HardModeHooksGlobal.h" 2 | #include "HardModeHandler.h" 3 | 4 | #include "Config.h" 5 | #include "LootMgr.h" 6 | 7 | void HardModeHooksGlobalScript::OnBeforeDropAddItem(Player const* player, Loot& /*loot*/, bool /*canRate*/, uint16 /*lootMode*/, LootStoreItem* lootStoreItem, LootStore const& /*store*/) 8 | { 9 | if (!sHardModeHandler->IsHardModeEnabled()) 10 | { 11 | return; 12 | } 13 | 14 | auto ncPlayer = const_cast(player); 15 | 16 | if (sHardModeHandler->PlayerHasRestriction(ncPlayer->GetGUID(), HARDMODE_RESTRICT_BAD_LUCK)) 17 | { 18 | if (!lootStoreItem || 19 | !lootStoreItem->itemid) 20 | { 21 | return; 22 | } 23 | 24 | auto itemProto = sObjectMgr->GetItemTemplate(lootStoreItem->itemid); 25 | if (!itemProto) 26 | { 27 | return; 28 | } 29 | 30 | // Quest items should still drop normally.. 31 | if (lootStoreItem->needs_quest || 32 | itemProto->Class == ITEM_CLASS_QUEST) 33 | { 34 | return; 35 | } 36 | 37 | auto roll = urand(0, 100); 38 | uint32 chance = sConfigMgr->GetOption("HardMode.Restrict.BadLuck.Chance", 10); 39 | if (roll <= chance) 40 | { 41 | // If the roll is higher than x percent then it is deleted. 42 | lootStoreItem->itemid = 0; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksGlobal.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_HARDMODE_HOOKS_GLOBAL_H 2 | #define MODULE_HARDMODE_HOOKS_GLOBAL_H 3 | 4 | #include "ScriptMgr.h" 5 | 6 | class HardModeHooksGlobalScript : GlobalScript 7 | { 8 | public: 9 | HardModeHooksGlobalScript() : GlobalScript("HardModeHooksGlobalScript") { } 10 | 11 | private: 12 | void OnBeforeDropAddItem(Player const* player, Loot& loot, bool canRate, uint16 lootMode, LootStoreItem* lootStoreItem, LootStore const& store) override; 13 | }; 14 | 15 | #endif // MODULE_HARDMODE_HOOKS_GLOBAL_H 16 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksGuild.cpp: -------------------------------------------------------------------------------- 1 | #include "HardModeHooks/HardModeHooksGuild.h" 2 | #include "HardModeHandler.h" 3 | #include "HardModeTypes.h" 4 | 5 | bool HardModeHooksGuildScript::CanGuildSendBankList(Guild const* /*guild*/, WorldSession* session, uint8 /*tabId*/, bool /*sendAllSlots*/) 6 | { 7 | if (!sHardModeHandler->IsHardModeEnabled()) 8 | { 9 | return true; 10 | } 11 | 12 | if (!session) 13 | { 14 | return true; 15 | } 16 | 17 | Player* player = session->GetPlayer(); 18 | if (!player) 19 | { 20 | return true; 21 | } 22 | 23 | if (!sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_GUILDBANK)) 24 | { 25 | return true; 26 | } 27 | 28 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_GUILDBANK); 29 | std::string alert = Acore::StringFormat("You cannot use the guild bank in the {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 30 | sHardModeHandler->SendAlert(player, alert); 31 | 32 | return false; 33 | } 34 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksGuild.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_HARDMODE_HOOKS_GUILD_H 2 | #define MODULE_HARDMODE_HOOKS_GUILD_H 3 | 4 | #include "ScriptMgr.h" 5 | 6 | class HardModeHooksGuildScript : GuildScript 7 | { 8 | public: 9 | HardModeHooksGuildScript() : GuildScript("HardModeHooksGuildScript") { } 10 | 11 | private: 12 | bool CanGuildSendBankList(Guild const* guild, WorldSession* session, uint8 tabId, bool sendAllSlots) override; 13 | }; 14 | 15 | #endif // MODULE_HARDMODE_HOOKS_GUILD_H 16 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksMisc.cpp: -------------------------------------------------------------------------------- 1 | #include "HardModeHooks/HardModeHooksMisc.h" 2 | #include "HardModeHandler.h" 3 | 4 | #include "Player.h" 5 | 6 | bool HardModeHooksMiscScript::CanSendAuctionHello(WorldSession const* session, ObjectGuid /*guid*/, Creature* /*creature*/) 7 | { 8 | if (!sHardModeHandler->IsHardModeEnabled()) 9 | { 10 | return true; 11 | } 12 | 13 | Player* player = session->GetPlayer(); 14 | if (!player) 15 | { 16 | return true; 17 | } 18 | 19 | if (!sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_AUCTION)) 20 | { 21 | return true; 22 | } 23 | 24 | 25 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_AUCTION); 26 | std::string alert = Acore::StringFormat("You cannot use the auction house in the {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 27 | sHardModeHandler->SendAlert(player, alert); 28 | 29 | return false; 30 | } 31 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksMisc.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_HARDMODE_HOOKS_MISC_H 2 | #define MODULE_HARDMODE_HOOKS_MISC_H 3 | 4 | #include "ScriptMgr.h" 5 | 6 | class HardModeHooksMiscScript : MiscScript 7 | { 8 | public: 9 | HardModeHooksMiscScript() : MiscScript("HardModeHooksMiscScript") { } 10 | 11 | private: 12 | bool CanSendAuctionHello(WorldSession const* session, ObjectGuid guid, Creature* creature) override; 13 | }; 14 | 15 | #endif // MODULE_HARDMODE_HOOKS_MISC_H 16 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksPlayer.cpp: -------------------------------------------------------------------------------- 1 | #include "HardModeHooks/HardModeHooksPlayer.h" 2 | #include "HardModeHandler.h" 3 | #include "HardModeTypes.h" 4 | 5 | #include "Config.h" 6 | #include "Player.h" 7 | 8 | void HardModeHooksPlayerScript::OnGiveXP(Player* player, uint32& amount, Unit* /*victim*/, uint8 xpSource) 9 | { 10 | if (!sHardModeHandler->IsHardModeEnabled()) 11 | { 12 | return; 13 | } 14 | 15 | if (!player) 16 | { 17 | return; 18 | } 19 | 20 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_RETAIL_XP)) 21 | { 22 | switch (xpSource) 23 | { 24 | case PlayerXPSource::XPSOURCE_KILL: 25 | amount = (amount / sConfigMgr->GetOption("Rate.XP.Kill", 1)); 26 | break; 27 | 28 | case PlayerXPSource::XPSOURCE_EXPLORE: 29 | amount = (amount / sConfigMgr->GetOption("Rate.XP.Explore", 1)); 30 | break; 31 | } 32 | } 33 | 34 | if (sHardModeHandler->CanTaintPlayer(player->GetGUID())) 35 | { 36 | sHardModeHandler->UpdatePlayerTainted(player->GetGUID(), true); 37 | } 38 | } 39 | 40 | void HardModeHooksPlayerScript::OnQuestComputeXP(Player* player, Quest const* /*quest*/, uint32& xpValue) 41 | { 42 | if (!sHardModeHandler->IsHardModeEnabled()) 43 | { 44 | return; 45 | } 46 | 47 | if (!player) 48 | { 49 | return; 50 | } 51 | 52 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_RETAIL_XP)) 53 | { 54 | xpValue = (xpValue / sConfigMgr->GetOption("Rate.XP.Quest", 1)); 55 | } 56 | } 57 | 58 | bool HardModeHooksPlayerScript::CanEquipItem(Player* player, uint8 /*slot*/, uint16& /*dest*/, Item* pItem, bool /*swap*/, bool /*notLoading*/) 59 | { 60 | if (!sHardModeHandler->IsHardModeEnabled()) 61 | { 62 | return true; 63 | } 64 | 65 | if (!player) 66 | { 67 | return true; 68 | } 69 | 70 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_SELFCRAFTED)) 71 | { 72 | auto itemProto = pItem->GetTemplate(); 73 | 74 | // Exclude item ids in the `hardmode_selfcraft_exclude` table. 75 | if (sHardModeHandler->IsSelfCraftItemExcluded(itemProto->ItemId)) 76 | { 77 | return true; 78 | } 79 | 80 | // Allow quest items to be equipped. 81 | if (itemProto->Class == ITEM_CLASS_QUEST) 82 | { 83 | return true; 84 | } 85 | 86 | // If the item is not creator by the player, block equip. 87 | if (pItem->GetGuidValue(ITEM_FIELD_CREATOR) != player->GetGUID()) 88 | { 89 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(player->GetGUID(), HARDMODE_RESTRICT_SELFCRAFTED); 90 | std::string alert = Acore::StringFormat("You cannot equip this item while in the {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 91 | sHardModeHandler->SendAlert(player, alert); 92 | 93 | return false; 94 | } 95 | } 96 | 97 | return true; 98 | } 99 | 100 | bool HardModeHooksPlayerScript::CanCastItemUseSpell(Player* player, Item* item, SpellCastTargets const& /*targets*/, uint8 /*castCount*/, uint32 /*glyphIndex*/) 101 | { 102 | if (!sHardModeHandler->IsHardModeEnabled()) 103 | { 104 | return true; 105 | } 106 | 107 | if (!player) 108 | { 109 | return true; 110 | } 111 | 112 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_SELFCRAFTED)) 113 | { 114 | // Exclude spell ids in the `hardmode_selfcraft_exclude` table. 115 | if (sHardModeHandler->IsSelfCraftSpellExcluded(item->GetTemplate()->Spells[0].SpellId)) 116 | { 117 | return true; 118 | } 119 | 120 | auto itemProto = item->GetTemplate(); 121 | 122 | // Only consider blocking on consumables. 123 | if (itemProto->Class != ITEM_CLASS_CONSUMABLE) 124 | { 125 | return true; 126 | } 127 | 128 | if (itemProto->SubClass != ITEM_SUBCLASS_FOOD && 129 | itemProto->SubClass != ITEM_SUBCLASS_POTION && 130 | itemProto->SubClass != ITEM_SUBCLASS_ELIXIR && 131 | itemProto->SubClass != ITEM_SUBCLASS_FLASK) 132 | { 133 | return true; 134 | } 135 | 136 | if (item->GetGuidValue(ITEM_FIELD_CREATOR) != player->GetGUID()) 137 | { 138 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(player->GetGUID(), HARDMODE_RESTRICT_SELFCRAFTED); 139 | std::string alert = Acore::StringFormat("You cannot use this item while in the {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 140 | sHardModeHandler->SendAlert(player, alert); 141 | 142 | return false; 143 | } 144 | } 145 | 146 | return true; 147 | } 148 | 149 | void HardModeHooksPlayerScript::OnCreateItem(Player* player, Item* item, uint32 /*count*/) 150 | { 151 | if (!sHardModeHandler->IsHardModeEnabled()) 152 | { 153 | return; 154 | } 155 | 156 | if (!player || !item) 157 | { 158 | return; 159 | } 160 | 161 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_SELFCRAFTED)) 162 | { 163 | if (!sConfigMgr->GetOption("HardMode.Restrict.SelfCrafted.CreatedBy", true)) 164 | { 165 | return; 166 | } 167 | 168 | auto itemProto = item->GetTemplate(); 169 | 170 | if (itemProto->Class != ITEM_CLASS_CONSUMABLE) 171 | { 172 | return; 173 | } 174 | 175 | item->SetGuidValue(ITEM_FIELD_CREATOR, player->GetGUID()); 176 | } 177 | } 178 | 179 | void HardModeHooksPlayerScript::OnPlayerResurrect(Player* player, float /*restorePercent*/, bool /*applySickness*/) 180 | { 181 | if (!sHardModeHandler->IsHardModeEnabled()) 182 | { 183 | return; 184 | } 185 | 186 | if (!player) 187 | { 188 | return; 189 | } 190 | 191 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_PERMADEATH)) 192 | { 193 | sHardModeHandler->TryShadowBanPlayer(player->GetGUID()); 194 | } 195 | 196 | sHardModeHandler->ValidatePlayerAuras(player); 197 | } 198 | 199 | void HardModeHooksPlayerScript::OnPlayerReleasedGhost(Player* player) 200 | { 201 | if (!sHardModeHandler->IsHardModeEnabled()) 202 | { 203 | return; 204 | } 205 | 206 | if (!player) 207 | { 208 | return; 209 | } 210 | 211 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_PERMADEATH)) 212 | { 213 | sHardModeHandler->TryShadowBanPlayer(player->GetGUID()); 214 | } 215 | } 216 | 217 | bool HardModeHooksPlayerScript::CanRepopAtGraveyard(Player* player) 218 | { 219 | if (!sHardModeHandler->IsHardModeEnabled()) 220 | { 221 | return true; 222 | } 223 | 224 | if (!player) 225 | { 226 | return true; 227 | } 228 | 229 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_PERMADEATH)) 230 | { 231 | return false; 232 | } 233 | 234 | return true; 235 | } 236 | 237 | bool HardModeHooksPlayerScript::OnBeforeTeleport(Player* player, uint32 mapId, float /*x*/, float /*y*/, float /*z*/, float /*orientation*/, uint32 /*options*/, Unit* /*target*/) 238 | { 239 | if (!sHardModeHandler->IsHardModeEnabled()) 240 | { 241 | return true; 242 | } 243 | 244 | if (sHardModeHandler->IsPlayerShadowBanned(player->GetGUID())) 245 | { 246 | return (mapId == HARDMODE_AREA_AZSHARACRATER); // Only allow teleports for Shadowban players if it's to the azshara crater / shadow tomb. 247 | } 248 | 249 | return true; 250 | } 251 | 252 | void HardModeHooksPlayerScript::OnPlayerLearnTalents(Player* player, uint32 /*talentId*/, uint32 /*talentRank*/, uint32 /*spellId*/) 253 | { 254 | if (!player) 255 | { 256 | return; 257 | } 258 | 259 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_TALENTS)) 260 | { 261 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_TALENTS); 262 | std::string alert = Acore::StringFormat("You cannot use talent points while in the {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 263 | sHardModeHandler->SendAlert(player, alert); 264 | 265 | player->resetTalents(true); 266 | } 267 | } 268 | 269 | bool HardModeHooksPlayerScript::CanInitTrade(Player* player, Player* target) 270 | { 271 | if (!sHardModeHandler->IsHardModeEnabled()) 272 | { 273 | return true; 274 | } 275 | 276 | if (!player || !target) 277 | { 278 | return true; 279 | } 280 | 281 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_TRADE)) 282 | { 283 | player->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); 284 | target->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); 285 | 286 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_TRADE); 287 | std::string alert = Acore::StringFormat("You cannot trade players while in the {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 288 | sHardModeHandler->SendAlert(player, alert); 289 | 290 | return false; 291 | } 292 | 293 | if (sHardModeHandler->PlayerHasRestriction(target->GetGUID(), HARDMODE_RESTRICT_INTERACT_TRADE)) 294 | { 295 | player->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); 296 | target->GetSession()->SendTradeStatus(TRADE_STATUS_TRADE_CANCELED); 297 | 298 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(target->GetGUID(), HARDMODE_RESTRICT_INTERACT_TRADE); 299 | std::string alert = Acore::StringFormat("You cannot trade players in the {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 300 | sHardModeHandler->SendAlert(player, alert); 301 | 302 | return false; 303 | } 304 | 305 | if (sHardModeHandler->CanTaintPlayer(player->GetGUID())) 306 | { 307 | sHardModeHandler->UpdatePlayerTainted(player->GetGUID(), true); 308 | } 309 | 310 | if (sHardModeHandler->CanTaintPlayer(target->GetGUID())) 311 | { 312 | sHardModeHandler->UpdatePlayerTainted(target->GetGUID(), true); 313 | } 314 | 315 | return true; 316 | } 317 | 318 | bool HardModeHooksPlayerScript::CanSendMail(Player* player, ObjectGuid receiverGuid, ObjectGuid /*mailbox*/, std::string& /*subject*/, std::string& /*body*/, uint32 /*money*/, uint32 /*cod*/, Item* /*item*/) 319 | { 320 | if (!sHardModeHandler->IsHardModeEnabled()) 321 | { 322 | return true; 323 | } 324 | 325 | if (!player) 326 | { 327 | return true; 328 | } 329 | 330 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_MAIL_SEND)) 331 | { 332 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_MAIL_SEND); 333 | std::string alert = Acore::StringFormat("You cannot send mail to other players while in the {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 334 | sHardModeHandler->SendAlert(player, alert); 335 | return false; 336 | } 337 | 338 | if (sHardModeHandler->PlayerHasRestriction(receiverGuid, HARDMODE_RESTRICT_INTERACT_MAIL_RECEIVE)) 339 | { 340 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(receiverGuid, HARDMODE_RESTRICT_INTERACT_MAIL_RECEIVE); 341 | std::string alert = Acore::StringFormat("You cannot send mail to players in the {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 342 | sHardModeHandler->SendAlert(player, alert); 343 | return false; 344 | } 345 | 346 | if (sHardModeHandler->CanTaintPlayer(player->GetGUID())) 347 | { 348 | sHardModeHandler->UpdatePlayerTainted(player->GetGUID(), true); 349 | } 350 | 351 | if (sHardModeHandler->CanTaintPlayer(receiverGuid)) 352 | { 353 | sHardModeHandler->UpdatePlayerTainted(receiverGuid, true); 354 | } 355 | 356 | return true; 357 | } 358 | 359 | bool HardModeHooksPlayerScript::CanJoinLfg(Player* player, uint8 /*roles*/, lfg::LfgDungeonSet& /*dungeons*/, const std::string& /*comment*/) 360 | { 361 | if (!sHardModeHandler->IsHardModeEnabled()) 362 | { 363 | return true; 364 | } 365 | 366 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_LFG)) 367 | { 368 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_LFG); 369 | std::string alert = Acore::StringFormat("You cannot join looking for group while in the {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 370 | sHardModeHandler->SendAlert(player, alert); 371 | return false; 372 | } 373 | 374 | return true; 375 | } 376 | 377 | bool HardModeHooksPlayerScript::CanGroupInvite(Player* player, std::string& memberName) 378 | { 379 | if (!sHardModeHandler->IsHardModeEnabled()) 380 | { 381 | return true; 382 | } 383 | 384 | Player* target = ObjectAccessor::FindPlayerByName(memberName); 385 | 386 | if (!target) 387 | { 388 | return true; 389 | } 390 | 391 | if (sHardModeHandler->PlayerHasRestriction(target->GetGUID(), HARDMODE_RESTRICT_INTERACT_GROUP_CROSSPLAY)) 392 | { 393 | if (!sHardModeHandler->HasMatchingModesWithRestriction(player, target, HARDMODE_RESTRICT_INTERACT_GROUP_CROSSPLAY)) 394 | { 395 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(target->GetGUID(), HARDMODE_RESTRICT_INTERACT_GROUP_CROSSPLAY); 396 | std::string alert = Acore::StringFormat("You cannot invite players if you aren't in the cross-play {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 397 | sHardModeHandler->SendAlert(player, alert); 398 | return false; 399 | } 400 | } 401 | 402 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_GROUP_CROSSPLAY)) 403 | { 404 | if (!sHardModeHandler->HasMatchingModesWithRestriction(player, target, HARDMODE_RESTRICT_INTERACT_GROUP_CROSSPLAY)) 405 | { 406 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_GROUP_CROSSPLAY); 407 | std::string alert = Acore::StringFormat("You cannot invite players that aren't in the cross-play {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 408 | sHardModeHandler->SendAlert(player, alert); 409 | return false; 410 | } 411 | } 412 | 413 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_GROUP)) 414 | { 415 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_GROUP); 416 | std::string alert = Acore::StringFormat("You cannot invite players while in the {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 417 | sHardModeHandler->SendAlert(player, alert); 418 | return false; 419 | } 420 | 421 | if (sHardModeHandler->PlayerHasRestriction(target->GetGUID(), HARDMODE_RESTRICT_INTERACT_GROUP)) 422 | { 423 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(target->GetGUID(), HARDMODE_RESTRICT_INTERACT_GROUP); 424 | std::string alert = Acore::StringFormat("You cannot invite players in the {} mode(s).", sHardModeHandler->GetDelimitedModes(restrictedModes, ", ")); 425 | sHardModeHandler->SendAlert(player, alert); 426 | return false; 427 | } 428 | 429 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_INTERACT_GROUP_RANGE) || 430 | sHardModeHandler->PlayerHasRestriction(target->GetGUID(), HARDMODE_RESTRICT_INTERACT_GROUP_RANGE)) 431 | { 432 | uint32 pLevel = player->GetLevel(); 433 | uint32 tLevel = target->GetLevel(); 434 | 435 | uint32 range = sConfigMgr->GetOption("HardMode.Restrict.Interact.Group.Range", 3); 436 | uint32 result = std::abs(int32(pLevel - tLevel)); 437 | if (result > range) 438 | { 439 | auto restrictedModes = sHardModeHandler->GetPlayerModesFromRestriction(target->GetGUID(), HARDMODE_RESTRICT_INTERACT_GROUP); 440 | std::string alert = Acore::StringFormat("You cannot invite players who are further than {} levels from you.", range); 441 | sHardModeHandler->SendAlert(player, alert); 442 | return false; 443 | } 444 | } 445 | 446 | return true; 447 | } 448 | 449 | void HardModeHooksPlayerScript::OnLogin(Player* player) 450 | { 451 | if (!sHardModeHandler->IsHardModeEnabled()) 452 | { 453 | return; 454 | } 455 | 456 | if (!player) 457 | { 458 | return; 459 | } 460 | 461 | sHardModeHandler->LoadPlayerSettings(player->GetGUID()); 462 | 463 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_SMALLFISH)) 464 | { 465 | // Schedule due to issues.. 466 | sHardModeHandler->GetScheduler()->Schedule(1s, [player](TaskContext /*task*/) 467 | { 468 | sHardModeHandler->UpdatePlayerScaleSpeed(player, SMALLFISH_SCALE); 469 | }); 470 | } 471 | 472 | sHardModeHandler->ValidatePlayerAuras(player); 473 | 474 | if (sHardModeHandler->IsPlayerShadowBanned(player->GetGUID())) 475 | { 476 | sHardModeHandler->UpdatePlayerShadowBanned(player->GetGUID(), false); 477 | sHardModeHandler->TryShadowBanPlayer(player->GetGUID()); 478 | } 479 | } 480 | 481 | void HardModeHooksPlayerScript::OnDelete(ObjectGuid guid, uint32 accountId) 482 | { 483 | if (!sHardModeHandler->IsHardModeEnabled()) 484 | { 485 | return; 486 | } 487 | 488 | sHardModeHandler->DeletePlayerSetting(guid.GetRawValue()); 489 | } 490 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksPlayer.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_HARDMODE_HOOKS_PLAYER_H 2 | #define MODULE_HARDMODE_HOOKS_PLAYER_H 3 | 4 | #include "Player.h" 5 | #include "ScriptMgr.h" 6 | 7 | class HardModeHooksPlayerScript : PlayerScript 8 | { 9 | public: 10 | HardModeHooksPlayerScript() : PlayerScript("HardModeHooksPlayerScript") { } 11 | 12 | private: 13 | void OnGiveXP(Player* player, uint32& amount, Unit* victim, uint8 xpSource) override; 14 | void OnQuestComputeXP(Player* player, Quest const* quest, uint32& xpValue) override; 15 | 16 | bool CanEquipItem(Player* player, uint8 slot, uint16& dest, Item* pItem, bool swap, bool notLoading) override; 17 | bool CanCastItemUseSpell(Player* player, Item* item, SpellCastTargets const& targets, uint8 castCount, uint32 glyphIndex) override; 18 | void OnCreateItem(Player* player, Item* item, uint32 count) override; 19 | 20 | void OnPlayerResurrect(Player* player, float restorePercent, bool applySickness) override; 21 | void OnPlayerReleasedGhost(Player* player) override; 22 | bool CanRepopAtGraveyard(Player* player) override; 23 | 24 | bool OnBeforeTeleport(Player* player, uint32 mapId, float x, float y, float z, float orientation, uint32 options, Unit* target) override; 25 | void OnPlayerLearnTalents(Player* player, uint32 talentId, uint32 talentRank, uint32 spellId) override; 26 | 27 | bool CanInitTrade(Player* player, Player* target) override; 28 | bool CanSendMail(Player* player, ObjectGuid receiverGuid, ObjectGuid mailbox, std::string& subject, std::string& body, uint32 money, uint32 cod, Item* item) override; 29 | bool CanJoinLfg(Player* player, uint8 roles, lfg::LfgDungeonSet& dungeons, const std::string& comment) override; 30 | bool CanGroupInvite(Player* player, std::string& memberName) override; 31 | 32 | void OnLogin(Player* player) override; 33 | void OnDelete(ObjectGuid guid, uint32 accountId) override; 34 | }; 35 | 36 | #endif // MODULE_HARDMODE_HOOKS_PLAYER_H 37 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksServer.cpp: -------------------------------------------------------------------------------- 1 | #include "HardModeHooks/HardModeHooksServer.h" 2 | #include "HardModeHandler.h" 3 | #include "HardModeTypes.h" 4 | 5 | #include "Config.h" 6 | #include "Guild.h" 7 | #include "Player.h" 8 | #include "SocialMgr.h" 9 | 10 | bool HardModeHooksServerScript::CanPacketSend(WorldSession* session, WorldPacket& packet) 11 | { 12 | if (!sHardModeHandler->IsHardModeEnabled()) 13 | { 14 | return true; 15 | } 16 | 17 | if (!session) 18 | { 19 | return true; 20 | } 21 | 22 | auto player = session->GetPlayer(); 23 | if (!player) 24 | { 25 | return true; 26 | } 27 | 28 | // The packet was modified and re-sent, let it through. 29 | if (HasModifiedTail(packet)) 30 | { 31 | return true; 32 | } 33 | 34 | auto opCode = packet.GetOpcode(); 35 | bool resend = false; 36 | 37 | switch (opCode) 38 | { 39 | case SMSG_WHO: 40 | resend = HandleWhoListOverride(packet); 41 | break; 42 | 43 | case SMSG_FRIEND_STATUS: 44 | case SMSG_CONTACT_LIST: 45 | resend = HandleFriendsListOverride(packet); 46 | break; 47 | 48 | case SMSG_GUILD_ROSTER: 49 | resend = HandleGuildRosterOverride(packet); 50 | break; 51 | case SMSG_INSPECT_TALENT: 52 | HandleInspectOverride(player, packet); 53 | break; 54 | } 55 | 56 | if (resend) 57 | { 58 | // Modify the tail, resend and stop sending the original. 59 | packet << HARDMODE_PACKET_TAIL; 60 | player->SendDirectMessage(&packet); 61 | 62 | return false; 63 | } 64 | 65 | return true; 66 | } 67 | 68 | bool HardModeHooksServerScript::CanPacketReceive(WorldSession* session, WorldPacket& packet) 69 | { 70 | if (!sHardModeHandler->IsHardModeEnabled()) 71 | { 72 | return true; 73 | } 74 | 75 | if (!session) 76 | { 77 | return true; 78 | } 79 | 80 | auto player = session->GetPlayer(); 81 | if (!player) 82 | { 83 | return true; 84 | } 85 | 86 | auto opCode = packet.GetOpcode(); 87 | 88 | switch (opCode) 89 | { 90 | case CMSG_GET_MAIL_LIST: 91 | return HandleGetMailListOverride(session); 92 | break; 93 | } 94 | 95 | return true; 96 | } 97 | 98 | bool HardModeHooksServerScript::HandleGetMailListOverride(WorldSession* session) 99 | { 100 | if (!session->GetPlayer()) 101 | { 102 | return true; 103 | } 104 | 105 | auto player = session->GetPlayer(); 106 | if (sHardModeHandler->CanTaintPlayer(player->GetGUID())) 107 | { 108 | sHardModeHandler->UpdatePlayerTainted(player->GetGUID(), true); 109 | } 110 | 111 | return true; 112 | } 113 | 114 | bool HardModeHooksServerScript::HandleWhoListOverride(WorldPacket& packet) 115 | { 116 | bool resendPacket = false; 117 | 118 | uint32 displayCount = packet.read(); 119 | uint32 matchCount = packet.read(); 120 | 121 | // No matches, don't try read any further. 122 | if (matchCount == 0 && displayCount == 0) 123 | { 124 | return false; 125 | } 126 | 127 | for (uint32 i = 0; i < displayCount; ++i) 128 | { 129 | std::string playerName = packet.read(); 130 | packet.read_skip(); //GuildName 131 | packet.read_skip(); //PlayerLvl 132 | packet.read_skip(); //PlayerClass 133 | packet.read_skip(); //PlayerRace 134 | packet.read_skip(); //PlayerGender 135 | packet.read_skip(); //PlayerZoneId 136 | 137 | auto targetGuid = sHardModeHandler->GetGUIDFromPlayerName(playerName); 138 | if (targetGuid && sHardModeHandler->PlayerHasRestriction(*targetGuid, HARDMODE_RESTRICT_HIDE_WHOLIST)) 139 | { 140 | packet.put(packet.rpos() - 4, static_cast(HARDMODE_AREA_UNKNOWN)); // ZoneId 141 | packet.put(packet.rpos() - 17, 0); // PlayerLvl 142 | resendPacket = true; 143 | } 144 | } 145 | 146 | return resendPacket; 147 | } 148 | 149 | bool HardModeHooksServerScript::HandleFriendsListOverride(WorldPacket& packet) 150 | { 151 | auto opCode = packet.GetOpcode(); 152 | 153 | switch (opCode) 154 | { 155 | case SMSG_FRIEND_STATUS: 156 | return HandleFriendStatus(packet); 157 | 158 | case SMSG_CONTACT_LIST: 159 | return HandleContactList(packet); 160 | } 161 | 162 | return false; 163 | } 164 | 165 | bool HardModeHooksServerScript::HandleFriendStatus(WorldPacket& packet) 166 | { 167 | bool resendPacket = false; 168 | 169 | uint8 status = packet.read(); 170 | ObjectGuid targetGuid = ObjectGuid(packet.read()); 171 | 172 | if (status == FRIEND_REMOVED) 173 | { 174 | return false; 175 | } 176 | 177 | if (status == FRIEND_ADDED_ONLINE || 178 | status == FRIEND_ADDED_OFFLINE) 179 | { 180 | packet.read_skip(); // Friend Note 181 | } 182 | 183 | if (status == FRIEND_ADDED_ONLINE || 184 | status == FRIEND_ONLINE) 185 | { 186 | packet.read_skip(); // Friend status 187 | packet.read_skip(); // Friend area 188 | packet.read_skip(); // Friend level 189 | } 190 | 191 | if (targetGuid && sHardModeHandler->PlayerHasRestriction(targetGuid, HARDMODE_RESTRICT_HIDE_FRIENDS)) 192 | { 193 | packet.put(packet.rpos() - 8, static_cast(HARDMODE_AREA_UNKNOWN)); // Area 194 | packet.put(packet.rpos() - 4, 0); // Level 195 | resendPacket = true; 196 | } 197 | 198 | return resendPacket; 199 | } 200 | 201 | bool HardModeHooksServerScript::HandleContactList(WorldPacket& packet) 202 | { 203 | bool resendPacket = false; 204 | 205 | packet.read_skip(); // Flags 206 | uint32 contactCount = packet.read(); 207 | 208 | if (contactCount < 1) 209 | { 210 | return false; 211 | } 212 | 213 | for (uint32 i = 0; i < contactCount; ++i) 214 | { 215 | ObjectGuid targetGuid = ObjectGuid(packet.read()); 216 | uint32 targetFlags = packet.read(); 217 | std::string targetNote = packet.read(); // target note 218 | 219 | if (!(targetFlags & SOCIAL_FLAG_FRIEND)) 220 | { 221 | // Not a friend query, goto next. 222 | continue; 223 | } 224 | 225 | uint8 targetStatus = packet.read(); 226 | if (!targetStatus) 227 | { 228 | // Target is not online, goto next. 229 | continue; 230 | } 231 | 232 | packet.read_skip(); // target area 233 | packet.read_skip(); // target level 234 | packet.read_skip(); // target class 235 | 236 | if (targetGuid && sHardModeHandler->PlayerHasRestriction(targetGuid, HARDMODE_RESTRICT_HIDE_FRIENDS)) 237 | { 238 | packet.put(packet.rpos() - 12, static_cast(HARDMODE_AREA_UNKNOWN)); // Area 239 | packet.put(packet.rpos() - 8, 0); // Level 240 | resendPacket = true; 241 | } 242 | } 243 | 244 | return resendPacket; 245 | } 246 | 247 | bool HardModeHooksServerScript::HandleGuildRosterOverride(WorldPacket& packet) 248 | { 249 | bool resendPacket = false; 250 | 251 | uint32 memberCount = packet.read(); 252 | packet.read_skip(); // WelcomeText 253 | packet.read_skip(); // InfoText 254 | uint32 rankCount = packet.read(); 255 | 256 | for (uint32 i = 0; i < rankCount; ++i) 257 | { 258 | packet.read_skip(); //RankFlags 259 | packet.read_skip(); //RankWithdrawGoldLimit 260 | 261 | for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; i++) 262 | { 263 | packet.read_skip(); //RankTabFlags 264 | packet.read_skip(); //RankTabWithdrawItemLimit 265 | } 266 | } 267 | 268 | for (uint32 i = 0; i < memberCount; ++i) 269 | { 270 | ObjectGuid memberGuid = ObjectGuid(packet.read()); 271 | uint8 memberStatus = packet.read(); //MemberStatus 272 | std::string memberName = packet.read(); //MemberName 273 | packet.read_skip(); //MemberRankId 274 | packet.read_skip(); //MemberLevel 275 | packet.read_skip(); //MemberClassId 276 | packet.read_skip(); //MemberGender 277 | packet.read_skip(); //MemberAreaId 278 | 279 | if (memberGuid && sHardModeHandler->PlayerHasRestriction(memberGuid, HARDMODE_RESTRICT_HIDE_GUILD)) 280 | { 281 | packet.put(packet.rpos() - 4, static_cast(HARDMODE_AREA_UNKNOWN)); // Area 282 | packet.put(packet.rpos() - 7, 0); // Area 283 | resendPacket = true; 284 | } 285 | 286 | if (!memberStatus) 287 | { 288 | packet.read_skip(); //MemberLastSave 289 | } 290 | 291 | packet.read_skip(); //MemberNote 292 | packet.read_skip(); //MemberOfficerNote 293 | } 294 | 295 | return resendPacket; 296 | } 297 | 298 | void HardModeHooksServerScript::HandleInspectOverride(Player* player, WorldPacket& packet) 299 | { 300 | if (!sConfigMgr->GetOption("HardMode.Inspect.Alert", true)) 301 | { 302 | return; 303 | } 304 | 305 | uint64 packGuid; 306 | packet.readPackGUID(packGuid); 307 | ObjectGuid targetGuid = ObjectGuid(packGuid); 308 | Player* targetPlayer = ObjectAccessor::FindPlayer(targetGuid); 309 | 310 | if (!targetPlayer) 311 | { 312 | return; 313 | } 314 | 315 | auto modes = sHardModeHandler->GetHardModes(); 316 | bool hasModes = false; 317 | for (auto it = modes->begin(); it != modes->end(); ++it) 318 | { 319 | auto mode = it->second; 320 | 321 | if (sHardModeHandler->IsModeEnabledForPlayer(targetPlayer->GetGUID(), mode.Id)) 322 | { 323 | hasModes = true; 324 | 325 | // No need to iterate everything. 326 | break; 327 | } 328 | } 329 | 330 | if (!hasModes) 331 | { 332 | return; 333 | } 334 | 335 | std::string sFormat = Acore::StringFormat("{} has modes {}.", targetPlayer->GetPlayerName(), sHardModeHandler->GetNamesFromEnabledModes(targetPlayer)); 336 | sHardModeHandler->SendAlert(player, sFormat); 337 | } 338 | 339 | bool HardModeHooksServerScript::HasModifiedTail(WorldPacket& packet) 340 | { 341 | if (packet.size() < 4) 342 | { 343 | return false; 344 | } 345 | 346 | // Read the last 4 bytes of the packet to check for modified tail. 347 | return packet.read(packet.size() - 4) == HARDMODE_PACKET_TAIL; 348 | } 349 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksServer.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_HARDMODE_HOOKS_SERVER_H 2 | #define MODULE_HARDMODE_HOOKS_SERVER_H 3 | 4 | #include "ScriptMgr.h" 5 | 6 | enum HardModeServerConstants 7 | { 8 | HARDMODE_PACKET_TAIL = 696969 9 | }; 10 | 11 | class HardModeHooksServerScript : ServerScript 12 | { 13 | public: 14 | HardModeHooksServerScript() : ServerScript("HardModeHooksServerScript") { } 15 | 16 | private: 17 | bool CanPacketSend(WorldSession* session, WorldPacket& packet) override; 18 | bool CanPacketReceive(WorldSession* session, WorldPacket& packet) override; 19 | bool HandleGetMailListOverride(WorldSession* session); 20 | bool HandleWhoListOverride(WorldPacket& packet); 21 | bool HandleFriendsListOverride(WorldPacket& packet); 22 | bool HandleFriendStatus(WorldPacket& packet); 23 | bool HandleContactList(WorldPacket& packet); 24 | bool HandleGuildRosterOverride(WorldPacket& packet); 25 | void HandleInspectOverride(Player* player, WorldPacket& packet); 26 | bool HasModifiedTail(WorldPacket& packet); 27 | }; 28 | 29 | #endif // MODULE_HARDMODE_HOOKS_SERVER_H 30 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksUnit.cpp: -------------------------------------------------------------------------------- 1 | #include "HardModeHooks/HardModeHooksUnit.h" 2 | #include "HardModeHandler.h" 3 | 4 | void HardModeHooksUnitScript::OnAuraApply(Unit* unit, Aura* /*aura*/) 5 | { 6 | if (!sHardModeHandler->IsHardModeEnabled()) 7 | { 8 | return; 9 | } 10 | 11 | if (!unit) 12 | { 13 | return; 14 | } 15 | 16 | if (!unit->IsPlayer()) 17 | { 18 | return; 19 | } 20 | 21 | Player* player = unit->ToPlayer(); 22 | if (!player || !player->IsInWorld()) 23 | { 24 | return; 25 | } 26 | 27 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_SMALLFISH)) 28 | { 29 | // Schedule due to issues.. 30 | sHardModeHandler->GetScheduler()->Schedule(50ms, [player](TaskContext /*task*/) 31 | { 32 | sHardModeHandler->UpdatePlayerScaleSpeed(player, SMALLFISH_SCALE); 33 | }); 34 | } 35 | } 36 | 37 | void HardModeHooksUnitScript::OnAuraRemove(Unit* unit, AuraApplication* /*auraApp*/, AuraRemoveMode mode) 38 | { 39 | if (!sHardModeHandler->IsHardModeEnabled()) 40 | { 41 | return; 42 | } 43 | 44 | if (!unit) 45 | { 46 | return; 47 | } 48 | 49 | if (!unit->IsPlayer()) 50 | { 51 | return; 52 | } 53 | 54 | Player* player = unit->ToPlayer(); 55 | 56 | if (!player || !player->IsInWorld()) 57 | { 58 | return; 59 | } 60 | 61 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_SMALLFISH)) 62 | { 63 | // Schedule due to issues.. 64 | sHardModeHandler->GetScheduler()->Schedule(50ms, [player](TaskContext /*task*/) 65 | { 66 | sHardModeHandler->UpdatePlayerScaleSpeed(player, SMALLFISH_SCALE); 67 | }); 68 | } 69 | 70 | // Don't reapply aura on death, resurrection handles reapplication already. 71 | if (mode == AURA_REMOVE_BY_DEATH) 72 | { 73 | return; 74 | } 75 | 76 | sHardModeHandler->ValidatePlayerAuras(player); 77 | } 78 | 79 | void HardModeHooksUnitScript::OnDamage(Unit* attacker, Unit* target, uint32& damage) 80 | { 81 | if (!sHardModeHandler->IsHardModeEnabled()) 82 | { 83 | return; 84 | } 85 | 86 | if (!attacker) 87 | { 88 | return; 89 | } 90 | 91 | if (!attacker->IsPlayer() && !attacker->IsSummon()) 92 | { 93 | return; 94 | } 95 | 96 | Player* player = attacker->ToPlayer(); 97 | 98 | if (!player || attacker->IsSummon()) 99 | { 100 | if (auto owner = attacker->GetOwner()) 101 | { 102 | player = owner->ToPlayer(); 103 | } 104 | } 105 | 106 | if (!player) 107 | { 108 | return; 109 | } 110 | 111 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_PACIFIST)) 112 | { 113 | auto modes = sHardModeHandler->GetPlayerModesFromRestriction(player->GetGUID(), HARDMODE_RESTRICT_PACIFIST); 114 | for (auto mode : modes) 115 | { 116 | if (!mode.Enabled) 117 | { 118 | continue; 119 | } 120 | 121 | sHardModeHandler->UpdateModeForPlayer(player->GetGUID(), mode.Id, false); 122 | } 123 | 124 | // TODO: Update this to alert in the chat so the player is more aware. 125 | sHardModeHandler->SendAlert(player, "You have failed the pacifist challenge."); 126 | player->AddAura(HARDMODE_AURA_PACIFIST_FAIL, player); 127 | } 128 | 129 | auto targetPlayer = target->ToPlayer(); 130 | 131 | if (!targetPlayer) 132 | { 133 | return; 134 | } 135 | 136 | if (!sHardModeHandler->HasMatchingModesWithRestriction(player, targetPlayer, HARDMODE_RESTRICT_BLOCK_CROSSPVP)) 137 | { 138 | damage = 0; 139 | sHardModeHandler->SendAlert(player, "You cannot damage players in other modes than your own."); 140 | } 141 | } 142 | 143 | void HardModeHooksUnitScript::ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage, SpellInfo const* /*spellInfo*/) 144 | { 145 | if (!sHardModeHandler->IsHardModeEnabled()) 146 | { 147 | return; 148 | } 149 | 150 | if (!attacker) 151 | { 152 | return; 153 | } 154 | 155 | if (!attacker->IsPlayer()) 156 | { 157 | return; 158 | } 159 | 160 | auto player = attacker->ToPlayer(); 161 | 162 | if (!player) 163 | { 164 | return; 165 | } 166 | 167 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_SMALLFISH)) 168 | { 169 | damage = damage * SMALLFISH_SCALE; 170 | } 171 | 172 | auto targetPlayer = target->ToPlayer(); 173 | 174 | if (!targetPlayer) 175 | { 176 | return; 177 | } 178 | 179 | if (!sHardModeHandler->HasMatchingModesWithRestriction(player, targetPlayer, HARDMODE_RESTRICT_BLOCK_CROSSPVP)) 180 | { 181 | damage = 0; 182 | sHardModeHandler->SendAlert(player, "You cannot damage players in other modes than your own."); 183 | } 184 | } 185 | 186 | void HardModeHooksUnitScript::ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage) 187 | { 188 | if (!sHardModeHandler->IsHardModeEnabled()) 189 | { 190 | return; 191 | } 192 | 193 | if (!attacker) 194 | { 195 | return; 196 | } 197 | 198 | if (!attacker->IsPlayer() && !attacker->IsSummon()) 199 | { 200 | return; 201 | } 202 | 203 | Player* player = attacker->ToPlayer(); 204 | 205 | if (!player || attacker->IsSummon()) 206 | { 207 | if (auto owner = attacker->GetOwner()) 208 | { 209 | player = owner->ToPlayer(); 210 | } 211 | } 212 | 213 | if (!player) 214 | { 215 | return; 216 | } 217 | 218 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_SMALLFISH)) 219 | { 220 | damage = damage * SMALLFISH_SCALE; 221 | } 222 | 223 | auto targetPlayer = target->ToPlayer(); 224 | 225 | if (!targetPlayer) 226 | { 227 | return; 228 | } 229 | 230 | if (!sHardModeHandler->HasMatchingModesWithRestriction(player, targetPlayer, HARDMODE_RESTRICT_BLOCK_CROSSPVP)) 231 | { 232 | damage = 0; 233 | sHardModeHandler->SendAlert(player, "You cannot damage players in other modes than your own."); 234 | } 235 | } 236 | 237 | void HardModeHooksUnitScript::ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage, SpellInfo const* /*spellInfo*/) 238 | { 239 | if (!sHardModeHandler->IsHardModeEnabled()) 240 | { 241 | return; 242 | } 243 | 244 | if (!attacker) 245 | { 246 | return; 247 | } 248 | 249 | if (!attacker->IsPlayer() && !attacker->IsSummon()) 250 | { 251 | return; 252 | } 253 | 254 | Player* player = attacker->ToPlayer(); 255 | 256 | if (!player || attacker->IsSummon()) 257 | { 258 | if (auto owner = attacker->GetOwner()) 259 | { 260 | player = owner->ToPlayer(); 261 | } 262 | } 263 | 264 | if (!player) 265 | { 266 | return; 267 | } 268 | 269 | if (sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_SMALLFISH)) 270 | { 271 | damage = damage * SMALLFISH_SCALE; 272 | } 273 | 274 | auto targetPlayer = target->ToPlayer(); 275 | 276 | if (!targetPlayer) 277 | { 278 | return; 279 | } 280 | 281 | if (!sHardModeHandler->HasMatchingModesWithRestriction(player, targetPlayer, HARDMODE_RESTRICT_BLOCK_CROSSPVP)) 282 | { 283 | damage = 0; 284 | sHardModeHandler->SendAlert(player, "You cannot damage players in other modes than your own."); 285 | } 286 | } 287 | 288 | void HardModeHooksUnitScript::OnUnitDeath(Unit* unit, Unit* killer) 289 | { 290 | if (!sHardModeHandler->IsHardModeEnabled()) 291 | { 292 | return; 293 | } 294 | 295 | if (!sConfigMgr->GetOption("HardMode.Restrict.Permadeath.Announce", true)) 296 | { 297 | return; 298 | } 299 | 300 | if (!unit) 301 | { 302 | return; 303 | } 304 | 305 | auto player = unit->ToPlayer(); 306 | if (!player) 307 | { 308 | return; 309 | } 310 | 311 | if (!sHardModeHandler->PlayerHasRestriction(player->GetGUID(), HARDMODE_RESTRICT_PERMADEATH)) 312 | { 313 | return; 314 | } 315 | 316 | if (sHardModeHandler->IsPlayerShadowBanned(player->GetGUID())) 317 | { 318 | return; 319 | } 320 | 321 | std::stringstream ss; 322 | 323 | if (killer) 324 | { 325 | ss << Acore::StringFormat("|cffFF0000Player {} has died to {} {} while undertaking the permadeath restriction!", player->GetName(), killer->ToPlayer() ? "player" : "creature", killer->GetName()); 326 | } 327 | else 328 | { 329 | ss << Acore::StringFormat("|cffFF0000Player {} has died while undertaking the permadeath restriction!", player->GetName()); 330 | } 331 | 332 | sWorld->SendServerMessage(SERVER_MSG_STRING, ss.str()); 333 | } 334 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksUnit.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_HARDMODE_HOOKS_UNIT_H 2 | #define MODULE_HARDMODE_HOOKS_UNIT_H 3 | 4 | #include "ScriptMgr.h" 5 | 6 | class HardModeHooksUnitScript : UnitScript 7 | { 8 | public: 9 | HardModeHooksUnitScript() : UnitScript("HardModeHooksUnitScript") { } 10 | 11 | private: 12 | void OnAuraApply(Unit* unit, Aura* aura) override; 13 | void OnAuraRemove(Unit* unit, AuraApplication* auraApp, AuraRemoveMode mode) override; 14 | 15 | void OnDamage(Unit* attacker, Unit* victim, uint32& damage) override; 16 | void ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage, SpellInfo const* spellInfo) override; 17 | void ModifyMeleeDamage(Unit* target, Unit* attacker, uint32& damage) override; 18 | void ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage, SpellInfo const* spellInfo) override; 19 | 20 | void OnUnitDeath(Unit* unit, Unit* killer) override; 21 | }; 22 | 23 | #endif // MODULE_HARDMODE_HOOKS_UNIT_H 24 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksWorld.cpp: -------------------------------------------------------------------------------- 1 | #include "HardModeHooks/HardModeHooksWorld.h" 2 | #include "HardModeHandler.h" 3 | 4 | void HardModeHooksWorldScript::OnUpdate(uint32 diff) 5 | { 6 | if (!sHardModeHandler->IsHardModeEnabled()) 7 | { 8 | return; 9 | } 10 | 11 | sHardModeHandler->GetScheduler()->Update(diff); 12 | } 13 | -------------------------------------------------------------------------------- /src/HardModeHooks/HardModeHooksWorld.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_HARDMODE_HOOKS_WORLD_H 2 | #define MODULE_HARDMODE_HOOKS_WORLD_H 3 | 4 | #include "ScriptMgr.h" 5 | 6 | class HardModeHooksWorldScript : WorldScript 7 | { 8 | public: 9 | HardModeHooksWorldScript() : WorldScript("HardModeHooksWorldScript") { } 10 | 11 | private: 12 | void OnUpdate(uint32 diff) override; 13 | }; 14 | 15 | #endif // MODULE_HARDMODE_HOOKS_WORLD_H 16 | -------------------------------------------------------------------------------- /src/HardModeShrineObject.cpp: -------------------------------------------------------------------------------- 1 | #include "HardModeShrineObject.h" 2 | #include "HardModeHandler.h" 3 | 4 | #include "Config.h" 5 | #include "Player.h" 6 | #include "ScriptedGossip.h" 7 | 8 | bool HardModeShrineObject::OnGossipHello(Player* player, GameObject* go) 9 | { 10 | if (!sHardModeHandler->IsHardModeEnabled()) 11 | { 12 | return false; 13 | } 14 | 15 | auto hardModes = sHardModeHandler->GetHardModes(); 16 | 17 | for (auto it = hardModes->begin(); it != hardModes->end(); ++it) 18 | { 19 | auto mode = it->second; 20 | 21 | if (!mode.Enabled) 22 | { 23 | continue; 24 | } 25 | 26 | bool flag = sHardModeHandler->IsModeEnabledForPlayer(player->GetGUID(), mode.Id); 27 | std::string state = flag ? "Disable" : "Enable"; 28 | std::string format = Acore::StringFormat("{} {} mode.", state, mode.Name); 29 | 30 | if (sHardModeHandler->IsPlayerTainted(player->GetGUID())) 31 | { 32 | if (flag) 33 | { 34 | std::string popupFormat = Acore::StringFormat("Are you sure you want to disable the {} mode?|n|nYou will not be able to re-enable it.", mode.Name); 35 | AddGossipItemFor(player, GOSSIP_ICON_CHAT, format, 0, mode.Id, popupFormat, 0, false); 36 | } 37 | } 38 | else 39 | { 40 | AddGossipItemFor(player, GOSSIP_ICON_CHAT, format, 0, mode.Id); 41 | } 42 | } 43 | 44 | if (!sHardModeHandler->IsPlayerTainted(player->GetGUID())) 45 | { 46 | SendGossipMenuFor(player, HARDMODE_SHRINE_GREETING, go->GetGUID()); 47 | } 48 | else 49 | { 50 | SendGossipMenuFor(player, HARDMODE_SHRINE_GREETING_TAINTED, go->GetGUID()); 51 | } 52 | 53 | return true; 54 | } 55 | 56 | bool HardModeShrineObject::OnGossipSelect(Player* player, GameObject* /*go*/, uint32 /*sender*/, uint32 mode) 57 | { 58 | if (!sHardModeHandler->IsHardModeEnabled()) 59 | { 60 | return false; 61 | } 62 | 63 | bool flag = sHardModeHandler->IsModeEnabledForPlayer(player->GetGUID(), mode); 64 | 65 | if (!flag && sHardModeHandler->IsPlayerTainted(player->GetGUID())) 66 | { 67 | sHardModeHandler->SendAlert(player, "You cannot enable hard modes while tainted."); 68 | } 69 | else 70 | { 71 | sHardModeHandler->UpdateModeForPlayer(player->GetGUID(), mode, !flag); 72 | } 73 | 74 | CloseGossipMenuFor(player); 75 | 76 | return true; 77 | } 78 | -------------------------------------------------------------------------------- /src/HardModeShrineObject.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_HARDMODE_SHRINE_OBJ_H 2 | #define MODULE_HARDMODE_SHRINE_OBJ_H 3 | 4 | #include "ScriptMgr.h" 5 | 6 | enum HardModeShrineConstants 7 | { 8 | HARDMODE_SHRINE_GREETING = 441101, 9 | HARDMODE_SHRINE_GREETING_TAINTED = 441102 10 | }; 11 | 12 | class HardModeShrineObject : GameObjectScript 13 | { 14 | public: 15 | HardModeShrineObject() : GameObjectScript("HardModeShrineObject") { } 16 | 17 | private: 18 | bool OnGossipHello(Player* player, GameObject* go) override; 19 | bool OnGossipSelect(Player* player, GameObject* go, uint32 sender, uint32 mode) override; 20 | }; 21 | 22 | #endif // MODULE_HARDMODE_SHRINE_OBJ_H 23 | -------------------------------------------------------------------------------- /src/HardModeTypes.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULE_HARDMODE_TYPES_H 2 | #define MODULE_HARDMODE_TYPES_H 3 | 4 | #include "Common.h" 5 | 6 | #include 7 | 8 | enum HardModeConstants 9 | { 10 | HARDMODE_MAIL_SENDER = 441102, 11 | HARDMODE_AURA_SHADOWBAN = 45681, 12 | HARDMODE_AREA_AZSHARACRATER = 37, 13 | HARDMODE_AREA_SHADOWTOMB = 3888, 14 | HARDMODE_AREA_UNKNOWN = 4988, 15 | HARDMODE_AREA_EBONHOLD = 609, 16 | HARDMODE_QUEST_DK_INITIAL = 12593, 17 | HARDMODE_AURA_PACIFIST_FAIL = 46221 18 | }; 19 | 20 | constexpr float SMALLFISH_SCALE = 0.5f; 21 | 22 | struct HardModeInfo 23 | { 24 | uint8 Id; 25 | std::string Name; 26 | std::string Description; 27 | uint64 Restrictions; 28 | bool Enabled; 29 | }; 30 | 31 | struct HardModePlayerSettings 32 | { 33 | std::vector Modes; 34 | bool Tainted; 35 | bool ShadowBanned; 36 | }; 37 | 38 | enum HardModeRestrictions 39 | { 40 | HARDMODE_RESTRICT_NONE = 0, // Used internally, DO NOT USE 41 | HARDMODE_RESTRICT_RETAIL_XP = 1, // 2: The player can only receive 1x exp rates from kills, quests, etc.. 42 | HARDMODE_RESTRICT_SELFCRAFTED = 2, // 4: The player can only use self-crafted items (armor, weapons, consumables, etc..) 43 | HARDMODE_RESTRICT_INTERACT_AUCTION = 3, // 8: The player cannot interact with the auction house. 44 | HARDMODE_RESTRICT_INTERACT_GUILDBANK = 4, // 16: The player cannot interact with the guild bank. 45 | HARDMODE_RESTRICT_INTERACT_MAIL_SEND = 5, // 32: The player cannot send mail. 46 | HARDMODE_RESTRICT_INTERACT_MAIL_RECEIVE = 6, // 64: The player cannot receive mail. 47 | HARDMODE_RESTRICT_INTERACT_TRADE = 7, // 128: The player cannot trade/be traded. 48 | HARDMODE_RESTRICT_PERMADEATH = 8, // 256: The player is sent to the shadow tomb on death. 49 | HARDMODE_RESTRICT_HIDE_WHOLIST = 9, // 512: The players location is hidden on the who list. 50 | HARDMODE_RESTRICT_HIDE_FRIENDS = 10, // 1024, The players location is hidden on the friends list. 51 | HARDMODE_RESTRICT_HIDE_GUILD = 11, // 2048, The players location is hidden on the guild roster. 52 | HARDMODE_RESTRICT_INTERACT_LFG = 12, // 4096, The player cannot queue for LFG. 53 | HARDMODE_RESTRICT_INTERACT_GROUP = 13, // 8192, The player cannot join groups. 54 | HARDMODE_RESTRICT_INTERACT_GROUP_CROSSPLAY = 14, // 16384 The player can only group with matching modes. 55 | HARDMODE_RESTRICT_BAD_LUCK = 15, // 32768 The player has bad luck with loot drops. 56 | HARDMODE_RESTRICT_PACIFIST = 16, // 65536 The player loses the mode if they damage or kill units. 57 | HARDMODE_RESTRICT_INTERACT_GROUP_RANGE = 17, // 131072 The player can only group with other players within x (default 3) levels from themself. 58 | HARDMODE_RESTRICT_INTERACT_TALENTS = 18, // 262144 The player cannot use talent points. 59 | HARDMODE_RESTRICT_SMALLFISH = 19, // 524288 The player is half the size, speed and deals half as much damage. 60 | HARDMODE_RESTRICT_BLOCK_CROSSPVP = 20, // 1048576 The player cannot damage other players with unmatching modes. 61 | HARDMODE_RESTRICT_COUNT = 21, // Used internally. DO NOT USE 62 | }; 63 | 64 | enum HardModeRewardType 65 | { 66 | HARDMODE_REWARD_TYPE_ITEM = 0, 67 | HARDMODE_REWARD_TYPE_TITLE = 1, 68 | HARDMODE_REWARD_TYPE_SPELL = 2 69 | }; 70 | 71 | struct HardModeReward 72 | { 73 | uint32 Mode; 74 | uint32 Level; 75 | uint32 Type; 76 | uint32 RewardId; 77 | uint32 RewardCount; 78 | }; 79 | 80 | #endif // MODULE_HARDMODE_TYPES_H 81 | -------------------------------------------------------------------------------- /src/HardMode_Loader.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 3 | */ 4 | 5 | void SC_AddHardModeScripts(); 6 | 7 | void AddHardModeScripts() 8 | { 9 | SC_AddHardModeScripts(); 10 | } 11 | 12 | --------------------------------------------------------------------------------