void CalculateStats(CMobEntity * PMob) { // remove all to keep mods in sync PMob->StatusEffectContainer->KillAllStatusEffect(); PMob->restoreModifiers(); PMob->restoreMobModifiers(); bool isNM = PMob->m_Type & MOBTYPE_NOTORIOUS; JOBTYPE mJob = PMob->GetMJob(); JOBTYPE sJob = PMob->GetSJob(); uint8 mLvl = PMob->GetMLevel(); ZONETYPE zoneType = PMob->loc.zone->GetType(); if(PMob->HPmodifier == 0) { float hpScale = PMob->HPscale; if (PMob->getMobMod(MOBMOD_HP_SCALE) != 0) { hpScale = (float)PMob->getMobMod(MOBMOD_HP_SCALE) / 100.0f; } float growth = 1.06f; float petGrowth = 0.75f; float base = 18.0f; //give hp boost every 10 levels after 25 //special boosts at 25 and 50 if(mLvl > 75) { growth = 1.28f; petGrowth = 1.03f; } else if(mLvl > 65) { growth = 1.27f; petGrowth = 1.02f; } else if(mLvl > 55) { growth = 1.25f; petGrowth = 0.99f; } else if(mLvl > 50) { growth = 1.21f; petGrowth = 0.96f; } else if(mLvl > 45) { growth = 1.17f; petGrowth = 0.95f; } else if(mLvl > 35) { growth = 1.14f; petGrowth = 0.92f; } else if(mLvl > 25) { growth = 1.1f; petGrowth = 0.82f; } // pets have lower health if(PMob->PMaster != nullptr) { growth = petGrowth; } PMob->health.maxhp = (int16)(base * pow(mLvl, growth) * hpScale); if(isNM) { PMob->health.maxhp = (int32)(PMob->health.maxhp * 2.0f); if(mLvl > 75){ PMob->health.maxhp = (int32)(PMob->health.maxhp * 2.5f); } } } else { PMob->health.maxhp = PMob->HPmodifier; } if(isNM) { PMob->health.maxhp = (int32)(PMob->health.maxhp * map_config.nm_hp_multiplier); } else { PMob->health.maxhp = (int32)(PMob->health.maxhp * map_config.mob_hp_multiplier); } bool hasMp = false; switch(mJob){ case JOB_PLD: case JOB_WHM: case JOB_BLM: case JOB_RDM: case JOB_DRK: case JOB_BLU: case JOB_SCH: case JOB_SMN: hasMp = true; break; default: break; } switch(sJob){ case JOB_PLD: case JOB_WHM: case JOB_BLM: case JOB_RDM: case JOB_DRK: case JOB_BLU: case JOB_SCH: case JOB_SMN: hasMp = true; break; default: break; } if(PMob->getMobMod(MOBMOD_MP_BASE)) { hasMp = true; } if(hasMp) { float scale = PMob->MPscale; if(PMob->getMobMod(MOBMOD_MP_BASE)) { scale = (float)PMob->getMobMod(MOBMOD_MP_BASE) / 100.0f; } if(PMob->MPmodifier == 0) { PMob->health.maxmp = (int16)(18.2 * pow(mLvl,1.1075) * scale) + 10; if(isNM) { PMob->health.maxmp = (int32)(PMob->health.maxmp * 1.5f); if(mLvl>75) { PMob->health.maxmp = (int32)(PMob->health.maxmp * 1.5f); } } } else { PMob->health.maxmp = PMob->MPmodifier; } if(isNM) { PMob->health.maxmp = (int32)(PMob->health.maxmp * map_config.nm_mp_multiplier); } else { PMob->health.maxmp = (int32)(PMob->health.maxmp * map_config.mob_mp_multiplier); } } PMob->UpdateHealth(); PMob->health.tp = 0; PMob->health.hp = PMob->GetMaxHP(); PMob->health.mp = PMob->GetMaxMP(); PMob->m_Weapons[SLOT_MAIN]->setDamage(GetWeaponDamage(PMob)); //reduce weapon delay of MNK if(PMob->GetMJob()==JOB_MNK){ PMob->m_Weapons[SLOT_MAIN]->resetDelay(); } uint16 fSTR = GetBaseToRank(PMob->strRank, mLvl); uint16 fDEX = GetBaseToRank(PMob->dexRank, mLvl); uint16 fVIT = GetBaseToRank(PMob->vitRank, mLvl); uint16 fAGI = GetBaseToRank(PMob->agiRank, mLvl); uint16 fINT = GetBaseToRank(PMob->intRank, mLvl); uint16 fMND = GetBaseToRank(PMob->mndRank, mLvl); uint16 fCHR = GetBaseToRank(PMob->chrRank, mLvl); uint16 mSTR = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),2), mLvl); uint16 mDEX = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),3), mLvl); uint16 mVIT = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),4), mLvl); uint16 mAGI = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),5), mLvl); uint16 mINT = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),6), mLvl); uint16 mMND = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),7), mLvl); uint16 mCHR = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),8), mLvl); uint16 sSTR = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),2), PMob->GetSLevel()); uint16 sDEX = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),3), PMob->GetSLevel()); uint16 sVIT = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),4), PMob->GetSLevel()); uint16 sAGI = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),5), PMob->GetSLevel()); uint16 sINT = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),6), PMob->GetSLevel()); uint16 sMND = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),7), PMob->GetSLevel()); uint16 sCHR = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),8), PMob->GetSLevel()); if(PMob->GetSLevel() > 15) { sSTR /= 2; sDEX /= 2; sAGI /= 2; sINT /= 2; sMND /= 2; sCHR /= 2; sVIT /= 2; } else { sSTR = 0; sDEX = 0; sAGI = 0; sINT = 0; sMND = 0; sCHR = 0; sVIT = 0; } PMob->stats.STR = fSTR + mSTR + sSTR; PMob->stats.DEX = fDEX + mDEX + sDEX; PMob->stats.VIT = fVIT + mVIT + sVIT; PMob->stats.AGI = fAGI + mAGI + sAGI; PMob->stats.INT = fINT + mINT + sINT; PMob->stats.MND = fMND + mMND + sMND; PMob->stats.CHR = fCHR + mCHR + sCHR; if(isNM) { PMob->stats.STR = (uint16)(PMob->stats.STR * 1.5f * map_config.nm_stat_multiplier); PMob->stats.DEX = (uint16)(PMob->stats.DEX * 1.5f * map_config.nm_stat_multiplier); PMob->stats.VIT = (uint16)(PMob->stats.VIT * 1.5f * map_config.nm_stat_multiplier); PMob->stats.AGI = (uint16)(PMob->stats.AGI * 1.5f * map_config.nm_stat_multiplier); PMob->stats.INT = (uint16)(PMob->stats.INT * 1.5f * map_config.nm_stat_multiplier); PMob->stats.MND = (uint16)(PMob->stats.MND * 1.5f * map_config.nm_stat_multiplier); PMob->stats.CHR = (uint16)(PMob->stats.CHR * 1.5f * map_config.nm_stat_multiplier); } else { PMob->stats.STR = (uint16)(PMob->stats.STR * map_config.mob_stat_multiplier); PMob->stats.DEX = (uint16)(PMob->stats.DEX * map_config.mob_stat_multiplier); PMob->stats.VIT = (uint16)(PMob->stats.VIT * map_config.mob_stat_multiplier); PMob->stats.AGI = (uint16)(PMob->stats.AGI * map_config.mob_stat_multiplier); PMob->stats.INT = (uint16)(PMob->stats.INT * map_config.mob_stat_multiplier); PMob->stats.MND = (uint16)(PMob->stats.MND * map_config.mob_stat_multiplier); PMob->stats.CHR = (uint16)(PMob->stats.CHR * map_config.mob_stat_multiplier); } // special case, give spell list to my pet if(PMob->getMobMod(MOBMOD_PET_SPELL_LIST) && PMob->PPet != nullptr) { // Stubborn_Dredvodd CMobEntity* PPet = (CMobEntity*)PMob->PPet; // give pet spell list PPet->m_SpellListContainer = mobSpellList::GetMobSpellList(PMob->getMobMod(MOBMOD_PET_SPELL_LIST)); } if(PMob->getMobMod(MOBMOD_SPELL_LIST)) { PMob->m_SpellListContainer = mobSpellList::GetMobSpellList(PMob->getMobMod(MOBMOD_SPELL_LIST)); } // cap all stats for mLvl / job for (int i=SKILL_DIV; i <=SKILL_BLU; i++) { uint16 maxSkill = battleutils::GetMaxSkill((SKILLTYPE)i,PMob->GetMJob(),mLvl > 99 ? 99 : mLvl); if (maxSkill != 0) { PMob->WorkingSkills.skill[i] = maxSkill; } else //if the mob is WAR/BLM and can cast spell { // set skill as high as main level, so their spells won't get resisted uint16 maxSubSkill = battleutils::GetMaxSkill((SKILLTYPE)i,PMob->GetSJob(),mLvl > 99 ? 99 : mLvl); if (maxSubSkill != 0) { PMob->WorkingSkills.skill[i] = maxSubSkill; } } } for (int i=SKILL_H2H; i <=SKILL_STF; i++) { uint16 maxSkill = battleutils::GetMaxSkill(3, mLvl > 99 ? 99 : mLvl); if (maxSkill != 0) { PMob->WorkingSkills.skill[i] = maxSkill; } } PMob->addModifier(Mod::DEF, GetBase(PMob,PMob->defRank)); PMob->addModifier(Mod::EVA, GetEvasion(PMob)); PMob->addModifier(Mod::ATT, GetBase(PMob,PMob->attRank)); PMob->addModifier(Mod::ACC, GetBase(PMob,PMob->accRank)); //natural magic evasion PMob->addModifier(Mod::MEVA, GetMagicEvasion(PMob)); // add traits for sub and main battleutils::AddTraits(PMob, traits::GetTraits(mJob), mLvl); battleutils::AddTraits(PMob, traits::GetTraits(PMob->GetSJob()), PMob->GetSLevel()); SetupJob(PMob); SetupRoaming(PMob); // All beastmen drop gil if (PMob->m_EcoSystem == SYSTEM_BEASTMEN) { PMob->defaultMobMod(MOBMOD_GIL_BONUS, 100); } if (PMob->PMaster != nullptr) { SetupPetSkills(PMob); } PMob->m_Behaviour |= PMob->getMobMod(MOBMOD_BEHAVIOR); if(zoneType == ZONETYPE_DUNGEON) { SetupDungeonMob(PMob); } else if(zoneType == ZONETYPE_BATTLEFIELD) { SetupBattlefieldMob(PMob); } else if(zoneType == ZONETYPE_DYNAMIS) { SetupDynamisMob(PMob); } if(PMob->m_Type & MOBTYPE_NOTORIOUS) { SetupNMMob(PMob); } if(PMob->m_Type & MOBTYPE_EVENT) { SetupEventMob(PMob); } if(PMob->m_Family == 335) { SetupMaat(PMob); } if (PMob->CanStealGil()) { PMob->ResetGilPurse(); } if(PMob->m_Type & MOBTYPE_EVENT || PMob->m_Type & MOBTYPE_FISHED || PMob->m_Type & MOBTYPE_BATTLEFIELD || zoneType == ZONETYPE_BATTLEFIELD || zoneType == ZONETYPE_DYNAMIS) { PMob->setMobMod(MOBMOD_CHARMABLE, 0); } // Check for possible miss-setups if (PMob->getMobMod(MOBMOD_SPECIAL_SKILL) != 0 && PMob->getMobMod(MOBMOD_SPECIAL_COOL) == 0) { ShowError("Mobutils::CalculateStats Mob (%s, %d) with special skill but no cool down set!\n", PMob->GetName(), PMob->id); } if (PMob->SpellContainer->HasSpells() && PMob->getMobMod(MOBMOD_MAGIC_COOL) == 0) { ShowError("Mobutils::CalculateStats Mob (%s, %d) with magic but no cool down set!\n", PMob->GetName(), PMob->id); } if (PMob->m_Detects == 0) { ShowError("Mobutils::CalculateStats Mob (%s, %d, %d) has no detection methods!\n", PMob->GetName(), PMob->id, PMob->m_Family); } }
void CalculateStats(CMobEntity * PMob) { // remove all to keep mods in sync PMob->StatusEffectContainer->KillAllStatusEffect(); PMob->restoreModifiers(); PMob->restoreMobModifiers(); bool isNM = PMob->m_Type & MOBTYPE_NOTORIOUS; JOBTYPE mJob = PMob->GetMJob(); JOBTYPE sJob = PMob->GetSJob(); uint8 mLvl = PMob->GetMLevel(); ZONETYPE zoneType = PMob->loc.zone->GetType(); if(PMob->HPmodifier == 0) { float hpScale = PMob->HPscale; if (PMob->getMobMod(MOBMOD_HP_SCALE) != 0) { hpScale = (float)PMob->getMobMod(MOBMOD_HP_SCALE) / 100.0f; } float growth = 1.06; float petGrowth = 0.75; float base = 18.0; //give hp boost every 10 levels after 25 //special boosts at 25 and 50 if(mLvl > 75) { growth = 1.28; petGrowth = 1.03; } else if(mLvl > 65) { growth = 1.27; petGrowth = 1.02; } else if(mLvl > 55) { growth = 1.25; petGrowth = 0.99; } else if(mLvl > 50) { growth = 1.21; petGrowth = 0.96; } else if(mLvl > 45) { growth = 1.17; petGrowth = 0.95; } else if(mLvl > 35) { growth = 1.14; petGrowth = 0.92; } else if(mLvl > 25) { growth = 1.1; petGrowth = 0.82; } // pets have lower health if(PMob->PMaster != nullptr) { growth = petGrowth; } PMob->health.maxhp = (int16)(base * pow(mLvl, growth) * hpScale); if(isNM) { PMob->health.maxhp *= 2.0; if(mLvl > 75){ PMob->health.maxhp *= 2.5; } } } else { PMob->health.maxhp = PMob->HPmodifier; } if(isNM) { PMob->health.maxhp *= map_config.nm_hp_multiplier; } else { PMob->health.maxhp *= map_config.mob_hp_multiplier; } bool hasMp = false; switch(mJob){ case JOB_PLD: case JOB_WHM: case JOB_BLM: case JOB_RDM: case JOB_DRK: case JOB_BLU: case JOB_SCH: case JOB_SMN: hasMp = true; break; } switch(sJob){ case JOB_PLD: case JOB_WHM: case JOB_BLM: case JOB_RDM: case JOB_DRK: case JOB_BLU: case JOB_SCH: case JOB_SMN: hasMp = true; break; } if(PMob->getMobMod(MOBMOD_MP_BASE)) { hasMp = true; } if(hasMp) { float scale = PMob->MPscale; if(PMob->getMobMod(MOBMOD_MP_BASE)) { scale = (float)PMob->getMobMod(MOBMOD_MP_BASE) / 100.0f; } if(PMob->MPmodifier == 0) { PMob->health.maxmp = (int16)(18.2 * pow(mLvl,1.1075) * scale) + 10; if(isNM) { PMob->health.maxmp *= 1.5; if(mLvl>75) { PMob->health.maxmp *= 1.5; } } } else { PMob->health.maxmp = PMob->MPmodifier; } if(isNM) { PMob->health.maxhp *= map_config.nm_mp_multiplier; } else { PMob->health.maxhp *= map_config.mob_mp_multiplier; } } PMob->UpdateHealth(); PMob->health.tp = 0; PMob->health.hp = PMob->GetMaxHP(); PMob->health.mp = PMob->GetMaxMP(); PMob->m_Weapons[SLOT_MAIN]->setDamage(GetWeaponDamage(PMob)); //reduce weapon delay of MNK if(PMob->GetMJob()==JOB_MNK){ PMob->m_Weapons[SLOT_MAIN]->resetDelay(); } uint16 fSTR = GetBaseToRank(PMob->strRank, mLvl); uint16 fDEX = GetBaseToRank(PMob->dexRank, mLvl); uint16 fVIT = GetBaseToRank(PMob->vitRank, mLvl); uint16 fAGI = GetBaseToRank(PMob->agiRank, mLvl); uint16 fINT = GetBaseToRank(PMob->intRank, mLvl); uint16 fMND = GetBaseToRank(PMob->mndRank, mLvl); uint16 fCHR = GetBaseToRank(PMob->chrRank, mLvl); uint16 mSTR = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),2), mLvl); uint16 mDEX = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),3), mLvl); uint16 mVIT = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),4), mLvl); uint16 mAGI = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),5), mLvl); uint16 mINT = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),6), mLvl); uint16 mMND = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),7), mLvl); uint16 mCHR = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),8), mLvl); uint16 sSTR = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),2), PMob->GetSLevel()); uint16 sDEX = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),3), PMob->GetSLevel()); uint16 sVIT = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),4), PMob->GetSLevel()); uint16 sAGI = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),5), PMob->GetSLevel()); uint16 sINT = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),6), PMob->GetSLevel()); uint16 sMND = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),7), PMob->GetSLevel()); uint16 sCHR = GetBaseToRank(grade::GetJobGrade(PMob->GetSJob(),8), PMob->GetSLevel()); if(PMob->GetSLevel() > 15) { sSTR /= 2; sDEX /= 2; sAGI /= 2; sINT /= 2; sMND /= 2; sCHR /= 2; sVIT /= 2; } else { sSTR = 0; sDEX = 0; sAGI = 0; sINT = 0; sMND = 0; sCHR = 0; sVIT = 0; } PMob->stats.STR = fSTR + mSTR + sSTR; PMob->stats.DEX = fDEX + mDEX + sDEX; PMob->stats.VIT = fVIT + mVIT + sVIT; PMob->stats.AGI = fAGI + mAGI + sAGI; PMob->stats.INT = fINT + mINT + sINT; PMob->stats.MND = fMND + mMND + sMND; PMob->stats.CHR = fCHR + mCHR + sCHR; if(isNM) { PMob->stats.STR *= (1.5 * map_config.nm_stat_multiplier); PMob->stats.DEX *= (1.5 * map_config.nm_stat_multiplier); PMob->stats.VIT *= (1.5 * map_config.nm_stat_multiplier); PMob->stats.AGI *= (1.5 * map_config.nm_stat_multiplier); PMob->stats.INT *= (1.5 * map_config.nm_stat_multiplier); PMob->stats.MND *= (1.5 * map_config.nm_stat_multiplier); PMob->stats.CHR *= (1.5 * map_config.nm_stat_multiplier); } else { PMob->stats.STR *= map_config.mob_stat_multiplier; PMob->stats.DEX *= map_config.mob_stat_multiplier; PMob->stats.VIT *= map_config.mob_stat_multiplier; PMob->stats.AGI *= map_config.mob_stat_multiplier; PMob->stats.INT *= map_config.mob_stat_multiplier; PMob->stats.MND *= map_config.mob_stat_multiplier; PMob->stats.CHR *= map_config.mob_stat_multiplier; } // special case, give spell list to my pet if(PMob->getMobMod(MOBMOD_PET_SPELL_LIST) && PMob->PPet != nullptr) { // Stubborn_Dredvodd CMobEntity* PPet = (CMobEntity*)PMob->PPet; // give pet spell list PPet->m_SpellListContainer = mobSpellList::GetMobSpellList(PMob->getMobMod(MOBMOD_PET_SPELL_LIST)); } if(PMob->getMobMod(MOBMOD_SPELL_LIST)) { PMob->m_SpellListContainer = mobSpellList::GetMobSpellList(PMob->getMobMod(MOBMOD_SPELL_LIST)); } // cap all stats for mLvl / job for (int i=SKILL_DIV; i <=SKILL_BLU; i++) { uint16 maxSkill = battleutils::GetMaxSkill((SKILLTYPE)i,PMob->GetMJob(),mLvl > 99 ? 99 : mLvl); if (maxSkill != 0) { PMob->WorkingSkills.skill[i] = maxSkill; } else //if the mob is WAR/BLM and can cast spell { // set skill as high as main level, so their spells won't get resisted uint16 maxSubSkill = battleutils::GetMaxSkill((SKILLTYPE)i,PMob->GetSJob(),mLvl > 99 ? 99 : mLvl); if (maxSubSkill != 0) { PMob->WorkingSkills.skill[i] = maxSubSkill; } } } PMob->addModifier(MOD_DEF, GetBase(PMob,PMob->defRank)); PMob->addModifier(MOD_EVA, GetEvasion(PMob)); PMob->addModifier(MOD_ATT, GetBase(PMob,PMob->attRank)); PMob->addModifier(MOD_ACC, GetBase(PMob,PMob->accRank)); //natural magic evasion PMob->addModifier(MOD_MEVA, GetMagicEvasion(PMob)); // add traits for sub and main battleutils::AddTraits(PMob, traits::GetTraits(mJob), mLvl); battleutils::AddTraits(PMob, traits::GetTraits(PMob->GetSJob()), PMob->GetSLevel()); SetupJob(PMob); SetupRoaming(PMob); if (PMob->PMaster != nullptr) { SetupPetSkills(PMob); } PMob->m_Behaviour |= PMob->getMobMod(MOBMOD_BEHAVIOR); if(zoneType == ZONETYPE_DUNGEON) { SetupDungeonMob(PMob); } else if(zoneType == ZONETYPE_BATTLEFIELD) { SetupBattlefieldMob(PMob); } else if(zoneType == ZONETYPE_DYNAMIS) { SetupDynamisMob(PMob); } if(PMob->m_Type & MOBTYPE_NOTORIOUS) { SetupNMMob(PMob); } if(PMob->m_Type & MOBTYPE_EVENT) { SetupEventMob(PMob); } if(PMob->m_Family == 335) { SetupMaat(PMob); } }