/** * @param {Technique} technique * @param {Monster} user * @param {Monster} target * * @returns {number} */ function simpleDamageCalculation (technique, user, target) { if (technique.power === 0) { return 0; } let userBaseStrength = user.level + 7; let userStrength = 1; let targetResist = 1; if (technique.range === TechniqueRange.melee) { userStrength = userBaseStrength * user.stats.melee; targetResist = target.stats.armour; } else if (technique.range === TechniqueRange.touch) { userStrength = userBaseStrength * user.stats.melee; targetResist = target.stats.dodge; } else if (technique.range === TechniqueRange.ranged) { userStrength = userBaseStrength * user.stats.ranged; targetResist = target.stats.dodge; } else if (technique.range === TechniqueRange.reach) { userStrength = userBaseStrength * user.stats.ranged; targetResist = target.stats.armour; } else if (technique.range === TechniqueRange.reliable) { userStrength = userBaseStrength; targetResist = 1; } const multiplier = simpleDamageMultiplier(technique.types, target.types); const moveStrength = technique.power * multiplier; const damage = Math.floor((userStrength * moveStrength) / targetResist); return Math.max(damage, 1); } /** * @param {(ElementType[]|string[])} techniqueTypes * @param {(ElementType[]|string[])} targetTypes * * @returns {number} */ function simpleDamageMultiplier (techniqueTypes, targetTypes) { let multiplier = 1; for (const techniqueType of techniqueTypes) { if (techniqueType === ElementType.aether) { continue; } for (const targetType of targetTypes) { if (targetType === ElementType.aether) { continue; } multiplier *= DB.elements[techniqueType].types.find((type) => type.against === targetType).multiplier; } } return Math.max(0.25, Math.min(multiplier, 4)); } /** * @param {Monster} opposingMonster * @param {Monster[]} participants * * @returns {number[]} */ function calculateAwardedExperience (opposingMonster, participants) { const awardedExperienceDistribution = []; for (const participantIndex in participants) { const participant = participants[participantIndex]; const awardedExperience = Math.max( Math.floor( opposingMonster.getExperienceRequired(-1) / opposingMonster.level * opposingMonster.experienceModifier / participant.level ), 1 ); awardedExperienceDistribution[participantIndex] = awardedExperience; } return awardedExperienceDistribution; } /** * @param {Monster} opposingMonster * * @returns {number} */ function calculateAwardedMoney (opposingMonster) { let money = opposingMonster.level * opposingMonster.moneyModifier; money = convertToCurrencyBase(money); return money; } /** * @param {Monster} playerMonster * @param {Monster} opposingMonster * @param {Item} ball * * @returns {boolean} */ function checkCapture (playerMonster, opposingMonster, ball) { const MAX_CATCH_RATE = 255; const MAX_ATTEMPT_RATE = 65536; const ATTEMPT_CONSTANT = 524325; // status effect let STATUS_MODIFER = 1.0; if (opposingMonster.statusEffect && opposingMonster.statusEffect.category === 'negative') { STATUS_MODIFER = 1.2; } // ball let BALL_MODIFIER = 1.0; if (ball.slug === 'tuxeball_wood') { if (opposingMonster.types.includes(ElementType.wood)) { BALL_MODIFIER = 1.5 } else { BALL_MODIFIER = 0.2; } } else if (ball.slug === 'tuxeball_fire') { if (opposingMonster.types.includes(ElementType.fire)) { BALL_MODIFIER = 1.5 } else { BALL_MODIFIER = 0.2; } } else if (ball.slug === 'tuxeball_earth') { if (opposingMonster.types.includes(ElementType.earth)) { BALL_MODIFIER = 1.5 } else { BALL_MODIFIER = 0.2; } } else if (ball.slug === 'tuxeball_metal') { if (opposingMonster.types.includes(ElementType.metal)) { BALL_MODIFIER = 1.5 } else { BALL_MODIFIER = 0.2; } } else if (ball.slug === 'tuxeball_water') { if (opposingMonster.types.includes(ElementType.water)) { BALL_MODIFIER = 1.5 } else { BALL_MODIFIER = 0.2; } } // calculate const catchCheck = Math.max( (3 * opposingMonster.hp - 2 * playerMonster.hp) * opposingMonster.catch_rate * STATUS_MODIFER * BALL_MODIFIER / (3 * opposingMonster.hp), 1 ); let attemptCheck = ATTEMPT_CONSTANT / ( Math.sqrt(Math.sqrt(MAX_CATCH_RATE / catchCheck)) * 8 ) const catchResistance = Math.random() * (opposingMonster.upper_catch_resistance - opposingMonster.lower_catch_resistance) + opposingMonster.lower_catch_resistance; attemptCheck = attemptCheck * catchResistance; return Math.random() * MAX_ATTEMPT_RATE > Math.round(attemptCheck); }