diff options
Diffstat (limited to 'home.asm')
-rw-r--r-- | home.asm | 5173 |
1 files changed, 151 insertions, 5022 deletions
@@ -124,2468 +124,11 @@ Start:: jp Init -ReadJoypad:: -; Poll joypad input. -; Unlike the hardware register, button -; presses are indicated by a set bit. - - ld a, 1 << 5 ; select direction keys - ld c, 0 - - ld [rJOYP], a - rept 6 - ld a, [rJOYP] - endr - cpl - and %1111 - swap a - ld b, a - - ld a, 1 << 4 ; select button keys - ld [rJOYP], a - rept 10 - ld a, [rJOYP] - endr - cpl - and %1111 - or b - - ld [hJoyInput], a - - ld a, 1 << 4 + 1 << 5 ; deselect keys - ld [rJOYP], a - ret - -Joypad:: -; Update the joypad state variables: -; [hJoyReleased] keys released since last time -; [hJoyPressed] keys pressed since last time -; [hJoyHeld] currently pressed keys - homecall _Joypad - ret - +INCLUDE "home/joypad.asm" INCLUDE "data/map_header_pointers.asm" -HandleMidJump:: -; Handle the player jumping down -; a ledge in the overworld. - ld b, BANK(_HandleMidJump) - ld hl, _HandleMidJump - jp Bankswitch - -EnterMap:: -; Load a new map. - ld a, $ff - ld [wJoyIgnore], a - call LoadMapData - callba Func_c335 ; initialize map variables - ld hl, wd72c - bit 0, [hl] - jr z, .doNotCountSteps - ld a, 3 - ld [wd13c], a ; some kind of step counter (counts up to 3 steps?) -.doNotCountSteps - ld hl, wd72e - bit 5, [hl] ; did a battle happen immediately before this? - res 5, [hl] ; unset the "battle just happened" flag - call z, Func_12e7 - call nz, MapEntryAfterBattle - ld hl, wd732 - ld a, [hl] - and 1 << 4 | 1 << 3 - jr z, .didNotFlyOrTeleportIn - res 3, [hl] - callba Func_70510 ; display fly/teleport in graphical effect - call UpdateSprites -.didNotFlyOrTeleportIn - callba CheckForceBikeOrSurf ; handle currents in SF islands and forced bike riding in cycling road - ld hl, wd72d - res 5, [hl] - call UpdateSprites - ld hl, wd126 - set 5, [hl] - set 6, [hl] - xor a - ld [wJoyIgnore], a - -OverworldLoop:: - call DelayFrame -OverworldLoopLessDelay:: - call DelayFrame - call LoadGBPal - ld a,[wd736] - bit 6,a ; jumping down a ledge? - call nz, HandleMidJump - ld a,[wWalkCounter] - and a - jp nz,.moveAhead ; if the player sprite has not yet completed the walking animation - call JoypadOverworld ; get joypad state (which is possibly simulated) - callba SafariZoneCheck - ld a,[wda46] - and a - jp nz,WarpFound2 - ld hl,wd72d - bit 3,[hl] - res 3,[hl] - jp nz,WarpFound2 - ld a,[wd732] - and a,$18 - jp nz,HandleFlyOrTeleportAway - ld a,[W_CUROPPONENT] - and a - jp nz,.newBattle - ld a,[wd730] - bit 7,a ; are we simulating button presses? - jr z,.notSimulating - ld a,[hJoyHeld] - jr .checkIfStartIsPressed -.notSimulating - ld a,[hJoyPressed] -.checkIfStartIsPressed - bit 3,a ; start button - jr z,.startButtonNotPressed -; if START is pressed - xor a - ld [$ff8c],a ; the $2920 ID for the start menu is 0 - jp .displayDialogue -.startButtonNotPressed - bit 0,a ; A button - jp z,.checkIfDownButtonIsPressed -; if A is pressed - ld a,[wd730] - bit 2,a - jp nz,.noDirectionButtonsPressed - call Func_30fd - jr nz,.checkForOpponent - call Func_3eb5 ; check for hidden items, PC's, etc. - ld a,[$ffeb] - and a - jp z,OverworldLoop - call IsSpriteOrSignInFrontOfPlayer ; check for sign or sprite in front of the player - ld a,[$ff8c] ; $2920 ID for NPC/sign text, if any - and a - jp z,OverworldLoop -.displayDialogue - ld a,$35 - call Predef ; check what is in front of the player - call UpdateSprites ; move sprites - ld a,[wFlags_0xcd60] - bit 2,a - jr nz,.checkForOpponent - bit 0,a - jr nz,.checkForOpponent - FuncCoord 8, 9 - ld a,[Coord] - ld [wcf0e],a - call DisplayTextID ; display either the start menu or the NPC/sign text - ld a,[wcc47] - and a - jr z,.checkForOpponent - dec a - ld a,$00 - ld [wcc47],a - jr z,.changeMap - ld a,$52 - call Predef - ld a,[W_CURMAP] - ld [wd71a],a - call Func_62ce - ld a,[W_CURMAP] - call SwitchToMapRomBank ; switch to the ROM bank of the current map - ld hl,W_CURMAPTILESET - set 7,[hl] -.changeMap - jp EnterMap -.checkForOpponent - ld a,[W_CUROPPONENT] - and a - jp nz,.newBattle - jp OverworldLoop -.noDirectionButtonsPressed - ld hl,wFlags_0xcd60 - res 2,[hl] - call UpdateSprites ; move sprites - ld a,$01 - ld [wcc4b],a - ld a,[wd528] ; the direction that was pressed last time - and a - jp z,OverworldLoop -; if a direction was pressed last time - ld [wd529],a ; save the last direction - xor a - ld [wd528],a ; zero the direction - jp OverworldLoop -.checkIfDownButtonIsPressed - ld a,[hJoyHeld] ; current joypad state - bit 7,a ; down button - jr z,.checkIfUpButtonIsPressed - ld a,$01 - ld [wSpriteStateData1 + 3],a - ld a,$04 - jr .handleDirectionButtonPress -.checkIfUpButtonIsPressed - bit 6,a ; up button - jr z,.checkIfLeftButtonIsPressed - ld a,$ff - ld [wSpriteStateData1 + 3],a - ld a,$08 - jr .handleDirectionButtonPress -.checkIfLeftButtonIsPressed - bit 5,a ; left button - jr z,.checkIfRightButtonIsPressed - ld a,$ff - ld [wSpriteStateData1 + 5],a - ld a,$02 - jr .handleDirectionButtonPress -.checkIfRightButtonIsPressed - bit 4,a ; right button - jr z,.noDirectionButtonsPressed - ld a,$01 - ld [wSpriteStateData1 + 5],a -.handleDirectionButtonPress - ld [wd52a],a ; new direction - ld a,[wd730] - bit 7,a ; are we simulating button presses? - jr nz,.noDirectionChange ; ignore direction changes if we are - ld a,[wcc4b] - and a - jr z,.noDirectionChange - ld a,[wd52a] ; new direction - ld b,a - ld a,[wd529] ; old direction - cp b - jr z,.noDirectionChange -; the code below is strange -; it computes whether or not the player did a 180 degree turn, but then overwrites the result -; also, it does a seemingly pointless loop afterwards - swap a ; put old direction in upper half - or b ; put new direction in lower half - cp a,$48 ; change dir from down to up - jr nz,.notDownToUp - ld a,$02 - ld [wd528],a - jr .oddLoop -.notDownToUp - cp a,$84 ; change dir from up to down - jr nz,.notUpToDown - ld a,$01 - ld [wd528],a - jr .oddLoop -.notUpToDown - cp a,$12 ; change dir from right to left - jr nz,.notRightToLeft - ld a,$04 - ld [wd528],a - jr .oddLoop -.notRightToLeft - cp a,$21 ; change dir from left to right - jr nz,.oddLoop - ld a,$08 - ld [wd528],a -.oddLoop - ld hl,wFlags_0xcd60 - set 2,[hl] - ld hl,wcc4b - dec [hl] - jr nz,.oddLoop - ld a,[wd52a] - ld [wd528],a - call NewBattle - jp c,.battleOccurred - jp OverworldLoop -.noDirectionChange - ld a,[wd52a] ; current direction - ld [wd528],a ; save direction - call UpdateSprites ; move sprites - ld a,[wd700] - cp a,$02 ; surfing - jr z,.surfing -; not surfing - call CollisionCheckOnLand - jr nc,.noCollision - push hl - ld hl,wd736 - bit 2,[hl] - pop hl - jp z,OverworldLoop - push hl - call ExtraWarpCheck ; sets carry if there is a potential to warp - pop hl - jp c,CheckWarpsCollision - jp OverworldLoop -.surfing - call CollisionCheckOnWater - jp c,OverworldLoop -.noCollision - ld a,$08 - ld [wWalkCounter],a - jr .moveAhead2 -.moveAhead - ld a,[wd736] - bit 7,a - jr z,.noSpinning - callba LoadSpinnerArrowTiles ; spin while moving -.noSpinning - call UpdateSprites ; move sprites -.moveAhead2 - ld hl,wFlags_0xcd60 - res 2,[hl] - ld a,[wd700] - dec a ; riding a bike? - jr nz,.normalPlayerSpriteAdvancement - ld a,[wd736] - bit 6,a ; jumping a ledge? - jr nz,.normalPlayerSpriteAdvancement - call BikeSpeedup ; if riding a bike and not jumping a ledge -.normalPlayerSpriteAdvancement - call AdvancePlayerSprite - ld a,[wWalkCounter] - and a - jp nz,CheckMapConnections ; it seems like this check will never succeed (the other place where CheckMapConnections is run works) -; walking animation finished - ld a,[wd730] - bit 7,a - jr nz,.doneStepCounting ; if button presses are being simulated, don't count steps -; step counting - ld hl,wd13b ; step counter - dec [hl] - ld a,[wd72c] - bit 0,a - jr z,.doneStepCounting - ld hl,wd13c - dec [hl] - jr nz,.doneStepCounting - ld hl,wd72c - res 0,[hl] -.doneStepCounting - ld a,[wd790] - bit 7,a ; in the safari zone? - jr z,.notSafariZone - callba SafariZoneCheckSteps - ld a,[wda46] - and a - jp nz,WarpFound2 -.notSafariZone - ld a,[W_ISINBATTLE] - and a - jp nz,CheckWarpsNoCollision - ld a,$13 - call Predef ; decrement HP of poisoned pokemon - ld a,[wd12d] - and a - jp nz,HandleBlackOut ; if all pokemon fainted -.newBattle - call NewBattle - ld hl,wd736 - res 2,[hl] - jp nc,CheckWarpsNoCollision ; check for warps if there was no battle -.battleOccurred - ld hl,wd72d - res 6,[hl] - ld hl,W_FLAGS_D733 - res 3,[hl] - ld hl,wd126 - set 5,[hl] - set 6,[hl] - xor a - ld [hJoyHeld],a ; clear joypad state - ld a,[W_CURMAP] - cp a,CINNABAR_GYM - jr nz,.notCinnabarGym - ld hl,wd79b - set 7,[hl] -.notCinnabarGym - ld hl,wd72e - set 5,[hl] - ld a,[W_CURMAP] - cp a,OAKS_LAB - jp z,.noFaintCheck - callab AnyPlayerPokemonAliveCheck ; check if all the player's pokemon fainted - ld a,d - and a - jr z,.allPokemonFainted -.noFaintCheck - ld c,$0a - call DelayFrames - jp EnterMap -.allPokemonFainted - ld a,$ff - ld [W_ISINBATTLE],a - call RunMapScript - jp HandleBlackOut - -; function to determine if there will be a battle and execute it (either a trainer battle or wild battle) -; sets carry if a battle occurred and unsets carry if not -NewBattle:: ; 0683 (0:0683) - ld a,[wd72d] - bit 4,a - jr nz,.noBattle - call Func_30fd - jr nz,.noBattle - ld a,[wd72e] - bit 4,a - jr nz,.noBattle - ld b, BANK(InitBattle) - ld hl, InitBattle - jp Bankswitch ; determines if a battle will occur and runs the battle if so -.noBattle - and a - ret - -; function to make bikes twice as fast as walking -BikeSpeedup:: ; 06a0 (0:06a0) - ld a,[wcc57] - and a - ret nz - ld a,[W_CURMAP] - cp a,ROUTE_17 ; Cycling Road - jr nz,.goFaster - ld a,[hJoyHeld] ; current joypad state - and a,%01110000 ; bit mask for up, left, right buttons - ret nz -.goFaster - jp AdvancePlayerSprite - -; check if the player has stepped onto a warp after having not collided -CheckWarpsNoCollision:: ; 06b4 (0:06b4) - ld a,[wd3ae] ; number of warps - and a - jp z,CheckMapConnections - ld a,[wd3ae] ; number of warps - ld b,$00 - ld c,a - ld a,[W_YCOORD] - ld d,a - ld a,[W_XCOORD] - ld e,a - ld hl,wd3af ; start of warp entries -CheckWarpsNoCollisionLoop:: ; 06cc (0:06cc) - ld a,[hli] ; check if the warp's Y position matches - cp d - jr nz,CheckWarpsNoCollisionRetry1 - ld a,[hli] ; check if the warp's X position matches - cp e - jr nz,CheckWarpsNoCollisionRetry2 -; if a match was found - push hl - push bc - ld hl,wd736 - set 2,[hl] - callba Func_c49d ; check if the player sprite is standing on a "door" tile - pop bc - pop hl - jr c,WarpFound1 ; if it is, go to 0735 - push hl - push bc - call ExtraWarpCheck ; sets carry if the warp is confirmed - pop bc - pop hl - jr nc,CheckWarpsNoCollisionRetry2 -; if the extra check passed - ld a,[W_FLAGS_D733] - bit 2,a - jr nz,WarpFound1 - push de - push bc - call Joypad - pop bc - pop de - ld a,[hJoyHeld] ; current joypad state - and a,%11110000 ; bit mask for directional buttons - jr z,CheckWarpsNoCollisionRetry2 ; if directional buttons aren't being pressed, do not pass through the warp - jr WarpFound1 - -; check if the player has stepped onto a warp after having collided -CheckWarpsCollision:: ; 0706 (0:0706) - ld a,[wd3ae] ; number of warps - ld c,a - ld hl,wd3af ; start of warp entries -.loop - ld a,[hli] ; Y coordinate of warp - ld b,a - ld a,[W_YCOORD] - cp b - jr nz,.retry1 - ld a,[hli] ; X coordinate of warp - ld b,a - ld a,[W_XCOORD] - cp b - jr nz,.retry2 - ld a,[hli] - ld [wd42f],a ; save target warp ID - ld a,[hl] - ld [$ff8b],a ; save target map - jr WarpFound2 -.retry1 - inc hl -.retry2 - inc hl - inc hl - dec c - jr nz,.loop - jp OverworldLoop - -CheckWarpsNoCollisionRetry1:: ; 072f (0:072f) - inc hl -CheckWarpsNoCollisionRetry2:: ; 0730 (0:0730) - inc hl - inc hl - jp ContinueCheckWarpsNoCollisionLoop - -WarpFound1:: ; 0735 (0:0735) - ld a,[hli] - ld [wd42f],a ; save target warp ID - ld a,[hli] - ld [$ff8b],a ; save target map - -WarpFound2:: ; 073c (0:073c) - ld a,[wd3ae] ; number of warps - sub c - ld [wd73b],a ; save ID of used warp - ld a,[W_CURMAP] - ld [wd73c],a - call CheckIfInOutsideMap - jr nz,.indoorMaps -; this is for handling "outside" maps that can't have the 0xFF destination map - ld a,[W_CURMAP] - ld [wLastMap],a - ld a,[W_CURMAPWIDTH] - ld [wd366],a - ld a,[$ff8b] ; destination map number - ld [W_CURMAP],a ; change current map to destination map - cp a,ROCK_TUNNEL_1 - jr nz,.notRockTunnel - ld a,$06 - ld [wd35d],a - call GBFadeIn1 -.notRockTunnel - call PlayMapChangeSound - jr .done -; for maps that can have the 0xFF destination map, which means to return to the outside map; not all these maps are necessarily indoors, though -.indoorMaps - ld a,[$ff8b] ; destination map - cp a,$ff - jr z,.goBackOutside -; if not going back to the previous map - ld [W_CURMAP],a ; current map number - callba Func_70787 ; check if the warp was a Silph Co. teleporter - ld a,[wcd5b] - dec a - jr nz,.notTeleporter -; if it's a Silph Co. teleporter - ld hl,wd732 - set 3,[hl] - call DoFlyOrTeleportAwayGraphics - jr .skipMapChangeSound -.notTeleporter - call PlayMapChangeSound -.skipMapChangeSound - ld hl,wd736 - res 0,[hl] - res 1,[hl] - jr .done -.goBackOutside - ld a,[wLastMap] - ld [W_CURMAP],a - call PlayMapChangeSound - xor a - ld [wd35d],a -.done - ld hl,wd736 - set 0,[hl] - call Func_12da - jp EnterMap - -ContinueCheckWarpsNoCollisionLoop:: ; 07b5 (0:07b5) - inc b ; increment warp number - dec c ; decrement number of warps - jp nz,CheckWarpsNoCollisionLoop - -; if no matching warp was found -CheckMapConnections:: ; 07ba (0:07ba) -.checkWestMap - ld a,[W_XCOORD] - cp a,$ff - jr nz,.checkEastMap - ld a,[W_MAPCONN3PTR] - ld [W_CURMAP],a - ld a,[wd38f] ; new X coordinate upon entering west map - ld [W_XCOORD],a - ld a,[W_YCOORD] - ld c,a - ld a,[wd38e] ; Y adjustment upon entering west map - add c - ld c,a - ld [W_YCOORD],a - ld a,[wd390] ; pointer to upper left corner of map without adjustment for Y position - ld l,a - ld a,[wd391] - ld h,a - srl c - jr z,.savePointer1 -.pointerAdjustmentLoop1 - ld a,[wd38d] ; width of connected map - add a,$06 - ld e,a - ld d,$00 - ld b,$00 - add hl,de - dec c - jr nz,.pointerAdjustmentLoop1 -.savePointer1 - ld a,l - ld [wd35f],a ; pointer to upper left corner of current tile block map section - ld a,h - ld [wd360],a - jp .loadNewMap -.checkEastMap - ld b,a - ld a,[wd525] ; map width - cp b - jr nz,.checkNorthMap - ld a,[W_MAPCONN4PTR] - ld [W_CURMAP],a - ld a,[wd39a] ; new X coordinate upon entering east map - ld [W_XCOORD],a - ld a,[W_YCOORD] - ld c,a - ld a,[wd399] ; Y adjustment upon entering east map - add c - ld c,a - ld [W_YCOORD],a - ld a,[wd39b] ; pointer to upper left corner of map without adjustment for Y position - ld l,a - ld a,[wd39c] - ld h,a - srl c - jr z,.savePointer2 -.pointerAdjustmentLoop2 - ld a,[wd398] - add a,$06 - ld e,a - ld d,$00 - ld b,$00 - add hl,de - dec c - jr nz,.pointerAdjustmentLoop2 -.savePointer2 - ld a,l - ld [wd35f],a ; pointer to upper left corner of current tile block map section - ld a,h - ld [wd360],a - jp .loadNewMap -.checkNorthMap - ld a,[W_YCOORD] - cp a,$ff - jr nz,.checkSouthMap - ld a,[W_MAPCONN1PTR] - ld [W_CURMAP],a - ld a,[wd378] ; new Y coordinate upon entering north map - ld [W_YCOORD],a - ld a,[W_XCOORD] - ld c,a - ld a,[wd379] ; X adjustment upon entering north map - add c - ld c,a - ld [W_XCOORD],a - ld a,[wd37a] ; pointer to upper left corner of map without adjustment for X position - ld l,a - ld a,[wd37b] - ld h,a - ld b,$00 - srl c - add hl,bc - ld a,l - ld [wd35f],a ; pointer to upper left corner of current tile block map section - ld a,h - ld [wd360],a - jp .loadNewMap -.checkSouthMap - ld b,a - ld a,[wd524] - cp b - jr nz,.didNotEnterConnectedMap - ld a,[W_MAPCONN2PTR] - ld [W_CURMAP],a - ld a,[wd383] ; new Y coordinate upon entering south map - ld [W_YCOORD],a - ld a,[W_XCOORD] - ld c,a - ld a,[wd384] ; X adjustment upon entering south map - add c - ld c,a - ld [W_XCOORD],a - ld a,[wd385] ; pointer to upper left corner of map without adjustment for X position - ld l,a - ld a,[wd386] - ld h,a - ld b,$00 - srl c - add hl,bc - ld a,l - ld [wd35f],a ; pointer to upper left corner of current tile block map section - ld a,h - ld [wd360],a -.loadNewMap ; load the connected map that was entered - call LoadMapHeader - call Func_2312 ; music - ld b,$09 - call GoPAL_SET -; Since the sprite set shouldn't change, this will just update VRAM slots at -; $C2XE without loading any tile patterns. - callba InitMapSprites - call LoadTileBlockMap - jp OverworldLoopLessDelay -.didNotEnterConnectedMap - jp OverworldLoop - -; function to play a sound when changing maps -PlayMapChangeSound:: ; 08c9 (0:08c9) - FuncCoord 8, 8 - ld a,[Coord] ; upper left tile of the 4x4 square the player's sprite is standing on - cp a,$0b ; door tile in tileset 0 - jr nz,.didNotGoThroughDoor - ld a,(SFX_02_57 - SFX_Headers_02) / 3 - jr .playSound -.didNotGoThroughDoor - ld a,(SFX_02_5c - SFX_Headers_02) / 3 -.playSound - call PlaySound - ld a,[wd35d] - and a - ret nz - jp GBFadeIn1 - -CheckIfInOutsideMap:: ; 08e1 (0:08e1) -; If the player is in an outside map (a town or route), set the z flag - ld a, [W_CURMAPTILESET] - and a ; most towns/routes have tileset 0 (OVERWORLD) - ret z - cp PLATEAU ; Route 23 / Indigo Plateau - ret - -; this function is an extra check that sometimes has to pass in order to warp, beyond just standing on a warp -; the "sometimes" qualification is necessary because of CheckWarpsNoCollision's behavior -; depending on the map, either "function 1" or "function 2" is used for the check -; "function 1" passes when the player is at the edge of the map and is facing towards the outside of the map -; "function 2" passes when the the tile in front of the player is among a certain set -; sets carry if the check passes, otherwise clears carry -ExtraWarpCheck:: ; 08e9 (0:08e9) - ld a, [W_CURMAP] - cp SS_ANNE_3 - jr z, .useFunction1 - cp ROCKET_HIDEOUT_1 - jr z, .useFunction2 - cp ROCKET_HIDEOUT_2 - jr z, .useFunction2 - cp ROCKET_HIDEOUT_4 - jr z, .useFunction2 - cp ROCK_TUNNEL_1 - jr z, .useFunction2 - ld a, [W_CURMAPTILESET] - and a ; outside tileset (OVERWORLD) - jr z, .useFunction2 - cp SHIP ; S.S. Anne tileset - jr z, .useFunction2 - cp SHIP_PORT ; Vermilion Port tileset - jr z, .useFunction2 - cp PLATEAU ; Indigo Plateau tileset - jr z, .useFunction2 -.useFunction1 - ld hl, Func_c3ff - jr .doBankswitch -.useFunction2 - ld hl, Func_c44e -.doBankswitch - ld b, BANK(Func_c44e) - jp Bankswitch - -MapEntryAfterBattle:: ; 091f (0:091f) - callba Func_c35f ; function that appears to disable warp testing after collisions if the player is standing on a warp - ld a,[wd35d] - and a - jp z,GBFadeIn2 - jp LoadGBPal - -HandleBlackOut:: -; For when all the player's pokemon faint. -; Does not print the "blacked out" message. - - call GBFadeIn1 - ld a, $08 - call StopMusic - ld hl, wd72e - res 5, [hl] - ld a, Bank(Func_40b0) ; also Bank(Func_62ce) and Bank(Func_5d5f) - ld [H_LOADEDROMBANK], a - ld [MBC3RomBank], a - call Func_40b0 - call Func_62ce - call Func_2312 - jp Func_5d5f - -StopMusic:: - ld [wMusicHeaderPointer], a - ld a, $ff - ld [wc0ee], a - call PlaySound -.wait - ld a, [wMusicHeaderPointer] - and a - jr nz, .wait - jp StopAllSounds - -HandleFlyOrTeleportAway:: - call UpdateSprites - call Delay3 - xor a - ld [wcf0b], a - ld [wd700], a - ld [W_ISINBATTLE], a - ld [wd35d], a - ld hl, wd732 - set 2, [hl] - res 5, [hl] - call DoFlyOrTeleportAwayGraphics - ld a, Bank(Func_62ce) - ld [H_LOADEDROMBANK], a - ld [$2000], a - call Func_62ce - jp Func_5d5f - -DoFlyOrTeleportAwayGraphics:: - ld b, BANK(_DoFlyOrTeleportAwayGraphics) - ld hl, _DoFlyOrTeleportAwayGraphics - jp Bankswitch - -LoadPlayerSpriteGraphics:: -; Load sprite graphics based on whether the player is standing, biking, or surfing. - - ; 0: standing - ; 1: biking - ; 2: surfing - - ld a, [wd700] - dec a - jr z, .ridingBike - - ld a, [$ffd7] - and a - jr nz, .determineGraphics - jr .startWalking - -.ridingBike - ; If the bike can't be used, - ; start walking instead. - call IsBikeRidingAllowed - jr c, .determineGraphics - -.startWalking - xor a - ld [wd700], a - ld [wd11a], a - jp LoadWalkingPlayerSpriteGraphics - -.determineGraphics - ld a, [wd700] - and a - jp z, LoadWalkingPlayerSpriteGraphics - dec a - jp z, LoadBikePlayerSpriteGraphics - dec a - jp z, LoadSurfingPlayerSpriteGraphics - jp LoadWalkingPlayerSpriteGraphics - -IsBikeRidingAllowed:: -; The bike can be used on Route 23 and Indigo Plateau, -; or maps with tilesets in BikeRidingTilesets. -; Return carry if biking is allowed. - - ld a, [W_CURMAP] - cp ROUTE_23 - jr z, .allowed - cp INDIGO_PLATEAU - jr z, .allowed - - ld a, [W_CURMAPTILESET] - ld b, a - ld hl, BikeRidingTilesets -.loop - ld a, [hli] - cp b - jr z, .allowed - inc a - jr nz, .loop - and a - ret - -.allowed - scf - ret - -INCLUDE "data/bike_riding_tilesets.asm" - -; load the tile pattern data of the current tileset into VRAM -LoadTilesetTilePatternData:: ; 09e8 (0:09e8) - ld a,[W_TILESETGFXPTR] - ld l,a - ld a,[W_TILESETGFXPTR + 1] - ld h,a - ld de,vTileset - ld bc,$600 - ld a,[W_TILESETBANK] - jp FarCopyData2 - -; this loads the current maps complete tile map (which references blocks, not individual tiles) to C6E8 -; it can also load partial tile maps of connected maps into a border of length 3 around the current map -LoadTileBlockMap:: ; 09fc (0:09fc) -; fill C6E8-CBFB with the background tile - ld hl,wOverworldMap - ld a,[wd3ad] ; background tile number - ld d,a - ld bc,$0514 -.backgroundTileLoop - ld a,d - ld [hli],a - dec bc - ld a,c - or b - jr nz,.backgroundTileLoop -; load tile map of current map (made of tile block IDs) -; a 3-byte border at the edges of the map is kept so that there is space for map connections - ld hl,wOverworldMap - ld a,[W_CURMAPWIDTH] - ld [$ff8c],a - add a,$06 ; border (east and west) - ld [$ff8b],a ; map width + border - ld b,$00 - ld c,a -; make space for north border (next 3 lines) - add hl,bc - add hl,bc - add hl,bc - ld c,$03 - add hl,bc ; this puts us past the (west) border - ld a,[W_MAPDATAPTR] ; tile map pointer - ld e,a - ld a,[W_MAPDATAPTR + 1] - ld d,a ; de = tile map pointer - ld a,[W_CURMAPHEIGHT] - ld b,a -.rowLoop ; copy one row each iteration - push hl - ld a,[$ff8c] ; map width (without border) - ld c,a -.rowInnerLoop - ld a,[de] - inc de - ld [hli],a - dec c - jr nz,.rowInnerLoop -; add the map width plus the border to the base address of the current row to get the next row's address - pop hl - ld a,[$ff8b] ; map width + border - add l - ld l,a - jr nc,.noCarry - inc h -.noCarry - dec b - jr nz,.rowLoop -.northConnection - ld a,[W_MAPCONN1PTR] - cp a,$ff - jr z,.southConnection - call SwitchToMapRomBank - ld a,[wd372] - ld l,a - ld a,[wd373] - ld h,a - ld a,[wd374] - ld e,a - ld a,[wd375] - ld d,a - ld a,[wd376] - ld [$ff8b],a - ld a,[wd377] - ld [$ff8c],a - call LoadNorthSouthConnectionsTileMap -.southConnection - ld a,[W_MAPCONN2PTR] - cp a,$ff - jr z,.westConnection - call SwitchToMapRomBank - ld a,[wd37d] - ld l,a - ld a,[wd37e] - ld h,a - ld a,[wd37f] - ld e,a - ld a,[wd380] - ld d,a - ld a,[wd381] - ld [$ff8b],a - ld a,[wd382] - ld [$ff8c],a - call LoadNorthSouthConnectionsTileMap -.westConnection - ld a,[W_MAPCONN3PTR] - cp a,$ff - jr z,.eastConnection - call SwitchToMapRomBank - ld a,[wd388] - ld l,a - ld a,[wd389] - ld h,a - ld a,[wd38a] - ld e,a - ld a,[wd38b] - ld d,a - ld a,[wd38c] - ld b,a - ld a,[wd38d] - ld [$ff8b],a - call LoadEastWestConnectionsTileMap -.eastConnection - ld a,[W_MAPCONN4PTR] - cp a,$ff - jr z,.done - call SwitchToMapRomBank - ld a,[wd393] - ld l,a - ld a,[wd394] - ld h,a - ld a,[wd395] - ld e,a - ld a,[wd396] - ld d,a - ld a,[wd397] - ld b,a - ld a,[wd398] - ld [$ff8b],a - call LoadEastWestConnectionsTileMap -.done - ret - -LoadNorthSouthConnectionsTileMap:: ; 0ade (0:0ade) - ld c,$03 -.loop - push de - push hl - ld a,[$ff8b] ; width of connection - ld b,a -.innerLoop - ld a,[hli] - ld [de],a - inc de - dec b - jr nz,.innerLoop - pop hl - pop de - ld a,[$ff8c] ; width of connected map - add l - ld l,a - jr nc,.noCarry1 - inc h -.noCarry1 - ld a,[W_CURMAPWIDTH] - add a,$06 - add e - ld e,a - jr nc,.noCarry2 - inc d -.noCarry2 - dec c - jr nz,.loop - ret - -LoadEastWestConnectionsTileMap:: ; 0b02 (0:0b02) - push hl - push de - ld c,$03 -.innerLoop - ld a,[hli] - ld [de],a - inc de - dec c - jr nz,.innerLoop - pop de - pop hl - ld a,[$ff8b] ; width of connected map - add l - ld l,a - jr nc,.noCarry1 - inc h -.noCarry1 - ld a,[W_CURMAPWIDTH] - add a,$06 - add e - ld e,a - jr nc,.noCarry2 - inc d -.noCarry2 - dec b - jr nz,LoadEastWestConnectionsTileMap - ret - -; function to check if there is a sign or sprite in front of the player -; if so, it is stored in [$FF8C] -; if not, [$FF8C] is set to 0 -IsSpriteOrSignInFrontOfPlayer:: ; 0b23 (0:0b23) - xor a - ld [$ff8c],a - ld a,[wd4b0] ; number of signs in the map - and a - jr z,.extendRangeOverCounter -; if there are signs - ld a,$35 - call Predef ; get the coordinates in front of the player in de - ld hl,wd4b1 ; start of sign coordinates - ld a,[wd4b0] ; number of signs in the map - ld b,a - ld c,$00 -.signLoop - inc c - ld a,[hli] ; sign Y - cp d - jr z,.yCoordMatched - inc hl - jr .retry -.yCoordMatched - ld a,[hli] ; sign X - cp e - jr nz,.retry -.xCoordMatched -; found sign - push hl - push bc - ld hl,wd4d1 ; start of sign text ID's - ld b,$00 - dec c - add hl,bc - ld a,[hl] - ld [$ff8c],a ; store sign text ID - pop bc - pop hl - ret -.retry - dec b - jr nz,.signLoop -; check if the player is front of a counter in a pokemon center, pokemart, etc. and if so, extend the range at which he can talk to the NPC -.extendRangeOverCounter - ld a,$35 - call Predef ; get the tile in front of the player in c - ld hl,W_TILESETTALKINGOVERTILES ; list of tiles that extend talking range (counter tiles) - ld b,$03 - ld d,$20 ; talking range in pixels (long range) -.counterTilesLoop - ld a,[hli] - cp c - jr z,IsSpriteInFrontOfPlayer2 ; jumps if the tile in front of the player is a counter tile - dec b - jr nz,.counterTilesLoop - -; part of the above function, but sometimes its called on its own, when signs are irrelevant -; the caller must zero [$FF8C] -IsSpriteInFrontOfPlayer:: ; 0b6b (0:0b6b) - ld d,$10 ; talking range in pixels (normal range) -IsSpriteInFrontOfPlayer2:: ; 0b6d (0:0b6d) - ld bc,$3c40 ; Y and X position of player sprite - ld a,[wSpriteStateData1 + 9] ; direction the player is facing -.checkIfPlayerFacingUp - cp a,$04 - jr nz,.checkIfPlayerFacingDown -; facing up - ld a,b - sub d - ld b,a - ld a,$08 - jr .doneCheckingDirection -.checkIfPlayerFacingDown - cp a,$00 - jr nz,.checkIfPlayerFacingRight -; facing down - ld a,b - add d - ld b,a - ld a,$04 - jr .doneCheckingDirection -.checkIfPlayerFacingRight - cp a,$0c - jr nz,.playerFacingLeft -; facing right - ld a,c - add d - ld c,a - ld a,$01 - jr .doneCheckingDirection -.playerFacingLeft -; facing left - ld a,c - sub d - ld c,a - ld a,$02 -.doneCheckingDirection - ld [wd52a],a - ld a,[W_NUMSPRITES] ; number of sprites - and a - ret z -; if there are sprites - ld hl,wSpriteStateData1 + $10 - ld d,a - ld e,$01 -.spriteLoop - push hl - ld a,[hli] ; image (0 if no sprite) - and a - jr z,.nextSprite - inc l - ld a,[hli] ; sprite visibility - inc a - jr z,.nextSprite - inc l - ld a,[hli] ; Y location - cp b - jr nz,.nextSprite - inc l - ld a,[hl] ; X location - cp c - jr z,.foundSpriteInFrontOfPlayer -.nextSprite - pop hl - ld a,l - add a,$10 - ld l,a - inc e - dec d - jr nz,.spriteLoop - ret -.foundSpriteInFrontOfPlayer - pop hl - ld a,l - and a,$f0 - inc a - ld l,a - set 7,[hl] - ld a,e - ld [$ff8c],a ; store sprite ID - ret - -; function to check if the player will jump down a ledge and check if the tile ahead is passable (when not surfing) -; sets the carry flag if there is a collision, and unsets it if there isn't a collision -CollisionCheckOnLand:: ; 0bd1 (0:0bd1) - ld a,[wd736] - bit 6,a ; is the player jumping? - jr nz,.noCollision -; if not jumping a ledge - ld a,[wcd38] - and a - jr nz,.noCollision - ld a,[wd52a] ; the direction that the player is trying to go in - ld d,a - ld a,[wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code) - and d ; check if a sprite is in the direction the player is trying to go - jr nz,.collision - xor a - ld [$ff8c],a - call IsSpriteInFrontOfPlayer ; check for sprite collisions again? when does the above check fail to detect a sprite collision? - ld a,[$ff8c] - and a ; was there a sprite collision? - jr nz,.collision -; if no sprite collision - ld hl,TilePairCollisionsLand - call CheckForJumpingAndTilePairCollisions - jr c,.collision - call CheckTilePassable - jr nc,.noCollision -.collision - ld a,[wc02a] - cp a,(SFX_02_5b - SFX_Headers_02) / 3 ; check if collision sound is already playing - jr z,.setCarry - ld a,(SFX_02_5b - SFX_Headers_02) / 3 - call PlaySound ; play collision sound (if it's not already playing) -.setCarry - scf - ret -.noCollision - and a - ret - -; function that checks if the tile in front of the player is passable -; clears carry if it is, sets carry if not -CheckTilePassable:: ; 0c10 (0:0c10) - ld a,$35 - call Predef ; get tile in front of player - ld a,[wcfc6] ; tile in front of player - ld c,a - ld hl,W_TILESETCOLLISIONPTR ; pointer to list of passable tiles - ld a,[hli] - ld h,[hl] - ld l,a ; hl now points to passable tiles -.loop - ld a,[hli] - cp a,$ff - jr z,.tileNotPassable - cp c - ret z - jr .loop -.tileNotPassable - scf - ret - -; check if the player is going to jump down a small ledge -; and check for collisions that only occur between certain pairs of tiles -; Input: hl - address of directional collision data -; sets carry if there is a collision and unsets carry if not -CheckForJumpingAndTilePairCollisions:: ; 0c2a (0:0c2a) - push hl - ld a,$35 - call Predef ; get the tile in front of the player - push de - push bc - callba HandleLedges ; check if the player is trying to jump a ledge - pop bc - pop de - pop hl - and a - ld a,[wd736] - bit 6,a ; is the player jumping? - ret nz -; if not jumping - -Func_c44:: ; 0c44 (0:0c44) - FuncCoord 8, 9 - ld a,[Coord] ; tile the player is on - ld [wcf0e],a - -CheckForTilePairCollisions:: ; 0c4a (0:0c4a) - ld a,[wcfc6] ; tile in front of the player - ld c,a -.tilePairCollisionLoop - ld a,[W_CURMAPTILESET] ; tileset number - ld b,a - ld a,[hli] - cp a,$ff - jr z,.noMatch - cp b - jr z,.tilesetMatches - inc hl -.retry - inc hl - jr .tilePairCollisionLoop -.tilesetMatches - ld a,[wcf0e] ; tile the player is on - ld b,a - ld a,[hl] - cp b - jr z,.currentTileMatchesFirstInPair - inc hl - ld a,[hl] - cp b - jr z,.currentTileMatchesSecondInPair - jr .retry -.currentTileMatchesFirstInPair - inc hl - ld a,[hl] - cp c - jr z,.foundMatch - jr .tilePairCollisionLoop -.currentTileMatchesSecondInPair - dec hl - ld a,[hli] - cp c - inc hl - jr nz,.tilePairCollisionLoop -.foundMatch - scf - ret -.noMatch - and a - ret - -; FORMAT: tileset number, tile 1, tile 2 -; terminated by 0xFF -; these entries indicate that the player may not cross between tile 1 and tile 2 -; it's mainly used to simulate differences in elevation - -TilePairCollisionsLand:: ; 0c7e (0:0c7e) - db CAVERN, $20, $05 - db CAVERN, $41, $05 - db FOREST, $30, $2E - db CAVERN, $2A, $05 - db CAVERN, $05, $21 - db FOREST, $52, $2E - db FOREST, $55, $2E - db FOREST, $56, $2E - db FOREST, $20, $2E - db FOREST, $5E, $2E - db FOREST, $5F, $2E - db $FF - -TilePairCollisionsWater:: ; 0ca0 (0:0ca0) - db FOREST, $14, $2E - db FOREST, $48, $2E - db CAVERN, $14, $05 - db $FF - -; this builds a tile map from the tile block map based on the current X/Y coordinates of the player's character -LoadCurrentMapView:: ; 0caa (0:0caa) - ld a,[H_LOADEDROMBANK] - push af - ld a,[W_TILESETBANK] ; tile data ROM bank - ld [H_LOADEDROMBANK],a - ld [$2000],a ; switch to ROM bank that contains tile data - ld a,[wd35f] ; address of upper left corner of current map view - ld e,a - ld a,[wd360] - ld d,a - ld hl,wTileMapBackup - ld b,$05 -.rowLoop ; each loop iteration fills in one row of tile blocks - push hl - push de - ld c,$06 -.rowInnerLoop ; loop to draw each tile block of the current row - push bc - push de - push hl - ld a,[de] - ld c,a ; tile block number - call DrawTileBlock - pop hl - pop de - pop bc - inc hl - inc hl - inc hl - inc hl - inc de - dec c - jr nz,.rowInnerLoop -; update tile block map pointer to next row's address - pop de - ld a,[W_CURMAPWIDTH] - add a,$06 - add e - ld e,a - jr nc,.noCarry - inc d -.noCarry -; update tile map pointer to next row's address - pop hl - ld a,$60 - add l - ld l,a - jr nc,.noCarry2 - inc h -.noCarry2 - dec b - jr nz,.rowLoop - ld hl,wTileMapBackup - ld bc,$0000 -.adjustForYCoordWithinTileBlock - ld a,[W_YBLOCKCOORD] - and a - jr z,.adjustForXCoordWithinTileBlock - ld bc,$0030 - add hl,bc -.adjustForXCoordWithinTileBlock - ld a,[W_XBLOCKCOORD] - and a - jr z,.copyToVisibleAreaBuffer - ld bc,$0002 - add hl,bc -.copyToVisibleAreaBuffer - ld de,wTileMap ; base address for the tiles that are directly transfered to VRAM during V-blank - ld b,$12 -.rowLoop2 - ld c,$14 -.rowInnerLoop2 - ld a,[hli] - ld [de],a - inc de - dec c - jr nz,.rowInnerLoop2 - ld a,$04 - add l - ld l,a - jr nc,.noCarry3 - inc h -.noCarry3 - dec b - jr nz,.rowLoop2 - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a ; restore previous ROM bank - ret - -AdvancePlayerSprite:: ; 0d27 (0:0d27) - ld a,[wSpriteStateData1 + 3] ; delta Y - ld b,a - ld a,[wSpriteStateData1 + 5] ; delta X - ld c,a - ld hl,wWalkCounter ; walking animation counter - dec [hl] - jr nz,.afterUpdateMapCoords -; if it's the end of the animation, update the player's map coordinates - ld a,[W_YCOORD] - add b - ld [W_YCOORD],a - ld a,[W_XCOORD] - add c - ld [W_XCOORD],a -.afterUpdateMapCoords - ld a,[wWalkCounter] ; walking animation counter - cp a,$07 - jp nz,.scrollBackgroundAndSprites -; if this is the first iteration of the animation - ld a,c - cp a,$01 - jr nz,.checkIfMovingWest -; moving east - ld a,[wd526] - ld e,a - and a,$e0 - ld d,a - ld a,e - add a,$02 - and a,$1f - or d - ld [wd526],a - jr .adjustXCoordWithinBlock -.checkIfMovingWest - cp a,$ff - jr nz,.checkIfMovingSouth -; moving west - ld a,[wd526] - ld e,a - and a,$e0 - ld d,a - ld a,e - sub a,$02 - and a,$1f - or d - ld [wd526],a - jr .adjustXCoordWithinBlock -.checkIfMovingSouth - ld a,b - cp a,$01 - jr nz,.checkIfMovingNorth -; moving south - ld a,[wd526] - add a,$40 - ld [wd526],a - jr nc,.adjustXCoordWithinBlock - ld a,[wd527] - inc a - and a,$03 - or a,$98 - ld [wd527],a - jr .adjustXCoordWithinBlock -.checkIfMovingNorth - cp a,$ff - jr nz,.adjustXCoordWithinBlock -; moving north - ld a,[wd526] - sub a,$40 - ld [wd526],a - jr nc,.adjustXCoordWithinBlock - ld a,[wd527] - dec a - and a,$03 - or a,$98 - ld [wd527],a -.adjustXCoordWithinBlock - ld a,c - and a - jr z,.pointlessJump ; mistake? -.pointlessJump - ld hl,W_XBLOCKCOORD - ld a,[hl] - add c - ld [hl],a - cp a,$02 - jr nz,.checkForMoveToWestBlock -; moved into the tile block to the east - xor a - ld [hl],a - ld hl,wd4e3 - inc [hl] - ld de,wd35f - call MoveTileBlockMapPointerEast - jr .updateMapView -.checkForMoveToWestBlock - cp a,$ff - jr nz,.adjustYCoordWithinBlock -; moved into the tile block to the west - ld a,$01 - ld [hl],a - ld hl,wd4e3 - dec [hl] - ld de,wd35f - call MoveTileBlockMapPointerWest - jr .updateMapView -.adjustYCoordWithinBlock - ld hl,W_YBLOCKCOORD - ld a,[hl] - add b - ld [hl],a - cp a,$02 - jr nz,.checkForMoveToNorthBlock -; moved into the tile block to the south - xor a - ld [hl],a - ld hl,wd4e2 - inc [hl] - ld de,wd35f - ld a,[W_CURMAPWIDTH] - call MoveTileBlockMapPointerSouth - jr .updateMapView -.checkForMoveToNorthBlock - cp a,$ff - jr nz,.updateMapView -; moved into the tile block to the north - ld a,$01 - ld [hl],a - ld hl,wd4e2 - dec [hl] - ld de,wd35f - ld a,[W_CURMAPWIDTH] - call MoveTileBlockMapPointerNorth -.updateMapView - call LoadCurrentMapView - ld a,[wSpriteStateData1 + 3] ; delta Y - cp a,$01 - jr nz,.checkIfMovingNorth2 -; if moving south - call ScheduleSouthRowRedraw - jr .scrollBackgroundAndSprites -.checkIfMovingNorth2 - cp a,$ff - jr nz,.checkIfMovingEast2 -; if moving north - call ScheduleNorthRowRedraw - jr .scrollBackgroundAndSprites -.checkIfMovingEast2 - ld a,[wSpriteStateData1 + 5] ; delta X - cp a,$01 - jr nz,.checkIfMovingWest2 -; if moving east - call ScheduleEastColumnRedraw - jr .scrollBackgroundAndSprites -.checkIfMovingWest2 - cp a,$ff - jr nz,.scrollBackgroundAndSprites -; if moving west - call ScheduleWestColumnRedraw -.scrollBackgroundAndSprites - ld a,[wSpriteStateData1 + 3] ; delta Y - ld b,a - ld a,[wSpriteStateData1 + 5] ; delta X - ld c,a - sla b - sla c - ld a,[$ffaf] - add b - ld [$ffaf],a ; update background scroll Y - ld a,[$ffae] - add c - ld [$ffae],a ; update background scroll X -; shift all the sprites in the direction opposite of the player's motion -; so that the player appears to move relative to them - ld hl,wSpriteStateData1 + $14 - ld a,[W_NUMSPRITES] ; number of sprites - and a ; are there any sprites? - jr z,.done - ld e,a -.spriteShiftLoop - ld a,[hl] - sub b - ld [hli],a - inc l - ld a,[hl] - sub c - ld [hl],a - ld a,$0e - add l - ld l,a - dec e - jr nz,.spriteShiftLoop -.done - ret - -; the following four functions are used to move the pointer to the upper left -; corner of the tile block map in the direction of motion - -MoveTileBlockMapPointerEast:: ; 0e65 (0:0e65) - ld a,[de] - add a,$01 - ld [de],a - ret nc - inc de - ld a,[de] - inc a - ld [de],a - ret - -MoveTileBlockMapPointerWest:: ; 0e6f (0:0e6f) - ld a,[de] - sub a,$01 - ld [de],a - ret nc - inc de - ld a,[de] - dec a - ld [de],a - ret - -MoveTileBlockMapPointerSouth:: ; 0e79 (0:0e79) - add a,$06 - ld b,a - ld a,[de] - add b - ld [de],a - ret nc - inc de - ld a,[de] - inc a - ld [de],a - ret - -MoveTileBlockMapPointerNorth:: ; 0e85 (0:0e85) - add a,$06 - ld b,a - ld a,[de] - sub b - ld [de],a - ret nc - inc de - ld a,[de] - dec a - ld [de],a - ret - -; the following 6 functions are used to tell the V-blank handler to redraw -; the portion of the map that was newly exposed due to the player's movement - -ScheduleNorthRowRedraw:: ; 0e91 (0:0e91) - FuncCoord 0, 0 - ld hl,Coord - call ScheduleRowRedrawHelper - ld a,[wd526] - ld [H_SCREENEDGEREDRAWADDR],a - ld a,[wd527] - ld [H_SCREENEDGEREDRAWADDR + 1],a - ld a,REDRAWROW - ld [H_SCREENEDGEREDRAW],a - ret - -ScheduleRowRedrawHelper:: ; 0ea6 (0:0ea6) - ld de,wScreenEdgeTiles - ld c,$28 -.loop - ld a,[hli] - ld [de],a - inc de - dec c - jr nz,.loop - ret - -ScheduleSouthRowRedraw:: ; 0eb2 (0:0eb2) - FuncCoord 0,16 - ld hl,Coord - call ScheduleRowRedrawHelper - ld a,[wd526] - ld l,a - ld a,[wd527] - ld h,a - ld bc,$0200 - add hl,bc - ld a,h - and a,$03 - or a,$98 - ld [H_SCREENEDGEREDRAWADDR + 1],a - ld a,l - ld [H_SCREENEDGEREDRAWADDR],a - ld a,REDRAWROW - ld [H_SCREENEDGEREDRAW],a - ret - -ScheduleEastColumnRedraw:: ; 0ed3 (0:0ed3) - FuncCoord 18,0 - ld hl,Coord - call ScheduleColumnRedrawHelper - ld a,[wd526] - ld c,a - and a,$e0 - ld b,a - ld a,c - add a,18 - and a,$1f - or b - ld [H_SCREENEDGEREDRAWADDR],a - ld a,[wd527] - ld [H_SCREENEDGEREDRAWADDR + 1],a - ld a,REDRAWCOL - ld [H_SCREENEDGEREDRAW],a - ret - -ScheduleColumnRedrawHelper:: ; 0ef2 (0:0ef2) - ld de,wScreenEdgeTiles - ld c,$12 -.loop - ld a,[hli] - ld [de],a - inc de - ld a,[hl] - ld [de],a - inc de - ld a,19 - add l - ld l,a - jr nc,.noCarry - inc h -.noCarry - dec c - jr nz,.loop - ret - -ScheduleWestColumnRedraw:: ; 0f08 (0:0f08) - FuncCoord 0,0 - ld hl,Coord - call ScheduleColumnRedrawHelper - ld a,[wd526] - ld [H_SCREENEDGEREDRAWADDR],a - ld a,[wd527] - ld [H_SCREENEDGEREDRAWADDR + 1],a - ld a,REDRAWCOL - ld [H_SCREENEDGEREDRAW],a - ret - -; function to write the tiles that make up a tile block to memory -; Input: c = tile block ID, hl = destination address -DrawTileBlock:: ; 0f1d (0:0f1d) - push hl - ld a,[W_TILESETBLOCKSPTR] ; pointer to tiles - ld l,a - ld a,[W_TILESETBLOCKSPTR + 1] - ld h,a - ld a,c - swap a - ld b,a - and a,$f0 - ld c,a - ld a,b - and a,$0f - ld b,a ; bc = tile block ID * 0x10 - add hl,bc - ld d,h - ld e,l ; de = address of the tile block's tiles - pop hl - ld c,$04 ; 4 loop iterations -.loop ; each loop iteration, write 4 tile numbers - push bc - ld a,[de] - ld [hli],a - inc de - ld a,[de] - ld [hli],a - inc de - ld a,[de] - ld [hli],a - inc de - ld a,[de] - ld [hl],a - inc de - ld bc,$0015 - add hl,bc - pop bc - dec c - jr nz,.loop - ret - -; function to update joypad state and simulate button presses -JoypadOverworld:: ; 0f4d (0:0f4d) - xor a - ld [wSpriteStateData1 + 3],a - ld [wSpriteStateData1 + 5],a - call RunMapScript - call Joypad - ld a,[W_FLAGS_D733] - bit 3,a ; check if a trainer wants a challenge - jr nz,.notForcedDownwards - ld a,[W_CURMAP] - cp a,ROUTE_17 ; Cycling Road - jr nz,.notForcedDownwards - ld a,[hJoyHeld] ; current joypad state - and a,%11110011 ; bit mask for all directions and A/B - jr nz,.notForcedDownwards - ld a,%10000000 ; down pressed - ld [hJoyHeld],a ; on the cycling road, if there isn't a trainer and the player isn't pressing buttons, simulate a down press -.notForcedDownwards - ld a,[wd730] - bit 7,a - ret z -; if simulating button presses - ld a,[hJoyHeld] ; current joypad state - ld b,a - ld a,[wcd3b] ; bit mask for button presses that override simulated ones - and b - ret nz ; return if the simulated button presses are overridden - ld hl,wcd38 ; index of current simulated button press - dec [hl] - ld a,[hl] - cp a,$ff - jr z,.doneSimulating ; if the end of the simulated button presses has been reached - ld hl,wccd3 ; base address of simulated button presses -; add offset to base address - add l - ld l,a - jr nc,.noCarry - inc h -.noCarry - ld a,[hl] - ld [hJoyHeld],a ; store simulated button press in joypad state - and a - ret nz - ld [hJoyPressed],a - ld [hJoyReleased],a - ret -; if done simulating button presses -.doneSimulating - xor a - ld [wcd3a],a - ld [wcd38],a - ld [wccd3],a - ld [wJoyIgnore],a - ld [hJoyHeld],a - ld hl,wd736 - ld a,[hl] - and a,$f8 - ld [hl],a - ld hl,wd730 - res 7,[hl] - ret - -; function to check the tile ahead to determine if the character should get on land or keep surfing -; sets carry if there is a collision and clears carry otherwise -; It seems that this function has a bug in it, but due to luck, it doesn't -; show up. After detecting a sprite collision, it jumps to the code that -; checks if the next tile is passable instead of just directly jumping to the -; "collision detected" code. However, it doesn't store the next tile in c, -; so the old value of c is used. 2429 is always called before this function, -; and 2429 always sets c to 0xF0. There is no 0xF0 background tile, so it -; is considered impassable and it is detected as a collision. -CollisionCheckOnWater:: ; 0fb7 (0:0fb7) - ld a,[wd730] - bit 7,a - jp nz,.noCollision ; return and clear carry if button presses are being simulated - ld a,[wd52a] ; the direction that the player is trying to go in - ld d,a - ld a,[wSpriteStateData1 + 12] ; the player sprite's collision data (bit field) (set in the sprite movement code) - and d ; check if a sprite is in the direction the player is trying to go - jr nz,.checkIfNextTileIsPassable ; bug? - ld hl,TilePairCollisionsWater - call CheckForJumpingAndTilePairCollisions - jr c,.collision - ld a,$35 - call Predef ; get tile in front of player (puts it in c and [wcfc6]) - ld a,[wcfc6] ; tile in front of player - cp a,$14 ; water tile - jr z,.noCollision ; keep surfing if it's a water tile - cp a,$32 ; either the left tile of the S.S. Anne boarding platform or the tile on eastern coastlines (depending on the current tileset) - jr z,.checkIfVermilionDockTileset - cp a,$48 ; tile on right on coast lines in Safari Zone - jr z,.noCollision ; keep surfing -; check if the [land] tile in front of the player is passable -.checkIfNextTileIsPassable - ld hl,W_TILESETCOLLISIONPTR ; pointer to list of passable tiles - ld a,[hli] - ld h,[hl] - ld l,a -.loop - ld a,[hli] - cp a,$ff - jr z,.collision - cp c - jr z,.stopSurfing ; stop surfing if the tile is passable - jr .loop -.collision - ld a,[wc02a] - cp a,(SFX_02_5b - SFX_Headers_02) / 3 ; check if collision sound is already playing - jr z,.setCarry - ld a,(SFX_02_5b - SFX_Headers_02) / 3 - call PlaySound ; play collision sound (if it's not already playing) -.setCarry - scf - jr .done -.noCollision - and a -.done - ret -.stopSurfing - xor a - ld [wd700],a - call LoadPlayerSpriteGraphics - call Func_2307 - jr .noCollision -.checkIfVermilionDockTileset - ld a, [W_CURMAPTILESET] ; tileset - cp SHIP_PORT ; Vermilion Dock tileset - jr nz, .noCollision ; keep surfing if it's not the boarding platform tile - jr .stopSurfing ; if it is the boarding platform tile, stop surfing - -; function to run the current map's script -RunMapScript:: ; 101b (0:101b) - push hl - push de - push bc - callba Func_f225 ; check if the player is pushing a boulder - ld a,[wFlags_0xcd60] - bit 1,a ; is the player pushing a boulder? - jr z,.afterBoulderEffect - callba Func_f2b5 ; displays dust effect when pushing a boulder -.afterBoulderEffect - pop bc - pop de - pop hl - call Func_310e - ld a,[W_CURMAP] ; current map number - call SwitchToMapRomBank ; change to the ROM bank the map's data is in - ld hl,W_MAPSCRIPTPTR - ld a,[hli] - ld h,[hl] - ld l,a - ld de,.return - push de - jp [hl] ; jump to script -.return - ret - -LoadWalkingPlayerSpriteGraphics:: ; 104d (0:104d) - ld de,RedSprite ; $4180 - ld hl,vNPCSprites - jr LoadPlayerSpriteGraphicsCommon - -LoadSurfingPlayerSpriteGraphics:: ; 1055 (0:1055) - ld de,SeelSprite - ld hl,vNPCSprites - jr LoadPlayerSpriteGraphicsCommon - -LoadBikePlayerSpriteGraphics:: ; 105d (0:105d) - ld de,RedCyclingSprite - ld hl,vNPCSprites - -LoadPlayerSpriteGraphicsCommon:: ; 1063 (0:1063) - push de - push hl - ld bc,(BANK(RedSprite) << 8) + $0c - call CopyVideoData - pop hl - pop de - ld a,$c0 - add e - ld e,a - jr nc,.noCarry - inc d -.noCarry - set 3,h - ld bc,$050c - jp CopyVideoData - -; function to load data from the map header -LoadMapHeader:: ; 107c (0:107c) - callba Func_f113 - ld a,[W_CURMAPTILESET] - ld [wd119],a - ld a,[W_CURMAP] - call SwitchToMapRomBank - ld a,[W_CURMAPTILESET] - ld b,a - res 7,a - ld [W_CURMAPTILESET],a - ld [$ff8b],a - bit 7,b - ret nz - ld hl,MapHeaderPointers - ld a,[W_CURMAP] - sla a - jr nc,.noCarry1 - inc h -.noCarry1 - add l - ld l,a - jr nc,.noCarry2 - inc h -.noCarry2 - ld a,[hli] - ld h,[hl] - ld l,a ; hl = base of map header -; copy the first 10 bytes (the fixed area) of the map data to D367-D370 - ld de,W_CURMAPTILESET - ld c,$0a -.copyFixedHeaderLoop - ld a,[hli] - ld [de],a - inc de - dec c - jr nz,.copyFixedHeaderLoop -; initialize all the connected maps to disabled at first, before loading the actual values - ld a,$ff - ld [W_MAPCONN1PTR],a - ld [W_MAPCONN2PTR],a - ld [W_MAPCONN3PTR],a - ld [W_MAPCONN4PTR],a -; copy connection data (if any) to WRAM - ld a,[W_MAPCONNECTIONS] - ld b,a -.checkNorth - bit 3,b - jr z,.checkSouth - ld de,W_MAPCONN1PTR - call CopyMapConnectionHeader -.checkSouth - bit 2,b - jr z,.checkWest - ld de,W_MAPCONN2PTR - call CopyMapConnectionHeader -.checkWest - bit 1,b - jr z,.checkEast - ld de,W_MAPCONN3PTR - call CopyMapConnectionHeader -.checkEast - bit 0,b - jr z,.getObjectDataPointer - ld de,W_MAPCONN4PTR - call CopyMapConnectionHeader -.getObjectDataPointer - ld a,[hli] - ld [wd3a9],a - ld a,[hli] - ld [wd3aa],a - push hl - ld a,[wd3a9] - ld l,a - ld a,[wd3aa] - ld h,a ; hl = base of object data - ld de,wd3ad ; background tile ID - ld a,[hli] - ld [de],a ; save background tile ID -.loadWarpData - ld a,[hli] ; number of warps - ld [wd3ae],a ; save the number of warps - and a ; are there any warps? - jr z,.loadSignData ; if not, skip this - ld c,a - ld de,wd3af ; base address of warps -.warpLoop ; one warp per loop iteration - ld b,$04 -.warpInnerLoop - ld a,[hli] - ld [de],a - inc de - dec b - jr nz,.warpInnerLoop - dec c - jr nz,.warpLoop -.loadSignData - ld a,[hli] ; number of signs - ld [wd4b0],a ; save the number of signs - and a ; are there any signs? - jr z,.loadSpriteData ; if not, skip this - ld c,a - ld de,wd4d1 ; base address of sign text IDs - ld a,d - ld [$ff95],a - ld a,e - ld [$ff96],a - ld de,wd4b1 ; base address of sign coordinates -.signLoop - ld a,[hli] - ld [de],a - inc de - ld a,[hli] - ld [de],a - inc de - push de - ld a,[$ff95] - ld d,a - ld a,[$ff96] - ld e,a - ld a,[hli] - ld [de],a - inc de - ld a,d - ld [$ff95],a - ld a,e - ld [$ff96],a - pop de - dec c - jr nz,.signLoop -.loadSpriteData - ld a,[wd72e] - bit 5,a ; did a battle happen immediately before this? - jp nz,.finishUp ; if so, skip this because battles don't destroy this data - ld a,[hli] - ld [W_NUMSPRITES],a ; save the number of sprites - push hl -; zero C110-C1FF and C210-C2FF - ld hl,wSpriteStateData1 + $10 - ld de,wSpriteStateData2 + $10 - xor a - ld b,$f0 -.zeroSpriteDataLoop - ld [hli],a - ld [de],a - inc e - dec b - jr nz,.zeroSpriteDataLoop -; initialize all C100-C1FF sprite entries to disabled (other than player's) - ld hl,wSpriteStateData1 + $12 - ld de,$0010 - ld c,$0f -.disableSpriteEntriesLoop - ld [hl],$ff - add hl,de - dec c - jr nz,.disableSpriteEntriesLoop - pop hl - ld de,wSpriteStateData1 + $10 - ld a,[W_NUMSPRITES] ; number of sprites - and a ; are there any sprites? - jp z,.finishUp ; if there are no sprites, skip the rest - ld b,a - ld c,$00 -.loadSpriteLoop - ld a,[hli] - ld [de],a ; store picture ID at C1X0 - inc d - ld a,$04 - add e - ld e,a - ld a,[hli] - ld [de],a ; store Y position at C2X4 - inc e - ld a,[hli] - ld [de],a ; store X position at C2X5 - inc e - ld a,[hli] - ld [de],a ; store movement byte 1 at C2X6 - ld a,[hli] - ld [$ff8d],a ; save movement byte 2 - ld a,[hli] - ld [$ff8e],a ; save text ID and flags byte - push bc - push hl - ld b,$00 - ld hl,W_MAPSPRITEDATA - add hl,bc - ld a,[$ff8d] - ld [hli],a ; store movement byte 2 in byte 0 of sprite entry - ld a,[$ff8e] - ld [hl],a ; this appears pointless, since the value is overwritten immediately after - ld a,[$ff8e] - ld [$ff8d],a - and a,$3f - ld [hl],a ; store text ID in byte 1 of sprite entry - pop hl - ld a,[$ff8d] - bit 6,a - jr nz,.trainerSprite - bit 7,a - jr nz,.itemBallSprite - jr .regularSprite -.trainerSprite - ld a,[hli] - ld [$ff8d],a ; save trainer class - ld a,[hli] - ld [$ff8e],a ; save trainer number (within class) - push hl - ld hl,W_MAPSPRITEEXTRADATA - add hl,bc - ld a,[$ff8d] - ld [hli],a ; store trainer class in byte 0 of the entry - ld a,[$ff8e] - ld [hl],a ; store trainer number in byte 1 of the entry - pop hl - jr .nextSprite -.itemBallSprite - ld a,[hli] - ld [$ff8d],a ; save item number - push hl - ld hl,W_MAPSPRITEEXTRADATA - add hl,bc - ld a,[$ff8d] - ld [hli],a ; store item number in byte 0 of the entry - xor a - ld [hl],a ; zero byte 1, since it is not used - pop hl - jr .nextSprite -.regularSprite - push hl - ld hl,W_MAPSPRITEEXTRADATA - add hl,bc -; zero both bytes, since regular sprites don't use this extra space - xor a - ld [hli],a - ld [hl],a - pop hl -.nextSprite - pop bc - dec d - ld a,$0a - add e - ld e,a - inc c - inc c - dec b - jp nz,.loadSpriteLoop -.finishUp - ld a,$19 - call Predef ; load tileset data - callab LoadWildData ; load wild pokemon data - pop hl ; restore hl from before going to the warp/sign/sprite data (this value was saved for seemingly no purpose) - ld a,[W_CURMAPHEIGHT] ; map height in 4x4 tile blocks - add a ; double it - ld [wd524],a ; store map height in 2x2 tile blocks - ld a,[W_CURMAPWIDTH] ; map width in 4x4 tile blocks - add a ; double it - ld [wd525],a ; map width in 2x2 tile blocks - ld a,[W_CURMAP] - ld c,a - ld b,$00 - ld a,[H_LOADEDROMBANK] - push af - ld a, BANK(MapSongBanks) - ld [H_LOADEDROMBANK],a - ld [$2000],a - ld hl, MapSongBanks - add hl,bc - add hl,bc - ld a,[hli] - ld [wd35b],a ; music 1 - ld a,[hl] - ld [wd35c],a ; music 2 - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - -; function to copy map connection data from ROM to WRAM -; Input: hl = source, de = destination -CopyMapConnectionHeader:: ; 1238 (0:1238) - ld c,$0b -.loop - ld a,[hli] - ld [de],a - inc de - dec c - jr nz,.loop - ret - -; function to load map data -LoadMapData:: ; 1241 (0:1241) - ld a,[H_LOADEDROMBANK] - push af - call DisableLCD - ld a,$98 - ld [wd527],a - xor a - ld [wd526],a - ld [$ffaf],a - ld [$ffae],a - ld [wWalkCounter],a - ld [wd119],a - ld [wd11a],a - ld [W_SPRITESETID],a - call LoadTextBoxTilePatterns - call LoadMapHeader - callba InitMapSprites ; load tile pattern data for sprites - call LoadTileBlockMap - call LoadTilesetTilePatternData - call LoadCurrentMapView -; copy current map view to VRAM - ld hl,wTileMap - ld de,vBGMap0 - ld b,18 -.vramCopyLoop - ld c,20 -.vramCopyInnerLoop - ld a,[hli] - ld [de],a - inc e - dec c - jr nz,.vramCopyInnerLoop - ld a,32 - 20 - add e - ld e,a - jr nc,.noCarry - inc d -.noCarry - dec b - jr nz,.vramCopyLoop - ld a,$01 - ld [wcfcb],a - call EnableLCD - ld b,$09 - call GoPAL_SET - call LoadPlayerSpriteGraphics - ld a,[wd732] - and a,$18 ; did the player fly or teleport in? - jr nz,.restoreRomBank - ld a,[W_FLAGS_D733] - bit 1,a - jr nz,.restoreRomBank - call Func_235f ; music related - call Func_2312 ; music related -.restoreRomBank - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - ret - -; function to switch to the ROM bank that a map is stored in -; Input: a = map number -SwitchToMapRomBank:: ; 12bc (0:12bc) - push hl - push bc - ld c,a - ld b,$00 - 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 - call BankswitchBack - ld a,[$ffe8] - ld [H_LOADEDROMBANK],a - ld [$2000],a ; switch to map ROM bank - pop bc - pop hl - ret - -Func_12da:: ; 12da (0:12da) - ld a, $1e - ld [wd13a], a - ld hl, wd730 - ld a, [hl] - or $26 - ld [hl], a - ret - -Func_12e7:: ; 12e7 (0:12e7) - ld hl, wd728 - res 0, [hl] - ret - -ForceBikeOrSurf:: ; 12ed (0:12ed) - ld b, BANK(RedSprite) - ld hl, LoadPlayerSpriteGraphics - call Bankswitch - jp Func_2307 ; update map/player state? +INCLUDE "home/overworld.asm" ; this is used to check if the player wants to interrupt the opening sequence at several points ; XXX is this used anywhere else? @@ -3365,75 +908,33 @@ InterlaceMergeSpriteBuffers:: ; 16ea (0:16ea) ld b, a jp CopyVideoData -Underground_Coll:: ; 172f (0:172f) - INCBIN "gfx/tilesets/underground.tilecoll" -Overworld_Coll:: ; 1735 (0:1735) - INCBIN "gfx/tilesets/overworld.tilecoll" -RedsHouse1_Coll:: -RedsHouse2_Coll:: ; 1749 (0:1749) - INCBIN "gfx/tilesets/reds_house.tilecoll" -Mart_Coll -Pokecenter_Coll:: ; 1753 (0:1753) - INCBIN "gfx/tilesets/pokecenter.tilecoll" -Dojo_Coll:: -Gym_Coll:: ; 1759 (0:1759) - INCBIN "gfx/tilesets/gym.tilecoll" -Forest_Coll:: ; 1765 (0:1765) - INCBIN "gfx/tilesets/forest.tilecoll" -House_Coll:: ; 1775 (0:1775) - INCBIN "gfx/tilesets/house.tilecoll" -ForestGate_Coll:: -Museum_Coll:: -Gate_Coll:: ; 177f (0:177f) - INCBIN "gfx/tilesets/gate.tilecoll" -Ship_Coll:: ; 178a (0:178a) - INCBIN "gfx/tilesets/ship.tilecoll" -ShipPort_Coll:: ; 1795 (0:1795) - INCBIN "gfx/tilesets/ship_port.tilecoll" -Cemetery_Coll:: ; 179a (0:179a) - INCBIN "gfx/tilesets/cemetery.tilecoll" -Interior_Coll:: ; 17a2 (0:17a2) - INCBIN "gfx/tilesets/interior.tilecoll" -Cavern_Coll:: ; 17ac (0:17ac) - INCBIN "gfx/tilesets/cavern.tilecoll" -Lobby_Coll:: ; 17b8 (0:17b8) - INCBIN "gfx/tilesets/lobby.tilecoll" -Mansion_Coll:: ; 17c0 (0:17c0) - INCBIN "gfx/tilesets/mansion.tilecoll" -Lab_Coll:: ; 17ca (0:17ca) - INCBIN "gfx/tilesets/lab.tilecoll" -Club_Coll:: ; 17d1 (0:17d1) - INCBIN "gfx/tilesets/club.tilecoll" -Facility_Coll:: ; 17dd (0:17dd) - INCBIN "gfx/tilesets/facility.tilecoll" -Plateau_Coll:: ; 17f0 (0:17f0) - INCBIN "gfx/tilesets/plateau.tilecoll" - -; does the same thing as FarCopyData at 009D -; only difference is that it uses [$ff8b] instead of [wHPBarMaxHP] for a temp value -; copy bc bytes of data from a:hl to de -FarCopyData2:: ; 17f7 (0:17f7) + +INCLUDE "data/collision.asm" + + +FarCopyData2:: +; Identical to FarCopyData, but uses $ff8b +; as temp space instead of wBuffer. ld [$ff8b],a ld a,[H_LOADEDROMBANK] push af ld a,[$ff8b] ld [H_LOADEDROMBANK],a - ld [$2000],a + ld [MBC3RomBank],a call CopyData pop af ld [H_LOADEDROMBANK],a - ld [$2000],a + ld [MBC3RomBank],a ret -; does a far copy but the source is de and the destination is hl -; copy bc bytes of data from a:de to hl -FarCopyData3:: ; 180d (0:180d) +FarCopyData3:: +; Copy bc bytes from a:de to hl. ld [$ff8b],a ld a,[H_LOADEDROMBANK] push af ld a,[$ff8b] ld [H_LOADEDROMBANK],a - ld [$2000],a + ld [MBC3RomBank],a push hl push de push de @@ -3445,18 +946,18 @@ FarCopyData3:: ; 180d (0:180d) pop hl pop af ld [H_LOADEDROMBANK],a - ld [$2000],a + ld [MBC3RomBank],a ret -; copies each source byte to the destination twice (next to each other) -; copy bc source bytes from a:hl to de -FarCopyDataDouble:: ; 182b (0:182b) +FarCopyDataDouble:: +; Expand bc bytes of 1bpp image data +; from a:hl to 2bpp data at de. ld [$ff8b],a ld a,[H_LOADEDROMBANK] push af ld a,[$ff8b] ld [H_LOADEDROMBANK],a - ld [$2000],a + ld [MBC3RomBank],a .loop ld a,[hli] ld [de],a @@ -3469,1740 +970,184 @@ FarCopyDataDouble:: ; 182b (0:182b) jr nz,.loop pop af ld [H_LOADEDROMBANK],a - ld [$2000],a + ld [MBC3RomBank],a ret -; copy (c * 16) bytes from b:de to hl during V-blank -; transfers up to 128 bytes per V-blank -CopyVideoData:: ; 1848 (0:1848) - ld a,[H_AUTOBGTRANSFERENABLED] ; save auto-transfer enabled flag - push af - xor a - ld [H_AUTOBGTRANSFERENABLED],a ; disable auto-transfer while copying - ld a,[H_LOADEDROMBANK] - ld [$ff8b],a - ld a,b - ld [H_LOADEDROMBANK],a - ld [$2000],a - ld a,e - ld [H_VBCOPYSRC],a - ld a,d - ld [H_VBCOPYSRC + 1],a - ld a,l - ld [H_VBCOPYDEST],a - ld a,h - ld [H_VBCOPYDEST + 1],a -.loop - ld a,c - cp a,8 ; are there more than 128 bytes left to copy? - jr nc,.copyMaxSize ; only copy up to 128 bytes at a time -.copyRemainder - ld [H_VBCOPYSIZE],a - call DelayFrame ; wait for V-blank handler to perform the copy - ld a,[$ff8b] - ld [H_LOADEDROMBANK],a - ld [$2000],a - pop af - ld [H_AUTOBGTRANSFERENABLED],a ; restore original auto-transfer enabled flag - ret -.copyMaxSize - ld a,8 ; 128 bytes - ld [H_VBCOPYSIZE],a - call DelayFrame ; wait for V-blank handler to perform the copy - ld a,c - sub a,8 - ld c,a - jr .loop +CopyVideoData:: +; Wait for the next VBlank, then copy c 2bpp +; tiles from b:de to hl, 8 tiles at a time. +; This takes c/8 frames. -; copy (c * 8) source bytes from b:de to hl during V-blank -; copies each source byte to the destination twice (next to each other) -; transfers up to 64 source bytes per V-blank -CopyVideoDataDouble:: ; 1886 (0:1886) - ld a,[H_AUTOBGTRANSFERENABLED] ; save auto-transfer enabled flag + ld a, [H_AUTOBGTRANSFERENABLED] push af - xor a - ld [H_AUTOBGTRANSFERENABLED],a ; disable auto-transfer while copying - ld a,[H_LOADEDROMBANK] - ld [$ff8b],a - ld a,b - ld [H_LOADEDROMBANK],a - ld [$2000],a - ld a,e - ld [H_VBCOPYDOUBLESRC],a - ld a,d - ld [H_VBCOPYDOUBLESRC + 1],a - ld a,l - ld [H_VBCOPYDOUBLEDEST],a - ld a,h - ld [H_VBCOPYDOUBLEDEST + 1],a -.loop - ld a,c - cp a,8 ; are there more than 64 source bytes left to copy? - jr nc,.copyMaxSize ; only copy up to 64 source bytes at a time -.copyRemainder - ld [H_VBCOPYDOUBLESIZE],a - call DelayFrame ; wait for V-blank handler to perform the copy - ld a,[$ff8b] - ld [H_LOADEDROMBANK],a - ld [$2000],a - pop af - ld [H_AUTOBGTRANSFERENABLED],a ; restore original auto-transfer enabled flag - ret -.copyMaxSize - ld a,8 ; 64 source bytes - ld [H_VBCOPYDOUBLESIZE],a - call DelayFrame ; wait for V-blank handler to perform the copy - ld a,c - sub a,8 - ld c,a - jr .loop + xor a ; disable auto-transfer while copying + ld [H_AUTOBGTRANSFERENABLED], a -; clears an area of the screen -; INPUT: -; hl = address of upper left corner of the area -; b = height -; c = width -ClearScreenArea:: ; 18c4 (0:18c4) - ld a,$7F ; blank tile - ld de,20 ; screen width -.loop - push hl - push bc -.innerLoop - ld [hli],a - dec c - jr nz,.innerLoop - pop bc - pop hl - add hl,de - dec b - jr nz,.loop - ret + ld a, [H_LOADEDROMBANK] + ld [$ff8b], a -; copies the screen tile buffer from WRAM to VRAM -; copying is done in 3 chunks of 6 rows each -; b: high byte of VRAM destination address ($98 or $9c for window tile map 0 or 1 resp.) -CopyScreenTileBufferToVRAM:: ; 18d6 (0:18d6) - ld c, $6 - ld hl, $0000 - ld de, wTileMap - call InitScreenTileBufferTransferParameters - call DelayFrame - ld hl, $600 - ld de, wTileMap + 20 * 6 - call InitScreenTileBufferTransferParameters - call DelayFrame - ld hl, $c00 - ld de, wTileMap + 20 * 12 - call InitScreenTileBufferTransferParameters - jp DelayFrame + ld a, b + ld [H_LOADEDROMBANK], a + ld [MBC3RomBank], a -InitScreenTileBufferTransferParameters:: ; 18fc (0:18fc) + ld a, e + ld [H_VBCOPYSRC], a ld a, d - ld [H_VBCOPYBGSRC+1], a - call GetRowColAddressBgMap + ld [H_VBCOPYSRC + 1], a + ld a, l - ld [H_VBCOPYBGDEST], a ; $ffc3 + ld [H_VBCOPYDEST], a ld a, h - ld [H_VBCOPYBGDEST+1], a - ld a, c - ld [H_VBCOPYBGNUMROWS], a ; $ffc5 - ld a, e - ld [H_VBCOPYBGSRC], a ; $ffc1 - ret - -ClearScreen:: ; 190f (0:190f) -; clears all tiles in the tilemap, -; then wait three frames - ld bc,$0168 ; tilemap size - inc b - ld hl,wTileMap ; TILEMAP_START - ld a,$7F ; $7F is blank tile -.loop - ld [hli],a - dec c - jr nz,.loop - dec b - jr nz,.loop - jp Delay3 - -TextBoxBorder:: ; 1922 (0:1922) -; draw a text box -; upper-left corner at coordinates hl -; height b -; width c - - ; first row - push hl - ld a,"┌" - ld [hli],a - inc a ; horizontal border ─ - call NPlaceChar - inc a ; upper-right border ┐ - ld [hl],a - - ; middle rows - pop hl - ld de,20 - add hl,de ; skip the top row - -.PlaceRow - push hl - ld a,"│" - ld [hli],a - ld a," " - call NPlaceChar - ld [hl],"│" - - pop hl - ld de,20 - add hl,de ; move to next row - dec b - jr nz,.PlaceRow + ld [H_VBCOPYDEST + 1], a - ; bottom row - ld a,"└" - ld [hli],a - ld a,"─" - call NPlaceChar - ld [hl],"┘" - ret -; -NPlaceChar:: ; 194f (0:194f) -; place a row of width c of identical characters - ld d,c .loop - ld [hli],a - dec d - jr nz,.loop - ret - -PlaceString:: ; 1955 (0:1955) - push hl -PlaceNextChar:: ; 1956 (0:1956) - ld a,[de] - - cp "@" - jr nz,.PlaceText - ld b,h - ld c,l - pop hl - ret - -.PlaceText - cp $4E - jr nz,.next - ld bc,$0028 - ld a,[$FFF6] - bit 2,a - jr z,.next2 - ld bc,$14 -.next2 - pop hl - add hl,bc - push hl - jp Next19E8 - -.next - cp $4F - jr nz,.next3 - pop hl - FuncCoord 1, 16 - ld hl,Coord - push hl - jp Next19E8 - -.next3 ; Check against a dictionary - and a - jp z,Char00 - cp $4C - jp z,Char4C - cp $4B - jp z,Char4B - cp $51 - jp z,Char51 - cp $49 - jp z,Char49 - cp $52 - jp z,Char52 - cp $53 - jp z,Char53 - cp $54 - jp z,Char54 - cp $5B - jp z,Char5B - cp $5E - jp z,Char5E - cp $5C - jp z,Char5C - cp $5D - jp z,Char5D - cp $55 - jp z,Char55 - cp $56 - jp z,Char56 - cp $57 - jp z,Char57 - cp $58 - jp z,Char58 - cp $4A - jp z,Char4A - cp $5F - jp z,Char5F - cp $59 - jp z,Char59 - cp $5A - jp z,Char5A - ld [hli],a - call PrintLetterDelay -Next19E8:: ; 19e8 (0:19e8) - inc de - jp PlaceNextChar - -Char00:: ; 19ec (0:19ec) - ld b,h - ld c,l - pop hl - ld de,Char00Text - dec de - ret - -Char00Text:: ; 0x19f4 “%d ERROR.” - TX_FAR _Char00Text - db "@" - -Char52:: ; 0x19f9 player’s name - push de - ld de,W_PLAYERNAME - jr FinishDTE - -Char53:: ; 19ff (0:19ff) ; rival’s name - push de - ld de,W_RIVALNAME - jr FinishDTE - -Char5D:: ; 1a05 (0:1a05) ; TRAINER - push de - ld de,Char5DText - jr FinishDTE - -Char5C:: ; 1a0b (0:1a0b) ; TM - push de - ld de,Char5CText - jr FinishDTE - -Char5B:: ; 1a11 (0:1a11) ; PC - push de - ld de,Char5BText - jr FinishDTE - -Char5E:: ; 1a17 (0:1a17) ; ROCKET - push de - ld de,Char5EText - jr FinishDTE - -Char54:: ; 1a1d (0:1a1d) ; POKé - push de - ld de,Char54Text - jr FinishDTE - -Char56:: ; 1a23 (0:1a23) ; …… - push de - ld de,Char56Text - jr FinishDTE - -Char4A:: ; 1a29 (0:1a29) ; PKMN - push de - ld de,Char4AText - jr FinishDTE - -Char59:: ; 1a2f (0:1a2f) -; depending on whose turn it is, print -; enemy active monster’s name, prefixed with “Enemy ” -; or -; player active monster’s name -; (like Char5A but flipped) - ld a,[H_WHOSETURN] - xor 1 - jr MonsterNameCharsCommon - -Char5A:: ; 1a35 (0:1a35) -; depending on whose turn it is, print -; player active monster’s name -; or -; enemy active monster’s name, prefixed with “Enemy ” - ld a,[H_WHOSETURN] -MonsterNameCharsCommon:: ; 1a37 (0:1a37) - push de - and a - jr nz,.Enemy - ld de,W_PLAYERMONNAME ; player active monster name - jr FinishDTE - -.Enemy ; 1A40 - ; print “Enemy ” - ld de,Char5AText - call PlaceString - - ld h,b - ld l,c - ld de,W_ENEMYMONNAME ; enemy active monster name - -FinishDTE:: ; 1a4b (0:1a4b) - call PlaceString - ld h,b - ld l,c - pop de - inc de - jp PlaceNextChar - -Char5CText:: ; 1a55 (0:1a55) - db "TM@" -Char5DText:: ; 1a58 (0:1a58) - db "TRAINER@" -Char5BText:: ; 1a60 (0:1a60) - db "PC@" -Char5EText:: ; 1a63 (0:1a63) - db "ROCKET@" -Char54Text:: ; 1a6a (0:1a6a) - db "POKé@" -Char56Text:: ; 1a6f (0:1a6f) - db "……@" -Char5AText:: ; 1a72 (0:1a72) - db "Enemy @" -Char4AText:: ; 1a79 (0:1a79) - db $E1,$E2,"@" ; PKMN - -Char55:: ; 1a7c (0:1a7c) - push de - ld b,h - ld c,l - ld hl,Char55Text - call TextCommandProcessor - ld h,b - ld l,c - pop de - inc de - jp PlaceNextChar - -Char55Text:: ; 1a8c (0:1a8c) -; equivalent to Char4B - TX_FAR _Char55Text - db "@" + ld a, c + cp 8 + jr nc, .keepgoing -Char5F:: ; 1a91 (0:1a91) -; ends a Pokédex entry - ld [hl],"." - pop hl +.done + ld [H_VBCOPYSIZE], a + call DelayFrame + ld a, [$ff8b] + ld [H_LOADEDROMBANK], a + ld [MBC3RomBank], a + pop af + ld [H_AUTOBGTRANSFERENABLED], a ret -Char58:: ; 1a95 (0:1a95) - ld a,[W_ISLINKBATTLE] - cp 4 - jp z,Next1AA2 - ld a,$EE - FuncCoord 18, 16 - ld [Coord],a -Next1AA2:: ; 1aa2 (0:1aa2) - call ProtectedDelay3 - call ManualTextScroll - ld a,$7F - FuncCoord 18, 16 - ld [Coord],a -Char57:: ; 1aad (0:1aad) - pop hl - ld de,Char58Text - dec de - ret +.keepgoing + ld a, 8 + ld [H_VBCOPYSIZE], a + call DelayFrame + ld a, c + sub 8 + ld c, a + jr .loop -Char58Text:: ; 1ab3 (0:1ab3) - db "@" +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] + push af + xor a ; disable auto-transfer while copying + ld [H_AUTOBGTRANSFERENABLED], a + ld a, [H_LOADEDROMBANK] + ld [$ff8b], a -Char51:: ; 1ab4 (0:1ab4) - push de - ld a,$EE - FuncCoord 18, 16 - ld [Coord],a - call ProtectedDelay3 - call ManualTextScroll - FuncCoord 1, 13 - ld hl,Coord - ld bc,$0412 - call ClearScreenArea - ld c,$14 - call DelayFrames - pop de - FuncCoord 1, 14 - ld hl,Coord - jp Next19E8 + ld a, b + ld [H_LOADEDROMBANK], a + ld [MBC3RomBank], a -Char49:: ; 1ad5 (0:1ad5) - push de - ld a,$EE - FuncCoord 18, 16 - ld [Coord],a - call ProtectedDelay3 - call ManualTextScroll - FuncCoord 1, 10 - ld hl,Coord - ld bc,$0712 - call ClearScreenArea - ld c,$14 - call DelayFrames - pop de - pop hl - FuncCoord 1, 11 - ld hl,Coord - push hl - jp Next19E8 + ld a, e + ld [H_VBCOPYDOUBLESRC], a + ld a, d + ld [H_VBCOPYDOUBLESRC + 1], a -Char4B:: ; 1af8 (0:1af8) - ld a,$EE - FuncCoord 18, 16 - ld [Coord],a - call ProtectedDelay3 - push de - call ManualTextScroll - pop de - ld a,$7F - FuncCoord 18, 16 - ld [Coord],a - ;fall through -Char4C:: ; 1b0a (0:1b0a) - push de - call Next1B18 - call Next1B18 - FuncCoord 1, 16 - ld hl,Coord - pop de - jp Next19E8 + ld a, l + ld [H_VBCOPYDOUBLEDEST], a + ld a, h + ld [H_VBCOPYDOUBLEDEST + 1], a -Next1B18:: ; 1b18 (0:1b18) - FuncCoord 0, 14 - ld hl,Coord - FuncCoord 0, 13 - ld de,Coord - ld b,$3C -.next - ld a,[hli] - ld [de],a - inc de - dec b - jr nz,.next - FuncCoord 1, 16 - ld hl,Coord - ld a,$7F - ld b,$12 -.next2 - ld [hli],a - dec b - jr nz,.next2 +.loop + ld a, c + cp 8 + jr nc, .keepgoing - ; wait five frames - ld b,5 -.WaitFrame +.done + ld [H_VBCOPYDOUBLESIZE], a call DelayFrame - dec b - jr nz,.WaitFrame - - ret - -ProtectedDelay3:: ; 1b3a (0:1b3a) - push bc - call Delay3 - pop bc - ret - -TextCommandProcessor:: ; 1b40 (0:1b40) - ld a,[wd358] - push af - set 1,a - ld e,a - ld a,[$fff4] - xor e - ld [wd358],a - ld a,c - ld [wcc3a],a - ld a,b - ld [wcc3b],a - -NextTextCommand:: ; 1b55 (0:1b55) - ld a,[hli] - cp a, "@" ; terminator - jr nz,.doTextCommand + ld a, [$ff8b] + ld [H_LOADEDROMBANK], a + ld [MBC3RomBank], a pop af - ld [wd358],a + ld [H_AUTOBGTRANSFERENABLED], a ret -.doTextCommand - push hl - cp a,$17 - jp z,TextCommand17 - cp a,$0e - jp nc,TextCommand0B ; if a != 0x17 and a >= 0xE, go to command 0xB -; if a < 0xE, use a jump table - ld hl,TextCommandJumpTable - push bc - add a - ld b,$00 - ld c,a - add hl,bc - pop bc - ld a,[hli] - ld h,[hl] - ld l,a - jp [hl] - -; draw box -; 04AAAABBCC -; AAAA = address of upper left corner -; BB = height -; CC = width -TextCommand04:: ; 1b78 (0:1b78) - pop hl - ld a,[hli] - ld e,a - ld a,[hli] - ld d,a - ld a,[hli] - ld b,a - ld a,[hli] - ld c,a - push hl - ld h,d - ld l,e - call TextBoxBorder - pop hl - jr NextTextCommand - -; place string inline -; 00{string} -TextCommand00:: ; 1b8a (0:1b8a) - pop hl - ld d,h - ld e,l - ld h,b - ld l,c - call PlaceString - ld h,d - ld l,e - inc hl - jr NextTextCommand - -; place string from RAM -; 01AAAA -; AAAA = address of string -TextCommand01:: ; 1b97 (0:1b97) - pop hl - ld a,[hli] - ld e,a - ld a,[hli] - ld d,a - push hl - ld h,b - ld l,c - call PlaceString - pop hl - jr NextTextCommand - -; print BCD number -; 02AAAABB -; AAAA = address of BCD number -; BB -; bits 0-4 = length in bytes -; bits 5-7 = unknown flags -TextCommand02:: ; 1ba5 (0:1ba5) - pop hl - ld a,[hli] - ld e,a - ld a,[hli] - ld d,a - ld a,[hli] - push hl - ld h,b - ld l,c - ld c,a - call PrintBCDNumber - ld b,h - ld c,l - pop hl - jr NextTextCommand - -; repoint destination address -; 03AAAA -; AAAA = new destination address -TextCommand03:: ; 1bb7 (0:1bb7) - pop hl - ld a,[hli] - ld [wcc3a],a - ld c,a - ld a,[hli] - ld [wcc3b],a - ld b,a - jp NextTextCommand - -; repoint destination to second line of dialogue text box -; 05 -; (no arguments) -TextCommand05:: ; 1bc5 (0:1bc5) - pop hl - FuncCoord 1, 16 - ld bc,Coord ; address of second line of dialogue text box - jp NextTextCommand - -; blink arrow and wait for A or B to be pressed -; 06 -; (no arguments) -TextCommand06:: ; 1bcc (0:1bcc) - ld a,[W_ISLINKBATTLE] - cp a,$04 - jp z,TextCommand0D - ld a,$ee ; down arrow - FuncCoord 18, 16 - ld [Coord],a ; place down arrow in lower right corner of dialogue text box - push bc - call ManualTextScroll ; blink arrow and wait for A or B to be pressed - pop bc - ld a," " - FuncCoord 18, 16 - ld [Coord],a ; overwrite down arrow with blank space - pop hl - jp NextTextCommand - -; scroll text up one line -; 07 -; (no arguments) -TextCommand07:: ; 1be7 (0:1be7) - ld a," " - FuncCoord 18, 16 - ld [Coord],a ; place blank space in lower right corner of dialogue text box - call Next1B18 ; scroll up text - call Next1B18 - pop hl - FuncCoord 1, 16 - ld bc,Coord ; address of second line of dialogue text box - jp NextTextCommand - -; execute asm inline -; 08{code} -TextCommand08:: ; 1bf9 (0:1bf9) - pop hl - ld de,NextTextCommand - push de ; return address - jp [hl] - -; print decimal number (converted from binary number) -; 09AAAABB -; AAAA = address of number -; BB -; bits 0-3 = how many digits to display -; bits 4-7 = how long the number is in bytes -TextCommand09:: ; 1bff (0:1bff) - pop hl - ld a,[hli] - ld e,a - ld a,[hli] - ld d,a - ld a,[hli] - push hl - ld h,b - ld l,c - ld b,a - and a,$0f - ld c,a - ld a,b - and a,$f0 - swap a - set 6,a - ld b,a - call PrintNumber - ld b,h - ld c,l - pop hl - jp NextTextCommand - -; wait half a second if the user doesn't hold A or B -; 0A -; (no arguments) -TextCommand0A:: ; 1c1d (0:1c1d) - push bc - call Joypad - ld a,[hJoyHeld] - and a,%00000011 ; A and B buttons - jr nz,.skipDelay - ld c,30 - call DelayFrames -.skipDelay - pop bc - pop hl - jp NextTextCommand -; plays sounds -; this actually handles various command ID's, not just 0B -; (no arguments) -TextCommand0B:: ; 1c31 (0:1c31) - pop hl - push bc - dec hl - ld a,[hli] - ld b,a ; b = command number that got us here - push hl - ld hl,TextCommandSounds -.loop - ld a,[hli] - cp b - jr z,.matchFound - inc hl +.keepgoing + ld a, 8 + ld [H_VBCOPYDOUBLESIZE], a + call DelayFrame + ld a, c + sub 8 + ld c, a jr .loop -.matchFound - cp a,$14 - jr z,.pokemonCry - cp a,$15 - jr z,.pokemonCry - cp a,$16 - jr z,.pokemonCry - ld a,[hl] - call PlaySound - call WaitForSoundToFinish - pop hl - pop bc - jp NextTextCommand -.pokemonCry - push de - ld a,[hl] - call PlayCry - pop de - pop hl - pop bc - jp NextTextCommand - -; format: text command ID, sound ID or cry ID -TextCommandSounds:: ; 1c64 (0:1c64) - db $0B,(SFX_02_3a - SFX_Headers_02) / 3 - db $12,(SFX_02_46 - SFX_Headers_02) / 3 - db $0E,(SFX_02_41 - SFX_Headers_02) / 3 - db $0F,(SFX_02_3a - SFX_Headers_02) / 3 - db $10,(SFX_02_3b - SFX_Headers_02) / 3 - db $11,(SFX_02_42 - SFX_Headers_02) / 3 - db $13,(SFX_02_44 - SFX_Headers_02) / 3 - db $14,NIDORINA ; used in OakSpeech - db $15,PIDGEOT ; used in SaffronCityText12 - db $16,DEWGONG ; unused? - -; draw ellipses -; 0CAA -; AA = number of ellipses to draw -TextCommand0C:: ; 1c78 (0:1c78) - pop hl - ld a,[hli] - ld d,a - push hl - ld h,b - ld l,c -.loop - ld a,$75 ; ellipsis - ld [hli],a - push de - call Joypad - pop de - ld a,[hJoyHeld] ; joypad state - and a,%00000011 ; is A or B button pressed? - jr nz,.skipDelay ; if so, skip the delay - ld c,10 - call DelayFrames -.skipDelay - dec d - jr nz,.loop - ld b,h - ld c,l - pop hl - jp NextTextCommand -; wait for A or B to be pressed -; 0D -; (no arguments) -TextCommand0D:: ; 1c9a (0:1c9a) +ClearScreenArea:: +; Clear tilemap area cxb at hl. + ld a, $7f ; blank tile + ld de, 20 ; screen width +.y + push hl push bc - call ManualTextScroll ; wait for A or B to be pressed +.x + ld [hli], a + dec c + jr nz, .x pop bc pop hl - jp NextTextCommand - -; process text commands in another ROM bank -; 17AAAABB -; AAAA = address of text commands -; BB = bank -TextCommand17:: ; 1ca3 (0:1ca3) - pop hl - ld a,[H_LOADEDROMBANK] - push af - ld a,[hli] - ld e,a - ld a,[hli] - ld d,a - ld a,[hli] - ld [H_LOADEDROMBANK],a - ld [$2000],a - push hl - ld l,e - ld h,d - call TextCommandProcessor - pop hl - pop af - ld [H_LOADEDROMBANK],a - ld [$2000],a - jp NextTextCommand - -TextCommandJumpTable:: ; 1cc1 (0:1cc1) - dw TextCommand00 - dw TextCommand01 - dw TextCommand02 - dw TextCommand03 - dw TextCommand04 - dw TextCommand05 - dw TextCommand06 - dw TextCommand07 - dw TextCommand08 - dw TextCommand09 - dw TextCommand0A - dw TextCommand0B - dw TextCommand0C - dw TextCommand0D - -; this function seems to be used only once -; it store the address of a row and column of the VRAM background map in hl -; INPUT: h - row, l - column, b - high byte of background tile map address in VRAM -GetRowColAddressBgMap:: ; 1cdd (0:1cdd) - xor a - srl h - rr a - srl h - rr a - srl h - rr a - or l - ld l,a - ld a,b - or h - ld h,a - ret - -; clears a VRAM background map with blank space tiles -; INPUT: h - high byte of background tile map address in VRAM -ClearBgMap:: ; 1cf0 (0:1cf0) - ld a," " - jr .next - ld a,l -.next - ld de,$400 ; size of VRAM background map - ld l,e -.loop - ld [hli],a - dec e - jr nz,.loop - dec d - jr nz,.loop - ret - -; When the player takes a step, a row or column of 2x2 tile blocks at the edge -; of the screen toward which they moved is exposed and has to be redrawn. -; This function does the redrawing. -RedrawExposedScreenEdge:: ; 1d01 (0:1d01) - ld a,[H_SCREENEDGEREDRAW] - and a - ret z - ld b,a - xor a - ld [H_SCREENEDGEREDRAW],a - dec b - jr nz,.redrawRow -.redrawColumn - ld hl,wScreenEdgeTiles - ld a,[H_SCREENEDGEREDRAWADDR] - ld e,a - ld a,[H_SCREENEDGEREDRAWADDR + 1] - ld d,a - ld c,18 ; screen height -.loop1 - ld a,[hli] - ld [de],a - inc de - ld a,[hli] - ld [de],a - ld a,31 - add e - ld e,a - jr nc,.noCarry - inc d -.noCarry -; the following 4 lines wrap us from bottom to top if necessary - ld a,d - and a,$03 - or a,$98 - ld d,a - dec c - jr nz,.loop1 - xor a - ld [H_SCREENEDGEREDRAW],a - ret -.redrawRow - ld hl,wScreenEdgeTiles - ld a,[H_SCREENEDGEREDRAWADDR] - ld e,a - ld a,[H_SCREENEDGEREDRAWADDR + 1] - ld d,a - push de - call .drawHalf ; draw upper half - pop de - ld a,32 ; width of VRAM background map - add e - ld e,a - ; draw lower half -.drawHalf - ld c,10 -.loop2 - ld a,[hli] - ld [de],a - inc de - ld a,[hli] - ld [de],a - ld a,e - inc a -; the following 6 lines wrap us from the right edge to the left edge if necessary - and a,$1f - ld b,a - ld a,e - and a,$e0 - or b - ld e,a - dec c - jr nz,.loop2 - ret - -; This function automatically transfers tile number data from the tile map at -; wTileMap to VRAM during V-blank. Note that it only transfers one third of the -; background per V-blank. It cycles through which third it draws. -; This transfer is turned off when walking around the map, but is turned -; on when talking to sprites, battling, using menus, etc. This is because -; the above function, RedrawExposedScreenEdge, is used when walking to -; improve efficiency. -AutoBgMapTransfer:: ; 1d57 (0:1d57) - ld a,[H_AUTOBGTRANSFERENABLED] - and a - ret z - ld hl,[sp + 0] - ld a,h - ld [H_SPTEMP],a - ld a,l - ld [H_SPTEMP + 1],a ; save stack pinter - ld a,[H_AUTOBGTRANSFERPORTION] - and a - jr z,.transferTopThird - dec a - jr z,.transferMiddleThird -.transferBottomThird - FuncCoord 0,12 - ld hl,Coord - ld sp,hl - ld a,[H_AUTOBGTRANSFERDEST + 1] - ld h,a - ld a,[H_AUTOBGTRANSFERDEST] - ld l,a - ld de,(12 * 32) - add hl,de - xor a ; TRANSFERTOP - jr .doTransfer -.transferTopThird - FuncCoord 0,0 - ld hl,Coord - ld sp,hl - ld a,[H_AUTOBGTRANSFERDEST + 1] - ld h,a - ld a,[H_AUTOBGTRANSFERDEST] - ld l,a - ld a,TRANSFERMIDDLE - jr .doTransfer -.transferMiddleThird - FuncCoord 0,6 - ld hl,Coord - ld sp,hl - ld a,[H_AUTOBGTRANSFERDEST + 1] - ld h,a - ld a,[H_AUTOBGTRANSFERDEST] - ld l,a - ld de,(6 * 32) - add hl,de - ld a,TRANSFERBOTTOM -.doTransfer - ld [H_AUTOBGTRANSFERPORTION],a ; store next portion - ld b,6 - -; unrolled loop and using pop for speed -TransferBgRows:: ; 1d9e (0:1d9e) - pop de - ld [hl],e - inc l - ld [hl],d - inc l - pop de - ld [hl],e - inc l - ld [hl],d - inc l - pop de - ld [hl],e - inc l - ld [hl],d - inc l - pop de - ld [hl],e - inc l - ld [hl],d - inc l - pop de - ld [hl],e - inc l - ld [hl],d - inc l - pop de - ld [hl],e - inc l - ld [hl],d - inc l - pop de - ld [hl],e - inc l - ld [hl],d - inc l - pop de - ld [hl],e - inc l - ld [hl],d - inc l - pop de - ld [hl],e - inc l - ld [hl],d - inc l - pop de - ld [hl],e - inc l - ld [hl],d - ld a,13 - add l - ld l,a - jr nc,.noCarry - inc h -.noCarry + add hl, de dec b - jr nz,TransferBgRows - ld a,[H_SPTEMP] - ld h,a - ld a,[H_SPTEMP + 1] - ld l,a - ld sp,hl ; restore stack pointer + jr nz, .y ret -; Copies [H_VBCOPYBGNUMROWS] rows from H_VBCOPYBGSRC to H_VBCOPYBGDEST. -; If H_VBCOPYBGSRC is XX00, the transfer is disabled. -VBlankCopyBgMap:: ; 1de1 (0:1de1) - ld a,[H_VBCOPYBGSRC] ; doubles as enabling byte - and a - ret z - ld hl,[sp + 0] - ld a,h - ld [H_SPTEMP],a - ld a,l - ld [H_SPTEMP + 1],a ; save stack pointer - ld a,[H_VBCOPYBGSRC] - ld l,a - ld a,[H_VBCOPYBGSRC + 1] - ld h,a - ld sp,hl - ld a,[H_VBCOPYBGDEST] - ld l,a - ld a,[H_VBCOPYBGDEST + 1] - ld h,a - ld a,[H_VBCOPYBGNUMROWS] - ld b,a - xor a - ld [H_VBCOPYBGSRC],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. - -; While we're here, convert to 2bpp. -; The process is straightforward: -; copy each byte twice. - - ld a, [H_VBCOPYDOUBLESIZE] - and a - ret z - - ld hl, [sp + 0] - ld a, h - ld [H_SPTEMP], a - ld a, l - ld [H_SPTEMP + 1], a +CopyScreenTileBufferToVRAM:: +; Copy wTileMap to the BG Map starting at b * $100. +; This is done in thirds of 6 rows, so it takes 3 frames. - ld a, [H_VBCOPYDOUBLESRC] - ld l, a - ld a, [H_VBCOPYDOUBLESRC + 1] - ld h, a - ld sp, hl - - ld a, [H_VBCOPYDOUBLEDEST] - ld l, a - ld a, [H_VBCOPYDOUBLEDEST + 1] - ld h, a + ld c, 6 - ld a, [H_VBCOPYDOUBLESIZE] - ld b, a - xor a ; transferred - ld [H_VBCOPYDOUBLESIZE], a - -.loop - rept 3 - pop de - ld [hl], e - inc l - ld [hl], e - inc l - ld [hl], d - inc l - ld [hl], d - inc l - endr + ld hl, $600 * 0 + ld de, wTileMap + 20 * 6 * 0 + call .setup + call DelayFrame - pop de - ld [hl], e - inc l - ld [hl], e - inc l - ld [hl], d - inc l - ld [hl], d - inc hl - dec b - jr nz, .loop + ld hl, $600 * 1 + ld de, wTileMap + 20 * 6 * 1 + call .setup + call DelayFrame - ld a, l - ld [H_VBCOPYDOUBLEDEST], a - ld a, h - ld [H_VBCOPYDOUBLEDEST + 1], a + ld hl, $600 * 2 + ld de, wTileMap + 20 * 6 * 2 + call .setup + jp DelayFrame - ld hl, [sp + 0] +.setup + ld a, d + ld [H_VBCOPYBGSRC+1], a + call GetRowColAddressBgMap ld a, l - ld [H_VBCOPYDOUBLESRC], a + ld [H_VBCOPYBGDEST], a ld a, h - ld [H_VBCOPYDOUBLESRC + 1], a - - ld a, [H_SPTEMP] - ld h, a - ld a, [H_SPTEMP + 1] - ld l, a - ld sp, hl - + ld [H_VBCOPYBGDEST+1], a + ld a, c + ld [H_VBCOPYBGNUMROWS], a + ld a, e + ld [H_VBCOPYBGSRC], a ret - -VBlankCopy:: -; Copy [H_VBCOPYSIZE] 2bpp tiles -; from H_VBCOPYSRC to H_VBCOPYDEST. - -; Source and destination addresses -; are updated, so transfer can -; continue in subsequent calls. - - ld a, [H_VBCOPYSIZE] - and a - ret z - - ld hl, [sp + 0] - ld a, h - ld [H_SPTEMP], a - ld a, l - ld [H_SPTEMP + 1], a - - ld a, [H_VBCOPYSRC] - ld l, a - ld a, [H_VBCOPYSRC + 1] - ld h, a - ld sp, hl - - ld a, [H_VBCOPYDEST] - ld l, a - ld a, [H_VBCOPYDEST + 1] - ld h, a - - ld a, [H_VBCOPYSIZE] - ld b, a - xor a ; transferred - ld [H_VBCOPYSIZE], a - +ClearScreen:: +; Clear wTileMap, then wait +; for the bg map to update. + ld bc, 20 * 18 + inc b + ld hl, wTileMap + ld a, $7f .loop - rept 7 - pop de - ld [hl], e - inc l - ld [hl], d - inc l - endr - - pop de - ld [hl], e - inc l - ld [hl], d - inc hl - dec b - jr nz, .loop - - ld a, l - ld [H_VBCOPYDEST], a - ld a, h - ld [H_VBCOPYDEST + 1], a - - ld hl, [sp + 0] - ld a, l - ld [H_VBCOPYSRC], a - ld a, h - ld [H_VBCOPYSRC + 1], a - - ld a, [H_SPTEMP] - ld h, a - ld a, [H_SPTEMP + 1] - ld l, a - ld sp, hl - - ret - - -UpdateMovingBgTiles:: -; Animate water and flower -; tiles in the overworld. - - ld a, [$ffd7] - and a - ret z - - ld a, [$ffd8] - inc a - ld [$ffd8], a - cp 20 - ret c - cp 21 - jr z, .flower - - ld hl, vTileset + $14 * $10 - ld c, $10 - - ld a, [wd085] - inc a - and 7 - ld [wd085], a - - and 4 - jr nz, .left -.right - ld a, [hl] - rrca ld [hli], a dec c - jr nz, .right - jr .done -.left - ld a, [hl] - rlca - ld [hli], a - dec c - jr nz, .left -.done - ld a, [$ffd7] - rrca - ret nc - xor a - ld [$ffd8], a - ret - -.flower - xor a - ld [$ffd8], a - - ld a, [wd085] - and 3 - cp 2 - ld hl, FlowerTile1 - jr c, .copy - ld hl, FlowerTile2 - jr z, .copy - ld hl, FlowerTile3 -.copy - ld de, vTileset + $3 * $10 - ld c, $10 -.loop - ld a, [hli] - ld [de], a - inc de - dec c jr nz, .loop - ret - -FlowerTile1: INCBIN "gfx/tilesets/flower/flower1.2bpp" -FlowerTile2: INCBIN "gfx/tilesets/flower/flower2.2bpp" -FlowerTile3: INCBIN "gfx/tilesets/flower/flower3.2bpp" - - -SoftReset:: - call StopAllSounds - call GBPalWhiteOut - ld c, $20 - call DelayFrames - ; fallthrough - -Init:: -; Program init. - -rLCDC_DEFAULT EQU %11100011 -; * LCD enabled -; * Window tile map at $9C00 -; * Window display enabled -; * BG and window tile data at $8800 -; * BG tile map at $9800 -; * 8x8 OBJ size -; * OBJ display enabled -; * BG display enabled - - di - - xor a - ld [rIF], a - ld [rIE], a - ld [$ff43], a - ld [$ff42], a - ld [$ff01], a - ld [$ff02], a - ld [$ff4b], a - ld [$ff4a], a - ld [$ff06], a - ld [$ff07], a - ld [$ff47], a - ld [$ff48], a - ld [$ff49], a - - ld a, rLCDC_ENABLE_MASK - ld [rLCDC], a - call DisableLCD - - ld sp, wStack - - ld hl, wc000 ; start of WRAM - ld bc, $2000 ; size of WRAM -.loop - ld [hl], 0 - inc hl - dec bc - ld a, b - or c - jr nz, .loop - - call ClearVram - - ld hl, $ff80 - ld bc, $ffff - $ff80 - call FillMemory - - call ClearSprites - - ld a, Bank(WriteDMACodeToHRAM) - ld [H_LOADEDROMBANK], a - ld [MBC3RomBank], a - call WriteDMACodeToHRAM - - xor a - ld [$ffd7], a - ld [$ff41], a - ld [$ffae], a - ld [$ffaf], a - ld [$ff0f], a - ld a, 1 << VBLANK + 1 << TIMER + 1 << SERIAL - ld [rIE], a - - ld a, 144 ; move the window off-screen - ld [$ffb0], a - ld [rWY], a - ld a, 7 - ld [rWX], a - - ld a, $ff - ld [$ffaa], a - - ld h, vBGMap0 / $100 - call ClearBgMap - ld h, vBGMap1 / $100 - call ClearBgMap - - ld a, rLCDC_DEFAULT - ld [rLCDC], a - ld a, 16 - ld [hSoftReset], a - call StopAllSounds - - ei - - ld a, $40 ; PREDEF_SGB_BORDER - call Predef - - ld a, $1f - ld [wc0ef], a - ld [wc0f0], a - ld a, $9c - ld [$ffbd], a - xor a - ld [$ffbc], a - dec a - ld [wcfcb], a - - ld a, $32 ; PREDEF_INTRO - call Predef - - call DisableLCD - call ClearVram - call GBPalNormal - call ClearSprites - ld a, rLCDC_DEFAULT - ld [rLCDC], a - - jp SetDefaultNamesBeforeTitlescreen - -ClearVram: - ld hl, $8000 - ld bc, $2000 - xor a - jp FillMemory - - -StopAllSounds:: - ld a, Bank(Func_9876) - ld [wc0ef], a - ld [wc0f0], a - xor a - ld [wMusicHeaderPointer], a - ld [wc0ee], a - ld [wcfca], a - dec a - jp PlaySound - - -VBlank:: - - push af - push bc - push de - push hl - - ld a, [H_LOADEDROMBANK] - ld [wd122], a - - ld a, [$ffae] - ld [rSCX], a - ld a, [$ffaf] - ld [rSCY], a - - ld a, [wd0a0] - and a - jr nz, .ok - ld a, [$ffb0] - ld [rWY], a -.ok - - call AutoBgMapTransfer - call VBlankCopyBgMap - call RedrawExposedScreenEdge - call VBlankCopy - call VBlankCopyDouble - call UpdateMovingBgTiles - call $ff80 ; hOAMDMA - ld a, Bank(PrepareOAMData) - ld [H_LOADEDROMBANK], a - ld [MBC3RomBank], a - call PrepareOAMData - - ; VBlank-sensitive operations end. - - call Random - - ld a, [H_VBLANKOCCURRED] - and a - jr z, .vblanked - xor a - ld [H_VBLANKOCCURRED], a -.vblanked - - ld a, [H_FRAMECOUNTER] - and a - jr z, .decced - dec a - ld [H_FRAMECOUNTER], a -.decced - - call Func_28cb - - ld a, [wc0ef] ; music ROM bank - ld [H_LOADEDROMBANK], a - ld [MBC3RomBank], a - - cp BANK(Func_9103) - jr nz, .notbank2 -.bank2 - call Func_9103 - jr .afterMusic -.notbank2 - cp 8 - jr nz, .bank1F -.bank8 - call Func_2136e - call Func_21879 - jr .afterMusic -.bank1F - call Func_7d177 -.afterMusic - - callba Func_18dee ; keep track of time played - - ld a, [$fff9] - and a - call z, ReadJoypad - - ld a, [wd122] - ld [H_LOADEDROMBANK], a - ld [MBC3RomBank], a - - pop hl - pop de - pop bc - pop af - reti - - -DelayFrame:: -; Wait for the next vblank interrupt. -; As a bonus, this saves battery. - -NOT_VBLANKED EQU 1 - - ld a, NOT_VBLANKED - ld [H_VBLANKOCCURRED], a -.halt - ; XXX this is a hack--rgbasm adds - ; a nop after halts by default. - db $76 ; halt - - ld a, [H_VBLANKOCCURRED] - and a - jr nz, .halt - ret - - -; These routines manage gradual fading -; (e.g., entering a doorway) -LoadGBPal:: ; 20ba (0:20ba) - ld a,[wd35d] ;tells if cur.map is dark (requires HM5_FLASH?) - ld b,a - ld hl,GBPalTable_00 ;16 - ld a,l - sub b - ld l,a - jr nc,.jr0 - dec h -.jr0 - ld a,[hli] - ld [rBGP],a - ld a,[hli] - ld [rOBP0],a - ld a,[hli] - ld [rOBP1],a - ret - -GBFadeOut1:: ; 20d1 (0:20d1) - ld hl,IncGradGBPalTable_01 ;0d - ld b,$04 - jr GBFadeOutCommon - -GBFadeOut2:: ; 20d8 (0:20d8) - ld hl,IncGradGBPalTable_02 ;1c - ld b,$03 - -GBFadeOutCommon:: ; 20dd (0:20dd) - ld a,[hli] - ld [rBGP],a - ld a,[hli] - ld [rOBP0],a - ld a,[hli] - ld [rOBP1],a - ld c,8 - call DelayFrames dec b - jr nz,GBFadeOutCommon - ret + jr nz, .loop + jp Delay3 -GBFadeIn1:: ; 20ef (0:20ef) - ld hl,DecGradGBPalTable_01 ;18 - ld b,$04 - jr GBFadeInCommon -GBFadeIn2:: ; 20f6 (0:20f6) - ld hl,DecGradGBPalTable_02 ;21 - ld b,$03 +INCLUDE "home/text.asm" +INCLUDE "home/vcopy.asm" +INCLUDE "home/init.asm" +INCLUDE "home/vblank.asm" +INCLUDE "home/fade.asm" -GBFadeInCommon:: ; 20fb (0:20fb) - ld a,[hld] - ld [rOBP1],a - ld a,[hld] - ld [rOBP0],a - ld a,[hld] - ld [rBGP],a - ld c,8 - call DelayFrames - dec b - jr nz,GBFadeInCommon - ret - -IncGradGBPalTable_01:: ; 210d (0:210d) - db %11111111 ;BG Pal - db %11111111 ;OBJ Pal 1 - db %11111111 ;OBJ Pal 2 - ;and so on... - db %11111110 - db %11111110 - db %11111000 - - db %11111001 - db %11100100 - db %11100100 -GBPalTable_00:: ; 2116 (0:2116) - db %11100100 - db %11010000 -DecGradGBPalTable_01:: ; 2118 (0:2118) - db %11100000 - ;19 - db %11100100 - db %11010000 - db %11100000 -IncGradGBPalTable_02:: ; 211c (0:211c) - db %10010000 - db %10000000 - db %10010000 - - db %01000000 - db %01000000 -DecGradGBPalTable_02:: ; 2121 (0:2121) - db %01000000 - - db %00000000 - db %00000000 - db %00000000 Serial:: ; 2125 (0:2125) push af @@ -5509,193 +1454,14 @@ Func_22fa:: ; 22fa (0:22fa) ld [$ff02], a ret + ; timer interrupt is apparently not invoked anyway Timer:: ; 2306 (0:2306) reti -Func_2307:: ; 2307 (0:2307) - call WaitForSoundToFinish - xor a - ld c, a - ld d, a - ld [wcfca], a - jr asm_2324 -Func_2312:: ; 2312 (0:2312) - ld c, $a - ld d, $0 - ld a, [wd72e] - bit 5, a - jr z, asm_2324 - xor a - ld [wcfca], a - ld c, $8 - ld d, c -asm_2324:: ; 2324 (0:2324) - ld a, [wd700] - and a - jr z, .asm_2343 - cp $2 - jr z, .asm_2332 - ld a, MUSIC_BIKE_RIDING - jr .asm_2334 -.asm_2332 - ld a, MUSIC_SURFING -.asm_2334 - ld b, a - ld a, d - and a - ld a, Bank(Func_7d8ea) - jr nz, .asm_233e - ld [wc0ef], a -.asm_233e - ld [wc0f0], a - jr .asm_234c -.asm_2343 - ld a, [wd35b] - ld b, a - call Func_2385 - jr c, .asm_2351 -.asm_234c - ld a, [wcfca] - cp b - ret z -.asm_2351 - ld a, c - ld [wMusicHeaderPointer], a - ld a, b - ld [wcfca], a - ld [wc0ee], a - jp PlaySound - -Func_235f:: ; 235f (0:235f) - ld a, [wc0ef] - ld b, a - cp $2 - jr nz, .checkForBank08 -.bank02 - ld hl, Func_9103 - jr .asm_2378 -.checkForBank08 - cp $8 - jr nz, .bank1F -.bank08 - ld hl, Func_21879 - jr .asm_2378 -.bank1F - ld hl, Func_7d177 -.asm_2378 - ld c, $6 -.asm_237a - push bc - push hl - call Bankswitch - pop hl - pop bc - dec c - jr nz, .asm_237a - ret - -Func_2385:: ; 2385 (0:2385) - ld a, [wd35c] - ld e, a - ld a, [wc0ef] - cp e - jr nz, .asm_2394 - ld [wc0f0], a - and a - ret -.asm_2394 - ld a, c - and a - ld a, e - jr nz, .asm_239c - ld [wc0ef], a -.asm_239c - ld [wc0f0], a - scf - ret +INCLUDE "home/audio.asm" -PlayMusic:: ; 23a1 (0:23a1) - ld b, a - ld [wc0ee], a - xor a - ld [wMusicHeaderPointer], a - ld a, c - ld [wc0ef], a - ld [wc0f0], a - ld a, b - -; plays music specified by a. If value is $ff, music is stopped -PlaySound:: ; 23b1 (0:23b1) - push hl - push de - push bc - ld b, a - ld a, [wc0ee] - and a - jr z, .asm_23c8 - xor a - ld [wc02a], a - ld [wc02b], a - ld [wc02c], a - ld [wc02d], a -.asm_23c8 - ld a, [wMusicHeaderPointer] - and a - jr z, .asm_23e3 - ld a, [wc0ee] - and a - jr z, .asm_2425 - xor a - ld [wc0ee], a - ld a, [wcfca] - cp $ff - jr nz, .asm_2414 - xor a - ld [wMusicHeaderPointer], a -.asm_23e3 - xor a - ld [wc0ee], a - ld a, [H_LOADEDROMBANK] - ld [$ffb9], a - ld a, [wc0ef] - ld [H_LOADEDROMBANK], a - ld [$2000], a - cp $2 - jr nz, .checkForBank08 -.bank02 - ld a, b - call Func_9876 - jr .asm_240b -.checkForBank08 - cp $8 - jr nz, .bank1F -.bank08 - ld a, b - call Func_22035 - jr .asm_240b -.bank1F - ld a, b - call Func_7d8ea -.asm_240b - ld a, [$ffb9] - ld [H_LOADEDROMBANK], a - ld [$2000], a - jr .asm_2425 -.asm_2414 - ld a, b - ld [wcfca], a - ld a, [wMusicHeaderPointer] - ld [wcfc8], a - ld [wcfc9], a - ld a, b - ld [wMusicHeaderPointer], a -.asm_2425 - pop bc - pop de - pop hl - ret UpdateSprites:: ; 2429 (0:2429) ld a, [wcfcb] @@ -5747,597 +1513,9 @@ Predef5CText:: ; 24f4 (0:24f4) call Predef jp TextScriptEnd -; bankswitches and runs _UncompressSpriteData -; bank is given in a, sprite input stream is pointed to in W_SPRITEINPUTPTR -UncompressSpriteData:: ; 24fd (0:24fd) - ld b, a - ld a, [H_LOADEDROMBANK] - push af - ld a, b - ld [H_LOADEDROMBANK], a - ld [$2000], a - ld a, $a - ld [$0], a - xor a - ld [$4000], a - call _UncompressSpriteData - pop af - ld [H_LOADEDROMBANK], a - ld [$2000], a - ret - -; initializes necessary data to load a sprite and runs UncompressSpriteDataLoop -_UncompressSpriteData:: ; 251a (0:251a) - ld hl, S_SPRITEBUFFER1 - ld c, (2*SPRITEBUFFERSIZE) % $100 - ld b, (2*SPRITEBUFFERSIZE) / $100 - xor a - call FillMemory ; clear sprite buffer 1 and 2 - ld a, $1 - ld [W_SPRITEINPUTBITCOUNTER], a - ld a, $3 - ld [W_SPRITEOUTPUTBITOFFSET], a - xor a - ld [W_SPRITECURPOSX], a - ld [W_SPRITECURPOSY], a - ld [W_SPRITELOADFLAGS], a ; wd0a8 - 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 [W_SPRITEHEIGHT], a - ld a, b - swap a - and $f - add a - add a - add a - ld [W_SPRITEWITDH], a - call ReadNextInputBit - ld [W_SPRITELOADFLAGS], a ; initialite bit1 to 0 and bit0 to the first input bit - ; this will load two chunks of data to S_SPRITEBUFFER1 and S_SPRITEBUFFER2 - ; 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 S_SPRITEBUFFER1 or S_SPRITEBUFFER2 -; 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:: ; 2556 (0:2556) - ld hl, S_SPRITEBUFFER1 - ld a, [W_SPRITELOADFLAGS] ; wd0a8 - bit 0, a - jr z, .useSpriteBuffer1 ; check which buffer to use - ld hl, S_SPRITEBUFFER2 -.useSpriteBuffer1 - call StoreSpriteOutputPointer - ld a, [W_SPRITELOADFLAGS] ; wd0a8 - 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 [W_SPRITEUNPACKMODE], 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:: ; 25d8 (0:25d8) - ld a, [W_SPRITEHEIGHT] - ld b, a - ld a, [W_SPRITECURPOSY] - inc a - cp b - jr z, .curColumnDone - ld [W_SPRITECURPOSY], a - ld a, [W_SPRITEOUTPUTPTR] - inc a - ld [W_SPRITEOUTPUTPTR], a - ret nz - ld a, [W_SPRITEOUTPUTPTR+1] - inc a - ld [W_SPRITEOUTPUTPTR+1], a - ret -.curColumnDone - xor a - ld [W_SPRITECURPOSY], a - ld a, [W_SPRITEOUTPUTBITOFFSET] - and a - jr z, .bitOffsetsDone - dec a - ld [W_SPRITEOUTPUTBITOFFSET], a - ld hl, W_SPRITEOUTPUTPTRCACHED - ld a, [hli] - ld [W_SPRITEOUTPUTPTR], a - ld a, [hl] - ld [W_SPRITEOUTPUTPTR+1], a - ret -.bitOffsetsDone - ld a, $3 - ld [W_SPRITEOUTPUTBITOFFSET], a - ld a, [W_SPRITECURPOSX] - add $8 - ld [W_SPRITECURPOSX], a - ld b, a - ld a, [W_SPRITEWITDH] - cp b - jr z, .allColumnsDone - ld a, [W_SPRITEOUTPUTPTR] - ld l, a - ld a, [W_SPRITEOUTPUTPTR+1] - ld h, a - inc hl - jp StoreSpriteOutputPointer -.allColumnsDone - pop hl - xor a - ld [W_SPRITECURPOSX], a - ld a, [W_SPRITELOADFLAGS] ; wd0a8 - bit 1, a - jr nz, .done ; test if there is one more sprite to go - xor $1 - set 1, a - ld [W_SPRITELOADFLAGS], a ; wd0a8 - jp UncompressSpriteDataLoop -.done - jp UnpackSprite - -; writes 2 bits (from a) to the output buffer (pointed to from W_SPRITEOUTPUTPTR) -WriteSpriteBitsToBuffer:: ; 2649 (0:2649) - ld e, a - ld a, [W_SPRITEOUTPUTBITOFFSET] - 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, [W_SPRITEOUTPUTPTR] - ld l, a - ld a, [W_SPRITEOUTPUTPTR+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:: ; 2670 (0:2670) - ld a, [W_SPRITEINPUTBITCOUNTER] - dec a - jr nz, .curByteHasMoreBitsToRead - call ReadNextInputByte - ld [W_SPRITEINPUTCURBYTE], a - ld a, $8 -.curByteHasMoreBitsToRead - ld [W_SPRITEINPUTBITCOUNTER], a - ld a, [W_SPRITEINPUTCURBYTE] - rlca - ld [W_SPRITEINPUTCURBYTE], a - and $1 - ret -; reads next byte from input stream and returns it in a -ReadNextInputByte:: ; 268b (0:268b) - ld a, [W_SPRITEINPUTPTR] - ld l, a - ld a, [W_SPRITEINPUTPTR+1] - ld h, a - ld a, [hli] - ld b, a - ld a, l - ld [W_SPRITEINPUTPTR], a - ld a, h - ld [W_SPRITEINPUTPTR+1], a - ld a, b - ret +INCLUDE "home/pic.asm" -; the nth item is 2^n - 1 -LengthEncodingOffsetList:: ; 269f (0:269f) - 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:: ; 26bf (0:26bf) - ld a, [W_SPRITEUNPACKMODE] - cp $2 - jp z, UnpackSpriteMode2 - and a - jp nz, XorSpriteChunks - ld hl, S_SPRITEBUFFER1 - call SpriteDifferentialDecode - ld hl, S_SPRITEBUFFER2 - ; 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:: ; 26d4 (0:26d4) - xor a - ld [W_SPRITECURPOSX], a - ld [W_SPRITECURPOSY], a - call StoreSpriteOutputPointer - ld a, [W_SPRITEFLIPPED] - 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 [W_SPRITEDECODETABLE0PTR], a - ld a, h - ld [W_SPRITEDECODETABLE0PTR+1], a - ld a, e - ld [W_SPRITEDECODETABLE1PTR], a - ld a, d - ld [W_SPRITEDECODETABLE1PTR+1], a - ld e, $0 ; last decoded nybble, initialized to 0 -.decodeNextByteLoop - ld a, [W_SPRITEOUTPUTPTR] - ld l, a - ld a, [W_SPRITEOUTPUTPTR+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, [W_SPRITEOUTPUTPTR] - ld l, a - ld a, [W_SPRITEOUTPUTPTR+1] - ld h, a - ld a, b - ld [hl], a ; write back decoded data - ld a, [W_SPRITEHEIGHT] - add l ; move on to next column - jr nc, .noCarry - inc h -.noCarry - ld [W_SPRITEOUTPUTPTR], a - ld a, h - ld [W_SPRITEOUTPUTPTR+1], a - ld a, [W_SPRITECURPOSX] - add $8 - ld [W_SPRITECURPOSX], a - ld b, a - ld a, [W_SPRITEWITDH] - cp b - jr nz, .decodeNextByteLoop ; test if current row is done - xor a - ld e, a - ld [W_SPRITECURPOSX], a - ld a, [W_SPRITECURPOSY] ; move on to next row - inc a - ld [W_SPRITECURPOSY], a - ld b, a - ld a, [W_SPRITEHEIGHT] - cp b - jr z, .done ; test if all rows finished - ld a, [W_SPRITEOUTPUTPTRCACHED] - ld l, a - ld a, [W_SPRITEOUTPUTPTRCACHED+1] - ld h, a - inc hl - call StoreSpriteOutputPointer - jr .decodeNextByteLoop -.done - xor a - ld [W_SPRITECURPOSY], 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:: ; 276d (0:276d) - srl a ; c=a%2, a/=2 - ld c, $0 - jr nc, .evenNumber - ld c, $1 -.evenNumber - ld l, a - ld a, [W_SPRITEFLIPPED] - 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, [W_SPRITEDECODETABLE0PTR] - ld l, a - ld a, [W_SPRITEDECODETABLE0PTR+1] - jr .tableLookup -.initialValue1 - ld a, [W_SPRITEDECODETABLE1PTR] - ld l, a - ld a, [W_SPRITEDECODETABLE1PTR+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:: ; 27a7 (0:27a7) - 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:: ; 27af (0:27af) - 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:: ; 27b7 (0:27b7) - 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:: ; 27bf (0:27bf) - 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:: ; 27c7 (0:27c7) - xor a - ld [W_SPRITECURPOSX], a - ld [W_SPRITECURPOSY], a - call ResetSpriteBufferPointers - ld a, [W_SPRITEOUTPUTPTR] ; points to buffer 1 or 2, depending on flags - ld l, a - ld a, [W_SPRITEOUTPUTPTR+1] - ld h, a - call SpriteDifferentialDecode ; decode buffer 1 or 2, depending on flags - call ResetSpriteBufferPointers - ld a, [W_SPRITEOUTPUTPTR] ; source buffer, points to buffer 1 or 2, depending on flags - ld l, a - ld a, [W_SPRITEOUTPUTPTR+1] - ld h, a - ld a, [W_SPRITEOUTPUTPTRCACHED] ; destination buffer, points to buffer 2 or 1, depending on flags - ld e, a - ld a, [W_SPRITEOUTPUTPTRCACHED+1] - ld d, a -.xorChunksLoop - ld a, [W_SPRITEFLIPPED] - 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, [W_SPRITECURPOSY] - inc a - ld [W_SPRITECURPOSY], a ; go to next row - ld b, a - ld a, [W_SPRITEHEIGHT] - cp b - jr nz, .xorChunksLoop ; test if column finished - xor a - ld [W_SPRITECURPOSY], a - ld a, [W_SPRITECURPOSX] - add $8 - ld [W_SPRITECURPOSX], a ; go to next column - ld b, a - ld a, [W_SPRITEWITDH] - cp b - jr nz, .xorChunksLoop ; test if all columns finished - xor a - ld [W_SPRITECURPOSX], a - ret - -; reverses the bits in the nybble given in register a -ReverseNybble:: ; 2837 (0:2837) - ld de, NybbleReverseTable - add e - ld e, a - jr nc, .asm_283f - inc d -.asm_283f - ld a, [de] - ret - -; resets sprite buffer pointers to buffer 1 and 2, depending on W_SPRITELOADFLAGS -ResetSpriteBufferPointers:: ; 2841 (0:2841) - ld a, [W_SPRITELOADFLAGS] ; wd0a8 - bit 0, a - jr nz, .buffer2Selected - ld de, S_SPRITEBUFFER1 - ld hl, S_SPRITEBUFFER2 - jr .storeBufferPointers -.buffer2Selected - ld de, S_SPRITEBUFFER2 - ld hl, S_SPRITEBUFFER1 -.storeBufferPointers - ld a, l - ld [W_SPRITEOUTPUTPTR], a - ld a, h - ld [W_SPRITEOUTPUTPTR+1], a - ld a, e - ld [W_SPRITEOUTPUTPTRCACHED], a - ld a, d - ld [W_SPRITEOUTPUTPTRCACHED+1], a - ret - -; maps each nybble to its reverse -NybbleReverseTable:: ; 2867 (0:2867) - 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:: ; 2877 (0:2877) - call ResetSpriteBufferPointers - ld a, [W_SPRITEFLIPPED] - push af - xor a - ld [W_SPRITEFLIPPED], a ; temporarily clear flipped flag for decoding the destination chunk - ld a, [W_SPRITEOUTPUTPTRCACHED] - ld l, a - ld a, [W_SPRITEOUTPUTPTRCACHED+1] - ld h, a - call SpriteDifferentialDecode - call ResetSpriteBufferPointers - pop af - ld [W_SPRITEFLIPPED], a - jp XorSpriteChunks - -; stores hl into the output pointers -StoreSpriteOutputPointer:: ; 2897 (0:2897) - ld a, l - ld [W_SPRITEOUTPUTPTR], a - ld [W_SPRITEOUTPUTPTRCACHED], a - ld a, h - ld [W_SPRITEOUTPUTPTR+1], a - ld [W_SPRITEOUTPUTPTRCACHED+1], a - ret ResetPlayerSpriteData:: ; 28a6 (0:28a6) ld hl, wSpriteStateData1 @@ -9982,56 +5160,7 @@ Random:: ret -Predef:: -; Call predefined function a. -; To preserve other registers, have the -; destination call GetPredefRegisters. - - ; Save the predef id for GetPredefPointer. - ld [wPredefID], a - - ; A hack for LoadDestinationWarpPosition. - ; See Func_c754 (predef $19). - ld a, [H_LOADEDROMBANK] - ld [wPredefParentBank], a - - push af - ld a, BANK(GetPredefPointer) - ld [H_LOADEDROMBANK], a - ld [$2000], a - - call GetPredefPointer - - ld a, [wPredefBank] - ld [H_LOADEDROMBANK], a - ld [$2000], a - - ld de, .done - push de - jp [hl] -.done - - pop af - ld [H_LOADEDROMBANK], a - ld [$2000], a - ret - -GetPredefRegisters:: -; Restore the contents of register pairs -; when GetPredefPointer was called. - ld a, [wPredefRegisters + 0] - ld h, a - ld a, [wPredefRegisters + 1] - ld l, a - ld a, [wPredefRegisters + 2] - ld d, a - ld a, [wPredefRegisters + 3] - ld e, a - ld a, [wPredefRegisters + 4] - ld b, a - ld a, [wPredefRegisters + 5] - ld c, a - ret +INCLUDE "home/predef.asm" Func_3ead:: ; 3ead (0:3ead) |