Yet another alcove question!

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
Post Reply
guigr
Posts: 16
Joined: Wed Apr 11, 2012 10:58 pm

Yet another alcove question!

Post by guigr »

I'm having a puzzle where I want to have some items in an alcove in order to open a door. It works well using a code taken here but you can just remove the item and the door will stay open.

Code: Select all

function checkAlcoveForItems()
   local itemName = "chitin_boots"
   local alcoveID = dungeon_alcove_3

   for i in alcoveID:containedItems() do
      if i.name == itemName then
         itemFound()
porte1:open()
      end
   end
end
So I tried to do a variation of this code activated by a pressure plate to check if the item was still is the alcove. But it doesn't work. Can someone help me here?

Code: Select all

function secondcheck()
   local itemName = "chitin_boots"
   local alcoveID = dungeon_alcove_3
   
   for i in alcoveID:containedItems() do
      if i.name == itemName then
porte1:open()
      else
porte1:close()
      end
   end
end
User avatar
antti
Posts: 688
Joined: Thu Feb 23, 2012 1:43 pm
Location: Espoo, Finland
Contact:

Re: Yet another alcove question!

Post by antti »

There's two possible pitfalls here that I can think of:
1) You need to add a connector for the alcove deactivation too (activation happens when items are added on the alcove and deactivation happens when the last item is removed from alcove, both activation and deactivation are needed in this case to cover all the possible cases)
2) The structure in the script probably does not work well for multiple items. For example if I first add the chitin boots to the alcove (the correct item), the door will open but then if I add another item after it, it would close again since the for loop would keep on running. To prevent it, I would add a break that will terminate the for-loop as soon as the correct item is found like so:

Code: Select all

function secondcheck()
   local itemName = "chitin_boots"
   local alcoveID = dungeon_alcove_3
   
   for i in alcoveID:containedItems() do
      if i.name == itemName then
         porte1:open()
         break
      else
         porte1:close()
      end
   end
end
For more information, check out this guide I just added on the modding documentation: http://www.grimrock.net/modding/how-to- ... ve-puzzle/
Steven Seagal of gaming industry
guigr
Posts: 16
Joined: Wed Apr 11, 2012 10:58 pm

Re: Yet another alcove question!

Post by guigr »

Thanks it works now!
I understand that it was doing the check only if there was an item there (for example a torch). If there was no item it wouldn't close the door. So I've told the alcove to close the door on deactivate and it seems to work.
Lilltiger
Posts: 95
Joined: Sun Sep 16, 2012 1:12 am

Re: Yet another alcove question!

Post by Lilltiger »

Edited: Added the exclusive check option, that only opens when it's the exactly specified items and no others
Edited: Fixed the code, there where some flaws in it.


Or you could do it in a more generic and nifty way:

Code: Select all

function checkForItems()
  -- You cant use the alcove and altars connections to trigger, as they do only activate for the first
  -- item added, or when the last one is removed, so use a lever or a pressure plate
  -- to activate the check instead

  if( checkForContainedItem(dungeon_alcove_3, "chitin_boots") ) then
    porte1:open()
  else
   porte1:close()
  end
end

function checkForContainedItem(container, itemName)
   for i in container:containedItems() do
      if( i.name == itemName ) then
         return true
      end
   end
  return false
end
But this only checks for one item, so let's expand it to check for multiple items:

Code: Select all

function checkForItems()
  -- You cant use the alcove and altars connections to trigger, as they do only activate for the first
  -- item added, or when the last one is removed, so use a lever or a pressure plate
  -- to activate the check instead

  -- Let's make an table of the item names to check
  --  Tables in LUA are a bit like array's in c, but still quite different, check the LUA docs

  item_name_table = {"chitin_boots","dagger","torch"}

  if( checkForContainedItem(dungeon_alcove_3, item_name_table, true ) ) then
    porte1:open()
  else
   porte1:close()
  end
end

function checkForContainedItem(container, itemNameTable, exclusive)
   if( exclusive ) then 
      return checkForContainedItemExclusive(container, itemNameTable)
   else
      return checkForContainedItemUnExclusive(container, itemNameTable)
   end
end

function checkForContainedItemUnExclusive(container, itemNameTable)
   local items_found = 0
   -- The outer loop needs to be the names,
   -- else we will trigger the items_found count several times for the same name.
   for id,names in ipairs(itemNameTable) do
      for i in container:containedItems() do      
         if( i.name == names) then
            -- If the item name and the item matches, add to the counter
            items_found = items_found+1
            -- Now we need to break out of this check to avoid triggering the same name twice
            -- A break exits the current/inner loop, but the outer loop will continue
            break
         end
      end
   end

   -- Now we check if we have found as many items as there are names in the table
   if( items_found == table.getn( itemNameTable ) ) then
       -- Return the value true, this also ends the function
       return true
   end

   -- Return false in all other cases, no need for an else in the above "if" as the function end's as soon
   -- it hit's a "return"
   return false
end

function checkForContainedItemExclusive(container, itemNameTable)
   items_found = 0
   -- Here we use the container as outerloop as we will return false as soon we get a missmatch
   for i in container:containedItems() do
      name_check = false
      for id,names in ipairs(itemNameTable) do
         
         if( i.name == names) then
            -- If the item name and the item matches, add to the counter, and set the name_check to true
            items_found = items_found+1
            name_check = true
            -- Now we need to break out of this check to avoid triggering the same name twice
            -- A break exits the current/inner loop, but the outer loop will continue
            break
         end

      end
      -- If name_check is false, then we found a item not named in our table, so return false
      if( name_check == false ) then
        return false
      end
   end

   -- Now we check if we have found as many items as there are names in the table
   -- This check wont pass if there are more of one item type then allowed.
   if( items_found == table.getn( itemNameTable ) ) then
       -- Return the value true, this also ends the function
       return true
   end

   -- Return false in all other cases, no need for an else in the above "if" as the function end's as soon
   -- it hit's a "return"
   return false
end
And there we have it, this functions works for all container objects, so both Alcove and Altar.

The code is tested and works, after some fixes :ugeek:
guigr
Posts: 16
Joined: Wed Apr 11, 2012 10:58 pm

Re: Yet another alcove question!

Post by guigr »

Wow, did you read my mind? I wanted it to work with multiple items but was not sure if it was worth the trouble.
Thanks a lot!
User avatar
petri
Posts: 1917
Joined: Thu Mar 01, 2012 4:58 pm
Location: Finland

Re: Yet another alcove question!

Post by petri »

You cant use the alcove and altars connections to trigger, as they do only activate for the first item added, or when the last one is removed
Actually you can, just tick Activate Always in inspector.
Post Reply