'QBasic Rockwars v1.1, by Brennen Bearnes 'Version 1.1 has the following changes: '1. A startup menu with the ability to change game settings. '2. 3 different types of game. '3. End screen now asks if you want to play again. '4. A few small changes and optimizations (I hope). 'You play the part of the blue castle. You've been attacked by 'the red castle, who has started sending robotic tanks equipped with 'a short range death ray at you. Fortunately, you've been hard at work 'on your own secret weapon, a powerful catapult that can launch rocks 'all the way to the other side of the screen. 'How to play: 'A tank will start coming at you as soon as the game begins. If the 'red castle is fairly close, then you should shoot the tank first. 'Every time you blow up a tank, the red castle sends another one, 'so sooner or later, you'll have to hit the castle. To fire, press 'F1, and type in the angle (10-180) and velocity (0-100) you want. Be 'sure to take the wind into account. If the tank gets close enough, 'then you're toast. 'Brent P. Newhall did all the code for the explosions, as well as the star 'field, and a number of other small but effective changes. 'The little moon orbiting a planet in the background was done 'by Marco Koegler (and thanks to everyone else that told me how to do it). 'I figured out how to plot the projectiles from GORILLA.BAS, which I 'found on an old computer at school. 'Suggestions are welcome, and if you improve this in any way, please 'send me a copy. 'bbearnes@worldnet.att.net 'http://www.geocities.com/SiliconValley/Park/8994/ ' Brent P. Newhall edited 9/30/96 ' Notes: The explode code now restores the screen to how it looked prior ' to the explosion. I then added code to erase the bullet and ' exploded item just after the explosion. I also added the stars. ' Before, you could enter an angle of zero and just wipe out ' anything before you. Now the angle can be no less than 10. ' I've also cleaned up the code a bit, making it more readable, ' less time- and memory-intensive, etc. 'Thanks Brent! DECLARE SUB newTank () DECLARE SUB drawTank () DECLARE SUB newRock () DECLARE SUB drawRock () DECLARE SUB explode (green%, blue%, red%, boomX, boomY, boomSize) CONST pi=3.141592654# TYPE arctype Radius AS INTEGER colr AS INTEGER p1 AS SINGLE p2 AS SINGLE END TYPE Restart: 'Variables that control the rock DIM SHARED rockAngle DIM SHARED rockSpeed DIM SHARED startRockX DIM SHARED startRockY DIM SHARED oldRockX DIM SHARED oldRockY DIM SHARED Rock1Exist DIM SHARED t 'time DIM SHARED rockX DIM SHARED rockY DIM SHARED startRockXvel DIM SHARED startRockYvel DIM SHARED gravity DIM SHARED wind 'The castles and tank. DIM SHARED castle2X DIM SHARED castleX DIM SHARED TankExist DIM SHARED TankX DIM SHARED oldTankX DIM SHARED tankSpeed DIM SHARED castleExist DIM SHARED Castle2Exist DIM SHARED x1 AS INTEGER, y1 AS INTEGER, x2 AS INTEGER, y2 AS INTEGER DIM SHARED TKills AS INTEGER, ShotsFired AS INTEGER, GameType AS INTEGER DIM SHARED Castle2Hits AS INTEGER DIM SHARED ExplodeHold(1 TO 10000) AS INTEGER castleExist=1 Castle2Exist=1 SCREEN 13 GameType=1 menu: CLS PRINT TAB(10); "QBasic RockWars v1.1" PRINT TAB(10); " By Brennen Bearnes" PRINT PRINT TAB(10); "1. Game Options" PRINT TAB(10); "2. Start Game" PRINT TAB(10); "3. Quit" DO LOCATE 7, 10: INPUT ">", menud LOOP UNTIL menud >=1 AND menud <= 3 SELECT CASE menud CASE 1 PRINT INPUT "Gravity (9.8 Default): ", gravinput PRINT PRINT "Game type:" PRINT "1. Red Castle can be destroyed," PRINT " unlimited tanks." PRINT PRINT "2. Red Castle cannot be destroyed," PRINT " limited tanks." PRINT PRINT "3. Red Castle takes several hits to" PRINT " destroy, limited tanks." PRINT INPUT ">", GameType IF GameType > 3 THEN GameType=3 IF GameType < 1 THEN GameType=1 GOSUB menu CASE 2 PRINT PRINT "While in the game:" PRINT "F1 to fire" PRINT "ESC exits" PRINT PRINT "Angles can be between 10 and 180." PRINT "Velocity can be between 0 and 100." PRINT "Remember to take the wind into account." PRINT PRINT "Enjoy!" SLEEP CASE 3 GOSUB Qwit END SELECT IF gravinput=0 THEN gravity=9.8 ELSE gravity=gravinput END IF 'How many hits it takes to kill the red castle, based on GameType IF GameType=1 THEN Castle2Hits=1 ELSEIF GameType=2 THEN Castle2Hits=1 ELSEIF GameType=3 THEN Castle2Hits=3 END IF CLS 'GET the player's castle. DIM SHARED castle%(15, 15) LINE (5, 5)-(20, 20), 1, BF LINE (8, 5)-(10, 7), 0, BF LINE (12, 5)-(14, 7), 0, BF LINE (16, 5)-(18, 7), 0, BF LINE (10, 15)-(15, 20), 0, BF GET (5, 5)-(20, 20), castle% CLS 'GET the computer's castle. DIM SHARED castle2%(15, 15) LINE (5, 5)-(20, 20), 4, BF LINE (8, 5)-(10, 7), 0, BF LINE (12, 5)-(14, 7), 0, BF LINE (16, 5)-(18, 7), 0, BF LINE (10, 15)-(15, 20), 0, BF GET (5, 5)-(20, 20), castle2% CLS 'GET the tank DIM SHARED tank%(11, 8) LINE (2, 4)-(10, 6), 2, BF LINE (5, 1)-(8, 4), 2, BF LINE (1, 2)-(5, 2), 2 CIRCLE (3, 6), 2, 2 CIRCLE (8, 6), 2, 2 GET (1, 1)-(11, 8), tank% CLS 'The tank firing. DIM SHARED tank2%(11, 8) LINE (2, 4)-(10, 6), 2, BF LINE (5, 1)-(8, 4), 2, BF LINE (1, 1)-(5, 3), 2 CIRCLE (3, 6), 2, 2 CIRCLE (8, 6), 2, 2 GET (1, 1)-(11, 8), tank2% CLS 'The center of the planet planetX=180: planetY = 45 'Draw the planet FOR circ%=1 TO 8 CIRCLE (planetX, planetY), circ%, 9 CIRCLE (planetX, planetY + 1), circ%, 9 NEXT circ% LINE (planetX - 8, planetY)-(planetX + 8, planetY), 4 LINE (planetX - 8, planetY - 2)-(planetX + 8, planetY - 2), 12 LINE (planetX - 7, planetY - 3)-(planetX + 7, planetY - 3), 12 LINE (planetX - 5, planetY - 5)-(planetX + 5, planetY - 5), 4 LINE (planetX - 8, planetY + 3)-(planetX + 8, planetY + 3), 4 LINE (planetX - 6, planetY + 5)-(planetX + 6, planetY + 5), 4 CIRCLE (planetX + 2, planetY + 4), 2, 4 CIRCLE (planetX + 2, planetY + 4), 1, 4 CIRCLE (planetX + 3, planetY + 4), 1, 4 'Draw the ground LINE (0, 175)-(320, 175), 10 PAINT (0, 176), 10, 1 'PUT the castles castleX=15 PUT (castleX, 159), castle% RANDOMIZE TIMER castle2X=INT(RND * 175) + 175 IF castle2X >=285 THEN castle2X = 285 PUT (castle2X, 159), castle2% 'The code to make the moon "orbit" the planet was done by Marco Koegler orbitRadius=30 'Radius of the orbit moonAngle=0 'Initialize the moons angle oldMoonX=planetX + 75: oldMoonY = planetY 'Display stars FOR cnt%=1 TO 75 PSET (INT(RND * 319), INT(RND * 120) + 30), INT(RND * 15 + 15) NEXT cnt% 'This is the main program loop. DO moonAngle=moonAngle + .5 IF moonAngle=360 THEN moonAngle = 0 theta=moonAngle * (pi / 180) moonX=planetX + orbitRadius * (COS(theta)) moonY=planetY - orbitRadius * (SIN(theta)) 'Erase old moon CIRCLE (oldMoonX, oldMoonY), 2, 0 'Draw new moon CIRCLE (moonX, moonY), 2, 8 oldMoonX=moonX: oldMoonY = moonY ptime!=TIMER: WHILE ptime! = TIMER: WEND ' Pause K$=INKEY$ IF LEN(K$)=2 THEN SELECT CASE ASC(RIGHT$(K$, 1)) CASE 59 'F1 IF Rock1Exist=0 THEN newRock END IF END SELECT ELSEIF LEN(K$)=1 THEN SELECT CASE ASC(K$) CASE 27: quit=1 END SELECT END IF IF Rock1Exist=1 THEN drawRock END IF IF TankExist=0 AND Castle2Exist = 1 THEN newTank ELSEIF TankExist=1 THEN drawTank END IF 'Check and see if the player has won or lost yet... IF castleExist=0 THEN '"Melt" the screen and end the game if the player loses. quit=2 END IF IF GameType=1 AND Castle2Exist = 0 AND TankExist = 0 THEN quit=3 ELSEIF GameType=2 AND TKills >= 20 THEN quit=4 ELSEIF GameType=3 THEN IF TKills >=20 THEN quit=4 END IF IF Castle2Exist=0 AND TankExist = 0 THEN quit=3 END IF END IF LOOP UNTIL quit > 0 'End of main program loop. 'The game now prints out your score at the end. Makes it seem like you've 'accomplished something. Or not. 'One shot is subtracted from ShotsFired if you destroy the red castle. 'seems only fair. IF quit=2 THEN 'The ending if you lose. '"Melt" the screen and end the game if the player loses. LOCATE 8, 15: PRINT "you lose" LOCATE 9, 14: PRINT "the end" LOCATE 14, 10: PRINT "tanks killed: "; TKills LOCATE 15, 10: PRINT "rocks fired: "; ShotsFired IF TKills >=1 THEN LOCATE 16, 10: PRINT "shots per kill: "; ShotsFired / TKills END IF SLEEP 2 DIM melt%(3000) FOR RR=1 TO 3000 RANDOMIZE TIMER XX=INT(RND * 271) RANDOMIZE TIMER YX=INT(RND * 150) GET (XX, YX)-(XX + 48, YX + 48), melt% PUT (XX, YX + 1), melt%, PSET IF INKEY$=CHR$(27) THEN END NEXT RR ELSEIF quit=3 THEN 'The ending if you kill both the tank and castle (Game types 1 and 3). LOCATE 13, 15: PRINT "you win" LOCATE 14, 10: PRINT "tanks killed: "; TKills LOCATE 15, 10: PRINT "rocks fired: "; ShotsFired LOCATE 16, 10: PRINT "shots per kill: "; ShotsFired / TKills ELSEIF quit=4 THEN 'The ending if you kill all the tanks. LOCATE 12, 5: PRINT "The red castle has no tanks left." LOCATE 13, 5: PRINT "Victory is yours." LOCATE 15, 10: PRINT "tanks killed: "; TKills LOCATE 16, 10: PRINT "rocks fired: "; ShotsFired LOCATE 17, 10: PRINT "shots per kill: "; ShotsFired / TKills END IF WHILE INKEY$="" WEND CLS 'Ask player if they want to play again, then send them back to the starting 'menu. INPUT "Do you want to play again"; menud$ menud$=UCASE$(menud$) SELECT CASE menud$ CASE "Y" quit=0 GOSUB Restart CASE "N" PRINT "Thanks for playing!" GOSUB Qwit END SELECT Qwit: END SUB drawRock oldRockX=rockX oldRockY=rockY 'Calculate the next position of the rock rockX=startRockX + (startRockXvel * t) + (.5 * (wind / 5) * t ^ 2) rockY=startRockY + ((-1 * (startRockYvel * t)) + (.5 * gravity * t ^ 2)) * (200 / 350) IF rockY >=174 THEN 'Do an explosion when the rock hits the "ground". Rock1Exist=0 'The below code used to go in front of every explosion, 'til I figured out 'it would be easier to specify the variables when calling the SUB. I'm a 'little slow sometimes. 'green%=20 'blue%=0 'boomX=rockX 'boomY=rockY 'boomSize=6 explode 20, 0, red%, rockX, rockY, 6 CIRCLE (oldRockX, oldRockY), 1, 0 ' Erase rock ELSEIF rockY >=159 AND rockX >= castle2X AND rockX <= castle2X + 15 THEN Rock1Exist=0 CIRCLE (oldRockX, oldRockY), 1, 0 ' Erase rock IF GameType <> 2 THEN IF GameType=3 OR GameType = 1 THEN Castle2Hits=Castle2Hits - 1 'Subtracts 1 hitpoint from castle. END IF 'Do an explosion if the enemy castle has 0 hit points left IF Castle2Hits=0 AND Castle2Exist = 1 THEN ShotsFired=ShotsFired - 1 'Subtract 1 from the players shots fired. Rock1Exist=0 Castle2Exist=0 explode 0, 0, red%, rockX, rockY, 50 PUT (castle2X, 159), castle2% ' Erase enemy castle END IF END IF ELSEIF rockY >=167 AND rockX >= TankX AND rockX <= TankX + 10 THEN 'Do an explosion if rock hits the tank. TKills=TKills + 1 'Add 1 to kill counter. TankExist=0 Rock1Exist=0 explode 20, 0, red%, TankX, rockY, 30 CIRCLE (oldRockX, oldRockY), 1, 0 ' Erase rock PUT (INT(TankX), 167), tank%, XOR ' Erase tank END IF IF rockX >=319 OR rockX <= 1 THEN Rock1Exist=0 CIRCLE (oldRockX, oldRockY), 1, 0 END IF IF Rock1Exist=1 THEN CIRCLE (oldRockX, oldRockY), 1, 0 CIRCLE (rockX, rockY), 1, 12 ELSEIF Rock1Exist=0 THEN rockX=0 rockY=0 END IF t=t + .1 END SUB SUB drawTank 'Move the tank, or if the tank is close enough, blow up the player's 'castle. tankSpeed=.5 IF TankX > castleX + 60 THEN 'Make the tank try to avoid the rocks (doesn't work very well, but can 'make the game a little more challenging). IF TankX - rockX < 20 AND TankX - rockX > -1 THEN tankSpeed=-.8 END IF oldTankX=TankX TankX=TankX - tankSpeed ELSEIF TankX <=castleX + 60 THEN PUT (INT(TankX), 167), tank2%, PSET SLEEP 1 PALETTE 95, 60 LINE (INT(TankX) - 2, 167)-(castleX + 15, 162), 95 FOR cnt%=1 TO 30 PALETTE 95, INT(RND * 30 + 30) ptime!=TIMER: WHILE ptime! = TIMER: WEND ' Pause NEXT cnt% PALETTE 95, 0 TankExist=0 explode 0, 30, red%, castleX + 15, 162, 50 castleExist=0 END IF PUT (INT(oldTankX), 167), tank%, XOR PUT (INT(TankX), 167), tank%, PSET END SUB SUB explode (green%, blue%, red%, boomX, boomY, boomSize) 'This code started as EXPLODE.BAS by Brent P. Newhall. I've only made a 'few minor changes. The comments are all his. ''I was thinking about that "I need fire and an exploding graphic" post ''and came up with this simple explosion program. Any suggestions, ''comments, etc. are welcome with open arms. ''NOTES: There are two lines that do not wrap properly; you'll be able to ''find them easily. Also, NumArcs is set to 100, which does an ''acceptable explosion on my 486DX2/50 with 8 megs of RAM. You Pentium ''people should be able to get a much nicer explosion if you set NumArcs ''equal to 1000 or so. ''The program sets colors 100 to 131 to varying shades of red, orange, ''and yellow for the explosive effect, with the nice side-effect that 'you can theoretically do several explosions at once. NumArcs=65 DIM arc(1 TO NumArcs) AS arctype RANDOMIZE TIMER FOR cnt%=1 TO NumArcs ' Initialise arc(cnt%).Radius=0 arc(cnt%).p1=RND * 5.8 arc(cnt%).p2=arc(cnt%).p1 + (RND / 2) arc(cnt%).colr=INT(RND * 5 + 100) NEXT cnt% red%=63 ' Start it deep red FOR cnt%=100 TO 130 ' Change colors PALETTE cnt%, red% + 256 * green% + 65536 * blue% IF cnt% <=114 THEN ' Lower red, increase yellow red%=red% - 2 green%=green% + 2 ELSE ' Lower red and yellow red%=red% - 2 green%=green% - 2 END IF NEXT cnt% PALETTE 131, 0 TimeCnt%=0 x1=boomX - boomSize IF x1 < 0 THEN x1=0 y1=boomY - boomSize IF y1 < 0 THEN y1=0 x2=boomX + boomSize IF x2 > 319 THEN x2=319 y2=boomY + boomSize IF y2 > 199 THEN y2=199 GET (x1, y1)-(x2, y2), ExplodeHold(1) DO TimeCnt%=TimeCnt% + 1 FOR CurrArc%=1 TO NumArcs IF arc(CurrArc%).Radius > 4 THEN ' Erase previous arc CIRCLE (boomX, boomY), arc(CurrArc%).Radius - 5, 0, arc(CurrArc%).p1, arc(CurrArc%).p2 END IF IF arc(CurrArc%).Radius=0 THEN ' Not yet alive ' About 30% of the time, create a new arc IF RND > .7 THEN arc(CurrArc%).Radius=1 ELSEIF arc(CurrArc%).colr=131 THEN ' Dead REM Do Nothing ELSE arc(CurrArc%).Radius=arc(CurrArc%).Radius + 1 ' Increase radius arc(CurrArc%).colr=arc(CurrArc%).colr + 1 ' Increase color ' Draw arc CIRCLE (boomX, boomY), arc(CurrArc%).Radius, arc(CurrArc%).colr, arc(CurrArc%).p1, arc(CurrArc%).p2 END IF NEXT CurrArc% t!=TIMER: WHILE t! = TIMER: WEND ' Pause IF TimeCnt% >=boomSize THEN quitExplode = 1 LOOP UNTIL quitExplode > 0 PUT (x1, y1), ExplodeHold(1), PSET END SUB SUB newRock 'Add 1 to shots fired counter. ShotsFired=ShotsFired + 1 'initialize the wind, and tell the player. RANDOMIZE TIMER: windirec=RND * 2: LOCATE 1, 1: PRINT SPC(30); IF windirec <=1 THEN RANDOMIZE TIMER: wind=RND * -10 LOCATE 1, 1: PRINT "wind: "; wind; " " ELSEIF windirec > 1 THEN RANDOMIZE TIMER: wind=RND * 10 LOCATE 1, 1: PRINT "wind:"; wind; " " END IF 'Get player input for angle and velocity, and initialize the rock. 'Velocity can range from 0 to 100, and angle can be in between 10 and 180. LOCATE 2, 1: PRINT "Angle: " DO LOCATE 2, 7: PRINT " "; LOCATE 2, 7: INPUT "", rockAngle LOOP UNTIL rockAngle >=10 AND rockAngle <= 180 LOCATE 3, 1: PRINT "Velocity: " DO LOCATE 3, 10: PRINT " "; LOCATE 3, 10: INPUT "", rockSpeed LOOP UNTIL rockSpeed >=0 AND rockSpeed <= 100 LINE (1, 1)-(50, 50), 0 startRockX=castleX + 6 startRockY=157 oldRockX=startRockX oldRockY=startRockY Rock1Exist=1 rockAngle=rockAngle / 180 * pi startRockXvel=COS(rockAngle) * rockSpeed startRockYvel=SIN(rockAngle) * rockSpeed t=0 drawRock END SUB SUB newTank 'Initialize tank. TankExist=1 TankX=castle2X - 12 oldTankX=castle2X - 12 PUT (castle2X, 159), castle2%, PSET drawTank END SUB