diff --git a/sc2/.gitattributes b/sc2/.gitattributes new file mode 100644 index 000000000..79ab785b5 --- /dev/null +++ b/sc2/.gitattributes @@ -0,0 +1 @@ +content/version export-subst diff --git a/sc2/ChangeLog b/sc2/ChangeLog index eb902e9c6..5198201d5 100644 --- a/sc2/ChangeLog +++ b/sc2/ChangeLog @@ -1,4 +1,6 @@ -0.7.2: +0.8: +- Grouping ship properties together at the top of the ship .c files, from + oldlaptop. - Some added documentation for UIO. - Added a StringHashTable type. - A few superficial fixes to charhashtable. diff --git a/sc2/build/unix/build.config b/sc2/build/unix/build.config index 126b61f34..4b4ef3c51 100644 --- a/sc2/build/unix/build.config +++ b/sc2/build/unix/build.config @@ -313,7 +313,7 @@ uqm_prepare_config() USE_INTERNAL_MIKMOD="" use_library libmikmod } - CHOICE_mikmod_DEFAULT=external + CHOICE_mikmod_DEFAULT=internal CHOICE_joystick_OPTIONS="enabled disabled" CHOICE_joystick_TITLE="Joystick support" diff --git a/sc2/content/base/gamestrings.txt b/sc2/content/base/gamestrings.txt index adc10e55a..fe0a504e3 100644 --- a/sc2/content/base/gamestrings.txt +++ b/sc2/content/base/gamestrings.txt @@ -1831,7 +1831,7 @@ Empty Slot #(Saved Game - Date:) -Saved Game - Date: +Saved Game #(Sound) -- OPTION_STRING_BASE diff --git a/sc2/content/version b/sc2/content/version index 5a41a146b..d75b5b1d8 100644 --- a/sc2/content/version +++ b/sc2/content/version @@ -1,3 +1,3 @@ 0.7.0 -$Date$ +$Format:%ad$ diff --git a/sc2/doc/devel/savefile b/sc2/doc/devel/savefile new file mode 100644 index 000000000..306c1ab10 --- /dev/null +++ b/sc2/doc/devel/savefile @@ -0,0 +1,149 @@ + SAVEFILE FORMAT + --------------- + +This document represents a work in progress. The save format described +here will evolve before finalization for 0.8. + +The old save file format used a custom compressor and was very finicky +about padding and alignment for machines that were not even in use +anymore. It was also extremely fragile and hard for modders to extend. + +The new save format seeks to alleviate these problems. + + GENERAL FORMAT + -------------- + +All multibyte values are little-endian. There are no alignment +restrictions inherent in the format. + +The save file begins with a 32-bit identifier and version number (a +"magic number") that identifies it as a particular version of an UQM +save file. If the format changes in a way that older versions of UQM +cannot read it, either the identifier or the version number should +change. + +The vanilla UQM system has a save number of 0x01534d55, which, if +interpreted as a byte stream is UMS (Ur-quan Masters Save) and a +binary 1 (version 1). Vanilla UQM reserves the tags "UMSx" for all x +for use to evolve the core save format. Modders are encouraged, but +not required, to also use the fourth bit as a version number. + +Following the 32-bit file identifier comes a series of chunks. All +chunks have the same general format: a 32-bit tag, similar to that of +the file as a whole, followed by a 32-bit integer specifying the size +of the chunk, and then that many bytes of data. + +Bytes in a chunk tag should all be in the range 0x20-0x7E -- that is, +they should be printable ASCII characters. Chunks are traditionally +referred to by their tag names. + +Chunks whose tag has a least significant byte in the range 0x41-0x5a, +inclusive---that is to say, whose names start with a capital +letter---are mandatory. If you extend the set of mandatory chunks, you +must increase the version of the file. Tags that do not start with a +capital letter may be ignored by other versions of UQM that otherwise +understand that data version. + +(Why would you want to have ignorable bits of save file? Such chunks +may contain helpful but ancillary information. For instance, at the +time of this writing, there is an outstanding bug that life forms are +un-stunned if you save and load in orbit. One could add a new chunk +that tracks the stunned status of life forms on the planet you're in +orbit around, and just revert to the old behavior if it's not there or +if you're running on a version without that fix. Such an ancillary +data chunk would have a tag like "stun" or "biot".) + +Note also that despite being "mandatory", it is not the case that all +chunks will be present in all save files. Different data is saved out +depending on the situation you saved in. + +Unless otherwise specified, chunks may be stored in any order in the +save file. + + CHUNK INVENTORY + --------------- + +- "Summ": Summary. This chunk must come first. This chunk + carries the flagship configuration information and some overview + information that is displayed on the savegame view screen. It is of + variable length, because the last element of this chunk is the name + of the save as chosen by the user. + +- "GlSt": Global State. This chunk must come second, after + Summ. Represents most of the data in the global state structure in + globdata.h. BattleGroupRef is excised from this; its value is + computed later on. + +- "GmSt": Game State. This chunk must come third, after GlSt. This is + the gigantic bitfield that the GET_GAME_STATE macros modify. It is + variably-sized; excess bytes in this array will be ignored, and if + there are insufficient bytes in the save file, the remaining bits + will be initialized to zero. Modders setting extra event flags may + be able to import a legacy game into a sensible state by choosing + their defaults judiciously. + +- "Evts": Events. An array of values describing scripted future + events. + +- "Enct": Encounters. Details of battle groups that are pursuing you + through HyperSpace. + +- "RacQ": Available Race Queue. Which species are active in the game, + where they are, etc. Corresponds to avail_race_q. + +- "IGpQ": Interplanetary Group Queue. Battlegroup information for + ships in your current star system, if you're in a current star + system. It is currently unclear whether or not this ever needs to + exist, but in keeping with legacy logic, it will appear whenever you + are in a star system but not in the middle of an encounter. + +- "NpcQ": NPC Queue. Battlegroup information for ships you are in the + middle of encountering. This should only appear if your loaded + activity is "IN_ENCOUNTER" and loading the game will trigger the red + alert. + +- "ShpQ": Ship Queue. Battlegroup information for your flagship's + escort fleet. + +- "Star": Star Description. Basic indexing information to indicate + which star system you are in. + +- "Scan": Scanner Masks. This is a semi-structured tree of DWORDs that + represents which planetary resources have been captured or + removed. It is a format roughly similar to the old star info + statefile format (see doc/devel/statefile) but little-endianness is + enforced, making this chunk endian-safe where the old statefile dump + was not. + +- "BtGp": Battle Group. Defines the relevant information for all ships + in a given star system. This includes an "encounter ID" - randomly + generated fleets have an encounter ID of zero, and ones built by the + plot have an 32-bit identifier. Vanilla UQM reserves the first 32 + encounter IDs for itself, and uses 15 of them (random encounter, + Ur-Quan Probe, Shofixti Survivor, Zoq-Fot-Pik Emissary, Unzervalt + Guardian, nine Melnorme Traders, and the final boss). This also + includes the expiration date for random encounters and which system + they are relevant to. Much of this information was originally stored + in randgrp.dat, but it has echoes in defgrp.dat as well. The data + here is a ragged 2D array of a slight extension of the SHIP_FRAGMENT + structure. There is one BtGp chunk per defined group. (Since one of + these is defined at game start, and the random encounter structure + has values that mean 'no encounter present', there should always be + at least two of these chunks in any save.) + +- "Grps": Active Battle Groups. These are IP_GROUP structures to + supplement the SHIP_FRAGMENTs specified in BtGp chunks. They give + more detailed information about the precise location and disposition + of each ship in the system you are either in or most recently left. + + THINGS LEFT TO DO + ----------------- + +The last 448 bits in GmSt probably shouldn't exist. However, we should +not remove them from the source base (and thus the save file) until +after other pending commits have been merged. When this happens, we +can break out those bits into an array of DWORDs instead. The loading +code basically ignores those GmSt bits by overwriting them while +loading later chunks, and GmSt is an expandable array in the first +place, so removing those final bits from the Game State array should +be compatible in both directions. 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/comm.c b/sc2/src/uqm/comm.c index 55c07df11..6336de8a9 100644 --- a/sc2/src/uqm/comm.c +++ b/sc2/src/uqm/comm.c @@ -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" diff --git a/sc2/src/uqm/gameopt.c b/sc2/src/uqm/gameopt.c index 726f0b2ce..b604dd538 100644 --- a/sc2/src/uqm/gameopt.c +++ b/sc2/src/uqm/gameopt.c @@ -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)); } - diff --git a/sc2/src/uqm/globdata.c b/sc2/src/uqm/globdata.c index 20e39a470..ff9edc2fb 100644 --- a/sc2/src/uqm/globdata.c +++ b/sc2/src/uqm/globdata.c @@ -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) { diff --git a/sc2/src/uqm/globdata.h b/sc2/src/uqm/globdata.h index acd5b53ee..216cadf11 100644 --- a/sc2/src/uqm/globdata.h +++ b/sc2/src/uqm/globdata.h @@ -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 diff --git a/sc2/src/uqm/grpinfo.c b/sc2/src/uqm/grpinfo.c index dc7be0f4c..43f1b22b6 100644 --- a/sc2/src/uqm/grpinfo.c +++ b/sc2/src/uqm/grpinfo.c @@ -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 */ diff --git a/sc2/src/uqm/grpintrn.h b/sc2/src/uqm/grpintrn.h new file mode 100644 index 000000000..d2136a507 --- /dev/null +++ b/sc2/src/uqm/grpintrn.h @@ -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 diff --git a/sc2/src/uqm/load.c b/sc2/src/uqm/load.c index 98924f173..9d434c4b2 100644 --- a/sc2/src/uqm/load.c +++ b/sc2/src/uqm/load.c @@ -18,19 +18,16 @@ #include -#include "load.h" - #include "build.h" -#include "libs/declib.h" #include "encount.h" #include "starmap.h" #include "libs/file.h" #include "globdata.h" -#include "load.h" #include "options.h" +#include "save.h" #include "setup.h" #include "state.h" -#include "grpinfo.h" +#include "grpintrn.h" #include "libs/tasklib.h" #include "libs/log.h" @@ -40,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) { @@ -120,39 +49,51 @@ read_8 (void *fp, BYTE *v) 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); + UWORD t = 0; + int shift, i; + for (i = 0, shift = 0; i < 2; ++i, shift += 8) + { + BYTE b; + if (read_8 (fp, &b) != 1) + return 0; + t |= ((UWORD)b) << shift; + } + + if (v) + *v = t; + + return 1; +} + +static inline size_t +read_16s (void *fp, SWORD *v) +{ + return read_16 (fp, v); } 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); + DWORD t = 0; + int shift, i; + for (i = 0, shift = 0; i < 4; ++i, shift += 8) + { + BYTE b; + if (read_8 (fp, &b) != 1) + return 0; + t |= ((DWORD)b) << shift; + } + + if (v) + *v = t; + + return 1; } 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 */ + return read_32 (fp, v); } static inline size_t @@ -162,6 +103,18 @@ read_a8 (void *fp, BYTE *ar, COUNT count) return ReadResFile (ar, 1, count, fp) == count; } +static inline size_t +skip_8 (void *fp, COUNT count) +{ + int i; + for (i = 0; i < count; ++i) + { + if (read_8(fp, NULL) != 1) + return 0; + } + return 1; +} + static inline size_t read_str (void *fp, char *str, COUNT count) { @@ -183,300 +136,221 @@ read_a16 (void *fp, UWORD *ar, COUNT count) } static void -LoadEmptyQueue (DECODE_REF fh) +LoadShipQueue (void *fh, QUEUE *pQueue, DWORD size) { - 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); + COUNT num_links = size / 11; while (num_links--) { HSHIPFRAG hStarShip; SHIP_FRAGMENT *FragPtr; 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); - // 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 */ + read_8 (fh, &FragPtr->captains_name_index); + read_8 (fh, &FragPtr->race_id); + read_8 (fh, &FragPtr->index); + read_16 (fh, &FragPtr->crew_level); + read_16 (fh, &FragPtr->max_crew); + read_8 (fh, &FragPtr->energy_level); + read_8 (fh, &FragPtr->max_energy); UnlockShipFrag (pQueue, hStarShip); } } static void -LoadRaceQueue (DECODE_REF fh, QUEUE *pQueue) +LoadRaceQueue (void *fh, QUEUE *pQueue, DWORD size) { - COUNT num_links; - - cread_16 (fh, &num_links); + COUNT num_links = size / 30; while (num_links--) { HFLEETINFO hStarShip; FLEET_INFO *FleetPtr; 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); - 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); + read_16 (fh, &FleetPtr->allied_state); + read_8 (fh, &FleetPtr->days_left); + read_8 (fh, &FleetPtr->growth_fract); + read_16 (fh, &FleetPtr->crew_level); + read_16 (fh, &FleetPtr->max_crew); + 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); UnlockFleetInfo (pQueue, hStarShip); } } static void -LoadGroupQueue (DECODE_REF fh, QUEUE *pQueue) +LoadGroupQueue (void *fh, QUEUE *pQueue, DWORD size) { - COUNT num_links; - - cread_16 (fh, &num_links); + COUNT num_links = size / 13; 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); + read_16 (fh, &GroupPtr->group_counter); + read_8 (fh, &GroupPtr->race_id); + read_8 (fh, &GroupPtr->sys_loc); + read_8 (fh, &GroupPtr->task); + read_8 (fh, &GroupPtr->in_system); /* was crew_level */ + read_8 (fh, &GroupPtr->dest_loc); + read_8 (fh, &GroupPtr->orbit_pos); + 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 */ 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); + 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); - EncounterPtr->num_ships = tmpb & ENCOUNTER_SHIPS_MASK; - EncounterPtr->flags = tmpb & ENCOUNTER_FLAGS_MASK; - cread_16 (fh, NULL); /* alignment padding */ + read_16s (fh, &EncounterPtr->loc_pt.x); + read_16s (fh, &EncounterPtr->loc_pt.y); + read_8 (fh, &EncounterPtr->race_id); + read_8 (fh, &EncounterPtr->num_ships); + read_8 (fh, &EncounterPtr->flags); // 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 */ + read_8 (fh, &ShipInfo->race_id); + read_16 (fh, &ShipInfo->crew_level); + read_16 (fh, &ShipInfo->max_crew); + read_8 (fh, &ShipInfo->max_energy); } - + // 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 */ 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 */ + read_8 (fh, &EventPtr->day_index); + read_8 (fh, &EventPtr->month_index); + read_16 (fh, &EventPtr->year_index); + read_8 (fh, &EventPtr->func_index); } static void -DummyLoadQueue (QUEUE *QueuePtr, DECODE_REF fh) +LoadClockState (CLOCK_STATE *ClockPtr, void *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 */ + 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); } -static void -LoadClockState (CLOCK_STATE *ClockPtr, DECODE_REF fh) +static BOOLEAN +LoadGameState (GAME_STATE *GSPtr, 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 */ + DWORD magic; + read_32 (fh, &magic); + if (magic != GLOBAL_STATE_TAG) + { + return FALSE; + } + read_32 (fh, &magic); + if (magic != 75) + { + /* Chunk is the wrong size. */ + return FALSE; + } + 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_16 (fh, &GSPtr->CurrentActivity); - 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); + 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); - 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 */ + read_32 (fh, &magic); + if (magic != GAME_STATE_TAG) + { + return FALSE; + } + memset (GSPtr->GameState, 0, sizeof (GSPtr->GameState)); + read_32 (fh, &magic); + if (magic > sizeof (GSPtr->GameState)) + { + read_a8 (fh, GSPtr->GameState, sizeof (GSPtr->GameState)); + skip_8 (fh, magic - sizeof (GSPtr->GameState)); + } + else + { + read_a8 (fh, GSPtr->GameState, magic); + } + return TRUE; } static BOOLEAN @@ -498,23 +372,36 @@ LoadSisState (SIS_STATE *SSPtr, void *fp) 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 */ + read_str (fp, SSPtr->PlanetName, SIS_NAME_SIZE) != 1 ) return FALSE; - else - return TRUE; + return TRUE; } static BOOLEAN LoadSummary (SUMMARY_DESC *SummPtr, void *fp) { + SDWORD magic; + DWORD nameSize = 0; + if (!read_32s (fp, &magic)) + return FALSE; + if (magic == SAVEFILE_TAG) + { + if (read_32 (fp, &magic) != 1 || magic != SUMMARY_TAG) + return FALSE; + if (read_32 (fp, &magic) != 1 || magic < 160) + return FALSE; + nameSize = magic - 160; + } + else + { + return FALSE; + } + 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 || @@ -524,24 +411,191 @@ LoadSummary (SUMMARY_DESC *SummPtr, void *fp) 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 */ + read_a8 (fp, SummPtr->DeviceList, MAX_EXCLUSIVE_DEVICES) != 1 ) return FALSE; + + if (nameSize < SAVE_NAME_SIZE) + { + if (read_a8 (fp, SummPtr->SaveName, nameSize) != 1) + return FALSE; + SummPtr->SaveName[nameSize] = 0; + } else - return TRUE; + { + 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); +} + +static void +LoadScanInfo (uio_Stream *fh, DWORD flen) +{ + GAME_STATE_FILE *fp = OpenStateFile (STARINFO_FILE, "wb"); + if (fp) + { + while (flen) + { + DWORD val; + read_32 (fh, &val); + swrite_32 (fp, val); + flen -= 4; + } + CloseStateFile (fp); + } +} + +static void +LoadGroupList (uio_Stream *fh, DWORD chunksize) +{ + GAME_STATE_FILE *fp = OpenStateFile (RANDGRPINFO_FILE, "rb"); + if (fp) + { + GROUP_HEADER h; + BYTE LastEnc, NumGroups; + int i; + ReadGroupHeader (fp, &h); + /* There's only supposed to be one of these, so group 0 should be + * zero here whenever we're here. We add the group list to the + * end here. */ + h.GroupOffset[0] = LengthStateFile (fp); + SeekStateFile (fp, 0, SEEK_SET); + WriteGroupHeader (fp, &h); + SeekStateFile (fp, h.GroupOffset[0], SEEK_SET); + read_8 (fh, &LastEnc); + NumGroups = (chunksize - 1) / 14; + swrite_8 (fp, LastEnc); + swrite_8 (fp, NumGroups); + for (i = 0; i < NumGroups; ++i) + { + BYTE race_outer; + IP_GROUP ip; + read_8 (fh, &race_outer); + read_16 (fh, &ip.group_counter); + read_8 (fh, &ip.race_id); + read_8 (fh, &ip.sys_loc); + read_8 (fh, &ip.task); + read_8 (fh, &ip.in_system); + read_8 (fh, &ip.dest_loc); + read_8 (fh, &ip.orbit_pos); + read_8 (fh, &ip.group_id); + read_16 (fh, &ip.loc.x); + read_16 (fh, &ip.loc.y); + + swrite_8 (fp, race_outer); + WriteIpGroup (fp, &ip); + } + CloseStateFile (fp); + } +} + +static void +LoadBattleGroup (uio_Stream *fh, DWORD chunksize) +{ + GAME_STATE_FILE *fp; + GROUP_HEADER h; + DWORD encounter, offset; + BYTE current; + int i; + + read_32 (fh, &encounter); + read_8 (fh, ¤t); + chunksize -= 5; + if (encounter) + { + /* This is a defined group, so it's new */ + fp = OpenStateFile (DEFGRPINFO_FILE, "rb"); + offset = LengthStateFile (fp); + memset (&h, 0, sizeof (GROUP_HEADER)); + } + else + { + /* This is the random group. Load in what was there, + * as we might have already seen the Group List. */ + fp = OpenStateFile (RANDGRPINFO_FILE, "rb"); + current = FALSE; + offset = 0; + ReadGroupHeader (fp, &h); + } + if (!fp) + { + skip_8 (fh, chunksize); + return; + } + read_16 (fh, &h.star_index); + read_8 (fh, &h.day_index); + read_8 (fh, &h.month_index); + read_16 (fh, &h.year_index); + read_8 (fh, &h.NumGroups); + chunksize -= 7; + /* Write out the half-finished state file so that we can use + * the file size to compute group offsets */ + SeekStateFile (fp, offset, SEEK_SET); + WriteGroupHeader (fp, &h); + for (i = 1; i <= h.NumGroups; ++i) + { + int j; + BYTE icon, NumShips; + read_8 (fh, &icon); + read_8 (fh, &NumShips); + chunksize -= 2; + h.GroupOffset[i] = LengthStateFile (fp); + SeekStateFile (fp, h.GroupOffset[i], SEEK_SET); + swrite_8 (fp, icon); + swrite_8 (fp, NumShips); + for (j = 0; j < NumShips; ++j) + { + BYTE race_outer; + SHIP_FRAGMENT sf; + read_8 (fh, &race_outer); + read_8 (fh, &sf.captains_name_index); + read_8 (fh, &sf.race_id); + read_8 (fh, &sf.index); + read_16 (fh, &sf.crew_level); + read_16 (fh, &sf.max_crew); + read_8 (fh, &sf.energy_level); + read_8 (fh, &sf.max_energy); + chunksize -= 10; + + swrite_8 (fp, race_outer); + WriteShipFragment (fp, &sf); + } + } + /* Now that the GroupOffset array is properly initialized, + * write the header back out. */ + SeekStateFile (fp, offset, SEEK_SET); + WriteGroupHeader (fp, &h); + CloseStateFile (fp); + /* And update the gamestate accordingly, if we're a defined group. */ + if (encounter) + { + SET_GAME_STATE_32 (SHOFIXTI_GRPOFFS0 + (encounter - 1) * 32, offset); + if (current) + { + GLOBAL (BattleGroupRef) = offset; + } + } + /* Consistency check. */ + if (chunksize) + { + log_add (log_Warning, "BattleGroup chunk mis-sized!"); + } } BOOLEAN @@ -549,24 +603,22 @@ LoadGame (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; + DWORD chunk, chunkSize; + BOOLEAN first_group_spec = TRUE; - 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)) { - log_add (log_Error, "Warning: Savegame is corrupt"); res_CloseResFile (in_fp); - return FALSE; + return LoadLegacyGame (which_game, SummPtr); } if (!SummPtr) @@ -580,29 +632,8 @@ 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 ((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)); @@ -611,141 +642,116 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) memset (&GLOBAL (GameState[0]), 0, sizeof (GLOBAL (GameState))); Activity = GLOBAL (CurrentActivity); - LoadGameState (&GlobData.Game_state, fh); + if (!LoadGameState (&GlobData.Game_state, in_fp)) + { + res_CloseResFile (in_fp); + return FALSE; + } 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)) + chunk = 0; + while (TRUE) { - 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--) + if (read_32(in_fp, &chunk) != 1) { - HEVENT hEvent; - EVENT *EventPtr; + break; + } + if (read_32(in_fp, &chunkSize) != 1) + { + res_CloseResFile (in_fp); + return FALSE; + } + switch (chunk) + { + case RACE_Q_TAG: + LoadRaceQueue (in_fp, &GLOBAL (avail_race_q), chunkSize); + break; + case IP_GRP_Q_TAG: + LoadGroupQueue (in_fp, &GLOBAL (ip_group_q), chunkSize); + break; + case ENCOUNTERS_TAG: + num_links = chunkSize / 65; + while (num_links--) + { + HENCOUNTER hEncounter; + ENCOUNTER *EncounterPtr; - hEvent = AllocEvent (); - LockEvent (hEvent, &EventPtr); + hEncounter = AllocEncounter (); + LockEncounter (hEncounter, &EncounterPtr); - LoadEvent (EventPtr, fh); + LoadEncounter (EncounterPtr, in_fp); + + UnlockEncounter (hEncounter); + PutEncounter (hEncounter); + } + break; + case EVENTS_TAG: + num_links = chunkSize / 5; +#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, in_fp); #ifdef DEBUG_LOAD - log_add (log_Debug, "\t%u/%u/%u -- %u", - EventPtr->month_index, - EventPtr->day_index, - EventPtr->year_index, - EventPtr->func_index); + 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); + UnlockEvent (hEvent); + PutEvent (hEvent); + } + break; + case STAR_TAG: + LoadStarDesc (&SD, in_fp); + break; + case NPC_SHIP_Q_TAG: + LoadShipQueue (in_fp, &GLOBAL (npc_built_ship_q), chunkSize); + break; + case SHIP_Q_TAG: + LoadShipQueue (in_fp, &GLOBAL (built_ship_q), chunkSize); + break; + case SCAN_TAG: + LoadScanInfo (in_fp, chunkSize); + break; + case GROUP_LIST_TAG: + if (first_group_spec) + { + InitGroupInfo (TRUE); + GLOBAL (BattleGroupRef) = 0; + first_group_spec = FALSE; + } + LoadGroupList (in_fp, chunkSize); + break; + case BATTLE_GROUP_TAG: + if (first_group_spec) + { + InitGroupInfo (TRUE); + GLOBAL (BattleGroupRef) = 0; + first_group_spec = FALSE; + } + LoadBattleGroup (in_fp, chunkSize); + break; + default: + log_add (log_Debug, "Skipping chunk of tag %08X (size %u)", chunk, chunkSize); + if (skip_8(in_fp, chunkSize) != 1) + { + res_CloseResFile (in_fp); + return FALSE; + } + break; } } - - // 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; @@ -760,5 +766,3 @@ LoadGame (COUNT which_game, SUMMARY_DESC *SummPtr) return TRUE; } - - diff --git a/sc2/src/uqm/load.h b/sc2/src/uqm/load.h deleted file mode 100644 index 6f2cce0f5..000000000 --- a/sc2/src/uqm/load.h +++ /dev/null @@ -1,38 +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 UQM_LOAD_H_ -#define UQM_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 /* UQM_LOAD_H_ */ diff --git a/sc2/src/uqm/load_legacy.c b/sc2/src/uqm/load_legacy.c new file mode 100644 index 000000000..6470a52f1 --- /dev/null +++ b/sc2/src/uqm/load_legacy.c @@ -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 + +#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; +} + + diff --git a/sc2/src/uqm/planets/devices.c b/sc2/src/uqm/planets/devices.c index 99b0ac379..e781d5b1c 100644 --- a/sc2/src/uqm/planets/devices.c +++ b/sc2/src/uqm/planets/devices.c @@ -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" diff --git a/sc2/src/uqm/planets/scan.c b/sc2/src/uqm/planets/scan.c index ed063337b..3d5d9fd7b 100644 --- a/sc2/src/uqm/planets/scan.c +++ b/sc2/src/uqm/planets/scan.c @@ -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" diff --git a/sc2/src/uqm/planets/solarsys.c b/sc2/src/uqm/planets/solarsys.c index 677b9dfdb..11bd4c0bf 100644 --- a/sc2/src/uqm/planets/solarsys.c +++ b/sc2/src/uqm/planets/solarsys.c @@ -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" diff --git a/sc2/src/uqm/restart.c b/sc2/src/uqm/restart.c index b877a2edb..f52e753b4 100644 --- a/sc2/src/uqm/restart.c +++ b/sc2/src/uqm/restart.c @@ -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" diff --git a/sc2/src/uqm/save.c b/sc2/src/uqm/save.c index c49fe505e..102b0309a 100644 --- a/sc2/src/uqm/save.c +++ b/sc2/src/uqm/save.c @@ -32,7 +32,7 @@ #include "shipcont.h" #include "setup.h" #include "state.h" -#include "grpinfo.h" +#include "grpintrn.h" #include "util.h" #include "hyper.h" // for SaveSisHyperState() @@ -41,106 +41,79 @@ #include "libs/inplib.h" #include "libs/log.h" #include "libs/memlib.h" -#include "libs/declib.h" +// Status boolean. If for some insane reason you need to +// save games in different threads, you'll need to +// protect your calls to SaveGame with a mutex. + +// It's arguably over-paranoid to check for error on +// every single write, but this preserves the older +// behavior. + +static BOOLEAN io_ok = TRUE; // XXX: these should handle endian conversions later -static inline COUNT -cwrite_8 (DECODE_REF fh, BYTE v) -{ - return cwrite (&v, 1, 1, fh); -} - -static inline COUNT -cwrite_16 (DECODE_REF fh, UWORD v) -{ - return cwrite (&v, 2, 1, fh); -} - -static inline COUNT -cwrite_32 (DECODE_REF fh, DWORD v) -{ - return cwrite (&v, 4, 1, fh); -} - -static inline COUNT -cwrite_ptr (DECODE_REF fh) -{ - return cwrite_32 (fh, 0); /* ptrs are useless in saves */ -} - -static inline COUNT -cwrite_a8 (DECODE_REF fh, const BYTE *ar, COUNT count) -{ - return cwrite (ar, 1, count, fh) == count; -} - -static inline size_t +static inline void write_8 (void *fp, BYTE v) { - return WriteResFile (&v, 1, 1, fp); + if (io_ok) + if (WriteResFile (&v, 1, 1, fp) != 1) + io_ok = FALSE; } -static inline size_t +static inline void write_16 (void *fp, UWORD v) { - return WriteResFile (&v, 2, 1, fp); + write_8 (fp, (BYTE)( v & 0xff)); + write_8 (fp, (BYTE)((v >> 8) & 0xff)); } -static inline size_t +static inline void write_32 (void *fp, DWORD v) { - return WriteResFile (&v, 4, 1, fp); + write_8 (fp, (BYTE)( v & 0xff)); + write_8 (fp, (BYTE)((v >> 8) & 0xff)); + write_8 (fp, (BYTE)((v >> 16) & 0xff)); + write_8 (fp, (BYTE)((v >> 24) & 0xff)); } -static inline size_t -write_ptr (void *fp) -{ - return write_32 (fp, 0); /* ptrs are useless in saves */ -} - -static inline size_t +static inline void write_a8 (void *fp, const BYTE *ar, COUNT count) { - return WriteResFile (ar, 1, count, fp) == count; + if (io_ok) + if (WriteResFile (ar, 1, count, fp) != count) + io_ok = FALSE; } -static inline size_t +static inline void write_str (void *fp, const char *str, COUNT count) { // no type conversion needed for strings - return write_a8 (fp, (const BYTE *)str, count); + write_a8 (fp, (const BYTE *)str, count); } -static inline size_t +static inline void write_a16 (void *fp, const UWORD *ar, COUNT count) { for ( ; count > 0; --count, ++ar) { - if (write_16 (fp, *ar) != 1) - return 0; + if (!io_ok) + break; + write_16 (fp, *ar); } - return 1; } static void -SaveEmptyQueue (DECODE_REF fh) -{ - COUNT num_links = 0; - - // Write the number of entries in the queue. - cwrite_16 (fh, num_links); -} - -static void -SaveShipQueue (DECODE_REF fh, QUEUE *pQueue) +SaveShipQueue (uio_Stream *fh, QUEUE *pQueue, DWORD tag) { COUNT num_links; HSHIPFRAG hStarShip; - // Write the number of entries in the queue. num_links = CountLinks (pQueue); - cwrite_16 (fh, num_links); + if (num_links == 0) + return; + write_32 (fh, tag); + write_32 (fh, num_links * 11); // Size of chunk: each entry is 11 bytes long. hStarShip = GetHeadLink (pQueue); while (num_links--) @@ -155,22 +128,16 @@ SaveShipQueue (DECODE_REF fh, QUEUE *pQueue) Index = FragPtr->race_id; // Write the number identifying this ship type. // See races.h; look for the enum containing NUM_AVAILABLE_RACES. - cwrite_16 (fh, Index); + write_16 (fh, Index); // Write SHIP_FRAGMENT elements - cwrite_16 (fh, 0); /* unused; was which_side */ - cwrite_8 (fh, FragPtr->captains_name_index); - cwrite_8 (fh, 0); /* padding */ - cwrite_16 (fh, 0); /* unused: was ship_flags */ - cwrite_8 (fh, FragPtr->race_id); - cwrite_8 (fh, FragPtr->index); - // XXX: writing crew as BYTE to maintain savegame compatibility - cwrite_8 (fh, FragPtr->crew_level); - cwrite_8 (fh, FragPtr->max_crew); - cwrite_8 (fh, FragPtr->energy_level); - cwrite_8 (fh, FragPtr->max_energy); - cwrite_16 (fh, 0); /* unused; was loc.x */ - cwrite_16 (fh, 0); /* unused; was loc.y */ + write_8 (fh, FragPtr->captains_name_index); + write_8 (fh, FragPtr->race_id); + write_8 (fh, FragPtr->index); + write_16 (fh, FragPtr->crew_level); + write_16 (fh, FragPtr->max_crew); + write_8 (fh, FragPtr->energy_level); + write_8 (fh, FragPtr->max_energy); UnlockShipFrag (pQueue, hStarShip); hStarShip = hNextShip; @@ -178,14 +145,17 @@ SaveShipQueue (DECODE_REF fh, QUEUE *pQueue) } static void -SaveRaceQueue (DECODE_REF fh, QUEUE *pQueue) +SaveRaceQueue (uio_Stream *fh, QUEUE *pQueue) { COUNT num_links; HFLEETINFO hFleet; - // Write the number of entries in the queue. num_links = CountLinks (pQueue); - cwrite_16 (fh, num_links); + if (num_links == 0) + return; + write_32 (fh, RACE_Q_TAG); + // Write chunk size: 30 bytes per entry + write_32 (fh, num_links * 30); hFleet = GetHeadLink (pQueue); while (num_links--) @@ -199,28 +169,27 @@ SaveRaceQueue (DECODE_REF fh, QUEUE *pQueue) Index = GetIndexFromStarShip (pQueue, hFleet); // The index is the position in the queue. - cwrite_16 (fh, Index); + write_16 (fh, Index); // Write FLEET_INFO elements - cwrite_16 (fh, FleetPtr->allied_state); - cwrite_8 (fh, FleetPtr->days_left); - cwrite_8 (fh, FleetPtr->growth_fract); - cwrite_8 (fh, FleetPtr->crew_level); - cwrite_8 (fh, FleetPtr->max_crew); - cwrite_8 (fh, FleetPtr->growth); - cwrite_8 (fh, FleetPtr->max_energy); - cwrite_16 (fh, FleetPtr->loc.x); - cwrite_16 (fh, FleetPtr->loc.y); + write_16 (fh, FleetPtr->allied_state); + write_8 (fh, FleetPtr->days_left); + write_8 (fh, FleetPtr->growth_fract); + write_16 (fh, FleetPtr->crew_level); + write_16 (fh, FleetPtr->max_crew); + write_8 (fh, FleetPtr->growth); + write_8 (fh, FleetPtr->max_energy); + write_16 (fh, FleetPtr->loc.x); + write_16 (fh, FleetPtr->loc.y); - cwrite_16 (fh, FleetPtr->actual_strength); - cwrite_16 (fh, FleetPtr->known_strength); - cwrite_16 (fh, FleetPtr->known_loc.x); - cwrite_16 (fh, FleetPtr->known_loc.y); - cwrite_8 (fh, FleetPtr->growth_err_term); - cwrite_8 (fh, FleetPtr->func_index); - cwrite_16 (fh, FleetPtr->dest_loc.x); - cwrite_16 (fh, FleetPtr->dest_loc.y); - cwrite_16 (fh, 0); /* alignment padding */ + write_16 (fh, FleetPtr->actual_strength); + write_16 (fh, FleetPtr->known_strength); + write_16 (fh, FleetPtr->known_loc.x); + write_16 (fh, FleetPtr->known_loc.y); + write_8 (fh, FleetPtr->growth_err_term); + write_8 (fh, FleetPtr->func_index); + write_16 (fh, FleetPtr->dest_loc.x); + write_16 (fh, FleetPtr->dest_loc.y); UnlockFleetInfo (pQueue, hFleet); hFleet = hNextFleet; @@ -228,12 +197,16 @@ SaveRaceQueue (DECODE_REF fh, QUEUE *pQueue) } static void -SaveGroupQueue (DECODE_REF fh, QUEUE *pQueue) +SaveGroupQueue (uio_Stream *fh, QUEUE *pQueue) { HIPGROUP hGroup, hNextGroup; + COUNT num_links; - // Write the number of entries in the queue. - cwrite_16 (fh, CountLinks (pQueue)); + num_links = CountLinks (pQueue); + if (num_links == 0) + return; + write_32 (fh, IP_GRP_Q_TAG); + write_32 (fh, num_links * 13); // 13 bytes per element right now for (hGroup = GetHeadLink (pQueue); hGroup; hGroup = hNextGroup) { @@ -242,243 +215,224 @@ SaveGroupQueue (DECODE_REF fh, QUEUE *pQueue) GroupPtr = LockIpGroup (pQueue, hGroup); hNextGroup = _GetSuccLink (GroupPtr); - cwrite_16 (fh, GroupPtr->race_id); /* unused; for old versions */ - - cwrite_16 (fh, 0); /* unused; was which_side */ - cwrite_8 (fh, 0); /* unused; was captains_name_index */ - cwrite_8 (fh, 0); /* padding; for savegame compat */ - cwrite_16 (fh, GroupPtr->group_counter); - cwrite_8 (fh, GroupPtr->race_id); - assert (GroupPtr->sys_loc < 0x10 && GroupPtr->task < 0x10); - cwrite_8 (fh, MAKE_BYTE (GroupPtr->sys_loc, GroupPtr->task)); - /* was var2 */ - cwrite_8 (fh, GroupPtr->in_system); /* was crew_level */ - cwrite_8 (fh, 0); /* unused; was max_crew */ - assert (GroupPtr->dest_loc < 0x10 && GroupPtr->orbit_pos < 0x10); - cwrite_8 (fh, MAKE_BYTE (GroupPtr->dest_loc, GroupPtr->orbit_pos)); - /* was energy_level */ - cwrite_8 (fh, GroupPtr->group_id); /* was max_energy */ - cwrite_16 (fh, GroupPtr->loc.x); - cwrite_16 (fh, GroupPtr->loc.y); + write_16 (fh, GroupPtr->group_counter); + write_8 (fh, GroupPtr->race_id); + write_8 (fh, GroupPtr->sys_loc); + write_8 (fh, GroupPtr->task); + write_8 (fh, GroupPtr->in_system); /* was crew_level */ + write_8 (fh, GroupPtr->dest_loc); + write_8 (fh, GroupPtr->orbit_pos); + write_8 (fh, GroupPtr->group_id); /* was max_energy */ + write_16 (fh, GroupPtr->loc.x); + write_16 (fh, GroupPtr->loc.y); UnlockIpGroup (pQueue, hGroup); } } static void -SaveEncounter (const ENCOUNTER *EncounterPtr, DECODE_REF fh) +SaveEncounters (uio_Stream *fh) { - COUNT i; + COUNT num_links; + HENCOUNTER hEncounter; + num_links = CountLinks (&GLOBAL (encounter_q)); + if (num_links == 0) + return; + write_32 (fh, ENCOUNTERS_TAG); + write_32 (fh, 65 * num_links); - cwrite_ptr (fh); /* useless ptr; HENCOUNTER pred */ - cwrite_ptr (fh); /* useless ptr; HENCOUNTER succ */ - cwrite_ptr (fh); /* useless ptr; HELEMENT hElement */ - cwrite_16 (fh, EncounterPtr->transition_state); - cwrite_16 (fh, EncounterPtr->origin.x); - cwrite_16 (fh, EncounterPtr->origin.y); - cwrite_16 (fh, EncounterPtr->radius); - // former STAR_DESC fields - cwrite_16 (fh, EncounterPtr->loc_pt.x); - cwrite_16 (fh, EncounterPtr->loc_pt.y); - cwrite_8 (fh, EncounterPtr->race_id); - // XXX: writing combined fields to maintain savegame compatibility - cwrite_8 (fh, (EncounterPtr->num_ships & ENCOUNTER_SHIPS_MASK) - | (EncounterPtr->flags & ENCOUNTER_FLAGS_MASK)); - cwrite_16 (fh, 0); /* alignment padding */ - - // Save each entry in the BRIEF_SHIP_INFO array - for (i = 0; i < MAX_HYPER_SHIPS; i++) + hEncounter = GetHeadLink (&GLOBAL (encounter_q)); + while (num_links--) { - const BRIEF_SHIP_INFO *ShipInfo = &EncounterPtr->ShipList[i]; + HENCOUNTER hNextEncounter; + ENCOUNTER *EncounterPtr; + COUNT i; - cwrite_16 (fh, 0); /* useless; was SHIP_INFO.ship_flags */ - cwrite_8 (fh, ShipInfo->race_id); - cwrite_8 (fh, 0); /* useless; was SHIP_INFO.var2 */ - // XXX: writing crew as BYTE to maintain savegame compatibility - cwrite_8 (fh, ShipInfo->crew_level); - cwrite_8 (fh, ShipInfo->max_crew); - cwrite_8 (fh, 0); /* useless; was SHIP_INFO.energy_level */ - cwrite_8 (fh, ShipInfo->max_energy); - cwrite_16 (fh, 0); /* useless; was SHIP_INFO.loc.x */ - cwrite_16 (fh, 0); /* useless; was SHIP_INFO.loc.y */ - cwrite_32 (fh, 0); /* useless val; STRING race_strings */ - cwrite_ptr (fh); /* useless ptr; FRAME icons */ - cwrite_ptr (fh); /* useless ptr; FRAME melee_icon */ + LockEncounter (hEncounter, &EncounterPtr); + hNextEncounter = GetSuccEncounter (EncounterPtr); + + write_16 (fh, EncounterPtr->transition_state); + write_16 (fh, EncounterPtr->origin.x); + write_16 (fh, EncounterPtr->origin.y); + write_16 (fh, EncounterPtr->radius); + // former STAR_DESC fields + write_16 (fh, EncounterPtr->loc_pt.x); + write_16 (fh, EncounterPtr->loc_pt.y); + write_8 (fh, EncounterPtr->race_id); + write_8 (fh, EncounterPtr->num_ships); + write_8 (fh, EncounterPtr->flags); + + // Save each entry in the BRIEF_SHIP_INFO array + for (i = 0; i < MAX_HYPER_SHIPS; i++) + { + const BRIEF_SHIP_INFO *ShipInfo = &EncounterPtr->ShipList[i]; + + write_8 (fh, ShipInfo->race_id); + write_16 (fh, ShipInfo->crew_level); + write_16 (fh, ShipInfo->max_crew); + write_8 (fh, ShipInfo->max_energy); + } + + // Save the stuff after the BRIEF_SHIP_INFO array + write_32 (fh, EncounterPtr->log_x); + write_32 (fh, EncounterPtr->log_y); + + UnlockEncounter (hEncounter); + hEncounter = hNextEncounter; } - - // Save the stuff after the BRIEF_SHIP_INFO array - cwrite_32 (fh, EncounterPtr->log_x); - cwrite_32 (fh, EncounterPtr->log_y); } static void -SaveEvent (const EVENT *EventPtr, DECODE_REF fh) +SaveEvents (uio_Stream *fh) { - cwrite_ptr (fh); /* useless ptr; HEVENT pred */ - cwrite_ptr (fh); /* useless ptr; HEVENT succ */ - cwrite_8 (fh, EventPtr->day_index); - cwrite_8 (fh, EventPtr->month_index); - cwrite_16 (fh, EventPtr->year_index); - cwrite_8 (fh, EventPtr->func_index); - cwrite_8 (fh, 0); /* padding */ - cwrite_16 (fh, 0); /* padding */ + COUNT num_links; + HEVENT hEvent; + num_links = CountLinks (&GLOBAL (GameClock.event_q)); + if (num_links == 0) + return; + write_32 (fh, EVENTS_TAG); + write_32 (fh, num_links * 5); /* Event chunks are five bytes each */ + + hEvent = GetHeadLink (&GLOBAL (GameClock.event_q)); + while (num_links--) + { + HEVENT hNextEvent; + EVENT *EventPtr; + + LockEvent (hEvent, &EventPtr); + hNextEvent = GetSuccEvent (EventPtr); + + write_8 (fh, EventPtr->day_index); + write_8 (fh, EventPtr->month_index); + write_16 (fh, EventPtr->year_index); + write_8 (fh, EventPtr->func_index); + + UnlockEvent (hEvent); + hEvent = hNextEvent; + } } +/* The clock state is folded in with the game state chunk. */ static void -DummySaveQueue (const QUEUE *QueuePtr, DECODE_REF fh) +SaveClockState (const CLOCK_STATE *ClockPtr, uio_Stream *fh) { - /* QUEUE should never actually be saved since it contains - * purely internal representation and the lists - * involved are actually saved separately */ - (void)QueuePtr; /* silence compiler */ - - /* QUEUE format with QUEUE_TABLE defined -- UQM default */ - cwrite_ptr (fh); /* HLINK head */ - cwrite_ptr (fh); /* HLINK tail */ - cwrite_ptr (fh); /* BYTE* pq_tab */ - cwrite_ptr (fh); /* HLINK free_list */ - cwrite_16 (fh, 0); /* MEM_HANDLE hq_tab */ - cwrite_16 (fh, 0); /* COUNT object_size */ - cwrite_8 (fh, 0); /* BYTE num_objects */ - - cwrite_8 (fh, 0); /* padding */ - cwrite_16 (fh, 0); /* padding */ + write_8 (fh, ClockPtr->day_index); + write_8 (fh, ClockPtr->month_index); + write_16 (fh, ClockPtr->year_index); + write_16 (fh, ClockPtr->tick_count); + write_16 (fh, ClockPtr->day_in_ticks); } +/* Save out the game state chunks. There are two of these; the Global + * State chunk is fixed size, but the Game State tag can be extended + * by modders. */ static void -SaveClockState (const CLOCK_STATE *ClockPtr, DECODE_REF fh) +SaveGameState (const GAME_STATE *GSPtr, uio_Stream *fh) { - cwrite_8 (fh, ClockPtr->day_index); - cwrite_8 (fh, ClockPtr->month_index); - cwrite_16 (fh, ClockPtr->year_index); - cwrite_16 (fh, ClockPtr->tick_count); - cwrite_16 (fh, ClockPtr->day_in_ticks); - cwrite_ptr (fh); /* useless ptr; Semaphore clock_sem */ - cwrite_ptr (fh); /* useless ptr; Task clock_task */ - cwrite_32 (fh, 0); /* useless value; DWORD TimeCounter */ + write_32 (fh, GLOBAL_STATE_TAG); + write_32 (fh, 75); + write_8 (fh, GSPtr->glob_flags); + write_8 (fh, GSPtr->CrewCost); + write_8 (fh, GSPtr->FuelCost); + write_a8 (fh, GSPtr->ModuleCost, NUM_MODULES); + write_a8 (fh, GSPtr->ElementWorth, NUM_ELEMENT_CATEGORIES); + write_16 (fh, GSPtr->CurrentActivity); - DummySaveQueue (&ClockPtr->event_q, fh); -} - -static void -SaveGameState (const GAME_STATE *GSPtr, DECODE_REF fh) -{ - cwrite_8 (fh, 0); /* obsolete; BYTE cur_state */ - cwrite_8 (fh, GSPtr->glob_flags); - cwrite_8 (fh, GSPtr->CrewCost); - cwrite_8 (fh, GSPtr->FuelCost); - cwrite_a8 (fh, GSPtr->ModuleCost, NUM_MODULES); - cwrite_a8 (fh, GSPtr->ElementWorth, NUM_ELEMENT_CATEGORIES); - cwrite_ptr (fh); /* useless ptr; PRIMITIVE *DisplayArray */ - cwrite_16 (fh, GSPtr->CurrentActivity); - - cwrite_16 (fh, 0); /* CLOCK_STATE alignment padding */ SaveClockState (&GSPtr->GameClock, fh); - cwrite_16 (fh, GSPtr->autopilot.x); - cwrite_16 (fh, GSPtr->autopilot.y); - cwrite_16 (fh, GSPtr->ip_location.x); - cwrite_16 (fh, GSPtr->ip_location.y); + write_16 (fh, GSPtr->autopilot.x); + write_16 (fh, GSPtr->autopilot.y); + write_16 (fh, GSPtr->ip_location.x); + write_16 (fh, GSPtr->ip_location.y); /* STAMP ShipStamp */ - cwrite_16 (fh, GSPtr->ShipStamp.origin.x); - cwrite_16 (fh, GSPtr->ShipStamp.origin.y); - cwrite_16 (fh, GSPtr->ShipFacing); - cwrite_8 (fh, GSPtr->ip_planet); - cwrite_8 (fh, GSPtr->in_orbit); + write_16 (fh, GSPtr->ShipStamp.origin.x); + write_16 (fh, GSPtr->ShipStamp.origin.y); + write_16 (fh, GSPtr->ShipFacing); + write_8 (fh, GSPtr->ip_planet); + write_8 (fh, GSPtr->in_orbit); /* VELOCITY_DESC velocity */ - cwrite_16 (fh, GSPtr->velocity.TravelAngle); - cwrite_16 (fh, GSPtr->velocity.vector.width); - cwrite_16 (fh, GSPtr->velocity.vector.height); - cwrite_16 (fh, GSPtr->velocity.fract.width); - cwrite_16 (fh, GSPtr->velocity.fract.height); - cwrite_16 (fh, GSPtr->velocity.error.width); - cwrite_16 (fh, GSPtr->velocity.error.height); - cwrite_16 (fh, GSPtr->velocity.incr.width); - cwrite_16 (fh, GSPtr->velocity.incr.height); - cwrite_16 (fh, 0); /* VELOCITY_DESC padding */ + write_16 (fh, GSPtr->velocity.TravelAngle); + write_16 (fh, GSPtr->velocity.vector.width); + write_16 (fh, GSPtr->velocity.vector.height); + write_16 (fh, GSPtr->velocity.fract.width); + write_16 (fh, GSPtr->velocity.fract.height); + write_16 (fh, GSPtr->velocity.error.width); + write_16 (fh, GSPtr->velocity.error.height); + write_16 (fh, GSPtr->velocity.incr.width); + write_16 (fh, GSPtr->velocity.incr.height); - cwrite_32 (fh, GSPtr->BattleGroupRef); - - DummySaveQueue (&GSPtr->avail_race_q, fh); - DummySaveQueue (&GSPtr->npc_built_ship_q, fh); - // Not saving ip_group_q, was not there originally - DummySaveQueue (&GSPtr->encounter_q, fh); - DummySaveQueue (&GSPtr->built_ship_q, fh); - - cwrite_a8 (fh, GSPtr->GameState, sizeof (GSPtr->GameState)); - - assert (sizeof (GSPtr->GameState) % 4 == 3); - cwrite_8 (fh, 0); /* GAME_STATE alignment padding */ + /* The Game state bits. Vanilla UQM uses 155 bytes here at + * present. Only the first 99 bytes are significant, though; + * the rest will be overwritten by the BtGp chunks. */ + write_32 (fh, GAME_STATE_TAG); + write_32 (fh, sizeof (GSPtr->GameState)); + write_a8 (fh, GSPtr->GameState, sizeof (GSPtr->GameState)); } -static BOOLEAN +/* This is folded into the Summary chunk */ +static void SaveSisState (const SIS_STATE *SSPtr, void *fp) { - if ( - write_32 (fp, SSPtr->log_x) != 1 || - write_32 (fp, SSPtr->log_y) != 1 || - write_32 (fp, SSPtr->ResUnits) != 1 || - write_32 (fp, SSPtr->FuelOnBoard) != 1 || - write_16 (fp, SSPtr->CrewEnlisted) != 1 || - write_16 (fp, SSPtr->TotalElementMass) != 1 || - write_16 (fp, SSPtr->TotalBioMass) != 1 || - write_a8 (fp, SSPtr->ModuleSlots, NUM_MODULE_SLOTS) != 1 || - write_a8 (fp, SSPtr->DriveSlots, NUM_DRIVE_SLOTS) != 1 || - write_a8 (fp, SSPtr->JetSlots, NUM_JET_SLOTS) != 1 || - write_8 (fp, SSPtr->NumLanders) != 1 || - write_a16 (fp, SSPtr->ElementAmounts, NUM_ELEMENT_CATEGORIES) != 1 || + write_32 (fp, SSPtr->log_x); + write_32 (fp, SSPtr->log_y); + write_32 (fp, SSPtr->ResUnits); + write_32 (fp, SSPtr->FuelOnBoard); + write_16 (fp, SSPtr->CrewEnlisted); + write_16 (fp, SSPtr->TotalElementMass); + write_16 (fp, SSPtr->TotalBioMass); + write_a8 (fp, SSPtr->ModuleSlots, NUM_MODULE_SLOTS); + write_a8 (fp, SSPtr->DriveSlots, NUM_DRIVE_SLOTS); + write_a8 (fp, SSPtr->JetSlots, NUM_JET_SLOTS); + write_8 (fp, SSPtr->NumLanders); + write_a16 (fp, SSPtr->ElementAmounts, NUM_ELEMENT_CATEGORIES); - write_str (fp, SSPtr->ShipName, SIS_NAME_SIZE) != 1 || - write_str (fp, SSPtr->CommanderName, SIS_NAME_SIZE) != 1 || - write_str (fp, SSPtr->PlanetName, SIS_NAME_SIZE) != 1 || - - write_16 (fp, 0) != 1 /* padding */ - ) - return FALSE; - else - return TRUE; + write_str (fp, SSPtr->ShipName, SIS_NAME_SIZE); + write_str (fp, SSPtr->CommanderName, SIS_NAME_SIZE); + write_str (fp, SSPtr->PlanetName, SIS_NAME_SIZE); } +/* Write out the Summary Chunk. This is variable length because of the + savegame name */ static BOOLEAN SaveSummary (const SUMMARY_DESC *SummPtr, void *fp) { - if (!SaveSisState (&SummPtr->SS, fp)) - return FALSE; + write_32 (fp, SUMMARY_TAG); + write_32 (fp, 160 + strlen(SummPtr->SaveName)); + SaveSisState (&SummPtr->SS, fp); - if ( - write_8 (fp, SummPtr->Activity) != 1 || - write_8 (fp, SummPtr->Flags) != 1 || - write_8 (fp, SummPtr->day_index) != 1 || - write_8 (fp, SummPtr->month_index) != 1 || - write_16 (fp, SummPtr->year_index) != 1 || - write_8 (fp, SummPtr->MCreditLo) != 1 || - write_8 (fp, SummPtr->MCreditHi) != 1 || - write_8 (fp, SummPtr->NumShips) != 1 || - write_8 (fp, SummPtr->NumDevices) != 1 || - write_a8 (fp, SummPtr->ShipList, MAX_BUILT_SHIPS) != 1 || - write_a8 (fp, SummPtr->DeviceList, MAX_EXCLUSIVE_DEVICES) != 1 || - - write_16 (fp, 0) != 1 /* padding */ - ) - return FALSE; - else - return TRUE; + write_8 (fp, SummPtr->Activity); + write_8 (fp, SummPtr->Flags); + write_8 (fp, SummPtr->day_index); + write_8 (fp, SummPtr->month_index); + write_16 (fp, SummPtr->year_index); + write_8 (fp, SummPtr->MCreditLo); + write_8 (fp, SummPtr->MCreditHi); + write_8 (fp, SummPtr->NumShips); + write_8 (fp, SummPtr->NumDevices); + write_a8 (fp, SummPtr->ShipList, MAX_BUILT_SHIPS); + write_a8 (fp, SummPtr->DeviceList, MAX_EXCLUSIVE_DEVICES); + write_a8 (fp, SummPtr->SaveName, strlen(SummPtr->SaveName)); } +/* Save the Star Description chunk. This is not to be confused with + * the Star *Info* chunk, which records which planetary features you + * have exploited with your lander */ static void -SaveStarDesc (const STAR_DESC *SDPtr, DECODE_REF fh) +SaveStarDesc (const STAR_DESC *SDPtr, uio_Stream *fh) { - cwrite_16 (fh, SDPtr->star_pt.x); - cwrite_16 (fh, SDPtr->star_pt.y); - cwrite_8 (fh, SDPtr->Type); - cwrite_8 (fh, SDPtr->Index); - cwrite_8 (fh, SDPtr->Prefix); - cwrite_8 (fh, SDPtr->Postfix); + write_32 (fh, STAR_TAG); + write_32 (fh, 8); + write_16 (fh, SDPtr->star_pt.x); + write_16 (fh, SDPtr->star_pt.y); + write_8 (fh, SDPtr->Type); + write_8 (fh, SDPtr->Index); + write_8 (fh, SDPtr->Prefix); + write_8 (fh, SDPtr->Postfix); } static void -PrepareSummary (SUMMARY_DESC *SummPtr) +PrepareSummary (SUMMARY_DESC *SummPtr, const char *name) { SummPtr->SS = GlobData.SIS_state; @@ -535,6 +489,8 @@ PrepareSummary (SUMMARY_DESC *SummPtr) SummPtr->day_index = GLOBAL (GameClock.day_index); SummPtr->month_index = GLOBAL (GameClock.month_index); SummPtr->year_index = GLOBAL (GameClock.year_index); + SummPtr->SaveName[SAVE_NAME_SIZE-1] = 0; + strncpy (SummPtr->SaveName, name, SAVE_NAME_SIZE-1); } static void @@ -549,7 +505,7 @@ SaveProblemMessage (STAMP *MsgStamp) // TODO: This should probably just use DoPopupWindow() ppStr[0] = GAME_STRING (SAVEGAME_STRING_BASE + 2); - + SetContextFont (StarConFont); t.baseline.x = t.baseline.y = 0; @@ -579,7 +535,7 @@ SaveProblemMessage (STAMP *MsgStamp) r.extent.height += 8; *MsgStamp = SaveContextFrame (&r); - + BatchGraphics (); DrawStarConBox (&r, 2, BUILD_COLOR (MAKE_RGB15 (0x10, 0x10, 0x10), 0x19), @@ -605,7 +561,7 @@ SaveProblem (void) { STAMP s; CONTEXT OldContext; - + OldContext = SetContext (SpaceContext); SaveProblemMessage (&s); FlushGraphics (); @@ -632,68 +588,210 @@ SaveFlagshipState (void) } } +static void +SaveStateFile (DWORD statefileId, DWORD tag, uio_Stream *fh) +{ + GAME_STATE_FILE *fp; + char buf[256]; + fp = OpenStateFile (statefileId, "rb"); + if (fp) + { + DWORD flen = LengthStateFile (fp); + write_32 (fh, tag); + write_32 (fh, flen); + while (flen) + { + COUNT num_bytes; + + num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; + ReadStateFile (buf, num_bytes, 1, fp); + write_a8 (fh, buf, num_bytes); + + flen -= num_bytes; + } + CloseStateFile (fp); + } +} + +static void +SaveStarInfo (uio_Stream *fh) +{ + GAME_STATE_FILE *fp; + fp = OpenStateFile (STARINFO_FILE, "rb"); + if (fp) + { + DWORD flen = LengthStateFile (fp); + if (flen % 4) + { + log_add (log_Warning, "Unexpected Star Info length! Expected an integral number of DWORDS.\n"); + } + else + { + write_32 (fh, SCAN_TAG); + write_32 (fh, flen); + while (flen) + { + DWORD val; + sread_32 (fp, &val); + write_32 (fh, val); + flen -= 4; + } + } + CloseStateFile (fp); + } +} + +static void +SaveBattleGroup (GAME_STATE_FILE *fp, DWORD encounter_id, DWORD grpoffs, uio_Stream *fh) +{ + GROUP_HEADER h; + DWORD size = 12; + int i; + SeekStateFile (fp, grpoffs, SEEK_SET); + ReadGroupHeader (fp, &h); + for (i = 1; i <= h.NumGroups; ++i) + { + BYTE NumShips; + SeekStateFile (fp, h.GroupOffset[i], SEEK_SET); + sread_8 (fp, NULL); + sread_8 (fp, &NumShips); + size += 2 + 10 * NumShips; + } + write_32 (fh, BATTLE_GROUP_TAG); + write_32 (fh, size); + write_32 (fh, encounter_id); + write_8 (fh, (grpoffs && (GLOBAL (BattleGroupRef) == grpoffs)) ? 1 : 0); // current + write_16 (fh, h.star_index); + write_8 (fh, h.day_index); + write_8 (fh, h.month_index); + write_16 (fh, h.year_index); + write_8 (fh, h.NumGroups); + for (i = 1; i <= h.NumGroups; ++i) + { + int j; + BYTE b; + SeekStateFile (fp, h.GroupOffset[i], SEEK_SET); + sread_8 (fp, &b); // Group race icon + write_8 (fh, b); + sread_8 (fp, &b); // NumShips + write_8 (fh, b); + for (j = 0; j < b; ++j) + { + BYTE race_outer; + SHIP_FRAGMENT sf; + sread_8 (fp, &race_outer); + ReadShipFragment (fp, &sf); + write_8 (fh, race_outer); + write_8 (fh, sf.captains_name_index); + write_8 (fh, sf.race_id); + write_8 (fh, sf.index); + write_16 (fh, sf.crew_level); + write_16 (fh, sf.max_crew); + write_8 (fh, sf.energy_level); + write_8 (fh, sf.max_energy); + } + } +} + +static void +SaveGroups (uio_Stream *fh) +{ + GAME_STATE_FILE *fp; + fp = OpenStateFile (RANDGRPINFO_FILE, "rb"); + if (fp && LengthStateFile (fp) > 0) + { + GROUP_HEADER h; + BYTE lastenc, count; + int i; + ReadGroupHeader (fp, &h); + /* Group List */ + SeekStateFile (fp, h.GroupOffset[0], SEEK_SET); + sread_8 (fp, &lastenc); + sread_8 (fp, &count); + write_32 (fh, GROUP_LIST_TAG); + write_32 (fh, 1 + 14 * count); // Chunk size + write_8 (fh, lastenc); + for (i = 0; i < count; ++i) + { + BYTE race_outer; + IP_GROUP ip; + sread_8 (fp, &race_outer); + ReadIpGroup (fp, &ip); + + write_8 (fh, race_outer); + write_16 (fh, ip.group_counter); + write_8 (fh, ip.race_id); + write_8 (fh, ip.sys_loc); + write_8 (fh, ip.task); + write_8 (fh, ip.in_system); + write_8 (fh, ip.dest_loc); + write_8 (fh, ip.orbit_pos); + write_8 (fh, ip.group_id); + write_16 (fh, ip.loc.x); + write_16 (fh, ip.loc.y); + } + SaveBattleGroup (fp, 0, 0, fh); + CloseStateFile (fp); + } + fp = OpenStateFile (DEFGRPINFO_FILE, "rb"); + if (fp && LengthStateFile (fp) > 0) + { + int state_index = SHOFIXTI_GRPOFFS0; + int encounter_index = 1; + while (state_index < NUM_GAME_STATE_BITS) + { + DWORD grpoffs = GET_GAME_STATE_32 (state_index); + if (grpoffs) + { + SaveBattleGroup (fp, encounter_index, grpoffs, fh); + } + ++encounter_index; + state_index += 32; + } + CloseStateFile (fp); + } +} + // This function first writes to a memory file, and then writes the whole // lot to the actual save file at once. BOOLEAN -SaveGame (COUNT which_game, SUMMARY_DESC *SummPtr) +SaveGame (COUNT which_game, SUMMARY_DESC *SummPtr, const char *name) { - BOOLEAN success, made_room; - void *out_fp, *h; - DECODE_REF fh; - - success = TRUE; - made_room = FALSE; -RetrySave: - h = HMalloc (10 * 1024); - if (h == 0 - || (fh = copen (h, MEMORY_STREAM, STREAM_WRITE)) == 0) - { - if (success) - { - success = FALSE; - made_room = TRUE; - HFree (h); - - FreeSC2Data (); - log_add (log_Debug, "Insufficient room for save buffers" - " -- RETRYING"); - goto RetrySave; - } - else - log_add (log_Debug, "Insufficient room for save buffers" - " -- GIVING UP!"); - } + uio_Stream *out_fp; + POINT pt; + STAR_DESC SD; + char file[PATH_MAX]; + if (CurStarDescPtr) + SD = *CurStarDescPtr; else + memset (&SD, 0, sizeof (SD)); + + // XXX: Backup: SaveFlagshipState() overwrites ip_location + pt = GLOBAL (ip_location); + SaveFlagshipState (); + if (LOBYTE (GLOBAL (CurrentActivity)) == IN_INTERPLANETARY + && !(GLOBAL (CurrentActivity) + & (START_ENCOUNTER | START_INTERPLANETARY))) + PutGroupInfo (GROUPS_RANDOM, GROUP_SAVE_IP); + + // Write the memory file to the actual savegame file. + sprintf (file, "uqmsave.%02u", which_game); + if ((out_fp = res_OpenResFile (saveDir, file, "wb"))) { - GAME_STATE_FILE *fp; - DWORD flen; - COUNT num_links; - POINT pt; - STAR_DESC SD; - char buf[256], file[PATH_MAX]; + io_ok = TRUE; + write_32 (out_fp, SAVEFILE_TAG); - success = TRUE; - if (CurStarDescPtr) - SD = *CurStarDescPtr; - else - memset (&SD, 0, sizeof (SD)); + PrepareSummary (SummPtr, name); + SaveSummary (SummPtr, out_fp); - // XXX: Backup: SaveFlagshipState() overwrites ip_location - pt = GLOBAL (ip_location); - SaveFlagshipState (); - if (LOBYTE (GLOBAL (CurrentActivity)) == IN_INTERPLANETARY - && !(GLOBAL (CurrentActivity) - & (START_ENCOUNTER | START_INTERPLANETARY))) - PutGroupInfo (GROUPS_RANDOM, GROUP_SAVE_IP); - - SaveGameState (&GlobData.Game_state, fh); + SaveGameState (&GlobData.Game_state, out_fp); // XXX: Restore GLOBAL (ip_location) = pt; // Only relevant when loading a game and must be cleaned GLOBAL (in_orbit) = 0; - SaveRaceQueue (fh, &GLOBAL (avail_race_q)); + SaveRaceQueue (out_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 @@ -701,161 +799,40 @@ RetrySave: if (!(GLOBAL (CurrentActivity) & START_INTERPLANETARY)) { if (GLOBAL (CurrentActivity) & START_ENCOUNTER) - SaveShipQueue (fh, &GLOBAL (npc_built_ship_q)); + SaveShipQueue (out_fp, &GLOBAL (npc_built_ship_q), NPC_SHIP_Q_TAG); else if (LOBYTE (GLOBAL (CurrentActivity)) == 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. - SaveGroupQueue (fh, &GLOBAL (ip_group_q)); - //SaveEmptyQueue (fh); - else - // XXX: empty queue write-out is only needed to maintain - // the savegame compatibility - SaveEmptyQueue (fh); + SaveGroupQueue (out_fp, &GLOBAL (ip_group_q)); } - SaveShipQueue (fh, &GLOBAL (built_ship_q)); + SaveShipQueue (out_fp, &GLOBAL (built_ship_q), SHIP_Q_TAG); - // Save the number of game events (compressed). - num_links = CountLinks (&GLOBAL (GameClock.event_q)); - cwrite_16 (fh, num_links); - // Save the game events themselves (compressed): + // Save the game event chunk + SaveEvents (out_fp); + + // Save the encounter chunk (black globes in HS/QS) + SaveEncounters (out_fp); + + // Save out the data that used to be in state files + SaveStarInfo (out_fp); + SaveGroups (out_fp); + + // Save out the Star Descriptor + SaveStarDesc (&SD, out_fp); + + res_CloseResFile (out_fp); + if (!io_ok) { - HEVENT hEvent; - - hEvent = GetHeadLink (&GLOBAL (GameClock.event_q)); - while (num_links--) - { - HEVENT hNextEvent; - EVENT *EventPtr; - - LockEvent (hEvent, &EventPtr); - hNextEvent = GetSuccEvent (EventPtr); - - SaveEvent (EventPtr, fh); - - UnlockEvent (hEvent); - hEvent = hNextEvent; - } + DeleteResFile(saveDir, file); + return FALSE; } - - // Save the number of encounters (black globes in HS/QS (compressed)) - num_links = CountLinks (&GLOBAL (encounter_q)); - // Save the encounters themselves (compressed): - cwrite_16 (fh, num_links); - { - HENCOUNTER hEncounter; - - hEncounter = GetHeadLink (&GLOBAL (encounter_q)); - while (num_links--) - { - HENCOUNTER hNextEncounter; - ENCOUNTER *EncounterPtr; - - LockEncounter (hEncounter, &EncounterPtr); - hNextEncounter = GetSuccEncounter (EncounterPtr); - - SaveEncounter (EncounterPtr, fh); - - UnlockEncounter (hEncounter); - hEncounter = hNextEncounter; - } - } - - // Copy the star info file to the memory file (compressed). - fp = OpenStateFile (STARINFO_FILE, "rb"); - if (fp) - { - flen = LengthStateFile (fp); - // Write the uncompressed size. - cwrite_32 (fh, flen); - while (flen) - { - COUNT num_bytes; - - num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; - ReadStateFile (buf, num_bytes, 1, fp); - cwrite (buf, num_bytes, 1, fh); - - flen -= num_bytes; - } - CloseStateFile (fp); - } - - // Copy the defined groupinfo file into the memory file (compressed) - fp = OpenStateFile (DEFGRPINFO_FILE, "rb"); - if (fp) - { - flen = LengthStateFile (fp); - // Write the uncompressed size. - cwrite_32 (fh, flen); - while (flen) - { - COUNT num_bytes; - - num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; - ReadStateFile (buf, num_bytes, 1, fp); - cwrite (buf, num_bytes, 1, fh); - - flen -= num_bytes; - } - CloseStateFile (fp); - } - - // Copy the random groupinfo file into the memory file (compressed) - fp = OpenStateFile (RANDGRPINFO_FILE, "rb"); - if (fp) - { - flen = LengthStateFile (fp); - // Write the uncompressed size. - cwrite_32 (fh, flen); - while (flen) - { - COUNT num_bytes; - - num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen; - ReadStateFile (buf, num_bytes, 1, fp); - cwrite (buf, num_bytes, 1, fh); - - flen -= num_bytes; - } - CloseStateFile (fp); - } - - // Write the current star desc into the memory file (compressed). - SaveStarDesc (&SD, fh); - - flen = cclose (fh); - - // Write the memory file to the actual savegame file. - sprintf (file, "starcon2.%02u", which_game); - log_add (log_Debug, "'%s' is %u bytes long", file, - flen + sizeof (*SummPtr)); - if (flen && (out_fp = res_OpenResFile (saveDir, file, "wb"))) - { - PrepareSummary (SummPtr); - - success = SaveSummary (SummPtr, out_fp); - // Then write the rest of the data. - if (success && WriteResFile (h, flen, 1, out_fp) != 1) - success = FALSE; - - if (res_CloseResFile ((uio_Stream *)out_fp) == 0) - success = FALSE; - - } - else - success = FALSE; - - if (!success) - DeleteResFile (saveDir, file); + } + else + { + return FALSE; } - HFree (h); - - if (made_room) - LoadSC2Data (); - - return (success); + return TRUE; } - diff --git a/sc2/src/uqm/save.h b/sc2/src/uqm/save.h index 2521cf27d..28852b8ae 100644 --- a/sc2/src/uqm/save.h +++ b/sc2/src/uqm/save.h @@ -17,16 +17,59 @@ #ifndef UQM_SAVE_H_ #define UQM_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) } diff --git a/sc2/src/uqm/ships/androsyn/androsyn.c b/sc2/src/uqm/ships/androsyn/androsyn.c index 2625b3f80..1139d8da0 100644 --- a/sc2/src/uqm/ships/androsyn/androsyn.c +++ b/sc2/src/uqm/ships/androsyn/androsyn.c @@ -22,22 +22,38 @@ #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 20 #define MAX_ENERGY 24 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 3 -#define SPECIAL_ENERGY_COST 2 #define ENERGY_WAIT 8 #define MAX_THRUST 24 #define THRUST_INCREMENT 3 #define TURN_WAIT 4 #define THRUST_WAIT 0 -#define WEAPON_WAIT 0 -#define SPECIAL_WAIT 0 - #define SHIP_MASS 6 +// Bubbles +#define WEAPON_ENERGY_COST 3 +#define WEAPON_WAIT 0 +#define ANDROSYNTH_OFFSET 14 +#define MISSILE_OFFSET 3 +#define MISSILE_SPEED DISPLAY_TO_WORLD (8) +#define MISSILE_LIFE 200 +#define MISSILE_HITS 3 +#define MISSILE_DAMAGE 2 +#define TRACK_WAIT 2 + +// Blazer +#define SPECIAL_ENERGY_COST 2 +#define BLAZER_DEGENERATION (-1) +#define SPECIAL_WAIT 0 +#define BLAZER_OFFSET 10 +#define BLAZER_THRUST 60 +#define BLAZER_TURN_WAIT 1 +#define BLAZER_DAMAGE 3 +#define BLAZER_MASS 1 + static RACE_DESC androsynth_desc = { { /* SHIP_INFO */ @@ -149,15 +165,10 @@ SetCustomShipData (RACE_DESC *pRaceDesc, const CustomShipData_t *data) } } - -#define BLAZER_DAMAGE 3 -#define BLAZER_MASS 1 - static void blazer_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) { -#define BLAZER_OFFSET 10 BYTE old_offs; COUNT old_crew_level; COUNT old_life; @@ -177,8 +188,6 @@ blazer_collision (ELEMENT *ElementPtr0, POINT *pPt0, collision (ElementPtr0, pPt0, ElementPtr1, pPt1); } -#define MISSILE_SPEED DISPLAY_TO_WORLD (8) - static void bubble_preprocess (ELEMENT *ElementPtr) { @@ -214,23 +223,15 @@ bubble_preprocess (ELEMENT *ElementPtr) facing -= (COUNT)TFB_Random () & (ANGLE_TO_FACING (HALF_CIRCLE) - 1); SetVelocityVector (&ElementPtr->velocity, MISSILE_SPEED, facing); - -#define TRACK_WAIT 2 turn_wait = TRACK_WAIT; } ElementPtr->turn_wait = MAKE_BYTE (turn_wait, thrust_wait); } -#define MISSILE_DAMAGE 2 -#define MISSILE_LIFE 200 - static COUNT initialize_bubble (ELEMENT *ShipPtr, HELEMENT BubbleArray[]) { -#define ANDROSYNTH_OFFSET 14 -#define MISSILE_OFFSET 3 -#define MISSILE_HITS 3 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -364,8 +365,6 @@ androsynth_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, } } -#define BLAZER_TURN_WAIT 1 - static void androsynth_postprocess (ELEMENT *ElementPtr) { @@ -375,7 +374,6 @@ androsynth_postprocess (ELEMENT *ElementPtr) /* take care of blazer effect */ if (ElementPtr->next.image.farray == StarShipPtr->RaceDescPtr->ship_data.special) { -#define BLAZER_DEGENERATION (-1) if ((StarShipPtr->cur_status_flags & SPECIAL) || StarShipPtr->RaceDescPtr->ship_info.energy_level == 0) { @@ -484,7 +482,6 @@ androsynth_preprocess (ELEMENT *ElementPtr) --ElementPtr->thrust_wait; else { -#define BLAZER_THRUST 60 COUNT facing; facing = StarShipPtr->ShipFacing; diff --git a/sc2/src/uqm/ships/arilou/arilou.c b/sc2/src/uqm/ships/arilou/arilou.c index 5b32bcd3b..78340a37a 100644 --- a/sc2/src/uqm/ships/arilou/arilou.c +++ b/sc2/src/uqm/ships/arilou/arilou.c @@ -22,24 +22,28 @@ #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 6 #define MAX_ENERGY 20 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 2 -#define SPECIAL_ENERGY_COST 3 #define ENERGY_WAIT 6 #define MAX_THRUST /* DISPLAY_TO_WORLD (10) */ 40 #define THRUST_INCREMENT MAX_THRUST -#define TURN_WAIT 0 #define THRUST_WAIT 0 -#define WEAPON_WAIT 1 -#define SPECIAL_WAIT 2 - +#define TURN_WAIT 0 #define SHIP_MASS 1 + +// Tracking Laser +#define WEAPON_ENERGY_COST 2 +#define WEAPON_WAIT 1 #define ARILOU_OFFSET 9 #define LASER_RANGE DISPLAY_TO_WORLD (100 + ARILOU_OFFSET) +// Teleporter +#define SPECIAL_ENERGY_COST 3 +#define SPECIAL_WAIT 2 +#define HYPER_LIFE 5 + static RACE_DESC arilou_desc = { { /* SHIP_INFO */ @@ -209,7 +213,6 @@ arilou_preprocess (ELEMENT *ElementPtr) && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) { /* Special key is pressed; start teleport */ -#define HYPER_LIFE 5 ZeroVelocityComponents (&ElementPtr->velocity); StarShipPtr->cur_status_flags &= ~(SHIP_AT_MAX_SPEED | LEFT | RIGHT | THRUST | WEAPON); diff --git a/sc2/src/uqm/ships/blackurq/blackurq.c b/sc2/src/uqm/ships/blackurq/blackurq.c index c05591d58..286191dd0 100644 --- a/sc2/src/uqm/ships/blackurq/blackurq.c +++ b/sc2/src/uqm/ships/blackurq/blackurq.c @@ -22,25 +22,48 @@ #include "uqm/globdata.h" - +// Core characteristics #define MAX_CREW MAX_CREW_SIZE #define MAX_ENERGY MAX_ENERGY_SIZE #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 6 -#define SPECIAL_ENERGY_COST (MAX_ENERGY_SIZE / 2) #define ENERGY_WAIT 4 #define MAX_THRUST 30 #define THRUST_INCREMENT 6 #define TURN_WAIT 4 #define THRUST_WAIT 6 -#define WEAPON_WAIT 6 -#define SPECIAL_WAIT 9 - #define SHIP_MASS 10 + +// Buzzsaw +#define WEAPON_ENERGY_COST 6 +#define WEAPON_WAIT 6 +#define MISSILE_OFFSET 9 +#define KOHR_AH_OFFSET 28 #define MISSILE_SPEED 64 -#define MISSILE_LIFE 64 /* actually, it's as long as you - * hold the button down. - */ +#define MISSILE_LIFE 64 + /* actually, it's as long as you hold the button down.*/ +#define MISSILE_HITS 10 +#define MISSILE_DAMAGE 4 +#define SAW_RATE 0 +#define MAX_SAWS 8 +#define ACTIVATE_RANGE 224 + /* Originally SPACE_WIDTH - the distance within which + * stationary sawblades will home */ +#define TRACK_WAIT 4 +#define FRAGMENT_SPEED MISSILE_SPEED +#define FRAGMENT_LIFE 10 +#define FRAGMENT_RANGE (FRAGMENT_LIFE * FRAGMENT_SPEED) + +// F.R.I.E.D. +#define SPECIAL_ENERGY_COST (MAX_ENERGY_SIZE / 2) +#define SPECIAL_WAIT 9 +#define GAS_OFFSET 2 +#define GAS_SPEED 16 +#define GAS_RATE 2 /* Controls animation of the gas cloud decay - the decay + * animation advances one frame every GAS_RATE frames. */ +#define GAS_HITS 100 +#define GAS_DAMAGE 3 +#define GAS_ALT_DAMAGE 50 +#define NUM_GAS_CLOUDS 16 static RACE_DESC black_urquan_desc = { @@ -113,9 +136,6 @@ static RACE_DESC black_urquan_desc = 0, /* CodeRef */ }; -#define SAW_RATE 0 -#define MAX_SAWS 8 - static void spin_preprocess (ELEMENT *ElementPtr) { @@ -154,8 +174,6 @@ spin_preprocess (ELEMENT *ElementPtr) UnlockElement (StarShipPtr->hShip); } -#define TRACK_WAIT 4 - static void buzztrack_preprocess (ELEMENT *ElementPtr) { @@ -172,7 +190,6 @@ buzztrack_preprocess (ELEMENT *ElementPtr) } else { -#define ACTIVATE_RANGE 224 /* Originally SPACE_WIDTH */ SIZE delta_x, delta_y; ELEMENT *eptr; @@ -311,10 +328,6 @@ buzzsaw_postprocess (ELEMENT *ElementPtr) static COUNT initialize_buzzsaw (ELEMENT *ShipPtr, HELEMENT SawArray[]) { -#define MISSILE_HITS 10 -#define MISSILE_DAMAGE 4 -#define MISSILE_OFFSET 9 -#define KOHR_AH_OFFSET 28 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -379,9 +392,6 @@ black_urquan_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; if (lpEvalDesc->ObjectPtr) { -#define FRAGMENT_LIFE 10 -#define FRAGMENT_SPEED MISSILE_SPEED -#define FRAGMENT_RANGE (FRAGMENT_LIFE * FRAGMENT_SPEED) HELEMENT h, hNext; ELEMENT *BuzzSawPtr; @@ -433,8 +443,6 @@ black_urquan_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, } } -#define GAS_RATE 2 - static void gas_cloud_preprocess (ELEMENT *ElementPtr) { @@ -450,8 +458,6 @@ gas_cloud_preprocess (ELEMENT *ElementPtr) } } -#define GAS_DAMAGE 3 - static void gas_cloud_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) @@ -459,7 +465,7 @@ gas_cloud_collision (ELEMENT *ElementPtr0, POINT *pPt0, if (ElementPtr1->state_flags & PLAYER_SHIP) ElementPtr0->mass_points = GAS_DAMAGE; else - ElementPtr0->mass_points = 50; + ElementPtr0->mass_points = GAS_ALT_DAMAGE; weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); } @@ -467,10 +473,6 @@ gas_cloud_collision (ELEMENT *ElementPtr0, POINT *pPt0, static void spawn_gas_cloud (ELEMENT *ElementPtr) { -#define GAS_SPEED 16 -#define GAS_HITS 100 -#define GAS_OFFSET 2 -#define NUM_GAS_CLOUDS 16 SIZE dx, dy; STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; diff --git a/sc2/src/uqm/ships/chenjesu/chenjesu.c b/sc2/src/uqm/ships/chenjesu/chenjesu.c index 6d548ba33..85a101485 100644 --- a/sc2/src/uqm/ships/chenjesu/chenjesu.c +++ b/sc2/src/uqm/ships/chenjesu/chenjesu.c @@ -23,27 +23,48 @@ #include "uqm/globdata.h" #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 36 #define MAX_ENERGY 30 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 5 -#define SPECIAL_ENERGY_COST MAX_ENERGY #define ENERGY_WAIT 4 #define MAX_THRUST /* DISPLAY_TO_WORLD (7) */ 27 #define THRUST_INCREMENT /* DISPLAY_TO_WORLD (2) */ 3 -#define TURN_WAIT 6 #define THRUST_WAIT 4 -#define WEAPON_WAIT 0 -#define SPECIAL_WAIT 0 - -#define MAX_DOGGIES 4 - +#define TURN_WAIT 6 #define SHIP_MASS 10 + +// Photon Shard +#define WEAPON_ENERGY_COST 5 +#define WEAPON_WAIT 0 +#define CHENJESU_OFFSET 16 +#define MISSILE_OFFSET 0 #define MISSILE_SPEED DISPLAY_TO_WORLD (16) -#define MISSILE_LIFE 90 /* actually, it's as long as you - * hold the button down. - */ +#define MISSILE_LIFE 90 + /* actually, it's as long as you hold the button down. */ +#define MISSILE_HITS 10 +#define MISSILE_DAMAGE 6 +#define NUM_SPARKLES 8 + +// Shrapnel +#define FRAGMENT_OFFSET 2 +#define NUM_FRAGMENTS 8 +#define FRAGMENT_LIFE 10 +#define FRAGMENT_SPEED MISSILE_SPEED +#define FRAGMENT_RANGE (FRAGMENT_LIFE * FRAGMENT_SPEED) + /* This bit is for the cyborg only. */ +#define FRAGMENT_HITS 1 +#define FRAGMENT_DAMAGE 2 + +// DOGI +#define SPECIAL_ENERGY_COST MAX_ENERGY +#define SPECIAL_WAIT 0 +#define DOGGY_OFFSET 18 +#define DOGGY_SPEED DISPLAY_TO_WORLD (8) +#define ENERGY_DRAIN 10 +#define MAX_DOGGIES 4 +#define DOGGY_HITS 3 +#define DOGGY_MASS 4 static RACE_DESC chenjesu_desc = { @@ -116,17 +137,9 @@ static RACE_DESC chenjesu_desc = 0, /* CodeRef */ }; -#define FRAGMENT_LIFE 10 -#define FRAGMENT_SPEED MISSILE_SPEED -#define FRAGMENT_RANGE (FRAGMENT_LIFE * FRAGMENT_SPEED) - static void crystal_postprocess (ELEMENT *ElementPtr) { -#define FRAGMENT_HITS 1 -#define FRAGMENT_DAMAGE 2 -#define FRAGMENT_OFFSET 2 -#define NUM_FRAGMENTS 8 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -212,7 +225,6 @@ crystal_collision (ELEMENT *ElementPtr0, POINT *pPt0, { ELEMENT *BlastElementPtr; -#define NUM_SPARKLES 8 LockElement (hBlastElement, &BlastElementPtr); BlastElementPtr->current.location = ElementPtr1->current.location; @@ -231,9 +243,6 @@ crystal_collision (ELEMENT *ElementPtr0, POINT *pPt0, } } -#define DOGGY_OFFSET 18 -#define DOGGY_SPEED DISPLAY_TO_WORLD (8) - static void doggy_preprocess (ELEMENT *ElementPtr) { @@ -314,7 +323,6 @@ static void doggy_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) { -#define ENERGY_DRAIN 10 collision (ElementPtr0, pPt0, ElementPtr1, pPt1); if ((ElementPtr1->state_flags & PLAYER_SHIP) && !elementsOfSamePlayer (ElementPtr0, ElementPtr1)) @@ -335,8 +343,6 @@ doggy_collision (ELEMENT *ElementPtr0, POINT *pPt0, ElementPtr0->thrust_wait += COLLISION_THRUST_WAIT << 1; } -#define CHENJESU_OFFSET 16 - static void spawn_doggy (ELEMENT *ElementPtr) { @@ -352,8 +358,8 @@ spawn_doggy (ELEMENT *ElementPtr) PutElement (hDoggyElement); LockElement (hDoggyElement, &DoggyElementPtr); - DoggyElementPtr->hit_points = 3; - DoggyElementPtr->mass_points = 4; + DoggyElementPtr->hit_points = DOGGY_HITS; + DoggyElementPtr->mass_points = DOGGY_MASS; DoggyElementPtr->thrust_wait = 0; DoggyElementPtr->playerNr = ElementPtr->playerNr; DoggyElementPtr->state_flags = APPEARING; @@ -499,9 +505,6 @@ chenjesu_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, static COUNT initialize_crystal (ELEMENT *ShipPtr, HELEMENT CrystalArray[]) { -#define MISSILE_HITS 10 -#define MISSILE_DAMAGE 6 -#define MISSILE_OFFSET 0 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; diff --git a/sc2/src/uqm/ships/chmmr/chmmr.c b/sc2/src/uqm/ships/chmmr/chmmr.c index d5a616443..8f6abf0dc 100644 --- a/sc2/src/uqm/ships/chmmr/chmmr.c +++ b/sc2/src/uqm/ships/chmmr/chmmr.c @@ -24,23 +24,36 @@ #include "uqm/globdata.h" #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW MAX_CREW_SIZE #define MAX_ENERGY MAX_ENERGY_SIZE #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 2 -#define SPECIAL_ENERGY_COST 1 #define ENERGY_WAIT 1 #define MAX_THRUST 35 #define THRUST_INCREMENT 7 -#define TURN_WAIT 3 #define THRUST_WAIT 5 -#define WEAPON_WAIT 0 -#define SPECIAL_WAIT 0 - +#define TURN_WAIT 3 #define SHIP_MASS 10 + +// Laser +#define WEAPON_ENERGY_COST 2 +#define WEAPON_WAIT 0 #define CHMMR_OFFSET 18 #define LASER_RANGE DISPLAY_TO_WORLD (150) +#define NUM_CYCLES 4 + +// Tractor Beam +#define SPECIAL_ENERGY_COST 1 +#define SPECIAL_WAIT 0 +#define NUM_SHADOWS 5 + +// Satellites +#define NUM_SATELLITES 3 +#define SATELLITE_OFFSET DISPLAY_TO_WORLD (64) +#define SATELLITE_HITPOINTS 10 +#define SATELLITE_MASS 10 +#define DEFENSE_RANGE (UWORD)64 +#define DEFENSE_WAIT 2 static RACE_DESC chmmr_desc = { @@ -202,7 +215,6 @@ laser_death (ELEMENT *ElementPtr) static COUNT initialize_megawatt_laser (ELEMENT *ShipPtr, HELEMENT LaserArray[]) { -#define NUM_CYCLES 4 RECT r; STARSHIP *StarShipPtr; LASER_BLOCK LaserBlock; @@ -337,8 +349,6 @@ chmmr_postprocess (ELEMENT *ElementPtr) facing = 0; if (TrackShip (ElementPtr, &facing) >= 0) { -#define NUM_SHADOWS 5 - ELEMENT *ShipElementPtr; LockElement (ElementPtr->hTarget, &ShipElementPtr); @@ -444,8 +454,6 @@ chmmr_postprocess (ELEMENT *ElementPtr) StarShipPtr->special_counter = 0; } -#define SATELLITE_OFFSET DISPLAY_TO_WORLD (64) - static void satellite_preprocess (ELEMENT *ElementPtr) { @@ -502,8 +510,6 @@ satellite_preprocess (ELEMENT *ElementPtr) static void spawn_point_defense (ELEMENT *ElementPtr) { -#define DEFENSE_RANGE (UWORD)64 -#define DEFENSE_WAIT 2 BYTE weakest; UWORD best_dist; STARSHIP *StarShipPtr; @@ -674,7 +680,6 @@ satellite_death (ELEMENT *ElementPtr) static void spawn_satellites (ELEMENT *ElementPtr) { -#define NUM_SATELLITES 3 COUNT i; STARSHIP *StarShipPtr; @@ -697,8 +702,8 @@ spawn_satellites (ELEMENT *ElementPtr) SattPtr->state_flags = IGNORE_SIMILAR | APPEARING | FINITE_LIFE; SattPtr->life_span = NORMAL_LIFE + 1; - SattPtr->hit_points = 10; - SattPtr->mass_points = 10; + SattPtr->hit_points = SATELLITE_HITPOINTS; + SattPtr->mass_points = SATELLITE_MASS; angle = (i * FULL_CIRCLE + (NUM_SATELLITES >> 1)) / NUM_SATELLITES; diff --git a/sc2/src/uqm/ships/druuge/druuge.c b/sc2/src/uqm/ships/druuge/druuge.c index ff75fc76d..6ba2591ce 100644 --- a/sc2/src/uqm/ships/druuge/druuge.c +++ b/sc2/src/uqm/ships/druuge/druuge.c @@ -20,23 +20,33 @@ #include "druuge.h" #include "resinst.h" +// Core characteristics #define MAX_CREW 14 #define MAX_ENERGY 32 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 4 -#define SPECIAL_ENERGY_COST 16 #define ENERGY_WAIT 50 #define MAX_THRUST 20 #define THRUST_INCREMENT 2 -#define TURN_WAIT 4 #define THRUST_WAIT 1 -#define WEAPON_WAIT 10 -#define SPECIAL_WAIT 30 - +#define TURN_WAIT 4 #define SHIP_MASS 5 + +// Mass Driver +#define WEAPON_ENERGY_COST 4 +#define WEAPON_WAIT 10 +#define DRUUGE_OFFSET 24 +#define MISSILE_OFFSET 6 #define MISSILE_SPEED DISPLAY_TO_WORLD (30) #define MISSILE_LIFE 20 #define MISSILE_RANGE (MISSILE_SPEED * MISSILE_LIFE) +#define MISSILE_HITS 4 +#define MISSILE_DAMAGE 6 +#define RECOIL_VELOCITY WORLD_TO_VELOCITY (DISPLAY_TO_WORLD (6)) +#define MAX_RECOIL_VELOCITY (RECOIL_VELOCITY * 4) + +// Furnace +#define SPECIAL_ENERGY_COST 16 +#define SPECIAL_WAIT 30 static RACE_DESC druuge_desc = { @@ -109,9 +119,6 @@ static RACE_DESC druuge_desc = 0, /* CodeRef */ }; -#define RECOIL_VELOCITY WORLD_TO_VELOCITY (DISPLAY_TO_WORLD (6)) -#define MAX_RECOIL_VELOCITY (RECOIL_VELOCITY * 4) - static void cannon_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) @@ -153,10 +160,6 @@ cannon_collision (ELEMENT *ElementPtr0, POINT *pPt0, static COUNT initialize_cannon (ELEMENT *ShipPtr, HELEMENT CannonArray[]) { -#define DRUUGE_OFFSET 24 -#define MISSILE_OFFSET 6 -#define MISSILE_HITS 4 -#define MISSILE_DAMAGE 6 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; diff --git a/sc2/src/uqm/ships/human/human.c b/sc2/src/uqm/ships/human/human.c index de751b960..354486dde 100644 --- a/sc2/src/uqm/ships/human/human.c +++ b/sc2/src/uqm/ships/human/human.c @@ -23,24 +23,36 @@ #include "uqm/colors.h" #include "uqm/globdata.h" - +// Core characteristics #define MAX_CREW 18 #define MAX_ENERGY 18 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 9 -#define SPECIAL_ENERGY_COST 4 #define ENERGY_WAIT 8 #define MAX_THRUST /* DISPLAY_TO_WORLD (6) */ 24 #define THRUST_INCREMENT /* DISPLAY_TO_WORLD (2) */ 3 -#define TURN_WAIT 1 #define THRUST_WAIT 4 -#define WEAPON_WAIT 10 -#define SPECIAL_WAIT 9 - +#define TURN_WAIT 1 #define SHIP_MASS 6 -#define MISSILE_LIFE 60 + +// Nuke +#define WEAPON_ENERGY_COST 9 +#define WEAPON_WAIT 10 +#define HUMAN_OFFSET 42 +#define NUKE_OFFSET 8 #define MIN_MISSILE_SPEED DISPLAY_TO_WORLD (10) #define MAX_MISSILE_SPEED DISPLAY_TO_WORLD (20) +#define MISSILE_SPEED (MAX_THRUST >= MIN_MISSILE_SPEED ? \ + MAX_THRUST : MIN_MISSILE_SPEED) +#define THRUST_SCALE DISPLAY_TO_WORLD (1) +#define MISSILE_LIFE 60 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 4 +#define TRACK_WAIT 3 + +// Point-Defense Laser +#define SPECIAL_ENERGY_COST 4 +#define SPECIAL_WAIT 9 +#define LASER_RANGE (UWORD)100 static RACE_DESC human_desc = { @@ -113,10 +125,6 @@ static RACE_DESC human_desc = 0, /* CodeRef */ }; -#define MISSILE_SPEED (MAX_THRUST >= MIN_MISSILE_SPEED ? \ - MAX_THRUST : MIN_MISSILE_SPEED) -#define TRACK_WAIT 3 - static void nuke_preprocess (ELEMENT *ElementPtr) { @@ -141,7 +149,6 @@ nuke_preprocess (ELEMENT *ElementPtr) { SIZE speed; -#define THRUST_SCALE DISPLAY_TO_WORLD (1) if ((speed = MISSILE_SPEED + ((MISSILE_LIFE - ElementPtr->life_span) * THRUST_SCALE)) > MAX_MISSILE_SPEED) @@ -196,7 +203,6 @@ spawn_point_defense (ELEMENT *ElementPtr) if (ObjectPtr != ShipPtr && CollidingElement (ObjectPtr) && !OBJECT_CLOAKED (ObjectPtr)) { -#define LASER_RANGE (UWORD)100 SIZE delta_x, delta_y; delta_x = ObjectPtr->next.location.x - @@ -265,10 +271,6 @@ spawn_point_defense (ELEMENT *ElementPtr) static COUNT initialize_nuke (ELEMENT *ShipPtr, HELEMENT NukeArray[]) { -#define HUMAN_OFFSET 42 -#define MISSILE_DAMAGE 4 -#define MISSILE_HITS 1 -#define NUKE_OFFSET 8 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; diff --git a/sc2/src/uqm/ships/ilwrath/ilwrath.c b/sc2/src/uqm/ships/ilwrath/ilwrath.c index e4975ff2c..394708134 100644 --- a/sc2/src/uqm/ships/ilwrath/ilwrath.c +++ b/sc2/src/uqm/ships/ilwrath/ilwrath.c @@ -24,21 +24,33 @@ #include "uqm/globdata.h" +// Core characteristics #define MAX_CREW 22 #define MAX_ENERGY 16 #define ENERGY_REGENERATION 4 -#define WEAPON_ENERGY_COST 1 -#define SPECIAL_ENERGY_COST 3 #define ENERGY_WAIT 4 #define MAX_THRUST 25 #define THRUST_INCREMENT 5 -#define TURN_WAIT 2 #define THRUST_WAIT 0 -#define WEAPON_WAIT 0 -#define SPECIAL_WAIT 13 - +#define TURN_WAIT 2 #define SHIP_MASS 7 +#define LOOK_AHEAD 4 + /* Controls how much the auto-turn will attempt to "lead" + * its target. */ + +// Hellfire Spout +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 0 #define MISSILE_LIFE 8 +#define ILWRATH_OFFSET 29 +#define MISSILE_SPEED MAX_THRUST +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 +#define MISSILE_OFFSET 0 + +// Cloaking Device +#define SPECIAL_ENERGY_COST 3 +#define SPECIAL_WAIT 13 static RACE_DESC ilwrath_desc = { @@ -178,11 +190,6 @@ ilwrath_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, static COUNT initialize_flame (ELEMENT *ShipPtr, HELEMENT FlameArray[]) { -#define ILWRATH_OFFSET 29 -#define MISSILE_SPEED MAX_THRUST -#define MISSILE_HITS 1 -#define MISSILE_DAMAGE 1 -#define MISSILE_OFFSET 0 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -278,7 +285,6 @@ ilwrath_preprocess (ELEMENT *ElementPtr) facing = StarShipPtr->ShipFacing; if (TrackShip (ElementPtr, &facing) >= 0) { -#define LOOK_AHEAD 4 ELEMENT *eptr; SIZE dx0, dy0, dx1, dy1; VELOCITY_DESC v; diff --git a/sc2/src/uqm/ships/lastbat/lastbat.c b/sc2/src/uqm/ships/lastbat/lastbat.c index 568b2aae1..9d44742c6 100644 --- a/sc2/src/uqm/ships/lastbat/lastbat.c +++ b/sc2/src/uqm/ships/lastbat/lastbat.c @@ -27,25 +27,58 @@ #include "libs/mathlib.h" #include "libs/timelib.h" - #define num_generators characteristics.max_thrust +// Core characteristics #define MAX_CREW 1 #define MAX_ENERGY MAX_ENERGY_SIZE #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 2 -#define SPECIAL_ENERGY_COST 3 #define ENERGY_WAIT 6 #define MAX_THRUST 0 #define THRUST_INCREMENT 0 #define TURN_WAIT 0 #define THRUST_WAIT 0 -#define WEAPON_WAIT ((ONE_SECOND / BATTLE_FRAME_RATE) * 10) -#define SPECIAL_WAIT ((ONE_SECOND / BATTLE_FRAME_RATE) * 3) - #define SHIP_MASS (MAX_SHIP_MASS * 10) -#define SAMATRA_OFFSET 9 -#define MISSILE_SPEED DISPLAY_TO_WORLD (8) +#define TURRET_WAIT 0 /* Controls animation of the Sa-Matra's central + * 'furnace', a new frame is displayed once every + * TURRET_WAIT frames. */ + +// Yellow comet +#define WEAPON_WAIT ((ONE_SECOND / BATTLE_FRAME_RATE) * 10) +#define COMET_DAMAGE 2 +#define COMET_OFFSET 0 +#define COMET_HITS 12 +#define COMET_SPEED DISPLAY_TO_WORLD (12) +#define COMET_LIFE 2 +#define COMET_TURN_WAIT 3 +#define MAX_COMETS 3 +#define WEAPON_ENERGY_COST 2 + /* Used for samatra_desc.weapon_energy_cost, but the value isn't + * actually used. */ + +// Green sentinel +#define SPECIAL_WAIT ((ONE_SECOND / BATTLE_FRAME_RATE) * 3) +#define SENTINEL_SPEED DISPLAY_TO_WORLD (8) +#define SENTINEL_LIFE 2 +#define SENTINEL_OFFSET 0 +#define SENTINEL_HITS 10 +#define SENTINEL_DAMAGE 1 +#define TRACK_WAIT 1 +#define ANIMATION_WAIT 1 +#define RECOIL_VELOCITY WORLD_TO_VELOCITY (DISPLAY_TO_WORLD (10)) +#define MAX_RECOIL_VELOCITY (RECOIL_VELOCITY * 4) +#define MAX_SENTINELS 4 +#define SPECIAL_ENERGY_COST 3 + /* Used for samatra_desc.special_energy_cost, but the value isn't + * actually used. */ + +// Blue force field +#define GATE_DAMAGE 1 +#define GATE_HITS 100 + +// Red generators +#define GENERATOR_HITS 15 +#define MAX_GENERATORS 8 static RACE_DESC samatra_desc = { @@ -153,8 +186,6 @@ comet_preprocess (ELEMENT *ElementPtr) ElementPtr->state_flags |= CHANGING; } -#define COMET_DAMAGE 2 - static void comet_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) @@ -199,10 +230,6 @@ comet_collision (ELEMENT *ElementPtr0, POINT *pPt0, static HELEMENT spawn_comet (ELEMENT *ElementPtr) { -#define COMET_OFFSET 0 -#define COMET_HITS 12 -#define COMET_SPEED DISPLAY_TO_WORLD (12) -#define COMET_LIFE 2 MISSILE_BLOCK MissileBlock; HELEMENT hComet; STARSHIP *StarShipPtr; @@ -258,12 +285,11 @@ spawn_comet (ELEMENT *ElementPtr) --CometPtr->turn_wait; else { -#define COMET_WAIT 3 facing = NORMALIZE_FACING (facing); if (TrackShip (CometPtr, &facing) > 0) SetVelocityVector (&CometPtr->velocity, COMET_SPEED, facing); - CometPtr->turn_wait = COMET_WAIT; + CometPtr->turn_wait = COMET_TURN_WAIT; } } UnlockElement (hComet); @@ -279,7 +305,6 @@ turret_preprocess (ELEMENT *ElementPtr) --ElementPtr->turn_wait; else { -#define TURRET_WAIT 0 ElementPtr->next.image.frame = SetAbsFrameIndex (ElementPtr->current.image.frame, (GetFrameIndex (ElementPtr->current.image.frame) % 10) + 1); @@ -289,9 +314,6 @@ turret_preprocess (ELEMENT *ElementPtr) } } -#define GATE_DAMAGE 1 -#define GATE_HITS 100 - static void gate_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) @@ -413,8 +435,6 @@ generator_death (ELEMENT *ElementPtr) } } -#define GENERATOR_HITS 15 - static void generator_preprocess (ELEMENT *ElementPtr) { @@ -443,8 +463,6 @@ generator_collision (ELEMENT *ElementPtr0, POINT *pPt0, (void) pPt1; /* Satisfying compiler (unused parameter) */ } -#define TRACK_WAIT 1 - static void sentinel_preprocess (ELEMENT *ElementPtr) { @@ -458,7 +476,6 @@ sentinel_preprocess (ELEMENT *ElementPtr) --ElementPtr->thrust_wait; else { -#define ANIMATION_WAIT 1 ElementPtr->next.image.frame = SetAbsFrameIndex (ElementPtr->current.image.frame, (GetFrameIndex (ElementPtr->current.image.frame) + 1) % 6); @@ -483,7 +500,7 @@ sentinel_preprocess (ELEMENT *ElementPtr) ElementPtr->state_flags &= ~NONSOLID; facing = (COUNT)TFB_Random (); SetVelocityVector (&ElementPtr->velocity, - MISSILE_SPEED, facing); + SENTINEL_SPEED, facing); } facing = NORMALIZE_FACING (facing); if (ElementPtr->hTarget == 0) @@ -577,16 +594,13 @@ sentinel_preprocess (ELEMENT *ElementPtr) } SetVelocityVector (&ElementPtr->velocity, - MISSILE_SPEED, facing); + SENTINEL_SPEED, facing); } ElementPtr->turn_wait = TRACK_WAIT; } } -#define RECOIL_VELOCITY WORLD_TO_VELOCITY (DISPLAY_TO_WORLD (10)) -#define MAX_RECOIL_VELOCITY (RECOIL_VELOCITY * 4) - static void sentinel_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) @@ -604,8 +618,8 @@ sentinel_collision (ELEMENT *ElementPtr0, POINT *pPt0, angle = ARCTAN (pPt0->x - pPt1->x, pPt0->y - pPt1->y); SetVelocityComponents (&ElementPtr0->velocity, - COSINE (angle, WORLD_TO_VELOCITY (MISSILE_SPEED)), - SINE (angle, WORLD_TO_VELOCITY (MISSILE_SPEED))); + COSINE (angle, WORLD_TO_VELOCITY (SENTINEL_SPEED)), + SINE (angle, WORLD_TO_VELOCITY (SENTINEL_SPEED))); ElementPtr0->turn_wait = TRACK_WAIT; ElementPtr0->state_flags |= COLLISION | DEFY_PHYSICS; } @@ -688,9 +702,6 @@ samatra_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); } -#define MAX_COMETS 3 -#define MAX_SENTINELS 4 - static void samatra_postprocess (ELEMENT *ElementPtr) { @@ -709,10 +720,6 @@ samatra_postprocess (ELEMENT *ElementPtr) if (StarShipPtr->special_counter == 0 && StarShipPtr->RaceDescPtr->characteristics.special_wait < MAX_SENTINELS) { -#define MISSILE_LIFE 2 -#define MISSILE_OFFSET 0 -#define MISSILE_HITS 10 -#define MISSILE_DAMAGE 1 MISSILE_BLOCK MissileBlock; HELEMENT hSentinel; @@ -724,12 +731,12 @@ samatra_postprocess (ELEMENT *ElementPtr) MissileBlock.sender = ElementPtr->playerNr; MissileBlock.flags = 0; MissileBlock.pixoffs = 0; - MissileBlock.speed = MISSILE_SPEED; - MissileBlock.hit_points = MISSILE_HITS; - MissileBlock.damage = MISSILE_DAMAGE; - MissileBlock.life = MISSILE_LIFE; + MissileBlock.speed = SENTINEL_SPEED; + MissileBlock.hit_points = SENTINEL_HITS; + MissileBlock.damage = SENTINEL_DAMAGE; + MissileBlock.life = SENTINEL_LIFE; MissileBlock.preprocess_func = sentinel_preprocess; - MissileBlock.blast_offs = MISSILE_OFFSET; + MissileBlock.blast_offs = SENTINEL_OFFSET; hSentinel = initialize_missile (&MissileBlock); if (hSentinel) @@ -765,7 +772,6 @@ samatra_preprocess (ELEMENT *ElementPtr) } else { -#define MAX_GENERATORS 8 POINT offs[] = { {-127-9, -53+18}, diff --git a/sc2/src/uqm/ships/melnorme/melnorme.c b/sc2/src/uqm/ships/melnorme/melnorme.c index 404722592..8e5ab2b8d 100644 --- a/sc2/src/uqm/ships/melnorme/melnorme.c +++ b/sc2/src/uqm/ships/melnorme/melnorme.c @@ -23,23 +23,38 @@ #include "uqm/globdata.h" #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 20 #define MAX_ENERGY MAX_ENERGY_SIZE #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 5 -#define SPECIAL_ENERGY_COST 20 #define ENERGY_WAIT 4 #define MAX_THRUST 36 #define THRUST_INCREMENT 6 -#define TURN_WAIT 4 #define THRUST_WAIT 4 -#define WEAPON_WAIT 1 -#define SPECIAL_WAIT 20 - +#define TURN_WAIT 4 #define SHIP_MASS 7 + +// Blaster Pulse +#define WEAPON_ENERGY_COST 5 +#define WEAPON_WAIT 1 +#define MELNORME_OFFSET 24 +#define LEVEL_COUNTER 72 +#define MAX_PUMP 4 #define PUMPUP_SPEED DISPLAY_TO_WORLD (45) #define PUMPUP_LIFE 10 +#define PUMPUP_DAMAGE 2 +#define MIN_PUMPITUDE_ANIMS 3 +#define NUM_PUMP_ANIMS 5 +#define REVERSE_DIR (BYTE)(1 << 7) + +// Confusion Pulse +#define SPECIAL_ENERGY_COST 20 +#define SPECIAL_WAIT 20 +#define CMISSILE_SPEED DISPLAY_TO_WORLD (30) +#define CMISSILE_LIFE 20 +#define CMISSILE_HITS 200 +#define CMISSILE_DAMAGE 0 +#define CMISSILE_OFFSET 4 static RACE_DESC melnorme_desc = { @@ -112,9 +127,6 @@ static RACE_DESC melnorme_desc = 0, /* CodeRef */ }; -#define NUM_PUMP_ANIMS 5 -#define REVERSE_DIR (BYTE)(1 << 7) - static void pump_up_preprocess (ELEMENT *ElementPtr) { @@ -146,11 +158,6 @@ pump_up_preprocess (ELEMENT *ElementPtr) static COUNT initialize_pump_up (ELEMENT *ShipPtr, HELEMENT PumpUpArray[]); -#define MELNORME_OFFSET 24 -#define LEVEL_COUNTER 72 -#define MAX_PUMP 4 -#define PUMPUP_DAMAGE 2 - static void pump_up_postprocess (ELEMENT *ElementPtr) { @@ -282,7 +289,6 @@ pump_up_collision (ELEMENT *ElementPtr0, POINT *pPt0, { ELEMENT *BlastElementPtr; -#define MIN_PUMPITUDE_ANIMS 3 LockElement (hBlastElement, &BlastElementPtr); BlastElementPtr->life_span = @@ -474,11 +480,6 @@ confusion_collision (ELEMENT *ElementPtr0, POINT *pPt0, static COUNT initialize_confusion (ELEMENT *ShipPtr, HELEMENT ConfusionArray[]) { -#define CMISSILE_SPEED DISPLAY_TO_WORLD (30) -#define CMISSILE_HITS 200 -#define CMISSILE_DAMAGE 0 -#define CMISSILE_LIFE 20 -#define CMISSILE_OFFSET 4 STARSHIP *StarShipPtr; MISSILE_BLOCK ConfusionBlock; diff --git a/sc2/src/uqm/ships/mmrnmhrm/mmrnmhrm.c b/sc2/src/uqm/ships/mmrnmhrm/mmrnmhrm.c index bc5ed0d60..e8f8348e1 100644 --- a/sc2/src/uqm/ships/mmrnmhrm/mmrnmhrm.c +++ b/sc2/src/uqm/ships/mmrnmhrm/mmrnmhrm.c @@ -20,35 +20,51 @@ #include "mmrnmhrm.h" #include "resinst.h" - +// Core characteristics #define MAX_CREW 20 #define MAX_ENERGY 10 +#define SHIP_MASS 3 + +// X-Wing characteristics #define ENERGY_REGENERATION 2 -#define WEAPON_ENERGY_COST 1 -#define SPECIAL_ENERGY_COST MAX_ENERGY #define ENERGY_WAIT 6 #define MAX_THRUST 20 #define THRUST_INCREMENT 5 -#define TURN_WAIT 2 #define THRUST_WAIT 1 -#define WEAPON_WAIT 0 -#define SPECIAL_WAIT 0 +#define TURN_WAIT 2 +// Y-Wing characteristics #define YWING_ENERGY_REGENERATION 1 -#define YWING_WEAPON_ENERGY_COST 1 #define YWING_SPECIAL_ENERGY_COST MAX_ENERGY #define YWING_ENERGY_WAIT 6 #define YWING_MAX_THRUST 50 #define YWING_THRUST_INCREMENT 10 -#define YWING_TURN_WAIT 14 #define YWING_THRUST_WAIT 0 -#define YWING_WEAPON_WAIT 20 -#define YWING_SPECIAL_WAIT 0 +#define YWING_TURN_WAIT 14 -#define SHIP_MASS 3 +// X-Wing Lasers #define MMRNMHRM_OFFSET 16 +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 0 +#define CENTER_OFFS DISPLAY_TO_WORLD (4) +#define WING_OFFS DISPLAY_TO_WORLD (10) #define LASER_RANGE DISPLAY_TO_WORLD (125 + MMRNMHRM_OFFSET) +// Y-Wing Missiles +#define YWING_WEAPON_ENERGY_COST 1 +#define YWING_WEAPON_WAIT 20 +#define LAUNCH_OFFS DISPLAY_TO_WORLD (4) +#define MISSILE_OFFSET 0 +#define MISSILE_SPEED DISPLAY_TO_WORLD (20) +#define MISSILE_LIFE 40 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 +#define TRACK_WAIT 5 + +// Transform +#define SPECIAL_ENERGY_COST MAX_ENERGY +#define SPECIAL_WAIT 0 +#define YWING_SPECIAL_WAIT 0 static RACE_DESC mmrnmhrm_desc = { @@ -121,9 +137,6 @@ static RACE_DESC mmrnmhrm_desc = 0, /* CodeRef */ }; -#define MISSILE_SPEED DISPLAY_TO_WORLD (20) -#define TRACK_WAIT 5 - // Private per-instance ship data typedef CHARACTERISTIC_STUFF MMRNMHRM_DATA; @@ -288,7 +301,6 @@ twin_laser_collision (ELEMENT *ElementPtr0, POINT *pPt0, static COUNT initialize_dual_weapons (ELEMENT *ShipPtr, HELEMENT WeaponArray[]) { -#define CENTER_OFFS DISPLAY_TO_WORLD (4) COORD cx, cy; COUNT facing, angle; SIZE offs_x, offs_y; @@ -302,7 +314,6 @@ initialize_dual_weapons (ELEMENT *ShipPtr, HELEMENT WeaponArray[]) if (ShipPtr->next.image.farray == StarShipPtr->RaceDescPtr->ship_data.ship) { -#define WING_OFFS DISPLAY_TO_WORLD (10) COORD ex, ey; LASER_BLOCK LaserBlock; ELEMENT *LaserPtr; @@ -342,11 +353,6 @@ initialize_dual_weapons (ELEMENT *ShipPtr, HELEMENT WeaponArray[]) } else { -#define MISSILE_HITS 1 -#define MISSILE_DAMAGE 1 -#define MISSILE_OFFSET 0 -#define MISSILE_LIFE 40 -#define LAUNCH_OFFS DISPLAY_TO_WORLD (4) MISSILE_BLOCK TorpBlock; ELEMENT *TorpPtr; diff --git a/sc2/src/uqm/ships/mycon/mycon.c b/sc2/src/uqm/ships/mycon/mycon.c index dcad5667a..8c99fbef5 100644 --- a/sc2/src/uqm/ships/mycon/mycon.c +++ b/sc2/src/uqm/ships/mycon/mycon.c @@ -20,26 +20,34 @@ #include "mycon.h" #include "resinst.h" +// Core characteristics #define MAX_CREW 20 #define MAX_ENERGY 40 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 20 -#define SPECIAL_ENERGY_COST MAX_ENERGY #define ENERGY_WAIT 4 #define MAX_THRUST /* DISPLAY_TO_WORLD (7) */ 27 #define THRUST_INCREMENT /* DISPLAY_TO_WORLD (2) */ 9 -#define TURN_WAIT 6 #define THRUST_WAIT 6 -#define WEAPON_WAIT 5 -#define SPECIAL_WAIT 0 - +#define TURN_WAIT 6 #define SHIP_MASS 7 +// Plasmoid +#define WEAPON_ENERGY_COST 20 +#define WEAPON_WAIT 5 +#define MYCON_OFFSET 24 +#define MISSILE_OFFSET 0 #define NUM_PLASMAS 11 #define NUM_GLOBALLS 8 #define PLASMA_DURATION 13 #define MISSILE_LIFE (NUM_PLASMAS * PLASMA_DURATION) #define MISSILE_SPEED DISPLAY_TO_WORLD (8) +#define MISSILE_DAMAGE 10 +#define TRACK_WAIT 1 + +// Regenerate +#define SPECIAL_ENERGY_COST MAX_ENERGY +#define SPECIAL_WAIT 0 +#define REGENERATION_AMOUNT 4 static RACE_DESC mycon_desc = { @@ -112,10 +120,6 @@ static RACE_DESC mycon_desc = 0, /* CodeRef */ }; -#define MISSILE_DAMAGE 10 - -#define TRACK_WAIT 1 - static void plasma_preprocess (ELEMENT *ElementPtr) { @@ -297,8 +301,6 @@ mycon_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, static COUNT initialize_plasma (ELEMENT *ShipPtr, HELEMENT PlasmaArray[]) { -#define MYCON_OFFSET 24 -#define MISSILE_OFFSET 0 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -343,7 +345,6 @@ mycon_postprocess (ELEMENT *ElementPtr) && ElementPtr->crew_level != StarShipPtr->RaceDescPtr->ship_info.max_crew && DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) { -#define REGENERATION_AMOUNT 4 SIZE add_crew; ProcessSound (SetAbsSoundIndex ( diff --git a/sc2/src/uqm/ships/orz/orz.c b/sc2/src/uqm/ships/orz/orz.c index 78bb39c16..1a95fec25 100644 --- a/sc2/src/uqm/ships/orz/orz.c +++ b/sc2/src/uqm/ships/orz/orz.c @@ -24,24 +24,42 @@ #include "uqm/globdata.h" #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 16 #define MAX_ENERGY 20 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST (MAX_ENERGY / 3) -#define SPECIAL_ENERGY_COST 0 #define ENERGY_WAIT 6 #define MAX_THRUST 35 #define THRUST_INCREMENT 5 -#define TURN_WAIT 1 #define THRUST_WAIT 0 -#define WEAPON_WAIT 4 -#define SPECIAL_WAIT 12 - +#define TURN_WAIT 1 #define SHIP_MASS 4 + +// Howitzer +#define WEAPON_ENERGY_COST (MAX_ENERGY / 3) +#define WEAPON_WAIT 4 #define ORZ_OFFSET 9 #define MISSILE_SPEED DISPLAY_TO_WORLD (30) #define MISSILE_LIFE 12 +#define MISSILE_HITS 2 +#define MISSILE_DAMAGE 3 +#define MISSILE_OFFSET 1 + +// Marine +#define SPECIAL_ENERGY_COST 0 +#define SPECIAL_WAIT 12 +#define MARINE_MAX_THRUST 32 +#define MARINE_THRUST_INCREMENT 8 +#define MARINE_HIT_POINTS 3 +#define MARINE_MASS_POINTS 1 +#define MAX_MARINES 8 +#define MARINE_WAIT 12 +#define ION_LIFE 1 +#define START_ION_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x15, 0x00), 0x7A) + +// Rotating Turret +#define TURRET_OFFSET 14 +#define TURRET_WAIT 3 static RACE_DESC orz_desc = { @@ -122,15 +140,9 @@ howitzer_collision (ELEMENT *ElementPtr0, POINT *pPt0, weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); } -#define TURRET_OFFSET 14 -#define TURRET_WAIT 3 - static COUNT initialize_turret_missile (ELEMENT *ShipPtr, HELEMENT MissileArray[]) { -#define MISSILE_HITS 2 -#define MISSILE_DAMAGE 3 -#define MISSILE_OFFSET 1 ELEMENT *TurretPtr; STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -180,8 +192,6 @@ initialize_turret_missile (ELEMENT *ShipPtr, HELEMENT MissileArray[]) return (1); } -#define MAX_MARINES 8 - static BYTE count_marines (STARSHIP *StarShipPtr, BOOLEAN FindSpot) { @@ -310,8 +320,6 @@ orz_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, UnlockElement (GetSuccElement (ShipPtr)); } -#define START_ION_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x15, 0x00), 0x7A) - static void ion_preprocess (ELEMENT *ElementPtr) { @@ -352,8 +360,6 @@ ion_preprocess (ELEMENT *ElementPtr) static void marine_preprocess (ELEMENT *ElementPtr); -#define MARINE_WAIT 12 - void intruder_preprocess (ELEMENT *ElementPtr) { @@ -475,7 +481,6 @@ spawn_marine_ion_trail (ELEMENT *ElementPtr, STARSHIP *StarShipPtr, hIonElement = AllocElement (); if (hIonElement) { -#define ION_LIFE 1 COUNT angle; ELEMENT *IonElementPtr; @@ -698,8 +703,10 @@ marine_preprocess (ELEMENT *ElementPtr) // XXX: thrust_wait is abused to store marine speed and // gravity well flags StarShipPtr->cur_status_flags = ElementPtr->thrust_wait << 6; - StarShipPtr->RaceDescPtr->characteristics.thrust_increment = 8; - StarShipPtr->RaceDescPtr->characteristics.max_thrust = 32; + StarShipPtr->RaceDescPtr->characteristics.thrust_increment = + MARINE_THRUST_INCREMENT; + StarShipPtr->RaceDescPtr->characteristics.max_thrust = + MARINE_MAX_THRUST; thrust_status = inertial_thrust (ElementPtr); @@ -965,8 +972,8 @@ turret_postprocess (ELEMENT *ElementPtr) SpaceMarinePtr->state_flags = IGNORE_SIMILAR | APPEARING | CREW_OBJECT; SpaceMarinePtr->life_span = NORMAL_LIFE; - SpaceMarinePtr->hit_points = 3; - SpaceMarinePtr->mass_points = 1; + SpaceMarinePtr->hit_points = MARINE_HIT_POINTS; + SpaceMarinePtr->mass_points = MARINE_MASS_POINTS; facing = FACING_TO_ANGLE (StarShipPtr->ShipFacing); SpaceMarinePtr->current.location.x = diff --git a/sc2/src/uqm/ships/pkunk/pkunk.c b/sc2/src/uqm/ships/pkunk/pkunk.c index 6e8902e07..76f8413f8 100644 --- a/sc2/src/uqm/ships/pkunk/pkunk.c +++ b/sc2/src/uqm/ships/pkunk/pkunk.c @@ -24,23 +24,36 @@ #include "uqm/tactrans.h" #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 8 #define MAX_ENERGY 12 #define ENERGY_REGENERATION 0 -#define WEAPON_ENERGY_COST 1 -#define SPECIAL_ENERGY_COST 2 #define ENERGY_WAIT 0 #define MAX_THRUST 64 #define THRUST_INCREMENT 16 -#define TURN_WAIT 0 #define THRUST_WAIT 0 -#define WEAPON_WAIT 0 -#define SPECIAL_WAIT 16 - +#define TURN_WAIT 0 #define SHIP_MASS 1 + +// Triple Miniguns +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 0 +#define PKUNK_OFFSET 15 +#define MISSILE_OFFSET 1 #define MISSILE_SPEED DISPLAY_TO_WORLD (24) #define MISSILE_LIFE 5 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 + +// Taunt +#define SPECIAL_ENERGY_COST 2 +#define SPECIAL_WAIT 16 + +// Respawn +#define PHOENIX_LIFE 12 +#define START_PHOENIX_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x15, 0x00), 0x7A) +#define TRANSITION_LIFE 1 +#define TRANSITION_SPEED DISPLAY_TO_WORLD (20) static RACE_DESC pkunk_desc = { @@ -173,10 +186,6 @@ animate (ELEMENT *ElementPtr) static COUNT initialize_bug_missile (ELEMENT *ShipPtr, HELEMENT MissileArray[]) { -#define PKUNK_OFFSET 15 -#define MISSILE_HITS 1 -#define MISSILE_DAMAGE 1 -#define MISSILE_OFFSET 1 COUNT i; STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -363,9 +372,6 @@ intercept_pkunk_death (ELEMENT *ElementPtr) UnlockElement (StarShipPtr->hShip); } -#define START_PHOENIX_COLOR BUILD_COLOR (MAKE_RGB15 (0x1F, 0x15, 0x00), 0x7A) -#define TRANSITION_LIFE 1 - static void spawn_phoenix_trail (ELEMENT *ElementPtr) { @@ -399,8 +405,6 @@ spawn_phoenix_trail (ELEMENT *ElementPtr) } // else, the element disappears. } -#define PHOENIX_LIFE 12 - static void phoenix_transition (ELEMENT *ElementPtr) { @@ -417,7 +421,6 @@ phoenix_transition (ELEMENT *ElementPtr) } else if ((hShipImage = AllocElement ())) { -#define TRANSITION_SPEED DISPLAY_TO_WORLD (20) COUNT angle; PutElement (hShipImage); diff --git a/sc2/src/uqm/ships/shofixti/shofixti.c b/sc2/src/uqm/ships/shofixti/shofixti.c index 454a29c7a..03de57e77 100644 --- a/sc2/src/uqm/ships/shofixti/shofixti.c +++ b/sc2/src/uqm/ships/shofixti/shofixti.c @@ -24,12 +24,10 @@ #include "uqm/tactrans.h" #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 6 #define MAX_ENERGY 4 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 1 -#define SPECIAL_ENERGY_COST 0 #define ENERGY_WAIT 9 #define MAX_THRUST 35 #define THRUST_INCREMENT 5 @@ -37,10 +35,24 @@ #define THRUST_WAIT 0 #define WEAPON_WAIT 3 #define SPECIAL_WAIT 0 - #define SHIP_MASS 1 + +// Dart Gun +#define WEAPON_ENERGY_COST 1 +#define SHOFIXTI_OFFSET 15 +#define MISSILE_OFFSET 1 #define MISSILE_SPEED DISPLAY_TO_WORLD (24) #define MISSILE_LIFE 10 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 + +// Glory Device +#define SPECIAL_ENERGY_COST 0 +#define DESTRUCT_RANGE 180 +#define MAX_DESTRUCTION (DESTRUCT_RANGE / 10) + +// Full game: Tanaka/Katana's damaged ships +#define NUM_LIMPETS 3 static RACE_DESC shofixti_desc = { @@ -116,10 +128,7 @@ static RACE_DESC shofixti_desc = static COUNT initialize_standard_missile (ELEMENT *ShipPtr, HELEMENT MissileArray[]) { -#define SHOFIXTI_OFFSET 15 -#define MISSILE_HITS 1 -#define MISSILE_DAMAGE 1 -#define MISSILE_OFFSET 1 + STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -266,7 +275,6 @@ self_destruct_kill_objects (ELEMENT *ElementPtr) continue; } -#define DESTRUCT_RANGE 180 delta_x = ObjPtr->next.location.x - ElementPtr->next.location.x; if (delta_x < 0) delta_x = -delta_x; @@ -279,7 +287,6 @@ self_destruct_kill_objects (ELEMENT *ElementPtr) if (delta_x <= DESTRUCT_RANGE && delta_y <= DESTRUCT_RANGE && dist <= DESTRUCT_RANGE * DESTRUCT_RANGE) { -#define MAX_DESTRUCTION (DESTRUCT_RANGE / 10) int destruction = 1 + MAX_DESTRUCTION * (DESTRUCT_RANGE - square_root (dist)) / DESTRUCT_RANGE; @@ -462,7 +469,6 @@ init_shofixti (void) && !GET_GAME_STATE (SHOFIXTI_RECRUITED)) { // Tanaka/Katana flies in a damaged ship. -#define NUM_LIMPETS 3 COUNT i; new_shofixti_desc.ship_data.ship_rsc[0] = OLDSHOF_BIG_MASK_PMAP_ANIM; @@ -484,7 +490,10 @@ init_shofixti (void) --new_shofixti_desc.characteristics.turn_wait; if (++new_shofixti_desc.characteristics.thrust_wait == 0) --new_shofixti_desc.characteristics.thrust_wait; + +/* This should be the same as MIN_THRUST_INCREMENT in vux.c */ #define MIN_THRUST_INCREMENT DISPLAY_TO_WORLD (1) + if (new_shofixti_desc.characteristics.thrust_increment <= MIN_THRUST_INCREMENT) { diff --git a/sc2/src/uqm/ships/sis_ship/sis_ship.c b/sc2/src/uqm/ships/sis_ship/sis_ship.c index 0553ef3e5..d5898277a 100644 --- a/sc2/src/uqm/ships/sis_ship/sis_ship.c +++ b/sc2/src/uqm/ships/sis_ship/sis_ship.c @@ -26,27 +26,73 @@ #include "uqm/hyper.h" #include "libs/mathlib.h" - -#define MAX_TRACKING 3 -#define MAX_DEFENSE 8 +/* Core characteristics. + * All of these are changed at init time by some module, except for + * MAX_ENERGY, THRUST_INCREMENT, and SHIP_MASS. */ #define MAX_CREW MAX_CREW_SIZE + /* This value gets thrown out - actual max crew is determined by the + * number of crew pods. The minimum value is 1 (just the Captain). */ + #define MAX_ENERGY MAX_ENERGY_SIZE #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 1 -#define SPECIAL_ENERGY_COST 0 -#define ENERGY_WAIT 10 -#define MAX_THRUST 10 -#define THRUST_INCREMENT 4 -#define TURN_WAIT 17 -#define THRUST_WAIT 6 -#define WEAPON_WAIT 6 -#define SPECIAL_WAIT 9 + /* Shiva furnaces increase this by 1 each. */ +#define SHIVA_ENERGY_REGEN_INC 1 +#define ENERGY_WAIT 10 + /* Dynamos decrease this by 2 each, to a minimum of 4. */ +#define MIN_ENERGY_WAIT 4 +#define DYNAMO_UNIT_ENERGY_WAIT_DEC 2 + +#define MAX_THRUST 10 + /* Thrusters increase this and decrease THRUST_WAIT based on + * THRUST_INCREMENT, see InitDriveSlots near the bottom of this file + * for details. */ +#define THRUST_INCREMENT 4 +#define THRUST_WAIT 6 +#define TURN_WAIT 17 + /* Turning jets decrease by 2 each */ #define SHIP_MASS MAX_SHIP_MASS + +/* Primary weapon - energy cost and damage change at init time based on + * the number and type of weapon modules installed. */ + +#define BLASTER_DAMAGE 2 + /* This is the damage value for the basic ion bolt guns. Fusion + * blasters and hellbore cannons end up doing (BLASTER_DAMAGE * 2) + * and (BLASTER_DAMAGE * 3) damage, respectively, but this depends + * on enum values. */ + +#define BLASTER_HITS 2 /* Hitpoints for ion bolt guns, see BLASTER_DAMAGE */ + +#define WEAPON_ENERGY_COST 1 + /* This value gets thrown out and reset in an ugly manner based on + * the enum that is used for module IDs. Bigger gun = higher value. + */ +#define WEAPON_WAIT 6 #define BLASTER_SPEED DISPLAY_TO_WORLD (24) #define BLASTER_LIFE 12 + /* This value is greatly increased, based in part on the enum used + * for module IDs (bigger gun == longer life). See the first half of + * InitWeaponSlots */ +#define MAX_TRACKING 3 +#define TRACKER_ENERGY_COST 3 +#define BLASTER_OFFSET 8 +#define SIS_VERT_OFFSET 28 + /* Used for foward, spread, and rear slots */ +#define SIS_HORZ_OFFSET 20 + /* Used for side slot */ + + +/* Secondary weapon */ +#define SPECIAL_ENERGY_COST 0 + /* Increased by 1 for each point defense module */ +#define ANTIMISSILE_ENERGY_INC 1 +#define SPECIAL_WAIT 9 +#define LASER_RANGE (UWORD)100 +#define MAX_DEFENSE 8 + static RACE_DESC sis_desc = { @@ -404,7 +450,6 @@ spawn_point_defense (ELEMENT *ElementPtr) if (ObjectPtr != ShipPtr && CollidingElement (ObjectPtr) && !OBJECT_CLOAKED (ObjectPtr)) { -#define LASER_RANGE (UWORD)100 SIZE delta_x, delta_y; delta_x = ObjectPtr->next.location.x - @@ -507,8 +552,6 @@ sis_battle_postprocess (ELEMENT *ElementPtr) } } -#define BLASTER_DAMAGE 2 - static void blaster_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) @@ -588,10 +631,6 @@ blaster_preprocess (ELEMENT *ElementPtr) static COUNT initialize_blasters (ELEMENT *ShipPtr, HELEMENT BlasterArray[]) { -#define SIS_VERT_OFFSET 28 -#define SIS_HORZ_OFFSET 20 -#define BLASTER_HITS 2 -#define BLASTER_OFFSET 8 BYTE nt; COUNT i; STARSHIP *StarShipPtr; @@ -707,10 +746,6 @@ sis_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, static void InitWeaponSlots (RACE_DESC *RaceDescPtr, const BYTE *ModuleSlots) { -#define SIS_VERT_OFFSET 28 -#define SIS_HORZ_OFFSET 20 -#define BLASTER_HITS 2 -#define BLASTER_OFFSET 8 COUNT i; SIS_DATA *SisData = GetCustomShipData (RaceDescPtr); MISSILE_BLOCK *lpMB = SisData->MissileBlock; @@ -810,22 +845,26 @@ InitModuleSlots (RACE_DESC *RaceDescPtr, const BYTE *ModuleSlots) ++num_trackers; break; case ANTIMISSILE_DEFENSE: - ++RaceDescPtr->characteristics.special_energy_cost; + RaceDescPtr->characteristics.special_energy_cost += + ANTIMISSILE_ENERGY_INC; break; case SHIVA_FURNACE: - ++RaceDescPtr->characteristics.energy_regeneration; + RaceDescPtr->characteristics.energy_regeneration += + SHIVA_ENERGY_REGEN_INC; break; case DYNAMO_UNIT: - RaceDescPtr->characteristics.energy_wait -= 2; - if (RaceDescPtr->characteristics.energy_wait < 4) - RaceDescPtr->characteristics.energy_wait = 4; + RaceDescPtr->characteristics.energy_wait -= + DYNAMO_UNIT_ENERGY_WAIT_DEC; + if (RaceDescPtr->characteristics.energy_wait < MIN_ENERGY_WAIT) + RaceDescPtr->characteristics.energy_wait = MIN_ENERGY_WAIT; break; } } if (num_trackers > MAX_TRACKING) num_trackers = MAX_TRACKING; - RaceDescPtr->characteristics.weapon_energy_cost += num_trackers * 3; + RaceDescPtr->characteristics.weapon_energy_cost += + num_trackers * TRACKER_ENERGY_COST; SisData->num_trackers = num_trackers; if (RaceDescPtr->characteristics.special_energy_cost) { diff --git a/sc2/src/uqm/ships/slylandr/slylandr.c b/sc2/src/uqm/ships/slylandr/slylandr.c index 729700876..8c4ca95a2 100644 --- a/sc2/src/uqm/ships/slylandr/slylandr.c +++ b/sc2/src/uqm/ships/slylandr/slylandr.c @@ -23,22 +23,30 @@ #include "uqm/globdata.h" #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 12 #define MAX_ENERGY 20 #define ENERGY_REGENERATION 0 -#define WEAPON_ENERGY_COST 2 -#define SPECIAL_ENERGY_COST 0 #define ENERGY_WAIT 10 #define MAX_THRUST 60 #define THRUST_INCREMENT MAX_THRUST -#define TURN_WAIT 0 #define THRUST_WAIT 0 -#define WEAPON_WAIT 17 -#define SPECIAL_WAIT 20 - +#define TURN_WAIT 0 #define SHIP_MASS 1 + +// Lightning weapon +#define WEAPON_ENERGY_COST 2 +#define WEAPON_WAIT 17 #define SLYLANDRO_OFFSET 9 +#define LASER_LENGTH 32 + /* Total length of lighting bolts. Actual range is usually less than + * this, since the lightning rarely is straight. */ + +// Harvester +#define SPECIAL_ENERGY_COST 0 +#define SPECIAL_WAIT 20 +#define HARVEST_RANGE (208 * 3 / 8) + /* Was originally (SPACE_HEIGHT * 3 / 8) */ static RACE_DESC slylandro_desc = { @@ -238,9 +246,8 @@ initialize_lightning (ELEMENT *ElementPtr, HELEMENT LaserArray[]) angle += LOWORD (rand_val) & (QUADRANT - 1); else angle -= LOWORD (rand_val) & (QUADRANT - 1); -#define LASER_RANGE 32 delta = WORLD_TO_VELOCITY ( - DISPLAY_TO_WORLD ((HIWORD (rand_val) & (LASER_RANGE - 1)) + 4) + DISPLAY_TO_WORLD ((HIWORD (rand_val) & (LASER_LENGTH - 1)) + 4) ); SetVelocityComponents (&LaserPtr->velocity, COSINE (angle, delta), SINE (angle, delta)); @@ -313,8 +320,6 @@ harvest_space_junk (ELEMENT *ElementPtr) && !GRAVITY_MASS (ObjPtr->mass_points) && CollisionPossible (ObjPtr, ElementPtr)) { -//HARVEST_RANGE was originally (SPACE_HEIGHT * 3 / 8) -#define HARVEST_RANGE (208 * 3 / 8) SIZE dx, dy; if ((dx = ObjPtr->next.location.x diff --git a/sc2/src/uqm/ships/spathi/spathi.c b/sc2/src/uqm/ships/spathi/spathi.c index f1f7243cf..aa4bd00ed 100644 --- a/sc2/src/uqm/ships/spathi/spathi.c +++ b/sc2/src/uqm/ships/spathi/spathi.c @@ -20,23 +20,39 @@ #include "spathi.h" #include "resinst.h" +// Core characteristics #define MAX_CREW 30 #define MAX_ENERGY 10 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 2 -#define SPECIAL_ENERGY_COST 3 #define ENERGY_WAIT 10 #define MAX_THRUST 48 #define THRUST_INCREMENT 12 -#define TURN_WAIT 1 #define THRUST_WAIT 1 -#define WEAPON_WAIT 0 -#define SPECIAL_WAIT 7 - +#define TURN_WAIT 1 #define SHIP_MASS 5 + +// Forward gun +#define WEAPON_ENERGY_COST 2 +#define WEAPON_WAIT 0 +#define SPATHI_FORWARD_OFFSET 16 #define MISSILE_SPEED DISPLAY_TO_WORLD (30) #define MISSILE_LIFE 10 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 +#define MISSILE_OFFSET 1 #define MISSILE_RANGE (MISSILE_SPEED * MISSILE_LIFE) + /* This is for the cyborg only. */ + +// B.U.T.T. +#define SPECIAL_ENERGY_COST 3 +#define SPECIAL_WAIT 7 +#define SPATHI_REAR_OFFSET 20 +#define DISCRIMINATOR_SPEED DISPLAY_TO_WORLD (8) +#define DISCRIMINATOR_LIFE 30 +#define DISCRIMINATOR_HITS 1 +#define DISCRIMINATOR_DAMAGE 2 +#define DISCRIMINATOR_OFFSET 4 +#define TRACK_WAIT 1 static RACE_DESC spathi_desc = { @@ -109,9 +125,6 @@ static RACE_DESC spathi_desc = 0, /* CodeRef */ }; -#define DISCRIMINATOR_SPEED DISPLAY_TO_WORLD (8) -#define TRACK_WAIT 1 - static void butt_missile_preprocess (ELEMENT *ElementPtr) { @@ -140,11 +153,6 @@ butt_missile_preprocess (ELEMENT *ElementPtr) static void spawn_butt_missile (ELEMENT *ShipPtr) { -#define SPATHI_REAR_OFFSET 20 -#define DISCRIMINATOR_LIFE 30 -#define DISCRIMINATOR_HITS 1 -#define DISCRIMINATOR_DAMAGE 2 -#define DISCRIMINATOR_OFFSET 4 HELEMENT ButtMissile; STARSHIP *StarShipPtr; MISSILE_BLOCK ButtMissileBlock; @@ -239,10 +247,6 @@ spathi_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, static COUNT initialize_standard_missile (ELEMENT *ShipPtr, HELEMENT MissileArray[]) { -#define SPATHI_FORWARD_OFFSET 16 -#define MISSILE_HITS 1 -#define MISSILE_DAMAGE 1 -#define MISSILE_OFFSET 1 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; diff --git a/sc2/src/uqm/ships/supox/supox.c b/sc2/src/uqm/ships/supox/supox.c index b9dd4656a..854c5b37c 100644 --- a/sc2/src/uqm/ships/supox/supox.c +++ b/sc2/src/uqm/ships/supox/supox.c @@ -22,23 +22,32 @@ #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 12 #define MAX_ENERGY 16 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 1 -#define SPECIAL_ENERGY_COST 1 #define ENERGY_WAIT 4 #define MAX_THRUST 40 #define THRUST_INCREMENT 8 -#define TURN_WAIT 1 #define THRUST_WAIT 0 -#define WEAPON_WAIT 2 -#define SPECIAL_WAIT 0 - +#define TURN_WAIT 1 #define SHIP_MASS 4 + +// Gob launcher +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 2 +#define SUPOX_OFFSET 23 +#define MISSILE_OFFSET 2 #define MISSILE_SPEED DISPLAY_TO_WORLD (30) #define MISSILE_LIFE 10 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 + +// Lateral/reverse thrust +#define SPECIAL_ENERGY_COST 1 + /* Unused - uncomment below to enable. */ +#define SPECIAL_WAIT 0 + /* Unused except to initialize supox_desc.special_wait */ static RACE_DESC supox_desc = { @@ -179,10 +188,6 @@ supox_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, static COUNT initialize_horn (ELEMENT *ShipPtr, HELEMENT HornArray[]) { -#define MISSILE_HITS 1 -#define MISSILE_DAMAGE 1 -#define MISSILE_OFFSET 2 -#define SUPOX_OFFSET 23 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; diff --git a/sc2/src/uqm/ships/syreen/syreen.c b/sc2/src/uqm/ships/syreen/syreen.c index fbcf8eb07..c65ecd204 100644 --- a/sc2/src/uqm/ships/syreen/syreen.c +++ b/sc2/src/uqm/ships/syreen/syreen.c @@ -22,24 +22,33 @@ #include "libs/mathlib.h" - +// Core characteristics #define SYREEN_MAX_CREW_SIZE MAX_CREW_SIZE #define MAX_CREW 12 #define MAX_ENERGY 16 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 1 -#define SPECIAL_ENERGY_COST 5 #define ENERGY_WAIT 6 #define MAX_THRUST /* DISPLAY_TO_WORLD (8) */ 36 #define THRUST_INCREMENT /* DISPLAY_TO_WORLD (2) */ 9 -#define TURN_WAIT 1 #define THRUST_WAIT 1 -#define WEAPON_WAIT 8 -#define SPECIAL_WAIT 20 - +#define TURN_WAIT 1 #define SHIP_MASS 2 + +// Particle Beam Stiletto +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 8 +#define SYREEN_OFFSET 30 #define MISSILE_SPEED DISPLAY_TO_WORLD (30) #define MISSILE_LIFE 10 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 2 +#define MISSILE_OFFSET 3 + +// Syreen song +#define SPECIAL_ENERGY_COST 5 +#define SPECIAL_WAIT 20 +#define ABANDONER_RANGE 208 /* originally SPACE_HEIGHT */ +#define MAX_ABANDONERS 8 static RACE_DESC syreen_desc = { @@ -115,10 +124,6 @@ static RACE_DESC syreen_desc = static COUNT initialize_dagger (ELEMENT *ShipPtr, HELEMENT DaggerArray[]) { -#define SYREEN_OFFSET 30 -#define MISSILE_HITS 1 -#define MISSILE_DAMAGE 2 -#define MISSILE_OFFSET 3 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -194,13 +199,11 @@ spawn_crew (ELEMENT *ElementPtr) dx = WORLD_TO_DISPLAY (dx); dy = WORLD_TO_DISPLAY (dy); -#define ABANDONER_RANGE 208 /* originally SPACE_HEIGHT */ if (dx <= ABANDONER_RANGE && dy <= ABANDONER_RANGE && (d_squared = (DWORD)((UWORD)dx * (UWORD)dx) + (DWORD)((UWORD)dy * (UWORD)dy)) <= (DWORD)((UWORD)ABANDONER_RANGE * (UWORD)ABANDONER_RANGE)) { -#define MAX_ABANDONERS 8 COUNT crew_loss; crew_loss = ((MAX_ABANDONERS diff --git a/sc2/src/uqm/ships/thradd/thradd.c b/sc2/src/uqm/ships/thradd/thradd.c index 3e3c3d707..0d7a8e24a 100644 --- a/sc2/src/uqm/ships/thradd/thradd.c +++ b/sc2/src/uqm/ships/thradd/thradd.c @@ -22,24 +22,42 @@ #include "uqm/globdata.h" - +// Core characteristics #define MAX_CREW 8 #define MAX_ENERGY 24 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 2 -#define SPECIAL_ENERGY_COST 1 #define ENERGY_WAIT 6 #define MAX_THRUST 28 #define THRUST_INCREMENT 7 -#define TURN_WAIT 1 #define THRUST_WAIT 0 -#define WEAPON_WAIT 12 -#define SPECIAL_WAIT 0 - +#define TURN_WAIT 1 #define SHIP_MASS 7 -#define THRADDASH_OFFSET 9 + +// Ion Blasters +#define WEAPON_ENERGY_COST 2 +#define WEAPON_WAIT 12 #define MISSILE_SPEED DISPLAY_TO_WORLD (30) #define MISSILE_LIFE 15 +#define MISSILE_OFFSET 3 +#define THRADDASH_OFFSET 9 +#define MISSILE_HITS 2 +#define MISSILE_DAMAGE 1 + +// Afterburner +#define SPECIAL_ENERGY_COST 1 +#define SPECIAL_WAIT 0 +#define SPECIAL_THRUST_INCREMENT 12 +#define SPECIAL_MAX_THRUST 72 +#define NAPALM_LIFE 48 +#define NAPALM_OFFSET 0 +#define NAPALM_HITS 1 +#define NAPALM_DAMAGE 2 +#define NAPALM_DECAY_RATE 5 + /* Controls the speed of the afterburner "decay" animation; it will + * decay one step (one animation frame) per NAPALM_DECAY_RATE + * frames. */ +#define NUM_NAPALM_FADES 6 + static RACE_DESC thraddash_desc = { @@ -202,8 +220,6 @@ thraddash_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, } } -#define NAPALM_WAIT 1 - static void flame_napalm_preprocess (ELEMENT *ElementPtr) { @@ -220,24 +236,26 @@ flame_napalm_preprocess (ELEMENT *ElementPtr) InitIntersectEndPoint (ElementPtr); InitIntersectFrame (ElementPtr); } + /* turn_wait is abused here to store the speed of the decay animation */ else if (ElementPtr->turn_wait > 0) --ElementPtr->turn_wait; else { -#define NUM_NAPALM_FADES 6 - if (ElementPtr->life_span <= NUM_NAPALM_FADES * (NAPALM_WAIT + 1) + if (ElementPtr->life_span <= NUM_NAPALM_FADES * (NAPALM_DECAY_RATE + 1) || GetFrameIndex ( ElementPtr->current.image.frame ) != NUM_NAPALM_FADES) ElementPtr->next.image.frame = DecFrameIndex (ElementPtr->current.image.frame); - else if (ElementPtr->life_span > NUM_NAPALM_FADES * (NAPALM_WAIT + 1)) + else if (ElementPtr->life_span > NUM_NAPALM_FADES * (NAPALM_DECAY_RATE + 1)) ElementPtr->next.image.frame = SetAbsFrameIndex ( ElementPtr->current.image.frame, GetFrameCount (ElementPtr->current.image.frame) - 1 ); - ElementPtr->turn_wait = NAPALM_WAIT; + /* turn_wait is abused here to store the speed of the decay + * animation. */ + ElementPtr->turn_wait = NAPALM_DECAY_RATE; ElementPtr->state_flags |= CHANGING; } } @@ -245,9 +263,6 @@ flame_napalm_preprocess (ELEMENT *ElementPtr) static COUNT initialize_horn (ELEMENT *ShipPtr, HELEMENT HornArray[]) { -#define MISSILE_HITS 2 -#define MISSILE_DAMAGE 1 -#define MISSILE_OFFSET 3 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -284,8 +299,6 @@ thraddash_preprocess (ELEMENT *ElementPtr) } else if (DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST)) { -#define SPECIAL_THRUST_INCREMENT 12 -#define SPECIAL_MAX_THRUST 72 COUNT max_thrust, thrust_increment; STATUS_FLAGS thrust_status; HELEMENT hTrailElement; @@ -317,10 +330,6 @@ thraddash_preprocess (ELEMENT *ElementPtr) StarShipPtr->RaceDescPtr->characteristics.max_thrust = max_thrust; { -#define NAPALM_HITS 1 -#define NAPALM_DAMAGE 2 -#define NAPALM_LIFE 48 -#define NAPALM_OFFSET 0 MISSILE_BLOCK MissileBlock; MissileBlock.cx = ElementPtr->next.location.x; @@ -348,7 +357,10 @@ thraddash_preprocess (ELEMENT *ElementPtr) LockElement (hTrailElement, &TrailElementPtr); SetElementStarShip (TrailElementPtr, StarShipPtr); TrailElementPtr->hTarget = 0; - TrailElementPtr->turn_wait = NAPALM_WAIT; + + /* turn_wait is abused here to store the speed of the decay + * animation */ + TrailElementPtr->turn_wait = NAPALM_DECAY_RATE; TrailElementPtr->state_flags |= NONSOLID; SetPrimType ( diff --git a/sc2/src/uqm/ships/umgah/umgah.c b/sc2/src/uqm/ships/umgah/umgah.c index 054cdfa9a..370ad4036 100644 --- a/sc2/src/uqm/ships/umgah/umgah.c +++ b/sc2/src/uqm/ships/umgah/umgah.c @@ -22,22 +22,31 @@ #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 10 #define MAX_ENERGY 30 #define ENERGY_REGENERATION MAX_ENERGY -#define WEAPON_ENERGY_COST 0 -#define SPECIAL_ENERGY_COST 1 #define ENERGY_WAIT 150 #define MAX_THRUST /* DISPLAY_TO_WORLD (5) */ 18 #define THRUST_INCREMENT /* DISPLAY_TO_WORLD (2) */ 6 -#define TURN_WAIT 4 #define THRUST_WAIT 3 -#define WEAPON_WAIT 0 -#define SPECIAL_WAIT 2 - +#define TURN_WAIT 4 #define SHIP_MASS 1 +// Antimatter cone +#define WEAPON_ENERGY_COST 0 +#define WEAPON_WAIT 0 +#define UMGAH_OFFSET 0 +#define CONE_OFFSET 0 +#define CONE_SPEED 0 +#define CONE_HITS 100 +#define CONE_DAMAGE 1 +#define CONE_LIFE 1 + +// Retropropulsion +#define SPECIAL_ENERGY_COST 1 +#define SPECIAL_WAIT 2 +#define JUMP_DIST DISPLAY_TO_WORLD (40) static RACE_DESC umgah_desc = { @@ -179,8 +188,6 @@ cone_collision (ELEMENT *ElementPtr0, POINT *pPt0, } } -#define JUMP_DIST DISPLAY_TO_WORLD (40) - static void umgah_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, COUNT ConcernCounter) @@ -299,12 +306,6 @@ umgah_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, static COUNT initialize_cone (ELEMENT *ShipPtr, HELEMENT ConeArray[]) { -#define UMGAH_OFFSET 0 -#define MISSILE_SPEED 0 -#define MISSILE_HITS 100 -#define MISSILE_DAMAGE 1 -#define MISSILE_LIFE 1 -#define MISSILE_OFFSET 0 STARSHIP *StarShipPtr; UMGAH_DATA* UmgahData; MISSILE_BLOCK MissileBlock; @@ -317,12 +318,12 @@ initialize_cone (ELEMENT *ShipPtr, HELEMENT ConeArray[]) MissileBlock.sender = ShipPtr->playerNr; MissileBlock.flags = IGNORE_SIMILAR; MissileBlock.pixoffs = UMGAH_OFFSET; - MissileBlock.speed = MISSILE_SPEED; - MissileBlock.hit_points = MISSILE_HITS; - MissileBlock.damage = MISSILE_DAMAGE; - MissileBlock.life = MISSILE_LIFE; + MissileBlock.speed = CONE_SPEED; + MissileBlock.hit_points = CONE_HITS; + MissileBlock.damage = CONE_DAMAGE; + MissileBlock.life = CONE_LIFE; MissileBlock.preprocess_func = cone_preprocess; - MissileBlock.blast_offs = MISSILE_OFFSET; + MissileBlock.blast_offs = CONE_OFFSET; // This func is called every frame while the player is holding down WEAPON // Don't reset the cone FRAME to the first image every time diff --git a/sc2/src/uqm/ships/urquan/urquan.c b/sc2/src/uqm/ships/urquan/urquan.c index ec31087d3..9df87d015 100644 --- a/sc2/src/uqm/ships/urquan/urquan.c +++ b/sc2/src/uqm/ships/urquan/urquan.c @@ -24,23 +24,39 @@ #include - +// Core characteristics #define MAX_CREW MAX_CREW_SIZE #define MAX_ENERGY MAX_ENERGY_SIZE #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 6 -#define SPECIAL_ENERGY_COST 8 #define ENERGY_WAIT 4 #define MAX_THRUST 30 #define THRUST_INCREMENT 6 -#define TURN_WAIT 4 #define THRUST_WAIT 6 -#define WEAPON_WAIT 6 -#define SPECIAL_WAIT 9 - +#define TURN_WAIT 4 #define SHIP_MASS 10 + +// Fusion blast +#define WEAPON_ENERGY_COST 6 +#define WEAPON_WAIT 6 #define MISSILE_SPEED DISPLAY_TO_WORLD (20) #define MISSILE_LIFE 20 +#define MISSILE_HITS 10 +#define MISSILE_DAMAGE 6 +#define MISSILE_OFFSET 8 +#define URQUAN_OFFSET 32 + +// Fighters +#define SPECIAL_ENERGY_COST 8 +#define SPECIAL_WAIT 9 +#define FIGHTER_OFFSET 4 +#define FIGHTER_SPEED DISPLAY_TO_WORLD (8) +#define ONE_WAY_FLIGHT 125 +#define TRACK_THRESHOLD 6 +#define FIGHTER_LIFE (ONE_WAY_FLIGHT + ONE_WAY_FLIGHT + 150) +#define FIGHTER_HITS 1 +#define FIGHTER_MASS 0 +#define FIGHTER_WEAPON_WAIT 8 +#define FIGHTER_LASER_RANGE DISPLAY_TO_WORLD (40 + FIGHTER_OFFSET) static RACE_DESC urquan_desc = { @@ -116,10 +132,6 @@ static RACE_DESC urquan_desc = static COUNT initialize_fusion (ELEMENT *ShipPtr, HELEMENT FusionArray[]) { -#define MISSILE_HITS 10 -#define MISSILE_DAMAGE 6 -#define MISSILE_OFFSET 8 -#define URQUAN_OFFSET 32 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -142,15 +154,6 @@ initialize_fusion (ELEMENT *ShipPtr, HELEMENT FusionArray[]) return (1); } -#define TRACK_THRESHOLD 6 -#define FIGHTER_SPEED DISPLAY_TO_WORLD (8) -#define ONE_WAY_FLIGHT 125 -#define FIGHTER_LIFE (ONE_WAY_FLIGHT + ONE_WAY_FLIGHT + 150) - -#define FIGHTER_WEAPON_WAIT 8 -#define FIGHTER_OFFSET 4 -#define LASER_RANGE DISPLAY_TO_WORLD (40 + FIGHTER_OFFSET) - static void fighter_postprocess (ELEMENT *ElementPtr) { @@ -162,8 +165,8 @@ fighter_postprocess (ELEMENT *ElementPtr) LaserBlock.cx = ElementPtr->next.location.x; LaserBlock.cy = ElementPtr->next.location.y; LaserBlock.face = ElementPtr->thrust_wait; - LaserBlock.ex = COSINE (FACING_TO_ANGLE (LaserBlock.face), LASER_RANGE); - LaserBlock.ey = SINE (FACING_TO_ANGLE (LaserBlock.face), LASER_RANGE); + LaserBlock.ex = COSINE (FACING_TO_ANGLE (LaserBlock.face), FIGHTER_LASER_RANGE); + LaserBlock.ey = SINE (FACING_TO_ANGLE (LaserBlock.face), FIGHTER_LASER_RANGE); LaserBlock.sender = ElementPtr->playerNr; LaserBlock.flags = IGNORE_SIMILAR; LaserBlock.pixoffs = FIGHTER_OFFSET; @@ -256,10 +259,10 @@ fighter_preprocess (ELEMENT *ElementPtr) delta_y = WRAP_DELTA_Y (delta_y); if (ElementPtr->thrust_wait == 0 - && abs (delta_x) < LASER_RANGE * 3 / 4 - && abs (delta_y) < LASER_RANGE * 3 / 4 + && abs (delta_x) < FIGHTER_LASER_RANGE * 3 / 4 + && abs (delta_y) < FIGHTER_LASER_RANGE * 3 / 4 && delta_x * delta_x + delta_y * delta_y < - (LASER_RANGE * 3 / 4) * (LASER_RANGE * 3 / 4)) + (FIGHTER_LASER_RANGE * 3 / 4) * (FIGHTER_LASER_RANGE * 3 / 4)) { ElementPtr->thrust_wait = (BYTE)NORMALIZE_FACING ( @@ -414,8 +417,8 @@ spawn_fighters (ELEMENT *ElementPtr) PutElement (hFighterElement); LockElement (hFighterElement, &FighterElementPtr); - FighterElementPtr->hit_points = 1; - FighterElementPtr->mass_points = 0; + FighterElementPtr->hit_points = FIGHTER_HITS; + FighterElementPtr->mass_points = FIGHTER_MASS; FighterElementPtr->thrust_wait = TRACK_THRESHOLD + 1; FighterElementPtr->playerNr = ElementPtr->playerNr; FighterElementPtr->state_flags = APPEARING | FINITE_LIFE diff --git a/sc2/src/uqm/ships/utwig/utwig.c b/sc2/src/uqm/ships/utwig/utwig.c index af4cc588f..cb5f2fdcb 100644 --- a/sc2/src/uqm/ships/utwig/utwig.c +++ b/sc2/src/uqm/ships/utwig/utwig.c @@ -23,24 +23,36 @@ #include "uqm/globdata.h" #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 20 #define MAX_ENERGY 20 #define ENERGY_REGENERATION 0 -#define WEAPON_ENERGY_COST 0 -#define SPECIAL_ENERGY_COST 1 #define ENERGY_WAIT 255 #define MAX_THRUST 36 #define THRUST_INCREMENT 6 -#define TURN_WAIT 1 #define THRUST_WAIT 6 -#define WEAPON_WAIT 7 -#define SPECIAL_WAIT 12 - +#define TURN_WAIT 1 #define SHIP_MASS 8 + +// Weapon +#define WEAPON_ENERGY_COST 0 +#define WEAPON_WAIT 7 #define UTWIG_OFFSET 9 #define MISSILE_SPEED DISPLAY_TO_WORLD (30) #define MISSILE_LIFE 10 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 +#define MISSILE_OFFSET 1 +#define LAUNCH_XOFFS0 DISPLAY_TO_WORLD (5) +#define LAUNCH_YOFFS0 -DISPLAY_TO_WORLD (18) +#define LAUNCH_XOFFS1 DISPLAY_TO_WORLD (13) +#define LAUNCH_YOFFS1 -DISPLAY_TO_WORLD (9) +#define LAUNCH_XOFFS2 DISPLAY_TO_WORLD (17) +#define LAUNCH_YOFFS2 -DISPLAY_TO_WORLD (4) + +// Shield +#define SPECIAL_ENERGY_COST 1 +#define SPECIAL_WAIT 12 static RACE_DESC utwig_desc = { @@ -116,15 +128,6 @@ static RACE_DESC utwig_desc = static COUNT initialize_lance (ELEMENT *ShipPtr, HELEMENT WeaponArray[]) { -#define LAUNCH_XOFFS0 DISPLAY_TO_WORLD (5) -#define LAUNCH_YOFFS0 -DISPLAY_TO_WORLD (18) -#define LAUNCH_XOFFS1 DISPLAY_TO_WORLD (13) -#define LAUNCH_YOFFS1 -DISPLAY_TO_WORLD (9) -#define LAUNCH_XOFFS2 DISPLAY_TO_WORLD (17) -#define LAUNCH_YOFFS2 -DISPLAY_TO_WORLD (4) -#define MISSILE_HITS 1 -#define MISSILE_DAMAGE 1 -#define MISSILE_OFFSET 1 COUNT i; STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; diff --git a/sc2/src/uqm/ships/vux/vux.c b/sc2/src/uqm/ships/vux/vux.c index a6975924e..83e6c470e 100644 --- a/sc2/src/uqm/ships/vux/vux.c +++ b/sc2/src/uqm/ships/vux/vux.c @@ -23,26 +23,44 @@ #include "uqm/globdata.h" #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 20 #define MAX_ENERGY 40 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 1 -#define SPECIAL_ENERGY_COST 2 #define ENERGY_WAIT 8 #define MAX_THRUST /* DISPLAY_TO_WORLD (5) */ 21 #define THRUST_INCREMENT /* DISPLAY_TO_WORLD (2) */ 7 -#define TURN_WAIT 6 #define THRUST_WAIT 4 -#define WEAPON_WAIT 0 -#define SPECIAL_WAIT 7 - +#define TURN_WAIT 6 #define SHIP_MASS 6 -#define WARP_OFFSET 46 /* How far outside of laser-range ship can warp in */ + +// Laser +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 0 #define VUX_OFFSET 12 #define LASER_BASE 150 #define LASER_RANGE DISPLAY_TO_WORLD (LASER_BASE + VUX_OFFSET) +// Limpet +#define SPECIAL_ENERGY_COST 2 +#define SPECIAL_WAIT 7 +#define LIMPET_SPEED 25 +#define LIMPET_OFFSET 8 +#define LIMPET_LIFE 80 +#define LIMPET_HITS 1 +#define LIMPET_DAMAGE 0 +#define MIN_THRUST_INCREMENT DISPLAY_TO_WORLD (1) + +// Aggressive Entry +#define WARP_OFFSET 46 + /* How far outside of the laser range can the ship warp in. */ +#define MAXX_ENTRY_DIST DISPLAY_TO_WORLD ((LASER_BASE + VUX_OFFSET + WARP_OFFSET) << 1) +#define MAXY_ENTRY_DIST DISPLAY_TO_WORLD ((LASER_BASE + VUX_OFFSET + WARP_OFFSET) << 1) + /* Originally, the warp distance was: + * DISPLAY_TO_WORLD (SPACE_HEIGHT << 1) + * where SPACE_HEIGHT = SCREEN_HEIGHT - (SAFE_Y * 2) + * But in reality this should be relative to the laser-range. */ + static RACE_DESC vux_desc = { { /* SHIP_INFO */ @@ -114,7 +132,6 @@ static RACE_DESC vux_desc = 0, /* CodeRef */ }; -#define LIMPET_SPEED 25 static void limpet_preprocess (ELEMENT *ElementPtr) @@ -128,8 +145,7 @@ limpet_preprocess (ELEMENT *ElementPtr) if ((delta_facing = TrackShip (ElementPtr, &facing)) > 0) { facing = orig_facing + delta_facing; - SetVelocityVector (&ElementPtr->velocity, - LIMPET_SPEED, facing); + SetVelocityVector (&ElementPtr->velocity, LIMPET_SPEED, facing); } ElementPtr->next.image.frame = IncFrameIndex (ElementPtr->next.image.frame); @@ -154,7 +170,6 @@ limpet_collision (ELEMENT *ElementPtr0, POINT *pPt0, --RDPtr->characteristics.turn_wait; if (++RDPtr->characteristics.thrust_wait == 0) --RDPtr->characteristics.thrust_wait; -#define MIN_THRUST_INCREMENT DISPLAY_TO_WORLD (1) if (RDPtr->characteristics.thrust_increment <= MIN_THRUST_INCREMENT) { RDPtr->characteristics.max_thrust = @@ -193,10 +208,6 @@ limpet_collision (ELEMENT *ElementPtr0, POINT *pPt0, static void spawn_limpets (ELEMENT *ElementPtr) { -#define LIMPET_OFFSET 8 -#define LIMPET_LIFE 80 -#define LIMPET_HITS 1 -#define LIMPET_DAMAGE 0 HELEMENT Limpet; STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -327,12 +338,6 @@ vux_preprocess (ELEMENT *ElementPtr) do { - // Originally, the warp distance was: - // DISPLAY_TO_WORLD (SPACE_HEIGHT << 1) - // where SPACE_HEIGHT = SCREEN_HEIGHT - (SAFE_Y * 2) - // But in reality this should be relative to the laser-range -#define MAXX_ENTRY_DIST DISPLAY_TO_WORLD ((LASER_BASE + VUX_OFFSET + WARP_OFFSET) << 1) -#define MAXY_ENTRY_DIST DISPLAY_TO_WORLD ((LASER_BASE + VUX_OFFSET + WARP_OFFSET) << 1) SIZE dx, dy; ElementPtr->current.location.x = diff --git a/sc2/src/uqm/ships/yehat/yehat.c b/sc2/src/uqm/ships/yehat/yehat.c index 7ebe109ca..f3d0fb899 100644 --- a/sc2/src/uqm/ships/yehat/yehat.c +++ b/sc2/src/uqm/ships/yehat/yehat.c @@ -22,23 +22,32 @@ #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 20 #define MAX_ENERGY 10 #define ENERGY_REGENERATION 2 -#define WEAPON_ENERGY_COST 1 -#define SPECIAL_ENERGY_COST 3 #define ENERGY_WAIT 6 #define MAX_THRUST 30 #define THRUST_INCREMENT 6 -#define TURN_WAIT 2 #define THRUST_WAIT 2 -#define WEAPON_WAIT 0 -#define SPECIAL_WAIT 2 - +#define TURN_WAIT 2 #define SHIP_MASS 3 + +// Twin Pulse Cannon +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 0 +#define YEHAT_OFFSET 16 +#define LAUNCH_OFFS DISPLAY_TO_WORLD (8) #define MISSILE_SPEED DISPLAY_TO_WORLD (20) #define MISSILE_LIFE 10 +#define MISSILE_HITS 1 +#define MISSILE_DAMAGE 1 +#define MISSILE_OFFSET 1 + +// Force Shield +#define SPECIAL_ENERGY_COST 3 +#define SPECIAL_WAIT 2 +#define SHIELD_LIFE 10 static RACE_DESC yehat_desc = { @@ -114,11 +123,6 @@ static RACE_DESC yehat_desc = static COUNT initialize_standard_missiles (ELEMENT *ShipPtr, HELEMENT MissileArray[]) { -#define YEHAT_OFFSET 16 -#define LAUNCH_OFFS DISPLAY_TO_WORLD (8) -#define MISSILE_HITS 1 -#define MISSILE_DAMAGE 1 -#define MISSILE_OFFSET 1 SIZE offs_x, offs_y; STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -334,7 +338,6 @@ yehat_preprocess (ELEMENT *ElementPtr) DeltaEnergy (ElementPtr, -SPECIAL_ENERGY_COST); /* so text will flash */ else { -#define SHIELD_LIFE 10 ElementPtr->life_span = SHIELD_LIFE + NORMAL_LIFE; ElementPtr->next.image.farray = StarShipPtr->RaceDescPtr->ship_data.special; diff --git a/sc2/src/uqm/ships/zoqfot/zoqfot.c b/sc2/src/uqm/ships/zoqfot/zoqfot.c index d6842745a..15a602481 100644 --- a/sc2/src/uqm/ships/zoqfot/zoqfot.c +++ b/sc2/src/uqm/ships/zoqfot/zoqfot.c @@ -22,24 +22,39 @@ #include "libs/mathlib.h" - +// Core characteristics #define MAX_CREW 10 #define MAX_ENERGY 10 #define ENERGY_REGENERATION 1 -#define WEAPON_ENERGY_COST 1 -#define SPECIAL_ENERGY_COST (MAX_ENERGY * 3 / 4) #define ENERGY_WAIT 4 #define MAX_THRUST 40 #define THRUST_INCREMENT 10 -#define TURN_WAIT 1 #define THRUST_WAIT 0 -#define WEAPON_WAIT 0 -#define SPECIAL_WAIT 6 - +#define TURN_WAIT 1 #define SHIP_MASS 5 + +// Main weapon +#define WEAPON_ENERGY_COST 1 +#define WEAPON_WAIT 0 +#define ZOQFOTPIK_OFFSET 13 +#define MISSILE_OFFSET 0 #define MISSILE_SPEED DISPLAY_TO_WORLD (10) + /* Used by the cyborg only. */ #define MISSILE_LIFE 10 #define MISSILE_RANGE (MISSILE_SPEED * MISSILE_LIFE) +#define MISSILE_DAMAGE 1 +#define MISSILE_HITS 1 +#define SPIT_WAIT 2 + /* Controls the main weapon color change animation's speed. + * The animation advances one frame every SPIT_WAIT frames. */ + +// Tongue +#define SPECIAL_ENERGY_COST (MAX_ENERGY * 3 / 4) +#define SPECIAL_WAIT 6 +#define TONGUE_SPEED 0 +#define TONGUE_HITS 1 +#define TONGUE_DAMAGE 12 +#define TONGUE_OFFSET 4 static RACE_DESC zoqfotpik_desc = { @@ -112,12 +127,10 @@ static RACE_DESC zoqfotpik_desc = 0, /* CodeRef */ }; -#define ZOQFOTPIK_OFFSET 13 -#define SPIT_WAIT 2 - static void spit_preprocess (ELEMENT *ElementPtr) { + /* turn_wait is abused here to control the animation speed. */ if (ElementPtr->turn_wait > 0) --ElementPtr->turn_wait; else @@ -136,6 +149,7 @@ spit_preprocess (ELEMENT *ElementPtr) (SIZE)COSINE (angle, speed), (SIZE)SINE (angle, speed)); + /* turn_wait is abused here to control the animation speed. */ ElementPtr->turn_wait = SPIT_WAIT; ElementPtr->state_flags |= CHANGING; } @@ -144,9 +158,6 @@ spit_preprocess (ELEMENT *ElementPtr) static COUNT initialize_spit (ELEMENT *ShipPtr, HELEMENT SpitArray[]) { -#define MISSILE_DAMAGE 1 -#define MISSILE_HITS 1 -#define MISSILE_OFFSET 0 STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; @@ -199,10 +210,6 @@ tongue_collision (ELEMENT *ElementPtr0, POINT *pPt0, static void spawn_tongue (ELEMENT *ElementPtr) { -#define TONGUE_SPEED 0 -#define TONGUE_HITS 1 -#define TONGUE_DAMAGE 12 -#define TONGUE_OFFSET 4 STARSHIP *StarShipPtr; MISSILE_BLOCK TongueBlock; HELEMENT Tongue; diff --git a/sc2/src/uqm/sis.h b/sc2/src/uqm/sis.h index 06dea4265..ee07a81db 100644 --- a/sc2/src/uqm/sis.h +++ b/sc2/src/uqm/sis.h @@ -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) diff --git a/sc2/src/uqm/starbase.c b/sc2/src/uqm/starbase.c index be12f06c7..f1192085c 100644 --- a/sc2/src/uqm/starbase.c +++ b/sc2/src/uqm/starbase.c @@ -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" diff --git a/sc2/src/uqm/starcon.c b/sc2/src/uqm/starcon.c index cf9d6724f..5903e6860 100644 --- a/sc2/src/uqm/starcon.c +++ b/sc2/src/uqm/starcon.c @@ -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" diff --git a/tools/resmap/README.txt b/tools/resmap/README.txt index 29b79ffd3..2ffa19688 100644 --- a/tools/resmap/README.txt +++ b/tools/resmap/README.txt @@ -3,6 +3,11 @@ game, as well as both integer and string names for each one. Running gen_resfiles.py will cause it to regenerate uqm.rmp, all the .ls2 files, and the i*.h source headers that produce the #defines. +XXX The information below is out of date. See the section 'Updating +the core resources' in sc2/doc/devel/resources for an up-to-date +description of the contents of the resources.csv file. + + The .csv file itself is a comma-separated-values list with nine fields: