local/global "persistant" variables, in scripts/functions

Talk about creating Grimrock 1 levels and mods here. Warning: forum contains spoilers!
hades200082
Posts: 14
Joined: Sun Feb 24, 2013 5:49 pm

Re: local/global "persistant" variables, in scripts/function

Post by hades200082 »

Sorry. Didn't see the dates

Was looking to see if I could use functions from an included lua file ion the editor.
Marble Mouth
Posts: 52
Joined: Sun Feb 10, 2013 12:46 am
Location: Dorchester, MA, USA

Re: local/global "persistant" variables, in scripts/function

Post by Marble Mouth »

I'm going to have to disagree with Antti on this one. In this code:

Code: Select all

function setVariable(variable, value)
   variable = value
end
Both variable and value are implicitly local to the function setVariable. Arguments are always local. So when lua evaluates the line "variable = value", it sets the local named "variable" to whatever value was passed in as the second argument. That has no effect on the "global" variables of the script_entity named variable_storage. Grimrock lua does not support the function loadstring either, which could also solve this problem. I think you would have to make a setter function for each variable that you want to be able to set from outside of the script entity, and hardcode the variable to be set by that function.

Reading this thread raised my blood pressure for a minute, until I confirmed that tables are indeed now supported in save games.

And I am aware that this is an old thread and the people who were originally interested may not be here anymore.

As a general matter of scripting habits, whenever you find yourself wanting to set a variable inside another script, you should consider why you need to. If at all possible, you should avoid this. Data should be housed in the same place where it is used. Reading a variable from another script_entity is tolerable, but writing to a variable in another script_entity can get very messy very quickly. You could end up with weird values in your variables (possibly the wrong data type,) and have no idea how those values got there. If possible, all the code that can modify any specific variable should live in the same script as that variable. It can help a lot to organize your scripts into an informal hierarchy: this is a top level (level 1) script, so it is allowed to call any script. This other script is a lower level script, so it should do all of its own nitty-gritty work, and other scripts should call on it to perform very specific tasks.

As an example, suppose I have a script that tracks a "burn" effect that can be applied to a party member by a monster or trap:

Code: Select all

setBurned = function( champion )
   burned = champion
end

setBurnTimeRemaining = function( time )
   burnTimeRemaining = time
end

function onTick() --called by a Timer
   if burned then
      burned:damage( 3 , "fire" )
   end
   burnTimeRemaining = burnTimeRemaining - 1
   if burnTimeRemaining == 0 then
      burned = nil
   end
end
And I use that script like so:

Code: Select all

burnScript.setBurned(party:getChampion(1))
burnScript.setBurnTimeRemaining(5)
But this script only allows one champion to be burning at a time. If I try to make another champion burning, it will overwrite the value that was already present in the variable "burned". And there's a couple other little changes I want to make. So I decide to change how I implemented burning to use a table instead:

Code: Select all

burned = {} --keys are ordinals, value is the time remaining for that champion to burn

setBurn = function( champion , time )
   local oldTime = burned[champion:getOrdinal()]
   if oldTime and ( oldTime > time ) then --don't reduce the time if the champion was already burning
      return
   end
   burned[champion:getOrdinal()] = time
end

function onTick() --called by timer
   for i = 1,4 do
      local ordinal = party:getChampion(i):getOrdinal()
      if burned[ordinal] then
         party:getChampion(i):damage( 3 , "fire" )
         local newTime = burned[ordinal] - 1
         if newTime == 0 then
            newTime = nil
         end
         burned[ordinal] = newTime
      end
   end
end
And now I have to use my script like so:

Code: Select all

burnScript.setBurn( party:getChampion(1) , 5 )
So I have to rewrite (slightly) everything that uses my burnScript. But even when I wasn't using a table to implement the burning, I should have written burnScript differently in the first place. I should have written it so that other scripts call burnScript and tell it what to do, not how to do it. If I had thought of making a champion burn as a single "action" that always requires both a champion and a duration, then I would have written burnScript as:

Code: Select all

setBurn = function( champion , time )
   burned = champion
   burnTimeRemaining = time
end

function onTick() --called by a Timer
   if burned then
      burned:damage( 3 , "fire" )
   end
   burnTimeRemaining = burnTimeRemaining - 1
   if burnTimeRemaining == 0 then
      burned = nil
   end
end
and my calls to burnScript as:

Code: Select all

burnScript.setBurn( party:getChampion(1) , 5 )
in the first place, so I would only have to change burnScript. The calling scripts wouldn't depend on setting specific variables within burnScript. I wouldn't have to change the calling scripts to change the implementation and improve the functionality. That is absolutely huge, in terms of keeping script development moving forward while still being able to fix bugs and enhance functionality in scripts that you've already written.
User avatar
Komag
Posts: 3658
Joined: Sat Jul 28, 2012 4:55 pm
Location: Boston, USA

Re: local/global "persistant" variables, in scripts/function

Post by Komag »

If I hadn't already superthreaded this, I would do so now, as that is some powerful deep stuff, thanks! :)
Finished Dungeons - complete mods to play
User avatar
akroma222
Posts: 1029
Joined: Thu Oct 04, 2012 10:08 am

Re: local/global "persistant" variables, in scripts/function

Post by akroma222 »

Very good to know, thanks all for the lesson.... time to redo some puzzles :roll:
Post Reply