7th-saga/calc.js

182 lines
4.0 KiB
JavaScript

// https://gamefaqs.gamespot.com/snes/563501-the-7th-saga/faqs/54038
exports.physicalAttack = (
attackerPowerInnate,
attackerPowerWeapon,
targetGuardInnate,
targetGuardArmor,
targetGuardAccessory,
options = {},
) => {
let attackPower = attackerPowerInnate;
if (options.attackerDefending) {
attackPower *= 1.5;
}
if (options.attackerPowerUp) {
attackPower *= 2;
}
let weaponPower = attackerPowerWeapon;
if (options.attackerDefending) {
weaponPower *= 1.5;
}
let guardPower = targetGuardInnate;
if (options.targetGuardDown) {
guardPower /= 2;
}
const totalAttackPower = attackPower + weaponPower;
const totalGuardPower = guardPower + targetGuardArmor + targetGuardAccessory;
let averageDamage = totalAttackPower - (totalGuardPower / 2);
if (options.targetGuardUp) {
averageDamage /= 2;
}
if (options.targetDefending) {
averageDamage /= 2;
}
let minDamage = averageDamage * 0.75;
let maxDamage = averageDamage * 1.25;
const absoluteMin = 1;
return {
normal: {
avg: Math.max(absoluteMin, averageDamage),
min: Math.max(absoluteMin, minDamage),
max: Math.max(absoluteMin, maxDamage),
},
critical: {
avg: Math.max(absoluteMin, averageDamage * 2),
min: Math.max(absoluteMin, minDamage * 2),
max: Math.max(absoluteMin, maxDamage * 2),
},
};
};
exports.magicalAttack = (
attackerMagicInnate,
targetMagicInnate,
targetResistanceInnate,
targetResistanceArmor,
targetResistanceAccessory,
spellPower,
options = {},
) => {
let attackerPower = attackerMagicInnate;
let targetPower = targetMagicInnate;
if (options.targetMagicUp) {
targetPower += 40;
}
const targetResistance = 100 - targetResistanceInnate - targetResistanceArmor - targetResistanceAccessory;
const spellBonusAttackPower = attackerPower + (options.attackerMagicUp ? 40 : 0);
const spellBonus = ((spellBonusAttackPower / 2) + spellPower) * (targetResistance / 100);
const averageDamage = attackerPower - targetPower + spellBonus;
return {
avg: Math.max(1, averageDamage),
min: Math.max(1, averageDamage * 0.75),
max: Math.max(1, averageDamage * 1.25),
};
};
exports.hpCatcherAttack = (
attackerMagicInnate,
attackerMaxHP,
attackerCurrentHP,
targetCurrentHP,
options = {},
) => {
let attackerPower = attackerMagicInnate;
if (options.attackerMagicUp) {
attackerPower += 40;
}
const adjust = dmg => Math.min(attackerMaxHP - attackerCurrentHP, Math.min(Math.min(dmg, 50), targetCurrentHP));
const minDamage = attackerPower / 2;
return {
min: adjust(minDamage),
max: adjust(minDamage + 15),
};
};
exports.mpCatcherAttack = (
attackerMagicInnate,
attackerMaxMP,
attackerCurrentMP,
targetCurrentMP,
options = {},
) => {
let attackerPower = attackerMagicInnate;
if (options.attackerMagicUp) {
attackerPower += 40;
}
const adjust = dmg => Math.min(attackerMaxMP - attackerCurrentMP, Math.min(Math.min(dmg, 40), targetCurrentMP));
const minDamage = attackerPower / 2;
return {
min: adjust(minDamage),
max: adjust(minDamage + 15),
};
};
exports.effectSpellHitRate = (
targetResistanceInnate,
targetResistanceArmor,
targetResistanceAccessory,
) => {
if (targetResistanceInnate === null) {
// e.g. "Class 1" enemies
return 0;
}
return Math.max(5, 100 - targetResistanceInnate - targetResistanceArmor - targetResistanceAccessory);
};
exports.hitRate = (
attackerSpeedInnate,
targetSpeedInnate,
options = {},
) => {
let attackerSpeed = attackerSpeedInnate;
if (options.attackerSpeedUp) {
attackerSpeed += 30;
}
let targetSpeed = targetSpeedInnate;
if (options.targetSpeedUp) {
targetSpeed += 30;
}
const hitRate = 85 + (0.8 * (attackerSpeed - targetSpeed));
return Math.max(10, Math.min(98, hitRate));
};
exports.runRate = (
attackerSpeedInnate,
targetSpeedInnate,
options = {},
) => {
let attackerSpeed = attackerSpeedInnate;
if (options.attackerSpeedUp) {
attackerSpeed += 30;
}
let targetSpeed = targetSpeedInnate;
if (options.targetSpeedUp) {
targetSpeed += 30;
}
const runRate = 0.25 + (1.6 * (attackerSpeed - targetSpeed));
return Math.max(0.1, Math.min(0.8, runRate));
};