User Tools

Site Tools


crpl:crpltutorial

This is an old revision of the document!


~~DISCUSSION~~ <!--Comments visible to editors only can be placed in HTML comments --> <!-- Right now, this is a wall of text. I'm working on getting it into wiki form, but it might take a bit of work :D --> <- CRPL Home

CRPL Tutorial

ATTENTION: WORK IN PROGRESS <box 60% round green |Acknowledgements> This tutorial is a contribution by members of the CW3 beta team. Their contributions are gratefully acknowledged

Special thanks to:

  • J
  • Michionlion

</box>

<!-- I don't believe we need an additional "contents" section of contents are auto-generated - see the contents section at the top-right of the page. 
==== Contents====
[[crpltutorial#Starting with CRPL|Starting with CRPL]]\\
[[crpltutorial#Using the tracelog and further introduction of a stack language|Using the tracelog and further introduction of a stack language]]\\
[[crpltutorial#Comparing numbers and conditions|Comparing numbers and conditions]]\\
[[crpltutorial#More functions|More functions]]\\
[[crpltutorial#Variables and Loops|Variables and Loops]]\\
[[crpltutorial#Defining your own functions|Defining your own functions]]\\
[[crpltutorial#Making you script more useful|Making you script more useful]]\\
[[crpltutorial#Useful links|Useful links]]\\
-->

Before you start

The most important thing that you will need to know is the basics of CW3 gameplay and CW3 editor. It is a good thing if you have programmed before but if that wasn't a stack language it sometimes is a disadvantage. You don't have to have any programming skills to start with CRPL.

Starting with CRPL

First of all, if you have programmed before, try to forget that while reading. CRPL is (unlike many others) a stack based language, that means you put (push) all numers on a big stack of numbers and functions (like SetCreeper or QueueMove) get (pop) the last number(s) from the stack and do something with it (create a spore, emit creeper). Think of a stack of plates in the cafeteria. People take the top plate. Then someone brings more plates and they go on top and people start taking from the top again. The whole script will be executed once per frame. In scripts, you can use '#' skip the rest of the line. Think of it as a comment in you script.

#this is a comment and will not be executed

Time to create your first CRPL script! Try to use the functions GetCoords and SetCreeper. CurrentCoords puts two numbers on the stack (the X and Y coordinates of the CRPL tower) and SetCreeper pops 3 numbers from the stack (X and Y coords the creeper will be set on and the amount of creeper). The following code sets the creeper height to 5 every frame (there are 30 frames in an in-game second):

#Set the creeper to height 5 on the current position
CurrentCoords 5 SetCreeper

Instead of '5' you could pick another number or a variable (explained later) and instead of CurrentCoords you could pick two number to indicate the cell where the creeper has to be set.

Here are 2 more examples of what you could write:

  • AddCreeper: instead of setting the creeper to a specific height, this adds creeper.
    0 0 1 AddCreeper

  • RandCoords: This picks a random X and Y coordinate somewhere on the map.

    #Set the creeper to 1 on a random position
    RandCoords 1 SetCreeper

One more useful functions before I move on to the next section, you can use TIME Delay to stop the execution of the script for the set amount of time. So if you want to add 20 creeper every 3 seconds, you could write:

FIXME

Time intervals are not seconds, but frames. each second has 30 frames in it.
#first we add the creeper
CurrentCoords 20 AddCreeper
#then wait 3 seconds
90 Delay

This of course gives much more possibilities check out this one:

CurrentCoords -10 AddCreeper 30 Delay
RandCoords 5 AddCreeper 30 Delay
CurrentCoords 15 AddCreeper 60 Delay

Using the tracelog and further introduction of a stack language

(click to show/hide) There's a built-in function to show numbers that are currently on the stack. To enable the trace log, you must call the function ShowTraceLog. After that you can use the function Trace to pop an item from the stack and show it on the trace log (removes the item from the stack!). Use Trace2, Trace3, Trace4, Trace5 and TraceStack to pop and show 2, 3, 4, 5 or the whole stack on the trace log (TraceStack doesn't pop anything from the list). The notation of the stack: We use OPERATION (BEFORE – AFTER), try to use this if possible. So here are a few examples: <box>Add (99 33 -- 132)</box>

once 
ShowTraceLog 
99 33 Add Trace 
endonce

<box> Sub (12 7 -- 5) Mod (15 6 -- 3) </box> You can use multiple operators, but remember that they only pop the last added items from the stack. So where we normally would write (1+2)*(3+4), you now have to write

1 2 add 3 4 add mul

The most important thing here is that you keep in mind that what you've put on the stack last, will be the first you take off (Last In First Out). So

8 5 4 add

will result in

8 9

because 5+4=9. If you add another 'add' the sum of 9 and 8 will be calculated since that are the last two items on the stack. If you want a challenge, read the following piece of code:

once  
ShowTraceLog
8 9 5 sub 3 8 mul add 5 7 8 add 
add mod div
Trace 
endonce

Try to guess what's in the trace log

Click here to see the answer

Click here to see the answer

<box left> 8 ( – 8)
9 (8 – 8 9)
5 (8 9 – 8 9 5)
sub (8 9 5 – 8 4)
3 (8 4 – 8 4 3)
8 (8 4 3 – 8 4 3 8)
mul (8 4 3 8 – 8 4 24)
add (8 4 24 – 8 28)
5 (8 28 – 8 28 5)
7 (8 28 5 – 8 28 5 7)
8 (8 28 5 7 – 8 28 5 7 8)
add (8 28 5 7 8 – 8 28 5 15)
add (8 28 5 15 – 8 28 20)
mod (8 28 20 – 8 8)
div (8 8 – 1)
Trace (1 – )
</box> It will show you the last item on the stack and that is 1.


Now you should know how the stack and trace and stack system works. You should probably never use the trace functions in custom maps, but use it as debug tool.

More Examples

3+9= becomes: 3 9 add
4*5= becomes: 4 5 mul
4+2*4= becomes: 4 2 4 mul add
(4+2)*4= becomes: 4 2 add 4 mul
(1+2)*(3+4)= becomes: 1 2 add 3 4 add mul
(7-4)*(2+3+4)= becomes: 7 4 sub 2 3 add 4 add mul
(16/4)/2= becomes: 16 4 div 2 div
16/(4/2)= becomes: 16 4 2 div div

If you have problems to visualise it, put the same code in a comment and put brackets around it:

# Send a spore to the top part of the map
# CurrentCoords (RandCoords 2 div) (5 4 sub) (2 3 mul) CreateSpore
CurrentCoords RandCoords 2 div 5 4 sub 2 3 mul CreateSpore
# Has a lot of conditions before deciding if the code following must be executed or not
# ((((0 32 80 GetUnitCountInRange) 1 gte) (<-Eaten 20 gt) and) (GetRunnerCount 20 lt) and) if
0 32 80 GetUnitCountInRange 1 gte <-Eaten 20 gt and GetRunnerCount 20 lt and if

Comparing numbers and conditions

Sometimes you want a condition to check if code must be executed or not. Like in many other languages, this is possible with the 'if' function. Since we can't use brackets to show what piece of code must be skipped if the condition is not true, we must use 'endif'. 'true' is indicated by the number 1, and 'false' is indicated by the number 0. The 'if' function pops one number from the stack and if it is not equal to 0, the code will be executed. If that number is 0, the program skips the code until the next endif. The words 'true' and 'false' simply push a 1 (true) or 0 (false) on the stack. There are a lot of functions to compare numbers. Most these functions pop two items from the stack and push 0 (false) or 1 (true) back on the stack. You can find the full list in V's CRPL docs thread. I'll highlight some:

Function Description
andtrue if last 2 items are true
ortrue if one of the last 2 items are true
xortrue if last 2 items are false
nottrue if the last item is false
gt'greater than', pops 2 items from the stack, if the first is greater than the second, it results in true
gte'greater than or equal'
lt'lower than'
lte'lower than or equal'
eq'equal' true if the last 2 item have the same value
neq'not equal', true if the last 2 items are not the same
eq0true if the last item on the stack is equal to 0
neq0true if the last item is not equal to 0

These will result in true:

Arg1 Arg2 Operation
true false or
true true and
true true or
false false xor
false not
5 5 eq
4 7 neq
9 neq0
9 2 gt
6 7 lt
2 2 gte

Written as:

Arg1 Arg2 Operation

#These will result in false: false false and true false xor true not false false or false true and 9 9 gt 6 4 lte 5 5 lt 4 5 9 add eq 2 eq0 1 8 8 div sub neq0 </code>

More functions

Time to learn some more useful commands, I'll take the pre-made towers as example. A function is shown by the function name followed by bracket with the arguments in the order they must be put on the stack, seperated by a ','. Empty brackets mean that you don't need to give any arguments.

Emitters: Click to read

Emitters: Click to read

AddCreeper (x, y, amount), adds [amount] creeper to the cell on [x, y]. SetCreeper (x, y, amount), sets creeper to [amount] height on cell [x, y]. SetCreeperNoLower (x, y, amount), sets creeper to [amount] height on cell [x, y], but it won't remove creeper if there is more creeper than [amount]. GetCreeper (x, y), gets the creeper of cell [x, y] and puts it on the stack. Code: # this: CurrentCoords 5 SetCreeperNoLower # does exactly the same as this: CurrentCoords GetCreeper 5 lt if CurrentCoords 5 SetCreeper endif #lt means lower than and if decides if the code until endif must be executed or not

Spore Towers Click to read

Spore Towers Click to read

CreateSpore (x start, y start, x destination, y destination, health, payload), Creates a spore at cell [x start, y start] that moves towards cell [x destination, y destination]. The spore has a health of [health] ('normal' spores have 1) and if it lands it will drop [payload] creeper.

# Send a spore to a random unit
CurrentCoords RandUnitCoords 1 10 CreateSpore
# RandUnitCoords pick the coordinates of a random player unit


Timing

SetTimer0 (time), set the timer of timer 0 to [time], the timers decrease with 1 each game frame. SetTimer1, SetTimer2 and SetTimer3 work the same. GetTimer0 (), pushes the current value of timer 0 on the stack, same thing for GetTimer1, GetTimer2 and GetTimer3

# Send a spore to a random unit every second
once 30 SetTimer0 endonce
GetTimer0 eq0 if
CurrentCoords RandUnitCoords 1 10 CreateSpore
30 SetTimer0
endif
# anything between once and endonce is only executed once per game
# eq0 pops a number from the stack and checks if it is equal to 0


Runner Nest

GetDigitalis (x, y), checks for Digitalis on cell [x, y] and pushes the health of the Digitalis back on the stack (0 - no Digitalis, 1 - full health). CreateRunner (x, y, move, health, payload), creates a runner on position [x, y], the runner has [health] health and moves pixels per frame. Once the runner is killed [payload] creeper is deposited. GetRunnerCount (), pushes the amount of runner currently on the map created by this CRPL-Core on the stack (exactly the same as GetGlobalRunnerCount, except this is only for runners created by this tower). GetGlobalRunnerCount (), pushes the total amount of runners currently on the map on the stack Code: # Create a weak runner every frame if Digitalis is present and less than 20 runners are on the map CurrentCoords GetDigitalis neq0 GetGlobalRunnerCount 20 lt and if CurrentCoords 2 5 5 CreateRunner endif

More Digitalis stuff

A CRPL-Core allways 'activates' Digitalis, that means once the Digitalis is connected to a CRPLT, the D will grow. This might be changed in the meantime! GetDigitalisGrowth (x, y), checks for digitalis growth area at cell [x, y], if Digitalis can grow there, 1 is pushed back on the stack, if not, 0 is pushed back on the stack. SetDigitalis (x, y, health), sets the health of the digitalis on cell [x, y] to [health], 0 removes the Digitalis while 1 sets the D to full health. SetDigitalisGrowth (x, y, present), sets if Digitalis can grow on cell [x, y]. Present must be 0 (no Digitalis growth area) or 1 (creates growth area).

#this code is mostly used in moving towers
#leave a trail of Digitalis growth area and set the digitalis to full health
CurrentCoords true SetDigitalisGrowth
CurrentCoords 1 SetDigitalis

Variables and Loops

A variable: a way to store numbers without using the stack once stored. You can use ->VARNAME to pop the last item from the stack and store it as variable and you can use <-VARNAME to push the value of the variable on the stack (doesn't remove the variable). Please not that instead of VARNAME you can use any word. Examples: Code: 16 ->mynumb 2 ->n2 4 ->endnumb while <-mynumb <-endnumb neq repeat <-mynumb <-n2 div endwhile

As you may have noticed, I used 'while', 'repeat' and 'endwhile'. These functions form a 'loop'. There are different loops you can create in CRPL. Lets start with a 'do' loop: A do loop has 2 functions and has the following form: do (limit, index) loop 'do' pops 2 items from the stack, if the index is bigger or equal to the limit, the execution skips to 'loop', else the loop runs with 'index', when 'loop' is read, the execution returns to 'do', the index is raised with 1 and everything starts again. Code: #Add 5 creeper to 5 random locations every 5 seconds 5 ->times 5 ->creeper 150 ->wait <-times 0 do RandCoords <-creeper AddCreeper loop <-wait Delay

There's also a while loop. A while loop has 3 functions and has the following form: while repeat (execute) endwhile When while is read, the code between while and repeat is executed (and should push true or false on the stack). If true is read, the code will be executed until endwhile and execution return to while. If false is read, the code between repeat and endwhile is skipped and the execution continues at endwhile. Code: #Add 5 creeper to 5 random locations every 5 seconds 5 ->times 5 ->creeper 150 ->wait 0 ->numb while <-numb 4 lte repeat RandCoords <-creeper AddCreeper <-numb 1 add ->numb endwhile <-wait Delay #lte means lower than or equal

In a do or while loop, you can use 'break' to stop the loop immediatly and continue at loop or endwhile Code: #Add 5 creeper to 5 random locations every 5 seconds 5 ->times 5 ->creeper 150 ->wait 0 ->numb while true repeat RandCoords <-creeper AddCreeper <-numb 1 add <-numb 4 gt if break endif ->numb endwhile <-wait Delay #'true' pushes 1 (true) on the stack, this means repeat allways reads true #and the loop will keep going until break is read #this can easily make your game crash if you don't add the break command! #gt means greater than

Defining your own functions

If you want to use the same piece of code multiple times or want a better overview, you can use functions. In the main code, use @FUNCTION to call the function. At the end of the code, use :FUNCTION to define the function. The function is the piece of code between :FUNCTION and the end of the script or another function. If you want to give arguments or return a value, use the stack. An example to help you:

@getnumb #pass the execution to :getnumb
@emit #pass the execution to :emit
#------------------ (end of main body, using a line helps visualizing it)
:emit #once @emit is read, execution continues here
->numb #pop a value from the stack and store it
CurrentCoords <-numb AddCreeper
:getnumb #start a new function here, the :emit function stops here
5 #push 5 on the stack
#end of the code, the :getnumb function stops here

And how it looks without comments:

@getnumb @emit
#---------------
:emit
->numb CurrentCoords <-numb AddCreeper
:getnumb 5

Making your script more useful

If you use $VARNAME:DEFAULT at the start of your code you can define the variable when adding scripts to units in-game. In other words, you can set these variables in-game and that can be different for other cores.

$amtToEmit:10
$interval:15
CurrentCoords <-amtToEmit SetCreeper
<-interval Delay

Take a look at '$interval:15'. When you attach the script to a core in-game you can choose a value for the variable 'interval'. If you don't input a number in-game, 15 is used. This is a very powerful mechanism to use the same script over different cores or if you want to give the script to other map makers.

A page filled with functions and examples: http://knucklecracker.com/creeperworld3/CRPL/docs/crpldocs.html

The KC wiki with a CRPL overview and reference: http://knucklecracker.com/wiki/doku.php?id=cw3:creeper_world_3

crpl/crpltutorial.1359298827.txt.gz · Last modified: 2014/10/01 15:02 (external edit)