Larian Banner: Baldur's Gate Patch 9
Previous Thread
Next Thread
Print Thread
Joined: Jun 2015
F
enthusiast
OP Offline
enthusiast
F
Joined: Jun 2015
Here is more of a general question about scripts than one about this specific one, I only take it as an easy example. (Might be stupid questions, but I do not understand it)

We have the following code in Torch.itemScript:

Code
... // irrelevant stuff
ITEM:__Me
EXTERN INT:%StartLit = 0

EVENTS

EVENT InitTorch
ON
	OnInit()
VARS
	INT:_IsStatusOn
ACTIONS
	IF "c1&!c2"
		IsEqual(%StartLit,1)
		ItemHasStatus(__Me,BURNING)
	THEN
		ItemApplyStatus(__Me,BURNING)
		Set(%StartLit,0)
		IF "c1"
			GetVar(_IsStatusOn,__Me,"IsStatusOn")
		THEN
			SetVar(__Me,"IsStatusOn",INT:1)
		ENDIF
	ELSE
		IF "c1&!c2"
			GetVar(_IsStatusOn,__Me,"IsStatusOn")
			ItemHasStatus(__Me,BURNING)
		THEN
			SetVar(__Me,"IsStatusOn",INT:0)
		ENDIF
	ENDIF
...


So I understand that I can have a candle start as lit or unlit.

But what about all those GetVar()s and SetVar()s ?

I thought that all 'VARS' were 'local' variables that exist throughout the function only. (Like auto variables in C)

Do those queries and calls turn them into variables persistent through saves and make a connection between all variables of that name ? (the same variable name is used in all functions in that item script)
The GetVar() in the IF does not make any sense to me, because the queried value is never used in the THEN part (only if it triggered something 'invisible' behind the scenes would it make sense)

Also, simple setting of a value could be done with Set() but here, 'external' calls are used on __Me.

And also, when is OnInit() thrown, only once when the object is created for the first time or on every savegame load as well ?

Joined: Mar 2016
Location: Belgium
T
addict
Offline
addict
T
Joined: Mar 2016
Location: Belgium
Originally Posted by FrauBlake
But what about all those GetVar()s and SetVar()s ?

I thought that all 'VARS' were 'local' variables that exist throughout the function only. (Like auto variables in C)

They're like "static" variables in C: if you give them a value during one invocation, they will still have the value during the next invocation. I don't know how it works when saving/restoring a game.

Originally Posted by FrauBlake

Do those queries and calls turn them into variables persistent through saves and make a connection between all variables of that name ? (the same variable name is used in all functions in that item script)

Note that there are two different variables in play here: the local/static _IsStatusOn ones, and then the global one that is accessed using the string constant name parameter of SetVar/GetVar ("IsStatusOn").

The former just refers to the local/static variable of the same name declared in the VARS block of the current function.

The latter will (attempt to) access a variable in the global VARS block with the name %IsStatusOn.
Originally Posted by FrauBlake

The GetVar() in the IF does not make any sense to me, because the queried value is never used in the THEN part (only if it triggered something 'invisible' behind the scenes would it make sense)

The GetVar() query returns FALSE if a global variable with the specified name (prepended with "%") is not defined in any script associated with the current item. So in this case it is only used to determine whether or not the current item has such a variable.

Since Torch.itemScript nor BurningItem.itemScript (included in Torch.itemScript) have a variable with this name, those GetVar() queries will fail if Torch.itemScript is associated with an item that does not declare a global %IsStatusOn in another script associated with the same item.

It appears that the only other script included in DOS:EE that defines such a variable is PUZZLE_StatusApplier.itemScript. This script also contains an EVENT that checks for %IsStatusOn's value, and hence would be affected by changes made by the Torch.itemScript.

Originally Posted by FrauBlake

Also, simple setting of a value could be done with Set() but here, 'external' calls are used on __Me.

You probably already know the answer to this one by now, but the Set() cannot be used to set %IsStatusOn here because it is not declared in the current script.

Originally Posted by FrauBlake

And also, when is OnInit() thrown, only once when the object is created for the first time or on every savegame load as well ?

I don't know the answer to this one.

Last edited by Tinkerer; 31/07/16 01:56 PM. Reason: Finished incomplete sentence
Joined: Sep 2015
A
addict
Offline
addict
A
Joined: Sep 2015
Quote
And also, when is OnInit() thrown, only once when the object is created for the first time or on every savegame load as well ?


The script is initiated after game start, save load and level load when the players gets in range.
If you want to have an action performed only once on init you have to use an iteger to set it off for the next inits.

PS: Thank you for the informative answer, Tinkerer. I didn't know that either.

Last edited by Abraxas*; 31/07/16 01:32 PM.

My mods for DOS 1 EE: FasterAnimations - QuietDay - Samaritan
Joined: Mar 2016
Location: Belgium
T
addict
Offline
addict
T
Joined: Mar 2016
Location: Belgium
Originally Posted by Abraxas*
PS: Thank you for the informative answer, Tinkerer. I didn't know that either.

You're welcome! I knew next to nothing about editing the various .txt/.xlsm files before reading your posts on that topic, so it's nice that I managed to give something back smile

Joined: Jun 2015
F
enthusiast
OP Offline
enthusiast
F
Joined: Jun 2015
HUGE thanks for your answers, I'm a total noob with those scripts.
(If you ever needed some Osiris answers, I'm much better with that ;-)

Originally Posted by Tinkerer
Originally Posted by FrauBlake
But what about all those GetVar()s and SetVar()s ?

I thought that all 'VARS' were 'local' variables that exist throughout the function only. (Like auto variables in C)

They're like "static" variables in C: if you give them a value during one invocation, they will still have the value during the next invocation. I don't know how it works when saving/restoring a game.

But still 'function local', having no connection to the other event's variables of that name, correct ?

BurningItem.itemScript obviously only starts and stops a candle's flame if it's lit or unlit, only stores the loop effect handle.

Must be that the BURNING status is stored with the object itself, because I see no other way it could be re-initialized by the script after a load.

Looking through the script and trying to understand it, in the case of the Torch, it does not seem to matter at all if local or static or 'script global', the variable seems to be nothing more than a 'target dump' for a potentially existing global variable.
Originally Posted by Tinkerer
Originally Posted by FrauBlake

Do those queries and calls turn them into variables persistent through saves and make a connection between all variables of that name ? (the same variable name is used in all functions in that item script)

Note that there are two different variables in play here: the local/static _IsStatusOn ones, and then the global one that is accessed using the string constant name parameter of SetVar/GetVar ("IsStatusOn").

The former just refers to the local/static variable of the same name declared in the VARS block of the current function.

The latter will (attempt to) access a variable in the global VARS block with the name %IsStatusOn.

My bad, sorry for being so stupid, should have figured that out myself.

Originally Posted by Tinkerer
Originally Posted by FrauBlake

The GetVar() in the IF does not make any sense to me, because the queried value is never used in the THEN part (only if it triggered something 'invisible' behind the scenes would it make sense)

The GetVar() query returns FALSE if a global variable with the specified name (prepended with "%") is not defined in any script associated with the current item. So in this case it is only used to determine whether or not the current item has such a variable.

Since Torch.itemScript nor BurningItem.itemScript (included in Torch.itemScript) have a variable with this name, those GetVar() queries will fail if Torch.itemScript is associated with an item that does not declare a global %IsStatusOn in another script associated with the same item.

It appears that the only other script included in DOS:EE that defines such a variable is PUZZLE_StatusApplier.itemScript. This script also contains an EVENT that checks for %IsStatusOn's value, and hence would be affected by changes made by the Torch.itemScript.

Does it only return FALSE because the variable is not found in global space or does it also set the local (static) _IsStatusOn to 'null' ?

Also, can globals (%xyz) be accessed in 'parallel' scripts that do not #include them or must there be some 'connection' ?
Originally Posted by Tinkerer
Originally Posted by FrauBlake

Also, simple setting of a value could be done with Set() but here, 'external' calls are used on __Me.

You probably already know the answer to this one by now, but the Set() cannot be used to set %IsStatusOn here because it is not declared in the current script.

Originally Posted by FrauBlake

And also, when is OnInit() thrown, only once when the object is created for the first time or on every savegame load as well ?

I don't know the answer to this one.

So put together, all that variable querying and setting is only for additional scripts that might get attached to an item and have that variable ? It serves no purpose if only Torch.itemScript is attached ?

Sorry again for asking stupidly. This script greatly confused me and finding no global variable of that name made me suspect that some 'hidden magic' was going on behind the scene. I never would have thought that a script contained some 'pro-active' stuff. But then, maybe it's just left over from something that existed before. (Cleaning up is not easy ;-)

The reason I picked just that script was that I want to create a candle that always burns if I move it out of inventory. Currently it is way too easy to trigger the OnUse event which might leave a candle off when used as a 'grenade'. Happened to me quite often and there's no way to check the state while a candle is in the inventory.

Do you also happen to know, what the 'data "Flags" "Torch"' in stat entries means ?
Could it have something to do with only items with it receiving the events handled in BurningItem.itemScript at all ? (Only found the events there)
All root templates that have the Torch.itemScript seem to use Stats with this flag.


BTW, your videos with the moving wagons are quite impressive !!

Joined: Jun 2015
F
enthusiast
OP Offline
enthusiast
F
Joined: Jun 2015
Originally Posted by Abraxas*
Quote
And also, when is OnInit() thrown, only once when the object is created for the first time or on every savegame load as well ?


The script is initiated after game start, save load and level load when the players gets in range.
If you want to have an action performed only once on init you have to use an iteger to set it off for the next inits.

PS: Thank you for the informative answer, Tinkerer. I didn't know that either.

MUCH thanks for your answer.

So that makes it an ideal place to clear a globally stored loop effect handle. (As done in BurningItem.itemScript)
... means I can remove some event catchers in my character script like OnLoaded I guess ;-)

Do you also happen to know if the game turns off loop effects on zoning ?
Could I restart a loop effect in an OnInit event after loading or would I additionally have to to wait until GameIsLoading() returned false ?

And finally, do you know if a timer is attached to the object that started it so that the finish event is only sent to that object or is that a global event ?

Joined: Jun 2013
old hand
Offline
old hand
Joined: Jun 2013
Originally Posted by FrauBlake

Do you also happen to know if the game turns off loop effects on zoning ?


It does when created from an Osiris call, I ran into this problem with A Necromancer's Crusade. I'm not sure if it's the same when created via item script though.


Joined: Jun 2015
F
enthusiast
OP Offline
enthusiast
F
Joined: Jun 2015
Originally Posted by SniperHF
Originally Posted by FrauBlake

Do you also happen to know if the game turns off loop effects on zoning ?


It does when created from an Osiris call, I ran into this problem with A Necromancer's Crusade. I'm not sure if it's the same when created via item script though.


... and it does when the game ends, because I have to restart it after a load.

The effect of torches is different from this because it's triggered by a status which is probably saved, mine isn't.

Joined: Mar 2016
Location: Belgium
T
addict
Offline
addict
T
Joined: Mar 2016
Location: Belgium
Originally Posted by FrauBlake
Originally Posted by Tinkerer
Originally Posted by FrauBlake
I thought that all 'VARS' were 'local' variables that exist throughout the function only. (Like auto variables in C)

They're like "static" variables in C: if you give them a value during one invocation, they will still have the value during the next invocation. I don't know how it works when saving/restoring a game.

But still 'function local', having no connection to the other event's variables of that name, correct ?

Correct.

Originally Posted by FrauBlake

Must be that the BURNING status is stored with the object itself, because I see no other way it could be re-initialized by the script after a load.

I don't know how Osiris internally handles item statuses. OTOH, saving and loading does not suddenly remove a poisoned status from a character either, so it would seem logical for all statuses to be stored as part of every object, since they were not necessarily set by the OnInit event of a script.

Originally Posted by FrauBlake

Looking through the script and trying to understand it, in the case of the Torch, it does not seem to matter at all if local or static or 'script global', the variable seems to be nothing more than a 'target dump' for a potentially existing global variable.

Yes. And in that case, you don't even need a local variable. The script author could just have used "_" as an anonymous variable, like in Osiris scripts.

Originally Posted by FrauBlake
Originally Posted by Tinkerer
Note that there are two different variables in play here: the local/static _IsStatusOn ones, and then the global one that is accessed using the string constant name parameter of SetVar/GetVar ("IsStatusOn").

The former just refers to the local/static variable of the same name declared in the VARS block of the current function.

The latter will (attempt to) access a variable in the global VARS block with the name %IsStatusOn.

My bad, sorry for being so stupid, should have figured that out myself.

It's easy to miss such details when you start out with these scripts, happened to me also several times.

Originally Posted by FrauBlake

Does it only return FALSE because the variable is not found in global space or does it also set the local (static) _IsStatusOn to 'null' ?

I don't know if it sets the result in case the variable does not exist, but I would not count on it. Even in case it does so today, that is definitely the kind of thing that may well be "implementation defined" or "undefined behaviour". I come from a compiler development background, and this is a very recognisable situation smile

Originally Posted by FrauBlake

Also, can globals (%xyz) be accessed in 'parallel' scripts that do not #include them or must there be some 'connection' ?

The connection is that the scripts must be associated with the same game object. They do not have to include each other. The variables are not part of a script (otherwise you would have one global variable shared by all game objects that use that script), but part of a game object.

Originally Posted by FrauBlake

So put together, all that variable querying and setting is only for additional scripts that might get attached to an item and have that variable ? It serves no purpose if only Torch.itemScript is attached ?

It serves the purpose that (the rest of) this script can be used both for items that do have additional scripts with these variables and for items that don't have them. It's basically introspection to help make the script more generic.

Originally Posted by FrauBlake

Do you also happen to know, what the 'data "Flags" "Torch"' in stat entries means ?
Could it have something to do with only items with it receiving the events handled in BurningItem.itemScript at all ? (Only found the events there)
All root templates that have the Torch.itemScript seem to use Stats with this flag.

I don't know, sorry. I never delved into the stats files. In general it does seem like several things have been implemented specifically for certain use cases because (possibly at that time) the generic scripting framework did not support the required functionality. I've seen some comments dating back to the early 2000s in some Osiris scripts, so there is probably quite a bit of cruft left smile

Quote

BTW, your videos with the moving wagons are quite impressive !!

Thanks smile The character and item scripts in that mod contain lots of comments, so you can also have a look at the code to learn more about how that part of the scripting system works.

Joined: Jun 2015
F
enthusiast
OP Offline
enthusiast
F
Joined: Jun 2015
Originally Posted by Tinkerer
I don't know how Osiris internally handles item statuses. OTOH, saving and loading does not suddenly remove a poisoned status from a character either, so it would seem logical for all statuses to be stored as part of every object, since they were not necessarily set by the OnInit event of a script.

I'm not even sure that it has to do with Osiris at all. I'd think it's the engine itself. Osiris itself might only be an API to the engine.

Originally Posted by Tinkerer
The connection is that the scripts must be associated with the same game object. They do not have to include each other. The variables are not part of a script (otherwise you would have one global variable shared by all game objects that use that script), but part of a game object.

Of course, that's what I meant ;-)

Do you happen to know if a timer started from a script gets 'attached' to the starting object and sends its finish event only to that object or would that be sent to world ?

(Timers don't have anything but the timer name as parameter so I'm unsure about it.)

Joined: Jun 2015
F
enthusiast
OP Offline
enthusiast
F
Joined: Jun 2015
I think I found out myself, it really seems to be the creator only who gets the timer finished event, at least that's what it looked like in a simple test, so no need to bother with this question anymore hehe


Link Copied to Clipboard
Powered by UBB.threads™ PHP Forum Software 7.7.5