; Incoming! ; Version 1.0 RC 1 ; For the Atari 2600 VCS ; by Ben Larson (c) 2001-2008 ; ; Started circa August 2001. Not worked on for looong stretches...obviously. :) ; Last modified Jan 26, 2008 ; ; ; Changes since Beta 6: ; ; 1) Various optimizations to free up space and clean things up, i.e. joystick code, ; wind adjustment, BCD-to-binary and binary-to-BCD subroutines ; 2) Modified computer AI in various ways: a) he uses 67 degrees for high elevation now instead of 70, ; b) he no longer uses a high elevation just because the player did - instead, now he will use a ; high elevation if his shot landed 40+ pixels above player 1, c) he will now not increase power if ; the shot was still going up when it landed, and d) he will increase power more than normal when ; switching to a high elevation if the player is 40+ pixels below him. ; 3) Added 'random terrain roughness mode' when difficulty switches are both set to left, instead of just ; completely flat terrain mode (which was mainly just for testing stuff anyway). ; 4) Corrected roundoff errors with shot position calculations by using 24-bit math for ; position calculations instead of 16-bit. This bug would have previously manifested ; itself as slightly uneven decreases/increases in shot velocity as you decrease/increase ; power. ; 5) Fixed minor bug where shot collision wouldn't register near very top of player graphic ; if the player was on the very highest mountain point. ; 6) Changed clouds slightly ; ; ; Bit descriptions for status registers used in the game: ; ; Status ; ------ ; 7 - 1 = a player has been hit, 0 = no player has been hit ; 6 - 1 = select mode, 0 = not select mode ; 5 - (unused) ; 4 - 1 = shot has wrapped off top of screen, 0 = shot on screen ; 3 - 1 = shot is rising, 0 = shot is falling ; 2 - 0 = frame we can check joysticks on, 1 = not ; 1 - 1 = a shot is in the air, 0 = no shot in the air ; 0 - 0 = player 1's turn, 1 = player 2's turn ; ; Status2 ; ------- ; 7 - (unused) ; 6 - (unused) ; 5 - (unused) ; 4 = 1 = shot went over player 1, 0 = shot went under ; 3 = 1 = shot has passed player 1's x position, 0 = shot has not passed ; 2 - 1 = game just ended, 0 = game isn't ended yet ; 1 - 1 = we are computing the computer's shot traj, 0 = not computing ; 0 = 0 = 1 player game, 1 = 2 player game ; processor 6502 include vcs.h org $F000 PField0 = $80 ; We need to reserve 15 bytes of RAM for each of these PField1A = $8F ; 'PField' vars, for a total of 75 bytes. These are PField2A = $9E ; where the playfield is written to after being dynamically PField1B = $AD ; generated PField2B = $BC ; $CB - Beginning of non-PF data ShotElevation = $CB AdditionCycles = $CC CloudXPos = $CD ShotYPos = $CE ShotXPosActual = $CF ShotXVelRemRem = $D0 P1Elevation = $D1 P2Elevation = $D2 P1Power = $D3 P2Power = $D4 Wind = $D5 TempAddr1 = $D6 TempAddr1B = $D7 TempAddr2 = $D8 TempAddr2B = $D9 TempAddr3 = $DA TempAddr3B = $DB TempAddr4 = $DC TempAddr4B = $DD TempAddr5 = $DE Temp = $DE TempAddr5B = $DF TempAddr6 = $E0 Temp2 = $E0 TempAddr6B = $E1 ShotXVelRemRemRem = $E2 ShotXPosRemRem = $E2 ShotYVelRemRemRem = $E3 ShotYPosRemRem = $E3 P1YPos = $E4 P1YPosB = $E5 P2YPos = $E6 P2YPosB = $E7 P1XPos = $E8 P2XPos = $E9 P1Score = $EA P2Score = $EB ;OldWind = $EC ShotXPosRem = $ED ShotYPosActual = $EE ShotYPosRem = $EF ShotYPosScrn = $F0 ShotXVel = $F1 ShotXVelRem = $F2 ShotYVel = $F3 Status2 = $F4 Status = $F5 CloudXPosRem = $F6 PFGenTemp = $F6 NumToWin = $F7 rand1 = $F8 rand2 = $F9 rand3 = $FA rand4 = $FB ShotYVelRem = $FC ShotYVelRemRem = $FD ; STACK = $FE ; STACK = $FF PFCalcTemp = $BC ; this space in RAM will also be used for intermediate calculations ; regarding the playfield generation PF0Temp = $EC PF1aTemp = $ED PF2aTemp = $EE PF1bTemp = $EF PF2bTemp = $F0 ; ***************** ; * PROGRAM START * ; ***************** ; ******************************** ; * GENERAL INITIALIZATION STUFF * ; ******************************** Start CLD ; Clear the decimal flag LDX #%01000000 ; Initially start in 'select' mode STX Status LDX #0 STX Status2 INX STX P1Score LDX #$06 STX P2Score STX NumToWin Reset Start2 LDA Status2 ;[0]+3 AND #%11111101 ;[3]+2 STA Status2 ;[5]+3 Reset the 'compute computer shot trajectory' bit for new scenario LDX #$FF ;[8]+2 TXS ;[10]+2 Set stack to beginning. STX rand1 ;[12]+3 Seed the random number generator JSR GraphicsDelay3 ; End vertical blank, begin 192 line picture scan period ; ******************************* ; * RANDOM PLAYFIELD GENERATION * ; ******************************* ; Now we need to generate the playfield using the random number generation ; routines. ; OK, we need to generate 20 values for playfield height in memory, ; ranging from 0 to 15, starting at PFCalcTemp. ; First we clear the playfield data variables LDX #0 ;[15]+2 TXA ;[17]+2 = 19 ClearPFData STA PField0,X ;[0]+4 INX ;[4]+2 CPX #75 ;[6]+2 BNE ClearPFData ;[8]+3 = 11 ;19 + 75*11 - 1 = 843 ; First we generate a random 3-bit starting value, and reinitialize ; X and Y JSR RandomByte ;[843]+6+328 AND #7 ;[1177]+2 mask out the upper 5 bits that we don't want CLC ;[1179]+2 ADC #4 ;[1181]+2 STA PFCalcTemp ;[1183]+3 LDY #0 ;[1186]+2 LDA SWCHB ;[1188]+3 ; look at the difficulty switches for terrain settings AND #%11000000 ;[1191]+2 ROL ;[1193]+2 ROL ;[1195]+2 ROL ;[1197]+2 CMP #0 BNE NoRandomRoughness JSR RandomByte BIT rand1 BPL RandomRoughness2 LDA #1 BNE NoRandomRoughness RandomRoughness2 BVS RandomRoughness3 LDA #2 BNE NoRandomRoughness RandomRoughness3 LDA #3 NoRandomRoughness STA ShotXVel ;[1199]+3 ; Use ShotXVel as a temp var. INC ShotXVel ;[1202]+5 TXA ;[1207]+2 SEC ;[1209]+2 SBC ShotXVel ;[1211]+3 STA ShotXVelRem ;[1214]+3 = 1217 ; Use ShotXVelRem as a temp var. GenPFVals Random3Bit LDA #3 ;[0]+3 STA PFGenTemp ;[3]+3 = 6 Random3Bit1 JSR RandomBit ;[0]+6+27 DEC PFGenTemp ;[33]+5 BNE Random3Bit1 ;[38]+3 = 41 ;6 + 3*41 - 1 = 128 LDA rand1 ;[128]+3 AND #7 ;[131]+3 ; mask out the upper 5 bits that we don't want CMP #4 ;[134]+2 BCC AdjustPos ;[136]+3 ; If value <= 3, adjust in positive direction CMP #7 ;[139]+2 BCC AdjustNeg ;[141]+3 ; Else if value <= 6, adjust in negative direction BCS EndofAccMod ; Else don't adjust at all AdjustPos ; Adjust acceleration 1 in positive direction - can't go > 3 INY ;[139]+2 CPY ShotXVel ;[141]+3 BNE EndofAccMod ;[144]+2 DEY ;[146]+2 JMP EndofAccMod ;[148]+3 AdjustNeg ; Adjust acceleration 1 in negative direction - can't go < -3. DEY ;[144]+2 CPY ShotXVelRem ;[146]+3 BNE EndofAccMod ;[149]+2 INY ;[151]+2 EndofAccMod TYA ;[153]+2 CLC ;[155]+2 ; clear the carry bit for the addition ADC PFCalcTemp,X ;[157]+4 CheckLow BPL CheckHigh ;[161]+3 PFAdjustLow LDY #1 LDA #0 BEQ EndofVelMod CheckHigh CMP #15 ;[164]+2 BCC EndofVelMod ;[166]+2 LDY #-1 ;[168]+2 LDA #14 ;[170]+2 EndofVelMod INX ;[172]+2 STA PFCalcTemp,X ;[174]+4 CPX #39 ;[178]+2 ; We want to generate 40 values total BNE GenPFVals ;[180]+3 = 183 ;1217 + 183*40 - 1 = 8536 ; ***************************** ; * LANDSCAPE DRAWING ROUTINE * ; ***************************** ; Landscape drawing routine ; The basic screen layout is like this: ; ; PField0| PField1a | PField2a |PField0| PField1b | PField2b ; 4 5 6 7|7 6 5 4 3 2 1 0|0 1 2 3 4 5 6 7|0 1 2 3|7 6 5 4 3 2 1 0|0 1 2 3 4 5 6 7 LDA #%00010000 ;[8536]+2 STA PF0Temp ;[8538]+3 LDA #0 ;[8541]+2 STA PF1aTemp ;[8543]+3 STA PF2aTemp ;[8546]+3 STA PF1bTemp ;[8549]+3 STA PF2bTemp ;[8552]+3 TAY ;[8555]+2 = 8557 ; TODO: End 192 picture line scan period, do overscan, vertical ; blank, and start another new picture line scan period JSR GraphicsDelay BitMaskTop SEC ;[0]+2 LDA #14 ;[2]+2 SBC PFCalcTemp,Y ;[4]+4 TAX ;[8]+2 = 10 OrMask LDA PField0,X ;[0]+4 ORA PF0Temp ;[4]+2 STA PField0,X ;[6]+5 LDA PField1A,X ;[11]+4 ORA PF1aTemp ;[15]+2 STA PField1A,X ;[17]+5 LDA PField2A,X ;[22]+4 ORA PF2aTemp ;[26]+2 STA PField2A,X ;[28]+5 LDA PField1B,X ;[33]+4 ORA PF1bTemp ;[37]+2 STA PField1B,X ;[39]+5 LDA PField2B,X ;[44]+4 ORA PF2bTemp ;[48]+2 STA PField2B,X ;[50]+5 INX ;[55]+2 CPX #15 ;[57]+2 BNE OrMask ;[59]+3 = 62 ; 62*15 - 1 = 929 ; 929 + 10 = 939 CLC ;[939]+2 LDA PF0Temp ;[941]+3 Rotate upper 4 bits of PF0Temp left ROL ;[944]+2 AND #%11100000 ;[946]+2 TAX ;[948]+2 LDA PF1aTemp ;[950]+3 Rotate PF1aTemp right ROR ;[953]+2 STA PF1aTemp ;[955]+3 LDA PF2aTemp ;[958]+3 Rotate PF2aTemp left ROL ;[961]+2 STA PF2aTemp ;[963]+3 LDA PF0Temp ;[966]+3 Rotate lower 4 bits of PF0Temp left ROL ;[969]+2 AND #%00011111 ;[971]+2 STX PFGenTemp ;[973]+3 ORA PFGenTemp ;[976]+2 TAX ;[978]+2 ASL ;[980]+2 Rotate left 4 more times to get bit 3 ASL ;[982]+2 into carry ASL ;[984]+2 ASL ;[986]+2 TXA ;[988]+2 AND #%11101111 ;[990]+2 Although we needed this bit earlier, now we have to delete it STA PF0Temp ;[992]+3 LDA PF1bTemp ;[995]+3 Rotate PF1Temp right ROR ;[998]+2 STA PF1bTemp ;[1000]+3 LDA PF2bTemp ;[1003]+3 Rotate PF2Temp left ROL ;[1006]+2 STA PF2bTemp ;[1008]+3 INY ;[1011]+2 CPY #20 ;[1013]+2 BNE NoOldDataClear ;[1015]+3 STY PFGenTemp ;[0]+3 LDY #0 ;[3]+2 TYA ;[5]+2 = 7 ClearPFData2 STA PField1B,Y ;[0]+4 INY ;[4]+2 CPY #30 ;[6]+2 BNE ClearPFData2 ;[8]+3 = 11 ;11*30 - 1 - 1 = 328 LDY PFGenTemp ;[328]+3 = 331 NoOldDataClear ; TODO: Every time Y is divisible by 8, end the 192 picture ; line scan period, do overscan, vertical blank, and ; start another new picture line scan period TYA AND #%00001000 BEQ NoGraphicsDelay JSR GraphicsDelay NoGraphicsDelay CPY #40 ;[1018]+2 BNE BitMaskTop ;[1020]+3 = 1023 ;1023*40 + 331 = 41251 ;41251 + 8557 = 49808 ; ****************************** ; * PLAYER POSITION GENERATION * ; ****************************** ; Calculate first player coarse position ; Generate random value from 0 to 3 for upper nibble and 0 to 15 for lower nibble JSR RandomByte AND #%00111111 ; mask out the bits that we don't want STA P1XPos ; Set first player horizontal position ; Calculate second player coarse position ; Generate random value from 0 to 3 for upper nibble and 0 to 15 for lower nibble JSR RandomByte AND #%00111111 ; mask out the bits that we don't want CLC ADC #89 STA P2XPos ; Set second player horizontal position ; *********************** ; * GAME INITIALIZATION * ; *********************** GameInit LDA #0 BIT Status BVS EndNoSelectMode NoSelectMode LDA #$50 EndNoSelectMode STA P1Power STA P2Power LDA PFColor STA COLUPF LDA BKColor STA COLUBK LDA #-42 STA ShotYPos LDA #$45 STA P1Elevation STA P2Elevation LDA #100 STA CloudXPos LDA #0 STA P1YPos STA P2YPos STA CXCLR STA HMCLR STA AdditionCycles STA ShotYPosScrn ;LDA #16 ;STA OldWind ; Set up the joysticks STA SWACNT ; Set port A (the one the joysticks are on) as input ; Set up the temp address registers LDA #$FD STA TempAddr1B STA TempAddr2B STA TempAddr3B STA TempAddr4B STA TempAddr5B STA TempAddr6B ; Set the player graphic pointers for the player 1 tank and player 2 tank LDA #$FE STA P1YPosB STA P2YPosB ; Initialize 'Wind' JSR RandomByte AND #%00001111 CLC ADC #9 STA Wind ; TODO: End 192 picture line scan period and do overscan WaitForTimer LDA INTIM BNE WaitForTimer ; Wait for the 192 line drawing period to end STA WSYNC LDA #35 STA TIM64T ; Synchronize the timer for the 30 line overscan period WaitForTimer2 LDA INTIM BNE WaitForTimer2 ; Wait for the 30 line overscan period to end ; ********************************** ; * BEGINNING OF MAIN PROGRAM LOOP * ; ********************************** ; ****************** ; * VERTICAL BLANK * ; ****************** VerticalBlank LDA #2 STA VSYNC ; Begin vertical sync. STA WSYNC ; First line of VSYNC STA WSYNC ; Second line of VSYNC. LDA #44 STA TIM64T ; End the VSYNC period. STA WSYNC ; Third line of VSYNC. STA VSYNC ; ****************** ; * CHECK SWITCHES * ; ****************** CheckSwitches LDY #0 ; Load Y with zero since we'll need it in a couple places LDA SWCHB ; Check the reset switch ROR BCC PreReset BIT Status ; Check the 'select mode' bit in 'Status' BVC NoReset ; If we're not in select mode, then we can't allow a controller button reset LDA INPT4 BMI NoReset ; If joystick 1's button isn't being pressed, then no reset PreReset STY Status ; If reset is being pressed, clear the status and player health bytes, then jump to 'Reset'. STY P1Score STY P2Score JMP Reset NoReset LDA SWCHB ; Check the select switch AND #Con_Select BNE NoSelect ; If the select switch isn't being pressed, jump to 'NoSelect' BIT Status ; Check the 'select mode' bit in 'Status' BVC NewSelect ; If the switch is being pressed, and we're not in select mode, jump to 'NewSelect' LDA Status2 ; Check if the 'game just ended' bit is set in 'Status2' AND #%00000100 BNE NewSelect ; If the bit is set (i.e. the game just ended), jump to 'NewSelect' LDA P2Power ; 'P2Power' is used as a timer in select mode. Check this timer BNE NoSelect ; If it's not equal to zero, jump to 'NoSelect' LDA P2Score ; OK, we are in select mode and we need to increment the game variation SED CLC ADC #$04 CMP #$26 BNE NoSelectAdjust ; Check if num. of games to win has reached 26 yet LDX Status2 ; If the num. of games to win = 26, change # of players and reset games to win to 6 INX TXA AND #%00000001 STA Status2 TAX INX STX P1Score LDA #$06 NoSelectAdjust STA P2Score ; Store new values for games to win and # of players STA NumToWin CLD JMP NoSelect ; Now we're done - Jump to 'NoSelect' NewSelect ; Select is being pressed, but we aren't in select mode yet STY P1Power ; we have to reset P2Power to something divisible by STY P2Power ; 8 - it's used as a timer in select mode LDA #%01000000 STA Status ; Reset the status byte to indicate that we're in select mode LDA Status2 AND #%00000001 STA Status2 ; Clear the 'game just ended', 'calc. computer shot' bits, and TAX ; computer shot over/under bits, if set INX STX P1Score LDA NumToWin STA P2Score ; Load P1Score and P2Score with # of players and num of games to win, respectively NoSelect BIT Status ; Check the 'player has been hit' bit of 'Status' BPL EndSwitchCheck ; If a player has not been hit, jump to 'EndSwitchCheck' LDA NumToWin CMP P1Score ; See if player 1 scored a game-ending hit BEQ Winner ; If so, jump to 'Winner' CheckPlayer2Winner CMP P2Score ; See if player 2 scored a game-ending hit BEQ Winner ; If so, jump to 'Winner' NoWinnerYet ; Nobody has won the game yet SED CLC LDA P1Score ADC P2Score ; Add the two player scores together CLD AND #%00000001 ; Look at the last bit of the added scores to determine who goes next STA Status ; Switch players JMP Start2 ; Jump to 'Start2' to generate a new scenario Winner ; Someone won the game LDA #%01000000 STA Status ; Put the game into select mode LDA #%00000100 ORA Status2 STA Status2 ; Set the 'game just ended' bit STY P1Power ; Now we have to reset P2Power to something divisible by STY P2Power ; 8 - it's used as a timer in select mode EndSwitchCheck ; ********************* ; * GAME CALCULATIONS * ; ********************* GameCalc ; Call the random bit generation subroutine so that we continue to seed it JSR RandomBit ; Reset multiple copy / horizontal span registers and player 1 color STY NUSIZ0 LDA #%00000110 STA NUSIZ1 STY REFP1 LDA P1Color CLC ADC #146 STA COLUP0 LDA #%00001000 STA REFP0 ; Do cloud movement LDA Wind SEC SBC #16 ASL ASL STA Temp BMI DoNegativeCloudMovement CLC ADC CloudXPosRem STA CloudXPosRem BCC EndDoCloudMovement INC CloudXPos LDA CloudXPos CMP #160 BCC EndDoCloudMovement LDA #0 STA CloudXPos JMP EndDoCloudMovement DoNegativeCloudMovement CLC ADC CloudXPosRem STA CloudXPosRem BCS EndDoCloudMovement LDA CloudXPos CLC ADC #-1 STA CloudXPos BCS EndDoCloudMovement LDA #159 STA CloudXPos EndDoCloudMovement ; Check to see if a shot is in the air or not...if so, we need to update the ; velocity / position values of the shot, otherwise we skip straight to 'DisplayTanks' LDA AdditionCycles ; If this is nonzero, the game is currently calculating shot vectors BNE JumpDisplayTanks LDX Status TXA AND #%00000010 BNE UpdateShot JumpDisplayTanks JMP DisplayTanks UpdateShot ; Now we have to adjust the X velocity vector value for wind ;JMP ComputeShotXPos LDA Temp ASL STA Temp TXA AND #%00000001 BEQ NoPlayer2NegativeWind LDA #0 SEC SBC Temp STA Temp NoPlayer2NegativeWind LDA Temp BMI DoNegativeWind LDA ShotXVelRemRem CLC ADC Temp STA ShotXVelRemRem BCC ComputeShotXPos LDA ShotXVelRem CLC ADC #1 STA ShotXVelRem BCC ComputeShotXPos INC ShotXVel JMP ComputeShotXPos DoNegativeWind LDA ShotXVelRemRem CLC ADC Temp STA ShotXVelRemRem BCS ComputeShotXPos LDA ShotXVelRem CLC ADC #-1 STA ShotXVelRem BCS ComputeShotXPos DEC ShotXVel ComputeShotXPos ; Compute new shot X position LDA ShotXPosRemRem SBC ShotXVelRemRem STA ShotXPosRemRem LDA ShotXPosRem SBC ShotXVelRem STA ShotXPosRem TYA SBC ShotXVel STA Temp TXA AND #%00000001 BEQ NoPlayer2XPosAdjust LDA #0 SEC SBC Temp STA Temp NoPlayer2XPosAdjust LDA ShotXPosActual SEC SBC Temp ; Subtract Temp, which is the shot's X-coordinate difference STA ShotXPosActual ; between last frame and this frame, from ShotXPosActual, which is ; the actual Shot X position ; Compute new shot Y position LDY ShotYPos LDA ShotYVelRem SEC SBC #4 ; Subtract the gravity constant from the Y velocity remainder STA ShotYVelRem BCS DontDecrementYVel DEC ShotYVel LDA ShotYVel CMP #255 BNE DontDecrementYVel LDA #%11110111 AND Status STA Status ; Shot has started falling - change Y direction to 'down'. DontDecrementYVel LDA ShotYPosRemRem SEC SBC ShotYVelRemRem STA ShotYPosRemRem LDA ShotYPosRem SBC ShotYVelRem STA ShotYPosRem LDA ShotYPos SBC ShotYVel STA ShotYPos ; A little confusing - Positive Y position actually means lower on screen LDA Status AND #%00001000 CMP #0 BEQ CheckWrapDown CheckWrapUp TYA SEC SBC ShotYPos ; Check to see if shot has wrapped around in the negative direction BCS EndShot INC ShotYPosScrn BCC EndShot CheckWrapDown TYA CMP ShotYPos BEQ EndShot SEC SBC ShotYPos ; Check to see if shot has wrapped around in positive direction BCC EndShot DEC ShotYPosScrn EndShot DisplayTanks ; Check if shot is off left or right sides of screen...if so, set ShotYPos to 120 so it triggers an off-screen ; detection during overscan period LDA ShotXPosActual CMP #159 BCC ShotNotOffLeftOrRight LDA #120 STA ShotYPos LDA #0 STA ShotYPosScrn ShotNotOffLeftOrRight ; Set value for 'ShotYPosActual' - It always has to be an even number LDA #1 STA VDELBL LDA #120 SEC SBC ShotYPos STA ShotYPosActual AND #%00000001 BEQ ComputeOffScreen INC ShotYPosActual ComputeOffScreen ; If shot is off-screen and ShotYPos is not between -40 and 0 (216-255 and 0), don't display it LDA ShotYPosScrn BEQ EndHideShot CMP #1 BNE HideShot FirstWrap LDA ShotYPos CMP #216 BCS EndHideShot HideShot LDA #162 STA ShotYPosActual EndHideShot ; Readjust player horizontal positions accordingly LDA CloudXPos LDX #1 JSR PositionSprite JSR WasteTime JSR WasteTime LDA P2XPos LDX #0 JSR PositionSprite JSR WasteTime JSR WasteTime LDA ShotXPosActual LDX #4 JSR PositionSprite JSR WasteTime JSR WasteTime LDA #0 STA ENABL STA GRP1 ; erase the shot, since it gets positioned in 'PositionSprite' ; Move the shot, if it's in the air ;STA HMCLR ;LDA Status ;AND #%00000010 ;BEQ NoShotMovement ;LDA ShotXPos ;ASL ;ASL ;ASL ;ASL ;STA HMBL ;BNE NoShotZeroMovement ;NoShotMovement ;LDA #0 ;STA HMBL ;NoShotZeroMovement ;STA WSYNC ;STA HMOVE ; ****************** ; * DISPLAY KERNEL * ; ****************** DrawScreen LDA INTIM BNE DrawScreen STA WSYNC STA VBLANK ; Write a '0' to VBLANK to turn the TIA back on STA CXCLR ; Clear collision registers for this frame LDA #%00000100 STA CTRLPF ; Change object priorities so that the shot goes in front of the cloud LDY #158 ; This is the first (rather minor) display loop. It handles the first 26 lines of ; the screen - the area before any of the playfield or players appear. DelayLoop STA WSYNC CPY #146 BCS NoCloud LDA CloudColor-138,Y STA COLUP1 LDA CloudData-134,Y STA GRP1 NoCloud LDX #$1F ;[]+2 TXS ;[]+2 CPY ShotYPosActual ;[]+3 PHP DEY LDA #0 STA WSYNC CPY #146 BCS NoCloud2 LDA CloudColor-138,Y STA COLUP1 LDA CloudData-134,Y NoCloud2 STA GRP1 DEY CPY #134 BNE DelayLoop LDX #$1F ;[]+2 TXS ;[]+2 CPY ShotYPosActual ;[]+3 PHP LDX #$FF ; ... and restore the pointer stack TXS STA WSYNC LDA P1XPos LDX #1 JSR PositionSprite LDY #130 LDA #0 STA NUSIZ1 ; reset the player graphic width + repeat bits STA GRP1 STA CTRLPF ; reset the object priorities LDA P1Color STA COLUP1 ; This is the second minor display loop. It handles the first 10 lines of ; the screen where the players may in fact, appear. SecondaryScanLoop STA WSYNC LDA (P1YPos),Y STA GRP1 LDX #$1F TXS CPY ShotYPosActual PHP LDA (P2YPos),Y STA GRP0 DEY STA WSYNC LDA (P1YPos),Y STA GRP1 LDA (P2YPos),Y STA GRP0 DEY CPY #120 BNE SecondaryScanLoop ; This is the beginning of the primary display loop. Each iteration handles ; eight lines of the display. 15 iterations are made, for a total of 120 lines ; of the display. ; The loop had to be unrolled into eight line segments in order to have ; enough time to draw the playfield as well as load the data for both players. ; The only alternative would've been to use double-line vertical resolution ; for the player graphics, which would've looked kinda too Indy 500-ish. :) LDX #0 STX Temp2 LDA PField1A,X STA WSYNC ScanLoop ; ****** FIRST LINE ****** STA PF1 ;[0]+3 = 3 < 29 ; Load player 1 data LDA (P1YPos),Y ;[3]+5 STA GRP1 ;[8]+3 ; This part loads the playfield data into the PF registers. LDA PField0,X ;[11]+4 STA PF0 ;[15]+3 = 18 < 23 ASL ;[18]+2 ASL ;[20]+2 ASL ;[22]+2 ASL ;[24]+2 STA PF0 ;[26]+3 = 29 < 51 and 29 >= 29 LDA PField2A,X ;[29]+4 STA PF2 ;[33]+3 = 36 < 40 ; Load player 2 data LDA (P2YPos),Y ;[36]+5 STA GRP0 ;[41]+3 LDA PField1B,X ;[44]+4 STA PF1 ;[48]+3 = 51 < 57 and 51 > 40 LDA PField2B,X ;[51]+4 STA PF2 ;[55]+3 = 58 < 68 and 58 > 51 LDX #$1F ;[58]+2 TXS ;[60]+2 CPY ShotYPosActual ;[62]+3 PHP ;[65]+3 LDX Temp2 ;[68]+3 LDA PField1A,X ;[71]+4 DEY ;[75]+2 = 77 ; ****** SECOND LINE ****** STA PF1 ;[0]+3 = 3 ( really 4 ) ; Load player 1 data LDA (P1YPos),Y ;[3]+5 STA GRP1 ;[8]+3 ; This part loads the playfield data into the PF registers. LDA PField0,X ;[11]+4 STA PF0 ;[15]+3 = 16 < 23 ASL ;[18]+2 ASL ;[20]+2 ASL ;[22]+2 ASL ;[24]+2 STA PF0 ;[26]+3 = 27 < 51 and 29 >= 29 LDA PField2A,X ;[29]+4 STA PF2 ;[33]+3 = 36 < 40 ; Load player 2 data LDA (P2YPos),Y ;[36]+5 STA GRP0 ;[41]+3 LDA PField1B,X ;[44]+4 STA PF1 ;[48]+3 = 51 < 57 and 51 > 40 LDA PField2B,X ;[51]+4 STA PF2 ;[55]+3 = 58 < 68 and 58 > 51 LDA PField1A,X ;[58]+4 DEY ;[62]+2 = 64 STA PF1 ;[64]+3 LDA BKColor,X ;[67]+4 = 71 NOP ;[71]+2 NOP ;[73]+2 = 75 ; ****** THIRD LINE ****** STA COLUBK ;[0]+3 = 3 < 29 ; Load player 1 data LDA (P1YPos),Y ;[3]+5 STA GRP1 ;[8]+3 ; This part loads the playfield data into the PF registers. LDA PField0,X ;[11]+4 STA PF0 ;[15]+3 = 18 < 23 ASL ;[18]+2 ASL ;[20]+2 ASL ;[22]+2 ASL ;[24]+2 STA PF0 ;[26]+3 = 29 < 51 and 29 >= 29 LDA PField2A,X ;[29]+4 STA PF2 ;[33]+3 = 36 < 40 ; Load player 2 data LDA (P2YPos),Y ;[36]+5 STA GRP0 ;[41]+3 LDA PField1B,X ;[44]+4 STA PF1 ;[48]+3 = 51 < 57 and 51 > 40 LDA PField2B,X ;[51]+4 STA PF2 ;[55]+3 = 58 < 68 and 58 > 51 LDX #$1F ;[58]+2 TXS ;[60]+2 CPY ShotYPosActual ;[62]+3 PHP ;[65]+3 LDX Temp2 ;[68]+3 LDA PField1A,X ;[71]+4 DEY ;[75]+2 = 77 ; ****** FOURTH LINE ****** STA PF1 ;[0]+3 = 3 ( really 4 ) ; Load player 1 data LDA (P1YPos),Y ;[3]+5-6 STA GRP1 ;[8]+3 ; This part loads the playfield data into the PF registers. LDA PField0,X ;[11]+4 STA PF0 ;[15]+3 = 18 < 23 ASL ;[18]+2 ASL ;[20]+2 ASL ;[22]+2 ASL ;[24]+2 STA PF0 ;[26]+3 = 29 < 51 and 29 >= 29 LDA PField2A,X ;[29]+4 STA PF2 ;[33]+3 = 36 < 40 ; Load player 2 data LDA (P2YPos),Y ;[36]+5 STA GRP0 ;[41]+3 LDA PField1B,X ;[44]+4 STA PF1 ;[48]+3 = 51 < 57 and 51 > 40 LDA PField2B,X ;[51]+4 STA PF2 ;[55]+3 = 58 < 68 and 58 > 51 LDA PField1A,X ;[58]+4 DEY ;[62]+2 = 64 STA PF1 ;[64]+3 ;LDA Temp ;[67]+3 Waste 3 cycles LDA PFColor,X ;[70]+4 = 74 NOP ;[71]+2 NOP ;[73]+2 = 75 ; ****** FIFTH LINE ****** STA COLUPF ;[0]+3 ; Load player 1 data LDA (P1YPos),Y ;[3]+5 STA GRP1 ;[8]+3 ; This part loads the playfield data into the PF registers. LDA PField0,X ;[11]+4 STA PF0 ;[15]+3 = 18 ( really 18 < 22.67 ) ASL ;[18]+2 ASL ;[20]+2 ASL ;[22]+2 ASL ;[24]+2 STA PF0 ;[26]+3 = 29 ( really 29 < 49.33 and 29 >= 28 ) LDA PField2A,X ;[29]+4 STA PF2 ;[33]+3 = 36 ( really 36 < 38.67 ) ; Load player 2 data LDA (P2YPos),Y ;[36]+5 STA GRP0 ;[41]+3 LDA PField1B,X ;[44]+4 STA PF1 ;[48]+3 = 51 ( really 51 < 54.67 and 51 > 38.67 ) LDA PField2B,X ;[51]+4 STA PF2 ;[55]+3 = 58 ( really 58 < 65.33 and 58 > 49.33 ) LDX #$1F ;[58]+2 TXS ;[60]+2 CPY ShotYPosActual ;[62]+3 PHP ;[65]+3 LDX Temp2 ;[68]+3 LDA PField1A,X ;[71]+4 DEY ;[75]+2 = 77 ; ****** SIXTH LINE ****** STA PF1 ;[0]+3 = 3 ( really 4 ) ; Load player 1 data LDA (P1YPos),Y ;[3]+5 STA GRP1 ;[8]+3 ; This part loads the playfield data into the PF registers. LDA PField0,X ;[11]+4 STA PF0 ;[15]+3 = 18 ( really 19 < 22.67 ) ASL ;[18]+2 ASL ;[20]+2 ASL ;[22]+2 ASL ;[24]+2 STA PF0 ;[26]+3 = 29 ( really 30 < 49.33 and 30 >= 28 ) LDA PField2A,X ;[29]+4 STA PF2 ;[33]+3 = 36 ( really 37 < 38.67 ) ; Load player 2 data LDA (P2YPos),Y ;[36]+5 STA GRP0 ;[41]+3 LDA PField1B,X ;[44]+4 STA PF1 ;[48]+3 = 51 ( really 52 < 54.67 and 52 > 38.67 ) LDA PField2B,X ;[51]+4 STA PF2 ;[55]+3 = 58 ( really 59 < 65.33 and 59 > 49.33 ) ;LDA P1Color,X ;[58]+4 ;STA COLUP1 ;[62]+3 ;ADC #146 ;[65]+2 ;STA COLUP0 ;[67]+3 NOP ;[58]+2 NOP ;[60]+2 NOP ;[62]+2 NOP ;[64]+2 NOP ;[66]+2 LDA PField1A,X ;[68]+4 DEY ;[72]+2 = 74 ; ****** SEVENTH LINE ****** STA PF1 ;[0]+3 = 3 ( really 2 ) ; Load player 1 data LDA (P1YPos),Y ;[3]+5 STA GRP1 ;[8]+3 ; This part loads the playfield data into the PF registers. LDA PField0,X ;[11]+4 STA PF0 ;[15]+3 = 18 ( really 17 < 22.67 ) ASL ;[18]+2 ASL ;[20]+2 ASL ;[22]+2 ASL ;[24]+2 STA PF0 ;[26]+3 = 29 ( really 28 < 49.33 and 28 >= 28 ) LDA PField2A,X ;[29]+4 STA PF2 ;[33]+3 = 36 ( really 35 < 38.67 ) ; Load player 2 data LDA (P2YPos),Y ;[36]+5 STA GRP0 ;[41]+3 LDA PField1B,X ;[44]+4 STA PF1 ;[48]+3 = 51 ( really 50 < 54.67 and 50 > 38.67 ) LDA PField2B,X ;[51]+4 STA PF2 ;[55]+3 = 58 ( really 57 < 65.33 and 57 > 49.33 ) LDX #$1F ;[58]+2 TXS ;[60]+2 CPY ShotYPosActual ;[62]+3 PHP ;[65]+3 LDX Temp2 ;[68]+3 LDA PField1A,X ;[71]+4 DEY ;[75]+2 = 77 ; ****** EIGHTH LINE ****** STA PF1 ;[0]+3 = 3 < 28 ; Load player 1 data LDA (P1YPos),Y ;[3]+5 STA GRP1 ;[8]+3 ; This part loads the playfield data into the PF registers. LDA PField0,X ;[11]+4 STA PF0 ;[15]+3 = 18 ( 18 < 22.67 ) ASL ;[18]+2 ASL ;[20]+2 ASL ;[22]+2 ASL ;[24]+2 STA PF0 ;[26]+3 = 29 ( 29 < 49.33 and 29 >= 28 ) LDA PField2A,X ;[29]+4 STA PF2 ;[33]+3 = 36 ( 36 < 38.67 ) ; Load player 2 data LDA (P2YPos),Y ;[36]+5 STA GRP0 ;[41]+3 LDA PField1B,X ;[44]+4 STA PF1 ;[48]+3 = 51 ( 51 < 54.67 and 51 > 38.67 ) LDA PField2B,X ;[51]+4 STA PF2 ;[55]+3 = 58 ( 58 < 65.33 and 58 > 49.33 ) INX ;[58]+2 LDA PField1A,X ;[60]+4 DEY ;[64]+2 BEQ Bypass ;[66]+2 (if not taken) STX Temp2 ;[68]+3 store new X value in 'Temp2' NOP ;[71]+2 JMP ScanLoop ;[73]+3 = 76 cycles Bypass ; This is the end of the main display loop. Now we need to clear the playfield ; and playfield registers and reset the first player graphic to get ready to ; display the 31 lines which comprise the alphanumerical status area at the ; bottom of the screen. STA WSYNC LDA #0 STA GRP0 STA GRP1 STA PF0 STA PF1 STA PF2 STA COLUBK STA ENABL STA REFP0 LDA #$80 STA COLUPF LDA #%00000001 STA NUSIZ0 STA NUSIZ1 LDX #$FF ; Restore the stack pointer TXS ; Get score digit memory offset values LDA P1Score AND #15 TAX LDA DigitLookup,X STA TempAddr2 LDA P1Score STA RESP0 STA RESP1 LSR LSR LSR LSR TAX LDA DigitLookup,X STA TempAddr1 LDA P2Score AND #15 TAX LDA DigitLookup,X STA TempAddr4 LDA P2Score LSR LSR LSR LSR TAX LDA DigitLookup,X STA TempAddr3 ; Here are the final display loops - they handle the alphanumerical status area ; at the bottom of the screen ; Draw the player health meters LDY #7 ;[82]+4 Bottom1 STA WSYNC LDA #%00110010 ;[0]+2 STA COLUP0 ;[2]+3 STA COLUP1 ;[5]+3 LDA (TempAddr1),Y ;[8]+5 STA GRP0 ;[12]+3 LDA (TempAddr2),Y ;[15]+5 STA GRP1 ;[20]+3 STA RESP0 ;[23]+3 STA RESP1 ;[26]+3 LDA (TempAddr3),Y ;[29]+5 STA GRP0 ;[34]+3 LDA (TempAddr4),Y ;[37]+5 STA GRP1 ;[42]+3 LDA #%11000100 ;[45]+2 NOP ;[47]+2 STA RESP0 ;[49]+3 STA RESP1 ;[52]+3 STA COLUP0 ;[55]+3 STA COLUP1 ;[58]+3 DEY ;[61]+2 CPY #-1 ;[63]+2 BNE Bottom1 ;[65]+3 = 68 (if taken) LDX #0 STX GRP0 STX GRP1 ; Check if we're in 'select' mode...if not, business as usual, otherwise we have to ; display the logo instead. BIT Status BVC DisplayEPW NoDisplay STA WSYNC INX CPX #13 BNE NoDisplay LDA P2Power ; We use 'P2Power' as a timer in select mode CMP #128 BNE LoadTemp INC P1Power ; We use 'P1Power' as a counter in select mode LoadTemp LDA P1Power AND #%00001111 TAX CLC ADC #8 AND #%00001111 STA Temp2 DoLogo STA WSYNC LDA #0 STA PF0 LDA Logo1,X STA PF1 LDA Logo2,X STA PF2 NOP NOP NOP NOP LDA Logo3,X STA PF0 LDA Logo4,X STA PF1 LDA Logo5,X STA PF2 INX TXA AND #%00001111 TAX CPX Temp2 BNE DoLogo LDA P2Power CLC ADC #8 STA P2Power ; Increment the timer ('P2Power') STA WSYNC LDA #0 STA PF0 STA PF1 STA PF2 STA WSYNC JMP EndEPW DisplayEPW ; Now we need to set things up to get ready to display the 'E P W' line STA WSYNC LDA #%00000001 STA CTRLPF LDA #%00001111 STA PF1 LDA #%11111111 STA PF2 STA WSYNC LDA #%00000110 STA NUSIZ0 LDA #%00001000 STA PF1 LDA #0 STA PF2 LDA #$1B TAX NOP JSR Waste12Cycles STA RESP0 LDY #7 Bottom2 STX COLUP0 STA WSYNC LDA LetterE,Y ;[]+5 STA GRP0 ;[]+3 DEX NOP JSR Waste12Cycles JSR Waste12Cycles NOP LDA LetterP,Y ;[]+5 STA GRP0 ;[]+3 NOP NOP NOP LDA LetterW,Y ;[]+5 STA GRP0 ;[]+3 DEY ;[]+2 CPY #-1 ;[]+2 BNE Bottom2 STA WSYNC LDA #%00000110 STA NUSIZ1 LDA #0 STA GRP0 STA GRP1 JSR Waste12Cycles NOP NOP NOP STA RESP0 STA RESP1 ; Get score digit memory offset values LDA Status ROR BCS DisplayP2Elevation ; If it's player 2's turn, we need to load P2 elevation LDA P1Elevation JMP EndDisplayP2Elevation DisplayP2Elevation LDA P2Elevation EndDisplayP2Elevation TAY AND #15 TAX LDA DigitLookup,X STA TempAddr2 TYA LSR LSR LSR LSR TAX LDA DigitLookup,X STA TempAddr1 LDA Status ROR BCS DisplayP2Power ; If it's player 2's turn, we need to load P2 power LDA P1Power JMP EndDisplayP2Power DisplayP2Power LDA P2Power EndDisplayP2Power TAY AND #15 TAX LDA DigitLookup,X STA TempAddr4 TYA LSR LSR LSR LSR TAX LDA DigitLookup,X STA TempAddr3 LDA Wind ; Get the wind sign value LSR LSR LSR LSR CLC ADC #10 TAX LDA DigitLookup,X STA TempAddr5 LDA Wind AND #15 STA Temp2 LDA Wind AND #16 BNE NoWindAdjustment LDA #16 SEC SBC Temp2 JMP EndNoWindAdjustment NoWindAdjustment LDA Temp2 EndNoWindAdjustment TAX LDA DigitLookup,X STA TempAddr6 ; Adjust the player colors so that the numbers in the display match the player ; whose turn it is LDA Status ROR BCC NotPlayer2Color LDA P1Color ADC #146 BNE EndNotPlayer2Color NotPlayer2Color LDA P1Color EndNotPlayer2Color STA COLUP1 STA COLUP0 LDY #7 Bottom3 STA WSYNC LDA (TempAddr1),Y ;[]+5 STA GRP0 ;[]+3 LDA (TempAddr2),Y STA GRP1 NOP NOP NOP NOP LDA (TempAddr6),Y TAX LDA (TempAddr3),Y STA GRP0 LDA (TempAddr4),Y STA GRP1 LDA (TempAddr5),Y STA GRP0 STX GRP1 DEY BPL Bottom3 ; Take care of the final two lines STA WSYNC LDY #0 STY GRP0 STY GRP1 STA WSYNC LDA #%00001111 STA PF1 LDA #%11111111 STA PF2 EndEPW LDY #0 STY GRP0 STY GRP1 STA WSYNC STY PF0 STY PF1 STY PF2 LDA #%00000010 STA VBLANK ; Make TIA output invisible, also disable joystick latches ; Now we need to worry about it bleeding when we turn ; the TIA output back on. ; Y is still zero. STY GRP0 STY GRP1 STY ENAM0 STY ENAM1 STY ENABL LDY BKColor STY COLUBK LDY PFColor STY COLUPF ; ************************* ; * OVERSCAN CALCULATIONS * ; ************************* OverScan ; Set up the timer LDA #35 STA TIM64T LDA AdditionCycles BNE ShotVectorCalc JMP OverScan2 ; ******************************************** ; * SHOT VECTOR CALCULATION OVERSCAN ROUTINE * ; ******************************************** ShotVectorCalc ; Figure out how many iterations to do this time through LDA AdditionCycles CMP #11 BCS MoreThan10 LDA AdditionCycles STA Temp STA Temp2 LDA #0 STA AdditionCycles BEQ EndMoreThan10 MoreThan10 LDA #10 STA Temp STA Temp2 LDA AdditionCycles ;SEC SBC #10 STA AdditionCycles EndMoreThan10 ; Now we compute the X-vector value LDA ShotElevation TAX TAY INY LDA Temp BEQ EndXTop XTop LDA TrigLookup,Y ;5 CLC ;2 ADC ShotXVelRemRemRem ;3 STA ShotXVelRemRemRem ;3 BCC NoCarry1 ;2 if not taken INC ShotXVelRemRem ;5 BNE NoCarry1 INC ShotXVelRem BNE NoCarry1 INC ShotXVel NoCarry1 LDA TrigLookup,X ;5 CLC ;2 ADC ShotXVelRemRem ;3 STA ShotXVelRemRem ;3 BCC NoCarry2 ;2 if not taken INC ShotXVelRem ;5 BNE NoCarry2 ;2 INC ShotXVel ;5 NoCarry2 DEC Temp ;5 LDA Temp ;3 BNE XTop ;3 EndXTop ; Now we compute the Y-vector value LDA #180 SEC SBC ShotElevation TAX TAY INY LDA Temp2 BEQ EndYTop YTop LDA TrigLookup,Y CLC ADC ShotYVelRemRemRem STA ShotYVelRemRemRem BCC NoCarry1b INC ShotYVelRemRem BNE NoCarry1b INC ShotYVelRem BNE NoCarry1b INC ShotYVel NoCarry1b LDA TrigLookup,X CLC ADC ShotYVelRemRem STA ShotYVelRemRem BCC NoCarry2b INC ShotYVelRem BNE NoCarry2b INC ShotYVel NoCarry2b DEC Temp2 LDA Temp2 BNE YTop EndYTop LDA AdditionCycles BNE NoVectorAdjust LDX #2 NoCarry3 ASL ShotXVelRemRemRem ROL ShotXVelRemRem ROL ShotXVelRem ROL ShotXVel DEX BNE NoCarry3 LDX #3 NoCarry3b ASL ShotYVelRemRemRem ROL ShotYVelRemRem ROL ShotYVelRem ROL ShotYVel DEX BNE NoCarry3b LDA #0 STA ShotXPosRemRem STA ShotYPosRemRem NoVectorAdjust JMP NotEndYet ; *************************** ; * NORMAL OVERSCAN ROUTINE * ; *************************** OverScan2 ; Make the tanks fall if they're not touching the ground LDA #%10000000 TAY AND CXP1FB BNE Player1HasLanded INC P1YPos Player1HasLanded TYA AND CXP0FB BNE Player2HasLanded INC P2YPos Player2HasLanded ; Now we need to check to see if there's a shot in the air, and if so, ; whether it has collided with the ground or not LDA Status AND #%00000010 ; Check to see if there is a shot in the air BEQ JumpToNoGround LDA #0 STA AUDV0 STA AUDV1 LDA ShotYPosScrn BEQ NoYMinusOneCheck LDA ShotYPos CMP #255 BNE JumpToNoGround NoYMinusOneCheck TYA AND CXBLPF BNE NoJumpToNoGround LDA ShotYPos BMI JumpToNoGround CMP #119 BCS NoJumpToNoGround JumpToNoGround JMP NoGround NoJumpToNoGround ; COMPUTER AI - SHOT ELEVATION ADJUSTMENT ; If player 2 fired and this is a one player game, we need to adjust the computer's shot power and elevation LDA Status2 ROR BCS NoComputerShotAdjust LDA Status ROR BCC NoComputerShotAdjust LDA P2Elevation ; If we're already using a high angle, nothing to do CMP #$67 BEQ NoAngleAdjust LDA Status AND #%00001000 ; If the shot was going up when impact occured, BNE AdjustAngle ; we use a high elevation LDA ShotYPos BPL NoNegativeShotAdjust LDA #0 ; If shot Y pos is negative, that means it's in the area above the top of the terrain, just use 0 NoNegativeShotAdjust ; for the purposes of the comparison with the player's Y position STA Temp CMP P1YPos BCS NoAngleAdjust ; If the shot landed below the player, no angle adjustment needed LDA P1YPos SEC SBC Temp ; Otherwise, compare the shot Y position with the player Y position CMP #40 ; See if the shot is 40+ pixels above the player - if so, use high angle BCC NoAngleAdjust AdjustAngle LDA P2Power JSR BCDToBinary STA Temp2 LDA P1YPos ; Is P1 lower than P2? CMP P2YPos BCC Use316ths SEC SBC P2YPos CMP #40 BCC Use316ths LDA Temp2 LSR LSR LSR CLC ADC Temp2 ; P2Power = P2Power + P2Power * (1/8) STA Temp2 Use316ths LSR LSR LSR STA Temp LSR CLC ADC Temp CLC ADC Temp2 ; P2Power = P2Power + P2Power * (3/16) EndUse316ths JSR BinaryToBCD STA P2Power LDA #$67 STA P2Elevation NoAngleAdjust LDA Status AND #%00001000 ; If the shot was going up when impact occured, BNE NoComputerShotAdjust ; then don't increase power! ; If the shot went over, increase power, otherwise decrease LDA Status2 AND #%00011000 CMP #24 SED BNE Undershot Overshot LDA P2Power SEC SBC #2 BCS DoAdjustment Undershot LDA P2Power CLC ADC #2 DoAdjustment STA P2Power CLD NoComputerShotAdjust LDA Status2 AND #%11100111 ; Turn off the shot has passed P1 and shot went under/over P1 bits STA Status2 LDA P2Power CMP #$99 BCC NoP2PowerOverMax LDA #$99 STA P2Power NoP2PowerOverMax LDA Status AND #%11101101 STA Status ROR BCC ChangeTurnToP2 LDA Status AND #%11111110 STA Status ;LDA Wind ; Save the old wind value if this was player 2's turn - we will ;STA OldWind ; need this for computer AI calculations (assuming 1 player game) JMP EndChangeTurnToP2 ChangeTurnToP2 LDA Status ORA #%00000001 STA Status EndChangeTurnToP2 ; Do the terrain damage LDA #2 STA Temp2 LDA #121 SEC SBC ShotYPosActual Again LSR ; Divide shot y position by 8 LSR LSR TAX CPX #14 BCS EndTerrainDamage ; Skip doing damage if y >= 14 (bottom of screen) LDA ShotXPosActual ; Divide shot x position by 4 LSR LSR TAY LDA PFDamageIndex,Y CPY #4 BCS PF1aDamage AND PField0,X STA PField0,X BCC EndTerrainDamage PF1aDamage CPY #12 BCS PF2aDamage AND PField1A,X STA PField1A,X BCC EndTerrainDamage PF2aDamage CPY #20 BCS PF0Damage AND PField2A,X STA PField2A,X BCC EndTerrainDamage PF0Damage CPY #24 BCS PF1bDamage AND PField0,X STA PField0,X BCC EndTerrainDamage PF1bDamage CPY #32 BCS PF2bDamage AND PField1B,X STA PField1B,X BCC EndTerrainDamage PF2bDamage CPY #40 BCS EndTerrainDamage AND PField2B,X STA PField2B,X EndTerrainDamage DEC Temp2 BEQ NotAgain LDA #122 SEC SBC ShotYPosActual JMP Again NotAgain ; Adjust the wind value JSR RandomBit JSR RandomBit LDA rand1 AND #%00000011 STA Temp2 JSR RandomBit LDA rand1 ROR BCS SubtractWind LDA Wind CLC ADC Temp2 CMP #25 BCC SubtractWindEnd LDA #24 BNE SubtractWindEnd SubtractWind LDA Wind SEC SBC Temp2 CMP #8 BCS SubtractWindEnd LDA #8 SubtractWindEnd STA Wind LDA #-42 STA ShotYPos JMP NoShot ; The shot is still in the air (or else there is no shot) NoGround ; Check to see if shot has passed over P1 yet. This is really only for the computer AI when ; playing a one player game LDA Status ROR BCC CheckShotHit LDA Status2 ROR BCS CheckShotHit LDA P1XPos ; Get X Position of player 1 CLC ADC #4 CMP ShotXPosActual BCC CheckShotHit ; Check to see if shot is right over player 1 or not SEC SBC #4 CMP ShotXPosActual BCS CheckShotHit LDA Status2 ; Record that the shot passed player 1's X position ORA #%00001000 STA Status2 LDA ShotYPosScrn ; The shot definitely went over if it's off the screen :) BNE ShotWentOver LDA #121 SEC SBC ShotYPosActual CMP #216 BCS ShotWentOver ; The shot also definitely went over it it's -40 < YPos < 0 CMP P1YPos BCC ShotWentOver ShotWentUnder LDA Status2 ; Record that the shot went under player 1 AND #%11101111 STA Status2 BNE CheckShotHit ShotWentOver LDA Status2 ; Record that the shot went over player 1 ORA #%00010000 STA Status2 ; Check to see if shot has hit the opposing player CheckShotHit LDA ShotYPosActual CMP #131 BCS NoShot LDA Status ROR BCS CheckShotP2Collision LDA CXP0FB JMP EndCheckShotP2Collision CheckShotP2Collision LDA CXP1FB EndCheckShotP2Collision AND #%01000000 BEQ NoShot LDA Status AND #%11101101 STA Status LDA #-42 STA ShotYPos SED CLC LDA Status AND #%00000001 BNE IncP2Score LDA P1Score ADC #1 STA P1Score JMP EndIncP2Score IncP2Score LDA P2Score ADC #1 STA P2Score EndIncP2Score CLD LDA Status ORA #%10000000 STA Status JMP NotEndYet NoShot ; Here is where we determine if the current player has fired. This can ; only happen if the player whose turn it is fires, and if there isn't already ; a shot in the air. Assuming everything's OK, we then need to set things up. LDA Status AND #%01000010 ; Check if we're in select mode or a shot is already in the air. BNE EndButtonChecks ; and if so, don't bother checking the buttons at all BIT CXP1FB BPL EndButtonChecks ; Cant fire if player 1 is in the air DontCheckP1YPos BIT CXP0FB BPL EndButtonChecks ; Cant fire if player 2 is in the air DontCheckP2YPos LDA Status ROR BCS CheckPlayer2Button CheckPlayer1Button LDA INPT4 BMI EndButtonChecks ; If joystick 1's button isn't being pressed, no shot BPL ShotFired CheckPlayer2Button LDA Status2 ROR BCC ShotFired ;BCS CheckHumanPlayer2Button ; If it's a one player game and player 2's turn, need to do some wind adjustments first ; COMPUTER AI - SHOT POWER WIND ADJUSTMENT ; Adjust the shot power now value based on wind change since the last time the computer fired ;LDA Wind ;SEC ;SBC OldWind ;STA Temp ;LDA P2Elevation ;CMP #$67 ;BNE UseLowElevationWind ;LDA Temp ;ASL ;STA Temp ;JMP NoLowElevationWind UseLowElevationWind ;LDA Temp ;ASL ;LDA Temp ;ROR ;STA Temp NoLowElevationWind ;LDA P2Power ;JSR BCDToBinary ;CLC ;ADC Temp ;JSR BinaryToBCD ;STA P2Power ;LDA P2Power ;CMP #$99 ;BCC ShotFired ;LDA #$99 ;STA P2Power ;JMP ShotFired CheckHumanPlayer2Button LDA INPT5 BMI EndButtonChecks ; If joystick 2's button isn't being pressed, no shot BPL ShotFired EndButtonChecks JMP EndButtonCheck ShotFired ; A shot has been fired by the active player. We must now change the status, ; compute starting values for the shot, and compute X and Y shot velocities LDA #%00000010 ; Activate the 'shot fired' sound effect STA AUDC0 LDA #%00000111 STA AUDF0 LDA #%00000111 STA AUDV0 LDA #%00001010 ORA Status STA Status ; Change status to indicate a shot in the air ROR BCS SetShotToP2YPos LDA P1YPos ; Set Y position of shot JMP EndSetShotToP2YPos SetShotToP2YPos LDA P2YPos EndSetShotToP2YPos SEC SBC #7 STA ShotYPos LDY #0 ;STY ShotXPos STY ShotYPosScrn LDA ShotYPos BPL ShotYPosIsntNegative INC ShotYPosScrn LDA #%00010000 ; The shot has wrapped off the top of the screen ORA Status STA Status ShotYPosIsntNegative ; Figure out starting X pixel coordinate of the shot LDA Status AND #%00000001 BNE UsePlayer2PosForShot LDA P1XPos CLC ADC #4 JMP EndUsePlayer2PosForShot UsePlayer2PosForShot LDA P2XPos CLC ADC #3 EndUsePlayer2PosForShot STA ShotXPosActual ; COMPUTER AI - SHOT CALCULATION LDA Status2 AND #%00000011 BNE NoComputerShotCalc ; If the 'calculated computer shot power' bit is set to '1', or ; this isn't a one player game then...we don't calculate computer shot power! LDA Status ROR BCC NoComputerShotCalc ; If it isn't player 2's turn, don't do this part yet TYA LDA P1XPos ; Compute X position for player 1 (the human opponent) STA Temp2 ; Store human player's X position in blocks LDA ShotXPosActual SEC SBC Temp2 LSR LSR STA Temp2 ; Store X distance to human player, in blocks, into Temp2 LDA P1YPos LSR LSR LSR STA Temp LDA P2YPos ; Compute difference in Y positions, in blocks LSR LSR LSR SEC SBC Temp STA Temp BPL NoYValueAdjust ; If the Y difference is negative, halve it LSR ORA #%10000000 NoYValueAdjust CLC ADC Temp2 ; Add this difference to the X difference TAX BPL NoLowerBoundAdjust TYA BEQ NoUpperBoundAdjust NoLowerBoundAdjust CMP #41 BCC NoUpperBoundAdjust LDA #40 NoUpperBoundAdjust TAX LDA PowerLookup,X STA P2Power LDA Status2 ; Turn on the 'calculated computer shot power' bit ORA #%00000010 AND #%11100111 ; Turn off the shot has passed P1 and shot went under/over P1 bits STA Status2 LDA Temp ; Set elevation high if the player tank is far above the computer's BMI NoComputerShotCalc CMP #8 BCC NoComputerShotCalc LDA #$67 STA P2Elevation LDA P2Power JSR BCDToBinary STA Temp2 LSR LSR LSR CLC ADC Temp2 ; P2Power = P2Power + (1/8)P2Power JSR BinaryToBCD STA P2Power NoComputerShotCalc ; Compute the power and store it in 'AdditionCycles' LDA Status ROR BCS P2Fired LDA P1Power JMP EndP2Fired P2Fired LDA P2Power EndP2Fired JSR BCDToBinary STA AdditionCycles ; Compute the elevation and store it in 'ShotElevation' LDA Status ROR BCS P2FiredB LDA P1Elevation JMP EndP2FiredB P2FiredB LDA P2Elevation EndP2FiredB JSR BCDToBinary ASL STA ShotElevation ; Now we reinitialize the X and Y velocity vectors LDA #0 STA ShotYVel STA ShotYVelRem STA ShotYVelRemRem STA ShotYVelRemRemRem STA ShotXVel STA ShotXVelRem STA ShotXVelRemRem STA ShotXVelRemRemRem ; Now we have to position the shot to the correct horizontal on-screen location. LDA ShotXPosActual LDX #4 JSR PositionSprite JMP NotEndYet EndButtonCheck ; Now we need to check the player joysticks, assuming there's no shot ; in the air, and we're on the correct frame, and not in select mode. SED LDA Status AND #%01000110 BEQ CheckJoysticks JMP EndCheckPlayer CheckJoysticks LDA #%00000001 ; Set 'joystick noise' sound tone STA AUDC0 STA AUDC1 LDY SWCHA LDA Status ROR BCS CheckPlayerTwoStick LDX #0 STX Temp TYA LSR LSR LSR LSR TAY JMP EndCheckPlayerTwoStick CheckPlayerTwoStick LDX #1 STX Temp EndCheckPlayerTwoStick TYA ROR BCS NoPlayerUp LDA P1Elevation,X CMP #$90 BEQ CheckPlayerLeftRight LDA P1Elevation,X ADC #1 STA P1Elevation,X LDX #0 JSR JoystickHighSound LDX Temp BCC CheckPlayerLeftRight NoPlayerUp TYA AND #%00000010 BNE NoPlayerUpOrDown LDA P1Elevation,X BEQ CheckPlayerLeftRight SEC SBC #1 STA P1Elevation,X LDX #0 JSR JoystickLowSound LDX Temp BCS CheckPlayerLeftRight NoPlayerUpOrDown LDA #0 STA AUDV0 CheckPlayerLeftRight TYA AND #%00000100 BNE NoPlayerLeft LDA P1Power,X BEQ EndCheckPlayer SEC SBC #1 STA P1Power,X LDX #1 JSR JoystickLowSound BCS EndCheckPlayer NoPlayerLeft TYA AND #%00001000 BNE NoPlayerLeftOrRight LDA P1Power,X CMP #$99 BEQ EndCheckPlayer ADC #1 STA P1Power,X LDX #1 JSR JoystickHighSound BCC EndCheckPlayer NoPlayerLeftOrRight LDA #0 STA AUDV1 EndCheckPlayer CLD NotEndYet LDA INTIM BNE NotEndYet STA WSYNC JMP VerticalBlank ; the mother of all jumps :) ; *************** ; * SUBROUTINES * ; *************** ; RANDOM BYTE GENERATION SUBROUTINE RandomByte LDX #8 ;[0]+2 RandomByte1 JSR RandomBit ;[2]+6+27 = 35 DEX ;[35]+2 BNE RandomByte1 ;[37]+3 = 40 ;40*8 - 1 = 319 LDA rand1 ;[319]+3 RTS ;[322]+6 = 328 ; JOYSTICK LOW SOUND SUBROUTINE (high sound subroutine is down a ways buried in some data) JoystickLowSound LDA #%00010000 STA AUDF0,X LDA #%00000010 STA AUDV0,X RTS ; BCD-TO-BINARY SUBROUTINE BCDToBinary TAX AND #%11110000 LSR LSR LSR LSR STA Temp2 LDY #9 MultTimes10b CLC ADC Temp2 DEY BNE MultTimes10b STA Temp2 TXA AND #%00001111 CLC ADC Temp2 Waste12Cycles ; This RTS is also used to waste cycles in other RTS ; parts of the program ; BINARY-TO-BCD SUBROUTINE BinaryToBCD LDY #-1 DivBy10 INY SEC SBC #10 BCS DivBy10 CLC ADC #10 STA Temp2 TYA ASL ASL ASL ASL CLC ADC Temp2 RTS ; GRAPHICS DELAY SUBROUTINES GraphicsDelay LDA INTIM BNE GraphicsDelay ; Wait for the 192 line drawing period to end STA WSYNC LDA #36 STA TIM64T ; Synchronize the timer for the 30 line overscan period GraphicsDelay2 LDA INTIM BNE GraphicsDelay2 ; Wait for the 30 line overscan period to end LDA #2 STA VSYNC ; Begin vertical sync. STA WSYNC ; First line of VSYNC STA WSYNC ; Second line of VSYNC. LDA #45 STA TIM64T STA WSYNC ; Third line of VSYNC. STA VSYNC GraphicsDelay3 LDA INTIM BNE GraphicsDelay3 ; Wait for the vertical blank period to end STA WSYNC LDA #229 STA TIM64T ; Synchronize the timer for the 192 line drawing period RTS ; SPRITE POSITIONING SUBROUTINE PositionSprite ; Set the horizontal position of the sprite ldy #1 ; fudged start offset ; Count 15-pixel loops sec CountX sbc #15 iny bcs CountX ; Use remainder for fine adjustment eor #15 sbc #7 ; -8 to +7 asl asl asl asl sta HMCLR ; clear any previous movement sta HMP0,x ; fine movement sta WSYNC LDA #0 STA GRP1 Jiggle dey bpl Jiggle nop sta RESP0,x sta WSYNC sta HMOVE NOP NOP LDA #132 ;2 CMP ShotYPosActual ;3 BNE DontShowShot ;2 LDA #%00000010 BNE EndDontShowShot DontShowShot LDA #%00000000 ;2 EndDontShowShot STA ENABL ;3 TXA ;2 CMP #2 ;2 BCS UseBallOffset ;2 lda #%01100000 BNE EndUseBallOffset UseBallOffset lda #%01010000 ;2 EndUseBallOffset sta HMP0,X sta WSYNC sta HMOVE WasteTime RTS ;Number0 ;Number1 ;Number2 ;Number3 ;Number4 ;Number5 ;Number6 ;Number7 ;Number8 ;Number9 ;ArrowLeft ;ArrowRight ;LetterE ;LetterP ;LetterW ;DigitLookup ;Logo1 ;Logo2 ;Logo3 ;Logo4 ;Logo5 ;PFColor ;BKColor ;P1Color ;TrigLookup ;PlayerData ;SunGraphic ;PFDamageIndex ;ShotXPosLookup ;RandomBit ;JoystickHighSound ;CloudColor ; *********************************** ; * LOOKUP TABLES AND GRAPHICS DATA * ; *********************************** PowerLookup .byte #$0 ; X difference = 0 blocks .byte #$11 .byte #$16 .byte #$20 .byte #$23 .byte #$25 ; X difference = 5 blocks .byte #$28 .byte #$30 .byte #$32 .byte #$34 .byte #$36 ; X difference = 10 blocks .byte #$38 .byte #$39 .byte #$41 .byte #$42 .byte #$44 ; X difference = 15 blocks .byte #$45 .byte #$47 .byte #$48 .byte #$49 .byte #$51 ; X difference = 20 blocks .byte #$52 .byte #$53 .byte #$54 .byte #$55 .byte #$57 ; X difference = 25 blocks .byte #$58 .byte #$59 .byte #$60 .byte #$61 .byte #$62 ; X difference = 30 blocks .byte #$63 .byte #$64 .byte #$65 .byte #$66 .byte #$67 ; X difference = 35 blocks .byte #$68 .byte #$69 .byte #$70 .byte #$71 .byte #$72 ; X difference = 40 blocks CloudData .byte %00000000 .byte %00000000 .byte %00000000 .byte %00000000 .byte %01111110 .byte %11111111 .byte %11111111 .byte %11111111 .byte %01111111 .byte %01110110 .byte %00101110 .byte %00000100 org $FD00 ; Numerical Graphics Data, etc. Number0 .byte #%01111000 .byte #%11001100 .byte #%11000110 .byte #%11000010 .byte #%01000011 .byte #%01100011 .byte #%00110011 .byte #%00011110 Number1 .byte #%01111000 .byte #%00110000 .byte #%00110000 .byte #%00011000 .byte #%00011000 .byte #%00011000 .byte #%00111100 .byte #%00001100 Number2 .byte #%11111100 .byte #%01000110 .byte #%00100000 .byte #%00011000 .byte #%00000110 .byte #%00000011 .byte #%00110011 .byte #%00011110 Number3 .byte #%01111100 .byte #%11001110 .byte #%00000110 .byte #%00000110 .byte #%00011100 .byte #%00000011 .byte #%00110011 .byte #%00011110 Number4 .byte #%00011110 .byte #%00001100 .byte #%00001100 .byte #%11111110 .byte #%01100110 .byte #%01100110 .byte #%00110011 .byte #%00110011 Number5 .byte #%01111100 .byte #%11001110 .byte #%00000110 .byte #%00000110 .byte #%01111100 .byte #%01100000 .byte #%00110011 .byte #%00111111 Number6 .byte #%01111100 .byte #%11001110 .byte #%11000110 .byte #%11000110 .byte #%01111100 .byte #%01100000 .byte #%00110011 .byte #%00011110 Number7 .byte #%01111000 .byte #%00110000 .byte #%00011000 .byte #%00001100 .byte #%00001100 .byte #%00000110 .byte #%00110011 .byte #%00111111 Number8 .byte #%01111100 .byte #%11001110 .byte #%11000110 .byte #%01100110 .byte #%00011100 .byte #%00110011 .byte #%00110011 .byte #%00011110 Number9 .byte #%01111100 .byte #%11000110 .byte #%00000110 .byte #%00011110 .byte #%00110011 .byte #%00110011 .byte #%00110011 .byte #%00011110 ArrowLeft .byte #%00000000 .byte #%00010000 .byte #%00110000 .byte #%01111111 .byte #%01111111 .byte #%00011000 .byte #%00001000 .byte #%00000000 ArrowRight .byte #%00000000 .byte #%00001000 .byte #%00001100 .byte #%01111111 .byte #%01111111 .byte #%00000110 .byte #%00000100 .byte #%00000000 LetterE .byte #%11111100 .byte #%11000110 .byte #%01100000 .byte #%01100000 .byte #%01111100 .byte #%00110000 .byte #%00110011 .byte #%00111111 LetterP .byte #%11000000 .byte #%11000000 .byte #%01100000 .byte #%01100000 .byte #%01111100 .byte #%00110011 .byte #%00110011 .byte #%00111110 LetterW .byte #%11001100 .byte #%11101100 .byte #%11011110 .byte #%01001010 .byte #%01000010 .byte #%01100011 .byte #%01100011 .byte #%01100011 DigitLookup .byte #0 .byte #8 .byte #16 .byte #24 .byte #32 .byte #40 .byte #48 .byte #56 .byte #64 .byte #72 .byte #80 .byte #88 ;.byte #96 ;.byte #104 ;.byte #112 ;.byte #120 Logo1 .byte #%00000000 .byte #%01000000 .byte #%01011000 .byte #%01010101 .byte #%01010101 .byte #%01010101 .byte #%01010100 .byte #%00000000 .byte #%00000000 .byte #%01111001 .byte #%10000100 .byte #%10110101 .byte #%10100101 .byte #%10110101 .byte #%10000101 .byte #%01111000 Logo2 .byte #%00000000 .byte #%00000000 .byte #%00010001 .byte #%10101010 .byte #%10101000 .byte #%10101010 .byte #%10010001 .byte #%00000000 .byte #%00000000 .byte #%00010011 .byte #%10101010 .byte #%10101011 .byte #%10101000 .byte #%10101000 .byte #%00010011 .byte #%00000000 Logo3 .byte #%00000000 .byte #%00000000 .byte #%01010000 .byte #%10100000 .byte #%10100000 .byte #%10100000 .byte #%10100000 .byte #%00000000 .byte #%00000000 .byte #%10010000 .byte #%10100000 .byte #%10100000 .byte #%10100000 .byte #%10100000 .byte #%10010000 .byte #%00000000 Logo4 .byte #%00000000 .byte #%00000000 .byte #%01011001 .byte #%01010100 .byte #%01010100 .byte #%01010101 .byte #%01010100 .byte #%00000000 .byte #%00000000 .byte #%11001100 .byte #%01001010 .byte #%11001100 .byte #%01001010 .byte #%01001010 .byte #%11001100 .byte #%00000000 Logo5 .byte #%00000000 .byte #%00001001 .byte #%00001010 .byte #%00001011 .byte #%00001010 .byte #%00000010 .byte #%00001001 .byte #%00000000 .byte #%00000000 .byte #%00001011 .byte #%00001001 .byte #%00001011 .byte #%00001001 .byte #%00001001 .byte #%00011011 .byte #%00000000 PFDamageIndex ; The basic screen layout is like this: ; ; PField0| PField1a | PField2a |PField0| PField1b | PField2b ; 4 5 6 7|7 6 5 4 3 2 1 0|0 1 2 3 4 5 6 7|0 1 2 3|7 6 5 4 3 2 1 0|0 1 2 3 4 5 6 7 .byte #%11101111 .byte #%11011111 .byte #%10111111 .byte #%01111111 .byte #%01111111 .byte #%10111111 .byte #%11011111 .byte #%11101111 .byte #%11110111 .byte #%11111011 .byte #%11111101 .byte #%11111110 .byte #%11111110 .byte #%11111101 .byte #%11111011 .byte #%11110111 .byte #%11101111 .byte #%11011111 .byte #%10111111 .byte #%01111111 .byte #%11111110 .byte #%11111101 .byte #%11111011 .byte #%11110111 .byte #%01111111 .byte #%10111111 .byte #%11011111 .byte #%11101111 .byte #%11110111 .byte #%11111011 .byte #%11111101 .byte #%11111110 .byte #%11111110 .byte #%11111101 .byte #%11111011 .byte #%11110111 .byte #%11101111 .byte #%11011111 .byte #%10111111 .byte #%01111111 org $FE00 ; Player data .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 PlayerData .byte %01111110 .byte %10101011 .byte %11111111 .byte %01111110 .byte %00111000 .byte %00111000 .byte %00111100 .byte %00001010 .byte %00000100 .byte %00000000 .byte $00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;SunGraphic ; .byte %00111100 ; .byte %01111110 ; .byte %01111110 ; .byte %11111111 ; .byte %11111111 ; .byte %11111111 ; .byte %11111111 ; .byte %01111110 ; .byte %01111110 ; .byte %00111100 ; JOYSTICK HIGH SOUND SUBROUTINE JoystickHighSound LDA #%00001110 STA AUDF0,X LDA #%00000010 STA AUDV0,X RTS org $FF00 CloudColor .byte %01100110 .byte %01101000 .byte %01101100 .byte %01101100 .byte %01101100 .byte %01101100 .byte %01101100 .byte %01101100 PFColor ; Playfield colors .byte $2C,$2A,$2A,$28,$28,$26,$26,$26,$24,$24,$24,$22,$22,$22,$22,$22 BKColor ; Background colors .byte $80,$82,$82,$82,$82,$84,$84,$84,$86,$86,$88,$8A,$8C,$8E,$8E,$8E P1Color .byte #%00110010 TrigLookup ; Trigonometric lookup values for shot vector calculations - each ; corresponds to the X component of a .byte #255,#0 ; 0 degrees .byte #254,#245 .byte #254,#215 .byte #254,#165 .byte #254,#96 .byte #254,#8 ; 5 degrees .byte #253,#153 .byte #253,#25 .byte #252,#132 .byte #251,#219 .byte #251,#32 ; 10 degrees .byte #250,#80 .byte #249,#109 .byte #248,#118 .byte #247,#108 .byte #246,#79 ; 15 degrees .byte #245,#31 .byte #243,#219 .byte #242,#132 .byte #241,#27 .byte #239,#159 ; 20 degrees .byte #238,#16 .byte #236,#110 .byte #234,#186 .byte #232,#243 .byte #231 ; 25 degrees .byte #28 .byte #229,#49 .byte #227,#53 .byte #225,#39 .byte #223,#7 .byte #220,#213 ; 30 degrees .byte #218,#147 .byte #216,#64 .byte #213,#220 .byte #211,#103 .byte #208,#225 ; 35 degrees .byte #206,#76 .byte #203,#166 .byte #200,#240 .byte #198,#44 .byte #195,#87 ; 40 degrees .byte #192,#115 .byte #189,#128 .byte #186,#126 .byte #183,#110 .byte #180,#80 ; 45 degrees .byte #177,#35 .byte #173,#232 .byte #170,#160 .byte #167,#75 .byte #163,#232 ; 50 degrees .byte #160,#122 .byte #156,#253 .byte #153,#118 .byte #149,#226 .byte #146,#67 ; 55 degrees .byte #142,#152 .byte #138,#225 .byte #135,#33 .byte #131,#85 .byte #127,#128 ; 60 degrees .byte #123,#160 .byte #119,#182 .byte #115,#195 .byte #111,#200 .byte #107,#196 ; 65 degrees .byte #103,#183 .byte #99,#162 .byte #95,#134 .byte #91,#98 .byte #87,#55 ; 70 degrees .byte #83,#5 .byte #78,#204 .byte #74,#141 .byte #70,#73 .byte #65,#255 ; 75 degrees .byte #61,#176 .byte #57,#92 .byte #53,#4 .byte #48,#167 .byte #44,#71 ; 80 degrees .byte #39,#227 .byte #35,#125 .byte #31,#20 .byte #26,#167 .byte #22,#57 ; 85 degrees .byte #17,#201 .byte #13,#88 .byte #8,#229 .byte #4,#115 .byte #0,#0 ; 90 degrees RandomBit LDA rand4 ;[0]+3 ASL ;[3]+2 ASL ;[5]+2 ASL ;[7]+2 EOR rand4 ;[9]+3 new bit is now in bit 6 of A ASL ;[11]+2 ASL ;[11]+2 new bit is now in carry ROL rand1 ;[13]+2 shift new bit into bit 0 of register; bit 7 goes into carry ROL rand2 ;[15]+2 shift old bit 7 into bit 8, etc. ROL rand3 ;[17]+2 ROL rand4 ;[19]+2 RTS ;[21]+6 = 27 org $FFFC .word Start .word Start