The autopilot will accelerate continuously towards the target, and about mid-trip it will smoothly turn around to apply full thrust in the opposite direction, to slow down. Towards the end of the trip it will again change orientation as needed to arrive within 1000 kilometers of the target, say, with matched or slightly higher velocity, then will turn itself off.
Because of the long acceleration --half the trip--, it will reach *very* high velocities, so I need to also find out where the non-combat speed cap is applied, so as to disable it.
Spec multiplier will be controlled by the autopilot, and it will be a function of basic (pre-spec) speed, but subject to gravitaty and stuff. I will compute gravity myself, so, I need to access the system planets, their positions and masses, and to output a value directly to the spec multiplier.
The autopilot will allow you to intercept other ships, not just bases. On approaching another ship, spec multiplier will be synchronized first, then spec lowered for both ships or groups of ships, so I also need to know how to get the speed AND spec of any ship I target.
Conversely, a pirate who has the autopilot can use it to intercept you, and as he/she approaches you, spec has to come down, so I need some kind of callback, or list of ships targeting the player, and to be able to get their position, speed and spec, and to be able to control their spec. Unless I add the autopilot to their AI or something along the lines.
I have most of the code written already; physics AND spec control. I just need to know how to hook it up and test it. For instance, all of the code changes should be bypassable by an environmental flag, presumably in vegastrike.config. Or, what I would like even better is to have a new item you can buy: Autopilot I. Before you buy it, everything works the way it does presently. But if you have Autopilot I in your ship, it overrides the A binding for spec and interprets A as autopilot on/off toggle. If you don't like it, you can sell it and all goes back to normal.
Here's a list of inputs and outputs I need to tap into; if someone could be so gracious to tell me where the variables, are or what functions to call to access them:
* The A key: I need to disconnect it from spec activation toggling, and bind it to autopilot on/off toggle.
* Ctrl-A: For transfer of current target to autopilot target memory.
* Shift-Ctrl-A: For transfer of autopilot target to current target (In case you forgot where you were going )
* The player's hitting A or Tab or any keyboard navigation controls should suspend autopilot if currently on. A should turn it back on if it's off.
* Hitting A when no target has been saved to autopilot memory should display a message: "Autopilot: NO TARGET SELECTED. Use Ctrl-A to assign current target to autopilot memory."
* The [`] key; I need to disable it in auto mode, and to set the mode to non-compensated, as the autopilot will control the ship itself and needs no interference from the nav computer.
INPUTS (other than keyboard):
* Current target
* The ship's current position relative to the star.
* The ship's current speed vector relative to the star.
* The ship's current rotational orientation.
* The ship's current rotational speed.
* The autopilot target's current position relative to the star.
* The autopilot target's current speed vector relative to the star.
* The autopilot target's current rotational orientation.
* The autopilot target's current rotational speed.
* The current spec multiplier of any ship I target.
* The current position, speed and spec of any ship targeting the player.
OUTPUTS:
* Current target (Shft-Ctrl-A writes to it)
* The player's ship's thrusters and spec multiplier.
* The ship's current position relative to the star. (Yeah, I think I might do my own physics during autopilot travel).
* The ship's current speed vector relative to the star.
* The ship's current rotational orientation.
* The ship's current rotational speed.
* Set speed and combat-speed-cap mode, to leave them in a friendly state when autopilot turns itself off.
And I'm not sure how I give autopilot to npc's, and how to mod their AI to use it... And I need to change their spawning also: I want to spawn them well in advance, perhaps as soon as you launch from a base, and if they see you and want to intercept you, they'll use their autopilots. But that comes after. First is to get the player's autopilot to work.
TIA
Here's my present code, haven't tried to compile yet; take as poetry...
Code: Select all
//assume these are globals, for simplicity:
//positions and velocities: They will function equally regardless of the
//frame of reference chosen, as long as it is non-accelerating and non-
//-rotating. The standard, local star coord system is a perfect choice.
vector3d my_pos;
vector3d dest_pos;
vector3d my_velocity;
vector3d dest_velocity;
//Our auto-pilot routine outputs a desired ship orientation, or "nose
//vector". This is sent to the maneuvering computer, which will operate
//the maneuvering jets to achieve that orientation. However this may
//take a short time to achieve, so the "actual nose vector" follows the
//(desired) nose vector, but isn't necessarily the same vector.
//Thus "nose_vector" is the autopilot's main output. Other autopilot
//output variables are "main_thruster-on" and "autopilot_on". Actually,
//autopilot_on is i/o, set by the client; reset by autopilot().
vector3d nose_vector;
vector3d actual_nose_vector;
//The ship will use the "main thrusters" (back-facing thrusters) both
//for accelerating and deccelerating. This implies 2 things: Ship will
//turn-around at about mid-flight and face backwards to deccelerate.
//And the power of the other thrusters can be made much less, for all
//ships, which will better match most models' larger main thrusters.
//NOTE: Another choice would be to modify the ships to add retro rockets
//of similar size to the main thrusters, but I think the first solution
//makes more sense, after all, as making equal thrusters pointing in all
//directions would amount to a duplication, or a multiplication, of
//these (probably complex and expensive) devices.
const double max_accel; //maximum *forward* acceleration for one's ship
boolean in_autopilot; //set/reset by client; reset by autopilot()
boolean main_thruster_on; //another autopilot() output variable
void autopilot(float time_delta) //to be called periodically
{
if( ! in_autopilot ) return;
vector3d linear_path = dest_pos - my_pos;
double distance = linear_path.length();
if( distance < 90.0 /*kilometers*/ )
{
issue_a_final_ASAP();
in_autopilot = false;
return;
}
vector3d normalized_path = linear_path/distance;
if( distance < 100.0 /*kilometers*/ )
{
//almost done, just turn the engines off and point at dest
main_thruster_on = false;
//if pointing away from destination, point at it
if( dot( actual_nose_vector, normalized_path ) < 0.9 )
{
nose_vector = normalized_path;
}
else //otherwise return to manual mode
{
issue_a_final_ASAP();
in_autopilot = false;
}
return;
}
vector3d approach_vector = my_velocity - dest_velocity;
//Ideal velocity:
//The ideal velocity is the maximum velocity we can barely brake
//on time not to hit our destination; which is equivalent to the
//speed we'd acquire if accelerating back from the destination.
//From a previous post: we deduced accel = 0.5 * v^2 / d
//If that's right, then v = sqrt( 2 * accel * d )
double ideal_velocity = sqrt( 2.0 * max_accel * distance );
vector3d ideal_approach_vector =
normalized_path * ideal_velocity;
//but we want our final speed vector to match the target, so...
ideal_approach_vector += dest_velocity;
//now we compute velocity vector correction needed
vector3d correction_vector = ideal_approach_vector - my_velocity;
//99% of the time we need the main thruster on, but check, just
//in case.. and use a bit of hystheresis..
double correction_magnitude = correction_vector.length();
if( main_truster_on )
if( correction_magnitude < 0.2 * max_accel * time_delta )
main_thruster_on = false;
if( ! main_truster_on )
if( correction_magnitude > 0.8 * max_accel * time_delta )
main_thruster_on = true;
//maybe control the throttle too?
if( main_thruster_on &&
correction_magnitude < max_accel * time_delta )
throttle_0_to_1 =
correction_magnitude / ( max_accel * time_delta );
//finally, indicate to the ship which direction it should point
if( main_thruster_on ) //important! avoids div by zero ;-)
nose_vector = correction_vector / correction_magnitude;
}
//The way SPEC works is we have a linearly varying quantity, which goes
//up or down trapezoidally with time. This is not the spec multiplier
//itself, but rather the exponent we raise a base to, to obtain the
//final spec multiplier. And it is only a cap: There are other factors
//that may lower spec. Its main purpose is to limit the rate of growth
//and shrinkage of spec numbers after the ship leaves one place, and
//before it arrives to another.
//The first idea was to make it a function of time or distance from
//departure/arrival or source/destination; but this proved complex to
//to compute. The current implementation simply makes it a function of
//pre-spec speed (my_velocity).
//The other factors affecting spec cap are gravity, proximity of other
//ships targeting you, and an absolute max_linear_spec cap.
//For smoothness, rather than picking the lowest of these caps, we
//use the formula for resistance of resistors in parallel, which yields
//lower resistance than the resistor with the lowest resistance. The
//formula is R = 1 / ( 1/R1 + 1/R2 + 1/R3 + ... + 1/Rn )
//The SPEC of ships flying together as a wing or convoy is synchronized
//by their computers. If a hostile ship targeting you comes within
//radar range the specs are synchronized to the lower of the two, and
//lowered down to non-spec as the ships approach some fraction of radar
//range, to be determined.
boolean spec_on; //probably under control of autopilot()
const double specmax_abs_cap = TBD; //=log(max_spec_multiplier)
double specmax_gravity;
double specmax_speed;
double linear_spec_var;
double specmul_bogie;
double spec_mul;
const double spec_speed_ratio = TBD; //max_linear_spec/1000km/sec?
const double spec_grav_influence = TBD; //tweak experimentally
const double FORRBDSZ = TBD; //"Fraction Of Radar Range Bogie (locking
//us) Downs SPEC to Zero"; --a number between 0 and 1, try 0.25
//Actually, at the above fraction of radar range, linear spec comes
//down to half (mul spec down to square root), but it falls to zero
//very fast as the range gets shorter (by 4th power of the distance)
std::vector<planet> planets;
void update_spec
(
float time_delta,
bogie *nearest_bogie = NULL
)
{
if( ! spec_on )
{
linear_spec_var = 0.0;
spec_mul = 1.0;
}
else
{
//evaluate net gravity's magnitude
vector3d gravity = vector3d(0.0,0.0,0.0);
planets.iterator_t i;
for( i = planets.begin(); i != planets.end(); ++i )
{
vector pull = i->pos() - my_pos;
double distance = pull.length();
pull /= distance;
pull /= distance;
pull /= distance;
pull *= i->mass;
gravity += pull;
}
double net_gravity_magnitude = gravity.length();
if( net_gravity_magnitude < 0.0000000000001 )
net_gravity_magnitude = 0.0000000000001;
//max spec as per gravity
specmax_gravity = spec_grav_influence / net_gravity_magnitude;
//max spec as per velocity
vector3d rel_dest_velocity = my_velocity - dest_velocity;
double rel_dest_speed = rel_dest_velocity.length();
rel_dest_speed -= min_speed_for_spec;
if( rel_dest_speed < 0.0 )
{
linear_spec_var = 0.0;
}
else
{
specmax_speed = spec_speed_ratio * rel_dest_velocity.length();
//overall max spec (use parallel resistance formula as a substitute
//for lowest() that yields a continuous function...
double temp = 1.0 /
( (1.0/specmax_abs_cap) + (1.0/specmax_gravity) + (1.0/specmax_speed) );
//add just a slight bit of low-pass filtering...
linear_spec_var -= ( time_delta * linear_spec_var );
linear_spec_var += ( time_delta * temp );
}
//finally, a hostile locking us within radar range lowers spec directly
if( nearest_bogie && nearest_bogie.distance() < radar_range )
{
//get a factor that maps from 1 to 0 as range moves from max radar-
//-range to zero
double factor = nearest_bogie.distance()/radar_range;
//turn this factor into a sigmoid, for smoothness. Note that at
//FORRBDSZ * radar_range factor will be one after next line
factor /= FORRBDSZ;
//raise factor to the 4th power.
factor *= factor;
factor *= factor;
//now smooth-out the long range part of the curve, quasi asymptotic to 1
factor = 1.0 / ( 1.0 + (1.0/factor) );
//and scale the spec multiplier by this factor
linear_spec_var *= factor;
synchronize_spec_with( nearest_bogie ); //lower of the two.
}
//finally, convert linear spec to exponential multiplier of speed
spec_mul = exp( linear_spec_var );
}
}
void update_physics(float time_delta)
{
//As spec numbers increase, mass decreases. The decrease in mass
//multiplies our speed to conserve momentum, and also multiplies our
//acceleration, for a given thrust; the net effect being quivalent to
//time-compression...
//So, first we compute physics normally, ignoring SPEC
vector3d accel;
if( main_thrusters_on )
{
accel = max_accel * actual_nose_vector;
}
else
{
accel = vector3d(0.0,0.0,0.0);
}
my_velocity += ( accel * time_delta );
//and now we SPEC the velocity and update position
vector3d post_spec_velocity = spec_mul * my_velocity;
my_pos += ( post_spec_velocity * time_delta );
}
void ship_update(long current_time) //time since boot, milliseconds
{
//compute time delta
static long previous_time = system_time(); //ms since boot
//compute time-delta in seconds (time since last call)
float time_delta = 0.001f * (current_time - previous_time);
previous_time = current_time;
if( time_delta <= 0.002f ) return;
if( time_delta > 0.5f ) time_delta = 0.5f;
//toggle autopilot state
if( autopilot_button_pressed() )
autopilot ^= true;
//execute updates
if( in_autopilot ) autopilot( time_delta );
else manual_pilot( time_delta );
update_spec( time_delta, &nearest_bogie );
update_physics( time_delta );
}