; 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››