Some Dialogue Questions # 2

Post » Sat Feb 06, 2010 1:22 pm

Sigh - thread # 2 - and still no end in sight

As I find it easier to reference a single thread here I go again. For anyone new to dialogue it probably contains many answers to common questions

For my own benefit here are some highlights of http://www.gamesas.com/index.php?/topic/976365-some-dialogue-questions/page__view__findpost__p__14106679 - many thanks to all the contributors of thread #1

Scripting Persuasion

Spoiler

They are indeed hard coded but could be over ridden by scripting. Carrie Irriettie, the companinion I'm working on, is particularly strong minded and doesn't pay much mind to persuasion. Her script constantly sets her disposition to the value of a local variable. The dialog for her persuasion responses then alters this variable.

The relevant snip of script:
short	fondnessif ( getDisposition != fondness )	if ( fondness > 0 )		setDisposition fondness	endIfendIf


And a bit of sample dialog:
"It's nice to hear you say such sweet things."
ID: NICI_Carrie, Disp: 75
[Global][Random100][>=][75]
[Function][Same six][=][1]
Result:
set fondness to fondness + 3

"You're going to make me blush."
ID: NICI_Carrie, Disp: 75
[Global][Random100][>=][50]
[Function][Same six][=][1]
Result:
set fondness to fondness + 2

The game engine would modify Carrie's disposition by some random amount when the player succeeds in persuasion with her. The bit of code above runs while the dialog menu is open and promptly undoes the dialog change. The game then looks up the dialog response. For the sample results shown above the results box alters Carrie's fondness variable. This triggers the the script to update Carrie's disposition. A bit cumbersome but it give the modder control of the NPC's disposition score. These two lines of dialog are placed above the line "I feel the same way. It's been some time now for me." in the Admire Fail section. (The filter [Global][Random100][>=][75] looks at a global variable that is rerolled by the game every frame - about 17 times per second or more)



Using Restart for Quests

Spoiler

Actually, Restart is more than a novelty. It is used to make a quest active again in the player's journal after first declining a quest and then later accepting the quest. I will use it to temporarily close a quest (so it does not appear active) during a long delay that does not require any player input between stages of a quest, or when the quest can be extended after the primary quest is completed.

The journal structure might look like this:

Index  Type   Text0	   N	 Name of quest10			So-and-so needs my help.15	  F	I told So-and-so that I did not have time.20		   I agreed to help So-and-so.25	  R	I decided to help So-and-so after all.100	 F	So-and-so thanked me for my help.


Journal entry 20 and 25 do not have to be different. The normal entry for accepting the quest could be the same as that recorded if the player first declines and later accepts. But in that case you would want to make the quest Restart at that point.



Using Variables in Dialogue

Spoiler

I'll give you an example from RoHT:
In the East Empire Company (EEC) quest, the player is supposed to have a Telvanni spy kill Canctunian Ponius by a scentless and tasteless poison. If the player decides to kill Ponius directly, an official enquiry will follow, and the Telvanni spy will have to flee. In that case, House Telvanni will lose its influence in the EEC completely.
Now, a scentless and tasteless poison is hard to find. It takes a master alchemist to make one, and neither Nalcarya of White Haven nor Abelle Chriditte are inclined to get involved in House politics and make one. So the player needs to find someone else. That someone was once a member of House Telvanni before he had to leave and hide from Therana. In order to persuade him to brew that poison, he'll demand a tower of his own, complete with guards.
Now there are three possible endings to that quest:
- The master alchemist gets his tower, brews the poison, and the Telvanni spy uses it to poison Canctunian Ponius.
- The master alchemist gets his tower, brews the poison, but the player decides to kill Canctunian Ponius by other means (or Ponius dies in an accident). The spy flees Vvardenfell.
- The master alchemist doesn't get his tower. The player kills Canctunian Ponius directly, or Canctunian has been dead from the beginning of the quest.

This situation is difficult to control by Journal entries alone, so I made global variables to keep track on the master alchemist's tower and on whether the spy takes over the EEC or flees Vvardenfell.

Let's get our hands dirty with some actual code:
The variables are called RoHT_EEC_status and RoHT_TelAzura_status. I added a global script to keep track of Canctunian Ponius' health:
begin RoHT_Canctunian_Script; this script checks, whether Canctunian is killed by the furtive poison or other means.; It is started by RoHT_advisor in the dialogue topic "imprudent activity"; global RoHT_EEC_status; This variable is set by RoHT_advisor in the dialogue "Greeting 1" and in this script; 0 = Canctunian Ponius lives and is in charge of the East Empire Company; 1 = Canctunian Ponius is dead and Mehitabel Llaras has taken office; 2 = Canctunian Ponius is dead and Mehitabel Llaras had to fleeif ( MenuMode == 1 )	returnendifif ( GetJournalIndex "RoHT_EastEmpireCompany" < 100 ); Canctunian should be alive	if ( GetDeadCount, "Canctunian Ponius" > 0 ); but if he isn't, you have probably killed him before and this quest can't be solved as intended		Journal, "RoHT_EastEmpireCompany", 110; stop this script, it has served its purpose; RoHT_EEC_status will be set to 2 by RoHT_advisor in the dialogue "Greeting 1", so that Mehitabel won't vanish before your eyes		StopScript, "RoHT_Canctunian_Script"	endif	else		return	endifelseif ( GetJournalIndex "RoHT_EastEmpireCompany" == 100 ); this Journal entry is set by your advisor in the dialogue "Greeting 1"	set RoHT_EEC_status to 1	"Canctunian Ponius"->SetHealth, 0	"Canctunian Ponius"->disable; quest solved, stop the script	StopScript, "RoHT_Canctunian_Script"endifEnd


That script is started in dialogue at the appropriate time and will run until Canctunian Ponius is dead, regardless of his cause of death. RoHT_TelAzura is also set in dialogue:
; global RoHT_TelAzura_status; This variable is set to 1 by RoHT_advisor in the dialogue topic "master alchemist"; 0 = Tel Azura isn't built yet, Ammardunibi Camp is active; 1 = Tel Azura is completely built; Ranos and Bodrusa have moved there


With these two variables I'm able to keep track of this quest's outcome, regardless of Journal entries. For example:
"RoHT_TelAzura_status = 1" and "RoHT_EEC_status = 0" means that the player has recruited the master alchemist, but hasn't made any progress on taking over the EEC yet.
"RoHT_TelAzura_status = 1" and "RoHT_EEC_status = 1" means complete success.
"RoHT_TelAzura_status = 1" and "RoHT_EEC_status = 2" means partial success - master alchemist won, EEC lost
"RoHT_TelAzura_status = 0" and "RoHT_EEC_status = 2" means complete failure.
I have made extensive use of these possibilties in later quests, for example when I needed to filter dialogue independently of the EEC quest but with regard to the master alchemist's status in House Telvanni. To get an idea of how convoluted this can get, have a look at http://i271.photobucket.com/albums/jj158/bhlmods/WIP%20Rise%20of%20House%20Telvanni/RoHTQuestTree.png. Doing this by Journal entries alone would be a royal pain in the ****.
If you'd like to take a closer look at it, let me know: I can send you the current WIP version. It contains quite a few interesting dialogue techniques, like quest deflectors, quest delays, quests within quests, dialogue-and-script-choreographed sequences... lots of stuff to browse through. :read:
Expect to find some bugs in later quests, though. I'm not done testing yet. :)

B

Edit:
I forgot to mention that using global variables also enables other mods to interact with your mod without being dependend on it. All that is required is that both mods feature the same global variable. For example, if you wanted one of your NPCs to comment on House Telvanni taking over the EEC, you'd add the global short variable "RoHT_EEC_status" to your mod and filter your dialogue for "global RoHT_EEC_status == 1". If RoHT is also running, players would be able to see that dialogue; if RoHT isn't running, they won't even notice that it exists. Point is that your mod will work, regardless of whether RoHT is present or not.



Modify PC Faction

Spoiler

You can use modpcfacrep for a faction the player is not in; however, Morrowind Scripting For Dummies says the getpcfacrep function is broken. I'm not sure if pcfacrep alone changes a faction's disposition, or if it just contributes toward rank increase.

I suggest you make a global variable to store the faction's disposition, then use something like set Illu_somefac_rep to ( illu_somefac_rep + 5 ) in the dialogue results to change it.



When adding a new topic and a journal entry which is linked to the new topic at the same time

Spoiler

I am sorry. I was rushing to post before I had to go to work and I did not complete my thought.

I was describing the situation that we have discussed before. A quest topic is introduced in a greeting (or another topic) at the same time the first journal entry for that quest is added. The new (quest) topic is filtered for that journal index. Because the index does not exist at the moment the greeting's dialog is displayed, the text of the new topic is not hyperlinked nor is the topic listed. Only after the dialog window is refreshed (choosing a different topic is sufficient) will the filter condition for the new topic be satisfied so it can be linked and listed.

Example:

Greeting:
No Filter: Hello, %PCName, are willing to help a mer who is down on his luck?
Result:
Journal "cyr_HardLuck" 10
AddTopic "down on his luck"

Topic: down on his luck
Filter [Journal: cyr_HardLuck = 10]: Yes, it seems that ever since I found this old Dwemer bone I have had nothing but bad luck.

It looks like it would work, but the journal condition for the topic needs to be satisfied before the greeting displays. In this case the topic 'down on his luck' will not be hyperlinked. However if the journal is not added until the player chooses the topic and no filter for the topic (as Bethesda regularly did), or if the topic is filtered for Journal: cyr_HardLuck <= 10 the hyperlink will appear at the moment of the initial greeting.




Why my scripts started from Dialogue won't save

Spoiler

You can just save the script twice and it should compile without needing a semi-colon. It will complain at first that it can't find the other script, but saving again should make it compile.



And to start this thread off I have a question about placeatme versus placeatpc

All I can understand from the MWSFD is that The PlaceAtMe function works the same as PlaceAtPC without it being centered on the PC. But what does this actually mean? Is placeatme working on another NPC or object?
User avatar
P PoLlo
 
Posts: 3408
Joined: Wed Oct 31, 2007 10:05 am

Post » Sat Feb 06, 2010 6:10 pm

The PlaceAtPC command will place the specified object at the player's feet with the specified offset, direction, and quantity. PlaceAtMe can operate on any object (including the player, ex: Player -> PlaceAtMe "object" x1,x2,x3 or Misc_Act_01 -> PlaceAtMe "Object" x1,x2,x3) and acts quite the same. Note that there are issues with PlaceAtPC (items always appearing with zero offset regardless of the specified value) when in third person but these should be fixed by the Morrowind Code Patch.
User avatar
Danny Blight
 
Posts: 3400
Joined: Wed Jun 27, 2007 11:30 am

Post » Sat Feb 06, 2010 6:05 pm

My lightning strike mod uses both functions: first it places a ring somewhere around the player, then places another ring around the first, then another around that and so on until the actual lightning ring is placed. This way I can somewhat randomize where the lightning is going to hit and not have it always centered around the player.
User avatar
Angela
 
Posts: 3492
Joined: Mon Mar 05, 2007 8:33 am

Post » Sat Feb 06, 2010 10:33 am

In my experience even with MCP installed both PlaceAtMe and PlaceATPC are still not reliable with the Y offset. If you need always reliable relative Y offset better use PlaceItem/PlaceItemCell + calculated sin/cos
User avatar
Nathan Risch
 
Posts: 3313
Joined: Sun Aug 05, 2007 10:15 pm

Post » Sat Feb 06, 2010 5:58 pm

The PlaceAtPC command will place the specified object at the player's feet with the specified offset, direction, and quantity. PlaceAtMe can operate on any object (including the player, ex: Player -> PlaceAtMe "object" x1,x2,x3 or Misc_Act_01 -> PlaceAtMe "Object" x1,x2,x3) and acts quite the same. Note that there are issues with PlaceAtPC (items always appearing with zero offset regardless of the specified value) when in third person but these should be fixed by the Morrowind Code Patch.


Thanks NMZ - that helps me understand better how the script I'm looking at is working - the script was kindly written by request by Melian and I've been doing my testing with MCP installed but I am aware that distance seems a bit messed up when in 3rd person to the extent I was thinking of forcing 1st person only in the script - though in 3rd person http://a.imageshack.us/img134/7308/hug2k.jpg

The way Melian currently has set the script is the placeatme drops a marker in front of the NPC and then pulls the player to that marker I was just wondering about reversing that to pull the NPC to the player. This would only be for NPC's where there is no obstacle in the way eg counter or table - I think I'll just go rewrite the script and see if it makes any difference using placeatpc versus placeatme

In my experience even with MCP installed both PlaceAtMe and PlaceATPC are still not reliable with the Y offset. If you need always reliable relative Y offset better use PlaceItem/PlaceItemCell + calculated sin/cos


Abot - I used to have the scripting capability of a 5 year old - I think I'm up to a 10 year old now - but even in college I struggled with sine and cosine :) Though if you know of a script that has those functions to place an item I'd be interested to read it to try and work out what it's doing.
User avatar
Miss Hayley
 
Posts: 3414
Joined: Tue Jun 27, 2006 2:31 am

Post » Sat Feb 06, 2010 9:03 pm

Though if you know of a script that has those functions to place an item I'd be interested to read it to try and work out what it's doing.
Well, this is the script
Spoiler

begin ab01ExNordWin01ScriptDontSaveObjectfloat x1float y1float z1float a1short i1short i2short i3float x2float x3float zsinfloat zcosif ( MenuMode )	returnendifif ( i3 > 0 )	set x1 to GetPos X	set y1 to GetPos Y	set z1 to GetPos Z	set a1 to GetAngle Z  ; this is an activator, usually Z angle is 0 <= a1 <= 360	disable	if ( i3 == 1 )		PlaceItem ab01Ex_nord_win_01ex x1 y1 z1 a1	elseif ( i3 == 2 )		PlaceItem ab01Ex_nord_win_01in x1 y1 z1 a1	else		PlaceItem ab01Ex_nord_win_01in2 x1 y1 z1 a1	endif	if ( ab01wgLightsOff )		return	endif	if ( a1 > 180 )		set a1 to ( a1 - 360 )   ; transform angle -180 <= a1 <= 180	endif; beginning of sin/cos calculation	if ( a1 >= 0 )		set x3 to a1		set i2 to 1  ; i2 = clockwise	else		set x3 to ( 0 - a1 )		set i2 to 0	endif	if ( x3 <= 45 )		set i1 to 1  ; i1 = quadrant	elseif ( x3 <= 90 )		set x3 to ( 90 - x3 )		set i1 to 2	elseif ( x3 <= 135 )		set x3 to ( x3 - 90 )		set i1 to 3	elseif ( x3 <= 180 )		set x3 to ( 180 - x3 )		set i1 to 4	endif	; Matt Singleton/Galsiah series	set x3 to ( x3 * 0.0174533 )  ; degrees to radiants	set x2 to ( x3 * x3 )	set zcos to ( ( ( 0.0074857 * x2 ) - 0.1655574 ) * x2 )	set zcos to ( ( ( 0.9995425 + zcos ) * x3 ) + 0.0000605 )	set x3 to ( 1.5707963 - x3 )  ;   cos( pi/2 - x3 ) = sin (x3)	set x2 to ( x3 * x3 )	set zsin to ( ( ( 0.0074857 * x2 ) - 0.1655574 ) * x2 )	set zsin to ( ( ( 0.9995425 + zsin ) * x3 ) + 0.0000605 )	if ( i1 > 1 )		if ( i1 < 4 )			set x2 to zcos			set zcos to zsin			set zsin to x2		endif	endif	if ( i2 == 1 )		if ( i1 > 2 )			set zsin to ( 0 - zsin )		endif	else		if ( i1 <= 2 )			set zcos to ( 0 - zcos )		else			set zcos to ( 0 - zcos )			set zsin to ( 0 - zsin )		endif	endif	; fix limits	if ( zsin < -1 )		set zsin to -1	elseif ( zsin > 1 )		set zsin to 1	endif	if ( zcos < -1 )		set zcos to -1	elseif ( zcos > 1 )		set zcos to 1	endif; end of sin/cos calculation, time to use them	; rotation - traslation	; move it 30 points in Y	set x1 to ( x1 - ( 30 * zcos ) )	set y1 to ( y1 - ( 30 * zsin ) )	; dx / not needed here, it would move it 20 points in X	;set x1 to ( x1 - ( 20 * zsin ) )	;set y1 to ( y1 + ( 20 * zcos ) )			if ( ab01debug == 26 )		if ( i3 == 1 ); placeitem is reliable			PlaceItem ab01WindowLightExD x1 y1 z1 a1		elseif ( i3 == 2 )			PlaceItem ab01WindowLightInD x1 y1 z1 a1		else			PlaceItem ab01WindowLightIn2D x1 y1 z1 a1		endif	else		if ( i3 == 1 )			PlaceItem ab01WindowLightEx x1 y1 z1 a1		elseif ( i3 == 2 )			PlaceItem ab01WindowLightIn x1 y1 z1 a1		else			PlaceItem ab01WindowLightIn2 x1 y1 z1 a1		endif	endif	set i3 to 0	returnendifif ( GetInterior )	if ( GetWindSpeed >= 0.01 )		set i1 to 0   ; interior as exterior	else		set i1 to 1	endifelse	set i1 to 0endifif ( NightTime )	if ( i1 )     	if ( GetDisabled )			enable		endif		return	elseif ( GetDisabled == 0 )		set x1 to Random 1001		if ( x1 < 985 )			return		endif		set i3 to 1	endif	returnendifif ( i1 )	if ( GetDisabled == 0 )		if ( GetCurrentWeather < 2 )			set i3 to 2		else			set i3 to 3		endif	endifelseif ( GetDisabled )	enableendifend


I'm currently using to place a light in front of a window, I'm using similar scripts to reliably place things in front (lightnings...) or behind (fish, birds) the player.
I tried to put some notes in the relevant parts, basically you approximate sine/cosine to calculate new position,
set x1 to ( x1 - ( 30 * zcos ) )set y1 to ( y1 - ( 30 * zsin ) )

changing +/- you can change back/front relative position.
User avatar
Zoe Ratcliffe
 
Posts: 3370
Joined: Mon Feb 19, 2007 12:45 am

Post » Sat Feb 06, 2010 8:53 am

In my experience even with MCP installed both PlaceAtMe and PlaceATPC are still not reliable with the Y offset. If you need always reliable relative Y offset better use PlaceItem/PlaceItemCell + calculated sin/cos


I don't disagree with this statement in that PlaceAtMe and PlaceAtPC can still be tricky at times, but in the work I've done even the best series approximation of sine and cosine can't help you with the main issue PlaceItem (which is otherwise wonderful) has: the z-axis. PlaceAtMe and PlaceAtPC usually do a great job of placing an item at ground level, while if you are scripting a dynamic situation where you won't know the ground level of the target area, PlaceItem can fail you.

Undeniably, if the script is of fixed function in a known environment, PlaceItem is better. If the z-axis won't matter or a ground level approximation using the Player's z-location is acceptable, PlaceItem is still better. But if you won't know the needed z-height to be at ground level, PlaceAtMe and PlaceAtPC are great help.
User avatar
Daniel Holgate
 
Posts: 3538
Joined: Tue May 29, 2007 1:02 am

Post » Sat Feb 06, 2010 12:10 pm

@ Abot - thanks for posting the script - I need to stack more fortify intelligence potions to grasp it unfortunately.

@ NMZmaster - interesting info on the z-axis in the end I went back to using the placeatme as Melian had also used setpos using local float variables - I had been trying to get around using the expansions and keeping the mod dependent only on the MW.esm - which was why I was trying placeatpc - had some great fun testing though - I forgot to add a script to the marker (called in the main script) which sets the x,y,z coordinates and kept ending up in the the ashlands - quite disconcerting when you begin in Seyda Neen.

As a seperate question I don't think I've ever seen a script which get's and set's the game settings in a script - is it possible? For example there is a game setting fVanityDelay which sets teh camera to spin around the player after 30 seconds of keyboard or mouse inactivity - is there anyway I can call that game setting and adjust it temporarily? Did Galsiah's leveling mod access the game settings?
User avatar
Mason Nevitt
 
Posts: 3346
Joined: Fri May 11, 2007 8:49 pm

Post » Sat Feb 06, 2010 7:58 pm

I'm fairly certain that the game settings can't be accessed at all by scripts -- though it would be nice at times.
User avatar
katsomaya Sanchez
 
Posts: 3368
Joined: Tue Jun 13, 2006 5:03 am

Post » Sat Feb 06, 2010 1:01 pm

I don't disagree with this statement in that PlaceAtMe and PlaceAtPC can still be tricky at times, but in the work I've done even the best series approximation of sine and cosine can't help you with the main issue PlaceItem (which is otherwise wonderful) has: the z-axis. PlaceAtMe and PlaceAtPC usually do a great job of placing an item at ground level, while if you are scripting a dynamic situation where you won't know the ground level of the target area, PlaceItem can fail you.

Undeniably, if the script is of fixed function in a known environment, PlaceItem is better. If the z-axis won't matter or a ground level approximation using the Player's z-location is acceptable, PlaceItem is still better. But if you won't know the needed z-height to be at ground level, PlaceAtMe and PlaceAtPC are great help.
True. If you want to place something at terrain level and at a definite Y offset (placing seaweed on shore slopes, making thunderbolts fall on roofs, finding a large enough plane area to place a tent...) PlaceAt may fail the Y offset, and placeitem needs the Z terrain/highest obstacle level to be already known.

While complicated, a way to find terrain/highest obstacle Z is dropping a "sonar" invisible race NPC and waiting a few frames for it to stop falling from high above sea level and/or popping up to sea bed level from below (if you want to find sea floor level), it usually works well enough.
User avatar
P PoLlo
 
Posts: 3408
Joined: Wed Oct 31, 2007 10:05 am

Post » Sat Feb 06, 2010 1:44 pm

While complicated, a way to find terrain/highest obstacle Z is dropping a "sonar" invisible race NPC and waiting a few frames for it to stop falling from high above sea level and/or popping up to sea bed level from below (if you want to find sea floor level), it usually works well enough.


Now there's a method I never thought of. It might not work for extremely time sensitive calculations, but if you have a few seconds to spare in the script that's a creative way to get around the lack of terrain information.
User avatar
Josh Dagreat
 
Posts: 3438
Joined: Fri Oct 19, 2007 3:07 am

Post » Sat Feb 06, 2010 7:30 pm

Ok, this is a (slightly commented) code of a sonar NPC sample, using a invisible race with no mesh
Spoiler
begin ab01tlSonarScriptDontSaveObjectshort framefloat z1float z2float t1float x1float y1SkipAnimif ( GetDisabled )	if ( t1 < 3 )		set t1 to ( t1 + GetSecondsPassed )		return	endif	setdelete 1	returnendifif ( frame == 0 )	SetScale 0.1  ; reduce NPC size	set t1 to Random 1001	set t1 to ( t1 * 0.0005 )  ; randomize setdelete delay a little, useful if going to place many at a time	SetParalysis 1  ;  coupled with skipanim ensures NPC stay put	SetWaterBreathing 1  ; avoid drowning sounds	SetAcrobatics 255 ; avoid falling damage	set frame to 1	returnelseif ( frame > 5 )  ; wait a few frames	set z1 to GetPos Z	if ( z2 >= z1 )		set z2 to ( z2 - z1 )	else		set z2 to ( z1 - z2 )	endif	if ( z2 < 10 )   ; probably still, assuming destination reached		disable		set x1 to GetPos X		set y1 to GetPos Y		if ( z1 < GetWaterLevel )			set z1 to GetWaterLevel  ; in this case, I want to place a lightning bolt, so out of water		endif		set z2 to Random 10001; once in a while I don't want the bolt to strike earth/water surface/roof/tree but to remain middle hair 		if ( z2 < 2500 ) 			set z2 to ( z2 * 0.5 ) 			set z1 to ( z1 + z2 )		endif		player->PlaceItem ab01tlLightning x1 y1 z1 0  ; places real object using player as parent to avoid any possible parent setdelete problem from start		return	endifendifset frame to ( frame + 1 )set z2 to GetPos Zif ( frame > 12 )	if ( ab01debug == 27 )		MessageBox "ab01tlSonar frame=%g, disabling" frame	endif	disableendifend

User avatar
Francesca
 
Posts: 3485
Joined: Thu Jun 22, 2006 5:26 pm

Post » Sat Feb 06, 2010 7:21 pm

Globals - I use Globals for keeping count of certain things but generally avoid Global scripts - however I was thinking of having one similar to the Sleepers script in the main quest which activates dreams and being attacked in your sleep - in the comments of that script it mentions it used to run slow before Doug tidied it up

What makes a global script run slow? Is there an optimal way or writing them?
User avatar
Anna Watts
 
Posts: 3476
Joined: Sat Jun 17, 2006 8:31 pm

Post » Sat Feb 06, 2010 10:43 am

What makes a global script run slow? Is there an optimal way or writing them?
Like any other script, after doing whatever your script must do in that frame, you should return as soon as possible.
A global script with proper return conditions on top, making it return as soon as possible and stop if/when no more needed, is hardly noticeable.
Local scripts run only when player is near, while a running global script is always running, so a poorly written global script is much more noticeable than a poorly written local script. Also, IIRC global scripts queue is restarted each time any global script is started from a startscript command, so this can add to the perceived weight.
Having said that, what are, in practice, some standard ways to write efficient scripts? Here's a couple examples
Probably the most used:
begin myScriptif ( MenuMode )	returnendif; ... do stuff here only when menus are closed
this obviously works as long as your script does not need to do things when in menumode

Another common way to write an efficient script is realizing that usually you don't need to execute its core each and every frame (first exception that comes to mind for instance are scripts needed to update position of things against gravity). This can be done adding a timer, for instance
begin myScriptif ( MenuMode )	returnendiffloat timerif ( timer < 5 )	set timer to ( timer + GetSecondsPassed )	returnendifset timer to 0; ... do stuff here only every 5 seconds

If your script is going to be executed/attached to many objects at the same time (think about a script moving city lanterns, or guards...) it may be more efficient to avoid running the "heavy" core instructions in the same frame for all the objects.
This can be done with a little timing randomization, for instance
begin myScriptif ( MenuMode )	returnendiffloat timerif ( timer < 5 )	set timer to ( timer + GetSecondsPassed )	returnendifset timer to Random 10001 set timer to ( timer * 0.0001 )   ; 0 <= timer <= 1, so next core run will be after a random interval between 4 and 5 seconds instead of always exactly 5 seconds

When you have nested decisions/loops (for example, multiple nested ifs) it is better to put faster/more common tests on top, for instance
short doOnceif ( player-GetItemCount "gold_001" >= 1000 )	if ( GetDistance "player" > 100 )		if ( MenuMode )			if ( doOnce )				player->RemoveItem "gold_001" 1000				set doOnce to 1			endif		endif	endifendif
is the same as
short doOnceif ( doOnce )   ; a simple short variable true/false test, probably as fast as it can be	if ( MenuMode )   ; a standard simple function test, fast		if ( GetDistance "player" > 100 )   ; a relatively slow computation			if ( player-GetItemCount "gold_001" >= 1000 )   ; a slow scanning of player inventory content				player->RemoveItem "gold_001" 1000				set doOnce to 1			endif		endif	endifendif
, but the second version is probably faster.
[EDIT]my usual typos
User avatar
FABIAN RUIZ
 
Posts: 3495
Joined: Mon Oct 15, 2007 11:13 am

Post » Sat Feb 06, 2010 3:59 pm

Thank you Abot that was an excellent reply

I have a question about local variables versus globals

I know a global variable defaults to 0 does this work with a local as well

For instance I want to use a variable for dialogue eg short romantic_notions - I know with a Global I can set the variable to whatever number I want in the results box - does this work with local variables as well?

So the script would be something like

begin CT_myscript

short romantic_notions

end CT_myscript

And then in dialogue I could go set romantic_notions to 1, 2, 3 or whatever for my filtering purposes

Or do I need to do something else in the script?
User avatar
Lisha Boo
 
Posts: 3378
Joined: Fri Aug 18, 2006 2:56 pm

Post » Sat Feb 06, 2010 3:53 pm

if you want the variables to save over multiple sessions of play, you'll need to have some sort of keepvars script that starts the global script and then stops it at game load, as recorded in MSFD.

locals indeed default to zero until set as something else by script or dialog.

edit, now i have a question.

if i have a global script running (ie: one not tied to an object) can i use its variables as dialog conditions?
User avatar
Charlotte Lloyd-Jones
 
Posts: 3345
Joined: Fri Jun 30, 2006 4:53 pm

Post » Sat Feb 06, 2010 4:09 pm

if i have a global script running (ie: one not tied to an object) can i use its variables as dialog conditions?
You can technically set *any* local variable as a condition in dialogue. Problem is, it won't detect. Only locals that are actually in talking NPC's script are checked. So if you include a local from other script, the line will never be selected.

Then again, the non-discriminating possibility to use any local in conditions allows for interesting solutions. For example, in my mod I have a dummy script that is not attached to anything nor is started from anywhere. Its only function is to contain local variables with same *names* that certain NPCs from other mods have: LGNPC, CoM, etc. Then I can create lines filtered by those vars even though actual NPCs they are intended for are not present in the mod. This way, for example, to a player that has Children installed, I can make a children-specific topic without making my mod depending on that one nor importing any actual element from it.
User avatar
Stacyia
 
Posts: 3361
Joined: Mon Jul 24, 2006 12:48 am

Post » Sat Feb 06, 2010 2:09 pm

You can technically set *any* local variable as a condition in dialogue. Problem is, it won't detect. Only locals that are actually in talking NPC's script are checked. So if you include a local from other script, the line will never be selected.


This is not entirely true. If you uses startScript to target a global script to an NPC then any local variables within that script will be usable as dialog conditions. A prime example of this is the Romance mod where a targeted script is used to store the variables governing the relationship and parental status of the NPCs.
User avatar
Ally Chimienti
 
Posts: 3409
Joined: Fri Jan 19, 2007 6:53 am

Post » Sat Feb 06, 2010 3:38 pm

You can technically set *any* local variable as a condition in dialogue. Problem is, it won't detect. Only locals that are actually in talking NPC's script are checked. So if you include a local from other script, the line will never be selected.

Then again, the non-discriminating possibility to use any local in conditions allows for interesting solutions. For example, in my mod I have a dummy script that is not attached to anything nor is started from anywhere. Its only function is to contain local variables with same *names* that certain NPCs from other mods have: LGNPC, CoM, etc. Then I can create lines filtered by those vars even though actual NPCs they are intended for are not present in the mod. This way, for example, to a player that has Children installed, I can make a children-specific topic without making my mod depending on that one nor importing any actual element from it.

arg.

this, combined with targeted scripts not allowing their variables as dialog conditions is kind of forcing me to either attach a variable keeper script onto vanilla NPCs (something i'd really like to avoid) or make more global variables (another thing i am not too hot on). i'll brainstorm and test some ideas later. thanks for the response.


This is not entirely true. If you uses startScript to target a global script to an NPC then any local variables within that script will be usable as dialog conditions. A prime example of this is the Romance mod where a targeted script is used to store the variables governing the relationship and parental status of the NPCs.


from MSFD -
Variables defined in a targeted script are not considered local to the object from the point
of view of dialogue and other scripts. For example, they cannot be used as dialogue
conditions. The special variable "companion" also cannot be used, i.e. declaring a short
variable "companion" in a targeted script and setting it to 1 will not enable companion
share on the target actor. I assume this applies to other special locals as well, but I haven't
tested any others.


you sure they arnt using targeted scripts to transfer values of global variables?
User avatar
Eibe Novy
 
Posts: 3510
Joined: Fri Apr 27, 2007 1:32 am

Post » Sat Feb 06, 2010 6:00 pm

This is not entirely true. If you uses startScript to target a global script to an NPC then any local variables within that script will be usable as dialog conditions. A prime example of this is the Romance mod where a targeted script is used to store the variables governing the relationship and parental status of the NPCs.
I don't use Romance mod, but a quick look through it in CS shows that all possible attempts at using local vars I could find are marked "script non utilisé" (at least for 3.7EV; I'm not aware of newer versions in existence). If you have in mind a certain dialogue topic where a local variable from a certain *targeted* script is used, feel free to elaborate. I, for my part, will try to experiment with that data as soon as I'm home. So far, it looks highly doubtful.
User avatar
phillip crookes
 
Posts: 3420
Joined: Wed Jun 27, 2007 1:39 pm

Post » Sat Feb 06, 2010 10:18 am

Okay - I have got around the variables not saved problem by adding an item to the NPC in dialogue each time I want to change the variable - that way the script checks to see if they have an item count and sets the variable accordingly - thanks for the replies
User avatar
Setal Vara
 
Posts: 3390
Joined: Thu Nov 16, 2006 1:24 pm

Post » Sat Feb 06, 2010 11:18 pm

Okay - I have got around the variables not saved problem by adding an item to the NPC in dialogue each time I want to change the variable - that way the script checks to see if they have an item count and sets the variable accordingly - thanks for the replies

ah, good idea, i'll give that a shot.
User avatar
Chris Jones
 
Posts: 3435
Joined: Wed May 09, 2007 3:11 am

Post » Sat Feb 06, 2010 12:41 pm

i've got an interesting problem.

i've created a new topic. in this topic, so far, are two responses. one dosent really do anything but check for an item. the other checks for an item, sets a global variable to itself plus a local variable in a global script. it then starts a script, targeted on the player, and finally goodbyes to exit dialog.

every time i error check results, the CS crashes.... any ideas on why?
User avatar
Ellie English
 
Posts: 3457
Joined: Tue Jul 11, 2006 4:47 pm

Post » Sat Feb 06, 2010 9:11 am

Try to create a dummy script, copy there the contents of your response's action box, and compile it. So far, "sets a global variable to itself plus a local variable in a global script" seems to be a most likely culprit. Try to do it some other way.
User avatar
sw1ss
 
Posts: 3461
Joined: Wed Nov 28, 2007 8:02 pm

Post » Sat Feb 06, 2010 6:33 pm

Try to create a dummy script, copy there the contents of your response's action box, and compile it. So far, "sets a global variable to itself plus a local variable in a global script" seems to be a most likely culprit. Try to do it some other way.

that's what i was afraid of.

i guess i'm going to have to go from one global script to 8 redundant ones. or perhaps add an if block with 8 " if ( PCCell == "****" ) " tests in it.

i'll report back in a few minutes with how it goes.
User avatar
Dorian Cozens
 
Posts: 3398
Joined: Sat May 26, 2007 9:47 am

Next

Return to III - Morrowind