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);
    }
}
Exemple #2
0
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());
}
Exemple #3
0
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;

}
Exemple #5
0
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);
    }
}