Difference between revisions of "Cubescript"

From Platinum Arts Sandbox Free 3D Game Maker
Jump to: navigation, search
(Branching/Decisions)
(cond)
Line 381: Line 381:
 
   lightstrength = [
 
   lightstrength = [
 
     cond [(< (ea 0) 0)] [
 
     cond [(< (ea 0) 0)] [
       result "It's like a black hole!"
+
       echo "It's like a black hole!"
 
     ] [(= (ea 0) 0)] [
 
     ] [(= (ea 0) 0)] [
       result "Blindlier than science!"
+
       echo "Blindlier than science!"
 
     ] [(< (ea 0) 8)] [
 
     ] [(< (ea 0) 8)] [
       result "It's weaker than Billy's night light!"
+
       echo "It's weaker than Billy's night light!"
 
     ] [(< (ea 0) 32)] [
 
     ] [(< (ea 0) 32)] [
       result "Nice night light you got there"
+
       echo "Nice night light you got there"
 
     ] [(< (ea 0) 96)] [
 
     ] [(< (ea 0) 96)] [
       result "It's like a lamp, but it's not a lamp"
+
       echo "It's like a lamp, but it's not a lamp"
 
     ] [(< (ea 0) 512)] [
 
     ] [(< (ea 0) 512)] [
       result "By Jove! I can actually see the ground!"
+
       echo "By Jove! I can actually see the ground!"
 
     ] [(>= (ea 0) 512)] [
 
     ] [(>= (ea 0) 512)] [
       result "Dark places are icky, don't you agree?"
+
       echo "Dark places are icky, don't you agree?"
 
     ]
 
     ]
 
   ]
 
   ]

Revision as of 19:54, 29 July 2010

Cubescript is the scripting language utilised within the sauerbraten/cube2 engine. it is used to set aliases, variables, create binds and generate the menu.

List of commands

General

The following commands are quite often used in a lot of scripts.

  • alias N B
    • creates an alias named N with body B, the intext version is denoted as N = B (equivalent to alias N B)
  • at S I
    • returns the Ith element in string S, note that counting starts from 0. If it's out of range, "" is returned
  • getalias A
    • returns the value of A. this also does not produce a warning should an alias be undeclared, nor complains when fetching built in variables.
  • if C T F (F is optional)
    • if condition C is true, execute T, otherwise F is executed
  • listlen S
    • returns the amount of elements in list S
  • loop V N B
    • loops N times, and aliases the current iteration to V; B is executed every iteration.
  • result S
    • returns the string, useful when aliases need to be executed
  • rnd N L
    • chooses a random number between 0 and N-1 (inclusive). L sets the lower limit. eg rnd 12 7 will return either 7 8 9 10 or 11
  • sleep N B
    • executes B after a delay of N milliseconds. NOTE: even if N is <= 0, it'll still wait till the next frame before executing it
  • while C B
    • executed B while C is true. NOTE: surround C in a [] container, or you risk an infinite loop due to the condition not being reevaluated.

Map Configuration

ONLY APPLIES TO FPSGAME

The following commands are useful in level only aliases

  • triggerstate
  • level_trigger
    • level trigger is invoked as level_trigger_1 = [] as an example, the end number is the 4th number in the mapmodel's strings
  • level_base
    • Used to give bases names in capture mode. This is unfortunately unused in PAS

Binds

The following commands are useful in binds.

  • onrelease

Gui Creation

These commands are used to create various menus.

  • cleargui
  • guibar
  • guibutton
  • guicheckbox
  • guifield
  • guikeyfield
  • guiimage
  • guilist
  • guirolloveraction
  • guirollovername
  • guislider
  • guilistslider
  • guinameslider
  • guistayopen
  • guitab
  • guitext
  • guititle
  • guistrut
  • newgui

Comparisons

The functions here can change the values, or return a logical comparison for all intents and purposes, the C version of booleans apply here; values not equal to 0 are true - and functions that return true return 1

Integer Arithmetic

  • + A B
    • returns the value of the numbers added together
  • * A B
    • returns the result of multiplying A and B
  • - A B
    • returns the value of A - B
  • = A B
    • returns true of the two are equal
  •  != A B
    • returns true if the two aren't equal
  • < A B
    • returns true if A is less-than B
  • > A B
    • returns true if A is greater-than B
  • <= A B
    • returns true if A is less-than-or-equal-to B
  • >= A B
    • returns true if A is greater-than-or-equal-to B
  •  ! A
    • if the argument is false, it returns true
  • &&
    • returns true if all arguments are true
  • ||
    • returns true it at least one argument is true
  • div A B
    • returns the value of A divided by B
  • mod A B
    • returns the modulus of the two arguments
  • min
    • returns the lowest valued argument of all provided arguments
  • max
    • returns the highest valued argument of all provided arguments

Bitwise Integer Operations

  • ^ A B
    • returns the value of A xor B ie (^ 8 4) is 12 - (^ 12 4) is 8
  • & A B
    • returns the value of the bits both A and B have
  • | A B
    • returns the value of the bits either A or B have
  • ~ A
    • returns the inverted bitwise version of A ie (& (~ 128) 255) is 127
  • ^~ A B
    • xor;s the arguments after applying an inversion on B
  • &~ A B
    • and's the arguments after applying an inversion on B
  • |~ A B
    • or's the arguments after applying an inversion on B
  • << A N
    • shifts A N bits
  • >> A N
    • shifts A -N bits

Floating Point Arithmetic

Generally these just have an -f suffix

  • +f A B
    • returns the value of the numbers added together
  • *f A B
    • returns the result of multiplying A and B
  • -f A B
    • returns the value of A - B
  • =f A B
    • returns true of the two are equal
  •  !=f A B
    • returns true if the two aren't equal
  • <f A B
    • returns true if A is less-than B
  • >f A B
    • returns true if A is greater-than B
  • <=f A B
    • returns true if A is less-than-or-equal-to B
  • >=f A B
    • returns true if A is greater-than-or-equal-to B
  • divf A B
    • returns the value of A divided by B
  • modf A B
    • returns the modulus of the two arguments
  • minf
    • returns the lowest valued argument of all provided arguments
  • maxf
    • returns the highest valued argument of all provided arguments

Strings

  • =s A B
    • returns 1 if the string matches, 0 otherwise
  •  !=s A B
    • returns 0 if the string matches, 1 otherwise
  • <s A B
    • returns true if the C strcmp returns less-than 0
  • >s A B
    • returns true if the C strcmp returns greater-than 0
  • <=s A B
    • returns true if the C strcmp returns less-than-or-equal-to 0
  • >=s A B
    • returns true if the C strcmp returns greater-than-or-equal-to 0
  • strcmp A B
    • returns 1 if the string matches, 0 otherwise (unlike the C version with returns the disparity)
  • strstr H N
    • returns the position of N in H - otherwise -1 is returned
  • strlen S
    • returns the length of the string
  • strreplace S O N
    • replaces all instances of O inside string S with N

String/text formatting

These commands are used to format aliases which are normally huge bits of text

  • concat C
    • everything you type after will be returned; with expressions and substitutions performed
  • concatword C
    • the next 25 arguments will be executed and subsequently concatenated without any spaces between them
  • format F S1 S2 S3 S4 S5 S6 S7 S8 S9
    • F is a string containing %# tokens, format substitutes the arguments with their respective %# tokens (ie: S5 will replace %5)

Writing in Cubescript

Syntax

Cubescript has many similarities with C, mostly in the way the script is formatted. But there are some HUGE differences. Newlines for one mean it's both the end of a function and the end of a string (should you have forgotten to close one off). The scripts below do the exact same thing. Comments are anything that follow a //.

one liner example

 alias hi [say "hi"; sleep 5000 [say "Hi again"]]

multi liner example

 alias hi [
   say "hi"
   sleep 5000 [
     say "Hi again"
   ]
]

it's obvious what the above code does, it'll make your character say hi, and wait 5 seconds before saying hi again.

indenting is done in levels, the Tabulator (TAB) key is usually used to indent the text. while not necessary, it tends to make it bigger, and more legible as seen in the above example (when you get to big stuff, you'll thank yourself for indenting it.

As a rule of thumb, pretty much only [ increases the indentation level. Also note, ", ] and ) can close each other, so make sure you close them off properly

containers

Containers in cubescript are of 3 specific types, "", () and [] - all of these have significant differences in operation and use

"" container

"" containers are used to store things EXACTLY as they are written, with a few small exceptions - in-text commands which are denoted by a preceding ^. They are as follows

  • ^f#
    • ^f# is used to colour text. # must be replaced by either a number or a capital letter (A-Z). r and s are special control characters which will restore and save the text's current colour respectively.
  • ^n
    • insert a '\n' character (newline/linefeed)
  • ^t
    • inserts a '\t' character (tabulator)
  • ^"
    • inserts a quote (")

() container

() containers are used mainly for logic/arithmetic operations. They are usually nested inside [] blocks, and unless they are nested inside []'s they're permanently substituted with their results.

For example - the following will turn into an infinite loop. The condition is initially evaluated and substituted with one and since 1 can never = 0, it's true forever more

 i = 0
 while (= $i 0) [i = (+ $i 1)]

the following code on the otherhand is devoid of such issues. Being nested inside the [] means it's not substituted and evaluated each cycle

 i = 0
 while [(= $i 0)] [i = (+ $i 1)]

[] container

This container is used for nesting, deferring execution of it's contents, deferring calculations and substitutions of () containers, and substitutions of aliases/variables written with a @ prefix (note several levels are needed to achieve this). [] containers are also the ONLY container capable of spanning multiple lines.

This is the most used container and due to it's properties, is ideal for creating aliases.

generally statements in cubescript can't span multiple lines. If you should use this container and occupy several, the execution of the prior command continues exactly where this container finished off. This can be demonstrated with an if statement.

 if 1 [
   do
   stuff
 ] [
   do
   other
   stuff
 ]

substitution

there are two principle ways of substituting values in cubescript, the first is through the use of $ tokens, the second is through the use of @ tokens.

a very simple example:

 myalias = 5
 echo $myalias

myalias is substituted into the echo statement, so you should see 5 printed to the top-left of the screen

using the @ token would have also resulted in the same behaviour

 myalias = 5
 echo @myalias

There's a big difference between the two, the @ token can be used to concatenate stuff together, $ can't. @ is also substituted immediately up to the first level of nesting. (this can be incremented by using additional @ tokens, ie @@ for 2 levels of nesting). Do take note that too few @ tokens may cause a substitution to happen too late, and too many may likewise cause it to happen too early.

An example of use in a level 1 nest

 myalias = "I am awesome"
 mymenu = [guitext @myalias]

if you were to type /echo $mymenu, it should read: guitext "I am awesome"; using the $ token on the other hand

 myalias = "I am awesome"
 mymenu = [guitext $myalias]

typing /echo $mymenu should produce: guitext $myalias


An example of concatenation

as i mentioned, @ also allows you to concatenate stuff together, which could result in shorter and simpler scripts. It should be noted that this can also result in extreme obfuscation

 myalias0 = 5
 myalias1 = 3.1415
 myalias2 = 2.481
 
 loop i 3 [
   echo $myalias@i
 ]

this should print 5, 3.1415 and 2.481 respectively

the purely $ token equivalent

 myalias0 = 5
 myalias1 = 3.1415
 myalias2 = 2.481
 
 loop i 3 [
   echo (getalias (concatword myalias $i))
 ]

Branching/Decisions

Decisions are based on 6 key commands, if, ?, cond, case (integer), casef (float) and cases (string). There are also other ways to do this. For example you might be able to easily query something about an object, where it's obviously unique. You would then execute an alias whose name has this unique bit attached onto the end. This is an advanced method and is generally not recommended.

if and ?

Arguments: Cond True False

Unlike most other languages, cubescript's if contains an implicit else, in short we do not have an else statement. The provided condition is true if it ends up as a series of alpha numerics, or in the case of a number, as a value other than 0.

 myalias1 = 5
 myalias2 = "woot"
 //if else-if else
 if $myalias1 [
   echo "myalias1 is true"
 ] [
   //this shows the alpha numerics case
   if $myalias2 [
     echo "myalias1 is false and myalias2 is true"
   ] [
     echo "myalias1 is false and myalias2 is false"
   ]
 ]

? acts exactly the same way, but there's one HUGE difference. ? does not execute the chosen result.

 //an example of where ? can be used where if would fail
 items = 1
 echo (format "You are carrying %1 item%2." $items (? (= $items 1) "" "s"))

cond

basically you provided a several pairs of arguments, the first half of the pair is the condition, and the second is the result. To put it in a programming perspective, this is like creating a long line of if else's together. Execution stops when the first condition is matched. Should you place several conditions where more than one may be true at any one time, only the first will be executed.

The following example assumes you have a light entity selected

 lightstrength = [
   cond [(< (ea 0) 0)] [
     echo "It's like a black hole!"
   ] [(= (ea 0) 0)] [
     echo "Blindlier than science!"
   ] [(< (ea 0) 8)] [
     echo "It's weaker than Billy's night light!"
   ] [(< (ea 0) 32)] [
     echo "Nice night light you got there"
   ] [(< (ea 0) 96)] [
     echo "It's like a lamp, but it's not a lamp"
   ] [(< (ea 0) 512)] [
     echo "By Jove! I can actually see the ground!"
   ] [(>= (ea 0) 512)] [
     echo "Dark places are icky, don't you agree?"
   ]
 ]

case

This works similar to switches in most programming languages. The biggest difference is there is no break; so there are no fallthroughs. (for example in C/C++, case 5: case 6: [...]; break; could cause both cases to execute the same code).

The first argument tells it which variable to use. The following arguments are given in pairs, the first half is the state, the second is the result.

The following example requires a particles entity to be selected, it will print out what type it is

 parttype = [
   pname = "Invalid Particle"
 
   case (ea 0) 0 [
     pname = "Fire and Smoke"
   ] 1 [
     pname = "Fire"
   ] 2 [
     pname = "Smoke Plume"
   ] 3 [
     pname = "Smoke"
   ] 4 [
     pname = "Fountain"
   ] 5 [
     pname = "Explosion"
   ] 6 [
     pname = "Meter"
   ] 7 [
     pname = "Vs Meter"
   ] 8 [
     pname = "Text"
   ] 9 [
     pname = "Flare"
   ] 10 [
     pname = "Lightning"
   ] 11 [
     pname = "Fire"
   ] 12 [
     pname = "Smoke"
   ] 13 [
     pname = "Water"
   ] 14 [
     pname = "Snow"
   ] 15 [
     pname = "Leaves"
   ] 32 [
     pname = "Lens Flare"
   ] 33 [
     pname = "Fixed Size Lens Flare"
   ] 34 [
     pname = "Sparkly Lens Flare"
   ] 35 [
     pname = "Sparkly Fixed Size Lens Flare"
   ]
 
   echo The particle you have selected is of type: $pname
 ]

Naming

another way of doing decisions/branches is to use paths with different names. This has limited usage though. in short it requires you to query some information to concatenate onto another word, which you would then execute. There are exceptions. Other than the number of results you can query, there is no limit here. A handy trick is to several execute the same alias, though this requires that they differ only slightly at most in operation.

 //This example demonstrates the exception
 //it requires you to have an entity selected
 //This will conflict with showquickgui
 newgui "particles" [guitext "It's like a random series of nothing"]
 newgui "light" [guitext "SHINY!!!!"]
 newgui "jumppad" [guitext "boing!"]
 
 identify = [showgui (et)]

 //shows a more standard example, at present this is exclusively used by edithud (see stdedit.cfg)
 //this also requires you to have an entity selected.
 identlight = [echo "it's so bright..."]
 identjumppad = [echo "boing? boing!"]
 identparticles = [echo "Please don't change it to a lens flare!"]
 identify = [ if (enthavesel) [ident@(et)] [echo Select an entity first!]]

Lists

Ordered lists are the closest cubescript has to the likes of arrays. They are declared the same as any other alias. Lists can use the "" and the [] container, the latter is recommended. Remember that it breaks at the next whitespace, this can be avoided by surrounding the element in quotes. To retrieve a specific item, at list index is used.

 //declares 2 equivalent lists of 3 elements
 mylist1 = [one two "three four"]
 mylist2 = "one two ^"three four^""
 
 //prints the 3rd element
 echo (at $mylist 2)

loops

There are two ways to loop through lists, depending on circumstances you may, or may not want to know the index. If you do not need to know the index, you would use looplist var list body. Otherwise you'd generally invoke loop var num with a supporting listlen list invocation.

 mylist = [
   0
   1
   3.14159265359
   2.71828182845
   sqrt(-1)
 ]
 
 //demonstrates looplist
 looplist var $mylist [
   echo $var
 ]
 
 //demonstrates loop + listlen combo
 loop i (listlen $mylist) [
   echo (at $mylist $i)
 ]

concatenation

This is unfortunately not simple. To concatenate an item onto the end of a list you are required to make the list equal itself plus the item. This is best achieved through the use of concatword and format.

 mylist = [1 2 3 4 5 6 7 8 9 10]
 
 //using concatword
 mylist = (concatword $mylist " " 11)
 
 //using format
 mylist = (format "%1 %2" $mylist 12)
 
 //since these lack spaces, concat and prettylist can be used as well...
 mylist = (concat $mylist 13)
 mylist = (prettylist $mylist 14)
 
 //should print 1 2 3 4 5 6 7 8 9 10 11 12 13 14
 echo mylist is $mylist

concat returns whatever is given to it, spaces included. the only difference with concatword is that concatword ignores spaces. concat and prettylist are ideal for merging lists into one...

 mylist1 = [1 2 3 4 5]
 mylist2 = [6 7 8 9 10]
 mylist3 = [11 12 13 14 15]
 mylist4 = [16 17 18 19 20]
 mylist5 = [21 22 23 24 25]
 mylist6 = [26 27 28 29 30]
 finallist = ""
 
 //the use of prettylist
 finallist = (prettylist $mylist1 $mylist2)
 
 //concat can combine them all, and we defined extra lists to show that...
 finallist = (concat $finallist $mylist3 $mylist4 $mylist5 $mylist6)

finding

there are two ways to find things, the firs tis to use listfind, and the second is to loop through the list. Both are demonstrated in the example below

 mylist = [
   "Jack"
   "Jane"
   "Joseph"
 ]
 
 //This is an example of looking for a single element, note that this variant of...
 //strcmp unlike its C counterpart returns 1 when strings are equal
 //in this example, a 0 should be printed at the top of your screen - listfind returns the index
 echo (listfind f $mylist [strcmp $f "Jack"])
 
 //In this example, -1, as Jill is not in the list
 echo (listfind f $mylist [strcmp $f "Jill"])
 
 //in this example, we want to find anything which contains an e and add it into a list
 results = ""
 looplist var $mylist [
   if (>= (strstr $var "e") 0) [
     results = (concatword $results "^"" $var " ^"")
   ]
 ]
 
 //this should print: Jane Joseph
 echo $results

See Also