diff --git a/sc2/src/uqm/Makeinfo b/sc2/src/uqm/Makeinfo index 5f0145617..4b224fac0 100644 --- a/sc2/src/uqm/Makeinfo +++ b/sc2/src/uqm/Makeinfo @@ -4,6 +4,7 @@ uqm_CFILES="battle.c battlecontrols.c border.c build.c cleanup.c clock.c cyborg.c demo.c displist.c dummy.c encount.c flash.c fmv.c galaxy.c gameev.c gameinp.c gameopt.c gendef.c getchar.c globdata.c gravity.c cons_res.c grpinfo.c hyper.c init.c intel.c intro.c ipdisp.c load.c + load_legacy.c loadship.c master.c menu.c misc.c oscill.c outfit.c pickship.c plandata.c process.c restart.c save.c settings.c setup.c setupmenu.c ship.c shipstat.c shipyard.c sis.c sounds.c starbase.c starcon.c @@ -14,7 +15,7 @@ uqm_HFILES="battlecontrols.h battle.h build.h clock.h cnctdlg.h coderes.h corecode.h credits.h demo.h displist.h dummy.h element.h encount.h flash.h fmv.h gameev.h gameopt.h gamestr.h gendef.h globdata.h grpinfo.h hyper.h ifontres.h igfxres.h ikey_con.h imusicre.h init.h - intel.h ipdisp.h isndres.h istrtab.h load.h master.h menustat.h + intel.h ipdisp.h isndres.h istrtab.h master.h menustat.h nameref.h oscill.h pickship.h process.h races.h resinst.h respkg.h restart.h save.h settings.h setup.h setupmenu.h shipcont.h ship.h sis.h sounds.h starbase.h starcon.h state.h status.h tactrans.h diff --git a/sc2/src/uqm/load.c b/sc2/src/uqm/load.c index b4da899ec..081ce9526 100644 --- a/sc2/src/uqm/load.c +++ b/sc2/src/uqm/load.c @@ -19,7 +19,6 @@ #include #include "build.h" -#include "libs/declib.h" #include "encount.h" #include "starmap.h" #include "libs/file.h" @@ -38,74 +37,6 @@ ACTIVITY NextActivity; -// XXX: these should handle endian conversions later -static inline COUNT -cread_8 (DECODE_REF fh, BYTE *v) -{ - BYTE t; - if (!v) /* read value ignored */ - v = &t; - return cread (v, 1, 1, fh); -} - -static inline COUNT -cread_16 (DECODE_REF fh, UWORD *v) -{ - UWORD t; - if (!v) /* read value ignored */ - v = &t; - return cread (v, 2, 1, fh); -} - -static inline COUNT -cread_16s (DECODE_REF fh, SWORD *v) -{ - UWORD t; - COUNT ret; - // value was converted to unsigned when saved - ret = cread_16 (fh, &t); - // unsigned to signed conversion - if (v) - *v = t; - return ret; -} - -static inline COUNT -cread_32 (DECODE_REF fh, DWORD *v) -{ - DWORD t; - if (!v) /* read value ignored */ - v = &t; - return cread (v, 4, 1, fh); -} - -static inline COUNT -cread_32s (DECODE_REF fh, SDWORD *v) -{ - DWORD t; - COUNT ret; - // value was converted to unsigned when saved - ret = cread_32 (fh, &t); - // unsigned to signed conversion - if (v) - *v = t; - return ret; -} - -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, BYTE *ar, COUNT count) -{ - assert (ar != NULL); - return cread (ar, 1, count, fh) == count; -} - static inline size_t read_8 (void *fp, BYTE *v) { @@ -124,6 +55,15 @@ read_16 (void *fp, UWORD *v) return ReadResFile (v, 2, 1, fp); } +static inline size_t +read_16s (void *fp, SWORD *v) +{ + SWORD t; + if (!v) /* read value ignored */ + v = &t; + return ReadResFile (v, 2, 1, fp); +} + static inline size_t read_32 (void *fp, DWORD *v) { @@ -193,11 +133,11 @@ read_a16 (void *fp, UWORD *ar, COUNT count) } static void -LoadEmptyQueue (DECODE_REF fh) +LoadEmptyQueue (void *fh) { COUNT num_links; - cread_16 (fh, &num_links); + read_16 (fh, &num_links); if (num_links) { log_add (log_Error, "LoadEmptyQueue(): BUG: the queue is not empty!"); @@ -208,11 +148,11 @@ LoadEmptyQueue (DECODE_REF fh) } static void -LoadShipQueue (DECODE_REF fh, QUEUE *pQueue) +LoadShipQueue (void *fh, QUEUE *pQueue) { COUNT num_links; - cread_16 (fh, &num_links); + read_16 (fh, &num_links); while (num_links--) { @@ -221,38 +161,38 @@ LoadShipQueue (DECODE_REF fh, QUEUE *pQueue) COUNT Index; BYTE tmpb; - cread_16 (fh, &Index); + read_16 (fh, &Index); hStarShip = CloneShipFragment (Index, pQueue, 0); FragPtr = LockShipFrag (pQueue, hStarShip); // Read SHIP_FRAGMENT elements - cread_16 (fh, NULL); /* unused: was which_side */ - cread_8 (fh, &FragPtr->captains_name_index); - cread_8 (fh, NULL); /* padding */ - cread_16 (fh, NULL); /* unused: was ship_flags */ - cread_8 (fh, &FragPtr->race_id); - cread_8 (fh, &FragPtr->index); + read_16 (fh, NULL); /* unused: was which_side */ + read_8 (fh, &FragPtr->captains_name_index); + read_8 (fh, NULL); /* padding */ + read_16 (fh, NULL); /* unused: was ship_flags */ + read_8 (fh, &FragPtr->race_id); + read_8 (fh, &FragPtr->index); // XXX: reading crew as BYTE to maintain savegame compatibility - cread_8 (fh, &tmpb); + read_8 (fh, &tmpb); FragPtr->crew_level = tmpb; - cread_8 (fh, &tmpb); + read_8 (fh, &tmpb); FragPtr->max_crew = tmpb; - cread_8 (fh, &FragPtr->energy_level); - cread_8 (fh, &FragPtr->max_energy); - cread_16 (fh, NULL); /* unused; was loc.x */ - cread_16 (fh, NULL); /* unused; was loc.y */ + read_8 (fh, &FragPtr->energy_level); + read_8 (fh, &FragPtr->max_energy); + read_16 (fh, NULL); /* unused; was loc.x */ + read_16 (fh, NULL); /* unused; was loc.y */ UnlockShipFrag (pQueue, hStarShip); } } static void -LoadRaceQueue (DECODE_REF fh, QUEUE *pQueue) +LoadRaceQueue (void *fh, QUEUE *pQueue) { COUNT num_links; - cread_16 (fh, &num_links); + read_16 (fh, &num_links); while (num_links--) { @@ -261,44 +201,44 @@ LoadRaceQueue (DECODE_REF fh, QUEUE *pQueue) COUNT Index; BYTE tmpb; - cread_16 (fh, &Index); + read_16 (fh, &Index); hStarShip = GetStarShipFromIndex (pQueue, Index); FleetPtr = LockFleetInfo (pQueue, hStarShip); // Read FLEET_INFO elements - cread_16 (fh, &FleetPtr->allied_state); - cread_8 (fh, &FleetPtr->days_left); - cread_8 (fh, &FleetPtr->growth_fract); - cread_8 (fh, &tmpb); + read_16 (fh, &FleetPtr->allied_state); + read_8 (fh, &FleetPtr->days_left); + read_8 (fh, &FleetPtr->growth_fract); + read_8 (fh, &tmpb); FleetPtr->crew_level = tmpb; - cread_8 (fh, &tmpb); + read_8 (fh, &tmpb); FleetPtr->max_crew = tmpb; - cread_8 (fh, &FleetPtr->growth); - cread_8 (fh, &FleetPtr->max_energy); - cread_16s(fh, &FleetPtr->loc.x); - cread_16s(fh, &FleetPtr->loc.y); + read_8 (fh, &FleetPtr->growth); + read_8 (fh, &FleetPtr->max_energy); + read_16s(fh, &FleetPtr->loc.x); + read_16s(fh, &FleetPtr->loc.y); - cread_16 (fh, &FleetPtr->actual_strength); - cread_16 (fh, &FleetPtr->known_strength); - cread_16s(fh, &FleetPtr->known_loc.x); - cread_16s(fh, &FleetPtr->known_loc.y); - cread_8 (fh, &FleetPtr->growth_err_term); - cread_8 (fh, &FleetPtr->func_index); - cread_16s(fh, &FleetPtr->dest_loc.x); - cread_16s(fh, &FleetPtr->dest_loc.y); - cread_16 (fh, NULL); /* alignment padding */ + read_16 (fh, &FleetPtr->actual_strength); + read_16 (fh, &FleetPtr->known_strength); + read_16s(fh, &FleetPtr->known_loc.x); + read_16s(fh, &FleetPtr->known_loc.y); + read_8 (fh, &FleetPtr->growth_err_term); + read_8 (fh, &FleetPtr->func_index); + read_16s(fh, &FleetPtr->dest_loc.x); + read_16s(fh, &FleetPtr->dest_loc.y); + read_16 (fh, NULL); /* alignment padding */ UnlockFleetInfo (pQueue, hStarShip); } } static void -LoadGroupQueue (DECODE_REF fh, QUEUE *pQueue) +LoadGroupQueue (void *fh, QUEUE *pQueue) { COUNT num_links; - cread_16 (fh, &num_links); + read_16 (fh, &num_links); while (num_links--) { @@ -306,101 +246,101 @@ LoadGroupQueue (DECODE_REF fh, QUEUE *pQueue) IP_GROUP *GroupPtr; BYTE tmpb; - cread_16 (fh, NULL); /* unused; was race_id */ + read_16 (fh, NULL); /* unused; was race_id */ hGroup = BuildGroup (pQueue, 0); GroupPtr = LockIpGroup (pQueue, hGroup); - cread_16 (fh, NULL); /* unused; was which_side */ - cread_8 (fh, NULL); /* unused; was captains_name_index */ - cread_8 (fh, NULL); /* padding; for savegame compat */ - cread_16 (fh, &GroupPtr->group_counter); - cread_8 (fh, &GroupPtr->race_id); - cread_8 (fh, &tmpb); /* was var2 */ + read_16 (fh, NULL); /* unused; was which_side */ + read_8 (fh, NULL); /* unused; was captains_name_index */ + read_8 (fh, NULL); /* padding; for savegame compat */ + read_16 (fh, &GroupPtr->group_counter); + read_8 (fh, &GroupPtr->race_id); + read_8 (fh, &tmpb); /* was var2 */ GroupPtr->sys_loc = LONIBBLE (tmpb); GroupPtr->task = HINIBBLE (tmpb); - cread_8 (fh, &GroupPtr->in_system); /* was crew_level */ - cread_8 (fh, NULL); /* unused; was max_crew */ - cread_8 (fh, &tmpb); /* was energy_level */ + read_8 (fh, &GroupPtr->in_system); /* was crew_level */ + read_8 (fh, NULL); /* unused; was max_crew */ + read_8 (fh, &tmpb); /* was energy_level */ GroupPtr->dest_loc = LONIBBLE (tmpb); GroupPtr->orbit_pos = HINIBBLE (tmpb); - cread_8 (fh, &GroupPtr->group_id); /* was max_energy */ - cread_16s(fh, &GroupPtr->loc.x); - cread_16s(fh, &GroupPtr->loc.y); + read_8 (fh, &GroupPtr->group_id); /* was max_energy */ + read_16s(fh, &GroupPtr->loc.x); + read_16s(fh, &GroupPtr->loc.y); UnlockIpGroup (pQueue, hGroup); } } static void -LoadEncounter (ENCOUNTER *EncounterPtr, DECODE_REF fh) +LoadEncounter (ENCOUNTER *EncounterPtr, void *fh) { COUNT i; BYTE tmpb; - cread_ptr (fh); /* useless ptr; HENCOUNTER pred */ + read_ptr (fh); /* useless ptr; HENCOUNTER pred */ EncounterPtr->pred = 0; - cread_ptr (fh); /* useless ptr; HENCOUNTER succ */ + read_ptr (fh); /* useless ptr; HENCOUNTER succ */ EncounterPtr->succ = 0; - cread_ptr (fh); /* useless ptr; HELEMENT hElement */ + read_ptr (fh); /* useless ptr; HELEMENT hElement */ EncounterPtr->hElement = 0; - cread_16s (fh, &EncounterPtr->transition_state); - cread_16s (fh, &EncounterPtr->origin.x); - cread_16s (fh, &EncounterPtr->origin.y); - cread_16 (fh, &EncounterPtr->radius); + read_16s (fh, &EncounterPtr->transition_state); + read_16s (fh, &EncounterPtr->origin.x); + read_16s (fh, &EncounterPtr->origin.y); + read_16 (fh, &EncounterPtr->radius); // former STAR_DESC fields - cread_16s (fh, &EncounterPtr->loc_pt.x); - cread_16s (fh, &EncounterPtr->loc_pt.y); - cread_8 (fh, &EncounterPtr->race_id); - cread_8 (fh, &tmpb); + read_16s (fh, &EncounterPtr->loc_pt.x); + read_16s (fh, &EncounterPtr->loc_pt.y); + read_8 (fh, &EncounterPtr->race_id); + read_8 (fh, &tmpb); EncounterPtr->num_ships = tmpb & ENCOUNTER_SHIPS_MASK; EncounterPtr->flags = tmpb & ENCOUNTER_FLAGS_MASK; - cread_16 (fh, NULL); /* alignment padding */ + read_16 (fh, NULL); /* alignment padding */ // Load each entry in the BRIEF_SHIP_INFO array for (i = 0; i < MAX_HYPER_SHIPS; i++) { BRIEF_SHIP_INFO *ShipInfo = &EncounterPtr->ShipList[i]; - cread_16 (fh, NULL); /* useless; was SHIP_INFO.ship_flags */ - cread_8 (fh, &ShipInfo->race_id); - cread_8 (fh, NULL); /* useless; was SHIP_INFO.var2 */ + read_16 (fh, NULL); /* useless; was SHIP_INFO.ship_flags */ + read_8 (fh, &ShipInfo->race_id); + read_8 (fh, NULL); /* useless; was SHIP_INFO.var2 */ // XXX: reading crew as BYTE to maintain savegame compatibility - cread_8 (fh, &tmpb); + read_8 (fh, &tmpb); ShipInfo->crew_level = tmpb; - cread_8 (fh, &tmpb); + read_8 (fh, &tmpb); ShipInfo->max_crew = tmpb; - cread_8 (fh, NULL); /* useless; was SHIP_INFO.energy_level */ - cread_8 (fh, &ShipInfo->max_energy); - cread_16 (fh, NULL); /* useless; was SHIP_INFO.loc.x */ - cread_16 (fh, NULL); /* useless; was SHIP_INFO.loc.y */ - cread_32 (fh, NULL); /* useless val; STRING race_strings */ - cread_ptr (fh); /* useless ptr; FRAME icons */ - cread_ptr (fh); /* useless ptr; FRAME melee_icon */ + read_8 (fh, NULL); /* useless; was SHIP_INFO.energy_level */ + read_8 (fh, &ShipInfo->max_energy); + read_16 (fh, NULL); /* useless; was SHIP_INFO.loc.x */ + read_16 (fh, NULL); /* useless; was SHIP_INFO.loc.y */ + read_32 (fh, NULL); /* useless val; STRING race_strings */ + read_ptr (fh); /* useless ptr; FRAME icons */ + read_ptr (fh); /* useless ptr; FRAME melee_icon */ } // Load the stuff after the BRIEF_SHIP_INFO array - cread_32s (fh, &EncounterPtr->log_x); - cread_32s (fh, &EncounterPtr->log_y); + read_32s (fh, &EncounterPtr->log_x); + read_32s (fh, &EncounterPtr->log_y); } static void -LoadEvent (EVENT *EventPtr, DECODE_REF fh) +LoadEvent (EVENT *EventPtr, void *fh) { - cread_ptr (fh); /* useless ptr; HEVENT pred */ + read_ptr (fh); /* useless ptr; HEVENT pred */ EventPtr->pred = 0; - cread_ptr (fh); /* useless ptr; HEVENT succ */ + read_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 */ + read_8 (fh, &EventPtr->day_index); + read_8 (fh, &EventPtr->month_index); + read_16 (fh, &EventPtr->year_index); + read_8 (fh, &EventPtr->func_index); + read_8 (fh, NULL); /* padding */ + read_16 (fh, NULL); /* padding */ } static void -DummyLoadQueue (QUEUE *QueuePtr, DECODE_REF fh) +DummyLoadQueue (QUEUE *QueuePtr, void *fh) { /* QUEUE should never actually be loaded since it contains * purely internal representation and the lists @@ -408,74 +348,74 @@ DummyLoadQueue (QUEUE *QueuePtr, DECODE_REF fh) (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); /* BYTE* 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 */ + read_ptr (fh); /* HLINK head */ + read_ptr (fh); /* HLINK tail */ + read_ptr (fh); /* BYTE* pq_tab */ + read_ptr (fh); /* HLINK free_list */ + read_16 (fh, NULL); /* MEM_HANDLE hq_tab */ + read_16 (fh, NULL); /* COUNT object_size */ + read_8 (fh, NULL); /* BYTE num_objects */ - cread_8 (fh, NULL); /* padding */ - cread_16 (fh, NULL); /* padding */ + read_8 (fh, NULL); /* padding */ + read_16 (fh, NULL); /* padding */ } static void -LoadClockState (CLOCK_STATE *ClockPtr, DECODE_REF fh) +LoadClockState (CLOCK_STATE *ClockPtr, void *fh) { - cread_8 (fh, &ClockPtr->day_index); - cread_8 (fh, &ClockPtr->month_index); - cread_16 (fh, &ClockPtr->year_index); - cread_16s (fh, &ClockPtr->tick_count); - cread_16s (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, NULL); /* not loading; DWORD TimeCounter */ + read_8 (fh, &ClockPtr->day_index); + read_8 (fh, &ClockPtr->month_index); + read_16 (fh, &ClockPtr->year_index); + read_16s (fh, &ClockPtr->tick_count); + read_16s (fh, &ClockPtr->day_in_ticks); + read_ptr (fh); /* not loading ptr; Semaphore clock_sem */ + read_ptr (fh); /* not loading ptr; Task clock_task */ + read_32 (fh, NULL); /* not loading; DWORD TimeCounter */ DummyLoadQueue (&ClockPtr->event_q, fh); } static void -LoadGameState (GAME_STATE *GSPtr, DECODE_REF fh) +LoadGameState (GAME_STATE *GSPtr, void *fh) { BYTE dummy8; - cread_8 (fh, &dummy8); /* 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; PRIMITIVE *DisplayArray */ - cread_16 (fh, &GSPtr->CurrentActivity); + read_8 (fh, &dummy8); /* obsolete */ + read_8 (fh, &GSPtr->glob_flags); + read_8 (fh, &GSPtr->CrewCost); + read_8 (fh, &GSPtr->FuelCost); + read_a8 (fh, GSPtr->ModuleCost, NUM_MODULES); + read_a8 (fh, GSPtr->ElementWorth, NUM_ELEMENT_CATEGORIES); + read_ptr (fh); /* not loading ptr; PRIMITIVE *DisplayArray */ + read_16 (fh, &GSPtr->CurrentActivity); - cread_16 (fh, NULL); /* CLOCK_STATE alignment padding */ + read_16 (fh, NULL); /* CLOCK_STATE alignment padding */ LoadClockState (&GSPtr->GameClock, fh); - cread_16s (fh, &GSPtr->autopilot.x); - cread_16s (fh, &GSPtr->autopilot.y); - cread_16s (fh, &GSPtr->ip_location.x); - cread_16s (fh, &GSPtr->ip_location.y); + read_16s (fh, &GSPtr->autopilot.x); + read_16s (fh, &GSPtr->autopilot.y); + read_16s (fh, &GSPtr->ip_location.x); + read_16s (fh, &GSPtr->ip_location.y); /* STAMP ShipStamp */ - cread_16s (fh, &GSPtr->ShipStamp.origin.x); - cread_16s (fh, &GSPtr->ShipStamp.origin.y); - cread_16 (fh, &GSPtr->ShipFacing); - cread_8 (fh, &GSPtr->ip_planet); - cread_8 (fh, &GSPtr->in_orbit); + read_16s (fh, &GSPtr->ShipStamp.origin.x); + read_16s (fh, &GSPtr->ShipStamp.origin.y); + read_16 (fh, &GSPtr->ShipFacing); + read_8 (fh, &GSPtr->ip_planet); + read_8 (fh, &GSPtr->in_orbit); /* VELOCITY_DESC velocity */ - cread_16 (fh, &GSPtr->velocity.TravelAngle); - cread_16s (fh, &GSPtr->velocity.vector.width); - cread_16s (fh, &GSPtr->velocity.vector.height); - cread_16s (fh, &GSPtr->velocity.fract.width); - cread_16s (fh, &GSPtr->velocity.fract.height); - cread_16s (fh, &GSPtr->velocity.error.width); - cread_16s (fh, &GSPtr->velocity.error.height); - cread_16s (fh, &GSPtr->velocity.incr.width); - cread_16s (fh, &GSPtr->velocity.incr.height); - cread_16 (fh, NULL); /* VELOCITY_DESC padding */ + read_16 (fh, &GSPtr->velocity.TravelAngle); + read_16s (fh, &GSPtr->velocity.vector.width); + read_16s (fh, &GSPtr->velocity.vector.height); + read_16s (fh, &GSPtr->velocity.fract.width); + read_16s (fh, &GSPtr->velocity.fract.height); + read_16s (fh, &GSPtr->velocity.error.width); + read_16s (fh, &GSPtr->velocity.error.height); + read_16s (fh, &GSPtr->velocity.incr.width); + read_16s (fh, &GSPtr->velocity.incr.height); + read_16 (fh, NULL); /* VELOCITY_DESC padding */ - cread_32 (fh, &GSPtr->BattleGroupRef); + read_32 (fh, &GSPtr->BattleGroupRef); DummyLoadQueue (&GSPtr->avail_race_q, fh); DummyLoadQueue (&GSPtr->npc_built_ship_q, fh); @@ -483,17 +423,17 @@ LoadGameState (GAME_STATE *GSPtr, DECODE_REF fh) DummyLoadQueue (&GSPtr->encounter_q, fh); DummyLoadQueue (&GSPtr->built_ship_q, fh); - cread_a8 (fh, GSPtr->GameState, sizeof (GSPtr->GameState)); + read_a8 (fh, GSPtr->GameState, sizeof (GSPtr->GameState)); assert (sizeof (GSPtr->GameState) % 4 == 3); - cread_8 (fh, NULL); /* GAME_STATE alignment padding */ + read_8 (fh, NULL); /* GAME_STATE alignment padding */ } static BOOLEAN -LoadSisState (SIS_STATE *SSPtr, void *fp, SDWORD first, BOOLEAN legacy) +LoadSisState (SIS_STATE *SSPtr, void *fp) { - SSPtr->log_x = first; if ( + read_32s (fp, &SSPtr->log_x) != 1 || read_32s (fp, &SSPtr->log_y) != 1 || read_32 (fp, &SSPtr->ResUnits) != 1 || read_32 (fp, &SSPtr->FuelOnBoard) != 1 || @@ -511,45 +451,33 @@ LoadSisState (SIS_STATE *SSPtr, void *fp, SDWORD first, BOOLEAN legacy) read_str (fp, SSPtr->PlanetName, SIS_NAME_SIZE) != 1 ) return FALSE; - if (legacy && (read_16 (fp, NULL) != 1)) - return FALSE; return TRUE; } static BOOLEAN -LoadSummary (SUMMARY_DESC *SummPtr, void *fp, BOOLEAN *legacy_ptr) +LoadSummary (SUMMARY_DESC *SummPtr, void *fp) { SDWORD magic; DWORD nameSize = 0; - BOOLEAN legacy; if (!read_32s (fp, &magic)) return FALSE; if (magic == SAVE_MAGIC) { - legacy = FALSE; - *legacy_ptr = FALSE; if (read_32 (fp, &magic) != 1 || magic != SUMMARY_MAGIC) return FALSE; if (read_32 (fp, &magic) != 1 || magic < 161) return FALSE; nameSize = magic - 160; - // Read in the real first value for LoadSisState - if (read_32 (fp, &magic) != 1) - return FALSE; } else { - // Otherwise, we're legacy and the "magic" number was - // really LoadSisState's first value - legacy = TRUE; - *legacy_ptr = TRUE; + return FALSE; } - if (!LoadSisState (&SummPtr->SS, fp, magic, legacy)) + if (!LoadSisState (&SummPtr->SS, fp)) return FALSE; - if ( - read_8 (fp, &SummPtr->Activity) != 1 || + 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 || @@ -563,42 +491,33 @@ LoadSummary (SUMMARY_DESC *SummPtr, void *fp, BOOLEAN *legacy_ptr) ) return FALSE; - if (!legacy) + if (nameSize < SAVE_NAME_SIZE) { - if (nameSize < SAVE_NAME_SIZE) - { - if (read_a8 (fp, SummPtr->SaveName, nameSize) != 1) - return FALSE; - SummPtr->SaveName[nameSize] = 0; - } - else - { - DWORD remaining = nameSize - SAVE_NAME_SIZE + 1; - if (read_a8 (fp, SummPtr->SaveName, SAVE_NAME_SIZE-1) != 1) - return FALSE; - SummPtr->SaveName[SAVE_NAME_SIZE-1] = 0; - if (skip_8 (fp, remaining) != 1) - return FALSE; - } + if (read_a8 (fp, SummPtr->SaveName, nameSize) != 1) + return FALSE; + SummPtr->SaveName[nameSize] = 0; } else { - SummPtr->SaveName[0] = 0; - if (read_16 (fp, NULL) != 1) /* padding */ + DWORD remaining = nameSize - SAVE_NAME_SIZE + 1; + if (read_a8 (fp, SummPtr->SaveName, SAVE_NAME_SIZE-1) != 1) + return FALSE; + SummPtr->SaveName[SAVE_NAME_SIZE-1] = 0; + if (skip_8 (fp, remaining) != 1) return FALSE; } return TRUE; } static void -LoadStarDesc (STAR_DESC *SDPtr, DECODE_REF fh) +LoadStarDesc (STAR_DESC *SDPtr, void *fh) { - cread_16s(fh, &SDPtr->star_pt.x); - cread_16s(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); + read_16s(fh, &SDPtr->star_pt.x); + read_16s(fh, &SDPtr->star_pt.y); + read_8 (fh, &SDPtr->Type); + read_8 (fh, &SDPtr->Index); + read_8 (fh, &SDPtr->Prefix); + read_8 (fh, &SDPtr->Postfix); } BOOLEAN @@ -609,23 +528,20 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) char buf[256]; SUMMARY_DESC loc_sd; GAME_STATE_FILE *fp; - DECODE_REF fh; COUNT num_links; STAR_DESC SD; ACTIVITY Activity; - BOOLEAN legacy; DWORD chunk, chunkSize; - sprintf (file, "starcon2.%02u", which_game); + sprintf (file, "uqmsave.%02u", which_game); in_fp = res_OpenResFile (saveDir, file, "rb"); if (!in_fp) - return FALSE; + return LoadLegacyGame (which_game, SummPtr); - if (!LoadSummary (&loc_sd, in_fp, &legacy)) + if (!LoadSummary (&loc_sd, in_fp)) { - log_add (log_Error, "Warning: Savegame is corrupt"); res_CloseResFile (in_fp); - return FALSE; + return LoadLegacyGame (which_game, SummPtr); } if (!SummPtr) @@ -639,54 +555,27 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) 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 (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_Error, "Warning: Savegame corrupt or from " - "an incompatible platform."); - res_CloseResFile (in_fp); - return FALSE; - } - GlobData.SIS_state = SummPtr->SS; - if (!legacy) + chunk = 0; + while (chunk != OMNIBUS_MAGIC) { - chunk = 0; - while (chunk != OMNIZIP_MAGIC) + if (read_32(in_fp, &chunk) != 1) { - if (read_32(in_fp, &chunk) != 1) - { - res_CloseResFile (in_fp); - return FALSE; - } - if (read_32(in_fp, &chunkSize) != 1) - { - res_CloseResFile (in_fp); - return FALSE; - } - if (chunk == OMNIZIP_MAGIC) - break; - - log_add (log_Debug, "Skipping chunk of tag %08X (size %u)", chunk, chunkSize); - if (skip_8(in_fp, chunkSize) != 1) - return FALSE; + res_CloseResFile (in_fp); + return FALSE; } - /* Fortunately for us, the OmnZ chunk is internally - * self-sizing, so we can ignore the chunk size as long as we - * aren't skipping it. */ - } + if (read_32(in_fp, &chunkSize) != 1) + { + res_CloseResFile (in_fp); + return FALSE; + } + if (chunk == OMNIBUS_MAGIC) + break; - if ((fh = copen (in_fp, FILE_STREAM, STREAM_READ)) == 0) - { - res_CloseResFile (in_fp); - return FALSE; + log_add (log_Debug, "Skipping chunk of tag %08X (size %u)", chunk, chunkSize); + if (skip_8(in_fp, chunkSize) != 1) + return FALSE; } ReinitQueue (&GLOBAL (GameClock.event_q)); @@ -697,11 +586,11 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) memset (&GLOBAL (GameState[0]), 0, sizeof (GLOBAL (GameState))); Activity = GLOBAL (CurrentActivity); - LoadGameState (&GlobData.Game_state, fh); + LoadGameState (&GlobData.Game_state, in_fp); NextActivity = GLOBAL (CurrentActivity); GLOBAL (CurrentActivity) = Activity; - LoadRaceQueue (fh, &GLOBAL (avail_race_q)); + LoadRaceQueue (in_fp, &GLOBAL (avail_race_q)); // START_INTERPLANETARY is only set when saving from Homeworld // encounter screen. When the game is loaded, the // GenerateOrbitalFunction for the current star system will @@ -709,22 +598,22 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) if (!(NextActivity & START_INTERPLANETARY)) { if (NextActivity & START_ENCOUNTER) - LoadShipQueue (fh, &GLOBAL (npc_built_ship_q)); + LoadShipQueue (in_fp, &GLOBAL (npc_built_ship_q)); else if (LOBYTE (NextActivity) == IN_INTERPLANETARY) // XXX: Technically, this queue does not need to be // saved/loaded at all. IP groups will be reloaded // from group state files. But the original code did, // and so will we until we can prove we do not need to. - LoadGroupQueue (fh, &GLOBAL (ip_group_q)); + LoadGroupQueue (in_fp, &GLOBAL (ip_group_q)); else // XXX: The empty queue read is only needed to maintain // the savegame compatibility - LoadEmptyQueue (fh); + LoadEmptyQueue (in_fp); } - LoadShipQueue (fh, &GLOBAL (built_ship_q)); + LoadShipQueue (in_fp, &GLOBAL (built_ship_q)); // Load the game events (compressed) - cread_16 (fh, &num_links); + read_16 (in_fp, &num_links); { #ifdef DEBUG_LOAD log_add (log_Debug, "EVENTS:"); @@ -737,7 +626,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) hEvent = AllocEvent (); LockEvent (hEvent, &EventPtr); - LoadEvent (EventPtr, fh); + LoadEvent (EventPtr, in_fp); #ifdef DEBUG_LOAD log_add (log_Debug, "\t%u/%u/%u -- %u", @@ -752,7 +641,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) } // Load the encounters (black globes in HS/QS (compressed)) - cread_16 (fh, &num_links); + read_16 (in_fp, &num_links); { while (num_links--) { @@ -762,7 +651,7 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) hEncounter = AllocEncounter (); LockEncounter (hEncounter, &EncounterPtr); - LoadEncounter (EncounterPtr, fh); + LoadEncounter (EncounterPtr, in_fp); UnlockEncounter (hEncounter); PutEncounter (hEncounter); @@ -775,13 +664,13 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) { DWORD flen; - cread_32 (fh, &flen); + read_32 (in_fp, &flen); while (flen) { COUNT num_bytes; num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; - cread (buf, num_bytes, 1, fh); + read_a8 (in_fp, buf, num_bytes); WriteStateFile (buf, num_bytes, 1, fp); flen -= num_bytes; @@ -795,13 +684,13 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) { DWORD flen; - cread_32 (fh, &flen); + read_32 (in_fp, &flen); while (flen) { COUNT num_bytes; num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; - cread (buf, num_bytes, 1, fh); + read_a8 (in_fp, buf, num_bytes); WriteStateFile (buf, num_bytes, 1, fp); flen -= num_bytes; @@ -815,13 +704,13 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) { DWORD flen; - cread_32 (fh, &flen); + read_32 (in_fp, &flen); while (flen) { COUNT num_bytes; num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; - cread (buf, num_bytes, 1, fh); + read_a8 (in_fp, buf, num_bytes); WriteStateFile (buf, num_bytes, 1, fp); flen -= num_bytes; @@ -829,9 +718,8 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) CloseStateFile (fp); } - LoadStarDesc (&SD, fh); + LoadStarDesc (&SD, in_fp); - cclose (fh); res_CloseResFile (in_fp); EncounterGroup = 0; diff --git a/sc2/src/uqm/load_legacy.c b/sc2/src/uqm/load_legacy.c new file mode 100644 index 000000000..3c7a7e702 --- /dev/null +++ b/sc2/src/uqm/load_legacy.c @@ -0,0 +1,761 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#include "build.h" +#include "libs/declib.h" +#include "encount.h" +#include "starmap.h" +#include "libs/file.h" +#include "globdata.h" +#include "options.h" +#include "save.h" +#include "setup.h" +#include "state.h" +#include "grpinfo.h" + +#include "libs/tasklib.h" +#include "libs/log.h" +#include "libs/misc.h" + +//#define DEBUG_LOAD + +// XXX: these should handle endian conversions later +static inline COUNT +cread_8 (DECODE_REF fh, BYTE *v) +{ + BYTE t; + if (!v) /* read value ignored */ + v = &t; + return cread (v, 1, 1, fh); +} + +static inline COUNT +cread_16 (DECODE_REF fh, UWORD *v) +{ + UWORD t; + if (!v) /* read value ignored */ + v = &t; + return cread (v, 2, 1, fh); +} + +static inline COUNT +cread_16s (DECODE_REF fh, SWORD *v) +{ + UWORD t; + COUNT ret; + // value was converted to unsigned when saved + ret = cread_16 (fh, &t); + // unsigned to signed conversion + if (v) + *v = t; + return ret; +} + +static inline COUNT +cread_32 (DECODE_REF fh, DWORD *v) +{ + DWORD t; + if (!v) /* read value ignored */ + v = &t; + return cread (v, 4, 1, fh); +} + +static inline COUNT +cread_32s (DECODE_REF fh, SDWORD *v) +{ + DWORD t; + COUNT ret; + // value was converted to unsigned when saved + ret = cread_32 (fh, &t); + // unsigned to signed conversion + if (v) + *v = t; + return ret; +} + +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, BYTE *ar, COUNT count) +{ + assert (ar != NULL); + return cread (ar, 1, count, fh) == count; +} + +static inline size_t +read_8 (void *fp, BYTE *v) +{ + BYTE t; + if (!v) /* read value ignored */ + v = &t; + return ReadResFile (v, 1, 1, fp); +} + +static inline size_t +read_16 (void *fp, UWORD *v) +{ + UWORD t; + if (!v) /* read value ignored */ + v = &t; + return ReadResFile (v, 2, 1, fp); +} + +static inline size_t +read_32 (void *fp, DWORD *v) +{ + DWORD t; + if (!v) /* read value ignored */ + v = &t; + return ReadResFile (v, 4, 1, fp); +} + +static inline size_t +read_32s (void *fp, SDWORD *v) +{ + DWORD t; + COUNT ret; + // value was converted to unsigned when saved + ret = read_32 (fp, &t); + // unsigned to signed conversion + if (v) + *v = t; + return ret; +} + +static inline size_t +read_ptr (void *fp) +{ + DWORD t; + return read_32 (fp, &t); /* ptrs are useless in saves */ +} + +static inline size_t +read_a8 (void *fp, BYTE *ar, COUNT count) +{ + assert (ar != NULL); + return ReadResFile (ar, 1, count, fp) == count; +} + +static inline size_t +read_str (void *fp, char *str, COUNT count) +{ + // no type conversion needed for strings + return read_a8 (fp, (BYTE *)str, count); +} + +static inline size_t +read_a16 (void *fp, UWORD *ar, COUNT count) +{ + assert (ar != NULL); + + for ( ; count > 0; --count, ++ar) + { + if (read_16 (fp, ar) != 1) + return 0; + } + return 1; +} + +static void +LoadEmptyQueue (DECODE_REF fh) +{ + COUNT num_links; + + cread_16 (fh, &num_links); + if (num_links) + { + log_add (log_Error, "LoadEmptyQueue(): BUG: the queue is not empty!"); +#ifdef DEBUG + explode (); +#endif + } +} + +static void +LoadShipQueue (DECODE_REF fh, QUEUE *pQueue) +{ + COUNT num_links; + + cread_16 (fh, &num_links); + + while (num_links--) + { + HSHIPFRAG hStarShip; + SHIP_FRAGMENT *FragPtr; + COUNT Index; + BYTE tmpb; + + cread_16 (fh, &Index); + + hStarShip = CloneShipFragment (Index, pQueue, 0); + FragPtr = LockShipFrag (pQueue, hStarShip); + + // Read SHIP_FRAGMENT elements + cread_16 (fh, NULL); /* unused: was which_side */ + cread_8 (fh, &FragPtr->captains_name_index); + cread_8 (fh, NULL); /* padding */ + cread_16 (fh, NULL); /* unused: was ship_flags */ + cread_8 (fh, &FragPtr->race_id); + cread_8 (fh, &FragPtr->index); + // XXX: reading crew as BYTE to maintain savegame compatibility + cread_8 (fh, &tmpb); + FragPtr->crew_level = tmpb; + cread_8 (fh, &tmpb); + FragPtr->max_crew = tmpb; + cread_8 (fh, &FragPtr->energy_level); + cread_8 (fh, &FragPtr->max_energy); + cread_16 (fh, NULL); /* unused; was loc.x */ + cread_16 (fh, NULL); /* unused; was loc.y */ + + UnlockShipFrag (pQueue, hStarShip); + } +} + +static void +LoadRaceQueue (DECODE_REF fh, QUEUE *pQueue) +{ + COUNT num_links; + + cread_16 (fh, &num_links); + + while (num_links--) + { + HFLEETINFO hStarShip; + FLEET_INFO *FleetPtr; + COUNT Index; + BYTE tmpb; + + cread_16 (fh, &Index); + + hStarShip = GetStarShipFromIndex (pQueue, Index); + FleetPtr = LockFleetInfo (pQueue, hStarShip); + + // Read FLEET_INFO elements + cread_16 (fh, &FleetPtr->allied_state); + cread_8 (fh, &FleetPtr->days_left); + cread_8 (fh, &FleetPtr->growth_fract); + cread_8 (fh, &tmpb); + FleetPtr->crew_level = tmpb; + cread_8 (fh, &tmpb); + FleetPtr->max_crew = tmpb; + cread_8 (fh, &FleetPtr->growth); + cread_8 (fh, &FleetPtr->max_energy); + cread_16s(fh, &FleetPtr->loc.x); + cread_16s(fh, &FleetPtr->loc.y); + + cread_16 (fh, &FleetPtr->actual_strength); + cread_16 (fh, &FleetPtr->known_strength); + cread_16s(fh, &FleetPtr->known_loc.x); + cread_16s(fh, &FleetPtr->known_loc.y); + cread_8 (fh, &FleetPtr->growth_err_term); + cread_8 (fh, &FleetPtr->func_index); + cread_16s(fh, &FleetPtr->dest_loc.x); + cread_16s(fh, &FleetPtr->dest_loc.y); + cread_16 (fh, NULL); /* alignment padding */ + + UnlockFleetInfo (pQueue, hStarShip); + } +} + +static void +LoadGroupQueue (DECODE_REF fh, QUEUE *pQueue) +{ + COUNT num_links; + + cread_16 (fh, &num_links); + + while (num_links--) + { + HIPGROUP hGroup; + IP_GROUP *GroupPtr; + BYTE tmpb; + + cread_16 (fh, NULL); /* unused; was race_id */ + + hGroup = BuildGroup (pQueue, 0); + GroupPtr = LockIpGroup (pQueue, hGroup); + + cread_16 (fh, NULL); /* unused; was which_side */ + cread_8 (fh, NULL); /* unused; was captains_name_index */ + cread_8 (fh, NULL); /* padding; for savegame compat */ + cread_16 (fh, &GroupPtr->group_counter); + cread_8 (fh, &GroupPtr->race_id); + cread_8 (fh, &tmpb); /* was var2 */ + GroupPtr->sys_loc = LONIBBLE (tmpb); + GroupPtr->task = HINIBBLE (tmpb); + cread_8 (fh, &GroupPtr->in_system); /* was crew_level */ + cread_8 (fh, NULL); /* unused; was max_crew */ + cread_8 (fh, &tmpb); /* was energy_level */ + GroupPtr->dest_loc = LONIBBLE (tmpb); + GroupPtr->orbit_pos = HINIBBLE (tmpb); + cread_8 (fh, &GroupPtr->group_id); /* was max_energy */ + cread_16s(fh, &GroupPtr->loc.x); + cread_16s(fh, &GroupPtr->loc.y); + + UnlockIpGroup (pQueue, hGroup); + } +} + +static void +LoadEncounter (ENCOUNTER *EncounterPtr, DECODE_REF fh) +{ + COUNT i; + BYTE tmpb; + + 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_16s (fh, &EncounterPtr->transition_state); + cread_16s (fh, &EncounterPtr->origin.x); + cread_16s (fh, &EncounterPtr->origin.y); + cread_16 (fh, &EncounterPtr->radius); + // former STAR_DESC fields + cread_16s (fh, &EncounterPtr->loc_pt.x); + cread_16s (fh, &EncounterPtr->loc_pt.y); + cread_8 (fh, &EncounterPtr->race_id); + cread_8 (fh, &tmpb); + EncounterPtr->num_ships = tmpb & ENCOUNTER_SHIPS_MASK; + EncounterPtr->flags = tmpb & ENCOUNTER_FLAGS_MASK; + cread_16 (fh, NULL); /* alignment padding */ + + // Load each entry in the BRIEF_SHIP_INFO array + for (i = 0; i < MAX_HYPER_SHIPS; i++) + { + BRIEF_SHIP_INFO *ShipInfo = &EncounterPtr->ShipList[i]; + + cread_16 (fh, NULL); /* useless; was SHIP_INFO.ship_flags */ + cread_8 (fh, &ShipInfo->race_id); + cread_8 (fh, NULL); /* useless; was SHIP_INFO.var2 */ + // XXX: reading crew as BYTE to maintain savegame compatibility + cread_8 (fh, &tmpb); + ShipInfo->crew_level = tmpb; + cread_8 (fh, &tmpb); + ShipInfo->max_crew = tmpb; + cread_8 (fh, NULL); /* useless; was SHIP_INFO.energy_level */ + cread_8 (fh, &ShipInfo->max_energy); + cread_16 (fh, NULL); /* useless; was SHIP_INFO.loc.x */ + cread_16 (fh, NULL); /* useless; was SHIP_INFO.loc.y */ + cread_32 (fh, NULL); /* useless val; STRING race_strings */ + cread_ptr (fh); /* useless ptr; FRAME icons */ + cread_ptr (fh); /* useless ptr; FRAME melee_icon */ + } + + // Load the stuff after the BRIEF_SHIP_INFO array + cread_32s (fh, &EncounterPtr->log_x); + cread_32s (fh, &EncounterPtr->log_y); +} + +static void +LoadEvent (EVENT *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 (QUEUE *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); /* BYTE* 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 (CLOCK_STATE *ClockPtr, DECODE_REF fh) +{ + cread_8 (fh, &ClockPtr->day_index); + cread_8 (fh, &ClockPtr->month_index); + cread_16 (fh, &ClockPtr->year_index); + cread_16s (fh, &ClockPtr->tick_count); + cread_16s (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, NULL); /* not loading; DWORD TimeCounter */ + + DummyLoadQueue (&ClockPtr->event_q, fh); +} + +static void +LoadGameState (GAME_STATE *GSPtr, DECODE_REF fh) +{ + BYTE dummy8; + + cread_8 (fh, &dummy8); /* 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; PRIMITIVE *DisplayArray */ + cread_16 (fh, &GSPtr->CurrentActivity); + + cread_16 (fh, NULL); /* CLOCK_STATE alignment padding */ + LoadClockState (&GSPtr->GameClock, fh); + + cread_16s (fh, &GSPtr->autopilot.x); + cread_16s (fh, &GSPtr->autopilot.y); + cread_16s (fh, &GSPtr->ip_location.x); + cread_16s (fh, &GSPtr->ip_location.y); + /* STAMP ShipStamp */ + cread_16s (fh, &GSPtr->ShipStamp.origin.x); + cread_16s (fh, &GSPtr->ShipStamp.origin.y); + cread_16 (fh, &GSPtr->ShipFacing); + cread_8 (fh, &GSPtr->ip_planet); + cread_8 (fh, &GSPtr->in_orbit); + + /* VELOCITY_DESC velocity */ + cread_16 (fh, &GSPtr->velocity.TravelAngle); + cread_16s (fh, &GSPtr->velocity.vector.width); + cread_16s (fh, &GSPtr->velocity.vector.height); + cread_16s (fh, &GSPtr->velocity.fract.width); + cread_16s (fh, &GSPtr->velocity.fract.height); + cread_16s (fh, &GSPtr->velocity.error.width); + cread_16s (fh, &GSPtr->velocity.error.height); + cread_16s (fh, &GSPtr->velocity.incr.width); + cread_16s (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); + // Not loading ip_group_q, was not there originally + 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 +LoadSisState (SIS_STATE *SSPtr, void *fp) +{ + if ( + read_32s (fp, &SSPtr->log_x) != 1 || + read_32s (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 || + + read_str (fp, SSPtr->ShipName, SIS_NAME_SIZE) != 1 || + read_str (fp, SSPtr->CommanderName, SIS_NAME_SIZE) != 1 || + read_str (fp, SSPtr->PlanetName, SIS_NAME_SIZE) != 1 || + + read_16 (fp, NULL) != 1 /* padding */ + ) + return FALSE; + else + return TRUE; +} + +static BOOLEAN +LoadSummary (SUMMARY_DESC *SummPtr, void *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_DESC *SDPtr, DECODE_REF fh) +{ + cread_16s(fh, &SDPtr->star_pt.x); + cread_16s(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 +LoadLegacyGame (COUNT which_game, SUMMARY_DESC *SummPtr) +{ + uio_Stream *in_fp; + 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) + return FALSE; + + loc_sd.SaveName[0] = '\0'; + if (!LoadSummary (&loc_sd, in_fp)) + { + log_add (log_Error, "Warning: Savegame is corrupt"); + res_CloseResFile (in_fp); + return FALSE; + } + + 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; + } + + // 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_Error, "Warning: Savegame corrupt or from " + "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 (ip_group_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; + + LoadRaceQueue (fh, &GLOBAL (avail_race_q)); + // START_INTERPLANETARY is only set when saving from Homeworld + // encounter screen. When the game is loaded, the + // GenerateOrbitalFunction for the current star system will + // create the encounter anew and populate the npc queue. + if (!(NextActivity & START_INTERPLANETARY)) + { + if (NextActivity & START_ENCOUNTER) + LoadShipQueue (fh, &GLOBAL (npc_built_ship_q)); + else if (LOBYTE (NextActivity) == IN_INTERPLANETARY) + // XXX: Technically, this queue does not need to be + // saved/loaded at all. IP groups will be reloaded + // from group state files. But the original code did, + // and so will we until we can prove we do not need to. + LoadGroupQueue (fh, &GLOBAL (ip_group_q)); + else + // XXX: The empty queue read is only needed to maintain + // the savegame compatibility + LoadEmptyQueue (fh); + } + LoadShipQueue (fh, &GLOBAL (built_ship_q)); + + // 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; + EVENT *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--) + { + HENCOUNTER hEncounter; + ENCOUNTER *EncounterPtr; + + hEncounter = AllocEncounter (); + LockEncounter (hEncounter, &EncounterPtr); + + LoadEncounter (EncounterPtr, fh); + + 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/uqm/save.c b/sc2/src/uqm/save.c index 509515c15..bfaa140f5 100644 --- a/sc2/src/uqm/save.c +++ b/sc2/src/uqm/save.c @@ -41,38 +41,63 @@ #include "libs/inplib.h" #include "libs/log.h" #include "libs/memlib.h" -#include "libs/declib.h" +typedef struct savebuf_struct +{ + char *buf; + size_t bufsize; + int index, error; +} SAVEBUF; // XXX: these should handle endian conversions later static inline COUNT -cwrite_8 (DECODE_REF fh, BYTE v) +cwrite_8 (SAVEBUF *fh, BYTE v) { - return cwrite (&v, 1, 1, fh); + if (!fh) + return 0; + if (!fh->error && fh->index < fh->bufsize) + { + fh->buf[fh->index++] = v; + return 1; + } + fh->error = 1; + return 0; } static inline COUNT -cwrite_16 (DECODE_REF fh, UWORD v) +cwrite_16 (SAVEBUF *fh, UWORD v) { - return cwrite (&v, 2, 1, fh); + if (cwrite_8 (fh, (BYTE)(v & 0xFF)) && + cwrite_8 (fh, (BYTE)((v >> 8) & 0xFF))) + return 1; + return 0; } static inline COUNT -cwrite_32 (DECODE_REF fh, DWORD v) +cwrite_32 (SAVEBUF *fh, DWORD v) { - return cwrite (&v, 4, 1, fh); + if (cwrite_8 (fh, (BYTE)(v & 0xFF)) && + cwrite_8 (fh, (BYTE)((v >> 8) & 0xFF)) && + cwrite_8 (fh, (BYTE)((v >> 16) & 0xFF)) && + cwrite_8 (fh, (BYTE)((v >> 24) & 0xFF))) + return 1; + return 0; } static inline COUNT -cwrite_ptr (DECODE_REF fh) +cwrite_ptr (SAVEBUF *fh) { return cwrite_32 (fh, 0); /* ptrs are useless in saves */ } static inline COUNT -cwrite_a8 (DECODE_REF fh, const BYTE *ar, COUNT count) +cwrite_a8 (SAVEBUF *fh, const BYTE *ar, COUNT count) { - return cwrite (ar, 1, count, fh) == count; + int i; + for (i = 0; i < count; ++i) + if (!cwrite_8 (fh, ar[i])) + return 0; + return 1; } static inline size_t @@ -124,7 +149,7 @@ write_a16 (void *fp, const UWORD *ar, COUNT count) } static void -SaveEmptyQueue (DECODE_REF fh) +SaveEmptyQueue (SAVEBUF *fh) { COUNT num_links = 0; @@ -133,7 +158,7 @@ SaveEmptyQueue (DECODE_REF fh) } static void -SaveShipQueue (DECODE_REF fh, QUEUE *pQueue) +SaveShipQueue (SAVEBUF *fh, QUEUE *pQueue) { COUNT num_links; HSHIPFRAG hStarShip; @@ -178,7 +203,7 @@ SaveShipQueue (DECODE_REF fh, QUEUE *pQueue) } static void -SaveRaceQueue (DECODE_REF fh, QUEUE *pQueue) +SaveRaceQueue (SAVEBUF *fh, QUEUE *pQueue) { COUNT num_links; HFLEETINFO hFleet; @@ -228,7 +253,7 @@ SaveRaceQueue (DECODE_REF fh, QUEUE *pQueue) } static void -SaveGroupQueue (DECODE_REF fh, QUEUE *pQueue) +SaveGroupQueue (SAVEBUF *fh, QUEUE *pQueue) { HIPGROUP hGroup, hNextGroup; @@ -266,7 +291,7 @@ SaveGroupQueue (DECODE_REF fh, QUEUE *pQueue) } static void -SaveEncounter (const ENCOUNTER *EncounterPtr, DECODE_REF fh) +SaveEncounter (const ENCOUNTER *EncounterPtr, SAVEBUF *fh) { COUNT i; @@ -312,7 +337,7 @@ SaveEncounter (const ENCOUNTER *EncounterPtr, DECODE_REF fh) } static void -SaveEvent (const EVENT *EventPtr, DECODE_REF fh) +SaveEvent (const EVENT *EventPtr, SAVEBUF *fh) { cwrite_ptr (fh); /* useless ptr; HEVENT pred */ cwrite_ptr (fh); /* useless ptr; HEVENT succ */ @@ -325,7 +350,7 @@ SaveEvent (const EVENT *EventPtr, DECODE_REF fh) } static void -DummySaveQueue (const QUEUE *QueuePtr, DECODE_REF fh) +DummySaveQueue (const QUEUE *QueuePtr, SAVEBUF *fh) { /* QUEUE should never actually be saved since it contains * purely internal representation and the lists @@ -346,7 +371,7 @@ DummySaveQueue (const QUEUE *QueuePtr, DECODE_REF fh) } static void -SaveClockState (const CLOCK_STATE *ClockPtr, DECODE_REF fh) +SaveClockState (const CLOCK_STATE *ClockPtr, SAVEBUF *fh) { cwrite_8 (fh, ClockPtr->day_index); cwrite_8 (fh, ClockPtr->month_index); @@ -361,7 +386,7 @@ SaveClockState (const CLOCK_STATE *ClockPtr, DECODE_REF fh) } static void -SaveGameState (const GAME_STATE *GSPtr, DECODE_REF fh) +SaveGameState (const GAME_STATE *GSPtr, SAVEBUF *fh) { cwrite_8 (fh, 0); /* obsolete; BYTE cur_state */ cwrite_8 (fh, GSPtr->glob_flags); @@ -470,7 +495,7 @@ SaveSummary (const SUMMARY_DESC *SummPtr, void *fp) } static void -SaveStarDesc (const STAR_DESC *SDPtr, DECODE_REF fh) +SaveStarDesc (const STAR_DESC *SDPtr, SAVEBUF *fh) { cwrite_16 (fh, SDPtr->star_pt.x); cwrite_16 (fh, SDPtr->star_pt.y); @@ -644,14 +669,14 @@ SaveGame (COUNT which_game, SUMMARY_DESC *SummPtr, const char *name) { BOOLEAN success, made_room; void *out_fp, *h; - DECODE_REF fh; + SAVEBUF fh_backing, *fh; success = TRUE; made_room = FALSE; + fh = &fh_backing; RetrySave: - h = HMalloc (10 * 1024); - if (h == 0 - || (fh = copen (h, MEMORY_STREAM, STREAM_WRITE)) == 0) + h = HMalloc (128 * 1024); + if (h == 0) { if (success) { @@ -677,6 +702,10 @@ RetrySave: STAR_DESC SD; char buf[256], file[PATH_MAX]; + fh->buf = h; + fh->bufsize = 128 * 1024; + fh->index = 0; + fh->error = 0; success = TRUE; if (CurStarDescPtr) SD = *CurStarDescPtr; @@ -773,6 +802,7 @@ RetrySave: { flen = LengthStateFile (fp); // Write the uncompressed size. + printf ("Star Info: %u bytes\n", flen); cwrite_32 (fh, flen); while (flen) { @@ -780,7 +810,7 @@ RetrySave: num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; ReadStateFile (buf, num_bytes, 1, fp); - cwrite (buf, num_bytes, 1, fh); + cwrite_a8 (fh, buf, num_bytes); flen -= num_bytes; } @@ -793,6 +823,7 @@ RetrySave: { flen = LengthStateFile (fp); // Write the uncompressed size. + printf ("Defined Group Info: %u bytes\n", flen); cwrite_32 (fh, flen); while (flen) { @@ -800,7 +831,7 @@ RetrySave: num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; ReadStateFile (buf, num_bytes, 1, fp); - cwrite (buf, num_bytes, 1, fh); + cwrite_a8 (fh, buf, num_bytes); flen -= num_bytes; } @@ -813,6 +844,7 @@ RetrySave: { flen = LengthStateFile (fp); // Write the uncompressed size. + printf ("Random Group Info: %u bytes\n", flen); cwrite_32 (fh, flen); while (flen) { @@ -820,7 +852,7 @@ RetrySave: num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; ReadStateFile (buf, num_bytes, 1, fp); - cwrite (buf, num_bytes, 1, fh); + cwrite_a8 (fh, buf, num_bytes); flen -= num_bytes; } @@ -830,10 +862,10 @@ RetrySave: // Write the current star desc into the memory file (compressed). SaveStarDesc (&SD, fh); - flen = cclose (fh); + flen = fh->index; // Write the memory file to the actual savegame file. - sprintf (file, "starcon2.%02u", which_game); + sprintf (file, "uqmsave.%02u", which_game); log_add (log_Debug, "'%s' is %u bytes long", file, flen + 181 + strlen(SummPtr->SaveName)); if (flen && (out_fp = res_OpenResFile (saveDir, file, "wb"))) @@ -842,7 +874,7 @@ RetrySave: success = SaveSummary (SummPtr, out_fp); // Then write the rest of the data. - if (success && write_32 (out_fp, OMNIZIP_MAGIC) != 1) + if (success && write_32 (out_fp, OMNIBUS_MAGIC) != 1) success = FALSE; if (success && write_32 (out_fp, flen) != 1) success = FALSE; diff --git a/sc2/src/uqm/save.h b/sc2/src/uqm/save.h index f06c4a051..62602eb90 100644 --- a/sc2/src/uqm/save.h +++ b/sc2/src/uqm/save.h @@ -33,7 +33,7 @@ extern "C" { #define MAX_EXCLUSIVE_DEVICES 16 #define SAVE_MAGIC 0x01534d55 // "UMS\x01": UQM Save version 1 #define SUMMARY_MAGIC 0x6d6d7553 // "Summ": Summary. Must be first! -#define OMNIZIP_MAGIC 0x5a6e6d4f // "OmnZ": All data compressed. +#define OMNIBUS_MAGIC 0x696e6d4f // "Omni": All data, uncompressed #define SAVE_NAME_SIZE 64 typedef struct @@ -53,6 +53,7 @@ typedef struct extern ACTIVITY NextActivity; extern BOOLEAN LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc); +extern BOOLEAN LoadLegacyGame (COUNT which_game, SUMMARY_DESC *summary_desc); extern void SaveProblem (void); extern BOOLEAN SaveGame (COUNT which_game, SUMMARY_DESC *summary_desc, const char *name);