mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
* [Quest API] Add Restore Methods for Health, Mana, and Endurance to Perl/Lua - Add `$mob->RestoreEndurance()`. - Add `$mob->RestoreHealth()`. - Add `$mob->RestoreMana()`. - Add `mob:RestoreEndurance()`. - Add `mob:RestoreHealth()`. - Add `mob:RestoreMana()`. - Allows operators to easily restore a mob to full health, mana, or endurance. - `RestoreHealth` is just a more verbosely named `Heal`. - Convert spots in source to use these short hands instead of directly using `SetEndurance(GetMaxEndurance())`, `SetHP(GetMaxHP())`, or `SetMana(GetMaxMana())`. * Update mob.h * Update mob.h
752 lines
19 KiB
C++
752 lines
19 KiB
C++
/**
|
|
* EQEmulator: Everquest Server Emulator
|
|
* Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server)
|
|
*
|
|
* 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; version 2 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
* are required to give you total support for your newly bought product;
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
*/
|
|
|
|
#include "npc_scale_manager.h"
|
|
#include "../common/repositories/npc_scale_global_base_repository.h"
|
|
#include "../common/repositories/npc_types_repository.h"
|
|
|
|
/**
|
|
* @param npc
|
|
*/
|
|
void NpcScaleManager::ScaleNPC(
|
|
NPC *npc,
|
|
bool always_scale,
|
|
bool override_special_abilities
|
|
) {
|
|
if (npc->IsSkipAutoScale() || npc->GetNPCTypeID() == 0) {
|
|
return;
|
|
}
|
|
|
|
auto npc_type = GetNPCScalingType(npc);
|
|
auto npc_level = npc->GetLevel();
|
|
auto is_auto_scaled = IsAutoScaled(npc);
|
|
auto zone_id = zone->GetZoneID();
|
|
auto instance_version = zone->GetInstanceVersion();
|
|
|
|
global_npc_scale scale_data = GetGlobalScaleDataForTypeLevel(
|
|
npc_type,
|
|
npc_level,
|
|
zone_id,
|
|
instance_version
|
|
);
|
|
|
|
if (!scale_data.level) {
|
|
LogNPCScaling(
|
|
"NPC: [{}] - scaling data not found for type [{}] level [{}]",
|
|
npc->GetCleanName(),
|
|
npc_type,
|
|
npc_level
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
if (always_scale || (npc->GetAC() == 0 && is_auto_scaled)) {
|
|
npc->ModifyNPCStat("ac", std::to_string(scale_data.ac));
|
|
}
|
|
|
|
if (always_scale || npc->GetMaxHP() == 0) {
|
|
npc->ModifyNPCStat("max_hp", std::to_string(scale_data.hp));
|
|
npc->RestoreHealth();
|
|
}
|
|
|
|
if (always_scale || npc->GetAccuracyRating() == 0) {
|
|
npc->ModifyNPCStat("accuracy", std::to_string(scale_data.accuracy));
|
|
}
|
|
|
|
if (always_scale || npc->GetSlowMitigation() == 0) {
|
|
npc->ModifyNPCStat("slow_mitigation", std::to_string(scale_data.slow_mitigation));
|
|
}
|
|
|
|
if (always_scale || npc->GetATK() == 0) {
|
|
npc->ModifyNPCStat("atk", std::to_string(scale_data.attack));
|
|
}
|
|
|
|
if (always_scale || npc->GetSTR() == 0) {
|
|
npc->ModifyNPCStat("str", std::to_string(scale_data.strength));
|
|
}
|
|
|
|
if (always_scale || npc->GetSTA() == 0) {
|
|
npc->ModifyNPCStat("sta", std::to_string(scale_data.stamina));
|
|
}
|
|
|
|
if (always_scale || npc->GetDEX() == 0) {
|
|
npc->ModifyNPCStat("dex", std::to_string(scale_data.dexterity));
|
|
}
|
|
|
|
if (always_scale || npc->GetAGI() == 0) {
|
|
npc->ModifyNPCStat("agi", std::to_string(scale_data.agility));
|
|
}
|
|
|
|
if (always_scale || npc->GetINT() == 0) {
|
|
npc->ModifyNPCStat("int", std::to_string(scale_data.intelligence));
|
|
}
|
|
|
|
if (always_scale || npc->GetWIS() == 0) {
|
|
npc->ModifyNPCStat("wis", std::to_string(scale_data.wisdom));
|
|
}
|
|
|
|
if (always_scale || npc->GetCHA() == 0) {
|
|
npc->ModifyNPCStat("cha", std::to_string(scale_data.charisma));
|
|
}
|
|
|
|
if (always_scale || npc->GetMR() == 0) {
|
|
npc->ModifyNPCStat("mr", std::to_string(scale_data.magic_resist));
|
|
}
|
|
|
|
if (always_scale || npc->GetCR() == 0) {
|
|
npc->ModifyNPCStat("cr", std::to_string(scale_data.cold_resist));
|
|
}
|
|
|
|
if (always_scale || npc->GetFR() == 0) {
|
|
npc->ModifyNPCStat("fr", std::to_string(scale_data.fire_resist));
|
|
}
|
|
|
|
if (always_scale || npc->GetPR() == 0) {
|
|
npc->ModifyNPCStat("pr", std::to_string(scale_data.poison_resist));
|
|
}
|
|
|
|
if (always_scale || npc->GetDR() == 0) {
|
|
npc->ModifyNPCStat("dr", std::to_string(scale_data.disease_resist));
|
|
}
|
|
|
|
if (always_scale || (npc->GetCorrup() == 0 && is_auto_scaled)) {
|
|
npc->ModifyNPCStat("cor", std::to_string(scale_data.corruption_resist));
|
|
}
|
|
|
|
if (always_scale || (npc->GetPhR() == 0 && is_auto_scaled)) {
|
|
npc->ModifyNPCStat("phr", std::to_string(scale_data.physical_resist));
|
|
}
|
|
|
|
// If either is scaled, both need to be. The values for base_damage and min_damage will be in flux until
|
|
// both are complete.
|
|
|
|
if (always_scale || npc->GetMinDMG() == 0 || npc->GetMaxDMG() == 0) {
|
|
int64 min_dmg = scale_data.min_dmg;
|
|
int64 max_dmg = scale_data.max_dmg;
|
|
|
|
if (RuleB(Combat, UseNPCDamageClassLevelMods)) {
|
|
uint32 class_level_damage_mod = GetClassLevelDamageMod(npc->GetLevel(), npc->GetClass());
|
|
min_dmg = (min_dmg * class_level_damage_mod) / 220;
|
|
max_dmg = (max_dmg * class_level_damage_mod) / 220;
|
|
}
|
|
|
|
npc->ModifyNPCStat("min_hit", std::to_string(min_dmg));
|
|
npc->ModifyNPCStat("max_hit", std::to_string(max_dmg));
|
|
|
|
LogNPCScaling("ClassLevelDamageMod::min_dmg base: [{}] calc: [{}]", scale_data.min_dmg, min_dmg);
|
|
LogNPCScaling("ClassLevelDamageMod::max_dmg base: [{}] calc: [{}]", scale_data.max_dmg, max_dmg);
|
|
}
|
|
|
|
if (always_scale || (npc->GetHPRegen() == 0 && is_auto_scaled)) {
|
|
npc->ModifyNPCStat("hp_regen", std::to_string(scale_data.hp_regen_rate));
|
|
}
|
|
|
|
if (always_scale || (npc->GetHPRegenPerSecond() == 0 && is_auto_scaled)) {
|
|
npc->ModifyNPCStat("hp_regen_per_second", std::to_string(scale_data.hp_regen_per_second));
|
|
}
|
|
|
|
if (always_scale || npc->GetAttackDelay() == 0) {
|
|
npc->ModifyNPCStat("attack_delay", std::to_string(scale_data.attack_delay));
|
|
}
|
|
|
|
if (always_scale || npc->GetSpellScale() == 0) {
|
|
npc->ModifyNPCStat("spellscale", std::to_string(scale_data.spell_scale));
|
|
}
|
|
|
|
if (always_scale || npc->GetHealScale() == 0) {
|
|
npc->ModifyNPCStat("healscale", std::to_string(scale_data.heal_scale));
|
|
}
|
|
|
|
if (always_scale || npc->GetAvoidanceRating() == 0) {
|
|
npc->ModifyNPCStat("avoidance", std::to_string(scale_data.avoidance));
|
|
}
|
|
|
|
if (always_scale || npc->GetHeroicStrikethrough() == 0) {
|
|
npc->ModifyNPCStat("heroic_strikethrough", std::to_string(scale_data.heroic_strikethrough));
|
|
}
|
|
|
|
if (override_special_abilities || (!npc->HasSpecialAbilities() && is_auto_scaled)) {
|
|
npc->ModifyNPCStat("special_abilities", scale_data.special_abilities);
|
|
}
|
|
|
|
if (LogSys.log_settings[Logs::NPCScaling].is_category_enabled == 1) {
|
|
std::string scale_log;
|
|
|
|
for (const auto &stat : scaling_stats) {
|
|
auto v = fmt::format("modify_stat_{}", stat);
|
|
if (npc->EntityVariableExists(v)) {
|
|
scale_log += fmt::format("{}: {} ", stat, npc->GetEntityVariable(v));
|
|
}
|
|
}
|
|
|
|
LogNPCScaling(
|
|
"([{}]) level: [{}] type: [{}] Auto: [{}] Setting: [{}]",
|
|
npc->GetCleanName(),
|
|
npc_level,
|
|
npc_type,
|
|
(is_auto_scaled ? "true" : "false"),
|
|
scale_log
|
|
);
|
|
}
|
|
}
|
|
|
|
void NpcScaleManager::ResetNPCScaling(NPC* npc)
|
|
{
|
|
for (const auto &scaling_stat : scaling_stats) {
|
|
auto stat_name = fmt::format("modify_stat_{}", scaling_stat);
|
|
auto reset_value = std::to_string(0);
|
|
if (npc->EntityVariableExists(stat_name)) {
|
|
npc->ModifyNPCStat(scaling_stat, reset_value);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool NpcScaleManager::LoadScaleData()
|
|
{
|
|
auto rows = NpcScaleGlobalBaseRepository::All(content_db);
|
|
for (const auto &s : rows) {
|
|
if (
|
|
s.zone_id_list.empty() ||
|
|
s.instance_version_list.empty()
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
global_npc_scale scale_data;
|
|
|
|
scale_data.type = s.type;
|
|
scale_data.level = s.level;
|
|
scale_data.ac = s.ac;
|
|
scale_data.hp = s.hp;
|
|
scale_data.accuracy = s.accuracy;
|
|
scale_data.slow_mitigation = s.slow_mitigation;
|
|
scale_data.attack = s.attack;
|
|
scale_data.strength = s.strength;
|
|
scale_data.stamina = s.stamina;
|
|
scale_data.dexterity = s.dexterity;
|
|
scale_data.agility = s.agility;
|
|
scale_data.intelligence = s.intelligence;
|
|
scale_data.wisdom = s.wisdom;
|
|
scale_data.charisma = s.charisma;
|
|
scale_data.magic_resist = s.magic_resist;
|
|
scale_data.cold_resist = s.cold_resist;
|
|
scale_data.fire_resist = s.fire_resist;
|
|
scale_data.poison_resist = s.poison_resist;
|
|
scale_data.disease_resist = s.disease_resist;
|
|
scale_data.corruption_resist = s.corruption_resist;
|
|
scale_data.physical_resist = s.physical_resist;
|
|
scale_data.min_dmg = s.min_dmg;
|
|
scale_data.max_dmg = s.max_dmg;
|
|
scale_data.hp_regen_rate = s.hp_regen_rate;
|
|
scale_data.hp_regen_per_second = s.hp_regen_per_second;
|
|
scale_data.attack_delay = s.attack_delay;
|
|
scale_data.spell_scale = s.spell_scale;
|
|
scale_data.heal_scale = s.heal_scale;
|
|
scale_data.avoidance = s.avoidance;
|
|
scale_data.heroic_strikethrough = s.heroic_strikethrough;
|
|
|
|
if (!s.special_abilities.empty()) {
|
|
scale_data.special_abilities = s.special_abilities;
|
|
}
|
|
|
|
const auto has_multiple_zones = Strings::Contains(s.zone_id_list, "|");
|
|
const auto has_multiple_versions = Strings::Contains(s.instance_version_list, "|");
|
|
|
|
if (!has_multiple_zones && !has_multiple_versions) {
|
|
scale_data.zone_id = Strings::ToUnsignedInt(s.zone_id_list);
|
|
scale_data.instance_version = static_cast<uint16>(Strings::ToUnsignedInt(s.instance_version_list));
|
|
|
|
npc_global_base_scaling_data.emplace(
|
|
std::make_pair(
|
|
std::make_tuple(
|
|
scale_data.type,
|
|
scale_data.level,
|
|
scale_data.zone_id,
|
|
scale_data.instance_version
|
|
),
|
|
scale_data
|
|
)
|
|
);
|
|
} else if (has_multiple_zones && !has_multiple_versions) {
|
|
scale_data.instance_version = static_cast<uint16>(Strings::ToUnsignedInt(s.instance_version_list));
|
|
|
|
const auto zones = Strings::Split(s.zone_id_list, "|");
|
|
|
|
for (const auto &z : zones) {
|
|
scale_data.zone_id = Strings::ToUnsignedInt(z);
|
|
|
|
npc_global_base_scaling_data.emplace(
|
|
std::make_pair(
|
|
std::make_tuple(
|
|
scale_data.type,
|
|
scale_data.level,
|
|
scale_data.zone_id,
|
|
scale_data.instance_version
|
|
),
|
|
scale_data
|
|
)
|
|
);
|
|
}
|
|
} else if (!has_multiple_zones) {
|
|
scale_data.zone_id = Strings::ToUnsignedInt(s.zone_id_list);
|
|
|
|
const auto versions = Strings::Split(s.instance_version_list, "|");
|
|
|
|
for (const auto &v : versions) {
|
|
scale_data.instance_version = static_cast<uint16>(Strings::ToUnsignedInt(v));
|
|
|
|
npc_global_base_scaling_data.emplace(
|
|
std::make_pair(
|
|
std::make_tuple(
|
|
scale_data.type,
|
|
scale_data.level,
|
|
scale_data.zone_id,
|
|
scale_data.instance_version
|
|
),
|
|
scale_data
|
|
)
|
|
);
|
|
}
|
|
} else {
|
|
const auto zones = Strings::Split(s.zone_id_list, "|");
|
|
const auto versions = Strings::Split(s.instance_version_list, "|");
|
|
|
|
for (const auto &z : zones) {
|
|
scale_data.zone_id = Strings::ToUnsignedInt(z);
|
|
|
|
for (const auto &v : versions) {
|
|
scale_data.instance_version = static_cast<uint16>(Strings::ToUnsignedInt(v));
|
|
|
|
npc_global_base_scaling_data.emplace(
|
|
std::make_pair(
|
|
std::make_tuple(
|
|
scale_data.type,
|
|
scale_data.level,
|
|
scale_data.zone_id,
|
|
scale_data.instance_version
|
|
),
|
|
scale_data
|
|
)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LogInfo("Loaded [{}] global scaling data entries", Strings::Commify(rows.size()));
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @param npc_type
|
|
* @param npc_level
|
|
* @return NpcScaleManager::global_npc_scale
|
|
*/
|
|
NpcScaleManager::global_npc_scale NpcScaleManager::GetGlobalScaleDataForTypeLevel(
|
|
int8 npc_type,
|
|
uint8 npc_level,
|
|
uint32 zone_id,
|
|
uint16 instance_version
|
|
) {
|
|
auto iter = npc_global_base_scaling_data.find(
|
|
std::make_tuple(
|
|
npc_type,
|
|
npc_level,
|
|
zone_id,
|
|
instance_version
|
|
)
|
|
);
|
|
|
|
if (iter != npc_global_base_scaling_data.end()) {
|
|
return iter->second;
|
|
}
|
|
|
|
iter = npc_global_base_scaling_data.find(
|
|
std::make_tuple(
|
|
npc_type,
|
|
npc_level,
|
|
zone_id,
|
|
0
|
|
)
|
|
);
|
|
if (iter != npc_global_base_scaling_data.end()) {
|
|
return iter->second;
|
|
}
|
|
|
|
iter = npc_global_base_scaling_data.find(
|
|
std::make_tuple(
|
|
npc_type,
|
|
npc_level,
|
|
0,
|
|
0
|
|
)
|
|
);
|
|
if (iter != npc_global_base_scaling_data.end()) {
|
|
return iter->second;
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
/**
|
|
* @param level
|
|
* @param npc_class
|
|
* @return
|
|
*/
|
|
uint32 NpcScaleManager::GetClassLevelDamageMod(uint32 level, uint32 npc_class)
|
|
{
|
|
uint32 multiplier;
|
|
|
|
switch (npc_class) {
|
|
case Class::Warrior: {
|
|
if (level < 20) {
|
|
multiplier = 220;
|
|
}
|
|
else if (level < 30) {
|
|
multiplier = 230;
|
|
}
|
|
else if (level < 40) {
|
|
multiplier = 250;
|
|
}
|
|
else if (level < 53) {
|
|
multiplier = 270;
|
|
}
|
|
else if (level < 57) {
|
|
multiplier = 280;
|
|
}
|
|
else if (level < 60) {
|
|
multiplier = 290;
|
|
}
|
|
else if (level < 70) {
|
|
multiplier = 300;
|
|
}
|
|
else {
|
|
multiplier = 311;
|
|
}
|
|
break;
|
|
}
|
|
case Class::Druid:
|
|
case Class::Cleric:
|
|
case Class::Shaman: {
|
|
if (level < 70) {
|
|
multiplier = 150;
|
|
}
|
|
else {
|
|
multiplier = 157;
|
|
}
|
|
break;
|
|
}
|
|
case Class::Berserker:
|
|
case Class::Paladin:
|
|
case Class::ShadowKnight: {
|
|
if (level < 35) {
|
|
multiplier = 210;
|
|
}
|
|
else if (level < 45) {
|
|
multiplier = 220;
|
|
}
|
|
else if (level < 51) {
|
|
multiplier = 230;
|
|
}
|
|
else if (level < 56) {
|
|
multiplier = 240;
|
|
}
|
|
else if (level < 60) {
|
|
multiplier = 250;
|
|
}
|
|
else if (level < 68) {
|
|
multiplier = 260;
|
|
}
|
|
else {
|
|
multiplier = 270;
|
|
}
|
|
break;
|
|
}
|
|
case Class::Monk:
|
|
case Class::Bard:
|
|
case Class::Rogue:
|
|
case Class::Beastlord: {
|
|
if (level < 51) {
|
|
multiplier = 180;
|
|
}
|
|
else if (level < 58) {
|
|
multiplier = 190;
|
|
}
|
|
else if (level < 70) {
|
|
multiplier = 200;
|
|
}
|
|
else {
|
|
multiplier = 210;
|
|
}
|
|
break;
|
|
}
|
|
case Class::Ranger: {
|
|
if (level < 58) {
|
|
multiplier = 200;
|
|
}
|
|
else if (level < 70) {
|
|
multiplier = 210;
|
|
}
|
|
else {
|
|
multiplier = 220;
|
|
}
|
|
break;
|
|
}
|
|
case Class::Magician:
|
|
case Class::Wizard:
|
|
case Class::Necromancer:
|
|
case Class::Enchanter: {
|
|
if (level < 70) {
|
|
multiplier = 120;
|
|
}
|
|
else {
|
|
multiplier = 127;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
if (level < 35) {
|
|
multiplier = 210;
|
|
}
|
|
else if (level < 45) {
|
|
multiplier = 220;
|
|
}
|
|
else if (level < 51) {
|
|
multiplier = 230;
|
|
}
|
|
else if (level < 56) {
|
|
multiplier = 240;
|
|
}
|
|
else if (level < 60) {
|
|
multiplier = 250;
|
|
}
|
|
else {
|
|
multiplier = 260;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return multiplier;
|
|
}
|
|
|
|
/**
|
|
* @param npc
|
|
* @return int8
|
|
*/
|
|
int8 NpcScaleManager::GetNPCScalingType(NPC *&npc)
|
|
{
|
|
std::string npc_name = npc->GetName();
|
|
|
|
if (npc->IsRaidTarget()) {
|
|
return 2;
|
|
}
|
|
|
|
if (npc->IsRareSpawn() || npc_name.find('#') != std::string::npos || isupper(npc_name[0])) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @param npc
|
|
* @return std::string
|
|
*/
|
|
std::string NpcScaleManager::GetNPCScalingTypeName(NPC *&npc)
|
|
{
|
|
|
|
if (int8 scaling_type = GetNPCScalingType(npc); scaling_type == 1) {
|
|
return "Named";
|
|
}
|
|
|
|
if (npc->IsRaidTarget()) {
|
|
return "Raid";
|
|
}
|
|
|
|
return "Trash";
|
|
}
|
|
|
|
/**
|
|
* Determines based on minimum criteria if NPC is auto scaled for certain things to be scaled like
|
|
* special abilities. We use this so we don't blindly assume we want things to be applied
|
|
*
|
|
* @param npc
|
|
* @return
|
|
*/
|
|
bool NpcScaleManager::IsAutoScaled(NPC* npc)
|
|
{
|
|
return (
|
|
npc->GetHP() == 0 &&
|
|
npc->GetMaxDMG() == 0 &&
|
|
npc->GetMinDMG() == 0 &&
|
|
npc->GetSTR() == 0 &&
|
|
npc->GetSTA() == 0 &&
|
|
npc->GetDEX() == 0 &&
|
|
npc->GetAGI() == 0 &&
|
|
npc->GetINT() == 0 &&
|
|
npc->GetWIS() == 0 &&
|
|
npc->GetCHA() == 0 &&
|
|
npc->GetMR() == 0 &&
|
|
npc->GetFR() == 0 &&
|
|
npc->GetCR() == 0 &&
|
|
npc->GetPR() == 0 &&
|
|
npc->GetDR() == 0
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns false if scaling data not found
|
|
* @param npc
|
|
* @return
|
|
*/
|
|
bool NpcScaleManager::ApplyGlobalBaseScalingToNPCStatically(NPC *&npc)
|
|
{
|
|
auto npc_type = GetNPCScalingType(npc);
|
|
auto npc_level = npc->GetLevel();
|
|
auto zone_id = zone->GetZoneID();
|
|
auto instance_version = zone->GetInstanceVersion();
|
|
|
|
global_npc_scale g = GetGlobalScaleDataForTypeLevel(
|
|
npc_type,
|
|
npc_level,
|
|
zone_id,
|
|
instance_version
|
|
);
|
|
|
|
if (!g.level) {
|
|
LogNPCScaling(
|
|
"NPC: [{}] - scaling data not found for type [{}] level [{}]",
|
|
npc->GetCleanName(),
|
|
npc_type,
|
|
npc_level
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
auto n = NpcTypesRepository::FindOne(content_db, static_cast<int>(npc->GetNPCTypeID()));
|
|
if (n.id > 0) {
|
|
n.AC = g.ac;
|
|
n.hp = g.hp;
|
|
n.Accuracy = g.accuracy;
|
|
n.slow_mitigation = g.slow_mitigation;
|
|
n.ATK = g.attack;
|
|
n.STR = g.strength;
|
|
n.STA = g.stamina;
|
|
n.DEX = g.dexterity;
|
|
n.AGI = g.agility;
|
|
n._INT = g.intelligence;
|
|
n.WIS = g.wisdom;
|
|
n.CHA = g.charisma;
|
|
n.MR = g.magic_resist;
|
|
n.CR = g.cold_resist;
|
|
n.FR = g.fire_resist;
|
|
n.PR = g.poison_resist;
|
|
n.DR = g.disease_resist;
|
|
n.Corrup = g.corruption_resist;
|
|
n.PhR = g.physical_resist;
|
|
n.mindmg = g.min_dmg;
|
|
n.maxdmg = g.max_dmg;
|
|
n.hp_regen_rate = g.hp_regen_rate;
|
|
n.hp_regen_per_second = g.hp_regen_per_second;
|
|
n.attack_delay = g.attack_delay;
|
|
n.spellscale = static_cast<float>(g.spell_scale);
|
|
n.healscale = static_cast<float>(g.heal_scale);
|
|
n.Avoidance = g.avoidance;
|
|
n.heroic_strikethrough = g.heroic_strikethrough;
|
|
n.special_abilities = g.special_abilities;
|
|
|
|
return NpcTypesRepository::UpdateOne(content_db, n);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns false if scaling data not found
|
|
* @param npc
|
|
* @return
|
|
*/
|
|
bool NpcScaleManager::ApplyGlobalBaseScalingToNPCDynamically(NPC *&npc)
|
|
{
|
|
auto npc_type = GetNPCScalingType(npc);
|
|
auto npc_level = npc->GetLevel();
|
|
auto zone_id = zone->GetZoneID();
|
|
auto instance_version = zone->GetInstanceVersion();
|
|
|
|
global_npc_scale d = GetGlobalScaleDataForTypeLevel(
|
|
npc_type,
|
|
npc_level,
|
|
zone_id,
|
|
instance_version
|
|
);
|
|
|
|
if (!d.level) {
|
|
LogNPCScaling(
|
|
"NPC: [{}] - scaling data not found for type [{}] level [{}]",
|
|
npc->GetCleanName(),
|
|
npc_type,
|
|
npc_level
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
auto n = NpcTypesRepository::FindOne(content_db, static_cast<int>(npc->GetNPCTypeID()));
|
|
if (n.id > 0) {
|
|
n.AC = 0;
|
|
n.hp = 0;
|
|
n.Accuracy = 0;
|
|
n.slow_mitigation = 0;
|
|
n.ATK = 0;
|
|
n.STR = 0;
|
|
n.STA = 0;
|
|
n.DEX = 0;
|
|
n.AGI = 0;
|
|
n._INT = 0;
|
|
n.WIS = 0;
|
|
n.CHA = 0;
|
|
n.MR = 0;
|
|
n.CR = 0;
|
|
n.FR = 0;
|
|
n.PR = 0;
|
|
n.DR = 0;
|
|
n.Corrup = 0;
|
|
n.PhR = 0;
|
|
n.mindmg = 0;
|
|
n.maxdmg = 0;
|
|
n.hp_regen_rate = 0;
|
|
n.hp_regen_per_second = 0;
|
|
n.attack_delay = 0;
|
|
n.spellscale = 0;
|
|
n.healscale = 0;
|
|
n.Avoidance = 0;
|
|
n.heroic_strikethrough = 0;
|
|
n.special_abilities = "";
|
|
|
|
return NpcTypesRepository::UpdateOne(content_db, n);
|
|
}
|
|
|
|
return false;
|
|
}
|