diff --git a/public/images/ui/legacy/pbinfo_stat.json b/public/images/ui/legacy/pbinfo_stat.json index b7da47fc192..a956f81150d 100644 --- a/public/images/ui/legacy/pbinfo_stat.json +++ b/public/images/ui/legacy/pbinfo_stat.json @@ -176,6 +176,27 @@ "w": 12, "h": 6 } + }, + { + "filename": "HP", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 8, + "h": 6 + }, + "frame": { + "x": 112, + "y": 0, + "w": 8, + "h": 6 + } } ] } diff --git a/public/images/ui/legacy/pbinfo_stat.png b/public/images/ui/legacy/pbinfo_stat.png index 62ec3758772..18b0ca314de 100644 Binary files a/public/images/ui/legacy/pbinfo_stat.png and b/public/images/ui/legacy/pbinfo_stat.png differ diff --git a/public/images/ui/legacy/pbinfo_stat_numbers.json b/public/images/ui/legacy/pbinfo_stat_numbers.json index fa7d757990f..c106d1cf41e 100644 --- a/public/images/ui/legacy/pbinfo_stat_numbers.json +++ b/public/images/ui/legacy/pbinfo_stat_numbers.json @@ -281,6 +281,27 @@ "w": 9, "h": 8 } + }, + { + "filename": "empty", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 1, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 1, + "h": 8 + }, + "frame": { + "x": 117, + "y": 0, + "w": 1, + "h": 8 + } } ] } diff --git a/public/images/ui/legacy/pbinfo_stat_numbers.png b/public/images/ui/legacy/pbinfo_stat_numbers.png index ee1453b2107..b02dfbec72f 100644 Binary files a/public/images/ui/legacy/pbinfo_stat_numbers.png and b/public/images/ui/legacy/pbinfo_stat_numbers.png differ diff --git a/public/images/ui/pbinfo_stat.json b/public/images/ui/pbinfo_stat.json index f431e5afafd..4ec46c467b1 100644 --- a/public/images/ui/pbinfo_stat.json +++ b/public/images/ui/pbinfo_stat.json @@ -176,6 +176,27 @@ "w": 13, "h": 7 } + }, + { + "filename": "HP", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 1, + "w": 9, + "h": 7 + }, + "frame": { + "x": 120, + "y": 0, + "w": 9, + "h": 7 + } } ] } diff --git a/public/images/ui/pbinfo_stat.png b/public/images/ui/pbinfo_stat.png index 46169091e7c..1c20ed70e82 100644 Binary files a/public/images/ui/pbinfo_stat.png and b/public/images/ui/pbinfo_stat.png differ diff --git a/public/images/ui/pbinfo_stat_numbers.json b/public/images/ui/pbinfo_stat_numbers.json index ec4f7117bb7..ccd49bbbb79 100644 --- a/public/images/ui/pbinfo_stat_numbers.json +++ b/public/images/ui/pbinfo_stat_numbers.json @@ -281,6 +281,27 @@ "w": 9, "h": 8 } + }, + { + "filename": "empty", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 1, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 1, + "h": 8 + }, + "frame": { + "x": 117, + "y": 0, + "w": 1, + "h": 8 + } } ] } diff --git a/public/images/ui/pbinfo_stat_numbers.png b/public/images/ui/pbinfo_stat_numbers.png index c778ba99273..1465f8b7a64 100644 Binary files a/public/images/ui/pbinfo_stat_numbers.png and b/public/images/ui/pbinfo_stat_numbers.png differ diff --git a/src/battle-scene.ts b/src/battle-scene.ts index d8c34fefdd6..0775da48112 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -122,6 +122,7 @@ export default class BattleScene extends SceneBase { public enableTutorials: boolean = import.meta.env.VITE_BYPASS_TUTORIAL === "1"; public enableMoveInfo: boolean = true; public enableRetries: boolean = false; + public hideIvs: boolean = false; /** * Determines the condition for a notification should be shown for Candy Upgrades * - 0 = 'Off' diff --git a/src/data/battle-stat.ts b/src/data/battle-stat.ts index d70e6655f8c..a0cb7ca88e1 100644 --- a/src/data/battle-stat.ts +++ b/src/data/battle-stat.ts @@ -8,7 +8,8 @@ export enum BattleStat { SPD, ACC, EVA, - RAND + RAND, + HP } export function getBattleStatName(stat: BattleStat) { @@ -27,6 +28,8 @@ export function getBattleStatName(stat: BattleStat) { return i18next.t("pokemonInfo:Stat.ACC"); case BattleStat.EVA: return i18next.t("pokemonInfo:Stat.EVA"); + case BattleStat.HP: + return i18next.t("pokemonInfo:Stat.HPStat"); default: return "???"; } diff --git a/src/locales/de/settings.ts b/src/locales/de/settings.ts index 227b8f97581..4ac69868a7e 100644 --- a/src/locales/de/settings.ts +++ b/src/locales/de/settings.ts @@ -15,6 +15,7 @@ export const settings: SimpleTranslationEntries = { "skipSeenDialogues": "Gesehenen Dialog überspringen", "battleStyle": "Kampfstil", "enableRetries": "Erneut versuchen aktivieren", + "hideIvs": "IS-Scanner verstecken", "tutorials": "Tutorials", "touchControls": "Touch Steuerung", "vibrations": "Vibration", diff --git a/src/locales/en/pokemon-info.ts b/src/locales/en/pokemon-info.ts index f31fdac69ab..70a06294c76 100644 --- a/src/locales/en/pokemon-info.ts +++ b/src/locales/en/pokemon-info.ts @@ -15,7 +15,8 @@ export const pokemonInfo: PokemonInfoTranslationEntries = { "SPD": "Speed", "SPDshortened": "Spd", "ACC": "Accuracy", - "EVA": "Evasiveness" + "EVA": "Evasiveness", + "HPStat": "HP" }, Type: { diff --git a/src/locales/en/settings.ts b/src/locales/en/settings.ts index 491bfa4a481..0b88f5e82c8 100644 --- a/src/locales/en/settings.ts +++ b/src/locales/en/settings.ts @@ -15,6 +15,7 @@ export const settings: SimpleTranslationEntries = { "skipSeenDialogues": "Skip Seen Dialogues", "battleStyle": "Battle Style", "enableRetries": "Enable Retries", + "hideIvs": "Hide IV scanner", "tutorials": "Tutorials", "touchControls": "Touch Controls", "vibrations": "Vibrations", diff --git a/src/locales/es/settings.ts b/src/locales/es/settings.ts index 407bfab602f..cac4b25c689 100644 --- a/src/locales/es/settings.ts +++ b/src/locales/es/settings.ts @@ -15,6 +15,7 @@ export const settings: SimpleTranslationEntries = { "skipSeenDialogues": "Skip Seen Dialogues", "battleStyle": "Battle Style", "enableRetries": "Enable Retries", + "hideIvs": "Hide IV scanner", "tutorials": "Tutorials", "touchControls": "Touch Controls", "vibrations": "Vibrations", diff --git a/src/locales/fr/settings.ts b/src/locales/fr/settings.ts index 9e3bd04923a..2ed697c4e7f 100644 --- a/src/locales/fr/settings.ts +++ b/src/locales/fr/settings.ts @@ -15,6 +15,7 @@ export const settings: SimpleTranslationEntries = { "skipSeenDialogues": "Passer dialogues connus", "battleStyle": "Style de combat", "enableRetries": "Activer les réessais", + "hideIvs": "Masquer Scanner d’IV", "tutorials": "Tutoriels", "touchControls": "Contrôles tactiles", "vibrations": "Vibrations", diff --git a/src/locales/it/settings.ts b/src/locales/it/settings.ts index 07cbe6b7f46..2381987d387 100644 --- a/src/locales/it/settings.ts +++ b/src/locales/it/settings.ts @@ -15,6 +15,7 @@ export const settings: SimpleTranslationEntries = { "skipSeenDialogues": "Skip Seen Dialogues", "battleStyle": "Battle Style", "enableRetries": "Enable Retries", + "hideIvs": "Hide IV scanner", "tutorials": "Tutorials", "touchControls": "Touch Controls", "vibrations": "Vibrations", diff --git a/src/locales/ja/settings.ts b/src/locales/ja/settings.ts index ad23d1b6576..ef20d071d2d 100644 --- a/src/locales/ja/settings.ts +++ b/src/locales/ja/settings.ts @@ -15,6 +15,7 @@ export const settings: SimpleTranslationEntries = { "skipSeenDialogues": "Skip Seen Dialogues", "battleStyle": "試合のルール", "enableRetries": "リトライを有効にする", + "hideIvs": "Hide IV scanner", "tutorials": "チュートリアル", "touchControls": "タッチ操作", "vibrations": "振動", diff --git a/src/locales/ko/settings.ts b/src/locales/ko/settings.ts index 40e9676b6da..3dcdc3b07c1 100644 --- a/src/locales/ko/settings.ts +++ b/src/locales/ko/settings.ts @@ -15,6 +15,7 @@ export const settings: SimpleTranslationEntries = { "skipSeenDialogues": "본 대화 생략", "battleStyle": "시합 룰", "enableRetries": "재도전 허용", + "hideIvs": "개체값탐지기 효과 끄기", "tutorials": "튜토리얼", "touchControls": "터치 컨트롤", "vibrations": "진동", diff --git a/src/locales/pt_BR/settings.ts b/src/locales/pt_BR/settings.ts index c3a077acc4a..316dacb8fc6 100644 --- a/src/locales/pt_BR/settings.ts +++ b/src/locales/pt_BR/settings.ts @@ -15,6 +15,7 @@ export const settings: SimpleTranslationEntries = { "skipSeenDialogues": "Pular Diálogos Vistos", "battleStyle": "Estilo de Batalha", "enableRetries": "Habilitar Novas Tentativas", + "hideIvs": "Esconder scanner de IV", "tutorials": "Tutorial", "touchControls": "Controles de Toque", "vibrations": "Vibração", diff --git a/src/locales/zh_CN/settings.ts b/src/locales/zh_CN/settings.ts index 92372deec42..a55fe3e8cd9 100644 --- a/src/locales/zh_CN/settings.ts +++ b/src/locales/zh_CN/settings.ts @@ -15,6 +15,7 @@ export const settings: SimpleTranslationEntries = { "skipSeenDialogues": "跳过已读对话", "battleStyle": "对战模式", "enableRetries": "允许重试", + "hideIvs": "禁用个体值探测器信息", "tutorials": "教程", "touchControls": "触摸操作", "vibrations": "手柄震动", diff --git a/src/locales/zh_TW/settings.ts b/src/locales/zh_TW/settings.ts index c6c055ed4d2..133cce61fd3 100644 --- a/src/locales/zh_TW/settings.ts +++ b/src/locales/zh_TW/settings.ts @@ -15,6 +15,7 @@ export const settings: SimpleTranslationEntries = { "skipSeenDialogues": "跳過已讀對話", "battleStyle": "對戰模式", "enableRetries": "允許重試", + "hideIvs": "禁用個體值探測器信息", "tutorials": "教程", "touchControls": "觸摸操作", "vibrations": "手柄震動", diff --git a/src/phases.ts b/src/phases.ts index c4662df199d..5d72ffef42a 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -50,7 +50,7 @@ import { GameMode, GameModes, getGameMode } from "./game-mode"; import PokemonSpecies, { getPokemonSpecies, speciesStarters } from "./data/pokemon-species"; import i18next from "./plugins/i18n"; import Overrides from "#app/overrides"; -import { TextStyle, addTextObject } from "./ui/text"; +import { TextStyle, addTextObject, getTextColor } from "./ui/text"; import { Type } from "./data/type"; import { BerryUsedEvent, EncounterPhaseEvent, MoveUsedEvent, TurnEndEvent, TurnInitEvent } from "./events/battle-scene"; import { Abilities } from "#enums/abilities"; @@ -5599,19 +5599,45 @@ export class ScanIvsPhase extends PokemonPhase { const pokemon = this.getPokemon(); - this.scene.ui.showText(i18next.t("battle:ivScannerUseQuestion", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => { - this.scene.ui.setMode(Mode.CONFIRM, () => { - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.clearText(); - new CommonBattleAnim(CommonAnim.LOCK_ON, pokemon, pokemon).play(this.scene, () => { - this.scene.ui.getMessageHandler().promptIvs(pokemon.id, pokemon.ivs, this.shownIvs).then(() => this.end()); + let enemyIvs: number[] = []; + let statsContainer: Phaser.GameObjects.Sprite[] = []; + let statsContainerLabels: Phaser.GameObjects.Sprite[] = []; + const enemyField = this.scene.getEnemyField(); + const uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible + for (let e = 0; e < enemyField.length; e++) { + enemyIvs = enemyField[e].ivs; + const currentIvs = this.scene.gameData.dexData[enemyField[e].species.getRootSpeciesId()].ivs; // we are using getRootSpeciesId() here because we want to check against the baby form, not the mid form if it exists + const ivsToShow = this.scene.ui.getMessageHandler().getTopIvs(enemyIvs, this.shownIvs); + statsContainer = enemyField[e].getBattleInfo().getStatsValueContainer().list as Phaser.GameObjects.Sprite[]; + statsContainerLabels = statsContainer.filter(m => m.name.indexOf("icon_stat_label") >= 0); + for (let s = 0; s < statsContainerLabels.length; s++) { + const ivStat = Stat[statsContainerLabels[s].frame.name]; + if (enemyIvs[ivStat] > currentIvs[ivStat] && ivsToShow.indexOf(Number(ivStat)) >= 0) { + const hexColour = enemyIvs[ivStat] === 31 ? getTextColor(TextStyle.PERFECT_IV, false, uiTheme) : getTextColor(TextStyle.SUMMARY_GREEN, false, uiTheme); + const hexTextColour = Phaser.Display.Color.HexStringToColor(hexColour).color; + statsContainerLabels[s].setTint(hexTextColour); + } + statsContainerLabels[s].setVisible(true); + } + } + + if (!this.scene.hideIvs) { + this.scene.ui.showText(i18next.t("battle:ivScannerUseQuestion", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => { + this.scene.ui.setMode(Mode.CONFIRM, () => { + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.clearText(); + new CommonBattleAnim(CommonAnim.LOCK_ON, pokemon, pokemon).play(this.scene, () => { + this.scene.ui.getMessageHandler().promptIvs(pokemon.id, pokemon.ivs, this.shownIvs).then(() => this.end()); + }); + }, () => { + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.clearText(); + this.end(); }); - }, () => { - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.clearText(); - this.end(); }); - }); + } else { + this.end(); + } } } diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts index 96acffd6bfb..3f9b906d1cf 100644 --- a/src/system/settings/settings.ts +++ b/src/system/settings/settings.ts @@ -79,6 +79,7 @@ export const SettingKeys = { Skip_Seen_Dialogues: "SKIP_SEEN_DIALOGUES", Battle_Style: "BATTLE_STYLE", Enable_Retries: "ENABLE_RETRIES", + Hide_IVs: "HIDE_IVS", Tutorials: "TUTORIALS", Touch_Controls: "TOUCH_CONTROLS", Vibration: "VIBRATION", @@ -250,6 +251,13 @@ export const Setting: Array = [ default: 0, type: SettingType.GENERAL }, + { + key: SettingKeys.Hide_IVs, + label: i18next.t("settings:hideIvs"), + options: OFF_ON, + default: 0, + type: SettingType.GENERAL + }, { key: SettingKeys.Tutorials, label: i18next.t("settings:tutorials"), @@ -618,6 +626,9 @@ export function setSetting(scene: BattleScene, setting: string, value: integer): case SettingKeys.Enable_Retries: scene.enableRetries = Setting[index].options[value].value === "On"; break; + case SettingKeys.Hide_IVs: + scene.hideIvs = Setting[index].options[value].value === "On"; + break; case SettingKeys.Skip_Seen_Dialogues: scene.skipSeenDialogues = Setting[index].options[value].value === "On"; break; diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index 98ebdf21078..dbf0d5911c8 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -12,8 +12,6 @@ import BattleFlyout from "./battle-flyout"; import { WindowVariant, addWindow } from "./ui-theme"; import i18next from "i18next"; -const battleStatOrder = [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD ]; - export default class BattleInfo extends Phaser.GameObjects.Container { private baseY: number; @@ -70,6 +68,10 @@ export default class BattleInfo extends Phaser.GameObjects.Container { public flyoutMenu?: BattleFlyout; + private battleStatOrder: BattleStat[]; + private battleStatOrderPlayer = [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD]; + private battleStatOrderEnemy = [BattleStat.HP, BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD]; + constructor(scene: Phaser.Scene, x: number, y: number, player: boolean) { super(scene, x, y); this.baseY = y; @@ -222,20 +224,44 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.statValuesContainer = this.scene.add.container(0, 0); this.statsContainer.add(this.statValuesContainer); - battleStatOrder.map((s, i) => { - const statX = i > 1 ? this.statNumbers[i - 2].x + this.statNumbers[i - 2].width + 4 : -this.statsBox.width + 8; - const statY = -this.statsBox.height / 2 + 4 + (i < battleStatOrder.length - 1 ? (i % 2 ? 10 : 0) : 5); + // this gives us a different starting location from the left of the label and padding between stats for a player vs enemy + // since the player won't have HP to show, it doesn't need to change from the current version + const startingX = this.player ? -this.statsBox.width + 8 : -this.statsBox.width + 5; + const paddingX = this.player ? 4 : 2; + const statOverflow = this.player ? 1 : 0; + this.battleStatOrder = this.player ? this.battleStatOrderPlayer : this.battleStatOrderEnemy; // this tells us whether or not to use the player or enemy battle stat order + + this.battleStatOrder.map((s, i) => { + // we do a check for i > statOverflow to see when the stat labels go onto the next column + // For enemies, we have HP (i=0) by itself then a new column, so we check for i > 0 + // For players, we don't have HP, so we start with i = 0 and i = 1 for our first column, and so need to check for i > 1 + const statX = i > statOverflow ? this.statNumbers[Math.max(i - 2, 0)].x + this.statNumbers[Math.max(i - 2, 0)].width + paddingX : startingX; // we have the Math.max(i - 2, 0) in there so for i===1 to not return a negative number; since this is now based on anything >0 instead of >1, we need to allow for i-2 < 0 + + const baseY = -this.statsBox.height / 2 + 4; // this is the baseline for the y-axis + let statY: number; // this will be the y-axis placement for the labels + if (this.battleStatOrder[i] === BattleStat.SPD || this.battleStatOrder[i] === BattleStat.HP) { + statY = baseY + 5; + } else { + statY = baseY + (!!(i % 2) === this.player ? 10 : 0); // we compare i % 2 against this.player to tell us where to place the label; because this.battleStatOrder for enemies has HP, this.battleStatOrder[1]=ATK, but for players this.battleStatOrder[0]=ATK, so this comparing i % 2 to this.player fixes this issue for us + } + const statLabel = this.scene.add.sprite(statX, statY, "pbinfo_stat", BattleStat[s]); statLabel.setName("icon_stat_label_" + i.toString()); statLabel.setOrigin(0, 0); statLabels.push(statLabel); this.statValuesContainer.add(statLabel); - const statNumber = this.scene.add.sprite(statX + statLabel.width, statY, "pbinfo_stat_numbers", "3"); + const statNumber = this.scene.add.sprite(statX + statLabel.width, statY, "pbinfo_stat_numbers", this.battleStatOrder[i] !== BattleStat.HP ? "3" : "empty"); statNumber.setName("icon_stat_number_" + i.toString()); statNumber.setOrigin(0, 0); this.statNumbers.push(statNumber); this.statValuesContainer.add(statNumber); + + if (this.battleStatOrder[i] === BattleStat.HP) { + statLabel.setVisible(false); + statNumber.setVisible(false); + } + }); if (!this.player) { @@ -274,6 +300,10 @@ export default class BattleInfo extends Phaser.GameObjects.Container { } } + getStatsValueContainer(): Phaser.GameObjects.Container { + return this.statValuesContainer; + } + initInfo(pokemon: Pokemon) { this.updateNameText(pokemon); const nameTextWidth = this.nameText.displayWidth; @@ -403,7 +433,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.statValuesContainer.setPosition(8, 7); } - const battleStats = battleStatOrder.map(() => 0); + const battleStats = this.battleStatOrder.map(() => 0); this.lastBattleStats = battleStats.join(""); this.updateBattleStats(battleStats); @@ -622,7 +652,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { const battleStats = pokemon.summonData ? pokemon.summonData.battleStats - : battleStatOrder.map(() => 0); + : this.battleStatOrder.map(() => 0); const battleStatsStr = battleStats.join(""); if (this.lastBattleStats !== battleStatsStr) { @@ -740,8 +770,10 @@ export default class BattleInfo extends Phaser.GameObjects.Container { } updateBattleStats(battleStats: integer[]): void { - battleStatOrder.map((s, i) => { - this.statNumbers[i].setFrame(battleStats[s].toString()); + this.battleStatOrder.map((s, i) => { + if (s !== BattleStat.HP) { + this.statNumbers[i].setFrame(battleStats[s].toString()); + } }); } diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts index 6c5049394a7..1c7dfb27630 100644 --- a/src/ui/battle-message-ui-handler.ts +++ b/src/ui/battle-message-ui-handler.ts @@ -196,24 +196,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler { this.scene.executeWithSeedOffset(() => { let levelUpStatsValuesText = ""; const stats = Utils.getEnumValues(Stat); - let shownStats: Stat[] = []; - if (shownIvsCount < 6) { - const statsPool = stats.slice(0); - for (let i = 0; i < shownIvsCount; i++) { - let shownStat: Stat; - let highestIv = -1; - statsPool.map(s => { - if (ivs[s] > highestIv) { - shownStat = s as Stat; - highestIv = ivs[s]; - } - }); - shownStats.push(shownStat!); // TODO: is the bang correct? - statsPool.splice(statsPool.indexOf(shownStat!), 1); // TODO: is the bang correct? - } - } else { - shownStats = stats; - } + const shownStats = this.getTopIvs(ivs, shownIvsCount); for (const s of stats) { levelUpStatsValuesText += `${shownStats.indexOf(s) > -1 ? this.getIvDescriptor(ivs[s], s, pokemonId) : "???"}\n`; } @@ -229,35 +212,70 @@ export default class BattleMessageUiHandler extends MessageUiHandler { }); } + getTopIvs(ivs: integer[], shownIvsCount: integer): Stat[] { + const stats = Utils.getEnumValues(Stat); + let shownStats: Stat[] = []; + if (shownIvsCount < 6) { + const statsPool = stats.slice(0); + for (let i = 0; i < shownIvsCount; i++) { + let shownStat: Stat | null = null; + let highestIv = -1; + statsPool.map(s => { + if (ivs[s] > highestIv) { + shownStat = s as Stat; + highestIv = ivs[s]; + } + }); + if (shownStat) { + shownStats.push(shownStat); + statsPool.splice(statsPool.indexOf(shownStat), 1); + } + } + } else { + shownStats = stats; + } + return shownStats; + } + getIvDescriptor(value: integer, typeIv: integer, pokemonId: integer): string { - const starterSpecies = this.scene.getPokemonById(pokemonId)!.species.getRootSpeciesId(true); // TODO: is this bang correct? + const starterSpecies = this.scene.getPokemonById(pokemonId)!.species.getRootSpeciesId(); // we are using getRootSpeciesId() here because we want to check against the baby form, not the mid form if it exists const starterIvs: number[] = this.scene.gameData.dexData[starterSpecies].ivs; const uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible // Function to wrap text in color based on comparison - const coloredText = (text: string, isBetter: boolean) => { - const textStyle: TextStyle = isBetter ? TextStyle.SUMMARY_GREEN : TextStyle.SUMMARY; + const coloredText = (text: string, isBetter: boolean, ivValue) => { + let textStyle: TextStyle; + if (isBetter) { + if (ivValue === 31) { + textStyle = TextStyle.PERFECT_IV; + } else { + textStyle = TextStyle.SUMMARY_GREEN; + } + } else { + textStyle = TextStyle.SUMMARY; + } + //const textStyle: TextStyle = isBetter ? TextStyle.SUMMARY_GREEN : TextStyle.SUMMARY; const color = getTextColor(textStyle, false, uiTheme); return `[color=${color}][shadow=${getTextColor(textStyle, true, uiTheme)}]${text}[/shadow][/color]`; }; if (value > 30) { - return coloredText(i18next.t("battleMessageUiHandler:ivBest"), value > starterIvs[typeIv]); + return coloredText(i18next.t("battleMessageUiHandler:ivBest"), value > starterIvs[typeIv], value); } if (value === 30) { - return coloredText(i18next.t("battleMessageUiHandler:ivFantastic"), value > starterIvs[typeIv]); + return coloredText(i18next.t("battleMessageUiHandler:ivFantastic"), value > starterIvs[typeIv], value); } if (value > 20) { - return coloredText(i18next.t("battleMessageUiHandler:ivVeryGood"), value > starterIvs[typeIv]); + return coloredText(i18next.t("battleMessageUiHandler:ivVeryGood"), value > starterIvs[typeIv], value); } if (value > 10) { - return coloredText(i18next.t("battleMessageUiHandler:ivPrettyGood"), value > starterIvs[typeIv]); + return coloredText(i18next.t("battleMessageUiHandler:ivPrettyGood"), value > starterIvs[typeIv], value); } if (value > 0) { - return coloredText(i18next.t("battleMessageUiHandler:ivDecent"), value > starterIvs[typeIv]); + return coloredText(i18next.t("battleMessageUiHandler:ivDecent"), value > starterIvs[typeIv], value); } - return coloredText(i18next.t("battleMessageUiHandler:ivNoGood"), value > starterIvs[typeIv]); + return coloredText(i18next.t("battleMessageUiHandler:ivNoGood"), value > starterIvs[typeIv], value); } showNameText(name: string): void { diff --git a/src/ui/text.ts b/src/ui/text.ts index 43dca9efc45..c1d7fe091c0 100644 --- a/src/ui/text.ts +++ b/src/ui/text.ts @@ -37,7 +37,8 @@ export enum TextStyle { MOVE_PP_NEAR_EMPTY, MOVE_PP_EMPTY, SMALLER_WINDOW_ALT, - BGM_BAR + BGM_BAR, + PERFECT_IV } export interface TextStyleOptions { @@ -291,6 +292,7 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui case TextStyle.SUMMARY_GREEN: return !shadow ? "#78c850" : "#306850"; case TextStyle.SETTINGS_LABEL: + case TextStyle.PERFECT_IV: return !shadow ? "#f8b050" : "#c07800"; case TextStyle.SETTINGS_SELECTED: return !shadow ? "#f88880" : "#f83018";