'=========================================================================== ' Subject: WORMHOLE Date: 10-15-96 (21:26) ' Author: Brent P. Newhall Code: QB, QBasic, PDS ' Origin: comp.lang.basic.misc Packet: GAMES.ABC '=========================================================================== ' Here is the updated WORMHOLE, including a lot of the improvements ' suggested by a lot of very nice people. Thanks, everybody. ' Weird line lengths are still a problem; there are no REM ********** ' this time, so you'll have to go through it yourself. Sorry! ' This starts to bog down with 10 baddies or so running on Visual Basic ' for DOS on a 486DX2/50, so I've added several comments as to what ' should be increased/decreased for QBASIC users. Do a word search on ' QBASIC and you'll find what you need. If it's still too slow, you'll ' have to REM stuff out on your own (start with GOSUB DoStars in the ' DoEverything: routine). ' Sorry for being lazy, but I'm really busy at the moment! Thanks for ' your patience. ' Wormhole ' Version 2.0.0 ' by Brent P. Newhall (bnewhall@gmu.edu) ' This program is PUBLIC DOMAIN. Anyone may use it however they ' wish, provided that credit is given where it's due for coding. ' One day, without warning, the heavens next to our planet opened ' like a flower. Out of this wormhole came an alien delegation, ' their only wish to sign a treaty with us. We sent our entire ' starfleet to the wormhole's mouth in this treaty's honor. ' Then, out of that wormhole poured ships the likes of which we had ' never dreamed. Our fleet was decimated; most ships were ' destroyed, others pulled into the wormhole to fight on the ' aliens' ground. But we had made our mark; the half of their ' fleet remaining withdrew into the wormhole. ' Now, you man the only spaceworthy ship left. Your mission: ' destroy the aliens as they come out of the wormhole, as their ' weapons are useless for a small critical distance from the ' wormhole's mouth. They will be defenselss unless they get ' past you. Good luck! ' Your ship can only move in a circular orbit around the wormhole ' out of which the red aliens are coming. Use the left and right ' arrow keys to move around, [SPACE] to fire a missile at the ' aliens, and [ESC] to quit. Hit [ENTER] to bypass the ' beginning, and [P] to pause. Your score is displayed in the ' lower left, and number of aliens destroyed in the lower right. ' Blue ships are our ships returning; let them pass. ' Version 1.0.0 -- Original release. ' Version 1.0.1 -- QBASIC compatibility assured, unneeded variables ' removed. ' Version 2.0.0 -- Longer missiles, multiple missiles, blue ' wormhole and discontinuities (long blue things), ' improved explosions, fading title, improved ' score handling, pause function, better graphics ' handling, blue good guys, history, QBASIC info. ' My highest score: 6882 points, 94 aliens destroyed. Beat that! TYPE MonsterType x AS INTEGER y AS INTEGER degree AS INTEGER radius AS SINGLE exist AS INTEGER dying AS INTEGER MonstType AS INTEGER END TYPE TYPE StarType radius AS INTEGER degree AS INTEGER colr AS INTEGER special AS INTEGER length AS INTEGER speed AS INTEGER END TYPE TYPE VertexType x AS SINGLE y AS SINGLE END TYPE TYPE PolygonType BorderColor AS INTEGER FilledColor AS INTEGER filled AS INTEGER lxo AS INTEGER lyo AS INTEGER NumVertices AS INTEGER END TYPE TYPE MissileType radius AS INTEGER x1 AS INTEGER y1 AS INTEGER x2 AS INTEGER y2 AS INTEGER angle AS INTEGER END TYPE CONST PI = 3.14159, DEG2RAD = PI / 180 CONST FALSE = 0, TRUE = NOT FALSE CONST TOT.STARS = 25 ' Increase for a prettier starfield effect ' Decrease for QBASIC (to 10, say) CONST TOT.MONSTERS = 20 ' Decrease for QBASIC DECLARE SUB DrawPolygon (poly AS PolygonType, verts() AS VertexType) DECLARE SUB ErasePolygon (poly AS PolygonType, verts() AS VertexType) DECLARE SUB RotatePolygon (poly AS PolygonType, verts() AS VertexType, angle AS INTEGER) DIM Monster(0 TO TOT.MONSTERS) AS MonsterType DIM star(1 TO TOT.STARS) AS StarType DIM ship AS PolygonType DIM ShipVert(1 TO 11) AS VertexType DIM Missile(1 TO 12) AS MissileType DIM SinLook(0 TO 360) AS DOUBLE DIM CosLook(0 TO 360) AS DOUBLE DIM MonstGraph(1 TO 1000, 1 TO 2) AS INTEGER DIM ExplodeGraph(1 TO 1000, 1 TO 5) AS INTEGER DIM melt(3000) AS INTEGER DIM score AS LONG ' Can go up to 2 trillion GOSUB Init DO GOSUB MainProgramLoop LOOP UNTIL quit > 0 GOSUB EndOfGame END MainProgramLoop: nothing$ = INKEY$ ' Mask out INKEY$ t! = TIMER: WHILE t! = TIMER: WEND ' Delay nothing$ = INKEY$ ' Mask out INKEY$ GOSUB DoEveryone ' Take care of enemies, ship, missiles, etc. nothing$ = INKEY$ ' Mask out INKEY$ GOSUB DoInput ' Take care of input RETURN DoEveryone: GOSUB DoColors GOSUB DoStars GOSUB DoWormhole ' REM with QBASIC GOSUB MoveShip GOSUB DoBaddies GOSUB DoMissiles GOSUB DoScore RETURN DoColors: ' Flash monster and score colors IF beginning THEN LOCATE 5, 17: PRINT "WORMHOLE"; IF GoingUp THEN ScoreColor% = ScoreColor% + 1 IF ScoreColor% = 60 THEN GoingUp = FALSE: Staying = 1 ELSEIF Staying THEN Staying = Staying + 1 IF Staying = 20 THEN Staying = 0 ELSE ScoreColor% = ScoreColor% - 1 IF ScoreColor% = 0 THEN beginning = FALSE LOCATE 5, 17: PRINT " "; GOSUB CreateMonster ' Create one monster to start END IF END IF ELSE MonstColor% = MonstColor% + 2 IF MonstColor% > 60 THEN MonstColor% = 0 PALETTE 101, MonstColor% ScoreColor% = ScoreColor% + ScoreMoving% IF ScoreColor% > 50 THEN ScoreMoving% = -1 ELSEIF ScoreColor% < 20 THEN ScoreMoving% = 1 END IF END IF PALETTE 102, ScoreColor% + ScoreColor% * 256 + ScoreColor% * 65536 RETURN DoStars: FOR cnt% = 1 TO TOT.STARS tx1% = INT(star(cnt%).radius * CosLook(star(cnt%).degree)) + 159 ty1% = INT(star(cnt%).radius * SinLook(star(cnt%).degree)) + 99 tx2% = INT((star(cnt%).radius + star(cnt%).length) * CosLook(star(cnt%).degree)) + 159 ty2% = INT((star(cnt%).radius + star(cnt%).length) * SinLook(star(cnt%).degree)) + 99 LINE (tx1%, ty1%)-(tx2%, ty2%), 0 ' Erase star star(cnt%).radius = star(cnt%).radius + star(cnt%).speed IF star(cnt%).radius > 170 THEN ' Out of bounds? ' Create a new star! star(cnt%).radius = INT(RND * 5) star(cnt%).degree = INT(RND * 361) IF RND > .9 THEN ' Special star(cnt%).special = TRUE star(cnt%).length = INT(RND * 10 + 15) star(cnt%).colr = 9 ' Color special blue star(cnt%).speed = 15 ' Move it really fast ELSE ' Normal star(cnt%).length = 1 star(cnt%).colr = INT(RND * 15 + 16) star(cnt%).speed = ((star(cnt%).colr - 15) / 5) + 1 END IF END IF tx1% = INT(star(cnt%).radius * CosLook(star(cnt%).degree)) + 159 ty1% = INT(star(cnt%).radius * SinLook(star(cnt%).degree)) + 99 tx2% = INT((star(cnt%).radius + star(cnt%).length) * CosLook(star(cnt%).degree)) + 159 ty2% = INT((star(cnt%).radius + star(cnt%).length) * SinLook(star(cnt%).degree)) + 99 LINE (tx1%, ty1%)-(tx2%, ty2%), star(cnt%).colr ' Erase star NEXT cnt% RETURN DoWormhole: CIRCLE (159, 99), wormholeradius1, 0 ' Erase old circles CIRCLE (159, 99), wormholeradius2, 0 wormholeradius1 = INT(RND * 6) ' Create new circle wormholeradius2 = INT(RND * 6) CIRCLE (159, 99), wormholeradius1, 9 ' Draw new circles CIRCLE (159, 99), wormholeradius2, 1 RETURN MoveShip: IF moving THEN ErasePolygon ship, ShipVert() posit% = posit% + moving * 3 ' Move ship IF posit% < 0 THEN posit% = posit% + 360 IF posit% > 360 THEN posit% = posit% - 360 ship.lxo = INT(80 * CosLook(posit%)) + 159 ship.lyo = INT(80 * SinLook(posit%)) + 99 RotatePolygon ship, ShipVert(), moving * 3 moving = 0 END IF DrawPolygon ship, ShipVert() RETURN DoBaddies: ToBeKilled% = 0 m% = 0 WHILE m% < NumMonsters m% = m% + 1 ' Loop through, 1..NumMonsters IF Monster(m%).dying THEN PUT (Monster(m%).x, Monster(m%).y), ExplodeGraph(1, Monster(m%).dying) ELSE PUT (Monster(m%).x, Monster(m%).y), MonstGraph(1, Monster(m%).MonstType) END IF IF Monster(m%).dying < 5 THEN ' If not at end of dying Monster(m%).radius = Monster(m%).radius + MonstSpeed Monster(m%).x = INT(Monster(m%).radius * CosLook(Monster(m%).degree)) + 154 Monster(m%).y = INT(Monster(m%).radius * SinLook(Monster(m%).degree)) + 94 IF Monster(m%).dying THEN Monster(m%).dying = Monster(m%).dying + 1 PUT (Monster(m%).x, Monster(m%).y), ExplodeGraph(1, Monster(m%).dying), PSET ELSE PUT (Monster(m%).x, Monster(m%).y), MonstGraph(1, Monster(m%).MonstType), PSET END IF IF Monster(m%).radius > 90 THEN ' Outside orbit IF Monster(m%).MonstType = 2 THEN ' Good guy score = score + 250 LINE (Monster(m%).x - 3, Monster(m%).y - 3)-(Monster(m%).x + 13, Monster(m%).y + 13), 0, BF GOSUB KillMonster ELSE ' Baddie, you lose! quit = 2 END IF END IF ELSE ' At end of dying ToBeKilled% = m% END IF WEND IF ToBeKilled% > 0 THEN m% = ToBeKilled% ' Erase out last vestiges of monster graphic LINE (Monster(m%).x - 3, Monster(m%).y - 3)-(Monster(m%).x + 13, Monster(m%).y + 13), 0, BF GOSUB KillMonster END IF IF NOT beginning THEN IF RND > MonstChance THEN ' Create new monster occasionally IF NumMonsters < TOT.MONSTERS - 2 THEN ' If there's space GOSUB CreateMonster END IF END IF END IF RETURN DoMissiles: miss% = 0 WHILE miss% < NumMissiles miss% = miss% + 1 ' Loop through, 1..NumMissiles ' Erase missile LINE (Missile(miss%).x1%, Missile(miss%).y1%)-(Missile(miss%).x2%, Missile(miss%).y2%), 0 IF Missile(miss%).radius = 0 THEN ' If at center GOSUB KillMissile ELSE Missile(miss%).radius = Missile(miss%).radius - 3 ' Move its coordinates Missile(miss%).x1 = INT(Missile(miss%).radius * CosLook(Missile(miss%).angle)) + 159 Missile(miss%).y1 = INT(Missile(miss%).radius * SinLook(Missile(miss%).angle)) + 99 Missile(miss%).x2 = INT((Missile(miss%).radius + 3) * CosLook(Missile(miss%).angle)) + 159 Missile(miss%).y2 = INT((Missile(miss%).radius + 3) * SinLook(Missile(miss%).angle)) + 99 IF POINT(Missile(miss%).x1%, Missile(miss%).y1%) >= 100 THEN cnt% = 0 ' Hit a monster! (front end) WHILE cnt% < NumMonsters AND Monster(cnt%).dying = 0 cnt% = cnt% + 1 ' Find hit monster IF Missile(miss%).x1% >= Monster(cnt%).x THEN IF Missile(miss%).y1% >= Monster(cnt%).y THEN IF Missile(miss%).x1% <= Monster(cnt%).x + 10 THEN IF Missile(miss%).y1% <= Monster(cnt%).y + 10 THEN Monster(cnt%).dying = 1 END IF END IF END IF END IF WEND GOSUB KillMissile ELSEIF POINT(Missile(miss%).x2%, Missile(miss%).y2%) >= 100 THEN cnt% = 0 ' Hit a monster! (back end) WHILE cnt% < NumMonsters AND Monster(cnt%).dying = 0 cnt% = cnt% + 1 ' Find hit monster IF Missile(miss%).x2% >= Monster(cnt%).x THEN IF Missile(miss%).y2% >= Monster(cnt%).y THEN IF Missile(miss%).x2% <= Monster(cnt%).x + 10 THEN IF Missile(miss%).y2% <= Monster(cnt%).y + 10 THEN Monster(cnt%).dying = 1 END IF END IF END IF END IF WEND GOSUB KillMissile ELSE ' Draw Missile LINE (Missile(miss%).x1%, Missile(miss%).y1%)-(Missile(miss%).x2%, Missile(miss%).y2%), 14 END IF END IF WEND RETURN Fire: IF TIMER > LastMissile! + .7 OR NumMissiles = 0 THEN ' If time has passed or there are no active missiles IF NumMissiles < 10 THEN ' If enough missiles left NumMissiles = NumMissiles + 1 Missile(NumMissiles).radius = 78 ' Put near ship Missile(NumMissiles).angle = posit% ' Missile Angle = Ship Angle score = score - 5 IF score < 0 THEN score = 0 LastMissile! = TIMER END IF END IF RETURN CreateMonster: NumMonsters = NumMonsters + 1 ' Another monster Monster(NumMonsters).x = 154 ' First coordinates Monster(NumMonsters).y = 94 Monster(NumMonsters).degree = INT(RND * 361) Monster(NumMonsters).radius = 0 ' In the middle Monster(NumMonsters).exist = TRUE IF RND > .95 THEN ' Good guy 5% of time Monster(NumMonsters).MonstType = 2 ELSE ' Bad guy 95% of time Monster(NumMonsters).MonstType = 1 END IF PUT (Monster(NumMonsters).x, Monster(NumMonsters).y), MonstGraph(1, Monster(NumMonsters).MonstType), PSET RETURN KillMonster: IF Monster(m%).MonstType = 1 THEN ' Further in, higher score score = score + (100 - Monster(m%).radius) MonstersKilled% = MonstersKilled% + 1 IF MonstersKilled% MOD 15 = 0 THEN MonstChance = MonstChance - .005 END IF IF MonstersKilled% MOD 20 = 0 THEN MonstSpeed = MonstSpeed + .05 END IF ELSE score = score - 100 IF score < 0 THEN score = 0 END IF FOR cnt1% = m% TO NumMonsters ' Copy next over current Monster(cnt1%).x = Monster(cnt1% + 1).x Monster(cnt1%).y = Monster(cnt1% + 1).y Monster(cnt1%).degree = Monster(cnt1% + 1).degree Monster(cnt1%).radius = Monster(cnt1% + 1).radius Monster(cnt1%).dying = Monster(cnt1% + 1).dying Monster(cnt1%).exist = Monster(cnt1% + 1).exist Monster(cnt1%).MonstType = Monster(cnt1% + 1).MonstType NEXT cnt1% NumMonsters = NumMonsters - 1 ' One less monster! RETURN KillMissile: FOR cnt1% = miss% TO NumMissiles ' Copy next over current Missile(cnt1%).x1 = Missile(cnt1% + 1).x1 Missile(cnt1%).y1 = Missile(cnt1% + 1).y1 Missile(cnt1%).x2 = Missile(cnt1% + 1).x2 Missile(cnt1%).y2 = Missile(cnt1% + 1).y2 Missile(cnt1%).angle = Missile(cnt1% + 1).angle Missile(cnt1%).radius = Missile(cnt1% + 1).radius NEXT cnt1% NumMissiles = NumMissiles - 1 ' One less missile RETURN DoScore: IF NOT beginning THEN LOCATE 25, 1: PRINT score; LOCATE 25, 36: PRINT MonstersKilled%; END IF RETURN DoInput: kp% = INP(&H60) ' Get keypress in kp% IF kp% < 100 THEN ' &H60 is > 100 if no keypresses IF kp% = 75 THEN ' [RIGHT] moving = 1 ELSEIF kp% = 77 THEN ' [LEFT] moving = -1 ELSEIF kp% = 57 THEN ' [SPACE] GOSUB Fire ELSEIF kp% = 25 THEN ' [P] GOSUB Pause ELSEIF kp% = 28 THEN ' [ENTER] GoingUp = FALSE Staying = 0 ScoreColor% = 1 ELSEIF kp% = 1 THEN ' [ESC] quit = 1 END IF END IF RETURN Pause: IF NOT beginning THEN LOCATE 5, 18: PRINT "PAUSED"; DO: LOOP UNTIL INKEY$ <> "" ' Wait for keypress LOCATE 5, 18: PRINT " "; END IF RETURN Init: SCREEN 13 RANDOMIZE TIMER CIRCLE (5, 5), 5, 100: PAINT (5, 5), 100 ' Draw monster LINE (0, 0)-(10, 10), 100 LINE (10, 0)-(0, 10), 100 LINE (4, 5)-(6, 5), 101 LINE (5, 4)-(5, 6), 101 PSET (0, 0), 101: PSET (10, 0), 101 PSET (0, 10), 101: PSET (10, 10), 101 GET (0, 0)-(10, 10), MonstGraph(1, 1) PUT (0, 0), MonstGraph(1, 1) PUT (10, 10), MonstGraph(1, 1) LINE (10, 15)-(20, 15), 0 ' Explosion 1 LINE (15, 10)-(16, 20), 0 LINE (14, 14)-(17, 16), 0, B CIRCLE (15, 15), 3, 12, , , 1 / 3 PAINT (15, 15), 12 PSET (14, 13), 7 PSET (17, 17), 7 GET (8, 8)-(22, 22), ExplodeGraph(1, 1) CIRCLE (16, 15), 4, 0 ' Explosion 2 CIRCLE (15, 15), 4, 12, , , 1 / 2 CIRCLE (15, 15), 2, 14, , , 1 / 2 PAINT (15, 15), 14 CIRCLE (13, 12), 1, 7: PSET (13, 12), 7 CIRCLE (18, 18), 1, 7: PSET (18, 18), 7 GET (8, 8)-(22, 22), ExplodeGraph(1, 2) PUT (10, 10), MonstGraph(1, 1), PSET ' Explosion 3 CIRCLE (15, 15), 6, 0: PAINT (15, 15), 0 CIRCLE (15, 15), 6, 4, , , 1 / 2 PAINT (15, 15), 4 CIRCLE (15, 15), 4, 14, , , 1 / 2 PAINT (15, 15), 14 PSET (10, 10), 0 CIRCLE (12, 11), 1, 8 CIRCLE (19, 19), 1, 8 GET (8, 8)-(22, 22), ExplodeGraph(1, 3) PUT (8, 8), ExplodeGraph(1, 3) CIRCLE (15, 15), 7, 116, , , 1 / 2 ' Explosion 4 PAINT (15, 15), 116 CIRCLE (15, 15), 4, 0, , , 1 / 2 PAINT (15, 15), 0 GET (8, 8)-(22, 22), ExplodeGraph(1, 4) PUT (8, 8), ExplodeGraph(1, 4) CIRCLE (15, 15), 7, 43, , , 1 / 2 ' Explosion 5 GET (8, 8)-(22, 22), ExplodeGraph(1, 5) PUT (8, 8), ExplodeGraph(1, 5) CIRCLE (15, 15), 5, 104, , , 1 / 3 ' Draw good guy PAINT (15, 15), 104 CIRCLE (15, 15), 5, 104, , , 3 LINE (15, 10)-(15, 20), 104 LINE (10, 10)-(20, 20), 104 LINE (20, 10)-(10, 20), 104 GET (10, 10)-(20, 20), MonstGraph(1, 2) PUT (10, 10), MonstGraph(1, 2) PALETTE 100, 30 ' Change monster color to red PALETTE 104, 3942440 ' Change good guy color to bright blue FOR cnt% = 0 TO 360 ' Initialise look-up tables SinLook(cnt%) = SIN(cnt% * DEG2RAD) CosLook(cnt%) = COS(cnt% * DEG2RAD) NEXT cnt% posit% = 0 ' Player's initial position = 0 ship.lxo = INT(80 * CosLook(posit%)) + 159 ship.lyo = INT(80 * SinLook(posit%)) + 99 score = 0 MonstersKilled% = 0 ScoreColor% = 0 ScoreMoving% = 1 FOR cnt% = 1 TO TOT.STARS ' Initialise stars star(cnt%).radius = INT(RND * 100) star(cnt%).degree = INT(RND * 361) IF RND > .9 THEN ' Special star(cnt%).special = TRUE star(cnt%).length = INT(RND * 10 + 15) star(cnt%).colr = 9 star(cnt%).speed = 15 ELSE ' Normal star(cnt%).length = 1 star(cnt%).colr = INT(RND * 15 + 16) star(cnt%).speed = ((star(cnt%).colr - 15) / 5) + 1 END IF NEXT cnt% ship.BorderColor = 53 ' Original ship color is light blue ship.filled = FALSE ' Ship is not filled ship.NumVertices = 11 ' 11 vertices FOR cnt% = 1 TO ship.NumVertices ' Define vertices READ ShipVert(cnt%).x, ShipVert(cnt%).y NEXT cnt% MonstSpeed = .1 MonstChance = .97 PALETTE 102, 0 COLOR 102 beginning = TRUE GoingUp = TRUE DrawPolygon ship, ShipVert() RETURN EndOfGame: IF quit = 1 THEN SCREEN 0: WIDTH 80 PRINT "Quitter!" ELSEIF quit = 2 THEN LOCATE 12, 16: PRINT "YOU LOSE"; SLEEP 2 ' Pause for two seconds done = FALSE cnt% = 0 WHILE cnt% < 2000 AND NOT done cnt% = cnt% + 1 ' Loop 3000 times XX% = INT(RND * 271) YX% = INT(RND * 150) GET (XX%, YX%)-(XX% + 48, YX% + 48), melt PUT (XX%, YX% + 1), melt, PSET ' End on keyhit only after melting awhile IF INKEY$ <> "" THEN IF cnt% > 500 THEN done = TRUE ' Do an occasional delay IF cnt% MOD 100 = 0 THEN t! = TIMER: WHILE t! = TIMER: WEND WEND SCREEN 0: WIDTH 80 ' Normal text screen END IF RETURN DATA 0, 0 DATA 5, -5 DATA 10, -5 DATA 5, -10 DATA 10, -10 DATA 15, -5 DATA 15, 5 DATA 10, 10 DATA 5, 10 DATA 10, 5 DATA 5, 5 SUB DrawPolygon (poly AS PolygonType, verts() AS VertexType) xo = poly.lxo yo = poly.lyo IF poly.filled THEN FOR index = 1 TO poly.NumVertices - 1 LINE (xo + verts(index).x, yo + verts(index).y)-(xo + verts(index + 1).x, yo + verts(index + 1).y), poly.FilledColor NEXT index LINE (xo + verts(poly.NumVertices).x, yo + verts(poly.NumVertices).y)-(xo + verts(1).x, yo + verts(1).y), poly.FilledColor PAINT (xo, yo), poly.FilledColor ELSE FOR index = 1 TO poly.NumVertices - 1 LINE (xo + verts(index).x, yo + verts(index).y)-(xo + verts(index + 1).x, yo + verts(index + 1).y), poly.BorderColor NEXT index LINE (xo + verts(poly.NumVertices).x, yo + verts(poly.NumVertices).y)-(xo + verts(1).x, yo + verts(1).y), poly.BorderColor END IF END SUB SUB ErasePolygon (poly AS PolygonType, verts() AS VertexType) xo = poly.lxo yo = poly.lyo IF poly.filled THEN FOR index = 1 TO poly.NumVertices - 1 LINE (xo + verts(index).x, yo + verts(index).y)-(xo + verts(index + 1).x, yo + verts(index + 1).y), 0 NEXT index LINE (xo + verts(poly.NumVertices).x, yo + verts(poly.NumVertices).y)-(xo + verts(1).x, yo + verts(1).y), 0 PAINT (xo, yo), FilledColor ELSE FOR index = 1 TO poly.NumVertices - 1 LINE (xo + verts(index).x, yo + verts(index).y)-(xo + verts(index + 1).x, yo + verts(index + 1).y), 0 NEXT index LINE (xo + verts(poly.NumVertices).x, yo + verts(poly.NumVertices).y)-(xo + verts(1).x, yo + verts(1).y), 0 END IF END SUB SUB RotatePolygon (poly AS PolygonType, verts() AS VertexType, angle AS INTEGER) IF angle >= 0 THEN si = SIN(angle * DEG2RAD) cs = COS(angle * DEG2RAD) ELSE si = SIN((angle + 360) * DEG2RAD) cs = COS((angle + 360) * DEG2RAD) END IF FOR index = 1 TO poly.NumVertices rx = verts(index).x * cs - verts(index).y * si ry = verts(index).y * cs + verts(index).x * si verts(index).x = rx verts(index).y = ry NEXT index END SUB