[Script/puzzle]Random lever movement that has to be repeated

Ask for help about creating mods and scripts for Grimrock 2 or share your tips, scripts, tools and assets with other modders here. Warning: forum contains spoilers!
Post Reply
User avatar
Blichew
Posts: 157
Joined: Thu Sep 27, 2012 12:39 am

[Script/puzzle]Random lever movement that has to be repeated

Post by Blichew »

Hi - so I've created a lever-based riddle lately which I wanted to share. If you make any interesting changes to the script, please post them here :)

I. PIC
II. Entity list
III. Script description - lever placement and function description
IV. Connections and other editor stuff
V. Ideas
VI. Whole contents of script entity (for TL;DR and copy-paste)

I. PIC - Here's what it looks like. At the beginning all levers are blocked, button is accessible (to present new random sequence):
SpoilerShow
Image
II. Here's what you need and what names you should give to entities to just copy-paste script:
SpoilerShow
1. 6x lever and 1x wall_button placed exactly on one wall, facing East. IDs: lr_1 lr_2 lr_3 lr_4 lr_5 lr_6 lr_button
2. 1x dungeon_wall_text placed on the tile next to it. ID: lr_wt. Text -

Code: Select all

Press the button above
to start playing the sequence
3. 1x counter. ID: lr_counter
4. 1x script_entity. ID: lr_script
5. 1x timer. ID: lr_timer - Interval set on 0.5. DISABLED at start.
6. Treasure (not included in script:) )
III. Everything is in written in the lr_script:
1. Button placement (to fit them on the same wall along with wall text) and global flag for information if the riddle is already set. Tricky part is that you have to figure out the numbers yourself. For reference: I had my levers placed X:8, Y:22, Z:0:
SpoilerShow

Code: Select all

lr_1:setWorldPosition(26.9999,-0.49,29.5,0)
lr_2:setWorldPosition(26.9999,-0.49,29.1,0)
lr_3:setWorldPosition(26.9999,-0.49,28.7,0)
lr_4:setWorldPosition(26.9999,-0.49,28.3,0)
lr_5:setWorldPosition(26.9999,-0.49,27.9,0)
lr_6:setWorldPosition(26.9999,-0.49,27.5,0)
lr_button:setWorldPositionY(0.6)

riddleSet = 0
2. Functions:
2.1 createRiddle() - responsible for chosing random lever (six times) and saving the combination in the array. Every time a lever is chosen it's toggled via the timer so the sequence actually plays.
SpoilerShow

Code: Select all

function createRiddle()
	lr_button.clickable:disable()
	if riddle_index < 7 then
		riddle[riddle_index] = math.random(6)
		local lever = findEntity("lr_"..riddle[riddle_index])
		lever.lever:toggle()
	else
		if riddle_index > 9 then
			for i=1,6 do
				local l = findEntity("lr_"..i)
				if l.lever:isActivated() then
					l.lever:toggle()
				end
			end
			hudPrint("Please enter correct combination to proceed. "..lr_trials.counter:getValue().." attempt(s) left")
			lr_wt.walltext:setWallText(lr_trials.counter:getValue().." attempt(s) left")
			--print("COMB: "..riddle[1]..", "..riddle[2]..", "..riddle[3]..", "..riddle[4]..", "..riddle[5]..", "..riddle[6]..".")
			lr_timer.timer:stop()
			lr_button.clickable:disable()
			riddleSet = 1
		end
	end
	riddle_index = riddle_index + 1
end
2.2 resetRiddle() - reset globals and enable all the levers for player to toggle after the button is pressed
SpoilerShow

Code: Select all

function resetRiddle()
	riddle = {}
	riddle_index = 1
	check_index = 1
	riddleSet = 0
	for i=1,6 do
		local l = findEntity("lr_"..i)
		l.clickable:enable()
	end
end
2.3 checkRiddle(sender)
SpoilerShow

Code: Select all

function checkRiddle(sender)
	if riddleSet == 1 and check_index < 7 then
		local seq_lever = findEntity("lr_"..riddle[check_index])
		-- DEBUG print("SEQ["..check_index.."]: "..seq_lever.id.." , PRESSED: "..sender.go.id)
		if seq_lever.id == sender.go.id then
			if check_index == 6 then
				riddleEnd(1)
			else
				hudPrint(check_index.." out of 6 levers moved in correct order. Keep going")
				check_index = check_index + 1
			end
		else
			lr_trials.counter:decrement()
			lr_button.clickable:enable()
			riddleSet = 0
			disableLevers()
			if lr_trials.counter:getValue() == 0 then
				riddleEnd(0)
			else
				if riddleSet == 1 then 
					hudPrint("Wrong. Try again with new combination.")
				end
			end
		end
	else
		
	end
end
2.4 disableLevers() - well, nothing fancy, just disable the levers after the player fails until new sequence is chosen
SpoilerShow

Code: Select all

function disableLevers()
	for i=1,6 do
		local l = findEntity("lr_"..i)
		l.clickable:disable()
		if l.lever:isActivated() then
			l.lever:toggle()
		end
	end
end
2.5 riddleEnd(status) - just a finishing function to finally block the levers and button either if: player completes the riddle OR players fails to complete the riddle for 3 times
SpoilerShow

Code: Select all

function riddleEnd(status)
	if status == 1 then
		lr_button.clickable:disable()
		disableLevers()
		hudPrint("Combination entered succesfully. Congratulations.")
		lr_wt.walltext:setWallText("Combination entered succesfully.")
		riddleSet = 0
		-- PUT YOUR REWARD HERE
	else
		lr_button.clickable:disable()
		hudPrint("That was your last attempt. Sorry.")
		lr_wt.walltext:setWallText(lr_trials.counter:getValue().." attempt(s) left")
	end
end
IV. Connections (hooks):
SpoilerShow
1. lr_1 lr_2 lr_3 lr_4 lr_5 lr_6 :onToggle - lr_script:checkRiddle()
2. lr_button:onActivate - lr_script:resetRiddle()
3. lr_button:onActivate - lr_timer:start
4. lr_timer:onActivate - lr_script:createRiddle()
V. Ideas - things I thought about but didn't put them actually in
SpoilerShow
1. Adding bossfight entity to show progress if the correct lever is moved by the player
2. Number of lever movements and max attempts are fixed - 6 and 3. They could be dependant on counters for easier configuration.
3. After unsuccessfull attempt player is punished just by subst. 1 attempt from the total 3. Spawner with fireball could be added in example :)
VI. Whole contents of script_entity lr_script:
SpoilerShow

Code: Select all

lr_1:setWorldPosition(26.9999,-0.49,29.5,0)
lr_2:setWorldPosition(26.9999,-0.49,29.1,0)
lr_3:setWorldPosition(26.9999,-0.49,28.7,0)
lr_4:setWorldPosition(26.9999,-0.49,28.3,0)
lr_5:setWorldPosition(26.9999,-0.49,27.9,0)
lr_6:setWorldPosition(26.9999,-0.49,27.5,0)
lr_button:setWorldPositionY(0.6)

riddleSet = 0


function createRiddle()
	lr_button.clickable:disable()
	if riddle_index < 7 then
		riddle[riddle_index] = math.random(6)
		local lever = findEntity("lr_"..riddle[riddle_index])
		lever.lever:toggle()
	else
		if riddle_index > 9 then
			for i=1,6 do
				local l = findEntity("lr_"..i)
				if l.lever:isActivated() then
					l.lever:toggle()
				end
			end
			hudPrint("Please enter correct combination to proceed. "..lr_trials.counter:getValue().." attempt(s) left")
			lr_wt.walltext:setWallText(lr_trials.counter:getValue().." attempt(s) left")
			--print("COMB: "..riddle[1]..", "..riddle[2]..", "..riddle[3]..", "..riddle[4]..", "..riddle[5]..", "..riddle[6]..".")
			lr_timer.timer:stop()
			lr_button.clickable:disable()
			riddleSet = 1
		end
	end
	riddle_index = riddle_index + 1
end

function resetRiddle()
	riddle = {}
	riddle_index = 1
	check_index = 1
	riddleSet = 0
	for i=1,6 do
		local l = findEntity("lr_"..i)
		l.clickable:enable()
	end
end

function checkRiddle(sender)
	if riddleSet == 1 and check_index < 7 then
		local seq_lever = findEntity("lr_"..riddle[check_index])
		print("SEQ["..check_index.."]: "..seq_lever.id.." , PRESSED: "..sender.go.id)
		if seq_lever.id == sender.go.id then
			if check_index == 6 then
				riddleEnd(1)
			else
				hudPrint(check_index.." out of 6 levers moved in correct order. Keep going")
				check_index = check_index + 1
			end
		else
			lr_trials.counter:decrement()
			lr_button.clickable:enable()
			riddleSet = 0
			disableLevers()
			if lr_trials.counter:getValue() == 0 then
				riddleEnd(0)
			else
				if riddleSet == 1 then 
					hudPrint("Wrong. Try again with new combination.")
				end
			end
		end
	else
		
	end
end

function disableLevers()
	for i=1,6 do
		local l = findEntity("lr_"..i)
		l.clickable:disable()
		if l.lever:isActivated() then
			l.lever:toggle()
		end
	end
end

function riddleEnd(status)
	if status == 1 then
		lr_button.clickable:disable()
		disableLevers()
		hudPrint("Combination entered succesfully. Congratulations.")
		lr_wt.walltext:setWallText("Combination entered succesfully.")
		riddleSet = 0
		-- PUT YOUR REWARD HERE
	else
		lr_button.clickable:disable()
		hudPrint("That was your last attempt. Sorry.")
		lr_wt.walltext:setWallText(lr_trials.counter:getValue().." attempt(s) left")
	end
end
That would be it, if you think something could be done more efficiently - please say it.

Blichew
Last edited by Blichew on Sun Nov 02, 2014 1:40 am, edited 2 times in total.
User avatar
Doridion
Posts: 256
Joined: Tue Jun 10, 2014 9:23 pm

Re: [Script/puzzle]Random lever movement that has to be repe

Post by Doridion »

Sticked in the superthread ! Thanks for it memory game :D
User avatar
Lark
Posts: 178
Joined: Wed Sep 19, 2012 4:23 pm
Location: Springfield, MO USA

Re: [Script/puzzle]Random lever movement that has to be repe

Post by Lark »

Hey! This is really nice. And I know just where to put it! Thank you Blichew! -Lark
User avatar
Blichew
Posts: 157
Joined: Thu Sep 27, 2012 12:39 am

Re: [Script/puzzle]Random lever movement that has to be repe

Post by Blichew »

Lark wrote:Hey! This is really nice. And I know just where to put it! Thank you Blichew! -Lark
:D with your script..... repeat a combinatin for 64 levers. Uh - Oh.....
Post Reply