Switeck's Shipping v0.5 OXP - Ai, Economy, and Ship changes

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

Moderators: another_commander, winston

Post Reply
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

Switeck wrote:
Eric Walch told me:
"enteringTraderAI.plist is only called by exitingTraderAI.plist. That is the AI used by ships entering wormholes.
Yes, that are the traders that actually entered the wormhole and arrive in the new system just before or simultaneously with the player.
Switeck wrote:
When a trader jumps in at the witchspace entry point in the current system, it always had a 10 percent chance of going to the sun. In trunk that now has changed a little. ...
In the past, any ship could become a sunskimmer. Now only ships that also contain the sunskim-trader role. The code "makeSunSkimmer" ensures that the heat-shielding is sufficient and it uses the right AI."
Ships that you see arriving at the witchpoint when you wait there, are always newly generated ships that are added at the moment somewhere else a ship uses the "performHyperspaceExit" command. In normal game it are only traders that are jumping in at the moment an other trader jumps out near the main station.
performHyperspaceExit generates special messages for both the original ship as for the replacement ship so that an AI can deal with this situation. It was never documented on the wiki, but its now on the OXP_howto_AI page.

EDIT:
When you want to test this, you can type a few times in the console:
system.mainStation.launchShipWithRole("trader"). This will add several launching traders to the main station. Wait a few minutes to give them time to launch and create a wormhole. Than you'll start seeing a lot of ships arriving at the witchpoint.

And when you are lazy like me, create a macro in the console:
:setM launchTrader system.mainStation.launchShipWithRole("trader") After that it only takes the line :launchTrader in the console. :wink:
Switeck
---- E L I T E ----
---- E L I T E ----
Posts: 2412
Joined: Mon May 31, 2010 11:11 pm

Post by Switeck »

Is "HOLD_FULL" from AI.plist files directly related to "likely_cargo" versus "max_cargo" in shipdata-overrides.plist?

I've seen pirates scoop cargo and kill them and get the extra stuff they grabbed back that way...but does Oolite also use an internal value to declare if new traders (to the system) have a full hold or not?
It would seem highly unusual for the smaller traders (Cobra 1's and 3's especially) to not be traveling with a full or at least nearly full hold.
And "likely_cargo" seems to be what cargo survives the destruction of the ship (usually about 10% of max cargo) rather than how much cargo the ship originally had before dying.
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:

Post by Commander McLane »

The Wiki wrote:
max_cargo

Sets the ship's cargo limit. On explosion of trader ships added by the System Populator, 10% of this value is used as likely cargo. When the result is lower than 16 it is the cargo, when higher than 15, it is changed in a random value between 0 and 15.


likely_cargo

This is only used for ships with role asteroid and pirate. With asteroids it gives the likely number of boulders it breaks into. With pirates added by the System Populator: when lower than 16 it is the cargo, when higher than 15, it is changed in a random value between 0 and 15. This value is overridden by the actual scooped cargo if the pirate had scooped something.
To me the explanations seem quite clear. Entering traders do not carry any cargo (which means that Oolite doesn't need to maintain a long list of every NPC's cargo all the time). Only in the very moment the ship dies its "cargo" is created in form of floating canisters. The number of canisters created depends on max_cargo, and is usually 10% of that value. I think the rationale behind this is that most of the cargo canisters would be destroyed in the blast, and only a lucky few would survive the ship's explosion intact. On top of that, the number of actually created canisters is capped at 15. I think the rationale behind that was to keep the total number of entities in a system (and thereby the frame rate on slower systems) at a reasonable level.

As a shipdata-key, likely_cargo is only ever used for asteroids and pirates. Its use is analogue to max_cargo for traders. There is, however, one important difference, as far as pirates are concerned. Their likely_cargo number is only used at the time of their death if they haven't scooped anything before. As soon as a pirate scoops a canister, its likely_cargo is out of the equation, and the number of canisters created at his death equals the number of canisters scooped.

HOLD_FULL is one of the AI messages which an AI can receive as a result of executing the checkForFullHold method.
The Wiki wrote:
checkForFullHold

If entity's cargo capacity is reached, will return "HOLD_FULL".
Since 1.73 it can also return "HOLD_NOT_FULL" or "NO_CARGO_BAY".
The method compares ship.cargoSpaceUsed with ship.cargoSpaceCapacity, or simply checks ship.cargoSpaceAvailable (of course it doesn't use the JS-properties, but the underlying counters in the code which are used by the JS-properties as well).

I don't know how this works exactly, but I would guess that in case of pirates cargoSpaceUsed would be 0 unless the ship has scooped something. After scooping something it should equal the number of canisters scooped.

So the HOLD_FULL message will be returned as soon as cargoSpaceUsed equals cargoSpaceCapacity, and cargoSpaceAvailable equals 0.
Switeck
---- E L I T E ----
---- E L I T E ----
Posts: 2412
Joined: Mon May 31, 2010 11:11 pm

Post by Switeck »

Switeck wrote:
does Oolite also use an internal value to declare if new traders (to the system) have a full hold or not?
I'm mainly concerned with traders...and to a lesser degree bounty hunters and even police ships. I want them to sometimes act as scavengers. (Though from what I understand police ships only scoop escape pods.) I use a checkForFullHold as a means of putting them into loot mode. But if they have undefined cargo in both amount and type...this could mean either *EVERY* new trader never has a full hold or they *ALL* have full holds. Neither of which is preferable, as that would mean there's no variation. I can work around every trader not having a full hold, by making some act like their holds are full. I'm screwed if they all have full holds, because even if they're told to scoop random cargo canisters they won't. :cry:
Commander McLane wrote:
On top of that, the number of actually created canisters is capped at 15. I think the rationale behind that was to keep the total number of entities in a system (and thereby the frame rate on slower systems) at a reasonable level.
I'd consider another important reason for that cap is to prevent a player from quickly getting rich killing Boas 2's and Anacondas. If an Anaconda dropped 10% of its max cargo, that would be 75 cargo canisters. Although a Cobra 3 would need 3 trips to a station to sell all those, it would likely make a huge profit doing so. Even having Boa 2's drop 17 or 18 cargo canisters would be a bonanza for a pirate-player. (They'd about have to be a pirate because that shiptype is normally never a pirate itself.)
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

Commander McLane wrote:
I don't know how this works exactly, but I would guess that in case of pirates cargoSpaceUsed would be 0 unless the ship has scooped something. After scooping something it should equal the number of canisters scooped.
Yes, the property cargoSpaceUsed is not giving the right answers here. As you say, Oolite does not put time in generating cargo the player can't see yet. Creating entities costs time and this time would be a waist for most of the cargo. Cargo is only generated on explosion, or when sending a distress message and the player is the aggressor. This allows fleeing traders to dump cargo. Before 1.74 this cargo dumping happened only for ships with role trader because it needed special flags to be set. Since 1.74 an oxp can define these "SCARCE_GOODS" or "PLENTIFUL_GOODS" flags in shipdata.plist->cargo_carried

This was all created this way, before we had JS. Maybe the probing of a ship with this JS properties should also generate that cargo. But than you run the risk when a filter function search the entire system for ships with cargo properties, it would create cargo for each ship. So, probably not a good idea to change the current behaviour. We just have to live with the fact that a empty cargo bay may eject stuff :roll:
User avatar
Kaks
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 3009
Joined: Mon Jan 21, 2008 11:41 pm
Location: The Big Smoke

Post by Kaks »

With any luck it might not be too much of a headache to create the ship's cargo only if the js cargo properties are accessed. That would make the ooniverse & these js properties consistent with each other without too many drawbacks...

I'll see what I can do! ;)

Kaks.
Hey, free OXPs: farsun v1.05 & tty v0.5! :0)
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:

Post by Commander McLane »

I did a small test. I added this code to route1traderAI

Code: Select all

    "CHECK_CARGO" =     {
        ENTER =         (
            "pauseAI: 1.0",
            checkForFullHold
        );
        "HOLD_FULL" =         (
            "commsMessage: My hold is full!"
        );
        "HOLD_NOT_FULL" =         (
            "commsMessage: Still room in here."
        );
        "NO_CARGO_BAY" =         (
            "commsMessage: Sorry, I don't have a cargo bay."
        );
        UPDATE =         (
            "setStateTo: HEAD_FOR_PLANET"
        );
    };
    GLOBAL =     {
        ENTER =         (
            "setStateTo: CHECK_CARGO"
        );
    };
Then I waited at the witchpoint and made the main station launch a lot of traders, waiting for those which would enter at the witchpoint. I was hoping to get a sample of messages in my log, and get an idea about the distribution of full and empty holds.

The result: nothing whatsoever, nada, rien. Not a single ship sent a commsMessage, altough I could confirm with the JS console that they all went through the CHECK_CARGO state.

The conclusion: the checkForFullHold-method doesn't do anything for entering traders. It may be that it is disabled for ships with role "trader". Or it may be that—like with pirates—the variable which has to be queried only begins to exist after the ship has scooped something. (Note that the checkForFullHold-method in pirateAI is only performed after scooping something, not before.) But there is also no error message in the log.

The result: currently checkForFullHold is useless as a decision-making method for entering traders.

EDIT: Okay, my fault, bad AI scripting. The UPDATE message was received too early, thereby changing the state before the hold-related messages were received. Running another test right now, will report on results later.
Last edited by Commander McLane on Fri Nov 19, 2010 1:09 pm, edited 1 time in total.
User avatar
Eric Walch
Slightly Grand Rear Admiral
Slightly Grand Rear Admiral
Posts: 5536
Joined: Sat Jun 16, 2007 3:48 pm
Location: Netherlands

Post by Eric Walch »

Commander McLane wrote:
I did a small test. I added this code to route1traderAI

Code: Select all

    "CHECK_CARGO" =     {
        ENTER =         (
            "pauseAI: 1.0",
            checkForFullHold
        );
        "HOLD_FULL" =         (
            "commsMessage: My hold is full!"
        );
        "HOLD_NOT_FULL" =         (
            "commsMessage: Still room in here."
        );
        "NO_CARGO_BAY" =         (
            "commsMessage: Sorry, I don't have a cargo bay."
        );
        UPDATE =         (
            "setStateTo: HEAD_FOR_PLANET"
        );
    };
    GLOBAL =     {
        ENTER =         (
            "setStateTo: CHECK_CARGO"
        );
    };
Then I waited at the witchpoint and made the main station launch a lot of traders, waiting for those which would enter at the witchpoint. I was hoping to get a sample of messages in my log, and get an idea about the distribution of full and empty holds.

The result: nothing whatsoever, nada, rien. Not a single ship sent a commsMessage,
That is because the AI is wrong. In ENTER the messages are generated. Than in UPDATE the state is set to "HEAD_FOR_PLANET" and the messages are evaluated. But the state is already in HEAD_FOR_PLANET, so the messages should be in HEAD_FOR_PLANET. But easier would be to not use UPDATE at all:

Code: Select all

    GLOBAL =     {
        ENTER =         (
            "setStateTo: CHECK_CARGO"
        );
    "CHECK_CARGO" =     {
        ENTER =         (
            "pauseAI: 1.0",
            checkForFullHold
        );
        "HOLD_FULL" =         (
            "commsMessage: My hold is full!",
            "setStateTo: HEAD_FOR_PLANET"
        );
        "HOLD_NOT_FULL" =         (
            "commsMessage: Still room in here.",
            "setStateTo: HEAD_FOR_PLANET"
        );
        "NO_CARGO_BAY" =         (
            "commsMessage: Sorry, I don't have a cargo bay.",
            "setStateTo: HEAD_FOR_PLANET"
        );
    };
Because checkForFullHold always generates a message, you'll always go to the next state.
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:

Post by Commander McLane »

Eric Walch wrote:

Code: Select all

    GLOBAL =     {
        ENTER =         (
            "setStateTo: CHECK_CARGO"
        );
    "CHECK_CARGO" =     {
        ENTER =         (
            "pauseAI: 1.0",
            checkForFullHold
        );
        "HOLD_FULL" =         (
            "commsMessage: My hold is full!",
            "setStateTo: HEAD_FOR_PLANET"
        );
        "HOLD_NOT_FULL" =         (
            "commsMessage: Still room in here.",
            "setStateTo: HEAD_FOR_PLANET"
        );
        "NO_CARGO_BAY" =         (
            "commsMessage: Sorry, I don't have a cargo bay.",
            "setStateTo: HEAD_FOR_PLANET"
        );
    };
    };
Because checkForFullHold always generates a message, you'll always go to the next state.
Yes, found that out as well and repeating the test right now with exactly the same change applied.
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:

Post by Commander McLane »

And the preliminary results are in, and I can say that we have a clear trend:

With the re-tweaked AI I made the main station launch 20 traders.
After waiting at the witchpoint for a considerable amount of time I counted 17 entering traders.
Out of these 17 three went sunskimming, so they got assigned route2sunskimAI by the engine and didn't send a message at all.
Each of the remaining 14 proudly informed me that he still had room.

Interpretation: I think it is safe to say that all entering traders get the HOLD_NOT_FULL message, and no traders "with full holds" are created.

Result: even the fact that the checkForFullHold method works doesn't change the result. As it always returns the same, it is still useless as a decision-making method for entering traders.

Fun fact: the gang of pirates who were obviously lurking a little distance in-system were really having some windfall profits from all the traders I sent to them. :wink: I came across a lot of cargo canisters when I headed for the planet. :D
Last edited by Commander McLane on Fri Nov 19, 2010 1:53 pm, edited 1 time in total.
Switeck
---- E L I T E ----
---- E L I T E ----
Posts: 2412
Joined: Mon May 31, 2010 11:11 pm

Post by Switeck »

Great...Oolite's cargo for traders (and probably pirates too) is literally:
http://en.wikipedia.org/wiki/Schr%C3%B6dinger%27s_cat
...in neither an "alive" or "dead" state.

The cargo hold is neither empty nor full nor can it even be said to not exist! It is at best an undefined concept with no states even after a new trader has spawned.

Which means I cannot use checkForFullHold for branching conditions until AFTER I put something in it.
But not using that check initially means even an Asp might scoop cargo. (Well fortunately Asps are not traders, so at least that's avoided.)
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:

Post by Commander McLane »

Switeck wrote:
But not using that check initially means even an Asp might scoop cargo. (Well fortunately Asps are not traders, so at least that's avoided.)
Don't know. Do they have scoops as a default?
Switeck
---- E L I T E ----
---- E L I T E ----
Posts: 2412
Joined: Mon May 31, 2010 11:11 pm

Post by Switeck »

Usually they do:
(from shipdata.plist)

Code: Select all

	"asp" =
	{
...
		has_scoop = 0.99;
...
		roles = "hunter pirate asp-pirate";
But fortunately, trader is not one of their roles...nor is sun-skimming.
They could be shanghai'ed into a trader or sun-skimming role by an OXP, but at least that won't be my fault. :P

I'm not totally sure they won't be automatically treated as "NO_CARGO_BAY" by checkForFullHold, since that wouldn't require "knowing" what cargo they did/didn't have.

I've already got a route1traderAI.plist script that seems to work...it's just not working the way my assumptions thought it would. No matter, I already know how to kill this cat and keep it dead. :twisted:
User avatar
Smivs
Retired Assassin
Retired Assassin
Posts: 8408
Joined: Tue Feb 09, 2010 11:31 am
Location: Lost in space
Contact:

Post by Smivs »

And weirdly, they sometimes do carry cargo...the one I killed yesterday left me a ton of food :roll:
Commander Smivs, the friendliest Gourd this side of Riedquat.
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:

Post by Commander McLane »

Hm. I've tried to follow pirateAI (which has become rather complex), and it seems my initial assumption was wrong. There is a checkForFullHold performed before actually scooping, at least in some cases, and there is a HOLD_FULL-message in the COLLECT_LOOT state, however it seems the check must have been performed in the previous state.

The AI really is rather complex.
Post Reply