`Coding Challenge - 3D Shooter
`Bill Robinson - San Francisco,CA.
 
`The A and D keys move your player, and the mouse button fires!
`You get 10 shots on screen at a time
`Each Robot only gets 1 shot at a time, and will only fire if his head sees you
`There are as many Robots at one time as the level#, example level#4 has 4 Robots at a time.
`Watch your health - each enemy hit cost 10 health points, health reaches 0(zero), GAME OVER.
`There are 20 levels, see how far you can get
`Robots get closer to you in each level, in level 20, they are in your face!
 
`I run sync rate 0 on my system, runs great, probably too fast for your faster systems, so you set sync rate 60, which
`is too slow, higher sync rate don't seem to work right, I still need to learn timer based movement, sorry.
`also, still some collision issues, but mostly works.
 
set display mode 1024,768,32
sync on : sync rate 0
hide mouse
backdrop on:color backdrop rgb(0,0,0)
set text opaque
 
set ambient light 20
set camera range 1,5000
randomize timer()
 
dim ballinfo#(200,10)   :`ballnum,1=active  ,2=ballspeed, ballx, bally, ballz
dim intro(10,10)        :`1=key, 2=x, 3=y, 4=z, 5=newx, 6=newy, 7=newz, 8=xinc, 9=yinc, 10=zinc
dim walldata(100,5)     :`column walls
 
dim enemy#(20,15)       :`store box info, location, rotations, motions, etc.
dim enemyinfo#(20,10)   :`enemy unit info 1=active, 2=speed, 3=xloc, 4=yloc, 5=zloc, 6=xinc, 7=yinc, 8=zinc, 9=minx, 10=maxx
dim enemyshots#(20,10)  :`enemy shot info
dim gunangle#(20,2)     :`enemy gun angle
 
#Constant WHITE=rgb(255,255,255)
#Constant YELLOW=rgb(255,255,0)
 
global testval=0
global offset=0
 
global gunangleinc#=2.0
global level
global numballs
global targetsleft
global targetx#=500.0
global targety#=300.0
global targetz#=500.0
global bazooka_angle=180
global hitnum
global gravity#
global egravity#
global gravityon
global health
 
global screenxmax=1024
global screenymax=768
global screenwidth
global screenheight
global screenxcenter
global screenycenter
global screenzcenter
global v3dymax=768
`Box
global boxxangle#
global boxyangle#
global iconptr
global boxxmin
global boxymin
global boxzmin
 
`balls
global ballxangle#
global ballyangle#
global ballx
global bally
global ballz
global maxballspeed#
global ballflag
global ballsatonce
global maxballs
global ballcount
global nextballptr
global lastballtime
global newballtime
global balltiming=100
global shadownum=500
 
`walls
global leftwall=0
global rightwall=2000
global floor=5
global ceiling=1000
global backwall=2000
 
`Camera - position camera 500,200,-800
global camx=1000
global camy=300
global camz=-800
global camxr
global camyr
global camzr
global camspeed=4
global walkflag=0       :`can player walk around flag
global mxold
 
`Enemies
global enemiesonscreen
global enemiesleft
global numshots
global enemyballspeed#=3.0
global eshotfired
 
screenwidth=screen width()
screenheight=screen height()
screenxcenter=screenwidth/2
screenycenter=screenheight/2
screenzcenter=0
 
`enemy unit info 1=active, 2=speed, 3=xloc, 4=yloc, 5=zloc, 6=xinc, 7=yinc, 8=zinc, 9=minx, 10=maxx
enemydata:
data 1,2,0,100,1800,1,0,0,100,1900
data 1,3,0,100,1700,1,0,0,100,1900
data 1,3,0,100,1600,1,0,0,100,1900
data 1,3,0,100,1500,1,0,0,100,1900
data 1,3,0,100,1400,1,0,0,100,1900
data 1,4,0,100,1300,1,0,0,100,1900
data 1,4,0,100,1200,1,0,0,100,1900
data 1,4,0,100,1100,1,0,0,100,1900
data 1,5,0,100,1000,1,0,0,100,1900
data 1,5,0,100,900,1,0,0,100,1900
data 1,2,0,100,800,1,0,0,100,1900
data 1,3,0,100,700,1,0,0,100,1900
data 1,3,0,100,600,1,0,0,100,1900
data 1,3,0,100,500,1,0,0,100,1900
data 1,3,0,100,400,1,0,0,100,1900
data 1,4,0,100,300,1,0,0,100,1900
data 1,4,0,100,200,1,0,0,100,1900
data 1,4,0,100,100,1,0,0,100,1900
data 1,5,0,100,0,1,0,0,100,1900
data 1,5,0,100,-100,1,0,0,100,1900
restore enemydata
for i=1 to 20
   for j=1 to 10
      read enemyinfo#(i,j)
   next j
   enemyinfo#(i,3)=300+rnd(1500)    :`random starting x position
next i
 
rem --- make left wall
make object box 310,3000,1004,2
yrotate object 310,90
color object 310,rgb(200,200,0)
position object 310,0,500,1000
set object emissive 310,rgb(100,100,0)
 
rem --- make right wall
make object box 311,3000,1004,2
yrotate object 311,-90
color object 311,rgb(255,255,0)
position object 311,2000,500,1000
 
rem --- make floor
make object box 303,2000,3000,2
xrotate object 303,-90
color object 303,rgb(0,140,0)
position object 303,1000,-2,1000      :`was -10 for z
 
rem --- make back wall
make object box 304,2000,1000,2
color object 304,rgb(0,0,200)
position object 304,1000,500,2000
 
rem --- make ceiling
make object box 305,2000,3000,2
xrotate object 305,90
color object 305,rgb(0,255,255)
position object 305,1000,1000,1000
set object emissive 305,rgb(0,70,70)
 
rem Create Tennis Balls
maxballs=199
for i=100 to 99+maxballs      :`balls are objects from 100 to 199
   make object sphere i,40
   set object i,1,1,0
   scale object i,40,40,40  :`scale ball smaller than bazooka tube=28
   color object i,rgb(255,255,0)
   hide object i
   set object collision off i
   ballinfo#(i,1)=0
next i
 
`Make shadow texture
create bitmap 1,64,64
set current bitmap 1
cls 0
ink rgb(10,10,10),0
for i=0 to 20
   circle 32,32,i
next i
`blur bitmap 1,6
get image 1,1,1,64,64,1
set current bitmap 0
delete bitmap 1
 
rem make SHADOW plains
for i=500 to 500+maxballs-1
   make object plain i,30,30     :`SHADOWS for ball
   set object i,1,1,0
   xrotate object i,-90
   color object i,rgb(10,10,10)
   texture object i,1
   set object collision off i
   hide object i
next i
 
rem Create Bazooka Tube
make object cylinder 300,40         :`Tennis ball CANNON
set object 300,1,1,0
scale object 300,42,250,42
color object 300,rgb(0,10,0)
xrotate object 300,90
fix object pivot 300
`texture object 300,406
 
rem Create Player Body for enemy to hit
make object box 315,150,250,100
`ghost object on 315
 
rem Create Pivot Cone for Bazooka
make object cone 301,5              :`pivot for cannon
`hide limb 301,0
glue object to limb 300,301,0
offset limb 300,0,0,25,0
glue object to limb 315,301,0
 
rem make target ball
make object sphere 302,40            :`Target ball
set object 302,1,1,0
color object 302,rgb(255,255,200)
`texture object 302,404
 
headcolor:
data 255,0,0
data 0,255,0
data 0,100,255
data 255,255,0
data 0,255,255
data 255,0,255
data 255,125,0
data 0,255,125
data 255,0,125
data 255,100,255
data 255,0,0
data 0,255,0
data 0,100,255
data 255,255,0
data 0,255,255
data 255,0,255
data 255,125,0
data 0,255,125
data 255,0,125
data 255,100,255
 
restore headcolor
for i=0 to 19
   read r,g,b
   rem ----- Create Enemy Body -----
   make object box 400+i,100,200,20        :`Enemy Body
   color object 400+i,rgb(255,150,0)
 
   make object box 420+i,50,50,50         :`Enemy Head
   color object 420+i,rgb(r,g,b)
   xrotate object 420+i,45
   fix object pivot 420+i
 
   rem Create Enemy Bazooka Tube
   make object cylinder 450+i,40          :`Enemy Tennis ball CANNON
   set object 450+i,1,1,0
   scale object 450+i,60,250,60
   color object 450+i,rgb(250,250,0)
   xrotate object 450+i,90
   fix object pivot 450+i
 
   hide object 400+i
   hide object 420+i
   hide object 450+i
next i
 
rem Create Enemy Shots
numenemyshots=20
for i=800 to 800+numenemyshots      :`balls are objects from 100 to 199
   make object sphere i,50
   set object i,1,1,0
   scale object i,40,40,40  :`scale ball smaller than bazooka tube=28
   color object i,rgb(255,0,0)
   hide object i
   set object collision on i
   ballinfo#(i,1)=0
next i
 
pillardata:
rem x,y,size,height
data 300,300,200,400
data 900,300,200,600
data 1500,300,200,400
restore pillardata
objnum=0
for i=1 to 3
   read x,z,s,h
   for j=1 to 4
      inc objnum
      make object plain objnum,s,h
      color object objnum,rgb(100,100,100)
      if j=1
         yrotate object objnum,90
         position object objnum,x,h/2,z         :`column left wall
         walldata(objnum,1)=1                   :`column left or right wall
 
      endif
      if j=2
         position object objnum,x+s/2,h/2,z+s/2
         walldata(objnum,1)=3                   :`column front or back wall
 
      endif
      if j=3
         yrotate object objnum,-90
         position object objnum,x+s,h/2,z
         walldata(objnum,1)=1
      endif
      if j=4
         position object objnum,x+s/2,h/2,z-s/2
         walldata(objnum,1)=3
      endif
      set object collision on objnum
      set object collision to boxes objnum
`      ghost object on objnum
 
   next j
   make static collision box x,0,z,x+s,h,z+s
next i
 
rem use my own collision for room walls and floor
set object collision off 300     :`Bazooka
set object collision off 301     :`Pivot cone for cannon
set object collision off 302     :`target ball for aiming cannon
 
rem position objects for room
hide object 301                              :`hide cannon pivot
position object 302,-1000,-1000,-1000        :`TARGET ball - move off screen for now
position object 301,camx,camy,camz+100       :`shooters view
 
`position enemy
position object 400,200,100,800
 
nextballptr=100         :`pointer into array - points to next ball to fire
ballcount=0             :`how many balls in use, on the screen
ballsatonce=10
numballs=5000
maxballspeed#=4
balltiming=120           :`was 100
gravityon=1
 
gravity# = 0.01
egravity#=0.001
position camera camx,camy,camz-offset
targetx#=screenwidth/2
point camera sw/2,200,2000
level=1
enemiesleft=level*3
health=100
 
time=timer()
ink rgb(255,255,255),0
`------------------------------------------------------------------------------------------------------
do
   position camera camx,camy,camz-offset
   position object 301,camx,camy-40,camz-30
   mx#=2000.0/screenwidth*mousex()                                     :`get mouse x location
   my#=1000.0/screenheight*mousey()                                    :`get mouse y location
 
   newmx#=mousemovex()
   inc targetx#,newmx#
   targety#=screenheight-my#
 
   if targetx#<0 then targetx#=0
   if targetx#>2000.0 then targetx#=2000.0         :`limit target position to 1000, instead of 1024 which is past wall
 
   position object 302,targetx#,targety#,targetz#  :`target ball moves as the target object
   point object 301,targetx#,targety#,targetz#     :`pivot cone points to target
   point camera 1000,200,2000
 
   keypress=scancode()                             :`scan for keys pressed, subroutine to hadle keys
   if keypress>0 then _key_action(keypress)
 
   mouse=mouseclick()                              :`get mouse click for firing tennis ball
   if mouse=1 then gosub _fire_tennis_ball         :`FIRE!
   if ballcount>0 then gosub _moveballs            :`move any visible balls on screen
 
   if enemiesleft<=0 and enemiesonscreen<=0
      sync
      if level=20 then gosub _game_won
 
      gosub completed_level
      inc level
      enemiesleft=level*3
      startflag=0
   endif
 
   if enemiesleft>0 and startflag=0
      gosub _start_level
      startflag=1
      health=100
      enemiesonscreen=0
   endif
 
   if enemiesleft>enemiesonscreen
      gosub _start_enemy
   endif
 
   if health<=0
      gosub _game_over
   endif
 
   gosub _move_enemy
   gosub _enemy_shots
   gosub _move_eshots
   gosub _show_score
   sync
loop
`------------------------------------------------------------------------------------------------------
 
 
_start_level:
   sync
   level$="Level#"+str$(level)+" - "+str$(enemiesleft)+" Enemy Robots to kill on this level - Good Luck!"
while (keypress=keystate(57))
   center text screenwidth/2,screenheight/2-100,level$
   center text screenwidth/2,screenheight/2-70,"Press space bar to continue"
   gosub _moveballs
   gosub _move_eshots
   gosub _show_score
   sync
endwhile
return
 
 
completed_level:
done$="Level#"+str$(level)+"    COMPLETED!!!     GREAT JOB!"
while (keypress=keystate(57))
   center text screenwidth/2,screenheight/2,done$
   center text screenwidth/2,screenheight/2+30,"Press space bar to continue"
   gosub _moveballs
   gosub _move_eshots
   gosub _show_score
   sync
endwhile
return
 
_game_won:
   dim textloc(20,3)
   set text font "Arial"
   set text size 18
   set text to bold
   gameover$="YOU DID GREAT!!! - YOU WON!!! - Thanks for Playing!!!"
   ptr=1
while (keypress=keystate(57))
   textloc(ptr,1)=rnd(screenwidth)
   textloc(ptr,2)=rnd(screenheight)
   textloc(ptr,3)=rgb(rnd(255),rnd(255),rnd(255))
   for i=1 to 20
      ink textloc(i,3),0
      center text textloc(i,1),textloc(i,2),gameover$
   next i
   ink rgb(255,255,255),0
   center text screenwidth/2,screenheight/2+30,"--- Press space bar to exit, bye,bye ---"
   gosub _moveballs
   gosub _move_eshots
   gosub _show_score
   wait 100
   sync
   inc ptr
   if ptr>20 then ptr=1
endwhile
   end
return
 
_game_over:
   gameover$="YOU DIED A PAINFULL DEATH! - You didn't move enough - GAME OVER"
   center text screenwidth/2,screenheight/2,gameover$
   center text screenwidth/2,screenheight/2+30,"Sorry, Thanks for Playing! - Press space bar to exit - bye"
   gosub _moveballs
   gosub _move_eshots
   gosub _show_score
   sync
   wait key
   end
return
 
rem --- show score on screen
_show_score:
set cursor 1,1:print screen fps()
`print "enemiesleft=";enemiesleft
`print "enemiesonscreen=";enemiesonscreen
`print "enemy shots=";numshots
 
center text screenxcenter,2,"Level:"+str$(level)+"   Robots Left: "+str$(enemiesleft)+"   Score: "+str$(score)+"   Health: "+str$(health)
return
 
rem --- fires tennis balls
_fire_tennis_ball:
if ballcount=ballsatonce then return
newballtime=timer()
if newballtime-lastballtime<balltiming then return else lastballtime=newballtime    :`control firing rate of tennis balls
if numballs=0                          :`out of tennis balls to shoot
`   play sound 3                        :`play empty gun sound
   retryflag=1                         :`set retry flag, do you want to try this level again?
   return                              :`sound 3 = your gun is empty
endif
 
ballx#=object position x(301)          :`get bazooka pivot location to start ball at
bally#=object position y(301)
ballz#=object position z(301)
position object nextballptr,ballx#,bally#,ballz#
point object nextballptr,targetx#,targety#,targetz#
move object nextballptr,100
`position object nextballptr,ballx#,bally#,ballz#
ballx#=object position x(nextballptr)          :`get bazooka pivot location to start ball at
bally#=object position y(nextballptr)
ballz#=object position z(nextballptr)
 
ballinfo#(nextballptr,3)=ballx#        :`store ball location
ballinfo#(nextballptr,4)=bally#
ballinfo#(nextballptr,5)=ballz#
`-----------------------
ballxi#=(targetx#-ballx#)/300.0*maxballspeed#  :`calculate some value to move ball each time toward target
ballyi#=(targety#-bally#)/300.0*maxballspeed#  :`mostly an arbitrary calculation, to get lots of slices
ballzi#=(targetz#-ballz#)/300.0*maxballspeed#  :`build screen routine then says how many slices each move
 
ballinfo#(nextballptr,6)=ballxi#             :`store ball increment values in array
ballinfo#(nextballptr,7)=ballyi#
ballinfo#(nextballptr,8)=ballzi#
`------------------------
position object nextballptr,ballx#,bally#,ballz#   :`start ball in bazooka
point object nextballptr,targetx#,targety#,-50     :`angle ball toward target on screen
 
shadownum=400+nextballptr                          :`calculate next shadow plain to use
position object shadownum,ballx#,2,ballz#          :`attemp at shadow for ball
show object shadownum
 
`play sound 1
show object nextballptr
set object collision on nextballptr                :`use DBPro collision for balls and boxes only
set object collision to spheres nextballptr
 
ballinfo#(nextballptr,1)=1                         :`show ball is active
ballinfo#(nextballptr,2)=maxballspeed#             :`store max ball speed
inc ballcount                                      :`one more ball on screen
dec numballs                                       :`one less ball you can fire
inc nextballptr                                    :`points to next ball to fire
if nextballptr>99+maxballs                         :`if next ball doesn't exist
   nextballptr=100                                 :`reset nextballptr to first ball object
endif
return
 
rem --- moves balls that have been fired
_moveballs:
for i=100 to 100+maxballs-1
   if ballinfo#(i,1)=1        :`only worry about active balls on screen
 
      ballxi#=ballinfo#(i,6)           :`get movement values for next ball position stored in array
      ballyi#=ballinfo#(i,7)
      ballzi#=ballinfo#(i,8)
 
      ballx#=ballinfo#(i,3)+ballxi#    :`calculate balls NEW POSITION
      bally#=ballinfo#(i,4)+ballyi#
      ballz#=ballinfo#(i,5)+ballzi#
 
      if ballx#<0 or ballx#>rightwall   :`ball hit left or RIGHT WALL
         ballxi#=ballxi#*-1
         ballinfo#(i,6)=ballxi#
         ballx#=ballx#+ballxi#
      endif
      if bally#<floor                   :`ball hit FLOOR routine
         ballyi#=ballyi#*-1
         ballinfo#(i,7)=ballyi#
         bally#=bally#+ballyi#
      endif
      if ballz#>backwall                :`ball hit BACK WALL routine
         ballzi#=ballzi#*-1
         ballinfo#(i,8)=ballzi#
         ballz#=ballz#+ballzi#
      endif
 
      if bally#>ceiling                   :`ball hit CEILING routine
         ballyi#=ballyi#*-1
         ballinfo#(i,7)=ballyi#
         bally#=bally#+ballyi#
      endif
 
      if gravityon=1                   :`gravity on, drop ball y increment down more to simulate gravity
         ballyi#=ballyi#-gravity#
         ballinfo#(i,7)=ballyi#
      endif
 
      ballinfo#(i,3)=ballx#            :`store balls new location for next update
      ballinfo#(i,4)=bally#
      ballinfo#(i,5)=ballz#
      position object i, ballx#, bally#, ballz#    :`position ball at new location on screen
      shadownum=400+i                              :`which shadow to use
      position object shadownum,ballx#,2,ballz#    :`position shadow for ball, same x,z, y=always near floor
`-------------------------
rem Check for Collision Hits
 
      hitnum=object hit(i,0)
 
      if ballz#<-900 or bally#>1200    :`balls bouncing behind player or too high are removed
         ballinfo#(i,1)=0
         dec ballcount
         hide object i
         set object collision off i
         hide object shadownum
      endif
 
      rem --- ball hitting columns in room ---
      if hitnum>=1 and hitnum<=12
         if walldata(hitnum,1)=1
            ballxi#=ballxi#*-1
            ballinfo#(i,6)=ballxi#
            ballx#=ballx#+ballxi#
            ballinfo#(i,3)=ballx#
 
            position object i, ballx#, bally#, ballz#    :`position ball at new location on screen
            shadownum=400+i                              :`which shadow to use
            position object shadownum,ballx#,2,ballz#    :`position shadow for ball, same x,z, y=always near floor
`            hitnum=0
         endif
         if walldata(hitnum,1)=3
            ballzi#=ballzi#*-1
            ballinfo#(i,8)=ballzi#
            ballz#=ballz#+ballzi#
            ballinfo#(i,5)=ballz#
 
            position object i, ballx#, bally#, ballz#    :`position ball at new location on screen
            shadownum=400+i                              :`which shadow to use
            position object shadownum,ballx#,2,ballz#    :`position shadow for ball, same x,z, y=always near floor
`            hitnum=0
         endif
      endif
 
      if hitnum>=400 and hitnum<=439
         if hitnum>=420
            dec hitnum,20
         endif
         position object hitnum,-2000,-2000,-2000
         position object hitnum+20,-2000,-2000,-2000
         position object hitnum+50,-2000,-2000,-2000
         hide object hitnum
         hide object hitnum+20
         hide object hitnum+50
         enemy#(hitnum-399,1)=100+100*rnd(10)
         dec enemiesonscreen
         dec enemiesleft
         inc score,100
 
         set object collision off i                      :`turn collision off for ball
         hide object i                                   :`hide ball
         position object i,-2000,-2000,-2000
         shadownum=400+i
         hide object shadownum                           :`which shadow to hide
         position object shadownum,-2000,-2000,-2000     :`position shadow off screen
      endif
`-------------------------
   endif
next i
return
 
 
function _key_action(keypress)
select keypress
`for next section of game where player can move around - not completed yet - used for debugging so far
   case 30                    :`A key - move camera/player left
      if camx>50
         dec camx,camspeed
         dec targetx#,camspeed
 
         position camera camx,camy,camz-offset
         position object 302,targetx#,targety#,targetz#  :`target ball moves as the target object
         point object 301,targetx#,targety#,targetz#     :`pivot cone points to target
      endif
   endcase
 
   case 32                    :`D key - move camera/player right
      if camx<1950
         inc camx,camspeed
         inc targetx#,camspeed
 
         position camera camx,camy,camz-offset
         position object 302,targetx#,targety#,targetz#
         point object 301,targetx#,targety#,targetz#
      endif
   endcase
 
   case 20                                   :`T key - Turbo mode for balls
      if level>=8                            :`I left this in, for players looking at the source code to have some fun with
         balltiming=balltiming-10            :`you may need to increase the maxballs variable for a level, this turbo
         wait 100                            :`mode really uses up balls fast
         if balltiming<40 then balltiming=100
      endif
   endcase
 
   case default
         :`do nothing yet
   endcase
endselect
endfunction
 
 
rem ----- start a new enemy on the screen -----
_start_enemy:
`enemy unit info 1=active, 2=speed, 3=xloc, 4=yloc, 5=zloc, 6=xinc, 7=yinc, 8=zinc, 9=minx, 10=maxx
`data 1,3,100,100,1500,1,0,0,100,1900
startone=0
for i=1 to level
   if startone=0
      if enemy#(i,1)=0
         for j=1 to 10
            enemy#(i,j)=enemyinfo#(i,j)
         next j
         edir=rnd(10)
         if edir>4
            enemy#(i,6)=enemyinfo#(i,2)
         else
            enemy#(i,6)=-enemyinfo#(i,2)
         endif
         inc enemiesonscreen
         show object 399+i
         show object 419+i
         show object 449+i
         enemy#(i,1)=1
         startone=1
      else
         if enemy#(i,1)>1 then dec enemy#(i,1),2
      endif
   endif
next i
return
 
 
rem --- moves any active enemy on the screen
`enemy unit info 1=active, 2=speed, 3=xloc, 4=yloc, 5=zloc, 6=xinc, 7=yinc, 8=zinc, 9=minx, 10=maxx
_move_enemy:
for i=1 to 20
   eobj=399+i
   if enemy#(i,1)=1                                  :`is enemy active
      newx=enemy#(i,3)+enemy#(i,6)
      if newx<enemy#(i,9) or newx>enemy#(i,10)
         enemy#(i,6)=enemy#(i,6)*-1
         newx=newx+enemy#(i,6)
      endif
      enemy#(i,3)=newx
      position object eobj,enemy#(i,3),enemy#(i,4),enemy#(i,5)
      position object eobj+20,enemy#(i,3),enemy#(i,4)+125,enemy#(i,5)
      position object eobj+50,enemy#(i,3)-50,enemy#(i,4)+100,enemy#(i,5)-25
 
      vis=static line of sight(camx,camy,camz,enemy#(i,3),enemy#(i,4),enemy#(i,5),1,1)
      if vis=0       :`can enemy head see me, yes then fire ready to fire
         if gunangle#(i,1)>0
            dec gunangle#(i,1),gunangleinc#
            xrotate object eobj+50,gunangle#(i,1)
            gunangle#(i,2)=0
         else
            point object eobj+50,camx,camy-500,camz
            gunangle#(i,2)=1
         endif
      else
         if gunangle#(i,1)<120
            inc gunangle#(i,1),gunangleinc#
            xrotate object eobj+50,gunangle#(i,1)
            gunangle#(i,2)=0
         endif
      endif
 
      point object eobj+20,camx,camy-500,camz
   endif
next i
return
 
 
rem --- controls shots already fired or starts a new enemy shot if needed, by calling 2 routines
_enemy_shots:
if enemiesonscreen>0
   for i=1 to 20
      numenemy=399+i
      if enemyshots#(i,1)=0            :`shot is active already
         if enemy#(i,1)=1              :`is enemy active
            if gunangle#(i,2)=1        :`enemy is pointing at you
               _fire_enemyshot(i)
               inc numshots
            endif
         endif
      endif
   next i
endif
return
 
 
_move_eshots:
if numshots>0
   for i=1 to 20
      if enemyshots#(i,1)=1 then _move_enemyshots(i)
   next i
endif
return
 
rem --- moves enemy shots ---
function _move_enemyshots(numenemy)
 
   if gravityon=1                   :`gravity on, drop ball y increment down more to simulate gravity
      ballyi#=enemyshots#(numenemy,7)-egravity#
      enemyshots#(numenemy,7)=ballyi#
   endif
 
   inc enemyshots#(numenemy,3),enemyshots#(numenemy,6)
   inc enemyshots#(numenemy,4),enemyshots#(numenemy,7)
   inc enemyshots#(numenemy,5),enemyshots#(numenemy,8)
 
   position object 800+numenemy,enemyshots#(numenemy,3),enemyshots#(numenemy,4),enemyshots#(numenemy,5)
   if enemyshots#(numenemy,5)<-800
      enemyshots#(numenemy,1)=0
      hide object 800+numenemy
      dec numshots
   endif
 
   rem --- enemy collision section ---
   hitnum=object hit(800+numenemy,0)
 
   ballx#=enemyshots#(numenemy,3)
   bally#=enemyshots#(numenemy,4)
   ballz#=enemyshots#(numenemy,5)
 
   ballxi#=enemyshots#(numenemy,6)
   ballyi#=enemyshots#(numenemy,7)
   ballzi#=enemyshots#(numenemy,8)
 
      if ballx#<0 or ballx#>rightwall   :`ball hit left or RIGHT WALL
         ballxi#=ballxi#*-1
         enemyshots#(numenemy,6)=ballxi#
         ballx#=ballx#+ballxi#
      endif
      if bally#<floor                   :`ball hit FLOOR routine
         ballyi#=ballyi#*-1
         enemyshots#(numenemy,7)=ballyi#
         bally#=bally#+ballyi#
      endif
      if ballz#>backwall                :`ball hit BACK WALL routine
         ballzi#=ballzi#*-1
         enemyshots#(numenemy,8)=ballzi#
         ballz#=ballz#+ballzi#
      endif
 
      rem --- ball hitting columns in room ---\
      if hitnum>=1 and hitnum<=12      :`and enemiesleft>0 and enemiesonscreen>0
         if walldata(hitnum,1)=1
            ballxi#=ballxi#*-1
            enemyshots#(numenemy,6)=ballxi#
            ballx#=ballx#+ballxi#
            enemyshots#(numenemy,3)=ballx#
 
            position object 800+numenemy, ballx#, bally#, ballz#    :`position ball at new location on screen
            hitnum=0
         endif
         if walldata(hitnum,1)=3
            ballzi#=ballzi#*-1
            enemyshots#(numenemy,8)=ballzi#
            ballz#=ballz#+ballzi#
            enemyshots#(numenemy,5)=ballz#
 
            position object 800+numenemy, ballx#, bally#, ballz#    :`position ball at new location on screen
            hitnum=0
         endif
      endif
 
      if hitnum=315
         dec health,10
      endif
endfunction
 
 
`enemy unit info 1=active, 2=speed, 3=xloc, 4=yloc, 5=zloc, 6=xinc, 7=yinc, 8=zinc, 9=minx, 10=maxx
function _fire_enemyshot(numenemy)
   enemyshots#(numenemy,1)=1
   enemyshots#(numenemy,2)=2
   enemyshots#(numenemy,3)=object position x(449+numenemy)     :`enemyinfo#(numenemy,3)
   enemyshots#(numenemy,4)=object position y(449+numenemy)     :`enemyinfo#(numenemy,4)
   enemyshots#(numenemy,5)=object position z(449+numenemy)-50     :`enemyinfo#(numenemy,5)-100
   enemyshots#(numenemy,6)=(camx-enemyshots#(numenemy,3))/1200.0*enemyballspeed#
   enemyshots#(numenemy,7)=(camy+50-enemyshots#(numenemy,4))/1200.0*enemyballspeed#
   enemyshots#(numenemy,8)=(camz-enemyshots#(numenemy,5))/1200.0*enemyballspeed#
   position object 800+numenemy,enemyshots#(numenemy,3),enemyshots#(numenemy,4),enemyshots#(numenemy,5)
   show object 800+numenemy
endfunction