Starship Rogue Sourcecode

  • Sam_Hayzen
    16th Oct 2019 Member 2 Permalink

    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
    

    Edited 2 times by Sam_Hayzen. Last: 20th Oct 2019