Tutorial
Here is a basic tutorial to show you how to use
JetScript. It will be split into two parts. 1) Writing the script, and 2) Using DBPro to actually make use of the script.
Part 1: Writing your script
Scripts are really useful in games for many reasons. They can store data for levels, people, and in this case even perform simple functions. But when you think about it, how would you (with any language) store data for multiple things (well use people in this example)? Ofcourse! It's done using arrays!
JetScript has it's share of arrays, but are layed out differently than most languages. This is more like an array/UDT sorta thing, and is used into other scripts like LUA (check out Unity, by David T. It seems to be quite popular). These arrays are called
Tables.
So, how would you use those tables (for those who don't know)? Well, it's pretty simple, and very structured.
Let's take me for this example. I want to put down every detail about me in a table.
Data = {
Zotoaster = {
Name = Alastair;
Age = 1000;
favouriteColour = { r=0; g=128; b=250; }
}
}
That's me. That's all my information. That's my whole brain, on a table.
So let's look at what I did here. Well, the foundations of this is that elements within elements are stored between braces {}. The variable name is set using an equals sign, as you would expect.
So I started with my "Data" column. Inside that, I have more elements. One of them is about me, "Zotoaster". Within that, it has my name, age (young for my species), and favourite color (a sort of bright blue. Not really my favourite color in real life, but I often use it to make a sky colour in games. You should really try it). My favourite colour also has 3 elements. "r, g and b" (or red, green and blue).
All the actuall elements have to have a semi-colon ( ; ) after them. The actual braces dont.
So we have established that: Tables are arrays with named elements, and you can have infinite elements. Right? Cool.
Ok, I could go onto explaining how this works in DBPro, but I wont.
...
That will be explained in the second part.
Moving on from tables and chairs - We look at functions. Now I know most languages have functions, and in DBPro you can use them to to solve a few parameters and then spit out the value to use in a maths expression. Well, not because I'm nasty (which I am, believe me), you can't do that with this. I don't know whether to laugh or cry, because it affects me too... awww. Well yeah whatever, it is only a scripting language, so we don't want it doing all the work.
The functions are made pretty easily, and are then called by DBPro. You must first establish your
main() function, as this is automatically run when the script starts. This is basically what it should look like:
Very complicated script there.
Now, because I've been working on this for oh, like, a day, there's not an awful lot you can do inside the functions - but you can do enough to make them useful. For example, I want a function to return the distance between two points in 2D. I could a) Do it the easy, handy, quick way and do it in DBPro. Or b) Do it the harder, more annoying inconvinient way, by using a script, just to please me
Here is how I would go about doing it.
function distance(x1,y1,x2,y2){
return(sqrt(((x2-x1)^2)+((y2-y1)^2)));
}
That's it. Basic Pythagoras' Theorem. Us Greeks are such geniuses, aren't we Py'?
But that's not all. I have also added a feature never seen on the face of programming languages before -
IF STATEMENTS!
Not just any "if statement", but also nested ones (ones which are inside each other, like a nest. Like, ifs living insde other ifs (cannibalism)).
Here is a very good example to show the functionality of if statements:
function max(a,b){
if(a>b){
return(a);
}
if(b>a){
return(b);
}
}
Alright, now, some more insight of functions (and other things):
Everything is in it's own block (the bit between two {} ). I don't know what it's actually called, so I'll call it a clause for now. I think that makes sense. The function has a clause, and the if statements have a clause. You have to enclose everything in these clauses, and they do not require a semi-colon ( ; ) at the end of them.
However! commands do. You will have noticed the
return command in the functions up there. Like all other commands, it requires a ; at the end.
The purpose of the 'return' command, is to directly send it's contents to DBPro. DBPro reads them, and you can access them, and then do you you like with them. Use them in the 'text' command. Use them to set an object size. Use them to ask your crush out on Valentine's day (if you are clever enough to). Do what you like, I, personally, don't care.
Ok, part one over. Let's move onto the next section - using the scripts in DBPro.
Part 2: Using the scripts in DBPro
Well, before you even can use any scripts, they must be set up. Do this using the.
...function. (All functions start wit 'js', for 'JetScript')
Now, you have to load the script.
num=jsReadScript(script$)
-num = the number of the script (returns a variable, yeah)
-script$ = the file name of the script.
And yes, you can use multiple scripts here.
Alright, back to tables. If you want to load a table, there are but two ways.
a) Use the 'jsGetTable' function. Something like this (using the table we set up above):
table1$=jsGetTable(num,"data->zotoaster->name")
table2$=jsGetTable(num,"data->zotoaster->favouritecolour")
I did it twice, because you can get different results. Table1$ here will just become "Alastair". Table2$ however will be "r=0;g=128;b=250;" as I have selected the whole clause.
b) Send the data to DBPro directly.
This is what it looks like in the script:
return(data->zotoaster->name);
(and you don't use quotation marks)
Which leads me onto my next point -
Using the 'return' command (in the script)
When you call return in the script, it will of course sent it's contents to DBPro. This will result in two things:
1) If it doesn't include quotation marks and does include arrows ->, it will return the table data that you send.
2) It will just send it's parameter (if it's an equation is will solve it unless it's enclosed in quotation marks.
Reading that couldn't be easier:
data$ will then just equal what is sent to you.
And lastly, to use the functions:
Well basically, functions just include the 'return' command, but not have parameters. These of course need to be substituted in. The way to do that is to use the 'jsCallFunc()' function in DBPro. Something like this:
data$=jsCallFunc(num,"funcname(parameter1,parameter2, etc)")
That basically lets the script send it's contents, but it will replace any variables of the function with the parameters you send it
So that's the tour over. Everyone off the bus and give it a go yourselfs. I intend of updating it quite alot, so don't get too used to it...
Here is a basic script to test out:
'DataBase
database = {
name = "Alastair";
age = 1024;
col = { r=255; g=0; b=0; }
}
'Main
function main(){
}
function something(){
return(database->name);
}
function max(a,b){
if(a>b){
return(a);
}
if(b>a){
return(b);
}
}
And the code (with updated functions):
`JetScript Library
sync on : sync rate 60
set display mode 1440,900,32
jsStartScript()
`Read script
num=jsReadScript("scr1.txt")
`Main Loop
do
text 10,10,"Database->name - "+jsCallFunc(num,"something()")
text 10,30,"Which is higher, 10 or 11? - "+jsCallFunc(num,"max(10,11)")
sync
cls
loop
`Scripting
function jsStartScript()
dim jsData(0) as jsData
endfunction
function jsReadScript(scr$)
lines=fileLines(scr$)
open to read 1,scr$
for l=1 to lines
read string 1,temp$
if left$(remChar(temp$," "),2)<>"//" and mid$(remChar(temp$," "),1)<>"'"
ln$=ln$+temp$
endif
next l
close file 1
array insert at bottom jsData() : num=array count(jsData())
for c=1 to len(ln$)
cur$=mid$(ln$,c)
curr$=mid(ln$,c,2)
if onR=0
if curr$<>"/*" and curr$<>"*/"
ncmdline$=ncmdline$+cur$
endif
endif
ncmdline$=remCharExc(ncmdline$,chr$(34),"/")
if curr$="/*" then onR=1
if curr$="*/" then onR=0
next c
jsData(num).scr=ncmdline$
jsData(num).cblck=ncmdline$
jsCallFunc(num,"main()")
endfunction num
function jsGetTable(num,table$)
list$=remCharExc(jsScr(num),chr$(34)," ")
lastTok$=getToken(table$,"->",getTokenCount(table$,"->"))
for t=1 to getTokenCount(table$,"->")-1
curtok$=getToken(table$,"->",t)
newtok$=newtok$+curtok$+"=-"
next t
for t=1 to getTokenCount(newtok$,"-")
curtok$=getToken(newtok$,"-",t)
list$=getPar(list$,curtok$,"{","}")
for l=1 to stTokenCount(list$)
lsttok$=stGetToken(list$,l)
if lsttok$=lastTok$
exit
endif
next l
next t
for t=1 to stTokenCount(list$)
curtok$=stGetToken(list$,t)
if curtok$=lastTok$
if stGetToken(list$,t+2)="{"
ret$=getPar(list$,lastTok$+"=","{","}")
else
for l=t+2 to stTokenCount(list$)
cur$=stGetToken(list$,l)
if cur$=";" then exit
ret$=ret$+cur$
next l
endif
endif
next t
endfunction ret$
function jsReturn(num)
for t=1 to jsCommandCount(num)
com$=jsCommand(num,t)
comnm$=lower$(stGetToken(com$,1))
if comnm$="return"
val$=jsParameter(num,t,1)
endif
next t
if charCount(val$,"->") and charCount(val$,chr$(34))=0
val$=jsGetTable(num,val$)
endif
endfunction val$
function jsScr(num)
scr$=jsData(num).scr
endfunction scr$
function jsCommand(num,c)
coml$=jsCommandL(num,c)
comnm$=stGetToken(coml$,1)
for p=1 to jsParamCount(num,c)
curpar$=jsParameter(num,c,p)
outpar$=outpar$+curpar$+","
next p
outpar$=left$(outpar$,len(outpar$)-1)
com$=comnm$+"("+outpar$+")"
endfunction com$
function jsCommandCount(num)
count=getTokenCount(jsBlock(num),",")
endfunction count
function jsCommandL(num,c)
com$=remCharExc(getToken(jsBlock(num),",",c),chr$(34)," ")
endfunction com$
function jsParamCount(num,c)
count=getTokenCount(jsCommandL(num,c),",")
endfunction count
function jsParameter(num,c,p)
com$=jsCommandL(num,c)
comnm$=stGetToken(com$,1)
parlst$=getPar(com$,comnm$,"(",")")
curpar$=getToken(parlst$,",",p)
if isNum(mid$(curpar$,1)) or mid$(curpar$,1)="(" or left$(jsGetToken(curpar$,1),4)="func"
par$=jsSolveExp(curpar$)
else
par$=curpar$
endif
endfunction par$
function jsSolveBlock(num)
block$=jsBlock(num)
if charCount(block$,"{")>0
for t=1 to charCount(block$,"{")
jsSolveNest(num)
next t
endif
endfunction
function jsSolveNest(num)
block$=jsBlock(num)
tin$=jsGetNest(num)
in$=remCharExc(tin$,chr$(34)," ")
if charCount(in$,"{")>0
for t=1 to len(in$)
cur$=mid$(in$,t)
if cur$="{" then exit
slv$=slv$+cur$
next t
if stGetToken(slv$,1)="if"
data$=getPar(slv$,"if","(",")")
val1$=stGetToken(data$,1)
val2$=stGetToken(data$,3)
cond$=stGetToken(data$,2)
if cond$="="
if val1$=val2$ then out$=getPar(block$,slv$,"{","}")
endif
if cond$="!"
if val1$<>val2$ then out$=getPar(block$,slv$,"{","}")
endif
if cond$="<"
if val1$<val2$ then out$=getPar(block$,slv$,"{","}")
endif
if cond$=">"
if val1$>val2$ then out$=getPar(block$,slv$,"{","}")
endif
endif
for t=1 to len(block$)
cur$=mid$(block$,t)
if t<jsData(num).nestpos or t>jsData(num).nestpos+len(tin$)
ret$=ret$+cur$
else
inc addslv
if addslv=1 then ret$=ret$+out$
endif
next t
ret$=remCharExc(ret$,chr$(34)," ")
jsData(num).cblck=ret$
else
jsData(num).cblck=remCharExc(block$,chr$(34)," ")
endif
endfunction
function jsGetNest(num)
block$=jsBlock(num)
if charCount(block$,"{")>0
for t=1 to len(block$)
cur$=mid$(block$,t)
if cur$="{" then inc brace
if cur$="}" then dec brace
if brace>max then max=brace
next t
brace=0
for t=1 to len(block$)
cur$=mid$(block$,t)
if cur$="{" then inc brace
if cur$="}" then dec brace
if brace=max then pos=t+1 : exit
next t
for t=pos-2 to 1 step -1
cur$=mid$(block$,t)
if cur$="{" then stpos=t+1 : exit
if cur$="}" then stpos=t+1 : exit
if cur$=";" then stpos=t+1 : exit
next t
jsData(num).nestpos=stpos
for t=stpos to len(block$)
cur$=mid$(block$,t)
ret$=ret$+cur$
if cur$="}" then exit
next t
else
ret$=block$
endif
endfunction ret$
function jsCallFunc(num,func$)
tokcount=getTokenCount(func$,",")
funcname$=stGetToken(func$,1)
param$=left$(getPar(jsScr(num),funcname$,"(",")"),len(getPar(jsScr(num),funcname$,"(",")")))
send$=getPar(func$,funcname$,"(",")")
for t=1 to getTokenCount(send$,",")
nparam$=nparam$+getToken(param$,",",t)+"="+getToken(send$,",",t)+","
next t
for t=1 to getTokenCount(nparam$,",")
curtok$=getToken(nparam$,",",t)
callpar$=callpar$+getToken(curtok$,"=",1)+","
next t
funccall$="function "+funcname$+"("+left$(callpar$,len(callpar$)-1)+")"
jsSetPath(num,funccall$)
block$=getPar(jsScr(num),funccall$,"{","}")
for b=1 to stTokenCount(block$)
blktok$=stGetToken(block$,b)
for t=1 to getTokenCount(nparam$,",")
curtok$=getToken(nparam$,",",t)
curpar$=getToken(curtok$,"=",1) : curval$=getToken(curtok$,"=",2)
if blktok$=curpar$
block$=stReplaceToken(block$,curpar$,curval$)
endif
next t
next b
jsData(num).cblck=block$
jsSolveBlock(num)
return$=jsReturn(num)
endfunction return$
function jsSetPath(num,path$)
scr$=jsScr(num)
for t=1 to getTokenCount(path$,"->")
curtok$=getToken(path$,"->",t)
scr$=getPar(scr$,curtok$,"{","}")
next t
jsData(num).path=path$
jsData(num).cblck=scr$
endfunction
function jsPath(num)
path$=jsData(num).path
endfunction path$
function jsBlock(num)
cblck$=jsData(num).cblck
endfunction cblck$
function jsGetToken(st$,t)
curtok$=stGetToken(st$,t) : tok$=curtok$
if t<sttokencount(st$) then nexttok$=stGetToken(st$,t+1)
if t>1 then prevtok$=stGetToken(st$,t-1)
if isLetter(left$(curtok$,1)) and nexttok$="("
tok$="func"+"-"+curtok$
endif
if curtok$="("
tok$="bropen"
endif
if curtok$=")"
tok$="brclose"
endif
if curtok$=";"
tok$="end"
endif
if nexttok$=","
if curtok$<>")" and curtok$<>"(" and curtok$<>","
tok$=curtok$
endif
endif
endfunction tok$
`Scripting - Maths Evaluator
function jsSolveExp(st$)
st$="("+st$+")"
ret$=st$
for t=1 to charCount(st$,"(")
ret$=jsSolveInner(ret$)
next t
endfunction ret$
function jsSolveInner(st$)
if mid$(st$,1)="(" then st$=" "+st$
if isNum(mid$(st$,1)) or mid$(st$,1)="-" then st$="0"+st$
for t=1 to len(st$)
cur$=mid$(st$,t)
if cur$="(" then inc brk
if cur$=")" then dec brk
if brk>max then inc max
next t
brk=0
for t=1 to stTokenCount(st$)
curtok$=stGetToken(st$,t)
if curtok$="(" then inc brk
if curtok$=")" then dec brk
if brk=max then nesttok=t : exit
next t
brk=0
prevtok$=stGetToken(st$,nesttok-1)
for t=nesttok+1 to stTokenCount(st$)
curtok$=stGetToken(st$,t)
if curtok$=")" then exit
nest$=nest$+curtok$
next t
nestsolve$=jsSolveExpS(nest$)
tret$=nestsolve$
if prevtok$="sin" then tret$=str$(sin(val(nestsolve$))) : hasfunc=1
if prevtok$="cos" then tret$=str$(cos(val(nestsolve$))) : hasfunc=1
if prevtok$="tan" then tret$=str$(tan(val(nestsolve$))) : hasfunc=1
if prevtok$="asin" then tret$=str$(asin(val(nestsolve$))) : hasfunc=1
if prevtok$="acos" then tret$=str$(acos(val(nestsolve$))) : hasfunc=1
if prevtok$="atan" then tret$=str$(atan(val(nestsolve$))) : hasfunc=1
if prevtok$="sqrt" then tret$=str$(sqrt(val(nestsolve$))) : hasfunc=1
for t=1 to stTokenCount(st$)
if t<(nesttok-hasfunc) or t>nesttok+stTokenCount(nest$)+1
ret$=ret$+stGetToken(st$,t)
else
inc addslv
if addslv=1 then ret$=ret$+tret$
endif
next t
for t=1 to len(ret$)
cur$=mid$(ret$,t)
if cur$="(" then inc brk
if cur$=")" then dec brk
if brk<0 then exit
out$=out$+cur$
next t
endfunction out$
function jsSolveExpS(string$)
string$="0"+string$
lasttok$="+"
for t=1 to stTokenCount(string$)
if isOther(stGetToken(string$,t)) then lasttok$=stGetToken(string$,t)
if isNum(stGetToken(string$,t))
if lasttok$="+" then ret#=ret#+val(stGetToken(string$,t))
if lasttok$="-" then ret#=ret#-val(stGetToken(string$,t))
if lasttok$="*" then ret#=ret#*val(stGetToken(string$,t))
if lasttok$="/" then ret#=ret#/val(stGetToken(string$,t))
if lasttok$="^" then ret#=ret#^val(stGetToken(string$,t))
endif
next t
ret$=str$(ret#)
endfunction ret$
`Script Data
type jsData
scr as string
cblck as string
path as string
func as string
nestpos as integer
nestlen as integer
endtype
`Functions - String
function getPar(ntext$,check$,o$,c$)
text$=" "+open$+ntext$+close$
local brace as integer : brace=1
for t=1 to len(text$)
com$=mid(text$,t,len(check$))
if com$=check$
for c=(t+len(check$)+1) to len(text$)
cur$=mid$(text$,c)
if cur$=o$ then inc brace
if cur$=c$ then dec brace
ret$=ret$+cur$
if brace<=0
exit
endif
next c
endif
next t
ret$=left$(ret$,len(ret$)-1)
endfunction ret$
function searchStr(st$,sh$)
for t=1 to len(st$)
cur$=mid(st$,t,len(sh$))
if cur$=sh$ then pos=t
next t
endfunction pos
function charCount(st$,ch$)
for t=1 to len(st$)
if mid(st$,t,len(ch$))=ch$ then inc count
next t
endfunction count
function mid(st$,p,ln)
l=ln-1
for s=p to p+l
new$=new$+mid$(st$,s)
next s
endfunction new$
function stReplaceToken(st$,toka$,tokb$)
for t=1 to stTokenCount(st$)
curtok$=stGetToken(st$,t)
if curtok$=toka$
ret$=ret$+tokb$
else
ret$=ret$+curtok$
endif
next t
endfunction ret$
function stTokenCount(st$)
for c=1 to len(st$)
oldtok=tok
cur$=mid$(st$,c)
if isLetter(cur$) then tok=1
if isNum(cur$) then tok=1
if isOther(cur$) then inc tok
if cur$="." then tok=1
if oldtok<>tok
inc count
endif
next c
endfunction count
function stGetToken(st$,num)
for c=1 to len(st$)
oldtok=tok
cur$=mid$(st$,c)
if isLetter(cur$) then tok=1
if isNum(cur$) then tok=1
if isOther(cur$) then inc tok
if cur$="." then tok=1
if oldtok<>tok
inc curtok
endif
if curtok=num
ret$=ret$+cur$
endif
next c
endfunction ret$
function isLetter(text$)
if asc(text$)>=asc("a") and asc(text$)<=asc("z") then alpha=1
if asc(text$)>=asc("A") and asc(text$)<=asc("Z") then alpha=1
endfunction alpha
function isNum(text$)
if asc(text$)>=asc("0") and asc(text$)<=asc("9") then num=1
endfunction num
function isOther(text$)
if isLetter(text$)=0 and isNum(text$)=0 then exitfunction 1
endfunction 0
function getToken(st$,t$,num)
if right$(st$,len(t$))<>t$ then st$=st$+t$
if left$(st$,len(t$))<>t$ then st$=t$+st$
for s=1 to len(st$)
cur$=mid(st$,s,len(t$))
if cur$=t$ then inc count
if count=num then pos=s+1 : exit
next s
for s=pos to len(st$)
tok$=tok$+mid$(st$,s)
if mid(st$,s,len(t$))=t$ then exit
next s
tok$=left$(tok$,len(tok$)-1)
tok$=right$(tok$,len(tok$)-(len(t$)-1))
endfunction tok$
function getTokenCount(st$,t$)
if right$(st$,len(t$))<>t$ then st$=st$+t$
if left$(st$,len(t$))<>t$ then st$=t$+st$
for s=1 to len(st$)
cur$=mid(st$,s,len(t$))
if cur$=t$ then inc count
next s
dec count
endfunction count
function remCharS(st$,ch$)
for t=1 to len(st$)
if mid$(st$,t)<>ch$
out$=out$+mid$(st$,t)
endif
next t
endfunction out$
function remChar(st$,ch$)
l=len(ch$)
if l>1
for s=1 to len(st$)
rm$=mid(st$,s,len(ch$))
if rm$=ch$ then sp=s : ep=s+(len(ch$)-1) : exit
next s
for s=1 to len(st$)
if s<sp or s>ep
new$=new$+mid$(st$,s)
endif
if s>ep then exit
next s
else
new$=remCharS(st$,ch$)
endif
endfunction new$
function remCharExc(st$,exc$,ch$)
for s=1 to len(st$)
cur$=mid$(st$,s)
if cur$=exc$ then onE=1-onE
if onE=0
if cur$<>ch$
mes$=mes$+cur$
endif
else
mes$=mes$+cur$
endif
next s
endfunction mes$
function trimleft(st$)
for l=1 to len(st$)
if mid$(st$,l)<>" " then onLet=1
if onLet=1 then new$=new$+mid$(st$,l)
next l
endfunction new$
`Functions - File
function fileLines(file$)
local lines as integer
open to read 1,file$
repeat
read string 1,null$
inc lines
until file end(1)
close file 1
endfunction lines
Enjoy