From b29e5ee203b6fa4592180ef6cca732462cca9af6 Mon Sep 17 00:00:00 2001 From: Rangi Date: Fri, 3 Jul 2020 11:51:00 -0400 Subject: Add subdirectories to data/ similar to pokecrystal Top level text/ is now solely for the former text/maps/ files, and other files are in their respective subdirectories in data/. --- home/overworld.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'home') diff --git a/home/overworld.asm b/home/overworld.asm index b96efcb4..460ce11e 100644 --- a/home/overworld.asm +++ b/home/overworld.asm @@ -867,7 +867,7 @@ IsBikeRidingAllowed:: scf ret -INCLUDE "data/bike_riding_tilesets.asm" +INCLUDE "data/tilesets/bike_riding_tilesets.asm" ; load the tile pattern data of the current tileset into VRAM LoadTilesetTilePatternData:: -- cgit v1.2.3 From 6bd86e10c32cd7b464425adfc01621f3ff6726aa Mon Sep 17 00:00:00 2001 From: Rangi Date: Fri, 3 Jul 2020 13:03:21 -0400 Subject: Reorganize home header --- home/clear_sprites.asm | 21 +++++++++++++++++++ home/header.asm | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ home/lcd.asm | 25 ++++++++++++++++++++++ home/start.asm | 10 +++++++++ 4 files changed, 113 insertions(+) create mode 100644 home/clear_sprites.asm create mode 100644 home/header.asm create mode 100644 home/lcd.asm create mode 100644 home/start.asm (limited to 'home') diff --git a/home/clear_sprites.asm b/home/clear_sprites.asm new file mode 100644 index 00000000..34f4b4ec --- /dev/null +++ b/home/clear_sprites.asm @@ -0,0 +1,21 @@ +ClearSprites:: + xor a + ld hl, wOAMBuffer + ld b, 40 * 4 +.loop + ld [hli], a + dec b + jr nz, .loop + ret + +HideSprites:: + ld a, 160 + ld hl, wOAMBuffer + ld de, 4 + ld b, 40 +.loop + ld [hl], a + add hl, de + dec b + jr nz, .loop + ret diff --git a/home/header.asm b/home/header.asm new file mode 100644 index 00000000..047f97f4 --- /dev/null +++ b/home/header.asm @@ -0,0 +1,57 @@ +; rst vectors (unused) + +SECTION "rst0", ROM0[$0000] + rst $38 + +SECTION "rst8", ROM0[$0008] + rst $38 + +SECTION "rst10", ROM0[$0010] + rst $38 + +SECTION "rst18", ROM0[$0018] + rst $38 + +SECTION "rst20", ROM0[$0020] + rst $38 + +SECTION "rst28", ROM0[$0028] + rst $38 + +SECTION "rst30", ROM0[$0030] + rst $38 + +SECTION "rst38", ROM0[$0038] + rst $38 + + +; Game Boy hardware interrupts + +SECTION "vblank", ROM0[$0040] + jp VBlank + +SECTION "lcd", ROM0[$0048] + rst $38 + +SECTION "timer", ROM0[$0050] + jp Timer + +SECTION "serial", ROM0[$0058] + jp Serial + +SECTION "joypad", ROM0[$0060] + reti + + +SECTION "Header", ROM0[$0100] + +Start:: +; Nintendo requires all Game Boy ROMs to begin with a nop ($00) and a jp ($C3) +; to the starting address. + nop + jp _Start + +; The Game Boy cartridge header data is patched over by rgbfix. +; This makes sure it doesn't get used for anything else. + + ds $0150 - @, $00 diff --git a/home/lcd.asm b/home/lcd.asm new file mode 100644 index 00000000..e88a42b3 --- /dev/null +++ b/home/lcd.asm @@ -0,0 +1,25 @@ +DisableLCD:: + xor a + ld [rIF], a + ld a, [rIE] + ld b, a + res 0, a + ld [rIE], a + +.wait + ld a, [rLY] + cp LY_VBLANK + jr nz, .wait + + ld a, [rLCDC] + and $ff ^ rLCDC_ENABLE_MASK + ld [rLCDC], a + ld a, b + ld [rIE], a + ret + +EnableLCD:: + ld a, [rLCDC] + set rLCDC_ENABLE, a + ld [rLCDC], a + ret diff --git a/home/start.asm b/home/start.asm new file mode 100644 index 00000000..448b6362 --- /dev/null +++ b/home/start.asm @@ -0,0 +1,10 @@ +_Start:: + cp GBC + jr z, .gbc + xor a + jr .ok +.gbc + ld a, 0 +.ok + ld [wGBC], a + jp Init -- cgit v1.2.3 From 9878f01e29b1443d6c894c1332cbf381fa12646e Mon Sep 17 00:00:00 2001 From: Rangi Date: Fri, 3 Jul 2020 16:37:47 -0400 Subject: Organize macros/ like pokecrystal While doing so I replaced the StopAllMusic macro with a SFX_STOP_ALL_MUSIC constant and applied it throughout the code. --- home/overworld.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'home') diff --git a/home/overworld.asm b/home/overworld.asm index 460ce11e..cc8c498c 100644 --- a/home/overworld.asm +++ b/home/overworld.asm @@ -772,7 +772,7 @@ HandleBlackOut:: StopMusic:: ld [wAudioFadeOutControl], a - ld a, $ff + ld a, SFX_STOP_ALL_MUSIC ld [wNewSoundID], a call PlaySound .wait -- cgit v1.2.3 From 35deb771130a9012ee4494b1db097761f2fe2919 Mon Sep 17 00:00:00 2001 From: Rangi Date: Fri, 3 Jul 2020 19:59:41 -0400 Subject: H_CONSTANTNAMES -> hConstantNames --- home/audio.asm | 6 +-- home/copy.asm | 6 +-- home/copy2.asm | 76 +++++++++++++++++----------------- home/init.asm | 6 +-- home/overworld.asm | 22 +++++----- home/pic.asm | 6 +-- home/predef.asm | 8 ++-- home/start_menu.asm | 2 +- home/text.asm | 12 +++--- home/vblank.asm | 20 ++++----- home/vcopy.asm | 116 ++++++++++++++++++++++++++-------------------------- 11 files changed, 140 insertions(+), 140 deletions(-) (limited to 'home') diff --git a/home/audio.asm b/home/audio.asm index 242f038b..04f0276d 100644 --- a/home/audio.asm +++ b/home/audio.asm @@ -170,10 +170,10 @@ PlaySound:: .noFadeOut xor a ld [wNewSoundID], a - ld a, [H_LOADEDROMBANK] + ld a, [hLoadedROMBank] ld [hSavedROMBank], a ld a, [wAudioROMBank] - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a cp BANK(Audio1_PlaySound) jr nz, .checkForAudio2 @@ -198,7 +198,7 @@ PlaySound:: .next2 ld a, [hSavedROMBank] - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a jr .done diff --git a/home/copy.asm b/home/copy.asm index be9c8c0c..910f508b 100644 --- a/home/copy.asm +++ b/home/copy.asm @@ -1,14 +1,14 @@ FarCopyData:: ; Copy bc bytes from a:hl to de. ld [wBuffer], a - ld a, [H_LOADEDROMBANK] + ld a, [hLoadedROMBank] push af ld a, [wBuffer] - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a call CopyData pop af - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ret diff --git a/home/copy2.asm b/home/copy2.asm index d4f35668..521223b6 100644 --- a/home/copy2.asm +++ b/home/copy2.asm @@ -2,24 +2,24 @@ FarCopyData2:: ; Identical to FarCopyData, but uses hROMBankTemp ; as temp space instead of wBuffer. ld [hROMBankTemp], a - ld a, [H_LOADEDROMBANK] + ld a, [hLoadedROMBank] push af ld a, [hROMBankTemp] - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a call CopyData pop af - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ret FarCopyData3:: ; Copy bc bytes from a:de to hl. ld [hROMBankTemp], a - ld a, [H_LOADEDROMBANK] + ld a, [hLoadedROMBank] push af ld a, [hROMBankTemp] - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a push hl push de @@ -31,7 +31,7 @@ FarCopyData3:: pop de pop hl pop af - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ret @@ -39,10 +39,10 @@ FarCopyDataDouble:: ; Expand bc bytes of 1bpp image data ; from a:hl to 2bpp data at de. ld [hROMBankTemp], a - ld a, [H_LOADEDROMBANK] + ld a, [hLoadedROMBank] push af ld a, [hROMBankTemp] - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a .loop ld a, [hli] @@ -55,7 +55,7 @@ FarCopyDataDouble:: or b jr nz, .loop pop af - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ret @@ -64,27 +64,27 @@ CopyVideoData:: ; tiles from b:de to hl, 8 tiles at a time. ; This takes c/8 frames. - ld a, [H_AUTOBGTRANSFERENABLED] + ld a, [hAutoBGTransferEnabled] push af xor a ; disable auto-transfer while copying - ld [H_AUTOBGTRANSFERENABLED], a + ld [hAutoBGTransferEnabled], a - ld a, [H_LOADEDROMBANK] + ld a, [hLoadedROMBank] ld [hROMBankTemp], a ld a, b - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ld a, e - ld [H_VBCOPYSRC], a + ld [hVBlankCopySource], a ld a, d - ld [H_VBCOPYSRC + 1], a + ld [hVBlankCopySource + 1], a ld a, l - ld [H_VBCOPYDEST], a + ld [hVBlankCopyDest], a ld a, h - ld [H_VBCOPYDEST + 1], a + ld [hVBlankCopyDest + 1], a .loop ld a, c @@ -92,18 +92,18 @@ CopyVideoData:: jr nc, .keepgoing .done - ld [H_VBCOPYSIZE], a + ld [hVBlankCopySize], a call DelayFrame ld a, [hROMBankTemp] - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a pop af - ld [H_AUTOBGTRANSFERENABLED], a + ld [hAutoBGTransferEnabled], a ret .keepgoing ld a, 8 - ld [H_VBCOPYSIZE], a + ld [hVBlankCopySize], a call DelayFrame ld a, c sub 8 @@ -114,26 +114,26 @@ CopyVideoDataDouble:: ; Wait for the next VBlank, then copy c 1bpp ; tiles from b:de to hl, 8 tiles at a time. ; This takes c/8 frames. - ld a, [H_AUTOBGTRANSFERENABLED] + ld a, [hAutoBGTransferEnabled] push af xor a ; disable auto-transfer while copying - ld [H_AUTOBGTRANSFERENABLED], a - ld a, [H_LOADEDROMBANK] + ld [hAutoBGTransferEnabled], a + ld a, [hLoadedROMBank] ld [hROMBankTemp], a ld a, b - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ld a, e - ld [H_VBCOPYDOUBLESRC], a + ld [hVBlankCopyDoubleSource], a ld a, d - ld [H_VBCOPYDOUBLESRC + 1], a + ld [hVBlankCopyDoubleSource + 1], a ld a, l - ld [H_VBCOPYDOUBLEDEST], a + ld [hVBlankCopyDoubleDest], a ld a, h - ld [H_VBCOPYDOUBLEDEST + 1], a + ld [hVBlankCopyDoubleDest + 1], a .loop ld a, c @@ -141,18 +141,18 @@ CopyVideoDataDouble:: jr nc, .keepgoing .done - ld [H_VBCOPYDOUBLESIZE], a + ld [hVBlankCopyDoubleSize], a call DelayFrame ld a, [hROMBankTemp] - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a pop af - ld [H_AUTOBGTRANSFERENABLED], a + ld [hAutoBGTransferEnabled], a ret .keepgoing ld a, 8 - ld [H_VBCOPYDOUBLESIZE], a + ld [hVBlankCopyDoubleSize], a call DelayFrame ld a, c sub 8 @@ -200,16 +200,16 @@ CopyScreenTileBufferToVRAM:: .setup ld a, d - ld [H_VBCOPYBGSRC+1], a + ld [hVBlankCopyBGSource+1], a call GetRowColAddressBgMap ld a, l - ld [H_VBCOPYBGDEST], a + ld [hVBlankCopyBGDest], a ld a, h - ld [H_VBCOPYBGDEST+1], a + ld [hVBlankCopyBGDest+1], a ld a, c - ld [H_VBCOPYBGNUMROWS], a + ld [hVBlankCopyBGNumRows], a ld a, e - ld [H_VBCOPYBGSRC], a + ld [hVBlankCopyBGSource], a ret ClearScreen:: diff --git a/home/init.asm b/home/init.asm index 9e3e2c82..efc886e0 100644 --- a/home/init.asm +++ b/home/init.asm @@ -60,7 +60,7 @@ rLCDC_DEFAULT EQU %11100011 call ClearSprites ld a, Bank(WriteDMACodeToHRAM) - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a call WriteDMACodeToHRAM @@ -101,9 +101,9 @@ rLCDC_DEFAULT EQU %11100011 ld [wAudioROMBank], a ld [wAudioSavedROMBank], a ld a, $9c - ld [H_AUTOBGTRANSFERDEST + 1], a + ld [hAutoBGTransferDest + 1], a xor a - ld [H_AUTOBGTRANSFERDEST], a + ld [hAutoBGTransferDest], a dec a ld [wUpdateSpritesEnabled], a diff --git a/home/overworld.asm b/home/overworld.asm index cc8c498c..9fb269dc 100644 --- a/home/overworld.asm +++ b/home/overworld.asm @@ -763,7 +763,7 @@ HandleBlackOut:: ld hl, wd72e res 5, [hl] ld a, Bank(ResetStatusAndHalveMoneyOnBlackout) ; also Bank(SpecialWarpIn) and Bank(SpecialEnterMap) - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a call ResetStatusAndHalveMoneyOnBlackout call SpecialWarpIn @@ -794,7 +794,7 @@ HandleFlyWarpOrDungeonWarp:: res 5, [hl] ; forced to ride bike call LeaveMapAnim ld a, Bank(SpecialWarpIn) - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a call SpecialWarpIn jp SpecialEnterMap @@ -1372,10 +1372,10 @@ TilePairCollisionsWater:: ; this builds a tile map from the tile block map based on the current X/Y coordinates of the player's character LoadCurrentMapView:: - ld a, [H_LOADEDROMBANK] + ld a, [hLoadedROMBank] push af ld a, [wTilesetBank] ; tile data ROM bank - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ; switch to ROM bank that contains tile data ld a, [wCurrentTileBlockMapViewPointer] ; address of upper left corner of current map view ld e, a @@ -1457,7 +1457,7 @@ LoadCurrentMapView:: dec b jr nz, .rowLoop2 pop af - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ; restore previous ROM bank ret @@ -2291,10 +2291,10 @@ LoadMapHeader:: ld a, [wCurMap] ld c, a ld b, $00 - ld a, [H_LOADEDROMBANK] + ld a, [hLoadedROMBank] push af ld a, BANK(MapSongBanks) - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ld hl, MapSongBanks add hl, bc @@ -2304,7 +2304,7 @@ LoadMapHeader:: ld a, [hl] ld [wMapMusicROMBank], a ; music 2 pop af - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ret @@ -2322,7 +2322,7 @@ CopyMapConnectionHeader:: ; function to load map data LoadMapData:: - ld a, [H_LOADEDROMBANK] + ld a, [hLoadedROMBank] push af call DisableLCD ld a, $98 @@ -2377,7 +2377,7 @@ LoadMapData:: call PlayDefaultMusicFadeOutCurrent .restoreRomBank pop af - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ret @@ -2396,7 +2396,7 @@ SwitchToMapRomBank:: ld [$ffe8], a ; save map ROM bank call BankswitchBack ld a, [$ffe8] - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ; switch to map ROM bank pop bc pop hl diff --git a/home/pic.asm b/home/pic.asm index a1c18e8a..cfc39f0f 100644 --- a/home/pic.asm +++ b/home/pic.asm @@ -2,10 +2,10 @@ ; bank is given in a, sprite input stream is pointed to in wSpriteInputPtr UncompressSpriteData:: ld b, a - ld a, [H_LOADEDROMBANK] + ld a, [hLoadedROMBank] push af ld a, b - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ld a, SRAM_ENABLE ld [MBC1SRamEnable], a @@ -13,7 +13,7 @@ UncompressSpriteData:: ld [MBC1SRamBank], a call _UncompressSpriteData pop af - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ret diff --git a/home/predef.asm b/home/predef.asm index 9bb9be74..4f0c37d9 100644 --- a/home/predef.asm +++ b/home/predef.asm @@ -8,18 +8,18 @@ Predef:: ; A hack for LoadDestinationWarpPosition. ; See LoadTilesetHeader (predef $19). - ld a, [H_LOADEDROMBANK] + ld a, [hLoadedROMBank] ld [wPredefParentBank], a push af ld a, BANK(GetPredefPointer) - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a call GetPredefPointer ld a, [wPredefBank] - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ld de, .done @@ -28,7 +28,7 @@ Predef:: .done pop af - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ret diff --git a/home/start_menu.asm b/home/start_menu.asm index eb4b4f2d..38333644 100755 --- a/home/start_menu.asm +++ b/home/start_menu.asm @@ -1,6 +1,6 @@ DisplayStartMenu:: ld a, BANK(StartMenu_Pokedex) - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a ld a, [wWalkBikeSurfState] ; walking/biking/surfing ld [wWalkBikeSurfStateCopy], a diff --git a/home/text.asm b/home/text.asm index 9db81530..89c93dd0 100644 --- a/home/text.asm +++ b/home/text.asm @@ -62,7 +62,7 @@ Char4ETest:: cp $4E ; next jr nz, .char4FTest ld bc, 2 * SCREEN_WIDTH - ld a, [hFlags_0xFFF6] + ld a, [hFlagsFFF6] bit 2, a jr z, .ok ld bc, SCREEN_WIDTH @@ -180,7 +180,7 @@ Char59:: ; or ; player active monster’s name ; (like Char5A but flipped) - ld a, [H_WHOSETURN] + ld a, [hWhoseTurn] xor 1 jr MonsterNameCharsCommon @@ -189,7 +189,7 @@ Char5A:: ; player active monster’s name ; or ; enemy active monster’s name, prefixed with “Enemy ” - ld a, [H_WHOSETURN] + ld a, [hWhoseTurn] MonsterNameCharsCommon:: push de and a @@ -675,14 +675,14 @@ TextCommand0D:: ; BB = bank TextCommand17:: pop hl - ld a, [H_LOADEDROMBANK] + ld a, [hLoadedROMBank] push af ld a, [hli] ld e, a ld a, [hli] ld d, a ld a, [hli] - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a push hl ld l, e @@ -690,7 +690,7 @@ TextCommand17:: call TextCommandProcessor pop hl pop af - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a jp NextTextCommand diff --git a/home/vblank.asm b/home/vblank.asm index e80fba75..e8232ea3 100644 --- a/home/vblank.asm +++ b/home/vblank.asm @@ -5,7 +5,7 @@ VBlank:: push de push hl - ld a, [H_LOADEDROMBANK] + ld a, [hLoadedROMBank] ld [wVBlankSavedROMBank], a ld a, [hSCX] @@ -28,7 +28,7 @@ VBlank:: call UpdateMovingBgTiles call $ff80 ; hOAMDMA ld a, BANK(PrepareOAMData) - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a call PrepareOAMData @@ -36,24 +36,24 @@ VBlank:: call Random - ld a, [H_VBLANKOCCURRED] + ld a, [hVBlankOccurred] and a jr z, .skipZeroing xor a - ld [H_VBLANKOCCURRED], a + ld [hVBlankOccurred], a .skipZeroing - ld a, [H_FRAMECOUNTER] + ld a, [hFrameCounter] and a jr z, .skipDec dec a - ld [H_FRAMECOUNTER], a + ld [hFrameCounter], a .skipDec call FadeOutAudio ld a, [wAudioROMBank] ; music ROM bank - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a cp BANK(Audio1_UpdateMusic) @@ -79,7 +79,7 @@ VBlank:: call z, ReadJoypad ld a, [wVBlankSavedROMBank] - ld [H_LOADEDROMBANK], a + ld [hLoadedROMBank], a ld [MBC1RomBank], a pop hl @@ -96,10 +96,10 @@ DelayFrame:: NOT_VBLANKED EQU 1 ld a, NOT_VBLANKED - ld [H_VBLANKOCCURRED], a + ld [hVBlankOccurred], a .halt halt - ld a, [H_VBLANKOCCURRED] + ld a, [hVBlankOccurred] and a jr nz, .halt ret diff --git a/home/vcopy.asm b/home/vcopy.asm index 3f49ad3e..a6213b32 100644 --- a/home/vcopy.asm +++ b/home/vcopy.asm @@ -120,15 +120,15 @@ RedrawRowOrColumn:: ; the above function, RedrawRowOrColumn, is used when walking to ; improve efficiency. AutoBgMapTransfer:: - ld a, [H_AUTOBGTRANSFERENABLED] + ld a, [hAutoBGTransferEnabled] and a ret z ld hl, sp + 0 ld a, h - ld [H_SPTEMP], a + ld [hSPTemp], a ld a, l - ld [H_SPTEMP + 1], a ; save stack pinter - ld a, [H_AUTOBGTRANSFERPORTION] + ld [hSPTemp + 1], a ; save stack pinter + ld a, [hAutoBGTransferPortion] and a jr z, .transferTopThird dec a @@ -136,9 +136,9 @@ AutoBgMapTransfer:: .transferBottomThird coord hl, 0, 12 ld sp, hl - ld a, [H_AUTOBGTRANSFERDEST + 1] + ld a, [hAutoBGTransferDest + 1] ld h, a - ld a, [H_AUTOBGTRANSFERDEST] + ld a, [hAutoBGTransferDest] ld l, a ld de, (12 * 32) add hl, de @@ -147,24 +147,24 @@ AutoBgMapTransfer:: .transferTopThird coord hl, 0, 0 ld sp, hl - ld a, [H_AUTOBGTRANSFERDEST + 1] + ld a, [hAutoBGTransferDest + 1] ld h, a - ld a, [H_AUTOBGTRANSFERDEST] + ld a, [hAutoBGTransferDest] ld l, a ld a, TRANSFERMIDDLE jr .doTransfer .transferMiddleThird coord hl, 0, 6 ld sp, hl - ld a, [H_AUTOBGTRANSFERDEST + 1] + ld a, [hAutoBGTransferDest + 1] ld h, a - ld a, [H_AUTOBGTRANSFERDEST] + ld a, [hAutoBGTransferDest] ld l, a ld de, (6 * 32) add hl, de ld a, TRANSFERBOTTOM .doTransfer - ld [H_AUTOBGTRANSFERPORTION], a ; store next portion + ld [hAutoBGTransferPortion], a ; store next portion ld b, 6 TransferBgRows:: @@ -192,73 +192,73 @@ TransferBgRows:: dec b jr nz, TransferBgRows - ld a, [H_SPTEMP] + ld a, [hSPTemp] ld h, a - ld a, [H_SPTEMP + 1] + ld a, [hSPTemp + 1] ld l, a ld sp, hl ret -; Copies [H_VBCOPYBGNUMROWS] rows from H_VBCOPYBGSRC to H_VBCOPYBGDEST. -; If H_VBCOPYBGSRC is XX00, the transfer is disabled. +; Copies [hVBlankCopyBGNumRows] rows from hVBlankCopyBGSource to hVBlankCopyBGDest. +; If hVBlankCopyBGSource is XX00, the transfer is disabled. VBlankCopyBgMap:: - ld a, [H_VBCOPYBGSRC] ; doubles as enabling byte + ld a, [hVBlankCopyBGSource] ; doubles as enabling byte and a ret z ld hl, sp + 0 ld a, h - ld [H_SPTEMP], a + ld [hSPTemp], a ld a, l - ld [H_SPTEMP + 1], a ; save stack pointer - ld a, [H_VBCOPYBGSRC] + ld [hSPTemp + 1], a ; save stack pointer + ld a, [hVBlankCopyBGSource] ld l, a - ld a, [H_VBCOPYBGSRC + 1] + ld a, [hVBlankCopyBGSource + 1] ld h, a ld sp, hl - ld a, [H_VBCOPYBGDEST] + ld a, [hVBlankCopyBGDest] ld l, a - ld a, [H_VBCOPYBGDEST + 1] + ld a, [hVBlankCopyBGDest + 1] ld h, a - ld a, [H_VBCOPYBGNUMROWS] + ld a, [hVBlankCopyBGNumRows] ld b, a xor a - ld [H_VBCOPYBGSRC], a ; disable transfer so it doesn't continue next V-blank + ld [hVBlankCopyBGSource], a ; disable transfer so it doesn't continue next V-blank jr TransferBgRows VBlankCopyDouble:: -; Copy [H_VBCOPYDOUBLESIZE] 1bpp tiles -; from H_VBCOPYDOUBLESRC to H_VBCOPYDOUBLEDEST. +; Copy [hVBlankCopyDoubleSize] 1bpp tiles +; from hVBlankCopyDoubleSource to hVBlankCopyDoubleDest. ; While we're here, convert to 2bpp. ; The process is straightforward: ; copy each byte twice. - ld a, [H_VBCOPYDOUBLESIZE] + ld a, [hVBlankCopyDoubleSize] and a ret z ld hl, sp + 0 ld a, h - ld [H_SPTEMP], a + ld [hSPTemp], a ld a, l - ld [H_SPTEMP + 1], a + ld [hSPTemp + 1], a - ld a, [H_VBCOPYDOUBLESRC] + ld a, [hVBlankCopyDoubleSource] ld l, a - ld a, [H_VBCOPYDOUBLESRC + 1] + ld a, [hVBlankCopyDoubleSource + 1] ld h, a ld sp, hl - ld a, [H_VBCOPYDOUBLEDEST] + ld a, [hVBlankCopyDoubleDest] ld l, a - ld a, [H_VBCOPYDOUBLEDEST + 1] + ld a, [hVBlankCopyDoubleDest + 1] ld h, a - ld a, [H_VBCOPYDOUBLESIZE] + ld a, [hVBlankCopyDoubleSize] ld b, a xor a ; transferred - ld [H_VBCOPYDOUBLESIZE], a + ld [hVBlankCopyDoubleSize], a .loop rept 3 @@ -286,19 +286,19 @@ VBlankCopyDouble:: jr nz, .loop ld a, l - ld [H_VBCOPYDOUBLEDEST], a + ld [hVBlankCopyDoubleDest], a ld a, h - ld [H_VBCOPYDOUBLEDEST + 1], a + ld [hVBlankCopyDoubleDest + 1], a ld hl, sp + 0 ld a, l - ld [H_VBCOPYDOUBLESRC], a + ld [hVBlankCopyDoubleSource], a ld a, h - ld [H_VBCOPYDOUBLESRC + 1], a + ld [hVBlankCopyDoubleSource + 1], a - ld a, [H_SPTEMP] + ld a, [hSPTemp] ld h, a - ld a, [H_SPTEMP + 1] + ld a, [hSPTemp + 1] ld l, a ld sp, hl @@ -306,37 +306,37 @@ VBlankCopyDouble:: VBlankCopy:: -; Copy [H_VBCOPYSIZE] 2bpp tiles (or 16 * [H_VBCOPYSIZE] tile map entries) -; from H_VBCOPYSRC to H_VBCOPYDEST. +; Copy [hVBlankCopySize] 2bpp tiles (or 16 * [hVBlankCopySize] tile map entries) +; from hVBlankCopySource to hVBlankCopyDest. ; Source and destination addresses are updated, ; so transfer can continue in subsequent calls. - ld a, [H_VBCOPYSIZE] + ld a, [hVBlankCopySize] and a ret z ld hl, sp + 0 ld a, h - ld [H_SPTEMP], a + ld [hSPTemp], a ld a, l - ld [H_SPTEMP + 1], a + ld [hSPTemp + 1], a - ld a, [H_VBCOPYSRC] + ld a, [hVBlankCopySource] ld l, a - ld a, [H_VBCOPYSRC + 1] + ld a, [hVBlankCopySource + 1] ld h, a ld sp, hl - ld a, [H_VBCOPYDEST] + ld a, [hVBlankCopyDest] ld l, a - ld a, [H_VBCOPYDEST + 1] + ld a, [hVBlankCopyDest + 1] ld h, a - ld a, [H_VBCOPYSIZE] + ld a, [hVBlankCopySize] ld b, a xor a ; transferred - ld [H_VBCOPYSIZE], a + ld [hVBlankCopySize], a .loop rept 7 @@ -356,19 +356,19 @@ VBlankCopy:: jr nz, .loop ld a, l - ld [H_VBCOPYDEST], a + ld [hVBlankCopyDest], a ld a, h - ld [H_VBCOPYDEST + 1], a + ld [hVBlankCopyDest + 1], a ld hl, sp + 0 ld a, l - ld [H_VBCOPYSRC], a + ld [hVBlankCopySource], a ld a, h - ld [H_VBCOPYSRC + 1], a + ld [hVBlankCopySource + 1], a - ld a, [H_SPTEMP] + ld a, [hSPTemp] ld h, a - ld a, [H_SPTEMP + 1] + ld a, [hSPTemp + 1] ld l, a ld sp, hl -- cgit v1.2.3 From 6ef36800b0dcb86100a7c716172015667e60dc99 Mon Sep 17 00:00:00 2001 From: Rangi Date: Fri, 3 Jul 2020 22:11:35 -0400 Subject: Replace raw hex values with HRAM constants To do: turn constants into labels and use ldh --- home/init.asm | 6 +++--- home/overworld.asm | 12 ++++++------ home/text.asm | 2 +- home/vblank.asm | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'home') diff --git a/home/init.asm b/home/init.asm index efc886e0..48294fa6 100644 --- a/home/init.asm +++ b/home/init.asm @@ -53,13 +53,13 @@ rLCDC_DEFAULT EQU %11100011 call ClearVram - ld hl, $ff80 - ld bc, $ffff - $ff80 + ld hl, $ff80 ; start of HRAM + ld bc, $ffff - $ff80 ; size of HRAM call FillMemory call ClearSprites - ld a, Bank(WriteDMACodeToHRAM) + ld a, BANK(WriteDMACodeToHRAM) ld [hLoadedROMBank], a ld [MBC1RomBank], a call WriteDMACodeToHRAM diff --git a/home/overworld.asm b/home/overworld.asm index 9fb269dc..c959beb6 100644 --- a/home/overworld.asm +++ b/home/overworld.asm @@ -88,7 +88,7 @@ OverworldLoopLessDelay:: call IsPlayerCharacterBeingControlledByGame jr nz, .checkForOpponent call CheckForHiddenObjectOrBookshelfOrCardKeyDoor - ld a, [$ffeb] + ld a, [hFoundHiddenObjectOrBookshelf] and a jp z, OverworldLoop ; jump if a hidden object or bookshelf was found, but not if a card key door was found call IsSpriteOrSignInFrontOfPlayer @@ -762,7 +762,7 @@ HandleBlackOut:: call StopMusic ld hl, wd72e res 5, [hl] - ld a, Bank(ResetStatusAndHalveMoneyOnBlackout) ; also Bank(SpecialWarpIn) and Bank(SpecialEnterMap) + ld a, BANK(ResetStatusAndHalveMoneyOnBlackout) ; also BANK(SpecialWarpIn) and BANK(SpecialEnterMap) ld [hLoadedROMBank], a ld [MBC1RomBank], a call ResetStatusAndHalveMoneyOnBlackout @@ -793,7 +793,7 @@ HandleFlyWarpOrDungeonWarp:: set 2, [hl] ; fly warp or dungeon warp res 5, [hl] ; forced to ride bike call LeaveMapAnim - ld a, Bank(SpecialWarpIn) + ld a, BANK(SpecialWarpIn) ld [hLoadedROMBank], a ld [MBC1RomBank], a call SpecialWarpIn @@ -2388,14 +2388,14 @@ SwitchToMapRomBank:: push bc ld c, a ld b, $00 - ld a, Bank(MapHeaderBanks) + ld a, BANK(MapHeaderBanks) call BankswitchHome ; switch to ROM bank 3 ld hl, MapHeaderBanks add hl, bc ld a, [hl] - ld [$ffe8], a ; save map ROM bank + ld [hMapROMBank], a ; save map ROM bank call BankswitchBack - ld a, [$ffe8] + ld a, [hMapROMBank] ld [hLoadedROMBank], a ld [MBC1RomBank], a ; switch to map ROM bank pop bc diff --git a/home/text.asm b/home/text.asm index 89c93dd0..0d2ed0a2 100644 --- a/home/text.asm +++ b/home/text.asm @@ -365,7 +365,7 @@ TextCommandProcessor:: push af set 1, a ld e, a - ld a, [$fff4] + ld a, [hClearLetterPrintingDelayFlags] xor e ld [wLetterPrintingDelayFlags], a ld a, c diff --git a/home/vblank.asm b/home/vblank.asm index e8232ea3..78f5f69d 100644 --- a/home/vblank.asm +++ b/home/vblank.asm @@ -26,7 +26,7 @@ VBlank:: call VBlankCopy call VBlankCopyDouble call UpdateMovingBgTiles - call $ff80 ; hOAMDMA + call hDMARoutine ld a, BANK(PrepareOAMData) ld [hLoadedROMBank], a ld [MBC1RomBank], a -- cgit v1.2.3 From 053afc46349952688c0ce2116cc76f8d4733895e Mon Sep 17 00:00:00 2001 From: Rangi Date: Fri, 3 Jul 2020 22:57:43 -0400 Subject: Move more code from home.asm to home/ --- home/bankswitch.asm | 35 ++++ home/list_menu.asm | 526 ++++++++++++++++++++++++++++++++++++++++++++++++ home/move_mon.asm | 242 ++++++++++++++++++++++ home/names.asm | 141 +++++++++++++ home/names2.asm | 93 +++++++++ home/overworld_text.asm | 31 +++ home/pokemon.asm | 464 ++++++++++++++++++++++++++++++++++++++++++ home/predef_text.asm | 237 ++++++++++++++++++++++ home/print_bcd.asm | 77 +++++++ home/print_num.asm | 217 ++++++++++++++++++++ home/trainers.asm | 436 +++++++++++++++++++++++++++++++++++++++ home/uncompress.asm | 196 ++++++++++++++++++ home/yes_no.asm | 40 ++++ 13 files changed, 2735 insertions(+) create mode 100644 home/bankswitch.asm create mode 100644 home/list_menu.asm create mode 100644 home/move_mon.asm create mode 100644 home/names.asm create mode 100644 home/names2.asm create mode 100644 home/overworld_text.asm create mode 100644 home/pokemon.asm create mode 100644 home/predef_text.asm create mode 100644 home/print_bcd.asm create mode 100644 home/print_num.asm create mode 100644 home/trainers.asm create mode 100644 home/uncompress.asm create mode 100644 home/yes_no.asm (limited to 'home') diff --git a/home/bankswitch.asm b/home/bankswitch.asm new file mode 100644 index 00000000..086ca2f3 --- /dev/null +++ b/home/bankswitch.asm @@ -0,0 +1,35 @@ +BankswitchHome:: +; switches to bank # in a +; Only use this when in the home bank! + ld [wBankswitchHomeTemp], a + ld a, [hLoadedROMBank] + ld [wBankswitchHomeSavedROMBank], a + ld a, [wBankswitchHomeTemp] + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ret + +BankswitchBack:: +; returns from BankswitchHome + ld a, [wBankswitchHomeSavedROMBank] + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ret + +Bankswitch:: +; self-contained bankswitch, use this when not in the home bank +; switches to the bank in b + ld a, [hLoadedROMBank] + push af + ld a, b + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ld bc, .Return + push bc + jp hl +.Return + pop bc + ld a, b + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ret diff --git a/home/list_menu.asm b/home/list_menu.asm new file mode 100644 index 00000000..68335ed5 --- /dev/null +++ b/home/list_menu.asm @@ -0,0 +1,526 @@ +; INPUT: +; [wListMenuID] = list menu ID +; [wListPointer] = address of the list (2 bytes) +DisplayListMenuID:: + xor a + ld [hAutoBGTransferEnabled], a ; disable auto-transfer + ld a, 1 + ld [hJoy7], a ; joypad state update flag + ld a, [wBattleType] + and a ; is it the Old Man battle? + jr nz, .specialBattleType + ld a, $01 ; hardcoded bank + jr .bankswitch +.specialBattleType ; Old Man battle + ld a, BANK(DisplayBattleMenu) +.bankswitch + call BankswitchHome + ld hl, wd730 + set 6, [hl] ; turn off letter printing delay + xor a + ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped + ld [wListCount], a + ld a, [wListPointer] + ld l, a + ld a, [wListPointer + 1] + ld h, a ; hl = address of the list + ld a, [hl] ; the first byte is the number of entries in the list + ld [wListCount], a + ld a, LIST_MENU_BOX + ld [wTextBoxID], a + call DisplayTextBoxID ; draw the menu text box + call UpdateSprites ; disable sprites behind the text box +; the code up to .skipMovingSprites appears to be useless + coord hl, 4, 2 ; coordinates of upper left corner of menu text box + lb de, 9, 14 ; height and width of menu text box + ld a, [wListMenuID] + and a ; is it a PC pokemon list? + jr nz, .skipMovingSprites + call UpdateSprites +.skipMovingSprites + ld a, 1 ; max menu item ID is 1 if the list has less than 2 entries + ld [wMenuWatchMovingOutOfBounds], a + ld a, [wListCount] + cp 2 ; does the list have less than 2 entries? + jr c, .setMenuVariables + ld a, 2 ; max menu item ID is 2 if the list has at least 2 entries +.setMenuVariables + ld [wMaxMenuItem], a + ld a, 4 + ld [wTopMenuItemY], a + ld a, 5 + ld [wTopMenuItemX], a + ld a, A_BUTTON | B_BUTTON | SELECT + ld [wMenuWatchedKeys], a + ld c, 10 + call DelayFrames + +DisplayListMenuIDLoop:: + xor a + ld [hAutoBGTransferEnabled], a ; disable transfer + call PrintListMenuEntries + ld a, 1 + ld [hAutoBGTransferEnabled], a ; enable transfer + call Delay3 + ld a, [wBattleType] + and a ; is it the Old Man battle? + jr z, .notOldManBattle +.oldManBattle + ld a, "▶" + Coorda 5, 4 ; place menu cursor in front of first menu entry + ld c, 80 + call DelayFrames + xor a + ld [wCurrentMenuItem], a + coord hl, 5, 4 + ld a, l + ld [wMenuCursorLocation], a + ld a, h + ld [wMenuCursorLocation + 1], a + jr .buttonAPressed +.notOldManBattle + call LoadGBPal + call HandleMenuInput + push af + call PlaceMenuCursor + pop af + bit 0, a ; was the A button pressed? + jp z, .checkOtherKeys +.buttonAPressed + ld a, [wCurrentMenuItem] + call PlaceUnfilledArrowMenuCursor + +; pointless because both values are overwritten before they are read + ld a, $01 + ld [wMenuExitMethod], a + ld [wChosenMenuItem], a + + xor a + ld [wMenuWatchMovingOutOfBounds], a + ld a, [wCurrentMenuItem] + ld c, a + ld a, [wListScrollOffset] + add c + ld c, a + ld a, [wListCount] + and a ; is the list empty? + jp z, ExitListMenu ; if so, exit the menu + dec a + cp c ; did the player select Cancel? + jp c, ExitListMenu ; if so, exit the menu + ld a, c + ld [wWhichPokemon], a + ld a, [wListMenuID] + cp ITEMLISTMENU + jr nz, .skipMultiplying +; if it's an item menu + sla c ; item entries are 2 bytes long, so multiply by 2 +.skipMultiplying + ld a, [wListPointer] + ld l, a + ld a, [wListPointer + 1] + ld h, a + inc hl ; hl = beginning of list entries + ld b, 0 + add hl, bc + ld a, [hl] + ld [wcf91], a + ld a, [wListMenuID] + and a ; is it a PC pokemon list? + jr z, .pokemonList + push hl + call GetItemPrice + pop hl + ld a, [wListMenuID] + cp ITEMLISTMENU + jr nz, .skipGettingQuantity +; if it's an item menu + inc hl + ld a, [hl] ; a = item quantity + ld [wMaxItemQuantity], a +.skipGettingQuantity + ld a, [wcf91] + ld [wd0b5], a + ld a, BANK(ItemNames) + ld [wPredefBank], a + call GetName + jr .storeChosenEntry +.pokemonList + ld hl, wPartyCount + ld a, [wListPointer] + cp l ; is it a list of party pokemon or box pokemon? + ld hl, wPartyMonNicks + jr z, .getPokemonName + ld hl, wBoxMonNicks ; box pokemon names +.getPokemonName + ld a, [wWhichPokemon] + call GetPartyMonName +.storeChosenEntry ; store the menu entry that the player chose and return + ld de, wcd6d + call CopyStringToCF4B ; copy name to wcf4b + ld a, CHOSE_MENU_ITEM + ld [wMenuExitMethod], a + ld a, [wCurrentMenuItem] + ld [wChosenMenuItem], a + xor a + ld [hJoy7], a ; joypad state update flag + ld hl, wd730 + res 6, [hl] ; turn on letter printing delay + jp BankswitchBack +.checkOtherKeys ; check B, SELECT, Up, and Down keys + bit 1, a ; was the B button pressed? + jp nz, ExitListMenu ; if so, exit the menu + bit 2, a ; was the select button pressed? + jp nz, HandleItemListSwapping ; if so, allow the player to swap menu entries + ld b, a + bit 7, b ; was Down pressed? + ld hl, wListScrollOffset + jr z, .upPressed +.downPressed + ld a, [hl] + add 3 + ld b, a + ld a, [wListCount] + cp b ; will going down scroll past the Cancel button? + jp c, DisplayListMenuIDLoop + inc [hl] ; if not, go down + jp DisplayListMenuIDLoop +.upPressed + ld a, [hl] + and a + jp z, DisplayListMenuIDLoop + dec [hl] + jp DisplayListMenuIDLoop + +DisplayChooseQuantityMenu:: +; text box dimensions/coordinates for just quantity + coord hl, 15, 9 + ld b, 1 ; height + ld c, 3 ; width + ld a, [wListMenuID] + cp PRICEDITEMLISTMENU + jr nz, .drawTextBox +; text box dimensions/coordinates for quantity and price + coord hl, 7, 9 + ld b, 1 ; height + ld c, 11 ; width +.drawTextBox + call TextBoxBorder + coord hl, 16, 10 + ld a, [wListMenuID] + cp PRICEDITEMLISTMENU + jr nz, .printInitialQuantity + coord hl, 8, 10 +.printInitialQuantity + ld de, InitialQuantityText + call PlaceString + xor a + ld [wItemQuantity], a ; initialize current quantity to 0 + jp .incrementQuantity +.waitForKeyPressLoop + call JoypadLowSensitivity + ld a, [hJoyPressed] ; newly pressed buttons + bit 0, a ; was the A button pressed? + jp nz, .buttonAPressed + bit 1, a ; was the B button pressed? + jp nz, .buttonBPressed + bit 6, a ; was Up pressed? + jr nz, .incrementQuantity + bit 7, a ; was Down pressed? + jr nz, .decrementQuantity + jr .waitForKeyPressLoop +.incrementQuantity + ld a, [wMaxItemQuantity] + inc a + ld b, a + ld hl, wItemQuantity ; current quantity + inc [hl] + ld a, [hl] + cp b + jr nz, .handleNewQuantity +; wrap to 1 if the player goes above the max quantity + ld a, 1 + ld [hl], a + jr .handleNewQuantity +.decrementQuantity + ld hl, wItemQuantity ; current quantity + dec [hl] + jr nz, .handleNewQuantity +; wrap to the max quantity if the player goes below 1 + ld a, [wMaxItemQuantity] + ld [hl], a +.handleNewQuantity + coord hl, 17, 10 + ld a, [wListMenuID] + cp PRICEDITEMLISTMENU + jr nz, .printQuantity +.printPrice + ld c, $03 + ld a, [wItemQuantity] + ld b, a + ld hl, hMoney ; total price +; initialize total price to 0 + xor a + ld [hli], a + ld [hli], a + ld [hl], a +.addLoop ; loop to multiply the individual price by the quantity to get the total price + ld de, hMoney + 2 + ld hl, hItemPrice + 2 + push bc + predef AddBCDPredef ; add the individual price to the current sum + pop bc + dec b + jr nz, .addLoop + ld a, [hHalveItemPrices] + and a ; should the price be halved (for selling items)? + jr z, .skipHalvingPrice + xor a + ld [hDivideBCDDivisor], a + ld [hDivideBCDDivisor + 1], a + ld a, $02 + ld [hDivideBCDDivisor + 2], a + predef DivideBCDPredef3 ; halves the price +; store the halved price + ld a, [hDivideBCDQuotient] + ld [hMoney], a + ld a, [hDivideBCDQuotient + 1] + ld [hMoney + 1], a + ld a, [hDivideBCDQuotient + 2] + ld [hMoney + 2], a +.skipHalvingPrice + coord hl, 12, 10 + ld de, SpacesBetweenQuantityAndPriceText + call PlaceString + ld de, hMoney ; total price + ld c, $a3 + call PrintBCDNumber + coord hl, 9, 10 +.printQuantity + ld de, wItemQuantity ; current quantity + lb bc, LEADING_ZEROES | 1, 2 ; 1 byte, 2 digits + call PrintNumber + jp .waitForKeyPressLoop +.buttonAPressed ; the player chose to make the transaction + xor a + ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped + ret +.buttonBPressed ; the player chose to cancel the transaction + xor a + ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped + ld a, $ff + ret + +InitialQuantityText:: + db "×01@" + +SpacesBetweenQuantityAndPriceText:: + db " @" + +ExitListMenu:: + ld a, [wCurrentMenuItem] + ld [wChosenMenuItem], a + ld a, CANCELLED_MENU + ld [wMenuExitMethod], a + ld [wMenuWatchMovingOutOfBounds], a + xor a + ld [hJoy7], a + ld hl, wd730 + res 6, [hl] + call BankswitchBack + xor a + ld [wMenuItemToSwap], a ; 0 means no item is currently being swapped + scf + ret + +PrintListMenuEntries:: + coord hl, 5, 3 + ld b, 9 + ld c, 14 + call ClearScreenArea + ld a, [wListPointer] + ld e, a + ld a, [wListPointer + 1] + ld d, a + inc de ; de = beginning of list entries + ld a, [wListScrollOffset] + ld c, a + ld a, [wListMenuID] + cp ITEMLISTMENU + ld a, c + jr nz, .skipMultiplying +; if it's an item menu +; item entries are 2 bytes long, so multiply by 2 + sla a + sla c +.skipMultiplying + add e + ld e, a + jr nc, .noCarry + inc d +.noCarry + coord hl, 6, 4 ; coordinates of first list entry name + ld b, 4 ; print 4 names +.loop + ld a, b + ld [wWhichPokemon], a + ld a, [de] + ld [wd11e], a + cp $ff + jp z, .printCancelMenuItem + push bc + push de + push hl + push hl + push de + ld a, [wListMenuID] + and a + jr z, .pokemonPCMenu + cp MOVESLISTMENU + jr z, .movesMenu +.itemMenu + call GetItemName + jr .placeNameString +.pokemonPCMenu + push hl + ld hl, wPartyCount + ld a, [wListPointer] + cp l ; is it a list of party pokemon or box pokemon? + ld hl, wPartyMonNicks + jr z, .getPokemonName + ld hl, wBoxMonNicks ; box pokemon names +.getPokemonName + ld a, [wWhichPokemon] + ld b, a + ld a, 4 + sub b + ld b, a + ld a, [wListScrollOffset] + add b + call GetPartyMonName + pop hl + jr .placeNameString +.movesMenu + call GetMoveName +.placeNameString + call PlaceString + pop de + pop hl + ld a, [wPrintItemPrices] + and a ; should prices be printed? + jr z, .skipPrintingItemPrice +.printItemPrice + push hl + ld a, [de] + ld de, ItemPrices + ld [wcf91], a + call GetItemPrice ; get price + pop hl + ld bc, SCREEN_WIDTH + 5 ; 1 row down and 5 columns right + add hl, bc + ld c, $a3 ; no leading zeroes, right-aligned, print currency symbol, 3 bytes + call PrintBCDNumber +.skipPrintingItemPrice + ld a, [wListMenuID] + and a + jr nz, .skipPrintingPokemonLevel +.printPokemonLevel + ld a, [wd11e] + push af + push hl + ld hl, wPartyCount + ld a, [wListPointer] + cp l ; is it a list of party pokemon or box pokemon? + ld a, PLAYER_PARTY_DATA + jr z, .next + ld a, BOX_DATA +.next + ld [wMonDataLocation], a + ld hl, wWhichPokemon + ld a, [hl] + ld b, a + ld a, $04 + sub b + ld b, a + ld a, [wListScrollOffset] + add b + ld [hl], a + call LoadMonData + ld a, [wMonDataLocation] + and a ; is it a list of party pokemon or box pokemon? + jr z, .skipCopyingLevel +.copyLevel + ld a, [wLoadedMonBoxLevel] + ld [wLoadedMonLevel], a +.skipCopyingLevel + pop hl + ld bc, $001c + add hl, bc + call PrintLevel + pop af + ld [wd11e], a +.skipPrintingPokemonLevel + pop hl + pop de + inc de + ld a, [wListMenuID] + cp ITEMLISTMENU + jr nz, .nextListEntry +.printItemQuantity + ld a, [wd11e] + ld [wcf91], a + call IsKeyItem ; check if item is unsellable + ld a, [wIsKeyItem] + and a ; is the item unsellable? + jr nz, .skipPrintingItemQuantity ; if so, don't print the quantity + push hl + ld bc, SCREEN_WIDTH + 8 ; 1 row down and 8 columns right + add hl, bc + ld a, "×" + ld [hli], a + ld a, [wd11e] + push af + ld a, [de] + ld [wMaxItemQuantity], a + push de + ld de, wd11e + ld [de], a + lb bc, 1, 2 + call PrintNumber + pop de + pop af + ld [wd11e], a + pop hl +.skipPrintingItemQuantity + inc de + pop bc + inc c + push bc + inc c + ld a, [wMenuItemToSwap] ; ID of item chosen for swapping (counts from 1) + and a ; is an item being swapped? + jr z, .nextListEntry + sla a + cp c ; is it this item? + jr nz, .nextListEntry + dec hl + ld a, $ec ; unfilled right arrow menu cursor to indicate an item being swapped + ld [hli], a +.nextListEntry + ld bc, 2 * SCREEN_WIDTH ; 2 rows + add hl, bc + pop bc + inc c + dec b + jp nz, .loop + ld bc, -8 + add hl, bc + ld a, "▼" + ld [hl], a + ret +.printCancelMenuItem + ld de, ListMenuCancelText + jp PlaceString + +ListMenuCancelText:: + db "CANCEL@" diff --git a/home/move_mon.asm b/home/move_mon.asm new file mode 100644 index 00000000..e13ebf4e --- /dev/null +++ b/home/move_mon.asm @@ -0,0 +1,242 @@ +; Function to remove a pokemon from the party or the current box. +; wWhichPokemon determines the pokemon. +; [wRemoveMonFromBox] == 0 specifies the party. +; [wRemoveMonFromBox] != 0 specifies the current box. +RemovePokemon:: + jpab _RemovePokemon + +AddPartyMon:: + push hl + push de + push bc + callba _AddPartyMon + pop bc + pop de + pop hl + ret + +; calculates all 5 stats of current mon and writes them to [de] +CalcStats:: + ld c, $0 +.statsLoop + inc c + call CalcStat + ld a, [hMultiplicand+1] + ld [de], a + inc de + ld a, [hMultiplicand+2] + ld [de], a + inc de + ld a, c + cp NUM_STATS + jr nz, .statsLoop + ret + +; calculates stat c of current mon +; c: stat to calc (HP=1,Atk=2,Def=3,Spd=4,Spc=5) +; b: consider stat exp? +; hl: base ptr to stat exp values ([hl + 2*c - 1] and [hl + 2*c]) +CalcStat:: + push hl + push de + push bc + ld a, b + ld d, a + push hl + ld hl, wMonHeader + ld b, $0 + add hl, bc + ld a, [hl] ; read base value of stat + ld e, a + pop hl + push hl + sla c + ld a, d + and a + jr z, .statExpDone ; consider stat exp? + add hl, bc ; skip to corresponding stat exp value +.statExpLoop ; calculates ceil(Sqrt(stat exp)) in b + xor a + ld [hMultiplicand], a + ld [hMultiplicand+1], a + inc b ; increment current stat exp bonus + ld a, b + cp $ff + jr z, .statExpDone + ld [hMultiplicand+2], a + ld [hMultiplier], a + call Multiply + ld a, [hld] + ld d, a + ld a, [hProduct + 3] + sub d + ld a, [hli] + ld d, a + ld a, [hProduct + 2] + sbc d ; test if (current stat exp bonus)^2 < stat exp + jr c, .statExpLoop +.statExpDone + srl c + pop hl + push bc + ld bc, wPartyMon1DVs - (wPartyMon1HPExp - 1) ; also wEnemyMonDVs - wEnemyMonHP + add hl, bc + pop bc + ld a, c + cp $2 + jr z, .getAttackIV + cp $3 + jr z, .getDefenseIV + cp $4 + jr z, .getSpeedIV + cp $5 + jr z, .getSpecialIV +.getHpIV + push bc + ld a, [hl] ; Atk IV + swap a + and $1 + sla a + sla a + sla a + ld b, a + ld a, [hli] ; Def IV + and $1 + sla a + sla a + add b + ld b, a + ld a, [hl] ; Spd IV + swap a + and $1 + sla a + add b + ld b, a + ld a, [hl] ; Spc IV + and $1 + add b ; HP IV: LSB of the other 4 IVs + pop bc + jr .calcStatFromIV +.getAttackIV + ld a, [hl] + swap a + and $f + jr .calcStatFromIV +.getDefenseIV + ld a, [hl] + and $f + jr .calcStatFromIV +.getSpeedIV + inc hl + ld a, [hl] + swap a + and $f + jr .calcStatFromIV +.getSpecialIV + inc hl + ld a, [hl] + and $f +.calcStatFromIV + ld d, $0 + add e + ld e, a + jr nc, .noCarry + inc d ; de = Base + IV +.noCarry + sla e + rl d ; de = (Base + IV) * 2 + srl b + srl b ; b = ceil(Sqrt(stat exp)) / 4 + ld a, b + add e + jr nc, .noCarry2 + inc d ; de = (Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4 +.noCarry2 + ld [hMultiplicand+2], a + ld a, d + ld [hMultiplicand+1], a + xor a + ld [hMultiplicand], a + ld a, [wCurEnemyLVL] + ld [hMultiplier], a + call Multiply ; ((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level + ld a, [hMultiplicand] + ld [hDividend], a + ld a, [hMultiplicand+1] + ld [hDividend+1], a + ld a, [hMultiplicand+2] + ld [hDividend+2], a + ld a, $64 + ld [hDivisor], a + ld a, $3 + ld b, a + call Divide ; (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + ld a, c + cp $1 + ld a, 5 ; + 5 for non-HP stat + jr nz, .notHPStat + ld a, [wCurEnemyLVL] + ld b, a + ld a, [hMultiplicand+2] + add b + ld [hMultiplicand+2], a + jr nc, .noCarry3 + ld a, [hMultiplicand+1] + inc a + ld [hMultiplicand+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level +.noCarry3 + ld a, 10 ; +10 for HP stat +.notHPStat + ld b, a + ld a, [hMultiplicand+2] + add b + ld [hMultiplicand+2], a + jr nc, .noCarry4 + ld a, [hMultiplicand+1] + inc a ; non-HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + 5 + ld [hMultiplicand+1], a ; HP: (((Base + IV) * 2 + ceil(Sqrt(stat exp)) / 4) * Level) / 100 + Level + 10 +.noCarry4 + ld a, [hMultiplicand+1] ; check for overflow (>999) + cp 999 / $100 + 1 + jr nc, .overflow + cp 999 / $100 + jr c, .noOverflow + ld a, [hMultiplicand+2] + cp 999 % $100 + 1 + jr c, .noOverflow +.overflow + ld a, 999 / $100 ; overflow: cap at 999 + ld [hMultiplicand+1], a + ld a, 999 % $100 + ld [hMultiplicand+2], a +.noOverflow + pop bc + pop de + pop hl + ret + +AddEnemyMonToPlayerParty:: + ld a, [hLoadedROMBank] + push af + ld a, BANK(_AddEnemyMonToPlayerParty) + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + call _AddEnemyMonToPlayerParty + pop bc + ld a, b + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ret + +MoveMon:: + ld a, [hLoadedROMBank] + push af + ld a, BANK(_MoveMon) + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + call _MoveMon + pop bc + ld a, b + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ret diff --git a/home/names.asm b/home/names.asm new file mode 100644 index 00000000..cbc8910b --- /dev/null +++ b/home/names.asm @@ -0,0 +1,141 @@ +GetMonName:: + push hl + ld a, [hLoadedROMBank] + push af + ld a, BANK(MonsterNames) + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ld a, [wd11e] + dec a + ld hl, MonsterNames + ld c, 10 + ld b, 0 + call AddNTimes + ld de, wcd6d + push de + ld bc, 10 + call CopyData + ld hl, wcd6d + 10 + ld [hl], "@" + pop de + pop af + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + pop hl + ret + +GetItemName:: +; given an item ID at [wd11e], store the name of the item into a string +; starting at wcd6d + push hl + push bc + ld a, [wd11e] + cp HM_01 ; is this a TM/HM? + jr nc, .Machine + + ld [wd0b5], a + ld a, ITEM_NAME + ld [wNameListType], a + ld a, BANK(ItemNames) + ld [wPredefBank], a + call GetName + jr .Finish + +.Machine + call GetMachineName +.Finish + ld de, wcd6d ; pointer to where item name is stored in RAM + pop bc + pop hl + ret + +GetMachineName:: +; copies the name of the TM/HM in [wd11e] to wcd6d + push hl + push de + push bc + ld a, [wd11e] + push af + cp TM_01 ; is this a TM? [not HM] + jr nc, .WriteTM +; if HM, then write "HM" and add 5 to the item ID, so we can reuse the +; TM printing code + add 5 + ld [wd11e], a + ld hl, HiddenPrefix ; points to "HM" + ld bc, 2 + jr .WriteMachinePrefix +.WriteTM + ld hl, TechnicalPrefix ; points to "TM" + ld bc, 2 +.WriteMachinePrefix + ld de, wcd6d + call CopyData + +; now get the machine number and convert it to text + ld a, [wd11e] + sub TM_01 - 1 + ld b, "0" +.FirstDigit + sub 10 + jr c, .SecondDigit + inc b + jr .FirstDigit +.SecondDigit + add 10 + push af + ld a, b + ld [de], a + inc de + pop af + ld b, "0" + add b + ld [de], a + inc de + ld a, "@" + ld [de], a + pop af + ld [wd11e], a + pop bc + pop de + pop hl + ret + +TechnicalPrefix:: + db "TM" +HiddenPrefix:: + db "HM" + +; sets carry if item is HM, clears carry if item is not HM +; Input: a = item ID +IsItemHM:: + cp HM_01 + jr c, .notHM + cp TM_01 + ret +.notHM + and a + ret + +; sets carry if move is an HM, clears carry if move is not an HM +; Input: a = move ID +IsMoveHM:: + ld hl, HMMoves + ld de, 1 + jp IsInArray + +HMMoves:: +INCLUDE "data/moves/hm_moves.asm" + +GetMoveName:: + push hl + ld a, MOVE_NAME + ld [wNameListType], a + ld a, [wd11e] + ld [wd0b5], a + ld a, BANK(MoveNames) + ld [wPredefBank], a + call GetName + ld de, wcd6d ; pointer to where move name is stored in RAM + pop hl + ret diff --git a/home/names2.asm b/home/names2.asm new file mode 100644 index 00000000..178a0780 --- /dev/null +++ b/home/names2.asm @@ -0,0 +1,93 @@ +NamePointers:: + dw MonsterNames + dw MoveNames + dw UnusedNames + dw ItemNames + dw wPartyMonOT ; player's OT names list + dw wEnemyMonOT ; enemy's OT names list + dw TrainerNames + +GetName:: +; arguments: +; [wd0b5] = which name +; [wNameListType] = which list +; [wPredefBank] = bank of list +; +; returns pointer to name in de + ld a, [wd0b5] + ld [wd11e], a + + ; TM names are separate from item names. + ; BUG: This applies to all names instead of just items. + cp HM_01 + jp nc, GetMachineName + + ld a, [hLoadedROMBank] + push af + push hl + push bc + push de + ld a, [wNameListType] ;List3759_entrySelector + dec a + jr nz, .otherEntries + ;1 = MON_NAMES + call GetMonName + ld hl, NAME_LENGTH + add hl, de + ld e, l + ld d, h + jr .gotPtr +.otherEntries + ;2-7 = OTHER ENTRIES + ld a, [wPredefBank] + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ld a, [wNameListType] ;VariousNames' entryID + dec a + add a + ld d, 0 + ld e, a + jr nc, .skip + inc d +.skip + ld hl, NamePointers + add hl, de + ld a, [hli] + ld [hSwapTemp + 1], a + ld a, [hl] + ld [hSwapTemp], a + ld a, [hSwapTemp] + ld h, a + ld a, [hSwapTemp + 1] + ld l, a + ld a, [wd0b5] + ld b, a + ld c, 0 +.nextName + ld d, h + ld e, l +.nextChar + ld a, [hli] + cp "@" + jr nz, .nextChar + inc c ;entry counter + ld a, b ;wanted entry + cp c + jr nz, .nextName + ld h, d + ld l, e + ld de, wcd6d + ld bc, $0014 + call CopyData +.gotPtr + ld a, e + ld [wUnusedCF8D], a + ld a, d + ld [wUnusedCF8D + 1], a + pop de + pop bc + pop hl + pop af + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ret diff --git a/home/overworld_text.asm b/home/overworld_text.asm new file mode 100644 index 00000000..b32335f7 --- /dev/null +++ b/home/overworld_text.asm @@ -0,0 +1,31 @@ +TextScriptEndingChar:: + db "@" + +TextScriptEnd:: + ld hl, TextScriptEndingChar + ret + +ExclamationText:: + TX_FAR _ExclamationText + db "@" + +GroundRoseText:: + TX_FAR _GroundRoseText + db "@" + +BoulderText:: + TX_FAR _BoulderText + db "@" + +MartSignText:: + TX_FAR _MartSignText + db "@" + +PokeCenterSignText:: + TX_FAR _PokeCenterSignText + db "@" + +PickUpItemText:: + TX_ASM + predef PickUpItem + jp TextScriptEnd diff --git a/home/pokemon.asm b/home/pokemon.asm new file mode 100644 index 00000000..141baa65 --- /dev/null +++ b/home/pokemon.asm @@ -0,0 +1,464 @@ +DrawHPBar:: +; Draw an HP bar d tiles long, and fill it to e pixels. +; If c is nonzero, show at least a sliver regardless. +; The right end of the bar changes with [wHPBarType]. + + push hl + push de + push bc + + ; Left + ld a, $71 ; "HP:" + ld [hli], a + ld a, $62 + ld [hli], a + + push hl + + ; Middle + ld a, $63 ; empty +.draw + ld [hli], a + dec d + jr nz, .draw + + ; Right + ld a, [wHPBarType] + dec a + ld a, $6d ; status screen and battle + jr z, .ok + dec a ; pokemon menu +.ok + ld [hl], a + + pop hl + + ld a, e + and a + jr nz, .fill + + ; If c is nonzero, draw a pixel anyway. + ld a, c + and a + jr z, .done + ld e, 1 + +.fill + ld a, e + sub 8 + jr c, .partial + ld e, a + ld a, $6b ; full + ld [hli], a + ld a, e + and a + jr z, .done + jr .fill + +.partial + ; Fill remaining pixels at the end if necessary. + ld a, $63 ; empty + add e + ld [hl], a +.done + pop bc + pop de + pop hl + ret + + +; loads pokemon data from one of multiple sources to wLoadedMon +; loads base stats to wMonHeader +; INPUT: +; [wWhichPokemon] = index of pokemon within party/box +; [wMonDataLocation] = source +; 00: player's party +; 01: enemy's party +; 02: current box +; 03: daycare +; OUTPUT: +; [wcf91] = pokemon ID +; wLoadedMon = base address of pokemon data +; wMonHeader = base address of base stats +LoadMonData:: + jpab LoadMonData_ + +OverwritewMoves:: +; Write c to [wMoves + b]. Unused. + ld hl, wMoves + ld e, b + ld d, 0 + add hl, de + ld a, c + ld [hl], a + ret + +LoadFlippedFrontSpriteByMonIndex:: + ld a, 1 + ld [wSpriteFlipped], a + +LoadFrontSpriteByMonIndex:: + push hl + ld a, [wd11e] + push af + ld a, [wcf91] + ld [wd11e], a + predef IndexToPokedex + ld hl, wd11e + ld a, [hl] + pop bc + ld [hl], b + and a + pop hl + jr z, .invalidDexNumber ; dex #0 invalid + cp NUM_POKEMON + 1 + jr c, .validDexNumber ; dex >#151 invalid +.invalidDexNumber + ld a, RHYDON ; $1 + ld [wcf91], a + ret +.validDexNumber + push hl + ld de, vFrontPic + call LoadMonFrontSprite + pop hl + ld a, [hLoadedROMBank] + push af + ld a, BANK(CopyUncompressedPicToHL) + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + xor a + ld [hStartTileID], a + call CopyUncompressedPicToHL + xor a + ld [wSpriteFlipped], a + pop af + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ret + + +PlayCry:: +; Play monster a's cry. + call GetCryData + call PlaySound + jp WaitForSoundToFinish + +GetCryData:: +; Load cry data for monster a. + dec a + ld c, a + ld b, 0 + ld hl, CryData + add hl, bc + add hl, bc + add hl, bc + + ld a, BANK(CryData) + call BankswitchHome + ld a, [hli] + ld b, a ; cry id + ld a, [hli] + ld [wFrequencyModifier], a + ld a, [hl] + ld [wTempoModifier], a + call BankswitchBack + + ; Cry headers have 3 channels, + ; and start from index CRY_SFX_START, + ; so add 3 times the cry id. + ld a, b + ld c, CRY_SFX_START + rlca ; * 2 + add b + add c + ret + +DisplayPartyMenu:: + ld a, [hTilesetType] + push af + xor a + ld [hTilesetType], a + call GBPalWhiteOutWithDelay3 + call ClearSprites + call PartyMenuInit + call DrawPartyMenu + jp HandlePartyMenuInput + +GoBackToPartyMenu:: + ld a, [hTilesetType] + push af + xor a + ld [hTilesetType], a + call PartyMenuInit + call RedrawPartyMenu + jp HandlePartyMenuInput + +PartyMenuInit:: + ld a, 1 ; hardcoded bank + call BankswitchHome + call LoadHpBarAndStatusTilePatterns + ld hl, wd730 + set 6, [hl] ; turn off letter printing delay + xor a ; PLAYER_PARTY_DATA + ld [wMonDataLocation], a + ld [wMenuWatchMovingOutOfBounds], a + ld hl, wTopMenuItemY + inc a + ld [hli], a ; top menu item Y + xor a + ld [hli], a ; top menu item X + ld a, [wPartyAndBillsPCSavedMenuItem] + push af + ld [hli], a ; current menu item ID + inc hl + ld a, [wPartyCount] + and a ; are there more than 0 pokemon in the party? + jr z, .storeMaxMenuItemID + dec a +; if party is not empty, the max menu item ID is ([wPartyCount] - 1) +; otherwise, it is 0 +.storeMaxMenuItemID + ld [hli], a ; max menu item ID + ld a, [wForcePlayerToChooseMon] + and a + ld a, A_BUTTON | B_BUTTON + jr z, .next + xor a + ld [wForcePlayerToChooseMon], a + inc a ; a = A_BUTTON +.next + ld [hli], a ; menu watched keys + pop af + ld [hl], a ; old menu item ID + ret + +HandlePartyMenuInput:: + ld a, 1 + ld [wMenuWrappingEnabled], a + ld a, $40 + ld [wPartyMenuAnimMonEnabled], a + call HandleMenuInput_ + call PlaceUnfilledArrowMenuCursor + ld b, a + xor a + ld [wPartyMenuAnimMonEnabled], a + ld a, [wCurrentMenuItem] + ld [wPartyAndBillsPCSavedMenuItem], a + ld hl, wd730 + res 6, [hl] ; turn on letter printing delay + ld a, [wMenuItemToSwap] + and a + jp nz, .swappingPokemon + pop af + ld [hTilesetType], a + bit 1, b + jr nz, .noPokemonChosen + ld a, [wPartyCount] + and a + jr z, .noPokemonChosen + ld a, [wCurrentMenuItem] + ld [wWhichPokemon], a + ld hl, wPartySpecies + ld b, 0 + ld c, a + add hl, bc + ld a, [hl] + ld [wcf91], a + ld [wBattleMonSpecies2], a + call BankswitchBack + and a + ret +.noPokemonChosen + call BankswitchBack + scf + ret +.swappingPokemon + bit 1, b ; was the B button pressed? + jr z, .handleSwap ; if not, handle swapping the pokemon +.cancelSwap ; if the B button was pressed + callba ErasePartyMenuCursors + xor a + ld [wMenuItemToSwap], a + ld [wPartyMenuTypeOrMessageID], a + call RedrawPartyMenu + jr HandlePartyMenuInput +.handleSwap + ld a, [wCurrentMenuItem] + ld [wWhichPokemon], a + callba SwitchPartyMon + jr HandlePartyMenuInput + +DrawPartyMenu:: + ld hl, DrawPartyMenu_ + jr DrawPartyMenuCommon + +RedrawPartyMenu:: + ld hl, RedrawPartyMenu_ + +DrawPartyMenuCommon:: + ld b, BANK(RedrawPartyMenu_) + jp Bankswitch + +; prints a pokemon's status condition +; INPUT: +; de = address of status condition +; hl = destination address +PrintStatusCondition:: + push de + dec de + dec de ; de = address of current HP + ld a, [de] + ld b, a + dec de + ld a, [de] + or b ; is the pokemon's HP zero? + pop de + jr nz, PrintStatusConditionNotFainted +; if the pokemon's HP is 0, print "FNT" + ld a, "F" + ld [hli], a + ld a, "N" + ld [hli], a + ld [hl], "T" + and a + ret + +PrintStatusConditionNotFainted:: + ld a, [hLoadedROMBank] + push af + ld a, BANK(PrintStatusAilment) + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + call PrintStatusAilment ; print status condition + pop bc + ld a, b + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ret + +; function to print pokemon level, leaving off the ":L" if the level is at least 100 +; INPUT: +; hl = destination address +; [wLoadedMonLevel] = level +PrintLevel:: + ld a, $6e ; ":L" tile ID + ld [hli], a + ld c, 2 ; number of digits + ld a, [wLoadedMonLevel] ; level + cp 100 + jr c, PrintLevelCommon +; if level at least 100, write over the ":L" tile + dec hl + inc c ; increment number of digits to 3 + jr PrintLevelCommon + +; prints the level without leaving off ":L" regardless of level +; INPUT: +; hl = destination address +; [wLoadedMonLevel] = level +PrintLevelFull:: + ld a, $6e ; ":L" tile ID + ld [hli], a + ld c, 3 ; number of digits + ld a, [wLoadedMonLevel] ; level + +PrintLevelCommon:: + ld [wd11e], a + ld de, wd11e + ld b, LEFT_ALIGN | 1 ; 1 byte + jp PrintNumber + +GetwMoves:: +; Unused. Returns the move at index a from wMoves in a + ld hl, wMoves + ld c, a + ld b, 0 + add hl, bc + ld a, [hl] + ret + +; copies the base stat data of a pokemon to wMonHeader +; INPUT: +; [wd0b5] = pokemon ID +GetMonHeader:: + ld a, [hLoadedROMBank] + push af + ld a, BANK(BaseStats) + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + push bc + push de + push hl + ld a, [wd11e] + push af + ld a, [wd0b5] + ld [wd11e], a + ld de, FossilKabutopsPic + ld b, $66 ; size of Kabutops fossil and Ghost sprites + cp FOSSIL_KABUTOPS ; Kabutops fossil + jr z, .specialID + ld de, GhostPic + cp MON_GHOST ; Ghost + jr z, .specialID + ld de, FossilAerodactylPic + ld b, $77 ; size of Aerodactyl fossil sprite + cp FOSSIL_AERODACTYL ; Aerodactyl fossil + jr z, .specialID + cp MEW + jr z, .mew + predef IndexToPokedex ; convert pokemon ID in [wd11e] to pokedex number + ld a, [wd11e] + dec a + ld bc, MonBaseStatsEnd - MonBaseStats + ld hl, BaseStats + call AddNTimes + ld de, wMonHeader + ld bc, MonBaseStatsEnd - MonBaseStats + call CopyData + jr .done +.specialID + ld hl, wMonHSpriteDim + ld [hl], b ; write sprite dimensions + inc hl + ld [hl], e ; write front sprite pointer + inc hl + ld [hl], d + jr .done +.mew + ld hl, MewBaseStats + ld de, wMonHeader + ld bc, MonBaseStatsEnd - MonBaseStats + ld a, BANK(MewBaseStats) + call FarCopyData +.done + ld a, [wd0b5] + ld [wMonHIndex], a + pop af + ld [wd11e], a + pop hl + pop de + pop bc + pop af + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ret + +; copy party pokemon's name to wcd6d +GetPartyMonName2:: + ld a, [wWhichPokemon] ; index within party + ld hl, wPartyMonNicks + +; this is called more often +GetPartyMonName:: + push hl + push bc + call SkipFixedLengthTextEntries ; add NAME_LENGTH to hl, a times + ld de, wcd6d + push de + ld bc, NAME_LENGTH + call CopyData + pop de + pop bc + pop hl + ret diff --git a/home/predef_text.asm b/home/predef_text.asm new file mode 100644 index 00000000..24001c24 --- /dev/null +++ b/home/predef_text.asm @@ -0,0 +1,237 @@ +; this function is used to display sign messages, sprite dialog, etc. +; INPUT: [hSpriteIndexOrTextID] = sprite ID or text ID +DisplayTextID:: + ld a, [hLoadedROMBank] + push af + callba DisplayTextIDInit ; initialization + ld hl, wTextPredefFlag + bit 0, [hl] + res 0, [hl] + jr nz, .skipSwitchToMapBank + ld a, [wCurMap] + call SwitchToMapRomBank +.skipSwitchToMapBank + ld a, 30 ; half a second + ld [hFrameCounter], a ; used as joypad poll timer + ld hl, wMapTextPtr + ld a, [hli] + ld h, [hl] + ld l, a ; hl = map text pointer + ld d, $00 + ld a, [hSpriteIndexOrTextID] ; text ID + ld [wSpriteIndex], a + and a + jp z, DisplayStartMenu + cp TEXT_SAFARI_GAME_OVER + jp z, DisplaySafariGameOverText + cp TEXT_MON_FAINTED + jp z, DisplayPokemonFaintedText + cp TEXT_BLACKED_OUT + jp z, DisplayPlayerBlackedOutText + cp TEXT_REPEL_WORE_OFF + jp z, DisplayRepelWoreOffText + ld a, [wNumSprites] + ld e, a + ld a, [hSpriteIndexOrTextID] ; sprite ID + cp e + jr z, .spriteHandling + jr nc, .skipSpriteHandling +.spriteHandling +; get the text ID of the sprite + push hl + push de + push bc + callba UpdateSpriteFacingOffsetAndDelayMovement ; update the graphics of the sprite the player is talking to (to face the right direction) + pop bc + pop de + ld hl, wMapSpriteData ; NPC text entries + ld a, [hSpriteIndexOrTextID] + dec a + add a + add l + ld l, a + jr nc, .noCarry + inc h +.noCarry + inc hl + ld a, [hl] ; a = text ID of the sprite + pop hl +.skipSpriteHandling +; look up the address of the text in the map's text entries + dec a + ld e, a + sla e + add hl, de + ld a, [hli] + ld h, [hl] + ld l, a ; hl = address of the text + ld a, [hl] ; a = first byte of text +; check first byte of text for special cases + cp $fe ; Pokemart NPC + jp z, DisplayPokemartDialogue + cp $ff ; Pokemon Center NPC + jp z, DisplayPokemonCenterDialogue + cp $fc ; Item Storage PC + jp z, FuncTX_ItemStoragePC + cp $fd ; Bill's PC + jp z, FuncTX_BillsPC + cp $f9 ; Pokemon Center PC + jp z, FuncTX_PokemonCenterPC + cp $f5 ; Vending Machine + jr nz, .notVendingMachine + callba VendingMachineMenu ; jump banks to vending machine routine + jr AfterDisplayingTextID +.notVendingMachine + cp $f7 ; prize menu + jp z, FuncTX_GameCornerPrizeMenu + cp $f6 ; cable connection NPC in Pokemon Center + jr nz, .notSpecialCase + callab CableClubNPC + jr AfterDisplayingTextID +.notSpecialCase + call PrintText_NoCreatingTextBox ; display the text + ld a, [wDoNotWaitForButtonPressAfterDisplayingText] + and a + jr nz, HoldTextDisplayOpen + +AfterDisplayingTextID:: + ld a, [wEnteringCableClub] + and a + jr nz, HoldTextDisplayOpen + call WaitForTextScrollButtonPress ; wait for a button press after displaying all the text + +; loop to hold the dialogue box open as long as the player keeps holding down the A button +HoldTextDisplayOpen:: + call Joypad + ld a, [hJoyHeld] + bit 0, a ; is the A button being pressed? + jr nz, HoldTextDisplayOpen + +CloseTextDisplay:: + ld a, [wCurMap] + call SwitchToMapRomBank + ld a, $90 + ld [hWY], a ; move the window off the screen + call DelayFrame + call LoadGBPal + xor a + ld [hAutoBGTransferEnabled], a ; disable continuous WRAM to VRAM transfer each V-blank +; loop to make sprites face the directions they originally faced before the dialogue + ld hl, wSpriteStateData2 + $19 + ld c, $0f + ld de, $0010 +.restoreSpriteFacingDirectionLoop + ld a, [hl] + dec h + ld [hl], a + inc h + add hl, de + dec c + jr nz, .restoreSpriteFacingDirectionLoop + ld a, BANK(InitMapSprites) + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + call InitMapSprites ; reload sprite tile pattern data (since it was partially overwritten by text tile patterns) + ld hl, wFontLoaded + res 0, [hl] + ld a, [wd732] + bit 3, a ; used fly warp + call z, LoadPlayerSpriteGraphics + call LoadCurrentMapView + pop af + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + jp UpdateSprites + +DisplayPokemartDialogue:: + push hl + ld hl, PokemartGreetingText + call PrintText + pop hl + inc hl + call LoadItemList + ld a, PRICEDITEMLISTMENU + ld [wListMenuID], a + ld a, [hLoadedROMBank] + push af + ld a, BANK(DisplayPokemartDialogue_) + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + call DisplayPokemartDialogue_ + pop af + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + jp AfterDisplayingTextID + +PokemartGreetingText:: + TX_FAR _PokemartGreetingText + db "@" + +LoadItemList:: + ld a, 1 + ld [wUpdateSpritesEnabled], a + ld a, h + ld [wItemListPointer], a + ld a, l + ld [wItemListPointer + 1], a + ld de, wItemList +.loop + ld a, [hli] + ld [de], a + inc de + cp $ff + jr nz, .loop + ret + +DisplayPokemonCenterDialogue:: +; zeroing these doesn't appear to serve any purpose + xor a + ld [hItemPrice], a + ld [hItemPrice + 1], a + ld [hItemPrice + 2], a + + inc hl + ld a, [hLoadedROMBank] + push af + ld a, BANK(DisplayPokemonCenterDialogue_) + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + call DisplayPokemonCenterDialogue_ + pop af + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + jp AfterDisplayingTextID + +DisplaySafariGameOverText:: + callab PrintSafariGameOverText + jp AfterDisplayingTextID + +DisplayPokemonFaintedText:: + ld hl, PokemonFaintedText + call PrintText + jp AfterDisplayingTextID + +PokemonFaintedText:: + TX_FAR _PokemonFaintedText + db "@" + +DisplayPlayerBlackedOutText:: + ld hl, PlayerBlackedOutText + call PrintText + ld a, [wd732] + res 5, a ; reset forced to use bike bit + ld [wd732], a + jp HoldTextDisplayOpen + +PlayerBlackedOutText:: + TX_FAR _PlayerBlackedOutText + db "@" + +DisplayRepelWoreOffText:: + ld hl, RepelWoreOffText + call PrintText + jp AfterDisplayingTextID + +RepelWoreOffText:: + TX_FAR _RepelWoreOffText + db "@" diff --git a/home/print_bcd.asm b/home/print_bcd.asm new file mode 100644 index 00000000..38aedd3c --- /dev/null +++ b/home/print_bcd.asm @@ -0,0 +1,77 @@ +; function to print a BCD (Binary-coded decimal) number +; de = address of BCD number +; hl = destination address +; c = flags and length +; bit 7: if set, do not print leading zeroes +; if unset, print leading zeroes +; bit 6: if set, left-align the string (do not pad empty digits with spaces) +; if unset, right-align the string +; bit 5: if set, print currency symbol at the beginning of the string +; if unset, do not print the currency symbol +; bits 0-4: length of BCD number in bytes +; Note that bits 5 and 7 are modified during execution. The above reflects +; their meaning at the beginning of the functions's execution. +PrintBCDNumber:: + ld b, c ; save flags in b + res 7, c + res 6, c + res 5, c ; c now holds the length + bit 5, b + jr z, .loop + bit 7, b + jr nz, .loop + ld [hl], "¥" + inc hl +.loop + ld a, [de] + swap a + call PrintBCDDigit ; print upper digit + ld a, [de] + call PrintBCDDigit ; print lower digit + inc de + dec c + jr nz, .loop + bit 7, b ; were any non-zero digits printed? + jr z, .done ; if so, we are done +.numberEqualsZero ; if every digit of the BCD number is zero + bit 6, b ; left or right alignment? + jr nz, .skipRightAlignmentAdjustment + dec hl ; if the string is right-aligned, it needs to be moved back one space +.skipRightAlignmentAdjustment + bit 5, b + jr z, .skipCurrencySymbol + ld [hl], "¥" + inc hl +.skipCurrencySymbol + ld [hl], "0" + call PrintLetterDelay + inc hl +.done + ret + +PrintBCDDigit:: + and $f + and a + jr z, .zeroDigit +.nonzeroDigit + bit 7, b ; have any non-space characters been printed? + jr z, .outputDigit +; if bit 7 is set, then no numbers have been printed yet + bit 5, b ; print the currency symbol? + jr z, .skipCurrencySymbol + ld [hl], "¥" + inc hl + res 5, b +.skipCurrencySymbol + res 7, b ; unset 7 to indicate that a nonzero digit has been reached +.outputDigit + add "0" + ld [hli], a + jp PrintLetterDelay +.zeroDigit + bit 7, b ; either printing leading zeroes or already reached a nonzero digit? + jr z, .outputDigit ; if so, print a zero digit + bit 6, b ; left or right alignment? + ret nz + inc hl ; if right-aligned, "print" a space by advancing the pointer + ret diff --git a/home/print_num.asm b/home/print_num.asm new file mode 100644 index 00000000..5155977b --- /dev/null +++ b/home/print_num.asm @@ -0,0 +1,217 @@ +PrintNumber:: +; Print the c-digit, b-byte value at de. +; Allows 2 to 7 digits. For 1-digit numbers, add +; the value to char "0" instead of calling PrintNumber. +; Flags LEADING_ZEROES and LEFT_ALIGN can be given +; in bits 7 and 6 of b respectively. + push bc + xor a + ld [hPastLeadingZeros], a + ld [hNumToPrint], a + ld [hNumToPrint + 1], a + ld a, b + and $f + cp 1 + jr z, .byte + cp 2 + jr z, .word +.long + ld a, [de] + ld [hNumToPrint], a + inc de + ld a, [de] + ld [hNumToPrint + 1], a + inc de + ld a, [de] + ld [hNumToPrint + 2], a + jr .start + +.word + ld a, [de] + ld [hNumToPrint + 1], a + inc de + ld a, [de] + ld [hNumToPrint + 2], a + jr .start + +.byte + ld a, [de] + ld [hNumToPrint + 2], a + +.start + push de + + ld d, b + ld a, c + ld b, a + xor a + ld c, a + ld a, b + + cp 2 + jr z, .tens + cp 3 + jr z, .hundreds + cp 4 + jr z, .thousands + cp 5 + jr z, .ten_thousands + cp 6 + jr z, .hundred_thousands + +print_digit: macro + +if (\1) / $10000 + ld a, \1 / $10000 % $100 +else xor a +endc + ld [hPowerOf10 + 0], a + +if (\1) / $100 + ld a, \1 / $100 % $100 +else xor a +endc + ld [hPowerOf10 + 1], a + + ld a, \1 / $1 % $100 + ld [hPowerOf10 + 2], a + + call .PrintDigit + call .NextDigit +endm + +.millions print_digit 1000000 +.hundred_thousands print_digit 100000 +.ten_thousands print_digit 10000 +.thousands print_digit 1000 +.hundreds print_digit 100 + +.tens + ld c, 0 + ld a, [hNumToPrint + 2] +.mod + cp 10 + jr c, .ok + sub 10 + inc c + jr .mod +.ok + + ld b, a + ld a, [hPastLeadingZeros] + or c + ld [hPastLeadingZeros], a + jr nz, .past + call .PrintLeadingZero + jr .next +.past + ld a, "0" + add c + ld [hl], a +.next + + call .NextDigit +.ones + ld a, "0" + add b + ld [hli], a + pop de + dec de + pop bc + ret + +.PrintDigit: +; Divide by the current decimal place. +; Print the quotient, and keep the modulus. + ld c, 0 +.loop + ld a, [hPowerOf10] + ld b, a + ld a, [hNumToPrint] + ld [hSavedNumToPrint], a + cp b + jr c, .underflow0 + sub b + ld [hNumToPrint], a + ld a, [hPowerOf10 + 1] + ld b, a + ld a, [hNumToPrint + 1] + ld [hSavedNumToPrint + 1], a + cp b + jr nc, .noborrow1 + + ld a, [hNumToPrint] + or 0 + jr z, .underflow1 + dec a + ld [hNumToPrint], a + ld a, [hNumToPrint + 1] +.noborrow1 + + sub b + ld [hNumToPrint + 1], a + ld a, [hPowerOf10 + 2] + ld b, a + ld a, [hNumToPrint + 2] + ld [hSavedNumToPrint + 2], a + cp b + jr nc, .noborrow2 + + ld a, [hNumToPrint + 1] + and a + jr nz, .borrowed + + ld a, [hNumToPrint] + and a + jr z, .underflow2 + dec a + ld [hNumToPrint], a + xor a +.borrowed + + dec a + ld [hNumToPrint + 1], a + ld a, [hNumToPrint + 2] +.noborrow2 + sub b + ld [hNumToPrint + 2], a + inc c + jr .loop + +.underflow2 + ld a, [hSavedNumToPrint + 1] + ld [hNumToPrint + 1], a +.underflow1 + ld a, [hSavedNumToPrint] + ld [hNumToPrint], a +.underflow0 + ld a, [hPastLeadingZeros] + or c + jr z, .PrintLeadingZero + + ld a, "0" + add c + ld [hl], a + ld [hPastLeadingZeros], a + ret + +.PrintLeadingZero: + bit BIT_LEADING_ZEROES, d + ret z + ld [hl], "0" + ret + +.NextDigit: +; Increment unless the number is left-aligned, +; leading zeroes are not printed, and no digits +; have been printed yet. + bit BIT_LEADING_ZEROES, d + jr nz, .inc + bit BIT_LEFT_ALIGN, d + jr z, .inc + ld a, [hPastLeadingZeros] + and a + ret z +.inc + inc hl + ret diff --git a/home/trainers.asm b/home/trainers.asm new file mode 100644 index 00000000..9c3519a2 --- /dev/null +++ b/home/trainers.asm @@ -0,0 +1,436 @@ +; stores hl in [wTrainerHeaderPtr] +StoreTrainerHeaderPointer:: + ld a, h + ld [wTrainerHeaderPtr], a + ld a, l + ld [wTrainerHeaderPtr+1], a + ret + +; executes the current map script from the function pointer array provided in hl. +; a: map script index to execute (unless overridden by [wd733] bit 4) +ExecuteCurMapScriptInTable:: + push af + push de + call StoreTrainerHeaderPointer + pop hl + pop af + push hl + ld hl, wFlags_D733 + bit 4, [hl] + res 4, [hl] + jr z, .useProvidedIndex ; test if map script index was overridden manually + ld a, [wCurMapScript] +.useProvidedIndex + pop hl + ld [wCurMapScript], a + call CallFunctionInTable + ld a, [wCurMapScript] + ret + +LoadGymLeaderAndCityName:: + push de + ld de, wGymCityName + ld bc, $11 + call CopyData ; load city name + pop hl + ld de, wGymLeaderName + ld bc, NAME_LENGTH + jp CopyData ; load gym leader name + +; reads specific information from trainer header (pointed to at wTrainerHeaderPtr) +; a: offset in header data +; 0 -> flag's bit (into wTrainerHeaderFlagBit) +; 2 -> flag's byte ptr (into hl) +; 4 -> before battle text (into hl) +; 6 -> after battle text (into hl) +; 8 -> end battle text (into hl) +ReadTrainerHeaderInfo:: + push de + push af + ld d, $0 + ld e, a + ld hl, wTrainerHeaderPtr + ld a, [hli] + ld l, [hl] + ld h, a + add hl, de + pop af + and a + jr nz, .nonZeroOffset + ld a, [hl] + ld [wTrainerHeaderFlagBit], a ; store flag's bit + jr .done +.nonZeroOffset + cp $2 + jr z, .readPointer ; read flag's byte ptr + cp $4 + jr z, .readPointer ; read before battle text + cp $6 + jr z, .readPointer ; read after battle text + cp $8 + jr z, .readPointer ; read end battle text + cp $a + jr nz, .done + ld a, [hli] ; read end battle text (2) but override the result afterwards (XXX why, bug?) + ld d, [hl] + ld e, a + jr .done +.readPointer + ld a, [hli] + ld h, [hl] + ld l, a +.done + pop de + ret + +TrainerFlagAction:: + predef_jump FlagActionPredef + +TalkToTrainer:: + call StoreTrainerHeaderPointer + xor a + call ReadTrainerHeaderInfo ; read flag's bit + ld a, $2 + call ReadTrainerHeaderInfo ; read flag's byte ptr + ld a, [wTrainerHeaderFlagBit] + ld c, a + ld b, FLAG_TEST + call TrainerFlagAction ; read trainer's flag + ld a, c + and a + jr z, .trainerNotYetFought ; test trainer's flag + ld a, $6 + call ReadTrainerHeaderInfo ; print after battle text + jp PrintText +.trainerNotYetFought + ld a, $4 + call ReadTrainerHeaderInfo ; print before battle text + call PrintText + ld a, $a + call ReadTrainerHeaderInfo ; (?) does nothing apparently (maybe bug in ReadTrainerHeaderInfo) + push de + ld a, $8 + call ReadTrainerHeaderInfo ; read end battle text + pop de + call SaveEndBattleTextPointers + ld hl, wFlags_D733 + set 4, [hl] ; activate map script index override (index is set below) + ld hl, wFlags_0xcd60 + bit 0, [hl] ; test if player is already engaging the trainer (because the trainer saw the player) + ret nz +; if the player talked to the trainer of his own volition + call EngageMapTrainer + ld hl, wCurMapScript + inc [hl] ; increment map script index before StartTrainerBattle increments it again (next script function is usually EndTrainerBattle) + jp StartTrainerBattle + +; checks if any trainers are seeing the player and wanting to fight +CheckFightingMapTrainers:: + call CheckForEngagingTrainers + ld a, [wSpriteIndex] + cp $ff + jr nz, .trainerEngaging + xor a + ld [wSpriteIndex], a + ld [wTrainerHeaderFlagBit], a + ret +.trainerEngaging + ld hl, wFlags_D733 + set 3, [hl] + ld [wEmotionBubbleSpriteIndex], a + xor a ; EXCLAMATION_BUBBLE + ld [wWhichEmotionBubble], a + predef EmotionBubble + ld a, D_RIGHT | D_LEFT | D_UP | D_DOWN + ld [wJoyIgnore], a + xor a + ld [hJoyHeld], a + call TrainerWalkUpToPlayer_Bank0 + ld hl, wCurMapScript + inc [hl] ; increment map script index (next script function is usually DisplayEnemyTrainerTextAndStartBattle) + ret + +; display the before battle text after the enemy trainer has walked up to the player's sprite +DisplayEnemyTrainerTextAndStartBattle:: + ld a, [wd730] + and $1 + ret nz ; return if the enemy trainer hasn't finished walking to the player's sprite + ld [wJoyIgnore], a + ld a, [wSpriteIndex] + ld [hSpriteIndexOrTextID], a + call DisplayTextID + ; fall through + +StartTrainerBattle:: + xor a + ld [wJoyIgnore], a + call InitBattleEnemyParameters + ld hl, wd72d + set 6, [hl] + set 7, [hl] + ld hl, wd72e + set 1, [hl] + ld hl, wCurMapScript + inc [hl] ; increment map script index (next script function is usually EndTrainerBattle) + ret + +EndTrainerBattle:: + ld hl, wCurrentMapScriptFlags + set 5, [hl] + set 6, [hl] + ld hl, wd72d + res 7, [hl] + ld hl, wFlags_0xcd60 + res 0, [hl] ; player is no longer engaged by any trainer + ld a, [wIsInBattle] + cp $ff + jp z, ResetButtonPressedAndMapScript + ld a, $2 + call ReadTrainerHeaderInfo + ld a, [wTrainerHeaderFlagBit] + ld c, a + ld b, FLAG_SET + call TrainerFlagAction ; flag trainer as fought + ld a, [wEnemyMonOrTrainerClass] + cp OPP_ID_OFFSET + jr nc, .skipRemoveSprite ; test if trainer was fought (in that case skip removing the corresponding sprite) + ld hl, wMissableObjectList + ld de, $2 + ld a, [wSpriteIndex] + call IsInArray ; search for sprite ID + inc hl + ld a, [hl] + ld [wMissableObjectIndex], a ; load corresponding missable object index and remove it + predef HideObject +.skipRemoveSprite + ld hl, wd730 + bit 4, [hl] + res 4, [hl] + ret nz + +ResetButtonPressedAndMapScript:: + xor a + ld [wJoyIgnore], a + ld [hJoyHeld], a + ld [hJoyPressed], a + ld [hJoyReleased], a + ld [wCurMapScript], a ; reset battle status + ret + +; calls TrainerWalkUpToPlayer +TrainerWalkUpToPlayer_Bank0:: + jpba TrainerWalkUpToPlayer + +; sets opponent type and mon set/lvl based on the engaging trainer data +InitBattleEnemyParameters:: + ld a, [wEngagedTrainerClass] + ld [wCurOpponent], a + ld [wEnemyMonOrTrainerClass], a + cp OPP_ID_OFFSET + ld a, [wEngagedTrainerSet] + jr c, .noTrainer + ld [wTrainerNo], a + ret +.noTrainer + ld [wCurEnemyLVL], a + ret + +GetSpritePosition1:: + ld hl, _GetSpritePosition1 + jr SpritePositionBankswitch + +GetSpritePosition2:: + ld hl, _GetSpritePosition2 + jr SpritePositionBankswitch + +SetSpritePosition1:: + ld hl, _SetSpritePosition1 + jr SpritePositionBankswitch + +SetSpritePosition2:: + ld hl, _SetSpritePosition2 +SpritePositionBankswitch:: + ld b, BANK(_GetSpritePosition1) ; BANK(_GetSpritePosition2), BANK(_SetSpritePosition1), BANK(_SetSpritePosition2) + jp Bankswitch ; indirect jump to one of the four functions + +CheckForEngagingTrainers:: + xor a + call ReadTrainerHeaderInfo ; read trainer flag's bit (unused) + ld d, h ; store trainer header address in de + ld e, l +.trainerLoop + call StoreTrainerHeaderPointer ; set trainer header pointer to current trainer + ld a, [de] + ld [wSpriteIndex], a ; store trainer flag's bit + ld [wTrainerHeaderFlagBit], a + cp $ff + ret z + ld a, $2 + call ReadTrainerHeaderInfo ; read trainer flag's byte ptr + ld b, FLAG_TEST + ld a, [wTrainerHeaderFlagBit] + ld c, a + call TrainerFlagAction ; read trainer flag + ld a, c + and a ; has the trainer already been defeated? + jr nz, .continue + push hl + push de + push hl + xor a + call ReadTrainerHeaderInfo ; get trainer header pointer + inc hl + ld a, [hl] ; read trainer engage distance + pop hl + ld [wTrainerEngageDistance], a + ld a, [wSpriteIndex] + swap a + ld [wTrainerSpriteOffset], a + predef TrainerEngage + pop de + pop hl + ld a, [wTrainerSpriteOffset] + and a + ret nz ; break if the trainer is engaging +.continue + ld hl, $c + add hl, de + ld d, h + ld e, l + jr .trainerLoop + +; hl = text if the player wins +; de = text if the player loses +SaveEndBattleTextPointers:: + ld a, [hLoadedROMBank] + ld [wEndBattleTextRomBank], a + ld a, h + ld [wEndBattleWinTextPointer], a + ld a, l + ld [wEndBattleWinTextPointer + 1], a + ld a, d + ld [wEndBattleLoseTextPointer], a + ld a, e + ld [wEndBattleLoseTextPointer + 1], a + ret + +; loads data of some trainer on the current map and plays pre-battle music +; [wSpriteIndex]: sprite ID of trainer who is engaged +EngageMapTrainer:: + ld hl, wMapSpriteExtraData + ld d, $0 + ld a, [wSpriteIndex] + dec a + add a + ld e, a + add hl, de ; seek to engaged trainer data + ld a, [hli] ; load trainer class + ld [wEngagedTrainerClass], a + ld a, [hl] ; load trainer mon set + ld [wEngagedTrainerSet], a + jp PlayTrainerMusic + +PrintEndBattleText:: + push hl + ld hl, wd72d + bit 7, [hl] + res 7, [hl] + pop hl + ret z + ld a, [hLoadedROMBank] + push af + ld a, [wEndBattleTextRomBank] + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + push hl + callba SaveTrainerName + ld hl, TrainerEndBattleText + call PrintText + pop hl + pop af + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + callba FreezeEnemyTrainerSprite + jp WaitForSoundToFinish + +GetSavedEndBattleTextPointer:: + ld a, [wBattleResult] + and a +; won battle + jr nz, .lostBattle + ld a, [wEndBattleWinTextPointer] + ld h, a + ld a, [wEndBattleWinTextPointer + 1] + ld l, a + ret +.lostBattle + ld a, [wEndBattleLoseTextPointer] + ld h, a + ld a, [wEndBattleLoseTextPointer + 1] + ld l, a + ret + +TrainerEndBattleText:: + TX_FAR _TrainerNameText + TX_ASM + call GetSavedEndBattleTextPointer + call TextCommandProcessor + jp TextScriptEnd + +; only engage with the trainer if the player is not already +; engaged with another trainer +; XXX unused? +CheckIfAlreadyEngaged:: + ld a, [wFlags_0xcd60] + bit 0, a + ret nz + call EngageMapTrainer + xor a + ret + +PlayTrainerMusic:: + ld a, [wEngagedTrainerClass] + cp OPP_SONY1 + ret z + cp OPP_SONY2 + ret z + cp OPP_SONY3 + ret z + ld a, [wGymLeaderNo] + and a + ret nz + xor a + ld [wAudioFadeOutControl], a + ld a, SFX_STOP_ALL_MUSIC + call PlaySound + ld a, BANK(Music_MeetEvilTrainer) + ld [wAudioROMBank], a + ld [wAudioSavedROMBank], a + ld a, [wEngagedTrainerClass] + ld b, a + ld hl, EvilTrainerList +.evilTrainerListLoop + ld a, [hli] + cp $ff + jr z, .noEvilTrainer + cp b + jr nz, .evilTrainerListLoop + ld a, MUSIC_MEET_EVIL_TRAINER + jr .PlaySound +.noEvilTrainer + ld hl, FemaleTrainerList +.femaleTrainerListLoop + ld a, [hli] + cp $ff + jr z, .maleTrainer + cp b + jr nz, .femaleTrainerListLoop + ld a, MUSIC_MEET_FEMALE_TRAINER + jr .PlaySound +.maleTrainer + ld a, MUSIC_MEET_MALE_TRAINER +.PlaySound + ld [wNewSoundID], a + jp PlaySound + +INCLUDE "data/trainers/encounter_types.asm" diff --git a/home/uncompress.asm b/home/uncompress.asm new file mode 100644 index 00000000..02683db7 --- /dev/null +++ b/home/uncompress.asm @@ -0,0 +1,196 @@ +; uncompresses the front or back sprite of the specified mon +; assumes the corresponding mon header is already loaded +; hl contains offset to sprite pointer ($b for front or $d for back) +UncompressMonSprite:: + ld bc, wMonHeader + add hl, bc + ld a, [hli] + ld [wSpriteInputPtr], a ; fetch sprite input pointer + ld a, [hl] + ld [wSpriteInputPtr+1], a +; define (by index number) the bank that a pokemon's image is in +; index = Mew, bank 1 +; index = Kabutops fossil, bank $B +; index < $1F, bank 9 +; $1F ≤ index < $4A, bank $A +; $4A ≤ index < $74, bank $B +; $74 ≤ index < $99, bank $C +; $99 ≤ index, bank $D + ld a, [wcf91] ; XXX name for this ram location + ld b, a + cp MEW + ld a, BANK(MewPicFront) + jr z, .GotBank + ld a, b + cp FOSSIL_KABUTOPS + ld a, BANK(FossilKabutopsPic) + jr z, .GotBank + ld a, b + cp TANGELA + 1 + ld a, BANK(TangelaPicFront) + jr c, .GotBank + ld a, b + cp MOLTRES + 1 + ld a, BANK(MoltresPicFront) + jr c, .GotBank + ld a, b + cp BEEDRILL + 2 + ld a, BANK(BeedrillPicFront) + jr c, .GotBank + ld a, b + cp STARMIE + 1 + ld a, BANK(StarmiePicFront) + jr c, .GotBank + ld a, BANK(VictreebelPicFront) +.GotBank + jp UncompressSpriteData + +; de: destination location +LoadMonFrontSprite:: + push de + ld hl, wMonHFrontSprite - wMonHeader + call UncompressMonSprite + ld hl, wMonHSpriteDim + ld a, [hli] + ld c, a + pop de + ; fall through + +; postprocesses uncompressed sprite chunks to a 2bpp sprite and loads it into video ram +; calculates alignment parameters to place both sprite chunks in the center of the 7*7 tile sprite buffers +; de: destination location +; a,c: sprite dimensions (in tiles of 8x8 each) +LoadUncompressedSpriteData:: + push de + and $f + ld [hSpriteWidth], a ; each byte contains 8 pixels (in 1bpp), so tiles=bytes for width + ld b, a + ld a, $7 + sub b ; 7-w + inc a ; 8-w + srl a ; (8-w)/2 ; horizontal center (in tiles, rounded up) + ld b, a + add a + add a + add a + sub b ; 7*((8-w)/2) ; skip for horizontal center (in tiles) + ld [hSpriteOffset], a + ld a, c + swap a + and $f + ld b, a + add a + add a + add a ; 8*tiles is height in bytes + ld [hSpriteHeight], a + ld a, $7 + sub b ; 7-h ; skip for vertical center (in tiles, relative to current column) + ld b, a + ld a, [hSpriteOffset] + add b ; 7*((8-w)/2) + 7-h ; combined overall offset (in tiles) + add a + add a + add a ; 8*(7*((8-w)/2) + 7-h) ; combined overall offset (in bytes) + ld [hSpriteOffset], a + xor a + ld [$4000], a + ld hl, sSpriteBuffer0 + call ZeroSpriteBuffer ; zero buffer 0 + ld de, sSpriteBuffer1 + ld hl, sSpriteBuffer0 + call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite) + ld hl, sSpriteBuffer1 + call ZeroSpriteBuffer ; zero buffer 1 + ld de, sSpriteBuffer2 + ld hl, sSpriteBuffer1 + call AlignSpriteDataCentered ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite) + pop de + jp InterlaceMergeSpriteBuffers + +; copies and aligns the sprite data properly inside the sprite buffer +; sprite buffers are 7*7 tiles in size, the loaded sprite is centered within this area +AlignSpriteDataCentered:: + ld a, [hSpriteOffset] + ld b, $0 + ld c, a + add hl, bc + ld a, [hSpriteWidth] +.columnLoop + push af + push hl + ld a, [hSpriteHeight] + ld c, a +.columnInnerLoop + ld a, [de] + inc de + ld [hli], a + dec c + jr nz, .columnInnerLoop + pop hl + ld bc, 7*8 ; 7 tiles + add hl, bc ; advance one full column + pop af + dec a + jr nz, .columnLoop + ret + +; fills the sprite buffer (pointed to in hl) with zeros +ZeroSpriteBuffer:: + ld bc, SPRITEBUFFERSIZE +.nextByteLoop + xor a + ld [hli], a + dec bc + ld a, b + or c + jr nz, .nextByteLoop + ret + +; combines the (7*7 tiles, 1bpp) sprite chunks in buffer 0 and 1 into a 2bpp sprite located in buffer 1 through 2 +; in the resulting sprite, the rows of the two source sprites are interlaced +; de: output address +InterlaceMergeSpriteBuffers:: + xor a + ld [$4000], a + push de + ld hl, sSpriteBuffer2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2 + ld de, sSpriteBuffer1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1 + ld bc, sSpriteBuffer0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0 + ld a, SPRITEBUFFERSIZE/2 ; $c4 + ld [hSpriteInterlaceCounter], a +.interlaceLoop + ld a, [de] + dec de + ld [hld], a ; write byte of source 2 + ld a, [bc] + dec bc + ld [hld], a ; write byte of source 1 + ld a, [de] + dec de + ld [hld], a ; write byte of source 2 + ld a, [bc] + dec bc + ld [hld], a ; write byte of source 1 + ld a, [hSpriteInterlaceCounter] + dec a + ld [hSpriteInterlaceCounter], a + jr nz, .interlaceLoop + ld a, [wSpriteFlipped] + and a + jr z, .notFlipped + ld bc, 2*SPRITEBUFFERSIZE + ld hl, sSpriteBuffer1 +.swapLoop + swap [hl] ; if flipped swap nybbles in all bytes + inc hl + dec bc + ld a, b + or c + jr nz, .swapLoop +.notFlipped + pop hl + ld de, sSpriteBuffer1 + ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied + ld a, [hLoadedROMBank] + ld b, a + jp CopyVideoData diff --git a/home/yes_no.asm b/home/yes_no.asm new file mode 100644 index 00000000..61aa1390 --- /dev/null +++ b/home/yes_no.asm @@ -0,0 +1,40 @@ +; displays yes/no choice +; yes -> set carry +YesNoChoice:: + call SaveScreenTilesToBuffer1 + call InitYesNoTextBoxParameters + jr DisplayYesNoChoice + +Func_35f4:: + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call InitYesNoTextBoxParameters + jp DisplayTextBoxID + +InitYesNoTextBoxParameters:: + xor a ; YES_NO_MENU + ld [wTwoOptionMenuID], a + coord hl, 14, 7 + ld bc, $80f + ret + +YesNoChoicePokeCenter:: + call SaveScreenTilesToBuffer1 + ld a, HEAL_CANCEL_MENU + ld [wTwoOptionMenuID], a + coord hl, 11, 6 + lb bc, 8, 12 + jr DisplayYesNoChoice + +WideYesNoChoice:: ; unused + call SaveScreenTilesToBuffer1 + ld a, WIDE_YES_NO_MENU + ld [wTwoOptionMenuID], a + coord hl, 12, 7 + lb bc, 8, 13 + +DisplayYesNoChoice:: + ld a, TWO_OPTION_MENU + ld [wTextBoxID], a + call DisplayTextBoxID + jp LoadScreenTilesFromBuffer1 -- cgit v1.2.3 From 9b144cf647fe0ca11941abff53db5e2ec2a20127 Mon Sep 17 00:00:00 2001 From: Rangi Date: Fri, 3 Jul 2020 23:05:25 -0400 Subject: home/pic.asm -> home/uncompress.asm; home/uncompress.asm -> home/pics.asm One does the actual decompression, the other synthesizes the decompressed data. --- home/pic.asm | 591 ------------------------------------------ home/pics.asm | 196 ++++++++++++++ home/uncompress.asm | 725 ++++++++++++++++++++++++++++++++++++++++------------ 3 files changed, 756 insertions(+), 756 deletions(-) delete mode 100644 home/pic.asm create mode 100644 home/pics.asm (limited to 'home') diff --git a/home/pic.asm b/home/pic.asm deleted file mode 100644 index cfc39f0f..00000000 --- a/home/pic.asm +++ /dev/null @@ -1,591 +0,0 @@ -; bankswitches and runs _UncompressSpriteData -; bank is given in a, sprite input stream is pointed to in wSpriteInputPtr -UncompressSpriteData:: - ld b, a - ld a, [hLoadedROMBank] - push af - ld a, b - ld [hLoadedROMBank], a - ld [MBC1RomBank], a - ld a, SRAM_ENABLE - ld [MBC1SRamEnable], a - xor a - ld [MBC1SRamBank], a - call _UncompressSpriteData - pop af - ld [hLoadedROMBank], a - ld [MBC1RomBank], a - ret - -; initializes necessary data to load a sprite and runs UncompressSpriteDataLoop -_UncompressSpriteData:: - ld hl, sSpriteBuffer1 - ld c, (2*SPRITEBUFFERSIZE) % $100 - ld b, (2*SPRITEBUFFERSIZE) / $100 - xor a - call FillMemory ; clear sprite buffer 1 and 2 - ld a, $1 - ld [wSpriteInputBitCounter], a - ld a, $3 - ld [wSpriteOutputBitOffset], a - xor a - ld [wSpriteCurPosX], a - ld [wSpriteCurPosY], a - ld [wSpriteLoadFlags], a - call ReadNextInputByte ; first byte of input determines sprite width (high nybble) and height (low nybble) in tiles (8x8 pixels) - ld b, a - and $f - add a - add a - add a - ld [wSpriteHeight], a - ld a, b - swap a - and $f - add a - add a - add a - ld [wSpriteWidth], a - call ReadNextInputBit - ld [wSpriteLoadFlags], a ; initialite bit1 to 0 and bit0 to the first input bit - ; this will load two chunks of data to sSpriteBuffer1 and sSpriteBuffer2 - ; bit 0 decides in which one the first chunk is placed - ; fall through - -; uncompresses a chunk from the sprite input data stream (pointed to at wd0da) into sSpriteBuffer1 or sSpriteBuffer2 -; each chunk is a 1bpp sprite. A 2bpp sprite consist of two chunks which are merged afterwards -; note that this is an endless loop which is terminated during a call to MoveToNextBufferPosition by manipulating the stack -UncompressSpriteDataLoop:: - ld hl, sSpriteBuffer1 - ld a, [wSpriteLoadFlags] - bit 0, a - jr z, .useSpriteBuffer1 ; check which buffer to use - ld hl, sSpriteBuffer2 -.useSpriteBuffer1 - call StoreSpriteOutputPointer - ld a, [wSpriteLoadFlags] - bit 1, a - jr z, .startDecompression ; check if last iteration - call ReadNextInputBit ; if last chunk, read 1-2 bit unpacking mode - and a - jr z, .unpackingMode0 ; 0 -> mode 0 - call ReadNextInputBit ; 1 0 -> mode 1 - inc a ; 1 1 -> mode 2 -.unpackingMode0 - ld [wSpriteUnpackMode], a -.startDecompression - call ReadNextInputBit - and a - jr z, .readRLEncodedZeros ; if first bit is 0, the input starts with zeroes, otherwise with (non-zero) input -.readNextInput - call ReadNextInputBit - ld c, a - call ReadNextInputBit - sla c - or c ; read next two bits into c - and a - jr z, .readRLEncodedZeros ; 00 -> RLEncoded zeroes following - call WriteSpriteBitsToBuffer ; otherwise write input to output and repeat - call MoveToNextBufferPosition - jr .readNextInput -.readRLEncodedZeros - ld c, $0 ; number of zeroes it length encoded, the number -.countConsecutiveOnesLoop ; of consecutive ones determines the number of bits the number has - call ReadNextInputBit - and a - jr z, .countConsecutiveOnesFinished - inc c - jr .countConsecutiveOnesLoop -.countConsecutiveOnesFinished - ld a, c - add a - ld hl, LengthEncodingOffsetList - add l - ld l, a - jr nc, .noCarry - inc h -.noCarry - ld a, [hli] ; read offset that is added to the number later on - ld e, a ; adding an offset of 2^length - 1 makes every integer uniquely - ld d, [hl] ; representable in the length encoding and saves bits - push de - inc c - ld e, $0 - ld d, e -.readNumberOfZerosLoop ; reads the next c+1 bits of input - call ReadNextInputBit - or e - ld e, a - dec c - jr z, .readNumberOfZerosDone - sla e - rl d - jr .readNumberOfZerosLoop -.readNumberOfZerosDone - pop hl ; add the offset - add hl, de - ld e, l - ld d, h -.writeZerosLoop - ld b, e - xor a ; write 00 to buffer - call WriteSpriteBitsToBuffer - ld e, b - call MoveToNextBufferPosition - dec de - ld a, d - and a - jr nz, .continueLoop - ld a, e - and a -.continueLoop - jr nz, .writeZerosLoop - jr .readNextInput - -; moves output pointer to next position -; also cancels the calling function if the all output is done (by removing the return pointer from stack) -; and calls postprocessing functions according to the unpack mode -MoveToNextBufferPosition:: - ld a, [wSpriteHeight] - ld b, a - ld a, [wSpriteCurPosY] - inc a - cp b - jr z, .curColumnDone - ld [wSpriteCurPosY], a - ld a, [wSpriteOutputPtr] - inc a - ld [wSpriteOutputPtr], a - ret nz - ld a, [wSpriteOutputPtr+1] - inc a - ld [wSpriteOutputPtr+1], a - ret -.curColumnDone - xor a - ld [wSpriteCurPosY], a - ld a, [wSpriteOutputBitOffset] - and a - jr z, .bitOffsetsDone - dec a - ld [wSpriteOutputBitOffset], a - ld hl, wSpriteOutputPtrCached - ld a, [hli] - ld [wSpriteOutputPtr], a - ld a, [hl] - ld [wSpriteOutputPtr+1], a - ret -.bitOffsetsDone - ld a, $3 - ld [wSpriteOutputBitOffset], a - ld a, [wSpriteCurPosX] - add $8 - ld [wSpriteCurPosX], a - ld b, a - ld a, [wSpriteWidth] - cp b - jr z, .allColumnsDone - ld a, [wSpriteOutputPtr] - ld l, a - ld a, [wSpriteOutputPtr+1] - ld h, a - inc hl - jp StoreSpriteOutputPointer -.allColumnsDone - pop hl - xor a - ld [wSpriteCurPosX], a - ld a, [wSpriteLoadFlags] - bit 1, a - jr nz, .done ; test if there is one more sprite to go - xor $1 - set 1, a - ld [wSpriteLoadFlags], a - jp UncompressSpriteDataLoop -.done - jp UnpackSprite - -; writes 2 bits (from a) to the output buffer (pointed to from wSpriteOutputPtr) -WriteSpriteBitsToBuffer:: - ld e, a - ld a, [wSpriteOutputBitOffset] - and a - jr z, .offset0 - cp $2 - jr c, .offset1 - jr z, .offset2 - rrc e ; offset 3 - rrc e - jr .offset0 -.offset1 - sla e - sla e - jr .offset0 -.offset2 - swap e -.offset0 - ld a, [wSpriteOutputPtr] - ld l, a - ld a, [wSpriteOutputPtr+1] - ld h, a - ld a, [hl] - or e - ld [hl], a - ret - -; reads next bit from input stream and returns it in a -ReadNextInputBit:: - ld a, [wSpriteInputBitCounter] - dec a - jr nz, .curByteHasMoreBitsToRead - call ReadNextInputByte - ld [wSpriteInputCurByte], a - ld a, $8 -.curByteHasMoreBitsToRead - ld [wSpriteInputBitCounter], a - ld a, [wSpriteInputCurByte] - rlca - ld [wSpriteInputCurByte], a - and $1 - ret - -; reads next byte from input stream and returns it in a -ReadNextInputByte:: - ld a, [wSpriteInputPtr] - ld l, a - ld a, [wSpriteInputPtr+1] - ld h, a - ld a, [hli] - ld b, a - ld a, l - ld [wSpriteInputPtr], a - ld a, h - ld [wSpriteInputPtr+1], a - ld a, b - ret - -; the nth item is 2^n - 1 -LengthEncodingOffsetList:: - dw %0000000000000001 - dw %0000000000000011 - dw %0000000000000111 - dw %0000000000001111 - dw %0000000000011111 - dw %0000000000111111 - dw %0000000001111111 - dw %0000000011111111 - dw %0000000111111111 - dw %0000001111111111 - dw %0000011111111111 - dw %0000111111111111 - dw %0001111111111111 - dw %0011111111111111 - dw %0111111111111111 - dw %1111111111111111 - -; unpacks the sprite data depending on the unpack mode -UnpackSprite:: - ld a, [wSpriteUnpackMode] - cp $2 - jp z, UnpackSpriteMode2 - and a - jp nz, XorSpriteChunks - ld hl, sSpriteBuffer1 - call SpriteDifferentialDecode - ld hl, sSpriteBuffer2 - ; fall through - -; decodes differential encoded sprite data -; input bit value 0 preserves the current bit value and input bit value 1 toggles it (starting from initial value 0). -SpriteDifferentialDecode:: - xor a - ld [wSpriteCurPosX], a - ld [wSpriteCurPosY], a - call StoreSpriteOutputPointer - ld a, [wSpriteFlipped] - and a - jr z, .notFlipped - ld hl, DecodeNybble0TableFlipped - ld de, DecodeNybble1TableFlipped - jr .storeDecodeTablesPointers -.notFlipped - ld hl, DecodeNybble0Table - ld de, DecodeNybble1Table -.storeDecodeTablesPointers - ld a, l - ld [wSpriteDecodeTable0Ptr], a - ld a, h - ld [wSpriteDecodeTable0Ptr+1], a - ld a, e - ld [wSpriteDecodeTable1Ptr], a - ld a, d - ld [wSpriteDecodeTable1Ptr+1], a - ld e, $0 ; last decoded nybble, initialized to 0 -.decodeNextByteLoop - ld a, [wSpriteOutputPtr] - ld l, a - ld a, [wSpriteOutputPtr+1] - ld h, a - ld a, [hl] - ld b, a - swap a - and $f - call DifferentialDecodeNybble ; decode high nybble - swap a - ld d, a - ld a, b - and $f - call DifferentialDecodeNybble ; decode low nybble - or d - ld b, a - ld a, [wSpriteOutputPtr] - ld l, a - ld a, [wSpriteOutputPtr+1] - ld h, a - ld a, b - ld [hl], a ; write back decoded data - ld a, [wSpriteHeight] - add l ; move on to next column - jr nc, .noCarry - inc h -.noCarry - ld [wSpriteOutputPtr], a - ld a, h - ld [wSpriteOutputPtr+1], a - ld a, [wSpriteCurPosX] - add $8 - ld [wSpriteCurPosX], a - ld b, a - ld a, [wSpriteWidth] - cp b - jr nz, .decodeNextByteLoop ; test if current row is done - xor a - ld e, a - ld [wSpriteCurPosX], a - ld a, [wSpriteCurPosY] ; move on to next row - inc a - ld [wSpriteCurPosY], a - ld b, a - ld a, [wSpriteHeight] - cp b - jr z, .done ; test if all rows finished - ld a, [wSpriteOutputPtrCached] - ld l, a - ld a, [wSpriteOutputPtrCached+1] - ld h, a - inc hl - call StoreSpriteOutputPointer - jr .decodeNextByteLoop -.done - xor a - ld [wSpriteCurPosY], a - ret - -; decodes the nybble stored in a. Last decoded data is assumed to be in e (needed to determine if initial value is 0 or 1) -DifferentialDecodeNybble:: - srl a ; c=a%2, a/=2 - ld c, $0 - jr nc, .evenNumber - ld c, $1 -.evenNumber - ld l, a - ld a, [wSpriteFlipped] - and a - jr z, .notFlipped ; determine if initial value is 0 or one - bit 3, e ; if flipped, consider MSB of last data - jr .selectLookupTable -.notFlipped - bit 0, e ; else consider LSB -.selectLookupTable - ld e, l - jr nz, .initialValue1 ; load the appropriate table - ld a, [wSpriteDecodeTable0Ptr] - ld l, a - ld a, [wSpriteDecodeTable0Ptr+1] - jr .tableLookup -.initialValue1 - ld a, [wSpriteDecodeTable1Ptr] - ld l, a - ld a, [wSpriteDecodeTable1Ptr+1] -.tableLookup - ld h, a - ld a, e - add l - ld l, a - jr nc, .noCarry - inc h -.noCarry - ld a, [hl] - bit 0, c - jr nz, .selectLowNybble - swap a ; select high nybble -.selectLowNybble - and $f - ld e, a ; update last decoded data - ret - -DecodeNybble0Table:: - dn $0, $1 - dn $3, $2 - dn $7, $6 - dn $4, $5 - dn $f, $e - dn $c, $d - dn $8, $9 - dn $b, $a -DecodeNybble1Table:: - dn $f, $e - dn $c, $d - dn $8, $9 - dn $b, $a - dn $0, $1 - dn $3, $2 - dn $7, $6 - dn $4, $5 -DecodeNybble0TableFlipped:: - dn $0, $8 - dn $c, $4 - dn $e, $6 - dn $2, $a - dn $f, $7 - dn $3, $b - dn $1, $9 - dn $d, $5 -DecodeNybble1TableFlipped:: - dn $f, $7 - dn $3, $b - dn $1, $9 - dn $d, $5 - dn $0, $8 - dn $c, $4 - dn $e, $6 - dn $2, $a - -; combines the two loaded chunks with xor (the chunk loaded second is the destination). The source chunk is differeintial decoded beforehand. -XorSpriteChunks:: - xor a - ld [wSpriteCurPosX], a - ld [wSpriteCurPosY], a - call ResetSpriteBufferPointers - ld a, [wSpriteOutputPtr] ; points to buffer 1 or 2, depending on flags - ld l, a - ld a, [wSpriteOutputPtr+1] - ld h, a - call SpriteDifferentialDecode ; decode buffer 1 or 2, depending on flags - call ResetSpriteBufferPointers - ld a, [wSpriteOutputPtr] ; source buffer, points to buffer 1 or 2, depending on flags - ld l, a - ld a, [wSpriteOutputPtr+1] - ld h, a - ld a, [wSpriteOutputPtrCached] ; destination buffer, points to buffer 2 or 1, depending on flags - ld e, a - ld a, [wSpriteOutputPtrCached+1] - ld d, a -.xorChunksLoop - ld a, [wSpriteFlipped] - and a - jr z, .notFlipped - push de - ld a, [de] - ld b, a - swap a - and $f - call ReverseNybble ; if flipped reverse the nybbles in the destination buffer - swap a - ld c, a - ld a, b - and $f - call ReverseNybble - or c - pop de - ld [de], a -.notFlipped - ld a, [hli] - ld b, a - ld a, [de] - xor b - ld [de], a - inc de - ld a, [wSpriteCurPosY] - inc a - ld [wSpriteCurPosY], a ; go to next row - ld b, a - ld a, [wSpriteHeight] - cp b - jr nz, .xorChunksLoop ; test if column finished - xor a - ld [wSpriteCurPosY], a - ld a, [wSpriteCurPosX] - add $8 - ld [wSpriteCurPosX], a ; go to next column - ld b, a - ld a, [wSpriteWidth] - cp b - jr nz, .xorChunksLoop ; test if all columns finished - xor a - ld [wSpriteCurPosX], a - ret - -; reverses the bits in the nybble given in register a -ReverseNybble:: - ld de, NybbleReverseTable - add e - ld e, a - jr nc, .noCarry - inc d -.noCarry - ld a, [de] - ret - -; resets sprite buffer pointers to buffer 1 and 2, depending on wSpriteLoadFlags -ResetSpriteBufferPointers:: - ld a, [wSpriteLoadFlags] - bit 0, a - jr nz, .buffer2Selected - ld de, sSpriteBuffer1 - ld hl, sSpriteBuffer2 - jr .storeBufferPointers -.buffer2Selected - ld de, sSpriteBuffer2 - ld hl, sSpriteBuffer1 -.storeBufferPointers - ld a, l - ld [wSpriteOutputPtr], a - ld a, h - ld [wSpriteOutputPtr+1], a - ld a, e - ld [wSpriteOutputPtrCached], a - ld a, d - ld [wSpriteOutputPtrCached+1], a - ret - -; maps each nybble to its reverse -NybbleReverseTable:: - db $0, $8, $4, $c, $2, $a, $6 ,$e, $1, $9, $5, $d, $3, $b, $7 ,$f - -; combines the two loaded chunks with xor (the chunk loaded second is the destination). Both chunks are differeintial decoded beforehand. -UnpackSpriteMode2:: - call ResetSpriteBufferPointers - ld a, [wSpriteFlipped] - push af - xor a - ld [wSpriteFlipped], a ; temporarily clear flipped flag for decoding the destination chunk - ld a, [wSpriteOutputPtrCached] - ld l, a - ld a, [wSpriteOutputPtrCached+1] - ld h, a - call SpriteDifferentialDecode - call ResetSpriteBufferPointers - pop af - ld [wSpriteFlipped], a - jp XorSpriteChunks - -; stores hl into the output pointers -StoreSpriteOutputPointer:: - ld a, l - ld [wSpriteOutputPtr], a - ld [wSpriteOutputPtrCached], a - ld a, h - ld [wSpriteOutputPtr+1], a - ld [wSpriteOutputPtrCached+1], a - ret diff --git a/home/pics.asm b/home/pics.asm new file mode 100644 index 00000000..02683db7 --- /dev/null +++ b/home/pics.asm @@ -0,0 +1,196 @@ +; uncompresses the front or back sprite of the specified mon +; assumes the corresponding mon header is already loaded +; hl contains offset to sprite pointer ($b for front or $d for back) +UncompressMonSprite:: + ld bc, wMonHeader + add hl, bc + ld a, [hli] + ld [wSpriteInputPtr], a ; fetch sprite input pointer + ld a, [hl] + ld [wSpriteInputPtr+1], a +; define (by index number) the bank that a pokemon's image is in +; index = Mew, bank 1 +; index = Kabutops fossil, bank $B +; index < $1F, bank 9 +; $1F ≤ index < $4A, bank $A +; $4A ≤ index < $74, bank $B +; $74 ≤ index < $99, bank $C +; $99 ≤ index, bank $D + ld a, [wcf91] ; XXX name for this ram location + ld b, a + cp MEW + ld a, BANK(MewPicFront) + jr z, .GotBank + ld a, b + cp FOSSIL_KABUTOPS + ld a, BANK(FossilKabutopsPic) + jr z, .GotBank + ld a, b + cp TANGELA + 1 + ld a, BANK(TangelaPicFront) + jr c, .GotBank + ld a, b + cp MOLTRES + 1 + ld a, BANK(MoltresPicFront) + jr c, .GotBank + ld a, b + cp BEEDRILL + 2 + ld a, BANK(BeedrillPicFront) + jr c, .GotBank + ld a, b + cp STARMIE + 1 + ld a, BANK(StarmiePicFront) + jr c, .GotBank + ld a, BANK(VictreebelPicFront) +.GotBank + jp UncompressSpriteData + +; de: destination location +LoadMonFrontSprite:: + push de + ld hl, wMonHFrontSprite - wMonHeader + call UncompressMonSprite + ld hl, wMonHSpriteDim + ld a, [hli] + ld c, a + pop de + ; fall through + +; postprocesses uncompressed sprite chunks to a 2bpp sprite and loads it into video ram +; calculates alignment parameters to place both sprite chunks in the center of the 7*7 tile sprite buffers +; de: destination location +; a,c: sprite dimensions (in tiles of 8x8 each) +LoadUncompressedSpriteData:: + push de + and $f + ld [hSpriteWidth], a ; each byte contains 8 pixels (in 1bpp), so tiles=bytes for width + ld b, a + ld a, $7 + sub b ; 7-w + inc a ; 8-w + srl a ; (8-w)/2 ; horizontal center (in tiles, rounded up) + ld b, a + add a + add a + add a + sub b ; 7*((8-w)/2) ; skip for horizontal center (in tiles) + ld [hSpriteOffset], a + ld a, c + swap a + and $f + ld b, a + add a + add a + add a ; 8*tiles is height in bytes + ld [hSpriteHeight], a + ld a, $7 + sub b ; 7-h ; skip for vertical center (in tiles, relative to current column) + ld b, a + ld a, [hSpriteOffset] + add b ; 7*((8-w)/2) + 7-h ; combined overall offset (in tiles) + add a + add a + add a ; 8*(7*((8-w)/2) + 7-h) ; combined overall offset (in bytes) + ld [hSpriteOffset], a + xor a + ld [$4000], a + ld hl, sSpriteBuffer0 + call ZeroSpriteBuffer ; zero buffer 0 + ld de, sSpriteBuffer1 + ld hl, sSpriteBuffer0 + call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite) + ld hl, sSpriteBuffer1 + call ZeroSpriteBuffer ; zero buffer 1 + ld de, sSpriteBuffer2 + ld hl, sSpriteBuffer1 + call AlignSpriteDataCentered ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite) + pop de + jp InterlaceMergeSpriteBuffers + +; copies and aligns the sprite data properly inside the sprite buffer +; sprite buffers are 7*7 tiles in size, the loaded sprite is centered within this area +AlignSpriteDataCentered:: + ld a, [hSpriteOffset] + ld b, $0 + ld c, a + add hl, bc + ld a, [hSpriteWidth] +.columnLoop + push af + push hl + ld a, [hSpriteHeight] + ld c, a +.columnInnerLoop + ld a, [de] + inc de + ld [hli], a + dec c + jr nz, .columnInnerLoop + pop hl + ld bc, 7*8 ; 7 tiles + add hl, bc ; advance one full column + pop af + dec a + jr nz, .columnLoop + ret + +; fills the sprite buffer (pointed to in hl) with zeros +ZeroSpriteBuffer:: + ld bc, SPRITEBUFFERSIZE +.nextByteLoop + xor a + ld [hli], a + dec bc + ld a, b + or c + jr nz, .nextByteLoop + ret + +; combines the (7*7 tiles, 1bpp) sprite chunks in buffer 0 and 1 into a 2bpp sprite located in buffer 1 through 2 +; in the resulting sprite, the rows of the two source sprites are interlaced +; de: output address +InterlaceMergeSpriteBuffers:: + xor a + ld [$4000], a + push de + ld hl, sSpriteBuffer2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2 + ld de, sSpriteBuffer1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1 + ld bc, sSpriteBuffer0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0 + ld a, SPRITEBUFFERSIZE/2 ; $c4 + ld [hSpriteInterlaceCounter], a +.interlaceLoop + ld a, [de] + dec de + ld [hld], a ; write byte of source 2 + ld a, [bc] + dec bc + ld [hld], a ; write byte of source 1 + ld a, [de] + dec de + ld [hld], a ; write byte of source 2 + ld a, [bc] + dec bc + ld [hld], a ; write byte of source 1 + ld a, [hSpriteInterlaceCounter] + dec a + ld [hSpriteInterlaceCounter], a + jr nz, .interlaceLoop + ld a, [wSpriteFlipped] + and a + jr z, .notFlipped + ld bc, 2*SPRITEBUFFERSIZE + ld hl, sSpriteBuffer1 +.swapLoop + swap [hl] ; if flipped swap nybbles in all bytes + inc hl + dec bc + ld a, b + or c + jr nz, .swapLoop +.notFlipped + pop hl + ld de, sSpriteBuffer1 + ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied + ld a, [hLoadedROMBank] + ld b, a + jp CopyVideoData diff --git a/home/uncompress.asm b/home/uncompress.asm index 02683db7..cfc39f0f 100644 --- a/home/uncompress.asm +++ b/home/uncompress.asm @@ -1,196 +1,591 @@ -; uncompresses the front or back sprite of the specified mon -; assumes the corresponding mon header is already loaded -; hl contains offset to sprite pointer ($b for front or $d for back) -UncompressMonSprite:: - ld bc, wMonHeader - add hl, bc - ld a, [hli] - ld [wSpriteInputPtr], a ; fetch sprite input pointer - ld a, [hl] - ld [wSpriteInputPtr+1], a -; define (by index number) the bank that a pokemon's image is in -; index = Mew, bank 1 -; index = Kabutops fossil, bank $B -; index < $1F, bank 9 -; $1F ≤ index < $4A, bank $A -; $4A ≤ index < $74, bank $B -; $74 ≤ index < $99, bank $C -; $99 ≤ index, bank $D - ld a, [wcf91] ; XXX name for this ram location +; bankswitches and runs _UncompressSpriteData +; bank is given in a, sprite input stream is pointed to in wSpriteInputPtr +UncompressSpriteData:: ld b, a - cp MEW - ld a, BANK(MewPicFront) - jr z, .GotBank - ld a, b - cp FOSSIL_KABUTOPS - ld a, BANK(FossilKabutopsPic) - jr z, .GotBank - ld a, b - cp TANGELA + 1 - ld a, BANK(TangelaPicFront) - jr c, .GotBank - ld a, b - cp MOLTRES + 1 - ld a, BANK(MoltresPicFront) - jr c, .GotBank - ld a, b - cp BEEDRILL + 2 - ld a, BANK(BeedrillPicFront) - jr c, .GotBank + ld a, [hLoadedROMBank] + push af ld a, b - cp STARMIE + 1 - ld a, BANK(StarmiePicFront) - jr c, .GotBank - ld a, BANK(VictreebelPicFront) -.GotBank - jp UncompressSpriteData - -; de: destination location -LoadMonFrontSprite:: - push de - ld hl, wMonHFrontSprite - wMonHeader - call UncompressMonSprite - ld hl, wMonHSpriteDim - ld a, [hli] - ld c, a - pop de - ; fall through + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ld a, SRAM_ENABLE + ld [MBC1SRamEnable], a + xor a + ld [MBC1SRamBank], a + call _UncompressSpriteData + pop af + ld [hLoadedROMBank], a + ld [MBC1RomBank], a + ret -; postprocesses uncompressed sprite chunks to a 2bpp sprite and loads it into video ram -; calculates alignment parameters to place both sprite chunks in the center of the 7*7 tile sprite buffers -; de: destination location -; a,c: sprite dimensions (in tiles of 8x8 each) -LoadUncompressedSpriteData:: - push de - and $f - ld [hSpriteWidth], a ; each byte contains 8 pixels (in 1bpp), so tiles=bytes for width - ld b, a - ld a, $7 - sub b ; 7-w - inc a ; 8-w - srl a ; (8-w)/2 ; horizontal center (in tiles, rounded up) +; initializes necessary data to load a sprite and runs UncompressSpriteDataLoop +_UncompressSpriteData:: + ld hl, sSpriteBuffer1 + ld c, (2*SPRITEBUFFERSIZE) % $100 + ld b, (2*SPRITEBUFFERSIZE) / $100 + xor a + call FillMemory ; clear sprite buffer 1 and 2 + ld a, $1 + ld [wSpriteInputBitCounter], a + ld a, $3 + ld [wSpriteOutputBitOffset], a + xor a + ld [wSpriteCurPosX], a + ld [wSpriteCurPosY], a + ld [wSpriteLoadFlags], a + call ReadNextInputByte ; first byte of input determines sprite width (high nybble) and height (low nybble) in tiles (8x8 pixels) ld b, a + and $f add a add a add a - sub b ; 7*((8-w)/2) ; skip for horizontal center (in tiles) - ld [hSpriteOffset], a - ld a, c + ld [wSpriteHeight], a + ld a, b swap a and $f - ld b, a add a add a - add a ; 8*tiles is height in bytes - ld [hSpriteHeight], a - ld a, $7 - sub b ; 7-h ; skip for vertical center (in tiles, relative to current column) - ld b, a - ld a, [hSpriteOffset] - add b ; 7*((8-w)/2) + 7-h ; combined overall offset (in tiles) - add a add a - add a ; 8*(7*((8-w)/2) + 7-h) ; combined overall offset (in bytes) - ld [hSpriteOffset], a - xor a - ld [$4000], a - ld hl, sSpriteBuffer0 - call ZeroSpriteBuffer ; zero buffer 0 - ld de, sSpriteBuffer1 - ld hl, sSpriteBuffer0 - call AlignSpriteDataCentered ; copy and align buffer 1 to 0 (containing the MSB of the 2bpp sprite) - ld hl, sSpriteBuffer1 - call ZeroSpriteBuffer ; zero buffer 1 - ld de, sSpriteBuffer2 - ld hl, sSpriteBuffer1 - call AlignSpriteDataCentered ; copy and align buffer 2 to 1 (containing the LSB of the 2bpp sprite) - pop de - jp InterlaceMergeSpriteBuffers + ld [wSpriteWidth], a + call ReadNextInputBit + ld [wSpriteLoadFlags], a ; initialite bit1 to 0 and bit0 to the first input bit + ; this will load two chunks of data to sSpriteBuffer1 and sSpriteBuffer2 + ; bit 0 decides in which one the first chunk is placed + ; fall through -; copies and aligns the sprite data properly inside the sprite buffer -; sprite buffers are 7*7 tiles in size, the loaded sprite is centered within this area -AlignSpriteDataCentered:: - ld a, [hSpriteOffset] - ld b, $0 - ld c, a - add hl, bc - ld a, [hSpriteWidth] -.columnLoop - push af - push hl - ld a, [hSpriteHeight] +; uncompresses a chunk from the sprite input data stream (pointed to at wd0da) into sSpriteBuffer1 or sSpriteBuffer2 +; each chunk is a 1bpp sprite. A 2bpp sprite consist of two chunks which are merged afterwards +; note that this is an endless loop which is terminated during a call to MoveToNextBufferPosition by manipulating the stack +UncompressSpriteDataLoop:: + ld hl, sSpriteBuffer1 + ld a, [wSpriteLoadFlags] + bit 0, a + jr z, .useSpriteBuffer1 ; check which buffer to use + ld hl, sSpriteBuffer2 +.useSpriteBuffer1 + call StoreSpriteOutputPointer + ld a, [wSpriteLoadFlags] + bit 1, a + jr z, .startDecompression ; check if last iteration + call ReadNextInputBit ; if last chunk, read 1-2 bit unpacking mode + and a + jr z, .unpackingMode0 ; 0 -> mode 0 + call ReadNextInputBit ; 1 0 -> mode 1 + inc a ; 1 1 -> mode 2 +.unpackingMode0 + ld [wSpriteUnpackMode], a +.startDecompression + call ReadNextInputBit + and a + jr z, .readRLEncodedZeros ; if first bit is 0, the input starts with zeroes, otherwise with (non-zero) input +.readNextInput + call ReadNextInputBit ld c, a -.columnInnerLoop - ld a, [de] - inc de - ld [hli], a + call ReadNextInputBit + sla c + or c ; read next two bits into c + and a + jr z, .readRLEncodedZeros ; 00 -> RLEncoded zeroes following + call WriteSpriteBitsToBuffer ; otherwise write input to output and repeat + call MoveToNextBufferPosition + jr .readNextInput +.readRLEncodedZeros + ld c, $0 ; number of zeroes it length encoded, the number +.countConsecutiveOnesLoop ; of consecutive ones determines the number of bits the number has + call ReadNextInputBit + and a + jr z, .countConsecutiveOnesFinished + inc c + jr .countConsecutiveOnesLoop +.countConsecutiveOnesFinished + ld a, c + add a + ld hl, LengthEncodingOffsetList + add l + ld l, a + jr nc, .noCarry + inc h +.noCarry + ld a, [hli] ; read offset that is added to the number later on + ld e, a ; adding an offset of 2^length - 1 makes every integer uniquely + ld d, [hl] ; representable in the length encoding and saves bits + push de + inc c + ld e, $0 + ld d, e +.readNumberOfZerosLoop ; reads the next c+1 bits of input + call ReadNextInputBit + or e + ld e, a dec c - jr nz, .columnInnerLoop + jr z, .readNumberOfZerosDone + sla e + rl d + jr .readNumberOfZerosLoop +.readNumberOfZerosDone + pop hl ; add the offset + add hl, de + ld e, l + ld d, h +.writeZerosLoop + ld b, e + xor a ; write 00 to buffer + call WriteSpriteBitsToBuffer + ld e, b + call MoveToNextBufferPosition + dec de + ld a, d + and a + jr nz, .continueLoop + ld a, e + and a +.continueLoop + jr nz, .writeZerosLoop + jr .readNextInput + +; moves output pointer to next position +; also cancels the calling function if the all output is done (by removing the return pointer from stack) +; and calls postprocessing functions according to the unpack mode +MoveToNextBufferPosition:: + ld a, [wSpriteHeight] + ld b, a + ld a, [wSpriteCurPosY] + inc a + cp b + jr z, .curColumnDone + ld [wSpriteCurPosY], a + ld a, [wSpriteOutputPtr] + inc a + ld [wSpriteOutputPtr], a + ret nz + ld a, [wSpriteOutputPtr+1] + inc a + ld [wSpriteOutputPtr+1], a + ret +.curColumnDone + xor a + ld [wSpriteCurPosY], a + ld a, [wSpriteOutputBitOffset] + and a + jr z, .bitOffsetsDone + dec a + ld [wSpriteOutputBitOffset], a + ld hl, wSpriteOutputPtrCached + ld a, [hli] + ld [wSpriteOutputPtr], a + ld a, [hl] + ld [wSpriteOutputPtr+1], a + ret +.bitOffsetsDone + ld a, $3 + ld [wSpriteOutputBitOffset], a + ld a, [wSpriteCurPosX] + add $8 + ld [wSpriteCurPosX], a + ld b, a + ld a, [wSpriteWidth] + cp b + jr z, .allColumnsDone + ld a, [wSpriteOutputPtr] + ld l, a + ld a, [wSpriteOutputPtr+1] + ld h, a + inc hl + jp StoreSpriteOutputPointer +.allColumnsDone pop hl - ld bc, 7*8 ; 7 tiles - add hl, bc ; advance one full column - pop af + xor a + ld [wSpriteCurPosX], a + ld a, [wSpriteLoadFlags] + bit 1, a + jr nz, .done ; test if there is one more sprite to go + xor $1 + set 1, a + ld [wSpriteLoadFlags], a + jp UncompressSpriteDataLoop +.done + jp UnpackSprite + +; writes 2 bits (from a) to the output buffer (pointed to from wSpriteOutputPtr) +WriteSpriteBitsToBuffer:: + ld e, a + ld a, [wSpriteOutputBitOffset] + and a + jr z, .offset0 + cp $2 + jr c, .offset1 + jr z, .offset2 + rrc e ; offset 3 + rrc e + jr .offset0 +.offset1 + sla e + sla e + jr .offset0 +.offset2 + swap e +.offset0 + ld a, [wSpriteOutputPtr] + ld l, a + ld a, [wSpriteOutputPtr+1] + ld h, a + ld a, [hl] + or e + ld [hl], a + ret + +; reads next bit from input stream and returns it in a +ReadNextInputBit:: + ld a, [wSpriteInputBitCounter] dec a - jr nz, .columnLoop + jr nz, .curByteHasMoreBitsToRead + call ReadNextInputByte + ld [wSpriteInputCurByte], a + ld a, $8 +.curByteHasMoreBitsToRead + ld [wSpriteInputBitCounter], a + ld a, [wSpriteInputCurByte] + rlca + ld [wSpriteInputCurByte], a + and $1 ret -; fills the sprite buffer (pointed to in hl) with zeros -ZeroSpriteBuffer:: - ld bc, SPRITEBUFFERSIZE -.nextByteLoop - xor a - ld [hli], a - dec bc +; reads next byte from input stream and returns it in a +ReadNextInputByte:: + ld a, [wSpriteInputPtr] + ld l, a + ld a, [wSpriteInputPtr+1] + ld h, a + ld a, [hli] + ld b, a + ld a, l + ld [wSpriteInputPtr], a + ld a, h + ld [wSpriteInputPtr+1], a ld a, b - or c - jr nz, .nextByteLoop ret -; combines the (7*7 tiles, 1bpp) sprite chunks in buffer 0 and 1 into a 2bpp sprite located in buffer 1 through 2 -; in the resulting sprite, the rows of the two source sprites are interlaced -; de: output address -InterlaceMergeSpriteBuffers:: +; the nth item is 2^n - 1 +LengthEncodingOffsetList:: + dw %0000000000000001 + dw %0000000000000011 + dw %0000000000000111 + dw %0000000000001111 + dw %0000000000011111 + dw %0000000000111111 + dw %0000000001111111 + dw %0000000011111111 + dw %0000000111111111 + dw %0000001111111111 + dw %0000011111111111 + dw %0000111111111111 + dw %0001111111111111 + dw %0011111111111111 + dw %0111111111111111 + dw %1111111111111111 + +; unpacks the sprite data depending on the unpack mode +UnpackSprite:: + ld a, [wSpriteUnpackMode] + cp $2 + jp z, UnpackSpriteMode2 + and a + jp nz, XorSpriteChunks + ld hl, sSpriteBuffer1 + call SpriteDifferentialDecode + ld hl, sSpriteBuffer2 + ; fall through + +; decodes differential encoded sprite data +; input bit value 0 preserves the current bit value and input bit value 1 toggles it (starting from initial value 0). +SpriteDifferentialDecode:: xor a - ld [$4000], a - push de - ld hl, sSpriteBuffer2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2 - ld de, sSpriteBuffer1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1 - ld bc, sSpriteBuffer0 + (SPRITEBUFFERSIZE - 1) ; source 1: end of buffer 0 - ld a, SPRITEBUFFERSIZE/2 ; $c4 - ld [hSpriteInterlaceCounter], a -.interlaceLoop - ld a, [de] - dec de - ld [hld], a ; write byte of source 2 - ld a, [bc] - dec bc - ld [hld], a ; write byte of source 1 - ld a, [de] - dec de - ld [hld], a ; write byte of source 2 - ld a, [bc] - dec bc - ld [hld], a ; write byte of source 1 - ld a, [hSpriteInterlaceCounter] - dec a - ld [hSpriteInterlaceCounter], a - jr nz, .interlaceLoop + ld [wSpriteCurPosX], a + ld [wSpriteCurPosY], a + call StoreSpriteOutputPointer ld a, [wSpriteFlipped] and a jr z, .notFlipped - ld bc, 2*SPRITEBUFFERSIZE - ld hl, sSpriteBuffer1 -.swapLoop - swap [hl] ; if flipped swap nybbles in all bytes + ld hl, DecodeNybble0TableFlipped + ld de, DecodeNybble1TableFlipped + jr .storeDecodeTablesPointers +.notFlipped + ld hl, DecodeNybble0Table + ld de, DecodeNybble1Table +.storeDecodeTablesPointers + ld a, l + ld [wSpriteDecodeTable0Ptr], a + ld a, h + ld [wSpriteDecodeTable0Ptr+1], a + ld a, e + ld [wSpriteDecodeTable1Ptr], a + ld a, d + ld [wSpriteDecodeTable1Ptr+1], a + ld e, $0 ; last decoded nybble, initialized to 0 +.decodeNextByteLoop + ld a, [wSpriteOutputPtr] + ld l, a + ld a, [wSpriteOutputPtr+1] + ld h, a + ld a, [hl] + ld b, a + swap a + and $f + call DifferentialDecodeNybble ; decode high nybble + swap a + ld d, a + ld a, b + and $f + call DifferentialDecodeNybble ; decode low nybble + or d + ld b, a + ld a, [wSpriteOutputPtr] + ld l, a + ld a, [wSpriteOutputPtr+1] + ld h, a + ld a, b + ld [hl], a ; write back decoded data + ld a, [wSpriteHeight] + add l ; move on to next column + jr nc, .noCarry + inc h +.noCarry + ld [wSpriteOutputPtr], a + ld a, h + ld [wSpriteOutputPtr+1], a + ld a, [wSpriteCurPosX] + add $8 + ld [wSpriteCurPosX], a + ld b, a + ld a, [wSpriteWidth] + cp b + jr nz, .decodeNextByteLoop ; test if current row is done + xor a + ld e, a + ld [wSpriteCurPosX], a + ld a, [wSpriteCurPosY] ; move on to next row + inc a + ld [wSpriteCurPosY], a + ld b, a + ld a, [wSpriteHeight] + cp b + jr z, .done ; test if all rows finished + ld a, [wSpriteOutputPtrCached] + ld l, a + ld a, [wSpriteOutputPtrCached+1] + ld h, a inc hl - dec bc + call StoreSpriteOutputPointer + jr .decodeNextByteLoop +.done + xor a + ld [wSpriteCurPosY], a + ret + +; decodes the nybble stored in a. Last decoded data is assumed to be in e (needed to determine if initial value is 0 or 1) +DifferentialDecodeNybble:: + srl a ; c=a%2, a/=2 + ld c, $0 + jr nc, .evenNumber + ld c, $1 +.evenNumber + ld l, a + ld a, [wSpriteFlipped] + and a + jr z, .notFlipped ; determine if initial value is 0 or one + bit 3, e ; if flipped, consider MSB of last data + jr .selectLookupTable +.notFlipped + bit 0, e ; else consider LSB +.selectLookupTable + ld e, l + jr nz, .initialValue1 ; load the appropriate table + ld a, [wSpriteDecodeTable0Ptr] + ld l, a + ld a, [wSpriteDecodeTable0Ptr+1] + jr .tableLookup +.initialValue1 + ld a, [wSpriteDecodeTable1Ptr] + ld l, a + ld a, [wSpriteDecodeTable1Ptr+1] +.tableLookup + ld h, a + ld a, e + add l + ld l, a + jr nc, .noCarry + inc h +.noCarry + ld a, [hl] + bit 0, c + jr nz, .selectLowNybble + swap a ; select high nybble +.selectLowNybble + and $f + ld e, a ; update last decoded data + ret + +DecodeNybble0Table:: + dn $0, $1 + dn $3, $2 + dn $7, $6 + dn $4, $5 + dn $f, $e + dn $c, $d + dn $8, $9 + dn $b, $a +DecodeNybble1Table:: + dn $f, $e + dn $c, $d + dn $8, $9 + dn $b, $a + dn $0, $1 + dn $3, $2 + dn $7, $6 + dn $4, $5 +DecodeNybble0TableFlipped:: + dn $0, $8 + dn $c, $4 + dn $e, $6 + dn $2, $a + dn $f, $7 + dn $3, $b + dn $1, $9 + dn $d, $5 +DecodeNybble1TableFlipped:: + dn $f, $7 + dn $3, $b + dn $1, $9 + dn $d, $5 + dn $0, $8 + dn $c, $4 + dn $e, $6 + dn $2, $a + +; combines the two loaded chunks with xor (the chunk loaded second is the destination). The source chunk is differeintial decoded beforehand. +XorSpriteChunks:: + xor a + ld [wSpriteCurPosX], a + ld [wSpriteCurPosY], a + call ResetSpriteBufferPointers + ld a, [wSpriteOutputPtr] ; points to buffer 1 or 2, depending on flags + ld l, a + ld a, [wSpriteOutputPtr+1] + ld h, a + call SpriteDifferentialDecode ; decode buffer 1 or 2, depending on flags + call ResetSpriteBufferPointers + ld a, [wSpriteOutputPtr] ; source buffer, points to buffer 1 or 2, depending on flags + ld l, a + ld a, [wSpriteOutputPtr+1] + ld h, a + ld a, [wSpriteOutputPtrCached] ; destination buffer, points to buffer 2 or 1, depending on flags + ld e, a + ld a, [wSpriteOutputPtrCached+1] + ld d, a +.xorChunksLoop + ld a, [wSpriteFlipped] + and a + jr z, .notFlipped + push de + ld a, [de] + ld b, a + swap a + and $f + call ReverseNybble ; if flipped reverse the nybbles in the destination buffer + swap a + ld c, a ld a, b + and $f + call ReverseNybble or c - jr nz, .swapLoop + pop de + ld [de], a .notFlipped - pop hl - ld de, sSpriteBuffer1 - ld c, (2*SPRITEBUFFERSIZE)/16 ; $31, number of 16 byte chunks to be copied - ld a, [hLoadedROMBank] + ld a, [hli] + ld b, a + ld a, [de] + xor b + ld [de], a + inc de + ld a, [wSpriteCurPosY] + inc a + ld [wSpriteCurPosY], a ; go to next row + ld b, a + ld a, [wSpriteHeight] + cp b + jr nz, .xorChunksLoop ; test if column finished + xor a + ld [wSpriteCurPosY], a + ld a, [wSpriteCurPosX] + add $8 + ld [wSpriteCurPosX], a ; go to next column ld b, a - jp CopyVideoData + ld a, [wSpriteWidth] + cp b + jr nz, .xorChunksLoop ; test if all columns finished + xor a + ld [wSpriteCurPosX], a + ret + +; reverses the bits in the nybble given in register a +ReverseNybble:: + ld de, NybbleReverseTable + add e + ld e, a + jr nc, .noCarry + inc d +.noCarry + ld a, [de] + ret + +; resets sprite buffer pointers to buffer 1 and 2, depending on wSpriteLoadFlags +ResetSpriteBufferPointers:: + ld a, [wSpriteLoadFlags] + bit 0, a + jr nz, .buffer2Selected + ld de, sSpriteBuffer1 + ld hl, sSpriteBuffer2 + jr .storeBufferPointers +.buffer2Selected + ld de, sSpriteBuffer2 + ld hl, sSpriteBuffer1 +.storeBufferPointers + ld a, l + ld [wSpriteOutputPtr], a + ld a, h + ld [wSpriteOutputPtr+1], a + ld a, e + ld [wSpriteOutputPtrCached], a + ld a, d + ld [wSpriteOutputPtrCached+1], a + ret + +; maps each nybble to its reverse +NybbleReverseTable:: + db $0, $8, $4, $c, $2, $a, $6 ,$e, $1, $9, $5, $d, $3, $b, $7 ,$f + +; combines the two loaded chunks with xor (the chunk loaded second is the destination). Both chunks are differeintial decoded beforehand. +UnpackSpriteMode2:: + call ResetSpriteBufferPointers + ld a, [wSpriteFlipped] + push af + xor a + ld [wSpriteFlipped], a ; temporarily clear flipped flag for decoding the destination chunk + ld a, [wSpriteOutputPtrCached] + ld l, a + ld a, [wSpriteOutputPtrCached+1] + ld h, a + call SpriteDifferentialDecode + call ResetSpriteBufferPointers + pop af + ld [wSpriteFlipped], a + jp XorSpriteChunks + +; stores hl into the output pointers +StoreSpriteOutputPointer:: + ld a, l + ld [wSpriteOutputPtr], a + ld [wSpriteOutputPtrCached], a + ld a, h + ld [wSpriteOutputPtr+1], a + ld [wSpriteOutputPtrCached+1], a + ret -- cgit v1.2.3 From e4e0af4d6713161d46cc0a1d580645ca40d6fa81 Mon Sep 17 00:00:00 2001 From: Rangi Date: Sat, 4 Jul 2020 01:00:45 -0400 Subject: Remove remaining raw $xxxx values, and replace "+ -1" with "- 1" (supported by rgbds 0.4.0) --- home/init.asm | 12 ++++++------ home/list_menu.asm | 2 +- home/names2.asm | 2 +- home/overworld.asm | 12 ++++++------ home/pics.asm | 4 ++-- home/predef_text.asm | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) (limited to 'home') diff --git a/home/init.asm b/home/init.asm index 48294fa6..83238bad 100644 --- a/home/init.asm +++ b/home/init.asm @@ -41,8 +41,8 @@ rLCDC_DEFAULT EQU %11100011 ld sp, wStack - ld hl, $c000 ; start of WRAM - ld bc, $2000 ; size of WRAM + ld hl, WRAM0_Begin + ld bc, WRAM1_End - WRAM0_Begin .loop ld [hl], 0 inc hl @@ -53,8 +53,8 @@ rLCDC_DEFAULT EQU %11100011 call ClearVram - ld hl, $ff80 ; start of HRAM - ld bc, $ffff - $ff80 ; size of HRAM + ld hl, HRAM_Begin + ld bc, HRAM_End - HRAM_Begin call FillMemory call ClearSprites @@ -119,8 +119,8 @@ rLCDC_DEFAULT EQU %11100011 jp SetDefaultNamesBeforeTitlescreen ClearVram:: - ld hl, $8000 - ld bc, $2000 + ld hl, VRAM_Begin + ld bc, VRAM_End - VRAM_Begin xor a jp FillMemory diff --git a/home/list_menu.asm b/home/list_menu.asm index 68335ed5..4ce973b2 100644 --- a/home/list_menu.asm +++ b/home/list_menu.asm @@ -454,7 +454,7 @@ PrintListMenuEntries:: ld [wLoadedMonLevel], a .skipCopyingLevel pop hl - ld bc, $001c + ld bc, $1c add hl, bc call PrintLevel pop af diff --git a/home/names2.asm b/home/names2.asm index 178a0780..319febd3 100644 --- a/home/names2.asm +++ b/home/names2.asm @@ -77,7 +77,7 @@ GetName:: ld h, d ld l, e ld de, wcd6d - ld bc, $0014 + ld bc, $14 call CopyData .gotPtr ld a, e diff --git a/home/overworld.asm b/home/overworld.asm index c959beb6..79e4ea97 100644 --- a/home/overworld.asm +++ b/home/overworld.asm @@ -1424,18 +1424,18 @@ LoadCurrentMapView:: dec b jr nz, .rowLoop ld hl, wTileMapBackup - ld bc, $0000 + ld bc, $0 .adjustForYCoordWithinTileBlock ld a, [wYBlockCoord] and a jr z, .adjustForXCoordWithinTileBlock - ld bc, $0030 + ld bc, $30 add hl, bc .adjustForXCoordWithinTileBlock ld a, [wXBlockCoord] and a jr z, .copyToVisibleAreaBuffer - ld bc, $0002 + ld bc, $2 add hl, bc .copyToVisibleAreaBuffer coord de, 0, 0 ; base address for the tiles that are directly transferred to VRAM during V-blank @@ -1739,7 +1739,7 @@ ScheduleSouthRowRedraw:: ld l, a ld a, [wMapViewVRAMPointer + 1] ld h, a - ld bc, $0200 + ld bc, $200 add hl, bc ld a, h and $03 @@ -1835,7 +1835,7 @@ DrawTileBlock:: ld a, [de] ld [hl], a inc de - ld bc, $0015 + ld bc, $15 add hl, bc pop bc dec c @@ -2180,7 +2180,7 @@ LoadMapHeader:: jr nz, .zeroSpriteDataLoop ; initialize all C100-C1FF sprite entries to disabled (other than player's) ld hl, wSpriteStateData1 + $12 - ld de, $0010 + ld de, $10 ld c, $0f .disableSpriteEntriesLoop ld [hl], $ff diff --git a/home/pics.asm b/home/pics.asm index 02683db7..c6d99cbb 100644 --- a/home/pics.asm +++ b/home/pics.asm @@ -93,7 +93,7 @@ LoadUncompressedSpriteData:: add a ; 8*(7*((8-w)/2) + 7-h) ; combined overall offset (in bytes) ld [hSpriteOffset], a xor a - ld [$4000], a + ld [MBC1SRamBank], a ld hl, sSpriteBuffer0 call ZeroSpriteBuffer ; zero buffer 0 ld de, sSpriteBuffer1 @@ -151,7 +151,7 @@ ZeroSpriteBuffer:: ; de: output address InterlaceMergeSpriteBuffers:: xor a - ld [$4000], a + ld [MBC1SRamBank], a push de ld hl, sSpriteBuffer2 + (SPRITEBUFFERSIZE - 1) ; destination: end of buffer 2 ld de, sSpriteBuffer1 + (SPRITEBUFFERSIZE - 1) ; source 2: end of buffer 1 diff --git a/home/predef_text.asm b/home/predef_text.asm index 24001c24..059e23ab 100644 --- a/home/predef_text.asm +++ b/home/predef_text.asm @@ -119,7 +119,7 @@ CloseTextDisplay:: ; loop to make sprites face the directions they originally faced before the dialogue ld hl, wSpriteStateData2 + $19 ld c, $0f - ld de, $0010 + ld de, $10 .restoreSpriteFacingDirectionLoop ld a, [hl] dec h -- cgit v1.2.3