added TAS calculations

This commit is contained in:
tmont 2021-03-16 13:16:28 -07:00
parent 52d6cf3a9e
commit c54dc3fb31
4 changed files with 222 additions and 17 deletions

View File

@ -131,16 +131,41 @@
}; };
exports.effectSpellHitRate = ( exports.effectSpellHitRate = (
attackerMagicInnate,
targetMagicInnate,
targetResistanceInnate, targetResistanceInnate,
targetResistanceArmor, targetResistanceArmor,
targetResistanceAccessory, targetResistanceAccessory,
options = {},
) => { ) => {
if (targetResistanceInnate === null) { if (targetResistanceInnate === null) {
// e.g. "Class 1" enemies // e.g. "Class 1" enemies
return 0; return 0;
} }
return Math.max(5, 100 - targetResistanceInnate - targetResistanceArmor - targetResistanceAccessory); const targetResistance = targetResistanceInnate + targetResistanceArmor + targetResistanceAccessory;
let attackerMagic = attackerMagicInnate;
let targetMagic = targetMagicInnate;
if (options.attackerMagicUp) {
attackerMagic += 40;
}
if (options.targetMagicUp) {
targetMagic += 40;
}
if (options.tas) {
const magicCalc = 256 * (attackerMagic - targetMagic) / attackerMagic;
let magicResult;
if (magicCalc > targetResistance) {
magicResult = 0;
} else {
magicResult = magicCalc;
}
return Math.max(0, 100 - (targetResistance - magicResult));
}
return Math.max(5, 100 - targetResistance);
}; };
exports.hitRate = ( exports.hitRate = (
@ -158,6 +183,36 @@
targetSpeed += 30; targetSpeed += 30;
} }
if (options.tas) {
const diff = attackerSpeed - targetSpeed;
let hitRate;
if (diff <= -89) {
hitRate = 26;
} else if (diff <= -59) {
hitRate = 77;
} else if (diff <= -29) {
hitRate = 128;
} else if (diff <= -19) {
hitRate = 154;
} else if (diff <= -9) {
hitRate = 181;
} else if (diff <= -4) {
hitRate = 203;
} else if (diff <= 2) {
hitRate = 213;
} else if (diff <= 6) {
hitRate = 218;
} else if (diff <= 11) {
hitRate = 231;
} else if (diff <= 21) {
hitRate = 244;
} else {
hitRate = 251;
}
return (hitRate / 256) * 100;
}
const hitRate = 85 + (0.8 * (attackerSpeed - targetSpeed)); const hitRate = 85 + (0.8 * (attackerSpeed - targetSpeed));
return Math.max(10, Math.min(98, hitRate)); return Math.max(10, Math.min(98, hitRate));
}; };
@ -177,6 +232,30 @@
targetSpeed += 30; targetSpeed += 30;
} }
if (options.tas) {
const diff = attackerSpeed - targetSpeed;
if (diff <= -42) {
return 2;
}
if (diff <= -12) {
return 5;
}
if (diff <= -7) {
return 10;
}
if (diff <= 3) {
return 30;
}
if (diff <= 18) {
return 40;
}
if (diff <= 48) {
return 60;
}
return 80;
}
const runRate = 25 + (1.6 * (attackerSpeed - targetSpeed)); const runRate = 25 + (1.6 * (attackerSpeed - targetSpeed));
return Math.max(10, Math.min(80, runRate)); return Math.max(10, Math.min(80, runRate));
}; };

View File

@ -18,8 +18,6 @@
window.Cookies.set('charStats', JSON.stringify(charStats), { window.Cookies.set('charStats', JSON.stringify(charStats), {
sameSite: 'strict', sameSite: 'strict',
}); });
} else {
} }
}; };
@ -374,7 +372,14 @@
} }
}); });
$enemyInfoModal.find('.apply-tas-form input[type="checkbox"]').on('change', () => {
refreshModal();
});
const refreshModal = () => { const refreshModal = () => {
const defaultCalcOptions = {
tas: $enemyInfoModal.find('.apply-tas-form input[type="checkbox"]').get(0).checked,
};
rowData.spells = Array.isArray(rowData.spells) ? rowData.spells : rowData.spells.split(','); rowData.spells = Array.isArray(rowData.spells) ? rowData.spells : rowData.spells.split(',');
const calc = window.saga.calc; const calc = window.saga.calc;
@ -458,6 +463,8 @@
if (charStats.magic === null) { if (charStats.magic === null) {
$enemyInfoModal.find('[class^="magic-"]').text('n/a'); $enemyInfoModal.find('[class^="magic-"]').text('n/a');
$enemyInfoModal.find('.debuff-rate').text('n/a');
$enemyInfoModal.find('.vacuum-rate').text('n/a');
} else { } else {
const charMagic = charStats.magic; const charMagic = charStats.magic;
const enemyMagic = rowData.magic; const enemyMagic = rowData.magic;
@ -515,6 +522,7 @@
const elementalRes = 0; const elementalRes = 0;
const resArmor = charStats.armor ? charStats.armor.resistance[spell.element.toLowerCase()] : 0; const resArmor = charStats.armor ? charStats.armor.resistance[spell.element.toLowerCase()] : 0;
const resAccessory = charStats.accessory ? charStats.accessory.resistance[spell.element.toLowerCase()] : 0; const resAccessory = charStats.accessory ? charStats.accessory.resistance[spell.element.toLowerCase()] : 0;
let def = calc.magicalAttack(enemyMagic, charMagic, elementalRes, resArmor, resAccessory, spell.power); let def = calc.magicalAttack(enemyMagic, charMagic, elementalRes, resArmor, resAccessory, spell.power);
let magicUp = calc.magicalAttack(enemyMagic, charMagic, elementalRes, resArmor, resAccessory, spell.power, { let magicUp = calc.magicalAttack(enemyMagic, charMagic, elementalRes, resArmor, resAccessory, spell.power, {
targetMagicUp: true, targetMagicUp: true,
@ -543,16 +551,112 @@
prefix = '.magic-enemy-dmg-MPCatcher'; prefix = '.magic-enemy-dmg-MPCatcher';
$enemyInfoModal.find(prefix).text(magicDmg(def)); $enemyInfoModal.find(prefix).text(magicDmg(def));
$enemyInfoModal.find(prefix + '-magic-up').text(magicDmg(magicUp)); $enemyInfoModal.find(prefix + '-magic-up').text(magicDmg(magicUp));
// character effect spell hit rate
const enemyDebuffRes = rowData.resDebuff === 100 ? null : rowData.resDebuff;
const enemyVacuumRes = rowData.resVacuum === 100 ? null : rowData.resVacuum;
const debuffRate = calc.effectSpellHitRate(
charMagic,
enemyMagic,
enemyDebuffRes,
0,
0,
{...defaultCalcOptions},
);
const debuffRateMagicUp = calc.effectSpellHitRate(
charMagic,
enemyMagic,
enemyDebuffRes,
0,
0,
{
...defaultCalcOptions,
attackerMagicUp: true,
},
);
const vacuumRate = calc.effectSpellHitRate(
charMagic,
enemyMagic,
enemyVacuumRes,
0,
0,
{...defaultCalcOptions},
);
const vacuumRateMagicUp = calc.effectSpellHitRate(
charMagic,
enemyMagic,
enemyVacuumRes,
0,
0,
{
...defaultCalcOptions,
attackerMagicUp: true,
},
);
$enemyInfoModal.find('.debuff-rate').text(toPer(debuffRate));
$enemyInfoModal.find('.debuff-rate-magic-up').text(toPer(debuffRateMagicUp));
$enemyInfoModal.find('.vacuum-rate').text(toPer(vacuumRate));
$enemyInfoModal.find('.vacuum-rate-magic-up').text(toPer(vacuumRateMagicUp));
// enemy effect spell hit rate
const resDebuffArmor = charStats.armor ? charStats.armor.resistance.debuff : 0;
const resDebuffAccessory = charStats.accessory ? charStats.accessory.resistance.debuff : 0;
const resVacuumArmor = charStats.armor ? charStats.armor.resistance.vacuum : 0;
const resVacuumAccessory = charStats.accessory ? charStats.accessory.resistance.vacuum : 0;
const enemyDebuffRate = calc.effectSpellHitRate(
enemyMagic,
charMagic,
0,
resDebuffArmor,
resDebuffAccessory,
{...defaultCalcOptions},
);
const enemyDebuffRateMagicUp = calc.effectSpellHitRate(
enemyMagic,
charMagic,
0,
resDebuffArmor,
resDebuffAccessory,
{
...defaultCalcOptions,
targetMagicUp: true,
},
);
const enemyVacuumRate = calc.effectSpellHitRate(
enemyMagic,
charMagic,
0,
resVacuumArmor,
resVacuumAccessory,
{...defaultCalcOptions},
);
const enemyVacuumRateMagicUp = calc.effectSpellHitRate(
enemyMagic,
charMagic,
0,
resVacuumArmor,
resVacuumAccessory,
{
...defaultCalcOptions,
targetMagicUp: true,
},
);
$enemyInfoModal.find('.hit-rate-enemy-debuff').text(toPer(enemyDebuffRate));
$enemyInfoModal.find('.hit-rate-enemy-debuff-magic-up').text(toPer(enemyDebuffRateMagicUp));
$enemyInfoModal.find('.hit-rate-enemy-vacuum').text(toPer(enemyVacuumRate));
$enemyInfoModal.find('.hit-rate-enemy-vacuum-magic-up').text(toPer(enemyVacuumRateMagicUp));
} }
if (charStats.speed !== null) { if (charStats.speed !== null) {
const hitRate = calc.hitRate(charStats.speed, rowData.speed); const hitRate = calc.hitRate(charStats.speed, rowData.speed, { ...defaultCalcOptions });
const hitRateSpeed = calc.hitRate(charStats.speed, rowData.speed, { const hitRateSpeed = calc.hitRate(charStats.speed, rowData.speed, {
attackerSpeedUp: true, attackerSpeedUp: true,
...defaultCalcOptions,
}); });
const runRate = rowData.cls === 1 ? 0 : calc.runRate(charStats.speed, rowData.speed); const runRate = rowData.cls === 1 ? 0 : calc.runRate(charStats.speed, rowData.speed, { ...defaultCalcOptions });
const runRateSpeed = rowData.cls === 1 ? 0 : calc.runRate(charStats.speed, rowData.speed, { const runRateSpeed = rowData.cls === 1 ? 0 : calc.runRate(charStats.speed, rowData.speed, {
attackerSpeedUp: true, attackerSpeedUp: true,
...defaultCalcOptions,
}); });
$enemyInfoModal.find('.run-rate').text(toPer(runRate)); $enemyInfoModal.find('.run-rate').text(toPer(runRate));
@ -560,16 +664,19 @@
$enemyInfoModal.find('.hit-rate').text(toPer(hitRate)); $enemyInfoModal.find('.hit-rate').text(toPer(hitRate));
$enemyInfoModal.find('.hit-rate-speed-up').text(toPer(hitRateSpeed)); $enemyInfoModal.find('.hit-rate-speed-up').text(toPer(hitRateSpeed));
const enemyHitRate = calc.hitRate(rowData.speed, charStats.speed); const enemyHitRate = calc.hitRate(rowData.speed, charStats.speed, { ...defaultCalcOptions });
const enemyHitRateSpeed = calc.hitRate(rowData.speed, charStats.speed, { const enemyHitRateSpeed = calc.hitRate(rowData.speed, charStats.speed, {
attackerSpeedUp: true, attackerSpeedUp: true,
...defaultCalcOptions,
}); });
const enemyHitRateCharSpeed = calc.hitRate(rowData.speed, charStats.speed, { const enemyHitRateCharSpeed = calc.hitRate(rowData.speed, charStats.speed, {
targetSpeedUp: true, targetSpeedUp: true,
...defaultCalcOptions,
}); });
const enemyHitRateCharSpeedSpeed = calc.hitRate(rowData.speed, charStats.speed, { const enemyHitRateCharSpeedSpeed = calc.hitRate(rowData.speed, charStats.speed, {
attackerSpeedUp: true, attackerSpeedUp: true,
targetSpeedUp: true, targetSpeedUp: true,
...defaultCalcOptions,
}); });
$enemyInfoModal.find('.hit-rate-enemy').text(toPer(enemyHitRate)); $enemyInfoModal.find('.hit-rate-enemy').text(toPer(enemyHitRate));
@ -577,15 +684,11 @@
$enemyInfoModal.find('.hit-rate-enemy-char-speed-up').text(toPer(enemyHitRateCharSpeed)); $enemyInfoModal.find('.hit-rate-enemy-char-speed-up').text(toPer(enemyHitRateCharSpeed));
$enemyInfoModal.find('.hit-rate-enemy-char-speed-up-speed-up').text(toPer(enemyHitRateCharSpeedSpeed)); $enemyInfoModal.find('.hit-rate-enemy-char-speed-up-speed-up').text(toPer(enemyHitRateCharSpeedSpeed));
} }
const debuffRate = calc.effectSpellHitRate(rowData.resDebuff === 100 ? null : rowData.resDebuff, 0, 0);
const vacuumRate = calc.effectSpellHitRate(rowData.resVacuum === 100 ? null : rowData.resVacuum, 0, 0);
$enemyInfoModal.find('.debuff-rate').text(toPer(debuffRate));
$enemyInfoModal.find('.vacuum-rate').text(toPer(vacuumRate));
}; };
$enemyInfoModal.on('hide.bs.modal', () => { $enemyInfoModal.on('hide.bs.modal', () => {
$enemyInfoModal.find('.apply-runes-form').hide().find('input').prop('checked', false); $enemyInfoModal.find('.apply-runes-form').hide().find('input').prop('checked', false);
$enemyInfoModal.find('.apply-tas-form input').prop('checked', true);
}); });
$table.find('tbody.data td').on('click', (e) => { $table.find('tbody.data td').on('click', (e) => {
@ -594,7 +697,7 @@
if (rowData.name === 'Gorsia') { if (rowData.name === 'Gorsia') {
$enemyInfoModal.find('.apply-runes-form').show().prop('checked', false); $enemyInfoModal.find('.apply-runes-form').show().prop('checked', false);
} else { } else {
$enemyInfoModal.find('.apply-runes-form').hide().find('input').prop('checked', false); $enemyInfoModal.find('.apply-runes-form').hide().find('input').prop('checked', true);
} }
refreshModal(); refreshModal();

View File

@ -79,6 +79,9 @@ block tab-content
div.form-check-inline.ml-4.apply-runes-form(style="font-size: 75%") div.form-check-inline.ml-4.apply-runes-form(style="font-size: 75%")
input.form-check-input#apply-runes(type="checkbox" autocomplete="off") input.form-check-input#apply-runes(type="checkbox" autocomplete="off")
label.form-check-label(for="apply-runes") Apply runes label.form-check-label(for="apply-runes") Apply runes
div.form-check-inline.ml-2.apply-tas-form(style="font-size: 75%")
input.form-check-input#apply-tas(type="checkbox" autocomplete="off" checked)
label.form-check-label(for="apply-tas") TAS calculations
div div
| #[span.gold]/#[span.exp] | #[span.gold]/#[span.exp]
div.modal-body(style="font-size: 85%") div.modal-body(style="font-size: 85%")
@ -146,6 +149,18 @@ block tab-content
th Char. speed up th Char. speed up
td: code.hit-rate-enemy-char-speed-up td: code.hit-rate-enemy-char-speed-up
td: code.hit-rate-enemy-char-speed-up-speed-up td: code.hit-rate-enemy-char-speed-up-speed-up
tr
th
th
th Magic up
tr
th Debuff
td: code.hit-rate-enemy-debuff
td: code.hit-rate-enemy-debuff-magic-up
tr
th Vacuum
td: code.hit-rate-enemy-vacuum
td: code.hit-rate-enemy-vacuum-magic-up
div.card.bg-light.mt-2 div.card.bg-light.mt-2
div.card-header Enemy magic div.card-header Enemy magic
@ -203,13 +218,13 @@ block tab-content
tr tr
th Debuff rate th Debuff rate
td: code.debuff-rate td: code.debuff-rate
th th w/ magic up
td td: code.debuff-rate-magic-up
tr tr
th Vacuum rate th Vacuum rate
td: code.vacuum-rate td: code.vacuum-rate
th th w/ magic up
td td: code.vacuum-rate-magic-up
div.col-4: div.card.bg-light div.col-4: div.card.bg-light
div.card-header Character magic div.card-header Character magic

View File

@ -87,7 +87,15 @@ html
div.col-8: select#char-armor.form-control(autocomplete="off") div.col-8: select#char-armor.form-control(autocomplete="off")
option(value="") Choose armor option(value="") Choose armor
each armor in charArmor each armor in charArmor
option(value=armor.name data-defense=armor.defense) option(
value=armor.name
data-defense=armor.defense
data-res-fire=armor.resistance.fire
data-res-ice=armor.resistance.ice
data-res-thunder=armor.resistance.thunder
data-res-vacuum=armor.resistance.vacuum
data-res-debuff=armor.resistance.debuff
)
= armor.name + ' (' + armor.defense + ')' = armor.name + ' (' + armor.defense + ')'
div.form-row.form-group div.form-row.form-group
label.col-form-label-sm.col-4(for="char-armor") Accessory label.col-form-label-sm.col-4(for="char-armor") Accessory