Issues with variables in dialogue result scripts

Post » Tue May 17, 2011 7:10 am

So I have the following script on one NPC:

short Player5sshort Player20sshort Player100sshort PlayerOwesshort ExchangeInshort ExchangeOutshort Billsshort Changeset ExchangeIn to 100set ExchangeOut to 43set Player5s to player.GetItemCount MoneyNCR5set Player20s to player.GetItemCount MoneyNCR20set Player100s to player.GetItemCount MoneyNCR100set PlayerOwes to ExchangeInIF Player100s >= 1 && PlayerOwes >= 100  set Bills to (PlayerOwes / 100)  IF Player100s >= Bills    player.RemoveItem MoneyNCR100 Bills    set PlayerOwes to (PlayerOwes - (Bills * 100))    set Player100s to (Player100s - Bills)  ELSEIF Player100s < Bills    player.RemoveItem MoneyNCR100 Player100s    set PlayerOwes to (PlayerOwes - (Player100s * 100))    set Player100s to 0  ENDIFENDIFIF Player20s >= 1 && PlayerOwes >= 20  set Bills to (PlayerOwes / 20)  IF Player20s >= Bills    player.RemoveItem MoneyNCR20 Bills    set PlayerOwes to (PlayerOwes - (Bills * 20))    set Player20s to (Player20s - Bills)  ELSEIF Player20s < Bills    player.RemoveItem MoneyNCR20 Player20s    set PlayerOwes to (PlayerOwes - (Player20s * 20))    set Player20s to 0  ENDIFENDIFIF Player20s < 1 && PlayerOwes >= 20 && Player100s >= 1  set Bills to (PlayerOwes / 20)  player.RemoveItem MoneyNCR100 1  set Player100s to (Player100s - 1)  set Change to (5 - Bills)  player.AddItem MoneyNCR20 Change  set Player20s to (Player20s + Change)  set PlayerOwes to (PlayerOwes - (Bills * 20))ENDIFIF Player5s >= 1 && PlayerOwes >= 5  set Bills to (PlayerOwes / 5)  IF Player5s >= Bills    player.RemoveItem MoneyNCR5 Bills    set Player5s to (Player5s - Bills)    set PlayerOwes to (PlayerOwes - (Bills * 5))  ELSEIF Player5s < Bills    player.RemoveItem MoneyNCR5 Player5s    set Player5s to 0    set PlayerOwes to (PlayerOwes - (Player5s * 5))  ENDIFENDIFIF Player5s < 1 && PlayerOwes >= 5  IF Player20s < 1    player.RemoveItem MoneyNCR100 1    set Player100s to (Player100s - 1)    player.AddItem MoneyNCR20 5    set Player20s to (Player20s + 5)  ENDIF  IF Player20s >=1    set Bills to (PlayerOwes / 5)    player.RemoveItem MoneyNCR20 1    set Player20s to (Player20s - 1)    set Change to (4 - Bills)    player.AddItem MoneyNCR5 Change    set Player5s to (Player5s + Change)    set PlayerOwes to (PlayerOwes - (Bills * 5))  ENDIFENDIF player.AddItem Caps001 ExchangeOutset JordyDialogue.NCROnHand to (JordyDialogue.NCROnHand + ExchangeIn)set JordyDialogue.PlayerNCROnHand to (JordyDialogue.PlayerNCROnHand - ExchangeIn)set JordyDialogue.PlayerCapsOnHand to (JordyDialogue.PlayerCapsOnHand + ExchangeOut)


It successfully pulls out the appropriate amount of mixed NCR bills, until $100 total has been removed, and then gives the player 43 caps. Seems pretty obvious that the temporary variables defined at the start of the script are working fine.

Now on another NPC, I have this...

short Player5sshort Player20sshort Player100sshort Owedshort Billsset Player5s to player.GetItemCount MoneyNCR5set Player20s to player.GetItemCount MoneyNCR20set Player100s to player.GetItemCount MoneyNCR100set Owed to 200player.RemoveItem MoneyNCR5 1player.RemoveItem MoneyNCR20 Player20sIF Player100s >= 2  player.RemoveItem MoneyNCR100 2  set Owed to 0ELSEIF Player100s == 1  player.RemoveItem MoneyNCR100 1  set Owed to 100ENDIFset Bills to (Owed / 20)IF Player20s >= Bills && Owed >= 20  player.RemoveItem MoneyNCR20 Bills  set Owed to 0ELSEIF Player20s >= 1 && Owed >= 20  player.RemoveItem MoneyNCR20 Player20s  set Owed to (Owed - (Player20s * 20))ENDIFset Bills to (Owed / 5)IF Player5s >= Bills && Owed >= 5  player.RemoveItem MoneyNCR5 Bills  set Owed to 0ELSEIF Player5s >= 1 && Owed >= 5  player.RemoveItem MoneyNCR5 Player5s  set Owed to (Owed - (Player5s * 5))ENDIF


I added the line to remove a single $5, and to remove $20's equal to Player20s, just as a test. However the only thing this script does when I hit that dialogue topic, is remove a single $5 -- seems apparent that something isn't working correctly with the temporary variables that I'm setting.


...anyone have any clues as to what I'm missing here?
User avatar
Luna Lovegood
 
Posts: 3325
Joined: Thu Sep 14, 2006 6:45 pm

Post » Tue May 17, 2011 5:33 am

Note: I can effectively do what I want by not using the variables, and just repeating the player.GetItemCount function...

Example, replacing...

IF Player100s >= 2


...with...

IF (player.GetItemCount MoneyNCR100) >= 2


...but I'd still like to know what I'm missing... why setting the temp variables work on the one NPC, but not on another (I have a large number of dialogue result scripts like this).

Any thoughts/ideas/input highly appreciated.

- DU
User avatar
Nims
 
Posts: 3352
Joined: Thu Jun 07, 2007 3:29 pm

Post » Tue May 17, 2011 7:49 am

The dialogue result script runs on the speaker. The variables you define in the result script are either assigned to the quest or have no assignment at all. Your variables might clutter some memory somewhere but are not used otherwise.

Once the script is compiled it doesn't care about your names anymore, your variables are numbered consecutively and the script uses those numbers to access the variables: set Player5s to 42 in your case would be translated to "set Variable #1 to 42"

If the NPC now has variables, then scripts that run on the NPC can access those variables, regardless of the names you gave them in the source code. E.g. when the NPC has the variables:

short var1
short var2
short var3

then your dialogue result script would use them this way:

var1 = Player5s
var2 = Player20s
var3 = Player100s

Variables that have no counterpart (e.g. PlayerOwes when the NPC has only 3 variables) will permanently stay at 0 in the dialogue result script. There even is a chance that some other values of the speaker, commands in the speaker's script, or something seemingly completely unrelated will be overwriten when you write to those rogue variables.

These are the same techniques virus programmers use to make the flash player install their junk on your PC; and yes, there should be a warning when you define variables in a result-script.

Use global variables or variables you defined on the NPCs or the Quest instead. (using proper references)
User avatar
Lisha Boo
 
Posts: 3378
Joined: Fri Aug 18, 2006 2:56 pm

Post » Tue May 17, 2011 12:56 am

Ack! You are saying that variables declared in a result script use the same memory as the (apparently unrelated) variables in the speaker's object script? Is this described anywhere in the geck wiki, or is there a recommendation anywhere to not declare variables in result scripts? I use variables in all different places as a convenient shorthand or as the local result of an expression. Does this problem apply to variables declared in other places, such as the "on begin/end/change" section of a package? Apart from a named script file, is there anywhere safe to declare a variable?
User avatar
Paula Ramos
 
Posts: 3384
Joined: Sun Jul 16, 2006 5:43 am

Post » Tue May 17, 2011 1:32 pm

Ack! You are saying that variables declared in a result script use the same memory as the (apparently unrelated) variables in the speaker's object script?


No I'm saying that variables declared in a result script are not used (if they exist at all). The script runs on the speaker and thus the speaker's variables (if available) are used. The Geck has no way of knowing what NPCs will be affected by the result script when you compile it. It only knows that variable #1 shall be used, and it knows that no reference was given. Thus variable #1 of the speaker is used at runtime.

Is this described anywhere in the geck wiki, or is there a recommendation anywhere to not declare variables in result scripts?

Don't think so, I might have writen it some 4 years ago in the TESCS Wiki. AFAIR the Morrowind CS simply crashed when you tried to compile a dialogue result script with declared variables, Oblivion's didn't.

I use variables in all different places as a convenient shorthand or as the local result of an expression. Does this problem apply to variables declared in other places, such as the "on begin/end/change" section of a package?


The dialogue result is the only thing that comes to my mind, the only other way to apply new scripts at runtime is an effect, but here the variables are assigned to the temporary effect reference.

Apart from a named script file, is there anywhere safe to declare a variable?


Globals or quests would be the obvious choices. It *might* work if you used the reference of that quest (JordyDialogue.Player5s in the first example)

A better choice for complex results would be quest stage scripts imo. Those would use the quest's variables by default.


Edit:
http://cs.elderscrolls.com/constwiki/index.php/Result_scripts

Clearly forbids declaring variables in result scripts. The dirty little trick to hijack an NPCs local variables seems undocumented, though.

And yes, My note about not being able to use the implied reference to access the actor's variables is only half the truth. :hubbahubba: If you take my above example, you cannot use "Var1" in the dialogue result script, but you *can* access it by declaring a variable in the result script (but you shouldn't unless it's just a proof of concept)
User avatar
lacy lake
 
Posts: 3450
Joined: Sun Dec 31, 2006 12:13 am

Post » Tue May 17, 2011 3:58 pm

This is very helpful and surprising. I have sometimes had odd bugs which I could not track down in different scripts; I will have to check carefully to see if this is the cause. From the non-programmer standpoint, the rule you point to in the obscure TES link is a key one: even though you can declare and (apparently) use variables in dialog result scripts, *never do this*. What happens is very hard to predict to a non-programmer. From the programmer standpoint, I understand your reference to buffer overflow exploits and I think we are describing the same problem in different terms.

Now I am concerned about the safeness of local variable declarations in other types of scripts.

* In dialog result scripts: as discussed these "shadow" NPC script variables, but this "dirty little trick" would be very hard to maintain.

* In quest stage scripts: do these "shadow" quest variables, or do these have their own storage allocated?

* Package begin/change/end: are local variable declarations safe?

* Terminal scripts: are local variable declarations safe?

There may be other places where scripts can be entered; is there a general rule about where these may be safe?
User avatar
electro_fantics
 
Posts: 3448
Joined: Fri Mar 30, 2007 11:50 pm

Post » Tue May 17, 2011 3:30 am

Well... well... CRUD.

Very useful information, thank you very much. Unfortunately, that also means that I have several hundred result scripts that have been working due to a lucky interaction, that I need to go change to avoid pushing my luck. *sigh*


Question then, as my understanding is still kinda funky here (still trying to learn about a lot of things here): Is there a downside to using a single generic quest/script to declare several different variables that are then used (and properly referenced) in the result scripts of several different NPCs associated with the mod?

...would it make a difference if the NPCs with such result scripts included both new custom NPCs, and vanilla NPCs whose dialogue is being modified?
User avatar
quinnnn
 
Posts: 3503
Joined: Sat Mar 03, 2007 1:11 pm

Post » Tue May 17, 2011 1:09 pm

]* In dialog result scripts: as discussed these "shadow" NPC script variables, but this "dirty little trick" would be very hard to maintain.

Yes, the only valid application would be shadowing an NPC's variables in the result script so that you can access them in the result script, but in this case you can just as well use references to that NPC.

* In quest stage scripts: do these "shadow" quest variables, or do these have their own storage allocated?

Quest-stage scripts are non-reference scripts just like quest scripts. They default to the quest. I haven't tested what happens when you declare variables, or use the same names as in the quest script, though, but I assume each quest-stage has its own set of variables assigned to the quest.

* Package begin/change/end: are local variable declarations safe?
* Terminal scripts: are local variable declarations safe?
There may be other places where scripts can be entered; is there a general rule about where these may be safe?

As a rule, the variables of the object are used that is directly (without reference-pointers) affected by functions. (i.e. the object that will vanish when you just type "disable".)

I thought that dialogue results are the only instance where a reference-script gets its reference assigned at runtime, but submenu-terminal should also use the variables of the terminal-object that called it.

For packages I'm not so sure now. The package runs on the NPC so yes, it may be the same case.

Generally I'd avoid complex scripts using their own variables in any tiny "result" box.
User avatar
Tom Flanagan
 
Posts: 3522
Joined: Sat Jul 21, 2007 1:51 am

Post » Tue May 17, 2011 6:53 am

Is there a downside to using a single generic quest/script to declare several different variables that are then used (and properly referenced) in the result scripts of several different NPCs associated with the mod?


IMHO, the scripting language has a number of limitations and unexpected interactions, so as a programmer, I find it hard to predict what is the best way to implement a particular behavior that I want. I had no idea about this limitation. In general, I have declared many variables in quest scripts, and then used them in different places. I did this because I find it slightly cleaner than using a "global" variable. "Never use globals" has been burned into my mind for many years.

In your case, it seems that you *want* local variables, but a reasonable way to *get* them may be by declaring them in one quest script. The scripts you have will become slightly verbose, especially if your quest script has a long name. If you had a local variable before named "x", and your quest is named "myquest", you will need to change all the variable references to "myquest.x". But, at least the results will be predictable. I am sure you recognize that when doing this, you will need to make sure that each script initializes the variables before using them. You will not be able to "assume" that the quest variables are initialized to zero.
User avatar
R.I.p MOmmy
 
Posts: 3463
Joined: Wed Sep 06, 2006 8:40 pm

Post » Tue May 17, 2011 5:01 am

Quest-stage scripts are non-reference scripts just like quest scripts. They default to the quest. I haven't tested what happens when you declare variables, or use the same names as in the quest script, though, but I assume each quest-stage has its own set of variables assigned to the quest.

Don't take this personally, in case you wrote the code. But given the limitations you have just pointed out for dialog result variables, I think it is highly unsafe to "assume" that quest stage local variables are allocated their own space and do not "clobber" the quest script variables.

* Package begin/change/end: are local variable declarations safe?
* Terminal scripts: are local variable declarations safe?
There may be other places where scripts can be entered; is there a general rule about where these may be safe?

Those are reference scripts with the script running on the package/terminal.

As a rule, the variables of the object are used that is directly (without reference-pointers) affected by functions. (i.e. the object that will vanish when you just type "disable".)

IMO dialogue results are the only instance where a reference-script gets its reference assigned at runtime.

I was not able to understand. For terminals I guess there is no way to attach a separate script to a terminal object, so maybe it cannot matter.

But a package runs on an NPC. Will local variables declared in a package begin/change/end script "clobber" variables on the NPC? Or are they safe? I have had a number of weird behaviors when trying to write scripts in the begin/change/end clauses, and I am not able to understand the reason. Do you have any helpful information on what can or cannot go into a package script?
User avatar
Erika Ellsworth
 
Posts: 3333
Joined: Sat Jan 06, 2007 5:52 am

Post » Tue May 17, 2011 2:51 am

Yes, my thinking is that I want local variables with much of what I'm doing.

One thing that needs to be done regularly for example in my mod (for reference sake, this is the Complete Economy Overhaul mod that I'm working on), is figure out how much of different currencies the player has, and take action based on that.

In the vanilla game it is generally easy, since everything is based off of caps -- so a simple player.getitemcount will suffice. With the alternate currencies however, I need to do some calculations in order to come up with the "single value" for comparison's sake.

Example: Major Knight wants NCR$ instead of caps to buy a pardon for the Primm sheriff.
In vanilla:
  • There is a dialogue conditional for player.getitemcount, with one branch at >=200 and another at <200
  • On the >=200 branch, the result script includes a simple player.removeitem to take away the 200 caps


For what I'm doing:
  • In order to use the dialogue conditionals I have to compare to a single variable that holds the NCR$ amount the player has at the moment, as an int.
  • To get that, on a previous dialogue topic's result script, I need to run a player.getitemcount for each denomination, multiply the result by the face value of that particular bill, add the results together, then store that to be checked by the dialogue conditional
  • On the >=200 branch, I have to pay out the $200 -- but have to figure out what bills are available to do so


This example is actually easier than many others, as the amount to be paid is nice and round. It gets even more fun when the player needs to pay $50, but doesn't have any $5s, so change needs to be made.


My current implementation obviously needs to be changed since I'm getting away with things in some places without realizing it... but with this new information I'm thinking using a single quest to define variables like "PlayerNCR5Count" that can be used and reused by different NPCs (obviously being sure to always run player.getitemcount to refresh the variable's value with each conversation).

...is there a more graceful way to accomplish this, or am I on the right track?
User avatar
Micah Judaeah
 
Posts: 3443
Joined: Tue Oct 24, 2006 6:22 pm

Post » Tue May 17, 2011 4:02 am

...is there a more graceful way to accomplish this, or am I on the right track?


I think both of us are making the mistake of treating this as a "programming" language. Perhaps the next games such as skyrim and dragon age II will use a proper programming language, maybe tcl or python or lua as other games have done. We cannot do some things which a real programming language would allow, such as subroutines, "real" local variables, etc. Just think of it as programming a Turing machine on a paper strip and you will be fine. (Programmer humor).

Clearly a subroutine is the "right" way to do the repeated conversions you describe. Maybe somehow you could use a placeholder object, which has an activator and a reference id, and send "begin activate" to trigger the conversion? I have never tried this and I'm not aware of any other places where this is used, but it could possibly work. I highly recommend to create a small standalone proof of concept esp for this, before making any large scale changes.
User avatar
sarah taylor
 
Posts: 3490
Joined: Thu Nov 16, 2006 3:36 pm

Post » Tue May 17, 2011 3:53 am

Don't take this personally, in case you wrote the code. But given the limitations you have just pointed out for dialog result variables, I think it is highly unsafe to "assume" that quest stage local variables are allocated their own space and do not "clobber" the quest script variables.


quest stage scripts and quest scripts are what gamesas calls "non-reference scripts" they are the only kind of script that isn't attached to an object that exists in the game world. So yes, they may be different. I can't remember having seen any variable declaration in quest stages, though. And I don't really see the need for it. If it's just about keeping the script readable, declare the variables in the quest script and use comments in the quest stage script.


I was not able to understand. For terminals I guess there is no way to attach a separate script to a terminal object, so maybe it cannot matter.


I had revised the above while you answered. Terminals *do* have scripts, and yes, I assume variables defined in the result scripts will "clobber" the world-object's variables.

But a package runs on an NPC. Will local variables declared in a package begin/change/end script "clobber" variables on the NPC? Or are they safe? I have had a number of weird behaviors when trying to write scripts in the begin/change/end clauses, and I am not able to understand the reason. Do you have any helpful information on what can or cannot go into a package script?


No, it may very well be as you said. I never even had the idea to declare variables in result scripts. Usually, when a result script needs to do something complicated, then I set a variable and let a proper script do the work.
User avatar
Trish
 
Posts: 3332
Joined: Fri Feb 23, 2007 9:00 am

Post » Tue May 17, 2011 6:03 am

No, it may very well be as you said. I never even had the idea to declare variables in result scripts. Usually, when a result script needs to do something complicated, then I set a variable and let a proper script do the work.

In the interest of helping out the newbie here, could you please explain "set a variable and let a proper script do the work"?
User avatar
Sara Lee
 
Posts: 3448
Joined: Mon Sep 25, 2006 1:40 pm

Post » Tue May 17, 2011 5:50 am

...is there a more graceful way to accomplish this, or am I on the right track?


Why not use globals to sum up your getitemcounts?

You also could use tokens (non-playable items) to create new variables on npcs on-the-fly (i.e. instead of "Set newVar to 100" use "Addditem NewVarToken 100") When you use an OnAdd Script in combination with GetContainer you can do all kinds of things to the new owner of the token.

In the interest of helping out the newbie here, could you please explain "set a variable and let a proper script do the work"?


in the result script:
set Myquest.NowDoit to 1


in Myquest's script
if NowDoit == 1   DoSomethingNifty   set NowDoit to 0endif


Though tokens might be preferable since you can easily get the reference of the NPC they're runing on.


E.g.

scn testtokenref ownerbegin onAdd  set owner to GetContainer  if owner.isActor      Owner.Setscale 0.5  endifend


Attach it to an item, and make a dialogue option for everyone to gives them the item.

Just by saying "shut up shorty" you can turn everyone into a halfling.
User avatar
Loane
 
Posts: 3411
Joined: Wed Apr 04, 2007 6:35 am

Post » Tue May 17, 2011 6:54 am

I never even had the idea to declare variables in result scripts. Usually, when a result script needs to do something complicated, then I set a variable and let a proper script do the work.

In most programming languages, this works, and is considered a good idea for readability:
int ibegin...   set i to x + y + somefunction + someotherfunction   if i < 10      ... do something   elseif i < 20      ... do some other thing   endifend

However, if we do this in a result script, it compiles and runs. But it turns out to clobber the first NPC variable, or fails to work at all if the NPC has no variables. Writing this instead is much less readable, subject to maintenance problems, etc:
begin ...   if x + y + somefunction + someotherfunction < 10      ... do something   elseif x + y + somefunction + someotherfunction < 20      ... do some other thing   endifend

That is an excellent example of how a programmer may "assume" something works, when we are learning in this thread that it is silently messing up some other script.
User avatar
Franko AlVarado
 
Posts: 3473
Joined: Sun Nov 18, 2007 7:49 pm

Post » Tue May 17, 2011 4:32 am

My current implementation obviously needs to be changed since I'm getting away with things in some places without realizing it... but with this new information I'm thinking using a single quest to define variables like "PlayerNCR5Count" that can be used and reused by different NPCs (obviously being sure to always run player.getitemcount to refresh the variable's value with each conversation).

...is there a more graceful way to accomplish this, or am I on the right track?


I use a container object to hold the player's currency amount in my own faction currency mod. You only need one quest script and minor set-up in each dialogue result script to do everything you're trying to do. By using a chest instead of variables it's much easier to do multiple currency types.

E.G.

...	;NCR $5	set nCurrentItems to (rCurrencyChest.GetItemCount MoneyNCR5)	if (nConversionPool >= 5)		set nItemMax to (nConversionPool / 5)		if (nCurrentItems >= nItemMax)			rCurrencyChest.RemoveItem MoneyNCR5 nItemMax ;only removes max items			Set nConversionPool to (nConversionPool - (nItemMax * 5))		else			rCurrencyChest.RemoveItem MoneyNCR5 nCurrentItems ;removes all items			Set nConversionPool to (nConversionPool - (nCurrentItems * 5))		endif			endif...	;Legion $25	set nCurrentItems to (rCurrencyChest.GetItemCount MoneyLegion25)	if (nConversionPool >= 25)		set nItemMax to (nConversionPool / 25)		if (nCurrentItems >= nItemMax)			rCurrencyChest.RemoveItem MoneyLegion25 nItemMax ;only removes max items			Set nConversionPool to (nConversionPool - (nItemMax * 25))		else			rCurrencyChest.RemoveItem MoneyLegion25 nCurrentItems ;removes all items			Set nConversionPool to (nConversionPool - (nCurrentItems * 25))		endif			endif

User avatar
Thema
 
Posts: 3461
Joined: Thu Sep 21, 2006 2:36 am

Post » Tue May 17, 2011 2:24 am

in the result script:
set Myquest.NowDoit to 1

in Myquest's script
if NowDoit == 1    DoSomethingNifty    set NowDoit to 0 endif


Here is another place where programmers make assumptions which lead in the wrong direction. I agree the above works. But I would never have thought of this, until it was pointed out to me in other threads at newvegasnexus. This type of approach is not "scalable" for a large number of quests; the program will eventually slow down to a crawl and no individual programmer will be "responsible".

In programming terminology, each of the two scripts you mention above can be called a "thread" and the above implementation has two threads running every frame. You are using a "semaphore" in one thread to alert the other thread. As a programmer, one concern I have with threads is that the order of operation of multiple threads is unknown. For example, with two threads running simultaneously, there is no guarantee that one thread will finish before another starts, and the operations may be interleaved. That is minor; the larger problem is runtime efficiency. If every quest developer starts throwing around a dozen threads for convenience, then there may be many hundreds of threads which all need to update every frame. This will eventually cause a noticeable slowdown.

On the other threads at newvegasnexus, the people replying to my comments have said that machines are fast enough to run all these threads with no slowdown; but many programmers would consider throwing multiple threads at these problems to be a "last resort" after trying all other possible approaches. In fact, I have come across certain comments in the base game scripting code which indicates this *did* become a problem during development and a number of scripts were hacked to try to improve the runtime. For example, see this comment in VERShadows01QuestScript:
; This GameMode script runs with a low frequency update so as to save processing cycles. It's responsible for some encounters in the Mountain Shadows Campground - including a Cazador take-over.
; Moved this encounter to Bonnie Springs, and reduced the number of spawns, so that we can run shenanigans on adorable consoles.
; - Jorge

User avatar
flora
 
Posts: 3479
Joined: Fri Jun 23, 2006 1:48 am

Post » Tue May 17, 2011 12:28 pm

in the result script:
set Myquest.NowDoit to 1


in Myquest's script
if NowDoit == 1   DoSomethingNifty   set NowDoit to 0endif



Interesting.

Question: How does the timing of that work?

For example, if I set NowDoit to 1 in a on begin result script of topica, can I assume that DoSomethingNifty has been run by the time I get to topicb?

If I set NowDoit to 1 in a result script... if I later in the same script have a if NowDoit == 0 clause, will that be run before moving on to the next topic?
User avatar
Jessica Colville
 
Posts: 3349
Joined: Wed Oct 18, 2006 6:53 pm

Post » Tue May 17, 2011 5:04 am

Here is another place where programmers make assumptions which lead in the wrong direction. I agree the above works. But I would never have thought of this, until it was pointed out to me in other threads at newvegasnexus. This type of approach is not "scalable" for a large number of quests; the program will eventually slow down to a crawl and no individual programmer will be "responsible".


Do you know how Stopped scripts factor into performance? I tend to use Start/Stop to only run quests when I need them, which I hope is improving the performance despite eating up some RAM for variables.
User avatar
k a t e
 
Posts: 3378
Joined: Fri Jan 19, 2007 9:00 am

Post » Tue May 17, 2011 8:49 am

Here is another place where programmers make assumptions which lead in the wrong direction. I agree the above works. But I would never have thought of this, until it was pointed out to me in other threads at newvegasnexus. This type of approach is not "scalable" for a large number of quests; the program will eventually slow down to a crawl and no individual programmer will be "responsible".


...and this is actually much of the reason why I was declaring (what I thought to be temporary) variables in result scripts in place of functions.

To look at your example earlier of setting a variable to functionresult+functionresult and then basing your if statements off of that, vs. basing your if statements off of the functionresults directly... I specifically wanted to avoid that, wanting to cut down on the number of times that I'm executing the same function in the same script.
User avatar
Nancy RIP
 
Posts: 3519
Joined: Mon Jan 29, 2007 5:42 am

Post » Tue May 17, 2011 10:43 am

Question: How does the timing of that work?


That is the exact problem. As far as I can tell, each block of code in the entire game with "begin gamemode" is collected into a list, in some random unpredictable order. Then in each frame of the game (say, 30 FPS or 60 FPS) this list is looped, and each block is executed. So you can think of these as guarded parallel threads. (If you are not familiar with multithread processing this whole set of reasoning may not be helpful to you.) So, once the line in the result script executes, then sometime before the next frame is rendered, the quest script will run and execute the block inside. If you think about the quest script as a subroutine which is what you are looking for, you will hurt your head. For example, if you want to execute this block to get one answer, and then later in the same script execute the block again to get a different answer, it will not work. The semaphore is only set once and then the block is executed once. Think of it as a separate thread which is executed by the game's global list once per frame, and you may be able to work out a way to do what you want.

Now don't even get me started on how to handle operations such as moveto, which are documented to take several frames to execute. I have no idea.
User avatar
Ryan Lutz
 
Posts: 3465
Joined: Sun Sep 09, 2007 12:39 pm

Post » Tue May 17, 2011 6:05 am

To look at your example earlier of setting a variable to functionresult+functionresult and then basing your if statements off of that, vs. basing your if statements off of the functionresults directly... I specifically wanted to avoid that, wanting to cut down on the number of times that I'm executing the same function in the same script.

Yes, this is taught in Programming 201. It is a blind spot for me and probably most programmers, and I am startled to learn that this will cause all kinds of unpredictable bugs. Now I have to go look through all my code, one script at a time, and there isn't even any way to global search. Sigh.
User avatar
An Lor
 
Posts: 3439
Joined: Sun Feb 18, 2007 8:46 pm

Post » Tue May 17, 2011 3:13 pm

In most programming languages, this works, and is considered a good idea for readability:
int ibegin...   set i to x + y + somefunction + someotherfunction   if i < 10      ... do something   elseif i < 20      ... do some other thing   endifend



Yes, here the troubles start here in the opposite case: when a programming language has sub-functions and you have a variable of the same name in the main routine and forget to declare it again in the sub-function.

Result scripts are something different though, we always had restrictions, it took a while to figure out that you could use simple non-nested if-constructs in Morrowind result scripts, despite what the CS helpfile said. In Oblivion we had a well prepared Wiki waiting for us that told us basics like "you may not declare variables in result scripts". That Fallout seemingly started from scratch seems a bit strange.


BTW: Did you know why we use i, j, k, l, m, n for counters? In FORTRAN they were implicitly considered integers when undeclared. The Cobol guys adopted that practice, a decade later they taught it the Basic guys, and a generation later C and Pascal kids like me learned it. Now we have PHP, PERL, .NET and still use the ancient IN block.

In a nutshell, programmers are sometimes a bit too hesitant to change their habits, coming from Morrowind I haven't thought about using result scripts for anything but small scriplets. NWN's C-dialect and even BG's scripting language are so much more versatile than the gamesas scripting language for me to even consider importing techniques.
User avatar
Eve(G)
 
Posts: 3546
Joined: Tue Oct 23, 2007 11:45 am

Post » Tue May 17, 2011 4:45 pm

Do you know how Stopped scripts factor into performance? I tend to use Start/Stop to only run quests when I need them, which I hope is improving the performance despite eating up some RAM for variables.

Good point. Now I have to question any "assumption" I make, but I "assume" that a stopped quest does not consume any CPU time. My problem is that when I introduce a quest script to do this type of semaphore operation, there is no point in the game when I can be guaranteed it is no longer needed. So I can never actually stop it.
User avatar
jadie kell
 
Posts: 3497
Joined: Sat Jul 29, 2006 3:54 pm

Next

Return to Fallout: New Vegas