Just when I thought I was out...

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

Moderators: another_commander, winston

User avatar
Griff
Oolite 2 Art Director
Oolite 2 Art Director
Posts: 2478
Joined: Fri Jul 14, 2006 12:29 pm
Location: Probably hugging his Air Fryer

Post by Griff »

Hi Roberto
I'll PM you me email address if you want to send the images over, there shouldn't be a problem splitting up the image and recombining them.
I've downloaded GIMP and had a quick look at it, it looks quite powerful.
The channel menu if off by default though, so to enable it, click on the tiny little triangle icon above the colour selector ( it's to the right of the letters FB/BG Color in your screen shot). this should bring up a menu with an 'Add tab' option. select this and then select Channels from the submenu. You should now get a new icon allowing you to work on the RGB channels in the image.


You can now switch off channel visibility by clicking the 'eye' icon and work on seperate colour channels by selecting their name.

Image

In the screen shot above, i've selected the Red channel so any paining i do will only occur in the red channel, I've also switched off the visibility for the green channel whilst leaving the blue channel visible.

Take care when you're selecting channels that you don't accidentally keep selected ones that you don't want to effect by accident.
User avatar
Roberto
---- E L I T E ----
---- E L I T E ----
Posts: 318
Joined: Sun Jun 11, 2006 1:16 pm
Location: London, UK

Post by Roberto »

Griff, you're a star :) Thanks very much. I'll give it a full try in a bit - I'm AI-ing atm :)
User avatar
Captain Hesperus
Grand High Clock-Tower Poobah
Grand High Clock-Tower Poobah
Posts: 2312
Joined: Tue Sep 19, 2006 1:10 pm
Location: Anywhere I can sell Trumbles.....

Post by Captain Hesperus »

Roberto wrote:
if no one knows how to solve my GIMP problems (as it were),
Hee, hee, hee! He said 'gimp problems'......

<stands up, gets coat and sneaks out side door>

Captain Hesperus
The truth, revealed!!
Image
User avatar
Roberto
---- E L I T E ----
---- E L I T E ----
Posts: 318
Joined: Sun Jun 11, 2006 1:16 pm
Location: London, UK

Post by Roberto »

I did indeed. You can't move for gimps around here... :)

So, having sidestepped onto the AI/traffic stuff for the moment, I could use some advice. I'm going to have four types of ships:

1. Those that launch from the HQ and fly to/dock at the system station, or hyperspace out
2. Those that launch from the HQ and fly to/dock at the system station (for non-hyperspace-capable ships)
3. Those that appear at the witchpoint and fly to/dock at the HQ
4. Those that launch from the system station and fly to/dock at the HQ

Types 1 and 2 are no problem (well, I don't envisage any problems). Type 3 I'm thinking should be done within a script, with dice-rolling triggering the occasional appearance of a ship while you're in the system. Type 4... I'm not sure about. Is there a way to get the system station to launch a specific ship type?
User avatar
LittleBear
---- E L I T E ----
---- E L I T E ----
Posts: 2867
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 »

On 4, not directly. But you could set the local main station to "tanaris_dodec" in planetinfo. (or whatever type of station is normally there). Then like_ship a dodec but give it the role "tanaris_dodec" and customAI. The custom AI could just be a renamed StationAI, but with a "launchShipWithRole:" to make it launch one of the special ships every so often. (This is how Asteroid Storm OXP detects the destruction of the Main Station in the mission. Its a clone of the normal station but with death actions. Only the doomsday asteroid can destroy it).
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
Roberto
---- E L I T E ----
---- E L I T E ----
Posts: 318
Joined: Sun Jun 11, 2006 1:16 pm
Location: London, UK

Post by Roberto »

Thanks, LB - that'd do it :)

This is what I'm thinking of for type 3, btw:

Code: Select all

taranis_traffic_witchpoint = (
	{
		conditions = (
			"galaxy_number equal 0",
			"planet_number equal 141",
			"d256_number equal 0"
            	); 
	         do = (
				{
				conditions = (
				"d256_number equal 0"
	            		); 
	            		do = (
		  			{
					conditions = (
					"d256_number equal 0"
	 	           		); 
		            		do = (
		  				{
						conditions = (
						"d100_number lessthan 50"
	 	           			); 
		            			do = (
						"addShips: taranis_traffic3 1"
		 	           		); 
						},
		  				{
						conditions = (
						"d100_number lessthan 5"
		 	           		); 
			            		do = (
						"addShips: taranis_traffic3 2"
		 	           		); 
						},
		  				{
						conditions = (
						"d100_number lessthan 5"
		 	           		); 
			            		do = (
						"addShips: taranis_traffic3 3"
		 	           		); 
						}
		 			); 
					},
		 		); 
				},
		 ); 
	},
); 
I'm guessing that Oolite reads and re-reads scripts pretty fast, so I need to ensure the dice odds are very low. I haven't inserted the code yet - does it seem reasonable? Also, should I slot it in between the final ); concluding taranis_one and the } right at the end?
User avatar
LittleBear
---- E L I T E ----
---- E L I T E ----
Posts: 2867
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 its read within system, I think it'll soon have the system filled up with ships. The SpaceBar AI has about ten states that it ficks though whilst ideal. In testing I put "sendCommsMessage: I'm in State1" etc to check what it was doing, and it seemed to be scanning though all states in less than a second, so I'guess it'd hit even low probablity numbers pretty fast. Could do it by like_shiping a boulder and spawn the special boulder way outside the space lane. Then give it an AI that had a long pause (say 3 minutes), then went to a d rolling state that that added system ships on a particular role then reset to the pause state again.

PS: Also discovered with random hits that as Oolite (like all computer games) uses a random seed rather than a true dice role, if you are using it a lot pattens soon come up. The seed is reset on making a H jump, but this may mean on some jumps getting lots of hits on what should be a low probablity number. The Random Hits Adverts build adverts with dice rolls, but as each advert has about 20 rolls, you can't display more than six without the first one being the same as the first. Got round this by just limiting the adverts to 6 at any one time. When the player H jumps the dice get re-rolled and a different set of adverts appear when he returns to the system.
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
Roberto
---- E L I T E ----
---- E L I T E ----
Posts: 318
Joined: Sun Jun 11, 2006 1:16 pm
Location: London, UK

Post by Roberto »

Interesting - I didn't know you could use addShips in an AI. What I might do in that case is add an indestructible billboard with a cunning secondary purpose :) Thanks again, LB - I suspect you've saved me hours of fruitless endeavour :)

Dr Nil - would you mind me incorporating your billboard? :) You'll get a couple of Outrider ads out of it, when I can find the time to do them :)

*EDIT* Having added a billboard quickly for testing purposes, I'm wondering how I can make the thing rotate (in a buoy-like fashion). I've tried giving it a "buoy" role (with a low probability) and a CLASS_BUOY scanClass, and I looked at the Buoy AI to see if there was anything I needed to add to mine (performIdle is about all it does). What am I missing?

This is the AI I've given it:

Code: Select all

{ 
    GLOBAL = { 
        ENTER = (performIdle); 
        EXIT = (); 
        "ROLL_1" = ("addShips: taranis_traffic3 1");
	UPDATE = ("rollD: 5000"); 
    }; 
}
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 »

As for making something rotate: insert the shipdata-key <key>rotating</key><true/>.

As for adding your type3-ships, half of 256^3 seems a fairly low probability to me. Legacy-scripts are executed every 10 seconds, so one of these ships should be launched roughly every 83,886,080 seconds, so after more than 23,301 hours of continuous gameplay!

Probably you don't need to do anything here. When I for testing purposes placed a station of mine quite close to the main station, I got ships coming over from the main station all the time. But I guess the probability for that shrinks with distance.
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 »

Roberto wrote:
Thanks, chaps - that Debug OXP is very handy!
Oh, good. It’s nice to have an indication of someone actually using it. Next I’ll get a bug report for -verify-oxp and my happiness will be complete. :-)
@Shader experts
In the absence of any feedback (so far) on my shading questions,
Hmm, where were those, then?
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 »

McLaine wrote:
As for adding your type3-ships, half of 256^3 seems a fairly low probability to me. Legacy-scripts are executed every 10 seconds, so one of these ships should be launched roughly every 83,886,080 seconds, so after more than 23,301 hours of continuous gameplay!
NO! Don't trust on the time of 10 seconds between updates. Set the current time in a local_variable and check if a certain time has past. This is the only save way to do timing. When you have for instance an AI script that includes a "scriptActionOnTarget" in the system than will this command also start the running of all available OXP legacy scripts. And there could be some that use this command often. The new one of little bear does it even a lot. That means you could get much more than just every ten secs.

Code: Select all

{ 
    GLOBAL = { 
        ENTER = (performIdle); 
        EXIT = (); 
        "ROLL_1" = ("addShips: taranis_traffic3 1"); 
   UPDATE = ("rollD: 5000"); 
    }; 
}
better include a pause and raise the probability. The system tries to update the AI every 0.125 seconds. But when it is busy it could take longer, specially on slower computers. When setting pauseAI: to 1.0 or even higher when this is possible, the timing is more reliable and constant with different systems.
Roberto wrote:
4. Those that launch from the system station and fly to/dock at the HQ
Maybe you could give one of your ships that goes to the main station a special AI that issues a command: "scriptActionOnTarget: launchShipWithRole: my_ship" before starting the docking procedure. This makes also sure the number of ships in the system does not change by this action. (Never tried it but I see not why it should not 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

Post by Eric Walch »

The situation described in my last post worked. I added next test state to my test AI.

Code: Select all

    WAIT_FOR_SHOT = {
        ENTER = (setTargetToStation); 
        EXIT = (); 
        ATTACKED = ("scriptActionOnTarget: launchShipWithRole: behemoth"); 
    UPDATE = ("commsMessage: Hello player, ready for action?", "pauseAI: 2"); 
    }; 

On shooting my testship a few times, the behemoth's were added to the launch que and one after the other launched from the station. Amazing to see them squeeze through the bay.

I just took this ship to be sure it was not system generated. Or could they?
User avatar
Roberto
---- E L I T E ----
---- E L I T E ----
Posts: 318
Joined: Sun Jun 11, 2006 1:16 pm
Location: London, UK

Post by Roberto »

@Ahruman
I basically wanted to know whether I could use the shaders in Griff's Illuminated Docking Bay for my own station, and also how to create an "illumination map". I think I know what I'm doing now, but I've moved onto the AI side of things for the time being.

@Commander McLane
Nailed the rotation :) Had to do some quaternion calculus:

Code: Select all

		<key>rotating</key>
		<true/>
		<key>rotational_velocity</key>
		<string>0.9987820251 0.0348782369 -0.0012179749 0.0348782369</string>
That makes it double-rotate just as the other ad boards/buoys do, only much slower, which I think is cool :)

@Eric Walsh
I bow to your knowledge - I didn't get a chance to do much tonight, but I'll insert pauses as you suggest.

I'm not really bothered about keeping the number of ships in the system constant (as long as it doesn't get ridiculous) - in fact, I'd prefer it if sometimes when you visit there's not much going on, and other times it's quite busy.

A big problem I've identified tonight is that the docking AI for my HQ's defence ships (which I essentially cribbed from the Behemoth OXP last year) isn't doing the job. I lured my test Frigate into hitting the HQ by mistake, thus triggering a response (that wouldn't be fatal to me!). After destroying the Frigate, the defence ship I was monitoring switched to the docking AI as intended, but promptly got stuck in "AWAIT_COORDS". Here's the AI in full (apologies for length of code):

Code: Select all

{
    "AWAIT_COORDS" = {
        ATTACKED = (setTargetToPrimaryAggressor, "setAITo: taranisDefenderAI.plist"); 
        "INCOMING_MISSILE" = (fightOrFleeMissile, setTargetToPrimaryAggressor, "setAITo: taranisDefenderAI.plist"); 
        "APPROACH_START" = ("setStateTo: GO_TO_START"); 
        "APPROACH_COORDINATES" = ("setStateTo: GO_TO_COORDS"); 
        "APPROACH_STATION" = ("setStateTo: GO_TO_STATION"); 
        "HOLD_POSITION" = (performIdle, "pauseAI: 10.0", "setStateTo: GLOBAL"); 
        "DOCKING_ABORTED" = ("setStateTo: ABORT"); 
        "TRY_AGAIN_LATER" = ("pauseAI: 30.0", "setStateTo: ABORT"); 
        "COLLISION" = ("setStateTo: ABORT"); 
        "GROUP_ATTACK_TARGET" = (setTargetToFoundTarget, "setAITo: taranisDefenderAI.plist"); 
        "RESTART_DOCKING" = ("setStateTo: GLOBAL"); 
        DOCKED = ("setStateTo: EXIT_SYSTEM"); 
        ENTER = (); 
        EXIT = (); 
        UPDATE = (); 
    }; 
    "EXIT_SYSTEM" = {ENTER = (performDocking, exitAI); EXIT = (); UPDATE = (); }; 
    ABORT = {
        ENTER = (abortDocking, "setSpeedFactorTo: 0.0", setDestinationToDockingAbort, "setDesiredRangeTo: 500.0", performFaceDestination); 
        "FACING_DESTINATION" = ("setSpeedFactorTo: 1.0", "setDesiredRangeTo: 500.0", performFlyToRangeFromDestination); 
        EXIT = (); 
        "RESTART_DOCKING" = ("setStateTo: GLOBAL"); 
        "REACHED_SAFETY" = (performIdle, "setStateTo: GLOBAL"); 
        "DESIRED_RANGE_ACHIEVED" = (performIdle, "setStateTo: GLOBAL"); 
        ATTACKED = (setTargetToPrimaryAggressor, "setAITo: taranisDefenderAI.plist"); 
        "INCOMING_MISSILE" = (fightOrFleeMissile, setTargetToPrimaryAggressor, "setAITo: taranisDefenderAI.plist"); 
        "GROUP_ATTACK_TARGET" = (setTargetToFoundTarget, "setAITo: taranisDefenderAI.plist"); 
        UPDATE = (); 
    }; 
    GLOBAL = {
        ENTER = ("setSpeedTo: 0.0", "setDesiredRangeTo: 5.0", requestDockingCoordinates, "setStateTo: AWAIT_COORDS"); 
        EXIT = (); 
        UPDATE = (); 
    }; 
    "GO_TO_WAYPOINT" = {
		ENTER = ("setDesiredRangeTo: 50.0", checkCourseToDestination);
		"COURSE_OK" = ("setSpeedFactorTo: 0.85", performFlyToRangeFromDestination);
		"WAYPOINT_SET" = ("setDesiredRangeTo: 50.0", checkCourseToDestination);
		"DESIRED_RANGE_ACHIEVED" = ("setStateTo: GO_TO_STATION");
        ATTACKED = (setTargetToPrimaryAggressor, "setAITo: taranisDefenderAI.plist"); 
        "INCOMING_MISSILE" = (fightOrFleeMissile, setTargetToPrimaryAggressor, "setAITo: taranisDefenderAI.plist"); 
        "GROUP_ATTACK_TARGET" = (setTargetToFoundTarget, "setAITo: taranisDefenderAI.plist"); 
		EXIT = ();
		UPDATE = ();
	}; 
    "GO_TO_START" = {
        ENTER = (
            "setSpeedFactorTo: 0.05",
			setDestinationFromCoordinates, 
            checkCourseToDestination
        );
		"WAYPOINT_SET" = ("setStateTo: GO_TO_WAYPOINT");
		"COURSE_OK" = ("setSpeedFactorTo: 0.25", performFaceDestination);
        "FACING_DESTINATION" = ("setDesiredRangeTo: 50.0", "setSpeedFactorTo: 0.85", performFlyToRangeFromDestination); 
        "DESIRED_RANGE_ACHIEVED" = (requestDockingCoordinates, "setStateTo: AWAIT_COORDS"); 
        "DOCKING_ABORTED" = ("setStateTo: ABORT"); 
        "COLLISION" = ("setStateTo: ABORT"); 
        "RESTART_DOCKING" = ("setStateTo: GLOBAL"); 
        ATTACKED = (setTargetToPrimaryAggressor, "setAITo: taranisDefenderAI.plist"); 
        "INCOMING_MISSILE" = (fightOrFleeMissile, setTargetToPrimaryAggressor, "setAITo: taranisDefenderAI.plist"); 
        "GROUP_ATTACK_TARGET" = (setTargetToFoundTarget, "setAITo: taranisDefenderAI.plist"); 
        EXIT = (); 
        UPDATE = ();
	};
    "GO_TO_COORDS" = {
        ENTER = (
            setDestinationFromCoordinates, 
            performFaceDestination
        );
        "FACING_DESTINATION" = ("setDesiredRangeTo: 50.0", "setSpeedTo: 100.0", performFlyToRangeFromDestination); 
        "DESIRED_RANGE_ACHIEVED" = (requestDockingCoordinates, "setStateTo: AWAIT_COORDS"); 
        "DOCKING_ABORTED" = ("setStateTo: ABORT"); 
        "COLLISION" = ("setStateTo: ABORT"); 
        "RESTART_DOCKING" = ("setStateTo: GLOBAL"); 
        ATTACKED = (setTargetToPrimaryAggressor, "setAITo: taranisDefenderAI.plist"); 
        "INCOMING_MISSILE" = (fightOrFleeMissile, setTargetToPrimaryAggressor, "setAITo: taranisDefenderAI.plist"); 
        "GROUP_ATTACK_TARGET" = (setTargetToFoundTarget, "setAITo: taranisDefenderAI.plist"); 
        EXIT = (); 
        UPDATE = ();
	};
    "GO_TO_STATION" = {
        ENTER = (
            setTargetToStation,
			setDestinationFromCoordinates, 
            performFaceDestination
        );
        "FACING_DESTINATION" = ("setDesiredRangeTo: 10.0", "setSpeedTo: 50.0", performFlyToRangeFromDestination); 
        "DESIRED_RANGE_ACHIEVED" = (requestDockingCoordinates, "setStateTo: AWAIT_COORDS"); 
        "DOCKING_ABORTED" = ("setStateTo: ABORT"); 
        "RESTART_DOCKING" = ("setStateTo: GLOBAL"); 
        "COLLISION" = ("setStateTo: ABORT"); 
        EXIT = (); 
        UPDATE = (); 
    }; 
}
Anything dodgy in there? As previously mentioned, the HQ doesn't have the "station" role - but then neither does the Behemoth.
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 »

Eric Walch wrote:
This is the only save way to do timing.
Wait, you found a fundamental flaw in the new timers, and didn’t tell me? :-)

Timers are only in 1.70, but they do provide a hopefully-safe way to do timing. It’s definitely more precise than any legacy script or AI method.

The way to use a JavaScript timer in conjunction with a script is to use sendScriptMessage: startTimer in the AI to call a script function, and ship.reactToAIMessage("TIMER_FIRED") to alert the AI when the timer has fired. For a one-shot timer, your JavaScript might look like this (untested):

Code: Select all

this.startTimer = function()
{
    // Called by AI to start a timer.
    this.aiTimer = new Timer(
        this,
        function() { delete this.aiTimer; this.ship.reactToAIMessage("TIMER_FIRED") },
        25 // seconds
    )
}
As Eric points out, scriptActionOnTarget: causes a “tickle” event, which runs all legacy scripts. As such, it has a lot of unnecessary overhead for most uses. From 1.70, using sendScriptMessage: to call one’s own ship script and do whatever needs doing from there is a more efficient approach.
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 »

Roberto wrote:
A big problem I've identified tonight is that the docking AI for my HQ's defence ships ..... but promptly got stuck in "AWAIT_COORDS". Here's the AI in full (apologies for length of code):
It misses a "APPROACH" message. That must have been in the original Behemoth code. But that code is old and misses some docking improvement Giles made later to the docking procedure. It mainly is not reacting well to exception situations. I spend several hours in figuring out how docking works. I wrote it down in: http://wiki.alioth.net/index.php/Docking_Instructions

I also wrote a better carrierAI and carierDockingAI. Both I included in the BehemothSpacewar.OXP. to be found here: http://wiki.alioth.net/index.php/OXP

Better take that docking routine as basis for your own.

-----
Ahruman wrote:
Timers are only in 1.70, but they do provide a hopefully-safe way to do timing. It’s definitely more precise than any legacy script or AI method.
You are right (as always). When I wrote "only", I mainly wanted to say to use a real time as basis for timing. But there are more ways to do that in Oolite.
When reading it the first time I just got flashbacks of Comodore 64 basic programs were sometimes an empty for-next loop was used for timing. It worked well, until you compiled the code. (Or raised the clock speed)

What I also wanted to ask is how sendScriptMessage works. With a search in this site I couldn't find a page with explanation. By name I would think it works like messageMother but than not on the mother but on the primary target.

But seeing your example I see it is calling a js function. Yes this can give power to AI for situations where the normal commands don't work. I'll put this, including your example in the AI page of the wiki.
Post Reply