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(); // set a random job if(PMob->getMobMod(MOBMOD_RAND_JOB)) { bool firstOption = WELL512::irand()%2 == 0; SKILLTYPE meleeSkill = SKILL_NON; JOBTYPE job = JOB_NON; uint16 spellList = 0; // skeleton if(PMob->m_Family == 227) { if(firstOption) { // blm job = JOB_BLM; // taken from mob_pools modelid int8 look[23] = {0x00, 0x00, 0x34, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; memcpy(&PMob->look, look, 23); spellList = 28; // undead spell list meleeSkill = SKILL_SYH; } else { // war job = JOB_WAR; int8 look[23] = {0x00, 0x00, 0x3C, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; memcpy(&PMob->look, look, 23); meleeSkill = SKILL_AXE; } } // evil weapon else if(PMob->m_Family == 110 || PMob->m_Family == 111) { if(firstOption) { // rdm job = JOB_RDM; meleeSkill = SKILL_SWD; spellList = 42; // evil weapon spell list } else { // war job = JOB_WAR; meleeSkill = SKILL_AXE; } } else { ShowError("mobutils::CalculateStats Undefined family is being set as a random job %d\n", PMob->m_Family); } PMob->SetMJob(job); PMob->SetSJob(job); PMob->m_SpellListContainer = mobSpellList::GetMobSpellList(spellList); PMob->m_Weapons[SLOT_MAIN]->setSkillType(meleeSkill); } 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(); // event mob types will always have custom roaming if(PMob->m_Type & MOBTYPE_EVENT) { PMob->m_roamFlags |= ROAMFLAG_EVENT; PMob->m_maxRoamDistance = 0.2f; // always go back to spawn } if(isNM) { // enmity range is larger PMob->m_enmityRange = 28; } if(mJob == JOB_DRG) { // drg can use 2 hour multiple times PMob->setMobMod(MOBMOD_2HOUR_MULTI, 1); } if(PMob->HPmodifier == 0){ float growth = 1.06; float base = 18.0; uint8 lvl = PMob->GetMLevel(); //give hp boost every 10 levels after 25 //special boosts at 25 and 50 if(lvl > 75){ growth = 1.28; }else if(lvl > 65){ growth = 1.27; } else if(lvl > 55){ growth = 1.25; } else if(lvl > 50){ growth = 1.21; } else if(lvl > 45){ growth = 1.17; } else if(lvl > 35){ growth = 1.14; } else if(lvl > 25){ growth = 1.1; } // pets have lower health if(PMob->PMaster != NULL) { growth = 0.95; } PMob->health.maxhp = (int16)(base * pow(lvl, growth) * PMob->HPscale); if(isNM) { PMob->health.maxhp *= 2.0; if(PMob->GetMLevel() > 75){ PMob->health.maxhp *= 2.5; } } } else { PMob->health.maxhp = PMob->HPmodifier; } 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(PMob->GetMLevel(),1.1075) * scale) + 10; if(isNM){ PMob->health.maxmp *= 1.5; if(PMob->GetMLevel()>75){ PMob->health.maxmp *= 1.5; } } } else { PMob->health.maxmp = PMob->MPmodifier; } } 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, PMob->GetMLevel()); uint16 fDEX = GetBaseToRank(PMob->dexRank, PMob->GetMLevel()); uint16 fVIT = GetBaseToRank(PMob->vitRank, PMob->GetMLevel()); uint16 fAGI = GetBaseToRank(PMob->agiRank, PMob->GetMLevel()); uint16 fINT = GetBaseToRank(PMob->intRank, PMob->GetMLevel()); uint16 fMND = GetBaseToRank(PMob->mndRank, PMob->GetMLevel()); uint16 fCHR = GetBaseToRank(PMob->chrRank, PMob->GetMLevel()); uint16 mSTR = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),2), PMob->GetMLevel()); uint16 mDEX = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),3), PMob->GetMLevel()); uint16 mVIT = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),4), PMob->GetMLevel()); uint16 mAGI = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),5), PMob->GetMLevel()); uint16 mINT = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),6), PMob->GetMLevel()); uint16 mMND = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),7), PMob->GetMLevel()); uint16 mCHR = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),8), PMob->GetMLevel()); 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; PMob->stats.DEX *= 1.5; PMob->stats.VIT *= 1.5; PMob->stats.AGI *= 1.5; PMob->stats.INT *= 1.5; PMob->stats.MND *= 1.5; PMob->stats.CHR *= 1.5; } // aggro mobs move around a bit more often if(PMob->m_Aggro != AGGRO_NONE && PMob->speed != 0) { PMob->setMobMod(MOBMOD_ROAM_COOL, 20); } // setup special ability if(mJob == JOB_RNG) { // giga if(PMob->m_Family == 126 && PMob->m_Family <= 130) { PMob->setMobMod(MOBMOD_SPECIAL_COOL, 35); // catapult PMob->setMobMod(MOBMOD_SPECIAL_SKILL, 402); } else { // all other rangers PMob->setMobMod(MOBMOD_SPECIAL_COOL, 20); PMob->setMobMod(MOBMOD_SPECIAL_SKILL, 16); } } else if(mJob == JOB_NIN) { PMob->setMobMod(MOBMOD_SPECIAL_COOL, 35); PMob->setMobMod(MOBMOD_SPECIAL_SKILL, 16); } else if(mJob == JOB_DRG && PMob->m_Family != 193) { PMob->setMobMod(MOBMOD_SPECIAL_COOL, 45); // sahigans if(PMob->m_Family == 213) { PMob->setMobMod(MOBMOD_SPECIAL_SKILL, 514); } else { // all other dragoons PMob->setMobMod(MOBMOD_SPECIAL_SKILL, 808); } } // all pets must be defined in the mob_pets file // set recast times for summoning pets if(PMob->loc.zone->GetType() != ZONETYPE_DYNAMIS) { if(mJob == JOB_BST) { PMob->setMobMod(MOBMOD_SPECIAL_COOL, 100); PMob->setMobMod(MOBMOD_SPECIAL_SKILL, 761); } else if(mJob == JOB_DRG && !isNM) { // only drgs in 3rd expansion calls wyvern as non-NM // include fomors if(PMob->loc.zone->GetContinentID() == THE_ARADJIAH_CONTINENT || PMob->m_Family == 115) { // 20 min recast PMob->setMobMod(MOBMOD_SPECIAL_SKILL, 476); PMob->setMobMod(MOBMOD_SPECIAL_COOL, 720); } } else if(mJob == JOB_PUP) { PMob->setMobMod(MOBMOD_SPECIAL_SKILL, 1645); PMob->setMobMod(MOBMOD_SPECIAL_COOL, 720); } } // ambush antlions if(PMob->m_Family == 357) { PMob->setMobMod(MOBMOD_SPECIAL_SKILL, 22); PMob->setMobMod(MOBMOD_SPECIAL_COOL, 1); PMob->m_specialFlags |= SPECIALFLAG_HIDDEN; PMob->m_roamFlags |= ROAMFLAG_AMBUSH; } // Phuabo if(PMob->m_Family == 194) { PMob->m_roamFlags |= ROAMFLAG_STEALTH; } // Yovra if(PMob->m_Family == 271) { PMob->m_roamFlags |= ROAMFLAG_STEALTH; } // Chigoe if(PMob->m_Family == 64) { PMob->m_roamFlags |= ROAMFLAG_STEALTH; } // Amphiptere if(PMob->m_Family == 6) { PMob->m_roamFlags |= ROAMFLAG_STEALTH; } if(PMob->m_Family == 362) { // rapido doesn't stop PMob->m_roamFlags |= ROAMFLAG_IGNORE; } // handle standback // mobs that stand back: blm, whm, rng, cor, nin if(mJob == JOB_RNG) { // giga if(PMob->m_Family == 126 && PMob->m_Family <= 130) { PMob->setMobMod(MOBMOD_STANDBACK_TIME, 20); } else if(PMob->m_Family == 199) { // they stay back forever PMob->setMobMod(MOBMOD_STANDBACK_TIME, 90); } else { PMob->setMobMod(MOBMOD_STANDBACK_TIME, 60); } } else if(mJob == JOB_COR) { PMob->setMobMod(MOBMOD_STANDBACK_TIME, 60); } else if(mJob == JOB_BLM) { PMob->setMobMod(MOBMOD_STANDBACK_TIME, 42); } else if(mJob == JOB_WHM) { PMob->setMobMod(MOBMOD_STANDBACK_TIME, 32); } else if(mJob == JOB_NIN) { PMob->setMobMod(MOBMOD_STANDBACK_TIME, 25); } // mobs with zero speed cannot standback if(PMob->speed == 0) { PMob->setMobMod(MOBMOD_STANDBACK_TIME, 0); } // special case, give spell list to my pet if(PMob->getMobMod(MOBMOD_PET_SPELL_LIST) && PMob->PPet != NULL) { // 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)); } // TODO: this should be put into its own column // has not been decided where yet if(PMob->m_Family == 258 || PMob->m_Family == 276) { // makes worms roam by going into ground / back up PMob->m_roamFlags |= ROAMFLAG_WORM; } if(PMob->m_Aggro != AGGRO_NONE && PMob->loc.zone->GetType() == ZONETYPE_OUTDOORS) { PMob->m_roamFlags |= ROAMFLAG_MEDIUM; } else { PMob->m_roamFlags |= ROAMFLAG_SMALL; } if(PMob->m_roamFlags & ROAMFLAG_AMBUSH) { // always stay close to spawn PMob->m_maxRoamDistance = 2.0f; } // cap all stats for lvl / job for (int i=SKILL_DIV; i <=SKILL_BLU; i++) { uint16 maxSkill = battleutils::GetMaxSkill((SKILLTYPE)i,PMob->GetMJob(),PMob->GetMLevel()); 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(),PMob->GetMLevel()); if (maxSubSkill != 0) { PMob->WorkingSkills.skill[i] = maxSubSkill; } } } if(zoneType == ZONETYPE_DYNAMIS || zoneType == ZONETYPE_BATTLEFIELD) { // never despawn PMob->SetDespawnTimer(0); // do not roam around PMob->m_roamFlags |= ROAMFLAG_EVENT; PMob->m_maxRoamDistance = 0.5f; } if((zoneType == ZONETYPE_BATTLEFIELD) && (PMob->m_bcnmID != 864) && (PMob->m_bcnmID != 704)) { // bcnmID 864 (desires of emptiness) and 704 (darkness named) don't superlink // force all mobs in same instance to superlink // plus one in case id is zero PMob->setMobMod(MOBMOD_SUPERLINK, PMob->m_battlefieldID); } uint8 evaRank = battleutils::GetSkillRank(SKILL_EVA, PMob->GetMJob()); PMob->addModifier(MOD_DEF, GetBase(PMob,PMob->defRank)); PMob->addModifier(MOD_EVA, GetBase(PMob,evaRank)); PMob->addModifier(MOD_ATT, GetBase(PMob,PMob->attRank)); PMob->addModifier(MOD_ACC, GetBase(PMob,PMob->accRank)); SKILLTYPE mEvasionRating = SKILL_ELE; if(mLvl > 83) { mEvasionRating = SKILL_SWD; } //natural magic evasion PMob->addModifier(MOD_MEVA, battleutils::GetMaxSkill(mEvasionRating, JOB_RDM, mLvl)); if((PMob->m_Type & MOBTYPE_NOTORIOUS) && mJob == JOB_WHM && mLvl >= 25) { // whm nms have stronger regen effect PMob->addModifier(MOD_REGEN, PMob->GetMLevel()/4); } // add traits for sub and main AddTraits(PMob, mJob, mLvl); AddTraits(PMob, PMob->GetSJob(), PMob->GetSLevel()); }
void LoadAutomatonStats(CCharEntity* PMaster, CPetEntity* PPet, Pet_t* petStats) { // Объявление переменных, нужных для рассчета. float raceStat = 0; // конечное число HP для уровня на основе расы. float jobStat = 0; // конечное число HP для уровня на основе первичной профессии. float sJobStat = 0; // коенчное число HP для уровня на основе вторичной профессии. int32 bonusStat = 0; // бонусное число HP которое добавляется при соблюдении некоторых условий. int32 baseValueColumn = 0; // номер колонки с базовым количеством HP int32 scaleTo60Column = 1; // номер колонки с модификатором до 60 уровня int32 scaleOver30Column = 2; // номер колонки с модификатором после 30 уровня int32 scaleOver60Column = 3; // номер колонки с модификатором после 60 уровня int32 scaleOver75Column = 4; // номер колонки с модификатором после 75 уровня int32 scaleOver60 = 2; // номер колонки с модификатором для расчета MP после 60 уровня int32 scaleOver75 = 3; // номер колонки с модификатором для расчета Статов после 75-го уровня uint8 grade; uint8 mlvl = PPet->GetMLevel(); uint8 slvl = PPet->GetSLevel(); JOBTYPE mjob = PPet->GetMJob(); JOBTYPE sjob = PPet->GetSJob(); // Расчет прироста HP от main job int32 mainLevelOver30 = dsp_cap(mlvl - 30, 0, 30); // Расчет условия +1HP каждый лвл после 30 уровня int32 mainLevelUpTo60 = (mlvl < 60 ? mlvl - 1 : 59 ); // Первый режим рассчета до 60 уровня (Используется так же и для MP) int32 mainLevelOver60To75 = dsp_cap(mlvl - 60, 0, 15); // Второй режим расчета после 60 уровня int32 mainLevelOver75 = (mlvl < 75 ? 0 : mlvl - 75); // Третий режим расчета после 75 уровня //Расчет бонусного количества HP int32 mainLevelOver10 = (mlvl < 10 ? 0 : mlvl - 10); // +2HP на каждом уровне после 10 int32 mainLevelOver50andUnder60 = dsp_cap(mlvl - 50, 0, 10); // +2HP на каждом уровне в промежутке от 50 до 60 уровня int32 mainLevelOver60 = (mlvl < 60 ? 0 : mlvl - 60); // Расчет raceStat jobStat bonusStat sJobStat // Расчет по расе grade = 4; raceStat = grade::GetHPScale(grade,baseValueColumn) + (grade::GetHPScale(grade,scaleTo60Column) * mainLevelUpTo60) + (grade::GetHPScale(grade,scaleOver30Column) * mainLevelOver30) + (grade::GetHPScale(grade,scaleOver60Column) * mainLevelOver60To75) + (grade::GetHPScale(grade,scaleOver75Column) * mainLevelOver75); // raceStat = (int32)(statScale[grade][baseValueColumn] + statScale[grade][scaleTo60Column] * (mlvl - 1)); // Расчет по main job grade = grade::GetJobGrade(mjob,0); jobStat = grade::GetHPScale(grade,baseValueColumn) + (grade::GetHPScale(grade,scaleTo60Column) * mainLevelUpTo60) + (grade::GetHPScale(grade,scaleOver30Column) * mainLevelOver30) + (grade::GetHPScale(grade,scaleOver60Column) * mainLevelOver60To75) + (grade::GetHPScale(grade,scaleOver75Column) * mainLevelOver75); // Расчет бонусных HP bonusStat = (mainLevelOver10 + mainLevelOver50andUnder60) * 2; PPet->health.maxhp = (int16)(raceStat + jobStat + bonusStat + sJobStat) * petStats->HPscale; PPet->health.hp = PPet->health.maxhp; //Начало расчера MP raceStat = 0; jobStat = 0; sJobStat = 0; // Расчет MP расе. grade = 4; //Если у main job нет МП рейтинга, расчитиваем расовый бонус на основе уровня subjob уровня(при условии, что у него есть МП рейтинг) if (!(grade::GetJobGrade(mjob,1) == 0 && grade::GetJobGrade(sjob,1) == 0)) { //Расчет нормального расового бонуса raceStat = grade::GetMPScale(grade,0) + grade::GetMPScale(grade,scaleTo60Column) * mainLevelUpTo60 + grade::GetMPScale(grade,scaleOver60) * mainLevelOver60; } //Для главной профессии grade = grade::GetJobGrade(mjob,1); if (grade > 0) { jobStat = grade::GetMPScale(grade,0) + grade::GetMPScale(grade,scaleTo60Column) * mainLevelUpTo60 + grade::GetMPScale(grade,scaleOver60) * mainLevelOver60; } grade = grade::GetJobGrade(sjob,1); if (grade > 0) { sJobStat = grade::GetMPScale(grade,0) + grade::GetMPScale(grade,scaleTo60Column) * mainLevelUpTo60 + grade::GetMPScale(grade,scaleOver60) * mainLevelOver60; } PPet->health.maxmp = (int16)(raceStat + jobStat + sJobStat) * petStats->MPscale; PPet->health.mp = PPet->health.maxmp; uint16 fSTR = GetBaseToRank(petStats->strRank, PPet->GetMLevel()); uint16 fDEX = GetBaseToRank(petStats->dexRank, PPet->GetMLevel()); uint16 fVIT = GetBaseToRank(petStats->vitRank, PPet->GetMLevel()); uint16 fAGI = GetBaseToRank(petStats->agiRank, PPet->GetMLevel()); uint16 fINT = GetBaseToRank(petStats->intRank, PPet->GetMLevel()); uint16 fMND = GetBaseToRank(petStats->mndRank, PPet->GetMLevel()); uint16 fCHR = GetBaseToRank(petStats->chrRank, PPet->GetMLevel()); uint16 mSTR = GetBaseToRank(grade::GetJobGrade(PPet->GetMJob(),2), PPet->GetMLevel()); uint16 mDEX = GetBaseToRank(grade::GetJobGrade(PPet->GetMJob(),3), PPet->GetMLevel()); uint16 mVIT = GetBaseToRank(grade::GetJobGrade(PPet->GetMJob(),4), PPet->GetMLevel()); uint16 mAGI = GetBaseToRank(grade::GetJobGrade(PPet->GetMJob(),5), PPet->GetMLevel()); uint16 mINT = GetBaseToRank(grade::GetJobGrade(PPet->GetMJob(),6), PPet->GetMLevel()); uint16 mMND = GetBaseToRank(grade::GetJobGrade(PPet->GetMJob(),7), PPet->GetMLevel()); uint16 mCHR = GetBaseToRank(grade::GetJobGrade(PPet->GetMJob(),8), PPet->GetMLevel()); uint16 sSTR = GetBaseToRank(grade::GetJobGrade(PPet->GetSJob(),2), PPet->GetSLevel()); uint16 sDEX = GetBaseToRank(grade::GetJobGrade(PPet->GetSJob(),3), PPet->GetSLevel()); uint16 sVIT = GetBaseToRank(grade::GetJobGrade(PPet->GetSJob(),4), PPet->GetSLevel()); uint16 sAGI = GetBaseToRank(grade::GetJobGrade(PPet->GetSJob(),5), PPet->GetSLevel()); uint16 sINT = GetBaseToRank(grade::GetJobGrade(PPet->GetSJob(),6), PPet->GetSLevel()); uint16 sMND = GetBaseToRank(grade::GetJobGrade(PPet->GetSJob(),7), PPet->GetSLevel()); uint16 sCHR = GetBaseToRank(grade::GetJobGrade(PPet->GetSJob(),8), PPet->GetSLevel()); PPet->stats.STR = fSTR + mSTR + sSTR; PPet->stats.DEX = fDEX + mDEX + sDEX; PPet->stats.VIT = fVIT + mVIT + sVIT; PPet->stats.AGI = fAGI + mAGI + sAGI; PPet->stats.INT = fINT + mINT + sINT; PPet->stats.MND = fMND + mMND + sMND; PPet->stats.CHR = fCHR + mCHR + sCHR; PPet->m_Weapons[SLOT_MAIN]->setDelay(floor(1000.0f*(petStats->cmbDelay/60.0f))); //every pet should use this eventually PPet->m_Weapons[SLOT_MAIN]->setDamage(1); //temp PPet->setModifier(MOD_ATT, PMaster->GetSkill(SKILL_AME) > puppetutils::getSkillCap((CCharEntity*)PMaster, SKILL_AME) ? puppetutils::getSkillCap((CCharEntity*)PMaster, SKILL_AME) : PMaster->GetSkill(SKILL_AME) ); if (PMaster->GetSkill(SKILL_AME) > puppetutils::getSkillCap((CCharEntity*)PMaster, SKILL_AME)) { PPet->setModifier(MOD_ACC, puppetutils::getSkillCap((CCharEntity*)PMaster, SKILL_AME) > 200 ? ((puppetutils::getSkillCap((CCharEntity*)PMaster, SKILL_AME) - 200) * 0.9) + 200 : puppetutils::getSkillCap((CCharEntity*)PMaster, SKILL_AME)); } else { PPet->setModifier(MOD_ACC, PMaster->GetSkill(SKILL_AME) > 200 ? ((PMaster->GetSkill(SKILL_AME) - 200) * 0.9) + 200 : PMaster->GetSkill(SKILL_AME)); } PPet->setModifier(MOD_RATT, PMaster->GetSkill(SKILL_ARA) > puppetutils::getSkillCap((CCharEntity*)PMaster, SKILL_ARA) ? puppetutils::getSkillCap((CCharEntity*)PMaster, SKILL_ARA) : PMaster->GetSkill(SKILL_ARA) ); if (PMaster->GetSkill(SKILL_ARA) > puppetutils::getSkillCap((CCharEntity*)PMaster, SKILL_ARA)) { PPet->setModifier(MOD_RACC, puppetutils::getSkillCap((CCharEntity*)PMaster, SKILL_ARA) > 200 ? ((puppetutils::getSkillCap((CCharEntity*)PMaster, SKILL_ARA) - 200) * 0.9) + 200 : puppetutils::getSkillCap((CCharEntity*)PMaster, SKILL_ARA)); } else { PPet->setModifier(MOD_RACC, PMaster->GetSkill(SKILL_ARA) > 200 ? ((PMaster->GetSkill(SKILL_ARA) - 200) * 0.9) + 200 : PMaster->GetSkill(SKILL_ARA)); } //temp eva/def (probably frame based) PPet->setModifier(MOD_EVA, battleutils::GetMaxSkill(SKILL_H2H,JOB_WAR,PPet->GetMLevel())); PPet->setModifier(MOD_DEF, battleutils::GetMaxSkill(SKILL_H2H,JOB_WAR,PPet->GetMLevel())); }
void LoadJugStats(CPetEntity* PMob, Pet_t* petStats){ //follows monster formulas but jugs have no subjob float growth = 1.0; uint8 lvl = PMob->GetMLevel(); //give hp boost every 10 levels after 25 //special boosts at 25 and 50 if(lvl > 75){ growth = 1.25; }else if(lvl > 65){ growth = 1.24; } else if(lvl > 55){ growth = 1.22; } else if(lvl > 50){ growth = 1.18; } else if(lvl > 45){ growth = 1.14; } else if(lvl > 35){ growth = 1.11; } else if(lvl > 25){ growth = 1.07; } PMob->health.maxhp = (int16)(18.0 * pow(lvl, growth) * petStats->HPscale); switch(PMob->GetMJob()){ case JOB_PLD: case JOB_WHM: case JOB_BLM: case JOB_RDM: case JOB_DRK: case JOB_BLU: case JOB_SCH: PMob->health.maxmp = (int16)(18.2 * pow(lvl,1.1075) * petStats->MPscale); break; } PMob->speed = petStats->speed; PMob->speedsub = petStats->speed; PMob->UpdateHealth(); PMob->health.tp = 0; PMob->health.hp = PMob->GetMaxHP(); PMob->health.mp = PMob->GetMaxMP(); uint16 evaRank = battleutils::GetSkillRank(SKILL_EVA, PMob->GetMJob()); PMob->setModifier(MOD_DEF, GetJugBase(PMob, petStats->defRank)); PMob->setModifier(MOD_EVA, GetJugBase(PMob, evaRank)); PMob->setModifier(MOD_ATT, GetJugBase(PMob, petStats->attRank)); PMob->setModifier(MOD_ACC, GetJugBase(PMob, petStats->accRank)); PMob->m_Weapons[SLOT_MAIN]->setDamage(GetJugWeaponDamage(PMob)); //reduce weapon delay of MNK if(PMob->GetMJob()==JOB_MNK){ PMob->m_Weapons[SLOT_MAIN]->resetDelay(); } uint16 fSTR = GetBaseToRank(petStats->strRank, PMob->GetMLevel()); uint16 fDEX = GetBaseToRank(petStats->dexRank, PMob->GetMLevel()); uint16 fAGI = GetBaseToRank(petStats->vitRank, PMob->GetMLevel()); uint16 fINT = GetBaseToRank(petStats->agiRank, PMob->GetMLevel()); uint16 fMND = GetBaseToRank(petStats->intRank, PMob->GetMLevel()); uint16 fCHR = GetBaseToRank(petStats->mndRank, PMob->GetMLevel()); uint16 fVIT = GetBaseToRank(petStats->chrRank, PMob->GetMLevel()); uint16 mSTR = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),2), PMob->GetMLevel()); uint16 mDEX = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),3), PMob->GetMLevel()); uint16 mVIT = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),4), PMob->GetMLevel()); uint16 mAGI = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),5), PMob->GetMLevel()); uint16 mINT = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),6), PMob->GetMLevel()); uint16 mMND = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),7), PMob->GetMLevel()); uint16 mCHR = GetBaseToRank(grade::GetJobGrade(PMob->GetMJob(),8), PMob->GetMLevel()); PMob->stats.STR = fSTR + mSTR; PMob->stats.DEX = fDEX + mDEX; PMob->stats.VIT = fVIT + mVIT; PMob->stats.AGI = fAGI + mAGI; PMob->stats.INT = fINT + mINT; PMob->stats.MND = fMND + mMND; PMob->stats.CHR = fCHR + mCHR; }
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); } }