Trevor Merritt e29ac45c84 scroll down works on CHIP-8 and High-Res modes
scroll left and right work in stdef and hidef
adds octo test roms
adds schip fonts to memory
2024-10-27 11:41:25 -04:00

1017 lines
16 KiB
Plaintext

###########################################
#
# ChipWar
#
# War. War never changes.
# This game takes place on a toroidal field
# of 16 territories. Each has some number
# of troops stationed there (1-5).
# at the beginning of the game, territories
# are divided between you (white)
# and an AI opponent (black).
#
# You can order your territories to attack
# adjacent enemy territories provided you
# have more than one troop available.
# When you attack, a number of 8-sided dice
# will be rolled and summed based on the
# number of attackers and defenders.
# If the attackers win, they capture the
# territory and transfer all but one of
# their troops over.
# If the defenders win, they destroy all
# but one of the attackers and lose one troop,
# or none if they have only a single troop.
#
# After white has taken a turn,
# each territory has a 50% chance of
# producing one new troop.
# The game ends when black or white has
# conquered the entire map.
#
# When selecting a territory, ASWD move
# your cursor, E selects the territory
# and Q ends your turn.
# With a territory selected, ASWD choose
# the direction in which to attack,
# E confirms the attack and Q cancels.
# When the game is over press any key to
# play again.
#
# Based loosely on the Flash game DiceWars:
#
# http://www.gamedesign.jp/flash/dice/dice.html
#
###########################################
: whitedice
0xFE 0x82 0x82 0x92 0x82 0x82 0xFE 0x00 # 1
0xFE 0x82 0x8A 0x82 0xA2 0x82 0xFE 0x00 # 2
0xFE 0x82 0xAA 0x82 0x92 0x82 0xFE 0x00 # 3
0xFE 0x82 0xAA 0x82 0xAA 0x82 0xFE 0x00 # 4
0xFE 0x82 0xAA 0x92 0xAA 0x82 0xFE 0x00 # 5
: blackdice
0xFE 0xFE 0xFE 0xEE 0xFE 0xFE 0xFE 0x00 # 1
0xFE 0xFE 0xF6 0xFE 0xDE 0xFE 0xFE 0x00 # 2
0xFE 0xFE 0xD6 0xFE 0xEE 0xFE 0xFE 0x00 # 3
0xFE 0xFE 0xD6 0xFE 0xD6 0xFE 0xFE 0x00 # 4
0xFE 0xFE 0xD6 0xEE 0xD6 0xFE 0xFE 0x00 # 5
: arrows
0x10 0x38 0x7C 0xFE 0x38 0x38 0x38 0x00 # n
0x10 0x18 0xFC 0xFE 0xFC 0x18 0x10 0x00 # e
0x38 0x38 0x38 0xFE 0x7C 0x38 0x10 0x00 # s
0x10 0x30 0x7E 0xFE 0x7E 0x30 0x10 0x00 # w
: p1
0x00 0x78 0x44 0x44 0x78 0x40 0x40 0x00
0x10 0x30 0x10 0x10 0x7C 0x00
: p2
0xFE 0x86 0xBA 0xBA 0x86 0xBE 0xBE 0xFE
0xC6 0xBA 0xE6 0xDE 0x82 0xFE
: curs1 0xAA 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0xAA
: curs2 0x80 0x00 0x80 0x00 0x80 0x00 0x80 0x00 0x80
: empty 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
: fill 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
: plus 0x00 0x40 0xE0 0x40
# game over
: go1 0x7E 0xFE 0xC0 0xDE 0xC6 0xFE 0x7E 0x00 0x7C 0xFE 0xC6 0xC6 0xC6 0xFE 0x7C
: go2 0x7C 0xFE 0xC6 0xFE 0xC6 0xC6 0xC6 0x00 0xC6 0xC6 0xC6 0xC6 0xEE 0x7C 0x38
: go3 0xC6 0xEE 0xFE 0xD6 0xC6 0xC6 0xC6 0x00 0x7E 0xFE 0xC0 0xF8 0xC0 0xFE 0x7E
: go4 0x7E 0xFE 0xC0 0xF8 0xC0 0xFE 0x7E 0x00 0xFC 0xFE 0xC6 0xFE 0xFC 0xCE 0xC6
# you win
: yw1 0xC6 0xC6 0xEE 0x7C 0x38 0x38 0x38 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
: yw2 0x7C 0xFE 0xC6 0xC6 0xC6 0xFE 0x7C 0x00 0x63 0x63 0x63 0x6B 0x7F 0x77 0x63
: yw3 0xC6 0xC6 0xC6 0xC6 0xC6 0xFE 0x7C 0x00 0x7E 0x7E 0x18 0x18 0x18 0x7E 0x7E
: yw4 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xC6 0xE6 0xF6 0xFE 0xDE 0xCE 0xC6
# title/loading screen
: ti1 0xFE 0x82 0xAA 0x92 0xAA 0x82 0xFE 0x00 0x06 0x06 0x06 0x06 0x06 0x07 0x03
: ti2 0x00 0x00 0x75 0x47 0x45 0x75 0x00 0x00 0x19 0x1B 0xDB 0xDB 0xDB 0xFB 0x33
: ti3 0x00 0x00 0x5C 0x54 0x5C 0x50 0x00 0x00 0xE7 0xF7 0x36 0xF7 0xF7 0x36 0x36
: ti4 0xFE 0xFE 0xF6 0xFE 0xDE 0xFE 0xFE 0x00 0xC0 0xE0 0x60 0xC0 0xE0 0x60 0x60
: lo1 0x8E 0x8A 0x8A 0xEE
: lo2 0x4C 0xAA 0xEA 0xAC
: lo3 0xB3 0xAA 0xAA 0xAB
: lo4 0x80 0x00 0x80 0xAA
# n e s w
: delta-x 0 1 0 -1
: delta-y -1 0 1 0
###########################################
#
# Register Map:
#
###########################################
# vf is always temporary
:alias mode ve
:alias cursorx vd
:alias cursory vc
:alias dir vb
:alias wdice v9
:alias bdice v8
:alias wtotal v7
:alias btotal v6
:alias wroll v5
:alias broll v4
:alias rolls v3
# v0-v2 are temporary
###########################################
#
# Mutable Data
#
###########################################
# game modes (mode)
:const MOVE 0
:const ATTACK 1
:const AIMOVE 2
:const WIN 3
:const LOSE 4
:const RESET 5
# space owners (owns-at)
:const START 0
:const WHITE 1
:const BLACK 2
:const EMPTY 3
: bcd-buffer 0
: tens 0
: ones 0
: owns-at 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
: dice-at 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
###########################################
#
# Utility Subroutines
#
###########################################
: random-vector
# trashes v0-v2
# returns in v1
v1 := random 0xFF
v2 := v1
v0 := 0
loop
while v2 != 0
v2 <<= v2
v0 += vf
again
if v0 != 4 then jump random-vector
;
: vfwait
delay := vf
loop
vf := delay
if vf != 0 then
again
;
: longwait
vf := 60
jump vfwait
: wait
vf := 30
jump vfwait
: uwait
vf := 10
jump vfwait
: fillscreen
# trashes v0-v1
clear
i := fill
v0 := 0
loop
v1 := 0
sprite v0 v1 15
v1 := 15
sprite v0 v1 15
v1 := 30
sprite v0 v1 2
v0 += 8
if v0 != 64 then
again
;
: draw-end-screen
v0 := 16
v1 := 8
v2 := 15
loop
sprite v0 v1 15
i += v2
v0 += 8
if v0 != 48 then
again
v0 := key
mode := RESET
;
: draw-game-over
fillscreen
i := go1
jump draw-end-screen
: draw-you-win
clear
i := yw1
jump draw-end-screen
###########################################
#
# Battle
#
###########################################
: draw-wtotal
# trashes v0-v2
v2 := 23
v1 := 11
i := bcd-buffer
bcd wtotal
i := tens load v0 i := hex v0
sprite v1 v2 5
v1 += 5
i := ones load v0 i := hex v0
sprite v1 v2 5
;
: draw-btotal
# trashes v0-v2
v2 := 23
v1 := 43
i := bcd-buffer
bcd btotal
i := tens load v0 i := hex v0
sprite v1 v2 5
v1 += 5
i := ones load v0 i := hex v0
sprite v1 v2 5
;
: draw-wroll
# trashes v0-v2
v2 := 16
v1 := 14
i := hex wroll
sprite v1 v2 5
v1 += -4
i := plus
sprite v1 v2 4
;
: draw-broll
# trashes v0-v2
v2 := 16
v1 := 46
i := hex broll
sprite v1 v2 5
v1 += -4
i := plus
sprite v1 v2 4
;
: draw-battle
# trashes v0-v2
clear
i := fill
v0 := 32
v1 := 0
loop
v1 := 0
sprite v0 v1 15
v1 := 15
sprite v0 v1 15
v1 := 30
sprite v0 v1 2
v0 += 8
if v0 != 64 then
again
# dice counters:
v1 := 4
v0 := 12
i := whitedice
v2 := wdice
v2 <<= v2
v2 <<= v2
v2 <<= v2
v2 += -8
i += v2
sprite v0 v1 7
i := whitedice
v2 := bdice
v2 <<= v2
v2 <<= v2
v2 <<= v2
v2 += -8
i += v2
v0 := 45
sprite v0 v1 7
draw-wtotal
draw-btotal
;
: b-do-roll
broll := random 7
broll += 1
draw-broll
draw-btotal
btotal += broll
draw-btotal
;
: w-do-roll
wroll := random 7
wroll += 1
draw-wroll
draw-wtotal
wtotal += wroll
draw-wtotal
;
: defender-wins
# set attacker to 1
cursor-to-index
i := dice-at
i += vf
v0 := 1
save v0
# set defender to max(1, old-1)
direction-to-index
i := dice-at
i += vf
load v0
v0 += -1
if v0 == 0 then v0 := 1
i := dice-at
i += vf
save v0
;
: attacker-wins
# set dest to attackers - 1
cursor-to-index
i := dice-at
i += vf
load v0
va := v0
va += -1
direction-to-index
i := dice-at
i += vf
v0 := va
save v0
# set dest to be attacker owned
direction-to-index
i := owns-at
i += vf
if mode == ATTACK then v0 := WHITE
if mode != ATTACK then v0 := BLACK
save v0
# set attackers to 1
cursor-to-index
i := dice-at
i += vf
v0 := 1
save v0
;
: white-wins-attack
attacker-wins
# if there are no black zones,
# game over and white wins.
i := owns-at
v1 := 0
loop
load v0
if v0 == BLACK then return
v1 += 1
if v1 != 18 then
again
mode := WIN
;
: black-wins-attack
attacker-wins
# if there are no white zones,
# game over and black wins.
i := owns-at
v1 := 0
loop
load v0
if v0 == WHITE then return
v1 += 1
if v1 != 18 then
again
mode := LOSE
;
: white-wins
if mode == ATTACK then jump white-wins-attack
jump defender-wins
: black-wins
if mode != ATTACK then jump black-wins-attack
jump defender-wins
: battle
wtotal := 0
btotal := 0
rolls := 0
draw-battle
wait
loop
if bdice > rolls then b-do-roll
if wdice > rolls then w-do-roll
wait
if bdice > rolls then draw-broll
if wdice > rolls then draw-wroll
uwait
rolls += 1
# get max of dice count
v0 := bdice
if wdice > bdice then v0 := wdice
if rolls != v0 then
again
longwait
# note that this gives black a fundamental
# advantage; it always wins ties:
if wtotal > btotal then jump white-wins
jump black-wins
###########################################
#
# Map
#
###########################################
: map-tile
# trashes v0-v2.
# takes an index in vf
# initializes i to the appropriate
# sprite data to draw
v2 := vf
i := dice-at
i += v2
load v0
v0 += -1
v1 <<= v0
v1 <<= v1
v1 <<= v1
i := owns-at
i += v2
load v0
i := whitedice
if v0 == BLACK then i := blackdice
i += v1
if v0 == EMPTY then i := empty
;
: draw-map
# trashes v0-v5
v4 := 4 # y position
v5 := 0 # map array index
clear
loop
v3 := 8 # x position
loop
vf := v5 map-tile
sprite v3 v4 7
v5 += 1
v3 += 8
if v3 != 56 then
again
v4 += 8
if v4 != 28 then
again
;
: draw-p1
i := p1
v0 := 0
v1 := 9
sprite v0 v1 14
;
: draw-p2
i := p2
v0 := 56
v1 := 9
sprite v0 v1 14
;
###########################################
#
# Cursor
#
###########################################
: draw-cursor
# trash v0-v2
v0 <<= cursorx
v0 <<= v0
v0 <<= v0
v0 += 7
v1 <<= cursory
v1 <<= v1
v1 <<= v1
v1 += 3
v2 := v0
v2 += 8
i := curs1
sprite v0 v1 9
i := curs2
sprite v2 v1 9
;
: cursor-to-index
# leave result in vf
vf := cursorx
if cursory == 1 then vf += 6
if cursory == 2 then vf += 12
;
: direction-to-index
# trashes v0-v2
# leave the result in vf
v1 := cursorx
i := delta-x
i += dir
load v0
v1 += v0
if v1 == -1 then v1 := 5
if v1 == 6 then v1 := 0
v2 := cursory
i := delta-y
i += dir
load v0
v2 += v0
if v2 == -1 then v2 := 2
if v2 == 3 then v2 := 0
if v2 == 1 then v1 += 6
if v2 == 2 then v1 += 12
vf := v1
;
: cursor-to-xy
# leave result in v0/v1
v0 <<= cursorx
v0 <<= v0
v0 <<= v0
v0 += 8
v1 <<= cursory
v1 <<= v1
v1 <<= v1
v1 += 4
;
: erase-selected
# trash v0-v2
cursor-to-index
map-tile
cursor-to-xy
sprite v0 v1 7
;
: draw-arrow
i := arrows
v0 <<= dir
v0 <<= v0
v0 <<= v0
i += v0
cursor-to-xy
sprite v0 v1 7
;
: start-attack
dir := 0
# ignore spaces we don't control
cursor-to-index
i := owns-at
i += vf
load v0
if v0 != WHITE then return
# ignore spaces with 1 die
i := dice-at
i += vf
load v0
if v0 == 1 then return
# switch to attack selection mode
mode := ATTACK
draw-cursor
erase-selected
draw-arrow
;
: cancel-attack
draw-arrow
mode := MOVE
draw-cursor
erase-selected
;
: start-fight
direction-to-index
# if the adjacent tile isn't black, give up
i := owns-at
i += vf
load v0
if v0 != BLACK then return
# set up and fight
i := dice-at
i += v1
load v0
bdice := v0
i := dice-at
cursor-to-index
i += vf
load v0
wdice := v0
battle
if mode == WIN then return
draw-map
draw-p1
draw-cursor
mode := MOVE
;
: start-ai-turn
restock
draw-map
longwait
draw-p2
mode := AIMOVE
ai-move
if mode == LOSE then return
mode := MOVE
draw-p2
draw-p1
;
: move-cursor
va := key
draw-cursor
if va == 7 then cursorx += -1
if va == 9 then cursorx += 1
if va == 5 then cursory += -1
if va == 8 then cursory += 1
if va == 6 then start-attack
if va == 4 then start-ai-turn
if cursorx == 6 then cursorx := 0
if cursorx == -1 then cursorx := 5
if cursory == 3 then cursory := 0
if cursory == -1 then cursory := 2
draw-cursor
;
: attack-cursor
va := key
draw-cursor
draw-arrow
if va == 7 then dir := 3
if va == 9 then dir := 1
if va == 5 then dir := 0
if va == 8 then dir := 2
draw-arrow
draw-cursor
if va == 4 then cancel-attack
if va == 6 then start-fight
;
###########################################
#
# AI Opponent
#
###########################################
: ai-pickdir
direction-to-index
# must be white
i := owns-at
i += vf
load v0
if v0 != WHITE then return
# is this zone weaker?
i := dice-at
i += vf
load v0
if v5 < v0 then return
# our new choice
v4 := dir
v5 := v0
;
: ai-single
# pick a random territory
v2 := random 0b1111
v1 := 0
cursorx := 0
cursory := 0
i := owns-at
loop
while v2 != 0
load v0
if v0 != EMPTY then v2 += -1
v1 += 1
cursorx += 1
if cursorx == 6 then cursory += 1
if cursorx == 6 then cursorx := 0
again
# v1 now contains the (0-17) index of
# our chosen territory.
# if it's not black, ignore it
i := owns-at
i += v1
load v0
if v0 != BLACK then return
# if it has 1 die, ignore it
i := dice-at
i += v1
load v0
if v0 == 1 then return
bdice := v0
# attack the weakest adjacent white zone
v4 := -1 # best direction
v5 := 0xFF # best die count (lower is better)
dir := 0 ai-pickdir
dir := 1 ai-pickdir
dir := 2 ai-pickdir
dir := 3 ai-pickdir
if v4 == -1 then return
dir := v4
wdice := v5
# show arrow
draw-cursor
longwait
draw-cursor
erase-selected
draw-arrow
longwait
# FIRE ZE MISSILES
battle
draw-map
draw-p2
wait
;
# unroll these loops so that I don't
# need to keep track of a loop index:
: ai-moves
ai-single
ai-single
ai-single
ai-single
ai-single
;
: ai-move
ai-moves
ai-moves
ai-moves
ai-moves
;
###########################################
#
# Restocking
#
###########################################
: restock-single
# take index in va
i := owns-at
i += va
load v0
if v0 == EMPTY then return
vb += 1
i := dice-at
i += va
load v0
v1 <<= v1
v0 += vf
if v0 == 6 then v0 := 5
i := dice-at
i += va
save v0
;
: restock
va := 0 # cell index
vb := 0 # bit index
random-vector
loop
restock-single
va += 1
if vb != 8 then
again
random-vector
loop
restock-single
va += 1
if vb != 16 then
again
;
###########################################
#
# Map Generation
#
###########################################
: fill-boards
# expects i to be initialized
# takes the fill value in v0
v1 := 0
loop
save v0
v1 += 1
if v1 != 18 then
again
;
: reset-owned
i := owns-at
v0 := START
jump fill-boards
: reset-dice
i := dice-at
v0 := 1
jump fill-boards
: place-empty
# trashes v0-v2
# pick an index 0-17
v2 := random 0b11111
if v2 > 17 then jump place-empty
# make sure that spot is uninitialized
i := owns-at
i += v2
load v0
if v0 != START then jump place-empty
# set it to be empty
i := owns-at
i += v2
v0 := EMPTY
save v0
;
: place-owned-single
# take index in va
i := owns-at
i += va
load v0
if v0 == EMPTY then return
v1 <<= v1
vb += 1
v0 := WHITE
if vf == 1 then v0 := BLACK
i := owns-at
i += va
save v0
;
: place-owned
va := 0 # cell index
vb := 0 # bit index
random-vector
loop
place-owned-single
va += 1
if vb != 8 then
again
random-vector
loop
place-owned-single
va += 1
if vb != 16 then
again
;
: random-map
reset-owned
reset-dice
place-empty
place-empty
place-owned
restock
;
###########################################
#
# Main
#
###########################################
: title-screen
v0 := 16
v1 := 4
v2 := 0
v3 := 15
i := ti1
loop
sprite v0 v1 15
v0 += 8
v2 += 1
i += v3
if v2 != 4 then
again
v0 := 16
v1 := 27
v2 := 0
v3 := 4
loop
sprite v0 v1 4
v0 += 8
v2 += 1
i += v3
if v2 != 4 then
again
;
: init-game
random-map
draw-map
draw-p1
draw-cursor
mode := MOVE
;
: main
title-screen
init-game
loop
if mode == MOVE then move-cursor
if mode == ATTACK then attack-cursor
if mode == WIN then draw-you-win
if mode == LOSE then draw-game-over
if mode == RESET then init-game
again