`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