iigs-game-engine/demos/kfest-2022/demo-9/App.Main.s
2023-03-06 14:39:38 -06:00

675 lines
18 KiB
ArmAsm

; Test driver to exercise graphics routines.
REL
DSK MAINSEG
use Locator.Macs
use Load.Macs
use Mem.Macs
use Misc.Macs
use Util.Macs
use EDS.GSOS.Macs
use GTE.Macs
mx %00
tiledata EXT ; tileset buffer
TileSetPalette EXT
; Keycodes
LEFT_ARROW equ $08
RIGHT_ARROW equ $15
UP_ARROW equ $0B
DOWN_ARROW equ $0A
; Direct page space
MyUserId equ 0
BankLoad equ 2
StartX equ 4
StartY equ 6
TileMapWidth equ 8
TileMapHeight equ 10
ScreenWidth equ 12
ScreenHeight equ 14
MaxGlobalX equ 16
MaxGlobalY equ 18
MaxBG0X equ 20
MaxBG0Y equ 22
OldOneSecondCounter equ 26
appTmp0 equ 28
appTmp1 equ 30
appTmp2 equ 32
PlayerX equ 34
PlayerY equ 36
PlayerXVel equ 38
PlayerYVel equ 40
PlayerStanding equ 42
PlayerGlobalX equ 44
PlayerGlobalY equ 46
LastHFlip equ 48
SpriteFrame equ 50
SpriteToggle equ 52
SpriteCount equ 54
phk
plb
sta MyUserId ; GS/OS passes the memory manager user ID for the application into the program
tdc
sta MyDirectPage ; Keep a copy for the overlay callback
_MTStartUp ; GTE requires the miscellaneous toolset to be running
lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER ; +ENGINE_MODE_DYN_TILES
jsr GTEStartUp ; Load and install the GTE User Tool
; Initialize local variables
stz StartX
stz StartY
stz frameCount
stz bg1offset
stz LastHFlip
stz SpriteCount
stz SpriteToggle
; Initialize the graphics screen playfield
pea #160
pea #200
_GTESetScreenMode
; Load a tileset
pea #0
pea #511
pea #^tiledata
pea #tiledata
_GTELoadTileSet
pea $0000
pea #^TileSetPalette
pea #TileSetPalette
_GTESetPalette
; Set up our level data
jsr BG0SetUp
jsr SetLimits
jsr AllocBank ; Alloc 64KB for Load/Unpack
sta BankLoad ; Store "Bank Pointer"
ldx #BG1DataFile ; Load the background file into the bank
jsr LoadFile
pea #164 ; Fill everything
pea #200
pea #256
lda BankLoad
pha
pea $0000
pea $0000 ; default flags
_GTECopyPicToBG1
lda #193 ; Tile ID of '0'
jsr InitOverlay ; Initialize the status bar
pha
_GTEGetSeconds
pla
sta OldOneSecondCounter
jsr UdtOverlay
pha ; space for result
pea #15
pea ^UpdateBG1Offset
pea UpdateBG1Offset
pea $0000
_GTEAddTimer
pla
; Initialize the sprite's global position (this is tracked outside of the tile engine)
lda #16
sta PlayerGlobalX
sta PlayerX
lda MaxGlobalY
sec
sbc #64 ; 32 for tiles, 16 for sprite
sta PlayerGlobalY
sta PlayerY
stz PlayerXVel
stz PlayerYVel
; Create the sprites
HERO_SIZE equ {SPRITE_16X16}
HERO_FLAGS equ HERO_SIZE ; no extra H/V bits for now
HERO_FRAME_1 equ {SPRITE_16X16+1}
HERO_VBUFF_1 equ VBUFF_SPRITE_START+0*VBUFF_SPRITE_STEP
HERO_FRAME_2 equ {SPRITE_16X16+7}
HERO_VBUFF_2 equ VBUFF_SPRITE_START+1*VBUFF_SPRITE_STEP
HERO_FRAME_3 equ {SPRITE_16X8+65}
HERO_VBUFF_3 equ VBUFF_SPRITE_START+2*VBUFF_SPRITE_STEP
HERO_FRAME_4 equ {SPRITE_16X8+71}
HERO_VBUFF_4 equ VBUFF_SPRITE_START+3*VBUFF_SPRITE_STEP
HERO_SLOT_1 equ 1
HERO_SLOT_2 equ 2
pea HERO_FRAME_1
pea HERO_VBUFF_1
_GTECreateSpriteStamp
pea HERO_FRAME_2
pea HERO_VBUFF_2
_GTECreateSpriteStamp
pea HERO_FRAME_3
pea HERO_VBUFF_3
_GTECreateSpriteStamp
pea HERO_FRAME_4
pea HERO_VBUFF_4
_GTECreateSpriteStamp
DO 0
lda #SPRITE_16X16
sta SpriteFlags1
lda #SPRITE_16X8
sta SpriteFlags2
ELSE
lda #SPRITE_16X16+SPRITE_COMPILED
sta SpriteFlags1
lda #SPRITE_16X8+SPRITE_COMPILED
sta SpriteFlags2
pha ; Space for result
pea HERO_SIZE
pea HERO_VBUFF_1
_GTECompileSpriteStamp
pla
sta HeroFrames1+2
sta HeroFrames1+6
pha ; Space for result
pea HERO_SIZE
pea HERO_VBUFF_2
_GTECompileSpriteStamp
pla
sta HeroFrames1+0
sta HeroFrames1+4
pha ; Space for result
pea HERO_SIZE
pea HERO_VBUFF_3
_GTECompileSpriteStamp
pla
sta HeroFrames2+2
sta HeroFrames2+6
pha ; Space for result
pea HERO_SIZE
pea HERO_VBUFF_4
_GTECompileSpriteStamp
pla
sta HeroFrames2+0
sta HeroFrames2+4
FIN
pea HERO_SLOT_1 ; Put the player in slot 1
lda SpriteFlags1
pha
lda HeroFrames1
pha
pei PlayerX
pei PlayerY
_GTEAddSprite
pea HERO_SLOT_2
lda SpriteFlags2
pha
lda HeroFrames2
pha
pei PlayerX
lda PlayerY
clc
adc #16
pha
_GTEAddSprite
EvtLoop
pha
_GTEReadControl
pla
jsr HandleKeys ; Do the generic key handlers
bcs :do_more
brl do_render
:do_more
bit #PAD_BUTTON_A
beq :no_a
pha
jsr handle_a
pla
:no_a
and #$007F
cmp #LEFT_ARROW
bne *+5
jmp handle_left
cmp #RIGHT_ARROW
bne *+5
jmp handle_right
cmp #' '
bne :not_stop
stz PlayerXVel
bra do_render
:not_stop
cmp #'d'
bne :not_d
lda StartX
cmp MaxBG0X
bcc *+5
brl do_render
inc StartX
pei StartX
pei StartY
_GTESetBG0Origin
brl do_render
:not_d
cmp #'a'
bne :not_a
lda StartX
bne *+5
brl do_render
dec StartX
pei StartX
pei StartY
_GTESetBG0Origin
brl do_render
:not_a
cmp #'s'
bne :not_s
lda StartY
cmp MaxBG0Y
bcs do_render
inc StartY
pei StartX
pei StartY
_GTESetBG0Origin
bra do_render
:not_s
cmp #'w'
bne :not_w
lda StartY
beq do_render
dec StartY
pei StartX
pei StartY
_GTESetBG0Origin
bra do_render
:not_w
do_render
jsr UpdatePlayerPos ; Apply forces
jsr ApplyCollisions ; Check if we run into things
jsr UpdateCameraPos ; Moves the screen
pea HERO_SLOT_1
pei PlayerX
pei PlayerY
_GTEMoveSprite ; Move the sprite to this local position
pea HERO_SLOT_2
pei PlayerX
lda PlayerY
clc
adc #16
pha
_GTEMoveSprite
lda StartX
lsr
pha
lda StartY
lsr
pha
_GTESetBG1Origin
; pea #RENDER_BG1_HORZ_OFFSET
pea #RENDER_WITH_SHADOWING
; pea #0
_GTERender
; Update the performance counters
inc frameCount
pha
_GTEGetSeconds
pla
cmp OldOneSecondCounter
beq :noudt
sta OldOneSecondCounter
jsr UdtOverlay
stz frameCount
:noudt
brl EvtLoop
handle_a
lda PlayerStanding
beq :no_jump
lda #-9
sta PlayerYVel
:no_jump rts
handle_left
lda PlayerXVel
bpl :ok
cmp #-4
bcc :out
:ok
dec PlayerXVel
:out
jmp do_render
handle_right lda PlayerXVel
bmi :ok
cmp #6
bcs :out
:ok
inc PlayerXVel
:out
jmp do_render
; Simple updates with gravity and collisions. It's important that eveything in this
; subroutine be done against the VBL tick count
UpdatePlayerPos
lda PlayerGlobalY
clc
adc PlayerYVel
bpl :not_neg_y
lda #0
:not_neg_y
cmp MaxGlobalY
bcc *+4
lda MaxGlobalY
sta PlayerGlobalY
lda PlayerGlobalX
clc
adc PlayerXVel
bpl :not_neg
lda #0
:not_neg
cmp MaxGlobalX
bcc *+4
lda MaxGlobalX
sta PlayerGlobalX
rts
ApplyCollisions
; Convert global to local coordinates
lda PlayerGlobalX
sec
sbc StartX
sta PlayerX
lda PlayerGlobalY
sec
sbc StartY
sta PlayerY
; Collision testing
inc PlayerYVel
stz PlayerStanding
; Check if the player is standing on the ground at their current local position
pha ; space for result
pei PlayerX
lda PlayerY
clc
adc #24
pha
_GTEGetTileAt
pla
; Decide if mario's feet are on a "ground" tile (blocks, pipes, etc.)
and #TILE_ID_MASK
cmp #64
bcc :not_ground
lda PlayerYVel
bmi :not_ground
lda PlayerGlobalY
and #$fff8
sta PlayerGlobalY
stz PlayerYVel ; Stop falling when we hit the ground
lda #1
sta PlayerStanding
bra :y_ok
:not_ground
lda PlayerYVel
bmi :y_ok
cmp #8
bcc :y_ok
lda #7
sta PlayerYVel
:y_ok
ldx LastHFlip ; Update sprite frame based on actions
lda PlayerXVel
beq :no_dxv
bpl :pos_dxv
ldx #SPRITE_HFLIP
bra :no_dxv
:pos_dxv
ldx #0
:no_dxv
sta PlayerXVel
stx LastHFlip
lda SpriteCount
eor SpriteToggle
sta SpriteCount
; If the player is standing and XVel != 0, pick a frame
ldx #2
lda PlayerXVel
beq :frame
jsr _GetVBLTicks
and #$0006
tax
:frame
pea HERO_SLOT_1
pei LastHFlip
lda HeroFrames1,x
pha
pea HERO_SLOT_2
pei LastHFlip
lda HeroFrames2,x
pha
_GTEUpdateSprite
_GTEUpdateSprite
rts
HeroFrames1 dw HERO_VBUFF_2,HERO_VBUFF_1,HERO_VBUFF_2,HERO_VBUFF_1
HeroFrames2 dw HERO_VBUFF_4,HERO_VBUFF_3,HERO_VBUFF_4,HERO_VBUFF_3
; Set the scroll position based on the global coordinates of the player
; Try to center the player on the screen
UpdateCameraPos
lda ScreenWidth
lsr
sta appTmp0
lda PlayerGlobalX
sec
sbc appTmp0
bpl :x_pos
lda #0
:x_pos cmp MaxBG0X
bcc :x_ok
lda MaxBG0X
:x_ok sta StartX
lda ScreenHeight
lsr
sta appTmp0
lda PlayerGlobalY
sec
sbc appTmp0
bpl :y_pos
lda #0
:y_pos cmp MaxBG0Y
bcc :y_ok
lda MaxBG0Y
:y_ok sta StartY
pei StartX
pei StartY
_GTESetBG0Origin
rts
; Timer callback to animate the background
UpdateBG1Offset
ldal bg1offset
pha
inc
inc
stal bg1offset
_GTESetBG1Displacement
rtl
bg1offset ds 2
; Exit code
Exit
_GTEShutDown
Quit
_QuitGS qtRec
bcs Fatal
Fatal brk $00
qtRec adrl $0000
da $00
; Sprite VBUFF / Compile tokens
SpriteFlags1 ds 2
SpriteFlags2 ds 2
; Color palette
MyDirectPage ds 2
SetLimits
pha ; Allocate space for width (in tiles), height (in tiles), pointer
pha
pha
pha
_GTEGetBG0TileMapInfo
pla
sta TileMapWidth
pla
sta TileMapHeight
pla
pla ; discard the pointer
pha ; Allocate space for x, y, width, height
pha
pha
pha
_GTEGetScreenInfo
pla
pla ; Discard screen corner
pla
sta ScreenWidth
pla
sta ScreenHeight
lda TileMapWidth
asl
asl
sta MaxGlobalX
sec
sbc ScreenWidth
sta MaxBG0X
lda TileMapHeight
asl
asl
asl
sta MaxGlobalY
sec
sbc ScreenHeight
sta MaxBG0Y
; Check if the current StartX and StartY are out of bounds
lda StartX
cmp MaxBG0X
bcc :x_ok
lda MaxBG0X
:x_ok pha
lda StartY
cmp MaxBG0Y
bcc :y_ok
lda MaxBG0Y
:y_ok pha
_GTESetBG0Origin
rts
; Load a binary file in the BG1 buffer
DoLoadBG1
lda BankLoad
ldx #BG1DataFile
jsr LoadFile
; ldx BankLoad
; lda #0
; ldy BG1DataBank
; jsl CopyBinToBG1
pea #256 ; fill the whole buffer
pea #208
pei BankLoad
pea $0008 ; skip header
_GTECopyPicToBG1
rts
_GetVBLTicks
PushLong #0
_GetTick
pla
plx
rts
BG1DataFile strl '1/bg1.bin'
frameCount equ 24
PUT ../StartUp.s
PUT ../../shell/Overlay.s
PUT gen/App.TileMapBG0.s