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 <assert.h>
20
21 #include "build.h"
22 #include "encount.h"
23 #include "starmap.h"
24 #include "libs/file.h"
25 #include "globdata.h"
26 #include "options.h"
27 #include "save.h"
28 #include "setup.h"
29 #include "state.h"
30 #include "grpintrn.h"
31
32 #include "libs/tasklib.h"
33 #include "libs/log.h"
34 #include "libs/misc.h"
35
36 //#define DEBUG_LOAD
37
38 ACTIVITY NextActivity;
39
40 static inline size_t
read_8(void * fp,BYTE * v)41 read_8 (void *fp, BYTE *v)
42 {
43 BYTE t;
44 if (!v) /* read value ignored */
45 v = &t;
46 return ReadResFile (v, 1, 1, fp);
47 }
48
49 static inline size_t
read_16(void * fp,UWORD * v)50 read_16 (void *fp, UWORD *v)
51 {
52 UWORD t = 0;
53 int shift, i;
54 for (i = 0, shift = 0; i < 2; ++i, shift += 8)
55 {
56 BYTE b;
57 if (read_8 (fp, &b) != 1)
58 return 0;
59 t |= ((UWORD)b) << shift;
60 }
61
62 if (v)
63 *v = t;
64
65 return 1;
66 }
67
68 static inline size_t
read_16s(void * fp,SWORD * v)69 read_16s (void *fp, SWORD *v)
70 {
71 return read_16 (fp, (UWORD *) v);
72 }
73
74 static inline size_t
read_32(void * fp,DWORD * v)75 read_32 (void *fp, DWORD *v)
76 {
77 DWORD t = 0;
78 int shift, i;
79 for (i = 0, shift = 0; i < 4; ++i, shift += 8)
80 {
81 BYTE b;
82 if (read_8 (fp, &b) != 1)
83 return 0;
84 t |= ((DWORD)b) << shift;
85 }
86
87 if (v)
88 *v = t;
89
90 return 1;
91 }
92
93 static inline size_t
read_32s(void * fp,SDWORD * v)94 read_32s (void *fp, SDWORD *v)
95 {
96 return read_32 (fp, (DWORD *) v);
97 }
98
99 static inline size_t
read_a8(void * fp,BYTE * ar,COUNT count)100 read_a8 (void *fp, BYTE *ar, COUNT count)
101 {
102 assert (ar != NULL);
103 return ReadResFile (ar, 1, count, fp) == count;
104 }
105
106 static inline size_t
read_a8s(void * fp,char * ar,COUNT count)107 read_a8s (void *fp, char *ar, COUNT count)
108 {
109 return read_a8(fp, (BYTE *) ar, count);
110 }
111
112 static inline size_t
skip_8(void * fp,COUNT count)113 skip_8 (void *fp, COUNT count)
114 {
115 int i;
116 for (i = 0; i < count; ++i)
117 {
118 if (read_8(fp, NULL) != 1)
119 return 0;
120 }
121 return 1;
122 }
123
124 static inline size_t
read_str(void * fp,char * str,COUNT count)125 read_str (void *fp, char *str, COUNT count)
126 {
127 // no type conversion needed for strings
128 return read_a8 (fp, (BYTE *)str, count);
129 }
130
131 static inline size_t
read_a16(void * fp,UWORD * ar,COUNT count)132 read_a16 (void *fp, UWORD *ar, COUNT count)
133 {
134 assert (ar != NULL);
135
136 for ( ; count > 0; --count, ++ar)
137 {
138 if (read_16 (fp, ar) != 1)
139 return 0;
140 }
141 return 1;
142 }
143
144 static void
LoadShipQueue(void * fh,QUEUE * pQueue,DWORD size)145 LoadShipQueue (void *fh, QUEUE *pQueue, DWORD size)
146 {
147 COUNT num_links = size / 11;
148
149 while (num_links--)
150 {
151 HSHIPFRAG hStarShip;
152 SHIP_FRAGMENT *FragPtr;
153 COUNT Index;
154
155 read_16 (fh, &Index);
156
157 hStarShip = CloneShipFragment (Index, pQueue, 0);
158 FragPtr = LockShipFrag (pQueue, hStarShip);
159
160 // Read SHIP_FRAGMENT elements
161 read_8 (fh, &FragPtr->captains_name_index);
162 read_8 (fh, &FragPtr->race_id);
163 read_8 (fh, &FragPtr->index);
164 read_16 (fh, &FragPtr->crew_level);
165 read_16 (fh, &FragPtr->max_crew);
166 read_8 (fh, &FragPtr->energy_level);
167 read_8 (fh, &FragPtr->max_energy);
168
169 UnlockShipFrag (pQueue, hStarShip);
170 }
171 }
172
173 static void
LoadRaceQueue(void * fh,QUEUE * pQueue,DWORD size)174 LoadRaceQueue (void *fh, QUEUE *pQueue, DWORD size)
175 {
176 COUNT num_links = size / 30;
177
178 while (num_links--)
179 {
180 HFLEETINFO hStarShip;
181 FLEET_INFO *FleetPtr;
182 COUNT Index;
183
184 read_16 (fh, &Index);
185
186 hStarShip = GetStarShipFromIndex (pQueue, Index);
187 FleetPtr = LockFleetInfo (pQueue, hStarShip);
188
189 // Read FLEET_INFO elements
190 read_16 (fh, &FleetPtr->allied_state);
191 read_8 (fh, &FleetPtr->days_left);
192 read_8 (fh, &FleetPtr->growth_fract);
193 read_16 (fh, &FleetPtr->crew_level);
194 read_16 (fh, &FleetPtr->max_crew);
195 read_8 (fh, &FleetPtr->growth);
196 read_8 (fh, &FleetPtr->max_energy);
197 read_16s(fh, &FleetPtr->loc.x);
198 read_16s(fh, &FleetPtr->loc.y);
199
200 read_16 (fh, &FleetPtr->actual_strength);
201 read_16 (fh, &FleetPtr->known_strength);
202 read_16s(fh, &FleetPtr->known_loc.x);
203 read_16s(fh, &FleetPtr->known_loc.y);
204 read_8 (fh, &FleetPtr->growth_err_term);
205 read_8 (fh, &FleetPtr->func_index);
206 read_16s(fh, &FleetPtr->dest_loc.x);
207 read_16s(fh, &FleetPtr->dest_loc.y);
208
209 UnlockFleetInfo (pQueue, hStarShip);
210 }
211 }
212
213 static void
LoadGroupQueue(void * fh,QUEUE * pQueue,DWORD size)214 LoadGroupQueue (void *fh, QUEUE *pQueue, DWORD size)
215 {
216 COUNT num_links = size / 13;
217
218 while (num_links--)
219 {
220 HIPGROUP hGroup;
221 IP_GROUP *GroupPtr;
222
223 hGroup = BuildGroup (pQueue, 0);
224 GroupPtr = LockIpGroup (pQueue, hGroup);
225
226 read_16 (fh, &GroupPtr->group_counter);
227 read_8 (fh, &GroupPtr->race_id);
228 read_8 (fh, &GroupPtr->sys_loc);
229 read_8 (fh, &GroupPtr->task);
230 read_8 (fh, &GroupPtr->in_system); /* was crew_level */
231 read_8 (fh, &GroupPtr->dest_loc);
232 read_8 (fh, &GroupPtr->orbit_pos);
233 read_8 (fh, &GroupPtr->group_id); /* was max_energy */
234 read_16s(fh, &GroupPtr->loc.x);
235 read_16s(fh, &GroupPtr->loc.y);
236
237 UnlockIpGroup (pQueue, hGroup);
238 }
239 }
240
241 static void
LoadEncounter(ENCOUNTER * EncounterPtr,void * fh)242 LoadEncounter (ENCOUNTER *EncounterPtr, void *fh)
243 {
244 COUNT i;
245
246 EncounterPtr->pred = 0;
247 EncounterPtr->succ = 0;
248 EncounterPtr->hElement = 0;
249 read_16s (fh, &EncounterPtr->transition_state);
250 read_16s (fh, &EncounterPtr->origin.x);
251 read_16s (fh, &EncounterPtr->origin.y);
252 read_16 (fh, &EncounterPtr->radius);
253 // former STAR_DESC fields
254 read_16s (fh, &EncounterPtr->loc_pt.x);
255 read_16s (fh, &EncounterPtr->loc_pt.y);
256 read_8 (fh, &EncounterPtr->race_id);
257 read_8 (fh, &EncounterPtr->num_ships);
258 read_8 (fh, &EncounterPtr->flags);
259
260 // Load each entry in the BRIEF_SHIP_INFO array
261 for (i = 0; i < MAX_HYPER_SHIPS; i++)
262 {
263 BRIEF_SHIP_INFO *ShipInfo = &EncounterPtr->ShipList[i];
264
265 read_8 (fh, &ShipInfo->race_id);
266 read_16 (fh, &ShipInfo->crew_level);
267 read_16 (fh, &ShipInfo->max_crew);
268 read_8 (fh, &ShipInfo->max_energy);
269 }
270
271 // Load the stuff after the BRIEF_SHIP_INFO array
272 read_32s (fh, &EncounterPtr->log_x);
273 read_32s (fh, &EncounterPtr->log_y);
274 }
275
276 static void
LoadEvent(EVENT * EventPtr,void * fh)277 LoadEvent (EVENT *EventPtr, void *fh)
278 {
279 EventPtr->pred = 0;
280 EventPtr->succ = 0;
281 read_8 (fh, &EventPtr->day_index);
282 read_8 (fh, &EventPtr->month_index);
283 read_16 (fh, &EventPtr->year_index);
284 read_8 (fh, &EventPtr->func_index);
285 }
286
287 static void
LoadClockState(CLOCK_STATE * ClockPtr,void * fh)288 LoadClockState (CLOCK_STATE *ClockPtr, void *fh)
289 {
290 read_8 (fh, &ClockPtr->day_index);
291 read_8 (fh, &ClockPtr->month_index);
292 read_16 (fh, &ClockPtr->year_index);
293 read_16s (fh, &ClockPtr->tick_count);
294 read_16s (fh, &ClockPtr->day_in_ticks);
295 }
296
297 static BOOLEAN
LoadGameState(GAME_STATE * GSPtr,void * fh)298 LoadGameState (GAME_STATE *GSPtr, void *fh)
299 {
300 DWORD magic;
301 read_32 (fh, &magic);
302 if (magic != GLOBAL_STATE_TAG)
303 {
304 return FALSE;
305 }
306 read_32 (fh, &magic);
307 if (magic != 75)
308 {
309 /* Chunk is the wrong size. */
310 return FALSE;
311 }
312 read_8 (fh, &GSPtr->glob_flags);
313 read_8 (fh, &GSPtr->CrewCost);
314 read_8 (fh, &GSPtr->FuelCost);
315 read_a8 (fh, GSPtr->ModuleCost, NUM_MODULES);
316 read_a8 (fh, GSPtr->ElementWorth, NUM_ELEMENT_CATEGORIES);
317 read_16 (fh, &GSPtr->CurrentActivity);
318
319 LoadClockState (&GSPtr->GameClock, fh);
320
321 read_16s (fh, &GSPtr->autopilot.x);
322 read_16s (fh, &GSPtr->autopilot.y);
323 read_16s (fh, &GSPtr->ip_location.x);
324 read_16s (fh, &GSPtr->ip_location.y);
325 /* STAMP ShipStamp */
326 read_16s (fh, &GSPtr->ShipStamp.origin.x);
327 read_16s (fh, &GSPtr->ShipStamp.origin.y);
328 read_16 (fh, &GSPtr->ShipFacing);
329 read_8 (fh, &GSPtr->ip_planet);
330 read_8 (fh, &GSPtr->in_orbit);
331
332 /* VELOCITY_DESC velocity */
333 read_16 (fh, &GSPtr->velocity.TravelAngle);
334 read_16s (fh, &GSPtr->velocity.vector.width);
335 read_16s (fh, &GSPtr->velocity.vector.height);
336 read_16s (fh, &GSPtr->velocity.fract.width);
337 read_16s (fh, &GSPtr->velocity.fract.height);
338 read_16s (fh, &GSPtr->velocity.error.width);
339 read_16s (fh, &GSPtr->velocity.error.height);
340 read_16s (fh, &GSPtr->velocity.incr.width);
341 read_16s (fh, &GSPtr->velocity.incr.height);
342
343 read_32 (fh, &magic);
344 if (magic != GAME_STATE_TAG)
345 {
346 return FALSE;
347 }
348 memset (GSPtr->GameState, 0, sizeof (GSPtr->GameState));
349 read_32 (fh, &magic);
350 if (magic > sizeof (GSPtr->GameState))
351 {
352 read_a8 (fh, GSPtr->GameState, sizeof (GSPtr->GameState));
353 skip_8 (fh, magic - sizeof (GSPtr->GameState));
354 }
355 else
356 {
357 read_a8 (fh, GSPtr->GameState, magic);
358 }
359 return TRUE;
360 }
361
362 static BOOLEAN
LoadSisState(SIS_STATE * SSPtr,void * fp)363 LoadSisState (SIS_STATE *SSPtr, void *fp)
364 {
365 if (
366 read_32s (fp, &SSPtr->log_x) != 1 ||
367 read_32s (fp, &SSPtr->log_y) != 1 ||
368 read_32 (fp, &SSPtr->ResUnits) != 1 ||
369 read_32 (fp, &SSPtr->FuelOnBoard) != 1 ||
370 read_16 (fp, &SSPtr->CrewEnlisted) != 1 ||
371 read_16 (fp, &SSPtr->TotalElementMass) != 1 ||
372 read_16 (fp, &SSPtr->TotalBioMass) != 1 ||
373 read_a8 (fp, SSPtr->ModuleSlots, NUM_MODULE_SLOTS) != 1 ||
374 read_a8 (fp, SSPtr->DriveSlots, NUM_DRIVE_SLOTS) != 1 ||
375 read_a8 (fp, SSPtr->JetSlots, NUM_JET_SLOTS) != 1 ||
376 read_8 (fp, &SSPtr->NumLanders) != 1 ||
377 read_a16 (fp, SSPtr->ElementAmounts, NUM_ELEMENT_CATEGORIES) != 1 ||
378
379 read_str (fp, SSPtr->ShipName, SIS_NAME_SIZE) != 1 ||
380 read_str (fp, SSPtr->CommanderName, SIS_NAME_SIZE) != 1 ||
381 read_str (fp, SSPtr->PlanetName, SIS_NAME_SIZE) != 1
382 )
383 return FALSE;
384 return TRUE;
385 }
386
387 static BOOLEAN
LoadSummary(SUMMARY_DESC * SummPtr,void * fp)388 LoadSummary (SUMMARY_DESC *SummPtr, void *fp)
389 {
390 DWORD magic;
391 DWORD nameSize = 0;
392 if (!read_32 (fp, &magic))
393 return FALSE;
394 if (magic == SAVEFILE_TAG)
395 {
396 if (read_32 (fp, &magic) != 1 || magic != SUMMARY_TAG)
397 return FALSE;
398 if (read_32 (fp, &magic) != 1 || magic < 160)
399 return FALSE;
400 nameSize = magic - 160;
401 }
402 else
403 {
404 return FALSE;
405 }
406
407 if (!LoadSisState (&SummPtr->SS, fp))
408 return FALSE;
409
410 if ( read_8 (fp, &SummPtr->Activity) != 1 ||
411 read_8 (fp, &SummPtr->Flags) != 1 ||
412 read_8 (fp, &SummPtr->day_index) != 1 ||
413 read_8 (fp, &SummPtr->month_index) != 1 ||
414 read_16 (fp, &SummPtr->year_index) != 1 ||
415 read_8 (fp, &SummPtr->MCreditLo) != 1 ||
416 read_8 (fp, &SummPtr->MCreditHi) != 1 ||
417 read_8 (fp, &SummPtr->NumShips) != 1 ||
418 read_8 (fp, &SummPtr->NumDevices) != 1 ||
419 read_a8 (fp, SummPtr->ShipList, MAX_BUILT_SHIPS) != 1 ||
420 read_a8 (fp, SummPtr->DeviceList, MAX_EXCLUSIVE_DEVICES) != 1
421 )
422 return FALSE;
423
424 if (nameSize < SAVE_NAME_SIZE)
425 {
426 if (read_a8s (fp, SummPtr->SaveName, nameSize) != 1)
427 return FALSE;
428 SummPtr->SaveName[nameSize] = 0;
429 }
430 else
431 {
432 DWORD remaining = nameSize - SAVE_NAME_SIZE + 1;
433 if (read_a8s (fp, SummPtr->SaveName, SAVE_NAME_SIZE-1) != 1)
434 return FALSE;
435 SummPtr->SaveName[SAVE_NAME_SIZE-1] = 0;
436 if (skip_8 (fp, remaining) != 1)
437 return FALSE;
438 }
439 return TRUE;
440 }
441
442 static void
LoadStarDesc(STAR_DESC * SDPtr,void * fh)443 LoadStarDesc (STAR_DESC *SDPtr, void *fh)
444 {
445 read_16s(fh, &SDPtr->star_pt.x);
446 read_16s(fh, &SDPtr->star_pt.y);
447 read_8 (fh, &SDPtr->Type);
448 read_8 (fh, &SDPtr->Index);
449 read_8 (fh, &SDPtr->Prefix);
450 read_8 (fh, &SDPtr->Postfix);
451 }
452
453 static void
LoadScanInfo(uio_Stream * fh,DWORD flen)454 LoadScanInfo (uio_Stream *fh, DWORD flen)
455 {
456 GAME_STATE_FILE *fp = OpenStateFile (STARINFO_FILE, "wb");
457 if (fp)
458 {
459 while (flen)
460 {
461 DWORD val;
462 read_32 (fh, &val);
463 swrite_32 (fp, val);
464 flen -= 4;
465 }
466 CloseStateFile (fp);
467 }
468 }
469
470 static void
LoadGroupList(uio_Stream * fh,DWORD chunksize)471 LoadGroupList (uio_Stream *fh, DWORD chunksize)
472 {
473 GAME_STATE_FILE *fp = OpenStateFile (RANDGRPINFO_FILE, "rb");
474 if (fp)
475 {
476 GROUP_HEADER h;
477 BYTE LastEnc, NumGroups;
478 int i;
479 ReadGroupHeader (fp, &h);
480 /* There's only supposed to be one of these, so group 0 should be
481 * zero here whenever we're here. We add the group list to the
482 * end here. */
483 h.GroupOffset[0] = LengthStateFile (fp);
484 SeekStateFile (fp, 0, SEEK_SET);
485 WriteGroupHeader (fp, &h);
486 SeekStateFile (fp, h.GroupOffset[0], SEEK_SET);
487 read_8 (fh, &LastEnc);
488 NumGroups = (chunksize - 1) / 14;
489 swrite_8 (fp, LastEnc);
490 swrite_8 (fp, NumGroups);
491 for (i = 0; i < NumGroups; ++i)
492 {
493 BYTE race_outer;
494 IP_GROUP ip;
495 read_8 (fh, &race_outer);
496 read_16 (fh, &ip.group_counter);
497 read_8 (fh, &ip.race_id);
498 read_8 (fh, &ip.sys_loc);
499 read_8 (fh, &ip.task);
500 read_8 (fh, &ip.in_system);
501 read_8 (fh, &ip.dest_loc);
502 read_8 (fh, &ip.orbit_pos);
503 read_8 (fh, &ip.group_id);
504 read_16s (fh, &ip.loc.x);
505 read_16s (fh, &ip.loc.y);
506
507 swrite_8 (fp, race_outer);
508 WriteIpGroup (fp, &ip);
509 }
510 CloseStateFile (fp);
511 }
512 }
513
514 static void
LoadBattleGroup(uio_Stream * fh,DWORD chunksize)515 LoadBattleGroup (uio_Stream *fh, DWORD chunksize)
516 {
517 GAME_STATE_FILE *fp;
518 GROUP_HEADER h;
519 DWORD encounter, offset;
520 BYTE current;
521 int i;
522
523 read_32 (fh, &encounter);
524 read_8 (fh, ¤t);
525 chunksize -= 5;
526 if (encounter)
527 {
528 /* This is a defined group, so it's new */
529 fp = OpenStateFile (DEFGRPINFO_FILE, "rb");
530 offset = LengthStateFile (fp);
531 memset (&h, 0, sizeof (GROUP_HEADER));
532 }
533 else
534 {
535 /* This is the random group. Load in what was there,
536 * as we might have already seen the Group List. */
537 fp = OpenStateFile (RANDGRPINFO_FILE, "rb");
538 current = FALSE;
539 offset = 0;
540 ReadGroupHeader (fp, &h);
541 }
542 if (!fp)
543 {
544 skip_8 (fh, chunksize);
545 return;
546 }
547 read_16 (fh, &h.star_index);
548 read_8 (fh, &h.day_index);
549 read_8 (fh, &h.month_index);
550 read_16 (fh, &h.year_index);
551 read_8 (fh, &h.NumGroups);
552 chunksize -= 7;
553 /* Write out the half-finished state file so that we can use
554 * the file size to compute group offsets */
555 SeekStateFile (fp, offset, SEEK_SET);
556 WriteGroupHeader (fp, &h);
557 for (i = 1; i <= h.NumGroups; ++i)
558 {
559 int j;
560 BYTE icon, NumShips;
561 read_8 (fh, &icon);
562 read_8 (fh, &NumShips);
563 chunksize -= 2;
564 h.GroupOffset[i] = LengthStateFile (fp);
565 SeekStateFile (fp, h.GroupOffset[i], SEEK_SET);
566 swrite_8 (fp, icon);
567 swrite_8 (fp, NumShips);
568 for (j = 0; j < NumShips; ++j)
569 {
570 BYTE race_outer;
571 SHIP_FRAGMENT sf;
572 read_8 (fh, &race_outer);
573 read_8 (fh, &sf.captains_name_index);
574 read_8 (fh, &sf.race_id);
575 read_8 (fh, &sf.index);
576 read_16 (fh, &sf.crew_level);
577 read_16 (fh, &sf.max_crew);
578 read_8 (fh, &sf.energy_level);
579 read_8 (fh, &sf.max_energy);
580 chunksize -= 10;
581
582 swrite_8 (fp, race_outer);
583 WriteShipFragment (fp, &sf);
584 }
585 }
586 /* Now that the GroupOffset array is properly initialized,
587 * write the header back out. */
588 SeekStateFile (fp, offset, SEEK_SET);
589 WriteGroupHeader (fp, &h);
590 CloseStateFile (fp);
591 /* And update the gamestate accordingly, if we're a defined group. */
592 if (encounter)
593 {
594 SET_GAME_STATE_32 (SHOFIXTI_GRPOFFS0 + (encounter - 1) * 32, offset);
595 if (current)
596 {
597 GLOBAL (BattleGroupRef) = offset;
598 }
599 }
600 /* Consistency check. */
601 if (chunksize)
602 {
603 log_add (log_Warning, "BattleGroup chunk mis-sized!");
604 }
605 }
606
607 BOOLEAN
LoadGame(COUNT which_game,SUMMARY_DESC * SummPtr)608 LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr)
609 {
610 uio_Stream *in_fp;
611 char file[PATH_MAX];
612 SUMMARY_DESC loc_sd;
613 COUNT num_links;
614 STAR_DESC SD;
615 ACTIVITY Activity;
616 DWORD chunk, chunkSize;
617 BOOLEAN first_group_spec = TRUE;
618
619 sprintf (file, "uqmsave.%02u", which_game);
620 in_fp = res_OpenResFile (saveDir, file, "rb");
621 if (!in_fp)
622 return LoadLegacyGame (which_game, SummPtr);
623
624 if (!LoadSummary (&loc_sd, in_fp))
625 {
626 res_CloseResFile (in_fp);
627 return LoadLegacyGame (which_game, SummPtr);
628 }
629
630 if (!SummPtr)
631 {
632 SummPtr = &loc_sd;
633 }
634 else
635 { // only need summary for displaying to user
636 memcpy (SummPtr, &loc_sd, sizeof (*SummPtr));
637 res_CloseResFile (in_fp);
638 return TRUE;
639 }
640
641 GlobData.SIS_state = SummPtr->SS;
642
643 ReinitQueue (&GLOBAL (GameClock.event_q));
644 ReinitQueue (&GLOBAL (encounter_q));
645 ReinitQueue (&GLOBAL (ip_group_q));
646 ReinitQueue (&GLOBAL (npc_built_ship_q));
647 ReinitQueue (&GLOBAL (built_ship_q));
648
649 memset (&GLOBAL (GameState[0]), 0, sizeof (GLOBAL (GameState)));
650 Activity = GLOBAL (CurrentActivity);
651 if (!LoadGameState (&GlobData.Game_state, in_fp))
652 {
653 res_CloseResFile (in_fp);
654 return FALSE;
655 }
656 NextActivity = GLOBAL (CurrentActivity);
657 GLOBAL (CurrentActivity) = Activity;
658
659 chunk = 0;
660 while (TRUE)
661 {
662 if (read_32(in_fp, &chunk) != 1)
663 {
664 break;
665 }
666 if (read_32(in_fp, &chunkSize) != 1)
667 {
668 res_CloseResFile (in_fp);
669 return FALSE;
670 }
671 switch (chunk)
672 {
673 case RACE_Q_TAG:
674 LoadRaceQueue (in_fp, &GLOBAL (avail_race_q), chunkSize);
675 break;
676 case IP_GRP_Q_TAG:
677 LoadGroupQueue (in_fp, &GLOBAL (ip_group_q), chunkSize);
678 break;
679 case ENCOUNTERS_TAG:
680 num_links = chunkSize / 65;
681 while (num_links--)
682 {
683 HENCOUNTER hEncounter;
684 ENCOUNTER *EncounterPtr;
685
686 hEncounter = AllocEncounter ();
687 LockEncounter (hEncounter, &EncounterPtr);
688
689 LoadEncounter (EncounterPtr, in_fp);
690
691 UnlockEncounter (hEncounter);
692 PutEncounter (hEncounter);
693 }
694 break;
695 case EVENTS_TAG:
696 num_links = chunkSize / 5;
697 #ifdef DEBUG_LOAD
698 log_add (log_Debug, "EVENTS:");
699 #endif /* DEBUG_LOAD */
700 while (num_links--)
701 {
702 HEVENT hEvent;
703 EVENT *EventPtr;
704
705 hEvent = AllocEvent ();
706 LockEvent (hEvent, &EventPtr);
707
708 LoadEvent (EventPtr, in_fp);
709
710 #ifdef DEBUG_LOAD
711 log_add (log_Debug, "\t%u/%u/%u -- %u",
712 EventPtr->month_index,
713 EventPtr->day_index,
714 EventPtr->year_index,
715 EventPtr->func_index);
716 #endif /* DEBUG_LOAD */
717 UnlockEvent (hEvent);
718 PutEvent (hEvent);
719 }
720 break;
721 case STAR_TAG:
722 LoadStarDesc (&SD, in_fp);
723 break;
724 case NPC_SHIP_Q_TAG:
725 LoadShipQueue (in_fp, &GLOBAL (npc_built_ship_q), chunkSize);
726 break;
727 case SHIP_Q_TAG:
728 LoadShipQueue (in_fp, &GLOBAL (built_ship_q), chunkSize);
729 break;
730 case SCAN_TAG:
731 LoadScanInfo (in_fp, chunkSize);
732 break;
733 case GROUP_LIST_TAG:
734 if (first_group_spec)
735 {
736 InitGroupInfo (TRUE);
737 GLOBAL (BattleGroupRef) = 0;
738 first_group_spec = FALSE;
739 }
740 LoadGroupList (in_fp, chunkSize);
741 break;
742 case BATTLE_GROUP_TAG:
743 if (first_group_spec)
744 {
745 InitGroupInfo (TRUE);
746 GLOBAL (BattleGroupRef) = 0;
747 first_group_spec = FALSE;
748 }
749 LoadBattleGroup (in_fp, chunkSize);
750 break;
751 default:
752 log_add (log_Debug, "Skipping chunk of tag %08X (size %u)", chunk, chunkSize);
753 if (skip_8(in_fp, chunkSize) != 1)
754 {
755 res_CloseResFile (in_fp);
756 return FALSE;
757 }
758 break;
759 }
760 }
761 res_CloseResFile (in_fp);
762
763 EncounterGroup = 0;
764 EncounterRace = -1;
765
766 ReinitQueue (&race_q[0]);
767 ReinitQueue (&race_q[1]);
768 CurStarDescPtr = FindStar (NULL, &SD.star_pt, 0, 0);
769 if (!(NextActivity & START_ENCOUNTER)
770 && LOBYTE (NextActivity) == IN_INTERPLANETARY)
771 NextActivity |= START_INTERPLANETARY;
772
773 return TRUE;
774 }
775