diff --git a/public/images/ui/game_mode_select_window.png b/public/images/ui/game_mode_select_window.png new file mode 100644 index 00000000000..ee36c93ffd2 Binary files /dev/null and b/public/images/ui/game_mode_select_window.png differ diff --git a/src/arena.ts b/src/arena.ts index 5cd0759c23c..001002b547e 100644 --- a/src/arena.ts +++ b/src/arena.ts @@ -10,6 +10,7 @@ import { CommonAnim } from "./data/battle-anims"; import { Type } from "./data/type"; import Move, { Moves } from "./data/move"; import { ArenaTag, ArenaTagType, getArenaTag } from "./data/arena-tag"; +import { GameMode } from "./game-mode"; export class Arena { public scene: BattleScene; @@ -29,7 +30,8 @@ export class Arena { } randomSpecies(waveIndex: integer, level: integer, attempt?: integer): PokemonSpecies { - const isBoss = waveIndex % 10 === 0 && !!this.pokemonPool[BiomePoolTier.BOSS].length; + const isBoss = waveIndex % 10 === 0 && !!this.pokemonPool[BiomePoolTier.BOSS].length + && (this.biomeType !== Biome.END || this.scene.gameMode !== GameMode.ENDLESS || waveIndex % 250 === 0); const tierValue = Utils.randInt(!isBoss ? 512 : 64); let tier = !isBoss ? tierValue >= 156 ? BiomePoolTier.COMMON : tierValue >= 32 ? BiomePoolTier.UNCOMMON : tierValue >= 6 ? BiomePoolTier.RARE : tierValue >= 1 ? BiomePoolTier.SUPER_RARE : BiomePoolTier.ULTRA_RARE diff --git a/src/battle-phases.ts b/src/battle-phases.ts index ba0f103cae2..38d6466a641 100644 --- a/src/battle-phases.ts +++ b/src/battle-phases.ts @@ -29,6 +29,7 @@ import { CheckTrappedAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, import { Unlockables, getUnlockableName } from "./system/unlockables"; import { getBiomeKey } from "./arena"; import { BattlerIndex, TurnCommand } from "./battle"; +import { GameMode } from "./game-mode"; export class CheckLoadPhase extends BattlePhase { private loaded: boolean; @@ -369,9 +370,16 @@ export class SelectBiomePhase extends BattlePhase { this.end(); }; - if (this.scene.currentBattle.waveIndex === this.scene.finalWave - 9) + if (this.scene.gameMode === GameMode.CLASSIC && this.scene.currentBattle.waveIndex === this.scene.finalWave - 9) setNextBiome(Biome.END); - else if (Array.isArray(biomeLinks[currentBiome])) { + else if (this.scene.gameMode === GameMode.ENDLESS) { + if (this.scene.currentBattle.waveIndex % 50 === 0) + setNextBiome(Biome.END); + else { + const allBiomes = Utils.getEnumValues(Biome); + setNextBiome(allBiomes[Utils.randInt(allBiomes.length - 2, 1)]); + } + } else if (Array.isArray(biomeLinks[currentBiome])) { const biomes = biomeLinks[currentBiome] as Biome[]; if (this.scene.findModifier(m => m instanceof MapModifier)) { this.scene.ui.setMode(Mode.BIOME_SELECT, currentBiome, (biomeIndex: integer) => { @@ -1841,7 +1849,7 @@ export class VictoryPhase extends PokemonPhase { if (!this.scene.getEnemyField().filter(p => !p?.isFainted(true)).length) { this.scene.pushPhase(new BattleEndPhase(this.scene)); - if (this.scene.currentBattle.waveIndex < this.scene.finalWave) { + if (this.scene.gameMode === GameMode.ENDLESS || this.scene.currentBattle.waveIndex < this.scene.finalWave) { this.scene.pushPhase(new SelectModifierPhase(this.scene)); this.scene.pushPhase(new NewBattlePhase(this.scene)); } else @@ -1880,6 +1888,8 @@ export class GameOverPhase extends BattlePhase { } end(): void { + if (!this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) + this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.ENDLESS_MODE)); if (!this.scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE]) this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.MINI_BLACK_HOLE)); @@ -2417,7 +2427,7 @@ export class SelectModifierPhase extends BattlePhase { if (toSlotIndex !== undefined && fromSlotIndex < 6 && toSlotIndex < 6 && fromSlotIndex !== toSlotIndex && itemIndex > -1) { this.scene.ui.setMode(Mode.MODIFIER_SELECT).then(() => { const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier - && (m as PokemonHeldItemModifier).pokemonId === party[fromSlotIndex].id) as PokemonHeldItemModifier[]; + && (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === party[fromSlotIndex].id) as PokemonHeldItemModifier[]; const itemModifier = itemModifiers[itemIndex]; this.scene.tryTransferHeldItemModifier(itemModifier, party[toSlotIndex], true, true).then(success => { if (success) { diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 088022ddaae..e5a9712d36e 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -21,6 +21,7 @@ import { getDefaultModifierTypeForTier, getEnemyModifierTypesForWave } from './m import AbilityBar from './ui/ability-bar'; import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, applyAbAttrs, initAbilities } from './data/ability'; import Battle from './battle'; +import { GameMode } from './game-mode'; const enableAuto = true; const quickStart = false; @@ -73,6 +74,7 @@ export default class BattleScene extends Phaser.Scene { public arenaEnemy: ArenaBase; public arenaNextEnemy: ArenaBase; public arena: Arena; + public gameMode: GameMode; public trainer: Phaser.GameObjects.Sprite; public currentBattle: Battle; public pokeballCounts: PokeballCounts; @@ -167,6 +169,7 @@ export default class BattleScene extends Phaser.Scene { this.loadImage('ability_bar', 'ui'); this.loadImage('ball_window', 'ui'); this.loadImage('boolean_window', 'ui'); + this.loadImage('game_mode_select_window', 'ui'); this.loadImage('party_bg', 'ui'); this.loadImage('party_bg_double', 'ui'); @@ -530,7 +533,7 @@ export default class BattleScene extends Phaser.Scene { if (!waveIndex) { if (lastBattle) { this.getEnemyField().forEach(enemyPokemon => enemyPokemon.destroy()); - if (lastBattle.waveIndex % 10) + if (this.gameMode === GameMode.CLASSIC && lastBattle.waveIndex % 10) this.pushPhase(new NextEncounterPhase(this)); else { this.pushPhase(new SelectBiomePhase(this)); diff --git a/src/game-mode.ts b/src/game-mode.ts new file mode 100644 index 00000000000..0247e024e19 --- /dev/null +++ b/src/game-mode.ts @@ -0,0 +1,4 @@ +export enum GameMode { + CLASSIC, + ENDLESS +} \ No newline at end of file diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index bead50fc74a..61c1d9bc230 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -11,6 +11,7 @@ import * as Utils from '../utils'; import { TempBattleStat, getTempBattleStatBoosterItemName, getTempBattleStatName } from '../data/temp-battle-stat'; import { BerryType, getBerryEffectDescription, getBerryName } from '../data/berry'; import { Unlockables } from '../system/unlockables'; +import { GameMode } from '../game-mode'; type Modifier = Modifiers.Modifier; @@ -694,7 +695,7 @@ const modifierPool = { const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => (m.getMove().pp - m.ppUsed) <= 5).length).length, 3); return thresholdPartyMemberCount; }), - new WeightedModifierType(modifierTypes.MAP, 1), + new WeightedModifierType(modifierTypes.MAP, (party: Pokemon[]) => party[0].scene.gameMode === GameMode.CLASSIC ? 1 : 0), new WeightedModifierType(modifierTypes.TM_GREAT, 2), new WeightedModifierType(modifierTypes.EXP_SHARE, 1), new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 3) @@ -745,8 +746,7 @@ const enemyModifierPool = { new WeightedModifierType(modifierTypes.SHELL_BELL, 1), ].map(m => { m.setTier(ModifierTier.ULTRA); return m; }), [ModifierTier.MASTER]: [ - new WeightedModifierType(modifierTypes.GOLDEN_EGG, 1), - new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, 1) + new WeightedModifierType(modifierTypes.GOLDEN_EGG, 1) ].map(m => { m.setTier(ModifierTier.MASTER); return m; }) }; diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 9baf34890d1..4446289acfe 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -283,6 +283,10 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier { return super.shouldApply(args) && args.length && args[0] instanceof Pokemon && (this.pokemonId === -1 || (args[0] as Pokemon).id === this.pokemonId); } + getTransferrable(withinParty: boolean) { + return true; + } + getIcon(scene: BattleScene, forSummary?: boolean): Phaser.GameObjects.Container { const container = !forSummary ? scene.add.container(0, 0) : super.getIcon(scene); @@ -357,6 +361,10 @@ export class PokemonBaseStatModifier extends PokemonHeldItemModifier { return true; } + + getTransferrable(_withinParty: boolean): boolean { + return false; + } } export class AttackTypeBoosterModifier extends PokemonHeldItemModifier { @@ -1014,9 +1022,11 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { if (!transferredItemCount) return false; + const withinParty = pokemon.isPlayer() === targetPokemon.isPlayer(); + const transferredModifierTypes: ModifierTypes.ModifierType[] = []; const itemModifiers = pokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier - && (m as PokemonHeldItemModifier).pokemonId === targetPokemon.id && !m.matchType(this), targetPokemon.isPlayer()) as PokemonHeldItemModifier[]; + && (m as PokemonHeldItemModifier).pokemonId === targetPokemon.id && m.getTransferrable(withinParty), targetPokemon.isPlayer()) as PokemonHeldItemModifier[]; for (let i = 0; i < transferredItemCount; i++) { if (!itemModifiers.length) @@ -1053,6 +1063,10 @@ export class TurnHeldItemTransferModifier extends HeldItemTransferModifier { return new TurnHeldItemTransferModifier(this.type, this.pokemonId, this.stackCount); } + getTransferrable(withinParty: boolean) { + return withinParty; + } + getTransferredItemCount(): integer { return this.getStackCount(); } diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 1e039df5949..44c1d9409f1 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -10,6 +10,7 @@ import PersistentModifierData from "./modifier-data"; import { PokemonHeldItemModifier } from "../modifier/modifier"; import ArenaData from "./arena-data"; import { Unlockables } from "./unlockables"; +import { GameMode } from "../game-mode"; interface SystemSaveData { trainerId: integer; @@ -20,6 +21,7 @@ interface SystemSaveData { } interface SessionSaveData { + gameMode: GameMode; party: PokemonData[]; enemyField: PokemonData[]; modifiers: PersistentModifierData[]; @@ -75,6 +77,7 @@ export class GameData { this.trainerId = Utils.randInt(65536); this.secretId = Utils.randInt(65536); this.unlocks = { + [Unlockables.ENDLESS_MODE]: false, [Unlockables.MINI_BLACK_HOLE]: false }; this.initDexData(); @@ -125,6 +128,7 @@ export class GameData { saveSession(scene: BattleScene): boolean { const sessionData = { + gameMode: scene.gameMode, party: scene.getParty().map(p => new PokemonData(p)), enemyField: scene.getEnemyField().map(p => new PokemonData(p)), modifiers: scene.findModifiers(() => true).map(m => new PersistentModifierData(m, true)), @@ -176,6 +180,8 @@ export class GameData { console.debug(sessionData); + scene.gameMode = sessionData.gameMode || GameMode.CLASSIC; + const loadPokemonAssets: Promise[] = []; const party = scene.getParty(); diff --git a/src/system/unlockables.ts b/src/system/unlockables.ts index aa3e58e9796..aa0e85dd093 100644 --- a/src/system/unlockables.ts +++ b/src/system/unlockables.ts @@ -1,9 +1,12 @@ export enum Unlockables { + ENDLESS_MODE, MINI_BLACK_HOLE } export function getUnlockableName(unlockable: Unlockables) { switch (unlockable) { + case Unlockables.ENDLESS_MODE: + return 'Endless Mode'; case Unlockables.MINI_BLACK_HOLE: return 'MINI BLACK HOLE'; } diff --git a/src/ui/confirm-ui-handler.ts b/src/ui/confirm-ui-handler.ts index a3fcca03feb..12cd43e160c 100644 --- a/src/ui/confirm-ui-handler.ts +++ b/src/ui/confirm-ui-handler.ts @@ -1,17 +1,9 @@ import BattleScene, { Button } from "../battle-scene"; +import OptionSelectUiHandler from "./option-select-ui-handler"; import { addTextObject, TextStyle } from "./text"; import { Mode } from "./ui"; -import UiHandler from "./uiHandler"; - -export default class ConfirmUiHandler extends UiHandler { - private yesHandler: Function; - private noHander: Function; - - private confirmContainer: Phaser.GameObjects.Container; - private confirmBg: Phaser.GameObjects.Image; - - private cursorObj: Phaser.GameObjects.Image; +export default class ConfirmUiHandler extends OptionSelectUiHandler { private switchCheck: boolean; private switchCheckCursor: integer; @@ -19,94 +11,34 @@ export default class ConfirmUiHandler extends UiHandler { super(scene, Mode.CONFIRM); } - setup() { - const ui = this.getUi(); - - this.confirmContainer = this.scene.add.container((this.scene.game.canvas.width / 6) - 49, -49); - this.confirmContainer.setVisible(false); - ui.add(this.confirmContainer); + getWindowName(): string { + return 'boolean_window'; + } - this.confirmBg = this.scene.add.image(0, 0, 'boolean_window'); - this.confirmBg.setOrigin(0, 1); - this.confirmContainer.add(this.confirmBg); + getWindowWidth(): integer { + return 48; + } - const confirmText = addTextObject(this.scene, 0, 0, 'Yes\nNo', TextStyle.WINDOW, { maxLines: 2 }); - confirmText.setPositionRelative(this.confirmBg, 16, 9); - confirmText.setLineSpacing(12); - this.confirmContainer.add(confirmText); - - this.setCursor(0); + getOptions(): string[] { + return [ 'Yes', 'No' ]; } show(args: any[]) { if (args.length >= 2 && args[0] instanceof Function && args[1] instanceof Function) { super.show(args); - this.yesHandler = args[0] as Function; - this.noHander = args[1] as Function; this.switchCheck = args.length >= 3 && args[2] as boolean; - this.confirmContainer.setVisible(true); this.setCursor(this.switchCheck ? this.switchCheckCursor : 0); } } - processInput(button: Button) { - const ui = this.getUi(); - - let success = false; - - if (button === Button.ACTION || button === Button.CANCEL) { - success = true; - if (button === Button.CANCEL) - this.setCursor(1); - const handler = this.cursor ? this.noHander : this.yesHandler; - handler(); - this.clear(); - } else { - switch (button) { - case Button.UP: - if (this.cursor) - success = this.setCursor(0); - break; - case Button.DOWN: - if (!this.cursor) - success = this.setCursor(1); - break; - } - } - - if (success) - ui.playSelect(); - } - setCursor(cursor: integer): boolean { const ret = super.setCursor(cursor); if (ret && this.switchCheck) this.switchCheckCursor = this.cursor; - if (!this.cursorObj) { - this.cursorObj = this.scene.add.image(0, 0, 'cursor'); - this.confirmContainer.add(this.cursorObj); - } - - this.cursorObj.setPositionRelative(this.confirmBg, 12, this.cursor ? 33 : 17); - return ret; } - - clear() { - super.clear(); - this.yesHandler = null; - this.noHander = null; - this.confirmContainer.setVisible(false); - this.eraseCursor(); - } - - eraseCursor() { - if (this.cursorObj) - this.cursorObj.destroy(); - this.cursorObj = null; - } } \ No newline at end of file diff --git a/src/ui/game-mode-select-ui-handler.ts b/src/ui/game-mode-select-ui-handler.ts new file mode 100644 index 00000000000..2092a945d0d --- /dev/null +++ b/src/ui/game-mode-select-ui-handler.ts @@ -0,0 +1,22 @@ +import BattleScene from "../battle-scene"; +import OptionSelectUiHandler from "./option-select-ui-handler"; +import { Mode } from "./ui"; + +export default class GameModeSelectUiHandler extends OptionSelectUiHandler { + + constructor(scene: BattleScene) { + super(scene, Mode.GAME_MODE_SELECT); + } + + getWindowName(): string { + return 'game_mode_select_window'; + } + + getWindowWidth(): integer { + return 64; + } + + getOptions(): string[] { + return [ 'Classic', 'Endless', 'Cancel' ]; + } +} \ No newline at end of file diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index 609873add5a..f6d3208b523 100644 --- a/src/ui/modifier-select-ui-handler.ts +++ b/src/ui/modifier-select-ui-handler.ts @@ -61,7 +61,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { this.getUi().clearText(); - const partyHasHeldItem = !!this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier).length; + const partyHasHeldItem = !!this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).getTransferrable(true)).length; this.transferButtonContainer.setVisible(false); this.transferButtonContainer.setAlpha(0); diff --git a/src/ui/option-select-ui-handler.ts b/src/ui/option-select-ui-handler.ts new file mode 100644 index 00000000000..78b5007d129 --- /dev/null +++ b/src/ui/option-select-ui-handler.ts @@ -0,0 +1,115 @@ +import BattleScene, { Button } from "../battle-scene"; +import { TextStyle, addTextObject } from "./text"; +import { Mode } from "./ui"; +import UiHandler from "./uiHandler"; + +export default abstract class OptionSelectUiHandler extends UiHandler { + protected handlers: Function[]; + + protected optionSelectContainer: Phaser.GameObjects.Container; + protected optionSelectBg: Phaser.GameObjects.Image; + + private cursorObj: Phaser.GameObjects.Image; + + constructor(scene: BattleScene, mode?: Mode) { + super(scene, mode); + } + + abstract getWindowName(): string; + + abstract getWindowWidth(): integer; + + abstract getOptions(): string[]; + + setup() { + const ui = this.getUi(); + + this.optionSelectContainer = this.scene.add.container((this.scene.game.canvas.width / 6) - (this.getWindowWidth() + 1), -(this.getWindowWidth() + 1)); + this.optionSelectContainer.setVisible(false); + ui.add(this.optionSelectContainer); + + this.optionSelectBg = this.scene.add.image(0, 0, this.getWindowName()); + this.optionSelectBg.setOrigin(0, 1); + this.optionSelectContainer.add(this.optionSelectBg); + + const options = this.getOptions(); + + const optionSelectText = addTextObject(this.scene, 0, 0, options.join('\n'), TextStyle.WINDOW, { maxLines: options.length }); + optionSelectText.setPositionRelative(this.optionSelectBg, 16, 9); + optionSelectText.setLineSpacing(12); + this.optionSelectContainer.add(optionSelectText); + + this.setCursor(0); + } + + show(args: any[]) { + const options = this.getOptions(); + + if (args.length >= options.length && args[0] instanceof Function && args[1] instanceof Function) { + super.show(args); + + this.handlers = args.slice(0, options.length) as Function[]; + + this.optionSelectContainer.setVisible(true); + this.setCursor(0); + } + } + + processInput(button: Button) { + const ui = this.getUi(); + + let success = false; + + const options = this.getOptions(); + + if (button === Button.ACTION || button === Button.CANCEL) { + success = true; + if (button === Button.CANCEL) + this.setCursor(options.length - 1); + const handler = this.handlers[this.cursor]; + handler(); + this.clear(); + } else { + switch (button) { + case Button.UP: + if (this.cursor) + success = this.setCursor(this.cursor - 1); + break; + case Button.DOWN: + if (this.cursor < options.length - 1) + success = this.setCursor(this.cursor + 1); + break; + } + } + + if (success) + ui.playSelect(); + } + + setCursor(cursor: integer): boolean { + const ret = super.setCursor(cursor); + + if (!this.cursorObj) { + this.cursorObj = this.scene.add.image(0, 0, 'cursor'); + this.optionSelectContainer.add(this.cursorObj); + } + + this.cursorObj.setPositionRelative(this.optionSelectBg, 12, 17 + this.cursor * 16); + + return ret; + } + + clear() { + super.clear(); + for (let h = 0; h < this.handlers.length; h++) + this.handlers[h] = null; + this.optionSelectContainer.setVisible(false); + this.eraseCursor(); + } + + eraseCursor() { + if (this.cursorObj) + this.cursorObj.destroy(); + this.cursorObj = null; + } +} \ No newline at end of file diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index acf737fe69d..748a7045369 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -200,7 +200,7 @@ export default class PartyUiHandler extends MessageUiHandler { filterResult = this.moveSelectFilter(pokemon.moveset[this.optionsCursor]); } else { const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier - && (m as PokemonHeldItemModifier).pokemonId === pokemon.id) as PokemonHeldItemModifier[]; + && (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === pokemon.id) as PokemonHeldItemModifier[]; filterResult = (this.selectFilter as PokemonModifierTransferSelectFilter)(pokemon, itemModifiers[this.transferOptionCursor]); } if (filterResult === null) { @@ -409,7 +409,8 @@ export default class PartyUiHandler extends MessageUiHandler { const pokemon = this.scene.getParty()[this.cursor]; const itemModifiers = this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER - ? this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).pokemonId === pokemon.id) as PokemonHeldItemModifier[] + ? this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier + && (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === pokemon.id) as PokemonHeldItemModifier[] : null; if (this.partyUiMode !== PartyUiMode.MOVE_MODIFIER && (this.transferMode || this.partyUiMode !== PartyUiMode.MODIFIER_TRANSFER)) { diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 3c984a09ad3..114d62b778b 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -9,6 +9,8 @@ import { DexEntryDetails, StarterDexUnlockTree } from "../system/game-data"; import { Gender, getGenderColor, getGenderSymbol } from "../data/gender"; import { pokemonPrevolutions } from "../data/pokemon-evolutions"; import { abilities } from "../data/ability"; +import { GameMode } from "../game-mode"; +import { Unlockables } from "../system/unlockables"; export type StarterSelectCallback = (starters: Starter[]) => void; @@ -269,26 +271,37 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (this.speciesLoaded.get(species.speciesId)) species.cry(this.scene); if (this.starterCursors.length === 3) { + const cancel = () => { + ui.setMode(Mode.STARTER_SELECT); + this.popStarter(); + this.clearText(); + }; ui.showText('Begin with these POKéMON?', null, () => { ui.setModeWithoutClear(Mode.CONFIRM, () => { - ui.setMode(Mode.STARTER_SELECT); - const thisObj = this; - const originalStarterSelectCallback = this.starterSelectCallback; - this.starterSelectCallback = null; - originalStarterSelectCallback(new Array(3).fill(0).map(function (_, i) { - return { - species: thisObj.genSpecies[thisObj.starterGens[i]][thisObj.starterCursors[i]], - shiny: thisObj.starterDetails[i][0], - formIndex: thisObj.starterDetails[i][1], - female: thisObj.starterDetails[i][2], - abilityIndex: thisObj.starterDetails[i][3] - }; - })); - }, () => { - ui.setMode(Mode.STARTER_SELECT); - this.popStarter(); - this.clearText(); - }); + const startRun = (gameMode: GameMode) => { + this.scene.gameMode = gameMode; + ui.setMode(Mode.STARTER_SELECT); + const thisObj = this; + const originalStarterSelectCallback = this.starterSelectCallback; + this.starterSelectCallback = null; + originalStarterSelectCallback(new Array(3).fill(0).map(function (_, i) { + return { + species: thisObj.genSpecies[thisObj.starterGens[i]][thisObj.starterCursors[i]], + shiny: thisObj.starterDetails[i][0], + formIndex: thisObj.starterDetails[i][1], + female: thisObj.starterDetails[i][2], + abilityIndex: thisObj.starterDetails[i][3] + }; + })); + }; + if (this.scene.gameData.unlocks[Unlockables.ENDLESS_MODE]) { + ui.setMode(Mode.STARTER_SELECT); + ui.showText('Select a game mode.', null, () => { + ui.setModeWithoutClear(Mode.GAME_MODE_SELECT, () => startRun(GameMode.CLASSIC), () => startRun(GameMode.ENDLESS), cancel); + }); + } else + startRun(GameMode.CLASSIC); + }, cancel); }); } success = true; diff --git a/src/ui/ui.ts b/src/ui/ui.ts index 13778608ffe..45dce7ba308 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -13,6 +13,7 @@ import StarterSelectUiHandler from './starter-select-ui-handler'; import EvolutionSceneHandler from './evolution-scene-handler'; import BiomeSelectUiHandler from './biome-select-ui-handler'; import TargetSelectUiHandler from './target-select-ui-handler'; +import GameModeSelectUiHandler from './game-mode-select-ui-handler'; export enum Mode { MESSAGE, @@ -26,7 +27,8 @@ export enum Mode { BIOME_SELECT, STARTER_SELECT, EVOLUTION_SCENE, - CONFIRM + CONFIRM, + GAME_MODE_SELECT }; const transitionModes = [ @@ -37,7 +39,8 @@ const transitionModes = [ ]; const noTransitionModes = [ - Mode.CONFIRM + Mode.CONFIRM, + Mode.GAME_MODE_SELECT ]; export default class UI extends Phaser.GameObjects.Container { @@ -63,7 +66,8 @@ export default class UI extends Phaser.GameObjects.Container { new BiomeSelectUiHandler(scene), new StarterSelectUiHandler(scene), new EvolutionSceneHandler(scene), - new ConfirmUiHandler(scene) + new ConfirmUiHandler(scene), + new GameModeSelectUiHandler(scene) ]; }