REM Project: AGE OF PRIMITIVES
REM Created: 3/14/2005 2:11:39 PM
REM     by Coding Fodder
REM ***** Main Source File *****
REM
sync on:sync rate 0
autocam off
 
type unit
   owner as integer
   kind as integer
   radius as float
   range as float
   attack as integer
   hitpoints as integer
   armor as integer
   speed as float
   attack_speed as integer
   harvest_speed as integer
   goalx as float
   goalz as float
   posx as float
   posz as float
   target as integer
   actiontime as float
   animation as integer
   animation_frame as integer
endtype
 
Dim units(1000) as unit
dim unit_list(1000) as boolean
dim selected_units(30)
dim battalion(10,30)
 
global game_time#
global last_time#
global time_step#
global units_selected
 
make object cube 10,100
hide object 10
game_time#=timer()/1000.0
make_land()
position camera 0,0,1000,150
point camera 0,0,1000,-200
pitch camera down 70
set directional light 0,1,-2,-0.7
 
for i=1 to 10
   create_fighter(rnd(1)+1,rnd(1000)-500,rnd(1000)-500)
next i
 
for i=1 to 10
   create_worker(rnd(1)+1,rnd(1000)-500,rnd(1000)-500)
next i
 
for i=1 to 50
   create_resource(rnd(5000)-2500,rnd(5000)-2500)
next i
 
 
do
   last_time#=game_time#
   game_time#=timer()/1000.0
   time_step#=game_time#-last_time#
   select_unit()
   display_selected()
   command_selected()
   camera_control()
   mouse_indicator()
   move_units()
   perform_action()
   check_death()
   text 1,1,str$(screen fps())
   sync
loop
 
function check_death()
   for i=1 to 999
      if unit_list(i)=1
         if units(i).hitpoints<=0 then remove_unit(i)
      endif
   next i
endfunction
 
function remove_unit(num)
   delete object num+1000
   unit_list(num)=0
   units(num).owner=0
   units(num).kind=0
   units(num).radius=0
   units(num).range=0
   units(num).attack=0
   units(num).hitpoints=0
   units(num).armor=0
   units(num).speed=0
   units(num).harvest_speed=0
   units(num).goalx=0
   units(num).goalz=0
   units(num).target=0
   units(num).actiontime=0
   units(num).animation=0
   units(num).animation_frame=0
 
   for i=1 to 10
      for j=1 to 30
         if battalion(i,j)=num
            for h=j to 29
               battalion(i,h)=battalion(i,h+1)
            next h
         endif
      next j
   next i
   for j=1 to units_selected
      if selected_units(j)=num
         for h=j to units_selected-1
            selected_units(h)=selected_units(h+1)
         next h
         dec units_selected
      endif
   next j
endfunction
 
function perform_action()
   for i=1 to 999
      if unit_list(i)=1
         if units(i).target>0
            target=units(i).target
            if units(target).owner>0
               if abs(game_time#-units(i).actiontime)>=units(i).attack_speed
                  if ((units(i).radius+units(i).range+units(target).radius)^2.0)>=((units(i).posx-units(target).posx)^2.0+(units(i).posz-units(target).posz)^2.0)
                     units(i).actiontime=game_time#
                     units(i).animation=1
                     units(i).animation_frame=1
                     units(target).hitpoints=units(target).hitpoints-units(i).attack
                  endif
               endif
            else
               if abs(units(i).actiontime-game_time#)>=units(i).harvest_speed
                     if ((units(i).radius+units(target).radius)^2.0)>=((units(i).posx-units(target).posx)^2.0+(units(i).posz-units(target).posz)^2.0)-5
                     units(i).actiontime=game_time#
                     units(i).animation=2
                     units(i).animation_frame=1
                  endif
               endif
            endif
         endif
         select units(i).animation
            case 1:position object i+1000,object position x(i+1000),sin(units(i).animation_frame)*20.0+20,object position z(i+1000)
                   units(i).animation_frame=units(i).animation_frame+time_step#*300.0
                   if units(i).animation_frame>180 then units(i).animation=0
            endcase
         endselect
      endif
   next i
endfunction
 
function move_units()
   for i=0 to 999
      if unit_list(i)=1
         if units(i).target>0
            units(i).goalx=units(units(i).target).posx
            units(i).goalz=units(units(i).target).posz
         endif
         dist#=time_step#*units(i).speed
         totaldist#=((units(i).posx-units(i).goalx)^2.0+(units(i).posz-units(i).goalz)^2.0)
         if totaldist#>100
            angle#=atanfull(units(i).goalx-units(i).posx,units(i).goalz-units(i).posz)
            tempx#=units(i).posx
            tempz#=units(i).posz
            clear=0
            counter=0
            repeat
               x#=tempx#+sin(angle#)*dist#
               z#=tempz#+cos(angle#)*dist#
               position_unit(i,x#,z#)
               if collision(i)=0
                  clear=1
               else
                  if totaldist#<1700
                     clear=1
                     position_unit(i,tempx#,tempz#)
                  endif
               endif
               dec angle#,10.0
               inc counter
            until clear=1 or counter=36
            if counter=36 then position_unit(i,tempx#,tempz#)
         endif
      endif
   next i
endfunction
 
function position_unit(num,x#,z#)
   position object num+1000,x#,object position y(num+1000),z#
   units(num).posx=x#
   units(num).posz=z#
endfunction
 
function mouse_indicator()
   follow#=3.0
   xdist#=mousex()-object screen x(10)
   zdist#=mousey()-object screen y(10)
   position object 10,object position x(10)-xdist#*follow#,0,object position z(10)+zdist#*follow#
endfunction
 
function command_selected()
   if units(selected_units(1)).owner=1
      if mouseclick()=2 or returnkey()=1
         obj=pick object(mousex(),mousey(),1000,1999)
         if obj=0
            for i=1 to units_selected
               set_unit_goal(selected_units(i),object position x(10),object position z(10))
               text 1,1,"please go here"
            next i
         else
            for i=1 to units_selected
               if units(obj-1000).owner>1
                  set_unit_target(selected_units(i),obj-1000)
               else
                  set_unit_goal(selected_units(i),object position x(10),object position z(10))
               endif
            next i
         endif
      endif
   endif
endfunction
 
function set_unit_goal(num,x#,z#)
   units(num).goalx=x#
   units(num).goalz=z#
   units(num).target=0
endfunction
 
function set_unit_target(num,target)
   units(num).target=target
endfunction
 
function display_selected()
   for i=1 to units_selected
      string$=""
      select units(selected_units(i)).kind
         case 1:string$="Fighter: ":endcase
         case 2:string$="Worker: ":endcase
         case 3:string$="Resource: ":endcase
      endselect
      string$=string$+" Hit points "+str$(units(selected_units(i)).hitpoints)
      text 1,i*15,string$
   next i
endfunction
 
function select_unit()
   if mouseclick()=1
      num=pick object(mousex(),mousey(),1000,1999)
      if num > 0
         if shiftkey()=1
            if units(num-1000).owner=1
               if units(selected_units(1)).owner>1 or units(selected_units(1)).owner=0
                  selected_units(1)=0
                  units_selected=0
               endif
               if units_selected<30
                  inc units_selected
                  selected_units(units_selected)=num-1000
                  for i=1 to units_selected-1
                     if selected_units(i)=num-1000
                        selected_units(units_selected)=0
                        dec units_selected
                     endif
                  next i
               endif
            else
               if units(selected_units(1)).owner>1 or units_selected=0 or units(selected_units(1)).owner=0
                  units_selected=1
                  selected_units(1)=num-1000
               endif
            endif
         else
            units_selected=1
            selected_units(1)=num-1000
         endif
      else
         if shiftkey()=0
            units_selected=0
            selected_units(1)=0
         endif
      endif
   endif
 
   if scancode()=2 then listswap(1)
   if scancode()=3 then listswap(2)
   if scancode()=4 then listswap(3)
   if scancode()=5 then listswap(4)
   if scancode()=6 then listswap(5)
   if scancode()=7 then listswap(6)
   if scancode()=8 then listswap(7)
   if scancode()=9 then listswap(8)
   if scancode()=10 then listswap(9)
   if scancode()=11 then listswap(10)
endfunction
 
function listswap(num)
   if controlkey()=1
      for i=1 to units_selected
         battalion(num,i)=0
         battalion(num,i)=selected_units(i)
      next i
      for i=units_selected+1 to 30
         battalion(num,i)=0
      next i
   else
      units_selected=0
      for i=1 to 30
         selected_units(i)=battalion(num,i)
         if battalion(num,i)>0 then inc units_selected
      next i
   endif
endfunction
 
function position_new_unit(num,x#,z#)
   position object num+1000,x#,object position y(num+1000),z#
   units(num).posx=x#
   units(num).posz=z#
   repeat
      if collision(num)=1
         inc angle#,1
         inc dist#,1
         position object num+1000,x#+cos(angle#)*dist#,object position y(num+1000),z#+sin(angle#)*dist#
         units(num).posx=x#+cos(angle#)*dist#
         units(num).posz=z#+sin(angle#)*dist#
      else
         clear=1
      endif
   until clear=1
   units(num).goalx=object position x(num+1000)
   units(num).goalz=object position z(num+1000)
endfunction
 
function collision(num)
   out=0
   select units(num).kind
      case 1:radius1#=20.0:endcase
      case 2:radius1#=20.0:endcase
      case 3:radius1#=40.0:endcase
   endselect
 
   for i=1 to num-1
      if unit_list(i)=1
         select units(i).kind
            case 1:radius#=20.0:endcase
            case 2:radius#=20.0:endcase
            case 3:radius#=40.0:endcase
         endselect
         if ((units(num).posx-units(i).posx)^2+(units(num).posz-units(i).posz)^2)<(radius1#+radius#)^2.0 then out=1
      endif
   next i
 
   for i=num+1 to 999
      if unit_list(i)=1
         select units(i).kind
            case 1:radius#=20.0:endcase
            case 2:radius#=20.0:endcase
            case 3:radius#=40.0:endcase
         endselect
         if ((units(num).posx-units(i).posx)^2+(units(num).posz-units(i).posz)^2)<(radius1#+radius#)^2.0 then out=1
      endif
   next i
endfunction out
 
function create_resource(x#,z#)
   num=empty_unit_number()
   if num<1000
      make object sphere num+1000,80
      color object num+1000,RGB(170,164,34)
      add_unit(num,0,3)
      position_new_unit(num,x#,z#)
   endif
endfunction
 
function create_worker(team,x#,z#)
   num=empty_unit_number()
   if num<1000
      make object sphere num+1000,40
      select team
         case 1:color object num+1000,rgb(0,0,255):endcase
         case 2:color object num+1000,rgb(255,0,0):endcase
      endselect
      add_unit(num,team,2)
      position object num+1000,0,20,0
      position_new_unit(num,x#,z#)
   endif
endfunction
 
function create_fighter(team,x#,z#)
   num=empty_unit_number()
   if num<1000
      make object cone num+1000,40
      select team
         case 1:color object num+1000,rgb(0,0,255):endcase
         case 2:color object num+1000,rgb(255,0,0):endcase
      endselect
      add_unit(num,team,1)
      position object num+1000,0,20,0
      position_new_unit(num,x#,z#)
   endif
endfunction
 
function add_unit(num,team,kind)
   unit_list(num)=1
   units(num).kind=kind
   units(num).owner=team
   units(num).posx=object position x(num+1000)
   units(num).posz=object position z(num+1000)
   units(num).goalx=object position x(num+1000)
   units(num).goalz=object position z(num+1000)
   select kind
      case 1:units(num).attack=10
             units(num).hitpoints=50
             units(num).speed=150.0
             units(num).attack_speed=2.0
             units(num).radius=20.0
             units(num).range=3.0
      endcase
      case 2:units(num).attack=2
             units(num).hitpoints=20
             units(num).speed=100.0
             units(num).attack_speed=2.0
             units(num).harvest_speed=0.700
             units(num).radius=20.0
             units(num).range=3.0
      endcase
      case 3:units(num).attack=0
             units(num).hitpoints=500+rnd(500)
             units(num).speed=0.0
             units(num).attack_speed=0
             units(num).radius=40.0
      endcase
   endselect
endfunction
 
function empty_unit_number()
   i=0
   repeat
      inc i
   until unit_list(i)=0 or i>999
endfunction i
 
function camera_control()
   camera_speed#=1500.0
   dist#=camera_speed#*time_step#
   pitch camera up 70
   if keystate(17)=1 then position camera 0,camera position x(),camera position y()+1,camera position z()
   if keystate(18)=1 then position camera 0,camera position x(),camera position y()-1,camera position z()
   if upkey() then move camera dist#
   if downkey() then move camera -dist#
   if rightkey() :turn camera right 90:move camera dist#:turn camera left 90:endif
   if leftkey() :turn camera left 90:move camera dist#:turn camera right 90:endif
   if mousex()<1 :turn camera left 90:move camera dist#:turn camera right 90:endif
   if mousex()>screen width()-2 :turn camera right 90:move camera dist#:turn camera left 90:endif
   if mousey()<1 :move camera dist#:endif
   if mousey()>screen height()-2 :move camera -dist#:endif
   pitch camera down 70
endfunction
 
function set_locked_pixel(x,y,color_value)
   start=get pixels pointer()
   repeat_number=get pixels pitch()
   bits_per_pixel=bitmap depth(num)/8
   pointer=start+y*repeat_number+x*bits_per_pixel
   *pointer=color_value
endfunction
 
function make_land()
   make object plain 1,5000,5000
   make object plain 2,5000,5000
   xrotate object 1,-90
   xrotate object 2,-90
 
   for bitnum=1 to 2
   lock pixels
   for i=0 to 255
      for j=0 to 255
         set_locked_pixel(i,j,rgb(rnd(20*(bitnum-1)),rnd(50+50*(bitnum-1))+155*(bitnum-1),rnd(20*(bitnum-1))))
      next j
   next i
   unlock pixels
      get image bitnum,0,0,255,255
      texture object bitnum,bitnum
   next bitnum
 
   scale object texture 1,5,5
   ghost object on 1
endfunction