Battle

戦闘中に使う計算式を説明をします。

行動順

// 行動順を決定する1~10までの値を取得します。
// この値が低いほど、先に行動できます。
function getActionOrder(agi) Number
{
	// すばやさが 0 の場合 Enemy と判断し、その場合はランダムで値を決めます
	if (agi == 0) {
		return 1 + Dice.Cast(1, 8);
	}
	var agiBonus = 3;
	if (agi >= 15)     agiBonus = 14 - agi;
	else if (agi >= 8) agiBonus = 0;
	else if (agi >= 6) agiBonus = 1;
	else if (agi >= 4) agiBonus = 2;

	var order = Dice.Cast(1, 10) + agiBonus;
	if (order < 1)  order = 1;
	if (order > 10) order = 10;
	return order;
}
攻撃命中率

function getFightLevel(Level, STR, WeaponSTR): Number
{
	// ちからが 0 の場合は Enemy と判断して、レベルを使います。
	if (STR == 0)
		return Level;
	var strBonus = 0;
	if (str > 15)
		strBonus = str - 15;
	else if (str < 6)
		strBonus = str - 6;
	var levelBonus = Level/3;
	return strBonus + levelBonus + WeaponSTR;
}

function getHitRate(targetAC, targetGroupNo, targetIsMovable, Level, STR, WeaponSTR): Number
{
	// 命中率 = 5 * (AC + A - (3 * グループ番号))
	var A = getFightLevel(Level, STR, WeaponSTR);
	var hitRate = 10 + targetAC + A - (3 * targetGroupNo);
	hitRate *= 5;
	if (targetIsMovable == false)
		hitRate += 20;
	if (hitRate > 95) hitRate = 95;
	if (hitRate < 5)  hitRate = 5;
	return hitRate;
}
クリティカルヒット率
// PC がエネミー攻撃時
function getCriticalHitRate(CharLevel, EnemyLevel)
{
	var p1 = min(CharLevel, 25) / 50;
	var p2 = max(0, 24 - EnemyLevel) / 35;
	return p1 * p2 * 100;
}

// エネミーが PC 攻撃時
function getCriticalHitRate(EnemyLevel, pc: PlayerCharacter)
{
	var fortuneCorrectionValue = 2; // 未対応の為固定値。本来クラス・種族に設定される値
	var fortuneValue = max(0, 19 - pc.getLevel()/5 - pc.getLuck()/6 - fortuneCorrectionValue);
	var registanceRate = pc.getCriticalRegistanceRate(); // 装備している防具類1つで50%、2つで75%・・・の様に低効率が上昇
	var p1 = (1 + fortuneValue) / 20;
	var p2 = (1 + EnemyLevel) / 50;
	var p3 = (100 - registanceRate) / 100;
	return p1 * p2 * p3 * 100;
}
ブレス回避率

function getBreathEvasionRate(pc: PlayerCharacter)
{
	var p1 = max(0, pc.getLuck() - 15) / 20;
	return p1;
}
スキル抵抗

function useSkill(skill: Skill, user: Battler, target: Battler)
{
	// 計算式による抵抗率を取得
	var validFormulaId = FormulaDatabase.isValidFormulaId(skill.getResistanceFormulaId());
	var resistanceRate = 0;
	if (validFormulaId) {
		var args = [user, target]; // a b で参照される計算式の引数
		resistanceRate = FormulaDatabase.evaluate(skill.getResistanceFormulaId(), args);
	}
	// 失敗率を取得
	var failureRate = 100 - skill.getSuccessRate();
	// 失敗率と抵抗率どちらかが該当するか判定
	if (Probability.testByPercent(resistanceRate) || Probability.testByPercent(failureRate)) {
		// 味方に向けてのスキルで失敗した場合は状態を深化させる
		if (skill.isForFriend()) {
			target.deepenStates(skill.getStates());
		}
		return StringTable.get("The spell is not effective to [target]!");
	}

	// 抵抗率計算式が設定されていない場合
	if (!validFormulaId) {
		// スキルが敵に向けたものかつ呪文タイプの場合
		if (skill.isForOpponent() && skill.isMagicalType()) {
			// 知恵か信仰心によるスキルボーナスを取得
			int skillBonus = 0;
			if (skill.isMageType()) {
				skillBonus = Math.max(0, user.param("int") - 15);
			}
			else if (skill.isPriestType()) {
				skillBonus = Math.max(0, user.param("pie") - 15);
			}
			// 敵に設定された呪文無効化率で呪文を邪魔するか判定
			int resistanceRate = target.getCantripInvalidityRate() - skillBonus*5;
			if (Probability.testByPercent(resistanceRate)) {
				// 既に死亡している場合はメッセージ無し
				if (target.isDead())
					return "";
				return StringTable::get("[target] resists the spell!");
			}
		}
	}

	// ダメージや能力値上昇などの処理
	var message = "";

	// 状態回復と状態抵抗処理
	var states: Array = skill.getStates();
	for (var i = 0; i < states.length; ++i) {
		var state = states[i];
		if (skill.isForFriend()) {
			// 味方に向けたスキルの場合は無条件で状態を取り除く
			target.removeState(state);
		}
		else {
			if (validFormulaId) {
				// 抵抗率計算式が設定されていた場合は無条件で状態を追加
				target.addState(state);
			}
			else {
				// 敵に向けたスキルで抵抗できなかった場合、状態を追加
				var resistanceRate = target.getStateResistanceRate(state); // 装備、種族、体力による抵抗率を取得
				if (Probability.testByPercent(100 - resistanceRate)) {
					target.addState(state);
				}
			}
		}
	}
	return message;
}

Level UP

レベルアップ時の HP 変化

// レベルに応じた最大HPは、クラスに応じた面数のダイスを、現在レベルの回数だけ振った合計になります。
// ・ダイスの面数の計算
// ダイスの面数は、生命力に応じた補正値とクラスの LevelUpHP に設定した値を足したものです。
// 生命力3以下  補正値 = -2
// 生命力4~5 補正値 = -1
// 生命力6~15 補正値 = 0
// 生命力16~ 補正値 = (生命力 - 15)
// ダイスの面数 = LevelUpHP + 補正数
// ・最大HP
// 現在のレベルだけ上記のダイスを振り、出た目を合計する。
// 合計が現在の最大HPより下の場合、現在の最大HP+1を出た目の合計とする。
// ※初期レベルのHPは上で算出された値に4を足しますが、仕様変更になるかもしれません。
// ・例:生命力15で LevelUpHP が10の場合の最大HP
// レベル1:4+1~10
// レベル2:(1~10) ×2 生命力が1上がって16になる
// レベル3:(1~11)×3
function calculateMaxHP(pc: PartyCharacter): int
{
	var VIT = pc.paramBase("vit");
	var classData = pc.getClass();
	var bonus = 0;
	if (VIT <= 3) bonus --;
	if (VIT <= 5) bonus --;
	if (VIT > 15) bonus = VIT - 15;
	// Database > Class で設定した値 LevelUpHP
	var LevelUpHP = classData.getLevelUpHP();
	// レベル 10 で 生命力が 15 で LevelUpHP が 8 の場合、最大値HP は 10D23 つまり 23~230が設定されます。
	var hp = Dice.Cast(getLevel(), LevelUpHP + bonus );
	var maxHP = pc.getMaxHP();
	// 現在の 最大HP が上の結果より大きい場合、レベルアップで上がる HP は 1 になります。
	if (maxHP >= hp) {
		return maxHP + 1;
	}
	return hp;
}
レベルアップ時の MP 変化

function levelUpMP(pc: PartyCharacter): void
{
	// 1. 種類とランク別に現在覚えている魔法の数を数える。タイプ 0 は黒魔法 1 は白魔法
	var skillCnt[2][8];
	for (var i = 0; i < pc.getLearningSkillCount(); ++i) {
		var skill = pc.getLearningSkillAt(i);
		var type = skill.getType();
		var rank = skill.getRank();
		skillCnt[type][rank] += 1;
	}
	// 2. キャラクターの現在の Level と Class と 1 を元に、現在の最大 MP を計算する
	var classID = pc.getClassID();
	var pcLevel = pc.getLevel();
	var classData = CharClassList.getAt(classID);
	for (var rank = 1; rank < 8; ++rank) {
		for (var type = 0; type < 2; ++type) {
			// データベースに指定のランクが登録されていない場合は
			// これ以上処理しないでタイプを切り替える
			if (skillCnt[type][rank] == 0)
				continue;
			// Database > Class で設定した覚えるスキルの表から
			// ループで使うためにクラス別の覚えるスキルの数を取得
			// 次のループで指定ランクのスキルを覚える最初のレベルを取得
			// 例 ファイアとスリープのランクが 1 で、覚えるレベルが 1 と 2 の場合
			// learningLevel つまりスキルを覚える最初のレベルは 1 になります。
			var learningSkillCount = classData.getLernningSkillCount();
			var learningLevel = 0;
			for (var i = 0; i < learningSkillCount; ++i) {
				var id = classData.getLearningSkillIDAt(i);
				var skill = CharSkillList.getAt(id);
				if (skill.getRank() == rank) {
					var lv = classData.getLearningSkillLevelAt(i);
					if (learningLevel == 0)
						learningLevel = lv;
					else
						learningLevel = Math.min(learningLevel, lv);
				}
			}
			// 現在のレベルで設定されうる MP
			// 上の例で現在レベル 5 の場合は
			// 5 - 1 + 1 = 5 つまり MP = 5 になります。 
			var mpLevel = pcLevel - learningLevel + 1;
			// 設定する現在の MP の最大値。 9 以上にはなりません。
			var maxMP = Math.max(mpLevel, skillCnt[type][rank]);
			// 現在のクラスがそのランクのスキルを覚えない場合は
			// 現在のキャラクターが覚えているスキルの数が MP になります
			if (learningLevel <= 0)
				maxMP = skillCnt[type][rank];
			if (maxMP > 9)
				maxMP = 9;
			// キャラクターに 最大MP をセットする
			pc.setMaxMPAt(rank, type, maxMP);
		}
	}
}
レベルアップ時の能力値の変化

	// 25% の確率で変化しません Dice.Cast(個数, 面数)
	if (Dice.Cast(1, 4) == 4)
		return;
	var value = 1;
	// 以下の条件が真の場合、能力値が下がる、または変わらないのどちらかになります。
	if (Dice.Cast(1, 130) < age) {
		// 能力値が18以上の場合 5/6 の確率で変化しません。
		if (ability >= 18) {
			if (Dice.Cast(1, 6) < 6)
				return;
		}
		// 3 未満の場合も変化しません。
		if (ability < 3)
			return;
		value = -1;
	}
	// 能力値が、種族の基本能力値 + 10 以上になる場合も変化しません。
	if (ability + value >= baseAbility + 10)
		return;
	ability = ability + value;

ETC

ピットの計算式

	// ピット発動?
	if (pc.agility < Dice.cast(1, 25) + mapLevel) {
		var damage = Dice.cast(mapLevel, 8);
		pc.hp -= damage;
	}
宝箱罠
// 罠の識別率を取得
function getTrapInspectionRate(pc: PartyCharacter)
{
	var factor = pc.getThiefLevel() + 1;
	return = min(95, pc.getAgility() * factor);
}

// 罠の解除率を取得
function getTrapDisarmRate(pc: PartyCharacter, mapLevel: int)
{
	var classBonus = pc.getThiefLevel() * 10;
	var p = (pc.getLevel() - mapLevel - 7 + classBonus) / 70;
	return max(5, p * 100);
}

// 罠を外せなかった場合、罠の発動率を取得
function getTrapActivationRate(pc: PartyCharacter)
{
	var p = (20 - pc.getAgility()) / 20;
	return max(5, p * 100);
}
シークレットドア探知確率 仕様変更の可能性あり

function getSecretDoorDetectionProbability(pc: PartyCharacter, mapLevel: int) {
	var classBonus = pc.getDetectionLevel() * 5;
	if (classBonus == 0)
		return 0;
	var p = (pc.getLevel() - mapLevel) * 3 + classBonus;
	return max(5, min(95, p));
}