I'm updating Thargoid's HiredGuns OXP (with his permission). One thing that needs changing is the tendency of the escorts (the 'hired guns') to crash into planetary bodies.
Now, I am having trouble determining how close they are to such bodies.
True, there are various messages Oolite gives to AIs about distances from such bodies. Yet, all such messages are issued, only, when the ship entity in question enters or leaves a sphere the extent of which is 3 x the radius of the planetary object. What I need, though, is a way of checking for being, I don't know, 5000 km from the planetary object - which is some three times less than that. Checking distance from each celestial object in the system does not seem like the way to go. entity and ship seem to lack an altitude property.
The player.ship entity has an altitude calculation, which isn't exposed to JS at the moment. It finds the closest stellar body and performs the altitude calculation. Theoretically this calc could be applied to any ship, but it would need core code changes to provide the facility. I might have a look at how hard that calc is to apply to a ship entity, but if I can, it would mean you'd be targeting Oolite 1.89/1.90 for the update. If you need something now, you'd have to do those calculations yourself.
What I did notice is that the older plist AI methods have some messages you can respond to: AEGIS_CLOSE_TO_MAIN_PLANET, CLOSE_TO_PLANET, CLOSE_TO_MOON, and CLOSE_TO_SECONDARY_PLANET. I'm not sure if equivalent functions exist in the newer PriorityAI.
> What I did notice is that the older plist AI methods have some messages you can respond to: AEGIS_CLOSE_TO_MAIN_PLANET, CLOSE_TO_PLANET, CLOSE_TO_MOON, and CLOSE_TO_SECONDARY_PLANET. I'm not sure if equivalent functions exist in the newer PriorityAI.
I am using the old AI. The messages you mention were those that I myself mentioned above. For the reasons I gave, they do not seem suitable to my purpose. Do please advise if you can suggest anything. Otherwise, those hired guns are going to keep crashing (into planetary bodies - actually, they crash into space stations too, but that is a separate problem).
this.$getAltitudeForShip = function $getAltitudeForShip(ship) {
var result = this.$calcAltitudeForShip(ship);
log(this.name, "alt = " + result.altitude);
log(this.name, "body = " + result.body);
}
// calculate the minimum altitude of the given ship from all planetary bodies
// returns dictionary with "altitude" and "body" properties
this.$calcAltitudeForShip = function $calcAltitudeForShip(ship) {
var ent = [];
var smallest = -1;
var closest = null;
if (system.isInterstellarSpace === false && system.sun) ent.push(system.sun);
ent = ent.concat(system.planets);
for (var i = 0; i < ent.length; i++ ) { //find the smallest distance
var alt = this.$altitudeOverPlanetaryBody(ent[i], ship);
if (smallest === -1 || (alt != -1 && alt < smallest)) {smallest = alt; closest = ent[i];}
}
return {"altitude":smallest, body:closest};
}
// calculates the altitude of a ship over a specific planetary body
this.$altitudeOverPlanetaryBody = function $altitudeOverPlanetaryBody(body, ship) {
var shippos = ship.position;
if (!shippos) return -1;
return shippos.distanceTo(body) - body.radius - ship.collisionRadius;
}
Executing the function $getAltitudeForShip, and passing the player.ship as a parameter, will demonstrate the functions.
Hopefully that makes sense and helps a bit. I've only done a quick shakedown test of this, so there might be some edge cases to test for.
Marvellous. I will use that code - in conjunction with the automatically generated AI messages. For, I'll do this. When a hiredGun receives a 'CLOSE_TO_<SOMETHING>' message, I'll start a timer that calls your js code and reacts to its findings; when a hiredGun receives an 'AWAY_FROM_<SOMETHING>' message, I'll stop the timer.
Here's a thing, though. Is there an AWAY_FROM_SECONDARY_PLANET message? This page does not say there is, but it does say there is a CLOSE_TO_SECONDARY_PLANET message.
Here's a thing, though. Is there an AWAY_FROM_SECONDARY_PLANET message?
There doesn't seem to be. Although, there's no AWAY_FROM_<any entity> either.
What happens, though, is that when you call the checkAegis AI function, you'll get either one of the following: AEGIS_CLOSE_TO_MAIN_PLANET CLOSE_TO_SUN CLOSE_TO_PLANET CLOSE_TO_MOON CLOSE_TO_SECONDARY_PLANET AEGIS_IN_DOCKING_RANGE or AEGIS_NONE which I think would mean, for you, that the ship was out of range.
But these messages are only sent if the checkAegis AI function is called. You are calling that function, right?
Hmm! I have not yet tested - I've only just finished the first draft of my code - but:
The aegis check is part of the system update and messages needs no command to generate them. The following messages are only generated when the status changes.
"AEGIS_CLOSE_TO_PLANET": Within 3x planetary radius of the main planet and not near station.
"AEGIS_IN_DOCKING_RANGE": Within 2x scanner radius of system station.
"AEGIS_LEAVING_DOCKING_RANGE": Has been in docking range but now only close to planet.
"AEGIS_NONE": None of the above three messages is true.
"AEGIS_CLOSE_TO_MAIN_PLANET": Within 3x planetary radius of the main planet and not near station.
"CLOSE_TO_PLANET": Within 3x planetary radius of any planet and not near station.
"AWAY_FROM_PLANET": Leaving the area of 3x planetary radius of any planet.
"CLOSE_TO_SUN": Within 3x sun radius of the sun .
"AWAY_FROM_SUN Leaving the area of 3x sun radius of the sun.
"CLOSE_TO_SECONDARY_PLANET": Within 3x radius of a planet that is not the main-planet.
"CLOSE_TO_MOON": Within 3x radius of a moon (=planet without atmosphere).
Also, I've forgotten how to get AI state changes - using plist AIs - to get logged in the main Oolite log. The following, in a ship script, doesn't seem to do it (even though I have the debugOXZ installed).
this.debug = true;
var consoleDebugMessages;
if ( this.debug === true ) {
this.logging = true;
consoleDebugMessages = true;
}
else {
consoleDebugMessages = false; // This does need setting to something, even when debugging is off.
}
One more (slightly involved) thing, if I may. I'm making progress, but I'd like the calcAltitudeForShip function to return, additionally, a boolean that is true if and only the player is moving towards the nearest celestial body. To that, I imagine we'd need to check the ship's speed (it should be >0) but also its vector. It's the vector check I don't know how to do. Could you - or someone else - advise on that, please?
this.$calcAltitudeForShip = function $calcAltitudeForShip(ship) {
var ent = [];
var smallest = -1;
var closest = null;
if (system.isInterstellarSpace === false && system.sun) ent.push(system.sun);
ent = ent.concat(system.planets);
for (var i = 0; i < ent.length; i++ ) { //find the smallest distance
var alt = this.$altitudeOverPlanetaryBody(ent[i], ship);
if (smallest === -1 || (alt != -1 && alt < smallest)) {smallest = alt; closest = ent[i];}
}
var deviation = 1;
if (closest) deviation = ship.vectorForward.angleTo(closest.position.subtract(ship.position));
return {"altitude":smallest, body:closest, movingTowards:((deviation < 0.18) && ship.speed > 0)};
}
Adjust the 0.18 value down to be ever more accurate about whether the ship is pointing at the closest planet. I took the 0.18 value from the Manual Witchspace Alignment OXP, so it might need some tweaking when dealing with planets.
Yes indeed! That's the stuff! The magic of Oolite and Javascript!
I now have the escorts recognising - without too much system load - when they are close to celestial bodies, messaging the player about it, and sometimes temporarily refusing to go further. The next and - for the moment, last - thing I'd like to implement is a flee function, whereby the escorts flee perpendicularly away from the celestial object (and I'm doing all this in a mix of JS and AI).
ENTER = ("sendScriptMessage: setPerpendicularlyCoordinatesToCelestialObject", setDestinationFromCoordinates, "setDesiredRangeTo: 250", "setSpeedFactorTo: 2.0", performFlyToRangeFromDestination);
setTargetToCelestialObject, setPerpendicularlyCoordinatesToCelestialObject - calc by ship script.
P.S.
I solved similar task in the Stealth Raiders OXP[WIP] for sun skimmers (by AI.plist) and for ship combats in nearby sun (by priority-based Javascript AI was developed a final AI.js).
But I decided that the priority-based Javascript AI would be better. I developed and test the some prototypes for priority-based Javascript AI for flee from sun heat in combat.
@rustem, both setTargetToCelestialObject and setPerpendicularlyCoordinatesToCelestialObject appear to be ship script functions, but without seeing the script it's hard to know what they do on their own. Which AI files are they from, and in which OXP?