some scripting tricks I've come across
Posted: Tue Oct 23, 2012 3:39 pm
As I've been working with Grimrock editor.. and in particular writing scripts, I've come across some neat things that may not be well documented, or are hidden within scripts that people have written... so I thought I'd start a thread to share a few I've come across... if people are interested and this takes off, please post your own tricks.
These are taken from working scripts that I have used, but are not complete scripts by themselves.
Number of items in a list.
if you have a list in a script entity then you can quickly find how many by using #chooses a random monster from the list... but now you can easily add more to the list without ever having to change the math.random range.
Compare text using a Substring
if you want to compare the name or id of entities and use a partial match all that begin with a particular word or phrase you can you sub to create a substringin this example we create a substring of the id that starts at character 1 and is 13 characters long. It then checks every pit on the same level as the party and opens it if the id substring begins with "sequence_pit_" Therefore sequence_pit_1; sequence_pit_2; sequence_pit_3; sequence_pit_4 etc. will all be opened because the first 13 characters all match "sequence_pit_"
EDIT - clarification on how to use sub
s:sub(i,j)
OR
string.sub(s,i,j)
s is the string we want to look at.
i is the start character
j (optional) is the end character. if j is omitted, then the result will run to the end of the original string s.
if i is negative, then the substring will start that many characters in from the right.
Check which plate/button/switch triggered the function
When you create a connection in the editor between an entity and a script, the entity is passed to the script as a variable..
Here we change the facing of a teleporter we spawn at the party's location, based on which of 4 pressure plates was activated.
Spawn items "up in the air"
When spawning items to automatically give to the party, or insert into containers, It was suggested by Petri to spawn them "up in the air", because if spawned with co-ordinates, they will remain in that space when (a copy is) placed in a champion's inventory.
A simple way to spawn something "in the air" is
If you want to give an item a particular id to refer to later, you need a more detailed spawn command
here we set the level, x, y and facing to nil when we spawn the gem as we add it to the eye socket.
Check if something has a nil value
As I've been working with more complex scripts I've often found the game crashes because I have attempted to use something that does not exist, or has a nil value... so it can often be beneficial to check if things are nil before acting upon them.This is a basic example where we check if the 1st champion's left hand is empty, and spawn a throwing axe there, otherwise we spawn it on the ground at the party's location. (this was part of my returning axe script)
Check if something IS NOT equal
Possibly a very basic one, but most people will be familar with checking if a == b, but also useful is to use ~= to check if something is not equal.
Here we check if the 1st champion has an item in his left hand, if an item exists, we remove it.
Repeat something until something else happens
Repeat until is a very powerful way to create a loop... though care should be taken using it, as it has the potential to cause an endless loop if the until condition can never be met.
This is a simple way to pick two random numbers a and b between 1 and 4 without a and b ever being the same. This could be used to pick two different champions in the party.
Do something for every value in a range (loop)
the for command can be very useful for creating looping scripts in Grimrock editor, allowing us to automate tasks a certain number of times.This loops over the values 1,2,3 and 4 and for each it adds a pitroot bread to the first inventory slot of that numbered champion.
Do something for every entry in a list (loop)
we can also use a for loop to do something for every entry in a list.In this case we go through a list of portcullis entity ids and open each door with that id.
Concatenate (i.e. join) strings
Sometimes it is useful to join separate strings together as a single string, especially when working with a variable string and a fixed string. To do this we can use the concatenate operator ..in this example we print to the screen that our first champion is hungry... if you are using the default party it will actually say "Contar Stoneskull is feeling hungry". It's worth noting that If you're joining a variable to a fixed string you will probably need to put a space in at the beginning of your string (as in the example above).
Add multiple tests to the same hook
With so many spells and effects using party, monster or other hooks, it can happen that you need to run two different scripts as part of the same hook. This can be done by evaluating each script as a variable and then returning both.here we first evaluate the checkHeld() function which will run a script and output either true or false. then we evaluate the checkTurn() function which will run another script and again output either true of false. Finally we return the AND of the outputs.. so if either (or both) output is false the overall output will be false and the monster will not execute its turn. If both are true, the monster turns.
These are taken from working scripts that I have used, but are not complete scripts by themselves.
Number of items in a list.
if you have a list in a script entity then you can quickly find how many by using #
Code: Select all
monsters = {"snail","herder","crowern","ogre"}
random_monster = math.random(1,#monsters)
Compare text using a Substring
if you want to compare the name or id of entities and use a partial match all that begin with a particular word or phrase you can you sub to create a substring
Code: Select all
for i in allEntities(party.level) do
if i.id:sub(1,13) == "sequence_pit_" then
i:open()
end
end
EDIT - clarification on how to use sub
s:sub(i,j)
OR
string.sub(s,i,j)
s is the string we want to look at.
i is the start character
j (optional) is the end character. if j is omitted, then the result will run to the end of the original string s.
if i is negative, then the substring will start that many characters in from the right.
Check which plate/button/switch triggered the function
When you create a connection in the editor between an entity and a script, the entity is passed to the script as a variable..
Code: Select all
function checkTrigger(trigger)
if trigger.id == "plate_N" then
Tfacing = 3
elseif trigger.id == "plate_E" then
Tfacing = 0
elseif trigger.id == "plate_S" then
Tfacing = 1
elseif trigger.id == "plate_W" then
Tfacing = 2
else
Tfacing = 0
end
spawn("teleporter",party.level,party.x,party.y,Tfacing)
Spawn items "up in the air"
When spawning items to automatically give to the party, or insert into containers, It was suggested by Petri to spawn them "up in the air", because if spawned with co-ordinates, they will remain in that space when (a copy is) placed in a champion's inventory.
A simple way to spawn something "in the air" is
Code: Select all
spawn("item_name")
Code: Select all
eye_socket_left:addItem(spawn("blue_gem",nil,nil,nil,nil,"fake_blue_gem"))
Check if something has a nil value
As I've been working with more complex scripts I've often found the game crashes because I have attempted to use something that does not exist, or has a nil value... so it can often be beneficial to check if things are nil before acting upon them.
Code: Select all
if party:getChampion(1):getItem(7) == nil then
party:getChampion(1):InsertItem(7,spawn("throwing_axe"))
else
spawn("throwing_axe",party.level,party.x,party.y,party.facing)
end
Check if something IS NOT equal
Possibly a very basic one, but most people will be familar with checking if a == b, but also useful is to use ~= to check if something is not equal.
Code: Select all
if party:getChampion(1):getItem(7) ~= nil then
party:getChampion(1):removeItem(7)
end
Repeat something until something else happens
Repeat until is a very powerful way to create a loop... though care should be taken using it, as it has the potential to cause an endless loop if the until condition can never be met.
Code: Select all
a = math.random(1,4)
repeat b = math.random(1,4)
until a ~= b
Do something for every value in a range (loop)
the for command can be very useful for creating looping scripts in Grimrock editor, allowing us to automate tasks a certain number of times.
Code: Select all
for i = 1,4 do
party:getChampion(i):insertItem(11,spawn("pitroot_bread"))
end
Do something for every entry in a list (loop)
we can also use a for loop to do something for every entry in a list.
Code: Select all
local list_of_gates = {"dungeon_portcullis_4","dungeon_portcullis_2","dungeon_portcullis_3"}
for _,i in ipairs(list_of_gates) do
door = findEntity(i)
door:open()
end
Concatenate (i.e. join) strings
Sometimes it is useful to join separate strings together as a single string, especially when working with a variable string and a fixed string. To do this we can use the concatenate operator ..
Code: Select all
hudPrint(party:getChampion(1):getName() .. " is feeling hungry")
Add multiple tests to the same hook
With so many spells and effects using party, monster or other hooks, it can happen that you need to run two different scripts as part of the same hook. This can be done by evaluating each script as a variable and then returning both.
Code: Select all
onTurn = function(monster,turn_dir)
local hold_test = grimwold_spell_script.checkHeld(monster)
local turn_test = grimwold_spell_script.checkTurn(monster,turn_dir)
return hold_test and turn_test
end,