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