Skip to content

Instantly share code, notes, and snippets.

@Measter
Last active December 26, 2015 12:18
Show Gist options
  • Save Measter/7149728 to your computer and use it in GitHub Desktop.
Save Measter/7149728 to your computer and use it in GitHub Desktop.
CoreRL written on the DCPU-16.Requires the library at https://github.com/Measter/lib
; -----------------------
; Title: Core RL
; Author: Measter
; Date: 2013/10/25
;
; Based on Core: A Minimal Roguelike.
; http://http://roguelikeeducation.org/1.html
; -----------------------
; Revisions
; 1 - Map generation.
; 2 - Added game logic.
; 3 - Fixes stack not being restored on exit of
; handle_player and handle_evil.
; 4 - Fixed fencpost errors in wall and floor generation.
; 5 - Changed calls to int_dec_conv to int_text_conv.
; 6 - Appended _func to all library calls.
; 7 - Fixed bug in keyboard input.
set pc, start
.include <memory/alloc.asm>
.include <find_device.asm>
.include <random.asm>
.include <init_lem.asm>
.include <int_text_conv.asm>
; A is string address.
:print_message
jsr clear_screen
set i, [lem_buffer]
:.loop_start
set [i], 0xF
shl [i], 12
bor [i], [a]
add a, 1
add i, 1
ifn [a], 0
set pc, .loop_start
set pc, end
:print_death_message
set push, dead_message
add [sp], 14
set push, [level]
set push, 10
jsr int_text_conv_func
add sp, 2
set a, dead_message
set pc, print_message
:print_quit_message
set push, quit_message
add [sp], 13
set push, [level]
set push, 10
jsr int_text_conv_func
add sp, 2
set a, quit_message
set pc, print_message
; After exit, B will be one of the following:
; 0 : Do nothing.
; 1 : Arrow press.
:int_handler
; Get pressed key.
set a, 1
hwi [keyboard_port]
; Arrow keys
ifg c, 0x79
ifl c, 0x84
set pc, .handle_arrows
ife c, 0x71
set pc, .handle_q
set b, 0
set pc, .exit
:.handle_q
set pc, print_quit_message
:.handle_arrows
ife c, 0x80 ; Up Arrow
sub [next_row], 1
ife c, 0x81 ; Down Arrow
add [next_row], 1
ife c, 0x82 ; Left Arrow
sub [next_col], 1
ife c, 0x83 ; Right Arrow
add [next_col], 1
set b, 1
set pc, .exit
:.exit
rfi 0
; Input
; SP+4 : R0
; SP+3 : C0
; SP+2 : R1
; SP+1 : C1
; SP+0 : Character
:fill
set push, z
set z, sp
add z, 2
set push, i
set push, j
set push, a
set i, [z+4]
:.outer_loop
ife i, [z+2]
set pc, .exit_outer
set j, [z+3]
:.inner_loop
ife j, [z+1]
set pc, .exit_inner
set a, [map_width]
mul a, i
add a, j
add a, [map_buffer]
set [a], [z+0]
add j, 1
set pc, .inner_loop
:.exit_inner
add i, 1
set pc, .outer_loop
:.exit_outer
set a, pop
set j, pop
set i, pop
set z, pop
set pc, pop
; Input
; SP+5 : R0
; SP+4 : C0
; SP+3 : R1
; SP+2 : C1
; SP+1 : G0
; SP+0 : G1
:swap
set push, z
set z, sp
add z, 2
set push, a
set push, b
set push, i
; A = row
; B = col
:.swap_loop_start
; Set row.
set i, [z+3]
sub i, [z+5]
jsr rand_func
set a, [rand_seed]
mod a, i
add a, [z+5]
; Set column.
set i, [z+2]
sub i, [z+4]
jsr rand_func
set b, [rand_seed]
mod b, i
add b, [z+4]
; Get tile.
set i, [map_width]
mul i, a
add i, b
add i, [map_buffer]
ifn [i], [z+1]
set pc, .swap_loop_start
set [i], [z+0]
set i, pop
set b, pop
set a, pop
set z, pop
set pc, pop
:new_level
set push, z
set z, sp
add z, 2
set push, a
set push, b
set push, i
; Outer wall.
set push, 0
set push, 0
set push, [map_height]
set push, [map_width]
set push, [k_wall]
jsr fill
add sp, 5
; Floor
set push, 1
set push, 1
set push, [map_height]
sub [sp], 1
set push, [map_width]
sub [sp], 1
set push, [k_floor]
jsr fill
add sp, 5
; Row
set i, [map_height]
sub i, 5
jsr rand_func
set a, [rand_seed]
mod a, i
add a, 2
; Col
set i, [map_width]
sub i, 6
jsr rand_func
set b, [rand_seed]
mod b, i
add b, 2
; Horizontal walls.
set push, a
set push, 1
set push, a
add [sp], 1
set push, [map_width]
sub [sp], 1
set push, [k_wall]
jsr fill
add sp, 5
; Horizontal doors
set push, a
set push, 1
set push, a
add [sp], 1
set push, b
set push, [k_wall]
set push, [k_floor]
jsr swap
add sp, 6
set push, a
set push, b
add [sp], 1
set push, a
add [sp], 1
set push, [map_width]
sub [sp], 1
set push, [k_wall]
set push, [k_floor]
jsr swap
add sp, 6
; Vertical walls.
set push, 1
set push, b
set push, [map_height]
sub [sp], 1
set push, b
add [sp], 1
set push, [k_wall]
jsr fill
add sp, 5
; Vertical doors
set push, 1
set push, b
set push, a
set push, b
add [sp], 1
set push, [k_wall]
set push, [k_floor]
jsr swap
add sp, 6
set push, a
add [sp], 1
set push, b
set push, [map_height]
sub [sp], 1
set push, b
add [sp], 1
set push, [k_wall]
set push, [k_floor]
jsr swap
add sp, 6
; Stairs
set push, 1
set push, 1
set push, [map_height]
sub [sp], 1
set push, [map_width]
sub [sp], 1
set push, [k_floor]
set push, [k_stairs]
jsr swap
add sp, 6
add [level], 1
set i, 0
:.actor_reset_start
set a, [map_actor_row]
add a, i
set [a], -1
add i, 1
ifl i, [map_max_actors]
set pc, .actor_reset_start
jsr place
set i, 0
set b, [level]
ifl 10, b
set b, 10
:.evil_loop_start
jsr place
add i, 1
ifl i, b
set pc, .evil_loop_start
set i, pop
set b, pop
set a, pop
set z, pop
set pc, pop
; Input
; SP+1 : Row
; SP+0 : Col
:new_actor
set push, z
set z, sp
add z, 2
set push, i
set push, j
; Search for empty entry.
set i, 0
:.loop_start
ife i, [map_max_actors]
set pc, .loop_end
set j, [map_actor_row]
add j, i
ife [j], -1
set pc, .loop_end
add i, 1
set pc, .loop_start
:.loop_end
ife i, [map_max_actors]
set pc, .exit
; Found empty entry.
; Set row.
set [j], [z+1]
; Set column.
set j, [map_actor_col]
add j, i
set [j], [z+0]
; Set tile.
set j, [z+1]
mul j, [map_width]
add j, [z+0]
add j, [map_buffer]
ife i, 0
set [j], [k_player]
ifn i, 0
set [j], [k_evil]
:.exit
set j, pop
set i, pop
set z, pop
set pc, pop
:place
set push, i
set push, a
set push, b
:.place_loop_start
; Row
set i, [map_height]
sub i, 1
jsr rand_func
set a, [rand_seed]
mod a, i
add a, 1
; Column
set i, [map_width]
sub i, 2
jsr rand_func
set b, [rand_seed]
mod b, i
add b, 2
; Tile address
set i, [map_width]
mul i, a
add i, b
add i, [map_buffer]
ifn [i], [k_floor]
set pc, .place_loop_start
set push, a
set push, b
jsr new_actor
add sp, 2
set b, pop
set a, pop
set i, pop
set pc, pop
; X = Actor ID.
:at_pos
set push, a
set push, b
set push, i
set x, 0
:.actor_loop_start
set a, [map_actor_row]
add a, x
ifn [a], [next_row]
set pc, .next
set a, [map_actor_col]
add a, x
ifn [a], [next_col]
set pc, .next
; Actor found.
set pc, .exit_loop
:.next
add x, 1
ifl x, [map_max_actors]
set pc, .actor_loop_start
; No actor at coordinates.
set x, 0xFFFF
:.exit_loop
set i, pop
set b, pop
set a, pop
set pc, pop
:clear_screen
set push, z
set z, sp
add z, 2
set push, a
set push, i
set i, 0
:.clear_loop_start
set a, [lem_buffer]
add a, i
set [a], 0x0000
add i, 1
ifl i, 0x180
set pc, .clear_loop_start
set i, pop
set a, pop
set z, pop
set pc, pop
:draw_map
set push, z
set z, sp
add z, 2
set push, a
set push, b
set push, i
set push, j
; A, B = Read buffer.
; X, Y = Destination buffer.
; I = Destination character.
; J = Source character.
set a, 0
:.outer_loop
ife a, [map_height]
set pc, .exit_outer
set b, 0
:.inner_loop
ife b, [map_width]
set pc, .exit_inner
set j, [map_width]
mul j, a ; Row
add j, b ; Plus column
add j, [map_buffer]
set i, 32
mul i, a ; Row
add i, b ; Plus column
add i, [lem_buffer]
set [i], [j]
add b, 1
set pc, .inner_loop
:.exit_inner
add a, 1
set pc, .outer_loop
:.exit_outer
set j, pop
set i, pop
set b, pop
set a, pop
set z, pop
set pc, pop
:main_loop
set i, 0
:main_actor_loop
ife i, [map_max_actors]
set pc, .actor_loop_end
set x, [map_actor_row]
add x, i
set [next_row], [x]
set x, [map_actor_col]
add x, i
set [next_col], [x]
ife i, 0
jsr handle_player
ifg i, 0
jsr handle_evil
; Move actor.
set a, [next_row]
mul a, [map_width]
add a, [next_col]
add a, [map_buffer]
; A = Next tile address.
ifn [a], [k_floor]
set pc, .continue
set y, [map_actor_row]
add y, i
set z, [y]
; Z = Actor current row.
mul z, [map_width]
set y, [map_actor_col]
add y, i
add z, [y]
add z, [map_buffer]
; Z = Actor current tile.
; Move actor.
set [a], [z]
set [z], [k_floor]
set [y], [next_col] ; Set column.
set y, [map_actor_row]
add y, i
set [y], [next_row] ; Set row.
:.continue
add i, 1
set pc, main_actor_loop
:.actor_loop_end
set pc, main_loop
:handle_player
jsr draw_map
; Clear keyboard buffer.
set a, 0
hwi [keyboard_port]
; Turn on interrupt queueing for input.
ias int_handler
set b, 0
:.input_wait_loop
ifn b, 1
set pc, .input_wait_loop
; Ignore all input.
ias 0
; Has pressed arrow key.
set a, [next_row]
mul a, [map_width]
add a, [next_col]
add a, [map_buffer]
ife [a], [k_player]
set pc, .self_or_wall
ife [a], [k_wall]
set pc, .self_or_wall
ife [a], [k_stairs]
set pc, .stairs
ife [a], [k_evil]
set pc, .evil
set pc, .exit
:.self_or_wall
sub i, 1
set pc, .continue
:.stairs
jsr new_level
set pc, .break
:.evil
jsr at_pos
; X = Actor ID.
ife x, 0xFFFF
set pc, .exit
; Kill enemy.
set [a], [k_floor] ; Set tile.
set a, [map_actor_row]
add a, x
set [a], 0xFFFF ; Kill enemy.
set pc, .continue
:.exit
set pc, pop
:.continue
add i, 1
add sp, 1 ; Handle stack.
set pc, main_actor_loop
:.break
add sp, 1 ; Handle stack.
set pc, main_loop
:handle_evil
ife [next_row], 0xFFFF
set pc, .continue
; Vertical check.
set x, [map_actor_row] ; Player.
set x, [x]
sub x, [next_row]
ife ex, 0xFFFF ; Underflow.
set x, 0xFFFF
ife ex, 0 ; No underflow, with remainder.
ifg x, 0
set x, 1
; X = Target row.
set a, [next_row]
add a, x
mul a, [map_width]
add a, [next_col]
add a, [map_buffer]
; A = Next row tile.
ife [a], [k_player]
set pc, .move_ver
ifn x, 0
ife [a], [k_floor]
set pc, .move_ver
; Horizontal check.
set x, [map_actor_col] ; Player.
set x, [x]
sub x, [next_col]
ife ex, 0xFFFF ; Underflow.
set x, 0xFFFF
ife ex, 0 ; No underflow, with remainder.
ifg x, 0
set x, 1
; X = Target row.
set a, [next_row]
mul a, [map_width]
add a, [next_col]
add a, x
add a, [map_buffer]
; A = Next column tile.
ife [a], [k_player]
set pc, .move_hor
ifn x, 0
ife [a], [k_floor]
set pc, .move_hor
set pc, .check_kill
:.move_hor
add [next_col], x
set pc, .check_kill
:.move_ver
add [next_row], x
:.check_kill
set a, [next_row]
mul a, [map_width]
add a, [next_col]
add a, [map_buffer]
ife [a], [k_player]
set pc, print_death_message
:.exit
set pc, pop
:.continue
add i, 1
add sp, 1 ; Handle stack.
set pc, main_actor_loop
:.break
add sp, 1 ; Handle stack.
set pc, main_loop
; After exit, J will be one of the following:
; 0 : Do nothing.
; 2 : Enter key or 5 digits.
:seed_int_handler
; Get pressed key.
set a, 1
hwi [keyboard_port]
ifg c, 0x29 ; Digit 0 less 1
ifl c, 0x41 ; Digit 9 plus 1
set pc, .digit
ife c, 0x11 ; Enter
set pc, .enter
set pc, .exit
:.digit
set [i], 0xF000
bor [i], c
add i, 1
mul [rand_seed], 10
sub c, 0x30
add [rand_seed], c
set pc, .exit
:.enter
set j, 2
:.exit
rfi 0
:get_seed
set push, i
set push, j
set push, a
set push, c
set i, [lem_buffer]
set j, enter_seed_message
:.print_loop_start
set [i], 0xF000
bor [i], [j]
add i, 1
add j, 1
ifn [j], 0
set pc, .print_loop_start
ias seed_int_handler
set j, 0
:.input_wait_loop
ifn j, 2
set pc, .input_wait_loop
ias 0
set c, pop
set a, pop
set j, pop
set i, pop
set pc, pop
:start
set [mem_start], heap_start
; Find LEM.
set push, 0x7349
set push, 0xF615
jsr find_device_func
set [lem_port], pop
add sp, 1
ife [lem_port], 0xFFFF
set pc, end
; Display buffer.
set push, 384
jsr mem_alloc_func
set [lem_buffer], pop
ife [lem_buffer], 0xFFFF
set pc, end
set push, 0x0
set push, 0x0
set push, [lem_buffer]
set push, [lem_port]
jsr init_lem_func
add sp, 4
; Find keyboard.
set push, 0x30CF
set push, 0x7406
jsr find_device_func
set [keyboard_port], pop
add sp, 1
ife [keyboard_port], 0xFFFF
set pc, keyboard_error
; Speficy keyboard interrupt message.
set a, 3
set b, 1
hwi [keyboard_port]
set [rand_seed], 0
jsr get_seed
; Map buffer.
set a, [map_width]
mul a, [map_height]
set push, a
jsr mem_alloc_func
set [map_buffer], pop
; Actor arrays.
set push, [map_max_actors]
jsr mem_alloc_func
set [map_actor_row], pop
set push, [map_max_actors]
jsr mem_alloc_func
set [map_actor_col], pop
jsr new_level
set pc, main_loop
:end
set pc, end
:keyboard_error
set a, keyboard_error_string
set pc, print_message
:lem_port
dat 0
:lem_buffer
dat 0
:keyboard_port
dat 0
:map_width
dat 21
:map_height
dat 12
:map_max_actors
dat 16
:map_buffer
dat 0
:map_actor_row
dat 0
:map_actor_col
dat 0
:level
dat 0
:k_floor
dat 0xF02E
:k_wall
dat 0xF023
:k_stairs
dat 0xF03C
:k_player
dat 0xF040
:k_evil
dat 0xF045
:next_row
dat 0
:next_col
dat 0
:keyboard_error_string
.asciiz "No keyboard detected."
:quit_message
.asciiz "Quit on level "
.pad 18, 0
:dead_message
.asciiz "Died on level "
.pad 18, 0
:enter_seed_message
.asciiz "Enter seed: "
:heap_start
dat 0
@Zardoz89
Copy link

Could do you check why hangs in dcpu-vm ??

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment