1 votes

Snake

A snake clone for the DCPU. Targeted at the DCPU-16 emulator, since I/O specs haven't been made official yet.

Download .dasm16 file |
;;;;;;;;;;;;;;;;;;;;;;
; Soron's Snake - v2 ;
;;;;;;;;;;;;;;;;;;;;;;

; coded by Soron of http://0x10cforum.com/, for the DCPU
; hereby released into the public domain
; (or use the Unlicense, CC0, etc., if your country doesn't have public domain)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Now conforms to the ABI! No longer clobbers your registers! ;
; Just be sure to "SET PC, exit_snake" when you want to exit  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; targetted for the DCPU-16 Studio assembler/emulator
; may or may not work for other emulators, since I/O hasn't been made official

; the snake is drawn on the background, and the food on the foreground

; suggested tweaks:
; adjust sleep_duration to speed up/slow down the game
; adjust the upper nybble of food_char to change food color
; adjust the lower byte of food_char to change food shape
; adjust prng_dat to start with a different RNG seed
; if you're not using a 32x16 window, adjust assorted things to not break
; (things such as dat_width and dat_height, up_dir and down_dir, etc.)

; this could also probably be made more efficient, but, uh... not a priority,
; given that we're looping 0x1000 times just to slow things down!

; directions:
; 0x0001 = right
; 0x0020 = down (assuming a 32 char-width screen)
; 0xFFFF = left
; 0xFFE0 = up
; up/down WILL need to be changed if you use a different-width screen

; how registers, etc., are used:
; A = head position
; B = direction
; C = food position
; X = position of thing to draw on screen, etc
; Y = position of last segment touched 
; Z = temporary data storage, for assorted calculations
; I = for loops and other iterations
; J = address of the stack element which stores the pos of start of tail
; SP = address of the stack element which stores the pos of end of tail
; O = not used. Why would you use this for Snake? What sort of madman ARE you?

:snake_init
	;conform to the ABI by not clobbering ALL the registers
	SET PUSH, X
	SET PUSH, Y
	SET PUSH, Z
	SET PUSH, I
	SET PUSH, J
	SET J, SP ; keep track of where OUR stack starts
	JSR clear_screen
	SET A, 0x0001 ; head position (add 0x8000 to get screen pos)
	SET B, 0x0001 ; direction
	JSR gen_food
	SET PUSH, 0x0000 ; start of tail position
	BOR [0x8000], [tail_color]
	BOR [0x8001], [head_color]

:game_loop
	JSR sleep
	
	IFE [0x9000], [up_key]
		SET PC, turn_up
	IFE [0x9000], [down_key]
		SET PC, turn_down
	IFE [0x9000], [left_key]
		SET PC, turn_left
	IFE [0x9000], [right_key]
		SET PC, turn_right

:move_snake
	SET [0x9000], 0
	SET Y, A
	ADD A, B ; yay overflow ^_^!
	SET X, A

:check_collision
	SET Z, [dat_width]
	MUL Z, [dat_height]
	IFG X, Z ; went off the screen somehow
		SET PC, lose_game
	
	SET Z, X
	ADD Z, 0x8000
	IFE [Z], [tail_color] ; hit the tail!
		SET PC, lose_game
	
	IFE B, [dir_left]
		SET PC, check_edge_collision
	IFE B, [dir_right]
		SET PC, check_edge_collision
	SET PC, draw_snake
	
:check_edge_collision
	;change this next block if you changed screen width
	SET X, A
	AND X, 0xFFE0
	SET Z, Y
	AND Z, 0xFFE0
	IFN X, Z
		SET PC, lose_game ; we have gone off the left/right edge!
	SET X, A
		
	 
:draw_snake
	ADD X, 0x8000
	BOR [X], [head_color]
	
	SET I, J
:tail_loop
	SUB I, 1
	IFG SP, I
		SET PC, finish_tail
	SET Z, [I]
	SET [I], Y
	SET Y, Z
	
	SET X, [I]
	ADD X, 0x8000
	BOR [X], [tail_color]
	SET PC, tail_loop

:turn_left
	IFN B, [dir_right]
		SET B, [dir_left]
	SET PC, move_snake

:turn_right
	IFN B, [dir_left]
		SET B, [dir_right]
	SET PC, move_snake

:turn_up
	IFN B, [dir_down]
		SET B, [dir_up]
	SET PC, move_snake

:turn_down
	IFN B, [dir_up]
		SET B, [dir_down]
	SET PC, move_snake


:finish_tail
	IFE A, C
		SET PC, grow_tail
	SET X, Y
	ADD X, 0x8000
	AND [X], 0xF0FF
	SET PC, game_loop

:grow_tail
	SET PUSH, Y
	SET X, C
	ADD X, 0x8000
	AND [X], 0x0F00 ; make sure to clear the old food item!
	JSR gen_food
	SET PC, game_loop

:gen_food
	JSR rand
	SET C, [prng_dat]
	SET Z, [dat_width]
	MUL Z, [dat_height]
	MOD C, Z
	SET X, C
	ADD X, 0x8000
	BOR [X], [food_char]
	SET PC, POP
	

:lose_game
	SET PC, snake_init

:exit_snake
	SET SP, J
	SET J, POP
	SET I, POP
	SET Z, POP
	SET Y, POP
	SET X, POP
	SET PC, POP

:sleep
	SET I, 0
:sleep_loop
	ADD I, 1
	IFG I, [sleep_duration]
		SET PC, POP
	SET PC, sleep_loop

:sleep_duration
	DAT 0x1000


:clear_screen
	SET A, SP
	SET SP, 0x8000
:clear_screen_loop
	SET POP, 0
	IFG SP, 0x8200
		SET PC, clear_screen_exit
	SET PC, clear_screen_loop
:clear_screen_exit
	SET SP, A
	SET PC, POP

:rand
	;introduce at least a LITTLE unpredictability
	MUL [prng_dat], A
	ADD [prng_dat], SP
	;now do the actual work
	MUL [prng_dat], 31421
	ADD [prng_dat], 6927
	SET PC, POP

:prng_dat
	DAT 0x13AD ; a reasonable start value

;if you change width, you WILL need to double-check edge-of-screen collision
:dat_width
	DAT 32
:dat_height
	DAT 16

:head_color
	DAT 0x0700
:tail_color
	DAT 0x0F00
:food_char
	DAT 0xC040 ; "@" char, for all y'all roguelike fans :)

:dir_right
	DAT 0x0001
:dir_down
	DAT 0x0020 ; relies on screen width
:dir_left
	DAT 0xFFFF
:dir_up
	DAT 0xFFE0 ; relies on screen width

:up_key
	DAT 0x0003
:down_key
	DAT 0x0004
:left_key
	DAT 0x0001
:right_key
	DAT 0x0002

Comments

Sign in to comment and vote

No comments yet