Pool 32/64 bit update.

Game development specific discussions.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Pool 32/64 bit update.

Post by dodicat »

Windows (or Linux I think).
Some small sounds for Windows, none for Linux.
Tested on Win 10.

Code: Select all

Dim Shared As Single ratio=1
'#define fullscreen
'  FONTS
Function Filter(Byref tim As Ulong Pointer,_
    Byval rad As Single,_
    Byval destroy As Long=1,_
    Byval fade As Long=0) As Ulong Pointer
    #define map(a,b,_x_,c,d) ((d)-(c))*((_x_)-(a))/((b)-(a))+(c)
    If fade<0 Then fade=0:If fade>100 Then fade=100
    Type p2
        As Long x,y
        As Ulong col
    End Type
    #macro ppoint(_x,_y,colour)
    pixel=row+pitch*(_y)+(_x)*4
    (colour)=*pixel
    #endmacro
    #macro ppset(_x,_y,colour)
    pixel=row+pitch*(_y)+(_x)*4
    *pixel=(colour)
    #endmacro
    #macro average()
    ar=0:ag=0:ab=0:inc=0
    xmin=x:If xmin>rad Then xmin=rad
    xmax=rad:If x>=(_x-1-rad) Then xmax=_x-1-x
    ymin=y:If ymin>rad Then ymin=rad
    ymax=rad:If y>=(_y-1-rad) Then ymax=_y-1-y
    For y1 As Long=-ymin To ymax
        For x1 As Long=-xmin To xmax
            inc=inc+1 
            ar=ar+(NewPoints(x+x1,y+y1).col Shr 16 And 255)
            ag=ag+(NewPoints(x+x1,y+y1).col Shr 8 And 255)
            ab=ab+(NewPoints(x+x1,y+y1).col And 255)
        Next x1
    Next y1
    If fade=0 Then
        averagecolour=Rgb(ar/(inc),ag/(inc),ab/(inc))
    Else
        averagecolour=Rgb(fd*ar/(inc),fd*ag/(inc),fd*ab/(inc))
    End If
    #endmacro
    Dim As Single fd=map(0,100,fade,1,0)
    Dim As Integer _x,_y
    Imageinfo tim,_x,_y
    Dim  As Ulong Pointer im=Imagecreate(_x,_y)
    Dim As Integer pitch
    Dim  As Any Pointer row
    Dim As Ulong Pointer pixel
    Dim As Ulong col
    Imageinfo tim,,,,pitch,row
    Dim As p2 NewPoints(_x-1,_y-1)
    For y As Long=0 To (_y)-1
        For x As Long=0 To (_x)-1
            ppoint(x,y,col)
            NewPoints(x,y)=Type<p2>(x,y,col)
        Next x
    Next y
    Dim As Ulong averagecolour
    Dim As Long ar,ag,ab
    Dim As Long xmin,xmax,ymin,ymax,inc
    Imageinfo im,,,,pitch,row
    For y As Long=0 To _y-1
        For x As Long=0 To _x-1  
            average()
            ppset((NewPoints(x,y).x),(NewPoints(x,y).y),averagecolour) 
        Next x
    Next y
    If destroy Then Imagedestroy tim: tim = 0
    Function= im
End Function
Sub drawstring(Byval xpos As Long,Byval ypos As Long,Byref text As String,Byval colour As Ulong,Byval size As Single,Byref im As Any Pointer=0)
    Type D2
        As Double x,y
        As Ulong col
    End Type
    size=Abs(size)
    Static As d2 XY()
    Static As Long runflag
    If runflag=0 Then   
        Redim  XY(128,127)
        Screen 8
        Width 640\8,200\16 
        Dim As Ulong Pointer img
        Dim count As Long
        For ch As Long=1 To 127
            img=Imagecreate(9,17)
            Draw String img,(1,1),Chr(ch)
            For x As Long=1 To 8  
                For y As Long=1 To 16
                    If Point(x,y,img)<>0 Then
                        count=count+1
                        XY(count,ch)=Type<D2>(x,y)
                    End If 
                Next y
            Next x
            count=0
            Imagedestroy img
        Next ch
        runflag=1 
    End If
    If size=0 Then Exit Sub
    Dim As D2 np,t
    #macro Scale(p1,p2,d)
    np.col=p2.col
    np.x=d*(p2.x-p1.x)+p1.x
    np.y=d*(p2.y-p1.y)+p1.y
    #endmacro
    Dim As D2 c=Type<D2>(xpos,ypos)
    Dim As Long dx=xpos,dy=ypos,f
    If Abs(size)=1.5 Then f=3 Else f=2
    For z6 As Long=1 To Len(text)
        Var asci=text[z6-1]
        For _x1 As Long=1 To 64*2
            t=Type<D2>(XY(_x1,asci).x+dx,XY(_x1,asci).y+dy,colour)         
            Scale(c,t,size)
            If XY(_x1,asci).x<>0 Then 
                If size>1 Then 
                    Line im,(np.x-size/f,np.y-size/f)-(np.x+size/f,np.y+size/f),np.col,bf
                Else
                    Pset im,(np.x,np.y),np.col
                End If
            End If
        Next _x1
        dx=dx+8
    Next z6 
End Sub
Sub init Constructor 
    drawstring(0,0,"",0,0)
    Screen 0
End Sub
Function Colour(Byref im As Any Pointer,Byval newcol As Ulong,Byval tweak As Long,Byval fontsize As Single) As Any Pointer
    #macro ppset2(_x,_y,colour)
    pixel2=row2+pitch2*(_y)+(_x)*dpp2 
    *pixel2=(colour)
    #endmacro
    #macro ppoint(_x,_y,colour)
    pixel=row+pitch*(_y)+(_x)*dpp
    (colour)=*pixel
    #endmacro
    Dim As Long grade
    Select Case  fontsize
    Case 1 To 1.5:grade=205
    Case 2 :grade=225
    Case 2.5:grade=222
    Case 3 To 3.5:grade=200
    Case 4 To 4.5:grade=190
    Case 5 To 5.5:grade=165
    Case Else: grade=160
    End Select
    Dim As Integer w,h
    Dim As Integer pitch,pitch2,dpp,dpp2
    Dim  As Any Pointer row,row2
    Dim As Ulong Pointer pixel,pixel2
    Dim As Ulong col
    Imageinfo im,w,h,dpp,pitch,row
    Dim As Any Pointer temp=Imagecreate(w,h)
    Imageinfo temp,,,dpp2,pitch2,row2
    For y As Long=0 To h-1
        For x As Long=0 To w-1
            ppoint(x,y,col)
            Var v=.299*((col Shr 16)And 255)+.587*((col Shr 8)And 255)+.114*(col And 255)
            If v>(grade+tweak) Then 
                ppset2(x,y,newcol)
            Else
                ppset2(x,y,Rgb(255,0,255))
            End If
        Next x
    Next y
    Return temp
End Function

Sub CreateFont(Byref myfont As Any Pointer,Byval fontsize As Single,Byval col As Ulong,Byval tweak As Long=0)
    fontsize=Int(2*Abs(fontsize))/2
    If fontsize=0 Then fontsize=.5
    Dim As Ubyte Ptr p
    Dim As Any Pointer temp
    Dim As Integer i
    temp = Imagecreate(FontSize*768,FontSize*16)
    myfont=Imagecreate(FontSize*768,FontSize*16)
    For i = 32 To 127
        drawstring ((i-32)*FontSize*8,1,Chr(i),Rgb(255,255,255),FontSize,temp)
    Next i
    If fontsize>1.5 Then
        For n As Single=0 To fontsize-2:temp=filter(temp,1,1,0):Next
        End If
        temp=Colour(temp,col,tweak,fontsize)
        Put myfont,(0,0),temp,trans
        Imageinfo( myfont,i,,,, p )
        p[0]=0:p[1]=32:p[2]=127
        For i = 32 To 127
            p[3+i-32]=FontSize*8
        Next i
        Imagedestroy(temp)
    End Sub 
    Screenres 950,600,32
    Dim As Any Ptr starter
    createfont starter,2,Rgb(200,200,200),10
    Sub MoveScreenByMouse(mx As Long=0,my As Long=0,mb As Long=0)
        Getmouse mx,my,,mb
        Static As Long lastmx,lastmy,lastx,lasty
        If lastx=mx Andalso lasty=my Then Exit Sub Else lastx=Mx:lasty=my
        Dim As Integer x,y: Screencontrol 0, x, y
        If mb=2 Then Screencontrol 100, x-(lastmx-mx),y-(lastmy-my):Exit Sub
        lastmx=mx:lastmy=my
    End Sub
    Do
        MoveScreenByMouse
        Screenlock
        Cls
        Draw String(0,20),"If the balls are not round, adjust the ratio on first line.",,starter
        Draw String(0,50),"Pick up the target each time you commence a break.",,starter
        Draw String(0,80),"The target is always in the lower middle pocket.",,starter
        Draw String(0,140),"The whole screen can be moved by right mouse button.",,starter
        Draw String(0,170),"Cue ball speed can be set by mouse on the cue,",,starter
        Draw String(0,200),"OR by dragging the speed circle.",,starter
        Draw String(0,230),"To strike either click the ball OR the strike circle.",,starter
        Draw String(0,260),"You can try FULLSCREEN by uncommenting #define fullscreen.",,starter
        Draw String(0,350),"Press spacebar to commence.",,starter
        Screenunlock
        Sleep 1,1
    Loop Until Len(Inkey)
    
    Const xres=1024
    Const yres=768
    Dim Shared As Long potred,potyellow
    Dim Shared As Any Ptr small,tiny,redplay,yelplay,fin,nums
    #ifdef fullscreen
    Screenres xres,yres,32,,1 'fullscreen option
    #else
    Screenres xres,yres,32
    #endif
    
    createfont small,1,Rgb(255,0,200)
    createfont tiny,1,Rgb(255,255,255)
    createfont fin,3,Rgb(200,0,0)
    createfont redplay,2.5,Rgb(180,0,0)
    createfont yelplay,2.5,Rgb(180,180,0)
    createfont nums,2,Rgb(255,155,0),5
    
    Type V3
        As Single x
        As Single y
        As Single z
        Declare Property length As Single
        Declare Property unit As V3
    End Type
    #macro incirc(cx,cy,r,mx,my,a,result)
    If a<=1 Then
        result=a*(cx-mx)*a*(cx-mx) +(cy-my)*(cy-my)<= r*r*a*a
    Else
        result=a*(cx-mx)*a*(cx-mx) +(cy-my)*(cy-my)<= (r)*(r)
    End If
    #endmacro
    #define lng(x1,y1,x2,y2) sqr((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
    #define vct Type<v3>
    #define dot *
    #define cross ^
    #define map(a,b,x,c,d) ((d)-(c))*((x)-(a))/((b)-(a))+(c)
    #define round(x,N) rtrim(rtrim(left(str((x)+(.5*sgn((x)))/(10^(N))),instr(str((x)+(.5*sgn((x)))/(10^(N))),".")+(N)),"0"),".")
    #define incircle(c,mx,my) (mx)>(c.x-c.r) and (mx)<(c.x+c.r) and (my)>(c.y-c.r) and (my)<(c.y+c.r) 
    #define Rd( c ) (( c ) Shr 16 And 255 )
    #define Gr( c ) (( c ) Shr  8 And 255 )
    #define Bl( c ) (( c )And 255 )
    #define redball Rgb(240,0,0)
    #define yellowball Rgb(240,240,0)
    #define whiteball Rgb(200,200,200)
    #define blackball Rgb(20,20,20)
    #define Intrange(f,l) int(Rnd*((l+1)-(f))+(f))
    #define ontable(p) p.x>.1*xres and p.x<.9*xres and p.y>.1*yres and p.y<.9*yres
    #macro arraydelete(a,position)
    Scope
        Dim As Long index=position 
        If index>=Lbound(a) And index<=Ubound(a) Then
            Imagedestroy a(index).i: a(index).i=0
            For x As Long=index To Ubound(a)-1
                a(x)=a(x+1)
            Next x
            Redim Preserve a(Lbound(a) To Ubound(a)-1)
        End If 
    End Scope
    #endmacro
    Type Line
        As v3 v1,v2
    End Type
    Type _object
        As v3 position,velocity
        As Single mass,radius
        As Ulong colour
        As Any Ptr i
    End Type
    Type Circle
        As Long x
        As Long y
        As Long r
        As Ulong col
    End Type
    Type msg
        As String s
        As Ulong c
    End Type
    Type kick
        As V3 o
        As Long pnum
        As Single block
        As Long ballnumber
    End Type
    
    Operator + (Byref v1 As v3,Byref v2 As v3) As v3
    Return vct(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z)
    End Operator
    Operator -(Byref v1 As v3,Byref v2 As v3) As v3
    Return vct(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z)
    End Operator
    Operator * (Byval f As Single,Byref v1 As v3) As v3
    Return vct(f*v1.x,f*v1.y,f*v1.z)
    End Operator
    Operator * (Byref v1 As v3,Byref v2 As v3) As Single 
    Return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z
    End Operator
    Operator ^ (Byref v1 As v3,Byref v2 As v3) As v3 
    Return vct(v1.y*v2.z-v2.y*v1.z,-(v1.x*v2.z-v2.x*v1.z),v1.x*v2.y-v2.x*v1.y)
    End Operator
    Operator <>(Byref v1 As V3,Byref v2 As V3) As Long
    Return (v1.x<>v2.x) Or (v1.y<>v2.y)
    End Operator
    
    Property v3.length As Single
    Return Sqr(x*x+y*y+z*z)
    End Property
    
    Property v3.unit As v3
    Dim n As Single=length
    If n=0 Then n=1e-20
    Return vct(x/n,y/n,z/n)
    End Property
    #ifdef __FB_WIN32__
    Declare Function sound Alias"Beep"(Byval f As Long,Byval d As Long) As Long
    Declare Function PotBeep Lib "user32" Alias "MessageBeep" (Byval As Long) As Long
    #endif
    
    'collisions
    Function segment_distance(Byref l As Line,Byref p As v3,Byref ip As v3=vct(0,0,0)) As Single
        Var s=l.v1,f=l.v2
        Dim As Single linelength=(s-f).length
        Dim As Single dist= ((1/linelength)*((s-f) cross (p-s))).length
        Dim As Single lpf=(p-f).length,lps=(p-s).length
        If lps >= lpf Then
            Var temp=Sqr(lps*lps-dist*dist)/linelength
            If temp>=1 Then temp=1:dist=lpf
            ip=s+(temp)*(f-s)
            Return dist
        Else
            Var temp=Sqr(lpf*lpf-dist*dist)/linelength
            If temp>=1 Then temp=1:dist=lps
            ip=f+(temp)*(s-f)
            Return dist
        End If
        Return dist
    End Function
    Sub check_ball_to_ball_collisions(ball() As _object)
        For x As Long=Lbound(ball) To Ubound(ball)-1
            For y As Long=x+1 To Ubound(ball)
                Var seperation=(ball(x).position-ball(y).position).length
                Var impulse=(ball(x).position-ball(y).position).unit
                If seperation<=ball(x).radius+ball(y).radius Then
                    ball(x).position=ball(y).position+(ball(x).radius+ball(y).radius)*impulse
                    Var impact=ball(x).velocity-ball(y).velocity
                    Var dv=impact dot impulse
                    Var ma=ball(x).mass: Var mb=ball(y).mass
                    ball(x).velocity=ball(x).velocity-dv*((2*mb/(ma+mb)))*impulse
                    ball(y).velocity=ball(y).velocity+dv*((2*ma/(mb+ma)))*impulse
                End If
            Next y
        Next x
    End Sub
    Sub check_ball_to_line_collisions(LN() As Line, ball() As _object,Byref pass As V3,Byref active As V3)
        For z As Long=Lbound(ball) To Ubound(ball)
            For z2 As Long=Lbound(Ln) To Ubound(Ln)
                Dim As v3 closepoint
                Var seperation=segment_distance(Ln(z2),ball(z).position,closepoint)
                If seperation<=ball(z).radius Then
                    pass=active
                    Var impact=-1*ball(z).velocity
                    Var impulse=(closepoint-ball(z).position).unit
                    ball(z).position=closepoint-(ball(z).radius)*impulse
                    Var dv=(impact dot impulse) 
                    ball(z).velocity=ball(z).velocity+2*dv*impulse 
                End If
            Next z2
        Next z
    End Sub
    Sub ORB(Byval cx As Long,Byval cy As Long,Byval r As Long,Byval col As Long,Byref i As Any Ptr=0)
        Dim As Long result
        Dim As Single dist,p
        For x As Long=cx-r-1 To cx+r+1
            For y As Long=cy-r-1 To cy+r+1
                incirc(cx,cy,r,x,y,ratio,result)
                If result Then
                    dist=lng(cx,cy,x,y)
                    p=map(0,r,dist,1,.2)
                    Pset i,(x,y),Rgb(rd(col)*p,gr(col)*p,bl(col)*p)
                End If
            Next y
        Next x
        Circle i,(cx,cy),r,Rgb(rd(col)*p,gr(col)*p,bl(col)*p),,,ratio
    End Sub
    
    'SPEED REGULATOR
    Function Regulate(Byval MyFps As Long,Byref fps As Long) As Long
        Static As Double timervalue,lastsleeptime,t3,frames
        Var t=Timer
        frames+=1
        If (t-t3)>=1 Then t3=t:fps=frames:frames=0
        Var sleeptime=lastsleeptime+((1/myfps)-T+timervalue)*1000
        If sleeptime<1 Then sleeptime=1
        lastsleeptime=sleeptime
        timervalue=T
        Return sleeptime
    End Function
    
    Sub setup(balls() As _object)
        Dim As Long rad=20
        Dim As Single c
        Var d=2*rad
        Var e=37
        For n As Long=1 To 15
            balls(n).radius=rad
            balls(n).mass=1
            balls(n).velocity=vct(0,0,0)
            If n Mod 2 Then balls(n).colour=Rgb(240,0,0) Else balls(n).colour=Rgb(240,240,0)
            If n>=1 And n<=5 Then
                c=n
                balls(n).position=vct(.2*xres,.3*yres+d*c,0)
                c=c+1
            End If
            If n>5 And n<=9 Then
                c=n-5.5
                balls(n).position=vct(.2*xres+e,.3*yres+d+d*c,0)
            End If
            If n>9 And n<=12 Then
                c=n-10
                balls(n).position=vct(.2*xres+2*e,.3*yres+2*d+d*c,0)
                
            End If
            If n>12 And n<=14 Then
                c=n-13.5
                balls(n).position=vct(.2*xres+3*e,.3*yres+3*d+d*c,0)
            End If
            If n=15 Then
                balls(n).position=vct(.2*xres+4*e,.5*yres,0)
            End If
        Next n
        balls(11).colour=Rgb(20,20,20)
        balls(16).position=vct(.7*xres,.5*yres,0)
        balls(16).radius=rad
        balls(16).mass=1
        balls(16).colour=Rgb(200,200,200)
        balls(16).velocity=vct(0,0,0)
        Var dy=balls(3).position.y-.5*yres
        Var dd=1/Sqr(ratio)
        For n As Long=Lbound(balls) To Ubound(balls)
            If n<>15 And n<>16 Then balls(n).position.y=balls(n).position.y-dy
            balls(n).i=Imagecreate(2.1*dd*rad,2.1*dd*rad)
            orb(dd*rad,dd*rad,dd*rad,balls(n).colour,balls(n).i)
        Next n
    End Sub
    
    Sub setcircles(c() As Circle)
        c(1)=Type<Circle>(.5*xres,.025*yres,5,Rgb(200,0,200))'speed
        c(2)=Type<Circle>(.5*xres,.9*yres,10,Rgb(200,200,200))'target
        c(3)=Type<Circle>(.8*xres,.025*yres,8,Rgb(0,200,200))'strike
        c(5)=Type<Circle>(.04*xres,.4*yres,5,Rgb(0,0,255))'screw
        c(6)=Type<Circle>(.2*xres,.05*yres,19)'help
    End Sub
    
    Sub setedges(edge() As Line)
        Var Hgap=vct(26,0,0),Vgap=vct(0,26,0)
        Var dg=1.4
        Var T_L=vct(.1*xres,.1*yres,0),T_R=vct(.9*xres,.1*yres,0)
        Var tC=.5*(T_R+T_L)
        Var B_R=vct(.9*xres,.9*yres,0)
        Var B_L=vct(.1*xres,.9*yres,0)
        Var bC=.5*(B_R+B_L)
        edge(1)=Type<Line>(T_l+dg*hgap,tc-hgap)
        edge(2)=Type<Line>(tc+hgap,T_R-dg*hgap)
        edge(3)=Type<Line>(T_R+dg*vgap,B_R-dg*vgap) 
        edge(4)=Type<Line>(B_R-dg*hgap,bc+hgap)  
        edge(5)=Type<Line>(bc-hgap,B_l+dg*hgap)   
        edge(6)=Type<Line>(B_l-dg*vgap,T_l+dg*vgap) 
    End Sub
    Sub setpockets(pockets() As V3,Vpockets() As V3,Opockets() As V3,Byval size As Single)
        size=size/2
        Dim As Single dsize=yres/80
        Dim As v3 tc=Type<v3>(.5*(.1*xres+.9*xres),.1*yres,0)
        Dim As v3 bc=Type<v3>(.5*(.1*xres+.9*xres),.9*yres,0)
        pockets(1)=Type<v3>(.1*xres,.1*yres,0)+vct(dsize,dsize,0)
        pockets(2)=tc+vct(0,-dsize,0)
        pockets(3)=Type<v3>(.9*xres,.1*yres,0)+vct(-dsize,dsize,0)
        pockets(4)=Type<v3>(.9*xres,.9*yres,0)+vct(-dsize,-dsize,0)
        pockets(5)=bc+vct(0,dsize,0)
        pockets(6)=Type<v3>(.1*xres,.9*yres,0)+vct(dsize,-dsize,0)
        Vpockets(1)=pockets(1)+vct(size,size,0):Opockets(1)=pockets(1)+vct(-2*size,-2*size,0)
        Vpockets(2)=pockets(2)+vct(0,size,0):Opockets(2)=pockets(2)+vct(0,-2*size,0)
        Vpockets(3)=pockets(3)+vct(-size,size,0):Opockets(3)=pockets(3)+vct(2*size,-2*size,0)
        Vpockets(4)=pockets(4)+vct(-size,-size,0):Opockets(4)=pockets(4)+vct(2*size,2*size,0)
        Vpockets(5)=pockets(5)+vct(0,-size,0):Opockets(5)=pockets(5)+vct(0,2*size,0)
        Vpockets(6)=pockets(6)+vct(size,-size,0):Opockets(6)=pockets(6)+vct(-2*size,2*size,0)
    End Sub
    
    'DRAWING SUBS
    
    Function lineto(Byref a As V3,Byref b As v3,Byval L As Single) As v3
        Var u=(b-a).unit
        Return a+L*u
    End Function
    
    
    Sub Bmouse(Byval sz As Single,p() As V3,im2 As Any Ptr)
        Dim As V3 xyp
        p(1)=vct(0,0)
        xyp=LineTo(vct(0,0),vct(sz,.8*sz),sz):p(2)=xyp
        xyp=LineTo(xyp,vct(sz/2,xyp.y+.03*sz),.4*sz):p(3)=xyp
        xyp=LineTo(vct(0,0),vct(0,1.2*sz),sz):p(7)=xyp
        xyp=LineTo(xyp,vct(sz/2,xyp.y-sz/2),.4*sz):p(6)=xyp
        xyp=LineTo(xyp,vct(sz/2,xyp.y+sz/2),sz):p(5)=xyp
        xyp=LineTo(xyp,vct(xyp.x+sz/2,xyp.y-.4*sz),.2*sz):p(4)=xyp
        Var ctr=(1/3)*(p(1)+p(2)+p(7))
        For n As Long=1 To Ubound(p)-1
            Line im2,(p(n).x,p(n).y)-(p(n+1).x,p(n+1).y),Rgb(0,0,0)
        Next n
        Line im2,(p(1).x,p(1).y)-(p(7).x,p(7).y),Rgb(0,0,0)
        Line im2,(p(3).x,p(3).y)-(p(6).x,p(6).y),Rgb(0,0,0)
        Paint im2,(ctr.x,ctr.y),Rgb(200,0,0),Rgb(0,0,0)
        ctr=.25*(p(3)+p(4)+p(5)+p(6))
        Paint im2,(ctr.x,ctr.y),Rgb(100,100,255),Rgb(0,0,0)
    End Sub
   
    Sub drawballs(ball() As _object,pocket() As v3,Byref s As String="",Byval ptb As Long,Byval cpu As Long,Byval ptp As Long,Byref pass As V3,Byref active As V3)
        Dim As Long diff=ball(1).radius
        For n As Long=Lbound(ball) To Ubound(ball)
            If cpu=1 And ptb<>0 And ptp<>0 Then
                If n=ptb Then
                    Dim As v3 u=(pocket(ptp)-ball(ptb).position)
                    u=u.unit
                    Dim As Single l=ball(ptb).velocity.length
                    ball(n).velocity=l*u
                End If
            End If
            ball(n).position=ball(n).position+ball(n).velocity
            
            If cpu=1 Then
                If n=Ubound(ball) Then
                    If pass<>vct(0,0,0) Then
                        Dim As v3 u=ball(ptb).position-ball(Ubound(ball)).position
                        u=u.unit
                        Var d=ball(Ubound(ball)).velocity.length
                        ball(Ubound(ball)).velocity=d*u
                        pass=vct(0,0,0)
                        active=vct(0,0,0)
                    End If
                End If
            End If
            
            
            If n<>Ubound(ball) Then
                If ball(n).velocity<>vct(0,0,0) Then
                    If Len(s)<11 Then
                        s=s+Str(ball(n).colour)
                    End If
                End If
            End If
            If Len(s) Then
                ball(Ubound(ball)).mass=1
            End If
            
            Put(ball(n).position.x-diff,ball(n).position.y-diff),ball(n).i,trans
            Var k=map(0,30,ball(n).velocity.length,.001,0)
            ball(n).velocity=(.99+k)*ball(n).velocity
            If (ball(n).velocity).length<.2 Then
                ball(n).velocity=vct(0,0,0)
            End If
        Next n
    End Sub
    
    Sub DrawImage(z() As Line,p() As V3,Byref im As Any Ptr,Byref im2 As Any Ptr)
        Line im,(.1*xres,.1*yres)-(.9*xres,.9*yres),Rgb(0,80,0),bf'table
        For n As Long=Lbound(z) To Ubound(z)
            Line im,(z(n).v1.x,z(n).v1.y)-(z(n).v2.x,z(n).v2.y),Rgb(00,85,0)
        Next n
        For k As Long=0 To 5
            Line im,(.09*xres-k,.09*yres-k)-(.91*xres+k,.91*yres+k),Rgb(100,50,0),b'outside
        Next k
        Dim As Ulong back=Rgb(0,0,70)
        Paint im,(5,5),back,Rgb(100,50,0)
        
        Circle im,(.09*xres,.09*yres),45,back,,,,f
        Circle im,(.09*xres,.91*yres),45,back,,,,f
        Circle im,(.91*xres,.09*yres),45,back,,,,f
        Circle im,(.91*xres,.91*yres),45,back,,,,f
        Circle im,(.5*xres,.08*yres),30,back,,,,f
        Circle im,(.5*xres,.92*yres),30,back,,,,f
        Circle im,(.2*xres,.05*yres),20
        Draw String im,(.23*xres,.04*yres),"<-Helper",,tiny
        Line im,(.395*xres,.025*yres-7)-(.605*xres,.025*yres+7),Rgb(200,200,200),b
        Draw String im,(.31*xres,.02*yres),"Speed ->",,tiny
        Draw String im,(.63*xres,.02*yres),"<- Speed",,tiny
        Circle im,(.8*xres,.025*yres),8,Rgb(200,100,00),,,,f
        ''Draw String im,(.82*xres,.015*yres),"<-- STRIKE",,small
        Draw String im,(10,.75*yres),"Scores",,tiny
        Draw String im,(0,.5*yres),"MESSAGES:",,small
        'screw
        orb(.04*xres,.4*yres,.04*xres,whiteball,im)
        Draw String im,(.01*xres,.3*yres),"CUEBALL",,tiny
        Draw String im,(.03*xres,.32*yres),"Top",,tiny
        Draw String im,(.025*xres,.46*yres),"Screw",,tiny
        Line im,(.04*xres,.35*yres)-(.04*xres,.45*yres)
        Bmouse(30,p(),im2)
    End Sub
    
    Sub drawcircles(c() As Circle,Byval moveflag As Long,Byval startflag As Long)
        If moveflag=0 Then c(2).col=Rgb(255,0,200) Else c(2).col=Rgb(200,200,200)
        Circle(c(1).x,c(1).y),c(1).r,c(1).col,,,,f
        Circle(c(2).x,c(2).y),c(2).r/3,c(2).col,,,,f
        If moveflag=0 Then 
            Circle(c(4).x,c(4).y),c(4).r,c(4).col,,,,f'cue
            If startflag Then 
                For n As Long=0 To 200 Step 3
                    Var p=lineto(Type<V3>(c(4).x,c(4).y),Type<v3>(c(2).x,c(2).y),-n)
                    Circle(p.x,p.y),4+n/100,Rgb(100,50+n/4,0),,,,f
                Next n
            End If
        End If
        Circle(c(5).x,c(5).y),c(5).r,c(5).col,,,,f
        Circle(c(6).x,c(6).y),c(6).r,c(6).col,,,,f
    End Sub
    
    'CHECK SUBS 
    
    Function fixspeed(Byref v As V3,Byval n As Single) As Single
        Dim As Single totdist=v.length,speed
        Var _lngth=map(0,(n*xres),totdist,0,20)
        speed=_lngth
        If speed>20 Then speed=20 
        If speed<2 Then speed=2
        Return speed 
    End Function
    
    Function pathtopocket2(all() As _object,Byref b As V3,Byref p As V3,Byref num As Long=0) As Long
        Dim As V3 tmp=vct(p-b)
        tmp=tmp.unit
        Dim As V3 dv=all(1).radius*tmp
        Dim As Line seg=Type<Line>(b+2.2*dv,p+2.2*dv)
        num=0
        Dim As Single r=2*all(1).radius
        For n As Long=Lbound(all) To Ubound(all)
            If segment_distance(seg,all(n).position) < r Then
                Return 0
            End If
            num=n
        Next n
        Return -1
    End Function
    
    Function pathtoball(all() As _object,Byref num As _object,Byval col As Ulong,Byval start As Long) As Long
        If all(start).colour=col Then
            num=all(start)
            Return start
        End If
        Return 0
    End Function
    
    Function pathtoballFULL(all() As _object,Byref num As _object,Byval col As Ulong,Byval start As Long,Byval finish As Long) As Long
        Dim As Single r=2*all(1).radius
        Dim As V3 cueball=all(Ubound(all)).position
        For n1 As Long=start To finish
            Dim As Long retval
            If all(n1).colour=col Then
                Var d=(all(n1).position-cueball).length
                Var thisball=all(n1)
                For n2 As Long=Lbound(all) To Ubound(all)-1
                    retval=1
                    If n2<>n1 Then
                        For k As Single=r/2 To d-r/2+1 Step 1
                            Dim As V3 v=lineto(cueball,thisball.position,k)
                            If (v-all(n2).position).length<r Then
                                retval=0:Exit For,For
                            End If
                        Next k
                    End If
                Next n2
                If retval=1 Then
                    num=thisball
                    retval=n1
                    Return retval
                End If
            End If 
        Next n1
        Return 0
    End Function
    Function pathtoballPART(all() As _object,Byref num As _object,Byval col As Ulong) As Long
        Dim As Single r=2*all(1).radius
        Dim As Long start=1
        Dim As V3 cueball=all(Ubound(all)).position
        For n1 As Long=start To Ubound(all)-1
            Dim As Long retval
            If all(n1).colour=col  Then
                Var d=(all(n1).position-cueball).length
                Var thisball=all(n1)
                For n2 As Long=Lbound(all) To Ubound(all)-1
                    If all(n2).colour=redball Or all(n2).colour=blackball Then
                        retval=1
                        If n2<>n1 Then
                            For k As Single=r/2 To d-r/2 Step 1
                                
                                Dim As V3 v=lineto(cueball,thisball.position,k)
                                If (v-all(n2).position).length<r Then
                                    retval=0:Exit For,For
                                End If
                            Next k
                        End If
                    End If
                    
                Next n2
                If retval=1 Then
                    If start>= Ubound(all)-1 Then Return 0
                    num=thisball
                    retval=n1
                    Return retval
                End If
            End If
        Next n1
        Return 0
    End Function
    Function Dpath(all() As _object,Byref b As V3,Byref o2 As V3,Byref o As V3) As Long
        Dim As Single r=2*all(1).radius
        For n As Long=Lbound(all) To Ubound(all)-1
            If all(n).position<>o Then
                If (all(n).position-o2).length<(r+1) Then  Return 0
            End If
        Next n
        Var v4=lineto(b,o2,0)'r/2)
        Var v5=lineto(o2,b,1.1*r)'1.5
        Dim As Line a=Type<Line>(v4,v5)
        For n2 As Long=Lbound(all) To Ubound(all)-1
            If segment_distance(a,all(n2).position)<r+1 Then Return 0
        Next n2
        Return -1
    End Function
    
    Function directpath(all() As _object,Byref num As V3,Byref num2 As V3) As Long
        Dim As Single r=2*all(1).radius
        Var d=(num2-num).length
        For n2 As Long=Lbound(all) To Ubound(all)-1
            For k As Single=r+1 To d-1*r-1
                Dim As V3 v=lineto(num2,num,k)
                If (v-all(n2).position).length<r+1 Then
                    Return 0
                End If
            Next k
        Next n2
        Return -1
    End Function
    
    Function Bpath(all() As _object,Byref num As _object,Byref v1 As V3,Byval col As Ulong) As Long
        Dim As Single r=2*all(1).radius
        For n1 As Long=Lbound(all) To Ubound(all)-1
            Dim As Long retval
            If all(n1).colour=col Then
                Var thisball=all(n1)
                For n2 As Long=Lbound(all) To Ubound(all)-1
                    If all(n2).colour=redball Or all(n2).colour=blackball Then
                        retval=1
                        If n2<>n1 Then
                            Var v4=lineto(v1,thisball.position,r/2)
                            Var v5=lineto(thisball.position,v1,r/2)
                            Dim As Line a=Type<Line>(v4,v5)
                            If segment_distance(a,all(n2).position)<1.1*r Then
                                retval=0:Exit For
                            End If
                        End If
                    End If
                Next n2
                If retval=1 Then
                    num=thisball
                    retval=n1
                    Return retval
                End If
            End If 
        Next n1
        Return 0
    End Function
    'check moving
    Function checkVELOCITY(ball() As _object) As Single
        Dim As Single ke
        For n As Long=Lbound(ball) To Ubound(ball)
            ke+=ball(n).velocity*ball(n).velocity
        Next n
        Return ke
    End Function
    
    Sub respot(ball() As _object)
        Dim As V3 oldpos=vct(.7*xres,.5*yres,0),newpos=oldpos
        Dim As Long flag
        st:
        flag=0
        For n As Long=Lbound(ball) To Ubound(ball)-1
            Var d=(newpos-ball(n).position).length
            If d<2*ball(Ubound(ball)).radius Then flag=1:Exit For
        Next n
        If flag=0 Then 
            ball(Ubound(ball)).position=newpos:ball(Ubound(ball)).velocity=vct(0,0,0):Exit Sub
        Else
            newpos=oldpos+vct(intrange(0,.15*xres),intrange(-.25*yres,.25*yres),0)
            Goto st
        End If
    End Sub
    'check potted
    Sub checkPOTS(ball() As _object,pocket() As V3,pocket2() As V3,Byref Pflag As Long,Byval trackblack As Long)
        Dim As Long k,f
        For n1 As Long=Lbound(ball) To Ubound(ball)
            For n2 As Long=Lbound(pocket) To Ubound(pocket)
                Dim As Circle c=Type<Circle>(pocket(n2).x,pocket(n2).y,ball(Lbound(ball)).radius)
                Dim As Circle c2=Type<Circle>(pocket2(n2).x,pocket2(n2).y,ball(Lbound(ball)).radius)
                Var x1= incircle(c,ball(n1).position.x,ball(n1).position.y)
                Var x2=incircle(c2,ball(n1).position.x,ball(n1).position.y)
                If x1 Or x2 Then
                    'If incircle(c,ball(n1).position.x,ball(n1).position.y) Or incircle(c2,ball(n1).position.x,ball(n1).position.y) Then
                    #ifdef __fb_win32__
                    potbeep(&h00000040L)
                    #endif
                    k=n1
                    Exit For,For
                End If
            Next n2
        Next n1
        If k=0 Then
            For n As Long=Lbound(ball) To Ubound(ball)-1
                If ball(n).position.x<.09*xres Or ball(n).position.x>.91*xres Or _
                ball(n).position.y<.09*yres Or ball(n).position.y>.91*yres Then
                k=n:f=1:Exit For
            End If
        Next n
    End If
    If k=Ubound(ball) Then 
        pflag=1
        ball(Ubound(ball)).velocity=vct(0,0,0)
        ball(Ubound(ball)).position=vct(.05*xres,.6*yres,0)
    End If
    
    If k=trackblack Then Pflag=13:Exit Sub
    
    If k <>0 And Pflag<>1 Then
        If ball(k).colour=yellowball Then Pflag=2
        If ball(k).colour=redball Then Pflag=3
        If f Then pflag=4
        ball(k).radius=0:ball(k).mass=0
        arraydelete(ball,k)
    End If
End Sub
Sub bsort(array() As Kick)
    For p1 As Long  = 1 To Ubound(array) - 1
        For p2 As Long  = p1 + 1 To Ubound(array)  
            If array(p1).block>array(p2).block Then Swap array(p1),array(p2)
        Next p2
    Next p1
End Sub
#macro show()
MoveScreenByMouse
Screenlock
Cls
Put(0,0),im,Pset
drawballs(balls(),vpockets(),s,catchptb,cpu,w2.pnum,pass,active)
check_ball_to_ball_collisions(balls())
check_ball_to_line_collisions(edge(),balls(),pass,active)
drawcircles(circ(),moveflag,startflag)
If lineflag=1 Then
    Draw String (.82*xres,.015*yres),"<-- STRIKE",,small
    Line(balls(Ubound(balls)).position.x,balls(Ubound(balls)).position.y)-(circ(2).x,circ(2).y),Rgb(255,255,255),,&b10
    Var BaL=vct(balls(Ubound(balls)).position.x,balls(Ubound(balls)).position.y)
    Var tgt=vct(circ(2).x,circ(2).y)
    temp=lineto(bal,tgt,-balls(1).radius)
    Var lngth=.6*xres-.4*xres
    Qs=lineto(temp,tgt,-lngth/3)
    Line(temp.x,temp.y)-(Qs.x,Qs.y),Rgb(200,0,200)
End If
If msgflag=0 Then Draw String(.51*xres,.9*yres),"<-- Pick up target from here.",,tiny
Var sp=round(speed,1)
Var ls=Len(sp)
Draw String(.49*xres-4*ls,.04*yres),sp,,nums

Draw String(10,30),"FPS = " & fps
If test.c=redball Then
    Draw String (.4*xres,.93*yres),test.s+" BREAK",,redplay
Else
    Draw String (.4*xres,.93*yres),test.s+" BREAK",,yelplay  
End If

Draw String(.065*yres,.8*yres),Str(scorered),,redplay
Draw String(.005*yres,.8*yres),Str(scoreyellow),,yelplay
Draw String(5,.52*yres),message.s,message.c

If strikeflag=1 Then Circle(circ(3).x,circ(3).y),8,circ(3).col,,,,f:strikeflag=0
For n As Long=Lbound(balls) To Ubound(balls)
    If balls(n).colour=blackball Then trackblack=n
Next n

If test.s="PLAYER" And moveflag=0 And help=-1 Then
    For n1 As Long=Lbound(balls) To Ubound(balls)-1
        For n2 As Long=Lbound(Vpockets) To Ubound(Vpockets)
            Dim As Long path
            Dim As _object oo
            Dim As V3 o3
            If balls(n1).colour=redball Then
                Var pp= pathtopocket2(balls(),balls(n1).position,Vpockets(n2))
                Var pb=pathtoball(balls(),oo,redball,n1)
                If pp And pb Then
                    Dim As V3 tocue=(balls(n1).position-balls(Ubound(balls)).position)
                    Var ang=tocue dot (Vpockets(n2)-balls(n1).position)
                    ang=ang/(tocue.length*(Vpockets(n2)-balls(n1).position).length)
                    If Acos(ang)<1.2    Then
                        Dim As V3 topocket=(Vpockets(n2)-oo.position)
                        topocket=topocket.unit
                        o3=oo.position-1.9*balls(Ubound(balls)).radius*topocket
                        If ontable(o3) Then
                            path=Dpath(balls(),balls(Ubound(balls)).position,o3,oo.position)
                        End If
                    End If
                    If pp And path And pb Then
                        Circle(o3.x,o3.y),5,Rgb(0,0,200)
                        Line(balls(n1).position.x,balls(n1).position.y)-(vpockets(n2).x,Vpockets(n2).y),Rgb(0,130,0),,&b1111000011111
                    End If
                End If
            End If
        Next n2
    Next n1
End If

If test.s="PLAYER" Then Put(mx,my),Mim,trans
Screenunlock
Sleep regulate(65,fps),1
#endmacro

#macro mouse(P,condition,flag)
While mb = 1
    Getmouse mx,my,,mb
    show()
    If (condition) Then
        If mx<>p.x Or my<>p.y  Then
            If flag<>2 Then p.x=mx
            If flag<>3 Then p.x=mx
            If flag=3 Then'screw line
                p.x=.04*xres
                p.y=my
                p.x=.04*xres
                balls(Ubound(balls)).mass=map(.35*yres,.45*yres,p.y,1.5,.5)   
            End If
            
            If flag=2 Then'cue line
                p.y=tmpcue.y
                p.x=tmpcue.x
                startflag=1
                circ(4)=Type<Circle>(p.x,p.y,5,Rgb(0,0,255))
                Var totlngth=(temp-Qs).length
                Var seglength=(temp-Type<v3>(p.x,p.y,0)).length
                speed=map(0,totlngth,seglength,0,20)
                lastspeed=speed
                circ(1).x=map(0,20,speed,.4*xres,.6*xres)
            End If
            
            If flag=0 Then'speed 
                speed=map((.4*xres),(.6*xres),p.x,0,20)
                lastspeed=speed
            End If
            
            If flag=1 Then'target 
                cpu=0
                p.y=my
                If moveflag=0 Then
                    lineflag=1
                    dirn=(vct(p.x-balls(Ubound(balls)).position.x,p.y-balls(Ubound(balls)).position.y)).unit
                End If
            End If
        End If
    End If
Wend
#endmacro
#macro player()
circ(5).y=map(1.5,.5,balls(Ubound(balls)).mass,.35*yres,.45*yres)
If test.s="COMPUTER" And cb=0 And potyellow<>1 Then test.s="PLAYER":test.c=redball
If cpu=0 Then speed=lastspeed:circ(1).x=map(0,20,speed,(.4*xres),(.6*xres))

'speed 
If incircle(Circ(1),mx,my) And cpu=0 Then
    If mb=1 Then circ(4)=Type<Circle>(0,0,0,0)
    mouse(circ(1), mx>.4*xres And mx<.6 * xres And my<.035*yres,0)
End If

'target 
If incircle(Circ(2),mx,my) Then
    If moveflag=0 Then
        If mb=1 Then circ(4)=Type<Circle>(0,0,0,0) 
        vflag=1
        mouse(circ(2), mx>1 And mx<xres-1 And my<yres-1 And my>1,1)
    End If
End If
'strike 
If moveflag=0 And vflag=1  Then
    
    Var LB=Type<Circle>(balls(Ubound(balls)).position.x,balls(Ubound(balls)).position.y,.8*balls(1).radius)
    If incircle(Circ(3),mx,my) Or incircle(LB,mx,my) And cpu=0  Then
        If mb=1 Then circ(4)=Type<Circle>(0,0,0,0)
        strikeflag=1
        startflag=1
        If mb=1 Then
            circ(2).x=.5*xres:circ(2).y=.9*yres
            potred=0
            lineflag=0
            msgflag=1
            vflag=0
            balls(Ubound(balls)).velocity=speed*dirn
            #ifdef __fb_win32__
            sound(1000,5)
            #endif
        End If
    End If
End If

Dim As Line sl=Type<Line>(temp,Qs) 
If segment_distance(sl,Type<V3>(mx,my))<5 And mb=1 Then
    circ(4)=Type<Circle>(mx,my,5)
End If

If incircle(Circ(4),mx,my) Then
    If lineflag=1 Then
        Dim As Line sl=Type<Line>(temp,Qs)
        cpu=0
        mouse(circ(4),(segment_distance(sl,Type<v3>(mx,my,0),tmpcue)<5),2)
    End If
End If

If incircle(circ(5),mx,my) And cpu=0 Then'screw
    mouse(circ(5),(my>.35*yres And my<.45*yres),3)
End If

If incircle(circ(6),mx,my) Then'helper
    If mb=1 Then If help=1 Then help=-1:circ(6).col=Rgb(0,0,200)
End If

If startflag=1 Then
    
    If moveflag=0 And lineflag=0 And strikeflag=0 Then 
        play=0
        If potred=1 Then play=1
    End If
End If
If play=0 Then test.s="COMPUTER":test.c=yellowball

show()
#endmacro

#macro compute()
help=1:circ(6).col=Rgb(0,0,50)
test.s="COMPUTER":test.c=yellowball
balls(Ubound(balls)).mass=1
circ(5).y=map(1.5,.5,balls(Ubound(balls)).mass,.35*yres,.45*yres)
Dim As Long start=1,interflag
ptp=0
block=0
#ifdef __FB_WIN32__
sound(1000,5)
#endif
start=1
speed=10
Redim w(0)
begin:
Do
    ptb=0
    If numyellow>0 Then
        ptb=pathtoball(balls(),o,yellowball,start):If ptb Then Exit Do
    Else
        ptb=pathtoball(balls(),o,blackball,start):If ptb Then Exit Do
    End If
    Exit Do
Loop

If ptb Then
    'CHECK  POT
    For n2 As Long=Lbound(Vpockets) To Ubound(Vpockets)
        Dim As V3 tocue=(o.position-balls(Ubound(balls)).position),o2
        Var ang=tocue dot (Vpockets(n2)-o.position)
        ang=ang/(tocue.length*(Vpockets(n2)-o.position).length)
        If Acos(ang)<block    Then
            ptp=0
            ptp= pathtopocket2(balls(),o.position,Vpockets(n2))
            Dim As Long path
            If ptp Then
                Dim As V3 topocket=(Vpockets(n2)-o.position)
                topocket=topocket.unit
                o2=o.position-1.75*balls(Ubound(balls)).radius*topocket
                path=dpath(balls(),balls(Ubound(balls)).position,o2,o.position)
                If n2=2 Or n2=5 Then
                    Var u=vct(1,0,0)
                    Var dt=u dot topocket
                    If Abs(dt)>.9 Then path=0
                End If
                If path  Then
                    Redim Preserve w(1 To Ubound(w)+1)
                    With w(Ubound(w))
                        .o=o.position
                        .pnum=n2
                        .block=block
                        .ballnumber=ptb
                    End With
                End If
            End If
        End If
    Next n2
End If

While block<=1.5
    block=block+.1
    Goto begin
Wend

While start<=Ubound(balls)-1
    start=start+1:block=0:Goto begin
Wend

If Ubound(w)<>0 Then
    bsort(w())
    w2=w(Lbound(w))
    interflag=1
    catchptb=w2.ballnumber
    Var topocket=(Vpockets(w2.pnum)-w2.o)
    Catchvector=topocket
    topocket=topocket.unit
    w2.o=w2.o-1.75*balls(Ubound(balls)).radius*topocket
    Var cuetoball=w2.o-balls(Ubound(balls)).position
    Dim As Single totdist=catchvector.length+cuetoball.length
    Var lngth=map(0,1.5*xres,totdist,0,20)
    Var f=map(0,1.5,w2.block,1,1.5)
    speed=f*lngth
    If speed>20 Then speed=20
    dirn=cuetoball.unit
End If

'DIRECT 
If interflag=0  Then
    If numyellow>0 Then
        ptb=pathtoballFULL(balls(),o,yellowball,1,Ubound(balls)-1)
    Else
        ptb=pathtoballFULL(balls(),o,blackball,1,Ubound(balls)-1)
    End If
    
    If ptb <>0  Then
        dirn=(o.position-balls(Ubound(balls)).position).unit
        speed=fixspeed((o.position-balls(Ubound(balls)).position),1)
        interflag=1
    End If
End If

If interflag=0  Then
    'indirect 
    If numyellow>0 Then
        ptb=pathtoballPART(balls(),o,yellowball)
    Else
        ptb=pathtoballPART(balls(),o,blackball)
    End If
    If ptb<>0 Then
        dirn=(o.position-balls(Ubound(balls)).position).unit 
        interflag=1
    End If
    speed=12
End If

If interflag=0  Then
    Dim As Ulong clr
    If numyellow>0 Then clr=yellowball Else clr=blackball
    Dim As V3 cueball=balls(Ubound(balls)).position,p
    'Glance hit
    For n As Long=1 To Ubound(balls)-1
        If balls(n).colour=clr Then
            Var v=balls(n).position-cueball
            Var norm=v.unit
            Swap norm.x,norm.y:norm.x=-norm.x
            p=balls(n).position+1.9*balls(Ubound(balls)).radius*norm
            ptb=directpath(balls(),p,cueball)
            If ptb Then dirn=p-cueball:dirn=dirn.unit:speed=fixspeed(v,1.5):interflag=1:Goto cont3
            p=balls(n).position-1.9*balls(Ubound(balls)).radius*norm
            ptb=directpath(balls(),p,cueball)
            If ptb Then dirn=p-cueball:dirn=dirn.unit:speed=fixspeed(v,1.5):interflag=1:Goto cont3
        End If
    Next n
End If
cont3:

'snookered
If interflag=0  Then
    Dim As Long path
    Dim As V3 cueball=balls(Ubound(balls)).position
    Dim As Single totlen
    For l As Long=1 To 6
        Dim As V3 perp
        If l=1 Or l=2 Then perp=vct(0,1,0)
        If l=4 Or l= 5 Then perp=vct(0,1,0)
        If l=3 Or l= 6 Then perp=vct(1,0,0)
        Var V1=edge(l).v1,V2=edge(l).v2
        Var dist=(V1-V2).length
        For k As Single=0 To dist Step .5
            path=0
            Dim As V3 v=lineto(V1,V2,k)
            path=dpath(balls(),cueball,v,v)
            If path Then
                path=0
                If numyellow>0 Then
                    path=Bpath(balls(),o,v,yellowball)
                Else
                    path=Bpath(balls(),o,v,blackball)
                End If
                totlen=(v-cueball).length
            End If
            
            If path Then 
                Dim As V3 leg1=(v-cueball),leg2=(o.position-v)
                leg1=leg1.unit:leg2=leg2.unit
                Var dt=Abs(Abs(leg1 dot perp)-Abs(leg2 dot perp))
                If dt <.001 Then
                    dirn=(v-cueball).unit
                    catchptb=path
                    active=leg2
                    active=active.unit
                    totlen=totlen+(o.position-v).length
                    Var lngth=map(0,1.5*xres,totlen,0,20)
                    speed=lngth
                    If speed>20 Then speed=20
                    interflag=1
                    Exit For,For
                End If
                
            End If
        Next k
    Next l
End If 
'no hit or pot
If interflag=0  Then
    Dim As Single dist=2*xres,k
    For n As Long=1 To Ubound(balls)-1
        Var d=(balls(Ubound(balls)).position-balls(n).position).length
        If dist>d Then dist=d:k=n
    Next n
    speed=fixspeed(balls(Ubound(balls)).position-balls(k).position,1.5)
    dirn=-1*(balls(Ubound(balls)).position-balls(k).position).unit
End If

circ(1).x=map(0,20,speed,(.4*xres),(.6*xres))

balls(Ubound(balls)).velocity=speed*dirn
strikeflag=1
startflag=0
play=1
#endmacro
Dim As Any Pointer im=Imagecreate(xres,yres,Rgb(0,50,0)),Mim=Imagecreate(80,80)
Redim As _object balls(1 To 16)
Dim As Line edge(1 To 6)
Dim As Line TS=Type<Line>(vct(.04*xres,.35*yres),vct(.04*xres,.45*yres))
Dim As Circle circ(1 To 4+2)
Dim As V3 pockets(1 To 6)
Dim As V3 Vpockets(1 To 6)
Dim As V3 Opockets(1 To 6)
Dim As V3 p(7)
setcircles(circ())
setup(balls())
setedges(edge())
DrawImage(edge(),p(),im,Mim)
setpockets(pockets(),Vpockets(),Opockets(),balls(1).radius)

Dim As Long mx,my,mb
Dim As String i
Dim As Long fps,msgflag,Vflag,Moveflag,lineflag,potflag,circflag
Dim As Long strikeflag,startflag
Dim As Single speed=10,block,lastspeed=10
Dim As V3 dirn=vct(0,0,0),temp,Qs,Catchvector,tmpcue
Dim As Long play=1,cpu
Dim As Long trackblack=100
Dim As _object o
Dim As Long ptb,catchptb,messageflag,cueflag,ptp,help=1
Dim As Long numyellow=7,numred=7
Dim As String s
Dim As msg message,test:test.s="PLAYER":test.c=redball
Dim As Long scoreRED,scoreYellow
Dim As v3 cueball,pass,active
Redim As kick w(0)
Dim As kick w2
Windowtitle "FreeBASIC Version " &__fb_version__
Setmouse ,,0
Do
    Getmouse mx,my,,mb
    i=Inkey
    potflag=0
    checkPOTS(balls(),pockets(),Opockets(),potflag,trackblack)
    Select Case potflag
    Case 1'cue
        If cpu=1 Then scorered+=1:potred=1:potyellow=0
        If cpu=0 Then scoreyellow+=1:potyellow=1:potred=0
        cueflag=1:help=1:circ(6).col=Rgb(0,0,50)
        If cpu =1 Then play=1
    Case 2 'yellow
        Static As Long y:w2.pnum=0
        Dim As Long rad=balls(1).radius/2
        orb(.03*xres,yres/10+2*rad*y,rad,Rgb(200,200,0),im)
        y=y+1:help=1:circ(6).col=Rgb(0,0,50)
        numyellow=numyellow-1
        If cpu=0 And cueflag=0 Then 
            scoreyellow+=1:potred=0:potyellow=1
        End If
        If cpu=1 And cueflag=0 Then
            If potred<>1 Then potyellow=1
            scoreYellow+=1
        End If
    Case 3 'red
        Static As Long r:w2.pnum=0
        Dim As Long rad=balls(1).radius/2
        orb(.06*xres,yres/10+2*rad*r,rad,Rgb(200,0,0),im)
        r=r+1:help=1:circ(6).col=Rgb(0,0,50)
        numred=numred-1
        If cpu=1 And cueflag=0 Then scorered+=1:potred=1:potyellow=0
        If cpu=0 And cueflag=0 Then
            If potyellow<>1 Then potred=1
            scoreRed+=1
        End If
    Case 4
        ptb=0
        If cpu=1 Then scorered+=1
        If cpu=0 Then scoreyellow+=1
    Case 13'black
        Dim As Long nr,ny
        Dim As String msg
        For n As Long=Lbound(balls) To Ubound(balls)
            If balls(n).colour=redball Then nr=nr+1
            If balls(n).colour=yellowball Then ny=ny+1
        Next n
        If nr=0 And cpu=0 Then scorered+=5:msg="Check scores"
        If ny=0 And cpu=1 Then scoreyellow+=5:msg="Check scores"
        If ny And cpu Then msg="Player wins"
        If nr And cpu=0 Then msg="Computer wins"
        show()
        Draw String (.15*xres,yres/2),"Game over -- " &msg,,fin
        Exit Do 
    Case Else
    End Select
    
    Var cb=checkVELOCITY(balls())
    
    If cb=0 Then 
        If Instr(message.s,"Red") Or Instr(message.s,"Seek") And cpu=1 Then  scorered+=1
        If Instr(message.s,"Yellow") Or Instr(message.s,"Seek")  And cpu=0 Then  scoreyellow+=1
        If Instr(message.s,"Black") And  cpu=1 And numyellow>0 Then  scorered+=1
        If Instr(message.s,"Black") And  cpu=0 And numred>0 Then  scoreyellow+=1
        s="":catchptb=0
        message.s=Lcase(message.s)
    End If
    If cb=0  Then Moveflag=0 Else Moveflag=1
    If cb=0 And cueflag=1 Then cueflag=0:respot(balls())
    
    If cpu=1 Then
        If  message.s="red ball" Or message.s="black ball" Then 
            strikeflag=1
            startflag=0
            play=1
            potyellow=0:potred=1
            w2.pnum=0
        End If
        message.s=""
    End If
    
    If cpu=0 Then
        If  message.s="yellow ball" Or message.s="black ball" Then  play=0
        message.s=""
    End If
    
    If play =1  Then 
        
        If cpu=0 Then
            If cb<>0 Then
                If Len(s)=0 Then message.s="Seek":message.c=redball Else message.s=""
                If Len(s)<> 0 Then
                    If Mid(s,6,1)<>"1" Then message.s="Yellow ball":message.c=yellowball
                    If Mid(s,6,1)="0" Then message.s="Black ball":message.c=Rgb(100,100,100)
                End If    
            End If 
        End If
        
        If cpu=1 Then
            If cb<>0 Then
                If Len(s)=0 Then message.s="Seek":message.c=yellowball Else message.s=""
                If Len(s)<>0 Then
                    If Mid(s,6,1)<>"8" Then message.s="Red ball":message.c=redball
                    If Mid(s,6,1)="0" Then message.s="Black ball":message.c=Rgb(100,100,100)
                End If
            End If 
        End If
        player()
    End If
    If cueflag=0 Then
        If play=0 Or potyellow=1 And cb=0 Then
            potyellow=0
            cpu=1
            Sleep 500
            compute()
        End If
    End If
Loop Until I=Chr(27)
Sleep
Imagedestroy im
For n As Long=1 To Ubound(balls)
    Imagedestroy balls(n).i
Next n
Imagedestroy Mim

 
sancho2
Posts: 547
Joined: May 17, 2015 6:41

Re: Pool 32/64 bit update.

Post by sancho2 »

This is a really nice game. The computer is a crack shot. I haven't beaten it yet.
I recommend a 'new game' button would be nice so you don't have to restart it after each game.
What is the thing labeled 'helper'?
Also, the game stops immediatly when the 8 ball drops, but there could still be a scratch on that shot if the white drops. So the game should run until the balls stop rolling.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Pool 32/64 bit update.

Post by dodicat »

Thanks for the comments sancho2.
The helper circle shows possible potting angles, if a clean pot is available.
Just align the target circle with a blue circle or the target line through a blue circle.
There is no help on the final black ball.
leopardpm
Posts: 1795
Joined: Feb 28, 2009 20:58

Re: Pool 32/64 bit update.

Post by leopardpm »

I love playing pool - but the computer is cheating, dang it! great game!
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: Pool 32/64 bit update.

Post by Tourist Trap »

leopardpm wrote:I love playing pool - but the computer is cheating, dang it! great game!
I can't wait for testing this! Wooots a dodicat studios production!!
sancho2
Posts: 547
Joined: May 17, 2015 6:41

Re: Pool 32/64 bit update.

Post by sancho2 »

So far the closest I can get is losing 15 to 13. I had his ball trapped and I snookered him until he finally exploded his ball out. It was 15 to 13 but I still had at least 6 balls on the table.
leopardpm
Posts: 1795
Joined: Feb 28, 2009 20:58

Re: Pool 32/64 bit update.

Post by leopardpm »

that is much closer to winning thn I have gotten so far... you ARE the pool master, Sancho!
BasicCoder2
Posts: 3906
Joined: Jan 01, 2009 7:03
Location: Australia

Re: Pool 32/64 bit update.

Post by BasicCoder2 »

The user interface I found nice to use,
http://www.gamesloon.com/free-sports-12 ... 30356.html
.
sancho2
Posts: 547
Joined: May 17, 2015 6:41

Re: Pool 32/64 bit update.

Post by sancho2 »

I beat it 13 to 11. However the computer sank the eight. I used that same strategy to block one of his balls and make him keep scratching.
Roland Chastain
Posts: 1002
Joined: Nov 24, 2011 19:49
Location: France
Contact:

Re: Pool 32/64 bit update.

Post by Roland Chastain »

Hello! Really beautiful program. One of the most beautiful achievements I know in FreeBASIC language.

When I start the application (under Windows 10), there is a black window which appears briefly. Yet I compiled with the option "-s gui". After that the welcome screen is created but in minimized state. No time to dive into the code. Just seen a "Cls" which can be removed I believe :

Code: Select all

#macro show()
MoveScreenByMouse
Screenlock
'Cls
@dodicat

I would like to make a package of your game and put a copy of it on my web site or on FB Portal. I hope you will not mind.

I noticed that you use (at the end of the welcome screen) the verb "to commence". I didn't know that it could be used in english. :)
paul doe
Moderator
Posts: 1733
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Pool 32/64 bit update.

Post by paul doe »

Bwahahaha the AI is merciless! I did one shot (by accident) and it completely destroyed me hahaha!

Very nice work, indeed!
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Pool 32/64 bit update.

Post by dodicat »

Hi Roland.
Please use the pool code as you wish.
Seems OK here with -s gui switch.
Commence, begin , start .. Like French, the English language has many choices.
After all, it is made up of French, German, Latin, Gaelic (tiny amount) and many other inputs.

Thanks for testing paul doe.
paul doe
Moderator
Posts: 1733
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Pool 32/64 bit update.

Post by paul doe »

dodicat wrote:Thanks for testing paul doe.
My pleasure. Reminded me of Lunar Ball. I played that one a lot with my friends when I was a kid. Good times =D
deltarho[1859]
Posts: 4308
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: Pool 32/64 bit update.

Post by deltarho[1859] »

I have just finished an extension to my random passkey encryption which now includes hashing the encrypted data and signing the hash all bundled into a single file for sending over the world wide wait.

I needed to do something completely different. I never have been one for games on a PC but thought I'd have a look to see what dodicat has been up to. I have just spent an hour and a half being thrashed at pool by a computer.

I have had a word with my anti-virus program to let a virus in. I am immune to digital flu but my PC is not so it might give me an edge next time that I play. <smile>

Excellent work, dodicat. You have gotten me into games!
srvaldez
Posts: 3379
Joined: Sep 25, 2005 21:54

Re: Pool 32/64 bit update.

Post by srvaldez »

well done dodicat :-)
works OK on my Mac
Image
a couple of changes would make the game even better
1: instead of dragging the cue have the cue move with the mouse movement
2: instead of a speed bar have the mouse pointer behave as that of a pinball launcher, you aim the cue, click-n-drag back then release the mouse to shoot, depending on how far you drag-back the mouse the stronger the hit.
Post Reply