This is the source code for the game so you can make a mod of it or something with tptasm.
The mnemonics probably don't make sense if you're reading this before I post the docs for the processor.
_Model "I8M7D28S"
%include "common"
start:
init:
ld holdPointerVar ;point to end of graphical memory
stsp ;put it in sp
ld alwaysFull | stl
initScreenDataLoop:
pop | out 1
and | jz exitInit ;stop once encountering zero
ld monitorCharDataPointer | dec | out 1 ;decrement pointer
st monitorCharDataPointer | jp initScreenDataLoop
exitInit:
main:
ld zero
addi retHere0
st returnAddress | jp randGenShip ;call randGenShip after storing this return address
retHere0:
ld incMonthsBit | out 2 ;increment months
ld four | dec | stl ;ld 3 into L
ld part3Health
and | jz mainLoop ;can't heal if tank is busted
ld part1Health | inc
and | jz mainLoop ;cockpit is already full health
ld part3 | and ;get level of the tank
inc
sta | rng ;store level of tank + 1 and get an rng
and
sub | rl | jnc mainLoop ;ship healing if check fails
ld part1Health | inc
st part1Health ;heal the cockpit
ld greenColor | out 1
ld setColorBit | out 1 ;make the text green
ld text_healed
stsp
ld zero
addi main_startRet
envoke_outString:
st returnAddress3 | jp outString_noColor
main_startRet:
rng
rr | jnc main_enemyCantShoot ;1/2 chance the enemy won't shoot first
mainLoop:
ld four | dec | stl ;store 3 in L
ld ePart1Health ;get health of enemy cockpit
rl | jz main_enemyCantShoot ;can't shoot if they're dead
ld ePart2Health ;get health of enemy guns
rl | jz main_enemyAttemptFlee ;can't shoot if guns busted, which means it wants to flee
ld ePart2 | and ;get the level of the gun
inc ;add one
st hold2 ;store number of times to shoot
ld zero
addi part2Health ;player ship pointer +2
st hold0
ld zero
addi main_enemyCantShoot ;return here
st returnAddress2 | jp shootShipNTimes ;call shootShipNTimes
main_enemyAttemptFlee: ;L should still be 3
ld ePart4Health
rl | jz main_enemyCantShoot ;can't flee if engine busted
ld part4Health
rl | jz main_enemyCanFlee ;can flee if player engine busted and enemy engine not
ld ePart4 | and ;get enemy engine level
sta
ld part4 | and ;get player engine level
sub | rl | jnc main_enemyCantShoot ;enemy can't flee if engine level lesser than that of player
main_enemyCanFlee:
ld text_enemyFled
stsp
ld zero
addi main
envoke_outString:
st returnAddress3 | jp outString
main_enemyCantShoot: ;also where to go when done shooting/fleeing/not having enemy turn
ld zero
addi retHere1
st returnAddress2 | jp renderBothShips ;call renderBothShips
retHere1:
ld part1Health
rl | jz main_gameOver ;you lose :(
ld zero
addi retHere3
st returnAddress | jp getInput ;call renderBothShips
retHere3:
ld four | dec | stl ;store 3 in L
ld lastInput | and ;get the action code of the input
dec | and | jz main_shoot ;look at this archaic switch statement
dec | and | jz main_flee
dec | and | jz main_scavenge | jp mainLoop
main_scavenge: ;uses hold 1 - 4
ld four | dec | stl ;3 -> L
ld ePart1Health
and | jz main_canScavenge ;can only scavenge if enemy cockpit dead
main_sayFailed:
ld text_failed
stsp
ld zero
addi mainLoop | jp envoke_outString
main_canScavenge:
ld C | stl ;set L to 0b1100
ld lastInput | and
rr ;get it as an *2 of the part slot
sta ;save it for later
ld zero
addi part2Health ;playerShipData + 2
add ;add the offset we figured out
stsp ;also set SP to it
pop ;get the part ID
st hold2 ;keep it
pop ;get the health
st hold1 ;keep it
ld zero
addi ePart2Health ;add it, enemyShipData + 2
add ;A is still that offset value
stsp ;also set SP to it
pop ;get the part ID
st hold4 ;keep it
pop ;get the health
st hold3 ;keep it
ld hold1
push
ld hold2 ;push those parts
push
ld zero
addi part1Health ;point to the base this time bc we're pushing, and minus one bc we added one to A
add ;A is still that offset value
stsp
ld hold3
push
ld hold4
push | jp mainLoop
main_flee:
ld ePart1Health ;get health of enemy cockpit
rl | jz main ;can always get away if the enemy is dead
ld ePart4Health ;get health of enemy cockpit
rl | jz main ;can always get away if the enemy's engine is dead
ld part4Health ;get player's engine health
rl | jz main_fleeFailed ;can't get away if engine busted
ld part4Health ;get enemy's engine health
rl | jz main ;will get away if enemy engine busted
ld four | dec | stl ;put 3 in L
rng ;get a random 0-3
and
sta
ld part4 | and ;get player engine level
add ;total
sta ;put that in A for a sec
ld ePart4 | and ;get enemy engine level
sub | rl | jc main
main_fleeFailed:
ld text_fleeFailed
stsp
ld zero
addi mainLoop | jp envoke_outString
main_shoot:
ld four | dec | stl ;store 3 in L
ld part2Health
and | jz main_sayFailed ;can't shoot if gun's busted
ld part2 | and ;get the level of the gun
inc ;add one
st hold2 ;store number of times to shoot
ld zero
addi ePart2Health ;enemy ship pointer +2
st hold0
ld zero
addi mainLoop ;return here
st returnAddress2 | jp shootShipNTimes ;call shootShipNTimes
main_gameOver:
ld text_youDied
stsp
ld zero
addi halt | jp envoke_outString
halt:
jp halt
renderShip: ;holdDat0 - pointer to ship data, uses hold 0 - 4
ld four | inc
st hold1 ;uses hold 1-3 as counters
st hold2 | inc
inc
st hold3
ld hold0 | inc
st hold4 ;keep the address of the cockpit(+1)
renderShip_horizSpacingLoop:
ld hold2 | dec
st hold2
rl | jz renderShip_loop ;start main once out of loops
ld emptySpaceByteIMeanWord | out 1 | jp renderShip_horizSpacingLoop
renderShip_loop:
ld hold1 | dec
st hold1
rl | jz renderShip_deadText ;ret once out of loops
ld hold0 | inc ;increment pointer
st hold0
stsp ;I had an oversight when making this arc and appearently the only way to access an indirect address is through the stack
pop | addi damagedPartColor ;get the value and add start of colors + 1
stsp
pop | out 1 ;get the color and out it
ld setColorBit | out 1 ;set it
ld hold0 | inc ;increment pointer
st hold0
stsp ;get the part ID
pop | addi assembledCharacterDataPlus1 ;get the value and add start of parts + 1
stsp
pop | out 1 | jp renderShip_loop ;get the part and out it
renderShip_deadText:
ld hold4
stsp
pop | rl | jnz renderShip_vertSpacingLoop ;get the health of the cockpit and print "DEAD" if zero
ld text_dead
stsp
ld zero
addi renderShip_ret | jp envoke_outString
renderShip_ret:
renderShip_vertSpacingLoop:
ld hold3 | dec
st hold3
rl | jz renderShip_exit ;start main once out of loops
ld newlineBit | out 1 | jp renderShip_vertSpacingLoop
renderShip_exit:
return:
ld returnAddress | jpb
renderBothShips: ;uses returnAddress2
ld zero
addi enemyShipData ;point to ship data
st hold0
ld zero
addi renderBothShips_ret
st returnAddress | jp renderShip
renderBothShips_ret:
ld returnAddress2
st returnAddress | jp renderShip
randGenShip: ;uses holdDat 0 - 1
ld eight
st hold0 ;uses hold0 for counter
ld zero
addi enemyShipData ;point to enemy ship
stsp
ld four | dec | stl ;get three, three is 0b11
randGenShip_firstLoop:
rng ;get sum rng
and ;we only need a 2-bit number
push ;save it
ld hold0 | dec
st hold0
rl | jnz randGenShip_firstLoop
ld commandPodCode
st ePart1
ld gunCode | stl
ld ePart2 | or
st ePart2
ld tankCode | stl
ld ePart3 | or
st ePart3
ld engineCode | stl
ld ePart4 | or
st ePart4 | jp return
damageShip: ;holdDat0 - ship to damage address (plus two), uses hold 0 - 1
ld six | stl ;six is 0b110
rng ;get rand num, used to decide which part to hit
and ;keep just those bits. We don't want bit 0 bc then it can point to health and we want part
sta ;put that in A
ld four | dec | stl ;store three into L for later
ld hold0 | add ;point to the part getting shot at (chosen randomly)
stsp
pop | and ;get the part and get its 'level'
st hold1 | rng ;keep this here for now and get an rng
and
addi 2 ;add two to give it at least a 1/4 chance of damaging
sta
ld hold1 | sub
rl | jnc return ;see if the number we rolled is greater than the part's level
pop | and | jz return ;if the part already has zero health, don't remove health
dec ;subtract the health
push | jp return
shootShipNTimes: ;holdDat0 - ship to damage address (plus two); hold2 - num times to shoot, uses hold 0 - 2 and returnAddress2
ld zero
addi shootShipNTimes_ret
st returnAddress | jp damageShip
shootShipNTimes_ret:
ld hold2 | dec
st hold2
rl | jnz shootShipNTimes
return2:
ld returnAddress2 | jpb
outString: ;sp - pointer to end of string (text should be reversed), uses returnAddress3
ld deadPartColor | out 1
ld setColorBit | out 1 ;make the text red
outString_noColor:
pop | out 1
rl | jnz outString_noColor
return3:
ld returnAddress3 | jpb
getInput: ;saves input to lastInput
ld zero | stl
getInput_loop:
in 1
or | jz getInput_loop ;loop until nonzero input
st lastInput ;actual data being outputted is irrelevant, the pulse resets the input
ld clearInputBit | out 2 | jp return ;scratch that, there's two outputs now, so bit two clears it
org_data 0
alwaysFull:
dw 0xFFFFFFF
assembledCharacterData:
dw 0x070 ;these take the character code -and- does the borders to properly render the image
assembledCharacterDataPlus1: ;pop loads SP-1 so..
dw 0x071
dw 0x272
dw 0x373
dw 0x074
dw 0x075
dw 0x376
dw 0x377
dw 0x078
dw 0x079
dw 0x07A
dw 0x27B
dw 0x07C
commandPodCode:
constTwelve:
constC:
twelve:
C:
dw 0xC
engineCode:
constEight:
eight:
incMonthsBit:
dw 8
costSix:
six:
dw 6
tankCode:
constFour:
four:
clearInputBit:
dw 4
gunCode:
constZero:
zero:
dw 0
vidDataStart: ;the actual graphical bitmap data for the ship parts
holdData: ;recycle graphical memory area for other stuff, as we don't need it after init
hold0:
dw 0x80AFFF5
hold1:
dw 0x80FD6BF
hold2:
dw 0x80FDEBF
hold3:
dw 0x9FB6736
hold4:
dw 0x8077FEE
returnAddress:
dw 0x80FC7FF
returnAddress2:
dw 0x9FCC219
returnAddress3:
dw 0x9FCDAD9
dw 0x8017BC2
dw 0x8077BCE
dw 0x809FFF3
lastInput:
dw 0x809FFF3
vidDataEnd:
dw 0x803B5A7
holdPointerVar:
dw holdPointerVar ;vidDataEnd + 1
monitorCharDataPointer:
dw 0x000043D
deadPartColor:
dw 0xC000000
damagedPartColor:
dw 0xBFE0000
hitPartColor:
dw 0x80E0000
healtyPartColor:
dw 0xFFFFFFF
greenColor:
dw 0x801E000
emptySpaceByteIMeanWord:
dw 0x7F
setColorBit:
dw 0x800 ;bit that correlates to monitor instruction for setting text color
;newlineBit:
;dw 0x80
enemyShipData:
ePart1Health:
dw 0x0000003
ePart1:
dw 0x000000C
ePart2Health:
dw 0x0000003
ePart2:
dw 0x0000000
ePart3Health:
dw 0x0000003
ePart3:
dw 0x0000004
ePart4Health:
dw 0x0000003
ePart4:
dw 0x0000008
playerShipData:
part1Health:
dw 0x0000003
part1:
dw 0x000000C
part2Health:
dw 0x0000003
part2:
dw 0x0000000
part3Health:
dw 0x0000003
part3:
dw 0x0000004
part4Health:
dw 0x0000003
part4:
dw 0x0000008
dw 0x00
dw 0x4D ;D
dw 0x4A ;A
dw 0x4E ;E
dw 0x4D ;D
dw 0x7F ;
text_dead:
dw text_dead ;points to itself bc that's how the stack works
dw 0x00
dw 0x80
dw 0x80
dw 0x80
dw 0x4D ;D
dw 0x4E ;E
dw 0x55 ;L
dw 0x52 ;I
dw 0x4A ;A
dw 0x4F ;F
text_failedP:
dw 0x7F ;
dw 0x4E ;E
dw 0x4E ;E
dw 0x55 ;L
dw 0x4F ;F
text_fleeFailed:
dw text_fleeFailed
text_failed:
dw text_failedP
dw 0x00
newlineBit: ;I put this here bc is saves space
dw 0x80
dw 0x80
dw 0x80
dw 0x5B ;R
dw 0x4E ;E
dw 0x5F ;V
dw 0x58 ;O
dw 0x7F ;
dw 0x4E ;E
dw 0x56 ;M
dw 0x4A ;A
dw 0x50 ;G
dw 0x7F ;
dw 0x7F ;
dw 0x7F ;
dw 0x7F ;
text_youDied:
dw text_youDied
dw 0x00
dw 0x80
dw 0x80
dw 0x80
dw 0x4D ;D
dw 0x4E ;E
dw 0x55 ;L
dw 0x4A ;A
dw 0x4E ;E
dw 0x51 ;H
text_healed:
dw text_healed
dw 0x00
dw 0x80
dw 0x80
dw 0x80
dw 0x4D ;D
dw 0x4E ;E
dw 0x55 ;L
dw 0x4F ;F
dw 0x7F ;
dw 0x62 ;Y
dw 0x56 ;M
dw 0x4E ;E
dw 0x57 ;N
dw 0x4E ;E
text_enemyFled:
dw text_enemyFled