diff --git a/public/images/categories.json b/public/images/categories.json new file mode 100644 index 000000000..8b6c6e4eb --- /dev/null +++ b/public/images/categories.json @@ -0,0 +1,83 @@ +{ + "textures": [ + { + "image": "categories.png", + "format": "RGBA8888", + "size": { + "w": 84, + "h": 11 + }, + "scale": 1, + "frames": [ + { + "filename": "physical", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 28, + "h": 11 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 28, + "h": 11 + }, + "frame": { + "x": 0, + "y": 0, + "w": 28, + "h": 11 + } + }, + { + "filename": "special", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 28, + "h": 11 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 28, + "h": 11 + }, + "frame": { + "x": 28, + "y": 0, + "w": 28, + "h": 11 + } + }, + { + "filename": "status", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 28, + "h": 11 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 28, + "h": 11 + }, + "frame": { + "x": 56, + "y": 0, + "w": 28, + "h": 11 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:624cc5ad31c0279b246b3f142bfd9c96:8422b1554e15389969070f2f708b78a0:70593749cf27aa2aea2f8132ad50259f$" + } +} diff --git a/public/images/categories.png b/public/images/categories.png new file mode 100644 index 000000000..94ba1d4c4 Binary files /dev/null and b/public/images/categories.png differ diff --git a/public/images/ui/summary_bg.png b/public/images/ui/summary_bg.png index 1cfe3f58f..4c0896b4f 100644 Binary files a/public/images/ui/summary_bg.png and b/public/images/ui/summary_bg.png differ diff --git a/public/images/ui/summary_moves_overlay_pp.png b/public/images/ui/summary_moves_overlay_pp.png new file mode 100644 index 000000000..a42c86f28 Binary files /dev/null and b/public/images/ui/summary_moves_overlay_pp.png differ diff --git a/src/auto-play.ts b/src/auto-play.ts index 92f8da427..6bfd4c754 100644 --- a/src/auto-play.ts +++ b/src/auto-play.ts @@ -9,7 +9,7 @@ import CommandUiHandler from "./ui/command-ui-handler"; import FightUiHandler from "./ui/fight-ui-handler"; import MessageUiHandler from "./ui/message-ui-handler"; import ModifierSelectUiHandler from "./ui/modifier-select-ui-handler"; -import PartyUiHandler from "./ui/party-ui-handler"; +import PartyUiHandler, { PartyUiMode } from "./ui/party-ui-handler"; import ConfirmUiHandler from "./ui/confirm-ui-handler"; import { Mode } from "./ui/ui"; @@ -129,17 +129,19 @@ export function initAutoPlay(speed: number) { const originalCommandUiHandlerShow = commandUiHandler.show; commandUiHandler.show = function (args: any[]) { originalCommandUiHandlerShow.apply(this, [ args ]); - const bestPartyMemberIndex = getBestPartyMemberIndex(); - if (bestPartyMemberIndex) { - console.log(bestPartyMemberIndex, thisArg.getParty()) - console.log('Switching to ', Species[thisArg.getParty()[bestPartyMemberIndex].species.speciesId]); - nextPartyMemberIndex = bestPartyMemberIndex; - commandUiHandler.setCursor(2); - thisArg.time.delayedCall(20, () => this.processInput(keyCodes.Z)); - } else { - commandUiHandler.setCursor(0); - thisArg.time.delayedCall(20, () => this.processInput(keyCodes.Z)); - } + thisArg.time.delayedCall(20, () => { + const bestPartyMemberIndex = getBestPartyMemberIndex(); + if (bestPartyMemberIndex) { + console.log(bestPartyMemberIndex, thisArg.getParty()) + console.log('Switching to ', Species[thisArg.getParty()[bestPartyMemberIndex].species.speciesId]); + nextPartyMemberIndex = bestPartyMemberIndex; + commandUiHandler.setCursor(2); + thisArg.time.delayedCall(20, () => this.processInput(keyCodes.Z)); + } else { + commandUiHandler.setCursor(0); + thisArg.time.delayedCall(20, () => this.processInput(keyCodes.Z)); + } + }); }; const originalFightUiHandlerShow = fightUiHandler.show; @@ -162,7 +164,11 @@ export function initAutoPlay(speed: number) { nextPartyMemberIndex = getBestPartyMemberIndex(); partyUiHandler.setCursor(nextPartyMemberIndex); nextPartyMemberIndex = -1; - this.processInput(keyCodes.Z); + if (partyUiHandler.partyUiMode === PartyUiMode.MODIFIER || partyUiHandler.getCursor()) { + this.processInput(keyCodes.Z); + this.processInput(keyCodes.Z); + } else + this.processInput(keyCodes.X); }); }; @@ -194,75 +200,77 @@ export function initAutoPlay(speed: number) { if (modifierSelectUiHandler.active) return; - originalModifierSelectUiHandlerShow.apply(this, [ args ]); + thisArg.time.delayedCall(20, () => { + originalModifierSelectUiHandlerShow.apply(this, [ args ]); - const party = thisArg.getParty(); - const modifierTypes = modifierSelectUiHandler.options.map(o => o.modifierType); - const faintedPartyMemberIndex = party.findIndex(p => !p.hp); - const lowHpPartyMemberIndex = party.findIndex(p => p.getHpRatio() <= 0.5); - const criticalHpPartyMemberIndex = party.findIndex(p => p.getHpRatio() <= 0.25); + const party = thisArg.getParty(); + const modifierTypes = modifierSelectUiHandler.options.map(o => o.modifierType); + const faintedPartyMemberIndex = party.findIndex(p => !p.hp); + const lowHpPartyMemberIndex = party.findIndex(p => p.getHpRatio() <= 0.5); + const criticalHpPartyMemberIndex = party.findIndex(p => p.getHpRatio() <= 0.25); - let optionIndex = tryGetBestModifier(modifierTypes, (modifierType: ModifierType) => { - if (modifierType instanceof PokemonHpRestoreModifierType) { - if (modifierType instanceof PokemonReviveModifierType) { - if (faintedPartyMemberIndex > -1) { - nextPartyMemberIndex = faintedPartyMemberIndex; + let optionIndex = tryGetBestModifier(modifierTypes, (modifierType: ModifierType) => { + if (modifierType instanceof PokemonHpRestoreModifierType) { + if (modifierType instanceof PokemonReviveModifierType) { + if (faintedPartyMemberIndex > -1) { + nextPartyMemberIndex = faintedPartyMemberIndex; + return true; + } + } else if (criticalHpPartyMemberIndex > -1){ + nextPartyMemberIndex = criticalHpPartyMemberIndex; return true; } - } else if (criticalHpPartyMemberIndex > -1){ - nextPartyMemberIndex = criticalHpPartyMemberIndex; - return true; - } - } - }); - - if (optionIndex === -1) { - optionIndex = tryGetBestModifier(modifierTypes, (modifierType: ModifierType) => { - if (modifierType.tier >= ModifierTier.ULTRA) { - nextPartyMemberIndex = 0; - return true; } }); - } - if (optionIndex === -1) { - optionIndex = tryGetBestModifier(modifierTypes, (modifierType: ModifierType) => { - if (modifierType instanceof PokemonBaseStatBoosterModifierType) { - nextPartyMemberIndex = 0; - return true; - } - }); - } - - if (optionIndex === -1) { - optionIndex = tryGetBestModifier(modifierTypes, (modifierType: ModifierType) => { - if (lowHpPartyMemberIndex && modifierType instanceof PokemonHpRestoreModifierType && !(ModifierType instanceof PokemonReviveModifierType)) { - nextPartyMemberIndex = lowHpPartyMemberIndex; - return true; - } - }); - } - - if (optionIndex === -1) - optionIndex = 0; - - const trySelectModifier = () => { - modifierSelectUiHandler.setCursor(optionIndex); - thisArg.time.delayedCall(20, () => { - modifierSelectUiHandler.processInput(keyCodes.Z); - thisArg.time.delayedCall(100, () => { - console.log(modifierTypes[optionIndex]?.name); - if (thisArg.getCurrentPhase() instanceof SelectModifierPhase) { - if (optionIndex < modifierSelectUiHandler.options.length - 1) { - optionIndex++; - trySelectModifier(); - } else - modifierSelectUiHandler.processInput(keyCodes.X); + if (optionIndex === -1) { + optionIndex = tryGetBestModifier(modifierTypes, (modifierType: ModifierType) => { + if (modifierType.tier >= ModifierTier.ULTRA) { + nextPartyMemberIndex = 0; + return true; } }); - }); - }; + } - thisArg.time.delayedCall(4000, () => trySelectModifier()); + if (optionIndex === -1) { + optionIndex = tryGetBestModifier(modifierTypes, (modifierType: ModifierType) => { + if (modifierType instanceof PokemonBaseStatBoosterModifierType) { + nextPartyMemberIndex = 0; + return true; + } + }); + } + + if (optionIndex === -1) { + optionIndex = tryGetBestModifier(modifierTypes, (modifierType: ModifierType) => { + if (lowHpPartyMemberIndex && modifierType instanceof PokemonHpRestoreModifierType && !(ModifierType instanceof PokemonReviveModifierType)) { + nextPartyMemberIndex = lowHpPartyMemberIndex; + return true; + } + }); + } + + if (optionIndex === -1) + optionIndex = 0; + + const trySelectModifier = () => { + modifierSelectUiHandler.setCursor(optionIndex); + thisArg.time.delayedCall(20, () => { + modifierSelectUiHandler.processInput(keyCodes.Z); + thisArg.time.delayedCall(250, () => { + console.log(modifierTypes[optionIndex]?.name); + if (thisArg.getCurrentPhase() instanceof SelectModifierPhase) { + if (optionIndex < modifierSelectUiHandler.options.length - 1) { + optionIndex++; + trySelectModifier(); + } else + modifierSelectUiHandler.processInput(keyCodes.X); + } + }); + }); + }; + + thisArg.time.delayedCall(4000, () => trySelectModifier()); + }); } } \ No newline at end of file diff --git a/src/battle-scene.ts b/src/battle-scene.ts index e418824cb..ebeeb35e3 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -11,11 +11,10 @@ import { Species } from './species'; import { initAutoPlay } from './auto-play'; import { Battle } from './battle'; import { populateAnims } from './battle-anims'; -import { Moves } from './move'; export default class BattleScene extends Phaser.Scene { - private auto: boolean; - private autoSpeed: integer = 10; + private auto: boolean = true; + private autoSpeed: integer = 1; private phaseQueue: Array; private phaseQueuePrepend: Array; @@ -49,6 +48,7 @@ export default class BattleScene extends Phaser.Scene { private rightKey: Phaser.Input.Keyboard.Key; private actionKey: Phaser.Input.Keyboard.Key; private cancelKey: Phaser.Input.Keyboard.Key; + private f2Key: Phaser.Input.Keyboard.Key; private blockInput: boolean; @@ -140,6 +140,7 @@ export default class BattleScene extends Phaser.Scene { this.loadImage('summary_moves', 'ui'); this.loadImage('summary_moves_effect', 'ui'); this.loadImage('summary_moves_overlay_row', 'ui'); + this.loadImage('summary_moves_overlay_pp', 'ui'); this.loadAtlas('summary_moves_cursor', 'ui'); // Load arena images @@ -163,6 +164,7 @@ export default class BattleScene extends Phaser.Scene { this.loadAtlas('items', ''); this.loadAtlas('types', ''); this.loadAtlas('statuses', ''); + this.loadAtlas('categories', ''); for (let i = 0; i < 6; i++) this.loadAtlas(`pokemon_icons_${i}`, 'ui'); @@ -291,6 +293,7 @@ export default class BattleScene extends Phaser.Scene { this.rightKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.RIGHT); this.actionKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Z); this.cancelKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.X); + this.f2Key = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.F2) Promise.all(loadPokemonAssets).then(() => { if (this.auto) diff --git a/src/gender.ts b/src/gender.ts index 4d5ba00a9..4e2156aac 100644 --- a/src/gender.ts +++ b/src/gender.ts @@ -14,12 +14,12 @@ export function getGenderSymbol(gender: Gender) { return ''; } -export function getGenderColor(gender: Gender) { +export function getGenderColor(gender: Gender, shadow?: boolean) { switch (gender) { case Gender.MALE: - return '#40c8f8'; + return shadow ? '#006090' : '#40c8f8'; case Gender.FEMALE: - return '#f89890'; + return shadow ? '#984038' : '#f89890'; } return '#ffffff'; } \ No newline at end of file diff --git a/src/text.ts b/src/text.ts index 53b3f6892..e59970a06 100644 --- a/src/text.ts +++ b/src/text.ts @@ -8,8 +8,8 @@ export enum TextStyle { }; export function addTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle) { - let styleOptions; - let shadowColor; + let styleOptions: Phaser.Types.GameObjects.Text.TextStyle; + let shadowColor: string; let shadowSize = 6; switch (style) { @@ -67,9 +67,9 @@ export function addTextObject(scene: Phaser.Scene, x: number, y: number, content styleOptions = { fontFamily: 'emerald', fontSize: '96px', - color: '#f4b4b0' + color: '#f89890' }; - shadowColor = '#d06c6a'; + shadowColor = '#984038'; break; } diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index 230c1753f..00491d05b 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -39,8 +39,6 @@ export default class FightUiHandler extends UiHandler { const messageHandler = this.getUi().getMessageHandler(); messageHandler.bg.setTexture('bg_fight'); this.setCursor(this.cursor); - this.typeIcon.setVisible(true); - this.ppText.setVisible(true); this.displayMoves(); } diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index aace7b826..e859e505e 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -5,7 +5,9 @@ import * as Utils from "../utils"; import { PlayerPokemon } from "../pokemon"; import { Type } from "../type"; import { TextStyle, addTextObject } from "../text"; -import Move from "../move"; +import Move, { MoveCategory } from "../move"; +import { getPokeballAtlasKey } from "../pokeball"; +import { getGenderColor, getGenderSymbol } from "../gender"; enum Page { PROFILE, @@ -21,7 +23,12 @@ export default class SummaryUiHandler extends UiHandler { private summaryUiMode: SummaryUiMode; private summaryContainer: Phaser.GameObjects.Container; + private numberText: Phaser.GameObjects.Text; private pokemonSprite: Phaser.GameObjects.Sprite; + private nameText: Phaser.GameObjects.Text; + private pokeball: Phaser.GameObjects.Sprite; + private levelText: Phaser.GameObjects.Text; + private genderText: Phaser.GameObjects.Text; private summaryPageContainer: Phaser.GameObjects.Container; private movesContainer: Phaser.GameObjects.Container; private moveDescriptionText: Phaser.GameObjects.Text; @@ -29,6 +36,10 @@ export default class SummaryUiHandler extends UiHandler { private selectedMoveCursorObj: Phaser.GameObjects.Sprite; private moveRowsContainer: Phaser.GameObjects.Container; private extraMoveRowContainer: Phaser.GameObjects.Container; + private moveEffectContainer: Phaser.GameObjects.Container; + private movePowerText: Phaser.GameObjects.Text; + private moveAccuracyText: Phaser.GameObjects.Text; + private moveCategoryIcon: Phaser.GameObjects.Sprite; private summaryPageTransitionContainer: Phaser.GameObjects.Container; private moveDescriptionScrollTween: Phaser.Tweens.Tween; @@ -38,6 +49,7 @@ export default class SummaryUiHandler extends UiHandler { private newMove: Move; private moveSelectFunction: Function; private transitioning: boolean; + private moveEffectsVisible: boolean; private moveSelect: boolean; private moveCursor: integer; @@ -58,9 +70,48 @@ export default class SummaryUiHandler extends UiHandler { summaryBg.setOrigin(0, 1); this.summaryContainer.add(summaryBg); + this.numberText = addTextObject(this.scene, 17, -150, '000', TextStyle.SUMMARY); + this.numberText.setOrigin(0, 1); + this.summaryContainer.add(this.numberText); + this.pokemonSprite = this.scene.add.sprite(56, -106, `pkmn__sub`); this.summaryContainer.add(this.pokemonSprite); + this.nameText = addTextObject(this.scene, 6, -39, '', TextStyle.SUMMARY); + this.nameText.setOrigin(0, 1); + this.summaryContainer.add(this.nameText); + + this.pokeball = this.scene.add.sprite(6, -23, 'pb'); + this.pokeball.setOrigin(0, 1); + this.summaryContainer.add(this.pokeball); + + this.levelText = addTextObject(this.scene, 36, -22, '', TextStyle.SUMMARY); + this.levelText.setOrigin(0, 1); + this.summaryContainer.add(this.levelText); + + this.genderText = addTextObject(this.scene, 96, -22, '', TextStyle.SUMMARY); + this.genderText.setOrigin(0, 1); + this.summaryContainer.add(this.genderText); + + this.moveEffectContainer = this.scene.add.container(106, -62); + this.summaryContainer.add(this.moveEffectContainer); + + const moveEffectBg = this.scene.add.image(0, 0, 'summary_moves_effect'); + moveEffectBg.setOrigin(0, 0); + this.moveEffectContainer.add(moveEffectBg); + + this.movePowerText = addTextObject(this.scene, 99, 27, '0', TextStyle.WINDOW); + this.movePowerText.setOrigin(1, 1); + this.moveEffectContainer.add(this.movePowerText); + + this.moveAccuracyText = addTextObject(this.scene, 99, 43, '0', TextStyle.WINDOW); + this.moveAccuracyText.setOrigin(1, 1); + this.moveEffectContainer.add(this.moveAccuracyText); + + this.moveCategoryIcon = this.scene.add.sprite(99, 57, 'categories'); + this.moveCategoryIcon.setOrigin(1, 1); + this.moveEffectContainer.add(this.moveCategoryIcon); + const getSummaryPageBg = () => { const ret = this.scene.add.sprite(0, 0, this.getPageKey(0)); ret.setOrigin(0, 1); @@ -90,17 +141,29 @@ export default class SummaryUiHandler extends UiHandler { this.summaryContainer.setVisible(true); this.cursor = -1; + this.numberText.setText(Utils.padInt(this.pokemon.species.speciesId, 3)); + this.pokemonSprite.play(this.pokemon.getSpriteKey()); this.pokemon.cry(); + this.nameText.setText(this.pokemon.name); + this.pokeball.setFrame(getPokeballAtlasKey(this.pokemon.pokeball)); + this.levelText.setText(this.pokemon.level.toString()); + this.genderText.setText(getGenderSymbol(this.pokemon.gender)); + this.genderText.setColor(getGenderColor(this.pokemon.gender)); + this.genderText.setShadowColor(getGenderColor(this.pokemon.gender, true)); + switch (this.summaryUiMode) { case SummaryUiMode.DEFAULT: - this.setCursor(Page.PROFILE); + const page = args.length < 2 ? Page.PROFILE : args[2] as Page; + this.hideMoveEffect(true); + this.setCursor(page); break; case SummaryUiMode.LEARN_MOVE: this.newMove = args[2] as Move; this.moveSelectFunction = args[3] as Function; + this.showMoveEffect(true); this.setCursor(Page.MOVES); this.showMoveSelect(); break; @@ -178,6 +241,17 @@ export default class SummaryUiHandler extends UiHandler { } else { const pages = Utils.getEnumValues(Page); switch (keyCode) { + case keyCodes.UP: + case keyCodes.DOWN: + const isDown = keyCode === keyCodes.DOWN; + const party = this.scene.getParty(); + const partyMemberIndex = party.indexOf(this.pokemon); + if ((isDown && partyMemberIndex < party.length - 1) || (!isDown && partyMemberIndex)) { + const page = this.cursor; + this.clear(); + this.show([ party[partyMemberIndex + (isDown ? 1 : -1)], this.summaryUiMode, page ]); + } + break; case keyCodes.LEFT: if (this.cursor) success = this.setCursor(this.cursor - 1); @@ -204,6 +278,14 @@ export default class SummaryUiHandler extends UiHandler { const selectedMove = this.getSelectedMove(); + if (selectedMove) { + this.movePowerText.setText(selectedMove.power >= 0 ? selectedMove.power.toString() : '---'); + this.moveAccuracyText.setText(selectedMove.accuracy >= 0 ? selectedMove.accuracy.toString() : '---'); + this.moveCategoryIcon.setFrame(MoveCategory[selectedMove.category].toLowerCase()); + this.showMoveEffect(); + } else + this.hideMoveEffect(); + this.moveDescriptionText.setText(selectedMove?.effect || ''); const moveDescriptionLineCount = Math.floor(this.moveDescriptionText.displayHeight / 14.83); @@ -245,6 +327,8 @@ export default class SummaryUiHandler extends UiHandler { callback: () => { this.moveCursorObj.setVisible(false); this.scene.time.delayedCall(100, () => { + if (!this.moveCursorObj) + return; this.moveCursorObj.setVisible(true); }); } @@ -378,6 +462,7 @@ export default class SummaryUiHandler extends UiHandler { this.extraMoveRowContainer.setVisible(true); this.selectedMoveIndex = -1; this.setCursor(0); + this.showMoveEffect(); } hideMoveSelect() { @@ -400,6 +485,32 @@ export default class SummaryUiHandler extends UiHandler { this.selectedMoveCursorObj.destroy(); this.selectedMoveCursorObj = null; } + + this.hideMoveEffect(); + } + + showMoveEffect(instant?: boolean) { + if (this.moveEffectsVisible) + return; + this.moveEffectsVisible = true; + this.scene.tweens.add({ + targets: this.moveEffectContainer, + x: 6, + duration: instant ? 0 : 250, + ease: 'Sine.easeOut' + }); + } + + hideMoveEffect(instant?: boolean) { + if (!this.moveEffectsVisible) + return; + this.moveEffectsVisible = false; + this.scene.tweens.add({ + targets: this.moveEffectContainer, + x: 106, + duration: instant ? 0 : 250, + ease: 'Sine.easeIn' + }); } clear() {