Legend of Grimrock 1 Modding

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
User avatar
Sir Tawmis
Posts: 980
Joined: Mon Jul 30, 2012 8:15 am
Contact:

Legend of Grimrock 1 Modding

Post by Sir Tawmis »

Posting it here because it used to be on the site - prior to the redesign - for preservation purposes.

Modding Grimrock 1
This series of documents and guides is intended for anyone who wishes to create their own Legend of Grimrock custom dungeons and mods. But if you wish to just play mods, you can simply subscribe to them in Steam Workshop or downloading them to your “Documents\Almost Human\Legend of Grimrock\Dungeons” -folder from Grimrock Nexus or elsewhere.

Legend of Grimrock comes with a built in dungeon editor and the getting started -guides describe all you need to know if you want to create your own dungeons, complete with monsters, items, puzzles and traps. If you are a little bit more adventurous and if you want to create even more extensive modifications, we have guides for you that will help you get started with scripting in the editor and creating new assets but, due to the breadth of these subjects, we can only scratch the surface here.

The modding and asset usage terms detail what you are and are not allowed to do with mods, custom dungeons and custom assets. You should be familiar with the usage terms before sharing any content you have created. We also cover how you can use and modify the original Legend of Grimrock assets.

Dungeon Editor Basics

Image

When starting the editor you are presented with an empty editor screen and to get going, we should create a new project by going to the “File” -drop down menu and selecting “New Project…”.

In the New Project dialog all we need to do for now is to enter a name for the dungeon and hit create and you should be presented with a blank map with a small room in the middle, where the player party starts in, that we can start working on! First, we’re going to need the draw tunnels tool to carve some empty spaces in the rock so let’s take a brief look at the tools palette: in the top left hand corner we have three buttons: select entity, add asset and draw tunnels. You’ll be switching between these tools pretty frequently so it’s good to learn their shortcuts which can be accessed by pressing 1, 2 and 3 on your keyboard.

Image

Let’s pick the draw tunnels tool and carve some hallways and rooms for the player to get lost in! While this tool is active, left clicking on the map draws tunnels and right clicking draws walls.

Preview
To try out the dungeons you are creating, all you need to do is to press the play button above the preview or F5 on the keyboard. The game will start running and you can move around in the dungeon in the usual fashion with W, A, S and D. You can access fullscreen mode by pressing Ctrl-F while in the preview.

You can freely edit the level while the preview is running. Any changes you make to the level will be instantly reflected in the preview when you press play again. Pressing the stop button will stop the preview and move the player party back to the starting location. The starting location can be easily changed by hovering over the map and pressing Y.

While running the preview in the editor, the player is equipped with a torch that never runs out to ease the testing of the dungeon. This torch will be present only in the editor so when the dungeon is exported, the player party will start without items.

Using Assets
A dungeon with nothing but empty hallways in it isn’t terribly exciting so what we need to liven up the place is some assets! Objects like items, monsters, doors and decorations are all assets and there’s a few assets that are only directly visible to the level designer such as script entities, blockers and timers. Asset browser is used to add instances of assets, which are called entities, to the level and you can use the search or the filter drop down menu to make finding them easier. Adding entities to the level is as simple as picking them from the browser, at which point your active tool is automatically changed to adding assets, and clicking on the map.

The select entities tool (shortcut 1) can be used to select entities so that you can move them around or manipulate their parameters in the Inspector. When one or more entities are selected, they can be moved with W, A, S and D and their orientation can be changed with Q and E. You can delete selected entities with the delete key and the entities can also be cut, copied and pasted with ctrl-X, ctrl-C and ctrl-V.
Define ... 'Lost.' Neverending Nights - The Neverwinter Machinima that WILL make you laugh!
Also read: Legend of Grimrock: Destiny's Chance here on the forum! Check out the site I made for Legend of Grimrock: Destiny's Chance.
User avatar
Sir Tawmis
Posts: 980
Joined: Mon Jul 30, 2012 8:15 am
Contact:

Re: Legend of Grimrock 1 Modding

Post by Sir Tawmis »

Inspector and Connectors
When a single entity is selected, its properties such as ID, position and facing are displayed in the inspector window. Many entities also have parameters that are specific to the asset type so for the sake of example, let’s run through a few different types of assets and their parameters by adding torch_holder, snail, dungeon_alcove and scroll entities to the level.

The torch holder has an “Add Torch” parameter which, when the checkbox is ticked, will add a burning torch which will illuminate the surroundings and which the player can pick up.

You can change a monster’s behaviour with the “AI State” drop down box: the default state is that the monster will wander around in the dungeon by itself and the guard state will make the monster stand in place until it sees or otherwise senses the player.

In the alcove’s inspector you can add items for the player to discover from the alcove. Just start typing the name of an asset (say, a dagger for instance) in the “Add New Item” text field and the text will autocomplete itself as you type to make it quicker to locate and add items to it. You can add items into sacks and other containers the same way.

And finally, you can add a text on a scroll for the player to read. If you want to have text on multiple lines, typing \n inserts a line break.

Connectors
When looking at the parameters of the torch holder and the alcove you might have noticed a peculiar looking “Add Connector” button. It is a simple but powerful way of creating all sorts of contraption, puzzles, traps and logic into the levels. To try it out, add a dungeon_pressure_plate and a dungeon_door_portcullis into the dungeon and select the pressure plate and click on “Add Connector”. Connectors are simply a way of creating gameplay logic by defining that when an event happens to the pressure plate, a target entity performs an action. In this case for example, we can make the portcullis to open when a weight is placed on the pressure plate and to close when the weight is taken off. To start off, let’s first define the portcullis as the target of the connector by pressing the “?” button by the “Target” text field and then clicking on the portcullis on the Map View. This will add the ID of the portcullis into the target text field and, to illustrate the connection, an arrow is drawn between the entities on the map view.

Now, the pressure plate is already functional and you can try it out in the preview but it’s not doing exactly what we want it to do quite yet: now when you step on it the door opens as it should but when you step off the plate the door still stays open. If we take a closer look, we can spot two problems: 1) we only have an action that opens the door and 2) we only perform an action when the pressure plate is activated. Pressure plates, alcoves, levers and similar assets have two events: activate and deactivate. The activate event happens when a weight is put on a pressure plate or an alcove, a lever is pulled down and deactivate happens when the opposite is done. In this case we need the door to open when the plate is activated and the door to close when the plate is deactivated. You could simply add a second connector to the pressure plate that closes the door when the plate is deactivated but an alternate, and perhaps a little more elegant solution, would be if we just use a single connector with the event type of “any” (so that the action is taken on both activate and deactivate) and then send a “toggle” (which will open the door if is closed and vice versa) action to the portcullis.

Image

Hidden Pressure Plates, Secrets and Spawners
If you ever need to trigger events without the player noticing that he has just stepped on a pressure plate, a good way to do it is to use pressure_plate_hidden asset: it has the same functionality as the normal pressure plate has but you just simply can’t see it. Just keep in mind that if you don’t want monsters or thrown items to accidentally trigger the hidden pressure plate, be sure to disable those parameters from the inspector. Good example cases where you often want to use hidden pressure plates are when you need to activate a secret or a spawner entity. Secrets are a special asset whose purpose are indicating it for the player when he has discovered a secret area and then tallying up the total number of secrets discovered in his game statistics. Spawners are a little more interesting since not only can you spawn monsters from it but you can use it to launch spells as well to create traps or puzzles. The cooldown parameter in a spawner defines in seconds how much time is needed before the spawner can spawn again if it is activated again. This can be useful in controlling the size of monster populations or to limit the total amount of fireballs flying through the air: a great number of spells can be very taxing on the game’s performance. A cooldown value of 0 means that the spawning speed is unlimited.

If you want to create “Spectral Relay” -style puzzles, you can spawn a blob spell (it’s a spell that the player cannot cast and its sole purpose is to be used in puzzles) and then catch the spell with a receptor and trigger something by adding a connector to it.

Using Counters and Timers
Counting things like button presses or triggering an event when a certain amount of keys are inserted into locks is a common occurrence in Legend of Grimrock levels. For most of these cases, using counter assets are the best, most simple solution. Counters are very straightforward: they just contain a single number that you can increment and decrement with connectors from other entities and you can also add connectors to the counter itself which will be triggered when the counter’s value reaches zero. So if you would want to create a button you need to press three times, you would need a counter whose initial value is 3 and then just make sure that a connector in the button has the counter entity as its target and decrement as its action. This means that any time you would press the button, the counter’s value goes down by 1 and after three presses the counter would reach 0 and any connectors added to the counter entity would be activated.

Doors that open with a delay or carefully timed sequences of events can be created by using timer assets. Timers are quite simple: if a timer is active, it waits for the duration of its timer interval -parameter (in seconds) and then activates its connectors. Once a timer is activated, it will not stop until something deactivates it so by default its connectors will be activated perpetually, once per timer interval. If you wish to stop the timer after a single completed cycle, just add a connector with the timer entity itself as the target and deactivate as the event.

More intricate sequences can be created by using counters along with timers. You can set a counter as the target of a timer’s connector, so it decrements a counter every time a timer ticks and then the counter triggers once reaching 0. You can even use multiple counters with different values to create even more intricate scenarios but when working on complex sequences, scripting can very easily be the easier, more elegant solution.
Define ... 'Lost.' Neverending Nights - The Neverwinter Machinima that WILL make you laugh!
Also read: Legend of Grimrock: Destiny's Chance here on the forum! Check out the site I made for Legend of Grimrock: Destiny's Chance.
User avatar
Sir Tawmis
Posts: 980
Joined: Mon Jul 30, 2012 8:15 am
Contact:

Re: Legend of Grimrock 1 Modding

Post by Sir Tawmis »

Levels, Wall Sets and Exporting
If you want to add more levels into your dungeon (and who wouldn’t?), you can do it by right clicking on a level’s name in the Project window. From the same context menu, you will find options for deleting levels or changing their order but take care when you are doing it since the levels need to line up: any pits you might have in the level need to have an empty space underneath and if you place a staircase that leads down (dungeon_stairs_down for instance), there needs to be a staircase entity in the same location (but with a reversed orientation) that leads up in the level below. Using the page up and page down -shortcuts for switching between levels can make it easier to align things between different floors.

From the same menu you can also access a level’s properties where you can change the name of the level or to swap its wall set or background music. Wall set is the base set of environment graphics any given level is constructed out of and it can be easily changed at any given time from the level properties. However, you should keep in mind that many assets are designed to work with a specific wallset only (they are indicated by dungeon_, temple_ and prison_ prefixes in the asset names) and some wallsets might contain assets that are not available for other wallsets. When changing the music, you need to make sure that the .ogg file you use is placed somewhere under the custom dungeon’s “mod_assets” folder, preferrably under the “sounds” subfolder.

When the level is ready for other players to try out, all you need to do is to publish it to Steam Workshop (only available for users who have the game on Steam) or to export it. Exporting packages the dungeon (along with any custom assets you might have) into a single .dat file which you can hand over to your friends to play or you can upload it to 3rd party services such as Grimrock Nexus. In the export and publish dialogs, which can be found from the File-menu on the top, you can define an author name and a description for the dungeon which will be displayed in the dungeon selection screen. Before sharing content you should familiarize yourself with the modding and asset usage terms.

After you have some custom dungeons to play, all you need to do is start a new game and pick a custom dungeon for you to explore! The game will look for custom dungeon .dat files from the “\Documents\Almost Human\Legend of Grimrock\Dungeons” directory in Windows or you can subscribe to custom dungeons in Steam Workshop and they will be automatically downloaded to the correct location.
Define ... 'Lost.' Neverending Nights - The Neverwinter Machinima that WILL make you laugh!
Also read: Legend of Grimrock: Destiny's Chance here on the forum! Check out the site I made for Legend of Grimrock: Destiny's Chance.
User avatar
Sir Tawmis
Posts: 980
Joined: Mon Jul 30, 2012 8:15 am
Contact:

Re: Legend of Grimrock 1 Modding

Post by Sir Tawmis »

Editor Keyboard Shortcuts

Select tool.....................1
Add object tool...............2
Draw walls tool...............3
Start preview..................F5
Stop preview..................Shift+F5
Toggle fullscreen preview...Ctrl-F
Previous level.................Page Up
Next level.....................Page Down
Nudge selection..............W,A,S,D and arrow keys
Rotate selection.............Q,E
Delete selection.............Delete
Open project................Ctrl-O
Save project.................Ctrl-S
Cut............................Ctrl-X
Copy..........................Ctrl-C
Paste.........................Ctrl-V
Set starting location.......Y
Expand selection...........Hold Shift while selecting
Remove from selection...Hold Ctrl while selecting
Clear selection.............Escape
Toggle collisions............F1
Open door...................Z
Kill monster.................K
Heal party...................H
Define ... 'Lost.' Neverending Nights - The Neverwinter Machinima that WILL make you laugh!
Also read: Legend of Grimrock: Destiny's Chance here on the forum! Check out the site I made for Legend of Grimrock: Destiny's Chance.
User avatar
Sir Tawmis
Posts: 980
Joined: Mon Jul 30, 2012 8:15 am
Contact:

Re: Legend of Grimrock 1 Modding

Post by Sir Tawmis »

Introduction to Scripting
Scripting is a vast topic so in the scope of these documents we can merely introduce you to the subject. Even though you can do a lot in the Dungeon Editor without ever touching scripting, I would encourage you to try it out since doing scripts, even very simple ones, will open a lot of new possibilities for your level designs. If you want to get started in programming in general, I think scripting in the Dungeon Editor and maybe creating a custom asset or two on the side is a good starting point since you can start off with very easy and simple scripts and then build up from there.

Level scripting in Legend of Grimrock is done using a programming language called Lua which is a very flexible language with a simple syntax and it’s a great language for getting started in programming too. Prior knowledge of Lua won’t be absolutely necessary here but I won’t be covering the details of Lua programming here either so even a cursory knowledge of scripting or programming in general will be helpful. But I’m sure you can get quite far even with just copying and pasting these examples and modifying them for your purposes too. I’m certain the modding community will also produce a great amount of scripts that will be available for anyone to use.

The game console is a very helpful tool when it comes to scripting (or for level design in general) and you can enable the console by editing the grimrock.cfg file (usually located in your “\Documents\Almost Human\Legend of Grimrock”). Then, you can access the console in the game preview window by pressing the tilde key (under Esc and above Tab) and run lines of script there. Also, messages that are printed from scripts will be displayed on the console and to get started with some practical stuff, let’s learn how to print a traditional “Hello world!” message!

Hello world
Scripts in the levels are contained in script_entity assets that you add to the map. Their location in the level typically doesn’t affect their functionality but for the sake of clarity it is usually a good idea to place the script entity close to what the script relates to. The scripts will be run when the dungeon is started for the first time but we can also run functions from the script entities by using the connectors from buttons, pressure plates, timers and other actuators. If we want to create a script that prints a message to the console any time when a button on a wall is pressed we would need to add a script entity to the level with the following script in it:

Code: Select all

-- hello world script
function hello()
	print("Hello world!")
end
The first line of the script is a comment, as indicated by the two dashes in front of the line, and therefore it will not be interpreted as code. In the following line we define a new function that we decide to simply call “hello” and next, between the function definition and its end statement, we have the piece of script that actually runs when some event in the game calls the hello-function.

The script is now completed but at this point if you would run the preview, the script would essentially do nothing since we don’t call the hello function from anywhere in the level yet, so let’s add a wall_button somewhere into the level and add a connector to the button and set the script entity as its target. At this point, the Action-field of the connector should show the name of the function (“hello”) so we can start the preview and press the wall button to see if “Hello world!” is printed to the console on top of the screen.

Any text printed using the print() function will only be visible on the console. If you need to output text that the player will also see, you should use hudPrint() instead.

So in practice, functions are a handy way for you to run pieces of script triggered by events (such as button presses) in the game. One script entity can contain multiple functions: just remember to pick the correct one when adding a connector.
Define ... 'Lost.' Neverending Nights - The Neverwinter Machinima that WILL make you laugh!
Also read: Legend of Grimrock: Destiny's Chance here on the forum! Check out the site I made for Legend of Grimrock: Destiny's Chance.
User avatar
Sir Tawmis
Posts: 980
Joined: Mon Jul 30, 2012 8:15 am
Contact:

Re: Legend of Grimrock 1 Modding

Post by Sir Tawmis »

How to Script a Combination Lock

Image

With this script, we will learn how to interact with other assets via script by doing a classic combination lock puzzle. To get started, we need three lever entities for the lock and a door of your choice we want to get open and a script_entity. Referring to an entity in the level from the script is done by using a unique ID. All the entities you add into a level will have an automatically generated unique ID assigned to them but when it comes to scripting, it often is helpful to rename them yourself so that they are easier to type and to remember. All IDs must contain only alphanumeric characters and underscores and the ID must start with a letter. You’ll also have to make sure that the IDs you define are unique so it generally is a good idea to avoid names that are too generic such as “door” or “lever”. So, for this puzzle let’s go to the first lever’s inspector and set its ID as combinationLever1 and do the same for the rest of the levers but just increment the number in the end of the IDs. And then, let’s set the ID of the door as combinationDoor. Alright, now we should have all the building blocks in place so let’s add the script:

Code: Select all

-- combination lock puzzle
function pullLever()
	if combinationLever1:getLeverState() == "activated" and
	combinationLever2:getLeverState() == "deactivated" and
	combinationLever3:getLeverState() == "activated" then
		combinationDoor:open()
	else
		combinationDoor:close()
	end
end
Before this script does anything, we need to add connectors to the levers: in each of the levers, add a connector with the script entity as its target and make sure that the pullLever function is defined as the action. And since we want to check if the puzzle is solved every time a lever is operated (instead of being only checked when a lever is pulled down) we need to use the event type of “any”.

In the script, within the pullLever function, we have one if-then-else conditional. We basically ask the state of each of the levers using the getLeverState method and if all the methods return a boolean value of true, then the script within the “then” block is run and if not, the script within the “else” block is run. In this case, the expected positions of the levers are down-up-down (activated levers have their handles in a downright position and vice versa). If the combination is deemed correct, we open the door and if not, we try to close it. Naturally the door will only actually close if the player has already managed to get it open once and therefore it can seem a little unnecessary to take closing the door into account too but paying attention to details like these can be important if you want the dungeon to appear to work logically from the player’s point of view.

If you encounter any problems when creating a script like this, you can use the print commands we learned previously to help us spot any potential problems. You could, for example, see what parts of the script are run by printing messages, for example print("hello!"), from them or we could see what states the levers actually return by adding print(combinationLever1:getLeverState(), combinationLever2:getLeverState(), combinationLever3:getLeverState()) within the pullLever function.
Define ... 'Lost.' Neverending Nights - The Neverwinter Machinima that WILL make you laugh!
Also read: Legend of Grimrock: Destiny's Chance here on the forum! Check out the site I made for Legend of Grimrock: Destiny's Chance.
User avatar
Sir Tawmis
Posts: 980
Joined: Mon Jul 30, 2012 8:15 am
Contact:

Re: Legend of Grimrock 1 Modding

Post by Sir Tawmis »

How to Add a Scroll With Text on an Alcove
It is not possible to define parameters, like the text for a scroll, for items that are added on alcoves or inside containers by using the inspector alone but it is possible to work around these limitations by scripting. First, let’s place an alcove into the level and set its ID to scrollAlcove and then let’s add the following script into a script_entity:

Code: Select all

local message = spawn("scroll")
message:setScrollText("This is an important\nmessage!")

scrollAlcove:addItem(message)
The first line of script defines a local variable called message which contains a spawned entity: a scroll item. On the next line, we set the text for the entity in the message-variable. The \n in the middle of the string is a line break. Then, on the last line, we add the item onto the alcove. This same method can be used to place items into containers such as sacks or wooden boxes too (the container can also subsequently be placed on an alcove too).
Define ... 'Lost.' Neverending Nights - The Neverwinter Machinima that WILL make you laugh!
Also read: Legend of Grimrock: Destiny's Chance here on the forum! Check out the site I made for Legend of Grimrock: Destiny's Chance.
User avatar
Sir Tawmis
Posts: 980
Joined: Mon Jul 30, 2012 8:15 am
Contact:

Re: Legend of Grimrock 1 Modding

Post by Sir Tawmis »

How to Script "Item on an Alcove" Puzzle
Riddles that prompt the player to insert an item of a specific type on an altar or an alcove is a classic RPG puzzle. To create such a puzzle in the Dungeon Editor, we need to know what items are placed on an alcove and, if an item of a specific type is found, trigger something like opening a door. For this example, we need to add an alcove and the item, in this case a pitroot_bread into the level. Change the alcove’s ID to itemPuzzleAlcove. Now we should be all set so let’s take a look at the script:

Code: Select all

function itemPuzzle()
   -- iterate through all contained items on alcove, checking for a matching name
   for i in itemPuzzleAlcove:containedItems() do
      if i.name == "pitroot_bread" then
         playSound("level_up")
         break
      end
   end
end
To get the script to trigger each time an item is added on it, we need to add a connector from the alcove into the script entity (make sure that itemPuzzle is set as its action) and tick the “Activate Always” checkbox. If the checkbox is not ticked, the script would be run only when the first item is placed on the alcove so it wouldn’t work correctly with multiple items.

But let’s go through the script now: the script is a short one but there’s actually a lot of things happening in those few lines, thanks to the for-loop. For-loops are probably familiar to anyone who has some programming experience but a quick and simple explanation of them would be that it’s a loop of code that is continuously run until it hits the condition that terminates the loop. In this loop, we process through all the objects found in the alcove using the containedItems-iterator (the loop terminates when it has gone through all the objects contained in the iterator) and we ask if the name-property of any of those objects matches what we are looking for. If a match is found, a delightful sound is played and the break-command terminates the for-loop to prevent multiple sounds from playing at once (resulting in a loud and distorted audio) if more than one pitroot breads have been inserted into the alcove.

With slight modifications, this piece of script can be used for many purposes. For example, when the following function is called, all teleporters in the current level will be deactivated:

Code: Select all

function deactivateTeleporters()
   for i in allEntities(party.level) do
      if i.name == "teleporter" then
         i:deactivate()
      end
   end
end
Instead of referring to a massive number of entities by their IDs, this can often be much more convenient and less prone for typos or misclicks. Just make sure that you’re not inadvertently controlling any entities you didn’t mean to!
Define ... 'Lost.' Neverending Nights - The Neverwinter Machinima that WILL make you laugh!
Also read: Legend of Grimrock: Destiny's Chance here on the forum! Check out the site I made for Legend of Grimrock: Destiny's Chance.
User avatar
Sir Tawmis
Posts: 980
Joined: Mon Jul 30, 2012 8:15 am
Contact:

Re: Legend of Grimrock 1 Modding

Post by Sir Tawmis »

Save Games and Variables
When creating scripts, you need to be aware of some limitations when it comes to save games. It is possible to create all sorts of variables, tables and whatnot to store data with Lua but the game itself will not necessarily be able save and load the data. Naturally you don’t need to worry about saving when dealing with “normal” assets, like counters, levers, timers and so on but when it comes to scripts a little more attention from the level designer is required. Local variables won’t be stored into save games and it’s preferable to use local variables always when you have data you only need temporarily. Script variables (or variables that are “global” but only within the script entity they are defined in) will be stored in save games but with these you need to be careful that they contain data that is compatible with save games. Script variables can contain numbers (3, 412, 0.15 etc.), strings (“Hello!” and such), booleans (true or false) and tables (which, logically, can not contain any other types of data besides numbers, strings, booleans or other tables). The following is a simple (and a rather silly) example of a script with a script variable and a local variable:

Code: Select all

-- super fun number guessing game!
counter = 0					-- this will be stored in the save
function numberGuess()
	counter = counter + 1
	local randomNumber = math.random(10)	-- this won't be saved
	if randomNumber == 10 then
		print("I guessed right and it took me only", counter, "tries!")
	else
		print("I guessed", randomNumber, "but I was wrong.")
	end
end
The counter-variable in the script would be saved because it is a script variable with a number in it but the randomNumber local variable won’t, which is preferable in this case since the randomNumber will always be generated again any time we need it while the counter is something we need to persist between saving and loading the game.

If you want to try out the super fun number guessing game, just add it as the target of a connector and give it a go! And if you want to increase the stakes, try to add the following as a reward: spawn(“dagger”, party.level, party.x, party.y, party.facing) and this as a punishment: damageTile(party.level, party.x, party.y, party.facing, 0, “physical”, 10) in to the if-then-else structure. You can find out the exact details of what spawn and damageTile can do from the scripting reference.

As a final note, here are various (most probably impractical) examples of what works and what doesn’t regarding variables:

Code: Select all

-- these variables and tables all work and will be stored in the save game:
startingHealth = 10
names = { "John", "Kate", "Boris" }
playerCharacter = {
	name = names[3],
	isAwesome = true,
	stats = { 4, 10, -2, startingHealth }
}

-- Use local variables in functions for data that doesn't need to be saved:
pears = 3
pineapples = 1
function countFruits()
	local fruits = pears + pineapples
	print("I have " .. fruits .. " delicious fruits.")
end

-- this doesn't work (upvalues are not supported):
local bananas = 1
function bananaSplit()
	bananas = bananas * 0.5
end

-- the following does not work when saving/loading:
-- (the variable contains the spawned object in it)
spawn("knife", 1, 16, 4, 0, "treasure")-- an item is spawned with ID of "treasure"
item = treasure
print(item.name, item.level)	-- prints "knife 1" to console

-- the following works because the variable contains just
-- a string instead of the object itself:
spawn("knife", 1, 16, 4, 0, "treasure")
item = "treasure"
print(findEntity(item).name, findEntity(item).level)

-- the following is okay since the object is contained in a local variable:
spawn("knife", 1, 16, 4, 0, "treasure")
function printTreasureLevel()
	local item = treasure
	print(item.name, item.level)
end
Define ... 'Lost.' Neverending Nights - The Neverwinter Machinima that WILL make you laugh!
Also read: Legend of Grimrock: Destiny's Chance here on the forum! Check out the site I made for Legend of Grimrock: Destiny's Chance.
User avatar
Sir Tawmis
Posts: 980
Joined: Mon Jul 30, 2012 8:15 am
Contact:

Re: Legend of Grimrock 1 Modding

Post by Sir Tawmis »

Scripting Reference
You are reading the Lua scripting reference manual for Legend of Grimrock. The focus of this document is on completeness rather than brevity. Refer to the tutorials for more detailed examples on how to use the material described here.

The Lua functions and methods described here can be accessed from a script entity and typed on the console.

In addition the following standard Lua functions can be used: tonumber, tostring, type, pairs, ipairs, and all functions in table, math and string modules. See the Lua reference manual for more details about their usage.

Accessing Entities
Almost all things in Legend of Grimrock are modeled as objects. There are two types of objects. Entities are game objects which are spawned in the dungeon either by placing them in the dungeon using the level editor or spawning them dynamically from a script. For example buttons, pressure plates, teleporters and the party are all entities. Each entity has an id, a string which identifies the entity uniquely. You can refer to an entity by simply typing it’s id. For example, the following script calls the rest() method on an entity with the id “party”:

party:rest()

All entities have the following properties that can be accessed with the dot operator:

“name” returns the name of the entity
“id” returns the unique identifier of the entity
“x” returns the x-coordinate of the entity on the map
“y” returns the y-coordinate of the entity on the map
“facing” returns the facing of the entity (0=north, 1=east, 2=south, 3=west)
“level” returns the dungeon level index of the entity
“class” returns the class name of the entity
For example, “torch1.x” would return the x-coordinate of the entity named “torch1”.

You can also refer to the script entity itself from its own script code using the implicit “self” variable. This can be handy if you need to refer to it’s coordinates. For example the following script prints the x- and y-coordinates of the script entity to the console:

print(self.x, self.y)

The second class of objects are objects that have no direct representation of them in the dungeon. For example, a Champion is an object that is contained inside the Party entity. You have no direct access to these objects but various functions return references to them. For example, the following script retrieves the first champion in the party and changes his name:

party:getChampion(1):setName("Jakob")

Global Functions
Entity Management
spawn(object, level, x, y, facing, [id])
Spawns a new object at given position on a dungeon level where x and y specify the x- and y-coordinates on the map and level is a level index. facing must be a number between 0 and 3 and it indicates the following directions: 0=north, 1=east, 2=south, 3=west. id parameter is optional. If given it must be an unique id in the context of the dungeon. If not given an unique id is automatically generated.

findEntity(id)
Returns an entity with given name or nil if no such entity exists.

entitiesAt(level, x, y)
Returns an iterator for entities at x,y in a given level.

allEntities(level)
Returns an iterator for all entities in a given level.

User Interface
hudPrint(text)
Prints a line of text to the text area at the bottom of the screen.

setMouseItem(item)
Sets the given item as mouse item, or destroys the mouse item if item is nil.

getMouseItem()
Returns the “mouse item”, the item attached to the mouse pointer. If there is no mouse item, nil is returned.

Sounds
playSound(sound)
Plays a sound effect. sound must be a name of a built-in or custom sound effect.

playSoundAt(sound, level, x, y)
Plays a sound effect at given position. sound must be a name of a built-in or custom sound effect.

Game Mechanics
rollDamage(power)
Returns a random amount of damage for an attack with given power.

damageTile(level, x, y, direction, flags, damageType, power)
Damages all creatures including the party in a given tile. direction specifies the direction of the attack for projectiles or melee attacks (0=north, 1=east, 2=south, 3=west). damageType must be one of the following: “physical”, “fire”, “poison”, “cold”, “shock”. Damage is rolled individually for all creatures using the power as base value. flags is a numeric bit field:

bit 0: monsters recoil from the impact
bit 1: ongoing damage such as poison cloud
bit 2: damage originated from champion with ordinal index 1
bit 3: damage originated from champion with ordinal index 2
bit 4: damage originated from champion with ordinal index 3
bit 5: damage originated from champion with ordinal index 4
bit 6: ignore immunities
bit 7: halve damage of back row party members
Bits 2-5 are used when dealing experience point awards. See also Champion:getOrdinal().

shootProjectile(projectile, level, x, y, direction, speed, gravity, velocityUp, offsetX, offsetY, offsetZ, attackPower, ignoreEntity, fragile, championOrdinal)
Shoots a projectile item. The parameters are:

projectile: the name of the item to shoot.
level,x,y: the initial position of the projectile in a level.
direction: the shooting direction (0=north, 1=east, 2=south, 3=west).
speed: the speed of the projectile (metres/second). Typical values around 10.
gravity: the gravity force in y-direction. Typical values around 0.
velocityUp: the initial velocity in y-direction. Typically set to 0.
offsetX,offsetY,offsetZ: 3D offset in world space from the center of cell.
attackPower: attack power of the projectile.
ignoreEntity: the entity to be ignored for collisions (or nil if the entity should not ignore any collisions).
fragile: a boolean flag, if set the projectile is destroyed on impact.
championOrdinal: a champion ordinal number, used for dealing experience points. This parameter is optional.
Misc
print(…)
Prints all arguments to the console.

completeGame([cinematicsFile])
Completes the game and optionally plays back a cinematics file. cinematicsFile must be a valid cinematics filename. Note, in the Dungeon Editor this function only prints “Game Completed” to the console.

getForward(direction)
Converts direction, a number between 0 and 3 corresponding to a compass direction, to delta-x and delta-y values.

getMaxLevels()
Returns the number of levels in the dungeon.

isWall(level, x, y)
Returns true if the given square contains solid wall.

getStatistic(stat)
Returns the value of a built-in statistic. Possible statistics are: “play_time”, “monsters_killed”, “items_found”, “secrets_found”, “treasures_found”, “toorum_notes_found”, “skulls_found”, “grimrock_doors_opened”, “tiles_moved”, “pit_falls”, “melee_attacks”, “ranged_attacks”, “unarmed_attacks”, “rocks_thrown”, “spells_cast” and “potions_mixed”.

Alcove
Alcove:addItem(item)
Adds an item to the alcove. For example Alcove:addItem(spawn(“dagger”)).

Alcove:containedItems()
Returns an iterator for items contained in the alcove.

Alcove:getItemCount()
Returns the number of items in the alcove.

Alcove:setActivateAlways(enable)
Enables the activate always mode for the alcove. Normally when an item is placed on an alcove, the alcove is triggered only if it was empty. Likewise the alcove is triggered when the last item is removed from it. With activate always the alcove is triggered every time an item is placed or removed from the alcove.

Alcove:addConnector(event, target, action)
Adds a new connector from the entity to a target entity. Event, target and action are strings. Using this method is equivalent to creating a connector in the inspector.

Alcove:destroy()
Removes the entity from the level.

Altar
Altars share the same scripting API with Alcoves. The only difference is that an alcove is a wall item while an altar is placed in the middle of a cell.

Blocker
Blocker:activate()
Activates the blocker. An active blocker prevents monsters from moving through the square where the blocker is located.

Blocker:deactivate()
Deactivates the blocker.

Blocker:toggle()
Toggles the blocker on and off.

Blocker:destroy()
Removes the entity from the level.

BurstSpell
BurstSpell:setAttackPower(power)
Overrides the attack power of the burst spell.

BurstSpell:destroy()
Removes the entity from the level.

Button
Button:setActivateOnce(once)
If set to true, the button can only be triggered once.

Button:push()
Simulates a push of the button as if the button had been operated by the player.

Button:addConnector(event, target, action)
Adds a new connector from the entity to a target entity. Event, target and action are strings. Using this method is equivalent to creating a connector in the inspector.

Button:destroy()
Removes the entity from the level.

Champion
Champion:setEnabled(enabled)
Enables or disables the champion. A disabled champion is essentially an empty party slot.

Champion:setName(name)
Sets the name of the champion.

Champion:setRace(race)
Sets the race of the champion. The race must be one of the following: “Human”, “Minotaur”, “Lizardman” or “Insectoid”.

Champion:setClass(class)
Sets the class of the champion. The class must be one of the following: “Fighter”, “Rogue”, “Mage” or “Ranger”.

Champion:setSex(gender)
Sets the gender of the champion. The gender must be either “male” or “female”. The gender determines the sounds to be played when the champion is damaged.

Champion:getEnabled()
Returns true if the champion is enabled and false if the champion is disabled.

Champion:getName()
Returns the name of the champion.

Champion:getRace()
Returns the race of the champion.

Champion:getClass()
Returns the class of the champion.

Champion:getSex()
Returns the gender of the champion.

Champion:getLevel()
Returns the current level of the champion.

Champion:getOrdinal()
Returns champion’s ordinal index between 1 and 4. The ordinal index is an unique identifier for the champion. It is guaranteed that the ordinal index never changes after character creation.

Champion:setPortrait(filename)
Sets the image file to be used as champion’s portrait. The portrait must be a valid TGA file of size 128*128 pixels. The file must be located in “mod_assets” folder or contained in the base game archive.

Champion:isAlive()
Returns true if the champion is alive.

Champion:gainExp(amount)
Gives a number of experience points to the champion.

Champion:levelUp()
Gives just enough experience points to get to the next level.

Champion:getSkillPoints()
Returns the number of unused skill points.

Champion:addSkillPoints(amount)
Gives a number of skill points to the champion.

Champion:getSkillLevel(skill)
Returns the current level of a skill. The skill must be one of the following: “air_magic”, “armors”, “assassination”, “athletics”, “axes”, “daggers”, “dodge”, “earth_magic”, “fire_magic”, “ice_magic”, “maces”, “missile_weapons”, “spellcraft”, “staves”, “swords”, “throwing_weapons” and “unarmed_combat”.

Champion:trainSkill(skill, levels, dontSpendPoints)
Increases a skill by a number of levels. If dontSpendPoints is true, skill points are not spent for leveling up the skill.

Champion:consumeFood(amount)
Consumes an amount of food taking racial food consumption rate and other factors into account.

Champion:modifyFood(amount)
Adds amount to current food stat directly without applying any modifiers. Amount can be a signed value.

Champion:getFood()
Returns champion’s current food value.

Champion:setCondition(condition, value)
Sets the value of a condition. The interpretation of value depends on the condition but it corresponds roughly to the number of seconds that the condition should last. The condition must be one of the following: “poison”, “diseased”, “paralyzed”, “haste”, “rage”, “fire_shield”, “shock_shield”, “poison_shield”, “frost_shield”, “invisibility”.

Champion:setConditionCumulative(condition, value)
Sets the value of a condition to the maximum of current value and the parameter value. I.e. this method has the same effect as:
champion:setCondition(condition, math.max(champion:getCondition(condition), value)).

Champion:getCondition(condition)
Returns the current value of a condition, or zero if the champion does not have the condition.

Champion:hasCondition(condition)
Returns true if the champion has a condition, i.e. the condition value is greater than zero.

Champion:damage(amount, type)
Deals damage to the champion. Type must be “physical”, “fire”, “shock”, “poison” or “cold”.

Champion:playDamageSound()
Plays the damage sound which is determined by champion’s race and gender.

Champion:setStat(stat, value)
Sets the base value of a statistic. The value of a stat cannot exceed its maximum value and the new value is clamped to the maximum value. Stat must be one of the following: “health”, “energy”, “strength”, “dexterity”, “vitality”, “willpower”, “protection”, “evasion”, “resist_fire”, “resist_cold”, “resist_poison”, “resist_shock”.

Champion:setStatMax(stat, value)
Sets the maximum value of a statistic.

Champion:modifyStat(stat, amount)
Adds amount to the value of a statistic. Same as calling
champion:setStat(stat, champion:getStat(stat) + amount).

Champion:modifyStatCapacity(stat, amount)
Adds amount to the maximum value of a statistic. Same as calling
champion:setStatMax(stat, champion:getStatMax(stat) + amount).

Champion:getStat(stat)
Returns the value of a statistic.

Champion:getStatMax(stat)
Returns the maximum value of a statistic.

Champion:getProtection()
Returns the current protection value of the champion.

Champion:getEvasion()
Returns the current evasion value of the champion.

Champion:getResistance(element)
Returns the elemental damage resistance value for an element. Element must be “fire”, “shock”, “poison” or “cold”.

Champion:getLoad()
Returns the current load of the champion in kilograms.

Champion:getMaxLoad()
Returns the maximum carrying capacity of the champion in kilograms.

Champion:insertItem(slot, item)
Inserts an item to an equipment slot. Slot must be one of the following: 1 (head), 2 (torso), 3 (legs), 4 (feet), 5 (cloak), 6 (neck), 7 (left hand), 8 (right hand), 9 (gaunlets), 10 (bracers), 11-31 (backpack slots).

Champion:removeItem(slot)
Removes an item from an equipment slot.

Champion:getItem(slot)
Returns an item in an equipment slot.

Champion:addTrait(trait, silent)
Gives a given trait to the champion. If silent is true there is no hud print. Trait must be one of the following:
“aggressive”, “agile”, “athletic”, “aura”, “cold_resistant”, “evasive”, “fire_resistant”, “fist_fighter”, “head_hunter”, “healthy”, “lightning_speed”, “natural_armor”, “poison_resistant”, “skilled”, “strong_mind”, “tough”.

Champion:removeTrait(trait)
Removes a given trait from the champion.

Champion:hasTrait(trait)
Returns true if the champion has a given trait.

Counter
Counter:setValue(value)
Sets the value of the counter.

Counter:getValue()
Returns the current value of the counter.

Counter:reset()
Resets the counter to the initial value.

Counter:increment()
Increments the value of the counter by 1.

Counter:decrement()
Decrements the value of the counter by 1.

Counter:addConnector(event, target, action)
Adds a new connector from the entity to a target entity. Event, target and action are strings. Using this method is equivalent to creating a connector in the inspector.

Counter:destroy()
Removes the entity from the level.

Door
Door:open()
Opens the door.

Door:close()
Closes the door.

Door:activate()
Same as Door:open().

Door:deactivate()
Same as Door:close().

Door:toggle()
Opens the door if it is closed, otherwise closes it.

Door:isOpen()
Returns true if the door is open.

Door:isClosed()
Returns true if the door is closed.

Door:addPullChain()
Adds a pullchain to the door. This function is intended to be used internally by the editor. Do not attempt to add a pullchain dynamically to a door from a script because it may cause problems with save games. This function is listed here only for completeness.

Door:setDoorState(state)
Sets door’s state immediately without playing animation and sound effects. State must be “open” or “closed”.

Door:setOpenedBy(key)
Sets the name of the item which can be used to unlock this door. Works only with doors with built-in locks.

Door:destroy()
Removes the entity from the level.

FX
FX:setParticleSystem(name)
Sets the particle system to be played when the FX is first updated.

FX:setLight(red, green, blue, brightness, range, time, castShadow)
Sets the light effect to be played when the FX is first updated. Red, green and blue define the color of the emitted light in range 0-1, brightness is light’s brightness typically in range 0-20, range is light’s range in world units (meters), time is the length of the effect in seconds, castShadow is a boolean flag which enables shadow casting for the light source. Large range and shadow casting can cause drops in frame rate.

FX:translate(x, y, z)
Translates (i.e. moves) the FX by x,y,z in world space. This function is typically used to lift particle system off the ground.

FX:destroy()
Removes the entity from the level.

Item
Item:setScrollText(text)
Sets the text for a scroll item. Lines are separated with ‘\n’ characters.

Item:setScrollImage(filename)
Sets custom scroll image to be displayed in the tooltip.

Item:setSubtileOffset(x, y)
Sets item’s relative position to the center of tile.

Item:setCharges(charges)
Sets the number of charges remaining.

Item:setFuel(fuel)
Sets the remaining fuel (in seconds) for torches.

Item:setStackSize(stackSize)
Sets the stack size for stackable items.

Item:getScrollText()
Returns the text of a scroll item.

Item:getScrollImage()
Returns the filename of the custom scroll image if it exists.

Item:getWeight()
Returns the weight of the item. Returns the total weight of a stack for stackable items.

Item:getUIName()
Returns the user interface name of the item.

Item:getCharges(charges)
Returns the number of charges remaining.

Item:getFuel(fuel)
Returns the remaining fuel (in seconds) for torches.

Item:getStackSize()
Returns the stack size for stackable items or 0 if the item is not stackable.

Item:containedItems()
Returns an iterator for contained items.

Item:addItem(item)
Adds a given item to a free container slot.

Item:insertItem(slot, item)
Inserts an item into given container slot.

Item:removeItem(slot)
Removes an item from a container slot.

Item:getItem(slot)
Returns the item in a given container slot.

Item:destroy()
Removes the entity from the level.

Lever
Lever:setLeverState(state)
Sets lever’s state immediately without playing animation and sound effects. State must be “activated” or “deactivated”.

Lever:setInverted(inverted)
Inverts the message to be sent when the lever is toggled, e.g. “activate” becomes “deactivate” and vice versa.

Lever:toggle()
Simulates a pull of the lever as if the lever had been operated by the player.

Lever:getLeverState()
Returns the state of the lever, either “activated” or “deactivated”.

Lever:addConnector(event, target, action)
Adds a new connector from the entity to a target entity. Event, target and action are strings. Using this method is equivalent to creating a connector in the inspector.

Lever:destroy()
Removes the entity from the level.

LightSource
LightSource:activate()
Turns on the light source.

LightSource:deactivate()
Turns off the light source.

LightSource:toggle()
Toggles the light source on and off.

LightSource:destroy()
Removes the entity from the level.

Lock
Lock:setOpenedBy(key)
Sets the name of the item which can be used to unlock this lock.

Lock:addConnector(event, target, action)
Adds a new connector from the entity to a target entity. Event, target and action are strings. Using this method is equivalent to creating a connector in the inspector.

Lock:destroy()
Removes the entity from the level.

Monster
Monster:setAIState(state)
Sets the AI state of the monster, which can be one of the following:
“default” the monster wanders lazily around in the dungeon, or
“guard” the monster waits in place until it sees or otherwise senses the party.

Monster:setHealth(health)
Sets monster’s health. Increases max health to accommodate the new health value if necessary.

Monster:setLevel(level)
Advances the monster in levels by giving it more health as specified by its level health adjustment property.

Monster:getHealth()
Returns monster’s current health.

Monster:getLevel()
Returns monster’s experience level.

Monster:addItem(item)
Adds an item to be carried by the monster. When the monster dies all items carried are dropped to ground.

Monster:destroy()
Removes the entity from the level.

Monster:setPosition(x, y, facing, level)
Instantly moves the monster to given location in the dungeon.

Party
Party:heal()
Restores all characters to full health and removes all harmful conditions.

Party:rest()
Puts the party to sleep.

Party:wakeUp(immediate)
Wakes up the party. If the immediate parameter is true, it indicates that the rest was interrupted abruptly, e.g. a monster attacked the party. The screen fades from black much quicker in this case.

Party:isResting()
Returns true if the party is resting.

Party:swapChampions(slot1, slot2)
Swaps the champions in slots slot1 and slot2. Slots must be in range 1-4.

Party:getChampion(slot)
Returns the champion in given slot (1-4).

Party:shakeCamera(intensity, duration)
Shakes the camera. Intensity is in the range 0-1 and duration is a length of the camera shake in seconds.

Party:playScreenEffect(particleSystem)
Plays an on-screen particle system. particleSystem refers to a particle system defined using the defineParticleSystem function.

Party:setPosition(x, y, facing, level)
Instantly moves the party to given location in the dungeon.

Pit
Pit:open()
Opens the pit. This has no effect if the pit does not have a trap door.

Pit:close()
Closes the pit. This has no effect if the pit does not have a trap door.

Pit:activate()
Same as Pit:open().

Pit:deactivate()
Same as Pit:close().

Pit:toggle()
Opens the pit if it is closed, otherwise closes it.

Pit:setPitState(state)
Sets the state of the pit immediately without playing animations or sound effects. State must be either “open” or “closed”.

Pit:isOpen()
Returns true if the pit is open.

Pit:isClosed()
Returns true if the pit is closed.

Pit:addTrapDoor()
Adds a trap door to the pit so that it can be closed. This function is intended to be used internally by the editor. Do not attempt to add a trap door dynamically to a pit from a script because it may cause problems with save games. This function is listed here only for completeness.

Pit:destroy()
Removes the entity from the level.

PressurePlate
PressurePlate:setTriggeredByParty(enable)
Sets whether the pressure plate is activated when the party steps on the plate.

PressurePlate:setTriggeredByMonster(enable)
Sets whether the pressure plate is activated when a monster steps on the plate.

PressurePlate:setTriggeredByItem(enable)
Sets whether the pressure plate is activated when an item is placed on the plate.

PressurePlate:setActivateOnce(enable)
If set to true, the pressure plate can only be triggered once.

PressurePlate:setInverted(enable)
Inverts the message to be sent when the pressure plate is activated, e.g. “activate” becomes “deactivate” and vice versa.

PressurePlate:setSilent(enable)
Sets whether the pressure plate makes a sound when it activates.

PressurePlate:isDown()
Returns true if the pressure plate is down.

PressurePlate:isUp()
Returns true if the pressure plate is up.

PressurePlate:addConnector(event, target, action)
Adds a new connector from the entity to a target entity. Event, target and action are strings. Using this method is equivalent to creating a connector in the inspector.

PressurePlate:destroy()
Removes the entity from the level.

ProjectileSpell
ProjectileSpell:setAttackPower(power)
Overrides the attack power of the projectile spell.

ProjectileSpell:destroy()
Removes the entity from the level.

Receptor
Receptor:setEntityType(entityType)
Sets the entity type which triggers the receptor. The receptor is a special wall trigger which activates when an entity of the specified type hits it.

Receptor:addConnector(event, target, action)
Adds a new connector from the entity to a target entity. Event, target and action are strings. Using this method is equivalent to creating a connector in the inspector.

Receptor:destroy()
Removes the entity from the level.

Secret
Secret:activate()
Marks the secret as found.

Secret:destroy()
Removes the entity from the level.

Spawner
Spawner:activate()
Spawns a new entity as specified by the spawned entity property. The spawner is then temporarily disabled for a period of time specified by the cool down property.

Spawner:setSpawnedEntity(name)
Sets the name of the entity to be spawned when the spawner is activated.

Spawner:setCoolDown(time)
Sets the cool down time in seconds.

Spawner:destroy()
Removes the entity from the level.

Teleporter
Teleport:activate()
Activates the teleporter.

Teleport:deactivate()
Deactivates the teleporter.

Teleport:toggle()
Toggles the teleporter on and off.

Teleport:isActivated()
Returns true if the teleporter is activated.

Teleport:setTriggeredByParty(enable)
Sets whether the teleporter teleports the party. Default is true.

Teleport:setTriggeredByMonster(enable)
Sets whether the teleporter teleports monsters. Default is true.

Teleport:setTriggeredByItem(enable)
Sets whether the teleporter teleports items. Default is true.

Teleport:setTeleportTarget(x, y, facing, [level])
Sets the target for teleportation. The level parameter is optional. It can be a level index, or “up” or “down”, in which case the parameter is interpreted as the level above and below the teleporter.

Teleport:setChangeFacing(enable)
If enabled teleported entities have their facing turned according to the teleport target. This property is set by default. If the parameter is false, the teleporter does not change the facing of teleported entities.

Teleport:setInvisible(enable)
Makes the teleporter invisible if the parameter is true, or visible if the parameter is false.

Teleport:setHideLight(enable)
Hides or unhides the dynamic light source attached to the teleporter. Useful for improving performance when there is a lot of teleporters close together in a level.

Teleport:setSilent(enable)
Makes the teleporter silent if the parameter is true, or audible if the parameter is false.

Teleport:setScreenFlash(enable)
Sets the state of the screen flash effect which is played when the party steps into the tele porter. If the parameter is true the screen flash effect is enabled, otherwise the effect is disabled.

Teleport:destroy()
Removes the entity from the level.

Timer
Timer:activate()
Activates the timer.

Timer:deactivate()
Deactivates the timer.

Timer:toggle()
Toggles the timer on and off.

Timer:isActivated()
Returns true if the timer is activated.

Timer:setTimerInterval(interval)
Sets the timer interval in seconds.

Timer:addConnector(event, target, action)
Adds a new connector from the entity to a target entity. Event, target and action are strings. Using this method is equivalent to creating a connector in the inspector.

Timer:destroy()
Removes the entity from the level.

TorchHolder
TorchHolder:addItem(item)
Adds an item to the torch holder. The item must be of type torch and only one torch may be inserted into the torch holder at one time.

TorchHolder:addTorch()
Shortcut for “TorchHolder:addItem(spawn(“torch”))”.

TorchHolder:hasTorch()
Returns true if there is a torch in the torch holder.

TorchHolder:setSilent(enable)
If the parameter is true the crackling flame sound is turned off. False makes the torch holder audible again.

TorchHolder:addConnector(event, target, action)
Adds a new connector from the entity to a target entity. Event, target and action are strings. Using this method is equivalent to creating a connector in the inspector.

TorchHolder:destroy()
Removes the entity from the level.

WallText
WallText:setWallText(text)
Sets the text which is display when the wall text is clicked with the mouse. Multiple lines can be separated with ‘\n’ characters.

WallText:getWallText()
Returns the wall text string.

WallText:destroy()
Removes the entity from the level.
Define ... 'Lost.' Neverending Nights - The Neverwinter Machinima that WILL make you laugh!
Also read: Legend of Grimrock: Destiny's Chance here on the forum! Check out the site I made for Legend of Grimrock: Destiny's Chance.
Locked