1 //Copyright Paul Reiche, Fred Ford. 1992-2002
2 
3 /*
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #include "genall.h"
20 #include "../lander.h"
21 #include "../lifeform.h"
22 #include "../planets.h"
23 #include "../../build.h"
24 #include "../../encount.h"
25 #include "../../globdata.h"
26 #include "../../gamestr.h"
27 #include "../../grpinfo.h"
28 #include "../../nameref.h"
29 #include "../../state.h"
30 #include "libs/mathlib.h"
31 
32 
33 static bool GenerateSol_initNpcs (SOLARSYS_STATE *solarSys);
34 static bool GenerateSol_reinitNpcs (SOLARSYS_STATE *solarSys);
35 static bool GenerateSol_generatePlanets (SOLARSYS_STATE *solarSys);
36 static bool GenerateSol_generateMoons (SOLARSYS_STATE *solarSys,
37 		PLANET_DESC *planet);
38 static bool GenerateSol_generateName (const SOLARSYS_STATE *,
39 		const PLANET_DESC *world);
40 static bool GenerateSol_generateOrbital (SOLARSYS_STATE *solarSys,
41 		PLANET_DESC *world);
42 static COUNT GenerateSol_generateEnergy (const SOLARSYS_STATE *,
43 		const PLANET_DESC *world, COUNT whichNode, NODE_INFO *);
44 static COUNT GenerateSol_generateLife (const SOLARSYS_STATE *,
45 		const PLANET_DESC *world, COUNT whichNode, NODE_INFO *);
46 static bool GenerateSol_pickupEnergy (SOLARSYS_STATE *solarSys,
47 		PLANET_DESC *world, COUNT whichNode);
48 
49 static int init_probe (void);
50 static void check_probe (void);
51 
52 
53 const GenerateFunctions generateSolFunctions = {
54 	/* .initNpcs         = */ GenerateSol_initNpcs,
55 	/* .reinitNpcs       = */ GenerateSol_reinitNpcs,
56 	/* .uninitNpcs       = */ GenerateDefault_uninitNpcs,
57 	/* .generatePlanets  = */ GenerateSol_generatePlanets,
58 	/* .generateMoons    = */ GenerateSol_generateMoons,
59 	/* .generateName     = */ GenerateSol_generateName,
60 	/* .generateOrbital  = */ GenerateSol_generateOrbital,
61 	/* .generateMinerals = */ GenerateDefault_generateMinerals,
62 	/* .generateEnergy   = */ GenerateSol_generateEnergy,
63 	/* .generateLife     = */ GenerateSol_generateLife,
64 	/* .pickupMinerals   = */ GenerateDefault_pickupMinerals,
65 	/* .pickupEnergy     = */ GenerateSol_pickupEnergy,
66 	/* .pickupLife       = */ GenerateDefault_pickupLife,
67 };
68 
69 
70 static bool
GenerateSol_initNpcs(SOLARSYS_STATE * solarSys)71 GenerateSol_initNpcs (SOLARSYS_STATE *solarSys)
72 {
73 	GLOBAL (BattleGroupRef) = GET_GAME_STATE_32 (URQUAN_PROBE_GRPOFFS0);
74 	if (GLOBAL (BattleGroupRef) == 0)
75 	{
76 		CloneShipFragment (URQUAN_DRONE_SHIP, &GLOBAL (npc_built_ship_q), 0);
77 		GLOBAL (BattleGroupRef) = PutGroupInfo (GROUPS_ADD_NEW, 1);
78 		ReinitQueue (&GLOBAL (npc_built_ship_q));
79 		SET_GAME_STATE_32 (URQUAN_PROBE_GRPOFFS0, GLOBAL (BattleGroupRef));
80 	}
81 
82 	if (!init_probe ())
83 		GenerateDefault_initNpcs (solarSys);
84 
85 	return true;
86 }
87 
88 static bool
GenerateSol_reinitNpcs(SOLARSYS_STATE * solarSys)89 GenerateSol_reinitNpcs (SOLARSYS_STATE *solarSys)
90 {
91 	if (GET_GAME_STATE (CHMMR_BOMB_STATE) != 3)
92 	{
93 		GenerateDefault_reinitNpcs (solarSys);
94 		check_probe ();
95 	}
96 	else
97 	{
98 		GLOBAL (BattleGroupRef) = 0;
99 		ReinitQueue (&GLOBAL (ip_group_q));
100 		assert (CountLinks (&GLOBAL (npc_built_ship_q)) == 0);
101 	}
102 	return true;
103 }
104 
105 static bool
GenerateSol_generatePlanets(SOLARSYS_STATE * solarSys)106 GenerateSol_generatePlanets (SOLARSYS_STATE *solarSys)
107 {
108 	COUNT planetI;
109 
110 #define SOL_SEED 334241042L
111 	RandomContext_SeedRandom (SysGenRNG, SOL_SEED);
112 
113 	solarSys->SunDesc[0].NumPlanets = 9;
114 	for (planetI = 0; planetI < 9; ++planetI)
115 	{
116 		COUNT angle;
117 		DWORD rand_val;
118 		UWORD word_val;
119 		PLANET_DESC *pCurDesc = &solarSys->PlanetDesc[planetI];
120 
121 		pCurDesc->rand_seed = RandomContext_Random (SysGenRNG);
122 		rand_val = pCurDesc->rand_seed;
123 		word_val = LOWORD (rand_val);
124 		angle = NORMALIZE_ANGLE ((COUNT)HIBYTE (word_val));
125 
126 		switch (planetI)
127 		{
128 			case 0: /* MERCURY */
129 				pCurDesc->data_index = METAL_WORLD;
130 				pCurDesc->radius = EARTH_RADIUS * 39L / 100;
131 				pCurDesc->NumPlanets = 0;
132 				break;
133 			case 1: /* VENUS */
134 				pCurDesc->data_index = PRIMORDIAL_WORLD;
135 				pCurDesc->radius = EARTH_RADIUS * 72L / 100;
136 				pCurDesc->NumPlanets = 0;
137 				angle = NORMALIZE_ANGLE (FULL_CIRCLE - angle);
138 				break;
139 			case 2: /* EARTH */
140 				pCurDesc->data_index = WATER_WORLD | PLANET_SHIELDED;
141 				pCurDesc->radius = EARTH_RADIUS;
142 				pCurDesc->NumPlanets = 2;
143 				break;
144 			case 3: /* MARS */
145 				pCurDesc->data_index = DUST_WORLD;
146 				pCurDesc->radius = EARTH_RADIUS * 152L / 100;
147 				pCurDesc->NumPlanets = 0;
148 				break;
149 			case 4: /* JUPITER */
150 				pCurDesc->data_index = RED_GAS_GIANT;
151 				pCurDesc->radius = EARTH_RADIUS * 500L /* 520L */ / 100;
152 				pCurDesc->NumPlanets = 4;
153 				break;
154 			case 5: /* SATURN */
155 				pCurDesc->data_index = ORA_GAS_GIANT;
156 				pCurDesc->radius = EARTH_RADIUS * 750L /* 952L */ / 100;
157 				pCurDesc->NumPlanets = 1;
158 				break;
159 			case 6: /* URANUS */
160 				pCurDesc->data_index = GRN_GAS_GIANT;
161 				pCurDesc->radius = EARTH_RADIUS * 1000L /* 1916L */ / 100;
162 				pCurDesc->NumPlanets = 0;
163 				break;
164 			case 7: /* NEPTUNE */
165 				pCurDesc->data_index = BLU_GAS_GIANT;
166 				pCurDesc->radius = EARTH_RADIUS * 1250L /* 2999L */ / 100;
167 				pCurDesc->NumPlanets = 1;
168 				break;
169 			case 8: /* PLUTO */
170 				pCurDesc->data_index = PELLUCID_WORLD;
171 				pCurDesc->radius = EARTH_RADIUS * 1550L /* 3937L */ / 100;
172 				pCurDesc->NumPlanets = 0;
173 				angle = FULL_CIRCLE - OCTANT;
174 				break;
175 		}
176 
177 		pCurDesc->location.x = COSINE (angle, pCurDesc->radius);
178 		pCurDesc->location.y = SINE (angle, pCurDesc->radius);
179 	}
180 
181 	return true;
182 }
183 
184 static bool
GenerateSol_generateMoons(SOLARSYS_STATE * solarSys,PLANET_DESC * planet)185 GenerateSol_generateMoons (SOLARSYS_STATE *solarSys, PLANET_DESC *planet)
186 {
187 	COUNT planetNr;
188 	DWORD rand_val;
189 
190 	GenerateDefault_generateMoons (solarSys, planet);
191 
192 	planetNr = planetIndex (solarSys, planet);
193 	switch (planetNr)
194 	{
195 		case 2: /* moons of EARTH */
196 		{
197 			COUNT angle;
198 
199 			/* Starbase: */
200 			solarSys->MoonDesc[0].data_index = HIERARCHY_STARBASE;
201 			solarSys->MoonDesc[0].radius = MIN_MOON_RADIUS;
202 			angle = HALF_CIRCLE + QUADRANT;
203 			solarSys->MoonDesc[0].location.x =
204 					COSINE (angle, solarSys->MoonDesc[0].radius);
205 			solarSys->MoonDesc[0].location.y =
206 					SINE (angle, solarSys->MoonDesc[0].radius);
207 
208 			/* Luna: */
209 			solarSys->MoonDesc[1].data_index = SELENIC_WORLD;
210 			solarSys->MoonDesc[1].radius = MIN_MOON_RADIUS
211 					+ (MAX_MOONS - 1) * MOON_DELTA;
212 			rand_val = RandomContext_Random (SysGenRNG);
213 			angle = NORMALIZE_ANGLE (LOWORD (rand_val));
214 			solarSys->MoonDesc[1].location.x =
215 					COSINE (angle, solarSys->MoonDesc[1].radius);
216 			solarSys->MoonDesc[1].location.y =
217 					SINE (angle, solarSys->MoonDesc[1].radius);
218 			break;
219 		}
220 		case 4: /* moons of JUPITER */
221 			solarSys->MoonDesc[0].data_index = RADIOACTIVE_WORLD;
222 					/* Io */
223 			solarSys->MoonDesc[1].data_index = HALIDE_WORLD;
224 					/* Europa */
225 			solarSys->MoonDesc[2].data_index = CYANIC_WORLD;
226 					/* Ganymede */
227 			solarSys->MoonDesc[3].data_index = PELLUCID_WORLD;
228 					/* Callisto */
229 			break;
230 		case 5: /* moons of SATURN */
231 			solarSys->MoonDesc[0].data_index = ALKALI_WORLD;
232 					/* Titan */
233 			break;
234 		case 7: /* moons of NEPTUNE */
235 			solarSys->MoonDesc[0].data_index = VINYLOGOUS_WORLD;
236 					/* Triton */
237 			break;
238 	}
239 
240 	return true;
241 }
242 
243 static bool
GenerateSol_generateName(const SOLARSYS_STATE * solarSys,const PLANET_DESC * world)244 GenerateSol_generateName (const SOLARSYS_STATE *solarSys,
245 		const PLANET_DESC *world)
246 {
247 	COUNT planetNr = planetIndex (solarSys, world);
248 	utf8StringCopy (GLOBAL_SIS (PlanetName), sizeof (GLOBAL_SIS (PlanetName)),
249 			GAME_STRING (PLANET_NUMBER_BASE + planetNr));
250 	SET_GAME_STATE (BATTLE_PLANET, solarSys->PlanetDesc[planetNr].data_index);
251 
252 	return true;
253 }
254 
255 static bool
GenerateSol_generateOrbital(SOLARSYS_STATE * solarSys,PLANET_DESC * world)256 GenerateSol_generateOrbital (SOLARSYS_STATE *solarSys, PLANET_DESC *world)
257 {
258 	DWORD rand_val;
259 	COUNT planetNr;
260 
261 	if (matchWorld (solarSys, world, 2, 0))
262 	{
263 		/* Starbase */
264 		PutGroupInfo (GROUPS_RANDOM, GROUP_SAVE_IP);
265 		ReinitQueue (&GLOBAL (ip_group_q));
266 		assert (CountLinks (&GLOBAL (npc_built_ship_q)) == 0);
267 
268 		EncounterGroup = 0;
269 		GLOBAL (CurrentActivity) |= START_ENCOUNTER;
270 		SET_GAME_STATE (GLOBAL_FLAGS_AND_DATA, (BYTE)~0);
271 		return true;
272 	}
273 
274 	DoPlanetaryAnalysis (&solarSys->SysInfo, world);
275 	rand_val = RandomContext_GetSeed (SysGenRNG);
276 
277 	solarSys->SysInfo.PlanetInfo.ScanSeed[MINERAL_SCAN] = rand_val;
278 	GenerateMineralDeposits (&solarSys->SysInfo, GENERATE_ALL, NULL);
279 	rand_val = RandomContext_GetSeed (SysGenRNG);
280 
281 	planetNr = planetIndex (solarSys, world);
282 	if (worldIsPlanet (solarSys, world))
283 	{
284 		switch (planetNr)
285 		{
286 			case 0: /* MERCURY */
287 				solarSys->SysInfo.PlanetInfo.AtmoDensity = 0;
288 				solarSys->SysInfo.PlanetInfo.PlanetDensity = 98;
289 				solarSys->SysInfo.PlanetInfo.PlanetRadius = 38;
290 				solarSys->SysInfo.PlanetInfo.AxialTilt = 3;
291 				solarSys->SysInfo.PlanetInfo.Weather = 0;
292 				solarSys->SysInfo.PlanetInfo.Tectonics = 2;
293 				solarSys->SysInfo.PlanetInfo.RotationPeriod = 59 * 240;
294 				solarSys->SysInfo.PlanetInfo.SurfaceTemperature = 165;
295 				break;
296 			case 1: /* VENUS */
297 				solarSys->SysInfo.PlanetInfo.AtmoDensity = 90 *
298 						EARTH_ATMOSPHERE;
299 				solarSys->SysInfo.PlanetInfo.PlanetDensity = 95;
300 				solarSys->SysInfo.PlanetInfo.PlanetRadius = 95;
301 				solarSys->SysInfo.PlanetInfo.AxialTilt = 177;
302 				solarSys->SysInfo.PlanetInfo.Weather = 7;
303 				solarSys->SysInfo.PlanetInfo.Tectonics = 1;
304 				solarSys->SysInfo.PlanetInfo.RotationPeriod = 243 * 240;
305 				solarSys->SysInfo.PlanetInfo.SurfaceTemperature = 457;
306 				break;
307 			case 2: /* EARTH */
308 				solarSys->SysInfo.PlanetInfo.AtmoDensity =
309 						EARTH_ATMOSPHERE;
310 				solarSys->SysInfo.PlanetInfo.PlanetDensity = 100;
311 				solarSys->SysInfo.PlanetInfo.PlanetRadius = 100;
312 				solarSys->SysInfo.PlanetInfo.AxialTilt = 23;
313 				solarSys->SysInfo.PlanetInfo.Weather = 1;
314 				solarSys->SysInfo.PlanetInfo.Tectonics = 1;
315 				solarSys->SysInfo.PlanetInfo.RotationPeriod = 240;
316 				solarSys->SysInfo.PlanetInfo.SurfaceTemperature = 22;
317 				break;
318 			case 3: /* MARS */
319 				// XXX: Mars atmo should actually be 1/2 in current units
320 				solarSys->SysInfo.PlanetInfo.AtmoDensity = 1;
321 				solarSys->SysInfo.PlanetInfo.PlanetDensity = 72;
322 				solarSys->SysInfo.PlanetInfo.PlanetRadius = 53;
323 				solarSys->SysInfo.PlanetInfo.AxialTilt = 24;
324 				solarSys->SysInfo.PlanetInfo.Weather = 1;
325 				solarSys->SysInfo.PlanetInfo.Tectonics = 1;
326 				solarSys->SysInfo.PlanetInfo.RotationPeriod = 246;
327 				solarSys->SysInfo.PlanetInfo.SurfaceTemperature = -53;
328 				break;
329 			case 4: /* JUPITER */
330 				solarSys->SysInfo.PlanetInfo.AtmoDensity =
331 						GAS_GIANT_ATMOSPHERE;
332 				solarSys->SysInfo.PlanetInfo.PlanetDensity = 24;
333 				solarSys->SysInfo.PlanetInfo.PlanetRadius = 1120;
334 				solarSys->SysInfo.PlanetInfo.AxialTilt = 3;
335 				solarSys->SysInfo.PlanetInfo.Weather = 7;
336 				solarSys->SysInfo.PlanetInfo.Tectonics = 0;
337 				solarSys->SysInfo.PlanetInfo.RotationPeriod = 98;
338 				solarSys->SysInfo.PlanetInfo.SurfaceTemperature = -143;
339 				solarSys->SysInfo.PlanetInfo.PlanetToSunDist =
340 						EARTH_RADIUS * 520L / 100;
341 				break;
342 			case 5: /* SATURN */
343 				solarSys->SysInfo.PlanetInfo.AtmoDensity =
344 						GAS_GIANT_ATMOSPHERE;
345 				solarSys->SysInfo.PlanetInfo.PlanetDensity = 13;
346 				solarSys->SysInfo.PlanetInfo.PlanetRadius = 945;
347 				solarSys->SysInfo.PlanetInfo.AxialTilt = 27;
348 				solarSys->SysInfo.PlanetInfo.Weather = 7;
349 				solarSys->SysInfo.PlanetInfo.Tectonics = 0;
350 				solarSys->SysInfo.PlanetInfo.RotationPeriod = 102;
351 				solarSys->SysInfo.PlanetInfo.SurfaceTemperature = -197;
352 				solarSys->SysInfo.PlanetInfo.PlanetToSunDist =
353 						EARTH_RADIUS * 952L / 100;
354 				break;
355 			case 6: /* URANUS */
356 				solarSys->SysInfo.PlanetInfo.AtmoDensity =
357 						GAS_GIANT_ATMOSPHERE;
358 				solarSys->SysInfo.PlanetInfo.PlanetDensity = 21;
359 				solarSys->SysInfo.PlanetInfo.PlanetRadius = 411;
360 				solarSys->SysInfo.PlanetInfo.AxialTilt = 98;
361 				solarSys->SysInfo.PlanetInfo.Weather = 7;
362 				solarSys->SysInfo.PlanetInfo.Tectonics = 0;
363 				solarSys->SysInfo.PlanetInfo.RotationPeriod = 172;
364 				solarSys->SysInfo.PlanetInfo.SurfaceTemperature = -217;
365 				solarSys->SysInfo.PlanetInfo.PlanetToSunDist =
366 						EARTH_RADIUS * 1916L / 100;
367 				break;
368 			case 7: /* NEPTUNE */
369 				solarSys->SysInfo.PlanetInfo.AtmoDensity =
370 						GAS_GIANT_ATMOSPHERE;
371 				solarSys->SysInfo.PlanetInfo.PlanetDensity = 28;
372 				solarSys->SysInfo.PlanetInfo.PlanetRadius = 396;
373 				solarSys->SysInfo.PlanetInfo.AxialTilt = 30;
374 				solarSys->SysInfo.PlanetInfo.Weather = 7;
375 				solarSys->SysInfo.PlanetInfo.Tectonics = 0;
376 				solarSys->SysInfo.PlanetInfo.RotationPeriod = 182;
377 				solarSys->SysInfo.PlanetInfo.SurfaceTemperature = -229;
378 				solarSys->SysInfo.PlanetInfo.PlanetToSunDist =
379 						EARTH_RADIUS * 2999L / 100;
380 				break;
381 			case 8: /* PLUTO */
382 				if (!GET_GAME_STATE (FOUND_PLUTO_SPATHI))
383 				{
384 					LoadStdLanderFont (&solarSys->SysInfo.PlanetInfo);
385 					solarSys->PlanetSideFrame[1] =
386 							CaptureDrawable (
387 							LoadGraphic (SPAPLUTO_MASK_PMAP_ANIM));
388 					solarSys->SysInfo.PlanetInfo.DiscoveryString =
389 							CaptureStringTable (
390 							LoadStringTable (SPAPLUTO_STRTAB));
391 				}
392 
393 				solarSys->SysInfo.PlanetInfo.AtmoDensity = 0;
394 				solarSys->SysInfo.PlanetInfo.PlanetDensity = 33;
395 				solarSys->SysInfo.PlanetInfo.PlanetRadius = 18;
396 				solarSys->SysInfo.PlanetInfo.AxialTilt = 119;
397 				solarSys->SysInfo.PlanetInfo.Weather = 0;
398 				solarSys->SysInfo.PlanetInfo.Tectonics = 0;
399 				solarSys->SysInfo.PlanetInfo.RotationPeriod = 1533;
400 				solarSys->SysInfo.PlanetInfo.SurfaceTemperature = -235;
401 				solarSys->SysInfo.PlanetInfo.PlanetToSunDist =
402 						EARTH_RADIUS * 3937L / 100;
403 				break;
404 		}
405 
406 		solarSys->SysInfo.PlanetInfo.SurfaceGravity =
407 				CalcGravity (&solarSys->SysInfo.PlanetInfo);
408 		LoadPlanet (planetNr == 2 ?
409 				CaptureDrawable (LoadGraphic (EARTH_MASK_ANIM)) : NULL);
410 	}
411 	else
412 	{
413 		// World is a moon.
414 		COUNT moonNr = moonIndex (solarSys, world);
415 
416 		solarSys->SysInfo.PlanetInfo.AxialTilt = 0;
417 		solarSys->SysInfo.PlanetInfo.AtmoDensity = 0;
418 		solarSys->SysInfo.PlanetInfo.Weather = 0;
419 		switch (planetNr)
420 		{
421 			case 2: /* moons of EARTH */
422 				// NOTE: Even though we save the seed here, it is irrelevant.
423 				//   The seed will be used to randomly place the tractors, but
424 				//   since they are mobile, they will be moved to different
425 				//   locations not governed by this seed.
426 				solarSys->SysInfo.PlanetInfo.ScanSeed[BIOLOGICAL_SCAN] =
427 						rand_val;
428 
429 				if (!GET_GAME_STATE (MOONBASE_DESTROYED))
430 				{
431 					LoadStdLanderFont (&solarSys->SysInfo.PlanetInfo);
432 					solarSys->PlanetSideFrame[1] =
433 							CaptureDrawable (
434 							LoadGraphic (MOONBASE_MASK_PMAP_ANIM));
435 					solarSys->SysInfo.PlanetInfo.DiscoveryString =
436 							CaptureStringTable (
437 							LoadStringTable (MOONBASE_STRTAB));
438 				}
439 
440 				solarSys->SysInfo.PlanetInfo.PlanetDensity = 60;
441 				solarSys->SysInfo.PlanetInfo.PlanetRadius = 25;
442 				solarSys->SysInfo.PlanetInfo.AxialTilt = 0;
443 				solarSys->SysInfo.PlanetInfo.Tectonics = 0;
444 				solarSys->SysInfo.PlanetInfo.RotationPeriod = 240 * 29;
445 				solarSys->SysInfo.PlanetInfo.SurfaceTemperature = -18;
446 				break;
447 
448 			case 4: /* moons of JUPITER */
449 				solarSys->SysInfo.PlanetInfo.PlanetToSunDist =
450 						EARTH_RADIUS * 520L / 100;
451 				switch (moonNr)
452 				{
453 					case 0: /* Io */
454 						solarSys->SysInfo.PlanetInfo.PlanetDensity = 69;
455 						solarSys->SysInfo.PlanetInfo.PlanetRadius = 25;
456 						solarSys->SysInfo.PlanetInfo.Tectonics = 3;
457 						solarSys->SysInfo.PlanetInfo.RotationPeriod = 390;
458 						solarSys->SysInfo.PlanetInfo.SurfaceTemperature = -163;
459 						break;
460 					case 1: /* Europa */
461 						solarSys->SysInfo.PlanetInfo.PlanetDensity = 54;
462 						solarSys->SysInfo.PlanetInfo.PlanetRadius = 25;
463 						solarSys->SysInfo.PlanetInfo.Tectonics = 1;
464 						solarSys->SysInfo.PlanetInfo.RotationPeriod = 840;
465 						solarSys->SysInfo.PlanetInfo.SurfaceTemperature = -161;
466 						break;
467 					case 2: /* Ganymede */
468 						solarSys->SysInfo.PlanetInfo.PlanetDensity = 35;
469 						solarSys->SysInfo.PlanetInfo.PlanetRadius = 41;
470 						solarSys->SysInfo.PlanetInfo.Tectonics = 0;
471 						solarSys->SysInfo.PlanetInfo.RotationPeriod = 1728;
472 						solarSys->SysInfo.PlanetInfo.SurfaceTemperature = -164;
473 						break;
474 					case 3: /* Callisto */
475 						solarSys->SysInfo.PlanetInfo.PlanetDensity = 35;
476 						solarSys->SysInfo.PlanetInfo.PlanetRadius = 38;
477 						solarSys->SysInfo.PlanetInfo.Tectonics = 1;
478 						solarSys->SysInfo.PlanetInfo.RotationPeriod = 4008;
479 						solarSys->SysInfo.PlanetInfo.SurfaceTemperature = -167;
480 						break;
481 				}
482 				break;
483 
484 			case 5: /* moon of SATURN: Titan */
485 				solarSys->SysInfo.PlanetInfo.PlanetToSunDist =
486 						EARTH_RADIUS * 952L / 100;
487 				solarSys->SysInfo.PlanetInfo.AtmoDensity = 160;
488 				solarSys->SysInfo.PlanetInfo.Weather = 2;
489 				solarSys->SysInfo.PlanetInfo.PlanetDensity = 34;
490 				solarSys->SysInfo.PlanetInfo.PlanetRadius = 40;
491 				solarSys->SysInfo.PlanetInfo.Tectonics = 1;
492 				solarSys->SysInfo.PlanetInfo.RotationPeriod = 3816;
493 				solarSys->SysInfo.PlanetInfo.SurfaceTemperature = -178;
494 				break;
495 
496 			case 7: /* moon of NEPTUNE: Triton */
497 				solarSys->SysInfo.PlanetInfo.PlanetToSunDist =
498 						EARTH_RADIUS * 2999L / 100;
499 				solarSys->SysInfo.PlanetInfo.AtmoDensity = 10;
500 				solarSys->SysInfo.PlanetInfo.Weather = 1;
501 				solarSys->SysInfo.PlanetInfo.PlanetDensity = 95;
502 				solarSys->SysInfo.PlanetInfo.PlanetRadius = 27;
503 				solarSys->SysInfo.PlanetInfo.Tectonics = 0;
504 				solarSys->SysInfo.PlanetInfo.RotationPeriod = 4300;
505 				solarSys->SysInfo.PlanetInfo.SurfaceTemperature = -216;
506 				break;
507 		}
508 
509 		solarSys->SysInfo.PlanetInfo.SurfaceGravity =
510 				CalcGravity (&solarSys->SysInfo.PlanetInfo);
511 		LoadPlanet (NULL);
512 	}
513 
514 	return true;
515 }
516 
517 static COUNT
GenerateSol_generateEnergy(const SOLARSYS_STATE * solarSys,const PLANET_DESC * world,COUNT whichNode,NODE_INFO * info)518 GenerateSol_generateEnergy (const SOLARSYS_STATE *solarSys,
519 		const PLANET_DESC *world, COUNT whichNode, NODE_INFO *info)
520 {
521 	if (matchWorld (solarSys, world, 8, MATCH_PLANET))
522 	{
523 		/* Pluto */
524 		// This check is needed because the retrieval bit is not set for
525 		// this node to keep it on the surface while the lander is taking off
526 		if (GET_GAME_STATE (FOUND_PLUTO_SPATHI))
527 		{	// already picked up
528 			return 0;
529 		}
530 
531 		if (info)
532 		{
533 			info->loc_pt.x = 20;
534 			info->loc_pt.y = MAP_HEIGHT - 8;
535 		}
536 
537 		return 1; // only matters when count is requested
538 	}
539 
540 	if (matchWorld (solarSys, world, 2, 1))
541 	{
542 		/* Earth Moon */
543 		// This check is redundant since the retrieval bit will keep the
544 		// node from showing up again
545 		if (GET_GAME_STATE (MOONBASE_DESTROYED))
546 		{	// already picked up
547 			return 0;
548 		}
549 
550 		if (info)
551 		{
552 			info->loc_pt.x = MAP_WIDTH * 3 / 4;
553 			info->loc_pt.y = MAP_HEIGHT * 1 / 4;
554 		}
555 
556 		return 1; // only matters when count is requested
557 	}
558 
559 	(void) whichNode;
560 	return 0;
561 }
562 
563 static bool
GenerateSol_pickupEnergy(SOLARSYS_STATE * solarSys,PLANET_DESC * world,COUNT whichNode)564 GenerateSol_pickupEnergy (SOLARSYS_STATE *solarSys, PLANET_DESC *world,
565 		COUNT whichNode)
566 {
567 	if (matchWorld (solarSys, world, 8, MATCH_PLANET))
568 	{	// Pluto
569 		assert (!GET_GAME_STATE (FOUND_PLUTO_SPATHI) && whichNode == 0);
570 
571 		// Ran into Fwiffo on Pluto
572 		#define FWIFFO_FRAGS  8
573 		if (!KillLanderCrewSeq (FWIFFO_FRAGS, ONE_SECOND / 20))
574 			return false; // lander probably died
575 
576 		SET_GAME_STATE (FOUND_PLUTO_SPATHI, 1);
577 
578 		GenerateDefault_landerReport (solarSys);
579 		SetLanderTakeoff ();
580 
581 		// Do not remove the node from the surface while the lander is
582 		// taking off. FOUND_PLUTO_SPATHI bit will keep the node from
583 		// showing up on subsequent visits.
584 		return false;
585 	}
586 
587 	if (matchWorld (solarSys, world, 2, 1))
588 	{	// Earth Moon
589 		assert (!GET_GAME_STATE (MOONBASE_DESTROYED) && whichNode == 0);
590 
591 		GenerateDefault_landerReport (solarSys);
592 		SetLanderTakeoff ();
593 
594 		SET_GAME_STATE (MOONBASE_DESTROYED, 1);
595 		SET_GAME_STATE (MOONBASE_ON_SHIP, 1);
596 
597 		return true; // picked up
598 	}
599 
600 	(void) whichNode;
601 	return false;
602 }
603 
604 static COUNT
GenerateSol_generateLife(const SOLARSYS_STATE * solarSys,const PLANET_DESC * world,COUNT whichNode,NODE_INFO * info)605 GenerateSol_generateLife (const SOLARSYS_STATE *solarSys,
606 		const PLANET_DESC *world, COUNT whichNode, NODE_INFO *info)
607 {
608 	if (matchWorld (solarSys, world, 2, 1))
609 	{
610 		/* Earth Moon */
611 		return GenerateRandomNodes (&solarSys->SysInfo, BIOLOGICAL_SCAN, 10,
612 				NUM_CREATURE_TYPES + 1, whichNode, info);
613 	}
614 
615 	return 0;
616 }
617 
618 
619 static int
init_probe(void)620 init_probe (void)
621 {
622 	HIPGROUP hGroup;
623 
624 	if (!GET_GAME_STATE (PROBE_MESSAGE_DELIVERED)
625 			&& GetGroupInfo (GLOBAL (BattleGroupRef), GROUP_INIT_IP)
626 			&& (hGroup = GetHeadLink (&GLOBAL (ip_group_q))))
627 	{
628 		IP_GROUP *GroupPtr;
629 
630 		GroupPtr = LockIpGroup (&GLOBAL (ip_group_q), hGroup);
631 		GroupPtr->task = IN_ORBIT;
632 		GroupPtr->sys_loc = 2 + 1; /* orbitting earth */
633 		GroupPtr->dest_loc = 2 + 1; /* orbitting earth */
634 		GroupPtr->loc.x = 0;
635 		GroupPtr->loc.y = 0;
636 		GroupPtr->group_counter = 0;
637 		UnlockIpGroup (&GLOBAL (ip_group_q), hGroup);
638 
639 		return 1;
640 	}
641 	else
642 		return 0;
643 }
644 
645 static void
check_probe(void)646 check_probe (void)
647 {
648 	HIPGROUP hGroup;
649 	IP_GROUP *GroupPtr;
650 
651 	if (!GLOBAL (BattleGroupRef))
652 		return; // nothing to check
653 
654 	hGroup = GetHeadLink (&GLOBAL (ip_group_q));
655 	if (!hGroup)
656 		return; // still nothing to check
657 
658 	GroupPtr = LockIpGroup (&GLOBAL (ip_group_q), hGroup);
659 	// REFORM_GROUP was set in ipdisp.c:ip_group_collision()
660 	// during a collision with the flagship.
661 	if (GroupPtr->race_id == URQUAN_DRONE_SHIP
662 			&& (GroupPtr->task & REFORM_GROUP))
663 	{
664 		// We just want the probe to take off as fast as possible,
665 		// so clear out REFORM_GROUP
666 		GroupPtr->task = FLEE | IGNORE_FLAGSHIP;
667 		GroupPtr->dest_loc = 0;
668 	}
669 	UnlockIpGroup (&GLOBAL (ip_group_q), hGroup);
670 }
671 
672