pokerogue/src/phases/damage-phase.ts
innerthunder 70295280da
[Move] Implement Substitute (#2559)
* Implement Substitute

Squashed commit from working branch

* Fix integration test imports

* Use Override Helper utils + Fix Baton Pass test

* Update src/test/moves/substitute.test.ts

Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com>

* Fix test imports + nits

* Document RemoveAllSubstitutesAttr

* Fix some strict-null issues

* more strict-null fixes

* Fix baton pass test

* Reorganized Substitute translation keys

* Added checks for substitute in contact logic

* Clean up Unseen Fist contact logic

* Remove misleading comment in Download attr

* RIP phases.ts

* Fix imports post-phase migration

* Rewrite `move.canIgnoreSubstitute` to `move.hitsSubstitute`

* Also fixed interactions with Shell Trap and Beak Blast

* Removed some leftover `canIgnoreSubstitute`s

* fix issues after beta merge

* Status move effectiveness now accounts for substitute

* More edge case tests (Counter test failing)

* Fix Counter + Trap edge cases + add Fail messagesd

* Fix leftover nit

* Resolve leftover test issues

* Fix Sub offset carrying over to Trainer fights

* Hide substitute sprite during catch attempts

* Make substitutes baton-passable again

* Remove placeholder locale keys and SPLASH_ONLY

* Fix imports and other nits

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* ESLint

* Fix imports

* Fix incorrect `resetSprite` timing

* Fix substitute disappearing on hit (maybe?)

* More animation fixes (mostly for Roar)

---------

Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com>
Co-authored-by: flx-sta <50131232+flx-sta@users.noreply.github.com>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
2024-09-13 12:46:22 -04:00

85 lines
2.3 KiB
TypeScript

import BattleScene from "#app/battle-scene";
import { BattlerIndex } from "#app/battle";
import { BattleSpec } from "#app/enums/battle-spec";
import { DamageResult, HitResult } from "#app/field/pokemon";
import * as Utils from "#app/utils";
import { PokemonPhase } from "./pokemon-phase";
export class DamagePhase extends PokemonPhase {
private amount: integer;
private damageResult: DamageResult;
private critical: boolean;
constructor(scene: BattleScene, battlerIndex: BattlerIndex, amount: integer, damageResult?: DamageResult, critical: boolean = false) {
super(scene, battlerIndex);
this.amount = amount;
this.damageResult = damageResult || HitResult.EFFECTIVE;
this.critical = critical;
}
start() {
super.start();
if (this.damageResult === HitResult.ONE_HIT_KO) {
if (this.scene.moveAnimations) {
this.scene.toggleInvert(true);
}
this.scene.time.delayedCall(Utils.fixedInt(1000), () => {
this.scene.toggleInvert(false);
this.applyDamage();
});
return;
}
this.applyDamage();
}
updateAmount(amount: integer): void {
this.amount = amount;
}
applyDamage() {
switch (this.damageResult) {
case HitResult.EFFECTIVE:
this.scene.playSound("se/hit");
break;
case HitResult.SUPER_EFFECTIVE:
case HitResult.ONE_HIT_KO:
this.scene.playSound("se/hit_strong");
break;
case HitResult.NOT_VERY_EFFECTIVE:
this.scene.playSound("se/hit_weak");
break;
}
if (this.amount) {
this.scene.damageNumberHandler.add(this.getPokemon(), this.amount, this.damageResult, this.critical);
}
if (this.damageResult !== HitResult.OTHER && this.amount > 0) {
const flashTimer = this.scene.time.addEvent({
delay: 100,
repeat: 5,
startAt: 200,
callback: () => {
this.getPokemon().getSprite().setVisible(flashTimer.repeatCount % 2 === 0);
if (!flashTimer.repeatCount) {
this.getPokemon().updateInfo().then(() => this.end());
}
}
});
} else {
this.getPokemon().updateInfo().then(() => this.end());
}
}
override end() {
if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
this.scene.initFinalBossPhaseTwo(this.getPokemon());
} else {
super.end();
}
}
}