Lever Puzzle Scripting Help

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
User avatar
Grimwold
Posts: 511
Joined: Thu Sep 13, 2012 11:45 pm
Location: A Dungeon somewhere in the UK

Re: Lever Puzzle Scripting Help

Post by Grimwold »

I think you're right... I was thinking you'd need to set the flags for the levers either side as well (which I had in the script before I edited it just now).
User avatar
Grimwold
Posts: 511
Joined: Thu Sep 13, 2012 11:45 pm
Location: A Dungeon somewhere in the UK

Re: Lever Puzzle Scripting Help

Post by Grimwold »

Here's a single function that should work just by linking each lever to it.

Code: Select all

function leverToggle(trigger)
  local plate_entity = findEntity("plate_" .. string.sub(trigger.id,-1))
  local numer = tonumber(string.sub(trigger.id,-1))
  local numup = numer + 1
  local numdn = numer - 1
  if plate_entity ~=nil and plate_entity:isDown() then
    if numup < 6 then
      local lever_entity = findEntity("lever_" .. tostring(numup))
      if lever_entity ~= nil then
        lever_entity:toggle()
      end
    end
    if numdn > 0 then
      local lever_entity = findEntity("lever_" .. tostring(numdn))
      if lever_entity ~= nil then
        lever_entity:toggle()
      end
    end
  end
  if lever_1:getLeverState() == "activated" and lever_2:getLeverState() == "activated"  and lever_3:getLeverState() == "activated"  and lever_4:getLeverState() == "activated"  and lever_5:getLeverState() == "activated" then
    door_1:open()
  else
    door_1:close()
  end
end
each hidden plate should be:
plate_1 to plate_5

each lever should be:
lever_1 to lever_5

you could use different IDs, but certain parts of the script would need modifying to reflect the different naming convention. And in particular, if you need to use double digits for plates and levers, you'd need to change the -1 in the string.sub() functions to -2

Note I added in a basic check for if all the levers are in the right position... which will open door_1


edit - ok I tested it with plate_10 to plate_14 and lever_10 to lever_14 with the above modifications (since I already had levers 1 to 9 in my test dungeon) and it worked well... though there is an easy solution from the get go (when you know what to expect).
User avatar
Babby Tutel
Posts: 10
Joined: Tue Jan 01, 2013 9:02 pm

Re: Lever Puzzle Scripting Help

Post by Babby Tutel »

These replies have been amazingly helpful. After a long day, this is a sight for sore eyes.

I'll be testing Grimwold's script momentarily, thank you both for going to the work of actually assembling it.
User avatar
Babby Tutel
Posts: 10
Joined: Tue Jan 01, 2013 9:02 pm

Re: Lever Puzzle Scripting Help

Post by Babby Tutel »

It works beautifully. I would never expect this to require such a lengthy script; the more you know, right?

I want to once again say thank you. If there's anything I could give in return, just ask.
User avatar
Grimwold
Posts: 511
Joined: Thu Sep 13, 2012 11:45 pm
Location: A Dungeon somewhere in the UK

Re: Lever Puzzle Scripting Help

Post by Grimwold »

Cool. Glad it worked out. :D
dasarby
Posts: 28
Joined: Sun Dec 30, 2012 10:46 pm

Re: Lever Puzzle Scripting Help

Post by dasarby »

If you use a single lock item, then you don't need the plates.

The idea is to set the lock when a lever is pulled, then toggle the adjacent switches, then turn the lock back off. Other toggle functions only run if the lock is not set.

Additionally, moving the check function as a call in the lever pull function will prevent redundant state checks.

Here is an adaptation using locks, with a function for each lever:

Code: Select all

locked = false

function Lever1Pull()
	if not locked then
	 	locked = true
	 	lever2:toggle()
	 	locked = false
	 	CheckLeverStates()
	end 
end

function Lever2Pull()
	if not locked then
	 	locked = true
	 	lever1:toggle()
	 	lever3:toggle()
		locked = false
		CheckLeverStates()
	end
end

function Lever3Pull()
	if not locked then
	 	locked = true
	 	lever2:toggle()
	 	lever4:toggle()
		locked = false
		CheckLeverStates()
	end
end

function Lever4Pull()
	if not locked then
	 	locked = true
	 	lever3:toggle()
	 	lever5:toggle()
		locked = false
		CheckLeverStates()
	end
end


function Lever5Pull()
	if not locked then
	 	locked = true
	 	lever4:toggle()
	 	locked = false
	 	CheckLeverStates()
	end 
end

function CheckLeverStates()
 if lever1:getLeverState() == "activated" and lever2:getLeverState() == "activated" and lever3:getLeverState() == "activated" and lever4:getLeverState() == "activated" and lever5:getLeverState() == "activated" then
 	eg_door:open()
 end
end
User avatar
Babby Tutel
Posts: 10
Joined: Tue Jan 01, 2013 9:02 pm

Re: Lever Puzzle Scripting Help

Post by Babby Tutel »

Thanks for the other script, dasarby but the hidden plate script functions fine, so I have no need to change it. I will, however, save yours-- it'll be helpful in the future when I don't need to beg for scripting help. :)
User avatar
Komag
Posts: 3659
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: Lever Puzzle Scripting Help

Post by Komag »

have you tested that? sometimes the order of things is tricky
Finished Dungeons - complete mods to play
dasarby
Posts: 28
Joined: Sun Dec 30, 2012 10:46 pm

Re: Lever Puzzle Scripting Help

Post by dasarby »

Yes, I tested it, seems to be working right. There would probably be a race condition if the player moves to a new switch and flips it before the lock is unlocked; but the toggles are damn near instantaneous.

This seems like a common enough puzzle I'd thought it would be useful to make it a bit more generic. This is in the flavor of Grimwold's, where each lever should trigger the same funcion, LeverPull. When all levers are down (activated), the Solved function is called, if any lever is not down, UnSolved is called. Just set them to whatever actions you need (i.e. open/close doors)

Which levers activate which other levers is mapped in the "levers" table. Set each lever's id to a list of the other levers that should be toggled. The following example is the simple case of "toggle levers next to the one that is pulled":

Code: Select all

locked = false

levers = {
	lever1={"lever2"},
	lever2={"lever1", "lever3"},
	lever3={"lever2", "lever4"},
	lever4={"lever3", "lever5"},
	lever5={"lever4"}
}

function Solved()
	eg_door:open()
end

function UnSolved()
	eg_door:close()
end

function PullLever(trigger)
	if not locked then
		locked = true
		if levers[trigger.id] then
			for _, id in ipairs(levers[trigger.id]) do
				findEntity(id):toggle()
			end
		end
		locked = false

		local solved = true
		for id, _ in pairs(levers) do
			solved = solved and findEntity(id):getLeverState() == "activated"
		end
		if solved then
			Solved()
		else
			UnSolved()
		end
	end
end
This should be pretty easy to extend to any number of levers, with arbitrary connection (ie in a circle, or toggle to two adjacent, etc)

I tested this one too, and it seems to be pretty good. Feedback appreciated.
User avatar
Komag
Posts: 3659
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: Lever Puzzle Scripting Help

Post by Komag »

looks good, would be a good addition to the script repository :)
Finished Dungeons - complete mods to play
Post Reply