Keeps shiny variant, gender and form when switching to evolutions; show ability descriptions; properly displaying sprites for megas and other forms

This commit is contained in:
Wlowscha 2025-01-04 01:14:12 +01:00
parent 955af4b00d
commit 657fdf07ed
No known key found for this signature in database
GPG Key ID: 3C8F1AD330565D04
4 changed files with 337 additions and 397 deletions

View File

@ -116,6 +116,10 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
).join("\n"),
TextStyle.WINDOW, { maxLines: options.length, lineSpacing: 12 }
);
console.log(options.map(o => o.item
? `[color=${o.color || "white"}] ${o.label}[/color]`
: `[color=${o.color || "white"}]${o.label}[/color]`
).join("\n"));
this.optionSelectText.setOrigin(0, 0);
this.optionSelectText.setName("text-option-select");
this.optionSelectContainer.add(this.optionSelectText);
@ -195,6 +199,8 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
let playSound = true;
console.log(button);
if (button === Button.ACTION || button === Button.CANCEL) {
if (this.blockInput) {
ui.playError();
@ -203,29 +209,36 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
success = true;
if (button === Button.CANCEL) {
console.log("Pressed CANCEL");
if (this.config?.maxOptions && this.config.options.length > this.config.maxOptions) {
this.scrollCursor = (this.config.options.length - this.config.maxOptions) + 1;
this.cursor = options.length - 1;
this.cursor = unskippedIndices.length - 1;
console.log("A", this.scrollCursor, this.cursor);
} else if (!this.config?.noCancel) {
this.setCursor(options.length - 1);
this.setCursor(unskippedIndices.length - 1);
console.log("B", this.scrollCursor, this.cursor);
} else {
console.log("C", this.scrollCursor, this.cursor);
return false;
}
}
const option = this.config?.options[unskippedIndices[this.cursor + (this.scrollCursor - (this.scrollCursor ? 1 : 0))]];
const option = this.config?.options[unskippedIndices[this.cursor] + (this.scrollCursor - (this.scrollCursor ? 1 : 0))];
console.log("CD", option);
if (option?.handler()) {
if (!option.keepOpen) {
console.log("D", this.scrollCursor, this.cursor);
this.clear();
}
playSound = !option.overrideSound;
} else {
console.log("E", this.scrollCursor, this.cursor);
ui.playError();
}
} else if (button === Button.SUBMIT && ui.getMode() === Mode.AUTO_COMPLETE) {
// this is here to differentiate between a Button.SUBMIT vs Button.ACTION within the autocomplete handler
// this is here because Button.ACTION is picked up as z on the keyboard, meaning if you're typing and hit z, it'll select the option you've chosen
success = true;
const option = this.config?.options[this.cursor + (this.scrollCursor - (this.scrollCursor ? 1 : 0))];
const option = this.config?.options[unskippedIndices[this.cursor] + (this.scrollCursor - (this.scrollCursor ? 1 : 0))];
if (option?.handler()) {
if (!option.keepOpen) {
this.clear();
@ -253,7 +266,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
}
if (this.config?.supportHover) {
// handle hover code if the element supports hover-handlers and the option has the optional hover-handler set.
this.config?.options[this.cursor + (this.scrollCursor - (this.scrollCursor ? 1 : 0))]?.onHover?.();
this.config?.options[unskippedIndices[this.cursor] + (this.scrollCursor - (this.scrollCursor ? 1 : 0))]?.onHover?.();
}
}
@ -332,9 +345,9 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
// Move the cursor up or down by 1
const isDown = cursor && cursor > this.cursor;
if (isDown) {
if (options[cursor].label === scrollDownLabel) {
if (options[Math.min(unskippedIndices[cursor], options.length)].label === scrollDownLabel) {
isScroll = true;
this.scrollCursor++;
this.scrollCursor += unskippedIndices[cursor] - unskippedIndices[this.cursor];
}
} else {
if (!cursor && this.scrollCursor) {

View File

@ -0,0 +1,158 @@
import BattleScene, { InfoToggle } from "../battle-scene";
import { TextStyle, addTextObject } from "./text";
import { addWindow } from "./ui-theme";
import * as Utils from "../utils";
import i18next from "i18next";
export interface PokedexInfoOverlaySettings {
delayVisibility?: boolean; // if true, showing the overlay will only set it to active and populate the fields and the handler using this field has to manually call setVisible later.
scale?:number; // scale the box? A scale of 0.5 is recommended
top?: boolean; // should the effect box be on top?
right?: boolean; // should the effect box be on the right?
onSide?: boolean; // should the effect be on the side? ignores top argument if true
//location and width of the component; unaffected by scaling
x?: number;
y?: number;
/** Default is always half the screen, regardless of scale */
width?: number;
/** Determines whether to display the small secondary box */
hideEffectBox?: boolean;
hideBg?: boolean;
}
const EFF_HEIGHT = 36;
const EFF_WIDTH = 82;
const DESC_HEIGHT = 36;
const BORDER = 8;
const GLOBAL_SCALE = 6;
export default class PokedexInfoOverlay extends Phaser.GameObjects.Container implements InfoToggle {
public active: boolean = false;
private desc: Phaser.GameObjects.Text;
private descScroll : Phaser.Tweens.Tween | null = null;
private descBg: Phaser.GameObjects.NineSlice;
private options : PokedexInfoOverlaySettings;
constructor(scene: BattleScene, options?: PokedexInfoOverlaySettings) {
if (options?.onSide) {
options.top = false;
}
super(scene, options?.x, options?.y);
const scale = options?.scale || 1; // set up the scale
this.setScale(scale);
this.options = options || {};
// prepare the description box
const width = (options?.width || PokedexInfoOverlay.getWidth(scale, scene)) / scale; // divide by scale as we always want this to be half a window wide
this.descBg = addWindow(scene, (options?.onSide && !options?.right ? EFF_WIDTH : 0), options?.top ? EFF_HEIGHT : 0, width - (options?.onSide ? EFF_WIDTH : 0), DESC_HEIGHT);
this.descBg.setOrigin(0, 0);
this.add(this.descBg);
// set up the description; wordWrap uses true pixels, unaffected by any scaling, while other values are affected
this.desc = addTextObject(scene, (options?.onSide && !options?.right ? EFF_WIDTH : 0) + BORDER, (options?.top ? EFF_HEIGHT : 0) + BORDER - 2, "", TextStyle.BATTLE_INFO, { wordWrap: { width: (width - (BORDER - 2) * 2 - (options?.onSide ? EFF_WIDTH : 0)) * GLOBAL_SCALE }});
this.desc.setLineSpacing(i18next.resolvedLanguage === "ja" ? 25 : 5);
// limit the text rendering, required for scrolling later on
const maskPointOrigin = {
x: (options?.x || 0),
y: (options?.y || 0),
};
if (maskPointOrigin.x < 0) {
maskPointOrigin.x += this.scene.game.canvas.width / GLOBAL_SCALE;
}
if (maskPointOrigin.y < 0) {
maskPointOrigin.y += this.scene.game.canvas.height / GLOBAL_SCALE;
}
const moveDescriptionTextMaskRect = this.scene.make.graphics();
moveDescriptionTextMaskRect.fillStyle(0xFF0000);
moveDescriptionTextMaskRect.fillRect(
maskPointOrigin.x + ((options?.onSide && !options?.right ? EFF_WIDTH : 0) + BORDER) * scale, maskPointOrigin.y + ((options?.top ? EFF_HEIGHT : 0) + BORDER - 2) * scale,
width - ((options?.onSide ? EFF_WIDTH : 0) - BORDER * 2) * scale, (DESC_HEIGHT - (BORDER - 2) * 2) * scale);
moveDescriptionTextMaskRect.setScale(6);
const moveDescriptionTextMask = this.createGeometryMask(moveDescriptionTextMaskRect);
this.add(this.desc);
this.desc.setMask(moveDescriptionTextMask);
if (options?.hideBg) {
this.descBg.setVisible(false);
}
// hide this component for now
this.setVisible(false);
}
// show this component with infos for the specific move
show(text: string):boolean {
if (!(this.scene as BattleScene).enableMoveInfo) {
return false; // move infos have been disabled // TODO:: is `false` correct? i used to be `undeefined`
}
this.desc.setText(text ?? "");
// stop previous scrolling effects and reset y position
if (this.descScroll) {
this.descScroll.remove();
this.descScroll = null;
this.desc.y = (this.options?.top ? EFF_HEIGHT : 0) + BORDER - 2;
}
// determine if we need to add new scrolling effects
const moveDescriptionLineCount = Math.floor(this.desc.displayHeight * (96 / 72) / 14.83);
if (moveDescriptionLineCount > 3) {
// generate scrolling effects
this.descScroll = this.scene.tweens.add({
targets: this.desc,
delay: Utils.fixedInt(2000),
loop: -1,
hold: Utils.fixedInt(2000),
duration: Utils.fixedInt((moveDescriptionLineCount - 3) * 2000),
y: `-=${14.83 * (72 / 96) * (moveDescriptionLineCount - 3)}`
});
}
if (!this.options.delayVisibility) {
this.setVisible(true);
}
this.active = true;
return true;
}
clear() {
this.setVisible(false);
this.active = false;
}
toggleInfo(visible: boolean): void {
if (visible) {
this.setVisible(true);
}
this.scene.tweens.add({
targets: this.desc,
duration: Utils.fixedInt(125),
ease: "Sine.easeInOut",
alpha: visible ? 1 : 0
});
if (!visible) {
this.setVisible(false);
}
}
isActive(): boolean {
return this.active;
}
// width of this element
static getWidth(scale:number, scene: BattleScene):number {
return scene.game.canvas.width / GLOBAL_SCALE / 2;
}
// height of this element
static getHeight(scale:number, onSide?: boolean):number {
return (onSide ? Math.max(EFF_HEIGHT, DESC_HEIGHT) : (EFF_HEIGHT + DESC_HEIGHT)) * scale;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ import { speciesEggMoves } from "#app/data/balance/egg-moves";
import { pokemonFormLevelMoves, pokemonSpeciesLevelMoves } from "#app/data/balance/pokemon-level-moves";
import PokemonSpecies, { allSpecies, getPokemonSpeciesForm, getPokerusStarters, PokemonForm } from "#app/data/pokemon-species";
import { getStarterValueFriendshipCap, speciesStarterCosts, POKERUS_STARTER_COUNT } from "#app/data/balance/starters";
import { catchableSpecies } from "#app/data/balance/biomes";
import { catchableSpecies, uncatchableSpecies } from "#app/data/balance/biomes";
import { Type } from "#enums/type";
import { AbilityAttr, DexAttr, DexAttrProps, DexEntry, StarterMoveset, StarterAttributes, StarterPreferences, StarterPrefs } from "#app/system/game-data";
import { Tutorial, handleTutorial } from "#app/tutorial";
@ -547,8 +547,7 @@ export default class PokedexUiHandler extends MessageUiHandler {
this.speciesLoaded.set(species.speciesId, false);
this.allSpecies.push(species);
const starter = !speciesStarterCosts.hasOwnProperty(species.speciesId) ? allSpecies.find(sp => sp.speciesId === pokemonStarters[species.speciesId]) : null ;
const starterContainer = new StarterContainer(this.scene, species, starter).setVisible(false);
const starterContainer = new StarterContainer(this.scene, species).setVisible(false);
this.iconAnimHandler.addOrUpdate(starterContainer.icon, PokemonIconAnimMode.NONE);
this.starterContainers.push(starterContainer);
starterBoxContainer.add(starterContainer);
@ -1381,7 +1380,10 @@ export default class PokedexUiHandler extends MessageUiHandler {
// TODO: We might also need to do it the other way around.
// const biomes = catchableSpecies[container.species.speciesId].concat(catchableSpecies[this.getStarterSpeciesId(container.species.speciesId)]).map(b => Biome[b.biome]);
const biomes = catchableSpecies[container.species.speciesId].map(b => Biome[b.biome]);
const fitsBiome = this.filterBar.getVals(DropDownColumn.BIOME).some(item => biomes.includes(indexToBiome.get(item)));
// Only show uncatchable mons if all biomes are selected.
// TODO: Have an entry for uncatchable mons.
const showUncatchable = (uncatchableSpecies.includes(container.species.speciesId) && this.filterBar.getVals(DropDownColumn.BIOME).length === 35) ? true : false;
const fitsBiome = this.filterBar.getVals(DropDownColumn.BIOME).some(item => biomes.includes(indexToBiome.get(item))) || showUncatchable;
// Caught / Shiny filter