taytyypa-menna-nopeasti/main.asm
Juhani Krekelä 411fa8c8d8 Jam version done
2025-10-26 15:03:33 +02:00

675 lines
No EOL
9.9 KiB
NASM

bits 16
org 0x100
SCREEN_WIDTH equ 320
SCREEN_HEIGHT equ 200
PLAYFIELD_HEIGHT equ 12 * 16
PLAYER_MIN_X equ -5
PLAYER_MAX_X equ 5
PLAYER_MIN_Y equ -10
PLAYER_MAX_Y equ 8
call video_init
call keyboard_init
call timer_init
call sound_off
level_intro:
mov [timer_tick.level_timer], 50
call get_backbuffer
call clear_screen
mov ah, 9
mov dx, intro_message
int 0x21
.wait:
hlt
cmp [timer_tick.level_timer], 0
jne .wait
mov word si, [level_objects]
lodsb
xor bh, bh
mov bl, al
mov byte [level_data + bx], 'W'
hazards:
lodsb
cmp al, 0xff
je .done
xor bh, bh
mov bl, al
mov byte [level_data + bx], '@'
.done:
reset_level:
call sound_off
mov ah, 7
call set_ink
call draw_level
mov ax, [level_timer_max]
mov [timer_tick.level_timer], ax
mov word [cursor_x], 160
mov word [cursor_y], 10
mov word [old_cursor_x], 160
mov word [old_cursor_y], 10
mov byte [turbo], 0
mov word [music_index], 0
mov byte [music_counter], 0
mainloop:
mov byte [timer_tick.done], 0
music:
cmp byte [music_counter], 0
jne .still_note_remaining
call sound_off
mov si, [music_index]
add si, music_data
lodsb
cmp al, 0xff
je .silence
call set_note
call sound_on
.silence:
lodsb
mov [music_counter], al
add word [music_index], 2
cmp word [music_index], music_data.end - music_data
jb .still_data_remaining
mov word [music_index], 0
.still_data_remaining:
.still_note_remaining:
dec byte [music_counter]
level_timer:
mov ax, [timer_tick.level_timer]
test ax, ax
je reset_level
mov bx, SCREEN_WIDTH
mul bx
div word [level_timer_max]
mov [level_timer_progress], ax
draw:
call get_backbuffer
mov ax, [old_cursor_x]
mov bx, [old_cursor_y]
cmp [cursor_x], ax
jne .erase_player
cmp [cursor_y], bx
je .no_erase_player
.erase_player:
mov cl, [turbo]
or [need_actual_clear], cl
test cl, cl
jnz .no_erase_player
mov dl, 0
call draw_player
.no_erase_player:
cmp byte [timer_tick.screenclear], 0
jne .no_clear
mov byte [timer_tick.screenclear], 1
cmp byte [need_actual_clear], 0
je .no_clear
mov byte [need_actual_clear], 0
call draw_level
.no_clear:
mov ah, 3
call set_ink
mov ax, [cursor_x]
mov bx, [cursor_y]
mov dl, 1
call draw_player
mov [old_cursor_x], ax
mov [old_cursor_y], bx
mov ax, [level_timer_progress]
mov bx, PLAYFIELD_HEIGHT
mov si, SCREEN_WIDTH
dec si
mov di, PLAYFIELD_HEIGHT
mov dl, 0
call draw_line
mov ax, 0
mov si, [level_timer_progress]
dec si
mov dl, 1
call draw_line
mov ah, 7
call set_ink
;call flip_pages
input:
call read_key
jnc .no_key
cmp ax, [key_codes.exit]
je game_end
.no_key:
update_cursor:
mov ax, 0 ; delta X
mov bx, 0 ; delta Y
cmp byte [key_held.left], 0
je .not_left
dec ax
.not_left:
cmp byte [key_held.right], 0
je .not_right
inc ax
.not_right:
cmp byte [key_held.up], 0
je .not_up
dec bx
.not_up:
cmp byte [key_held.down], 0
je .not_down
inc bx
.not_down:
add [cursor_x], ax
add [cursor_y], bx
mov [cursor_dx], ax
mov [cursor_dy], bx
cmp word [cursor_x], 0
jge .x_not_underflow
mov word [cursor_x], 0
.x_not_underflow:
cmp word [cursor_x], SCREEN_WIDTH
jl .x_not_overflow
mov word [cursor_x], SCREEN_WIDTH - 1
.x_not_overflow:
cmp word [cursor_y], 0
jge .y_not_underflow
mov word [cursor_y], 0
.y_not_underflow:
cmp word [cursor_y], PLAYFIELD_HEIGHT
jl .y_not_overflow
mov word [cursor_y], PLAYFIELD_HEIGHT - 1
.y_not_overflow:
horizontal_collision:
sub [cursor_y], bx
cmp word [cursor_dx], 0
jl .towards_left
jg .towards_right
jmp .end
.towards_left:
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MIN_X
add bx, PLAYER_MIN_Y
call get_tile_at
cmp al, 'x'
je .collided
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MIN_X
call get_tile_at
cmp al, 'x'
je .collided
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MIN_X
add bx, PLAYER_MAX_Y
call get_tile_at
cmp al, 'x'
je .collided
jmp .end
.towards_right:
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MAX_X
add bx, PLAYER_MIN_Y
call get_tile_at
cmp al, 'x'
je .collided
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MAX_X
call get_tile_at
cmp al, 'x'
je .collided
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MAX_X
add bx, PLAYER_MAX_Y
call get_tile_at
cmp al, 'x'
je .collided
jmp .end
.collided:
mov ax, [cursor_dx]
sub [cursor_x], ax
.end:
mov bx, [cursor_dy]
add [cursor_y], bx
vertical_collision:
cmp word [cursor_dy], 0
jl .upwards
jg .downwards
jmp .end
.upwards:
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MIN_X
add bx, PLAYER_MIN_Y
call get_tile_at
cmp al, 'x'
je .collided
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MAX_X
add bx, PLAYER_MIN_Y
call get_tile_at
cmp al, 'x'
je .collided
jmp .end
.downwards:
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MIN_X
add bx, PLAYER_MAX_Y
call get_tile_at
cmp al, 'x'
je .collided
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MAX_X
add bx, PLAYER_MAX_Y
call get_tile_at
cmp al, 'x'
je .collided
jmp .end
.collided:
mov bx, [cursor_dy]
sub [cursor_y], bx
.end:
tile_collisions:
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MIN_X
add bx, PLAYER_MIN_Y
call .test_point
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MAX_X
add bx, PLAYER_MIN_Y
call .test_point
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MIN_X
call .test_point
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MAX_X
call .test_point
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MIN_X
add bx, PLAYER_MAX_Y
call .test_point
mov ax, [cursor_x]
mov bx, [cursor_y]
add ax, PLAYER_MAX_X
add bx, PLAYER_MAX_Y
call .test_point
jmp .end
.test_point:
call get_tile_at
cmp al, '@'
je .hazard
cmp al, 'W'
je .goal
ret
.hazard:
pop ax
jmp reset_level
.goal:
pop ax
jmp complete_level
.end:
wait_frame:
cmp byte [turbo], 0
jne mainloop
cmp byte [timer_tick.done], 0
jne mainloop
hlt
jmp wait_frame
complete_level:
call sound_off
mov word [timer_tick.level_timer], 70
call get_backbuffer
call clear_screen
mov ah, 9
mov dx, win_message
int 0x21
.wait:
hlt
cmp word [timer_tick.level_timer], 0
jne .wait
game_end:
call sound_off
call timer_deinit
call keyboard_deinit
call video_deinit
ret
draw_level:
pusha
call get_backbuffer
call clear_screen
mov si, level_data
mov dx, 12
.rows:
mov cx, 20
.tiles:
lodsb
xor ah, ah
mov di, ax
mov ax, 20
sub ax, cx
shl ax, 4
mov bx, 12
sub bx, dx
shl bx, 4
cmp di, 'x'
jne .not_wall
call draw_box
.not_wall:
cmp di, '@'
jne .not_hazard
push ax
mov ah, 5
call set_ink
pop ax
call draw_hazard
push ax
mov ah, 7
call set_ink
pop ax
.not_hazard:
cmp di, 'W'
jne .not_goal
push ax
mov ah, 3
call set_ink
pop ax
call draw_goal
push ax
mov ah, 7
call set_ink
pop ax
.not_goal:
loop .tiles
dec dx
test dx, dx
jnz .rows
popa
ret
; ax = X
; bx = Y
; dl = colour
draw_player:
pusha
mov si, ax
mov di, bx
sub di, 10
call draw_line
mov si, ax
mov di, bx
sub si, 5
add di, 8
call draw_line
mov si, ax
mov di, bx
add si, 5
add di, 8
call draw_line
popa
ret
; ax = X
; bx = Y
draw_box:
pusha
mov dl, 1
; (0, 0) -> (1, 0)
mov si, ax
mov di, bx
add si, 15
call draw_line
; (0, 0) -> (1, 1)
add di, 15
call draw_line
; (0, 0) -> (0, 1)
sub si, 15
call draw_line
; (0, 1) -> (1, 1)
add bx, 15
add si, 15
call draw_line
; (1, 0) -> (1, 1)
add ax, 15
sub bx, 15
call draw_line
; (1, 0) -> (0, 1)
sub si, 15
call draw_line
popa
ret
; ax = X
; bx = Y
draw_hazard:
pusha
mov dl, 1
; (0, 15) -> (3, 0)
mov si, ax
mov di, bx
add bx, 15
add si, 3
call draw_line
; (8, 15) -> (11, 0)
add ax, 8
add si, 8
call draw_line
; (12, 0) -> (15, 15)
xchg ax, si
xchg bx, di
inc ax
add si, 7
call draw_line
; (4, 0) -> (7, 15)
sub ax, 8
sub si, 8
call draw_line
popa
ret
; ax = X
; bx = Y
draw_goal:
pusha
; (1,1) -> (1,14)
mov dl, 1
inc ax
inc bx
mov si, ax
mov di, bx
add di, 13
call draw_line
; (1,14) -> (14, 14)
add bx, 13
add si, 13
call draw_line
; (14, 14) -> (14, 1)
add ax, 13
sub di, 13
call draw_line
; (14, 1) -> (11, 10)
sub bx, 13
sub si, 3
add di, 9
call draw_line
; (11,10) -> (8,1)
xchg ax, si
xchg bx, di
sub si, 6
call draw_line
; (7,1) -> (4, 10)
xchg ax, si
xchg bx, di
dec ax
sub si, 7
call draw_line
; (4,10) -> (1,1)
xchg ax, si
xchg bx, di
sub si, 6
call draw_line
popa
ret
; ax = X
; bx = Y
; tile -> al
; ??? -> ah
get_tile_at:
cmp ax, 0
jl .oob
cmp bx, 0
jl .oob
cmp ax, SCREEN_WIDTH
jge .oob
cmp bx, PLAYFIELD_HEIGHT
jge .oob
push bx
shr ax, 4
shr bx, 4
shl bx, 2
add ax, bx
shl bx, 2
add bx, ax
mov al, [level_data + bx]
pop bx
ret
.oob:
mov al, '.'
ret
%include "beepboop.asm"
%include "debugpr.asm"
%include "graphics.asm"
%include "keyboard.asm"
%include "timer.asm"
section data
level_data:
db 'xxx................x'
db 'x.x................x'
db 'x.x.............xxxx'
db 'x...............x..x'
db 'x......@........x...'
db 'xxxxx..........xx...'
db 'xxxxxx..........x..x'
db '...x............x..x'
db '...................x'
db '.......@...........x'
db '...............@xxxx'
db 'xxxxxxxxxxxx.@......'
level_objects:
dw .level1
.level1:
db 99
db 0xff
intro_message db 'T', 132, 'ytyyp', 132, ' menn', 132, ' nopeasti.$'
win_message db 'You are winner.$'
music_data:
db 6,4, 7,4, 6,4, 7,4, 6,4, 7,4, 0xff,12
db 6,4, 11,4, 0xff,2, 11,4, 7,4, 11,4, 0xff,2, 8,4, 0xff,20
db 8,4, 5,4, 6,4, 5,4, 0xff,16, 6,8, 5,8, 0xff,24, 6,4, 5,4, 6,4, 5,4, 3,8, 0xff,16
db 1,8, 3,8, 5,8, 0xff,20
.end:
music_index resw 1
music_counter resb 1
cursor_x resw 1
cursor_y resw 1
cursor_dx resw 1
cursor_dy resw 1
old_cursor_x resw 1
old_cursor_y resw 1
level_timer_max dw 150
level_timer_progress resw 1
need_actual_clear db 0
turbo resb 1