keen1: initial mostly working proof

This commit is contained in:
Vince Weaver 2024-03-10 00:44:20 -05:00
parent 2cf26ac28d
commit a091e8e7ec
33 changed files with 3482 additions and 16 deletions

98
games/keen/Makefile Normal file
View File

@ -0,0 +1,98 @@
include ../../Makefile.inc
DOS33 = ../../utils/dos33fs-utils/dos33
DOS33_RAW = ../../utils/dos33fs-utils/dos33_raw
B2D = ../../utils/bmp2dhr/b2d
PNG2GR = ../../utils/gr-utils/png2gr
LZSA = ~/research/lzsa/lzsa/lzsa
TOKENIZE = ../../utils/asoft_basic-utils/tokenize_asoft
EMPTY_DISK = ../../empty_disk/empty.dsk
all: keen.dsk
keen.dsk: HELLO LOADER KEEN_TITLE KEEN_LEVEL1
#KEEN_LEVEL2
cp $(EMPTY_DISK) keen.dsk
$(DOS33) -y keen.dsk SAVE A HELLO
$(DOS33) -y keen.dsk BSAVE -a 0x1000 LOADER
$(DOS33) -y keen.dsk BSAVE -a 0x4000 KEEN_TITLE
$(DOS33) -y keen.dsk BSAVE -a 0x2000 KEEN_LEVEL1
# $(DOS33) -y keen.dsk BSAVE -a 0x2000 KEEN_LEVEL2
###
HELLO: hello.bas
$(TOKENIZE) < hello.bas > HELLO
####
LOADER: loader.o
ld65 -o LOADER loader.o -C ../../linker_scripts/apple2_1000.inc
loader.o: loader.s
ca65 -o loader.o loader.s -l loader.lst
####
KEEN_TITLE: keen_title.o
ld65 -o KEEN_TITLE keen_title.o -C ../../linker_scripts/apple2_4000.inc
keen_title.o: keen_title.s zp.inc hardware.inc init_vars.s \
zx02_optim.s \
graphics/keen1_title.hgr.zx02
ca65 -o keen_title.o keen_title.s -l keen_title.lst
####
KEEN_LEVEL1: keen_level1.o
ld65 -o KEEN_LEVEL1 keen_level1.o -C ../../linker_scripts/apple2_2000.inc
keen_level1.o: keen_level1.s zp.inc hardware.inc \
print_help.s gr_fast_clear.s quit_yn.s text_drawbox.s level_end.s \
enemies_level1.s actions_level1.s item_level1.s \
graphics/keen_graphics.inc \
maps/level1_map.lzsa \
status_bar.s draw_keen.s move_keen.s gr_putsprite_crop.s \
draw_tilemap.s \
sound_effects.s speaker_tone.s \
keyboard.s handle_laser.s
ca65 -o keen_level1.o keen_level1.s -l keen_level1.lst
####
KEEN_LEVEL2: keen_level2.o
ld65 -o KEEN_LEVEL2 keen_level2.o -C ../../linker_scripts/apple2_2000.inc
keen_level2.o: keen_level2.s zp.inc hardware.inc \
print_help.s gr_fast_clear.s quit_yn.s text_drawbox.s level_end.s \
enemies_level2.s actions_level2.s item_level2.s \
graphics/keen_graphics.inc keen_sprites.inc \
maps/level2_map.lzsa \
status_bar.s draw_keen.s move_keen.s gr_putsprite_crop.s \
draw_tilemap.s \
sound_effects.s speaker_tone.s \
keyboard.s handle_laser.s
ca65 -o keen_level2.o keen_level2.s -l keen_level2.lst
####
graphics/keen1_title.hgr.zx02:
cd graphics && make
graphics/keen_graphics.inc:
cd graphics && make
maps/level1_map.lzsa:
cd maps && make
####
clean:
rm -f *~ *.o *.lst HELLO KEEN_TITLE KEEN_LEVEL1
cd graphics && make clean
cd maps && make clean
# cd title && make clean

204
games/keen/actions_level1.s Normal file
View File

@ -0,0 +1,204 @@
; someone pressed UP
up_action:
; set X and Y value
; convert tile values to X,Y
; X=((KEEN_X/2)-1)+TILEX
lda KEEN_X
lsr
sec
sbc #1
clc
adc TILEMAP_X
sta XPOS
; Y = (KEENY/4)+TILEY
lda KEEN_Y
lsr
lsr
clc
adc TILEMAP_Y
sta YPOS
; $39,$22 = 57,34
; check if it's a key slot
check_red_keyhole:
; key slot is 280,148
; 280,148 (-80,-12) -> 200,136 -> (/4,/4) -> 50,34
lda XPOS
cmp #50
beq redkey_x
cmp #51
bne check_if_exit
redkey_x:
lda YPOS
cmp #34
bne check_if_exit
; check that we have the key
lda INVENTORY
and #INV_RED_KEY
bne open_the_wall
no_red_key:
jsr buzzer_noise
jmp done_up_action
; open the red wall
; there has to be a more efficient way of doing this
open_the_wall:
; reset smc
lda #>BIG_TILEMAP
sta rwr_smc1+2
sta rwr_smc2+2
remove_red_wall_outer:
ldx #0
remove_red_wall_loop:
rwr_smc1:
lda BIG_TILEMAP,X
cmp #49 ; red key tile
bne not_red_tile
lda #2 ; lblue bg tile
rwr_smc2:
sta BIG_TILEMAP,X
not_red_tile:
inx
bne remove_red_wall_loop
inc rwr_smc1+2
inc rwr_smc2+2
lda rwr_smc1+2
cmp #(>BIG_TILEMAP)+40
bne remove_red_wall_outer
; refresh local tilemap
jsr copy_tilemap_subset
jsr rumble_noise
jmp done_up_action
; check if it's the exit
check_if_exit:
; exit is 296,148
; 296,148 (-80,-12) -> 216,136 -> (/4,/4) -> 54,34
lda XPOS
cmp #54
beq exit_x
cmp #55
bne done_up_action
exit_x:
lda YPOS
cmp #34
bne done_up_action
; check that we have the key
lda INVENTORY
and #INV_RED_KEY
beq done_up_action
lda #1
sta DOOR_ACTIVATED
sta FRAMEL ; restart timer
done_up_action:
rts
;==========================
; open the door, end level
;==========================
check_open_door:
lda DOOR_ACTIVATED
beq done_open_door
asl
tay
lda door_opening,Y
sta INL
lda door_opening+1,Y
sta INH
; need to find actual door location
; it's at 54,34
; Y is going to be at 20 unless something weird is going on
; X is going to be ((54-TILE_X)+2)*2
lda #56
sec
sbc TILEMAP_X
asl
sta XPOS
lda #20
sta YPOS
jsr put_sprite_crop
lda FRAMEL
and #$7
bne done_open_door
; increment
inc DOOR_ACTIVATED
lda DOOR_ACTIVATED
cmp #6
bne done_open_door
jsr level_end
done_open_door:
rts
door_opening:
.word door_sprite0
.word door_sprite0
.word door_sprite1
.word door_sprite2
.word door_sprite1
.word door_sprite0
door_sprite0:
.byte 4,4
.byte $15,$55,$55,$f5
.byte $55,$f5,$5f,$55
.byte $25,$25,$25,$25
.byte $55,$55,$55,$55
door_sprite1:
.byte 4,4
.byte $51,$f5,$f5,$5f
.byte $55,$05,$05,$50
.byte $05,$50,$50,$55
.byte $52,$55,$55,$52
door_sprite2:
.byte 4,4
.byte $f5,$05,$05,$f0
.byte $55,$00,$00,$55
.byte $55,$00,$00,$55
.byte $05,$50,$50,$25

120
games/keen/draw_keen.s Normal file
View File

@ -0,0 +1,120 @@
;=========================
; draw keen
;=========================
draw_keen:
lda KEEN_X
sta XPOS
lda KEEN_Y
sta YPOS
lda KEEN_DIRECTION
bmi keen_facing_left
;=========================
; facing right
keen_facing_right:
check_falling_right:
lda KEEN_FALLING
beq check_jumping_right
draw_falling_right:
ldx #<keen_sprite_falling_right
lda #>keen_sprite_falling_right
jmp actually_draw_keen
check_jumping_right:
lda KEEN_JUMPING
beq check_shooting_right
draw_jumping_right:
ldx #<keen_sprite_jumping_right
lda #>keen_sprite_jumping_right
jmp actually_draw_keen
check_shooting_right:
lda KEEN_SHOOTING
beq check_walking_right
draw_shooting_right:
ldx #<keen_sprite_shooting_right
lda #>keen_sprite_shooting_right
dec KEEN_SHOOTING
jmp actually_draw_keen
check_walking_right:
lda KEEN_WALKING
beq draw_standing_right
draw_walking_right:
lda FRAMEL
and #$02
beq draw_standing_right
ldx #<keen_sprite_walking_right
lda #>keen_sprite_walking_right
jmp actually_draw_keen
draw_standing_right:
ldx #<keen_sprite_stand_right
lda #>keen_sprite_stand_right
jmp actually_draw_keen
;==================
; facing left
keen_facing_left:
check_falling_left:
lda KEEN_FALLING
beq check_jumping_left
draw_falling_left:
ldx #<keen_sprite_falling_left
lda #>keen_sprite_falling_left
jmp actually_draw_keen
check_jumping_left:
lda KEEN_JUMPING
beq check_shooting_left
draw_jumping_left:
ldx #<keen_sprite_jumping_left
lda #>keen_sprite_jumping_left
jmp actually_draw_keen
check_shooting_left:
lda KEEN_SHOOTING
beq check_walking_left
draw_shooting_left:
ldx #<keen_sprite_shooting_left
lda #>keen_sprite_shooting_left
dec KEEN_SHOOTING
jmp actually_draw_keen
check_walking_left:
lda KEEN_WALKING
beq draw_standing_left
draw_walking_left:
lda FRAMEL
and #$02
beq draw_standing_left
ldx #<keen_sprite_walking_left
lda #>keen_sprite_walking_left
jmp actually_draw_keen
draw_standing_left:
ldx #<keen_sprite_stand_left
lda #>keen_sprite_stand_left
jmp actually_draw_keen
;====================
; actually draw
actually_draw_keen:
stx INL
sta INH
jsr put_sprite_crop
rts

143
games/keen/draw_tilemap.s Normal file
View File

@ -0,0 +1,143 @@
;================================
; draw local tilemap to screen
;================================
draw_tilemap:
ldy #0 ; Y on screen currently drawing
sty tiley ; we draw two at a time
ldx #1 ; offset in current screen
stx tilemap_offset ; tilemap
lda #0 ; init odd/even
sta tile_odd
tilemap_outer_loop:
ldy tiley ; setup pointer to current Y
lda gr_offsets,Y
sta GBASL
lda gr_offsets+1,Y
clc
adc DRAW_PAGE
sta GBASH
ldy #6 ; we draw in window 6->34
tilemap_loop:
ldx tilemap_offset ; get actual tile
lda TILEMAP,X
asl ; *4 ; get offset in tile
asl
tax
lda tile_odd
beq not_odd_line
inx
inx
not_odd_line:
lda TILES,X ; draw two tiles
cmp #$AA ; transparency
beq skip_tile1
sta (GBASL),Y
skip_tile1:
iny
lda TILES+1,X
cmp #$AA
beq skip_tile2
sta (GBASL),Y
skip_tile2:
iny
inc tilemap_offset
cpy #34 ; until done
bne tilemap_loop
; move to next line
lda tile_odd ; toggle odd/even
eor #$1 ; (should we just add/mask?)
sta tile_odd
bne move_to_odd_line
move_to_even_line:
lda tilemap_offset
clc
adc #2
jmp done_move_to_line
move_to_odd_line:
lda tilemap_offset
sec
sbc #14
done_move_to_line:
sta tilemap_offset
ldy tiley ; move to next line
iny
iny
sty tiley
cpy #40 ; check if at end
bne tilemap_outer_loop
rts
; these should probably be in the zero page
tilemap_offset: .byte $00
tile_odd: .byte $00
tiley: .byte $00
;===================================
; copy tilemap
;===================================
; want to copy a 16x10 area from global tileset to local
; default at first we want to start at 128,88
; which is 13, 20???
copy_tilemap_subset:
; set start
lda TILEMAP_Y
clc
adc #>BIG_TILEMAP
sta cptl1_smc+2 ; set proper row in big tilemap
adc #$10
sta cptl3_smc+1 ; set loop limit
; reset row
lda #<TILEMAP
sta cptl2_smc+1 ; set small tilemap to row0
cp_tilemap_outer_loop:
ldx TILEMAP_X
ldy #0
cp_tilemap_inner_loop:
cptl1_smc:
lda $9400,X
cptl2_smc:
sta $BC00,Y
iny
inx
cpy #16
bne cp_tilemap_inner_loop
; next line
inc cptl1_smc+2 ; incremement page
clc
lda cptl2_smc+1 ; increment row
adc #$10
sta cptl2_smc+1
lda cptl1_smc+2
cptl3_smc:
cmp #$a
bne cp_tilemap_outer_loop
rts

339
games/keen/enemies_level1.s Normal file
View File

@ -0,0 +1,339 @@
NUM_ENEMIES = 4
;=======================
; laser enemies
;=======================
; see if laser hits any enemies
laser_enemies:
ldy #0
laser_enemies_loop:
; see if out
lda enemy_data+ENEMY_DATA_OUT,Y
beq done_laser_enemy
; get local tilemap co-ord
sec
lda enemy_data+ENEMY_DATA_TILEX,Y
sbc TILEMAP_X
sta TILE_TEMP
sec
lda enemy_data+ENEMY_DATA_TILEY,Y
sbc TILEMAP_Y
asl
asl
asl
asl
clc
adc TILE_TEMP
cmp LASER_TILE
bne done_laser_enemy
; hit something
hit_something:
lda #0
sta LASER_OUT
sta FRAMEL
; sta enemy_data+ENEMY_DATA_OUT,Y
lda #1
sta enemy_data+ENEMY_DATA_EXPLODING,Y
jsr enemy_noise
jsr inc_score_by_10
jmp exit_laser_enemy
done_laser_enemy:
tya
clc
adc #8
tay
cpy #(NUM_ENEMIES*8)
bne laser_enemies_loop
exit_laser_enemy:
rts
;=======================
; move enemy
;=======================
; which one is in Y
move_enemy:
lda enemy_data+ENEMY_DATA_TYPE,Y
and #$fc
cmp #ENEMY_CAMERA
beq aim_camera
; FIXME: actually move them
move_bot:
move_crawler:
lda FRAMEL
and #$f
bne done_move_enemy
lda enemy_data+ENEMY_DATA_TYPE,Y
eor #$2
sta enemy_data+ENEMY_DATA_TYPE,Y
jmp done_move_enemy
aim_camera:
lda KEEN_X
lsr
clc
adc TILEMAP_X
cmp enemy_data+ENEMY_DATA_TILEX,Y
bcc aim_camera_left
aim_camera_right:
lda #2
sta enemy_data+ENEMY_DATA_TYPE,Y
jmp done_move_enemy
aim_camera_left:
lda #0
sta enemy_data+ENEMY_DATA_TYPE,Y
done_move_enemy:
rts
;=======================
; draw and move enemies
;=======================
draw_enemies:
ldy #0
draw_enemies_loop:
; see if out
lda enemy_data+ENEMY_DATA_OUT,Y
beq done_draw_enemy
; check if on screen
lda TILEMAP_X
cmp enemy_data+ENEMY_DATA_TILEX,Y
bcs done_draw_enemy
clc
adc #14
cmp enemy_data+ENEMY_DATA_TILEX,Y
bcc done_draw_enemy
lda TILEMAP_Y
cmp enemy_data+ENEMY_DATA_TILEY,Y
bcs done_draw_enemy
clc
adc #10
cmp enemy_data+ENEMY_DATA_TILEY,Y
bcc done_draw_enemy
; set X and Y value
; convert tile values to X,Y
; X = (ENEMY_TILE_X-TILEX)*2 + 6
lda enemy_data+ENEMY_DATA_TILEX,Y
sec
sbc TILEMAP_X
asl
clc
adc #4
sta XPOS
; Y = (ENEMY_TILE_Y-TILEY)*4
lda enemy_data+ENEMY_DATA_TILEY,Y
sec
sbc TILEMAP_Y
asl
asl
sta YPOS
; see if exploding
lda enemy_data+ENEMY_DATA_EXPLODING,Y
beq draw_proper_enemy
draw_exploding_enemy:
asl
tax
lda enemy_explosion_sprites,X
sta INL
lda enemy_explosion_sprites+1,X
sta INH
lda FRAMEL
and #$3
bne done_exploding
; move to next frame
lda enemy_data+ENEMY_DATA_EXPLODING,Y
clc
adc #1
sta enemy_data+ENEMY_DATA_EXPLODING,Y
cmp #4
bne done_exploding
lda #0
sta enemy_data+ENEMY_DATA_OUT,Y
done_exploding:
jmp draw_enemy
; otherwise draw proper sprite
draw_proper_enemy:
lda enemy_data+ENEMY_DATA_TYPE,Y
tax
lda enemy_sprites,X
sta INL
lda enemy_sprites+1,X
sta INH
draw_enemy:
tya
pha
jsr put_sprite_crop
pla
tay
jsr move_enemy
done_draw_enemy:
tya
clc
adc #8
tay
cpy #(NUM_ENEMIES*8)
beq exit_draw_enemy
jmp draw_enemies_loop
exit_draw_enemy:
rts
enemy_sprites:
.word enemy_camera_sprite1
.word enemy_camera_sprite2
.word enemy_crawler_sprite1
.word enemy_crawler_sprite2
.word enemy_bot_sprite1
.word enemy_bot_sprite2
enemy_bot_sprite1:
.byte 2,2
.byte $Ae,$e3
.byte $6e,$0e
enemy_bot_sprite2:
.byte 2,2
.byte $e3,$Ae
.byte $0e,$6e
enemy_crawler_sprite1:
.byte 2,2
.byte $f5,$cA
.byte $f5,$Ac
enemy_crawler_sprite2:
.byte 2,2
.byte $5f,$cA
.byte $5f,$Ac
enemy_camera_sprite1:
.byte 2,2
.byte $AA,$76
.byte $f7,$A5
enemy_camera_sprite2:
.byte 2,2
.byte $76,$AA
.byte $A5,$f7
enemy_explosion_sprites:
.word enemy_explosion_sprite1
.word enemy_explosion_sprite1
.word enemy_explosion_sprite2
.word enemy_explosion_sprite3
enemy_explosion_sprite1:
.byte 2,2
.byte $d9,$d9
.byte $9d,$9d
enemy_explosion_sprite2:
.byte 2,2
.byte $9A,$9A
.byte $A9,$A9
enemy_explosion_sprite3:
.byte 2,2
.byte $7A,$5A
.byte $A5,$A7
ENEMY_CAMERA = 0
ENEMY_CRAWLER = 4
ENEMY_BOT = 8
ENEMY_DATA_OUT = 0
ENEMY_DATA_EXPLODING = 1
ENEMY_DATA_TYPE = 2
ENEMY_DATA_DIRECTION = 3
ENEMY_DATA_TILEX = 4
ENEMY_DATA_TILEY = 5
ENEMY_DATA_X = 6
ENEMY_DATA_Y = 7
enemy_data:
enemy0:
; 156,92 (-80,-12) -> 76,80 -> (/4,/4) -> 19,20
.byte 1 ; out
.byte 0 ; exploding
.byte ENEMY_CAMERA ; type
.byte $ff ; direction
.byte 19,20 ; tilex,tiley
.byte 0,0 ; x,y
enemy1:
; 272,92 (-80,-12) -> 192,80 -> (/4,/4) -> 48,20
.byte 1 ; out
.byte 0 ; exploding
.byte ENEMY_CAMERA ; type
.byte $ff ; direction
.byte 48,20 ; tilex,tiley
.byte 0,0 ; x,y
enemy2:
; 156,112 (-80,-12) -> 76,100 -> (/4,/4) -> 19,25
.byte 1 ; out
.byte 0 ; exploding
.byte ENEMY_CRAWLER ; type
.byte $ff ; direction
.byte 19,25 ; tilex,tiley
.byte 0,0 ; x,y
enemy3:
; 184,116 (-80,-12) -> 104,104 -> (/4,/4) -> 26,26
.byte 1 ; out
.byte 0 ; exploding
.byte ENEMY_BOT ; type
.byte $ff ; direction
.byte 26,26 ; tilex,tiley
.byte 0,0 ; x,y

5
games/keen/gr_offsets.s Normal file
View File

@ -0,0 +1,5 @@
gr_offsets:
.word $400,$480,$500,$580,$600,$680,$700,$780
.word $428,$4a8,$528,$5a8,$628,$6a8,$728,$7a8
.word $450,$4d0,$550,$5d0,$650,$6d0,$750,$7d0

24
games/keen/gr_pageflip.s Normal file
View File

@ -0,0 +1,24 @@
;==========
; page_flip
;==========
page_flip:
lda DISP_PAGE ; 3
beq page_flip_show_1 ; 2nt/3
page_flip_show_0:
bit PAGE0 ; 4
lda #4 ; 2
sta DRAW_PAGE ; DRAW_PAGE=1 ; 3
lda #0 ; 2
sta DISP_PAGE ; DISP_PAGE=0 ; 3
rts ; 6
page_flip_show_1:
bit PAGE1 ; 4
sta DRAW_PAGE ; DRAW_PAGE=0 ; 3
lda #1 ; 2
sta DISP_PAGE ; DISP_PAGE=1 ; 3
rts ; 6
;====================
; DISP_PAGE=0 26
; DISP_PAGE=1 24

View File

@ -0,0 +1,359 @@
;=============================================
; put_sprite_crop
;=============================================
; Sprite to display in INH,INL
; Location is XPOS,YPOS
; Note, only works if YPOS is multiple of two
; transparent color is $A (grey #2)
; this means we can have black ($0) in a sprite
; FIXME: force YPOS to be even?
put_sprite_crop:
ldy #0 ; byte 0 is xsize ; 2
lda (INL),Y ; 5
sta CH ; xsize is in CH ; 3
iny ; 2
clc
adc XPOS
sta XMAX
lda (INL),Y ; byte 1 is ysize ; 5
sta CV ; ysize is in CV ; 3
iny ; 2
lda YPOS ; make a copy of ypos ; 3
sta TEMPY ; as we modify it ; 3
;===========
; 28
put_sprite_crop_loop:
sty TEMP ; save sprite pointer ; 3
ldy TEMPY ; 3
bpl put_sprite_crop_pos ; if < 0, skip to next
clc ; skip line in sprite too
lda TEMP
adc CH
tay
bne crop_increment_y
put_sprite_crop_pos:
psc_smc1:
cpy #48 ; bge if >= 48, done sprite
bcs crop_sprite_done
lda gr_offsets,Y ; lookup low-res memory address ; 4
clc ; 2
adc XPOS ; add in xpos ; 3
sta OUTL ; store out low byte of addy ; 3
clc ; never wraps, handle negative
lda gr_offsets+1,Y ; look up high byte ; 4
adc DRAW_PAGE ; ; 3
sta OUTH ; and store it out ; 3
ldy TEMP ; restore sprite pointer ; 3
; OUTH:OUTL now points at right place
ldx XPOS ; load xposition into x ; 3
;===========
; 34
crop_put_sprite_pixel:
lda (INL),Y ; get sprite colors ; 5
iny ; increment sprite pointer ; 2
sty TEMP ; save sprite pointer ; 3
cpx #0 ; if off-screen left, skip draw
bmi skip_drawing
cpx #40
bcs skip_drawing ; if off-screen right, skip draw
ldy #$0 ; 2
; check if completely transparent
; if so, skip
cmp #$aa ; if all zero, transparent ; 2
beq crop_put_sprite_done_draw ; don't draw it ; 2nt/3
;==============
; 16/17
sta COLOR ; save color for later ; 3
; check if top pixel transparent
and #$f0 ; check if top nibble zero ; 2
cmp #$a0
bne crop_put_sprite_bottom ; if not skip ahead ; 2nt/3
;==============
; 7/8
lda COLOR
and #$0f
sta COLOR
lda #$f0 ; setup mask ; 2
sta MASK ; 3
bmi crop_put_sprite_mask ; always? ; 3
;=============
; 8
crop_put_sprite_bottom:
lda COLOR ; re-load color ; 3
and #$0f ; check if bottom nibble zero ; 2
cmp #$0a
bne crop_put_sprite_all ; if not, skip ahead ; 2nt/3
;=============
; 7/8
lda COLOR
and #$f0
sta COLOR
lda #$0f ; 2
sta MASK ; setup mask ; 3
;===========
; 5
crop_put_sprite_mask:
lda (OUTL),Y ; get color at output ; 5
and MASK ; mask off unneeded part ; 3
ora COLOR ; or the color in ; 3
sta (OUTL),Y ; store it back ; 6
jmp crop_put_sprite_done_draw ; we are done ; 3
;===========
; 20
crop_put_sprite_all:
lda COLOR ; load color ; 3
sta (OUTL),Y ; and write it out ; 6
;============
; 9
crop_put_sprite_done_draw:
skip_drawing:
ldy TEMP ; restore sprite pointer ; 3
inc OUTL ; increment output pointer ; 5
inx ; increment x counter ; 2
cpx XMAX
bne crop_put_sprite_pixel ; if not done, keep looping ; 2nt/3
;==============
; 12/13
crop_increment_y:
inc TEMPY ; each line has two y vars ; 5
inc TEMPY ; 5
dec CV ; decemenet total y count ; 5
bne put_sprite_crop_loop ; loop if not done ; 2nt/3
;==============
; 17/18
crop_sprite_done:
rts ; return ; 6
; 0,0 = 400+0
; -1,0 = 400+ff=4ff, inc=400
; sprite: 5x4
;
; -2,0 Xstart=0, sprite_offset=2, xsize=3
; -1,0, Xstart=0, sprite_offset=1, xsize=4
; 0,0, Xstrat=0, sprite_offset=0, xsize=5
; 1,0, Xstart=1, sprite_offset=0, xsize=5
;
; 39,0 Xstart=39, sprite_offset=0, xsize=1
;
;
;
;
.if 0
;=============================================
; put_sprite_flipped_crop
;=============================================
; Sprite to display in INH,INL
; Location is XPOS,YPOS
; Note, only works if YPOS is multiple of two
; transparent color is $A (grey #2)
; this means we can have black ($0) in a sprite
put_sprite_flipped_crop:
ldy #0 ; byte 0 is xsize ; 2
lda (INL),Y ; 5
sta CH ; xsize is in CH ; 3
iny ; 2
lda (INL),Y ; byte 1 is ysize ; 5
sta CV ; ysize is in CV ; 3
dey ; make Y zero again ; 2
lda INH ; ???
sta ppfc_smc+2
clc
lda INL
adc #1 ; add one (not two) because X counts
; from CH to 1 (not CH-1 to 0)
sta ppfc_smc+1
bcc psfc16
inc ppfc_smc+2
psfc16:
lda YPOS ; make a copy of ypos ; 3
sta TEMPY ; as we modify it ; 3
;===========
; 28
put_spritefc_loop:
; sty TEMP ; save sprite pointer ; 3
ldy TEMPY ; 3
bmi fcrop_increment_y ; if < 0, skip to next
psc_smc2:
cpy #48 ; bge if >= 48, done sprite
bcs fcrop_sprite_done
lda gr_offsets,Y ; lookup low-res memory address ; 4
clc ; 2
adc XPOS ; add in xpos ; 3
sta OUTL ; store out low byte of addy ; 3
lda gr_offsets+1,Y ; look up high byte ; 4
clc
adc DRAW_PAGE ; ; 3
sta OUTH ; and store it out ; 3
; ldy TEMP ; restore sprite pointer ; 3
; OUTH:OUTL now points at right place
ldx CH ; load xsize into x ; 3
;===========
; 34
put_spritefc_pixel:
clc
txa ; want (CH-X-1)+XPOS
eor #$ff
adc CH
adc XPOS
bmi cskip_drawing
cmp #40
bcs cskip_drawing ; if off-screen right, skip draw
ppfc_smc:
lda $C000,X ; get sprite colors ; 5
; iny ; increment sprite pointer ; 2
; sty TEMP ; save sprite pointer ; 3
ldy #$0 ; 2
; check if completely transparent
; if so, skip
cmp #$aa ; if all zero, transparent ; 2
beq put_spritefc_done_draw ; don't draw it ; 2nt/3
;==============
; 16/17
sta COLOR ; save color for later ; 3
; check if top pixel transparent
and #$f0 ; check if top nibble zero ; 2
cmp #$a0
bne put_spritefc_bottom ; if not skip ahead ; 2nt/3
;==============
; 7/8
lda COLOR
and #$0f
sta COLOR
lda #$f0 ; setup mask ; 2
sta MASK ; 3
bmi put_spritefc_mask ; always? ; 3
;=============
; 8
put_spritefc_bottom:
lda COLOR ; re-load color ; 3
and #$0f ; check if bottom nibble zero ; 2
cmp #$0a
bne put_spritefc_all ; if not, skip ahead ; 2nt/3
;=============
; 7/8
lda COLOR
and #$f0
sta COLOR
lda #$0f ; 2
sta MASK ; setup mask ; 3
;===========
; 5
put_spritefc_mask:
lda (OUTL),Y ; get color at output ; 5
and MASK ; mask off unneeded part ; 3
ora COLOR ; or the color in ; 3
sta (OUTL),Y ; store it back ; 6
jmp put_spritefc_done_draw ; we are done ; 3
;===========
; 20
put_spritefc_all:
lda COLOR ; load color ; 3
sta (OUTL),Y ; and write it out ; 6
;============
; 9
put_spritefc_done_draw:
cskip_drawing:
; ldy TEMP ; restore sprite pointer ; 3
inc OUTL ; increment output pointer ; 5
dex ; decrement x counter ; 2
bne put_spritefc_pixel ; if not done, keep looping ; 2nt/3
;==============
; 12/13
fcrop_increment_y:
inc TEMPY ; each line has two y vars ; 5
inc TEMPY ; 5
lda CH
clc
adc ppfc_smc+1
sta ppfc_smc+1
bcc psfco
inc ppfc_smc+2
psfco:
dec CV ; decemenet total y count ; 5
beq fcrop_sprite_done ; loop if not done ; 2nt/3
jmp put_spritefc_loop
;==============
; 17/18
fcrop_sprite_done:
rts ; return ; 6
.endif

View File

@ -10,7 +10,7 @@ PNG2GR = ../../../utils/gr-utils/png2gr
PNG2SPRITES = ../../../utils/gr-utils/png2sprites
HGR_SPRITE = ../../../utils/hgr-utils/hgr_make_sprite
all: keen1_title.hgr.zx02
all: keen1_title.hgr.zx02 level1_bg.gr.zx02
####
@ -27,6 +27,15 @@ keen1_title.hgr: keen1_title.png
####
level1_bg.gr.zx02: level1_bg.gr
$(ZX02) level1_bg.gr level1_bg.gr.zx02
level1_bg.gr: level1_bg.png
$(PNG2GR) level1_bg.png level1_bg.gr
####
clean:
rm -f *~ *.o *.lst *.zx02 *.hgr

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

100
games/keen/handle_laser.s Normal file
View File

@ -0,0 +1,100 @@
; draw/move laser
; o/~ carrying a laser, down the road that I must travel o/~
; o/~ carrying a laser, in the darkness of the night o/~
;====================
; move laser
;====================
move_laser:
lda LASER_OUT
beq done_move_laser
lda LASER_X
clc
adc LASER_DIRECTION
sta LASER_X
laser_check_tiles:
; collision detect with tiles
; laser location is roughly
; (y/4)*16 + (x/2) - 2
lda LASER_Y
lsr
lsr
asl
asl
asl
asl
sta LASER_TILE
lda LASER_X
lsr
clc
adc LASER_TILE
sec
sbc #2
sta LASER_TILE
ldx LASER_TILE
lda TILEMAP,X
cmp #HARD_TILES
bcs destroy_laser
laser_check_enemies:
; collision detect with enemies
jsr laser_enemies
; detect if off screen
laser_check_right:
lda LASER_X
cmp #31
bcc laser_check_left ; not_too_far_right
bcs destroy_laser
laser_check_left:
cmp #6
bcs done_move_laser
bcc destroy_laser
destroy_laser:
lda #0
sta LASER_OUT
done_move_laser:
rts
;====================
; draw laser
;====================
draw_laser:
lda LASER_OUT
beq done_draw_laser
lda LASER_X
sta XPOS
lda LASER_Y
sta YPOS
; lda LASER_DIRECTION
lda #<laser_sideways_sprite
sta INL
lda #>laser_sideways_sprite
sta INH
jsr put_sprite_crop
done_draw_laser:
rts
laser_sideways_sprite:
.byte 4,1
; .byte $3A,$cA,$3A,$cA
.byte $A3,$Ac,$A3,$Ac

14
games/keen/hello.bas Normal file
View File

@ -0,0 +1,14 @@
5 HOME
10 PRINT "LOADING KEEN V0.01"
20 PRINT " KEEN1 PROOF-OF-CONCEPT DEMAKE"
30 PRINT:PRINT
70 PRINT "BASED ON KEEN1 BY ID"
75 PRINT:PRINT
80 PRINT "APPLE II PORT: VINCE WEAVER"
90 PRINT "DISK CODE : QKUMBA"
95 PRINT
100 PRINT " ______"
110 PRINT " A \/\/\/ SOFTWARE PRODUCTION"
115 PRINT
120 PRINT " HTTP://WWW.DEATER.NET/WEAVE/VMWPROD"
130 PRINT CHR$(4);"BRUN LOADER"

View File

@ -9,16 +9,16 @@ init_vars:
sta FRAMEH
sta DISP_PAGE
sta JOYSTICK_ENABLED
sta DUKE_WALKING
sta DUKE_JUMPING
sta KEEN_WALKING
sta KEEN_JUMPING
sta LEVEL_OVER
sta LASER_OUT
sta DUKE_XL
sta KEEN_XL
sta SCORE0
sta SCORE1
sta SCORE2
sta DUKE_FALLING
sta DUKE_SHOOTING
sta KEEN_FALLING
sta KEEN_SHOOTING
sta KICK_UP_DUST
sta DOOR_ACTIVATED
sta INVENTORY

49
games/keen/item_level1.s Normal file
View File

@ -0,0 +1,49 @@
;==================
; check for items
;==================
; X holds ??
check_item:
check_red_key:
lda TILEMAP,X
cmp #31 ; red key
bne check_blue_key
jsr pickup_noise
lda INVENTORY
ora #INV_RED_KEY
sta INVENTORY
; erase red key (304,96)
lda #0
sta $A938 ; hack
jsr copy_tilemap_subset
jsr update_status_bar
jmp done_check_item
check_blue_key:
cmp #30 ; blue key
bne done_check_item
jsr pickup_noise
lda INVENTORY
ora #INV_BLUE_KEY
sta INVENTORY
; erase blue key
lda #0
sta $970c ; hack
jsr copy_tilemap_subset
jsr update_status_bar
jmp keen_check_head
done_check_item:
rts

46
games/keen/joystick.s Normal file
View File

@ -0,0 +1,46 @@
; Oliver Schmidt
; comp.sys.apple2.programmer
; Call with joystick number (0 or 1) in A.
; Results are stored in value0 and value1.
; UPPER_THRESHOLD is the paddle value you want to consider as "right enough" /
; "down enough".
UPPER_THRESHOLD = 128
;PTRIG = $c070
PADDL1 = $C065
handle_joystick:
lda #0
; Read both paddles simultaneously
asl ; Joystick number -> paddle number
tax
ldy #$00
sty value0
sty value1
lda PTRIG ; Trigger paddles
loop: lda PADDL0,x ; Read paddle (0 or 2)
bmi set0 ; Cycles: 2 3
nop ; Cycles: 2
bpl nop0 ; Cycles: 3
set0: sty value0 ; Cycles: 4
nop0: ; - -
; Cycles: 7 7
lda PADDL1,x ; Read paddle (1 or 3)
bmi set1 ; Cycles: 2 3
nop ; Cycles: 2
bpl nop1 ; Cycles: 3
set1: sty value1 ; Cycles: 4
nop1: ; - -
; Cycles: 7 7
iny
cpy #UPPER_THRESHOLD+1
bne loop
rts
value0: .byte $00
value1: .byte $00

243
games/keen/keen_level1.s Normal file
View File

@ -0,0 +1,243 @@
; Keen PoC Level 1
; by deater (Vince Weaver) <vince@deater.net>
; Zero Page
.include "zp.inc"
.include "hardware.inc"
.include "common_defines.inc"
keen_start:
;===================
; init screen
jsr TEXT
jsr HOME
bit KEYRESET
bit SET_GR
bit PAGE0
bit LORES
bit TEXTGR
jsr clear_top ; avoid grey stripes at load
;=====================
; init vars
;=====================
lda #0
sta ANIMATE_FRAME
sta FRAMEL
sta FRAMEH
sta DISP_PAGE
sta JOYSTICK_ENABLED
sta KEEN_WALKING
sta KEEN_JUMPING
sta LEVEL_OVER
sta LASER_OUT
sta KEEN_XL
sta SCORE0
sta SCORE1
sta SCORE2
sta KEEN_FALLING
sta KEEN_SHOOTING
sta KICK_UP_DUST
sta DOOR_ACTIVATED
sta INVENTORY
lda #<enemy_data
sta ENEMY_DATAL
lda #>enemy_data
sta ENEMY_DATAH
; FIXME: temporary
; lda INVENTORY
; ora #INV_RED_KEY
; sta INVENTORY
; lda #$10
; sta SCORE0
lda #1
sta FIREPOWER
lda #2 ; draw twice (both pages)
sta UPDATE_STATUS
lda #7
sta HEALTH
lda #4
sta DRAW_PAGE
lda #18
sta KEEN_X
lda #0
sta KEEN_Y
lda #1
sta KEEN_DIRECTION
jsr update_status_bar
;====================================
; load level1 background
;====================================
lda #<level1_bg_zx02
sta ZX0_src
lda #>level1_bg_zx02
sta ZX0_src+1
lda #$c ; load to page $c00
jsr full_decomp
;====================================
; load level1 tilemap
;====================================
lda #<level1_data_zx02
sta ZX0_src
lda #>level1_data_zx02
sta ZX0_src+1
lda #$90 ; load to page $9000
jsr full_decomp
;====================================
; copy in tilemap subset
;====================================
lda #28
sta TILEMAP_X
lda #0
sta TILEMAP_Y
jsr copy_tilemap_subset
;====================================
;====================================
; Main LOGO loop
;====================================
;====================================
keen_loop:
; copy over background
jsr gr_copy_to_current
; draw tilemap
jsr draw_tilemap
; draw enemies
jsr draw_enemies
; draw laser
jsr draw_laser
; draw keen
jsr draw_keen
; handle door opening
jsr check_open_door
; draw a status bar
jsr draw_status_bar
jsr page_flip
jsr handle_keypress
jsr move_keen
; jsr move_enemies
jsr move_laser
;========================
; increment frame count
;========================
inc FRAMEL
bne no_frame_oflo
inc FRAMEH
no_frame_oflo:
;===========================
; check end of level
;===========================
lda LEVEL_OVER
beq do_keen_loop
jmp done_with_keen
do_keen_loop:
; delay
; lda #200
; jsr WAIT
jmp keen_loop
done_with_keen:
bit KEYRESET ; clear keypress
lda #LOAD_KEEN2
sta WHICH_LOAD
rts ; exit back
;==========================
; includes
;==========================
; level graphics
level1_bg_zx02:
.incbin "graphics/level1_bg.gr.zx02"
.include "text_print.s"
.include "gr_offsets.s"
.include "gr_fast_clear.s"
.include "gr_copy.s"
.include "gr_pageflip.s"
.include "gr_putsprite_crop.s"
.include "zx02_optim.s"
.include "status_bar.s"
.include "keyboard.s"
.include "joystick.s"
.include "text_drawbox.s"
.include "print_help.s"
.include "quit_yn.s"
.include "level_end.s"
.include "draw_keen.s"
.include "keen_sprites.inc"
.include "move_keen.s"
.include "handle_laser.s"
.include "draw_tilemap.s"
.include "enemies_level1.s"
.include "actions_level1.s"
.include "item_level1.s"
.include "sound_effects.s"
.include "speaker_tone.s"
level1_data_zx02:
.incbin "maps/level1_map.zx02"

View File

@ -186,7 +186,7 @@ done_intro:
;============================
; set up initial location
lda #LOAD_DUKE1
lda #LOAD_KEEN1
sta WHICH_LOAD ; start at first level
rts

251
games/keen/keyboard.s Normal file
View File

@ -0,0 +1,251 @@
JUMP_HEIGHT = 8
;==============================
; Handle Keypress
;==============================
handle_keypress:
; first handle joystick
lda JOYSTICK_ENABLED
beq actually_handle_keypress
; only check joystick every-other frame
lda FRAMEL
and #$1
beq actually_handle_keypress
check_button:
lda PADDLE_BUTTON0
bpl button_clear
lda JS_BUTTON_STATE
bne js_check
lda #1
sta JS_BUTTON_STATE
lda #' '
jmp check_sound
button_clear:
lda #0
sta JS_BUTTON_STATE
js_check:
jsr handle_joystick
js_check_left:
lda value0
cmp #$20
bcs js_check_right ; if less than 32, left
lda #'A'
bne check_sound
js_check_right:
cmp #$40
bcc js_check_up
lda #'D'
bne check_sound
js_check_up:
lda value1
cmp #$20
bcs js_check_down
lda #'W'
bne check_sound
js_check_down:
cmp #$40
bcc done_joystick
lda #'S'
bne check_sound
done_joystick:
actually_handle_keypress:
lda KEYPRESS
bmi keypress
jmp no_keypress
keypress:
and #$7f ; clear high bit
cmp #' '
beq check_sound ; make sure not to lose space
and #$df ; convert uppercase to lower case
check_sound:
cmp #$14 ; control-T
bne check_help
lda SOUND_STATUS
eor #SOUND_DISABLED
sta SOUND_STATUS
jmp done_keypress
check_help:
cmp #'H' ; H (^H is same as left)
bne check_joystick
jsr print_help
jmp done_keypress
; can't be ^J as that's the same as down
check_joystick:
cmp #'J' ; J
bne check_left
lda JOYSTICK_ENABLED
eor #1
sta JOYSTICK_ENABLED
jmp done_keypress
check_left:
cmp #'A'
beq left_pressed
cmp #8 ; left key
bne check_right
left_pressed:
lda KEEN_DIRECTION
cmp #$ff ; check if facing left
bne face_left
lda #1
sta KEEN_WALKING
jmp done_left_pressed
face_left:
lda #$ff
sta KEEN_DIRECTION
lda #0
sta KEEN_WALKING
done_left_pressed:
jmp done_keypress
check_right:
cmp #'D'
beq right_pressed
cmp #$15 ; right key
bne check_up
right_pressed:
lda KEEN_DIRECTION
cmp #$1 ; check if facing right
bne face_right
lda #1
sta KEEN_WALKING
jmp done_left_pressed
face_right:
lda #$1
sta KEEN_DIRECTION
lda #0
sta KEEN_WALKING
done_right_pressed:
jmp done_keypress
check_up:
cmp #'W'
beq up_pressed
cmp #$0B ; up key
bne check_down
up_pressed:
jsr up_action
done_up_pressed:
jmp done_keypress
check_down:
cmp #'S'
beq down_pressed
cmp #$0A
bne check_space
down_pressed:
done_down_pressed:
jmp done_keypress
check_space:
cmp #' '
bne check_return
space_pressed:
; jump
lda KEEN_JUMPING
bne done_keypress ; don't jump if already jumping
lda KEEN_FALLING
bne done_keypress ; don't jump if falling
lda #JUMP_HEIGHT
sta KEEN_JUMPING
jsr jump_noise
jmp done_keypress
check_return:
cmp #13
bne check_escape
return_pressed:
; shoot
lda LASER_OUT
bne done_return
jsr laser_noise
lda KEEN_DIRECTION
sta LASER_DIRECTION
lda #2
sta KEEN_SHOOTING
cmp #1
beq laser_right
laser_left:
lda KEEN_X
sec
sbc #1
jmp laser_assign
laser_right:
lda KEEN_X
clc
adc #2
laser_assign:
sta LASER_X
lda KEEN_Y
clc
adc #4
sta LASER_Y
inc LASER_OUT
done_return:
jmp no_keypress
check_escape:
cmp #27
bne done_keypress
jsr print_quit
jmp done_keypress
done_keypress:
no_keypress:
bit KEYRESET
rts

65
games/keen/level_end.s Normal file
View File

@ -0,0 +1,65 @@
; Print bonuses
level_end:
bit KEYRESET ; clear keyboard
bit SET_TEXT
lda #12
sta drawbox_x1
lda #26
sta drawbox_x2
lda #19
sta drawbox_y1
lda #23
sta drawbox_y2
lda #21
sta bonus_text+1
scroll_bonus_loop:
lda #' '|$80
sta clear_all_color+1
jsr clear_all
jsr drawbox
jsr normal_text
lda #<bonus_text
sta OUTL
lda #>bonus_text
sta OUTH
jsr move_and_print_list
jsr page_flip
lda #220
jsr WAIT
lda #220
jsr WAIT
level_end_wait:
lda KEYPRESS
bmi really_end_level
dec drawbox_y1
dec drawbox_y2
dec bonus_text+1
lda drawbox_y1
bmi really_end_level
jmp scroll_bonus_loop
really_end_level:
bit KEYRESET
lda #NEXT_LEVEL
sta LEVEL_OVER
jsr clear_all
rts
bonus_text:
.byte 14,10,"BONUS: NONE",0
.byte 255

View File

@ -0,0 +1,3 @@
Urgh I've completely forgotten all of this
Fall through tiles that are < HARD_TILES which defaults to 32

34
games/keen/maps/Makefile Normal file
View File

@ -0,0 +1,34 @@
CC = gcc
CFLAGS = -g -Wall -O2
ZX02 = ~/research/6502_compression/zx02.git/build/zx02 -f
all: level1_map.zx02 png2map
###
level1_map.zx02: level1_map.inc
$(ZX02) level1_map.inc level1_map.zx02
level1_map.inc: level1_map.png png2map
./png2map level1_map.png level1_map.inc
###
loadpng.o: loadpng.c loadpng.h
$(CC) $(CFLAGS) -c loadpng.c
rle_common.o: rle_common.c rle_common.h
$(CC) $(CFLAGS) -c rle_common.c
###
png2map: png2map.o loadpng.o
$(CC) $(LFLAGS) -o png2map png2map.o loadpng.o -lpng
png2map.o: png2map.c loadpng.h
$(CC) $(CFLAGS) -c png2map.c
###
clean:
rm -f *~ *.o *.inc png2map

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

236
games/keen/maps/loadpng.c Normal file
View File

@ -0,0 +1,236 @@
/* Loads a 80x48 (or 40x48) PNG image into a 40x48 Apple II layout */
/* It's not interleaved like an actual Apple II */
/* But the top/bottom are pre-packed into a naive 40x24 array */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <png.h>
#include "loadpng.h"
static int convert_color(int color, char *filename) {
int c=0;
switch(color) {
case 0x000000: c=0; break; /* black */
case 0xe31e60: c=1; break; /* magenta */
case 0x604ebd: c=2; break; /* dark blue */
case 0xff44fd: c=3; break; /* purple */
case 0x00a360: c=4; break; /* dark green */
case 0x9c9c9c: c=5; break; /* grey 1 */
case 0x14cffd: c=6; break; /* medium blue */
case 0xd0c3ff: c=7; break; /* light blue */
case 0x607203: c=8; break; /* brown */
case 0xff6a3c: c=9; break; /* orange */
case 0x9d9d9d: c=10; break; /* grey 2 */
case 0xffa0d0: c=11; break; /* pink */
case 0x14f53c: c=12; break; /* bright green */
case 0xd0dd8d: c=13; break; /* yellow */
case 0x72ffd0: c=14; break; /* aqua */
case 0xffffff: c=15; break; /* white */
default:
fprintf(stderr,"Unknown color %x, file %s\n",
color,filename);
exit(-1);
break;
}
return c;
}
/* expects a PNG where the xsize is either 1280x200 */
int loadpng(char *filename, unsigned char **image_ptr, int *xsize, int *ysize,
int png_type) {
int x,y,ystart,yadd,xadd;
int color;
FILE *infile;
int debug=0;
unsigned char *image,*out_ptr;
int width, height;
int a2_color;
png_byte bit_depth;
png_structp png_ptr;
png_infop info_ptr;
png_bytep *row_pointers;
png_byte color_type;
unsigned char header[8];
/* open file and test for it being a png */
infile = fopen(filename, "rb");
if (infile==NULL) {
fprintf(stderr,"Error! Could not open %s\n",filename);
return -1;
}
/* Check the header */
fread(header, 1, 8, infile);
if (png_sig_cmp(header, 0, 8)) {
fprintf(stderr,"Error! %s is not a PNG file\n",filename);
return -1;
}
/* initialize stuff */
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
fprintf(stderr,"Error create_read_struct\n");
exit(-1);
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
fprintf(stderr,"Error png_create_info_struct\n");
exit(-1);
}
png_init_io(png_ptr, infile);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
width = png_get_image_width(png_ptr, info_ptr);
height = png_get_image_height(png_ptr, info_ptr);
if (width==1280) {
*xsize=1280;
xadd=1;
}
else {
fprintf(stderr,"Unsupported width %d\n",width);
return -1;
}
if (png_type==PNG_WHOLETHING) {
*ysize=height;
ystart=0;
yadd=1;
}
else {
fprintf(stderr,"Unknown type\n");
return -1;
}
color_type = png_get_color_type(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
if (debug) {
printf("PNG: width=%d height=%d depth=%d\n",width,height,bit_depth);
if (color_type==PNG_COLOR_TYPE_RGB) printf("Type RGB\n");
else if (color_type==PNG_COLOR_TYPE_RGB_ALPHA) printf("Type RGBA\n");
else if (color_type==PNG_COLOR_TYPE_PALETTE) printf("Type palette\n");
printf("Generating output size %d x %d\n",*xsize,*ysize);
}
// number_of_passes = png_set_interlace_handling(png_ptr);
png_read_update_info(png_ptr, info_ptr);
row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
for (y=0; y<height; y++) {
/* FIXME: do we ever free these? */
row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
}
png_read_image(png_ptr, row_pointers);
fclose(infile);
image=calloc(width*height,sizeof(unsigned char));
if (image==NULL) {
fprintf(stderr,"Memory error!\n");
return -1;
}
out_ptr=image;
if (color_type==PNG_COLOR_TYPE_RGB_ALPHA) {
for(y=ystart;y<height;y+=yadd) {
for(x=0;x<width;x+=xadd) {
/* top color */
color= (row_pointers[y][x*xadd*4]<<16)+
(row_pointers[y][x*xadd*4+1]<<8)+
(row_pointers[y][x*xadd*4+2]);
if (debug) {
printf("%x ",color);
}
a2_color=convert_color(color,filename);
*out_ptr=a2_color;
out_ptr++;
}
if (debug) printf("\n");
}
}
else if (color_type==PNG_COLOR_TYPE_PALETTE) {
for(y=ystart;y<height;y+=yadd) {
for(x=0;x<width;x+=xadd) {
if (bit_depth==8) {
/* top color */
a2_color=row_pointers[y][x];
/* bottom color */
// color=row_pointers[y+(yadd/2)][x];
// a2_color|=(color<<4);
if (debug) {
printf("%x ",a2_color);
}
*out_ptr=a2_color;
out_ptr++;
}
else if (bit_depth==4) {
/* top color */
a2_color=row_pointers[y][x/2];
if (x%2==0) {
a2_color=(a2_color>>4);
}
a2_color&=0xf;
// /* bottom color */
// color=row_pointers[y+(yadd/2)][x/2];
// if (x%2==0) {
// color=(color>>4);
// }
// color&=0xf;
// a2_color|=(color<<4);
if (debug) {
printf("%x ",a2_color);
}
*out_ptr=a2_color;
out_ptr++;
}
}
if (debug) printf("\n");
}
}
else {
printf("Unknown color type\n");
}
*image_ptr=image;
return 0;
}

View File

@ -0,0 +1,9 @@
#define PNG_WHOLETHING 0
#define PNG_ODDLINES 1
#define PNG_EVENLINES 2
int loadpng(char *filename, unsigned char **image_ptr, int *xsize, int *ysize,
int png_type);
int loadpng80(char *filename, unsigned char **image_ptr, int *xsize, int *ysize,
int png_type);

188
games/keen/maps/png2map.c Normal file
View File

@ -0,0 +1,188 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "loadpng.h"
/* converts a png of map to format by our duke engine */
/* 1280x200 image */
/* 256 sprites of size 2x4 in a 16x16 grid at 8,4 */
static unsigned char tiles[256][2][4];
static unsigned char tilemap[256][40];
static unsigned char temp_tile[2][4];
static int ascii_output=0;
int main(int argc, char **argv) {
int i,j,x,y;
int numtiles=0,found_tile;
unsigned char *image;
int xsize,ysize;
FILE *outfile;
if (argc<3) {
fprintf(stderr,"Usage:\t%s INFILE OUTFILE\n\n",argv[0]);
exit(-1);
}
outfile=fopen(argv[2],"w");
if (outfile==NULL) {
fprintf(stderr,"Error! Could not open %s\n",argv[2]);
exit(-1);
}
if (loadpng(argv[1],&image,&xsize,&ysize,PNG_WHOLETHING)<0) {
fprintf(stderr,"Error loading png!\n");
exit(-1);
}
fprintf(stderr,"Loaded image %d by %d\n",xsize,ysize);
// for(x=0;x<128;x++) {
// for(y=0;y<64;y++) {
// printf("%02X,",image[(y*xsize)+x]);
// }
// printf("\n");
// }
/* loading tiles */
for(x=0;x<16;x++) {
for(y=0;y<16;y++) {
tiles[(y*16)+x][0][0]=image[((y*4+4)*xsize)+8+(x*4)];
tiles[(y*16)+x][1][0]=image[((y*4+4)*xsize)+8+(x*4)+2];
tiles[(y*16)+x][0][1]=image[((y*4+5)*xsize)+8+(x*4)];
tiles[(y*16)+x][1][1]=image[((y*4+5)*xsize)+8+(x*4)+2];
tiles[(y*16)+x][0][2]=image[((y*4+6)*xsize)+8+(x*4)];
tiles[(y*16)+x][1][2]=image[((y*4+6)*xsize)+8+(x*4)+2];
tiles[(y*16)+x][0][3]=image[((y*4+7)*xsize)+8+(x*4)];
tiles[(y*16)+x][1][3]=image[((y*4+7)*xsize)+8+(x*4)+2];
}
}
i=0;
for(j=0;j<256;j++) {
if ((tiles[j][0][0]!=0) ||
(tiles[j][1][0]!=0) ||
(tiles[j][0][1]!=0) ||
(tiles[j][1][1]!=0) ||
(tiles[j][0][2]!=0) ||
(tiles[j][1][2]!=0) ||
(tiles[j][0][3]!=0) ||
(tiles[j][1][3]!=0)) {
numtiles=j+1;
}
}
printf("Found %d tiles\n",numtiles);
if (ascii_output) {
fprintf(outfile,"tiles:\n");
for(i=0;i<numtiles;i++) {
fprintf(outfile,"tile%02x:\t.byte ",i);
fprintf(outfile,"$%02x,",tiles[i][0][0]+(tiles[i][0][1]<<4));
fprintf(outfile,"$%02x,",tiles[i][1][0]+(tiles[i][1][1]<<4));
fprintf(outfile,"$%02x,",tiles[i][0][2]+(tiles[i][0][3]<<4));
fprintf(outfile,"$%02x" ,tiles[i][1][2]+(tiles[i][1][3]<<4));
fprintf(outfile,"\n");
}
}
else {
for(i=0;i<256;i++) {
fputc(tiles[i][0][0]+(tiles[i][0][1]<<4),outfile);
fputc(tiles[i][1][0]+(tiles[i][1][1]<<4),outfile);
fputc(tiles[i][0][2]+(tiles[i][0][3]<<4),outfile);
fputc(tiles[i][1][2]+(tiles[i][1][3]<<4),outfile);
}
}
if (ascii_output) fprintf(outfile,"\n");
/* loading tilemap */
/* starts at 80,12 */
for(x=0;x<256;x++) {
for(y=0;y<40;y++) {
/* get temp tile */
temp_tile[0][0]=image[((y*4+12)*xsize)+80+(x*4)];
temp_tile[1][0]=image[((y*4+12)*xsize)+80+(x*4)+2];
temp_tile[0][1]=image[((y*4+13)*xsize)+80+(x*4)];
temp_tile[1][1]=image[((y*4+13)*xsize)+80+(x*4)+2];
temp_tile[0][2]=image[((y*4+14)*xsize)+80+(x*4)];
temp_tile[1][2]=image[((y*4+14)*xsize)+80+(x*4)+2];
temp_tile[0][3]=image[((y*4+15)*xsize)+80+(x*4)];
temp_tile[1][3]=image[((y*4+15)*xsize)+80+(x*4)+2];
/* find tile */
found_tile=-1;
/* if all black, assume transparent */
if ((temp_tile[0][0]==0) &&
(temp_tile[1][0]==0) &&
(temp_tile[0][1]==0) &&
(temp_tile[1][1]==0) &&
(temp_tile[0][2]==0) &&
(temp_tile[1][2]==0) &&
(temp_tile[0][3]==0) &&
(temp_tile[1][3]==0)) {
found_tile=0;
}
else for(i=0;i<numtiles;i++) {
if ((temp_tile[0][0]==tiles[i][0][0]) &&
(temp_tile[1][0]==tiles[i][1][0]) &&
(temp_tile[0][1]==tiles[i][0][1]) &&
(temp_tile[1][1]==tiles[i][1][1]) &&
(temp_tile[0][2]==tiles[i][0][2]) &&
(temp_tile[1][2]==tiles[i][1][2]) &&
(temp_tile[0][3]==tiles[i][0][3]) &&
(temp_tile[1][3]==tiles[i][1][3])) {
found_tile=i;
break;
}
}
tilemap[x][y]=found_tile;
if (found_tile==-1) {
printf("Error! Unknown tile at %d,%d\n",
80+(x*4),12+(y*4));
}
}
}
if (ascii_output) {
fprintf(outfile,"tilemap:\n");
for(j=0;j<40;j++) {
fprintf(outfile,"\t.byte ");
for(i=0;i<256;i++) {
fprintf(outfile,"$%02x",tilemap[i][j]);
if (i!=255) fprintf(outfile,",");
}
fprintf(outfile,"\n");
}
fprintf(outfile,"\n");
}
else {
for(j=0;j<40;j++) {
for(i=0;i<256;i++) {
fputc(tilemap[i][j],outfile);
}
}
}
fclose(outfile);
return 0;
}

394
games/keen/move_keen.s Normal file
View File

@ -0,0 +1,394 @@
KEEN_SPEED = $80
YDEFAULT = 20
HARD_TILES = 32 ; start at 32
;=========================
; move keen
;=========================
move_keen:
lda #0
sta SUPPRESS_WALK
jsr keen_get_feet_location ; get location of feet
jsr check_falling ; check for/handle falling
jsr keen_collide ; check for right/left collision
jsr handle_jumping ; handle jumping
lda KEEN_WALKING
beq done_move_keen
lda SUPPRESS_WALK
bne done_move_keen
lda KEEN_DIRECTION
bmi move_left
lda KEEN_X
cmp #22
bcc keen_walk_right
keen_scroll_right:
clc
lda KEEN_XL
adc #KEEN_SPEED
sta KEEN_XL
bcc skip_keen_scroll_right
inc TILEMAP_X
jsr copy_tilemap_subset
skip_keen_scroll_right:
jmp done_move_keen
keen_walk_right:
lda KEEN_XL
clc
adc #KEEN_SPEED
sta KEEN_XL
bcc dwr_noflo
inc KEEN_X
dwr_noflo:
jmp done_move_keen
move_left:
lda KEEN_X
cmp #14
bcs keen_walk_left
keen_scroll_left:
sec
lda KEEN_XL
sbc #KEEN_SPEED
sta KEEN_XL
bcs skip_keen_scroll_left
dec TILEMAP_X
jsr copy_tilemap_subset
skip_keen_scroll_left:
jmp done_move_keen
keen_walk_left:
lda KEEN_XL
sec
sbc #KEEN_SPEED
sta KEEN_XL
bcs dwl_noflo
dec KEEN_X
dwl_noflo:
jmp done_move_keen
done_move_keen:
rts
;=========================
; keen collide
;=========================
keen_collide:
;==================
; check for item
;==================
keen_check_item:
lda KEEN_FOOT_OFFSET
sec
sbc #16
tax
jsr check_item
;===================
; collide with head
;===================
keen_check_head:
; only check above head if jumping
lda KEEN_JUMPING
beq collide_left_right
lda KEEN_FOOT_OFFSET
sec
sbc #16 ; above head is -2 rows
tax
lda TILEMAP,X
; if tile# < HARD_TILES then we are fine
cmp #HARD_TILES
bcc collide_left_right ; blt
lda #0
sta KEEN_JUMPING
lda #1
sta KEEN_FALLING
jsr head_noise
collide_left_right:
;===================
; collide left/right
;===================
lda KEEN_DIRECTION
beq done_keen_collide
bmi check_left_collide
check_right_collide:
lda KEEN_FOOT_OFFSET
clc
adc #1 ; right is one to right
tax
lda TILEMAP,X
; if tile# < HARD_TILES then we are fine
cmp #HARD_TILES
bcc done_keen_collide ; blt
lda #1 ;
sta SUPPRESS_WALK
jmp done_keen_collide
check_left_collide:
lda KEEN_FOOT_OFFSET
sec
sbc #2 ; left is one to left
; +1 fudge factor
tax
lda TILEMAP,X
; if tile# < HARD_TILES then we are fine
cmp #HARD_TILES
bcc done_keen_collide ; blt
lda #1
sta SUPPRESS_WALK
jmp done_keen_collide
done_keen_collide:
rts
;=========================
; check_jumping
;=========================
handle_jumping:
lda KEEN_JUMPING
beq done_handle_jumping
lda KEEN_Y
beq dont_wrap_jump
dec KEEN_Y
dec KEEN_Y
dont_wrap_jump:
dec KEEN_JUMPING
bne done_handle_jumping
lda #1 ; avoid gap before falling triggered
sta KEEN_FALLING
done_handle_jumping:
rts
;=======================
; keen_get_feet_location
;=======================
; xx 0
; xx 1
;------ -----
; xx 0 xx 2
; xx 1 xx 3
; xx 2 xx 4
; xx 3 xx 5
;------ -------
; xx 4 xx 6
; xx 5 xx 7
; xx 6
; xx 7
;-----------------------
; YY = block
;========================
; YYYY YYYY
; -XX- -XX-
; -XX- -XX-
; left, foot = (X+1)/2
; right, foot = (X+2)/2
keen_get_feet_location:
; + 1 is because sprite is 4 pixels wide?
; screen is 16 wide, but offset 4 in
; to get to feet add 6 to Y?
; block index of foot is (feet approximately 6 lower than Y)
; INT((y+4)/4)*16 + (x-4+1/2)
; FIXME: if 18,18 -> INT(26/4)*16 = 96 + 7 = 103 = 6R7
; 0 = 32 (2)
; 1 = 32 (2)
; 2 = 32 (2)
; 3 = 32 (2)
; 4 = 48 (3)
; 5 = 48 (3)
; 6 = 48 (3)
; 7 = 48 (3)
lda KEEN_Y
clc
adc #4 ; +4
lsr ; / 4 (INT)
lsr
asl ; *4
asl
asl
asl
sta KEEN_FOOT_OFFSET
; lda KEEN_DIRECTION
; bmi foot_left
foot_right:
lda KEEN_X
clc
adc #2
; jmp foot_done
;foot_left:
; lda KEEN_X
; sec
; sbc #1
foot_done:
lsr
; offset by two block at edge of screen
sec
sbc #2
clc
adc KEEN_FOOT_OFFSET
sta KEEN_FOOT_OFFSET
rts
;=========================
; check_falling
;=========================
check_falling:
lda KEEN_JUMPING
bne done_check_falling ; don't check falling if jumping
lda KEEN_FOOT_OFFSET
clc
adc #16 ; underfoot is on next row (+16)
tax
lda TILEMAP,X
; if tile# < HARD_TILES then we fall
cmp #HARD_TILES
bcs feet_on_ground ; bge
;=======================
; falling
lda #1
sta KEEN_FALLING
; scroll but only if Y>=20 (YDEFAULT)
lda KEEN_Y
cmp #YDEFAULT
bcs scroll_fall ; bge
inc KEEN_Y
inc KEEN_Y
jmp done_check_falling
scroll_fall:
inc TILEMAP_Y
jsr copy_tilemap_subset
jmp done_check_falling
feet_on_ground:
;===========================
; if had been falling
; kick up dust, make noise
; stop walking?
lda KEEN_FALLING
beq was_not_falling
; clear falling
lda #0
sta KEEN_FALLING
lda #2
sta KICK_UP_DUST
lda #0
sta KEEN_WALKING
jsr land_noise
was_not_falling:
; check to see if Y still hi, if so scroll back down
lda KEEN_Y
cmp #YDEFAULT
bcs done_check_falling ; bge
; too high up on screen, adjust down and also adjust tilemap down
inc KEEN_Y
inc KEEN_Y
dec TILEMAP_Y ; share w above?
jsr copy_tilemap_subset
done_check_falling:
rts

56
games/keen/quit_yn.s Normal file
View File

@ -0,0 +1,56 @@
; Quit? Are you sure?
print_quit:
bit KEYRESET ; clear keyboard
bit SET_TEXT
lda #' '|$80
sta clear_all_color+1
jsr clear_all
lda #6
sta drawbox_x1
lda #33
sta drawbox_x2
lda #8
sta drawbox_y1
lda #13
sta drawbox_y2
jsr drawbox
jsr normal_text
lda #<quit_text
sta OUTL
lda #>quit_text
sta OUTH
jsr move_and_print_list
jsr page_flip
query_quit:
lda KEYPRESS
bpl query_quit
bit KEYRESET
cmp #'Y'|$80
beq really_quit
cmp #'y'|$80
beq really_quit
bit SET_GR
rts
really_quit:
lda #GAME_OVER
sta LEVEL_OVER
lda #LOAD_TITLE
sta WHICH_LOAD
rts
quit_text:
.byte 8,10,"ARE YOU SURE YOU WANT TO",0
.byte 14,11,"QUIT? (Y/N)",0
.byte 255

149
games/keen/sound_effects.s Normal file
View File

@ -0,0 +1,149 @@
;======================
; noise when jump
jump_noise:
lda SOUND_STATUS
bmi done_jump_noise
; bit $C030
done_jump_noise:
rts
;======================
; noise when bump head
head_noise:
lda SOUND_STATUS
bmi done_head_noise
lda #NOTE_D3
sta speaker_frequency
lda #5
sta speaker_duration
jsr speaker_tone
; bit $C030
; bit $C030
done_head_noise:
rts
;======================
; noise when land after jump
land_noise:
lda SOUND_STATUS
bmi done_land_noise
; bit $C030
done_land_noise:
rts
;======================
; rumble noise
rumble_noise:
lda SOUND_STATUS
bmi done_rumble_noise
ldx #50
rumble_red:
bit $C030
lda #100
jsr WAIT
dex
bne rumble_red
done_rumble_noise:
rts
;======================
; pickup noise
; C, two octaves+C?
pickup_noise:
lda SOUND_STATUS
bmi done_pickup_noise
lda #NOTE_C3
sta speaker_frequency
lda #25
sta speaker_duration
jsr speaker_tone
lda #NOTE_C5
sta speaker_frequency
lda #20
sta speaker_duration
jsr speaker_tone
done_pickup_noise:
rts
;======================
; buzzer noise
; C, two octaves+C?
buzzer_noise:
lda SOUND_STATUS
bmi done_buzzer_noise
lda #NOTE_C3
sta speaker_frequency
lda #10
sta speaker_duration
jsr speaker_tone
done_buzzer_noise:
rts
;======================
; enemy noise
enemy_noise:
lda SOUND_STATUS
bmi done_enemy_noise
lda #NOTE_A3
sta speaker_frequency
lda #20
sta speaker_duration
jsr speaker_tone
lda #NOTE_A4
sta speaker_frequency
lda #10
sta speaker_duration
jsr speaker_tone
done_enemy_noise:
rts
;======================
; laser noise
laser_noise:
lda SOUND_STATUS
bmi done_enemy_noise
lda #NOTE_D4
sta speaker_frequency
lda #15
sta speaker_duration
jsr speaker_tone
done_laser_noise:
rts

67
games/keen/speaker_tone.s Normal file
View File

@ -0,0 +1,67 @@
; based on code from here
; http://eightbitsoundandfury.ld8.org/programming.html
; A,X,Y trashed
; duration also trashed
NOTE_C3 = 255
NOTE_CSHARP3 = 241
NOTE_D3 = 227
NOTE_DSHARP3 = 214
NOTE_E3 = 202
NOTE_F3 = 191
NOTE_FSHARP3 = 180
NOTE_G3 = 170
NOTE_GSHARP3 = 161
NOTE_A3 = 152
NOTE_ASHARP3 = 143
NOTE_B3 = 135
NOTE_C4 = 128
NOTE_CSHARP4 = 121
NOTE_D4 = 114
NOTE_DSHARP4 = 108
NOTE_E4 = 102
NOTE_F4 = 96
NOTE_FSHARP4 = 91
NOTE_G4 = 85
NOTE_GSHARP4 = 81
NOTE_A4 = 76
NOTE_ASHARP4 = 72
NOTE_B4 = 68
NOTE_C5 = 64
NOTE_CSHARP5 = 60
NOTE_D5 = 57
NOTE_DSHARP5 = 54
NOTE_E5 = 51
NOTE_F5 = 48
NOTE_FSHARP5 = 45
NOTE_G5 = 43
NOTE_GSHARP5 = 40
NOTE_A5 = 38
NOTE_ASHARP5 = 36
NOTE_B5 = 34
speaker_tone:
lda $C030 ; click speaker
speaker_loop:
dey ; y never set?
bne slabel1 ; duration roughly 256*?
dec speaker_duration ; (Duration)
beq done_tone
slabel1:
dex
bne speaker_loop
ldx speaker_frequency ; (Frequency)
jmp speaker_tone
done_tone:
rts
speaker_duration:
.byte $00
speaker_frequency:
.byte $00

177
games/keen/status_bar.s Normal file
View File

@ -0,0 +1,177 @@
; Draw Status Bar
;===========================
; inc_score_by_10
;===========================
; FIXME: make sure interrupt routine handles d flag properly
inc_score_by_10:
sed
lda SCORE0
clc
adc #$10
sta SCORE0
lda SCORE1
adc #0
sta SCORE1
lda SCORE2
adc #0
sta SCORE2
cld
jsr update_score
rts
;===========================
; update score
;===========================
update_score:
lda SCORE0
and #$f
ora #$b0 ; 0 -> $b0
sta status_string+6
lda SCORE0
lsr
lsr
lsr
lsr
ora #$b0 ; 0 -> $b0
sta status_string+5
lda SCORE1
and #$f
ora #$b0 ; 0 -> $b0
sta status_string+4
lda SCORE1
lsr
lsr
lsr
lsr
ora #$b0 ; 0 -> $b0
sta status_string+3
lda SCORE2
and #$f
ora #$b0 ; 0 -> $b0
sta status_string+2
lda #2
sta UPDATE_STATUS
rts
;===========================
; update health
;===========================
update_health:
ldx #0
update_health_loop:
cpx HEALTH
bcc health_on
lda #'_'|$80
bne done_health
health_on:
lda #' '
done_health:
sta status_string+9,X
inx
cpx #8
bne update_health_loop
rts
;===========================
; update items
;===========================
update_items:
lda INVENTORY
and #INV_RED_KEY
beq done_red_key
lda #'R'&$3f
sta status_string+33
done_red_key:
lda INVENTORY
and #INV_BLUE_KEY
beq done_blue_key
lda #'B'&$3f
sta status_string+35
done_blue_key:
rts
;===========================
; update the status bar
;===========================
update_status_bar:
jsr update_score
jsr update_health
jsr update_items
lda #2
sta UPDATE_STATUS
rts
;===========================
; draw the status bar
;===========================
draw_status_bar:
; to improve frame rate, only draw if update status set?
; not implemented yet
jsr inverse_text ; print help node
lda #<help_string
sta OUTL
lda #>help_string
sta OUTH
jsr move_and_print
jsr normal_text ; (normal)
jsr move_and_print ; print explain text
jsr raw_text
jsr move_and_print ; print status line
rts
help_string:
.byte 3,20," PRESS 'H' FOR HELP ",0
score_string:
; 012456789012345678901234567890123456789
.byte 0,22,"SCORE HEALTH FIREPOWER INVENTORY",0
status_string:
; .byte 0,23,"ZZZZZ XXXXXXXX =- ",0
.byte 0,23,"ZZZZZ"
.byte ' '|$80,' '|$80
.byte "XXXXXXXX"
.byte ' '|$80,' '|$80
.byte '='|$80,'-'|$80,' '|$80,' '|$80,' '|$80,' '|$80,' '|$80,' '|$80,' '|$80,' '|$80
.byte ' '|$80,' '|$80,' '|$80,' '|$80,' '|$80,' '|$80,' '|$80,' '|$80,' '|$80,' '|$80,' '|$80,' '|$80,0

84
games/keen/text_drawbox.s Normal file
View File

@ -0,0 +1,84 @@
; draw inverse box on text screen
; we could use HLIN/VLIN instead?
; note Y should be in text coords (0..23) not GR (0..47)
drawbox:
lda drawbox_y1
jsr text_hlin
lda drawbox_y2
jsr text_hlin
jsr text_vlins
rts
;========================
; text hlin
;========================
; draw from x1,A to x2,A
text_hlin:
asl
tay
lda gr_offsets,Y
sta OUTL
lda gr_offsets+1,Y
clc
adc DRAW_PAGE
sta OUTH
lda #' '
ldy drawbox_x1
drawbox_hlin_loop:
sta (OUTL),Y
iny
cpy drawbox_x2
bne drawbox_hlin_loop
rts
;========================
; text vlin
;========================
; draw from A,y1 to A,y2
text_vlins:
ldx drawbox_y1
text_vlins_loop:
txa
asl
tay
lda gr_offsets,Y
sta OUTL
lda gr_offsets+1,Y
clc
adc DRAW_PAGE
sta OUTH
lda #' '
ldy drawbox_x1
sta (OUTL),Y
ldy drawbox_x2
sta (OUTL),Y
inx
cpx drawbox_y2
bcc text_vlins_loop
beq text_vlins_loop ; ble
rts
drawbox_x1: .byte $00
drawbox_x2: .byte $00
drawbox_y1: .byte $00
drawbox_y2: .byte $00

View File

@ -88,12 +88,12 @@ PATTERN_H = $7F
WHICH_LOAD = $80 ; which file to load
DUKE_XL = $81
DUKE_X = $82 ; location of protagonist
DUKE_Y = $83
DUKE_DIRECTION = $84
DUKE_WALKING = $85
DUKE_JUMPING = $86
KEEN_XL = $81
KEEN_X = $82 ; location of protagonist
KEEN_Y = $83
KEEN_DIRECTION = $84
KEEN_WALKING = $85
KEEN_JUMPING = $86
LASER_OUT = $87
LASER_X = $88
@ -102,7 +102,7 @@ LASER_DIRECTION = $8A
TILEMAP_X = $8B
TILEMAP_Y = $8C
DUKE_FOOT_OFFSET = $8D
KEEN_FOOT_OFFSET = $8D
FIREPOWER = $8E
INVENTORY = $8F
@ -116,8 +116,8 @@ SCORE1 = $92
SCORE2 = $93
UPDATE_STATUS = $94
DUKE_FALLING = $95
DUKE_SHOOTING = $96
KEEN_FALLING = $95
KEEN_SHOOTING = $96
KICK_UP_DUST = $97
SUPPRESS_WALK = $98
ENEMY_DATAL = $99