Merge branch 'better-saves'

This commit is contained in:
Michael Martin
2013-10-19 17:12:38 -07:00
21 changed files with 2397 additions and 1208 deletions
+2 -1
View File
@@ -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
+1 -1
View File
@@ -31,8 +31,8 @@
#include "endian_uqm.h"
#include "gamestr.h"
#include "options.h"
#include "load.h"
#include "oscill.h"
#include "save.h"
#include "settings.h"
#include "setup.h"
#include "sounds.h"
+219 -30
View File
@@ -26,7 +26,6 @@
#include "sis.h"
#include "units.h"
#include "gamestr.h"
#include "load.h"
#include "options.h"
#include "save.h"
#include "settings.h"
@@ -253,7 +252,7 @@ DrawNameString (bool nameCaptain, UNICODE *Str, COUNT CursorPos,
// disallow the change
return (FALSE);
}
PreUpdateFlashRect ();
SetContextForeGroundColor (BackGround);
@@ -264,7 +263,7 @@ DrawNameString (bool nameCaptain, UNICODE *Str, COUNT CursorPos,
text_r.corner.x += *pchar_deltas++;
if (CursorPos < lf.CharCount) /* end of line */
--text_r.corner.x;
if (state & DDSHS_BLOCKCUR)
{ // Use block cursor for keyboardless systems
if (CursorPos == lf.CharCount)
@@ -284,7 +283,7 @@ DrawNameString (bool nameCaptain, UNICODE *Str, COUNT CursorPos,
{ // Insertion point cursor
text_r.extent.width = 1;
}
text_r.corner.y = r.corner.y;
text_r.extent.height = r.extent.height;
SetContextForeGroundColor (BLACK_COLOR);
@@ -292,7 +291,7 @@ DrawNameString (bool nameCaptain, UNICODE *Str, COUNT CursorPos,
SetContextForeGroundColor (ForeGround);
font_DrawText (&lf);
PostUpdateFlashRect ();
}
@@ -347,15 +346,190 @@ NameCaptainOrShip (bool nameCaptain)
utf8StringCopy (Setting, tes.MaxSize, buf);
else
utf8StringCopy (buf, sizeof (buf), Setting);
SetFlashRect (SFR_MENU_3DO);
DrawNameString (nameCaptain, buf, 0, DDSHS_NORMAL);
if (namingCB)
namingCB ();
}
static BOOLEAN
DrawSaveNameString (UNICODE *Str, COUNT CursorPos, COUNT state, COUNT gameIndex)
{
RECT r;
TEXT lf;
Color BackGround, ForeGround;
FONT Font;
UNICODE fullStr[256], dateStr[80];
DateToString (dateStr, sizeof dateStr, GLOBAL(GameClock.month_index),
GLOBAL(GameClock.day_index), GLOBAL(GameClock.year_index));
strncat (dateStr, ": ", sizeof(dateStr) - strlen(dateStr) -1);
snprintf (fullStr, sizeof fullStr, "%s%s", dateStr, Str);
SetContextForeGroundColor (BUILD_COLOR (MAKE_RGB15 (0x1B, 0x00, 0x1B), 0x33));
r.extent.width = 15;
if (MAX_SAVED_GAMES > 99)
r.extent.width += 5;
r.extent.height = 11;
r.corner.x = 8;
r.corner.y = (160 + ((gameIndex % SAVES_PER_PAGE) * 13));
DrawRectangle (&r);
r.extent.width = (204 - SAFE_X);
r.corner.x = (30 + SAFE_X);
DrawRectangle (&r);
Font = TinyFont;
lf.baseline.x = r.corner.x + 3;
lf.baseline.y = r.corner.y + 8;
BackGround = BUILD_COLOR (MAKE_RGB15 (0x1B, 0x00, 0x1B), 0x33);
ForeGround = BUILD_COLOR (MAKE_RGB15 (0x00, 0x00, 0x14), 0x01);
lf.align = ALIGN_LEFT;
SetContextFont (Font);
lf.pStr = fullStr;
lf.CharCount = (COUNT)~0;
if (!(state & DDSHS_EDIT))
{
TEXT t;
SetContextForeGroundColor (BLACK_COLOR);
DrawFilledRectangle (&r);
t.baseline.x = r.corner.x + 3;
t.baseline.y = r.corner.y + 8;
t.align = ALIGN_LEFT;
t.pStr = Str;
t.CharCount = (COUNT)~0;
SetContextForeGroundColor (CAPTAIN_NAME_TEXT_COLOR);
font_DrawText (&lf);
}
else
{ // editing state
COUNT i, FullCursorPos;
RECT text_r;
BYTE char_deltas[256];
BYTE *pchar_deltas;
TextRect (&lf, &text_r, char_deltas);
if ((text_r.extent.width + 2) >= r.extent.width)
{ // the text does not fit the input box size and so
// will not fit when displayed later
// disallow the change
return (FALSE);
}
PreUpdateFlashRect ();
SetContextForeGroundColor (BackGround);
DrawFilledRectangle (&r);
pchar_deltas = char_deltas;
FullCursorPos = CursorPos + strlen(dateStr) - 1;
for (i = FullCursorPos; i > 0; --i)
text_r.corner.x += *pchar_deltas++;
if (FullCursorPos < lf.CharCount) /* end of line */
--text_r.corner.x;
if (state & DDSHS_BLOCKCUR)
{ // Use block cursor for keyboardless systems
if (FullCursorPos == lf.CharCount)
{ // cursor at end-line -- use insertion point
text_r.extent.width = 1;
}
else if (FullCursorPos + 1 == lf.CharCount)
{ // extra pixel for last char margin
text_r.extent.width = (SIZE)*pchar_deltas + 2;
}
else
{ // normal mid-line char
text_r.extent.width = (SIZE)*pchar_deltas + 1;
}
}
else
{ // Insertion point cursor
text_r.extent.width = 1;
}
text_r.corner.y = r.corner.y;
text_r.extent.height = r.extent.height;
SetContextForeGroundColor (BLACK_COLOR);
DrawFilledRectangle (&text_r);
SetContextForeGroundColor (ForeGround);
font_DrawText (&lf);
PostUpdateFlashRect ();
}
return (TRUE);
}
static BOOLEAN
OnSaveNameChange (TEXTENTRY_STATE *pTES)
{
COUNT hl = DDSHS_EDIT;
COUNT *gameIndex = pTES->CbParam;
if (pTES->JoystickMode)
hl |= DDSHS_BLOCKCUR;
return DrawSaveNameString (pTES->BaseStr, pTES->CursorPos, hl, *gameIndex);
}
static BOOLEAN
NameSaveGame (COUNT gameIndex, UNICODE *buf)
{
TEXTENTRY_STATE tes;
COUNT CursPos = strlen(buf);
COUNT *gIndex = HMalloc (sizeof (COUNT));
RECT r;
*gIndex = gameIndex;
DrawSaveNameString (buf, CursPos, DDSHS_EDIT, gameIndex);
tes.MaxSize = SAVE_NAME_SIZE;
// text entry setup
tes.Initialized = FALSE;
tes.BaseStr = buf;
tes.CursorPos = CursPos;
tes.CbParam = gIndex;
tes.ChangeCallback = OnSaveNameChange;
tes.FrameCallback = 0;
r.extent.width = (204 - SAFE_X);
r.extent.height = 11;
r.corner.x = (30 + SAFE_X);
r.corner.y = (160 + ((gameIndex % SAVES_PER_PAGE) * 13));
SetFlashRect (&r);
if (!DoTextEntry (&tes))
buf[0] = 0;
SetFlashRect(NULL);
DrawSaveNameString (buf, CursPos, DDSHS_NORMAL, gameIndex);
if (namingCB)
namingCB ();
SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT);
HFree (gIndex);
SetFlashRect (NULL);
if (tes.Success)
return (TRUE);
else
return (FALSE);
}
void
@@ -611,7 +785,7 @@ DrawSavegameSummary (PICK_GAME_STATE *pickState, COUNT gameIndex)
UninitQueue (&GLOBAL (built_ship_q));
SetContextClipRect (&OldRect);
SetContext (SpaceContext);
// draw devices
s.origin.y = 13;
@@ -680,7 +854,7 @@ DrawSavegameSummary (PICK_GAME_STATE *pickState, COUNT gameIndex)
SetContextForeGroundColor (
BUILD_COLOR (MAKE_RGB15 (0x10, 0x00, 0x10), 0x01));
font_DrawText (&t);
// print the location
t.baseline.x = 6;
t.baseline.y = 139 + 6;
@@ -697,7 +871,7 @@ DrawSavegameSummary (PICK_GAME_STATE *pickState, COUNT gameIndex)
{
BYTE QuasiState;
STAR_DESC *SDPtr;
QuasiState = GET_GAME_STATE (ARILOU_SPACE_SIDE);
SET_GAME_STATE (ARILOU_SPACE_SIDE, 0);
SDPtr = FindStar (NULL, &starPt, 1, 1);
@@ -770,11 +944,11 @@ DrawGameSelection (PICK_GAME_STATE *pickState, COUNT selSlot)
COUNT curSlot;
UNICODE buf[256];
UNICODE buf2[80];
BatchGraphics ();
SetContextFont (TinyFont);
// Erase the selection menu
r.extent.width = 240;
r.extent.height = 65;
@@ -825,9 +999,7 @@ DrawGameSelection (PICK_GAME_STATE *pickState, COUNT selSlot)
{
DateToString (buf2, sizeof buf2, desc->month_index,
desc->day_index, desc->year_index);
snprintf (buf, sizeof buf, "%s %s",
GAME_STRING (SAVEGAME_STRING_BASE + 4), buf2);
// "Saved Game - Date:"
snprintf (buf, sizeof buf, "%s: %s", buf2, desc->SaveName[0] ? desc->SaveName : GAME_STRING (SAVEGAME_STRING_BASE + 4));
}
font_DrawText (&t);
}
@@ -928,7 +1100,7 @@ DoPickGame (MENU_STATE *pMS)
SetContext (SpaceContext);
RedrawPickDisplay (pickState, pMS->CurState);
}
SleepThreadUntil (TimeIn + ONE_SECOND / 30);
}
@@ -936,22 +1108,38 @@ DoPickGame (MENU_STATE *pMS)
}
static BOOLEAN
SaveLoadGame (PICK_GAME_STATE *pickState, COUNT gameIndex)
SaveLoadGame (PICK_GAME_STATE *pickState, COUNT gameIndex, BOOLEAN *canceled_by_user)
{
SUMMARY_DESC *desc = pickState->summary + gameIndex;
UNICODE nameBuf[256];
STAMP saveStamp;
BOOLEAN success;
saveStamp.frame = NULL;
// TODO: fix ConfirmSaveLoad() interface so it does not rely on
// MsgStamp != NULL parameter.
ConfirmSaveLoad (pickState->saving ? &saveStamp : NULL);
if (pickState->saving)
success = SaveGame (gameIndex, desc);
{
// Initialize the save name with whatever name is there already
// SAVE_NAME_SIZE is less than 256, so this is safe.
strncpy(nameBuf, desc->SaveName, SAVE_NAME_SIZE);
nameBuf[SAVE_NAME_SIZE] = 0;
if (NameSaveGame (gameIndex, nameBuf))
{
PlayMenuSound (MENU_SOUND_SUCCESS);
ConfirmSaveLoad (pickState->saving ? &saveStamp : NULL);
success = SaveGame (gameIndex, desc, nameBuf);
}
else
{
success = FALSE;
*canceled_by_user = TRUE;
}
}
else
{
ConfirmSaveLoad (pickState->saving ? &saveStamp : NULL);
success = LoadGame (gameIndex, NULL);
}
// TODO: the same should be done for both save and load if we also
// display a load problem message
@@ -1005,12 +1193,12 @@ PickGame (BOOLEAN saving, BOOLEAN fromMainMenu)
// draw the current savegame and fade in
SetTransitionSource (NULL);
BatchGraphics ();
SetContextBackGroundColor (BLACK_COLOR);
ClearDrawable ();
RedrawPickDisplay (&pickState, MenuState.CurState);
DrawSaveLoad (&pickState);
if (fromMainMenu)
{
UnbatchGraphics ();
@@ -1028,10 +1216,12 @@ PickGame (BOOLEAN saving, BOOLEAN fromMainMenu)
SetMenuSounds (MENU_SOUND_ARROWS | MENU_SOUND_PAGEUP | MENU_SOUND_PAGEDOWN,
0);
MenuState.InputFunc = DoPickGame;
// Save/load retry loop
while (1)
{
BOOLEAN canceled_by_user = FALSE;
pickState.success = FALSE;
DoInput (&MenuState, TRUE);
if (!pickState.success)
@@ -1039,11 +1229,11 @@ PickGame (BOOLEAN saving, BOOLEAN fromMainMenu)
lastUsedSlot = MenuState.CurState;
if (SaveLoadGame (&pickState, MenuState.CurState))
if (SaveLoadGame (&pickState, MenuState.CurState, &canceled_by_user))
break; // all good
// something broke
if (saving)
if (saving && !canceled_by_user)
SaveProblem ();
// TODO: Shouldn't we have a Problem() equivalent for Load too?
@@ -1058,7 +1248,7 @@ PickGame (BOOLEAN saving, BOOLEAN fromMainMenu)
{ // Load succeeded, signal up the chain
GLOBAL (CurrentActivity) |= CHECK_LOAD;
}
if (!(GLOBAL (CurrentActivity) & CHECK_ABORT) &&
(saving || (!pickState.success && !fromMainMenu)))
{ // Restore previous screen
@@ -1145,7 +1335,7 @@ GameOptions (void)
DrawMenuStateStrings (PM_SAVE_GAME, MenuState.CurState);
SetFlashRect (SFR_MENU_3DO);
SetMenuSounds (MENU_SOUND_ARROWS, MENU_SOUND_SELECT);
MenuState.InputFunc = DoGameOptions;
DoInput (&MenuState, TRUE);
@@ -1154,4 +1344,3 @@ GameOptions (void)
return !(GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_LOAD));
}
+29 -13
View File
@@ -48,31 +48,31 @@ GLOBDATA GlobData;
BYTE
getGameState (int startBit, int endBit)
getGameState (BYTE *state, int startBit, int endBit)
{
return (BYTE) (((startBit >> 3) == (endBit >> 3)
? (GLOBAL (GameState[startBit >> 3]) >> (startBit & 7))
: ((GLOBAL (GameState[startBit >> 3]) >> (startBit & 7))
| (GLOBAL (GameState[endBit >> 3])
? (state[startBit >> 3] >> (startBit & 7))
: ((state[startBit >> 3] >> (startBit & 7))
| (state[endBit >> 3]
<< (endBit - startBit - (endBit & 7)))))
& ((1 << (endBit - startBit + 1)) - 1));
}
void
setGameState (int startBit, int endBit, BYTE val
setGameState (BYTE *state, int startBit, int endBit, BYTE val
#ifdef STATE_DEBUG
, const char *name
#endif
)
{
GLOBAL (GameState[startBit >> 3]) =
(GLOBAL (GameState[startBit >> 3])
state[startBit >> 3] =
(state[startBit >> 3]
& (BYTE) ~(((1 << (endBit - startBit + 1)) - 1) << (startBit & 7)))
| (BYTE)((val) << (startBit & 7));
if ((startBit >> 3) < (endBit >> 3)) {
GLOBAL (GameState[endBit >> 3]) =
(GLOBAL (GameState[endBit >> 3])
state[endBit >> 3] =
(state[endBit >> 3]
& (BYTE)~((1 << ((endBit & 7) + 1)) - 1))
| (BYTE)((val) >> (endBit - startBit - (endBit & 7)));
}
@@ -82,21 +82,21 @@ setGameState (int startBit, int endBit, BYTE val
}
DWORD
getGameState32 (int startBit)
getGameState32 (BYTE *state, int startBit)
{
DWORD v;
int shift;
for (v = 0, shift = 0; shift < 32; shift += 8, startBit += 8)
{
v |= getGameState (startBit, startBit + 7) << shift;
v |= getGameState (state, startBit, startBit + 7) << shift;
}
return v;
}
void
setGameState32 (int startBit, DWORD val
setGameState32 (BYTE *state, int startBit, DWORD val
#ifdef STATE_DEBUG
, const char *name
#endif
@@ -107,7 +107,7 @@ setGameState32 (int startBit, DWORD val
for (i = 0; i < 4; ++i, v >>= 8, startBit += 8)
{
setGameState (startBit, startBit + 7, v & 0xff
setGameState (state, startBit, startBit + 7, v & 0xff
#ifdef STATE_DEBUG
, "(ignored)"
#endif
@@ -119,6 +119,22 @@ setGameState32 (int startBit, DWORD val
#endif
}
void
copyGameState (BYTE *dest, DWORD target, BYTE *src, DWORD begin, DWORD end)
{
while (begin < end)
{
BYTE b;
DWORD delta = 7;
if (begin + delta > end)
delta = end - begin;
b = getGameState (src, begin, begin + delta);
setGameState (dest, target, target + delta, b);
begin += 8;
target += 8;
}
}
static void
CreateRadar (void)
{
+118 -91
View File
@@ -255,61 +255,6 @@ START_GAME_STATE
ADD_GAME_STATE (LANDER_SHIELDS, 4)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS0, 8)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS1, 8)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS2, 8)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS3, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS0, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS1, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS2, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS3, 8)
ADD_GAME_STATE (MET_MELNORME, 1)
ADD_GAME_STATE (MELNORME_RESCUE_REFUSED, 1)
ADD_GAME_STATE (MELNORME_RESCUE_COUNT, 3)
@@ -329,10 +274,6 @@ START_GAME_STATE
ADD_GAME_STATE (MELNORME_PISSED_COUNT, 2)
ADD_GAME_STATE (MELNORME_HATE_COUNT, 2)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS0, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS1, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS2, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS3, 8)
ADD_GAME_STATE (PROBE_MESSAGE_DELIVERED, 1)
ADD_GAME_STATE (PROBE_ILWRATH_ENCOUNTER, 1)
@@ -647,11 +588,6 @@ START_GAME_STATE
ADD_GAME_STATE (URQUAN_PROTECTING_SAMATRA, 1)
ADD_GAME_STATE (COLONY_GRPOFFS0, 8)
ADD_GAME_STATE (COLONY_GRPOFFS1, 8)
ADD_GAME_STATE (COLONY_GRPOFFS2, 8)
ADD_GAME_STATE (COLONY_GRPOFFS3, 8)
#define THRADDASH_BODY_THRESHOLD 25
ADD_GAME_STATE (THRADDASH_BODY_COUNT, 5)
@@ -671,11 +607,6 @@ START_GAME_STATE
ADD_GAME_STATE (ILWRATH_WORSHIP, 2)
ADD_GAME_STATE (ILWRATH_FIGHT_THRADDASH, 1)
ADD_GAME_STATE (SAMATRA_GRPOFFS0, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS1, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS2, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS3, 8)
ADD_GAME_STATE (READY_TO_CONFUSE_URQUAN, 1)
ADD_GAME_STATE (URQUAN_HYPNO_VISITS, 1)
ADD_GAME_STATE (MENTIONED_PET_COMPULSION, 1)
@@ -877,6 +808,79 @@ START_GAME_STATE
ADD_GAME_STATE (ORZ_STACK0, 1)
ADD_GAME_STATE (ORZ_STACK1, 1)
/* These state bits are actually offsets into defgrp.dat. They really
* shouldn't be part of the serialized Game State array! --MCM */
ADD_GAME_STATE (SHOFIXTI_GRPOFFS0, 8)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS1, 8)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS2, 8)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS3, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS0, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS1, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS2, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS3, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS0, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS1, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS2, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS3, 8)
ADD_GAME_STATE (COLONY_GRPOFFS0, 8)
ADD_GAME_STATE (COLONY_GRPOFFS1, 8)
ADD_GAME_STATE (COLONY_GRPOFFS2, 8)
ADD_GAME_STATE (COLONY_GRPOFFS3, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS0, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS1, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS2, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS3, 8)
END_GAME_STATE
// Values for GAME_STATE.glob_flags:
@@ -970,38 +974,61 @@ extern GLOBDATA GlobData;
#define MAX_ENCOUNTERS 16
#define MAX_BATTLE_GROUPS 32
/* DEFGRP enumeration. These identify scripted TrueSpace encounters
* more consistently than offsets into the DEFGRPINFO_FILE state
* file. */
enum {
DEFGRP_NONE,
DEFGRP_SHOFIXTI,
DEFGRP_ZOQFOT,
DEFGRP_MELNORME0,
DEFGRP_MELNORME1,
DEFGRP_MELNORME2,
DEFGRP_MELNORME3,
DEFGRP_MELNORME4,
DEFGRP_MELNORME5,
DEFGRP_MELNORME6,
DEFGRP_MELNORME7,
DEFGRP_MELNORME8,
DEFGRP_URQUAN_PROBE,
DEFGRP_COLONY,
DEFGRP_SAMATRA,
NUM_DEFGRPS
};
//#define STATE_DEBUG
extern BYTE getGameState (int startBit, int endBit);
extern void setGameState (int startBit, int endBit, BYTE val
extern BYTE getGameState (BYTE *state, int startBit, int endBit);
extern void setGameState (BYTE *state, int startBit, int endBit, BYTE val
#ifdef STATE_DEBUG
, const char *name
#endif
);
extern void copyGameState (BYTE *dest, DWORD target, BYTE *src, DWORD begin, DWORD end);
#define GET_GAME_STATE(SName) getGameState (GLOBAL(GameState), (SName), (END_##SName))
#ifdef STATE_DEBUG
# define SET_GAME_STATE(SName, val) \
setGameState (GLOBAL(GameState), (SName), (END_##SName), (val), #SName)
#else
# define SET_GAME_STATE(SName, val) \
setGameState (GLOBAL(GameState), (SName), (END_##SName), (val))
#endif
extern DWORD getGameState32 (BYTE *state, int startBit);
extern void setGameState32 (BYTE *state, int startBit, DWORD val
#ifdef STATE_DEBUG
, const char *name
#endif
);
#define GET_GAME_STATE(SName) getGameState ((SName), (END_##SName))
#ifdef STATE_DEBUG
# define SET_GAME_STATE(SName, val) \
setGameState ((SName), (END_##SName), (val), #SName)
#else
# define SET_GAME_STATE(SName, val) \
setGameState ((SName), (END_##SName), (val))
#endif
extern DWORD getGameState32 (int startBit);
extern void setGameState32 (int startBit, DWORD val
#ifdef STATE_DEBUG
, const char *name
#endif
);
#define GET_GAME_STATE_32(SName) getGameState32 ((SName))
#define GET_GAME_STATE_32(SName) getGameState32 (GLOBAL(GameState), (SName))
#ifdef STATE_DEBUG
# define SET_GAME_STATE_32(SName, val) \
setGameState32 ((SName), (val), #SName)
setGameState32 (GLOBAL(GameState), (SName), (val), #SName)
#else
# define SET_GAME_STATE_32(SName, val) \
setGameState32 ((SName), (val))
setGameState32 (GLOBAL(GameState), (SName), (val))
#endif
+7 -42
View File
@@ -23,7 +23,7 @@
#include "globdata.h"
#include "intel.h"
#include "state.h"
#include "grpinfo.h"
#include "grpintrn.h"
#include "libs/mathlib.h"
#include "libs/log.h"
@@ -35,42 +35,7 @@
static BYTE LastEncGroup;
// Last encountered group, saved into state files
//#define DEBUG_GROUPS
// A group header describes battle groups present in a star system. There is
// at most 1 group header per system.
// 'Random' group info file (RANDGRPINFO_FILE) always contains only one
// group header record, which describes the last-visited star system,
// (which may be the current system). Thus the randomly generated groups
// are valid for 7 days (set in PutGroupInfo) after the player leaves
// the system, or until the player enters another star system.
typedef struct
{
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[NUM_SAVED_BATTLE_GROUPS + 1];
// Absolute offsets of group definitions in a state file
// Group 0 is a list of groups present in solarsys
// (RANDGRPINFO_FILE only)
// Groups 1..max are definitions of actual battle groups
// containing ship makeup and status
// Each group has the following format:
// 1 byte, RaceType (LastEncGroup in Group 0)
// 1 byte, NumShips (NumGroups in Group 0)
// Ships follow:
// 1 byte, RaceType
// 16 bytes, part of SHIP_FRAGMENT struct
} GROUP_HEADER;
static void
void
ReadGroupHeader (GAME_STATE_FILE *fp, GROUP_HEADER *pGH)
{
sread_8 (fp, &pGH->NumGroups);
@@ -82,7 +47,7 @@ ReadGroupHeader (GAME_STATE_FILE *fp, GROUP_HEADER *pGH)
sread_a32 (fp, pGH->GroupOffset, NUM_SAVED_BATTLE_GROUPS + 1);
}
static void
void
WriteGroupHeader (GAME_STATE_FILE *fp, const GROUP_HEADER *pGH)
{
swrite_8 (fp, pGH->NumGroups);
@@ -94,7 +59,7 @@ WriteGroupHeader (GAME_STATE_FILE *fp, const GROUP_HEADER *pGH)
swrite_a32 (fp, pGH->GroupOffset, NUM_SAVED_BATTLE_GROUPS + 1);
}
static void
void
ReadShipFragment (GAME_STATE_FILE *fp, SHIP_FRAGMENT *FragPtr)
{
BYTE tmpb;
@@ -116,7 +81,7 @@ ReadShipFragment (GAME_STATE_FILE *fp, SHIP_FRAGMENT *FragPtr)
sread_16 (fp, NULL); /* unused; was loc.y */
}
static void
void
WriteShipFragment (GAME_STATE_FILE *fp, const SHIP_FRAGMENT *FragPtr)
{
swrite_16 (fp, 0); /* unused: was which_side */
@@ -134,7 +99,7 @@ WriteShipFragment (GAME_STATE_FILE *fp, const SHIP_FRAGMENT *FragPtr)
swrite_16 (fp, 0); /* unused; was loc.y */
}
static void
void
ReadIpGroup (GAME_STATE_FILE *fp, IP_GROUP *GroupPtr)
{
BYTE tmpb;
@@ -157,7 +122,7 @@ ReadIpGroup (GAME_STATE_FILE *fp, IP_GROUP *GroupPtr)
sread_16s(fp, &GroupPtr->loc.y);
}
static void
void
WriteIpGroup (GAME_STATE_FILE *fp, const IP_GROUP *GroupPtr)
{
swrite_16 (fp, 0); /* unused; was which_side */
+56
View File
@@ -0,0 +1,56 @@
#ifndef _GRPINTRN_H
#define _GRPINTRN_H
// For IPGROUP
#include "grpinfo.h"
// For SHIP_FRAGMENT
#include "races.h"
// For GAME_STATE_FILE
#include "state.h"
//#define DEBUG_GROUPS
// A group header describes battle groups present in a star system. There is
// at most 1 group header per system.
// 'Random' group info file (RANDGRPINFO_FILE) always contains only one
// group header record, which describes the last-visited star system,
// (which may be the current system). Thus the randomly generated groups
// are valid for 7 days (set in PutGroupInfo) after the player leaves
// the system, or until the player enters another star system.
typedef struct
{
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[NUM_SAVED_BATTLE_GROUPS + 1];
// Absolute offsets of group definitions in a state file
// Group 0 is a list of groups present in solarsys
// (RANDGRPINFO_FILE only)
// Groups 1..max are definitions of actual battle groups
// containing ship makeup and status
// Each group has the following format:
// 1 byte, RaceType (LastEncGroup in Group 0)
// 1 byte, NumShips (NumGroups in Group 0)
// Ships follow:
// 1 byte, RaceType
// 16 bytes, part of SHIP_FRAGMENT struct
// (part of IP_GROUP struct in Group 0)
} GROUP_HEADER;
void ReadGroupHeader (GAME_STATE_FILE *fp, GROUP_HEADER *pGH);
void WriteGroupHeader (GAME_STATE_FILE *fp, const GROUP_HEADER *pGH);
void ReadShipFragment (GAME_STATE_FILE *fp, SHIP_FRAGMENT *FragPtr);
void WriteShipFragment (GAME_STATE_FILE *fp, const SHIP_FRAGMENT *FragPtr);
void ReadIpGroup (GAME_STATE_FILE *fp, IP_GROUP *GroupPtr);
void WriteIpGroup (GAME_STATE_FILE *fp, const IP_GROUP *GroupPtr);
#endif
+475 -471
View File
File diff suppressed because it is too large Load Diff
-39
View File
@@ -1,39 +0,0 @@
/*
* 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
*/
#ifndef _LOAD_H
#define _LOAD_H
#include "sis.h"
// for SUMMARY_DESC
#include "libs/compiler.h"
#include "globdata.h"
#if defined(__cplusplus)
extern "C" {
#endif
extern ACTIVITY NextActivity;
extern BOOLEAN LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc);
#if defined(__cplusplus)
}
#endif
#endif /* _LOAD_H */
+821
View File
@@ -0,0 +1,821 @@
//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 <assert.h>
#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;
}
typedef struct struct_GAMESTATE_TRANSPOSE {
int start, end, target;
} GAMESTATE_TRANSPOSE;
#define LEGACY_GAMESTATE_SIZE 155
/* The *_GRPOFFS* states are no longer intermingled with the rest of
* the state. We need to shuffle all the rest of the state data
* down. */
static GAMESTATE_TRANSPOSE transpose[] = {
{ 0, 51, 0 },
{ 404, 450, 52 },
{ 483, 878, 99 },
{ 911, 930, 495 },
{ 963, 1237, 515 },
{ -1, -1, -1 } };
static DWORD old_defgrp_offsets[] = { 0, 52, 84, 116, 148, 180, 212, 244,
276, 308, 340, 372, 451, 879, 931 };
static DWORD new_defgrp_offsets[] = {
0,
SHOFIXTI_GRPOFFS0,
ZOQFOT_GRPOFFS0,
MELNORME0_GRPOFFS0,
MELNORME1_GRPOFFS0,
MELNORME2_GRPOFFS0,
MELNORME3_GRPOFFS0,
MELNORME4_GRPOFFS0,
MELNORME5_GRPOFFS0,
MELNORME6_GRPOFFS0,
MELNORME7_GRPOFFS0,
MELNORME8_GRPOFFS0,
URQUAN_PROBE_GRPOFFS0,
COLONY_GRPOFFS0,
SAMATRA_GRPOFFS0
};
static void
InterpretLegacyGameState (BYTE *result, BYTE *legacy)
{
int i;
DWORD grpoffs[NUM_DEFGRPS];
GAMESTATE_TRANSPOSE *t = &transpose[0];
grpoffs[0] = 0;
for (i = 1; i < NUM_DEFGRPS; ++i)
{
grpoffs[i] = getGameState32 (legacy, old_defgrp_offsets[i]);
}
while (t->start >= 0)
{
copyGameState (result, t->target, legacy, t->start, t->end);
++t;
}
for (i = 1; i < NUM_DEFGRPS; ++i)
{
setGameState32 (result, new_defgrp_offsets[i], grpoffs[i]);
}
}
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, oldstate[LEGACY_GAMESTATE_SIZE];
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, oldstate, LEGACY_GAMESTATE_SIZE);
InterpretLegacyGameState (GSPtr->GameState, oldstate);
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;
}
+1 -1
View File
@@ -23,9 +23,9 @@
#include "../encount.h"
#include "../gamestr.h"
#include "../controls.h"
#include "../save.h"
#include "../settings.h"
#include "../shipcont.h"
#include "../load.h"
#include "../setup.h"
#include "../state.h"
#include "../sis.h"
+1 -1
View File
@@ -30,13 +30,13 @@
#include "../nameref.h"
#include "../resinst.h"
#include "../settings.h"
#include "../load.h"
#include "../util.h"
#include "../process.h"
#include "../setup.h"
#include "../sounds.h"
#include "../state.h"
#include "../sis.h"
#include "../save.h"
#include "options.h"
#include "libs/graphics/gfx_common.h"
#include "libs/graphics/drawable.h"
+1 -1
View File
@@ -37,11 +37,11 @@
#include "../ipdisp.h"
#include "../grpinfo.h"
#include "../process.h"
#include "../load.h"
#include "../setup.h"
#include "../sounds.h"
#include "../state.h"
#include "../uqmdebug.h"
#include "../save.h"
#include "options.h"
#include "libs/graphics/gfx_common.h"
#include "libs/mathlib.h"
+1 -1
View File
@@ -30,8 +30,8 @@
#include "supermelee/melee.h"
#include "resinst.h"
#include "nameref.h"
#include "save.h"
#include "settings.h"
#include "load.h"
#include "setup.h"
#include "sounds.h"
#include "setupmenu.h"
+466 -489
View File
File diff suppressed because it is too large Load Diff
+46 -3
View File
@@ -17,16 +17,59 @@
#ifndef _SAVE_H
#define _SAVE_H
#include "sis.h"
// for SUMMARY_DESC
#include "sis.h" // SUMMARY_DESC includes SIS_STATE in it
#include "globdata.h"
#include "libs/compiler.h"
#if defined(__cplusplus)
extern "C" {
#endif
// XXX: Theoretically, a player can have 17 devices on board without
// cheating. We only provide
// room for 16 below, which is not really a problem since this
// is only used for displaying savegame summaries. There is also
// room for only 16 devices on screen.
#define MAX_EXCLUSIVE_DEVICES 16
#define SAVE_NAME_SIZE 64
// The savefile tag numbers.
#define SAVEFILE_TAG 0x01534d55 // "UMS\x01": UQM Save version 1
#define SUMMARY_TAG 0x6d6d7553 // "Summ": Summary. Must be first!
#define GLOBAL_STATE_TAG 0x74536c47 // "GlSt": Global State. Must be 2nd!
#define GAME_STATE_TAG 0x74536d47 // "GmSt": Game State Bits. Must be 3rd!
#define EVENTS_TAG 0x73747645 // "Evts": Events
#define ENCOUNTERS_TAG 0x74636e45 // "Enct": Encounters
#define RACE_Q_TAG 0x51636152 // "RacQ": avail_race_q
#define IP_GRP_Q_TAG 0x51704749 // "IGpQ": ip_group_q
#define NPC_SHIP_Q_TAG 0x5163704e // "NpcQ": npc_built_ship_q
#define SHIP_Q_TAG 0x51706853 // "ShpQ": built_ship_q
#define STAR_TAG 0x72617453 // "Star": STAR_DESC
#define SCAN_TAG 0x6e616353 // "Scan": Scan Masks (stuff picked up)
#define BATTLE_GROUP_TAG 0x70477442 // "BtGp": Battle Group definition
#define GROUP_LIST_TAG 0x73707247 // "Grps": Group List
typedef struct
{
SIS_STATE SS;
BYTE Activity;
BYTE Flags;
BYTE day_index, month_index;
COUNT year_index;
BYTE MCreditLo, MCreditHi;
BYTE NumShips, NumDevices;
BYTE ShipList[MAX_BUILT_SHIPS];
BYTE DeviceList[MAX_EXCLUSIVE_DEVICES];
UNICODE SaveName[SAVE_NAME_SIZE];
} SUMMARY_DESC;
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);
extern BOOLEAN SaveGame (COUNT which_game, SUMMARY_DESC *summary_desc, const char *name);
#if defined(__cplusplus)
}
+1 -21
View File
@@ -76,7 +76,7 @@ enum
CANNON_WEAPON,
TRACKING_SYSTEM,
ANTIMISSILE_DEFENSE,
NUM_PURCHASE_MODULES,
BOMB_MODULE_0 = NUM_PURCHASE_MODULES,
@@ -154,26 +154,6 @@ typedef struct
UNICODE PlanetName[SIS_NAME_SIZE];
} SIS_STATE;
// XXX: Theoretically, a player can have 17 devices on board without
// cheating. We only provide
// room for 16 below, which is not really a problem since this
// is only used for displaying savegame summaries. There is also
// room for only 16 devices on screen.
#define MAX_EXCLUSIVE_DEVICES 16
typedef struct
{
SIS_STATE SS;
BYTE Activity;
BYTE Flags;
BYTE day_index, month_index;
COUNT year_index;
BYTE MCreditLo, MCreditHi;
BYTE NumShips, NumDevices;
BYTE ShipList[MAX_BUILT_SHIPS];
BYTE DeviceList[MAX_EXCLUSIVE_DEVICES];
} SUMMARY_DESC;
#define OVERRIDE_LANDER_FLAGS (1 << 7)
#define AFTER_BOMB_INSTALLED (1 << 7)
+1 -1
View File
@@ -22,7 +22,7 @@
#include "starmap.h"
#include "comm.h"
#include "gamestr.h"
#include "load.h"
#include "save.h"
#include "starbase.h"
#include "sis.h"
#include "resinst.h"
+1 -1
View File
@@ -24,10 +24,10 @@
#include "gameev.h"
#include "types.h"
#include "globdata.h"
#include "load.h"
#include "resinst.h"
#include "restart.h"
#include "starbase.h"
#include "save.h"
#include "setup.h"
#include "master.h"
#include "controls.h"