From a091e8e7ecb55f1d33e55df5cd0d9939c281f666 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Sun, 10 Mar 2024 00:44:20 -0500 Subject: [PATCH] keen1: initial mostly working proof --- games/duke/{ => old}/level1_data.inc | 0 games/keen/Makefile | 98 +++++++ games/keen/actions_level1.s | 204 ++++++++++++++ games/keen/draw_keen.s | 120 ++++++++ games/keen/draw_tilemap.s | 143 ++++++++++ games/keen/enemies_level1.s | 339 +++++++++++++++++++++++ games/keen/gr_offsets.s | 5 + games/keen/gr_pageflip.s | 24 ++ games/keen/gr_putsprite_crop.s | 359 ++++++++++++++++++++++++ games/keen/graphics/Makefile | 11 +- games/keen/graphics/level1_bg.png | Bin 0 -> 14255 bytes games/keen/handle_laser.s | 100 +++++++ games/keen/hello.bas | 14 + games/keen/init_vars.s | 10 +- games/keen/item_level1.s | 49 ++++ games/keen/joystick.s | 46 ++++ games/keen/keen_level1.s | 243 +++++++++++++++++ games/keen/keen_title.s | 2 +- games/keen/keyboard.s | 251 +++++++++++++++++ games/keen/level_end.s | 65 +++++ games/keen/maps/LEVEL_RULES | 3 + games/keen/maps/Makefile | 34 +++ games/keen/maps/level1_map.png | Bin 0 -> 9232 bytes games/keen/maps/loadpng.c | 236 ++++++++++++++++ games/keen/maps/loadpng.h | 9 + games/keen/maps/png2map.c | 188 +++++++++++++ games/keen/move_keen.s | 394 +++++++++++++++++++++++++++ games/keen/quit_yn.s | 56 ++++ games/keen/sound_effects.s | 149 ++++++++++ games/keen/speaker_tone.s | 67 +++++ games/keen/status_bar.s | 177 ++++++++++++ games/keen/text_drawbox.s | 84 ++++++ games/keen/zp.inc | 18 +- 33 files changed, 3482 insertions(+), 16 deletions(-) rename games/duke/{ => old}/level1_data.inc (100%) create mode 100644 games/keen/Makefile create mode 100644 games/keen/actions_level1.s create mode 100644 games/keen/draw_keen.s create mode 100644 games/keen/draw_tilemap.s create mode 100644 games/keen/enemies_level1.s create mode 100644 games/keen/gr_offsets.s create mode 100644 games/keen/gr_pageflip.s create mode 100644 games/keen/gr_putsprite_crop.s create mode 100644 games/keen/graphics/level1_bg.png create mode 100644 games/keen/handle_laser.s create mode 100644 games/keen/hello.bas create mode 100644 games/keen/item_level1.s create mode 100644 games/keen/joystick.s create mode 100644 games/keen/keen_level1.s create mode 100644 games/keen/keyboard.s create mode 100644 games/keen/level_end.s create mode 100644 games/keen/maps/LEVEL_RULES create mode 100644 games/keen/maps/Makefile create mode 100644 games/keen/maps/level1_map.png create mode 100644 games/keen/maps/loadpng.c create mode 100644 games/keen/maps/loadpng.h create mode 100644 games/keen/maps/png2map.c create mode 100644 games/keen/move_keen.s create mode 100644 games/keen/quit_yn.s create mode 100644 games/keen/sound_effects.s create mode 100644 games/keen/speaker_tone.s create mode 100644 games/keen/status_bar.s create mode 100644 games/keen/text_drawbox.s diff --git a/games/duke/level1_data.inc b/games/duke/old/level1_data.inc similarity index 100% rename from games/duke/level1_data.inc rename to games/duke/old/level1_data.inc diff --git a/games/keen/Makefile b/games/keen/Makefile new file mode 100644 index 00000000..15bf6ece --- /dev/null +++ b/games/keen/Makefile @@ -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 + diff --git a/games/keen/actions_level1.s b/games/keen/actions_level1.s new file mode 100644 index 00000000..6b153c60 --- /dev/null +++ b/games/keen/actions_level1.s @@ -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 + diff --git a/games/keen/draw_keen.s b/games/keen/draw_keen.s new file mode 100644 index 00000000..43a98a11 --- /dev/null +++ b/games/keen/draw_keen.s @@ -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 + jmp actually_draw_keen + +check_jumping_right: + lda KEEN_JUMPING + beq check_shooting_right +draw_jumping_right: + ldx #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 + 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 + jmp actually_draw_keen + +draw_standing_right: + ldx #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 + jmp actually_draw_keen + +check_jumping_left: + lda KEEN_JUMPING + beq check_shooting_left +draw_jumping_left: + ldx #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 + 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 + jmp actually_draw_keen + +draw_standing_left: + ldx #keen_sprite_stand_left + jmp actually_draw_keen + + + ;==================== + ; actually draw + +actually_draw_keen: + stx INL + sta INH + jsr put_sprite_crop + + rts + + diff --git a/games/keen/draw_tilemap.s b/games/keen/draw_tilemap.s new file mode 100644 index 00000000..677dd7a0 --- /dev/null +++ b/games/keen/draw_tilemap.s @@ -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 # 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 + + diff --git a/games/keen/gr_offsets.s b/games/keen/gr_offsets.s new file mode 100644 index 00000000..d3af91f7 --- /dev/null +++ b/games/keen/gr_offsets.s @@ -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 + diff --git a/games/keen/gr_pageflip.s b/games/keen/gr_pageflip.s new file mode 100644 index 00000000..f199f5be --- /dev/null +++ b/games/keen/gr_pageflip.s @@ -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 + diff --git a/games/keen/gr_putsprite_crop.s b/games/keen/gr_putsprite_crop.s new file mode 100644 index 00000000..72fd8ab2 --- /dev/null +++ b/games/keen/gr_putsprite_crop.s @@ -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 diff --git a/games/keen/graphics/Makefile b/games/keen/graphics/Makefile index 8edb44e5..6fb28fa5 100644 --- a/games/keen/graphics/Makefile +++ b/games/keen/graphics/Makefile @@ -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 diff --git a/games/keen/graphics/level1_bg.png b/games/keen/graphics/level1_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..9a6005f1813b21ae52d12255f889c6fa5019f9e2 GIT binary patch literal 14255 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 J*2`Om|1WblS;_za literal 0 HcmV?d00001 diff --git a/games/keen/handle_laser.s b/games/keen/handle_laser.s new file mode 100644 index 00000000..f3fe8469 --- /dev/null +++ b/games/keen/handle_laser.s @@ -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 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 + diff --git a/games/keen/hello.bas b/games/keen/hello.bas new file mode 100644 index 00000000..0be6d720 --- /dev/null +++ b/games/keen/hello.bas @@ -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" diff --git a/games/keen/init_vars.s b/games/keen/init_vars.s index 538b9b1d..e7800fa8 100644 --- a/games/keen/init_vars.s +++ b/games/keen/init_vars.s @@ -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 diff --git a/games/keen/item_level1.s b/games/keen/item_level1.s new file mode 100644 index 00000000..043c7ae3 --- /dev/null +++ b/games/keen/item_level1.s @@ -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 diff --git a/games/keen/joystick.s b/games/keen/joystick.s new file mode 100644 index 00000000..751fd039 --- /dev/null +++ b/games/keen/joystick.s @@ -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 + diff --git a/games/keen/keen_level1.s b/games/keen/keen_level1.s new file mode 100644 index 00000000..b5ecb7fe --- /dev/null +++ b/games/keen/keen_level1.s @@ -0,0 +1,243 @@ +; Keen PoC Level 1 + +; by deater (Vince Weaver) + +; 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_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+1 + + lda #$c ; load to page $c00 + + jsr full_decomp + + + ;==================================== + ; load level1 tilemap + ;==================================== + + 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" diff --git a/games/keen/keen_title.s b/games/keen/keen_title.s index 262e51e6..364ecbae 100644 --- a/games/keen/keen_title.s +++ b/games/keen/keen_title.s @@ -186,7 +186,7 @@ done_intro: ;============================ ; set up initial location - lda #LOAD_DUKE1 + lda #LOAD_KEEN1 sta WHICH_LOAD ; start at first level rts diff --git a/games/keen/keyboard.s b/games/keen/keyboard.s new file mode 100644 index 00000000..7cab8b56 --- /dev/null +++ b/games/keen/keyboard.s @@ -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 diff --git a/games/keen/level_end.s b/games/keen/level_end.s new file mode 100644 index 00000000..2836b615 --- /dev/null +++ b/games/keen/level_end.s @@ -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 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 diff --git a/games/keen/maps/LEVEL_RULES b/games/keen/maps/LEVEL_RULES new file mode 100644 index 00000000..dab4da83 --- /dev/null +++ b/games/keen/maps/LEVEL_RULES @@ -0,0 +1,3 @@ +Urgh I've completely forgotten all of this + +Fall through tiles that are < HARD_TILES which defaults to 32 diff --git a/games/keen/maps/Makefile b/games/keen/maps/Makefile new file mode 100644 index 00000000..c20515dc --- /dev/null +++ b/games/keen/maps/Makefile @@ -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 diff --git a/games/keen/maps/level1_map.png b/games/keen/maps/level1_map.png new file mode 100644 index 0000000000000000000000000000000000000000..8fe435b4e263f1542e7a4a654b4a231033d08598 GIT binary patch literal 9232 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 Nw)db>jsfY^zX8?9oy-6L literal 0 HcmV?d00001 diff --git a/games/keen/maps/loadpng.c b/games/keen/maps/loadpng.c new file mode 100644 index 00000000..dae7fbaa --- /dev/null +++ b/games/keen/maps/loadpng.c @@ -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 +#include + +#include +#include +#include +#include +#include + +#include +#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>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; +} + + + + + diff --git a/games/keen/maps/loadpng.h b/games/keen/maps/loadpng.h new file mode 100644 index 00000000..51882f61 --- /dev/null +++ b/games/keen/maps/loadpng.h @@ -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); + diff --git a/games/keen/maps/png2map.c b/games/keen/maps/png2map.c new file mode 100644 index 00000000..37ff27ba --- /dev/null +++ b/games/keen/maps/png2map.c @@ -0,0 +1,188 @@ +#include +#include + +#include +#include +#include +#include +#include + +#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 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 + + + diff --git a/games/keen/quit_yn.s b/games/keen/quit_yn.s new file mode 100644 index 00000000..a1256c5c --- /dev/null +++ b/games/keen/quit_yn.s @@ -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 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 diff --git a/games/keen/sound_effects.s b/games/keen/sound_effects.s new file mode 100644 index 00000000..fb1c0acd --- /dev/null +++ b/games/keen/sound_effects.s @@ -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 + diff --git a/games/keen/speaker_tone.s b/games/keen/speaker_tone.s new file mode 100644 index 00000000..069cf498 --- /dev/null +++ b/games/keen/speaker_tone.s @@ -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 + diff --git a/games/keen/status_bar.s b/games/keen/status_bar.s new file mode 100644 index 00000000..d167af36 --- /dev/null +++ b/games/keen/status_bar.s @@ -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 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 + diff --git a/games/keen/text_drawbox.s b/games/keen/text_drawbox.s new file mode 100644 index 00000000..8855c0bc --- /dev/null +++ b/games/keen/text_drawbox.s @@ -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 + diff --git a/games/keen/zp.inc b/games/keen/zp.inc index 25419a34..5d3c3036 100644 --- a/games/keen/zp.inc +++ b/games/keen/zp.inc @@ -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