1623 lines
73 KiB
C++
1623 lines
73 KiB
C++
#include "ABAllCreatureScript.h"
|
|
|
|
#include "ABConfig.h"
|
|
#include "ABCreatureInfo.h"
|
|
#include "ABMapInfo.h"
|
|
#include "ABScriptMgr.h"
|
|
#include "ABUtils.h"
|
|
#include "AutoBalance.h"
|
|
|
|
#include "MapMgr.h"
|
|
|
|
void AutoBalance_AllCreatureScript::OnBeforeCreatureSelectLevel(const CreatureTemplate* /*creatureTemplate*/, Creature* creature, uint8& level)
|
|
{
|
|
Map* creatureMap = creature->GetMap();
|
|
|
|
if (creatureMap && creatureMap->IsDungeon())
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance:: ------------------------------------------------");
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnBeforeCreatureSelectLevel: Creature {} ({}) | Entry ID: ({}) | Spawn ID: ({})",
|
|
creature->GetName(),
|
|
level,
|
|
creature->GetEntry(),
|
|
creature->GetSpawnId()
|
|
);
|
|
|
|
// Create the new creature's AB info
|
|
AutoBalanceCreatureInfo* creatureABInfo = creature->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo");
|
|
|
|
// mark this creature as brand new so that only the level will be modified before creation
|
|
creatureABInfo->isBrandNew = true;
|
|
|
|
// if the creature already has a selectedLevel on it, we have already processed it and can re-use that value
|
|
if (creatureABInfo->selectedLevel)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnBeforeCreatureSelectLevel: Creature {} ({}) | has already been processed, using level {}.",
|
|
creature->GetName(),
|
|
creatureABInfo->UnmodifiedLevel,
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
|
|
level = creatureABInfo->selectedLevel;
|
|
return;
|
|
}
|
|
|
|
// Update the map's data if it is out of date (just before changing the map's creature list)
|
|
UpdateMapDataIfNeeded(creature->GetMap());
|
|
|
|
Map* creatureMap = creature->GetMap();
|
|
InstanceMap* instanceMap = creatureMap->ToInstanceMap();
|
|
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnBeforeCreatureSelectLevel: Creature {} ({}) | is in map {} ({}{}{}{})",
|
|
creature->GetName(),
|
|
level,
|
|
creatureMap->GetMapName(),
|
|
creatureMap->GetId(),
|
|
instanceMap ? "-" + std::to_string(instanceMap->GetInstanceId()) : "",
|
|
instanceMap ? ", " + std::to_string(instanceMap->GetMaxPlayers()) + "-player" : "",
|
|
instanceMap ? instanceMap->IsHeroic() ? " Heroic" : " Normal" : ""
|
|
);
|
|
|
|
// Set level originally intended for the creature
|
|
creatureABInfo->UnmodifiedLevel = level;
|
|
|
|
// add the creature to the map's tracking list
|
|
AddCreatureToMapCreatureList(creature);
|
|
|
|
// Update the map's data if it is out of date (just after changing the map's creature list)
|
|
UpdateMapDataIfNeeded(creature->GetMap());
|
|
|
|
// do an initial modification run of the creature, but don't update the level yet
|
|
ModifyCreatureAttributes(creature);
|
|
|
|
if (isCreatureRelevant(creature))
|
|
{
|
|
// set the new creature level
|
|
level = creatureABInfo->selectedLevel;
|
|
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnBeforeCreatureSelectLevel: Creature {} ({}) | will spawn in as level ({}).",
|
|
creature->GetName(),
|
|
creatureABInfo->UnmodifiedLevel,
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// don't change level value
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnBeforeCreatureSelectLevel: Creature {} ({}) | will spawn in at its original level ({}).",
|
|
creature->GetName(),
|
|
creatureABInfo->UnmodifiedLevel,
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AutoBalance_AllCreatureScript::OnCreatureSelectLevel(const CreatureTemplate* /* cinfo */, Creature* creature)
|
|
{
|
|
// ensure we're in a dungeon with a creature
|
|
if (
|
|
!creature ||
|
|
!creature->GetMap() ||
|
|
!creature->GetMap()->IsDungeon() ||
|
|
!creature->GetMap()->GetInstanceId()
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// get the creature's info
|
|
AutoBalanceCreatureInfo* creatureABInfo = creature->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo");
|
|
|
|
// If the creature is brand new, it needs more processing
|
|
if (creatureABInfo->isBrandNew)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance:: ------------------------------------------------");
|
|
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnCreatureSelectLevel: Creature {} ({}) | Entry ID: ({}) | Spawn ID: ({})",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
creature->GetEntry(),
|
|
creature->GetSpawnId()
|
|
);
|
|
|
|
if (creatureABInfo->isBrandNew)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnCreatureSelectLevel: Creature {} ({}) | is no longer brand new.",
|
|
creature->GetName(),
|
|
creature->GetLevel()
|
|
);
|
|
creatureABInfo->isBrandNew = false;
|
|
}
|
|
|
|
// Update the map's data if it is out of date
|
|
UpdateMapDataIfNeeded(creature->GetMap());
|
|
|
|
ModifyCreatureAttributes(creature);
|
|
|
|
// store the creature's max health value for validation in `OnCreatureAddWorld`
|
|
creatureABInfo->initialMaxHealth = creature->GetMaxHealth();
|
|
|
|
AutoBalanceCreatureInfo* creatureABInfo = creature->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo");
|
|
|
|
if (creature->GetLevel() != creatureABInfo->selectedLevel && isCreatureRelevant(creature))
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnCreatureSelectLevel: Creature {} ({}) | is set to level ({}).",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
creature->SetLevel(creatureABInfo->selectedLevel);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOG_ERROR("module.AutoBalance", "AutoBalance_AllCreatureScript::OnCreatureSelectLevel: Creature {} ({}) | is new to the instance but wasn't flagged as brand new. Please open an issue.",
|
|
creature->GetName(),
|
|
creature->GetLevel()
|
|
);
|
|
}
|
|
}
|
|
|
|
void AutoBalance_AllCreatureScript::OnCreatureAddWorld(Creature* creature)
|
|
{
|
|
if (creature->GetMap()->IsDungeon())
|
|
{
|
|
Map* creatureMap = creature->GetMap();
|
|
InstanceMap* instanceMap = creatureMap->ToInstanceMap();
|
|
AutoBalanceCreatureInfo* creatureABInfo = creature->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo");
|
|
|
|
// final checks on the creature before spawning
|
|
if (isCreatureRelevant(creature))
|
|
{
|
|
// level check
|
|
if (creature->GetLevel() != creatureABInfo->selectedLevel && !creature->IsSummon())
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnCreatureAddWorld: Creature {} ({}) | is set to level ({}) just after being added to the world.",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
creature->SetLevel(creatureABInfo->selectedLevel);
|
|
}
|
|
|
|
// max health check
|
|
if (creature->GetMaxHealth() != creatureABInfo->initialMaxHealth)
|
|
{
|
|
|
|
float oldMaxHealth = creature->GetMaxHealth();
|
|
float healthPct = creature->GetHealthPct();
|
|
creature->SetMaxHealth(creatureABInfo->initialMaxHealth);
|
|
creature->SetHealth(creature->GetMaxHealth() * (healthPct / 100));
|
|
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnCreatureAddWorld: Creature {} ({}) | had its max health changed from ({})->({}) just after being added to the world.",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
oldMaxHealth,
|
|
creatureABInfo->initialMaxHealth
|
|
);
|
|
}
|
|
}
|
|
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnCreatureAddWorld: Creature {} ({}) | added to map {} ({}{}{}{})",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
creatureMap->GetMapName(),
|
|
creatureMap->GetId(),
|
|
instanceMap ? "-" + std::to_string(instanceMap->GetInstanceId()) : "",
|
|
instanceMap ? ", " + std::to_string(instanceMap->GetMaxPlayers()) + "-player" : "",
|
|
instanceMap ? instanceMap->IsHeroic() ? " Heroic" : " Normal" : ""
|
|
);
|
|
}
|
|
}
|
|
|
|
void AutoBalance_AllCreatureScript::OnCreatureRemoveWorld(Creature* creature)
|
|
{
|
|
if (creature->GetMap()->IsDungeon())
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance:: ------------------------------------------------");
|
|
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnCreatureRemoveWorld: Creature {} ({}) | Entry ID: ({}) | Spawn ID: ({})",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
creature->GetEntry(),
|
|
creature->GetSpawnId()
|
|
|
|
);
|
|
|
|
InstanceMap* instanceMap = creature->GetMap()->ToInstanceMap();
|
|
Map* map = sMapMgr->FindBaseMap(creature->GetMapId());
|
|
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnCreatureRemoveWorld: Creature {} ({}) | removed from map {} ({}{}{}{})",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
map->GetMapName(),
|
|
map->GetId(),
|
|
instanceMap ? "-" + std::to_string(instanceMap->GetInstanceId()) : "",
|
|
instanceMap ? ", " + std::to_string(instanceMap->GetMaxPlayers()) + "-player" : "",
|
|
instanceMap ? instanceMap->IsHeroic() ? " Heroic" : " Normal" : ""
|
|
);
|
|
|
|
// remove the creature from the map's tracking list, if present
|
|
RemoveCreatureFromMapData(creature);
|
|
}
|
|
}
|
|
|
|
void AutoBalance_AllCreatureScript::OnAllCreatureUpdate(Creature* creature, uint32 /*diff*/)
|
|
{
|
|
// ensure we're in a dungeon with a creature
|
|
if (
|
|
!creature ||
|
|
!creature->GetMap() ||
|
|
!creature->GetMap()->IsDungeon() ||
|
|
!creature->GetMap()->GetInstanceId()
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// update map data before making creature changes
|
|
UpdateMapDataIfNeeded(creature->GetMap());
|
|
|
|
// If the config is out of date and the creature was reset, run modify against it
|
|
if (ResetCreatureIfNeeded(creature))
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance:: ------------------------------------------------");
|
|
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnAllCreatureUpdate: Creature {} ({}) | Entry ID: ({}) | Spawn ID: ({})",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
creature->GetEntry(),
|
|
creature->GetSpawnId()
|
|
);
|
|
|
|
// Update the map's data if it is out of date
|
|
UpdateMapDataIfNeeded(creature->GetMap());
|
|
|
|
ModifyCreatureAttributes(creature);
|
|
|
|
AutoBalanceCreatureInfo* creatureABInfo = creature->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo");
|
|
|
|
if (creature->GetLevel() != creatureABInfo->selectedLevel && isCreatureRelevant(creature))
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::OnAllCreatureUpdate: Creature {} ({}) | is set to level ({}).",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
creature->SetLevel(creatureABInfo->selectedLevel);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reset the passed creature to stock if the config has changed
|
|
bool AutoBalance_AllCreatureScript::ResetCreatureIfNeeded(Creature* creature)
|
|
{
|
|
// make sure we have a creature
|
|
if (!creature || !isCreatureRelevant(creature))
|
|
return false;
|
|
|
|
// get (or create) map and creature info
|
|
AutoBalanceMapInfo* mapABInfo = GetMapInfo(creature->GetMap());
|
|
AutoBalanceCreatureInfo* creatureABInfo = creature->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo");
|
|
|
|
// if creature is dead and mapConfigTime is 0, skip for now
|
|
if (creature->isDead() && creatureABInfo->mapConfigTime == 1)
|
|
return false;
|
|
// if the creature is dead but mapConfigTime is NOT 0, we set it to 0 so that it will be recalculated if revived
|
|
// also remember that this creature was once alive but is now dead
|
|
else if (creature->isDead())
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance:: ------------------------------------------------");
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ResetCreatureIfNeeded: Creature {} ({}) | is dead and mapConfigTime is not 0 - prime for reset if revived.", creature->GetName(), creature->GetLevel());
|
|
creatureABInfo->mapConfigTime = 1;
|
|
creatureABInfo->wasAliveNowDead = true;
|
|
return false;
|
|
}
|
|
|
|
// if the config is outdated, reset the creature
|
|
if (creatureABInfo->mapConfigTime < mapABInfo->mapConfigTime)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance:: ------------------------------------------------");
|
|
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ResetCreatureIfNeeded: Creature {} ({}) | Entry ID: ({}) | Spawn ID: ({})",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
creature->GetEntry(),
|
|
creature->GetSpawnId()
|
|
);
|
|
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ResetCreatureIfNeeded: Creature {} ({}) | Map config time is out of date ({} < {}). Resetting creature before modify.",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
creatureABInfo->mapConfigTime,
|
|
mapABInfo->mapConfigTime
|
|
);
|
|
|
|
// retain some values
|
|
uint8 unmodifiedLevel = creatureABInfo->UnmodifiedLevel;
|
|
bool isActive = creatureABInfo->isActive;
|
|
bool wasAliveNowDead = creatureABInfo->wasAliveNowDead;
|
|
bool isInCreatureList = creatureABInfo->isInCreatureList;
|
|
|
|
// reset AutoBalance modifiers
|
|
creature->CustomData.Erase("AutoBalanceCreatureInfo");
|
|
AutoBalanceCreatureInfo* creatureABInfo = creature->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo");
|
|
|
|
// grab the creature's template and the original creature's stats
|
|
CreatureTemplate const* creatureTemplate = creature->GetCreatureTemplate();
|
|
|
|
// set the creature's level
|
|
if (creature->GetLevel() != unmodifiedLevel)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ResetCreatureIfNeeded: Creature {} ({}) | is set to level ({}).",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
unmodifiedLevel
|
|
);
|
|
creature->SetLevel(unmodifiedLevel);
|
|
creature->UpdateAllStats();
|
|
}
|
|
else
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ResetCreatureIfNeeded: Creature {} ({}) | is already set to level ({}).",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
unmodifiedLevel
|
|
);
|
|
}
|
|
|
|
// get the creature's base stats
|
|
CreatureBaseStats const* origCreatureBaseStats = sObjectMgr->GetCreatureBaseStats(unmodifiedLevel, creatureTemplate->unit_class);
|
|
|
|
// health
|
|
float currentHealthPercent = (float)creature->GetHealth() / (float)creature->GetMaxHealth();
|
|
creature->SetMaxHealth(origCreatureBaseStats->GenerateHealth(creatureTemplate));
|
|
creature->SetHealth((float)origCreatureBaseStats->GenerateHealth(creatureTemplate) * currentHealthPercent);
|
|
|
|
// mana
|
|
if (creature->getPowerType() == POWER_MANA && creature->GetPower(POWER_MANA) >= 0 && creature->GetMaxPower(POWER_MANA) > 0)
|
|
{
|
|
float currentManaPercent = creature->GetPower(POWER_MANA) / creature->GetMaxPower(POWER_MANA);
|
|
creature->SetMaxPower(POWER_MANA, origCreatureBaseStats->GenerateMana(creatureTemplate));
|
|
creature->SetPower(POWER_MANA, creature->GetMaxPower(POWER_MANA) * currentManaPercent);
|
|
}
|
|
|
|
// armor
|
|
creature->SetArmor(origCreatureBaseStats->GenerateArmor(creatureTemplate));
|
|
|
|
// restore the saved data
|
|
creatureABInfo->UnmodifiedLevel = unmodifiedLevel;
|
|
creatureABInfo->isActive = isActive;
|
|
creatureABInfo->wasAliveNowDead = wasAliveNowDead;
|
|
creatureABInfo->isInCreatureList = isInCreatureList;
|
|
|
|
// damage and ccduration are handled using AutoBalanceCreatureInfo data only
|
|
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ResetCreatureIfNeeded: Creature {} ({}) is reset to its original stats.",
|
|
creature->GetName(),
|
|
creature->GetLevel()
|
|
);
|
|
|
|
// return true to indicate that the creature was reset
|
|
return true;
|
|
}
|
|
|
|
// creature was not reset, return false
|
|
return false;
|
|
|
|
}
|
|
|
|
void AutoBalance_AllCreatureScript::ModifyCreatureAttributes(Creature* creature)
|
|
{
|
|
// make sure we have a creature
|
|
if (!creature)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: creature is null.");
|
|
return;
|
|
}
|
|
|
|
// grab creature and map data
|
|
AutoBalanceCreatureInfo* creatureABInfo = creature->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo");
|
|
Map* map = creature->GetMap();
|
|
InstanceMap* instanceMap = map->ToInstanceMap();
|
|
AutoBalanceMapInfo* mapABInfo = GetMapInfo(instanceMap);
|
|
|
|
// mark the creature as updated using the current settings if needed
|
|
// if this creature is brand new, do not update this so that it will be re-processed next OnCreatureUpdate
|
|
if (creatureABInfo->mapConfigTime < mapABInfo->mapConfigTime && !creatureABInfo->isBrandNew)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | Map config time set to ({}).",
|
|
creature->GetName(),
|
|
creature->GetLevel(),
|
|
mapABInfo->mapConfigTime
|
|
);
|
|
creatureABInfo->mapConfigTime = mapABInfo->mapConfigTime;
|
|
}
|
|
|
|
// check to make sure that the creature's map is enabled for scaling
|
|
if (!mapABInfo->enabled)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | is in map {} ({}{}{}{}) that is not enabled, not changed.",
|
|
creature->GetName(),
|
|
creatureABInfo->UnmodifiedLevel,
|
|
map->GetMapName(),
|
|
map->GetId(),
|
|
instanceMap ? "-" + std::to_string(instanceMap->GetInstanceId()) : "",
|
|
instanceMap ? ", " + std::to_string(instanceMap->GetMaxPlayers()) + "-player" : "",
|
|
instanceMap ? instanceMap->IsHeroic() ? " Heroic" : " Normal" : ""
|
|
);
|
|
|
|
// return the creature back to their original level, if it's not already
|
|
creatureABInfo->selectedLevel = creatureABInfo->UnmodifiedLevel;
|
|
|
|
return;
|
|
}
|
|
|
|
// if the creature isn't relevant, don't modify it
|
|
if (!isCreatureRelevant(creature))
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | is not relevant, not changed.",
|
|
creature->GetName(),
|
|
creatureABInfo->UnmodifiedLevel
|
|
);
|
|
|
|
// return the creature back to their original level, if it's not already
|
|
creatureABInfo->selectedLevel = creatureABInfo->UnmodifiedLevel;
|
|
|
|
return;
|
|
}
|
|
|
|
// if this creature is below 85% of the minimum LFG level for the map, make no changes
|
|
// if this creature is above 115% of the maximum LFG level for the map, make no changes
|
|
// if this is a critter that is substantial enough to be considered a real enemy, still modify it
|
|
// if this is a trigger, still modify it
|
|
if (
|
|
(
|
|
(creatureABInfo->UnmodifiedLevel < (uint8)(((float)mapABInfo->lfgMinLevel * .85f) + 0.5f)) ||
|
|
(creatureABInfo->UnmodifiedLevel > (uint8)(((float)mapABInfo->lfgMaxLevel * 1.15f) + 0.5f))
|
|
) &&
|
|
(
|
|
!(creature->IsCritter() && creatureABInfo->UnmodifiedLevel >= 5 && creature->GetMaxHealth() > 100) &&
|
|
!creature->IsTrigger()
|
|
)
|
|
)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | is a {} outside of the expected NPC level range for the map ({} to {}), not modified.",
|
|
creature->GetName(),
|
|
creatureABInfo->UnmodifiedLevel,
|
|
creature->IsCritter() ? "critter" : "creature",
|
|
(uint8)(((float)mapABInfo->lfgMinLevel * .85f) + 0.5f),
|
|
(uint8)(((float)mapABInfo->lfgMaxLevel * 1.15f) + 0.5f)
|
|
);
|
|
|
|
creatureABInfo->selectedLevel = creatureABInfo->UnmodifiedLevel;
|
|
|
|
return;
|
|
}
|
|
|
|
// if the creature was dead (but this function is being called because they are being revived), reset it and allow modifications
|
|
if (creatureABInfo->wasAliveNowDead)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | was dead but appears to be alive now, reset wasAliveNowDead flag.", creature->GetName(), creatureABInfo->UnmodifiedLevel);
|
|
// if the creature was dead, reset it
|
|
creatureABInfo->wasAliveNowDead = false;
|
|
}
|
|
// if the creature is dead and wasn't marked as dead by this script, simply skip
|
|
else if (creature->isDead())
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | is dead, do not modify.", creature->GetName(), creatureABInfo->UnmodifiedLevel);
|
|
return;
|
|
}
|
|
|
|
CreatureTemplate const* creatureTemplate = creature->GetCreatureTemplate();
|
|
|
|
// check to see if the creature is in the forced num players list
|
|
uint32 forcedNumPlayers = GetForcedNumPlayers(creatureTemplate->Entry);
|
|
|
|
if (forcedNumPlayers == 0)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | is in the forced num players list with a value of 0, not changed.", creature->GetName(), creatureABInfo->UnmodifiedLevel);
|
|
return; // forcedNumPlayers 0 means that the creature is contained in DisabledID -> no scaling
|
|
}
|
|
|
|
// start with the map's adjusted player count
|
|
uint32 adjustedPlayerCount = mapABInfo->adjustedPlayerCount;
|
|
|
|
// if the forced value is set and the adjusted player count is above the forced value, change it to match
|
|
if (forcedNumPlayers > 0 && adjustedPlayerCount > forcedNumPlayers)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | is in the forced num players list with a value of {}, adjusting adjustedPlayerCount to match.", creature->GetName(), creatureABInfo->UnmodifiedLevel, forcedNumPlayers);
|
|
adjustedPlayerCount = forcedNumPlayers;
|
|
}
|
|
|
|
// store the current player count in the creature and map's data
|
|
creatureABInfo->instancePlayerCount = adjustedPlayerCount;
|
|
|
|
if (!creatureABInfo->instancePlayerCount) // no players in map, do not modify attributes
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | is on a map with no players, not changed.", creature->GetName(), creatureABInfo->UnmodifiedLevel);
|
|
return;
|
|
}
|
|
|
|
if (!sABScriptMgr->OnBeforeModifyAttributes(creature, creatureABInfo->instancePlayerCount))
|
|
return;
|
|
|
|
// only scale levels if level scaling is enabled and the instance's average creature level is not within the skip range
|
|
if
|
|
(
|
|
LevelScaling &&
|
|
(
|
|
(mapABInfo->avgCreatureLevel > mapABInfo->highestPlayerLevel + mapABInfo->levelScalingSkipHigherLevels || mapABInfo->levelScalingSkipHigherLevels == 0) ||
|
|
(mapABInfo->avgCreatureLevel < mapABInfo->highestPlayerLevel - mapABInfo->levelScalingSkipLowerLevels || mapABInfo->levelScalingSkipLowerLevels == 0)
|
|
) &&
|
|
!creatureABInfo->neverLevelScale
|
|
)
|
|
{
|
|
uint8 selectedLevel;
|
|
|
|
// handle "special" creatures
|
|
// note that these already passed a more complex check above
|
|
if (
|
|
(creature->IsTotem() && creature->IsSummon() && creatureABInfo->summoner && creatureABInfo->summoner->IsPlayer()) ||
|
|
(
|
|
creature->IsCritter() && creatureABInfo->UnmodifiedLevel <= 5 && creature->GetMaxHealth() <= 100
|
|
)
|
|
)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | is a {} that will not be level scaled, but will have modifiers set.",
|
|
creature->GetName(),
|
|
creatureABInfo->UnmodifiedLevel,
|
|
creature->IsTotem() ? "totem" : "critter"
|
|
);
|
|
|
|
selectedLevel = creatureABInfo->UnmodifiedLevel;
|
|
}
|
|
// if we're using dynamic scaling, calculate the creature's level based relative to the highest player level in the map
|
|
else if (LevelScalingMethod == AUTOBALANCE_SCALING_DYNAMIC)
|
|
{
|
|
// calculate the creature's new level
|
|
selectedLevel = (mapABInfo->highestPlayerLevel + mapABInfo->levelScalingDynamicCeiling) - (mapABInfo->highestCreatureLevel - creatureABInfo->UnmodifiedLevel);
|
|
|
|
// check to be sure that the creature's new level is at least the dynamic scaling floor
|
|
if (selectedLevel < (mapABInfo->highestPlayerLevel - mapABInfo->levelScalingDynamicFloor))
|
|
selectedLevel = mapABInfo->highestPlayerLevel - mapABInfo->levelScalingDynamicFloor;
|
|
|
|
// check to be sure that the creature's new level is no higher than the dynamic scaling ceiling
|
|
if (selectedLevel > (mapABInfo->highestPlayerLevel + mapABInfo->levelScalingDynamicCeiling))
|
|
selectedLevel = mapABInfo->highestPlayerLevel + mapABInfo->levelScalingDynamicCeiling;
|
|
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaled to level ({}) via dynamic scaling.",
|
|
creature->GetName(),
|
|
creatureABInfo->UnmodifiedLevel,
|
|
selectedLevel
|
|
);
|
|
}
|
|
// otherwise we're using "fixed" scaling and should use the highest player level in the map
|
|
else
|
|
{
|
|
selectedLevel = mapABInfo->highestPlayerLevel;
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaled to level ({}) via fixed scaling.", creature->GetName(), creatureABInfo->UnmodifiedLevel, selectedLevel);
|
|
}
|
|
|
|
creatureABInfo->selectedLevel = selectedLevel;
|
|
|
|
if (creature->GetLevel() != selectedLevel)
|
|
{
|
|
if (!creatureABInfo->isBrandNew)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | is set to new selectedLevel ({}).",
|
|
creature->GetName(),
|
|
creatureABInfo->UnmodifiedLevel,
|
|
selectedLevel
|
|
);
|
|
|
|
creature->SetLevel(selectedLevel);
|
|
}
|
|
}
|
|
}
|
|
else if (!LevelScaling)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | not level scaled due to level scaling being disabled.", creature->GetName(), creatureABInfo->UnmodifiedLevel);
|
|
creatureABInfo->selectedLevel = creatureABInfo->UnmodifiedLevel;
|
|
}
|
|
else if (creatureABInfo->neverLevelScale)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | not level scaled due to being marked as multipliers only.", creature->GetName(), creatureABInfo->UnmodifiedLevel);
|
|
creatureABInfo->selectedLevel = creatureABInfo->UnmodifiedLevel;
|
|
}
|
|
else
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | not level scaled due the instance's average creature level being inside the skip range.", creature->GetName(), creatureABInfo->UnmodifiedLevel);
|
|
creatureABInfo->selectedLevel = creatureABInfo->UnmodifiedLevel;
|
|
}
|
|
|
|
if (creatureABInfo->isBrandNew)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | is brand new, do not modify level or stats yet.",
|
|
creature->GetName(),
|
|
creatureABInfo->UnmodifiedLevel
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
CreatureBaseStats const* origCreatureBaseStats = sObjectMgr->GetCreatureBaseStats(creatureABInfo->UnmodifiedLevel, creatureTemplate->unit_class);
|
|
CreatureBaseStats const* newCreatureBaseStats = sObjectMgr->GetCreatureBaseStats(creatureABInfo->selectedLevel, creatureTemplate->unit_class);
|
|
|
|
// Inflection Point
|
|
AutoBalanceInflectionPointSettings inflectionPointSettings = getInflectionPointSettings(instanceMap, isBossOrBossSummon(creature));
|
|
|
|
// Generate the default multiplier
|
|
float defaultMultiplier = getDefaultMultiplier(instanceMap, inflectionPointSettings);
|
|
|
|
if (!sABScriptMgr->OnAfterDefaultMultiplier(creature, defaultMultiplier))
|
|
return;
|
|
|
|
// Stat Modifiers
|
|
AutoBalanceStatModifiers statModifiers = getStatModifiers(map, creature);
|
|
float statMod_global = statModifiers.global;
|
|
float statMod_health = statModifiers.health;
|
|
float statMod_mana = statModifiers.mana;
|
|
float statMod_armor = statModifiers.armor;
|
|
float statMod_damage = statModifiers.damage;
|
|
float statMod_ccDuration = statModifiers.ccduration;
|
|
|
|
// Storage for the final values applied to the creature
|
|
uint32 newFinalHealth = 0;
|
|
uint32 newFinalMana = 0;
|
|
uint32 newFinalArmor = 0;
|
|
|
|
//
|
|
// Health Scaling
|
|
//
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | ---------- HEALTH MULTIPLIER ----------",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
|
|
float healthMultiplier = defaultMultiplier * statMod_global * statMod_health;
|
|
float scaledHealthMultiplier;
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | HealthMultiplier: ({}) = defaultMultiplier ({}) * statMod_global ({}) * statMod_health ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
healthMultiplier,
|
|
defaultMultiplier,
|
|
statMod_global,
|
|
statMod_health
|
|
);
|
|
|
|
// Can't be less than MinHPModifier
|
|
if (healthMultiplier <= MinHPModifier)
|
|
{
|
|
healthMultiplier = MinHPModifier;
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | HealthMultiplier: ({}) - capped to MinHPModifier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
healthMultiplier,
|
|
MinHPModifier
|
|
);
|
|
}
|
|
|
|
// set the non-level-scaled health multiplier on the creature's AB info
|
|
creatureABInfo->HealthMultiplier = healthMultiplier;
|
|
|
|
// only level scale health if level scaling is enabled and the creature level has been altered
|
|
if (LevelScaling && creatureABInfo->selectedLevel != creatureABInfo->UnmodifiedLevel)
|
|
{
|
|
// the max health that the creature had before we did anything with it
|
|
float origHealth = origCreatureBaseStats->GenerateHealth(creatureTemplate);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | origHealth ({}) = origCreatureBaseStats->GenerateHealth(creatureTemplate)",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
origHealth
|
|
);
|
|
|
|
// the base health of the new creature level for this creature's class
|
|
// uses a custom smoothing formula to smooth transitions between expansions
|
|
float newBaseHealth = getBaseExpansionValueForLevel(newCreatureBaseStats->BaseHealth, mapABInfo->highestPlayerLevel);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newBaseHealth ({}) = getBaseExpansionValueForLevel(newCreatureBaseStats->BaseHealth, mapABInfo->highestPlayerLevel ({}))",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newBaseHealth,
|
|
mapABInfo->highestPlayerLevel
|
|
);
|
|
|
|
// the health of the creature at its new level (before per-player scaling)
|
|
float newHealth = newBaseHealth * creatureTemplate->ModHealth;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newHealth ({}) = newBaseHealth ({}) * creature ModHealth ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newHealth,
|
|
newBaseHealth,
|
|
creatureTemplate->ModHealth
|
|
);
|
|
|
|
// the multiplier that would need to be applied to the creature's original health to get the new level's health (before per-player scaling)
|
|
float newHealthMultiplier = newHealth / origHealth;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newHealthMultiplier ({}) = newHealth ({}) / origHealth ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newHealthMultiplier,
|
|
newHealth,
|
|
origHealth
|
|
);
|
|
|
|
// the multiplier that would need to be applied to the creature's original health to get the new level's health (after per-player scaling)
|
|
scaledHealthMultiplier = healthMultiplier * newHealthMultiplier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledHealthMultiplier ({}) = healthMultiplier ({}) * newHealthMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledHealthMultiplier,
|
|
healthMultiplier,
|
|
newHealthMultiplier
|
|
);
|
|
|
|
// the actual health value to be applied to the level-scaled and player-scaled creature
|
|
newFinalHealth = round(origHealth * scaledHealthMultiplier);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newFinalHealth ({}) = origHealth ({}) * scaledHealthMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newFinalHealth,
|
|
origHealth,
|
|
scaledHealthMultiplier
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// the non-level-scaled health multiplier is the same as the level-scaled health multiplier
|
|
scaledHealthMultiplier = healthMultiplier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledHealthMultiplier ({}) = healthMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledHealthMultiplier,
|
|
healthMultiplier
|
|
);
|
|
|
|
// the original health of the creature
|
|
uint32 origHealth = origCreatureBaseStats->GenerateHealth(creatureTemplate);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | origHealth ({}) = origCreatureBaseStats->GenerateHealth(creatureTemplate)",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
origHealth
|
|
);
|
|
|
|
// the actual health value to be applied to the player-scaled creature
|
|
newFinalHealth = round(origHealth * creatureABInfo->HealthMultiplier);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newFinalHealth ({}) = origHealth ({}) * HealthMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newFinalHealth,
|
|
origHealth,
|
|
creatureABInfo->HealthMultiplier
|
|
);
|
|
}
|
|
|
|
//
|
|
// Mana Scaling
|
|
//
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | ---------- MANA MULTIPLIER ----------",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
|
|
float manaMultiplier = defaultMultiplier * statMod_global * statMod_mana;
|
|
float scaledManaMultiplier;
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | ManaMultiplier: ({}) = defaultMultiplier ({}) * statMod_global ({}) * statMod_mana ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
manaMultiplier,
|
|
defaultMultiplier,
|
|
statMod_global,
|
|
statMod_mana
|
|
);
|
|
|
|
// Can't be less than MinManaModifier
|
|
if (manaMultiplier <= MinManaModifier)
|
|
{
|
|
manaMultiplier = MinManaModifier;
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | ManaMultiplier: ({}) - capped to MinManaModifier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
manaMultiplier,
|
|
MinManaModifier
|
|
);
|
|
}
|
|
|
|
// if the creature doesn't have mana, set the multiplier to 0.0
|
|
if (!origCreatureBaseStats->GenerateMana(creatureTemplate))
|
|
{
|
|
manaMultiplier = 0.0f;
|
|
creatureABInfo->ManaMultiplier = 0.0f;
|
|
scaledManaMultiplier = 0.0f;
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | Creature doesn't have mana, multiplier set to ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
creatureABInfo->ManaMultiplier
|
|
);
|
|
}
|
|
// if the creature has mana, continue calculations
|
|
else
|
|
{
|
|
// set the non-level-scaled mana multiplier on the creature's AB info
|
|
creatureABInfo->ManaMultiplier = manaMultiplier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | ManaMultiplier: ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
creatureABInfo->ManaMultiplier
|
|
);
|
|
|
|
// only level scale mana if level scaling is enabled and the creature level has been altered
|
|
if (LevelScaling && creatureABInfo->selectedLevel != creatureABInfo->UnmodifiedLevel)
|
|
{
|
|
// the max mana that the creature had before we did anything with it
|
|
uint32 origMana = origCreatureBaseStats->GenerateMana(creatureTemplate);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | origMana ({}) = origCreatureBaseStats->GenerateMana(creatureTemplate)",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
origMana
|
|
);
|
|
|
|
// the max mana that the creature would have at its new level
|
|
// there is no per-expansion adjustment for mana
|
|
uint32 newMana = newCreatureBaseStats->GenerateMana(creatureTemplate);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newMana ({}) = newCreatureBaseStats->GenerateMana(creatureTemplate)",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newMana
|
|
);
|
|
|
|
// the multiplier that would need to be applied to the creature's original mana to get the new level's mana (before per-player scaling)
|
|
float newManaMultiplier = (float)newMana / (float)origMana;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newManaMultiplier ({}) = newMana ({}) / origMana ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newManaMultiplier,
|
|
newMana,
|
|
origMana
|
|
);
|
|
|
|
// the multiplier that would need to be applied to the creature's original mana to get the new level's mana (after per-player scaling)
|
|
scaledManaMultiplier = manaMultiplier * newManaMultiplier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledManaMultiplier ({}) = manaMultiplier ({}) * newManaMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledManaMultiplier,
|
|
manaMultiplier,
|
|
newManaMultiplier
|
|
);
|
|
|
|
// the actual mana value to be applied to the level-scaled and player-scaled creature
|
|
newFinalMana = round(origMana * scaledManaMultiplier);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newFinalMana ({}) = origMana ({}) * scaledManaMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newFinalMana,
|
|
origMana,
|
|
scaledManaMultiplier
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// scaled mana multiplier is the same as the non-level-scaled mana multiplier
|
|
scaledManaMultiplier = manaMultiplier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledManaMultiplier ({}) = manaMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledManaMultiplier,
|
|
manaMultiplier
|
|
);
|
|
|
|
// the original mana of the creature
|
|
uint32 origMana = origCreatureBaseStats->GenerateMana(creatureTemplate);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | origMana ({}) = origCreatureBaseStats->GenerateMana(creatureTemplate)",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
origMana
|
|
);
|
|
|
|
// the actual mana value to be applied to the player-scaled creature
|
|
newFinalMana = round(origMana * creatureABInfo->ManaMultiplier);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newFinalMana ({}) = origMana ({}) * creatureABInfo->ManaMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newFinalMana,
|
|
origMana,
|
|
creatureABInfo->ManaMultiplier
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Armor Scaling
|
|
//
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | ---------- ARMOR MULTIPLIER ----------",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
|
|
float armorMultiplier = defaultMultiplier * statMod_global * statMod_armor;
|
|
float scaledArmorMultiplier;
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | armorMultiplier: ({}) = defaultMultiplier ({}) * statMod_global ({}) * statMod_armor ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
armorMultiplier,
|
|
defaultMultiplier,
|
|
statMod_global,
|
|
statMod_armor
|
|
);
|
|
|
|
// set the non-level-scaled armor multiplier on the creature's AB info
|
|
creatureABInfo->ArmorMultiplier = armorMultiplier;
|
|
|
|
// only level scale armor if level scaling is enabled and the creature level has been altered
|
|
if (LevelScaling && creatureABInfo->selectedLevel != creatureABInfo->UnmodifiedLevel)
|
|
{
|
|
// the armor that the creature had before we did anything with it
|
|
uint32 origArmor = origCreatureBaseStats->GenerateArmor(creatureTemplate);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | origArmor ({}) = origCreatureBaseStats->GenerateArmor(creatureTemplate)",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
origArmor
|
|
);
|
|
|
|
// the armor that the creature would have at its new level
|
|
// there is no per-expansion adjustment for armor
|
|
uint32 newArmor = newCreatureBaseStats->GenerateArmor(creatureTemplate);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newArmor ({}) = newCreatureBaseStats->GenerateArmor(creatureTemplate)",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newArmor
|
|
);
|
|
|
|
// the multiplier that would need to be applied to the creature's original armor to get the new level's armor (before per-player scaling)
|
|
float newArmorMultiplier = (float)newArmor / (float)origArmor;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newArmorMultiplier ({}) = newArmor ({}) / origArmor ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newArmorMultiplier,
|
|
newArmor,
|
|
origArmor
|
|
);
|
|
|
|
// the multiplier that would need to be applied to the creature's original armor to get the new level's armor (after per-player scaling)
|
|
scaledArmorMultiplier = armorMultiplier * newArmorMultiplier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledArmorMultiplier ({}) = armorMultiplier ({}) * newArmorMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledArmorMultiplier,
|
|
armorMultiplier,
|
|
newArmorMultiplier
|
|
);
|
|
|
|
// the actual armor value to be applied to the level-scaled and player-scaled creature
|
|
newFinalArmor = round(origArmor * scaledArmorMultiplier);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newFinalArmor ({}) = origArmor ({}) * scaledArmorMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newFinalArmor,
|
|
origArmor,
|
|
scaledArmorMultiplier
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// Scaled armor multiplier is the same as the non-level-scaled armor multiplier
|
|
scaledArmorMultiplier = armorMultiplier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledArmorMultiplier ({}) = armorMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledArmorMultiplier,
|
|
armorMultiplier
|
|
);
|
|
|
|
// the original armor of the creature
|
|
uint32 origArmor = origCreatureBaseStats->GenerateArmor(creatureTemplate);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | origArmor ({}) = origCreatureBaseStats->GenerateArmor(creatureTemplate)",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
origArmor
|
|
);
|
|
|
|
// the actual armor value to be applied to the player-scaled creature
|
|
newFinalArmor = round(origArmor * creatureABInfo->ArmorMultiplier);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newFinalArmor ({}) = origArmor ({}) * creatureABInfo->ArmorMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newFinalArmor,
|
|
origArmor,
|
|
creatureABInfo->ArmorMultiplier
|
|
);
|
|
}
|
|
|
|
//
|
|
// Damage Scaling
|
|
//
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | ---------- DAMAGE MULTIPLIER ----------",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
|
|
float damageMultiplier = defaultMultiplier * statMod_global * statMod_damage;
|
|
float scaledDamageMultiplier;
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | DamageMultiplier: ({}) = defaultMultiplier ({}) * statMod_global ({}) * statMod_damage ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
damageMultiplier,
|
|
defaultMultiplier,
|
|
statMod_global,
|
|
statMod_damage
|
|
);
|
|
|
|
// Can't be less than MinDamageModifier
|
|
if (damageMultiplier <= MinDamageModifier)
|
|
{
|
|
damageMultiplier = MinDamageModifier;
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | DamageMultiplier: ({}) - capped to MinDamageModifier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
damageMultiplier,
|
|
MinDamageModifier
|
|
);
|
|
}
|
|
|
|
// set the non-level-scaled damage multiplier on the creature's AB info
|
|
creatureABInfo->DamageMultiplier = damageMultiplier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | DamageMultiplier: ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
creatureABInfo->DamageMultiplier
|
|
);
|
|
|
|
// only level scale damage if level scaling is enabled and the creature level has been altered
|
|
if (LevelScaling && creatureABInfo->selectedLevel != creatureABInfo->UnmodifiedLevel)
|
|
{
|
|
|
|
// the original base damage of the creature
|
|
// note that we don't mess with the damage modifier here since it applied equally to the original and new levels
|
|
float origBaseDamage = origCreatureBaseStats->GenerateBaseDamage(creatureTemplate);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | origBaseDamage ({}) = origCreatureBaseStats->GenerateBaseDamage(creatureTemplate)",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
origBaseDamage
|
|
);
|
|
|
|
// the base damage of the new creature level for this creature's class
|
|
// uses a custom smoothing formula to smooth transitions between expansions
|
|
float newBaseDamage = getBaseExpansionValueForLevel(newCreatureBaseStats->BaseDamage, mapABInfo->highestPlayerLevel);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newBaseDamage ({}) = getBaseExpansionValueForLevel(newCreatureBaseStats->BaseDamage, mapABInfo->highestPlayerLevel ({}))",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newBaseDamage,
|
|
mapABInfo->highestPlayerLevel
|
|
);
|
|
|
|
// the multiplier that would need to be applied to the creature's original damage to get the new level's damage (before per-player scaling)
|
|
float newDamageMultiplier = newBaseDamage / origBaseDamage;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | newDamageMultiplier ({}) = newBaseDamage ({}) / origBaseDamage ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
newDamageMultiplier,
|
|
newBaseDamage,
|
|
origBaseDamage
|
|
);
|
|
|
|
// the actual multiplier that will be used to scale the creature's damage (after per-player scaling)
|
|
scaledDamageMultiplier = damageMultiplier * newDamageMultiplier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledDamageMultiplier ({}) = damageMultiplier ({}) * newDamageMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledDamageMultiplier,
|
|
damageMultiplier,
|
|
newDamageMultiplier
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// the scaled damage multiplier is the same as the non-level-scaled damage multiplier
|
|
scaledDamageMultiplier = damageMultiplier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledDamageMultiplier ({}) = damageMultiplier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledDamageMultiplier,
|
|
origCreatureBaseStats->GenerateBaseDamage(creatureTemplate),
|
|
damageMultiplier
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Crowd Control Debuff Duration Scaling
|
|
//
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | ---------- CC DURATION MULTIPLIER ----------",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
|
|
float ccDurationMultiplier;
|
|
|
|
if (statMod_ccDuration != -1.0f)
|
|
{
|
|
// calculate CC Duration from the default multiplier and the config settings
|
|
ccDurationMultiplier = defaultMultiplier * statMod_ccDuration;
|
|
|
|
// Min/Max checking
|
|
if (ccDurationMultiplier < MinCCDurationModifier)
|
|
ccDurationMultiplier = MinCCDurationModifier;
|
|
else if (ccDurationMultiplier > MaxCCDurationModifier)
|
|
ccDurationMultiplier = MaxCCDurationModifier;
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | ccDurationMultiplier: ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
ccDurationMultiplier
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// the CC Duration will not be changed
|
|
ccDurationMultiplier = 1.0f;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | Crowd Control Duration will not be changed.",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
}
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | ccDurationMultiplier: ({}) = defaultMultiplier ({}) * statMod_ccDuration ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
ccDurationMultiplier,
|
|
defaultMultiplier,
|
|
statMod_ccDuration
|
|
);
|
|
|
|
//
|
|
// Apply New Values
|
|
//
|
|
if (!sABScriptMgr->OnBeforeUpdateStats(creature, newFinalHealth, newFinalMana, damageMultiplier, newFinalArmor))
|
|
return;
|
|
|
|
uint32 prevMaxHealth = creature->GetMaxHealth();
|
|
uint32 prevMaxPower = creature->GetMaxPower(Powers::POWER_MANA);
|
|
uint32 prevHealth = creature->GetHealth();
|
|
uint32 prevPower = creature->GetPower(Powers::POWER_MANA);
|
|
|
|
uint32 prevPlayerDamageRequired = creature->GetPlayerDamageReq();
|
|
uint32 prevCreateHealth = creature->GetCreateHealth();
|
|
|
|
Powers pType = creature->getPowerType();
|
|
|
|
creature->SetArmor(newFinalArmor);
|
|
creature->SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, (float)newFinalArmor);
|
|
creature->SetCreateHealth(newFinalHealth);
|
|
creature->SetMaxHealth(newFinalHealth);
|
|
creature->ResetPlayerDamageReq();
|
|
creature->SetCreateMana(newFinalMana);
|
|
creature->SetMaxPower(Powers::POWER_MANA, newFinalMana);
|
|
creature->SetStatFlatModifier(UNIT_MOD_ENERGY, BASE_VALUE, (float)100.0f);
|
|
creature->SetStatFlatModifier(UNIT_MOD_RAGE, BASE_VALUE, (float)100.0f);
|
|
creature->SetStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, (float)newFinalHealth);
|
|
creature->SetStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, (float)newFinalMana);
|
|
creatureABInfo->ScaledHealthMultiplier = scaledHealthMultiplier;
|
|
creatureABInfo->ScaledManaMultiplier = scaledManaMultiplier;
|
|
creatureABInfo->ScaledArmorMultiplier = scaledArmorMultiplier;
|
|
creatureABInfo->ScaledDamageMultiplier = scaledDamageMultiplier;
|
|
creatureABInfo->CCDurationMultiplier = ccDurationMultiplier;
|
|
|
|
// adjust the current health as appropriate
|
|
uint32 scaledCurHealth = 0;
|
|
uint32 scaledCurPower = 0;
|
|
|
|
// if this is a summon and it's a clone of its summoner, keep the health and mana values of the summon
|
|
// only do this once, when `_isSummonCloneOfSummoner(creature)` returns true but !creatureABInfo->isCloneOfSummoner is false
|
|
if
|
|
(
|
|
creature->IsSummon() &&
|
|
_isSummonCloneOfSummoner(creature) &&
|
|
!creatureABInfo->isCloneOfSummoner
|
|
)
|
|
{
|
|
creatureABInfo->isCloneOfSummoner = true;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | Summon is a clone of its summoner, keeping health and mana values.",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
|
|
if (prevHealth && prevMaxHealth)
|
|
{
|
|
scaledCurHealth = prevHealth;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledCurHealth ({}) = prevHealth ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledCurHealth,
|
|
prevHealth
|
|
);
|
|
}
|
|
|
|
if (prevPower && prevMaxPower)
|
|
{
|
|
scaledCurPower = prevPower;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledCurPower ({}) = prevPower ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledCurPower,
|
|
prevPower
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (prevHealth && prevMaxHealth)
|
|
{
|
|
scaledCurHealth = float(newFinalHealth) / float(prevMaxHealth) * float(prevHealth);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledCurHealth ({}) = float(newFinalHealth) ({}) / float(prevMaxHealth) ({}) * float(prevHealth) ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledCurHealth,
|
|
newFinalHealth,
|
|
prevMaxHealth,
|
|
prevHealth
|
|
);
|
|
}
|
|
else
|
|
{
|
|
scaledCurHealth = 0;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledCurHealth ({}) = 0",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledCurHealth
|
|
);
|
|
}
|
|
|
|
if (prevPower && prevMaxPower)
|
|
{
|
|
scaledCurPower = float(newFinalMana) / float(prevMaxPower) * float(prevPower);
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledCurPower ({}) = float(newFinalMana) ({}) / float(prevMaxPower) ({}) * float(prevPower) ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledCurPower,
|
|
newFinalMana,
|
|
prevMaxPower,
|
|
prevPower
|
|
);
|
|
}
|
|
else
|
|
{
|
|
scaledCurPower = 0;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | scaledCurPower ({}) = 0",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
scaledCurPower
|
|
);
|
|
}
|
|
}
|
|
|
|
creature->SetHealth(scaledCurHealth);
|
|
if (pType == Powers::POWER_MANA)
|
|
creature->SetPower(Powers::POWER_MANA, scaledCurPower);
|
|
else
|
|
creature->setPowerType(pType); // fix creatures with different power types
|
|
|
|
uint32 playerDamageRequired = creature->GetPlayerDamageReq();
|
|
if (prevPlayerDamageRequired == 0)
|
|
{
|
|
// If already reached damage threshold for loot, drop to zero again
|
|
creature->LowerPlayerDamageReq(playerDamageRequired, true);
|
|
}
|
|
else
|
|
{
|
|
// Scale the damage requirements similar to creature HP scaling
|
|
uint32 scaledPlayerDmgReq = float(prevPlayerDamageRequired) * float(newFinalHealth) / float(prevCreateHealth);
|
|
// Do some math
|
|
creature->LowerPlayerDamageReq(playerDamageRequired - scaledPlayerDmgReq, true);
|
|
}
|
|
|
|
//
|
|
// Reward Scaling
|
|
//
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | ---------- REWARD SCALING ----------",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
|
|
// calculate the average multiplier after level scaling is applied
|
|
float avgHealthDamageMultipliers;
|
|
|
|
// only if one of the scaling options is enabled
|
|
if (RewardScalingXP || RewardScalingMoney)
|
|
{
|
|
// use health and damage to calculate the average multiplier
|
|
avgHealthDamageMultipliers = (scaledHealthMultiplier + scaledDamageMultiplier) / 2.0f;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | avgHealthDamageMultipliers ({}) = (scaledHealthMultiplier ({}) + scaledDamageMultiplier ({})) / 2.0f",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
avgHealthDamageMultipliers,
|
|
scaledHealthMultiplier,
|
|
scaledDamageMultiplier
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// Reward scaling is disabled
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | Reward scaling is disabled.",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
}
|
|
|
|
// XP Scaling
|
|
if (RewardScalingXP)
|
|
{
|
|
if (RewardScalingMethod == AUTOBALANCE_SCALING_FIXED)
|
|
{
|
|
creatureABInfo->XPModifier = RewardScalingXPModifier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | Fixed Mode: XPModifier ({}) = RewardScalingXPModifier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
creatureABInfo->XPModifier,
|
|
RewardScalingXPModifier
|
|
);
|
|
}
|
|
else if (RewardScalingMethod == AUTOBALANCE_SCALING_DYNAMIC)
|
|
{
|
|
creatureABInfo->XPModifier = avgHealthDamageMultipliers * RewardScalingXPModifier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | Dynamic Mode: XPModifier ({}) = avgHealthDamageMultipliers ({}) * RewardScalingXPModifier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
creatureABInfo->XPModifier,
|
|
avgHealthDamageMultipliers,
|
|
RewardScalingXPModifier
|
|
);
|
|
}
|
|
}
|
|
|
|
// Money Scaling
|
|
if (RewardScalingMoney)
|
|
{
|
|
|
|
if (RewardScalingMethod == AUTOBALANCE_SCALING_FIXED)
|
|
{
|
|
creatureABInfo->MoneyModifier = RewardScalingMoneyModifier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | Fixed Mode: MoneyModifier ({}) = RewardScalingMoneyModifier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
creatureABInfo->MoneyModifier,
|
|
RewardScalingMoneyModifier
|
|
);
|
|
}
|
|
else if (RewardScalingMethod == AUTOBALANCE_SCALING_DYNAMIC)
|
|
{
|
|
creatureABInfo->MoneyModifier = avgHealthDamageMultipliers * RewardScalingMoneyModifier;
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | Dynamic Mode: MoneyModifier ({}) = avgHealthDamageMultipliers ({}) * RewardScalingMoneyModifier ({})",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
creatureABInfo->MoneyModifier,
|
|
avgHealthDamageMultipliers,
|
|
RewardScalingMoneyModifier
|
|
);
|
|
}
|
|
}
|
|
|
|
// update all stats
|
|
creature->UpdateAllStats();
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | ---------- FINAL STATS ----------",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel
|
|
);
|
|
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | Health ({}/{} {:.1f}%) -> ({}/{} {:.1f}%)",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
prevHealth,
|
|
prevMaxHealth,
|
|
prevMaxHealth ? float(prevHealth) / float(prevMaxHealth) * 100.0f : 0.0f,
|
|
creature->GetHealth(),
|
|
creature->GetMaxHealth(),
|
|
creature->GetMaxHealth() ? float(creature->GetHealth()) / float(creature->GetMaxHealth()) * 100.0f : 0.0f
|
|
);
|
|
|
|
if (prevPower && prevMaxPower && pType == Powers::POWER_MANA)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance_StatGeneration", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | Mana ({}/{} {:.1f}%) -> ({}/{} {:.1f}%)",
|
|
creature->GetName(),
|
|
creatureABInfo->selectedLevel,
|
|
prevPower,
|
|
prevMaxPower,
|
|
prevMaxPower ? float(prevPower) / float(prevMaxPower) * 100.0f : 0.0f,
|
|
creature->GetPower(Powers::POWER_MANA),
|
|
creature->GetMaxPower(Powers::POWER_MANA),
|
|
creature->GetMaxPower(Powers::POWER_MANA) ? float(creature->GetPower(Powers::POWER_MANA)) / float(creature->GetMaxPower(Powers::POWER_MANA)) * 100.0f : 0.0f
|
|
);
|
|
}
|
|
|
|
// debug log the new stat multipliers stored in CreatureABInfo in a compact, single-line format
|
|
if (creatureABInfo->UnmodifiedLevel != creatureABInfo->selectedLevel)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}->{}) | Multipliers: H:{:.3f}->{:.3f} M:{:.3f}->{:.3f} A:{:.3f}->{:.3f} D:{:.3f}->{:.3f} CC:{:.3f} XP:{:.3f} $:{:.3f}",
|
|
creature->GetName(),
|
|
creatureABInfo->UnmodifiedLevel,
|
|
creatureABInfo->selectedLevel,
|
|
creatureABInfo->HealthMultiplier,
|
|
creatureABInfo->ScaledHealthMultiplier,
|
|
creatureABInfo->ManaMultiplier,
|
|
creatureABInfo->ScaledManaMultiplier,
|
|
creatureABInfo->ArmorMultiplier,
|
|
creatureABInfo->ScaledArmorMultiplier,
|
|
creatureABInfo->DamageMultiplier,
|
|
creatureABInfo->ScaledDamageMultiplier,
|
|
creatureABInfo->CCDurationMultiplier,
|
|
creatureABInfo->XPModifier,
|
|
creatureABInfo->MoneyModifier
|
|
);
|
|
}
|
|
else
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::ModifyCreatureAttributes: Creature {} ({}) | Multipliers: H:{:.3f} M:{:.3f} A:{:.3f} D:{:.3f} CC:{:.3f} XP:{:.3f} $:{:.3f}",
|
|
creature->GetName(),
|
|
creatureABInfo->UnmodifiedLevel,
|
|
creatureABInfo->HealthMultiplier,
|
|
creatureABInfo->ManaMultiplier,
|
|
creatureABInfo->ArmorMultiplier,
|
|
creatureABInfo->DamageMultiplier,
|
|
creatureABInfo->CCDurationMultiplier,
|
|
creatureABInfo->XPModifier,
|
|
creatureABInfo->MoneyModifier
|
|
);
|
|
}
|
|
}
|
|
|
|
bool AutoBalance_AllCreatureScript::_isSummonCloneOfSummoner(Creature* summon)
|
|
{
|
|
// if the summon doesn't exist or isn't a summon
|
|
if (!summon || !summon->IsSummon())
|
|
return false;
|
|
|
|
// get the summon's info
|
|
AutoBalanceCreatureInfo* summonABInfo = summon->CustomData.GetDefault<AutoBalanceCreatureInfo>("AutoBalanceCreatureInfo");
|
|
|
|
// get the saved summoner
|
|
Creature* summoner = summonABInfo->summoner;
|
|
|
|
// if the summoner doesn't exist
|
|
if (!summoner)
|
|
return false;
|
|
|
|
// if this creature's ID is in the list of creatures that are not clones of their summoner (creatureIDsThatAreNotClones), return false
|
|
if (
|
|
std::find
|
|
(
|
|
creatureIDsThatAreNotClones.begin(),
|
|
creatureIDsThatAreNotClones.end(),
|
|
summon->GetEntry()
|
|
) != creatureIDsThatAreNotClones.end()
|
|
)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::_isSummonCloneOfSummoner: Creature {} ({}) | creatureIDsThatAreNotClones contains this creature's ID ({}) | false",
|
|
summon->GetName(),
|
|
summonABInfo->selectedLevel,
|
|
summon->GetEntry()
|
|
);
|
|
return false;
|
|
}
|
|
|
|
|
|
// create a running score for this check
|
|
int8 score = 0;
|
|
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::_isSummonCloneOfSummoner: Creature {} ({}) | Is this a clone of it's summoner {} ({})?",
|
|
summon->GetName(),
|
|
summonABInfo->selectedLevel,
|
|
summoner->GetName(),
|
|
summoner->GetLevel()
|
|
);
|
|
|
|
|
|
// if the entry ID is the same, +2
|
|
if (summon->GetEntry() == summoner->GetEntry())
|
|
{
|
|
score += 2;
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::_isSummonCloneOfSummoner: Creature {} ({}) | Entry: ({}) == ({}) | score: +2 = ({})",
|
|
summon->GetName(),
|
|
summonABInfo->selectedLevel,
|
|
summon->GetEntry(),
|
|
summoner->GetEntry(),
|
|
score
|
|
);
|
|
}
|
|
|
|
// if the max health is the same, +3
|
|
if (summon->GetMaxHealth() == summoner->GetMaxHealth())
|
|
{
|
|
score += 3;
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::_isSummonCloneOfSummoner: Creature {} ({}) | MaxHealth: ({}) == ({}) | score: +3 = ({})",
|
|
summon->GetName(),
|
|
summonABInfo->selectedLevel,
|
|
summon->GetMaxHealth(),
|
|
summoner->GetMaxHealth(),
|
|
score
|
|
);
|
|
}
|
|
|
|
// if the type (humanoid, dragonkin, etc) is the same, +1
|
|
if (summon->GetCreatureType() == summoner->GetCreatureType())
|
|
{
|
|
score += 1;
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::_isSummonCloneOfSummoner: Creature {} ({}) | CreatureType: ({}) == ({}) | score: +1 = ({})",
|
|
summon->GetName(),
|
|
summonABInfo->selectedLevel,
|
|
summon->GetCreatureType(),
|
|
summoner->GetCreatureType(),
|
|
score
|
|
);
|
|
}
|
|
|
|
// if the name is the same, +2
|
|
if (summon->GetName() == summoner->GetName())
|
|
{
|
|
score += 2;
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::_isSummonCloneOfSummoner: Creature {} ({}) | Name: ({}) == ({}) | score: +2 = ({})",
|
|
summon->GetName(),
|
|
summonABInfo->selectedLevel,
|
|
summon->GetName(),
|
|
summoner->GetName(),
|
|
score
|
|
);
|
|
}
|
|
// if the summoner's name is a part of the summon's name, +1
|
|
else if (summon->GetName().find(summoner->GetName()) != std::string::npos)
|
|
{
|
|
score += 1;
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::_isSummonCloneOfSummoner: Creature {} ({}) | Name: ({}) contains ({}) | score: +1 = ({})",
|
|
summon->GetName(),
|
|
summonABInfo->selectedLevel,
|
|
summon->GetName(),
|
|
summoner->GetName(),
|
|
score
|
|
);
|
|
}
|
|
|
|
// if the display ID is the same, +1
|
|
if (summon->GetDisplayId() == summoner->GetDisplayId())
|
|
{
|
|
score += 1;
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::_isSummonCloneOfSummoner: Creature {} ({}) | DisplayId: ({}) == ({}) | score: +1 = ({})",
|
|
summon->GetName(),
|
|
summonABInfo->selectedLevel,
|
|
summon->GetDisplayId(),
|
|
summoner->GetDisplayId(),
|
|
score
|
|
);
|
|
}
|
|
|
|
// if the score is at least 5, consider this a clone
|
|
if (score >= 5)
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::_isSummonCloneOfSummoner: Creature {} ({}) | score ({}) >= 5 | true",
|
|
summon->GetName(),
|
|
summonABInfo->selectedLevel,
|
|
score
|
|
);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
LOG_DEBUG("module.AutoBalance", "AutoBalance_AllCreatureScript::_isSummonCloneOfSummoner: Creature {} ({}) | score ({}) < 5 | false",
|
|
summon->GetName(),
|
|
summonABInfo->selectedLevel,
|
|
score
|
|
);
|
|
return false;
|
|
}
|
|
}
|