diff --git a/README.md b/README.md index 424d47ff1b0..b2955f8c4b5 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,11 @@ PokéRogue is a browser based Pokémon fangame heavily inspired by the roguelite If you have the motivation and experience with Typescript/Javascript (or are willing to learn) please feel free to fork the repository and make pull requests with contributions. If you don't know what to work on but want to help, reference the below **To-Do** section or the **#vote** channel in the discord. ### 💻 Environment Setup -node: 18.3.0 +#### Prerequisites +- node: 18.3.0 +- npm: [how to install](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) +#### Running Locally 1. Clone the repo and in the root directory run `npm install` - *if you run into any errors, reach out in the **#dev-corner** channel in discord* 2. Run `npm run start:dev` to locally run the project in `localhost:8000` diff --git a/public/audio/cry/25-gigantamax.m4a b/public/audio/cry/25-gigantamax.m4a index ea4becab5b8..2cf38814bce 100644 Binary files a/public/audio/cry/25-gigantamax.m4a and b/public/audio/cry/25-gigantamax.m4a differ diff --git a/public/audio/cry/25.m4a b/public/audio/cry/25.m4a index ea4becab5b8..2cf38814bce 100644 Binary files a/public/audio/cry/25.m4a and b/public/audio/cry/25.m4a differ diff --git a/public/audio/cry/669-white.m4a b/public/audio/cry/669-white.m4a new file mode 100644 index 00000000000..773241dac0f Binary files /dev/null and b/public/audio/cry/669-white.m4a differ diff --git a/public/audio/cry/670-white.m4a b/public/audio/cry/670-white.m4a new file mode 100644 index 00000000000..45e83e386af Binary files /dev/null and b/public/audio/cry/670-white.m4a differ diff --git a/public/audio/cry/671-white.m4a b/public/audio/cry/671-white.m4a new file mode 100644 index 00000000000..e604dea4064 Binary files /dev/null and b/public/audio/cry/671-white.m4a differ diff --git a/public/images/pokemon/1024-stellar.json b/public/images/pokemon/1024-stellar.json index 3f8ffe6c4ca..0972c56328f 100644 --- a/public/images/pokemon/1024-stellar.json +++ b/public/images/pokemon/1024-stellar.json @@ -4,30 +4,30 @@ "image": "1024-stellar.png", "format": "RGBA8888", "size": { - "w": 96, - "h": 96 + "w": 119, + "h": 119 }, - "scale": 0.5, + "scale": 1, "frames": [ { "filename": "0001.png", "rotated": false, "trimmed": false, "sourceSize": { - "w": 96, - "h": 96 + "w": 119, + "h": 119 }, "spriteSourceSize": { - "x": 9, + "x": 0, "y": 0, - "w": 78, - "h": 96 + "w": 115, + "h": 119 }, "frame": { "x": 0, "y": 0, - "w": 78, - "h": 96 + "w": 115, + "h": 119 } } ] @@ -36,6 +36,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:c9ee64bda72f2dadb06109338796ccac:1313f1218b7da2c57ad9f290d1323840:c1508f3b01ae78a28a1267fd6caa4f7b$" + "smartupdate": "$TexturePacker:SmartUpdate:bc663acf2e62803fce6c3a525dc8dd98:ccd7d0de8a487235cfbd6f372afa931f:c1508f3b01ae78a28a1267fd6caa4f7b$" } } diff --git a/public/images/pokemon/1024-stellar.png b/public/images/pokemon/1024-stellar.png index 6500eddec8e..7e40fb0043f 100644 Binary files a/public/images/pokemon/1024-stellar.png and b/public/images/pokemon/1024-stellar.png differ diff --git a/public/images/pokemon/back/1024-stellar.json b/public/images/pokemon/back/1024-stellar.json index f80edd88606..ce84b0d4502 100644 --- a/public/images/pokemon/back/1024-stellar.json +++ b/public/images/pokemon/back/1024-stellar.json @@ -4,30 +4,30 @@ "image": "1024-stellar.png", "format": "RGBA8888", "size": { - "w": 96, - "h": 96 + "w": 119, + "h": 119 }, - "scale": 0.333, + "scale": 1, "frames": [ { "filename": "0001.png", "rotated": false, "trimmed": false, "sourceSize": { - "w": 96, - "h": 96 + "w": 119, + "h": 119 }, "spriteSourceSize": { - "x": 5, + "x": 0, "y": 0, - "w": 86, - "h": 96 + "w": 115, + "h": 119 }, "frame": { "x": 0, "y": 0, - "w": 86, - "h": 96 + "w": 115, + "h": 119 } } ] @@ -36,6 +36,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:ac5e775f77477eeabd029932804747c4:f7a112a87c35dc81cb0da88b7cbb39e8:c1508f3b01ae78a28a1267fd6caa4f7b$" + "smartupdate": "$TexturePacker:SmartUpdate:210ba1c2e6e58501571ae226d073a3c5:f12bdf191842f7ec3a4be98a43fb8121:c1508f3b01ae78a28a1267fd6caa4f7b$" } } diff --git a/public/images/pokemon/back/1024-stellar.png b/public/images/pokemon/back/1024-stellar.png index 7940444f580..0bb2993d857 100644 Binary files a/public/images/pokemon/back/1024-stellar.png and b/public/images/pokemon/back/1024-stellar.png differ diff --git a/public/images/pokemon/back/shiny/1024-stellar.json b/public/images/pokemon/back/shiny/1024-stellar.json index eeabac109a3..ce84b0d4502 100644 --- a/public/images/pokemon/back/shiny/1024-stellar.json +++ b/public/images/pokemon/back/shiny/1024-stellar.json @@ -4,30 +4,30 @@ "image": "1024-stellar.png", "format": "RGBA8888", "size": { - "w": 96, - "h": 96 + "w": 119, + "h": 119 }, - "scale": 0.333, + "scale": 1, "frames": [ { "filename": "0001.png", "rotated": false, "trimmed": false, "sourceSize": { - "w": 96, - "h": 96 + "w": 119, + "h": 119 }, "spriteSourceSize": { - "x": 5, + "x": 0, "y": 0, - "w": 86, - "h": 96 + "w": 115, + "h": 119 }, "frame": { "x": 0, "y": 0, - "w": 86, - "h": 96 + "w": 115, + "h": 119 } } ] @@ -36,6 +36,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:2bd25bae0fabcfbc35e24bd578a7b4b5:aec60788a0d77f38fb599d721e41a0d6:c1508f3b01ae78a28a1267fd6caa4f7b$" + "smartupdate": "$TexturePacker:SmartUpdate:210ba1c2e6e58501571ae226d073a3c5:f12bdf191842f7ec3a4be98a43fb8121:c1508f3b01ae78a28a1267fd6caa4f7b$" } } diff --git a/public/images/pokemon/back/shiny/1024-stellar.png b/public/images/pokemon/back/shiny/1024-stellar.png index 6b9e35174ee..0bb2993d857 100644 Binary files a/public/images/pokemon/back/shiny/1024-stellar.png and b/public/images/pokemon/back/shiny/1024-stellar.png differ diff --git a/public/images/pokemon/shiny/1024-stellar.json b/public/images/pokemon/shiny/1024-stellar.json index dd07eb812f2..ba751e2bc5c 100644 --- a/public/images/pokemon/shiny/1024-stellar.json +++ b/public/images/pokemon/shiny/1024-stellar.json @@ -4,30 +4,30 @@ "image": "1024-stellar.png", "format": "RGBA8888", "size": { - "w": 96, - "h": 96 + "w": 119, + "h": 119 }, - "scale": 0.5, + "scale": 1, "frames": [ { "filename": "0001.png", "rotated": false, "trimmed": false, "sourceSize": { - "w": 96, - "h": 96 + "w": 119, + "h": 119 }, "spriteSourceSize": { - "x": 9, + "x": 0, "y": 0, - "w": 78, - "h": 96 + "w": 115, + "h": 119 }, "frame": { "x": 0, "y": 0, - "w": 78, - "h": 96 + "w": 115, + "h": 119 } } ] @@ -36,6 +36,6 @@ "meta": { "app": "https://www.codeandweb.com/texturepacker", "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:a7e89af07a22475413df24b510c193f7:45261af90c4a51e3dc73cccb894a2aad:c1508f3b01ae78a28a1267fd6caa4f7b$" + "smartupdate": "$TexturePacker:SmartUpdate:3510deaf42eaa3ee2fdfa22c00a2b30b:3beb6b12ca1bb50ad260593b41939f27:c1508f3b01ae78a28a1267fd6caa4f7b$" } } diff --git a/public/images/pokemon/shiny/1024-stellar.png b/public/images/pokemon/shiny/1024-stellar.png index 42ed145d937..b00b395ec56 100644 Binary files a/public/images/pokemon/shiny/1024-stellar.png and b/public/images/pokemon/shiny/1024-stellar.png differ diff --git a/src/battle-scene.ts b/src/battle-scene.ts index fdd50661b2a..26fbe1b2fb6 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -17,7 +17,7 @@ import { TextStyle, addTextObject } from './ui/text'; import { Moves } from "./data/enums/moves"; import { allMoves } from "./data/move"; import { initMoves } from './data/move'; -import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave } from './modifier/modifier-type'; +import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getModifierPoolForType } from './modifier/modifier-type'; import AbilityBar from './ui/ability-bar'; import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, IncrementMovePriorityAbAttr, applyAbAttrs, initAbilities } from './data/ability'; import { Abilities } from "./data/enums/abilities"; @@ -795,7 +795,10 @@ export default class BattleScene extends SceneBase { this.trainer.setVisible(true); if (reloadI18n) { - const localizable: Localizable[] = [ ...allMoves ]; + const localizable: Localizable[] = [ + ...allMoves, + ...Utils.getEnumValues(ModifierPoolType).map(mpt => getModifierPoolForType(mpt)).map(mp => Object.values(mp).flat().map(mt => mt.modifierType).filter(mt => 'localize' in mt).map(lpb => lpb as unknown as Localizable)).flat() + ]; for (let item of localizable) item.localize(); } @@ -975,6 +978,9 @@ export default class BattleScene extends SceneBase { case Species.DEERLING: case Species.SAWSBUCK: case Species.VIVILLON: + case Species.FLABEBE: + case Species.FLOETTE: + case Species.FLORGES: case Species.ORICORIO: case Species.SQUAWKABILLY: case Species.TATSUGIRI: diff --git a/src/data/ability.ts b/src/data/ability.ts index b2399844a85..348f78da677 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -2134,6 +2134,9 @@ export class SuppressFieldAbilitiesAbAttr extends AbAttr { } } + +export class AlwaysHitAbAttr extends AbAttr { } + export class UncopiableAbilityAbAttr extends AbAttr { constructor() { super(false); @@ -2615,7 +2618,9 @@ export function initAbilities() { new Ability(Abilities.SNIPER, "Sniper (N)", "Powers up moves if they become critical hits when attacking.", 4), new Ability(Abilities.MAGIC_GUARD, "Magic Guard", "The Pokémon only takes damage from attacks.", 4) .attr(BlockNonDirectDamageAbAttr), - new Ability(Abilities.NO_GUARD, "No Guard (N)", "The Pokémon employs no-guard tactics to ensure incoming and outgoing attacks always land.", 4), + new Ability(Abilities.NO_GUARD, "No Guard", "The Pokémon employs no-guard tactics to ensure incoming and outgoing attacks always land.", 4) + .attr(AlwaysHitAbAttr) + .attr(DoubleBattleChanceAbAttr), new Ability(Abilities.STALL, "Stall (N)", "The Pokémon moves after all other Pokémon do.", 4), new Ability(Abilities.TECHNICIAN, "Technician", "Powers up the Pokémon's weaker moves.", 4) .attr(MovePowerBoostAbAttr, (user, target, move) => move.power <= 60, 1.5), diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index ce90b038fd5..58c017c7a1d 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1024,6 +1024,39 @@ export class SaltCuredTag extends BattlerTag { } } +export class CursedTag extends BattlerTag { + private sourceIndex: integer; + + constructor(sourceId: integer) { + super(BattlerTagType.CURSED, BattlerTagLapseType.TURN_END, 1, Moves.CURSE, sourceId); + } + + onAdd(pokemon: Pokemon): void { + super.onAdd(pokemon); + + pokemon.scene.queueMessage(getPokemonMessage(pokemon, ' has been cursed!')); + this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex(); + } + + lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { + const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType); + + if (ret) { + pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.SALT_CURE)); + + const cancelled = new Utils.BooleanHolder(false); + applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); + + if (!cancelled.value) { + pokemon.damageAndUpdate(Math.floor(pokemon.getMaxHp() / 4)); + pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` is hurt by the ${this.getMoveName()}!`)); + } + } + + return ret; + } +} + export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourceMove: Moves, sourceId: integer): BattlerTag { switch (tagType) { case BattlerTagType.RECHARGING: @@ -1121,6 +1154,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, turnCount - 1, sourceMove); case BattlerTagType.SALT_CURED: return new SaltCuredTag(sourceId); + case BattlerTagType.CURSED: + return new CursedTag(sourceId); case BattlerTagType.CHARGED: return new TypeBoostTag(tagType, sourceMove, Type.ELECTRIC, 2, true); case BattlerTagType.NONE: diff --git a/src/data/enums/battler-tag-type.ts b/src/data/enums/battler-tag-type.ts index b0fb7c2cc75..9c740ef4629 100644 --- a/src/data/enums/battler-tag-type.ts +++ b/src/data/enums/battler-tag-type.ts @@ -49,6 +49,7 @@ export enum BattlerTagType { BYPASS_SLEEP = "BYPASS_SLEEP", IGNORE_FLYING = "IGNORE_FLYING", SALT_CURED = "SALT_CURED", + CURSED = "CURSED", CHARGED = "CHARGED", GROUNDED = "GROUNDED" } diff --git a/src/data/move.ts b/src/data/move.ts index c19c822a5d2..03fd53ec29f 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2493,6 +2493,7 @@ export class AddBattlerTagAttr extends MoveEffectAttr { return -5; case BattlerTagType.SEEDED: case BattlerTagType.SALT_CURED: + case BattlerTagType.CURSED: case BattlerTagType.FRENZY: case BattlerTagType.TRAPPED: case BattlerTagType.BIND: @@ -2527,6 +2528,34 @@ export class AddBattlerTagAttr extends MoveEffectAttr { } } +export class CurseAttr extends MoveEffectAttr { + + apply(user: Pokemon, target: Pokemon, move:Move, args: any[]): boolean { + // Determine the correct target based on the user's type + if (!user.getTypes(true).includes(Type.GHOST)) { + // For non-Ghost types, target the user itself + target = user; + } + + if (user.getTypes(true).includes(Type.GHOST)) { + if (target.getTag(BattlerTagType.CURSED)) { + user.scene.queueMessage('But it failed!'); + return false; + } + let curseRecoilDamage = Math.floor(user.getMaxHp() / 2); + user.damageAndUpdate(curseRecoilDamage, HitResult.OTHER, false, true, true); + user.scene.queueMessage(getPokemonMessage(user, ' cut its own HP!')); + target.addTag(BattlerTagType.CURSED, 0, move.id, user.id); + return true; + } else { + target = user; + user.scene.unshiftPhase(new StatChangePhase(user.scene, user.getBattlerIndex(), this.selfTarget, [BattleStat.ATK, BattleStat.DEF], 1)); + user.scene.unshiftPhase(new StatChangePhase(user.scene, user.getBattlerIndex(), this.selfTarget, [BattleStat.SPD], -1)); + return true; + } + } +} + export class LapseBattlerTagAttr extends MoveEffectAttr { public tagTypes: BattlerTagType[]; @@ -5132,6 +5161,7 @@ export function initMoves() { .attr(StatChangeAttr, BattleStat.SPATK, 1, true) .danceMove(), new AttackMove(Moves.FREEZE_SHOCK, Type.ICE, MoveCategory.PHYSICAL, 140, 90, 5, 30, 0, 5) + .attr(ChargeAttr, ChargeAnim.FREEZE_SHOCK_CHARGING, 'became cloaked\nin a freezing light!') .attr(StatusEffectAttr, StatusEffect.PARALYSIS) .makesContact(false), new AttackMove(Moves.ICE_BURN, Type.ICE, MoveCategory.SPECIAL, 140, 90, 5, 30, 0, 5) diff --git a/src/data/pokeball.ts b/src/data/pokeball.ts index 45775f33d65..f5e39ba38ab 100644 --- a/src/data/pokeball.ts +++ b/src/data/pokeball.ts @@ -1,4 +1,5 @@ import BattleScene from "../battle-scene"; +import i18next from '../plugins/i18n'; export enum PokeballType { POKEBALL, @@ -30,22 +31,22 @@ export function getPokeballName(type: PokeballType): string { let ret: string; switch (type) { case PokeballType.POKEBALL: - ret = 'Poké Ball'; + ret = i18next.t('pokeball:pokeBall'); break; case PokeballType.GREAT_BALL: - ret = 'Great Ball'; + ret = i18next.t('pokeball:greatBall'); break; case PokeballType.ULTRA_BALL: - ret = 'Ultra Ball'; + ret = i18next.t('pokeball:ultraBall'); break; case PokeballType.ROGUE_BALL: - ret = 'Rogue Ball'; + ret = i18next.t('pokeball:rogueBall'); break; case PokeballType.MASTER_BALL: - ret = 'Master Ball'; + ret = i18next.t('pokeball:masterBall'); break; case PokeballType.LUXURY_BALL: - ret = 'Luxury Ball'; + ret = i18next.t('pokeball:luxuryBall'); break; } return ret; diff --git a/src/data/pokemon-evolutions.ts b/src/data/pokemon-evolutions.ts index fca8dbd76ca..68369389066 100644 --- a/src/data/pokemon-evolutions.ts +++ b/src/data/pokemon-evolutions.ts @@ -917,7 +917,7 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.TRUMBEAK, 14, null, null) ], [Species.TRUMBEAK]: [ - new SpeciesEvolution(Species.TOUCANNON, 36, null, null) + new SpeciesEvolution(Species.TOUCANNON, 28, null, null) ], [Species.YUNGOOS]: [ new SpeciesEvolution(Species.GUMSHOOS, 20, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.SHORT) diff --git a/src/data/pokemon-level-moves.ts b/src/data/pokemon-level-moves.ts index fe7f9a0a76f..e205febcd2a 100644 --- a/src/data/pokemon-level-moves.ts +++ b/src/data/pokemon-level-moves.ts @@ -10919,8 +10919,8 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { ], [Species.CHESPIN]: [ [ 1, Moves.TACKLE ], - [ 1, Moves.VINE_WHIP ], [ 1, Moves.GROWL ], + [ 1, Moves.VINE_WHIP ], [ 8, Moves.ROLLOUT ], [ 11, Moves.BITE ], [ 15, Moves.LEECH_SEED ], @@ -10934,8 +10934,8 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { ], [Species.QUILLADIN]: [ [ 1, Moves.TACKLE ], - [ 1, Moves.VINE_WHIP ], [ 1, Moves.GROWL ], + [ 1, Moves.VINE_WHIP ], [ 8, Moves.ROLLOUT ], [ 11, Moves.BITE ], [ 15, Moves.LEECH_SEED ], diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 409c32b68d3..30622fb033d 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -1473,7 +1473,7 @@ export function initSpecies() { new PokemonSpecies(Species.PORYGON_Z, "Porygon-Z", 4, false, false, false, "Virtual Pokémon", Type.NORMAL, null, 0.9, 34, Abilities.ADAPTABILITY, Abilities.DOWNLOAD, Abilities.ANALYTIC, 535, 85, 80, 70, 135, 75, 90, 30, 50, 268, GrowthRate.MEDIUM_FAST, null, false), new PokemonSpecies(Species.GALLADE, "Gallade", 4, false, false, false, "Blade Pokémon", Type.PSYCHIC, Type.FIGHTING, 1.6, 52, Abilities.STEADFAST, Abilities.SHARPNESS, Abilities.JUSTIFIED, 518, 68, 125, 65, 65, 115, 80, 45, 35, 259, GrowthRate.SLOW, 100, false, true, new PokemonForm("Normal", "", Type.PSYCHIC, Type.FIGHTING, 1.6, 52, Abilities.STEADFAST, Abilities.SHARPNESS, Abilities.JUSTIFIED, 518, 68, 125, 65, 65, 115, 80, 45, 35, 259), - new PokemonForm("Mega", SpeciesFormKey.MEGA, Type.PSYCHIC, Type.FIGHTING, 1.6, 56.4, Abilities.INNER_FOCUS, Abilities.INNER_FOCUS, Abilities.INNER_FOCUS, 618, 68, 165, 95, 65, 115, 110, 45, 35, 259), + new PokemonForm("Mega", SpeciesFormKey.MEGA, Type.PSYCHIC, Type.FIGHTING, 1.6, 56.4, Abilities.SHARPNESS, Abilities.SHARPNESS, Abilities.SHARPNESS, 618, 68, 165, 95, 65, 115, 110, 45, 35, 259), ), new PokemonSpecies(Species.PROBOPASS, "Probopass", 4, false, false, false, "Compass Pokémon", Type.ROCK, Type.STEEL, 1.4, 340, Abilities.STURDY, Abilities.MAGNET_PULL, Abilities.SAND_FORCE, 525, 60, 55, 145, 75, 150, 40, 60, 70, 184, GrowthRate.MEDIUM_FAST, 50, false), new PokemonSpecies(Species.DUSKNOIR, "Dusknoir", 4, false, false, false, "Gripper Pokémon", Type.GHOST, null, 2.2, 106.6, Abilities.PRESSURE, Abilities.NONE, Abilities.FRISK, 525, 45, 100, 135, 65, 135, 45, 45, 35, 263, GrowthRate.FAST, 50, false), @@ -3058,7 +3058,7 @@ export const speciesStarters = { [Species.FUECOCO]: 3, [Species.QUAXLY]: 3, [Species.LECHONK]: 2, - [Species.TAROUNTULA]: 2, + [Species.TAROUNTULA]: 1, [Species.NYMBLE]: 3, [Species.PAWMI]: 3, [Species.TANDEMAUS]: 4, diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index 10e88acc519..044bd4ec858 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -697,9 +697,9 @@ export const trainerConfigs: TrainerConfigs = { [TrainerType.GIOVANNI]: new TrainerConfig(++t).initForGymLeader([ Species.SANDILE, Species.MURKROW, Species.NIDORAN_M, Species.NIDORAN_F ], Type.DARK).setBattleBgm('battle_kanto_gym'), [TrainerType.FALKNER]: new TrainerConfig(++t).initForGymLeader([ Species.PIDGEY, Species.HOOTHOOT, Species.DODUO ], Type.FLYING).setBattleBgm('battle_johto_gym'), [TrainerType.BUGSY]: new TrainerConfig(++t).initForGymLeader([ Species.SCYTHER, Species.HERACROSS, Species.SHUCKLE, Species.PINSIR ], Type.BUG).setBattleBgm('battle_johto_gym'), - [TrainerType.WHITNEY]: new TrainerConfig(++t).initForGymLeader([ Species.CLEFAIRY, Species.MILTANK ], Type.NORMAL).setBattleBgm('battle_johto_gym'), + [TrainerType.WHITNEY]: new TrainerConfig(++t).initForGymLeader([ Species.GIRAFARIG, Species.MILTANK ], Type.NORMAL).setBattleBgm('battle_johto_gym'), [TrainerType.MORTY]: new TrainerConfig(++t).initForGymLeader([ Species.GASTLY, Species.MISDREAVUS, Species.SABLEYE ], Type.GHOST).setBattleBgm('battle_johto_gym'), - [TrainerType.CHUCK]: new TrainerConfig(++t).initForGymLeader([ Species.POLIWRATH, ], Type.FIGHTING).setBattleBgm('battle_johto_gym'), + [TrainerType.CHUCK]: new TrainerConfig(++t).initForGymLeader([ Species.POLIWRATH, Species.MANKEY ], Type.FIGHTING).setBattleBgm('battle_johto_gym'), [TrainerType.JASMINE]: new TrainerConfig(++t).initForGymLeader([ Species.MAGNEMITE, Species.STEELIX ], Type.STEEL).setBattleBgm('battle_johto_gym'), [TrainerType.PRYCE]: new TrainerConfig(++t).initForGymLeader([ Species.SEEL, Species.SWINUB ], Type.ICE).setBattleBgm('battle_johto_gym'), [TrainerType.CLAIR]: new TrainerConfig(++t).initForGymLeader([ Species.DRATINI, Species.HORSEA, Species.GYARADOS ], Type.DRAGON).setBattleBgm('battle_johto_gym'), diff --git a/src/egg-hatch-phase.ts b/src/egg-hatch-phase.ts index 9259e7b10a4..a28d8e2983c 100644 --- a/src/egg-hatch-phase.ts +++ b/src/egg-hatch-phase.ts @@ -82,7 +82,11 @@ export class EggHatchPhase extends Phase { this.eggContainer.add(this.eggLightraysOverlay); this.eggHatchContainer.add(this.eggContainer); - const getPokemonSprite = () => this.scene.add.sprite(this.eggHatchBg.displayWidth / 2, this.eggHatchBg.displayHeight / 2, `pkmn__sub`); + const getPokemonSprite = () => { + const ret = this.scene.add.sprite(this.eggHatchBg.displayWidth / 2, this.eggHatchBg.displayHeight / 2, `pkmn__sub`); + ret.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true }); + return ret; + }; this.eggHatchContainer.add((this.pokemonSprite = getPokemonSprite())); @@ -245,7 +249,7 @@ export class EggHatchPhase extends Phase { this.scene.validateAchv(achvs.HATCH_SHINY); this.eggContainer.setVisible(false); this.pokemonSprite.play(this.pokemon.getSpriteKey(true)); - this.pokemonSprite.pipelineData['ignoreTimeTint'] = true; + this.pokemonSprite.setPipelineData('ignoreTimeTint', true); this.pokemonSprite.setPipelineData('spriteKey', this.pokemon.getSpriteKey()); this.pokemonSprite.setPipelineData('shiny', this.pokemon.shiny); this.pokemonSprite.setPipelineData('variant', this.pokemon.variant); diff --git a/src/evolution-phase.ts b/src/evolution-phase.ts index fc58d141300..fb3803a1e75 100644 --- a/src/evolution-phase.ts +++ b/src/evolution-phase.ts @@ -71,7 +71,11 @@ export class EvolutionPhase extends Phase { this.evolutionBgOverlay.setAlpha(0); this.evolutionContainer.add(this.evolutionBgOverlay); - const getPokemonSprite = () => this.scene.addPokemonSprite(this.pokemon, this.evolutionBaseBg.displayWidth / 2, this.evolutionBaseBg.displayHeight / 2, `pkmn__sub`); + const getPokemonSprite = () => { + const ret = this.scene.addPokemonSprite(this.pokemon, this.evolutionBaseBg.displayWidth / 2, this.evolutionBaseBg.displayHeight / 2, `pkmn__sub`); + ret.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true }); + return ret; + }; this.evolutionContainer.add((this.pokemonSprite = getPokemonSprite())); this.evolutionContainer.add((this.pokemonTintSprite = getPokemonSprite())); @@ -92,7 +96,10 @@ export class EvolutionPhase extends Phase { [ this.pokemonSprite, this.pokemonTintSprite, this.pokemonEvoSprite, this.pokemonEvoTintSprite ].map(sprite => { sprite.play(this.pokemon.getSpriteKey(true)); sprite.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: false, teraColor: getTypeRgb(this.pokemon.getTeraType()) }); - sprite.pipelineData['ignoreTimeTint'] = true; + sprite.setPipelineData('ignoreTimeTint', true); + sprite.setPipelineData('spriteKey', this.pokemon.getSpriteKey()); + sprite.setPipelineData('shiny', this.pokemon.shiny); + sprite.setPipelineData('variant', this.pokemon.variant); [ 'spriteColors', 'fusionSpriteColors' ].map(k => { if (this.pokemon.summonData?.speciesForm) k += 'Base'; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 21a665fc3b1..608f0c55009 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1832,7 +1832,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return false; break; case StatusEffect.FREEZE: - if (this.isOfType(Type.ICE)) + if (this.isOfType(Type.ICE) || [WeatherType.SUNNY, WeatherType.HARSH_SUN].includes(this.scene?.arena.weather?.weatherType)) return false; break; case StatusEffect.BURN: diff --git a/src/locales/en/pokeball.ts b/src/locales/en/pokeball.ts new file mode 100644 index 00000000000..6f774d416b9 --- /dev/null +++ b/src/locales/en/pokeball.ts @@ -0,0 +1,8 @@ +export const pokeball = { + "pokeBall": "Poké Ball", + "greatBall": "Great Ball", + "ultraBall": "Ultra Ball", + "rogueBall": "Rogue Ball", + "masterBall": "Master Ball", + "luxuryBall": "Luxury Ball", +} as const; \ No newline at end of file diff --git a/src/locales/fr/move.ts b/src/locales/fr/move.ts index 3a7eca94275..c75c5448f53 100644 --- a/src/locales/fr/move.ts +++ b/src/locales/fr/move.ts @@ -1443,7 +1443,7 @@ export const move: MoveTranslations = { }, "healingWish": { name: "Voeu Soin", - effect: "Un soin qui permet au lanceur de récupérer jusqu’à la moitié de ses PV max." + effect: "Le lanceur tombe K.O. pour soigner les altérations de statut et les PV du Pokémon qui viendra le remplacer sur le terrain." }, "brine": { name: "Saumure", diff --git a/src/locales/fr/pokeball.ts b/src/locales/fr/pokeball.ts new file mode 100644 index 00000000000..0244550c5b2 --- /dev/null +++ b/src/locales/fr/pokeball.ts @@ -0,0 +1,8 @@ +export const pokeball = { + "pokeBall": "Poké Ball", + "greatBall": "Super Ball", + "ultraBall": "Hyper Ball", + "rogueBall": "Rogue Ball", + "masterBall": "Master Ball", + "luxuryBall": "Luxe Ball", +} as const; \ No newline at end of file diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 77d70954768..6197db23790 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -19,6 +19,7 @@ import { VoucherType, getVoucherTypeIcon, getVoucherTypeName } from '../system/v import { FormChangeItem, SpeciesFormChangeItemTrigger, pokemonFormChanges } from '../data/pokemon-forms'; import { ModifierTier } from './modifier-tier'; import { Nature, getNatureName, getNatureStatMultiplier } from '#app/data/nature'; +import { Localizable } from '#app/plugins/i18n'; const outputModifierData = false; const useMaxWeightForOutput = false; @@ -131,10 +132,19 @@ export interface GeneratedPersistentModifierType { getPregenArgs(): any[]; } -class AddPokeballModifierType extends ModifierType { +class AddPokeballModifierType extends ModifierType implements Localizable { + private pokeballType: PokeballType; + private count: integer; + constructor(pokeballType: PokeballType, count: integer, iconImage?: string) { - super(`${count}x ${getPokeballName(pokeballType)}`, `Receive ${getPokeballName(pokeballType)} x${count}\nCatch Rate: ${getPokeballCatchMultiplier(pokeballType) > -1 ? `${getPokeballCatchMultiplier(pokeballType)}x` : 'Certain'}`, - (_type, _args) => new Modifiers.AddPokeballModifier(this, pokeballType, count), iconImage, 'pb', 'pb_bounce_1'); + super('', '', (_type, _args) => new Modifiers.AddPokeballModifier(this, pokeballType, count), iconImage, 'pb', 'pb_bounce_1'); + this.pokeballType = pokeballType; + this.count = count; + } + + localize() { + this.name = `${this.count}x ${getPokeballName(this.pokeballType)}`; + this.description = `Receive ${getPokeballName(this.pokeballType)} x${this.count}\nCatch Rate: ${getPokeballCatchMultiplier(this.pokeballType) > -1 ? `${getPokeballCatchMultiplier(this.pokeballType)}x` : 'Certain'}`; } } diff --git a/src/phases.ts b/src/phases.ts index 98d474390b7..31f631bf4a6 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -30,7 +30,7 @@ import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, get import { TempBattleStat } from "./data/temp-battle-stat"; import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag"; import { ArenaTagType } from "./data/enums/arena-tag-type"; -import { CheckTrappedAbAttr, MoveAbilityBypassAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs } from "./data/ability"; +import { CheckTrappedAbAttr, MoveAbilityBypassAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr } from "./data/ability"; import { Unlockables, getUnlockableName } from "./system/unlockables"; import { getBiomeKey } from "./field/arena"; import { BattleType, BattlerIndex, TurnCommand } from "./battle"; @@ -379,6 +379,33 @@ export class UnavailablePhase extends Phase { } } +export class ReloadSessionPhase extends Phase { + constructor(scene: BattleScene) { + super(scene); + } + + start(): void { + this.scene.ui.setMode(Mode.SESSION_RELOAD); + + let delayElapsed = false; + let loaded = false; + + this.scene.time.delayedCall(Utils.fixedInt(1500), () => { + if (loaded) + this.end(); + else + delayElapsed = true; + }); + + this.scene.gameData.loadSystem().then(() => { + if (delayElapsed) + this.end(); + else + loaded = true; + }); + } +} + export class OutdatedPhase extends Phase { constructor(scene: BattleScene) { super(scene); @@ -767,7 +794,8 @@ export class EncounterPhase extends BattlePhase { pokemon.resetBattleData(); } - this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false); + if (!this.loaded) + this.scene.arena.trySetWeather(getRandomWeatherType(this.scene.arena), false); const enemyField = this.scene.getEnemyField(); this.scene.tweens.add({ @@ -2173,7 +2201,7 @@ export class MovePhase extends BattlePhase { const targets = this.scene.getField(true).filter(p => { if (this.targets.indexOf(p.getBattlerIndex()) > -1) { const hiddenTag = p.getTag(HiddenTag); - if (hiddenTag && !this.move.getMove().getAttrs(HitsTagAttr).filter(hta => (hta as HitsTagAttr).tagType === hiddenTag.tagType).length) + if (hiddenTag && !this.move.getMove().getAttrs(HitsTagAttr).filter(hta => (hta as HitsTagAttr).tagType === hiddenTag.tagType).length && !p.hasAbilityWithAttr(AlwaysHitAbAttr) && !this.pokemon.hasAbilityWithAttr(AlwaysHitAbAttr)) return false; return true; } @@ -2467,6 +2495,9 @@ export class MoveEffectPhase extends PokemonPhase { if (user.turnData.hitsLeft < user.turnData.hitCount) return true; + if (user.hasAbilityWithAttr(AlwaysHitAbAttr) || target.hasAbilityWithAttr(AlwaysHitAbAttr)) + return true; + const hiddenTag = target.getTag(HiddenTag); if (hiddenTag && !this.move.getMove().getAttrs(HitsTagAttr).filter(hta => (hta as HitsTagAttr).tagType === hiddenTag.tagType).length) return false; @@ -3389,6 +3420,8 @@ export class GameOverPhase extends BattlePhase { handleClearSession(): void { this.scene.gameData.tryClearSession(this.scene, this.scene.sessionSlotId).then((success: boolean | [boolean, boolean]) => { + if (!success[0]) + return this.scene.reset(true); this.scene.time.delayedCall(1000, () => { let firstClear = false; if (this.victory && success[1]) { @@ -4296,7 +4329,7 @@ export class EggLapsePhase extends Phase { const eggsToHatch: Egg[] = this.scene.gameData.eggs.filter((egg: Egg) => { return --egg.hatchWaves < 1 - }) + }); if (eggsToHatch.length) { this.scene.queueMessage('Oh?'); diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts index 9a72ff55f9d..eabafd82c76 100644 --- a/src/plugins/i18n.ts +++ b/src/plugins/i18n.ts @@ -6,6 +6,9 @@ import { menu as frMenu } from '../locales/fr/menu'; import { move as enMove } from '../locales/en/move'; import { move as frMove } from '../locales/fr/move'; +import { pokeball as enPokeball } from '../locales/en/pokeball'; +import { pokeball as frPokeball } from '../locales/fr/pokeball'; + export interface MoveTranslationEntry { name: string, effect: string @@ -50,6 +53,7 @@ export function initI18n(): void { en: { menu: enMenu, move: enMove, + pokeball: enPokeball, }, it: { menu: itMenu, @@ -57,6 +61,7 @@ export function initI18n(): void { fr: { menu: frMenu, move: frMove, + pokeball: frPokeball, } }, }); @@ -68,6 +73,7 @@ declare module 'i18next' { resources: { menu: typeof enMenu; move: typeof enMove; + pokeball: typeof enPokeball; }; } } diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 88fcb2ce736..c5b9f32cf9c 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -1,7 +1,7 @@ import BattleScene, { PokeballCounts, bypassLogin } from "../battle-scene"; import Pokemon, { EnemyPokemon, PlayerPokemon } from "../field/pokemon"; import { pokemonEvolutions, pokemonPrevolutions } from "../data/pokemon-evolutions"; -import PokemonSpecies, { SpeciesFormKey, allSpecies, getPokemonSpecies, noStarterFormKeys, speciesStarters } from "../data/pokemon-species"; +import PokemonSpecies, { allSpecies, getPokemonSpecies, noStarterFormKeys, speciesStarters } from "../data/pokemon-species"; import { Species, defaultStarterSpecies } from "../data/enums/species"; import * as Utils from "../utils"; import PokemonData from "./pokemon-data"; @@ -27,7 +27,7 @@ import { Moves } from "../data/enums/moves"; import { speciesEggMoves } from "../data/egg-moves"; import { allMoves } from "../data/move"; import { TrainerVariant } from "../field/trainer"; -import { OutdatedPhase, UnavailablePhase } from "#app/phases"; +import { OutdatedPhase, ReloadSessionPhase } from "#app/phases"; import { Variant, variantData } from "#app/data/variant"; const saveKey = 'x0i2O7WRiANTqPmZ'; // Temporary; secure encryption is not yet necessary @@ -280,6 +280,9 @@ export class GameData { if (error.startsWith('client version out of date')) { this.scene.clearPhaseQueue(); this.scene.unshiftPhase(new OutdatedPhase(this.scene)); + } else if (error.startsWith('session out of date')) { + this.scene.clearPhaseQueue(); + this.scene.unshiftPhase(new ReloadSessionPhase(this.scene)); } console.error(error); return resolve(false); @@ -340,7 +343,7 @@ export class GameData { this.starterData[s].eggMoves = starterEggMoveData[s]; } - this.migrateStarterAbilities(systemData); + this.migrateStarterAbilities(systemData, this.starterData); } else { if ([ '1.0.0', '1.0.1' ].includes(systemData.gameVersion)) this.migrateStarterAbilities(systemData); @@ -551,6 +554,10 @@ export class GameData { .then(response => response.text()) .then(error => { if (error) { + if (error.startsWith('session out of date')) { + this.scene.clearPhaseQueue(); + this.scene.unshiftPhase(new ReloadSessionPhase(this.scene)); + } console.error(error); return resolve(false); } @@ -715,9 +722,19 @@ export class GameData { Utils.apiFetch(`savedata/delete?datatype=${GameDataType.SESSION}&slot=${slotId}`, true).then(response => { if (response.ok) { loggedInUser.lastSessionSlot = -1; - return resolve(true); + resolve(true); } - resolve(false); + return response.text(); + }).then(error => { + if (error) { + if (error.startsWith('session out of date')) { + this.scene.clearPhaseQueue(); + this.scene.unshiftPhase(new ReloadSessionPhase(this.scene)); + } + console.error(error); + resolve(false); + } + resolve(true); }); }); }); @@ -735,12 +752,19 @@ export class GameData { return resolve([false, false]); const sessionData = this.getSessionSaveData(scene); Utils.apiPost(`savedata/clear?slot=${slotId}`, JSON.stringify(sessionData)).then(response => { - if (response.ok) { + if (response.ok) loggedInUser.lastSessionSlot = -1; - return response.json(); + return response.json(); + }).then(jsonResponse => { + if (!jsonResponse.error) + return resolve([true, jsonResponse.success as boolean]); + if (jsonResponse && jsonResponse.error.startsWith('session out of date')) { + this.scene.clearPhaseQueue(); + this.scene.unshiftPhase(new ReloadSessionPhase(this.scene)); } + console.error(jsonResponse); resolve([false, false]); - }).then(jsonResponse => resolve([true, jsonResponse.success as boolean])); + }); }); }); } @@ -1207,9 +1231,9 @@ export class GameData { } } - migrateStarterAbilities(systemData: SystemSaveData): void { + migrateStarterAbilities(systemData: SystemSaveData, initialStarterData?: StarterData): void { const starterIds = Object.keys(this.starterData).map(s => parseInt(s) as Species); - const starterData = systemData.starterData; + const starterData = initialStarterData || systemData.starterData; const dexData = systemData.dexData; for (let s of starterIds) { const dexAttr = dexData[s].caughtAttr; diff --git a/src/ui/menu-ui-handler.ts b/src/ui/menu-ui-handler.ts index 88a80f7d21d..8b2c5646903 100644 --- a/src/ui/menu-ui-handler.ts +++ b/src/ui/menu-ui-handler.ts @@ -336,10 +336,14 @@ export default class MenuUiHandler extends MessageUiHandler { case Button.UP: if (this.cursor) success = this.setCursor(this.cursor - 1); + else + success = this.setCursor(this.menuOptions.length - 1); break; case Button.DOWN: if (this.cursor + 1 < this.menuOptions.length) success = this.setCursor(this.cursor + 1); + else + success = this.setCursor(0); break; } } diff --git a/src/ui/session-reload-modal-ui-handler.ts b/src/ui/session-reload-modal-ui-handler.ts new file mode 100644 index 00000000000..fdcd9b2c206 --- /dev/null +++ b/src/ui/session-reload-modal-ui-handler.ts @@ -0,0 +1,47 @@ +import BattleScene from "../battle-scene"; +import { ModalConfig, ModalUiHandler } from "./modal-ui-handler"; +import { addTextObject, TextStyle } from "./text"; +import { Mode } from "./ui"; + +export default class SessionReloadModalUiHandler extends ModalUiHandler { + constructor(scene: BattleScene, mode?: Mode) { + super(scene, mode); + } + + getModalTitle(): string { + return ''; + } + + getWidth(): number { + return 160; + } + + getHeight(): number { + return 32; + } + + getMargin(): [number, number, number, number] { + return [ 0, 0, 48, 0 ]; + } + + getButtonLabels(): string[] { + return [ ]; + } + + setup(): void { + super.setup(); + + const label = addTextObject(this.scene, this.getWidth() / 2, this.getHeight() / 2, 'Your session is out of date.\nYour data will be reloaded…', TextStyle.WINDOW, { fontSize: '48px', align: 'center' }); + label.setOrigin(0.5, 0.5); + + this.modalContainer.add(label); + } + + show(args: any[]): boolean { + const config: ModalConfig = { + buttonActions: [] + }; + + return super.show([ config ]); + } +} \ No newline at end of file diff --git a/src/ui/ui.ts b/src/ui/ui.ts index f1fe29d9035..6e20b2cb8b8 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -34,6 +34,7 @@ import TitleUiHandler from './title-ui-handler'; import SavingIconHandler from './saving-icon-handler'; import UnavailableModalUiHandler from './unavailable-modal-ui-handler'; import OutdatedModalUiHandler from './outdated-modal-ui-handler'; +import SessionReloadModalUiHandler from './session-reload-modal-ui-handler'; export enum Mode { MESSAGE, @@ -62,6 +63,7 @@ export enum Mode { LOGIN_FORM, REGISTRATION_FORM, LOADING, + SESSION_RELOAD, UNAVAILABLE, OUTDATED }; @@ -90,6 +92,7 @@ const noTransitionModes = [ Mode.LOGIN_FORM, Mode.REGISTRATION_FORM, Mode.LOADING, + Mode.SESSION_RELOAD, Mode.UNAVAILABLE, Mode.OUTDATED ]; @@ -141,6 +144,7 @@ export default class UI extends Phaser.GameObjects.Container { new LoginFormUiHandler(scene), new RegistrationFormUiHandler(scene), new LoadingModalUiHandler(scene), + new SessionReloadModalUiHandler(scene), new UnavailableModalUiHandler(scene), new OutdatedModalUiHandler(scene) ];