Spaces:
Running
Running
export const Scripts: ModdedBattleScriptsData = { | |
gen: 9, | |
actions: { | |
getDamage(source, target, move, suppressMessages) { | |
if (typeof move === 'string') move = this.dex.getActiveMove(move); | |
if (typeof move === 'number') { | |
const basePower = move; | |
move = new Dex.Move({ | |
basePower, | |
type: '???', | |
category: 'Physical', | |
willCrit: false, | |
}) as ActiveMove; | |
move.hit = 0; | |
} | |
if (!move.ignoreImmunity || (move.ignoreImmunity !== true && !move.ignoreImmunity[move.type])) { | |
if (!target.runImmunity(move.type, !suppressMessages)) { | |
return false; | |
} | |
} | |
if (move.ohko) return target.maxhp; | |
if (move.damageCallback) return move.damageCallback.call(this.battle, source, target); | |
if (move.damage === 'level') { | |
return source.level; | |
} else if (move.damage) { | |
return move.damage; | |
} | |
let basePower: number | false | null = move.basePower; | |
if (move.basePowerCallback) { | |
basePower = move.basePowerCallback.call(this.battle, source, target, move); | |
} | |
if (!basePower) return basePower === 0 ? undefined : basePower; | |
basePower = this.battle.clampIntRange(basePower, 1); | |
let critMult; | |
let critRatio = this.battle.runEvent('ModifyCritRatio', source, target, move, move.critRatio || 0); | |
if (this.battle.gen <= 5) { | |
critRatio = this.battle.clampIntRange(critRatio, 0, 5); | |
critMult = [0, 16, 8, 4, 3, 2]; | |
} else { | |
critRatio = this.battle.clampIntRange(critRatio, 0, 4); | |
if (this.battle.gen === 6) { | |
critMult = [0, 16, 8, 2, 1]; | |
} else { | |
critMult = [0, 24, 8, 2, 1]; | |
} | |
} | |
const moveHit = target.getMoveHitData(move); | |
moveHit.crit = move.willCrit || false; | |
if (move.willCrit === undefined) { | |
if (critRatio) { | |
moveHit.crit = this.battle.randomChance(1, critMult[critRatio]); | |
} | |
} | |
if (moveHit.crit) { | |
moveHit.crit = this.battle.runEvent('CriticalHit', target, null, move); | |
} | |
// happens after crit calculation | |
basePower = this.battle.runEvent('BasePower', source, target, move, basePower, true); | |
if (!basePower) return 0; | |
basePower = this.battle.clampIntRange(basePower, 1); | |
// Hacked Max Moves have 0 base power, even if you Dynamax | |
if ((!source.volatiles['dynamax'] && move.isMax) || (move.isMax && this.dex.moves.get(move.baseMove).isMax)) { | |
basePower = 0; | |
} | |
const level = source.level; | |
const attacker = move.overrideOffensivePokemon === 'target' ? target : source; | |
const defender = move.overrideDefensivePokemon === 'source' ? source : target; | |
const isPhysical = move.category === 'Physical'; | |
const defenseStat: StatIDExceptHP = move.overrideDefensiveStat || (isPhysical ? 'def' : 'spd'); | |
const statTable: { [k in StatIDExceptHP]: string } = { atk: 'Atk', def: 'Def', spa: 'SpA', spd: 'SpD', spe: 'Spe' }; | |
let maxAttack = 0; | |
let defBoosts = defender.boosts[defenseStat]; | |
let ignoreNegativeOffensive = !!move.ignoreNegativeOffensive; | |
let ignorePositiveDefensive = !!move.ignorePositiveDefensive; | |
if (moveHit.crit) { | |
ignoreNegativeOffensive = true; | |
ignorePositiveDefensive = true; | |
} | |
const ignoreDefensive = !!(move.ignoreDefensive || (ignorePositiveDefensive && defBoosts > 0)); | |
if (ignoreDefensive) { | |
this.battle.debug('Negating (sp)def boost/penalty.'); | |
defBoosts = 0; | |
} | |
let attack = 0; | |
for (const attackStat in statTable) { | |
let atkBoosts = attacker.boosts[attackStat as keyof BoostsTable]; | |
const ignoreOffensive = !!(move.ignoreOffensive || (ignoreNegativeOffensive && atkBoosts < 0)); | |
if (ignoreOffensive) { | |
this.battle.debug('Negating (sp)atk boost/penalty.'); | |
atkBoosts = 0; | |
} | |
attack = attacker.calculateStat(attackStat as any, atkBoosts, 1, source); | |
attack = this.battle.runEvent('Modify' + (statTable as any)[attackStat], source, target, move, attack); | |
if (attack > maxAttack) maxAttack = attack; | |
} | |
let defense = defender.calculateStat(defenseStat, defBoosts, 1, target); | |
// Apply Stat Modifiers | |
defense = this.battle.runEvent('Modify' + statTable[defenseStat], target, source, move, defense); | |
if (this.battle.gen <= 4 && ['explosion', 'selfdestruct'].includes(move.id) && defenseStat === 'def') { | |
defense = this.battle.clampIntRange(Math.floor(defense / 2), 1); | |
} | |
const tr = this.battle.trunc; | |
// int(int(int(2 * L / 5 + 2) * A * P / D) / 50); | |
const baseDamage = tr(tr(tr(tr(2 * level / 5 + 2) * basePower * maxAttack) / defense) / 50); | |
// Calculate damage modifiers separately (order differs between generations) | |
return this.modifyDamage(baseDamage, source, target, move, suppressMessages); | |
}, | |
}, | |
}; | |