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 "globdata.h"
20 
21 #include "coderes.h"
22 #include "encount.h"
23 #include "starmap.h"
24 #include "master.h"
25 #include "setup.h"
26 #include "units.h"
27 #include "hyper.h"
28 #include "resinst.h"
29 #include "nameref.h"
30 #include "build.h"
31 #include "state.h"
32 #include "grpinfo.h"
33 #include "gamestr.h"
34 
35 #include <assert.h>
36 #include <stdlib.h>
37 #ifdef STATE_DEBUG
38 #	include "libs/log.h"
39 #endif
40 
41 
42 static void CreateRadar (void);
43 
44 CONTEXT RadarContext;
45 FRAME PlayFrame;
46 
47 GLOBDATA GlobData;
48 
49 
50 BYTE
getGameState(BYTE * state,int startBit,int endBit)51 getGameState (BYTE *state, int startBit, int endBit)
52 {
53 	return (BYTE) (((startBit >> 3) == (endBit >> 3)
54 			? (state[startBit >> 3] >> (startBit & 7))
55 			: ((state[startBit >> 3] >> (startBit & 7))
56 			  | (state[endBit >> 3]
57 			  << (endBit - startBit - (endBit & 7)))))
58 			& ((1 << (endBit - startBit + 1)) - 1));
59 }
60 
61 void
setGameState(BYTE * state,int startBit,int endBit,BYTE val,const char * name)62 setGameState (BYTE *state, int startBit, int endBit, BYTE val
63 #ifdef STATE_DEBUG
64 		, const char *name
65 #endif
66 )
67 {
68 	state[startBit >> 3] =
69 			(state[startBit >> 3]
70 			& (BYTE) ~(((1 << (endBit - startBit + 1)) - 1) << (startBit & 7)))
71 			| (BYTE)((val) << (startBit & 7));
72 
73 	if ((startBit >> 3) < (endBit >> 3)) {
74 		state[endBit >> 3] =
75 				(state[endBit >> 3]
76 				& (BYTE)~((1 << ((endBit & 7) + 1)) - 1))
77 				| (BYTE)((val) >> (endBit - startBit - (endBit & 7)));
78 	}
79 #ifdef STATE_DEBUG
80 	log_add (log_Debug, "State '%s' set to %d.", name, (int)val);
81 #endif
82 }
83 
84 DWORD
getGameState32(BYTE * state,int startBit)85 getGameState32 (BYTE *state, int startBit)
86 {
87 	DWORD v;
88 	int shift;
89 
90 	for (v = 0, shift = 0; shift < 32; shift += 8, startBit += 8)
91 	{
92 		v |= getGameState (state, startBit, startBit + 7) << shift;
93 	}
94 
95 	return v;
96 }
97 
98 void
setGameState32(BYTE * state,int startBit,DWORD val,const char * name)99 setGameState32 (BYTE *state, int startBit, DWORD val
100 #ifdef STATE_DEBUG
101 		, const char *name
102 #endif
103 )
104 {
105 	DWORD v = val;
106 	int i;
107 
108 	for (i = 0; i < 4; ++i, v >>= 8, startBit += 8)
109 	{
110 		setGameState (state, startBit, startBit + 7, v & 0xff
111 #ifdef STATE_DEBUG
112 				, "(ignored)"
113 #endif
114 				);
115 	}
116 
117 #ifdef STATE_DEBUG
118 	log_add (log_Debug, "State '%s' set to %u.", name, (unsigned)val);
119 #endif
120 }
121 
122 void
copyGameState(BYTE * dest,DWORD target,BYTE * src,DWORD begin,DWORD end)123 copyGameState (BYTE *dest, DWORD target, BYTE *src, DWORD begin, DWORD end)
124 {
125 	while (begin < end)
126 	{
127 		BYTE b;
128 		DWORD delta = 7;
129 		if (begin + delta > end)
130 			delta = end - begin;
131 		b = getGameState (src, begin, begin + delta);
132 		setGameState (dest, target, target + delta, b);
133 		begin += 8;
134 		target += 8;
135 	}
136 }
137 
138 static void
CreateRadar(void)139 CreateRadar (void)
140 {
141 	if (RadarContext == 0)
142 	{
143 		RECT r;
144 		CONTEXT OldContext;
145 
146 		RadarContext = CreateContext ("RadarContext");
147 		OldContext = SetContext (RadarContext);
148 		SetContextFGFrame (Screen);
149 		r.corner.x = RADAR_X;
150 		r.corner.y = RADAR_Y;
151 		r.extent.width = RADAR_WIDTH;
152 		r.extent.height = RADAR_HEIGHT;
153 		SetContextClipRect (&r);
154 		SetContext (OldContext);
155 	}
156 }
157 
158 BOOLEAN
LoadSC2Data(void)159 LoadSC2Data (void)
160 {
161 	if (FlagStatFrame == 0)
162 	{
163 		FlagStatFrame = CaptureDrawable (
164 				LoadGraphic (FLAGSTAT_MASK_PMAP_ANIM));
165 		if (FlagStatFrame == NULL)
166 			return FALSE;
167 
168 		MiscDataFrame = CaptureDrawable (
169 				LoadGraphic (MISCDATA_MASK_PMAP_ANIM));
170 		if (MiscDataFrame == NULL)
171 			return FALSE;
172 
173 		FontGradFrame = CaptureDrawable (
174 				LoadGraphic (FONTGRAD_PMAP_ANIM));
175 	}
176 
177 	CreateRadar ();
178 
179 	if (LOBYTE (GLOBAL (CurrentActivity)) == IN_HYPERSPACE)
180 	{
181 		GLOBAL (ShipStamp.origin.x) =
182 				GLOBAL (ShipStamp.origin.y) = -1;
183 	}
184 
185 	return TRUE;
186 }
187 
188 static void
copyFleetInfo(FLEET_INFO * dst,SHIP_INFO * src,FLEET_STUFF * fleet)189 copyFleetInfo (FLEET_INFO *dst, SHIP_INFO *src, FLEET_STUFF *fleet)
190 {
191 	// other leading fields are irrelevant
192 	dst->crew_level = src->crew_level;
193 	dst->max_crew = src->max_crew;
194 	dst->max_energy = src->max_energy;
195 
196 	dst->race_strings = src->race_strings;
197 	dst->icons = src->icons;
198 	dst->melee_icon = src->melee_icon;
199 
200 	dst->actual_strength = fleet->strength;
201 	dst->known_loc = fleet->known_loc;
202 }
203 
204 BOOLEAN
InitGameStructures(void)205 InitGameStructures (void)
206 {
207 	COUNT i;
208 
209 	InitGlobData ();
210 
211 	PlayFrame = CaptureDrawable (LoadGraphic (PLAYMENU_ANIM));
212 
213 	{
214 		COUNT num_ships;
215 		SPECIES_ID s_id = ARILOU_ID;
216 
217 		num_ships = KOHR_AH_ID - s_id + 1
218 				+ 2; /* Yehat Rebels and Ur-Quan probe */
219 
220 		InitQueue (&GLOBAL (avail_race_q), num_ships, sizeof (FLEET_INFO));
221 		for (i = 0; i < num_ships; ++i)
222 		{
223 			SPECIES_ID ship_ref;
224 			HFLEETINFO hFleet;
225 			FLEET_INFO *FleetPtr;
226 
227 			if (i < num_ships - 2)
228 				ship_ref = s_id++;
229 			else if (i == num_ships - 2)
230 				ship_ref = YEHAT_ID;
231 			else  /* (i == num_ships - 1) */
232 				ship_ref = UR_QUAN_PROBE_ID;
233 
234 			hFleet = AllocLink (&GLOBAL (avail_race_q));
235 			if (!hFleet)
236 				continue;
237 			FleetPtr = LockFleetInfo (&GLOBAL (avail_race_q), hFleet);
238 			FleetPtr->SpeciesID = ship_ref;
239 
240 			if (i < num_ships - 1)
241 			{
242 				HMASTERSHIP hMasterShip;
243 				MASTER_SHIP_INFO *MasterPtr;
244 
245 				hMasterShip = FindMasterShip (ship_ref);
246 				MasterPtr = LockMasterShip (&master_q, hMasterShip);
247 				// Grab a copy of loaded icons and strings (not owned)
248 				copyFleetInfo (FleetPtr, &MasterPtr->ShipInfo,
249 						&MasterPtr->Fleet);
250 				UnlockMasterShip (&master_q, hMasterShip);
251 			}
252 			else
253 			{
254 				// Ur-Quan probe.
255 				RACE_DESC *RDPtr = load_ship (FleetPtr->SpeciesID,
256 						FALSE);
257 				if (RDPtr)
258 				{	// Grab a copy of loaded icons and strings
259 					copyFleetInfo (FleetPtr, &RDPtr->ship_info,
260 							&RDPtr->fleet);
261 					// avail_race_q owns these resources now
262 					free_ship (RDPtr, FALSE, FALSE);
263 				}
264 			}
265 
266 			FleetPtr->allied_state = BAD_GUY;
267 			FleetPtr->known_strength = 0;
268 			FleetPtr->loc = FleetPtr->known_loc;
269 			// XXX: Hack: Rebel special case
270 			if (i == YEHAT_REBEL_SHIP)
271 				FleetPtr->actual_strength = 0;
272 			FleetPtr->growth = 0;
273 			FleetPtr->growth_fract = 0;
274 			FleetPtr->growth_err_term = 255 >> 1;
275 			FleetPtr->days_left = 0;
276 			FleetPtr->func_index = ~0;
277 
278 			UnlockFleetInfo (&GLOBAL (avail_race_q), hFleet);
279 			PutQueue (&GLOBAL (avail_race_q), hFleet);
280 		}
281 	}
282 
283 	InitSISContexts ();
284 	LoadSC2Data ();
285 
286 	InitPlanetInfo ();
287 	InitGroupInfo (TRUE);
288 
289 	GLOBAL (glob_flags) = 0;
290 
291 	GLOBAL (ElementWorth[COMMON]) = 1;
292 	GLOBAL_SIS (ElementAmounts[COMMON]) = 0;
293 	GLOBAL (ElementWorth[CORROSIVE]) = 2;
294 	GLOBAL_SIS (ElementAmounts[CORROSIVE]) = 0;
295 	GLOBAL (ElementWorth[BASE_METAL]) = 3;
296 	GLOBAL_SIS (ElementAmounts[BASE_METAL]) = 0;
297 	GLOBAL (ElementWorth[NOBLE]) = 4;
298 	GLOBAL_SIS (ElementAmounts[NOBLE]) = 0;
299 	GLOBAL (ElementWorth[RARE_EARTH]) = 5;
300 	GLOBAL_SIS (ElementAmounts[RARE_EARTH]) = 0;
301 	GLOBAL (ElementWorth[PRECIOUS]) = 6;
302 	GLOBAL_SIS (ElementAmounts[PRECIOUS]) = 0;
303 	GLOBAL (ElementWorth[RADIOACTIVE]) = 8;
304 	GLOBAL_SIS (ElementAmounts[RADIOACTIVE]) = 0;
305 	GLOBAL (ElementWorth[EXOTIC]) = 25;
306 	GLOBAL_SIS (ElementAmounts[EXOTIC]) = 0;
307 
308 	for (i = 0; i < NUM_DRIVE_SLOTS; ++i)
309 		GLOBAL_SIS (DriveSlots[i]) = EMPTY_SLOT + 0;
310 	GLOBAL_SIS (DriveSlots[5]) =
311 			GLOBAL_SIS (DriveSlots[6]) = FUSION_THRUSTER;
312 	for (i = 0; i < NUM_JET_SLOTS; ++i)
313 		GLOBAL_SIS (JetSlots[i]) = EMPTY_SLOT + 1;
314 	GLOBAL_SIS (JetSlots[0]) =
315 			GLOBAL_SIS (JetSlots[6]) = TURNING_JETS;
316 	for (i = 0; i < NUM_MODULE_SLOTS; ++i)
317 		GLOBAL_SIS (ModuleSlots[i]) = EMPTY_SLOT + 2;
318 	GLOBAL_SIS (ModuleSlots[15]) = GUN_WEAPON;
319 	GLOBAL_SIS (ModuleSlots[2]) = CREW_POD;
320 	GLOBAL_SIS (CrewEnlisted) = CREW_POD_CAPACITY;
321 	GLOBAL_SIS (ModuleSlots[8]) = STORAGE_BAY;
322 	GLOBAL_SIS (ModuleSlots[1]) = FUEL_TANK;
323 	GLOBAL_SIS (FuelOnBoard) = 10 * FUEL_TANK_SCALE;
324 
325 	InitQueue (&GLOBAL (built_ship_q),
326 			MAX_BUILT_SHIPS, sizeof (SHIP_FRAGMENT));
327 	InitQueue (&GLOBAL (npc_built_ship_q), MAX_SHIPS_PER_SIDE,
328 			sizeof (SHIP_FRAGMENT));
329 	InitQueue (&GLOBAL (ip_group_q), MAX_BATTLE_GROUPS,
330 			sizeof (IP_GROUP));
331 	InitQueue (&GLOBAL (encounter_q), MAX_ENCOUNTERS, sizeof (ENCOUNTER));
332 
333 	GLOBAL (CurrentActivity) = IN_INTERPLANETARY | START_INTERPLANETARY;
334 
335 	GLOBAL_SIS (ResUnits) = 0;
336 	GLOBAL (CrewCost) = 3;
337 	GLOBAL (FuelCost) = 20;
338 	GLOBAL (ModuleCost[PLANET_LANDER]) = 500 / MODULE_COST_SCALE;
339 	GLOBAL (ModuleCost[FUSION_THRUSTER]) = 500 / MODULE_COST_SCALE;
340 	GLOBAL (ModuleCost[TURNING_JETS]) = 500 / MODULE_COST_SCALE;
341 	GLOBAL (ModuleCost[CREW_POD]) = 2000 / MODULE_COST_SCALE;
342 	GLOBAL (ModuleCost[STORAGE_BAY]) = 750 / MODULE_COST_SCALE;
343 	GLOBAL (ModuleCost[FUEL_TANK]) = 500 / MODULE_COST_SCALE;
344 	GLOBAL (ModuleCost[DYNAMO_UNIT]) = 2000 / MODULE_COST_SCALE;
345 	GLOBAL (ModuleCost[GUN_WEAPON]) = 2000 / MODULE_COST_SCALE;
346 
347 	GLOBAL_SIS (NumLanders) = 1;
348 
349 	utf8StringCopy (GLOBAL_SIS (ShipName), sizeof (GLOBAL_SIS (ShipName)),
350 			GAME_STRING (NAMING_STRING_BASE + 2));
351 	utf8StringCopy (GLOBAL_SIS (CommanderName),
352 			sizeof (GLOBAL_SIS (CommanderName)),
353 			GAME_STRING (NAMING_STRING_BASE + 3));
354 
355 	SetRaceAllied (HUMAN_SHIP, TRUE);
356 	CloneShipFragment (HUMAN_SHIP, &GLOBAL (built_ship_q), 0);
357 
358 	GLOBAL_SIS (log_x) = UNIVERSE_TO_LOGX (SOL_X);
359 	GLOBAL_SIS (log_y) = UNIVERSE_TO_LOGY (SOL_Y);
360 	CurStarDescPtr = 0;
361 	GLOBAL (autopilot.x) = ~0;
362 	GLOBAL (autopilot.y) = ~0;
363 
364 	return (TRUE);
365 }
366 
367 void
FreeSC2Data(void)368 FreeSC2Data (void)
369 {
370 	DestroyContext (RadarContext);
371 	RadarContext = 0;
372 	DestroyDrawable (ReleaseDrawable (FontGradFrame));
373 	FontGradFrame = 0;
374 	DestroyDrawable (ReleaseDrawable (MiscDataFrame));
375 	MiscDataFrame = 0;
376 	DestroyDrawable (ReleaseDrawable (FlagStatFrame));
377 	FlagStatFrame = 0;
378 }
379 
380 void
UninitGameStructures(void)381 UninitGameStructures (void)
382 {
383 	HFLEETINFO hStarShip;
384 
385 	UninitQueue (&GLOBAL (encounter_q));
386 	UninitQueue (&GLOBAL (ip_group_q));
387 	UninitQueue (&GLOBAL (npc_built_ship_q));
388 	UninitQueue (&GLOBAL (built_ship_q));
389 	UninitGroupInfo ();
390 	UninitPlanetInfo ();
391 
392 //    FreeSC2Data ();
393 
394 	// The only resources avail_race_q owns are the Ur-Quan probe's
395 	// so free them now
396 	hStarShip = GetTailLink (&GLOBAL (avail_race_q));
397 	if (hStarShip)
398 	{
399 		FLEET_INFO *FleetPtr;
400 
401 		FleetPtr = LockFleetInfo (&GLOBAL (avail_race_q), hStarShip);
402 		DestroyDrawable (ReleaseDrawable (FleetPtr->melee_icon));
403 		DestroyDrawable (ReleaseDrawable (FleetPtr->icons));
404 		DestroyStringTable (ReleaseStringTable (FleetPtr->race_strings));
405 		UnlockFleetInfo (&GLOBAL (avail_race_q), hStarShip);
406 	}
407 
408 	UninitQueue (&GLOBAL (avail_race_q));
409 
410 	DestroyDrawable (ReleaseDrawable (PlayFrame));
411 	PlayFrame = 0;
412 }
413 
414 void
InitGlobData(void)415 InitGlobData (void)
416 {
417 	COUNT i;
418 
419 	i = GLOBAL (glob_flags);
420 	memset (&GlobData, 0, sizeof (GlobData));
421 	GLOBAL (glob_flags) = (BYTE)i;
422 
423 	GLOBAL (DisplayArray) = DisplayArray;
424 }
425 
426 
427 BOOLEAN
inFullGame(void)428 inFullGame (void)
429 {
430 	ACTIVITY act = LOBYTE (GLOBAL (CurrentActivity));
431 	return (act == IN_LAST_BATTLE || act == IN_ENCOUNTER ||
432 			act == IN_HYPERSPACE || act == IN_INTERPLANETARY ||
433 			act == WON_LAST_BATTLE);
434 }
435 
436 BOOLEAN
inSuperMelee(void)437 inSuperMelee (void)
438 {
439 	return (LOBYTE (GLOBAL (CurrentActivity)) == SUPER_MELEE);
440 			// TODO: && !inMainMenu ()
441 }
442 
443 #if 0
444 BOOLEAN
445 inBattle (void)
446 {
447 	// TODO: IN_BATTLE is also set while in HyperSpace/QuasiSpace.
448 	return ((GLOBAL (CurrentActivity) & IN_BATTLE) != 0);
449 }
450 #endif
451 
452 #if 0
453 // Disabled for now as there are similar functions in uqm/planets/planets.h
454 // Pre: inFullGame()
455 BOOLEAN
456 inInterPlanetary (void)
457 {
458 	assert (inFullGame ());
459 	return (pSolarSysState != NULL);
460 }
461 
462 // Pre: inFullGame()
463 BOOLEAN
464 inSolarSystem (void)
465 {
466 	assert (inFullGame ());
467 	return (LOBYTE (GLOBAL (CurrentActivity)) == IN_INTERPLANETARY);
468 }
469 
470 // Pre: inFullGame()
471 BOOLEAN
472 inOrbit (void)
473 {
474 	assert (inFullGame ());
475 	return (pSolarSysState != NULL) &&
476 			(pSolarSysState->pOrbitalDesc != NULL);
477 }
478 #endif
479 
480 // In HyperSpace or QuasiSpace
481 // Pre: inFullGame()
482 BOOLEAN
inHQSpace(void)483 inHQSpace (void)
484 {
485 	//assert (inFullGame ());
486 	return (LOBYTE (GLOBAL (CurrentActivity)) == IN_HYPERSPACE);
487 			// IN_HYPERSPACE is also set for QuasiSpace
488 }
489 
490 // In HyperSpace
491 // Pre: inFullGame()
492 BOOLEAN
inHyperSpace(void)493 inHyperSpace (void)
494 {
495 	//assert (inFullGame ());
496 	return (LOBYTE (GLOBAL (CurrentActivity)) == IN_HYPERSPACE) &&
497 				(GET_GAME_STATE (ARILOU_SPACE_SIDE) <= 1);
498 			// IN_HYPERSPACE is also set for QuasiSpace
499 }
500 
501 // In QuasiSpace
502 // Pre: inFullGame()
503 BOOLEAN
inQuasiSpace(void)504 inQuasiSpace (void)
505 {
506 	//assert (inFullGame ());
507 	return (LOBYTE (GLOBAL (CurrentActivity)) == IN_HYPERSPACE) &&
508 				(GET_GAME_STATE (ARILOU_SPACE_SIDE) > 1);
509 			// IN_HYPERSPACE is also set for QuasiSpace
510 }
511 
512