|
|
 |
View previous topic :: View next topic |
 |
|
|
|
|
Author |
Message |
|
|
|
|
|
Gazz Moderator (Script&Mod)


Joined: 13 Jan 2006 Posts: 12153 on topic Location: Bavaria

 |
Posted: Sat, 14. Aug 10, 19:33 Post subject: [Tutorial] The MD - First Contact |
|
|
For a first time user this can be quite confusing.
Some very basic information on how the MD "ticks" is simply not there.
There are a few tutorials on how to do particular things.
This here is rather on why it is necessary to do them. Sort of an introduction to the "real" tutorials.
Script Editor (SE) experience is useful only insofar, that it helps understanding what the objects do, once the MD tells them to do something.
This is by no means a complete list but only the issues I... encountered so far.
- Where are the files?
Use Doubleshadow's Mod Manager to unpack director\*.* , starting with 01.CAT (provided you want the graphics) or 03.CAT.
- Get an XML editor
You need one. (Yes, you do!)
Visual Web Developer 2008 is free and it works.
- director.htm
Very important reference file.
Requires ActiveX so don't try opening it with Firefox.
- MD file naming convention
director\*.xml
That's it.
If you mess up the XML structure, the whole file is ignored.
- When are MD files read / activated / patched?
To "activate" your script once the game is *modified*:
Start new game ...or...
Load game
Once "in" the game, all cues stay loaded and are buffered in the savegame.
Deleting the *.xml file has no effect.
When loading a game, the buffered code of all cues in the savegame (including those "waiting to fire"!)
is overwritten by yourscript.xml, provided that the cue names match.
Therefore there is no need to "patch" the MD code itself and no need for a version check.
All that could require fixing is the state of the cues and which are currently "hot".
This isn't more or less work than with the SE... just different.
- When do Cues unload? How to get rid of them?
The only way to completely remove cues from your savegame is
| Code: |
| <destroy_cue cue="xgz_mdl_setup"/> |
for all cue names you used.
That's the uninstall script or when you royally screwed up.
No idea if that automatically destroys all subcues with it. I would assume so, but...
Variables
All variables are assigned on the fly without requiring declaration.
They are not and cannot be limited to a data type.
Variable Scope
All variables are global and immediately accessible in all cues of all MD scripts.
Expect typical name concflict issues.
Only when a variable is used as "mycue.variable" (or in it's home cue, "this.variable"), it is created "semi-local".
For all practical purposes you just used a longer variable name in doing so, so the name is unique again.
Every local variable can be accessed in all cues of all MD scripts if you reference it as "mycue.variable" so it's not really "local".
Not tested:
Local variable might be affected by the destroy_cue action while global ones are not tied to a specific cue.
The Local / Global variable ambiguity
While using the same term, MD and SE use completely incompatible systems.
Objects
Just like in the SE:
unless you find/create an object, you have no object.
You have {player.ship} as a constant.
Supposedly object="" also defaults to {player.ship} but being verbose is far easier to read and debug.
Timing
Unless otherwise directed, a cue's actions execute instantly when the conditions are met.
If there is a delay then it's too small for me to measure.
So obviously, the conditon is checked every frame or nearly so.
But there ain't no such thing as a free lunch.
Have 200 unique cues simultaneously waiting for a condition like the distance between 2 objects... and watch your FPS drop.
The MD cannot magically check many things instantly without using CPU time to do that.
So just like in the SE - use sensible delays to limit how often things are checked.
Some conditons (ship destroyed) are "real" events, that are apparently driven by real hardcoded events/signals like in the SE.
Those are rather harmless in that regard.
When do Cues fire and what do they fire?
A cue will always wait patiently until all specified conditions are met.
Then it executes the <action> and all included subcues.
| Code: |
<cue name="cue_test">
<condition> <object_exists object="gzstation"/> </condition>
<action> <incoming_message popup="1" text="Test for condition: station EXIST"/> </action>
<cues>
<cue name="subcue_test">
<action> <incoming_message popup="1" text="Unconditional subcue of station EXIST"/> </action>
</cue>
</cues>
</cue> |
Both messages fire at the same time.
When do Cues refire?
They don't.
Once a (non instanced) cue has run, it's done forever.
You want to keep doing something, you include a failsafe to reset and enable the cue to run again - based on it's conditions.
| Code: |
<cue name="xgz_mdl_setup">
<condition> <object_exists negate="1" object="gzstation"/> </condition>
<action>
<do_all>
<reset_cue cue="xgz_mdl_setup_reset"/>
<find_sector name="this.mdl_sector" x="0" y="0" nearest="1"/>
<create_station name="gzstation" safety="0" race="neutral" typename="SS_DOCK_A_TRADE">
<position x="00km" y="00km" z="00km"/>
<sector sector="this.mdl_sector"/>
<equipment loadout="none"/>
</create_station>
<incoming_message popup="1" text="Object not found. New {object.name@gzstation} created."/>
</do_all>
</action>
<cues>
<cue name="xgz_mdl_setup_reset">
<condition>
<check_all>
<object_exists negate="1" object="gzstation" />
</check_all>
</condition>
<action>
<do_all>
<incoming_message popup="1" text="Setup complete, object 'gzstation' not found. Reseting setup script."/>
<reset_cue cue="xgz_mdl_setup"/>
</do_all>
</action>
</cue>
</cues>
</cue> |
When the "setup" runs, the subcue starts waiting for it's sole condition - which is that the required station is no longer there.
If that ever happens, it kicks the main cue back into action.
Note: The reset automatically applies to all (?) subcues, such as the failsafe cue itself.
(yes, there are other ways to have reoccurring missions and the likes but that's definitely not "basics")
Operators
There are (+-*/).
Nothing binary, no SQR, no nothing. Suck it up.
Check_Value can supposedly (not tested) compare a string to exact="xyz".
That's the complete list of string operations.
Game Data
Very little is accessible.
Any remotely intelligent weapon/loadout selection is impossible because the MD cannot read laser damage,
required ammo, missile damage / flags, or even the range of any weapon at all.
Whenever the MD selects an enemy ship and a weapon loadout it's deciding based on assumptions, not data.
You can hardcode such data points in your MD script but then your MD script will only work properly in the mod it was written for.
Since the MD cannot access SE global variables such as 'XTMOD.ACTIVE', it will have a hard time figuring out if a different mod is active.
Creative workarounds will be required.
_________________ My complete script download page. . . . . . Xai-Corp MSCI List is scripter's friend. I AM THE LAW!
Dogs and colour blindness explained: People with green eyes can't see dogs.
Last edited by Gazz on Mon, 16. Aug 10, 12:56; edited 7 times in total |
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
Gazz Moderator (Script&Mod)


Joined: 13 Jan 2006 Posts: 12153 on topic Location: Bavaria

|
Posted: Sat, 14. Aug 10, 19:33 Post subject: |
|
|
** reserved **
|
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
eldyranx3

Joined: 14 Jan 2006 Posts: 1909 on topic

|
Posted: Sat, 14. Aug 10, 20:22 Post subject: |
|
|
Exactly what I needed! Pouring through the 2.0 Plot XML had me scratching my head for a while. Thank You Sir, you are a GoD among Men.
_________________
 |
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
ScRaT_GER

Joined: 08 Jan 2008 Posts: 1958 on topic

|
Posted: Sat, 14. Aug 10, 21:26 Post subject: |
|
|
Nice overview Gazz!
| Quote: |
| I have no idea how the game's FPS would be affected by 200 unique cues simultaneously waiting for something like the distance between 2 objects becoming smaller than x m. |
For this purpose you can set the "delay" attribute for each cue, which specifies the time interval for checking the cues conditions.
So if you write
| Code: |
| <cue name="X" delay="1s">...</cue> |
the cues conditions will be checked in 1s intervals.
However this does not work with event conditions like "object_destroyed", because these only fire momentarily, so only by accident the cues conditions would be checked at the same time the event takes place.
Greetings,
ScRaT
_________________
Skripts:
Teladi Informations Service, Fahrtenbuch, Handelsübersicht |
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
Gazz Moderator (Script&Mod)


Joined: 13 Jan 2006 Posts: 12153 on topic Location: Bavaria

|
Posted: Sat, 14. Aug 10, 22:14 Post subject: |
|
|
Yah, so the tooltip says but I intentionally glossed over all details like that.
Performance tuning is a long way off from the first script. =P
I'm more interested in generic info on how the system works here.
How does the leg bone connect to the hip bone?
For instance, how do I "do stuff" with every single member (ship) of a group?
The very basic tools already come in a group flavour but what if I need something else?
In the SE I'd loop through the ship array and get all objects single file.
Cake.
How does that work in the MD?
_________________ My complete script download page. . . . . . Xai-Corp MSCI List is scripter's friend. I AM THE LAW!
Dogs and colour blindness explained: People with green eyes can't see dogs. |
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
ScRaT_GER

Joined: 08 Jan 2008 Posts: 1958 on topic

|
Posted: Sat, 14. Aug 10, 22:24 Post subject: |
|
|
| Quote: |
| In the SE I'd loop through the ship array and get all objects single file. How does that work in the MD? |
Exactly the same way - only less intuitive.
Given "this.stations" is a group of stations, you can write something like this:
| Code: |
<action>
<do_all exact="{group.object.count@this.stations}" counter="mycount">
<set_value name="this.tmpStation" exact="{group.object.{counter@mycount}@this.stations}"/>
</do_all>
</action> |
That should work, but I didn't test it.
Btw: The count begins at 1. So the first object of a group can be refenced by {group.object.1@mygroup} instead of {group.object.0@mygroup}.
Greetings,
ScRaT
_________________
Skripts:
Teladi Informations Service, Fahrtenbuch, Handelsübersicht |
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
Aro

Joined: 15 Jul 2003 Posts: 1977 on topic Location: Whitish Northern Area

|
Posted: Sun, 15. Aug 10, 04:07 Post subject: |
|
|
| Quote: |
| I have no idea how the game's FPS would be affected by 200 unique cues simultaneously waiting for something like the distance between 2 objects becoming smaller than x m. |
FPS will plummet like a rock. A simple create station and a ship script running unchecked will start to slow a computer down after a few seconds. Was interesting to watch though.
Variable scope can also be a little weird at times.
Large cues holding many sub-cues can be an issue as well, some of the cues may not fire. Seems that ES uses a 'cue.Step' to control missions. And breaking them up with a main controller to run them.
|
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
Shush
Joined: 06 Dec 2003 Posts: 17 on topic Location: Melbourne, Australia

|
Posted: Sun, 15. Aug 10, 06:13 Post subject: |
|
|
Great MD topic, I'll add my own experiences...
You could also do the following with ScRaT_GER's example:
| Code: |
<cue name="Blah.setup">
<action>
this.stations = whatever
</action>
<cues>
<cue name="Blah.instance.handler" instantiate="static">
<condition>
<check_value value="{group.object.count@parent.stations}" min="1"/>
</condition>
<action>
<do_all>
<set_object name="this.tmpStation" value="{group.object.1@parent.stations}"/>
<remove_object_from_group object="{group.object.1@parent.stations}" group="parent.stations"/>
<do something with "this.tmpStation"/>
</do_all>
</action>
</cue>
</cues>
</cue>
|
What this does is fork of a complete copy, (instance), of every cue and subcue under the instantiate="static" command. Each instance exists seperately until it and all of its sub cues finish or are cancelled, the instance is then destroyed. The way I interpret the instantiate="static" command, is that the original cue is static and that the copy generated by the condition is the instance.
The main cue Blah.setup is run once, the sub cue Blah.instance.handler is copied and run, (instanced), everytime the group.object.count is bigger than or equal to 1. In other words the "Blah.instance.handler" check_value condition constantly loops at some pre-determined internal mission director frequency, (probably within the main game loop and thus probably limited to actual frame rendering frequency). This is where the delay="" command is extremely useful for performance, it would limit the polling and hence potential instance generation to "n" per second, where delay="ns".
Ok, so what stops the instancing from running out of control? Well if you're not careful, nothing, that's why the remove_object_from_group command in this example saves the day. It reduces the size of the station queue/list/array by one for each instance that is generated.
You will also notice that I referenced this.tmpStation as parent.tmpStation in the sub cue, I could have called the group variable Blah.stations which would be a global variable name not only accessible in all cues of this MD file but all cues of all MD files, this has obvious advantages for accessing global data between MD files, but drawbacks for localised data. Two very important reasons to use this., parent. and parent.parent., (as you traverse down the sub queue tree, you prepend one parent. for each cue) etc, are;
1) MD does a search for variable names throughout your entire cue/sub cue tree structure trying to find the actual variable, I'm guessing with complicated cue trees this could be fairly performance intensive, using this., parent., etc allows MD to know exactly which cue your variable is located within, without having to search for it.
2) Using instances will often require you to reference the instance's copy of a variable, you must use this. and parent. etc in this particular example, any other way of referencing your variable names will cause all instances to reference a global copy of that variable.
So what was the point of all this? It's obviously more complicated than ScRaT_GER's example but it lends itself to some extremely powerful multiple thread/fork/task techniques that are very difficult or impossible to perform using loops or sequential code. For example in my upcoming set of LIFE scripts and MD missions I use this technique frequently to allow me to add dynamic missions to the universe based on the universe's current state rather than pre-determined click on this, stuff spawns, do something, type missions. With instances I can be reactive to pre-existing ships/stations being attacked, create an actor, offer a conversation/mission and handle universe events without having to fake anything.
P.S. Anyone who wants to experiment with instancing may find it hairy to wrap your head around the fact that there can be multiple copies of your cues all firing simultaneously, here's a few lines of helper code that can make it much easier to track the instances themselves.
P.P.S. This code is for instructional purposes, but it should run with trivial modifications.
| Code: |
<!-- Use this within your instance, prints instance ID and total instance count -->
<incoming_message author="Blah.instance.handler {instance@Blah.instance.handler}" text="Total Instance Count: {instances.count@{static@Blah.instance.handler}}"/>
<!-- Global instance count, put this in a setup cue -->
<set_value name="Blah.instancesCount" exact="0"/>
<!-- Use this before the instanced cues -->
<cue name="Blah.instance.watcher" delay="1s">
<condition>
<check_value negate="1" value="{instances.count@{Blah.instance.handler}}" exact="{value@Blah.instancesCount}"/>
</condition>
<action>
<do_all>
<!-- If instances count = 0 then do something -->
<do_if value="{instances.count@{LIFE.GNS.StationHandler}}" exact="0">
<incoming_message author="Blah.instance.watcher" text="Instance Count: 0"/>
</do_if>
<!-- If instances count has decreased, then do something -->
<do_if value="{instances.count@{Blah.instance.handler}}" max="{value@Blah.instancesCount}-1">
<incoming_message author="Blah.instance.watcher" text="Instance Count: decreased"/>
</do_if>
<!-- If instances count has increased, then do something -->
<do_if value="{instances.count@{Blah.instance.handler}}" min="{value@Blah.instancesCount}+1">
<incoming_message author="Blah.instance.watcher" text="Instance Count: increased"/>
</do_if>
<!-- Save instances count -->
<set_value name="Blah.instancesCount" exact="{instances.count@{Blah.instance.handler}}"/>
</do_all>
</action>
</cue>
|
|
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
Gazz Moderator (Script&Mod)


Joined: 13 Jan 2006 Posts: 12153 on topic Location: Bavaria

|
Posted: Sun, 15. Aug 10, 09:14 Post subject: |
|
|
| Shush wrote: |
Ok, so what stops the instancing from running out of control? Well if you're not careful, nothing, that's why the remove_object_from_group command in this example saves the day. It reduces the size of the station queue/list/array by one for each instance that is generated.
|
Wouldn't this run your instanced instructions once for every group member and then never again?
When the group count reaches 0, that's it forever.
So
| Code: |
| <cue name="Blah.instance.handler" instantiate="static"> |
leads to this cue being run multiple times even though Blah.Setup would be a completed cue once it has reached the point of Blah.instance.handler exactly once?
| Quote: |
| Anyone who wants to experiment with instancing may find it hairy to wrap your head around the fact that there can be multiple copies of your cues all firing simultaneously, here's a few lines of helper code that can make it much easier to track the instances themselves. |
That in itself is pretty normal. SE Signal and Jobs scripts do that all the time. Or one turret script that runs on several tasks of the same object, using a weapon changer script that "serves" all of them at once.
The difficulty with MD instances is... I dunno. If I knew I could probably understand it. Which I haven't, yet.
I'm not even interested in specific examples but rather why the cues do what they do.
The jump between single and multiple instance is triggered by what, when, and how often?
_________________ My complete script download page. . . . . . Xai-Corp MSCI List is scripter's friend. I AM THE LAW!
Dogs and colour blindness explained: People with green eyes can't see dogs. |
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
Shush
Joined: 06 Dec 2003 Posts: 17 on topic Location: Melbourne, Australia

|
Posted: Sun, 15. Aug 10, 09:56 Post subject: |
|
|
| Quote: |
Wouldn't this run your instanced instructions once for every group member and then never again?
When the group count reaches 0, that's it forever. |
The first condition within the instanced cue is what initiates the copy/instancing process, so in the example I gave whenever the object count is >= 1 a new instance is spawned. As far as the top level parent cue, i.e. the static cue is concerned, the condition is never met and it sits there idle waiting forever unless you happen to cancel or complete it, which you can do elsewhere in a static cancel/reset cue or even within the instance that was just spawned.
| Quote: |
| leads to this cue being run multiple times even though Blah.Setup would be a completed cue once it has reached the point of Blah.instance.handler exactly once? |
Blah.Setup is never completed, that's the tricky bit, the instance is spawned and Blah.Setup sits there passively idling waiting to spawn new instances. If I was to guess as to how it is implemented internally; Blah.Setup gets to the instantiate="static" line, checks the condition, if the check is satisified it copies every cue and sub cue under this condition and then begins processing the new instance. The condition that spawned the instance is not marked as completed so that when processing gets back to Blah.Setup it happily performs the condition again and again ad infinitum until you stop it with a cancel/reset as mentioned above.
| Quote: |
| That in itself is pretty normal. SE Signal and Jobs scripts do that all the time. Or one turret script that runs on several tasks of the same object, using a weapon changer script that "serves" all of them at once. |
Yup I started with MSCI and progressed to MD, they are both powerful in their own rights, but the real golden opportunity the devs missed was providing a data passing mechanism between the two. Though you can get around this by having MD create objects in the universe, running a script to tell MSCI about them and then using either homebase or user wing arrays to pass back objects fron the MSCI to the MD. I do this a lot in my stuff and though it's a serious kludge, it works really well with only 1 or 2 caveats.
| Quote: |
| The difficulty with MD instances is... I dunno. If I knew I could probably understand it. Which I haven't, yet. I'm not even interested in specific examples but rather why the cues do what they do. The jump between single and multiple instance is triggered by what, when, and how often? |
I've tried to explain it above, it will click, the eureka moment I had was when I wrote a very simple instancing example and used incoming message to watch what was happening; in exactly the same way I use XTail with 8-10 log files running simultaneously on a second monitor to debug what the game really does in the MSCI, it's the only way to fully appreciate all the idosyncrasies and gotchya's.
|
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
Gazz Moderator (Script&Mod)


Joined: 13 Jan 2006 Posts: 12153 on topic Location: Bavaria

|
Posted: Sun, 15. Aug 10, 10:21 Post subject: |
|
|
That already makes more sense.
The tricky bit with stuff like that usually isn't getting an answer but finding the right question.
Takes a real noob to do that so manuals/tutorials written by experts suck when they don't explain the "obvious" issues.
It's obvious that there must be instances, both from seeing the game work and the "instantiate" property of the cue tag.
Only without a clear understanding of what exact bits of what cues are executed and when, it's not useable.
The SE is easier in that reagard.
You start an action - something happens.
You have it wait until conditions XYZ are met - then it does something.
The sequence of events is always clear.
_________________ My complete script download page. . . . . . Xai-Corp MSCI List is scripter's friend. I AM THE LAW!
Dogs and colour blindness explained: People with green eyes can't see dogs. |
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
ScRaT_GER

Joined: 08 Jan 2008 Posts: 1958 on topic

|
Posted: Sun, 15. Aug 10, 10:37 Post subject: |
|
|
| Quote: |
| With instances I can be reactive to pre-existing ships/stations being attacked, create an actor, offer a conversation/mission and handle universe events without having to fake anything. |
Wow, that's a really good technique! Until now, I didn't even know how instances really work! And I still don't completely, which is why I have the following questions:
You wrote:
| Quote: |
| Blah.Setup is never completed, that's the tricky bit, the instance is spawned and Blah.Setup sits there passively idling waiting to spawn new instances. If I was to guess as to how it is implemented internally; Blah.Setup gets to the instantiate="static" line, checks the condition, if the check is satisified it copies every cue and sub cue under this condition and then begins processing the new instance. The condition that spawned the instance is not marked as completed so that when processing gets back to Blah.Setup it happily performs the condition again and again ad infinitum until you stop it with a cancel/reset as mentioned above. |
So you don't need "reset_cue cue="Blah.Setup" in your instance cues? What happens if you supply one?
| Quote: |
| but the real golden opportunity the devs missed was providing a data passing mechanism between the two |
Yes, that's a pity.
| Quote: |
| 2) Using instances will often require you to reference the instance's copy of a variable, you must use this. and parent. etc in this particular example, any other way of referencing your variable names will cause all instances to reference a global copy of that variable. |
That's interesting, too.
As far as I understood it, when cues are instantiated, cues with the exact same name are created and run. When I now tried to reference a variable not using this or parent, which copy would be rerenced?
I'm asking that, because atm I wouldn't know how to destroy all instances of a cue or some objects created by instances of a cue (e.g. for uninstalling). Of course I could use a instance-local uninstall-cue, but I guess it might be nicer to seperate the "working" cues from the ones to uninstall.
Can instances of a cue be referenced by one of the following commands?
| director.htm wrote: |
{instance@cue}: {instance@this} - Instance id of the specified cue
{static@cue}: {static@this} - Instance id of the static cue of a cue instance
{instances.count@cue}: {instances.count@this} - Number of instances of this static cue
{instances.num@cue}: {instances.1@this} - Instance id of an instance of this static cue |
So could you write something like "<destroy_cue cue="{instance.1@myStaticCue}/>" ?
Greetings,
ScRaT
_________________
Skripts:
Teladi Informations Service, Fahrtenbuch, Handelsübersicht |
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
Shush
Joined: 06 Dec 2003 Posts: 17 on topic Location: Melbourne, Australia

|
Posted: Sun, 15. Aug 10, 16:45 Post subject: |
|
|
| Quote: |
| So you don't need "reset_cue cue="Blah.Setup" in your instance cues? What happens if you supply one? |
Nope you definitely don't need to reset your top level cue, and for simple instance handlers you wouldn't. The top level cue could sit there happily checking the initial instance condition and spawning instances forever. The obvious caveat is that you need a mechanism to make sure that the spawning doesn't get out of control, that usually means that each instance somehow changes the properties of the initial condition.
The instances themselves once fully complete or cancelled, destroy themselves out of existance; so they spawn as self contained entities that can replicate MD behavioural rules, that react and process to spontaneous events that occur throughout the universe through various MD condition checks.
For more complex instance handlers I've found I invariably do end up reset'ing the top level cue, cancelling individual instances and even cancelling all instances. There are multiple ways of doing these exceptions, but the cleanest way I have found so far is by having an instance watcher cue, similar to the code I showed in a reply to gazz's post. By using global variables and knowing how and when I want to control the instances I can feed information into the instance watcher which sits just above the instance handler and have it somewhat elegantly control everything.
I've added some examples code from one of my current MD projects.
| Code: |
<!-- Check if instances count has changed -->
<cue name="LIFE.GNS.Restart" delay="1s">
<condition>
<check_value negate="1" value="{instances.count@{LIFE.GNS.StationHandler}}" exact="{value@LIFE.GNS.instancesCount}"/>
</condition>
<action>
<do_all>
<!-- If instances count = 0 then restart LIFE.GNS -->
<do_if value="{instances.count@{LIFE.GNS.StationHandler}}" exact="0">
<!--incoming_message author="LIFE.GNS.Restart" text="Instance Count: {instances.count@{LIFE.GNS.StationHandler}}"/-->
<reset_cue cue="LIFE.GNS"/>
</do_if>
<!-- If instances count has decreased, then cancel all instances -->
<do_if value="{instances.count@{LIFE.GNS.StationHandler}}" max="{value@LIFE.GNS.instancesCount}-1">
<set_value name="LIFE.GNS.cancelInstances" exact="1"/>
</do_if>
<!-- Save instances count -->
<set_value name="LIFE.GNS.instancesCount" exact="{instances.count@{LIFE.GNS.StationHandler}}"/>
<reset_cue cue="LIFE.GNS.Restart"/>
</do_all>
</action>
</cue> |
LIFE.GNS is the top most level cue and performs all the setup, it sits above LIFE.GNS.Restart. LIFE.GNS.Restart is the instance watcher that sits just above the instance handler, LIFE.GNS.StationHandler. The instances themselves are spawned by LIFE.GNS.StationHandler which as part of their conditions, checks the global variable LIFE.GNS.cancelInstances, when the global goes true they all systematically cancel themselves and then the top most level cue is reset, (for my code I absoloutely must have 0 instances running before I completely reset LIFE.GNS). This allows me to on the fly to react to events in the universe as I mentioned earlier. This bit of code belongs to an MD file that allows me to spawn station actors on any number of stations in a sector belonging to any number of races, if the number of stations, races or player's notoriety to these stations/races changes, then everything adapts within a few seconds with appropriate actors being destroyed and new actors generated.
| Quote: |
That's interesting, too.
As far as I understood it, when cues are instantiated, cues with the exact same name are created and run. When I now tried to reference a variable not using this or parent, which copy would be rerenced? |
I re-read what I wrote and it is poorly written, as you said when an instance is spawned, everything about the instanced cues and their sub cues is copied; i.e. the cues, the conditions, the actions, the variables etc. But depending on the scope of a variable, i.e. whether it is local or global, MD will search for the variable in different ways. I pulled this out of the XMDGuide on page 10 -->
| Code: |
If it doesn't find a cue of the correct name then it will start looking down all cue structures but may not always find the correct instance (in fact for instantiated cues it will always find the master instance). You can shortcut this
process and prevent the latter part of it by using "this" to refer to the current cue instance rather than the cue name, and "parent" to refer to the parent cue instance." |
The important bit there is "(in fact for instantiated cues it will always find the master instance)"...Now to be honest I haven't fully tested the MD to see if it behaves exactly the way this line of text reads to me, but the way this. and parent. work is exactly as expected, so my assumption is that a global variable will always be referenced from within the static master cue by the copied instanced cues rather than from within the instances themselves.
| Quote: |
| I'm asking that, because atm I wouldn't know how to destroy all instances of a cue or some objects created by instances of a cue (e.g. for uninstalling). Of course I could use a instance-local uninstall-cue, but I guess it might be nicer to seperate the "working" cues from the ones to uninstall. |
If you can perform your cleanup in the instance itself I will go out on a limb and say that generally it is usually easier to do it locally within the instance itself. But as I showed above sometimes you need a more macroscopic control, using my watcher cue I am able to control when instances destroy themselves. If you were able to seperate worker instances from cleanup instances, then I am guessing you could use either method to control how the cleanup instances did their thing. Because my MD projects seem to be all based on the dynamic state of the universe without me creating new objects, this isn't much of an issue for me as I have very little to clean up; but when I do have to clean things up, like actors, offers, conversations etc, I can invariably handle it all locally within the worker instance itself.
{instance@cue}: returns a unique identifier for an instance, very useful for debugging and differentiating an instance from other instances. You can only use it within an instanced cue and the value it returns is very similar to other ID's, like actor ID's, object ID's etc.
{static@cue} returns a unique identifier for the master copy of the instanced cues, so for example if you need to know the total number of spawned instances within an instance, you would query the instance count of the master copy, not of one of the individual instances; like so:
| Code: |
| {instances.count@{static@LIFE.attacked.handler}} |
where LIFE.attacked.handler is the name of the instanced cue.
[quote]So could you write something like "<destroy_cue cue="{instance.1@myStaticCue}/>" ?[/code]
I haven't tried this but it absoloutely should work, in fact I think I'll work it into some of my code and see how I go. You would most likely be performing it in a non instanced cue and when you do that if you reference an instanced cue by name then you be default reference the static copy, i.e. the master copy. What would be interesting is if you could destroy an instance from another instance, which would have to look something like this -->
| Code: |
| <destroy_cue cue="{instance.1@{static@myInstancedCue}}/> |
|
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
ScRaT_GER

Joined: 08 Jan 2008 Posts: 1958 on topic

|
Posted: Sun, 15. Aug 10, 17:39 Post subject: |
|
|
Thanks for the info! This is going to be really valuable for later projects I'm planning.
| Quote: |
| This bit of code belongs to an MD file that allows me to spawn station actors on any number of stations in a sector belonging to any number of races, if the number of stations, races or player's notoriety to these stations/races changes, then everything adapts within a few seconds with appropriate actors being destroyed and new actors generated. |
Yes, that's exactly what I needed! It's practically impossible to spawn multiple actors using one cue and handling their conversations.
Because of that, I had to limit myself to one single station - until now...
| Quote: |
| If you can perform your cleanup in the instance itself I will go out on a limb and say that generally it is usually easier to do it locally within the instance itself. |
Okay, together with your watcher cue, the cue control should work fine. Thanks for the insights.
BTW: I noticed that you name your cues with dots everywhere, like "LIFE.GNS.StationHandler". Couldn't that be problem for the MD when it tries to find names. For example LIFE.GNS.StationHandler could either reference the "cue-local" variable "StationHandler" in the cue "LIFE.GNS" or it could reference the cue-local variable "GNS.StationHandler" in the cue "LIFE". Or am I missing something here?
Greetings,
ScRaT
PS: I'm really looking forward to your LIFE project - looks very promising!
_________________
Skripts:
Teladi Informations Service, Fahrtenbuch, Handelsübersicht |
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
Shush
Joined: 06 Dec 2003 Posts: 17 on topic Location: Melbourne, Australia

|
Posted: Sun, 15. Aug 10, 17:57 Post subject: |
|
|
| Quote: |
| BTW: I noticed that you name your cues with dots everywhere, like "LIFE.GNS.StationHandler". Couldn't that be problem for the MD when it tries to find names. For example LIFE.GNS.StationHandler could either reference the "cue-local" variable "StationHandler" in the cue "LIFE.GNS" or it could reference the cue-local variable "GNS.StationHandler" in the cue "LIFE". Or am I missing something here? |
It shouldn't be a problem as all my cue names are unique, here is my MD file that handles the news for LIFE across multiple stations in a sector, you'll see what I mean about the naming and you may get some use out of the rest of the code
| Code: |
<?xml version="1.0" encoding="ISO-8859-1" ?>
<?xml-stylesheet href="director.xsl" type="text/xsl" ?>
<director name="test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="director.xsd">
<documentation>
<author name="Ari Tsironis" alias="Shush" contact="Shush at forum.egosoft.com"/>
<content reference="LIFE.GNS" name="LIFE.GNS" description="Galactic News System launcher for LIFE"/>
<version number="0.0" date="today" status="testing"/>
</documentation>
<cues>
<!-- Galactic News System launcher, check MCSI<->MD flag for 666, (START GNS) -->
<cue name="LIFE.GNS">
<condition>
<check_all>
<check_age value="{player.age}" min="5s"/>
<check_value value="{player.notoriety.other2}" exact="666"/>
</check_all>
</condition>
<action>
<do_all>
<!--incoming_message author="LIFE.GNS" text="Initialising:"/-->
<!-- Global instance count -->
<set_value name="LIFE.GNS.instancesCount" exact="0"/>
<!-- Global cancel instances flag -->
<set_value name="LIFE.GNS.cancelInstances" exact="0"/>
<!-- Save player's notoriety with all races -->
<set_value name="LIFE.GNS.argonNotoriety" exact="{player.notoriety.argon}"/>
<set_value name="LIFE.GNS.boronNotoriety" exact="{player.notoriety.boron}"/>
<set_value name="LIFE.GNS.splitNotoriety" exact="{player.notoriety.split}"/>
<set_value name="LIFE.GNS.paranidNotoriety" exact="{player.notoriety.paranid}"/>
<set_value name="LIFE.GNS.teladiNotoriety" exact="{player.notoriety.teladi}"/>
<set_value name="LIFE.GNS.pirateNotoriety" exact="{player.notoriety.pirate}"/>
<set_value name="LIFE.GNS.gonerNotoriety" exact="{player.notoriety.goner}"/>
<set_value name="LIFE.GNS.other1Notoriety" exact="{player.notoriety.other1}"/>
<set_value name="LIFE.GNS.atfNotoriety" exact="{player.notoriety.atf}"/>
<set_value name="LIFE.GNS.terranNotoriety" exact="{player.notoriety.terran}"/>
<set_value name="LIFE.GNS.yakiNotoriety" exact="{player.notoriety.yaki}"/>
<!-- Build a list of candidate stations -->
<find_station group="this.stations" multiple="1" nearest="1" max="10" findobject="{player.ship}" dockingallowed="1" typename="SS_DOCK_TR_MILITARY_3|SS_DOCK_TR_MILITARY_2|SS_DOCK_TR_MILITARY_1|SS_DOCK_T_TRADE|
SS_DOCK_S_TRADE|SS_DOCK_P_TRADE|SS_DOCK_A_TRADE|SS_DOCK_B_TRADE|SS_DOCK_GONER|SS_DOCK_GONER_NEW|SS_DOCK_PIRATES"><jumps exact="0"/></find_station>
<!-- Nothing in our list, so find any station we can dock at -->
<do_if value="{group.object.count@this.stations}" exact="0">
<find_station group="this.stations" nearest="1" max="1" findobject="{player.ship}" dockingallowed="1" enemy="0"><jumps exact="0"/></find_station>
</do_if>
<!-- Global no stations flag -->
<set_value name="LIFE.GNS.noStations" exact="0"/>
<do_if value="{group.object.count@this.stations}" exact="0"><set_value name="LIFE.GNS.noStations" exact="1"/></do_if>
<!--play_subtitles duration="5000" text="GNS: {object.name@{group.object.1@this.stations}} {group.object.count@this.stations}"/-->
</do_all>
</action>
<cues>
<!-- No dockable stations, so restart LIFE.GNS when player leaves the sector -->
<cue name="LIFE.GNS.NoStations">
<condition>
<check_all>
<object_changed_sector/>
<check_value value="{value@LIFE.GNS.noStations}" exact="1"/>
</check_all>
</condition>
<action>
<do_all>
<!--incoming_message author="LIFE.GNS.NoStations" text="Instance Count: {instances.count@{LIFE.GNS.StationHandler}}"/-->
<reset_cue cue="LIFE.GNS"/>
</do_all>
</action>
</cue>
<!-- Restart LIFE.GNS when player's notoriety changes with any race -->
<cue name="LIFE.GNS.PlayerNotoriety" delay="1s">
<condition>
<check_any>
<check_value negate="1" value="{value@LIFE.GNS.argonNotoriety}" exact="{player.notoriety.argon}"/>
<check_value negate="1" value="{value@LIFE.GNS.boronNotoriety}" exact="{player.notoriety.boron}"/>
<check_value negate="1" value="{value@LIFE.GNS.splitNotoriety}" exact="{player.notoriety.split}"/>
<check_value negate="1" value="{value@LIFE.GNS.paranidNotoriety}" exact="{player.notoriety.paranid}"/>
<check_value negate="1" value="{value@LIFE.GNS.teladiNotoriety}" exact="{player.notoriety.teladi}"/>
<check_value negate="1" value="{value@LIFE.GNS.pirateNotoriety}" exact="{player.notoriety.pirate}"/>
<check_value negate="1" value="{value@LIFE.GNS.gonerNotoriety}" exact="{player.notoriety.goner}"/>
<check_value negate="1" value="{value@LIFE.GNS.other1Notoriety}" exact="{player.notoriety.other1}"/>
<check_value negate="1" value="{value@LIFE.GNS.atfNotoriety}" exact="{player.notoriety.atf}"/>
<check_value negate="1" value="{value@LIFE.GNS.terranNotoriety}" exact="{player.notoriety.terran}"/>
<check_value negate="1" value="{value@LIFE.GNS.yakiNotoriety}" exact="{player.notoriety.yaki}"/>
</check_any>
</condition>
<action>
<do_all>
<!--incoming_message author="LIFE.GNS.PlayerNotoriety" text="Instance Count: {instances.count@{LIFE.GNS.StationHandler}}"/-->
<!-- If there are no instances of LIFE.GNS.StationHandler then restart LIFE.GNS -->
<do_if value="{instances.count@{LIFE.GNS.StationHandler}}" exact="0"><reset_cue cue="LIFE.GNS"/></do_if>
<!-- If there are instances of LIFE.GNS.StationHandler then use the global LIFE.GNS.cancelInstances to restart LIFE.GNS -->
<do_if value="{instances.count@{LIFE.GNS.StationHandler}}" min="1"><set_value name="LIFE.GNS.cancelInstances" exact="1"/></do_if>
</do_all>
</action>
</cue>
<!-- Check if instances count has changed -->
<cue name="LIFE.GNS.Restart" delay="1s">
<condition>
<check_value negate="1" value="{instances.count@{LIFE.GNS.StationHandler}}" exact="{value@LIFE.GNS.instancesCount}"/>
</condition>
<action>
<do_all>
<!-- If instances count = 0 then restart LIFE.GNS -->
<do_if value="{instances.count@{LIFE.GNS.StationHandler}}" exact="0">
<!--incoming_message author="LIFE.GNS.Restart" text="Instance Count: {instances.count@{LIFE.GNS.StationHandler}}"/-->
<reset_cue cue="LIFE.GNS"/>
</do_if>
<!-- If instances count has decreased, then cancel all instances -->
<do_if value="{instances.count@{LIFE.GNS.StationHandler}}" max="{value@LIFE.GNS.instancesCount}-1">
<set_value name="LIFE.GNS.cancelInstances" exact="1"/>
</do_if>
<!-- Save instances count -->
<set_value name="LIFE.GNS.instancesCount" exact="{instances.count@{LIFE.GNS.StationHandler}}"/>
<reset_cue cue="LIFE.GNS.Restart"/>
</do_all>
</action>
</cue>
<!-- Found a station -->
<cue name="LIFE.GNS.StationHandler" instantiate="static" delay="1s">
<condition>
<check_value value="{group.object.count@parent.stations}" min="1"/>
</condition>
<action>
<do_all>
<!-- Save station object and remove it from group so that we don't have runaway instance creation -->
<set_object name="this.station" value="{group.object.1@parent.stations}"/>
<remove_object_from_group object="{group.object.1@parent.stations}" group="parent.stations"/>
<!-- Save station owner and players notoriety with station owner -->
<set_value name="this.owner" exact="{object.race@this.station}"/>
<set_value name="this.notoriety" exact="{player.notoriety.{object.race@this.station}}"/>
<!--set_value name="this.instanceID" exact="{instance@LIFE.GNS.StationHandler}"/>
<set_value name="this.instancesCount" exact="{instances.count@{static@LIFE.GNS.StationHandler}}"/>
<incoming_message author="{object.name@this.station}" text="StationHandler: {lookup.race.name@{value@this.owner}} {value@this.notoriety} {value@this.instanceID} {value@this.instancesCount}"/-->
<!--play_subtitles duration="5000" text="StationHandler: {object.name@this.station} {lookup.race.name@{value@this.owner}} {value@this.notoriety} {value@this.instanceID} {value@this.instancesCount}"/-->
<!-- Create GNS Representative -->
<do_if value="{value@this.owner}" exact="{lookup.race@argon}">
<create_actor name="this.actor" location="crew" race="{value@this.owner}" character=".I.B.C. Representative" object="this.station" voiceflags="32"/>
<create_offer actor="this.actor" conversation="LIFE.GNS.conversation.argon" cue="LIFE.GNS.StationHandler" discipline="XXXT"/>
</do_if>
<do_if value="{value@this.owner}" exact="{lookup.race@boron}">
<create_actor name="this.actor" location="crew" race="{value@this.owner}" character=".R.C.N. Representative" object="this.station" voiceflags="32"/>
<create_offer actor="this.actor" conversation="LIFE.GNS.conversation.boron" cue="LIFE.GNS.StationHandler" discipline="XXXT"/>
</do_if>
<do_if value="{value@this.owner}" exact="{lookup.race@split}">
<create_actor name="this.actor" location="crew" race="{value@this.owner}" character=".S.F.N. Representative" object="this.station" voiceflags="32"/>
<create_offer actor="this.actor" conversation="LIFE.GNS.conversation.split" cue="LIFE.GNS.StationHandler" discipline="XXXT"/>
</do_if>
<do_if value="{value@this.owner}" exact="{lookup.race@paranid}">
<create_actor name="this.actor" location="crew" race="{value@this.owner}" character=".I.P.N. Representative" object="this.station" voiceflags="32"/>
<create_offer actor="this.actor" conversation="LIFE.GNS.conversation.paranid" cue="LIFE.GNS.StationHandler" discipline="XXXT"/>
</do_if>
<do_if value="{value@this.owner}" exact="{lookup.race@teladi}">
<create_actor name="this.actor" location="crew" race="{value@this.owner}" character=".C.B.N.N. Representative" object="this.station" voiceflags="32"/>
<create_offer actor="this.actor" conversation="LIFE.GNS.conversation.teladi" cue="LIFE.GNS.StationHandler" discipline="XXXT"/>
</do_if>
<do_if value="{value@this.owner}" exact="{lookup.race@pirate}">
<create_actor name="this.actor" location="crew" race="{value@this.owner}" character=".M.I.N. Representative" object="this.station" voiceflags="32"/>
<create_offer actor="this.actor" conversation="LIFE.GNS.conversation.pirate" cue="LIFE.GNS.StationHandler" discipline="XXXT"/>
</do_if>
<do_if value="{value@this.owner}" exact="{lookup.race@terran}">
<create_actor name="this.actor" location="crew" race="{value@this.owner}" character=".S.S.N. Representative" object="this.station" voiceflags="32"/>
<create_offer actor="this.actor" conversation="LIFE.GNS.conversation.terran" cue="LIFE.GNS.StationHandler" discipline="XXXT"/>
</do_if>
<do_if value="{value@this.owner}" exact="{lookup.race@yaki}">
<create_actor name="this.actor" location="crew" race="{value@this.owner}" character=".Y.C.N. Representative" object="this.station" voiceflags="32"/>
<create_offer actor="this.actor" conversation="LIFE.GNS.conversation.yaki" cue="LIFE.GNS.StationHandler" discipline="XXXT"/>
</do_if>
</do_all>
</action>
<cues>
<!-- Main Event handler -->
<cue name="LIFE.GNS.EventHandler">
<cues>
<!-- Check player changed sector, station destroyed, MCSI<->MD flag 667 (STOP GNS), global cancel instances flag -->
<cue name="LIFE.GNS.CancelInstance">
<condition>
<check_any>
<object_changed_sector/>
<object_destroyed object="parent.parent.station"/>
<object_destroyed_by_player object="parent.parent.station"/>
<check_value value="{player.notoriety.other2}" exact="667"/>
<check_value value="{value@LIFE.GNS.cancelInstances}" exact="1"/>
</check_any>
</condition>
<action>
<do_all>
<!--set_value name="this.instanceID" exact="{instance@LIFE.GNS.StationHandler}"/>
<set_value name="this.instancesCount" exact="{instances.count@{static@LIFE.GNS.StationHandler}}"/>
<incoming_message author="{actor.name@parent.parent.actor}" text="CancelInstance: {value@this.instanceID} {value@this.instancesCount}"/-->
<!--play_subtitles duration="5000" text="CancelInstance: {actor.name@parent.parent.actor} {value@this.instanceID} {value@this.instancesCount}"/-->
<!-- If GNS Representative exists, remove him and his conversation -->
<do_if value="{actor.exists@parent.parent.actor}" exact="1">
<do_if value="{value@parent.parent.owner}" exact="{lookup.race@argon}"><remove_offer actor="parent.parent.actor" conversation="LIFE.GNS.conversation.argon" discipline="XXXT"/></do_if>
<do_if value="{value@parent.parent.owner}" exact="{lookup.race@boron}"><remove_offer actor="parent.parent.actor" conversation="LIFE.GNS.conversation.boron" discipline="XXXT"/></do_if>
<do_if value="{value@parent.parent.owner}" exact="{lookup.race@split}"><remove_offer actor="parent.parent.actor" conversation="LIFE.GNS.conversation.split" discipline="XXXT"/></do_if>
<do_if value="{value@parent.parent.owner}" exact="{lookup.race@paranid}"><remove_offer actor="parent.parent.actor" conversation="LIFE.GNS.conversation.paranid" discipline="XXXT"/></do_if>
<do_if value="{value@parent.parent.owner}" exact="{lookup.race@teladi}"><remove_offer actor="parent.parent.actor" conversation="LIFE.GNS.conversation.teladi" discipline="XXXT"/></do_if>
<do_if value="{value@parent.parent.owner}" exact="{lookup.race@pirate}"><remove_offer actor="parent.parent.actor" conversation="LIFE.GNS.conversation.pirate" discipline="XXXT"/></do_if>
<do_if value="{value@parent.parent.owner}" exact="{lookup.race@terran}"><remove_offer actor="parent.parent.actor" conversation="LIFE.GNS.conversation.terran" discipline="XXXT"/></do_if>
<do_if value="{value@parent.parent.owner}" exact="{lookup.race@yaki}"><remove_offer actor="parent.parent.actor" conversation="LIFE.GNS.conversation.yaki" discipline="XXXT"/></do_if>
<clear_actor_location actor="parent.parent.actor"/>
<destroy_actor actor="parent.parent.actor"/>
</do_if>
<!-- Cancel instance -->
<cancel_cue cue="LIFE.GNS.StationHandler"/>
</do_all>
</action>
</cue>
<!-- Process conversation -->
<cue name="LIFE.GNS.Conversation">
<condition>
<check_any>
<check_all>
<check_value value="{value@parent.parent.owner}" exact="{lookup.race@argon}"/>
<conversation_completed conversation="LIFE.GNS.conversation.argon" actor="parent.parent.actor"/>
</check_all>
<check_all>
<check_value value="{value@parent.parent.owner}" exact="{lookup.race@boron}"/>
<conversation_completed conversation="LIFE.GNS.conversation.boron" actor="parent.parent.actor"/>
</check_all>
<check_all>
<check_value value="{value@parent.parent.owner}" exact="{lookup.race@split}"/>
<conversation_completed conversation="LIFE.GNS.conversation.split" actor="parent.parent.actor"/>
</check_all>
<check_all>
<check_value value="{value@parent.parent.owner}" exact="{lookup.race@paranid}"/>
<conversation_completed conversation="LIFE.GNS.conversation.paranid" actor="parent.parent.actor"/>
</check_all>
<check_all>
<check_value value="{value@parent.parent.owner}" exact="{lookup.race@teladi}"/>
<conversation_completed conversation="LIFE.GNS.conversation.teladi" actor="parent.parent.actor"/>
</check_all>
<check_all>
<check_value value="{value@parent.parent.owner}" exact="{lookup.race@pirate}"/>
<conversation_completed conversation="LIFE.GNS.conversation.pirate" actor="parent.parent.actor"/>
</check_all>
<check_all>
<check_value value="{value@parent.parent.owner}" exact="{lookup.race@terran}"/>
<conversation_completed conversation="LIFE.GNS.conversation.terran" actor="parent.parent.actor"/>
</check_all>
<check_all>
<check_value value="{value@parent.parent.owner}" exact="{lookup.race@yaki}"/>
<conversation_completed conversation="LIFE.GNS.conversation.yaki" actor="parent.parent.actor"/>
</check_all>
</check_any>
</condition>
<!--action>
<do_all>
<set_value name="this.instanceID" exact="{instance@LIFE.GNS.StationHandler}"/>
<set_value name="this.instancesCount" exact="{instances.count@{static@LIFE.GNS.StationHandler}}"/>
<incoming_message author="{actor.name@parent.parent.actor}" text="Conversation: {lookup.race.name@{value@parent.parent.owner}} {value@this.instanceID} {value@this.instancesCount}"/>
<play_subtitles duration="5000" text="Conversation: {actor.name@parent.parent.actor} {lookup.race.name@{value@parent.parent.owner}} {value@this.instanceID} {value@this.instancesCount}"/>
</do_all>
</action-->
<cues>
<!-- Wait for dialog menu to close, run news script, restart event handler -->
<cue name="LIFE.GNS.NewsScript">
<condition>
<check_value value="{player.menu.dialog}" exact="0"/>
</condition>
<action>
<!-- GNS needs to know station owner's race -->
<do_all>
<run_script script="plugin.LIFE.generate.news" task="1">
<scriptargs>
<scriptvalue datatype="integer" datavalue="{value@parent.parent.parent.owner}"/>
</scriptargs>
</run_script>
<reset_cue cue="LIFE.GNS.EventHandler"/>
</do_all>
</action>
</cue>
</cues>
</cue>
</cues>
</cue>
</cues>
</cue>
</cues>
</cue>
</cues>
</director> |
|
|
|
|
|
|
|
Back to top |
|
|
|
 |
|
|
|
|
|
|
|
 |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You cannot download files in this forum
|
 |
|
|
|
|
|