From d8acbafc7517622b94232c0bb45948f0c945d1a5 Mon Sep 17 00:00:00 2001 From: Llinos Evans <36418502+PlagueVonKarma@users.noreply.github.com> Date: Wed, 28 Aug 2024 14:01:06 +0100 Subject: [PATCH] Stat exp., DV, & Hidden Power display s/o Crystal Legacy for their DV & Hidden Power display code, which got this off the ground. Credited aptly. I modified what they had with Stat Exp, but the menu is a little jank and scrolling is buggy. Someone wanna pick that up? --- README.md | 3 +- engine/gfx/cgb_layouts.asm | 13 +- engine/gfx/color.asm | 1 - engine/pokemon/stats_screen.asm | 545 +++++++++++++++++++++++++++++--- gfx/stats/pages.pal | 6 + gfx/stats/stats.pal | 2 + maps/PlayersHouse2F.asm | 8 +- 7 files changed, 531 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 20ede46..e6456ae 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ As the open source nature of this project implies, people are free to reuse what If you use our implementations of anything at all, it is encouraged to submit Pull Requests for bug fixes if you find any issues! We very much appreciate them! ## Development Credits -- Plague von Karma (Director, Kanto Expansion Pak Founder, Programming, Maps) +- Plague von Karma (Director, Kanto Expansion Pak Founder, Programming, Maps, Stat Exp. Display code) - Martha's Against Humanity (Kanto Expansion Pak ROM Hack Creator, Programmer, Spriter) - Zeta_Null (Repository Creator, Spriter, Programming, Music) - LadyMisticus (Documentation, Programming, Mapping, Spriter) @@ -134,6 +134,7 @@ JEP-affiliated spriters require sprites to be used with direct credit for non-co - ZoomTen - Honey Pot & Honey Grandma features from Pokemon October, commits [here](https://github.com/pokeachromicdevs/pokeoctober/commit/d00cd6fafdbe5069d2cc452a154942f82f7fceb6), [here](https://github.com/pokeachromicdevs/pokeoctober/commit/1a6f3e4f0307656018f02d4981c973efa814a248), and [here](https://github.com/pokeachromicdevs/pokeoctober/commit/8114fead91828dd6d986fe120d6c5cd5e3c6cbf6). Safari Game restoration [here](https://github.com/pokeachromicdevs/pokeoctober/commit/2ff835730b2a61a757ad67f13e50480c965d2a0c}. - Ferropexola/aforward9600: Time of day-based tileset palette code - Rangi42/polishedcrystal: [Decoration shop script](https://github.com/Rangi42/polishedcrystal/blob/master/maps/GoldenrodHarbor.asm) +- cRz-Shadows & Crystal Legacy Devs - [DVs & Hidden Power display code](https://github.com/cRz-Shadows/Pokemon_Crystal_Legacy/blob/main/engine/pokemon/stats_screen.asm) Original readme proceeding... # 16-bit index expansion for Crystal diff --git a/engine/gfx/cgb_layouts.asm b/engine/gfx/cgb_layouts.asm index 3eea777..9ed9f15 100644 --- a/engine/gfx/cgb_layouts.asm +++ b/engine/gfx/cgb_layouts.asm @@ -215,7 +215,7 @@ _CGB_StatsScreenHPPals: call LoadPalette_White_Col1_Col2_Black ; exp palette ld hl, StatsScreenPagePals ld de, wBGPals1 palette 3 - ld bc, 3 palettes ; pink, green, and blue page palettes + ld bc, 4 palettes ; pink, green, and blue page palettes - now with orange! ld a, BANK(wBGPals1) call FarCopyWRAM call WipeAttrmap @@ -230,20 +230,25 @@ _CGB_StatsScreenHPPals: ld a, $2 ; exp palette call ByteFill - hlcoord 13, 5, wAttrmap + hlcoord 11, 5, wAttrmap lb bc, 2, 2 ld a, $3 ; pink page palette call FillBoxCGB - hlcoord 15, 5, wAttrmap + hlcoord 13, 5, wAttrmap lb bc, 2, 2 ld a, $4 ; green page palette call FillBoxCGB - hlcoord 17, 5, wAttrmap + hlcoord 15, 5, wAttrmap lb bc, 2, 2 ld a, $5 ; blue page palette call FillBoxCGB + + hlcoord 17, 5, wAttrmap + lb bc, 2, 2 + ld a, $6 ; orange page palette + call FillBoxCGB call ApplyAttrmap call ApplyPals diff --git a/engine/gfx/color.asm b/engine/gfx/color.asm index 2102973..5af4d13 100644 --- a/engine/gfx/color.asm +++ b/engine/gfx/color.asm @@ -375,7 +375,6 @@ LoadStatsScreenPals: ret z ld hl, StatsScreenPals ld b, 0 - dec c add hl, bc add hl, bc ldh a, [rSVBK] diff --git a/engine/pokemon/stats_screen.asm b/engine/pokemon/stats_screen.asm index 4d41aa9..2a744e3 100644 --- a/engine/pokemon/stats_screen.asm +++ b/engine/pokemon/stats_screen.asm @@ -1,7 +1,11 @@ +; BUG: The icons up top don't match your scrolling. +; I probably missed something. +; Review: https://github.com/pret/pokecrystal/wiki/Add-a-fourth-stats-page const_def 1 const PINK_PAGE ; 1 const GREEN_PAGE ; 2 const BLUE_PAGE ; 3 + const ORANGE_PAGE ; 4 DEF NUM_STAT_PAGES EQU const_value - 1 DEF STAT_PAGE_MASK EQU %00000011 @@ -62,12 +66,7 @@ StatsScreenInit_gotaddress: StatsScreenMain: xor a ld [wJumptableIndex], a -; ??? - ld [wStatsScreenFlags], a - ld a, [wStatsScreenFlags] - and ~STAT_PAGE_MASK - or PINK_PAGE ; first_page - ld [wStatsScreenFlags], a + ld [wStatsScreenFlags], a ; PINK_PAGE .loop ld a, [wJumptableIndex] and ~(1 << 7) @@ -82,12 +81,7 @@ StatsScreenMain: StatsScreenMobile: xor a ld [wJumptableIndex], a -; ??? - ld [wStatsScreenFlags], a - ld a, [wStatsScreenFlags] - and ~STAT_PAGE_MASK - or PINK_PAGE ; first_page - ld [wStatsScreenFlags], a + ld [wStatsScreenFlags], a ; PINK_PAGE .loop farcall Mobile_SetOverworldDelay ld a, [wJumptableIndex] @@ -373,20 +367,22 @@ StatsScreen_JoypadAction: .a_button ld a, c - cp BLUE_PAGE ; last page + cp ORANGE_PAGE ; last page jr z, .b_button .d_right inc c - ld a, BLUE_PAGE ; last page + ld a, ORANGE_PAGE ; last page cp c jr nc, .set_page ld c, PINK_PAGE ; first page jr .set_page .d_left + ld a, c dec c + and a ; cp PINK_PAGE jr nz, .set_page - ld c, BLUE_PAGE ; last page + ld c, ORANGE_PAGE ; last page jr .set_page .done @@ -489,19 +485,6 @@ StatsScreen_InitUpperHalf: dw sBoxMonNicknames dw wBufferMonNickname -StatsScreen_PlaceVerticalDivider: ; unreferenced -; The Japanese stats screen has a vertical divider. - hlcoord 7, 0 - ld bc, SCREEN_WIDTH - ld d, SCREEN_HEIGHT -.loop - ld a, $31 ; vertical divider - ld [hl], a - add hl, bc - dec d - jr nz, .loop - ret - StatsScreen_PlaceHorizontalDivider: hlcoord 0, 7 ld b, SCREEN_WIDTH @@ -513,7 +496,7 @@ StatsScreen_PlaceHorizontalDivider: ret StatsScreen_PlacePageSwitchArrows: - hlcoord 12, 6 + hlcoord 10, 6 ld [hl], "◀" hlcoord 19, 6 ld [hl], "▶" @@ -569,7 +552,6 @@ StatsScreen_LoadGFX: .PageTilemap: ld a, [wStatsScreenFlags] maskbits NUM_STAT_PAGES - dec a ld hl, .Jumptable rst JumpTable ret @@ -580,6 +562,7 @@ StatsScreen_LoadGFX: dw LoadPinkPage dw LoadGreenPage dw LoadBluePage + dw LoadOrangePage assert_table_length NUM_STAT_PAGES LoadPinkPage: @@ -829,6 +812,486 @@ IDNoString: OTString: db "OT/@" +; Will display DVs, Stat Exp, Hidden Power... +; Tech itself comes from pret's tutorial: https://github.com/pret/pokecrystal/wiki/Add-a-fourth-stats-page +; DVs and Hidden Power yoinked from Crystal Legacy: https://github.com/cRz-Shadows/Pokemon_Crystal_Legacy/blob/main/engine/pokemon/stats_screen.asm +LoadOrangePage: + ; BUG: This code doesn't display the divider for some reason. Not sure how to get one going. Are you a bad enough dude to make this happen? + ;hlcoord 10, 12 + ;ld de, SCREEN_WIDTH + ;ld b, 1 + ;ld a, $31 ; vertical divider +;.vertical_divider + ;ld [hl], a + ;add hl, de + ;dec b + ;jr nz, .vertical_divider + + call StatsScreen_PrintStatExp + call StatsScreen_PrintDVs + + ; For now, there is no condition for showing Hidden Power. + ; Crystal Legacy had the display as a reward, but you can figure out the Hidden Power from the DVs showing anyway. Why bother, then? + ; Condition code proceeding... + ; check if we've caught all the unown, Event flag set by talking to printer guy at ruins lab + ;ld de, EVENT_CAUGHT_ALL_UNOWN + ;ld b, CHECK_FLAG + ;call EventFlagAction + ;ld a, c + ;and a + ;ret z ; flag was not set + + call StatsScreen_PrintHiddenPower + ret + +StatsScreen_PrintStatExp: + hlcoord 1, 8 + ld de, .statExpStr1 + call PlaceString + hlcoord 1, 9 + ld de, .statExpStr2 + call PlaceString + + hlcoord 1, 10 + ld de, .statExpStr3 + call PlaceString + + hlcoord 1, 11 + ld de, .statExpStr4 + call PlaceString + + hlcoord 1, 12 + ld de, .statExpStr5 + call PlaceString + + hlcoord 1, 13 + ld de, .statExpStr6 + call PlaceString + + ;ld a, [wTempMonHPExp] + ;swap a + ;and %011111 + ;ld [wPokedexStatus], a + ld de, wTempMonHPExp + lb bc, PRINTNUM_LEADINGZEROS | 2, 5 ; bytes, digits + hlcoord 6, 9 + call PrintNum + + ld de, wTempMonAtkExp + lb bc, PRINTNUM_LEADINGZEROS | 2, 5 ; bytes, digits + hlcoord 6, 10 + call PrintNum + + ld de, wTempMonDefExp + lb bc, PRINTNUM_LEADINGZEROS | 2, 5 ; bytes, digits + hlcoord 6, 11 + call PrintNum + + ld de, wTempMonSpcExp + lb bc, PRINTNUM_LEADINGZEROS | 2, 5 ; bytes, digits + hlcoord 6, 12 + call PrintNum + + ld de, wTempMonSpdExp + lb bc, PRINTNUM_LEADINGZEROS | 2, 5 ; bytes, digits + hlcoord 6, 13 + call PrintNum + + ret + +.statExpStr1: + db " STAT EXP. / DVs@" + +.statExpStr2: + db "HP: /@" + +.statExpStr3: + db "ATK: /@" + +.statExpStr4: + db "DEF: /@" + +.statExpStr5: + db "SPC: /@" + +.statExpStr6: + db "SPE: /@" + +StatsScreen_PrintDVs: + ; we're using wPokedexStatus because why not, nobody using it atm lol + ; ATK DV + ld a, [wTempMonDVs] ; only get the first byte of the word + and %11110000 ; most significant nybble of first byte in word-sized wTempMonDVs + swap a ; so we can print it properly + ld [wPokedexStatus], a + ld c, 0 + ; calc HP stat contribution + and 1 ; a still has the ATK DV + jr z, .atk_not_odd + ld a, 0 + add 8 + ld b, 0 + ld c, a + ; +.atk_not_odd + push bc + ld de, wPokedexStatus + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 ; bytes, digits + hlcoord 14, 10 + call PrintNum + + ; DEF DV + ld a, [wTempMonDVs] ; only get the first byte of the word + and %00001111 ; least significant nybble, don't need to swap the bits of the byte + ld [wPokedexStatus], a ;DEF + ; calc HP stat contribution + pop bc + and 1 ; a still has the DEF DV + jr z, .def_not_odd + ld a, c + add 4 + ld b, 0 + ld c, a + ; +.def_not_odd + push bc + ld de, wPokedexStatus + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 ; bytes, digits + hlcoord 14, 11 + call PrintNum + + ; SPE DV + ld a, [wTempMonDVs + 1] ; second byte of word + and %11110000 ; most significant nybble of 2nd byte in word-sized wTempMonDVs + swap a ; so we can print it properly + ld [wPokedexStatus], a ;SPEED + ; calc HP stat contribution + pop bc + and 1 ; a still has the SPEED DV + jr z, .speed_not_odd + ld a, c + add 2 + ld b, 0 + ld c, a + ; +.speed_not_odd + push bc + ld de, wPokedexStatus + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 ; bytes, digits + hlcoord 14, 12 ; 1, 5, 9, 13 + call PrintNum + + ; SPC DV + ld a, [wTempMonDVs + 1] ; second byte of word + and %00001111 ; least significant nybble, don't need to swap the bits of the byte + ld [wPokedexStatus], a ;SPC + ; calc HP stat contribution + pop bc + and 1 ; a still has the DEF DV + jr z, .spc_not_odd + ld a, c + add 1 + ld b, 0 + ld c, a + ; +.spc_not_odd + push bc + ld de, wPokedexStatus + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 ; bytes, digits + hlcoord 14, 13 + call PrintNum + ; hlcoord 18, 15 ; 1, 4, 7, 10, 13 + ; call PrintNum + + ; HP + ; HP DV is determined by the last bit of each of these four DVs + ; odd Attack DV adds 8, Defense adds 4, Speed adds 2, and Special adds 1 + ;For example, a Lugia with the DVs 5 Atk, 15 Def, 13 Spe, and 13 Spc will have: + ; 5 Attack = Odd, HP += 8 + ; 15 Defense = Odd, HP += 4 + ; 13 Speed = Odd, HP += 2 + ; 13 Special = Odd, HP += 1 + ;resulting in an HP stat of 15 + ; THANKS SMOGON + ; going to "and 1" each final value and push a counter to stack to preserve it + pop bc + ld a, c + ld [wPokedexStatus], a + ld de, wPokedexStatus + lb bc, PRINTNUM_LEADINGZEROS | 1, 2 ; bytes, digits + hlcoord 14, 9 ; 1, 4, 7, 10, 13 + call PrintNum + ret + +StatsScreen_LoadUnownFont: + ld a, BANK(sScratch) + call OpenSRAM + ld hl, UnownFont + ; sScratch + $188 was the address of sDecompressBuffer in pokegold + ld de, sScratch + $188 + ld bc, 38 tiles + ld a, BANK(UnownFont) + call FarCopyBytes + ; ld hl, sScratch + $188 + ; ld bc, (NUM_UNOWN + 1) tiles + ;call Pokedex_InvertTiles + ld de, sScratch + $188 + ld hl, vTiles1 tile $3a ;FIRST_UNOWN_CHAR + lb bc, BANK(Pokedex_LoadUnownFont), NUM_UNOWN + call Request2bpp + call CloseSRAM + ret + +StatsScreen_HiddenPow_BP: + call StatsScreen_LoadUnownFont +; Take the top/most significant bit from each stat +; basically, if the DV is 8 or above +; arrange those bits in order, into a nybble + ; Attack + ld a, [wTempMonDVs] + swap a + and %1000 + ; Defense + ld b, a + ld a, [wTempMonDVs] + and %1000 + srl a + or b + ; Speed + ld b, a + ld a, [wTempMonDVs + 1] + swap a + and %1000 + srl a + srl a + or b + ; Special + ld b, a + ld a, [wTempMonDVs + 1] + and %1000 + srl a + srl a + srl a + or b +; Multiply by 5 + ld b, a + add a + add a + add b +; Add Special & 3 + ld b, a + ld a, [wTempMonDVs + 1] + and %0011 + add b +; Divide by 2 and add 30 + 1 + srl a + add 30 + inc a + ret + +StatsScreen_PrintHiddenPower: +; print Type first + ld a, [wTempMonDVs] + and %0011 + ld b, a + ; + (Atk & 3) << 2 + ld a, [wTempMonDVs] + and %0011 << 4 + swap a + add a + add a + or b +; Skip Normal + inc a +; Skip Bird + cp BIRD + jr c, .done + inc a +; Skip unused types + cp UNUSED_TYPES + jr c, .done + add UNUSED_TYPES_END - UNUSED_TYPES +.done + add a + ld e, a + ld d, 0 + ld a, BANK(TypeNames) + ld hl, TypeNames + add hl, de + call GetFarWord + ld d, h + ld e, l + + hlcoord 2, 16 + call PlaceString_UnownFont_Type + hlcoord 1, 15 + ld de, .hidden_pow_text + call PlaceString_UnownFont + + call StatsScreen_HiddenPow_BP + ld de, .hp_70_text + cp 70 + jr c, .not70 + ld de, .hp_70_text + sub 70 + jr .print1 +.not70 + cp 60 + jr c, .not60 + ld de, .hp_60_text + sub 60 + jr .print1 +.not60 + cp 50 + jr c, .not50 + ld de, .hp_50_text + sub 50 + jr .print1 +.not50 + cp 40 + jr c, .not40 + ld de, .hp_40_text + sub 40 + jr .print1 +.not40 + ld de, .hp_30_text + sub 30 +.print1 + hlcoord 8, 16 + push af + call PlaceString_UnownFont + pop af + + cp 9 + jr c, .not9 + ld de, .hp_9_text + jr .print2 +.not9 + cp 8 + jr c, .not8 + ld de, .hp_8_text + jr .print2 +.not8 + cp 7 + jr c, .not7 + ld de, .hp_7_text + jr .print2 +.not7 + cp 6 + jr c, .not6 + ld de, .hp_6_text + jr .print2 +.not6 + cp 5 + jr c, .not5 + ld de, .hp_5_text + jr .print2 +.not5 + cp 4 + jr c, .not4 + ld de, .hp_4_text + jr .print2 +.not4 + cp 3 + jr c, .not3 + ld de, .hp_3_text + jr .print2 +.not3 + cp 2 + jr c, .not2 + ld de, .hp_2_text + jr .print2 +.not2 + cp 1 + ret c + ld de, .hp_1_text +.print2 + ; hlcoord 13, 16 + call PlaceString_UnownFont + ret +.hidden_pow_text: + db "HIDDEN POWER@" +.hp_70_text: + db "SEVENTY@" +.hp_60_text: + db "SIXTY@" +.hp_50_text: + db "FIFTY@" +.hp_40_text: + db "FOURTY@" +.hp_30_text: + db "THIRTY@" +.hp_1_text: + db "-ONE@" +.hp_2_text: + db "-TWO@" +.hp_3_text: + db "-THREE@" +.hp_4_text: + db "-FOUR@" +.hp_5_text: + db "-FIVE@" +.hp_6_text: + db "-SIX@" +.hp_7_text: + db "-SEVEN@" +.hp_8_text: + db "-EIGHT@" +.hp_9_text: + db "-NINE@" + +PlaceString_UnownFont_Type: + push hl + push de +.loop + pop hl + ld a, BANK(TypeNames) + call GetFarByte + ld d, h + ld e, l + pop hl + cp "@" + ret z + inc de + sub "A" + add $BA ; FIRST_UNOWN_CHAR + ld [hli], a + push hl + push de + jr .loop + +PlaceString_UnownFont: + push hl + push de +.loop + pop hl + ld a, [hl] + pop hl + cp "@" + ret z + cp " " + call z, .skip_space + cp "-" + call z, .skip_space + inc de + sub "A" + add $BA ; FIRST_UNOWN_CHAR + + ld [hli], a + push hl + push de + jr .loop +.skip_space: + ld [hl], a + inc hl + push hl + inc de + push de + pop hl + ld a, [hl] + pop hl + ret + StatsScreen_PlaceFrontpic: ld hl, wTempMonDVs predef GetUnownLetter @@ -961,8 +1424,7 @@ StatsScreen_GetAnimationParam: .Tempmon: ld bc, wTempMonSpecies - jr .CheckEggFaintedFrzSlp ; utterly pointless - + ; fallthrough .CheckEggFaintedFrzSlp: ld a, [wCurPartySpecies] cp EGG @@ -1128,6 +1590,9 @@ StatsScreen_AnimateEgg: ret StatsScreen_LoadPageIndicators: + hlcoord 11, 5 + ld a, $36 ; " " " " + call .load_square hlcoord 13, 5 ld a, $36 ; first of 4 small square tiles call .load_square @@ -1138,13 +1603,19 @@ StatsScreen_LoadPageIndicators: ld a, $36 ; " " " " call .load_square ld a, c + cp PINK_PAGE + hlcoord 11, 5 + jr z, .load_highlighted_square cp GREEN_PAGE + hlcoord 13, 5 + jr z, .load_highlighted_square + cp BLUE_PAGE + hlcoord 15, 5 + jr z, .load_highlighted_square + ; must be ORANGE_PAGE + hlcoord 17, 5 +.load_highlighted_square ld a, $3a ; first of 4 large square tiles - hlcoord 13, 5 ; PINK_PAGE (< GREEN_PAGE) - jr c, .load_square - hlcoord 15, 5 ; GREEN_PAGE (= GREEN_PAGE) - jr z, .load_square - hlcoord 17, 5 ; BLUE_PAGE (> GREEN_PAGE) .load_square push bc ld [hli], a diff --git a/gfx/stats/pages.pal b/gfx/stats/pages.pal index 837e10c..096cb9b 100644 --- a/gfx/stats/pages.pal +++ b/gfx/stats/pages.pal @@ -13,3 +13,9 @@ RGB 17, 31, 31 RGB 17, 31, 31 RGB 00, 00, 00 +; orange + RGB 31, 31, 31 + RGB 30, 24, 16 + RGB 30, 22, 12 + RGB 00, 00, 00 + \ No newline at end of file diff --git a/gfx/stats/stats.pal b/gfx/stats/stats.pal index 5b12e02..69a9af4 100644 --- a/gfx/stats/stats.pal +++ b/gfx/stats/stats.pal @@ -4,3 +4,5 @@ RGB 21, 31, 14 ; blue RGB 17, 31, 31 +; orange + RGB 30, 24, 16 diff --git a/maps/PlayersHouse2F.asm b/maps/PlayersHouse2F.asm index 05c411e..9dd5137 100644 --- a/maps/PlayersHouse2F.asm +++ b/maps/PlayersHouse2F.asm @@ -113,11 +113,11 @@ PlayersHouse2F_MapEvents: db 0, 0 ; filler def_warp_events -IF DEF(_DEBUG) +;IF DEF(_DEBUG) warp_event 7, 0, DEBUG_ROOM, 1 -else - warp_event 7, 0, PLAYERS_HOUSE_1F, 3 -endc +;else +; warp_event 7, 0, PLAYERS_HOUSE_1F, 3 +;endc def_coord_events