Give IV-Scanner a menu and a toggle

This commit is contained in:
karl-police 2024-05-18 03:19:19 +02:00
parent 7935f28089
commit 1db10e952b
3 changed files with 207 additions and 10 deletions

View File

@ -1,5 +1,5 @@
import * as ModifierTypes from './modifier-type'; import * as ModifierTypes from './modifier-type';
import { LearnMovePhase, LevelUpPhase, PokemonHealPhase } from "../phases"; import { LearnMovePhase, LevelUpPhase, PokemonHealPhase, ScanIvsPhase, CommandPhase } from "../phases";
import BattleScene from "../battle-scene"; import BattleScene from "../battle-scene";
import { getLevelTotalExp } from "../data/exp"; import { getLevelTotalExp } from "../data/exp";
import { PokeballType } from "../data/pokeball"; import { PokeballType } from "../data/pokeball";
@ -21,6 +21,13 @@ import { Nature } from '#app/data/nature';
import { BattlerTagType } from '#app/data/enums/battler-tag-type'; import { BattlerTagType } from '#app/data/enums/battler-tag-type';
import * as Overrides from '../overrides'; import * as Overrides from '../overrides';
import { ModifierType, modifierTypes } from './modifier-type'; import { ModifierType, modifierTypes } from './modifier-type';
import { Mode } from '#app/ui/ui.js';
import i18next from 'i18next';
import { BattleType } from '#app/battle.js';
import { battleMessageUiHandler } from '#app/locales/de/battle-message-ui-handler.js';
import BattleMessageUiHandler from '#app/ui/battle-message-ui-handler.js';
import Button from 'phaser3-rex-plugins/plugins/button';
import { CommonAnim, CommonBattleAnim } from '#app/data/battle-anims.js';
export type ModifierPredicate = (modifier: Modifier) => boolean; export type ModifierPredicate = (modifier: Modifier) => boolean;
@ -70,6 +77,16 @@ export class ModifierBar extends Phaser.GameObjects.Container {
if (this.modifierCache && this.modifierCache.length > iconOverflowIndex) if (this.modifierCache && this.modifierCache.length > iconOverflowIndex)
thisArg.updateModifierOverflowVisibility(false); thisArg.updateModifierOverflowVisibility(false);
}); });
/*
Pseudo-Click Events.
Pseudo because POINTER_DOWN is when input is down.
TODO: A real click is when mouse is down, and goes up
while still inside the element's X and Y.
*/
icon.on(Phaser.Input.Events.POINTER_DOWN, () => {
modifier.onClick(this.scene);
})
}); });
for (let icon of this.getAll()) for (let icon of this.getAll())
@ -110,6 +127,8 @@ export abstract class Modifier {
} }
abstract apply(args: any[]): boolean | Promise<boolean>; abstract apply(args: any[]): boolean | Promise<boolean>;
onClick(scene: Phaser.Scene) {};
} }
export abstract class PersistentModifier extends Modifier { export abstract class PersistentModifier extends Modifier {
@ -1925,6 +1944,10 @@ export class IvScannerModifier extends PersistentModifier {
super(type, stackCount); super(type, stackCount);
} }
// Whether the IV-Scanner, should auto-prompt each wave.
public shouldAutoPrompt: boolean = true;
private isForceScanning: boolean = false;
match(modifier: Modifier): boolean { match(modifier: Modifier): boolean {
return modifier instanceof IvScannerModifier; return modifier instanceof IvScannerModifier;
} }
@ -1940,6 +1963,133 @@ export class IvScannerModifier extends PersistentModifier {
getMaxStackCount(scene: BattleScene): integer { getMaxStackCount(scene: BattleScene): integer {
return 3; return 3;
} }
// Opens the menu for the IV Scanner
// Does not implement own sanity checks.
openIvScannerMenu(scene: BattleScene): void {
// Only if not a Trainer
if (scene.currentBattle.battleType !== BattleType.WILD) {
return;
}
// We shall prevent this phase being stacked through clicks.
if (scene.getCurrentPhase() instanceof ScanIvsPhase)
return;
// Interrupt the current phase, if it is our turn
if (!(scene.getCurrentPhase() instanceof CommandPhase)) {
//console.log("Not our turn!")
return;
}
var commandPhase = scene.getCurrentPhase() as CommandPhase;
const enemyField = scene.getEnemyField();
var scanOptions = [];
// Create buttons for every enemy Pokemon
enemyField.map(pokemon => {
scanOptions.push({
label: `Scan: ${pokemon.name}`,
handler: () => {
scene.ui.revertMode(); // hide commandPhase controls
// Show prompt
// Handler to close the IV Prompt
scene.ui.setMode(Mode.MESSAGE);
scene.ui.clearText();
scene.ui.showText(`${pokemon.name}`, null, () => {
new CommonBattleAnim(CommonAnim.LOCK_ON, pokemon, pokemon).play(scene, () => {
scene.ui.getMessageHandler().promptIvs(pokemon.id, pokemon.ivs, Math.min(this.getStackCount() * 2, 6))
// promptIvs has its own Action Handler, and once that is executed, the promise is resolved
.then(() => {
scene.ui.showText(null, 0);
// go back to our commandPhase prompt
scene.ui.setMode(Mode.COMMAND, commandPhase.getFieldIndex());
});
});
});
return true;
},
keepOpen: false,
})
})
const ivOptions = [
{
// Label automatically changes text.
label: `Toggle ${this.shouldAutoPrompt ? "OFF" : "ON"}`,
handler: () => {
scene.ui.revertMode();
// Message Confirmation Mode
scene.ui.setMode(Mode.MESSAGE);
// Toggle
this.shouldAutoPrompt = !this.shouldAutoPrompt;
let textToShow = `IV-Scanner auto-prompt\nhas been toggled ${this.shouldAutoPrompt ? "ON" : "OFF"}`;
scene.ui.showText(textToShow, null, () => {
scene.ui.showText(null, 0);
// go back to our commandPhase prompt
scene.ui.setMode(Mode.COMMAND, commandPhase.getFieldIndex());
}, null, true);
return true;
},
// Prevents the container from closing after selecting
keepOpen: false,
},
// Auto put in the Pokemon Scan options right here!
// Thanks to the --> ...
...scanOptions.map(option => ({
...option,
})),
{
label: i18next.t('menuUiHandler:cancel'),
handler: () => {
scene.ui.revertMode(); // closes the container ui
scene.ui.setMode(Mode.COMMAND, commandPhase.getFieldIndex());
return true;
}
}
];
const ivOptionsConfig = {
xOffset: 98,
options: ivOptions
};
scene.ui.setOverlayMode(Mode.MENU_OPTION_SELECT, ivOptionsConfig);
}
// Click Event for the IV-Scanner
onClick(scene: BattleScene): void {
this.openIvScannerMenu(scene);
// Put in queue at the top.
//scene.unshiftPhase(scene.getCurrentPhase());
// Add a Phase for every enemy.
/*enemyField.map(
p => {
var iv = new ScanIvsPhase(scene, p.getBattlerIndex(), Math.min(this.getStackCount() * 2, 6))
scene.unshiftPhase(iv);
}
);*/
// Interrupt the CommandPhase
//scene.shiftPhase();
}
} }
export class ExtraModifierModifier extends PersistentModifier { export class ExtraModifierModifier extends PersistentModifier {

View File

@ -4828,6 +4828,12 @@ export class ScanIvsPhase extends PokemonPhase {
const pokemon = this.getPokemon(); const pokemon = this.getPokemon();
const ivScannerModifier = this.scene.findModifier(m => m instanceof IvScannerModifier) as IvScannerModifier;
// Only show if auto-prompt is enabled.
if (!ivScannerModifier.shouldAutoPrompt)
return this.end()
this.scene.ui.showText(i18next.t('battle:ivScannerUseQuestion', { pokemonName: pokemon.name }), null, () => { this.scene.ui.showText(i18next.t('battle:ivScannerUseQuestion', { pokemonName: pokemon.name }), null, () => {
this.scene.ui.setMode(Mode.CONFIRM, () => { this.scene.ui.setMode(Mode.CONFIRM, () => {
this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.setMode(Mode.MESSAGE);

View File

@ -7,12 +7,16 @@ import { Mode } from "./ui";
import UiHandler from "./ui-handler"; import UiHandler from "./ui-handler";
import { addWindow } from "./ui-theme"; import { addWindow } from "./ui-theme";
import {Button} from "../enums/buttons"; import {Button} from "../enums/buttons";
import { IvScannerModifier } from "#app/modifier/modifier.js";
export default class BallUiHandler extends UiHandler { export default class BallUiHandler extends UiHandler {
private pokeballSelectContainer: Phaser.GameObjects.Container; private pokeballSelectContainer: Phaser.GameObjects.Container;
private pokeballSelectBg: Phaser.GameObjects.NineSlice; private pokeballSelectBg: Phaser.GameObjects.NineSlice;
private optionsText: Phaser.GameObjects.Text;
private countsText: Phaser.GameObjects.Text; private countsText: Phaser.GameObjects.Text;
private ivScannerAdded = false;
private cursorObj: Phaser.GameObjects.Image; private cursorObj: Phaser.GameObjects.Image;
constructor(scene: BattleScene) { constructor(scene: BattleScene) {
@ -32,14 +36,17 @@ export default class BallUiHandler extends UiHandler {
let optionsTextContent = ''; let optionsTextContent = '';
for (let pb = 0; pb < Object.keys(this.scene.pokeballCounts).length; pb++) // For every Pokeball, add them to the text content.
for (let pb = 0; pb < Object.keys(this.scene.pokeballCounts).length; pb++) {
optionsTextContent += `${getPokeballName(pb)}\n`; optionsTextContent += `${getPokeballName(pb)}\n`;
optionsTextContent += 'Cancel'; }
const optionsText = addTextObject(this.scene, 0, 0, optionsTextContent, TextStyle.WINDOW, { align: 'right', maxLines: 6 }); optionsTextContent += 'Cancel'; // Warning, "Cancel", is used in a RegExp.
optionsText.setOrigin(0, 0);
optionsText.setPositionRelative(this.pokeballSelectBg, 42, 9); this.optionsText = addTextObject(this.scene, 0, 0, optionsTextContent, TextStyle.WINDOW, { align: 'right', maxLines: 6 });
optionsText.setLineSpacing(12); this.optionsText.setOrigin(0, 0);
this.pokeballSelectContainer.add(optionsText); this.optionsText.setPositionRelative(this.pokeballSelectBg, 42, 9);
this.optionsText.setLineSpacing(12);
this.pokeballSelectContainer.add(this.optionsText);
this.countsText = addTextObject(this.scene, 0, 0, '', TextStyle.WINDOW, { maxLines: 5 }); this.countsText = addTextObject(this.scene, 0, 0, '', TextStyle.WINDOW, { maxLines: 5 });
this.countsText.setPositionRelative(this.pokeballSelectBg, 18, 9); this.countsText.setPositionRelative(this.pokeballSelectBg, 18, 9);
@ -49,9 +56,33 @@ export default class BallUiHandler extends UiHandler {
this.setCursor(0); this.setCursor(0);
} }
updatePositions(): void {
this.optionsText.setPositionRelative(this.pokeballSelectBg, 42, 9);
this.countsText.setPositionRelative(this.pokeballSelectBg, 18, 9);
}
addIvScanner(): void {
if (this.ivScannerAdded)
return;
this.ivScannerAdded = true;
this.optionsText.setText(
this.optionsText.text.replace(new RegExp("Cancel", "g"), "IV-Scanner\nCancel")
);
this.optionsText.setMaxLines(7);
this.pokeballSelectBg.height = 112 + 12;
this.updatePositions();
}
show(args: any[]): boolean { show(args: any[]): boolean {
super.show(args); super.show(args);
const ivScannerModifier = this.scene.findModifier(m => m instanceof IvScannerModifier) as IvScannerModifier;
if (ivScannerModifier) {
this.addIvScanner();
}
this.updateCounts(); this.updateCounts();
this.pokeballSelectContainer.setVisible(true); this.pokeballSelectContainer.setVisible(true);
this.setCursor(this.cursor); this.setCursor(this.cursor);
@ -65,6 +96,7 @@ export default class BallUiHandler extends UiHandler {
let success = false; let success = false;
const pokeballTypeCount = Object.keys(this.scene.pokeballCounts).length; const pokeballTypeCount = Object.keys(this.scene.pokeballCounts).length;
let maxLines = this.optionsText.style.maxLines;
if (button === Button.ACTION || button === Button.CANCEL) { if (button === Button.ACTION || button === Button.CANCEL) {
const commandPhase = this.scene.getCurrentPhase() as CommandPhase; const commandPhase = this.scene.getCurrentPhase() as CommandPhase;
@ -78,6 +110,15 @@ export default class BallUiHandler extends UiHandler {
} }
} else } else
ui.playError(); ui.playError();
} else if (button === Button.ACTION && this.cursor < (pokeballTypeCount+1) && this.ivScannerAdded) {
this.scene.ui.revertMode();
ui.setMode(Mode.COMMAND, commandPhase.getFieldIndex());
const ivScannerModifier = this.scene.findModifier(m => m instanceof IvScannerModifier) as IvScannerModifier;
ivScannerModifier.openIvScannerMenu(this.scene);
success = true;
} else { } else {
ui.setMode(Mode.COMMAND, commandPhase.getFieldIndex()); ui.setMode(Mode.COMMAND, commandPhase.getFieldIndex());
success = true; success = true;
@ -85,10 +126,10 @@ export default class BallUiHandler extends UiHandler {
} else { } else {
switch (button) { switch (button) {
case Button.UP: case Button.UP:
success = this.setCursor(this.cursor ? this.cursor - 1 : pokeballTypeCount); success = this.setCursor(this.cursor ? this.cursor - 1 : (maxLines-1));
break; break;
case Button.DOWN: case Button.DOWN:
success = this.setCursor(this.cursor < pokeballTypeCount ? this.cursor + 1 : 0); success = this.setCursor(this.cursor < (maxLines-1) ? this.cursor + 1 : 0);
break; break;
} }
} }