mh3-data
Version:
Monster Hunter Tri data for monsters, quests, and weapons
223 lines (222 loc) • 8.14 kB
JavaScript
import { Weapons } from '../../model';
import { Sharpness } from '../../model/weapons';
import { ARMOR_SKILL_MULTIPLIERS, CRITICAL_HIT_MULTIPLIERS, DEMONDRUG_MULTIPLIERS, ELEMENT_ATTACK_MULTIPLIERS, FORTIFY_MULTIPLIERS, LOW_HEALTH_SKILL_MULTIPLIERS, MIGHT_MULTIPLIERS, POWERCHARM_MULTIPLIER, POWERTALON_MULTIPLIER } from './attack-multipliers';
const ELEMENTAL_DAMAGE_DIVIDER = 10;
/**
* Default params for {@link getWeaponClassMultiplier}
*/
const defaultWeaponClassArgs = Object.freeze({
powercharm: false,
powertalon: false,
demondrug: 'none',
might: 'none',
armor: 'none'
});
/**
* Default params for {@link getRawMultiplier}
*/
const defaultRawArgs = Object.freeze({
criticalHit: 'none',
lowHealthSkill: 'none',
fortify: 'none'
}); /**
* Default params for {@link calculateElementalDamage}
*/
const defaultElementArgs = Object.freeze({
awaken: false,
elementAttack: 'none'
});
/**
* @returns true if weapon has the provided sharpness level, otherwise throws error
* @throws Error if weapon does not have provided sharpness level
*/
export function validateWeaponSharpness(weapon, sharpness) {
const validSharpness = sharpness <= weapon.sharpnessUp.length - 1;
if (!validSharpness) {
throw new Error(`'${weapon.name}' cannot have '${Weapons.sharpnessAsString(sharpness)}' sharpness`);
}
return validSharpness;
}
/**
* @returns sharpness multiplier for RAW damage (as opposed to ELEMENTAL)
*/
export function getSharpnessRawMultiplier(sharpness) {
switch (sharpness) {
case Sharpness.RED:
return 0.5;
case Sharpness.ORANGE:
return 0.75;
case Sharpness.YELLOW:
return 1;
case Sharpness.GREEN:
return 1.05;
case Sharpness.BLUE:
return 1.2;
case Sharpness.WHITE:
return 1.32;
case Sharpness.PURPLE:
return 1.5;
default:
throw new Error(`Invalid sharpness value '${sharpness}'`);
}
}
/**
* @returns sharpness multiplier for ELEMENTAL damage (as opposed to RAW)
*/
export function getSharpnessElementalMultiplier(sharpness) {
switch (sharpness) {
case Sharpness.RED:
return 0.25;
case Sharpness.ORANGE:
return 0.55;
case Sharpness.YELLOW:
return 0.75;
case Sharpness.GREEN:
return 1;
case Sharpness.BLUE:
return 1.0625;
case Sharpness.WHITE:
return 1.125;
case Sharpness.PURPLE:
return 1.2;
default:
throw new Error(`Invalid sharpness value '${sharpness}'`);
}
}
/**
* Used by {@link calculateElementalDamage}
* @returns Elemental damage or 0 if weapon has status rather than element
*/
function getHitzoneForWeaponElement(hitzoneValues, weaponElement) {
if (weaponElement === 'sleep' ||
weaponElement === 'poison' ||
weaponElement === 'paralysis')
return 0;
switch (weaponElement) {
case 'fire':
return hitzoneValues.fire;
case 'water':
return hitzoneValues.water;
case 'ice':
return hitzoneValues.ice;
case 'thunder':
return hitzoneValues.thunder;
case 'dragon':
return hitzoneValues.dragon;
default:
throw new Error(`Invalid hitzone type '${weaponElement}'`);
}
}
/**
* Get additional attack buffs multiplied against the weapon's class modifier.
*
* Taken from Lord Grahf's [Monster Hunter Tri Damage Formula FAQ](https://gamefaqs.gamespot.com/wii/943655-monster-hunter-tri/faqs/59207)
* - Section 9a. Attack Up Multipliers (ATKUP)
*
* Items and armor skills can affect attack stats. Multipliers are broken into different sub-categories
* which can stack amongst each other. Each category has a multiplier which is applied to the weapon's class modifier.
*/
export function getWeaponClassMultiplier(weaponClassArgs = defaultWeaponClassArgs) {
let totalAttackMultiplier = 0;
const { powercharm, powertalon, demondrug, might, armor } = weaponClassArgs;
/**
* 1. Powercharm
*/
totalAttackMultiplier += powercharm ? POWERCHARM_MULTIPLIER : 0;
/**
* 2. Powertalon
*/
totalAttackMultiplier += powertalon ? POWERTALON_MULTIPLIER : 0;
/**
* 3. Demondrug/Kitchen
*/
totalAttackMultiplier += DEMONDRUG_MULTIPLIERS[demondrug];
/**
* 4. Might
*/
totalAttackMultiplier += MIGHT_MULTIPLIERS[might];
/**
* 5. Armor Skill
*/
totalAttackMultiplier += ARMOR_SKILL_MULTIPLIERS[armor];
return totalAttackMultiplier;
}
/**
* Get additional attack buffs multiplied against the weapon's raw
*
* - Critical hits recieve a 1.25 bonus (0.75 for negative critical)
*
* - Felyne Heroics recieves a 1.35 bonus
* - Adrenaline+2 recieves a 1.30 bonus
* - Does not stack with heroics (and vice versa)
*
* - Fortify recieves a 10% bonus per faint
*/
export function getRawMultiplier(rawArgs = defaultRawArgs) {
const { criticalHit, lowHealthSkill, fortify } = rawArgs;
return (CRITICAL_HIT_MULTIPLIERS[criticalHit] *
LOW_HEALTH_SKILL_MULTIPLIERS[lowHealthSkill] *
FORTIFY_MULTIPLIERS[fortify]);
}
/**
* Handles decimal logic when applying the defense multiplier.
* The damage decimal is always dropped before being put against a defense multiplier.
* The result then has its decimal dropped again.
*/
export function applyDefenseMultiplier(damage, defenseMultiplier) {
return Math.floor(Math.floor(damage) * defenseMultiplier);
}
/**
* This should be used for calculating elemental damage as part of the overall damage formula.
*
* @see {@link calculateIsolatedElementalDamage} for calculating elemental damage standalone.
*
* Taken from Lord Grahf's [Monster Hunter Tri Damage Formula FAQ](https://gamefaqs.gamespot.com/wii/943655-monster-hunter-tri/faqs/59207)
* - Section 1c. Elemental Damage Formula (EFMLA)
*
* [ELEMENT x ESHARP x ELMZONE] / [DIVIDER] = Elemental Damage
*
* @param weapon
* @param sharpness
* @param hitzoneValues
* @param elementArgs Optional, default all `false`
*
* @example
* [ELEMENT]: 250 // (250 thunder element)
* [ESHARP]: 1.0 // (Green sharpness for elements, x 1.0)
* [ELMZONE]: .20 // (Rathian's weakness to thunder at head is 20)
* [DIVIDER]: 10 // (Elemental Divider is always 10)
* [DEFENSE]: .75 // (.75 online high rank defense from earlier)
*
* [ELEMENT x ESHARP x ELMZONE] / [DIVIDER] = Elemental Damage [X DEFENSE]
* 250 x 1.0 x .20 / 10 = 5 (Added Thunder Damage)
*/
export function calculateElementalDamage({ weapon, sharpness, hitzoneValues, elementArgs = defaultElementArgs }) {
const { awaken, elementAttack } = elementArgs;
const sharpnessMultiplier = getSharpnessElementalMultiplier(sharpness);
const elementalHitzoneMultiplier = getHitzoneForWeaponElement(hitzoneValues, weapon.secondaryDamageType);
// Element is not calculated for non-awakened weapon or if hitzone multiplier is 0
if ((weapon.awaken && !awaken) || elementalHitzoneMultiplier === 0)
return 0;
const elementMultiplier = ELEMENT_ATTACK_MULTIPLIERS[elementAttack];
const secondaryAttackWithBuffs = weapon.secondaryAttack * elementMultiplier;
return ((secondaryAttackWithBuffs *
sharpnessMultiplier *
elementalHitzoneMultiplier) /
ELEMENTAL_DAMAGE_DIVIDER);
}
/**
* Use this for calculation elemental damage in isolation, meaning it's assumed the result
* will not be used as part of an overall damage calculation that includes raw.
*
* @see {@link calculateElementalDamage} for calculating elemental damage as part of the overall damage
*/
export function calculateIsolatedElementalDamage({ weapon, sharpness, hitzoneValues, elementArgs = defaultElementArgs, defenseMultiplier }) {
return applyDefenseMultiplier(calculateElementalDamage({
weapon,
sharpness,
hitzoneValues,
elementArgs
}), defenseMultiplier);
}
//# sourceMappingURL=damage-util.js.map