diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 38691decd52..1c5656f92d2 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -113,6 +113,8 @@ export default class BattleScene extends SceneBase { public damageNumbersMode: integer = 0; public reroll: boolean = false; public showMovesetFlyout: boolean = true; + public showTeams: boolean = true; + public showTeamSprites: boolean = false; public showArenaFlyout: boolean = true; public showTimeOfDayWidget: boolean = true; public timeOfDayAnimation: EaseType = EaseType.NONE; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 68e16b919ab..99ff0bd633f 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -108,6 +108,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { private shinySparkle: Phaser.GameObjects.Sprite; + public usedInBattle: boolean = false; public partyslot: integer; constructor(scene: BattleScene, x: number, y: number, species: PokemonSpecies, level: integer, abilityIndex?: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, variant?: Variant, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData) { @@ -1696,6 +1697,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { toggleFlyout(visible: boolean): void { this.battleInfo.toggleFlyout(visible); } + toggleTeamTray(visible: boolean): void { + this.battleInfo.toggleTeamTray(visible); + } addExp(exp: integer) { const maxExpLevel = this.scene.getMaxExpLevel(); diff --git a/src/phases.ts b/src/phases.ts index e034a9ed88b..6a5af044aab 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2666,6 +2666,9 @@ export class TurnInitPhase extends FieldPhase { if (pokemon?.isActive()) { if (pokemon.isPlayer()) { this.scene.currentBattle.addParticipant(pokemon as PlayerPokemon); + } else { + pokemon.usedInBattle = true; + pokemon.getBattleInfo().iconsActive = true } pokemon.resetTurnData(); @@ -2674,6 +2677,32 @@ export class TurnInitPhase extends FieldPhase { } }); + var Pt = this.scene.getEnemyParty() + var Pt2 = Pt.slice() + if (Pt2.length > 1) { + Pt2[1] = Pt[0] + Pt2[0] = Pt[1] + } + Pt.forEach((pokemon, i) => { + if (pokemon.hasTrainer() || true) { + console.log(i) + if (pokemon.getFieldIndex() == 1 && pokemon.isOnField()) { + // Switch this to cycle between + // - hiding the top mon's team bar + // - showing the bottom mon's team bar with its active slots reversed + if (false) { + pokemon.getBattleInfo().displayParty(Pt) + Pt[0].getBattleInfo().switchIconVisibility(false); // Make the top mon's team bar go away + Pt[0].getBattleInfo().iconsActive = false; // Prevent the top mon from re-opening its bar + } else { + pokemon.getBattleInfo().displayParty(Pt2) + } + } else { + pokemon.getBattleInfo().displayParty(Pt) + } + } + }) + this.scene.pushPhase(new TurnStartPhase(this.scene)); var txt = ["Turn: " + this.scene.currentBattle.turn] diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts index 53f4ee66c79..05cc9c7216b 100644 --- a/src/system/settings/settings.ts +++ b/src/system/settings/settings.ts @@ -99,6 +99,7 @@ export const SettingKeys = { SE_Volume: "SE_VOLUME", Music_Preference: "MUSIC_PREFERENCE", Show_BGM_Bar: "SHOW_BGM_BAR", + Show_Pokemon_Teams: "SHOW_POKEMON_TEAMS", Damage_Display: "DAMAGE_DISPLAY", LazyReloads: "FLAG_EVERY_RESET_AS_RELOAD", FancyBiome: "FANCY_BIOMES", @@ -490,6 +491,26 @@ export const Setting: Array = [ default: 1, type: SettingType.DISPLAY }, + { + key: SettingKeys.Show_Pokemon_Teams, + label: i18next.t("settings:showTeamTray"), + options: [ + { + value: "Off", + label: i18next.t("settings:off") + }, + { + value: "Ball", + label: i18next.t("settings:simple") + }, + { + value: "Sprite", + label: i18next.t("settings:fancy") + } + ], + default: 1, + type: SettingType.DISPLAY + }, { key: SettingKeys.Show_Arena_Flyout, label: i18next.t("settings:showArenaFlyout"), @@ -764,6 +785,10 @@ export function setSetting(scene: BattleScene, setting: string, value: integer): case SettingKeys.Show_Moveset_Flyout: scene.showMovesetFlyout = Setting[index].options[value].value === "On"; break; + case SettingKeys.Show_Pokemon_Teams: + scene.showTeams = Setting[index].options[value].value !== "Off"; + scene.showTeamSprites = Setting[index].options[value].value === "Sprite"; + break; case SettingKeys.Show_Arena_Flyout: scene.showArenaFlyout = Setting[index].options[value].value === "On"; break; diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts index 9288fd35892..d219f3503d4 100644 --- a/src/ui-inputs.ts +++ b/src/ui-inputs.ts @@ -132,7 +132,7 @@ export class UiInputs { buttonStats(pressed: boolean = true): void { // allow access to Button.STATS as a toggle for other elements for (const t of this.scene.getInfoToggles(true)) { - t.toggleInfo(pressed); + t.toggleInfo(pressed,); } // handle normal pokemon battle ui for (const p of this.scene.getField().filter(p => p?.isActive(true))) { @@ -146,6 +146,12 @@ export class UiInputs { } } + if (this.scene.showTeams) { + for (const p of this.scene.getField().filter(p => p?.isActive(true))) { + p.toggleTeamTray(pressed); + } + } + if (this.scene.showArenaFlyout) { this.scene.ui.processInfoButton(pressed); } diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index 5d066cfb154..59b8e8c86ae 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -71,6 +71,15 @@ export default class BattleInfo extends Phaser.GameObjects.Container { public flyoutMenu?: BattleFlyout; + private teamIcons: Phaser.GameObjects.Sprite[]; + private teamIconOver: Phaser.GameObjects.Sprite[]; + private teamIconsShow: boolean[]; + public iconsActive: boolean = false; + private teamCount: integer = 0; + private showingTeam: boolean = false; + private pressedShow: boolean = false; + private override: boolean = false; + constructor(scene: Phaser.Scene, x: number, y: number, player: boolean) { super(scene, x, y); this.baseY = y; @@ -115,6 +124,27 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.ownedIcon.setPositionRelative(this.nameText, 0, 11.75); this.add(this.ownedIcon); + this.teamIcons = new Array(6); + this.teamIconOver = new Array(6); + this.teamIconsShow = new Array(6).fill(false); + + for (var ballindex = 0; ballindex < 6; ballindex++) { + this.teamIcons[ballindex] = this.scene.add.sprite(0, 0, "pb_tray_ball", "empty") + this.teamIcons[ballindex].setName("pb_teamball_" + ballindex); + this.teamIcons[ballindex].setVisible(true); + this.teamIcons[ballindex].setAlpha(0); + this.teamIcons[ballindex].setOrigin(0, 0); + this.teamIcons[ballindex].setPositionRelative(this.nameText, 6 * ballindex, 11.75); + this.add(this.teamIcons[ballindex]); + this.teamIconOver[ballindex] = this.scene.add.sprite(0, 0, "pb_tray_ball", "empty") + this.teamIconOver[ballindex].setName("pb_teamball_" + ballindex); + this.teamIconOver[ballindex].setVisible(true); + this.teamIconOver[ballindex].setAlpha(0); + this.teamIconOver[ballindex].setOrigin(0, 0); + this.teamIconOver[ballindex].setPositionRelative(this.nameText, 6 * ballindex, 11.75); + this.add(this.teamIconOver[ballindex]); + } + this.championRibbon = this.scene.add.sprite(0, 0, "champion_ribbon"); this.championRibbon.setName("icon_champion_ribbon"); this.championRibbon.setVisible(false); @@ -490,6 +520,151 @@ export default class BattleInfo extends Phaser.GameObjects.Container { } } + displayParty(overwriteparty?: Pokemon[], useparty?: EnemyPokemon[]): void { + // Floor 8: 2 pokemon + // Floor 25: 3 + // Floor 55: 4 + // Floor 95: 5 + // Floor 145: 6 + // Floor 195: 6 + var party = (this.scene as BattleScene).getEnemyParty() + if (useparty != undefined) { + console.debug("Using specified enemy party"); + //party = useparty; + } else if (overwriteparty != undefined) { + console.debug("Using specified party"); + } + var P; + if (useparty != undefined) { + //console.debug("Using specified enemy party"); + P = useparty; + } else if (overwriteparty != undefined) { + //console.debug("Using specified party"); + P = overwriteparty + } else { + P = party + } + var staticparty = (this.scene as BattleScene).getEnemyParty() + var states = new Array(6) + for (var i = 0; i < 6; i++) { + states[i] = "empty"; + } + var total_visible = 0 + for (var i = 0; i < P.length; i++) { + states[i] = "ball" + if (!party[i].hp) { + states[i] = "faint" + } else if (party[i].status) { + states[i] = (this.scene as BattleScene).showTeamSprites ? "ball" : "status" + } + if (P[i].isOnField()) { + //console.log(P[i].name + " is in battle; set it as seen") + P[i].usedInBattle = true + } + if (P[i].usedInBattle) total_visible++; + //console.log(P[i].name, P[i].getIconAtlasKey(true)) + } + console.log("Updating ball icons for party (" + P.length + ")") + if (staticparty.length > 0) { + for (var i = 0; i < staticparty.length; i++) { + //console.log(i, staticparty[i].name) + } + } + var Spacing = P.length == 6 ? 6 : 8 + this.teamCount = P.length + for (var ballindex = 0; ballindex < 6; ballindex++) { + //console.log(ballindex + ": setting icon " + states[ballindex]) + if (states[ballindex] == "ball" && P[ballindex].usedInBattle && (this.scene as BattleScene).showTeamSprites) { + this.teamIcons[ballindex].setTexture(P[ballindex].getIconAtlasKey(true)) + this.teamIcons[ballindex].setFrame(P[ballindex].getIconId(true)) + this.teamIcons[ballindex].setPositionRelative(this.nameText, Spacing * ballindex - 3, 11.75 - 4); + this.teamIcons[ballindex].setDisplaySize(18 * 0.8, 15 * 0.8) + this.teamIconOver[ballindex].setTexture(P[ballindex].getIconAtlasKey(true)) + this.teamIconOver[ballindex].setFrame(P[ballindex].getIconId(true)) + this.teamIconOver[ballindex].setPositionRelative(this.nameText, Spacing * ballindex - 3, 11.75 - 4); + this.teamIconOver[ballindex].setDisplaySize(18 * 0.8, 15 * 0.8) + this.teamIconOver[ballindex].setVisible(true) + this.teamIconsShow[ballindex] = true + if (P[ballindex].status && P[ballindex].hp) { + switch (P[ballindex].status.effect) { + case StatusEffect.NONE: + // Uncallable; replaced by "ball" + break; + case StatusEffect.POISON: + this.teamIconOver[ballindex].setTintFill(0xe40dfc) + break; + case StatusEffect.TOXIC: + this.teamIconOver[ballindex].setTintFill(0xfa2590) + break; + case StatusEffect.PARALYSIS: + this.teamIconOver[ballindex].setTintFill(0xf7ec1e) + break; + case StatusEffect.SLEEP: + this.teamIconOver[ballindex].setTintFill(0x54bfaa) + break; + case StatusEffect.FREEZE: + this.teamIconOver[ballindex].setTintFill(0xcbf0f2) + break; + case StatusEffect.BURN: + this.teamIconOver[ballindex].setTintFill(0xf51905) + break; + case StatusEffect.FAINT: + // Uncallable; replaced by "faint" + break; + } + } else { + this.teamIconOver[ballindex].clearTint() + this.teamIconOver[ballindex].setVisible(false) + this.teamIconsShow[ballindex] = false + } + } else { + this.teamIcons[ballindex].setTexture("pb_tray_ball") + this.teamIcons[ballindex].setFrame(states[ballindex]) + this.teamIcons[ballindex].setPositionRelative(this.nameText, Spacing * ballindex, 11.75); + this.teamIcons[ballindex].setDisplaySize(7, 7) + this.teamIcons[ballindex].setVisible(states[ballindex] != 'empty') + this.teamIconOver[ballindex].clearTint() + this.teamIconOver[ballindex].setVisible(false) + this.teamIconsShow[ballindex] = false + this.teamIcons[ballindex].clearTint() + if (states[ballindex] == "status" && P[ballindex].usedInBattle) { + if (P[ballindex].status && P[ballindex].hp) { + switch (P[ballindex].status.effect) { + case StatusEffect.NONE: + // Uncallable; replaced by "ball" + break; + case StatusEffect.POISON: + this.teamIcons[ballindex].setTintFill(0xe40dfc) + break; + case StatusEffect.TOXIC: + this.teamIcons[ballindex].setTintFill(0xfa2590) + break; + case StatusEffect.PARALYSIS: + this.teamIcons[ballindex].setTintFill(0xf7ec1e) + break; + case StatusEffect.SLEEP: + this.teamIcons[ballindex].setTintFill(0x54bfaa) + break; + case StatusEffect.FREEZE: + this.teamIcons[ballindex].setTintFill(0xcbf0f2) + break; + case StatusEffect.BURN: + this.teamIcons[ballindex].setTintFill(0xf51905) + break; + case StatusEffect.FAINT: + // Uncallable; replaced by "faint" + break; + } + } else if (this.teamIcons[ballindex].tint) { + this.teamIcons[ballindex].clearTint() + } + } else if (this.teamIcons[ballindex].tint) { + this.teamIcons[ballindex].clearTint() + } + } + } + } + setOffset(offset: boolean): void { if (this.offset === offset) { return; @@ -538,11 +713,15 @@ export default class BattleInfo extends Phaser.GameObjects.Container { if (this.lastStatus !== StatusEffect.NONE) { this.statusIndicator.setFrame(StatusEffect[this.lastStatus].toLowerCase()); + } else if (this.player) { + this.statusIndicator.setVisible(!!this.lastStatus); + } else { + this.statusIndicator.setVisible(!!this.lastStatus); + this.switchIconVisibility(this.showingTeam, true) } - this.statusIndicator.setVisible(!!this.lastStatus); if (!this.player && this.ownedIcon.visible) { - this.ownedIcon.setAlpha(this.statusIndicator.visible ? 0 : 1); + this.switchIconVisibility(this.showingTeam, true) } } @@ -751,6 +930,65 @@ export default class BattleInfo extends Phaser.GameObjects.Container { //this.updateEffectiveness(this.currentEffectiveness); this.effectivenessContainer?.setVisible(true); } + if (!this.override) this.switchIconVisibility(visible); + // this.teamIconOver[ballindex].setAlpha(0.4, 0.4, 0.7, 0.7) + } + toggleTeamTray(visible: boolean): void { + this.pressedShow = visible; + if (!this.override) this.switchIconVisibility(visible); + } + + /** + * Overrides the state of the team display. + * + * The state can't be switched by the player until the override is removed, but you can call this again to change the override state. + */ + addTeamDisplayOverride(visible: boolean): void { + this.override = true; + this.switchIconVisibility(visible); + } + /** + * Removes any override on the team display. + * + * The team display will then show/hide as required. + */ + removeTeamDisplayOverride(): void { + this.override = false; + this.switchIconVisibility(this.pressedShow); + } + + /** Show or hide team display. */ + switchIconVisibility(visible: boolean = this.showingTeam, override?: boolean): void { + if (!this.iconsActive) visible = false + if (this.showingTeam == visible && !override) return; // Don't spam requests + this.showingTeam = visible + this.scene.tweens.add({ + targets: this.teamIcons, + duration: Utils.fixedInt(125), + ease: "Sine.easeInOut", + alpha: visible ? 1 : 0 + }); + this.scene.tweens.add({ + targets: this.teamIconOver, + duration: Utils.fixedInt(125), + ease: "Sine.easeInOut", + alphaTopLeft: visible ? 0.4 : 0, + alphaTopRight: visible ? 0.4 : 0, + alphaBottomLeft: visible ? 0.7 : 0, + alphaBottomRight: visible ? 0.7 : 0, + }); + this.scene.tweens.add({ + targets: [ this.championRibbon, this.ownedIcon ], + duration: Utils.fixedInt(125), + ease: "Sine.easeInOut", + alpha: visible && this.iconsActive ? 0 : this.statusIndicator.visible ? 0 : 1 + }); + this.scene.tweens.add({ + targets: this.statusIndicator, + duration: Utils.fixedInt(125), + ease: "Sine.easeInOut", + alpha: visible && this.iconsActive ? 0 : (!!this.lastStatus ? 1 : 0) + }); } /**