bool StatBlock::summonLimitReached(int power_id) const { //find the limit Power *spawn_power = &powers->powers[power_id]; int max_summons = 0; if(spawn_power->spawn_limit_mode == SPAWN_LIMIT_MODE_FIXED) max_summons = spawn_power->spawn_limit_qty; else if(spawn_power->spawn_limit_mode == SPAWN_LIMIT_MODE_STAT) { int stat_val = 1; switch(spawn_power->spawn_limit_stat) { case SPAWN_LIMIT_STAT_PHYSICAL: stat_val = get_physical(); break; case SPAWN_LIMIT_STAT_MENTAL: stat_val = get_mental(); break; case SPAWN_LIMIT_STAT_OFFENSE: stat_val = get_offense(); break; case SPAWN_LIMIT_STAT_DEFENSE: stat_val = get_defense(); break; } max_summons = (stat_val / (spawn_power->spawn_limit_every == 0 ? 1 : spawn_power->spawn_limit_every)) * spawn_power->spawn_limit_qty; } else return false;//unlimited or unknown mode //if the power is available, there should be at least 1 allowed summon if(max_summons < 1) max_summons = 1; //find out how many there are currently int qty_summons = 0; for (unsigned int i=0; i < summons.size(); i++) { if(!summons[i]->corpse && summons[i]->summoned_power_index == power_id && summons[i]->cur_state != ENEMY_SPAWN && summons[i]->cur_state != ENEMY_DEAD && summons[i]->cur_state != ENEMY_CRITDEAD) { qty_summons++; } } return qty_summons >= max_summons; }
/** * Base damage and absorb is 0 * Plus an optional bonus_per_[base stat] */ void StatBlock::calcBase() { // bonuses are skipped for the default level 1 of a stat int lev0 = level -1; int phys0 = get_physical() -1; int ment0 = get_mental() -1; int off0 = get_offense() -1; int def0 = get_defense() -1; clampFloor(lev0,0); clampFloor(phys0,0); clampFloor(ment0,0); clampFloor(off0,0); clampFloor(def0,0); for (int i=0; i<STAT_COUNT; i++) { base[i] = starting[i]; base[i] += lev0 * per_level[i]; base[i] += phys0 * per_physical[i]; base[i] += ment0 * per_mental[i]; base[i] += off0 * per_offense[i]; base[i] += def0 * per_defense[i]; } // add damage/absorb from equipment base[STAT_DMG_MELEE_MIN] += dmg_melee_min_add; base[STAT_DMG_MELEE_MAX] += dmg_melee_max_add; base[STAT_DMG_MENT_MIN] += dmg_ment_min_add; base[STAT_DMG_MENT_MAX] += dmg_ment_max_add; base[STAT_DMG_RANGED_MIN] += dmg_ranged_min_add; base[STAT_DMG_RANGED_MAX] += dmg_ranged_max_add; base[STAT_ABS_MIN] += absorb_min_add; base[STAT_ABS_MAX] += absorb_max_add; // increase damage and absorb to minimum amounts clampFloor(base[STAT_DMG_MELEE_MIN], 0); clampFloor(base[STAT_DMG_MELEE_MAX], base[STAT_DMG_MELEE_MIN]); clampFloor(base[STAT_DMG_RANGED_MIN], 0); clampFloor(base[STAT_DMG_RANGED_MAX], base[STAT_DMG_RANGED_MIN]); clampFloor(base[STAT_DMG_MENT_MIN], 0); clampFloor(base[STAT_DMG_MENT_MAX], base[STAT_DMG_MENT_MIN]); clampFloor(base[STAT_ABS_MIN], 0); clampFloor(base[STAT_ABS_MAX], base[STAT_ABS_MIN]); }
/** * Recalc derived stats from base stats + effect bonuses */ void StatBlock::applyEffects() { // preserve hp/mp states prev_maxhp = get(STAT_HP_MAX); prev_maxmp = get(STAT_MP_MAX); pres_hp = hp; pres_mp = mp; // calculate primary stats // refresh the character menu if there has been a change if (get_physical() != physical_character + effects.bonus_physical || get_mental() != mental_character + effects.bonus_mental || get_offense() != offense_character + effects.bonus_offense || get_defense() != defense_character + effects.bonus_defense) refresh_stats = true; offense_additional = effects.bonus_offense; defense_additional = effects.bonus_defense; physical_additional = effects.bonus_physical; mental_additional = effects.bonus_mental; calcBase(); for (int i=0; i<STAT_COUNT; i++) { current[i] = base[i] + effects.bonus[i]; } for (unsigned i=0; i<effects.bonus_resist.size(); i++) { vulnerable[i] = vulnerable_base[i] - effects.bonus_resist[i]; } current[STAT_HP_MAX] += (current[STAT_HP_MAX] * current[STAT_HP_PERCENT]) / 100; current[STAT_MP_MAX] += (current[STAT_MP_MAX] * current[STAT_MP_PERCENT]) / 100; if (hp > get(STAT_HP_MAX)) hp = get(STAT_HP_MAX); if (mp > get(STAT_MP_MAX)) mp = get(STAT_MP_MAX); speed = speed_default; }
/** * Recalc derived stats from base stats * Creatures might skip these formulas. */ void StatBlock::recalc() { level = 0; for (int i=0; i<MAX_CHARACTER_LEVEL; i++) { if (xp >= xp_table[i]) level=i+1; } // TODO: move these formula numbers to an engine config file int hp_base = 10; int hp_per_level = 2; int hp_per_physical = 8; int hp_regen_base = 10; int hp_regen_per_level = 1; int hp_regen_per_physical = 4; int mp_base = 10; int mp_per_level = 2; int mp_per_mental = 8; int mp_regen_base = 10; int mp_regen_per_level = 1; int mp_regen_per_mental = 4; int accuracy_base = 75; int accuracy_per_level = 1; int accuracy_per_offense = 5; int avoidance_base = 25; int avoidance_per_level = 1; int avoidance_per_defense = 5; int crit_base = 5; int crit_per_level = 1; int lev0 = level -1; int phys0 = get_physical() -1; int ment0 = get_mental() -1; int off0 = get_offense() -1; int def0 = get_defense() -1; hp = maxhp = hp_base + (hp_per_level * lev0) + (hp_per_physical * phys0); mp = maxmp = mp_base + (mp_per_level * lev0) + (mp_per_mental * ment0); hp_per_minute = hp_regen_base + (hp_regen_per_level * lev0) + (hp_regen_per_physical * phys0); mp_per_minute = mp_regen_base + (mp_regen_per_level * lev0) + (mp_regen_per_mental * ment0); accuracy = accuracy_base + (accuracy_per_level * lev0) + (accuracy_per_offense * off0); avoidance = avoidance_base + (avoidance_per_level * lev0) + (avoidance_per_defense * def0); crit = crit_base + (crit_per_level * lev0); physoff = get_physical() + get_offense(); physdef = get_physical() + get_defense(); mentoff = get_mental() + get_offense(); mentdef = get_mental() + get_defense(); physment = get_physical() + get_mental(); offdef = get_offense() + get_defense(); int stat_sum = get_physical() + get_mental() + get_offense() + get_defense(); // determine class // if all four stats are max, Grand Master if (stat_sum >= 20) character_class = "Grand Master"; // if three stats are max, Master else if (stat_sum >= 16) character_class = "Master"; // if one attribute is much higher than the others, use the attribute class name else if (get_physical() > get_mental()+1 && get_physical() > get_offense()+1 && get_physical() > get_defense()+1) character_class = "Warrior"; else if (get_mental() > get_physical()+1 && get_mental() > get_offense()+1 && get_mental() > get_defense()+1) character_class = "Wizard"; else if (get_offense() > get_physical()+1 && get_offense() > get_mental()+1 && get_offense() > get_defense()+1) character_class = "Ranger"; else if (get_defense() > get_physical()+1 && get_defense() > get_mental()+1 && get_defense() > get_offense()+1) character_class = "Paladin"; // if there is no dominant attribute, use the dicipline class name else if (physoff > physdef && physoff > mentoff && physoff > mentdef && physoff > physment && physoff > offdef) character_class = "Rogue"; else if (physdef > physoff && physdef > mentoff && physdef > mentdef && physdef > physment && physdef > offdef) character_class = "Knight"; else if (mentoff > physoff && mentoff > physdef && mentoff > mentdef && mentoff > physment && mentoff > offdef) character_class = "Shaman"; else if (mentdef > physoff && mentdef > physdef && mentdef > mentoff && mentdef > physment && mentdef > offdef) character_class = "Cleric"; else if (physment > physoff && physment > physdef && physment > mentoff && physment > mentdef && physment > offdef) character_class = "Battle Mage"; else if (offdef > physoff && offdef > physdef && offdef > mentoff && offdef > mentdef && offdef > physment) character_class = "Heavy Archer"; // otherwise, use the generic name else character_class = "Adventurer"; }