Page 2 of 3

Re: How to make pit puzzle, such as the chamber of pits?

Posted: Thu Sep 27, 2012 5:12 am
by Komag
so I'm testing antti's version, just for kicks, and got a very weird crash

my script so far:

Code: Select all

time = 1
function pitSequence()
  local sequence = { pitpuz7, pitpuz4, pitpuz1, pitpuz2, pitpuz3, pitpuz6, pitpuz5, pitpuz8, pitpuz9 }   --this doesn't contain ALL the pits, only the exact sequence or the path of closing and opening pits
  sequence[time]:close()    --close a pit in the sequence
--  sequence[time-3]:open()   --and then open a pit again a few steps behind
  time = time + 1
end
I just wanted to see it close them in my order - I have 9 pits:
1 2 3
4 5 6
7 8 9 z
x
so I have them closing 7 4 1, 2 3, 6 5, 8 9, so I can move from x to z
Anyway, without any method yet to shut down the timer, soon after 9 closed, I got a crash, and my mouse was stuck to the middle of the screen, even if I alt=tabbed to other windows open! I had to use keyboard shortcuts to close the editor, then my mouse was free again!

But I feel a little sense of déjà vu - is this already a known bug, that when using mouselook and you get a crash then the mouse is stuck near the screen center? I didn't see it on the "known issues" list for 1.2.11.

The error is:
sequence[time]:close() --close a pit in the sequence - "attempt to index a nil value" and it's right when the next timer tick happens after closing the last pit

Re: How to make pit puzzle, such as the chamber of pits?

Posted: Thu Sep 27, 2012 5:40 am
by Komag
I'm almost there!!! but I have to go to bed, and I'll be busy most of the day tomorrow. Here's what I've got so far, working partially:

Code: Select all

time = 1
function pitSequence()
  local sequence = { pitpuz7, pitpuz4, pitpuz1, pitpuz2, pitpuz3, pitpuz6, pitpuz5, pitpuz8, pitpuz9 }
  if time < 10 then
    sequence[time]:close()    --close a pit in the sequence
  end
  if time > 2 then
    sequence[time-2]:open()   --and then open a pit again a few steps behind
  end
  if levercount == 2 then
    time = time + 1
  else
    time = time - 1
  end
  if time == 12 then
    time = 1
    pitpuztimer:deactivate()
  end
end

levercount = 2
function leverPull()
	if pitpuzlever1:getLeverState() == activated and
	   pitpuzlever2:getLeverState() == activated then
	   levercount = 2
	   time = 1
	elseif pitpuzlever1:getLeverState() == deactivated and
	   pitpuzlever2:getLeverState() == deactivated then
	   levercount = 2
	   time = 1
	else
	   levercount = 1
	   time = 11
	end
end
The two levers are located on either end of the pit puzzle (like in the original game), along with a button on each end, and the levers are linked to the script with the leverpull function (the buttons are linked to a 1sec timer linked to the script with the pitSequence function).

I haven't yet set up the levers to cancel and open all the pits if they're in the middle of the sequence.

The forward sequence works well. The reverse sequence works partially, but I only barely rigged it so I haven't set up proper pit closing or stopping it at the right time, so it will crash with an attempt to index a nil value.

Re: How to make pit puzzle, such as the chamber of pits?

Posted: Thu Sep 27, 2012 1:19 pm
by Komag
Okay, this works perfectly so far as I have tested, including pulling the lever halfway through to reset everything:

Code: Select all

time = 1
function pitSequence()
  local sequence = { pitpuz7, pitpuz4, pitpuz1, pitpuz2, pitpuz3, pitpuz6, pitpuz5, pitpuz8, pitpuz9 } -- doesn't have to include all pits, just the path you want
  if levercount == 2 then
    if time < 10 then
      sequence[time]:close() --close a pit in the sequence
    end
    if time > 2 then
      sequence[time-2]:open() --and then open a pit again two steps behind
    end
    time = time + 1
    if time == 12 then
      time = 1
      pitpuztimer:deactivate()
    end
  elseif levercount == 1 then
    if time > 2 then
      sequence[time-2]:close() --close a pit in the sequence
    end
    if time < 10 then
      sequence[time]:open() --and then open a pit again two steps behind
    end
    time = time - 1
    if time == 0 then
      time = 11
      pitpuztimer:deactivate()
    end
  end
end

levercount = 2
function leverPull()
  if pitpuzlever1:getLeverState() == "activated" and
    pitpuzlever2:getLeverState() == "activated" then
      levercount = 2
      time = 1
  elseif pitpuzlever1:getLeverState() == "deactivated" and
    pitpuzlever2:getLeverState() == "deactivated" then
      levercount = 2
      time = 1
  else
    levercount = 1
    time = 11
  end
  for i=1,9 do
    local pit = findEntity("pitpuz"..i)
    if pit then
      pit:open()
    end
  end
  pitpuztimer:deactivate()
end
- link the two buttons to the timer, which is linked to the script with pitSequence
- link the two levers to the script directly with leverPull

Re: How to make pit puzzle, such as the chamber of pits?

Posted: Thu Sep 27, 2012 1:51 pm
by Komag
another version, with much easier customization (with notes where to do it) for you:

Code: Select all

time = 1
steps = 9 -- CUSTOMIZE: HOW MANY STEPS YOU HAVE
thetimer = pitpuztimer -- CUSTOMIZE: ID OF THE TIMER

function pitSequence()
  local sequence = { pitpuz7, pitpuz4, pitpuz1, pitpuz2, pitpuz3, pitpuz6, pitpuz5, pitpuz8, pitpuz9 } -- CUSTOMIZE: IDS OF THE PITS YOU WANT TO CLOSE, IN ORDER
  if levercount == 2 then
    if time < steps + 1 then
      sequence[time]:close() --close a pit in the sequence
    end
    if time > 2 then
      sequence[time-2]:open() --and then open a pit again two steps behind
    end
    time = time + 1
    if time == steps + 3 then
      time = 1
      thetimer:deactivate()
    end
  elseif levercount == 1 then
    if time > 2 then
      sequence[time-2]:close() --close a pit in the sequence
    end
    if time < steps + 1 then
      sequence[time]:open() --and then open a pit again two steps behind
    end
    time = time - 1
    if time == 0 then
      time = steps + 2
      thetimer:deactivate()
    end
  end
end

levercount = 2
function leverPull()
  if pitpuzlever1:getLeverState() == "activated" and -- CUSTOMIZE: ID OF LEVER1
    pitpuzlever2:getLeverState() == "activated" then -- CUSTOMIZE: ID OF LEVER2
      levercount = 2
      time = 1
  elseif pitpuzlever1:getLeverState() == "deactivated" and -- CUSTOMIZE: ID OF LEVER1
    pitpuzlever2:getLeverState() == "deactivated" then -- CUSTOMIZE: ID OF LEVER2
      levercount = 2
      time = 1
  else
    levercount = 1
    time = steps + 2
  end
  for i=1,steps do
    local pit = findEntity("pitpuz"..i) -- CUSTOMIZE: PARTIAL ID OF PITS
    if pit then
      pit:open()
    end
  end
  thetimer:deactivate()
end

Re: How to make pit puzzle, such as the chamber of pits?

Posted: Thu Sep 27, 2012 2:51 pm
by antti
Komag wrote:another version, with much easier customization (with notes where to do it) for you:

Code: Select all

time = 1
steps = 9 -- CUSTOMIZE: HOW MANY STEPS YOU HAVE
thetimer = pitpuztimer -- CUSTOMIZE: ID OF THE TIMER

function pitSequence()
  local sequence = { pitpuz7, pitpuz4, pitpuz1, pitpuz2, pitpuz3, pitpuz6, pitpuz5, pitpuz8, pitpuz9 } -- CUSTOMIZE: IDS OF THE PITS YOU WANT TO CLOSE, IN ORDER
  if levercount == 2 then
    if time < steps + 1 then
      sequence[time]:close() --close a pit in the sequence
    end
    if time > 2 then
      sequence[time-2]:open() --and then open a pit again two steps behind
    end
    time = time + 1
    if time == steps + 3 then
      time = 1
      thetimer:deactivate()
    end
  elseif levercount == 1 then
    if time > 2 then
      sequence[time-2]:close() --close a pit in the sequence
    end
    if time < steps + 1 then
      sequence[time]:open() --and then open a pit again two steps behind
    end
    time = time - 1
    if time == 0 then
      time = steps + 2
      thetimer:deactivate()
    end
  end
end

levercount = 2
function leverPull()
  if pitpuzlever1:getLeverState() == "activated" and -- CUSTOMIZE: ID OF LEVER1
    pitpuzlever2:getLeverState() == "activated" then -- CUSTOMIZE: ID OF LEVER2
      levercount = 2
      time = 1
  elseif pitpuzlever1:getLeverState() == "deactivated" and -- CUSTOMIZE: ID OF LEVER1
    pitpuzlever2:getLeverState() == "deactivated" then -- CUSTOMIZE: ID OF LEVER2
      levercount = 2
      time = 1
  else
    levercount = 1
    time = steps + 2
  end
  for i=1,steps do
    local pit = findEntity("pitpuz"..i) -- CUSTOMIZE: PARTIAL ID OF PITS
    if pit then
      pit:open()
    end
  end
  thetimer:deactivate()
end
I don't think you need the steps variable if it is there to just indicate how many pits you have in the sequence table. You could just replace them with #sequence, which gets the length of the table. It would simplify the customization a little bit as well.

Re: How to make pit puzzle, such as the chamber of pits?

Posted: Thu Sep 27, 2012 3:14 pm
by Komag
Ah, thanks, I was wondering if there was a way to get that, didn't know about the #. I'm at the courthouse on jury duty right now, but I'll update this tonight

Re: How to make pit puzzle, such as the chamber of pits?

Posted: Thu Sep 27, 2012 11:50 pm
by Komag
antti wrote:I don't think you need the steps variable if it is there to just indicate how many pits you have in the sequence table. You could just replace them with #sequence, which gets the length of the table. It would simplify the customization a little bit as well.
hmm, tried it, but it's used in the separate leverPull function, so it crashes with "attempt to get length of global 'sequence' (a nil value)

it works correctly if I just pull out the sequence and put it at the top to make it global, but is there any reason to avoid doing that?

Re: How to make pit puzzle, such as the chamber of pits?

Posted: Fri Sep 28, 2012 1:27 am
by Montis
I would say no, since no variables are really global.

Re: How to make pit puzzle, such as the chamber of pits?

Posted: Fri Sep 28, 2012 2:11 am
by Komag
here is the altered version with streamlined CUSTOMIZATION all at the top:

Code: Select all

thetimer = pitpuztimer -- CUSTOMIZE: ID OF THE TIMER
thelever1 = pitpuzlever1 -- CUSTOMIZE: ID OF THE FIRST LEVER
thelever2 = pitpuzlever2 -- CUSTOMIZE: ID OF THE SECOND LEVER
namepart = "pitpuz" -- CUSTOMIZE: PARTIAL ID OF PITS
sequence = { pitpuz7, pitpuz4, pitpuz1, pitpuz2, pitpuz3, pitpuz6, pitpuz5, pitpuz8, pitpuz9 } -- CUSTOMIZE: IDS OF THE PITS YOU WANT TO CLOSE, IN ORDER

time = 1
function pitSequence()
  if levercount == 2 then
    if time < #sequence + 1 then
      sequence[time]:deactivate() --close a pit in the sequence
    end
    if time > 2 then
      sequence[time-2]:activate() --and then open a pit again two steps behind
    end
    time = time + 1
    if time == #sequence + 3 then
      time = 1
      thetimer:deactivate()
    end
  elseif levercount == 1 then
    if time > 2 then
      sequence[time-2]:deactivate() --close a pit in the sequence
    end
    if time < #sequence + 1 then
      sequence[time]:activate() --and then open a pit again two steps behind
    end
    time = time - 1
    if time == 0 then
      time = #sequence + 2
      thetimer:deactivate()
    end
  end
end

levercount = 2
function leverPull()
  if thelever1:getLeverState() == "activated" and
    thelever2:getLeverState() == "activated" then
      levercount = 2
      time = 1
  elseif thelever1:getLeverState() == "deactivated" and
    thelever2:getLeverState() == "deactivated" then
      levercount = 2
      time = 1
  else
    levercount = 1
    time = #sequence + 2
  end
  for i=1,#sequence do
    local pit = findEntity(namepart..i)
    if pit then
      pit:activate()
    end
  end
  thetimer:deactivate()
end
tested and working well, nice and clean to implement :)

Re: How to make pit puzzle, such as the chamber of pits?

Posted: Fri Sep 28, 2012 5:26 am
by Komag
the dungeon crashed when trying to load into the real game as a custom dungeon:
pitpuzscript: cannot serialize table 'thetimer' with metatable
stack traceback:
[C]: in function 'error'
[string "ScriptEntity.lua"]: in function 'saveValue'
[string "ScriptEntity.lua"]: in function 'saveState'
[string "GameMode.lua"]: in function 'saveGame'
[string "GameMode.lua"]: in function 'autoSave'
[string "GameMode.lua"]: in function 'newGame'
[string "GameMode.lua"]: in function 'startGame'
[string "NewGameMenu.lua"]: in function 'startGame'
[string "NewGameMenu.lua"]: in function 'update'
[string "GameMode.lua"]: in function 'update'
[string "Grimrock.lua"]: in function 'display'
[string "Grimrock.lua"]: in main chunk