`Coding Challenge - Pinball Game
`Bill Robinson
`Started 7-27-06 --- Deadline 8-8-06
`All Rights Reserved for use as a published game.
`
`Launch ball with RETURN key, or left mouse button.
`The mouse y-direction controls the power of the ball launch
`The Up & Down arrow keys also control the ball launch power
`Left Flipper - use either the Z key, Left Shift, or Left CTRL
`Right Flipper - use either the / key, Right Shift, or Right CTRL
`Complete a work to blast a ball into the multi-ball hopper
`
`set display mode 1024,768,32
set display mode 1280,1024,32
sync on : sync rate 0
 
hide mouse
autocam off
set ambient light 15
color backdrop rgb(0,0,30)
randomize timer()
set camera range 1,20000
 
` Create the ODE World
ode start
ode set world gravity 0,-3.5,-3.0       :`was 0,-1.5,-3.0
ode set world step 0.08              :`was 0.3
ode set world erp (0.4)*2.5         :`error correction each step
ode set world cfm (10^-5)*2.5       :`Constriant Force Mixing
`ode set dynamic minimum 2.0
 
#constant MAXNUMBALLS 20
dim pocketinfo(10,10)
dim doorstatus(10)
dim ballcolor(10,3)
 
dim collisions(1000)
dim lflip(360,3)
dim rflip(360,3)
dim ballsinplay(MAXNUMBALLS)
dim targets(300,10)
dim targetgroups(20,10)
dim gates(10,10)
 
 
#Constant WHITE=rgb(255,255,255)
#Constant YELLOW=rgb(255,255,0)
#Constant RED1=rgb(255,0,0)
#Constant CYAN=rgb(0,100,100)
#Constant MAGENTA=rgb(100,0,100)
#Constant GREEN1=rgb(0,255,0)
 
global numballs
global score
 
global screenxcenter
global screenycenter
 
`balls
global ballx#
global bally#
global ballz#
global maxballspeed#
global ballsatonce
global maxballs=MAXNUMBALLS
global ballcount
global nextballptr
global lastballtime
global newballtime
global balltiming=300
global ballsize=18
global ballsleft
global mx
global my
global ballinplay=0
global tiltflag=0
global tiltcount=0
global balltime=0
global safe_flag=0
global fire_flag=1
global ballsinhopper=0
global multi_ballflag=0
global hopperdoordelay=0
global ballhit
 
`walls
global leftwall=0
global rightwall=360
global bottomwall=0
global topwall=600
global playfield=0
global playfieldglass=40
global ballchannel=328        :`rightwall-40
global shootingwall_upper=40
global wallthickness=5
global wallheight=40
global railwidth=5
global railheight=25
global channelwidth=25
global gatesize=40
global gatewidth=5
 
`pockets
global pocketsize
global doorsize
global pocketsopen=5
global bonusopenflag=0
 
`bumpers
global slotxstart=100
global slotspacing=30
global numslotbumpers=6
global slotbumperzpos=450
global kick_flag=0
global kicktime=0
 
`flippers
global leftflipper
global leftflipperkey=
global leftflipperangle
global leftflippergoal
 
global rightflipper
global rightflipperkey
global rightflipperangle
 
global flippermaxangle=130
global flipperminangle=50
global flipspeed=10
global flipperlength=40
 
global lflipx
global lflipy
global lflipz
global rflipx
global rflipy
global rflipz
 
`decals & targets
global decal_idstart
global decal_objid
global decal_id
global target_id
global target_idfirst
global target_idlast
global numtargets
global numtargetgroups
global targetgroup
 
 
`particles
global blastoff_flag=1
global rocketflag
global rocket_xpos#
global rocket_ypos#
global rocket_zpos#
 
`Camera
global camx=180
global camy=100
global camz=-100
 
`ODE - globals
global odeballptr
 
 
 
remstart
create bitmap 1,9,9                    :`make image for particles
ink rgb(255,255,255),0
dot 4,4
get image 1,1,1,9,9
set current bitmap 0
remend
 
_load_gatedata()
_ball_textures()              :`build textures for balls
_playfield_graphics()         :`build playfield graphics
gosub _intro
 
screenxcenter=screen width()/2
 
rem --- make LEFT wall
_make_rail(310,wallthickness*2,wallheight,topwall,YELLOW,leftwall,wallheight/2,topwall/2,0,50,1)
 
rem --- make RIGHT wall
_make_rail(311,wallthickness*2,wallheight,topwall,YELLOW,rightwall,wallheight/2,topwall/2,0,50,1)
 
rem --- make TOP wall
_make_rail(304,rightwall,wallheight,wallthickness*3,YELLOW,rightwall/2,wallheight/2,topwall,0,50,1)
 
rem --- make BALL CHANNEL wall
_make_rail(312,wallthickness/2,railheight,topwall-250,YELLOW,ballchannel,railheight/2,(topwall-230)/2,0,50,1)
 
rem --- make TOP LEFT Corner wall
_make_rail(315,50,wallheight,wallthickness*4,YELLOW,leftwall+12,wallheight/2,topwall-17,-60,10,1)
rem --- make TOP RIGHT Corner wall
_make_rail(316,50,wallheight,wallthickness*4,YELLOW,rightwall-12,wallheight/2,topwall-17,60,10,1)
 
 
rem --- make slanted rails for bottom exit
rail_length=125
_make_rail(303,rail_length,railheight,wallthickness,rgb(0,0,255),rail_length/2,railheight/2,20,20,10,1)
_make_rail(306,rail_length,railheight,wallthickness,rgb(0,0,255),ballchannel-rail_length/2,railheight/2,20,-20,10,1)
 
rem --- playfield board
make object box 305,rightwall,4,topwall
color object 305,rgb(100,100,0)
position object 305,rightwall/2+leftwall/2,-2,topwall/2
ode create static box 305
ode set contact fdir1 305,0
texture object 305,10
set object emissive 305,rgb(100,100,0)
 
remstart
rem --- make playfieldglass
make object box 307,rightwall,3,topwall
color object 307,rgb(0,0,0)
position object 307,rightwall/2+leftwall/2,playfieldglass,topwall/2
ode create static box 307
ghost object on 307
hide object 307
remend
 
rem --- make SLOT Bumpers
`global slotxstart=100
`global slotspacing=30
 
 
`_make_rail(objid, xsize, ysize, zsize, color, posx, posy, posz, yangle, bounce, ODE item)
objid=350
for i=0 to numslotbumpers-1
   xloc=slotxstart+i*slotspacing
   _make_rail(objid,railwidth,railheight,50,YELLOW,xloc,railheight/2,slotbumperzpos,0,10,1)
   inc objid
next i
 
`-------------------------------------------------------------------------------------------------------
rem _make_rail(objid,xsize,ysize,zsize,color,posx,posy,posz,yangle,bounce)
 
rem --- make BALL KICKERS
_make_rail(360,railwidth*2,railheight,70,RED1,80,railheight/2,130,-45,100,1)
_make_rail(361,railwidth*2,railheight,70,RED1,240,railheight/2,130,45,100,1)
 
 
 
rem --- make FLIPPERS
flipperlength=48
lflipx=112
lflipy=railheight/2
lflipz=52
rflipx=216
rflipy=railheight/2
rflipz=52
rem --- LEFT FLIPPER
_make_rail(370,railwidth*2,railheight,flipperlength,WHITE,lflipx,lflipy,lflipz,flippermaxangle,10,1)
rem --- RIGHT FLIPPER
_make_rail(371,railwidth*2,railheight,flipperlength,WHITE,rflipx,rflipy,rflipz,flipperminangle,10,1)
leftflipperangle=flippermaxangle
rightflipperangle=flipperminangle
 
rem --- ODE has rotation problems if you chang the pivot point, so move position of flipper with pivot still in the middle
rem --- to simulate the flipper pivoting on the end, build curved position array for flippers
_lflipposition(lflipx,lflipy,lflipz,flipperlength/2-2)      :`radius=30, half of flipper size
_rflipposition(rflipx,rflipy,rflipz,flipperlength/2-2)      :`radius=30, half of flipper size
position object 370,lflip(leftflipperangle,1),lflip(leftflipperangle,2),lflip(leftflipperangle,3)
position object 371,rflip(rightflipperangle,1),rflip(rightflipperangle,2),rflip(rightflipperangle,3)
 
rem - Left Flipper guide rails
_make_rail(380,railwidth/4,railheight,40,RED1,leftwall+channelwidth+1,railheight/2,125,0,1,1)
_make_rail(381,railwidth/4,railheight,90,RED1,70,railheight/2,80,-60,1,1)
 
rem --- Right Flipper guide rails
_make_rail(390,railwidth/4,railheight,40,RED1,ballchannel-channelwidth+2,railheight/2,125,0,1,1)
_make_rail(391,railwidth/4,railheight,96,RED1,ballchannel-68,railheight/2,80,60,1,1)
 
rem --- Left Side Bump on side rail
_make_rail(400,12,railheight,13,RED1,leftwall+wallthickness/2+7,railheight/2,210,0,1,1)
rem --- Right Side Bump on side rail
_make_rail(410,12,railheight,13,RED1,ballchannel-railwidth/2-5,railheight/2,210,0,1,1)
 
rem --- Gates
_open_gate(1)
_open_gate(2)
_open_gate(3)
 
rem --- Scoreboard
_make_rail(420,wallthickness*2,200,railwidth,YELLOW,leftwall,100,topwall,0,1,0)
_make_rail(421,wallthickness*2,200,railwidth,YELLOW,rightwall,100,topwall,0,1,0)
_make_rail(422,rightwall,wallthickness,wallthickness,YELLOW,rightwall/2,200,topwall,0,1,0)
 
rem --- multi-ball chute
_make_rail(423,4,160,railheight*2,MAGENTA,180-railheight,100,topwall-railheight/2,0,1,1)
_make_rail(424,railheight*2,160,4,MAGENTA,180,100,topwall-railheight*2,0,1,1)
_make_rail(425,4,160,railheight*2,MAGENTA,180+railheight,100,topwall-railheight/2,0,1,1)
`_make_rail(426,railheight*2,4,railheight*2,MAGENTA,180,railheight,topwall-railheight/2,0,1,1)
_make_hopperdoor()
fade object 423,50
fade object 424,50
fade object 425,50
ghost object on 423
ghost object on 424
ghost object on 425
 
rem --- make objects and decals ---------------------------------------------------------------------------------------
decal_idstart=1000
decal_id=1000
decal_objid=1000
 
target_idfirst=900
target_id=900
 
rem --- read target group info into array
targetgroupinfo:
data 3
data 1,1,6
data 2,7,10
data 3,11,15
 
restore targetgroupinfo
read numtargetgroups
for i=1 to numtargetgroups
   read targetgroups(i,1)
   read targetgroups(i,2)
   read targetgroups(i,3)
next i
 
rem --- "ROCKET" targets
xsize=4
for i=0 to 5
_make_target(target_id,xsize,railheight,railheight,CYAN,leftwall+8,railheight/2,420-i*(railheight+10))
set object emissive target_id,CYAN
set object collision on target_id
set object collision to boxes target_id
inc target_id
next i
 
rem --- "SHIP" targets
for i=0 to 3
_make_target(target_id,xsize,railheight,railheight,CYAN,ballchannel-4,railheight/2,350-i*(railheight+10))
set object emissive target_id,CYAN
set object collision on target_id
set object collision to boxes target_id
inc target_id
next i
 
`remstart
rem --- "BLAST" targets
for i=0 to 4
_make_target(target_id,slotspacing-16,railheight,4,CYAN,slotxstart+slotspacing/2+i*slotspacing,railheight/2,slotbumperzpos)
set object emissive target_id,CYAN
set object collision on target_id
set object collision to boxes target_id
inc target_id
next i
`remend
 
target_idlast=target_id-1
numtargets=target_id-1
 
rem --- make ROCKET DECALS
savedecal_id=decal_id
decal_id=_make_decals(decal_id,"ROCKET",rgb(0,100,100),rgb(0,0,0),16)
temp=_make_decals(savedecal_id+100,"ROCKET",rgb(0,255,255),rgb(0,0,0),16)
for i=0 to 5
   make object plain decal_objid,railheight,railheight
   texture object decal_objid,decal_objid
   xrotate object decal_objid,-90
   position object decal_objid,leftwall+railheight,1,420-i*(railheight+10)
   set object emissive decal_objid,CYAN
   inc decal_objid
next i
 
rem --- make SHIP DECALS
savedecal_id=decal_id
decal_id=_make_decals(decal_id,"SHIP",rgb(50,100,100),rgb(0,0,0),16)
temp=_make_decals(savedecal_id+100,"SHIP",rgb(50,255,255),rgb(0,0,0),16)
for i=0 to 3
   make object plain decal_objid,railheight,railheight
   texture object decal_objid,decal_objid
   xrotate object decal_objid,-90
   position object decal_objid,ballchannel-railheight+4,1,350-i*(railheight+10)
   set object emissive decal_objid,CYAN
   inc decal_objid
next i
 
rem --- make BLAST DECALS
savedecal_id=decal_id
decal_id=_make_decals(decal_id,"BLAST",rgb(0,100,100),rgb(0,0,0),16)
temp=_make_decals(savedecal_id+100,"BLAST",rgb(0,255,255),rgb(0,0,0),16)
for i=0 to 4
   make object plain decal_objid,railheight,railheight
   texture object decal_objid,decal_objid
   xrotate object decal_objid,-90
   position object decal_objid,slotxstart+slotspacing/2+i*slotspacing,1,slotbumperzpos-60
   set object emissive decal_objid,CYAN
   inc decal_objid
next i
 
 
 
 
 
rem --- Create ODE pinballs --------------------------------------------------------------------
for i=1 to maxballs
   make object sphere i,ballsize,16,16          :`was i,30
   set object i,1,1,0
   set object collision off i
   position object i, 5000,5000,0      :`move object WAY off screen
   texnum=rnd(5)+11
   texture object i,texnum
   dec texnum,10
`   color object i,rgb(ballcolor(texnum,1),ballcolor(texnum,2),ballcolor(texnum,3))
   set object emissive i,rgb(ballcolor(texnum,1),ballcolor(texnum,2),ballcolor(texnum,3))
   hide object i
set object collision on i
set object collision to spheres i
next i
 
 
`remstart
rem --- make power bar
make object box 201,25,2,2
color object 201,rgb(255,0,255)
`position object 201,leftwall+150,1,160   :`position power bar
`remend
 
remstart
rem --- make firing rate bar
make object box 202,100,100,2
color object 202,rgb(255,255,0)
position object 202,rightwall-1100+100,1,160         :`was ceiling-120,160
remend
 
`--------------------------------------------------------
 
nextballptr=1           :`pointer into array - points to next ball to fire
odeballptr=1
ballcount=0             :`how many balls in use, on the screen
ballsatonce=1           :`how many balls on screen at the same time
numballs=10            :`number of balls to shoot
maxballspeed#=8         :`how fast should the balls shoot
balltiming=200          :`pause between each ball being fired
level=1                 :`start at this level
 
position camera 180,400,-100
point camera 180,0,300
ink rgb(255,255,255),0
 
set text font "Arial"
set text size 30
 
 
 
rem ---------------------------------------------------------------------------------------------------------------------
rem ----- main loop -----------------------------------------------------------------------------------------------------
rem --- ODE has changed pivot rotation problems, so move position of flipper with pivot still in the middle
rem --- to simulate the flipper pivoting on the end, build curved position array for flippers
 
ballcheck=1
blastoff_flag=0
safe_flag=1
_close_gate(2)
_close_gate(3)
balltime=timer()
do
   if fire_flag=1 and ballcount=0
      mess$="Ball #"+str$(ballinplay+1)+" - Ready to Fire!"
      size=_decal_signs(1300,mess$,rgb(255,0,255),0,16)
      if object exist(1300) then delete object 1300
      make object plain 1300,size,70
      xrotate object 1300,-90
      position object 1300,180,20,230
      texture object 1300,1300
      set text size 30
      fire_flag=0
   endif
 
   keypress=scancode()                             :`scan for keys pressed, subroutine to hadle keys
   if keypress>0
      _key_action(keypress)
   else
   endif
 
`if rightkey()=1 then rocketflag=1        :`right arrow key
`if rocketflag=1 and blastoff_flag=0 then targetgroup=1:_blast_off(ballhit)
 
   leftflipperkey=0
   rightflipperkey=0
   if keystate(44)=1 then _left_flipper()       :`Z key
   if keystate(29)=1 then _left_flipper()       :`Left CTRL key
   if keystate(42)=1 then _left_flipper()       :`Left Shift key
 
   if keystate(53)=1 then _right_flipper()      :`/ key
   if keystate(157)=1 then _right_flipper()     :`Right CTRL key
   if keystate(54)=1 then _right_flipper()      :`Right Shift key
 
   if upkey()=1 then position mouse mousex(),mousey()-2
   if downkey()=1 then position mouse mousex(),mousey()+2
 
   if returnkey()=1 then gosub _fire_pinball    :`FIRE!
   if spacekey()=1 then _tilt(ballinplay)                 :`tilt machine to nudge sleeping ball
 
   if safe_flag=1
      if leftflipperkey=1 or rightflipperkey=1 then _close_gate(1)
   endif
   rem --- return LEFT flipper to start position
   if leftflipper=1 and leftflipperkey=0
      if leftflipperangle<flippermaxangle
         inc leftflipperangle,flipspeed
         ode destroy object 370
         position object 370,lflip(leftflipperangle,1),lflip(leftflipperangle,2),lflip(leftflipperangle,3)
         _make_ode_flipper(370,leftflipperangle,10)
      else
         leftflipper=0
      endif
   endif
 
   rem --- return RIGHT flipper to start position
   if rightflipper=1 AND rightflipperkey=0
      if rightflipperangle>flipperminangle
         dec rightflipperangle,flipspeed
         ode destroy object 371
         position object 371,rflip(rightflipperangle,1),rflip(rightflipperangle,2),rflip(rightflipperangle,3)
         _make_ode_flipper(371,rightflipperangle,10)
      else
         rightflipper=0
      endif
   endif
 
   rem --- allow 10 seconds of safe play mode, where gates close side exits
   if safe_flag=1
      if timer()-balltime>10000
         safe_flag=0
         _open_gate(2)
         _open_gate(3)
         _close_gate(1)
      endif
   endif
 
   mx#=mousex()
   my#=mousey()
   mousebutton=mouseclick()
   if mousebutton=1 then gosub _fire_pinball         :`also FIRE!
 
   position object 201,rightwall-20,1,150-my#/7       :`position power meter line
 
   rem --- has ball kicker activated, reset after a time has passed
   if kick_flag>0
      if kicktime>0
         dec kicktime
      else
         _kick_reset(kick_flag)
      endif
   endif
 
`  --- clear balls falling thru bottom hole
   if object position z(ballcheck)<-10
      position object ballcheck,5000,500,0
      hide object ballcheck
      ode destroy object ballcheck
      ballsinplay(ballcheck)=0
      dec ballcount
      if ballcount=0 then fire_flag=1
   endif
 
   inc ballcheck
   if ballcheck>maxballs then ballcheck=1
 
remstart
   for i=1 to maxballs
      if ballsinplay(i)=1
 
      endif
   next i
remend
 
   if ballinplay>0
      for i=1 to maxballs
`         _check_droptargethits(ballinplay)
         if ballsinplay(i)>0
            _check_droptargethits(i)
         endif
      next i
   endif
remstart
set cursor 0,200
print "ballinplay=";ballinplay
print "rocketflag=";rocketflag
print "blastoff_flag=";blastoff_flag
print "targetgroup=";targetgroup
print "ballcount=";ballcount
print "ballsinhopper=";ballsinhopper
print "hopperdoordelay=";hopperdoordelay
remend
 
   if hopperdoordelay>0
      dec hopperdoordelay
      if hopperdoordelay=0 then _make_hopperdoor()
   endif
 
   if blastoff_flag=1
      goalflag=1
      if rocket_xpos#<179 then inc rocket_xpos#,0.5:goalflag=0
      if rocket_xpos#>181 then dec rocket_xpos#,0.5:goalflag=0
      if rocket_ypos#<190 then inc rocket_ypos#,0.5:goalflag=0
      if rocket_zpos#<topwall-ballsize-5 then inc rocket_zpos#,0.5:goalflag=0
      if goalflag=1
         if ballsinhopper=2
            _remove_hopperdoor()
            multi_ballflag=1
            inc ballcount,ballsinhopper
            ballsinhopper=0
            hopperdoordelay=500
         else
            inc ballsinhopper
            dec ballcount
`            dec ballinplay
         endif
`         _drop_multiball(ballinplay)
         _drop_multiball(ballhit)
 
`         inc ballsinhopper
`         dec ballcount
 
         _reset_targets(targetgroup)
         fire_flag=1
      else
`         _move_particles(ballinplay,rocket_xpos#,rocket_ypos#,rocket_zpos#,3)
         _move_particles(ballhit,rocket_xpos#,rocket_ypos#,rocket_zpos#,3)
      endif
   endif
 
   rem --- checks for groups of targets completed
   if targetgroup=0
      targetgroup=_check_target_groups(1,6,1)
      if targetgroup>0 and blastoff_flag=0
`         _blast_off(ballinplay)
         _blast_off(ballhit)
      endif
   endif
 
   if targetgroup=0
      targetgroup=_check_target_groups(7,10,2)
      if targetgroup>0 and blastoff_flag=0
`         _blast_off(ballinplay)
         _blast_off(ballhit)
      endif
   endif
 
   if targetgroup=0
      targetgroup=_check_target_groups(11,15,3)
      if targetgroup>0 and blastoff_flag=0
`         _blast_off(ballinplay)
         _blast_off(ballhit)
      endif
   endif
 
 
   gosub _show_score                               :`show score on screen
   ode update                                      :`let ODE update physics
   if tiltflag>0
      ode destroy object 401
      delete object 401
      tiltflag=0
   endif
   sync
loop
rem --------------------------------------------------------------------
ode end
end
 
 
function _make_hopperdoor()
_make_rail(426,railheight*2,4,railheight*2,MAGENTA,180,railheight,topwall-railheight/2,0,1,1)
endfunction
 
function _remove_hopperdoor()
ode destroy object 426
if object exist(426)=1 then delete object 426
endfunction
 
 
function _kick_out(objid)
if objid=360
   ode destroy object objid
   if object exist(objid)=1 then delete object objid
   _make_rail(360,railwidth*3,railheight,70,RED1,90,railheight/2,140,-45,100,1)
   kick_flag=360
   kicktime=20
endif
if objid=361
   ode destroy object objid
   if object exist(objid)=1 then delete object objid
   _make_rail(361,railwidth*3,railheight,70,RED1,230,railheight/2,140,45,100,1)
   kick_flag=361
   kicktime=20
endif
endfunction
 
 
function _kick_reset(objid)
if objid=360
   ode destroy object objid
   if object exist(objid)=1 then delete object objid
   _make_rail(360,railwidth*2,railheight,70,RED1,80,railheight/2,130,-45,100,1)
   kick_flag=0
endif
if objid=361
   ode destroy object objid
   if object exist(objid)=1 then delete object objid
   _make_rail(361,railwidth*2,railheight,70,RED1,240,railheight/2,130,45,100,1)
   kick_flag=0
endif
endfunction
 
 
function _tilt(objid)
x=object position x(objid)
y=object position y(objid)
z=object position z(objid)
make object sphere 401,ballsize,16,16
set object 401,1,1,0
set object collision off 401
position object 401, x,y+ballsize,z
 
ode destroy object 401
ode create dynamic sphere 401
ode set body mass 401,0.002
ode set contact bounce 401,1
 
ode set linear velocity 401,0,-1,0
tiltflag=401
endfunction
 
 
function _reset_targets(group)
for targetnum=targetgroups(group,2) to targetgroups(group,3)
   objid=targetnum+target_idfirst-1
   decalid=targetnum+decal_idstart-1
 
   move object up objid,targets(targetnum,5)
   texture object decalid,decalid
   targets(targetnum,1)=1
next targetnum
targetgroup=0
blastoff_flag=0
rocketflag=0
endfunction
 
 
function _drop_multiball(ball)
`while object position y(ballinplay)>ballinplay*ballsize
`   move object down ballinplay,1
`endwhile
 
`print "_drop_multiball(ballinplay)"
`sync
`wait key
 
blastoff_flag=0
rocketflag=0
ode create dynamic sphere ball
ode set body mass ball,0.002                 :`was 20, then 40
ode set contact bounce ball,1
 
ode set contact fdir1 ball,0                 :` was 30.0  Add FRICTION
ode set contact slip1 ball,1000
ode set contact slip2 ball,1000
ode set linear velocity ball,0,-5,0
delete particles 1
endfunction
 
 
function _check_target_groups(targetmin,targetmax,group)
rocketflag=group
for i=targetmin to targetmax
   if targets(i,1)=1 then rocketflag=0
next i
endfunction rocketflag
 
 
function _blast_off(objid)
ode destroy object objid
_make_particles()
blastoff_flag=1
rocket_xpos#=object position x(objid)
rocket_ypos#=object position y(objid)-20
rocket_zpos#=object position z(objid)
inc score,1000
`dec ballinplay
`position camera 180,500,topwall
`point camera 180,0,topwall
endfunction
 
 
function _make_particles()
make particles 1,1,2,30               :`rocket particles
set particle velocity 1,12       :`was 10
set particle emissions 1,20      :`was 8
set particle gravity 1,-4
set particle life 1,20
rotate particles 1,0,0,180             :`rocket exhaust particles point down
color particles 1,255,0,0
set particle chaos 1,100
endfunction
 
 
function _move_particles(objid,xpos#,ypos#,zpos#,thrust#)
   position object objid,xpos#,ypos#+20,zpos#
   position particles 1,xpos#,ypos#,zpos#
   set particle life 1,thrust#
endfunction
 
 
function _check_droptargethits(obj)
hitnum=object collision(obj,0)
 
      rem --- ball hitting drop targets ---
      if hitnum>=target_idfirst and hitnum<=target_idlast
         arrayindex=hitnum-899   :`targets objects start at 900, target info array starts at 1
         objid=hitnum+100        :`letter objects start at 1000
         decalid=objid+100       :`decals start at 1100
 
`         ballnum=0
         if targets(arrayindex,1)=1
            texture object objid,decalid
            move object down hitnum,targets(arrayindex,5)
            targets(arrayindex,1)=0
            inc score,100
            ballhit=obj
         endif
      endif
 
      if hitnum=360 or hitnum=361
         _kick_out(hitnum)
      endif
endfunction
 
 
rem --- targets(x,1=active, 2=posx, 3=posy, 4=posz, 5=downposy)
function _target_add(index,xpos,ypos,zpos,yposdown)
targets(index,1)=1
targets(index,2)=xpos
targets(index,3)=ypos
targets(index,4)=zpos
targets(index,5)=yposdown
endfunction
 
 
function _make_target(objid,xsize,ysize,zsize,color,xpos,ypos,zpos)
make object box objid,xsize,ysize,zsize
color object objid,color
position object objid,xpos,ypos,zpos
_target_add(objid-899,xpos,ypos,zpos,railheight-1)
endfunction
 
 
function _make_decals(decal_id,word$,fgcolor,bgcolor,fontsize)
set text font "Arial"
set text size fontsize
set text to bold
set text opaque
ink fgcolor,bgcolor
for i=0 to len(word$)-1
   cls bgcolor
   l$=mid$(word$,i+1)
   if l$="I"
         set cursor 9,3
   else
         set cursor 6,3
   endif
   center text 10,3,l$
   circle 10,10,8
   get image decal_id,0,0,20,20
   inc decal_id
`sync
`wait key
next i
endfunction decal_id
 
 
function _key_action(keypress)
select keypress
   `T key
   case 20
      if numballs<100
         inc numballs,100
      endif
   endcase
endselect
endfunction
 
 
function _left_flipper()
if leftflipperangle>flipperminangle
   dec leftflipperangle,flipspeed
   ode destroy object 370
   position object 370,lflip(leftflipperangle,1),lflip(leftflipperangle,2),lflip(leftflipperangle,3)
   _make_ode_flipper(370,leftflipperangle,10)
   leftflipper=1
endif
leftflipperkey=1
endfunction
 
 
function _right_flipper()
if rightflipperangle<flippermaxangle
   inc rightflipperangle,flipspeed
   ode destroy object 371
   position object 371,rflip(rightflipperangle,1),rflip(rightflipperangle,2),rflip(rightflipperangle,3)
   _make_ode_flipper(371,rightflipperangle,10)
   rightflipper=1
endif
rightflipperkey=1
endfunction
 
 
rem --- show score on screen
_show_score:
set cursor 1,1
print screen fps()
center text 100,100,"SCORE: "+str$(score)
return
 
 
 
 
rem ---------- fires pinballs --------------------------------------------------------
_fire_pinball:
if ballcount=ballsatonce then return
_open_gate(1)
_close_gate(2)
_close_gate(3)
safe_flag=1
fire_flag=0
hide object 1300
balltime=timer()
newballtime=timer()
if newballtime-lastballtime<balltiming then return else lastballtime=newballtime    :`control firing rate of pinballs
if numballs=0                          :`out of pinballs to shoot
   retryflag=1                         :`set retry flag, do you want to try this level again?
   return                              :`sound 3 = your gun is empty
endif
 
ballx#=rightwall-20
bally#=15
ballz#=0
 
`----------- ODE STUFF -------------------------------------------------------------------
position object odeballptr,ballx#,bally#,ballz#
`position object odeballptr,180,190,topwall-railheight/2
show object odeballptr
inc ballinplay
if ballinplay>maxballs then ballinplay=1
 
ode destroy object odeballptr
ode create dynamic sphere odeballptr
ode set body mass odeballptr,0.002                 :`was 20, then 40
ode set contact bounce odeballptr,1
 
ode set linear velocity odeballptr,0,0,80.0-my#/60.0
`ode set linear velocity odeballptr,0,-5,0
ode set contact fdir1 odeballptr,0                 :` was 30.0  Add FRICTION
ode set contact slip1 odeballptr,1000
ode set contact slip2 odeballptr,1000
 
dec numballs
inc ballcount                                     :`one more ball on screen, one less ball you can fired
 
ballsinplay(odeballptr)=1
inc odeballptr
if odeballptr>maxballs
   odeballptr=1
endif
`-----------------------------------------------------------------------------------------
return
 
 
rem - gatedata(gatenum,1=gate#, 2=objid, 3=openangle, 4=closeangle, 5=open xpos, 6=zpos, 7=close xpos
gatedata:
data 3
data 1,415,0,35,328,385,338
data 2,416,0,-35,26,165,16
data 3,417,0,35,305,165,315
 
function _load_gatedata()
restore gatedata     :`rem - point to gate data above
read numgates
for i=1 to numgates
   for j=1 to 7
      read gates(i,j)
   next j
next i
endfunction
 
 
function _open_gate(gatenum)
objid=gates(gatenum,2)
openangle=gates(gatenum,3)
xpos=gates(gatenum,5)
zpos=gates(gatenum,6)
ode destroy object objid
if object exist(objid)=1 then delete object objid
`_make_rail(objid,railwidth,railheight,railheight*2,GREEN1,ballchannel,railheight/2,380,openangle,1,1)
_make_gate(objid,gatewidth,railheight,gatesize,GREEN1,xpos,railheight/2,zpos,openangle,1,1)
endfunction
 
 
function _close_gate(gatenum)
objid=gates(gatenum,2)
closedangle=gates(gatenum,4)
xpos=gates(gatenum,7)
zpos=gates(gatenum,6)
ode destroy object objid
if object exist(objid)=1 then delete object objid
`_make_rail(objid,railwidth,railheight,railheight*2,GREEN1,ballchannel+12,railheight/2,380,closedangle,1,1)
_make_gate(objid,gatewidth*2,railheight,gatesize,GREEN1,xpos,railheight/2,zpos,closedangle,1,1)
endfunction
 
 
function _make_gate(objid,xsize,ysize,zsize,color,posx,posy,posz,yangle,bounce,odeflag)
make object box objid,xsize,ysize,zsize
color object objid,color
if odeflag=1 and yangle<>0
   rotate object objid,0,-yangle,0
endif
position object objid,posx,posy,posz
if odeflag=1
   ode create static box objid
   ode set contact fdir1 objid,0
   ode set contact bounce objid,bounce
endif
scale object objid,25,100,100
if odeflag=1 and yangle<>0
   rotate object objid,0,yangle,0
endif
endfunction
 
 
function _Game_Over()
`set cursor 1,200
center text screen width()/2,200,"Game Over"
center text screen width()/2,250,"Play Again Y/N?"
 
if a$="Y"
`more code needed here
else
   print "Thanks for Playing!"
   print "Press a key to exit game - Bye!"
   sync
   wait key
   end
endif
endfunction
 
`remend
 
 
function _lflipposition(posx,posy,posz,radius)
 
for i=0 to 360
   lflip(i,1)=posx+sin(wrapvalue(i))*radius
   lflip(i,2)=railheight/2
   lflip(i,3)=posz+cos(wrapvalue(i))*radius     :`was (radius*-1)
next i
endfunction
 
 
function _rflipposition(posx,posy,posz,radius)
 
for i=0 to 360
   rflip(i,1)=posx+sin(wrapvalue(i+180))*radius
   rflip(i,2)=railheight/2
   rflip(i,3)=posz+cos(wrapvalue(i+180))*radius     :`was (radius*-1)
next i
endfunction
 
 
 
ballcolors:
data 255,0,0
data 0,255,0
data 0,0,255
data 255,255,0
data 0,255,255
data 255,0,255
 
function _ball_textures()
restore ballcolors
for i=1 to 6
   for j=1 to 3
      read ballcolor(i,j)
   next j
next i
 
for i=1 to 6
   create bitmap i,50,50
   ink rgb(10,10,10),0
   box 0,0,50,50
   if i=1 then ink rgb(255,0,0),0
   if i=2 then ink rgb(0,255,0),0
   if i=3 then ink rgb(0,0,255),0
   if i=4 then ink rgb(255,255,0),0
   if i=5 then ink rgb(0,255,255),0
   if i=6 then ink rgb(255,0,255),0
   for x=1 to 1000
      ang=rnd(360)
      rad=rnd(20)
      dot 25+sin(ang)*rad,25+cos(ang)*rad
   next x
   blur bitmap i,3
   get image i+10,0,0,50,50
   delete bitmap i
next i
endfunction
 
 
function _playfield_graphics()
ink rgb(255,255,255),rgb(0,0,200)
cls 0
 
maxx=360
maxy=600
ink rgb(255,255,255),0
line 0,0,maxx,0
line maxx,0,maxx,maxy
line maxx,maxy,0,maxy
line 0,maxy,0,0
 
ink rgb(255,0,255),0
label$="POWER 987654321"
ptr=1
xloc=rightwall-18
yloc=360
for y=1 to len(label$)
   set cursor xloc,yloc
   print mid$(label$,ptr)
   inc yloc,15
   inc ptr
next y
 
x=rightwall-25
for y=450 to 650 step 15
   line x,y,x+20,y
next y
get image 10,0,0,maxx,maxy,1
endfunction
 
 
_intro:
sync
set text font "Arial"
set text size 30
cx=screen width()/2
cy=100
 
introtext:
data "-green"
data "Rocket Ship Pinball"
data "   "
data "-purple"
data "You get 5 balls per game"
data "  "
data "Complete the target words to blast balls off playfield."
data "This earns you a a BONUS score of 1000."
data "You get to launch the ball on the table again"
data "   "
data "   "
data "-cyan"
data "The mouse y-position, or UP/DOWN arrow keys to adjust power"
data "The LEFT mouse button, or RETURN key Launches the pinball"
data "The Z KEY, Left Shift, or Left CTRL key, controls the LEFT Flipper"
data "The / KEY, Right Shift, or Right CTRL key, controls the RIGHT Flipper"
data "  "
data "  "
data "  "
data "(Press the SPACE BAR to tilt the table if a balls gets stuck!)"
data "   "
data "-yellow"
data "Press a key to continue"
data "999"
 
cls
restore introtext
read t$
while t$<>"999"
   if left$(t$,1)="-"
      if t$="-green" then ink rgb(0,255,0),0
      if t$="-purple" then ink rgb(200,0,200),0
      if t$="-yellow" then ink rgb(255,255,0),0
      if t$="-cyan" then ink rgb(0,255,255),0
   else
      center text cx,cy,t$
      inc cy,30
   endif
   read t$
endwhile
 
sync
wait key
ink rgb(0,255,255),0
cls
sync
return
 
 
 
function _decal_signs(decal_id,word$,fgcolor,bgcolor,fontsize)
set text font "Arial"
set text size fontsize
set text to bold
set text opaque
ink fgcolor,bgcolor
signlen=len(word$)*10
cls bgcolor
center text signlen/2,3,word$
get image decal_id,0,0,signlen,fontsize+4,1
endfunction signlen
 
 
function _make_rail(objid,xsize,ysize,zsize,color,posx,posy,posz,yangle,bounce,odeflag)
make object box objid,xsize,ysize,zsize
color object objid,color
if odeflag=1 and yangle<>0
   rotate object objid,0,-yangle,0
endif
position object objid,posx,posy,posz
if odeflag=1
   ode create static box objid
   ode set contact fdir1 objid,0
   ode set contact bounce objid,bounce
endif
if odeflag=1 and yangle<>0
   rotate object objid,0,yangle,0
endif
endfunction
 
 
function _make_ode_flipper(objid,yangle,bounce)
if yangle<>0
   rotate object objid,0,-yangle,0
endif
ode create static box objid
ode set contact fdir1 objid,0
ode set contact bounce objid,bounce
if yangle<>0
   rotate object objid,0,yangle,0
endif
endfunction
 
 
function _remove_gravity(objid)
ode set gravity objid,0
endfunction
 
 
function _add_gravity(objid)
ode set gravity objid,gravity#
endfunction
 
 
function _add_force(objid,angle,force)
x1#=object position x(objid)
y1#=object position y(objid)
z1#=object position z(objid)
 
x2#=x1#-50.0
y2#=y1#
z2#=z1#-50.0
ode add force objid,x1#,y1#,z1#,x2#,y2#,z2#
endfunction
 
 
function _check_collisions()
` while ODE COLLISION MESSAGE EXISTS()
`  ODE COLLISION GET MESSAGE
` endwhile
 
phyptr=0
while ODE COLLISION MESSAGE EXISTS()
  `
  rem collision event
   ODE COLLISION GET MESSAGE
   phya=ODE GET OBJECT A()
   phyb=ODE GET OBJECT B()
if phya>0
   collisions(ptr)=phya
   inc phyptr
endif
   phyavelocity#=abs(ODE GET OBJECT A VELOCITY X())+abs(ODE GET OBJECT A VELOCITY Y()/4)+abs(ODE GET OBJECT A VELOCITY Z())
   phybvelocity#=abs(ODE GET OBJECT B VELOCITY X())+abs(ODE GET OBJECT B VELOCITY Y()/4)+abs(ODE GET OBJECT B VELOCITY Z())
set cursor 0,20
print "VelA=";phyavelocity#
print "VelB=";phybvelocity#
endwhile
endfunction