Decoded: QBasic Gorillas by Microsoft Corporation (1990) Beginner friendly, line-by-line code walkthrough by MaiZure Original code: http://www.maizure.org/projects/decoded-qbasic-gorillas/GORILLA.BAS With line numbers http://www.maizure.org/projects/decoded-qbasic-gorillas/GORILLA_linenum.txt 1 COMMENT 2 COMMENT 3 COMMENT 4 COMMENT 5 COMMENT 6 COMMENT 7 COMMENT 8 COMMENT 9 COMMENT 10 COMMENT 11 COMMENT 12 COMMENT 13 COMMENT 14 COMMENT 15 COMMENT 16 COMMENT 17 COMMENT 18 COMMENT 19 COMMENT 20 BLANK 21 COMMENT 22 All untyped variables (no suffix symbol) will be treated as integers 23 BLANK 24 COMMENT 25 Declares the subroutine DoSun, which changes the sun's graphic 26 Declares the subroutine SetScreen, which builds palettes for the screen mode 27 Declares the subroutine EndGame, which is never defined in the code 28 Declares the subroutine Center, which centers text in a row 29 Declares the subroutine Intro, which displays the title pop-up 30 Declares the subroutine SparklePause, which creates an animated border 31 Declares the subroutine GetInputs, gets game setup input 32 Declares the subroutine PlayGame, which is the main game loop 33 Declares the subroutine DoExplosion, which makes banana hit explosions 34 Declares the subroutine MakeCityScape, which creates the city buildings 35 Declares the subroutine PlaceGorillas, which finds a place for players 36 Declares the subroutine UpdateScores, which changes player scores 37 Declares the subroutine DrawGorilla, which draws the players 38 Declares the subroutine GorillaIntro, which shows the intro screen 39 Declares the subroutine Rest, which defines a busy-waiting sleep 40 Declares the subroutine VictoryDance, which draw a win animation 41 Declares the subroutine ClearGorillas, which is never defined or called 42 Declares the subroutine DrawBan, which draws a frame of animated bananas 43 Declares the function Scl, which rescales input numbers for CGA mode 44 Declares the function GetNum, which gets user input as integers 45 Declares the function DoShot, which reads input to fire bananas 46 Declares the function ExplodeGorilla, which animates player death 47 Declares the function Getn, which is never defined or called in the code 48 Declares the function PlotShot, which performs physics and hit detection 49 Declares the function CalcDelay, which measures user machine speed 50 BLANK 51 COMMENT 52 COMMENT 53 BLANK 54 COMMENT 55 Defines the user type XYPoint, used for coordinates. This is similar to a C struct. We will soon define arrays of coordinates typedef'd to XYPoint 56 XCoor is an integer memry of XYPoint. Defines an x-coordinate in a point 57 YCoor is an integer memry of XYPoint. Defines an y-coordinate in a point 58 End the XYPoint definition 59 BLANK 60 COMMENT 61 Defines overall game speed constant reference. Higher is faster 62 Defines 'True' as -1. This is typical in BASIC. 63 Defines 'False' as logical inverse of True. Portable! (oh...it's DOS) 64 Defines a state flag detecting if the player hit themselves 65 Defines the background color (Nevermind the color value here, most colors are replaced by a custom palette during game init) 66 Defines the color of the gorillas to 1. 1 is redefined latr 67 Defines the color of the building windows 68 Defines the color of the sun 69 Defines the sun happy state as 0. This is NOT the initial start state. 70 Defines the sun angry state as -1. Both states different for drawing 71 Defines a gorilla drawing state for right arm up 72 Defines a second gorilla drawing state for left arm up 73 Defines a third gorilla drawing state for no arms. This is most common 74 BLANK 75 COMMENT 76 Global array holding the gorilla X positions 77 Global array holding the gorilla Y positions 78 Global variable holding the index of a city building 79 BLANK 80 Global variable holding Pi. This is not declared as a constant because Pi is later defined with the arctan function. In BASIC (at this time), constants must use literals 81 Defines long integer arrays of image data for banama animation frames. For now, we don't give an explicit array size 82 Defines an integer array of a single gorilla image (arms down) 83 Defines an integer array of a single gorilla image (left arm up) 84 Defines an integer array of a single gorilla image (right arm up) 85 BLANK 86 Defines a global for the gravity. Player can configure this at start 87 Defines a global variable for the wind speed 88 BLANK 89 COMMENT 90 Defines a global variable holding the screen height in pixels 91 Defines a global variable holding the screen width in pixels 92 Defines a global variable holding the screen mode (1 = CGA, 9 = EGA) 93 Defines a global variable holding the maximum text columns 94 BLANK 95 COMMENT 96 Defines a global variable holding explosion color (depends on mode) 97 Defines a global variable holding the sun color (depends on mode) 98 Defines a global variable holding the background color (depends on mode) 99 Defines a global flag set if a banana collides with the sun 100 BLANK 101 Defines a global variable holding the height of the sun 102 Defines a global variable holding the height of a gorilla 103 Defines a global single-precision float for a game speed scaling factor 104 BLANK 105 Defines a function to return a random integer between 1 and the input NOTE ON BIOS ACCESS IN QBASIC BIOS Data in DOS can be accessed in BASIC via PEEK & POKE by pointing to the base memory segment 0 and offsetting 1024 bytes (0x400). BIOS data occupies the next 256 bytes (1024-1280 / 0x400-0x4FF). The first keyboard status byte is offset 0x17 from BIOS start -- at raw memory address 0x417. The bits of this byte mean the following: Bit 0 - Right-Shift status Bit 1 - Left-Shift status Bit 2 - Control key status Bit 3 - Alt key status Bit 4 - ScrollLock key status Bit 5 - NumLock key status Bit 6 - CapsLock key status Bit 7 - Insert key status For more information about the BIOS Data map in DOS, see: http://www.bioscentral.com/misc/bda.htm 106 Sets the current memory segment (pointer) to 0 for upcoming memory operation (PEEK/POKE). Offset 0 is the DOS interrupt vector table and BIOS Data starts 1024 bytes later. 107 Saves a variable to of the current keyboard status at address 0x417. 108 Masks bit 5 of the keyboard status register and checks the value 109 Asserts bit 5 at address 0x417, turning on numlock 110 Ends BIOS check block 111 Resets segment to default data 112 BLANK 113 Calls subroutine InitVars to set up the game 114 Calls the Intro procedure to display title 115 Calls GetInput so the player can set up the game 116 Sets up the player names based on user input 117 Starts the main game loop with the player settings 118 BLANK 119 Sets memory segment to base 120 Restores the previously saved keyboard state 121 Resets segment to default data 122 Ends the game 123 BLANK 124 BLANK NOTE ON IMAGE STORED AS DATA IN BASIC QBasic image data can be stored in integer arrays. Gorillas supports both CGA and EGA graphics (screen mode 1 and 9). CGA graphics allocates 2 bits per pixel while EGA allocates 1 bit per pixel per channel (plane). In general, the first 4 bytes determines the dimensions of the image while the subsequent data is stored little-endian, MSB to LSB, row-major, top-to bottom. One caveat is that when the image pixels change to a new row, the remainder of the byte is dropped and you change rows and bytes. It's generally much easier to draw the picture, capture the data array with GET and ignore the values. Here in Gorilla, the developers hardcoded the image in the following data streams. 125 Jump label to define the CGA graphics for the banana frames 126 COMMENT 127 Defines data for a (3x5) image of the banana facing left CGA frame 128 COMMENT 129 Defines data for a (5x3) image of the banana facing down CGA frame 130 COMMENT 131 Defines data for a (5x3) image of the banana facing up CGA frame 132 COMMENT 133 Defines the (3x5) image of the banana facing right CGA frame 134 BLANK 135 Jump label to define the EGA graphics for the banana frames 136 COMMENT 137 Defines the (6x7) image for the banana facing left EGA frame 138 COMMENT 139 Defines the (9x4) image for the banana facing down EGA frame 140 COMMENT 141 Defines the (9x4) image for the banana facing up EGA frame 142 COMMENT 143 Defines the (6x7) image for the banana facing right EGA frame 144 BLANK PROCEDURE TO INITIALIZE MEMORY, VIDEO, AND ASSETS 145 Defines a jump label to initialize game variables 146 Pi is 4 * the arctangent of 1 147 BLANK 148 COMMENT 149 Defines an error trapping procedure to handle upcoming screen mode tests 150 Sets the mode variable to 9 151 Sets the screen to mode. Initially it's 9 (EGA) If this fails then we'll jump to line 210 and attempt to set the screen mode 1 for CGA graphics. If this fails, then the program will exit. 152 Sets another error trapping procedure for palette testing 153 Attempts to define a palette that requires 64KB of EGA 154 Clears error trapping procedures 155 BLANK 156 Defines variable Machspeed as the result of Calcdelay. This is a floating point scaling factor for game speed 157 BLANK 158 Check if the screen mode is EGA.. EGA SETTINGS 159 Define variable for the screen width (640) 160 Define variable for the screen height (350) 161 Define varaible for the gorilla height (25) 162 Sets the data pointer to EGABanana 163 Define the size of the array for each banana frame. In this case, nine 4-byte integers. 164 BLANK 165 Loop through the 9 integers 166 Read in the data that forms the banana facing left image 167 Continue with the next integer 168 BLANK 169 Loop through the 9 integers 170 Read in the data that forms the banana facing down image 171 Continue with the next integer 172 BLANK 173 Loop through the 9 integers 174 Read in the data that forms the banana facing up image 175 Continue with the next integer 176 BLANK 177 Loop through the 9 integers 178 Read in the data that forms the banana facing right image 179 Continue with the next integer 180 BLANK 181 Define the sun height (39 in EGA) 182 BLANK 183 End EGA settings 184 BLANK CGA SETTINGS 185 Define variable for the screen width (320) 186 Define variable for the screen height (200) 187 Define varaible for the gorilla height (12) 188 Sets the data pointer to CGABanana 189 Define the size of the array for each banana frame. In this case, three 4-byte integers. 190 Redefine the gorilla images to size 20 for CGA. Originally 120 in EGA 191 BLANK 192 Loop through the 3 integers 193 Read in the data that forms the banana facing left image 194 Continue with the next integer 195 Loop through the 3 integers 196 Read in the data that forms the banana facing left image 197 Continue with the next integer 198 Loop through the 3 integers 199 Read in the data that forms the banana facing left image 200 Continue with the next integer 201 Loop through the 3 integers 202 Read in the data that forms the banana facing left image 203 Continue with the next integer 204 BLANK 205 Slows down the game slightly to account for reduced resolution. Moving 5px in CGA goes a lot further than 5px in EGA 206 Defines the sun height (20 in CGA) 207 End CGA Settings 208 Return to main calling function on line 113 209 BLANK SCREEN MODE ERROR HANDLER 210 Define a jump label for the screen mode error handler 211 If we're handling a mode error and the mode is already 1... 212 Then clear the screen 213 Move the text cursor to position Y=10, X=5 214 Print that the game in incompatible with this computer 215 End the program 216 Otherwise the screen mode is EGA so.. 217 Set the screen mode variable to 1 (CGA) 218 Return to the faulty command and retry it - line 151 219 End screen mode error handler 220 BLANK EGA PALETTE ERROR HANDLER 221 Define a jump label for the EGA 64k palette error handler 222 Sets the screen mode to CGA 223 Returns to the line following the faulty line - line 154 224 BLANK 225 Sets all arrays to static allocation at load time 226 COMMENT 227 COMMENT FUNCTION FOR CALCULATING SYSTEM SPEED 228 Defines the function CalcDelay that returns the number of program ticks that it takes to reach a half second. 229 BLANK 230 Sets a temporary variable to the current application timer. This timer returns the number of seconds past midnight with short precision 231 Start a loop 232 Increments another temporary variable. In BASIC it is legal to use a variable in an expression before declaration. It declared it to zero immediately. 233 Continue the loop until the first tick beyond a half second. Note that this does busy-wait the application 234 Sets the function return to the new counter. 235 BLANK 236 Ends CalcDelay. Note that the return value is stored as a short even though the value returned is effectively an integer. 237 BLANK 238 COMMENT 239 COMMENT 240 COMMENT 241 COMMENT 242 COMMENT 243 COMMENT SUBROUTINE FOR CENTERING TEXT 244 Defines the subroutine that centers input text on an input line 245 Saves the middle point based on previous variable for number of columns 246 Moves the text cursor to the target row and half the text length left, plus a half letter 247 Prints the text 248 Ends the sub center text sub 249 BLANK 250 COMMENT 251 COMMENT 252 COMMENT 253 COMMENT 254 COMMENT SUBROUTINE FOR EXPLOSIONS 255 Defines the subroutine to create explosions when a banana hits buildings 256 BLANK 257 Play background music in 32nd notes of the lowest octave: E-F-G-E-F-D-C 258 Explosion radius should be 1/50th of the screen height 259 Define separate explosion growth step sizes based on screen mode 260 Loop on drawing concentric circles in step sizes 261 Draw a circle based on current loop interation and the explosion color 262 Continue loop to next explosion circle 263 Loop on clearing the explosion circle in reverse from large to small 264 Draw the circles with the background color, clearing away the buildings 265 Loop again for a delay 266 Iterator the empty loop 267 Delay for 5/1000 of a game tick. Creates a delay effect in clearing 268 Continue drawing the next clearing circle 269 End the sub 270 BLANK 271 COMMENT 272 COMMENT 273 COMMENT 274 COMMENT 275 COMMENT 276 COMMENT 277 COMMENT FUNCTION FOR PLAYER SHOTS 278 Declares the function for player shots that returns true if player hits 279 BLANK 280 COMMENT 281 Check if player 1 is active 282 Set the text cursor column to the far left 283 Otherwise, it's player 2 284 If we're in EGA then.. 285 Text input cursor is in column 66 on the far right 286 Otherwise, we're in CGA 287 So the far right column is only 26 288 End screen mode check 289 End column check 290 BLANK 291 Move the text cursor to the calculated column, row 2 292 Print input angle label 293 Get user input number for firing angle at 7 spaces in front of text 294 BLANK 295 Move text cursor to the calculated column, row 3 296 Print input speed label 297 Get user input number for firing speed at 10 spaces in front of text 298 BLANK 299 If it's player two.. 300 Get the supplementary angle because player two fires to the left 301 End player number check 302 BLANK 303 COMMENT 304 Start a loop of 4, one for each line of user input 305 Move the text cursor to the target line and the for left 306 Print 30 spaces if EGA or 15 spaces if CGA 307 Move the text cursor to Column 50 if EGA or column 25 if CGA 308 Print 30 or 15 spaces depending on screen mode 309 Continue loop to next row 310 BLANK 311 Resets the sun hit flag 312 Execute PlotShot (the shot loop) and save the return condition. This line executes while the banana is in flight 313 Checks the result of the shot. If no player was hit then... 314 This function will return false 315 If a player was hit (could be either player) 316 This function will return true 317 Set the player number to the player that survived 318 Perform the victory sequence for the survivor 319 End the hit check 320 BLANK 321 End the subroutine 322 BLANK 323 COMMENT 324 COMMENT 325 COMMENT 326 COMMENT 327 COMMENT 328 SUBROUTINE FOR DRAWING THE SUN 329 BLANK 330 COMMENT 331 Sets the sun's x and y screen position to top center. Uses the built in scaling routine to handle CGA mode resolution differences 332 BLANK 333 COMMENT 334 Draws over the old sun with a box colored like the background 335 BLANK 336 COMMENT 337 COMMENT 338 Draws the sun circle with the sun color 339 Fills the circle with the color 340 BLANK 341 COMMENT 342 Draws the sun ray from 9 o'clock to 3 o'clock 343 Draws another sun ray 344 BLANK 345 Draws another sun ray 346 Draws another sun ray 347 BLANK 348 Draws another sun ray 349 Draws another sun ray 350 BLANK 351 Draws another sun ray 352 Draws another sun ray 353 BLANK 354 COMMENT 355 If the sun state is angry (it was hit by a banana) 356 Then draw a mouth circle 357 Fill in the mouth circle 358 Otherwise the sun has a smile 359 Draw a smile using a partial circle from about 8 o'clock to 4 o'clock 360 End mouth check 361 BLANK 362 COMMENT 363 Draw a circle for the sun's left eye 364 Draw a circle for the sun's right eye 365 Fill the left eye circle with a single pixel 366 Fill the left eye circle with a single pixel 367 BLANK 368 End the sun subroutine 369 BLANK 370 COMMENT 371 COMMENT 372 COMMENT 373 COMMENT 374 COMMENT 375 COMMENT 376 COMMENT SUBROUTINE FOR DRAWING ANIMATED BANANAS 377 Defines the subroutine for drawing a single frame of in-flight bananas 378 BLANK 379 Compares the input rotation option 380 If the input rotation is 0... 381 Check if this is to draw or clear (PSET or XOR). If we're drawing then PUT the left-facing banana data array at the given coordinates using PSET. If we're clearing, then put the same banana data at the given coordinates using XOR. PSET copies source bits to the destination, while XOR performs a logical exclusive or between the source and the destination. In a general sense, the XOR should erase everything, but the Qbasic implementation restores the background 382 If the input rotation is 1... 383 Check if we're drawing or clearing the up-facing banana 384 If the input rotation is 2... 385 Check if we're drawing or clearing the down-facing banana 386 If the input rotation is 3... 387 Check if we're drawing or clearing the right-facing banana 388 End rotation check 389 BLANK 390 End of banana animation subroutine 391 BLANK 392 COMMENT 393 COMMENT 394 COMMENT 395 COMMENT 396 COMMENT 397 COMMENT 398 COMMENT SUBROUTINE FOR DRAWING GORILLAS 399 Define the subroutine for drawing gorillas, including animations. The overall idea here is that we pre-draw all of the gorilla frames and capture them for later use. The clever part of this is that the originally gorilla drawing happens as part of the introduction sequence and appears part of the game, and now just random initialization stream of images. 400 Declares a single precision variable that we'll use to control sub-pixel precision animations 401 BLANK 402 COMMENT 403 Draws the larger square that makes up the gorilla head 404 Draws the thin, but wider part of the middle of the head 405 BLANK 406 COMMENT 407 Draws that awesome gorilla unibrow 408 BLANK 409 COMMENT 410 If we're in EGA mode... 411 Then loop twice 412 Draw one pixel of the left eye 413 Draw one pixel of the right eye 414 Loop to the next pixel 415 End the EGA drawing 416 BLANK 417 COMMENT 418 Draw a single horizontal line for the neck connection 419 BLANK 420 COMMENT 421 Draw a wide square for the chest 422 Draw a more narrow square for the lower torso 423 BLANK 424 COMMENT 425 Loops 5 times to draw legs 426 Draws a partial ellipse for the left leg. This loop sweeps it from left to right 427 Draw another partial ellipse for the right leg 428 Continue to the next loop 429 BLANK 430 COMMENT 431 Draw a partial circle for the left chest outline 432 Draw a partial circle for the right chest outline 433 BLANK 434 Set up a loop of 5 steps with the same idea as the legs 435 Compare the case for the arms (right, left, and neither up) 436 If the right arm is up.. 437 COMMENT 438 Draw the left arm down by sweeping a partial ellipse left to right 439 Draw the right arm up by sweeping a partial ellipse left to right 440 Save the current image in to the gorilla right image array 441 If the left arm is up... 442 COMMENT 443 Draw the left arm up by sweeping a partial ellipse left to right 444 Draw the right arm down by sweeping a partial ellipse left to right 445 Save the current image in to the gorilla left image array 446 If both arms are down... 447 COMMENT 448 Draw the left arm down by sweeping a partial ellipse left to right 449 Draw the right arm down by sweeping a partial ellipse left to right 450 Save the current image in to the gorilla down image array 451 End gorilla state cases 452 Continue with next loop 453 End drawing subroutine 454 BLANK 455 COMMENT 456 COMMENT 457 COMMENT 458 COMMENT FUNCTION FOR PLAYER DEATH EXPLOSIONS 459 Defines function for the exploding Gorilla 460 Defines X variable to offset from gorilla origin to explodsion center 461 Defines Y variable to offset from gorilla origin to explodsion center 462 Calculates an X dimension scaling factor based on smallest mode (CGA) 463 Calculates an Y dimension scaling factor based on smallest mode (CGA) 464 Shortcut to determine which player was hit. Player 1 is on the left 465 Plays background music, 1st octave, 16th nodes E-F-G-E-F-D-C 466 BLANK 467 Loops through drawing explosion ellipse 8 for CGA, 16 for EGA 468 Draws a magenta elipse at the bottom of the gorilla. Start of explosion 469 Draws a magenta horizontal line and iterates it to draw a box 470 Next loop iteration 471 BLANK 472 Loops through drawing explosion ellipse 16 for CGA, 32 for EGA 473 Draws a clear (background color) ellipse at the base of the gorilla 474 Draws a series of growing ellipses that alternate colors from the center 475 Next loop iteration 476 BLANK 477 Loops through drawing the destruction ellipse, 24 for CGA, 48 for EGA. This starts from largest to smallest 478 Draws a shrinking ellipse centered on the gorilla with the background color 479 Loop for a small delay (slower than the original explosion drawing) 480 Continue the delay loop 481 Next loop iteration 482 BLANK 483 Set the function to the destroyed gorilla 484 End the function 485 BLANK 486 COMMENT 487 COMMENT 488 COMMENT 489 COMMENT 490 COMMENT SUBROUTINE FOR GAME SETTINGS 491 Defines subroutine to get user input during game set up 492 Sets text color to light grey and background to zero (Still mode 0 now) 493 Clears the screen 494 BLANK 495 Sets the text cursor about a third of way down the screen and indented 496 Prints a prompt and reads user input. LINE INPUT has a 255 char limit 497 If no input was received... 498 Set the default player name to Player 1 499 Otherwise some input was received... 500 Use the first 10 characters of input as the player 1 name 501 End player 1 name check 502 BLANK 503 Move the text cusor down 2 lines 504 Prints a prompt and reads user input. LINE INPUT has a 255 char limit 505 If no input was received... 506 Set the default player name to Player 2 507 Otherwise some input was received... 508 Use the first 10 characters of input as the player 2 name 509 End player 2 name check 510 BLANK 511 Begin a loop until the input number makes sense (positive less than 100) 512 Clear a line - move text cursor down the screen and print 25 spaces 513 Move the text cursor back to the beginning of the line 514 Prompt the player for the number of desired games 515 Set the number of games to the number of the first 2 characters input 516 Repeat the loop until valid 517 If no input was received then default to 3 games 518 BLANK 519 Begin a loop until the input number makes sense (positive gravity) 520 Clear a line - move text cursor down the screen and print 28 spaces 521 Reset the cusor on the line 522 Prompt the player for gravity level 523 Recast the input to a double precision 524 Repeat loop until the input is valid 525 Set default gravity to 9.8 is user doesn't input anything 526 End the user input subroutine 527 BLANK 528 COMMENT 529 COMMENT 530 COMMENT 531 COMMENT FUNCTION FOR USER NUMBER INPUT 532 Define a function that returns numbers input by the user 533 Sets a blank string to hold a result 534 Sets a loop invariant to false 535 Clears the keyboard buffer 536 BLANK 537 Kick off a loop while the defined invariant is false 538 BLANK 539 Sets the cursor to the requested X and Y position 540 Prints the user input with an underscore as a cursor plus blank space 541 BLANK 542 Reads the last input 543 Checks the input 544 If the input is a numeric character... 545 Then append the input to the current result 546 If the input is a period (decimal point)... 547 Check if there isn't already a period in the result 548 And add the period to the current result 549 End check for double period 550 If the input character is a carriage return 551 Check if the current result is greater than 360 552 If so, clear the input 553 Otherwise... 554 End the loop, accepting the input result 555 End check for large input 556 Check if the input is backspace 557 If the result already has some valid input... 558 Remove the most recent input 559 End check for valid input 560 If the input is anything else.. 561 If there is is any keyboard input at all.. 562 Generate a Beep with the PC speaker 563 End keyboard input check 564 End all input evaluation 565 Loop on unresolved input 566 BLANK 567 Move the cusor to the desired target location 568 Print the final result 569 BLANK 570 Set the function to the final result cast as a double precision 571 End the function 572 BLANK 573 COMMENT 574 COMMENT 575 COMMENT 576 COMMENT 577 COMMENT 578 COMMENT SUBROUTINE FOR INTRO ANIMATIONS 579 Define the introduction sequence subroutine 580 Move the cursor and draw line 1 of the game menu 581 Move the cursor and draw line 2 of the game menu 582 Move the cursor and draw line 3 of the game menu 583 Move the cursor and draw line 4 of the game menu 584 BLANK 585 Start a loop while a string is empty 586 Set the string to read from the keyboard buffer 587 Repeat the keyboard reading loop 588 BLANK 589 Checks if we're using screen mode 1 (CGA) 590 Sets an x position variable for CGA 591 Sets a y position variable for CGA 592 Otherwise we're using EGA 593 Sets an x position variable for EGA 594 Sets a y position variable for EGA 595 Ends screen mode check 596 BLANK 597 Sets the screen mode to the best mode available 598 Initializes the screen 599 BLANK 600 Checks if we're in CGA and prints a message centered on line 5 601 BLANK 602 Sets a limit for the text view on the screen between lines 9 and 24 603 BLANK 604 Sets the gorilla color to the background (clever invisible drawing hack) 605 BLANK 606 Draws the gorilla with arms down at the calculated coordinates. Remember that this drawing function saves the image for easy use later 607 Clears the text area defined on line 602 608 Draws the gorilla with left arm up at the calculated coordinates 609 Clears the text area 610 Draws the gorilla with right arm up at the calculated coordinates 611 Clears the text area 612 BLANK 613 Sets the text area to between lines 1 and 25 614 IF EGA, resets the palette back to normal 615 BLANK 616 If the user chose to view the intro... 617 Center the title on line 2 618 Draw centered text on line 5 619 Define a string using both player names 620 Center that new string on line 7 621 BLANK 622 Draw player 1 gorilla with arms down on the left side of the screen 623 Draw player 2 gorilla with arms down on the left side of the screen 624 Wait for one tick 625 BLANK 626 Draw player 1 gorilla with left arm up on the left side of the screen 627 Draw player 2 gorilla with right arm up on the left side of the screen 628 Play music at 120 bpm in the first octave with some rests 629 Wait for 1/3 of a tick 630 BLANK 631 Draw player 1 gorilla with right arm up on the left side of the screen 632 Draw player 2 gorilla with left arm up on the left side of the screen 633 Play music in the 2nd octave with some flat notes 634 Wait for 1/3 of a tick 635 BLANK 636 Draw player 1 gorilla with left arm up on the left side of the screen 637 Draw player 2 gorilla with right arm up on the left side of the screen 638 Play music in the 2nd octave with some flat notes 639 Wait for 1/3 of a tick 640 BLANK 641 Draw player 1 gorilla with right arm up on the left side of the screen 642 Draw player 2 gorilla with left arm up on the left side of the screen 643 Play music in the 2nd octave with some flat notes 644 Wait for 1/3 of a tick 645 BLANK 646 Start a 4-step loop to animator gorillas beating chests 647 Draw player 1 gorilla with left arm up on the left side of the screen 648 Draw player 2 gorilla with right arm up on the left side of the screen 649 Play more music 650 Wait for 1/10 of a tick 651 Draw player 1 gorilla with right arm up on the left side of the screen 652 Draw player 2 gorilla with left arm up on the left side of the screen 653 Play more music 654 Wait for 1/10 of a tick 655 Loop to next animation cycle 656 End intro check 657 End intro subroutine 658 BLANK 659 COMMENT 660 COMMENT SUBROUTINE DISPLAYING TITLE AND MUSIC 661 Defines the introduction subroutine 662 BLANK 663 Sets the screen mode to 0, text only. 664 Sets the width and height to console standard 80x25 665 Defines the column count global to the text width of 80 666 Sets the text color to white and background color to black 667 Clears the screen 668 BLANK 669 Calls the game's center text function to print title text on line 4 670 Changes the color to light grey 671 Prints centered copyright text on line 6 672 Prints centered gameplay text on line 8 673 Prints centered gameplay text on line 9 674 Prints centered gameplay text on line 10 675 Prints centered gameplay text on line 11 676 Prints centered gameplay text on line 12 677 Prints centered prompt on line 24 678 BLANK 679 Plays background music at 160 bpm in 8th/quarters, 1st octave: CDEDCDECC 680 Calls the intro animation effect 681 Checks if the game has already initialized CGA and resets column global 682 Ends subroutine 683 BLANK 684 COMMENT 685 COMMENT 686 COMMENT 687 COMMENT 688 COMMENT SUBROUTINE FOR MAKING THE CITY 689 Defines the subroutine for creating the city skyline 690 BLANK 691 Initializes variable to 2 (start of the first building) 692 BLANK 693 COMMENT 694 Sets a variable to a random number between 1 and 6. Used to choose design 695 Compared new variable cases 696 If the new variable is 1, then height of building 1 is 15 697 If the new variable is 2, then height of building 1 is 130 698 If the new variable is 3 to 5, then height of building 1 is 15 699 If the new variable is 6, then height of building 1 is 130 700 Ends random variable comparison 701 BLANK 702 Checks if we're in EGA mode to set up building dimensions 703 Sets the bottom line of the building for EGA 704 Sets a value for delta height for EGA 705 Sets an ideal building width for EGA 706 Sets a random variance factor for EGA 707 Sets the width of the windows for EGA 708 Sets the height of the windows for EGA 709 Sets vertical window spacing for EGA 710 Sets horizontal window spacing for EGA 711 Otherwise, we're in CGA and need a different set of default sizes 712 Sets the bottom line of the building for CGA 713 Sets a value for delta height for CGA 714 Modifies previous set building height for CGA mode 715 Sets an ideal building width for CGA 716 Sets a random variance factor for CGA 717 Sets the width of the windows for CGA 718 Sets the height of the windows for CGA 719 Sets vertical window spacing for CGA 720 Sets horizontal window spacing for CGA 721 End mode check 722 BLANK 723 Sets the current building counter to 1 724 Starts a loop to construct buildings 725 BLANK 726 Compares the randomized building design strategy 727 If the setting is 1 then... 728 Add the delta height factor to the building height 729 If the setting is 1 then... 730 Subtract the delta height factor to the building height 731 If the setting is 3 to 5 then... 732 If we're on the right side of the screen... 733 Subtract 2x the delta height from the current height 734 Otherwise we're on the left side... 735 Add 2x the delta height from the current height 736 End the screen side cases 737 If the setting is 4... ***THIS IS A BUG -- IT SHOULD BE 6 738 If we're on the right side of the screen... 739 Add 2x the delta height from the current height 740 Otherwise we're on the left side... 741 Subtract 2x the delta height from the current height 742 End screen side cases 743 End building height strategy 744 BLANK 745 COMMENT 746 Determines the building width by adding a random amount to the base width 747 If the building width puts it wider then the screen, then cut the size 748 BLANK 749 COMMENT 750 Adds a random amount to the building height 751 Checks if the building is too short and clips it at the base height 752 BLANK 753 COMMENT 754 If the building is too height, then set it to max height offset by ground 755 BLANK 756 COMMENT 757 Saves the building left side as the x coordinate in the array 758 Saves the building top side as the y coordinate in the array 759 BLANK 760 If EGA, choose a random building color between 5 and 7 (custom palettes) 761 BLANK 762 COMMENT 763 Draw the building outline with the background color 764 Draw the building interior with the chosen random color 765 BLANK 766 COMMENT 767 Defines a starting point for the window 3 pixels inside the building 768 Starts a loop over all windows 769 Starts another loop over all floors in vertical steps 770 If the screen mode is not EGA... 771 Set the window color to random CGA value 772 Otherwise then if a 1d4 roll is a 1... 773 Then the window light is off (dark grey color) 774 Otherwise... 775 The window is on -- yellow 776 End screen mode check 777 Draw the window box based on the dimensions set above. 778 Loop through all windows in column-major order 779 Add the horizontal amount for a new column 780 Continue window loop until we reach the other edge of the building 781 BLANK 782 The next building starts at 2 pixels after the current building 783 BLANK 784 Increment the building counter 785 BLANK 786 Loop until we reach the edge of the screen 787 BLANK 788 Save the building count 789 BLANK 790 COMMENT 791 Set a random wind speed between -4 and 5. 792 If a 1d3 roll is a 1 then 793 If the wind speed is above 0 794 Add more random wind 795 Otherwise, it's less than 0 796 Add more random wind in the other direction 797 End wind direction check 798 End wind modification 799 BLANK 800 COMMENT 801 If there is wind... 802 Calculate the length of a line based on wind speed (3x * mode scaling) 803 Draw a line from the center of the screen in magenta 804 Set a variable that inverts itself based on wind direction 805 Draw the top side arrowhead using that variable 806 Draw the bottom side arrowhead using that variable 807 End check for wind 808 End the subroutine 809 BLANK 810 COMMENT 811 COMMENT 812 COMMENT 813 COMMENT 814 COMMENT 815 COMMENT SUBROUTINE FOR PLACING PLAYERS GORILLAS 816 Define the subroutine to place gorillas 817 BLANK 818 If we're in EGA... 819 Set x offsets to the middle of the gorilla (14) 820 Set y offsets to the bottom of the gorilla (30) 821 Otherwise we're in CGA 822 Set x offsets to the middle of the gorilla (7) 823 Set y offsets to the bottom of the gorilla (16) 824 End screen mode check 825 Calculate an X scaling factor using CGA basis 826 Calculate an Y scaling factor using CGA basis 827 BLANK 828 COMMENT 829 For each gorilla... 830 Gorilla 1 then choose building 2 or 3 and gorilla 2 chooses 2 or 3 from the end 831 BLANK 832 Find the width by averaging input building and neighbor in the building array 833 The gorilla's X position is half the width minus the gorilla middle offset 834 The gorilla's Y position is the building's height minus the offset to the gorilla's feet 835 Draw the gorilla at its new position with arms down 836 Continue to next gorilla 837 BLANK 838 End gorilla placement subroutine 839 BLANK 840 COMMENT 841 COMMENT 842 COMMENT 843 COMMENT 844 COMMENT SUBROUTINE FOR THE MAIN GAME LOOP 845 Defines the main game loop 846 Allocates space for 31 buildings 847 Allocates space for holding win count for both players 848 BLANK 849 Sets a player turn count 850 BLANK 851 Start a loop for the number of game rounds 852 BLANK 853 Clear the screen 854 Seed the random function using the system timer 855 Create the city 856 Place the gorillas 857 Set the sun's state to happy 858 Reset the hit flag 859 Loop on each shot while no one has been hit 860 Change player's turn 861 Move cursor to top left 862 Print the player 1 name 863 Move cursor to top right 864 Print the player 2 name 865 Center the score counter near the bottom on row 23 866 Save which gorilla is throwing 867 BLANK 868 COMMENT 869 Perform the throw. Turn is over when this function returns 870 BLANK 871 COMMENT 872 Reset the sun's state 873 BLANK 874 If a player was hit by the banana, then update the scores 875 Loop while there are more rounds to play 876 Wait for one second 877 Loop on next round 878 BLANK 879 Game is over, set screen mode back to 0 (text only) 880 Set text size to the classic 80x25 881 Set the text colors to light grey with black background 882 Set max columns to 80 883 Clear the screen 884 BLANK 885 Center the game over on line 8 886 Center the score count on line 10 887 Move cursor and print player 1's score 888 Move cursor print player 2's score 889 Center a prompt to press a key 890 Draw start animations and wait for input 891 Reset the colors again 892 Clear the screen 893 End the main game loop 894 BLANK 895 COMMENT 896 COMMENT 897 COMMENT 898 COMMENT 899 COMMENT 900 COMMENT 901 COMMENT FUNCTION FOR CONTROLLING SHOT PHYSICS 902 Defines the function controlling the banana in flight 903 BLANK 904 Converts the input angle from degrees to radians for upcoming trig functions 905 Sets a variable to 1 or 2 depending on game mode (not used) 906 BLANK 907 Calculates the movement speed in the X direction 908 Calculates the movement speed in the Y direction 909 BLANK 910 Saves the current X position 911 Saves the current Y position 912 BLANK 913 COMMENT 914 If player 1 just threw the banana... 915 Draw player 1 with it's left arm raised 916 Otherwise player 2 just threw the banana 917 Draw player 2 with it's right arm raised 918 End player check 919 BLANK 920 COMMENT 921 Play a short sound for the throw 922 Wait 1/10 of a tick 923 BLANK 924 COMMENT 925 Drop the gorilla's arms 926 BLANK 927 Set a scaling factor for CGA 928 BLANK 929 Calculate which side of the banana to watch..assuming proper throws 930 BLANK 931 Initializes any impact to false 932 Initializes the sun to not hit 933 Initializes the banana as on screen 934 No players have been hit yet 935 The banana hasn't been drawn yet, so erase flag is false 936 BLANK 937 Save the starting X position again 938 Save the starting Y position again 939 BLANK 940 If this is player 2... 941 Banana starts on the right side of the gorilla 942 Sets the scanning direction 4 positive pixels 943 Otherwise this is player 1... 944 The scanning direction is 4 pixels negative 945 End player check 946 BLANK 947 If the shot is too slow then.. 948 Set the current X position to the starting X position 949 Set the current Y position to the starting Y position 950 Set the scanning point color to the gorilla color 951 End check for slow shot 952 BLANK 953 Loop while the banana is in flight and visible on the screen 954 BLANK 955 Wait for 1/50 of a tick 956 BLANK 957 COMMENT 958 If the banana is already drawn... 959 Set the flag to erase the banana 960 Call the draw function to erase the old banana drawing 961 End banana erase check 962 BLANK 963 Update banana X position based on X velocity times the tick rate and the wind against the tick squared (less effect). 964 Update banana Y position based on the same factors and include a slight speedup or slowdown depending on the screen mode 965 BLANK 966 If the banana is off the screen on any three sides... 967 Deassert the flag to break the physics loop. No, wind can't blow bananas back on screen 968 End check for off screen 969 BLANK 970 BLANK 971 If the banana is on screen... 972 BLANK 973 COMMENT 974 Set Y check offset point to 0 975 Set X check offset point to the side of the thrower 976 Loop while checking for collisions 977 Saves the color at the check point 978 If the color matches the background then... 979 The banana hasn't hit anything 980 If the banana has already hit the sun... 981 Check of the banana has travelled far enough away and deassert the flag 982 End check for sun hit 983 If the check point matches the sun and it's within the bounding box... 984 Asset the sun shock if it isn't already 985 Set one sun flag 986 Set the other sun flag 987 Otherwise the banana has hit something 988 Set impact to true 989 End check for color point 990 Update the look X position based on the travel direction 991 Update the look Y 992 Loop until the banana hits something or it cannot look anymore 993 BLANK 994 If the banana hasn't hit anything and it hasn't hit the sun 995 COMMENT 996 Update the banana's rotation for the four frames 997 Draw the newly updated banana 998 Erase it on the next update 999 End the check for updates 1000 BLANK 1001 Update the old X position to the new X position 1002 Update the old Y position to the new Y position 1003 Update the rotation 1004 BLANK 1005 End the check while on screen 1006 BLANK 1007 BLANK 1008 Update the timer count by 1/10 1009 BLANK 1010 Continue loop while banana is in fight and hasn't hit anything 1011 BLANK 1012 If the banana hit something that's not a gorilla (its a building) 1013 Call the basic explosion procedure 1014 Otherwise, if the banana has hit a gorilla.. 1015 Call the gorilla explode procedure 1016 End check for hits 1017 BLANK 1018 Set the function return to the player that was hit 1019 BLANK 1020 End the physics update function 1021 BLANK 1022 COMMENT 1023 COMMENT SUBROUTING FOR PROGRAM SLEEP AND DELAYS 1024 Define the function for in-game delay -- busy-waiting 1025 Get the current system timer 1026 Calculate the delay stopping point using the game's tick interval 1027 Start an arbitrary loop 1028 Loop until the system timer passes the stopping point 1029 End the subroutine 1030 BLANK 1031 COMMENT 1032 COMMENT 1033 COMMENT 1034 COMMENT 1035 COMMENT FUNCTION TO SCALE INPUT IN CGA MODE 1036 Defines function to translate input numbers from EGA to CGA values 1037 BLANK 1038 Checks if the input short can be recast smoothly to integer 1039 If not, then decrement the input, which should now recast properly 1040 End re-cast check 1041 If we're in CGA... 1042 Then set the output to half the input, plus hair to round up 1043 Otherwise we're in EGA 1044 Simply return the input value as an integer 1045 End final check 1046 BLANK 1047 End function 1048 BLANK 1049 COMMENT 1050 COMMENT SUBROUTINE FOR SETTING SCREEN MODE 1051 Define subroutine for setting the screen mode 1052 BLANK 1053 Check if we're in EGA mode 1054 Define the explosion color as color 2 (green, but redefined below) 1055 Sets the background color to 1 (blue) 1056 Changes color 0 (usually black) to 1 (blue) 1057 Changes color 1 (usually blue) to 46 (tan) 1058 Changes color 2 (usually green) to 44 (magenta) 1059 Changes color 3 to 54 1060 Changes color 5 to 7 1061 Changes color 6 to 4 1062 Changes color 7 to 3 1063 Changes color 9 to 63 (white) 1064 Otherwise, we're in CGA 1065 Sets explosion color to 2 (red in CGA) 1066 Sets background color to black 1067 Sets background color and the color set 1068 BLANK 1069 Ends case for mode select 1070 BLANK 1071 Ends screen setup subroutine 1072 BLANK 1073 COMMENT 1074 COMMENT SUBROUTINE FOR ANIMATED GAME SCREENS 1075 Defines the subroutine for animating stars 1076 BLANK 1077 Changes the current text color to red foreground, blank background 1078 Sets the string of stars 1079 Loops on the keyboard buffer until it's empty. This prevents the next loop from early interruption 1080 BLANK 1081 Loop while there is no user input 1082 Loop for 5 steps, the number of spaces between each star + 1 1083 Set the cursor to the upper left 1084 Print the star string offset by the inner loop at the top of the screen 1085 Set the cursor near the bottom, below the intro text 1086 Print the bottom-row star string offset by the inner loop 1087 BLANK 1088 Begin a third loop for printing vertical stars, 1 character at a time 1089 The target character is offset by the 2nd and 3rd loops mod 5 1090 For every 5th character (The stars only)... 1091 Point the cursor to a vertical position at the right of the screen 1092 Print the right-side star 1093 Point cursor to the first column but subtracting b for opposite motion 1094 Print the left-side star 1095 Otherwise, this isn't the first character... 1096 Point the cursor to a vertical position at the right of the screen 1097 Print an empty space 1098 Point cursor to the first column but subtracting b for opposite motion 1099 Print an empty space 1100 End check for vertical character 1101 End 3rd loop 1102 End 2nd loop 1103 End entire loop on user input 1104 End animation subroutine 1105 BLANK 1106 COMMENT 1107 COMMENT 1108 COMMENT 1109 COMMENT 1110 COMMENT 1111 COMMENT SUBROUTINE FOR CHANGING PLAYER SCORE 1112 Defines the subroutine for updating player scores 1113 If the player killed themselves 1114 Increment the opponents score 1115 Otherwise.. 1116 Increment the player's score 1117 End the score update check 1118 End the subroutine 1119 BLANK 1120 COMMENT 1121 COMMENT 1122 COMMENT 1123 COMMENT SUBROUTINE FOR PLAYER VICTORY ANIMATION 1124 Defines the subroutine for victory animations for the input player 1125 BLANK 1126 Loop four times 1127 Draw the gorilla with the left arm raised in the winner's location 1128 Plays foreground music 32nd notes in the lowest octave: E-F-G-E-F-D-C 1129 Delay the game 0.2 game ticks 1130 Draw the gorilla with the right arm raised in the winner's location 1131 Plays foreground music 32nd notes in the lowest octave: E-F-G-E-F-D-C 1132 Delay the game 0.2 game ticks 1133 Continue to next loop 1134 Ends the subroutine 1135 BLANK