type vec2
x as float
y as float
endtype
type masterNode
tl as vec2 `top left
br as vec2 `bottom right
m as dword `location in memory
endtype
type unit
p as vec2 `position
lp as vec2 `last position
d as vec2 `direction
ang as float
c as dword `color
node as dword `address of the current node
endtype
d3d_init
global ret as vec2
global dim unit(0) as unit
global unitnum as dword
global dim off(1,1) as vec2
off(0,0).x=-1 `0
off(0,0).y=-1
off(0,1).x= 1 `4
off(0,1).y=-1
off(1,0).x=-1 `8
off(1,0).y= 1
off(1,1).x= 1 `12
off(1,1).y= 1
Global M as masterNode `master node. This node is the largest node, and contains
`all other subnodes.
M.tl.x=40
M.tl.y=20
M.br.x=screen width()-100
M.br.y=screen height()-100
`initialize the largest node
create_Mnode()
mouse=0
sync on
sync rate 0
do
cls
d3d_batch_set_line2d 100000
d3d_batch_set_dot2d 100000
if mouseclick()=1 and mouse=0
add_unit(mousex(),mousey(),rgb(rnd(255),rnd(255),rnd(255)))
mouse=1
ENDIF
if mouseclick()=2 and mouse=0
mouse=1
q as dword
q=getNode(M.m,mousex(),mousey())
if q>0 and q<>M.m then cleanNode(peek dword(q+16))
endif
if spacekey()=1
for n=0 to 3
add_unit(normPoint()*30+mousex(),normPoint()*30+mousey(),rgb(rnd(255),rnd(255),rnd(255)))
next n
endif
for a=1 to unitnum
unit(a).ang=wrapvalue(unit(a).ang+rnd(100)/25.0-2.0)
moveObj(a,unit(a).p.x+cos(unit(a).ang),unit(a).p.y+sin(unit(a).ang))
next
if mouseclick()=0 then mouse=0
print "contains(M.m)="+str$(contains(M.m))
print screen fps()
draw_all()
d3d_batch_draw_line2d 1
d3d_batch_draw_dot2d 1
sync
LOOP
//Draws everything.
function draw_all()
color as dword
color=rgb(0,0,255)
d3d_batch_add_line2d M.br.x,M.tl.y,M.br.x,M.br.y,color
d3d_batch_add_line2d M.tl.x,M.br.y,M.br.x,M.br.y,color
d3d_batch_add_line2d M.tl.x,M.tl.y,M.tl.x,M.br.y,color
d3d_batch_add_line2d M.tl.x,M.tl.y,M.br.x,M.tl.y,color
draw_node(M.m,color)
ENDFUNCTION
function moveObj(obj as integer,x as float, y as float)
unit(obj).lp=unit(obj).p
unit(obj).p.x=x
unit(obj).p.y=y
if unit(obj).p.x<M.tl.x then unit(obj).p.x=M.br.x `wraparound
if unit(obj).p.x>M.br.x then unit(obj).p.x=M.tl.x
if unit(obj).p.y<M.tl.y then unit(obj).p.y=M.br.y `wraparound
if unit(obj).p.y>M.br.y then unit(obj).p.y=M.tl.y
Q_handle_move(obj)
endfunction
function Q_handle_move(obj as integer)
`this function will handle unit obj moving from position unit(obj).lp to unit(obj).p, assuming
`that the object is in the node it was in at unit(obj).lp
if unit(obj).node=M.m then exitfunction `don't mess with teh master!!!
if isInNode(unit(obj).node,unit(obj).p.x,unit(obj).p.y)=1
exitfunction
endif
`Alright, Here, we have an obj that has moved from its node (gasp!), time to remove its info
`from its last node, and add its info to the new one.
poke dword unit(obj).node+20,0
cleanNode(peek dword(unit(obj).node+16)) `may leave its super all BLAGH.
unit(obj).node=0 `out with the old.
add_unit_to_quadnode(getNode(M.m,unit(obj).p.x,unit(obj).p.y),obj) `in with the new.
endfunction
function isInNode(nodeAddress as dword, x as float, y as float) `check if x and y are bounded by node nodeAddress
if nodeAddress>0
qx#=peek float(nodeAddress+24)
qy#=peek float(nodeAddress+28)
w#=peek float(nodeAddress+32)
h#=peek float(nodeAddress+36)
if absolute(x-qx#)<=w# and absolute(y-qy#)<=h# then exitfunction 1
endif
endfunction 0
function absolute(n as float)
a#=n*sign(n)
endfunction a#
function draw_node(nodeAddress as dword,color as dword) `draws a node and all of its subnodes
if nodeAddress>0 `is a valid node
if peek dword(nodeAddress)>0 `has subnodes
x#=peek float(nodeAddress+24)
y#=peek float(nodeAddress+28)
w#=peek float(nodeAddress+32)
h#=peek float(nodeAddress+36)
d3d_batch_add_line2d x#,y#-h#,x#,y#+h#,color
d3d_batch_add_line2d x#-w#,y#,x#+w#,y#,color
for n=0 to 3
draw_node(peek dword(nodeAddress+n*4),color)
NEXT
else
o as dword
o =peek dword(nodeAddress+20)
if o>0 then d3d_batch_add_dot2d unit(o).p.x,unit(o).p.y,unit(o).c
endif
ENDIF
endfunction
function getNode(nodeAddress as dword, x as float, y as float) `returns the highest order subnode at (x,y)
if peek dword(nodeAddress)>0
centx as float
centy as float
centx=peek float(nodeAddress+24)
centy=peek float(nodeAddress+28)
x2=sign(x-centx)
y2=sign(y-centy)
if x2=0 then x2=1
if y2=0 then y2=1
if x2=-1 then x2=0
if y2=-1 then y2=0
exitfunction getNode(peek dword(nodeAddress+x2*8+y2*4),x,y)
else
exitfunction nodeAddress
endif
endfunction 0
function add_unit(x as float, y as float, color as dword) `add a unit to the array and the quadtree
array insert at bottom unit()
inc unitnum,1
unit(unitnum).p.x=x
unit(unitnum).p.y=y
unit(unitnum).lp=unit(unitnum).p
unit(unitnum).d.x=0
unit(unitnum).d.y=1
unit(unitnum).c=color
add_unit_to_quadnode(getNode(M.m,x,y),unitnum)
endfunction
function cleanNode(nodeAddress as dword)
if nodeAddress>0 and peek dword(nodeAddress)>0 `if it's not a node, ignore it. If it has no subnodes, ignore it. An empty node is a clean node.
r=contains(nodeAddress)
for n=0 to 3
cleanNode(peek dword(nodeAddress+n*4))
NEXT
if r=0 `no objects? Then the subnodes are doing NOTHING! LAZY SUBNODES WTF GTFO
delete_subnodes(nodeAddress)
exitfunction
endif
if r=1 `if there's one object... kill teh clutter, and bump that sucker up from its node.
obj as dword
for n=0 to 3
obj=peek dword(peek dword(nodeAddress+n*4)+20)
if obj>0 then goto skip
next n
skip:
delete_subnodes(nodeAddress)
add_unit_to_quadnode(nodeAddress,obj)
exitfunction
endif
`more than one object? That's OK, because all the subnodes have been cleaned (at the top o' teh function).
endif
ENDFUNCTION
function contains(nodeAddress as dword) ` return the number of objects contained in the node and its subnodes.
ret as dword
if peek dword(nodeAddress)>0
ret=0
for n=0 to 3
ret=ret+contains(peek dword(nodeAddress+n*4))
NEXT
exitfunction ret
else
ret=peek dword(nodeAddress+20)
if ret>0 then exitfunction 1
exitfunction 0
endif
ENDFUNCTION 0
function add_unit_to_quadnode(nodeAddress as dword, obj as dword) `add a unit to the node.
`handles if multiple objs are in the same node. Passing in nodeAddress might be a bit of a pain,
`but it allows one to pinpoint a node, instead of going aaall the way down from the master node
`every single recursive step. call with M.m in nodeAddress if you just want to add it to the quadtree.
if nodeAddress>0 and obj>0
if peek dword(nodeAddress+20)>0
obj2=peek dword(nodeAddress+20)
if unit(obj).p.x=unit(obj2).p.x and unit(obj).p.y=unit(obj2).p.y then exitfunction `if they're in the same position, forget it.
poke dword nodeAddress+20,0
fill_subnodes(nodeAddress)
add_unit_to_quadnode(getNode(nodeAddress,unit(obj2).p.x,unit(obj2).p.y),obj2)
add_unit_to_quadnode(getNode(nodeAddress,unit(obj).p.x,unit(obj).p.y),obj)
else
poke dword nodeAddress+20,obj
unit(obj).node=nodeAddress
endif
ENDIF
endfunction
function create_Mnode()
M.m=alloc zeroed(44)
poke float M.m+24,(M.tl.x+M.br.x)/2.0
poke float M.m+28,(M.tl.y+M.br.y)/2.0
poke float M.m+32,(M.br.x-M.tl.x)/2.0
poke float M.m+36,(M.br.y-M.tl.y)/2.0
endfunction
function create_node(super as dword, index as dword)
`index goes from 0 to 3
`four dwords for subnodes - 0 - 4 - 8 - 12
`one dword for supernodes - 16
`one dword for stored info - 20
`center position x - 24
`center position y - 28
`half the width of the cell - 32
`half the height - 36
`node depth level - 40
mem as dword
mem=alloc zeroed(44)
poke dword super+4*index,mem
poke dword mem+16,super
w#=peek float(super+32)/2
h#=peek float(super+36)/2
poke float mem+24,peek float(super+24)+w#*off(index).x
poke float mem+28,peek float(super+28)+h#*off(index).y
poke float mem+32,w#
poke float mem+36,h#
poke dword mem+40,peek dword(super+40)+1 `IE : |3|3|_2|_2|_2|_______1| <-bintree w/ depth level, 0 would be the whole thing.
endfunction
function delete_subnodes(nodeAddress as dword)
if nodeAddress>0 and peek dword(nodeAddress)>0
for n=0 to 3
delete_subnodes(peek dword(nodeAddress+n*4))
free peek dword(nodeAddress+n*4)
poke dword nodeAddress+n*4,0 `dissociate pointers
next
endif
endfunction
function fill_subnodes(nodeAddress as dword)
g as dword
g=peek dword(nodeAddress+20)
poke dword nodeAddress+20,0
for n=0 to 3
create_node(nodeAddress,n)
NEXT
if g>0
add_unit_to_quadnode(getNode(nodeAddress,unit(g).p.x,unit(g).p.y),g)
endif
ENDFUNCTION
function sign(a as float)
if a=0 then exitfunction 0
if a<0 then exitfunction -1
endfunction 1
//these two functions are just fancy ways to return a random point
//on the real number line, that probably lies close to 0, but could be anywhere from
//-infinity to infinity (but likely close to the origin)
function normPoint()
`returns a value whose probability of being between any two values is the same as the area under the normal distribution inbetween those two values.
p#=(rnd(999997)+1)/999999.0
r#=SNormInv(p#)
endfunction r#
Function SNormInv(p as float) `estimates the inverse of the sum of the normal distribution. Fun!
q as float
r as float
A1 as float
A2 as float
A3 as float
A4 as float
A5 as float
A6 as float
B1 as float
B2 as float
B3 as float
B4 as float
B5 as float
C1 as float
C2 as float
C3 as float
C4 as float
C5 as float
C6 as float
D1 as float
D2 as float
D3 as float
D4 as float
P_LOW as float
P_HIGH as float
`Coefficients in rational approximations.
A1= -39.69683
A2= 220.9461
A3= -275.9285
A4= 138.3578
A5= -30.66480
A6= 2.506628
B1= -54.47610
B2= 161.5858
B3= -155.6990
B4= 66.80131
B5= -13.28068
C1= -0.007785
C2= -0.322396
C3= -2.400758
C4= -2.549733
C5= 4.374664
C6= 2.938164
D1= 0.007784696
D2= 0.3224671
D3= 2.445134
D4= 3.754409
P_LOW= 0.02425
P_HIGH=1-P_LOW
if p>0 and p<P_LOW
`Rational approximation for lower region.
q = Sqrt(-2*Log(p))
ret#=(((((C1*q+C2)*q+C3)*q+C4)*q+C5)*q+C6)/((((D1*q+D2)*q+D3)*q+D4)*q+1)
exitfunction ret#
endif
If p>=P_LOW and p<=P_HIGH
`Rational approximation for central region.
q=p-0.5
r=q*q
ret#=(((((A1*r+A2)*r+A3)*r+A4)*r+A5)*r+A6)*q/(((((B1*r+B2)*r+B3)*r+B4)*r+B5)*r+1)
exitfunction ret#
endif
if p> _HIGH and p<1
`Rational approximation for upper region.
q = Sqrt(-2*Log(1-p))
ret#=-(((((C1*q+C2)*q+C3)*q+C4)*q+C5)*q+C6)/((((D1*q+D2)*q+D3)*q+D4)*q+1)
exitfunction ret#
endif
endfunction 0.0
Basically... A quadtree is used to separate space, and organize objects. It's used a lot in situations where points are clustered together.
I'm feeling especially lazy right now, and honestly it's better to write your own quadtree code than to learn how I do it, so I'll drop this code here with admittedly little information for you.You can press the spacebar or click to add points. if it goes too fast, limit the framerate. There's one bug with the code where you'll sometimes see subtrees with nothing in them - That's bad.
[edit]
also:
A quadtree is good for grouped points. In this demo, every point eventually tends to spread out, and become homogeneously distributed across the screen. That doesn't exercise the benefits of a quadtree. if you comment out the code responsible for moving the points, you can see the grouping much better (like so
type vec2
x as float
y as float
endtype
type masterNode
tl as vec2 `top left
br as vec2 `bottom right
m as dword `location in memory
endtype
type unit
p as vec2 `position
lp as vec2 `last position
d as vec2 `direction
ang as float
c as dword `color
node as dword `address of the current node
endtype
d3d_init
global ret as vec2
global dim unit(0) as unit
global unitnum as dword
global dim off(1,1) as vec2
off(0,0).x=-1 `0
off(0,0).y=-1
off(0,1).x= 1 `4
off(0,1).y=-1
off(1,0).x=-1 `8
off(1,0).y= 1
off(1,1).x= 1 `12
off(1,1).y= 1
Global M as masterNode `master node. This node is the largest node, and contains
`all other subnodes.
M.tl.x=40
M.tl.y=20
M.br.x=screen width()-100
M.br.y=screen height()-100
`initialize the largest node
create_Mnode()
mouse=0
sync on
sync rate 0
do
cls
d3d_batch_set_line2d 100000
d3d_batch_set_dot2d 100000
if mouseclick()=1 and mouse=0
add_unit(mousex(),mousey(),rgb(rnd(255),rnd(255),rnd(255)))
mouse=1
ENDIF
if mouseclick()=2 and mouse=0
mouse=1
q as dword
q=getNode(M.m,mousex(),mousey())
if q>0 and q<>M.m then cleanNode(peek dword(q+16))
endif
if spacekey()=1
for n=0 to 3
add_unit(normPoint()*30+mousex(),normPoint()*30+mousey(),rgb(rnd(255),rnd(255),rnd(255)))
next n
endif
if mouseclick()=0 then mouse=0
print "contains(M.m)="+str$(contains(M.m))
print screen fps()
draw_all()
d3d_batch_draw_line2d 1
d3d_batch_draw_dot2d 1
sync
LOOP
//Draws everything.
function draw_all()
color as dword
color=rgb(0,0,255)
d3d_batch_add_line2d M.br.x,M.tl.y,M.br.x,M.br.y,color
d3d_batch_add_line2d M.tl.x,M.br.y,M.br.x,M.br.y,color
d3d_batch_add_line2d M.tl.x,M.tl.y,M.tl.x,M.br.y,color
d3d_batch_add_line2d M.tl.x,M.tl.y,M.br.x,M.tl.y,color
draw_node(M.m,color)
ENDFUNCTION
function moveObj(obj as integer,x as float, y as float)
unit(obj).lp=unit(obj).p
unit(obj).p.x=x
unit(obj).p.y=y
if unit(obj).p.x<M.tl.x then unit(obj).p.x=M.br.x `wraparound
if unit(obj).p.x>M.br.x then unit(obj).p.x=M.tl.x
if unit(obj).p.y<M.tl.y then unit(obj).p.y=M.br.y `wraparound
if unit(obj).p.y>M.br.y then unit(obj).p.y=M.tl.y
Q_handle_move(obj)
endfunction
function Q_handle_move(obj as integer)
`this function will handle unit obj moving from position unit(obj).lp to unit(obj).p, assuming
`that the object is in the node it was in at unit(obj).lp
if unit(obj).node=M.m then exitfunction `don't mess with teh master!!!
if isInNode(unit(obj).node,unit(obj).p.x,unit(obj).p.y)=1
exitfunction
endif
`Alright, Here, we have an obj that has moved from its node (gasp!), time to remove its info
`from its last node, and add its info to the new one.
poke dword unit(obj).node+20,0
cleanNode(peek dword(unit(obj).node+16)) `may leave its super all BLAGH.
unit(obj).node=0 `out with the old.
add_unit_to_quadnode(getNode(M.m,unit(obj).p.x,unit(obj).p.y),obj) `in with the new.
endfunction
function isInNode(nodeAddress as dword, x as float, y as float) `check if x and y are bounded by node nodeAddress
if nodeAddress>0
qx#=peek float(nodeAddress+24)
qy#=peek float(nodeAddress+28)
w#=peek float(nodeAddress+32)
h#=peek float(nodeAddress+36)
if absolute(x-qx#)<=w# and absolute(y-qy#)<=h# then exitfunction 1
endif
endfunction 0
function absolute(n as float)
a#=n*sign(n)
endfunction a#
function draw_node(nodeAddress as dword,color as dword) `draws a node and all of its subnodes
if nodeAddress>0 `is a valid node
if peek dword(nodeAddress)>0 `has subnodes
x#=peek float(nodeAddress+24)
y#=peek float(nodeAddress+28)
w#=peek float(nodeAddress+32)
h#=peek float(nodeAddress+36)
d3d_batch_add_line2d x#,y#-h#,x#,y#+h#,color
d3d_batch_add_line2d x#-w#,y#,x#+w#,y#,color
for n=0 to 3
draw_node(peek dword(nodeAddress+n*4),color)
NEXT
else
o as dword
o =peek dword(nodeAddress+20)
if o>0 then d3d_batch_add_dot2d unit(o).p.x,unit(o).p.y,unit(o).c
endif
ENDIF
endfunction
function getNode(nodeAddress as dword, x as float, y as float) `returns the highest order subnode at (x,y)
if peek dword(nodeAddress)>0
centx as float
centy as float
centx=peek float(nodeAddress+24)
centy=peek float(nodeAddress+28)
x2=sign(x-centx)
y2=sign(y-centy)
if x2=0 then x2=1
if y2=0 then y2=1
if x2=-1 then x2=0
if y2=-1 then y2=0
exitfunction getNode(peek dword(nodeAddress+x2*8+y2*4),x,y)
else
exitfunction nodeAddress
endif
endfunction 0
function add_unit(x as float, y as float, color as dword) `add a unit to the array and the quadtree
array insert at bottom unit()
inc unitnum,1
unit(unitnum).p.x=x
unit(unitnum).p.y=y
unit(unitnum).lp=unit(unitnum).p
unit(unitnum).d.x=0
unit(unitnum).d.y=1
unit(unitnum).c=color
add_unit_to_quadnode(getNode(M.m,x,y),unitnum)
endfunction
function cleanNode(nodeAddress as dword)
if nodeAddress>0 and peek dword(nodeAddress)>0 `if it's not a node, ignore it. If it has no subnodes, ignore it. An empty node is a clean node.
r=contains(nodeAddress)
for n=0 to 3
cleanNode(peek dword(nodeAddress+n*4))
NEXT
if r=0 `no objects? Then the subnodes are doing NOTHING! LAZY SUBNODES WTF GTFO
delete_subnodes(nodeAddress)
exitfunction
endif
if r=1 `if there's one object... kill teh clutter, and bump that sucker up from its node.
obj as dword
for n=0 to 3
obj=peek dword(peek dword(nodeAddress+n*4)+20)
if obj>0 then goto skip
next n
skip:
delete_subnodes(nodeAddress)
add_unit_to_quadnode(nodeAddress,obj)
exitfunction
endif
`more than one object? That's OK, because all the subnodes have been cleaned (at the top o' teh function).
endif
ENDFUNCTION
function contains(nodeAddress as dword) ` return the number of objects contained in the node and its subnodes.
ret as dword
if peek dword(nodeAddress)>0
ret=0
for n=0 to 3
ret=ret+contains(peek dword(nodeAddress+n*4))
NEXT
exitfunction ret
else
ret=peek dword(nodeAddress+20)
if ret>0 then exitfunction 1
exitfunction 0
endif
ENDFUNCTION 0
function add_unit_to_quadnode(nodeAddress as dword, obj as dword) `add a unit to the node.
`handles if multiple objs are in the same node. Passing in nodeAddress might be a bit of a pain,
`but it allows one to pinpoint a node, instead of going aaall the way down from the master node
`every single recursive step. call with M.m in nodeAddress if you just want to add it to the quadtree.
if nodeAddress>0 and obj>0
if peek dword(nodeAddress+20)>0
obj2=peek dword(nodeAddress+20)
if unit(obj).p.x=unit(obj2).p.x and unit(obj).p.y=unit(obj2).p.y then exitfunction `if they're in the same position, forget it.
poke dword nodeAddress+20,0
fill_subnodes(nodeAddress)
add_unit_to_quadnode(getNode(nodeAddress,unit(obj2).p.x,unit(obj2).p.y),obj2)
add_unit_to_quadnode(getNode(nodeAddress,unit(obj).p.x,unit(obj).p.y),obj)
else
poke dword nodeAddress+20,obj
unit(obj).node=nodeAddress
endif
ENDIF
endfunction
function create_Mnode()
M.m=alloc zeroed(44)
poke float M.m+24,(M.tl.x+M.br.x)/2.0
poke float M.m+28,(M.tl.y+M.br.y)/2.0
poke float M.m+32,(M.br.x-M.tl.x)/2.0
poke float M.m+36,(M.br.y-M.tl.y)/2.0
endfunction
function create_node(super as dword, index as dword)
`index goes from 0 to 3
`four dwords for subnodes - 0 - 4 - 8 - 12
`one dword for supernodes - 16
`one dword for stored info - 20
`center position x - 24
`center position y - 28
`half the width of the cell - 32
`half the height - 36
`node depth level - 40
mem as dword
mem=alloc zeroed(44)
poke dword super+4*index,mem
poke dword mem+16,super
w#=peek float(super+32)/2
h#=peek float(super+36)/2
poke float mem+24,peek float(super+24)+w#*off(index).x
poke float mem+28,peek float(super+28)+h#*off(index).y
poke float mem+32,w#
poke float mem+36,h#
poke dword mem+40,peek dword(super+40)+1 `IE : |3|3|_2|_2|_2|_______1| <-bintree w/ depth level, 0 would be the whole thing.
endfunction
function delete_subnodes(nodeAddress as dword)
if nodeAddress>0 and peek dword(nodeAddress)>0
for n=0 to 3
delete_subnodes(peek dword(nodeAddress+n*4))
free peek dword(nodeAddress+n*4)
poke dword nodeAddress+n*4,0 `dissociate pointers
next
endif
endfunction
function fill_subnodes(nodeAddress as dword)
g as dword
g=peek dword(nodeAddress+20)
poke dword nodeAddress+20,0
for n=0 to 3
create_node(nodeAddress,n)
NEXT
if g>0
add_unit_to_quadnode(getNode(nodeAddress,unit(g).p.x,unit(g).p.y),g)
endif
ENDFUNCTION
function sign(a as float)
if a=0 then exitfunction 0
if a<0 then exitfunction -1
endfunction 1
//these two functions are just fancy ways to return a random point
//on the real number line, that probably lies close to 0, but could be anywhere from
//-infinity to infinity (but likely close to the origin)
function normPoint()
`returns a value whose probability of being between any two values is the same as the area under the normal distribution inbetween those two values.
p#=(rnd(999997)+1)/999999.0
r#=SNormInv(p#)
endfunction r#
Function SNormInv(p as float) `estimates the inverse of the sum of the normal distribution. Fun!
q as float
r as float
A1 as float
A2 as float
A3 as float
A4 as float
A5 as float
A6 as float
B1 as float
B2 as float
B3 as float
B4 as float
B5 as float
C1 as float
C2 as float
C3 as float
C4 as float
C5 as float
C6 as float
D1 as float
D2 as float
D3 as float
D4 as float
P_LOW as float
P_HIGH as float
`Coefficients in rational approximations.
A1= -39.69683
A2= 220.9461
A3= -275.9285
A4= 138.3578
A5= -30.66480
A6= 2.506628
B1= -54.47610
B2= 161.5858
B3= -155.6990
B4= 66.80131
B5= -13.28068
C1= -0.007785
C2= -0.322396
C3= -2.400758
C4= -2.549733
C5= 4.374664
C6= 2.938164
D1= 0.007784696
D2= 0.3224671
D3= 2.445134
D4= 3.754409
P_LOW= 0.02425
P_HIGH=1-P_LOW
if p>0 and p<P_LOW
`Rational approximation for lower region.
q = Sqrt(-2*Log(p))
ret#=(((((C1*q+C2)*q+C3)*q+C4)*q+C5)*q+C6)/((((D1*q+D2)*q+D3)*q+D4)*q+1)
exitfunction ret#
endif
If p>=P_LOW and p<=P_HIGH
`Rational approximation for central region.
q=p-0.5
r=q*q
ret#=(((((A1*r+A2)*r+A3)*r+A4)*r+A5)*r+A6)*q/(((((B1*r+B2)*r+B3)*r+B4)*r+B5)*r+1)
exitfunction ret#
endif
if p> _HIGH and p<1
`Rational approximation for upper region.
q = Sqrt(-2*Log(1-p))
ret#=-(((((C1*q+C2)*q+C3)*q+C4)*q+C5)*q+C6)/((((D1*q+D2)*q+D3)*q+D4)*q+1)
exitfunction ret#
endif
endfunction 0.0
[edit2]
also, this is kinda old code of mine. I'm just posting it because I figure other people could use it xD
That means I'm not immediately familiar with the code.

Why does blue text appear every time you are near?