| 1 | ' Q B a s i c G o r i l l a s\r |
| 2 | '\r |
| 3 | ' Copyright (C) Microsoft Corporation 1990\r |
| 4 | '\r |
| 5 | ' Your mission is to hit your opponent with the exploding banana\r |
| 6 | ' by varying the angle and power of your throw, taking into account\r |
| 7 | ' wind speed, gravity, and the city skyline.\r |
| 8 | '\r |
| 9 | ' Speed of this game is determined by the constant SPEEDCONST. If the\r |
| 10 | ' program is too slow or too fast adjust the "CONST SPEEDCONST = 500" line\r |
| 11 | ' below. The larger the number the faster the game will go.\r |
| 12 | '\r |
| 13 | ' To run this game, press Shift+F5.\r |
| 14 | '\r |
| 15 | ' To exit QBasic, press Alt, F, X.\r |
| 16 | '\r |
| 17 | ' To get help on a BASIC keyword, move the cursor to the keyword and press\r |
| 18 | ' F1 or click the right mouse button.\r |
| 19 | '\r |
| 20 | \r |
| 21 | 'Set default data type to integer for faster game play\r |
| 22 | DEFINT A-Z\r |
| 23 | \r |
| 24 | 'Sub Declarations\r |
| 25 | DECLARE SUB DoSun (Mouth)\r |
| 26 | DECLARE SUB SetScreen ()\r |
| 27 | DECLARE SUB EndGame ()\r |
| 28 | DECLARE SUB Center (Row, Text$)\r |
| 29 | DECLARE SUB Intro ()\r |
| 30 | DECLARE SUB SparklePause ()\r |
| 31 | DECLARE SUB GetInputs (Player1$, Player2$, NumGames)\r |
| 32 | DECLARE SUB PlayGame (Player1$, Player2$, NumGames)\r |
| 33 | DECLARE SUB DoExplosion (x#, y#)\r |
| 34 | DECLARE SUB MakeCityScape (BCoor() AS ANY)\r |
| 35 | DECLARE SUB PlaceGorillas (BCoor() AS ANY)\r |
| 36 | DECLARE SUB UpdateScores (Record(), PlayerNum, Results)\r |
| 37 | DECLARE SUB DrawGorilla (x, y, arms)\r |
| 38 | DECLARE SUB GorillaIntro (Player1$, Player2$)\r |
| 39 | DECLARE SUB Rest (t#)\r |
| 40 | DECLARE SUB VictoryDance (Player)\r |
| 41 | DECLARE SUB ClearGorillas ()\r |
| 42 | DECLARE SUB DrawBan (xc#, yc#, r, bc)\r |
| 43 | DECLARE FUNCTION Scl (n!)\r |
| 44 | DECLARE FUNCTION GetNum# (Row, Col)\r |
| 45 | DECLARE FUNCTION DoShot (PlayerNum, x, y)\r |
| 46 | DECLARE FUNCTION ExplodeGorilla (x#, y#)\r |
| 47 | DECLARE FUNCTION Getn# (Row, Col)\r |
| 48 | DECLARE FUNCTION PlotShot (StartX, StartY, Angle#, Velocity, PlayerNum)\r |
| 49 | DECLARE FUNCTION CalcDelay! ()\r |
| 50 | \r |
| 51 | 'Make all arrays Dynamic\r |
| 52 | '$DYNAMIC\r |
| 53 | \r |
| 54 | 'User-Defined TYPEs\r |
| 55 | TYPE XYPoint\r |
| 56 | XCoor AS INTEGER\r |
| 57 | YCoor AS INTEGER\r |
| 58 | END TYPE\r |
| 59 | \r |
| 60 | 'Constants\r |
| 61 | CONST SPEEDCONST = 500\r |
| 62 | CONST TRUE = -1\r |
| 63 | CONST FALSE = NOT TRUE\r |
| 64 | CONST HITSELF = 1\r |
| 65 | CONST BACKATTR = 0\r |
| 66 | CONST OBJECTCOLOR = 1\r |
| 67 | CONST WINDOWCOLOR = 14\r |
| 68 | CONST SUNATTR = 3\r |
| 69 | CONST SUNHAPPY = FALSE\r |
| 70 | CONST SUNSHOCK = TRUE\r |
| 71 | CONST RIGHTUP = 1\r |
| 72 | CONST LEFTUP = 2\r |
| 73 | CONST ARMSDOWN = 3\r |
| 74 | STOP\r |
| 75 | END\r |
| 76 | \r |
| 77 | \r |
| 78 | \r |
| 79 | \r |
| 80 | Player1$, Player2$ - player names\r |
| 81 | ' NumGames - number of games to play\r |
| 82 | SUB PlayGame (Player1$, Player2$, NumGames)\r |
| 83 | DIM BCoor(0 TO 30) AS XYPoint\r |
| 84 | DIM TotalWins(1 TO 2)\r |
| 85 | \r |
| 86 | J = 1\r |
| 87 | \r |
| 88 | FOR i = 1 TO NumGames\r |
| 89 | \r |
| 90 | CLS\r |
| 91 | RANDOMIZE (TIMER)\r |
| 92 | CALL MakeCityScape(BCoor())\r |
| 93 | CALL PlaceGorillas(BCoor())\r |
| 94 | DoSun SUNHAPPY\r |
| 95 | Hit = FALSE\r |
| 96 | DO WHILE Hit = FALSE\r |
| 97 | J = 1 - J\r |
| 98 | LOCATE 1, 1\r |
| 99 | PRINT Player1$\r |
| 100 | LOCATE 1, (MaxCol - 1 - LEN(Player2$))\r |
| 101 | PRINT Player2$\r |
| 102 | Center 23, LTRIM$(STR$(TotalWins(1))) + ">Score<" + LTRIM$(STR$(TotalWins(2)))\r |
| 103 | Tosser = J + 1: Tossee = 3 - J\r |
| 104 | \r |
| 105 | 'Plot the shot. Hit is true if Gorilla gets hit.\r |
| 106 | Hit = DoShot(Tosser, GorillaX(Tosser), GorillaY(Tosser))\r |
| 107 | \r |
| 108 | 'Reset the sun, if it got hit\r |
| 109 | IF SunHit THEN DoSun SUNHAPPY\r |
| 110 | \r |
| 111 | IF Hit = TRUE THEN CALL UpdateScores(TotalWins(), Tosser, Hit)\r |
| 112 | LOOP\r |
| 113 | SLEEP 1\r |
| 114 | NEXT i\r |
| 115 | \r |
| 116 | SCREEN 0\r |
| 117 | WIDTH 80, 25\r |
| 118 | COLOR 7, 0\r |
| 119 | MaxCol = 80\r |
| 120 | CLS\r |
| 121 | \r |
| 122 | Center 8, "GAME OVER!"\r |
| 123 | Center 10, "Score:"\r |
| 124 | LOCATE 11, 30: PRINT Player1$; TAB(50); TotalWins(1)\r |
| 125 | LOCATE 12, 30: PRINT Player2$; TAB(50); TotalWins(2)\r |
| 126 | Center 24, "Press any key to continue"\r |
| 127 | SparklePause\r |
| 128 | COLOR 7, 0\r |
| 129 | CLS\r |
| 130 | END SUB\r |
| 131 | \r |
| 132 | 'PlayGame:\r |
| 133 | ' Plots banana shot across the screen\r |
| 134 | 'Parameters:\r |
| 135 | ' StartX, StartY - starting shot location\r |
| 136 | ' Angle - shot angle\r |
| 137 | ' Velocity - shot velocity\r |
| 138 | ' PlayerNum - the banana thrower\r |
| 139 | FUNCTION PlotShot (StartX, StartY, Angle#, Velocity, PlayerNum)\r |
| 140 | \r |
| 141 | Angle# = Angle# / 180 * pi# 'Convert degree angle to radians\r |
| 142 | Radius = Mode MOD 7\r |
| 143 | \r |
| 144 | InitXVel# = COS(Angle#) * Velocity\r |
| 145 | InitYVel# = SIN(Angle#) * Velocity\r |
| 146 | \r |
| 147 | oldx# = StartX\r |
| 148 | oldy# = StartY\r |
| 149 | \r |
| 150 | 'draw gorilla toss\r |
| 151 | IF PlayerNum = 1 THEN\r |
| 152 | PUT (StartX, StartY), GorL&, PSET\r |
| 153 | ELSE\r |
| 154 | PUT (StartX, StartY), GorR&, PSET\r |
| 155 | END IF\r |
| 156 | \r |
| 157 | 'throw sound\r |
| 158 | PLAY "MBo0L32A-L64CL16BL64A+"\r |
| 159 | Rest .1\r |
| 160 | \r |
| 161 | 'redraw gorilla\r |
| 162 | PUT (StartX, StartY), GorD&, PSET\r |
| 163 | \r |
| 164 | adjust = Scl(4) 'For scaling CGA\r |
| 165 | \r |
| 166 | xedge = Scl(9) * (2 - PlayerNum) 'Find leading edge of banana for check\r |
| 167 | \r |
| 168 | Impact = FALSE\r |
| 169 | ShotInSun = FALSE\r |
| 170 | OnScreen = TRUE\r |
| 171 | PlayerHit = 0\r |
| 172 | NeedErase = FALSE\r |
| 173 | \r |
| 174 | StartXPos = StartX\r |
| 175 | StartYPos = StartY - adjust - 3\r |
| 176 | \r |
| 177 | IF PlayerNum = 2 THEN\r |
| 178 | StartXPos = StartXPos + Scl(25)\r |
| 179 | direction = Scl(4)\r |
| 180 | ELSE\r |
| 181 | direction = Scl(-4)\r |
| 182 | END IF\r |
| 183 | \r |
| 184 | IF Velocity < 2 THEN 'Shot too slow - hit self\r |
| 185 | x# = StartX\r |
| 186 | y# = StartY\r |
| 187 | pointval = OBJECTCOLOR\r |
| 188 | END IF\r |
| 189 | \r |
| 190 | DO WHILE (NOT Impact) AND OnScreen\r |
| 191 | \r |
| 192 | Rest .02\r |
| 193 | \r |
| 194 | 'Erase old banana, if necessary\r |
| 195 | IF NeedErase THEN\r |
| 196 | NeedErase = FALSE\r |
| 197 | CALL DrawBan(oldx#, oldy#, oldrot, FALSE)\r |
| 198 | END IF\r |
| 199 | \r |
| 200 | x# = StartXPos + (InitXVel# * t#) + (.5 * (Wind / 5) * t# ^ 2)\r |
| 201 | y# = StartYPos + ((-1 * (InitYVel# * t#)) + (.5 * gravity# * t# ^ 2)) * (ScrHeight / 350)\r |
| 202 | \r |
| 203 | IF (x# >= ScrWidth - Scl(10)) OR (x# <= 3) OR (y# >= ScrHeight - 3) THEN\r |
| 204 | OnScreen = FALSE\r |
| 205 | END IF\r |
| 206 | \r |
| 207 | \r |
| 208 | IF OnScreen AND y# > 0 THEN\r |
| 209 | \r |
| 210 | 'check it\r |
| 211 | LookY = 0\r |
| 212 | LookX = Scl(8 * (2 - PlayerNum))\r |
| 213 | DO\r |
| 214 | pointval = POINT(x# + LookX, y# + LookY)\r |
| 215 | IF pointval = 0 THEN\r |
| 216 | Impact = FALSE\r |
| 217 | IF ShotInSun = TRUE THEN\r |
| 218 | IF ABS(ScrWidth \ 2 - x#) > Scl(20) OR y# > SunHt THEN ShotInSun = FALSE\r |
| 219 | END IF\r |
| 220 | ELSEIF pointval = SUNATTR AND y# < SunHt THEN\r |
| 221 | IF NOT SunHit THEN DoSun SUNSHOCK\r |
| 222 | SunHit = TRUE\r |
| 223 | ShotInSun = TRUE\r |
| 224 | ELSE\r |
| 225 | Impact = TRUE\r |
| 226 | END IF\r |
| 227 | LookX = LookX + direction\r |
| 228 | LookY = LookY + Scl(6)\r |
| 229 | LOOP UNTIL Impact OR LookX <> Scl(4)\r |
| 230 | \r |
| 231 | IF NOT ShotInSun AND NOT Impact THEN\r |
| 232 | 'plot it\r |
| 233 | rot = (t# * 10) MOD 4\r |
| 234 | CALL DrawBan(x#, y#, rot, TRUE)\r |
| 235 | NeedErase = TRUE\r |
| 236 | END IF\r |
| 237 | \r |
| 238 | oldx# = x#\r |
| 239 | oldy# = y#\r |
| 240 | oldrot = rot\r |
| 241 | \r |
| 242 | END IF\r |
| 243 | \r |
| 244 | \r |
| 245 | t# = t# + .1\r |
| 246 | \r |
| 247 | LOOP\r |
| 248 | \r |
| 249 | IF pointval <> OBJECTCOLOR AND Impact THEN\r |
| 250 | CALL DoExplosion(x# + adjust, y# + adjust)\r |
| 251 | ELSEIF pointval = OBJECTCOLOR THEN\r |
| 252 | PlayerHit = ExplodeGorilla(x#, y#)\r |
| 253 | END IF\r |
| 254 | \r |
| 255 | PlotShot = PlayerHit\r |
| 256 | \r |
| 257 | END FUNCTION\r |
| 258 | \r |
| 259 | 'Rest:\r |
| 260 | ' pauses the program\r |
| 261 | SUB Rest (t#)\r |
| 262 | s# = TIMER\r |
| 263 | t2# = MachSpeed * t# / SPEEDCONST\r |
| 264 | DO\r |
| 265 | LOOP UNTIL TIMER - s# > t2#\r |
| 266 | END SUB\r |
| 267 | \r |
| 268 | 'Scl:\r |
| 269 | ' Pass the number in to scaling for cga. If the number is a decimal, then we\r |
| 270 | ' want to scale down for cga or scale up for ega. This allows a full range\r |
| 271 | ' of numbers to be generated for scaling.\r |
| 272 | ' (i.e. for 3 to get scaled to 1, pass in 2.9)\r |
| 273 | FUNCTION Scl (n!)\r |
| 274 | \r |
| 275 | IF n! <> INT(n!) THEN\r |
| 276 | IF Mode = 1 THEN n! = n! - 1\r |
| 277 | END IF\r |
| 278 | IF Mode = 1 THEN\r |
| 279 | Scl = CINT(n! / 2 + .1)\r |
| 280 | ELSE\r |
| 281 | Scl = CINT(n!)\r |
| 282 | END IF\r |
| 283 | \r |
| 284 | END FUNCTION\r |
| 285 | \r |
| 286 | 'SetScreen:\r |
| 287 | ' Sets the appropriate color statements\r |
| 288 | SUB SetScreen\r |
| 289 | \r |
| 290 | IF Mode = 9 THEN\r |
| 291 | ExplosionColor = 2\r |
| 292 | BackColor = 1\r |
| 293 | PALETTE 0, 1\r |
| 294 | PALETTE 1, 46\r |
| 295 | PALETTE 2, 44\r |
| 296 | PALETTE 3, 54\r |
| 297 | PALETTE 5, 7\r |
| 298 | PALETTE 6, 4\r |
| 299 | PALETTE 7, 3\r |
| 300 | PALETTE 9, 63 'Display Color\r |
| 301 | ELSE\r |
| 302 | ExplosionColor = 2\r |
| 303 | BackColor = 0\r |
| 304 | COLOR BackColor, 2\r |
| 305 | \r |
| 306 | END IF\r |
| 307 | \r |
| 308 | END SUB\r |
| 309 | \r |
| 310 | 'SparklePause:\r |
| 311 | ' Creates flashing border for intro and game over screens\r |
| 312 | SUB SparklePause\r |
| 313 | \r |
| 314 | COLOR 4, 0\r |
| 315 | A$ = "* * * * * * * * * * * * * * * * * "\r |
| 316 | WHILE INKEY$ <> "": WEND 'Clear keyboard buffer\r |
| 317 | \r |
| 318 | WHILE INKEY$ = ""\r |
| 319 | FOR A = 1 TO 5\r |
| 320 | LOCATE 1, 1 'print horizontal sparkles\r |
| 321 | PRINT MID$(A$, A, 80);\r |
| 322 | LOCATE 22, 1\r |
| 323 | PRINT MID$(A$, 6 - A, 80);\r |
| 324 | \r |
| 325 | FOR b = 2 TO 21 'Print Vertical sparkles\r |
| 326 | c = (A + b) MOD 5\r |
| 327 | IF c = 1 THEN\r |
| 328 | LOCATE b, 80\r |
| 329 | PRINT "*";\r |
| 330 | LOCATE 23 - b, 1\r |
| 331 | PRINT "*";\r |
| 332 | ELSE\r |
| 333 | LOCATE b, 80\r |
| 334 | PRINT " ";\r |
| 335 | LOCATE 23 - b, 1\r |
| 336 | PRINT " ";\r |
| 337 | END IF\r |
| 338 | NEXT b\r |
| 339 | NEXT A\r |
| 340 | WEND\r |
| 341 | END SUB\r |
| 342 | \r |
| 343 | 'UpdateScores:\r |
| 344 | ' Updates players' scores\r |
| 345 | 'Parameters:\r |
| 346 | ' Record - players' scores\r |
| 347 | ' PlayerNum - player\r |
| 348 | ' Results - results of player's shot\r |
| 349 | SUB UpdateScores (Record(), PlayerNum, Results)\r |
| 350 | IF Results = HITSELF THEN\r |
| 351 | Record(ABS(PlayerNum - 3)) = Record(ABS(PlayerNum - 3)) + 1\r |
| 352 | ELSE\r |
| 353 | Record(PlayerNum) = Record(PlayerNum) + 1\r |
| 354 | END IF\r |
| 355 | END SUB\r |
| 356 | \r |
| 357 | 'VictoryDance:\r |
| 358 | ' gorilla dances after he has eliminated his opponent\r |
| 359 | 'Parameters:\r |
| 360 | ' Player - which gorilla is dancing\r |
| 361 | SUB VictoryDance (Player)\r |
| 362 | \r |
| 363 | FOR i# = 1 TO 4\r |
| 364 | PUT (GorillaX(Player), GorillaY(Player)), GorL&, PSET\r |
| 365 | PLAY "MFO0L32EFGEFDC"\r |
| 366 | Rest .2\r |
| 367 | PUT (GorillaX(Player), GorillaY(Player)), GorR&, PSET\r |
| 368 | PLAY "MFO0L32EFGEFDC"\r |
| 369 | Rest .2\r |
| 370 | NEXT\r |
| 371 | END SUB\r |
| 372 | \r |
| 373 | \1a |