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
galaxy_gen.cpp
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <vector>
4 #include <string>
5 #include "macosx_math.h"
6 #include <math.h>
7 #include <time.h>
8 #include <assert.h>
9 
10 #include "configxml.h"
11 #include "vs_globals.h"
12 #include "xml_support.h"
13 #include "gfxlib.h"
14 #include "galaxy_xml.h"
15 #include "galaxy_gen.h"
16 #include "vs_random.h"
17 
18 #ifndef _WIN32
19 #include <ctype.h>
20 #endif
21 
22 #if _MSC_VER >= 1300
23 #define snprintf _snprintf
24 #endif
25 
26 #ifndef M_PI
27 #define M_PI 3.1415926536
28 #endif
29 #include "vsfilesystem.h"
30 
31 using namespace VSFileSystem;
32 using std::string;
33 using std::vector;
34 
35 static VSRandom starsysrandom( time( NULL ) );
36 static void seedrand( unsigned long seed )
37 {
38  starsysrandom = VSRandom( seed );
39 }
40 static int stringhash( const string &key )
41 {
42  unsigned int k = 0;
43  string::const_iterator start = key.begin();
44  for (; start != key.end(); start++)
45  k += (k*128)+*start;
46  return k;
47 }
48 
49 static unsigned int ssrand()
50 {
51  return starsysrandom.rand();
52 }
53 
54 static string GetWrapXY( string cname, int &wrapx, int &wrapy )
55 {
56  string wrap = cname;
57  wrapx = wrapy = 1;
58  string::size_type pos = wrap.find( "wrapx" );
59  if (pos != string::npos) {
60  string Wrapx = wrap.substr( pos+5, wrap.length() );
61  cname = cname.substr( 0, pos );
62  sscanf( Wrapx.c_str(), "%d", &wrapx );
63  pos = Wrapx.find( "wrapy" );
64  if (pos != string::npos) {
65  string Wrapy = Wrapx.substr( pos+5, Wrapx.length() );
66  sscanf( Wrapy.c_str(), "%d", &wrapy );
67  }
68  }
69  return cname;
70 }
71 
72 string getStarSystemName( const string &in );
73 
74 namespace StarSystemGent
75 {
76 float mmax( float a, float b )
77 {
78  return (a > b) ? a : b;
79 }
80 
81 int rnd( int lower, int upper )
82 {
83  if (upper > lower)
84  return lower+ssrand()%(upper-lower);
85  else return lower;
86 }
87 const char nada[1] = "";
88 string getGenericName( vector< string > &s )
89 {
90  if ( s.empty() )
91  return string( nada );
92  return s[rnd( 0, s.size() )];
93 }
94 
95 string getRandName( vector< string > &s )
96 {
97  if ( s.empty() )
98  return string( nada );
99  unsigned int i = rnd( 0, s.size() );
100  string k = s[i];
101  s.erase( s.begin()+i );
102  return k;
103 }
104 struct Color
105 {
106  float r, g, b, a;
107  float nr, ng, nb, na;
108  Color( float rr, float gg, float bb )
109  {
110  r = rr;
111  b = bb;
112  g = gg;
113  }
114 };
115 class Vector
116 {
117 public:
118  float i;
119  float j;
120  float k;
121  float s;
122  float t;
124  {
125  i = j = k = 0;
126  }
127  template < class vec >Vector( const vec &in )
128  {
129  memcpy( this, &in, sizeof (*this) );
130  }
131  Vector( const Vector &in )
132  {
133  memcpy( this, &in, sizeof (*this) );
134  }
135  Vector( float x, float y, float z )
136  {
137  i = x;
138  j = y;
139  k = z;
140  }
141  Vector( float x, float y, float z, float s, float t )
142  {
143  i = x;
144  j = y;
145  k = z;
146  this->s = s;
147  this->t = t;
148  }
149  float Mag()
150  {
151  return sqrtf( i*i+j*j+k*k );
152  }
153  Vector Cross( const Vector &v ) const
154  {
155  return Vector( this->j*v.k-this->k*v.j,
156  this->k*v.i-this->i*v.k,
157  this->i*v.j-this->j*v.i );
158  }
159  void Yaw( float rad ) //only works with unit vector
160  {
161  float theta = 0;
162  float m = Mag();
163  if (i > 0)
164  theta = (float) atan( k/i );
165  else if (i < 0)
166  theta = M_PI+(float) atan( k/i );
167  else if (k <= 0 && i == 0)
168  theta = -M_PI/2;
169  else if (k > 0 && i == 0)
170  theta = M_PI/2;
171  theta += rad;
172  i = m*cosf( theta );
173  k = m*sinf( theta );
174  }
175 
176  void Roll( float rad )
177  {
178  float theta = 0;
179  float m = Mag();
180  if (i > 0)
181  theta = (float) atan( j/i );
182  else if (i < 0)
183  theta = M_PI+(float) atan( j/i );
184  else if (j <= 0 && i == 0)
185  theta = -M_PI/2;
186  else if (j > 0 && i == 0)
187  theta = M_PI/2;
188  theta += rad;
189  i = m*cosf( theta );
190  j = m*sinf( theta );
191  }
192 
193  void Pitch( float rad )
194  {
195  float theta = 0;
196  float m = Mag();
197  if (k > 0)
198  theta = (float) atan( j/k );
199  else if (k < 0)
200  theta = M_PI+(float) atan( j/k );
201  else if (j <= 0 && k == 0)
202  theta = -M_PI/2;
203  else if (j > 0 && k == 0)
204  theta = M_PI/2;
205  theta += rad;
206  k = m*cosf( theta );
207  j = m*sinf( theta );
208  }
209 };
210 
211 float grand()
212 {
213  return float( ssrand() )/VS_RAND_MAX;
214 }
215 vector< Color >lights;
218 
219 static void Tab()
220 {
221  for (int i = 0; i < xmllevel; i++)
222  f.Fprintf( "\t" );
223 }
224 
225 float difffunc( float inputdiffuse )
226 {
227  return sqrt( ( (inputdiffuse) ) );
228 }
229 void WriteLight( unsigned int i )
230 {
231  static float ambientColorFactor = XMLSupport::parse_float( vs_config->getVariable( "galaxy", "AmbientLightFactor", "0" ) );
232  float ambient = (lights[i].r+lights[i].g+lights[i].b);
233 
234  ambient *= ambientColorFactor;
235  Tab();
236  f.Fprintf( "<Light>\n" );
237  xmllevel++;
238  Tab();
239  f.Fprintf( "<ambient red=\"%f\" green=\"%f\" blue=\"%f\"/>\n", ambient, ambient, ambient );
240  Tab();
241  f.Fprintf( "<diffuse red=\"%f\" green=\"%f\" blue=\"%f\"/>\n", difffunc( lights[i].r ), difffunc( lights[i].g ),
242  difffunc( lights[i].b ) );
243  Tab();
244  f.Fprintf( "<specular red=\"%f\" green=\"%f\" blue=\"%f\"/>\n", lights[i].nr, lights[i].ng, lights[i].nb );
245  xmllevel--;
246  Tab();
247  f.Fprintf( "</Light>\n" );
248 }
249 struct GradColor
250 {
251  float minrad;
252  float r;
253  float g;
254  float b;
255  float variance;
256 };
257 
258 const int STAR = 0;
259 const int PLANET = 1;
260 const int MOON = 2;
261 const int JUMP = 3;
262 //begin global variables
263 
264 vector< string >starentities;
265 vector< string >jumps;
266 vector< string >gradtex;
267 vector< string >naturalphenomena;
268 vector< string >starbases;
269 unsigned int numstarbases;
270 unsigned int numnaturalphenomena;
271 unsigned int numstarentities;
272 vector< string >background;
273 vector< string >names;
274 vector< string >rings;
275 const float moonofmoonprob = .01;
276 string systemname;
277 vector< float > radii;
278 const float minspeed = .001;
279 const float maxspeed = 8;
280 vector< float > starradius;
281 string faction;
282 vector< GradColor >colorGradiant;
283 float compactness = 2;
284 float jumpcompactness = 2;
285 
287 {
288  string name;
289  string unitname;
290  string technique;
291  unsigned int num; //The texture number for the city lights
292  unsigned int moonlevel; //0==top-level planet, 1==first-level moon, 2 is second-level moon... probably won't be used.
293  unsigned int numstarbases; //Number of starbases allocated to orbit around this planet. Usually 1 or 0 but quite possibly more.
294  unsigned int numjumps; //Number of jump points.
296  num( 0 )
297  , moonlevel( 0 )
298  , numstarbases( 0 )
299  , numjumps( 0 ) {}
300 };
301 
302 struct StarInfo
303 {
304  vector< PlanetInfo >planets;
305  unsigned int numjumps;
306  unsigned int numstarbases;
308  numjumps( 0 )
309  , numstarbases( 0 ) {}
310 };
311 vector< StarInfo >stars;
313 
315 {
316  xmllevel = 0;
317  lights.clear();
318  gradtex.clear();
319  naturalphenomena.clear();
320  starbases.clear();
321  starentities.clear();
322  numstarentities = 0;
323  numstarbases = 0;
325  background.clear();
326  stars.clear();
327  planetoffset = 0;
328  staroffset = 0;
329  moonlevel = 0;
330  names.clear();
331  jumps.clear();
332  rings.clear();
333  systemname.erase();
334  starradius.clear();
335  faction.erase();
336  colorGradiant.clear();
337  compactness = 2;
338  jumpcompactness = 2;
339  radii.clear();
340 }
341 
342 void readColorGrads( vector< string > &entity, const char *file )
343 {
344  VSFile f;
345  VSError err = f.OpenReadOnly( file, UniverseFile );
346  static float radiusscale = XMLSupport::parse_float( vs_config->getVariable( "galaxy", "StarRadiusScale", "1000" ) );
347  if (err > Ok) {
348  printf( "Failed to load %s", file );
349  GradColor( g );
350  g.minrad = 0;
351  g.r = g.g = g.b = .9;
352  g.variance = .1;
353  entity.push_back( "white_star.png" );
354  colorGradiant.push_back( g );
355  return;
356  }
357  char input_buffer[1000];
358  char output_buffer[1000];
359  GradColor g;
360  while ( !f.Eof() ) {
361  f.ReadLine( input_buffer, 999 );
362  if (sscanf( input_buffer, "%f %f %f %f %f %s", &g.minrad, &g.r, &g.g, &g.b, &g.variance, output_buffer ) == 6) {
363  g.minrad *= radiusscale;
364  colorGradiant.push_back( g );
365  entity.push_back( output_buffer );
366  }
367  }
368  f.Close();
369 }
370 
371 float clamp01( float a )
372 {
373  if (a > 1)
374  a = 1;
375  if (a < 0)
376  a = 0;
377  return a;
378 }
379 float getcolor( float c, float var )
380 {
381  return clamp01( c-var+2*var*grand() );
382 }
383 GradColor whichGradColor( float r, unsigned int &j )
384 {
385  unsigned int i;
386  if ( colorGradiant.empty() ) {
387  vector< string >entity;
388  string fullpath = "stars.txt";
389  readColorGrads( entity, fullpath.c_str() );
390  }
391  for (i = 1; i < colorGradiant.size(); i++)
392  if (colorGradiant[i].minrad > r)
393  break;
394  j = i-1;
395  return colorGradiant[i-1];
396 }
397 
398 Color StarColor( float radius, unsigned int &entityindex )
399 {
400  GradColor gc = whichGradColor( radius, entityindex );
401  float r = getcolor( gc.r, gc.variance );
402  float g = getcolor( gc.g, gc.variance );
403  float b = getcolor( gc.b, gc.variance );
404  return Color( r, g, b );
405 }
407 {
408  unsigned int myint = 0;
409  static float radiusscale = XMLSupport::parse_float( vs_config->getVariable( "galaxy", "StarRadiusScale", "1000" ) );
410  Color tmp = StarColor( radius*radiusscale, myint );
411  return GFXColor( tmp.r, tmp.g, tmp.b, 1 );
412 }
414 {
415  float a = 2*M_PI*mmax( r.Mag(), s.Mag() );
416  float speed = minspeed+(maxspeed-minspeed)*grand();
417  return a/speed;
418 }
419 
420 void CreateLight( unsigned int i )
421 {
422  if (i == 0) {
423  assert( !starradius.empty() );
424  assert( starradius[0] );
425  } else {
426  assert( starradius.size() == i );
427  starradius.push_back( starradius[0]*(.5+grand()*.5) );
428  }
429  unsigned int gradindex;
430  lights.push_back( StarColor( starradius[i], gradindex ) );
431  starentities.push_back( gradtex[gradindex] );
432  float h = lights.back().r;
433  if (h < lights.back().g) h = lights.back().g;
434  if (h < lights.back().b) h = lights.back().b;
435  float norm = (.5+.5/numstarentities);
436  if (h > .001) {
437  lights.back().nr = lights.back().r/h;
438  lights.back().ng = lights.back().g/h;
439  lights.back().nb = lights.back().b/h;
440 
441  lights.back().r *= norm/h;
442  lights.back().g *= norm/h;
443  lights.back().b *= norm/h;
444  } else {
445  lights.back().nr = 0;
446  lights.back().ng = 0;
447  lights.back().nb = 0;
448  }
449  WriteLight( i );
450 }
451 
452 Vector generateCenter( float minradii, bool jumppoint )
453 {
454  Vector r;
455  float tmpcompactness = compactness;
456  if (jumppoint)
457  tmpcompactness = jumpcompactness;
458  r = Vector( tmpcompactness*grand()+1, tmpcompactness*grand()+1, tmpcompactness*grand()+1 );
459  r.i *= minradii;
460  r.j *= minradii;
461  r.k *= minradii;
462  int i = ( rnd( 0, 8 ) );
463  r.i = (i&1) ? -r.i : r.i;
464  r.j = (i&2) ? -r.j : r.j;
465  r.k = (i&4) ? -r.k : r.k;
466  return r;
467 }
468 float makeRS( Vector &r, Vector &s, float minradii, bool jumppoint )
469 {
470  r = Vector( grand(), grand(), grand() );
471  int i = ( rnd( 0, 8 ) );
472  r.i = (i&1) ? -r.i : r.i;
473  r.j = (i&2) ? -r.j : r.j;
474  r.k = (i&4) ? -r.k : r.k;
475 
476  Vector k( grand(), grand(), grand() );
477  i = ( rnd( 0, 8 ) );
478  k.i = (i&1) ? -k.i : k.i;
479  k.j = (i&2) ? -k.j : k.j;
480  k.k = (i&4) ? -k.k : k.k;
481 
482  s = r.Cross( k );
483  float sm = s.Mag();
484  if (sm < .01)
485  return makeRS( r, s, minradii, jumppoint );
486  s.i /= sm;
487  s.j /= sm;
488  s.k /= sm;
489  sm = r.Mag();
490  r.i /= sm;
491  r.j /= sm;
492  r.k /= sm;
493  bool tmp = false;
494  float rm;
495  float tmpcompactness = compactness;
496  if (jumppoint)
497  tmpcompactness = jumpcompactness;
498  rm = (tmpcompactness*grand()+1);
499  if (rm < 1) {
500  rm = (1+grand()*.5);
501  tmp = true;
502  }
503  rm *= minradii;
504  r.i *= rm;
505  r.j *= rm;
506  r.k *= rm;
507  sm = (tmpcompactness*grand()+1);
508  if (tmp) sm = (1+grand()*.5);
509  sm *= minradii;
510  s.i *= sm;
511  s.j *= sm;
512  s.k *= sm;
513  return mmax( rm, sm );
514 }
515 
516 void Updateradii( float orbitsize, float thisplanetradius )
517 {
518 #ifdef HUGE_SYSTEMS
519  orbitsize += thisplanetradius;
520  radii.back() = orbitsize;
521 #endif
522 }
523 
524 Vector generateAndUpdateRS( Vector &r, Vector &s, float thisplanetradius, bool jumppoint )
525 {
526  if ( radii.empty() ) {
527  r = Vector( 0, 0, 0 );
528  s = Vector( 0, 0, 0 );
529  return generateCenter( starradius[0], jumppoint );
530  }
531  float tmp = radii.back()+thisplanetradius;
532  Updateradii( makeRS( r, s, tmp, jumppoint ), thisplanetradius );
533  return generateCenter( tmp, jumppoint );
534 }
535 
536 vector< string >parseBigUnit( const string &input )
537 {
538  char *mystr = strdup( input.c_str() );
539  char *ptr = mystr;
540  char *oldptr = mystr;
541  vector< string >ans;
542  while (*ptr != '\0') {
543  while (*ptr != '&' && *ptr != '\0')
544  ptr++;
545  if (*ptr == '&') {
546  *ptr = '\0';
547  ptr++;
548  }
549  ans.push_back( string( oldptr ) );
550  oldptr = ptr;
551  }
552  free( mystr );
553  return ans;
554 }
555 
556 void WriteUnit( const string &tag,
557  const string &name,
558  const string &filename,
559  const Vector &r,
560  const Vector &s,
561  const Vector &center,
562  const string &nebfile,
563  const string &destination,
564  bool faction,
565  float thisloy = 0 )
566 {
567  Tab();
568  f.Fprintf( "<%s name=\"%s\" file=\"%s\" ", tag.c_str(), name.c_str(), filename.c_str() );
569  if (nebfile.length() > 0)
570  f.Fprintf( "nebfile=\"%s\" ", nebfile.c_str() );
571  f.Fprintf( "ri=\"%f\" rj=\"%f\" rk=\"%f\" si=\"%f\" sj=\"%f\" sk=\"%f\" ", r.i, r.j, r.k, s.i, s.j, s.k );
572  f.Fprintf( "x=\"%f\" y=\"%f\" z=\"%f\" ", center.i, center.j, center.k );
573  float loy = LengthOfYear( r, s );
574  if (loy || thisloy)
575  f.Fprintf( "year= \"%f\" ", thisloy ? thisloy : loy );
576  if ( destination.length() )
577  f.Fprintf( "destination=\"%s\" ", destination.c_str() );
578  else if (faction)
579  f.Fprintf( "faction=\"%s\" ", StarSystemGent::faction.c_str() );
580  f.Fprintf( "/>\n" );
581 }
582 string getJumpTo( const string &s )
583 {
584  char tmp[1000] = "";
585  if ( 1 == sscanf( s.c_str(), "Jump_To_%s", tmp ) )
586  tmp[0] = tolower( tmp[0] );
587  else return s;
588  return string( tmp );
589 }
590 string starin( const string &input )
591 {
592  char *tmp = strdup( input.c_str() );
593  for (unsigned int i = 0; tmp[i] != '\0'; i++)
594  if (tmp[i] == '*') {
595  tmp[i] = '\0';
596  string ans( tmp );
597  free( tmp );
598  return ans;
599  }
600  free( tmp );
601  return string();
602 }
603 
604 string GetNebFile( string &input )
605 {
606  string ip = input.c_str();
607  char *ptr = strdup( ip.c_str() );
608  for (unsigned int i = 0; ptr[i] != '\0'; i++)
609  if (ptr[i] == '^') {
610  ptr[i] = '\0';
611  string ans( ptr );
612  input = ptr+i+1;
613  free( ptr );
614  return ans;
615  }
616  free( ptr );
617  return string();
618 }
619 
620 string AnalyzeType( string &input, string &nebfile, float &radius )
621 {
622  if ( input.empty() )
623  return "";
624  char ptr = *input.begin();
625  string ip;
626  if ( 0 == sscanf( GetNebFile( input ).c_str(), "%f", &radius ) ) {
627  radius = 100;
628  ip = (input.c_str()+1);
629  } else {
630  ip = (input);
631  }
632  string retval;
633  switch (ptr)
634  {
635  case 'N':
636  nebfile = GetNebFile( input );
637  retval = "Nebula";
638  break;
639  case 'A':
640  retval = "Asteroid";
641  break;
642  case 'B':
643  retval = "Building";
644  break;
645  case 'E':
646  retval = "Enhancement";
647  break;
648  case 'U':
649  default:
650  retval = "Unit";
651  }
652  return retval;
653 }
655 {
656  Vector R, S;
657 
658  string nam;
659  string s = string( "" );
660  while (s.length() == 0) {
661  nam = getRandName( starbases );
662  if (nam.length() == 0)
663  return;
664  string tmp;
665  if ( ( tmp = starin( nam ) ).length() > 0 ) {
666  nam = (tmp);
667  s = getRandName( jumps );
668  } else {
669  break;
670  }
671  }
672  numstarbases--;
673  string nebfile( "" );
674  float radius;
675  string type = AnalyzeType( nam, nebfile, radius );
676  Vector center = generateAndUpdateRS( R, S, radius, true );
677 
678  WriteUnit( type, "", nam, R, S, center, nebfile, s, true );
679 }
680 
681 void MakeJump( float radius, bool forceRS = false, Vector R = Vector( 0, 0, 0 ), Vector S = Vector( 0,
682  0,
683  0 ), Vector center = Vector(
684  0,
685  0,
686  0 ), float thisloy = 0 )
687 {
688  string s = getRandName( jumps );
689  if (s.length() == 0)
690  return;
691  Vector RR, SS;
692  if (forceRS) {
693  RR = R;
694  SS = S;
695  Updateradii( mmax( RR.Mag(), SS.Mag() ), radius );
696  } else {
697  center = generateAndUpdateRS( RR, SS, radius, true );
698  }
699  string thisname;
700  thisname = string( "Jump_To_" )+getStarSystemName( s );
701  if (thisname.length() > 8)
702  *(thisname.begin()+8) = toupper( *(thisname.begin()+8) );
703  Tab();
704  //backwards compatibility
705  static bool usePNGFilename = (VSFileSystem::LookForFile( "jump.png", VSFileSystem::TextureFile ) <= VSFileSystem::Ok);
706  static const char *jumpFilename = usePNGFilename ? "jump.png" : "jump.texture";
707  f.Fprintf( "<Jump name=\"%s\" file=\"%s\" ", thisname.c_str(), jumpFilename );
708  f.Fprintf( "ri=\"%f\" rj=\"%f\" rk=\"%f\" si=\"%f\" sj=\"%f\" sk=\"%f\" ", RR.i, RR.j, RR.k, SS.i, SS.j, SS.k );
709  f.Fprintf( "radius=\"%f\" ", radius );
710  f.Fprintf( "x=\"%f\" y=\"%f\" z=\"%f\" ", center.i, center.j, center.k );
711  float loy = LengthOfYear( RR, SS );
712  float temprandom = .1*fmod( loy, 10 ); //use this so as not to alter state here
713  if (loy || thisloy) {
714  f.Fprintf( "year= \"%f\" ", thisloy ? thisloy : loy );
715  temprandom = grand();
716  loy = 864*temprandom;
717  if (loy)
718  f.Fprintf( "day=\"%f\" ", loy );
719  }
720  f.Fprintf( "alpha=\"ONE ONE\" destination=\"%s\" faction=\"%s\" />\n", getJumpTo(
721  s ).c_str(), StarSystemGent::faction.c_str() );
722 
724 }
725 
726 void MakeBigUnit( int callingentitytype, string name = string(), float orbitalradius = 0 )
727 {
728  vector< string >fullname;
729  if (name.length() == 0) {
730  string s = getRandName( naturalphenomena );
731  if (s.length() == 0)
732  return;
733  fullname = parseBigUnit( s );
734  } else {
735  fullname.push_back( name );
736  }
737  if ( fullname.empty() )
738  return;
740  Vector r, s;
741 
742  float stdloy = 0;
743  bool first = false;
744  float size = 0;
745  string tmp;
746  Vector center( 0, 0, 0 );
747  string nebfile( "" );
748  for (unsigned int i = 0; i < fullname.size(); i++) {
749  if ( 1 == sscanf( fullname[i].c_str(), "jump%f", &size ) ) {
750  if (!first) {
751  first = true;
752  center = generateAndUpdateRS( r, s, size, callingentitytype != STAR );
753  stdloy = LengthOfYear( r, s );
754  }
755  MakeJump( size, true, r, s, center, stdloy );
756  //We still want jumps inside asteroid fields, etcVvv.
757  } else if ( 1
758  == sscanf( fullname[i].c_str(), "planet%f",
759  &size ) || 1
760  == sscanf( fullname[i].c_str(), "moon%f", &size ) || 1 == sscanf( fullname[i].c_str(), "gas%f", &size ) ) {
761  //FIXME: Obsolete/not supported/too lazy to implement.
762  } else if ( ( tmp = starin( fullname[i] ) ).length() > 0 ) {
763  if (!first) {
764  first = true;
765  center = generateAndUpdateRS( r, s, size, callingentitytype != STAR );
766  stdloy = LengthOfYear( r, s );
767  }
768  string S = getRandName( jumps );
769  if (S.length() > 0) {
770  string type = AnalyzeType( tmp, nebfile, size );
771  WriteUnit( type, S, tmp, r, s, center, nebfile, getJumpTo( S ), false, stdloy );
772  }
773  } else {
774  string type = AnalyzeType( fullname[i], nebfile, size );
775  if (!first) {
776  first = true;
777  center = generateAndUpdateRS( r, s, size, callingentitytype != STAR ? type == "Unit" : false );
778  stdloy = LengthOfYear( r, s );
779  }
780  WriteUnit( type, "", fullname[i], r, s, center, nebfile, string( "" ), i != 0, stdloy );
781  }
782  }
783 }
784 void MakeMoons( float callingradius, int callingentitytype );
785 void MakeJumps( float callingradius, int callingentitytype, int numberofjumps );
786 void MakePlanet( float radius, int entitytype, string texturename, string unitname, string technique, int texturenum, int numberofjumps, int numberofstarbases )
787 {
788  if (entitytype == JUMP) {
789  MakeJump( radius );
790  return;
791  }
792  if (texturename.length() == 0) //FIXME?
793  return;
794  Vector RR, SS;
795  Vector center = generateAndUpdateRS( RR, SS, radius, false );
796  string thisname;
797  thisname = getRandName( names );
798  Tab();
799  static string default_atmosphere = vs_config->getVariable( "galaxy",
800  "DefaultAtmosphereTexture",
801  "sol/earthcloudmaptrans.png" );
802  string atmosphere = _Universe->getGalaxy()->getPlanetVariable( texturename, "atmosphere", "false" );
803  if (atmosphere == "false")
804  atmosphere = "";
805  else if (atmosphere == "true")
806  atmosphere = default_atmosphere;
807  string cname;
808  string planetlites = _Universe->getGalaxy()->getPlanetVariable( texturename, "lights", "" );
809  if ( !planetlites.empty() ) {
810  planetlites = ' '+planetlites;
811  vector< string::size_type >lites;
812  lites.push_back( 0 );
813  while (lites.back() != string::npos)
814  lites.push_back( planetlites.find( lites.back()+1, ' ' ) );
815  unsigned randomnum = rnd( 0, lites.size()-1 );
816  cname = planetlites.substr( lites[randomnum]+1, lites[randomnum+1] );
817  }
818  f.Fprintf( "<Planet name=\"%s\" file=\"%s\" unit=\"%s\" ", thisname.c_str(), texturename.c_str(), unitname.c_str() );
819  if (!technique.empty())
820  f.Fprintf( "technique=\"%s\" ", technique.c_str() );
821  if (texturename.find_first_of('|') != string::npos)
822  f.Fprintf("Red=\"0\" Green=\"0\" Blue=\"0\" DRed=\"0.87\" DGreen=\"0.87\" DBlue=\"0.87\" SRed=\"0.85\" SGreen=\"0.85\" SBlue=\"0.85\" ");
823  f.Fprintf( "ri=\"%f\" rj=\"%f\" rk=\"%f\" si=\"%f\" sj=\"%f\" sk=\"%f\" ", RR.i, RR.j, RR.k, SS.i, SS.j, SS.k );
824  f.Fprintf( "radius=\"%f\" ", radius );
825  f.Fprintf( "x=\"%f\" y=\"%f\" z=\"%f\" ", center.i, center.j, center.k );
826  float loy = LengthOfYear( RR, SS );
827  float temprandom = .1*fmod( loy, 10 ); //use this so as not to alter state here
828  if (loy) {
829  f.Fprintf( "year= \"%f\" ", loy );
830  temprandom = grand();
831  loy = 864*temprandom;
832  if (loy)
833  f.Fprintf( "day=\"%f\" ", loy );
834  }
835  f.Fprintf( ">\n" );
836  xmllevel++;
837  if ( !cname.empty() ) {
838  int wrapx = 1;
839  int wrapy = 1;
840  cname = GetWrapXY( cname, wrapx, wrapy );
841  string::size_type t;
842  while ( ( t = cname.find( '*' ) ) != string::npos )
843  cname.replace( t, 1, texturenum == 0 ? "" : XMLSupport::tostring( texturenum ) );
844  Tab();
845  f.Fprintf( "<CityLights file=\"%s\" wrapx=\"%d\" wrapy=\"%d\"/>\n", cname.c_str(), wrapx, wrapy );
846  }
847  static float atmosphere_prob = XMLSupport::parse_float( vs_config->getVariable( "galaxy", "AtmosphereProbability", "0.5" ) );
848  if ( (entitytype == PLANET && temprandom < atmosphere_prob) && ( !atmosphere.empty() ) ) {
849  string NAME = thisname+" Atmosphere";
850  {
851  bool doalphaatmosphere = (temprandom< .08 || temprandom >.3);
852  if (doalphaatmosphere) {
853  float fograd = radius*1.007;
854  if (.007*radius > 2500.0)
855  fograd = radius+2500.0;
856  Tab();
857  f.Fprintf( "<Atmosphere file=\"%s\" alpha=\"SRCALPHA INVSRCALPHA\" radius=\"%f\"/>\n",
858  atmosphere.c_str(), fograd );
859  }
860  float r = .9, g = .9, b = 1, a = 1;
861  float dr = .9, dg = .9, db = 1, da = 1;
862  if (!doalphaatmosphere) {
863  if (temprandom > .26 || temprandom < .09) {
864  r = .5;
865  g = 1;
866  b = .5;
867  } else if (temprandom > .24 || temprandom < .092) {
868  r = 1;
869  g = .6;
870  b = .5;
871  }
872  }
873 
874 /*----------------------------------------------------------------------------------------*\
875 | **************************************************************************************** |
876 | ********************************* FIXME: USE BFXM ************************************* |
877 | **************************************************************************************** |
878 \*----------------------------------------------------------------------------------------*/
879 
880  Tab();
881  f.Fprintf( "<Fog>\n" );
882  xmllevel++;
883  Tab();
884  f.Fprintf(
885  "<FogElement file=\"atmXatm.bfxm\" ScaleAtmosphereHeight=\"1.0\" red=\"%f\" blue=\"%f\" green=\"%f\" alpha=\"%f\" dired=\"%f\" diblue=\"%f\" digreen=\"%f\" dialpha=\"%f\" concavity=\".3\" focus=\".6\" minalpha=\"0\" maxalpha=\"0.7\"/>\n",
886  r,
887  g,
888  b,
889  a,
890  dr,
891  dg,
892  db,
893  da );
894  Tab();
895  f.Fprintf(
896  "<FogElement file=\"atmXhalo.bfxm\" ScaleAtmosphereHeight=\"1.0\" red=\"%f\" blue=\"%f\" green=\"%f\" alpha=\"%f\" dired=\"%f\" diblue=\"%f\" digreen=\"%f\" dialpha=\"%f\" concavity=\"1\" focus=\".6\" minalpha=\"0\" maxalpha=\"0.7\"/>\n",
897  r,
898  g,
899  b,
900  a,
901  dr,
902  dg,
903  db,
904  da );
905  xmllevel--;
906  Tab();
907  f.Fprintf( "</Fog>\n" );
908  }
909  }
910 //FIRME: need scaling of radius based on planet type.
911  radii.push_back( radius );
912 
913  static float ringprob = XMLSupport::parse_float( vs_config->getVariable( "galaxy", "RingProbability", ".1" ) );
914  static float dualringprob = XMLSupport::parse_float( vs_config->getVariable( "galaxy", "DoubleRingProbability", ".025" ) );
915  if (entitytype == PLANET) {
916  float ringrand = grand();
917  if (ringrand < ringprob) {
918  string ringname = getRandName( rings );
919  static float innerRingRadMin = XMLSupport::parse_float( vs_config->getVariable( "galaxy", "InnerRingRadius", "1.5" ) );
920  static float outerRingRadMin = XMLSupport::parse_float( vs_config->getVariable( "galaxy", "OuterRingRadius", "2.5" ) );
921  double inner_rad = ( innerRingRadMin*(1+grand()*.5) )*radius;
922  double outer_rad = inner_rad+( outerRingRadMin*grand() )*radius;
923  int wrapx = 1;
924  int wrapy = 1;
925  if ( ringname.empty() ) {
926  static string defringname = vs_config->getVariable( "galaxy",
927  "DefaultRingTexture",
928  "planets/ring.pngwrapx36wrapy2" );
929  ringname = defringname;
930  }
931  ringname = GetWrapXY( ringname, wrapx, wrapy );
932  Vector r, s;
933  makeRS( r, s, 1, false );
934  float rmag = r.Mag();
935  if (rmag > .001) {
936  r.i /= rmag;
937  r.j /= rmag;
938  r.k /= rmag;
939  }
940  float smag = s.Mag();
941  if (smag > .001) {
942  s.i /= smag;
943  s.j /= smag;
944  s.k /= smag;
945  }
946  if ( ringrand < (1-dualringprob) ) {
947  Tab();
948  f.Fprintf(
949  "<Ring file=\"%s\" ri=\"%f\" rj=\"%f\" rk=\"%f\" si=\"%f\" sj=\"%f\" sk=\"%f\" innerradius=\"%f\" outerradius=\"%f\" wrapx=\"%d\" wrapy=\"%d\" />\n",
950  ringname.c_str(),
951  r.i,
952  r.j,
953  r.k,
954  s.i,
955  s.j,
956  s.k,
957  inner_rad,
958  outer_rad,
959  wrapx,
960  wrapy );
961  }
962  if ( ringrand < dualringprob || ringrand >= (ringprob-dualringprob) ) {
963  double movable = grand();
964  static float second_ring_move =
965  XMLSupport::parse_float( vs_config->getVariable( "galaxy", "SecondRingDifference", ".4" ) );
966  inner_rad = outer_rad*( 1+.1*(second_ring_move+second_ring_move*movable) );
967  outer_rad = inner_rad*(outerRingRadMin*movable);
968  Tab();
969  f.Fprintf(
970  "<Ring file=\"%s\" ri=\"%f\" rj=\"%f\" rk=\"%f\" si=\"%f\" sj=\"%f\" sk=\"%f\" innerradius=\"%f\" outerradius=\"%f\" wrapx=\"%d\" wrapy=\"%d\" />\n",
971  ringname.c_str(),
972  r.i,
973  r.j,
974  r.k,
975  s.i,
976  s.j,
977  s.k,
978  inner_rad,
979  outer_rad,
980  wrapx,
981  wrapy );
982  }
983  }
984  }
985  for (int i = 0; i < numberofstarbases; i++)
986  MakeSmallUnit();
987  static float moon_size_compared_to_planet =
988  XMLSupport::parse_float( vs_config->getVariable( "galaxy", "MoonRelativeToPlanet", ".4" ) );
989  static float moon_size_compared_to_moon =
990  XMLSupport::parse_float( vs_config->getVariable( "galaxy", "MoonRelativeToMoon", ".8" ) );
991  moonlevel++;
992  MakeMoons( entitytype != MOON ? moon_size_compared_to_planet*radius : moon_size_compared_to_moon*radius, entitytype );
993  MakeJumps( 100+grand()*300, entitytype, numberofjumps );
994  moonlevel--;
995  radii.pop_back();
996  xmllevel--;
997  Tab();
998  f.Fprintf( "</Planet>\n" );
999 
1000  //writes out some pretty planet tags
1001 }
1002 
1003 void MakeJumps( float callingradius, int callingentitytype, int numberofjumps )
1004 {
1005  for (int i = 0; i < numberofjumps; i++)
1006  MakeJump( ( .5+.5*grand() )*callingradius );
1007 }
1008 void MakeMoons( float callingradius, int callingentitytype )
1009 {
1010  while (planetoffset < stars[staroffset].planets.size() && stars[staroffset].planets[planetoffset].moonlevel == moonlevel) {
1011  PlanetInfo &infos = stars[staroffset].planets[planetoffset++];
1012  MakePlanet(
1013  ( .5+.5*grand() )*callingradius, callingentitytype == STAR ? PLANET : MOON,
1014  infos.name, infos.unitname, infos.technique,
1015  infos.num, infos.numjumps,
1016  infos.numstarbases );
1017  }
1018 }
1020 {
1021  float radius = starradius[staroffset];
1022  Vector r, s;
1023  unsigned int i;
1024  Vector center = generateAndUpdateRS( r, s, radius, false ); //WTF why was this commented out--that means all stars start on top of each other
1025  planetoffset = 0;
1026 
1027  char b[3] = " A";
1028  b[1] += staroffset;
1029  Tab();
1030  f.Fprintf( "<Planet name=\"%s%s\" file=\"%s\" ", systemname.c_str(), b, starentities[staroffset].c_str() );
1031  f.Fprintf( "ri=\"%f\" rj=\"%f\" rk=\"%f\" si=\"%f\" sj=\"%f\" sk=\"%f\" ", r.i, r.j, r.k, s.i, s.j, s.k );
1032  if (staroffset != 0)
1033  f.Fprintf( "radius=\"%f\" x=\"%f\" y=\"%f\" z=\"%f\" ", radius, center.i, center.j, center.k );
1034  else
1035  f.Fprintf( "radius=\"%f\" x=\"0\" y=\"0\" z=\"0\" ", radius );
1036  float loy = LengthOfYear( r, s );
1037  if (loy) {
1038  f.Fprintf( "year= \"%f\" ", loy );
1039  loy *= grand();
1040  if (loy)
1041  f.Fprintf( "day=\"%f\" ", loy );
1042  }
1043  f.Fprintf( " Red=\"%f\" Green=\"%f\" Blue=\"%f\" ReflectNoLight=\"true\" light=\"%d\">\n", lights[staroffset].r,
1045  f.Fprintf(
1046  "<fog>\n\t<FogElement file=\"atmXatm.bfxm\" ScaleAtmosphereHeight=\".900\" red=\"%f\" blue=\"%f\" green=\"%f\" alpha=\"1.0\" dired=\"%f\" diblue=\"%f\" digreen=\"%f\" dialpha=\"1\" concavity=\".3\" focus=\".6\" minalpha=\".7\" maxalpha=\"1\"/>\n\t<FogElement file=\"atmXhalo.bfxm\" ScaleAtmosphereHeight=\".9000\" red=\"%f\" blue=\"%f\" green=\"%f\" alpha=\"1.0\" dired=\"%f\" diblue=\"%f\" digreen=\"%f\" dialpha=\"1\" concavity=\".3\" focus=\".6\" minalpha=\".7\" maxalpha=\"1\"/>\n</fog>\n",
1047  lights[staroffset].r,
1048  lights[staroffset].g,
1049  lights[staroffset].b,
1050  lights[staroffset].r,
1051  lights[staroffset].g,
1052  lights[staroffset].b,
1053  lights[staroffset].r,
1054  lights[staroffset].g,
1055  lights[staroffset].b,
1056  lights[staroffset].r,
1057  lights[staroffset].g,
1058  lights[staroffset].b );
1059  radii.push_back( 1.5*radius );
1060  static float planet_size_compared_to_sun =
1061  XMLSupport::parse_float( vs_config->getVariable( "galaxy", "RockyRelativeToPrimary", ".05" ) );
1062  xmllevel++;
1063  unsigned int numu;
1064  if (numstarentities) {
1065  numu = numnaturalphenomena
1068  } else {
1069  numu = 1;
1070  }
1071  if ( (int) staroffset == (int) (numstarentities-staroffset)-1 )
1072  numu = numnaturalphenomena;
1073  for (i = 0; i < numu; ++i)
1074  MakeBigUnit( STAR );
1075  for (i = 0; i < stars[staroffset].numstarbases; ++i)
1076  MakeSmallUnit();
1077  MakeJumps( 100+grand()*300, STAR, stars[staroffset].numjumps );
1078  MakeMoons( planet_size_compared_to_sun*radius, STAR );
1079  //Fixme: no jumps should be made around the star.
1080  if ( !jumps.empty() )
1081  VSFileSystem::vs_fprintf( stderr, "ERROR: jumps not empty() Size==%u!!!!!\n", jumps.size() );
1082  staroffset++;
1083 }
1084 
1085 void endStar()
1086 {
1087  radii.pop_back();
1088  xmllevel--;
1089  Tab();
1090  f.Fprintf( "</Planet>\n" );
1091 }
1093 {
1094  beginStar();
1095  endStar();
1096 }
1098 {
1099  beginStar();
1100  while (staroffset < numstarentities) {
1101  if (grand() > .5) {
1102  CreateFirstStar();
1103  break;
1104  } else {
1105  CreateStar();
1106  }
1107  }
1108  endStar();
1109 }
1110 
1112 {
1113  unsigned int i;
1114  for (i = 0; i < numstarentities || i == 0; i++)
1115  CreateLight( i );
1116  CreateFirstStar();
1117 }
1118 
1120 {
1121  assert( !starradius.empty() );
1122  assert( starradius[0] );
1123  xmllevel = 0;
1124  Tab();
1125  f.Fprintf( "<?xml version=\"1.0\" ?>\n<system name=\"%s\" background=\"%s\">\n", systemname.c_str(),
1126  getRandName( background ).c_str() );
1127  xmllevel++;
1128  CreatePrimaries();
1129  xmllevel--;
1130  Tab();
1131  f.Fprintf( "</system>\n" );
1132 }
1133 
1134 void readentity( vector< string > &entity, const char *filename )
1135 {
1136  VSFile f;
1137  VSError err = f.OpenReadOnly( filename, UniverseFile );
1138  if (err > Ok)
1139  return;
1141  char input_buffer[1000];
1142  while ( 1 == f.Fscanf( "%s", input_buffer ) )
1143  entity.push_back( input_buffer );
1144  f.Close();
1145 }
1146 
1147 const char * noslash( const char *in )
1148 {
1149  const char *tmp = in;
1150  while (*tmp != '\0' && *tmp != '/')
1151  tmp++;
1152  if (*tmp != '\0')
1153  tmp++;
1154  else
1155  return in;
1156  const char *tmp2 = tmp;
1157  tmp2 = noslash( tmp2 );
1158  if (tmp2[0] != '\0')
1159  return tmp2;
1160  else
1161  return tmp;
1162 }
1163 }
1164 using namespace StarSystemGent;
1165 string getStarSystemFileName( const string &input )
1166 {
1167  return input+string( ".system" );
1168 }
1169 string getStarSystemName( const string &in )
1170 {
1171  return string( noslash( in.c_str() ) );
1172 }
1173 string getStarSystemSector( const string &in )
1174 {
1175  string::size_type sep = in.find( '/' );
1176  if (sep == string::npos)
1177  return string( "." );
1178 
1179  else
1180  return in.substr( 0, sep );
1181 }
1182 void readnames( vector< string > &entity, const char *filename )
1183 {
1184  VSFile f;
1185  VSError err = f.OpenReadOnly( filename, UniverseFile );
1186  if (err > Ok)
1187  return;
1189  char input_buffer[1000];
1190  while ( !f.Eof() ) {
1191  f.ReadLine( input_buffer, 999 );
1192  if (input_buffer[0] == '\0' || input_buffer[0] == '\n' || input_buffer[0] == '\r')
1193  continue;
1194  for (unsigned int i = 0; input_buffer[i] != '\0' && i < 999; i++) {
1195  if (input_buffer[i] == '\r')
1196  input_buffer[i] = '\0';
1197  if (input_buffer[i] == '\n') {
1198  input_buffer[i] = '\0';
1199  break;
1200  }
1201  }
1202  entity.push_back( input_buffer );
1203  }
1204  f.Close();
1205 }
1206 
1207 void readplanetentity( vector< StarInfo > &starinfos, string planetlist, unsigned int numstars )
1208 {
1209  if (numstars < 1) {
1210  numstars = 1;
1211  vs_fprintf( stderr, "No stars exist in this system!\n" );
1212  }
1213  string::size_type i, j;
1214  unsigned int u;
1215  starinfos.reserve( numstars );
1216  for (u = 0; u < numstars; ++u)
1217  starinfos.push_back( StarInfo() );
1218  u--;
1219  while (i = planetlist.find( ' ' ), 1) {
1220  if (i == 0) {
1221  planetlist = planetlist.substr( 1 );
1222  continue;
1223  }
1224  int nummoon = 0;
1225  for (j = 0; j < i && j < planetlist.size() && planetlist[j] == '*'; ++j)
1226  nummoon++;
1227  if (nummoon == 0)
1228  u++;
1229  if ( j == string::npos || j >= planetlist.size() ) break;
1230  starinfos[u%numstars].planets.push_back( PlanetInfo() );
1231  starinfos[u%numstars].planets.back().moonlevel = nummoon;
1232  {
1233  GalaxyXML::Galaxy *galaxy = _Universe->getGalaxy();
1234 
1235  static const string numtag("#num#");
1236  static const string empty;
1237  static const string::size_type numlen = numtag.length();
1238  string::size_type numpos;
1239 
1240  // Get planet name and texture
1241  string planetname = galaxy->getPlanetNameFromInitial( planetlist.substr( j, i == string::npos ? string::npos : i-j ) );
1242  string texturename = galaxy->getPlanetVariable( planetname, "texture", "No texture supplied in <planets>!" );
1243 
1244  // Get unit name, deriving a default name from its texture
1245  string defunitname = texturename.substr(0, texturename.find_first_of('|'));
1246  if (defunitname.find_last_of('/') != string::npos)
1247  defunitname = defunitname.substr(defunitname.find_last_of('/')+1);
1248  defunitname = defunitname.substr(0, defunitname.find_last_of('.'));
1249 
1250  numpos=0;
1251  while ((numpos = defunitname.find(numtag, numpos)) != string::npos)
1252  defunitname.replace(numpos, numlen, empty);
1253 
1254  string unitname = galaxy->getPlanetVariable( planetname, "unit", defunitname );
1255 
1256  // Get planet rendering technique
1257  string techniquename=galaxy->getPlanetVariable( planetname, "technique", "" );
1258 
1259  // Replace randomized number placeholder tags
1260  starinfos[u%numstars].planets.back().num =
1261  rnd( XMLSupport::parse_int( galaxy->getPlanetVariable( planetname, "texture_min", "0" ) ),
1262  XMLSupport::parse_int( galaxy->getPlanetVariable( planetname, "texture_max", "0" ) ) );
1263 
1264  char num[32];
1265  if (starinfos[u%numstars].planets.back().num == 0)
1266  num[0] = 0;
1267  else
1268  snprintf(num, sizeof(num), "%d", starinfos[u%numstars].planets.back().num);
1269 
1270  numpos=0;
1271  while ((numpos = texturename.find(numtag, numpos)) != string::npos)
1272  texturename.replace(numpos, numlen, num);
1273 
1274  // Store info
1275  starinfos[u%numstars].planets.back().name = texturename;
1276  starinfos[u%numstars].planets.back().unitname = unitname;
1277  starinfos[u%numstars].planets.back().technique = techniquename;
1278  }
1279  starinfos[u%numstars].planets.back().numstarbases = 0;
1280  starinfos[u%numstars].planets.back().numjumps = 0;
1281  if (i == string::npos) break;
1282  planetlist = planetlist.substr( i+1 );
1283  }
1284  unsigned int k;
1285  if ( starinfos.size() ) {
1286  bool size = 0;
1287  for (k = 0; k < starinfos.size(); ++k)
1288  if ( starinfos[k].planets.size() ) {
1289  size = true;
1290  break;
1291  }
1292  if (!size) {
1293  int oldjumps = jumps.size();
1294  int oldstarbases = numstarbases;
1295  int newstuff;
1296  for (k = starinfos.size(); k > 0; --k) {
1297  newstuff = oldjumps/k;
1298  starinfos[k-1].numjumps = newstuff;
1299  oldjumps -= newstuff;
1300  newstuff = oldstarbases/k;
1301  starinfos[k-1].numstarbases = newstuff;
1302  oldstarbases -= newstuff;
1303  }
1304  } else {
1305  for (k = 0; k < jumps.size(); ++k) {
1306  vector< PlanetInfo > *temp; //& doesn't like me so I use *.
1307  do
1308  temp = &starinfos[rnd( 0, starinfos.size() )].planets;
1309  while ( !temp->size() );
1310  (*temp)[rnd( 0, temp->size() )].numjumps++;
1311  }
1312  for (k = 0; k < numstarbases; ++k) {
1313  vector< PlanetInfo > *temp; //& appears to still have dislike for me.
1314  do
1315  temp = &starinfos[rnd( 0, starinfos.size() )].planets;
1316  while ( !temp->size() );
1317  (*temp)[rnd( 0, temp->size() )].numstarbases++;
1318  }
1319  }
1320  }
1321 }
1322 
1323 static int pushDown( int val )
1324 {
1325  while ( grand() > (1/val) )
1326  val--;
1327  return val;
1328 }
1329 static int pushDownTowardsMean( int mean, int val )
1330 {
1331  int delta = mean-1;
1332  return delta+pushDown( val-delta );
1333 }
1334 static int pushTowardsMean( int mean, int val )
1335 {
1336  static bool dopushingtomean = XMLSupport::parse_bool( vs_config->getVariable( "galaxy", "PushValuesToMean", "true" ) );
1337  if (!dopushingtomean)
1338  return val;
1339  if (val < mean)
1340  return -pushDownTowardsMean( -mean, -val );
1341  return pushDownTowardsMean( mean, val );
1342 }
1343 
1345 {
1347  static float radiusscale = XMLSupport::parse_float( vs_config->getVariable( "galaxy", "StarRadiusScale", "1000" ) );
1348  si.sunradius *= radiusscale;
1349  systemname = si.name;
1350  static float compactness_scale = XMLSupport::parse_float( vs_config->getVariable( "galaxy", "CompactnessScale", "1.5" ) );
1351  static float jump_compactness_scale =
1352  XMLSupport::parse_float( vs_config->getVariable( "galaxy", "JumpCompactnessScale", "1.5" ) );
1353  static int meannaturalphenomena = XMLSupport::parse_int( vs_config->getVariable( "galaxy", "MeanNaturalPhenomena", "1" ) );
1354  static int meanbases = XMLSupport::parse_int( vs_config->getVariable( "galaxy", "MeanStarBases", "2" ) );
1355  compactness = si.compactness*compactness_scale;
1356  jumpcompactness = si.compactness*jump_compactness_scale;
1357  if (si.seed)
1358  seedrand( si.seed );
1359  else
1360  seedrand( stringhash( si.sector+'/'+si.name ) );
1361  VSFileSystem::vs_fprintf( stderr, "star %d, natural %d, bases %d", si.numstars, si.numun1, si.numun2 );
1362  int nat = pushTowardsMean( meannaturalphenomena, si.numun1 );
1363  numnaturalphenomena = nat > si.numun1 ? si.numun1 : nat;
1364  numstarbases = pushTowardsMean( meanbases, si.numun2 );
1365  static float smallUnitsMultiplier = XMLSupport::parse_float( vs_config->getVariable( "galaxy", "SmallUnitsMultiplier", "0" ) );
1366  numstarbases = (int) (si.numun2*smallUnitsMultiplier);
1368  VSFileSystem::vs_fprintf( stderr, "star %d, natural %d, bases %d", numstarentities, numnaturalphenomena, numstarbases );
1369  starradius.push_back( si.sunradius );
1370  readColorGrads( gradtex, (si.stars).c_str() );
1371 
1372  readentity( starbases, (si.smallun).c_str() );
1373  readentity( background, (si.backgrounds).c_str() );
1374  if ( background.empty() )
1375  background.push_back( si.backgrounds );
1376  if (si.nebulae)
1377  readentity( naturalphenomena, (si.nebulaelist).c_str() );
1378  if (si.asteroids)
1379  readentity( naturalphenomena, (si.asteroidslist).c_str() );
1380  for (unsigned int i = 0; i < si.jumps.size(); i++)
1381  jumps.push_back( si.jumps[i] );
1382  faction = si.faction;
1383 
1385 
1386  readentity( rings, (si.ringlist).c_str() );
1387  readnames( names, (si.names).c_str() );
1388 
1390 
1391  VSError err = f.OpenCreateWrite( si.filename, SystemFile );
1392  if (err <= Ok) {
1393  CreateStarSystem();
1394  f.Close();
1395  }
1396  ResetGlobalVariables(); //deallocate any unused memory in vectors.
1397 }
1398 #ifdef CONSOLE_APP
1399 int main( int argc, char **argv )
1400 {
1401  if (argc < 9) {
1403  stderr,
1404  "Usage: starsysgen <seed> <sector>/<system> <sunradius>/<compactness> <numstars> [N][A]<numnaturalphenomena> <numstarbases> <faction> <namelist> [OtherSystemJumpNodes]...\n" );
1405  return 1;
1406  }
1407  int seed;
1408  if ( 1 != sscanf( argv[1], "%d", &seed ) )
1409  return 1;
1410  string sectorname( getStarSystemSector( argv[2] ) );
1411  string filen( getStarSystemFileName( argv[2] ) );
1412  string systemname = string( getStarSystemName( argv[2] ) );
1413  int numbigthings;
1414  bool nebula = true;
1415  bool asteroid = true;
1416  float srad;
1417  float comp;
1418  sscanf( argv[3], "%f/%f", &srad&comp );
1419  vector< string >jumps;
1420  for (unsigned int i = 12; i < argc; i++)
1421  jumps.push_back( string( argv[i] ) );
1422  if ( 1 == sscanf( argv[8], "AN%d", &numbigthings ) || 1 == sscanf( argv[8], "NA%d", &numun[0] ) )
1423  nebula = asteroid = true;
1424  else if ( 1 == sscanf( argv[8], "A%d", &numbigthings ) )
1425  asteroid = true;
1426  else if ( 1 == sscanf( argv[8], "N%d", &numbigthings ) )
1427  nebula = true;
1428  else if ( 1 == sscanf( argv[8], "%d", &numbigthings ) )
1429  nebula = asteroid = true;
1430  else
1431  return -1;
1432  generateStarSystem( "./",
1433  seed,
1434  sectorname,
1435  systemname,
1436  filen,
1437  srad, comp;
1438  strtol( argv[4], NULL, 10 ),
1439  strtol( argv[5], NULL, 10 ),
1440  strtol( argv[6], NULL, 10 ),
1441  strtol( argv[7], NULL, 10 ),
1442  nebula,
1443  asteroid,
1444  numbigthings,
1445  strtol( argv[9], NULL, 10 ),
1446  argv[10],
1447  argv[11],
1448  jumps );
1449 
1450  return 0;
1451 }
1452 #endif
1453