675 lines
No EOL
9.9 KiB
NASM
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 |