2 * See Licensing and Copyright notice in naev.h
8 * @brief Handles all the space stuff, namely systems and planets.
39 #define XML_PLANET_ID "Planets" /**< Planet xml document tag. */
40 #define XML_PLANET_TAG "planet" /**< Individual planet xml tag. */
42 #define XML_SYSTEM_ID "Systems" /**< Systems xml document tag. */
43 #define XML_SYSTEM_TAG "ssys" /**< Individual systems xml tag. */
45 #define PLANET_DATA "dat/planet.xml" /**< XML file containing planets. */
46 #define SYSTEM_DATA "dat/ssys.xml" /**< XML file containing systems. */
48 #define PLANET_GFX_SPACE "gfx/planet/space/" /**< Location of planet space graphics. */
49 #define PLANET_GFX_EXTERIOR "gfx/planet/exterior/" /**< Location of planet exterior graphics (when landed). */
51 #define PLANET_GFX_EXTERIOR_W 400 /**< Planet exterior graphic width. */
52 #define PLANET_GFX_EXTERIOR_H 400 /**< Planet exterior graphic height. */
54 #define CHUNK_SIZE 32 /**< Size to allocate by. */
55 #define CHUNK_SIZE_SMALL 8 /**< Smaller size to allocate chunks by. */
57 /* used to overcome warnings due to 0 values */
58 #define FLAG_XSET (1<<0) /**< Set the X position value. */
59 #define FLAG_YSET (1<<1) /**< Set the Y position value. */
60 #define FLAG_ASTEROIDSSET (1<<2) /**< Set the asteroid value. */
61 #define FLAG_INTERFERENCESET (1<<3) /**< Set the interference value. */
62 #define FLAG_SERVICESSET (1<<4) /**< Set the service value. */
63 #define FLAG_TECHSET (1<<5) /**< Set the tech value. */
64 #define FLAG_FACTIONSET (1<<6) /**< Set the faction value. */
68 * planet <-> system name stack
70 static char** planetname_stack
= NULL
; /**< Planet name stack corresponding to system. */
71 static char** systemname_stack
= NULL
; /**< System name stack corresponding to planet. */
72 static int spacename_nstack
= 0; /**< Size of planet<->system stack. */
73 static int spacename_mstack
= 0; /**< Size of memory in planet<->system stack. */
79 StarSystem
*systems_stack
= NULL
; /**< Star system stack. */
80 int systems_nstack
= 0; /**< Number of star systems. */
81 static int systems_mstack
= 0; /**< Number of memory allocated for star system stack. */
86 static Planet
*planet_stack
= NULL
; /**< Planet stack. */
87 static int planet_nstack
= 0; /**< Planet stack size. */
88 static int planet_mstack
= 0; /**< Memory size of planet stack. */
93 static int systems_loading
= 1; /**< Systems are loading. */
94 StarSystem
*cur_system
= NULL
; /**< Current star system. */
100 int space_spawn
= 1; /**< Spawn enabled by default. */
101 static double spawn_timer
= 0; /**< Timer that controls spawn rate. */
102 extern int pilot_nstack
;
106 * star stack and friends
108 #define STAR_BUF 100 /**< Area to leave around screen for stars, more = less repitition */
112 * @brief Represents a background star. */
113 static gl_vbo
*star_vertexVBO
= NULL
; /**< Star Vertex VBO. */
114 static gl_vbo
*star_colourVBO
= NULL
; /**< Star Colour VBO. */
115 static GLfloat
*star_vertex
= NULL
; /**< Vertex of the stars. */
116 static GLfloat
*star_colour
= NULL
; /**< Brightness of the stars. */
117 static unsigned int nstars
= 0; /**< total stars */
118 static unsigned int mstars
= 0; /**< memory stars are taking */
124 extern double interference_alpha
; /* gui.c */
125 static double interference_target
= 0.; /**< Target alpha level. */
126 static double interference_timer
= 0.; /**< Interference timer. */
130 * Internal Prototypes.
133 static int planet_parse( Planet
* planet
, const xmlNodePtr parent
);
135 static int systems_load (void);
136 static StarSystem
* system_parse( StarSystem
*system
, const xmlNodePtr parent
);
137 static void system_parseJumps( const xmlNodePtr parent
);
139 static int system_calcSecurity( StarSystem
*sys
);
140 static void system_setFaction( StarSystem
*sys
);
141 static void space_addFleet( Fleet
* fleet
, int init
);
142 static PlanetClass
planetclass_get( const char a
);
144 * Externed prototypes.
146 int space_sysSave( xmlTextWriterPtr writer
);
147 int space_sysLoad( xmlNodePtr parent
);
151 * @brief Basically returns a PlanetClass integer from a char
153 * @param a Char to get class from.
154 * @return Identifier matching the char.
156 static PlanetClass
planetclass_get( const char a
)
159 /* planets use letters */
160 case 'A': return PLANET_CLASS_A
;
161 case 'B': return PLANET_CLASS_B
;
162 case 'C': return PLANET_CLASS_C
;
163 case 'D': return PLANET_CLASS_D
;
164 case 'E': return PLANET_CLASS_E
;
165 case 'F': return PLANET_CLASS_F
;
166 case 'G': return PLANET_CLASS_G
;
167 case 'H': return PLANET_CLASS_H
;
168 case 'I': return PLANET_CLASS_I
;
169 case 'J': return PLANET_CLASS_J
;
170 case 'K': return PLANET_CLASS_K
;
171 case 'L': return PLANET_CLASS_L
;
172 case 'M': return PLANET_CLASS_M
;
173 case 'N': return PLANET_CLASS_N
;
174 case 'O': return PLANET_CLASS_O
;
175 case 'P': return PLANET_CLASS_P
;
176 case 'Q': return PLANET_CLASS_Q
;
177 case 'R': return PLANET_CLASS_R
;
178 case 'S': return PLANET_CLASS_S
;
179 case 'T': return PLANET_CLASS_T
;
180 case 'X': return PLANET_CLASS_X
;
181 case 'Y': return PLANET_CLASS_Y
;
182 case 'Z': return PLANET_CLASS_Z
;
183 /* stations use numbers - not as many types */
184 case '0': return STATION_CLASS_A
;
185 case '1': return STATION_CLASS_B
;
186 case '2': return STATION_CLASS_C
;
187 case '3': return STATION_CLASS_D
;
190 WARN("Invalid planet class.");
191 return PLANET_CLASS_NULL
;
195 * @brief Gets the char representing the planet class from the planet.
197 * @param p Planet to get the class char from.
198 * @return The planet's class char.
200 char planet_getClass( Planet
*p
)
203 case PLANET_CLASS_A
: return 'A';
204 case PLANET_CLASS_B
: return 'B';
205 case PLANET_CLASS_C
: return 'C';
206 case PLANET_CLASS_D
: return 'D';
207 case PLANET_CLASS_E
: return 'E';
208 case PLANET_CLASS_F
: return 'F';
209 case PLANET_CLASS_G
: return 'G';
210 case PLANET_CLASS_H
: return 'H';
211 case PLANET_CLASS_I
: return 'I';
212 case PLANET_CLASS_J
: return 'J';
213 case PLANET_CLASS_K
: return 'K';
214 case PLANET_CLASS_L
: return 'L';
215 case PLANET_CLASS_M
: return 'M';
216 case PLANET_CLASS_N
: return 'N';
217 case PLANET_CLASS_O
: return 'O';
218 case PLANET_CLASS_P
: return 'P';
219 case PLANET_CLASS_Q
: return 'Q';
220 case PLANET_CLASS_R
: return 'R';
221 case PLANET_CLASS_S
: return 'S';
222 case PLANET_CLASS_T
: return 'T';
223 case PLANET_CLASS_X
: return 'X';
224 case PLANET_CLASS_Y
: return 'Y';
225 case PLANET_CLASS_Z
: return 'Z';
227 case STATION_CLASS_A
: return '0';
228 case STATION_CLASS_B
: return '1';
229 case STATION_CLASS_C
: return '2';
230 case STATION_CLASS_D
: return '3';
233 WARN("Invalid planet class.");
240 * @brief Checks to make sure if pilot is far enough away to hyperspace.
242 * @param p Pilot to check if he can hyperspace.
243 * @return 1 if he can hyperspace, 0 else.
245 int space_canHyperspace( Pilot
* p
)
249 if (p
->fuel
< HYPERSPACE_FUEL
) return 0;
251 for (i
=0; i
< cur_system
->nplanets
; i
++) {
252 d
= vect_dist(&p
->solid
->pos
, &cur_system
->planets
[i
]->pos
);
253 if (d
< HYPERSPACE_EXIT_MIN
)
261 * @brief Tries to get the pilot into hyperspace.
263 * @param p Pilot to try to start hyperspacing.
264 * @return 0 on success.
266 int space_hyperspace( Pilot
* p
)
268 if (p
->fuel
< HYPERSPACE_FUEL
)
270 if (!space_canHyperspace(p
))
273 /* pilot is now going to get automatically ready for hyperspace */
274 pilot_setFlag(p
, PILOT_HYP_PREP
);
281 * @brief Gets the name of all the planets that belong to factions.
283 * @param[out] nplanets Number of planets found.
284 * @param factions Factions to check against.
285 * @param nfactions Number of factions in factions.
286 * @return An array of faction names. Individual names are not allocated.
288 char** space_getFactionPlanet( int *nplanets
, int *factions
, int nfactions
)
298 tmp
= malloc(sizeof(char*) * mtmp
);
300 for (i
=0; i
<systems_nstack
; i
++)
301 for (j
=0; j
<systems_stack
[i
].nplanets
; j
++) {
302 planet
= systems_stack
[i
].planets
[j
];
303 for (k
=0; k
<nfactions
; k
++)
304 if (planet
->faction
== factions
[k
]) {
306 if (ntmp
> mtmp
) { /* need more space */
308 tmp
= realloc(tmp
, sizeof(char*) * mtmp
);
310 tmp
[ntmp
-1] = planet
->name
;
311 break; /* no need to check all factions */
321 * @brief Gets the name of a random planet.
323 * @return The name of a random planet.
325 char* space_getRndPlanet (void)
335 tmp
= malloc(sizeof(char*) * mtmp
);
337 for (i
=0; i
<systems_nstack
; i
++)
338 for (j
=0; j
<systems_stack
[i
].nplanets
; j
++) {
340 if (ntmp
> mtmp
) { /* need more space */
342 tmp
= realloc(tmp
, sizeof(char*) * mtmp
);
344 tmp
[ntmp
-1] = systems_stack
[i
].planets
[j
]->name
;
347 res
= tmp
[RNG(0,ntmp
-1)];
355 * @brief Sees if a system is reachable.
357 * @return 1 if target system is reachable, 0 if it isn't.
359 int space_sysReachable( StarSystem
*sys
)
363 if (sys_isKnown(sys
)) return 1; /* it is known */
365 /* check to see if it is adjacent to known */
366 for (i
=0; i
<sys
->njumps
; i
++)
367 if (sys_isKnown(system_getIndex( sys
->jumps
[i
] )))
375 * @brief Get the system from it's name.
377 * @param sysname Name to match.
378 * @return System matching sysname.
380 StarSystem
* system_get( const char* sysname
)
384 for (i
=0; i
<systems_nstack
; i
++)
385 if (strcmp(sysname
, systems_stack
[i
].name
)==0)
386 return &systems_stack
[i
];
388 DEBUG("System '%s' not found in stack", sysname
);
394 * @brief Get the system by it's index.
396 * @param id Index to match.
397 * @return System matching index.
399 StarSystem
* system_getIndex( int id
)
401 return &systems_stack
[ id
];
406 * @brief Get the name of a system from a planetname.
408 * @param planetname Planet name to match.
409 * @return Name of the system planet belongs to.
411 char* planet_getSystem( const char* planetname
)
415 for (i
=0; i
<spacename_nstack
; i
++)
416 if (strcmp(planetname_stack
[i
],planetname
)==0)
417 return systemname_stack
[i
];
419 DEBUG("Planet '%s' not found in planetname stack", planetname
);
425 * @brief Gets a planet based on it's name.
427 * @param planetname Name to match.
428 * @return Planet matching planetname.
430 Planet
* planet_get( const char* planetname
)
434 if (planetname
==NULL
) {
435 WARN("Trying to find NULL planet...");
439 for (i
=0; i
<planet_nstack
; i
++)
440 if (strcmp(planet_stack
[i
].name
,planetname
)==0)
441 return &planet_stack
[i
];
443 WARN("Planet '%s' not found in the universe", planetname
);
449 * @brief Controls fleet spawning.
451 * @param dt Current delta tick.
453 void space_update( const double dt
)
459 /* Needs a current system. */
460 if (cur_system
== NULL
)
470 /* Only check if there are fleets and pilots. */
471 if ((cur_system
->nfleets
== 0) || (cur_system
->avg_pilot
== 0.))
474 if (spawn_timer
< 0.) { /* time to possibly spawn */
476 /* spawn chance is based on overall % */
477 f
= RNG(0,100*cur_system
->nfleets
);
479 for (i
=0; i
< cur_system
->nfleets
; i
++) {
480 j
+= cur_system
->fleets
[i
].chance
;
481 if (f
< j
) { /* add one fleet */
482 space_addFleet( cur_system
->fleets
[i
].fleet
, 0 );
487 /* Target is actually half of average pilots. */
488 target
= cur_system
->avg_pilot
/2.;
491 spawn_timer
= 45./target
;
493 /* Calculate ship modifier, it tries to stabilize at avg pilots. */
494 /* First get pilot facton ==> [-1., inf ] */
495 mod
= (double)pilot_nstack
- target
;
497 /* Scale and offset. */
498 /*mod = 2.*mod + 1.5;*/
499 mod
= MIN( mod
, -0.5 );
501 spawn_timer
*= 1. + mod
;
509 if (cur_system
->nebu_volatility
> 0.) {
510 /* Player takes damage. */
512 pilot_hit( player
, NULL
, 0, DAMAGE_TYPE_RADIATION
,
513 pow2(cur_system
->nebu_volatility
) / 500. * dt
);
520 if (cur_system
->interference
> 0.) {
522 if (cur_system
->interference
>= 1000.)
523 interference_alpha
= 1.;
525 /* Normal scenario. */
527 interference_timer
-= dt
;
528 if (interference_timer
< 0.) {
530 * 250 -> [ 0.75, 3.75 ]
531 * 500 -> [ 0.5, 2.5 ]
532 * 750 -> [ 0.25, 1.25 ]
533 * 1000 -> [ 0, 0 ] */
534 interference_timer
+= (1000. - cur_system
->interference
) / 1000. *
535 (3. + RNG_2SIGMA() );
538 * 250 -> [-0.5, 1.5 ]
540 * 1000 -> [ 0, 6 ] */
541 interference_target
= cur_system
->interference
/1000. * 2. *
542 (1. + RNG_2SIGMA() );
545 /* Head towards target. */
546 if (fabs(interference_alpha
- interference_target
) > 1e-05) {
548 interference_alpha
+= (interference_target
- interference_alpha
) * dt
;
550 /* Limit alpha to [0.-1.]. */
551 if (interference_alpha
> 1.)
552 interference_alpha
= 1.;
553 else if (interference_alpha
< 0.)
554 interference_alpha
= 0.;
562 * @brief Creates a fleet.
564 * @param fleet Fleet to add to the system.
565 * @param init Is being run during the space initialization.
567 static void space_addFleet( Fleet
* fleet
, int init
)
576 /* Needed to determine angle. */
579 /* c will determino how to create the fleet, only non-zero if it's run in init. */
581 if (RNGF() < 0.5) /* 50% chance of starting out en route. */
583 else if (RNGF() < 0.5) /* 25% of starting out landed. */
585 else /* 25% chance starting out entering hyperspace. */
590 /* simulate they came from hyperspace */
592 d
= RNGF()*(HYPERSPACE_ENTER_MAX
-HYPERSPACE_ENTER_MIN
) + HYPERSPACE_ENTER_MIN
;
593 vect_pset( &vp
, d
, RNGF()*2.*M_PI
);
595 /* Starting out landed or heading towards landing.. */
596 else if ((c
==1) || (c
==2)) {
597 /* Get friendly planet to land on. */
599 for (i
=0; i
<cur_system
->nplanets
; i
++)
600 if (planet_hasService(cur_system
->planets
[i
],PLANET_SERVICE_INHABITED
) &&
601 !areEnemies(fleet
->faction
,cur_system
->planets
[i
]->faction
)) {
602 planet
= cur_system
->planets
[i
];
606 /* No suitable planet found. */
607 if (planet
== NULL
) {
608 d
= RNGF()*(HYPERSPACE_ENTER_MAX
-HYPERSPACE_ENTER_MIN
) + HYPERSPACE_ENTER_MIN
;
609 vect_pset( &vp
, d
, RNGF()*2.*M_PI
);
613 /* Start out landed. */
615 vectcpy( &vp
, &planet
->pos
);
616 /* Start out near landed. */
618 d
= RNGF()*(HYPERSPACE_ENTER_MAX
-HYPERSPACE_ENTER_MIN
) + HYPERSPACE_ENTER_MIN
;
619 vect_pset( &vp
, d
, RNGF()*2.*M_PI
);
624 for (i
=0; i
< fleet
->npilots
; i
++) {
625 plt
= &fleet
->pilots
[i
];
626 if (RNG(0,100) <= plt
->chance
) {
627 /* other ships in the fleet should start split up */
628 vect_cadd(&vp
, RNG(75,150) * (RNG(0,1) ? 1 : -1),
629 RNG(75,150) * (RNG(0,1) ? 1 : -1));
630 a
= vect_angle(&vp
, &vn
);
635 /* Entering via hyperspace. */
637 vect_pset( &vv
, HYPERSPACE_VEL
, a
);
638 flags
|= PILOT_HYP_END
;
640 /* Starting out landed. */
643 /* Starting out almost landed. */
645 /* Put speed at half in case they start very near. */
646 vect_pset( &vv
, plt
->ship
->speed
* 0.5, a
);
648 /* Create the pilot. */
649 fleet_createPilot( fleet
, plt
, a
, &vp
, &vv
, NULL
, flags
);
656 * @brief Initilaizes background stars.
658 * @param n Number of stars to add (stars per 800x640 screen).
660 void space_initStars( int n
)
663 GLfloat w
, h
, hw
, hh
;
666 /* Calculate size. */
667 size
= SCREEN_W
*SCREEN_H
+STAR_BUF
*STAR_BUF
;
668 size
/= pow2(conf
.zoom_far
);
670 /* Calculate star buffer. */
671 w
= (SCREEN_W
+ 2.*STAR_BUF
);
672 w
+= conf
.zoom_stars
* (w
/ conf
.zoom_far
- 1.);
673 h
= (SCREEN_H
+ 2.*STAR_BUF
);
674 h
+= conf
.zoom_stars
* (h
/ conf
.zoom_far
- 1.);
678 /* Calculate stars. */
680 nstars
= (unsigned int)(size
/(800.*600.));
682 if (mstars
< nstars
) {
684 star_vertex
= realloc( star_vertex
, nstars
* sizeof(GLfloat
) * 4 );
685 star_colour
= realloc( star_colour
, nstars
* sizeof(GLfloat
) * 8 );
688 for (i
=0; i
< nstars
; i
++) {
689 /* Set the position. */
690 star_vertex
[4*i
+0] = RNGF()*w
- hw
;
691 star_vertex
[4*i
+1] = RNGF()*h
- hh
;
692 star_vertex
[4*i
+2] = 0.;
693 star_vertex
[4*i
+3] = 0.;
694 /* Set the colour. */
695 star_colour
[8*i
+0] = 1.;
696 star_colour
[8*i
+1] = 1.;
697 star_colour
[8*i
+2] = 1.;
698 star_colour
[8*i
+3] = RNGF()*0.6 + 0.2;
699 star_colour
[8*i
+4] = 1.;
700 star_colour
[8*i
+5] = 1.;
701 star_colour
[8*i
+6] = 1.;
702 star_colour
[8*i
+7] = 0.;
705 /* Destroy old VBO. */
706 if (star_vertexVBO
!= NULL
) {
707 gl_vboDestroy( star_vertexVBO
);
708 star_vertexVBO
= NULL
;
710 if (star_colourVBO
!= NULL
) {
711 gl_vboDestroy( star_colourVBO
);
712 star_colourVBO
= NULL
;
715 /* Create now VBO. */
716 star_vertexVBO
= gl_vboCreateStream(
717 nstars
* sizeof(GLfloat
) * 4, star_vertex
);
718 star_colourVBO
= gl_vboCreateStatic(
719 nstars
* sizeof(GLfloat
) * 8, star_colour
);
724 * @brief Initializes the system.
726 * @param sysname Name of the system to initialize.
728 void space_init ( const char* sysname
)
733 /* cleanup some stuff */
734 player_clear(); /* clears targets */
735 pilot_clearTimers(player
); /* Clear timers. */
736 pilots_clean(); /* destroy all the current pilots, except player */
737 weapon_clear(); /* get rid of all the weapons */
738 spfx_clear(); /* get rid of the explosions */
739 space_spawn
= 1; /* spawn is enabled by default. */
740 interference_timer
= 0.; /* Restart timer. */
742 /* Must clear escorts to keep deployment sane. */
743 player_clearEscorts();
745 if ((sysname
==NULL
) && (cur_system
==NULL
))
746 ERR("Cannot reinit system if there is no system previously loaded");
747 else if (sysname
!=NULL
) {
748 for (i
=0; i
< systems_nstack
; i
++)
749 if (strcmp(sysname
, systems_stack
[i
].name
)==0)
752 if (i
>=systems_nstack
)
753 ERR("System %s not found in stack", sysname
);
754 cur_system
= systems_stack
+i
;
756 nt
= ntime_pretty(0);
757 player_message("\epEntering System %s on %s.", sysname
, nt
);
760 /* Handle background */
761 if (cur_system
->nebu_density
> 0.) {
762 /* Background is Nebula */
763 nebu_prep( cur_system
->nebu_density
, cur_system
->nebu_volatility
);
766 sound_env( SOUND_ENV_NEBULA
, cur_system
->nebu_density
);
769 /* Backrgound is Stary */
770 space_initStars( cur_system
->stars
);
773 sound_env( SOUND_ENV_NORMAL
, 0. );
777 /* Iterate through planets to clear bribes. */
778 for (i
=0; i
<cur_system
->nplanets
; i
++)
779 cur_system
->planets
[i
]->bribed
= 0;
781 /* Clear interference if you leave system with interference. */
782 if (cur_system
->interference
== 0.)
783 interference_alpha
= 0.;
785 /* See if we should get a new music song. */
788 /* Reset player enemies. */
791 /* Update the pilot sensor range. */
792 pilot_updateSensorRange();
794 /* set up fleets -> pilots */
795 for (i
=0; i
< cur_system
->nfleets
; i
++) {
796 if (RNG(0,100) <= (cur_system
->fleets
[i
].chance
/2)) /* fleet check (50% chance) */
797 space_addFleet( cur_system
->fleets
[i
].fleet
, 1 );
800 /* start the spawn timer */
803 /* we now know this system */
804 sys_setFlag(cur_system
,SYSTEM_KNOWN
);
809 * @brief Loads all the planets in the game.
811 * @return 0 on success.
813 static int planets_load ( void )
820 buf
= ndata_read( PLANET_DATA
, &bufsize
);
821 doc
= xmlParseMemory( buf
, bufsize
);
823 node
= doc
->xmlChildrenNode
;
824 if (strcmp((char*)node
->name
,XML_PLANET_ID
)) {
825 ERR("Malformed "PLANET_DATA
" file: missing root element '"XML_PLANET_ID
"'");
829 node
= node
->xmlChildrenNode
; /* first system node */
831 ERR("Malformed "PLANET_DATA
" file: does not contain elements");
835 /* Initialize stack if needed. */
836 if (planet_stack
== NULL
) {
837 planet_mstack
= CHUNK_SIZE
;
838 planet_stack
= malloc( sizeof(Planet
) * planet_mstack
);
843 if (xml_isNode(node
,XML_PLANET_TAG
)) {
845 /* See if stack must grow. */
847 if (planet_nstack
> planet_mstack
) {
848 planet_mstack
+= CHUNK_SIZE
;
849 planet_stack
= realloc( planet_stack
, sizeof(Planet
) * planet_mstack
);
852 planet_parse( &planet_stack
[planet_nstack
-1], node
);
854 } while (xml_nextNode(node
));
867 * @brief Parses a planet from an xml node.
869 * @param planet Planet to fill up.
870 * @param parent Node that contains planet data.
871 * @return 0 on success.
873 static int planet_parse( Planet
*planet
, const xmlNodePtr parent
)
877 xmlNodePtr node
, cur
, ccur
;
880 /* Clear up memory for sane defaults. */
881 memset( planet
, 0, sizeof(Planet
) );
882 planet
->faction
= -1;
886 xmlr_attr( parent
, "name", planet
->name
);
888 node
= parent
->xmlChildrenNode
;
891 /* Only handle nodes. */
894 if (xml_isNode(node
,"GFX")) {
895 cur
= node
->children
;
897 if (xml_isNode(cur
,"space")) { /* load space gfx */
898 planet
->gfx_space
= xml_parseTexture( cur
,
899 PLANET_GFX_SPACE
"%s", 1, 1, OPENGL_TEX_MIPMAPS
);
901 else if (xml_isNode(cur
,"exterior")) { /* load land gfx */
902 snprintf( str
, PATH_MAX
, PLANET_GFX_EXTERIOR
"%s", xml_get(cur
));
903 planet
->gfx_exterior
= strdup(str
);
905 } while (xml_nextNode(cur
));
908 else if (xml_isNode(node
,"pos")) {
909 cur
= node
->children
;
911 if (xml_isNode(cur
,"x")) {
913 planet
->pos
.x
= xml_getFloat(cur
);
915 else if (xml_isNode(cur
,"y")) {
917 planet
->pos
.y
= xml_getFloat(cur
);
919 } while(xml_nextNode(cur
));
922 else if (xml_isNode(node
,"general")) {
923 cur
= node
->children
;
926 xmlr_strd(cur
, "bar", planet
->bar_description
);
927 xmlr_strd(cur
, "description", planet
->description
);
928 xmlr_long(cur
, "population", planet
->population
);
929 xmlr_float(cur
, "prodfactor", planet
->prodfactor
);
931 if (xml_isNode(cur
,"class"))
933 planetclass_get(cur
->children
->content
[0]);
934 else if (xml_isNode(cur
,"faction")) {
935 flags
|= FLAG_FACTIONSET
;
936 planet
->faction
= faction_get( xml_get(cur
) );
938 else if (xml_isNode(cur
, "services")) {
939 flags
|= FLAG_SERVICESSET
;
940 ccur
= cur
->children
;
941 planet
->services
= 0;
945 if (xml_isNode(ccur
, "land"))
946 planet
->services
|= PLANET_SERVICE_LAND
;
947 else if (xml_isNode(ccur
, "refuel"))
948 planet
->services
|= PLANET_SERVICE_REFUEL
| PLANET_SERVICE_INHABITED
;
949 else if (xml_isNode(ccur
, "bar"))
950 planet
->services
|= PLANET_SERVICE_BAR
| PLANET_SERVICE_INHABITED
;
951 else if (xml_isNode(ccur
, "missions"))
952 planet
->services
|= PLANET_SERVICE_MISSIONS
| PLANET_SERVICE_INHABITED
;
953 else if (xml_isNode(ccur
, "commodity"))
954 planet
->services
|= PLANET_SERVICE_COMMODITY
| PLANET_SERVICE_INHABITED
;
955 else if (xml_isNode(ccur
, "outfits"))
956 planet
->services
|= PLANET_SERVICE_OUTFITS
| PLANET_SERVICE_INHABITED
;
957 else if (xml_isNode(ccur
, "shipyard"))
958 planet
->services
|= PLANET_SERVICE_SHIPYARD
| PLANET_SERVICE_INHABITED
;
960 WARN("Planet '%s' has unknown services tag '%s'", planet
->name
, ccur
->name
);
962 } while (xml_nextNode(ccur
));
964 else if (xml_isNode(cur
, "tech")) {
965 ccur
= cur
->children
;
967 if (xml_isNode(ccur
,"main")) {
968 flags
|= FLAG_TECHSET
;
969 planet
->tech
[0] = xml_getInt(ccur
);
971 else if (xml_isNode(ccur
,"special")) {
972 for (i
=1; i
<PLANET_TECH_MAX
; i
++)
973 if (planet
->tech
[i
]==0) {
974 planet
->tech
[i
] = xml_getInt(ccur
);
977 if (i
==PLANET_TECH_MAX
) WARN("Planet '%s' has too many"
978 "'special tech' entries", planet
->name
);
980 } while (xml_nextNode(ccur
));
983 else if (xml_isNode(cur
, "commodities")) {
984 ccur
= cur
->children
;
987 if (xml_isNode(ccur
,"commodity")) {
988 planet
->ncommodities
++;
989 /* Memory must grow. */
990 if (planet
->ncommodities
> mem
) {
991 mem
+= CHUNK_SIZE_SMALL
;
992 planet
->commodities
= realloc(planet
->commodities
,
993 mem
* sizeof(Commodity
*));
995 planet
->commodities
[planet
->ncommodities
-1] =
996 commodity_get( xml_get(ccur
) );
998 } while (xml_nextNode(ccur
));
999 /* Shrink to minimum size. */
1000 planet
->commodities
= realloc(planet
->commodities
,
1001 planet
->ncommodities
* sizeof(Commodity
*));
1003 } while(xml_nextNode(cur
));
1007 DEBUG("Unknown node '%s' in planet '%s'",node
->name
,planet
->name
);
1008 } while (xml_nextNode(node
));
1011 /* Some postprocessing. */
1012 planet
->cur_prodfactor
= planet
->prodfactor
;
1017 #define MELEMENT(o,s) if (o) WARN("Planet '%s' missing '"s"' element", planet->name)
1018 MELEMENT(planet
->gfx_space
==NULL
,"GFX space");
1019 MELEMENT( planet_hasService(planet
,PLANET_SERVICE_LAND
) &&
1020 planet
->gfx_exterior
==NULL
,"GFX exterior");
1021 MELEMENT( planet_hasService(planet
,PLANET_SERVICE_INHABITED
) &&
1022 (planet
->population
==0), "population");
1023 MELEMENT( planet_hasService(planet
,PLANET_SERVICE_INHABITED
) &&
1024 (planet
->prodfactor
==0.), "prodfactor");
1025 MELEMENT((flags
&FLAG_XSET
)==0,"x");
1026 MELEMENT((flags
&FLAG_YSET
)==0,"y");
1027 MELEMENT(planet
->class==PLANET_CLASS_NULL
,"class");
1028 MELEMENT( planet_hasService(planet
,PLANET_SERVICE_LAND
) &&
1029 planet
->description
==NULL
,"desription");
1030 MELEMENT( planet_hasService(planet
,PLANET_SERVICE_BAR
) &&
1031 planet
->bar_description
==NULL
,"bar");
1032 MELEMENT( planet_hasService(planet
,PLANET_SERVICE_INHABITED
) &&
1033 (flags
&FLAG_FACTIONSET
)==0,"faction");
1034 MELEMENT((flags
&FLAG_SERVICESSET
)==0,"services");
1035 MELEMENT( (planet_hasService(planet
,PLANET_SERVICE_OUTFITS
) ||
1036 planet_hasService(planet
,PLANET_SERVICE_SHIPYARD
)) &&
1037 (flags
&FLAG_TECHSET
)==0, "tech" );
1038 MELEMENT( planet_hasService(planet
,PLANET_SERVICE_COMMODITY
) &&
1039 (planet
->ncommodities
==0),"commodity" );
1047 * @brief Adds a planet to a star system.
1049 * @param sys Star System to add planet to.
1050 * @param planetname Name of the planet to add.
1051 * @return 0 on success.
1053 int system_addPlanet( StarSystem
*sys
, const char *planetname
)
1060 /* Check if need to grow the star system planet stack. */
1062 if (sys
->planets
== NULL
)
1063 sys
->planets
= malloc( sizeof(Planet
*) * CHUNK_SIZE_SMALL
);
1064 else if (sys
->nplanets
> CHUNK_SIZE_SMALL
)
1065 sys
->planets
= realloc( sys
->planets
, sizeof(Planet
*) * sys
->nplanets
);
1066 planet
= planet_get(planetname
);
1069 sys
->planets
[sys
->nplanets
-1] = planet
;
1071 /* add planet <-> star system to name stack */
1073 if (spacename_nstack
> spacename_mstack
) {
1074 spacename_mstack
+= CHUNK_SIZE
;
1075 planetname_stack
= realloc(planetname_stack
,
1076 sizeof(char*) * spacename_mstack
);
1077 systemname_stack
= realloc(systemname_stack
,
1078 sizeof(char*) * spacename_mstack
);
1080 planetname_stack
[spacename_nstack
-1] = planet
->name
;
1081 systemname_stack
[spacename_nstack
-1] = sys
->name
;
1083 system_setFaction(sys
);
1085 /* Regenerate the economy stuff. */
1093 * @brief Removes a planet from a star system.
1095 * @param sys Star System to remove planet from.
1096 * @param planetname Name of the planet to remove.
1097 * @return 0 on success.
1099 int system_rmPlanet( StarSystem
*sys
, const char *planetname
)
1105 WARN("Unable to remove planet '%s' from NULL system.", planetname
);
1109 /* Try to find planet. */
1110 planet
= planet_get( planetname
);
1111 for (i
=0; i
<sys
->nplanets
; i
++)
1112 if (sys
->planets
[i
] == planet
)
1115 /* Planet not found. */
1116 if (i
>=sys
->nplanets
) {
1117 WARN("Planet '%s' not found in system '%s' for removal.", planetname
, sys
->name
);
1121 /* Remove planet from system. */
1123 memmove( &sys
->planets
[i
], &sys
->planets
[i
+1], sizeof(Planet
*) * (sys
->nplanets
-i
) );
1125 /* Remove from the name stack thingy. */
1127 for (i
=0; i
<spacename_nstack
; i
++)
1128 if (strcmp(planetname
, planetname_stack
[i
])==0) {
1130 memmove( &planetname_stack
[i
], &planetname_stack
[i
+1],
1131 sizeof(char*) * (spacename_nstack
-i
) );
1132 memmove( &systemname_stack
[i
], &systemname_stack
[i
+1],
1133 sizeof(char*) * (spacename_nstack
-i
) );
1138 WARN("Unable to find planet '%s' and system '%s' in planet<->system stack.",
1139 planetname
, sys
->name
);
1141 system_setFaction(sys
);
1143 /* Regenerate the economy stuff. */
1151 * @brief Adds a fleet to a star system.
1153 * @param sys Star System to add fleet to.
1154 * @param fleet Fleet to add.
1155 * @return 0 on success.
1157 int system_addFleet( StarSystem
*sys
, SystemFleet
*fleet
)
1165 /* Add the fleet. */
1167 sys
->fleets
= realloc( sys
->fleets
, sizeof(SystemFleet
)*sys
->nfleets
);
1168 memcpy( &sys
->fleets
[sys
->nfleets
-1], fleet
, sizeof(SystemFleet
) );
1170 /* Adjust the system average. */
1172 for (i
=0; i
< fleet
->fleet
->npilots
; i
++)
1173 avg
+= ((double)fleet
->fleet
->pilots
[i
].chance
) / 100.;
1174 avg
*= ((double)fleet
->chance
) / 100.;
1175 sys
->avg_pilot
+= avg
;
1177 /* Recalculate security. */
1178 system_calcSecurity(sys
);
1185 * @brief Removes a fleet from a star system.
1187 * @param sys Star System to remove fleet from.
1188 * @param fleet Fleet to remove.
1189 * @return 0 on success.
1191 int system_rmFleet( StarSystem
*sys
, SystemFleet
*fleet
)
1196 /* Find a matching fleet (will grab first since can be duplicates). */
1197 for (i
=0; i
<sys
->nfleets
; i
++)
1198 if ((fleet
->fleet
== sys
->fleets
[i
].fleet
) &&
1199 (fleet
->chance
== sys
->fleets
[i
].chance
))
1203 if (i
>= sys
->nfleets
)
1206 /* Remove the fleet. */
1208 memmove(&sys
->fleets
[i
], &sys
->fleets
[i
+1], sizeof(SystemFleet
) * (sys
->nfleets
- i
));
1209 sys
->fleets
= realloc(sys
->fleets
, sizeof(SystemFleet
) * sys
->nfleets
);
1211 /* Adjust the system average. */
1213 for (i
=0; i
< fleet
->fleet
->npilots
; i
++)
1214 avg
+= ((double)fleet
->fleet
->pilots
[i
].chance
) / 100.;
1215 avg
*= ((double)fleet
->chance
) / 100.;
1216 sys
->avg_pilot
-= avg
;
1218 /* Recalculate security. */
1219 system_calcSecurity(sys
);
1226 * @brief Adds a FleetGroup to a star system.
1228 * @param sys Star System to add fleet to.
1229 * @param fltgrp FleetGroup to add.
1230 * @return 0 on success.
1232 int system_addFleetGroup( StarSystem
*sys
, FleetGroup
*fltgrp
)
1240 /* Add all the fleets. */
1241 for (i
=0; i
<fltgrp
->nfleets
; i
++) {
1242 fleet
.fleet
= fltgrp
->fleets
[i
];
1243 fleet
.chance
= fltgrp
->chance
[i
];
1244 if (system_addFleet( sys
, &fleet
))
1253 * @brief Removes a fleetgroup from a star system.
1255 * @param sys Star System to remove fleet from.
1256 * @param fltgrp FleetGroup to remove.
1257 * @return 0 on success.
1259 int system_rmFleetGroup( StarSystem
*sys
, FleetGroup
*fltgrp
)
1267 /* Add all the fleets. */
1268 for (i
=0; i
<fltgrp
->nfleets
; i
++) {
1269 fleet
.fleet
= fltgrp
->fleets
[i
];
1270 fleet
.chance
= fltgrp
->chance
[i
];
1271 if (system_rmFleet( sys
, &fleet
))
1280 * @brief Creates a system from an XML node.
1282 * @param parent XML node to get system from.
1283 * @return System matching parent data.
1285 static StarSystem
* system_parse( StarSystem
*sys
, const xmlNodePtr parent
)
1292 xmlNodePtr cur
, node
;
1296 /* Clear memory for sane defaults. */
1297 memset( sys
, 0, sizeof(StarSystem
) );
1303 sys
->name
= xml_nodeProp(parent
,"name"); /* already mallocs */
1305 node
= parent
->xmlChildrenNode
;
1307 do { /* load all the data */
1309 /* Only handle nodes. */
1310 xml_onlyNodes(node
);
1312 if (xml_isNode(node
,"pos")) {
1313 cur
= node
->children
;
1315 if (xml_isNode(cur
,"x")) {
1317 sys
->pos
.x
= xml_getFloat(cur
);
1319 else if (xml_isNode(cur
,"y")) {
1321 sys
->pos
.y
= xml_getFloat(cur
);
1323 } while (xml_nextNode(cur
));
1326 else if (xml_isNode(node
,"general")) {
1327 cur
= node
->children
;
1329 if (xml_isNode(cur
,"stars")) /* non-zero */
1330 sys
->stars
= xml_getInt(cur
);
1331 else if (xml_isNode(cur
,"asteroids")) {
1332 flags
|= FLAG_ASTEROIDSSET
;
1333 sys
->asteroids
= xml_getInt(cur
);
1335 else if (xml_isNode(cur
,"interference")) {
1336 flags
|= FLAG_INTERFERENCESET
;
1337 sys
->interference
= xml_getFloat(cur
);
1339 else if (xml_isNode(cur
,"nebula")) {
1340 ptrc
= xml_nodeProp(cur
,"volatility");
1341 if (ptrc
!= NULL
) { /* Has volatility */
1342 sys
->nebu_volatility
= atof(ptrc
);
1345 sys
->nebu_density
= xml_getFloat(cur
);
1347 } while (xml_nextNode(cur
));
1350 /* loads all the planets */
1351 else if (xml_isNode(node
,"planets")) {
1352 cur
= node
->children
;
1354 if (xml_isNode(cur
,"planet"))
1355 system_addPlanet( sys
, xml_get(cur
) );
1356 } while (xml_nextNode(cur
));
1359 /* loads all the fleets */
1360 else if (xml_isNode(node
,"fleets")) {
1361 cur
= node
->children
;
1363 if (xml_isNode(cur
,"fleet")) {
1365 /* Try to load it as a FleetGroup. */
1366 fltgrp
= fleet_getGroup(xml_get(cur
));
1367 if (fltgrp
!= NULL
) {
1368 /* Try to load it as a FleetGroup. */
1369 fltgrp
= fleet_getGroup(xml_get(cur
));
1370 if (fltgrp
== NULL
) {
1371 WARN("Fleet '%s' for Star System '%s' not found",
1372 xml_get(cur
), sys
->name
);
1376 /* Add the fleetgroup. */
1377 system_addFleetGroup( sys
, fltgrp
);
1381 /* Try to load it as a fleet. */
1382 flt
= fleet_get(xml_get(cur
));
1384 WARN("Fleet '%s' for Star System '%s' not found",
1385 xml_get(cur
), sys
->name
);
1388 /* Get the fleet. */
1391 /* Get the chance. */
1392 xmlr_attr(cur
,"chance",ptrc
); /* mallocs ptrc */
1393 fleet
.chance
= (ptrc
==NULL
) ? 0 : atoi(ptrc
);
1394 if (fleet
.chance
== 0)
1395 WARN("Fleet '%s' for Star System '%s' has 0%% chance to appear",
1396 fleet
.fleet
->name
, sys
->name
);
1398 free(ptrc
); /* free the ptrc */
1400 /* Add the fleet. */
1401 system_addFleet( sys
, &fleet
);
1404 } while (xml_nextNode(cur
));
1408 /* Avoid warning. */
1409 if (xml_isNode(node
,"jumps"))
1412 DEBUG("Unknown node '%s' in star system '%s'",node
->name
,sys
->name
);
1413 } while (xml_nextNode(node
));
1415 #define MELEMENT(o,s) if (o) WARN("Star System '%s' missing '"s"' element", sys->name)
1416 if (sys
->name
== NULL
) WARN("Star System '%s' missing 'name' tag", sys
->name
);
1417 MELEMENT((flags
&FLAG_XSET
)==0,"x");
1418 MELEMENT((flags
&FLAG_YSET
)==0,"y");
1419 MELEMENT(sys
->stars
==0,"stars");
1420 MELEMENT((flags
&FLAG_ASTEROIDSSET
)==0,"asteroids");
1421 MELEMENT((flags
&FLAG_INTERFERENCESET
)==0,"inteference");
1424 /* post-processing */
1425 system_setFaction( sys
);
1432 * @brief Sets the system faction based on the planets it has.
1434 * @param sys System to set the faction of.
1436 static void system_setFaction( StarSystem
*sys
)
1440 for (i
=0; i
<sys
->nplanets
; i
++) /** @todo Handle multiple different factions. */
1441 if (sys
->planets
[i
]->faction
> 0) {
1442 sys
->faction
= sys
->planets
[i
]->faction
;
1449 * @brief Loads the jumps into a system.
1451 * @param parent System parent node.
1453 static void system_parseJumps( const xmlNodePtr parent
)
1458 xmlNodePtr cur
, node
;
1460 name
= xml_nodeProp(parent
,"name"); /* already mallocs */
1461 for (i
=0; i
<systems_nstack
; i
++)
1462 if (strcmp( systems_stack
[i
].name
, name
)==0) {
1463 sys
= &systems_stack
[i
];
1466 if (i
==systems_nstack
) {
1467 WARN("System '%s' was not found in the stack for some reason",name
);
1470 free(name
); /* no more need for it */
1472 node
= parent
->xmlChildrenNode
;
1474 do { /* load all the data */
1475 if (xml_isNode(node
,"jumps")) {
1476 cur
= node
->children
;
1478 if (xml_isNode(cur
,"jump")) {
1479 for (i
=0; i
<systems_nstack
; i
++)
1480 if (strcmp( systems_stack
[i
].name
, xml_raw(cur
))==0) {
1482 sys
->jumps
= realloc(sys
->jumps
, sys
->njumps
*sizeof(int));
1483 sys
->jumps
[sys
->njumps
-1] = i
;
1486 if (i
==systems_nstack
)
1487 WARN("System '%s' not found for jump linking",xml_get(cur
));
1489 } while (xml_nextNode(cur
));
1491 } while (xml_nextNode(node
));
1496 * @brief Loads the entire universe into ram - pretty big feat eh?
1498 * @return 0 on success.
1500 int space_load (void)
1506 systems_loading
= 1;
1508 ret
= planets_load();
1511 ret
= systems_load();
1516 systems_loading
= 0;
1518 /* Calculate system properties. */
1519 for (i
=0; i
<systems_nstack
; i
++)
1520 system_calcSecurity(&systems_stack
[i
]);
1527 * @brief Calculates the security in a star system.
1529 * @param sys System to calculate security in.
1530 * @return 0 on success.
1532 static int system_calcSecurity( StarSystem
*sys
)
1535 double guard
, hostile
, c
, mod
;
1538 /* Do not run while loading to speed up. */
1539 if (systems_loading
)
1546 /* Calculate hostiles/friendlies. */
1547 for (i
=0; i
<sys
->nfleets
; i
++) {
1548 f
= sys
->fleets
[i
].fleet
;
1549 c
= (double)sys
->fleets
[i
].chance
/ 100.;
1550 mod
= c
* f
->pilot_avg
* pow(f
->mass_avg
, 1./3.);
1551 if (fleet_isFlag(f
, FLEET_FLAG_GUARD
))
1553 else if (faction_getPlayerDef(f
->faction
) < 0)
1560 else if (hostile
== 0.)
1563 sys
->security
= guard
/ (hostile
+ guard
);
1570 * @brief Loads the entire systems, needs to be called after planets_load.
1572 * Does multiple passes to load:
1574 * - First loads the star systems.
1575 * - Next sets the jump routes.
1577 * @return 0 on success.
1579 static int systems_load (void)
1586 /* Load the file. */
1587 buf
= ndata_read( SYSTEM_DATA
, &bufsize
);
1591 doc
= xmlParseMemory( buf
, bufsize
);
1593 WARN("'%s' is not a valid XML file.", SYSTEM_DATA
);
1597 node
= doc
->xmlChildrenNode
;
1598 if (!xml_isNode(node
,XML_SYSTEM_ID
)) {
1599 ERR("Malformed "SYSTEM_DATA
" file: missing root element '"XML_SYSTEM_ID
"'");
1603 node
= node
->xmlChildrenNode
; /* first system node */
1605 ERR("Malformed "SYSTEM_DATA
" file: does not contain elements");
1609 /* Allocate if needed. */
1610 if (systems_stack
== NULL
) {
1611 systems_mstack
= CHUNK_SIZE
;
1612 systems_stack
= malloc( sizeof(StarSystem
) * systems_mstack
);
1618 * First pass - loads all the star systems_stack.
1621 if (xml_isNode(node
,XML_SYSTEM_TAG
)) {
1622 /* Check if memory needs to grow. */
1624 if (systems_nstack
> systems_mstack
) {
1625 systems_mstack
+= CHUNK_SIZE
;
1626 systems_stack
= realloc(systems_stack
, sizeof(StarSystem
) * systems_mstack
);
1629 system_parse(&systems_stack
[systems_nstack
-1],node
);
1631 } while (xml_nextNode(node
));
1635 * Second pass - loads all the jump routes.
1637 node
= doc
->xmlChildrenNode
->xmlChildrenNode
;
1639 if (xml_isNode(node
,XML_SYSTEM_TAG
))
1640 system_parseJumps(node
); /* will automatically load the jumps into the system */
1642 } while (xml_nextNode(node
));
1651 DEBUG("Loaded %d Star System%s with %d Planet%s",
1652 systems_nstack
, (systems_nstack
==1) ? "" : "s",
1653 planet_nstack
, (planet_nstack
==1) ? "" : "s" );
1660 * @brief Renders the system.
1662 * @param dt Current delta tick.
1664 void space_render( const double dt
)
1666 if (cur_system
== NULL
)
1669 if (cur_system
->nebu_density
> 0.)
1672 space_renderStars(dt
);
1677 * @brief Renders the system overlay.
1679 * @param dt Current delta tick.
1681 void space_renderOverlay( const double dt
)
1683 if (cur_system
== NULL
)
1686 if (cur_system
->nebu_density
> 0.)
1687 nebu_renderOverlay(dt
);
1692 * @brief Renders the starry background.
1694 * @param dt Current delta tick.
1696 void space_renderStars( const double dt
)
1699 GLfloat hh
, hw
, h
, w
;
1705 * gprof claims it's the slowest thing in the game!
1708 /* Do some scaling for now. */
1709 gl_cameraZoomGet( &z
);
1710 z
= 1. * (1. - conf
.zoom_stars
) + z
* conf
.zoom_stars
;
1711 gl_matrixMode( GL_PROJECTION
);
1713 gl_matrixScale( z
, z
);
1715 if ((player
!= NULL
) && !player_isFlag(PLAYER_DESTROYED
) &&
1716 !player_isFlag(PLAYER_CREATING
) &&
1717 pilot_isFlag(player
,PILOT_HYPERSPACE
) && /* hyperspace fancy effects */
1718 (player
->ptimer
< HYPERSPACE_STARS_BLUR
)) {
1720 glShadeModel(GL_SMOOTH
);
1722 /* lines will be based on velocity */
1723 m
= HYPERSPACE_STARS_BLUR
-player
->ptimer
;
1724 m
/= HYPERSPACE_STARS_BLUR
;
1725 m
*= HYPERSPACE_STARS_LENGTH
;
1726 x
= m
*cos(VANGLE(player
->solid
->vel
)+M_PI
);
1727 y
= m
*sin(VANGLE(player
->solid
->vel
)+M_PI
);
1729 /* Generate lines. */
1730 for (i
=0; i
< nstars
; i
++) {
1731 brightness
= star_colour
[8*i
+3];
1732 star_vertex
[4*i
+2] = star_vertex
[4*i
+0] + x
*brightness
;
1733 star_vertex
[4*i
+3] = star_vertex
[4*i
+1] + y
*brightness
;
1736 /* Draw the lines. */
1737 gl_vboSubData( star_vertexVBO
, 0, nstars
* 4 * sizeof(GLfloat
), star_vertex
);
1738 gl_vboActivate( star_vertexVBO
, GL_VERTEX_ARRAY
, 2, GL_FLOAT
, 0 );
1739 gl_vboActivate( star_colourVBO
, GL_COLOR_ARRAY
, 4, GL_FLOAT
, 0 );
1740 glDrawArrays( GL_LINES
, 0, nstars
);
1742 glShadeModel(GL_FLAT
);
1744 else { /* normal rendering */
1745 if (!paused
&& (player
!= NULL
) && !player_isFlag(PLAYER_DESTROYED
) &&
1746 !player_isFlag(PLAYER_CREATING
)) { /* update position */
1748 /* Calculate some dimensions. */
1749 w
= (SCREEN_W
+ 2.*STAR_BUF
);
1750 w
+= conf
.zoom_stars
* (w
/ conf
.zoom_far
- 1.);
1751 h
= (SCREEN_H
+ 2.*STAR_BUF
);
1752 h
+= conf
.zoom_stars
* (h
/ conf
.zoom_far
- 1.);
1756 /* Calculate new star positions. */
1757 for (i
=0; i
< nstars
; i
++) {
1759 /* calculate new position */
1760 b
= 9. - 10.*star_colour
[8*i
+3];
1761 star_vertex
[4*i
+0] = star_vertex
[4*i
+0] -
1762 (GLfloat
)player
->solid
->vel
.x
/ b
*(GLfloat
)dt
;
1763 star_vertex
[4*i
+1] = star_vertex
[4*i
+1] -
1764 (GLfloat
)player
->solid
->vel
.y
/ b
*(GLfloat
)dt
;
1766 /* check boundries */
1767 if (star_vertex
[4*i
+0] > hw
)
1768 star_vertex
[4*i
+0] -= w
;
1769 else if (star_vertex
[4*i
+0] < -hw
)
1770 star_vertex
[4*i
+0] += w
;
1771 if (star_vertex
[4*i
+1] > hh
)
1772 star_vertex
[4*i
+1] -= h
;
1773 else if (star_vertex
[4*i
+1] < -hh
)
1774 star_vertex
[4*i
+1] += h
;
1777 /* Upload the data. */
1778 gl_vboSubData( star_vertexVBO
, 0, nstars
* 4 * sizeof(GLfloat
), star_vertex
);
1782 gl_vboActivate( star_vertexVBO
, GL_VERTEX_ARRAY
, 2, GL_FLOAT
, 2 * sizeof(GLfloat
) );
1783 gl_vboActivate( star_colourVBO
, GL_COLOR_ARRAY
, 4, GL_FLOAT
, 4 * sizeof(GLfloat
) );
1784 glDrawArrays( GL_POINTS
, 0, nstars
);
1788 /* Disable vertex array. */
1797 * @brief Renders the current systemsplanets.
1799 void planets_render (void)
1801 if (cur_system
==NULL
) return;
1804 for (i
=0; i
< cur_system
->nplanets
; i
++)
1805 gl_blitSprite( cur_system
->planets
[i
]->gfx_space
,
1806 cur_system
->planets
[i
]->pos
.x
, cur_system
->planets
[i
]->pos
.y
,
1812 * @brief Cleans up the system.
1814 void space_exit (void)
1818 /* Free the names. */
1819 if (planetname_stack
)
1820 free(planetname_stack
);
1821 if (systemname_stack
)
1822 free(systemname_stack
);
1823 spacename_nstack
= 0;
1825 /* Free the planets. */
1826 for (i
=0; i
< planet_nstack
; i
++) {
1827 free(planet_stack
[i
].name
);
1829 if (planet_stack
[i
].description
)
1830 free(planet_stack
[i
].description
);
1831 if (planet_stack
[i
].bar_description
)
1832 free(planet_stack
[i
].bar_description
);
1835 if (planet_stack
[i
].gfx_space
)
1836 gl_freeTexture(planet_stack
[i
].gfx_space
);
1837 if (planet_stack
[i
].gfx_exterior
)
1838 free(planet_stack
[i
].gfx_exterior
);
1841 free(planet_stack
[i
].commodities
);
1844 planet_stack
= NULL
;
1848 /* Free the systems. */
1849 for (i
=0; i
< systems_nstack
; i
++) {
1850 free(systems_stack
[i
].name
);
1851 if (systems_stack
[i
].fleets
)
1852 free(systems_stack
[i
].fleets
);
1853 if (systems_stack
[i
].jumps
)
1854 free(systems_stack
[i
].jumps
);
1856 free(systems_stack
[i
].planets
);
1858 free(systems_stack
);
1859 systems_stack
= NULL
;
1863 /* stars must be free too */
1878 * @brief Clears all system knowledge.
1880 void space_clearKnown (void)
1883 for (i
=0; i
<systems_nstack
; i
++)
1884 sys_rmFlag(&systems_stack
[i
],SYSTEM_KNOWN
);
1889 * @brief Clears all system markers.
1891 void space_clearMarkers (void)
1894 for (i
=0; i
<systems_nstack
; i
++) {
1895 sys_rmFlag(&systems_stack
[i
], SYSTEM_MARKED
);
1896 systems_stack
[i
].markers_misc
= 0;
1897 systems_stack
[i
].markers_rush
= 0;
1898 systems_stack
[i
].markers_cargo
= 0;
1904 * @brief Clears all the system computer markers.
1906 void space_clearComputerMarkers (void)
1909 for (i
=0; i
<systems_nstack
; i
++)
1910 sys_rmFlag(&systems_stack
[i
],SYSTEM_CMARKED
);
1915 * @brief Adds a marker to a system.
1917 * @param sys Name of the system to add marker to.
1918 * @param type Type of the marker to add.
1919 * @return 0 on success.
1921 int space_addMarker( const char *sys
, SysMarker type
)
1926 /* Get the system. */
1927 ssys
= system_get(sys
);
1931 /* Get the marker. */
1933 case SYSMARKER_MISC
:
1934 markers
= &ssys
->markers_misc
;
1936 case SYSMARKER_RUSH
:
1937 markers
= &ssys
->markers_rush
;
1939 case SYSMARKER_CARGO
:
1940 markers
= &ssys
->markers_cargo
;
1943 WARN("Unknown marker type.");
1947 /* Decrement markers. */
1949 sys_setFlag(ssys
, SYSTEM_MARKED
);
1956 * @brief Removes a marker from a system.
1958 * @param sys Name of the system to remove marker from.
1959 * @param type Type of the marker to remove.
1960 * @return 0 on success.
1962 int space_rmMarker( const char *sys
, SysMarker type
)
1967 /* Get the system. */
1968 ssys
= system_get(sys
);
1972 /* Get the marker. */
1974 case SYSMARKER_MISC
:
1975 markers
= &ssys
->markers_misc
;
1977 case SYSMARKER_RUSH
:
1978 markers
= &ssys
->markers_rush
;
1980 case SYSMARKER_CARGO
:
1981 markers
= &ssys
->markers_cargo
;
1984 WARN("Unknown marker type.");
1988 /* Decrement markers. */
1990 if (*markers
<= 0) {
1991 sys_rmFlag(ssys
, SYSTEM_MARKED
);
2000 * @brief Saves what is needed to be saved for space.
2002 * @param writer XML writer to use.
2003 * @return 0 on success.
2005 int space_sysSave( xmlTextWriterPtr writer
)
2009 xmlw_startElem(writer
,"space");
2011 for (i
=0; i
<systems_nstack
; i
++) {
2013 if (!sys_isKnown(&systems_stack
[i
])) continue; /* not known */
2015 xmlw_elem(writer
,"known","%s",systems_stack
[i
].name
);
2018 xmlw_endElem(writer
); /* "space" */
2025 * @brief Loads player's space properties from an XML node.
2027 * @param parent Parent node for space.
2028 * @return 0 on success.
2030 int space_sysLoad( xmlNodePtr parent
)
2032 xmlNodePtr node
, cur
;
2037 node
= parent
->xmlChildrenNode
;
2039 if (xml_isNode(node
,"space")) {
2040 cur
= node
->xmlChildrenNode
;
2043 if (xml_isNode(cur
,"known")) {
2044 sys
= system_get(xml_get(cur
));
2045 if (sys
!= NULL
) /* Must exist */
2046 sys_setFlag(sys
,SYSTEM_KNOWN
);
2048 } while (xml_nextNode(cur
));
2050 } while (xml_nextNode(node
));