; @com.wudsn.ide.asm.mainsourcefile=scorch.asm .IF *>0 ;this is a trick that prevents compiling this file alone ;-------------------------------------------------- .proc draw ;;fuxxing good draw :) ; xdraw,ydraw (word) - coordinates of first point ; xbyte,ybyte (word) - coordinates of last point ;-------------------------------------------------- ;creditz to Dr Jankowski / MIM U.W. ; (xi,yi)-----(xk,yk) ;20 DX=XK-XI ;30 DY=YK-YI ;40 DP=2*DY ;50 DD=2*(DY-DX) ;60 DI=2*DY-DX ;70 REPEAT ;80 IF DI>=0 ;90 DI=DI+DD ;100 YI=YI+1 ;110 ELSE ;120 DI=DI+DP ;130 ENDIF ;140 plot XI,YI ;150 XI=XI+1 ;160 UNTIL XI=XK ; begin: xdraw,ydraw - end: xbyte,ybyte ; let's store starting coordinates ; will be needed, because everything is calculated relatively mwa #$ffff LineLength mwa xdraw xtempDRAW ; It's a little crazy, but we don't have to check later to see if Y is out of screen mva ydraw ytempDRAW mva ydraw+1 ytempDRAW+1 bmi DrawOutOfTheScreen ; if line goes our of the screen we are not drawing it, but... cpw xdraw #screenwidth bcs DrawOutOfTheScreen cpw xbyte #screenwidth bcs DrawOutOfTheScreen lda ybyte+1 bpl DrawOnTheScreen DrawOutOfTheScreen rts DrawOnTheScreen ; constant parameters ; XI=0 ,YI=0 lda #0 sta XI sta XI+1 sta YI sta YI+1 sta HowToDraw ; reset flags sta DrawDirFactor ; reset flags ; setting the direction controll bits cpw ydraw ybyte bcc LineDown ; here one line up ; we are subctracting Yend from Ybegin (reverse order) ; DY=YI-YK sbw ydraw ybyte DY ; we are setting bit 7 lda #%10000000 sta HowToDraw ;here we can because it's first operation bne CheckDirectionX ; JMP LineDown ; one line down here ; we are clearing bit 7 (it's cleared :) ) ; mva #0 HowToDraw ;here we can because it's first operation ; substract Ybegin from Yend (normal order) ; DY=YK-YI sbw ybyte ydraw DY CheckDirectionX cpw xdraw xbyte bcc LineRight ; here goes line to the left ; substract Xend from Xbegin (reverse) ; DX=XI-XK sbw xdraw xbyte DX ; we set bit 6 lda HowToDraw ora #%01000000 sta HowToDraw bne CheckDirectionFactor ; JMP LineRight ; here goes one line to the right ; we clear bit 6 ; we can do nothing because the bit is cleared! ;lda HowToDraw ;and #%10111111 ;sta HowToDraw ; substracting Xbegin from Xend (normal way) ; DX=XK-XI sbw xbyte xdraw DX CheckDirectionFactor ; here we check Direction Factor ; I do not know if we are using proper English word ; but the meaning is 'a' in y=ax+b ; lda DX ; we already have DX in A cpw DX DY bcs NoSwapXY SwapXY ; not this half of a quarter! - parameters must be swapped ; XK=DY ; DY=DX ; DX=XK - because DY is there so DY and DX are swapped ; YK ... not used mvy DY XK mvx DY+1 XK+1 ; now we have XK in Y and X for optimization mwa DX DY ; DX=XK optimized (4 bytes saved!) sty DX stx DX+1 ; and let's set bit 7 of DrawDirFactor dec DrawDirFactor ; bmi LineParametersReady ; JMP - but we don't need JMP :) NoSwapXY ; 'a' factor is fire, so we copy parameters ; XK=DX mwa DX XK ; and clearing bit 7 of DrawDirFactor ; and bit 7 clear ; (is not needed because already cleared) ;lda #0 ;sta DrawDirFactor LineParametersReady ; let's check if length is not zero lda DX ora DX+1 ora DY ora DY+1 bne NotOnePoint ; length=0 sta LineLength sta LineLength+1 jmp EndOfDraw NotOnePoint ; here we have DX,DY,XK and we know which operations ; are to be performed with these factors when doing PLOT ; (accordingly to given bits of 'HowToDraw') ; Now we must calculate DP, DD and DI ; DP=2*DY ; DD=2*(DY-DX) ; DI=2*DY-DX mwa DY DP aslw DP sbw DY DX DD aslw DD mwa DY DI aslw DI sbw DI DX DrawLoop ; REPEAT ; IF DI>=0 lda DI+1 bmi DINegative ; DI=DI+DD ; YI=YI+1 adw DI DD inw YI jmp drplot DINegative ; ELSE ; DI=DI+DP adw DI DP drplot ; Our plot that checks how to calculate pixels. ; In xtempDRAW and ycircle there are begin coordinates ; of our line ; First we check the 'a' factor (like in y=ax+b) ; If necessary we swap XI and YI ; (as we can not change XI and YI we move XI to temp2 ; and YI to temp) bit DrawDirFactor bmi SwappedXY mwa XI temp mwa YI temp2 jmp CheckPlotY SwappedXY mwa XI temp2 mwa YI temp CheckPlotY bit HowToDraw bmi LineGoesUp ; here we know that line goes down and we are not changing Y adw temp2 ytempDRAW ydraw ; YI jmp CheckPlotX LineGoesUp ; line goes up here - we are reversing Y sbw ytempDRAW temp2 ydraw ; YI CheckPlotX bit HowToDraw bvs LineGoesLeft ; here we know that line goes right and we are not changing X adw temp xtempDRAW xdraw ; XI jmp PutPixelinDraw LineGoesLeft ; line goes left - we are reversing X sbw xtempDRAW temp xdraw ; XI PutPixelinDraw ; 0 - plot, %10000000 - LineLength (N), %01000000 - DrawCheck (V) bit drawFunction bpl @+ inw LineLength bit Vdebug bmi MeasureVisualisation bpl ContinueDraw ; jmp @ bvc @+ DrawCheck lda tracerflag ora SmokeTracerFlag yestrace beq notrace jsr plot notrace ;aftertrace ;key lda HitFlag bne StopHitChecking CheckCollisionDraw ; checking collision! lda ydraw+1 bmi StopHitChecking jsr CheckCollisionWithTank lda HitFlag bne StopHitChecking clc lda xdraw adc #mountaintable sta temp+1 ldy #0 lda ydraw cmp (temp),y bcc StopHitChecking mwa xdraw XHit lda (temp),y sec sbc #1 sta YHit sty YHit+1 mva #$ff HitFlag StopHitChecking jmp ContinueDraw @ MeasureVisualisation jsr plot ContinueDraw ; XI=XI+1 ; UNTIL XI=XK inw XI cpw XI XK jne DrawLoop EndOfDraw mwa xtempDRAW xdraw mwa ytempDRAW ydraw rts .endp ; Circle is now in external file icl 'circle2.asm' ;-------------------------------------------------- .proc placetanks ;-------------------------------------------------- ldx #(MaxPlayers-1) ;maxNumberOfPlayers-1 lda #0 @ ; clearing the tables with coordinates of the tank ; it is necessary, because randomizing checks ; if the given tank is already placed ; after check if its position is not (0,0) ; I will be honest with you - I have no idea ; what the above comment was intending to mean :) sta XtankstableL,x sta XtankstableH,x sta Ytankstable,x dex bpl @- mwa #0 temptankX sta temptankNr ;player number StillRandomize ldx NumberOfPlayers lda random and #$07 tay cpy NumberOfPlayers bcs StillRandomize lda xtankstableL,y bne StillRandomize lda xtankstableH,y bne StillRandomize ; here we know that we got a random number ; of the tank that is not in use ; this number is in Y clc lda temptankX adc disktance,x sta temptankX sta xtankstableL,y bcc NotHigherByte03 inc temptankX+1 NotHigherByte03 lda temptankX+1 sta xtankstableH,y INC temptankNr ldx temptankNr Cpx NumberOfPlayers bne StillRandomize ; getting random displacements relative to even positions ldx #$00 StillRandomize02 lda random and #$1f ; maximal displacement is 31 pixels clc adc xtankstableL,x sta xtankstableL,x bcc NotHigherByte02 inc xtankstableH,x NotHigherByte02 ; and we deduct 15 to make the displacement work two ways sec lda xtankstableL,x sbc #$0f ; and clear lowest bit to be sure that the X coordinate is even ; (this is to have P/M background look nice) ; "AND" does not change "Carry" bit. ; x correction for P/M ; -- .IF XCORRECTION_FOR_PM = 1 and #$fe .ENDIF ; -- sta xtankstableL,x bcs NotHigherByte01 dec xtankstableH,x NotHigherByte01 inx Cpx NumberOfPlayers bne StillRandomize02 rts ; during calculating heights of thw mountains ; check if the tank is not somewhere around ; if so, make horizontal line 8 pixels long CheckTank ldx NumberOfPlayers dex CheckNextTank lda xtankstableL,x cmp xdraw bne UnequalTanks lda xtankstableH,x cmp xdraw+1 bne UnequalTanks lda ydraw ;sec ;sbc #$01 ; minus 1, because it was 1 pixel too high sta ytankstable,x ; what's the heck is that????!!!! mva #7 deltaX mwa #0 delta UnequalTanks dex bpl CheckNextTank rts .endp ;------------------------------------------------- .proc ClearTanks jsr PMoutofScreen lda #1 ; erase tanks flag bne drawtanks.era .endp ;------------------------------------------------- .proc drawtanks ;------------------------------------------------- lda #0 ; no erase tanks flag era sta Erase lda TankNr pha ldx NumberOfPlayers dex stx TankNr DrawNextTank jsr drawtanknr dec TankNr ldx TankNr bpl DrawNextTank pla sta TankNr rts .endp ;--------- ClearTankNr lda #1 ; erase tank flag bne @er PutTankNr lda #0 ; no erase tank flag @er sta Erase .proc DrawTankNr ldx tankNr ; let's check the energy lda eXistenZ,x bne SkipHidingPM ; if energy=0 then no tank ; hide P/M lda TanksPMOrder,x tax lda #0 cpx #$4 ; 5th tank is defferent bne No5thTankHide sta hposp0+4 sta hposp0+5 beq @+ No5thTankHide cpx #$5 ; 6th tank is defferent bne No6thTankHide sta hposp0+6 sta hposp0+7 beq @+ No6thTankHide sta hposp0,x @ ldx TankNr jmp DoNotDrawTankNr SkipHidingPM ldy TankShape,x lda TankShapesTable,y tay lda AngleTable,x cmp #91 ; left or right tank shape bcs LeftTank :2 iny ; right tank LeftTank sty CharCode jsr SetupXYdraw jsr TypeChar.Fast lda Erase jne noTankNoPM ; now P/M graphics on the screen (only for 5 tanks) ; horizontal position ldx TankNr lda TanksPMOrder,x tax mwa xdraw xbyte rorw xbyte ; divide by 2 (carry does not matter) lda xbyte clc adc #PMOffsetX ; P/M to graphics offset cpx #$4 ; 5th tank are joined missiles and offset is defferent bne No5thTank clc adc #$04 ; missile offset offset sta hposp0+4 sta hposp0+5 bne NoMissile No5thTank cpx #$5 ; 6th tank are joined missiles and offset is defferent bne Tanks1to4 clc adc #$04 ; missile offset offset sta hposp0+6 sta hposp0+7 bne NoMissile Tanks1to4 sta hposp0,x NoMissile ; vertical position lda pmtableL,x sta xbyte lda pmtableH,x sta xbyte+1 ; calculate start position of the tank lda ydraw clc adc #PMOffsetY sta temp ldy #$00 cpx #$5 bcs PMForTank6 ; clear sprite and put 3 lines on the tank at the same time ldx #3 ; three lines of PM ClearPM cpy temp bne ZeroesToGo @ lda (xbyte),y and #%11110000 ora #%00001111 ; (2 bits set) we set on two pixels in three lines sta (xbyte),y dey dex bne @- ZeroesToGo lda (xbyte),y and #%11110000 sta (xbyte),y dey bne ClearPM beq NoPlayerMissile PMForTank6 ; clear sprite and put 3 lines on the tank at the same time ldx #3 ; three lines of PM ClearPM6 cpy temp bne ZeroesToGo6 @ lda (xbyte),y and #%00001111 ora #%11110000 ; (2 bits set) we set on two pixels in three lines sta (xbyte),y dey dex bne @- ZeroesToGo6 lda (xbyte),y and #%00001111 sta (xbyte),y dey bne ClearPM6 NoPlayerMissile noTankNoPM ldy #$01 lda Erase seq:dey sty color ; draw defensive weapons like shield ( tank number in X ) ; in xdraw, ydraw we have coordinates left LOWER corner of Tank char ldx TankNr lda ActiveDefenceWeapon,x cmp #ind_Shield ; one shot shield beq DrawTankSh cmp #ind_Force_Shield ; shield with energy and parachute beq DrawTankShieldBold cmp #ind_Heavy_Shield ; shield with energy beq DrawTankShieldBold cmp #ind_Bouncy_Castle ; Auto Defence beq DrawTankShieldWihHorns cmp #ind_Mag_Deflector ; Mag Deflector beq DrawTankShieldWihHorns cmp #ind_White_Flag ; White Flag beq DrawTankFlag bne NoShieldDraw DrawTankSh jsr DrawTankShield beq NoShieldDraw ; JMP DrawTankShieldWihHorns jsr DrawTankShield jsr DrawTankShieldHorns jmp NoShieldDraw DrawTankShieldBold jsr DrawTankShield jsr DrawTankShieldBoldLine beq NoShieldDraw ; JMP DrawTankFlag lda #char_flag ; flag symbol sta CharCode lda Ytankstable,x sec sbc #8 sta ydraw jsr TypeChar.Fast NoShieldDraw BarrelChange ldy #$01 lda Erase seq:dey sty color jsr DrawBarrel ldx TankNr DoNotDrawTankNr rts .endp ; ------------------------------------- .proc FlashTank ; ------------------------------------- ; number of blinking tank in TankNr mva #18 fs ; temp, how many times flash the tank tankflash_loop jsr CheckStartKey ; START KEY sne:mva #1 fs ; finish it mva #1 Erase ldx TankNr jsr DrawTankNr.SkipHidingPM ; it's necessary becouse DrawTankNr skips tanks with no energy ! ;PAUSE 2 ldy #1 jsr PauseYFrames mva #0 Erase ldx TankNr jsr DrawTankNr.SkipHidingPM ;PAUSE 2 ldy #1 jsr PauseYFrames dec fs jne tankflash_loop rts .endp ;-------------------------------------------------- .proc DrawTankShield ; X - tank number ; if use DrawInPosition entry point then: ; xdraw, ydraw - coordinates left LOWER corner of Tank char ; values remain there after a DrawTankNr proc. ; ; this proc change xdraw, ydraw and temp! ;-------------------------------------------------- sbw xdraw #$03 ; 3 pixels to left ; draw left vertical line of shield ( | ) mva #7 temp ; strange !!! @ jsr plot .nowarn dew ydraw dec temp bne @- ; draw left oblique line of shield ( / ) mva #3 temp @ jsr plot .nowarn dew ydraw inw xdraw dec temp bne @- ; draw top horizontal line of shield ( _ ) mva #7 temp @ jsr plot inw xdraw dec temp bne @- ; draw right oblique line of shield ( \ ) mva #3 temp @ jsr plot inw ydraw inw xdraw dec temp bne @- ; draw right vertical line of shield ( | ) mva #7 temp @ jsr plot inw ydraw dec temp bne @- rts ; Z allways set .endp ;-------------------------------------------------- .proc DrawTankShieldHorns ; use only directly after DrawTankShield ; this proc draws a little "horns" on shield. ; Symbol of defensive but aggressive :) weapon ;-------------------------------------------------- .nowarn dew xdraw ; 1 pixel left sbw ydraw #$0a ; 10 pixels up jsr plot .nowarn dew ydraw inw xdraw jsr plot sbw xdraw #$0d ; 13 pixels left jsr plot inw xdraw inw ydraw jmp plot ; jsr:rts ; rts .endp ;-------------------------------------------------- .proc DrawTankShieldBoldLine ; use only directly after DrawTankShield ; this proc draws bold top on shield. ; Symbol of ablative shield ? :) ;-------------------------------------------------- sbw xdraw #$04 ; 5 pixels left sbw ydraw #$0b ; 11 pixels up ; draw additional top horizontal line of shield ( _ ) mva #6 temp @ jsr plot .nowarn dew xdraw dec temp bne @- rts ; Z allways set .endp ;-------------------------------------------------- .proc DrawTankParachute ;Tank number in X ;-------------------------------------------------- lda #char_parachute ; parachute symbol sta CharCode lda Ytankstable,x cmp #16 bcc ToHighToParachute ;sec sbc #8 sta ydraw jsr SetupXYdraw.X jsr TypeChar.Fast ToHighToParachute ldx TankNr rts .endp ;-------------------------------------------------- .proc DrawTankRocketEngine ; X - tank number ; ; this proc change xdraw, ydraw and temp! ;-------------------------------------------------- clc lda Ytankstable,x adc #2 ; 1 pixel down sta ydraw mva #0 ydraw+1 clc lda XtanksTableL,x adc #2 ; 2 pixels to right sta xdraw lda XtanksTableH,x adc #0 sta xdraw+1 ; draw first horizontal line mva #5 temp @ jsr plot inw xdraw dec temp bne @- sbw xdraw #2 ; 2 pixels left inw ydraw ; 1 pixel down ; draw second horizontal line mva #3 temp @ jsr plot .nowarn dew xdraw dec temp bne @- adw xdraw #2 ; 2 pixels right inw ydraw ; 1 pixel down ; and last pixel jsr plot ldx TankNr rts .endp ;-------------------------------------------------- .proc DrawTankEngine ; X - tank number ; ; this proc change xdraw, ydraw and temp! ;-------------------------------------------------- jsr SetupXYdraw.X ; one pixel under tank clc lda Ytankstable,x adc #1 sta ydraw mva #0 ydraw+1 ; plot one (first - clear) and 6 random color pixels mvy #7 temp ; clear first pixel under tank bne @pl ; A=0 @ lda Erase eor #%00000001 and random and #%00000001 @pl sta color jsr plot inw xdraw dec temp bne @- ; clear last pixel under tank mva #0 color jsr plot ldx TankNr rts .endp ;-------------------------------------------------- .proc TankFalls; ;-------------------------------------------------- lda #0 sta PreviousFall ; bit 7 - left, bit 6 - right sta EndOfTheFallFlag sta Parachute mva #2 FallingSoundBit ; another trick for only one sfx initialization in loop ; let's check if the given tank has got the parachute ldx TankNr lda ActiveDefenceWeapon,x cmp #ind_Parachute ; parachute beq ParachuteActive cmp #ind_StrongParachute ; strong parachute beq ParachuteActive cmp #ind_Force_Shield ; shield witch energy and parachute bne TankFallsX ParachuteActive inc Parachute TankFallsX ; sound only if really falls lda Parachute and FallingSoundBit ; bit 1 beq NoFallingSound mva #0 FallingSoundBit mva #sfx_shield_off sfx_effect NoFallingSound ; clear previous position mva #1 Erase jsr ClearTankNr ; and the parachute (if present) lda Parachute and #01 beq DoNotClearParachute ; here we clear the parachute ; ldx TankNr jsr DrawTankParachute DoNotClearParachute mva #0 Erase ; ldx TankNr lda EndOfTheFallFlag ; We only get byte below the tank if still falling bne NoGroundCheck ; coordinates of the first pixel under the tank ldx TankNr jsr SetupXYdraw.X lda Ytankstable,x clc adc #1 ; in this point the comment helped us! For the very first ; time in our lives! Tada! It opens a new chapter!!! sta ydraw ; ; UnderTank1 ; byte under tank ; UnderTank2 ; byte under tank reversed (for simple check right direction) lda #08 sta temp ; Loop Counter ByteBelowTank jsr point_plot bne EmptyPoint2 sec ror UnderTank2 sec bcs ROLPoint2 EmptyPoint2 clc ror UnderTank2 clc ROLPoint2 rol UnderTank1 inw xdraw dec temp bne ByteBelowTank NoGroundCheck ldx TankNr lda Ytankstable,x cmp #screenheight-1 ; tank on lowest position (no falling down) jcs EndOfFall lda UnderTank1 bne NoFallingDown ; Tank falling down ---- lda Parachute and #1 bne ParachutePresent ; decreasing energy ldy #2 ; how much energy to substract if no parachute jsr DecreaseEnergyX ParachutePresent ; check parachute type lda ActiveDefenceWeapon,x cmp #ind_StrongParachute ; strong parachute bne OneTimeParachute ; decreasing energy of parachute ldy #1 ; how much parachute energy to substract jsr DecreaseShieldEnergyX cpy #0 ; is necessary to reduce tenk energy ? beq @+ jsr DecreaseEnergyX @ ; check energy of parachute lda ShieldEnergy,x bne OneTimeParachute lda #$00 sta Parachute sta ActiveDefenceWeapon,x ; deactivate defence OneTimeParachute lda Parachute ora #2 ; we set bit nr 1 (nr 0 means that parachute is present) sta Parachute ; tank is falling down - modify coorinates lda Ytankstable,x clc adc #1 sta Ytankstable,x jmp EndOfFCycle NoFallingDown ; check direction (left or right) ldy #SlideLeftTableLen-1 ; SlideLeftTable length -1 (from 0 to 7) @ lda SlideLeftTable,y cmp UnderTank1 beq FallingLeft cmp UnderTank2 beq FallingRight dey bpl @- bmi NoLeftOrRight FallingRight ; tank is falling right bit PreviousFall ; bit 6 - left bvs EndRightFall ; we finish falling right if the tank reached the edge of the screen lda XtanksTableH,x cmp #>(screenwidth-TankWidth-2) ; 2 pixels correction due to a barrel wider than tank bne @+ lda XtanksTableL,x cmp #<(screenwidth-TankWidth-2) ; 2 pixels correction due to a barrel wider than tank @ bcs EndRightFall NotRightEdge ; tank is falling right - modify coorinates clc lda XtankstableL,x adc #1 sta XtankstableL,x scc inc XtankstableH,x mva #%10000000 PreviousFall ; set bit 7 - right bne EndOfFCycle FallingLeft ; tank is falling left bit PreviousFall ; bit 7 - right bmi EndLeftFall ; we finish falling left if the tank reached the edge of the screen lda XtanksTableH,x bne NotLeftEdge lda XtanksTableL,x cmp #3 ; 2 pixels correction due to a barrel wider than tank bcc EndLeftFall NotLeftEdge ; tank is falling left - modify coorinates sec lda XtankstableL,x sbc #1 sta XtankstableL,x scs dec XtankstableH,x mva #%01000000 PreviousFall ; set bit 6 - left bne EndOfFCycle EndLeftFall EndRightFall NoLeftOrRight inc EndOfTheFallFlag ; after this is shouldn't fall EndOfFCycle ; draw tank on new position jsr DrawTankNr ; ew have TankNr in X (I hope :) ) ; checking is parachute present and if so, draw it lda Parachute cmp #3 ; parachute and falling bne DoNotDrawParachute ; here we draw parachute ; ldx TankNr jsr DrawTankParachute jsr WaitOneFrame ; only if tank with parachute RapidFalling DoNotDrawParachute lda EndOfTheFallFlag jeq TankFallsX ; Tank falling down already finished, but it is not sure that ; the horizontal coordinate is even. ; If it is odd then it must be corrected because otherwise ; P/M graphics background would not look OK ; ldx TankNr ; x correction for P/M ; -- .IF XCORRECTION_FOR_PM = 1 lda XtanksTableL,x and #$01 beq EndOfFall ; if it is even then it is the end ; and if not, we push it one pixel the way it was falling before lda #%10000000 ; set "virtual ground" for right falling ldy #%00000001 bit PreviousFall bmi ForceFallLeft tay ; tricky - replaces ldy #%10000000 lda #%00000001 ; set "virtual ground" for left falling ForceFallLeft sta UnderTank1 sty UnderTank2 jmp TankFallsX .ENDIF ; -- EndOfFall mva #1 Erase ; ldx TankNr ; if tank was falling down having parachute, ; we must deduct one parachute lda Parachute cmp #$03 ; was falling down and the parachute bne NoParachuteWeapon ; first we check type of parachute lda ActiveDefenceWeapon,x cmp #ind_Parachute ; deactivate weapon only if parachute (54) bne NoParachuteWeapon mva #0 ActiveDefenceWeapon,x ; deactivate defence weapon (parachute) NoParachuteWeapon ; now we clear parachute on the screen if present lda Parachute and #01 beq ThereWasNoParachute jsr DrawTankParachute ThereWasNoParachute lda BlackHole ; if Black Hole option is set ... beq NotBlackHole lda Ytankstable,x ; ... and tank has fallen to the bottom ... cmp #screenheight-1 bcc NotBlackHole lda #0 ; ... then the tank disappears. sta eXistenZ,x sta LastExistenZ,x sta Energy,x NotBlackHole ; ldx TankNr jsr PutTankNr ; redraw tank after erase parachute (exactly for redraw leaky schield :) ) mva #sfx_silencer sfx_effect rts .endp ;-------------------------------------------------- .proc ClearPMmemory ;-------------------------------------------------- lda #$00 tay @ sta pmgraph+$300,y sta pmgraph+$400,y sta pmgraph+$500,y sta pmgraph+$600,y sta pmgraph+$700,y iny bne @- rts .endp ;-------------------------------------------------- .proc SoilDown ;-------------------------------------------------- ; how it is supposed to work: ; first loop is looking for the highest pixels ; and fills with their Y coordinates both temporary tables ; ; second (main) loop works this way: ; sets end-of-soil-fall-down-flag to 1 ( IsEndOfTheFallFlag=1 ) ; goes through the horizontal line checking if ; Y coordinate from the first table equals to height of the peak ; if so, it goes further ; if not: ; sets end-of-soil-fall-down-flag to 0 ; increases Y from the first table ; if there is no pixel there it plots here and ; zeroes pixel from the second table and after that ; increases Y of the second table ; repeats with next pixels au to the end of the line ; if the flag is 0 then repeat the main loop ; and that's it :) ; ; I am sorry but after these 4 years I have no idea ; how it works. I have just translated Polish comment ; but I do not understand a word of it :) ; If you know how it works, please write here :)))) jsr ClearTanks NoClearTanks ; Fix for lonely pixel after nuclear winter :) #103 lda #0 sta xdraw sta xdraw+1 sta ydraw sta ydraw+1 sta color jsr plot .IF TARGET >= 800 lda FastSoilDown bne GoFast jsr CheckStartKey ; START KEY bne @+ GoFast jmp SoilDownTurbo.NoClearTanks @ .ENDIF ; First we look for highest pixels and fill with their coordinates ; both tables mwa RangeLeft xdraw adw RangeLeft #mountaintable temp adw RangeLeft #mountaintable2 tempor2 cpw xdraw RangeRight jcs NothingToFall NextColumn1 mwa #0 ydraw NextPoint1 jsr point_plot beq FoundFirstPoint StillNothing inc ydraw lda ydraw cmp #screenheight bne NextPoint1 ; no pixels on whole column !!! FoundFirstPoint ldy #0 lda ydraw sta (tempor2),y sta (temp),y FoundPeek1 inw tempor2 inw temp inw xdraw ;vcmp xdraw,screenwidth,NextColumn1 cpw RangeRight xdraw bcs NextColumn1 ; we have both tables filled with starting values ; main loop starts here MainFallout2 .IF TARGET >= 800 jsr CheckStartKey ; START KEY bne NoFastDown jmp SoilDownTurbo.NoClearTanks NoFastDown .ENDIF mwa RangeLeft xdraw adw RangeLeft #mountaintable temp adw RangeLeft #mountaintable2 tempor2 mva #1 IsEndOfTheFallFlag FalloutOfLine ldy #0 ; is Y coordinate from the first table ; equal to peak height, if so, go ahead lda (tempor2),y cmp #screenheight-1 ;cmp (temp),y bcs ColumnIsReady ; in the other case there are things to be done sty IsEndOfTheFallFlag ; flag to 0 ; we are increasing Y in the first table ;lda (tempor2),y clc adc #1 sta (tempor2),y ; and checking if there is a pixel there sta ydraw jsr point_plot beq ThereIsPixelHere ; if no pixel we plot it mva #1 color jsr plot.MakePlot ; zeroing pixel from the second table ; and increase Y in second table ldy #0 lda (temp),y sta ydraw clc adc #1 sta (temp),y sty color jsr plot.MakePlot mva #sfx_silencer sfx_effect ThereIsPixelHere ColumnIsReady inw temp inw tempor2 inw xdraw ;vcmp xdraw,screenwidth,FalloutOfLine cpw RangeRight xdraw bcs FalloutOfLine jsr CheckExitKeys ; Check for O, Esc or Start+Option keys spl:rts ; exit if pressed 'Exit keys' lda IsEndOfTheFallFlag ; we repeat untill at some point first table reaches ; level of the mountains jeq MainFallout2 ; now correct heights are in the mountaintable ;sta color ; Pozor! :) we know - now A=1 ... but DrawTanks set color to 1 NothingToFall jmp DrawTanks ; rts .endp ;-------------------------------------------------- .proc calculatemountains ;-------------------------------------------------- mwa #0 xdraw ; starting point /* getrandomY ;getting random Y coordinate ; sec ; ??? lda random cmp #screenheight-(margin*4) ;it means that max line=199 bcs getrandomY ; clc ; C is clear adc #(margin*2) sta ydraw sta yfloat+1 */ sta yfloat ;yfloat equals to e.g. 140.0 (A=0) mva #screenheight-margin-5 yfloat+1 sta ydraw ; how to make nice looking mountains? ; randomize points and join them with lines ; Here we do it simpler way - we randomize X (or deltaX) ; and "delta" (change of Y coordinate) NextPart lda random and mountainDeltaL sta delta ; it is after the dot (xxx.delta) lda random and mountainDeltaH ;(max delta) sta delta+1 ; before the dot (delta+1.delta) lda random ; and #$01 ;random sign (+/- or up/down) sta UpNdown ; theoretically we have here ready ; fixed-point delta value ; (-1*(UpNdown.7th.bit))*(delta+1.delta) ;loop drawing one line ChangingDirection lda random ;length of the line and #$0f ;max line length clc adc #3 sta deltaX OnePart jsr placeTanks.CheckTank ; checks if at a given X coordinate ; is any tank and if so ; changes parameters of drawing ; to generate flat 8 pixels ; (it will be the place for the tank) ; it also stores Y position of the tank adw xdraw #mountaintable modify lda ydraw ldy #0 sta (modify),y ; Up or Down bit UpNdown bpl ToBottom ToTop ;it means substracting ;sbw yfloat delta sec lda yfloat sbc delta sta yfloat lda yfloat+1 sbc delta+1 sta yfloat+1 ;lda yfloat+1 cmp #margin bcs @+ ; if smaller than 10 ; ldy #$00 sty UpNdown ; Y=0 jmp @+ ToBottom ;adw yfloat delta clc lda yfloat adc delta sta yfloat lda yfloat+1 adc delta+1 sta yfloat+1 ;lda yfloat+1 cmp #screenheight-margin bcc @+ ; if higher than screen dey ; Y=0 sty UpNdown ; Y=$ff @ sta ydraw inw xdraw cpw xdraw #screenwidth beq EndDrawing dec deltaX bne OnePart jmp NextPart EndDrawing rts .endp /* ;-------------------------------------------------- .proc calculatemountains ; Only for testing - makes ground flat (0 pixels) ; and places tanks on it ; remember to remove in final compilation :) ;-------------------------------------------------- mwa #0 xdraw nextPointDrawing adw xdraw #mountaintable modify lda #screenheight ldy #0 sta (modify),y inw xdraw cpw xdraw #screenwidth bne nextPointDrawing ; 20 first points - max height! mwa #mountaintable modify ldy #20 lda #0 @ sta (modify),y dey bpl @- ldx NumberOfPlayers dex SetYofNextTank lda #screenheight-1 sta ytankstable,x dex bpl SetYofNextTank rts .endp */ ;-------------------------------------------------- .proc CheckMaxMountain ; in A return y coordinate of highest mountain ;-------------------------------------------------- mwa #mountaintable modify ldy #0 ldx #screenheight-1 nextPointChecking txa cmp (modify),y bcc NotHigher lda (modify),y tax NotHigher inw modify cpw modify #(mountaintable+screenwidth) bne nextPointChecking txa rts .endp ;-------------------------------------------------------- .proc DisplayOffensiveTextNr ; ; all text start from `talk` and end with an inverse. ; we go through the `talk`, count number of inverses. ; if equal to TextNumberOff, it is our text, printit lda #0 notZero sta plot4x4color tya tax ; save Y mwa #talk.talk5_data LineAddress4x4 jsr _calc_packed_display ; record starts with length byte ldy #0 lda (LineAddress4x4),y sta fx inw LineAddress4x4 ; point to packed payload txa ; load Y tay jmp Display4x4AboveTankPacked .endp ;-------------------------------------------------------- .proc Display4x4AboveTankPacked ; ; Displays packed texts using PutChar4x4 above tank and mountains. ;parameters are: ;Y - number of tank above which text is displayed ;fx - length of text ;LineAddress4x4 - address of packed payload lda xtankstableL,y sta temp lda xtankstableH,y sta temp+1 jsr Calculate4x4TextPosition jmp TypeLine4x4Packed.noLengthNoColor .endp ;-------------------------------------------------------- .proc Display4x4AboveTank ; ; Displays texts using PutChar4x4 above tank and mountains. ; Pretty cool, eh! ;parameters are: ;Y - number of tank above which text is displayed ;fx - length of text ;LineAddress4x4 - address of the text ;lets calculate position of the text first! ;that's easy because we have number of tank ;and xtankstableL and H keep X position of a given tank lda xtankstableL,y sta temp lda xtankstableH,y sta temp+1 jsr Calculate4x4TextPosition jmp TypeLine4x4.noLengthNoColor ; rts .endp ;-------------------------------------------------------- .proc Calculate4x4TextPosition ; we have X coordinate of center of text in temp ; now we should substract length of the text-1 ; temp2 = (fx-1)*2 ldy fx dey tya asl sta temp2 mva #0 temp2+1 ;now we have HALF length in pixels ;stored in temp2 ;here we assume max length of text ;to display is 127 chars, but later it turns out it must be max 63! sbw temp temp2 ; here begin of the text is in TEMP !!!! ;now we should check overflows ;lda temp+1 ; opty bpl DOTNnotLessThanZero ;less than zero, so should be zero mwa #0 temp beq DOTNnoOverflow ; jmp DOTNnotLessThanZero ;so check if end larger than screenwidth lda fx asl asl ;length in pixels - ;text length max 63 chars !!!!!!!! clc adc temp sta temp2 lda #0 adc temp+1 sta temp2+1 ;now in temp2 is end of the text in pixels ;so check if not greater than screenwitdth cpw temp2 #screenwidth bcc DOTNnoOverflow ;if end is greater than screenwidth ;then screenwidth - length is fine lda fx asl asl sta temp mva #0 temp+1 sec lda #<(screenwidth-1) sbc temp sta temp lda #>(screenwidth-1) sbc temp+1 sta temp+1 DOTNnoOverflow ;here in temp we have really good x position of text mwa temp LineXdraw ;now let's get y position ;we will try to put text as low as possible ;just above mountains (so mountaintable will be checked) lda fx asl asl tay ;in temp there still is X position of text ;if we add temp and Y we will get end of the text ;so, lets go through mountaintable and look for ;the lowest value within ;Mountaitable+temp and Mountaitable+temp+Y adw temp #MountainTable mva #screenheight temp2 ;initialisation of the lowest value DOTLowestMountainValueLoop lda (temp),y cmp temp2 bcs DOTOldLowestValue ;old lowest value ;new lowest value sta temp2 DOTOldLowestValue dey cpy #$ff bne DOTLowestMountainValueLoop sec lda temp2 sbc #(4+9) ;9 pixels above ground (and tanks...) sta LineYdraw rts .endp ;-------------------------------------------------------- .proc DisplayTankNameAbove ; TankNr in X txa ; TankNr :3 asl ; *8 clc adc #Tanksnames sta LineAddress4x4+1 ; TextAddress+1 ;find length of the tank's name ldy #7 @ lda (LineAddress4x4),y bne end_found dey bne @- end_found iny sty fx ldy tankNr jmp Display4x4AboveTank ; rts .endp ;------------------------------- .proc TypeLine4x4 ; ;------------------------------- ;this routine prints line of length `fx` ;address in LineAddress4x4 ;starting from LineXdraw, LineYdraw lda #14 ; default length of 4x4 texts sta fx variableLength lda #$ff ; $ff - visible characters, $00 - clearing staplot4x4color sta plot4x4color noLengthNoColor ldy #0 sty LineCharNr TypeLine4x4Loop ldy LineCharNr lda (LineAddress4x4),y sta CharCode4x4 mwa LineXdraw dx mva LineYdraw dy mva #0 dy+1 ; dy is 2 bytes value jsr PutChar4x4 ;type empty pixels as well! adw LineXdraw #4 inc:lda LineCharNr cmp fx bne TypeLine4x4Loop EndOfTypeLine4x4 rts .endp ;------------------------------- .proc TypeLine4x4Packed ; ;------------------------------- ;this routine prints packed line of length `fx` ;packed payload address in LineAddress4x4 ;starting from LineXdraw, LineYdraw lda #14 ; default length of 4x4 texts sta fx variableLength lda #$ff ; $ff - visible characters, $00 - clearing staplot4x4color sta plot4x4color noLengthNoColor ; init packed bitstream ; Reuse ZP vars: ; - LineAddress4x4 is the packed byte pointer (advanced during decoding) ; - Multiplier/Multiplier_ are used as bit buffer/state lda #0 sta Multiplier sta Multiplier+1 sta Multiplier_ ldy #0 sty LineCharNr TypeLine4x4PackedLoop ldy LineCharNr jsr _packed_get5bits tay lda talk.talk5_alphabet,y sta CharCode4x4 mwa LineXdraw dx mva LineYdraw dy mva #0 dy+1 ; dy is 2 bytes value jsr PutChar4x4 ;type empty pixels as well! adw LineXdraw #4 inc:lda LineCharNr cmp fx bne TypeLine4x4PackedLoop rts .endp ;-------------------------------- ; Packed 5-bit bitstream decoder ; ; Uses a 16-bit shift register where the lowest bits are the next bits to read. ; Bytes are appended little-endian (LSB-first) at bit position PackedBitCount4x4. ;-------------------------------- .proc _packed_get5bits ; ensure at least 5 bits available lda Multiplier_ cmp #5 bcs have_bits ; read next byte and append at current bit count ldy #0 lda (LineAddress4x4),y sta temp2 ; new byte lda #0 sta temp2+1 inw LineAddress4x4 ldx Multiplier_ beq append_ready append_shift asl temp2 rol temp2+1 dex bne append_shift append_ready lda Multiplier ora temp2 sta Multiplier lda Multiplier+1 ora temp2+1 sta Multiplier+1 lda Multiplier_ clc adc #8 sta Multiplier_ have_bits lda Multiplier and #$1f sta temp2 ; shift register right by 5 ldx #5 @ lsr Multiplier+1 ror Multiplier dex bne @- lda Multiplier_ sec sbc #5 sta Multiplier_ lda temp2 rts .endp ;-------------------------------- .proc AreYouSure ;using 4x4 font mva #4 ResultY ; where seppuku text starts Y-wise on the screen ;top frame mva ResultY LineYdraw jsr TL4x4_top adb ResultY #4 ;next line ;sure? mwa #areYouSureText LineAddress4x4 jsr _sep_opty ;bottom frame mva ResultY LineYdraw jsr TL4x4_bottom jsr GetKey cmp #@kbcode._Y ; $2b ; "Y" bne @+ mva #$80 escFlag bne skip01 @ mva #0 escFlag skip01 jsr WaitForKeyRelease ;clean mva #3 di mva #4 ResultY @ mva #$ff plot4x4color mwa #lineClear LineAddress4x4 jsr _sep_opty dec di bne @- quit_areyousure rts .endp .proc _sep_opty mva ResultY LineYdraw jsr TL4x4_empty.go ; center and type line adb ResultY #4 ;next line rts .endp ;-------------------------------- .proc DisplaySeppuku ;using 4x4 font mva #20 fs ; temp, how many times blink the billboard seppuku_loop jsr CheckStartKey ; START KEY sne:mva #1 fs ; finish it mva #4 ResultY ; where seppuku text starts Y-wise on the screen ;top frame mva ResultY LineYdraw jsr TL4x4_top adb ResultY #4 ;next line ;seppuku mwa #seppukuText LineAddress4x4 jsr _sep_opty ;bottom frame mva ResultY LineYdraw jsr TL4x4_bottom ; just go ;clean seppuku mva #3 di ;mva #4 ResultY lda #4 sta ResultY loplop ;@ mwa #lineClear LineAddress4x4 jsr _sep_opty dec di bne loplop ;@- dec fs jne seppuku_loop quit_seppuku rts .endp ; ------------------------------------- .proc SetupXYdraw lda ytankstable,x sta ydraw mva #0 ydraw+1 X lda XtanksTableL,x sta xdraw lda XtanksTableH,x sta xdraw+1 rts .endp ;-------------------------------------------------- .proc DrawBarrel ; X - tankNr ; changes xdraw, ydraw, fx, fy ;-------------------------------------------------- ;vx calculation ;vx = sin(90-Angle) for Angle <=90 ;vx = -sin(Angle-90) for 90 < Angle <= 180 ; erase previous barrel ;cos(Angle) (but we use sin table only so some shenanigans happen) ; mva #0 color ; lda previousBarrelAngle,x ; sta Angle ; jsr DrawBarrelTech ; ; mva #1 color ldx TankNr jsr SetupXYdraw sbw ydraw #3 ydraw ; barell start (Y coordinate) mva #0 goleft lda BarrelLength,x sta yc ; current tank barrel length lda angleTable,x sta Angle ; angle in Angle and A cmp #91 bcc angleUnder90 ;over 90 ;sec - allways set sbc #90 tax ; barrel start offset over 90deg adw xdraw #4 xdraw ; barell start (X coordinate) dec goleft ; $00 -> $ff bmi @+ ; jmp @+ angleUnder90 sec ; X = 90-Angle lda #90 sbc Angle tax ; barrel start offset under 90deg adw xdraw #3 xdraw ; barell start (X coordinate) @ lda sintable,x ; cos(X) sta vx ;======vy ;vy = sin(Angle) for Angle <=90 ;vy = sin(180-Angle) for 90 < Angle <= 180 ;-- lda Angle cmp #91 bcc YangleUnder90 lda #180 sec sbc Angle YangleUnder90 tax lda sintable,x sta vy lda #0 ; all arithmetic to zero sta vx+1 sta vy+1 lda #128 ; ; add 0.5 to fx and fy (not vx and vx) for better rounding - it's my opinion (Pecus) sta fx sta fy ; draw by vx vy ; in each step ; 1. plot(xdraw, ydraw) ; 2. add vx and vy to 3 byte variables xdraw.fx, ydraw.fy ; 3 check length, if shorter, go to 1. ; mva #6 yc ; barrel length barrelLoop bit goleft bmi goright clc lda fx adc vx sta fx bcc @+ lda xdraw adc vx+1 sta xdraw bcc @+ inc xdraw+1 @ jmp ybarrel goright sec lda fx sbc vx sta fx bcs @+ lda xdraw sbc vx+1 sta xdraw bcs @+ dec xdraw+1 @ ybarrel sec lda fy sbc vy sta fy bcs @+ lda ydraw sbc vy+1 sta ydraw bcs @+ dec ydraw+1 @ jsr plot ;.MakePlot dec yc bne barrelLoop mwa xdraw EndOfTheBarrelX mva ydraw EndOfTheBarrelY rts .endp ;-------------------------------------------------- .proc PMoutofScreen ;-------------------------------------------------- lda #$00 ; let all P/M disappear ldy #7 @ sta hposp0,y dey bpl @- ;:8 sta hposp0+# ; optimized... but Y! rts .endp ;-------------------------------------------------- .proc SetPMWidthAndColors lda #%01010101 sta sizem ; all missiles, double width ldy #3 @ lda #$00 sta sizep0,y ; P0-P3 widths lda TankColoursTable,y ; colours of sprites under tanks bit TeamGame bvc no_team lda TankColoursTableT,y ; colours of sprites under tanks for Teams no_team sta PCOLR0,y dey bpl @- LDA TankColoursTable+4 STA COLOR3 ; joined missiles (5th tank) rts .endp .endif