; Tank ; Bill Kendrick 2015 Byte Array PMG,PMGM,PMG0,PMG1,CHSET,SC Byte Array Tank=[ INCLUDE "TANKSPR.ACT" ] INCLUDE "TANKMEM.ACT" ; No motion on input except every ; MaxSpd-th frame Byte Spd,MaxSpd ; Players' directions & "been hit" ctr Byte D0,D1,HIT0,HIT1 ; Players' positions Int X0,Y0,X1,Y1 ; Whether to draw player this frame Byte Draw0=[1],Draw1=[1] ; Bullet "alive" counters & directions Byte B0=[0],BD0,B1=[0],BD1 ; Bullet positions Int BX0,BY0,BX1,BY1 ; Explosion sfx counter Byte Expl=[0] ; X/Y deltas (shifted to positive) ; for player & bullet internal X/Y ; locations (which are right-shifted ; to become screen X/Y locations) Int Array Delta=[ 4 0 5 1 6 2 7 3 8 4 7 5 6 6 5 7 4 8 3 7 2 6 1 5 0 4 1 3 2 2 3 1 ] ; Meat of the game, all within a VBI! Proc VBIDrawSprite() Byte I Int OX0,OY0,OX1,OY1 Byte Pointer Src0Ptr,Src1Ptr Byte Pointer PMGY0,PMGY1,PMGYM SAVETEMPS ; Only handle user input & movement ; occasionally Spd=Spd+1 If Spd>=MaxSpd Then Spd=0 ; --- MOVE PLAYER 1 --- OX0=X0 OY0=Y0 ; Spin right or left from joy input ; (or auto spin if hit) If (STICK0 & 8)=0 Or HIT0>0 Then D0=(D0+1)&15 Draw0=1 ElseIf (STICK0 & 4)=0 Then D0=(D0-1)&15 Draw0=1 Fi ; Move forward on joy input ; (if not spinning due to hit) If HIT0=0 And (STICK0 & 1)=0 Then AUDC2=15 ; loud engine sfx X0=X0+Delta(D0 Lsh 1)-4 Y0=Y0+Delta((D0 Lsh 1)+1)-4 ; Don't go off-screen If X0<0 Or X0>604 Or Y0<0 Or Y0>244 Then X0=OX0 Y0=OY0 Else Draw0=1 Fi Else If HIT0>0 Then If HIT0=32 Then ; On first contact w/ bullet, ; fly across the screen in ; direction of enemy's bullet PMGY0=PMG0+16+(Y0 Rsh 2)-2 For I=0 To 7 Do PMGY0(I+2)=0 Od OX0=X0 OY0=Y0 X0=X0+Delta(BD1 Lsh 1)-4 Y0=Y0+Delta((BD1 Lsh 1)+1)-4 If X0<0 Or X0>604 Or Y0<0 Or Y0>244 Then X0=OX0 Y0=OY0 Else Draw0=1 Fi Fi ; Being-hit sfx AUDC2=HIT0 Rsh 2 AUDF2=HIT0 HIT0=HIT0-1 Else ; Low engine idle sfx AUDC2=2 AUDF2=200 Fi Fi ; --- MOVE PLAYER 2 --- ; (see above) OX1=X1 OY1=Y1 If (STICK1 & 8)=0 Or HIT1>0 Then D1=(D1+1)&15 Draw1=1 ElseIf (STICK1 & 4)=0 Then D1=(D1-1)&15 Draw1=1 Fi If HIT1=0 And (STICK1 & 1)=0 Then X1=X1+Delta(D1 Lsh 1)-4 Y1=Y1+Delta((D1 Lsh 1)+1)-4 AUDC4=15 If X1<0 Or X1>604 Or Y1<0 Or Y1>244 Then X1=OX1 Y1=OY1 Else Draw1=1 Fi Else If HIT1>0 Then If HIT1=32 Then PMGY1=PMG1+16+(Y1 Rsh 2)-2 For I=0 To 7 Do PMGY1(I+2)=0 Od OX1=X1 OY1=Y1 X1=X1+(Delta(BD0 Lsh 1)-4) Lsh 3 Y1=Y1+(Delta((BD0 Lsh 1)+1)-4) Lsh 3 If X1<0 Or X1>604 Or Y1<0 Or Y1>244 Then X1=OX1 Y1=OY1 Else Draw1=1 Fi Fi AUDC4=HIT1 Rsh 2 AUDF4=HIT1 HIT1=HIT1-1 Else AUDC4=2 AUDF4=200 Fi Fi Fi ; --- DRAW PLAYER 1 --- If Draw0=1 Then ; Draw shape based on dir tank faces Src0Ptr=Tank+(D0 Lsh 3) ; Draw at tank's Y position PMGY0=PMG0+16+(Y0 Rsh 2)-2 ; Erase above/below, draw in new pos PMGY0(0)=0 PMGY0(1)=0 For I=0 To 7 Do PMGY0(I+2)=Src0Ptr^ Src0Ptr==+1 Od PMGY0(10)=0 PMGY0(11)=0 ; Move to X position HPOSP0=(X0 Rsh 2)+48 Draw0=0 ; Bump backwards if we touch other ; tank, water, or brick If P0PL>0 Or (P0PF&2)=2 Or (P0PF&4)=4 Then OX0=X0 OY0=Y0 X0=X0-((Delta(D0 Lsh 1) Lsh 1)-8) Y0=Y0-((Delta((D0 Lsh 1)+1) Lsh 1)-8) If X0<0 Or X0>604 Or Y0<0 Or Y0>244 Then X0=OX0 Y0=OY0 Else Draw0=1 Fi Fi Fi ; --- DRAW PLAYER 2 --- ; (see above) If Draw1=1 Then Src1Ptr=Tank+(D1 Lsh 3) PMGY1=PMG1+16+(Y1 Rsh 2)-2 PMGY1(0)=0 PMGY1(1)=0 For I=0 To 7 Do PMGY1(I+2)=Src1Ptr^ Src1Ptr==+1 Od PMGY1(10)=0 PMGY1(11)=0 HPOSP1=(X1 Rsh 2)+48 Draw1=0 If P1PL>0 Or (P1PF&2)=2 Or (P1PF&2)=4 Then OX1=X1 OY1=Y1 X1=X1-((Delta(D1 Lsh 1) Lsh 1)-8) Y1=Y1-((Delta((D1 Lsh 1)+1) Lsh 1)-8) If X1<0 Or X1>604 Or Y1<0 Or Y1>244 Then X1=OX1 Y1=OY1 Else Draw1=1 Fi Fi Fi ; --- PLAYER 1 FIRE --- ; If not hit, bullet not already in ; flight, and fire btn press, shoot! If HIT0+HIT1=0 And STRIG0=0 And B0=0 Then ; Set flight time, direction, ; and starting pos B0=64 BD0=D0 BX0=X0+8 BY0=Y0+16 Fi ; --- PLAYER 2 FIRE --- ; (see above) If HIT0+HIT1=0 And STRIG1=0 And B1=0 Then B1=64 BD1=D1 BX1=X1+8 BY1=Y1+16 Fi ; --- PLAYER 1 BULLET --- If B0>0 Then ; Erase in old position ; (missiles shared, so &ing vs ; just setting to 0) PMGYM=PMGM+16+(BY0 Rsh 2) PMGYM(0)=PMGYM(0)&252 ; Move bullet BX0=BX0+Delta(BD0 Lsh 1)-4 BY0=BY0+Delta((BD0 Lsh 1)+1)-4 ; Countdown flight time B0=B0-1 ; Stop bullet immediately if out of ; bounds If BX0<0 Or BX0>604 Or BY0<0 Or BY0>260 Then B0=0 Fi ; Bullet sfx AUDC1=(B0 Rsh 2) ; If still alive, set new X pos ; and draw in new Y pos ; (missiles shared, so %ing vs ; just setting to 1) If B0>0 Then HPOSM0=(BX0 Rsh 2)+48 PMGYM=PMGM+16+(BY0 Rsh 2) PMGYM(0)=PMGYM(0)%1 Fi ; Now that it's drawn in new pos, ; check for detection... ; Touching opponent? Make them ; explode! If M0PL=2 Then B0=1 ;Will die next loop HIT1=32 ; FIXME: Scoring Fi ; Touching brick? Destroy it! If M0PF=2 Then B0=1 ;Will die next loop SC((BY0 Rsh 5)*20+(BX0 Rsh 5))=2 Expl=15 Fi Else HPOSM0=0 Fi ; Prepare for fresh collision ; detection during the next frame HITCLR=0 ; Brick just exploded? Play sfx If Expl>0 Then Expl=Expl-1 CONSOL=RANDOM Fi GETTEMPS XITVBV ; Enable our VBI Proc VBIInit() CRITIC=1 OldVBI=VVBLKD VVBLKD=VBIDrawSprite CRITIC=0 Return ; Disable our VBI Proc ClearVBI() CRITIC=1 VVBLKD=OldVBI CRITIC=0 Return ; Draw a random map Proc DrawMap() Byte I,X,Y,X1,X2,Y1,Y2 Zero(SC,240) ; River going down center(ish) of ; screen X=Rand(10)+5 For Y=0 To 9 Do SC(Y*20+X)=130 If X>0 And Rand(255)<64 Then X=X-1 ElseIf X<19 And Rand(255)<64 Then X=X+1 Fi Od ; Some random brick walls ; FIXME: This sucks For I=0 To 5 Do X1=Rand(20) X2=Rand(20) Y=Rand(10) For X=X1 To X2 Do SC(Y*20+X)=65 Od X=Rand(20) Y1=Rand(10) Y2=Rand(10) For Y=Y1 To Y2 Do SC(Y*20+X)=65 Od Od Return Proc Main() Byte I,B Graphics(2) ; Some space for Player/Missile gfx ; and redefine character set PMG=RAMTOP-16 PMBASE=PMG CHBAS=PMG+8 ; Pointers to tops of PMG memory ; for missiles, P0, and P1 PMG==*256 PMGM=PMG+384 PMG0=PMG+512 PMG1=PMG+640 ; Zero out PMG data Zero(PMG+384,384) ; Zero out charset data CHSET=PMG+2048 Zero(CHSET+1024) ; Chset: Dirt Poke(CHSET+2,2) Poke(CHSET+4,32) Poke(CHSET+7,8) ; Chset: Brick Poke(CHSET+8,251) Poke(CHSET+9,251) Poke(CHSET+10,251) Poke(CHSET+12,223) Poke(CHSET+13,223) Poke(CHSET+14,223) ; Chset: Water/Explosion (the same) For I=16 To 31 Do B=Rand(255) Poke(CHSET+I,B) Od ; Find beginning of screen memory SC=SAVMSC ; PMG config GPRIOR=1 ; All PMGs above playfield SIZEP0=0 ; Narrow P0 SIZEP1=0 ; Narrow P1 SDMCTL=46 ; Std playfield (+2), ; missile DMA (+4), ; player DMA (+4), ; screen DMA (+32) GRACTL=3 ; Enable players & missiles ; Players' starting state D0=0 X0=1 Y0=1 HIT0=0 D1=6 X1=50 Y1=50 HIT1=0 ; Movement speed MaxSpd=3 ; Sound config AUDCTL=0 ; ??? SKCTL=3 ; ??? ; Default sounds AUDF1=40 ; Player 1 engine AUDC1=0 AUDF2=200 ; Player 1 bullet AUDC2=0 AUDF3=30 ; Player 2 engine AUDC3=0 AUDF4=220 ; Player 2 bullet AUDC4=0 ; Screen colors COLOR0=34 ; Yellow dirt COLOR1=70 ; Red bricks COLOR2=172 ; Blue water COLOR3=0 ; Black (unused) COLOR4=192 ; Dark green ground (bkgd) PCOLR0=220 ; Light yellow green P1 PCOLR1=186 ; Light bluegreen P2 ; Set up map & start game VBI DrawMap() VBIInit() ; Main program loop (outside VBI) CH=255 DO ; FIXME: Do anything else? :) UNTIL CH=28 OD ; Exit loop on [Esc] CH=255 ; End game VBI ClearVBI() GRACTL=0 ; Silence sounds AUDCTL=0 SKCTL=3 AUDF1=0 AUDC1=0 AUDF2=0 AUDC2=0 AUDF3=0 AUDC3=0 AUDF4=0 AUDC4=0 Return