'=========================================================================== ' Subject: LEAPGUY Date: 06-12-96 (00:00) ' Author: Steven Hanov Code: QB, QBasic, PDS ' Origin: hanov@wchat.on.ca Packet: GAMES.ABC '=========================================================================== '**************************************************************************** '* IDENTIFICATION * '* * '* NAME: Steven Hanov (hanovs@wchat.on.ca) * '* PROGRAM: a:\class.bas * * '* SCHOOL: Cardinal Newman C. S. S. * '* TEACHER: The teacher formerly known as Mrs. Gotovac. * '* COMPUTER: IBM/MS-DOS * '* LANGUAGE: QBASIC * '* PLANET: Earth (Sol-III) * '* PERIOD: LATE 20th CENTURY (Gregorian Calender) * '* CLASS: DPT 3A1 Period 2 * '* DATE: 96/06/12 * '* * '**************************************************************************** '**************************************************************************** '* PROGRAM ANALYSIS * '* * '* In the 1980s, when the dinosaurs ruled the earth, we all used computers * '* like the Commodore 64. It was great for games, and one game I liked was * '* JUMPMAN (By EPYX MegaGames). This program is a re-creation of what I * '* remember of the game. It has four levels, and is not entirely accurate. * '* However, it presented a unique programming challenge that I was not * '* entirely confident that I could meet. But after many hours of work, both * '* in and out of class, the project is finally completed. * '* * '* The object of the game is to pick up all of the brown "bombs". * '* Occasionally, white SmartDarts will fire at you from the sides of the * '* screen. To move, make sure the numeric keypad is ON. The controls are * '* on the keypad, and should be obvious. 8, 6, 2, and 4 move up, right, * '* down, and left, respectively. 7 and 8, and 9 are also used to jump. * '* * '* One problem I had was speed; on a slow computer the character moves * '* fine, but on a fast computer the gameplay is impossible. I surmounted * '* this difficulty with the speed option in the introductory screen. * '* On the school's computers, a value of one to three should be used. This * '* value is used to control the speed of both the character and the * '* SmartDart. * '* * '* Enjoy! * '* * '**************************************************************************** DECLARE SUB HighScores () DECLARE SUB paldef (c!, r!, g!, B!) DECLARE SUB ClearKeyBuffer (n!) DECLARE SUB centre (y!, t$) DECLARE SUB UpdateScore () DECLARE SUB Die () DECLARE SUB Bullet () DECLARE SUB pandisplay (xp!, yp!) DECLARE SUB DrawGuy (x!, y!) '**************************************************************************** '* VARIABLE DICTIONARY * '**************************************************************************** DIM SHARED graph(1000), pf(40, 25) AS STRING, snd DIM SHARED bgraph(100), x, y, xx, xy, DontDraw, lives, dead, bombs, Points DIM SHARED DartSpeed, GuySpeed, Delay, ResetFlag, Bonus DIM SHARED Score(15), Name$(15), TotalScore, FileName$ 'NAME ***** DESCRIPTION ************************************************ 'graph() The image of the background behind the character is stored ' in here, using the GET and PUT graphics commands. 'bgraph() Likewise, but with the bullet. 'pf(x,y) The current level is stored in here using the symbols explained ' in the data statements. 'x,y The current co-ordinate on the screen, in 8x8 units. The screen ' is 40 units horizontally and 25 vertically. 'xx, xy The true, pixel co-ordinate on the screen. Range: 320,200 'DontDraw A flag for the DrawGuy sub telling it not to call the Bullet sub 'lives Self explanatory 'dead A flag that lets the main program know if the bullet has ' contacted the player. 'bombs The number of bombs remaining on the playing field. 'points The number of bombs the player has picked up. Whenever it's ' displayed, its multiplied by 100. The points are reset whenever ' the player dies to make it more challenging. 'GuySpeed Used in the DrawGuy sub in a delay loop to slow it down. 'DartSpeed Derived from DrawGuy. Controls dart speed. 'Delay This flag tells the bullet sub not to delay because it is ' being called by the DrawGuy sub, which has already delayed. ' This makes the two objects move at the same time more smoothly. 'ResetFlag Tells the DrawGuy and Bullet subs to re-GET the background ' that they're on (into the GRAPH and BGRAPH) on a level change ' or else they'd draw a chunk of the old level on the new one. 'Bonus Contains the time bonus remaining for the level. 'TotalScore Contains the total score in the game divided by 100. 'Score() 'Name$() Used to read and sort the high scores from disk 'FileName$ The name and location of the score file. '**************************************************************************** '* MAIN * '**************************************************************************** RANDOMIZE TIMER KEY 15, CHR$(0) + CHR$(1) 'Defines Key# 15 = Esc 'ON KEY(15) GOSUB Ending 'ANYTIME user hits escape, gosub Ending. ON TIMER(10) GOSUB DecrementBonus 'Sets up the timer - Every ten seconds, 'you loose 100 time bonus. TIMER OFF 'But not right now. KEY(15) ON lives = 6 snd = 1 'Clicking sound on movement ON rt$ = "6" 'Define RIGHT key lt$ = "4" 'LEFT key UP$ = "8" 'UP key dn$ = "2" 'DOWN key Delay = 1 'Delay on call bullet sub. FileName$ = "SCORES.DAT" SCREEN 13 y = 0: x = 0 FOR s = 1 TO 25 READ l$ x = 0 FOR d = 1 TO 40 a$ = MID$(l$, d, 1) IF a$ = "W" THEN 'Displays in the introductory screen c = 15 'graphic, which is stored in DATA. ELSEIF a$ = "R" THEN 'It looks just like the old C=64 game! c = 4 ELSEIF a$ = "M" THEN c = 5 'R=RED square, M=magenta, C=cyan, ELSEIF a$ = "C" THEN 'Y=yellow, G=Green,B=Blue c = 3 ELSEIF a$ = "Y" THEN c = 14 ELSEIF a$ = "G" THEN c = 2 ELSEIF a$ = "B" THEN c = 1 ELSE c = 0 END IF LINE (x, y)-(x + 7, y + 7), c, BF x = x + 8 NEXT y = y + 8 NEXT WHILE INKEY$ = "": WEND 'Wait for keypress CALL HighScores 'Display HighScores PLAY "mbt128 O3 C16 O1 c16" CLS COLOR 3 centre 2, "LeapGuy" centre 4, "By Steven Hanov" LOCATE 6: PRINT COLOR 5 PRINT " Movement:" COLOR 14 PRINT " 7 8 9 Make sure your numlock" PRINT " key is ON. Use 7, 8, " PRINT " 4 6 and 9 to jump left, up," PRINT " or right." PRINT " 2 " LOCATE 19: COLOR 2 PRINT "Choose a speed for LeapGuy," PRINT "from 0 (fast) to 15 (slow):"; INPUT "", GuySpeed 'IF GuySpeed = 0 THEN GuySpeed = 8 GuySpeed = GuySpeed * 100 DartSpeed = GuySpeed \ 25 IF DartSpeed = 0 THEN DartSpeed = 10 NextLevel: FOR y = 1 TO 25 'Reads in the next level from DATA READ l$ 'and stores in pf(x,y) IF l$ = "STOP" THEN GOTO YouWon 'UNLESS there are no more levels. FOR x = 1 TO 40 pf(x, y) = MID$(l$, x, 1) NEXT NEXT READ OriginalX, OriginalY 'Starting position for JumpGuy ClearKeyBuffer 15 'A sub that stops a really annoying problem. Bonus = 1000 ReDraw: IF lives = 0 THEN 'IF the user has no life, TIMER OFF 'Don't decrement the bonus anymore... PLAY "T128 MB O1 L4 c2 e2 g2 >c1" seconds = TIMER WHILE TIMER - seconds < 4 'Flash screen red and white for pandisplay 1, 0 'four seconds. paldef 2, 63, 63, 63 FOR d = 1 TO 100: NEXT pandisplay 0, 0 'AND a cool earthquake effect paldef 2, 32, 0, 0 'with an OUT call I got from the 'Net FOR d = 1 TO 100: NEXT WEND paldef 2, 0, 32, 0 'Turn colour 2 from red to back to green PLAY "MBO3 C8 C8 2 THEN 'Move left, don't go off edge FOR s = 1 TO 8 xx = xx - 1 CALL DrawGuy(xx, xy) NEXT x = x - 1 ELSEIF a$ = UP$ AND pf(x, y) = "#" THEN 'The user is on a ladder, so FOR s = 1 TO 8 'move UP, (NOt JUMP) when they xy = xy - 1 'press 8. CALL DrawGuy(xx, xy) NEXT y = y - 1 ELSEIF a$ = dn$ AND pf(x, y + 1) = "#" THEN 'Go down a ladder. FOR s = 1 TO 8 xy = xy + 1 CALL DrawGuy(xx, xy) NEXT y = y + 1 END IF IF pf(x, y) = "#" THEN jump = 0 'If they jumped onto a ladder, IF pf(x, y) = "=" THEN 'Stop the jump. FOR s = 1 TO 8 xy = xy - 1 'If they're right OVER a girder, CALL DrawGuy(xx, xy) 'Climb on top of it. NEXT y = y - 1 jump = 0 'And stop jump that your in middle of ELSEIF pf(x, y + 1) = " " AND jump = 0 AND pf(x, y) <> "#" THEN fell = 0 'If you're standing on air, FOR d = 1 TO 2 IF pf(x, y + 1) <> " " THEN EXIT FOR snd = 0 FOR s = 1 TO 8 'Fall up to two units. xy = xy + 1 CALL DrawGuy(xx, xy) NEXT snd = 1 y = y + 1 fell = fell + 1 NEXT IF pf(x, y + 1) = " " AND fell = 2 THEN CALL Die 'If you fell two units, and you GOTO ReDraw 'STILL haven't landed, you're out of END IF 'luck. ELSEIF pf(x, y) = "+" OR pf(x, y - 1) = "+" THEN FOR s = 1 TO 8 'If you're legs or torso is on a xy = xy - 1 'rope, climb it. CALL DrawGuy(xx, xy) NEXT y = y - 1 jump = 2 ELSEIF pf(x, y) = "o" OR pf(x, y - 1) = "o" THEN 'On a bomb? PUT (xx - 8, xy - 16), graph, PSET 'Erase Jumpman IF pf(x, y) = "o" THEN pf(x, y) = " " 'Get the bomb if under legs LINE (xx - 8, xy - 8)-(xx, xy - 1), 0, BF 'Erase bomb ELSE 'OR ELSE: pf(x, y - 1) = " " 'Get if under torso LINE (xx - 16, xy - 16)-(xx - 8, xy - 8), 0, BF 'erase it 'LINE (xx - 8, xy - 16)-(xx, xy - 1), 0, BF END IF PLAY "t128 mb o1 l32 c o4 ccc" 'Sound effect LINE (xx - 8, xy - 16)-(xx, xy - 1), 0, BF GET (xx - 8, xy - 16)-(xx + 7, xy - 1), graph 'Stores new image, CALL DrawGuy(xx, xy) 'without the bomb Points = Points + 1 'Draw guy on top, increase CALL UpdateScore 'points, and display new points END IF IF jump = 1 THEN 'If the user's in apex of a jump, IF x < 38 AND x > 2 THEN 'And they're not in danger of passing edge, snd = 0 'Turn movement click sound flag off FOR s = 1 TO 8 xy = xy + 2 'Jump back down to earth xx = xx + xstep CALL DrawGuy(xx, xy) NEXT y = y + 2 x = x + xstep snd = 0 END IF jump = 2 'Completed jump cycle END IF IF (a$ = UP$ OR a$ = "7" OR a$ = "9") AND pf(x, y) <> "#" THEN 'Jump. IF a$ = "9" AND x < 38 THEN 'Jump RIGHT. xstep = 2 ELSEIF a$ = "7" AND x > 2 THEN 'Jump LEFT xstep = -2 max = 2 ELSE xstep = 0 'Jump UP. END IF PLAY "MBT128L32ML o3 CEG>CC< G8 F8 G8 E16 F16 G16 A16 B16 >C16 D16 C1" CASE 1 PLAY "O2 L4MN T200 CC< G >CL8 GF#G G# G G# A A# A A# B >CC2" CASE 2 PLAY "O2 L4MN MBT200MN C8 D# G8 >C< A#. G2 D#8 F D#8 F# A#2 F#8 F8 D#8 C8 C1" END SELECT GOTO NextLevel YouWon: 'The level re-drawer will send computer here if no more levels. TIMER OFF 'Can you smell the meatballs in this plate of spaghetti? :-) CLS COLOR 15 ClearKeyBuffer 15 centre 12, "*** YOU WON ***" WHILE INKEY$ = "": WEND CALL HighScores END '**************************************************************************** '* SUBROUTINES * '**************************************************************************** DecrementBonus: IF Bonus > 0 THEN 'This sub gets called every 10 seconds during Bonus = Bonus - 100 'game play (See help on "ON TIMER()" command) SOUND 440, 1 CALL UpdateScore 'Decrements time bonus END IF RETURN Ending: CLS COLOR 14 centre 12, CHR$(2) + " Buh-Bye! " + CHR$(2) END RETURN CreateNewFile: CLOSE 1 'Gets called by Highscores if scorefile doesn't OPEN FileName$ FOR OUTPUT AS 1 'exist. FOR s = 1 TO 15 PRINT #1, "------------" 'This creates a new file PRINT #1, 0 NEXT CLOSE 1 RESUME 'And resumes where the "FILE NOT FOUND" 'error occured. 'This following is the intro-screen graphic. DATA " CCC C CC CC CCCC CC CC CC C C" DATA " C C C C C C C C C C C C C CC C" DATA "C C C C C C CCCC C C CCCC C CC" DATA " CC CCC C C C C C C C C C" DATA " " DATA " BBBBBBBBBBBB " DATA " WWWW BB BB " DATA " WWWW WW BB BB " DATA " RRRRRRRRRR BB BB " DATA " RR RRRR BBBBBBBBBBBB " DATA " WW RRRR BB BB " DATA " MMMM BB BB " DATA " MMMMMMMMMM BB BB " DATA " MM MM BBBBBBBBBBBB " DATA " WW WWWW BB BB " DATA " YYYY BB BB " DATA " YYYY BB BB " DATA " BBBBBBBBBBBB " DATA " BB BB " DATA " GGGGGGGGGGGGGGGGGGGGBBGGGGGGGGBB " DATA " GG GG GG GG GG BB GG GGBB " DATA " GGGGGGGGGGGGGGGGGGGGBBBBBBBBBBBB " DATA " " DATA " " DATA " " 'The following are the levels. After each is the staring x,y position. ' It is possible to add more before the "STOP". Each is 25 lines. ' 1234567890123456789012345678901234567890 DATA " " DATA " " DATA " " DATA " o o o o " DATA " ==#=== ==== o o ==== ====#== " DATA " # # # " DATA " # ====#==== # " DATA " # o # o # " DATA " # ==== # ==== # " DATA " # ======#===== # " DATA " o # o # o # o " DATA " # # # " DATA " # # # # # " DATA " ==== === ==#=======#== === ==== " DATA " + # # + " DATA " + # # + " DATA " # # " DATA " # =================== # " DATA " ==#======= ========#== " DATA " # # " DATA " # o o # " DATA " # # " DATA " o # ======= # o " DATA " ====================================== " DATA " " DATA 20,17 DATA " " DATA " " DATA " " DATA " o o " DATA " # o =========#========= o # " DATA " #==== # ======# " DATA " # === # # # === # " DATA " # ====#==============#==== # " DATA " # # # # " DATA " # o # # o # o # " DATA " === =#=============================# " DATA " # # " DATA " # # " DATA " # # " DATA " # # o # o # " DATA " #============= =======#========= " DATA " # # " DATA " # # # " DATA " #=============== ==#========# " DATA " # === # # " DATA " # === # # " DATA " # o === o # # " DATA " ====== ========= === " DATA " " DATA " " DATA 37,22 DATA " " DATA " " DATA " " DATA " " DATA " o # o o # o " DATA " ===========#===== ======#=========== " DATA " # # " DATA " # # " DATA " o # # # o " DATA " === ======= ===#== ======= === " DATA " + # + " DATA " + # + " DATA " + # o # o # + " DATA " + =#======== ===== =======#= + " DATA " + # o o # + " DATA " + # # + " DATA " + # # + " DATA " + # # # # + " DATA " + ===========#======#=========== + " DATA " + # # + " DATA " o # # o " DATA " o # # o " DATA " ====================================== " DATA " " DATA " " DATA 21,13 DATA " " DATA " " DATA " " DATA " o o o o " DATA " =#======== ==== ==== =========#= " DATA " # # " DATA " # # " DATA " # o o # # " DATA " ======== ==================#======== " DATA " + == # " DATA " == # " DATA " o == o # o # o " DATA " ==================#=================== " DATA " + # + " DATA " # " DATA " o o # o o " DATA " ======== =======#======== ======== " DATA " + # + " DATA " + o # o + " DATA " + === ========#========= === + " DATA " + # + " DATA " + # + " DATA " +o # o+ " DATA " ====================================== " DATA " " DATA 20,12 DATA "STOP" SUB Bullet STATIC B, PrevX, PrevY, xtep, ytep, px, py, elapsed, DontChase IF Delay = 1 THEN 'If the sub is being not being called by the 'DrawGuy sub, there is no delay so it'll 'have to delay itself. elapsed = elapsed + 1 'Does so by only executing every 25th CALL IF elapsed < DartSpeed THEN 'or so. EXIT SUB ELSE elapsed = 0 END IF END IF IF ResetFlag = 1 THEN B = 0 'Player has started new level. Reread IF B = 0 OR dead = 1 THEN 'The background or if first time called. IF INT(RND * 500) <> 99 THEN EXIT SUB 'Makes bullets come OCCASIONALLY elapsed = 0 'NOt one after another. DontChase = 0 B = 1 a = INT(RND * 2) 'Come from top or left side? IF a = 0 THEN 'If side, px = 2 py = INT(RND * 180) + 2 xtep = .2 'Y step value, ytep = 0 'X step value ELSE px = INT(RND * 290) + 2 'If top.... py = 2 xtep = 0 ytep = .2 END IF PrevX = px PrevY = py GET (px, py)-(px + 1, py + 1), bgraph 'Gets background behind bullet END IF 'so it doesn't erase what's behind. px = px + xtep 'Move it horiz or vert.. py = py + ytep PUT (PrevX, PrevY), bgraph, PSET 'Erase bullet and put back what was there. PrevX = px 'The previous position saved for the next PrevY = py 'time. GET (px, py)-(px + 1, py + 1), bgraph 'Saves background again. LINE (px, py)-(px + 1, py + 1), 15, B 'Draws bullet cx = px \ 8 + 1 'Calculates the "text" (8x8) position cy = py \ 8 + 1 'of the bullet IF cx = x AND cy = y THEN 'If same as guy's position, smite him. CALL Die EXIT SUB END IF IF x < cx OR y < cy THEN d = -1 'IF the bullet is on same line as IF y > cy OR x > cx THEN d = 1 'guy, AND it has not already changed IF cx = x AND DontChase = 0 THEN 'course, swerve directly to him. ytep = d xtep = 0 DontChase = 1 'But it can only do it once. SOUND 400, 1: SOUND 1000, 1 END IF IF cy = y AND DontChase = 0 THEN 'Same, but for vertically. ytep = 0 xtep = d DontChase = 1 SOUND 400, 1: SOUND 1000, 1 END IF IF PrevX > 290 OR PrevY > 180 OR PrevX < 2 OR PrevY < 2 THEN PUT (PrevX, PrevY), bgraph, PSET PrevX = 0 PrevY = 0 'If offscreen, erase everything and px = 0 'prepare to start a new instance of the py = 0 'bullet on the next call. (B=0) B = 0 END IF END SUB SUB centre (y, t$) 'Centres something on the screen at the line Y LOCATE y, 20 - LEN(t$) / 2 PRINT t$; END SUB SUB ClearKeyBuffer (n) 'Clears the keyboard buffer by repeatedly reading in keys. FOR s = 1 TO n a$ = INKEY$ NEXT END SUB SUB Die DontDraw = 1 'Stop the bullet movement (in DrawGuy calls) snd = 0 'No click sound on movement. FOR i = xy TO 200 STEP 3 CALL DrawGuy(xx, i) 'Make him fall. SOUND 400 + (200 - i), .4 NEXT snd = 1 SLEEP 1 DontDraw = 0 PLAY "t200o3 MF MN L4 c2ccc2d#ddccc" lives = lives - 1 dead = 1 'Set death flag END SUB SUB DrawGuy (x, y) STATIC a, B, PrevX, PrevY FOR s = 1 TO GuySpeed: NEXT 'Delays for fast computers. IF ResetFlag = 1 THEN B = 0 'If next level reread background px = x - 8 py = y - 16 IF B = 0 THEN 'If first time called, read background B = 1 'behind the guy with GET so he doesn't erase it PrevX = px 'or leave trails. PrevY = py GET (px, py)-(px + 15, py + 15), graph END IF PUT (PrevX, PrevY), graph, PSET 'Put background back, erase guy PrevX = px PrevY = py GET (px, py)-(px + 15, py + 15), graph 'Get background at next position a = a + .5 'Move legs IF a = 4 THEN a = 0 LINE (px + 3, py)-(px + 5, py + 2), 15, BF LINE (px + 2, py + 3)-(px + 6, py + 6), 4, BF 'Draws guy LINE (px + 4, py + 6)-(px + 4 - a, py + 13), 5 LINE (px + 4, py + 5)-(px + 5 + a, py + 13), 5 LINE (px + 4 - a, py + 14)-(px + 4 - a + 1, py + 15), 15, BF LINE (px + 4, py + 14)-(px + 5 + a + 1, py + 15), 15, BF IF DontDraw = 0 THEN Delay = 0 'Calls the bullet sub and tells it not to delay CALL Bullet 'because we've already delayed. Delay = 1 END IF IF snd = 1 THEN SOUND 10000, .1 'The infamous click sound. END SUB SUB HighScores ON ERROR GOTO CreateNewFile 'If file doesn't exist, branch there. CLS OPEN FileName$ FOR INPUT AS 1 ON ERROR GOTO 0 FOR s = 1 TO 15 INPUT #1, Name$(s) 'REad in scores INPUT #1, Score(s) NEXT CLOSE 1 FOR outside = 1 TO 15 FOR inside = outside + 1 TO 15 'A bubble sort, just for you, IF Score(outside) < Score(inside) THEN 'Mrs. Gotovac. SWAP Score(outside), Score(inside) SWAP Name$(outside), Name$(inside) END IF NEXT NEXT PLAY "T128 O2 L4 MS MB G8>C8 G8 G8 C8 G8 G8 C8 D16 E16 F8 E16 D16 C2" COLOR 14 centre 2, "High Scores" COLOR 3 PRINT : PRINT FOR s = 1 TO 15 LOCATE s + 3, 10 PRINT Name$(s); TAB(22); Score(s); " " NEXT LINE (68, 4)-(236, 144), 4, B LINE (68, 20)-(236, 20), 4 ClearKeyBuffer 15 IF TotalScore * 100 > Score(1) THEN COLOR 14 centre 20, CHR$(2) + " NEW HIGH SCORE " + CHR$(2) PRINT INPUT "Please enter your name: ", n$ n$ = LEFT$(n$, 12) FOR s = 14 TO 1 STEP -1 Name$(s + 1) = Name$(s) Score(s + 1) = Score(s) NEXT Name$(1) = n$ Score(1) = TotalScore * 100 OPEN FileName$ FOR OUTPUT AS 1 FOR s = 1 TO 15 LOCATE s + 3, 10 PRINT Name$(s); TAB(22); Score(s); " " PRINT #1, Name$(s) PRINT #1, Score(s) NEXT LINE (68, 4)-(236, 144), 4, B CLOSE 1 END IF WHILE INKEY$ = "": WEND END SUB SUB paldef (c, r, g, B) 'Redefines a colour to be another custom colour. OUT &H3C8, c OUT &H3C9, r OUT &H3C9, g OUT &H3C9, B END SUB SUB pandisplay (xp, yp) 'Makes the display instantly jump for earthquake effect. OUT &H3D4, 12: OUT &H3D5, yp OUT &H3D4, 13: OUT &H3D5, xp END SUB SUB UpdateScore 'Updates the scoreboard. LOCATE 25, 1 COLOR 2: PRINT "Lives:"; COLOR 14: PRINT lives; COLOR 2: PRINT TAB(11); "Points:"; COLOR 14: PRINT Points * 100; COLOR 2: PRINT TAB(24); "Bonus:"; COLOR 14: PRINT Bonus; " "; END SUB