QBasic Rockwars
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

595 lines
16 KiB

  1. 'QBasic Rockwars v1.1, by Brennen Bearnes
  2. 'Version 1.1 has the following changes:
  3. '1. A startup menu with the ability to change game settings.
  4. '2. 3 different types of game.
  5. '3. End screen now asks if you want to play again.
  6. '4. A few small changes and optimizations (I hope).
  7. 'You play the part of the blue castle. You've been attacked by
  8. 'the red castle, who has started sending robotic tanks equipped with
  9. 'a short range death ray at you. Fortunately, you've been hard at work
  10. 'on your own secret weapon, a powerful catapult that can launch rocks
  11. 'all the way to the other side of the screen.
  12. 'How to play:
  13. 'A tank will start coming at you as soon as the game begins. If the
  14. 'red castle is fairly close, then you should shoot the tank first.
  15. 'Every time you blow up a tank, the red castle sends another one,
  16. 'so sooner or later, you'll have to hit the castle. To fire, press
  17. 'F1, and type in the angle (10-180) and velocity (0-100) you want. Be
  18. 'sure to take the wind into account. If the tank gets close enough,
  19. 'then you're toast.
  20. 'Brent P. Newhall did all the code for the explosions, as well as the star
  21. 'field, and a number of other small but effective changes.
  22. 'The little moon orbiting a planet in the background was done
  23. 'by Marco Koegler (and thanks to everyone else that told me how to do it).
  24. 'I figured out how to plot the projectiles from GORILLA.BAS, which I
  25. 'found on an old computer at school.
  26. 'Suggestions are welcome, and if you improve this in any way, please
  27. 'send me a copy.
  28. 'bbearnes@worldnet.att.net
  29. 'http://www.geocities.com/SiliconValley/Park/8994/
  30. ' Brent P. Newhall edited 9/30/96
  31. ' Notes: The explode code now restores the screen to how it looked prior
  32. ' to the explosion. I then added code to erase the bullet and
  33. ' exploded item just after the explosion. I also added the stars.
  34. ' Before, you could enter an angle of zero and just wipe out
  35. ' anything before you. Now the angle can be no less than 10.
  36. ' I've also cleaned up the code a bit, making it more readable,
  37. ' less time- and memory-intensive, etc.
  38. 'Thanks Brent!
  39. DECLARE SUB newTank ()
  40. DECLARE SUB drawTank ()
  41. DECLARE SUB newRock ()
  42. DECLARE SUB drawRock ()
  43. DECLARE SUB explode (green%, blue%, red%, boomX, boomY, boomSize)
  44. CONST pi=3.141592654#
  45. TYPE arctype
  46. Radius AS INTEGER
  47. colr AS INTEGER
  48. p1 AS SINGLE
  49. p2 AS SINGLE
  50. END TYPE
  51. Restart:
  52. 'Variables that control the rock
  53. DIM SHARED rockAngle
  54. DIM SHARED rockSpeed
  55. DIM SHARED startRockX
  56. DIM SHARED startRockY
  57. DIM SHARED oldRockX
  58. DIM SHARED oldRockY
  59. DIM SHARED Rock1Exist
  60. DIM SHARED t 'time
  61. DIM SHARED rockX
  62. DIM SHARED rockY
  63. DIM SHARED startRockXvel
  64. DIM SHARED startRockYvel
  65. DIM SHARED gravity
  66. DIM SHARED wind
  67. 'The castles and tank.
  68. DIM SHARED castle2X
  69. DIM SHARED castleX
  70. DIM SHARED TankExist
  71. DIM SHARED TankX
  72. DIM SHARED oldTankX
  73. DIM SHARED tankSpeed
  74. DIM SHARED castleExist
  75. DIM SHARED Castle2Exist
  76. DIM SHARED x1 AS INTEGER, y1 AS INTEGER, x2 AS INTEGER, y2 AS INTEGER
  77. DIM SHARED TKills AS INTEGER, ShotsFired AS INTEGER, GameType AS INTEGER
  78. DIM SHARED Castle2Hits AS INTEGER
  79. DIM SHARED ExplodeHold(1 TO 10000) AS INTEGER
  80. castleExist=1
  81. Castle2Exist=1
  82. SCREEN 13
  83. GameType=1
  84. menu:
  85. CLS
  86. PRINT TAB(10); "QBasic RockWars v1.1"
  87. PRINT TAB(10); " By Brennen Bearnes"
  88. PRINT
  89. PRINT TAB(10); "1. Game Options"
  90. PRINT TAB(10); "2. Start Game"
  91. PRINT TAB(10); "3. Quit"
  92. DO
  93. LOCATE 7, 10: INPUT ">", menud
  94. LOOP UNTIL menud >=1 AND menud <= 3
  95. SELECT CASE menud
  96. CASE 1
  97. PRINT
  98. INPUT "Gravity (9.8 Default): ", gravinput
  99. PRINT
  100. PRINT "Game type:"
  101. PRINT "1. Red Castle can be destroyed,"
  102. PRINT " unlimited tanks."
  103. PRINT
  104. PRINT "2. Red Castle cannot be destroyed,"
  105. PRINT " limited tanks."
  106. PRINT
  107. PRINT "3. Red Castle takes several hits to"
  108. PRINT " destroy, limited tanks."
  109. PRINT
  110. INPUT ">", GameType
  111. IF GameType > 3 THEN GameType=3
  112. IF GameType < 1 THEN GameType=1
  113. GOSUB menu
  114. CASE 2
  115. PRINT
  116. PRINT "While in the game:"
  117. PRINT "F1 to fire"
  118. PRINT "ESC exits"
  119. PRINT
  120. PRINT "Angles can be between 10 and 180."
  121. PRINT "Velocity can be between 0 and 100."
  122. PRINT "Remember to take the wind into account."
  123. PRINT
  124. PRINT "Enjoy!"
  125. SLEEP
  126. CASE 3
  127. GOSUB Qwit
  128. END SELECT
  129. IF gravinput=0 THEN
  130. gravity=9.8
  131. ELSE
  132. gravity=gravinput
  133. END IF
  134. 'How many hits it takes to kill the red castle, based on GameType
  135. IF GameType=1 THEN
  136. Castle2Hits=1
  137. ELSEIF GameType=2 THEN
  138. Castle2Hits=1
  139. ELSEIF GameType=3 THEN
  140. Castle2Hits=3
  141. END IF
  142. CLS
  143. 'GET the player's castle.
  144. DIM SHARED castle%(15, 15)
  145. LINE (5, 5)-(20, 20), 1, BF
  146. LINE (8, 5)-(10, 7), 0, BF
  147. LINE (12, 5)-(14, 7), 0, BF
  148. LINE (16, 5)-(18, 7), 0, BF
  149. LINE (10, 15)-(15, 20), 0, BF
  150. GET (5, 5)-(20, 20), castle%
  151. CLS
  152. 'GET the computer's castle.
  153. DIM SHARED castle2%(15, 15)
  154. LINE (5, 5)-(20, 20), 4, BF
  155. LINE (8, 5)-(10, 7), 0, BF
  156. LINE (12, 5)-(14, 7), 0, BF
  157. LINE (16, 5)-(18, 7), 0, BF
  158. LINE (10, 15)-(15, 20), 0, BF
  159. GET (5, 5)-(20, 20), castle2%
  160. CLS
  161. 'GET the tank
  162. DIM SHARED tank%(11, 8)
  163. LINE (2, 4)-(10, 6), 2, BF
  164. LINE (5, 1)-(8, 4), 2, BF
  165. LINE (1, 2)-(5, 2), 2
  166. CIRCLE (3, 6), 2, 2
  167. CIRCLE (8, 6), 2, 2
  168. GET (1, 1)-(11, 8), tank%
  169. CLS
  170. 'The tank firing.
  171. DIM SHARED tank2%(11, 8)
  172. LINE (2, 4)-(10, 6), 2, BF
  173. LINE (5, 1)-(8, 4), 2, BF
  174. LINE (1, 1)-(5, 3), 2
  175. CIRCLE (3, 6), 2, 2
  176. CIRCLE (8, 6), 2, 2
  177. GET (1, 1)-(11, 8), tank2%
  178. CLS
  179. 'The center of the planet
  180. planetX=180: planetY = 45
  181. 'Draw the planet
  182. FOR circ%=1 TO 8
  183. CIRCLE (planetX, planetY), circ%, 9
  184. CIRCLE (planetX, planetY + 1), circ%, 9
  185. NEXT circ%
  186. LINE (planetX - 8, planetY)-(planetX + 8, planetY), 4
  187. LINE (planetX - 8, planetY - 2)-(planetX + 8, planetY - 2), 12
  188. LINE (planetX - 7, planetY - 3)-(planetX + 7, planetY - 3), 12
  189. LINE (planetX - 5, planetY - 5)-(planetX + 5, planetY - 5), 4
  190. LINE (planetX - 8, planetY + 3)-(planetX + 8, planetY + 3), 4
  191. LINE (planetX - 6, planetY + 5)-(planetX + 6, planetY + 5), 4
  192. CIRCLE (planetX + 2, planetY + 4), 2, 4
  193. CIRCLE (planetX + 2, planetY + 4), 1, 4
  194. CIRCLE (planetX + 3, planetY + 4), 1, 4
  195. 'Draw the ground
  196. LINE (0, 175)-(320, 175), 10
  197. PAINT (0, 176), 10, 1
  198. 'PUT the castles
  199. castleX=15
  200. PUT (castleX, 159), castle%
  201. RANDOMIZE TIMER
  202. castle2X=INT(RND * 175) + 175
  203. IF castle2X >=285 THEN castle2X = 285
  204. PUT (castle2X, 159), castle2%
  205. 'The code to make the moon "orbit" the planet was done by Marco Koegler
  206. orbitRadius=30 'Radius of the orbit
  207. moonAngle=0 'Initialize the moons angle
  208. oldMoonX=planetX + 75: oldMoonY = planetY
  209. 'Display stars
  210. FOR cnt%=1 TO 75
  211. PSET (INT(RND * 319), INT(RND * 120) + 30), INT(RND * 15 + 15)
  212. NEXT cnt%
  213. 'This is the main program loop.
  214. DO
  215. moonAngle=moonAngle + .5
  216. IF moonAngle=360 THEN moonAngle = 0
  217. theta=moonAngle * (pi / 180)
  218. moonX=planetX + orbitRadius * (COS(theta))
  219. moonY=planetY - orbitRadius * (SIN(theta))
  220. 'Erase old moon
  221. CIRCLE (oldMoonX, oldMoonY), 2, 0
  222. 'Draw new moon
  223. CIRCLE (moonX, moonY), 2, 8
  224. oldMoonX=moonX: oldMoonY = moonY
  225. ptime!=TIMER: WHILE ptime! = TIMER: WEND ' Pause
  226. K$=INKEY$
  227. IF LEN(K$)=2 THEN
  228. SELECT CASE ASC(RIGHT$(K$, 1))
  229. CASE 59 'F1
  230. IF Rock1Exist=0 THEN
  231. newRock
  232. END IF
  233. END SELECT
  234. ELSEIF LEN(K$)=1 THEN
  235. SELECT CASE ASC(K$)
  236. CASE 27: quit=1
  237. END SELECT
  238. END IF
  239. IF Rock1Exist=1 THEN
  240. drawRock
  241. END IF
  242. IF TankExist=0 AND Castle2Exist = 1 THEN
  243. newTank
  244. ELSEIF TankExist=1 THEN
  245. drawTank
  246. END IF
  247. 'Check and see if the player has won or lost yet...
  248. IF castleExist=0 THEN
  249. '"Melt" the screen and end the game if the player loses.
  250. quit=2
  251. END IF
  252. IF GameType=1 AND Castle2Exist = 0 AND TankExist = 0 THEN
  253. quit=3
  254. ELSEIF GameType=2 AND TKills >= 20 THEN
  255. quit=4
  256. ELSEIF GameType=3 THEN
  257. IF TKills >=20 THEN
  258. quit=4
  259. END IF
  260. IF Castle2Exist=0 AND TankExist = 0 THEN
  261. quit=3
  262. END IF
  263. END IF
  264. LOOP UNTIL quit > 0
  265. 'End of main program loop.
  266. 'The game now prints out your score at the end. Makes it seem like you've
  267. 'accomplished something. Or not.
  268. 'One shot is subtracted from ShotsFired if you destroy the red castle.
  269. 'seems only fair.
  270. IF quit=2 THEN 'The ending if you lose.
  271. '"Melt" the screen and end the game if the player loses.
  272. LOCATE 8, 15: PRINT "you lose"
  273. LOCATE 9, 14: PRINT "the end"
  274. LOCATE 14, 10: PRINT "tanks killed: "; TKills
  275. LOCATE 15, 10: PRINT "rocks fired: "; ShotsFired
  276. IF TKills >=1 THEN
  277. LOCATE 16, 10: PRINT "shots per kill: "; ShotsFired / TKills
  278. END IF
  279. SLEEP 2
  280. DIM melt%(3000)
  281. FOR RR=1 TO 3000
  282. RANDOMIZE TIMER
  283. XX=INT(RND * 271)
  284. RANDOMIZE TIMER
  285. YX=INT(RND * 150)
  286. GET (XX, YX)-(XX + 48, YX + 48), melt%
  287. PUT (XX, YX + 1), melt%, PSET
  288. IF INKEY$=CHR$(27) THEN END
  289. NEXT RR
  290. ELSEIF quit=3 THEN
  291. 'The ending if you kill both the tank and castle (Game types 1 and 3).
  292. LOCATE 13, 15: PRINT "you win"
  293. LOCATE 14, 10: PRINT "tanks killed: "; TKills
  294. LOCATE 15, 10: PRINT "rocks fired: "; ShotsFired
  295. LOCATE 16, 10: PRINT "shots per kill: "; ShotsFired / TKills
  296. ELSEIF quit=4 THEN 'The ending if you kill all the tanks.
  297. LOCATE 12, 5: PRINT "The red castle has no tanks left."
  298. LOCATE 13, 5: PRINT "Victory is yours."
  299. LOCATE 15, 10: PRINT "tanks killed: "; TKills
  300. LOCATE 16, 10: PRINT "rocks fired: "; ShotsFired
  301. LOCATE 17, 10: PRINT "shots per kill: "; ShotsFired / TKills
  302. END IF
  303. WHILE INKEY$=""
  304. WEND
  305. CLS
  306. 'Ask player if they want to play again, then send them back to the starting
  307. 'menu.
  308. INPUT "Do you want to play again"; menud$
  309. menud$=UCASE$(menud$)
  310. SELECT CASE menud$
  311. CASE "Y"
  312. quit=0
  313. GOSUB Restart
  314. CASE "N"
  315. PRINT "Thanks for playing!"
  316. GOSUB Qwit
  317. END SELECT
  318. Qwit:
  319. END
  320. SUB drawRock
  321. oldRockX=rockX
  322. oldRockY=rockY
  323. 'Calculate the next position of the rock
  324. rockX=startRockX + (startRockXvel * t) + (.5 * (wind / 5) * t ^ 2)
  325. rockY=startRockY + ((-1 * (startRockYvel * t)) + (.5 * gravity * t ^ 2)) * (200 / 350)
  326. IF rockY >=174 THEN
  327. 'Do an explosion when the rock hits the "ground".
  328. Rock1Exist=0
  329. 'The below code used to go in front of every explosion, 'til I figured out
  330. 'it would be easier to specify the variables when calling the SUB. I'm a
  331. 'little slow sometimes.
  332. 'green%=20
  333. 'blue%=0
  334. 'boomX=rockX
  335. 'boomY=rockY
  336. 'boomSize=6
  337. explode 20, 0, red%, rockX, rockY, 6
  338. CIRCLE (oldRockX, oldRockY), 1, 0 ' Erase rock
  339. ELSEIF rockY >=159 AND rockX >= castle2X AND rockX <= castle2X + 15 THEN
  340. Rock1Exist=0
  341. CIRCLE (oldRockX, oldRockY), 1, 0 ' Erase rock
  342. IF GameType <> 2 THEN
  343. IF GameType=3 OR GameType = 1 THEN
  344. Castle2Hits=Castle2Hits - 1 'Subtracts 1 hitpoint from castle.
  345. END IF
  346. 'Do an explosion if the enemy castle has 0 hit points left
  347. IF Castle2Hits=0 AND Castle2Exist = 1 THEN
  348. ShotsFired=ShotsFired - 1 'Subtract 1 from the players shots fired.
  349. Rock1Exist=0
  350. Castle2Exist=0
  351. explode 0, 0, red%, rockX, rockY, 50
  352. PUT (castle2X, 159), castle2% ' Erase enemy castle
  353. END IF
  354. END IF
  355. ELSEIF rockY >=167 AND rockX >= TankX AND rockX <= TankX + 10 THEN
  356. 'Do an explosion if rock hits the tank.
  357. TKills=TKills + 1 'Add 1 to kill counter.
  358. TankExist=0
  359. Rock1Exist=0
  360. explode 20, 0, red%, TankX, rockY, 30
  361. CIRCLE (oldRockX, oldRockY), 1, 0 ' Erase rock
  362. PUT (INT(TankX), 167), tank%, XOR ' Erase tank
  363. END IF
  364. IF rockX >=319 OR rockX <= 1 THEN
  365. Rock1Exist=0
  366. CIRCLE (oldRockX, oldRockY), 1, 0
  367. END IF
  368. IF Rock1Exist=1 THEN
  369. CIRCLE (oldRockX, oldRockY), 1, 0
  370. CIRCLE (rockX, rockY), 1, 12
  371. ELSEIF Rock1Exist=0 THEN
  372. rockX=0
  373. rockY=0
  374. END IF
  375. t=t + .1
  376. END SUB
  377. SUB drawTank
  378. 'Move the tank, or if the tank is close enough, blow up the player's
  379. 'castle.
  380. tankSpeed=.5
  381. IF TankX > castleX + 60 THEN
  382. 'Make the tank try to avoid the rocks (doesn't work very well, but can
  383. 'make the game a little more challenging).
  384. IF TankX - rockX < 20 AND TankX - rockX > -1 THEN
  385. tankSpeed=-.8
  386. END IF
  387. oldTankX=TankX
  388. TankX=TankX - tankSpeed
  389. ELSEIF TankX <=castleX + 60 THEN
  390. PUT (INT(TankX), 167), tank2%, PSET
  391. SLEEP 1
  392. PALETTE 95, 60
  393. LINE (INT(TankX) - 2, 167)-(castleX + 15, 162), 95
  394. FOR cnt%=1 TO 30
  395. PALETTE 95, INT(RND * 30 + 30)
  396. ptime!=TIMER: WHILE ptime! = TIMER: WEND ' Pause
  397. NEXT cnt%
  398. PALETTE 95, 0
  399. TankExist=0
  400. explode 0, 30, red%, castleX + 15, 162, 50
  401. castleExist=0
  402. END IF
  403. PUT (INT(oldTankX), 167), tank%, XOR
  404. PUT (INT(TankX), 167), tank%, PSET
  405. END SUB
  406. SUB explode (green%, blue%, red%, boomX, boomY, boomSize)
  407. 'This code started as EXPLODE.BAS by Brent P. Newhall. I've only made a
  408. 'few minor changes. The comments are all his.
  409. ''I was thinking about that "I need fire and an exploding graphic" post
  410. ''and came up with this simple explosion program. Any suggestions,
  411. ''comments, etc. are welcome with open arms.
  412. ''NOTES: There are two lines that do not wrap properly; you'll be able to
  413. ''find them easily. Also, NumArcs is set to 100, which does an
  414. ''acceptable explosion on my 486DX2/50 with 8 megs of RAM. You Pentium
  415. ''people should be able to get a much nicer explosion if you set NumArcs
  416. ''equal to 1000 or so.
  417. ''The program sets colors 100 to 131 to varying shades of red, orange,
  418. ''and yellow for the explosive effect, with the nice side-effect that
  419. 'you can theoretically do several explosions at once.
  420. NumArcs=65
  421. DIM arc(1 TO NumArcs) AS arctype
  422. RANDOMIZE TIMER
  423. FOR cnt%=1 TO NumArcs ' Initialise
  424. arc(cnt%).Radius=0
  425. arc(cnt%).p1=RND * 5.8
  426. arc(cnt%).p2=arc(cnt%).p1 + (RND / 2)
  427. arc(cnt%).colr=INT(RND * 5 + 100)
  428. NEXT cnt%
  429. red%=63 ' Start it deep red
  430. FOR cnt%=100 TO 130 ' Change colors
  431. PALETTE cnt%, red% + 256 * green% + 65536 * blue%
  432. IF cnt% <=114 THEN ' Lower red, increase yellow
  433. red%=red% - 2
  434. green%=green% + 2
  435. ELSE ' Lower red and yellow
  436. red%=red% - 2
  437. green%=green% - 2
  438. END IF
  439. NEXT cnt%
  440. PALETTE 131, 0
  441. TimeCnt%=0
  442. x1=boomX - boomSize
  443. IF x1 < 0 THEN x1=0
  444. y1=boomY - boomSize
  445. IF y1 < 0 THEN y1=0
  446. x2=boomX + boomSize
  447. IF x2 > 319 THEN x2=319
  448. y2=boomY + boomSize
  449. IF y2 > 199 THEN y2=199
  450. GET (x1, y1)-(x2, y2), ExplodeHold(1)
  451. DO
  452. TimeCnt%=TimeCnt% + 1
  453. FOR CurrArc%=1 TO NumArcs
  454. IF arc(CurrArc%).Radius > 4 THEN ' Erase previous arc
  455. CIRCLE (boomX, boomY), arc(CurrArc%).Radius - 5, 0, arc(CurrArc%).p1, arc(CurrArc%).p2
  456. END IF
  457. IF arc(CurrArc%).Radius=0 THEN ' Not yet alive
  458. ' About 30% of the time, create a new arc
  459. IF RND > .7 THEN arc(CurrArc%).Radius=1
  460. ELSEIF arc(CurrArc%).colr=131 THEN ' Dead
  461. REM Do Nothing
  462. ELSE
  463. arc(CurrArc%).Radius=arc(CurrArc%).Radius + 1 ' Increase radius
  464. arc(CurrArc%).colr=arc(CurrArc%).colr + 1 ' Increase color
  465. ' Draw arc
  466. CIRCLE (boomX, boomY), arc(CurrArc%).Radius, arc(CurrArc%).colr, arc(CurrArc%).p1, arc(CurrArc%).p2
  467. END IF
  468. NEXT CurrArc%
  469. t!=TIMER: WHILE t! = TIMER: WEND ' Pause
  470. IF TimeCnt% >=boomSize THEN quitExplode = 1
  471. LOOP UNTIL quitExplode > 0
  472. PUT (x1, y1), ExplodeHold(1), PSET
  473. END SUB
  474. SUB newRock
  475. 'Add 1 to shots fired counter.
  476. ShotsFired=ShotsFired + 1
  477. 'initialize the wind, and tell the player.
  478. RANDOMIZE TIMER: windirec=RND * 2:
  479. LOCATE 1, 1: PRINT SPC(30);
  480. IF windirec <=1 THEN
  481. RANDOMIZE TIMER: wind=RND * -10
  482. LOCATE 1, 1: PRINT "wind: "; wind; " "
  483. ELSEIF windirec > 1 THEN
  484. RANDOMIZE TIMER: wind=RND * 10
  485. LOCATE 1, 1: PRINT "wind:"; wind; " "
  486. END IF
  487. 'Get player input for angle and velocity, and initialize the rock.
  488. 'Velocity can range from 0 to 100, and angle can be in between 10 and 180.
  489. LOCATE 2, 1: PRINT "Angle: "
  490. DO
  491. LOCATE 2, 7: PRINT " ";
  492. LOCATE 2, 7: INPUT "", rockAngle
  493. LOOP UNTIL rockAngle >=10 AND rockAngle <= 180
  494. LOCATE 3, 1: PRINT "Velocity: "
  495. DO
  496. LOCATE 3, 10: PRINT " ";
  497. LOCATE 3, 10: INPUT "", rockSpeed
  498. LOOP UNTIL rockSpeed >=0 AND rockSpeed <= 100
  499. LINE (1, 1)-(50, 50), 0
  500. startRockX=castleX + 6
  501. startRockY=157
  502. oldRockX=startRockX
  503. oldRockY=startRockY
  504. Rock1Exist=1
  505. rockAngle=rockAngle / 180 * pi
  506. startRockXvel=COS(rockAngle) * rockSpeed
  507. startRockYvel=SIN(rockAngle) * rockSpeed
  508. t=0
  509. drawRock
  510. END SUB
  511. SUB newTank
  512. 'Initialize tank.
  513. TankExist=1
  514. TankX=castle2X - 12
  515. oldTankX=castle2X - 12
  516. PUT (castle2X, 159), castle2%, PSET
  517. drawTank
  518. END SUB