; 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: a screen-paging overworld camera. Each d-pad press INSTANTLY redraws ; the next screenful of the world -- no character walking. At a map edge it hops ; to the connected map using that connection's alignment offset (or clamps if ; there's none). B restores the origin view and returns to the SL0P menu. It is ; self-contained: it renders straight from the map block buffer (wOverworldMap) ; and never touches the walk engine. ; =========================================================================== DEF SLOP_PAGE_X EQU 10 ; coords moved per horizontal page (~one screen) DEF SLOP_PAGE_Y EQU 8 ; coords moved per vertical page SlopExplore: ; save origin (map, coords, block coords, view pointer) to restore on exit ld a, [wYCoord] ld b, a ld a, [wXCoord] ld c, a push bc ld a, [wYBlockCoord] ld b, a ld a, [wXBlockCoord] ld c, a push bc ld a, [wCurrentTileBlockMapViewPointer] ld b, a ld a, [wCurrentTileBlockMapViewPointer + 1] ld c, a push bc ld a, [wCurMap] push af call LoadMapData ; reload current map + tileset (menu clobbered VRAM) .renderView ; block-aligned camera; view pointer = wOverworldMap + (by+1)*stride + bx, ; where by = wYCoord/2, bx = wXCoord/2, stride = wCurMapWidth + 2*MAP_BORDER. xor a ld [wYBlockCoord], a ld [wXBlockCoord], a ld a, [wCurMapWidth] add MAP_BORDER * 2 ld c, a ld b, 0 ld a, [wYCoord] srl a inc a ld hl, 0 .mulRow add hl, bc dec a jr nz, .mulRow ld a, [wXCoord] srl a add l ld l, a jr nc, .noCarry inc h .noCarry ld bc, wOverworldMap add hl, bc ld a, l ld [wCurrentTileBlockMapViewPointer], a ld a, h ld [wCurrentTileBlockMapViewPointer + 1], a call LoadCurrentMapView ld b, HIGH(vBGMap0) call CopyScreenTileBufferToVRAM ldh a, [rLCDC] ; hide sprites for a clean camera res B_LCDC_OBJS, a ldh [rLCDC], a ld a, $90 ldh [hWY], a .input call DelayFrame call JoypadLowSensitivity ldh a, [hJoyPressed] ld d, a bit B_PAD_B, d jp nz, .exit bit B_PAD_UP, d jr z, .ckDown ld a, [wYCoord] sub SLOP_PAGE_Y jp nc, .setY ld hl, wNorthConnectedMap ld de, wNorthConnectedMapYAlignment ld a, 0 ; clamp target = top jp .crossV .ckDown bit B_PAD_DOWN, d jr z, .ckLeft ld a, [wCurrentMapHeight2] dec a ld b, a ; b = max Y ld a, [wYCoord] add SLOP_PAGE_Y cp b jp c, .setY jp z, .setY ld hl, wSouthConnectedMap ld de, wSouthConnectedMapYAlignment ld a, b ; clamp target = max Y jp .crossV .ckLeft bit B_PAD_LEFT, d jr z, .ckRight ld a, [wXCoord] sub SLOP_PAGE_X jp nc, .setX ld hl, wWestConnectedMap ld de, wWestConnectedMapYAlignment ld a, 0 jp .crossH .ckRight bit B_PAD_RIGHT, d jp z, .input ld a, [wCurrentMapWidth2] dec a ld b, a ; b = max X ld a, [wXCoord] add SLOP_PAGE_X cp b jp c, .setX jp z, .setX ld hl, wEastConnectedMap ld de, wEastConnectedMapYAlignment ld a, b jp .crossH .setY ld [wYCoord], a jp .renderView .setX ld [wXCoord], a jp .renderView ; vertical cross (up/down): hl -> connected-map byte, de -> its YAlignment, ; a = Y to clamp to when there is no connection. .crossV ld b, a ld a, [hl] inc a jr z, .clampY ; $ff -> no connection ld a, [de] ; YAlignment -> new Y (absolute) ld c, a inc de ld a, [de] ; XAlignment -> added to X ld b, a ld a, [wXCoord] add b ld [wXCoord], a ld a, c ld [wYCoord], a ld a, [hl] ld [wCurMap], a call LoadMapData jp .renderView .clampY ld a, b ld [wYCoord], a jp .renderView ; horizontal cross (left/right): hl -> connected-map byte, de -> its YAlignment, ; a = X to clamp to when there is no connection. .crossH ld b, a ld a, [hl] inc a jr z, .clampX ld a, [de] ; YAlignment -> added to Y ld c, a inc de ld a, [de] ; XAlignment -> new X (absolute) ld [wXCoord], a ld a, [wYCoord] add c ld [wYCoord], a ld a, [hl] ld [wCurMap], a call LoadMapData jp .renderView .clampX ld a, b ld [wXCoord], a jp .renderView .exit pop af ld [wCurMap], a pop bc ld a, b ld [wCurrentTileBlockMapViewPointer], a ld a, c ld [wCurrentTileBlockMapViewPointer + 1], a pop bc ld a, b ld [wYBlockCoord], a ld a, c ld [wXBlockCoord], a pop bc ld a, b ld [wYCoord], a ld a, c ld [wXCoord], a call LoadMapData ; restore origin view (renders from 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