вывод из самбомудлей модов для азероткор

This commit is contained in:
2026-03-07 22:28:31 +04:00
parent 5877ea78cd
commit adcfe8e31d
1720 changed files with 1941740 additions and 40 deletions
+8
View File
@@ -0,0 +1,8 @@
[*]
charset = utf-8
indent_style = space
indent_size = 4
tab_width = 4
insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 80
@@ -0,0 +1,49 @@
### TITLE
## Type(Scope/Subscope): Commit ultra short explanation
## |---- Write below the examples with a maximum of 50 characters ----|
## Example 1: fix(DB/SAI): Missing spell to NPC Hogger
## Example 2: fix(CORE/Raid): Phase 2 of Ragnaros
## Example 3: feat(CORE/Commands): New GM command to do something
### DESCRIPTION
## Explain why this change is being made, what does it fix etc...
## |---- Write below the examples with a maximum of 72 characters per lines ----|
## Example: Hogger (id: 492) was not charging player when being engaged.
## Provide links to any issue, commit, pull request or other resource
## Example 1: Closes issue #23
## Example 2: Ported from other project's commit (link)
## Example 3: References taken from wowpedia / wowhead / wowwiki / https://wowgaming.altervista.org/aowow/
## =======================================================
## EXTRA INFOS
## =======================================================
## "Type" can be:
## feat (new feature)
## fix (bug fix)
## refactor (refactoring production code)
## style (formatting, missing semi colons, etc; no code change)
## docs (changes to documentation)
## test (adding or refactoring tests; no production code change)
## chore (updating bash scripts, git files etc; no production code change)
## --------------------
## Remember to
## Capitalize the subject line
## Use the imperative mood in the subject line
## Do not end the subject line with a period
## Separate subject from body with a blank line
## Use the body to explain what and why rather than how
## Can use multiple lines with "-" for bullet points in body
## --------------------
## More info here https://www.conventionalcommits.org/en/v1.0.0-beta.2/
## =======================================================
## "Scope" can be:
## CORE (core related, c++)
## DB (database related, sql)
## =======================================================
## "Subscope" is optional and depends on the nature of the commit.
## =======================================================
+105
View File
@@ -0,0 +1,105 @@
## AUTO-DETECT
## Handle line endings automatically for files detected as
## text and leave all files detected as binary untouched.
## This will handle all files NOT defined below.
* text=auto eol=lf
# Text
*.conf text
*.conf.dist text
*.cmake text
## Scripts
*.sh text
*.fish text
*.lua text
## SQL
*.sql text
## C++
*.c text
*.cc text
*.cxx text
*.cpp text
*.c++ text
*.hpp text
*.h text
*.h++ text
*.hh text
## For documentation
# Documents
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
## DOCUMENTATION
*.markdown text
*.md text
*.mdwn text
*.mdown text
*.mkd text
*.mkdn text
*.mdtxt text
*.mdtext text
*.txt text
AUTHORS text
CHANGELOG text
CHANGES text
CONTRIBUTING text
COPYING text
copyright text
*COPYRIGHT* text
INSTALL text
license text
LICENSE text
NEWS text
readme text
*README* text
TODO text
## GRAPHICS
*.ai binary
*.bmp binary
*.eps binary
*.gif binary
*.ico binary
*.jng binary
*.jp2 binary
*.jpg binary
*.jpeg binary
*.jpx binary
*.jxr binary
*.pdf binary
*.png binary
*.psb binary
*.psd binary
*.svg text
*.svgz binary
*.tif binary
*.tiff binary
*.wbmp binary
*.webp binary
## ARCHIVES
*.7z binary
*.gz binary
*.jar binary
*.rar binary
*.tar binary
*.zip binary
## EXECUTABLES
*.exe binary
*.pyc binary
@@ -0,0 +1,82 @@
name: Bug report
description: Create a bug report to help us improve.
title: "Bug: "
body:
- type: textarea
id: current
attributes:
label: Current Behaviour
description: |
Description of the problem or issue here.
Include entries of affected creatures / items / quests / spells etc.
If this is a crash, post the crashlog (upload to https://gist.github.com/) and include the link here.
Never upload files! Use GIST for text and YouTube for videos!
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behaviour
description: |
Tell us what should happen instead.
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: Steps to reproduce the problem
description: |
What does someone else need to do to encounter the same bug?
placeholder: |
1. Step 1
2. Step 2
3. Step 3
validations:
required: true
- type: textarea
id: extra
attributes:
label: Extra Notes
description: |
Do you have any extra notes that can help solve the issue that does not fit any other field?
placeholder: |
None
validations:
required: false
- type: textarea
id: abcommands
attributes:
label: AutoBalance Debug Commands
description: |
Please include text or an image of the `.ab mapstat` command. If your issue is concerning scaling of creatures, please also include the `.ab creaturestat` command while targeting the problematic creature.
placeholder: |
None
validations:
required: false
- type: textarea
id: commit
attributes:
label: AC rev. hash/commit
description: |
Copy the result of the `.server debug` command (if you need to run it from the client get a prat addon)
validations:
required: true
- type: input
id: os
attributes:
label: Operating system
description: |
The Operating System the Server is running on.
i.e. Windows 11 x64, Debian 10 x64, macOS 12, Ubuntu 20.04
validations:
required: true
- type: textarea
id: custom
attributes:
label: Custom changes or Modules
description: |
List which custom changes or modules you have applied, i.e. Eluna module, etc.
placeholder: |
None
validations:
required: false
@@ -0,0 +1,33 @@
name: Feature request
description: Suggest an idea for this project
title: "Feature: "
body:
- type: markdown
attributes:
value: |
Thank you for taking your time to fill out a feature request. Remember to fill out all fields including the title above.
An issue that is not properly filled out will be closed.
- type: textarea
id: description
attributes:
label: Describe your feature request or suggestion in detail
description: |
A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe a possible solution to your feature or suggestion in detail
description: |
A clear and concise description of any alternative solutions or features you've considered.
validations:
required: false
- type: textarea
id: additional
attributes:
label: Additional context
description: |
Add any other context or screenshots about the feature request here.
validations:
required: false
@@ -0,0 +1,12 @@
name: core-build
on:
push:
branches:
- 'master'
pull_request:
jobs:
build:
uses: azerothcore/reusable-workflows/.github/workflows/core_build_modules.yml@main
with:
module_repo: ${{ github.event.repository.name }}
+51
View File
@@ -0,0 +1,51 @@
!.gitignore
#
#Generic
#
.directory
.mailmap
*.orig
*.rej
*.*~
.hg/
*.kdev*
.DS_Store
CMakeLists.txt.user
*.bak
*.patch
*.diff
*.REMOTE.*
*.BACKUP.*
*.BASE.*
*.LOCAL.*
#
# IDE & other softwares
#
/.settings/
/.externalToolBuilders/*
# exclude in all levels
nbproject/
.sync.ffs_db
*.kate-swp
.idea
cmake-build-debug
.vscode
#
# Eclipse
#
*.pydevproject
.metadata
.gradle
tmp/
*.tmp
*.swp
*~.nib
local.properties
.settings/
.loadpath
.project
.cproject
+40
View File
@@ -0,0 +1,40 @@
# ![logo](https://raw.githubusercontent.com/azerothcore/azerothcore.github.io/master/images/logo-github.png) AzerothCore
## Beta testing warning
The current version of the master branch is currently in beta, under testing to ensure all the functionalities are working properly.
If you encur in problems please open an Issue and consider to use the last [stable version](https://github.com/azerothcore/mod-autobalance/releases/tag/stable) of this repository.
## AutoBalance
- Latest build status with azerothcore: [![Build Status](https://github.com/azerothcore/mod-autobalance/workflows/core-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/mod-autobalance)
This module is intended to scale based on number of players, instance mobs and bosses' health, mana, and damage.
**NOTE:** This module requires at least [this commit](https://github.com/azerothcore/azerothcore-wotlk/commit/f127e583aae3cfa51a77d056c1892a7de07ffb52) of AzerothCore in order to work correctly. Older versions are not supported.
All settings are well-described in the configuration file.
**PLEASE** include the output from the `.ab mapstat` and `.ab creaturestat` commands (while targeting a problematic creature) when reporting issues. This will help us to quickly identify the problem and provide a solution.
## In-game Commands
| Command | Permission | Description |
| :------ | :--------- | :---------- |
| `.ab mapstat` | All Players | Displays AB-calcualted settings for the current map, including player count, difficulty, world modifiers, and others. |
| `.ab creaturestat` | All Players | Displays AB-calculated settings for the targeted dungeon creature including level scaling, difficulty, modifiers, and boss status. |
| `.ab setoffset` | Game Masters | Sets the server-wide player difficulty offset. Instances will be scaled as though they had this many more/less players than they really do. |
| `.ab getoffset` | All Players | Gets the current server-wide player difficulty offset. Instances will be scaled as though they had this many more/less players than they really do. |
| `.reload config` | Game Masters | Reloads all your configuration files, including `AutoBalance.conf`. This lets you update AutoBalance settings without restarting your worldserver. This module is designed to contiue to work as expected when this command is issued. |
## Logger Names
| Logger | Description |
| :----- | ----------- |
| `Logger.module.AutoBalance` | Main logger, verbose debug logs. Map detection, list management, creature adjustments, multiplier, modifiers. Catch-all. |
| `Logger.module.AutoBalance_CombatLocking` | Debug logs related to the combat locking/unlocking mechanism for maps. |
| `Logger.module.AutoBalance_DamageHealingCC` | Debug logs for the spell/melee/CC modifications that are made in real-time. |
| `Logger.module.AutoBalance_StatGeneration` | Detailed debug logs that show all the calculation steps in how different multipliers are derived. |
## References
- [Interactive Inflection Point Spreadsheet](https://docs.google.com/spreadsheets/d/100cmKIJIjCZ-ncWd0K9ykO8KUgwFTcwg4h2nfE_UeCc/copy)
- [InflectionPoint Curve Examples](https://i.imgur.com/x42UnUR.png)
- [Impact of CurveFloor and CurveCeiling on enemy multiplier](https://i.imgur.com/I8S4cwJ.png)
@@ -0,0 +1,9 @@
{
"name": "mod-autobalance",
"version": "2.2.0",
"compatibility" : [
{ "version": "1.0.0", "branch": "none" },
{ "version": "^2.0.0", "branch": "2.0" },
{ "version": "^3.0.0", "branch": "master" }
]
}
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File
@@ -0,0 +1,25 @@
<!-- First of all, THANK YOU for your contribution. -->
## Changes Proposed:
-
-
## Issues Addressed:
<!-- If your fix has a relating issue, link it below -->
- Closes
## SOURCE:
<!-- If you can, include a source that can strengthen your claim -->
## Tests Performed:
<!-- Does it build without errors? Did you test in-game? What did you test? On which OS did you test? Describe any other tests performed -->
-
-
## How to Test the Changes:
<!-- Describe in a detailed step-by-step order how to test the changes -->
1.
2.
3.
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
## Set a local git commit template
git config --local commit.template ".git_commit_template.txt" ;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_ALL_CREATURE_SCRIPT_H
#define __AB_ALL_CREATURE_SCRIPT_H
#include "ScriptMgr.h"
class AutoBalance_AllCreatureScript : public AllCreatureScript
{
public:
AutoBalance_AllCreatureScript()
: AllCreatureScript("AutoBalance_AllCreatureScript")
{
}
void OnBeforeCreatureSelectLevel(const CreatureTemplate* /*creatureTemplate*/, Creature* creature, uint8& level) override;
void Creature_SelectLevel(const CreatureTemplate* /* cinfo */, Creature* creature) override;
void OnCreatureAddWorld(Creature* creature) override;
void OnCreatureRemoveWorld(Creature* creature) override;
void OnAllCreatureUpdate(Creature* creature, uint32 /*diff*/) override;
// Reset the passed creature to stock if the config has changed
bool ResetCreatureIfNeeded(Creature* creature);
void ModifyCreatureAttributes(Creature* creature);
private:
bool _isSummonCloneOfSummoner(Creature* summon);
};
#endif /* __AB_ALL_CREATURE_SCRIPT_H */
@@ -0,0 +1,227 @@
#include "ABAllMapScript.h"
#include "ABConfig.h"
#include "ABMapInfo.h"
#include "ABUtils.h"
#include "Chat.h"
#include "Message.h"
void AutoBalance_AllMapScript::OnPlayerEnterAll(Map* map, Player* player)
{
if (!EnableGlobal)
return;
if (!map->IsDungeon())
return;
LOG_DEBUG("module.AutoBalance", "AutoBalance:: ------------------------------------------------");
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllMapScript::OnPlayerEnterAll: Player {}{} | enters {} ({}{})",
player->GetName(),
player->IsGameMaster() ? " (GM)" : "",
map->GetMapName(),
map->GetId(),
map->GetInstanceId() ? "-" + std::to_string(map->GetInstanceId()) : ""
);
// get the map's info
AutoBalanceMapInfo* mapABInfo = GetMapInfo(map);
// store the previous difficulty for comparison later
int prevAdjustedPlayerCount = mapABInfo->adjustedPlayerCount;
// add player to this map's player list
AddPlayerToMap(map, player);
// recalculate the zone's level stats
mapABInfo->highestCreatureLevel = 0;
mapABInfo->lowestCreatureLevel = 0;
//mapABInfo->avgCreatureLevel = 0;
mapABInfo->activeCreatureCount = 0;
WorldSession* session = player->GetSession();
LocaleConstant locale = session->GetSessionDbLocaleIndex();
// if the previous player count is the same as the new player count, update without force
if ((prevAdjustedPlayerCount == mapABInfo->adjustedPlayerCount) && (mapABInfo->adjustedPlayerCount != 1))
{
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllMapScript::OnPlayerEnterAll: Player difficulty unchanged at {}. Updating map data (no force).",
mapABInfo->adjustedPlayerCount
);
// Update the map's data
UpdateMapDataIfNeeded(map, false);
}
else
{
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllMapScript::OnPlayerEnterAll: Player difficulty changed from ({})->({}). Updating map data (force).",
prevAdjustedPlayerCount,
mapABInfo->adjustedPlayerCount
);
// Update the map's data, forced
UpdateMapDataIfNeeded(map, true);
}
// see which existing creatures are active
for (std::vector<Creature*>::iterator creatureIterator = mapABInfo->allMapCreatures.begin(); creatureIterator != mapABInfo->allMapCreatures.end(); ++creatureIterator)
{
AddCreatureToMapCreatureList(*creatureIterator, false, true);
}
// Notify players of the change
if (PlayerChangeNotify && mapABInfo->enabled)
{
if (map->GetEntry()->IsDungeon() && player)
{
if (mapABInfo->playerCount)
{
for (std::vector<Player*>::const_iterator playerIterator = mapABInfo->allMapPlayers.begin(); playerIterator != mapABInfo->allMapPlayers.end(); ++playerIterator)
{
Player* thisPlayer = *playerIterator;
if (thisPlayer)
{
ChatHandler chatHandle = ChatHandler(thisPlayer->GetSession());
InstanceMap* instanceMap = map->ToInstanceMap();
std::string instanceDifficulty; if (instanceMap->IsHeroic()) instanceDifficulty = "Heroic"; else instanceDifficulty = "Normal";
if (thisPlayer && thisPlayer == player) // This is the player that entered
{
chatHandle.PSendSysMessage(ABGetLocaleText(locale, "welcome_to_player").c_str(),
map->GetMapName(),
instanceMap->GetMaxPlayers(),
instanceDifficulty.c_str(),
mapABInfo->playerCount,
mapABInfo->adjustedPlayerCount);
// notify GMs that they won't be accounted for
if (player->IsGameMaster())
chatHandle.PSendSysMessage(ABGetLocaleText(locale, "welcome_to_gm").c_str());
}
else
{
// announce non-GMs entering the instance only
if (!player->IsGameMaster())
chatHandle.PSendSysMessage(ABGetLocaleText(locale, "announce_non_gm_entering_instance").c_str(), player->GetName().c_str(), mapABInfo->playerCount, mapABInfo->adjustedPlayerCount);
}
}
}
}
}
}
}
void AutoBalance_AllMapScript::OnPlayerLeaveAll(Map* map, Player* player)
{
if (!EnableGlobal)
return;
if (!map->IsDungeon())
return;
LOG_DEBUG("module.AutoBalance", "AutoBalance:: ------------------------------------------------");
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllMapScript::OnPlayerLeaveAll: Player {}{} | exits {} ({}{})",
player->GetName(),
player->IsGameMaster() ? " (GM)" : "",
map->GetMapName(),
map->GetId(),
map->GetInstanceId() ? "-" + std::to_string(map->GetInstanceId()) : ""
);
// get the map's info
AutoBalanceMapInfo* mapABInfo = GetMapInfo(map);
// store the previous difficulty for comparison later
int prevAdjustedPlayerCount = mapABInfo->adjustedPlayerCount;
// remove this player from this map's player list
bool playerWasRemoved = RemovePlayerFromMap(map, player);
// report the number of players in the map
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllMapScript::OnPlayerLeaveAll: There are {} player(s) left in the map.", mapABInfo->allMapPlayers.size());
// if a player was NOT removed, return now - stats don't need to be updated
if (!playerWasRemoved)
return;
// recalculate the zone's level stats
mapABInfo->highestCreatureLevel = 0;
mapABInfo->lowestCreatureLevel = 0;
//mapABInfo->avgCreatureLevel = 0;
mapABInfo->activeCreatureCount = 0;
// see which existing creatures are active
for (std::vector<Creature*>::iterator creatureIterator = mapABInfo->allMapCreatures.begin(); creatureIterator != mapABInfo->allMapCreatures.end(); ++creatureIterator)
AddCreatureToMapCreatureList(*creatureIterator, false, true);
// if the previous player count is the same as the new player count, update without force
if (prevAdjustedPlayerCount == mapABInfo->adjustedPlayerCount)
{
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllMapScript::OnPlayerLeaveAll: Player difficulty unchanged at {}. Updating map data (no force).",
mapABInfo->adjustedPlayerCount
);
// Update the map's data
UpdateMapDataIfNeeded(map, false);
}
else
{
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllMapScript::OnPlayerLeaveAll: Player difficulty changed from ({})->({}). Updating map data (force).",
prevAdjustedPlayerCount,
mapABInfo->adjustedPlayerCount
);
// Update the map's data, forced
UpdateMapDataIfNeeded(map, true);
}
// updates the player count and levels for the map
if (map->GetEntry() && map->GetEntry()->IsDungeon())
{
{
mapABInfo->playerCount = mapABInfo->allMapPlayers.size();
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllMapScript::OnPlayerLeaveAll: Player {} left the instance.",
player->GetName(),
mapABInfo->playerCount,
mapABInfo->adjustedPlayerCount
);
}
}
// Notify remaining players in the instance that a player left
if (PlayerChangeNotify && mapABInfo->enabled)
{
if (map->GetEntry()->IsDungeon() && player && !player->IsGameMaster())
{
if (mapABInfo->playerCount)
{
for (std::vector<Player*>::const_iterator playerIterator = mapABInfo->allMapPlayers.begin(); playerIterator != mapABInfo->allMapPlayers.end(); ++playerIterator)
{
Player* thisPlayer = *playerIterator;
if (thisPlayer && thisPlayer != player)
{
ChatHandler chatHandle = ChatHandler(thisPlayer->GetSession());
if (mapABInfo->combatLocked)
{
chatHandle.PSendSysMessage(ABGetLocaleText(thisPlayer->GetSession()->GetSessionDbLocaleIndex(), "leaving_instance_combat").c_str(),
player->GetName().c_str(),
mapABInfo->adjustedPlayerCount);
}
else
{
chatHandle.PSendSysMessage(ABGetLocaleText(thisPlayer->GetSession()->GetSessionDbLocaleIndex(), "leaving_instance").c_str(),
player->GetName().c_str(),
mapABInfo->playerCount,
mapABInfo->adjustedPlayerCount);
}
}
}
}
}
}
}
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_ALL_MAP_SCRIPT_H
#define __AB_ALL_MAP_SCRIPT_H
#include "ScriptMgr.h"
class AutoBalance_AllMapScript : public AllMapScript
{
public:
AutoBalance_AllMapScript()
: AllMapScript("AutoBalance_AllMapScript", {
ALLMAPHOOK_ON_PLAYER_ENTER_ALL,
ALLMAPHOOK_ON_PLAYER_LEAVE_ALL
})
{
}
// hook triggers after the player has already entered the world
void OnPlayerEnterAll(Map* map, Player* player) override;
// hook triggers just before the player left the world
void OnPlayerLeaveAll(Map* map, Player* player) override;
};
#endif
@@ -0,0 +1,186 @@
#include "ABCommandScript.h"
#include "ABConfig.h"
#include "ABCreatureInfo.h"
#include "ABMapInfo.h"
#include "ABUtils.h"
#include "Message.h"
bool AutoBalance_CommandScript::HandleABSetOffsetCommand(ChatHandler* handler, const char* args)
{
if (!*args)
{
handler->PSendSysMessage(".autobalance setoffset #");
handler->PSendSysMessage(ABGetLocaleText(handler->GetSession()->GetSessionDbLocaleIndex(), "set_offset_command_description").c_str());
return false;
}
char* offset = strtok((char*)args, " ");
int32 offseti = -1;
if (offset)
{
offseti = (uint32)atoi(offset);
std::vector<std::string> args = { std::to_string(offseti) };
handler->PSendSysMessage(ABGetLocaleText(handler->GetSession()->GetSessionDbLocaleIndex(), "set_offset_command_success").c_str(), offseti);
PlayerCountDifficultyOffset = offseti;
globalConfigTime = GetCurrentConfigTime();
return true;
}
else
handler->PSendSysMessage(ABGetLocaleText(handler->GetSession()->GetSessionDbLocaleIndex(), "set_offset_command_error").c_str());
return false;
}
bool AutoBalance_CommandScript::HandleABGetOffsetCommand(ChatHandler* handler, const char* /*args*/)
{
handler->PSendSysMessage(ABGetLocaleText(handler->GetSession()->GetSessionDbLocaleIndex(), "get_offset_command_success").c_str(), PlayerCountDifficultyOffset);
return true;
}
bool AutoBalance_CommandScript::HandleABMapStatsCommand(ChatHandler* handler, const char* /*args*/)
{
Player* player = handler->GetPlayer();
auto locale = handler->GetSession()->GetSessionDbLocaleIndex();
AutoBalanceMapInfo* mapABInfo = GetMapInfo(player->GetMap());
if (player->GetMap()->IsDungeon())
{
handler->PSendSysMessage("---");
// Map basics
handler->PSendSysMessage("{} ({}-player {}) | ID {}-{}{}",
player->GetMap()->GetMapName(),
player->GetMap()->ToInstanceMap()->GetMaxPlayers(),
player->GetMap()->ToInstanceMap()->IsHeroic() ? "Heroic" : "Normal",
player->GetMapId(),
player->GetInstanceId(),
mapABInfo->enabled ? "" : " | AutoBalance DISABLED");
// if the map isn't enabled, don't display anything else
// if (!mapABInfo->enabled) { return true; }
// Player stats
handler->PSendSysMessage("Players on map: {} (Lvl {} - {})",
mapABInfo->playerCount,
mapABInfo->lowestPlayerLevel,
mapABInfo->highestPlayerLevel
);
// Adjusted player count (multiple scenarios)
if (mapABInfo->combatLockTripped)
handler->PSendSysMessage(ABGetLocaleText(locale, "adjusted_player_count_combat_locked").c_str(), mapABInfo->adjustedPlayerCount);
else if (mapABInfo->playerCount < mapABInfo->minPlayers && !PlayerCountDifficultyOffset)
handler->PSendSysMessage(ABGetLocaleText(locale, "adjusted_player_count_map_minimum").c_str(), mapABInfo->adjustedPlayerCount);
else if (mapABInfo->playerCount < mapABInfo->minPlayers && PlayerCountDifficultyOffset)
handler->PSendSysMessage(ABGetLocaleText(locale, "adjusted_player_count_map_minimum_difficulty_offset").c_str(), mapABInfo->adjustedPlayerCount, PlayerCountDifficultyOffset);
else if (PlayerCountDifficultyOffset)
handler->PSendSysMessage(ABGetLocaleText(locale, "adjusted_player_count_difficulty_offset").c_str(), mapABInfo->adjustedPlayerCount, PlayerCountDifficultyOffset);
else
handler->PSendSysMessage(ABGetLocaleText(locale, "adjusted_player_count").c_str(), mapABInfo->adjustedPlayerCount);
// LFG levels
handler->PSendSysMessage(ABGetLocaleText(locale, "lfg_range").c_str(), mapABInfo->lfgMinLevel, mapABInfo->lfgMaxLevel, mapABInfo->lfgTargetLevel);
// Calculated map level (creature average)
handler->PSendSysMessage(ABGetLocaleText(locale, "map_level").c_str(),
(uint8)(mapABInfo->avgCreatureLevel + 0.5f),
mapABInfo->isLevelScalingEnabled && mapABInfo->enabled ? "->" + std::to_string(mapABInfo->highestPlayerLevel) + ABGetLocaleText(locale, "level_scaling_enabled").c_str() : ABGetLocaleText(locale, "level_scaling_disabled").c_str()
);
// World Health Multiplier
handler->PSendSysMessage(ABGetLocaleText(locale, "world_health_multiplier").c_str(), mapABInfo->worldHealthMultiplier);
// World Damage and Healing Multiplier
if (mapABInfo->worldDamageHealingMultiplier != mapABInfo->scaledWorldDamageHealingMultiplier)
{
handler->PSendSysMessage(ABGetLocaleText(locale, "world_hostile_damage_healing_multiplier_to").c_str(),
mapABInfo->worldDamageHealingMultiplier,
mapABInfo->scaledWorldDamageHealingMultiplier
);
}
else
{
handler->PSendSysMessage(ABGetLocaleText(locale, "world_hostile_damage_healing_multiplier").c_str(),
mapABInfo->worldDamageHealingMultiplier
);
}
// Creature Stats
handler->PSendSysMessage(ABGetLocaleText(locale, "original_creature_level_range").c_str(),
mapABInfo->lowestCreatureLevel,
mapABInfo->highestCreatureLevel,
mapABInfo->avgCreatureLevel
);
handler->PSendSysMessage(ABGetLocaleText(locale, "active_total_creatures_in_map").c_str(),
mapABInfo->activeCreatureCount,
mapABInfo->allMapCreatures.size()
);
return true;
}
else
{
handler->PSendSysMessage(ABGetLocaleText(locale, "ab_command_only_in_instance").c_str());
return false;
}
}
bool AutoBalance_CommandScript::HandleABCreatureStatsCommand(ChatHandler* handler, const char* /*args*/)
{
Creature* target = handler->getSelectedCreature();
auto locale = handler->GetSession()->GetSessionDbLocaleIndex();
if (!target)
{
handler->SendSysMessage(LANG_SELECT_CREATURE);
handler->SetSentErrorMessage(true);
return false;
}
else if (!target->GetMap()->IsDungeon())
{
handler->PSendSysMessage(ABGetLocaleText(locale, "target_no_in_instance").c_str());
handler->SetSentErrorMessage(true);
return false;
}
AutoBalanceCreatureInfo* targetABInfo = target->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo");
handler->PSendSysMessage("---");
handler->PSendSysMessage("{} ({}{}{}), {}",
target->GetName(),
targetABInfo->UnmodifiedLevel,
isCreatureRelevant(target) && targetABInfo->UnmodifiedLevel != target->GetLevel() ? "->" + std::to_string(targetABInfo->selectedLevel) : "",
isBossOrBossSummon(target) ? " | Boss" : "",
targetABInfo->isActive ? ABGetLocaleText(locale, "active_for_map_stats").c_str() : ABGetLocaleText(locale, "ignored_for_map_stats").c_str());
handler->PSendSysMessage(ABGetLocaleText(locale, "creature_difficulty_level").c_str(), targetABInfo->instancePlayerCount);
// summon
if (target->IsSummon() && targetABInfo->summoner && targetABInfo->isCloneOfSummoner)
handler->PSendSysMessage(ABGetLocaleText(locale, "clone_of_summon").c_str(), targetABInfo->summonerName, targetABInfo->summonerLevel);
else if (target->IsSummon() && targetABInfo->summoner)
handler->PSendSysMessage(ABGetLocaleText(locale, "summon_of_summon").c_str(), targetABInfo->summonerName, targetABInfo->summonerLevel);
else if (target->IsSummon())
handler->PSendSysMessage(ABGetLocaleText(locale, "summon_without_summoner").c_str());
// level scaled
if (targetABInfo->UnmodifiedLevel != target->GetLevel())
{
handler->PSendSysMessage(ABGetLocaleText(locale, "health_multiplier_to").c_str(), targetABInfo->HealthMultiplier, targetABInfo->ScaledHealthMultiplier);
handler->PSendSysMessage(ABGetLocaleText(locale, "mana_multiplier_to").c_str(), targetABInfo->ManaMultiplier, targetABInfo->ScaledManaMultiplier);
handler->PSendSysMessage(ABGetLocaleText(locale, "armor_multiplier_to").c_str(), targetABInfo->ArmorMultiplier, targetABInfo->ScaledArmorMultiplier);
handler->PSendSysMessage(ABGetLocaleText(locale, "damage_multiplier_to").c_str(), targetABInfo->DamageMultiplier, targetABInfo->ScaledDamageMultiplier);
}
// not level scaled
else
{
handler->PSendSysMessage(ABGetLocaleText(locale, "health_multiplier").c_str(), targetABInfo->HealthMultiplier);
handler->PSendSysMessage(ABGetLocaleText(locale, "mana_multiplier").c_str(), targetABInfo->ManaMultiplier);
handler->PSendSysMessage(ABGetLocaleText(locale, "armor_multiplier").c_str(), targetABInfo->ArmorMultiplier);
handler->PSendSysMessage(ABGetLocaleText(locale, "damage_multiplier").c_str(), targetABInfo->DamageMultiplier);
}
handler->PSendSysMessage(ABGetLocaleText(locale, "cc_duration_multiplier").c_str(), targetABInfo->CCDurationMultiplier);
handler->PSendSysMessage(ABGetLocaleText(locale, "xp_money_multiplier").c_str(), targetABInfo->XPModifier, targetABInfo->MoneyModifier);
return true;
}
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_COMMAND_SCRIPT_H
#define __AB_COMMAND_SCRIPT_H
#include "Chat.h"
#include "Config.h"
#include "ScriptMgr.h"
using namespace Acore::ChatCommands;
class AutoBalance_CommandScript : public CommandScript
{
public:
AutoBalance_CommandScript() : CommandScript("AutoBalance_CommandScript") { }
ChatCommandTable GetCommands() const override
{
static ChatCommandTable ABCommandTable =
{
{ "setoffset", HandleABSetOffsetCommand, SEC_GAMEMASTER, Console::Yes },
{ "getoffset", HandleABGetOffsetCommand, SEC_PLAYER, Console::Yes },
{ "mapstat", HandleABMapStatsCommand, SEC_PLAYER, Console::Yes },
{ "creaturestat", HandleABCreatureStatsCommand, SEC_PLAYER, Console::Yes }
};
static ChatCommandTable commandTable =
{
{ "autobalance", ABCommandTable },
{ "ab", ABCommandTable },
};
return commandTable;
};
static bool HandleABSetOffsetCommand(ChatHandler* handler, const char* args);
static bool HandleABGetOffsetCommand(ChatHandler* handler, const char* args);
static bool HandleABMapStatsCommand(ChatHandler* handler, const char* args);
static bool HandleABCreatureStatsCommand(ChatHandler* handler, const char* args);
};
#endif /* __AB_COMMAND_SCRIPT_H */
+349
View File
@@ -0,0 +1,349 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#include "ABConfig.h"
#include "ABUtils.h"
std::map <int, int> forcedCreatureIds;
std::list<uint32> disabledDungeonIds;
uint32 minPlayersNormal;
uint32 minPlayersHeroic;
uint32 minPlayersRaid;
uint32 minPlayersRaidHeroic;
std::map<uint32, uint8> minPlayersPerDungeonIdMap;
std::map<uint32, uint8> minPlayersPerHeroicDungeonIdMap;
std::map<uint32, AutoBalanceInflectionPointSettings> dungeonOverrides;
std::map<uint32, AutoBalanceInflectionPointSettings> bossOverrides;
std::map<uint32, AutoBalanceStatModifiers> statModifierOverrides;
std::map<uint32, AutoBalanceStatModifiers> statModifierBossOverrides;
std::map<uint32, AutoBalanceStatModifiers> statModifierCreatureOverrides;
std::map<uint8, AutoBalanceLevelScalingDynamicLevelSettings> levelScalingDynamicLevelOverrides;
std::map<uint32, uint32> levelScalingDistanceCheckOverrides;
// spell IDs that spend player health
// player abilities don't actually appear to be caught by `ModifySpellDamageTaken`,
// but I'm leaving them here in case they ever DO get caught by it
std::list<uint32> spellIdsThatSpendPlayerHealth =
{
45529, // Blood Tap
2687, // Bloodrage
27869, // Dark Rune
16666, // Demonic Rune
755, // Health Funnel (Rank 1)
3698, // Health Funnel (Rank 2)
3699, // Health Funnel (Rank 3)
3700, // Health Funnel (Rank 4)
11693, // Health Funnel (Rank 5)
11694, // Health Funnel (Rank 6)
11695, // Health Funnel (Rank 7)
27259, // Health Funnel (Rank 8)
47856, // Health Funnel (Rank 9)
1454, // Life Tap (Rank 1)
1455, // Life Tap (Rank 2)
1456, // Life Tap (Rank 3)
11687, // Life Tap (Rank 4)
11688, // Life Tap (Rank 5)
11689, // Life Tap (Rank 6)
27222, // Life Tap (Rank 7)
57946, // Life Tap (Rank 8)
29858, // Soulshatter
55213 // Unholy Frenzy
};
// spell IDs that should never be modified
// handles cases where a spell is reflecting damage or otherwise converting player damage to something else
std::list<uint32> spellIdsToNeverModify =
{
1177 // Twin Empathy (AQ40 Twin Emperors, only in `spell_dbc` database table)
};
// creature IDs that should never be considered clones
// handles cases where a creature is spawned by another creature, but is not a clone (doesn't retain health/mana values)
std::list<uint32> creatureIDsThatAreNotClones =
{
16152 // Attumen the Huntsman (Karazhan) combined form
};
int8 PlayerCountDifficultyOffset;
bool LevelScaling;
int8 LevelScalingSkipHigherLevels;
int8 LevelScalingSkipLowerLevels;
int8 LevelScalingDynamicLevelCeilingDungeons;
int8 LevelScalingDynamicLevelFloorDungeons;
int8 LevelScalingDynamicLevelCeilingRaids;
int8 LevelScalingDynamicLevelFloorRaids;
int8 LevelScalingDynamicLevelCeilingHeroicDungeons;
int8 LevelScalingDynamicLevelFloorHeroicDungeons;
int8 LevelScalingDynamicLevelCeilingHeroicRaids;
int8 LevelScalingDynamicLevelFloorHeroicRaids;
ScalingMethod LevelScalingMethod;
uint32 rewardRaid;
uint32 rewardDungeon;
uint32 MinPlayerReward;
bool Announcement;
bool LevelScalingEndGameBoost;
bool PlayerChangeNotify;
bool rewardEnabled;
float MinHPModifier;
float MinManaModifier;
float MinDamageModifier;
float MinCCDurationModifier;
float MaxCCDurationModifier;
//
// RewardScaling.*
//
ScalingMethod RewardScalingMethod;
bool RewardScalingXP;
bool RewardScalingMoney;
float RewardScalingXPModifier;
float RewardScalingMoneyModifier;
uint64_t globalConfigTime = GetCurrentConfigTime();
//
// Enable.*
//
bool EnableGlobal;
bool Enable5M;
bool Enable10M;
bool Enable15M;
bool Enable20M;
bool Enable25M;
bool Enable40M;
bool Enable5MHeroic;
bool Enable10MHeroic;
bool Enable25MHeroic;
bool EnableOtherNormal;
bool EnableOtherHeroic;
//
// InflectionPoint*
//
float InflectionPoint;
float InflectionPointCurveFloor;
float InflectionPointCurveCeiling;
float InflectionPointBoss;
float InflectionPointHeroic;
float InflectionPointHeroicCurveFloor;
float InflectionPointHeroicCurveCeiling;
float InflectionPointHeroicBoss;
float InflectionPointRaid;
float InflectionPointRaidCurveFloor;
float InflectionPointRaidCurveCeiling;
float InflectionPointRaidBoss;
float InflectionPointRaidHeroic;
float InflectionPointRaidHeroicCurveFloor;
float InflectionPointRaidHeroicCurveCeiling;
float InflectionPointRaidHeroicBoss;
float InflectionPointRaid10M;
float InflectionPointRaid10MCurveFloor;
float InflectionPointRaid10MCurveCeiling;
float InflectionPointRaid10MBoss;
float InflectionPointRaid10MHeroic;
float InflectionPointRaid10MHeroicCurveFloor;
float InflectionPointRaid10MHeroicCurveCeiling;
float InflectionPointRaid10MHeroicBoss;
float InflectionPointRaid15M;
float InflectionPointRaid15MCurveFloor;
float InflectionPointRaid15MCurveCeiling;
float InflectionPointRaid15MBoss;
float InflectionPointRaid20M;
float InflectionPointRaid20MCurveFloor;
float InflectionPointRaid20MCurveCeiling;
float InflectionPointRaid20MBoss;
float InflectionPointRaid25M;
float InflectionPointRaid25MCurveFloor;
float InflectionPointRaid25MCurveCeiling;
float InflectionPointRaid25MBoss;
float InflectionPointRaid25MHeroic;
float InflectionPointRaid25MHeroicCurveFloor;
float InflectionPointRaid25MHeroicCurveCeiling;
float InflectionPointRaid25MHeroicBoss;
float InflectionPointRaid40M;
float InflectionPointRaid40MCurveFloor;
float InflectionPointRaid40MCurveCeiling;
float InflectionPointRaid40MBoss;
//
// StatModifier*
//
float StatModifier_Global;
float StatModifier_Health;
float StatModifier_Mana;
float StatModifier_Armor;
float StatModifier_Damage;
float StatModifier_CCDuration;
float StatModifierHeroic_Global;
float StatModifierHeroic_Health;
float StatModifierHeroic_Mana;
float StatModifierHeroic_Armor;
float StatModifierHeroic_Damage;
float StatModifierHeroic_CCDuration;
float StatModifierRaid_Global;
float StatModifierRaid_Health;
float StatModifierRaid_Mana;
float StatModifierRaid_Armor;
float StatModifierRaid_Damage;
float StatModifierRaid_CCDuration;
float StatModifierRaidHeroic_Global;
float StatModifierRaidHeroic_Health;
float StatModifierRaidHeroic_Mana;
float StatModifierRaidHeroic_Armor;
float StatModifierRaidHeroic_Damage;
float StatModifierRaidHeroic_CCDuration;
float StatModifierRaid10M_Global;
float StatModifierRaid10M_Health;
float StatModifierRaid10M_Mana;
float StatModifierRaid10M_Armor;
float StatModifierRaid10M_Damage;
float StatModifierRaid10M_CCDuration;
float StatModifierRaid10MHeroic_Global;
float StatModifierRaid10MHeroic_Health;
float StatModifierRaid10MHeroic_Mana;
float StatModifierRaid10MHeroic_Armor;
float StatModifierRaid10MHeroic_Damage;
float StatModifierRaid10MHeroic_CCDuration;
float StatModifierRaid15M_Global;
float StatModifierRaid15M_Health;
float StatModifierRaid15M_Mana;
float StatModifierRaid15M_Armor;
float StatModifierRaid15M_Damage;
float StatModifierRaid15M_CCDuration;
float StatModifierRaid20M_Global;
float StatModifierRaid20M_Health;
float StatModifierRaid20M_Mana;
float StatModifierRaid20M_Armor;
float StatModifierRaid20M_Damage;
float StatModifierRaid20M_CCDuration;
float StatModifierRaid25M_Global;
float StatModifierRaid25M_Health;
float StatModifierRaid25M_Mana;
float StatModifierRaid25M_Armor;
float StatModifierRaid25M_Damage;
float StatModifierRaid25M_CCDuration;
float StatModifierRaid25MHeroic_Global;
float StatModifierRaid25MHeroic_Health;
float StatModifierRaid25MHeroic_Mana;
float StatModifierRaid25MHeroic_Armor;
float StatModifierRaid25MHeroic_Damage;
float StatModifierRaid25MHeroic_CCDuration;
float StatModifierRaid40M_Global;
float StatModifierRaid40M_Health;
float StatModifierRaid40M_Mana;
float StatModifierRaid40M_Armor;
float StatModifierRaid40M_Damage;
float StatModifierRaid40M_CCDuration;
//
// StatModifier* (Boss)
//
float StatModifier_Boss_Global;
float StatModifier_Boss_Health;
float StatModifier_Boss_Mana;
float StatModifier_Boss_Armor;
float StatModifier_Boss_Damage;
float StatModifier_Boss_CCDuration;
float StatModifierHeroic_Boss_Global;
float StatModifierHeroic_Boss_Health;
float StatModifierHeroic_Boss_Mana;
float StatModifierHeroic_Boss_Armor;
float StatModifierHeroic_Boss_Damage;
float StatModifierHeroic_Boss_CCDuration;
float StatModifierRaid_Boss_Global;
float StatModifierRaid_Boss_Health;
float StatModifierRaid_Boss_Mana;
float StatModifierRaid_Boss_Armor;
float StatModifierRaid_Boss_Damage;
float StatModifierRaid_Boss_CCDuration;
float StatModifierRaidHeroic_Boss_Global;
float StatModifierRaidHeroic_Boss_Health;
float StatModifierRaidHeroic_Boss_Mana;
float StatModifierRaidHeroic_Boss_Armor;
float StatModifierRaidHeroic_Boss_Damage;
float StatModifierRaidHeroic_Boss_CCDuration;
float StatModifierRaid10M_Boss_Global;
float StatModifierRaid10M_Boss_Health;
float StatModifierRaid10M_Boss_Mana;
float StatModifierRaid10M_Boss_Armor;
float StatModifierRaid10M_Boss_Damage;
float StatModifierRaid10M_Boss_CCDuration;
float StatModifierRaid10MHeroic_Boss_Global;
float StatModifierRaid10MHeroic_Boss_Health;
float StatModifierRaid10MHeroic_Boss_Mana;
float StatModifierRaid10MHeroic_Boss_Armor;
float StatModifierRaid10MHeroic_Boss_Damage;
float StatModifierRaid10MHeroic_Boss_CCDuration;
float StatModifierRaid15M_Boss_Global;
float StatModifierRaid15M_Boss_Health;
float StatModifierRaid15M_Boss_Mana;
float StatModifierRaid15M_Boss_Armor;
float StatModifierRaid15M_Boss_Damage;
float StatModifierRaid15M_Boss_CCDuration;
float StatModifierRaid20M_Boss_Global;
float StatModifierRaid20M_Boss_Health;
float StatModifierRaid20M_Boss_Mana;
float StatModifierRaid20M_Boss_Armor;
float StatModifierRaid20M_Boss_Damage;
float StatModifierRaid20M_Boss_CCDuration;
float StatModifierRaid25M_Boss_Global;
float StatModifierRaid25M_Boss_Health;
float StatModifierRaid25M_Boss_Mana;
float StatModifierRaid25M_Boss_Armor;
float StatModifierRaid25M_Boss_Damage;
float StatModifierRaid25M_Boss_CCDuration;
float StatModifierRaid25MHeroic_Boss_Global;
float StatModifierRaid25MHeroic_Boss_Health;
float StatModifierRaid25MHeroic_Boss_Mana;
float StatModifierRaid25MHeroic_Boss_Armor;
float StatModifierRaid25MHeroic_Boss_Damage;
float StatModifierRaid25MHeroic_Boss_CCDuration;
float StatModifierRaid40M_Boss_Global;
float StatModifierRaid40M_Boss_Health;
float StatModifierRaid40M_Boss_Mana;
float StatModifierRaid40M_Boss_Armor;
float StatModifierRaid40M_Boss_Damage;
float StatModifierRaid40M_Boss_CCDuration;
+321
View File
@@ -0,0 +1,321 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_CONFIG_H
#define __AB_CONFIG_H
#include "ABInflectionPointSettings.h"
#include "ABLevelScalingDynamicLevelSettings.h"
#include "ABStatModifiers.h"
#include "AutoBalance.h"
#include "SharedDefines.h"
#include <list>
#include <map>
extern std::map<uint32, AutoBalanceInflectionPointSettings> dungeonOverrides;
extern std::map<uint32, AutoBalanceInflectionPointSettings> bossOverrides;
extern std::map<uint32, AutoBalanceStatModifiers> statModifierOverrides;
extern std::map<uint32, AutoBalanceStatModifiers> statModifierBossOverrides;
extern std::map<uint32, AutoBalanceStatModifiers> statModifierCreatureOverrides;
extern std::map<uint8 , AutoBalanceLevelScalingDynamicLevelSettings> levelScalingDynamicLevelOverrides;
extern std::map<uint32, uint32> levelScalingDistanceCheckOverrides;
extern std::map <int, int> forcedCreatureIds;
extern std::list<uint32> disabledDungeonIds;
extern uint32 minPlayersNormal;
extern uint32 minPlayersHeroic;
extern uint32 minPlayersRaid;
extern uint32 minPlayersRaidHeroic;
extern std::map<uint32, uint8> minPlayersPerDungeonIdMap;
extern std::map<uint32, uint8> minPlayersPerHeroicDungeonIdMap;
extern std::list<uint32> spellIdsThatSpendPlayerHealth;
extern std::list<uint32> spellIdsToNeverModify;
extern std::list<uint32> creatureIDsThatAreNotClones;
extern int8 PlayerCountDifficultyOffset;
extern bool LevelScaling;
extern int8 LevelScalingSkipHigherLevels;
extern int8 LevelScalingSkipLowerLevels;
extern int8 LevelScalingDynamicLevelCeilingDungeons;
extern int8 LevelScalingDynamicLevelFloorDungeons;
extern int8 LevelScalingDynamicLevelCeilingRaids;
extern int8 LevelScalingDynamicLevelFloorRaids;
extern int8 LevelScalingDynamicLevelCeilingHeroicDungeons;
extern int8 LevelScalingDynamicLevelFloorHeroicDungeons;
extern int8 LevelScalingDynamicLevelCeilingHeroicRaids;
extern int8 LevelScalingDynamicLevelFloorHeroicRaids;
extern ScalingMethod LevelScalingMethod;
extern uint32 rewardRaid;
extern uint32 rewardDungeon;
extern uint32 MinPlayerReward;
extern bool Announcement;
extern bool LevelScalingEndGameBoost;
extern bool PlayerChangeNotify;
extern bool rewardEnabled;
extern float MinHPModifier;
extern float MinManaModifier;
extern float MinDamageModifier;
extern float MinCCDurationModifier;
extern float MaxCCDurationModifier;
//
// RewardScaling.*
//
extern ScalingMethod RewardScalingMethod;
extern bool RewardScalingXP;
extern bool RewardScalingMoney;
extern float RewardScalingXPModifier;
extern float RewardScalingMoneyModifier;
extern uint64_t globalConfigTime;
//
// Enable.*
//
extern bool EnableGlobal;
extern bool Enable5M;
extern bool Enable10M;
extern bool Enable15M;
extern bool Enable20M;
extern bool Enable25M;
extern bool Enable40M;
extern bool Enable5MHeroic;
extern bool Enable10MHeroic;
extern bool Enable25MHeroic;
extern bool EnableOtherNormal;
extern bool EnableOtherHeroic;
//
// InflectionPoint*
//
extern float InflectionPoint;
extern float InflectionPointCurveFloor;
extern float InflectionPointCurveCeiling;
extern float InflectionPointBoss;
extern float InflectionPointHeroic;
extern float InflectionPointHeroicCurveFloor;
extern float InflectionPointHeroicCurveCeiling;
extern float InflectionPointHeroicBoss;
extern float InflectionPointRaid;
extern float InflectionPointRaidCurveFloor;
extern float InflectionPointRaidCurveCeiling;
extern float InflectionPointRaidBoss;
extern float InflectionPointRaidHeroic;
extern float InflectionPointRaidHeroicCurveFloor;
extern float InflectionPointRaidHeroicCurveCeiling;
extern float InflectionPointRaidHeroicBoss;
extern float InflectionPointRaid10M;
extern float InflectionPointRaid10MCurveFloor;
extern float InflectionPointRaid10MCurveCeiling;
extern float InflectionPointRaid10MBoss;
extern float InflectionPointRaid10MHeroic;
extern float InflectionPointRaid10MHeroicCurveFloor;
extern float InflectionPointRaid10MHeroicCurveCeiling;
extern float InflectionPointRaid10MHeroicBoss;
extern float InflectionPointRaid15M;
extern float InflectionPointRaid15MCurveFloor;
extern float InflectionPointRaid15MCurveCeiling;
extern float InflectionPointRaid15MBoss;
extern float InflectionPointRaid20M;
extern float InflectionPointRaid20MCurveFloor;
extern float InflectionPointRaid20MCurveCeiling;
extern float InflectionPointRaid20MBoss;
extern float InflectionPointRaid25M;
extern float InflectionPointRaid25MCurveFloor;
extern float InflectionPointRaid25MCurveCeiling;
extern float InflectionPointRaid25MBoss;
extern float InflectionPointRaid25MHeroic;
extern float InflectionPointRaid25MHeroicCurveFloor;
extern float InflectionPointRaid25MHeroicCurveCeiling;
extern float InflectionPointRaid25MHeroicBoss;
extern float InflectionPointRaid40M;
extern float InflectionPointRaid40MCurveFloor;
extern float InflectionPointRaid40MCurveCeiling;
extern float InflectionPointRaid40MBoss;
//
// StatModifier*
//
extern float StatModifier_Global;
extern float StatModifier_Health;
extern float StatModifier_Mana;
extern float StatModifier_Armor;
extern float StatModifier_Damage;
extern float StatModifier_CCDuration;
extern float StatModifierHeroic_Global;
extern float StatModifierHeroic_Health;
extern float StatModifierHeroic_Mana;
extern float StatModifierHeroic_Armor;
extern float StatModifierHeroic_Damage;
extern float StatModifierHeroic_CCDuration;
extern float StatModifierRaid_Global;
extern float StatModifierRaid_Health;
extern float StatModifierRaid_Mana;
extern float StatModifierRaid_Armor;
extern float StatModifierRaid_Damage;
extern float StatModifierRaid_CCDuration;
extern float StatModifierRaidHeroic_Global;
extern float StatModifierRaidHeroic_Health;
extern float StatModifierRaidHeroic_Mana;
extern float StatModifierRaidHeroic_Armor;
extern float StatModifierRaidHeroic_Damage;
extern float StatModifierRaidHeroic_CCDuration;
extern float StatModifierRaid10M_Global;
extern float StatModifierRaid10M_Health;
extern float StatModifierRaid10M_Mana;
extern float StatModifierRaid10M_Armor;
extern float StatModifierRaid10M_Damage;
extern float StatModifierRaid10M_CCDuration;
extern float StatModifierRaid10MHeroic_Global;
extern float StatModifierRaid10MHeroic_Health;
extern float StatModifierRaid10MHeroic_Mana;
extern float StatModifierRaid10MHeroic_Armor;
extern float StatModifierRaid10MHeroic_Damage;
extern float StatModifierRaid10MHeroic_CCDuration;
extern float StatModifierRaid15M_Global;
extern float StatModifierRaid15M_Health;
extern float StatModifierRaid15M_Mana;
extern float StatModifierRaid15M_Armor;
extern float StatModifierRaid15M_Damage;
extern float StatModifierRaid15M_CCDuration;
extern float StatModifierRaid20M_Global;
extern float StatModifierRaid20M_Health;
extern float StatModifierRaid20M_Mana;
extern float StatModifierRaid20M_Armor;
extern float StatModifierRaid20M_Damage;
extern float StatModifierRaid20M_CCDuration;
extern float StatModifierRaid25M_Global;
extern float StatModifierRaid25M_Health;
extern float StatModifierRaid25M_Mana;
extern float StatModifierRaid25M_Armor;
extern float StatModifierRaid25M_Damage;
extern float StatModifierRaid25M_CCDuration;
extern float StatModifierRaid25MHeroic_Global;
extern float StatModifierRaid25MHeroic_Health;
extern float StatModifierRaid25MHeroic_Mana;
extern float StatModifierRaid25MHeroic_Armor;
extern float StatModifierRaid25MHeroic_Damage;
extern float StatModifierRaid25MHeroic_CCDuration;
extern float StatModifierRaid40M_Global;
extern float StatModifierRaid40M_Health;
extern float StatModifierRaid40M_Mana;
extern float StatModifierRaid40M_Armor;
extern float StatModifierRaid40M_Damage;
extern float StatModifierRaid40M_CCDuration;
//
// StatModifier* (Boss)
//
extern float StatModifier_Boss_Global;
extern float StatModifier_Boss_Health;
extern float StatModifier_Boss_Mana;
extern float StatModifier_Boss_Armor;
extern float StatModifier_Boss_Damage;
extern float StatModifier_Boss_CCDuration;
extern float StatModifierHeroic_Boss_Global;
extern float StatModifierHeroic_Boss_Health;
extern float StatModifierHeroic_Boss_Mana;
extern float StatModifierHeroic_Boss_Armor;
extern float StatModifierHeroic_Boss_Damage;
extern float StatModifierHeroic_Boss_CCDuration;
extern float StatModifierRaid_Boss_Global;
extern float StatModifierRaid_Boss_Health;
extern float StatModifierRaid_Boss_Mana;
extern float StatModifierRaid_Boss_Armor;
extern float StatModifierRaid_Boss_Damage;
extern float StatModifierRaid_Boss_CCDuration;
extern float StatModifierRaidHeroic_Boss_Global;
extern float StatModifierRaidHeroic_Boss_Health;
extern float StatModifierRaidHeroic_Boss_Mana;
extern float StatModifierRaidHeroic_Boss_Armor;
extern float StatModifierRaidHeroic_Boss_Damage;
extern float StatModifierRaidHeroic_Boss_CCDuration;
extern float StatModifierRaid10M_Boss_Global;
extern float StatModifierRaid10M_Boss_Health;
extern float StatModifierRaid10M_Boss_Mana;
extern float StatModifierRaid10M_Boss_Armor;
extern float StatModifierRaid10M_Boss_Damage;
extern float StatModifierRaid10M_Boss_CCDuration;
extern float StatModifierRaid10MHeroic_Boss_Global;
extern float StatModifierRaid10MHeroic_Boss_Health;
extern float StatModifierRaid10MHeroic_Boss_Mana;
extern float StatModifierRaid10MHeroic_Boss_Armor;
extern float StatModifierRaid10MHeroic_Boss_Damage;
extern float StatModifierRaid10MHeroic_Boss_CCDuration;
extern float StatModifierRaid15M_Boss_Global;
extern float StatModifierRaid15M_Boss_Health;
extern float StatModifierRaid15M_Boss_Mana;
extern float StatModifierRaid15M_Boss_Armor;
extern float StatModifierRaid15M_Boss_Damage;
extern float StatModifierRaid15M_Boss_CCDuration;
extern float StatModifierRaid40M_Boss_Damage;
extern float StatModifierRaid20M_Boss_Global;
extern float StatModifierRaid20M_Boss_Health;
extern float StatModifierRaid20M_Boss_Mana;
extern float StatModifierRaid20M_Boss_Armor;
extern float StatModifierRaid20M_Boss_Damage;
extern float StatModifierRaid20M_Boss_CCDuration;
extern float StatModifierRaid25M_Boss_Global;
extern float StatModifierRaid25M_Boss_Health;
extern float StatModifierRaid25M_Boss_Mana;
extern float StatModifierRaid25M_Boss_Armor;
extern float StatModifierRaid25M_Boss_Damage;
extern float StatModifierRaid25M_Boss_CCDuration;
extern float StatModifierRaid25MHeroic_Boss_Global;
extern float StatModifierRaid25MHeroic_Boss_Health;
extern float StatModifierRaid25MHeroic_Boss_Mana;
extern float StatModifierRaid25MHeroic_Boss_Armor;
extern float StatModifierRaid25MHeroic_Boss_Damage;
extern float StatModifierRaid25MHeroic_Boss_CCDuration;
extern float StatModifierRaid40M_Boss_Global;
extern float StatModifierRaid40M_Boss_Health;
extern float StatModifierRaid40M_Boss_Mana;
extern float StatModifierRaid40M_Boss_Armor;
extern float StatModifierRaid40M_Boss_CCDuration;
#endif
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_CREATURE_INFO_H
#define __AB_CREATURE_INFO_H
#include "AutoBalance.h"
#include "Creature.h"
#include "DataMap.h"
class AutoBalanceCreatureInfo : public DataMap::Base
{
public:
AutoBalanceCreatureInfo() {}
uint64_t mapConfigTime = 1; // The last map config time that this creature was updated
uint32 instancePlayerCount = 0; // The number of players this creature has been scaled for
uint8 selectedLevel = 0; // The level that this creature should be set to
float DamageMultiplier = 1.0f; // Per-player damage multiplier (no level scaling)
float ScaledDamageMultiplier = 1.0f; // Per-player and level scaling damage multiplier
float HealthMultiplier = 1.0f; // Per-player health multiplier (no level scaling)
float ScaledHealthMultiplier = 1.0f; // Per-player and level scaling health multiplier
float ManaMultiplier = 1.0f; // Per-player mana multiplier (no level scaling)
float ScaledManaMultiplier = 1.0f; // Per-player and level scaling mana multiplier
float ArmorMultiplier = 1.0f; // Per-player armor multiplier (no level scaling)
float ScaledArmorMultiplier = 1.0f; // Per-player and level scaling armor multiplier
float CCDurationMultiplier = 1.0f; // Per-player crowd control duration multiplier (level scaling doesn't affect this)
float XPModifier = 1.0f; // Per-player XP modifier (level scaling provided by normal XP distribution)
float MoneyModifier = 1.0f; // Per-player money modifier (no level scaling)
uint8 UnmodifiedLevel = 0; // Original level of the creature as determined by the game
bool isActive = false; // Whether or not the current creature is affecting map stats. May change as conditions change.
bool wasAliveNowDead = false; // Whether or not the creature was alive and is now dead
bool isInCreatureList = false; // Whether or not the creature is in the map's creature list
bool isBrandNew = false; // Whether or not the creature is brand new to the map (hasn't been added to the world yet)
bool neverLevelScale = false; // Whether or not the creature should never be level scaled (can still be player scaled)
uint32 initialMaxHealth = 0; // Stored max health value to be applied just before being added to the world
// creature->IsSummon() // Whether or not the creature is a summon
Creature* summoner = nullptr; // The creature that summoned this creature
std::string summonerName = ""; // The name of the creature that summoned this creature
uint8 summonerLevel = 0; // The level of the creature that summoned this creature
bool isCloneOfSummoner = false; // Whether or not the creature is a clone of its summoner
Relevance relevance = AUTOBALANCE_RELEVANCE_UNCHECKED; // Whether or not the creature is relevant for scaling
};
#endif
@@ -0,0 +1,176 @@
#include "ABGameObjectScript.h"
#include "ABConfig.h"
#include "ABMapInfo.h"
#include "ABUtils.h"
void AutoBalance_GameObjectScript::OnGameObjectModifyHealth(GameObject* target, Unit* source, int32& amount, SpellInfo const* spellInfo)
{
// uncomment to debug this hook
bool _debug_damage_and_healing = (source && target && (source->GetTypeId() == TYPEID_PLAYER || source->IsControlledByPlayer()));
if (_debug_damage_and_healing)
_Debug_Output("OnGameObjectModifyHealth", target, source, amount, "BEFORE:", spellInfo->SpellName[0], spellInfo->Id);
// modify the amount
amount = _Modify_GameObject_Damage_Healing(target, source, amount, spellInfo);
if (_debug_damage_and_healing)
_Debug_Output("OnGameObjectModifyHealth", target, source, amount, "AFTER:", spellInfo->SpellName[0], spellInfo->Id);
}
void AutoBalance_GameObjectScript::_Debug_Output(std::string function_name, GameObject* target, Unit* source, int32 amount, std::string prefix, std::string spell_name, uint32 spell_id)
{
if (target && source && amount)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_GameObjectScript::{}: {} {} {} {} ({} - {})",
function_name,
prefix,
source->GetName(),
amount,
target->GetName(),
spell_name,
spell_id
);
}
else if (target && source)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_GameObjectScript::{}: {} {} 0 {} ({} - {})",
function_name,
prefix,
source->GetName(),
target->GetName(),
spell_name,
spell_id
);
}
else if (target && amount)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_GameObjectScript::{}: {} ?? {} {} ({} - {})",
function_name,
prefix,
amount,
target->GetName(),
spell_name,
spell_id
);
}
else if (target)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_GameObjectScript::{}: {} ?? ?? {} ({} - {})",
function_name,
prefix,
target->GetName(),
spell_name,
spell_id
);
}
else
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_GameObjectScript::{}: {} W? T? F? ({} - {})",
function_name,
prefix,
spell_name,
spell_id
);
}
}
int32 AutoBalance_GameObjectScript::_Modify_GameObject_Damage_Healing(GameObject* target, Unit* source, int32 amount, SpellInfo const* spellInfo)
{
//
// Pre-flight Checks
//
// uncomment to debug this function
bool _debug_damage_and_healing = (source && target && (source->GetTypeId() == TYPEID_PLAYER || source->IsControlledByPlayer()));
// check that we're enabled globally, else return the original value
if (!EnableGlobal)
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_GameObjectScript::_Modify_GameObject_Damage_Healing: EnableGlobal is false, returning original value of ({}).", amount);
return amount;
}
// make sure the target is in an instance, else return the original damage
if (!(target->GetMap()->IsDungeon()))
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_GameObjectScript::_Modify_GameObject_Damage_Healing: Target is not in an instance, returning original value of ({}).", amount);
return amount;
}
// make sure the target is in the world, else return the original value
if (!target->IsInWorld())
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_GameObjectScript::_Modify_GameObject_Damage_Healing: Target does not exist in the world, returning original value of ({}).", amount);
return amount;
}
// if the spell ID is in our "never modify" list, return the original value
if
(
spellInfo &&
spellInfo->Id &&
std::find
(
spellIdsToNeverModify.begin(),
spellIdsToNeverModify.end(),
spellInfo->Id
) != spellIdsToNeverModify.end()
)
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Spell {}({}) is in the never modify list, returning original value of ({}).",
spellInfo->SpellName[0],
spellInfo->Id,
amount
);
return amount;
}
// get the map's info
AutoBalanceMapInfo* targetMapABInfo = GetMapInfo(target->GetMap());
// if the target's map is not enabled, return the original damage
if (!targetMapABInfo->enabled)
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_GameObjectScript::_Modify_GameObject_Damage_Healing: Target's map is not enabled, returning original value of ({}).", amount);
return amount;
}
//
// Multiplier calculation
//
// calculate the new damage amount using the map's World Health Multiplier
int32 newAmount = _Calculate_Amount_For_GameObject(target, amount, targetMapABInfo->worldHealthMultiplier);
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_GameObjectScript::_Modify_GameObject_Damage_Healing: Returning modified damage: ({}) -> ({})", amount, newAmount);
return newAmount;
}
int32 AutoBalance_GameObjectScript::_Calculate_Amount_For_GameObject(GameObject* target, int32 amount, float multiplier)
{
// since it would be very complicated to reduce the real health of destructible game objects, instead we will
// adjust the damage to them as though their health were scaled. Damage will usually be dealt by vehicles and
// other non-player sources, so this effect shouldn't be as noticable as if we applied it to the player.
uint32 realMaxHealth = target->GetGOValue()->Building.MaxHealth;
uint32 scaledMaxHealth = realMaxHealth * multiplier;
float percentDamageOfScaledMaxHealth = (float)amount / (float)scaledMaxHealth;
uint32 scaledAmount = realMaxHealth * percentDamageOfScaledMaxHealth;
return scaledAmount;
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_GAME_OBJECT_SCRIPT_H
#define __AB_GAME_OBJECT_SCRIPT_H
#include "ScriptMgr.h"
#include "SpellInfo.h"
#include "Unit.h"
class AutoBalance_GameObjectScript : public AllGameObjectScript
{
public:
AutoBalance_GameObjectScript()
: AllGameObjectScript("AutoBalance_GameObjectScript")
{}
void OnGameObjectModifyHealth(GameObject* target, Unit* source, int32& amount, SpellInfo const* spellInfo) override;
private:
[[maybe_unused]] bool _debug_damage_and_healing = false; // defaults to false, overwritten in each function
void _Debug_Output(std::string function_name, GameObject* target, Unit* source, int32 amount, std::string prefix = "", std::string spell_name = "Unknown Spell", uint32 spell_id = 0);
int32 _Modify_GameObject_Damage_Healing(GameObject* target, Unit* source, int32 amount, SpellInfo const* spellInfo);
int32 _Calculate_Amount_For_GameObject(GameObject* target, int32 amount, float multiplier);
};
#endif
@@ -0,0 +1,45 @@
#include "ABGlobalScript.h"
#include "ABConfig.h"
#include "ABMapInfo.h"
#include "ABUtils.h"
void AutoBalance_GlobalScript::OnAfterUpdateEncounterState(Map* map, EncounterCreditType type, uint32 /*creditEntry*/, Unit* /*source*/, Difficulty /*difficulty_fixed*/, DungeonEncounterList const* /*encounters*/, uint32 /*dungeonCompleted*/, bool updated)
{
//if (!dungeonCompleted)
// return;
if (!rewardEnabled || !updated)
return;
AutoBalanceMapInfo* mapABInfo = GetMapInfo(map);
if (mapABInfo->adjustedPlayerCount < MinPlayerReward)
return;
// skip if it's not a pre-wotlk dungeon/raid and if it's not scaled
if (!LevelScaling || mapABInfo->mapLevel <= 70 || mapABInfo->lfgMinLevel <= 70
// skip when not in dungeon or not kill credit
|| type != ENCOUNTER_CREDIT_KILL_CREATURE || !map->IsDungeon())
return;
Map::PlayerList const& playerList = map->GetPlayers();
if (playerList.IsEmpty())
return;
uint32 reward = map->ToInstanceMap()->GetMaxPlayers() > 5 ? rewardRaid : rewardDungeon;
if (!reward)
return;
//instanceStart=0, endTime;
uint8 difficulty = map->GetDifficulty();
for (Map::PlayerList::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr)
{
if (!itr->GetSource() || itr->GetSource()->IsGameMaster() || itr->GetSource()->GetLevel() < DEFAULT_MAX_LEVEL)
continue;
itr->GetSource()->AddItem(reward, 1 + difficulty); // difficulty boost
}
}
@@ -0,0 +1,19 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_GLOBAL_SCRIPT_H
#define __AB_GLOBAL_SCRIPT_H
#include "ScriptMgr.h"
class AutoBalance_GlobalScript : public GlobalScript {
public:
AutoBalance_GlobalScript() : GlobalScript("AutoBalance_GlobalScript", {
GLOBALHOOK_ON_AFTER_UPDATE_ENCOUNTER_STATE
}) { }
void OnAfterUpdateEncounterState(Map* map, EncounterCreditType type, uint32 creditEntry, Unit* source, Difficulty difficulty_fixed, DungeonEncounterList const* encounters, uint32 dungeonCompleted, bool updated) override;
};
#endif /* __AB_GLOBAL_SCRIPT_H */
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_INFLECTION_POINT_SETTINGS_H
#define __AB_INFLECTION_POINT_SETTINGS_H
#include "DataMap.h"
class AutoBalanceInflectionPointSettings : public DataMap::Base
{
public:
AutoBalanceInflectionPointSettings() {}
AutoBalanceInflectionPointSettings(float value, float curveFloor, float curveCeiling) :
value(value), curveFloor(curveFloor), curveCeiling(curveCeiling) {}
float value = 0.5;
float curveFloor = 0.0;
float curveCeiling = 1.0;
};
#endif
@@ -0,0 +1,23 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_LEVEL_SCALING_DYNAMIC_LEVEL_SETTINGS_H
#define __AB_LEVEL_SCALING_DYNAMIC_LEVEL_SETTINGS_H
#include "DataMap.h"
class AutoBalanceLevelScalingDynamicLevelSettings : public DataMap::Base
{
public:
AutoBalanceLevelScalingDynamicLevelSettings() {}
AutoBalanceLevelScalingDynamicLevelSettings(int skipHigher, int skipLower, int ceiling, int floor) :
skipHigher(skipHigher), skipLower(skipLower), ceiling(ceiling), floor(floor) {}
int skipHigher = 0;
int skipLower = 0;
int ceiling = 1;
int floor = 1;
};
#endif
+62
View File
@@ -0,0 +1,62 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_MAP_INFO_H
#define __AB_MAP_INFO_H
#include "Creature.h"
#include "DataMap.h"
#include "Player.h"
#include <vector>
class AutoBalanceMapInfo : public DataMap::Base
{
public:
AutoBalanceMapInfo() {}
std::vector<Creature*> allMapCreatures; // All creatures in the map, active and non-active
std::vector<Player*> allMapPlayers; // All players that are currently in the map
bool enabled = false; // Should AutoBalance make any changes to this map or its creatures?
uint64_t globalConfigTime = 1; // The last global config time that this map was updated
uint64_t mapConfigTime = 1; // The last map config time that this map was updated
uint8 playerCount = 0; // The actual number of non-GM players in the map
uint8 adjustedPlayerCount = 0; // The currently difficulty level expressed as number of players
uint8 minPlayers = 1; // Will be set by the config
uint8 mapLevel = 0; // Calculated from the avgCreatureLevel
uint8 lowestPlayerLevel = 0; // The lowest-level player in the map
uint8 highestPlayerLevel = 0; // The highest-level player in the map
uint8 lfgMinLevel = 0; // The minimum level for the map according to LFG
uint8 lfgTargetLevel = 0; // The target level for the map according to LFG
uint8 lfgMaxLevel = 0; // The maximum level for the map according to LFG
uint8 worldMultiplierTargetLevel = 0; // The level of the pseudo-creature that the world modifiers scale to
float worldDamageHealingMultiplier = 1.0f; // The damage/healing multiplier for the world (where source isn't an enemy creature)
float scaledWorldDamageHealingMultiplier = 1.0f; // The damage/healing multiplier for the world (where source isn't an enemy creature)
float worldHealthMultiplier = 1.0f; // The "health" multiplier for any destructible buildings in the map
bool combatLocked = false; // Whether or not the map is combat locked
bool combatLockTripped = false; // Set to true when combat locking was needed during this current combat (some tried to leave)
uint8 combatLockMinPlayers = 0; // The instance cannot be set to less than this number of players until combat ends
uint8 highestCreatureLevel = 0; // The highest-level creature in the map
uint8 lowestCreatureLevel = 0; // The lowest-level creature in the map
float avgCreatureLevel = 0; // The average level of all active creatures in the map (continuously updated)
uint32 activeCreatureCount = 0; // The number of creatures in the map that are included in the map's stats (not necessarily alive)
bool isLevelScalingEnabled = false; // Whether level scaling is enabled on this map
uint8 levelScalingSkipHigherLevels = 0; // Used to determine if this map should scale or not
uint8 levelScalingSkipLowerLevels = 0; // Used to determine if this map should scale or not
uint8 levelScalingDynamicCeiling = 0; // How many levels MORE than the highestPlayerLevel creature should be scaled to
uint8 levelScalingDynamicFloor = 0; // How many levels LESS than the highestPlayerLevel creature should be scaled to
uint8 prevMapLevel = 0; // Used to reduce calculations when they are not necessary
bool initialized = false; // Whether or not the map has been initialized
};
#endif
@@ -0,0 +1,11 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#include "ABModuleScript.h"
ABModuleScript::ABModuleScript(const char* name)
: ModuleScript(name)
{
ScriptRegistry<ABModuleScript>::AddScript(this);
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_MODULE_SCRIPT_H
#define __AB_MODULE_SCRIPT_H
#include "Creature.h"
#include "ScriptMgr.h"
/*
* Dedicated hooks for Autobalance Module
* Can be used to extend/customize this system
*/
class ABModuleScript : public ModuleScript
{
protected:
ABModuleScript(const char* name);
public:
virtual bool OnBeforeModifyAttributes(Creature* /*creature*/, uint32& /*instancePlayerCount*/) { return true; }
virtual bool OnAfterDefaultMultiplier(Creature* /*creature*/, float& /*defaultMultiplier*/) { return true; }
virtual bool OnBeforeUpdateStats (Creature* /*creature*/, uint32& /*scaledHealth*/, uint32& /*scaledMana*/, float& /*damageMultiplier*/, uint32& /*newBaseArmor*/) { return true; }
};
template class ScriptRegistry<ABModuleScript>;
#endif
@@ -0,0 +1,242 @@
#include <string>
#include "ABConfig.h"
#include "ABCreatureInfo.h"
#include "ABMapInfo.h"
#include "ABPlayerScript.h"
#include "ABUtils.h"
#include "Chat.h"
#include "Message.h"
void AutoBalance_PlayerScript::OnPlayerLogin(Player* Player)
{
if (EnableGlobal && Announcement)
ChatHandler(Player->GetSession()).SendSysMessage("This server is running the |cff4CFF00AutoBalance |rmodule.");
}
void AutoBalance_PlayerScript::OnPlayerLevelChanged(Player* player, uint8 oldlevel)
{
LOG_DEBUG("module.AutoBalance", "AutoBalance:: ------------------------------------------------");
LOG_DEBUG("module.AutoBalance", "AutoBalance_PlayerScript::OnLevelChanged: {} has leveled ({}->{})", player->GetName(), oldlevel, player->GetLevel());
if (!player || player->IsGameMaster())
return;
Map* map = player->GetMap();
if (!map || !map->IsDungeon())
return;
// update the map's player stats
UpdateMapPlayerStats(map);
// schedule all creatures for an update
AutoBalanceMapInfo* mapABInfo = GetMapInfo(map);
mapABInfo->mapConfigTime = GetCurrentConfigTime();
}
void AutoBalance_PlayerScript::OnPlayerGiveXP(Player* player, uint32& amount, Unit* victim, uint8 /*xpSource*/)
{
Map* map = player->GetMap();
// If this isn't a dungeon, make no changes
if (!map->IsDungeon() || !map->GetInstanceId() || !victim)
return;
AutoBalanceMapInfo* mapABInfo = GetMapInfo(map);
if (victim && RewardScalingXP && mapABInfo->enabled)
{
Map* map = player->GetMap();
AutoBalanceCreatureInfo* creatureABInfo = victim->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo");
if (map->IsDungeon())
{
if (RewardScalingMethod == AUTOBALANCE_SCALING_DYNAMIC)
{
LOG_DEBUG("module.AutoBalance", "AutoBalance_PlayerScript::OnGiveXP: Distributing XP from '{}' to '{}' in dynamic mode - {}->{}",
victim->GetName(), player->GetName(), amount, uint32(amount * creatureABInfo->XPModifier));
amount = uint32(amount * creatureABInfo->XPModifier);
}
else if (RewardScalingMethod == AUTOBALANCE_SCALING_FIXED)
{
// Ensure that the players always get the same XP, even when entering the dungeon alone
auto maxPlayerCount = map->ToInstanceMap()->GetMaxPlayers();
auto currentPlayerCount = mapABInfo->playerCount;
LOG_DEBUG("module.AutoBalance", "AutoBalance_PlayerScript::OnGiveXP: Distributing XP from '{}' to '{}' in fixed mode - {}->{}",
victim->GetName(), player->GetName(), amount, uint32(amount * creatureABInfo->XPModifier * ((float)currentPlayerCount / maxPlayerCount)));
amount = uint32(amount * creatureABInfo->XPModifier * ((float)currentPlayerCount / maxPlayerCount));
}
}
}
}
void AutoBalance_PlayerScript::OnPlayerBeforeLootMoney(Player* player, Loot* loot)
{
Map* map = player->GetMap();
// If this isn't a dungeon, make no changes
if (!map->IsDungeon())
return;
AutoBalanceMapInfo* mapABInfo = GetMapInfo(map);
ObjectGuid sourceGuid = loot->sourceWorldObjectGUID;
if (mapABInfo->enabled && RewardScalingMoney)
{
// if the loot source is a creature, honor the modifiers for that creature
if (sourceGuid.IsCreature())
{
Creature* sourceCreature = ObjectAccessor::GetCreature(*player, sourceGuid);
AutoBalanceCreatureInfo* creatureABInfo = sourceCreature->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo");
// Dynamic Mode
if (RewardScalingMethod == AUTOBALANCE_SCALING_DYNAMIC)
{
LOG_DEBUG("module.AutoBalance", "AutoBalance_PlayerScript::OnBeforeLootMoney: Distributing money from '{}' in dynamic mode - {}->{}",
sourceCreature->GetName(), loot->gold, uint32(loot->gold * creatureABInfo->MoneyModifier));
loot->gold = uint32(loot->gold * creatureABInfo->MoneyModifier);
}
// Fixed Mode
else if (RewardScalingMethod == AUTOBALANCE_SCALING_FIXED)
{
// Ensure that the players always get the same money, even when entering the dungeon alone
auto maxPlayerCount = map->ToInstanceMap()->GetMaxPlayers();
auto currentPlayerCount = mapABInfo->playerCount;
LOG_DEBUG("module.AutoBalance", "AutoBalance_PlayerScript::OnBeforeLootMoney: Distributing money from '{}' in fixed mode - {}->{}",
sourceCreature->GetName(), loot->gold, uint32(loot->gold * creatureABInfo->MoneyModifier * ((float)currentPlayerCount / maxPlayerCount)));
loot->gold = uint32(loot->gold * creatureABInfo->MoneyModifier * ((float)currentPlayerCount / maxPlayerCount));
}
}
// for all other loot sources, just distribute in Fixed mode as though the instance was full
else
{
auto maxPlayerCount = map->ToInstanceMap()->GetMaxPlayers();
auto currentPlayerCount = mapABInfo->playerCount;
LOG_DEBUG("module.AutoBalance", "AutoBalance_PlayerScript::OnBeforeLootMoney: Distributing money from a non-creature in fixed mode - {}->{}",
loot->gold, uint32(loot->gold * ((float)currentPlayerCount / maxPlayerCount)));
loot->gold = uint32(loot->gold * ((float)currentPlayerCount / maxPlayerCount));
}
}
}
void AutoBalance_PlayerScript::OnPlayerEnterCombat(Player* player, Unit* /*enemy*/)
{
// if the player or their map is gone, return
if (!player || !player->GetMap())
return;
Map* map = player->GetMap();
// If this isn't a dungeon, no work to do
if (!map || !map->IsDungeon())
return;
LOG_DEBUG("module.AutoBalance_CombatLocking", "AutoBalance_PlayerScript::OnPlayerEnterCombat: {} enters combat.", player->GetName());
AutoBalanceMapInfo* mapABInfo = GetMapInfo(map);
// if this map isn't enabled, no work to do
if (!mapABInfo->enabled)
return;
// lock the current map
if (!mapABInfo->combatLocked)
{
mapABInfo->combatLocked = true;
mapABInfo->combatLockMinPlayers = mapABInfo->playerCount;
LOG_DEBUG("module.AutoBalance_CombatLocking", "AutoBalance_PlayerScript::OnPlayerEnterCombat: Map {} ({}{}) | Locking difficulty to no less than ({}) as {} enters combat.",
map->GetMapName(),
map->GetId(),
map->GetInstanceId() ? "-" + std::to_string(map->GetInstanceId()) : "",
mapABInfo->combatLockMinPlayers,
player->GetName()
);
}
}
void AutoBalance_PlayerScript::OnPlayerLeaveCombat(Player* player)
{
// if the player or their map is gone, return
if (!player || !player->GetMap())
return;
Map* map = player->GetMap();
// If this isn't a dungeon, no work to do
if (!map || !map->IsDungeon())
return;
// this hook can get called even if the player isn't in combat
// I believe this happens whenever AC attempts to remove combat, but it doesn't check to see if the player is in combat first
// unfortunately, `player->IsInCombat()` doesn't work here
LOG_DEBUG("module.AutoBalance_CombatLocking", "AutoBalance_PlayerScript::OnPlayerLeaveCombat: {} leaves (or wasn't in) combat.", player->GetName());
AutoBalanceMapInfo* mapABInfo = GetMapInfo(map);
// if this map isn't enabled, no work to do
if (!mapABInfo->enabled)
return;
// check to see if any of the other players are in combat
bool anyPlayersInCombat = false;
for (auto player : mapABInfo->allMapPlayers)
{
if (player && player->IsInCombat())
{
anyPlayersInCombat = true;
LOG_DEBUG("module.AutoBalance_CombatLocking", "AutoBalance_PlayerScript::OnPlayerLeaveCombat: Map {} ({}{}) | Player {} (and potentially others) are still in combat.",
map->GetMapName(),
map->GetId(),
map->GetInstanceId() ? "-" + std::to_string(map->GetInstanceId()) : "",
player->GetName()
);
break;
}
}
auto locale = player->GetSession()->GetSessionDbLocaleIndex();
// if no players are in combat, unlock the map
if (!anyPlayersInCombat && mapABInfo->combatLocked)
{
mapABInfo->combatLocked = false;
mapABInfo->combatLockMinPlayers = 0;
LOG_DEBUG("module.AutoBalance_CombatLocking", "AutoBalance_PlayerScript::OnPlayerLeaveCombat: Map {} ({}{}) | Unlocking difficulty as {} leaves combat.",
map->GetMapName(),
map->GetId(),
map->GetInstanceId() ? "-" + std::to_string(map->GetInstanceId()) : "",
player->GetName()
);
// if the combat lock needed to be used, notify the players of it lifting
if (mapABInfo->combatLockTripped)
{
for (auto player : mapABInfo->allMapPlayers)
{
if (player && player->GetSession())
ChatHandler(player->GetSession()).PSendSysMessage(ABGetLocaleText(locale, "leaving_instance_combat_change").c_str());
}
}
// if the number of players changed while combat was in progress, schedule the map for an update
if (mapABInfo->combatLockTripped && mapABInfo->playerCount != mapABInfo->combatLockMinPlayers)
{
mapABInfo->mapConfigTime = 1;
LOG_DEBUG("module.AutoBalance_CombatLocking", "AutoBalance_PlayerScript::OnPlayerLeaveCombat: Map {} ({}{}) | Reset map config time to ({}).",
map->GetMapName(),
map->GetId(),
map->GetInstanceId() ? "-" + std::to_string(map->GetInstanceId()) : "",
mapABInfo->mapConfigTime
);
mapABInfo->combatLockTripped = false;
}
}
}
@@ -0,0 +1,28 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_PLAYER_SCRIPT_H
#define __AB_PLAYER_SCRIPT_H
#include "Player.h"
#include "ScriptMgr.h"
#include "Unit.h"
class AutoBalance_PlayerScript : public PlayerScript
{
public:
AutoBalance_PlayerScript()
: PlayerScript("AutoBalance_PlayerScript")
{
}
void OnPlayerLogin(Player* Player) override;
virtual void OnPlayerLevelChanged(Player* player, uint8 oldlevel) override;
void OnPlayerGiveXP(Player* player, uint32& amount, Unit* victim, uint8 xpSource) override;
void OnPlayerBeforeLootMoney(Player* player, Loot* loot) override;
virtual void OnPlayerEnterCombat(Player* player, Unit* enemy) override;
virtual void OnPlayerLeaveCombat(Player* player) override;
};
#endif /* __AB_PLAYER_SCRIPT_H */
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#include "ABModuleScript.h"
#include "ABScriptMgr.h"
#include "ScriptMgr.h"
#include "ScriptMgrMacros.h"
ABScriptMgr* ABScriptMgr::instance()
{
static ABScriptMgr instance;
return &instance;
}
bool ABScriptMgr::OnBeforeModifyAttributes(Creature* creature, uint32& instancePlayerCount)
{
auto ret = IsValidBoolScript<ABModuleScript>([&](ABModuleScript* script)
{
return !script->OnBeforeModifyAttributes(creature, instancePlayerCount);
});
if (ret && *ret)
return false;
return true;
}
bool ABScriptMgr::OnAfterDefaultMultiplier(Creature* creature, float& defaultMultiplier)
{
auto ret = IsValidBoolScript<ABModuleScript>([&](ABModuleScript* script)
{
return !script->OnAfterDefaultMultiplier(creature, defaultMultiplier);
});
if (ret && *ret)
return false;
return true;
}
bool ABScriptMgr::OnBeforeUpdateStats(Creature* creature, uint32& scaledHealth, uint32& scaledMana, float& damageMultiplier, uint32& newBaseArmor)
{
auto ret = IsValidBoolScript<ABModuleScript>([&](ABModuleScript* script)
{
return !script->OnBeforeUpdateStats(creature, scaledHealth, scaledMana, damageMultiplier, newBaseArmor);
});
if (ret && *ret)
return false;
return true;
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_SCRIPT_MGR_H
#define __AB_SCRIPT_MGR_H
#include "Creature.h"
#include "ScriptMgr.h"
// Manages registration, loading, and execution of scripts.
class ABScriptMgr
{
public: /* Initialization */
static ABScriptMgr* instance();
// Called at the start of ModifyCreatureAttributes method.
// It can be used to add some condition to skip autobalancing system for example.
bool OnBeforeModifyAttributes(Creature* creature, uint32 & instancePlayerCount);
// Called right after default multiplier has been set, you can use it to change.
// Current scaling formula based on number of players or just skip modifications
bool OnAfterDefaultMultiplier(Creature* creature, float &defaultMultiplier);
// Called before change creature values, to tune some values or skip modifications.
bool OnBeforeUpdateStats (Creature* creature, uint32 &scaledHealth, uint32 &scaledMana, float &damageMultiplier, uint32 &newBaseArmor);
};
#define sABScriptMgr ABScriptMgr::instance()
#endif
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_MODULE_STAT_MODIFIERS_H
#define __AB_MODULE_STAT_MODIFIERS_H
#include "DataMap.h"
class AutoBalanceStatModifiers : public DataMap::Base
{
public:
AutoBalanceStatModifiers() {}
AutoBalanceStatModifiers(float global, float health, float mana, float armor, float damage, float ccduration) :
global(global), health(health), mana(mana), armor(armor), damage(damage), ccduration(ccduration) {}
float global = 1.0;
float health = 1.0;
float mana = 1.0;
float armor = 1.0;
float damage = 1.0;
float ccduration = 1.0;
};
#endif
@@ -0,0 +1,557 @@
#include "ABUnitScript.h"
#include "ABConfig.h"
#include "ABCreatureInfo.h"
#include "ABMapInfo.h"
#include "ABUtils.h"
void AutoBalance_UnitScript::ModifyPeriodicDamageAurasTick(Unit* target, Unit* source, uint32& amount, SpellInfo const* spellInfo)
{
// if the spell is negative (damage), we need to flip the sign
// if the spell is positive (healing or other) we keep it the same
int32 adjustedAmount = !spellInfo->IsPositive() ? amount * -1 : amount;
// only debug if the source or target is a player
bool _debug_damage_and_healing = ((source && (source->GetTypeId() == TYPEID_PLAYER || source->IsControlledByPlayer())) || (target && target->GetTypeId() == TYPEID_PLAYER));
_debug_damage_and_healing = (source && source->GetMap()->GetInstanceId());
if (_debug_damage_and_healing)
_Debug_Output("ModifyPeriodicDamageAurasTick", target, source, adjustedAmount, AUTOBALANCE_DAMAGE_HEALING_DEBUG_PHASE_BEFORE, spellInfo->SpellName[0], spellInfo->Id);
// set amount to the absolute value of the function call
// the provided amount doesn't indicate whether it's a positive or negative value
adjustedAmount = _Modify_Damage_Healing(target, source, adjustedAmount, spellInfo);
amount = abs(adjustedAmount);
if (_debug_damage_and_healing)
_Debug_Output("ModifyPeriodicDamageAurasTick", target, source, adjustedAmount, AUTOBALANCE_DAMAGE_HEALING_DEBUG_PHASE_AFTER, spellInfo->SpellName[0], spellInfo->Id);
}
void AutoBalance_UnitScript::ModifySpellDamageTaken(Unit* target, Unit* source, int32& amount, SpellInfo const* spellInfo)
{
// if the spell is negative (damage), we need to flip the sign to negative
// if the spell is positive (healing or other) we keep it the same (positive)
int32 adjustedAmount = !spellInfo->IsPositive() ? amount * -1 : amount;
// only debug if the source or target is a player
bool _debug_damage_and_healing = ((source && (source->GetTypeId() == TYPEID_PLAYER || source->IsControlledByPlayer())) || (target && target->GetTypeId() == TYPEID_PLAYER));
_debug_damage_and_healing = (source && source->GetMap()->GetInstanceId());
if (_debug_damage_and_healing)
_Debug_Output("ModifySpellDamageTaken", target, source, adjustedAmount, AUTOBALANCE_DAMAGE_HEALING_DEBUG_PHASE_BEFORE, spellInfo->SpellName[0], spellInfo->Id);
// set amount to the absolute value of the function call
// the provided amount doesn't indicate whether it's a positive or negative value
adjustedAmount = _Modify_Damage_Healing(target, source, adjustedAmount, spellInfo);
amount = abs(adjustedAmount);
if (_debug_damage_and_healing)
_Debug_Output("ModifySpellDamageTaken", target, source, adjustedAmount, AUTOBALANCE_DAMAGE_HEALING_DEBUG_PHASE_AFTER, spellInfo->SpellName[0], spellInfo->Id);
}
void AutoBalance_UnitScript::ModifyMeleeDamage(Unit* target, Unit* source, uint32& amount)
{
// melee damage is always negative, so we need to flip the sign to negative
int32 adjustedAmount = amount * -1;
// only debug if the source or target is a player
bool _debug_damage_and_healing = ((source && (source->GetTypeId() == TYPEID_PLAYER || source->IsControlledByPlayer())) || (target && target->GetTypeId() == TYPEID_PLAYER));
_debug_damage_and_healing = (source && source->GetMap()->GetInstanceId());
if (_debug_damage_and_healing)
_Debug_Output("ModifyMeleeDamage", target, source, adjustedAmount, AUTOBALANCE_DAMAGE_HEALING_DEBUG_PHASE_BEFORE, "Melee");
// set amount to the absolute value of the function call
adjustedAmount = _Modify_Damage_Healing(target, source, adjustedAmount);
amount = abs(adjustedAmount);
if (_debug_damage_and_healing)
_Debug_Output("ModifyMeleeDamage", target, source, adjustedAmount, AUTOBALANCE_DAMAGE_HEALING_DEBUG_PHASE_AFTER, "Melee");
}
void AutoBalance_UnitScript::ModifyHealReceived(Unit* target, Unit* source, uint32& amount, SpellInfo const* spellInfo)
{
// healing is always positive, no need for any sign flip
// only debug if the source or target is a player
bool _debug_damage_and_healing = ((source && (source->GetTypeId() == TYPEID_PLAYER || source->IsControlledByPlayer())) || (target && target->GetTypeId() == TYPEID_PLAYER));
_debug_damage_and_healing = (source && source->GetMap()->GetInstanceId());
if (_debug_damage_and_healing)
_Debug_Output("ModifyHealReceived", target, source, amount, AUTOBALANCE_DAMAGE_HEALING_DEBUG_PHASE_BEFORE, spellInfo->SpellName[0], spellInfo->Id);
amount = _Modify_Damage_Healing(target, source, amount, spellInfo);
if (_debug_damage_and_healing)
_Debug_Output("ModifyHealReceived", target, source, amount, AUTOBALANCE_DAMAGE_HEALING_DEBUG_PHASE_AFTER, spellInfo->SpellName[0], spellInfo->Id);
}
void AutoBalance_UnitScript::OnAuraApply(Unit* unit, Aura* aura)
{
// only debug if the source or target is a player
bool _debug_damage_and_healing = (unit && unit->GetTypeId() == TYPEID_PLAYER);
_debug_damage_and_healing = (unit && unit->GetMap()->GetInstanceId());
// Only if this aura has a duration
if (aura && (aura->GetDuration() > 0 || aura->GetMaxDuration() > 0))
{
uint32 auraDuration = _Modifier_CCDuration(unit, aura->GetCaster(), aura);
// only update if we decided to change it
if (auraDuration != (float)aura->GetDuration())
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::OnAuraApply(): Spell '{}' had it's duration adjusted ({}->{}).",
aura->GetSpellInfo()->SpellName[0],
aura->GetMaxDuration() / 1000,
auraDuration / 1000
);
aura->SetMaxDuration(auraDuration);
aura->SetDuration(auraDuration);
}
}
}
void AutoBalance_UnitScript::_Debug_Output(std::string function_name, Unit* target, Unit* source, int32 amount, Damage_Healing_Debug_Phase phase, std::string spell_name, uint32 spell_id)
{
if (phase == AUTOBALANCE_DAMAGE_HEALING_DEBUG_PHASE_BEFORE)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance:: ------------------------------------------------");
}
if (target && source && amount)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::{}: {}: {}{} {} {}{} with {}{} for ({})",
function_name,
phase ? "AFTER" : "BEFORE",
source->GetName(),
source->GetEntry() ? " (" + std::to_string(source->GetEntry()) + ")" : "",
amount > 0 ? "heals" : "damages",
target->GetName(),
target->GetEntry() ? " (" + std::to_string(target->GetEntry()) + ")" : "",
spell_name,
spell_id ? " (" + std::to_string(spell_id) + ")" : "",
amount
);
}
else if (target && source)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::{}: {}: {}{} damages {}{} with {}{} for (0)",
function_name,
phase ? "AFTER" : "BEFORE",
source->GetName(),
source->GetEntry() ? " (" + std::to_string(source->GetEntry()) + ")" : "",
target->GetName(),
target->GetEntry() ? " (" + std::to_string(target->GetEntry()) + ")" : "",
spell_name,
spell_id ? " (" + std::to_string(spell_id) + ")" : ""
);
}
else if (target && amount)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::{}: {}: ?? {} {}{} with {}{} for ({})",
function_name,
phase ? "AFTER" : "BEFORE",
amount > 0 ? "heals" : "damages",
target->GetName(),
target->GetEntry() ? " (" + std::to_string(target->GetEntry()) + ")" : "",
spell_name,
spell_id ? " (" + std::to_string(spell_id) + ")" : "",
amount
);
}
else if (target)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::{}: {}: ?? affects {}{} with {}{}",
function_name,
phase ? "AFTER" : "BEFORE",
target->GetName(),
target->GetEntry() ? " (" + std::to_string(target->GetEntry()) + ")" : "",
spell_name,
spell_id ? " (" + std::to_string(spell_id) + ")" : ""
);
}
else
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::{}: {}: W? T? F? with {}{}",
function_name,
phase ? "AFTER" : "BEFORE",
spell_name,
spell_id ? " (" + std::to_string(spell_id) + ")" : ""
);
}
}
int32 AutoBalance_UnitScript::_Modify_Damage_Healing(Unit* target, Unit* source, int32 amount, SpellInfo const* spellInfo)
{
//
// Pre-flight Checks
//
// only debug if the source or target is a player
bool _debug_damage_and_healing = ((source && (source->GetTypeId() == TYPEID_PLAYER || source->IsControlledByPlayer())) || (target && target->GetTypeId() == TYPEID_PLAYER));
_debug_damage_and_healing = (source && source->GetMap()->GetInstanceId());
// check that we're enabled globally, else return the original value
if (!EnableGlobal)
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: EnableGlobal is false, returning original value of ({}).", amount);
return amount;
}
// if the source is gone (logged off? despawned?), use the same target and source.
// hacky, but better than crashing or having the damage go to 1.0x
if (!source)
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Source is null, using target as source.");
source = target;
}
// make sure the source and target are in an instance, else return the original damage
if (!(source->GetMap()->IsDungeon() && target->GetMap()->IsDungeon()))
{
//if (_debug_damage_and_healing)
// LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Not in an instance, returning original value of ({}).", amount);
return amount;
}
// make sure that the source is in the world, else return the original value
if (!source->IsInWorld())
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Source does not exist in the world, returning original value of ({}).", amount);
return amount;
}
// if the spell ID is in our "never modify" list, return the original value
if
(
spellInfo &&
spellInfo->Id &&
std::find
(
spellIdsToNeverModify.begin(),
spellIdsToNeverModify.end(),
spellInfo->Id
) != spellIdsToNeverModify.end()
)
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Spell {}({}) is in the never modify list, returning original value of ({}).",
spellInfo->SpellName[0],
spellInfo->Id,
amount
);
return amount;
}
// get the maps' info
AutoBalanceMapInfo* sourceMapABInfo = GetMapInfo(source->GetMap());
AutoBalanceMapInfo* targetMapABInfo = GetMapInfo(target->GetMap());
// if either the target or the source's maps are not enabled, return the original damage
if (!sourceMapABInfo->enabled || !targetMapABInfo->enabled)
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Source or Target's map is not enabled, returning original value of ({}).", amount);
return amount;
}
//
// Source and Target Checking
//
// if the source is a player and they are healing themselves, return the original value
if (source->GetTypeId() == TYPEID_PLAYER && source->GetGUID() == target->GetGUID() && amount >= 0)
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Source is a player that is self-healing, returning original value of ({}).", amount);
return amount;
}
// if the source is a player and they are damaging themselves, log to debug but continue
else if (source->GetTypeId() == TYPEID_PLAYER && source->GetGUID() == target->GetGUID() && amount < 0)
{
// if the spell used is in our list of spells to ignore, return the original value
if
(
spellInfo &&
spellInfo->Id &&
std::find
(
spellIdsThatSpendPlayerHealth.begin(),
spellIdsThatSpendPlayerHealth.end(),
spellInfo->Id
) != spellIdsThatSpendPlayerHealth.end()
)
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Source is a player that is self-damaging with a spell that is ignored, returning original value of ({}).", amount);
return amount;
}
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Source is a player that is self-damaging, continuing.");
}
// if the source is a player and they are damaging unit that is friendly, log to debug but continue
else if (source->GetTypeId() == TYPEID_PLAYER && target->IsFriendlyTo(source) && amount < 0)
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Source is a player that is damaging a friendly unit, continuing.");
}
// if the source is a player under any other condition, return the original value
else if (source->GetTypeId() == TYPEID_PLAYER)
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Source is an enemy player, returning original value of ({}).", amount);
return amount;
}
// if the creature is attacking itself with an aura with effect type SPELL_AURA_SHARE_DAMAGE_PCT, return the orginal damage
else if
(
source->GetTypeId() == TYPEID_UNIT &&
source->GetTypeId() != TYPEID_PLAYER &&
source->GetGUID() == target->GetGUID() &&
_isAuraWithEffectType(spellInfo, SPELL_AURA_SHARE_DAMAGE_PCT)
)
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Source is a creature that is self-damaging with an aura that shares damage, returning original value of ({}).", amount);
return amount;
}
// if the source is under the control of the player, return the original damage
// noteably, this should NOT include mind control targets
if ((source->IsHunterPet() || source->IsPet() || source->IsSummon()) && source->IsControlledByPlayer())
{
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Source is a player-controlled pet or summon, returning original value of ({}).", amount);
return amount;
}
//
// Multiplier calculation
//
float damageMultiplier = 1.0f;
// if the source is a player AND the target is that same player AND the value is damage (negative), use the map's multiplier
if (source->GetTypeId() == TYPEID_PLAYER && source->GetGUID() == target->GetGUID() && amount < 0)
{
// if this aura damages based on a percent of the player's max health, use the un-level-scaled multiplier
if (_isAuraWithEffectType(spellInfo, SPELL_AURA_PERIODIC_DAMAGE_PERCENT))
{
damageMultiplier = sourceMapABInfo->worldDamageHealingMultiplier;
if (_debug_damage_and_healing)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Spell damage based on percent of max health. Ignore level scaling.");
LOG_DEBUG("module.AutoBalance_DamageHealingCC",
"AutoBalance_UnitScript::_Modify_Damage_Healing: Source is a player and the target is that same player, using the map's (level-scaling ignored) multiplier: ({})",
damageMultiplier
);
}
}
else
{
damageMultiplier = sourceMapABInfo->scaledWorldDamageHealingMultiplier;
if (_debug_damage_and_healing)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC",
"AutoBalance_UnitScript::_Modify_Damage_Healing: Source is a player and the target is that same player, using the map's multiplier: ({})",
damageMultiplier
);
}
}
}
// if the target is a player AND the value is healing (positive), use the map's damage multiplier
// (player to player healing was already eliminated in the Source and Target Checking section)
else if (target->GetTypeId() == TYPEID_PLAYER && amount >= 0)
{
damageMultiplier = targetMapABInfo->scaledWorldDamageHealingMultiplier;
if (_debug_damage_and_healing)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC",
"AutoBalance_UnitScript::_Modify_Damage_Healing: A non-player is healing a player, using the map's multiplier: ({})",
damageMultiplier
);
}
}
// if the target is a player AND the source is not a creature, use the map's multiplier
else if (target->GetTypeId() == TYPEID_PLAYER && source->GetTypeId() != TYPEID_UNIT && amount < 0)
{
// if this aura damages based on a percent of the player's max health, use the un-level-scaled multiplier
if (_isAuraWithEffectType(spellInfo, SPELL_AURA_PERIODIC_DAMAGE_PERCENT))
{
damageMultiplier = targetMapABInfo->worldDamageHealingMultiplier;
if (_debug_damage_and_healing)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Spell damage based on percent of max health. Ignore level scaling.");
LOG_DEBUG("module.AutoBalance_DamageHealingCC",
"AutoBalance_UnitScript::_Modify_Damage_Healing: Target is a player and the source is not a creature, using the map's (level-scaling-ignored) multiplier: ({})",
damageMultiplier
);
}
}
else
{
damageMultiplier = targetMapABInfo->scaledWorldDamageHealingMultiplier;
if (_debug_damage_and_healing)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC",
"AutoBalance_UnitScript::_Modify_Damage_Healing: Target is a player and the source is not a creature, using the map's multiplier: ({})",
damageMultiplier
);
}
}
}
// otherwise, use the source creature's damage multiplier
else
{
// if this aura damages based on a percent of the player's max health, use the un-level-scaled multiplier
if (_isAuraWithEffectType(spellInfo, SPELL_AURA_PERIODIC_DAMAGE_PERCENT))
{
damageMultiplier = source->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo")->DamageMultiplier;
if (_debug_damage_and_healing)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Spell damage based on percent of max health. Ignore level scaling.");
LOG_DEBUG("module.AutoBalance_DamageHealingCC",
"AutoBalance_UnitScript::_Modify_Damage_Healing: Using the source creature's (level-scaling ignored) damage multiplier: ({})",
damageMultiplier
);
}
}
// non percent-based, used the normal multiplier
else
{
damageMultiplier = source->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo")->ScaledDamageMultiplier;
if (_debug_damage_and_healing)
{
LOG_DEBUG("module.AutoBalance_DamageHealingCC",
"AutoBalance_UnitScript::_Modify_Damage_Healing: Using the source creature's damage multiplier: ({})",
damageMultiplier
);
}
}
}
// we are good to go, return the original damage times the multiplier
if (_debug_damage_and_healing)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_Modify_Damage_Healing: Returning modified {}: ({}) * ({}) = ({})",
amount <= 0 ? "damage" : "healing",
amount,
damageMultiplier,
amount * damageMultiplier
);
return amount * damageMultiplier;
}
uint32 AutoBalance_UnitScript::_Modifier_CCDuration(Unit* target, Unit* caster, Aura* aura)
{
// store the original duration of the aura
float originalDuration = (float)aura->GetDuration();
// check that we're enabled globally, else return the original duration
if (!EnableGlobal)
return originalDuration;
// ensure that both the target and the caster are defined
if (!target || !caster)
return originalDuration;
// if the aura wasn't cast just now, don't change it
if (aura->GetDuration() != aura->GetMaxDuration())
return originalDuration;
// if the target isn't a player or the caster is a player, return the original duration
if (!target->IsPlayer() || caster->IsPlayer())
return originalDuration;
// make sure we're in an instance, else return the original duration
if (!(target->GetMap()->IsDungeon() && caster->GetMap()->IsDungeon()))
return originalDuration;
// get the current creature's CC duration multiplier
float ccDurationMultiplier = caster->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo")->CCDurationMultiplier;
// if it's the default of 1.0, return the original damage
if (ccDurationMultiplier == 1)
return originalDuration;
// if the aura was cast by a pet or summon, return the original duration
if ((caster->IsHunterPet() || caster->IsPet() || caster->IsSummon()) && caster->IsControlledByPlayer())
return originalDuration;
// only if this aura is a CC
if (
aura->HasEffectType(SPELL_AURA_MOD_CHARM) ||
aura->HasEffectType(SPELL_AURA_MOD_CONFUSE) ||
aura->HasEffectType(SPELL_AURA_MOD_DISARM) ||
aura->HasEffectType(SPELL_AURA_MOD_FEAR) ||
aura->HasEffectType(SPELL_AURA_MOD_PACIFY) ||
aura->HasEffectType(SPELL_AURA_MOD_POSSESS) ||
aura->HasEffectType(SPELL_AURA_MOD_SILENCE) ||
aura->HasEffectType(SPELL_AURA_MOD_STUN) ||
aura->HasEffectType(SPELL_AURA_MOD_SPEED_SLOW_ALL)
)
{
return originalDuration * ccDurationMultiplier;
}
else
return originalDuration;
}
bool AutoBalance_UnitScript::_isAuraWithEffectType(SpellInfo const* spellInfo, AuraType auraType, bool log)
{
// if the spell is not defined, return false
if (!spellInfo)
{
if (log)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_isAuraWithEffectType: SpellInfo is null, returning false.");
return false;
}
// if the spell doesn't have any effects, return false
if (!spellInfo->GetEffects().size())
{
if (log)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_isAuraWithEffectType: SpellInfo has no effects, returning false.");
return false;
}
// iterate through the spell effects
for (SpellEffectInfo effect : spellInfo->GetEffects())
{
// if the effect is not an aura, continue to next effect
if (!effect.IsAura())
{
if (log)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_isAuraWithEffectType: SpellInfo has an effect that is not an aura, continuing to next effect.");
continue;
}
if (effect.ApplyAuraName == auraType)
{
// if the effect is an aura of the target type, return true
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_isAuraWithEffectType: SpellInfo has an aura of the target type, returning true.");
return true;
}
}
// if no aura effect of type auraType was found, return false
if (log)
LOG_DEBUG("module.AutoBalance_DamageHealingCC", "AutoBalance_UnitScript::_isAuraWithEffectType: SpellInfo has no aura of the target type, returning false.");
return false;
}
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_UNIT_SCRIPT_H
#define __AB_UNIT_SCRIPT_H
#include "AutoBalance.h"
#include "ScriptMgr.h"
#include "SpellAuras.h"
#include "SpellInfo.h"
class AutoBalance_UnitScript : public UnitScript
{
public:
AutoBalance_UnitScript()
: UnitScript("AutoBalance_UnitScript", true, {
UNITHOOK_MODIFY_PERIODIC_DAMAGE_AURAS_TICK,
UNITHOOK_MODIFY_SPELL_DAMAGE_TAKEN,
UNITHOOK_MODIFY_MELEE_DAMAGE,
UNITHOOK_MODIFY_HEAL_RECEIVED,
UNITHOOK_ON_AURA_APPLY
})
{
}
void ModifyPeriodicDamageAurasTick(Unit* target, Unit* source, uint32& amount, SpellInfo const* spellInfo) override;
void ModifySpellDamageTaken(Unit* target, Unit* source, int32& amount, SpellInfo const* spellInfo) override;
void ModifyMeleeDamage(Unit* target, Unit* source, uint32& amount) override;
void ModifyHealReceived(Unit* target, Unit* source, uint32& amount, SpellInfo const* spellInfo) override;
void OnAuraApply(Unit* unit, Aura* aura) override;
private:
[[maybe_unused]] bool _debug_damage_and_healing = false; // defaults to false, overwritten in each function
void _Debug_Output(std::string function_name, Unit* target, Unit* source, int32 amount, Damage_Healing_Debug_Phase phase, std::string spell_name = "Unknown Spell", uint32 spell_id = 0);
int32 _Modify_Damage_Healing(Unit* target, Unit* source, int32 amount, SpellInfo const* spellInfo = nullptr);
uint32 _Modifier_CCDuration(Unit* target, Unit* caster, Aura* aura);
bool _isAuraWithEffectType(SpellInfo const* spellInfo, AuraType auraType, bool log = false);
};
#endif /* __AB_UNIT_SCRIPT_H */
File diff suppressed because it is too large Load Diff
+64
View File
@@ -0,0 +1,64 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_UTILS_H
#define __AB_UTILS_H
#include "ABInflectionPointSettings.h"
#include "ABLevelScalingDynamicLevelSettings.h"
#include "ABMapInfo.h"
#include "ABStatModifiers.h"
#include "AutoBalance.h"
#include "Creature.h"
#include "Map.h"
#include "SharedDefines.h"
#include <list>
#include <map>
#include <string>
void AddCreatureToMapCreatureList(Creature* creature, bool addToCreatureList = true, bool forceRecalculation = false);
void RemoveCreatureFromMapData(Creature* creature);
uint64_t GetCurrentConfigTime();
uint32 getBaseExpansionValueForLevel(const uint32 baseValues[3], uint8 targetLevel);
float getBaseExpansionValueForLevel(const float baseValues[3], uint8 targetLevel);
float getDefaultMultiplier(Map* map, AutoBalanceInflectionPointSettings inflectionPointSettings);
int GetForcedNumPlayers(int creatureId);
World_Multipliers getWorldMultiplier(Map* map, BaseValueType baseValueType);
AutoBalanceInflectionPointSettings getInflectionPointSettings(InstanceMap* instanceMap, bool isBoss = false);
void getStatModifiersDebug(Map* map, Creature* creature, std::string message);
AutoBalanceStatModifiers getStatModifiers(Map* map, Creature* creature = nullptr);
bool hasBossOverride(uint32 dungeonId);
bool hasDungeonOverride(uint32 dungeonId);
bool hasDynamicLevelOverride(uint32 dungeonId);
bool hasLevelScalingDistanceCheckOverride(uint32 dungeonId);
bool hasStatModifierBossOverride(uint32 dungeonId);
bool hasStatModifierCreatureOverride(uint32 creatureId);
bool hasStatModifierOverride(uint32 dungeonId);
bool isBossOrBossSummon(Creature* creature, bool log = false);
bool isCreatureRelevant(Creature* creature);
bool isDungeonInDisabledDungeonIds(uint32 dungeonId);
bool isDungeonInMinPlayerMap(uint32 dungeonId, bool isHeroic);
void LoadForcedCreatureIdsFromString(std::string creatureIds, int forcedPlayerCount);
std::list<uint32> LoadDisabledDungeons(std::string dungeonIdString);
std::map <uint32, uint32> LoadDistanceCheckOverrides(std::string dungeonIdString);
std::map <uint8 , AutoBalanceLevelScalingDynamicLevelSettings> LoadDynamicLevelOverrides(std::string dungeonIdString);
std::map <uint32, AutoBalanceInflectionPointSettings> LoadInflectionPointOverrides(std::string dungeonIdString);
void LoadMapSettings(Map* map);
std::map <uint32, uint8> LoadMinPlayersPerDungeonId(std::string minPlayersString);
std::map <uint32, AutoBalanceStatModifiers> LoadStatModifierOverrides(std::string dungeonIdString);
bool ShouldMapBeEnabled (Map* map);
void UpdateMapPlayerStats (Map* map);
void AddPlayerToMap(Map* map, Player* player);
bool RemovePlayerFromMap(Map* map, Player* player);
bool UpdateMapDataIfNeeded(Map* map, bool force = false);
AutoBalanceMapInfo* GetMapInfo(Map* map);
#endif
@@ -0,0 +1,509 @@
#include "ABWorldScript.h"
#include "ABConfig.h"
#include "ABUtils.h"
#include "Configuration/Config.h"
#include "Log.h"
void AutoBalance_WorldScript::OnBeforeConfigLoad(bool /*reload*/)
{
SetInitialWorldSettings();
globalConfigTime = GetCurrentConfigTime();
LOG_INFO("module.AutoBalance", "AutoBalance::OnBeforeConfigLoad: Config loaded. Global config time set to ({}).", globalConfigTime);
}
void AutoBalance_WorldScript::SetInitialWorldSettings()
{
forcedCreatureIds.clear();
disabledDungeonIds.clear();
dungeonOverrides.clear();
bossOverrides.clear();
statModifierOverrides.clear();
statModifierBossOverrides.clear();
statModifierCreatureOverrides.clear();
levelScalingDynamicLevelOverrides.clear();
levelScalingDistanceCheckOverrides.clear();
LoadForcedCreatureIdsFromString(sConfigMgr->GetOption<std::string>("AutoBalance.ForcedID40", ""), 40);
LoadForcedCreatureIdsFromString(sConfigMgr->GetOption<std::string>("AutoBalance.ForcedID25", ""), 25);
LoadForcedCreatureIdsFromString(sConfigMgr->GetOption<std::string>("AutoBalance.ForcedID10", ""), 10);
LoadForcedCreatureIdsFromString(sConfigMgr->GetOption<std::string>("AutoBalance.ForcedID5" , ""), 5);
LoadForcedCreatureIdsFromString(sConfigMgr->GetOption<std::string>("AutoBalance.ForcedID2" , ""), 2);
LoadForcedCreatureIdsFromString(sConfigMgr->GetOption<std::string>("AutoBalance.DisabledID", ""), 0);
//
// Disabled Dungeon IDs
//
disabledDungeonIds = LoadDisabledDungeons(sConfigMgr->GetOption<std::string>("AutoBalance.Disable.PerInstance", ""));
//
// Min Players
//
minPlayersNormal = sConfigMgr->GetOption<int>("AutoBalance.MinPlayers", 1);
minPlayersHeroic = sConfigMgr->GetOption<int>("AutoBalance.MinPlayers.Heroic", 1);
minPlayersRaid = sConfigMgr->GetOption<int>("AutoBalance.MinPlayers.Raid", minPlayersNormal);
minPlayersRaidHeroic = sConfigMgr->GetOption<int>("AutoBalance.MinPlayers.RaidHeroic", minPlayersHeroic);
if (sConfigMgr->GetOption<float>("AutoBalance.PerDungeonPlayerCounts", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.PerDungeonPlayerCounts` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
minPlayersPerDungeonIdMap = LoadMinPlayersPerDungeonId(
sConfigMgr->GetOption<std::string>("AutoBalance.MinPlayers.PerInstance",
sConfigMgr->GetOption<std::string>("AutoBalance.PerDungeonPlayerCounts", "", false), false)); // `AutoBalance.PerDungeonPlayerCounts` for backwards compatibility
minPlayersPerHeroicDungeonIdMap = LoadMinPlayersPerDungeonId(
sConfigMgr->GetOption<std::string>("AutoBalance.MinPlayers.Heroic.PerInstance",
sConfigMgr->GetOption<std::string>("AutoBalance.PerDungeonPlayerCounts", "", false), false)); // `AutoBalance.PerDungeonPlayerCounts` for backwards compatibility
//
// Overrides
//
if (sConfigMgr->GetOption<float>("AutoBalance.PerDungeonScaling", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.PerDungeonScaling` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
dungeonOverrides = LoadInflectionPointOverrides(
sConfigMgr->GetOption<std::string>("AutoBalance.InflectionPoint.PerInstance",
sConfigMgr->GetOption<std::string>("AutoBalance.PerDungeonScaling", "", false), false)); // `AutoBalance.PerDungeonScaling` for backwards compatibility
if (sConfigMgr->GetOption<float>("AutoBalance.PerDungeonBossScaling", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.PerDungeonBossScaling` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
bossOverrides = LoadInflectionPointOverrides(
sConfigMgr->GetOption<std::string>("AutoBalance.InflectionPoint.Boss.PerInstance",
sConfigMgr->GetOption<std::string>("AutoBalance.PerDungeonBossScaling", "", false), false)); // `AutoBalance.PerDungeonBossScaling` for backwards compatibility
statModifierOverrides = LoadStatModifierOverrides(
sConfigMgr->GetOption<std::string>("AutoBalance.StatModifier.PerInstance", "", false));
statModifierBossOverrides = LoadStatModifierOverrides(
sConfigMgr->GetOption<std::string>("AutoBalance.StatModifier.Boss.PerInstance", "", false));
statModifierCreatureOverrides = LoadStatModifierOverrides(
sConfigMgr->GetOption<std::string>("AutoBalance.StatModifier.PerCreature", "", false));
levelScalingDynamicLevelOverrides = LoadDynamicLevelOverrides(
sConfigMgr->GetOption<std::string>("AutoBalance.LevelScaling.DynamicLevel.PerInstance", "", false));
levelScalingDistanceCheckOverrides = LoadDistanceCheckOverrides(
sConfigMgr->GetOption<std::string>("AutoBalance.LevelScaling.DynamicLevel.DistanceCheck.PerInstance", "", false));
//
// AutoBalance.Enable.*
// Deprecated setting warning
//
if (sConfigMgr->GetOption<int>("AutoBalance.enable", -1, false) != -1)
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.enable` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
EnableGlobal = sConfigMgr->GetOption<bool>("AutoBalance.Enable.Global" , sConfigMgr->GetOption<bool>("AutoBalance.enable", 1, false)); // `AutoBalance.enable` for backwards compatibility
Enable5M = sConfigMgr->GetOption<bool>("AutoBalance.Enable.5M" , sConfigMgr->GetOption<bool>("AutoBalance.enable", 1, false));
Enable10M = sConfigMgr->GetOption<bool>("AutoBalance.Enable.10M" , sConfigMgr->GetOption<bool>("AutoBalance.enable", 1, false));
Enable15M = sConfigMgr->GetOption<bool>("AutoBalance.Enable.15M" , sConfigMgr->GetOption<bool>("AutoBalance.enable", 1, false));
Enable20M = sConfigMgr->GetOption<bool>("AutoBalance.Enable.20M" , sConfigMgr->GetOption<bool>("AutoBalance.enable", 1, false));
Enable25M = sConfigMgr->GetOption<bool>("AutoBalance.Enable.25M" , sConfigMgr->GetOption<bool>("AutoBalance.enable", 1, false));
Enable40M = sConfigMgr->GetOption<bool>("AutoBalance.Enable.40M" , sConfigMgr->GetOption<bool>("AutoBalance.enable", 1, false));
EnableOtherNormal = sConfigMgr->GetOption<bool>("AutoBalance.Enable.OtherNormal", sConfigMgr->GetOption<bool>("AutoBalance.enable", 1, false));
Enable5MHeroic = sConfigMgr->GetOption<bool>("AutoBalance.Enable.5MHeroic" , sConfigMgr->GetOption<bool>("AutoBalance.enable", 1, false));
Enable10MHeroic = sConfigMgr->GetOption<bool>("AutoBalance.Enable.10MHeroic" , sConfigMgr->GetOption<bool>("AutoBalance.enable", 1, false));
Enable25MHeroic = sConfigMgr->GetOption<bool>("AutoBalance.Enable.25MHeroic" , sConfigMgr->GetOption<bool>("AutoBalance.enable", 1, false));
EnableOtherHeroic = sConfigMgr->GetOption<bool>("AutoBalance.Enable.OtherHeroic", sConfigMgr->GetOption<bool>("AutoBalance.enable", 1, false));
//
// Deprecated setting warning
//
if (sConfigMgr->GetOption<int>("AutoBalance.DungeonsOnly", -1, false) != -1)
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.DungeonsOnly` defined in `AutoBalance.conf`. This variable has been removed and has no effect. Please see `AutoBalance.conf.dist` for more details.");
if (sConfigMgr->GetOption<int>("AutoBalance.levelUseDbValuesWhenExists", -1, false) != -1)
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.levelUseDbValuesWhenExists` defined in `AutoBalance.conf`. This variable has been removed and has no effect. Please see `AutoBalance.conf.dist` for more details.");
//
// Misc Settings
// TODO: Organize and standardize variable names
//
PlayerChangeNotify = sConfigMgr->GetOption<bool> ("AutoBalance.PlayerChangeNotify", 1);
rewardEnabled = sConfigMgr->GetOption<bool> ("AutoBalance.reward.enable", 1);
PlayerCountDifficultyOffset = sConfigMgr->GetOption<uint32>("AutoBalance.playerCountDifficultyOffset", 0);
rewardRaid = sConfigMgr->GetOption<uint32>("AutoBalance.reward.raidToken", 49426);
rewardDungeon = sConfigMgr->GetOption<uint32>("AutoBalance.reward.dungeonToken", 47241);
MinPlayerReward = sConfigMgr->GetOption<float> ("AutoBalance.reward.MinPlayerReward", 1);
//
// InflectionPoint*
// warn the console if deprecated values are detected
//
if (sConfigMgr->GetOption<float>("AutoBalance.BossInflectionMult", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.BossInflectionMult` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
InflectionPoint = sConfigMgr->GetOption<float>("AutoBalance.InflectionPoint", 0.5f, false);
InflectionPointCurveFloor = sConfigMgr->GetOption<float>("AutoBalance.InflectionPoint.CurveFloor", 0.0f, false);
InflectionPointCurveCeiling = sConfigMgr->GetOption<float>("AutoBalance.InflectionPoint.CurveCeiling", 1.0f, false);
InflectionPointBoss = sConfigMgr->GetOption<float>("AutoBalance.InflectionPoint.BossModifier", sConfigMgr->GetOption<float>("AutoBalance.BossInflectionMult", 1.0f, false), false); // `AutoBalance.BossInflectionMult` for backwards compatibility
InflectionPointHeroic = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointHeroic", 0.5f, false);
InflectionPointHeroicCurveFloor = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointHeroic.CurveFloor", 0.0f, false);
InflectionPointHeroicCurveCeiling = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointHeroic.CurveCeiling", 1.0f, false);
InflectionPointHeroicBoss = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointHeroic.BossModifier", sConfigMgr->GetOption<float>("AutoBalance.BossInflectionMult", 1.0f, false), false); // `AutoBalance.BossInflectionMult` for backwards compatibility
InflectionPointRaid = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid", 0.5f, false);
InflectionPointRaidCurveFloor = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid.CurveFloor", 0.0f, false);
InflectionPointRaidCurveCeiling = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid.CurveCeiling", 1.0f, false);
InflectionPointRaidBoss = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid.BossModifier", sConfigMgr->GetOption<float>("AutoBalance.BossInflectionMult", 1.0f, false), false); // `AutoBalance.BossInflectionMult` for backwards compatibility
InflectionPointRaidHeroic = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaidHeroic", 0.5f, false);
InflectionPointRaidHeroicCurveFloor = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaidHeroic.CurveFloor", 0.0f, false);
InflectionPointRaidHeroicCurveCeiling = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaidHeroic.CurveCeiling", 1.0f, false);
InflectionPointRaidHeroicBoss = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaidHeroic.BossModifier", sConfigMgr->GetOption<float>("AutoBalance.BossInflectionMult", 1.0f, false), false); // `AutoBalance.BossInflectionMult` for backwards compatibility
InflectionPointRaid10M = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid10M", InflectionPointRaid, false);
InflectionPointRaid10MCurveFloor = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid10M.CurveFloor", InflectionPointRaidCurveFloor, false);
InflectionPointRaid10MCurveCeiling = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid10M.CurveCeiling", InflectionPointRaidCurveCeiling, false);
InflectionPointRaid10MBoss = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid10M.BossModifier", InflectionPointRaidBoss, false);
InflectionPointRaid10MHeroic = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid10MHeroic", InflectionPointRaidHeroic, false);
InflectionPointRaid10MHeroicCurveFloor = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid10MHeroic.CurveFloor", InflectionPointRaidHeroicCurveFloor, false);
InflectionPointRaid10MHeroicCurveCeiling = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid10MHeroic.CurveCeiling", InflectionPointRaidHeroicCurveCeiling, false);
InflectionPointRaid10MHeroicBoss = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid10MHeroic.BossModifier", InflectionPointRaidHeroicBoss, false);
InflectionPointRaid15M = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid15M", InflectionPointRaid, false);
InflectionPointRaid15MCurveFloor = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid15M.CurveFloor", InflectionPointRaidCurveFloor, false);
InflectionPointRaid15MCurveCeiling = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid15M.CurveCeiling", InflectionPointRaidCurveCeiling, false);
InflectionPointRaid15MBoss = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid15M.BossModifier", InflectionPointRaidBoss, false);
InflectionPointRaid20M = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid20M", InflectionPointRaid, false);
InflectionPointRaid20MCurveFloor = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid20M.CurveFloor", InflectionPointRaidCurveFloor, false);
InflectionPointRaid20MCurveCeiling = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid20M.CurveCeiling", InflectionPointRaidCurveCeiling, false);
InflectionPointRaid20MBoss = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid20M.BossModifier", InflectionPointRaidBoss, false);
InflectionPointRaid25M = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid25M", InflectionPointRaid, false);
InflectionPointRaid25MCurveFloor = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid25M.CurveFloor", InflectionPointRaidCurveFloor, false);
InflectionPointRaid25MCurveCeiling = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid25M.CurveCeiling", InflectionPointRaidCurveCeiling, false);
InflectionPointRaid25MBoss = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid25M.BossModifier", InflectionPointRaidBoss, false);
InflectionPointRaid25MHeroic = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid25MHeroic", InflectionPointRaidHeroic, false);
InflectionPointRaid25MHeroicCurveFloor = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid25MHeroic.CurveFloor", InflectionPointRaidHeroicCurveFloor, false);
InflectionPointRaid25MHeroicCurveCeiling = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid25MHeroic.CurveCeiling", InflectionPointRaidHeroicCurveCeiling, false);
InflectionPointRaid25MHeroicBoss = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid25MHeroic.BossModifier", InflectionPointRaidHeroicBoss, false);
InflectionPointRaid40M = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid40M", InflectionPointRaid, false);
InflectionPointRaid40MCurveFloor = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid40M.CurveFloor", InflectionPointRaidCurveFloor, false);
InflectionPointRaid40MCurveCeiling = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid40M.CurveCeiling", InflectionPointRaidCurveCeiling, false);
InflectionPointRaid40MBoss = sConfigMgr->GetOption<float>("AutoBalance.InflectionPointRaid40M.BossModifier", InflectionPointRaidBoss, false);
//
// StatModifier*
// warn the console if deprecated values are detected
//
if (sConfigMgr->GetOption<float>("AutoBalance.rate.global", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.rate.global` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
if (sConfigMgr->GetOption<float>("AutoBalance.rate.health", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.rate.health` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
if (sConfigMgr->GetOption<float>("AutoBalance.rate.mana", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.rate.mana` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
if (sConfigMgr->GetOption<float>("AutoBalance.rate.armor", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.rate.armor` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
if (sConfigMgr->GetOption<float>("AutoBalance.rate.damage", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.rate.damage` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
//
// 5-player dungeons
//
StatModifier_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifier.Global", sConfigMgr->GetOption<float>("AutoBalance.rate.global", 1.0f, false), false); // `AutoBalance.rate.global` for backwards compatibility
StatModifier_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifier.Health", sConfigMgr->GetOption<float>("AutoBalance.rate.health", 1.0f, false), false); // `AutoBalance.rate.health` for backwards compatibility
StatModifier_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifier.Mana", sConfigMgr->GetOption<float>("AutoBalance.rate.mana", 1.0f, false), false); // `AutoBalance.rate.mana` for backwards compatibility
StatModifier_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifier.Armor", sConfigMgr->GetOption<float>("AutoBalance.rate.armor", 1.0f, false), false); // `AutoBalance.rate.armor` for backwards compatibility
StatModifier_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifier.Damage", sConfigMgr->GetOption<float>("AutoBalance.rate.damage", 1.0f, false), false); // `AutoBalance.rate.damage` for backwards compatibility
StatModifier_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifier.CCDuration", -1.0f, false);
StatModifier_Boss_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifier.Boss.Global", sConfigMgr->GetOption<float>("AutoBalance.rate.global", 1.0f, false), false); // `AutoBalance.rate.global` for backwards compatibility
StatModifier_Boss_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifier.Boss.Health", sConfigMgr->GetOption<float>("AutoBalance.rate.health", 1.0f, false), false); // `AutoBalance.rate.health` for backwards compatibility
StatModifier_Boss_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifier.Boss.Mana", sConfigMgr->GetOption<float>("AutoBalance.rate.mana", 1.0f, false), false); // `AutoBalance.rate.mana` for backwards compatibility
StatModifier_Boss_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifier.Boss.Armor", sConfigMgr->GetOption<float>("AutoBalance.rate.armor", 1.0f, false), false); // `AutoBalance.rate.armor` for backwards compatibility
StatModifier_Boss_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifier.Boss.Damage", sConfigMgr->GetOption<float>("AutoBalance.rate.damage", 1.0f, false), false); // `AutoBalance.rate.damage` for backwards compatibility
StatModifier_Boss_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifier.Boss.CCDuration", -1.0f, false);
//
// 5-player heroic dungeons
//
StatModifierHeroic_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierHeroic.Global", sConfigMgr->GetOption<float>("AutoBalance.rate.global", 1.0f, false), false); // `AutoBalance.rate.global` for backwards compatibility
StatModifierHeroic_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierHeroic.Health", sConfigMgr->GetOption<float>("AutoBalance.rate.health", 1.0f, false), false); // `AutoBalance.rate.health` for backwards compatibility
StatModifierHeroic_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierHeroic.Mana", sConfigMgr->GetOption<float>("AutoBalance.rate.mana", 1.0f, false), false); // `AutoBalance.rate.mana` for backwards compatibility
StatModifierHeroic_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierHeroic.Armor", sConfigMgr->GetOption<float>("AutoBalance.rate.armor", 1.0f, false), false); // `AutoBalance.rate.armor` for backwards compatibility
StatModifierHeroic_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierHeroic.Damage", sConfigMgr->GetOption<float>("AutoBalance.rate.damage", 1.0f, false), false); // `AutoBalance.rate.damage` for backwards compatibility
StatModifierHeroic_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierHeroic.CCDuration", -1.0f, false);
StatModifierHeroic_Boss_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierHeroic.Boss.Global", sConfigMgr->GetOption<float>("AutoBalance.rate.global", 1.0f, false), false); // `AutoBalance.rate.global` for backwards compatibility
StatModifierHeroic_Boss_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierHeroic.Boss.Health", sConfigMgr->GetOption<float>("AutoBalance.rate.health", 1.0f, false), false); // `AutoBalance.rate.health` for backwards compatibility
StatModifierHeroic_Boss_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierHeroic.Boss.Mana", sConfigMgr->GetOption<float>("AutoBalance.rate.mana", 1.0f, false), false); // `AutoBalance.rate.mana` for backwards compatibility
StatModifierHeroic_Boss_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierHeroic.Boss.Armor", sConfigMgr->GetOption<float>("AutoBalance.rate.armor", 1.0f, false), false); // `AutoBalance.rate.armor` for backwards compatibility
StatModifierHeroic_Boss_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierHeroic.Boss.Damage", sConfigMgr->GetOption<float>("AutoBalance.rate.damage", 1.0f, false), false); // `AutoBalance.rate.damage` for backwards compatibility
StatModifierHeroic_Boss_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierHeroic.Boss.CCDuration", -1.0f, false);
//
// Default for all raids
//
StatModifierRaid_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid.Global", sConfigMgr->GetOption<float>("AutoBalance.rate.global", 1.0f, false), false); // `AutoBalance.rate.global` for backwards compatibility
StatModifierRaid_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid.Health", sConfigMgr->GetOption<float>("AutoBalance.rate.health", 1.0f, false), false); // `AutoBalance.rate.health` for backwards compatibility
StatModifierRaid_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid.Mana", sConfigMgr->GetOption<float>("AutoBalance.rate.mana", 1.0f, false), false); // `AutoBalance.rate.mana` for backwards compatibility
StatModifierRaid_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid.Armor", sConfigMgr->GetOption<float>("AutoBalance.rate.armor", 1.0f, false), false); // `AutoBalance.rate.armor` for backwards compatibility
StatModifierRaid_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid.Damage", sConfigMgr->GetOption<float>("AutoBalance.rate.damage", 1.0f, false), false); // `AutoBalance.rate.damage` for backwards compatibility
StatModifierRaid_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid.CCDuration", -1.0f, false);
StatModifierRaid_Boss_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid.Boss.Global", sConfigMgr->GetOption<float>("AutoBalance.rate.global", 1.0f, false), false); // `AutoBalance.rate.global` for backwards compatibility
StatModifierRaid_Boss_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid.Boss.Health", sConfigMgr->GetOption<float>("AutoBalance.rate.health", 1.0f, false), false); // `AutoBalance.rate.health` for backwards compatibility
StatModifierRaid_Boss_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid.Boss.Mana", sConfigMgr->GetOption<float>("AutoBalance.rate.mana", 1.0f, false), false); // `AutoBalance.rate.mana` for backwards compatibility
StatModifierRaid_Boss_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid.Boss.Armor", sConfigMgr->GetOption<float>("AutoBalance.rate.armor", 1.0f, false), false); // `AutoBalance.rate.armor` for backwards compatibility
StatModifierRaid_Boss_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid.Boss.Damage", sConfigMgr->GetOption<float>("AutoBalance.rate.damage", 1.0f, false), false); // `AutoBalance.rate.damage` for backwards compatibility
StatModifierRaid_Boss_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid.Boss.CCDuration", -1.0f, false);
//
// Default for all heroic raids
//
StatModifierRaidHeroic_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaidHeroic.Global", sConfigMgr->GetOption<float>("AutoBalance.rate.global", 1.0f, false), false); // `AutoBalance.rate.global` for backwards compatibility
StatModifierRaidHeroic_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaidHeroic.Health", sConfigMgr->GetOption<float>("AutoBalance.rate.health", 1.0f, false), false); // `AutoBalance.rate.health` for backwards compatibility
StatModifierRaidHeroic_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaidHeroic.Mana", sConfigMgr->GetOption<float>("AutoBalance.rate.mana", 1.0f, false), false); // `AutoBalance.rate.mana` for backwards compatibility
StatModifierRaidHeroic_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaidHeroic.Armor", sConfigMgr->GetOption<float>("AutoBalance.rate.armor", 1.0f, false), false); // `AutoBalance.rate.armor` for backwards compatibility
StatModifierRaidHeroic_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaidHeroic.Damage", sConfigMgr->GetOption<float>("AutoBalance.rate.damage", 1.0f, false), false); // `AutoBalance.rate.damage` for backwards compatibility
StatModifierRaidHeroic_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaidHeroic.CCDuration", -1.0f, false);
StatModifierRaidHeroic_Boss_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaidHeroic.Boss.Global", sConfigMgr->GetOption<float>("AutoBalance.rate.global", 1.0f, false), false); // `AutoBalance.rate.global` for backwards compatibility
StatModifierRaidHeroic_Boss_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaidHeroic.Boss.Health", sConfigMgr->GetOption<float>("AutoBalance.rate.health", 1.0f, false), false); // `AutoBalance.rate.health` for backwards compatibility
StatModifierRaidHeroic_Boss_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaidHeroic.Boss.Mana", sConfigMgr->GetOption<float>("AutoBalance.rate.mana", 1.0f, false), false); // `AutoBalance.rate.mana` for backwards compatibility
StatModifierRaidHeroic_Boss_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaidHeroic.Boss.Armor", sConfigMgr->GetOption<float>("AutoBalance.rate.armor", 1.0f, false), false); // `AutoBalance.rate.armor` for backwards compatibility
StatModifierRaidHeroic_Boss_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaidHeroic.Boss.Damage", sConfigMgr->GetOption<float>("AutoBalance.rate.damage", 1.0f, false), false); // `AutoBalance.rate.damage` for backwards compatibility
StatModifierRaidHeroic_Boss_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaidHeroic.Boss.CCDuration", -1.0f, false);
//
// 10-player raids
//
StatModifierRaid10M_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10M.Global", StatModifierRaid_Global, false);
StatModifierRaid10M_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10M.Health", StatModifierRaid_Health, false);
StatModifierRaid10M_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10M.Mana", StatModifierRaid_Mana, false);
StatModifierRaid10M_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10M.Armor", StatModifierRaid_Armor, false);
StatModifierRaid10M_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10M.Damage", StatModifierRaid_Damage, false);
StatModifierRaid10M_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10M.CCDuration", StatModifierRaid_CCDuration, false);
StatModifierRaid10M_Boss_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10M.Boss.Global", StatModifierRaid_Boss_Global, false);
StatModifierRaid10M_Boss_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10M.Boss.Health", StatModifierRaid_Boss_Health, false);
StatModifierRaid10M_Boss_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10M.Boss.Mana", StatModifierRaid_Boss_Mana, false);
StatModifierRaid10M_Boss_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10M.Boss.Armor", StatModifierRaid_Boss_Armor, false);
StatModifierRaid10M_Boss_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10M.Boss.Damage", StatModifierRaid_Boss_Damage, false);
StatModifierRaid10M_Boss_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10M.Boss.CCDuration", StatModifierRaid_Boss_CCDuration, false);
//
// 10-player heroic raids
//
StatModifierRaid10MHeroic_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10MHeroic.Global", StatModifierRaidHeroic_Global, false);
StatModifierRaid10MHeroic_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10MHeroic.Health", StatModifierRaidHeroic_Health, false);
StatModifierRaid10MHeroic_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10MHeroic.Mana", StatModifierRaidHeroic_Mana, false);
StatModifierRaid10MHeroic_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10MHeroic.Armor", StatModifierRaidHeroic_Armor, false);
StatModifierRaid10MHeroic_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10MHeroic.Damage", StatModifierRaidHeroic_Damage, false);
StatModifierRaid10MHeroic_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10MHeroic.CCDuration", StatModifierRaidHeroic_CCDuration, false);
StatModifierRaid10MHeroic_Boss_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10MHeroic.Boss.Global", StatModifierRaidHeroic_Boss_Global, false);
StatModifierRaid10MHeroic_Boss_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10MHeroic.Boss.Health", StatModifierRaidHeroic_Boss_Health, false);
StatModifierRaid10MHeroic_Boss_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10MHeroic.Boss.Mana", StatModifierRaidHeroic_Boss_Mana, false);
StatModifierRaid10MHeroic_Boss_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10MHeroic.Boss.Armor", StatModifierRaidHeroic_Boss_Armor, false);
StatModifierRaid10MHeroic_Boss_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10MHeroic.Boss.Damage", StatModifierRaidHeroic_Boss_Damage, false);
StatModifierRaid10MHeroic_Boss_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid10MHeroic.Boss.CCDuration", StatModifierRaidHeroic_Boss_CCDuration, false);
//
// 15-player raids
//
StatModifierRaid15M_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid15M.Global", StatModifierRaid_Global, false);
StatModifierRaid15M_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid15M.Health", StatModifierRaid_Health, false);
StatModifierRaid15M_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid15M.Mana", StatModifierRaid_Mana, false);
StatModifierRaid15M_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid15M.Armor", StatModifierRaid_Armor, false);
StatModifierRaid15M_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid15M.Damage", StatModifierRaid_Damage, false);
StatModifierRaid15M_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid15M.CCDuration", StatModifierRaid_CCDuration, false);
StatModifierRaid15M_Boss_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid15M.Boss.Global", StatModifierRaid_Boss_Global, false);
StatModifierRaid15M_Boss_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid15M.Boss.Health", StatModifierRaid_Boss_Health, false);
StatModifierRaid15M_Boss_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid15M.Boss.Mana", StatModifierRaid_Boss_Mana, false);
StatModifierRaid15M_Boss_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid15M.Boss.Armor", StatModifierRaid_Boss_Armor, false);
StatModifierRaid15M_Boss_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid15M.Boss.Damage", StatModifierRaid_Boss_Damage, false);
StatModifierRaid15M_Boss_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid15M.Boss.CCDuration", StatModifierRaid_Boss_CCDuration, false);
//
// 20-player raids
//
StatModifierRaid20M_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid20M.Global", StatModifierRaid_Global, false);
StatModifierRaid20M_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid20M.Health", StatModifierRaid_Health, false);
StatModifierRaid20M_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid20M.Mana", StatModifierRaid_Mana, false);
StatModifierRaid20M_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid20M.Armor", StatModifierRaid_Armor, false);
StatModifierRaid20M_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid20M.Damage", StatModifierRaid_Damage, false);
StatModifierRaid20M_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid20M.CCDuration", StatModifierRaid_CCDuration, false);
StatModifierRaid20M_Boss_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid20M.Boss.Global", StatModifierRaid_Boss_Global, false);
StatModifierRaid20M_Boss_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid20M.Boss.Health", StatModifierRaid_Boss_Health, false);
StatModifierRaid20M_Boss_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid20M.Boss.Mana", StatModifierRaid_Boss_Mana, false);
StatModifierRaid20M_Boss_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid20M.Boss.Armor", StatModifierRaid_Boss_Armor, false);
StatModifierRaid20M_Boss_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid20M.Boss.Damage", StatModifierRaid_Boss_Damage, false);
StatModifierRaid20M_Boss_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid20M.Boss.CCDuration", StatModifierRaid_Boss_CCDuration, false);
//
// 25-player raids
//
StatModifierRaid25M_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25M.Global", StatModifierRaid_Global, false);
StatModifierRaid25M_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25M.Health", StatModifierRaid_Health, false);
StatModifierRaid25M_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25M.Mana", StatModifierRaid_Mana, false);
StatModifierRaid25M_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25M.Armor", StatModifierRaid_Armor, false);
StatModifierRaid25M_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25M.Damage", StatModifierRaid_Damage, false);
StatModifierRaid25M_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25M.CCDuration", StatModifierRaid_CCDuration, false);
StatModifierRaid25M_Boss_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25M.Boss.Global", StatModifierRaid_Boss_Global, false);
StatModifierRaid25M_Boss_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25M.Boss.Health", StatModifierRaid_Boss_Health, false);
StatModifierRaid25M_Boss_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25M.Boss.Mana", StatModifierRaid_Boss_Mana, false);
StatModifierRaid25M_Boss_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25M.Boss.Armor", StatModifierRaid_Boss_Armor, false);
StatModifierRaid25M_Boss_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25M.Boss.Damage", StatModifierRaid_Boss_Damage, false);
StatModifierRaid25M_Boss_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25M.Boss.CCDuration", StatModifierRaid_Boss_CCDuration, false);
//
// 25-player heroic raids
//
StatModifierRaid25MHeroic_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25MHeroic.Global", StatModifierRaidHeroic_Global, false);
StatModifierRaid25MHeroic_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25MHeroic.Health", StatModifierRaidHeroic_Health, false);
StatModifierRaid25MHeroic_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25MHeroic.Mana", StatModifierRaidHeroic_Mana, false);
StatModifierRaid25MHeroic_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25MHeroic.Armor", StatModifierRaidHeroic_Armor, false);
StatModifierRaid25MHeroic_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25MHeroic.Damage", StatModifierRaidHeroic_Damage, false);
StatModifierRaid25MHeroic_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25MHeroic.CCDuration", StatModifierRaidHeroic_CCDuration, false);
StatModifierRaid25MHeroic_Boss_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25MHeroic.Boss.Global", StatModifierRaidHeroic_Boss_Global, false);
StatModifierRaid25MHeroic_Boss_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25MHeroic.Boss.Health", StatModifierRaidHeroic_Boss_Health, false);
StatModifierRaid25MHeroic_Boss_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25MHeroic.Boss.Mana", StatModifierRaidHeroic_Boss_Mana, false);
StatModifierRaid25MHeroic_Boss_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25MHeroic.Boss.Armor", StatModifierRaidHeroic_Boss_Armor, false);
StatModifierRaid25MHeroic_Boss_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25MHeroic.Boss.Damage", StatModifierRaidHeroic_Boss_Damage, false);
StatModifierRaid25MHeroic_Boss_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid25MHeroic.Boss.CCDuration", StatModifierRaidHeroic_Boss_CCDuration, false);
//
// 40-player raids
//
StatModifierRaid40M_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid40M.Global", StatModifierRaid_Global, false);
StatModifierRaid40M_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid40M.Health", StatModifierRaid_Health, false);
StatModifierRaid40M_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid40M.Mana", StatModifierRaid_Mana, false);
StatModifierRaid40M_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid40M.Armor", StatModifierRaid_Armor, false);
StatModifierRaid40M_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid40M.Damage", StatModifierRaid_Damage, false);
StatModifierRaid40M_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid40M.CCDuration", StatModifierRaid_CCDuration, false);
StatModifierRaid40M_Boss_Global = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid40M.Boss.Global", StatModifierRaid_Boss_Global, false);
StatModifierRaid40M_Boss_Health = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid40M.Boss.Health", StatModifierRaid_Boss_Health, false);
StatModifierRaid40M_Boss_Mana = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid40M.Boss.Mana", StatModifierRaid_Boss_Mana, false);
StatModifierRaid40M_Boss_Armor = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid40M.Boss.Armor", StatModifierRaid_Boss_Armor, false);
StatModifierRaid40M_Boss_Damage = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid40M.Boss.Damage", StatModifierRaid_Boss_Damage, false);
StatModifierRaid40M_Boss_CCDuration = sConfigMgr->GetOption<float>("AutoBalance.StatModifierRaid40M.Boss.CCDuration", StatModifierRaid_Boss_CCDuration, false);
//
// Modifier Min/Max
//
MinHPModifier = sConfigMgr->GetOption<float>("AutoBalance.MinHPModifier", 0.1f);
MinManaModifier = sConfigMgr->GetOption<float>("AutoBalance.MinManaModifier", 0.01f);
MinDamageModifier = sConfigMgr->GetOption<float>("AutoBalance.MinDamageModifier", 0.01f);
MinCCDurationModifier = sConfigMgr->GetOption<float>("AutoBalance.MinCCDurationModifier", 0.25f);
MaxCCDurationModifier = sConfigMgr->GetOption<float>("AutoBalance.MaxCCDurationModifier", 1.0f);
//
// LevelScaling.*
//
LevelScaling = sConfigMgr->GetOption<bool>("AutoBalance.LevelScaling", true);
std::string LevelScalingMethodString = sConfigMgr->GetOption<std::string>("AutoBalance.LevelScaling.Method", "dynamic", false);
if (LevelScalingMethodString == "fixed")
LevelScalingMethod = AUTOBALANCE_SCALING_FIXED;
else if (LevelScalingMethodString == "dynamic")
LevelScalingMethod = AUTOBALANCE_SCALING_DYNAMIC;
else
{
LOG_ERROR("server.loading", "mod-autobalance: invalid value `{}` for `AutoBalance.LevelScaling.Method` defined in `AutoBalance.conf`. Defaulting to a value of `dynamic`.", LevelScalingMethodString);
LevelScalingMethod = AUTOBALANCE_SCALING_DYNAMIC;
}
if (sConfigMgr->GetOption<float>("AutoBalance.LevelHigherOffset", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.LevelHigherOffset` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
LevelScalingSkipHigherLevels = sConfigMgr->GetOption<uint8>("AutoBalance.LevelScaling.SkipHigherLevels", sConfigMgr->GetOption<uint32>("AutoBalance.LevelHigherOffset", 3, false), true);
if (sConfigMgr->GetOption<float>("AutoBalance.LevelLowerOffset", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.LevelLowerOffset` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
LevelScalingSkipLowerLevels = sConfigMgr->GetOption<uint8>("AutoBalance.LevelScaling.SkipLowerLevels", sConfigMgr->GetOption<uint32>("AutoBalance.LevelLowerOffset", 5, false), true);
LevelScalingDynamicLevelCeilingDungeons = sConfigMgr->GetOption<uint8>("AutoBalance.LevelScaling.DynamicLevel.Ceiling.Dungeons", 1);
LevelScalingDynamicLevelFloorDungeons = sConfigMgr->GetOption<uint8>("AutoBalance.LevelScaling.DynamicLevel.Floor.Dungeons", 5);
LevelScalingDynamicLevelCeilingHeroicDungeons = sConfigMgr->GetOption<uint8>("AutoBalance.LevelScaling.DynamicLevel.Ceiling.HeroicDungeons", 2);
LevelScalingDynamicLevelFloorHeroicDungeons = sConfigMgr->GetOption<uint8>("AutoBalance.LevelScaling.DynamicLevel.Floor.HeroicDungeons", 5);
LevelScalingDynamicLevelCeilingRaids = sConfigMgr->GetOption<uint8>("AutoBalance.LevelScaling.DynamicLevel.Ceiling.Raids", 3);
LevelScalingDynamicLevelFloorRaids = sConfigMgr->GetOption<uint8>("AutoBalance.LevelScaling.DynamicLevel.Floor.Raids", 5);
LevelScalingDynamicLevelCeilingHeroicRaids = sConfigMgr->GetOption<uint8>("AutoBalance.LevelScaling.DynamicLevel.Ceiling.HeroicRaids", 3);
LevelScalingDynamicLevelFloorHeroicRaids = sConfigMgr->GetOption<uint8>("AutoBalance.LevelScaling.DynamicLevel.Floor.HeroicRaids", 5);
if (sConfigMgr->GetOption<float>("AutoBalance.LevelEndGameBoost", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.LevelEndGameBoost` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
LevelScalingEndGameBoost = sConfigMgr->GetOption<bool>("AutoBalance.LevelScaling.EndGameBoost", sConfigMgr->GetOption<bool>("AutoBalance.LevelEndGameBoost", 1, false), true);
if (LevelScalingEndGameBoost)
{
LOG_WARN("server.loading", "mod-autobalance: `AutoBalance.LevelScaling.EndGameBoost` is enabled in the configuration, but is not currently implemented. No effect.");
LevelScalingEndGameBoost = 0;
}
//
// RewardScaling.*
// warn the console if deprecated values are detected
//
if (sConfigMgr->GetOption<float>("AutoBalance.DungeonScaleDownXP", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.DungeonScaleDownXP` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
if (sConfigMgr->GetOption<float>("AutoBalance.DungeonScaleDownMoney", false, false))
LOG_WARN("server.loading", "mod-autobalance: deprecated value `AutoBalance.DungeonScaleDownMoney` defined in `AutoBalance.conf`. This variable will be removed in a future release. Please see `AutoBalance.conf.dist` for more details.");
std::string RewardScalingMethodString = sConfigMgr->GetOption<std::string>("AutoBalance.RewardScaling.Method", "dynamic", false);
if (RewardScalingMethodString == "fixed")
RewardScalingMethod = AUTOBALANCE_SCALING_FIXED;
else if (RewardScalingMethodString == "dynamic")
RewardScalingMethod = AUTOBALANCE_SCALING_DYNAMIC;
else
{
LOG_ERROR("server.loading", "mod-autobalance: invalid value `{}` for `AutoBalance.RewardScaling.Method` defined in `AutoBalance.conf`. Defaulting to a value of `dynamic`.", RewardScalingMethodString);
RewardScalingMethod = AUTOBALANCE_SCALING_DYNAMIC;
}
RewardScalingXP = sConfigMgr->GetOption<bool>("AutoBalance.RewardScaling.XP", sConfigMgr->GetOption<bool>("AutoBalance.DungeonScaleDownXP", true, false));
RewardScalingXPModifier = sConfigMgr->GetOption<float>("AutoBalance.RewardScaling.XP.Modifier", 1.0f, false);
RewardScalingMoney = sConfigMgr->GetOption<bool>("AutoBalance.RewardScaling.Money", sConfigMgr->GetOption<bool>("AutoBalance.DungeonScaleDownMoney", true, false));
RewardScalingMoneyModifier = sConfigMgr->GetOption<float>("AutoBalance.RewardScaling.Money.Modifier", 1.0f, false);
//
// Announcement
//
Announcement = sConfigMgr->GetOption<bool>("AutoBalanceAnnounce.enable", true);
}
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef __AB_WORLD_SCRIPT_H
#define __AB_WORLD_SCRIPT_H
#include "WorldScript.h"
class AutoBalance_WorldScript : public WorldScript
{
public:
AutoBalance_WorldScript()
: WorldScript("AutoBalance_WorldScript", {
WORLDHOOK_ON_BEFORE_CONFIG_LOAD
})
{
}
void OnBeforeConfigLoad(bool /*reload*/) override;
void SetInitialWorldSettings();
};
#endif
@@ -0,0 +1,6 @@
void AddAutoBalanceScripts();
void Addmod_autobalanceScripts()
{
AddAutoBalanceScripts();
}
@@ -0,0 +1,85 @@
/*
* Copyright (C) 2018 AzerothCore <http://www.azerothcore.org>
* Copyright (C) 2012 CVMagic <http://www.trinitycore.org/f/topic/6551-vas-autobalance/>
* Copyright (C) 2008-2010 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
* Copyright (C) 1985-2010 KalCorp <http://vasserver.dyndns.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Script Name: AutoBalance
* Original Authors: KalCorp and Vaughner
* Maintainer(s): AzerothCore
* Original Script Name: AutoBalance
* Description: This script is intended to scale based on number of players,
* instance mobs & world bosses' level, health, mana, and damage.
*/
#include "AutoBalance.h"
#include "ABAllCreatureScript.h"
#include "ABAllMapScript.h"
#include "ABCommandScript.h"
#include "ABConfig.h"
#include "ABCreatureInfo.h"
#include "ABGameObjectScript.h"
#include "ABGlobalScript.h"
#include "ABInflectionPointSettings.h"
#include "ABLevelScalingDynamicLevelSettings.h"
#include "ABMapInfo.h"
#include "ABModuleScript.h"
#include "ABPlayerScript.h"
#include "ABScriptMgr.h"
#include "ABStatModifiers.h"
#include "ABUnitScript.h"
#include "ABUtils.h"
#include "ABWorldScript.h"
#include "Configuration/Config.h"
#include "Chat.h"
#include "Creature.h"
#include "Group.h"
#include "Language.h"
#include "Log.h"
#include "Map.h"
#include "MapMgr.h"
#include "Message.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptMgrMacros.h"
#include "SharedDefines.h"
#include "Unit.h"
#include "World.h"
#include <chrono>
#include <vector>
#if AC_COMPILER == AC_COMPILER_GNU
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
void AddAutoBalanceScripts()
{
new AutoBalance_WorldScript();
new AutoBalance_PlayerScript();
new AutoBalance_UnitScript();
new AutoBalance_GameObjectScript();
new AutoBalance_AllCreatureScript();
new AutoBalance_AllMapScript();
new AutoBalance_CommandScript();
new AutoBalance_GlobalScript();
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef MOD_AUTOBALANCE_H
#define MOD_AUTOBALANCE_H
enum ScalingMethod
{
AUTOBALANCE_SCALING_FIXED,
AUTOBALANCE_SCALING_DYNAMIC
};
enum BaseValueType
{
AUTOBALANCE_HEALTH,
AUTOBALANCE_DAMAGE_HEALING
};
enum Relevance
{
AUTOBALANCE_RELEVANCE_FALSE,
AUTOBALANCE_RELEVANCE_TRUE,
AUTOBALANCE_RELEVANCE_UNCHECKED
};
enum Damage_Healing_Debug_Phase
{
AUTOBALANCE_DAMAGE_HEALING_DEBUG_PHASE_BEFORE,
AUTOBALANCE_DAMAGE_HEALING_DEBUG_PHASE_AFTER
};
struct World_Multipliers
{
float scaled = 1.0f;
float unscaled = 1.0f;
};
#endif
+569
View File
@@ -0,0 +1,569 @@
#include "Message.h"
#include "DatabaseEnv.h"
#include "ItemTemplate.h"
#include <iostream>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
const std::unordered_map<LocaleConstant, std::string> AB_WELCOME_TO_PLAYER = {
{LOCALE_enUS, "|cffc3dbff [AutoBalance]|r|cffFF8000 Welcome to {} ({}-player {}). There are {} player(s) in this instance. Difficulty set to {} player(s).|r"},
{LOCALE_koKR, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} ({}-player {})에 오신 것을 환영합니다. 이 인스턴스에는 {}명의 플레이어가 있습니다. 난이도가 {}명으로 설정되었습니다.|r"},
{LOCALE_frFR, "|cffc3dbff [AutoBalance]|r|cffFF8000 Bienvenue dans {} ({} {}). Il y a {} joueur(s) dans cette instance. La difficulté est réglée sur {} joueur(s).|r"},
{LOCALE_deDE, "|cffc3dbff [AutoBalance]|r|cffFF8000 Willkommen in {} ({} Spieler {}). Es gibt {} Spieler in dieser Instanz. Schwierigkeit auf {} Spieler eingestellt.|r"},
{LOCALE_zhCN, "|cffc3dbff [AutoBalance]|r|cffFF8000 欢迎来到 {}{}人 {})。此副本中有 {} 名玩家。难度设置为 {} 名玩家。|r"},
{LOCALE_zhTW, "|cffc3dbff [AutoBalance]|r|cffFF8000 歡迎來到 {}{}人 {})。此副本中有 {} 名玩家。難度設定為 {} 名玩家。|r"},
{LOCALE_esES, "|cffc3dbff [AutoBalance]|r|cffFF8000 Bienvenido a {} ({} jugador {}). Hay {} jugador(es) en esta instancia. La dificultad se establece en {} jugador(es).|r"},
{LOCALE_esMX, "|cffc3dbff [AutoBalance]|r|cffFF8000 Bienvenido a {} ({} jugador {}). Hay {} jugador(es) en esta instancia. La dificultad se establece en {} jugador(es).|r"},
{LOCALE_ruRU, "|cffc3dbff [AutoBalance]|r|cffFF8000 Добро пожаловать в {} ({} игрок {}). В этом экземпляре {} игроков. Сложность установлена на {} игроков.|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_WELCOME_TO_GM = {
{LOCALE_enUS, "|cffc3dbff [AutoBalance]|r|cffFF8000 Your GM flag is turned on. AutoBalance will ignore you. Please turn GM off and exit/re-enter the instance if you'd like to be considering for AutoBalancing.|r"},
{LOCALE_koKR, "|cffc3dbff [AutoBalance]|r|cffFF8000 GM 플래그가 켜져 있습니다. AutoBalance는 당신을 무시합니다. AutoBalancing을 고려하려면 GM을 끄고 인스턴스를 나가고 다시 들어가십시오.|r"},
{LOCALE_frFR, "|cffc3dbff [AutoBalance]|r|cffFF8000 Votre drapeau GM est activé. AutoBalance vous ignorera. Veuillez désactiver GM et sortir/revenir dans l'instance si vous souhaitez être pris en compte pour l'AutoBalancing.|r"},
{LOCALE_deDE, "|cffc3dbff [AutoBalance]|r|cffFF8000 Ihre GM-Flagge ist eingeschaltet. AutoBalance wird Sie ignorieren. Bitte schalten Sie GM aus und verlassen Sie das Instanz, wenn Sie für das AutoBalancing berücksichtigt werden möchten.|r"},
{LOCALE_zhCN, "|cffc3dbff [AutoBalance]|r|cffFF8000 您的GM模式已打开。AutoBalance将忽略。如果您希望考虑自动平衡,请关闭GM并退出/重新进入副本。|r"},
{LOCALE_zhTW, "|cffc3dbff [AutoBalance]|r|cffFF8000 您的GM模式已打開。AutoBalance將忽略。如果您希望考慮自動平衡,請關閉GM並退出/重新進入副本。|r"},
{LOCALE_esES, "|cffc3dbff [AutoBalance]|r|cffFF8000 Su bandera de GM está encendida. AutoBalance te ignorará. Por favor, apague GM y salga/vuelva a entrar en la instancia si desea ser considerado para el AutoBalance.|r"},
{LOCALE_esMX, "|cffc3dbff [AutoBalance]|r|cffFF8000 Su bandera de GM está encendida. AutoBalance te ignorará. Por favor, apague GM y salga/vuelva a entrar en la instancia si desea ser considerado para el AutoBalance.|r"},
{LOCALE_ruRU, "|cffc3dbff [AutoBalance]|r|cffFF8000 Ваш флаг GM включен. AutoBalance будет игнорировать вас. Пожалуйста, отключите GM и выйдите/войдите в экземпляр, если хотите, чтобы вас учитывали при автобалансировке.|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_ANNOUNCE_NON_GM_ENTERING_INSTANCE = {
{LOCALE_enUS, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} enters the instance. There are {} player(s) in this instance. Difficulty set to {} player(s).|r"},
{LOCALE_koKR, "|cffc3dbff [AutoBalance]|r|cffFF8000 {}이(가) 인스턴스에 들어왔습니다. 이 인스턴스에는 {}명의 플레이어가 있습니다. 난이도가 {}명으로 설정되었습니다.|r"},
{LOCALE_frFR, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} entre dans l'instance. Il y a {} joueur(s) dans cette instance. La difficulté est réglée sur {} joueur(s).|r"},
{LOCALE_deDE, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} betritt die Instanz. Es gibt {} Spieler in dieser Instanz. Schwierigkeit auf {} Spieler eingestellt.|r"},
{LOCALE_zhCN, "|cffc3dbff [AutoBalance]|r|cffFF8000 {}进入了副本。此副本中有 {} 名玩家。难度设置为 {} 名玩家。|r"},
{LOCALE_zhTW, "|cffc3dbff [AutoBalance]|r|cffFF8000 {}進入了副本。此副本中有 {} 名玩家。難度設定為 {} 名玩家。|r"},
{LOCALE_esES, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} entra en la instancia. Hay {} jugador(es) en esta instancia. La dificultad se establece en {} jugador(es).|r"},
{LOCALE_esMX, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} entra en la instancia. Hay {} jugador(es) en esta instancia. La dificultad se establece en {} jugador(es).|r"},
{LOCALE_ruRU, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} входит в экземпляр. В этом экземпляре {} игроков. Сложность установлена на {} игроков.|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_LEAVING_INSTANCE_COMBAT = {
{LOCALE_enUS, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} left the instance while combat was in progress. Difficulty locked to no less than {} players until combat ends.|r"},
{LOCALE_koKR, "|cffc3dbff [AutoBalance]|r|cffFF8000 {}이(가) 전투 중에 인스턴스를 떠났습니다. 전투가 끝날 때까지 난이도가 {}명 미만으로 잠겨 있습니다.|r"},
{LOCALE_frFR, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} a quitté l'instance alors que le combat était en cours. La difficulté est verrouillée à pas moins de {} joueur(s) jusqu'à la fin du combat.|r"},
{LOCALE_deDE, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} hat die Instanz verlassen, während der Kampf im Gange war. Die Schwierigkeit ist gesperrt, bis der Kampf endet, auf nicht weniger als {} Spieler.|r"},
{LOCALE_zhCN, "|cffc3dbff [AutoBalance]|r|cffFF8000 {}在战斗进行中离开了副本。直到战斗结束,难度锁定为不少于 {} 名玩家。|r"},
{LOCALE_zhTW, "|cffc3dbff [AutoBalance]|r|cffFF8000 {}在戰鬥進行中離開了副本。直到戰鬥結束,難度鎖定為不少於 {} 名玩家。|r"},
{LOCALE_esES, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} salió de la instancia mientras el combate estaba en progreso. La dificultad está bloqueada a no menos de {} jugador(es) hasta que termine el combate.|r"}
};
const std::unordered_map<LocaleConstant, std::string> AB_LEAVING_INSTANCE = {
{LOCALE_enUS, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} left the instance. There are {} player(s) in this instance. Difficulty set to {} player(s).|r"},
{LOCALE_koKR, "|cffc3dbff [AutoBalance]|r|cffFF8000 {}이(가) 인스턴스를 떠났습니다. 이 인스턴스에는 {}명의 플레이어가 있습니다. 난이도가 {}명으로 설정되었습니다.|r"},
{LOCALE_frFR, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} a quitté l'instance. Il y a {} joueur(s) dans cette instance. La difficulté est réglée sur {} joueur(s).|r"},
{LOCALE_deDE, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} hat die Instanz verlassen. Es gibt {} Spieler in dieser Instanz. Schwierigkeit auf {} Spieler eingestellt.|r"},
{LOCALE_zhCN, "|cffc3dbff [AutoBalance]|r|cffFF8000 {}离开了副本。此副本中有 {} 名玩家。难度设置为 {} 名玩家。|r"},
{LOCALE_zhTW, "|cffc3dbff [AutoBalance]|r|cffFF8000 {}離開了副本。此副本中有 {} 名玩家。難度設定為 {} 名玩家。|r"},
{LOCALE_esES, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} salió de la instancia. Hay {} jugador(es) en esta instancia. La dificultad se establece en {} jugador(es).|r"},
{LOCALE_esMX, "|cffc3dbff [AutoBalance]|r|cffFF8000 {} salió de la instancia. Hay {} jugador(es) en esta instancia. La dificultad se establece en {}"}
};
const std::unordered_map<LocaleConstant, std::string> AB_SET_OFFSET_COMMAND_DESCRIPTION = {
{LOCALE_enUS, "Set the player difficulty offset for this instance. Usage: .ab offset <number>.|r"},
{LOCALE_koKR, "이 인스턴스의 플레이어 난이도 오프셋을 설정합니다. 사용법: .ab offset <숫자>.|r"},
{LOCALE_frFR, "Définissez le décalage de difficulté du joueur pour cette instance. Utilisation : .ab offset <nombre>.|r"},
{LOCALE_deDE, "Legen Sie den Spieler-Schwierigkeits-Offset für diese Instanz fest. Verwendung: .ab offset <Nummer>.|r"},
{LOCALE_zhCN, "设置此副本的玩家难度。用法:.ab offset <数字>。|r"},
{LOCALE_zhTW, "設定此副本的玩家難度。用法:.ab offset <數字>。|r"},
{LOCALE_esES, "Establece el desplazamiento de dificultad del jugador para esta instancia. Uso: .ab offset <número>.|r"},
{LOCALE_esMX, "Establece el desplazamiento de dificultad del jugador para esta instancia. Uso: .ab offset <número>.|r"},
{LOCALE_ruRU, "Устанавливает смещение сложности игрока для этого экземп"}
};
const std::unordered_map<LocaleConstant, std::string> AB_SET_OFFSET_COMMAND_SUCCESS = {
{LOCALE_enUS, "Changing Player Difficulty Offset to {}.|r"},
{LOCALE_koKR, "플레이어 난이도 오프셋을 {}(으)로 변경합니다.|r"},
{LOCALE_frFR, "Modification du décalage de difficulté du joueur à {}.|r"},
{LOCALE_deDE, "Spieler-Schwierigkeits-Offset auf {} ändern.|r"},
{LOCALE_zhCN, "将玩家难度更改为 {}。|r"},
{LOCALE_zhTW, "將玩家難度更改為 {}。|r"},
{LOCALE_esES, "Cambiando el desplazamiento de dificultad del jugador a {}.|r"},
{LOCALE_esMX, "Cambiando el desplazamiento de dificultad del jugador a {}.|r"},
{LOCALE_ruRU, "Изменение смещения сложности игрока на {}.|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_SET_OFFSET_COMMAND_ERROR = {
{LOCALE_enUS, "Error changing Player Difficulty Offset! Please try again.|r"},
{LOCALE_koKR, "플레이어 난이도 오프셋 변경 중 오류가 발생했습니다! 다시 시도하십시오.|r"},
{LOCALE_frFR, "Erreur lors de la modification du décalage de difficulté du joueur ! Veuillez réessayer.|r"},
{LOCALE_deDE, "Fehler beim Ändern des Spieler-Schwierigkeits-Offsets! Bitte versuchen Sie es erneut.|r"},
{LOCALE_zhCN, "更改玩家难度时出错!请重试。|r"},
{LOCALE_zhTW, "更改玩家難度時出錯!請重試。|r"},
{LOCALE_esES, "¡Error al cambiar el desplazamiento de dificultad del jugador! Por favor, inténtelo de nuevo.|r"},
{LOCALE_esMX, "¡Error al cambiar el desplazamiento de dificultad del jugador! Por favor, inténtelo de nuevo.|r"},
{LOCALE_ruRU, "Ошибка при изменении смещения сложности игрока! Пожалуйста, попробуйте еще раз.|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_GET_OFFSET_COMMAND_SUCCESS = {
{LOCALE_enUS, "Current Player Difficulty Offset = {}.|r"},
{LOCALE_koKR, "현재 플레이어 난이도 오프셋 = {}.|r"},
{LOCALE_frFR, "Décalage de difficulté actuel du joueur = {}.|r"},
{LOCALE_deDE, "Aktueller Spieler-Schwierigkeits-Offset = {}.|r"},
{LOCALE_zhCN, "当前玩家难度偏移 = {}。|r"},
{LOCALE_zhTW, "當前玩家難度偏移 = {}。|r"},
{LOCALE_esES, "Desplazamiento de dificultad actual del jugador = {}.|r"},
{LOCALE_esMX, "Desplazamiento de dificultad actual del jugador = {}.|r"},
{LOCALE_ruRU, "Текущее смещение сложности игрока = {}.|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_ADJUSTED_PLAYER_COUNT_COMBAT_LOCKED = {
{LOCALE_enUS, "Adjusted Player Count: {} (Combat Locked)|r"},
{LOCALE_koKR, "조정된 플레이어 수: {} (전투 잠금됨)|r"},
{LOCALE_frFR, "Nombre de joueurs ajusté : {} (verrouillé en combat)|r"},
{LOCALE_deDE, "Angepasste Spieleranzahl: {} (Kampf gesperrt)|r"},
{LOCALE_zhCN, "调整后的玩家数量:{}(战斗锁定)|r"},
{LOCALE_zhTW, "調整後的玩家數量:{}(戰鬥鎖定)|r"},
{LOCALE_esES, "Cantidad de jugadores ajustada: {} (bloqueada en combate)|r"},
{LOCALE_esMX, "Cantidad de jugadores ajustada: {} (bloqueada en combate)|r"},
{LOCALE_ruRU, "Количество игроков, отрегулированное: {} (заблокировано в бою)|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_ADJUSTED_PLAYER_COUNT_MAP_MINIMUM = {
{LOCALE_enUS, "Adjusted Player Count: {} (Map Minimum)|r"},
{LOCALE_koKR, "조정된 플레이어 수: {} (지도 최소)|r"},
{LOCALE_frFR, "Nombre de joueurs ajusté : {} (minimum de la carte)|r"},
{LOCALE_deDE, "Angepasste Spieleranzahl: {} (Kartenminimum)|r"},
{LOCALE_zhCN, "调整后的玩家数量:{}(地图最小)|r"},
{LOCALE_zhTW, "調整後的玩家數量:{}(地圖最小)|r"},
{LOCALE_esES, "Cantidad de jugadores ajustada: {} (mínimo del mapa)|r"},
{LOCALE_esMX, "Cantidad de jugadores ajustada: {} (mínimo del mapa)|r"},
{LOCALE_ruRU, "Количество игроков, отрегулированное: {} (минимальное для карты)|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_ADJUSTED_PLAYER_COUNT_MAP_MINIMUM_DIFFICULTY_OFFSET = {
{LOCALE_enUS, "Adjusted Player Count: {} (Map Minimum + Difficulty Offset of {})|r"},
{LOCALE_koKR, "조정된 플레이어 수: {} (지도 최소 + {}의 난이도 오프셋)|r"},
{LOCALE_frFR, "Nombre de joueurs ajusté : {} (minimum de la carte + décalage de difficulté de {})|r"},
{LOCALE_deDE, "Angepasste Spieleranzahl: {} (Kartenminimum + Schwierigkeits-Offset von {})|r"},
{LOCALE_zhCN, "调整后的玩家数量:{}(地图最小 + {}的难度修正)|r"},
{LOCALE_zhTW, "調整後的玩家數量:{}(地圖最小 + {}的難度修正)|r"},
{LOCALE_esES, "Cantidad de jugadores ajustada: {} (mínimo del mapa + desplazamiento de dificultad de {})|r"},
{LOCALE_esMX, "Cantidad de jugadores ajustada: {} (mínimo del mapa + desplazamiento de dificultad de {})|r"},
{LOCALE_ruRU, "Количество игроков, отрегулированное: {} (минимальное для карты"}
};
const std::unordered_map<LocaleConstant, std::string> AB_ADJUSTED_PLAYER_COUNT_DIFFICULTY_OFFSET = {
{LOCALE_enUS, "Adjusted Player Count: {} (Difficulty Offset of {})|r"},
{LOCALE_koKR, "조정된 플레이어 수: {} ({}의 난이도 오프셋)|r"},
{LOCALE_frFR, "Nombre de joueurs ajusté : {} (décalage de difficulté de {})|r"},
{LOCALE_deDE, "Angepasste Spieleranzahl: {} (Schwierigkeits-Offset von {})|r"},
{LOCALE_zhCN, "调整后的玩家数量:{}({}的难度修正)|r"},
{LOCALE_zhTW, "調整後的玩家數量:{}({}的難度修正)|r"},
{LOCALE_esES, "Cantidad de jugadores ajustada: {} (desplazamiento de dificultad de {})|r"},
{LOCALE_esMX, "Cantidad de jugadores ajustada: {} (desplazamiento de dificultad de {})|r"},
{LOCALE_ruRU, "Количество игроков, отрегулированное: {} (смещение сложности {})|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_ADJUSTED_PLAYER_COUNT = {
{LOCALE_enUS, "Adjusted Player Count: {}|r"},
{LOCALE_koKR, "조정된 플레이어 수: {}|r"},
{LOCALE_frFR, "Nombre de joueurs ajusté : {}|r"},
{LOCALE_deDE, "Angepasste Spieleranzahl: {}|r"},
{LOCALE_zhCN, "调整后的玩家数量:{}|r"},
{LOCALE_zhTW, "調整後的玩家數量:{}|r"},
{LOCALE_esES, "Cantidad de jugadores ajustada: {}|r"},
{LOCALE_esMX, "Cantidad de jugadores ajustada: {}|r"},
{LOCALE_ruRU, "Количество игроков, отрегулированное: {}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_LFG_RANGE = {
{LOCALE_enUS, "LFG Range: Lvl {} - {} (Target: Lvl {})|r"},
{LOCALE_koKR, "LFG 범위: 레벨 {} - {} (대상: 레벨 {})|r"},
{LOCALE_frFR, "Plage LFG : Niveau {} - {} (Cible : Niveau {})|r"},
{LOCALE_deDE, "LFG-Bereich: Stufe {} - {} (Ziel: Stufe {})|r"},
{LOCALE_zhCN, "LFG范围:等级 {} - {}(目标:等级 {})|r"},
{LOCALE_zhTW, "LFG範圍:等級 {} - {}(目標:等級 {})|r"},
{LOCALE_esES, "Rango de LFG: Nivel {} - {} (Objetivo: Nivel {})|r"},
{LOCALE_esMX, "Rango de LFG: Nivel {} - {} (Objetivo: Nivel {})|r"},
{LOCALE_ruRU, "Диапазон поиска группы: Ур. {} - {} (Цель: Ур. {})|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_MAP_LEVEL = {
{LOCALE_enUS, "Map Level: {}{}|r"},
{LOCALE_koKR, "지도 레벨: {}{}|r"},
{LOCALE_frFR, "Niveau de la carte : {}{}|r"},
{LOCALE_deDE, "Kartenlevel: {}{}|r"},
{LOCALE_zhCN, "地图等级:{}{}|r"},
{LOCALE_zhTW, "地圖等級:{}{}|r"},
{LOCALE_esES, "Nivel del mapa: {}{}|r"},
{LOCALE_esMX, "Nivel del mapa: {}{}|r"},
{LOCALE_ruRU, "Уровень карты: {}{}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_LEVEL_SCALING_ENABLED = {
{LOCALE_enUS, " (Level Scaling Enabled)|r"},
{LOCALE_koKR, " (레벨 스케일링 활성화됨)|r"},
{LOCALE_frFR, " (Mise à l'échelle des niveaux activée)|r"},
{LOCALE_deDE, " (Stufenanpassung aktiviert)|r"},
{LOCALE_zhCN, " (启用等级自动平衡)|r"},
{LOCALE_zhTW, " (啟用等級縮放平衡)|r"},
{LOCALE_esES, " (Escalado de nivel activado)|r"},
{LOCALE_esMX, " (Escalado de nivel activado)|r"},
{LOCALE_ruRU, " (Масштабирование уровней включено)|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_LEVEL_SCALING_DISABLED = {
{LOCALE_enUS, " (Level Scaling Disabled)|r"},
{LOCALE_koKR, " (레벨 스케일링 비활성화됨)|r"},
{LOCALE_frFR, " (Mise à l'échelle des niveaux désactivée)|r"},
{LOCALE_deDE, " (Stufenanpassung deaktiviert)|r"},
{LOCALE_zhCN, " (禁用等级自动平衡)|r"},
{LOCALE_zhTW, " (停用等級縮放平衡)|r"},
{LOCALE_esES, " (Escalado de nivel desactivado)|r"},
{LOCALE_esMX, " (Escalado de nivel desactivado)|r"},
{LOCALE_ruRU, " (Масштабирование уровней отключено)|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_WORLD_HEALTH_MULTIPLIER = {
{LOCALE_enUS, "World health multiplier: {:.3f}|r"},
{LOCALE_koKR, "월드 체력 배율: {:.3f}|r"},
{LOCALE_frFR, "Multiplicateur de santé mondiale : {:.3f}|r"},
{LOCALE_deDE, "Weltgesundheitsmultiplikator: {:.3f}|r"},
{LOCALE_zhCN, "全局生命值倍率:{:.3f}|r"},
{LOCALE_zhTW, "全局生命值倍增器:{:.3f}|r"},
{LOCALE_esES, "Multiplicador de salud mundial: {:.3f}|r"},
{LOCALE_esMX, "Multiplicador de salud mundial: {:.3f}|r"},
{LOCALE_ruRU, "Множитель здоровья мира: {:.3f}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_WORLD_HOSTILE_DAMAGE_HEALING_MULTIPLIER_TO = {
{LOCALE_enUS, "World hostile damage and healing multiplier: {:.3f} -> {:.3f}|r"},
{LOCALE_koKR, "월드 적 대미지 및 치유 배율: {:.3f} -> {:.3f}|r"},
{LOCALE_frFR, "Multiplicateur de dégâts et de soins hostiles mondiaux : {:.3f} -> {:.3f}|r"},
{LOCALE_deDE, "Weltweiter feindlicher Schadens- und Heilungs-Multiplikator: {:.3f} -> {:.3f}|r"},
{LOCALE_zhCN, "全局伤害和治疗倍率:{:.3f} -> {:.3f}|r"},
{LOCALE_zhTW, "全局敵對傷害和治療倍增器:{:.3f} -> {:.3f}|r"},
{LOCALE_esES, "Multiplicador de daño y curación hostil mundial: {:.3f} -> {:.3f}|r"},
{LOCALE_esMX, "Multiplicador de daño y curación hostil mundial: {:.3f} -> {:.3f}|r"},
{LOCALE_ruRU, "Множитель урона и лечения мира: {:.3f} -> {:.3f}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_WORLD_HOSTILE_DAMAGE_HEALING_MULTIPLIER = {
{LOCALE_enUS, "World hostile damage and healing multiplier: {:.3f}|r"},
{LOCALE_koKR, "월드 적 대미지 및 치유 배율: {:.3f}|r"},
{LOCALE_frFR, "Multiplicateur de dégâts et de soins hostiles mondiaux : {:.3f}|r"},
{LOCALE_deDE, "Weltweiter feindlicher Schadens- und Heilungs-Multiplikator: {:.3f}|r"},
{LOCALE_zhCN, "全局伤害和治疗倍率:{:.3f}|r"},
{LOCALE_zhTW, "全局敵對傷害和治療倍增器:{:.3f}|r"},
{LOCALE_esES, "Multiplicador de daño y curación hostil mundial: {:.3f}|r"},
{LOCALE_esMX, "Multiplicador de daño y curación hostil mundial: {:.3f}|r"},
{LOCALE_ruRU, "Множитель урона и лечения мира: {:.3f}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_ORIGINAL_CREATURE_LEVEL_RANGE = {
{LOCALE_enUS, "Original Creature Level Range: {} - {} (Avg: {:.2f})|r"},
{LOCALE_koKR, "원래 크리쳐 레벨 범위: {} - {} (평균: {:.2f})|r"},
{LOCALE_frFR, "Plage de niveaux de créatures d'origine : {} - {} (Moyenne : {:.2f})|r"},
{LOCALE_deDE, "Originaler Kreaturenlevelbereich: {} - {} (Durchschnitt: {:.2f})|r"},
{LOCALE_zhCN, "原始生物等级范围:{} - {}(平均:{:2.f}|r"},
{LOCALE_zhTW, "原始生物等級範圍:{} - {}(平均:{:2.f}|r"},
{LOCALE_esES, "Rango de niveles de criaturas originales: {} - {} (Promedio: {:.2f})|r"},
{LOCALE_esMX, "Rango de niveles de criaturas originales: {} - {} (Promedio: {:.2f})|r"},
{LOCALE_ruRU, "Исходный диапазон уровней существ: {} - {} (Среднее: {:.2f})|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_ACTIVE_TOTAL_CREATURES_IN_MAP = {
{LOCALE_enUS, "Active | Total Creatures in map: {} | {}|r"},
{LOCALE_koKR, "활성 | 지도 내 총 크리쳐: {} | {}|r"},
{LOCALE_frFR, "Actif | Créatures totales dans la carte : {} | {}|r"},
{LOCALE_deDE, "Aktiv | Gesamte Kreaturen in der Karte: {} | {}|r"},
{LOCALE_zhCN, "Active | 地图中的总生物: {} | {}|r"},
{LOCALE_zhTW, "Active | 地圖中的總生物: {} | {}|r"},
{LOCALE_esES, "Activo | Criaturas totales en el mapa: {} | {}|r"},
{LOCALE_esMX, "Activo | Criaturas totales en el mapa: {} | {}|r"},
{LOCALE_ruRU, "Активные | Всего существ на карте: {} | {}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_COMMAND_ONLY_IN_INSTANCE = {
{LOCALE_enUS, "This command can only be used in a dungeon or raid.|r"},
{LOCALE_koKR, "이 명령은 던전이나 공격대에서만 사용할 수 있습니다.|r"},
{LOCALE_frFR, "Cette commande ne peut être utilisée que dans un donjon ou un raid.|r"},
{LOCALE_deDE, "Dieser Befehl kann nur in einem Dungeon oder Schlachtzug verwendet werden.|r"},
{LOCALE_zhCN, "此命令只能在地下城或团队副本中使用。|r"},
{LOCALE_zhTW, "此命令只能在地城或團隊副本中使用。|r"},
{LOCALE_esES, "Este comando solo se puede usar en una mazmorra o banda.|r"},
{LOCALE_esMX, "Este comando solo se puede usar en una mazmorra o banda.|r"},
{LOCALE_ruRU, "Эту команду можно использовать только в подземелье или рейде.|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_TARGET_NO_IN_INSTANCE = {
{LOCALE_enUS, "That target is not in an instance.|r"},
{LOCALE_koKR, "그 대상은 인스턴스에 있지 않습니다.|r"},
{LOCALE_frFR, "Cette cible n'est pas dans une instance.|r"},
{LOCALE_deDE, "Dieses Ziel befindet sich nicht in einer Instanz.|r"},
{LOCALE_zhCN, "该目标不在副本中。|r"},
{LOCALE_zhTW, "該目標不在副本中。|r"},
{LOCALE_esES, "Ese objetivo no está en una instancia.|r"},
{LOCALE_esMX, "Ese objetivo no está en una instancia.|r"},
{LOCALE_ruRU, "Эта цель не находится в подземелье.|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_ACTIVE_FOR_MAP_STATS = {
{LOCALE_enUS, "Active for Map Stats|r"},
{LOCALE_koKR, "지도 통계용 활성|r"},
{LOCALE_frFR, "Actif pour les statistiques de la carte|r"},
{LOCALE_deDE, "Aktiv für Kartenstatistiken|r"},
{LOCALE_zhCN, "地图平衡激活|r"},
{LOCALE_zhTW, "地圖平衡激活|r"},
{LOCALE_esES, "Activo para estadísticas del mapa|r"},
{LOCALE_esMX, "Activo para estadísticas del mapa|r"},
{LOCALE_ruRU, "Активно для статистики карты|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_IGNORED_FOR_MAP_STATS = {
{LOCALE_enUS, "Ignored for Map Stats|r"},
{LOCALE_koKR, "지도 통계용 무시됨|r"},
{LOCALE_frFR, "Ignoré pour les statistiques de la carte|r"},
{LOCALE_deDE, "Ignoriert für Kartenstatistiken|r"},
{LOCALE_zhCN, "地图平衡已忽略|r"},
{LOCALE_zhTW, "地圖平衡已忽略|r"},
{LOCALE_esES, "Ignorado para estadísticas del mapa|r"},
{LOCALE_esMX, "Ignorado para estadísticas del mapa|r"},
{LOCALE_ruRU, "Игнорируется для статистики карты|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_CREATURE_DIFFICULTY_LEVEL = {
{LOCALE_enUS, "Creature difficulty level: {} player(s)|r"},
{LOCALE_koKR, "생물 난이도 레벨: {} 플레이어|r"},
{LOCALE_frFR, "Niveau de difficulté de la créature : {} joueur(s)|r"},
{LOCALE_deDE, "Kreaturschwierigkeitsstufe: {} Spieler|r"},
{LOCALE_zhCN, "生物难度等级:{} 玩家|r"},
{LOCALE_zhTW, "生物難度等級:{} 玩家|r"},
{LOCALE_esES, "Nivel de dificultad de la criatura: {} jugador(es)|r"},
{LOCALE_esMX, "Nivel de dificultad de la criatura: {} jugador(es)|r"},
{LOCALE_ruRU, "Уровень сложности существа: {} игрок(ов)|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_CLONE_OF_SUMMON = {
{LOCALE_enUS, "Clone of {} ({})|r"},
{LOCALE_koKR, "{}의 복제 ({})|r"},
{LOCALE_frFR, "Clone de {} ({})|r"},
{LOCALE_deDE, "Klon von {} ({})|r"},
{LOCALE_zhCN, "{}的克隆({}|r"},
{LOCALE_zhTW, "{}的克隆({}|r"},
{LOCALE_esES, "Clon de {} ({})|r"},
{LOCALE_esMX, "Clon de {} ({})|r"},
{LOCALE_ruRU, "Клон {} ({})|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_SUMMON_OF_SUMMON = {
{LOCALE_enUS, "Summon of {} ({})|r"},
{LOCALE_koKR, "{}의 소환 ({})|r"},
{LOCALE_frFR, "Invocation de {} ({})|r"},
{LOCALE_deDE, "Beschwörung von {} ({})|r"},
{LOCALE_zhCN, "{}的召唤({}|r"},
{LOCALE_zhTW, "{}的召喚({}|r"},
{LOCALE_esES, "Invocación de {} ({})|r"},
{LOCALE_esMX, "Invocación de {} ({})|r"},
{LOCALE_ruRU, "Призыв {} ({})|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_SUMMON_WITHOUT_SUMMONER = {
{LOCALE_enUS, "Summon without a summoner.|r"},
{LOCALE_koKR, "소환사 없는 소환.|r"},
{LOCALE_frFR, "Invocation sans invocateur.|r"},
{LOCALE_deDE, "Beschwörung ohne Beschwörer.|r"},
{LOCALE_zhCN, "没有召唤者的召唤物。|r"},
{LOCALE_zhTW, "沒有召喚者的召喚物。|r"},
{LOCALE_esES, "Invocación sin invocador.|r"},
{LOCALE_esMX, "Invocación sin invocador.|r"},
{LOCALE_ruRU, "Призыв без призывателя.|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_HEALTH_MULTIPLIER_TO = {
{LOCALE_enUS, "Health multiplier: {:.3f} -> {:.3f}|r"},
{LOCALE_koKR, "체력 배율: {:.3f} -> {:.3f}|r"},
{LOCALE_frFR, "Multiplicateur de santé : {:.3f} -> {:.3f}|r"},
{LOCALE_deDE, "Gesundheitsmultiplikator: {:.3f} -> {:.3f}|r"},
{LOCALE_zhCN, "生命值倍率:{:.3f} -> {:.3f}|r"},
{LOCALE_zhTW, "生命值倍增器:{:.3f} -> {:.3f}|r"},
{LOCALE_esES, "Multiplicador de salud: {:.3f} -> {:.3f}|r"},
{LOCALE_esMX, "Multiplicador de salud: {:.3f} -> {:.3f}|r"},
{LOCALE_ruRU, "Множитель здоровья: {:.3f} -> {:.3f}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_MANA_MULTIPLIER_TO = {
{LOCALE_enUS, "Mana multiplier: {:.3f} -> {:.3f}|r"},
{LOCALE_koKR, "마나 배율: {:.3f} -> {:.3f}|r"},
{LOCALE_frFR, "Multiplicateur de mana : {:.3f} -> {:.3f}|r"},
{LOCALE_deDE, "Manamultiplikator: {:.3f} -> {:.3f}|r"},
{LOCALE_zhCN, "法力值倍率:{:.3f} -> {:.3f}|r"},
{LOCALE_zhTW, "法力值倍增器:{:.3f} -> {:.3f}|r"},
{LOCALE_esES, "Multiplicador de maná: {:.3f} -> {:.3f}|r"},
{LOCALE_esMX, "Multiplicador de maná: {:.3f} -> {:.3f}|r"},
{LOCALE_ruRU, "Множитель маны: {:.3f} -> {:.3f}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_ARMOR_MULTIPLIER_TO = {
{LOCALE_enUS, "Armor multiplier: {:.3f} -> {:.3f}|r"},
{LOCALE_koKR, "방어구 배율: {:.3f} -> {:.3f}|r"},
{LOCALE_frFR, "Multiplicateur d'armure : {:.3f} -> {:.3f}|r"},
{LOCALE_deDE, "Rüstungsmultiplikator: {:.3f} -> {:.3f}|r"},
{LOCALE_zhCN, "护甲倍率:{:.3f} -> {:.3f}|r"},
{LOCALE_zhTW, "護甲倍增器:{:.3f} -> {:.3f}|r"},
{LOCALE_esES, "Multiplicador de armadura: {:.3f} -> {:.3f}|r"},
{LOCALE_esMX, "Multiplicador de armadura: {:.3f} -> {:.3f}|r"},
{LOCALE_ruRU, "Множитель брони: {:.3f} -> {:.3f}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_DAMAGE_MULTIPLIER_TO = {
{LOCALE_enUS, "Damage multiplier: {:.3f} -> {:.3f}|r"},
{LOCALE_koKR, "피해 배율: {:.3f} -> {:.3f}|r"},
{LOCALE_frFR, "Multiplicateur de dégâts : {:.3f} -> {:.3f}|r"},
{LOCALE_deDE, "Schadensmultiplikator: {:.3f} -> {:.3f}|r"},
{LOCALE_zhCN, "伤害倍率:{:.3f} -> {:.3f}|r"},
{LOCALE_zhTW, "傷害倍增器:{:.3f} -> {:.3f}|r"},
{LOCALE_esES, "Multiplicador de daño: {:.3f} -> {:.3f}|r"},
{LOCALE_esMX, "Multiplicador de daño: {:.3f} -> {:.3f}|r"},
{LOCALE_ruRU, "Множитель урона: {:.3f} -> {:.3f}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_HEALTH_MULTIPLIER = {
{LOCALE_enUS, "Health multiplier: {:.3f}|r"},
{LOCALE_koKR, "체력 배율: {:.3f}|r"},
{LOCALE_frFR, "Multiplicateur de santé : {:.3f}|r"},
{LOCALE_deDE, "Gesundheitsmultiplikator: {:.3f}|r"},
{LOCALE_zhCN, "生命值倍率:{:.3f}|r"},
{LOCALE_zhTW, "生命值倍增器:{:.3f}|r"},
{LOCALE_esES, "Multiplicador de salud: {:.3f}|r"},
{LOCALE_esMX, "Multiplicador de salud: {:.3f}|r"},
{LOCALE_ruRU, "Множитель здоровья: {:.3f}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_MANA_MULTIPLIER = {
{LOCALE_enUS, "Mana multiplier: {:.3f}|r"},
{LOCALE_koKR, "마나 배율: {:.3f}|r"},
{LOCALE_frFR, "Multiplicateur de mana : {:.3f}|r"},
{LOCALE_deDE, "Manamultiplikator: {:.3f}|r"},
{LOCALE_zhCN, "法力值倍率:{:.3f}|r"},
{LOCALE_zhTW, "法力值倍增器:{:.3f}|r"},
{LOCALE_esES, "Multiplicador de maná: {:.3f}|r"},
{LOCALE_esMX, "Multiplicador de maná: {:.3f}|r"},
{LOCALE_ruRU, "Множитель маны: {:.3f}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_ARMOR_MULTIPLIER = {
{LOCALE_enUS, "Armor multiplier: {:.3f}|r"},
{LOCALE_koKR, "방어구 배율: {:.3f}|r"},
{LOCALE_frFR, "Multiplicateur d'armure : {:.3f}|r"},
{LOCALE_deDE, "Rüstungsmultiplikator: {:.3f}|r"},
{LOCALE_zhCN, "护甲倍率:{:.3f}|r"},
{LOCALE_zhTW, "護甲倍增器:{:.3f}|r"},
{LOCALE_esES, "Multiplicador de armadura: {:.3f}|r"},
{LOCALE_esMX, "Multiplicador de armadura: {:.3f}|r"},
{LOCALE_ruRU, "Множитель брони: {:.3f}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_DAMAGE_MULTIPLIER = {
{LOCALE_enUS, "Damage multiplier: {:.3f}|r"},
{LOCALE_koKR, "피해 배율: {:.3f}|r"},
{LOCALE_frFR, "Multiplicateur de dégâts : {:.3f}|r"},
{LOCALE_deDE, "Schadensmultiplikator: {:.3f}|r"},
{LOCALE_zhCN, "伤害倍率:{:.3f}|r"},
{LOCALE_zhTW, "傷害倍增器:{:.3f}|r"},
{LOCALE_esES, "Multiplicador de daño: {:.3f}|r"},
{LOCALE_esMX, "Multiplicador de daño: {:.3f}|r"},
{LOCALE_ruRU, "Множитель урона: {:.3f}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_CC_DURATION_MULTIPLIER = {
{LOCALE_enUS, "CC Duration multiplier: {:.3f}|r"},
{LOCALE_koKR, "CC 지속시간 배율: {:.3f}|r"},
{LOCALE_frFR, "Multiplicateur de durée de la CC : {:.3f}|r"},
{LOCALE_deDE, "CC-Dauer-Multiplikator: {:.3f}|r"},
{LOCALE_zhCN, "控制持续时间倍率:{:.3f}|r"},
{LOCALE_zhTW, "控制持續時間倍增器:{:.3f}|r"},
{LOCALE_esES, "Multiplicador de duración de CC: {:.3f}|r"},
{LOCALE_esMX, "Multiplicador de duración de CC: {:.3f}|r"},
{LOCALE_ruRU, "Множитель длительности контроля: {:.3f}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_XP_MONEY_MULTIPLIER = {
{LOCALE_enUS, "XP multiplier: {:.3f} Money multiplier: {:.3f}|r"},
{LOCALE_koKR, "경험치 배율: {:.3f} 돈 배율: {:.3f}|r"},
{LOCALE_frFR, "Multiplicateur d'XP : {:.3f} Multiplicateur d'argent : {:.3f}|r"},
{LOCALE_deDE, "XP-Multiplikator: {:.3f} Geldmultiplikator: {:.3f}|r"},
{LOCALE_zhCN, "经验值倍率:{:.3f} 金钱倍率:{:.3f}|r"},
{LOCALE_zhTW, "經驗值倍增器:{:.3f} 金錢倍增器:{:.3f}|r"},
{LOCALE_esES, "Multiplicador de XP: {:.3f} Multiplicador de dinero: {:.3f}|r"},
{LOCALE_esMX, "Multiplicador de XP: {:.3f} Multiplicador de dinero: {:.3f}|r"},
{LOCALE_ruRU, "Множитель опыта: {:.3f} Множитель денег: {:.3f}|r"},
};
const std::unordered_map<LocaleConstant, std::string> AB_LEAVING_INSTANCE_COMBAT_CHANGE = {
{LOCALE_enUS, "|cffc3dbff [AutoBalance]|r|cffFF8000 Combat has ended. Difficulty is no longer locked.|r"},
{LOCALE_koKR, "|cffc3dbff [AutoBalance]|r|cffFF8000 전투가 종료되었습니다. 난이도가 더 이상 잠겨 있지 않습니다.|r"},
{LOCALE_frFR, "|cffc3dbff [AutoBalance]|r|cffFF8000 Le combat est terminé. La difficulté n'est plus verrouillée.|r"},
{LOCALE_deDE, "|cffc3dbff [AutoBalance]|r|cffFF8000 Der Kampf ist vorbei. Die Schwierigkeit ist nicht mehr gesperrt.|r"},
{LOCALE_zhCN, "|cffc3dbff [AutoBalance]|r|cffFF8000 战斗结束了。难度不再被锁定。|r"},
{LOCALE_zhTW, "|cffc3dbff [AutoBalance]|r|cffFF8000 戰鬥已結束。難度不再被鎖定。|r"},
{LOCALE_esES, "|cffc3dbff [AutoBalance]|r|cffFF8000 El combate ha terminado. La dificultad ya no está bloqueada.|r"},
{LOCALE_esMX, "|cffc3dbff [AutoBalance]|r|cffFF8000 El combate ha terminado. La dificultad ya no está bloqueada.|r"},
{LOCALE_ruRU, "|cffc3dbff [AutoBalance]|r|cffFF8000 Бой окончен. Сложность больше не заблокирована.|r"},
};
std::unordered_map<std::string, const std::unordered_map<LocaleConstant, std::string>*> abTextMaps = {
{"welcome_to_player", &AB_WELCOME_TO_PLAYER},
{"welcome_to_gm", &AB_WELCOME_TO_GM},
{"announce_non_gm_entering_instance", &AB_ANNOUNCE_NON_GM_ENTERING_INSTANCE},
{"leaving_instance_combat", &AB_LEAVING_INSTANCE_COMBAT},
{"leaving_instance", &AB_LEAVING_INSTANCE},
{"set_offset_command_description", &AB_SET_OFFSET_COMMAND_DESCRIPTION},
{"set_offset_command_success", &AB_SET_OFFSET_COMMAND_SUCCESS},
{"set_offset_command_error", &AB_SET_OFFSET_COMMAND_ERROR},
{"get_offset_command_success", &AB_GET_OFFSET_COMMAND_SUCCESS},
{"adjusted_player_count_combat_locked", &AB_ADJUSTED_PLAYER_COUNT_COMBAT_LOCKED},
{"adjusted_player_count_map_minimum", &AB_ADJUSTED_PLAYER_COUNT_MAP_MINIMUM},
{"adjusted_player_count_map_minimum_difficulty_offset", &AB_ADJUSTED_PLAYER_COUNT_MAP_MINIMUM_DIFFICULTY_OFFSET},
{"adjusted_player_count_difficulty_offset", &AB_ADJUSTED_PLAYER_COUNT_DIFFICULTY_OFFSET},
{"adjusted_player_count", &AB_ADJUSTED_PLAYER_COUNT},
{"lfg_range", &AB_LFG_RANGE},
{"map_level", &AB_MAP_LEVEL},
{"level_scaling_enabled", &AB_LEVEL_SCALING_ENABLED},
{"level_scaling_disabled", &AB_LEVEL_SCALING_DISABLED},
{"world_health_multiplier", &AB_WORLD_HEALTH_MULTIPLIER},
{"world_hostile_damage_healing_multiplier_to", &AB_WORLD_HOSTILE_DAMAGE_HEALING_MULTIPLIER_TO},
{"world_hostile_damage_healing_multiplier", &AB_WORLD_HOSTILE_DAMAGE_HEALING_MULTIPLIER},
{"original_creature_level_range", &AB_ORIGINAL_CREATURE_LEVEL_RANGE},
{"active_total_creatures_in_map", &AB_ACTIVE_TOTAL_CREATURES_IN_MAP},
{"ab_command_only_in_instance", &AB_COMMAND_ONLY_IN_INSTANCE},
{"target_no_in_instance", &AB_TARGET_NO_IN_INSTANCE},
{"active_for_map_stats", &AB_ACTIVE_FOR_MAP_STATS},
{"ignored_for_map_stats", &AB_IGNORED_FOR_MAP_STATS},
{"creature_difficulty_level", &AB_CREATURE_DIFFICULTY_LEVEL},
{"clone_of_summon", &AB_CLONE_OF_SUMMON},
{"summon_of_summon", &AB_SUMMON_OF_SUMMON},
{"summon_without_summoner", &AB_SUMMON_WITHOUT_SUMMONER},
{"health_multiplier_to", &AB_HEALTH_MULTIPLIER_TO},
{"mana_multiplier_to", &AB_MANA_MULTIPLIER_TO},
{"armor_multiplier_to", &AB_ARMOR_MULTIPLIER_TO},
{"damage_multiplier_to", &AB_DAMAGE_MULTIPLIER_TO},
{"health_multiplier", &AB_HEALTH_MULTIPLIER},
{"mana_multiplier", &AB_MANA_MULTIPLIER},
{"armor_multiplier", &AB_ARMOR_MULTIPLIER},
{"damage_multiplier", &AB_DAMAGE_MULTIPLIER},
{"cc_duration_multiplier", &AB_CC_DURATION_MULTIPLIER},
{"xp_money_multiplier", &AB_XP_MONEY_MULTIPLIER},
{"leaving_instance_combat_change", &AB_LEAVING_INSTANCE_COMBAT_CHANGE},
};
std::string ABGetLocaleText(LocaleConstant locale, const std::string& titleType) {
auto textMapIt = abTextMaps.find(titleType);
if (textMapIt != abTextMaps.end())
{
const std::unordered_map<LocaleConstant, std::string>* textMap = textMapIt->second;
auto it = textMap->find(locale);
if (it != textMap->end())
return it->second;
}
return "";
}
+12
View File
@@ -0,0 +1,12 @@
// Message.h
#ifndef AB_MESSAGE_H
#define AB_MESSAGE_H
#include "Common.h"
#include "ItemTemplate.h"
#include <string>
std::string ABGetLocaleText(LocaleConstant locale, const std::string& titleType);
#endif // AB_MESSAGE_H