Useful scripts repository

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
User avatar
Komag
Posts: 3654
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: Useful scripts repository

Post by Komag »

Play Correct Party Hurt Sounds Based on Any Race/Gender Combination

This simple script allows you to play the right hurt sounds for any party make-up:

Code: Select all

function partyHurt()
  for i=1,4 do
    local theRace = party:getChampion(i):getRace()
    local theSex = party:getChampion(i):getSex()
    champHurt(theRace,theSex)
  end
end

function champHurt(race,sex)
  if race == "Human" then playSound("damage_human_"..sex)
    elseif race == "Minotaur" then playSound("damage_minotaur_"..sex)
    elseif race == "Lizardman" then playSound("damage_lizardman_"..sex)
    elseif race == "Insectoid" then playSound("damage_insectoid_"..sex)
  end
end
------------------
EDIT - Oops, didn't realize there is a much easier way, simply:

Code: Select all

function doDamage()
  for i=1,4 do
    if party:getChampion(i):getEnabled() and
       party:getChampion(i):isAlive() then
       party:getChampion(i):damage(math.random(5,10),"physical")
       party:getChampion(i):playDamageSound()
    end
  end
end
This example damages each player a random amount between 5 and 10, then plays all their hurt sounds (which already accounts for race and gender automatically)


-----
original thread for discussion/questions:
viewtopic.php?p=51233#p51233
Finished Dungeons - complete mods to play
User avatar
Komag
Posts: 3654
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: Useful scripts repository

Post by Komag »

Control console debug printing

As I'm drawing closer to finishing my dungeon, I realized I wanted to go through and turn off all the debug messages I used to work through the scripts.

I knew it would take a while to hunt them all down, and I knew I would still be making more of them while working on the last couple levels, so I set up the following script to handle it much more neatly:

script entity called pr

Code: Select all

printON = true

function nt(m1,m2,m3,m4)
  if printON then
     if      m2 == nil and m3 == nil and m4 == nil then print(m1)
      elseif m3 == nil and m4 == nil then print(m1,m2)
      elseif m4 == nil then print(m1,m2,m3)
      else   print(m1,m2,m3,m4)
     end
  end
end

pr.nt("Debug texts are ON")
------------------------------------

-- this function and variable are for console printing. If
-- printON is true then all the console debug text will
-- print during play. Turn this to false before final release.

-- In scripts in the dungeon I might have a line like:
-- pr.nt("blah blah blah")
It can handle prints with up to four segments (I've only ever used two), such as:
pr.nt(my_table, variable1.." is not the way", suchTimer.x, suchTimer.y)

I've converted all my "print" to "pr.nt" by doing a big 'ol search and replace in the dungeon.lua, and voila, now it works great, and I can leave them on for the beta-testers and then just turn em off at public release time by editing "printON = true" to "printON = false"

-----
original thread for discussion/questions:
viewtopic.php?f=14&t=4915&hilit=print
Finished Dungeons - complete mods to play
User avatar
Komag
Posts: 3654
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: Useful scripts repository

Post by Komag »

How to set up a hot-key to run any script quick!

The gui hooks are truly awesome, and one nice little trick is to set up some simple key press code to run whatever script you want at the touch of a key.

First, you need to add the main gui hook to the party definition like this:

Code: Select all

cloneObject{
  name = "party",
  baseObject = "party",
  onDrawGui = function(g)
    guiScript.doGui(g)
  end,
}
Next, add a script entity to your dungeon called guiScript and put in this code:

Code: Select all

function doGui(g) -- triggers EVERY frame by render gui hook
  --code
end
Now you're ready to put whatever you want in place of --code

For this example, let's just do a simple print message when you press the 'm' key. Change your guiScript code to:

Code: Select all

mFree = true

function doGui(g) -- triggers EVERY frame by render gui hook
  if g.keyDown("m") then
     if mFree then
        print("m key was pressed")
        --other code
     end
     mFree = false
    else -- key no longer being held down
     mFree = true
  end
end
And that's it! Now, in game, if you press the m key it will print the message "m key was pressed". And it will only print one time, even if you hold the key down for a few seconds, until you let go and press it again.

You'll notice I added a "global" variable called mFree just before the function. This acts as a flag so that holding the key down won't trigger the code to be run multiple times in a row. The first frame rendered after you press the key checks to see if mFree is true, and only if it's true does it run the code, and it also sets it to false, preventing the code from running again until you first let go of the key (to set the flag true) to make it available again.

If you want to test some feature over and over, you can temporarily put in a link in this code, such as:

Code: Select all

mFree = true

function doGui(g) -- triggers EVERY frame by render gui hook
  if g.keyDown("m") then
     if mFree then
        --print("m key was pressed")
        myOtherScript.myOtherTestFunction()
     end
     mFree = false
    else
     mFree = true
  end
end
Now, every time you press m it will run myOtherTestFunction() for whatever you have set up there.

You can use this for testing things out when designing complex puzzles, or you could add this as an actual gameplay feature for players to use in your dungeon, making 'm' be a new interface key which casts a free missile spell or something, whatever you want, anything is possible!


-----
original thread for discussion/questions:
viewtopic.php?f=14&t=4945
Finished Dungeons - complete mods to play
User avatar
Komag
Posts: 3654
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: Useful scripts repository

Post by Komag »

Universal "Check Alcove for Item" script, useful for alcoves, altars, etc

I would 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 swordCheck() 
  if (f.ndItemNameInside(mySwordAlcove, "long_sword") then
     hudPrint("The sword was found, you may pass")
    else
     hudPrint("The sword is missing!")
  end
end
You would link your alcove to the "swordCheck" function, probably with an "any" link (but that may depend on what exactly you are doing).

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.

You can use this for multiple alcoves as well, such as:

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
You would link each alcove to this same "puzzleCheck" function, so every time you put something in any of them, the function will run the check on all three alcoves.


-----
original thread for discussion/questions:
viewtopic.php?p=56510#p56510
Finished Dungeons - complete mods to play
User avatar
The cube
Posts: 94
Joined: Tue Apr 23, 2013 6:09 pm
Location: Barren Desert

Re: Useful scripts repository

Post by The cube »

not sure how useful this is but:
A middle-tile pillar that spawns an earthquake when destroyed!

made this cool pillar after reading the neikun`s middle pillar post.
when the player destroys this pillar, an eartquake appears :o

Code: Select all

defineObject{
   name = "dungeon_supporting_center_pillar",
   class = "Blockage",
   model = "assets/models/dungeon/dungeon_pillar.fbx",
   placement = "floor",
   hitSound = "impact_blade",
   editorIcon = 100,
   health = 50,
   evasion = -1000,
   hitEffect = "hit_dust",
   brokenModel = "assets/models/dungeon_floor_01.fbx" -- not sure if this works.. add the model you wish to see when the pillar is destroyed.	
   onProjectileHit = function()
      return false -- projectiles can`t shoot down pillars!
   end,	
   onDie = function(self)
        spawn("poison_cloud", self.level, self.x, self.y, 0)
        scriptEntityName.functionName() -- add your earthquake script`s name and the script entity that it is in here.
   end,
}
originally i made this with the northern dungeon wallset, code for it:

Code: Select all

defineObject{
   name = "northern_dungeon_supporting_center_pillar",
   class = "Blockage",
   model = "mod_assets/models/northern_dungeon/northern_dungeon_pillar.fbx",
   placement = "floor",
   hitSound = "impact_blade",
   editorIcon = 100,
   health = 50,
   evasion = -1000,
   hitEffect = "hit_dust",
   onProjectileHit = function()
      return false -- projectiles can`t shoot down pillars!
   end,
   brokenModel = "mod_assets/models/northern_dungeon/northern_dungeon_floor_01.fbx",
   onDie = function(self)
        spawn("poison_cloud", self.level, self.x, self.y, 0)
        scriptEntityName.functionName() -- add your earthquake script`s name and the script entity that it is in here.
   end,
}
EDIT: Works now :) i tried to spawn poison_clud instaed of poison_cloud when the pillar was destroyed.
User avatar
Neikun
Posts: 2457
Joined: Thu Sep 13, 2012 1:06 pm
Location: New Brunswick, Canada
Contact:

Re: Useful scripts repository

Post by Neikun »

Probably a better idea to spawn an empty model rather than a floor so there's no worry on clipping.
That ore a pile of rubble. Not sure if Skuggs has one lying around.
"I'm okay with being referred to as a goddess."
Community Model Request Thread
See what I'm working on right now: Neikun's Workshop
Lead Coordinator for Legends of the Northern Realms Project
  • Message me to join in!
User avatar
Kein Mitleid
Posts: 3
Joined: Fri Jun 21, 2013 4:06 am

Re: Useful scripts repository

Post by Kein Mitleid »

Walk the correct path on some plates to perform a specified action.

For this code, you don't need to connect anything, as the program takes care of that for you. I realize this script isn't as advanced as Grimwold's is but if you need something simple, use this. Just insert your door and plate id's and the puzzle should work correctly.

Code: Select all

-- insert id of door to open
door = "DOOR GOES HERE"
-- insert ids of plates in order
plates = { "PLATES GO HERE" }
					
counter = 0
last_plate = nil

for i = 1, #plates do
	for j = 0, i - 1 do
		if plates[i] == plates[j] then break end
		if j == i - 1 then
			hudPrint(tostring(plates[i]))
			local plate = findEntity(plates[i])
			plate:addConnector("activate", self.id, "isPressed")
			plate:setTriggeredByParty(true)
			plate:setTriggeredByMonster(false)
			plate:setTriggeredByItem(false)
end end end

function isPressed(plate)
	if last_plate == plates[counter] and plate.id == plates[counter + 1] then
		counter = counter + 1
		if counter == #plates then findEntity(door):open() end
		last_plate = plates[counter]
	else
		counter = 0
		last_plate = nil
end end
Last edited by Kein Mitleid on Tue Jun 25, 2013 2:38 am, edited 2 times in total.
User avatar
Kein Mitleid
Posts: 3
Joined: Fri Jun 21, 2013 4:06 am

Re: Useful scripts repository

Post by Kein Mitleid »

Levers, each with more than two values, that are part of a combination lock.

In this script, you can make several levers, each with more than two values, that are part of a combination lock that opens a door. You don't have to connect anything for this script either, as the program does that for you. Just put your values in at the top and the code should run just fine.

To give you an example of what the script does, let's say you have 3 levers, each of which can be any of characters "0123456789". If you flick the first lever, the program will output "100" in the HUD. If you flick the third lever, you might get "101". You need the correct solution to open the door, which for instance, could be something like "420".

Code: Select all

-- first is lever id, second is chars to iterate through
-- add more {lever, chars} items if necessary
levers = { {"LEVER ID", "CHARS"} }
-- insert solution here
solution = "SOLUTION"
-- insert door here
door = "DOOR ID"

counters = {}
entity = 1 chars = 2

for k = 1, #levers do
	levers[k][entity] = findEntity(levers[k][entity])
	levers[k][entity]:addConnector("any", self.id, "isPulled")
	counters[k] = 0
end

function isPulled(lever)
	local correct = 0
	local string = ""

	for k = 1, #levers do
		if lever.id == levers[k][entity].id then
			counters[k] = counters[k] + 1
			if counters[k] == #levers[k][chars] then counters[k] = 0 end
		end

		local char = levers[k][chars]:sub(counters[k] + 1, counters[k] + 1)
		if char == solution:sub(k, k) then correct = correct + 1 end
		string = string .. char
	end

	hudPrint(string)
	if correct == #levers then findEntity(door):open() end
end
User avatar
Komag
Posts: 3654
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: Useful scripts repository

Post by Komag »

Proper Poison Damage While Resting
no more cheating!

I always felt it was cheap that if you got poisoned you could just rest away the poison and heal faster than the poison hurts you. With this code that is no longer the case, making it much more realistic and plausible, forcing you to actually use some antidote potions and have a little more immersive tension and urgency in the case of getting poisoned.

add a script entity lua item, name it poisonScript, containing the following code:

Code: Select all

function extraPoison()
  if not party:isResting() then return end
  if poisonTick < 2 then poisonTick = poisonTick + 1 return end
  poisonTick = 0

  for i=1,4 do
    local champ = party:getChampion(i)
    if champ:hasCondition("poison") then
      local amt = champ:getCondition("poison")
      local resist = champ:getResistance("poison")
      pr.nt(champ:getName(),amt,"resist"..resist)
      champ:damage(amt/3*(1-((resist+0.1)/100)), "poison")
    end
  end
end

poisonTick = 0
While resting, any champion who is poisoned will take extra damage over time (although the damage amount will be reduced by percentage according to their poison resistance)

The final part to make this work is left to you:

You'll need a Universal Timer set up in your dungeon (every mod should have one!), and have it run the above function every 1 second (which is sped up during resting). For example, if your universal timer is set up to tick every 1/5 of a second, then have it run the poison function poisonScript.extraPoison() once every 5 ticks.

-----
original thread for discussion/questions:
viewtopic.php?f=14&t=5718#p62575
Finished Dungeons - complete mods to play
User avatar
AdrTru
Posts: 223
Joined: Sat Jan 19, 2013 10:10 pm
Location: Trutnov, Czech Republic

Re: Useful scripts repository

Post by AdrTru »

Easy way for fix variable parameter

Code: Select all

function getEntity(ent)
    if type(ent) == "string" then ent = findEntity(ent) end
    return ent
end
This small code redefine variable ent.
Input parameter may be entity or entity.id and result is allways entity (or nil).
For me it is usefull when I call function from different sources.

Usage:

Code: Select all

function XXX(data)
   data = getEntity(data)
   if data == nil then return false end
   ..
   
   ..
end
My LOG2 projects: virtual money, Forge recipes, liquid potions and
MultiAlcoveManager, Toolbox, Graphic text,
Post Reply