Script Help

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
User avatar
LocalFire
Posts: 261
Joined: Thu Feb 21, 2013 1:16 am
Location: Auckland, New Zealand

Script Help

Post by LocalFire »

So I've made a logic puzzle its pretty basic, place shields on hooks next to banners, the correct combination opens a door

At first I was using levers toggled by the correct shield going on the wall, but if someone put the right shield on the hook multiple times it screwed up the levers so you could have the right answer without the door opening. To fix this I went with counters, the idea was that the counters would reset if the shield was removed and increase only if the right shield was in place, heres my script

Code: Select all

function shieldrose()
 if rose:getItemCount() ~= 0 then
   for i in rose:containedItems() do
      if i.name == "shield_rose" then
s2:increment()
         
      end
   end
else
s2:reset()
end
end
So the first problem is that the counter won't reset if the shield is removed, I tried moving the getItemCount down to the else section but that stops the counter from increasing when the shield is in place
How can I fix this script?

Second is getting it so that all the active counters trigger a door to open, I'm using this

Code: Select all

function leveraction()
     if s1:getValue() == 1 and
s2:getValue() == 1 and
s3:getValue() == 1 and
s4:getValue() == 1 and
s5:getValue() == 1 and
        s6:getValue()== 1  then
          
script_entity_38:destroy()
helm_door:open()
playSound("level_up")
   hudPrint("1000 EXP gained")
hudPrint("You Learnt the Sigils and Arms of the Knight Captains")
global_scripts.grantExp(1000)
 secret_27:activate()
end
end
which doesn't work, I don't have that much experience with counters so any help would great
My Dungeons
Paths of the Earth: viewtopic.php?f=14&t=5136
Beneath the Sands: viewtopic.php?f=14&t=5216
Videos: viewtopic.php?f=11&t=5443
User avatar
msyblade
Posts: 792
Joined: Fri Oct 12, 2012 4:40 am
Location: New Mexico, USA
Contact:

Re: Script Help

Post by msyblade »

Couple of things you can try. First requires some funny math, but bypasses the scripting need to get the counts right. complex stuff, likely confusing when put into words like this. Just let me know if its not clear and ill try to rephrase. Use the connectors from the shield hook directly to the counter to increment/decrement it. ie:Activate= decrement, Deactivate=increment, in ADDITION to the decrement line in the script. Then set the counter to 2, instead of 1. This way, when the wrong shield is placed, the counter will goto 1, and when its removed, it will return to 2. if the correct shield is placed, the counter decrements once for the connecter, AND once for the script, thus setting the counter to 0 and tripping it. You can stack this effect multiple times, concurrently, using a "master" counter set to, saaay 6. So use this trick, but when the counter trips, it decrements the "master" counter 1, each counter you connect to the master counter, needs to completely trip to decrement the master. and if the first counter increments, it has no effect on the master counter. "Stacking" counters in such a way can get complex, and sometimes you may find that u need to adjust values in unforeseen ways during testing, due to the complex nature that ties it all together. You'll find that the master is simply tripping one puzzle early (just add 1 to it, and try it again), or that an individual counter tripping late, or becoming out of sync. With some tweaking you can create some very powerful puzzles. There is also a torch no remove script around here, that can help you "lock" the item in place after used. You need to use the same counter trick above to use the script only when the correct item is placed, otherwise anything placed will turn INTO the shield when removed.

Also,try removing all of the "ands" from your 2nd script, and try using :setValue (1) instead of reset. Hopefully one of these will have u up and running soon! ;)
Currently conspiring with many modders on the "Legends of the Northern Realms"project.

"You have been captured by a psychopathic diety who needs a new plaything to torture."
Hotel Hades
User avatar
LocalFire
Posts: 261
Joined: Thu Feb 21, 2013 1:16 am
Location: Auckland, New Zealand

Re: Script Help

Post by LocalFire »

OK so I tried this an I can get it so the right shields decrease the counter to zero, it increases when removed and the wrong shield only activates it by dropping one point, The problem comes from connecting the counters to a master counter, each time I test it, I get a different response, a hook that worked before stops working and one that didn't now doe's, all without actually changing anything

So I've removed the master counter and changed the script to this

Code: Select all

function shieldicon()
 if icon:getItemCount() ~= 0 then
   for i in icon:containedItems() do
      if i.name == "shield_icon" then
s1:decrement()
         
else
 
s1:setValue(1)
end
end
end end
So the wrong shield resets the counter, but if the wrong shield is added it stops the script working for the right shield, it works fine when the correct shield is in place the first time, and increases back to 1 when removed, back to zero when replaced, but once a wrong answer is given it stops and the counter is stuck on 1, Help
My Dungeons
Paths of the Earth: viewtopic.php?f=14&t=5136
Beneath the Sands: viewtopic.php?f=14&t=5216
Videos: viewtopic.php?f=11&t=5443
User avatar
msyblade
Posts: 792
Joined: Fri Oct 12, 2012 4:40 am
Location: New Mexico, USA
Contact:

Re: Script Help

Post by msyblade »

LEAVE THE SCRIPT as is. Make sure the counter is set to 2, AND set to increment on deactivate, and decrement on activate. SHOULD work, but it makes my head hurt also. If you have that set up correctly, consider using a socket "accept item" script, that denies any item other than the correct shield on that hook, but MAKE SURE to create hints so the player knows it isnt just a normal hook when he guesses wrong and nothing happens.
Currently conspiring with many modders on the "Legends of the Northern Realms"project.

"You have been captured by a psychopathic diety who needs a new plaything to torture."
Hotel Hades
User avatar
LocalFire
Posts: 261
Joined: Thu Feb 21, 2013 1:16 am
Location: Auckland, New Zealand

Re: Script Help

Post by LocalFire »

Ok back the way it was, so it works with the first shield being right, drops it from 2 to zero, taking it off goe's to 1, putting on the wrong shield back to 2

But after a wrong answer the right shield only drops it by 1 point and it won't increase after the shield is taken off
My Dungeons
Paths of the Earth: viewtopic.php?f=14&t=5136
Beneath the Sands: viewtopic.php?f=14&t=5216
Videos: viewtopic.php?f=11&t=5443
User avatar
LocalFire
Posts: 261
Joined: Thu Feb 21, 2013 1:16 am
Location: Auckland, New Zealand

Re: Script Help

Post by LocalFire »

with some tweaks I've got it to open the door with the right answers, the wrong ones still screw up[ the counters by changing the counters by different values each time they are placed, On top of that a wrong answer messes with the right answers working

Going to see if I can put in a reset switch, might fix things
My Dungeons
Paths of the Earth: viewtopic.php?f=14&t=5136
Beneath the Sands: viewtopic.php?f=14&t=5216
Videos: viewtopic.php?f=11&t=5443
User avatar
msyblade
Posts: 792
Joined: Fri Oct 12, 2012 4:40 am
Location: New Mexico, USA
Contact:

Re: Script Help

Post by msyblade »

just understand that this can of whoop ass, has a mathematical equation, that will bring it together. it's just u stop banging your head on a drywall, and figure it out. add/subtract until u eliminate the loophole. I know, it hurts, but it's how these complex things get added together by someone else, that make me n u think "ohhhhhhh!"
Currently conspiring with many modders on the "Legends of the Northern Realms"project.

"You have been captured by a psychopathic diety who needs a new plaything to torture."
Hotel Hades
alois
Posts: 112
Joined: Mon Feb 18, 2013 7:29 am

Re: Script Help

Post by alois »

Hi LocalFire. If I have understood correctly what you mean, you have 6 shields to put in the correct places (and when this happens you want to open a door). I think that you may achieve that with a variable (let us call it 'counter'), which holds the value 0 at the beginning.

Frist of all, in a script_entity put the following function:

Code: Select all

counter = 0
function setBit(val,bit,oo)
	local div1 = math.pow(10,bit)
	local div2 = math.pow(10,bit-1)
	local big = div1*math.floor(val/div1)
	local sma = val%div2
	return big + sma + (oo * div2)
end
Then, in the same script_entity, for the activate part of the holders:

Code: Select all

function activateHolder1() -- Holder2, ..., Holder6
   if (the holder contains the correct shield)
      counter = setBit(counter,1,1) -- setBit(counter,2,1) / setBit(counter,3,1) / ... / setBit(counter,6,1)
   else
      counter = setBit(counter,1,0) -- setBit(counter,2,0) / setBit(counter,3,0) / ... / setBit(counter,6,0)
   end
   if (counter == 111111) then 
      -- open door!
   end
end
And in the deactivate

Code: Select all

function deactivateHolder1() -- Holder2, ..., Holder6
   counter = setBit(counter,1,0) -- setBit(counter,2,0) / setBit(counter,3,0) / ... / setBit(counter,6,0)
   -- no need to check since the holder is empty!
end
This should hopefully work :)

alois :)
User avatar
JohnWordsworth
Posts: 1397
Joined: Fri Sep 14, 2012 4:19 pm
Location: Devon, United Kingdom
Contact:

Re: Script Help

Post by JohnWordsworth »

An alternative solution is to have a single function which just checks all of the alcoves whenever an item is added to any of them. For example, if you wanted to have 3 alcoves, one that needs a knife, one that needs a long sword and one that needs a sling put them in to beat the puzzle (and each alcove only accepts 1 specific item), then you could create a level with the following entities...
  • A script entity named 'alcove_puzzle_script'.
  • 3 Alcoves, with the following names 'knife_alcove', 'long_sword_alcove' and 'sling_alcove'.
  • A knife, a long sword and a sling.
Then in your script entity you could define the following script...
SpoilerShow

Code: Select all

function checkAlcoveForItem(alcove, itemName)
  if ( alcove == nil or itemName == nil ) then
    return false;
  end

  if ( alcove:getItemCount() > 0 ) then
    for item in alcove:containedItems() do
      if ( item.name == itemName ) then
        return true;
      end
    end
  end
  
  return false;
end

function puzzleCheck()
  local score = 0;
  
  if ( checkAlcoveForItem(findEntity("knife_alcove"), "knife") ) then 
    score = score + 1;
  end
  
  if ( checkAlcoveForItem(findEntity("sling_alcove"), "sling") ) then 
    score = score + 1;
  end
  
  if ( checkAlcoveForItem(findEntity("long_sword_alcove"), "long_sword") ) then 
    score = score + 1;
  end

  if ( score == 3 ) then
    hudPrint("WOOT - All 3 items are correct.");
  else
    hudPrint("Not Yet Solved.");
  end
end
In this script we have defined 2 functions.

checkAlcoveForItem(alcove, itemName): You should provide an alcove, found using findEntity("alcove_id"), and the name of the item you are checking for. This just separates the loop you are using into one place to cut down on repetitive code. This new function returns TRUE if the alcove contains an item with the given name, false otherwise.

puzzleCheck(): This checks all 3 alcoves at any given point in time to see if the puzzle has been solved. It uses the aforementioned function that we made to check each alcove for the given object. We keep track of the number of alcoves that are correct with a local 'score' variable. If the score is high enough - the puzzle is complete, otherwise it is not. We just print something to the HUD here based on the output, but you could do anything.

Last but not least, to tie all of this together - you need to make sure the 'puzzleCheck' method is actually called. As it only needs to be called when the contents of the alcoves change, you can simply add a connector to each alcove pointing to the given script entity. Make sure it hooks up to the 'puzzleCheck' method and not the other one.
My Grimrock Projects Page with links to the Grimrock Model Toolkit, GrimFBX, Atlas Toolkit, QuickBar, NoteBook and the Oriental Weapons Pack.
User avatar
Komag
Posts: 3658
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: Script Help

Post by Komag »

Going off of John's good scripts, I would adapt them to set it up this way:

Have one script at the top of your dungeon that you will forever always use for this sort of thing, with the simple name f

inside that script have only this code:

Code: Select all

function ndItemNameInside(entity, itemName)
  if (entity == nil or itemName == nil) then
     print("need two variables")
     return false
  end
  for i in entity:containedItems() do
    if (i.name == itemName) then
      return true
    end
  end
  return false
end

function ndItemIDInside(entity, itemID)
  if (entity == nil or itemID == nil) then
     print("need two variables")
     return false
  end
  for i in entity:containedItems() do
    if (i.id == itemID) then
      return true
    end
  end
  return false
end
This will be your universal search script, and whenever you want to use it to search a container (like an alcove) for a certain item.name or a certain item.id, you refer to it from inside different script entities like this:

Code: Select all

function puzzleCheck() 
  if (f.ndItemNameInside(knife_alcove, "knife") and
     (f.ndItemNameInside(sling_alcove, "sling") and
     (f.ndItemNameInside(long_sword_alcove, "long_sword") then
     hudPrint("WOOT - All 3 items are correct.")
    else
     hudPrint("Not Yet Solved.")
  end
end
If you wanted only special certain items (not just any scroll, but the scroll with certain words), you can use the ID version with f.ndItemIDInside.
Finished Dungeons - complete mods to play
Post Reply