Qs about Roles/AIs

Discussion and information relevant to creating special missions, new ships, skins etc.

Moderators: another_commander, winston

Paradox
---- E L I T E ----
---- E L I T E ----
Posts: 607
Joined: Wed Feb 20, 2013 1:24 am
Location: Aboard the D.T.T Snake Charmer: My Xanadu
Contact:

Qs about Roles/AIs

Post by Paradox »

What I am looking for, is a role/ai that instructs the ship to act as a random wanderer/scavenger around the main space lanes, but does not include docking with any stations etc... Is there anything that does this currently? ( I am a pixel jockey, not a scripter!) Here's what I am working on...

Image

I am making 2-3 different models and would like them to simply be an alien race (or maybe sentient robot life forms?) that wanders the space lanes scavenging and maybe mining? And maybe occasionally go rogue and pirate...? But looking at the included core(?) AIs, and then trying to recover from the resulting migraine, it looks like the scavenger roll makes them go back to the dock when full?

Next question... One of the models I want to make, is going to be carrying a "derelict" Cobra 3 (or at least one of the core spacecraft) around in its claws. Am I allowed to include the core model with my oxp, or can I "call it" within the shipdata.plist in some way... as a subentity perhaps? Not sure how that would work...
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Re: Qs about Roles/AIs

Post by Eric Walch »

In UPS there are AI's called route1UpsScavengerAI.plist and route1UpsMinerAI.plist

Not random, but while traveling to the main station, they scan for loot resp. rocks
User avatar
Commander McLane
---- E L I T E ----
---- E L I T E ----
Posts: 9520
Joined: Thu Dec 14, 2006 9:08 am
Location: a Hacker Outpost in a moderately remote area
Contact:

Re: Qs about Roles/AIs

Post by Commander McLane »

Otherwise you'd have to modify route1patrolAI.plist. It already contains the traveling back and forth the main space lane, but you'd have to rip out the hunter/police-specific behaviour like scanning for offenders and fighting them, and replace it with scavenger-specific behaviour, like scanning for asteroids and loot. Also, you'd need to rip out the docking bits.
Paradox
---- E L I T E ----
---- E L I T E ----
Posts: 607
Joined: Wed Feb 20, 2013 1:24 am
Location: Aboard the D.T.T Snake Charmer: My Xanadu
Contact:

Re: Qs about Roles/AIs

Post by Paradox »

Ok, I thank you Commanders! AIs look mainly like "blocks" of code, hopefully they can be cut and paste with just a few pointers being changed.... I hope. If I can pry myself out of Wings3d long enough, I will look at the examples you both gave me again and see if I think I can pull it off. Thank you for your time <salute>! }:]
User avatar
Commander McLane
---- E L I T E ----
---- E L I T E ----
Posts: 9520
Joined: Thu Dec 14, 2006 9:08 am
Location: a Hacker Outpost in a moderately remote area
Contact:

Re: Qs about Roles/AIs

Post by Commander McLane »

I've taken the liberty to strip route1patrolAI off everything not needed for your type of ship. Here's the result:

Code: Select all

{
    GLOBAL =     {
        ENTER =         (
            "setStateTo: HEAD_FOR_WITCHPOINT"
        );
    };
    "HEAD_FOR_PLANET" =     {
        "AEGIS_CLOSE_TO_MAIN_PLANET" =         (
            "setStateTo: HEAD_FOR_WITCHPOINT"
        );
        ATTACKED =         (
            setTargetToPrimaryAggressor,
            groupAttackTarget
        );
        "ATTACKED_BY_CLOAKED" =         (
            "setAITo: interceptAI.plist",
            "setStateTo: FLEE_FOR_CLOAKED"
        );
        "ATTACKER_MISSED" =         (
            setTargetToPrimaryAggressor,
            groupAttackTarget
        );
        "CASCADE_WEAPON_DETECTED" =         (
            "setAITo: fleeQMineAI.plist"
        );
        "COURSE_OK" =         (
            setSpeedToCruiseSpeed,
            performFlyToRangeFromDestination
        );
        "DESIRED_RANGE_ACHIEVED" =         (
            "setStateTo: HEAD_FOR_WITCHPOINT"
        );
        ENTER =         (
            setCourseToPlanet,
            "setDesiredRangeTo: 50000.0",
            checkCourseToDestination
        );
        "GROUP_ATTACK_TARGET" =         (
            setTargetToFoundTarget,
            "setStateTo: INBOUND_LOOT",
            "setAITo: interceptAI.plist"
        );
        "INCOMING_MISSILE" =         (
            fightOrFleeMissile,
            setTargetToPrimaryAggressor,
            deployEscorts,
            groupAttackTarget
        );
        RESTARTED =         (
            checkAegis
        );
        "TARGET_FOUND" =         (
            setTargetToFoundTarget,
            "setAITo: collectLootAI.plist"
        );
        UPDATE =         (
            setCourseToPlanet,
            "setDesiredRangeTo: 50000.0",
            checkCourseToDestination,
            scanForLoot,
            "pauseAI: 10.0"
        );
        "WAYPOINT_SET" =         (
            "setAITo: gotoWaypointAI.plist"
        );
    };
    "HEAD_FOR_WITCHPOINT" =     {
        ATTACKED =         (
            setTargetToPrimaryAggressor,
            groupAttackTarget
        );
        "ATTACKED_BY_CLOAKED" =         (
            "setAITo: interceptAI.plist",
            "setStateTo: FLEE_FOR_CLOAKED"
        );
        "ATTACKER_MISSED" =         (
            setTargetToPrimaryAggressor,
            groupAttackTarget
        );
        "CASCADE_WEAPON_DETECTED" =         (
            "setAITo: fleeQMineAI.plist"
        );
        "COURSE_OK" =         (
            setSpeedToCruiseSpeed,
            performFlyToRangeFromDestination
        );
        "DESIRED_RANGE_ACHIEVED" =         (
            "setStateTo: HEAD_FOR_PLANET"
        );
        ENTER =         (
            setCourseToWitchpoint,
            checkCourseToDestination
        );
        "GROUP_ATTACK_TARGET" =         (
            setTargetToFoundTarget,
            "setStateTo: OUTBOUND_LOOT",
            "setAITo: interceptAI.plist"
        );
        "INCOMING_MISSILE" =         (
            fightOrFleeMissile,
            setTargetToPrimaryAggressor,
            deployEscorts,
            groupAttackTarget
        );
        "TARGET_FOUND" =         (
            setTargetToFoundTarget,
            "setAITo: collectLootAI.plist"
        );
        UPDATE =         (
            setCourseToWitchpoint,
            checkCourseToDestination,
            scanForLoot,
            "pauseAI: 10.0"
        );
        "WAYPOINT_SET" =         (
            "setAITo: gotoWaypointAI.plist"
        );
    };
    "HYPER_OUT" =     {
        UPDATE =         (
            performHyperSpaceExit
        );
    };
    "INBOUND_LOOT" =     {
        ATTACKED =         (
            setTargetToPrimaryAggressor,
            groupAttackTarget
        );
        "ATTACKER_MISSED" =         (
            setTargetToPrimaryAggressor,
            groupAttackTarget
        );
        "CASCADE_WEAPON_DETECTED" =         (
            "setAITo: fleeQMineAI.plist"
        );
        ENTER =         (
            "setSpeedTo: 0.0",
            performIdle
        );
        "GROUP_ATTACK_TARGET" =         (
            setTargetToFoundTarget,
            "setAITo: interceptAI.plist"
        );
        "HOLD_FULL" =         (
            "setStateTo: HEAD_FOR_PLANET"
        );
        "INCOMING_MISSILE" =         (
            fightOrFleeMissile,
            setTargetToPrimaryAggressor,
            deployEscorts,
            groupAttackTarget
        );
        "NOTHING_FOUND" =         (
            "setStateTo: HEAD_FOR_PLANET"
        );
        "TARGET_FOUND" =         (
            setTargetToFoundTarget,
            "setAITo: collectLootAI.plist"
        );
        UPDATE =         (
            scanForLoot,
            "pauseAI: 10.0"
        );
    };
    "OUTBOUND_LOOT" =     {
        ATTACKED =         (
            setTargetToPrimaryAggressor,
            groupAttackTarget
        );
        "ATTACKER_MISSED" =         (
            setTargetToPrimaryAggressor,
            groupAttackTarget
        );
        "CASCADE_WEAPON_DETECTED" =         (
            "setAITo: fleeQMineAI.plist"
        );
        ENTER =         (
            "setSpeedTo: 0.0",
            performIdle
        );
        "GROUP_ATTACK_TARGET" =         (
            setTargetToFoundTarget,
            "setAITo: interceptAI.plist"
        );
        "HOLD_FULL" =         (
            "setStateTo: HEAD_FOR_WITCHPOINT"
        );
        "INCOMING_MISSILE" =         (
            fightOrFleeMissile,
            setTargetToPrimaryAggressor,
            deployEscorts,
            groupAttackTarget
        );
        "NOTHING_FOUND" =         (
            "setStateTo: HEAD_FOR_WITCHPOINT"
        );
        "TARGET_FOUND" =         (
            setTargetToFoundTarget,
            "setAITo: collectLootAI.plist"
        );
        UPDATE =         (
            scanForLoot,
            "pauseAI: 10.0"
        );
    };
}
In this form the AI will only scavenge. It won't mine, and it won't attack anything, just fly between planet and witchpoint, and collect everything scoopable in-between. When it's full, it'll still continue to patrol the line. But you should probably make sure to give it enough cargo capacity that it's never going to get full. Alternatively it could jump out (just replace the "HEAD_FOR_…" with "HYPER_OUT" following the "HOLD_FULL" messages).
Paradox
---- E L I T E ----
---- E L I T E ----
Posts: 607
Joined: Wed Feb 20, 2013 1:24 am
Location: Aboard the D.T.T Snake Charmer: My Xanadu
Contact:

Re: Qs about Roles/AIs

Post by Paradox »

Commander McLane wrote:
I've taken the liberty to strip route1patrolAI off everything not needed for your type of ship. Here's the result:
Commander McLane wrote:
In this form the AI will only scavenge. It won't mine, and it won't attack anything, just fly between planet and witchpoint, and collect everything scoopable in-between. When it's full, it'll still continue to patrol the line. But you should probably make sure to give it enough cargo capacity that it's never going to get full. Alternatively it could jump out (just replace the "HEAD_FOR_…" with "HYPER_OUT" following the "HOLD_FULL" messages).
Thank you so very much Commander McLane! I did go ahead and change the two "HEAD_FOR_PLANET"s to "HYPER_OUT"s, but this leads to another question...
I know you can create a custom "role" for ships, and in this way :spawn them, but after reading System_Populator, I am still fuzzy as to how this works. Let's say I add:

Code: Select all

role = "dox_scavenger (1.0)";
to my shipdata.plist. Since no other ships in Oolite have this code, does that guarantee that one of them will be added? Or do I need to specify a "built in" role , such as scavenger or pirate etc?

Anyways, thanks again for taking the time to answer my questions and hacking that AI for me!
User avatar
Commander McLane
---- E L I T E ----
---- E L I T E ----
Posts: 9520
Joined: Thu Dec 14, 2006 9:08 am
Location: a Hacker Outpost in a moderately remote area
Contact:

Re: Qs about Roles/AIs

Post by Commander McLane »

The key is spelled roles, not role. And as it's the only ship with your custom role, you don't need to specify a role weight (the parameter in parenthesis).

Thus, what you need in shipdata, is

Code: Select all

roles = "dox_scavenger";
Now you can spawn the ship using the :spawn macro in the console. Just type:

Code: Select all

:spawn dox_scavenger
Note that you can achieve the same by using the ship's unique shipdata key and putting it in brackets. So, if the shipdata key is "dox-scavenger", you can also type:

Code: Select all

:spawn [dox-scavenger]
This suffices for testing purposes. For your OXP you will need to create a spawning script, because you can't depend on all players using the debug console. The system populator only knows about Oolite's generic roles, and only spawns ships using those roles. It cannot spawn anything that only has a custom role.
Paradox
---- E L I T E ----
---- E L I T E ----
Posts: 607
Joined: Wed Feb 20, 2013 1:24 am
Location: Aboard the D.T.T Snake Charmer: My Xanadu
Contact:

Re: Qs about Roles/AIs

Post by Paradox »

Commander McLane wrote:
The key is spelled roles, not role. And as it's the only ship with your custom role, you don't need to specify a role weight (the parameter in parenthesis).
Spelling mistake on my part, though I didn't know about the weight. Thanks for that info!
Commander McLane wrote:
This suffices for testing purposes. For your OXP you will need to create a spawning script, because you can't depend on all players using the debug console. The system populator only knows about Oolite's generic roles, and only spawns ships using those roles. It cannot spawn anything that only has a custom role.
That's the part I was dreading to hear... <whimper> Ok, looks like I will have to take a look at some other oxps and see if I can figure that part out. First finish Heavy Metal, then hopefully by then I will have some feedback on the DTT Wraith, then I will get back to this. Thanks once again for the info Commander!
User avatar
Commander McLane
---- E L I T E ----
---- E L I T E ----
Posts: 9520
Joined: Thu Dec 14, 2006 9:08 am
Location: a Hacker Outpost in a moderately remote area
Contact:

Re: Qs about Roles/AIs

Post by Commander McLane »

Paradox wrote:
Next question... One of the models I want to make, is going to be carrying a "derelict" Cobra 3 (or at least one of the core spacecraft) around in its claws. Am I allowed to include the core model with my oxp, or can I "call it" within the shipdata.plist in some way... as a subentity perhaps? Not sure how that would work...
We haven't yet answered this question. The answer is "yes" on all accounts.

Yes, you are allowed to use all core models in your OXP; and yes, you can simply use them as subentities. From a game point of view, there is no technical difference between a main entity and a subentity, thus everything that has a shipdata-representation can be used as a subentity. There is one caveat: subentities cannot have subentities themselves. Thus, the core ships you want to use would automatically lose their subentities when spawned as subentities themselves. Having said that, you can immediately disregard it for the core ships, because none of them has subentities. But, for players who use a replacement shipset that overrides the original set, this could make an optical difference.

Thus, to be on the safe side, you should create clones of those ships you want to use. Create shipdata entries for the ships you want to use, and define only those keys that are necessary for them to function as a subentity (for instance, you don't need a max_speed, or an exhaust, or view- and weapon-positions). You also need clones of your scavenger for each possible carried ship, differing only in their subentities-key. The [EliteWiki] Salvager Tugger from [wiki]Anarchies OXP[/wiki] is a good example for what you need, because it's doing the exact same thing, only that it's tugging various ships of the core set instead of holding them in its claws. Feel free to butcher its shipdata. :D
Paradox
---- E L I T E ----
---- E L I T E ----
Posts: 607
Joined: Wed Feb 20, 2013 1:24 am
Location: Aboard the D.T.T Snake Charmer: My Xanadu
Contact:

Re: Qs about Roles/AIs

Post by Paradox »

Commander McLane wrote:
Thus, to be on the safe side, you should create clones of those ships you want to use. Create shipdata entries for the ships you want to use, and define only those keys that are necessary for them to function as a subentity (for instance, you don't need a max_speed, or an exhaust, or view- and weapon-positions). You also need clones of your scavenger for each possible carried ship, differing only in their subentities-key. The  Salvager Tugger from  Anarchies OXP is a good example for what you need, because it's doing the exact same thing, only that it's tugging various ships of the core set instead of holding them in its claws. Feel free to butcher its shipdata.
OK, I think I understand all that. };] Will have to give this part more thought as I am also thinking of showing damage/parts missing from the ships, which will mean basically a new model or a modification of the core model anyways. Well, thank you for the information, and addressing the re-use question! };]
User avatar
Commander McLane
---- E L I T E ----
---- E L I T E ----
Posts: 9520
Joined: Thu Dec 14, 2006 9:08 am
Location: a Hacker Outpost in a moderately remote area
Contact:

Re: Qs about Roles/AIs

Post by Commander McLane »

Paradox wrote:
Will have to give this part more thought as I am also thinking of showing damage/parts missing from the ships, which will mean basically a new model or a modification of the core model anyways.
Yep.
Paradox wrote:
Well, thank you for the information, and addressing the re-use question! };]
You're welcome. :)
User avatar
Commander McLane
---- E L I T E ----
---- E L I T E ----
Posts: 9520
Joined: Thu Dec 14, 2006 9:08 am
Location: a Hacker Outpost in a moderately remote area
Contact:

Re: Qs about Roles/AIs

Post by Commander McLane »

Okay, next step: spawning script.

First of all: Don't Panic! Writing scripts is no rocket science. For standard tasks (like spawning ships) it's actually quite straightforward. You simply tell the game engine what it has to do and when. You just have to use the right language to do so. :wink:

You need a world script (that's a script attached to the game universe as a whole, as opposed to a script attached to a specific ship and only existing while that ship is also existing; you can also think of a world script as being attached to the player, because the game universe only exists inasmuch as the player is there). The simplest way of creating one is to create a simple text file and save it in the Config-folder of your OXP (right next to your shipdata.plist) under the name of "script.js".

Here's what it has to contain:

Code: Select all

"use strict";

this.name           = "dox-scavenger";
this.description    = "Script for randomly spawning dox scavengers whenever the player enters a new system";
this.author         = "Commander McLane";
this.copyright      = "© 2013 Commander McLane";
this.license        = "CC-by-nc-sa 3.0";
this.version        = "1.0";


this.shipExitedWitchspace = function()
{
    if(!system.isInterstellarSpace && ... && Math.random() < 0.1)
    {
        system.addShipsToRoute("dox_scavenger", 1, 0.3, "wp");
    }
}
Let's go through it line by line:

The first line tells the JavaScript-engine that we're conforming to some standard. I don't know any details, I just know that each script should have it right at the beginning.

Then comes a group of six lines that contain meta-information about the script. For the most part they're exactly that: convenient meta-information, but not strictly necessary. However, there's one exception: the

Code: Select all

this.name           = "dox-scavenger";
is mandatory. Also, the name has to be unique (just like shipdata keys of your ship), because this is how the JavaScript-engine actually distinguishes all the various scripts. It doesn't use file names for that. Therefore each OXP can contain a "script.js" in its Config-folder without confusing the scripting engine, as long as they all have a unique this.name.

The last seven lines are the actual script code.

Code: Select all

this.shipExitedWitchspace
is an event handler. It tells the scripting engine when to perform the commands enclosed in the following curly brackets. In this case, we want the action each time when the player exited from witchspace and has entered a new system. There is a Image list of all existing event handlers on the Wiki that explains when each of them "fires". For the purpose of populating a system with additional ships (or creatures) the moment when the player enters the system is of course the logical choice.

But I assume that you don't want to spawn one of your scavengers literally every time when the player pops out of witchspace. Thus the spawning code should only be executed under some conditions. Those are defined in the if clause:

Code: Select all

    if(!system.isInterstellarSpace && ... && Math.random() < 0.1)
First of all, !system.isInterstellarSpace checks that the player is in a planetary system (the "!" means "not"). It prevents the scavengers from being spawned in case of a misjump. After all, in interstellar space there is no space lane between witchpoint and planet, and there are no asteroids.

Last of all, Math.random() < 0.1 adds an element of random. Math.random() creates a random number between 0 and 1. So only ten percent of the time it will be < 0.1, and the condition will be fulfilled. I just filled in this probability arbitrarily, and you can of course decrease or increase the probability by decreasing or increasing the number.

Between those two, the ... stand for any other conditions you can come up with. For instance, you can make the tech level of the system into a condition, or the political affiliation, or the economy, or any other property of the system. So the player would only ever encounter the scavengers in systems that are at least poor industrial, excluding anarchies and feudals, with a tech level not higher than 10. Or whatever combination of conditions allows the scavengers to flourish best. A Image list of all system-related properties that can be used as conditions is of course also on the Wiki.

Finally, if all conditions are met, the part in the innermost curly brackets is executed:

Code: Select all

        system.addShipsToRoute("dox_scavenger", 1, 0.3, "wp");
It tells the engine to add a specified amount of ships with a specified role to a specified location along one of the space lanes.

In this case, the role is "dox_scavenger", the amount is 1 of them, the location is at 30 per cent of the way in, and the route is from witchpoint to planet.

Of course, you can modify each of the parameters to your liking:
  • Specify another role to spawn a ship/ships of that role.
  • Specify another number to spawn more than one ship (the limit is 64, so you can spawn a pretty big cluster of ships with a single command).
  • Specify another fraction to move the spawning point forward or back. 0 means (on the main route) exactly the witchpoint position, and 1 means on the surface of the planet. You can also use a negative number to spawn something behind the witchpoint, or a number > 1 to spawn something behind the planet (caution: because 1 means the surface of the planet, chances are that 1.05 will spawn your ship inside the planet). You can even use random here: replacing the 0.3 with Math.random() will cause your scavenger to spawn at a random location between the witchpoint and the planet; (Math.random() * 0.8 ) + 0.1 will make sure that it's not too close to either the witchpoint or the planet.
  • Specify another one of the space lanes. Apart from "wp" (witchpoint to planet) there's also "pw" (planet to witchpoint), "ws" (witchpoint to sun), "sw" (sun to witchpoint), "ps" (planet to sun), and "sp" (sun to planet). If you skip the parameter altogether, the direct line between witchpoint and main station is used.
And that's it. There you are with a highly modifiable and customizable spawning script. :)

EDIT: added quotation marks at a vital point in the code example.
Last edited by Commander McLane on Tue Apr 02, 2013 10:06 pm, edited 1 time in total.
Paradox
---- E L I T E ----
---- E L I T E ----
Posts: 607
Joined: Wed Feb 20, 2013 1:24 am
Location: Aboard the D.T.T Snake Charmer: My Xanadu
Contact:

Re: Qs about Roles/AIs

Post by Paradox »

Ow wow, he made one just for me!!! }:] :happy_dance: :lol: Thank you for this Commander McLane.
Commander McLane wrote:
First of all: Don't Panic! Writing scripts is no rocket science. For standard tasks (like spawning ships) it's actually quite straightforward. You simply tell the game engine what it has to do and when. You just have to use the right language to do so.
It's that "right language" part that's the killer. I have spent days trouble shooting Rainmeter code, just to find that one "(" that should have been a "{", or a "," instead of a "."! };] It's not that I can't code/script (although programming is an entirely different matter!), it's that I HATE trying to learn all the new syntaxs and at 51 yrs old, I am mighty thin on hair to pull when I get frustrated! };] And mild ADD means that if I am not really interested in something, I have a he!! of a time concentrating on it.
But... with that out of the way, let me see if I can mangle this...

Code: Select all

"use strict"; // Need this!

this.name           = "dox-scavenger"; //Also Need this, and must be unique(?)
this.description    = "Script for randomly spawning dox scavengers whenever the player enters a new system"; //metadata
this.author         = "Commander McLane"; //metadata
this.copyright      = "© 2013 Commander McLane"; //metadata
this.license        = "CC-by-nc-sa 3.0"; //metadata
this.version        = "1.0"; //metadata


this.shipExitedWitchspace = function() //This is the condition.


That part is easy enough, now the meat and potatoes... Let's say I want to spawn 2 different types of Dox, and want them to appear in a random spot between the witchpoint and planet, only in tech systems of 8 and above, with a 1 out of 4 chance...

Code: Select all

{
    if(!system.isInterstellarSpace && techLevel => 8 && Math.random() < 0.25)
    {
        system.addShipsToRoute("dox_scavenger1", 1, (Math.random() * 0.8 ) + 0.1, wp);
        system.addShipsToRoute("dox_scavenger2", 1, (Math.random() * 0.8 ) + 0.1, wp);
    }
}


So, did I butcher it? Bet you a cheeseburger I did! }:]

The wiki is good at telling you what things do, but not at how to use them in an actual script. Definitions, but not examples.
User avatar
Commander McLane
---- E L I T E ----
---- E L I T E ----
Posts: 9520
Joined: Thu Dec 14, 2006 9:08 am
Location: a Hacker Outpost in a moderately remote area
Contact:

Re: Qs about Roles/AIs

Post by Commander McLane »

Paradox wrote:
So, did I butcher it? Bet you a cheeseburger I did! }:]
Almost there! :D

Some corrections:

Code: Select all

"use strict"; // Need this!

this.name           = "dox-scavenger"; //Also Need this, and must be unique(!)
this.description    = "Script for randomly spawning dox scavengers whenever the player enters a new system"; //metadata
this.author         = "Commander McLane"; //metadata
this.copyright      = "© 2013 Commander McLane"; //metadata
this.license        = "CC-by-nc-sa 3.0"; //metadata
this.version        = "1.0"; //metadata


this.shipExitedWitchspace = function() //This is the event handler.
{
    if(!system.isInterstellarSpace && system.techLevel >= 7 && Math.random() < 0.25) //These are the conditions.
    {
        system.addShipsToRoute("dox_scavenger1", 1, (Math.random() * 0.8) + 0.1, "wp"); //adding one specimen of type1 at a random location between 10-90% into the space lane
        system.addShipsToRoute("dox_scavenger2", 1, (Math.random() * 0.8) + 0.1, "wp"); //adding one specimen of type2 at a random location between 10-90% into the space lane
    }
}
I made a few changes and amendments to the comments.

techLevel is a property of system, thus you have to write system.techLevel, otherwise the engine doesn't know whose techLevel to check. The comparison operator is written just as you'd also pronounce it: "greater than or equal": >= (I'm not sure if => would work as well). Finally, as in all things computery, the internal counter for techLevel (as for everything else) starts with 0. Thus, what is displayed to the player as TL 8 is actually internally techLevel 7. (By the way: you could also write system.techLevel > 6. As very often, there are many ways to achieve the same result.)

Finally, I put quotation marks around the "wp". I forgot those in my post above. Sorry. All strings need to be in quotation marks.

So far, so good. Now for an alternative approach: With this spawning script the player will encounter two different dox in one quarter of all TL8+ systems. They'll always appear in pairs, although not necessarily together. But what if you want more variation, and have sometimes only spawned type1, and other times only type2? In that case you want to handle the two types of dox independent from each other.

That's easily achievable by putting multiple condition clauses in the same event handler. All condition clauses are executed in order, one after the other. So:

Code: Select all

"use strict"; // Need this!

this.name           = "dox-scavenger"; //Also Need this, and must be unique(!)
this.description    = "Script for randomly spawning dox scavengers whenever the player enters a new system"; //metadata
this.author         = "Commander McLane"; //metadata
this.copyright      = "© 2013 Commander McLane"; //metadata
this.license        = "CC-by-nc-sa 3.0"; //metadata
this.version        = "1.0"; //metadata


this.shipExitedWitchspace = function() //This is the event handler.
{
    if(!system.isInterstellarSpace && system.techLevel >= 7 && Math.random() < 0.25) //These are the conditions.
    {
        system.addShipsToRoute("dox_scavenger1", 1, (Math.random() * 0.8) + 0.1, "wp"); //adding one specimen of type1
    }
    if(!system.isInterstellarSpace && system.techLevel >= 7 && Math.random() < 0.25) //These are the conditions.
    {    
        system.addShipsToRoute("dox_scavenger2", 1, (Math.random() * 0.8) + 0.1, "wp"); //adding one specimen of type2
    }
}
I just separated the two addShips-commands into different if-clauses. The conditions themselves are identical. But this time the random part of the condition is calculated twice with a different random number. So either the first one may be lower than 0.25, or the second one, or both. Accordingly you'll either get a type1 dox, or a type2, or both.

Alternatively, you can nest the condition clauses. The script doesn't actually need to check twice whether the player is in interstellar space, or what the system's techLevel is. This cannot possible change between the two checks. Thus it makes sense to check for these two first, in an outer condition clause, and then only create the random numbers in an inner condition clause, which is only ever executed if the outer conditions were already true. Thus, nested conditions make the code also run faster, because double checks are avoided, and fewer checks need to be made.

Then we get:

Code: Select all

"use strict"; // Need this!

this.name           = "dox-scavenger"; //Also Need this, and must be unique(!)
this.description    = "Script for randomly spawning dox scavengers whenever the player enters a new system"; //metadata
this.author         = "Commander McLane"; //metadata
this.copyright      = "© 2013 Commander McLane"; //metadata
this.license        = "CC-by-nc-sa 3.0"; //metadata
this.version        = "1.0"; //metadata


this.shipExitedWitchspace = function() //This is the event handler.
{
    if(!system.isInterstellarSpace && system.techLevel >= 7) //Outer conditions. These need to be true in order to proceed.
    {
        if(Math.random() < 0.25) //Random element.
        {
            system.addShipsToRoute("dox_scavenger1", 1, (Math.random() * 0.8) + 0.1, "wp"); //adding one specimen of type1
        }
        if(Math.random() < 0.25) //Random element.
        {
            system.addShipsToRoute("dox_scavenger2", 1, (Math.random() * 0.8) + 0.1, "wp"); //adding one specimen of type2
        }
    }
}
Incidentally, spawning two types with a 25%-probability results in an increased overall probability to see at least one: from 1/4 to 7/16. To counteract this, you may want to decrease the probability, let's say to 20% each time, which would result in a 9/25-probability to see at least one.
Paradox
---- E L I T E ----
---- E L I T E ----
Posts: 607
Joined: Wed Feb 20, 2013 1:24 am
Location: Aboard the D.T.T Snake Charmer: My Xanadu
Contact:

Re: Qs about Roles/AIs

Post by Paradox »

Commander McLane wrote:
Paradox wrote:
So, did I butcher it? Bet you a cheeseburger I did! }:]

Almost there!
LOLZ! You owe me a cheeseburger.
Commander McLane wrote:
I made a few changes and amendments to the comments.
Noted!
Commander McLane wrote:
So far, so good. Now for an alternative approach: With this spawning script the player will encounter two different dox in one quarter of all TL8+ systems. They'll always appear in pairs, although not necessarily together. But what if you want more variation, and have sometimes only spawned type1, and other times only type2? In that case you want to handle the two types of dox independent from each other.
Yes, that is more the idea I had in mind...
Commander McLane wrote:
That's easily achievable by putting multiple condition clauses in the same event handler. All condition clauses are executed in order, one after the other.

...

Incidentally, spawning two types with a 25%-probability results in an increased overall probability to see at least one: from 1/4 to 7/16. To counteract this, you may want to decrease the probability, let's say to 20% each time, which would result in a 9/25-probability to see at least one.
OK, left eye is starting to twitch, and my legs have gone numb from the knees down, but I'm not bleeding from the ears yet, so that's a good sign.

Furthermore, I actually do understand what you are doing there. Although there was no way I could have come up with any of this from just the wiki alone!

As for the probability, I will turn that down after testing.
I thank you Obi-Wan err.. Commander McLane! I very much appreciate your taking the time to explain this in a way that even I can comprehend! :bow:
Post Reply