BudgetBuster/BudgetBuster.z80

1385 lines
21 KiB
Z80 Assembly

;****************************************************************************************************************************************************
;* KeepUp
;*
;****************************************************************************************************************************************************
;*
;*
;****************************************************************************************************************************************************
;****************************************************************************************************************************************************
;* Includes
;****************************************************************************************************************************************************
; system includes
INCLUDE "hardware.inc"
INCLUDE "sprite.inc"
INCLUDE "memory.z80"
INCLUDE "tiles.z80"
INCLUDE "map.z80"
INCLUDE "game over.z80"
;****************************************************************************************************************************************************
;* user data (constants)
;****************************************************************************************************************************************************
;****************************************************************************************************************************************************
;* equates
;****************************************************************************************************************************************************
SpriteAttr Player
SpriteAttr Bullet
SpriteAttr Ghost1
;****************************************************************************************************************************************************
;* cartridge header
;****************************************************************************************************************************************************
SECTION "Org $00",ROM0[$00]
RST_00:
jp $100
SECTION "Org $08",ROM0[$08]
RST_08:
jp $100
SECTION "Org $10",ROM0[$10]
RST_10:
jp $100
SECTION "Org $18",ROM0[$18]
RST_18:
jp $100
SECTION "Org $20",ROM0[$20]
RST_20:
jp $100
SECTION "Org $28",ROM0[$28]
RST_28:
jp $100
SECTION "Org $30",ROM0[$30]
RST_30:
jp $100
SECTION "Org $38",ROM0[$38]
RST_38:
jp $100
SECTION "V-Blank IRQ Vector",ROM0[$40]
VBL_VECT:
call VBLANK_CODE
reti
SECTION "LCD IRQ Vector",ROM0[$48]
LCD_VECT:
reti
SECTION "Timer IRQ Vector",ROM0[$50]
TIMER_VECT:
reti
SECTION "Serial IRQ Vector",ROM0[$58]
SERIAL_VECT:
reti
SECTION "Joypad IRQ Vector",ROM0[$60]
JOYPAD_VECT:
reti
SECTION "Start",ROM0[$100]
nop
jp Start
; $0104-$0133 (Nintendo logo - do _not_ modify the logo data here or the GB will not run the program)
DB $CE,$ED,$66,$66,$CC,$0D,$00,$0B,$03,$73,$00,$83,$00,$0C,$00,$0D
DB $00,$08,$11,$1F,$88,$89,$00,$0E,$DC,$CC,$6E,$E6,$DD,$DD,$D9,$99
DB $BB,$BB,$67,$63,$6E,$0E,$EC,$CC,$DD,$DC,$99,$9F,$BB,$B9,$33,$3E
; $0134-$013E (Game title - up to 11 upper case ASCII characters; pad with $00)
DB "BUSTER",0,0,0,0,0
;0123456789A
; $013F-$0142 (Product code - 4 ASCII characters, assigned by Nintendo, just leave blank)
DB " "
;0123
; $0143 (Color GameBoy compatibility code)
DB $00 ; $00 - DMG
; $80 - DMG/GBC
; $C0 - GBC Only cartridge
; $0144 (High-nibble of license code - normally $00 if $014B != $33)
DB $00
; $0145 (Low-nibble of license code - normally $00 if $014B != $33)
DB $00
; $0146 (GameBoy/Super GameBoy indicator)
DB $00 ; $00 - GameBoy
; $0147 (Cartridge type - all Color GameBoy cartridges are at least $19)
DB $09 ; ROM+RAM+BATTERY
; $0148 (ROM size)
DB $01 ; $01 - 512Kbit = 64Kbyte = 4 banks
; $0149 (RAM size)
DB $01 ; $01 - 64KByte
; $014A (Destination code)
DB $00 ; $01 - All others
; $00 - Japan
; $014B (Licensee code - this _must_ be $33)
DB $33 ; $33 - Check $0144/$0145 for Licensee code.
; $014C (Mask ROM version - handled by RGBFIX)
DB $00
; $014D (Complement check - handled by RGBFIX)
DB $00
; $014E-$014F (Cartridge checksum - handled by RGBFIX)
DW $00
;****************************************************************************************************************************************************
;* Program Start
;****************************************************************************************************************************************************
SECTION "Program Start",ROM0[$150]
Start::
; interrupt/stack pointer boilerplate
di
ld a,$01
ldh [$FF],a
ld sp,$FFFE
; clear pending interrupts
xor a
ldh [$0F],a
; wait for v-blank before continuing
halt
nop
; disable LCD screen for now
ldh [rLCDC],a
; clear out shadow OAM and room for a few variables
ld hl,_RAM
ld bc,$AB
call mem_Set
; copy OAM DMA code to HRAM where we can easily access it later
ld de,_HRAM
ld hl,dmacode
ld bc,dmaend-dmacode
call mem_Copy
; set bg palette and sprite palette 0
ld a,%11100100
ld [rBGP],a
ld [rOBP0],a
; load tiles and map
ld hl,TileLabel
call load_Tiles
ld hl,MapLabel
call load_Map
ld hl,GameOverLabel
ld de,_SCRN1+0+(SCRN_VY_B*0)
ld bc,32*18
call mem_Copy
; set up sound registers
ld a,%10000000
; Channel 1: Wave Pattern Duty = 50%
; Sound Length = 0 (unused)
ldh [$11],a
; Channel 1: Volume = 0/15
; Envelope Direction = Decrease (unused)
; Number of Envelop Sweep = 0 (disable)
xor a
ldh [$12],a
ld a,%01000000
; Channel 2: Wave Pattern Duty = 25%
; Sound Length = 0 (unused)
ldh [$16],a
; Channel 2: Volume = 0/15
; Envelope Direction = Decrease (unused)
; Number of Envelop Sweep = 0 (disable)
xor a
ldh [$17],a
; Channel 3: Muted
ldh [$1C],a
ld a,%01110111
; Channels 1, 2 and 3 enabled on both outputs
ldh [$25],a
; Set Channel 3 wave pattern to a 50% square wave at 8/15 amplitude
; When played at 100% volume, sounds the same as Channel 1
cpl
ld hl,$FF30
ld [hli],a ; \
ld [hli],a ; |
ld [hli],a ; |
ld [hli],a ; |-- First 16 samples of waveform = 0100
ld [hli],a ; |
ld [hli],a ; |
ld [hli],a ; |
ld [hli],a ; /
xor a
ld [hli],a ; \
ld [hli],a ; |
ld [hli],a ; |
ld [hli],a ; |-- Last 16 samples of waveform = 0000
ld [hli],a ; |
ld [hli],a ; |
ld [hli],a ; |
ld [hli],a ; /
; Channel 1: Sweep Time = 0 (disable)
; Sweep Increase/Decrease = Addition (unused)
; Number of sweep shift = 0 (unused)
ldh [$10],a
; clear pending interrupts
ldh [$0F],a
; turn interrupts and screen back on
ei
; /------------ ............LCD Display Enable: On
; |/----------- Window Tile Map Display Select: 9800-9BFF
; ||/---------- .........Window Display Enable: Off
; |||/--------- ..BG & Window Tile Data Select: 8000-8FFF
; ||||/-------- ....BG Tile Map Display Select: 9800-9BFF
; |||||/------- .............OBJ (Sprite) Size: 8x8
; ||||||/------ ...OBJ (Sprite) Display Enable: Off
; |||||||/----- ....................BG Display: On
ld a,%10010001
ld [rLCDC],a
ld a,$E1
ld [$FFD3],a
ld a,$D6
ld [$FFD4],a
ld a,$0A
ld [0],a
ld hl,$A000
ld a,[hl+]
push af
ld a,[hl+]
push af
ld a,[hl+]
push af
ld a,[hl+]
push af
ld a,[hl]
push af
xor a
ld [0],a
pop af
ld hl,$C0AA
ld [hl-],a
pop af
ld [hl-],a
pop af
ld [hl-],a
pop af
ld [hl-],a
pop af
ld [hl],a
xor a
add [hl]
inc hl
add [hl]
inc hl
add [hl]
inc hl
add [hl]
inc hl
cp [hl]
ld a,$00
ld [hl-],a
jr z,.checksumPass
ld [hl-],a
ld [hl-],a
ld [hl-],a
ld [hl],a
.checksumPass
; Put the player in its starting location
ld a,(SCRN_Y/2)+12
ld [PlayerYAddr],a
ld a,(SCRN_X/2)+4
ld [PlayerXAddr],a
; Set the player's appearance
ld a,$01
ld [PlayerTileNum],a
Main::
call Get_Keys
ld a,[$C0A0]
sub $1
jr nc,.setGlobalCounter
ld a,$05
.setGlobalCounter
ld [$C0A0],a
ld a,[$FF40]
and %00001000
jp z,.down
ld a,%01000110
and b
cp %01000110
jr nz,.dontEraseScore
ld a,$0a
ld [0],a
ld hl,$A000
inc [hl]
xor a
ld [0],a
ld hl,$C0A6
ld [hl+],a
ld [hl+],a
ld [hl+],a
ld [hl+],a
ld [hl],a
.dontEraseScore
ld a,%00001000
and b
jr z,.ghostOnMe
xor a
ld hl,$C0A2
ld [hl+],a
ld [hl+],a
ld [hl+],a
ld [hl],a
ld [$C0AA],a
; Put the player in its starting location
ld a,(SCRN_Y/2)+12
ld [PlayerYAddr],a
ld a,(SCRN_X/2)+4
ld [PlayerXAddr],a
; Set the player's appearance
ld a,$01
ld [PlayerTileNum],a
ld a,[$FF40]
and %11110111
ld [$FF40],a
ld hl,Ghost1TileNum
.eraseGhostLoop
ld [hl],$00
inc hl
inc hl
inc hl
inc hl
ld a,l
cp $2A
jr nz,.eraseGhostLoop
jr .down
.ghostOnMe
ld a,[PlayerXAddr]
ld b,a
ld a,[PlayerYAddr]
ld c,a
ld hl,Ghost1YAddr
.ghostOnMeLoop
ld a,l
cp $28
jp z,.direction
ld a,[hl+]
ld e,a
ld a,[hl+]
ld d,a
ld a,[hl+]
inc hl
cp $04
jr nz,.ghostOnMeLoop
ld a,d
cp b
jr nz,.ghostOnMeLoop
ld a,e
cp c
jr nz,.ghostOnMeLoop
dec hl
dec hl
ld [hl],$00
inc hl
inc hl
ld a,$04
ld [PlayerTileNum],a
xor a
ld [PlayerFlags],a
jr .ghostOnMeLoop
.down
ld a,%10000000
and b
jr z,.up
ld a,%00000001
and b
jr nz,.doneFacingDown
ld a,$01
ld [PlayerTileNum],a
ld a,[PlayerFlags]
or %01000000
and %11011111
ld [PlayerFlags],a
.doneFacingDown
push bc
ld a,[PlayerXAddr]
dec a
ld b,a
ld a,[PlayerYAddr]
sub $08
ld c,a
call Wall_At_Location
pop bc
jr nz,.left
push bc
ld a,[PlayerXAddr]
sub $08
ld b,a
ld a,[PlayerYAddr]
sub $08
ld c,a
call Wall_At_Location
pop bc
jr nz,.left
ld a,[PlayerYAddr]
inc a
ld [PlayerYAddr],a
jr .left
.up
ld a,%01000000
and b
jr z,.left
ld a,%00000001
and b
jr nz,.doneFacingUp
ld a,$01
ld [PlayerTileNum],a
ld a,[PlayerFlags]
and %10011111
ld [PlayerFlags],a
.doneFacingUp
push bc
ld a,[PlayerXAddr]
dec a
ld b,a
ld a,[PlayerYAddr]
sub $11
ld c,a
call Wall_At_Location
pop bc
jr nz,.left
push bc
ld a,[PlayerXAddr]
sub $08
ld b,a
ld a,[PlayerYAddr]
sub $11
ld c,a
call Wall_At_Location
pop bc
jr nz,.left
ld a,[PlayerYAddr]
dec a
ld [PlayerYAddr],a
.left
ld a,%00100000
and b
jr z,.right
ld a,%00000001
and b
jr nz,.doneFacingLeft
ld a,$02
ld [PlayerTileNum],a
ld a,[PlayerFlags]
or %00100000
and %10111111
ld [PlayerFlags],a
.doneFacingLeft
push bc
ld a,[PlayerXAddr]
sub $9
ld b,a
ld a,[PlayerYAddr]
sub $10
ld c,a
call Wall_At_Location
pop bc
jr nz,.shoot
push bc
ld a,[PlayerXAddr]
sub $9
ld b,a
ld a,[PlayerYAddr]
sub $9
ld c,a
call Wall_At_Location
pop bc
jr nz,.shoot
ld a,[PlayerXAddr]
dec a
ld [PlayerXAddr],a
jr .shoot
.right
ld a,%00010000
and b
jr z,.shoot
ld a,%00000001
and b
jr nz,.doneFacingRight
ld a,$02
ld [PlayerTileNum],a
ld a,[PlayerFlags]
and %10011111
ld [PlayerFlags],a
.doneFacingRight
push bc
ld a,[PlayerXAddr]
ld b,a
ld a,[PlayerYAddr]
sub $10
ld c,a
call Wall_At_Location
pop bc
jr nz,.shoot
push bc
ld a,[PlayerXAddr]
ld b,a
ld a,[PlayerYAddr]
sub $9
ld c,a
call Wall_At_Location
pop bc
jr nz,.shoot
ld a,[PlayerXAddr]
inc a
ld [PlayerXAddr],a
.shoot
ld a,%00000001
and b
jr z,.switch
ld a,[BulletTileNum]
or a
jr nz,.switch
call shoot_noise
ld a,$03
ld [BulletTileNum],a
ld a,[PlayerYAddr]
ld [BulletYAddr],a
ld a,[PlayerXAddr]
ld [BulletXAddr],a
ld a,[PlayerTileNum]
and %00000001
ld c,a
ld a,[PlayerFlags]
and %01100000
ld a,$00
jr z,.direction
ld a,%00000010
.direction
or c
sla a
sla a
sla a
sla a
sla a
ld c,a
ld a,[BulletFlags]
and %10011111
or c
ld [BulletFlags],a
.switch
ld a,%00000010
and b
jr z,.unpressB
ld a,[$C0A1]
or a
jr nz,.bulletDespawnWall
ld a,$01
ld [$C0A1],a
ld hl,Ghost1TileNum
.findCurrentSelected
ld a,[hl]
cp $04
jr z,.selectionFound
inc hl
inc hl
inc hl
inc hl
ld a,l
cp $2A
jr z,.bulletDespawnWall
jr .findCurrentSelected
.selectionFound
ld [hl],$06
ld a,$09
ld b,a
call Find_Next_Ghost
jr .bulletDespawnWall
.unpressB
xor a
ld [$C0A1],a
.bulletDespawnWall
ld a,[BulletXAddr]
sub $05
ld b,a
ld a,[BulletYAddr]
sub $0E
ld c,a
call Wall_At_Location
jr nz,.despawn
ld a,[BulletXAddr]
sub $04
ld b,a
ld a,[BulletYAddr]
sub $0E
ld c,a
call Wall_At_Location
jr nz,.despawn
ld a,[BulletXAddr]
sub $06
ld b,a
ld a,[BulletYAddr]
sub $0D
ld c,a
call Wall_At_Location
jr nz,.despawn
ld a,[BulletXAddr]
sub $03
ld b,a
ld a,[BulletYAddr]
sub $0D
ld c,a
call Wall_At_Location
jr nz,.despawn
ld a,[BulletXAddr]
sub $06
ld b,a
ld a,[BulletYAddr]
sub $0C
ld c,a
call Wall_At_Location
jr nz,.despawn
ld a,[BulletXAddr]
sub $03
ld b,a
ld a,[BulletYAddr]
sub $0C
ld c,a
call Wall_At_Location
jr nz,.despawn
ld a,[BulletXAddr]
sub $05
ld b,a
ld a,[BulletYAddr]
sub $0B
ld c,a
call Wall_At_Location
jr nz,.despawn
ld a,[BulletXAddr]
sub $05
ld b,a
ld a,[BulletYAddr]
sub $0B
ld c,a
call Wall_At_Location
jr z,.bulletMovement
.despawn
xor a
ld [BulletTileNum],a
.bulletMovement
ld a,[BulletFlags]
srl a
srl a
srl a
srl a
srl a
and %00000011
jr z,.bulletRight
dec a
jr z,.bulletUp
dec a
jr z,.bulletLeft
.bulletDown
ld a,[BulletYAddr]
add $03
ld [BulletYAddr],a
jr .bulletDespawnX
.bulletUp
ld a,[BulletYAddr]
sub $03
ld [BulletYAddr],a
jr .bulletDespawnX
.bulletRight
ld a,[BulletXAddr]
add $03
ld [BulletXAddr],a
jr .bulletDespawnX
.bulletLeft
ld a,[BulletXAddr]
sub $03
ld [BulletXAddr],a
.bulletDespawnX
ld a,[BulletXAddr]
sub $A7
jr c,.bulletDespawnY
xor a
ld [BulletTileNum],a
.bulletDespawnY
ld a,[BulletYAddr]
sub $9F
jr c,.moveGhosts
xor a
ld [BulletTileNum],a
.moveGhosts
ld hl,$C0A0
ld a,[hl]
or a
jr nz,.killGhosts
ld hl,$C00A
ld bc,$0006
.ghostLoop
ld a,l
dec hl
cp a,$2A
jr z,.killGhosts
ld a,[PlayerXAddr]
cp [hl]
jr z,.ghostY
ld a,[hl]
jr c,.xCarried
add $02
.xCarried
dec a
ld [hl],a
.ghostY
dec hl
ld a,[PlayerYAddr]
cp [hl]
jr z,.resetGhostLoop
ld a,[hl]
jr c,.yCarried
add $02
.yCarried
dec a
ld [hl],a
.resetGhostLoop
add hl,bc
jr .ghostLoop
.killGhosts
ld a,[BulletTileNum]
or a
jr z,.dieToGhosts
ld hl,$C00A
.killGhostLoop
ld a,l
cp $2A
jr z,.dieToGhosts
ld a,[hl]
or a
jr z,.resetGhostKillLoop
dec hl
ld a,$FF
add [hl]
ld b,a
sub $07
ld c,a
ld a,$FD
push hl
ld hl,BulletXAddr
add [hl]
pop hl
ld d,a
sub $03
ld e,a
call One_Dimensional_Hit_Detection
inc hl
jr z,.resetGhostKillLoop
dec hl
dec hl
ld a,$F7
add [hl]
ld b,a
sub $07
ld c,a
ld a,$F5
push hl
ld hl,BulletYAddr
add [hl]
pop hl
ld d,a
sub $03
ld e,a
call One_Dimensional_Hit_Detection
inc hl
inc hl
jr z,.resetGhostKillLoop
call hit_noise
call Increment_Score
ld a,[hl]
cp $04
jr nz,.skipGhostVisibility
ld a,$09
ld b,a
push hl
call Find_Next_Ghost
pop hl
.skipGhostVisibility
ld [hl],$0
xor a
ld [BulletTileNum],a
jr .dieToGhosts
.resetGhostKillLoop
ld bc,$0004
add hl,bc
jr .killGhostLoop
.dieToGhosts
ld a,[PlayerTileNum]
or a
jr z,.initGhostsVisibleLoop
cp $04
jr z,.initGhostsVisibleLoop
ld hl,$C00A
.playerKillLoop
ld a,l
cp $2A
jr z,.callRng
ld a,[hl]
or a
jr z,.resetPlayerKillLoop
dec hl
ld a,$FF
add [hl]
ld b,a
sub $07
ld c,a
ld a,$FF
push hl
ld hl,PlayerXAddr
add [hl]
pop hl
ld d,a
sub $07
ld e,a
call One_Dimensional_Hit_Detection
inc hl
jr z,.resetPlayerKillLoop
dec hl
dec hl
ld a,$F7
add [hl]
ld b,a
sub $07
ld c,a
ld a,$F7
push hl
ld hl,PlayerYAddr
add [hl]
pop hl
ld d,a
sub $07
ld e,a
call One_Dimensional_Hit_Detection
inc hl
inc hl
jr z,.resetPlayerKillLoop
ld a,[PlayerTileNum]
call die_noise
call Save_High
xor a
ld [PlayerTileNum],a
ld [BulletTileNum],a
ld a,[$FF40]
or %00001000
ld [$FF40],a
.initGhostsVisibleLoop
ld hl,Ghost1TileNum
.ghostsVisibleLoop
ld a,[hl]
cp $06
jr nz,.doNotAppear
ld [hl],$04
.doNotAppear
inc hl
inc hl
inc hl
inc hl
ld a,l
cp $2A
jr nz,.ghostsVisibleLoop
jr .callRng
.resetPlayerKillLoop
ld bc,$0004
add hl,bc
jr .playerKillLoop
.callRng
call Random_
ld a,[$FFD3]
cp $40
jr z,.spawnGhost
cp $33
jr z,.spawnGhost
cp $AB
jr z,.spawnGhost
cp $BA
jr nz,.wait
.spawnGhost
ld a,[$FFD4]
.modFortyEight
sub $48
jr nc,.modFortyEight
add $48
call ID_To_Coords
ld hl,Ghost1TileNum
ld de,$0004
.findGhostSlot
ld a,[hl]
or a
jr z,.ghostSlotFound
add hl,de
ld a,l
cp $2A
jr z,.wait ; too many ghosts! we're out of slots
jr .findGhostSlot
.ghostSlotFound
push hl
ld hl,Ghost1TileNum
.findVisibleGhost
ld a,[hl]
cp $04
jr z,.visibleGhostFound
add hl,de
ld a,l
cp $2A
jr z,.noVisibleGhost
jr .findVisibleGhost
.visibleGhostFound
ld a,$06
jr .finishSpawning
.noVisibleGhost
ld a,$04
.finishSpawning
pop hl
ld [hl],a
dec hl
sla b
sla b
sla b
ld a,$08
add b
ld [hl-],a
sla c
sla c
sla c
ld a,$10
add c
ld [hl],a
.wait
halt ; This is the loop where the code waits for a v-blank
nop
jp Main
VBLANK_CODE::
ld hl,$9A26
ld a,[$C0A2]
add $10
ld [hl+],a
ld a,[$C0A3]
add $10
ld [hl+],a
ld a,[$C0A4]
add $10
ld [hl+],a
ld a,[$C0A5]
add $10
ld [hl],a
ld hl,$9A30
ld a,[$C0A6]
add $10
ld [hl+],a
ld a,[$C0A7]
add $10
ld [hl+],a
ld a,[$C0A8]
add $10
ld [hl+],a
ld a,[$C0A9]
add $10
ld [hl],a
ld hl,$9E26
ld a,[$C0A2]
add $10
ld [hl+],a
ld a,[$C0A3]
add $10
ld [hl+],a
ld a,[$C0A4]
add $10
ld [hl+],a
ld a,[$C0A5]
add $10
ld [hl],a
ld hl,$9E30
ld a,[$C0A6]
add $10
ld [hl+],a
ld a,[$C0A7]
add $10
ld [hl+],a
ld a,[$C0A8]
add $10
ld [hl+],a
ld a,[$C0A9]
add $10
ld [hl],a
.end
jp _HRAM
; in: a = number from $00 to $47
; out: b = x of border tile, c = y of border tile
ID_To_Coords::
.topBorder
cp $14
jr nc,.bottomBorder
ld b,a
ld c,$00
ret
.bottomBorder
cp $28
jr nc,.leftBorder
sub $14
ld b,a
ld a,$11
ld c,a
ret
.leftBorder
cp $38
jr nc,.rightBorder
sub $28
ld c,a
ld b,$00
ret
.rightBorder
sub $38
ld c,a
ld b,$13
ret
Find_Next_Ghost::
dec b
ret z
inc hl
inc hl
inc hl
inc hl
ld a,l
cp $2A
jr nz,.dontWrap
ld hl,Ghost1TileNum
.dontWrap
ld a,[hl]
cp $06
jr nz,Find_Next_Ghost
ld [hl],$04
ret
; in: b = object 1 x1, c = object 1 x2,
; d = object 2 x1, e = object 2 x2
One_Dimensional_Hit_Detection::
ld a,d
push de
cp b
ld d,$00
jr nc,.dbNoCarry
inc d
.dbNoCarry
cp c
ld a,$00
jr nc,.dcNoCarry
inc a
.dcNoCarry
xor d
pop de
ret nz
ld a,e
cp b
ld d,$00
jr nc,.ebNoCarry
inc d
.ebNoCarry
cp c
ld a,$00
jr nc,.ecNoCarry
inc a
.ecNoCarry
xor d
ret
Increment_Score::
push hl
ld hl,$C0A5
call Increment_Digit
call Check_High
pop hl
ret
Increment_Digit::
ld a,[hl]
cp $09
jp z,.carry
inc a
ld [hl],a
ret
.carry
ld a,l
cp $A2
jr z,.cap
ld [hl],0
dec hl
jr Increment_Digit
.cap
ld a,$09
ld [$C0A3],a
ld [$C0A4],a
ld [$C0A5],a
ret
Check_High::
; i tried so hard to do something clever here but i kept being unable to convince myself it was right
; i don't care anymore, the function can be gross
ld a,[$C0A2]
ld b,a
ld a,[$C0A6]
cp b
jr z,.digitThree
jr c,.newHigh
ret
.digitThree
ld a,[$C0A3]
ld b,a
ld a,[$C0A7]
cp b
jr z,.digitTwo
jr c,.newHigh
ret
.digitTwo
ld a,[$C0A4]
ld b,a
ld a,[$C0A8]
cp b
jr z,.digitOne
jr c,.newHigh
ret
.digitOne
ld a,[$C0A5]
ld b,a
ld a,[$C0A9]
cp b
jr c,.newHigh
ret
.newHigh
ld a,$01
ld [$C0AA],a
ld a,[$C0A2]
ld [$C0A6],a
ld a,[$C0A3]
ld [$C0A7],a
ld a,[$C0A4]
ld [$C0A8],a
ld a,[$C0A5]
ld [$C0A9],a
ret
Save_High::
ld a,[$C0AA]
or a
ret z
ld hl,$C0A6
ld a,[hl+]
push af
ld a,[hl+]
push af
ld a,[hl+]
push af
ld a,[hl]
push af
xor a
add [hl]
dec hl
add [hl]
dec hl
add [hl]
dec hl
add [hl]
push af
ld a,$0A
ld [0],a
pop af
ld hl,$A004
ld [hl-],a
pop af
ld [hl-],a
pop af
ld [hl-],a
pop af
ld [hl-],a
pop af
ld [hl],a
xor a
ld [0],a
ret
; in: b = x, c = y
; out: hl = tile reference
Tile_At_Location::
srl b
srl b
srl b
ld a,%11111000
and c
ld e,a
sla e
sla e
srl a
srl a
srl a
srl a
srl a
srl a
ld d,a
ld h,d
ld l,e
ld c,b
ld b,$00
add hl,bc
ld bc,MapLabel
add hl,bc
ret
; in: b = x, c = y
; out: a = %10000000 if wall, else 0
; sets Z flag if not wall, else resets
Wall_At_Location::
call Tile_At_Location
ld a,[hl]
cp $05
push af
pop bc
ld a,c
and %10000000
ret
shoot_noise::
ld a,%10110100
ldh [$11],a
ld a,%11000011
ldh [$12],a
ld a,%01110010
ldh [$13],a
ld a,%11000110
ldh [$14],a
ret
hit_noise::
ld a,%10110100
ldh [$16],a
ld a,%11000011
ldh [$17],a
ld a,%11010110
ldh [$18],a
ld a,%11000110
ldh [$19],a
ret
die_noise::
ld a,%10010100
ldh [$16],a
ld a,%11000011
ldh [$17],a
ld a,%01100011
ldh [$18],a
ld a,%11000101
ldh [$19],a
ret
Random_::
; Generate a random 16-bit value.
ld a, [rDIV]
ld b, a
ld a, [$FFD3]
adc b
ld [$FFD3], a
ld a, [rDIV]
ld b, a
ld a, [$FFD4]
sbc b
ld [$FFD4], a
ret
load_Tiles::
ld de,_VRAM
ld bc,16*26
jp mem_Copy
load_Map::
ld de,_SCRN0+0+(SCRN_VY_B*0)
ld bc,32*32
jp mem_Copy
dmacode::
ld a,_RAM/$100
ldh [rDMA],a ; Start DMA
ld a,$28 ; 160ns
dma_wait::
dec a
jr nz,dma_wait
ld a,[rLCDC]
or %00000010
ld [rLCDC],a
ret
dmaend::
; v^<>SsBA
Get_Keys::
ld a,$20
ld [$ff00],a
ld a,[$ff00]
ld a,[$ff00] ; wait a few cycles
cpl
and $0f
swap a
ld b,a
ld a,$10
ld [$ff00],a
ld a,[$ff00]
ld a,[$ff00]
ld a,[$ff00]
ld a,[$ff00]
ld a,[$ff00]
ld a,[$ff00] ; wait a few more cycles
cpl
and $0f
or b
ld b,a
ld a,$30
ld [$ff00],a ; reset joypad
ret
;*** End Of File ***