Pressure Plate Question

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
Post Reply
Ryeath_Greystalk
Posts: 366
Joined: Tue Jan 15, 2013 3:26 am
Location: Oregon

Pressure Plate Question

Post by Ryeath_Greystalk »

I figured out how to add connectors to pressure plates in a script entity, but wat I am hhoping for is a way to remove connectors in a script entity. Ideally a remove all connectors would be awesome. Anyone know if this is possible. What I am trying to do is use one pressure plate to control different doors depending on the posistion of some wall levers.

So far

Code: Select all

function SetPressurePlateTarget()	
	if NorthLever:getLeverState()=="deactivated" and
	SouthLever:getLeverState()=="deactivated" then
		VariablePlate1:addConnector("activate","NorthwestDoor","toggle")
	else
	if NorthLever:getLeverState()=="activated" and
	SouthLever:getLeverState()=="activated" then
		VariablePlate1:addConnector("activate","SoutheastDoor","toggle")	
	else
	if NorthLever:getLeverState()=="deactivated" and
	SouthLever:getLeverState()=="activated" then
		VariablePlate1:addConnector("activate","NortheastDoor","toggle")
	else
	if NorthLever:getLeverState()=="activated" and
	SouthLever:getLeverState()=="deactivated" then
		VariablePlate1:addConnector("activate","SouthwestDoor","toggle")
				end
			end
		end
	end
end


But the problem is the connectors just stack instead of replacing the previous one.

Any suggestions?

Thanks in advance.
dasarby
Posts: 28
Joined: Sun Dec 30, 2012 10:46 pm

Re: Pressure Plate Question

Post by dasarby »

As best I can tell, there is no good way to remove a connector once its been added (I kinda suspect the addConnector function is meant to be used by the editor, not directly from scripts, but it is convenient for some things).

The work around I use is to use a script level variable to flag which things have been connected to what, and then don't run addConnector if it as already been connected, and then using some other flag to indicate if the script should run.

I suspect, though, that for your case you can accomplish this without using addConnector. It seems to me you have two levers, NorthLever and SouthLever, and a pressure plate which when activated opens a different grate based on which combo of levers is down, ya? If so, you probably want the following instead.

Instead of wiring the pressure plate to the appropriate door, just open the door directly from the script.

Code: Select all

function OpenSelectedDoor()
	if NorthLever:getLeverState()=="deactivated" and SouthLever:getLeverState()=="deactivated" then
		NorthwestDoor:open()
   elseif NorthLever:getLeverState()=="activated" and SouthLever:getLeverState()=="activated" then
   		SoutheastDoor:open()
   elseif NorthLever:getLeverState()=="deactivated" and SouthLever:getLeverState()=="activated" then
   		NortheastDoor:open()
   elseif NorthLever:getLeverState()=="activated" and SouthLever:getLeverState()=="deactivated" then
   		NortheastDoor:close()
   end
end
Then add a connector from your pressure place to that function. Add a deactivate connector from your place to each door to close them all. That should have the same effect as what your trying to do.
Ryeath_Greystalk
Posts: 366
Joined: Tue Jan 15, 2013 3:26 am
Location: Oregon

Re: Pressure Plate Question

Post by Ryeath_Greystalk »

Thanks dasarby.

You understand perfectly what I was trying to accomplish. I will give your method a try.
Ryeath_Greystalk
Posts: 366
Joined: Tue Jan 15, 2013 3:26 am
Location: Oregon

Re: Pressure Plate Question

Post by Ryeath_Greystalk »

It worked perfectly.

My final code ended up being

Code: Select all

function SetPressurePlateTarget()	
	if NorthLever:getLeverState()=="deactivated" and
	SouthLever:getLeverState()=="deactivated" then
		NorthwestDoor:open()
		SouthwestDoor:close()
		SoutheastDoor:close()
		NortheastDoor:close()
	else
	if NorthLever:getLeverState()=="activated" and
	SouthLever:getLeverState()=="activated" then
		SoutheastDoor:open()
		NortheastDoor:close()
		NorthwestDoor:close()
		SouthwestDoor:close()	
	else
	if NorthLever:getLeverState()=="deactivated" and
	SouthLever:getLeverState()=="activated" then
		NortheastDoor:open()
		NorthwestDoor:close()
		SoutheastDoor:close()
		SouthwestDoor:close()
	else
	if NorthLever:getLeverState()=="activated" and
	SouthLever:getLeverState()=="deactivated" then
		SouthwestDoor:open()
		SoutheastDoor:close()
		NorthwestDoor:close()
		NortheastDoor:close()
				end
			end
		end
	end
end
Much appreciate the help.
User avatar
Komag
Posts: 3659
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: Pressure Plate Question

Post by Komag »

Let's clean that up a little: ;)

Code: Select all

function SetPressurePlateTarget()
   local N = false
   local S = false
   if NorthLever:getLeverState()=="activated" then N = true end
   if SouthLever:getLeverState()=="activated" then S = true end
   if       not N and not S then _doors("Northwe")
     elseif     N and     S then _doors("Southea")
     elseif not N and     S then _doors("Northea")
     elseif     N and not S then _doors("Southwe")
   end
end

function _doors(dir)
  for i in allEntities(party.level) do
    if i.id:sub(8,13) == "stDoor" then i:close() end
  end
  local i = findEntity(dir.."stDoor")
  if i then i:open() end
end
Finished Dungeons - complete mods to play
Ryeath_Greystalk
Posts: 366
Joined: Tue Jan 15, 2013 3:26 am
Location: Oregon

Re: Pressure Plate Question

Post by Ryeath_Greystalk »

Thanks for taking the time to clean up the code Komag.

I pretty sure I understand the first function. The "if" statement needs to return "true" to operate _doors("Northwe") function.
So if both levers are up then N=false and S=false, so then they get inverted by the "not" function, which would make two "trues" and thus call the open door function. And so forth.

The second part is way over my head for now, but I will look up those commands later today and see if I can figure it out.
dasarby
Posts: 28
Joined: Sun Dec 30, 2012 10:46 pm

Re: Pressure Plate Question

Post by dasarby »

I see a potental problem with Komag's, namely closing the doors by finding all and substring matching. It is possible (albeit probably unlikely :D) that it will close another door that is not part of the puzzle. For example, if you had a door named "HallFirstDoor", it would also get closed, because it is 13 letters long and ends in "stDoor".

More nitpickingly, it seems unnecessary to use allEntities here; we know the ids of the doors, so why loop across everything on the level? True, the loop is probably pretty fast, but for levels with large amounts of entities you might notice a slowdown. It seems clearer and faster to just loop across the doors we want, close them all, and then open the door directly:

Code: Select all

function SetPressurePlateTarget()
  local N = NorthLever:getLeverState() == "activated"
  local S = SouthLever:getLeverState() == "activated"

  if N and S then _doors(SoutheastDoor)
  elseif N then   _doors(SouthwestDoor)
  elseif S then   _doors(NortheastDoor)
  else            _doors(NorthwestDoor)
  end

end

function _doors(openDoor)
  local allDoors = {SoutheastDoor, SouthwestDoor, NorthwestDoor, NortheastDoor}
  for _, door in ipairs(allDoors) do
    door:close()
  end
  openDoor:open()
end
Ryeath_Greystalk
Posts: 366
Joined: Tue Jan 15, 2013 3:26 am
Location: Oregon

Re: Pressure Plate Question

Post by Ryeath_Greystalk »

Ok, I think I'm getting close here.

The first function is using boolean logic to figure out what door should be opened. It then passes the first 7 letters of the door name to the _doors(dir) function. Here I am guessing that dir is another local variable?

The first section of the _doors function searches all the entities on the level that the player is on looking for any name that ends with stDoor and performs the door:close() function. The sub(8,13) I'm unsure of. The 13 makes sense as each door name has 13 letters, but the 8 is confusing me a bit. At any rate, this should perform the duty of closing all 4 doors.

The next line I believe joins together the 7 letters passed from the first function, for example Northwe, with stDoor, to complete the door name, in this case NorthwestDoor. (I base this from reading Komags post about tables and it looks like two dots (..) joins strings together.) If it finds the entity named NorthwestDoor ir performs the door:open() function.

That is some really slick programming there. Well beyond my pitiful knowledge, but still awesome you would take time to help out.

edit-- looks like dasarby and I were typing replies at the same time :)
User avatar
Komag
Posts: 3659
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: Pressure Plate Question

Post by Komag »

I like dasarby's better, more direct like he says, good :)

I would write the table a little different:

Code: Select all

function _doors(openDoor)
  local allDoors = {SoutheastDoor, SouthwestDoor, NorthwestDoor, NortheastDoor}
  for i=1,4 do allDoors[i]:close() end
  openDoor:open()
end
Finished Dungeons - complete mods to play
dasarby
Posts: 28
Joined: Sun Dec 30, 2012 10:46 pm

Re: Pressure Plate Question

Post by dasarby »

that's probably waaay more idiomatic LoG lua than my table loop :D. (assigning to _, the unused variable, is idiomatic in another language in which I do most of my work, so I do it without thinking. using an indexed for loop is probably better and clearer here!)
Post Reply