Scripters cove

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

Moderators: another_commander, winston

User avatar
Thargoid
Thargoid
Thargoid
Posts: 5525
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »

Thanks, for that. Seems the post updated since I first looked!

Anyway I tried the following AI for the drone:

Code: Select all

{
    "ATTACK_SHIP" = {
        ENTER = (performAttack); 
        "THARGOID_DESTROYED" = ("setStateTo: CHECK_FOR_CONTROL"); 
        "TARGET_DESTROYED" = ("setStateTo: LOOK_FOR_TARGETS"); 
        "TARGET_LOST" = ("setStateTo: LOOK_FOR_TARGETS"); 
        UPDATE = ("scanForNearestShipHavingRole: thargoid-mothership", "pauseAI: 5.0"); 
        "NOTHING_FOUND" = ("setStateTo: CHECK_FOR_CONTROL"); 
        EXIT = (); 
    }; 
    "CHECK_FOR_CONTROL" = {
        "THARGOID_DESTROYED" = ("setStateTo: CHECK_FOR_CONTROL"); 
		"TARGET_FOUND" = ("setStateTo: LOOK_FOR_TARGETS"); 
		"NOTHING_FOUND" = (becomeUncontrolledThargon); 
		ENTER = ("setSpeedTo: 0.0", performTumble);
		EXIT = ();
		UPDATE = ("scanForNearestShipHavingRole: thargoid-mothership", "pauseAI: 1.0");
	}; 
    "LOOK_FOR_TARGETS" = {
        "THARGOID_DESTROYED" = ("setStateTo: CHECK_FOR_CONTROL"); 
		"TARGET_FOUND" = (setTargetToFoundTarget, "setStateTo: ATTACK_SHIP"); 
		ENTER = (scanForNonThargoid, "pauseAI: 1.0");
		EXIT = ();
		UPDATE = ("scanForNearestShipHavingRole: thargoid-mothership", "pauseAI: 10.0");
	}; 
    GLOBAL = {ENTER = ("setStateTo: LOOK_FOR_TARGETS"); EXIT = (); UPDATE = (); }; 
}


If I just spawn a drone, it works and shuts itself down properly (doesn't attack anything, but doesn't really have time to). However if I spawn the mothership (with 2 drone escorts as part of it's shipdata) and kill the ship, the drones just fly around doing nothing and stay active. In both cases the drones don't actually do anything aggressive at all. The ship has a role of "thargoid-mothership", as ideally I'd like the controller and the Thargoid warships to be able to interchangably control Thargons (so a warship could spawn a controller (minus escorts or additional thargons) as a death action, to keep the fight going).

I think I need to look into TFM a little more and get by brain around the workings and flow routes through AI's, and exactly which points the codes in ENTER, EXIt and UPDATE actually occur. But not at the moment, as it's well gone midnight here...

Will also try your second code and the missile option tomorrow too...
Last edited by Thargoid on Thu Sep 25, 2008 8:45 pm, edited 1 time in total.
User avatar
LittleBear
---- E L I T E ----
---- E L I T E ----
Posts: 2866
Joined: Tue Apr 04, 2006 7:02 pm
Location: On a survey mission for GalCop. Ship: Cobra Corvette: Hidden Dragon Rated: Deadly.

Post by LittleBear »

Because you are calling them as escorts, Oolite will over-ride your custom AI and give them the native escortAI. To get round this you'd need to set auto_ai to false in shipdata and give them a modded escort AI. Same wheeze, copy the native escortAI and tweak it a bit to add a check for THARGOID_DESTROYED into its states.
OXPS : The Assassins Guild, Asteroid Storm, The Bank of the Black Monks, Random Hits, The Galactic Almanac, Renegade Pirates can be downloaded from the Elite Wiki here.
User avatar
Thargoid
Thargoid
Thargoid
Posts: 5525
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »

I've tried the code below, modded from the escortAI and with auto_ai set false in the drone shipdata. It works in terms of making them go inactive once the mothership is dead, but the drones don't do anything aggressive (inspite of copious performAttack commands).

I think I need the next step in AI for Aliens, as I'm obviously doing something wrong (even after reviewing the wiki entries), but I'm not sure what. Oh and sorry for being a pain with all this!

Code: Select all

{
    "FLYING_ESCORT" = {
        ENTER = (performEscort); 
        "GROUP_ATTACK_TARGET" = (setTargetToFoundTarget, performAttack); 
        RESTARTED = ("setStateTo: BEGIN_BUSINESS");
		ESCORTING = ("setDesiredRangeTo: 0.0", performEscort);
        "INCOMING_MISSILE" = ("messageMother: INCOMING_MISSILE"); 
        "ATTACKED" = ("messageMother: ATTACKED"); 
        "NOT_ESCORTING" = ("setStateTo: LOOK_FOR_BUSINESS"); 
        "TARGET_LOST" = ("setStateTo: LOOK_FOR_BUSINESS"); 
        "TARGET_DESTROYED" = ("setStateTo: LOOK_FOR_BUSINESS"); 
		"ENTER WORMHOLE" = ("setStateTo: ENTER_WORMHOLE");
		EXIT = ();
        UPDATE = (escortCheckMother, "pauseAI: 15"); 
    }; 
    "BEGIN_BUSINESS" = {
		"LAUNCHED OKAY" = ("setStateTo: CLEAR_STATION");
        ATTACKED = (setTargetToPrimaryAggressor, performAttack);
        ENTER = (escortCheckMother); 
        EXIT = ();
		ESCORTING = ("setDesiredRangeTo: 0.0", "setStateTo: FLYING_ESCORT");
        "NOT_ESCORTING" = ("setStateTo: CHECK_FOR_CONTROL");
        UPDATE = (escortCheckMother, "pauseAI: 7.5"); 
    }; 
    "ENTER_WORMHOLE" = {
		ENTER = (setDestinationToTarget, "setDesiredRangeTo: 1.0", "setSpeedFactorTo: 1.0", performFlyToRangeFromDestination);
		"PLAYER WITCHSPACE" = (enterTargetWormhole);
        UPDATE = (); 
		EXIT = ();
    }; 
    "CLEAR_STATION" = {
		ENTER = (setTargetToStation, setDestinationWithinTarget, "setDesiredRangeTo: 8000.0", "setSpeedFactorTo: 0.5", performFlyToRangeFromDestination);
		"DESIRED_RANGE_ACHIEVED" = ("setStateTo: LOOK_FOR_BUSINESS");
        UPDATE = (scanForFormationLeader, "pauseAI: 15.0"); 
        "TARGET_FOUND" = (setTargetToFoundTarget, suggestEscort); 
  		ESCORTING = ("setDesiredRangeTo: 0.0", "setStateTo: FLYING_ESCORT");
		EXIT = ();
    }; 
    "LOOK_FOR_BUSINESS" = {
		"LAUNCHED OKAY" = ("setStateTo: CLEAR_STATION");
        ATTACKED = (setTargetToPrimaryAggressor, performAttack);
        RESTARTED = ("setStateTo: BEGIN_BUSINESS");
        ENTER = (scanForFormationLeader); 
        EXIT = ();
		ESCORTING = ("setDesiredRangeTo: 0.0", "setStateTo: FLYING_ESCORT");
        "TARGET_FOUND" = (setTargetToFoundTarget, suggestEscort); 
        "NOTHING_FOUND" = ("setStateTo: CHECK_FOR_CONTROL"); 
        UPDATE = ("pauseAI: 7.5", scanForFormationLeader); 
    }; 

    "CHECK_FOR_CONTROL" = {
        "THARGOID_DESTROYED" = ("setStateTo: CHECK_FOR_CONTROL"); 
		"TARGET_FOUND" = ("setStateTo: LOOK_FOR_BUSINESS"); 
		"NOTHING_FOUND" = (becomeUncontrolledThargon); 
		ENTER = ("setSpeedTo: 0.0", performTumble);
		EXIT = ();
		UPDATE = ("scanForNearestShipHavingRole: thargoid-mothership", "pauseAI: 1.0");
	}; 
    GLOBAL = {ENTER = ("setStateTo: BEGIN_BUSINESS"); EXIT = (); UPDATE = (); }; 
}
[/color]
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 »

Thargoid wrote:
It works in terms of making them go inactive once the mothership is dead, but the drones don't do anything aggressive (inspite of copious performAttack commands).
Writing a good escort AI is quite difficult. One important thing with escorts is that they are a kind of drones. escorts don't act by themselves. Normally they fly in the "FLYING_ESCORT" state. When they are attacked they react with:  "ATTACKED" = ("messageMother: ATTACKED"); Meaning it does nothing else than to tell their mother they are attacked. Normal AI routines initiate an attack on this point, escorts only brief their mother.

Escorts only react on a groupAttackTarget command issued by their mother. (Or alternatively a deployEscorts but the first would be better as deployEscorts sets them in an interceptAI.plist and you loose complete control with scripting e.g.: no check_control).
User avatar
Thargoid
Thargoid
Thargoid
Posts: 5525
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »


Eric - That makes things somewhat clearer. So if I want to use the escort way of doing this, I need to tweak the mother's AI as well (currently just the normal thargoidAI.plist). I presume just change "performAttack" in the "ATTACK_SHIP" state to "groupAttackTarget", or are both needed? I also presume deployescorts wouldn't be needed anyway as they're already existing objects, I'm not thinking of having the controller as a dockable entity.

LB - Thanks for the code. Unfortunately when I tried it as the controller's AI, it doesn't seem to work. It just sits there, not launching anything at all (it's shipdata has it set up with 5 missiles, with missile_role set as thargon (same as a standard warship)...

I just tried something else, to spawn a controller (with LB's AI for the moment) and then afterwards spawned 5 normal thargons (the standard ones from the game plists). All appeared, but the thargons again didn't attack me. A system vessel turned up and they proceeded to have a fight, but am I missing something here? As they were spawned rather than generated as a missile, is that causing the lack of aggression?

I'm still trying to work out the best way to generate them (spawn, escort or missile), all routes seem to be giving me problems one way or another! It's a fun exercise though, although I'm getting a little tired of having to keep re-booting Oolite with all the code changes :twisted:

User avatar
Thargoid
Thargoid
Thargoid
Posts: 5525
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »


A "good news" update, it's now working :D

The controller is flying under a slightly modified thargoidAI (added the groupAttackTarget in before the performAttack as noted above), and the drones (tweaked thargons) under the drone AI I posted before, using the escorts configuration (and the missiles too).

I set the controller up with 2 escort drones and 5 missile-drones, and the 2 appeared firing (as did the mother controller), and after a bit of zapping the controller launched it's 5 other ones. All 7 went inactive after the controller was destroyed. So I've now gone from neither way working to both ways working :oops: But a definite improvement.

Once again thanks to you both for the inputs (again), progress definitely underway here!
User avatar
LittleBear
---- E L I T E ----
---- E L I T E ----
Posts: 2866
Joined: Tue Apr 04, 2006 7:02 pm
Location: On a survey mission for GalCop. Ship: Cobra Corvette: Hidden Dragon Rated: Deadly.

Post by LittleBear »

If your using the native ThargoidAI tweaked, throwing in a few fireMissile Commands at part of its ATTACK_SHIP state should get it launching. Just an "ATTACKED" = "fireMissile"; should do it. Every time a beam hits it should cause a launch and throw one in under ENTER should get a bird in the air when it enters the ATTACK_SHIP state. If you wanna have a look at the RandomHitsMark3AI.plist I've thrown in a few fireMissile commands and in play it has the effect of the ship spewing out a few Worms when it first spots the player and launches more if the player (or anybody else) attacks it. As the native ThargoidAI always attacks when it detects any NonThargoid (including the player naturally), throwing in fireMissile under entry and update should get it launching as soon as it spots humans. You might also (not totally sure about this) need an auto_ai false in the drone's shipdata entry as well, to make sure it doesn't get treated as a missile.
OXPS : The Assassins Guild, Asteroid Storm, The Bank of the Black Monks, Random Hits, The Galactic Almanac, Renegade Pirates can be downloaded from the Elite Wiki here.
User avatar
Thargoid
Thargoid
Thargoid
Posts: 5525
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »


I've decided to make 2 versions, one with 5 thargons and one with 10. For the 5, I'm just using the escort configuration, so they're basically all there at the start of the encounter.

For the 10 version, as having all 10 present at once would be a little excessive I think, I'm using the 5 as above, but 5 others set up as missiles (without any fireMissile modifications to the AI's). Hence if the player (or whoever) zaps the 5 and then the controller, it will generate a second wave of 5 as per a normal thargoid (unless it gets nuked before it can launch of course).

I'm using the modified ThargoidAI on the mothership (the controller) to give it the escort actions, and for the drone it's a merged escort and thargon AI that I posted up before (with the auto_ai false command in the drone ship data based on previous suggestions), although I may adjust that a little more as there's something I'm pondering for them as a sting in the tail... :twisted:

All good fun though, it's interesting getting the ol' noggin around this coding, been a while since I did this kinda thing.
User avatar
Lestradae
---- E L I T E ----
---- E L I T E ----
Posts: 3095
Joined: Tue Apr 17, 2007 10:30 pm
Location: Vienna, Austria

..

Post by Lestradae »

I do have a probably stoopid question ...

Noticed that java scripts in oxps sometimes are in the Config folder as "script.js", sometimes they are in a folder of their own "Scripts" with names of their own (i.e. "myfunny_thargoid.js").

Is there a reason for that? Are those different java scripts, or just two ways to do the same thing?

Please, when answering, keep in mind L´s utter scripting-noobness :(

:?:

L
User avatar
Svengali
Commander
Commander
Posts: 2370
Joined: Sat Oct 20, 2007 2:52 pm

Re: ..

Post by Svengali »

Lestradae wrote:
Noticed that java scripts in oxps sometimes are in the Config folder as "script.js", sometimes they are in a folder of their own "Scripts" with names of their own (i.e. "myfunny_thargoid.js").

Is there a reason for that? Are those different java scripts, or just two ways to do the same thing?
They are the same.

If your oxp has only one worldScript then you can use the script.js in the Config-folder. This script.js is automatically identified as worldScript, so you don't have to tell Oolite that point. But if your oxp is splitted into a few worldScripts (like Erics UPS-Courier) then you have to use the other way. Here it is not enough to put the scripts in the Scripts-folder, you also have to declare a world-scripts.plist in your Config-folder. This file contains then the names of your worldScripts.

I'm prefering the second variant, because it gives you more flexibility for later changes and you have all JS-files (worldScripts and shipScripts) in one folder.
User avatar
Thargoid
Thargoid
Thargoid
Posts: 5525
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »

A quick comment/request about java scripts, for those doing all the lovely new coding.

We're beginning to have some OXPs which interact with each other (Svengali et al's OXPConfig and my own Repair Nanobots for two immediate examples). In both cases these link to the other OXP JS code using the this.name header in the JS script as an identifier (in my case via worldScripts).

So just to make people aware that if an OXP is set up to "interact" with either OXP, if during an update or even just an idle tinkering the entry in this.name changes, then the linkage won't work any more and spurious results and errors may occur.

Hence this is a little request to forewarn everyone that in some cases making alterations to the script's this.name may have consequences. You may all know this anyway, but just wanted to put it up somewhere for reference in case either people don't or new people come over to the dark side :twisted:
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 »

Thargoid wrote:
A quick comment/request about java scripts, for those doing all the lovely new coding. :twisted:
Keeping the same name is not only important for JS scripts, but also for old style Legacy Scripts. The main level names in a "script.plist" are added to the list of worldScripts. With JS you can't do much with it, but you can see if a legacy script exists.

This can be very useful when a JS scripts uses ships from other oxp's. I do it in BehemothSpacewar.oxp. There I test if both oxp's I rely upon are present. If not, I add a replacement ship from Oolite's internal ship-set. A_H gave at some point the thargorn_treath legacy script a new script name. (from: thargoid_witchspace_test to thargoid_witchspace_Battle) That change spoiled my test for it's presents.

Iit would also be useful when legacy gets translated to JS they keep the same scriptname. e.g. Transports.oxp has changed the script name after translation. (Only the casing, but that already counts as a new name).
UPS.oxp (and also the next buoyRepair.oxp release) will use the fueltanker from transports.oxp when installed. Because the changed names I have to test both names.
User avatar
Thargoid
Thargoid
Thargoid
Posts: 5525
Joined: Thu Jun 12, 2008 6:55 pm

Post by Thargoid »

Quick question. Are the other targets in the multi-target system equipment actually available for JS scripting (the ones you cycle through with + and -)?

For the suggestion for expanding the scanning via a probe or something similar, but this is the basic requirement if that would be a possible new bit of equipment...
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 »

Bug in JS?

Svengali brought to my attention that:

Code: Select all

this.s = 0; this.s +=4; this.s++;  
results in 4 while the outcome should be 5.

Or in detail, when you type:

Code: Select all

this.s = 0; this.s = this.s + 4;
and ask for the value of this.s you get 4. This is okay but when you do a further this.s++ the answer stays 4. When doing another this.s++ the answer becomes 5.

Same is happening with:

Code: Select all

let s = 0; s += 4; s++;
result = 4

Is this a bug in the JS script? Or is it introduced by the console? Or don't I understand JS after all.
User avatar
JensAyton
Grand Admiral Emeritus
Grand Admiral Emeritus
Posts: 6657
Joined: Sat Apr 02, 2005 2:43 pm
Location: Sweden
Contact:

Post by JensAyton »

This is actually expected behaviour (inherited from C). The value of the expression x++ is the value of x before incrementing (analogously for x--). The expression ++x yields the value after incrementing. So:
> this.s = 0
0
> this.s += 4
4
> this.s++
4
> this.s
5 // note value actually changed
but
> this.s = 0
0
> this.s += 4
4
> ++this.s
5
> this.s
5
Post Reply