Compare commits

..

No commits in common. "d34e0dd2c60b4f50456fa33dc19187c1c0cfd609" and "e37b278b4f0a5d9b8d2cb5621cff1057c02cc0f0" have entirely different histories.

42 changed files with 279 additions and 774 deletions

View File

@ -26,7 +26,7 @@ We're using ESLint as our common linter and formatter. It will run automatically
## 🪧 To Do
Check out [Github Issues](https://github.com/pagefaultgames/pokerogue/issues) to see how can you help us!
Check out our [Trello Board](https://trello.com/b/z10B703R/pokerogue-board) to see what we're working on
# 📝 Credits
> If this project contains assets you have produced and you do not see your name here, **please** reach out.

2
package-lock.json generated
View File

@ -38,7 +38,7 @@
"vitest-canvas-mock": "^0.3.3"
},
"engines": {
"node": ">=20.0.0"
"node": ">=18.0.0"
}
},
"node_modules/@ampproject/remapping": {

View File

@ -146,14 +146,14 @@
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 66,
"h": 55
"w": 3,
"h": 3
},
"frame": {
"x": 0,
"y": 112,
"w": 66,
"h": 55
"x": 132,
"y": 0,
"w": 3,
"h": 3
}
},
{

View File

@ -2,12 +2,6 @@ import Move from "./data/move";
/** Alias for all {@linkcode BattleScene} events */
export enum BattleSceneEventType {
/**
* Triggers when the corresponding setting is changed
* @see {@linkcode CandyUpgradeNotificationChangedEvent}
*/
CANDY_UPGRADE_NOTIFICATION_CHANGED = "onCandyUpgradeDisplayChanged",
/**
* Triggers when a move is successfully used
* @see {@linkcode MoveUsedEvent}
@ -30,20 +24,6 @@ export enum BattleSceneEventType {
NEW_ARENA = "onNewArena",
}
/**
* Container class for {@linkcode BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED} events
* @extends Event
*/
export class CandyUpgradeNotificationChangedEvent extends Event {
/** The new value the setting was changed to */
public newValue: number;
constructor(newValue: number) {
super(BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED);
this.newValue = newValue;
}
}
/**
* Container class for {@linkcode BattleSceneEventType.MOVE_USED} events
* @extends Event

View File

@ -93,19 +93,6 @@ export default class BattleScene extends SceneBase {
public showLevelUpStats: boolean = true;
public enableTutorials: boolean = import.meta.env.VITE_BYPASS_TUTORIAL === "1";
public enableRetries: boolean = false;
/**
* Determines the condition for a notification should be shown for Candy Upgrades
* - 0 = 'Off'
* - 1 = 'Passives Only'
* - 2 = 'On'
*/
public candyUpgradeNotification: integer = 0;
/**
* Determines what type of notification is used for Candy Upgrades
* - 0 = 'Icon'
* - 1 = 'Animation'
*/
public candyUpgradeDisplay: integer = 0;
public moneyFormat: MoneyFormat = MoneyFormat.NORMAL;
public uiTheme: UiTheme = UiTheme.DEFAULT;
public windowType: integer = 0;

View File

@ -1573,41 +1573,18 @@ export class PostSummonClearAllyStatsAbAttr extends PostSummonAbAttr {
}
}
/**
* Download raises either the Attack stat or Special Attack stat by one stage depending on the foe's currently lowest defensive stat:
* it will raise Attack if the foe's current Defense is lower than its current Special Defense stat;
* otherwise, it will raise Special Attack.
* @extends PostSummonAbAttr
* @see {applyPostSummon}
*/
export class DownloadAbAttr extends PostSummonAbAttr {
private enemyDef: integer;
private enemySpDef: integer;
private enemyCountTally: integer;
private stats: BattleStat[];
// TODO: Implement the Substitute feature(s) once move is implemented.
/**
* Checks to see if it is the opening turn (starting a new game), if so, Download won't work. This is because Download takes into account
* vitamins and items, so it needs to use the BattleStat and the stat alone.
* @param {Pokemon} pokemon Pokemon that is using the move, as well as seeing the opposing pokemon.
* @param {boolean} passive N/A
* @param {any[]} args N/A
* @returns Returns true if ability is used successful, false if not.
*/
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
this.enemyDef = 0;
this.enemySpDef = 0;
this.enemyCountTally = 0;
if (pokemon.getOpponents()[0].summonData !== undefined) {
for (const opponent of pokemon.getOpponents()) {
this.enemyCountTally++;
this.enemyDef += opponent.getBattleStat(Stat.DEF);
this.enemySpDef += opponent.getBattleStat(Stat.SPDEF);
}
this.enemyDef = Math.round(this.enemyDef / this.enemyCountTally);
this.enemySpDef = Math.round(this.enemySpDef / this.enemyCountTally);
this.enemyDef += opponent.stats[BattleStat.DEF];
this.enemySpDef += opponent.stats[BattleStat.SPDEF];
}
if (this.enemyDef < this.enemySpDef) {
@ -2685,38 +2662,6 @@ export class PreventBerryUseAbAttr extends AbAttr {
}
}
/**
* A Pokemon with this ability heals by a percentage of their maximum hp after eating a berry
* @param healPercent - Percent of Max HP to heal
* @see {@linkcode apply()} for implementation
*/
export class HealFromBerryUseAbAttr extends AbAttr {
/** Percent of Max HP to heal */
private healPercent: number;
constructor(healPercent: number) {
super();
// Clamp healPercent so its between [0,1].
this.healPercent = Math.max(Math.min(healPercent, 1), 0);
}
apply(pokemon: Pokemon, passive: boolean, ...args: [Utils.BooleanHolder, any[]]): boolean {
const { name: abilityName } = passive ? pokemon.getPassiveAbility() : pokemon.getAbility();
pokemon.scene.unshiftPhase(
new PokemonHealPhase(
pokemon.scene,
pokemon.getBattlerIndex(),
Math.max(Math.floor(pokemon.getMaxHp() * this.healPercent), 1),
getPokemonMessage(pokemon, `'s ${abilityName}\nrestored its HP!`),
true
)
);
return true;
}
}
export class RunSuccessAbAttr extends AbAttr {
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
(args[0] as Utils.IntegerHolder).value = 256;
@ -3363,11 +3308,9 @@ export function initAbilities() {
.bypassFaint(),
new Ability(Abilities.VOLT_ABSORB, 3)
.attr(TypeImmunityHealAbAttr, Type.ELECTRIC)
.partial() // Healing not blocked by Heal Block
.ignorable(),
new Ability(Abilities.WATER_ABSORB, 3)
.attr(TypeImmunityHealAbAttr, Type.WATER)
.partial() // Healing not blocked by Heal Block
.ignorable(),
new Ability(Abilities.OBLIVIOUS, 3)
.attr(BattlerTagImmunityAbAttr, BattlerTagType.INFATUATED)
@ -3466,8 +3409,7 @@ export function initAbilities() {
.attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.getMove().hasFlag(MoveFlags.SOUND_BASED))
.ignorable(),
new Ability(Abilities.RAIN_DISH, 3)
.attr(PostWeatherLapseHealAbAttr, 1, WeatherType.RAIN, WeatherType.HEAVY_RAIN)
.partial(), // Healing not blocked by Heal Block
.attr(PostWeatherLapseHealAbAttr, 1, WeatherType.RAIN, WeatherType.HEAVY_RAIN),
new Ability(Abilities.SAND_STREAM, 3)
.attr(PostSummonWeatherChangeAbAttr, WeatherType.SANDSTORM)
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.SANDSTORM),
@ -3588,7 +3530,6 @@ export function initAbilities() {
.attr(PostWeatherLapseHealAbAttr, 2, WeatherType.RAIN, WeatherType.HEAVY_RAIN)
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 1.25)
.attr(TypeImmunityHealAbAttr, Type.WATER)
.partial() // Healing not blocked by Heal Block
.ignorable(),
new Ability(Abilities.DOWNLOAD, 4)
.attr(DownloadAbAttr),
@ -3666,8 +3607,7 @@ export function initAbilities() {
.ignorable(),
new Ability(Abilities.ICE_BODY, 4)
.attr(BlockWeatherDamageAttr, WeatherType.HAIL)
.attr(PostWeatherLapseHealAbAttr, 1, WeatherType.HAIL, WeatherType.SNOW)
.partial(), // Healing not blocked by Heal Block
.attr(PostWeatherLapseHealAbAttr, 1, WeatherType.HAIL, WeatherType.SNOW),
new Ability(Abilities.SOLID_ROCK, 4)
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 0.75)
.ignorable(),
@ -3828,8 +3768,7 @@ export function initAbilities() {
.ignorable()
.unimplemented(),
new Ability(Abilities.CHEEK_POUCH, 6)
.attr(HealFromBerryUseAbAttr, 1/3)
.partial(), // Healing not blocked by Heal Block
.unimplemented(),
new Ability(Abilities.PROTEAN, 6)
.unimplemented(),
new Ability(Abilities.FUR_COAT, 6)
@ -4262,7 +4201,6 @@ export function initAbilities() {
.ignorable(),
new Ability(Abilities.EARTH_EATER, 9)
.attr(TypeImmunityHealAbAttr, Type.GROUND)
.partial() // Healing not blocked by Heal Block
.ignorable(),
new Ability(Abilities.MYCELIUM_MIGHT, 9)
.attr(MoveAbilityBypassAbAttr, (pokemon, move: Move) => move.category === MoveCategory.STATUS)
@ -4276,8 +4214,7 @@ export function initAbilities() {
.attr(PostSummonStatChangeAbAttr, BattleStat.EVA, -1)
.condition(getOncePerBattleCondition(Abilities.SUPERSWEET_SYRUP)),
new Ability(Abilities.HOSPITALITY, 9)
.attr(PostSummonAllyHealAbAttr, 4, true)
.partial(), // Healing not blocked by Heal Block
.attr(PostSummonAllyHealAbAttr, 4, true),
new Ability(Abilities.TOXIC_CHAIN, 9)
.attr(PostAttackApplyStatusEffectAbAttr, false, 30, StatusEffect.TOXIC),
new Ability(Abilities.EMBODY_ASPECT_TEAL, 9)

View File

@ -9,14 +9,14 @@ export interface TrainerTypeMessages {
}
export interface TrainerTypeDialogue {
[key: integer]: TrainerTypeMessages | Array<TrainerTypeMessages>
[key: integer]: TrainerTypeMessages | [TrainerTypeMessages, TrainerTypeMessages]
}
export function getTrainerTypeDialogue(): TrainerTypeDialogue {
return trainerTypeDialogue;
}
export const trainerTypeDialogue: TrainerTypeDialogue = {
export const trainerTypeDialogue = {
[TrainerType.YOUNGSTER]: [
{
encounter: [

View File

@ -12,7 +12,7 @@ import * as Utils from "../utils";
import { WeatherType } from "./weather";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
import { ArenaTagType } from "./enums/arena-tag-type";
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr, HealFromBerryUseAbAttr } from "./ability";
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr } from "./ability";
import { Abilities } from "./enums/abilities";
import { allAbilities } from "./ability";
import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier";
@ -86,10 +86,6 @@ export enum MoveFlags {
WIND_MOVE = 1 << 14,
TRIAGE_MOVE = 1 << 15,
IGNORE_ABILITIES = 1 << 16,
/**
* Enables all hits of a multi-hit move to be accuracy checked individually
*/
CHECK_ALL_HITS = 1 << 17,
}
type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
@ -350,11 +346,6 @@ export default class Move implements Localizable {
return this;
}
checkAllHits(checkAllHits?: boolean): this {
this.setFlag(MoveFlags.CHECK_ALL_HITS, checkAllHits);
return this;
}
checkFlag(flag: MoveFlags, user: Pokemon, target: Pokemon): boolean {
switch (flag) {
case MoveFlags.MAKES_CONTACT:
@ -964,7 +955,8 @@ export enum MultiHitType {
_2,
_2_TO_5,
_3,
_10,
_3_INCR,
_1_TO_10,
BEAT_UP,
}
@ -1295,8 +1287,37 @@ export class MultiHitAttr extends MoveAttr {
case MultiHitType._3:
hitTimes = 3;
break;
case MultiHitType._10:
case MultiHitType._3_INCR:
hitTimes = 3;
// TODO: Add power increase for every hit
break;
case MultiHitType._1_TO_10:
{
const rand = user.randSeedInt(90);
const hitValue = new Utils.IntegerHolder(rand);
applyAbAttrs(MaxMultiHitAbAttr, user, null, hitValue);
if (hitValue.value >= 81) {
hitTimes = 1;
} else if (hitValue.value >= 73) {
hitTimes = 2;
} else if (hitValue.value >= 66) {
hitTimes = 3;
} else if (hitValue.value >= 60) {
hitTimes = 4;
} else if (hitValue.value >= 54) {
hitTimes = 5;
} else if (hitValue.value >= 49) {
hitTimes = 6;
} else if (hitValue.value >= 44) {
hitTimes = 7;
} else if (hitValue.value >= 40) {
hitTimes = 8;
} else if (hitValue.value >= 36) {
hitTimes = 9;
} else {
hitTimes = 10;
}
}
break;
case MultiHitType.BEAT_UP:
const party = user.isPlayer() ? user.scene.getParty() : user.scene.getEnemyParty();
@ -1556,11 +1577,8 @@ export class EatBerryAttr extends MoveEffectAttr {
}
target.scene.updateModifiers(target.isPlayer());
}
this.chosenBerry = undefined;
applyAbAttrs(HealFromBerryUseAbAttr, target, new Utils.BooleanHolder(false));
return true;
}
@ -2730,43 +2748,6 @@ export class WaterShurikenPowerAttr extends VariablePowerAttr {
}
}
/**
* Attribute used for multi-hit moves that increase power in increments of the
* move's base power for each hit, namely Triple Kick and Triple Axel.
* @extends VariablePowerAttr
* @see {@linkcode apply}
*/
export class MultiHitPowerIncrementAttr extends VariablePowerAttr {
/** The max number of base power increments allowed for this move */
private maxHits: integer;
constructor(maxHits: integer) {
super();
this.maxHits = maxHits;
}
/**
* Increases power of move in increments of the base power for the amount of times
* the move hit. In the case that the move is extended, it will circle back to the
* original base power of the move after incrementing past the maximum amount of
* hits.
* @param user {@linkcode Pokemon} that used the move
* @param target {@linkcode Pokemon} that the move was used on
* @param move {@linkcode Move} with this attribute
* @param args [0] {@linkcode Utils.NumberHolder} for final calculated power of move
* @returns true if attribute application succeeds
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const hitsTotal = user.turnData.hitCount - Math.max(user.turnData.hitsLeft, 0);
const power = args[0] as Utils.NumberHolder;
power.value = move.power * (1 + hitsTotal % this.maxHits);
return true;
}
}
export class VariableAtkAttr extends MoveAttr {
constructor() {
super();
@ -5427,9 +5408,12 @@ export function initMoves() {
.attr(SketchAttr)
.ignoresVirtual(),
new AttackMove(Moves.TRIPLE_KICK, Type.FIGHTING, MoveCategory.PHYSICAL, 10, 90, 10, -1, 0, 2)
.attr(MultiHitAttr, MultiHitType._3)
.attr(MultiHitPowerIncrementAttr, 3)
.checkAllHits(),
.attr(MultiHitAttr, MultiHitType._3_INCR)
.attr(MissEffectAttr, (user: Pokemon, move: Move) => {
user.turnData.hitsLeft = 1;
return true;
})
.partial(),
new AttackMove(Moves.THIEF, Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, -1, 0, 2)
.attr(StealHeldItemChanceAttr, 0.3),
new StatusMove(Moves.SPIDER_WEB, Type.BUG, -1, 10, -1, 0, 2)
@ -7281,9 +7265,12 @@ export function initMoves() {
new AttackMove(Moves.FLIP_TURN, Type.WATER, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 8)
.attr(ForceSwitchOutAttr, true, false),
new AttackMove(Moves.TRIPLE_AXEL, Type.ICE, MoveCategory.PHYSICAL, 20, 90, 10, -1, 0, 8)
.attr(MultiHitAttr, MultiHitType._3)
.attr(MultiHitPowerIncrementAttr, 3)
.checkAllHits(),
.attr(MultiHitAttr, MultiHitType._3_INCR)
.attr(MissEffectAttr, (user: Pokemon, move: Move) => {
user.turnData.hitsLeft = 1;
return true;
})
.partial(),
new AttackMove(Moves.DUAL_WINGBEAT, Type.FLYING, MoveCategory.PHYSICAL, 40, 90, 10, -1, 0, 8)
.attr(MultiHitAttr, MultiHitType._2),
new AttackMove(Moves.SCORCHING_SANDS, Type.GROUND, MoveCategory.SPECIAL, 70, 100, 10, 30, 0, 8)
@ -7526,9 +7513,9 @@ export function initMoves() {
new AttackMove(Moves.SPIN_OUT, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, 100, 0, 9)
.attr(StatChangeAttr, BattleStat.SPD, -2, true),
new AttackMove(Moves.POPULATION_BOMB, Type.NORMAL, MoveCategory.PHYSICAL, 20, 90, 10, -1, 0, 9)
.attr(MultiHitAttr, MultiHitType._10)
.attr(MultiHitAttr, MultiHitType._1_TO_10)
.slicingMove()
.checkAllHits(),
.partial(),
new AttackMove(Moves.ICE_SPINNER, Type.ICE, MoveCategory.PHYSICAL, 80, 100, 15, -1, 0, 9)
.attr(ClearTerrainAttr),
new AttackMove(Moves.GLAIVE_RUSH, Type.DRAGON, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 9)

View File

@ -1,4 +1,5 @@
import { Gender } from "./gender";
import { FlinchChanceModifier } from "../modifier/modifier";
import { Moves } from "./enums/moves";
import { PokeballType } from "./pokeball";
import Pokemon from "../field/pokemon";
@ -215,7 +216,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
],
[Species.SLOWPOKE]: [
new SpeciesEvolution(Species.SLOWBRO, 37, null, null),
new SpeciesEvolution(Species.SLOWKING, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => true /* King's Rock */), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.SLOWKING, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => !!p.scene.findModifier(m => (m instanceof FlinchChanceModifier) && (m as FlinchChanceModifier).pokemonId === p.id, true)), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.MAGNEMITE]: [
new SpeciesEvolution(Species.MAGNETON, 30, null, null)
@ -1243,7 +1244,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
],
[Species.POLIWHIRL]: [
new SpeciesEvolution(Species.POLIWRATH, 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG),
new SpeciesEvolution(Species.POLITOED, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => true /* King's Rock */), SpeciesWildEvolutionDelay.VERY_LONG)
new SpeciesEvolution(Species.POLITOED, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => !!p.scene.findModifier(m => (m instanceof FlinchChanceModifier) && (m as FlinchChanceModifier).pokemonId === p.id, true)), SpeciesWildEvolutionDelay.VERY_LONG)
],
[Species.WEEPINBELL]: [
new SpeciesEvolution(Species.VICTREEBEL, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)

View File

@ -1,4 +1,4 @@
import Phaser from "phaser";
import Phaser, {Time} from "phaser";
import * as Utils from "./utils";
import {initTouchControls} from "./touch-controls";
import pad_generic from "./configs/pad_generic";
@ -6,7 +6,6 @@ import pad_unlicensedSNES from "./configs/pad_unlicensedSNES";
import pad_xbox360 from "./configs/pad_xbox360";
import pad_dualshock from "./configs/pad_dualshock";
import {Button} from "./enums/buttons";
import BattleScene from "./battle-scene";
export interface GamepadMapping {
[key: string]: number;
@ -48,17 +47,16 @@ const repeatInputDelayMillis = 250;
*/
export class InputsController {
private buttonKeys: Phaser.Input.Keyboard.Key[][];
private gamepads: Phaser.Input.Gamepad.Gamepad[] = new Array();
private scene: BattleScene;
private gamepads: Array<string> = new Array();
private scene: Phaser.Scene;
private buttonLock: Button;
private buttonLock2: Button;
private interactions: Map<Button, Map<string, boolean>> = new Map();
private time: Phaser.Time.Clock;
private player: GamepadMapping;
private time: Time;
private player: Map<String, GamepadMapping> = new Map();
private gamepadSupport: boolean = true;
public events: Phaser.Events.EventEmitter;
/**
* Initializes a new instance of the game control system, setting up initial state and configurations.
@ -71,7 +69,7 @@ export class InputsController {
* Specific buttons like MENU and STATS are set not to repeat their actions.
* It concludes by calling the `init` method to complete the setup.
*/
constructor(scene: BattleScene) {
constructor(scene: Phaser.Scene) {
this.scene = scene;
this.time = this.scene.time;
this.buttonKeys = [];
@ -110,6 +108,7 @@ export class InputsController {
}, this);
// Check to see if the gamepad has already been setup by the browser
this.scene.input.gamepad.refreshPads();
if (this.scene.input.gamepad.total) {
this.refreshGamepads();
for (const thisGamepad of this.gamepads) {
@ -202,7 +201,7 @@ export class InputsController {
setupGamepad(thisGamepad: Phaser.Input.Gamepad.Gamepad): void {
const gamepadID = thisGamepad.id.toLowerCase();
const mappedPad = this.mapGamepad(gamepadID);
this.player = mappedPad.gamepadMapping;
this.player["mapping"] = mappedPad.gamepadMapping;
}
/**
@ -237,26 +236,26 @@ export class InputsController {
*/
getActionGamepadMapping(): ActionGamepadMapping {
const gamepadMapping = {};
if (!this?.player) {
if (!this.player?.mapping) {
return gamepadMapping;
}
gamepadMapping[this.player.LC_N] = Button.UP;
gamepadMapping[this.player.LC_S] = Button.DOWN;
gamepadMapping[this.player.LC_W] = Button.LEFT;
gamepadMapping[this.player.LC_E] = Button.RIGHT;
gamepadMapping[this.player.TOUCH] = Button.SUBMIT;
gamepadMapping[this.player.RC_S] = this.scene.abSwapped ? Button.CANCEL : Button.ACTION;
gamepadMapping[this.player.RC_E] = this.scene.abSwapped ? Button.ACTION : Button.CANCEL;
gamepadMapping[this.player.SELECT] = Button.STATS;
gamepadMapping[this.player.START] = Button.MENU;
gamepadMapping[this.player.RB] = Button.CYCLE_SHINY;
gamepadMapping[this.player.LB] = Button.CYCLE_FORM;
gamepadMapping[this.player.LT] = Button.CYCLE_GENDER;
gamepadMapping[this.player.RT] = Button.CYCLE_ABILITY;
gamepadMapping[this.player.RC_W] = Button.CYCLE_NATURE;
gamepadMapping[this.player.RC_N] = Button.CYCLE_VARIANT;
gamepadMapping[this.player.LS] = Button.SPEED_UP;
gamepadMapping[this.player.RS] = Button.SLOW_DOWN;
gamepadMapping[this.player.mapping.LC_N] = Button.UP;
gamepadMapping[this.player.mapping.LC_S] = Button.DOWN;
gamepadMapping[this.player.mapping.LC_W] = Button.LEFT;
gamepadMapping[this.player.mapping.LC_E] = Button.RIGHT;
gamepadMapping[this.player.mapping.TOUCH] = Button.SUBMIT;
gamepadMapping[this.player.mapping.RC_S] = this.scene.abSwapped ? Button.CANCEL : Button.ACTION;
gamepadMapping[this.player.mapping.RC_E] = this.scene.abSwapped ? Button.ACTION : Button.CANCEL;
gamepadMapping[this.player.mapping.SELECT] = Button.STATS;
gamepadMapping[this.player.mapping.START] = Button.MENU;
gamepadMapping[this.player.mapping.RB] = Button.CYCLE_SHINY;
gamepadMapping[this.player.mapping.LB] = Button.CYCLE_FORM;
gamepadMapping[this.player.mapping.LT] = Button.CYCLE_GENDER;
gamepadMapping[this.player.mapping.RT] = Button.CYCLE_ABILITY;
gamepadMapping[this.player.mapping.RC_W] = Button.CYCLE_NATURE;
gamepadMapping[this.player.mapping.RC_N] = Button.CYCLE_VARIANT;
gamepadMapping[this.player.mapping.LS] = Button.SPEED_UP;
gamepadMapping[this.player.mapping.RS] = Button.SLOW_DOWN;
return gamepadMapping;
}

View File

@ -1635,7 +1635,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
"encounter": {
1: `Ich habe mich entschieden, erneut meinen Hut in den Ring zu werfen.
$Komm jetzt... Zeig mir die Früchte deines Trainings.`,
},
"victory": {
1: "Ich freue mich auf Neuigkeiten über all deine Erfolge!"
},
@ -1643,6 +1642,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "Was ist los? Das ist doch nicht alles, oder?"
}
},
},
"nemona": {
"encounter": {
1: "Yesss! Ich bin so aufgeregt! Zeit, dass wir uns austoben!"
@ -2337,7 +2337,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
};
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
// Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

@ -11,7 +11,6 @@ export const menu: SimpleTranslationEntries = {
"dailyRun": "Täglicher Run (Beta)",
"loadGame": "Spiel laden",
"newGame": "Neues Spiel",
"settings": "Einstellungen",
"selectGameMode": "Wähle einen Spielmodus",
"logInOrCreateAccount": "Melde dich an oder erstelle einen Account zum starten. Keine Email nötig!",
"username": "Benutzername",

View File

@ -14,8 +14,7 @@ export const tutorial: SimpleTranslationEntries = {
$Dort kannst du u. A. die Spielgeschwin-\ndigkeit und das Fensterdesign ändern.
$Das Menü verbirgt noch andere Funktionen - probier' sie gerne aus!`,
"starterSelect": `In diesem Bildschirm kannst du mit Z oder Leertaste deine\nStarter auswählen.
$Sie begleiten dich am Anfang deines Abenteuers.
"starterSelect": `Hier kannst du deine Starter-Pokémon auswählen.\nSie begleiten dich am Anfang deines Abenteuers.
$Jeder Starter hat einen Preis. Dein Team kann bis zu sechs\nMitglieder haben, solange der Gesamtpreis max. 10 beträgt.
$Du kannst Geschlecht, Fähigkeit und Form beliebig auswählen,\nsobald du sie mindestens einmal gefangen hast.
$Die DVs ergeben sich aus den Höchstwerten aller Pokémon,\ndie du bereits gefangen hast.

View File

@ -1595,7 +1595,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
"encounter": {
1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`,
},
"victory": {
1: "I eagerly await news of all your achievements!"
},
@ -1603,6 +1602,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "What's the matter? This isn't all, is it?"
}
},
},
"nemona": {
"encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!"
@ -2278,7 +2278,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
// Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

@ -11,7 +11,6 @@ export const menu: SimpleTranslationEntries = {
"dailyRun": "Daily Run (Beta)",
"loadGame": "Load Game",
"newGame": "New Game",
"settings": "Settings",
"selectGameMode": "Select a game mode.",
"logInOrCreateAccount": "Log in or create an account to start. No email required!",
"username": "Username",

View File

@ -12,7 +12,7 @@ export const tutorial: SimpleTranslationEntries = {
$From the settings you can change game speed, window style, and other options.
$There are also various other features here, so be sure to check them all!`,
"starterSelect": `From this screen, you can select your starters by pressing\nZ or the Space bar. These are your initial party members.
"starterSelect": `From this screen, you can select your starters.\nThese are your initial party members.
$Each starter has a value. Your party can have up to\n6 members as long as the total does not exceed 10.
$You can also select gender, ability, and form depending on\nthe variants you've caught or hatched.
$The IVs for a species are also the best of every one you've\ncaught or hatched, so try to get lots of the same species!`,

View File

@ -3,8 +3,8 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const battle: SimpleTranslationEntries = {
"bossAppeared": "¡{{bossName}} te corta el paso!",
"trainerAppeared": "¡{{trainerName}}\nte desafía!",
"trainerAppearedDouble": "¡{{trainerName}}\nwould te desafían!",
"trainerSendOut": "¡{{trainerName}} saca a\n{{pokemonName}}!",
"trainerAppearedDouble": "{{trainerName}}\nwould like to battle!",
"trainerSendOut": "{{trainerName}} sent out\n{{pokemonName}}!",
"singleWildAppeared": "¡Un {{pokemonName}} salvaje te corta el paso!",
"multiWildAppeared": "¡Un {{pokemonName1}} y un {{pokemonName2}} salvajes\nte cortan el paso!",
"playerComeBack": "¡{{pokemonName}}, ven aquí!",
@ -13,9 +13,9 @@ export const battle: SimpleTranslationEntries = {
"trainerGo": "¡{{trainerName}} saca a {{pokemonName}}!",
"switchQuestion": "¿Quieres cambiar a\n{{pokemonName}}?",
"trainerDefeated": "¡Has derrotado a\n{{trainerName}}!",
"moneyWon": "¡Has ganado\n₽{{moneyAmount}} por vencer!",
"moneyWon": "You got\n₽{{moneyAmount}} for winning!",
"pokemonCaught": "¡{{pokemonName}} atrapado!",
"partyFull": "Tu equipo esta completo.\n¿Quieres liberar un Pokémon para meter a {{pokemonName}}?",
"partyFull": "Your party is full.\nRelease a Pokémon to make room for {{pokemonName}}?",
"pokemon": "Pokémon",
"sendOutPokemon": "¡Adelante, {{pokemonName}}!",
"hitResultCriticalHit": "!Un golpe crítico!",
@ -39,7 +39,7 @@ export const battle: SimpleTranslationEntries = {
"learnMoveAnd": "Y…",
"levelCapUp": "¡Se ha incrementado el\nnivel máximo a {{levelCap}}!",
"moveNotImplemented": "{{moveName}} aún no está implementado y no se puede seleccionar.",
"moveNoPP": "¡No hay suficientes PP\npara este movimiento!",
"moveNoPP": "There's no PP left for\nthis move!",
"moveDisabled": "!No puede usar {{moveName}} porque ha sido anulado!",
"noPokeballForce": "Una fuerza misteriosa\nte impide usar Poké Balls.",
"noPokeballTrainer": "¡No puedes atrapar a los\nPokémon de los demás!",

View File

@ -1,40 +1,40 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const biome: SimpleTranslationEntries = {
"unknownLocation": "En algún lugar que no puedes recordar",
"TOWN": "Ciudad",
"PLAINS": "Valle",
"GRASS": "Campo",
"TALL_GRASS": "Pradera de Hierba Alta",
"METROPOLIS": "Metrópolis",
"FOREST": "Bosque",
"SEA": "Mar",
"SWAMP": "Pantano",
"BEACH": "Playa",
"LAKE": "Lago",
"SEABED": "Fondo del mar",
"MOUNTAIN": "Montaña",
"unknownLocation": "Somewhere you can\'t remember",
"TOWN": "Town",
"PLAINS": "Plains",
"GRASS": "Grassy Field",
"TALL_GRASS": "Tall Grass",
"METROPOLIS": "Metropolis",
"FOREST": "Forest",
"SEA": "Sea",
"SWAMP": "Swamp",
"BEACH": "Beach",
"LAKE": "Lake",
"SEABED": "Seabed",
"MOUNTAIN": "Mountain",
"BADLANDS": "Badlands",
"CAVE": "Cueva",
"DESERT": "Desierto",
"ICE_CAVE": "Cueva Helada",
"MEADOW": "Prado",
"POWER_PLANT": "Central Eléctrica",
"VOLCANO": "Volcán",
"GRAVEYARD": "Cementerio",
"CAVE": "Cave",
"DESERT": "Desert",
"ICE_CAVE": "Ice Cave",
"MEADOW": "Meadow",
"POWER_PLANT": "Power Plant",
"VOLCANO": "Volcano",
"GRAVEYARD": "Graveyard",
"DOJO": "Dojo",
"FACTORY": "Fábrica",
"RUINS": "Ruinas Antiguas",
"WASTELAND": "Páramo",
"ABYSS": "Abismo",
"SPACE": "Espacio",
"CONSTRUCTION_SITE": "Obra",
"JUNGLE": "Jungla",
"FAIRY_CAVE": "Cueva de Hadas",
"TEMPLE": "Templo",
"SLUM": "Suburbio",
"SNOWY_FOREST": "Bosque nevado",
"ISLAND": "Isla",
"LABORATORY": "Laboratorio",
"FACTORY": "Factory",
"RUINS": "Ancient Ruins",
"WASTELAND": "Wasteland",
"ABYSS": "Abyss",
"SPACE": "Space",
"CONSTRUCTION_SITE": "Construction Site",
"JUNGLE": "Jungle",
"FAIRY_CAVE": "Fairy Cave",
"TEMPLE": "Temple",
"SLUM": "Slum",
"SNOWY_FOREST": "Snowy Forest",
"ISLAND": "Island",
"LABORATORY": "Laboratory",
"END": "???",
} as const;

View File

@ -1595,7 +1595,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
"encounter": {
1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`,
},
"victory": {
1: "I eagerly await news of all your achievements!"
},
@ -1603,6 +1602,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "What's the matter? This isn't all, is it?"
}
},
},
"nemona": {
"encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!"
@ -2278,7 +2278,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
// Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

@ -11,7 +11,6 @@ export const menu: SimpleTranslationEntries = {
"dailyRun": "Reto diario (Beta)",
"loadGame": "Cargar partida",
"newGame": "Nueva partida",
"settings": "Settings",
"selectGameMode": "Elige un modo de juego.",
"logInOrCreateAccount": "Inicia sesión o crea una cuenta para empezar. ¡No se requiere correo electrónico!",
"username": "Usuario",

View File

@ -2,17 +2,17 @@ import {SimpleTranslationEntries} from "#app/plugins/i18n";
// Titles of special trainers like gym leaders, elite four, and the champion
export const titles: SimpleTranslationEntries = {
"elite_four": "Alto Mando",
"elite_four_female": "Alto Mando",
"gym_leader": "Líder de gimnasio",
"gym_leader_female": "Líder de gimnasio",
"gym_leader_double": "Líderes de Gimnasio",
"champion": "Campeón",
"champion_female": "Campeona",
"champion_double": "Campeones",
"elite_four": "Elite Four",
"elite_four_female": "Elite Four",
"gym_leader": "Gym Leader",
"gym_leader_female": "Gym Leader",
"gym_leader_double": "Gym Leader Duo",
"champion": "Champion",
"champion_female": "Champion",
"champion_double": "Champion Duo",
"rival": "Rival",
"professor": "Profesor",
"frontier_brain": "As del Frente Batalla",
"professor": "Professor",
"frontier_brain": "Frontier Brain",
// Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc.
} as const;

View File

@ -1595,7 +1595,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
"encounter": {
1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`,
},
"victory": {
1: "I eagerly await news of all your achievements!"
},
@ -1603,6 +1602,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "What's the matter? This isn't all, is it?"
}
},
},
"nemona": {
"encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!"
@ -3873,7 +3873,6 @@ export const PGFdialogue: DialogueTranslationEntries = {
"encounter": {
1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`,
},
"victory": {
1: "I eagerly await news of all your achievements!"
},
@ -3881,6 +3880,7 @@ export const PGFdialogue: DialogueTranslationEntries = {
1: "What's the matter? This isn't all, is it?"
}
},
},
"nemona": {
"encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!"

View File

@ -6,7 +6,6 @@ export const menu: SimpleTranslationEntries = {
"dailyRun": "Défi du jour (Bêta)",
"loadGame": "Charger la partie",
"newGame": "Nouvelle partie",
"settings": "Paramètres",
"selectGameMode": "Sélectionnez un mode de jeu.",
"logInOrCreateAccount": "Connectez-vous ou créez un compte pour commencer. Aucun e-mail requis !",
"username": "Nom dutilisateur",

View File

@ -16,7 +16,7 @@ export const tutorial: SimpleTranslationEntries = {
$Il y a également toute une variété dautres fonctionnalités,
$jetez-y un œil !`,
"starterSelect": `Choisissez vos starters depuis cet écran avec Z ou Espace.\nIls formeront votre équipe de départ.
"starterSelect": `Choisissez vos starters depuis cet écran.\nIls formeront votre équipe de départ.
$Chacun possède une valeur. Votre équipe peut avoir jusquà\n6 membres, tant que vous ne dépassez pas un cout de 10.
$Vous pouvez aussi choisir le sexe, le talent et la forme en\nfonction des variants déjà capturés ou éclos.
$Les IVs dun starter sont les meilleurs de tous ceux de son\nespèce déjà obtenus. Essayez donc den obtenir plusieurs !`,

View File

@ -1595,7 +1595,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
"encounter": {
1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`,
},
"victory": {
1: "I eagerly await news of all your achievements!"
},
@ -1603,6 +1602,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "What's the matter? This isn't all, is it?"
}
},
},
"nemona": {
"encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!"
@ -2278,7 +2278,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
// Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

@ -10,7 +10,6 @@ export const menu: SimpleTranslationEntries = {
"continue": "Continua",
"newGame": "Nuova Partita",
"loadGame": "Carica Partita",
"settings": "Settings",
"dailyRun": "Corsa Giornaliera (Beta)",
"selectGameMode": "Seleziona una modalità di gioco.",
"logInOrCreateAccount": "Accedi o crea un nuovo account per iniziare. Non è richiesta un'email!",

View File

@ -1595,7 +1595,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
"encounter": {
1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`,
},
"victory": {
1: "I eagerly await news of all your achievements!"
},
@ -1603,6 +1602,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "What's the matter? This isn't all, is it?"
}
},
},
"nemona": {
"encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!"
@ -2278,7 +2278,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
// Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

@ -11,7 +11,6 @@ export const menu: SimpleTranslationEntries = {
"dailyRun": "Desafio Diário (Beta)",
"loadGame": "Carregar Jogo",
"newGame": "Novo Jogo",
"settings": "Configurações",
"selectGameMode": "Escolha um modo de jogo.",
"logInOrCreateAccount": "Inicie uma sessão ou crie uma conta para começar. Não é necessário email!",
"username": "Nome de Usuário",

View File

@ -18,8 +18,7 @@ export const tutorial: SimpleTranslationEntries = {
$Existem também vários outros recursos disponíveis aqui.
$Não deixe de conferir todos eles!`,
"starterSelect": `Aqui você pode escolher seus iniciais apertando a tecla Z ou\na Barra de Espaço.
$Esses serão os primeiro Pokémon da sua equipe.
"starterSelect": `Aqui você pode escolher seus iniciais.\nEsses serão os primeiro Pokémon da sua equipe.
$Cada inicial tem seu custo. Sua equipe pode ter até 6\nmembros, desde que a soma dos custos não ultrapasse 10.
$Você pode escolher o gênero, a habilidade\ne até a forma do seu inicial.
$Essas opções dependem das variantes dessa\nespécie que você capturou ou chocou.

View File

@ -1595,7 +1595,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
"encounter": {
1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`,
},
"victory": {
1: "I eagerly await news of all your achievements!"
},
@ -1603,6 +1602,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "What's the matter? This isn't all, is it?"
}
},
},
"nemona": {
"encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!"
@ -2278,7 +2278,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
// Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

@ -11,7 +11,6 @@ export const menu: SimpleTranslationEntries = {
"dailyRun": "每日挑战 (Beta)",
"loadGame": "加载游戏",
"newGame": "新游戏",
"settings": "设置",
"selectGameMode": "选择一个游戏模式",
"logInOrCreateAccount": "登录或创建账户以开始游戏。无需邮箱!",
"username": "用户名",

View File

@ -13,7 +13,7 @@ export const tutorial: SimpleTranslationEntries = {
$在设置中\n和其他选项
$这里还有各种其他功能`,
"starterSelect": `在此页面中,您可以通过按Z或空格键选择\n您的初始宝可梦。这些是您最初的队伍成员。
"starterSelect": `在此页面中,您可以选择您的初始宝可梦。\n这些是您最初的队伍成员。
$每个初始宝可梦都有一个费用值\n最多可以拥有6名成员10
$您还可以根据您捕获或孵化的变种选择性别\n
$一个物种个体值是您捕获或孵化的所有宝可\n梦中最好的`,

View File

@ -1595,7 +1595,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
"encounter": {
1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`,
},
"victory": {
1: "I eagerly await news of all your achievements!"
},
@ -1603,6 +1602,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
1: "What's the matter? This isn't all, is it?"
}
},
},
"nemona": {
"encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!"
@ -2278,7 +2278,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
// Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

@ -11,7 +11,6 @@ export const menu: SimpleTranslationEntries = {
"dailyRun": "每日挑戰 (Beta)",
"loadGame": "加載遊戲",
"newGame": "新遊戲",
"settings": "Settings",
"selectGameMode": "選擇遊戲模式",
"logInOrCreateAccount": "登入或註冊即可開始遊戲,無需郵箱!",
"username": "用戶名",

View File

@ -5,6 +5,7 @@ import { version } from "../package.json";
import UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin";
import BBCodeTextPlugin from "phaser3-rex-plugins/plugins/bbcodetext-plugin";
import InputTextPlugin from "phaser3-rex-plugins/plugins/inputtext-plugin.js";
import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
import TransitionImagePackPlugin from "phaser3-rex-plugins/templates/transitionimagepack/transitionimagepack-plugin.js";
import { LoadingScene } from "./loading-scene";
@ -71,82 +72,23 @@ const config: Phaser.Types.Core.GameConfig = {
version: version
};
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
const setPositionRelative = function (guideObject: any, x: number, y: number) {
if (guideObject && guideObject instanceof Phaser.GameObjects.GameObject) {
const offsetX = guideObject.width * (-0.5 + (0.5 - guideObject.originX));
const offsetY = guideObject.height * (-0.5 + (0.5 - guideObject.originY));
this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y);
};
return;
}
declare module "phaser" {
namespace GameObjects {
interface Container {
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface Sprite {
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface Image {
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface NineSlice {
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface Text {
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
interface Rectangle {
/**
* Sets this object's position relative to another object with a given offset
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
* @param x The relative x position
* @param y The relative y position
*/
setPositionRelative(guideObject: any, x: number, y: number): void;
}
}
}
this.setPosition(x, y);
};
Phaser.GameObjects.Container.prototype.setPositionRelative = setPositionRelative;
Phaser.GameObjects.Sprite.prototype.setPositionRelative = setPositionRelative;
Phaser.GameObjects.Image.prototype.setPositionRelative = setPositionRelative;
Phaser.GameObjects.NineSlice.prototype.setPositionRelative = setPositionRelative;
Phaser.GameObjects.Text.prototype.setPositionRelative = setPositionRelative;
BBCodeText.prototype.setPositionRelative = setPositionRelative;
Phaser.GameObjects.Rectangle.prototype.setPositionRelative = setPositionRelative;
document.fonts.load("16px emerald").then(() => document.fonts.load("10px pkmnems"));

View File

@ -30,7 +30,7 @@ import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, get
import { TempBattleStat } from "./data/temp-battle-stat";
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
import { ArenaTagType } from "./data/enums/arena-tag-type";
import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, IgnoreOpponentEvasionAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, BlockRedirectAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr, MaxMultiHitAbAttr, HealFromBerryUseAbAttr } from "./data/ability";
import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, IgnoreOpponentEvasionAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, BlockRedirectAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr } from "./data/ability";
import { Unlockables, getUnlockableName } from "./system/unlockables";
import { getBiomeKey } from "./field/arena";
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
@ -262,14 +262,6 @@ export class TitlePhase extends Phase {
return true;
},
keepOpen: true
},
{
label: i18next.t("menu:settings"),
handler: () => {
this.scene.ui.setOverlayMode(Mode.SETTINGS);
return true;
},
keepOpen: true
});
const config: OptionSelectConfig = {
options: options,
@ -1023,6 +1015,7 @@ export class EncounterPhase extends BattlePhase {
}
}
}
handleTutorial(this.scene, Tutorial.Access_Menu).then(() => super.end());
}
@ -2228,9 +2221,7 @@ export class BerryPhase extends FieldPhase {
if (cancelled.value) {
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is too\nnervous to eat berries!"));
} else {
this.scene.unshiftPhase(
new CommonAnimPhase(this.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM)
);
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM));
for (const berryModifier of this.scene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon) as BerryModifier[]) {
if (berryModifier.consumed) {
@ -2243,8 +2234,6 @@ export class BerryPhase extends FieldPhase {
}
this.scene.updateModifiers(pokemon.isPlayer());
applyAbAttrs(HealFromBerryUseAbAttr, pokemon, new Utils.BooleanHolder(false));
}
}
});
@ -2833,14 +2822,10 @@ export class MoveEffectPhase extends PokemonPhase {
const user = this.getUserPokemon();
// Hit check only calculated on first hit for multi-hit moves unless flag is set to check all hits.
// However, if an ability with the MaxMultiHitAbAttr, namely Skill Link, is present, act as a normal
// multi-hit move and proceed with all hits
// Hit check only calculated on first hit for multi-hit moves
if (user.turnData.hitsLeft < user.turnData.hitCount) {
if (!this.move.getMove().hasFlag(MoveFlags.CHECK_ALL_HITS) || user.hasAbilityWithAttr(MaxMultiHitAbAttr)) {
return true;
}
}
if (user.hasAbilityWithAttr(AlwaysHitAbAttr) || target.hasAbilityWithAttr(AlwaysHitAbAttr)) {
return true;

View File

@ -65,14 +65,19 @@ export interface DialogueTranslationEntry {
}
export interface DialogueTranslationCategory {
[category: string]: DialogueTranslationEntry;
encounter: DialogueTranslationEntry;
victory: DialogueTranslationEntry;
defeat?: DialogueTranslationEntry;
}
export interface DialogueTranslationTrainerClass {
[key: string]: DialogueTranslationCategory;
}
export interface DialogueTranslationEntries {
[trainertype: string]: DialogueTranslationCategory;
[key: string]: DialogueTranslationTrainerClass;
}
export interface Localizable {
localize(): void;
}

View File

@ -19,34 +19,28 @@ export function initGameSpeed() {
const originalAddEvent = this.time.addEvent;
this.time.addEvent = function (config: Phaser.Time.TimerEvent | Phaser.Types.Time.TimerEventConfig) {
if (!(config instanceof Phaser.Time.TimerEvent) && config.delay) {
if (config.delay) {
config.delay = transformValue(config.delay);
}
return originalAddEvent.apply(this, [ config ]);
};
const originalTweensAdd = this.tweens.add;
this.tweens.add = function (config: Phaser.Types.Tweens.TweenBuilderConfig | Phaser.Types.Tweens.TweenChainBuilderConfig | Phaser.Tweens.Tween | Phaser.Tweens.TweenChain) {
if (config.loopDelay) {
config.loopDelay = transformValue(config.loopDelay as number);
}
if (!(config instanceof Phaser.Tweens.TweenChain) ) {
if (config.duration) {
config.duration = transformValue(config.duration);
}
if (!(config instanceof Phaser.Tweens.Tween)) {
if (config.delay) {
config.delay = transformValue(config.delay as number);
config.delay = transformValue(config.delay);
}
if (config.repeatDelay) {
config.repeatDelay = transformValue(config.repeatDelay);
}
if (config.loopDelay) {
config.loopDelay = transformValue(config.loopDelay);
}
if (config.hold) {
config.hold = transformValue(config.hold);
}
}
}
return originalTweensAdd.apply(this, [ config ]);
};
const originalTweensChain = this.tweens.chain;
@ -57,13 +51,13 @@ export function initGameSpeed() {
t.duration = transformValue(t.duration);
}
if (t.delay) {
t.delay = transformValue(t.delay as number);
t.delay = transformValue(t.delay);
}
if (t.repeatDelay) {
t.repeatDelay = transformValue(t.repeatDelay);
}
if (t.loopDelay) {
t.loopDelay = transformValue(t.loopDelay as number);
t.loopDelay = transformValue(t.loopDelay);
}
if (t.hold) {
t.hold = transformValue(t.hold);
@ -84,7 +78,7 @@ export function initGameSpeed() {
config.repeatDelay = transformValue(config.repeatDelay);
}
if (config.loopDelay) {
config.loopDelay = transformValue(config.loopDelay as number);
config.loopDelay = transformValue(config.loopDelay);
}
if (config.hold) {
config.hold = transformValue(config.hold);

View File

@ -5,7 +5,6 @@ import BattleScene from "../battle-scene";
import { hasTouchscreen } from "../touch-controls";
import { updateWindowType } from "../ui/ui-theme";
import { PlayerGender } from "./game-data";
import { CandyUpgradeNotificationChangedEvent } from "#app/battle-scene-events.js";
import { MoneyFormat } from "../enums/money-format";
export enum Setting {
@ -19,8 +18,6 @@ export enum Setting {
Window_Type = "WINDOW_TYPE",
Tutorials = "TUTORIALS",
Enable_Retries = "ENABLE_RETRIES",
Candy_Upgrade_Notification = "CANDY_UPGRADE_NOTIFICATION",
Candy_Upgrade_Display = "CANDY_UPGRADE_DISPLAY",
Money_Format = "MONEY_FORMAT",
Sprite_Set = "SPRITE_SET",
Move_Animations = "MOVE_ANIMATIONS",
@ -55,8 +52,6 @@ export const settingOptions: SettingOptions = {
[Setting.Window_Type]: new Array(5).fill(null).map((_, i) => (i + 1).toString()),
[Setting.Tutorials]: ["Off", "On"],
[Setting.Enable_Retries]: ["Off", "On"],
[Setting.Candy_Upgrade_Notification]: ["Off", "Passives Only", "On"],
[Setting.Candy_Upgrade_Display]: ["Icon", "Animation"],
[Setting.Money_Format]: ["Normal", "Abbreviated"],
[Setting.Sprite_Set]: ["Consistent", "Mixed Animated"],
[Setting.Move_Animations]: ["Off", "On"],
@ -83,8 +78,6 @@ export const settingDefaults: SettingDefaults = {
[Setting.Window_Type]: 0,
[Setting.Tutorials]: 1,
[Setting.Enable_Retries]: 0,
[Setting.Candy_Upgrade_Notification]: 0,
[Setting.Candy_Upgrade_Display]: 0,
[Setting.Money_Format]: 0,
[Setting.Sprite_Set]: 0,
[Setting.Move_Animations]: 1,
@ -100,7 +93,7 @@ export const settingDefaults: SettingDefaults = {
[Setting.Vibration]: 0
};
export const reloadSettings: Setting[] = [Setting.UI_Theme, Setting.Language, Setting.Sprite_Set, Setting.Candy_Upgrade_Display];
export const reloadSettings: Setting[] = [Setting.UI_Theme, Setting.Language, Setting.Sprite_Set];
export function setSetting(scene: BattleScene, setting: Setting, value: integer): boolean {
switch (setting) {
@ -134,16 +127,6 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer)
case Setting.Enable_Retries:
scene.enableRetries = settingOptions[setting][value] === "On";
break;
case Setting.Candy_Upgrade_Notification:
if (scene.candyUpgradeNotification === value) {
break;
}
scene.candyUpgradeNotification = value;
scene.eventTarget.dispatchEvent(new CandyUpgradeNotificationChangedEvent(value));
break;
case Setting.Candy_Upgrade_Display:
scene.candyUpgradeDisplay = value;
case Setting.Money_Format:
switch (settingOptions[setting][value]) {
case "Normal":

View File

@ -3,8 +3,6 @@ export const keysDown = new Map();
let lastTouchedId;
export function initTouchControls(buttonMap) {
const dpadDiv = document.querySelector("#dpad");
preventElementZoom(dpadDiv);
for (const button of document.querySelectorAll("[data-key]")) {
// @ts-ignore
bindKey(button, button.dataset.key, buttonMap);
@ -117,26 +115,3 @@ function bindKey(node, key, buttonMap) {
}
});
}
/**
* {@link https://stackoverflow.com/a/39778831/4622620|Source}
*
* Prevent zoom on specified element
* @param {HTMLElement} element
*/
function preventElementZoom(element) {
element.addEventListener("touchstart", (event) => {
const currentTouchTimeStamp = event.timeStamp;
const previousTouchTimeStamp = event.currentTarget.dataset.lastTouchTimeStamp || currentTouchTimeStamp;
const timeStampDifference = currentTouchTimeStamp - previousTouchTimeStamp;
const fingers = event.touches.length;
event.currentTarget.dataset.lastTouchTimeStamp = currentTouchTimeStamp;
if (!timeStampDifference || timeStampDifference > 500 || fingers > 1) {
return;
} // not double-tap
event.preventDefault();
event.target.click();
});
}

View File

@ -1,4 +1,3 @@
import { BattleSceneEventType, CandyUpgradeNotificationChangedEvent } from "#app/battle-scene-events.js";
import { pokemonPrevolutions } from "#app/data/pokemon-evolutions";
import { Variant, getVariantTint } from "#app/data/variant";
import { argbFromRgba } from "@material/material-color-utilities";
@ -104,29 +103,6 @@ function getValueReductionCandyCounts(baseValue: integer): [integer, integer] {
return starterCandyCosts[baseValue - 1].costReduction;
}
/**
* Calculates the icon position for a Pokemon of a given UI index
* @param index UI index to calculate the icon position of
* @returns An interface with an x and y property
*/
function calcIconPosition(index: number): {x: number, y: number} {
const x = (index % 9) * 18;
const y = Math.floor(index / 9) * 18;
return {x: x, y: y};
}
/**
* Calculates the {@linkcode Phaser.GameObjects.Sprite} position for a Pokemon of a given UI index
* @param index UI index to calculate the icon position of
* @returns An interface with an x and y property
*/
function calcSpritePosition(index: number): {x: number, y: number} {
const position = calcIconPosition(index);
return {x: position.x - 2, y: position.y + 2};
}
const gens = [
i18next.t("starterSelectUiHandler:gen1"),
i18next.t("starterSelectUiHandler:gen2"),
@ -226,8 +202,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
private shinyIcons: Phaser.GameObjects.Image[][];
private hiddenAbilityIcons: Phaser.GameObjects.Image[];
private classicWinIcons: Phaser.GameObjects.Image[];
private candyUpgradeIcon: Phaser.GameObjects.Image[];
private candyUpgradeOverlayIcon: Phaser.GameObjects.Image[];
private iconAnimHandler: PokemonIconAnimHandler;
@ -418,8 +392,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.genSpecies[g].push(species);
const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true);
const defaultProps = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
const position = calcIconPosition(s);
const icon = this.scene.add.sprite(position.x - 2, position.y + 2, species.getIconAtlasKey(defaultProps.formIndex, defaultProps.shiny, defaultProps.variant));
const x = (s % 9) * 18;
const y = Math.floor(s / 9) * 18;
const icon = this.scene.add.sprite(x - 2, y + 2, species.getIconAtlasKey(defaultProps.formIndex, defaultProps.shiny, defaultProps.variant));
icon.setScale(0.5);
icon.setOrigin(0, 0);
icon.setFrame(species.getIconId(defaultProps.female, defaultProps.formIndex, defaultProps.shiny, defaultProps.variant));
@ -442,8 +417,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
});
this.starterValueLabels = new Array(81).fill(null).map((_, i) => {
const position = calcIconPosition(i);
const ret = addTextObject(this.scene, position.x + 152, position.y + 11, "0", TextStyle.WINDOW, { fontSize: "32px" });
const x = (i % 9) * 18;
const y = Math.floor(i / 9) * 18;
const ret = addTextObject(this.scene, x + 152, y + 11, "0", TextStyle.WINDOW, { fontSize: "32px" });
ret.setShadowOffset(2, 2);
ret.setOrigin(0, 0);
ret.setVisible(false);
@ -452,8 +428,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
});
const getShinyStar = (i: integer, v: integer): Phaser.GameObjects.Image => {
const position = calcIconPosition(i);
const ret = this.scene.add.image((position.x - v * 3) + 163, position.y + 11, "shiny_star_small");
const x = (i % 9) * 18 - v * 3;
const y = Math.floor(i / 9) * 18;
const ret = this.scene.add.image(x + 163, y + 11, "shiny_star_small");
ret.setOrigin(0, 0);
ret.setScale(0.5);
ret.setVisible(false);
@ -466,8 +443,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
});
this.hiddenAbilityIcons = new Array(81).fill(null).map((_, i) => {
const position = calcIconPosition(i);
const ret = this.scene.add.image(position.x + 163, position.y + 16, "ha_capsule");
const x = (i % 9) * 18;
const y = Math.floor(i / 9) * 18;
const ret = this.scene.add.image(x + 163, y + 16, "ha_capsule");
ret.setOrigin(0, 0);
ret.setScale(0.5);
ret.setVisible(false);
@ -476,8 +454,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
});
this.classicWinIcons = new Array(81).fill(null).map((_, i) => {
const position = calcIconPosition(i);
const ret = this.scene.add.image(position.x + 153, position.y + 21, "champion_ribbon");
const x = (i % 9) * 18;
const y = Math.floor(i / 9) * 18;
const ret = this.scene.add.image(x + 153, y + 21, "champion_ribbon");
ret.setOrigin(0, 0);
ret.setScale(0.5);
ret.setVisible(false);
@ -485,26 +464,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
return ret;
});
this.candyUpgradeIcon = new Array(81).fill(null).map((_, i) => {
const position = calcIconPosition(i);
const ret = this.scene.add.image(position.x + 163, position.y + 21, "candy");
ret.setOrigin(0, 0);
ret.setScale(0.25);
ret.setVisible(false);
this.starterSelectContainer.add(ret);
return ret;
});
this.candyUpgradeOverlayIcon = new Array(81).fill(null).map((_, i) => {
const position = calcIconPosition(i);
const ret = this.scene.add.image(position.x + 163, position.y + 21, "candy_overlay");
ret.setOrigin(0, 0);
ret.setScale(0.25);
ret.setVisible(false);
this.starterSelectContainer.add(ret);
return ret;
});
this.pokemonSprite = this.scene.add.sprite(53, 63, "pkmn__sub");
this.pokemonSprite.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true });
this.starterSelectContainer.add(this.pokemonSprite);
@ -694,14 +653,25 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.starterSelectContainer.add(this.statsContainer);
this.scene.eventTarget.addEventListener(BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED, (e) => this.onCandyUpgradeDisplayChanged(e));
this.updateInstructions();
}
show(args: any[]): boolean {
if (args.length >= 2 && args[0] instanceof Function && typeof args[1] === "number") {
super.show(args);
for (let g = 0; g < this.genSpecies.length; g++) {
this.genSpecies[g].forEach((species, s) => {
const dexEntry = this.scene.gameData.dexData[species.speciesId];
const icon = this.starterSelectGenIconContainers[g].getAt(s) as Phaser.GameObjects.Sprite;
if (dexEntry.caughtAttr) {
icon.clearTint();
} else if (dexEntry.seenAttr) {
icon.setTint(0x808080);
}
});
}
this.starterSelectCallback = args[0] as StarterSelectCallback;
this.starterSelectContainer.setVisible(true);
@ -714,21 +684,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.setCursor(0);
this.tryUpdateValue(0);
for (let g = 0; g < this.genSpecies.length; g++) {
this.genSpecies[g].forEach((species, s) => {
const icon = this.starterSelectGenIconContainers[g].getAt(s) as Phaser.GameObjects.Sprite;
const dexEntry = this.scene.gameData.dexData[species.speciesId];
if (dexEntry.caughtAttr) {
icon.clearTint();
} else if (dexEntry.seenAttr) {
icon.setTint(0x808080);
}
this.setUpgradeAnimation(icon, species);
});
}
handleTutorial(this.scene, Tutorial.Starter_Select);
return true;
@ -751,161 +706,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.starterSelectMessageBoxContainer.setVisible(!!text?.length);
}
/**
* Determines if 'Icon' based upgrade notifications should be shown
* @returns true if upgrade notifications are enabled and set to display an 'Icon'
*/
isUpgradeIconEnabled(): boolean {
return this.scene.candyUpgradeNotification !== 0 && this.scene.candyUpgradeDisplay === 0;
}
/**
* Determines if 'Animation' based upgrade notifications should be shown
* @returns true if upgrade notifications are enabled and set to display an 'Animation'
*/
isUpgradeAnimationEnabled(): boolean {
return this.scene.candyUpgradeNotification !== 0 && this.scene.candyUpgradeDisplay === 1;
}
/**
* Determines if a passive upgrade is available for the given species ID
* @param speciesId The ID of the species to check the passive of
* @returns true if the user has enough candies and a passive has not been unlocked already
*/
isPassiveAvailable(speciesId: number): boolean {
// Get this species ID's starter data
const starterData = this.scene.gameData.starterData[speciesId];
return starterData.candyCount >= getPassiveCandyCount(speciesStarters[speciesId])
&& !(starterData.passiveAttr & PassiveAttr.UNLOCKED);
}
/**
* Determines if a value reduction upgrade is available for the given species ID
* @param speciesId The ID of the species to check the value reduction of
* @returns true if the user has enough candies and all value reductions have not been unlocked already
*/
isValueReductionAvailable(speciesId: number): boolean {
// Get this species ID's starter data
const starterData = this.scene.gameData.starterData[speciesId];
return starterData.candyCount >= getValueReductionCandyCounts(speciesStarters[speciesId])[starterData.valueReduction]
&& starterData.valueReduction < 2;
}
/**
* Sets a bounce animation if enabled and the Pokemon has an upgrade
* @param icon {@linkcode Phaser.GameObjects.GameObject} to animate
* @param species {@linkcode PokemonSpecies} of the icon used to check for upgrades
* @param startPaused Should this animation be paused after it is added?
*/
setUpgradeAnimation(icon: Phaser.GameObjects.Sprite, species: PokemonSpecies, startPaused: boolean = false): void {
this.scene.tweens.killTweensOf(icon);
// Skip animations if they are disabled
if (this.scene.candyUpgradeDisplay === 0 || species.speciesId !== species.getRootSpeciesId(false)) {
return;
}
const position = calcSpritePosition(this.genSpecies[species.generation - 1].indexOf(species));
icon.y = position.y;
const tweenChain: Phaser.Types.Tweens.TweenChainBuilderConfig = {
targets: icon,
loop: -1,
// Make the initial bounce a little randomly delayed
delay: Utils.randIntRange(0, 50) * 5,
loopDelay: 1000,
tweens: [
{
targets: icon,
y: position.y - 5,
duration: Utils.fixedInt(125),
ease: "Cubic.easeOut",
yoyo: true
},
{
targets: icon,
y: position.y - 3,
duration: Utils.fixedInt(150),
ease: "Cubic.easeOut",
yoyo: true
}
],};
const passiveAvailable = this.isPassiveAvailable(species.speciesId);
// 'Only Passives' mode
if (this.scene.candyUpgradeNotification === 1) {
if (passiveAvailable) {
this.scene.tweens.chain(tweenChain).paused = startPaused;
}
// 'On' mode
} else if (this.scene.candyUpgradeNotification === 2) {
if (passiveAvailable || this.isValueReductionAvailable(species.speciesId)) {
this.scene.tweens.chain(tweenChain).paused = startPaused;
}
}
}
/**
* Sets the visibility of a Candy Upgrade Icon given an index
* @param index The UI index of the icon within this generation container
*/
setUpgradeIcon(index: number): void {
const species = this.genSpecies[this.getGenCursorWithScroll()][index];
const slotVisible = !!species?.speciesId;
if (!species // No Pokemon exists at that UI index
|| this.scene.candyUpgradeNotification === 0 // Notification setting is 'Off'
|| species.speciesId !== species.getRootSpeciesId(false)) { // Pokemon is not the base evolution and can't use candy
// Set all icons as hidden and exit early
this.candyUpgradeIcon[index].setVisible(false);
this.candyUpgradeOverlayIcon[index].setVisible(false);
return;
}
const passiveAvailable = this.isPassiveAvailable(species.speciesId);
// 'Only Passive Unlocks' mode
if (this.scene.candyUpgradeNotification === 1) {
this.candyUpgradeIcon[index].setVisible(slotVisible && passiveAvailable);
this.candyUpgradeOverlayIcon[index].setVisible(slotVisible && this.candyUpgradeIcon[index].visible);
// 'On' mode
} else if (this.scene.candyUpgradeNotification === 2) {
this.candyUpgradeIcon[index].setVisible(
slotVisible && ( passiveAvailable || this.isValueReductionAvailable(species.speciesId)));
this.candyUpgradeOverlayIcon[index].setVisible(slotVisible && this.candyUpgradeIcon[index].visible);
}
}
/**
* Processes an {@linkcode CandyUpgradeNotificationChangedEvent} sent when the corresponding setting changes
* @param event {@linkcode Event} sent by the callback
*/
onCandyUpgradeDisplayChanged(event: Event): void {
const candyUpgradeDisplayEvent = event as CandyUpgradeNotificationChangedEvent;
if (!candyUpgradeDisplayEvent) {
return;
}
// Loop through all visible candy icons when set to 'Icon' mode
if (this.scene.candyUpgradeDisplay === 0) {
this.genSpecies[this.getGenCursorWithScroll()].forEach((_species, s) => {
this.setUpgradeIcon(s);
});
return;
}
// Loop through all animations when set to 'Animation' mode
for (let g = 0; g < this.genSpecies.length; g++) {
this.genSpecies[g].forEach((species, s) => {
const icon = this.starterSelectGenIconContainers[g].getAt(s) as Phaser.GameObjects.Sprite;
this.setUpgradeAnimation(icon, species);
});
}
}
processInput(button: Button): boolean {
if (this.blockInput) {
return false;
@ -1148,16 +948,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
});
ui.setMode(Mode.STARTER_SELECT);
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, undefined);
// Update the candy upgrade display
if (this.isUpgradeIconEnabled() ) {
this.setUpgradeIcon(this.cursor);
}
if (this.isUpgradeAnimationEnabled()) {
const genSpecies = this.genSpecies[this.lastSpecies.generation - 1];
this.setUpgradeAnimation(this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(genSpecies.indexOf(this.lastSpecies)), this.lastSpecies, true);
}
return true;
}
return false;
@ -1185,18 +975,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.tryUpdateValue(0);
ui.setMode(Mode.STARTER_SELECT);
this.scene.playSound("buy");
// If the notification setting is set to 'On', update the candy upgrade display
if (this.scene.candyUpgradeNotification === 2) {
if (this.isUpgradeIconEnabled() ) {
this.setUpgradeIcon(this.cursor);
}
if (this.isUpgradeAnimationEnabled()) {
const genSpecies = this.genSpecies[this.lastSpecies.generation - 1];
this.setUpgradeAnimation(this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(genSpecies.indexOf(this.lastSpecies)), this.lastSpecies, true);
}
}
return true;
}
return false;
@ -1515,24 +1293,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}
this.hiddenAbilityIcons[s].setVisible(slotVisible && !!this.scene.gameData.dexData[speciesId].caughtAttr && !!(this.scene.gameData.starterData[speciesId].abilityAttr & 4));
this.classicWinIcons[s].setVisible(slotVisible && this.scene.gameData.starterData[speciesId].classicWinCount > 0);
// 'Candy Icon' mode
if (this.scene.candyUpgradeDisplay === 0) {
if (!starterColors[speciesId]) {
// Default to white if no colors are found
starterColors[speciesId] = [ "ffffff", "ffffff" ];
}
// Set the candy colors
this.candyUpgradeIcon[s].setTint(argbFromRgba(Utils.rgbHexToRgba(starterColors[speciesId][0])));
this.candyUpgradeOverlayIcon[s].setTint(argbFromRgba(Utils.rgbHexToRgba(starterColors[speciesId][1])));
this.setUpgradeIcon(s);
} else if (this.scene.candyUpgradeDisplay === 1) {
this.candyUpgradeIcon[s].setVisible(false);
this.candyUpgradeOverlayIcon[s].setVisible(false);
}
}
} else {
changed = super.setCursor(cursor);
@ -1610,11 +1370,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
lastSpeciesIcon.setTexture(this.lastSpecies.getIconAtlasKey(props.formIndex, props.shiny, props.variant), this.lastSpecies.getIconId(props.female, props.formIndex, props.shiny, props.variant));
this.checkIconId(lastSpeciesIcon, this.lastSpecies, props.female, props.formIndex, props.shiny, props.variant);
this.iconAnimHandler.addOrUpdate(lastSpeciesIcon, PokemonIconAnimMode.NONE);
// Resume the animation for the previously selected species
const speciesIndex = this.genSpecies[this.lastSpecies.generation - 1].indexOf(this.lastSpecies);
const icon = this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(speciesIndex) as Phaser.GameObjects.Sprite;
this.scene.tweens.getTweensOf(icon).forEach(tween => tween.resume());
}
this.lastSpecies = species;
@ -1679,22 +1434,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonCandyDarknessOverlay.setCrop(0,0,16, candyCropY);
}
// Pause the animation when the species is selected
const speciesIndex = this.genSpecies[species.generation - 1].indexOf(species);
const icon = this.starterSelectGenIconContainers[species.generation - 1].getAt(speciesIndex) as Phaser.GameObjects.Sprite;
if (this.isUpgradeAnimationEnabled()) {
this.scene.tweens.getTweensOf(icon).forEach(tween => tween.pause());
// Reset the position of the icon
const position = calcSpritePosition(speciesIndex);
icon.x = position.x;
icon.y = position.y;
}
// Initiates the small up and down idle animation
this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.PASSIVE);
this.iconAnimHandler.addOrUpdate(this.starterSelectGenIconContainers[species.generation - 1].getAt(this.genSpecies[species.generation - 1].indexOf(species)) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.PASSIVE);
let starterIndex = -1;

View File

@ -38,7 +38,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
this.titleContainer.add(this.dailyRunScoreboard);
this.playerCountLabel = addTextObject(this.scene, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - 109, `? ${i18next.t("menu:playersOnline")}`, TextStyle.MESSAGE, { fontSize: "54px" });
this.playerCountLabel = addTextObject(this.scene, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - 90, `? ${i18next.t("menu:playersOnline")}`, TextStyle.MESSAGE, { fontSize: "54px" });
this.playerCountLabel.setOrigin(1, 0);
this.titleContainer.add(this.playerCountLabel);