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 "../../comm.h"
25 #include "../../gendef.h"
26 #include "../../starmap.h"
27 #include "../../globdata.h"
28 #include "../../ipdisp.h"
29 #include "../../nameref.h"
30 #include "../../setup.h"
31 #include "../../sounds.h"
32 #include "../../state.h"
33 #include "libs/mathlib.h"
34 
35 
36 static bool GenerateVux_generatePlanets (SOLARSYS_STATE *solarSys);
37 static bool GenerateVux_generateOrbital (SOLARSYS_STATE *solarSys,
38 		PLANET_DESC *world);
39 static COUNT GenerateVux_generateEnergy (const SOLARSYS_STATE *,
40 		const PLANET_DESC *world, COUNT whichNode, NODE_INFO *);
41 static COUNT GenerateVux_generateLife (const SOLARSYS_STATE *,
42 		const PLANET_DESC *world, COUNT whichNode, NODE_INFO *);
43 static bool GenerateVux_pickupEnergy (SOLARSYS_STATE *, PLANET_DESC *world,
44 		COUNT whichNode);
45 static bool GenerateVux_pickupLife (SOLARSYS_STATE *, PLANET_DESC *world,
46 		COUNT whichNode);
47 
48 
49 const GenerateFunctions generateVuxFunctions = {
50 	/* .initNpcs         = */ GenerateDefault_initNpcs,
51 	/* .reinitNpcs       = */ GenerateDefault_reinitNpcs,
52 	/* .uninitNpcs       = */ GenerateDefault_uninitNpcs,
53 	/* .generatePlanets  = */ GenerateVux_generatePlanets,
54 	/* .generateMoons    = */ GenerateDefault_generateMoons,
55 	/* .generateName     = */ GenerateDefault_generateName,
56 	/* .generateOrbital  = */ GenerateVux_generateOrbital,
57 	/* .generateMinerals = */ GenerateDefault_generateMinerals,
58 	/* .generateEnergy   = */ GenerateVux_generateEnergy,
59 	/* .generateLife     = */ GenerateVux_generateLife,
60 	/* .pickupMinerals   = */ GenerateDefault_pickupMinerals,
61 	/* .pickupEnergy     = */ GenerateVux_pickupEnergy,
62 	/* .pickupLife       = */ GenerateVux_pickupLife,
63 };
64 
65 
66 static bool
GenerateVux_generatePlanets(SOLARSYS_STATE * solarSys)67 GenerateVux_generatePlanets (SOLARSYS_STATE *solarSys)
68 {
69 	COUNT angle;
70 
71 	GenerateDefault_generatePlanets (solarSys);
72 
73 	if (CurStarDescPtr->Index == MAIDENS_DEFINED)
74 	{
75 		GenerateDefault_generatePlanets (solarSys);
76 				// XXX: this is the second time that this function is
77 				// called. Is it safe to remove one, or does this change
78 				// the RNG so that the outcome is different?
79 		solarSys->PlanetDesc[0].data_index = REDUX_WORLD;
80 		solarSys->PlanetDesc[0].radius = EARTH_RADIUS * 212L / 100;
81 		angle = ARCTAN (solarSys->PlanetDesc[0].location.x,
82 				solarSys->PlanetDesc[0].location.y);
83 		solarSys->PlanetDesc[0].location.x =
84 				COSINE (angle, solarSys->PlanetDesc[0].radius);
85 		solarSys->PlanetDesc[0].location.y =
86 				SINE (angle, solarSys->PlanetDesc[0].radius);
87 	}
88 	else
89 	{
90 		if (CurStarDescPtr->Index == VUX_DEFINED)
91 		{
92 			solarSys->PlanetDesc[0].data_index = REDUX_WORLD;
93 			solarSys->PlanetDesc[0].NumPlanets = 1;
94 			solarSys->PlanetDesc[0].radius = EARTH_RADIUS * 42L / 100;
95 			angle = HALF_CIRCLE + OCTANT;
96 		}
97 		else /* if (CurStarDescPtr->Index == VUX_BEAST_DEFINED) */
98 		{
99 			memmove (&solarSys->PlanetDesc[1], &solarSys->PlanetDesc[0],
100 					sizeof (solarSys->PlanetDesc[0])
101 					* solarSys->SunDesc[0].NumPlanets);
102 			++solarSys->SunDesc[0].NumPlanets;
103 
104 			angle = HALF_CIRCLE - OCTANT;
105 			solarSys->PlanetDesc[0].data_index = WATER_WORLD;
106 			solarSys->PlanetDesc[0].radius = EARTH_RADIUS * 110L / 100;
107 			solarSys->PlanetDesc[0].NumPlanets = 0;
108 		}
109 
110 		solarSys->PlanetDesc[0].location.x =
111 				COSINE (angle, solarSys->PlanetDesc[0].radius);
112 		solarSys->PlanetDesc[0].location.y =
113 				SINE (angle, solarSys->PlanetDesc[0].radius);
114 		solarSys->PlanetDesc[0].rand_seed = MAKE_DWORD (
115 				solarSys->PlanetDesc[0].location.x,
116 				solarSys->PlanetDesc[0].location.y);
117 	}
118 	return true;
119 }
120 
121 static bool
GenerateVux_generateOrbital(SOLARSYS_STATE * solarSys,PLANET_DESC * world)122 GenerateVux_generateOrbital (SOLARSYS_STATE *solarSys, PLANET_DESC *world)
123 {
124 	if ((matchWorld (solarSys, world, 0, MATCH_PLANET)
125 			&& (CurStarDescPtr->Index == VUX_DEFINED
126 			|| (CurStarDescPtr->Index == MAIDENS_DEFINED
127 			&& !GET_GAME_STATE (ZEX_IS_DEAD))))
128 			&& StartSphereTracking (VUX_SHIP))
129 	{
130 		NotifyOthers (VUX_SHIP, IPNL_ALL_CLEAR);
131 		PutGroupInfo (GROUPS_RANDOM, GROUP_SAVE_IP);
132 		ReinitQueue (&GLOBAL (ip_group_q));
133 		assert (CountLinks (&GLOBAL (npc_built_ship_q)) == 0);
134 
135 		CloneShipFragment (VUX_SHIP,
136 				&GLOBAL (npc_built_ship_q), INFINITE_FLEET);
137 		if (CurStarDescPtr->Index == VUX_DEFINED)
138 		{
139 			SET_GAME_STATE (GLOBAL_FLAGS_AND_DATA, 1 << 7);
140 		}
141 		else
142 		{
143 			SET_GAME_STATE (GLOBAL_FLAGS_AND_DATA, 1 << 6);
144 		}
145 
146 		GLOBAL (CurrentActivity) |= START_INTERPLANETARY;
147 		InitCommunication (VUX_CONVERSATION);
148 
149 		if (GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_LOAD))
150 			return true;
151 
152 		{
153 			GLOBAL (CurrentActivity) &= ~START_INTERPLANETARY;
154 			ReinitQueue (&GLOBAL (npc_built_ship_q));
155 			GetGroupInfo (GROUPS_RANDOM, GROUP_LOAD_IP);
156 
157 			if (CurStarDescPtr->Index == VUX_DEFINED
158 					|| !GET_GAME_STATE (ZEX_IS_DEAD))
159 				return true;
160 
161 			RepairSISBorder ();
162 		}
163 	}
164 
165 	if (matchWorld (solarSys, world, 0, MATCH_PLANET))
166 	{
167 		if (CurStarDescPtr->Index == MAIDENS_DEFINED)
168 		{
169 			if (!GET_GAME_STATE (SHOFIXTI_MAIDENS))
170 			{
171 				LoadStdLanderFont (&solarSys->SysInfo.PlanetInfo);
172 				solarSys->PlanetSideFrame[1] = CaptureDrawable (
173 						LoadGraphic (MAIDENS_MASK_PMAP_ANIM));
174 				solarSys->SysInfo.PlanetInfo.DiscoveryString =
175 						CaptureStringTable (
176 						LoadStringTable (MAIDENS_STRTAB));
177 			}
178 		}
179 		else if (CurStarDescPtr->Index == VUX_BEAST_DEFINED)
180 		{
181 			if (!GET_GAME_STATE (VUX_BEAST))
182 			{
183 				LoadStdLanderFont (&solarSys->SysInfo.PlanetInfo);
184 				solarSys->PlanetSideFrame[1] = 0;
185 				solarSys->SysInfo.PlanetInfo.DiscoveryString =
186 						CaptureStringTable (
187 						LoadStringTable (BEAST_STRTAB));
188 			}
189 		}
190 		else
191 		{
192 			LoadStdLanderFont (&solarSys->SysInfo.PlanetInfo);
193 			solarSys->PlanetSideFrame[1] =
194 					CaptureDrawable (LoadGraphic (RUINS_MASK_PMAP_ANIM));
195 			solarSys->SysInfo.PlanetInfo.DiscoveryString =
196 					CaptureStringTable (LoadStringTable (RUINS_STRTAB));
197 		}
198 	}
199 
200 	GenerateDefault_generateOrbital (solarSys, world);
201 
202 	if (matchWorld (solarSys, world, 0, MATCH_PLANET))
203 	{
204 		solarSys->SysInfo.PlanetInfo.Weather = 2;
205 		solarSys->SysInfo.PlanetInfo.Tectonics = 0;
206 	}
207 
208 	return true;
209 }
210 
211 static COUNT
GenerateVux_generateEnergy(const SOLARSYS_STATE * solarSys,const PLANET_DESC * world,COUNT whichNode,NODE_INFO * info)212 GenerateVux_generateEnergy (const SOLARSYS_STATE *solarSys,
213 		const PLANET_DESC *world, COUNT whichNode, NODE_INFO *info)
214 {
215 	if (CurStarDescPtr->Index == MAIDENS_DEFINED
216 			&& matchWorld (solarSys, world, 0, MATCH_PLANET))
217 	{
218 		// This check is redundant since the retrieval bit will keep the
219 		// node from showing up again
220 		if (GET_GAME_STATE (SHOFIXTI_MAIDENS))
221 		{	// already picked up
222 			return 0;
223 		}
224 
225 		if (info)
226 		{
227 			info->loc_pt.x = MAP_WIDTH / 3;
228 			info->loc_pt.y = MAP_HEIGHT * 5 / 8;
229 		}
230 
231 		return 1; // only matters when count is requested
232 	}
233 
234 	if (CurStarDescPtr->Index == VUX_DEFINED
235 			&& matchWorld (solarSys, world, 0, MATCH_PLANET))
236 	{
237 		return GenerateDefault_generateRuins (solarSys, whichNode, info);
238 	}
239 
240 	return 0;
241 }
242 
243 static bool
GenerateVux_pickupEnergy(SOLARSYS_STATE * solarSys,PLANET_DESC * world,COUNT whichNode)244 GenerateVux_pickupEnergy (SOLARSYS_STATE *solarSys, PLANET_DESC *world,
245 		COUNT whichNode)
246 {
247 	if (CurStarDescPtr->Index == MAIDENS_DEFINED
248 			&& matchWorld (solarSys, world, 0, MATCH_PLANET))
249 	{
250 		assert (!GET_GAME_STATE (SHOFIXTI_MAIDENS) && whichNode == 0);
251 
252 		GenerateDefault_landerReport (solarSys);
253 		SetLanderTakeoff ();
254 
255 		SET_GAME_STATE (SHOFIXTI_MAIDENS, 1);
256 		SET_GAME_STATE (MAIDENS_ON_SHIP, 1);
257 
258 		return true; // picked up
259 	}
260 
261 	if (CurStarDescPtr->Index == VUX_DEFINED
262 			&& matchWorld (solarSys, world, 0, MATCH_PLANET))
263 	{
264 		// Standard ruins report
265 		GenerateDefault_landerReportCycle (solarSys);
266 		return false;
267 	}
268 
269 	(void) whichNode;
270 	return false;
271 }
272 
273 static COUNT
GenerateVux_generateLife(const SOLARSYS_STATE * solarSys,const PLANET_DESC * world,COUNT whichNode,NODE_INFO * info)274 GenerateVux_generateLife (const SOLARSYS_STATE *solarSys,
275 		const PLANET_DESC *world, COUNT whichNode, NODE_INFO *info)
276 {
277 	if (CurStarDescPtr->Index == MAIDENS_DEFINED
278 			&& matchWorld (solarSys, world, 0, MATCH_PLANET))
279 	{
280 		static const SBYTE life[] =
281 		{
282 			 9,  9,  9,  9, /* Carousel Beast */
283 			14, 14, 14, 14, /* Amorphous Trandicula */
284 			18, 18, 18, 18, /* Penguin Cyclops */
285 			-1 /* term */
286 		};
287 		return GeneratePresetLife (&solarSys->SysInfo, life, whichNode, info);
288 	}
289 
290 	if (CurStarDescPtr->Index == VUX_BEAST_DEFINED
291 			&& matchWorld (solarSys, world, 0, MATCH_PLANET))
292 	{
293 		static const SBYTE life[] =
294 		{
295 			NUM_CREATURE_TYPES + 2, /* VUX Beast */
296 					// Must be the first node, see pickupLife() below
297 			3, 3, 3, 3, 3, /* Whackin' Bush */
298 			8, 8, 8, 8, 8, /* Glowing Medusa */
299 			-1 /* term */
300 		};
301 		return GeneratePresetLife (&solarSys->SysInfo, life, whichNode, info);
302 	}
303 
304 	return GenerateDefault_generateLife (solarSys, world, whichNode, info);
305 }
306 
307 static bool
GenerateVux_pickupLife(SOLARSYS_STATE * solarSys,PLANET_DESC * world,COUNT whichNode)308 GenerateVux_pickupLife (SOLARSYS_STATE *solarSys, PLANET_DESC *world,
309 		COUNT whichNode)
310 {
311 	if (CurStarDescPtr->Index == VUX_BEAST_DEFINED
312 			&& matchWorld (solarSys, world, 0, MATCH_PLANET))
313 	{
314 		if (whichNode == 0)
315 		{	// Picked up Zex' Beauty
316 			assert (!GET_GAME_STATE (VUX_BEAST));
317 
318 			GenerateDefault_landerReport (solarSys);
319 			SetLanderTakeoff ();
320 
321 			SET_GAME_STATE (VUX_BEAST, 1);
322 			SET_GAME_STATE (VUX_BEAST_ON_SHIP, 1);
323 		}
324 
325 		return true; // picked up
326 	}
327 
328 	return GenerateDefault_pickupLife (solarSys, world, whichNode);
329 }
330