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 "encount.h"
20 
21 #include "battle.h"
22 #include "battlecontrols.h"
23 #include "build.h"
24 #include "colors.h"
25 #include "starmap.h"
26 #include "cons_res.h"
27 #include "controls.h"
28 #include "menustat.h"
29 #include "gameopt.h"
30 #include "gamestr.h"
31 #include "globdata.h"
32 #include "sis.h"
33 		// for DrawStatusMessage(), SetStatusMessageMode()
34 #include "init.h"
35 #include "pickship.h"
36 #include "intel.h"
37 #include "nameref.h"
38 #include "resinst.h"
39 #include "settings.h"
40 #include "setup.h"
41 #include "sounds.h"
42 #include "libs/graphics/gfx_common.h"
43 #include "libs/log.h"
44 #include "libs/mathlib.h"
45 #include "libs/inplib.h"
46 #include "libs/misc.h"
47 
48 
49 static void DrawFadeText (const UNICODE *str1, const UNICODE *str2,
50 		BOOLEAN fade_in, RECT *pRect);
51 
52 
53 static BOOLEAN
DoSelectAction(MENU_STATE * pMS)54 DoSelectAction (MENU_STATE *pMS)
55 {
56 	SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT);
57 	if (GLOBAL (CurrentActivity) & CHECK_ABORT)
58 	{
59 		pMS->CurState = ATTACK + 1;
60 		return (FALSE);
61 	}
62 	if (!pMS->Initialized)
63 	{
64 		pMS->Initialized = TRUE;
65 		pMS->InputFunc = DoSelectAction;
66 	}
67 	else if (PulsedInputState.menu[KEY_MENU_SELECT])
68 	{
69 		switch (pMS->CurState)
70 		{
71 			case HAIL:
72 			case ATTACK:
73 				if (LOBYTE (GLOBAL (CurrentActivity)) == IN_LAST_BATTLE)
74 					pMS->CurState = HAIL;
75 				return (FALSE);
76 			case ATTACK + 1:
77 				// Clearing FlashRect is not necessary
78 				if (!GameOptions ())
79 					return FALSE;
80 				DrawMenuStateStrings (PM_CONVERSE, pMS->CurState);
81 				SetFlashRect (SFR_MENU_3DO);
82 				break;
83 			default:
84 				printf ("Unknown option: %d\n", pMS->CurState);
85 		}
86 	}
87 	DoMenuChooser (pMS, PM_CONVERSE);
88 	return (TRUE);
89 }
90 
91 static QUEUE *
GetShipFragQueueForPlayer(COUNT playerNr)92 GetShipFragQueueForPlayer (COUNT playerNr)
93 {
94 	if (playerNr == RPG_PLAYER_NUM)
95 		return &GLOBAL (built_ship_q);
96 	else
97 		return &GLOBAL (npc_built_ship_q);
98 }
99 
100 // Called by comm code to intialize battle fleets during encounter
101 void
BuildBattle(COUNT which_player)102 BuildBattle (COUNT which_player)
103 {
104 	QUEUE *pQueue;
105 	HSHIPFRAG hStarShip, hNextShip;
106 	HSTARSHIP hBuiltShip;
107 	STARSHIP *BuiltShipPtr;
108 
109 	EncounterRace = -1;
110 
111 	if (GetHeadLink (&GLOBAL (npc_built_ship_q)) == 0)
112 	{
113 		SET_GAME_STATE (BATTLE_SEGUE, 0);
114 		return;
115 	}
116 
117 	if (which_player != RPG_PLAYER_NUM)
118 	{	// This function is called first for the NPC character
119 		// and this is when a centerpiece is loaded
120 		switch (LOBYTE (GLOBAL (CurrentActivity)))
121 		{
122 			case IN_LAST_BATTLE:
123 				load_gravity_well (NUMBER_OF_PLANET_TYPES);
124 				break;
125 			case IN_HYPERSPACE:
126 				load_gravity_well ((BYTE)((COUNT)TFB_Random ()
127 						% NUMBER_OF_PLANET_TYPES));
128 				break;
129 			default:
130 				SET_GAME_STATE (ESCAPE_COUNTER, 110);
131 				load_gravity_well (GET_GAME_STATE (BATTLE_PLANET));
132 				break;
133 		}
134 	}
135 	pQueue = GetShipFragQueueForPlayer (which_player);
136 
137 	ReinitQueue (&race_q[which_player]);
138 	for (hStarShip = GetHeadLink (pQueue);
139 			hStarShip != 0; hStarShip = hNextShip)
140 	{
141 		SHIP_FRAGMENT *FragPtr;
142 
143 		FragPtr = LockShipFrag (pQueue, hStarShip);
144 		hNextShip = _GetSuccLink (FragPtr);
145 
146 		hBuiltShip = Build (&race_q[which_player],
147 				FragPtr->race_id == SAMATRA_SHIP ?
148 					SA_MATRA_ID : FragPtr->SpeciesID);
149 		if (hBuiltShip)
150 		{
151 			BuiltShipPtr = LockStarShip (&race_q[which_player], hBuiltShip);
152 			BuiltShipPtr->captains_name_index = FragPtr->captains_name_index;
153 			BuiltShipPtr->playerNr = which_player;
154 			if (FragPtr->crew_level != INFINITE_FLEET)
155 				BuiltShipPtr->crew_level = FragPtr->crew_level;
156 			else /* if infinite ships */
157 				BuiltShipPtr->crew_level = FragPtr->max_crew;
158 			BuiltShipPtr->max_crew = FragPtr->max_crew;
159 			BuiltShipPtr->race_strings = FragPtr->race_strings;
160 			BuiltShipPtr->icons = FragPtr->icons;
161 			BuiltShipPtr->index = FragPtr->index;
162 			BuiltShipPtr->ship_cost = 0;
163 			BuiltShipPtr->RaceDescPtr = 0;
164 
165 			UnlockStarShip (&race_q[which_player], hBuiltShip);
166 		}
167 
168 		UnlockShipFrag (pQueue, hStarShip);
169 	}
170 
171 	if (which_player == RPG_PLAYER_NUM
172 			&& (hBuiltShip = Build (&race_q[0], SIS_SHIP_ID)))
173 	{
174 		BuiltShipPtr = LockStarShip (&race_q[0], hBuiltShip);
175 		BuiltShipPtr->captains_name_index = 0;
176 		BuiltShipPtr->playerNr = RPG_PLAYER_NUM;
177 		BuiltShipPtr->crew_level = 0;
178 		BuiltShipPtr->max_crew = 0;
179 				// Crew will be copied directly from
180 				// GLOBAL_SIS (CrewEnlisted) later.
181 		BuiltShipPtr->race_strings = 0;
182 		BuiltShipPtr->icons = 0;
183 		BuiltShipPtr->index = -1;
184 		BuiltShipPtr->ship_cost = 0;
185 		BuiltShipPtr->energy_counter = MAX_ENERGY_SIZE;
186 		BuiltShipPtr->RaceDescPtr = 0;
187 		UnlockStarShip (&race_q[0], hBuiltShip);
188 	}
189 }
190 
191 BOOLEAN
FleetIsInfinite(COUNT playerNr)192 FleetIsInfinite (COUNT playerNr)
193 {
194 	QUEUE *pQueue;
195 	HSHIPFRAG hShipFrag;
196 	SHIP_FRAGMENT *FragPtr;
197 	BOOLEAN ret;
198 
199 	pQueue = GetShipFragQueueForPlayer (playerNr);
200 	hShipFrag = GetHeadLink (pQueue);
201 	if (!hShipFrag)
202 	{	// Ship queue is empty in SuperMelee or for RPG player w/o escorts
203 		return FALSE;
204 	}
205 
206 	FragPtr = LockShipFrag (pQueue, hShipFrag);
207 	ret = (FragPtr->crew_level == INFINITE_FLEET);
208 	UnlockShipFrag (pQueue, hShipFrag);
209 
210 	return ret;
211 }
212 
213 void
UpdateShipFragCrew(STARSHIP * StarShipPtr)214 UpdateShipFragCrew (STARSHIP *StarShipPtr)
215 {
216 	QUEUE *frag_q;
217 	HSHIPFRAG hShipFrag, hNextFrag;
218 	SHIP_FRAGMENT *frag;
219 	QUEUE *ship_q;
220 	HSTARSHIP hStarShip, hNextShip;
221 	STARSHIP *ship;
222 
223 	frag_q = GetShipFragQueueForPlayer (StarShipPtr->playerNr);
224 	ship_q = &race_q[StarShipPtr->playerNr];
225 
226 	// Find a SHIP_FRAGMENT that corresponds to the given STARSHIP
227 	// The ships and fragments are in the same order in two queues
228 	// XXX: It would probably be simpler to keep HSHIPFRAG in STARSHIP struct
229 	for (hShipFrag = GetHeadLink (frag_q), hStarShip = GetHeadLink (ship_q);
230 			hShipFrag != 0 && hStarShip != 0;
231 			hShipFrag = hNextFrag, hStarShip = hNextShip)
232 	{
233 		ship = LockStarShip (ship_q, hStarShip);
234 		hNextShip = _GetSuccLink (ship);
235 		frag = LockShipFrag (frag_q, hShipFrag);
236 		hNextFrag = _GetSuccLink (frag);
237 
238 		if (ship == StarShipPtr)
239 		{
240 			assert (frag->crew_level != INFINITE_FLEET);
241 
242 			// Record crew left after the battle */
243 			frag->crew_level = ship->crew_level;
244 
245 			UnlockShipFrag (frag_q, hShipFrag);
246 			UnlockStarShip (ship_q, hStarShip);
247 			break;
248 		}
249 
250 		UnlockShipFrag (frag_q, hShipFrag);
251 		UnlockStarShip (ship_q, hStarShip);
252 	}
253 }
254 
255 /*
256  * Encountering an alien.
257  * Draws the encounter screen, plays the red alert music, and
258  * waits for a decision of the player on how to handle the situation.
259  * Returns either HAIL or ATTACK.
260  */
261 COUNT
InitEncounter(void)262 InitEncounter (void)
263 {
264 	COUNT i;
265 	FRAME SegueFrame;
266 	STAMP s;
267 	TEXT t;
268 	extern FRAME planet[];
269 	MUSIC_REF MR;
270 
271 
272 	SetContext (SpaceContext);
273 	SetContextFont (TinyFont);
274 
275 	MR = LoadMusic (REDALERT_MUSIC);
276 	PlayMusic (MR, FALSE, 1);
277 	SegueFrame = CaptureDrawable (LoadGraphic (SEGUE_PMAP_ANIM));
278 	WaitForSoundEnd (TFBSOUND_WAIT_ALL);
279 	StopMusic ();
280 	DestroyMusic (MR);
281 	s.origin.x = s.origin.y = 0;
282 
283 	SetTransitionSource (NULL);
284 	BatchGraphics ();
285 
286 	SetContextBackGroundColor (BLACK_COLOR);
287 	ClearDrawable ();
288 	s.frame = SegueFrame;
289 	DrawStamp (&s);
290 
291 //    t.baseline.x = SIS_SCREEN_WIDTH >> 1;
292 	t.baseline.x = (SIS_SCREEN_WIDTH >> 1) + 1;
293 	t.baseline.y = 10;
294 	t.align = ALIGN_CENTER;
295 
296 	SetContextFont (MicroFont);
297 	SetContextForeGroundColor (
298 			BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x14), 0x01));
299 	if (inHQSpace ())
300 	{
301 		t.pStr = GAME_STRING (ENCOUNTER_STRING_BASE + 0);
302 				// "ENCOUNTER IN"
303 		t.CharCount = (COUNT)~0;
304 		font_DrawText (&t);
305 		t.baseline.y += 12;
306 		t.pStr = GAME_STRING (ENCOUNTER_STRING_BASE + 1);
307 				// "DEEP SPACE"
308 		t.CharCount = (COUNT)~0;
309 		font_DrawText (&t);
310 	}
311 	else
312 	{
313 		UNICODE buf[256];
314 
315 		t.pStr = GAME_STRING (ENCOUNTER_STRING_BASE + 2);
316 				// "ENCOUNTER AT"
317 		t.CharCount = (COUNT)~0;
318 		font_DrawText (&t);
319 		t.baseline.y += 12;
320 		GetClusterName (CurStarDescPtr, buf);
321 		t.pStr = buf;
322 		t.CharCount = (COUNT)~0;
323 		font_DrawText (&t);
324 		t.baseline.y += 12;
325 		t.pStr = GLOBAL_SIS (PlanetName);
326 		t.CharCount = (COUNT)~0;
327 		font_DrawText (&t);
328 	}
329 	DrawSISMessage (NULL);
330 
331 	s.origin.x = SIS_SCREEN_WIDTH >> 1;
332 	s.origin.y = SIS_SCREEN_HEIGHT >> 1;
333 	s.frame = planet[0];
334 	DrawStamp (&s);
335 
336 	if (LOBYTE (GLOBAL (CurrentActivity)) != IN_LAST_BATTLE)
337 	{
338 #define NUM_DISPLAY_PTS (sizeof (display_pt) / sizeof (display_pt[0]))
339 		HSHIPFRAG hStarShip, hNextShip;
340 		POINT display_pt[] =
341 		{
342 			{ 10,  51},
343 			{-10,  51},
344 			{ 33,  40},
345 			{-33,  40},
346 			{ 49,  18},
347 			{-49,  18},
348 			{ 52,  -6},
349 			{-52,  -6},
350 			{ 44, -27},
351 			{-44, -27},
352 		};
353 
354 		for (hStarShip = GetHeadLink (&GLOBAL (npc_built_ship_q)), i = 0;
355 				hStarShip && i < 60; hStarShip = hNextShip, ++i)
356 		{
357 			RECT r;
358 			SHIP_FRAGMENT *FragPtr;
359 
360 			FragPtr = LockShipFrag (&GLOBAL (npc_built_ship_q), hStarShip);
361 			if (FragPtr->crew_level != INFINITE_FLEET)
362 				hNextShip = _GetSuccLink (FragPtr);
363 			else /* if infinite ships */
364 				hNextShip = hStarShip;
365 
366 			s.origin = display_pt[i % NUM_DISPLAY_PTS];
367 			if (i >= NUM_DISPLAY_PTS)
368 			{
369 				COUNT angle, radius;
370 
371 				radius = square_root ((long)s.origin.x * s.origin.x
372 						+ (long)s.origin.y * s.origin.y)
373 						+ ((i / NUM_DISPLAY_PTS) * 18);
374 
375 				angle = ARCTAN (s.origin.x, s.origin.y);
376 				s.origin.x = COSINE (angle, radius);
377 				s.origin.y = SINE (angle, radius);
378 			}
379 			s.frame = SetAbsFrameIndex (FragPtr->icons, 0);
380 			GetFrameRect (s.frame, &r);
381 			s.origin.x += (SIS_SCREEN_WIDTH >> 1) - (r.extent.width >> 1);
382 			s.origin.y += (SIS_SCREEN_HEIGHT >> 1) - (r.extent.height >> 1);
383 			DrawStamp (&s);
384 
385 			UnlockShipFrag (&GLOBAL (npc_built_ship_q), hStarShip);
386 		}
387 	}
388 
389 	UnbatchGraphics ();
390 	DestroyDrawable (ReleaseDrawable (SegueFrame));
391 	ScreenTransition (3, NULL);
392 
393 
394 	{
395 		MENU_STATE MenuState;
396 
397 		MenuState.InputFunc = DoSelectAction;
398 		MenuState.Initialized = FALSE;
399 
400 		DrawMenuStateStrings (PM_CONVERSE, MenuState.CurState = HAIL);
401 		SetFlashRect (SFR_MENU_3DO);
402 
403 		DoInput (&MenuState, TRUE);
404 
405 		SetFlashRect (NULL);
406 
407 		return (MenuState.CurState);
408 	}
409 }
410 
411 static void
DrawFadeText(const UNICODE * str1,const UNICODE * str2,BOOLEAN fade_in,RECT * pRect)412 DrawFadeText (const UNICODE *str1, const UNICODE *str2, BOOLEAN fade_in,
413 		RECT *pRect)
414 {
415 	SIZE i;
416 	DWORD TimeIn;
417 	TEXT t1, t2;
418 	static const Color fade_cycle[] =
419 	{
420 		BUILD_COLOR (MAKE_RGB15_INIT (0x0A, 0x0A, 0x0A), 0x1D),
421 		BUILD_COLOR (MAKE_RGB15_INIT (0x09, 0x09, 0x09), 0x1E),
422 		BUILD_COLOR (MAKE_RGB15_INIT (0x08, 0x08, 0x08), 0x1F),
423 		BUILD_COLOR (MAKE_RGB15_INIT (0x06, 0x06, 0x06), 0x20),
424 		BUILD_COLOR (MAKE_RGB15_INIT (0x05, 0x05, 0x05), 0x21),
425 		BUILD_COLOR (MAKE_RGB15_INIT (0x04, 0x04, 0x04), 0x22),
426 		BUILD_COLOR (MAKE_RGB15_INIT (0x03, 0x03, 0x03), 0x23),
427 	};
428 #define NUM_FADES (sizeof (fade_cycle) / sizeof (fade_cycle[0]))
429 
430 	t1.baseline.x = pRect->corner.x + 100;
431 	t1.baseline.y = pRect->corner.y + 45;
432 	t1.align = ALIGN_CENTER;
433 	t1.pStr = str1;
434 	t1.CharCount = (COUNT)~0;
435 	t2 = t1;
436 	t2.baseline.y += 11;
437 	t2.pStr = str2;
438 
439 	FlushInput ();
440 	TimeIn = GetTimeCounter ();
441 	if (fade_in)
442 	{
443 		for (i = 0; i < (SIZE) NUM_FADES; ++i)
444 		{
445 			if (AnyButtonPress (TRUE))
446 				i = NUM_FADES - 1;
447 
448 			SetContextForeGroundColor (fade_cycle[i]);
449 			font_DrawText (&t1);
450 			font_DrawText (&t2);
451 			SleepThreadUntil (TimeIn + (ONE_SECOND / 20));
452 			TimeIn = GetTimeCounter ();
453 		}
454 	}
455 	else
456 	{
457 		for (i = NUM_FADES - 1; i >= 0; --i)
458 		{
459 			if (AnyButtonPress (TRUE))
460 				i = 0;
461 
462 			SetContextForeGroundColor (fade_cycle[i]);
463 			font_DrawText (&t1);
464 			font_DrawText (&t2);
465 			SleepThreadUntil (TimeIn + (ONE_SECOND / 20));
466 			TimeIn = GetTimeCounter ();
467 		}
468 		SetContextForeGroundColor (
469 				BUILD_COLOR (MAKE_RGB15 (0x0A, 0x0A, 0x0A), 0x08));
470 		font_DrawText (&t1);
471 		font_DrawText (&t2);
472 	}
473 }
474 
475 COUNT
UninitEncounter(void)476 UninitEncounter (void)
477 {
478 	COUNT ships_killed;
479 
480 	ships_killed = 0;
481 
482 	free_gravity_well ();
483 
484 	if ((GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_LOAD))
485 			|| GLOBAL_SIS (CrewEnlisted) == (COUNT)~0
486 			|| LOBYTE (GLOBAL (CurrentActivity)) == IN_LAST_BATTLE
487 			|| LOBYTE (GLOBAL (CurrentActivity)) == WON_LAST_BATTLE)
488 		goto ExitUninitEncounter;
489 
490 	if (GET_GAME_STATE (BATTLE_SEGUE) == 0)
491 	{
492 		ReinitQueue (&race_q[0]);
493 		ReinitQueue (&race_q[1]);
494 	}
495 	else
496 	{
497 		BOOLEAN Sleepy;
498 		SIZE VictoryState;
499 		COUNT RecycleAmount = 0;
500 		SIZE i;
501 		RECT r;
502 		RECT scavenge_r = {{0, 0}, {0, 0}};
503 		TEXT t;
504 		STAMP ship_s;
505 		const UNICODE *str1 = NULL;
506 		const UNICODE *str2 = NULL;
507 		StatMsgMode prevMsgMode;
508 		UNICODE buf[80];
509 		HSHIPFRAG hStarShip;
510 		SHIP_FRAGMENT *FragPtr;
511 		static const Color fade_ship_cycle[] =
512 		{
513 			BUILD_COLOR (MAKE_RGB15_INIT (0x07, 0x00, 0x00), 0x2F),
514 			BUILD_COLOR (MAKE_RGB15_INIT (0x0F, 0x00, 0x00), 0x2D),
515 			BUILD_COLOR (MAKE_RGB15_INIT (0x17, 0x00, 0x00), 0x2B),
516 			BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x0A, 0x0A), 0x27),
517 			BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x14, 0x14), 0x25),
518 			BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x1F, 0x1F), 0x0F),
519 			BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x14, 0x14), 0x25),
520 			BUILD_COLOR (MAKE_RGB15_INIT (0x1F, 0x0A, 0x0A), 0x27),
521 			BUILD_COLOR (MAKE_RGB15_INIT (0x1B, 0x00, 0x00), 0x2A),
522 			BUILD_COLOR (MAKE_RGB15_INIT (0x17, 0x00, 0x00), 0x2B),
523 		};
524 #define NUM_SHIP_FADES (sizeof (fade_ship_cycle) / \
525 		sizeof (fade_ship_cycle[0]))
526 
527 		COUNT race_bounty[] =
528 		{
529 			RACE_SHIP_COST
530 		};
531 
532 		SET_GAME_STATE (BATTLE_SEGUE, 0);
533 		SET_GAME_STATE (BOMB_CARRIER, 0);
534 
535 		VictoryState = (
536 				battle_counter[1] || !battle_counter[0]
537 				|| GET_GAME_STATE (URQUAN_PROTECTING_SAMATRA)
538 				) ? 0 : 1;
539 
540 		hStarShip = GetHeadLink (&GLOBAL (npc_built_ship_q));
541 		FragPtr = LockShipFrag (&GLOBAL (npc_built_ship_q), hStarShip);
542 		EncounterRace = FragPtr->race_id;
543 		if (GetStarShipFromIndex (&GLOBAL (avail_race_q), EncounterRace) == 0)
544 		{
545 			/* Suppress the final tally and salvage info */
546 			VictoryState = -1;
547 			InitSISContexts ();
548 		}
549 		UnlockShipFrag (&GLOBAL (npc_built_ship_q), hStarShip);
550 
551 		prevMsgMode = SetStatusMessageMode (SMM_RES_UNITS);
552 		ship_s.origin.x = 0;
553 		ship_s.origin.y = 0;
554 		Sleepy = TRUE;
555 		for (i = 0; i < NUM_SIDES; ++i)
556 		{
557 			QUEUE *pQueue;
558 			HSHIPFRAG hNextShip;
559 
560 			if (i == 0)
561 				pQueue = &GLOBAL (built_ship_q);
562 			else
563 			{
564 				if (VictoryState < 0)
565 					VictoryState = 0;
566 				else
567 				{
568 					DrawSISFrame ();
569 					DrawSISMessage (NULL);
570 					if (inHQSpace ())
571 						DrawHyperCoords (GLOBAL (ShipStamp.origin));
572 					else if (GLOBAL (ip_planet) == 0)
573 						DrawHyperCoords (CurStarDescPtr->star_pt);
574 					else
575 						DrawSISTitle(GLOBAL_SIS (PlanetName));
576 
577 					SetContext (SpaceContext);
578 					if (VictoryState)
579 						DrawArmadaPickShip (TRUE, &scavenge_r);
580 				}
581 				pQueue = &GLOBAL (npc_built_ship_q);
582 			}
583 
584 			ReinitQueue (&race_q[(NUM_SIDES - 1) - i]);
585 
586 			for (hStarShip = GetHeadLink (pQueue); hStarShip;
587 					hStarShip = hNextShip)
588 			{
589 				FragPtr = LockShipFrag (pQueue, hStarShip);
590 				hNextShip = _GetSuccLink (FragPtr);
591 
592 				if (FragPtr->crew_level == 0
593 						|| (VictoryState && i == NUM_SIDES - 1))
594 				{
595 					if (i == NUM_SIDES - 1)
596 					{
597 						++ships_killed;
598 						if (VictoryState)
599 						{
600 #define MAX_DEAD_DISPLAYED 5
601 							COUNT j;
602 
603 							if (ships_killed == 1)
604 							{
605 								RecycleAmount = 0;
606 
607 								DrawStatusMessage (NULL);
608 
609 								ship_s.origin.x = scavenge_r.corner.x + 32;
610 								ship_s.origin.y = scavenge_r.corner.y + 56;
611 								ship_s.frame = IncFrameIndex (FragPtr->icons);
612 								DrawStamp (&ship_s);
613 								SetContextForeGroundColor (
614 										BUILD_COLOR (MAKE_RGB15 (0x08, 0x08, 0x08), 0x1F));
615 								SetContextFont (TinyFont);
616 
617 								utf8StringCopy (buf, sizeof buf,
618 										GetStringAddress (FragPtr->race_strings));
619 								// XXX: this will not work with UTF-8 strings
620 								strupr (buf);
621 
622 								t.baseline.x = scavenge_r.corner.x + 100;
623 								t.baseline.y = scavenge_r.corner.y + 68;
624 								t.align = ALIGN_CENTER;
625 								t.pStr = buf;
626 								t.CharCount = (COUNT)~0;
627 								font_DrawText (&t);
628 								t.baseline.y += 6;
629 								t.pStr = GAME_STRING (
630 										ENCOUNTER_STRING_BASE + 3);
631 										// "BATTLE GROUP"
632 								t.CharCount = (COUNT)~0;
633 								font_DrawText (&t);
634 
635 								ship_s.frame = FragPtr->icons;
636 
637 								SetContextFont (MicroFont);
638 								str1 = GAME_STRING (
639 										ENCOUNTER_STRING_BASE + 4);
640 										// "Enemy Ships"
641 								str2 = GAME_STRING (
642 										ENCOUNTER_STRING_BASE + 5),
643 										// "Destroyed"
644 								DrawFadeText (str1, str2, TRUE, &scavenge_r);
645 							}
646 
647 							r.corner.y = scavenge_r.corner.y + 9;
648 							r.extent.height = 22;
649 
650 							SetContextForeGroundColor (BLACK_COLOR);
651 
652 							r.extent.width = 34;
653 							r.corner.x = scavenge_r.corner.x +
654 									scavenge_r.extent.width
655 									- (10 + r.extent.width);
656 							DrawFilledRectangle (&r);
657 
658 							/* collect bounty ResUnits */
659 							j = race_bounty[EncounterRace] >> 3;
660 							RecycleAmount += j;
661 							sprintf (buf, "%u", RecycleAmount);
662 							t.baseline.x = r.corner.x + r.extent.width - 1;
663 							t.baseline.y = r.corner.y + 14;
664 							t.align = ALIGN_RIGHT;
665 							t.pStr = buf;
666 							t.CharCount = (COUNT)~0;
667 							SetContextForeGroundColor (
668 									BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x18), 0x50));
669 							font_DrawText (&t);
670 							DeltaSISGauges (0, 0, j);
671 
672 							if ((VictoryState++ - 1) % MAX_DEAD_DISPLAYED)
673 								ship_s.origin.x += 17;
674 							else
675 							{
676 								SetContextForeGroundColor (BLACK_COLOR);
677 
678 								r.corner.x = scavenge_r.corner.x + 10;
679 								r.extent.width = 104;
680 								DrawFilledRectangle (&r);
681 
682 								ship_s.origin.x = r.corner.x + 2;
683 								ship_s.origin.y = scavenge_r.corner.y + 12;
684 							}
685 
686 							if (Sleepy)
687 							{
688 								TimeCount Time = GetTimeCounter ();
689 								for (j = 0; j < NUM_SHIP_FADES; ++j)
690 								{
691 									Sleepy = (BOOLEAN)!AnyButtonPress (TRUE) &&
692 											!(GLOBAL (CurrentActivity) & CHECK_ABORT);
693 									if (!Sleepy)
694 										break;
695 
696 									SetContextForeGroundColor (fade_ship_cycle[j]);
697 									DrawFilledStamp (&ship_s);
698 
699 									SleepThreadUntil (Time + (ONE_SECOND / 15));
700 									Time = GetTimeCounter ();
701 								}
702 							}
703 							DrawStamp (&ship_s);
704 						}
705 					}
706 
707 					UnlockShipFrag (pQueue, hStarShip);
708 					RemoveQueue (pQueue, hStarShip);
709 					FreeShipFrag (pQueue, hStarShip);
710 
711 					continue;
712 				}
713 
714 				UnlockShipFrag (pQueue, hStarShip);
715 			}
716 		}
717 		SetStatusMessageMode (prevMsgMode);
718 
719 		if (VictoryState)
720 		{
721 #ifdef NEVER
722 			DestroyDrawable (ReleaseDrawable (s.frame));
723 #endif /* NEVER */
724 
725 			WaitForAnyButton (TRUE, ONE_SECOND * 3, FALSE);
726 			if (!CurrentInputState.key[PlayerControls[0]][KEY_ESCAPE])
727 			{
728 				DrawFadeText (str1, str2, FALSE, &scavenge_r);
729 				if (!CurrentInputState.key[PlayerControls[0]][KEY_ESCAPE])
730 				{
731 					SetContextForeGroundColor (BLACK_COLOR);
732 					r.corner.x = scavenge_r.corner.x + 10;
733 					r.extent.width = 132;
734 					DrawFilledRectangle (&r);
735 					sprintf (buf, "%u %s", RecycleAmount,
736 							GAME_STRING (STATUS_STRING_BASE + 1)); // "RU"
737 					t.baseline.x = r.corner.x + (r.extent.width >> 1);
738 					t.baseline.y = r.corner.y + 14;
739 					t.align = ALIGN_CENTER;
740 					t.pStr = buf;
741 					t.CharCount = (COUNT)~0;
742 					SetContextForeGroundColor (
743 							BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x18), 0x50));
744 					font_DrawText (&t);
745 
746 					str1 = GAME_STRING (ENCOUNTER_STRING_BASE + 6);
747 							// "Debris"
748 					str2 = GAME_STRING (ENCOUNTER_STRING_BASE + 7);
749 							// "Scavenged"
750 					DrawFadeText (str1, str2, TRUE, &scavenge_r);
751 					WaitForAnyButton (TRUE, ONE_SECOND * 2, FALSE);
752 					if (!CurrentInputState.key[PlayerControls[0]][KEY_ESCAPE])
753 						DrawFadeText (str1, str2, FALSE, &scavenge_r);
754 				}
755 			}
756 
757 			DrawStatusMessage (NULL);
758 		}
759 
760 		if (ships_killed && EncounterRace == THRADDASH_SHIP
761 				&& !GET_GAME_STATE (THRADD_MANNER))
762 		{
763 			if ((ships_killed += GET_GAME_STATE (THRADDASH_BODY_COUNT)) >
764 					THRADDASH_BODY_THRESHOLD)
765 				ships_killed = THRADDASH_BODY_THRESHOLD;
766 			SET_GAME_STATE (THRADDASH_BODY_COUNT, ships_killed);
767 		}
768 	}
769 ExitUninitEncounter:
770 
771 	return (ships_killed);
772 }
773 
774 void
EncounterBattle(void)775 EncounterBattle (void)
776 {
777 	ACTIVITY OldActivity;
778 	extern UWORD nth_frame;
779 	InputContext *savedPlayerInput = NULL;
780 
781 
782 	SET_GAME_STATE (BATTLE_SEGUE, 1);
783 
784 	OldActivity = GLOBAL (CurrentActivity);
785 	if (LOBYTE (OldActivity) == IN_LAST_BATTLE)
786 		GLOBAL (CurrentActivity) = MAKE_WORD (IN_LAST_BATTLE, 0);
787 	else
788 		GLOBAL (CurrentActivity) = MAKE_WORD (IN_ENCOUNTER, 0);
789 
790 //    FreeSC2Data ();
791 //    DestroyFont (ReleaseFont (MicroFont));
792 	WaitForSoundEnd (TFBSOUND_WAIT_ALL);
793 //    DestroySound (ReleaseSound (MenuSounds));
794 
795 	if (GLOBAL (glob_flags) & CYBORG_ENABLED)
796 	{
797 		BYTE cur_speed;
798 
799 		cur_speed = (BYTE)(GLOBAL (glob_flags) & COMBAT_SPEED_MASK)
800 				>> COMBAT_SPEED_SHIFT;
801 		if (cur_speed == 1)
802 			cur_speed = 0; /* normal speed */
803 		else if (cur_speed == 2)
804 			++cur_speed;   /* 4x speed, 3 of 4 frames skipped */
805 		else /* if (cur_speed == 3) */
806 			cur_speed = (BYTE)~0; /* maximum speed - no rendering */
807 		nth_frame = MAKE_WORD (1, cur_speed);
808 		PlayerControl[0] = CYBORG_CONTROL | AWESOME_RATING;
809 		savedPlayerInput = PlayerInput[0];
810 		PlayerInput[0] = NULL;
811 		if (!SetPlayerInput (0)) {
812 			log_add (log_Fatal, "Could not set cyborg player input.");
813 			explode ();  // Does not return;
814 		}
815 	}
816 
817 	GameSounds = CaptureSound (LoadSound (GAME_SOUNDS));
818 
819 	Battle (NULL);
820 
821 	DestroySound (ReleaseSound (GameSounds));
822 	GameSounds = 0;
823 
824 	if (GLOBAL (CurrentActivity) & CHECK_ABORT)
825 		GLOBAL_SIS (CrewEnlisted) = (COUNT)~0;
826 
827 	if (GLOBAL (glob_flags) & CYBORG_ENABLED)
828 	{
829 		nth_frame = MAKE_WORD (0, 0);
830 		PlayerControl[0] = HUMAN_CONTROL | STANDARD_RATING;
831 		ClearPlayerInput (0);
832 		PlayerInput[0] = savedPlayerInput;
833 	}
834 
835 //    MicroFont = CaptureFont (
836 // LoadFont (MICRO_FONT)
837 // );
838 //    MenuSounds = CaptureSound (LoadSound (MENU_SOUNDS));
839 //    LoadSC2Data ();
840 
841 	GLOBAL (CurrentActivity) = OldActivity;
842 
843 }
844 
845