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:

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:

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!