diff --git a/sc2/src/sc2code/globdata.h b/sc2/src/sc2code/globdata.h index c8db47904..d885f0813 100644 --- a/sc2/src/sc2code/globdata.h +++ b/sc2/src/sc2code/globdata.h @@ -924,13 +924,17 @@ typedef struct VELOCITY_DESC velocity; DWORD BattleGroupRef; - QUEUE avail_race_q, npc_built_ship_q; + QUEUE avail_race_q; + QUEUE npc_built_ship_q; + // Non-player-character list of ships (during encounter) + // or list of groups present in solarsys (during IP) QUEUE encounter_q; QUEUE built_ship_q; /* Queue of SIS escort ships */ BYTE GameState[(NUM_GAME_STATE_BITS + 7) >> 3]; } GAME_STATE; +typedef GAME_STATE *PGAME_STATE; typedef struct { diff --git a/sc2/src/sc2code/grpinfo.c b/sc2/src/sc2code/grpinfo.c index 55f5f1e8e..95ad9a62d 100644 --- a/sc2/src/sc2code/grpinfo.c +++ b/sc2/src/sc2code/grpinfo.c @@ -38,11 +38,95 @@ static BYTE LastEncGroup; typedef struct { - BYTE NumGroups, day_index, month_index; + BYTE NumGroups; + BYTE day_index, month_index; COUNT star_index, year_index; + // day_index, month_index, year_index specify when + // random groups expire (if you were to leave the system + // by going to HSpace and stay there till such time) + // star_index is the index of a star this group header + // applies to; ~0 means uninited DWORD GroupOffset[MAX_BATTLE_GROUPS + 1]; + // Absolute offsets of group definitions in a state file + // Group 0 is actually a list of groups present in solarsys + // Groups 1..max are definitions of actual battle groups + // containing ships composition and status + + // Each group has the following format: + // 1 byte, RaceType (LastEncGroup in Group 0) + // 1 byte, NumShips + // Ships follow: + // 1 byte, RaceType + // 16 bytes, part of SHIP_FRAGMENT struct + } GROUP_HEADER; +static void +ReadGroupHeader (PVOID fp, GROUP_HEADER* pGH) +{ + sread_8 (fp, &pGH->NumGroups); + sread_8 (fp, &pGH->day_index); + sread_8 (fp, &pGH->month_index); + sread_8 (fp, NULL); /* padding */ + sread_16 (fp, &pGH->star_index); + sread_16 (fp, &pGH->year_index); + sread_a32 (fp, pGH->GroupOffset, MAX_BATTLE_GROUPS + 1); +} + +static void +WriteGroupHeader (PVOID fp, GROUP_HEADER* pGH) +{ + swrite_8 (fp, pGH->NumGroups); + swrite_8 (fp, pGH->day_index); + swrite_8 (fp, pGH->month_index); + swrite_8 (fp, 0); /* padding */ + swrite_16 (fp, pGH->star_index); + swrite_16 (fp, pGH->year_index); + swrite_a32 (fp, pGH->GroupOffset, MAX_BATTLE_GROUPS + 1); +} + +static void +ReadShipFragment (PVOID fp, SHIP_FRAGMENTPTR FragPtr) +{ + BYTE tmpb; + + // Read SHIP_FRAGMENT elements + sread_16 (fp, &FragPtr->s.Player); + sread_8 (fp, &FragPtr->s.Captain); + sread_8 (fp, NULL); /* padding */ + // Read SHIP_INFO elements + sread_16 (fp, &FragPtr->ShipInfo.ship_flags); + sread_8 (fp, &FragPtr->ShipInfo.var1); + sread_8 (fp, &FragPtr->ShipInfo.var2); + sread_8 (fp, &tmpb); + FragPtr->ShipInfo.crew_level = tmpb; + sread_8 (fp, &tmpb); + FragPtr->ShipInfo.max_crew = tmpb; + sread_8 (fp, &FragPtr->ShipInfo.energy_level); + sread_8 (fp, &FragPtr->ShipInfo.max_energy); + sread_16 (fp, &FragPtr->ShipInfo.loc.x); + sread_16 (fp, &FragPtr->ShipInfo.loc.y); +} + +static void +WriteShipFragment (PVOID fp, SHIP_FRAGMENTPTR FragPtr) +{ + // Write SHIP_FRAGMENT elements + swrite_16 (fp, FragPtr->s.Player); + swrite_8 (fp, FragPtr->s.Captain); + swrite_8 (fp, 0); /* padding */ + // Write SHIP_INFO elements + swrite_16 (fp, FragPtr->ShipInfo.ship_flags); + swrite_8 (fp, FragPtr->ShipInfo.var1); + swrite_8 (fp, FragPtr->ShipInfo.var2); + swrite_8 (fp, FragPtr->ShipInfo.crew_level); + swrite_8 (fp, FragPtr->ShipInfo.max_crew); + swrite_8 (fp, FragPtr->ShipInfo.energy_level); + swrite_8 (fp, FragPtr->ShipInfo.max_energy); + swrite_16 (fp, FragPtr->ShipInfo.loc.x); + swrite_16 (fp, FragPtr->ShipInfo.loc.y); +} + void InitGroupInfo (BOOLEAN FirstTime) { @@ -56,14 +140,16 @@ InitGroupInfo (BOOLEAN FirstTime) GH.NumGroups = 0; GH.star_index = (COUNT)~0; GH.GroupOffset[0] = 0; - WriteStateFile (&GH, sizeof (GH), 1, fp); + WriteGroupHeader (fp, &GH); CloseStateFile (fp); } if (FirstTime && (fp = OpenStateFile (DEFGRPINFO_FILE, "wb"))) { - PutStateFileChar (0, fp); + // Group headers cannot start with offset 0 in + // defined group info file, so bump it + swrite_8 (fp, 0); CloseStateFile (fp); } @@ -297,11 +383,11 @@ FlushGroupInfo (GROUP_HEADER *pGH, DWORD offset, BYTE which_group, PVOID fp) &GLOBAL (npc_built_ship_q), hStarShip); RaceType = GET_RACE_ID (FragPtr); SeekStateFile (fp, pGH->GroupOffset[which_group], SEEK_SET); - WriteStateFile (&RaceType, sizeof (RaceType), 1, fp); + swrite_8 (fp, RaceType); UnlockStarShip (&GLOBAL (npc_built_ship_q), hStarShip); } SeekStateFile (fp, offset, SEEK_SET); - WriteStateFile (pGH, sizeof (*pGH), 1, fp); + WriteGroupHeader (fp, pGH); #ifdef DEBUG_GROUPS log_add (log_Debug, "1)FlushGroupInfo(%lu): WG = %u(%lu), NG = %u, " "SI = %u", offset, which_group, pGH->GroupOffset[which_group], @@ -311,22 +397,20 @@ FlushGroupInfo (GROUP_HEADER *pGH, DWORD offset, BYTE which_group, PVOID fp) NumShips = (BYTE)CountLinks (&GLOBAL (npc_built_ship_q)); if (which_group != GROUP_LIST) - { - SeekStateFile (fp, pGH->GroupOffset[which_group] - + sizeof (LastEncGroup), SEEK_SET); + { // skip RaceType + SeekStateFile (fp, pGH->GroupOffset[which_group] + 1, SEEK_SET); } else { SeekStateFile (fp, pGH->GroupOffset[0], SEEK_SET); - WriteStateFile (&LastEncGroup, sizeof (LastEncGroup), 1, fp); + swrite_8 (fp, LastEncGroup); } - WriteStateFile (&NumShips, sizeof (NumShips), 1, fp); + swrite_8 (fp, NumShips); hStarShip = GetHeadLink (&GLOBAL (npc_built_ship_q)); while (NumShips--) { HSTARSHIP hNextShip; - PBYTE Ptr; FragPtr = (SHIP_FRAGMENTPTR)LockStarShip ( &GLOBAL (npc_built_ship_q), hStarShip @@ -334,7 +418,7 @@ FlushGroupInfo (GROUP_HEADER *pGH, DWORD offset, BYTE which_group, PVOID fp) hNextShip = _GetSuccLink (FragPtr); RaceType = GET_RACE_ID (FragPtr); - WriteStateFile (&RaceType, sizeof (RaceType), 1, fp); + swrite_8 (fp, RaceType); #ifdef DEBUG_GROUPS if (which_group == GROUP_LIST) @@ -346,9 +430,7 @@ FlushGroupInfo (GROUP_HEADER *pGH, DWORD offset, BYTE which_group, PVOID fp) GET_GROUP_MISSION (FragPtr), GET_GROUP_DEST (FragPtr)); #endif /* DEBUG_GROUPS */ - Ptr = (PBYTE)&FragPtr->RaceDescPtr; - WriteStateFile (Ptr, - ((PBYTE)&FragPtr->ShipInfo.race_strings) - Ptr, 1, fp); + WriteShipFragment (fp, FragPtr); UnlockStarShip (&GLOBAL (npc_built_ship_q), hStarShip); hStarShip = hNextShip; } @@ -372,7 +454,7 @@ GetGroupInfo (DWORD offset, BYTE which_group) SHIP_FRAGMENTPTR FragPtr; SeekStateFile (fp, offset, SEEK_SET); - ReadStateFile (&GH, sizeof (GH), 1, fp); + ReadGroupHeader (fp, &GH); #ifdef DEBUG_GROUPS log_add (log_Debug, "GetGroupInfo(%lu): %u(%lu) out of %u", offset, which_group, GH.GroupOffset[which_group], GH.NumGroups); @@ -402,11 +484,12 @@ GetGroupInfo (DWORD offset, BYTE which_group) "date %u/%u/%u!", month_index, day_index, year_index); #endif /* DEBUG_GROUPS */ + // Erase random groups (out of date) fp = OpenStateFile (RANDGRPINFO_FILE, "wb"); GH.NumGroups = 0; GH.star_index = (COUNT)~0; GH.GroupOffset[0] = 0; - WriteStateFile (&GH, sizeof (GH), 1, fp); + WriteGroupHeader (fp, &GH); } else { @@ -417,8 +500,8 @@ GetGroupInfo (DWORD offset, BYTE which_group) continue; SeekStateFile (fp, GH.GroupOffset[which_group], SEEK_SET); - ReadStateFile (&RaceType, sizeof (RaceType), 1, fp); - ReadStateFile (&NumShips, sizeof (NumShips), 1, fp); + sread_8 (fp, &RaceType); + sread_8 (fp, &NumShips); if (NumShips) { @@ -516,7 +599,7 @@ GetGroupInfo (DWORD offset, BYTE which_group) if (which_group == GROUP_LIST) { SeekStateFile (fp, GH.GroupOffset[0], SEEK_SET); - ReadStateFile (&LastEncGroup, sizeof (LastEncGroup), 1, fp); + sread_8 (fp, &LastEncGroup); if (LastEncGroup) { @@ -536,25 +619,20 @@ GetGroupInfo (DWORD offset, BYTE which_group) } ReinitQueue (&GLOBAL (npc_built_ship_q)); - SeekStateFile (fp, GH.GroupOffset[which_group] - + sizeof (LastEncGroup), SEEK_SET); - - ReadStateFile (&NumShips, sizeof (NumShips), 1, fp); + // skip RaceType + SeekStateFile (fp, GH.GroupOffset[which_group] + 1, SEEK_SET); + + sread_8 (fp, &NumShips); while (NumShips--) { - PBYTE Ptr; - - ReadStateFile (&RaceType, sizeof (RaceType), 1, fp); + sread_8 (fp, &RaceType); hStarShip = CloneShipFragment (RaceType, &GLOBAL (npc_built_ship_q), 0); FragPtr = (SHIP_FRAGMENTPTR)LockStarShip ( &GLOBAL (npc_built_ship_q), hStarShip); - Ptr = (PBYTE)&FragPtr->RaceDescPtr; - ReadStateFile (Ptr, - ((PBYTE)&FragPtr->ShipInfo.race_strings) - Ptr, 1, - fp); + ReadShipFragment (fp, FragPtr); #ifdef DEBUG_GROUPS if (which_group == GROUP_LIST) @@ -625,12 +703,13 @@ PutGroupInfo (DWORD offset, BYTE which_group) if (offset == GROUPS_ADD_NEW) { offset = LengthStateFile (fp); - GH.NumGroups = 0; - GH.GroupOffset[0] = 0; SeekStateFile (fp, offset, SEEK_SET); - WriteStateFile (&GH, sizeof (GH), 1, fp); - // XXX: It seems that GH is not completely initialised. - // Some garbage is saved. -- SvdB + // XXX: All important fields are inited here, and the + // rest are inited below + GH.NumGroups = 0; + GH.star_index = (COUNT)~0; + GH.GroupOffset[0] = 0; + WriteGroupHeader (fp, &GH); } if (which_group != GROUP_LIST) @@ -642,7 +721,7 @@ PutGroupInfo (DWORD offset, BYTE which_group) which_group = GROUP_LIST; } } - ReadStateFile (&GH, sizeof (GH), 1, fp); + ReadGroupHeader (fp, &GH); #ifdef NEVER if (GetHeadLink (&GLOBAL (npc_built_ship_q)) diff --git a/sc2/src/sc2code/load.c b/sc2/src/sc2code/load.c index 67d8b259b..4afdce866 100644 --- a/sc2/src/sc2code/load.c +++ b/sc2/src/sc2code/load.c @@ -16,6 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include + #include "load.h" #include "build.h" @@ -35,62 +37,166 @@ ACTIVITY NextActivity; -static BOOLEAN LoadSummary (uio_Stream *in_fp); +// XXX: these should handle endian conversions later +static inline COUNT +cread_8 (DECODE_REF fh, PBYTE v) +{ + BYTE t; + if (!v) /* read value ignored */ + v = &t; + return cread (v, 1, 1, fh); +} + +static inline COUNT +cread_16 (DECODE_REF fh, PUWORD v) +{ + UWORD t; + if (!v) /* read value ignored */ + v = &t; + return cread (v, 2, 1, fh); +} + +static inline COUNT +cread_32 (DECODE_REF fh, PDWORD v) +{ + DWORD t; + if (!v) /* read value ignored */ + v = &t; + return cread (v, 4, 1, fh); +} + +static inline COUNT +cread_ptr (DECODE_REF fh) +{ + DWORD t; + return cread_32 (fh, &t); /* ptrs are useless in saves */ +} + +static inline COUNT +cread_a8 (DECODE_REF fh, PBYTE ar, COUNT count) +{ + assert (ar != NULL); + return cread (ar, 1, count, fh) == count; +} + +static inline COUNT +read_8 (PVOID fp, PBYTE v) +{ + BYTE t; + if (!v) /* read value ignored */ + v = &t; + return ReadResFile (v, 1, 1, fp); +} + +static inline COUNT +read_16 (PVOID fp, PUWORD v) +{ + UWORD t; + if (!v) /* read value ignored */ + v = &t; + return ReadResFile (v, 2, 1, fp); +} + +static inline COUNT +read_32 (PVOID fp, PDWORD v) +{ + DWORD t; + if (!v) /* read value ignored */ + v = &t; + return ReadResFile (v, 4, 1, fp); +} + +static inline COUNT +read_ptr (PVOID fp) +{ + DWORD t; + return read_32 (fp, &t); /* ptrs are useless in saves */ +} + +static inline COUNT +read_a8 (PVOID fp, PBYTE ar, COUNT count) +{ + assert (ar != NULL); + return ReadResFile (ar, 1, count, fp) == count; +} + +static inline COUNT +read_a16 (PVOID fp, PUWORD ar, COUNT count) +{ + assert (ar != NULL); + + for ( ; count > 0; --count, ++ar) + { + if (read_16 (fp, ar) != 1) + return 0; + } + return 1; +} static void LoadShipQueue (DECODE_REF fh, PQUEUE pQueue, BOOLEAN MakeQ) { COUNT num_links; - cread ((PBYTE)&num_links, sizeof (num_links), 1, fh); - if (num_links) + cread_16 (fh, &num_links); + if (num_links && MakeQ) + InitQueue (pQueue, num_links, sizeof (SHIP_FRAGMENT)); + + while (num_links--) { - if (MakeQ) - InitQueue (pQueue, num_links, sizeof (SHIP_FRAGMENT)); + HSTARSHIP hStarShip; + SHIP_FRAGMENTPTR FragPtr; + COUNT Index; + BYTE tmpb; - do + cread_16 (fh, &Index); + + if (pQueue == &GLOBAL (avail_race_q)) + hStarShip = GetStarShipFromIndex (pQueue, Index); + else + hStarShip = CloneShipFragment (Index, pQueue, 0); + + FragPtr = (SHIP_FRAGMENTPTR)LockStarShip (pQueue, hStarShip); + + if (pQueue != &GLOBAL (avail_race_q)) + { // queues other than avail_race_q save SHIP_FRAGMENT elements + // Read SHIP_FRAGMENT elements + cread_16 (fh, &FragPtr->s.Player); + cread_8 (fh, &FragPtr->s.Captain); + cread_8 (fh, NULL); /* padding */ + } + // Read SHIP_INFO elements + cread_16 (fh, &FragPtr->ShipInfo.ship_flags); + cread_8 (fh, &FragPtr->ShipInfo.var1); + cread_8 (fh, &FragPtr->ShipInfo.var2); + cread_8 (fh, &tmpb); + FragPtr->ShipInfo.crew_level = tmpb; + cread_8 (fh, &tmpb); + FragPtr->ShipInfo.max_crew = tmpb; + cread_8 (fh, &FragPtr->ShipInfo.energy_level); + cread_8 (fh, &FragPtr->ShipInfo.max_energy); + cread_16 (fh, &FragPtr->ShipInfo.loc.x); + cread_16 (fh, &FragPtr->ShipInfo.loc.y); + + if (pQueue == &GLOBAL (avail_race_q)) { - HSTARSHIP hStarShip; - SHIP_FRAGMENTPTR FragPtr; - COUNT Index, Offset; - PBYTE Ptr; + // avail_race_q contains information not about specific ships, + // but about a race. + EXTENDED_SHIP_FRAGMENTPTR ExtFragPtr = + (EXTENDED_SHIP_FRAGMENTPTR) FragPtr; - cread ((PBYTE)&Index, sizeof (Index), 1, fh); + cread_16 (fh, &ExtFragPtr->ShipInfo.actual_strength); + cread_16 (fh, &ExtFragPtr->ShipInfo.known_strength); + cread_16 (fh, &ExtFragPtr->ShipInfo.known_loc.x); + cread_16 (fh, &ExtFragPtr->ShipInfo.known_loc.y); + cread_8 (fh, &ExtFragPtr->ShipInfo.growth_err_term); + cread_8 (fh, &ExtFragPtr->ShipInfo.func_index); + cread_16 (fh, &ExtFragPtr->ShipInfo.dest_loc.x); + cread_16 (fh, &ExtFragPtr->ShipInfo.dest_loc.y); + cread_16 (fh, NULL); /* alignment padding */ + } - if (pQueue == &GLOBAL (avail_race_q)) - { - hStarShip = GetStarShipFromIndex (pQueue, Index); - FragPtr = (SHIP_FRAGMENTPTR)LockStarShip (pQueue, hStarShip); - Offset = 0; - } - else - { - hStarShip = CloneShipFragment (Index, pQueue, 0); - FragPtr = (SHIP_FRAGMENTPTR)LockStarShip (pQueue, hStarShip); - Offset = (PBYTE)&FragPtr->ShipInfo - - (PBYTE)&FragPtr->RaceDescPtr; - } - - Ptr = ((PBYTE)&FragPtr->ShipInfo) - Offset; - cread ((PBYTE)Ptr, - ((PBYTE)&FragPtr->ShipInfo.race_strings) - Ptr, 1, fh); - - // Hack to retain savegame backwards compatibility, after - // increasing crew_level and max_crew from BYTE to COUNT. - // For the queues that are saved here, a BYTE is large enough. - FragPtr->ShipInfo.max_crew = FragPtr->ShipInfo.dummy_max_crew; - FragPtr->ShipInfo.crew_level = FragPtr->ShipInfo.dummy_crew_level; - - if (Offset == 0) - { - EXTENDED_SHIP_FRAGMENTPTR ExtFragPtr; - - ExtFragPtr = (EXTENDED_SHIP_FRAGMENTPTR)FragPtr; - Ptr = (PBYTE)&ExtFragPtr->ShipInfo.actual_strength; - cread ((PBYTE)Ptr, ((PBYTE)&ExtFragPtr[1]) - Ptr, 1, fh); - } - UnlockStarShip (pQueue, hStarShip); - } while (--num_links); + UnlockStarShip (pQueue, hStarShip); } } @@ -98,278 +204,448 @@ static void LoadEncounter (ENCOUNTERPTR EncounterPtr, DECODE_REF fh) { COUNT i; -#define LOAD_BLOCK(file, start, end) \ - cread((PBYTE) (start), (PBYTE) (end) - (PBYTE) start, \ - 1, (file)) - // An ENCOUNTER structure (indirectly) contains an array of - // SHIP_INFO structure, which is bigger now because of the - // larger type for crew. - // This hack makes sure the savegames format is unchanged. - // The original code consisted of just one line: - // cread ((PBYTE)EncounterPtr, sizeof (*EncounterPtr), 1, fh); - // Load the stuff before the SHIP_INFO array: - LOAD_BLOCK(fh, EncounterPtr, EncounterPtr->SD.ShipList); + cread_ptr (fh); /* useless ptr; HENCOUNTER pred */ + EncounterPtr->pred = 0; + cread_ptr (fh); /* useless ptr; HENCOUNTER succ */ + EncounterPtr->succ = 0; + cread_ptr (fh); /* useless ptr; HELEMENT hElement */ + EncounterPtr->hElement = 0; + cread_16 (fh, &EncounterPtr->transition_state); + cread_16 (fh, &EncounterPtr->origin.x); + cread_16 (fh, &EncounterPtr->origin.y); + cread_16 (fh, &EncounterPtr->radius); + // EXTENDED_STAR_DESC fields + cread_16 (fh, &EncounterPtr->SD.star_pt.x); + cread_16 (fh, &EncounterPtr->SD.star_pt.y); + cread_8 (fh, &EncounterPtr->SD.Type); + cread_8 (fh, &EncounterPtr->SD.Index); + cread_16 (fh, NULL); /* alignment padding */ // Load each entry in the SHIP_INFO array: for (i = 0; i < MAX_HYPER_SHIPS; i++) { - SHIP_INFO *ShipInfo = &EncounterPtr->SD.ShipList[i]; - LOAD_BLOCK(fh, ShipInfo, &ShipInfo->crew_level); - ShipInfo->crew_level = ShipInfo->dummy_crew_level; - ShipInfo->max_crew = ShipInfo->dummy_max_crew; + SHIP_INFOPTR ShipInfo = &EncounterPtr->SD.ShipList[i]; + BYTE tmpb; + + cread_16 (fh, &ShipInfo->ship_flags); + cread_8 (fh, &ShipInfo->var1); + cread_8 (fh, &ShipInfo->var2); + cread_8 (fh, &tmpb); + ShipInfo->crew_level = tmpb; + cread_8 (fh, &tmpb); + ShipInfo->max_crew = tmpb; + cread_8 (fh, &ShipInfo->energy_level); + cread_8 (fh, &ShipInfo->max_energy); + cread_16 (fh, &ShipInfo->loc.x); + cread_16 (fh, &ShipInfo->loc.y); + cread_32 (fh, NULL); /* useless val; STRING race_strings */ + ShipInfo->race_strings = 0; + cread_ptr (fh); /* useless ptr; FRAME icons */ + ShipInfo->icons = 0; + cread_ptr (fh); /* useless ptr; FRAME melee_icon */ + ShipInfo->melee_icon = 0; } // Load the stuff after the SHIP_INFO array: - LOAD_BLOCK(fh, &EncounterPtr->log_x, &EncounterPtr[1]); + cread_32 (fh, &EncounterPtr->log_x); + cread_32 (fh, &EncounterPtr->log_y); +} + +static void +LoadEvent (EVENTPTR EventPtr, DECODE_REF fh) +{ + cread_ptr (fh); /* useless ptr; HEVENT pred */ + EventPtr->pred = 0; + cread_ptr (fh); /* useless ptr; HEVENT succ */ + EventPtr->succ = 0; + cread_8 (fh, &EventPtr->day_index); + cread_8 (fh, &EventPtr->month_index); + cread_16 (fh, &EventPtr->year_index); + cread_8 (fh, &EventPtr->func_index); + cread_8 (fh, NULL); /* padding */ + cread_16 (fh, NULL); /* padding */ +} + +static void +DummyLoadQueue (PQUEUE QueuePtr, DECODE_REF fh) +{ + /* QUEUE should never actually be loaded since it contains + * purely internal representation and the lists + * involved are actually loaded separately */ + (void)QueuePtr; /* silence compiler */ + + /* QUEUE format with QUEUE_TABLE defined -- UQM default */ + cread_ptr (fh); /* HLINK head */ + cread_ptr (fh); /* HLINK tail */ + cread_ptr (fh); /* PBYTE pq_tab */ + cread_ptr (fh); /* HLINK free_list */ + cread_16 (fh, NULL); /* MEM_HANDLE hq_tab */ + cread_16 (fh, NULL); /* COUNT object_size */ + cread_8 (fh, NULL); /* BYTE num_objects */ + + cread_8 (fh, NULL); /* padding */ + cread_16 (fh, NULL); /* padding */ +} + +static void +LoadClockState (PCLOCK_STATE ClockPtr, DECODE_REF fh) +{ + cread_8 (fh, &ClockPtr->day_index); + cread_8 (fh, &ClockPtr->month_index); + cread_16 (fh, &ClockPtr->year_index); + cread_16 (fh, &ClockPtr->tick_count); + cread_16 (fh, &ClockPtr->day_in_ticks); + cread_ptr (fh); /* not loading ptr; Semaphore clock_sem */ + cread_ptr (fh); /* not loading ptr; Task clock_task */ + cread_32 (fh, &ClockPtr->TimeCounter); /* theoretically useless */ + + DummyLoadQueue (&ClockPtr->event_q, fh); +} + +static void +LoadGameState (PGAME_STATE GSPtr, DECODE_REF fh) +{ + DWORD tmpd; + + cread_8 (fh, &GSPtr->cur_state); /* obsolete */ + cread_8 (fh, &GSPtr->glob_flags); + cread_8 (fh, &GSPtr->CrewCost); + cread_8 (fh, &GSPtr->FuelCost); + cread_a8 (fh, GSPtr->ModuleCost, NUM_MODULES); + cread_a8 (fh, GSPtr->ElementWorth, NUM_ELEMENT_CATEGORIES); + cread_ptr (fh); /* not loading ptr; PPRIMITIVE DisplayArray */ + cread_16 (fh, &GSPtr->CurrentActivity); + + cread_16 (fh, NULL); /* CLOCK_STATE alignment padding */ + LoadClockState (&GSPtr->GameClock, fh); + + cread_16 (fh, &GSPtr->autopilot.x); + cread_16 (fh, &GSPtr->autopilot.y); + cread_16 (fh, &GSPtr->ip_location.x); + cread_16 (fh, &GSPtr->ip_location.y); + /* STAMP ShipStamp */ + cread_16 (fh, &GSPtr->ShipStamp.origin.x); + cread_16 (fh, &GSPtr->ShipStamp.origin.y); + cread_32 (fh, &tmpd); /* abused ptr to store DWORD */ + GSPtr->ShipStamp.frame = (FRAME)tmpd; + + /* VELOCITY_DESC velocity */ + cread_16 (fh, &GSPtr->velocity.TravelAngle); + cread_16 (fh, &GSPtr->velocity.vector.width); + cread_16 (fh, &GSPtr->velocity.vector.height); + cread_16 (fh, &GSPtr->velocity.fract.width); + cread_16 (fh, &GSPtr->velocity.fract.height); + cread_16 (fh, &GSPtr->velocity.error.width); + cread_16 (fh, &GSPtr->velocity.error.height); + cread_16 (fh, &GSPtr->velocity.incr.width); + cread_16 (fh, &GSPtr->velocity.incr.height); + cread_16 (fh, NULL); /* VELOCITY_DESC padding */ + + cread_32 (fh, &GSPtr->BattleGroupRef); + + DummyLoadQueue (&GSPtr->avail_race_q, fh); + DummyLoadQueue (&GSPtr->npc_built_ship_q, fh); + DummyLoadQueue (&GSPtr->encounter_q, fh); + DummyLoadQueue (&GSPtr->built_ship_q, fh); + + cread_a8 (fh, GSPtr->GameState, sizeof (GSPtr->GameState)); + + assert (sizeof (GSPtr->GameState) % 4 == 3); + cread_8 (fh, NULL); /* GAME_STATE alignment padding */ } static BOOLEAN -LoadSummary (uio_Stream *in_fp) +LoadSisState (PSIS_STATE SSPtr, PVOID fp) { - // XXX: This function seems to be unused. - SUMMARY_DESC S; + if ( + read_32 (fp, &SSPtr->log_x) != 1 || + read_32 (fp, &SSPtr->log_y) != 1 || + read_32 (fp, &SSPtr->ResUnits) != 1 || + read_32 (fp, &SSPtr->FuelOnBoard) != 1 || + read_16 (fp, &SSPtr->CrewEnlisted) != 1 || + read_16 (fp, &SSPtr->TotalElementMass) != 1 || + read_16 (fp, &SSPtr->TotalBioMass) != 1 || + read_a8 (fp, SSPtr->ModuleSlots, NUM_MODULE_SLOTS) != 1 || + read_a8 (fp, SSPtr->DriveSlots, NUM_DRIVE_SLOTS) != 1 || + read_a8 (fp, SSPtr->JetSlots, NUM_JET_SLOTS) != 1 || + read_8 (fp, &SSPtr->NumLanders) != 1 || + read_a16 (fp, SSPtr->ElementAmounts, NUM_ELEMENT_CATEGORIES) != 1 || - return (ReadResFile (&S, sizeof (S), 1, in_fp) == sizeof (S)); + read_a8 (fp, SSPtr->ShipName, SIS_NAME_SIZE) != 1 || + read_a8 (fp, SSPtr->CommanderName, SIS_NAME_SIZE) != 1 || + read_a8 (fp, SSPtr->PlanetName, SIS_NAME_SIZE) != 1 || + + read_16 (fp, NULL) != 1 /* padding */ + ) + return FALSE; + else + return TRUE; +} + +static BOOLEAN +LoadSummary (SUMMARY_DESC *SummPtr, PVOID fp) +{ + if (!LoadSisState (&SummPtr->SS, fp)) + return FALSE; + + if ( + read_8 (fp, &SummPtr->Activity) != 1 || + read_8 (fp, &SummPtr->Flags) != 1 || + read_8 (fp, &SummPtr->day_index) != 1 || + read_8 (fp, &SummPtr->month_index) != 1 || + read_16 (fp, &SummPtr->year_index) != 1 || + read_8 (fp, &SummPtr->MCreditLo) != 1 || + read_8 (fp, &SummPtr->MCreditHi) != 1 || + read_8 (fp, &SummPtr->NumShips) != 1 || + read_8 (fp, &SummPtr->NumDevices) != 1 || + read_a8 (fp, SummPtr->ShipList, MAX_BUILT_SHIPS) != 1 || + read_a8 (fp, SummPtr->DeviceList, MAX_EXCLUSIVE_DEVICES) != 1 || + + read_16 (fp, NULL) != 1 /* padding */ + ) + return FALSE; + else + return TRUE; +} + +static void +LoadStarDesc (STAR_DESCPTR SDPtr, DECODE_REF fh) +{ + cread_16 (fh, &SDPtr->star_pt.x); + cread_16 (fh, &SDPtr->star_pt.y); + cread_8 (fh, &SDPtr->Type); + cread_8 (fh, &SDPtr->Index); + cread_8 (fh, &SDPtr->Prefix); + cread_8 (fh, &SDPtr->Postfix); } BOOLEAN -LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc) +LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) { uio_Stream *in_fp; - char buf[256], file[PATH_MAX]; + char file[PATH_MAX]; + char buf[256]; + SUMMARY_DESC loc_sd; + GAME_STATE_FILE *fp; + DECODE_REF fh; + COUNT num_links; + STAR_DESC SD; + ACTIVITY Activity; sprintf (file, "starcon2.%02u", which_game); in_fp = res_OpenResFile (saveDir, file, "rb"); - if (in_fp) + if (!in_fp) + return FALSE; + + if (!LoadSummary (&loc_sd, in_fp)) { - GAME_STATE_FILE *fp; - DECODE_REF fh; - COUNT num_links; - Semaphore clock_sem; - Task clock_task; - QUEUE event_q, encounter_q, avail_q, npc_q, player_q; - STAR_DESC SD; - ACTIVITY Activity; - - ReadResFile (buf, sizeof (*summary_desc), 1, in_fp); - - if (summary_desc == 0) - summary_desc = (SUMMARY_DESC *)buf; - else - { - memcpy (summary_desc, buf, sizeof (*summary_desc)); - res_CloseResFile (in_fp); - return TRUE; - } - - // Crude check for big-endian/little-endian incompatibilities. - // year_index is suitable as it's a multi-byte value within - // a specific recognisable range. - if (summary_desc->year_index < START_YEAR || - summary_desc->year_index >= START_YEAR + - YEARS_TO_KOHRAH_VICTORY + 1 /* Utwig intervention */ + - 1 /* time to destroy all races, plenty */ + - 25 /* for cheaters */) - { - log_add (log_Always, "Warning: Savegame corrupt or from an " - "an incompatible platform."); - res_CloseResFile (in_fp); - return FALSE; - } - - GlobData.SIS_state = summary_desc->SS; - - if ((fh = copen (in_fp, FILE_STREAM, STREAM_READ)) == 0) - { - res_CloseResFile (in_fp); - return FALSE; - } - - ReinitQueue (&GLOBAL (GameClock.event_q)); - ReinitQueue (&GLOBAL (encounter_q)); - ReinitQueue (&GLOBAL (npc_built_ship_q)); - ReinitQueue (&GLOBAL (built_ship_q)); - - clock_sem = GLOBAL (GameClock.clock_sem); - clock_task = GLOBAL (GameClock.clock_task); - event_q = GLOBAL (GameClock.event_q); - encounter_q = GLOBAL (encounter_q); - avail_q = GLOBAL (avail_race_q); - npc_q = GLOBAL (npc_built_ship_q); - player_q = GLOBAL (built_ship_q); - - memset ((PBYTE)&GLOBAL (GameState[0]), - 0, sizeof (GLOBAL (GameState))); - Activity = GLOBAL (CurrentActivity); - cread ((PBYTE)&GlobData.Game_state, sizeof (GlobData.Game_state), 1, - fh); - NextActivity = GLOBAL (CurrentActivity); - GLOBAL (CurrentActivity) = Activity; - - GLOBAL (GameClock.clock_sem) = clock_sem; - GLOBAL (GameClock.clock_task) = clock_task; - GLOBAL (GameClock.event_q) = event_q; - GLOBAL (encounter_q) = encounter_q; - GLOBAL (avail_race_q) = avail_q; - GLOBAL (npc_built_ship_q) = npc_q; - GLOBAL (built_ship_q) = player_q; - // It shouldn't be possible to ever save with TimeCounter != 0 - // But if it does happen, it needs to be reset to 0, since on load - // the clock semaphore is gauranteed to be 0 - if (GLOBAL (GameClock.TimeCounter) != 0) - log_add (log_Always, "Warning: Game clock wasn't stopped during " - "save, Savegame may be corrupt!\n"); - GLOBAL (GameClock.TimeCounter) = 0; - - LoadShipQueue (fh, &GLOBAL (avail_race_q), FALSE); - if (!(NextActivity & START_INTERPLANETARY)) - LoadShipQueue (fh, &GLOBAL (npc_built_ship_q), FALSE); - LoadShipQueue (fh, &GLOBAL (built_ship_q), FALSE); - - cread ((PBYTE)&num_links, sizeof (num_links), 1, fh); - { -#ifdef DEBUG_LOAD - log_add (log_Debug, "EVENTS:"); -#endif /* DEBUG_LOAD */ - while (num_links--) - { - HEVENT hEvent; - EVENTPTR EventPtr; - - hEvent = AllocEvent (); - LockEvent (hEvent, &EventPtr); - - cread ((PBYTE)EventPtr, sizeof (*EventPtr), 1, fh); - -#ifdef DEBUG_LOAD - log_add (log_Debug, "\t%u/%u/%u -- %u", - EventPtr->month_index, - EventPtr->day_index, - EventPtr->year_index, - EventPtr->func_index); -#endif /* DEBUG_LOAD */ - UnlockEvent (hEvent); - PutEvent (hEvent); - } - } - - cread ((PBYTE)&num_links, sizeof (num_links), 1, fh); - { - while (num_links--) - { - BYTE i, NumShips; - HENCOUNTER hEncounter; - ENCOUNTERPTR EncounterPtr; - - hEncounter = AllocEncounter (); - LockEncounter (hEncounter, &EncounterPtr); - - LoadEncounter(EncounterPtr, fh); - EncounterPtr->hElement = 0; - NumShips = LONIBBLE (EncounterPtr->SD.Index); - for (i = 0; i < NumShips; ++i) - { - HSTARSHIP hStarShip; - SHIP_FRAGMENTPTR TemplatePtr; - - hStarShip = GetStarShipFromIndex ( - &GLOBAL (avail_race_q), - EncounterPtr->SD.ShipList[i].var1); - TemplatePtr = (SHIP_FRAGMENTPTR)LockStarShip ( - &GLOBAL (avail_race_q), hStarShip); - EncounterPtr->SD.ShipList[i].race_strings = - TemplatePtr->ShipInfo.race_strings; - EncounterPtr->SD.ShipList[i].icons = - TemplatePtr->ShipInfo.icons; - EncounterPtr->SD.ShipList[i].melee_icon = - TemplatePtr->ShipInfo.melee_icon; - UnlockStarShip (&GLOBAL (avail_race_q), hStarShip); - } - - UnlockEncounter (hEncounter); - PutEncounter (hEncounter); - } - } - - fp = OpenStateFile (STARINFO_FILE, "wb"); - if (fp) - { - DWORD flen; - - cread ((PBYTE)&flen, sizeof (flen), 1, fh); - while (flen) - { - COUNT num_bytes; - - num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; - cread ((PBYTE)buf, num_bytes, 1, fh); - WriteStateFile (buf, num_bytes, 1, fp); - - flen -= num_bytes; - } - CloseStateFile (fp); - } - - fp = OpenStateFile (DEFGRPINFO_FILE, "wb"); - if (fp) - { - DWORD flen; - - cread ((PBYTE)&flen, sizeof (flen), 1, fh); - while (flen) - { - COUNT num_bytes; - - num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; - cread ((PBYTE)buf, num_bytes, 1, fh); - WriteStateFile (buf, num_bytes, 1, fp); - - flen -= num_bytes; - } - CloseStateFile (fp); - } - - fp = OpenStateFile (RANDGRPINFO_FILE, "wb"); - if (fp) - { - DWORD flen; - - cread ((PBYTE)&flen, sizeof (flen), 1, fh); - while (flen) - { - COUNT num_bytes; - - num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; - cread ((PBYTE)buf, num_bytes, 1, fh); - WriteStateFile (buf, num_bytes, 1, fp); - - flen -= num_bytes; - } - CloseStateFile (fp); - } - - cread ((PBYTE)&SD, sizeof (SD), 1, fh); - - cclose (fh); + log_add (log_Always, "Warning: Savegame is corrupt"); res_CloseResFile (in_fp); + return FALSE; + } - EncounterGroup = 0; - EncounterRace = -1; - - ReinitQueue (&race_q[0]); - ReinitQueue (&race_q[1]); - CurStarDescPtr = FindStar (NULL_PTR, &SD.star_pt, 0, 0); - if (!(NextActivity & START_ENCOUNTER) - && LOBYTE (NextActivity) == IN_INTERPLANETARY) - NextActivity |= START_INTERPLANETARY; - - GLOBAL (DisplayArray) = DisplayArray; - + if (!SummPtr) + { + SummPtr = &loc_sd; + } + else + { // only need summary for displaying to user + memcpy (SummPtr, &loc_sd, sizeof (*SummPtr)); + res_CloseResFile (in_fp); return TRUE; } - return FALSE; + // Crude check for big-endian/little-endian incompatibilities. + // year_index is suitable as it's a multi-byte value within + // a specific recognisable range. + if (SummPtr->year_index < START_YEAR || + SummPtr->year_index >= START_YEAR + + YEARS_TO_KOHRAH_VICTORY + 1 /* Utwig intervention */ + + 1 /* time to destroy all races, plenty */ + + 25 /* for cheaters */) + { + log_add (log_Always, "Warning: Savegame corrupt or from an " + "an incompatible platform."); + res_CloseResFile (in_fp); + return FALSE; + } + + GlobData.SIS_state = SummPtr->SS; + + if ((fh = copen (in_fp, FILE_STREAM, STREAM_READ)) == 0) + { + res_CloseResFile (in_fp); + return FALSE; + } + + ReinitQueue (&GLOBAL (GameClock.event_q)); + ReinitQueue (&GLOBAL (encounter_q)); + ReinitQueue (&GLOBAL (npc_built_ship_q)); + ReinitQueue (&GLOBAL (built_ship_q)); + + memset (&GLOBAL (GameState[0]), 0, sizeof (GLOBAL (GameState))); + Activity = GLOBAL (CurrentActivity); + LoadGameState (&GlobData.Game_state, fh); + NextActivity = GLOBAL (CurrentActivity); + GLOBAL (CurrentActivity) = Activity; + + // It shouldn't be possible to ever save with TimeCounter != 0 + // But if it does happen, it needs to be reset to 0, since on load + // the clock semaphore is gauranteed to be 0 + if (GLOBAL (GameClock.TimeCounter) != 0) + log_add (log_Always, "Warning: Game clock wasn't stopped during " + "save, Savegame may be corrupt!\n"); + GLOBAL (GameClock.TimeCounter) = 0; + + LoadShipQueue (fh, &GLOBAL (avail_race_q), FALSE); + if (!(NextActivity & START_INTERPLANETARY)) + LoadShipQueue (fh, &GLOBAL (npc_built_ship_q), FALSE); + LoadShipQueue (fh, &GLOBAL (built_ship_q), FALSE); + + // Load the game events (compressed) + cread_16 (fh, &num_links); + { +#ifdef DEBUG_LOAD + log_add (log_Debug, "EVENTS:"); +#endif /* DEBUG_LOAD */ + while (num_links--) + { + HEVENT hEvent; + EVENTPTR EventPtr; + + hEvent = AllocEvent (); + LockEvent (hEvent, &EventPtr); + + LoadEvent (EventPtr, fh); + +#ifdef DEBUG_LOAD + log_add (log_Debug, "\t%u/%u/%u -- %u", + EventPtr->month_index, + EventPtr->day_index, + EventPtr->year_index, + EventPtr->func_index); +#endif /* DEBUG_LOAD */ + UnlockEvent (hEvent); + PutEvent (hEvent); + } + } + + // Load the encounters (black globes in HS/QS (compressed)) + cread_16 (fh, &num_links); + { + while (num_links--) + { + BYTE i, NumShips; + HENCOUNTER hEncounter; + ENCOUNTERPTR EncounterPtr; + + hEncounter = AllocEncounter (); + LockEncounter (hEncounter, &EncounterPtr); + + LoadEncounter (EncounterPtr, fh); + + NumShips = LONIBBLE (EncounterPtr->SD.Index); + for (i = 0; i < NumShips; ++i) + { + HSTARSHIP hStarShip; + SHIP_FRAGMENTPTR TemplatePtr; + + hStarShip = GetStarShipFromIndex ( + &GLOBAL (avail_race_q), + EncounterPtr->SD.ShipList[i].var1); + TemplatePtr = (SHIP_FRAGMENTPTR)LockStarShip ( + &GLOBAL (avail_race_q), hStarShip); + EncounterPtr->SD.ShipList[i].race_strings = + TemplatePtr->ShipInfo.race_strings; + EncounterPtr->SD.ShipList[i].icons = + TemplatePtr->ShipInfo.icons; + EncounterPtr->SD.ShipList[i].melee_icon = + TemplatePtr->ShipInfo.melee_icon; + UnlockStarShip (&GLOBAL (avail_race_q), hStarShip); + } + + UnlockEncounter (hEncounter); + PutEncounter (hEncounter); + } + } + + // Copy the star info file from the compressed stream + fp = OpenStateFile (STARINFO_FILE, "wb"); + if (fp) + { + DWORD flen; + + cread_32 (fh, &flen); + while (flen) + { + COUNT num_bytes; + + num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; + cread (buf, num_bytes, 1, fh); + WriteStateFile (buf, num_bytes, 1, fp); + + flen -= num_bytes; + } + CloseStateFile (fp); + } + + // Copy the defined groupinfo file from the compressed stream + fp = OpenStateFile (DEFGRPINFO_FILE, "wb"); + if (fp) + { + DWORD flen; + + cread_32 (fh, &flen); + while (flen) + { + COUNT num_bytes; + + num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; + cread (buf, num_bytes, 1, fh); + WriteStateFile (buf, num_bytes, 1, fp); + + flen -= num_bytes; + } + CloseStateFile (fp); + } + + // Copy the random groupinfo file from the compressed stream + fp = OpenStateFile (RANDGRPINFO_FILE, "wb"); + if (fp) + { + DWORD flen; + + cread_32 (fh, &flen); + while (flen) + { + COUNT num_bytes; + + num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; + cread (buf, num_bytes, 1, fh); + WriteStateFile (buf, num_bytes, 1, fp); + + flen -= num_bytes; + } + CloseStateFile (fp); + } + + LoadStarDesc (&SD, fh); + + cclose (fh); + res_CloseResFile (in_fp); + + EncounterGroup = 0; + EncounterRace = -1; + + ReinitQueue (&race_q[0]); + ReinitQueue (&race_q[1]); + CurStarDescPtr = FindStar (NULL, &SD.star_pt, 0, 0); + if (!(NextActivity & START_ENCOUNTER) + && LOBYTE (NextActivity) == IN_INTERPLANETARY) + NextActivity |= START_INTERPLANETARY; + + return TRUE; } diff --git a/sc2/src/sc2code/races.h b/sc2/src/sc2code/races.h index 86e0640f6..0003311e8 100644 --- a/sc2/src/sc2code/races.h +++ b/sc2/src/sc2code/races.h @@ -101,10 +101,9 @@ typedef struct { UWORD ship_flags; BYTE var1, var2; - BYTE dummy_crew_level, dummy_max_crew; - /* Necessary for savegame backwards compatibility. - * Unused during the game, only used during save/load. - */ + COUNT crew_level, max_crew; + /* For ships in npc_built_ship_q, the value INFINITE_FLEET for + * crew_level indicates an infinite number of ships. */ BYTE energy_level, max_energy; POINT loc; @@ -115,9 +114,6 @@ typedef struct STRING race_strings; FRAME icons, melee_icon; - COUNT crew_level, max_crew; - /* For ships in npc_built_ship_q, the value INFINITE_FLEET for - * crew_level indicates an infinite number of ships. */ #define INFINITE_FLEET ((COUNT) ~0) } SHIP_INFO; typedef SHIP_INFO *PSHIP_INFO; @@ -164,10 +160,9 @@ typedef struct BYTE days_left; /* Days left before the fleet reachers 'dest_loc'. */ BYTE growth_fract; - BYTE dummy_crew_level, dummy_max_crew; - /* Necessary for savegame backwards compatibility. - * Unused during the game, only used during save/load. - */ + COUNT crew_level, max_crew; + /* For ships in npc_built_ship_q, the value INFINITE_FLEET for + * crew_level indicates an infinite number of ships. */ BYTE energy_level, max_energy; POINT loc; /* Location of the fleet (center) */ @@ -175,9 +170,6 @@ typedef struct STRING race_strings; /* Race specific strings, see doc/devel/racestrings. */ FRAME icons, melee_icon; - COUNT crew_level, max_crew; - /* For ships in npc_built_ship_q, the value INFINITE_FLEET for - * crew_level indicates an infinite number of ships. */ /* -== The fields below this line are included in savegames. ==- */ diff --git a/sc2/src/sc2code/save.c b/sc2/src/sc2code/save.c index 6380df59e..3e83a2211 100644 --- a/sc2/src/sc2code/save.c +++ b/sc2/src/sc2code/save.c @@ -16,6 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include + #include "save.h" #include "build.h" @@ -35,6 +37,78 @@ #include "libs/log.h" +// XXX: these should handle endian conversions later +static inline COUNT +cwrite_8 (DECODE_REF fh, BYTE v) +{ + return cwrite (&v, 1, 1, fh); +} + +static inline COUNT +cwrite_16 (DECODE_REF fh, UWORD v) +{ + return cwrite (&v, 2, 1, fh); +} + +static inline COUNT +cwrite_32 (DECODE_REF fh, DWORD v) +{ + return cwrite (&v, 4, 1, fh); +} + +static inline COUNT +cwrite_ptr (DECODE_REF fh) +{ + return cwrite_32 (fh, 0); /* ptrs are useless in saves */ +} + +static inline COUNT +cwrite_a8 (DECODE_REF fh, PBYTE ar, COUNT count) +{ + return cwrite (ar, 1, count, fh) == count; +} + +static inline COUNT +write_8 (PVOID fp, BYTE v) +{ + return WriteResFile (&v, 1, 1, fp); +} + +static inline COUNT +write_16 (PVOID fp, UWORD v) +{ + return WriteResFile (&v, 2, 1, fp); +} + +static inline COUNT +write_32 (PVOID fp, DWORD v) +{ + return WriteResFile (&v, 4, 1, fp); +} + +static inline COUNT +write_ptr (PVOID fp) +{ + return write_32 (fp, 0); /* ptrs are useless in saves */ +} + +static inline COUNT +write_a8 (PVOID fp, PBYTE ar, COUNT count) +{ + return WriteResFile (ar, 1, count, fp) == count; +} + +static inline COUNT +write_a16 (PVOID fp, PUWORD ar, COUNT count) +{ + for ( ; count > 0; --count, ++ar) + { + if (write_16 (fp, *ar) != 1) + return 0; + } + return 1; +} + static void SaveShipQueue (DECODE_REF fh, PQUEUE pQueue) { @@ -43,67 +117,62 @@ SaveShipQueue (DECODE_REF fh, PQUEUE pQueue) // Write the number of entries in the queue. num_links = CountLinks (pQueue); - cwrite ((PBYTE)&num_links, sizeof (num_links), 1, fh); + cwrite_16 (fh, num_links); hStarShip = GetHeadLink (pQueue); while (num_links--) { HSTARSHIP hNextShip; SHIP_FRAGMENTPTR FragPtr; - COUNT Index, Offset; - PBYTE Ptr; + COUNT Index; FragPtr = (SHIP_FRAGMENTPTR)LockStarShip (pQueue, hStarShip); hNextShip = _GetSuccLink (FragPtr); if (pQueue == &GLOBAL (avail_race_q)) - { Index = GetIndexFromStarShip (pQueue, hStarShip); // The index is the position in the queue. - Offset = 0; - } else - { Index = GET_RACE_ID (FragPtr); - Offset = (PBYTE)&FragPtr->ShipInfo - - (PBYTE)&FragPtr->RaceDescPtr; - } // Write the number identifying this ship type. // See races.h; look for the enum containing NUM_AVAILABLE_RACES. - cwrite ((PBYTE)&Index, sizeof (Index), 1, fh); + cwrite_16 (fh, Index); - // Hack to retain savegame backwards compatibility, after - // increasing crew_level and max_crew from BYTE to COUNT. - // For the queues that are saved here, a BYTE is large enough. - FragPtr->ShipInfo.dummy_max_crew = FragPtr->ShipInfo.max_crew; - FragPtr->ShipInfo.dummy_crew_level = FragPtr->ShipInfo.crew_level; - - // Write part of FragPtr, starting with FragPtr->ShipInfo for - // GLOBAL(avail_race_q), and FragPtr->RaceDescPtr for other queues. - // When FragPtr->RaceDescPtr is saved, it does not actually - // contain a pointer (see the definition of SHIP_FRAGMENT). - // This is only so because SaveShipQueue() is only ever called with - // GLOBAL_avail_race_q), GLOBAL(built_ship_q) and - // GLOBAL(npc_built_ship_q). - Ptr = ((PBYTE)&FragPtr->ShipInfo) - Offset; - cwrite ((PBYTE)Ptr, ((PBYTE)&FragPtr->ShipInfo.race_strings) - Ptr, - 1, fh); + if (pQueue != &GLOBAL (avail_race_q)) + { // queues other than avail_race_q save SHIP_FRAGMENT elements + // Write SHIP_FRAGMENT elements + cwrite_16 (fh, FragPtr->s.Player); + cwrite_8 (fh, FragPtr->s.Captain); + cwrite_8 (fh, 0); /* padding */ + } + // Write SHIP_INFO elements + cwrite_16 (fh, FragPtr->ShipInfo.ship_flags); + cwrite_8 (fh, FragPtr->ShipInfo.var1); + cwrite_8 (fh, FragPtr->ShipInfo.var2); + cwrite_8 (fh, FragPtr->ShipInfo.crew_level); + cwrite_8 (fh, FragPtr->ShipInfo.max_crew); + cwrite_8 (fh, FragPtr->ShipInfo.energy_level); + cwrite_8 (fh, FragPtr->ShipInfo.max_energy); + cwrite_16 (fh, FragPtr->ShipInfo.loc.x); + cwrite_16 (fh, FragPtr->ShipInfo.loc.y); - if (Offset == 0) + if (pQueue == &GLOBAL (avail_race_q)) { - // The queue being saved is avail_race_q. - // It contains information not about specific ships, but about - // a race. What is saved is everything in the EXTENDED_SHIP_INFO - // structure from the field 'actual_strength' onwards, - // for each of the races. - EXTENDED_SHIP_FRAGMENTPTR ExtFragPtr; + // avail_race_q contains information not about specific ships, + // but about a race. + EXTENDED_SHIP_FRAGMENTPTR ExtFragPtr = + (EXTENDED_SHIP_FRAGMENTPTR) FragPtr; - ExtFragPtr = (EXTENDED_SHIP_FRAGMENTPTR)FragPtr; - Ptr = (PBYTE)&ExtFragPtr->ShipInfo.actual_strength; - cwrite ((PBYTE)Ptr, ((PBYTE)&ExtFragPtr[1]) - Ptr, 1, fh); - // XXX: This saves padding too, which may contain - // garbage. + cwrite_16 (fh, ExtFragPtr->ShipInfo.actual_strength); + cwrite_16 (fh, ExtFragPtr->ShipInfo.known_strength); + cwrite_16 (fh, ExtFragPtr->ShipInfo.known_loc.x); + cwrite_16 (fh, ExtFragPtr->ShipInfo.known_loc.y); + cwrite_8 (fh, ExtFragPtr->ShipInfo.growth_err_term); + cwrite_8 (fh, ExtFragPtr->ShipInfo.func_index); + cwrite_16 (fh, ExtFragPtr->ShipInfo.dest_loc.x); + cwrite_16 (fh, ExtFragPtr->ShipInfo.dest_loc.y); + cwrite_16 (fh, 0); /* alignment padding */ } UnlockStarShip (pQueue, hStarShip); @@ -115,59 +184,234 @@ static void SaveEncounter (ENCOUNTERPTR EncounterPtr, DECODE_REF fh) { COUNT i; -#define SAVE_BLOCK(file, start, end) \ - cwrite((PBYTE) (start), (PBYTE) (end) - (PBYTE) start, \ - 1, (file)) - // An ENCOUNTER structure (indirectly) contains an array of - // SHIP_INFO structure, which is bigger now because of the - // larger type for crew. - // This hack makes sure the savegames format is unchanged. - // The original code consisted of jsut one line: - // cwrite ((PBYTE)EncounterPtr, sizeof (*EncounterPtr), 1, fh); - // Save the stuff before the SHIP_INFO array: - SAVE_BLOCK(fh, EncounterPtr, EncounterPtr->SD.ShipList); + cwrite_ptr (fh); /* useless ptr; HENCOUNTER pred */ + cwrite_ptr (fh); /* useless ptr; HENCOUNTER succ */ + cwrite_ptr (fh); /* useless ptr; HELEMENT hElement */ + cwrite_16 (fh, EncounterPtr->transition_state); + cwrite_16 (fh, EncounterPtr->origin.x); + cwrite_16 (fh, EncounterPtr->origin.y); + cwrite_16 (fh, EncounterPtr->radius); + // EXTENDED_STAR_DESC fields + cwrite_16 (fh, EncounterPtr->SD.star_pt.x); + cwrite_16 (fh, EncounterPtr->SD.star_pt.y); + cwrite_8 (fh, EncounterPtr->SD.Type); + cwrite_8 (fh, EncounterPtr->SD.Index); + cwrite_16 (fh, 0); /* alignment padding */ // Save each entry in the SHIP_INFO array: for (i = 0; i < MAX_HYPER_SHIPS; i++) { - SHIP_INFO *ShipInfo = &EncounterPtr->SD.ShipList[i]; - ShipInfo->dummy_crew_level = (BYTE) ShipInfo->crew_level; - ShipInfo->dummy_max_crew = (BYTE) ShipInfo->max_crew; - SAVE_BLOCK(fh, ShipInfo, &ShipInfo->crew_level); + SHIP_INFOPTR ShipInfo = &EncounterPtr->SD.ShipList[i]; + + cwrite_16 (fh, ShipInfo->ship_flags); + cwrite_8 (fh, ShipInfo->var1); + cwrite_8 (fh, ShipInfo->var2); + cwrite_8 (fh, ShipInfo->crew_level); + cwrite_8 (fh, ShipInfo->max_crew); + cwrite_8 (fh, ShipInfo->energy_level); + cwrite_8 (fh, ShipInfo->max_energy); + cwrite_16 (fh, ShipInfo->loc.x); + cwrite_16 (fh, ShipInfo->loc.y); + cwrite_32 (fh, 0); /* useless val; STRING race_strings */ + cwrite_ptr (fh); /* useless ptr; FRAME icons */ + cwrite_ptr (fh); /* useless ptr; FRAME melee_icon */ } // Save the stuff after the SHIP_INFO array: - SAVE_BLOCK(fh, &EncounterPtr->log_x, &EncounterPtr[1]); + cwrite_32 (fh, EncounterPtr->log_x); + cwrite_32 (fh, EncounterPtr->log_y); } static void -PrepareSummary (SUMMARY_DESC *summary_desc) +SaveEvent (EVENTPTR EventPtr, DECODE_REF fh) { - summary_desc->SS = GlobData.SIS_state; + cwrite_ptr (fh); /* useless ptr; HEVENT pred */ + cwrite_ptr (fh); /* useless ptr; HEVENT succ */ + cwrite_8 (fh, EventPtr->day_index); + cwrite_8 (fh, EventPtr->month_index); + cwrite_16 (fh, EventPtr->year_index); + cwrite_8 (fh, EventPtr->func_index); + cwrite_8 (fh, 0); /* padding */ + cwrite_16 (fh, 0); /* padding */ +} - switch (summary_desc->Activity = LOBYTE (GLOBAL (CurrentActivity))) +static void +DummySaveQueue (PQUEUE QueuePtr, DECODE_REF fh) +{ + /* QUEUE should never actually be saved since it contains + * purely internal representation and the lists + * involved are actually saved separately */ + (void)QueuePtr; /* silence compiler */ + + /* QUEUE format with QUEUE_TABLE defined -- UQM default */ + cwrite_ptr (fh); /* HLINK head */ + cwrite_ptr (fh); /* HLINK tail */ + cwrite_ptr (fh); /* PBYTE pq_tab */ + cwrite_ptr (fh); /* HLINK free_list */ + cwrite_16 (fh, 0); /* MEM_HANDLE hq_tab */ + cwrite_16 (fh, 0); /* COUNT object_size */ + cwrite_8 (fh, 0); /* BYTE num_objects */ + + cwrite_8 (fh, 0); /* padding */ + cwrite_16 (fh, 0); /* padding */ +} + +static void +SaveClockState (PCLOCK_STATE ClockPtr, DECODE_REF fh) +{ + cwrite_8 (fh, ClockPtr->day_index); + cwrite_8 (fh, ClockPtr->month_index); + cwrite_16 (fh, ClockPtr->year_index); + cwrite_16 (fh, ClockPtr->tick_count); + cwrite_16 (fh, ClockPtr->day_in_ticks); + cwrite_ptr (fh); /* useless ptr; Semaphore clock_sem */ + cwrite_ptr (fh); /* useless ptr; Task clock_task */ + cwrite_32 (fh, ClockPtr->TimeCounter); /* theoretically useless */ + + DummySaveQueue (&ClockPtr->event_q, fh); +} + +static void +SaveGameState (PGAME_STATE GSPtr, DECODE_REF fh) +{ + cwrite_8 (fh, 0); /* obsolete; BYTE cur_state */ + cwrite_8 (fh, GSPtr->glob_flags); + cwrite_8 (fh, GSPtr->CrewCost); + cwrite_8 (fh, GSPtr->FuelCost); + cwrite_a8 (fh, GSPtr->ModuleCost, NUM_MODULES); + cwrite_a8 (fh, GSPtr->ElementWorth, NUM_ELEMENT_CATEGORIES); + cwrite_ptr (fh); /* useless ptr; PPRIMITIVE DisplayArray */ + cwrite_16 (fh, GSPtr->CurrentActivity); + + cwrite_16 (fh, 0); /* CLOCK_STATE alignment padding */ + SaveClockState (&GSPtr->GameClock, fh); + + cwrite_16 (fh, GSPtr->autopilot.x); + cwrite_16 (fh, GSPtr->autopilot.y); + cwrite_16 (fh, GSPtr->ip_location.x); + cwrite_16 (fh, GSPtr->ip_location.y); + /* STAMP ShipStamp */ + cwrite_16 (fh, GSPtr->ShipStamp.origin.x); + cwrite_16 (fh, GSPtr->ShipStamp.origin.y); + cwrite_32 (fh, (DWORD)GSPtr->ShipStamp.frame); /* abused ptr to store DWORD */ + /* VELOCITY_DESC velocity */ + cwrite_16 (fh, GSPtr->velocity.TravelAngle); + cwrite_16 (fh, GSPtr->velocity.vector.width); + cwrite_16 (fh, GSPtr->velocity.vector.height); + cwrite_16 (fh, GSPtr->velocity.fract.width); + cwrite_16 (fh, GSPtr->velocity.fract.height); + cwrite_16 (fh, GSPtr->velocity.error.width); + cwrite_16 (fh, GSPtr->velocity.error.height); + cwrite_16 (fh, GSPtr->velocity.incr.width); + cwrite_16 (fh, GSPtr->velocity.incr.height); + cwrite_16 (fh, 0); /* VELOCITY_DESC padding */ + + cwrite_32 (fh, GSPtr->BattleGroupRef); + + DummySaveQueue (&GSPtr->avail_race_q, fh); + DummySaveQueue (&GSPtr->npc_built_ship_q, fh); + DummySaveQueue (&GSPtr->encounter_q, fh); + DummySaveQueue (&GSPtr->built_ship_q, fh); + + cwrite_a8 (fh, GSPtr->GameState, sizeof (GSPtr->GameState)); + + assert (sizeof (GSPtr->GameState) % 4 == 3); + cwrite_8 (fh, 0); /* GAME_STATE alignment padding */ +} + +static BOOLEAN +SaveSisState (PSIS_STATE SSPtr, PVOID fp) +{ + if ( + write_32 (fp, SSPtr->log_x) != 1 || + write_32 (fp, SSPtr->log_y) != 1 || + write_32 (fp, SSPtr->ResUnits) != 1 || + write_32 (fp, SSPtr->FuelOnBoard) != 1 || + write_16 (fp, SSPtr->CrewEnlisted) != 1 || + write_16 (fp, SSPtr->TotalElementMass) != 1 || + write_16 (fp, SSPtr->TotalBioMass) != 1 || + write_a8 (fp, SSPtr->ModuleSlots, NUM_MODULE_SLOTS) != 1 || + write_a8 (fp, SSPtr->DriveSlots, NUM_DRIVE_SLOTS) != 1 || + write_a8 (fp, SSPtr->JetSlots, NUM_JET_SLOTS) != 1 || + write_8 (fp, SSPtr->NumLanders) != 1 || + write_a16 (fp, SSPtr->ElementAmounts, NUM_ELEMENT_CATEGORIES) != 1 || + + write_a8 (fp, SSPtr->ShipName, SIS_NAME_SIZE) != 1 || + write_a8 (fp, SSPtr->CommanderName, SIS_NAME_SIZE) != 1 || + write_a8 (fp, SSPtr->PlanetName, SIS_NAME_SIZE) != 1 || + + write_16 (fp, 0) != 1 /* padding */ + ) + return FALSE; + else + return TRUE; +} + +static BOOLEAN +SaveSummary (SUMMARY_DESC *SummPtr, PVOID fp) +{ + if (!SaveSisState (&SummPtr->SS, fp)) + return FALSE; + + if ( + write_8 (fp, SummPtr->Activity) != 1 || + write_8 (fp, SummPtr->Flags) != 1 || + write_8 (fp, SummPtr->day_index) != 1 || + write_8 (fp, SummPtr->month_index) != 1 || + write_16 (fp, SummPtr->year_index) != 1 || + write_8 (fp, SummPtr->MCreditLo) != 1 || + write_8 (fp, SummPtr->MCreditHi) != 1 || + write_8 (fp, SummPtr->NumShips) != 1 || + write_8 (fp, SummPtr->NumDevices) != 1 || + write_a8 (fp, SummPtr->ShipList, MAX_BUILT_SHIPS) != 1 || + write_a8 (fp, SummPtr->DeviceList, MAX_EXCLUSIVE_DEVICES) != 1 || + + write_16 (fp, 0) != 1 /* padding */ + ) + return FALSE; + else + return TRUE; +} + +static void +SaveStarDesc (STAR_DESCPTR SDPtr, DECODE_REF fh) +{ + cwrite_16 (fh, SDPtr->star_pt.x); + cwrite_16 (fh, SDPtr->star_pt.y); + cwrite_8 (fh, SDPtr->Type); + cwrite_8 (fh, SDPtr->Index); + cwrite_8 (fh, SDPtr->Prefix); + cwrite_8 (fh, SDPtr->Postfix); +} + +static void +PrepareSummary (SUMMARY_DESC *SummPtr) +{ + SummPtr->SS = GlobData.SIS_state; + + switch (SummPtr->Activity = LOBYTE (GLOBAL (CurrentActivity))) { case IN_HYPERSPACE: if (GET_GAME_STATE (ARILOU_SPACE_SIDE) > 1) - summary_desc->Activity = IN_QUASISPACE; + SummPtr->Activity = IN_QUASISPACE; break; case IN_INTERPLANETARY: if (GET_GAME_STATE (GLOBAL_FLAGS_AND_DATA) == (BYTE)~0) - summary_desc->Activity = IN_STARBASE; + SummPtr->Activity = IN_STARBASE; else if (pSolarSysState && pSolarSysState->MenuState.Initialized >= 3) - summary_desc->Activity = IN_PLANET_ORBIT; + SummPtr->Activity = IN_PLANET_ORBIT; break; } - summary_desc->MCreditLo = GET_GAME_STATE (MELNORME_CREDIT0); - summary_desc->MCreditHi = GET_GAME_STATE (MELNORME_CREDIT1); + SummPtr->MCreditLo = GET_GAME_STATE (MELNORME_CREDIT0); + SummPtr->MCreditHi = GET_GAME_STATE (MELNORME_CREDIT1); { HSTARSHIP hStarShip, hNextShip; - for (hStarShip = GetHeadLink (&GLOBAL (built_ship_q)), summary_desc->NumShips = 0; - hStarShip; hStarShip = hNextShip, ++summary_desc->NumShips) + for (hStarShip = GetHeadLink (&GLOBAL (built_ship_q)), SummPtr->NumShips = 0; + hStarShip; hStarShip = hNextShip, ++SummPtr->NumShips) { SHIP_FRAGMENTPTR StarShipPtr; @@ -175,26 +419,26 @@ PrepareSummary (SUMMARY_DESC *summary_desc) &GLOBAL (built_ship_q), hStarShip ); hNextShip = _GetSuccLink (StarShipPtr); - summary_desc->ShipList[summary_desc->NumShips] = GET_RACE_ID (StarShipPtr); + SummPtr->ShipList[SummPtr->NumShips] = GET_RACE_ID (StarShipPtr); UnlockStarShip (&GLOBAL (built_ship_q), hStarShip); } } - summary_desc->NumDevices = InventoryDevices (summary_desc->DeviceList); + SummPtr->NumDevices = InventoryDevices (SummPtr->DeviceList); - summary_desc->Flags = GET_GAME_STATE (LANDER_SHIELDS) + SummPtr->Flags = GET_GAME_STATE (LANDER_SHIELDS) | (GET_GAME_STATE (IMPROVED_LANDER_SPEED) << (4 + 0)) | (GET_GAME_STATE (IMPROVED_LANDER_CARGO) << (4 + 1)) | (GET_GAME_STATE (IMPROVED_LANDER_SHOT) << (4 + 2)) | ((GET_GAME_STATE (CHMMR_BOMB_STATE) < 2 ? 0 : 1) << (4 + 3)); - summary_desc->day_index = GLOBAL (GameClock.day_index); - summary_desc->month_index = GLOBAL (GameClock.month_index); - summary_desc->year_index = GLOBAL (GameClock.year_index); + SummPtr->day_index = GLOBAL (GameClock.day_index); + SummPtr->month_index = GLOBAL (GameClock.month_index); + SummPtr->year_index = GLOBAL (GameClock.year_index); } static void -SaveProblemMessage (STAMP *MsgStamp) +SaveProblemMessage (PSTAMP MsgStamp) { #define MAX_MSG_LINES 1 RECT r; @@ -299,7 +543,7 @@ SaveProblem (void) // This function first writes to a memory file, and then writes the whole // lot to the actual save file at once. BOOLEAN -SaveGame (COUNT which_game, SUMMARY_DESC *summary_desc) +SaveGame (COUNT which_game, SUMMARY_DESC *SummPtr) { BOOLEAN success, made_room; PVOID out_fp; @@ -346,6 +590,8 @@ RetrySave: else memset (&SD, 0, sizeof (SD)); + // XXX: Backup: ShipStamp.frame is abused to store DWORD info + // SaveFlagshipState() overwrites it with a DWORD value frame = GLOBAL (ShipStamp.frame); pt = GLOBAL (ip_location); SaveFlagshipState (); @@ -354,10 +600,10 @@ RetrySave: & (START_ENCOUNTER | START_INTERPLANETARY))) PutGroupInfo (GROUPS_RANDOM, GROUP_SAVE_IP); - cwrite ((PBYTE)&GlobData.Game_state, sizeof (GlobData.Game_state), - 1, fh); + SaveGameState (&GlobData.Game_state, fh); GLOBAL (ip_location) = pt; + // XXX: Restore: ShipStamp.frame is abused to store DWORD info GLOBAL (ShipStamp.frame) = frame; SaveShipQueue (fh, &GLOBAL (avail_race_q)); @@ -367,7 +613,7 @@ RetrySave: // Save the number of game events (compressed). num_links = CountLinks (&GLOBAL (GameClock.event_q)); - cwrite ((PBYTE)&num_links, sizeof (num_links), 1, fh); + cwrite_16 (fh, num_links); // Save the game events themselves (compressed): { HEVENT hEvent; @@ -381,7 +627,7 @@ RetrySave: LockEvent (hEvent, &EventPtr); hNextEvent = GetSuccEvent (EventPtr); - cwrite ((PBYTE)EventPtr, sizeof (*EventPtr), 1, fh); + SaveEvent (EventPtr, fh); UnlockEvent (hEvent); hEvent = hNextEvent; @@ -391,7 +637,7 @@ RetrySave: // Save the number of encounters (black globes in HS/QS (compressed)) num_links = CountLinks (&GLOBAL (encounter_q)); // Save the encounters themselves (compressed): - cwrite ((PBYTE)&num_links, sizeof (num_links), 1, fh); + cwrite_16 (fh, num_links); { HENCOUNTER hEncounter; @@ -404,7 +650,7 @@ RetrySave: LockEncounter (hEncounter, &EncounterPtr); hNextEncounter = GetSuccEncounter (EncounterPtr); - SaveEncounter(EncounterPtr, fh); + SaveEncounter (EncounterPtr, fh); UnlockEncounter (hEncounter); hEncounter = hNextEncounter; @@ -416,54 +662,55 @@ RetrySave: if (fp) { flen = LengthStateFile (fp); - // (DWORD) Write the uncompressed size. - cwrite ((PBYTE)&flen, sizeof (flen), 1, fh); + // Write the uncompressed size. + cwrite_32 (fh, flen); while (flen) { COUNT num_bytes; num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; ReadStateFile (buf, num_bytes, 1, fp); - cwrite ((PBYTE)buf, num_bytes, 1, fh); + cwrite (buf, num_bytes, 1, fh); flen -= num_bytes; } CloseStateFile (fp); } - // Copy the ? groupinfo file into the memory file (compressed). + // Copy the defined groupinfo file into the memory file (compressed) fp = OpenStateFile (DEFGRPINFO_FILE, "rb"); if (fp) { flen = LengthStateFile (fp); - // (DWORD) Write the uncompressed size. - cwrite ((PBYTE)&flen, sizeof (flen), 1, fh); + // Write the uncompressed size. + cwrite_32 (fh, flen); while (flen) { COUNT num_bytes; num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; ReadStateFile (buf, num_bytes, 1, fp); - cwrite ((PBYTE)buf, num_bytes, 1, fh); + cwrite (buf, num_bytes, 1, fh); flen -= num_bytes; } CloseStateFile (fp); } - // Copy the ? groupinfo file into the memory file (compressed). + // Copy the random groupinfo file into the memory file (compressed) fp = OpenStateFile (RANDGRPINFO_FILE, "rb"); if (fp) { flen = LengthStateFile (fp); - cwrite ((PBYTE)&flen, sizeof (flen), 1, fh); + // Write the uncompressed size. + cwrite_32 (fh, flen); while (flen) { COUNT num_bytes; num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; ReadStateFile (buf, num_bytes, 1, fp); - cwrite ((PBYTE)buf, num_bytes, 1, fh); + cwrite (buf, num_bytes, 1, fh); flen -= num_bytes; } @@ -471,22 +718,19 @@ RetrySave: } // Write the current star desc into the memory file (compressed). - cwrite ((PBYTE)&SD, sizeof (SD), 1, fh); + SaveStarDesc (&SD, fh); flen = cclose (fh); // Write the memory file to the actual savegame file. sprintf (file, "starcon2.%02u", which_game); log_add (log_Debug, "'%s' is %u bytes long", file, - flen + sizeof (*summary_desc)); - if (flen && (out_fp = (PVOID)res_OpenResFile (saveDir, file, "wb"))) + flen + sizeof (*SummPtr)); + if (flen && (out_fp = res_OpenResFile (saveDir, file, "wb"))) { - PrepareSummary (summary_desc); + PrepareSummary (SummPtr); - // First write the summary. - success = (BOOLEAN)(WriteResFile ( - summary_desc, sizeof (*summary_desc), 1, out_fp) != 0); - + success = SaveSummary (SummPtr, out_fp); // Then write the rest of the data. if (success && WriteResFile (mem_lock (h), (COUNT)flen, 1, out_fp) == 0) @@ -513,4 +757,3 @@ RetrySave: return (success); } - diff --git a/sc2/src/sc2code/ships/androsyn/androsyn.c b/sc2/src/sc2code/ships/androsyn/androsyn.c index 2c15c3a61..ef4f4e8f3 100644 --- a/sc2/src/sc2code/ships/androsyn/androsyn.c +++ b/sc2/src/sc2code/ships/androsyn/androsyn.c @@ -43,7 +43,7 @@ static RACE_DESC androsynth_desc = FIRES_FORE | SEEKING_WEAPON, 15, /* Super Melee cost */ ~0, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { MAX_X_UNIVERSE >> 1, MAX_Y_UNIVERSE >> 1, @@ -51,7 +51,6 @@ static RACE_DESC androsynth_desc = (STRING)ANDROSYNTH_RACE_STRINGS, (FRAME)ANDROSYNTH_ICON_MASK_PMAP_ANIM, (FRAME)ANDROSYNTH_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/arilou/arilou.c b/sc2/src/sc2code/ships/arilou/arilou.c index be9691fc2..578276edb 100644 --- a/sc2/src/sc2code/ships/arilou/arilou.c +++ b/sc2/src/sc2code/ships/arilou/arilou.c @@ -45,7 +45,7 @@ static RACE_DESC arilou_desc = /* FIRES_FORE | */ IMMEDIATE_WEAPON, 16, /* Super Melee cost */ 250 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 438, 6372, @@ -53,7 +53,6 @@ static RACE_DESC arilou_desc = (STRING)ARILOU_RACE_STRINGS, (FRAME)ARILOU_ICON_MASK_PMAP_ANIM, (FRAME)ARILOU_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/blackurq/blackurq.c b/sc2/src/sc2code/ships/blackurq/blackurq.c index 8a40d8e83..1365ae34e 100644 --- a/sc2/src/sc2code/ships/blackurq/blackurq.c +++ b/sc2/src/sc2code/ships/blackurq/blackurq.c @@ -47,7 +47,7 @@ static RACE_DESC black_urquan_desc = FIRES_FORE, 30, /* Super Melee cost */ 2666 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 6000, 6250, @@ -55,7 +55,6 @@ static RACE_DESC black_urquan_desc = (STRING)KOHR_AH_RACE_STRINGS, (FRAME)KOHR_AH_ICON_MASK_PMAP_ANIM, (FRAME)KOHR_AH_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/chenjesu/chenjesu.c b/sc2/src/sc2code/ships/chenjesu/chenjesu.c index adbd73dd4..e2390a432 100644 --- a/sc2/src/sc2code/ships/chenjesu/chenjesu.c +++ b/sc2/src/sc2code/ships/chenjesu/chenjesu.c @@ -50,7 +50,7 @@ static RACE_DESC chenjesu_desc = FIRES_FORE | SEEKING_SPECIAL | SEEKING_WEAPON, 28, /* Super Melee cost */ 0 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 0, 0, @@ -58,7 +58,6 @@ static RACE_DESC chenjesu_desc = (STRING)CHENJESU_RACE_STRINGS, (FRAME)CHENJESU_ICON_MASK_PMAP_ANIM, (FRAME)CHENJESU_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/chmmr/chmmr.c b/sc2/src/sc2code/ships/chmmr/chmmr.c index 555936184..2777fad6c 100644 --- a/sc2/src/sc2code/ships/chmmr/chmmr.c +++ b/sc2/src/sc2code/ships/chmmr/chmmr.c @@ -47,7 +47,7 @@ static RACE_DESC chmmr_desc = FIRES_FORE | IMMEDIATE_WEAPON | SEEKING_SPECIAL | POINT_DEFENSE, 30, /* Super Melee cost */ 0, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 0, 0, @@ -55,7 +55,6 @@ static RACE_DESC chmmr_desc = (STRING)CHMMR_RACE_STRINGS, (FRAME)CHMMR_ICON_MASK_PMAP_ANIM, (FRAME)CHMMR_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/druuge/druuge.c b/sc2/src/sc2code/ships/druuge/druuge.c index 29d0281ae..0b32ba0a5 100644 --- a/sc2/src/sc2code/ships/druuge/druuge.c +++ b/sc2/src/sc2code/ships/druuge/druuge.c @@ -43,7 +43,7 @@ static RACE_DESC druuge_desc = FIRES_FORE, 17, /* Super Melee cost */ 1400 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 9500, 2792, @@ -51,7 +51,6 @@ static RACE_DESC druuge_desc = (STRING)DRUUGE_RACE_STRINGS, (FRAME)DRUUGE_ICON_MASK_PMAP_ANIM, (FRAME)DRUUGE_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/human/human.c b/sc2/src/sc2code/ships/human/human.c index 27af62b86..ae5def14c 100644 --- a/sc2/src/sc2code/ships/human/human.c +++ b/sc2/src/sc2code/ships/human/human.c @@ -47,7 +47,7 @@ static RACE_DESC human_desc = FIRES_FORE | SEEKING_WEAPON | POINT_DEFENSE, 11, /* Super Melee cost */ 0 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 1752, 1450, @@ -55,7 +55,6 @@ static RACE_DESC human_desc = (STRING)HUMAN_RACE_STRINGS, (FRAME)HUMAN_ICON_MASK_PMAP_ANIM, (FRAME)HUMAN_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/ilwrath/ilwrath.c b/sc2/src/sc2code/ships/ilwrath/ilwrath.c index e051eadf4..9e2a699dc 100644 --- a/sc2/src/sc2code/ships/ilwrath/ilwrath.c +++ b/sc2/src/sc2code/ships/ilwrath/ilwrath.c @@ -45,7 +45,7 @@ static RACE_DESC ilwrath_desc = FIRES_FORE, 10, /* Super Melee cost */ 1410 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 48, 1700, @@ -53,7 +53,6 @@ static RACE_DESC ilwrath_desc = (STRING)ILWRATH_RACE_STRINGS, (FRAME)ILWRATH_ICON_MASK_PMAP_ANIM, (FRAME)ILWRATH_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/lastbat/lastbat.c b/sc2/src/sc2code/ships/lastbat/lastbat.c index b63f2345d..a032c263d 100644 --- a/sc2/src/sc2code/ships/lastbat/lastbat.c +++ b/sc2/src/sc2code/ships/lastbat/lastbat.c @@ -50,7 +50,7 @@ static RACE_DESC samatra_desc = /* FIRES_FORE | */ IMMEDIATE_WEAPON | CREW_IMMUNE, 16, /* Super Melee cost */ 0, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 0, 0, @@ -58,7 +58,6 @@ static RACE_DESC samatra_desc = (STRING)0, (FRAME)0, (FRAME)0, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/melnorme/melnorme.c b/sc2/src/sc2code/ships/melnorme/melnorme.c index e1985c095..a86baa054 100644 --- a/sc2/src/sc2code/ships/melnorme/melnorme.c +++ b/sc2/src/sc2code/ships/melnorme/melnorme.c @@ -46,7 +46,7 @@ static RACE_DESC melnorme_desc = FIRES_FORE, 18, /* Super Melee cost */ ~0, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { MAX_X_UNIVERSE >> 1, MAX_Y_UNIVERSE >> 1, @@ -54,7 +54,6 @@ static RACE_DESC melnorme_desc = (STRING)MELNORME_RACE_STRINGS, (FRAME)MELNORME_ICON_MASK_PMAP_ANIM, (FRAME)MELNORME_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/mmrnmhrm/mmrnmhrm.c b/sc2/src/sc2code/ships/mmrnmhrm/mmrnmhrm.c index 6b90bc3e6..013522fad 100644 --- a/sc2/src/sc2code/ships/mmrnmhrm/mmrnmhrm.c +++ b/sc2/src/sc2code/ships/mmrnmhrm/mmrnmhrm.c @@ -58,7 +58,7 @@ static RACE_DESC mmrnmhrm_desc = FIRES_FORE | IMMEDIATE_WEAPON, 19, /* Super Melee cost */ 0 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 0, 0, @@ -66,7 +66,6 @@ static RACE_DESC mmrnmhrm_desc = (STRING)MMRNMHRM_RACE_STRINGS, (FRAME)MMRNMHRM_ICON_MASK_PMAP_ANIM, (FRAME)MMRNMHRM_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/mycon/mycon.c b/sc2/src/sc2code/ships/mycon/mycon.c index caa15e372..1157bd02a 100644 --- a/sc2/src/sc2code/ships/mycon/mycon.c +++ b/sc2/src/sc2code/ships/mycon/mycon.c @@ -46,7 +46,7 @@ static RACE_DESC mycon_desc = FIRES_FORE | SEEKING_WEAPON, 21, /* Super Melee cost */ 1070 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 6392, 2200, @@ -54,7 +54,6 @@ static RACE_DESC mycon_desc = (STRING)MYCON_RACE_STRINGS, (FRAME)MYCON_ICON_MASK_PMAP_ANIM, (FRAME)MYCON_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/orz/orz.c b/sc2/src/sc2code/ships/orz/orz.c index e0c27dc35..d95e4fe22 100644 --- a/sc2/src/sc2code/ships/orz/orz.c +++ b/sc2/src/sc2code/ships/orz/orz.c @@ -48,7 +48,7 @@ static RACE_DESC orz_desc = FIRES_FORE | SEEKING_SPECIAL, 23, /* Super Melee cost */ 333 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 3608, 2637, @@ -56,7 +56,6 @@ static RACE_DESC orz_desc = (STRING)ORZ_RACE_STRINGS, (FRAME)ORZ_ICON_MASK_PMAP_ANIM, (FRAME)ORZ_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/pkunk/pkunk.c b/sc2/src/sc2code/ships/pkunk/pkunk.c index 30db0ac57..af52821de 100644 --- a/sc2/src/sc2code/ships/pkunk/pkunk.c +++ b/sc2/src/sc2code/ships/pkunk/pkunk.c @@ -46,7 +46,7 @@ static RACE_DESC pkunk_desc = FIRES_FORE | FIRES_LEFT | FIRES_RIGHT, 20, /* Super Melee cost */ 666 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 502, 401, @@ -54,7 +54,6 @@ static RACE_DESC pkunk_desc = (STRING)PKUNK_RACE_STRINGS, (FRAME)PKUNK_ICON_MASK_PMAP_ANIM, (FRAME)PKUNK_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/probe/probe.c b/sc2/src/sc2code/ships/probe/probe.c index d71b932b7..a801c7404 100644 --- a/sc2/src/sc2code/ships/probe/probe.c +++ b/sc2/src/sc2code/ships/probe/probe.c @@ -40,7 +40,7 @@ static RACE_DESC probe_desc = 0, 0, /* Super Melee cost */ 0, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 0, 0, @@ -48,7 +48,6 @@ static RACE_DESC probe_desc = 0, 0, (FRAME)PROBE_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/shofixti/shofixti.c b/sc2/src/sc2code/ships/shofixti/shofixti.c index c1cfa0b16..8f6857f1b 100644 --- a/sc2/src/sc2code/ships/shofixti/shofixti.c +++ b/sc2/src/sc2code/ships/shofixti/shofixti.c @@ -46,7 +46,7 @@ static RACE_DESC shofixti_desc = FIRES_FORE, 5, /* Super Melee cost */ 0 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 0, 0, @@ -54,7 +54,6 @@ static RACE_DESC shofixti_desc = (STRING)SHOFIXTI_RACE_STRINGS, (FRAME)SHOFIXTI_ICON_MASK_PMAP_ANIM, (FRAME)SHOFIXTI_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/sis_ship/sis_ship.c b/sc2/src/sc2code/ships/sis_ship/sis_ship.c index 14bbf7c1c..95b9d4d91 100644 --- a/sc2/src/sc2code/ships/sis_ship/sis_ship.c +++ b/sc2/src/sc2code/ships/sis_ship/sis_ship.c @@ -52,7 +52,7 @@ static RACE_DESC sis_desc = 0, 16, /* Super Melee cost */ 0 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 0, 0, @@ -60,7 +60,6 @@ static RACE_DESC sis_desc = 0, (FRAME)SIS_ICON_MASK_PMAP_ANIM, 0, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/slylandr/slylandr.c b/sc2/src/sc2code/ships/slylandr/slylandr.c index 013eec964..57eb31928 100644 --- a/sc2/src/sc2code/ships/slylandr/slylandr.c +++ b/sc2/src/sc2code/ships/slylandr/slylandr.c @@ -45,7 +45,7 @@ static RACE_DESC slylandro_desc = SEEKING_WEAPON | CREW_IMMUNE, 17, /* Super Melee cost */ ~0, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 333, 9812, @@ -53,7 +53,6 @@ static RACE_DESC slylandro_desc = (STRING)SLYLANDRO_RACE_STRINGS, (FRAME)SLYLANDRO_ICON_MASK_PMAP_ANIM, (FRAME)SLYLANDRO_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/spathi/spathi.c b/sc2/src/sc2code/ships/spathi/spathi.c index fed58fc05..f9ea02679 100644 --- a/sc2/src/sc2code/ships/spathi/spathi.c +++ b/sc2/src/sc2code/ships/spathi/spathi.c @@ -43,7 +43,7 @@ static RACE_DESC spathi_desc = FIRES_FORE | FIRES_AFT | SEEKING_SPECIAL | DONT_CHASE, 18, /* Super Melee cost */ 1000 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 2549, 3600, @@ -51,7 +51,6 @@ static RACE_DESC spathi_desc = (STRING)SPATHI_RACE_STRINGS, (FRAME)SPATHI_ICON_MASK_PMAP_ANIM, (FRAME)SPATHI_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/supox/supox.c b/sc2/src/sc2code/ships/supox/supox.c index ab1790dd4..437e7c54f 100644 --- a/sc2/src/sc2code/ships/supox/supox.c +++ b/sc2/src/sc2code/ships/supox/supox.c @@ -45,7 +45,7 @@ static RACE_DESC supox_desc = FIRES_FORE, 16, /* Super Melee cost */ 333 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 7468, 9246, @@ -53,7 +53,6 @@ static RACE_DESC supox_desc = (STRING)SUPOX_RACE_STRINGS, (FRAME)SUPOX_ICON_MASK_PMAP_ANIM, (FRAME)SUPOX_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/syreen/syreen.c b/sc2/src/sc2code/ships/syreen/syreen.c index c79583abd..ff874ceb8 100644 --- a/sc2/src/sc2code/ships/syreen/syreen.c +++ b/sc2/src/sc2code/ships/syreen/syreen.c @@ -46,7 +46,7 @@ static RACE_DESC syreen_desc = FIRES_FORE, 13, /* Super Melee cost */ 0 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, SYREEN_MAX_CREW_SIZE, MAX_ENERGY, MAX_ENERGY, { 0, 0, @@ -54,7 +54,6 @@ static RACE_DESC syreen_desc = (STRING)SYREEN_RACE_STRINGS, (FRAME)SYREEN_ICON_MASK_PMAP_ANIM, (FRAME)SYREEN_MICON_MASK_PMAP_ANIM, - MAX_CREW, SYREEN_MAX_CREW_SIZE, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/thradd/thradd.c b/sc2/src/sc2code/ships/thradd/thradd.c index aea6aef90..7f3ffd52f 100644 --- a/sc2/src/sc2code/ships/thradd/thradd.c +++ b/sc2/src/sc2code/ships/thradd/thradd.c @@ -46,7 +46,7 @@ static RACE_DESC thraddash_desc = FIRES_FORE, 10, /* Super Melee cost */ 833 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 2535, 8358, @@ -54,7 +54,6 @@ static RACE_DESC thraddash_desc = (STRING)THRADDASH_RACE_STRINGS, (FRAME)THRADDASH_ICON_MASK_PMAP_ANIM, (FRAME)THRADDASH_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/umgah/umgah.c b/sc2/src/sc2code/ships/umgah/umgah.c index e07de2046..381f2e310 100644 --- a/sc2/src/sc2code/ships/umgah/umgah.c +++ b/sc2/src/sc2code/ships/umgah/umgah.c @@ -45,7 +45,7 @@ static RACE_DESC umgah_desc = FIRES_FORE | IMMEDIATE_WEAPON, 7, /* Super Melee cost */ 833 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 1798, 6000, @@ -53,7 +53,6 @@ static RACE_DESC umgah_desc = (STRING)UMGAH_RACE_STRINGS, (FRAME)UMGAH_ICON_MASK_PMAP_ANIM, (FRAME)UMGAH_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/urquan/urquan.c b/sc2/src/sc2code/ships/urquan/urquan.c index a3da5f970..263110aed 100644 --- a/sc2/src/sc2code/ships/urquan/urquan.c +++ b/sc2/src/sc2code/ships/urquan/urquan.c @@ -47,7 +47,7 @@ static RACE_DESC urquan_desc = FIRES_FORE | SEEKING_SPECIAL, 30, /* Super Melee cost */ 2666 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 5750, 6000, @@ -55,7 +55,6 @@ static RACE_DESC urquan_desc = (STRING)URQUAN_RACE_STRINGS, (FRAME)URQUAN_ICON_MASK_PMAP_ANIM, (FRAME)URQUAN_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/utwig/utwig.c b/sc2/src/sc2code/ships/utwig/utwig.c index b0407998f..c0f46a9ae 100644 --- a/sc2/src/sc2code/ships/utwig/utwig.c +++ b/sc2/src/sc2code/ships/utwig/utwig.c @@ -47,7 +47,7 @@ static RACE_DESC utwig_desc = FIRES_FORE | POINT_DEFENSE | SHIELD_DEFENSE, 22, /* Super Melee cost */ 666 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY >> 1, MAX_ENERGY, { 8534, 8797, @@ -55,7 +55,6 @@ static RACE_DESC utwig_desc = (STRING)UTWIG_RACE_STRINGS, (FRAME)UTWIG_ICON_MASK_PMAP_ANIM, (FRAME)UTWIG_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/vux/vux.c b/sc2/src/sc2code/ships/vux/vux.c index 0be6bb9da..199c0ddd8 100644 --- a/sc2/src/sc2code/ships/vux/vux.c +++ b/sc2/src/sc2code/ships/vux/vux.c @@ -48,7 +48,7 @@ static RACE_DESC vux_desc = FIRES_FORE | SEEKING_SPECIAL | IMMEDIATE_WEAPON, 12, /* Super Melee cost */ 900 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 4412, 1558, @@ -56,7 +56,6 @@ static RACE_DESC vux_desc = (STRING)VUX_RACE_STRINGS, (FRAME)VUX_ICON_MASK_PMAP_ANIM, (FRAME)VUX_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/yehat/yehat.c b/sc2/src/sc2code/ships/yehat/yehat.c index 0be0379ec..bd083daf7 100644 --- a/sc2/src/sc2code/ships/yehat/yehat.c +++ b/sc2/src/sc2code/ships/yehat/yehat.c @@ -45,7 +45,7 @@ static RACE_DESC yehat_desc = FIRES_FORE | SHIELD_DEFENSE, 23, /* Super Melee cost */ 750 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 4970, 40, @@ -53,7 +53,6 @@ static RACE_DESC yehat_desc = (STRING)YEHAT_RACE_STRINGS, (FRAME)YEHAT_ICON_MASK_PMAP_ANIM, (FRAME)YEHAT_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/ships/zoqfot/zoqfot.c b/sc2/src/sc2code/ships/zoqfot/zoqfot.c index 8eb8858dc..039b0dfec 100644 --- a/sc2/src/sc2code/ships/zoqfot/zoqfot.c +++ b/sc2/src/sc2code/ships/zoqfot/zoqfot.c @@ -46,7 +46,7 @@ static RACE_DESC zoqfotpik_desc = FIRES_FORE, 6, /* Super Melee cost */ 320 / SPHERE_RADIUS_INCREMENT, /* Initial sphere of influence radius */ - 0, 0, /* Hack; old crew field */ + MAX_CREW, MAX_CREW, MAX_ENERGY, MAX_ENERGY, { 3761, 5333, @@ -54,7 +54,6 @@ static RACE_DESC zoqfotpik_desc = (STRING)ZOQFOTPIK_RACE_STRINGS, (FRAME)ZOQFOTPIK_ICON_MASK_PMAP_ANIM, (FRAME)ZOQFOTPIK_MICON_MASK_PMAP_ANIM, - MAX_CREW, MAX_CREW, }, { MAX_THRUST, diff --git a/sc2/src/sc2code/sis.h b/sc2/src/sc2code/sis.h index 13116014c..e2779ffc8 100644 --- a/sc2/src/sc2code/sis.h +++ b/sc2/src/sc2code/sis.h @@ -196,6 +196,8 @@ enum #define STATUS_MESSAGE_WIDTH 60 #define STATUS_MESSAGE_HEIGHT 7 +#define SIS_NAME_SIZE 16 + typedef struct { SDWORD log_x, log_y; @@ -216,9 +218,9 @@ typedef struct COUNT ElementAmounts[NUM_ELEMENT_CATEGORIES]; - UNICODE ShipName[16]; - UNICODE CommanderName[16]; - UNICODE PlanetName[16]; + UNICODE ShipName[SIS_NAME_SIZE]; + UNICODE CommanderName[SIS_NAME_SIZE]; + UNICODE PlanetName[SIS_NAME_SIZE]; } SIS_STATE; typedef SIS_STATE *PSIS_STATE; diff --git a/sc2/src/sc2code/state.c b/sc2/src/sc2code/state.c index d9003a878..5c630e16c 100644 --- a/sc2/src/sc2code/state.c +++ b/sc2/src/sc2code/state.c @@ -54,7 +54,7 @@ OpenStateFile (int stateFile, const char *mode) GAME_STATE_FILE *fp; if (stateFile < 0 || stateFile >= NUM_STATE_FILES) - return NULL_PTR; + return NULL; fp = &state_files[stateFile]; fp->open_count++; @@ -67,7 +67,7 @@ OpenStateFile (int stateFile, const char *mode) { fp->data = HMalloc (fp->size_hint); if (!fp->data) - return NULL_PTR; + return NULL; fp->size = fp->size_hint; } @@ -185,15 +185,6 @@ WriteStateFile (PVOID lpBuf, COUNT size, COUNT count, GAME_STATE_FILE *fp) return (bytes / size); } -int -PutStateFileChar (char ch, GAME_STATE_FILE *fp) -{ - if (1 == WriteStateFile (&ch, sizeof(ch), 1, fp)) - return ch; - else - return EOF; -} - int SeekStateFile (GAME_STATE_FILE *fp, long offset, int whence) { @@ -220,14 +211,13 @@ InitPlanetInfo (void) fp = OpenStateFile (STARINFO_FILE, "wb"); if (fp) { - DWORD offset; STAR_DESCPTR pSD; - offset = 0; + // Set record offsets for all stars to 0 (not present) pSD = &star_array[0]; do { - WriteStateFile (&offset, sizeof (offset), 1, fp); + swrite_32 (fp, 0); ++pSD; } while (pSD->star_pt.x <= MAX_X_UNIVERSE && pSD->star_pt.y <= MAX_Y_UNIVERSE); @@ -242,6 +232,9 @@ UninitPlanetInfo (void) DeleteStateFile (STARINFO_FILE); } +#define OFFSET_SIZE (sizeof (DWORD)) +#define SCAN_RECORD_SIZE (sizeof (DWORD) * NUM_SCAN_TYPES) + void GetPlanetInfo (void) { @@ -266,27 +259,24 @@ GetPlanetInfo (void) moon_index = (COUNT)(pSolarSysState->pOrbitalDesc - pSolarSysState->MoonDesc + 1); - SeekStateFile (fp, star_index * sizeof (offset), SEEK_SET); - ReadStateFile (&offset, sizeof (offset), 1, fp); + SeekStateFile (fp, star_index * OFFSET_SIZE, SEEK_SET); + sread_32 (fp, &offset); if (offset) { COUNT i; + // Skip scan records for all preceeding planets to the one we need for (i = 0; i < planet_index; ++i) - offset += sizeof ( - pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask - ) * (pSolarSysState->PlanetDesc[i].NumPlanets + 1); + offset += (pSolarSysState->PlanetDesc[i].NumPlanets + 1) * + SCAN_RECORD_SIZE; - offset += sizeof ( - pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask - ) * moon_index; + // Skip scan records for all preceeding moons to the one we need + offset += moon_index * SCAN_RECORD_SIZE; SeekStateFile (fp, offset, SEEK_SET); - ReadStateFile (pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask, - sizeof ( - pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask - ), 1, fp); + sread_a32 (fp, pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask, + NUM_SCAN_TYPES); } CloseStateFile (fp); @@ -314,11 +304,11 @@ PutPlanetInfo (void) moon_index = (COUNT)(pSolarSysState->pOrbitalDesc - pSolarSysState->MoonDesc + 1); - SeekStateFile (fp, star_index * sizeof (offset), SEEK_SET); - ReadStateFile (&offset, sizeof (offset), 1, fp); + SeekStateFile (fp, star_index * OFFSET_SIZE, SEEK_SET); + sread_32 (fp, &offset); if (offset == 0) - { + { // Scan record not present yet -- init it DWORD ScanRetrieveMask[NUM_SCAN_TYPES] = { 0, 0, 0, @@ -326,34 +316,34 @@ PutPlanetInfo (void) offset = LengthStateFile (fp); - SeekStateFile (fp, star_index * sizeof (offset), SEEK_SET); - WriteStateFile (&offset, sizeof (offset), 1, fp); + // Write the record offset + SeekStateFile (fp, star_index * OFFSET_SIZE, SEEK_SET); + swrite_32 (fp, offset); + // Init scan records for all planets and moons in the system SeekStateFile (fp, offset, SEEK_SET); for (i = 0; i < pSolarSysState->SunDesc[0].NumPlanets; ++i) { COUNT j; - WriteStateFile (ScanRetrieveMask, sizeof (ScanRetrieveMask), 1, fp); + swrite_a32 (fp, ScanRetrieveMask, NUM_SCAN_TYPES); + // init moons for (j = 0; j < pSolarSysState->PlanetDesc[i].NumPlanets; ++j) - WriteStateFile (ScanRetrieveMask, sizeof (ScanRetrieveMask), 1, fp); + swrite_a32 (fp, ScanRetrieveMask, NUM_SCAN_TYPES); } } + // Skip scan records for all preceeding planets to the one we need for (i = 0; i < planet_index; ++i) - offset += sizeof ( - pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask - ) * (pSolarSysState->PlanetDesc[i].NumPlanets + 1); + offset += (pSolarSysState->PlanetDesc[i].NumPlanets + 1) * + SCAN_RECORD_SIZE; - offset += sizeof ( - pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask - ) * moon_index; + // Skip scan records for all preceeding moons to the one we need + offset += moon_index * SCAN_RECORD_SIZE; SeekStateFile (fp, offset, SEEK_SET); - WriteStateFile (pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask, - sizeof ( - pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask - ), 1, fp); + swrite_a32 (fp, pSolarSysState->SysInfo.PlanetInfo.ScanRetrieveMask, + NUM_SCAN_TYPES); CloseStateFile (fp); } diff --git a/sc2/src/sc2code/state.h b/sc2/src/sc2code/state.h index b63e98366..1caf833ce 100644 --- a/sc2/src/sc2code/state.h +++ b/sc2/src/sc2code/state.h @@ -19,7 +19,9 @@ #ifndef _STATE_H #define _STATE_H +#include "port.h" #include "libs/compiler.h" +#include extern void InitPlanetInfo (void); extern void UninitPlanetInfo (void); @@ -67,8 +69,76 @@ void DeleteStateFile (int stateFile); DWORD LengthStateFile (GAME_STATE_FILE *fp); int ReadStateFile (PVOID lpBuf, COUNT size, COUNT count, GAME_STATE_FILE *fp); int WriteStateFile (PVOID lpBuf, COUNT size, COUNT count, GAME_STATE_FILE *fp); -int PutStateFileChar (char ch, GAME_STATE_FILE *fp); int SeekStateFile (GAME_STATE_FILE *fp, long offset, int whence); +static inline COUNT +sread_8 (PVOID fp, PBYTE v) +{ + BYTE t; + if (!v) /* read value ignored */ + v = &t; + return ReadStateFile (v, 1, 1, fp); +} + +static inline COUNT +sread_16 (PVOID fp, PUWORD v) +{ + UWORD t; + if (!v) /* read value ignored */ + v = &t; + return ReadStateFile (v, 2, 1, fp); +} + +static inline COUNT +sread_32 (PVOID fp, PDWORD v) +{ + DWORD t; + if (!v) /* read value ignored */ + v = &t; + return ReadStateFile (v, 4, 1, fp); +} + +static inline COUNT +sread_a32 (PVOID fp, PDWORD ar, COUNT count) +{ + assert (ar != NULL); + + for ( ; count > 0; --count, ++ar) + { + if (sread_32 (fp, ar) != 1) + return 0; + } + return 1; +} + +static inline COUNT +swrite_8 (PVOID fp, BYTE v) +{ + return WriteStateFile (&v, 1, 1, fp); +} + +static inline COUNT +swrite_16 (PVOID fp, UWORD v) +{ + return WriteStateFile (&v, 2, 1, fp); +} + +static inline COUNT +swrite_32 (PVOID fp, DWORD v) +{ + return WriteStateFile (&v, 4, 1, fp); +} + +static inline COUNT +swrite_a32 (PVOID fp, PDWORD ar, COUNT count) +{ + for ( ; count > 0; --count, ++ar) + { + if (swrite_32 (fp, *ar) != 1) + return 0; + } + return 1; +} + #endif /* _STATE_H */