Rename HitResult.OTHER to INDIRECT, create INDIRECT_KO for PSong/DBond, add functionality for INDIRECT_KO to damageanim/number handler

This commit is contained in:
Christopher Schmidt 2025-02-20 20:42:21 -05:00
parent 5ede4be6e0
commit 27c01bbbc4
10 changed files with 33 additions and 30 deletions

View File

@ -958,7 +958,7 @@ export class PostDefendContactDamageAbAttr extends PostDefendAbAttr {
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): boolean { override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): boolean {
if (!simulated && move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) if (!simulated && move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)
&& !attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr) && !move.hitsSubstitute(attacker, pokemon)) { && !attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr) && !move.hitsSubstitute(attacker, pokemon)) {
attacker.damageAndUpdate(Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); attacker.damageAndUpdate(Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.INDIRECT);
attacker.turnData.damageTaken += Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)); attacker.turnData.damageTaken += Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio));
return true; return true;
} }
@ -3469,7 +3469,7 @@ export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr {
if (!simulated) { if (!simulated) {
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
globalScene.queueMessage(i18next.t("abilityTriggers:postWeatherLapseDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName })); globalScene.queueMessage(i18next.t("abilityTriggers:postWeatherLapseDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }));
pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / (16 / this.damageFactor)), HitResult.OTHER); pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / (16 / this.damageFactor)), HitResult.INDIRECT);
} }
return true; return true;
@ -3781,7 +3781,7 @@ export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr {
for (const opp of pokemon.getOpponents()) { for (const opp of pokemon.getOpponents()) {
if ((opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(Abilities.COMATOSE)) && !opp.hasAbilityWithAttr(BlockNonDirectDamageAbAttr) && !opp.switchOutStatus) { if ((opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(Abilities.COMATOSE)) && !opp.hasAbilityWithAttr(BlockNonDirectDamageAbAttr) && !opp.switchOutStatus) {
if (!simulated) { if (!simulated) {
opp.damageAndUpdate(Utils.toDmgValue(opp.getMaxHp() / 8), HitResult.OTHER); opp.damageAndUpdate(Utils.toDmgValue(opp.getMaxHp() / 8), HitResult.INDIRECT);
globalScene.queueMessage(i18next.t("abilityTriggers:badDreams", { pokemonName: getPokemonNameWithAffix(opp) })); globalScene.queueMessage(i18next.t("abilityTriggers:badDreams", { pokemonName: getPokemonNameWithAffix(opp) }));
} }
hadEffect = true; hadEffect = true;
@ -4236,7 +4236,7 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr {
return false; return false;
} }
if (!simulated) { if (!simulated) {
attacker.damageAndUpdate(Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); attacker.damageAndUpdate(Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.INDIRECT);
attacker.turnData.damageTaken += Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)); attacker.turnData.damageTaken += Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio));
} }
return true; return true;
@ -4261,7 +4261,7 @@ export class PostFaintHPDamageAbAttr extends PostFaintAbAttr {
applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean { applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
if (move !== undefined && attacker !== undefined && !simulated) { //If the mon didn't die to indirect damage if (move !== undefined && attacker !== undefined && !simulated) { //If the mon didn't die to indirect damage
const damage = pokemon.turnData.attacksReceived[0].damage; const damage = pokemon.turnData.attacksReceived[0].damage;
attacker.damageAndUpdate((damage), HitResult.OTHER); attacker.damageAndUpdate((damage), HitResult.INDIRECT);
attacker.turnData.damageTaken += damage; attacker.turnData.damageTaken += damage;
} }
return true; return true;
@ -4675,7 +4675,7 @@ export class FormBlockDamageAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
(args[0] as Utils.NumberHolder).value = this.multiplier; (args[0] as Utils.NumberHolder).value = this.multiplier;
pokemon.removeTag(this.tagType); pokemon.removeTag(this.tagType);
if (this.recoilDamageFunc) { if (this.recoilDamageFunc) {
pokemon.damageAndUpdate(this.recoilDamageFunc(pokemon), HitResult.OTHER, false, true, true); pokemon.damageAndUpdate(this.recoilDamageFunc(pokemon), HitResult.INDIRECT, false, true, true);
} }
} }
return true; return true;

View File

@ -698,7 +698,7 @@ class SpikesTag extends ArenaTrapTag {
const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio); const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio);
globalScene.queueMessage(i18next.t("arenaTag:spikesActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); globalScene.queueMessage(i18next.t("arenaTag:spikesActivateTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
pokemon.damageAndUpdate(damage, HitResult.OTHER); pokemon.damageAndUpdate(damage, HitResult.INDIRECT);
if (pokemon.turnData) { if (pokemon.turnData) {
pokemon.turnData.damageTaken += damage; pokemon.turnData.damageTaken += damage;
} }

View File

@ -723,7 +723,7 @@ export class DestinyBondTag extends BattlerTag {
pokemonNameWithAffix2: getPokemonNameWithAffix(pokemon) pokemonNameWithAffix2: getPokemonNameWithAffix(pokemon)
}) })
); );
pokemon.damageAndUpdate(pokemon.hp, HitResult.OTHER, false, true); pokemon.damageAndUpdate(pokemon.hp, HitResult.INDIRECT_KO, false, true);
return false; return false;
} }
} }
@ -898,7 +898,7 @@ export class PowderTag extends BattlerTag {
const cancelDamage = new BooleanHolder(false); const cancelDamage = new BooleanHolder(false);
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelDamage); applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelDamage);
if (!cancelDamage.value) { if (!cancelDamage.value) {
pokemon.damageAndUpdate(Math.floor(pokemon.getMaxHp() / 4), HitResult.OTHER); pokemon.damageAndUpdate(Math.floor(pokemon.getMaxHp() / 4), HitResult.INDIRECT);
} }
// "When the flame touched the powder\non the Pokémon, it exploded!" // "When the flame touched the powder\non the Pokémon, it exploded!"
@ -1459,7 +1459,7 @@ export class ContactDamageProtectedTag extends ProtectedTag {
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) {
const attacker = effectPhase.getPokemon(); const attacker = effectPhase.getPokemon();
if (!attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { if (!attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {
attacker.damageAndUpdate(toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); attacker.damageAndUpdate(toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.INDIRECT);
} }
} }
} }
@ -1613,7 +1613,7 @@ export class PerishSongTag extends BattlerTag {
}) })
); );
} else { } else {
pokemon.damageAndUpdate(pokemon.hp, HitResult.ONE_HIT_KO, false, true); pokemon.damageAndUpdate(pokemon.hp, HitResult.INDIRECT_KO, false, true);
} }
return ret; return ret;
@ -2327,7 +2327,7 @@ export class GulpMissileTag extends BattlerTag {
applyAbAttrs(BlockNonDirectDamageAbAttr, attacker, cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, attacker, cancelled);
if (!cancelled.value) { if (!cancelled.value) {
attacker.damageAndUpdate(Math.max(1, Math.floor(attacker.getMaxHp() / 4)), HitResult.OTHER); attacker.damageAndUpdate(Math.max(1, Math.floor(attacker.getMaxHp() / 4)), HitResult.INDIRECT);
} }
if (this.tagType === BattlerTagType.GULP_MISSILE_ARROKUDA) { if (this.tagType === BattlerTagType.GULP_MISSILE_ARROKUDA) {

View File

@ -1568,7 +1568,7 @@ export class RecoilAttr extends MoveEffectAttr {
return false; return false;
} }
user.damageAndUpdate(recoilDamage, HitResult.OTHER, false, true); user.damageAndUpdate(recoilDamage, HitResult.INDIRECT, false, true);
globalScene.queueMessage(i18next.t("moveTriggers:hitWithRecoil", { pokemonName: getPokemonNameWithAffix(user) })); globalScene.queueMessage(i18next.t("moveTriggers:hitWithRecoil", { pokemonName: getPokemonNameWithAffix(user) }));
user.turnData.damageTaken += recoilDamage; user.turnData.damageTaken += recoilDamage;
@ -1600,7 +1600,7 @@ export class SacrificialAttr extends MoveEffectAttr {
* @returns true if the function succeeds * @returns true if the function succeeds
**/ **/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
user.damageAndUpdate(user.hp, HitResult.OTHER, false, true); user.damageAndUpdate(user.hp, HitResult.INDIRECT, false, true);
user.turnData.damageTaken += user.hp; user.turnData.damageTaken += user.hp;
return true; return true;
@ -1638,7 +1638,7 @@ export class SacrificialAttrOnHit extends MoveEffectAttr {
return false; return false;
} }
user.damageAndUpdate(user.hp, HitResult.OTHER, false, true); user.damageAndUpdate(user.hp, HitResult.INDIRECT, false, true);
user.turnData.damageTaken += user.hp; user.turnData.damageTaken += user.hp;
return true; return true;
@ -1680,7 +1680,7 @@ export class HalfSacrificialAttr extends MoveEffectAttr {
// Check to see if the Pokemon has an ability that blocks non-direct damage // Check to see if the Pokemon has an ability that blocks non-direct damage
applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled);
if (!cancelled.value) { if (!cancelled.value) {
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / 2), HitResult.OTHER, false, true); user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / 2), HitResult.INDIRECT, false, true);
globalScene.queueMessage(i18next.t("moveTriggers:cutHpPowerUpMove", { pokemonName: getPokemonNameWithAffix(user) })); // Queue recoil message globalScene.queueMessage(i18next.t("moveTriggers:cutHpPowerUpMove", { pokemonName: getPokemonNameWithAffix(user) })); // Queue recoil message
} }
return true; return true;
@ -1723,7 +1723,7 @@ export class AddSubstituteAttr extends MoveEffectAttr {
return false; return false;
} }
user.damageAndUpdate(Math.floor(user.getMaxHp() * this.hpCost), HitResult.OTHER, false, true); user.damageAndUpdate(Math.floor(user.getMaxHp() * this.hpCost), HitResult.INDIRECT, false, true);
user.addTag(BattlerTagType.SUBSTITUTE, 0, move.id, user.id); user.addTag(BattlerTagType.SUBSTITUTE, 0, move.id, user.id);
return true; return true;
} }
@ -1878,7 +1878,7 @@ export class FlameBurstAttr extends MoveEffectAttr {
return false; return false;
} }
targetAlly.damageAndUpdate(Math.max(1, Math.floor(1 / 16 * targetAlly.getMaxHp())), HitResult.OTHER); targetAlly.damageAndUpdate(Math.max(1, Math.floor(1 / 16 * targetAlly.getMaxHp())), HitResult.INDIRECT);
return true; return true;
} }
@ -3326,7 +3326,7 @@ export class CutHpStatStageBoostAttr extends StatStageChangeAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
return new Promise<boolean>(resolve => { return new Promise<boolean>(resolve => {
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / this.cutRatio), HitResult.OTHER, false); user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / this.cutRatio), HitResult.INDIRECT, false);
user.updateInfo().then(() => { user.updateInfo().then(() => {
const ret = super.apply(user, target, move, args); const ret = super.apply(user, target, move, args);
if (this.messageCallback) { if (this.messageCallback) {
@ -5236,7 +5236,7 @@ const crashDamageFunc = (user: Pokemon, move: Move) => {
return false; return false;
} }
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / 2), HitResult.OTHER, false); user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / 2), HitResult.INDIRECT, false);
globalScene.queueMessage(i18next.t("moveTriggers:keptGoingAndCrashed", { pokemonName: getPokemonNameWithAffix(user) })); globalScene.queueMessage(i18next.t("moveTriggers:keptGoingAndCrashed", { pokemonName: getPokemonNameWithAffix(user) }));
user.turnData.damageTaken += Utils.toDmgValue(user.getMaxHp() / 2); user.turnData.damageTaken += Utils.toDmgValue(user.getMaxHp() / 2);
@ -5532,7 +5532,7 @@ export class CurseAttr extends MoveEffectAttr {
return false; return false;
} }
const curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2)); const curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2));
user.damageAndUpdate(curseRecoilDamage, HitResult.OTHER, false, true); user.damageAndUpdate(curseRecoilDamage, HitResult.INDIRECT, false, true);
globalScene.queueMessage( globalScene.queueMessage(
i18next.t("battlerTags:cursedOnAdd", { i18next.t("battlerTags:cursedOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(user), pokemonNameWithAffix: getPokemonNameWithAffix(user),

View File

@ -36,6 +36,7 @@ export default class DamageNumberHandler {
case HitResult.NOT_VERY_EFFECTIVE: case HitResult.NOT_VERY_EFFECTIVE:
[ textColor, shadowColor ] = [ "#f08030", "#c03028" ]; [ textColor, shadowColor ] = [ "#f08030", "#c03028" ];
break; break;
case HitResult.INDIRECT_KO:
case HitResult.ONE_HIT_KO: case HitResult.ONE_HIT_KO:
[ textColor, shadowColor ] = [ "#a040a0", "#483850" ]; [ textColor, shadowColor ] = [ "#a040a0", "#483850" ];
break; break;

View File

@ -3163,7 +3163,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
damageAndUpdate(damage: number, result?: DamageResult, critical: boolean = false, ignoreSegments: boolean = false, ignoreFaintPhase: boolean = false, source?: Pokemon): number { damageAndUpdate(damage: number, result?: DamageResult, critical: boolean = false, ignoreSegments: boolean = false, ignoreFaintPhase: boolean = false, source?: Pokemon): number {
let isIndirectDamage: boolean = true; let isIndirectDamage: boolean = true;
if (result !== undefined) { if (result !== undefined) {
if (result === HitResult.OTHER) { if (result === HitResult.INDIRECT || result === HitResult.INDIRECT_KO) {
isIndirectDamage = true; isIndirectDamage = true;
} else { } else {
isIndirectDamage = false; isIndirectDamage = false;
@ -5506,12 +5506,13 @@ export enum HitResult {
HEAL, HEAL,
FAIL, FAIL,
MISS, MISS,
OTHER, INDIRECT,
IMMUNE, IMMUNE,
CONFUSION CONFUSION,
INDIRECT_KO
} }
export type DamageResult = HitResult.EFFECTIVE | HitResult.SUPER_EFFECTIVE | HitResult.NOT_VERY_EFFECTIVE | HitResult.ONE_HIT_KO | HitResult.CONFUSION | HitResult.OTHER; export type DamageResult = HitResult.EFFECTIVE | HitResult.SUPER_EFFECTIVE | HitResult.NOT_VERY_EFFECTIVE | HitResult.ONE_HIT_KO | HitResult.CONFUSION | HitResult.INDIRECT_KO | HitResult.INDIRECT;
/** Interface containing the results of a damage calculation for a given move */ /** Interface containing the results of a damage calculation for a given move */
export interface DamageCalculationResult { export interface DamageCalculationResult {

View File

@ -21,7 +21,7 @@ export class DamageAnimPhase extends PokemonPhase {
start() { start() {
super.start(); super.start();
if (this.damageResult === HitResult.ONE_HIT_KO) { if (this.damageResult === HitResult.ONE_HIT_KO || this.damageResult === HitResult.INDIRECT_KO) {
if (globalScene.moveAnimations) { if (globalScene.moveAnimations) {
globalScene.toggleInvert(true); globalScene.toggleInvert(true);
} }
@ -46,6 +46,7 @@ export class DamageAnimPhase extends PokemonPhase {
globalScene.playSound("se/hit"); globalScene.playSound("se/hit");
break; break;
case HitResult.SUPER_EFFECTIVE: case HitResult.SUPER_EFFECTIVE:
case HitResult.INDIRECT_KO:
case HitResult.ONE_HIT_KO: case HitResult.ONE_HIT_KO:
globalScene.playSound("se/hit_strong"); globalScene.playSound("se/hit_strong");
break; break;
@ -58,7 +59,7 @@ export class DamageAnimPhase extends PokemonPhase {
globalScene.damageNumberHandler.add(this.getPokemon(), this.amount, this.damageResult, this.critical); globalScene.damageNumberHandler.add(this.getPokemon(), this.amount, this.damageResult, this.critical);
} }
if (this.damageResult !== HitResult.OTHER && this.amount > 0) { if (this.damageResult !== HitResult.INDIRECT && this.amount > 0) {
const flashTimer = globalScene.time.addEvent({ const flashTimer = globalScene.time.addEvent({
delay: 100, delay: 100,
repeat: 5, repeat: 5,

View File

@ -210,7 +210,7 @@ export class FaintPhase extends PokemonPhase {
} else { } else {
// Final boss' HP threshold has been bypassed; cancel faint and force check for 2nd phase // Final boss' HP threshold has been bypassed; cancel faint and force check for 2nd phase
enemy.hp++; enemy.hp++;
globalScene.unshiftPhase(new DamageAnimPhase(enemy.getBattlerIndex(), 0, HitResult.OTHER)); globalScene.unshiftPhase(new DamageAnimPhase(enemy.getBattlerIndex(), 0, HitResult.INDIRECT));
this.end(); this.end();
} }
return true; return true;

View File

@ -68,7 +68,7 @@ export class PokemonHealPhase extends CommonAnimPhase {
} }
const healAmount = new Utils.NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value)); const healAmount = new Utils.NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value));
if (healAmount.value < 0) { if (healAmount.value < 0) {
pokemon.damageAndUpdate(healAmount.value * -1, HitResult.OTHER as DamageResult); pokemon.damageAndUpdate(healAmount.value * -1, HitResult.INDIRECT as DamageResult);
healAmount.value = 0; healAmount.value = 0;
} }
// Prevent healing to full if specified (in case of healing tokens so Sturdy doesn't cause a softlock) // Prevent healing to full if specified (in case of healing tokens so Sturdy doesn't cause a softlock)

View File

@ -49,7 +49,7 @@ export class WeatherEffectPhase extends CommonAnimPhase {
const damage = Utils.toDmgValue(pokemon.getMaxHp() / 16); const damage = Utils.toDmgValue(pokemon.getMaxHp() / 16);
globalScene.queueMessage(getWeatherDamageMessage(this.weather?.weatherType!, pokemon)!); // TODO: are those bangs correct? globalScene.queueMessage(getWeatherDamageMessage(this.weather?.weatherType!, pokemon)!); // TODO: are those bangs correct?
pokemon.damageAndUpdate(damage, HitResult.OTHER, false, true); pokemon.damageAndUpdate(damage, HitResult.INDIRECT, false, true);
}; };
this.executeForAll((pokemon: Pokemon) => { this.executeForAll((pokemon: Pokemon) => {