sync on
sync rate 0
autocam off
set display mode 1280, 1024, 32
set ambient light 0
randomize timer()
color backdrop 0
 
`CONSTANTS GO HERE
`constants for the stats panel
   #constant STATS_IMG_W 16
   #constant STATS_IMG_H 48
   #constant STATS_IMG_TRANSPARENCY_MASK_A 0x66FFFFFF
   #constant STATS_IMG_TRANSPARENCY_MASK_B 0x33FFFFFF
`constant for enemy creation
   #constant ENEMY_WEAPON_SIZE 3.0
   #constant CREATION_TIMER 5000
`Map generation constants
   #constant TEXTURE_SIZE 64
`Control Keys (NOT CURRENTLY USED, but usefull to keep ;-) hehe)
   #constant KeyW 17
   #constant KeyA 30
   #constant KeyS 31
   #constant KeyD 32
`Player contants
   #constant TARGET_COLOR 0xFF0000  :`Used for the targetting blob
   #constant PLAYER_SPEED 3.0
   #constant PLAYER_WEAPON_SIZE 5.0
 
 
`Create the stats panel temaplate...
global STATS_IMG_SIZE
STATS_IMG_SIZE = 12 + (STATS_IMG_W * STATS_IMG_H * 4)
CREATE_STATS_PANEL_TEMPLATE()
 
make memblock 1, 12 + (TEXTURE_SIZE * TEXTURE_SIZE * 4)
write memblock dword 1, 0, TEXTURE_SIZE
write memblock dword 1, 4, TEXTURE_SIZE
write memblock dword 1, 8, 32
c as dword
for x = 0 to TEXTURE_SIZE - 1
   for y = 0 to TEXTURE_SIZE - 1
      c = rgb(32, 128 + rnd(127), 32)
      write memblock dword 1, 12 + ((y*TEXTURE_SIZE)+x)*4, c
   next y
next x
make image from memblock 1, 1
delete memblock 1
 
 
 
 
`This is here so I can see the arguements easier :-)
`function GENERATE_TERRAIN(obj, img, W, H, MAX_HEIGHT#, SMOOTHING_ITTERATIONS, SMOOTHING_FACTOR#, MAPSCALE#, USCALE#, VSCALE#)
 
`Create the terrain
GENERATE_TERRAIN(1, 1, 64, 64, 50.0, 4, 0.75, 4.0, 2.0, 2.0)
position object 1, 0, 0, 0
 
 
 
 
`Create the player + Data
Type Coord
   x#
   y#
   z#
EndType
Type PlayerData
   Pos as Coord
   moved as boolean
   Target as Coord
   Health#
EndType
 
`Create player details
P as PlayerData
P.Pos.x# = 10
P.Pos.z# = 10
P.Pos.y# = GET_CUSTOM_TERRAIN_HEIGHT(1, P.Pos.x#, P.Pos.z#) + object size y(1) * 0.5
P.Target.x# = P.Pos.x# + 0.0001
P.Target.z# = P.Pos.z#
P.Health# = 41
 
`Start the player as moved - this is to make sure everything starts in the right place.
P.moved = 1
`Create the player
CREATE_CHARACTER(2, 0xCCCCDD, PLAYER_WEAPON_SIZE)
`Position it
position object 2, P.Pos.x#, P.Pos.y#, P.Pos.z#
`Make health bar
MAKE_HEALTH_BAR(2, int(P.Health#))
`Create a temporary vector for working out headings
null = make vector2(1)
 
 
 
`Target Object stuff
make object sphere 3, 0.5  :`Target Object for when moving
set object transparency 3, 3
color object 3, TARGET_COLOR
a as DWORD
CLICK_DIST# = 0.0
 
`Lighting
set point light 0, 0, 0, 0
set light range 0, 40
 
 
`Enemy Data Stuff
EnemyTimer = 0
 
Type EnemyData
   Pos as Coord
   TimeToLive#
   Health#
EndType
 
 
`Create the enemies
Dim Enemies(5) as EnemyData
for i = 0 to 5
   `Create a new character, but with a smaller weapon.. Also comes in Yellow
   CREATE_CHARACTER(i+1000, rgb(255,255,0) && STATS_IMG_TRANSPARENCY_MASK_A, ENEMY_WEAPON_SIZE)
   Enemies(i).Health# = -1
   `Hide the object until its needed... Excluding would be better - but it is bugged, so hiding it is!
   hide object i+1000
next u
`This is used for calculating distances for firing from the enemy
null = make vector3(2)
 
global msg$
 
 
`Mouse Status
mouseStatus = 0
 
frameTime# = 1.0
startTime = timer()
do
   frameTime# = (frameTime# * 0.8) + ((timer() - startTime) * 0.2)
   startTime = timer()
   text 0,0, "FPS: " + str$(screen fps())
   paste image 10, screen width() - TEXTURE_SIZE, 0
 
   if mouseclick() = 1 AND mouseStatus = 0
      P.moved = 1
      mouseStatus = mouseclick()
      null = pick object(mousex(), mousey(), 1, 1)
      P.Target.x# = camera position x() + get pick vector x()
      P.Target.z# = camera position z() + get pick vector z()
      position object 3, P.Target.x#, GET_CUSTOM_TERRAIN_HEIGHT(1,P.Target.x#,P.Target.z#) + 0.25, P.Target.z#
      point object 2, object position x(3), object position y(3), object position z(3)
 
      set vector2 1, P.Target.x# - P.Pos.x#, P.Target.z# - P.Pos.z#
      CLICK_DIST# = length vector2(1)*1.5
      a = 255
   else
      if mouseclick() = 0 then mouseStatus = 0
   endif
 
   if P.moved
      set vector2 1, P.Target.x# - P.Pos.x#, P.Target.z# - P.Pos.z#
      dist# = length vector2(1)
 
      if dist# < 0.1 then P.moved = 0
 
      a = (dist# / CLICK_DIST#) * 255.0
      color object 3, (a << 24) || TARGET_COLOR
 
      normalize vector2 1, 1
 
      inc P.Pos.x#, x vector2(1) * frameTime# * 0.001 * PLAYER_SPEED
      inc P.Pos.z#, y vector2(1) * frameTime# * 0.001 * PLAYER_SPEED
      P.Pos.y# = GET_CUSTOM_TERRAIN_HEIGHT(1, P.Pos.x#, P.Pos.z#) + 0.5
 
      position object 2, P.Pos.x#, P.Pos.y#, P.Pos.z#
 
      position light 0, P.Pos.x#, P.Pos.y# + 10, P.Pos.z#
 
      position camera P.Pos.x# + 10, P.Pos.y# + 10, P.Pos.z# + 10
      point camera P.Pos.x#, P.Pos.y#, P.Pos.z#
   endif
 
   `Show player health. This If statement is just to make sure nothing bad happens if its not made yet...
   if image exist(2)
      paste image 2, object screen x(2), object screen y(2) - STATS_IMG_H, 1
   endif
 
 
 
   if spacekey() then show limb 2,2 else hide limb 2,2
 
 
   text 0, 20, "T: " + str$(timer() - EnemyTimer)
   if timer() - EnemyTimer > CREATION_TIMER then CREATE_ENEMY() : EnemyTimer = timer()
   gosub PROCESS_ENEMIES
 
   sync
loop
end
 
 
 
PROCESS_ENEMIES:
   for obj = 1000 to 1005
      if object visible(obj)
         enemyId = obj-1000
         enemyImg = obj-900
         point object obj, P.Pos.x#, P.Pos.y#, P.Pos.z#
         if Enemies(enemyId).TimeToLive# < 0.5
            inc Enemies(enemyId).TimeToLive#, frameTime# * 0.001
         else
            move object obj, frameTime# * 0.0005
         endif
         position object obj, object position x(obj), GET_CUSTOM_TERRAIN_HEIGHT(1, object position x(obj), object position z(obj)) + Enemies(enemyId).TimeToLive#, object position z(obj)
 
         Enemies(enemyId).Pos.x# = object position x(obj)
         Enemies(enemyId).Pos.y# = object position y(obj)
         Enemies(enemyId).Pos.z# = object position z(obj)
         set vector3 2, Enemies(enemyId).Pos.x# - P.Pos.x#,  Enemies(enemyId).Pos.y# - P.Pos.y#,  Enemies(enemyId).Pos.z# - P.Pos.z#
         if length vector3(2) < ENEMY_WEAPON_SIZE+0.5
            show limb obj,2
            if object collision(obj, 2)
               dec P.Health#, frameTime# * 0.01
               MAKE_HEALTH_BAR(2, int(P.Health#))
            endif
         else
            hide limb obj, 2
         endif
 
 
         if limb visible(2,2) AND object collision(2, obj)
            `If enemy hit, then rediuce its health
            dec Enemies(enemyId).Health#, frameTime# * 0.05
            MAKE_HEALTH_BAR(enemyImg, int(Enemies(enemyId).Health#))
         endif
 
         `If the image exists (which it should, we just made it) then paste it. This is mainly to avoid crashes
         if image exist(enemyImg)
            paste image enemyImg, object screen x(obj), object screen y(obj) - STATS_IMG_H, 1
         endif
 
         `If the enemy is out of health - delete it
         if Enemies(enemyId).Health# <= 0
            hide object obj
            inc P.Health#, 20.0
            if P.Health# > 41 then P.Health# = 41
         endif
      endif
   next obj
return
 
 
 
 
function CREATE_ENEMY()
   obj = 1000
   while Enemies(obj-1000).Health# > 0 AND obj < 1005 : inc obj : endwhile
 
   if object exist(obj)
      show object obj
      `Create Image and array index for this enemy object
      enemyImg = obj - 900
      enemyID = obj - 1000
 
      `Create a random position for the enemy
      Enemies(enemyID).Pos.x# = rnd(5.0)
      Enemies(enemyID).Pos.z# = rnd(5.0)
      `If rnd(1) = 1 then position the object in the negative x/z direction, otherwise positive.
      `The static 5 is to make sure its a fair minimum distance from the player when spawned
      if rnd(1) then Enemies(enemyID).Pos.x# = -Enemies(enemyID).Pos.x# - 5.0 else inc Enemies(enemyID).Pos.x#, 5.0
      if rnd(1) then Enemies(enemyID).Pos.z# = -Enemies(enemyID).Pos.z# - 5.0 else inc Enemies(enemyID).Pos.z#, 5.0
 
      `This offsets the enemy so the random position above is relative to the player
      inc Enemies(enemyID).Pos.x#, P.Pos.x#
      inc Enemies(enemyID).Pos.z#, P.Pos.z#
 
      `Now we know exactly where the enemy is - we can work out how high up to put it
      Enemies(enemyId).Pos.y# = GET_CUSTOM_TERRAIN_HEIGHT(1, Enemies(enemyID).Pos.x#, Enemies(enemyID).Pos.z#) - 0.5
 
      `Now we have all 3 coords, we can position and point.
      position object obj, Enemies(enemyID).Pos.x#, Enemies(enemyID).Pos.y#, Enemies(enemyID).Pos.z#
      point object obj, P.Pos.x#, P.Pos.y#, P.Pos.z#
 
      `TimeToLive# is the vertical offset. It starts at -1.0 as that puts it underground.
      `When its +0.5 then its above ground and can start heading for the player
      Enemies(enemyId).TimeToLive# = -1.0
      `Starting health - might be a strange number, but it just makes the health bar easier ;-)
      Enemies(enemyId).Health# = 41.0
      `Create the health bar
      MAKE_HEALTH_BAR(enemyImg, int(Enemies(enemyId).Health#))
   endif
 
endfunction
 
 
 
 
function MAKE_HEALTH_BAR(img, health)
   `Create memblock if it doesn't exist
   if memblock exist(img) = 0 then make memblock img, STATS_IMG_SIZE
   `Copy in the template memblock image
   copy memblock 99, img, 0, 0, STATS_IMG_SIZE
   `Loop through the middle bar and write in the required bar pixels
   for x = 3 to 12
      for y = 44-health to 44
         write memblock dword img, 12 + ((y*STATS_IMG_W) + x)*4, rgb(255, 0, 0) && STATS_IMG_TRANSPARENCY_MASK_A
      next y
   next x
   `Turn it into an image :-)
   make image from memblock img, img
endfunction
 
 
 
 
function CREATE_CHARACTER(obj, c, weaponLength#)
   `Main body of character
   make object sphere obj, 1
   `The nose - mainly so you know where you're going ;-)
   make object cone 10000, 1
   `Scale the nose to make it more "nosey"
   scale object 10000, 50.0, 100.0, 50.0
   `Turn it into a mesh so it can be added as a limb
   make mesh from object 10, 10000
   `Add the mesh to the bodo object
   add limb obj, 1, 10
   `rotate and offset it to put it in the right place
   rotate limb obj, 1, 90, 0, 0
   offset limb obj, 1, 0.0, 0.0, 0.5
   `Make the bar-o-spacekey
   make object cone 10001, 1
   `Offset it so it pivots on its end
   offset limb 10001, 0, 0.0, 0.0, 0.5
   `scale it up to make it a big bar-o-death
   scale object 10001, 100, 100, 100*weaponLength#
   `Rotate it so it points out front and is not a bar-o-suicide
   rotate limb 10001, 0, -90, 0, 0
   `turn it into a mesh
   make mesh from object 11, 10001
   `add that mesh to the player
   add limb obj, 2, 11
   `hide the limb so we can fire when needed
   hide limb obj, 2
   `Color the object in
   color object obj, c
 
   set object collision to polygons obj
 
   `cleanup
   delete object 10000
   delete object 10001
   delete mesh 10
   delete mesh 11
endfunction
 
 
 
 
 
 
 
 
function GET_CUSTOM_TERRAIN_HEIGHT(obj, x#, z#)
   height# = 1000.0 - intersect object(obj, x#, 1000, z#,  x#, -1000, z#)
endfunction height#
 
 
 
 
function GENERATE_TERRAIN(obj, img, W, H, MAX_HEIGHT#, SMOOTHING_ITTERATIONS, SMOOTHING_FACTOR#, MAPSCALE#, USCALE#, VSCALE#)
   dim HEIGHTMAP#(W,H)
   dim NORMALS#(W,H,3)
 
   for i = 0 to W-1
      for j = 0 to H-1
         HEIGHTMAP#(i, j) = rnd(MAX_HEIGHT#)
      next j
   next i
 
 
   for iters = 0 to SMOOTHING_ITTERATIONS
      for i = 0   to W-1       : for j = 0 to H           : HEIGHTMAP#(i, j) = (HEIGHTMAP#(i,j) * SMOOTHING_FACTOR#) + (HEIGHTMAP#(i+1,j) * (1.0-SMOOTHING_FACTOR#)) : next j : next i
      for i = W-1 to 0  step -1: for j = 0 to H           : HEIGHTMAP#(i, j) = (HEIGHTMAP#(i,j) * SMOOTHING_FACTOR#) + (HEIGHTMAP#(i+1,j) * (1.0-SMOOTHING_FACTOR#)) : next j : next i
      for i = 0 to W           : for j = 0 to H-1         : HEIGHTMAP#(i, j) = (HEIGHTMAP#(i,j) * SMOOTHING_FACTOR#) + (HEIGHTMAP#(i,j+1) * (1.0-SMOOTHING_FACTOR#)) : next j : next i
      for i = 0 to W           : for j = H-1 to 0 step -1 : HEIGHTMAP#(i, j) = (HEIGHTMAP#(i,j) * SMOOTHING_FACTOR#) + (HEIGHTMAP#(i,j+1) * (1.0-SMOOTHING_FACTOR#)) : next j : next i
   next iters
 
 
   colValue = 255 / MAX_HEIGHT#
   make memblock 1, 12 + (W*H*4)
   write memblock dword 1, 0, W
   write memblock dword 1, 4, H
   write memblock dword 1, 8, 32
   for i = 0 to W-1
      for j = 0 to H-1
         c = HEIGHTMAP#(i,j)*colValue
         write memblock dword 1, 12 + ((j*W)+i)*4, rgb(c,c,c)
      next j
   next i
   make image from memblock 10, 1
 
 
 
 
   ` CALCULATE NORMALS
 
   for i = 1 to W-1
      for j = 1 to H-1
         null = make vector3(1)
         null = make vector3(2)
         null = make vector3(3)
         null = make vector3(4)
         null = make vector3(5)
         null = make vector3(6)
         null = make vector3(7)
         null = make vector3(8)
         null = make vector3(9)
 
         set vector3 1,  MAPSCALE#, HEIGHTMAP#(i,j) - HEIGHTMAP#(i+1,j  ),  0
         set vector3 2,          0, HEIGHTMAP#(i,j) - HEIGHTMAP#(i  ,j-1), -MAPSCALE#
         set vector3 3, -MAPSCALE#, HEIGHTMAP#(i,j) - HEIGHTMAP#(i-1,j  ),  0
         set vector3 4,          0, HEIGHTMAP#(i,j) - HEIGHTMAP#(i  ,j+1),  MAPSCALE#
 
 
         cross product vector3 5, 1, 2
         cross product vector3 6, 2, 3
         cross product vector3 7, 3, 4
         cross product vector3 8, 4, 1
 
         add vector3 9, 9, 5
         add vector3 9, 9, 6
         add vector3 9, 9, 7
         add vector3 9, 9, 8
         divide vector3 9, 4
         normalize vector3 9, 9
         NORMALS#(i,j,0) = x vector3(9)
         NORMALS#(i,j,1) = y vector3(9)
         NORMALS#(i,j,2) = z vector3(9)
         null = delete vector3(1)
         null = delete vector3(2)
         null = delete vector3(3)
         null = delete vector3(4)
         null = delete vector3(5)
         null = delete vector3(6)
         null = delete vector3(7)
         null = delete vector3(8)
         null = delete vector3(9)
      next j
   next i
 
 
   if memblock exist(1) then delete memblock 1
   make memblock 1, 12 + (32 * 3 * 2 * W * H)
 
   write memblock dword 1,0,274 : `FVF FORMAT
   write memblock dword 1,4,32  : `SIZE PER VERT
   write memblock dword 1,8,W*H*2*3   : `VERT NO
 
 
   poly = 0
   for i = 0 to W-1
      for j = 0 to H-1
         ` ** POLY 1 **
         x = i   : z = j   : CREATE_MESH_ENTRY(1, 12 + (poly * 192)      , (x - (W/2)) * MAPSCALE#, HEIGHTMAP#(x,z), (z - (H/2)) * MAPSCALE#,   NORMALS#(x,z,0), NORMALS#(x,z,1), NORMALS#(x,z,2), 0.0    , 0.0    )
         x = i   : z = j+1 : CREATE_MESH_ENTRY(1, 12 + (poly * 192) +  32, (x - (W/2)) * MAPSCALE#, HEIGHTMAP#(x,z), (z - (H/2)) * MAPSCALE#,   NORMALS#(x,z,0), NORMALS#(x,z,1), NORMALS#(x,z,2), 0.0    , VSCALE#)
         x = i+1 : z = j   : CREATE_MESH_ENTRY(1, 12 + (poly * 192) +  64, (x - (W/2)) * MAPSCALE#, HEIGHTMAP#(x,z), (z - (H/2)) * MAPSCALE#,   NORMALS#(x,z,0), NORMALS#(x,z,1), NORMALS#(x,z,2), USCALE#, 0.0    )
         ` ** POLY 2 **
         x = i+1 : z = j   : CREATE_MESH_ENTRY(1, 12 + (poly * 192) +  96, (x - (W/2)) * MAPSCALE#, HEIGHTMAP#(x,z), (z - (H/2)) * MAPSCALE#,   NORMALS#(x,z,0), NORMALS#(x,z,1), NORMALS#(x,z,2), USCALE#, 0.0    )
         x = i   : z = j+1 : CREATE_MESH_ENTRY(1, 12 + (poly * 192) + 128, (x - (W/2)) * MAPSCALE#, HEIGHTMAP#(x,z), (z - (H/2)) * MAPSCALE#,   NORMALS#(x,z,0), NORMALS#(x,z,1), NORMALS#(x,z,2), 0.0    , VSCALE#)
         x = i+1 : z = j+1 : CREATE_MESH_ENTRY(1, 12 + (poly * 192) + 160, (x - (W/2)) * MAPSCALE#, HEIGHTMAP#(x,z), (z - (H/2)) * MAPSCALE#,   NORMALS#(x,z,0), NORMALS#(x,z,1), NORMALS#(x,z,2), USCALE#, VSCALE#)
         inc poly
      next j
   next i
 
 
   make mesh from memblock 1, 1
   if object exist(obj) = 1 then delete object obj
   make object obj, 1, img
   delete mesh 1
   delete memblock 1
endfunction
 
 
 
 
function CREATE_MESH_ENTRY(memblockNum, n, x#, y#, z#, nx#, ny#, nz#, u#, v#)
   write memblock float 1, n +  0, x#
   write memblock float 1, n +  4, y#
   write memblock float 1, n +  8, z#
   write memblock float 1, n + 12, nx#
   write memblock float 1, n + 16, ny#
   write memblock float 1, n + 20, nz#
   write memblock float 1, n + 24, u#
   write memblock float 1, n + 28, v#
endfunction
 
 
 
 
function CREATE_STATS_PANEL_TEMPLATE()
   `Create Stats Panel
   make memblock 99, STATS_IMG_SIZE
   write memblock dword 99, 0, STATS_IMG_W
   write memblock dword 99, 4, STATS_IMG_H
   write memblock dword 99, 8, 32
   for x = 0 to STATS_IMG_W - 1
      for y = 0 to STATS_IMG_H - 1
         if x > 3 AND x < 12 AND y > 3 AND y < 44
            write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, rgb(160, 160, 160) && STATS_IMG_TRANSPARENCY_MASK_B
         else
            write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, rgb(160, 160, 160) && STATS_IMG_TRANSPARENCY_MASK_A
         endif
      next y
   next x
   `TopLeft
   x = 0 : y = 0 : write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, 0
   x = 1 : y = 0 : write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, 0
   x = 0 : y = 1 : write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, 0
 
   `TopRight
   x = STATS_IMG_W-1 : y = 0 : write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, 0
   x = STATS_IMG_W-2 : y = 0 : write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, 0
   x = STATS_IMG_W-1 : y = 1 : write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, 0
 
   `BottomRight
   x = STATS_IMG_W-1 : y = STATS_IMG_H-1 : write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, 0
   x = STATS_IMG_W-2 : y = STATS_IMG_H-1 : write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, 0
   x = STATS_IMG_W-1 : y = STATS_IMG_H-2 : write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, 0
 
   `BottomLeft
   x = 0 : y = STATS_IMG_H-1 : write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, 0
   x = 1 : y = STATS_IMG_H-1 : write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, 0
   x = 0 : y = STATS_IMG_H-2 : write memblock dword 99, 12 + ((y*STATS_IMG_W) + x)*4, 0
endfunction