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 ## 🪧 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 # 📝 Credits
> If this project contains assets you have produced and you do not see your name here, **please** reach out. > 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" "vitest-canvas-mock": "^0.3.3"
}, },
"engines": { "engines": {
"node": ">=20.0.0" "node": ">=18.0.0"
} }
}, },
"node_modules/@ampproject/remapping": { "node_modules/@ampproject/remapping": {

View File

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

View File

@ -2,12 +2,6 @@ import Move from "./data/move";
/** Alias for all {@linkcode BattleScene} events */ /** Alias for all {@linkcode BattleScene} events */
export enum BattleSceneEventType { 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 * Triggers when a move is successfully used
* @see {@linkcode MoveUsedEvent} * @see {@linkcode MoveUsedEvent}
@ -30,20 +24,6 @@ export enum BattleSceneEventType {
NEW_ARENA = "onNewArena", 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 * Container class for {@linkcode BattleSceneEventType.MOVE_USED} events
* @extends Event * @extends Event

View File

@ -93,19 +93,6 @@ export default class BattleScene extends SceneBase {
public showLevelUpStats: boolean = true; public showLevelUpStats: boolean = true;
public enableTutorials: boolean = import.meta.env.VITE_BYPASS_TUTORIAL === "1"; public enableTutorials: boolean = import.meta.env.VITE_BYPASS_TUTORIAL === "1";
public enableRetries: boolean = false; 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 moneyFormat: MoneyFormat = MoneyFormat.NORMAL;
public uiTheme: UiTheme = UiTheme.DEFAULT; public uiTheme: UiTheme = UiTheme.DEFAULT;
public windowType: integer = 0; 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 { export class DownloadAbAttr extends PostSummonAbAttr {
private enemyDef: integer; private enemyDef: integer;
private enemySpDef: integer; private enemySpDef: integer;
private enemyCountTally: integer;
private stats: BattleStat[]; 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 { applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
this.enemyDef = 0; this.enemyDef = 0;
this.enemySpDef = 0; this.enemySpDef = 0;
this.enemyCountTally = 0;
if (pokemon.getOpponents()[0].summonData !== undefined) {
for (const opponent of pokemon.getOpponents()) { for (const opponent of pokemon.getOpponents()) {
this.enemyCountTally++; this.enemyDef += opponent.stats[BattleStat.DEF];
this.enemyDef += opponent.getBattleStat(Stat.DEF); this.enemySpDef += opponent.stats[BattleStat.SPDEF];
this.enemySpDef += opponent.getBattleStat(Stat.SPDEF);
}
this.enemyDef = Math.round(this.enemyDef / this.enemyCountTally);
this.enemySpDef = Math.round(this.enemySpDef / this.enemyCountTally);
} }
if (this.enemyDef < this.enemySpDef) { 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 { export class RunSuccessAbAttr extends AbAttr {
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
(args[0] as Utils.IntegerHolder).value = 256; (args[0] as Utils.IntegerHolder).value = 256;
@ -3363,11 +3308,9 @@ export function initAbilities() {
.bypassFaint(), .bypassFaint(),
new Ability(Abilities.VOLT_ABSORB, 3) new Ability(Abilities.VOLT_ABSORB, 3)
.attr(TypeImmunityHealAbAttr, Type.ELECTRIC) .attr(TypeImmunityHealAbAttr, Type.ELECTRIC)
.partial() // Healing not blocked by Heal Block
.ignorable(), .ignorable(),
new Ability(Abilities.WATER_ABSORB, 3) new Ability(Abilities.WATER_ABSORB, 3)
.attr(TypeImmunityHealAbAttr, Type.WATER) .attr(TypeImmunityHealAbAttr, Type.WATER)
.partial() // Healing not blocked by Heal Block
.ignorable(), .ignorable(),
new Ability(Abilities.OBLIVIOUS, 3) new Ability(Abilities.OBLIVIOUS, 3)
.attr(BattlerTagImmunityAbAttr, BattlerTagType.INFATUATED) .attr(BattlerTagImmunityAbAttr, BattlerTagType.INFATUATED)
@ -3466,8 +3409,7 @@ export function initAbilities() {
.attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.getMove().hasFlag(MoveFlags.SOUND_BASED)) .attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.getMove().hasFlag(MoveFlags.SOUND_BASED))
.ignorable(), .ignorable(),
new Ability(Abilities.RAIN_DISH, 3) new Ability(Abilities.RAIN_DISH, 3)
.attr(PostWeatherLapseHealAbAttr, 1, WeatherType.RAIN, WeatherType.HEAVY_RAIN) .attr(PostWeatherLapseHealAbAttr, 1, WeatherType.RAIN, WeatherType.HEAVY_RAIN),
.partial(), // Healing not blocked by Heal Block
new Ability(Abilities.SAND_STREAM, 3) new Ability(Abilities.SAND_STREAM, 3)
.attr(PostSummonWeatherChangeAbAttr, WeatherType.SANDSTORM) .attr(PostSummonWeatherChangeAbAttr, WeatherType.SANDSTORM)
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.SANDSTORM), .attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.SANDSTORM),
@ -3588,7 +3530,6 @@ export function initAbilities() {
.attr(PostWeatherLapseHealAbAttr, 2, WeatherType.RAIN, WeatherType.HEAVY_RAIN) .attr(PostWeatherLapseHealAbAttr, 2, WeatherType.RAIN, WeatherType.HEAVY_RAIN)
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 1.25) .attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 1.25)
.attr(TypeImmunityHealAbAttr, Type.WATER) .attr(TypeImmunityHealAbAttr, Type.WATER)
.partial() // Healing not blocked by Heal Block
.ignorable(), .ignorable(),
new Ability(Abilities.DOWNLOAD, 4) new Ability(Abilities.DOWNLOAD, 4)
.attr(DownloadAbAttr), .attr(DownloadAbAttr),
@ -3666,8 +3607,7 @@ export function initAbilities() {
.ignorable(), .ignorable(),
new Ability(Abilities.ICE_BODY, 4) new Ability(Abilities.ICE_BODY, 4)
.attr(BlockWeatherDamageAttr, WeatherType.HAIL) .attr(BlockWeatherDamageAttr, WeatherType.HAIL)
.attr(PostWeatherLapseHealAbAttr, 1, WeatherType.HAIL, WeatherType.SNOW) .attr(PostWeatherLapseHealAbAttr, 1, WeatherType.HAIL, WeatherType.SNOW),
.partial(), // Healing not blocked by Heal Block
new Ability(Abilities.SOLID_ROCK, 4) new Ability(Abilities.SOLID_ROCK, 4)
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 0.75) .attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 0.75)
.ignorable(), .ignorable(),
@ -3828,8 +3768,7 @@ export function initAbilities() {
.ignorable() .ignorable()
.unimplemented(), .unimplemented(),
new Ability(Abilities.CHEEK_POUCH, 6) new Ability(Abilities.CHEEK_POUCH, 6)
.attr(HealFromBerryUseAbAttr, 1/3) .unimplemented(),
.partial(), // Healing not blocked by Heal Block
new Ability(Abilities.PROTEAN, 6) new Ability(Abilities.PROTEAN, 6)
.unimplemented(), .unimplemented(),
new Ability(Abilities.FUR_COAT, 6) new Ability(Abilities.FUR_COAT, 6)
@ -4262,7 +4201,6 @@ export function initAbilities() {
.ignorable(), .ignorable(),
new Ability(Abilities.EARTH_EATER, 9) new Ability(Abilities.EARTH_EATER, 9)
.attr(TypeImmunityHealAbAttr, Type.GROUND) .attr(TypeImmunityHealAbAttr, Type.GROUND)
.partial() // Healing not blocked by Heal Block
.ignorable(), .ignorable(),
new Ability(Abilities.MYCELIUM_MIGHT, 9) new Ability(Abilities.MYCELIUM_MIGHT, 9)
.attr(MoveAbilityBypassAbAttr, (pokemon, move: Move) => move.category === MoveCategory.STATUS) .attr(MoveAbilityBypassAbAttr, (pokemon, move: Move) => move.category === MoveCategory.STATUS)
@ -4276,8 +4214,7 @@ export function initAbilities() {
.attr(PostSummonStatChangeAbAttr, BattleStat.EVA, -1) .attr(PostSummonStatChangeAbAttr, BattleStat.EVA, -1)
.condition(getOncePerBattleCondition(Abilities.SUPERSWEET_SYRUP)), .condition(getOncePerBattleCondition(Abilities.SUPERSWEET_SYRUP)),
new Ability(Abilities.HOSPITALITY, 9) new Ability(Abilities.HOSPITALITY, 9)
.attr(PostSummonAllyHealAbAttr, 4, true) .attr(PostSummonAllyHealAbAttr, 4, true),
.partial(), // Healing not blocked by Heal Block
new Ability(Abilities.TOXIC_CHAIN, 9) new Ability(Abilities.TOXIC_CHAIN, 9)
.attr(PostAttackApplyStatusEffectAbAttr, false, 30, StatusEffect.TOXIC), .attr(PostAttackApplyStatusEffectAbAttr, false, 30, StatusEffect.TOXIC),
new Ability(Abilities.EMBODY_ASPECT_TEAL, 9) new Ability(Abilities.EMBODY_ASPECT_TEAL, 9)

View File

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

View File

@ -12,7 +12,7 @@ import * as Utils from "../utils";
import { WeatherType } from "./weather"; import { WeatherType } from "./weather";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
import { ArenaTagType } from "./enums/arena-tag-type"; 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 { Abilities } from "./enums/abilities";
import { allAbilities } from "./ability"; import { allAbilities } from "./ability";
import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier"; import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier";
@ -86,10 +86,6 @@ export enum MoveFlags {
WIND_MOVE = 1 << 14, WIND_MOVE = 1 << 14,
TRIAGE_MOVE = 1 << 15, TRIAGE_MOVE = 1 << 15,
IGNORE_ABILITIES = 1 << 16, 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; type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
@ -350,11 +346,6 @@ export default class Move implements Localizable {
return this; return this;
} }
checkAllHits(checkAllHits?: boolean): this {
this.setFlag(MoveFlags.CHECK_ALL_HITS, checkAllHits);
return this;
}
checkFlag(flag: MoveFlags, user: Pokemon, target: Pokemon): boolean { checkFlag(flag: MoveFlags, user: Pokemon, target: Pokemon): boolean {
switch (flag) { switch (flag) {
case MoveFlags.MAKES_CONTACT: case MoveFlags.MAKES_CONTACT:
@ -964,7 +955,8 @@ export enum MultiHitType {
_2, _2,
_2_TO_5, _2_TO_5,
_3, _3,
_10, _3_INCR,
_1_TO_10,
BEAT_UP, BEAT_UP,
} }
@ -1295,8 +1287,37 @@ export class MultiHitAttr extends MoveAttr {
case MultiHitType._3: case MultiHitType._3:
hitTimes = 3; hitTimes = 3;
break; 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; hitTimes = 10;
}
}
break; break;
case MultiHitType.BEAT_UP: case MultiHitType.BEAT_UP:
const party = user.isPlayer() ? user.scene.getParty() : user.scene.getEnemyParty(); const party = user.isPlayer() ? user.scene.getParty() : user.scene.getEnemyParty();
@ -1556,11 +1577,8 @@ export class EatBerryAttr extends MoveEffectAttr {
} }
target.scene.updateModifiers(target.isPlayer()); target.scene.updateModifiers(target.isPlayer());
} }
this.chosenBerry = undefined; this.chosenBerry = undefined;
applyAbAttrs(HealFromBerryUseAbAttr, target, new Utils.BooleanHolder(false));
return true; 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 { export class VariableAtkAttr extends MoveAttr {
constructor() { constructor() {
super(); super();
@ -5427,9 +5408,12 @@ export function initMoves() {
.attr(SketchAttr) .attr(SketchAttr)
.ignoresVirtual(), .ignoresVirtual(),
new AttackMove(Moves.TRIPLE_KICK, Type.FIGHTING, MoveCategory.PHYSICAL, 10, 90, 10, -1, 0, 2) new AttackMove(Moves.TRIPLE_KICK, Type.FIGHTING, MoveCategory.PHYSICAL, 10, 90, 10, -1, 0, 2)
.attr(MultiHitAttr, MultiHitType._3) .attr(MultiHitAttr, MultiHitType._3_INCR)
.attr(MultiHitPowerIncrementAttr, 3) .attr(MissEffectAttr, (user: Pokemon, move: Move) => {
.checkAllHits(), user.turnData.hitsLeft = 1;
return true;
})
.partial(),
new AttackMove(Moves.THIEF, Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, -1, 0, 2) new AttackMove(Moves.THIEF, Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, -1, 0, 2)
.attr(StealHeldItemChanceAttr, 0.3), .attr(StealHeldItemChanceAttr, 0.3),
new StatusMove(Moves.SPIDER_WEB, Type.BUG, -1, 10, -1, 0, 2) 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) new AttackMove(Moves.FLIP_TURN, Type.WATER, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 8)
.attr(ForceSwitchOutAttr, true, false), .attr(ForceSwitchOutAttr, true, false),
new AttackMove(Moves.TRIPLE_AXEL, Type.ICE, MoveCategory.PHYSICAL, 20, 90, 10, -1, 0, 8) new AttackMove(Moves.TRIPLE_AXEL, Type.ICE, MoveCategory.PHYSICAL, 20, 90, 10, -1, 0, 8)
.attr(MultiHitAttr, MultiHitType._3) .attr(MultiHitAttr, MultiHitType._3_INCR)
.attr(MultiHitPowerIncrementAttr, 3) .attr(MissEffectAttr, (user: Pokemon, move: Move) => {
.checkAllHits(), user.turnData.hitsLeft = 1;
return true;
})
.partial(),
new AttackMove(Moves.DUAL_WINGBEAT, Type.FLYING, MoveCategory.PHYSICAL, 40, 90, 10, -1, 0, 8) new AttackMove(Moves.DUAL_WINGBEAT, Type.FLYING, MoveCategory.PHYSICAL, 40, 90, 10, -1, 0, 8)
.attr(MultiHitAttr, MultiHitType._2), .attr(MultiHitAttr, MultiHitType._2),
new AttackMove(Moves.SCORCHING_SANDS, Type.GROUND, MoveCategory.SPECIAL, 70, 100, 10, 30, 0, 8) 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) new AttackMove(Moves.SPIN_OUT, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, 100, 0, 9)
.attr(StatChangeAttr, BattleStat.SPD, -2, true), .attr(StatChangeAttr, BattleStat.SPD, -2, true),
new AttackMove(Moves.POPULATION_BOMB, Type.NORMAL, MoveCategory.PHYSICAL, 20, 90, 10, -1, 0, 9) 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() .slicingMove()
.checkAllHits(), .partial(),
new AttackMove(Moves.ICE_SPINNER, Type.ICE, MoveCategory.PHYSICAL, 80, 100, 15, -1, 0, 9) new AttackMove(Moves.ICE_SPINNER, Type.ICE, MoveCategory.PHYSICAL, 80, 100, 15, -1, 0, 9)
.attr(ClearTerrainAttr), .attr(ClearTerrainAttr),
new AttackMove(Moves.GLAIVE_RUSH, Type.DRAGON, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 9) 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 { Gender } from "./gender";
import { FlinchChanceModifier } from "../modifier/modifier";
import { Moves } from "./enums/moves"; import { Moves } from "./enums/moves";
import { PokeballType } from "./pokeball"; import { PokeballType } from "./pokeball";
import Pokemon from "../field/pokemon"; import Pokemon from "../field/pokemon";
@ -215,7 +216,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
], ],
[Species.SLOWPOKE]: [ [Species.SLOWPOKE]: [
new SpeciesEvolution(Species.SLOWBRO, 37, null, null), 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]: [ [Species.MAGNEMITE]: [
new SpeciesEvolution(Species.MAGNETON, 30, null, null) new SpeciesEvolution(Species.MAGNETON, 30, null, null)
@ -1243,7 +1244,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
], ],
[Species.POLIWHIRL]: [ [Species.POLIWHIRL]: [
new SpeciesEvolution(Species.POLIWRATH, 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG), 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]: [ [Species.WEEPINBELL]: [
new SpeciesEvolution(Species.VICTREEBEL, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG) 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 * as Utils from "./utils";
import {initTouchControls} from "./touch-controls"; import {initTouchControls} from "./touch-controls";
import pad_generic from "./configs/pad_generic"; 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_xbox360 from "./configs/pad_xbox360";
import pad_dualshock from "./configs/pad_dualshock"; import pad_dualshock from "./configs/pad_dualshock";
import {Button} from "./enums/buttons"; import {Button} from "./enums/buttons";
import BattleScene from "./battle-scene";
export interface GamepadMapping { export interface GamepadMapping {
[key: string]: number; [key: string]: number;
@ -48,17 +47,16 @@ const repeatInputDelayMillis = 250;
*/ */
export class InputsController { export class InputsController {
private buttonKeys: Phaser.Input.Keyboard.Key[][]; private buttonKeys: Phaser.Input.Keyboard.Key[][];
private gamepads: Phaser.Input.Gamepad.Gamepad[] = new Array(); private gamepads: Array<string> = new Array();
private scene: BattleScene; private scene: Phaser.Scene;
private buttonLock: Button; private buttonLock: Button;
private buttonLock2: Button; private buttonLock2: Button;
private interactions: Map<Button, Map<string, boolean>> = new Map(); private interactions: Map<Button, Map<string, boolean>> = new Map();
private time: Phaser.Time.Clock; private time: Time;
private player: GamepadMapping; private player: Map<String, GamepadMapping> = new Map();
private gamepadSupport: boolean = true; private gamepadSupport: boolean = true;
public events: Phaser.Events.EventEmitter;
/** /**
* Initializes a new instance of the game control system, setting up initial state and configurations. * 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. * Specific buttons like MENU and STATS are set not to repeat their actions.
* It concludes by calling the `init` method to complete the setup. * It concludes by calling the `init` method to complete the setup.
*/ */
constructor(scene: BattleScene) { constructor(scene: Phaser.Scene) {
this.scene = scene; this.scene = scene;
this.time = this.scene.time; this.time = this.scene.time;
this.buttonKeys = []; this.buttonKeys = [];
@ -110,6 +108,7 @@ export class InputsController {
}, this); }, this);
// Check to see if the gamepad has already been setup by the browser // Check to see if the gamepad has already been setup by the browser
this.scene.input.gamepad.refreshPads();
if (this.scene.input.gamepad.total) { if (this.scene.input.gamepad.total) {
this.refreshGamepads(); this.refreshGamepads();
for (const thisGamepad of this.gamepads) { for (const thisGamepad of this.gamepads) {
@ -202,7 +201,7 @@ export class InputsController {
setupGamepad(thisGamepad: Phaser.Input.Gamepad.Gamepad): void { setupGamepad(thisGamepad: Phaser.Input.Gamepad.Gamepad): void {
const gamepadID = thisGamepad.id.toLowerCase(); const gamepadID = thisGamepad.id.toLowerCase();
const mappedPad = this.mapGamepad(gamepadID); const mappedPad = this.mapGamepad(gamepadID);
this.player = mappedPad.gamepadMapping; this.player["mapping"] = mappedPad.gamepadMapping;
} }
/** /**
@ -237,26 +236,26 @@ export class InputsController {
*/ */
getActionGamepadMapping(): ActionGamepadMapping { getActionGamepadMapping(): ActionGamepadMapping {
const gamepadMapping = {}; const gamepadMapping = {};
if (!this?.player) { if (!this.player?.mapping) {
return gamepadMapping; return gamepadMapping;
} }
gamepadMapping[this.player.LC_N] = Button.UP; gamepadMapping[this.player.mapping.LC_N] = Button.UP;
gamepadMapping[this.player.LC_S] = Button.DOWN; gamepadMapping[this.player.mapping.LC_S] = Button.DOWN;
gamepadMapping[this.player.LC_W] = Button.LEFT; gamepadMapping[this.player.mapping.LC_W] = Button.LEFT;
gamepadMapping[this.player.LC_E] = Button.RIGHT; gamepadMapping[this.player.mapping.LC_E] = Button.RIGHT;
gamepadMapping[this.player.TOUCH] = Button.SUBMIT; gamepadMapping[this.player.mapping.TOUCH] = Button.SUBMIT;
gamepadMapping[this.player.RC_S] = this.scene.abSwapped ? Button.CANCEL : Button.ACTION; gamepadMapping[this.player.mapping.RC_S] = this.scene.abSwapped ? Button.CANCEL : Button.ACTION;
gamepadMapping[this.player.RC_E] = this.scene.abSwapped ? Button.ACTION : Button.CANCEL; gamepadMapping[this.player.mapping.RC_E] = this.scene.abSwapped ? Button.ACTION : Button.CANCEL;
gamepadMapping[this.player.SELECT] = Button.STATS; gamepadMapping[this.player.mapping.SELECT] = Button.STATS;
gamepadMapping[this.player.START] = Button.MENU; gamepadMapping[this.player.mapping.START] = Button.MENU;
gamepadMapping[this.player.RB] = Button.CYCLE_SHINY; gamepadMapping[this.player.mapping.RB] = Button.CYCLE_SHINY;
gamepadMapping[this.player.LB] = Button.CYCLE_FORM; gamepadMapping[this.player.mapping.LB] = Button.CYCLE_FORM;
gamepadMapping[this.player.LT] = Button.CYCLE_GENDER; gamepadMapping[this.player.mapping.LT] = Button.CYCLE_GENDER;
gamepadMapping[this.player.RT] = Button.CYCLE_ABILITY; gamepadMapping[this.player.mapping.RT] = Button.CYCLE_ABILITY;
gamepadMapping[this.player.RC_W] = Button.CYCLE_NATURE; gamepadMapping[this.player.mapping.RC_W] = Button.CYCLE_NATURE;
gamepadMapping[this.player.RC_N] = Button.CYCLE_VARIANT; gamepadMapping[this.player.mapping.RC_N] = Button.CYCLE_VARIANT;
gamepadMapping[this.player.LS] = Button.SPEED_UP; gamepadMapping[this.player.mapping.LS] = Button.SPEED_UP;
gamepadMapping[this.player.RS] = Button.SLOW_DOWN; gamepadMapping[this.player.mapping.RS] = Button.SLOW_DOWN;
return gamepadMapping; return gamepadMapping;
} }

View File

@ -1635,7 +1635,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
"encounter": { "encounter": {
1: `Ich habe mich entschieden, erneut meinen Hut in den Ring zu werfen. 1: `Ich habe mich entschieden, erneut meinen Hut in den Ring zu werfen.
$Komm jetzt... Zeig mir die Früchte deines Trainings.`, $Komm jetzt... Zeig mir die Früchte deines Trainings.`,
},
"victory": { "victory": {
1: "Ich freue mich auf Neuigkeiten über all deine Erfolge!" 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?" 1: "Was ist los? Das ist doch nicht alles, oder?"
} }
}, },
},
"nemona": { "nemona": {
"encounter": { "encounter": {
1: "Yesss! Ich bin so aufgeregt! Zeit, dass wir uns austoben!" 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. // 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) // Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = { export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

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

View File

@ -14,8 +14,7 @@ export const tutorial: SimpleTranslationEntries = {
$Dort kannst du u. A. die Spielgeschwin-\ndigkeit und das Fensterdesign ändern. $Dort kannst du u. A. die Spielgeschwin-\ndigkeit und das Fensterdesign ändern.
$Das Menü verbirgt noch andere Funktionen - probier' sie gerne aus!`, $Das Menü verbirgt noch andere Funktionen - probier' sie gerne aus!`,
"starterSelect": `In diesem Bildschirm kannst du mit Z oder Leertaste deine\nStarter auswählen. "starterSelect": `Hier kannst du deine Starter-Pokémon auswählen.\nSie begleiten dich am Anfang deines Abenteuers.
$Sie 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. $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. $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. $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": { "encounter": {
1: `I decided to throw my hat in the ring once more. 1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`, $Come now Show me the fruits of your training.`,
},
"victory": { "victory": {
1: "I eagerly await news of all your achievements!" 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?" 1: "What's the matter? This isn't all, is it?"
} }
}, },
},
"nemona": { "nemona": {
"encounter": { "encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!" 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. // 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) // Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = { export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

@ -11,7 +11,6 @@ export const menu: SimpleTranslationEntries = {
"dailyRun": "Daily Run (Beta)", "dailyRun": "Daily Run (Beta)",
"loadGame": "Load Game", "loadGame": "Load Game",
"newGame": "New Game", "newGame": "New Game",
"settings": "Settings",
"selectGameMode": "Select a game mode.", "selectGameMode": "Select a game mode.",
"logInOrCreateAccount": "Log in or create an account to start. No email required!", "logInOrCreateAccount": "Log in or create an account to start. No email required!",
"username": "Username", "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. $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!`, $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. $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. $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!`, $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 = { export const battle: SimpleTranslationEntries = {
"bossAppeared": "¡{{bossName}} te corta el paso!", "bossAppeared": "¡{{bossName}} te corta el paso!",
"trainerAppeared": "¡{{trainerName}}\nte desafía!", "trainerAppeared": "¡{{trainerName}}\nte desafía!",
"trainerAppearedDouble": "¡{{trainerName}}\nwould te desafían!", "trainerAppearedDouble": "{{trainerName}}\nwould like to battle!",
"trainerSendOut": "¡{{trainerName}} saca a\n{{pokemonName}}!", "trainerSendOut": "{{trainerName}} sent out\n{{pokemonName}}!",
"singleWildAppeared": "¡Un {{pokemonName}} salvaje te corta el paso!", "singleWildAppeared": "¡Un {{pokemonName}} salvaje te corta el paso!",
"multiWildAppeared": "¡Un {{pokemonName1}} y un {{pokemonName2}} salvajes\nte cortan el paso!", "multiWildAppeared": "¡Un {{pokemonName1}} y un {{pokemonName2}} salvajes\nte cortan el paso!",
"playerComeBack": "¡{{pokemonName}}, ven aquí!", "playerComeBack": "¡{{pokemonName}}, ven aquí!",
@ -13,9 +13,9 @@ export const battle: SimpleTranslationEntries = {
"trainerGo": "¡{{trainerName}} saca a {{pokemonName}}!", "trainerGo": "¡{{trainerName}} saca a {{pokemonName}}!",
"switchQuestion": "¿Quieres cambiar a\n{{pokemonName}}?", "switchQuestion": "¿Quieres cambiar a\n{{pokemonName}}?",
"trainerDefeated": "¡Has derrotado a\n{{trainerName}}!", "trainerDefeated": "¡Has derrotado a\n{{trainerName}}!",
"moneyWon": "¡Has ganado\n₽{{moneyAmount}} por vencer!", "moneyWon": "You got\n₽{{moneyAmount}} for winning!",
"pokemonCaught": "¡{{pokemonName}} atrapado!", "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", "pokemon": "Pokémon",
"sendOutPokemon": "¡Adelante, {{pokemonName}}!", "sendOutPokemon": "¡Adelante, {{pokemonName}}!",
"hitResultCriticalHit": "!Un golpe crítico!", "hitResultCriticalHit": "!Un golpe crítico!",
@ -39,7 +39,7 @@ export const battle: SimpleTranslationEntries = {
"learnMoveAnd": "Y…", "learnMoveAnd": "Y…",
"levelCapUp": "¡Se ha incrementado el\nnivel máximo a {{levelCap}}!", "levelCapUp": "¡Se ha incrementado el\nnivel máximo a {{levelCap}}!",
"moveNotImplemented": "{{moveName}} aún no está implementado y no se puede seleccionar.", "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!", "moveDisabled": "!No puede usar {{moveName}} porque ha sido anulado!",
"noPokeballForce": "Una fuerza misteriosa\nte impide usar Poké Balls.", "noPokeballForce": "Una fuerza misteriosa\nte impide usar Poké Balls.",
"noPokeballTrainer": "¡No puedes atrapar a los\nPokémon de los demás!", "noPokeballTrainer": "¡No puedes atrapar a los\nPokémon de los demás!",

View File

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

View File

@ -1595,7 +1595,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
"encounter": { "encounter": {
1: `I decided to throw my hat in the ring once more. 1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`, $Come now Show me the fruits of your training.`,
},
"victory": { "victory": {
1: "I eagerly await news of all your achievements!" 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?" 1: "What's the matter? This isn't all, is it?"
} }
}, },
},
"nemona": { "nemona": {
"encounter": { "encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!" 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. // 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) // Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = { export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

@ -11,7 +11,6 @@ export const menu: SimpleTranslationEntries = {
"dailyRun": "Reto diario (Beta)", "dailyRun": "Reto diario (Beta)",
"loadGame": "Cargar partida", "loadGame": "Cargar partida",
"newGame": "Nueva partida", "newGame": "Nueva partida",
"settings": "Settings",
"selectGameMode": "Elige un modo de juego.", "selectGameMode": "Elige un modo de juego.",
"logInOrCreateAccount": "Inicia sesión o crea una cuenta para empezar. ¡No se requiere correo electrónico!", "logInOrCreateAccount": "Inicia sesión o crea una cuenta para empezar. ¡No se requiere correo electrónico!",
"username": "Usuario", "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 // Titles of special trainers like gym leaders, elite four, and the champion
export const titles: SimpleTranslationEntries = { export const titles: SimpleTranslationEntries = {
"elite_four": "Alto Mando", "elite_four": "Elite Four",
"elite_four_female": "Alto Mando", "elite_four_female": "Elite Four",
"gym_leader": "Líder de gimnasio", "gym_leader": "Gym Leader",
"gym_leader_female": "Líder de gimnasio", "gym_leader_female": "Gym Leader",
"gym_leader_double": "Líderes de Gimnasio", "gym_leader_double": "Gym Leader Duo",
"champion": "Campeón", "champion": "Champion",
"champion_female": "Campeona", "champion_female": "Champion",
"champion_double": "Campeones", "champion_double": "Champion Duo",
"rival": "Rival", "rival": "Rival",
"professor": "Profesor", "professor": "Professor",
"frontier_brain": "As del Frente Batalla", "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. // 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; } as const;

View File

@ -1595,7 +1595,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
"encounter": { "encounter": {
1: `I decided to throw my hat in the ring once more. 1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`, $Come now Show me the fruits of your training.`,
},
"victory": { "victory": {
1: "I eagerly await news of all your achievements!" 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?" 1: "What's the matter? This isn't all, is it?"
} }
}, },
},
"nemona": { "nemona": {
"encounter": { "encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!" 1: "Yesss! I'm so psyched! Time for us to let loose!"
@ -3873,7 +3873,6 @@ export const PGFdialogue: DialogueTranslationEntries = {
"encounter": { "encounter": {
1: `I decided to throw my hat in the ring once more. 1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`, $Come now Show me the fruits of your training.`,
},
"victory": { "victory": {
1: "I eagerly await news of all your achievements!" 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?" 1: "What's the matter? This isn't all, is it?"
} }
}, },
},
"nemona": { "nemona": {
"encounter": { "encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!" 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)", "dailyRun": "Défi du jour (Bêta)",
"loadGame": "Charger la partie", "loadGame": "Charger la partie",
"newGame": "Nouvelle partie", "newGame": "Nouvelle partie",
"settings": "Paramètres",
"selectGameMode": "Sélectionnez un mode de jeu.", "selectGameMode": "Sélectionnez un mode de jeu.",
"logInOrCreateAccount": "Connectez-vous ou créez un compte pour commencer. Aucun e-mail requis !", "logInOrCreateAccount": "Connectez-vous ou créez un compte pour commencer. Aucun e-mail requis !",
"username": "Nom dutilisateur", "username": "Nom dutilisateur",

View File

@ -16,7 +16,7 @@ export const tutorial: SimpleTranslationEntries = {
$Il y a également toute une variété dautres fonctionnalités, $Il y a également toute une variété dautres fonctionnalités,
$jetez-y un œil !`, $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. $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. $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 !`, $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": { "encounter": {
1: `I decided to throw my hat in the ring once more. 1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`, $Come now Show me the fruits of your training.`,
},
"victory": { "victory": {
1: "I eagerly await news of all your achievements!" 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?" 1: "What's the matter? This isn't all, is it?"
} }
}, },
},
"nemona": { "nemona": {
"encounter": { "encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!" 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. // 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) // Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = { export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

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

View File

@ -1595,7 +1595,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
"encounter": { "encounter": {
1: `I decided to throw my hat in the ring once more. 1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`, $Come now Show me the fruits of your training.`,
},
"victory": { "victory": {
1: "I eagerly await news of all your achievements!" 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?" 1: "What's the matter? This isn't all, is it?"
} }
}, },
},
"nemona": { "nemona": {
"encounter": { "encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!" 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. // 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) // Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = { export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

@ -11,7 +11,6 @@ export const menu: SimpleTranslationEntries = {
"dailyRun": "Desafio Diário (Beta)", "dailyRun": "Desafio Diário (Beta)",
"loadGame": "Carregar Jogo", "loadGame": "Carregar Jogo",
"newGame": "Novo Jogo", "newGame": "Novo Jogo",
"settings": "Configurações",
"selectGameMode": "Escolha um modo de jogo.", "selectGameMode": "Escolha um modo de jogo.",
"logInOrCreateAccount": "Inicie uma sessão ou crie uma conta para começar. Não é necessário email!", "logInOrCreateAccount": "Inicie uma sessão ou crie uma conta para começar. Não é necessário email!",
"username": "Nome de Usuário", "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. $Existem também vários outros recursos disponíveis aqui.
$Não deixe de conferir todos eles!`, $Não deixe de conferir todos eles!`,
"starterSelect": `Aqui você pode escolher seus iniciais apertando a tecla Z ou\na Barra de Espaço. "starterSelect": `Aqui você pode escolher seus iniciais.\nEsses serão os primeiro Pokémon da sua equipe.
$Esses 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. $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. $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. $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": { "encounter": {
1: `I decided to throw my hat in the ring once more. 1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`, $Come now Show me the fruits of your training.`,
},
"victory": { "victory": {
1: "I eagerly await news of all your achievements!" 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?" 1: "What's the matter? This isn't all, is it?"
} }
}, },
},
"nemona": { "nemona": {
"encounter": { "encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!" 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. // 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) // Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = { export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

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

View File

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

View File

@ -1595,7 +1595,6 @@ export const PGMdialogue: DialogueTranslationEntries = {
"encounter": { "encounter": {
1: `I decided to throw my hat in the ring once more. 1: `I decided to throw my hat in the ring once more.
$Come now Show me the fruits of your training.`, $Come now Show me the fruits of your training.`,
},
"victory": { "victory": {
1: "I eagerly await news of all your achievements!" 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?" 1: "What's the matter? This isn't all, is it?"
} }
}, },
},
"nemona": { "nemona": {
"encounter": { "encounter": {
1: "Yesss! I'm so psyched! Time for us to let loose!" 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. // 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) // Dialogue of the endboss of the game when the player character is male (Or unset)
export const PGMbattleSpecDialogue: SimpleTranslationEntries = { export const PGMbattleSpecDialogue: SimpleTranslationEntries = {

View File

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

View File

@ -5,6 +5,7 @@ import { version } from "../package.json";
import UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin"; import UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin";
import BBCodeTextPlugin from "phaser3-rex-plugins/plugins/bbcodetext-plugin"; import BBCodeTextPlugin from "phaser3-rex-plugins/plugins/bbcodetext-plugin";
import InputTextPlugin from "phaser3-rex-plugins/plugins/inputtext-plugin.js"; 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 TransitionImagePackPlugin from "phaser3-rex-plugins/templates/transitionimagepack/transitionimagepack-plugin.js";
import { LoadingScene } from "./loading-scene"; import { LoadingScene } from "./loading-scene";
@ -71,82 +72,23 @@ const config: Phaser.Types.Core.GameConfig = {
version: version 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) { 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 offsetX = guideObject.width * (-0.5 + (0.5 - guideObject.originX));
const offsetY = guideObject.height * (-0.5 + (0.5 - guideObject.originY)); const offsetY = guideObject.height * (-0.5 + (0.5 - guideObject.originY));
this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y); this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y);
}; return;
}
declare module "phaser" { this.setPosition(x, y);
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;
}
}
}
Phaser.GameObjects.Container.prototype.setPositionRelative = setPositionRelative; Phaser.GameObjects.Container.prototype.setPositionRelative = setPositionRelative;
Phaser.GameObjects.Sprite.prototype.setPositionRelative = setPositionRelative; Phaser.GameObjects.Sprite.prototype.setPositionRelative = setPositionRelative;
Phaser.GameObjects.Image.prototype.setPositionRelative = setPositionRelative; Phaser.GameObjects.Image.prototype.setPositionRelative = setPositionRelative;
Phaser.GameObjects.NineSlice.prototype.setPositionRelative = setPositionRelative; Phaser.GameObjects.NineSlice.prototype.setPositionRelative = setPositionRelative;
Phaser.GameObjects.Text.prototype.setPositionRelative = setPositionRelative; Phaser.GameObjects.Text.prototype.setPositionRelative = setPositionRelative;
BBCodeText.prototype.setPositionRelative = setPositionRelative;
Phaser.GameObjects.Rectangle.prototype.setPositionRelative = setPositionRelative; Phaser.GameObjects.Rectangle.prototype.setPositionRelative = setPositionRelative;
document.fonts.load("16px emerald").then(() => document.fonts.load("10px pkmnems")); 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 { TempBattleStat } from "./data/temp-battle-stat";
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag"; import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
import { ArenaTagType } from "./data/enums/arena-tag-type"; 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 { Unlockables, getUnlockableName } from "./system/unlockables";
import { getBiomeKey } from "./field/arena"; import { getBiomeKey } from "./field/arena";
import { BattleType, BattlerIndex, TurnCommand } from "./battle"; import { BattleType, BattlerIndex, TurnCommand } from "./battle";
@ -262,14 +262,6 @@ export class TitlePhase extends Phase {
return true; return true;
}, },
keepOpen: true keepOpen: true
},
{
label: i18next.t("menu:settings"),
handler: () => {
this.scene.ui.setOverlayMode(Mode.SETTINGS);
return true;
},
keepOpen: true
}); });
const config: OptionSelectConfig = { const config: OptionSelectConfig = {
options: options, options: options,
@ -1023,6 +1015,7 @@ export class EncounterPhase extends BattlePhase {
} }
} }
} }
handleTutorial(this.scene, Tutorial.Access_Menu).then(() => super.end()); handleTutorial(this.scene, Tutorial.Access_Menu).then(() => super.end());
} }
@ -2228,9 +2221,7 @@ export class BerryPhase extends FieldPhase {
if (cancelled.value) { if (cancelled.value) {
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is too\nnervous to eat berries!")); pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is too\nnervous to eat berries!"));
} else { } else {
this.scene.unshiftPhase( this.scene.unshiftPhase(new CommonAnimPhase(this.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM));
new CommonAnimPhase(this.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM)
);
for (const berryModifier of this.scene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon) as BerryModifier[]) { for (const berryModifier of this.scene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon) as BerryModifier[]) {
if (berryModifier.consumed) { if (berryModifier.consumed) {
@ -2243,8 +2234,6 @@ export class BerryPhase extends FieldPhase {
} }
this.scene.updateModifiers(pokemon.isPlayer()); 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(); const user = this.getUserPokemon();
// Hit check only calculated on first hit for multi-hit moves unless flag is set to check all hits. // Hit check only calculated on first hit for multi-hit moves
// However, if an ability with the MaxMultiHitAbAttr, namely Skill Link, is present, act as a normal
// multi-hit move and proceed with all hits
if (user.turnData.hitsLeft < user.turnData.hitCount) { if (user.turnData.hitsLeft < user.turnData.hitCount) {
if (!this.move.getMove().hasFlag(MoveFlags.CHECK_ALL_HITS) || user.hasAbilityWithAttr(MaxMultiHitAbAttr)) {
return true; return true;
} }
}
if (user.hasAbilityWithAttr(AlwaysHitAbAttr) || target.hasAbilityWithAttr(AlwaysHitAbAttr)) { if (user.hasAbilityWithAttr(AlwaysHitAbAttr) || target.hasAbilityWithAttr(AlwaysHitAbAttr)) {
return true; return true;

View File

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

View File

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

View File

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

View File

@ -3,8 +3,6 @@ export const keysDown = new Map();
let lastTouchedId; let lastTouchedId;
export function initTouchControls(buttonMap) { export function initTouchControls(buttonMap) {
const dpadDiv = document.querySelector("#dpad");
preventElementZoom(dpadDiv);
for (const button of document.querySelectorAll("[data-key]")) { for (const button of document.querySelectorAll("[data-key]")) {
// @ts-ignore // @ts-ignore
bindKey(button, button.dataset.key, buttonMap); 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 { pokemonPrevolutions } from "#app/data/pokemon-evolutions";
import { Variant, getVariantTint } from "#app/data/variant"; import { Variant, getVariantTint } from "#app/data/variant";
import { argbFromRgba } from "@material/material-color-utilities"; import { argbFromRgba } from "@material/material-color-utilities";
@ -104,29 +103,6 @@ function getValueReductionCandyCounts(baseValue: integer): [integer, integer] {
return starterCandyCosts[baseValue - 1].costReduction; 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 = [ const gens = [
i18next.t("starterSelectUiHandler:gen1"), i18next.t("starterSelectUiHandler:gen1"),
i18next.t("starterSelectUiHandler:gen2"), i18next.t("starterSelectUiHandler:gen2"),
@ -226,8 +202,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
private shinyIcons: Phaser.GameObjects.Image[][]; private shinyIcons: Phaser.GameObjects.Image[][];
private hiddenAbilityIcons: Phaser.GameObjects.Image[]; private hiddenAbilityIcons: Phaser.GameObjects.Image[];
private classicWinIcons: Phaser.GameObjects.Image[]; private classicWinIcons: Phaser.GameObjects.Image[];
private candyUpgradeIcon: Phaser.GameObjects.Image[];
private candyUpgradeOverlayIcon: Phaser.GameObjects.Image[];
private iconAnimHandler: PokemonIconAnimHandler; private iconAnimHandler: PokemonIconAnimHandler;
@ -418,8 +392,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.genSpecies[g].push(species); this.genSpecies[g].push(species);
const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true); const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true);
const defaultProps = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr); const defaultProps = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
const position = calcIconPosition(s); const x = (s % 9) * 18;
const icon = this.scene.add.sprite(position.x - 2, position.y + 2, species.getIconAtlasKey(defaultProps.formIndex, defaultProps.shiny, defaultProps.variant)); 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.setScale(0.5);
icon.setOrigin(0, 0); icon.setOrigin(0, 0);
icon.setFrame(species.getIconId(defaultProps.female, defaultProps.formIndex, defaultProps.shiny, defaultProps.variant)); 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) => { this.starterValueLabels = new Array(81).fill(null).map((_, i) => {
const position = calcIconPosition(i); const x = (i % 9) * 18;
const ret = addTextObject(this.scene, position.x + 152, position.y + 11, "0", TextStyle.WINDOW, { fontSize: "32px" }); 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.setShadowOffset(2, 2);
ret.setOrigin(0, 0); ret.setOrigin(0, 0);
ret.setVisible(false); ret.setVisible(false);
@ -452,8 +428,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}); });
const getShinyStar = (i: integer, v: integer): Phaser.GameObjects.Image => { const getShinyStar = (i: integer, v: integer): Phaser.GameObjects.Image => {
const position = calcIconPosition(i); const x = (i % 9) * 18 - v * 3;
const ret = this.scene.add.image((position.x - v * 3) + 163, position.y + 11, "shiny_star_small"); 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.setOrigin(0, 0);
ret.setScale(0.5); ret.setScale(0.5);
ret.setVisible(false); ret.setVisible(false);
@ -466,8 +443,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}); });
this.hiddenAbilityIcons = new Array(81).fill(null).map((_, i) => { this.hiddenAbilityIcons = new Array(81).fill(null).map((_, i) => {
const position = calcIconPosition(i); const x = (i % 9) * 18;
const ret = this.scene.add.image(position.x + 163, position.y + 16, "ha_capsule"); const y = Math.floor(i / 9) * 18;
const ret = this.scene.add.image(x + 163, y + 16, "ha_capsule");
ret.setOrigin(0, 0); ret.setOrigin(0, 0);
ret.setScale(0.5); ret.setScale(0.5);
ret.setVisible(false); ret.setVisible(false);
@ -476,8 +454,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}); });
this.classicWinIcons = new Array(81).fill(null).map((_, i) => { this.classicWinIcons = new Array(81).fill(null).map((_, i) => {
const position = calcIconPosition(i); const x = (i % 9) * 18;
const ret = this.scene.add.image(position.x + 153, position.y + 21, "champion_ribbon"); const y = Math.floor(i / 9) * 18;
const ret = this.scene.add.image(x + 153, y + 21, "champion_ribbon");
ret.setOrigin(0, 0); ret.setOrigin(0, 0);
ret.setScale(0.5); ret.setScale(0.5);
ret.setVisible(false); ret.setVisible(false);
@ -485,26 +464,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
return ret; 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 = 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.pokemonSprite.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true });
this.starterSelectContainer.add(this.pokemonSprite); this.starterSelectContainer.add(this.pokemonSprite);
@ -694,14 +653,25 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.starterSelectContainer.add(this.statsContainer); this.starterSelectContainer.add(this.statsContainer);
this.scene.eventTarget.addEventListener(BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED, (e) => this.onCandyUpgradeDisplayChanged(e));
this.updateInstructions(); this.updateInstructions();
} }
show(args: any[]): boolean { show(args: any[]): boolean {
if (args.length >= 2 && args[0] instanceof Function && typeof args[1] === "number") { if (args.length >= 2 && args[0] instanceof Function && typeof args[1] === "number") {
super.show(args); 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.starterSelectCallback = args[0] as StarterSelectCallback;
this.starterSelectContainer.setVisible(true); this.starterSelectContainer.setVisible(true);
@ -714,21 +684,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.setCursor(0); this.setCursor(0);
this.tryUpdateValue(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); handleTutorial(this.scene, Tutorial.Starter_Select);
return true; return true;
@ -751,161 +706,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.starterSelectMessageBoxContainer.setVisible(!!text?.length); 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 { processInput(button: Button): boolean {
if (this.blockInput) { if (this.blockInput) {
return false; return false;
@ -1148,16 +948,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}); });
ui.setMode(Mode.STARTER_SELECT); ui.setMode(Mode.STARTER_SELECT);
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, undefined); 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 true;
} }
return false; return false;
@ -1185,18 +975,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.tryUpdateValue(0); this.tryUpdateValue(0);
ui.setMode(Mode.STARTER_SELECT); ui.setMode(Mode.STARTER_SELECT);
this.scene.playSound("buy"); 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 true;
} }
return false; 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.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); 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 { } else {
changed = super.setCursor(cursor); 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)); 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.checkIconId(lastSpeciesIcon, this.lastSpecies, props.female, props.formIndex, props.shiny, props.variant);
this.iconAnimHandler.addOrUpdate(lastSpeciesIcon, PokemonIconAnimMode.NONE); 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; this.lastSpecies = species;
@ -1679,22 +1434,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonCandyDarknessOverlay.setCrop(0,0,16, candyCropY); this.pokemonCandyDarknessOverlay.setCrop(0,0,16, candyCropY);
} }
this.iconAnimHandler.addOrUpdate(this.starterSelectGenIconContainers[species.generation - 1].getAt(this.genSpecies[species.generation - 1].indexOf(species)) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.PASSIVE);
// 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);
let starterIndex = -1; let starterIndex = -1;

View File

@ -38,7 +38,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
this.titleContainer.add(this.dailyRunScoreboard); 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.playerCountLabel.setOrigin(1, 0);
this.titleContainer.add(this.playerCountLabel); this.titleContainer.add(this.playerCountLabel);