Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
navigation.cpp
Go to the documentation of this file.
1 #include "navigation.h"
2 #include "macosx_math.h"
3 #include <math.h>
4 #ifndef _WIN32
5 #include <assert.h>
6 #endif
7 #include "cmd/unit_generic.h"
8 using namespace Orders;
9 #include "lin_time.h"
10 #include "cmd/script/flightgroup.h"
11 #include "config_xml.h"
12 #include "vs_globals.h"
13 #include "warpto.h"
14 #include "flybywire.h"
15 #include "cmd/unit_util.h"
37 static float CalculateBalancedDecelTime( float l, float v, float &F, float mass )
38 {
39  float accel = F/mass;
40  if (accel <= 0)
41  return 0;
42  if (l < 0) {
43  l = -l;
44  v = -v;
45  F = -F;
46  }
47  double temp = .5*v*v+(l-v*SIMULATION_ATOM*(.5)+.5*SIMULATION_ATOM*SIMULATION_ATOM*accel)*accel;
48  if (temp < 0)
49  temp = 0;
50  return ( -v+sqrtf( temp ) )/accel;
51 }
66 static float CalculateDecelTime( float l, float v, float &F, float D, float mass )
67 {
68  float accel = F/mass;
69  float decel = D/mass;
70  if (l < 0) {
71  l = -l;
72  v = -v;
73  accel = decel;
74  decel = F/mass;
75  F = -D;
76  }
77  float vsqr = v*v;
78  float fourac = 2*accel*( (.5*v*v/decel)-v*SIMULATION_ATOM*.5-l )/(1+accel/decel);
79  if (fourac > vsqr) return FLT_MAX; //FIXME avoid sqrt negative not sure if this is right
80 
81  return ( -v+sqrtf( vsqr-fourac ) )/accel;
82 }
83 
84 //failed attempt below
96 //end failed attempt
97 
98 void MoveTo::SetDest( const QVector &target )
99 {
100  targetlocation = target;
101  done = false;
102 }
103 
104 bool MoveToParent::OptimizeSpeed( Unit *parent, float v, float &a, float max_speed )
105 {
106  v += ( a/parent->GetMass() )*SIMULATION_ATOM;
107  if ( (!max_speed) || fabs( v ) <= max_speed )
108  return true;
109  float deltaa = parent->GetMass()*(fabs( v )-max_speed)/SIMULATION_ATOM; //clamping should take care of it
110  a += (v > 0) ? -deltaa : deltaa;
111  return false;
112 }
113 
115 bool MoveToParent::Done( const Vector &ang_vel )
116 {
117  if (fabs( ang_vel.i ) < THRESHOLD
118  && fabs( ang_vel.j ) < THRESHOLD
119  && fabs( ang_vel.k ) < THRESHOLD) //if velocity is lower than threshold
120  return true;
121  return false;
122 }
123 
125 {
126  done = done || m.Execute( parent, targetlocation );
127 }
128 bool MoveToParent::Execute( Unit *parent, const QVector &targetlocation )
129 {
130  bool done = false;
131  Vector local_vel( parent->UpCoordinateLevel( parent->GetVelocity() ) );
132  //local location is ued for storing the last velocity;
133  terminatingX += ( (local_vel.i > 0) != (last_velocity.i > 0) || (!local_vel.i) );
134  terminatingY += ( (local_vel.j > 0) != (last_velocity.j > 0) || (!local_vel.j) );
135  terminatingZ += ( (local_vel.k > 0) != (last_velocity.k > 0) || (!local_vel.k) );
136 
137  last_velocity = local_vel;
138  Vector heading = parent->ToLocalCoordinates( ( targetlocation-parent->Position() ).Cast() );
139  Vector thrust( parent->Limits().lateral, parent->Limits().vertical,
140  afterburn ? parent->Limits().afterburn : parent->Limits().forward );
141  float max_speed =
142  ( afterburn ? parent->GetComputerData().max_ab_speed() : parent->GetComputerData().max_speed() );
143  Vector normheading = heading;
144  normheading.Normalize();
145  Vector max_velocity = max_speed*normheading;
146  max_velocity.Set( fabs( max_velocity.i ),
147  fabs( max_velocity.j ),
148  fabs( max_velocity.k ) );
149  if (done) return done; //unreachable
150 
151  if (terminatingX > switchbacks
152  && terminatingY > switchbacks
153  && terminatingZ > switchbacks) {
154  if ( Done( last_velocity ) ) {
155  if (selfterminating) {
156  done = true;
157  } else {
158  terminatingX = 0;
159  terminatingY = 0;
160  terminatingZ = 0;
161  }
162  return done;
163  }
164  thrust = (-parent->GetMass()/SIMULATION_ATOM)*last_velocity;
165  } else {
166  float div = 1.0f;
167  float vdiv = 1.0f;
168  if (selfterminating && terminatingX > 8 && terminatingY > 8 && terminatingZ > 8) {
169  int tmp = (terminatingX-4);
170  if (terminatingY < terminatingX) tmp = terminatingY-4;
171  if (terminatingZ < terminatingX && terminatingZ < terminatingY) tmp = terminatingZ-4;
172  tmp /= 4;
173  if (tmp > 30) tmp = 30;
174  vdiv = (float) (1<<tmp);
175  div = vdiv;
176  thrust.i /= div;
177  thrust.j /= div;
178  thrust.k /= div;
179  }
180  //start with Forward/Reverse:
181  float t = CalculateDecelTime( heading.k, last_velocity.k, thrust.k, parent->Limits().retro/div, parent->GetMass() );
182  if (t < THRESHOLD) {
183  thrust.k =
184  ( thrust.k > 0 ? -parent->Limits().retro
185  /div : ( afterburn ? parent->Limits().afterburn/div : parent->Limits().forward/div ) );
186  } else if (t < SIMULATION_ATOM) {
187  thrust.k *= t/SIMULATION_ATOM;
188  thrust.k +=
190  -t)
191  *( thrust.k > 0 ? -parent->Limits().retro
192  /div : ( afterburn ? parent->Limits().afterburn/div : parent->Limits().forward/div ) )/SIMULATION_ATOM;
193  }
194  OptimizeSpeed( parent, last_velocity.k, thrust.k, max_velocity.k/vdiv );
195  t = CalculateBalancedDecelTime( heading.i, last_velocity.i, thrust.i, parent->GetMass() );
196  if (t < THRESHOLD)
197  thrust.i = -thrust.i;
198  else if (t < SIMULATION_ATOM)
199  thrust.i *= ( t-(SIMULATION_ATOM-t) )/SIMULATION_ATOM;
200  OptimizeSpeed( parent, last_velocity.i, thrust.i, max_velocity.i/vdiv );
201  t = CalculateBalancedDecelTime( heading.j, last_velocity.j, thrust.j, parent->GetMass() );
202  if (t < THRESHOLD)
203  thrust.j = -thrust.j;
204  else if (t < SIMULATION_ATOM)
205  thrust.j *= ( t-(SIMULATION_ATOM-t) )/SIMULATION_ATOM;
206  OptimizeSpeed( parent, last_velocity.j, thrust.j, max_velocity.j/vdiv );
207  }
208  parent->ApplyLocalForce( thrust );
209 
210  return done;
211 }
213 {
214 #ifdef ORDERDEBUG
215  VSFileSystem::vs_fprintf( stderr, "mt%x", this );
216  fflush( stderr );
217 #endif
218 }
219 
220 bool ChangeHeading::OptimizeAngSpeed( float optimal_speed_pos, float optimal_speed_neg, float v, float &a )
221 {
222  v += ( a/parent->GetMoment() )*SIMULATION_ATOM;
223  if ( (optimal_speed_pos == 0 && optimal_speed_neg == 0) || (v >= -optimal_speed_neg && v <= optimal_speed_pos) )
224  return true;
225  if (v > 0) {
226  float deltaa = parent->GetMoment()*(v-optimal_speed_pos)/SIMULATION_ATOM; //clamping should take care of it
227  a -= deltaa;
228  } else {
229  float deltaa = parent->GetMoment()*(-v-optimal_speed_neg)/SIMULATION_ATOM; //clamping should take care of it
230  a += deltaa;
231  }
232  return false;
233 }
234 
239 void ChangeHeading::TurnToward( float atancalc, float ang_veli, float &torquei )
240 {
241  //We need to end up at destination with positive velocity, but no more than we can decelerate from in a single SIMULATION_ATOM
242  if (1) {
243  float mass = parent->GetMoment();
244  float max_arrival_speed = torquei*SIMULATION_ATOM/mass;
245  float accel_needed = (atancalc/SIMULATION_ATOM-ang_veli)/SIMULATION_ATOM;
246  float arrival_velocity = accel_needed*SIMULATION_ATOM+ang_veli;
247  if (fabs( arrival_velocity ) <= max_arrival_speed && fabs( accel_needed ) < torquei/mass) {
248  torquei = accel_needed*mass;
249  return;
250  }
251  }
252  float t = CalculateBalancedDecelTime( atancalc, ang_veli, torquei, parent->GetMoment() ); //calculate when we should decel
253  if (t < 0) {
254  //if it can't make it: try the other way
255  torquei = fabs( torquei ); //copy sign again
256  t = CalculateBalancedDecelTime( atancalc > 0 ? atancalc-2*PI : atancalc+2*PI, ang_veli, torquei, parent->GetMoment() );
257  }
258  if (t > 0) {
259  if (t < SIMULATION_ATOM)
260  torquei *= ( (t/SIMULATION_ATOM)-( (SIMULATION_ATOM-t)/SIMULATION_ATOM ) );
261  } else {
262  torquei = -parent->GetMoment()*ang_veli/SIMULATION_ATOM; //clamping should take care of it
263  }
264 }
265 void ChangeHeading::SetDest( const QVector &target )
266 {
267  final_heading = target;
268  ResetDone();
269 }
272 bool ChangeHeading::Done( const Vector &ang_vel )
273 {
274  if (fabs( ang_vel.i ) < THRESHOLD
275  && fabs( ang_vel.j ) < THRESHOLD
276  && fabs( ang_vel.k ) < THRESHOLD)
277  return true;
278  return false;
279 }
280 
282 {
283  bool temp = done;
284  Order::Execute();
285  done = temp;
286  Vector ang_vel = parent->GetAngularVelocity();
287  Vector local_velocity( parent->UpCoordinateLevel( ang_vel ) );
288  Vector local_heading( parent->ToLocalCoordinates( ( final_heading-parent->Position() ).Cast() ) );
289  char xswitch =
290  ( (local_heading.i > 0) != (last_velocity.i > 0) || (!local_heading.i) ) && last_velocity.i != 0 ? 1 : 0;
291  char yswitch =
292  ( (local_heading.j > 0) != (last_velocity.j > 0) || (!local_heading.j) ) && last_velocity.j != 0 ? 1 : 0;
293  static bool AICheat = XMLSupport::parse_bool( vs_config->getVariable( "AI", "turn_cheat", "true" ) );
294  bool cheater = false;
295  static float min_for_no_oversteer = XMLSupport::parse_float( vs_config->getVariable( "AI", "min_angular_accel_cheat", "50" ) );
296  if ( AICheat && ( (parent->Limits().yaw+parent->Limits().pitch)*180/( PI*parent->GetMass() ) > min_for_no_oversteer )
297  && !parent->isSubUnit() ) {
298  if (xswitch || yswitch) {
299  Vector P, Q, R;
300  parent->GetOrientation( P, Q, R );
301  Vector desiredR = ( final_heading-parent->Position() ).Cast();
302  desiredR.Normalize();
303  static float cheatpercent = XMLSupport::parse_float( vs_config->getVariable( "AI", "ai_cheat_dot", ".99" ) );
304  if (desiredR.Dot( R ) > cheatpercent) {
305  P = Q.Cross( desiredR );
306  Q = desiredR.Cross( P );
307  parent->SetOrientation( Q, desiredR );
308  xswitch = yswitch = 1;
309  if (xswitch) {
310  if (yswitch) {
311  local_velocity.j = .0f;
312  local_velocity.i = .0f;
313  ang_vel.i = .0f;
314  ang_vel.j = .0f;
315  } else {
316  local_velocity.i = .0f;
317  ang_vel.i = .0f;
318  }
319  } else if (yswitch) {
320  local_velocity.j = .0f;
321  ang_vel.j = .0f;
322  }
323  cheater = true;
324  ang_vel.k = local_velocity.k = 0;
325  parent->SetAngularVelocity( ang_vel );
326  }
327  }
328  }
329  terminatingX += xswitch;
330  terminatingY += yswitch;
331  last_velocity = local_velocity;
332  if (done /*||(xswitch&&yswitch)*/)
333  return;
334  Vector torque( parent->Limits().pitch, parent->Limits().yaw, 0 ); //set torque to max accel in any direction
335  if (terminatingX > switchbacks && terminatingY > switchbacks) {
336  if ( Done( local_velocity ) ) {
337  if (this->terminating) {
338  done = true;
339  } else {
340  terminatingX = 0;
341  terminatingY = 0;
342  }
343  return;
344  }
345  torque = (-parent->GetMoment()/SIMULATION_ATOM)*local_velocity;
346  } else {
347  TurnToward( atan2( local_heading.j, local_heading.k ), local_velocity.i, torque.i ); //find angle away from axis 0,0,1 in yz plane
348  OptimizeAngSpeed( turningspeed*parent->GetComputerData().max_pitch_down,
349  turningspeed*parent->GetComputerData().max_pitch_up,
350  local_velocity.i,
351  torque.i );
352  TurnToward( atan2( local_heading.i, local_heading.k ), -local_velocity.j, torque.j );
353  torque.j = -torque.j;
354  OptimizeAngSpeed( turningspeed*parent->GetComputerData().max_yaw_left,
355  turningspeed*parent->GetComputerData().max_yaw_right,
356  local_velocity.j,
357  torque.j );
358  torque.k = -parent->GetMoment()*local_velocity.k/SIMULATION_ATOM; //try to counteract roll;
359  }
360  if (!cheater)
361  parent->ApplyLocalTorque( torque );
362 }
364 {
365 #ifdef ORDERDEBUG
366  VSFileSystem::vs_fprintf( stderr, "ch%x", this );
367  fflush( stderr );
368 #endif
369 }
370 FaceTargetITTS::FaceTargetITTS( bool fini, int accuracy ) : ChangeHeading( QVector( 0, 0, 1 ), accuracy )
371  , finish( fini )
372 {
373  type = FACING;
374  subtype = STARGET;
375  speed = float(.00001);
376  useitts = true;
377  static bool alwaysuseitts = XMLSupport::parse_bool( vs_config->getVariable( "AI", "always_use_itts", "false" ) );
378  if (!alwaysuseitts)
379  if (rand() >= g_game.difficulty*RAND_MAX)
380  useitts = false;
381 }
383 {
384 #ifdef ORDERDEBUG
385  VSFileSystem::vs_fprintf( stderr, "fti%x", this );
386  fflush( stderr );
387 #endif
388 }
389 
391 {
392  Unit *target = parent->Target();
393  if (target == NULL) {
394  done = finish;
395  return;
396  }
397  if ( speed == float(.00001) ) {
398  float mrange;
399  float range;
400  parent->getAverageGunSpeed( speed, range, mrange );
401  if ( speed == float(.00001) )
402  speed = FLT_MAX;
403  }
404  SetDest( useitts ? target->PositionITTS( parent->Position(), parent->cumulative_velocity, speed, false ) : target->Position() );
406  if (!finish)
407  ResetDone();
408 }
409 
410 FaceTarget::FaceTarget( bool fini, int accuracy ) : ChangeHeading( QVector( 0, 0, 1 ), accuracy )
411  , finish( fini )
412 {
413  type = FACING;
414  subtype = STARGET;
415 }
416 
418 {
419  Unit *target = parent->Target();
420  if (target == NULL) {
421  done = finish;
422  return;
423  }
424  SetDest( target->isSubUnit() ? target->Position() : target->LocalPosition() );
426  if (!finish)
427  ResetDone();
428 }
429 
431 {
432 #ifdef ORDERDEBUG
433  VSFileSystem::vs_fprintf( stderr, "ft%x", this );
434  fflush( stderr );
435 #endif
436 }
437 extern float CalculateNearestWarpUnit( const Unit *thus, float minmultiplier, Unit **nearest_unit, bool negative_spec_units );
438 AutoLongHaul::AutoLongHaul( bool fini, int accuracy ) : ChangeHeading( QVector( 0, 0, 1 ), accuracy )
439  , finish( fini )
440 {
441  type = FACING|MOVEMENT;
442  subtype = STARGET;
443  deactivatewarp = false;
444  StraightToTarget = true;
445  inside_landing_zone = false;
446 }
447 void AutoLongHaul::MakeLinearVelocityOrder()
448 {
449  eraseType( MOVEMENT );
450  static float combat_mode_mult =
451  XMLSupport::parse_float( vs_config->getVariable( "auto_physics", "auto_docking_speed_boost", "20" ) );
452 
453  float speed =
455  max_combat_ab_speed /*won't do insanity flight mode + spec = ludicrous speed*/;
456  if (inside_landing_zone)
457  speed *= combat_mode_mult;
458  MatchLinearVelocity *temp = new MatchLinearVelocity( Vector( 0, 0, speed ), true, false, false );
459  temp->SetParent( parent );
460  Order::EnqueueOrder( temp );
461 }
463 {
464  ChangeHeading::SetParent( parent1 );
465  group.SetUnit( parent1->Target() );
466  inside_landing_zone = false;
467  MakeLinearVelocityOrder();
468 }
469 extern bool DistanceWarrantsWarpTo( Unit *parent, float dist, bool following );
470 
471 QVector AutoLongHaul::NewDestination( const QVector &curnewdestination, double magnitude )
472 {
473  return curnewdestination;
474 }
475 static float mymax( float a, float b )
476 {
477  return a > b ? a : b;
478 }
479 static float mymin( float a, float b )
480 {
481  return a < b ? a : b;
482 }
483 
484 bool useJitteryAutopilot( Unit *parent, Unit *target, float minaccel )
485 {
486  static float specInterdictionLimit =
487  XMLSupport::parse_float( vs_config->getVariable( "physics", "min_spec_interdiction_for_jittery_autopilot", ".05" ) );
488  if ( target->isPlanet() == false
489  && (target->graphicOptions.specInterdictionOnline == 0 || fabs( target->specInterdiction ) < specInterdictionLimit) )
490  return true;
491  if (parent->computer.combat_mode == false)
492  return true;
493  float maxspeed = parent->GetComputerData().max_combat_ab_speed;
494  static float accel_auto_limit =
495  XMLSupport::parse_float( vs_config->getVariable( "physics", "max_accel_for_smooth_autopilot", "10" ) );
496  static float speed_auto_limit =
497  XMLSupport::parse_float( vs_config->getVariable( "physics", "max_over_combat_speed_for_smooth_autopilot", "2" ) );
498  if (minaccel < accel_auto_limit || parent->Velocity.MagnitudeSquared() > maxspeed*maxspeed*speed_auto_limit
499  *speed_auto_limit)
500  return true;
501  return false;
502 }
503 bool AutoLongHaul::InsideLandingPort( const Unit *obstacle ) const
504 {
505  static float landing_port_limit =
506  XMLSupport::parse_float( vs_config->getVariable( "physics", "auto_landing_port_unclamped_seconds", "120" ) );
507  return UnitUtil::getSignificantDistance( parent,
508  obstacle ) < -landing_port_limit*parent->GetComputerData().max_combat_ab_speed;
509 }
510 
512 {
513  Unit *target = group.GetUnit();
514  if (target == NULL) {
515  group.SetUnit( parent->Target() );
516  done = finish;
517  parent->autopilotactive = false;
518  return;
519  }
520  static bool compensate_for_interdiction =
521  XMLSupport::parse_bool( vs_config->getVariable( "physics", "autopilot_compensate_for_interdiction", "false" ) );
522  static float enough_warp_for_cruise =
523  XMLSupport::parse_float( vs_config->getVariable( "physics", "enough_warp_for_cruise", "1000" ) );
524  static float go_perpendicular_speed =
525  XMLSupport::parse_float( vs_config->getVariable( "physics", "warp_perpendicular", "80" ) );
526  static float min_warp_orbit_radius =
527  XMLSupport::parse_float( vs_config->getVariable( "physics", "min_warp_orbit_radius", "100000000" ) );
528  static float warp_orbit_multiplier =
529  XMLSupport::parse_float( vs_config->getVariable( "physics", "warp_orbit_multiplier", "4" ) );
530  static float warp_behind_angle =
531  cos( 3.1415926536*XMLSupport::parse_float( vs_config->getVariable( "physics", "warp_behind_angle", "150" ) )/180. );
532  QVector myposition = parent->isSubUnit() ? parent->Position() : parent->LocalPosition(); //get unit pos
533  QVector destination = target->isSubUnit() ? target->Position() : target->LocalPosition(); //get destination
534  QVector destinationdirection = (destination-myposition); //find vector from us to destination
535  double destinationdistance = destinationdirection.Magnitude();
536  destinationdirection = destinationdirection*(1./destinationdistance); //this is a direction, so it is normalize
537  if (parent->graphicOptions.WarpFieldStrength < enough_warp_for_cruise && parent->graphicOptions.InWarp) {
538  //face target unless warp ramping is done and warp is less than some intolerable ammt
539  Unit *obstacle = NULL;
540  float maxmultiplier = CalculateNearestWarpUnit( parent, FLT_MAX, &obstacle, compensate_for_interdiction ); //find the unit affecting our spec
541  bool currently_inside_landing_zone = false;
542  if (obstacle)
543  currently_inside_landing_zone = InsideLandingPort( obstacle );
544  if (currently_inside_landing_zone != inside_landing_zone) {
545  inside_landing_zone = currently_inside_landing_zone;
546  MakeLinearVelocityOrder();
547  }
548  if (maxmultiplier < enough_warp_for_cruise && obstacle != NULL && obstacle != target) {
549  //if it exists and is not our destination
550  QVector obstacledirection = (obstacle->LocalPosition()-myposition); //find vector from us to obstacle
551  double obstacledistance = obstacledirection.Magnitude();
552 
553  obstacledirection = obstacledirection*(1./obstacledistance); //normalize the obstacle direction as well
554  float angle = obstacledirection.Dot( destinationdirection );
555  if (obstacledistance-obstacle->rSize() < destinationdistance-target->rSize() && angle > warp_behind_angle) {
556  //if our obstacle is closer than obj and the obstacle is not behind us
557  QVector planetdest = destination-obstacle->LocalPosition(); //find the vector from planet to dest
558  QVector planetme = -obstacledirection; //obstacle to me
559  QVector planetperp = planetme.Cross( planetdest ); //find vector out of that plane
560  QVector detourvector = destinationdirection.Cross( planetperp ); //find vector perpendicular to our desired course emerging from planet
561  double renormalizedetour = detourvector.Magnitude();
562  if (renormalizedetour > .01) detourvector = detourvector*(1./renormalizedetour); //normalize it
563  double finaldetourdistance = mymax( obstacle->rSize()*warp_orbit_multiplier, min_warp_orbit_radius ); //scale that direction by some multiplier of obstacle size and a constant
564  detourvector = detourvector*finaldetourdistance; //we want to go perpendicular to our transit direction by that ammt
565  QVector newdestination = NewDestination( obstacle->LocalPosition()+detourvector, finaldetourdistance ); //add to our position
566  float weight = (maxmultiplier-go_perpendicular_speed)/(enough_warp_for_cruise-go_perpendicular_speed); //find out how close we are to our desired warp multiplier and weight our direction by that
567  weight *= weight; //
568  if (maxmultiplier < go_perpendicular_speed) {
569  QVector perpendicular = myposition+planetme*( finaldetourdistance/planetme.Magnitude() );
570  weight = (go_perpendicular_speed-maxmultiplier)/go_perpendicular_speed;
571  destination = weight*perpendicular+(1-weight)*newdestination;
572  } else {
573  QVector olddestination = myposition+destinationdirection*finaldetourdistance; //destination direction in the same magnitude as the newdestination from the ship
574  destination = newdestination*(1-weight)+olddestination*weight; //use the weight to combine our direction and the dest
575  }
576  StraightToTarget = false;
577  } else {
578  StraightToTarget = true;
579  }
580  } else {StraightToTarget = true; }} else if (parent->graphicOptions.WarpFieldStrength >= enough_warp_for_cruise) {
581  StraightToTarget = true;
582  }
583  if (parent->graphicOptions.InWarp == 0 && parent->graphicOptions.RampCounter == 0)
584  deactivatewarp = false;
585  float mass = parent->GetMass();
586  float minaccel =
587  mymin( parent->limits.lateral, mymin( parent->limits.vertical, mymin( parent->limits.forward, parent->limits.retro ) ) );
588  if (mass) minaccel /= mass;
589  if ( StraightToTarget && useJitteryAutopilot( parent, target, minaccel ) ) {
590  QVector cfacing = parent->cumulative_transformation_matrix.getR(); //velocity.Cast();
591  float speed = cfacing.Magnitude();
592  if (speed > .01)
593  cfacing = cfacing*(1./speed);
594  static float dotLimit =
595  cos( 3.1415926536*XMLSupport::parse_float( vs_config->getVariable( "physics",
596  "autopilot_spec_lining_up_angle",
597  "3" ) )/180. );
598  if (cfacing.Dot( destinationdirection ) < dotLimit) //if wanting to face target but overshooting.
599  deactivatewarp = true; //turn off drive
600  }
601  static bool rampdown = XMLSupport::parse_bool( vs_config->getVariable( "physics", "autopilot_ramp_warp_down", "true" ) );
602  if (DistanceWarrantsWarpTo( parent,
603  UnitUtil::getSignificantDistance( parent, target ), false ) && deactivatewarp == false) { \
604  if (parent->graphicOptions.InWarp == 0) {
605  parent->graphicOptions.InWarp = 1;
606  parent->graphicOptions.WarpRamping = 1;
607  }
608  } else if (parent->graphicOptions.InWarp == 1) {
609  parent->graphicOptions.InWarp = 0;
610  if (rampdown)
611  parent->graphicOptions.WarpRamping = 1;
612  }
613  SetDest( destination );
614  bool combat_mode = parent->GetComputerData().combat_mode;
615  parent->GetComputerData().combat_mode = !inside_landing_zone; //turn off limits in landing zone
617  parent->GetComputerData().combat_mode = combat_mode;
618  if (!finish)
619  ResetDone();
620  static float distance_to_stop =
621  XMLSupport::parse_float( vs_config->getVariable( "physics", "auto_pilot_termination_distance", "6000" ) );
622  static float enemy_distance_to_stop =
623  XMLSupport::parse_float( vs_config->getVariable( "physics", "auto_pilot_termination_distance_enemy", "24000" ) );
624  static bool do_auto_finish = XMLSupport::parse_bool( vs_config->getVariable( "physics", "autopilot_terminate", "true" ) );
625  double dis = UnitUtil::getSignificantDistance( parent, target );
626  bool stopnow = false;
627  float speed = parent->GetComputerData().max_combat_ab_speed;
628  if (speed && parent->limits.retro) {
629  float time_to_destination = dis/speed; //conservative
630  float time_to_stop = speed*mass/parent->limits.retro;
631  if (time_to_destination <= time_to_stop)
632  stopnow = true;
633  }
634  if ( do_auto_finish
635  && ( stopnow || dis < distance_to_stop || (target->Target() == parent && dis < enemy_distance_to_stop) ) ) {
636  parent->autopilotactive = false;
637  if (parent->graphicOptions.InWarp == 1) {
638  parent->graphicOptions.InWarp = 0;
639  if (rampdown)
640  parent->graphicOptions.WarpRamping = 1;
641  }
642  done = true;
643  }
644 }
645 
647 {
648 #ifdef ORDERDEBUG
649  VSFileSystem::vs_fprintf( stderr, "ft%x", this );
650  fflush( stderr );
651 #endif
652 }
653 
655 {
656  if ( un->getFlightgroup() )
659 }
660 FaceDirection::FaceDirection( float dist, bool fini, int accuracy ) : ChangeHeading( QVector( 0, 0, 1 ), accuracy )
661  , finish( fini )
662 {
663  type = FACING;
664  subtype |= SSELF;
665  this->dist = dist;
666 }
667 
669 {
670  Unit *target = group.GetUnit();
671  if (target == NULL) {
672  done = finish;
673  return;
674  }
675  Vector face( target->GetTransformation().getR() );
676  if ( ( parent->Position()-target->Position() ).Magnitude()-parent->rSize()-target->rSize() > dist )
677  SetDest( target->Position() );
678  else
679  SetDest( parent->Position()+face.Cast() );
681  if (!finish)
682  ResetDone();
683 }
684 
686 {
687 #ifdef ORDERDEBUG
688  VSFileSystem::vs_fprintf( stderr, "ft%x", this );
689  fflush( stderr );
690 #endif
691 }
692 
694 {
695  if ( un->getFlightgroup() )
697  MoveTo::SetParent( un );
698 }
699 
700 FormUp::FormUp( const QVector &pos ) : MoveTo( QVector( 0, 0, 0 ), false, 255, false )
701  , Pos( pos )
702 {
703  subtype |= SSELF;
704 }
705 void FormUp::SetPos( const QVector &v )
706 {
707  Pos = v;
708 }
710 {
711  Unit *targ = group.GetUnit();
712  if (targ) {
713  MoveTo::SetDest( Transform( targ->GetTransformation(), Pos ) );
714  static bool can_warp_to = XMLSupport::parse_bool( vs_config->getVariable( "AI", "warp_to_wingmen", "true" ) );
715  if ( rand()%64 == 0 && ( can_warp_to || _Universe->AccessCockpit()->autoInProgress() ) )
716  WarpToP( parent, targ, true );
717  }
718  MoveTo::Execute();
719 }
720 
722 
724 {
725  Unit *ownerDoNotDereference = NULL;
726  Unit *temp;
728  (temp = *i) != NULL;
729  ++i)
730  if (temp == un->owner) {
731  ownerDoNotDereference = temp;
732  break;
733  }
734  if (ownerDoNotDereference != NULL)
735  AttachSelfOrder( ownerDoNotDereference );
736  MoveTo::SetParent( un );
737 }
738 
739 FormUpToOwner::FormUpToOwner( const QVector &pos ) : MoveTo( QVector( 0, 0, 0 ), false, 255, false )
740  , Pos( pos )
741 {
742  subtype |= SSELF;
743 }
745 {
746  Pos = v;
747 }
749 {
750  Unit *targ = group.GetUnit();
751  if (targ) {
752  MoveTo::SetDest( Transform( targ->GetTransformation(), Pos ) );
753  static bool can_warp_to = XMLSupport::parse_bool( vs_config->getVariable( "AI", "warp_to_wingmen", "true" ) );
754  if ( rand()%64 == 0 && ( can_warp_to || _Universe->AccessCockpit()->autoInProgress() ) )
755  WarpToP( parent, targ, true );
756  }
757  MoveTo::Execute();
758 }
759 
761