; SL0P MENU - a top-level cheat menu opened with SELECT in the overworld ; (hooked in home/overworld.asm). Table-driven: each entry has a name in ; SlopMenuText and a handler in SlopMenuHandlers. A handler returns: ; carry SET -> a map warp was started; exit the menu and let it proceed ; carry CLEAR -> return to the SL0P menu (redraw) ; Handlers may be submenus (WarpSubmenu, GiveItemSubmenu) or direct actions. ; ; To add an entry: add a "NAME" line to SlopMenuText, a `dw Handler` to ; SlopMenuHandlers, and bump SLOP_MENU_COUNT. DEF SLOP_MENU_COUNT EQU 13 SECTION "Slop Menu", ROMX SlopMenu:: ; ---- open the menu display (shared by the top menu and every submenu) ---- ldh a, [hUILayoutFlags] set BIT_SINGLE_SPACED_LINES, a set BIT_DOUBLE_SPACED_MENU, a ldh [hUILayoutFlags], a ld a, $ff ld [wUpdateSpritesEnabled], a call ClearSprites .redraw call ClearScreen hlcoord 5, 0 ld de, SlopMenuTitle call PlaceString hlcoord 4, 2 lb bc, SLOP_MENU_COUNT + 2, 11 call TextBoxBorder hlcoord 6, 3 ld de, SlopMenuText call PlaceString ; ON marker for the NOWILD toggle (item 10 -> row 13) ld a, [wUnusedFlag] and a jr z, .nowildOff hlcoord 13, 13 ld de, SlopOnText call PlaceString .nowildOff call SlopMenuShow xor a ld [wCurrentMenuItem], a ld [wLastMenuItem], a ld [wMenuWatchMovingOutOfBounds], a ld [wMenuJoypadPollCount], a ld a, 5 ld [wTopMenuItemX], a ld a, 3 ld [wTopMenuItemY], a ld a, PAD_A | PAD_B ld [wMenuWatchedKeys], a ld a, SLOP_MENU_COUNT - 1 ld [wMaxMenuItem], a call HandleMenuInput bit B_PAD_B, a jr nz, .close ; dispatch: call SlopMenuHandlers[wCurrentMenuItem] ld a, [wCurrentMenuItem] add a ld e, a ld d, 0 ld hl, SlopMenuHandlers add hl, de ld a, [hli] ld h, [hl] ld l, a ld de, .afterHandler push de jp hl .afterHandler jr c, .exitProceed jr .redraw .exitProceed call SlopMenuRestoreFlags ret .close call SlopMenuRestoreFlags ld a, $01 ld [wUpdateSpritesEnabled], a ; CloseTextDisplay rebuilds the overworld (LoadCurrentMapView restores the ; collision map) and ends with `pop af` + bankswitch expecting the caller's bank ; to have been pushed. We bypass DisplayTextID, so push it ourselves - otherwise ; the pop eats a stack word and corrupts the bank/collision state. ldh a, [hLoadedROMBank] push af jp CloseTextDisplay SlopMenuRestoreFlags: ldh a, [hUILayoutFlags] res BIT_SINGLE_SPACED_LINES, a res BIT_DOUBLE_SPACED_MENU, a ldh [hUILayoutFlags], a ret ; push wTileMap into VRAM and switch on the menu window display SlopMenuShow: ld b, HIGH(vBGMap1) call CopyScreenTileBufferToVRAM xor a ldh [hWY], a call LoadFontTilePatterns ld a, $01 ldh [hAutoBGTransferEnabled], a ret SlopMenuTitle: db "SL0P MENU@" SlopMenuText: db "WARP" next "HEAL" next "MONEY" next "COINS" next "BADGES" next "DEX" next "MAXTEAM" next "TEACH" next "HMS" next "ITEMS" next "NOWILD" next "REPEL" next "EXPLORE@" SlopOnText: db "ON@" SlopMenuHandlers: dw WarpSubmenu dw SlopHealParty dw SlopMaxCash dw SlopMaxCoins dw SlopAllBadges dw SlopDex dw SlopMaxTeam dw SlopTeach dw SlopGiveHMs dw GiveItemSubmenu dw SlopToggleNoWild dw SlopRepel dw SlopExplore ; =========================================================================== ; WARP submenu ; =========================================================================== DEF WARP_COUNT EQU 13 WarpSubmenu: call ClearScreen hlcoord 4, 0 ld de, WarpTitleText1 call PlaceString hlcoord 5, 1 ld de, WarpTitleText2 call PlaceString hlcoord 3, 2 lb bc, 13, 11 call TextBoxBorder hlcoord 5, 3 ld de, WarpMenuText call PlaceString call SlopMenuShow xor a ld [wCurrentMenuItem], a ld [wLastMenuItem], a ld [wMenuWatchMovingOutOfBounds], a ld [wMenuJoypadPollCount], a ld a, 4 ld [wTopMenuItemX], a ld a, 3 ld [wTopMenuItemY], a ld a, PAD_A | PAD_B ld [wMenuWatchedKeys], a ld a, WARP_COUNT - 1 ld [wMaxMenuItem], a call HandleMenuInput bit B_PAD_B, a jr nz, .cancel ld a, [wCurrentMenuItem] ld e, a ld d, 0 ld hl, WarpMapTable add hl, de ld a, [hl] ld [wDestinationMap], a ld hl, wStatusFlags6 set BIT_FLY_WARP, [hl] scf ret .cancel and a ret WarpTitleText1: db "SECRET SL0P@" WarpTitleText2: db "WARP MENU@" WarpMenuText: db "PALLET" next "VIRIDIAN" next "PEWTER" next "CERULEAN" next "LAVENDER" next "VERMILION" next "CELADON" next "FUCHSIA" next "CINNABAR" next "INDIGO" next "SAFFRON" next "ROUTE 4" next "ROUTE 10@" WarpMapTable: db PALLET_TOWN, VIRIDIAN_CITY, PEWTER_CITY, CERULEAN_CITY, LAVENDER_TOWN db VERMILION_CITY, CELADON_CITY, FUCHSIA_CITY, CINNABAR_ISLAND, INDIGO_PLATEAU db SAFFRON_CITY, ROUTE_4, ROUTE_10 ; =========================================================================== ; EXPLORE (P1): overworld map-connection browser. Renders the current map (no ; NPCs), and U/D/L/R jump to the connected map in that direction if one exists ; (via wCurMapConnections + the connection headers). B restores the original ; map and returns to the SL0P menu. No warping yet - read-only browse. ; =========================================================================== SlopExplore: ; save origin map + coords on the stack ld a, [wYCoord] ld b, a ld a, [wXCoord] ld c, a push bc ; origin Y,X ld a, [wCurrentTileBlockMapViewPointer] ld b, a ld a, [wCurrentTileBlockMapViewPointer + 1] ld c, a push bc ; origin view pointer ld a, [wCurMap] push af ; origin map .render ; LoadMapData loads the map header + block map into wOverworldMap, but it renders ; using a STALE wCurrentTileBlockMapViewPointer -- the game only ever sets that ; from warp / connection / walk data, never from wXCoord/wYCoord. So load the ; map, then compute a centered view pointer ourselves and redraw the view. call LoadMapData ; stride = wCurMapWidth + MAP_BORDER*2 ; bufRow = height/2 + 1 ; bufCol = width/2 ; wCurrentTileBlockMapViewPointer = wOverworldMap + bufRow*stride + bufCol ld a, [wCurMapWidth] add MAP_BORDER * 2 ld c, a ld b, 0 ; bc = row stride (blocks) ld hl, 0 ld a, [wCurMapHeight] srl a inc a ; bufRow (>= 1) .viewRowLoop add hl, bc dec a jr nz, .viewRowLoop ld a, [wCurMapWidth] srl a ; bufCol = width/2 add l ld l, a jr nc, .viewNoCarry inc h .viewNoCarry ld bc, wOverworldMap add hl, bc ld a, l ld [wCurrentTileBlockMapViewPointer], a ld a, h ld [wCurrentTileBlockMapViewPointer + 1], a xor a ld [wYBlockCoord], a ld [wXBlockCoord], a call LoadCurrentMapView ; redraw wTileMap centered on the map ldh a, [rLCDC] ; hide ALL sprites (player + actors) via LCDC res B_LCDC_OBJS, a ldh [rLCDC], a ld a, $90 ldh [hWY], a ; window off-screen -> the BG map is visible ; overlay direction markers at the screen edges for the legit connections call LoadFontTilePatterns ld a, [wCurMapConnections] ld e, a bit NORTH_F, e jr z, .noN hlcoord 9, 0 ld [hl], $8D .noN bit SOUTH_F, e jr z, .noS hlcoord 9, 15 ld [hl], $92 .noS bit WEST_F, e jr z, .noW hlcoord 0, 8 ld [hl], $96 .noW bit EAST_F, e jr z, .noE hlcoord 18, 8 ld [hl], $84 .noE ld b, HIGH(vBGMap0) call CopyScreenTileBufferToVRAM ; push map + markers to VRAM .input call DelayFrame call JoypadLowSensitivity ldh a, [hJoyPressed] ld d, a bit B_PAD_B, d jr nz, .exit bit B_PAD_UP, d jr z, .chkDown ld a, [wCurMapConnections] bit NORTH_F, a jp z, .input ld a, [wNorthConnectedMap] ld [wCurMap], a jp .render .chkDown bit B_PAD_DOWN, d jr z, .chkLeft ld a, [wCurMapConnections] bit SOUTH_F, a jp z, .input ld a, [wSouthConnectedMap] ld [wCurMap], a jp .render .chkLeft bit B_PAD_LEFT, d jr z, .chkRight ld a, [wCurMapConnections] bit WEST_F, a jp z, .input ld a, [wWestConnectedMap] ld [wCurMap], a jp .render .chkRight bit B_PAD_RIGHT, d jp z, .input ld a, [wCurMapConnections] bit EAST_F, a jp z, .input ld a, [wEastConnectedMap] ld [wCurMap], a jp .render .exit pop af ld [wCurMap], a ; restore origin map pop bc ; restore origin view pointer ld a, b ld [wCurrentTileBlockMapViewPointer], a ld a, c ld [wCurrentTileBlockMapViewPointer + 1], a pop bc ; restore origin Y,X ld a, b ld [wYCoord], a and $1 ld [wYBlockCoord], a ld a, c ld [wXCoord], a and $1 ld [wXBlockCoord], a call LoadMapData ; reload origin, rendered from the restored pointer and a ; carry clear -> back to SL0P menu ret ; =========================================================================== ; ITEMS submenu: give 99 of the chosen item (stacks via GiveItem) ; =========================================================================== DEF GIVE_COUNT EQU 12 GiveItemSubmenu: call ClearScreen hlcoord 6, 0 ld de, GiveTitleText call PlaceString hlcoord 1, 1 lb bc, GIVE_COUNT + 2, 16 call TextBoxBorder hlcoord 3, 2 ld de, GiveItemText call PlaceString call SlopMenuShow xor a ld [wCurrentMenuItem], a ld [wLastMenuItem], a ld [wMenuWatchMovingOutOfBounds], a ld [wMenuJoypadPollCount], a ld a, 2 ld [wTopMenuItemX], a ld [wTopMenuItemY], a ld a, PAD_A | PAD_B ld [wMenuWatchedKeys], a ld a, GIVE_COUNT - 1 ld [wMaxMenuItem], a call HandleMenuInput bit B_PAD_B, a jr nz, .back ld a, [wCurrentMenuItem] ld e, a ld d, 0 ld hl, GiveItemTable add hl, de ld b, [hl] ld c, 99 call GiveItem .back and a ret GiveTitleText: db "GIVE x99@" GiveItemText: db "MASTER BALL" next "ULTRA BALL" next "RARE CANDY" next "FULL RESTORE" next "MAX REVIVE" next "MAX ELIXER" next "PP UP" next "MOON STONE" next "FIRE STONE" next "THUNDERSTONE" next "WATER STONE" next "LEAF STONE@" GiveItemTable: db MASTER_BALL, ULTRA_BALL, RARE_CANDY, FULL_RESTORE db MAX_REVIVE, MAX_ELIXER, PP_UP, MOON_STONE db FIRE_STONE, THUNDER_STONE, WATER_STONE, LEAF_STONE ; =========================================================================== ; Direct-action cheats (return carry clear -> back to the SL0P menu) ; =========================================================================== ; HEAL: full HP + clear status for the whole party. SlopHealParty: ld a, [wPartyCount] and a jr z, .done ld c, a ld hl, wPartyMon1 .loop push hl ld de, $04 add hl, de xor a ld [hl], a ; status = 0 pop hl push hl ld de, $22 add hl, de ; -> maxHP ld a, [hli] ld b, a ld e, [hl] ld d, b pop hl push hl inc hl ; -> curHP ld a, d ld [hli], a ld a, e ld [hl], a pop hl ld de, $2C add hl, de dec c jr nz, .loop .done and a ret ; TEACH: give every party member an OP coverage moveset + PP ; (Hyper Beam / Earthquake / Ice Beam / Thunderbolt) SlopTeach: ld a, [wPartyCount] and a jr z, .done ld c, a ld hl, wPartyMon1 .loop push bc push hl ld de, $08 ; -> moves add hl, de ld a, $3F ; Hyper Beam ld [hli], a ld a, $59 ; Earthquake ld [hli], a ld a, $3A ; Ice Beam ld [hli], a ld a, $55 ; Thunderbolt ld [hli], a pop hl push hl ld de, $1D ; -> PP add hl, de ld b, 4 .pp ld a, $1F ; 31 PP each ld [hli], a dec b jr nz, .pp pop hl ld de, $2C add hl, de pop bc dec c jr nz, .loop .done and a ret ; HMS: give all five HMs (Cut/Fly/Surf/Strength/Flash) SlopGiveHMs: ld b, HM_CUT .loop push bc ld c, 1 call GiveItem pop bc inc b ld a, b cp HM_FLASH + 1 jr nz, .loop and a ret ; MONEY: 999999 (BCD) SlopMaxCash: ld a, $99 ld [wPlayerMoney], a ld [wPlayerMoney + 1], a ld [wPlayerMoney + 2], a and a ret ; COINS: 9999 game-corner coins (BCD) SlopMaxCoins: ld a, $99 ld [wPlayerCoins], a ld [wPlayerCoins + 1], a and a ret ; NOWILD toggle: no wild encounters (hooked in TryDoWildEncounter) SlopToggleNoWild: ld a, [wUnusedFlag] xor $01 ld [wUnusedFlag], a and a ret ; REPEL: refill repel steps SlopRepel: ld a, 255 ld [wRepelRemainingSteps], a and a ret ; BADGES: all 8 SlopAllBadges: ld a, $ff ld [wObtainedBadges], a and a ret ; DEX: mark every Pokemon owned + seen (19-byte flag arrays; last byte = 7 bits) SlopDex: ld hl, wPokedexOwned call .fill ld hl, wPokedexSeen call .fill and a ret .fill ld c, 18 .floop ld a, $ff ld [hli], a dec c jr nz, .floop ld [hl], $7f ret ; MAXTEAM: level 100, perfect DVs, maxed EVs, 999 stats + HP, exp = lvl 100 SlopMaxTeam: ld a, [wPartyCount] and a jr z, .done ld c, a ld hl, wPartyMon1 .loop push bc push hl ; current HP (+$01) = 999 inc hl ld a, $03 ld [hli], a ld a, $E7 ld [hl], a pop hl push hl ; exp (+$0E) = 1,000,000 ld de, $0E add hl, de ld a, $0F ld [hli], a ld a, $42 ld [hli], a ld a, $40 ld [hli], a ; EVs (+$11..$1A) = FFFF x5, then DVs (+$1B..$1C) = FFFF -> 12 bytes of $FF ld b, 12 .ffloop ld a, $ff ld [hli], a dec b jr nz, .ffloop pop hl push hl ; level (+$21) = 100 ld de, $21 add hl, de ld a, 100 ld [hli], a ; maxHP + 4 stats (+$22..$2B) = 999 x5 ld b, 5 .statloop ld a, $03 ld [hli], a ld a, $E7 ld [hli], a dec b jr nz, .statloop pop hl ld de, $2C add hl, de pop bc dec c jr nz, .loop .done and a ret