Compare commits

...

9 Commits

Author SHA1 Message Date
AJ Fontaine
daa9e1ef0f
[BUG] Fix fullheal, burn/poison, and endure tokens in existing saves not updating after rebalance (#1848)
* Fix tokens not actually updating

* Remove changes to getArgs

* Added parentheses around conditional for safety

* Laid a space betwixt the two and its respective one at the behest of Temp
2024-06-05 23:07:47 -04:00
José Ricardo Fleury Oliveira
c1b4be83d0
translations (#1850) 2024-06-05 21:52:59 -05:00
returntoice
6b31db0bc5
[Localization] Paldean gym leaders and elite 4 dialogue Korean translation (#1838)
* Your commit message

* localization
2024-06-05 21:54:08 -04:00
sodam
19114e4fd3
[Localization] #1761 Korean trainer dialogue (Gym leader in Hoenn region) (#1830)
* localized to korean (Gym leader's dialouge in Houenn region)

* modified the spacing

Co-authored-by: returntoice <dieandbecome@gmail.com>

* modified the spacing

Co-authored-by: returntoice <dieandbecome@gmail.com>

* modified the spelling

Co-authored-by: returntoice <dieandbecome@gmail.com>

---------

Co-authored-by: returntoice <dieandbecome@gmail.com>
2024-06-05 21:52:30 -04:00
prime
1c98106642
[QoL] Move Info Overlay (#1585)
* move info implemented for starter selection

a move info box is displayed when editing the starter moveset.

also menus have now onHover triggers.

todo:
- show ui when selecting TMs
- show ui when selecting moves to remember (memory mushroom)

* More Move Info Overlays

Added overlays during Memory Mushroom use and when viewing TMs.
Furthermore a settings option can enable/disable those overlays.

* Added missing ko language entry

... though translation still remains necessary

* updated ui

also added overrides for item rewards

* minor ui update

moved values to the right in the tm move info box

* fixed typedoc issues

* removed settings in to prepare for merge

* updated settings option

added settings option to new settings implementation

* minor changes

removed unused graphic
moved settings option to accessibility
2024-06-05 20:28:12 -05:00
Matthew
c5689dfc96
dont make api calls when no server is connected in local (#1847)
* dont make api calls in local without a server connected and fix fusionLuck not set by default
2024-06-05 21:24:47 -04:00
Tempoanon
6d35399c31
[Bug] Change confuse chance from 2/3 to 1/3 (#1827) 2024-06-05 20:05:44 -05:00
flx-sta
283714bd0f
[Refactor] Move enums from game-data into their respective files in src/data/enums (#1837)
* move PlayerGender enum into src/data/enums/player-gender.ts

this is necessary to avoid circular dependencies which did crash tests in the past (in PRs)

* Update settings.ts

* Update game-data.ts

* Update summary-ui-handler.ts

* Update ui.ts

* move Passive & GameDataType enums into own files
2024-06-05 19:11:07 -05:00
Blitzy
46dc7e9b01
[Balance] Give Partner Pikachu its Signature Moves and change Cosplay's stats (#1737)
* Update Cosplay Pikachu stats

* Give Partner Pikachu its signature moves in its learnset

* Added a "custom" note next to stats

* Spread out signatures per Brain Frog's request
2024-06-05 16:56:31 -05:00
37 changed files with 637 additions and 214 deletions

View File

@ -11,7 +11,8 @@ import { Phase } from "./phase";
import { initGameSpeed } from "./system/game-speed";
import { Biome } from "./data/enums/biome";
import { Arena, ArenaBase } from "./field/arena";
import { GameData, PlayerGender } from "./system/game-data";
import { GameData } from "./system/game-data";
import { PlayerGender } from "./data/enums/player-gender";
import { TextStyle, addTextObject } from "./ui/text";
import { Moves } from "./data/enums/moves";
import { allMoves } from "./data/move";
@ -70,15 +71,20 @@ const expSpriteKeys: string[] = [];
export let starterColors: StarterColors;
interface StarterColors {
[key: string]: [string, string]
[key: string]: [string, string]
}
export interface PokeballCounts {
[pb: string]: integer;
[pb: string]: integer;
}
export type AnySound = Phaser.Sound.WebAudioSound | Phaser.Sound.HTML5AudioSound | Phaser.Sound.NoAudioSound;
export interface InfoToggle {
toggleInfo(force?: boolean): void;
isActive(): boolean;
}
export default class BattleScene extends SceneBase {
public rexUI: UIPlugin;
public inputController: InputsController;
@ -96,6 +102,7 @@ export default class BattleScene extends SceneBase {
public showArenaFlyout: boolean = true;
public showLevelUpStats: boolean = true;
public enableTutorials: boolean = import.meta.env.VITE_BYPASS_TUTORIAL === "1";
public enableMoveInfo: boolean = true;
public enableRetries: boolean = false;
/**
* Determines the condition for a notification should be shown for Candy Upgrades
@ -119,17 +126,17 @@ export default class BattleScene extends SceneBase {
public skipSeenDialogues: boolean = false;
/**
* Defines the experience gain display mode.
*
* @remarks
* The `expParty` can have several modes:
* - `0` - Default: The normal experience gain display, nothing changed.
* - `1` - Level Up Notification: Displays the level up in the small frame instead of a message.
* - `2` - Skip: No level up frame nor message.
*
* Modes `1` and `2` are still compatible with stats display, level up, new move, etc.
* @default 0 - Uses the default normal experience gain display.
*/
* Defines the experience gain display mode.
*
* @remarks
* The `expParty` can have several modes:
* - `0` - Default: The normal experience gain display, nothing changed.
* - `1` - Level Up Notification: Displays the level up in the small frame instead of a message.
* - `2` - Skip: No level up frame nor message.
*
* Modes `1` and `2` are still compatible with stats display, level up, new move, etc.
* @default 0 - Uses the default normal experience gain display.
*/
public expParty: integer = 0;
public hpBarSpeed: integer = 0;
public fusionPaletteSwaps: boolean = true;
@ -208,6 +215,8 @@ export default class BattleScene extends SceneBase {
public rngSeedOverride: string = "";
public rngOffset: integer = 0;
private infoToggles: InfoToggle[] = [];
/**
* Allows subscribers to listen for events
*
@ -514,7 +523,7 @@ export default class BattleScene extends SceneBase {
this.playTimeTimer = this.time.addEvent({
delay: Utils.fixedInt(1000),
repeat: -1,
callback: () => {
callback: () => {
if (this.gameData) {
this.gameData.gameStats.playTime++;
}
@ -598,25 +607,25 @@ export default class BattleScene extends SceneBase {
/*const loadPokemonAssets: Promise<void>[] = [];
for (let s of Object.keys(speciesStarters)) {
const species = getPokemonSpecies(parseInt(s));
loadPokemonAssets.push(species.loadAssets(this, false, 0, false));
}
for (let s of Object.keys(speciesStarters)) {
const species = getPokemonSpecies(parseInt(s));
loadPokemonAssets.push(species.loadAssets(this, false, 0, false));
}
Promise.all(loadPokemonAssets).then(() => {
const starterCandyColors = {};
const rgbaToHexFunc = (r, g, b) => [r, g, b].map(x => x.toString(16).padStart(2, '0')).join('');
Promise.all(loadPokemonAssets).then(() => {
const starterCandyColors = {};
const rgbaToHexFunc = (r, g, b) => [r, g, b].map(x => x.toString(16).padStart(2, '0')).join('');
for (let s of Object.keys(speciesStarters)) {
const species = getPokemonSpecies(parseInt(s));
for (let s of Object.keys(speciesStarters)) {
const species = getPokemonSpecies(parseInt(s));
starterCandyColors[species.speciesId] = species.generateCandyColors(this).map(c => rgbaToHexFunc(c[0], c[1], c[2]));
}
starterCandyColors[species.speciesId] = species.generateCandyColors(this).map(c => rgbaToHexFunc(c[0], c[1], c[2]));
}
console.log(JSON.stringify(starterCandyColors));
console.log(JSON.stringify(starterCandyColors));
resolve();
});*/
resolve();
});*/
resolve();
});
@ -681,6 +690,16 @@ export default class BattleScene extends SceneBase {
: ret;
}
// store info toggles to be accessible by the ui
addInfoToggle(infoToggle: InfoToggle): void {
this.infoToggles.push(infoToggle);
}
// return the stored info toggles; used by ui-inputs
getInfoToggles(activeOnly: boolean = false): InfoToggle[] {
return activeOnly ? this.infoToggles.filter(t => t?.isActive()) : this.infoToggles;
}
getPokemonById(pokemonId: integer): Pokemon {
const findInParty = (party: Pokemon[]) => party.find(p => p.id === pokemonId);
return findInParty(this.getParty()) || findInParty(this.getEnemyParty());
@ -727,7 +746,7 @@ export default class BattleScene extends SceneBase {
const container = this.add.container(x, y);
const icon = this.add.sprite(0, 0, pokemon.getIconAtlasKey(ignoreOverride));
icon.setFrame(pokemon.getIconId(true));
icon.setFrame(pokemon.getIconId(true));
// Temporary fix to show pokemon's default icon if variant icon doesn't exist
if (icon.frame.name !== pokemon.getIconId(true)) {
console.log(`${pokemon.name}'s variant icon does not exist. Replacing with default.`);
@ -1335,7 +1354,7 @@ export default class BattleScene extends SceneBase {
return;
}
const formattedMoney =
this.moneyFormat === MoneyFormat.ABBREVIATED ? Utils.formatFancyLargeNumber(this.money, 3) : this.money.toLocaleString();
this.moneyFormat === MoneyFormat.ABBREVIATED ? Utils.formatFancyLargeNumber(this.money, 3) : this.money.toLocaleString();
this.moneyText.setText(`${formattedMoney}`);
this.fieldUI.moveAbove(this.moneyText, this.luckText);
if (forceVisible) {
@ -1925,7 +1944,7 @@ export default class BattleScene extends SceneBase {
const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier;
newItemModifier.pokemonId = target.id;
const matchingModifier = target.scene.findModifier(m => m instanceof PokemonHeldItemModifier
&& (m as PokemonHeldItemModifier).matchType(itemModifier) && m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier;
&& (m as PokemonHeldItemModifier).matchType(itemModifier) && m.pokemonId === target.id, target.isPlayer()) as PokemonHeldItemModifier;
let removeOld = true;
if (matchingModifier) {
const maxStackCount = matchingModifier.getMaxStackCount(target.scene);
@ -2029,8 +2048,8 @@ export default class BattleScene extends SceneBase {
}
/**
* Removes all modifiers from enemy of PersistentModifier type
*/
* Removes all modifiers from enemy of PersistentModifier type
*/
clearEnemyModifiers(): void {
const modifiersToRemove = this.enemyModifiers.filter(m => m instanceof PersistentModifier);
for (const m of modifiersToRemove) {
@ -2040,8 +2059,8 @@ export default class BattleScene extends SceneBase {
}
/**
* Removes all modifiers from enemy of PokemonHeldItemModifier type
*/
* Removes all modifiers from enemy of PokemonHeldItemModifier type
*/
clearEnemyHeldItemModifiers(): void {
const modifiersToRemove = this.enemyModifiers.filter(m => m instanceof PokemonHeldItemModifier);
for (const m of modifiersToRemove) {

View File

@ -8,7 +8,7 @@ import { Moves } from "./data/enums/moves";
import { TrainerType } from "./data/enums/trainer-type";
import { GameMode } from "./game-mode";
import { BattleSpec } from "./enums/battle-spec";
import { PlayerGender } from "./system/game-data";
import { PlayerGender } from "./data/enums/player-gender";
import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier";
import { PokeballType } from "./data/pokeball";
import {trainerConfigs} from "#app/data/trainer-config";

View File

@ -200,6 +200,9 @@ export class InterruptedTag extends BattlerTag {
}
}
/**
* BattlerTag that represents the {@link https://bulbapedia.bulbagarden.net/wiki/Confusion_(status_condition)}
*/
export class ConfusedTag extends BattlerTag {
constructor(turnCount: integer, sourceMove: Moves) {
super(BattlerTagType.CONFUSED, BattlerTagLapseType.MOVE, turnCount, sourceMove);
@ -235,7 +238,8 @@ export class ConfusedTag extends BattlerTag {
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is\nconfused!"));
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION));
if (pokemon.randSeedInt(3)) {
// 1/3 chance of hitting self with a 40 base power move
if (pokemon.randSeedInt(3) === 0) {
const atk = pokemon.getBattleStat(Stat.ATK);
const def = pokemon.getBattleStat(Stat.DEF);
const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100));

View File

@ -0,0 +1,10 @@
/**
* enum for the game data types
*/
export enum GameDataType {
SYSTEM,
SESSION,
SETTINGS,
TUTORIALS,
SEEN_DIALOGUES
}

View File

@ -0,0 +1,7 @@
/**
* enum for passive
*/
export enum Passive {
UNLOCKED = 1,
ENABLED = 2
}

View File

@ -0,0 +1,8 @@
/**
* enum for the players gender
*/
export enum PlayerGender {
UNSET,
MALE,
FEMALE
}

View File

@ -18539,12 +18539,14 @@ export const pokemonFormLevelMoves: PokemonSpeciesFormLevelMoves = {
[ 8, Moves.DOUBLE_TEAM ],
[ 12, Moves.ELECTRO_BALL ],
[ 16, Moves.FEINT ],
[ 20, Moves.SPARK ],
[ 20, Moves.ZIPPY_ZAP ], //Custom
[ 24, Moves.AGILITY ],
[ 28, Moves.IRON_TAIL ],
[ 32, Moves.DISCHARGE ],
[ 34, Moves.FLOATY_FALL ], //Custom
[ 36, Moves.THUNDERBOLT ],
[ 40, Moves.LIGHT_SCREEN ],
[ 42, Moves.SPLISHY_SPLASH ], //Custom
[ 44, Moves.THUNDER ],
[ 48, Moves.PIKA_PAPOW ],
],

View File

@ -918,12 +918,12 @@ export function initSpecies() {
new PokemonSpecies(Species.PIKACHU, 1, false, false, false, "Mouse Pokémon", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 320, 35, 55, 40, 50, 50, 90, 190, 50, 112, GrowthRate.MEDIUM_FAST, 50, true, true,
new PokemonForm("Normal", "", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 320, 35, 55, 40, 50, 50, 90, 190, 50, 112, true, null, true),
new PokemonForm("Partner", "partner", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 430, 45, 80, 50, 75, 60, 120, 190, 50, 112, true, "", true),
new PokemonForm("Cosplay", "cosplay", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 320, 35, 55, 40, 50, 50, 90, 190, 50, 112, true, null, true),
new PokemonForm("Cool Cosplay", "cool-cosplay", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 320, 35, 55, 40, 50, 50, 90, 190, 50, 112, true, null, true),
new PokemonForm("Beauty Cosplay", "beauty-cosplay", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 320, 35, 55, 40, 50, 50, 90, 190, 50, 112, true, null, true),
new PokemonForm("Cute Cosplay", "cute-cosplay", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 320, 35, 55, 40, 50, 50, 90, 190, 50, 112, true, null, true),
new PokemonForm("Smart Cosplay", "smart-cosplay", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 320, 35, 55, 40, 50, 50, 90, 190, 50, 112, true, null, true),
new PokemonForm("Tough Cosplay", "tough-cosplay", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 320, 35, 55, 40, 50, 50, 90, 190, 50, 112, true, null, true),
new PokemonForm("Cosplay", "cosplay", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 430, 45, 80, 50, 75, 60, 120, 190, 50, 112, true, null, true), //Custom
new PokemonForm("Cool Cosplay", "cool-cosplay", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 430, 45, 80, 50, 75, 60, 120, 190, 50, 112, true, null, true), //Custom
new PokemonForm("Beauty Cosplay", "beauty-cosplay", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 430, 45, 80, 50, 75, 60, 120, 190, 50, 112, true, null, true), //Custom
new PokemonForm("Cute Cosplay", "cute-cosplay", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 430, 45, 80, 50, 75, 60, 120, 190, 50, 112, true, null, true), //Custom
new PokemonForm("Smart Cosplay", "smart-cosplay", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 430, 45, 80, 50, 75, 60, 120, 190, 50, 112, true, null, true), //Custom
new PokemonForm("Tough Cosplay", "tough-cosplay", Type.ELECTRIC, null, 0.4, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 430, 45, 80, 50, 75, 60, 120, 190, 50, 112, true, null, true), //Custom
new PokemonForm("G-Max", SpeciesFormKey.GIGANTAMAX, Type.ELECTRIC, null, 21, 6, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 420, 45, 60, 65, 100, 75, 75, 190, 50, 112),
),
new PokemonSpecies(Species.RAICHU, 1, false, false, false, "Mouse Pokémon", Type.ELECTRIC, null, 0.8, 30, Abilities.STATIC, Abilities.NONE, Abilities.LIGHTNING_ROD, 485, 60, 90, 55, 90, 80, 110, 75, 50, 243, GrowthRate.MEDIUM_FAST, 50, true),

View File

@ -211,8 +211,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.generateFusionSpecies();
}
}
this.luck = (this.shiny ? this.variant + 1 : 0) + (this.fusionShiny ? this.fusionVariant + 1 : 0);
this.fusionLuck = this.luck;
}
this.generateName();

View File

@ -29,6 +29,7 @@ export class LoadingScene extends SceneBase {
}
preload() {
Utils.localPing();
this.load["manifest"] = this.game["manifest"];
if (!isMobile()) {
@ -126,6 +127,7 @@ export class LoadingScene extends SceneBase {
this.loadImage("summary_stats_overlay_exp", "ui");
this.loadImage("summary_moves", "ui");
this.loadImage("summary_moves_effect", "ui");
this.loadImage("summary_moves_effect_type", "ui");
this.loadImage("summary_moves_overlay_row", "ui");
this.loadImage("summary_moves_overlay_pp", "ui");
this.loadAtlas("summary_moves_cursor", "ui");

View File

@ -99,6 +99,10 @@ export const modifierType: ModifierTypeTranslationEntries = {
name: "TM{{moveId}} - {{moveName}}",
description: "Bringt einem Pokémon {{moveName}} bei",
},
"TmModifierTypeWithInfo": {
name: "TM{{moveId}} - {{moveName}}",
description: "Bringt einem Pokémon {{moveName}} bei\n(Halte C oder Shift für mehr Infos)",
},
"EvolutionItemModifierType": {
description: "Erlaubt es bestimmten Pokémon sich zu entwickeln",
},

View File

@ -99,6 +99,10 @@ export const modifierType: ModifierTypeTranslationEntries = {
name: "TM{{moveId}} - {{moveName}}",
description: "Teach {{moveName}} to a Pokémon",
},
"TmModifierTypeWithInfo": {
name: "TM{{moveId}} - {{moveName}}",
description: "Teach {{moveName}} to a Pokémon\n(Hold C or Shift for more info)",
},
"EvolutionItemModifierType": {
description: "Causes certain Pokémon to evolve",
},

View File

@ -99,6 +99,10 @@ export const modifierType: ModifierTypeTranslationEntries = {
name: "MT{{moveId}} - {{moveName}}",
description: "Enseña {{moveName}} a un Pokémon",
},
"TmModifierTypeWithInfo": {
name: "MT{{moveId}} - {{moveName}}",
description: "Enseña {{moveName}} a un Pokémon\n(Hold C or Shift for more info)",
},
"EvolutionItemModifierType": {
description: "Hace que ciertos Pokémon evolucionen",
},

View File

@ -99,6 +99,10 @@ export const modifierType: ModifierTypeTranslationEntries = {
name: "CT{{moveId}} - {{moveName}}",
description: "Apprend la capacité {{moveName}} à un Pokémon",
},
"TmModifierTypeWithInfo": {
name: "CT{{moveId}} - {{moveName}}",
description: "Apprend la capacité {{moveName}} à un Pokémon\n(Hold C or Shift for more info)",
},
"EvolutionItemModifierType": {
description: "Permet à certains Pokémon dévoluer",
},

View File

@ -99,6 +99,10 @@ export const modifierType: ModifierTypeTranslationEntries = {
name: "MT{{moveId}} - {{moveName}}",
description: "Insegna {{moveName}} a un Pokémon",
},
"TmModifierTypeWithInfo": {
name: "MT{{moveId}} - {{moveName}}",
description: "Insegna {{moveName}} a un Pokémon\n(Hold C or Shift for more info)",
},
"EvolutionItemModifierType": {
description: "Fa evolvere determinate specie di Pokémon",
},

View File

@ -512,158 +512,158 @@ export const PGMdialogue: DialogueTranslationEntries = {
},
"roxanne": {
"encounter": {
1: "Would you kindly demonstrate how you battle?",
2: "You can learn many things by battling many trainers.",
3: "Oh, you caught me strategizing.\nWould you like to battle?"
1: "당신이 어떻게 싸우는지 보여주시겠어요?",
2: "당신은 여러 트레이너와 싸우면서 많은 것을 배울 수 있을거예요.",
3: "아, 전략짜는 거 들켰네요.\n배틀할까요?"
},
"victory": {
1: "Oh, I appear to have lost.\nI understand.",
2: "It seems that I still have so much more to learn when it comes to battle.",
3: "I'll take what I learned here today to heart."
1: "아, 제가 진 것 같네요.\n승복하겠습니다.",
2: "전 아직도 포켓몬 배틀에 대해서 한참 더 배워야할 것 같네요.",
3: "오늘 여기서 배운 것들을 마음에 담아둬야겠어요."
},
"defeat": {
1: "I have learned many things from our battle.\nI hope you have too.",
2: "I look forward to battling you again.\nI hope you'll use what you've learned here.",
3: "I won due to everything I have learned."
1: "전 방금 승부에서 많은 것을 배웠습니다.\n당신도 그랬길 바래요.",
2: "다시 붙을 날이 기대되네요.\n당신이 여기서 배운 걸 활용할 수 있길 바랍니다.",
3: "여태까지 공부해온 것 덕분에 이겼네요."
}
},
"brawly": {
"encounter": {
1: "Oh man, a challenger!\nLet's see what you can do!",
2: "You seem like a big splash.\nLet's battle!",
3: "Time to create a storm!\nLet's go!"
1: "오, 도전자잖아!\n어디 한 번 볼까!",
2: "넌 큰 파란을 일으킬 것 같군.\n승부다!",
3: "폭풍을 일으킬 시간이야!\n가자!"
},
"victory": {
1: "Oh woah, you've washed me out!",
2: "You surfed my wave and crashed me down!",
3: "I feel like I'm lost in Granite Cave!"
1: "우와, 너 날 씻겨버렸네!",
2: "내 파도를 타고, 나까지 밀어내다니!",
3: "바위 동굴에서 길을 잃은 기분이야!"
},
"defeat": {
1: "Haha, I surfed the big wave!\nChallenge me again sometime.",
2: "Surf with me again some time!",
3: "Just like the tides come in and out, I hope you return to challenge me again."
1: "하핫, 난 큰 파도를 탔다고!\n언제 또 도전해주라.",
2: "언젠가 또 같이 서핑하자고!",
3: "파도가 밀려왔다가 밀려나듯, 언젠가 너도 다시 도전하러 와."
}
},
"wattson": {
"encounter": {
1: "Time to get shocked!\nWahahahaha!",
2: "I'll make sparks fly!\nWahahahaha!",
3: "I hope you brought Paralyz Heal!\nWahahahaha!"
1: "찌릿찌릿해질 때가 됐군!\n와하하하핫!",
2: "스파크가 튀도록 해주마!\n와하하하하!",
3: "와하하하하!\n마비 치료제를 가져왔길 바라네!"
},
"victory": {
1: "Seems like I'm out of charge!\nWahahahaha!",
2: "You've completely grounded me!\nWahahahaha!",
3: "Thanks for the thrill!\nWahahahaha!"
1: "이 몸 배터리가 다 됐군!\n와하하하하!",
2: "자네 완전히 날 좌초시켰군!\n와하하하핫!",
3: "스릴 넘치는 배틀, 고맙네!\n와하하하하하!"
},
"defeat": {
1: "Recharge your batteries and challenge me again sometime!\nWahahahaha!",
2: "I hope you found our battle electrifying!\nWahahahaha!",
3: "Aren't you shocked I won?\nWahahahaha!"
1: "자네의 배터리 재충전하게. 그리고 나에게 도전하러 돌아오도록!\n와하하하핫!",
2: "방금 배틀이 자네에게 짜릿짜릿했길 바란다네!\n와하하하하!",
3: "자네 혹시 내가 이겨서 충격 받았나?\n와하하하핫!"
}
},
"flannery": {
"encounter": {
1: "Nice to meet you! Wait, no…\nI will crush you!",
2: "I've only been a leader for a little while, but I'll smoke you!",
3: "It's time to demonstrate the moves my grandfather has taught me! Let's battle!"
1: "어서오세요! 잠깐, 아냐…\n너를 무너뜨려줄게!",
2: "난 체육관 관장이 된지는 얼마 안됐지만, 널 태워버릴거야!",
3: "할아버지에게 배운 기술을 한 수 보여줄게! 승부다!"
},
"victory": {
1: "You remind me of my grandfather…\nNo wonder I lost.",
2: "Am I trying too hard?\nI should relax, can't get too heated.",
3: "Losing isn't going to smother me out.\nTime to reignite training!"
1: "너 우리 할아버지를 생각나게 하네…\n내가 진 게 놀랍진 않아.",
2: "나 너무 열심히 하는 건가?\n너무 열 올리면 안되니깐, 진정해야겠어.",
3: "패배는 날 꺼뜨릴 수 없어.\n트레이닝으로 다시 불을 붙일 때야!"
},
"defeat": {
1: "I hope I've made my grandfather proud…\nLet's battle again some time.",
2: "I…I can't believe I won!\nDoing things my way worked!",
3: "Let's exchange burning hot moves again soon!"
1: "할아버지가 자랑스러워하시길…\n언젠가 다시 배틀하자.",
2: "내…내가 이기다니!\n내 방식대로 한 게 통했어!",
3: "조만간 다시 뜨겁게 불타오르는 배틀을 하자!"
}
},
"norman": {
"encounter": {
1: "I'm surprised you managed to get here.\nLet's battle.",
2: "I'll do everything in my power as a Gym Leader to win.\nLet's go!",
3: "You better give this your all.\nIt's time to battle!"
1: "여기까지 오다니 놀랍군.\n한 번 겨뤄볼까.",
2: "관장으로서 최선을 다해 널 이길 거란다.\n가자!",
3: "최선을 다하는 게 좋을 거야.\n승부할 시간이다!"
},
"victory": {
1: "I lost to you…?\nRules are rules, though.",
2: "Was moving from Olivine a mistake…?",
3: "I can't believe it.\nThat was a great match."
1: "내가 지다니…?\n규칙은 규칙이니, 흐음.",
2: "담청시티에서 이사한 게 문제였나…?",
3: "믿을 수 없구나.\n훌륭한 승부였어."
},
"defeat": {
1: "We both tried our best.\nI hope we can battle again soon.",
2: "You should try challenging my kid instead.\nYou might learn something!",
3: "Thank you for the excellent battle.\nBetter luck next time."
1: "우린 둘 다 최선을 다했지.\n다시 대결할 수 있었으면 좋겠구나.",
2: "우리 집 꼬마에게 도전해보는 것도 좋겠군.\n아마 뭔가 배울 수 있을거다!",
3: "방금 전 배틀 완벽했어.\n다음에도 행운이 함께하길."
}
},
"winona": {
"encounter": {
1: "I've been soaring the skies looking for prey…\nAnd you're my target!",
2: "No matter how our battle is, my Flying Pokémon and I will triumph with grace. Let's battle!",
3: "I hope you aren't scared of heights.\nLet's ascend!"
1: "저는 먹이를 찾아서 하늘을 날아다녔어요…\n그리고 당신은 제 타겟입니다!",
2: "배틀이 어떻게 되든, 전 제 비행 포켓몬과 우아하게 승리하겠어요. 승부합시다!",
3: "당신이 높은 곳을 무서워하지 않기를.\n자, 날아올라요!"
},
"victory": {
1: "You're the first Trainer I've seen with more grace than I.\nExcellently played.",
2: "Oh, my Flying Pokémon have plummeted!\nVery well.",
3: "Though I may have fallen, my Pokémon will continue to fly!"
1: "저보다 우아하게 나서는 트레이너는 처음 봤습니다.\n훌륭하시네요.",
2: "이런, 제 비행 포켓몬이 추락해버렸네요!\n훌륭한 배틀이었습니다.",
3: "비록 전 떨어졌지만, 제 포켓몬은 다시 날아갈 겁니다!"
},
"defeat": {
1: "My Flying Pokémon and I will forever dance elegantly!",
2: "I hope you enjoyed our show.\nOur graceful dance is finished.",
3: "Won't you come see our elegant choreography again?"
1: "제 비행 포켓몬과 영원히 우아하게 춤출게요.",
2: "우리의 쇼가 즐거웠길 바라요.\우아한 춤은 끝났습니다.",
3: "우리의 엘레강스한 안무를 다시 보러오지 않을래요?"
}
},
"tate": {
"encounter": {
1: "Hehehe…\nWere you surprised to see me without my sister?",
2: "I can see what you're thinking…\nYou want to battle!",
3: "How can you defeat someone…\nWho knows your every move?"
1: "헤헤헤…\n내가 란과 같이 있지 않아서 놀랐지?",
2: "네가 무슨 생각을 하는지 알아…\n승부하고 싶은거지!",
3: "네 움직임을 모두 알고 있는데…\n어떻게 이기려고?"
},
"victory": {
1: "It can't be helped…\nI miss Liza…",
2: "Your bond with your Pokémon was stronger than mine.",
3: "If I were with Liza, we would have won.\nWe can finish each other's thoughts!"
1: "어쩔 수 없지…\n란이 보고싶다아…",
2: "너와 네 포켓몬과의 유대, 나보다 더 견고한걸.",
3: "란이랑 함께였다면, 우리가 이겼어.\n둘이선 더 잘 할 수 있다구!"
},
"defeat": {
1: "My Pokémon and I are superior!",
2: "If you can't even defeat me, you'll never be able to defeat Liza either.",
3: "It's all thanks to my strict training with Liza.\nI can make myself one with Pokémon."
1: "내 포켓몬과 나는 우수하다구!",
2: "날 못 이긴다면, 넌 란한테도 절대로 못 이겨.",
3: "란과 함께한 엄격한 훈련 덕이야.\n덕분에 포켓몬과 하나가 될 수 있었어."
}
},
"liza": {
"encounter": {
1: "Fufufu…\nWere you surprised to see me without my brother?",
2: "I can determine what you desire…\nYou want to battle, don't you?",
3: "How can you defeat someone…\nWho's one with their Pokémon?"
1: "후후후…\n내가 풍과 같이 있지 않아서 놀랐지?",
2: "네가 무얼 바라는지 알아…\n포켓몬 배틀, 맞지?",
3: "포켓몬과 하나가 된 사람…\n어떻게 이기려고?"
},
"victory": {
1: "It can't be helped…\nI miss Tate…",
2: "Your bond with your Pokémon…\nIt's stronger than mine.",
3: "If I were with Tate, we would have won.\nWe can finish each other's sentences!"
1: "어쩔 수 없지…\n풍이 보고싶다아…",
2: "너와 네 포켓몬과의 유대, 나보다 더 견고한걸.",
3: "풍이랑 함께였다면, 우리가 이겼어.\n둘이선 더 잘 할 수 있다구!"
},
"defeat": {
1: "My Pokémon and I are victorious.",
2: "If you can't even defeat me, you'll never be able to defeat Tate either.",
3: "It's all thanks to my strict training with Tate.\nI can synchronize myself with my Pokémon."
1: "내 포켓몬과 내가 승리한거야.",
2: "날 못 이긴다면, 넌 풍한테도 절대로 못 이겨.",
3: "풍과 함께한 엄격한 훈련 덕이야.\n덕분에 포켓몬과 싱크로 될 수 있었어."
}
},
"juan": {
"encounter": {
1: "Now's not the time to act coy.\nLet's battle!",
2: "Ahahaha, You'll be witness to my artistry with Water Pokémon!",
3: "A typhoon approaches!\nWill you be able to test me?",
4: "Please, you shall bear witness to our artistry.\nA grand illusion of water sculpted by my Pokémon and myself!"
1: "지금은 겸양을 부릴 때가 아니군요.\n승부합시다!",
2: "아하하하, 물 포켓몬과 함께 아트를 보여드리겠습니다!",
3: "태풍이 다가오는군요!\n저를 테스트해주시겠습니까?",
4: "자, 마음껏 봐주십시오.\n저와 포켓몬이 이루어내는 물의 일루전을!"
},
"victory": {
1: "You may be a genius who can take on Wallace!",
2: "I focused on elegance while you trained.\nIt's only natural that you defeated me.",
3: "Ahahaha!\nVery well, You have won this time.",
4: "From you, I sense the brilliant shine of skill that will overcome all."
1: "당신은 윤진 관장을 뛰어넘을 지니어스군요!",
2: "당신이 훈련할 때 저는 엘레강스에 집중했습니다.\n당신이 이기는 건 당연하죠.",
3: "아하하하하!\n잘했습니다, 이번엔 당신이 이겼네요.",
4: "모든 것을 극복하는 브릴리언트 스킬, 당신에게 느껴지네요."
},
"defeat": {
1: "My Pokémon and I have sculpted an illusion of Water and come out victorious.",
2: "Ahahaha, I have won, and you have lost.",
3: "Shall I loan you my outfit? It may help you battle!\nAhahaha, I jest!",
4: "I'm the winner! Which is to say, you lost."
1: "저와 포켓몬이 이루어내는 물의 일루전이 승리했습니다.",
2: "아하하핫, 저는 이겼고, 당신은 졌습니다.",
3: "겉옷 빌려드릴까요? 아마도 배틀에 도움이 될겁니다!\n아하하하, 농담입니다!",
4: "제가 승리자군요! 그리고, 당신은 졌네요."
}
},
"crasher_wake": {
@ -1046,24 +1046,24 @@ export const PGMdialogue: DialogueTranslationEntries = {
},
"kofu": {
"encounter": {
1: "I'mma serve you a full course o' Water-type Pokémon! Don't try to eat 'em, though!"
1: "물포켓몬의 풀코스를! 배 터지게 먹여 주도록 하마!"
},
"victory": {
1: "Vaultin' Veluza! Yer a lively one, aren't ya! A little TOO lively, if I do say so myself!"
1: "우옷! 우오오옷! 이렇게 팔팔한 트레이너가 다 있다니!"
},
"defeat": {
1: "You come back to see me again now, ya hear?"
1: "젊은 친구! 다음에 또 만나기를 기대하고 있으마!"
}
},
"tulip": {
"encounter": {
1: "Allow me to put my skills to use to make your cute little Pokémon even more beautiful!"
1: "리파의 기술로 너의 포켓몬들을 지금보다 훨~씬 아름답게 만들어 줄게!"
},
"victory": {
1: "Your strength has a magic to it that cannot be washed away."
1: "너의 강함은 풀 수 없는 매직이구나."
},
"defeat": {
1: "You know, in my line of work, people who lack talent in one area or the other often fade away quickly—never to be heard of again."
1: "…리파의 업계에서는 어중간한 재능을 가진 사람은 대체로 금방 사라져 버려."
}
},
"sidney": {
@ -1193,13 +1193,13 @@ export const PGMdialogue: DialogueTranslationEntries = {
},
"rika": {
"encounter": {
1: "I'd say I'll go easy on you, but… I'd be lying! Think fast!"
1: "실컷 귀여워해 줄 테니까… 한 번 열심히 해 보라고!"
},
"victory": {
1: "Not bad, kiddo."
1: "너, 꽤 하는구나!"
},
"defeat": {
1: "Nahahaha! You really are something else, kiddo!"
1: "아하하! 제법인데! 역시 너는 재밌는 녀석이라니까!"
}
},
"bruno": {
@ -1295,14 +1295,14 @@ export const PGMdialogue: DialogueTranslationEntries = {
},
"poppy": {
"encounter": {
1: "Oooh! Do you wanna have a Pokémon battle with me?"
1: "우와~! 뽀삐와 포켓몬 승부가 하고 싶으세요?"
},
"victory": {
1: "Uagh?! Mmmuuuggghhh…"
1: "훌쩍, 으에엥~"
},
"defeat": {
1: `Yaaay! I did it! I de-feet-ed you! You can come for… For… An avenge match?
$Come for an avenge match anytime you want!`,
1: `만세~! 만세~ 목수, 성공했어요!
$에헴! !`,
}
},
"agatha": {
@ -1390,14 +1390,14 @@ export const PGMdialogue: DialogueTranslationEntries = {
},
"larry_elite": {
"encounter": {
1: `Hello there… It's me, Larry.
$I serve as a member of the Elite Four too, yes Unfortunately for me.`,
1: `…안녕하십니까, 청목입니다.
$귀찮게도 .`,
},
"victory": {
1: "Well, that took the wind from under our wings…"
1: "날고 있는 새포켓몬도 떨어뜨릴 기세로군요."
},
"defeat": {
1: "It's time for a meeting with the boss."
1: "치프와 만나기로 한 시각이군요."
}
},
"lance": {
@ -1483,14 +1483,14 @@ export const PGMdialogue: DialogueTranslationEntries = {
},
"hassel": {
"encounter": {
1: "Prepare to learn firsthand how the fiery breath of ferocious battle feels!"
1: "맹렬하게 몰아치는 승부의 숨결을 직접 가르쳐 드리겠습니다!!"
},
"victory": {
1: `Fortune smiled on me this time, but…
$Judging from how the match went, who knows if I will be so lucky next time.`,
1: `이번에는 당신이 승리를 쟁취했군요.
$하지만, .`,
},
"defeat": {
1: "That was an ace!"
1: "저에게 더 배우고 싶은 것이 있으시다면 또 승부하도록 하죠."
}
},
"blue": {
@ -1662,13 +1662,13 @@ export const PGMdialogue: DialogueTranslationEntries = {
},
"katy": {
"encounter": {
1: "Don't let your guard down unless you would like to find yourself knocked off your feet!"
1: "쓰러지고 싶지 않다면 방심하지 말고 열심히 해 봐~"
},
"victory": {
1: "All of my sweet little Pokémon dropped like flies!"
1: "내 포켓몬들 모두 지쳐서 헤벌레~ 해졌어~"
},
"defeat": {
1: "Eat up, my cute little Vivillon!"
1: "비비용~ 많~이 먹으렴~"
}
},
"pryce": {
@ -1969,60 +1969,60 @@ export const PGMdialogue: DialogueTranslationEntries = {
},
"brassius": {
"encounter": {
1: "I assume you are ready? Let our collaborative work of art begin!"
1: "준비는 됐겠지!? 그럼, 우리 둘의 예술적인 합작품을 한번 만들어 보도록 할까!"
},
"victory": {
1: "Ahhh…vant-garde!"
1: "아… 아방가르드!!"
},
"defeat": {
1: "I will begin on a new piece at once!"
1: "바로 신작을 만들러 가야 하니 이만 실례하겠다!"
}
},
"iono": {
"encounter": {
1: `How're ya feelin' about this battle?
1: `자~ 오늘의 각오는~ 모야모야~?
$...
$Let's get this show on the road! How strong is our challenger?
$I 'unno! Let's find out together!`,
$그럼, !
$도전자님의 ~!?`,
},
"victory": {
1: "You're as flashy and bright as a 10,000,000-volt Thunderbolt, friendo!"
1: "너의 반짝임은 1000만볼트!"
},
"defeat": {
1: "Your eyeballs are MINE!"
1: "당신의 눈길을 일렉트릭네트로 뾰로롱!"
}
},
"larry": {
"encounter": {
1: "When all's said and done, simplicity is strongest."
1: "그렇습니다. 심플한 것이 가장 강한 것입니다!"
},
"victory": {
1: "A serving of defeat, huh?"
1: "허, 이걸로 한 방 먹은 게 되었군요."
},
"defeat": {
1: "I'll call it a day."
1: "오늘은 저는 이만 실례하겠습니다."
}
},
"ryme": {
"encounter": {
1: "Come on, baby! Rattle me down to the bone!"
1: "나의 영혼 흔들어 봐 Come On!"
},
"victory": {
1: "You're cool, my friend—you move my SOUL!"
1: "너의 Cool한 Youth 나의 Soul이 Move!"
},
"defeat": {
1: "Later, baby!"
1: "Bye Bye Baby~!"
}
},
"grusha": {
"encounter": {
1: "All I need to do is make sure the power of my Pokémon chills you to the bone!"
1: "내가 너를 철저하게 얼려 버리면 고민할 것도 없겠지!"
},
"victory": {
1: "Your burning passion… I kinda like it, to be honest."
1: "너의 그 열기… 싫지 않아."
},
"defeat": {
1: "Things didn't heat up for you."
1: "너에겐 아직 열기가 부족하구나."
}
},
"marnie_elite": {

View File

@ -99,6 +99,10 @@ export const modifierType: ModifierTypeTranslationEntries = {
name: "No.{{moveId}} {{moveName}}",
description: "포켓몬에게 {{moveName}}[[를]] 가르침",
},
"TmModifierTypeWithInfo": {
name: "No.{{moveId}} {{moveName}}",
description: "포켓몬에게 {{moveName}}를(을) 가르침\n(Hold C or Shift for more info)",
},
"EvolutionItemModifierType": {
description: "어느 특정 포켓몬을 진화",
},

View File

@ -99,6 +99,10 @@ export const modifierType: ModifierTypeTranslationEntries = {
name: "TM{{moveId}} - {{moveName}}",
description: "Ensina {{moveName}} a um Pokémon",
},
"TmModifierTypeWithInfo": {
name: "TM{{moveId}} - {{moveName}}",
description: "Ensina {{moveName}} a um Pokémon\n(Segure C ou Shift para mais informações)",
},
"EvolutionItemModifierType": {
description: "Faz certos Pokémon evoluírem",
},

View File

@ -9,7 +9,7 @@ export const tutorial: SimpleTranslationEntries = {
$Se o jogo estiver rodando lentamente, certifique-se de que a 'Aceleração de hardware' esteja ativada
$nas configurações do seu navegador.`,
"accessMenu": `Para acessar o menu, aperte M ou Esc.
"accessMenu": `Para acessar o menu, pressione M ou Esc.
$O menu contém configurações e diversas funções.`,
"menu": `A partir deste menu, você pode acessar as configurações.

View File

@ -99,6 +99,10 @@ export const modifierType: ModifierTypeTranslationEntries = {
name: "招式学习器 {{moveId}} - {{moveName}}",
description: "教会一只宝可梦{{moveName}}",
},
"TmModifierTypeWithInfo": {
name: "招式学习器 {{moveId}} - {{moveName}}",
description: "教会一只宝可梦{{moveName}}\n(Hold C or Shift for more info)",
},
"EvolutionItemModifierType": {
description: "使某些宝可梦进化",
},

View File

@ -98,6 +98,10 @@ export const modifierType: ModifierTypeTranslationEntries = {
name: "招式學習器 {{moveId}} - {{moveName}}",
description: "教會一隻寶可夢{{moveName}}",
},
TmModifierTypeWithInfo: {
name: "TM{{moveId}} - {{moveName}}",
description: "教會一隻寶可夢{{moveName}}\n(Hold C or Shift for more info)",
},
EvolutionItemModifierType: { description: "使某些寶可夢進化" },
FormChangeItemModifierType: { description: "使某些寶可夢更改形態" },
FusePokemonModifierType: {

View File

@ -23,6 +23,7 @@ import { ModifierTier } from "./modifier-tier";
import { Nature, getNatureName, getNatureStatMultiplier } from "#app/data/nature";
import i18next from "#app/plugins/i18n";
import { getModifierTierTextTint } from "#app/ui/text";
import * as Overrides from "../overrides";
const outputModifierData = false;
const useMaxWeightForOutput = false;
@ -721,7 +722,7 @@ export class TmModifierType extends PokemonModifierType {
}
getDescription(scene: BattleScene): string {
return i18next.t("modifierType:ModifierType.TmModifierType.description", { moveName: allMoves[this.moveId].name });
return i18next.t(scene.enableMoveInfo ? "modifierType:ModifierType.TmModifierTypeWithInfo.description" : "modifierType:ModifierType.TmModifierType.description", { moveName: allMoves[this.moveId].name });
}
}
@ -1673,6 +1674,14 @@ export function getPlayerModifierTypeOptions(count: integer, party: PlayerPokemo
}
options.push(candidate);
});
// OVERRIDE IF NECESSARY
if (Overrides.ITEM_REWARD_OVERRIDE?.length) {
options.forEach((mod, i) => {
// @ts-ignore: keeps throwing don't use string as index error in typedoc run
const override = modifierTypes[Overrides.ITEM_REWARD_OVERRIDE[i]]?.();
mod.type = (override instanceof ModifierTypeGenerator ? override.generateType(party) : override) || mod.type;
});
}
return options;
}

View File

@ -2195,7 +2195,8 @@ export class EnemyAttackStatusEffectChanceModifier extends EnemyPersistentModifi
super(type, stackCount);
this.effect = effect;
this.chance = (chancePercent || 5) / 100;
//Hardcode temporarily
this.chance = .025 * ((this.effect === StatusEffect.BURN || this.effect === StatusEffect.POISON) ? 2 : 1);
}
match(modifier: Modifier): boolean {
@ -2230,7 +2231,8 @@ export class EnemyStatusEffectHealChanceModifier extends EnemyPersistentModifier
constructor(type: ModifierType, chancePercent: number, stackCount?: integer) {
super(type, stackCount);
this.chance = (chancePercent || 2.5) / 100;
//Hardcode temporarily
this.chance = .025;
}
match(modifier: Modifier): boolean {
@ -2268,7 +2270,8 @@ export class EnemyEndureChanceModifier extends EnemyPersistentModifier {
constructor(type: ModifierType, chancePercent?: number, stackCount?: integer) {
super(type, stackCount || 10);
this.chance = (chancePercent || 2) / 100;
//Hardcode temporarily
this.chance = .02;
}
match(modifier: Modifier) {

View File

@ -110,3 +110,11 @@ export const OPP_MODIFIER_OVERRIDE: Array<ModifierOverride> = [];
export const STARTING_HELD_ITEMS_OVERRIDE: Array<ModifierOverride> = [];
export const OPP_HELD_ITEMS_OVERRIDE: Array<ModifierOverride> = [];
/**
* An array of items by keys as defined in the "modifierTypes" object in the "modifier/modifier-type.ts" file.
* Items listed will replace the normal rolls.
* If less items are listed than rolled, only some items will be replaced
* If more items are listed than rolled, only the first X items will be shown, where X is the number of items rolled.
*/
export const ITEM_REWARD_OVERRIDE: Array<String> = [];

View File

@ -43,7 +43,8 @@ import { EggHatchPhase } from "./egg-hatch-phase";
import { Egg } from "./data/egg";
import { vouchers } from "./system/voucher";
import { loggedInUser, updateUserInfo } from "./account";
import { PlayerGender, SessionSaveData } from "./system/game-data";
import { SessionSaveData } from "./system/game-data";
import { PlayerGender } from "./data/enums/player-gender";
import { addPokeballCaptureStars, addPokeballOpenParticles } from "./field/anims";
import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms";
import { battleSpecDialogue, getCharVariantFromDialogue, miscDialogue } from "./data/dialogue";

View File

@ -36,28 +36,11 @@ import { TerrainChangedEvent, WeatherChangedEvent } from "#app/field/arena-event
import { Device } from "#app/enums/devices.js";
import { EnemyAttackStatusEffectChanceModifier } from "../modifier/modifier";
import { StatusEffect } from "#app/data/status-effect.js";
import { PlayerGender } from "#app/data/enums/player-gender";
import { GameDataType } from "#app/data/enums/game-data-type";
const saveKey = "x0i2O7WRiANTqPmZ"; // Temporary; secure encryption is not yet necessary
export enum GameDataType {
SYSTEM,
SESSION,
SETTINGS,
TUTORIALS,
SEEN_DIALOGUES
}
export enum PlayerGender {
UNSET,
MALE,
FEMALE
}
export enum Passive {
UNLOCKED = 1,
ENABLED = 2
}
export function getDataTypeKey(dataType: GameDataType, slotId: integer = 0): string {
switch (dataType) {
case GameDataType.SYSTEM:

View File

@ -3,7 +3,7 @@ import i18next from "i18next";
import BattleScene from "../../battle-scene";
import { hasTouchscreen } from "../../touch-controls";
import { updateWindowType } from "../../ui/ui-theme";
import { PlayerGender } from "../game-data";
import { PlayerGender } from "#app/data/enums/player-gender";
import { CandyUpgradeNotificationChangedEvent } from "#app/battle-scene-events.js";
import { MoneyFormat } from "../../enums/money-format";
import SettingsUiHandler from "#app/ui/settings/settings-ui-handler";
@ -44,6 +44,7 @@ export const SettingKeys = {
UI_Theme: "UI_THEME",
Window_Type: "WINDOW_TYPE",
Tutorials: "TUTORIALS",
Move_Info: "MOVE_INFO",
Enable_Retries: "ENABLE_RETRIES",
Skip_Seen_Dialogues: "SKIP_SEEN_DIALOGUES",
Candy_Upgrade_Notification: "CANDY_UPGRADE_NOTIFICATION",
@ -132,6 +133,13 @@ export const Setting: Array<Setting> = [
default: 1,
type: SettingType.GENERAL
},
{
key: SettingKeys.Move_Info,
label: "Move Info",
options: OFF_ON,
default: 1,
type: SettingType.ACCESSIBILITY
},
{
key: SettingKeys.Enable_Retries,
label: "Enable Retries",
@ -312,6 +320,9 @@ export function setSetting(scene: BattleScene, setting: string, value: integer):
case SettingKeys.Tutorials:
scene.enableTutorials = Setting[index].options[value] === "On";
break;
case SettingKeys.Move_Info:
scene.enableMoveInfo = Setting[index].options[value] === "On";
break;
case SettingKeys.Enable_Retries:
scene.enableRetries = Setting[index].options[value] === "On";
break;

View File

@ -114,6 +114,11 @@ export class UiInputs {
}
buttonStats(pressed: boolean = true): void {
// allow access to Button.STATS as a toggle for other elements
for (const t of this.scene.getInfoToggles(true)) {
t.toggleInfo(pressed);
}
// handle normal pokemon battle ui
for (const p of this.scene.getField().filter(p => p?.isActive(true))) {
p.toggleStats(pressed);
}

View File

@ -14,15 +14,17 @@ export interface OptionSelectConfig {
maxOptions?: integer;
delay?: integer;
noCancel?: boolean;
supportHover?: boolean;
}
export interface OptionSelectItem {
label: string;
handler: () => boolean;
onHover?: () => void;
keepOpen?: boolean;
overrideSound?: boolean;
item?: string;
itemArgs?: any[]
itemArgs?: any[];
}
const scrollUpLabel = "↑";
@ -193,6 +195,10 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler {
}
break;
}
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?.();
}
}
if (success && playSound) {

View File

@ -4,7 +4,7 @@ import { Mode } from "./ui";
import * as Utils from "../utils";
import { addWindow } from "./ui-theme";
import MessageUiHandler from "./message-ui-handler";
import { GameDataType } from "../system/game-data";
import { GameDataType } from "#app/data/enums/game-data-type";
import { OptionSelectConfig, OptionSelectItem } from "./abstact-option-select-ui-handler";
import { Tutorial, handleTutorial } from "../tutorial";
import { updateUserInfo } from "../account";

View File

@ -1,5 +1,5 @@
import BattleScene from "../battle-scene";
import { getPlayerShopModifierTypeOptionsForWave, ModifierTypeOption } from "../modifier/modifier-type";
import { getPlayerShopModifierTypeOptionsForWave, ModifierTypeOption, TmModifierType } from "../modifier/modifier-type";
import { getPokeballAtlasKey, PokeballType } from "../data/pokeball";
import { addTextObject, getModifierTierTextTint, getTextColor, TextStyle } from "./text";
import AwaitableUiHandler from "./awaitable-ui-handler";
@ -7,6 +7,8 @@ import { Mode } from "./ui";
import { LockModifierTiersModifier, PokemonHeldItemModifier } from "../modifier/modifier";
import { handleTutorial, Tutorial } from "../tutorial";
import {Button} from "../enums/buttons";
import MoveInfoOverlay from "./move-info-overlay";
import { allMoves } from "../data/move";
export const SHOP_OPTIONS_ROW_LIMIT = 6;
@ -17,6 +19,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
private transferButtonContainer: Phaser.GameObjects.Container;
private rerollCostText: Phaser.GameObjects.Text;
private lockRarityButtonText: Phaser.GameObjects.Text;
private moveInfoOverlay : MoveInfoOverlay;
private rowCursor: integer = 0;
private player: boolean;
@ -73,6 +76,21 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
this.lockRarityButtonText = addTextObject(this.scene, -4, -2, "Lock Rarities", TextStyle.PARTY);
this.lockRarityButtonText.setOrigin(0, 0);
this.lockRarityButtonContainer.add(this.lockRarityButtonText);
// prepare move overlay
const overlayScale = 1;
this.moveInfoOverlay = new MoveInfoOverlay(this.scene, {
delayVisibility: true,
scale: overlayScale,
onSide: true,
right: true,
x: 1,
y: -MoveInfoOverlay.getHeight(overlayScale, true) -1,
width: (this.scene.game.canvas.width / 6) - 2,
});
ui.add(this.moveInfoOverlay);
// register the overlay to receive toggle events
this.scene.addInfoToggle(this.moveInfoOverlay);
}
show(args: any[]): boolean {
@ -293,6 +311,8 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
this.cursorObj.setScale(this.rowCursor === 1 ? 2 : this.rowCursor >= 2 ? 1.5 : 1);
// the modifier selection has been updated, always hide the overlay
this.moveInfoOverlay.clear();
if (this.rowCursor) {
const sliceWidth = (this.scene.game.canvas.width / 6) / (options.length + 2);
if (this.rowCursor < 2) {
@ -300,7 +320,13 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
} else {
this.cursorObj.setPosition(sliceWidth * (cursor + 1) + (sliceWidth * 0.5) - 16, (-this.scene.game.canvas.height / 12 - this.scene.game.canvas.height / 32) - (-16 + 28 * (this.rowCursor - (this.shopOptionsRows.length - 1))));
}
ui.showText(options[this.cursor].modifierTypeOption.type.getDescription(this.scene));
const type = options[this.cursor].modifierTypeOption.type;
ui.showText(type.getDescription(this.scene));
if (type instanceof TmModifierType) {
// prepare the move overlay to be shown with the toggle
this.moveInfoOverlay.show(allMoves[type.moveId]);
}
} else if (!cursor) {
this.cursorObj.setPosition(6, this.lockRarityButtonContainer.visible ? -72 : -60);
ui.showText("Spend money to reroll your item options.");

194
src/ui/move-info-overlay.ts Normal file
View File

@ -0,0 +1,194 @@
import BattleScene, {InfoToggle} from "../battle-scene";
import { TextStyle, addTextObject } from "./text";
import { addWindow } from "./ui-theme";
import * as Utils from "../utils";
import Move, { MoveCategory } from "../data/move";
import { Type } from "../data/type";
import i18next from "i18next";
export interface MoveInfoOverlaySettings {
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;
width?: number; // default is always half the screen, regardless of scale
}
const EFF_HEIGHT = 46;
const EFF_WIDTH = 82;
const DESC_HEIGHT = 46;
const BORDER = 8;
const GLOBAL_SCALE = 6;
export default class MoveInfoOverlay extends Phaser.GameObjects.Container implements InfoToggle {
public active: boolean = false;
private move: Move;
private desc: Phaser.GameObjects.Text;
private descScroll : Phaser.Tweens.Tween = null;
private val: Phaser.GameObjects.Container;
private pp: Phaser.GameObjects.Text;
private pow: Phaser.GameObjects.Text;
private acc: Phaser.GameObjects.Text;
private typ: Phaser.GameObjects.Sprite;
private cat: Phaser.GameObjects.Sprite;
private options : MoveInfoOverlaySettings;
constructor(scene: BattleScene, options?: MoveInfoOverlaySettings) {
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 || MoveInfoOverlay.getWidth(scale, scene)) / scale; // divide by scale as we always want this to be half a window wide
const descBg = addWindow(scene, (options?.onSide && !options?.right ? EFF_WIDTH : 0), options?.top ? EFF_HEIGHT : 0, width - (options?.onSide ? EFF_WIDTH : 0), DESC_HEIGHT);
descBg.setOrigin(0, 0);
this.add(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 } });
// 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);
// prepare the effect box
this.val = new Phaser.GameObjects.Container(scene, options?.right ? width - EFF_WIDTH : 0, options?.top || options?.onSide ? 0 : DESC_HEIGHT);
this.add(this.val);
const valuesBg = addWindow(scene, 0, 0, EFF_WIDTH, EFF_HEIGHT);
valuesBg.setOrigin(0, 0);
this.val.add(valuesBg);
this.typ = this.scene.add.sprite(25, EFF_HEIGHT - 35,`types${Utils.verifyLang(i18next.language) ? `_${i18next.language}` : ""}` , "unknown");
this.typ.setScale(0.8);
this.val.add(this.typ);
this.cat = this.scene.add.sprite(57, EFF_HEIGHT - 35, "categories", "physical");
this.val.add(this.cat);
const ppTxt = addTextObject(scene, 12, EFF_HEIGHT - 25, "PP", TextStyle.MOVE_INFO_CONTENT);
ppTxt.setOrigin(0.0, 0.5);
ppTxt.setText(i18next.t("fightUiHandler:pp"));
this.val.add(ppTxt);
this.pp = addTextObject(scene, 70, EFF_HEIGHT - 25, "--", TextStyle.MOVE_INFO_CONTENT);
this.pp.setOrigin(1, 0.5);
this.val.add(this.pp);
const powTxt = addTextObject(scene, 12, EFF_HEIGHT - 17, "POWER", TextStyle.MOVE_INFO_CONTENT);
powTxt.setOrigin(0.0, 0.5);
powTxt.setText(i18next.t("fightUiHandler:power"));
this.val.add(powTxt);
this.pow = addTextObject(scene, 70, EFF_HEIGHT - 17, "---", TextStyle.MOVE_INFO_CONTENT);
this.pow.setOrigin(1, 0.5);
this.val.add(this.pow);
const accTxt = addTextObject(scene, 12, EFF_HEIGHT - 9, "ACC", TextStyle.MOVE_INFO_CONTENT);
accTxt.setOrigin(0.0, 0.5);
accTxt.setText(i18next.t("fightUiHandler:accuracy"));
this.val.add(accTxt);
this.acc = addTextObject(scene, 70, EFF_HEIGHT - 9, "---", TextStyle.MOVE_INFO_CONTENT);
this.acc.setOrigin(1, 0.5);
this.val.add(this.acc);
// hide this component for now
this.setVisible(false);
}
// show this component with infos for the specific move
show(move : Move):boolean {
if (!(this.scene as BattleScene).enableMoveInfo) {
return; // move infos have been disabled
}
this.move = move;
this.pow.setText(move.power >= 0 ? move.power.toString() : "---");
this.acc.setText(move.accuracy >= 0 ? move.accuracy.toString() : "---");
this.pp.setText(move.pp >= 0 ? move.pp.toString() : "---");
this.typ.setTexture(`types${Utils.verifyLang(i18next.language) ? `_${i18next.language}` : ""}`, Type[move.type].toLowerCase());
this.cat.setFrame(MoveCategory[move.category].toLowerCase());
this.desc.setText(move?.effect || "");
// stop previous scrolling effects
if (this.descScroll) {
this.descScroll.remove();
this.descScroll = null;
}
// 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(force?: boolean): void {
this.setVisible(force ?? !this.visible);
}
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;
}
}

View File

@ -17,6 +17,7 @@ import { addWindow } from "./ui-theme";
import { SpeciesFormChangeItemTrigger } from "../data/pokemon-forms";
import { getVariantTint } from "#app/data/variant";
import {Button} from "../enums/buttons";
import MoveInfoOverlay from "./move-info-overlay";
const defaultMessage = "Choose a Pokémon.";
@ -73,6 +74,7 @@ export default class PartyUiHandler extends MessageUiHandler {
private partySlots: PartySlot[];
private partyCancelButton: PartyCancelButton;
private partyMessageBox: Phaser.GameObjects.NineSlice;
private moveInfoOverlay: MoveInfoOverlay;
private optionsMode: boolean;
private optionsScroll: boolean;
@ -179,6 +181,17 @@ export default class PartyUiHandler extends MessageUiHandler {
this.iconAnimHandler = new PokemonIconAnimHandler();
this.iconAnimHandler.setup(this.scene);
// prepare move overlay. in case it appears to be too big, set the overlayScale to .5
const overlayScale = 1;
this.moveInfoOverlay = new MoveInfoOverlay(this.scene, {
scale: overlayScale,
top: true,
x: 1,
y: -MoveInfoOverlay.getHeight(overlayScale) - 1, //this.scene.game.canvas.height / 6 - MoveInfoOverlay.getHeight(overlayScale) - 29,
width: this.scene.game.canvas.width / 12 - 30,
});
ui.add(this.moveInfoOverlay);
this.options = [];
this.partySlots = [];
@ -191,6 +204,9 @@ export default class PartyUiHandler extends MessageUiHandler {
super.show(args);
// reset the infoOverlay
this.moveInfoOverlay.clear();
this.partyUiMode = args[0] as PartyUiMode;
this.fieldIndex = args.length > 1 ? args[1] as integer : -1;
@ -244,6 +260,8 @@ export default class PartyUiHandler extends MessageUiHandler {
ui.playSelect();
return true;
} else if (this.partyUiMode === PartyUiMode.REMEMBER_MOVE_MODIFIER && option !== PartyOption.CANCEL) {
// clear overlay on cancel
this.moveInfoOverlay.clear();
const filterResult = (this.selectFilter as PokemonSelectFilter)(pokemon);
if (filterResult === null) {
this.selectCallback(this.cursor, option);
@ -408,6 +426,19 @@ export default class PartyUiHandler extends MessageUiHandler {
success = this.setCursor(this.optionsCursor < this.options.length - 1 ? this.optionsCursor + 1 : 0); /** Move cursor */
break;
}
// show move description
if (this.partyUiMode === PartyUiMode.REMEMBER_MOVE_MODIFIER) {
const option = this.options[this.optionsCursor];
const pokemon = this.scene.getParty()[this.cursor];
const move = allMoves[pokemon.getLearnableLevelMoves()[option]];
if (move) {
this.moveInfoOverlay.show(move);
} else {
// or hide the overlay, in case it's the cancel button
this.moveInfoOverlay.clear();
}
}
}
} else {
if (button === Button.ACTION) {
@ -625,6 +656,11 @@ export default class PartyUiHandler extends MessageUiHandler {
? pokemon.getLearnableLevelMoves()
: null;
if (this.partyUiMode === PartyUiMode.REMEMBER_MOVE_MODIFIER && learnableLevelMoves?.length) {
// show the move overlay with info for the first move
this.moveInfoOverlay.show(allMoves[learnableLevelMoves[0]]);
}
const itemModifiers = this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER
? this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier
&& (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === pokemon.id) as PokemonHeldItemModifier[]
@ -874,6 +910,8 @@ export default class PartyUiHandler extends MessageUiHandler {
}
clearOptions() {
// hide the overlay
this.moveInfoOverlay.clear();
this.optionsMode = false;
this.optionsScroll = false;
this.optionsScrollCursor = 0;
@ -895,6 +933,8 @@ export default class PartyUiHandler extends MessageUiHandler {
clear() {
super.clear();
// hide the overlay
this.moveInfoOverlay.clear();
this.partyContainer.setVisible(false);
this.clearPartySlots();
}

View File

@ -20,7 +20,8 @@ import { Type } from "../data/type";
import { Button } from "../enums/buttons";
import { GameModes, gameModes } from "../game-mode";
import { TitlePhase } from "../phases";
import { AbilityAttr, DexAttr, DexAttrProps, DexEntry, Passive as PassiveAttr, StarterFormMoveData, StarterMoveset } from "../system/game-data";
import { AbilityAttr, DexAttr, DexAttrProps, DexEntry, StarterFormMoveData, StarterMoveset } from "../system/game-data";
import { Passive as PassiveAttr } from "#app/data/enums/passive";
import { Tutorial, handleTutorial } from "../tutorial";
import * as Utils from "../utils";
import { OptionSelectItem } from "./abstact-option-select-ui-handler";
@ -30,6 +31,7 @@ import { StatsContainer } from "./stats-container";
import { TextStyle, addBBCodeTextObject, addTextObject } from "./text";
import { Mode } from "./ui";
import { addWindow } from "./ui-theme";
import MoveInfoOverlay from "./move-info-overlay";
export type StarterSelectCallback = (starters: Starter[]) => void;
@ -191,6 +193,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
private starterSelectMessageBoxContainer: Phaser.GameObjects.Container;
private statsContainer: StatsContainer;
private pokemonFormText: Phaser.GameObjects.Text;
private moveInfoOverlay : MoveInfoOverlay;
private genMode: boolean;
private statsMode: boolean;
@ -403,7 +406,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.valueLimitLabel.setOrigin(0.5, 0);
this.starterSelectContainer.add(this.valueLimitLabel);
const startLabel = addTextObject(this.scene, 124, 162, i18next.t("starterSelectUiHandler:start"), TextStyle.TOOLTIP_CONTENT);
//TODO: back to translated version
const startLabel = addTextObject(this.scene, 124, 162, "Random", TextStyle.TOOLTIP_CONTENT);
startLabel.setOrigin(0.5, 0);
this.starterSelectContainer.add(startLabel);
@ -659,6 +663,15 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.message.setOrigin(0, 0);
this.starterSelectMessageBoxContainer.add(this.message);
const overlayScale = 1; // scale for the move info. "2/3" might be another good option...
this.moveInfoOverlay = new MoveInfoOverlay(this.scene, {
scale: overlayScale,
top: true,
x: 1,
y: this.scene.game.canvas.height / 6 - MoveInfoOverlay.getHeight(overlayScale) - 29,
});
this.starterSelectContainer.add(this.moveInfoOverlay);
const date = new Date();
date.setUTCHours(0, 0, 0, 0);
@ -1056,6 +1069,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
const showSwapOptions = (moveset: StarterMoveset) => {
ui.setMode(Mode.STARTER_SELECT).then(() => {
ui.showText(i18next.t("starterSelectUiHandler:selectMoveSwapOut"), null, () => {
this.moveInfoOverlay.show(allMoves[moveset[0]]);
ui.setModeWithoutClear(Mode.OPTION_SELECT, {
options: moveset.map((m: Moves, i: number) => {
const option: OptionSelectItem = {
@ -1063,8 +1078,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
handler: () => {
ui.setMode(Mode.STARTER_SELECT).then(() => {
ui.showText(`${i18next.t("starterSelectUiHandler:selectMoveSwapWith")} ${allMoves[m].name}.`, null, () => {
const possibleMoves = this.speciesStarterMoves.filter((sm: Moves) => sm !== m);
this.moveInfoOverlay.show(allMoves[possibleMoves[0]]);
ui.setModeWithoutClear(Mode.OPTION_SELECT, {
options: this.speciesStarterMoves.filter((sm: Moves) => sm !== m).map(sm => {
options: possibleMoves.map(sm => {
// make an option for each available starter move
const option = {
label: allMoves[sm].name,
@ -1072,7 +1090,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.switchMoveHandler(i, sm, m);
showSwapOptions(this.starterMoveset);
return true;
}
},
onHover: () => {
this.moveInfoOverlay.show(allMoves[sm]);
},
};
return option;
}).concat({
@ -1080,25 +1101,37 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
handler: () => {
showSwapOptions(this.starterMoveset);
return true;
}
},
onHover: () => {
this.moveInfoOverlay.clear();
},
}),
supportHover: true,
maxOptions: 8,
yOffset: 19
});
});
});
return true;
}
},
onHover: () => {
this.moveInfoOverlay.show(allMoves[m]);
},
};
return option;
}).concat({
label: i18next.t("menu:cancel"),
handler: () => {
this.moveInfoOverlay.clear();
this.clearText();
ui.setMode(Mode.STARTER_SELECT);
return true;
}
},
onHover: () => {
this.moveInfoOverlay.clear();
},
}),
supportHover: true,
maxOptions: 8,
yOffset: 19
});

View File

@ -17,7 +17,7 @@ import { StatusEffect } from "../data/status-effect";
import { getBiomeName } from "../data/biomes";
import { Nature, getNatureStatMultiplier } from "../data/nature";
import { loggedInUser } from "../account";
import { PlayerGender } from "../system/game-data";
import { PlayerGender } from "#app/data/enums/player-gender";
import { Variant, getVariantTint } from "#app/data/variant";
import {Button} from "../enums/buttons";
import { Ability } from "../data/ability.js";

View File

@ -38,7 +38,7 @@ import OutdatedModalUiHandler from "./outdated-modal-ui-handler";
import SessionReloadModalUiHandler from "./session-reload-modal-ui-handler";
import {Button} from "../enums/buttons";
import i18next, {ParseKeys} from "i18next";
import {PlayerGender} from "#app/system/game-data";
import { PlayerGender } from "#app/data/enums/player-gender";
import GamepadBindingUiHandler from "./settings/gamepad-binding-ui-handler";
import SettingsKeyboardUiHandler from "#app/ui/settings/settings-keyboard-ui-handler";
import KeyboardBindingUiHandler from "#app/ui/settings/keyboard-binding-ui-handler";

View File

@ -263,6 +263,8 @@ export const isLocal = (
// Set the server URL based on whether it's local or not
export const serverUrl = isLocal ? `${window.location.hostname}:${window.location.port}` : "";
export const apiUrl = isLocal ? serverUrl : "https://api.pokerogue.net";
// used to disable api calls when isLocal is true and a server is not found
export let isLocalServerConnected = false;
export function setCookie(cName: string, cValue: string): void {
const expiration = new Date();
@ -285,8 +287,22 @@ export function getCookie(cName: string): string {
return "";
}
/**
* When locally running the game, "pings" the local server
* with a GET request to verify if a server is running,
* sets isLocalServerConnected based on results
*/
export function localPing() {
if (isLocal) {
apiFetch("game/titlestats")
.then(resolved => isLocalServerConnected = true,
rejected => isLocalServerConnected = false
);
}
}
export function apiFetch(path: string, authed: boolean = false): Promise<Response> {
return new Promise((resolve, reject) => {
return (isLocal && isLocalServerConnected) || !isLocal ? new Promise((resolve, reject) => {
const request = {};
if (authed) {
const sId = getCookie(sessionIdKey);
@ -297,11 +313,11 @@ export function apiFetch(path: string, authed: boolean = false): Promise<Respons
fetch(`${apiUrl}/${path}`, request)
.then(response => resolve(response))
.catch(err => reject(err));
});
}) : new Promise(() => {});
}
export function apiPost(path: string, data?: any, contentType: string = "application/json", authed: boolean = false): Promise<Response> {
return new Promise((resolve, reject) => {
return (isLocal && isLocalServerConnected) || !isLocal ? new Promise((resolve, reject) => {
const headers = {
"Accept": contentType,
"Content-Type": contentType,
@ -315,7 +331,7 @@ export function apiPost(path: string, data?: any, contentType: string = "applica
fetch(`${apiUrl}/${path}`, { method: "POST", headers: headers, body: data })
.then(response => resolve(response))
.catch(err => reject(err));
});
}) : new Promise(() => {});
}
export class BooleanHolder {