diff --git a/package-lock.json b/package-lock.json index c849f347bbe..384b4469d0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pokemon-rogue-battle", - "version": "0.0.1", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pokemon-rogue-battle", - "version": "0.0.1", + "version": "1.0.0", "dependencies": { "@material/material-color-utilities": "^0.2.7", "crypto-js": "^4.2.0", diff --git a/public/images/trainer/rival.json b/public/images/trainer/rosa.json similarity index 99% rename from public/images/trainer/rival.json rename to public/images/trainer/rosa.json index 6c80e5382eb..2ee67671872 100644 --- a/public/images/trainer/rival.json +++ b/public/images/trainer/rosa.json @@ -1,7 +1,7 @@ { "textures": [ { - "image": "rival.png", + "image": "rosa.png", "format": "RGBA8888", "size": { "w": 267, diff --git a/public/images/trainer/rival.png b/public/images/trainer/rosa.png similarity index 100% rename from public/images/trainer/rival.png rename to public/images/trainer/rosa.png diff --git a/src/battle-phases.ts b/src/battle-phases.ts index 4d5204f208b..db21f3738a1 100644 --- a/src/battle-phases.ts +++ b/src/battle-phases.ts @@ -44,11 +44,12 @@ import { EggHatchPhase } from "./egg-hatch-phase"; import { Egg } from "./data/egg"; import { vouchers } from "./system/voucher"; import { loggedInUser, updateUserInfo } from "./account"; -import { GameDataType } from "./system/game-data"; +import { GameDataType, PlayerGender } from "./system/game-data"; import { addPokeballCaptureStars, addPokeballOpenParticles } from "./anims"; import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangeMoveUsedTrigger } from "./data/pokemon-forms"; import { battleSpecDialogue } from "./data/dialogue"; import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "./ui/modifier-select-ui-handler"; +import { Setting } from "./system/settings"; export class LoginPhase extends BattlePhase { private showText: boolean; @@ -223,6 +224,39 @@ export class CheckLoadPhase extends BattlePhase { } } +export class SelectGenderPhase extends BattlePhase { + constructor(scene: BattleScene) { + super(scene); + } + + start(): void { + super.start(); + + this.scene.ui.showText('Are you a boy or a girl?', null, () => { + this.scene.ui.setMode(Mode.OPTION_SELECT, { + options: [ + { + label: 'Boy', + handler: () => { + this.scene.gameData.gender = PlayerGender.MALE; + this.scene.gameData.saveSetting(Setting.Player_Gender, 0); + this.scene.gameData.saveSystem().then(() => this.end()); + } + }, + { + label: 'Girl', + handler: () => { + this.scene.gameData.gender = PlayerGender.FEMALE; + this.scene.gameData.saveSetting(Setting.Player_Gender, 1); + this.scene.gameData.saveSystem().then(() => this.end()); + } + } + ] + }); + }); + } +} + export class SelectStarterPhase extends BattlePhase { constructor(scene: BattleScene) { super(scene); @@ -841,7 +875,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { this.scene.ui.showText(`Go! ${this.getPokemon().name}!`); if (this.player) this.scene.pbTray.hide(); - this.scene.trainer.setTexture('trainer_m_back_pb'); + this.scene.trainer.setTexture(`trainer_${this.scene.gameData.gender === PlayerGender.FEMALE ? 'f' : 'm'}_back_pb`); this.scene.time.delayedCall(562, () => { this.scene.trainer.setFrame('2'); this.scene.time.delayedCall(64, () => { @@ -1080,7 +1114,7 @@ export class ShowTrainerPhase extends BattlePhase { this.scene.trainer.setVisible(true) - this.scene.trainer.setTexture('trainer_m_back'); + this.scene.trainer.setTexture(`trainer_${this.scene.gameData.gender === PlayerGender.FEMALE ? 'f' : 'm'}_back`); this.scene.tweens.add({ targets: this.scene.trainer, @@ -3742,8 +3776,12 @@ export class ScanIvsPhase extends PokemonPhase { } export class TrainerMessageTestPhase extends BattlePhase { - constructor(scene: BattleScene) { + private trainerTypes: TrainerType[]; + + constructor(scene: BattleScene, ...trainerTypes: TrainerType[]) { super(scene); + + this.trainerTypes = trainerTypes; } start() { @@ -3752,7 +3790,10 @@ export class TrainerMessageTestPhase extends BattlePhase { let testMessages: string[] = []; for (let t of Object.keys(trainerConfigs)) { - const config = trainerConfigs[parseInt(t)]; + const type = parseInt(t); + if (this.trainerTypes.length && !this.trainerTypes.find(tt => tt === type as TrainerType)) + continue; + const config = trainerConfigs[type]; [ config.encounterMessages, config.femaleEncounterMessages, config.victoryMessages, config.femaleVictoryMessages, config.defeatMessages, config.femaleDefeatMessages ] .map(messages => { if (messages?.length) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 33e78150da7..2d218309834 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1,6 +1,6 @@ import Phaser from 'phaser'; import UI, { Mode } from './ui/ui'; -import { EncounterPhase, SummonPhase, NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, CheckLoadPhase, TurnInitPhase, ReturnPhase, LevelCapPhase, TestMessagePhase, ShowTrainerPhase, TrainerMessageTestPhase, LoginPhase, ConsolidateDataPhase } from './battle-phases'; +import { EncounterPhase, SummonPhase, NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, CheckLoadPhase, TurnInitPhase, ReturnPhase, LevelCapPhase, TestMessagePhase, ShowTrainerPhase, TrainerMessageTestPhase, LoginPhase, ConsolidateDataPhase, SelectGenderPhase } from './battle-phases'; import Pokemon, { PlayerPokemon, EnemyPokemon } from './pokemon'; import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies, initSpecies, speciesStarters } from './data/pokemon-species'; import * as Utils from './utils'; @@ -12,7 +12,7 @@ import { BattlePhase } from './battle-phase'; import { initGameSpeed } from './system/game-speed'; import { Biome } from "./data/enums/biome"; import { Arena, ArenaBase, getBiomeHasProps, getBiomeKey } from './arena'; -import { GameData } from './system/game-data'; +import { GameData, PlayerGender } from './system/game-data'; import StarterSelectUiHandler from './ui/starter-select-ui-handler'; import { TextStyle, addTextObject } from './ui/text'; import { Moves } from "./data/enums/moves"; @@ -521,7 +521,7 @@ export default class BattleScene extends Phaser.Scene { field.add(a); }); - const trainer = this.addFieldSprite(0, 0, 'trainer_m_back'); + const trainer = this.addFieldSprite(0, 0, `trainer_${this.gameData.gender === PlayerGender.FEMALE ? 'f' : 'm'}_back`); trainer.setOrigin(0.5, 1); field.add(trainer); @@ -570,6 +570,8 @@ export default class BattleScene extends Phaser.Scene { this.pushPhase(new LoginPhase(this)); if (!bypassLogin) this.pushPhase(new ConsolidateDataPhase(this)); // TODO: Remove + if (!this.gameData.gender) + this.pushPhase(new SelectGenderPhase(this)); this.pushPhase(new CheckLoadPhase(this)); } else this.pushPhase(new EncounterPhase(this)); @@ -728,7 +730,7 @@ export default class BattleScene extends Phaser.Scene { [ this.arenaEnemy, this.arenaNextEnemy ].forEach(a => a.setPosition(-280, 0)); this.arenaNextEnemy.setVisible(false); - this.trainer.setTexture('trainer_m_back'); + this.trainer.setTexture(`trainer_${this.gameData.gender === PlayerGender.FEMALE ? 'f' : 'm'}_back`); this.trainer.setPosition(406, 186); if (clearScene) { diff --git a/src/battle.ts b/src/battle.ts index d8c30e403e6..3248e21b133 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -8,6 +8,7 @@ import { Moves } from "./data/enums/moves"; import { TrainerType } from "./data/enums/trainer-type"; import { GameMode } from "./game-mode"; import { BattleSpec } from "./enums/battle-spec"; +import { PlayerGender } from "./system/game-data"; export enum BattleType { WILD, @@ -231,15 +232,15 @@ export const fixedBattles: FixedBattleConfigs = { [5]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.YOUNGSTER, !!Utils.randSeedInt(2))), [8]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) - .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL, true)), + .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL, scene.gameData.gender === PlayerGender.MALE)), [25]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) - .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_2, true)), + .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_2, scene.gameData.gender === PlayerGender.MALE)), [55]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) - .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_3, true)), + .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_3, scene.gameData.gender === PlayerGender.MALE)), [95]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) - .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_4, true)), + .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_4, scene.gameData.gender === PlayerGender.MALE)), [145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) - .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_5, true)), + .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_5, scene.gameData.gender === PlayerGender.MALE)), [182]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.LORELEI, TrainerType.WILL, TrainerType.SIDNEY, TrainerType.AARON, TrainerType.SHAUNTAL, TrainerType.MALVA, [ TrainerType.HALA, TrainerType.MOLAYNE ], TrainerType.RIKA, TrainerType.CRISPIN ])), [184]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182) @@ -251,5 +252,5 @@ export const fixedBattles: FixedBattleConfigs = { [190]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(182) .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.BLUE, TrainerType.RED, TrainerType.LANCE_CHAMPION, TrainerType.STEVEN, TrainerType.WALLACE, TrainerType.CYNTHIA, TrainerType.ALDER, TrainerType.IRIS, TrainerType.DIANTHA, TrainerType.LEON, [ TrainerType.GEETA, TrainerType.NEMONA ], TrainerType.KIERAN ])), [195]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) - .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_6, true)) + .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_6, scene.gameData.gender === PlayerGender.MALE)) }; \ No newline at end of file diff --git a/src/data/dialogue.ts b/src/data/dialogue.ts index d5a6f90a57b..5ddcd423b58 100644 --- a/src/data/dialogue.ts +++ b/src/data/dialogue.ts @@ -192,60 +192,141 @@ export const trainerTypeDialogue = { `Shall I loan you my outfit? It may help you battle!\nAhahaha, I jest!` ] }, - [TrainerType.RIVAL]: { - encounter: [ - `There you are! I've been looking everywhere for you!\nDid you forget to say goodbye to your best friend? - $So you're finally pursuing your dream, huh?\nI knew you'd do it one day… - $Anyway, I'll forgive you for forgetting me, but on one condition. You have to battle me! - $You'd better give it your best! Wouldn't want your adventure to be over before it started, right?` - ], - victory: [ - `You already have three Pokémon?!\nThat's not fair at all! - $Just kidding! I lost fair and square, and now I know you'll do fine out there. - $By the way, the professor wanted me to give you some items. Hopefully they're helpful! - $Do your best like always! I believe in you!` - ] - }, - [TrainerType.RIVAL_2]: { - encounter: [ - `Oh, fancy meeting you here. Looks like you're still undefeated. Right on! - $I know what you're thinking, and no, I wasn't following you. I just happened to be in the area. - $I'm happy for you but I just want to let you know that it's OK to lose sometimes. - $We learn from our mistakes, often more than we would if we kept succeeding. - $In any case, I've been training hard for our rematch, so you'd better give it your all!` - ], - victory: [ - `I… wasn't supposed to lose that time…` - ] - }, - [TrainerType.RIVAL_3]: { - encounter: [ - `Long time no see! Still haven't lost, huh.\nYou're starting to get on my nerves. Just kidding! - $But really, I think it's about time you came home.\nYour family and friends miss you, you know. - $I know your dream means a lot to you, but the reality is you're going to lose sooner or later. - $And when you do, I'll be there for you like always.\nNow, let me show you how strong I've become!` - ], - victory: [ - `After all that… it wasn't enough…?` - ] - }, - [TrainerType.RIVAL_4]: { - encounter: [ - `It's me! You didn't forget about me again did you? - $You made it really far! I'm proud of you.\nBut it looks like it's the end of your journey. - $You've awoken something in me I never knew was there.\nIt seems like all I do now is train. - $I hardly even eat or sleep now, I just train my Pokémon all day, getting stronger every time. - $And now, I've finally reached peak performance.\nI don't think anyone could beat me now. - $And you know what? It's all because of you.\nI don't know whether to thank you or hate you. - $Prepare yourself.` - ], - victory: [ - `What…@d{64} what are you?` - ] - }, + [TrainerType.RIVAL]: [ + { + encounter: [ + `Hey, I was looking for you! I knew you were eager to get going but doesn't your best friend deserve a goodbye? + $So you're finally pursuing your dream, huh?\nI knew you'd do it one day… + $Since we're here, how about a battle?\nAfter all, I want to make sure you're ready. + $Don't hold back, I want you to give me everything you've got!` + ], + victory: [ + `Wow, I guess you really are ready, huh?\nI didn't stand a chance. + $Now I know you'll have no problems out there.\nYou're a champion in the making. + $By the way, the professor asked me to give you these items. They look pretty cool. + $Good luck! I believe in you!` + ] + }, + { + encounter: [ + `There you are! I've been looking everywhere for you!\nDid you forget to say goodbye to your best friend? + $So you're finally pursuing your dream, huh?\nI knew you'd do it one day… + $Anyway, I'll forgive you for forgetting me, but on one condition. You have to battle me! + $You'd better give it your best! Wouldn't want your adventure to be over before it started, right?` + ], + victory: [ + `You just started and you're already this strong?!\nYou cheated, didn't you? + $Just kidding! I lost fair and square, and now I know you'll do fine out there. + $By the way, the professor wanted me to give you some items. Hopefully they're helpful! + $Do your best like always! I believe in you!` + ] + } + ], + [TrainerType.RIVAL_2]: [ + { + encounter: [ + `Oh, you're here too! Still a perfect record, huh? As I expected. + $I know it kind of looks like I followed you here, but that's mostly not true. + $Honestly though, I've been itching for a rematch since you beat me back at home. + $I've been doing a lot of my own training so I'll definitely put up a fight this time. + $Don't hold back, just like before! I'm ready now!` + ], + victory: [ + `Oh. I guess I was overconfident.` + ] + }, + { + encounter: [ + `Oh, fancy meeting you here. Looks like you're still undefeated. Right on! + $I know what you're thinking, and no, I wasn't following you. I just happened to be in the area. + $I'm happy for you but I just want to let you know that it's OK to lose sometimes. + $We learn from our mistakes, often more than we would if we kept succeeding. + $In any case, I've been training hard for our rematch, so you'd better give it your all!` + ], + victory: [ + `I… wasn't supposed to lose that time…` + ] + } + ], + [TrainerType.RIVAL_3]: [ + { + encounter: [ + `Look who it is! It's been a while. You're… still undefeated? Huh. + $I was sort of hoping otherwise.\nIt's not the same back home without you. + $I know it's selfish, but I need to get this off my chest.\nI think you're in over your head here. + $Never losing once is just unrealistic.\nWe need to lose sometimes in order to grow. + $You've had a great run but there's still so much ahead, and it only gets harder. Are you prepared for that? + $If so, prove it to me.` + ], + victory: [ + `But… I've been training so much…\nHow are we still so far apart?` + ] + }, + { + encounter: [ + `Long time no see! Still haven't lost, huh.\nYou're starting to get on my nerves. Just kidding! + $But really, I think it's about time you came home.\nYour family and friends miss you, you know. + $I know your dream means a lot to you, but the reality is you're going to lose sooner or later. + $And when you do, I'll be there for you like always.\nNow, let me show you how strong I've become!` + ], + victory: [ + `After all that… it wasn't enough…?` + ] + } + ], + [TrainerType.RIVAL_4]: [ + { + encounter: [ + `Hey. + $I won't mince words. I'm here to win, and this time I will. + $I've learned to maximize my potential by putting all my time into training. + $You get a lot of extra time when you cut out the unnecessary sleep and social interaction. + $None of that matters anymore, not until I win. + $I've even reached the point where I don't lose anymore. Maybe your philosophy wasn't so wrong after all. + $Prepare yourself.` + ], + victory: [ + `What…@d{64} what are you?` + ] + }, + { + encounter: [ + `It's me! You didn't forget about me again did you? + $You made it really far! I'm proud of you.\nBut it looks like it's the end of your journey. + $You've awoken something in me I never knew was there.\nIt seems like all I do now is train. + $I hardly even eat or sleep now, I just train my Pokémon all day, getting stronger every time. + $And now, I've finally reached peak performance.\nI don't think anyone could beat me now. + $And you know what? It's all because of you.\nI don't know whether to thank you or hate you. + $Prepare yourself.` + ], + victory: [ + `What…@d{64} what are you?` + ] + } + ], [TrainerType.RIVAL_5]: { encounter: [ `…` ], victory: [ '…' ] + }, + [TrainerType.RIVAL_6]: { + encounter: [ + `We meet again. + $I've had some time to reflect on all this.\nThere's a reason this all seems so strange. + $Your dream, my drive to beat you…\nIt's all a part of something greater. + $This isn't about me, or about you… This is about the world, and it's my purpose to push you to your limits. + $Whether I've fulfilled that purpose I can't say, but I've done everything in my power. + $Being in this dreadful place, I can see it now.\nThis is all the world's known for a long time now. + $Those times we cherished together that seem so recent are nothing but a distant memory. + $Who can say whether they were ever even real in the first place. + $You need to keep pushing, because if you don't, it will never end. You're the only one who can do this. + $I hardly know what any of this means, I just know that it's true. + $If you can't defeat me here and now, you won't stand a chance.` + ], + victory: [ + `It looks like my work is done here. + $I want you to promise me one thing.\nAfter you heal the world, please come home. + $…Thank you.` + ] } }; diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 5f0b3b85c38..841aefe6b7a 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -31,6 +31,12 @@ export enum GameDataType { SETTINGS } +export enum PlayerGender { + UNSET, + MALE, + FEMALE +} + export function getDataTypeKey(dataType: GameDataType): string { switch (dataType) { case GameDataType.SYSTEM: @@ -45,6 +51,7 @@ export function getDataTypeKey(dataType: GameDataType): string { interface SystemSaveData { trainerId: integer; secretId: integer; + gender: PlayerGender; dexData: DexData; gameStats: GameStats; unlocks: Unlocks; @@ -136,6 +143,8 @@ export class GameData { public trainerId: integer; public secretId: integer; + + public gender: PlayerGender; public dexData: DexData; private defaultDexData: DexData; @@ -185,6 +194,7 @@ export class GameData { const data: SystemSaveData = { trainerId: this.trainerId, secretId: this.secretId, + gender: this.gender, dexData: this.dexData, gameStats: this.gameStats, unlocks: this.unlocks, @@ -239,6 +249,10 @@ export class GameData { this.trainerId = systemData.trainerId; this.secretId = systemData.secretId; + this.gender = systemData.gender; + + this.saveSetting(Setting.Player_Gender, systemData.gender === PlayerGender.FEMALE ? 1 : 0); + if (systemData.gameStats) this.gameStats = systemData.gameStats; diff --git a/src/system/settings.ts b/src/system/settings.ts index 5aa791d2947..c7a97db1ea2 100644 --- a/src/system/settings.ts +++ b/src/system/settings.ts @@ -1,5 +1,6 @@ import BattleScene from "../battle-scene"; import { updateWindowType } from "../ui/window"; +import { PlayerGender } from "./game-data"; export enum Setting { Game_Speed = "GAME_SPEED", @@ -8,6 +9,7 @@ export enum Setting { SE_Volume = "SE_VOLUME", Show_Stats_on_Level_Up = "SHOW_LEVEL_UP_STATS", Window_Type = "WINDOW_TYPE", + Player_Gender = "PLAYER_GENDER", Touch_Controls = "TOUCH_CONTROLS", Vibration = "VIBRATION" } @@ -27,6 +29,7 @@ export const settingOptions: SettingOptions = { [Setting.SE_Volume]: new Array(11).fill(null).map((_, i) => i ? (i * 10).toString() : 'Mute'), [Setting.Show_Stats_on_Level_Up]: [ 'Off', 'On' ], [Setting.Window_Type]: new Array(4).fill(null).map((_, i) => (i + 1).toString()), + [Setting.Player_Gender]: [ 'Boy', 'Girl' ], [Setting.Touch_Controls]: [ 'Auto', 'Disabled' ], [Setting.Vibration]: [ 'Auto', 'Disabled' ] }; @@ -38,6 +41,7 @@ export const settingDefaults: SettingDefaults = { [Setting.SE_Volume]: 10, [Setting.Show_Stats_on_Level_Up]: 1, [Setting.Window_Type]: 0, + [Setting.Player_Gender]: 0, [Setting.Touch_Controls]: 0, [Setting.Vibration]: 0 }; @@ -65,6 +69,14 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer) case Setting.Window_Type: updateWindowType(scene, parseInt(settingOptions[setting][value])); break; + case Setting.Player_Gender: + if (scene.gameData) { + const female = settingOptions[setting][value] === 'Girl'; + scene.gameData.gender = female ? PlayerGender.FEMALE : PlayerGender.MALE; + scene.trainer.setTexture(scene.trainer.texture.key.replace(female ? 'm' : 'f', female ? 'f' : 'm')); + } else + return false; + break; case Setting.Touch_Controls: scene.enableTouchControls = settingOptions[setting][value] !== 'Disabled' && hasTouchscreen(); const touchControls = document.getElementById('touchControls');