From 18bda032190d1b6e639848b22d2917d2444c970b Mon Sep 17 00:00:00 2001 From: Frankie-hz <105882754+Frankie-hz@users.noreply.github.com> Date: Wed, 15 Apr 2026 02:24:13 -0400 Subject: [PATCH] [cpp] Cleanup my old HP formula Cleanup the hp formula and make it readable Remove unused code --- sql/mob_family_mods.sql | 16 ++- sql/mob_pool_mods.sql | 9 -- src/map/grades.cpp | 21 ---- src/map/grades.h | 1 - src/map/utils/mobutils.cpp | 236 ++++++++++++++++++++----------------- src/map/utils/mobutils.h | 1 - 6 files changed, 142 insertions(+), 142 deletions(-) diff --git a/sql/mob_family_mods.sql b/sql/mob_family_mods.sql index ee19dd296c2..781e34a4f72 100644 --- a/sql/mob_family_mods.sql +++ b/sql/mob_family_mods.sql @@ -468,11 +468,12 @@ INSERT INTO `mob_family_mods` VALUES (176,10,8,1); -- SUBLINK: 8 (Mamool Ja, Sa INSERT INTO `mob_family_mods` VALUES (176,68,10,0); -- EVA: 10 -- Manticore -INSERT INTO `mob_family_mods` VALUES (179,31,30,1); -- ROAM_DISTANCE: 30 -INSERT INTO `mob_family_mods` VALUES (179,36,60,1); -- ROAM_COOL: 60 -INSERT INTO `mob_family_mods` VALUES (179,51,4,1); -- ROAM_TURNS: 4 -INSERT INTO `mob_family_mods` VALUES (179,52,30,1); -- ROAM_RATE: 30 -INSERT INTO `mob_family_mods` VALUES (179,62,10,0); -- ATTP: 10 +INSERT INTO `mob_family_mods` VALUES (179,31,30,1); -- ROAM_DISTANCE: 30 +INSERT INTO `mob_family_mods` VALUES (179,36,60,1); -- ROAM_COOL: 60 +INSERT INTO `mob_family_mods` VALUES (179,51,4,1); -- ROAM_TURNS: 4 +INSERT INTO `mob_family_mods` VALUES (179,52,30,1); -- ROAM_RATE: 30 +INSERT INTO `mob_family_mods` VALUES (179,62,10,0); -- ATTP: 10 +INSERT INTO `mob_family_mods` VALUES (179,3,50,0); -- HPP: 50 -- Marid INSERT INTO `mob_family_mods` VALUES (180,36,30,1); -- ROAM_COOL: 30 @@ -497,11 +498,13 @@ INSERT INTO `mob_family_mods` VALUES (188,52,20,1); -- ROAM_RATE: 20 -- Orc INSERT INTO `mob_family_mods` VALUES (189,10,2,1); -- SUBLINK: 2 (Orc, Orc Warmachine) +INSERT INTO `mob_family_mods` VALUES (189,3,5,0); -- HPP: 5 -- Orc-Warmachine INSERT INTO `mob_family_mods` VALUES (190,10,2,1); -- SUBLINK: 2 (Orc, Orc Warmachine) INSERT INTO `mob_family_mods` VALUES (190,36,50,1); -- ROAM_COOL: 50 INSERT INTO `mob_family_mods` VALUES (190,52,30,1); -- ROAM_RATE: 30 +INSERT INTO `mob_family_mods` VALUES (190,3,5,0); -- HPP: 5 -- Wyvern-Pet INSERT INTO `mob_family_mods` VALUES (193,3,40,1); -- MP_BASE: 40 @@ -512,6 +515,9 @@ INSERT INTO `mob_family_mods` VALUES (194,3,50,1); -- MP_BASE: 50 -- Qiqirn INSERT INTO `mob_family_mods` VALUES (199,10,12,1); -- SUBLINK: 12 (Qiqirn) +-- Quadav +INSERT INTO `mob_family_mods` VALUES (202,3,-5,0); -- HPP: -5 + -- Qutrub INSERT INTO `mob_family_mods` VALUES (203,36,50,1); -- ROAM_COOL: 50 INSERT INTO `mob_family_mods` VALUES (203,51,3,1); -- ROAM_TURNS: 3 diff --git a/sql/mob_pool_mods.sql b/sql/mob_pool_mods.sql index e77062225c1..8da80cdd630 100644 --- a/sql/mob_pool_mods.sql +++ b/sql/mob_pool_mods.sql @@ -192,15 +192,6 @@ INSERT INTO `mob_pool_mods` VALUES (2271,165,15,0); -- CRITHITRATE: 15 -- Ladon INSERT INTO `mob_pool_mods` VALUES (2314,28,23,1); -- EXP_BONUS: 23 --- Maats Avatar -INSERT INTO `mob_pool_mods` VALUES (2461,61,25,1); -- HP_SCALE: 25 - --- Maats Pet -INSERT INTO `mob_pool_mods` VALUES (2462,61,25,1); -- HP_SCALE: 25 - --- Maats Wyvern -INSERT INTO `mob_pool_mods` VALUES (2463,61,20,1); -- HP_SCALE: 20 - -- Mammet-19 Epsilon INSERT INTO `mob_pool_mods` VALUES (2499,240,90,0); -- SLEEPRES: 90 diff --git a/src/map/grades.cpp b/src/map/grades.cpp index 141b934c876..c49778a03e8 100644 --- a/src/map/grades.cpp +++ b/src/map/grades.cpp @@ -148,22 +148,6 @@ std::array, 8> MobHPScale = { { { 22, 3, 0 }, // G } }; -/************************************************************************ - * * - * Random Increment based on level * - * * - ************************************************************************/ - -std::array, 6> MobRBI = { { - // RI | Scale - { 0, 0 }, // 0 - { 1, 0 }, // 1 - { 2, 0 }, // 2 - { 3, 3 }, // 3 - { 4, 7 }, // 4 - { 5, 14 }, // 5 -} }; - namespace grade { @@ -197,9 +181,4 @@ uint8 GetMobHPScale(uint8 rank, uint8 scale) return MobHPScale[rank][scale]; } -uint8 GetMobRBI(uint8 rank, uint8 scale) -{ - return MobRBI[rank][scale]; -} - }; // namespace grade diff --git a/src/map/grades.h b/src/map/grades.h index ba81d42201e..1c4d3619727 100644 --- a/src/map/grades.h +++ b/src/map/grades.h @@ -36,7 +36,6 @@ float GetHPScale(uint8 rank, uint8 scale); float GetMPScale(uint8 rank, uint8 scale); float GetStatScale(uint8 rank, uint8 scale); uint8 GetMobHPScale(uint8 rank, uint8 scale); -uint8 GetMobRBI(uint8 rank, uint8 scale); }; // namespace grade diff --git a/src/map/utils/mobutils.cpp b/src/map/utils/mobutils.cpp index 129f0b034ff..513fdd56efa 100644 --- a/src/map/utils/mobutils.cpp +++ b/src/map/utils/mobutils.cpp @@ -586,10 +586,108 @@ bool CheckSubJobZone(CMobEntity* PMob) /************************************************************************ * * - * Calculate mob stats * + * Calculate base mob HP from job grades and levels * * * ************************************************************************/ +static uint32 CalculateBaseMobHP(uint8 mLvl, uint8 baseHP, uint8 jobScale, uint8 scaleXHP) +{ + // HP formula has multiple parts based on level ranges: + // Levels 1-5: Base HP + scaling per level + // Levels 5-30: Additional scaling with conditional multiplier + // Levels 30+: Increased scaling with special modifiers + if (mLvl == 0) + { + return 0; + } + + const uint8 level5Scaling = std::min(mLvl, static_cast(5)); + const uint8 level30Scaling = std::min(mLvl, static_cast(30)); + + uint32 hp = baseHP + (level5Scaling - 1) * (jobScale + 5); + // Additional bonuses based on scaling thresholds + uint32 riBonus = 0; + switch (level5Scaling) + { + case 0: + case 1: + case 2: + riBonus = 0; + break; + case 3: + riBonus = 3; + break; + case 4: + riBonus = 7; + break; + default: // 5 + riBonus = 14; + break; + } + + hp += riBonus; + + if (mLvl > 5) + { + uint32 level5Bonus = (level30Scaling - 5) * (2 * jobScale + level30Scaling + 6) / 2; + hp += level5Bonus; + } + + if (mLvl > 30) + { + uint32 level30Bonus = (mLvl - 30) * (63 + scaleXHP) + (mLvl - 31) * (jobScale + 6); + hp += level30Bonus; + } + + return hp; +} + +/************************************************************************ + * * + * Calculate subjob HP contribution * + * * + ************************************************************************/ +static uint32 CalculateSubjobHP(uint8 mLvl, uint8 sjJobScale, uint8 sjScaleXHP) +{ + // Subjob HP contribution varies by main job level: + // 50+ = 100% of subjob stats + // 40-49 = 75% of subjob stats + // 31-39 = 50% of subjob stats + // 25-30 = 25% of subjob stats + // 1-24 = 0% of subjob stats + int sjScale = 0; + if (mLvl > 49) + { + sjScale = mLvl; + } + else if (mLvl > 39) + { + sjScale = (mLvl * 3) / 4; + } + else if (mLvl > 30) + { + sjScale = mLvl / 2; + } + else if (mLvl > 24) + { + sjScale = mLvl / 4; + } + + const double sjHp = + sjJobScale * std::max(sjScale - 1, 0) + + (0.5 + 0.5 * sjScaleXHP) * std::max(sjScale - 10, 0) + + std::max(sjScale - 30, 0) + + std::max(sjScale - 50, 0) + + std::max(sjScale - 70, 0); + + return static_cast(std::ceil(sjHp / 2.0)); +} + +/************************************************************************ + * * + * Calculate mob stats * + * * + ************************************************************************/ void CalculateMobStats(CMobEntity* PMob, bool recover) { // Reset modifiers to base values to prevent stacking @@ -614,114 +712,52 @@ void CalculateMobStats(CMobEntity* PMob, bool recover) if (recover == true) { - if (PMob->HPmodifier == 0) - { - uint32 mobHP = 1; // Set mob HP - - uint32 baseMobHP = 0; // Define base mobs hp - uint32 sjHP = 0; // Define base subjob hp - - mJobGrade = grade::GetJobGrade(mJob, 0); // main jobs grade - sJobGrade = grade::GetJobGrade(sJob, 0); // subjobs grade - - uint8 base = 0; // Column for base hp - uint8 jobScale = 1; // Column for job scaling - uint8 scaleX = 2; // Column for modifier scale - - uint8 BaseHP = grade::GetMobHPScale(mJobGrade, base); // Main job base HP - uint8 JobScale = grade::GetMobHPScale(mJobGrade, jobScale); // Main job scaling - uint8 ScaleXHP = grade::GetMobHPScale(mJobGrade, scaleX); // Main job modifier scale - uint8 sjJobScale = grade::GetMobHPScale(sJobGrade, jobScale); // Sub job scaling - uint8 sjScaleXHP = grade::GetMobHPScale(sJobGrade, scaleX); // Sub job modifier scale - - uint8 RIgrade = std::min(mLvl, (uint8)5); // RI Grade - uint8 RIbase = 1; // Column for RI base - - uint8 RI = grade::GetMobRBI(RIgrade, RIbase); // Random Increment addition per grade vs. base - - uint8 mLvlIf = (PMob->GetMLevel() > 5 ? 1 : 0); - uint8 mLvlIf30 = (PMob->GetMLevel() > 30 ? 1 : 0); - uint8 raceScale = 6; - uint8 mLvlScale = 0; + // HP Calculations + mJobGrade = grade::GetJobGrade(mJob, 0); + sJobGrade = grade::GetJobGrade(sJob, 0); - if (mLvl > 0) - { - baseMobHP = BaseHP + (std::min(mLvl, (uint8)5) - 1) * (JobScale + raceScale - 1) + RI + mLvlIf * (std::min(mLvl, (uint8)30) - 5) * (2 * (JobScale + raceScale) + std::min(mLvl, (uint8)30) - 6) / 2 + mLvlIf30 * ((mLvl - 30) * (63 + ScaleXHP) + (mLvl - 31) * (JobScale + raceScale)); - } - - // 50+ = 1 hp sjstats - if (mLvl > 49) - { - mLvlScale = std::floor(mLvl); - } - // 40-49 = 3/4 hp sjstats - else if (mLvl > 39) - { - mLvlScale = std::floor(mLvl * 0.75); - } - // 31-39 = 1/2 hp sjstats - else if (mLvl > 30) - { - mLvlScale = std::floor(mLvl * 0.50); - } - // 25-30 = 1/4 hp sjstats - else if (mLvl > 24) - { - mLvlScale = std::floor(mLvl * 0.25); - } - // 1-24 = no hp sjstats - else - { - mLvlScale = 0; - } + // 1. Retrieve HP scaling values from job grades + // Index 0: Base HP + // Index 1: Job scaling + // Index 2: Modifier scale + uint8 BaseHP = grade::GetMobHPScale(mJobGrade, 0); + uint8 JobScale = grade::GetMobHPScale(mJobGrade, 1); + uint8 ScaleXHP = grade::GetMobHPScale(mJobGrade, 2); + uint8 sjJobScale = grade::GetMobHPScale(sJobGrade, 1); + uint8 sjScaleXHP = grade::GetMobHPScale(sJobGrade, 2); - sjHP = std::ceil((sjJobScale * (std::max((mLvlScale - 1), 0)) + (0.5 + 0.5 * sjScaleXHP) * (std::max(mLvlScale - 10, 0)) + std::max(mLvlScale - 30, 0) + std::max(mLvlScale - 50, 0) + std::max(mLvlScale - 70, 0)) / 2); + // 2. Calculate base HP from main job + uint32 baseMobHP = CalculateBaseMobHP(mLvl, BaseHP, JobScale, ScaleXHP); - // Orcs 5% more hp - if ((PMob->m_Family == 189) || (PMob->m_Family == 190)) - { - mobHP = (baseMobHP + sjHP) * 1.05; - } - // Quadavs 5% less hp - else if (PMob->m_Family == 202) - { - mobHP = (baseMobHP + sjHP) * 0.95; - } - // Manticore family has 50% more HP - else if (PMob->m_Family == 179) - { - mobHP = (baseMobHP + sjHP) * 1.5; - } - else - { - mobHP = baseMobHP + sjHP; - } + // 3. Calculate subjob HP contribution scaled by level range + uint32 sjHP = CalculateSubjobHP(mLvl, sjJobScale, sjScaleXHP); - if (PMob->PMaster != nullptr) - { - mobHP *= 0.30f; // Retail captures have all pets at 30% of the mobs family of the same level - } + // 4. Final mob HP before traits/family modifiers + uint32 mobHP = baseMobHP + sjHP; - PMob->health.maxhp = (int16)(mobHP); - } - else + // 5. Apply pet multiplier (pets are 30% of base mob HP) + if (PMob->PMaster != nullptr) { - PMob->health.maxhp = PMob->HPmodifier; + mobHP = (uint32)(mobHP * 0.30f); } + PMob->health.maxhp = (int16)(mobHP); + + // Apply NM/Mob HP multiplier from settings if (isNM) { - auto hpMultiplierNM = settings::get("map.NM_HP_MULTIPLIER"); - hpMultiplierNM = (hpMultiplierNM >= 0.1f && hpMultiplierNM <= 2.0f) ? hpMultiplierNM : 1.0f; - PMob->health.maxhp = (int32)(PMob->health.maxhp * hpMultiplierNM); + float hpMultiplierNM = settings::get("map.NM_HP_MULTIPLIER"); + hpMultiplierNM = (hpMultiplierNM >= 0.1f && hpMultiplierNM <= 2.0f) ? hpMultiplierNM : 1.0f; + PMob->health.maxhp = (int32)(PMob->health.maxhp * hpMultiplierNM); } else { - auto hpMultiplierMob = settings::get("map.MOB_HP_MULTIPLIER"); - hpMultiplierMob = (hpMultiplierMob >= 0.1f && hpMultiplierMob <= 2.0f) ? hpMultiplierMob : 1.0f; - PMob->health.maxhp = (int32)(PMob->health.maxhp * hpMultiplierMob); + float hpMultiplierMob = settings::get("map.MOB_HP_MULTIPLIER"); + hpMultiplierMob = (hpMultiplierMob >= 0.1f && hpMultiplierMob <= 2.0f) ? hpMultiplierMob : 1.0f; + PMob->health.maxhp = (int32)(PMob->health.maxhp * hpMultiplierMob); } + // MP Calculations bool hasMp = false; switch (mJob) @@ -979,11 +1015,7 @@ void CalculateMobStats(CMobEntity* PMob, bool recover) PMob->m_Behavior |= PMob->getMobMod(MOBMOD_BEHAVIOR); - if (zoneType & ZONE_TYPE::DUNGEON) - { - SetupDungeonMob(PMob); - } - else if (PMob->m_Type & MOBTYPE_BATTLEFIELD) + if (PMob->m_Type & MOBTYPE_BATTLEFIELD) { SetupBattlefieldMob(PMob); } @@ -1331,10 +1363,6 @@ void SetupBattlefieldMob(CMobEntity* PMob) } } -void SetupDungeonMob(CMobEntity* PMob) -{ -} - void SetupEventMob(CMobEntity* PMob) { // event mob types will always have scripted roaming (any mob can have it scripted, but these ALWAYS do) @@ -1734,7 +1762,6 @@ auto InstantiateAlly(uint32 groupid, uint16 zoneID, CInstance* instance) -> CMob PMob->m_SpawnType = rset->get("spawntype"); PMob->m_DropID = rset->get("dropid"); - PMob->HPmodifier = rset->get("HP"); PMob->MPmodifier = rset->get("MP"); PMob->m_minLevel = rset->get("minLevel"); @@ -1907,7 +1934,6 @@ auto InstantiateDynamicMob(uint32 groupid, uint16 groupZoneId, uint16 targetZone PMob->m_SpawnType = rset->get("spawntype"); PMob->m_DropID = rset->get("dropid"); - PMob->HPmodifier = rset->get("HP"); PMob->MPmodifier = rset->get("MP"); uint16 sqlModelID[10]; diff --git a/src/map/utils/mobutils.h b/src/map/utils/mobutils.h index ff278912cde..e22f0c70798 100644 --- a/src/map/utils/mobutils.h +++ b/src/map/utils/mobutils.h @@ -57,7 +57,6 @@ void SetupJob(CMobEntity* PMob); void SetupRoaming(CMobEntity* PMob); void SetupDynamisMob(CMobEntity* PMob); void SetupBattlefieldMob(CMobEntity* PMob); -void SetupDungeonMob(CMobEntity* PMob); void SetupEventMob(CMobEntity* PMob); void SetupNMMob(CMobEntity* PMob); void SetupDungeonInstanceMob(CMobEntity* PMob);