set display mode 800, 600, 32
sync on
sync rate 0
randomize timer()
backdrop on
color backdrop rgb(0,0,0)
set ambient light 0
set directional light 0, 1, -1, 1
color light 0, rgb(96, 96, 96)
 
 
#constant SPHERE_COUNT 5
#constant SPHERE_MASS 10.0
#constant ORBIT_RADIUS 1.75
 
autocam off
y# = 20.0
position camera 0, 20, 0
point camera 0,0,0
set camera fov 45
aspect# = screen width()* (1.0 / screen height())
S_HEIGHT# = (tan(22.5) * 20.0) * 2.0
S_WIDTH# = S_HEIGHT# * aspect#
 
 
 
Type Coord
   x#
   y#
   z#
EndType
 
Dim Spheres(SPHERE_COUNT) as Coord
for i = 1 to SPHERE_COUNT
   tests = 0
   while SpherePositionOk(i) = 0 OR tests = 0
      inc tests
      Spheres(i).x# = (rnd(S_WIDTH# * 600.0) - (S_WIDTH# * 300.0)) * 0.001
      Spheres(i).y# = 0.0
      Spheres(i).z# = (rnd(S_HEIGHT# * 600.0) - (S_HEIGHT# * 300.0)) * 0.001
   endwhile
 
   make object sphere i, 1.0, 64, 64
   position object i, Spheres(i).x#, Spheres(i).y#, Spheres(i).z#
   color object i, rgb(255.0, 0.0, 0.0)
   set object specular power i, 100
   set object specular i, rgb(255,255,255)
 
   set object collision to spheres i
next i
 
 
 
Dim Targets(SPHERE_COUNT) as Coord
active_target = rnd(SPHERE_COUNT-1)+1
 
for i = 1 to SPHERE_COUNT
   if i > 1
      a# = atanfull(Spheres(i).x# - Spheres(i-1).x#, Spheres(i).z# - Spheres(i-1).z#)
   else
      a# = atanfull(Spheres(1).x# - Spheres(5).x#, Spheres(1).z# - Spheres(5).z#)
   endif
 
   Targets(i).x# = Spheres(i).x# + (ORBIT_RADIUS * sin(a#))
   Targets(i).y# = 0.0
   Targets(i).z# = Spheres(i).z# + (ORBIT_RADIUS * cos(a#))
 
   obj = i + SPHERE_COUNT
   make object sphere obj, 0.5, 64, 64
   position object obj, Targets(i).x#, Targets(i).y#, Targets(i).z#
   if i = active_target
      set object diffuse obj, rgb(255.0, 255.0, 0.0)
   else
      set object diffuse obj, rgb(32.0, 32.0, 0.0)
   endif
   set object specular power obj, 100
   set object specular obj, rgb(255,255,255)
 
   set object collision to spheres obj
next i
 
 
 
Type PlayerData
   x#
   z#
   sX#
   sZ#
   angle#
   turnRate#
   speed#
   acc#
   accAngle#
   mass#
 
   Score
 
   ThrustKey
   LeftTurnKey
   RightTurnKey
EndType
#constant NUM_PLAYERS 2
 
Dim Player(NUM_PLAYERS) as PlayerData
for i = 1 to NUM_PLAYERS
   obj = i + 99
   t_obj = active_target - 1
   if t_obj < 1 then t_obj = SPHERE_COUNT
 
   make object cone obj, 0.5
   offset limb obj, 0, 0, 0, 0.25
   position object obj, Targets(t_obj).x#, Targets(t_obj).y#, Targets(t_obj).z#
   scale object obj, 50, 50, 100
   rotate limb obj, 0, 90, 0, 0
   set object emissive obj, rgb(64, 64, 255)
 
 
 
   make object cone obj+10, 0.5
   offset limb obj+10, 0, 0, 0, 0.25
   position object obj+10, Targets(t_obj).x#, Targets(t_obj).y#, Targets(t_obj).z#
   scale object obj+10, 25, 25, 100
   rotate limb obj+10, 0, 90, 0, 0
   set object emissive obj+10, rgb(255, 192, 0)
 
   make light i
   position light i, Targets(t_obj).x#, Targets(t_obj).y#, Targets(t_obj).z#
 
 
   `Rotate ship away from planet
   if t_obj >1
      a# = atanfull(Spheres(t_obj).x# - Spheres(t_obj-1).x#, Spheres(t_obj).z# - Spheres(t_obj-1).z#)
   else
      a# = atanfull(Spheres(1).x# - Spheres(5).x#, Spheres(1).z# - Spheres(5).z#)
   endif
 
 
 
 
   Player(i).x# = Targets(t_obj).x#
   Player(i).z# = Targets(t_obj).z#
   Player(i).turnRate# = 0.0
   Player(i).speed# = 0.0
   Player(i).mass# = 10.0
   if i = 1 then Player(i).acc# = 20.0 else Player(i).acc# = 0.0
   Player(i).accAngle# = 180.0
   Player(i).angle# = a#
   yrotate object obj, a#
 
   Player(i).Score = 0
 
   set object collision to polygons obj
 
   select i
      case 1
         `Player 1 controls
         Player(1).ThrustKey = 57      :`Space
         Player(1).LeftTurnKey = 203   :`Left Arrow
         Player(1).RightTurnKey = 205  :`Right Arrow
      endcase
   endselect
next i
 
 
 
 
`Ghost Target Sphere
make object sphere 1000, 1.0, 64, 64
gosub INITIALISE_GHOST_TARGET
 
 
make object cube 1001, 1
hide object 1001
 
 
`Game Timer
GameTimer# = 60.0
RestartTimer# = 5.0
 
`AI Timer
targetAngle# = 0.0
targetAcc# = 0.0
 
`Used for sphere distance
null = make vector2(1)
null = make vector2(2)
null = make vector2(3)
 
 
`Framerate movement stuff
frameTime# = 1.0
frameTimeS# = frameTime# * 0.001
startTime = timer()
`Main loop
do
   frameTime# = (frameTime# * 0.8) + ((timer() - startTime) * 0.2)
   startTime = timer()
   frameTimeS# = frameTime# * 0.001
 
 
   `Game Timer Display
   if GameTimer# > 10.0
      dec GameTimer#, frameTimeS#
      center text screen width() * 0.5, 0, left$(str$(GameTimer#), 5)
   else
      if GameTimer# <= 0
         GameTimer# = 0
      else
         dec GameTimer#, frameTimeS#
         center text screen width() * 0.5, 0, left$(str$(GameTimer#), 4)
      endif
   endif
 
   `Score Display
   text 10, 10, "(P)" + str$(Player(1).Score) + ":" + str$(Player(2).Score) + "(AI)"
 
   if GameTimer# > 0
      gosub DO_PLAYER_STUFF
      if ghost_timer# < 1.0 then gosub DO_TARGETER
   else
      scx# = screen width() * 0.5
      scy# = (screen height() - text height("T")) * 0.5
      center text scx#, scy#, "GAME OVER"
      center text scx#, scy# + text height("T"), "The Winner is"
 
      if Player(1).Score > Player(2).Score
         center text scx#, scy# + (2 * text height("T")), "Player 1"
      else
         if Player(1).Score < Player(2).Score
            center text scx#, scy# + (2 * text height("T")), "The computer"
         else
            center text scx#, scy# + (2 * text height("T")), "Nobody - ITS A DRAW!!"
         endif
      endif
 
      dec RestartTimer#, frameTimeS#
      center text scx#, screen height() - text height("T"), "Game restarts in... " + left$(str$(RestartTimer#), 4)
      if RestartTimer# <= 0
         gosub RESET_STATS
      endif
   endif
 
   sync
loop
end
 
 
 
RESET_STATS:
   RestartTimer# = 5.0
   GameTimer# = 60.0
 
   `Move spheres
   for i = 1 to SPHERE_COUNT
      tests = 0
      while SpherePositionOk(i) = 0 OR tests = 0
         inc tests
         Spheres(i).x# = (rnd(S_WIDTH# * 600.0) - (S_WIDTH# * 300.0)) * 0.001
         Spheres(i).y# = 0.0
         Spheres(i).z# = (rnd(S_HEIGHT# * 600.0) - (S_HEIGHT# * 300.0)) * 0.001
      endwhile
 
      position object i, Spheres(i).x#, Spheres(i).y#, Spheres(i).z#
      color object i, rgb(255.0, 0.0, 0.0)
      set object specular power i, 100
      set object specular i, rgb(255,255,255)
      set object collision to spheres i
   next i
 
   null = make vector2(1)
 
 
   `Move targets
   active_target = rnd(SPHERE_COUNT-1)+1
   for i = 1 to SPHERE_COUNT
      if i > 1
         a# = atanfull(Spheres(i).x# - Spheres(i-1).x#, Spheres(i).z# - Spheres(i-1).z#)
      else
         a# = atanfull(Spheres(1).x# - Spheres(5).x#, Spheres(1).z# - Spheres(5).z#)
      endif
 
      Targets(i).x# = Spheres(i).x# + (ORBIT_RADIUS * sin(a#))
      Targets(i).y# = 0.0
      Targets(i).z# = Spheres(i).z# + (ORBIT_RADIUS * cos(a#))
 
      obj = i + SPHERE_COUNT
      position object obj, Targets(i).x#, Targets(i).y#, Targets(i).z#
      if i = active_target
         set object diffuse obj, rgb(255.0, 255.0, 0.0)
      else
         set object diffuse obj, rgb(32.0, 32.0, 0.0)
      endif
      set object specular power obj, 100
      set object specular obj, rgb(255,255,255)
 
      set object collision to spheres obj
   next i
 
   `Reset Players
   for i = 1 to NUM_PLAYERS
      obj = i + 99
      t_obj = active_target - 1
      if t_obj < 1 then t_obj = SPHERE_COUNT
 
      position object obj, Targets(t_obj).x#, Targets(t_obj).y#, Targets(t_obj).z#
      set object emissive obj, rgb(64, 64, 255)
 
 
      position object obj+10, Targets(t_obj).x#, Targets(t_obj).y#, Targets(t_obj).z#
      set object emissive obj+10, rgb(255, 192, 0)
 
      position light i, Targets(t_obj).x#, Targets(t_obj).y#, Targets(t_obj).z#
 
 
      `Rotate ship away from planet
      if t_obj >1
         a# = atanfull(Spheres(t_obj).x# - Spheres(t_obj-1).x#, Spheres(t_obj).z# - Spheres(t_obj-1).z#)
      else
         a# = atanfull(Spheres(1).x# - Spheres(5).x#, Spheres(1).z# - Spheres(5).z#)
      endif
 
 
      Player(i).x# = Targets(t_obj).x#
      Player(i).z# = Targets(t_obj).z#
      Player(i).turnRate# = 0.0
      Player(i).speed# = 0.0
      Player(i).mass# = 10.0
      if i = 1 then Player(i).acc# = 20.0 else Player(i).acc# = 0.0
      Player(i).accAngle# = 180.0
      Player(i).angle# = a#
      yrotate object obj, a#
 
      Player(i).score = 0
 
      set object collision to polygons obj
   next i
 
return
 
 
 
 
INITIALISE_GHOST_TARGET:
   set alpha mapping on 1000, 50
   scale object 1000, 0, 0, 0
   position object 1000, Targets(active_target).x#, Targets(active_target).y#, Targets(active_target).z#
   ghost_timer# = 0.0
   show object 1000
return
 
 
 
 
 
 
DO_TARGETER:
   ghost_timer# = curvevalue(1.0, ghost_timer#, 400.0 / frameTime#)
 
   if ghost_timer# < 1.0
      scale object 1000, ghost_timer# * 500.0, 1, ghost_timer# * 500.0
      a# = 50.0 - (50.0 * ghost_timer#)
      if a# < 0 then a# = 0
      set alpha mapping on 1000, a#
   else
      hide object 1000
   endif
return
 
 
 
 
 
 
 
DO_PLAYER_STUFF:
   for i = 1 to NUM_PLAYERS
      obj = i + 99
      if i = 2
         `AI Player
         fX# = 0.0 : fZ# = 0.0
         for j = 1 to SPHERE_COUNT
            DistX# = Spheres(j).x# - Player(i).x#
            DistZ# = Spheres(j).z# - Player(i).z#
            set vector2 1, DistX#, DistZ#
            Dist# = length vector2(1)
            if Dist# < 1.0 then Dist# = 1.0
 
            `XZ Components of Grav
            Grav# = SPHERE_MASS * Player(i).mass# / (Dist# * Dist#) * 0.5
            xGrav# = Grav# * DistX# / Dist#
            zGrav# = Grav# * DistZ# / Dist#
 
            inc fX#, xGrav#
            inc fZ#, zGrav#
         next j
 
         gAccX# = (fX# / SPHERE_MASS) * frameTimeS#
         gAccZ# = (fZ# / SPHERE_MASS) * frameTimeS#
 
         `CALCULATE TAGERT COORD
         tx# = Targets(active_target).x#
         ty# = Targets(active_target).y#
         tz# = Targets(active_target).z#
         objDetect = 1
         SphereInWay = 0
         hide object 1001
         while objDetect <= SPHERE_COUNT AND SphereInWay = 0
            if intersect object(objDetect, Player(2).x#, ty#, Player(2).z#, tx#, ty#, tz#) > 0
               angle# = atanfull(Spheres(objDetect).x# - Player(2).x#, Spheres(objDetect).z# - Player(2).z#)
               inc angle#, 90
               tx# = Spheres(objDetect).x# + (ORBIT_RADIUS * sin(angle#))
               tz# = Spheres(objDetect).z# + (ORBIT_RADIUS * cos(angle#))
               show object 1001
               position object 1001, tx#, ty#, tz#
               SphereInWay = 1
            endif
            inc objDetect
         endwhile
 
 
 
         set vector2 2, tx# - Player(i).x#, tz# - Player(i).z#
         normalize vector2 2, 2
         multiply vector2 2, 2.0
 
         targetSpeedX# = x vector2(2)
         targetSpeedZ# = y vector2(2)
         totalAccX# = (targetSpeedX# - Player(i).sX#)
         totalAccZ# = (targetSpeedZ# - Player(i).sZ#)
 
         EngineAccX# = totalAccX# - gAccX#
         EngineAccZ# = totalAccZ# - gAccZ#
 
         set vector2 3, EngineAccX#, EngineAccZ#
 
         targetAngle# = atanfull(EngineAccX#, EngineAccZ#)
         targetAcc# = length vector2(3)
 
         Player(i).angle# = curveangle(targetAngle#, Player(i).angle#, 250.0 / frameTime#)
         Player(i).acc# = curvevalue(targetAcc#, Player(i).acc#, 500.0 / frameTime#)
 
         inc Player(i).sX#, Player(i).acc# * sin(Player(i).angle#) * frameTimeS#
         inc Player(i).sZ#, Player(i).acc# * cos(Player(i).angle#) * frameTimeS#
      endif
      if i = 1
         `Human Player
         if keystate(Player(i).ThrustKey)
            Player(i).acc# = curvevalue(4.0, Player(i).acc#, 100.0/ frameTime#)
         else
            Player(i).acc# = curvevalue(0.0, Player(i).acc#, 100.0/ frameTime#)
         endif
 
 
         if keystate(Player(i).LeftTurnKey)
            Player(i).turnRate# = curvevalue(-0.360, Player(i).turnRate#, 500.0 / frameTime#)
         else
            if keystate(Player(i).RightTurnKey)
               Player(i).turnRate# = curvevalue(0.360, Player(i).turnRate#, 500.0 / frameTime#)
            else
               `niether direction being pressed
               Player(i).turnRate# = curvevalue(0.0, Player(i).turnRate#, 100.0 / frameTime#)
            endif
         endif
 
         inc Player(i).angle#, Player(i).turnRate# * frameTime#
 
         `Update speed based on angle and if thrusting
         inc Player(i).sX#, sin(Player(i).angle#) * Player(i).acc# * frameTimeS#
         inc Player(i).sZ#, cos(Player(i).angle#) * Player(i).acc# * frameTimeS#
 
         `Update Speed based on gravity effect
         fX# = 0.0 : fZ# = 0.0
         for j = 1 to SPHERE_COUNT
            DistX# = Spheres(j).x# - Player(i).x#
            DistZ# = Spheres(j).z# - Player(i).z#
            set vector2 1, DistX#, DistZ#
            Dist# = length vector2(1)
            if Dist# < 1.0 then Dist# = 1.0
 
            `XZ Components of Grav
            Grav# = SPHERE_MASS * Player(i).mass# / (Dist# * Dist#) * 0.5
            xGrav# = Grav# * DistX# / Dist#
            zGrav# = Grav# * DistZ# / Dist#
 
            inc fX#, xGrav#
            inc fZ#, zGrav#
         next j
         inc Player(i).sX#, (fX# / SPHERE_MASS) * frameTimeS#
         inc Player(i).sZ#, (fZ# / SPHERE_MASS) * frameTimeS#
 
      endif
 
 
 
 
      `Update position based on overall speed
      inc Player(i).x#, Player(i).sX# * frameTimeS#
      inc Player(i).z#, Player(i).sZ# * frameTimeS#
 
      `Check if player has hit the target
      if object collision(obj, active_target + SPHERE_COUNT)
         inc Player(i).Score
         current_target = active_target
         active_target = rnd(SPHERE_COUNT-1)+1
         if current_target = active_target
            if active_target < SPHERE_COUNT then inc active_target else dec active_target
         endif
 
         if active_target > SPHERE_COUNT then active_target = 1
         for j = 1 to SPHERE_COUNT
            t_obj = j + SPHERE_COUNT
            if j = active_target
               set object diffuse t_obj, rgb(255.0, 255.0, 0.0)
            else
               set object diffuse t_obj, rgb(32.0, 32.0, 0.0)
            endif
            set object specular power t_obj, 100
            set object specular t_obj, rgb(255,255,255)
         next j
         gosub INITIALISE_GHOST_TARGET
      endif
 
 
      `Check of off the left or right
      if Player(i).x# < -(S_WIDTH#*0.5)
         Player(i).x# = S_WIDTH#*0.5
      else
         if Player(i).x# > S_WIDTH#*0.5
            Player(i).x# = -S_WIDTH#*0.5
         endif
      endif
 
 
      `Check if off top or bottom
      if Player(i).z# < -(S_HEIGHT#*0.5)
         Player(i).z# = S_HEIGHT#*0.5
      else
         if Player(i).z# > S_HEIGHT#*0.5
            Player(i).z# = -S_HEIGHT#*0.5
         endif
      endif
 
      position object obj, Player(i).x#, object position y(obj), Player(i).z#
      yrotate object obj, Player(i).angle#
 
 
 
      `Thruster Stuff
      position object obj+10, Player(i).x#, object position y(obj), Player(i).z#
      Player(i).accAngle# = curveangle(Player(i).angle#+180.0, Player(i).accAngle#, 100.0 / frameTime#)
      yrotate object obj+10, Player(i).accAngle#
      scale object obj+10, 25, 25, Player(i).acc# * 25.0
 
      `Thruster Light
      position light i, Player(i).x#, object position y(obj), Player(i).z#
      set light range i, Player(i).acc#+4.0
   next i
return
 
 
 
 
 
 
function SpherePositionOk(j)
   null = make vector3(1)
   for i = 1 to j-1
      set vector3 1, Spheres(j).x# - Spheres(i).x#, Spheres(j).y# - Spheres(i).y#, Spheres(j).z# - Spheres(i).z#
      if length vector3(1) < 3.0
         null = delete vector3(1)
         exitfunction 0
      endif
   next j
   null = delete vector3(1)
endfunction 1