; @com.wudsn.ide.asm.mainsourcefile=scorch.asm .IF *>0 ;this is a trick that prevents compiling this file alone ; All main procedures of the game not dependent on hardware (I hope) :) START jsr MakeDarkScreen ; Startup sequence jsr Initialize ;jsr GameOverScreen ; only for test !!! RMTSong song_main_menu jsr Options ;startup screen jsr SetVariablesFromOptions jsr MakeDarkScreen bit escFlag bpl @+ jsr CheckStartKey ; START KEY bne START jmp StartAfterSplash ; reset all game option if Start key pressed (and Esc) @ jsr EnterPlayerNames jsr MakeDarkScreen bit escFlag bmi START jsr RandomizeSequence ; for the round #1 shooting sequence is random MainGameLoop jsr SetWallsType ; first set default barrel lengths (fix for Long Schlong activation :) ) ; we must do it before purchase/activate ; and set Auto Defense to off jsr SetStandardBarrels jsr CallPurchaseForEveryTank jsr MakeDarkScreen bit escFlag bmi START jsr GetRandomWind jsr RoundInit jsr MainRoundLoop mva #$ff MeteorsFlag bit escFlag jvs GoGameOver bmi START jsr CalculateGains jsr SortSequence mva #0 TankNr ; sta COLBAKS ; set background color to black jsr SetJoystickPort ; set joystick port for player ; Hide all (easier than hide last ;) ) tanks jsr cleartanks ; A=0 ; here gains and losses should be displayed (dollars) ; finally we have changed our minds and money of players ; is displayed only in weapons shop ; Results are number of other deaths ; before the player dies itself RmtSong song_round_over jsr DisplayResults jsr DemoModeOrKey jsr MakeDarkScreen lda GameIsOver beq NoGameOverYet GoGameOver jsr GameOverScreen jmp START NoGameOverYet inc CurrentRoundNr mva #sfx_silencer sfx_effect jmp MainGameLoop ;-------------------------------------------------- .proc CalculateGains ;-------------------------------------------------- ; add gains and substract losses ; gain is what player gets for lost energy of opponents ; energy lost by opponents is added during Round and ; little below in source, multiplied by 2 to get "dollars". ; By analogy, loss is energy that given player losses during ; each Round. ; Important! If player has 10 energy and gets a central hit ; from nuke that would take 90 energy points, his loss ; is 90, not 10 ldx NumberOfPlayers dex CalculateGainsLoop ; adding the remaining energy of the tank to gain ; winner gets more ! :) lda Energy,x adc gainL,x sta gainL,x bcc @+ inc gainH,x @ ; add gain * 2 asl gainL,x rol gainH,x clc lda moneyL,x adc gainL,x sta moneyL,x lda moneyH,x adc gainH,x sta moneyH,x ; substract lose ; if lose is greater than money then zero money lda moneyH,x cmp loseH,x bne @+ lda moneyL,x cmp loseL,x @ bcs substractlose zeromoney lda #0 sta moneyL,x sta moneyH,x beq skipzeroing substractlose ; sec ; C is allways set at this point lda moneyL,x sbc loseL,x sta moneyL,x lda moneyH,x sbc loseH,x sta moneyH,x skipzeroing ; and earned money for summary clc lda EarnedMoneyL,x adc gainL,x sta EarnedMoneyL,x lda EarnedMoneyH,x adc gainH,x sta EarnedMoneyH,x ; substract lose ; if lose is greater than money then zero money lda EarnedMoneyH,x cmp loseH,x bne @+ lda EarnedMoneyL,x cmp loseL,x @ bcs esubstractlose ezeromoney lda #0 sta EarnedMoneyL,x sta EarnedMoneyH,x beq eskipzeroing esubstractlose ; sec ; C is allways set at this point lda EarnedMoneyL,x sbc loseL,x sta EarnedMoneyL,x lda EarnedMoneyH,x sbc loseH,x sta EarnedMoneyH,x eskipzeroing dex jpl CalculateGainsLoop ; Team game calculations ; set initial values inx ; now X=0 txa inx ; now X=1 initialTeamsVal sta ResultsTable+MaxPlayers,x sta DirectHits+MaxPlayers,x sta EarnedMoneyH+MaxPlayers,x sta EarnedMoneyL+MaxPlayers,x dex bpl initialTeamsVal ; and now Team scores calculations tax ; now X=0 tay CalculateTeamsResults clc lda ResultsTable+MaxPlayers,y adc ResultsTable,x sta ResultsTable+MaxPlayers,y clc lda DirectHits+MaxPlayers,y adc DirectHits,x sta DirectHits+MaxPlayers,y clc lda EarnedMoneyL+MaxPlayers,y adc EarnedMoneyL,x sta EarnedMoneyL+MaxPlayers,y lda EarnedMoneyH+MaxPlayers,y adc EarnedMoneyH,x sta EarnedMoneyH+MaxPlayers,y tya eor #$01 ; swap team tay inx cpx NumberOfPlayers bne CalculateTeamsResults rts .endp ;-------------------------------------------------- .proc RoundInit ;-------------------------------------------------- ; at the beginning of each Round we set energy ; of all players to 99 ; the maximum shooting energy to 990 (it is 10*energy) ; the default shooting energy to 350 ; the shooting angle is randomized ; of course gains an loses are zeroed RmtSong song_ingame jsr SetPMWidthAndColors ; A=0 lda #0 sta AfterBFGflag ; reset BFG flag sta COLOR2 ; status line "off" sta COLOR1 tax @ sta singleRoundVars,x inx cpx #(singleRoundVarsEnd-singleRoundVars) bne @- ldx #(MaxPlayers-1) SettingEnergies lda #$00 sta gainL,x sta gainH,x sta loseL,x sta loseH,x lda #99 sta Energy,x sta eXistenZ,x sta LASTeXistenZ,x ; anything in eXistenZ table means that this tank exist ; in the given round jsr MaxForceCalculate lda #<350 sta ForceTableL,x lda #>350 sta ForceTableH,x ;lda #(255-45) ;it does not look good when all tanks have ;barrels pointing the same direction ;so it would be nice to have more or less random ;angles jsr RandomizeAngle sta AngleTable,x dex bpl SettingEnergies ; set mountain type if ... lda RandomMountains beq noRandomMountains @ ldy RANDOM cpy #5 bcs @- jsr SetVariablesFromOptions.setMountainsType noRandomMountains ;generating the new landscape jsr PMoutofScreen ;let P/M disappear jsr clearscreen ;let the screen be clean jsr ClearPMmemory jsr placetanks ;let the tanks be evenly placed jsr calculatemountains ;let mountains be easy for the eye ;jsr calculatemountains0 ;only for tests - makes mountains flat and 0 height mwa #StatusBufferROM temp mwa #StatusBufferCopy temp2 mwa #StatusBufferCopyEnd+1 modify jsr CopyFromROM jsr SetMainScreen jsr drawmountains ;draw them jsr drawtanks ;finally draw tanks mva #$00 TankSequencePointer lda random ;lda #$00 ; allways sta MeteorsRound ; Turns meteors on or off during the next round. ;---------round screen is ready--------- mva #TextForegroundColor COLOR1 ; status line "on" rts .endp ;-------------------------------------------------- .proc MainRoundLoop ; here we must check if by a chance there is only one ; tank with energy greater than 0 left ;-------------------------------------------------- ldy #0 ; in Y - number of tanks with energy greater than zero sty ATRACT ; reset atract mode ldx NumberOfPlayers dex CheckingIfRoundIsFinished lda eXistenZ,x beq NoEnergy iny NoEnergy dex bpl CheckingIfRoundIsFinished cpy #2 ; is it less than 2 tanks have energy >0 ? bcc FinishTheRound bit TeamGame bvc NoTeams ; Check if one team is not dead ; check team 1 ldx NumberOfPlayers jsr CheckTeamDead beq FinishTheRound ; check team 2 ldx NumberOfPlayers dex ; for team 2 jsr CheckTeamDead beq FinishTheRound NoTeams jmp DoNotFinishTheRound FinishTheRound ;points for the last living tank(s) ldx NumberOfPlayers dex WhichTankWonLoop lda eXistenZ,x beq CheckNext ; set winning tanks points lda CurrentResult clc adc ResultsTable,x sta ResultsTable,x inc CurrentResult ; this is for honesty (in Team game) :) CheckNext dex bpl WhichTankWonLoop rts DoNotFinishTheRound ; Seppuku here lda noDeathCounter cmp seppukuVal bcc @+ mva #0 noDeathCounter mva #sfx_seppuku sfx_effect jsr DisplaySeppuku jmp Seppuku @ ; Auto Defense - activates defensives ldx NumberOfPlayers dex CheckNextTankAD lda Energy,x ; only active players beq @+ lda AutoDefenseFlag,x ; with Auto Defence activated beq @+ ; run auto defense for tank in X jsr AutoDefense @ dex bpl CheckNextTankAD jsr DrawTanks ; redraw tanks with new defences ; ldx TankSequencePointer lda TankSequence,x sta TankNr tax lda Energy,x ;skip if no energy jeq NextPlayerShoots mva #$ff plot4x4color jsr DisplayTankNameAbove mva #1 color ;to display flying point ldx tankNr lda TankStatusColoursTable,x bit TeamGame bvc NoTeamColors lda TankStatusColoursTableT,x NoTeamColors sta COLOR2 ; set color of status line jsr RandomizeForce.LimitForce jsr PutTankNameOnScreen ; jsr DisplayStatus ; There is no need anymore, it is always after PutTankNameOnScreen lda MeteorsRound bmi @+ ; A = 0 sta MeteorsFlag @ lda SkillTable,x beq ManualShooting RoboTanks ; robotanks shoot here ; TankNr still in X jsr ArtificialIntelligence ; after calliing AI we allways have TankNr in X ;ldx TankNr jsr DisplayStatus ; to make visible AI selected defensive (and offensive :) ) jsr MoveBarrelToNewPosition jsr CheckExitKeys spl:rts ; keys Esc or O jmp AfterManualShooting ManualShooting lda JoyNumber,x jsr SetJoystickPort ; set joystick port for player jsr WaitForKeyRelease lda #%00000000 sta TestFlightFlag ; set "Test Fight" off jsr BeforeFire bit escFlag spl:rts ; keys Esc or O AfterManualShooting ldy #$00 sty plot4x4color dey sty MeteorsFlag ; $ff jsr DisplayTankNameAbove ; defensive weapons without flight handling ldx TankNr lda ActiveDefenceWeapon,x cmp #ind_Hovercraft beq GoFloat cmp #ind_White_Flag ; White Flag beq ShootWhiteFlag cmp #ind_Nuclear_Winter_ bne StandardShoot ShootAtomicWinter ; --- atomic winter --- jsr AtomicWinter jmp NextPlayerShoots ; and we skip shoot ShootWhiteFlag ; --- white flag --- jsr WhiteFlag jsr TankFlying.SoilDownAfterLanding ; Soildown like after Hovercraf landing :) jmp NextPlayerShoots ; and we skip shoot GoFloat jsr TankFlying lda #0 sta ActiveDefenceWeapon,x ; deactivate after use bit escFlag bpl ManualShooting ; after floating tank can shoot rts StandardShoot inc noDeathCounter jsr DecreaseWeaponBeforeShoot jsr DisplayStatus ; ldx TankNr dec Energy,x ; lower energy to eventually let tanks commit suicide ShootNow lda ActiveWeapon,x cmp #ind_Buy_me ; BFG beq WeponNoFlight ; but with explosion cmp #ind_Punch ; Punch beq WeponNoFlight ; but with explosion lda MeteorsRound bmi @+ ; A = 0 sta MeteorsFlag @ jsr Shoot ; bullet flight mva #$ff MeteorsFlag bit escFlag spl:rts ; keys Esc or O lda HitFlag ;0 if missed beq missed bne GoExplosion WeponNoFlight jsr NoShoot ; no bullet flight GoExplosion jsr Explosion continueMainRoundLoopAfterSeppuku mva #sfx_silencer sfx_effect AfterExplode jsr SoilDown ; allways NoFallDown2 ;here tanks are falling down mva tankNr tempor2 ldx NumberOfPlayers dex TanksFallDown stx TankNr lda eXistenZ,x beq NoExistNoFall jsr TankFalls NoExistNoFall dex bpl TanksFallDown mvx tempor2 TankNr missed ldy WeaponDepleted bne @+ ldx TankNr tya sta ActiveWeapon,x @ ;here we clear offensive text (after a shoot) - is cleared !! :) ; ldy TankNr ; jsr DisplayOffensiveTextNr NextPlayerShoots ;before it shoots, the eXistenZ table must be updated ;accordingly to actual energy (was forgotten, sorry to ourselves) ldx #(MaxPlayers-1) SeteXistenZ lda Energy,x sta eXistenZ,x jsr MaxForceCalculate dex bpl SeteXistenZ ;was setup of maximum energy for players PlayersAgain ; In LASTeXistenZ there are values of eXistenZ before shoot ; from the next tank. ; Now it must be checked if by a chance something that had ; LASTeXistenZ>0 is not equal to 0 right now, ; because it means this tank died during this round. ; Most important thing is: ; after each explosion of the tank these operations must be ; performed from the beginning! ; (it is made by another jump into the after explosion routines) ; It is because exploding tank can destroy their neighbours, ; additionally this tank just have had LASTeXistenZ set to 0, ; otherwise it would explode again and again. ; OK, text how to do it is ready, now comes coding . ; Aaaah! - in the main loop we have to set eXistenZ and LASTeXistenZ mva #sfx_next_player sfx_effect ldx NumberOfPlayers dex CheckingPlayersDeath lda LASTeXistenZ,x beq NoPlayerNoDeath lda eXistenZ,x beq PlayerXdeath NoPlayerNoDeath dex bpl CheckingPlayersDeath ; if processor is here it means there are no more explosions inc:lda TankSequencePointer cmp NumberOfPlayers bne NotLastPlayerInRound mva #0 TankSequencePointer lda WindChangeInRound beq NoWindChangeNow jsr GetRandomWind ; wind change after each turn (not round only) NoWindChangeNow NotLastPlayerInRound jmp MainRoundLoop .endp ;--------------------------------- .proc CheckTeamDead ; Optimalisation procedure ; Counts alive in Team ;--------------------------------- dex ldy #0 ; in Y - number of tanks with energy greater than zero CheckingTeam lda eXistenZ,x beq NoEnergy iny NoEnergy dex dex bpl CheckingTeam cpy #0 rts .endp ;--------------------------------- .proc PlayerXdeath ; this tank should not explode anymore: ; there is 0 in A, and Tank Number in X, so... ;--------------------------------- sta LASTeXistenZ,x ; save x somewhere stx TankTempY ;clear NoDeathCounter here sta noDeathCounter mva #sfx_death_begin sfx_effect ; display defensive text here (well, defensive ; is not the real meaning, it should be pre-death, ; but I am too lazy to change names of variables) ; in X there is a number of tank that died lda #talk.VeryFunnyText ; mumber of defensive text after BFG! ("VERY FUNNY.") bit AfterBFGflag ; check BFG flag bmi TextAfterBFG ; if BFG then no points for dead tanks ... lda CurrentResult clc adc ResultsTable,x sta ResultsTable,x ;inc CurrentResult ; RandomizeDeffensiveText randomize talk.NumberOfOffensiveTexts (talk.NumberOfDeffensiveTexts+talk.NumberOfOffensiveTexts-1) TextAfterBFG sta TextNumberOff inc CurrentResult ; ... but increase result of winner (BFG) ldy TankTempY lda #$ff jsr DisplayOffensiveTextNr.notZero ; tank flash ldy TankTempY mva TankNr temp2 ; not elegant, and probably unnecessary sty TankNr jsr FlashTank ; blinking and pausing (like PAUSE 72 - 18x(2+2) ) mva temp2 TankNr ;Deffensive text cleanup ;here we clear Deffensive text (after a shoot) ldy TankTempY jsr DisplayOffensiveTextNr ; calculate position of the explosion (the post-death one) ldx TankTempY clc lda xtankstableL,x adc #4 ; more or less in the middle of the tank sta xdraw lda xtankstableH,x adc #0 sta xdraw+1 sec lda ytankstable,x sbc #4 sta ydraw lda #0 sta ydraw+1 ; there is 0 left in A, so... TODO: bad code above. revisit ;cleanup of the soil fall down ranges (left and right) jsr ClearScreenSoilRange ; We are randomizing the weapon now. ; jumping into the middle of the explosion ; routine MetodOfDeath lda random and #%00011111 ; range 0-31 cmp #(weaponsOfDeathEnd-weaponsOfDeath) ; we have 20 weapons in table (from 0 to 19) bcs MetodOfDeath tay lda weaponsOfDeath,y ;lda #32 ; plasma blast only jsr ExplosionDirect mva #sfx_silencer sfx_effect ; Clear current Shooter settings. After that, Shooter will "search" for the target again ldx NumberOfPlayers dex @ lda skillTable,x cmp #2 ; clear variables only if Shooter bne NotShooter lda #0 sta PreviousAngle,x sta PreviousEnergyL,x sta PreviousEnergyH,x NotShooter dex bpl @- ; jump to after explosion routines (soil fallout, etc.) ; After going through these routines we are back ; to checking if a tank exploded and maybe we have ; a deadly shot here again. jmp MainRoundLoop.AfterExplode .endp ;-------------------------------------------------- .proc DecreaseEnergyX ;Decreases energy of player nr X by the value Y ;increases his financial loss ;increases gain of tank TankNr ;-------------------------------------------------- sty EnergyDecrease ; Lose increase lda loseL,x clc adc EnergyDecrease sta loseL,x scc inc loseH,x ; Energy now, not less than 0 sec lda Energy,x sbc EnergyDecrease bcs NotNegativeEnergy ; if less than 0 then 0 lda #0 NotNegativeEnergy sta Energy,x ;now increase the gain of the shooting tank ldy TankNr clc lda gainL,y adc EnergyDecrease sta gainL,y lda gainH,y adc #0 sta gainH,y rts .endp ;-------------------------------------------------- .proc DecreaseShieldEnergyX ; Decreases energy of shield player nr X by the value Y ; if shield energy is 0 after decrease then in Y we have ; rest of the energy - to decrease tank energy ;-------------------------------------------------- sty EnergyDecrease ldy #0 ; if Shield survive then no decrease tank anergy ; Energy cannot be less than 0 sec lda ShieldEnergy,x sbc EnergyDecrease bcs NotNegativeShieldEnergy ; now calculate rest of energy for future tank energy decrease sec lda EnergyDecrease sbc ShieldEnergy,x tay ; ShieldEnargy less than 0 then .. 0 lda #0 NotNegativeShieldEnergy sta ShieldEnergy,x rts .endp ;--------------------------------- .proc Seppuku ;--------------------------------- lda #0 ; get position of the tank ldx TankNr ; lda #0 ; turn off defense weapons when hara-kiring sta ActiveDefenceWeapon,x sta ShieldEnergy,x jsr SetupXYdraw lda #ind_Missile ; Missile jsr ExplosionDirect jmp MainRoundLoop.continueMainRoundLoopAfterSeppuku .endp ;-------------------------------------------------- .proc GetRandomWind ;in: MaxWind (byte) ;out: Wind (word) ;uses: _ ;-------------------------------------------------- mva #$00 Wind+1 sta Wind+2 sta Wind+3 @ lda random sta Wind beq noWind ; if 0 then nothing to do cmp MaxWind bcs @- ; if more than MaxWind then randomize again ; multiply Wind by 16 ; two bytes of Wind are treated as a decimal part of vx variable :4 aslw Wind ; decide the direction lda random bmi noWindDirectionChange sec ; Wind = -Wind .rept 2 lda #$00 sbc Wind+# sta Wind+# .endr lda #$ff sta Wind+2 sta Wind+3 noWind noWindDirectionChange rts .endp ;-------------------------------------------------- .proc MaxForceCalculate ; calculates max force for tank (tanknr in X) ; Energy of tank X in A ;-------------------------------------------------- sta L1 lda #0 ldy #9 clc CYK ror ror L1 bcc NIE clc adc #10 ; multiplication by 10 NIE dey bne CYK sta MaxForceTableH,x lda L1 sta MaxForceTableL,x rts .endp ;-------------------------------------------------- .proc WeaponCleanup ; cleaning of the weapon possesion tables ; 99 of Baby Missles and White Flags, all other weapons=0) ;-------------------------------------------------- ldx #(number_of_weapons - 1) @ lda #$0 cpx #ind_White_Flag ; White Flag bne no99 set99 lda #99 no99 .REPT MaxPlayers, #+1 sta TanksWeapon:1,x .ENDR dex beq set99 ; Baby Missile (index=0) bpl @- rts .endp ;-------------------------------------------------- .proc Initialize ;Initialization sequence ;uses: temp, ... ;-------------------------------------------------- deletePtr = temp ; clean variables lda #0 sta escFlag tay mwa #variablesStart deletePtr @ tya sta (deletePtr),y inw deletePtr cpw deletePtr #ClearedvariablesEnd bne @- tya jsr SetJoystickPort ; ser initial shapes for each tank (tanks 0-5 has shape 0 now) ldy #1 sty TankShape+1 sty TankShape+4 iny sty TankShape+2 sty TankShape+5 mwa #1024 RandBoundaryHigh mva #$ff LastWeapon sta HowMuchToFall mva #1 color jsr SetStandardBarrels jsr WeaponCleanup mva #>WeaponFont chbas ;parameter for old plot (unPlot) max 5 points ldx #4 SetunPlots lda #display sta oldplotH,x lda #0 sta oldply,x lda #$ff sta oldora,x dex bpl SetunPlots ;setting up P/M graphics lda #>pmgraph sta pmbase lda #$03 ; P/M on sta GRACTL jsr SetPMWidthAndColors lda #%00100001 ; P/M priorities (multicolor players on) - prior=1 sta GPRIOR jsr PMoutofScreen ;let the tanks be visible! ldx #(maxPlayers-1) lda #99 ; tank is visible MakeTanksVisible sta eXistenZ,x dex bpl MakeTanksVisible mva #1 CurrentRoundNr ;we start from round 1 mva #6 NTSCcounter rts .endp ;-------------------------------------------------- .proc SetStandardBarrels ; set standart barrel length and deactivate Auto Defense ; for all tanks ;-------------------------------------------------- ldx #maxPlayers-1 @ lda #StandardBarrel ; standard barrel length sta BarrelLength,x lda #$00 ; deactivate Auto Defense sta AutoDefenseFlag,x dex bpl @- rts .endp ;---------------------------------------------- /* .proc RandomizeSequence0 ldx #0 @ txa sta TankSequence,x inx cpx #MaxPlayers bne @- rts .endp */ ;-------------------------------------------------- .proc RandomizeSequence ; in: NumberOfPlayers ; out: TankSequence ; how: get random number lower than NumberOfPlayers ; put it in the first slot. ; get another random number lower than NumberOfPlayers ; check if was previously saved in first slot ; if not then save it in second slot ; repeat untill NumberOfPlayers ldx #0 GetRandomAgainX txy ; destroy A! dey lda RANDOM cmp NumberOfPlayers bcs GetRandomAgainX cpx #0 bne NotFirstSlot sta TankSequence,x ;now first slot is ready inx bne GetRandomAgainX NotFirstSlot ;now we have to check if the value was not used ;in previous slots UsageLoop cmp TankSequence,y beq GetRandomAgainX ;apparently we have already used this value dey bpl UsageLoop ;well, looks like this value is new! sta TankSequence,x inx cpx NumberOfPlayers bcc GetRandomAgainX ; and "sequence" for teans ldx #MaxPlayers stx TankSequence+MaxPlayers+1 ; B-Team inx stx TankSequence+MaxPlayers ; A-Team rts .endp ;---------------------------------------------- .proc RandomizeAngle ; routine returns in A ; a valid angle for the tank's barrel. ; X is not changed ;---------------------------------------------- ; lets randomize someting between 0 and 180 randomize 0 180 rts .endp ;---------------------------------------------- .proc RandomizeForce ; routine returns in ForceTable/L/H ; valid force of shooting for TankNr ; in X must be TankNr ; low and high randomize boundary passed as word value ; RandBoundaryLow ; RandBoundaryHigh ;---------------------------------------------- lda RANDOM sta temp2 lda RANDOM and #%00000011 ;(0..1023) sta temp2+1 cpw RandBoundaryLow temp2 seq:bcs RandomizeForce cpw RandBoundaryHigh temp2 bcc RandomizeForce lda temp2 sta ForceTableL,x lda temp2+1 sta ForceTableH,x ;--------- LimitForce ; in X must be TankNr ; cuts force to MaxForceTable lda MaxForceTableH,x cmp ForceTableH,x bne @+ lda MaxForceTableL,x cmp ForceTableL,x @ bcs @+ lda MaxForceTableL,x sta ForceTableL,x lda MaxForceTableH,x sta ForceTableH,x @ rts .endp ;---------------------------------------------- .proc Table2Force ;---------------------------------------------- lda ForceTableL,x sta Force lda ForceTableH,x sta Force+1 rts .endp ;---------------------------------------------- .proc MoveBarrelToNewPosition ;---------------------------------------------- mva #1 Erase jsr DrawTankNr.BarrelChange MoveBarrel mva #sfx_set_power_2 sfx_effect jsr PutTankNr ; and Erase = 0 jsr DisplayStatus.displayAngle ; jsr CheckExitKeys spl:rts ;---Exit key pressed-quit game--- ldx TankNr ; mva #1 Erase bit TestFlightFlag bmi AIaim jsr WaitOneFrame AIaim jsr DrawTankNr.BarrelChange lda NewAngle cmp AngleTable,x beq BarrelPositionIsFine bcc rotateLeft rotateRight ; older is lower inc angleTable,x jmp MoveBarrel rotateLeft ; older is bigger dec angleTable,x jmp MoveBarrel BarrelPositionIsFine jmp PutTankNr ; and Erase = 0 ; rts .endp ;-------------------------------------------------- .proc DemoModeOrKey ; Waits for the key pressed if at least one human is playing. ; Otherwise, waits 3 seconds (demo mode). ;-------------------------------------------------- ;check demo mode ldx numberOfPlayers dex checkForHuman ; if all in skillTable other than 0 then switch to DEMO MODE lda skillTable,x beq peopleAreHere dex bpl checkForHuman ; no people, just wait a bit ldy #75 jmp PauseYFrames ; rts peopleAreHere jmp getkey ; jsr:rts .endp ;---------------------------------------------- .proc SortSequence ; ;---------------------------------------------- ; here we try to get a sequence of tanks for two ; purposes: ; 1. to make up shooting sequence for the next round (from down to top) ; 2. to display game results more nicely (from top to down) ; ; I think I will go for a stupid bubble sort... ; it is easy to test :) ; ; Results are in ResultsTable, in TankSequence (Sorted Table) we want to ; have numbers of tanks from the worst to the best. ; in other words, if ResultsTable=(5,4,65,23,3,6) ; the TankSequence=(4,1,0,5,3,2) ; let's assume initially the TankSequence=(0,1,2,3,4,5) ldx #0 SequenceStart txa sta TankSequence,x inx cpx #MaxPlayers bne SequenceStart ; i=0:sortflag=0 ;loop: ; if TR(i) < TX(i+1) then i=i+1: here quit if i=numberofplayers ; or goto loop: ; else ; temp=TR(i): tempo=TankSequence(i) ; TR(i)=TR(i+1): TankSequence(i)=TankSequence(i+1) ; TR(i+1)=temp: TankSequence(i+1)=tempo ; i=i+1 ; sortflag=sortflag+1 ; go loop: ; if sortflag=0 then finished, else repeat... ; ; or something like this :) Bubble ldx #0 ;i=x stx temp2 ; sortflag=temp2 inx ; because NumberOfPlayers start from 1 (not 0) BubbleBobble ldy TankSequence-1,x ; x count from 1 to NumberOfPlayers (we need cout from 0 to NumberOfPlayers-1) lda ResultsTable,y ldy TankSequence,x cmp ResultsTable,y bcc nextishigher bne swapvalues nextisequal ; if results are equal, check Direct Hits ldy TankSequence-1,x lda DirectHits,y ldy TankSequence,x cmp DirectHits,y bcc nextishigher bne swapvalues nextisequal2 ; if results are equal, check money (H) ldy TankSequence-1,x lda EarnedMoneyH,y ldy TankSequence,x cmp EarnedMoneyH,y bcc nextishigher bne swapvalues nextisequal2b ; if results are equal, check money (L) ldy TankSequence-1,x lda EarnedMoneyL,y ldy TankSequence,x cmp EarnedMoneyL,y ; beq nextishigher ; this is to block hangs when 2 equal values meet bcc nextishigher ;here we must swap values ;because next is smaller than previous swapvalues lda TankSequence-1,x sta temp lda TankSequence,x sta TankSequence-1,x lda temp sta TankSequence,x inc temp2 nextishigher inx cpx NumberOfPlayers bne BubbleBobble lda temp2 bne Bubble rts .endp ;-------------------------------------------------- .proc SetWallsType ;-------------------------------------------------- mva #0 WallsType lda OptionsTable+8 cmp #4 beq SetRandomWalls lsr ror WallsType lsr ror WallsType rts SetRandomWalls lda random and #%11000000 sta WallsType rts .endp ; -------------------------------------- ; Sets the appropriate variables based on the 'OptionsTable' ; ; this function returns: ; - 'NumberOfPlayers' ; - 'moneyL' and 'moneyH' (in arrays) for each player ; - 'gravity' ; - 'MaxWind' ; - 'RoundsInTheGame' ; - 'flyDelay' ; - 'seppukuVal' ; - 'mountainDeltaL' and 'mountainDeltaH' .proc SetVariablesFromOptions ;first option ldy OptionsTable iny iny sty NumberOfPlayers ;1=1 player (but minimum is 2) ;second option (cash) ldy OptionsTable+1 ldx #0 @ lda CashOptionL,y sta moneyL,x lda CashOptionH,y sta moneyH,x inx cpx NumberOfPlayers bne @- ;third option (gravity) ldy OptionsTable+2 lda GravityTable,y sta gravity ;fourth option (wind) ldy OptionsTable+3 lda MaxWindTable,y sta MaxWind ;fifth option (no of rounds) ldy OptionsTable+4 lda RoundsTable,y sta RoundsInTheGame ;6th option (shell speed) ldy OptionsTable+5 lda flyDelayTable,y sta flyDelay ;7th option (Airstrike after how many missess) ldy OptionsTable+6 lda seppukuTable,y sta seppukuVal ;8th option (how aggressive are mountains) ldy OptionsTable+7 setMountainsType lda mountainsDeltaTableH,y sta mountainDeltaH lda mountainsDeltaTableL,y sta mountainDeltaL rts .endp ;-------------------------------- .proc DisplayResults ; ;displays results of the round ;using 4x4 font jsr RoundOverSprites mva #$ff plot4x4color ;centering the result screen mva #((ScreenHeight/2)-(8*4)) ResultY ;upper frame mva ResultY LineYdraw jsr TL4x4_top adb ResultY #4 ;next line ;Header1 ;Displays round number lda CurrentRoundNr cmp RoundsInTheGame beq GameOver4x4 ;sta decimal mwx #RoundNrDisplay displayposition jsr displaybyte ;decimal (byte), displayposition (word) mwa #LineHeader1 LineAddress4x4 mva ResultY LineYdraw jsr TL4x4_empty.go ; center and type line beq @+ ;unconditional jump, because TypeLine4x4 ends with beq GameOver4x4 RmtSong song_round_over mwa #LineGameOver LineAddress4x4 mva ResultY LineYdraw jsr TL4x4_empty.go ; center and type line mva #1 GameIsOver @ adb ResultY #4 ;next line ;Empty line mva ResultY LineYdraw jsr TL4x4_empty adb ResultY #2 ;next line ;Header2 mwa #LineHeader2 LineAddress4x4 mva ResultY LineYdraw jsr TL4x4_empty.go ; center and type line adb ResultY #4 ;next line ;Empty line mva ResultY LineYdraw jsr TL4x4_empty sbb ResultY #2 ;next line (was empty) ldx NumberOfPlayers ;we start from the highest (best) tank bit TeamGame bvc NoTeamsResults ldx #MaxPlayers+2 ; set pointer to teams results NoTeamsResults dex ;and it is the last one stx ResultOfTankNr ;in TankSequence table mwa #TanksNames tempXROLLER ResultOfTheNextPlayer ldx ResultOfTankNr ;we are after a round, so we can use TankNr lda TankSequence,x ;and we keep here real number if the tank sta TankNr ;for which we are displaying results adb ResultY #4 ;next line ;there are at least 2 players, so we can safely ;start displaying the result lda #3 ;it means | sta ResultLineBuffer ldy TankNr lda ResultsTable,y sta decimal mva #0 decimal+1 mwa #(ResultLineBuffer+8) displayposition jsr displaydec5 ;decimal (byte), displayposition (word) ; overwrite the second digit of the points (max 255) ;it means ":" mva #26 ResultLineBuffer+9 ldx #0 lda TankNr asl asl ; times 8, because it is lengtgh asl ; of the names of the tanks tay TankNameCopyLoop lda (tempXROLLER),y ;XROLLER is not working now and #$3f ;always CAPITAL letters inx sta ResultLineBuffer,x iny cpx #8 ; end of name bne TankNameCopyLoop ; last letter of tank name overwrites first digit of the points (max 255) ;just after the digits ;it means | mva #$3 ResultLineBuffer+13 ;result line display mwa #ResultLineBuffer LineAddress4x4 mva ResultY LineYdraw jsr TL4x4_empty.go ; center and type line adb ResultY #4 ;next line ;Empty line mva ResultY LineYdraw jsr TL4x4_empty dec ResultOfTankNr bmi FinishResultDisplay ; check for last player lda ResultOfTankNr cmp #MaxPlayers-1 ; check for last team beq FinishResultDisplay sbb ResultY #2 ;distance between lines is smaller jmp ResultOfTheNextPlayer FinishResultDisplay mva ResultY LineYdraw ;jmp TL4x4_bottom ; just go .endp .proc TL4x4_bottom ;bottom of the frame mwa #LineBottom LineAddress4x4 jmp TL4x4_empty.go ; center and type line .endp .proc TL4x4_top ;bottom of the frame mwa #LineTop LineAddress4x4 jmp TL4x4_empty.go ; center and type line .endp .proc TL4x4_empty ;empty frame mwa #LineEmpty LineAddress4x4 go mwa #((ScreenWidth/2)-(8*4)) LineXdraw ; center and type line jmp TypeLine4x4 ; jsr:rts .endp .IF VU_METER = 1 .proc VUMeter ; No VUMeter if key pressed jsr GetKeyFast cmp #@kbcode._none bne EndMeter ; check timer ; Atari 800 has 3 bytes clock, but 5200 only 2 bytes .IF TARGET = 800 LDA RTCLOK+1 .ELIF TARGET = 5200 lda RTCLOK .ENDIF cmp #VuMeterTime bcc EndMeter bit noMusic ; if no music - no VuMeters bmi EndMeter ; Let's go! jsr ClearTanks ; store all angles ldx NumberOfPlayers dex @ lda AngleTable,x sta previousAngle,x lda #0 sta AngleTable,x dex bpl @- jsr DrawTanks ; let's go! Meter mva #1 Erase jsr drawbarrels ; clear barrels ldx NumberOfPlayers @ txa and #%00000001 tay lda trackn_audc+2,y :4 asl sta AngleTable,x dex bpl @- mva #0 Erase jsr drawbarrels ; draw barrels jsr WaitOneFrame jsr GetKeyFast cmp #@kbcode._none beq Meter ; restore all angles jsr ClearTanks ldx NumberOfPlayers dex @ lda previousAngle,x sta AngleTable,x dex bpl @- jsr drawtanks jsr drawtanknr EndMeterAndReset lda #0 ; only older byte .IF TARGET = 800 sta RTCLOK+1 .ELIF TARGET = 5200 sta RTCLOK .ENDIF EndMeter rts ;----------- drawbarrels lda TankNr pha ldx NumberOfPlayers dex stx TankNr DrawNextTank lda eXistenZ,x beq nobarrel ; if energy=0 then no tank jsr drawtanknr.BarrelChange nobarrel dec TankNr ldx TankNr bpl DrawNextTank pla sta TankNr rts .endp .ENDIF .ENDIF