Skip to content

Commit

Permalink
[s2478] Creature: Implement base stat usage for npcs
Browse files Browse the repository at this point in the history
Works retroactively with old data since that one was correct for what we had
  • Loading branch information
killerwife committed Apr 25, 2024
1 parent 43f3028 commit e955409
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 59 deletions.
9 changes: 7 additions & 2 deletions sql/base/mangos.sql
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `db_version`;
CREATE TABLE `db_version` (
`version` varchar(120) DEFAULT NULL,
`creature_ai_version` varchar(120) DEFAULT NULL,
`required_s2477_01_mangos_charmed_spell_list` bit(1) DEFAULT NULL
`required_s2478_01_mangos_creature_cls_stats` bit(1) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Used DB version notes';

--
Expand Down Expand Up @@ -1352,6 +1352,11 @@ CREATE TABLE `creature_template` (
`DamageVariance` float NOT NULL DEFAULT '1',
`ArmorMultiplier` float NOT NULL DEFAULT '1',
`ExperienceMultiplier` float NOT NULL DEFAULT '1',
`StrengthMultiplier` float NOT NULL DEFAULT '1',
`AgilityMultiplier` float NOT NULL DEFAULT '1',
`StaminaMultiplier` float NOT NULL DEFAULT '1',
`IntellectMultiplier` float NOT NULL DEFAULT '1',
`SpiritMultiplier` float NOT NULL DEFAULT '1',
`MinLevelHealth` int(10) unsigned NOT NULL DEFAULT '0',
`MaxLevelHealth` int(10) unsigned NOT NULL DEFAULT '0',
`MinLevelMana` int(10) unsigned NOT NULL DEFAULT '0',
Expand Down Expand Up @@ -1409,7 +1414,7 @@ CREATE TABLE `creature_template` (
LOCK TABLES `creature_template` WRITE;
/*!40000 ALTER TABLE `creature_template` DISABLE KEYS */;
INSERT INTO `creature_template` VALUES
(1,'Waypoint (Only GM can see it)','Visual',NULL,1,1,0,10045,0,0,0,35,1,8,8,1,1,0,0,4096,0,130,5242886,0,0,0,0,0.91,1.14286,20,0,0,0,0,0,0,-1,1,1,1,1,1,1,8,8,0,0,7,7,1.76,2.42,0,3,100,2000,2200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'','');
(1,'Waypoint (Only GM can see it)','Visual',NULL,1,1,0,10045,0,0,0,35,1,8,8,1,1,0,0,4096,0,130,5242886,0,0,0,0,0.91,1.14286,20,0,0,0,0,0,0,-1,1,1,1,1,1,1,1,1,1,1,1,8,8,0,0,7,7,1.76,2.42,0,3,100,2000,2200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'','');
/*!40000 ALTER TABLE `creature_template` ENABLE KEYS */;
UNLOCK TABLES;

Expand Down
15 changes: 15 additions & 0 deletions sql/updates/mangos/s2478_01_mangos_creature_cls_stats.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ALTER TABLE db_version CHANGE COLUMN required_s2477_01_mangos_charmed_spell_list required_s2478_01_mangos_creature_cls_stats bit;

ALTER TABLE creature_template_classlevelstats ADD `Strength` int(11) NOT NULL DEFAULT '0';
ALTER TABLE creature_template_classlevelstats ADD `Agility` int(11) NOT NULL DEFAULT '0';
ALTER TABLE creature_template_classlevelstats ADD `Stamina` int(11) NOT NULL DEFAULT '0';
ALTER TABLE creature_template_classlevelstats ADD `Intellect` int(11) NOT NULL DEFAULT '0';
ALTER TABLE creature_template_classlevelstats ADD `Spirit` int(11) NOT NULL DEFAULT '0';

ALTER TABLE creature_template ADD `StrengthMultiplier` FLOAT NOT NULL DEFAULT 1 AFTER `ExperienceMultiplier`;
ALTER TABLE creature_template ADD `AgilityMultiplier` FLOAT NOT NULL DEFAULT 1 AFTER `StrengthMultiplier`;
ALTER TABLE creature_template ADD `StaminaMultiplier` FLOAT NOT NULL DEFAULT 1 AFTER `AgilityMultiplier`;
ALTER TABLE creature_template ADD `IntellectMultiplier` FLOAT NOT NULL DEFAULT 1 AFTER `StaminaMultiplier`;
ALTER TABLE creature_template ADD `SpiritMultiplier` FLOAT NOT NULL DEFAULT 1 AFTER `IntellectMultiplier`;


44 changes: 40 additions & 4 deletions src/game/Entities/Creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,15 @@ void Creature::SelectLevel(uint32 forcedLevel /*= USE_DEFAULT_DATABASE_LEVEL*/)
float meleeAttackPwr = 0.f;
float rangedAttackPwr = 0.f;

float healthMultiplier = 1.f;
float manaMultiplier = 1.f;

float strength = 0.f;
float agility = 0.f;
float stamina = 0.f;
float intellect = 0.f;
float spirit = 0.f;

float damageMod = _GetDamageMod(rank);
float damageMulti = cinfo->DamageMultiplier * damageMod;
bool usedDamageMulti = false;
Expand All @@ -1318,13 +1327,17 @@ void Creature::SelectLevel(uint32 forcedLevel /*= USE_DEFAULT_DATABASE_LEVEL*/)
{
// Use Creature Stats to calculate stat values

// health
if (cinfo->HealthMultiplier >= 0)
health = std::round(cCLS->BaseHealth * cinfo->HealthMultiplier);
health = cCLS->BaseHealth;
// health
if (cinfo->HealthMultiplier > 0)
healthMultiplier = cinfo->HealthMultiplier;

// mana
if (cinfo->PowerMultiplier >= 0)
mana = std::round(cCLS->BaseMana * cinfo->PowerMultiplier);
mana = cCLS->BaseMana;
// mana
if (cinfo->PowerMultiplier > 0)
manaMultiplier = cinfo->PowerMultiplier;

// armor
if (cinfo->ArmorMultiplier >= 0)
Expand All @@ -1345,6 +1358,18 @@ void Creature::SelectLevel(uint32 forcedLevel /*= USE_DEFAULT_DATABASE_LEVEL*/)
meleeAttackPwr = cCLS->BaseMeleeAttackPower;
rangedAttackPwr = cCLS->BaseRangedAttackPower;
}

// attributes
if (cinfo->StrengthMultiplier >= 0)
strength = cCLS->Strength * cinfo->StrengthMultiplier;
if (cinfo->AgilityMultiplier >= 0)
agility = cCLS->Agility * cinfo->AgilityMultiplier;
if (cinfo->StaminaMultiplier >= 0)
stamina = cCLS->Stamina * cinfo->StaminaMultiplier;
if (cinfo->IntellectMultiplier >= 0)
intellect = cCLS->Intellect * cinfo->IntellectMultiplier;
if (cinfo->SpiritMultiplier >= 0)
spirit = cCLS->Spirit * cinfo->SpiritMultiplier;
}

if (!usedDamageMulti || health == -1 || mana == -1 || armor == -1.f) // some field needs to default to old db fields
Expand Down Expand Up @@ -1457,6 +1482,17 @@ void Creature::SelectLevel(uint32 forcedLevel /*= USE_DEFAULT_DATABASE_LEVEL*/)
SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, meleeAttackPwr * damageMod);
SetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, rangedAttackPwr * damageMod);

// primary attributes
SetCreateStat(STAT_STRENGTH, strength);
SetCreateStat(STAT_AGILITY, agility);
SetCreateStat(STAT_STAMINA, stamina);
SetCreateStat(STAT_INTELLECT, intellect);
SetCreateStat(STAT_SPIRIT, spirit);

// multipliers
SetModifierValue(UNIT_MOD_HEALTH, TOTAL_PCT, healthMultiplier);
SetModifierValue(UNIT_MOD_MANA, TOTAL_PCT, manaMultiplier);

UpdateAllStats();
}

Expand Down
12 changes: 10 additions & 2 deletions src/game/Entities/Creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ struct CreatureInfo
float DamageVariance;
float ArmorMultiplier;
float ExperienceMultiplier;
float StrengthMultiplier;
float AgilityMultiplier;
float StaminaMultiplier;
float IntellectMultiplier;
float SpiritMultiplier;
uint32 MinLevelHealth;
uint32 MaxLevelHealth;
uint32 MinLevelMana;
Expand Down Expand Up @@ -299,6 +304,11 @@ struct CreatureClassLvlStats
float BaseMeleeAttackPower;
float BaseRangedAttackPower;
uint32 BaseArmor;
uint32 Strength;
uint32 Agility;
uint32 Stamina;
uint32 Intellect;
uint32 Spirit;
};

struct CreatureModelInfo
Expand Down Expand Up @@ -672,8 +682,6 @@ class Creature : public Unit
bool UpdateAllStats() override;
void UpdateResistances(uint32 school) override;
void UpdateArmor() override;
void UpdateMaxHealth() override;
void UpdateMaxPower(Powers power) override;
void UpdateAttackPowerAndDamage(bool ranged = false) override;
void UpdateDamagePhysical(WeaponAttackType attType) override;
uint32 GetCurrentEquipmentId() const { return m_equipmentId; }
Expand Down
5 changes: 2 additions & 3 deletions src/game/Entities/Player.h
Original file line number Diff line number Diff line change
Expand Up @@ -1697,9 +1697,6 @@ class Player : public Unit
bool UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator = 1);
bool UpdateFishingSkill();

float GetHealthBonusFromStamina() const;
float GetManaBonusFromIntellect() const;

bool UpdateStats(Stats stat) override;
bool UpdateAllStats() override;
void UpdateResistances(uint32 school) override;
Expand All @@ -1715,6 +1712,8 @@ class Player : public Unit
void UpdateRating(CombatRating cr);
void UpdateAllRatings();

void ApplyFeralAPBonus(int32 amount, bool apply); // TBC only

void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float& min_damage, float& max_damage, uint8 index = 0);

void UpdateDefenseBonusesMod();
Expand Down
94 changes: 55 additions & 39 deletions src/game/Entities/StatSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,27 +175,37 @@ void Player::UpdateArmor()
pet->UpdateScalingAuras();
}

float Player::GetHealthBonusFromStamina() const
float Unit::GetHealthBonusFromStamina(float stamina)
{
float stamina = GetStat(STAT_STAMINA);

float baseStam = stamina < 20 ? stamina : 20;
float moreStam = stamina - baseStam;

return baseStam + (moreStam * 10.0f);
}

float Player::GetManaBonusFromIntellect() const
float Unit::GetHealthBonusFromStamina() const
{
float intellect = GetStat(STAT_INTELLECT);
float stamina = GetStat(STAT_STAMINA);

return Unit::GetHealthBonusFromStamina(stamina);
}

float Unit::GetManaBonusFromIntellect(float intellect)
{
float baseInt = intellect < 20 ? intellect : 20;
float moreInt = intellect - baseInt;

return baseInt + (moreInt * 15.0f);
}

void Player::UpdateMaxHealth()
float Unit::GetManaBonusFromIntellect() const
{
float intellect = GetStat(STAT_INTELLECT);

return Unit::GetManaBonusFromIntellect(intellect);
}

void Unit::UpdateMaxHealth()
{
UnitMods unitMod = UNIT_MOD_HEALTH;

Expand All @@ -207,7 +217,7 @@ void Player::UpdateMaxHealth()
SetMaxHealth((uint32)value);
}

void Player::UpdateMaxPower(Powers power)
void Unit::UpdateMaxPower(Powers power)
{
UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);

Expand Down Expand Up @@ -737,6 +747,13 @@ bool Creature::UpdateStats(Stats /*stat*/)

bool Creature::UpdateAllStats()
{
for (int i = STAT_STRENGTH; i < MAX_STATS; ++i)
{
float value = GetTotalStatValue(Stats(i));
SetStat(Stats(i), (int32)value);
}

UpdateArmor();
UpdateMaxHealth();
UpdateAttackPowerAndDamage();
UpdateAttackPowerAndDamage(true);
Expand All @@ -763,36 +780,20 @@ void Creature::UpdateResistances(uint32 school)

void Creature::UpdateArmor()
{
float dynamic = (GetStat(STAT_AGILITY) * 2.0f);

m_auraModifiersGroup[UNIT_MOD_ARMOR][TOTAL_VALUE] += dynamic;
int32 value = GetTotalResistanceValue(SPELL_SCHOOL_NORMAL);
int32 oldValue = GetArmor();
SetArmor(value);
}

void Creature::UpdateMaxHealth()
{
UnitMods unitMod = UNIT_MOD_HEALTH;

float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth();
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE);
value *= GetModifierValue(unitMod, TOTAL_PCT);

SetMaxHealth((uint32)value);
}

void Creature::UpdateMaxPower(Powers power)
{
UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power);

float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power);
value *= GetModifierValue(unitMod, BASE_PCT);
value += GetModifierValue(unitMod, TOTAL_VALUE);
value *= GetModifierValue(unitMod, TOTAL_PCT);

SetMaxPower(power, uint32(value));
m_auraModifiersGroup[UNIT_MOD_ARMOR][TOTAL_VALUE] -= dynamic;
}

void Creature::UpdateAttackPowerAndDamage(bool ranged)
{
float val2 = 0.0f;
float level = float(GetLevel());

UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER;

uint16 index = UNIT_FIELD_ATTACK_POWER;
Expand All @@ -804,25 +805,40 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged)
index = UNIT_FIELD_RANGED_ATTACK_POWER;
index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS;
index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER;

val2 = GetStat(STAT_AGILITY) - 10.0f;
}
else
{
switch (getClass())
{
case CLASS_ROGUE:
val2 = (GetStat(STAT_STRENGTH) - 10.0f) + GetStat(STAT_AGILITY);
break;
default:
val2 = (GetStat(STAT_STRENGTH) - 10.0f) * 2.f;
break;
}
}

float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
SetModifierValue(unitMod, BASE_VALUE, val2);
float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT);
float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE);

float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;

SetInt32Value(index, (uint32)base_attPower); // UNIT_FIELD_(RANGED)_ATTACK_POWER field
SetInt32Value(index_mod, (uint32)attPowerMod); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field
SetFloatValue(index_mult, attPowerMultiplier); // UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field

if (ranged)
// automatically update weapon damage after attack power modification
if (!ranged)
{
UpdateDamagePhysical(RANGED_ATTACK);
return;
UpdateDamagePhysical(BASE_ATTACK);
UpdateDamagePhysical(OFF_ATTACK);
}

// automatically update weapon damage after attack power modification
UpdateDamagePhysical(BASE_ATTACK);
UpdateDamagePhysical(OFF_ATTACK);
else
UpdateDamagePhysical(RANGED_ATTACK);
}

void Creature::UpdateDamagePhysical(WeaponAttackType attType)
Expand Down
10 changes: 8 additions & 2 deletions src/game/Entities/Unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -2052,12 +2052,18 @@ class Unit : public WorldObject
Powers GetPowerTypeByAuraGroup(UnitMods unitMod) const;
bool CanModifyStats() const { return m_canModifyStats; }
void SetCanModifyStats(bool modifyStats) { m_canModifyStats = modifyStats; }

static float GetHealthBonusFromStamina(float stamina);
float GetHealthBonusFromStamina() const;
static float GetManaBonusFromIntellect(float intellect);
float GetManaBonusFromIntellect() const;

virtual bool UpdateStats(Stats stat) = 0;
virtual bool UpdateAllStats() = 0;
virtual void UpdateResistances(uint32 school) = 0;
virtual void UpdateArmor() = 0;
virtual void UpdateMaxHealth() = 0;
virtual void UpdateMaxPower(Powers power) = 0;
virtual void UpdateMaxHealth();
virtual void UpdateMaxPower(Powers power);
virtual void UpdateAttackPowerAndDamage(bool ranged = false) = 0;
virtual void UpdateDamagePhysical(WeaponAttackType attType) = 0;
float GetTotalAttackPowerValue(WeaponAttackType attType) const;
Expand Down
Loading

0 comments on commit e955409

Please sign in to comment.