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
planet_generic.cpp
Go to the documentation of this file.
1 #include "planet_generic.h"
2 #include "unit_factory.h"
3 #include "gfx/mesh.h"
4 #include "galaxy_xml.h"
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include "universe_util.h"
8 #include "lin_time.h"
9 
10 char * getnoslash( char *inp )
11 {
12  char *tmp = inp;
13  for (unsigned int i = 0; inp[i] != '\0'; i++)
14  if (inp[i] == '/' || inp[i] == '\\')
15  tmp = inp+i+1;
16  return tmp;
17 }
18 
19 string getCargoUnitName( const char *textname )
20 {
21  char *tmp2 = strdup( textname );
22  char *tmp = getnoslash( tmp2 );
23  unsigned int i;
24  for (i = 0; tmp[i] != '\0' && (isalpha( tmp[i] ) || tmp[i] == '_'); i++) {}
25  if (tmp[i] != '\0')
26  tmp[i] = '\0';
27  string retval( tmp );
28  free( tmp2 );
29  return retval;
30 }
31 
33  double velocity,
34  double initpos,
35  const QVector &x_axis,
36  const QVector &y_axis,
37  const QVector &centre,
38  Unit *targetunit ) : Order( MOVEMENT, 0 )
39  , velocity( velocity )
40  , theta( initpos )
41  , inittheta( initpos )
42  , x_size( x_axis )
43  , y_size( y_axis )
44  , current_orbit_frame( 0 )
45 {
46  for (unsigned int t = 0; t < NUM_ORBIT_AVERAGE; ++t)
47  orbiting_average[t] = QVector( 0, 0, 0 );
48  orbiting_last_simatom = SIMULATION_ATOM;
49  orbit_list_filled = false;
50  p->SetResolveForces( false );
51  double delta = x_size.Magnitude()-y_size.Magnitude();
52  if (delta == 0)
53  focus = QVector( 0, 0, 0 );
54  else if (delta > 0)
55  focus = x_size*( delta/x_size.Magnitude() );
56  else
57  focus = y_size*( -delta/y_size.Magnitude() );
58  if (targetunit) {
59  type = (MOVEMENT);
60  subtype = (SSELF);
61  AttachSelfOrder( targetunit );
62  } else {
63  type = (MOVEMENT);
64  subtype = (SLOCATION);
65  AttachOrder( centre );
66  }
67  const double div2pi = ( 1.0/(2.0*PI) );
68  if (Network != NULL || SERVER)
69  theta = inittheta+velocity * getNewTime()*div2pi;
70  this->SetParent( p );
71 }
72 
74 {
75  parent->SetResolveForces( true );
76 }
77 
79 {
80  bool mining = parent->rSize() > 1444 && parent->rSize() < 1445;
81  bool done = this->done;
82  this->Order::Execute();
83  this->done = done; //we ain't done till the cows come home
84  if (done)
85  return;
86  QVector origin( targetlocation );
87  static float orbit_centroid_averaging = XMLSupport::parse_float( vs_config->getVariable( "physics", "orbit_averaging", "16" ) );
88  float averaging = (float) orbit_centroid_averaging/(float) (parent->predicted_priority+1.0f);
89  if (averaging < 1.0f) averaging = 1.0f;
90  if (subtype&SSELF) {
91  Unit *unit = group.GetUnit();
92  if (unit) {
93  unsigned int o = current_orbit_frame++;
94  current_orbit_frame %= NUM_ORBIT_AVERAGE;
95  if (current_orbit_frame == 0)
96  orbit_list_filled = true;
97  QVector desired = unit->prev_physical_state.position;
98  if (orbiting_average[o].i == 0 && orbiting_average[o].j == 0 && orbiting_average[o].k == 0) {
99  //clear all of them.
100  for (o = 0; o < NUM_ORBIT_AVERAGE; o++)
101  orbiting_average[o] = desired;
102  orbiting_last_simatom = SIMULATION_ATOM;
103  current_orbit_frame = 2;
104  orbit_list_filled = false;
105  } else {
106  if (SIMULATION_ATOM != orbiting_last_simatom) {
107  QVector sum_diff( 0, 0, 0 );
108  QVector sum_position;
109  int limit;
110  if (orbit_list_filled) {
111  sum_position = orbiting_average[o];
112  limit = NUM_ORBIT_AVERAGE-1;
113  o = (o+1)%NUM_ORBIT_AVERAGE;
114  } else {
115  sum_position = orbiting_average[0];
116  limit = o;
117  o = 1;
118  }
119  for (int i = 0; i < limit; i++) {
120  sum_diff += (orbiting_average[o]-orbiting_average[(o+NUM_ORBIT_AVERAGE-1)%NUM_ORBIT_AVERAGE]);
121  sum_position += orbiting_average[o];
122  o = (o+1)%NUM_ORBIT_AVERAGE;
123  }
124  if (limit != 0)
125  sum_diff *= ( 1./(limit) );
126  sum_position *= ( 1./(limit+1) );
127 
128  float ratio_simatom = (SIMULATION_ATOM/orbiting_last_simatom);
129  sum_diff *= ratio_simatom;
130  unsigned int number_to_fill;
131  number_to_fill = (int) ( (NUM_ORBIT_AVERAGE/ratio_simatom)+.99 );
132  if (number_to_fill > NUM_ORBIT_AVERAGE) number_to_fill = NUM_ORBIT_AVERAGE;
133  if (ratio_simatom <= 1)
134  number_to_fill = NUM_ORBIT_AVERAGE;
135  //subtract it so the average remains the same.
136  sum_position += ( sum_diff*(number_to_fill/ -2.) );
137  for (o = 0; o < number_to_fill; o++) {
138  orbiting_average[o] = sum_position;
139  sum_position += sum_diff;
140  }
141  orbit_list_filled = (o >= NUM_ORBIT_AVERAGE-1);
142  o %= NUM_ORBIT_AVERAGE;
143  current_orbit_frame = (o+1)%NUM_ORBIT_AVERAGE;
144  orbiting_last_simatom = SIMULATION_ATOM;
145  }
146  orbiting_average[o] = desired;
147  }
148  } else {
149  done = true;
150  parent->SetResolveForces( true );
151  return; //flung off into space.
152  }
153  }
154  QVector sum_orbiting_average( 0, 0, 0 );
155  {
156  int limit;
157  if (orbit_list_filled)
158  limit = NUM_ORBIT_AVERAGE;
159  else
160  limit = current_orbit_frame;
161  for (int o = 0; o < limit; o++)
162  sum_orbiting_average += orbiting_average[o];
163  sum_orbiting_average *= 1./(limit == 0 ? 1 : limit);
164  }
165  const double div2pi = ( 1.0/(2.0*PI) );
166  theta += velocity*SIMULATION_ATOM*div2pi;
167  if (Network != NULL || SERVER) {
168  float truetheta = inittheta+velocity * getNewTime()*div2pi;
169  theta = theta*( (averaging-1.0f)/averaging )+truetheta*(1.0f/averaging);
170  }
171  QVector x_offset = cos( theta )*x_size;
172  QVector y_offset = sin( theta )*y_size;
173 
174  QVector destination = origin-focus+sum_orbiting_average+x_offset+y_offset;
175  double mag = ( destination-parent->LocalPosition() ).Magnitude();
176  if (mining && 0) {
177  printf( "(%.2f %.2f %.2f)\n(%.2f %.2f %.2f) del %.2f spd %.2f\n",
178  parent->LocalPosition().i,
179  parent->LocalPosition().j,
180  parent->LocalPosition().k,
181  destination.i,
182  destination.j,
183  destination.k,
184  mag,
185  mag*(1./SIMULATION_ATOM)
186  );
187  }
188  parent->Velocity = parent->cumulative_velocity = ( ( ( destination-parent->LocalPosition() )*(1./SIMULATION_ATOM) ).Cast() );
189  static float Unreasonable_value =
190  XMLSupport::parse_float( vs_config->getVariable( "physics", "planet_ejection_stophack", "2000" ) );
191  float v2 = parent->Velocity.Dot( parent->Velocity );
192  if (v2 > Unreasonable_value*Unreasonable_value ) {
193  parent->Velocity.Set( 0, 0, 0 );
194  parent->cumulative_velocity.Set( 0, 0, 0 );
195  parent->SetCurPosition( origin-focus+sum_orbiting_average+x_offset+y_offset );
196  }
197 }
198 
199 string GetElMeshName( string name, string faction, char direction )
200 {
201  using namespace VSFileSystem;
202  char strdir[2] = {direction, 0};
203  string elxmesh = string( strdir )+"_elevator.bfxm";
204  string elevator_mesh = name+"_"+faction+elxmesh;
205  VSFile f;
206  VSError err = f.OpenReadOnly( elevator_mesh, MeshFile );
207  if (err > Ok)
208  f.Close();
209  else elevator_mesh = name+elxmesh;
210  return elevator_mesh;
211 }
212 
213 Vector Planet::AddSpaceElevator( const std::string &name, const std::string &faction, char direction )
214 {
215  Vector dir, scale;
216  switch (direction)
217  {
218  case 'u':
219  dir.Set( 0, 1, 0 );
220  break;
221  case 'd':
222  dir.Set( 0, -1, 0 );
223  break;
224  case 'l':
225  dir.Set( -1, 0, 0 );
226  break;
227  case 'r':
228  dir.Set( 1, 0, 0 );
229  break;
230  case 'b':
231  dir.Set( 0, 0, -1 );
232  break;
233  default:
234  dir.Set( 0, 0, 1 );
235  break;
236  }
237  Matrix ElevatorLoc( Vector( dir.j, dir.k, dir.i ), dir, Vector( dir.k, dir.i, dir.j ) );
238  scale = dir*radius+Vector( 1, 1, 1 )-dir;
239  Mesh *shield = meshdata.back();
240  string elevator_mesh = GetElMeshName( name, faction, direction ); //filename
241  Mesh *tmp = meshdata.back() = Mesh::LoadMesh( elevator_mesh.c_str(),
242  scale,
244  GetFactionIndex( faction ),
245  NULL );
246 
247  meshdata.push_back( shield );
248  {
249  //subunit computations
250  Vector mn( tmp->corner_min() );
251  Vector mx( tmp->corner_max() );
252  if (dir.Dot( Vector( 1, 1, 1 ) ) > 0)
253  ElevatorLoc.p.Set( dir.i*mx.i, dir.j*mx.j, dir.k*mx.k );
254  else
255  ElevatorLoc.p.Set( -dir.i*mn.i, -dir.j*mn.j, -dir.k*mn.k );
256  Unit *un = UnitFactory::createUnit( name.c_str(), true, FactionUtil::GetFactionIndex( faction ), "", NULL );
257  if (pImage->dockingports.back().GetPosition().MagnitudeSquared() < 10)
258  pImage->dockingports.clear();
259  pImage->dockingports.push_back( DockingPorts( ElevatorLoc.p, un->rSize()*1.5, 0, DockingPorts::Type::INSIDE ) );
260  un->SetRecursiveOwner( this );
261  un->SetOrientation( ElevatorLoc.getQ(), ElevatorLoc.getR() );
262  un->SetPosition( ElevatorLoc.p );
263  SubUnits.prepend( un );
264  }
265  return dir;
266 }
267 
269 
271 {
272  if (level > 2) {
273  un_iter satiterator = satellites.createIterator();
274  assert( *satiterator );
275  if ( (*satiterator)->isUnit() == PLANETPTR ) {
276  return ( (Planet*) (*satiterator) )->GetTopPlanet( level-1 );
277  } else {
278  VSFileSystem::vs_fprintf( stderr, "Planets are unable to orbit around units" );
279  return NULL;
280  }
281  } else {
282  return this;
283  }
284 }
285 
286 void Planet::AddSatellite( Unit *orbiter )
287 {
288  satellites.prepend( orbiter );
289  orbiter->SetOwner( this );
290 }
291 
292 extern float ScaleJumpRadius( float );
294 
296  QVector y,
297  float vely,
298  const Vector &rotvel,
299  float pos,
300  float gravity,
301  float radius,
302  const string &filename,
303  const string &technique,
304  const string &unitname,
305  BLENDFUNC blendSrc,
306  BLENDFUNC blendDst,
307  const vector< string > &dest,
308  int level,
309  const GFXMaterial &ourmat,
310  const vector< GFXLightLocal > &ligh,
311  bool isunit,
312  int faction,
313  string fullname,
314  bool inside_out )
315 {
316  //this function is OBSOLETE
317  Unit *un = NULL;
318  if (level > 2) {
319  un_iter satiterator = satellites.createIterator();
320  assert( *satiterator );
321  if ( (*satiterator)->isUnit() == PLANETPTR ) {
322  un = ( (Planet*) (*satiterator) )->beginElement( x, y, vely, rotvel, pos,
323  gravity, radius,
324  filename, technique, unitname,
325  blendSrc, blendDst,
326  dest,
327  level-1,
328  ourmat, ligh,
329  isunit,
330  faction, fullname,
331  inside_out );
332  } else {
333  VSFileSystem::vs_fprintf( stderr, "Planets are unable to orbit around units" );
334  }
335  } else {
336  if (isunit == true) {
337  Unit *sat_unit = NULL;
338  Flightgroup *fg = getStaticBaseFlightgroup( faction );
339  satellites.prepend( sat_unit = UnitFactory::createUnit( filename.c_str(), false, faction, "", fg, fg->nr_ships-1 ) );
340  sat_unit->setFullname( fullname );
341  un = sat_unit;
342  un_iter satiterator( satellites.createIterator() );
343  (*satiterator)->SetAI( new PlanetaryOrbit( *satiterator, vely, pos, x, y, QVector( 0, 0, 0 ), this ) );
344  (*satiterator)->SetOwner( this );
345  } else {
346  Planet *p;
347  if (dest.size() != 0)
348  radius = ScaleJumpRadius( radius );
349  satellites.prepend( p = UnitFactory::createPlanet( x, y, vely, rotvel, pos, gravity, radius,
350  filename, technique, unitname,
351  blendSrc, blendDst, dest,
352  QVector( 0, 0, 0 ), this, ourmat, ligh, faction, fullname, inside_out ) );
353  un = p;
354  p->SetOwner( this );
355  }
356  }
357  return un;
358 }
359 
361  Unit( 0 )
362  , radius( 0.0f )
363  , satellites()
364 {
365  inside = false;
366  //Not needed as Unit default constructor is called and already does Init
367  //Init();
368  terraintrans = NULL;
369  atmospheric = false;
370  //Force shields to 0
371  memset( &(this->shield), 0, sizeof (Unit::shield) );
372  this->shield.number = 2;
373 }
374 
376  QVector y,
377  float vely,
378  const Vector &rotvel,
379  float pos,
380  float gravity,
381  float radius,
382  const string &filename,
383  const string &technique,
384  const string &unitname,
385  const vector< string > &dest,
386  const QVector &orbitcent,
387  Unit *parent,
388  int faction,
389  string fullname,
390  bool inside_out,
391  unsigned int lights_num )
392 {
393  atmosphere = NULL;
394  terrain = NULL;
395  static float bodyradius = XMLSupport::parse_float( vs_config->getVariable( "graphics", "star_body_radius", ".33" ) );
396  if (lights_num)
397  radius *= bodyradius;
398  inside = false;
400  Init();
401  //static int neutralfaction=FactionUtil::GetFaction("neutral");
402  //this->faction = neutralfaction;
403  killed = false;
404  bool notJumppoint = dest.empty();
405  for (unsigned int i = 0; i < dest.size(); ++i)
406  AddDestination( dest[i] );
407  //name = "Planet - ";
408  //name += textname;
409  name = fullname;
410  this->fullname = name;
411  this->radius = radius;
412  this->gravity = gravity;
413  static float densityOfRock = XMLSupport::parse_float( vs_config->getVariable( "physics", "density_of_rock", "3" ) );
414  static float densityOfJumpPoint =
415  XMLSupport::parse_float( vs_config->getVariable( "physics", "density_of_jump_point", "100000" ) );
416  //static float massofplanet = XMLSupport::parse_float(vs_config->getVariable("physics","mass_of_planet","10000000"));
417  hull = (4./3)*M_PI*radius*radius*radius*(notJumppoint ? densityOfRock : densityOfJumpPoint);
418  this->Mass = (4./3)*M_PI*radius*radius*radius*( notJumppoint ? densityOfRock : (densityOfJumpPoint/100000) );
419  SetAI( new PlanetaryOrbit( this, vely, pos, x, y, orbitcent, parent ) ); //behavior
420  terraintrans = NULL;
421 
422  colTrees = NULL;
423  SetAngularVelocity( rotvel );
424  // The docking port is 20% bigger than the planet
425  static float planetdockportsize = XMLSupport::parse_float( vs_config->getVariable( "physics", "planet_port_size", "1.2" ) );
426  static float planetdockportminsize =
427  XMLSupport::parse_float( vs_config->getVariable( "physics", "planet_port_min_size", "300" ) );
428  if ( (!atmospheric) && notJumppoint ) {
429  float dock = radius*planetdockportsize;
430  if (dock-radius < planetdockportminsize)
431  dock = radius+planetdockportminsize;
432  pImage->dockingports.push_back( DockingPorts( Vector( 0, 0, 0 ), dock, 0, DockingPorts::Type::CONNECTED_OUTSIDE ) );
433  }
434  string tempname = unitname.empty() ? ::getCargoUnitName( filename.c_str() ) : unitname;
435  setFullname( tempname );
436 
437  int tmpfac = faction;
438  if (UniverseUtil::LookupUnitStat( tempname, FactionUtil::GetFactionName( faction ), "Cargo_Import" ).length() == 0)
440  Unit *un = UnitFactory::createUnit( tempname.c_str(), true, tmpfac );
441 
442  static bool smartplanets = XMLSupport::parse_bool( vs_config->getVariable( "physics", "planets_can_have_subunits", "false" ) );
443  if ( un->name != string( "LOAD_FAILED" ) ) {
447  VSSprite *tmp = pImage->pHudImage;
449  un->GetImageInformation().pHudImage = tmp;
450  maxwarpenergy = un->WarpCapData();
451  if (smartplanets) {
452  SubUnits.prepend( un );
453  un->SetRecursiveOwner( this );
454  this->SetTurretAI();
455  un->SetTurretAI(); //allows adding planetary defenses, also allows launching fighters from planets, interestingly
456  un->name = "Defense_grid";
457  }
458  static bool neutralplanets =
459  XMLSupport::parse_bool( vs_config->getVariable( "physics", "planets_always_neutral", "true" ) );
460  if (neutralplanets) {
461  static int neutralfaction = FactionUtil::GetNeutralFaction();
462  this->faction = neutralfaction;
463  } else {
464  this->faction = faction;
465  }
466  }
467  if ( un->name == string( "LOAD_FAILED" ) || (!smartplanets) )
468  un->Kill();
469 }
470 
472  QVector y,
473  float vely,
474  const Vector &rotvel,
475  float pos,
476  float gravity,
477  float radius,
478  const string &filename,
479  const string &technique,
480  const string &unitname,
481  const vector< string > &dest,
482  const QVector &orbitcent,
483  Unit *parent,
484  int faction,
485  string fullname,
486  bool inside_out,
487  unsigned int lights_num )
488 {
489  inside = false;
490  terraintrans = NULL;
491  atmospheric = false;
492  this->InitPlanet( x, y, vely, rotvel,
493  pos,
494  gravity, radius,
495  filename, technique, unitname,
496  dest,
497  orbitcent, parent,
498  faction, fullname,
499  inside_out,
500  lights_num );
501  corner_min.i = corner_min.j = corner_min.k = -this->radius;
502  corner_max.i = corner_max.j = corner_max.k = this->radius;
503  this->radial_size = this->radius;
504  for (unsigned int i = 0; i < lights_num; i++) {
505  int l = -1;
506  lights.push_back( l );
507  }
508  //Force shields to 0
509  /*
510  * this->shield.number=2;
511  * this->shield.recharge=0;
512  * this->shield.shield2fb.frontmax=0;
513  * this->shield.shield2fb.backmax=0;
514  * this->shield.shield2fb.front=0;
515  * this->shield.shield2fb.back=0;
516  */
517  memset( &(this->shield), 0, sizeof (Unit::shield) );
518  this->shield.number = 2;
519  if ( meshdata.empty() ) meshdata.push_back( NULL );
520 }
521 
523 {
524  //static std::map<std::string, std::string> planetTypes (readPlanetTypes("planet_types.xml"));
525  //return planetTypes[getCargoUnitName()];
527 }
528 
530 {
531  if (terraintrans) {
532  Matrix *tmp = new Matrix();
534  //terraintrans->SetTransformation (tmp);
535  }
536 }
537 
538 void Planet::Kill( bool erasefromsave )
539 {
540  un_iter iter;
541  Unit *tmp;
542  for (iter = satellites.createIterator();
543  (tmp = *iter);
544  ++iter)
545  tmp->SetAI( new Order );
546  /* probably not FIXME...right now doesn't work on paged out systems... not a big deal */
547  satellites.clear();
548  insiders.clear();
549  Unit::Kill( erasefromsave );
550 }
551