From 9eb57c0c661cde84064ae5a5319bd27e6d01be5f Mon Sep 17 00:00:00 2001 From: Opaque02 <66582645+Opaque02@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:04:12 +1000 Subject: [PATCH] [QoL] IV scanner update to hide the prompt and let you see the stats mid battle on the stats screen (#3285) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * IV scanner PR fix Updated locales to have updated keys for IV scanner in menu Updated legacy UI to work with IV scanner changes Updated code to have player and enemy battle stats for ease of use Updated logic to make the player side work exactly the same as previously since there should be no HP stat shown for players. Also updated the colours so there's no more grey option for unknown stats Added HP, updated logic and colours. Need to undo changes to player pokemon to not be as squished because of no HP, and need to see what happens for trainers Fixing up some git errors Fixed a bug with double battles not updating the pokemon properly Updated settings to allow for the ability to skip the IV scanning prompts Adding functionality to IV scanner to skip prompt and see IVs mid battle * Merged with latest + fixed bug with IV scanner vs pokemon info container getRootSpeciesId being different * Updated as per merge comment * Updating to fix comments * Updated comments * Update src/locales/fr/settings.ts Co-authored-by: Lugiad' * Update src/locales/de/settings.ts Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> * Update src/locales/pt_BR/settings.ts Co-authored-by: José Ricardo Fleury Oliveira * Update src/locales/ko/settings.ts Co-authored-by: Enoch * Update src/locales/zh_CN/settings.ts Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Update src/locales/zh_TW/settings.ts Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Updating text of IV scanner to be gold * Updated text colour to use one of the existing golds instead of a custom gold * Japanese locale * Updating docs --------- Co-authored-by: Lugiad' Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: José Ricardo Fleury Oliveira Co-authored-by: Enoch Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> --- public/images/ui/legacy/pbinfo_stat.json | 21 +++++ public/images/ui/legacy/pbinfo_stat.png | Bin 263 -> 451 bytes .../images/ui/legacy/pbinfo_stat_numbers.json | 21 +++++ .../images/ui/legacy/pbinfo_stat_numbers.png | Bin 392 -> 435 bytes public/images/ui/pbinfo_stat.json | 21 +++++ public/images/ui/pbinfo_stat.png | Bin 278 -> 496 bytes public/images/ui/pbinfo_stat_numbers.json | 21 +++++ public/images/ui/pbinfo_stat_numbers.png | Bin 430 -> 499 bytes src/battle-scene.ts | 1 + src/data/battle-stat.ts | 5 +- src/locales/de/settings.ts | 1 + src/locales/en/pokemon-info.ts | 3 +- src/locales/en/settings.ts | 1 + src/locales/es/settings.ts | 1 + src/locales/fr/settings.ts | 1 + src/locales/it/settings.ts | 1 + src/locales/ja/settings.ts | 1 + src/locales/ko/settings.ts | 1 + src/locales/pt_BR/settings.ts | 1 + src/locales/zh_CN/settings.ts | 1 + src/locales/zh_TW/settings.ts | 1 + src/phases.ts | 50 +++++++++--- src/system/settings/settings.ts | 11 +++ src/ui/battle-info.ts | 52 ++++++++++--- src/ui/battle-message-ui-handler.ts | 72 +++++++++++------- src/ui/text.ts | 4 +- 26 files changed, 240 insertions(+), 52 deletions(-) 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 62ec3758772daea6013a4de5532575a66caf8116..18b0ca314dec0bc30e3527d9828421a5417256e0 100644 GIT binary patch literal 451 zcmV;!0X+VRP)Px#1ZP1_K>z@;j|==^1poj6Q%OWYR7gvul)G&MK@dY%SBgVbak;v1=-gE}SLiO> zibA&{n`aRq2+q#het@v^;c(}qg9h05{f^J)?c;tFzG02^lp68vzae?Qz7BjGtuanI(D^*SybWIJI?a<0V$QQ( zot&rM{i?k3PpF=`>bqR&_66EcxugA!33xhRPDk*7b)Y@Q=yQ>okK?*DhdA9+X@KgT zq)mF);MDsQzJHfHdVl&Jk+0lORKLN5rv66EOo1;``8e+Tn|oI1{G9*Z@AF;mXg__A z>{l;HbszM{Uo^~EMBe>CiJ6bq0djo+z~!Msui683oIYRSex3gcm|uM!pncx2^9uG# zefO*83H2vms(NVc&2*sZcm9uX>4ziTUS6B+06ITq)<+Mg_y6jj{ATk%`Z2x$!H8}^ txZ~DE0000EWmrjOO-%qQ00008000000002eQEc4QuN(io6fN32b;e=)XJ@8wjxa57 z6;5`pyz#?~2;;a-r4XYn{3?!Y<6HKbItN$2xk}gw>0y zUzy)p<5e-!w)Vy<(87aih3;8-LtI=7KLTHk<}Jk-^i|&t;uc GLK6T7%VuW) 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 ee1453b21070f8de40a299a2d0c82c49093799cc..b02dfbec72f63c34f12dd1232d071eefc305c9c1 100644 GIT binary patch literal 435 zcmV;k0ZjghP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!TOkOSlj+ytcz%1M?yuOEzFY<6PpQlR}L@;nacBaX)b^VgrweYTS4aX=q&JWh^D>SJQ~MU3O3 zV4cI~Ha6wI4#r&$$i?zF79=MPi)>f>*e>C5a8{QC`Z`a!#|ILG{$a5WNYo*XE$Zk# zsBwbRVJsHT=} dYn*i^gd@0!^jmMfva0|9002ovPDHLkV1kzcyjlPN literal 392 zcmV;30eAk1P)NeVolC?^B79yfh4NP^lrY9U!*DY-V@3rV{hYdQ>YK;=1YJaz3T;`<^$DGJL<5 z0VRW87@CHmA>NuYKzH1TLC5xSzn%dVgI*Y#hCzM2e@<+(--30)Oref_gmu$R&9E*Q zKCPUg&65~>rQzm$c=)wGxON}pkE{!ZPit-h_?q;dhMV)@;n(^|U!-Qgl_%A@VDM** z28vT)T`)O@Pln{f8%r6yr(x9i(DP6xH!0n5bN5`F;gccxJgbFgqhZwe(DRg7RCba7 mA?H5)Du%PaS?j+(7uOe-FYwO$9P0Z30000Px#1ZP1_K>z@;j|==^1poj6fJsC_R7gwhmd#BAF%X3vI@zs>1~^bcBIUpZB#>x< zLmHr_-BJS2@X*WCc)S~O$RVF(jb}VR9@`sbGYrGA81p=b_H(#ot{dxEa`x~kaC+Xp z9tndWm6om&qn8Wos)I260oL-C*`S)TJ?>k~if4w@s9-S}r z=u8yPqcQan96mp4Lud@(b=1i>y+*kylI3zdcdM4~hq;wCb%6Ur_c|Hgcf^wZ+~yyT zulxA|=&)ya9>(B7)<=M5^kwv#Q@nVVOYMNZihd(^b m4rN$LW=%~1DgXcg2mk;800000(o>TF0000>3p^r=85p>QL70(Y)*K0-;9^e~#}JM4YbQkt9Z}$Lk>2rt zuKR?x9W_gW7GHdEIZRA3PQiWWf_gEBD>-+P7WbQFDeB5(FiQnkYJT0+d!^ilFVNop z&g@AaU;a`5G;zDk43V2*;$L0AUpUvbfi-hpw1(4@QY8*&1zW>D^RKHGtIA58?GDdB z^z5+u8@b1GkFN|~6tyyB+m=mNc0TgfI9*xz^hZc=_{JB-6D{k$v)J#gjM>h5gnvUW Wt8RFN+!3I289ZJ6T-G@yGywokWokPB 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 c778ba992734421a718b2c49db1db0ae77a28e09..1465f8b7a6497fa417bb2b7d2d8e80de93e8dd48 100644 GIT binary patch literal 499 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!T8~Esx)bWzSVxwcsx71 zHVPoblQ#P^&l6{yarMvNWEAHXbzSe`vTB;9;nN3_GZ=U90p^v*7x!#)M#7$>J!@uW+MgBZOOjC)Q=9*dDI z-fX=Nhb#{E_=i{y(Pw=fu1g$Ei6dcgUY^cdzsmwHJP*%dtikX zquv8~X2n77I-v8AltXfPu(qy~ph#YqhT4aR`cJy|(%| z=-B0U>%RW@K!)Z)r(RDcEhmNo@O81j>Y!uaUmr{-E|U+WG!HuUcz&65QgkGFQ^dP* pGQ=U$J=Ax7r$eNB= literal 430 zcmV;f0a5;mP)X}UpFSFJe%YMSjb zvz=}Te=dw_+OM;>zwNiTz<(WGW!%j?&)@0VTARh5OWbc`j(J{Tok%Zt#$YoH;sBj7 z0D#IlJRc6p%*|?r>-8D{#_^;+F^22I1yqy`_PebZNKrNbfWEEq_WF{{oLyYu^!yS4 z#PO(4jM4P@WGYS8UqlLVGYqiSvW&F&OBuS>FtHC$Vz?0ZyX|CN5<3@SjG<>5X2}?8 zQ)v+?7z&xQg%~oUa!zD?QzeEgj_Hh<7_VVM6DZ`EEo4UD)*|DZy2Lt;DavMIyoRBA zxP2Ty%KN9gENZI8IE_78Q^T$GD~(@jhsGYQsdI~*V!X;!+J?fg{Gd2S+NQZaWGcsm zi<{b~a&9zLI&@IbQb7LyuD?x7eaKXf@hzMCJ+VH0TaTtDpMHPh { - 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";