###########################################
#
#  Outlaw
#
#  An adaptation of the Atari 2600 game
#  "Outlaw" for the Chip8.
#
#  Move with ASWD and fire with E.
#  Holding a direction while firing will
#  fire an angled shot, which ricochets.
#  Plays fairly well at 30 cycles/frame
#
###########################################

: cactus 0x38 0x38 0x3B 0x1B 0x1B 0x1B 0xDF 0xDE 0xD8 0xD8 0xF8 0x78 0x18 0x1C 0x0C 
: left   0x00 0x00 0x70 0xF8 0x70 0x67 0x7C 0x60 0x60 0x78 0x28 0xEC
: lwalk1 0x18 0x3E 0x1C 0x18 0x7E 0x99 0x99 0x99 0x5A 0x3C 0x66 0xC3
: lwalk2 0x18 0x3E 0x1C 0x18 0x7E 0x99 0x99 0x99 0x5A 0x3C 0x24 0x36
: right  0x00 0x00 0x06 0x1F 0x0E 0xE6 0x3E 0x06 0x06 0x1E 0x14 0x37 
: rwalk1 0x18 0x7C 0x38 0x18 0x7E 0x99 0x99 0x99 0x5A 0x3C 0x66 0xC3
: rwalk2 0x18 0x7C 0x38 0x18 0x7E 0x99 0x99 0x99 0x5A 0x3C 0x24 0x6C
: edge   0xFF 0xFF
: bullet 0x80

###########################################
#
#  Register map
#
###########################################

:alias leftx      ve
:alias lefty      vd
:alias leftframe  vc
:alias leftbx     vb
:alias leftby     va
:alias leftfire   v9

:alias rightx     v8
:alias righty     v7
:alias rightframe v6
:alias rightbx    v5
:alias rightby    v4
:alias rightfire  v3

:const FIRE_ST 1
:const FIRE_UP 2
:const FIRE_DN 3

# v0-v2 and vf are left as temporaries

###########################################
#
#  Bullets
#
###########################################

: fire-left-bullet
	v0 := 6
	if v0 -key then return
	leftfire := FIRE_ST
	v0 := 5
	if v0 key then leftfire := FIRE_UP
	v0 := 8
	if v0 key then leftfire := FIRE_DN
	
	# spawn bullet
	leftbx := leftx
	leftbx += 9
	leftby := lefty
	leftby += 5

	# draw initial bullet frame
	i := bullet
	sprite leftbx leftby 1
;

: move-left-bullet
	sprite leftbx leftby 1
	leftbx += 1
	if leftfire == FIRE_UP then leftby += -1
	if leftfire == FIRE_DN then leftby +=  1

	# bounce off top and bottom edge
	if leftby ==  1 then leftfire := FIRE_DN
	if leftby == 30 then leftfire := FIRE_UP

	# despawn on right edge
	if leftbx   == 63 then leftfire := 0
	if leftfire == 0  then return
	sprite leftbx leftby 1

	# collide with obstacles
	if vf == 0 then return
	leftfire := 0
;

: fire-right-bullet
	if rightfire != 0 then return
	rightfire := FIRE_ST
	v0 := random 0b11
	if v0 == 1 then rightfire := FIRE_UP
	if v0 == 2 then rightfire := FIRE_DN
	
	# spawn bullet
	rightbx := rightx
	rightbx += -1
	rightby := righty
	rightby += 5

	# draw initial bullet frame
	i := bullet
	sprite rightbx rightby 1
;

: move-right-bullet
	sprite rightbx rightby 1
	rightbx += -1
	if rightfire == FIRE_UP then rightby += -1
	if rightfire == FIRE_DN then rightby +=  1

	# bounce off top and bottom edge
	if rightby ==  1 then rightfire := FIRE_DN
	if rightby == 30 then rightfire := FIRE_UP

	# despawn on right edge
	if rightbx   == 0 then rightfire := 0
	if rightfire == 0 then return
	sprite rightbx rightby 1

	# collide with obstacles
	if vf == 0 then return
	rightfire := 0
;

###########################################
#
#  Gunslingers
#
###########################################

: move-left-player
	v1 := leftx
	v2 := lefty

	# process movement keys
	v0 := 7
	if v0 key then v1 += -1
	v0 := 9
	if v0 key then v1 +=  1
	v0 := 5
	if v0 key then v2 += -1
	v0 := 8
	if v0 key then v2 +=  1

	# animate player movement
	v0 := 0
	if v1 != leftx then v0 := 24
	if v2 != lefty then v0 := 24
	if leftframe == 24 then v0 := 12
	vf := 6
	if vf key then v0 := 0

	# clamp position within left side
	if v1 ==  0 then v1 :=  1
	if v1 == 21 then v1 := 20
	if v2 ==  0 then v2 :=  1
	if v2 == 18 then v2 := 17

	# update position
	i := left
	i += leftframe
	sprite leftx lefty 12
	leftx     := v1
	lefty     := v2
	leftframe := v0
	i := left
	i += leftframe
	sprite leftx lefty 12
;

: brain-table
	v1 += -1          return
	v1 +=  1          return
	v2 += -1          return # vertical movement is 2x as likely
	v2 += -1          return # as horizontal movement
	v2 +=  1          return
	v2 +=  1          return
	v0 := v0          return # do nothing
	fire-right-bullet return
: do-brain
	v0 := random 0b11100 # entries are 4 bytes each
	jump0 brain-table

: move-right-player
	v1 := rightx
	v2 := righty

	# process (random) movement
	do-brain

	# animate movement
	v0 := 0
	if v1 != rightx then v0 := 24
	if v2 != righty then v0 := 24
	if rightframe == 24 then v0 := 12

	# clamp position within right side
	if v1 == 35 then v1 := 36
	if v1 == 56 then v1 := 55
	if v2 ==  0 then v2 :=  1
	if v2 == 18 then v2 := 17

	# update position
	i := right
	i += rightframe
	sprite rightx righty 12
	rightx     := v1
	righty     := v2
	rightframe := v0
	i := right
	i += rightframe
	sprite rightx righty 12
;

###########################################
#
#  Main
#
###########################################

: rightdead
	sprite rightx righty 12
	i := bullet
	sprite leftbx leftby 1

: gameover
	v0 := 32
	buzzer := v0
	delay  := v0
	loop
		v0 := delay
		if v0 != 0 then
	again
	jump main

: leftdead
	sprite leftx lefty 12
	i := bullet
	sprite rightbx rightby 1
	jump gameover

: main
	# initialize state
	leftx      :=  5
	lefty      := 10
	leftframe  :=  0
	rightx     := 51
	righty     := 10
	rightframe :=  0
	leftfire   :=  0
	rightfire  :=  0

	# draw background
	clear
	i  := cactus
	v0 := 28
	v1 := 9
	sprite v0 v1 15

	i  := edge
	v0 := 0
	v1 := 31
	loop
		sprite v0 v1 2
		v0 += 8
		if v0 != 64 then
	again

	i := left
	sprite leftx lefty 12
	i := right
	sprite rightx righty 12

	# main game loop
	loop
		move-left-player
		if vf != 0 then jump leftdead
		move-right-player
		if vf != 0 then jump rightdead

		i := bullet
		if leftfire  != 0 then move-left-bullet
		if leftfire  == 0 then fire-left-bullet
		if rightfire != 0 then move-right-bullet
	again
