Nexus Skirmisher

Nexus Modding => Scripting => Topic started by: The Old Dragon on November 22, 2009, 09:59:33

Title: Scripting Issues
Post by: The Old Dragon on November 22, 2009, 09:59:33
Hi folks,

I've got a little bit of a sticky script that's been holding me up for a day or two.

What I'm trying to achieve is a script that will...

1) Install a device (well, a transport ship really, but the game sees it as a device) on a certain entity.
2) Send said device/transport model to a second entity.
3) When the device/transport gets close to the second entity, transfer and dock the device/transport.
4) Once docked, delete said device/transport to make room for others.

At the moment, I'm as far as docked. The debug code kicks to tell me that the transport has docked but I'm having trouble isolating the recently docked object from the rest.  At the moment, it'll either ignore the fact that they're docking or destroy everything within the area regardless of whether it's docked or not. Here's the code I've got for the 'sticky' bit...

Code: [Select]
If(E.location=M.CH_O,
TSD:=GetFreeSel();
SelectDevices(TSD,M.CH_O,Inset(S.this,25)&E.ship:docking=4);
ExecList(TSD,
Dump(TSD);
Debug("Deleting Station Transport");
DeleteDevice(S.this);
);
);

Anyone have an idea on how to resolve this little issue?

EDIT:

Blooming typical, I post for a solution to something that's been bothering me for days, then ten minutes later I find one. Life sure can be mean sometimes.

By adding a 'distance' section to the condition, I've got it to do what I wanted. But if anyone knows of a neater solution, I'm still all ears.
Title:
Post by: Mularac on November 23, 2009, 02:07:49
so... what was the solution?
anyway, I have an other problem, a lot simpler but it still bugs me like hell:

here's the deal. I've been working on a machine that will search for brusque changes in the shield integrity values of a ship, or otherwise, it'll keep a close watch if you manually disengage shields for some reason, it'll then store the previous value of the shield integrity (so far so good) and it will, supposedly, add it back to the shield via the M.Ship:=ShieldIntegrity:=*value*; command.
But there comes my problem, if i place the variable name in the *value* slot, the game will crash with a cExpression.cpp Line:521.
so... perhaps I'm doing somithing wrong there, I'm not too fluent with nexus variables...
anyway, here's the code:

Code: [Select]
RULE event Tick  //I start the tick line
:action
debug("tick1");
if(flag=1,  //this is a check so that the variable is not overwritten after the shield drain
set(shield,m.pship.5:ShieldIntegrity);
debug(shield);  //I declare and show the "shield" variable on the console
);
Delay(0,2.9,  //I set a 2.9 delay because the tick refreshes every 3 sec, and I want the less dead time possible.
set(shield2,m.pship.5:ShieldIntegrity);   //I declare the variable "shield2" as the value of the shield integrity 2.9 seconds after the first check
debug("tick2");
debug(shield2);
if(shield2=0,   //and here comes the magic: if the shield has been drained I perform this check
flag:=0;    //I disable the check
debug("drained and the shield value is:");
debug(shield);   //debuggind purposes
if(shield>1000,  //and here I compare the two values. if the previous value was higher than 1000, the if will take over. This is meant to avoid       triggers caused by "regular" shield draining.
debug("charged");
debug(shield);
m.pship.5:=shieldintegrity:=shield;  //}And in here I refil the ships' shield tank with the previous charge.
);
);
 ,0);

:end
END
tick 3



Damn.... there's got to be something magical about this site.... Old Dragon, same thing happened to me. The solution came no more than 10' after I finished typing this... the error was this:
m.pship.5:=shieldintegrity:=shield;  

it should have been:

m.pship.5:shieldintegrity:=shield;

now I have to figure out how to make this thing generic....
Title:
Post by: Arparso on November 23, 2009, 09:06:24
That got to be the best help thread ever ... problems solving themselves - every tech support guy's wet dream ;)
Title:
Post by: The Old Dragon on November 23, 2009, 09:14:53
Indeed there is... it's the magic of Arparso, lol. The very thought of posting it on the Skirmisher forum seems to make the problem roll over and play dead. lol

But more seriously, the solution code to my problem is...

Code: [Select]
If(E.location=M.CH_O,
TSD:=GetFreeSel();
SelectDevices(TSD,M.CH_O,Inset(S.this,25)&E.ship:docking=4&Distance(S.this,M.CH_O)<100);
ExecList(TSD,
DeleteDevice(S.this);
);
);

As for making yours more specific Mularac, hmmm...

You could try encapsulating the code within a 'SelectShips' command with the condition 'S.race=#race_Player&S.this:IsShielded', if you're only interested in the player or 'S.race=#race_Player|Not(S.race=#race_Player)&S.this:IsShielded' if you want to include all objects within the scene that have active shields, then 'ExecList' it.

With that done, you could then replace the 'M.PShip.5' with 'S.this' instead.

The only problem would be with the variable name... perhaps it could be overcome with by using the variable 'Shield:Name'? Not too sure though.
Title:
Post by: Arparso on November 23, 2009, 09:33:52
You could also store the last shield value directly at the object level like this:

Code: [Select]
TICK 1

RULE event Tick
:action
SelectEx(s.ship & s.isShielded,
s:this:lastShieldIntegrity:=s:this:shieldIntegrity;
Debug("saved shield for", s.this, "with", s:this:lastShieldIntegrity);
);
:end
END

If the shield is currently active, it stores the current shieldIntegrity in the lastShieldIntegrity variable for each object. If the shield is not active, the value won't be overridden.
Title:
Post by: Mularac on November 23, 2009, 11:47:45
thanks guys, tomorrow afternoon I'm gonna get right into it :P
not today, though... got to prepare for a big exam tomorrow.
Title:
Post by: Arparso on November 23, 2009, 14:35:33
Even easier solution with no need for a tick event:
Code: [Select]
   MACHINE "ShieldPreserve"

        STATE ShieldPreserve
               
            RULE event In
                :action
                    SelectEx(s.shield,
                        EnableActivateEvents(s.this, 1);
                        Debug("enabled 'activate' events for shield", s.this, "on", s.this:owner);
                    );
                :end
            END
           
            RULE event DeviceActivated
                :action
                    if(e.device:shield,
                        e.device:owner:ShieldIntegrity := e.device:owner:LastShieldIntegrity;                      
                        Debug("Activated shield,", E.device, "on", E.device:owner, "( restored last integrity", E.device:owner:LastShieldIntegrity, ")");
                    );
                :end
            END
           
            RULE event DeviceDeactivated
                :action
                    if(e.device:shield,
                        e.device:owner:LastShieldIntegrity := e.device:owner:ShieldIntegrity;
                        Debug("Deactivated shield", E.device, "on", E.device:owner, "with last integrity at", E.device:owner:LastShieldIntegrity);
                    );
                :end
            END

        END

    END
When the shield gets deactivated (manually, per mission script or ship behaviour), it saves the ship's last known shield integrity in an object variable called "LastShieldIntegrity". Upon activating the shield again, this old shield integrity simply gets restored again. The script won't work for ships and/or shields, that aren't present at the start of the mission, though. You have to call EnableActivateEvents manually for each shield device, that gets spawned during the course of the mission - or else the script will simply ignore these additional shields.
Title:
Post by: The Old Dragon on November 23, 2009, 19:50:53
Could either,
a) A  'LongRangeArrived' rule to accomadate any later ships arriving by IP .
or
b) A 'DockOut' rule to cover those that get released from a mothership.

Be added to cover any late additions?

These rules could simply call for the 'In' rule to run again...
Title:
Post by: Arparso on November 23, 2009, 20:41:56
Sure, that'll work. I'm not sure about ships created using CreateShip(), though (like in my little Warfare mod experiment) - I don't think, that command triggers any events per default.
Title:
Post by: Mularac on November 23, 2009, 23:44:28
Probably not, unless you assign a GetSceneObj to those ship.
and a question, wouldn't that overide a previous and general ShieldIntegrity command issued to the ships with a given value? (like the one on SG:WB)
Title:
Post by: Arparso on November 24, 2009, 00:44:49
Quote from: Mularac
Probably not, unless you assign a GetSceneObj to those ship.
GetSceneObj doesn't really interfere with events - it's just a way to store an object reference in a variable, so you can use that object much more easily in your scripts without having to Select it every time. The problem simply is the game not triggering any event when you create a new ship using CreateShip, so the ShieldPreserve machine has no way of knowing about the arrival of the new ship.

Quote from: Mularac
and a question, wouldn't that overide a previous and general ShieldIntegrity command issued to the ships with a given value? (like the one on SG:WB)
I don't quite understand, what you mean. Basically this won't override anything else, but different scripts might conflict with each other on some rare occasions. For example you might have a script automatically activating all inactive shields and another script automatically deactivating all active shields... of course, it's a stupid example, but obviously both these scripts won't work as expected when they are run at the same time.

I'm not really familiar with the Stargate shield script... could you elaborate?
Title:
Post by: Mularac on November 24, 2009, 01:08:08
it's real simple, here's the code (well... a part of it):

Code: [Select]
State chargeshields

Rule event in
name "shield up"
:action
Debug("shieldup");
SelectShips(shieldup, 1);
ExecList(shieldup, S.this:shieldIntegrity:=4500000;);
Delay(0,1,Disable("shield up"),0);
:end
END

Rule event Longrangearrived
:action
E.ship:shieldIntegrity:=4500000;
makefullyknown(e.ship);
:end
END

It basically charges the shields of a ship at the start of a fight or when the ship jumps in.
Title:
Post by: Mularac on November 25, 2009, 00:18:18
you sonova... it actually worked! from where the hell did you get that knowledge of nexus scripting system?!
Title:
Post by: Arparso on November 25, 2009, 00:57:46
Uhm... magic? :P

I guess me currently studying computer science might have something to do with that. But its mostly learning-by-doing while creating my first missions, the Skirmisher or investigating questions from the forum, etc.
Title:
Post by: Mularac on November 25, 2009, 01:23:46
you're studying computer science... what are the odds... me too :P
Title:
Post by: Mularac on December 04, 2009, 21:59:14
there's a bit of a problem there with your code, when I send the "EnableActivateEvents" command and the shields of a ship havent been rised, then the previous shieldintegrity value are overwritten when I actually rise them, as the game detects that since the shields haven't been rised the shield integrity is "0".

So far my only solution has been to had the game inmediately rise the shields, even though there is no ship in sight, but that's only temporary.
Title:
Post by: The Old Dragon on December 04, 2009, 22:33:49
Another option then, maybe, is to manually write the initial value?
This would remove the need to temporarily raise the shields at the start of the mission...
Title:
Post by: Mularac on December 04, 2009, 23:52:55
the initial value?
there's such thing???

On another topic, how do you change the name of a ship when you insert it on a mission? I only get the name that appears on the .sobj file...
Title:
Post by: Arparso on December 05, 2009, 01:28:24
@Mularac:
You'll need to initialize the "LastShieldIntegrity" variable of each ship with a proper value, if you want to have the shields fully loaded after their first activation. Simply change the first rule of my example script above to:
Code: [Select]
           RULE event In
                :action
                    SelectEx(s.shield,
                        EnableActivateEvents(s.this, 1);
                        s.this:owner:LastShieldIntegrity:=100000;            // raise this value, if it's not sufficient for your shields
                        Debug("enabled 'activate' events for shield", s.this, "on", s.this:owner);
                    );
                :end
            END
After starting the mission, the shields won't be up at first, but they should be fully loaded after their first activation. (if not, raise the initial LastShieldIntegrity value even more)

Other question: how do you insert your ship into the mission? If by "CreateShip()" - this command takes the ship's name as 3rd parameter.
Title:
Post by: Mularac on December 05, 2009, 02:37:46
thanks, that did it.

and, no, the ship came from a fleet, added via de addlocation command. (campaign scripting)
I've tried the  *** := uGet("ship_***");, and it worked, because I could use "***" instead of "ship_***" in plenty of other things, but in the mission I get "ship_***" instead of "***"
That is, if I can now get pass the "I crash withouth no apparent reason" thing. I hate it that when I change two things I get four erros that each cost me a couple of hours....
Title:
Post by: The Old Dragon on December 05, 2009, 10:11:00
Welcome to campaign level scripting, if nexus doesn't find a file it needs, then it throws temper tantrums like a spoilt brat!

As for renaming ships, there is a 'rename' command...

Code: [Select]
RenameShip(ship, name);
It renames the ship.

or why not give the ship the name you wish in the .Sobj file? seems to work fine for me...
Title:
Post by: Arparso on December 05, 2009, 12:52:26
Yeah, Nexus error handling mechanic can be summed up by "OMG!!! CRASH!!!"... except when you're in the editor, which gives you pretty useful error messages most of the time. But even the most minor script error will crash the game, no matter how trivial it really is.

Regarding ship names: the most elegant solution would be to create a proper text file containing the proper name for your ship in all the languages you want to cater to. Nexus does it that way in universetextstextsfleets.ini. For example, the Stiletto of the vanilla campaign is named "ship_stiletto" in the .sobj-files - so it's corresponding entry in the fleets.ini file looks like this:
Code: [Select]
TEXT "ship_Stiletto"
0 "Stiletto" $$data "07/23/2004 15:06:45" "" 1
1 "Stiletto" $$data "08/18/2004 09:31:54" "" 1
2 "Stiletto" $$data "06/23/2004 16:44:35" "" 1
3 "Stiletto" $$data "07/23/2004 15:06:45" "" 1
5 "Stiletto" $$data "09/02/2004 16:00:38" "" 1
END
Each line in the text block corresponds to a different language, identified by the starting number (0 = English, 1 = German, 2 = Hungarian, 3 = French, 5 = Italian ... at least I think so). "Stiletto" would be the ship's name for each of these five languages, but you could totally translate each name to each language as you can do with every text entry (like dialogues, for example). You can forget about the $$data stuff and everything after it - probably just remainders of a proprietary tool Mithis used to manage all their text entries.
Title:
Post by: Mularac on December 05, 2009, 13:15:41
oh... thanks, to the both of you. And no Old Dragon, I can't really do that, as I for example have the Angelwing sindrom on one of the ships, it'lll change during one of the missions... so assigning the same name to both ships doesn't seem to be the right thing to do...
And I get the error when I press start campaign, so where do you think the bugger is? episode_1.rules? tacticstypes.ini? some missing entry in one of the text files? (it's not the 1° mission, I've already tested that)

Nevermind, solved it...
Title:
Post by: Mularac on December 10, 2009, 22:24:25
here's a quick one: how do you detect that a wrecked ship has been destroyed? (modification level scripting, not campaign)
Title:
Post by: The Old Dragon on December 10, 2009, 23:39:58
It might be a quick question, but I doubt the answer will be.

I've recently been playing around with wrecks myself (one of the N:TAA scenes is set in a ship graveyard). So far, I've been having problems with manipulating them in the normal ways (selectships,etc) because nexus only 'works' with live ships, though wrecks still count towards the scenes total objects! However, if you assign it a name in the normal way then you can use them in your scripts, it's just damn long-winded manually adding them to lists! But getting back to your question...

Assuming that this is an objective event that your working on (and therefore quite specific in what you're watching), what you could try...

1)  Is to assign the wreck a name.
2)  Using a 'tick' rule, maybe you could keep an eye on the wrecks damage level, something like...

                   
Code: [Select]
If(M.Wreck1:damage=0, localevent(Call something rule));
However, the tick could miss it and crash the scene  :(

3)  There may be a preset 'exploding' rule in the manual, perhaps you could use that with the wrecks name as a condition?

As I've not really needed to know when a wrecks gone nova, all I've got are some theories, but maybe it'll put you on the right path though.
Title:
Post by: Mularac on December 11, 2009, 02:18:39
well, I sorted it out. Sort of. Just prevented that the wreck could be fired upon, thus, you were never capable of destroying it :P
as for your problem:
are you doing some campaign scripting? Because if you are, then you're problem is a real easy one. Instead of giving them a GetSceneObj, you could call them with the uGet("name_of_the_ship") command, and check whatever you need to check.
Title:
Post by: Arparso on December 11, 2009, 02:20:50
Oh, don't use a tick rule for that. Nexus indeed has a special event for exploding ships, called "Exploding" :P

Code: [Select]
           RULE event Exploding
                :action
                    Debug("Oh my god!", E.ship, "is exploding");
                :end
            END

If you only want to watch a particular ship, check if E.ship is the one you wanted to keep an eye on as a :condition like so:

Code: [Select]
           RULE event Exploding
                :condition E.ship = WatchedShip
                :action
                    Debug("Oh my god!", E.ship, "is exploding");
                :end
            END

... or if you want to watch a selected group of ships (you previously added to a list) ...

Code: [Select]
           RULE event Exploding
                :condition InSelection(E.ship, MyListOfWatchedShips)
                :action
                    Debug("Oh my god!", E.ship, "is exploding");
                :end
            END

And btw.: Nexus also "works" with wrecked ships, but you can't use SelectShips() for that, because SelectShips(condition) is nothing different than Select(s.ship & condition)... it even states that in the manual. Since s.ship is only ever true for not-wrecked ships, SelectShips will never ever return a wrecked one. Use plain old Select(s.wreck) for that... ;)
Title:
Post by: The Old Dragon on December 11, 2009, 14:37:20
Ahh, thanks Arparso... another tidbit learned  :thumbup:

@Mularac...

Always doing campaign stuff these days, recently finished the 'general' scenes that the player can visit. Now moving onto background events, this should be fun...
Title:
Post by: Mularac on December 20, 2009, 16:45:29
I got a question, how do you select all the devices belonging to a given set? just like you did with the shields, but with sets. I've managed to do when working with a single device, but when it comes to set it still eludes me... (not a priority, though)
Title:
Post by: The Old Dragon on December 20, 2009, 23:37:06
With the 'InSet' condition is how I normally do it.

Code: [Select]
SelectDevices(1,InSet(S.this,25));
Where the second number dictates the set you're looking for.

If you want to collect them from multiple ships, then you'll need to create a list of those ships first and place the SelectD command within an 'execlist' command.
Title:
Post by: Arparso on December 21, 2009, 00:29:30
Or you can use the plain Select() command, if you want to gather the devices from all ships:

Code: [Select]
Select(1, s.device & InSet(S.this,25));
Title:
Post by: Mularac on December 21, 2009, 02:20:46
great, thanks. Arpaso, I take it that it can also be used in the SelectEx command, right?
EDIT: yep, it can.
Title:
Post by: The Old Dragon on January 02, 2010, 17:06:15
Well, after a little break (been playing Dragon Age) I'm back to working on N:TAA again.

As such I've run into a couple rather annoying bugs.

The first of which is that one of the scenes has a space station that it shouldn't have (belongs in another scene), thing is there's no mention of it except in the files where it's supposed to be. All I can think of at the mo is that both scenes are within the same asteroid field, though I've not seen this before...

The second being more of an annoyance as it doesn't interfere with gameplay. When a strikecraft leaves a hidden ship, the hidden ship comes up as an 'unidentified object' in the tactical display. I can get it to disappear again within a few seconds, but I'd prefer if it doesn't show up at all.Anyone got some different ideas on how to keep it hidden?
Title:
Post by: Mularac on January 02, 2010, 20:31:42
about the first one, how did you set that station, by the solar system editor or using something else?

and as for the second one, I know it's not the best programming, but how about a 0.01 tick rule with the hideship command in it?
Title:
Post by: The Old Dragon on January 03, 2010, 10:05:23
About the 'mystery' station,  in the scene where it's supposed to be I've added it via the 'AddLocation' command as it's held in the Stations.sobj file also included it's 'position'  data in the scene. As for the scene where it's not supposed to be, there's no call that I can find or mention of it anywhere  ?(

With the 'hidden ship', I've included commands to transfer the squadron to it's destination and to hide the launching ship as soon as each one launches. So it should remain hidden at all times.
Title:
Post by: Mularac on January 08, 2010, 04:28:14
A question, is it possible to detect when a fighter wing is completely destroyed? I tried witht the co_devicedestroyed, but it didn't work. Any ideas?
Title:
Post by: Arparso on January 08, 2010, 12:13:52
You can recognize bombers of the same wing by checking for the same launcherWeapon. All it then comes down to is counting the surviving wingmates in the event a bomber has been shot down. If there are none left, the squad obviously has been destroyed.

Try this:

Code: [Select]
// runs for all exploding bombers and checks, if the whole squad has been destroyed
    RULE event Exploding
        condition E.ship:bomber
        :action
            E.BombersInSameSquad := GetFreeSel();            
            Select(E.BombersInSameSquad, S.bomber & S.launcherWeapon = E.ship:launcherWeapon & S.this != E.ship);
            If(AllNumOf(E.BombersInSameSquad) = 0,
                Debug("Squadron destroyed")
            );
        :end
    END

/edit:
Just noticed a problem with the above code: if a bomber wing is currently docking and, lets say, the last one is being shot down while his mates already have docked... then the script above will think the whole squadron has been destroyed, because it doesn't count docked wingmates.

/edit2:
Doh! Even simpler solution: Just check the "count" variable of the launcherWeapon of the exploding bomber - this will give you the remaining amount of bombers in that wing (including the currently exploding one). No need to use stupid selections this time ;)

Code: [Select]
// runs for all exploding bombers and checks, if the whole squad has been destroyed
    RULE event Exploding
        condition E.ship:bomber
        :action
            // count all remaining bombers in bomber wing
            // (this includes the currently exploding bomber!)
            If(E.ship:launcherWeapon:count = 1,
                Debug("Squadron destroyed")
            );
        :end
    END
Title:
Post by: The Old Dragon on January 08, 2010, 20:50:24
Just a quick question, sure I've seen the answer somewhere. Just can't seem to find it now.

How do you select the slowest ship in a group?
Title:
Post by: Mularac on January 08, 2010, 22:20:13
you're right, that sounds oddly familiar to me...

yeah, I know now it's from the skirmisher's AI:

if(AllNumOf(AIFleetL1)>0, m.AITeam_leader:=PickMax(AIFleetL1, 1 / s.this:tGetMaxVelocity()), ChangeState(noTeam1,0)); //slowest ship is AI leader

So, it seems you can do that with the tGetMaxVelocity() command, the exact way this command works seems to elude me... perhaps you can knock more sense out of it :)
Title:
Post by: Arparso on January 08, 2010, 22:54:51
Not that hard to explain, I guess. Let's assume, we've got a bunch of ships selected in MyFleet:

Selecting the fastest ship would be easy:
PickMax(MyFleet, s.this:tGetMaxVelocity());

It's like sorting the list by maximum speed and then picking the fastest one using PickMax. Sadly, there's no PickMin function, so you have to invert the sorting. You could do that by simply negating the maximum speed:
PickMax(MyFleet, -s.this:tGetMaxVelocity());

DeSade (who wrote the Skirmisher's AI) chose to divide 1 by the maximum speed, which also works well:
PickMax(MyFleet, 1/s.this:tGetMaxVelocity())
Title:
Post by: The Old Dragon on January 08, 2010, 23:06:07
Thanks guys, I thought it was along those lines, just didn't know how to factor in the speed condition.
Title:
Post by: Mularac on February 10, 2010, 21:29:02
Is is there a way to mimic a "for" command in the BlackRuler scriptim system? I desperately need one for the piece of coding I'm working on.
here's the original idea, it's rather simple... and easy, if I could just use a bloody for...:
I need to collect each weapon in a separete variable, like this, for instance: e.norm_weap1, e.heavy_weap3 and such. I'm dealing with both an unknown ammount of weapons (from 0 to 7) and an unknown type of devicetype for each set. My only information is that the ships carries 2 slots for normal weapons, 2 for heavy, 2 specials and one for artillery (for now it's just an other heavy, but I'll find the way to set it apart). Don't mind the flaks.
Title:
Post by: Arparso on February 10, 2010, 22:03:46
Nexus doesn't know a for-loop, but it knows while-loops and both are pretty much interchangeable. For example:

Code: [Select]
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Index is {0}", i);
}

... might be written in Nexus scripting as:

Code: [Select]
E.index := 0;
while(E.index < 10,
Debug("Index is", E.index);
E.index := E.index + 1;
);

I'm not sure, if you need it here, though. Why do you need the weapons in seperate variables? Why not just put them in a selection / in an array?
Title:
Post by: Mularac on February 10, 2010, 22:45:49
I need it because in one mission the player has to choose wich weapon it wants to fix or not, in a dialog. And each dialog is connected to the weapon in question, and that weapon can only be connected to the game via a variable.
Title:
Post by: Mularac on February 13, 2010, 22:04:29
I've got a question.. for the past few days I've been trying to select two different devicetypes (supp_bsgen and supp_res) with the selectdevices rules, so that they may be activated with the enbladevice command. (and no, enabling them with two separate SelectDevices commands doesn't count). Or, in other words, I need to put those devices into a variable useful for the EnableDevice command.
Somehow, writing
Code: [Select]
SelectDevices(1, m.*ship*, s.this:Devtype=#supp_BsGen & s.this:Devtype=#supp_res);
doesn't work, and writing a list and using the additem command doesn't work either... here's the rule I'm working with atm:

Code: [Select]
SelectDevices(1, m.ac,  InSet(s.this,66));
Execlist(1,
debug(s.this);
dev:=s.this;
Debug(dev);
);
SelectDevices(2, m.ac, InSet(s.this,65));
Execlist(2,
debug(s.this);
addItem(dev, s.this);
Debug(dev);
);
Debug("----------------The devices are:", dev);
E.time:=250;
m.pgen:=1;
ChangeState(countdown, dev:=dev; E.time:=p.time);


In the countdown state all that is there is a "EnableDevice(dev, 1);"
Title:
Post by: The Old Dragon on February 13, 2010, 23:14:09
Try this as your selection instead...

Code: [Select]
SelectDevices(1, m.*ship*, s.this:Devtype=#supp_BsGen | s.this:Devtype=#supp_res);
Your original condition is asking for an item that is both a supp_BsGen and a supp_res. Clearly an imposibility.
This new line asks for an item that is either of those devices.
Title:
Post by: Mularac on February 14, 2010, 00:00:21
you're right, that was stupid from my end. But that way wouldn't work either, as the rule will settle with the first one of those two that is true, so the output would only be one device, not the both of them.
Title:
Post by: Arparso on February 14, 2010, 00:57:48
How so? SelectDevices selects all devices matching its criteria, not just a single one, so Dragon's line will make selection 1 include all devices of types #supp_BsGen and #supp_res on that particular ship.
Title:
Post by: Mularac on February 14, 2010, 01:50:58
well... with the debug commands I tracked the variables down to this:

This is the code:
Code: [Select]
SelectDevices(1, m.ac,  InSet(s.this,66)| InSet(s.this,42));
Execlist(1,
debug("1",s.this);
dev:=s.this;
Debug("2",dev);
);

Debug("----------------The devices are:", dev);

and this is what the console gave me:

Code: [Select]
       1  shield/HybridShieldMk3
        2  shield/HybridShieldMk3
        1  device/supp_res
        2  device/supp_res
        ----------------The devices are:  device/supp_res

funny, eh? The selectdevices did indeed select both ones, I was wrong about that one too, but when the "dev" variable left the execlist command it only stayed with the first one, so when I tried it only one of the devices got enabled, hence my previous post. Most peculiar indeed.
Title:
Post by: The Old Dragon on February 14, 2010, 10:12:08
The reason that Nexus is only giving you the one debug line  instead of three is because the last 'debug' command is outside of the 'execlist' command.

 If you were to place it within the  parenthesis  (you know, the '()' that surround this little explanation ) then the debug line would fire for each device and as in a circumstance like this, Nexus collects up the various items that fulfill the criteria and puts them in a list. Then it'll take the first item and run through any commands in the execlist that are applicable and when it's done, Nexus puts down item one and picks up item two, executes the commands,puts it down,item three, etc.  You get the idea.

Then it'll proceed with the rest of the command. But as the 'dev' variable can only store one value, only the last run through of the previous 'execlist' command will be recorded.

So this is how I believe it should have read...

Code: [Select]
SelectDevices(1, m.ac,  InSet(s.this,66)| InSet(s.this,42));
Execlist(1,
debug("1",s.this);
dev:=s.this;
Debug("2",dev);
        Debug("----------------The devices are:", dev);
);
Title:
Post by: Arparso on February 14, 2010, 11:27:27
... although debug("1",s.this), Debug("2",dev) and Debug("----------------The devices are:", dev) all do the same, more or less ;)

Do you want to enable both devices at the same time? Then the following should suffice:

Code: [Select]
SelectEx(s.device & s.owner=M.*ship* & (InSet(s.this,66)| InSet(s.this,42)),
EnableDevice(s.this, 1);
);

You can leave out the s.owner=M.*ship* part, if you want to enable all such devices on all ships simultaneously or replace it with s.owner:race=#race_whoever, if you're going to enable all such devices only for ships of a specific race.
Title:
Post by: Mularac on February 14, 2010, 16:46:15
yes, I do want to enable them, but not when the devices are selected. That code is part of a nice 647 line machine that handles a way to fix a ship's devices (it's one mission exculsive, that's way I set the "ship" parameter in the SelectDevices as only one scene object.
That machine works in a similar way as your warfare mod does it (that's from where I took the idea) a series of dialogs appear, you select the device you want to fix, that goes to a specific rule where the device in question is selected and then a timer appears, and when that timer is done the device is "fixed" (enabled).
The mechanics are: each dialog is connected to their special rule, where the device is selected and the time is set. And then the state is change with this information:

Code: [Select]
ChangeState(countdown, dev:=dev; E.time:=p.time);

that is common to pretty much all devices, where dev is the device and e.time is the time that would take to repair it. In the state "countdown", I give a StartCountdown rule with the time in question and when that is done a rule appears that pretty much all it does is to enable "dev" via the enabledevice command, and then returns to the previous state, so I can't have them enable in the same rule.
As for what old dragon said: yeah, I know that, and the reason while all of them were the same was for the sake of testing what the variable would look like in an out the execlist. However, placing the "changestate" rule inside the execlist wouldn't work either, only one of the devices got fixed.
Well... since there's only one device on the list that actually needs two devices to be fixed I'm gonna have to go with 'Plan B'; a small "if" command in the last rule that would detect that if dev belongs to that devices set, then it must also enable the other device I needed.
Title:
Post by: The Old Dragon on February 14, 2010, 18:30:05
How about adding the selected devices into a seperate list via the 'AddItem' command? And using the dev variable to select a command that would 'ExecList' the selected devices?

So the first rule of the new state would be like...

Code: [Select]
RULE       event In
                 :action
                             ChooseFirst(
                                       dev=1,
                                                  LocalEvent(RuleOne);
                                        ,
                                        dev=2,
                                                  LocalEvent(*****************);
                              ):
                  :end
END
RULE       event RuleOne
               :action
                            ExecList(1,
                                             //script whatever to happen here.
                            );
                :end
END

From those local events you can then dictate what will happen.  Is this any use?
Title:
Post by: Mularac on February 14, 2010, 19:32:07
I... don't think I understand you.
Here, I'll post a simplified version of my machine (not the 600 lines, as there's a lot of repetetive code I couldn't avoid, but it is still some good 200 lines... perhaps they'll help me make my point):

Code: [Select]
Machine "Fixing_Devices"

State Setup

Rule event in
:action
something_is_inside:=1;  //this is used to check if all the devices in a given set (military, non-military) are done or not.
if(m.first_time=0,
/*Here I divided the weapons, no use to show this...*/
m.first_time:=1;
LocalEvent(MainMenu);
);
:end
END

Rule event Selected
Condition E.ship=M.ac&m.Dialog_running!=1&Timer_on=0
:action
LocalEvent(mainmenu);
:end
END

Rule event MainMenu
:action
M.Dialog_running:=1;
ChooseFirst(
m.No_More_N_Devs = 1 & m.No_More_M_Devs = 1 & No_More_Devs = 0,
No_more_devs:=1;
Dialog("No_More_Devs",0,0);  //this dialog is show in case there're no more devices to fix
, m.No_More_N_Devs = 1 & no_more_devs = 0,
Dialog("First_Choice_military",0,0);  //this is the tree of non-military is all done
, m.No_More_M_Devs = 1 & no_more_devs = 0,
Dialog("First_Choice_no_military",0,0);  //idem but with the military done
, m.No_More_N_Devs = 0 & m.No_More_M_Devs = 0,
Dialog("First_Choice",0,0);   //when they're all incomplete.
);
:end
END

Rule event Cycle_normal
:action
m.military_cycle:=0;
ChooseFirst(
m.eng = 1 | m.eng_sec =1 & m.nav = 1 & m.sens = 1 & m.pgen = 1 & m.hyp = 0 & m.hyp_cycle = 0,
something_is_inside:=1;
Deletependingdialogs(1);
Dialog("fixing_hyp",0,0);  //this is the ultimate goal, repair the hyperdrive, and to do so you have to fix all of the above (engine, nav, sensors and pgen)
M.Dialog_running:=1;
, m.eng = 0 & m.eng_cycle = 0,
something_is_inside:=1;
Deletependingdialogs(1);
Dialog("fixing_eng",0,0);
M.Dialog_running:=1;
/*...*/
, m.pgen = 0 & m.pgen_cycle = 0,  //this is the part I'm interested in, the power generator
something_is_inside:=1;
Deletependingdialogs(1);
Dialog("fixing_pgen",0,0);
M.Dialog_running:=1;
/*...*/
, m.blank = 0,  //in case the player didn't choose anything
Deletependingdialogs(1);
M.Dialog_running:=1;
if(something_is_inside=1,
Dialog("blank_choice",0,0);
,
Dialog("No_More_N_Devs",0,0);
m.No_More_N_Devs:=1;
);
);
:end
END

Rule event Cycle_military
:action
m.military_cycle:=1;
ChooseFirst(
/* Pretty much the same as above, but with weapons and weapons generators */
, m.blank = 0,
Deletependingdialogs(1);
M.Dialog_running:=1;
if(something_is_inside=1,
Dialog("blank_choice",0,0);
,
Dialog("No_More_M_Devs",0,0);
m.No_More_M_Devs:=1;
);
);
:end
END

Rule event Re_Start
:action
LocalEvent(blanc);
LocalEvent(MainMenu);
:end
END

Rule event Blanc
:action
something_is_inside:=1;
M.Dialog_running:=0;
m.eng_cycle:=0;
m.pgen_cycle:=0; //these are the cycle variables, and in here we set them back to 0, as the whole cycle is re-starting.
:end
END

/* and all of these are the output of the player choosing to fix these devices */

Rule event eng
:action
SelectDevices(1, m.ac, s.this:devtype=#eng_b304);
Execlist(1,dev:=s.this);
M.eng:=1;
Debug("e.dev is", e.dev);
ChangeState(countdown, dev:=dev; E.time:=110);
:end
END

Rule event eng_sec
:action
SelectDevices(1, m.ac, s.this:devtype=#eng_b304); //#eng_b304_sec);
Execlist(1, dev:=s.this);
m.eng_sec:=1;
ChangeState(countdown, dev:=dev; E.time:=55;);
:end
END

/*...*/

Rule event pgen  ///this is the polemic rule, still not working...
:action
E.time:=250;
SelectDevices(1, m.ac,  InSet(s.this,66)| InSet(s.this,42));
Execlist(1,
debug("1",s.this);
Debug("----------------The devices are:", s.this);
ChangeState(countdown, dev:=s.this; E.time:=p.time);
);

:end
END

/*this is the cycle part, the one that enables the rolling of the dialog-options. Basically this works this way, when a dialog is called in the "cycle_***" rule, three options appear: "fix it","next" and "nothing right now", the fix it relates to the above rules, the next to the ones below and the nothing right now to the "blanc" rule. */

/*...*/

Rule event eng_Cycle
:action
//this event means that player didn't choose to repair this device, so we must clear it from the cycle list:
m.eng_cycle:=1;
LocalEvent(Cycle_normal);
:end
END

Rule event eng_sec_cycle
:action
//this event means that player didn't choose to repair this device, so we must clear it from the cycle list:
m.eng_sec_cycle:=1;
LocalEvent(Cycle_normal);
:end
END

/*...*/

Rule event pgen_cycle
:action
//this event means that player didn't choose to repair this device, so we must clear it from the cycle list:
m.pgen_cycle:=1;
LocalEvent(Cycle_normal);
:end
END

Rule event Fix_cycle  //this event is only fired if the dialog with the dialog with the options times out.
:action
if(m.military_cycle = 1,
Debug(m.military_cycle);
Delay(0,0.1,LocalEvent(cycle_military);,0);
,
Debug(m.military_cycle);
Delay(0,0.1,LocalEvent(cycle_normal);,0);
);
:end
END
END

State Countdown
Rule event in
:action
//in here we reset the cycle of all devices
M.Dialog_running:=0;
m.eng_cycle:=0;
/*...*/
m.pgen_cycle:=0;
/*...*/
StartCountDown(e.time, Repair);
m.fixing:=1;
Debug("dev is",dev);
:end
END

Rule event Repair
:action
Debug("event Repair", dev);
if(dev!=0 & engineering = 0,
EnableDevice(dev,1);
Debug("repairing", dev);
,
if( engineering = 1,
m.engineering:=1;
);
);
m.fixing:=0;
ChangeState(setup,0);
:end
END
END
END
Title:
Post by: The Old Dragon on February 14, 2010, 21:13:40
I've had a tinker and sent you an email Mularac, fingers crossed it helps.

What I've done is add this line...

Code: [Select]
AddItem(TBR,S.this);
to the execlist section of the 'PGen' rule and set the 'dev' value of the same rule to 999. I also modified the 'Repair' rule to read...

Code: [Select]
Rule event Repair
:action
Debug("event Repair", dev);
if(dev!=0 & engineering = 0 & dev!=999,
EnableDevice(dev,1);
Debug("repairing", dev);
,
if( engineering = 1,
m.engineering:=1;
);
);

If(dev=999 & engineering = 0,
ExecList(TBR,
EnableDevice(s.this,1);
Debug("repairing", s.this);
,
if( engineering = 1,
m.engineering:=1;
);
);
);
m.fixing:=0;
ChangeState(setup,0);
:end
END
Title:
Post by: Mularac on February 16, 2010, 00:51:58
A question: Anyone know how the devs managed to detect when a ship was disabled and add that to the winning conditions (instead of wrecking it)?
Title:
Post by: Arparso on February 16, 2010, 11:37:18
Don't know how the devs did it, but it's certainly possible to detect disabled ships. The resulting script depends on your exact criteria of what disabling a ship actually means... one variant could be:

Code: [Select]
RULE event CO_DeviceDestroyed
:action
E.WorkingCriticalDevices := GetFreeSel();
Select(E.WorkingCriticalDevices, S.device & S.owner=E.ship & Not(S.destroyed) & (S.shield | S.Weapon | S.main | S.secondary | S.combat | S.stealth));
If(AllNumOf(E.WorkingCriticalDevices) = 0,
Debug(E.ship, "was disabled");
);
:end
END

After a device has been permanently destroyed the script checks, if there are any shields, weapons or engines left for the ship in question.
Title:
Post by: Mularac on February 16, 2010, 16:28:41
Great, thanks. It's funny, because I went trought the vanilla missions and couldn't find a thing....
Title:
Post by: Mularac on February 25, 2010, 18:33:49
hey, anybody knows how to escape the " " in a dialog file? (for example, to write a dialog that involves, inside the text the use of the " ")
Title:
Post by: Arparso on February 25, 2010, 22:16:22
I have no idea. If " doesn't work, use single quotation marks instead, I suppose.
Title:
Post by: The Old Dragon on February 25, 2010, 23:55:04
Use two single quotation marks to mimic the character. It may not look quite right in the actual dialog.ini file, but in the game you'd never tell it's two singles.
Title:
Post by: Mularac on March 02, 2010, 01:10:18
A simple question whose answer I'm already fearing: Is it possible to keep missiles on route to their target to not be vaporized when their mothership is destroyed/wrecked (can't really remember which one is it...)?
Title:
Post by: Mularac on March 06, 2010, 14:56:35
hey, do you know if it is possible to determine a ship's relative size?
and on other factor, how does the "weight" variables work?
Title:
Post by: Arparso on March 07, 2010, 21:40:54
Quote
hey, do you know if it is possible to determine a ship's relative size?
I only know the radius variable, which gives the radius of an invisible sphere enclosing the whole ship... it's a good approximation for the overall size of the ship, if the ship's design isn't too exotic.

Quote
and on other factor, how does the "weight" variables work?
Which weight variables?  ?(
Title:
Post by: Mularac on March 07, 2010, 22:06:20
Quote
>   Choose(weight1, command1, weight2, command2, …., weightN, commandN);
It chooses randomly from N pieces of possibilities, according to the weight (’weight1’ .. ’weightN’). If every weight is 0, than it doesn’t do anything; implicitly, if only one weight is bigger than 0, than it will choose that line – with this you can virtually implement the SWITCH-CASE command that is known from C. ’Command’ here and everywhere else can contain several script commands that are separated by semicolons.

Quote
>   SelWeightMul(list, mul, condition);
Where the ’condition’ returns with 1, it multiplies their weight by ’mul’.

etc...
Title:
Post by: Arparso on March 07, 2010, 22:26:03
Quote
Choose (weight1, command1, weight2, command2, …., weightN, commandN);

It chooses randomly from N pieces of possibilities, according to the weight (’weight1’ .. ’weightN’). If every weight is 0, than it doesn’t do anything; implicitly, if only one weight is bigger than 0, than it will choose that line
The weight basically represents the probability, that the following command(s) will get chosen by the game to get executed. Quick example:

Code: [Select]
Choose(
10,
Debug("First choice"),
5,
Debug("Second choice")
);
In this code snippet, it is 2x more likely, that the "First choice" gets executed instead of the "Second choice". The higher the weight, the more likely it is for the corresponding command(s) to get chosen and thus executed. It is still a random choice, which command gets executed - you just have some influence on their likeliness to happen.

Other weighted commands work similarly.
Title:
Post by: Hyperion5 on April 03, 2010, 17:18:27
hmm, looking through all the problems and fixes here, really good ideas btw, i notice most are mostly scripting. has anyone tried alternate devices? quick mod from energy cell pobably buggy, but just for concept:

Code: [Select]
DEVICETYPE
Name "Shield_Capacitor0"
Category 4 //changed to 'shield' category, now governed by the ENERGYSYSTEM_SHIELD subsystem
Sets 24 60 62 66 100 126 ; //same device sets, still fits in energy cell hardpoint
Automatic //Automatic, stays on, so it's reserve count remains
MaxReserve 20000 //ADDs to Max reserve, stores until device deactivates (automatic device here, so until disabled)
Scanned 140
Hpmax 1100
RepairHP 10
Available
InstallRP 6
Info_Category ""
Info_Size ""
Info_Efficiency 6
Info_Emission 0
DEVICETYPE

In fact, one could probably re make the shield system as different parts with the right work: shield_cat1: Generators shield_cat2: Capacitors, shield_cat3: Projectors

Just a concept, but the current problem with that is shields are set as a universal value (the actual percent set in tacticsbase.ini, but the actual rule is in execlist.ini) It seems set to activate once a ships collective shield once energy reaches a set percentage so an actual shield capacitor currently wouldn't work too well for when shields have to drop.

you could check my thread (Modifications >>The ExecList?) i'm looking for help finding commands in that file.
Title:
Post by: The Old Dragon on April 04, 2010, 12:39:27
Just a quick question... does anyone know how to 'de-weaponise' the techscanner?  
At the moment, as soon as you scan something, it's classed as an enemy because you've 'fired' at it. To me this really kind of limits its use as a data recovery tool due to this outcome.
Title:
Post by: GeoModder on April 04, 2010, 23:01:14
Can't you rescript it so that 'firing' the scanner makes an ally of the 'targeted' object under certain conditions? Like when engines are off or weapons not activated/loaded?
Title:
Post by: Mularac on April 04, 2010, 23:57:45
you can't 'de-weaponise'  a weapon, but I think there might a small workarround. Just change the relation back to 'neutral' when the scanner "fires" (using the Fired event) or better even when the ship is 'hit' (can't remember the exact rule that you used there... but I'm possitive there was one). With a bit of luck, it won't be noticed by the player...
Title:
Post by: Mularac on April 22, 2010, 02:13:05
Got a small question, people: is it there a way to have a ship fire a missile and if that ship get's destroyed the missile won't (if it is still travelling to the target)?
Title:
Post by: Arparso on April 22, 2010, 22:17:17
Good question. Sadly I wouldn't know how to do that. :(
Title:
Post by: jstubbles on April 24, 2010, 20:50:18
On the subject of missiles, does anybody know if you can prevent missiles from flying away from ships that about to explode? When a ship is in it's "final time" phase, my missiles are flying away from it, then swoop back in on the next target, once the "danger" is gone.... so annoying.
Title:
Post by: jstubbles on April 26, 2010, 04:37:30
On top of my previous issue, I also seem to be having a problem when I use the same ship to battle between two different races. In this case, a cylon basestar. If I give civ_player a basestar and try to attack the basestar using the quick-combat buttons like "destroy hull" - nothing happens at all. I have to manually select and fire all weapons against the ship. Even then, it sometimes behaves irrationally, sometimes not firing at all even then.

Any ideas????
Title:
Post by: Mularac on April 29, 2010, 01:27:02
Not atm, sorry. But I'll look into it.
As we're on the subject of missiles, does anyone know if it's possible to get the absolute co-ordinates of the point of impact? (highly unlikely. But I just had to ask)
Title:
Post by: The Old Dragon on April 29, 2010, 19:47:54
Try this, it worked on my test range...

Code: [Select]
RULE event Exploded

condition E.ship:class=#cls_missile

:action

       //Record the location data for the explosion...

EposX:=E.ship:PositionX;
EposY:=E.ship:PositionY;
EposZ:=E.ship:PositionZ;

                        //And tell what is is...

Debug("X Coordinate = ",EPosX);
Debug("Y Coordinate = ",EPosY);
Debug("Z Coordinate = ",EPosZ);

:end //end action

END //end rule

Gave me valid data whenever a missile struck home  :)
Title:
Post by: jstubbles on May 02, 2010, 20:47:40
I'm having an issue right now where I'll tell a ship to engage a target, then the weapons power up part way, then stop. They do that over and over again, even though they are well within combat range of the weapon :( they eventually fire when they get even closer, but the AI fires long before my own craft would.

Their hitchancecat settings encompass both the combat and artillery range settings, but they still keep resetting each time, it's really odd. If I set them to manually fire, they'll fire without a problem
Title:
Post by: Mularac on May 03, 2010, 01:41:02
Are you talking about long-distance weapons? try setting (if you haven't already) their sets to the ones corresponding to an artillery weapon: Sets 2 4 30 100 31 (or 32) 117 ;
Title:
Post by: jstubbles on May 04, 2010, 04:20:58
They're combat weapons, not artillery weapons. In this case, they're missiles, which I'm not using as artillery. Problem is, if I give them a hitchange cat that only has settings for range 1, I cannot fire at range 2 (obviously), but the AI CAN fire at range 2 and I can do it if I manually fire them, which makes no sense at all.

Another funny issue I'm having right now is with the missile engines. For some reason, if I set the engine velocity factor to a value higher than 60, it makes both the flare and strip PULSE - even though I have pulsefactor set to 0 wherever possible.
Title:
Post by: Mularac on May 04, 2010, 23:15:34
Well, just to ask: when you say that you're only giving a hitchance cat for only 1, you meant that you left the other places as 0?

Guys, I've an interesting problem that's been keeping me for several hours...
In one of my missions I'm having the camera follow the trajectory of a missile as it heads towards a ship and then impacts on it, and what I've been trying to achieve is to move the camera to where the camboatview() cam was last at, the impact zone. My aim is to have a seamingless transition between that cam and the regular one (this is done in cinema mode. That's why I asked you if you could obtain the co-ordenates of a missile before it impacts the ship)

however, this is very tough since the only point of reference is the co-ordinates of the missile as it explodes, and you can't obtain it's co-ordinates a sec before (I know, a tick rule, but that's a bit too risky).
Using the ship where it collides as the 2 reference is the closest I've got, but it's far from ideal...

so... ideas?


EDIT: Man, I love this site.... solved :P
The tick rule was the answer, after all. It saved the missile postions as long as it was alive, every sec. And then, using the exploded rule (thanks Old Dragon) used a camMoveTo command, using the last known position of the missile from the tick rule as the "from" co-ordinates, and then I used the co-ordinates that the exploded rule gave to me as the "to", and using a handy explotion to shake the screen a bit and soften the transtion, worked like a charm.

EDIT: Either way, I have an other issue, how did you create a wreckyard again? I tried setting the wreck ships as asteroids, but that's far from ideal. And if I just leave them as objects  and then "wreck" them with behaviour:=2, the game crashes due to too many ships (currently have about 30 wrecks :P)
So how did you do that again, Old Dragon, if I may ask?
Title:
Post by: The Old Dragon on May 05, 2010, 00:15:00
Mine's the 'far from ideal' approach I'm afraid  :(

What I've done is to damage the ships I want to be wrecks (about 60 to 75 percent) and then turn them into 'asteroids' with 'Behaviour:=4;' command.

With that level of damage, the 'wrecks' yaw & roll with all the burn marks just as if you'd shot them all up yourself. But anymore damage than that and they won't respond to the command to change!
Title:
Post by: Mularac on May 09, 2010, 21:17:34
Uhm... I'm sorry, but that didn't work out either... I still get the tairace.cpp (too many ships) error...
Title:
Post by: The Old Dragon on May 10, 2010, 14:25:53
Hmmm, not too sure then...

How many wrecks are you trying to create?

If you wish to, send me the relevant files and I'll see if I can spot something.
Title:
Post by: Mularac on May 10, 2010, 21:19:36
better than that, could you write an small example of what you did?
Title:
Post by: The Old Dragon on May 11, 2010, 08:57:45
Certainly can. This is an excerpt from the actual rule of the campaign edition mission that does the work, as you can see, there really isn't much to it...

Code: [Select]
//List the ships we want to be wrecked...

SWrecks:=GetfreeSel();
SelectShips(SWrecks,S.race=#race_Wreck);
ExecList(SWrecks,

    //And make them damaged.

    S.this:Damage:=Rnd(60,75);

    //And turn them into asteroids...

    S.this:Behaviour:=4;

);
Title:
Post by: Mularac on May 11, 2010, 20:37:52
odd... that's pretty similar of what I did... (well, almost identical, in fact...) how many wrecks did you place?
Title:
Post by: The Old Dragon on May 11, 2010, 23:46:45
Erm... about nineteen or twenty.
It's also worth mentioning that when that particular area is loaded, they're the only ships in the area to begin with, apart from the player that is. Any other objects that count towards the ship total are to be added by random(ish) scripts.

Could it be that you're trying to place all the ships/objects in the scene in one go?  And therefore exceeding the game limit?
Title:
Post by: Mularac on May 12, 2010, 16:27:54
yeah... that's clearly it. I have about 40 or so wrecks flying arround :P
Title:
Post by: Arparso on May 12, 2010, 23:45:06
The ship limit is about 28, isn't it?

Anyway, there actually is a way you can make any ship behave like an asteroid and not contribute to the ship limit right from the start. Copy & Paste™ the following snippet to the ENTITIES block at the bottom of your .mission file:

Code: [Select]
SHIP
Name "Ast.01.003"
Class #my_shipclass
Behaviour 4
Position 4934.08 -4970.09 4627.69
Orientation 8.22877 41.7865 -14.8206
END

Of course, replace the class, position and orientation as needed, preferably using the mission editor for both position and orientation unless you enjoy entering lots of numbers by hand ;)

You can use any shipclass this way, no matter if it's an asteroid, battleship or escape pod. They don't contribute to the amount of ships in the scene, so the game won't crash no matter how many of them you add (unless we're talking thousands, I guess).
Title:
Post by: The Old Dragon on May 12, 2010, 23:53:04
Hey Mularac,

May have a solution for you, unfortunately it does mean you've got some work to do.

The first version is the simple, no frills approach. What you need to do locate your 'wrecks' in the entities section (if you're in a modmission or in the .sobj files for campaigns) and do some editing...

1) Remove the 'race' entry.
2) Change the 'shiptype' to its 'class'.
3) Add the entry "Behaviour 4"

The ship/wreck shouldn't now count towards the ship total. On the plus side, you should now have your graveyard. Downside... the 'wrecks' will now just sit there, no rolling or damage and not particularly realistic.

Now my second version will look better (hopefully) but requires a bit more work.

First of all, do the above steps, then add this machine to your mission file...

Code: [Select]
MACHINE "Wrecker"

STATE Default

RULE event In

:action

//You'll need to list name and list any ship you want to be a wreck in here...

*******:=GetSceneObj("*******");
//(Repeat for each)

Wrecks:=GetFreeSel();
AddItem(Wrecks,*******);

//And call the second half

LocalEvent(Alter);

:END //end action

END //end rule

RULE event Alter

:action
//Pick and alter 'wreck'.

M.Change:=Pick(Wrecks);
M.Change:behaviour:=0;
M.Change:damage:=65;
M.Change:Behaviour:=4;

//Rinse and repeat if required...

RemoveItem(Wrecks,M.Change);
M.Change:=0;
If(AllNumOf(Wrecks)>0,LocalEvent(Alter));

:end //end action

END //end rule

END //end state

END //end machine

Now you'll need to fil in the first rule. Each wreck will need to be named and then manually added to the list I'm afraid. I did look into other ways of selecting them, but for one reason or another, they ended up as duds, so it's time to start typing.

My missions have a three to five second 'fade in' period (normally), so if the machine is triggered  to run straight away then the player will be none the wiser.

EDIT:

Just my luck, I start answering a post and someone beats me to it, lol  :D
Title:
Post by: Mularac on May 13, 2010, 00:35:06
Arparso: Yes I know, I did that from the start (I in fact used the asteroid generator of the mission editor ranging from 3 or 4 shipclass and then I replaced those with my shipclases), I was looking for something better.
Old Dragon: Thanks a lot, I'll look into it when I have some time.
Title:
Post by: Arparso on May 13, 2010, 19:32:47
I've made a few modifications to Old Dragons script to make it just a bit more flexible. Your typical shipwreck should look like this in the mission file:

Code: [Select]
SHIP
Name "Wreck1"
Class #my_shipclass
Race #race_Wrecks
Behaviour 4
Position 4934.08 -4970.09 4627.69
Orientation 8.22877 41.7865 -14.8206
END

It's important to define both a race and behaviour 4. If you leave out the behavior, the wreck will initially contribute to the ship limit and the game will crash, if there are too many. You won't even get to your SceneInit rule to change the behaviour, because the game will crash way before that.

The race is important to make selecting your wrecks easier and also to disable the default ship animation including blinking lights. For some reason I couldn't disable that on raceless ships... and a wreck with blinking position lights, rotating sections or simply glowing "windows" doesn't look much like a wreck. The downside is: as long as a race is specified for that wreck, you can't enable the animation again, which you might want to do on certain special wrecks the player is supposed to have a look at or something. But that's probably not the general case, so for all "normal" wrecks a race works just fine. Probably stick to a special "wreck race", so you don't accidently wreck the wrong ships.

Second part is Old Dragon's slightly modified machine:

Code: [Select]
MACHINE "Wrecker"

STATE Default
RULE event In
:action
// select all wrecks
Wrecks:=GetFreeSel();
Select(Wrecks, S.race = #race_Wrecks & S.behaviour = 4);

If(AllNumOf(Wrecks) > 0,
// make all wrecks visible to the player (and everyone else)
ExecList(Wrecks,
MakeFullyKnown(s.this);
FreezeReconState(s.this, 1);
);
// make each wreck "float" in space
LocalEvent(MakeFloat);
,
// leave state, if there were no wrecks at all
LeaveState();
);
:end
END

RULE event MakeFloat
:action
// randomly pick a wreck
E.Wreck := Pick(Wrecks);
// temporarely make it a normal ship and apply some damage
E.Wreck:behaviour := 0;
E.Wreck:damage := 65;
// make it a wreck again
E.Wreck:Behaviour:=4;

// remove current wreck from the list
RemoveItem(Wrecks,E.Wreck);
E.Wreck:=0;
// repeat above for all remaining wrecks and leave current state, if done
If(AllNumOf(Wrecks) > 0,
LocalEvent(MakeFloat);
,
LeaveState();
);
:end
END

END

END //end machine "Wrecker"

Selecting the wrecks is now a breeze as you just look for the "wreck race" and "behaviour 4" setting. Strangely, wrecks with a race won't be visible to the player immediately, so I added the MakeFullyKnown/FreezeReconState bit for every wreck. The rest of the machine is more or less the same, except for two changes:I had a quick test mission with a hundred wrecked Hecate-class destroyers in my FreeSpace mod, which worked really well. Even perfomance wasn't an issue with all these huge ships, probably because the 100+ blink lights on each ship weren't active and no AI was needed for them.
Title:
Post by: Arparso on May 13, 2010, 20:07:08
Okay, small addendum:

The script somewhat fails, if you've got more than 256 wrecks. I tried it with 1000 and apart from the bad performance, quite a lot of the wrecks didn't float like they actually should. It turns out, they weren't picked up by the script, because the wreck list only selected the first 256 wrecks. Trying to raise the list's capacity using Dim(list, size) crashed the game for values above 256, so it seems Nexus only supports lists/selections with up to 256 items.

What a bummer... :(
Title:
Post by: The Old Dragon on May 27, 2010, 14:42:59
Little question, I'm trying to select all ships in the scene except the players and any possible stations/ platforms, etc. This is my current line...

Code: [Select]
SelectShips(MainList,Not(S.race=#race_Player)&HasDevType(S.this,S.Engine));
It all works exept for the 'S.Engine' part (I'm using the engines as a filter 'cause that's the one thing that a stationary object shouldn't require). Anyone got an idea on how to get the last part working?
Title:
Post by: Mularac on May 28, 2010, 01:19:00
Did you try using inSet instead of s.engine? (sorry, I can't try anything right now, I'm writing from my linux partition)
Also, if that doesn't work a much uglier way could be this:

Code: [Select]
selectShips(mainList, s.this:race!=#race_player);  //select all the non-player ships
execlist(mainList,
selectDevices(1, s.this, InSet(s.this, 50)); //put in the list 1 all the devices that fall under the set 50 (engines)
If(AllNumOf(1)!=0, removeItem(mainList, s.this)); //and if that list isn't empty then remove that ship from the mainList (because it has at least one engine)
);

Sorry I didn't test... but it may work. And it's ugly as hell. So you should just wait to have Arparso tell you the way it's done :P
Title:
Post by: The Old Dragon on May 28, 2010, 01:30:51
Hi there Mularac,

I was kinda hoping to avoid sets if possible, trying to keep this script as independant as possible. If anyone modifies/creates their tactictypes then the script won't work too well (assuming that I can get it working to begin with  that is :P ).

But I'll keep that in mind  :)
Title:
Post by: Mularac on May 28, 2010, 02:33:23
But the engines are to be placed on the 50 set, otherwise it won't work well at all, specially in campaign scripting.
Title:
Post by: Arparso on May 28, 2010, 04:00:30
Instead of checking for Inset(), you could always replace that with S.Engine instead:

Code: [Select]
SelectShips(MainList, S.Race!=#race_player);  //select all the non-player ships
execlist(MainList,
E.Engines := GetFreeSel();
E.EngineCount := SelectDevices(E.Engines, S.This, S.Engine); //put in the list 1 all the devices that fall under the set 50 (engines)
If(E.EngineCount > 0, removeItem(MainList, s.this)); //and if that list isn't empty then remove that ship from the mainList (because it has at least one engine)
DeleteSelect(E.Engines);
);
Title:
Post by: The Old Dragon on May 28, 2010, 08:48:13
@ Mularac,

Hmmm, there's something I wasn't aware of :)

Thanks guys  :thumbsup:
Title:
Post by: Mularac on May 28, 2010, 16:31:55
i don't know about the AI or anything else, but I know for a fact that the weapon and ship configuration screen handles the devices according to their sets (as to where to place the devices in each category and all).
But honestly i don't know if there's an other issue... but nexus has many hardcoded issues, so I don't know....
 

@Arparso:  Why did you use the E.EnginesCount variable? Isn't it enough by using the E.engines list?

-- Just corrected myself: it's more efficient to check a variable that use walk trough a list... that's why you used enginesCount, right?
Title:
Post by: Arparso on May 28, 2010, 19:47:12
Quote
@Arparso: Why did you use the E.EnginesCount variable? Isn't it enough by using the E.engines list?

-- Just corrected myself: it's more efficient to check a variable that use walk trough a list... that's why you used enginesCount, right?
Exactly. SelectDevices() already returns the number of selected devices, so a call to AllNumOf() isn't required anymore. I wouldn't expect a performance difference between both variants, although it's hard to tell without knowing how these functions are implemented. Unless you're calling AllNumOf() a few thousand times per frame, you probably shouldn't even care.
Title:
Post by: The Old Dragon on June 07, 2010, 14:54:51
Question:

How can I get the top speed of a ship on normal burn?

obj:tGetVelocity(); only reports the current speed (not helpfull as I know the speed at this point will be zero);
obj:tGetMaxVelocity(); gives the engines top possible speed when on full burn( again, not usefull as this speed exceeds the limit I'm trying to set).

The idea is to limit a formation leaders top speed slightly so that any other ship of the same class/type as the leader can take it's place in a formation instead of lagging behind.
Oh, and I can't look at the tacticstypes.ini for this info as the script is for any and all ships.
Title:
Post by: Arparso on June 07, 2010, 16:01:44
Quote
How can I get the top speed of a ship on normal burn?
I don't know of a script command or variable to directly get the normal speed, but it can be calculated. tGetMaxVelocity() gets you the highest achievable speed when routing additional energy into the engine subsystem. This is 50% more than the ship's regular speed, so the regular speed can be calculated by multiplying the maximum velocity with 2/3.

There's one caveat to that: probably every engine has both a setting for EnergyIn and EnergyOutput. The first dictates how much energy the engine uses each tick when being fully active (at regular speed) and the second setting specifies the amount of energy the engine itself generates each tick. If both values are equal, the engine can operate at regular speed (100%) without needing any additional energy and achieves up to 150% speed when being fed with support energy.
If EnergyOutput is actually higher than EnergyIn, the engine will actually exceed the regular speed without needing additional energy, but will still be limited to a maximum of 150% of the regular speed. Using the above calculation, however, gets you the regular speed, but not the actual speed the engine is really capable of.
The other way around is even worse: if EnergyOutput is lower than EnergyIn, the engine will not be able to reach the regular speed without any additional support energy. It also won't get to the usual 150% speed level, even if being fed enough support energy. tGetMaxVelocity() will NOT account for that (nor will the GUI) and will still report the theoretical 150% speed, even though the engine operates below that level. This leaves you with a calculated regular speed way above the actual engine's capabilities.

I don't know a good way to get around these two cases. Especially the second one is pretty bad as you'll calculate a speed way too fast for your engine while in the first case you'll just slow down your ship a bit, which alone would be tolerable. That being said, I'd consider it bad practice to actually include such an engine in your mod (with EnergyOutput being lower than EnergyIn), as it also screws up the manual speed panel on the GUI. Avoiding that, the simple calculation above should be sufficient for most needs.
Title:
Post by: The Old Dragon on June 11, 2010, 15:26:12
Thanks Arparso, that works just fine.

Got another quick question that's making me go ggrrrr.

Using the 'Detected' rule, how do I find out which ship is doing the detecting?
Title:
Post by: Arparso on June 11, 2010, 18:08:05
Now that's a good question... I have absolutely no idea and I don't even see any helpful scripting command or variable.
Title:
Post by: The Old Dragon on June 14, 2010, 15:07:31
Well, I managed to find an alternative route round this one, got a tick running every five seconds which issues a 'SelectShips' command with a few conditions. Not particularly neat, but it works (for the most part).

But now I've got another happy little question...

If a ship (or any item really) is in a list, is it possible to get that list ID from the ship/item?

So, for example, just say a single ship in a squadron has a cloaking device. Once the squadron has located an enemy, then the cloaked ship will engage its cloak for maximum advantage. Now while cloaked, this ship won't be able to follow the AI orders of the other ships so I'll need to pluck it out and place it in a 'squadron' of it's own. My problem is finding the squadron list ID to begin with.

EDIT 15/06/10:

Kind of got an answer. If' it's a ship and it's in a formation than the answer's yes (needs some carefull setting up first though).  Don't know about things not in a formation though.
Title:
Post by: Arparso on June 16, 2010, 23:38:40
Using IndexOf() (http://nexusthegame.net/wiki/IndexOf) it should be possible. You'd have to loop through all your squadron lists and look for your ship in one of them using the aforementioned IndexOf(). I wrote a short rule doing just that:

Code: [Select]
// description: looks through all lists with ids between E.firstList
// and E.lastList to find E.object and returns the list's id or -1
// param: E.firstList - id of the first list to look through
// param: E.lastList  - id of the last list to look through
// param: E.object    - the object being searched
RULE event GetFirstListContainingObject
:action
// stores the list currently being searched, starts with first list
E.currentList := E.firstList;
// marks, if the object has been found yet (currently 0, false)
E.foundObject := 0;

// loop through all lists, unless the object has been found
While(E.currentList <= E.lastList & E.foundObject = 0,
// look for the object in the current list
E.list := IndexOf(E.currentList, E.object);
// if object has been found, set foundObject to 1 (true)
If(E.list > -1,
E.foundObject := 1;
);
// advance to the next list
E.currentList := E.currentList + 1;
);

// check, if the object has actually been found in one of the lists
If(E.foundObject = 1,
// object has been found
// get the last list id and return it to the event caller
E.currentList := E.currentList - 1;
Debug("Object", E.object, "was found in list", E.currentList);
return(E.currentList);
,
// else return -1
Debug("Object not found in any list");
return(-1);
);
:end
END

Use it like so:

Code: [Select]
E.listId := LocalEvent(GetFirstListContainingObject,
E.firstList := 10;
E.lastList := 14;
E.object := m.ship)
);

There's one big problem regarding the scope of variables, though. Basically, every MACHINE has it's own lists. List 55 in one MACHINE can and probably will contain a totally different selection than list 55 in a different MACHINE. If the above rule for "GetFirstListContainingObject" is not in the same MACHINE as the place where you're calling it via LocalEvent(), it won't be able to access the correct lists and give wrong results. Sadly I don't know a way around this issue...

Also don't search through lists with the Id -1, because the above code returns -1 as error code, if it didn't find the object in any of the lists. If including the list -1 in the search, you couldn't differentiate between "not found" and "found in list -1" ;)

PS: While looking at the list of script commands Nexus offers, I realize I could have used InSelection() (http://nexusthegame.net/wiki/InSelection) instead of IndexOf(), but it works either way.
Title:
Post by: The Old Dragon on June 17, 2010, 00:46:19
Thanks Arparso, that's certainly opened up a new avenue or two.
Quick question, where did you get the 'E.FirstList' & 'E.LastList' parameters from? It's the first time I've seen those particular variables.

My solution went along these lines...

Code: [Select]
    E.Leader:=E.ship:FormLeader;
    Debug("Squadron leader is ",E.Leader);

E.Index:=IndexOf(M.LeadersList,E.Leader);
ThisSquadron:=GetN(M.SquadIndex,E.Index);
Debug("This Squadron is ",ThisSquadron);

M.NewList:=GetfreeSel();
SelectShips(M.NewList,InSelection(ThisSquadron,S.this));
ExecList(M.NewList,
Debug(ThisSquadron,"Squadron consists of ",S.this);
);

I should point out that during the filtering process, all available ships are placed in formations which are then catalogued (M.SquadIndex) with the formation leaders also being recorded  (M.LeadersList).  Although I believe this'll be sufficient for my needs (at least for now, lol), I daresay I'll integrate your approach at some point to handle any possible stationary objects.

Once again, thank you  :thumbup:
Title:
Post by: Arparso on June 17, 2010, 10:29:17
Quote
Quick question, where did you get the 'E.FirstList' & 'E.LastList' parameters from? It's the first time I've seen those particular variables.

Well, I just defined them on my own. As you know, you can raise a certain event using one of the following commands:These commands will execute all "reachable" (*) RULEs belonging to that particular event and supply them with a list of named parameters in var_set. Like so:
Code: [Select]
// no parameters:
LocalEvent(myEvent, 0);
// one parameter containing the number 1:
LocalEvent(myEvent, E.myParameter := 1);
// one parameter containing the value of another variable:
LocalEvent(myEvent, E.myShip := M.playerShip);
// multiple parameters combined:
LocalEvent(myEvent, E.myParameter := 1; E.myShip := M.playerShip; E.anotherParameter := P.count);
You can name these parameters as you wish, much like I named mine E.firstList, E.lastList and E.object. Predefined events such as FatalDamaged already come with a range of variables supplied by the game itself, but generally work just the same.

(*) what RULEs are "reachable" depends on the command itself and its location in the script. E.g. LocalEvent can reach each RULE in its own MACHINE and each embedded "child" MACHINE. Calling LocalEvent at the "root" SceneInit-RULE that every mission has, can reach ALL rules belonging to that event in the whole mission script, for example, because all of the mission's rulesets/MACHINEs are "children" of that root level. Calling LocalEvent() inside a MACHINE, however, won't execute any RULE outside that particular MACHINE (and its embedded child MACHINES, if it has any).
Title:
Post by: Mularac on July 26, 2010, 22:58:43
Today I was working on a scripted "progress bar" for the repairing devices tab (critical for one mission, where you start with all your devices off-line (damage 100)). However, if you set the damage of a device to '100', you can't then set it to anything other than '0' (the variable will be changed, but nothing will appear on the gui until the bar reaches '0'.

The workarround to that problem I found was setting the damage to 99, but then the ship will start to automatically fix the devices, as it is supposed to, but completely screwing the "climax" of the mission.

So my question:
a) is there an other work-arround to my 1° problem?
b) if not, anyone know a way to stop the ship from fixing it's devices withouth altering the tacticstypes.ini?
Title:
Post by: The Old Dragon on July 27, 2010, 01:14:28
As this is a scripted mission and you therefore know which object/s is/are to be damaged, could you not write a small routine that will select the various devices and then check their damage levels?

Then it could reset them where necessary and with the use of the 'Timer' command, you could re-run the routine as and when required (instead of using a 'tick').
Title:
Post by: Mularac on July 27, 2010, 01:58:05
The mission is like this, you start with all the devices disabled, so I put them with damage = 100, aka, completely destroyed, so the ship wouldn't try to fix it on it's own, and wrote a routine that would allow the player to cicle between all the devices that hasn't been fixed and choose which one they want to fix.
What I also wanted to do is write an other small routine (which I've already wrote, btw) that would "fake" a fixing progress bar for the duration of the fixing, and in doing that I encountered the problems I listed above.
Title:
Post by: Mularac on August 31, 2010, 23:05:26
Just checking, though I know the answer... is there a way to make an event kick in when a weapon hits a target? like the ion-scream bomb, for example.
Title:
Post by: Arparso on September 01, 2010, 01:02:34
Well, the FirstHit event kicks in if you've previously requested it for each ship using obj:tRequestFirstHitEvent() (and immediately request it again after each hit). You only get the victim and the attacker, though, not the specific weapon landing the hit. Can't think of anything else right now.
Title:
Post by: Mularac on September 01, 2010, 01:24:29
Yeah, I know that one. But what put it off is the thought of an other weapon beating the one I requested to the target ship... Meh, I think that a mere delay will do it...
Title:
Post by: Mularac on September 06, 2010, 00:53:56
About that previous issue, I managed to find a way to narrow down the problem.

Basically, when a specific weapon fires, a firstHit event is called regarding the targetted ship, and then I save the attacker and victim in 2 separate lists but with the same index, so when the FirstHit event is called, all I have to do is check that the "e.shooter" variable of that rule corresponds to the object present in the "attackers" list in the same index as the one of the victim. There's, however, a giagantic fault with that. Nexus doesn't admit repeated objects in their lists, so if, let's say, 2 ships attack the same one, the code will only get triggered for one of the hits.

So, is there a way to have repeated objects in a list??
Title:
Post by: Arparso on September 06, 2010, 11:15:43
I believe there is, if you're using an array rather than a normal selection. Use "Dim()" to create an array of a given size a and use "GetN()" and "SetN()" to retrieve or set individual array elements at a given position in the array. Something like:

Code: [Select]
MyShip := GetSceneObj("MyShip");
MyArray := GetFreeSel();
Dim(MyArray, 200);
SetN(MyArray, 15, MyShip);
MyShipToo := GetN(MyArray, 15);

Can't test it right now as I'm not at home, but that should work. However, if I remember correctly, Nexus doesn't support lists, arrays or selections bigger than 256 elements... for whatever arbitrary reason.
Title:
Post by: Mularac on September 06, 2010, 16:20:50
Yeah, that did it! thanks!
Title:
Post by: The Old Dragon on October 11, 2010, 15:04:35
Hi All,

Quick question, does anyone know where to find the code that triggers the various warnings (I'm mainly interested in the one for detecting incoming fighters, but I'd like to see the rest too)?

Thanks.
Title:
Post by: Arparso on October 11, 2010, 20:29:37
I think those might be hardcoded. I'm not completely sure, of course, but I don't remember stumbling across any script code related to issuing those warnings.
Title:
Post by: Mularac on December 01, 2010, 18:34:50
A question:

I've been making a cinematic scene that would show a couple hundred of ships appearing out of nowhere.
To be able to do that I've been turning them into wrecks the minute they appear, by changing their behaviour to 4. However, that didn't work, they still behave and more importantly, count as normal ships, so when I hit 20 or so the game crashes.
These ships appeared with the CreateShip command, they weren't part of the entities section.
My question:

How can I bypass this? any ideas?
Title: (no subject)
Post by: Arparso on December 02, 2010, 02:19:59
Tried it out and found a simple workaround: simply make the newly spawned ship disappear and immediately let it appear again. Of course, set behaviour to 4 before making the ship disappear or else you'll still run into the unit limit:

Code: [Select]
E.newShip := CreateShip(#styp_gtc_fenris, #race_player, "DynamicShip");
E.newShip:behaviour := 4;
E.disappearedShip := Disappear(E.newShip);
Appear(E.disappearedShip);

My interpretation of what happens internally:
Actually... I've got to thank you for that question, because experimenting with the solution I may have managed to work around the ship limit altogether :)
I made a separate thread for that (http://arparso.de/nexus/forum/index.php/topic,139.0.html), so that it won't get buried (and not found later) in this general purpose scripting thread.