`*********************************
`Shooter
`*********************************
 
`Setup
sync on : sync rate 80
hide mouse
randomize timer()
 
`display mode
set display mode 640,480,16
 
set text font "Comic Sans MS"
set text size 18
 
`Create player
gosub CreatePlayer
 
`Create World
gosub CreateWorld
 
`Create level var
global Level
Level = 1
 
`create enemies
global Enemies as integer
Enemies = 5
 
`Start game
Restart:
 
ghost object off 1
 
`vars
type Plr
   id as integer
   health as integer
   power as integer
   aph as integer
   `animation phase(used for getting the point of animation)
   Move as float
   Run as float
   WeaponDrawed as integer
   maxdelay as integer
   delay as integer
endtype
dim Player(Enemies + 1) as Plr
Player(1).id = 1
Player(1).power = 1
Player(1).aph = 0
Player(1).Move = 0.4
Player(1).Run = 0.5
Player(1).maxdelay = 50
Player(1).WeaponDrawed = 1
Player(1).Health = 3
 
`Enemies
type enemyInfo
   AngX# as float
   AngY# as float
   move as integer
   left as integer
   right as integer
   shoot as integer
   status as integer
   time as integer
   targetx as float
   targetz as float
endtype
dim Enemy(Enemies) as enemyInfo
 
for i = 1 to Enemies
 
   `Create enemy
   if object exist(1 + i) = 0 then clone object 1 + i,1
 
   `Player data
   Player(1 + i).id = 1 + i
   Player(1 + i).aph = 0
   Player(1 + i).Move = 0.2
   Player(1 + i).Run = 0.2
   Player(1 + i).WeaponDrawed = 0
   Player(1 + i).Health = 1 + (Level/2)
   Player(1 + i).maxdelay = 100
 
   X# = rnd(1000)
   Z# = rnd(1000)
   position object Player(1 + i).id,X#,0,Z#
 
   `enemy AI data
   Enemy(i).move = 0
   Enemy(i).status = 0
   Enemy(i).left = 0
   Enemy(i).right = 0
   Enemy(i).AngX# = 0
   Enemy(i).AngY# = rnd(360)
   Enemy(i).shoot = 0
   Enemy(i).time = rnd(500)
 
   `unhide objects in case you reached the next level
   show object 1 + i
next i
 
`Delete all unnecessary enemies
while object exist(1 + i) > 0
   delete object 1 + i
endwhile
 
`Create a bom
if object exist(2000) = 0 then make object cube 2000, 0.3
color object 2000, rgb(75,75,75)
hide object 2000 : position object 2000,0,-30,0
BombPlaced = 0
BombTimer = 0
Explosion = 0
 
`Explosion
if object exist(2001) = 0 then make object sphere 2001, 2
color object 2001, RGB(255,128,0)
hide object 2001 : position object 2001, 0, -30, 0 : scale object 2001, 10, 10, 10
disable object zwrite 2001
set object ambient 2001, rgb(255,128,0)
set object emissive 2001, rgb(255,128,0)
 
`reset variables
angx# = 0.0
angy# = 0.0
 
`Deals ghosting for the main player
global ghosting as integer
ghosting = 0
 
`Create a vector for checking distances
r = make vector3(1)
 
`position player
position object 1,500,0,500
 
do
 
   `Control player
   angx# = wrapvalue(angx# + (mousemovey()*0.2))
   `Angle boundries
   if wrapvalue(angx#-180) > 260.0
      angx# = 80.0
   else
      if wrapvalue(angx#-180) < 150 then angx# = 330
   endif
   angy# = wrapvalue(angy# + (mousemovex()*0.2))
   if upkey() = 1 then move = 1 else move = 0
   if downkey() = 1 then back = 1 else back = 0
   if leftkey() = 1 then left = 1 else left = 0
   if rightkey() = 1 then right = 1 else right = 0
   if controlkey() = 1 and hold = 0
      hold = 1
      Player(1).WeaponDrawed = abs(Player(1).WeaponDrawed-1)
   endif
   if mouseclick() = 1 then shoot = 1 else shoot = 0
 
   ControlPlayer(1, angx#, angy#, move, back, left, right, shoot)
 
   `turn on/off ghosting player
   if shiftkey() > 0 and hold = 0
      hold = 1
      if ghosting = 0 then ghosting = 1 else ghosting = 0
      if ghosting > 0 then ghost object on 1 else ghost object off 1
   endif
 
   `Camera
   CamBehind(1, 6.0, 2.0, 1.25, angx#, angy#)
 
   `Control bullets
   gosub ControlBullets
 
   `Control bomb
   gosub BombControl
 
   `control water
   waterAng# = wrapvalue(waterAng#+0.2)
   position object 10000, 500, -2.5 + sin(waterAng#)*0.5, 500
 
   `Control enemies
   gosub EnemiesAI
 
   `Enable keys
   if controlkey() + shiftkey() = 0 then hold = 0
   if mouseclick() <> 2 then MouseHold = 0
 
   `Control HUD
   gosub HUD
 
   sync
loop
 
`*** Enemy AI ***
EnemiesAI:
 
   Kills = 0
   for e = 1 to Enemies
      obj = Player(1 + e).id
      if Player(1 + e).Health > 0
 
         set vector3 1, object position x(1) - object position x(obj), object position y(1) - object position y(obj), object position z(1) - object position z(obj)
 
         `*** Enemy AI ***
         select Enemy(e).status
            case 0
 
               `Get distance
               dist# = length vector3(1)
 
               `if player gets too close, draw weapon and attack
               if dist# < 150.0
                  Player(1 + e).WeaponDrawed = 1
                  Enemy(e).status = 1
               else
 
                  `Wander
 
                  `Reset enemy
                  Player(1 + e).WeaponDrawed = 0
                  Enemy(e).shoot = 0
 
                  `Wander
                  if Enemy(e).time >= 0 then inc Enemy(e).time : Enemy(e).move = 0
 
                  if Enemy(e).time > 500
                     Enemy(e).time = -1
                  endif
 
                  if Enemy(e).time = -1
 
                     `Calculate target
                     Enemy(e).targetx = object position x(obj) - 50 + rnd(100)
                     Enemy(e).targetz = object position z(obj) - 50 + rnd(100)
 
                     `Get boundries
                     if Enemy(e).targetx < 0 then Enemy(e).targetx = abs(Enemy(e).targetx)
                     if Enemy(e).targetz < 0 then Enemy(e).targetz = abs(Enemy(e).targetz)
                     if Enemy(e).targetx > 1000 then Enemy(e).targetx = 1000 - abs(Enemy(e).targetx)
                     if Enemy(e).targetz > 1000 then Enemy(e).targetz = 1000 - abs(Enemy(e).targetz)
 
                     `Proceed to the next step
                     Enemy(e).time = -2
                  endif
                  if Enemy(e).time = -2
 
                     `Point object to get data
                     point object obj, Enemy(e).targetx, object position y(obj), Enemy(e).targetz
 
                     `get data
                     Enemy(e).AngY# = object angle y(obj)
                     Enemy(e).move = 1
 
                     `for distance
                     set vector3 1, object position x(obj) - Enemy(e).targetx, 0, object position z(obj) - Enemy(e).targetz
                     if length vector3(1) < 0.2 then Enemy(e).time = 0
                  endif
 
 
               endif
 
            endcase
            case 1
 
               `get distance
               dist# = length vector3(1)
 
               `ATTACK!!!
               point object obj, object position x(1), object position y(1), object position z(1)
               Enemy(e).AngY# = object angle y(obj) - 3 + rnd(6)
               Enemy(e).AngX# = object angle x(obj)
               Enemy(e).shoot = 1
               if dist# < 50.0 then Enemy(e).move = 0 else Enemy(e).move = 1
 
               `Reset to normal if you escaped.
               if dist# > 175.0 then Enemy(e).status = 0
 
            endcase
         endselect
 
         `update enemy
         ControlPlayer(1 + e, Enemy(e).AngX#, Enemy(e).AngY#, Enemy(e).move, 0, Enemy(e).left, Enemy(e).right, Enemy(e).shoot)
      else
 
         `Kill enemy
         hide object obj
         position object obj, 0, -50, 0
         inc Kills
 
      endif
   next e
 
return
 
`*** HUD ***
HUD:
 
   `Draw HUD
   ink 0,0
   box 0,0,100,40
   ink rgb(0,255,0),0
   box 0,0,100 / 3 * Player(1).health, 20
   ink 0,0
   center text 50,0,str$(Player(1).health)
   ink rgb(255,255,255),0
   text 5, 20, "Kills: " + str$(Kills) + "/" + str$(Enemies)
 
   `Handle losing
   if Player(1).health <= 0 then goto Lose
   if Kills = Enemies then goto Win
 
return
 
`*** Control All bullets ***
ControlBullets:
 
   `control all bullets
   for b = 1 to bulletQuant
      `If bullet is in the air
      if Bullet(b) > 0
 
         `move object
         move object bulletStart + b, 1
         dec Bullet(b)
 
         `detect anything that can stop the bullet
         if object position y(bulletStart + b) < get ground height(1, object position x(bulletStart + b), object position z(bulletStart + b)) then Bullet(b) = 0
         col = object collision(bulletStart + b, 0)
         if col > 0
            Bullet(b) = 0
            if col > 1 and col <= 1 + Enemies
               `For enemies
               dec Player(col).Health, Player(1).power
               Enemy(col-1).status = 2
            endif
            if col = 1
               dec Player(1).health
            endif
         endif
 
         `bullet dies
         if Bullet(b) = 0 then hide object bulletStart + b : position object bulletStart + b, 0,-50,0
      endif
   next b
 
return
 
`*** Control the bomb ***
BombControl:
 
   if mouseclick() = 2 and MouseHold = 0
      MouseHold = 1
      if BombPlaced = 0
         BombPlaced = 1
         BombTimer = 200
         show object 2000
         position object 2000, object position x(1), get ground height(1, object position x(1), object position z(1)), object position z(1)
      endif
   endif
   if BombTimer > 0
      dec BombTimer
      red = int(255.0/200*(200-BombTimer))
      color object 2000, rgb(red, 128, 0)
      set object emissive 2000, rgb(red, 128, 0)
      set object ambient 2000, rgb(red, 128, 0)
      if BombTimer = 0 then Explosion = 40
   endif
 
   `handle explosion
   if Explosion > 0
      dec Explosion : show object 2001
      position object 2001, object position x(2000), object position y(2000), object position z(2000)
      scale object 2001, 1000 - (Explosion*20), 1000 - (Explosion*20), 1000 - (Explosion*20)
      set alpha mapping on 2001, Explosion*2
 
      `Check for collision
      for i = 1 to 1 + Enemies
         if object collision(2001, i) > 0 then col = i
      next i
      if col > 0
         if col > 0 and col < 1 + Enemies
            dec Player(col).health, 1
         endif
      endif
 
      if Explosion <= 0
         hide object 2001 : scale object 2001, 10, 10, 10 : position object 2001, 0, -30, 0
         hide object 2000 : position object 2000, 0, -30, 0
         BombPlaced = 0
      endif
   endif
 
return
 
`*** Create player ***
CreatePlayer:
 
   `create player
   make object box 1,2,3,1
   make object sphere 2,1.5
   make mesh from object 1,2
   delete object 2
   add limb 1,1,1
   link limb 1,0,1
   offset limb 1,1,0,2.5,0
   delete mesh 1
 
   `make arms
   make object box 2,0.5,1.5,0.5
   offset limb 2,0,0,-0.75,0
   make mesh from object 1,2
 
   `left arm
   add limb 1,2,1
   add limb 1,3,1
   link limb 1,2,3
   offset limb 1,3,0,-1.5,0
   offset limb 1,2,1.25,1.5,0
 
   `right arm
   add limb 1,4,1
   add limb 1,5,1
   link limb 1,4,5
   offset limb 1,5,0,-1.5,0
   offset limb 1,4,-1.25,1.5,0
 
   `make legs
 
   `left leg
   add limb 1,6,1
   add limb 1,7,1
   link limb 1,6,7
   offset limb 1,7,0,-1.5,0
   offset limb 1,6,-0.5,-1,0
 
   `right leg
   add limb 1,8,1
   add limb 1,9,1
   link limb 1,8,9
   offset limb 1,9,0,-1.5,0
   offset limb 1,8,0.5,-1,0
 
   `clean up
   delete object 2
   delete mesh 1
 
return
 
CreateWorld:
 
   set camera range 0.1,100000
 
   `Create world
   make matrix 1,1000,1000,50,50
   CreateGrassTex(1,256,256)
   prepare matrix texture 1,1,1,1
 
   `prepare heights
   for y = 1 to 50
      for x = 1 to 50
         set matrix height 1, x, y, sin(x*y)*5
      next x
   next y
   update matrix 1
 
   `make water
   make object plain 10000,1000,1000
   rotate object 10000,-90,0,0
   position object 10000,500,-2.5,500
   set object light 10000,1
   set reflection shading on 10000
   set object collision off 10000
 
   `make sky
   make object plain 10001,10000,10000
   CreateSkyTex(2,512,512)
   position object 10001,500,500,500
   xrotate object 10001,90
   texture object 10001,2
   set object cull 10001,0
   set object light 10001,1
   scale object texture 10001,5,5
 
   for i = 0 to 3
      make object plain 10002 + i, 10000, 1000
      position object 10002 + i, 500 + cos(90*i)*5000, 0, 500 + sin(90*i)*5000
      color object 10002 + i, rgb(0,0,50)
      point object 10002 + i, 500, 0, 500
   next i
 
   `fog
   fog on
   fog color rgb(0,0,50)
   fog distance 5000
   backdrop on
   color backdrop rgb(0,0,50)
 
   `make bullets
   #constant bulletStart = 1000
   #constant bulletQuant = 500
   global currentBullet
   dim Bullet(bulletQuant)
   for i = 1 to bulletQuant
      make object box bulletStart + i, 0.1, 0.2, 1
      color object bulletStart + i, rgb(255, 0, 0)
      set object emissive bulletStart + i, rgb(255,0,0)
      set object ambient bulletStart + i, rgb(255,0,0)
      hide object bulletStart + i
   next i
 
return
 
`************************************
`           LOSE/WIN
`************************************
 
Lose:
 
   sync
 
   center text screen width()/2, screen height()/2, "You lose!"
   center text screen width()/2, screen height()/2 + 50, "Press any key to restart, esc to quit."
 
   sync
 
   wait 2000
 
wait key
 
Enemies = 5
goto Restart
 
Win:
 
   inc Level
 
   sync
 
   center text screen width()/2, screen height()/2, "You win!"
   center text screen width()/2, screen height()/2 + 50, "Press any key to go to level " + str$(Level) + ", esc to quit."
 
   sync
 
   wait 2000
wait key
 
Enemies = Enemies + 2
goto Restart
 
`************************************
`Function
`************************************
 
function ControlPlayer(id, angx#, angy#, move, back, left, right, shoot)
 
   `Extract data
   obj = Player(id).id
   posx# = object position x(obj)
   posy# = object position y(obj)
   posz# = object position z(obj)
   Weapon = Player(id).WeaponDrawed
 
   `animate character
   animate(obj)
 
   `Control player
 
   `move the player
   if Weapon = 1
      move# = Player(id).Move
      rotate limb obj,2,wrapvalue(angx#-90),0,0
      rotate limb obj,3, 0, 0, 0
   else
      move# = Player(id).Run
   endif
   if move = 1 and left+right = 0
      posx# = newxvalue(posx#, angy#, move#)
      posz# = newzvalue(posz#, angy#, move#)
   endif
   if back = 1 and left+right = 0
      posx# = newxvalue(posx#, angy#, -move#)
      posz# = newzvalue(posz#, angy#, -move#)
   endif
   if left = 1
      yrotate object obj, wrapvalue(angy# - 90)
      if Weapon > 0
         rotate limb obj,2, wrapvalue(angx#-90), 90, 0
         rotate limb obj,3, 0, 0, 0
      endif
      posx# = newxvalue(posx#, wrapvalue(angy# - 90), move#)
      posz# = newzvalue(posz#, wrapvalue(angy# - 90), move#)
   endif
   if right = 1
      yrotate object obj, wrapvalue(angy# + 90)
      if Weapon > 0
         rotate limb obj,2, -90,0,-10
         rotate limb obj,3, wrapvalue(angx#), 0, -90
      endif
      posx# = newxvalue(posx#, wrapvalue(angy# + 90), move#)
      posz# = newzvalue(posz#, wrapvalue(angy# + 90), move#)
   endif
 
   `animate
   if left + right + move + back > 0
      if Player(id).aph <= 2 then Player(id).aph = 3
   else
      if Player(id).aph > 2 then Player(id).aph = 0
   endif
 
   `Shooting
   if Weapon > 0
      if Player(id).delay > 0 then dec Player(id).delay
      if shoot > 0 and Player(id).delay = 0
         Player(id).delay = Player(id).maxdelay
         inc currentBullet
         if currentBullet > bulletQuant then currentBullet = 1
         position object bulletStart + currentBullet, limb position x(obj,2), limb position y(obj,2), limb position z(obj,2)
         rotate object bulletStart + currentBullet, angx#, angy#, 0
         if right > 0 then move object right bulletStart + currentBullet, 2.0
         move object bulletStart + currentBullet, 6
         show object bulletStart + currentBullet
         Bullet(currentBullet) = 150
      endif
   endif
 
   `calculate height
   posy# = get ground height(1, posx#, posz#) + 4
 
   `Boundries
   if posx# < 0.0 then posx# = 0.0
   if posz# < 0.0 then posz# = 0.0
   if posx# > 1000.0 then posx# = 1000.0
   if posz# > 1000.0 then posz# = 1000.0
 
   `update player
   position object obj, posx#, posy#, posz#
   if left + right = 0
      yrotate object obj, angy#
   endif
 
endfunction
 
function animate(id)
 
   obj = Player(id).id
   Phase = Player(id).aph
 
   `Animate character
   if Phase <= 2
      select Phase
         case 0
            `reset body
            for i = 1 to 8
               rotate limb obj,i,0,0,0
            next i
            Player(id).aph = 1
         endcase
         case 1
            pass = 0
            if wrapvalue(limb angle x(obj,6)+180)>150
               rotate limb obj,6,wrapvalue(limb angle x(obj,6)-0.1),0,0
               rotate limb obj,7,wrapvalue(360-limb angle x(obj,6)),0,0
            else
               pass=1
            endif
            if wrapvalue(limb angle x(obj,8)+180)>150
               rotate limb obj,8,wrapvalue(limb angle x(obj,8)-0.1),0,0
               rotate limb obj,9,wrapvalue(360-limb angle x(obj,8)),0,0
            else
               pass=1
            endif
            if pass = 1 then Player(id).aph = 2
         endcase
         case 2
            pass = 0
            if wrapvalue(limb angle x(obj,6)+180)<180
               rotate limb obj,6,wrapvalue(limb angle x(obj,6)+0.1),0,0
               rotate limb obj,7,wrapvalue(360-limb angle x(obj,6)),0,0
            else
               pass=1
            endif
            if wrapvalue(limb angle x(obj,8)+180)<180
               rotate limb obj,8,wrapvalue(limb angle x(obj,8)+0.1),0,0
               rotate limb obj,9,wrapvalue(360-limb angle x(obj,8)),0,0
            else
               pass=1
            endif
            if pass = 1 then Player(id).aph = 1
         endcase
      endselect
      rotate limb obj,2,0,0,0 : rotate limb obj,3,0,0,0
      rotate limb obj,4,0,0,0 : rotate limb obj,5,0,0,0
   endif
   if Phase>2 and Phase<=5
      select Phase
         case 3
            `reset body
            for i = 1 to 8
               rotate limb obj,i,0,0,0
            next i
            Player(id).aph = 4
         endcase
         case 4
            pass = 0
            if wrapvalue(limb angle x(obj, 6)-180) < 210
               rotate limb obj,6,wrapvalue(limb angle x(obj,6)+2),0,0
               rotate limb obj,7,wrapvalue(30 - limb angle x(obj,6)),0,0
            else
               pass = 1
            endif
            if wrapvalue(limb angle x(obj, 8)-180) > 150
               rotate limb obj,8,wrapvalue(limb angle x(obj,8)-2),0,0
               rotate limb obj,9,wrapvalue(30-limb angle x(obj,8)),0,0
            else
               pass = 1
            endif
            if pass = 1 then Player(id).aph = 5
         endcase
         case 5
            pass = 0
            if wrapvalue(limb angle x(obj,6)-180) > 150
               rotate limb obj,6,wrapvalue(limb angle x(obj,6)-2),0,0
               rotate limb obj,7,wrapvalue(30-limb angle x(obj,6)),0,0
            else
               pass = 1
            endif
            if wrapvalue(limb angle x(obj,8)-180) < 210
               rotate limb obj,8,wrapvalue(limb angle x(obj,8)+2),0,0
               rotate limb obj,9,wrapvalue(30-limb angle x(obj,8)),0,0
            else
               pass = 1
            endif
            if pass = 1 then Player(id).aph = 4
         endcase
      endselect
      rotate limb obj,2, limb angle x(obj,8),0,0
      rotate limb obj,4, limb angle x(obj,6),0,0
      rotate limb obj,3, -100,0,0
      rotate limb obj,5, -100,0,0
   endif
 
endfunction
 
function CamBehind(obj, Dist#, Height#, RightOff#, angx#, angy#)
 
   `get position data
   posx# = object position x(obj)
   posy# = object position y(obj) + Height#
   posz# = object position z(obj)
   angy# = wrapvalue(angy#-180)
 
   `work out the camera position
   camx# = newxvalue(posx#, angy#, cos(angx#)*Dist#)
   camz# = newzvalue(posz#, angy#, cos(angx#)*Dist#)
   camy# = posy# + (sin(angx#)*Dist#)
 
   `Work out right of cam pos
   camx# = newxvalue(camx#, wrapvalue(angy#-90), RightOff#)
   camz# = newzvalue(camz#, wrapvalue(angy#-90), RightOff#)
 
   `smoothen up
   camx# = curvevalue(camx#, camera position x(), 5)
   camy# = curvevalue(camy#, camera position y(), 5)
   camz# = curvevalue(camz#, camera position z(), 5)
 
   `collision with ground
   if camy# < get ground height(1, camx#, camz#)+1
      distance# = sqrt(Dist#^2 - (posy#-get ground height(1,posx#,posz#))^2)
      camx# = newxvalue(posx#, angy#, distance#)
      camz# = newzvalue(posz#, angy#, distance#)
      camy# = get ground height(1, camx#, camz#)+1
   endif
 
   `update camera
   position camera camx#,camy#,camz#
   point camera newxvalue(posx#, wrapvalue(angy#-90), RightOff#), posy#, newzvalue(posz#, wrapvalue(angy#-90), RightOff#)
 
endfunction
 
function CreateGrassTex(nr, Width, Height)
 
 
   `create a memblock
   make memblock nr, 12 + (Width*Height*4)
 
   `write header
   write memblock DWORD nr,0, Width
   write memblock DWORD nr,4, Height
   write memblock DWORD nr,8, 32
 
   `write data
   for i = 1 to (Width*Height)
      green = 50 + rnd(55)
      write memblock byte nr, 12 + ((i-1)*4), 0
      write memblock byte nr, 13 + ((i-1)*4), green
      write memblock byte nr, 14 + ((i-1)*4), 0
      write memblock byte nr, 15 + ((i-1)*4), 255
   next i
 
   `create an image from the memblock and delete memblock
   make image from memblock nr,nr
   delete memblock nr
 
endfunction
 
function CreateSkyTex(nr, width, height)
   make memblock nr, 12 + (width*height*4)
   write memblock dword nr, 0, width
   write memblock dword nr, 4, height
   write memblock dword nr, 8, 32
   for y = 1 to height
      for x = 1 to width
         pos = 12 + ((y-1)*width*4) + ((x-1)*4)
         BW = rnd(10)
         if BW > 0
            blue = 255
            green = rnd(255)
            red = green
         else
            blue = 255
            green = blue
            red = green
         endif
         write memblock byte nr, pos, blue
         write memblock byte nr, pos+1, green
         write memblock byte nr, pos+2, red
         write memblock byte nr, pos+3, 255
      next x
   next y
   make image from memblock nr, nr
   create bitmap nr, width, height
   set current bitmap nr
   paste image nr, 0, 0
   blur bitmap nr, 2
   blur bitmap nr, 2
   get image nr, 0,0, width, height
   delete bitmap nr
   set current bitmap 0
endfunction