'===========================================================================
' 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
