|
|
- '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
|