[QoL] Highlight targets of multitarget moves instead of immediate execution (#2863)

* show targets for move targeting multiple pokemon

* dont allow selecting target if multiple

* fix targeting

* cleanup

* more cleanup

* only highlight targets is move is not status

* fix tests failing

* fix tests

* change "immediately" to "auto"

* nevermind just remove auto

* remove status move condition
This commit is contained in:
Adrian T 2024-07-12 02:17:02 +08:00 committed by GitHub
parent 2f81bd504c
commit aa90a9ff2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 59 additions and 40 deletions

View File

@ -1973,6 +1973,9 @@ export class CommandPhase extends FieldPhase {
turnCommand.targets = [this.fieldIndex]; turnCommand.targets = [this.fieldIndex];
} }
console.log(moveTargets, playerPokemon.name); console.log(moveTargets, playerPokemon.name);
if (moveTargets.targets.length > 1 && moveTargets.multiple) {
this.scene.unshiftPhase(new SelectTargetPhase(this.scene, this.fieldIndex));
}
if (moveTargets.targets.length <= 1 || moveTargets.multiple) { if (moveTargets.targets.length <= 1 || moveTargets.multiple) {
turnCommand.move.targets = moveTargets.targets; turnCommand.move.targets = moveTargets.targets;
} else if (playerPokemon.getTag(BattlerTagType.CHARGING) && playerPokemon.getMoveQueue().length >= 1) { } else if (playerPokemon.getTag(BattlerTagType.CHARGING) && playerPokemon.getMoveQueue().length >= 1) {
@ -2222,13 +2225,13 @@ export class SelectTargetPhase extends PokemonPhase {
const turnCommand = this.scene.currentBattle.turnCommands[this.fieldIndex]; const turnCommand = this.scene.currentBattle.turnCommands[this.fieldIndex];
const move = turnCommand.move?.move; const move = turnCommand.move?.move;
this.scene.ui.setMode(Mode.TARGET_SELECT, this.fieldIndex, move, (cursor: integer) => { this.scene.ui.setMode(Mode.TARGET_SELECT, this.fieldIndex, move, (targets: BattlerIndex[]) => {
this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.setMode(Mode.MESSAGE);
if (cursor === -1) { if (targets.length < 1) {
this.scene.currentBattle.turnCommands[this.fieldIndex] = null; this.scene.currentBattle.turnCommands[this.fieldIndex] = null;
this.scene.unshiftPhase(new CommandPhase(this.scene, this.fieldIndex)); this.scene.unshiftPhase(new CommandPhase(this.scene, this.fieldIndex));
} else { } else {
turnCommand.targets = [cursor]; turnCommand.targets = targets;
} }
if (turnCommand.command === Command.BALL && this.fieldIndex) { if (turnCommand.command === Command.BALL && this.fieldIndex) {
this.scene.currentBattle.turnCommands[this.fieldIndex - 1].skip = true; this.scene.currentBattle.turnCommands[this.fieldIndex - 1].skip = true;

View File

@ -8,7 +8,8 @@ import {
LoginPhase, LoginPhase,
NewBattlePhase, NewBattlePhase,
SelectStarterPhase, SelectStarterPhase,
TitlePhase, TurnInitPhase, SelectTargetPhase,
TitlePhase, TurnEndPhase, TurnInitPhase,
TurnStartPhase, TurnStartPhase,
} from "#app/phases"; } from "#app/phases";
import BattleScene from "#app/battle-scene.js"; import BattleScene from "#app/battle-scene.js";
@ -170,6 +171,15 @@ export default class GameManager {
this.onNextPrompt("CommandPhase", Mode.FIGHT, () => { this.onNextPrompt("CommandPhase", Mode.FIGHT, () => {
(this.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); (this.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false);
}); });
// Confirm target selection if move is multi-target
this.onNextPrompt("SelectTargetPhase", Mode.TARGET_SELECT, () => {
const handler = this.scene.ui.getHandler() as TargetSelectUiHandler;
const move = (this.scene.getCurrentPhase() as SelectTargetPhase).getPokemon().getMoveset()[movePosition].getMove();
if (move.isMultiTarget()) {
handler.processInput(Button.ACTION);
}
}, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnEndPhase));
} }
/** /**

View File

@ -6,17 +6,20 @@ import * as Utils from "../utils";
import { getMoveTargets } from "../data/move"; import { getMoveTargets } from "../data/move";
import {Button} from "#enums/buttons"; import {Button} from "#enums/buttons";
import { Moves } from "#enums/moves"; import { Moves } from "#enums/moves";
import Pokemon from "#app/field/pokemon.js";
export type TargetSelectCallback = (cursor: integer) => void; export type TargetSelectCallback = (targets: BattlerIndex[]) => void;
export default class TargetSelectUiHandler extends UiHandler { export default class TargetSelectUiHandler extends UiHandler {
private fieldIndex: integer; private fieldIndex: integer;
private move: Moves; private move: Moves;
private targetSelectCallback: TargetSelectCallback; private targetSelectCallback: TargetSelectCallback;
private isMultipleTargets: boolean = false;
private targets: BattlerIndex[]; private targets: BattlerIndex[];
private targetsHighlighted: Pokemon[];
private targetFlashTween: Phaser.Tweens.Tween; private targetFlashTween: Phaser.Tweens.Tween;
private targetBattleInfoMoveTween: Phaser.Tweens.Tween; private targetBattleInfoMoveTween: Phaser.Tweens.Tween[] = [];
constructor(scene: BattleScene) { constructor(scene: BattleScene) {
super(scene, Mode.TARGET_SELECT); super(scene, Mode.TARGET_SELECT);
@ -37,13 +40,15 @@ export default class TargetSelectUiHandler extends UiHandler {
this.move = args[1] as Moves; this.move = args[1] as Moves;
this.targetSelectCallback = args[2] as TargetSelectCallback; this.targetSelectCallback = args[2] as TargetSelectCallback;
this.targets = getMoveTargets(this.scene.getPlayerField()[this.fieldIndex], this.move).targets; const moveTargets = getMoveTargets(this.scene.getPlayerField()[this.fieldIndex], this.move);
this.targets = moveTargets.targets;
this.isMultipleTargets = moveTargets.multiple ?? false;
if (!this.targets.length) { if (!this.targets.length) {
return false; return false;
} }
this.setCursor(this.targets.indexOf(this.cursor) > -1 ? this.cursor : this.targets[0]); this.setCursor(this.targets.includes(this.cursor) ? this.cursor : this.targets[0]);
return true; return true;
} }
@ -54,8 +59,11 @@ export default class TargetSelectUiHandler extends UiHandler {
let success = false; let success = false;
if (button === Button.ACTION || button === Button.CANCEL) { if (button === Button.ACTION || button === Button.CANCEL) {
this.targetSelectCallback(button === Button.ACTION ? this.cursor : -1); const targetIndexes: BattlerIndex[] = this.isMultipleTargets ? this.targets : [this.cursor];
this.targetSelectCallback(button === Button.ACTION ? targetIndexes : []);
success = true; success = true;
} else if (this.isMultipleTargets) {
success = false;
} else { } else {
switch (button) { switch (button) {
case Button.UP: case Button.UP:
@ -89,73 +97,71 @@ export default class TargetSelectUiHandler extends UiHandler {
} }
setCursor(cursor: integer): boolean { setCursor(cursor: integer): boolean {
const lastCursor = this.cursor; const singleTarget = this.scene.getField()[cursor];
const multipleTargets = this.targets.map(index => this.scene.getField()[index]);
this.targetsHighlighted = this.isMultipleTargets ? multipleTargets : [ singleTarget ];
const ret = super.setCursor(cursor); const ret = super.setCursor(cursor);
if (this.targetFlashTween) { if (this.targetFlashTween) {
this.targetFlashTween.stop(); this.targetFlashTween.stop();
const lastTarget = this.scene.getField()[lastCursor]; for (const pokemon of multipleTargets) {
if (lastTarget) { pokemon.setAlpha(1);
lastTarget.setAlpha(1);
} }
} }
const target = this.scene.getField()[cursor];
this.targetFlashTween = this.scene.tweens.add({ this.targetFlashTween = this.scene.tweens.add({
targets: [ target ], targets: this.targetsHighlighted,
alpha: 0, alpha: 0,
loop: -1, loop: -1,
duration: Utils.fixedInt(250), duration: Utils.fixedInt(250),
ease: "Sine.easeIn", ease: "Sine.easeIn",
yoyo: true, yoyo: true,
onUpdate: t => { onUpdate: t => {
if (target) { for (const target of this.targetsHighlighted) {
target.setAlpha(t.getValue()); target.setAlpha(t.getValue());
} }
} }
}); });
if (this.targetBattleInfoMoveTween.length >= 1) {
if (this.targetBattleInfoMoveTween) { this.targetBattleInfoMoveTween.filter(t => t !== undefined).forEach(tween => tween.stop());
this.targetBattleInfoMoveTween.stop(); for (const pokemon of multipleTargets) {
const lastTarget = this.scene.getField()[lastCursor]; pokemon.getBattleInfo().resetY();
if (lastTarget) {
lastTarget.getBattleInfo().resetY();
} }
} }
const targetBattleInfo = target.getBattleInfo(); const targetsBattleInfo = this.targetsHighlighted.map(target => target.getBattleInfo());
this.targetBattleInfoMoveTween = this.scene.tweens.add({ targetsBattleInfo.map(info => {
targets: [ targetBattleInfo ], this.targetBattleInfoMoveTween.push(this.scene.tweens.add({
y: { start: targetBattleInfo.getBaseY(), to: targetBattleInfo.getBaseY() + 1 }, targets: [ info ],
loop: -1, y: { start: info.getBaseY(), to: info.getBaseY() + 1 },
duration: Utils.fixedInt(250), loop: -1,
ease: "Linear", duration: Utils.fixedInt(250),
yoyo: true ease: "Linear",
yoyo: true
}));
}); });
return ret; return ret;
} }
eraseCursor() { eraseCursor() {
const target = this.scene.getField()[this.cursor];
if (this.targetFlashTween) { if (this.targetFlashTween) {
this.targetFlashTween.stop(); this.targetFlashTween.stop();
this.targetFlashTween = null; this.targetFlashTween = null;
} }
if (target) { for (const pokemon of this.targetsHighlighted) {
target.setAlpha(1); pokemon.setAlpha(1);
} }
const targetBattleInfo = target.getBattleInfo(); if (this.targetBattleInfoMoveTween.length >= 1) {
if (this.targetBattleInfoMoveTween) { this.targetBattleInfoMoveTween.filter(t => t !== undefined).forEach(tween => tween.stop());
this.targetBattleInfoMoveTween.stop(); this.targetBattleInfoMoveTween = [];
this.targetBattleInfoMoveTween = null;
} }
if (targetBattleInfo) { for (const pokemon of this.targetsHighlighted) {
targetBattleInfo.resetY(); pokemon.getBattleInfo().resetY();
} }
} }