Merge branch 'master' of ssh://git.code.sf.net/p/sc2/uqm

This commit is contained in:
Serge van den Boom
2013-10-20 13:09:21 +02:00
27 changed files with 2848 additions and 1434 deletions
+9
View File
@@ -0,0 +1,9 @@
.DS_Store
*.app
build.vars
config.state
config_unix.h
obj
uqm-debug
uqm-wrapper
uqm
+1 -1
View File
@@ -593,7 +593,7 @@ uqm_install_osx() {
$PREPROC_C -D__MACOSX__ -include $HEADER - | \
awk '(/'$HEADER_FILE'/ && $2 == 1) { print $3; exit }' | \
$SED 's/.Headers.*$/"/'`
cp -r "$FRAMEWORK" "$INSTROOT/Frameworks"
cp -a "$FRAMEWORK" "$INSTROOT/Frameworks"
done
# Install game content (it should probably make a zipfile)
+1 -1
View File
@@ -326,7 +326,7 @@ PROG_windres_VERSION='windres --version'
### Rez resource compiler (for MacOS X) ###
PROG_Rez_NAME="Rez resource compiler (Apple Developer Tools)"
PROG_Rez_FILE="/Developer/Tools/Rez"
PROG_Rez_FILE="Rez"
PROG_Rez_ACTION=""
PROG_Rez_VERSION=''
+1 -1
View File
@@ -1831,7 +1831,7 @@ Empty Slot
#(Saved Game - Date:)
Saved Game - Date:
Saved Game
#(Sound) -- OPTION_STRING_BASE
+149
View File
@@ -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.
+123
View File
@@ -0,0 +1,123 @@
Ur-Quan Masters State Files
---------------------------
Statefiles are a legacy component of the UQM runtime and savegame
format. They represent largish (10-64KB) chunks of semi-structured
data that the engine used to keep on disk during gameplay, checking
and updating it as needed. These files were then dumped into and
restored from save files in a compressed form.
In UQM as it exists now (0.7), these files exist as expandable memory
arrays that are consulted as if they were files. UQM 0.8 will change
the savegame format to remove the compression (64K just isn't much
anymore) and put more structure to the data within. The statefile
abstraction itself is not guaranteed to be retained, and indeed core
team considers it kind of horrible and would like to destroy it.
There are three state files.
STARINFO_FILE aka "starinfo.dat"
--------------------------------
This is probably the most reasonable of the three. It keeps track of
which star systems you have visited, and which mineral deposits and
interesting life forms and gadgets you have harvested from the worlds
therein.
The file begins with one DWORD for every star system in the
game. (There are 502 star systems, defined in a gigantic array in
starmap_array in plandata.c). The DWORD is 0 if the star system is
unvisited. It is otherwise an absolute offset within the state file.
Generally speaking, UQM star systems are procedurally generated with a
PRNG and various properties of the star including its type and
location. Thus, the information in starmap.c is sufficient to provide
an accounting of the number and quality of worlds in any given
system. Each world can have up to 32 each of mineral deposits, energy
signatures, or life forms. Thus, each world, in order, in the system
will be listed at its offset with three DWORDS, representing mineral,
energy, and biological entities respectively. Captured entities have a
1 bit set.
With a little over 3,800 visitable celestial bodies, this state file
is capped at a little under 50 KB.
RANDGRPINFO_FILE aka "randgrp.dat"
----------------------------------
This is a "battle group file" - it tracks the information regarding
groups of ships that you can encounter in interplanetary space. This
file gives the location information for all ships in the last solar
system you visited, and it tracks the fleet composition, health, &c
for ships randomly generated due to visiting a solar system in some
species's sphere of influence. Random battle groups are reset after a
week in HyperSpace or upon arrival in some other star system.
The data structures, and the reader/writer functions for them, are
primarily defined in grpinfo.c.
The RANDGRPINFO file starts with a GROUP_HEADER struct, specifying
which star this information is for, when the data expires, and then 65
offsets into the file. This is a *one-indexed array* for
randomly-generated groups.
This is because the offset for group zero points to an entirely
different data structure: the "Group List". This gives the starmap
depiction and location on the Interplanetary map of every battle group
in the system, whether it is randomly generated or pre-defined. This
comprises two bytes (the ID of the most recently encountered group,
and then the number of groups), followed by a series of 17-byte chunks
representing battle groups. These are a byte indicating the race
identifier of the fleet (battle groups can be mixed-composition, but
only one ship appears on the map at a time; this specifies that)
followed by 16 bytes that represent an IP_GROUP structure. See the
Read/WriteIpGroup functions in gengrp.c for the exact layout in the
virtual file. There's a lot of wasted space there, a legacy of the
time when these files were actually structure dumps on 32-bit machines
with very specific memory layouts.
The offsets that are not Group Zero have a similar layout, interpreted
differently. Each of these represents a single battle group. It
retains the two-byte prologue, the second of which specifies the
number of 17-byte chunks to follow. The first byte here is the
displayed race identifier, again, and then each 17-byte chunk is that
ship's particular race ID followed by a 16-byte representation of a
SHIP_FRAGMENT.
There are no requirements about order of layout or total size of this
file; the only requirement is that there is a GROUP_HEADER at offset
zero and that the extents described in the valid offsets do not
overlap.
DEFGRPINFO_FILE aka "defgrp.dat"
--------------------------------
This is a random-access scratch space for battle groups that are
deliberately placed by the plot. There's one GROUP_HEADER in this
file, somewhere, for each star system that has ever had predefined
ships and that the player has visited. There is *no guarantee of any
kind* as to where they are, a priori.
This information instead lives within the game state array, a
155-byte-long bitfield that is mostly used for storing plot events and
event flags. 32-bit values within this array store the relevant
offsets for their fleets, or a 0 if they have not yet been
encountered. In vanilla UQM, there are 14 of these values,
corresponding to the Ur-Quan Probe, the Zoq-Fot-Pik scout, the
Shofixti Survivor, the Unzervalt Guardian, the Sa-Matra, and the nine
Melnorme traders in TrueSpace. Each of these has a corresponding entry
in the game state array that ends in _OFFS0. (Due to the
implementation of GET_GAME_STATE, these values actually are stored as
four eight-bit values each, but this can be ignored pretty much
everywhere but the definition of the states themselves).
If one of these offsets is non-zero, then that offset in the
DEFGRPINFO_FILE will have a SHIP_FRAGMENT-based group definition in
the same format as the ones in RANDGRPINFO_FILE.
The Game State array uses 0 as a special value to mean "this
predefined battle group has not yet been spawned." Because of that, 0
is not a legal offset to place a GROUP_HEADER. To ensure that no
GROUP_HEADER is placed there, a zero is written to the first byte of
the file. That way, the first defined group (which, for vanilla UQM,
will always be the Ur-Quan Probe) thus begins at offset 1.
+8 -11
View File
@@ -1,19 +1,16 @@
/* SDLMain.m - main entry point for our Cocoa-ized SDL app
Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
Non-NIB-Code & other changes: Max Horn <max@quendi.de>
/* SDLMain.m - main entry point for our Cocoa-ized SDL app
Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
Non-NIB-Code & other changes: Max Horn <max@quendi.de>
Feel free to customize this file to suit your needs
Feel free to customize this file to suit your needs
*/
#import <Cocoa/Cocoa.h>
#ifndef _SDLMain_h_
#define _SDLMain_h_
/* An internal Apple class used to setup Apple menus */
@interface NSAppleMenuController:NSObject {}
- (void)controlMenu:(NSMenu *)aMenu;
@end
#import <Cocoa/Cocoa.h>
@interface SDLMain : NSObject
@end
@interface SDLApplication : NSApplication
@end
#endif /* _SDLMain_h_ */
+297 -201
View File
@@ -1,285 +1,381 @@
/* SDLMain.m - main entry point for our Cocoa-ized SDL app
Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
Non-NIB-Code & other changes: Max Horn <max@quendi.de>
/* SDLMain.m - main entry point for our Cocoa-ized SDL app
Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
Non-NIB-Code & other changes: Max Horn <max@quendi.de>
Feel free to customize this file to suit your needs
Modified for use with The Ur-Quan Masters by Nicolas Simonds
<uqm at submedia dot net>
Feel free to customize this file to suit your needs
*/
#import "port.h"
#import SDL_INCLUDE(SDL.h)
#import "SDLMain.h"
#import <sys/param.h>
/* for PATH_MAX */
#import <string.h>
/* for strrchr() */
#import <unistd.h>
#include "SDL.h"
#include "SDLMain.h"
#include <sys/param.h> /* for MAXPATHLEN */
#include <unistd.h>
static int gArgc;
static char **gArgv;
static BOOL gFinderLaunch;
/* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
but the method still is there and works. To avoid warnings, we declare
it ourselves here. */
@interface NSApplication(SDL_Missing_Methods)
- (void)setAppleMenu:(NSMenu *)menu;
@end
@implementation SDLApplication
/* Use this flag to determine whether we use SDLMain.nib or not */
#define SDL_USE_NIB_FILE 0
/* Use this flag to determine whether we use CPS (docking) or not */
#define SDL_USE_CPS 1
#ifdef SDL_USE_CPS
/* Portions of CPS.h */
typedef struct CPSProcessSerNum
{
UInt32 lo;
UInt32 hi;
} CPSProcessSerNum;
extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
#endif /* SDL_USE_CPS */
static int gArgc;
static char **gArgv;
static BOOL gFinderLaunch;
static BOOL gCalledAppMainline = FALSE;
static NSString *getApplicationName(void)
{
const NSDictionary *dict;
NSString *appName = 0;
/* Determine the application name */
dict = (const NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
if (dict)
appName = [dict objectForKey: @"CFBundleName"];
if (![appName length])
appName = [[NSProcessInfo processInfo] processName];
return appName;
}
#if SDL_USE_NIB_FILE
/* A helper category for NSString */
@interface NSString (ReplaceSubString)
- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
@end
#endif
@interface NSApplication (SDLApplication)
@end
@implementation NSApplication (SDLApplication)
/* Invoked from the Quit menu item */
- (void)terminate:(id)sender
{
/* Post a SDL_QUIT event */
SDL_Event event;
event.type = SDL_QUIT;
SDL_PushEvent (&event);
(void) sender; /* Get rid of unused variable warning */
}
/* override NSApplication:sendEvent, to keep Cocoa from beeping on
non-command keystrokes */
- (void)sendEvent:(NSEvent *)anEvent {
if (NSKeyDown == [anEvent type] || NSKeyUp == [anEvent type]) {
if ([anEvent modifierFlags] & NSCommandKeyMask)
[super sendEvent: anEvent];
} else
[super sendEvent: anEvent];
/* Post a SDL_QUIT event */
SDL_Event event;
event.type = SDL_QUIT;
SDL_PushEvent(&event);
}
@end
/* The main class of the application, the application's delegate */
@implementation SDLMain
static char *
basename (char *path)
{
char *base;
base = strrchr (path, '/');
if (base == NULL)
return path;
return (base + 1);
}
/* Set the working directory to the .app's parent directory */
- (void) setupWorkingDirectory:(BOOL)shouldChdir
{
char origindir[PATH_MAX];
char *c;
if (!shouldChdir)
return;
strncpy (origindir, gArgv[0], sizeof origindir);
origindir[sizeof origindir - 1] = '\0';
c = basename (origindir);
if (c == origindir)
strcpy (origindir, ".");
else
*c = '\0';
/* chdir to the binary app's point of origin */
if (chdir (origindir) != 0)
abort ();
/* then chdir to the .app's parent */
if ( chdir ("../Resources/") != 0 )
abort();
if (shouldChdir)
{
char parentdir[MAXPATHLEN];
CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8 *)parentdir, MAXPATHLEN)) {
chdir(parentdir); /* chdir to the binary app's parent */
}
CFRelease(url);
CFRelease(url2);
}
}
void
setupAppleMenu (void)
#if SDL_USE_NIB_FILE
/* Fix menu to contain the real app name instead of "SDL App" */
- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
{
NSMenu *appleMenu;
NSRange aRange;
NSEnumerator *enumerator;
NSMenuItem *menuItem;
NSMenuItem *menuItem;
NSString *title;
NSString *appName;
aRange = [[aMenu title] rangeOfString:@"SDL App"];
if (aRange.length != 0)
[aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
appName = [NSString stringWithUTF8String:basename (gArgv[0])];
appleMenu = [[NSMenu alloc] initWithTitle:appName];
enumerator = [[aMenu itemArray] objectEnumerator];
while ((menuItem = [enumerator nextObject]))
{
aRange = [[menuItem title] rangeOfString:@"SDL App"];
if (aRange.length != 0)
[menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
if ([menuItem hasSubmenu])
[self fixMenu:[menuItem submenu] withAppName:appName];
}
}
/* Add menu items */
title = [@"Hide " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(hide:)
keyEquivalent:@"h"];
#else
menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others"
action:@selector(hideOtherApplications:)
keyEquivalent:@"h"];
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
static void setApplicationMenu(void)
{
/* warning: this code is very odd */
NSMenu *appleMenu;
NSMenuItem *menuItem;
NSString *title;
NSString *appName;
[appleMenu addItemWithTitle:@"Show All"
action:@selector(unhideAllApplications:)
keyEquivalent:@""];
appName = getApplicationName();
appleMenu = [[NSMenu alloc] initWithTitle:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
/* Add menu items */
title = [@"About " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
title = [@"Quit " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(terminate:)
keyEquivalent:@"q"];
[appleMenu addItem:[NSMenuItem separatorItem]];
/* Put menu into the menubar */
menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil
keyEquivalent:@""];
[menuItem setSubmenu:appleMenu];
[[NSApp mainMenu] addItem:menuItem];
title = [@"Hide " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
/* Tell the application object that this is now the application menu */
[NSApp setAppleMenu:appleMenu];
menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
/* Finally give up our references to the objects */
[appleMenu release];
[menuItem release];
[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
title = [@"Quit " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
/* Put menu into the menubar */
menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
[menuItem setSubmenu:appleMenu];
[[NSApp mainMenu] addItem:menuItem];
/* Tell the application object that this is now the application menu */
[NSApp setAppleMenu:appleMenu];
/* Finally give up our references to the objects */
[appleMenu release];
[menuItem release];
}
/* Create a window menu */
void
setupWindowMenu (void)
static void setupWindowMenu(void)
{
NSMenu *windowMenu;
NSMenuItem *windowMenuItem;
NSMenuItem *menuItem;
NSMenu *windowMenu;
NSMenuItem *windowMenuItem;
NSMenuItem *menuItem;
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
/* "Minimize" item */
menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize"
action:@selector(performMiniaturize:)
keyEquivalent:@"m"];
[windowMenu addItem:menuItem];
[menuItem release];
/* "Minimize" item */
menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
[windowMenu addItem:menuItem];
[menuItem release];
/* Put menu into the menubar */
windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window"
action:nil keyEquivalent:@""];
[windowMenuItem setSubmenu:windowMenu];
[[NSApp mainMenu] addItem:windowMenuItem];
/* Put menu into the menubar */
windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
[windowMenuItem setSubmenu:windowMenu];
[[NSApp mainMenu] addItem:windowMenuItem];
/* Tell the application object that this is now the window menu */
[NSApp setWindowsMenu:windowMenu];
/* Tell the application object that this is now the window menu */
[NSApp setWindowsMenu:windowMenu];
/* Finally give up our references to the objects */
[windowMenu release];
[windowMenuItem release];
/* Finally give up our references to the objects */
[windowMenu release];
[windowMenuItem release];
}
/* Replacement for NSApplicationMain */
void
CustomApplicationMain (int argc, char **argv)
static void CustomApplicationMain (int argc, char **argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
SDLMain *sdlMain;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
SDLMain *sdlMain;
/* Ensure the application object is initialised */
[SDLApplication sharedApplication];
/* Ensure the application object is initialised */
[NSApplication sharedApplication];
/* Set up the menubar */
[NSApp setMainMenu:[[NSMenu alloc] init]];
setupAppleMenu ();
setupWindowMenu ();
#ifdef SDL_USE_CPS
{
CPSProcessSerNum PSN;
/* Tell the dock about us */
if (!CPSGetCurrentProcess(&PSN))
if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
if (!CPSSetFrontProcess(&PSN))
[NSApplication sharedApplication];
}
#endif /* SDL_USE_CPS */
/* Create SDLMain and make it the app delegate */
sdlMain = [[SDLMain alloc] init];
[NSApp setDelegate:sdlMain];
/* Set up the menubar */
[NSApp setMainMenu:[[NSMenu alloc] init]];
setApplicationMenu();
setupWindowMenu();
/* Start the main event loop */
[NSApp run];
/* Create SDLMain and make it the app delegate */
sdlMain = [[SDLMain alloc] init];
[NSApp setDelegate:sdlMain];
[sdlMain release];
[pool release];
/* Start the main event loop */
[NSApp run];
(void) argc; /* Get rid of unused variable warning */
(void) argv; /* Get rid of unused variable warning */
[sdlMain release];
[pool release];
}
#endif
/*
* Catch document open requests...this lets us notice files when the app
* was launched by double-clicking a document, or when a document was
* dragged/dropped on the app's icon. You need to have a
* CFBundleDocumentsType section in your Info.plist to get this message,
* apparently.
*
* Files are added to gArgv, so to the app, they'll look like command line
* arguments. Previously, apps launched from the finder had nothing but
* an argv[0].
*
* This message may be received multiple times to open several docs on launch.
*
* This message is ignored once the app's mainline has been called.
*/
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
const char *temparg;
size_t arglen;
char *arg;
char **newargv;
if (!gFinderLaunch) /* MacOS is passing command line args. */
return FALSE;
if (gCalledAppMainline) /* app has started, ignore this document. */
return FALSE;
temparg = [filename UTF8String];
arglen = SDL_strlen(temparg) + 1;
arg = (char *) SDL_malloc(arglen);
if (arg == NULL)
return FALSE;
newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
if (newargv == NULL)
{
SDL_free(arg);
return FALSE;
}
gArgv = newargv;
SDL_strlcpy(arg, temparg, arglen);
gArgv[gArgc++] = arg;
gArgv[gArgc] = NULL;
return TRUE;
}
/* Called when the internal event loop has just started running */
- (void) applicationDidFinishLaunching: (NSNotification *) note
{
int status;
int status;
/* Set the working directory to the .app's parent directory */
[self setupWorkingDirectory:gFinderLaunch];
/* Set the working directory to the .app's parent directory */
[self setupWorkingDirectory:gFinderLaunch];
/* allow Cocoa to hear keystrokes like Command-Q, etc. */
setenv ("SDL_ENABLEAPPEVENTS", "1", 1);
#if SDL_USE_NIB_FILE
/* Set the main menu to contain the real app name instead of "SDL App" */
[self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
#endif
/* Hand off to main application code */
status = SDL_main (gArgc, gArgv);
/* Hand off to main application code */
gCalledAppMainline = TRUE;
status = SDL_main (gArgc, gArgv);
/* We're done, thank you for playing */
exit (status);
(void) note; /* Get rid of unused variable warning */
/* We're done, thank you for playing */
exit(status);
}
@end
@implementation NSString (ReplaceSubString)
- (NSString *) stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
{
unsigned int bufferSize;
unsigned int selfLen = [self length];
unsigned int aStringLen = [aString length];
unichar *buffer;
NSRange localRange;
NSString *result;
unsigned int bufferSize;
unsigned int selfLen = [self length];
unsigned int aStringLen = [aString length];
unichar *buffer;
NSRange localRange;
NSString *result;
bufferSize = selfLen + aStringLen - aRange.length;
buffer = NSAllocateMemoryPages (bufferSize * sizeof (unichar));
bufferSize = selfLen + aStringLen - aRange.length;
buffer = (unichar *)NSAllocateMemoryPages(bufferSize*sizeof(unichar));
/* Get first part into buffer */
localRange.location = 0;
localRange.length = aRange.location;
[self getCharacters:buffer range:localRange];
/* Get first part into buffer */
localRange.location = 0;
localRange.length = aRange.location;
[self getCharacters:buffer range:localRange];
/* Get middle part into buffer */
localRange.location = 0;
localRange.length = aStringLen;
[aString getCharacters:(buffer + aRange.location) range:localRange];
/* Get middle part into buffer */
localRange.location = 0;
localRange.length = aStringLen;
[aString getCharacters:(buffer+aRange.location) range:localRange];
/* Get last part into buffer */
localRange.location = aRange.location + aRange.length;
localRange.length = selfLen - localRange.location;
[self getCharacters:(buffer + aRange.location+aStringLen)
range:localRange];
/* Get last part into buffer */
localRange.location = aRange.location + aRange.length;
localRange.length = selfLen - localRange.location;
[self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
/* Build output string */
result = [NSString stringWithCharacters:buffer length:bufferSize];
/* Build output string */
result = [NSString stringWithCharacters:buffer length:bufferSize];
NSDeallocateMemoryPages (buffer, bufferSize);
NSDeallocateMemoryPages(buffer, bufferSize);
return result;
return result;
}
@end
#ifdef main
# undef main
#endif
/* Main entry point to executable - should *not* be SDL_main! */
int
main (int argc, char **argv)
int main (int argc, char **argv)
{
/* Copy the arguments into a global variable */
int i;
/* Copy the arguments into a global variable */
/* This is passed if we are launched by double-clicking */
if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
gArgv[0] = argv[0];
gArgv[1] = NULL;
gArgc = 1;
gFinderLaunch = YES;
} else {
int i;
gArgc = argc;
gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
for (i = 0; i <= argc; i++)
gArgv[i] = argv[i];
gFinderLaunch = NO;
}
/* If we are launched by double-clicking, argv[1] is "-psn_<some_number> */
if ( argc >= 2 && strncmp (argv[1], "-psn_", 5) == 0 ) {
gArgc = 1;
gFinderLaunch = YES;
} else {
gArgc = argc;
gFinderLaunch = NO;
}
gArgv = (char **) malloc (sizeof *gArgv * (gArgc + 1));
if (gArgv == NULL)
abort ();
for (i = 0; i < gArgc; i++)
gArgv[i] = argv[i];
gArgv[i] = NULL;
CustomApplicationMain (argc, argv);
free (gArgv);
return 0;
#if SDL_USE_NIB_FILE
NSApplicationMain (argc, argv);
#else
CustomApplicationMain (argc, argv);
#endif
return 0;
}
+2 -1
View File
@@ -4,6 +4,7 @@ uqm_CFILES="battle.c battlecontrols.c border.c build.c cleanup.c clock.c
cyborg.c demo.c displist.c dummy.c encount.c flash.c fmv.c galaxy.c
gameev.c gameinp.c gameopt.c gendef.c getchar.c globdata.c gravity.c
cons_res.c grpinfo.c hyper.c init.c intel.c intro.c ipdisp.c load.c
load_legacy.c
loadship.c master.c menu.c misc.c oscill.c outfit.c pickship.c
plandata.c process.c restart.c save.c settings.c setup.c setupmenu.c
ship.c shipstat.c shipyard.c sis.c sounds.c starbase.c starcon.c
@@ -14,7 +15,7 @@ uqm_HFILES="battlecontrols.h battle.h build.h clock.h cnctdlg.h coderes.h
corecode.h credits.h demo.h displist.h dummy.h element.h encount.h
flash.h fmv.h gameev.h gameopt.h gamestr.h gendef.h globdata.h
grpinfo.h hyper.h ifontres.h igfxres.h ikey_con.h imusicre.h init.h
intel.h ipdisp.h isndres.h istrtab.h load.h master.h menustat.h
intel.h ipdisp.h isndres.h istrtab.h master.h menustat.h
nameref.h oscill.h pickship.h process.h races.h resinst.h respkg.h
restart.h save.h settings.h setup.h setupmenu.h shipcont.h ship.h
sis.h sounds.h starbase.h starcon.h state.h status.h tactrans.h
+1 -1
View File
@@ -31,8 +31,8 @@
#include "endian_uqm.h"
#include "gamestr.h"
#include "options.h"
#include "load.h"
#include "oscill.h"
#include "save.h"
#include "settings.h"
#include "setup.h"
#include "sounds.h"
+202 -13
View File
@@ -26,7 +26,6 @@
#include "sis.h"
#include "units.h"
#include "gamestr.h"
#include "load.h"
#include "options.h"
#include "save.h"
#include "settings.h"
@@ -352,10 +351,185 @@ NameCaptainOrShip (bool nameCaptain)
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
@@ -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);
}
@@ -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
@@ -1032,6 +1220,8 @@ PickGame (BOOLEAN saving, BOOLEAN fromMainMenu)
// 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?
@@ -1154,4 +1344,3 @@ GameOptions (void)
return !(GLOBAL (CurrentActivity) & (CHECK_ABORT | CHECK_LOAD));
}
+29 -13
View File
@@ -48,31 +48,31 @@ GLOBDATA GlobData;
BYTE
getGameState (int startBit, int endBit)
getGameState (BYTE *state, int startBit, int endBit)
{
return (BYTE) (((startBit >> 3) == (endBit >> 3)
? (GLOBAL (GameState[startBit >> 3]) >> (startBit & 7))
: ((GLOBAL (GameState[startBit >> 3]) >> (startBit & 7))
| (GLOBAL (GameState[endBit >> 3])
? (state[startBit >> 3] >> (startBit & 7))
: ((state[startBit >> 3] >> (startBit & 7))
| (state[endBit >> 3]
<< (endBit - startBit - (endBit & 7)))))
& ((1 << (endBit - startBit + 1)) - 1));
}
void
setGameState (int startBit, int endBit, BYTE val
setGameState (BYTE *state, int startBit, int endBit, BYTE val
#ifdef STATE_DEBUG
, const char *name
#endif
)
{
GLOBAL (GameState[startBit >> 3]) =
(GLOBAL (GameState[startBit >> 3])
state[startBit >> 3] =
(state[startBit >> 3]
& (BYTE) ~(((1 << (endBit - startBit + 1)) - 1) << (startBit & 7)))
| (BYTE)((val) << (startBit & 7));
if ((startBit >> 3) < (endBit >> 3)) {
GLOBAL (GameState[endBit >> 3]) =
(GLOBAL (GameState[endBit >> 3])
state[endBit >> 3] =
(state[endBit >> 3]
& (BYTE)~((1 << ((endBit & 7) + 1)) - 1))
| (BYTE)((val) >> (endBit - startBit - (endBit & 7)));
}
@@ -82,21 +82,21 @@ setGameState (int startBit, int endBit, BYTE val
}
DWORD
getGameState32 (int startBit)
getGameState32 (BYTE *state, int startBit)
{
DWORD v;
int shift;
for (v = 0, shift = 0; shift < 32; shift += 8, startBit += 8)
{
v |= getGameState (startBit, startBit + 7) << shift;
v |= getGameState (state, startBit, startBit + 7) << shift;
}
return v;
}
void
setGameState32 (int startBit, DWORD val
setGameState32 (BYTE *state, int startBit, DWORD val
#ifdef STATE_DEBUG
, const char *name
#endif
@@ -107,7 +107,7 @@ setGameState32 (int startBit, DWORD val
for (i = 0; i < 4; ++i, v >>= 8, startBit += 8)
{
setGameState (startBit, startBit + 7, v & 0xff
setGameState (state, startBit, startBit + 7, v & 0xff
#ifdef STATE_DEBUG
, "(ignored)"
#endif
@@ -119,6 +119,22 @@ setGameState32 (int startBit, DWORD val
#endif
}
void
copyGameState (BYTE *dest, DWORD target, BYTE *src, DWORD begin, DWORD end)
{
while (begin < end)
{
BYTE b;
DWORD delta = 7;
if (begin + delta > end)
delta = end - begin;
b = getGameState (src, begin, begin + delta);
setGameState (dest, target, target + delta, b);
begin += 8;
target += 8;
}
}
static void
CreateRadar (void)
{
+117 -90
View File
@@ -255,61 +255,6 @@ START_GAME_STATE
ADD_GAME_STATE (LANDER_SHIELDS, 4)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS0, 8)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS1, 8)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS2, 8)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS3, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS0, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS1, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS2, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS3, 8)
ADD_GAME_STATE (MET_MELNORME, 1)
ADD_GAME_STATE (MELNORME_RESCUE_REFUSED, 1)
ADD_GAME_STATE (MELNORME_RESCUE_COUNT, 3)
@@ -329,10 +274,6 @@ START_GAME_STATE
ADD_GAME_STATE (MELNORME_PISSED_COUNT, 2)
ADD_GAME_STATE (MELNORME_HATE_COUNT, 2)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS0, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS1, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS2, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS3, 8)
ADD_GAME_STATE (PROBE_MESSAGE_DELIVERED, 1)
ADD_GAME_STATE (PROBE_ILWRATH_ENCOUNTER, 1)
@@ -647,11 +588,6 @@ START_GAME_STATE
ADD_GAME_STATE (URQUAN_PROTECTING_SAMATRA, 1)
ADD_GAME_STATE (COLONY_GRPOFFS0, 8)
ADD_GAME_STATE (COLONY_GRPOFFS1, 8)
ADD_GAME_STATE (COLONY_GRPOFFS2, 8)
ADD_GAME_STATE (COLONY_GRPOFFS3, 8)
#define THRADDASH_BODY_THRESHOLD 25
ADD_GAME_STATE (THRADDASH_BODY_COUNT, 5)
@@ -671,11 +607,6 @@ START_GAME_STATE
ADD_GAME_STATE (ILWRATH_WORSHIP, 2)
ADD_GAME_STATE (ILWRATH_FIGHT_THRADDASH, 1)
ADD_GAME_STATE (SAMATRA_GRPOFFS0, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS1, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS2, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS3, 8)
ADD_GAME_STATE (READY_TO_CONFUSE_URQUAN, 1)
ADD_GAME_STATE (URQUAN_HYPNO_VISITS, 1)
ADD_GAME_STATE (MENTIONED_PET_COMPULSION, 1)
@@ -877,6 +808,79 @@ START_GAME_STATE
ADD_GAME_STATE (ORZ_STACK0, 1)
ADD_GAME_STATE (ORZ_STACK1, 1)
/* These state bits are actually offsets into defgrp.dat. They really
* shouldn't be part of the serialized Game State array! --MCM */
ADD_GAME_STATE (SHOFIXTI_GRPOFFS0, 8)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS1, 8)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS2, 8)
ADD_GAME_STATE (SHOFIXTI_GRPOFFS3, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS0, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS1, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS2, 8)
ADD_GAME_STATE (ZOQFOT_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME0_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME1_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME2_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME3_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME4_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME5_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME6_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME7_GRPOFFS3, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS0, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS1, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS2, 8)
ADD_GAME_STATE (MELNORME8_GRPOFFS3, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS0, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS1, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS2, 8)
ADD_GAME_STATE (URQUAN_PROBE_GRPOFFS3, 8)
ADD_GAME_STATE (COLONY_GRPOFFS0, 8)
ADD_GAME_STATE (COLONY_GRPOFFS1, 8)
ADD_GAME_STATE (COLONY_GRPOFFS2, 8)
ADD_GAME_STATE (COLONY_GRPOFFS3, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS0, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS1, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS2, 8)
ADD_GAME_STATE (SAMATRA_GRPOFFS3, 8)
END_GAME_STATE
// Values for GAME_STATE.glob_flags:
@@ -970,38 +974,61 @@ extern GLOBDATA GlobData;
#define MAX_ENCOUNTERS 16
#define MAX_BATTLE_GROUPS 32
/* DEFGRP enumeration. These identify scripted TrueSpace encounters
* more consistently than offsets into the DEFGRPINFO_FILE state
* file. */
enum {
DEFGRP_NONE,
DEFGRP_SHOFIXTI,
DEFGRP_ZOQFOT,
DEFGRP_MELNORME0,
DEFGRP_MELNORME1,
DEFGRP_MELNORME2,
DEFGRP_MELNORME3,
DEFGRP_MELNORME4,
DEFGRP_MELNORME5,
DEFGRP_MELNORME6,
DEFGRP_MELNORME7,
DEFGRP_MELNORME8,
DEFGRP_URQUAN_PROBE,
DEFGRP_COLONY,
DEFGRP_SAMATRA,
NUM_DEFGRPS
};
//#define STATE_DEBUG
extern BYTE getGameState (int startBit, int endBit);
extern void setGameState (int startBit, int endBit, BYTE val
extern BYTE getGameState (BYTE *state, int startBit, int endBit);
extern void setGameState (BYTE *state, int startBit, int endBit, BYTE val
#ifdef STATE_DEBUG
, const char *name
#endif
);
extern void copyGameState (BYTE *dest, DWORD target, BYTE *src, DWORD begin, DWORD end);
#define GET_GAME_STATE(SName) getGameState (GLOBAL(GameState), (SName), (END_##SName))
#ifdef STATE_DEBUG
# define SET_GAME_STATE(SName, val) \
setGameState (GLOBAL(GameState), (SName), (END_##SName), (val), #SName)
#else
# define SET_GAME_STATE(SName, val) \
setGameState (GLOBAL(GameState), (SName), (END_##SName), (val))
#endif
extern DWORD getGameState32 (BYTE *state, int startBit);
extern void setGameState32 (BYTE *state, int startBit, DWORD val
#ifdef STATE_DEBUG
, const char *name
#endif
);
#define GET_GAME_STATE(SName) getGameState ((SName), (END_##SName))
#ifdef STATE_DEBUG
# define SET_GAME_STATE(SName, val) \
setGameState ((SName), (END_##SName), (val), #SName)
#else
# define SET_GAME_STATE(SName, val) \
setGameState ((SName), (END_##SName), (val))
#endif
extern DWORD getGameState32 (int startBit);
extern void setGameState32 (int startBit, DWORD val
#ifdef STATE_DEBUG
, const char *name
#endif
);
#define GET_GAME_STATE_32(SName) getGameState32 ((SName))
#define GET_GAME_STATE_32(SName) getGameState32 (GLOBAL(GameState), (SName))
#ifdef STATE_DEBUG
# define SET_GAME_STATE_32(SName, val) \
setGameState32 ((SName), (val), #SName)
setGameState32 (GLOBAL(GameState), (SName), (val), #SName)
#else
# define SET_GAME_STATE_32(SName, val) \
setGameState32 ((SName), (val))
setGameState32 (GLOBAL(GameState), (SName), (val))
#endif
+7 -42
View File
@@ -23,7 +23,7 @@
#include "globdata.h"
#include "intel.h"
#include "state.h"
#include "grpinfo.h"
#include "grpintrn.h"
#include "libs/mathlib.h"
#include "libs/log.h"
@@ -35,42 +35,7 @@
static BYTE LastEncGroup;
// Last encountered group, saved into state files
//#define DEBUG_GROUPS
// A group header describes battle groups present in a star system. There is
// at most 1 group header per system.
// 'Random' group info file (RANDGRPINFO_FILE) always contains only one
// group header record, which describes the last-visited star system,
// (which may be the current system). Thus the randomly generated groups
// are valid for 7 days (set in PutGroupInfo) after the player leaves
// the system, or until the player enters another star system.
typedef struct
{
BYTE NumGroups;
BYTE day_index, month_index;
COUNT star_index, year_index;
// day_index, month_index, year_index specify when
// random groups expire (if you were to leave the system
// by going to HSpace and stay there till such time)
// star_index is the index of a star this group header
// applies to; ~0 means uninited
DWORD GroupOffset[NUM_SAVED_BATTLE_GROUPS + 1];
// Absolute offsets of group definitions in a state file
// Group 0 is a list of groups present in solarsys
// (RANDGRPINFO_FILE only)
// Groups 1..max are definitions of actual battle groups
// containing ship makeup and status
// Each group has the following format:
// 1 byte, RaceType (LastEncGroup in Group 0)
// 1 byte, NumShips (NumGroups in Group 0)
// Ships follow:
// 1 byte, RaceType
// 16 bytes, part of SHIP_FRAGMENT struct
} GROUP_HEADER;
static void
void
ReadGroupHeader (GAME_STATE_FILE *fp, GROUP_HEADER *pGH)
{
sread_8 (fp, &pGH->NumGroups);
@@ -82,7 +47,7 @@ ReadGroupHeader (GAME_STATE_FILE *fp, GROUP_HEADER *pGH)
sread_a32 (fp, pGH->GroupOffset, NUM_SAVED_BATTLE_GROUPS + 1);
}
static void
void
WriteGroupHeader (GAME_STATE_FILE *fp, const GROUP_HEADER *pGH)
{
swrite_8 (fp, pGH->NumGroups);
@@ -94,7 +59,7 @@ WriteGroupHeader (GAME_STATE_FILE *fp, const GROUP_HEADER *pGH)
swrite_a32 (fp, pGH->GroupOffset, NUM_SAVED_BATTLE_GROUPS + 1);
}
static void
void
ReadShipFragment (GAME_STATE_FILE *fp, SHIP_FRAGMENT *FragPtr)
{
BYTE tmpb;
@@ -116,7 +81,7 @@ ReadShipFragment (GAME_STATE_FILE *fp, SHIP_FRAGMENT *FragPtr)
sread_16 (fp, NULL); /* unused; was loc.y */
}
static void
void
WriteShipFragment (GAME_STATE_FILE *fp, const SHIP_FRAGMENT *FragPtr)
{
swrite_16 (fp, 0); /* unused: was which_side */
@@ -134,7 +99,7 @@ WriteShipFragment (GAME_STATE_FILE *fp, const SHIP_FRAGMENT *FragPtr)
swrite_16 (fp, 0); /* unused; was loc.y */
}
static void
void
ReadIpGroup (GAME_STATE_FILE *fp, IP_GROUP *GroupPtr)
{
BYTE tmpb;
@@ -157,7 +122,7 @@ ReadIpGroup (GAME_STATE_FILE *fp, IP_GROUP *GroupPtr)
sread_16s(fp, &GroupPtr->loc.y);
}
static void
void
WriteIpGroup (GAME_STATE_FILE *fp, const IP_GROUP *GroupPtr)
{
swrite_16 (fp, 0); /* unused; was which_side */
+56
View File
@@ -0,0 +1,56 @@
#ifndef _GRPINTRN_H
#define _GRPINTRN_H
// For IPGROUP
#include "grpinfo.h"
// For SHIP_FRAGMENT
#include "races.h"
// For GAME_STATE_FILE
#include "state.h"
//#define DEBUG_GROUPS
// A group header describes battle groups present in a star system. There is
// at most 1 group header per system.
// 'Random' group info file (RANDGRPINFO_FILE) always contains only one
// group header record, which describes the last-visited star system,
// (which may be the current system). Thus the randomly generated groups
// are valid for 7 days (set in PutGroupInfo) after the player leaves
// the system, or until the player enters another star system.
typedef struct
{
BYTE NumGroups;
BYTE day_index, month_index;
COUNT star_index, year_index;
// day_index, month_index, year_index specify when
// random groups expire (if you were to leave the system
// by going to HSpace and stay there till such time)
// star_index is the index of a star this group header
// applies to; ~0 means uninited
DWORD GroupOffset[NUM_SAVED_BATTLE_GROUPS + 1];
// Absolute offsets of group definitions in a state file
// Group 0 is a list of groups present in solarsys
// (RANDGRPINFO_FILE only)
// Groups 1..max are definitions of actual battle groups
// containing ship makeup and status
// Each group has the following format:
// 1 byte, RaceType (LastEncGroup in Group 0)
// 1 byte, NumShips (NumGroups in Group 0)
// Ships follow:
// 1 byte, RaceType
// 16 bytes, part of SHIP_FRAGMENT struct
// (part of IP_GROUP struct in Group 0)
} GROUP_HEADER;
void ReadGroupHeader (GAME_STATE_FILE *fp, GROUP_HEADER *pGH);
void WriteGroupHeader (GAME_STATE_FILE *fp, const GROUP_HEADER *pGH);
void ReadShipFragment (GAME_STATE_FILE *fp, SHIP_FRAGMENT *FragPtr);
void WriteShipFragment (GAME_STATE_FILE *fp, const SHIP_FRAGMENT *FragPtr);
void ReadIpGroup (GAME_STATE_FILE *fp, IP_GROUP *GroupPtr);
void WriteIpGroup (GAME_STATE_FILE *fp, const IP_GROUP *GroupPtr);
#endif
+474 -470
View File
File diff suppressed because it is too large Load Diff
-39
View File
@@ -1,39 +0,0 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _LOAD_H
#define _LOAD_H
#include "sis.h"
// for SUMMARY_DESC
#include "libs/compiler.h"
#include "globdata.h"
#if defined(__cplusplus)
extern "C" {
#endif
extern ACTIVITY NextActivity;
extern BOOLEAN LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc);
#if defined(__cplusplus)
}
#endif
#endif /* _LOAD_H */
+821
View File
@@ -0,0 +1,821 @@
//Copyright Paul Reiche, Fred Ford. 1992-2002
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <assert.h>
#include "build.h"
#include "libs/declib.h"
#include "encount.h"
#include "starmap.h"
#include "libs/file.h"
#include "globdata.h"
#include "options.h"
#include "save.h"
#include "setup.h"
#include "state.h"
#include "grpinfo.h"
#include "libs/tasklib.h"
#include "libs/log.h"
#include "libs/misc.h"
//#define DEBUG_LOAD
// XXX: these should handle endian conversions later
static inline COUNT
cread_8 (DECODE_REF fh, BYTE *v)
{
BYTE t;
if (!v) /* read value ignored */
v = &t;
return cread (v, 1, 1, fh);
}
static inline COUNT
cread_16 (DECODE_REF fh, UWORD *v)
{
UWORD t;
if (!v) /* read value ignored */
v = &t;
return cread (v, 2, 1, fh);
}
static inline COUNT
cread_16s (DECODE_REF fh, SWORD *v)
{
UWORD t;
COUNT ret;
// value was converted to unsigned when saved
ret = cread_16 (fh, &t);
// unsigned to signed conversion
if (v)
*v = t;
return ret;
}
static inline COUNT
cread_32 (DECODE_REF fh, DWORD *v)
{
DWORD t;
if (!v) /* read value ignored */
v = &t;
return cread (v, 4, 1, fh);
}
static inline COUNT
cread_32s (DECODE_REF fh, SDWORD *v)
{
DWORD t;
COUNT ret;
// value was converted to unsigned when saved
ret = cread_32 (fh, &t);
// unsigned to signed conversion
if (v)
*v = t;
return ret;
}
static inline COUNT
cread_ptr (DECODE_REF fh)
{
DWORD t;
return cread_32 (fh, &t); /* ptrs are useless in saves */
}
static inline COUNT
cread_a8 (DECODE_REF fh, BYTE *ar, COUNT count)
{
assert (ar != NULL);
return cread (ar, 1, count, fh) == count;
}
static inline size_t
read_8 (void *fp, BYTE *v)
{
BYTE t;
if (!v) /* read value ignored */
v = &t;
return ReadResFile (v, 1, 1, fp);
}
static inline size_t
read_16 (void *fp, UWORD *v)
{
UWORD t;
if (!v) /* read value ignored */
v = &t;
return ReadResFile (v, 2, 1, fp);
}
static inline size_t
read_32 (void *fp, DWORD *v)
{
DWORD t;
if (!v) /* read value ignored */
v = &t;
return ReadResFile (v, 4, 1, fp);
}
static inline size_t
read_32s (void *fp, SDWORD *v)
{
DWORD t;
COUNT ret;
// value was converted to unsigned when saved
ret = read_32 (fp, &t);
// unsigned to signed conversion
if (v)
*v = t;
return ret;
}
static inline size_t
read_ptr (void *fp)
{
DWORD t;
return read_32 (fp, &t); /* ptrs are useless in saves */
}
static inline size_t
read_a8 (void *fp, BYTE *ar, COUNT count)
{
assert (ar != NULL);
return ReadResFile (ar, 1, count, fp) == count;
}
static inline size_t
read_str (void *fp, char *str, COUNT count)
{
// no type conversion needed for strings
return read_a8 (fp, (BYTE *)str, count);
}
static inline size_t
read_a16 (void *fp, UWORD *ar, COUNT count)
{
assert (ar != NULL);
for ( ; count > 0; --count, ++ar)
{
if (read_16 (fp, ar) != 1)
return 0;
}
return 1;
}
typedef struct struct_GAMESTATE_TRANSPOSE {
int start, end, target;
} GAMESTATE_TRANSPOSE;
#define LEGACY_GAMESTATE_SIZE 155
/* The *_GRPOFFS* states are no longer intermingled with the rest of
* the state. We need to shuffle all the rest of the state data
* down. */
static GAMESTATE_TRANSPOSE transpose[] = {
{ 0, 51, 0 },
{ 404, 450, 52 },
{ 483, 878, 99 },
{ 911, 930, 495 },
{ 963, 1237, 515 },
{ -1, -1, -1 } };
static DWORD old_defgrp_offsets[] = { 0, 52, 84, 116, 148, 180, 212, 244,
276, 308, 340, 372, 451, 879, 931 };
static DWORD new_defgrp_offsets[] = {
0,
SHOFIXTI_GRPOFFS0,
ZOQFOT_GRPOFFS0,
MELNORME0_GRPOFFS0,
MELNORME1_GRPOFFS0,
MELNORME2_GRPOFFS0,
MELNORME3_GRPOFFS0,
MELNORME4_GRPOFFS0,
MELNORME5_GRPOFFS0,
MELNORME6_GRPOFFS0,
MELNORME7_GRPOFFS0,
MELNORME8_GRPOFFS0,
URQUAN_PROBE_GRPOFFS0,
COLONY_GRPOFFS0,
SAMATRA_GRPOFFS0
};
static void
InterpretLegacyGameState (BYTE *result, BYTE *legacy)
{
int i;
DWORD grpoffs[NUM_DEFGRPS];
GAMESTATE_TRANSPOSE *t = &transpose[0];
grpoffs[0] = 0;
for (i = 1; i < NUM_DEFGRPS; ++i)
{
grpoffs[i] = getGameState32 (legacy, old_defgrp_offsets[i]);
}
while (t->start >= 0)
{
copyGameState (result, t->target, legacy, t->start, t->end);
++t;
}
for (i = 1; i < NUM_DEFGRPS; ++i)
{
setGameState32 (result, new_defgrp_offsets[i], grpoffs[i]);
}
}
static void
LoadEmptyQueue (DECODE_REF fh)
{
COUNT num_links;
cread_16 (fh, &num_links);
if (num_links)
{
log_add (log_Error, "LoadEmptyQueue(): BUG: the queue is not empty!");
#ifdef DEBUG
explode ();
#endif
}
}
static void
LoadShipQueue (DECODE_REF fh, QUEUE *pQueue)
{
COUNT num_links;
cread_16 (fh, &num_links);
while (num_links--)
{
HSHIPFRAG hStarShip;
SHIP_FRAGMENT *FragPtr;
COUNT Index;
BYTE tmpb;
cread_16 (fh, &Index);
hStarShip = CloneShipFragment (Index, pQueue, 0);
FragPtr = LockShipFrag (pQueue, hStarShip);
// Read SHIP_FRAGMENT elements
cread_16 (fh, NULL); /* unused: was which_side */
cread_8 (fh, &FragPtr->captains_name_index);
cread_8 (fh, NULL); /* padding */
cread_16 (fh, NULL); /* unused: was ship_flags */
cread_8 (fh, &FragPtr->race_id);
cread_8 (fh, &FragPtr->index);
// XXX: reading crew as BYTE to maintain savegame compatibility
cread_8 (fh, &tmpb);
FragPtr->crew_level = tmpb;
cread_8 (fh, &tmpb);
FragPtr->max_crew = tmpb;
cread_8 (fh, &FragPtr->energy_level);
cread_8 (fh, &FragPtr->max_energy);
cread_16 (fh, NULL); /* unused; was loc.x */
cread_16 (fh, NULL); /* unused; was loc.y */
UnlockShipFrag (pQueue, hStarShip);
}
}
static void
LoadRaceQueue (DECODE_REF fh, QUEUE *pQueue)
{
COUNT num_links;
cread_16 (fh, &num_links);
while (num_links--)
{
HFLEETINFO hStarShip;
FLEET_INFO *FleetPtr;
COUNT Index;
BYTE tmpb;
cread_16 (fh, &Index);
hStarShip = GetStarShipFromIndex (pQueue, Index);
FleetPtr = LockFleetInfo (pQueue, hStarShip);
// Read FLEET_INFO elements
cread_16 (fh, &FleetPtr->allied_state);
cread_8 (fh, &FleetPtr->days_left);
cread_8 (fh, &FleetPtr->growth_fract);
cread_8 (fh, &tmpb);
FleetPtr->crew_level = tmpb;
cread_8 (fh, &tmpb);
FleetPtr->max_crew = tmpb;
cread_8 (fh, &FleetPtr->growth);
cread_8 (fh, &FleetPtr->max_energy);
cread_16s(fh, &FleetPtr->loc.x);
cread_16s(fh, &FleetPtr->loc.y);
cread_16 (fh, &FleetPtr->actual_strength);
cread_16 (fh, &FleetPtr->known_strength);
cread_16s(fh, &FleetPtr->known_loc.x);
cread_16s(fh, &FleetPtr->known_loc.y);
cread_8 (fh, &FleetPtr->growth_err_term);
cread_8 (fh, &FleetPtr->func_index);
cread_16s(fh, &FleetPtr->dest_loc.x);
cread_16s(fh, &FleetPtr->dest_loc.y);
cread_16 (fh, NULL); /* alignment padding */
UnlockFleetInfo (pQueue, hStarShip);
}
}
static void
LoadGroupQueue (DECODE_REF fh, QUEUE *pQueue)
{
COUNT num_links;
cread_16 (fh, &num_links);
while (num_links--)
{
HIPGROUP hGroup;
IP_GROUP *GroupPtr;
BYTE tmpb;
cread_16 (fh, NULL); /* unused; was race_id */
hGroup = BuildGroup (pQueue, 0);
GroupPtr = LockIpGroup (pQueue, hGroup);
cread_16 (fh, NULL); /* unused; was which_side */
cread_8 (fh, NULL); /* unused; was captains_name_index */
cread_8 (fh, NULL); /* padding; for savegame compat */
cread_16 (fh, &GroupPtr->group_counter);
cread_8 (fh, &GroupPtr->race_id);
cread_8 (fh, &tmpb); /* was var2 */
GroupPtr->sys_loc = LONIBBLE (tmpb);
GroupPtr->task = HINIBBLE (tmpb);
cread_8 (fh, &GroupPtr->in_system); /* was crew_level */
cread_8 (fh, NULL); /* unused; was max_crew */
cread_8 (fh, &tmpb); /* was energy_level */
GroupPtr->dest_loc = LONIBBLE (tmpb);
GroupPtr->orbit_pos = HINIBBLE (tmpb);
cread_8 (fh, &GroupPtr->group_id); /* was max_energy */
cread_16s(fh, &GroupPtr->loc.x);
cread_16s(fh, &GroupPtr->loc.y);
UnlockIpGroup (pQueue, hGroup);
}
}
static void
LoadEncounter (ENCOUNTER *EncounterPtr, DECODE_REF fh)
{
COUNT i;
BYTE tmpb;
cread_ptr (fh); /* useless ptr; HENCOUNTER pred */
EncounterPtr->pred = 0;
cread_ptr (fh); /* useless ptr; HENCOUNTER succ */
EncounterPtr->succ = 0;
cread_ptr (fh); /* useless ptr; HELEMENT hElement */
EncounterPtr->hElement = 0;
cread_16s (fh, &EncounterPtr->transition_state);
cread_16s (fh, &EncounterPtr->origin.x);
cread_16s (fh, &EncounterPtr->origin.y);
cread_16 (fh, &EncounterPtr->radius);
// former STAR_DESC fields
cread_16s (fh, &EncounterPtr->loc_pt.x);
cread_16s (fh, &EncounterPtr->loc_pt.y);
cread_8 (fh, &EncounterPtr->race_id);
cread_8 (fh, &tmpb);
EncounterPtr->num_ships = tmpb & ENCOUNTER_SHIPS_MASK;
EncounterPtr->flags = tmpb & ENCOUNTER_FLAGS_MASK;
cread_16 (fh, NULL); /* alignment padding */
// Load each entry in the BRIEF_SHIP_INFO array
for (i = 0; i < MAX_HYPER_SHIPS; i++)
{
BRIEF_SHIP_INFO *ShipInfo = &EncounterPtr->ShipList[i];
cread_16 (fh, NULL); /* useless; was SHIP_INFO.ship_flags */
cread_8 (fh, &ShipInfo->race_id);
cread_8 (fh, NULL); /* useless; was SHIP_INFO.var2 */
// XXX: reading crew as BYTE to maintain savegame compatibility
cread_8 (fh, &tmpb);
ShipInfo->crew_level = tmpb;
cread_8 (fh, &tmpb);
ShipInfo->max_crew = tmpb;
cread_8 (fh, NULL); /* useless; was SHIP_INFO.energy_level */
cread_8 (fh, &ShipInfo->max_energy);
cread_16 (fh, NULL); /* useless; was SHIP_INFO.loc.x */
cread_16 (fh, NULL); /* useless; was SHIP_INFO.loc.y */
cread_32 (fh, NULL); /* useless val; STRING race_strings */
cread_ptr (fh); /* useless ptr; FRAME icons */
cread_ptr (fh); /* useless ptr; FRAME melee_icon */
}
// Load the stuff after the BRIEF_SHIP_INFO array
cread_32s (fh, &EncounterPtr->log_x);
cread_32s (fh, &EncounterPtr->log_y);
}
static void
LoadEvent (EVENT *EventPtr, DECODE_REF fh)
{
cread_ptr (fh); /* useless ptr; HEVENT pred */
EventPtr->pred = 0;
cread_ptr (fh); /* useless ptr; HEVENT succ */
EventPtr->succ = 0;
cread_8 (fh, &EventPtr->day_index);
cread_8 (fh, &EventPtr->month_index);
cread_16 (fh, &EventPtr->year_index);
cread_8 (fh, &EventPtr->func_index);
cread_8 (fh, NULL); /* padding */
cread_16 (fh, NULL); /* padding */
}
static void
DummyLoadQueue (QUEUE *QueuePtr, DECODE_REF fh)
{
/* QUEUE should never actually be loaded since it contains
* purely internal representation and the lists
* involved are actually loaded separately */
(void)QueuePtr; /* silence compiler */
/* QUEUE format with QUEUE_TABLE defined -- UQM default */
cread_ptr (fh); /* HLINK head */
cread_ptr (fh); /* HLINK tail */
cread_ptr (fh); /* BYTE* pq_tab */
cread_ptr (fh); /* HLINK free_list */
cread_16 (fh, NULL); /* MEM_HANDLE hq_tab */
cread_16 (fh, NULL); /* COUNT object_size */
cread_8 (fh, NULL); /* BYTE num_objects */
cread_8 (fh, NULL); /* padding */
cread_16 (fh, NULL); /* padding */
}
static void
LoadClockState (CLOCK_STATE *ClockPtr, DECODE_REF fh)
{
cread_8 (fh, &ClockPtr->day_index);
cread_8 (fh, &ClockPtr->month_index);
cread_16 (fh, &ClockPtr->year_index);
cread_16s (fh, &ClockPtr->tick_count);
cread_16s (fh, &ClockPtr->day_in_ticks);
cread_ptr (fh); /* not loading ptr; Semaphore clock_sem */
cread_ptr (fh); /* not loading ptr; Task clock_task */
cread_32 (fh, NULL); /* not loading; DWORD TimeCounter */
DummyLoadQueue (&ClockPtr->event_q, fh);
}
static void
LoadGameState (GAME_STATE *GSPtr, DECODE_REF fh)
{
BYTE dummy8, oldstate[LEGACY_GAMESTATE_SIZE];
cread_8 (fh, &dummy8); /* obsolete */
cread_8 (fh, &GSPtr->glob_flags);
cread_8 (fh, &GSPtr->CrewCost);
cread_8 (fh, &GSPtr->FuelCost);
cread_a8 (fh, GSPtr->ModuleCost, NUM_MODULES);
cread_a8 (fh, GSPtr->ElementWorth, NUM_ELEMENT_CATEGORIES);
cread_ptr (fh); /* not loading ptr; PRIMITIVE *DisplayArray */
cread_16 (fh, &GSPtr->CurrentActivity);
cread_16 (fh, NULL); /* CLOCK_STATE alignment padding */
LoadClockState (&GSPtr->GameClock, fh);
cread_16s (fh, &GSPtr->autopilot.x);
cread_16s (fh, &GSPtr->autopilot.y);
cread_16s (fh, &GSPtr->ip_location.x);
cread_16s (fh, &GSPtr->ip_location.y);
/* STAMP ShipStamp */
cread_16s (fh, &GSPtr->ShipStamp.origin.x);
cread_16s (fh, &GSPtr->ShipStamp.origin.y);
cread_16 (fh, &GSPtr->ShipFacing);
cread_8 (fh, &GSPtr->ip_planet);
cread_8 (fh, &GSPtr->in_orbit);
/* VELOCITY_DESC velocity */
cread_16 (fh, &GSPtr->velocity.TravelAngle);
cread_16s (fh, &GSPtr->velocity.vector.width);
cread_16s (fh, &GSPtr->velocity.vector.height);
cread_16s (fh, &GSPtr->velocity.fract.width);
cread_16s (fh, &GSPtr->velocity.fract.height);
cread_16s (fh, &GSPtr->velocity.error.width);
cread_16s (fh, &GSPtr->velocity.error.height);
cread_16s (fh, &GSPtr->velocity.incr.width);
cread_16s (fh, &GSPtr->velocity.incr.height);
cread_16 (fh, NULL); /* VELOCITY_DESC padding */
cread_32 (fh, &GSPtr->BattleGroupRef);
DummyLoadQueue (&GSPtr->avail_race_q, fh);
DummyLoadQueue (&GSPtr->npc_built_ship_q, fh);
// Not loading ip_group_q, was not there originally
DummyLoadQueue (&GSPtr->encounter_q, fh);
DummyLoadQueue (&GSPtr->built_ship_q, fh);
cread_a8 (fh, oldstate, LEGACY_GAMESTATE_SIZE);
InterpretLegacyGameState (GSPtr->GameState, oldstate);
cread_8 (fh, NULL); /* GAME_STATE alignment padding */
}
static BOOLEAN
LoadSisState (SIS_STATE *SSPtr, void *fp)
{
if (
read_32s (fp, &SSPtr->log_x) != 1 ||
read_32s (fp, &SSPtr->log_y) != 1 ||
read_32 (fp, &SSPtr->ResUnits) != 1 ||
read_32 (fp, &SSPtr->FuelOnBoard) != 1 ||
read_16 (fp, &SSPtr->CrewEnlisted) != 1 ||
read_16 (fp, &SSPtr->TotalElementMass) != 1 ||
read_16 (fp, &SSPtr->TotalBioMass) != 1 ||
read_a8 (fp, SSPtr->ModuleSlots, NUM_MODULE_SLOTS) != 1 ||
read_a8 (fp, SSPtr->DriveSlots, NUM_DRIVE_SLOTS) != 1 ||
read_a8 (fp, SSPtr->JetSlots, NUM_JET_SLOTS) != 1 ||
read_8 (fp, &SSPtr->NumLanders) != 1 ||
read_a16 (fp, SSPtr->ElementAmounts, NUM_ELEMENT_CATEGORIES) != 1 ||
read_str (fp, SSPtr->ShipName, SIS_NAME_SIZE) != 1 ||
read_str (fp, SSPtr->CommanderName, SIS_NAME_SIZE) != 1 ||
read_str (fp, SSPtr->PlanetName, SIS_NAME_SIZE) != 1 ||
read_16 (fp, NULL) != 1 /* padding */
)
return FALSE;
else
return TRUE;
}
static BOOLEAN
LoadSummary (SUMMARY_DESC *SummPtr, void *fp)
{
if (!LoadSisState (&SummPtr->SS, fp))
return FALSE;
if (
read_8 (fp, &SummPtr->Activity) != 1 ||
read_8 (fp, &SummPtr->Flags) != 1 ||
read_8 (fp, &SummPtr->day_index) != 1 ||
read_8 (fp, &SummPtr->month_index) != 1 ||
read_16 (fp, &SummPtr->year_index) != 1 ||
read_8 (fp, &SummPtr->MCreditLo) != 1 ||
read_8 (fp, &SummPtr->MCreditHi) != 1 ||
read_8 (fp, &SummPtr->NumShips) != 1 ||
read_8 (fp, &SummPtr->NumDevices) != 1 ||
read_a8 (fp, SummPtr->ShipList, MAX_BUILT_SHIPS) != 1 ||
read_a8 (fp, SummPtr->DeviceList, MAX_EXCLUSIVE_DEVICES) != 1 ||
read_16 (fp, NULL) != 1 /* padding */
)
return FALSE;
else
return TRUE;
}
static void
LoadStarDesc (STAR_DESC *SDPtr, DECODE_REF fh)
{
cread_16s(fh, &SDPtr->star_pt.x);
cread_16s(fh, &SDPtr->star_pt.y);
cread_8 (fh, &SDPtr->Type);
cread_8 (fh, &SDPtr->Index);
cread_8 (fh, &SDPtr->Prefix);
cread_8 (fh, &SDPtr->Postfix);
}
BOOLEAN
LoadLegacyGame (COUNT which_game, SUMMARY_DESC *SummPtr)
{
uio_Stream *in_fp;
char file[PATH_MAX];
char buf[256];
SUMMARY_DESC loc_sd;
GAME_STATE_FILE *fp;
DECODE_REF fh;
COUNT num_links;
STAR_DESC SD;
ACTIVITY Activity;
sprintf (file, "starcon2.%02u", which_game);
in_fp = res_OpenResFile (saveDir, file, "rb");
if (!in_fp)
return FALSE;
loc_sd.SaveName[0] = '\0';
if (!LoadSummary (&loc_sd, in_fp))
{
log_add (log_Error, "Warning: Savegame is corrupt");
res_CloseResFile (in_fp);
return FALSE;
}
if (!SummPtr)
{
SummPtr = &loc_sd;
}
else
{ // only need summary for displaying to user
memcpy (SummPtr, &loc_sd, sizeof (*SummPtr));
res_CloseResFile (in_fp);
return TRUE;
}
// Crude check for big-endian/little-endian incompatibilities.
// year_index is suitable as it's a multi-byte value within
// a specific recognisable range.
if (SummPtr->year_index < START_YEAR ||
SummPtr->year_index >= START_YEAR +
YEARS_TO_KOHRAH_VICTORY + 1 /* Utwig intervention */ +
1 /* time to destroy all races, plenty */ +
25 /* for cheaters */)
{
log_add (log_Error, "Warning: Savegame corrupt or from "
"an incompatible platform.");
res_CloseResFile (in_fp);
return FALSE;
}
GlobData.SIS_state = SummPtr->SS;
if ((fh = copen (in_fp, FILE_STREAM, STREAM_READ)) == 0)
{
res_CloseResFile (in_fp);
return FALSE;
}
ReinitQueue (&GLOBAL (GameClock.event_q));
ReinitQueue (&GLOBAL (encounter_q));
ReinitQueue (&GLOBAL (ip_group_q));
ReinitQueue (&GLOBAL (npc_built_ship_q));
ReinitQueue (&GLOBAL (built_ship_q));
memset (&GLOBAL (GameState[0]), 0, sizeof (GLOBAL (GameState)));
Activity = GLOBAL (CurrentActivity);
LoadGameState (&GlobData.Game_state, fh);
NextActivity = GLOBAL (CurrentActivity);
GLOBAL (CurrentActivity) = Activity;
LoadRaceQueue (fh, &GLOBAL (avail_race_q));
// START_INTERPLANETARY is only set when saving from Homeworld
// encounter screen. When the game is loaded, the
// GenerateOrbitalFunction for the current star system will
// create the encounter anew and populate the npc queue.
if (!(NextActivity & START_INTERPLANETARY))
{
if (NextActivity & START_ENCOUNTER)
LoadShipQueue (fh, &GLOBAL (npc_built_ship_q));
else if (LOBYTE (NextActivity) == IN_INTERPLANETARY)
// XXX: Technically, this queue does not need to be
// saved/loaded at all. IP groups will be reloaded
// from group state files. But the original code did,
// and so will we until we can prove we do not need to.
LoadGroupQueue (fh, &GLOBAL (ip_group_q));
else
// XXX: The empty queue read is only needed to maintain
// the savegame compatibility
LoadEmptyQueue (fh);
}
LoadShipQueue (fh, &GLOBAL (built_ship_q));
// Load the game events (compressed)
cread_16 (fh, &num_links);
{
#ifdef DEBUG_LOAD
log_add (log_Debug, "EVENTS:");
#endif /* DEBUG_LOAD */
while (num_links--)
{
HEVENT hEvent;
EVENT *EventPtr;
hEvent = AllocEvent ();
LockEvent (hEvent, &EventPtr);
LoadEvent (EventPtr, fh);
#ifdef DEBUG_LOAD
log_add (log_Debug, "\t%u/%u/%u -- %u",
EventPtr->month_index,
EventPtr->day_index,
EventPtr->year_index,
EventPtr->func_index);
#endif /* DEBUG_LOAD */
UnlockEvent (hEvent);
PutEvent (hEvent);
}
}
// Load the encounters (black globes in HS/QS (compressed))
cread_16 (fh, &num_links);
{
while (num_links--)
{
HENCOUNTER hEncounter;
ENCOUNTER *EncounterPtr;
hEncounter = AllocEncounter ();
LockEncounter (hEncounter, &EncounterPtr);
LoadEncounter (EncounterPtr, fh);
UnlockEncounter (hEncounter);
PutEncounter (hEncounter);
}
}
// Copy the star info file from the compressed stream
fp = OpenStateFile (STARINFO_FILE, "wb");
if (fp)
{
DWORD flen;
cread_32 (fh, &flen);
while (flen)
{
COUNT num_bytes;
num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen;
cread (buf, num_bytes, 1, fh);
WriteStateFile (buf, num_bytes, 1, fp);
flen -= num_bytes;
}
CloseStateFile (fp);
}
// Copy the defined groupinfo file from the compressed stream
fp = OpenStateFile (DEFGRPINFO_FILE, "wb");
if (fp)
{
DWORD flen;
cread_32 (fh, &flen);
while (flen)
{
COUNT num_bytes;
num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen;
cread (buf, num_bytes, 1, fh);
WriteStateFile (buf, num_bytes, 1, fp);
flen -= num_bytes;
}
CloseStateFile (fp);
}
// Copy the random groupinfo file from the compressed stream
fp = OpenStateFile (RANDGRPINFO_FILE, "wb");
if (fp)
{
DWORD flen;
cread_32 (fh, &flen);
while (flen)
{
COUNT num_bytes;
num_bytes = flen >= sizeof (buf) ? sizeof (buf) : (COUNT)flen;
cread (buf, num_bytes, 1, fh);
WriteStateFile (buf, num_bytes, 1, fp);
flen -= num_bytes;
}
CloseStateFile (fp);
}
LoadStarDesc (&SD, fh);
cclose (fh);
res_CloseResFile (in_fp);
EncounterGroup = 0;
EncounterRace = -1;
ReinitQueue (&race_q[0]);
ReinitQueue (&race_q[1]);
CurStarDescPtr = FindStar (NULL, &SD.star_pt, 0, 0);
if (!(NextActivity & START_ENCOUNTER)
&& LOBYTE (NextActivity) == IN_INTERPLANETARY)
NextActivity |= START_INTERPLANETARY;
return TRUE;
}
+1 -1
View File
@@ -23,9 +23,9 @@
#include "../encount.h"
#include "../gamestr.h"
#include "../controls.h"
#include "../save.h"
#include "../settings.h"
#include "../shipcont.h"
#include "../load.h"
#include "../setup.h"
#include "../state.h"
#include "../sis.h"
+1 -1
View File
@@ -30,13 +30,13 @@
#include "../nameref.h"
#include "../resinst.h"
#include "../settings.h"
#include "../load.h"
#include "../util.h"
#include "../process.h"
#include "../setup.h"
#include "../sounds.h"
#include "../state.h"
#include "../sis.h"
#include "../save.h"
#include "options.h"
#include "libs/graphics/gfx_common.h"
#include "libs/graphics/drawable.h"
+1 -1
View File
@@ -37,11 +37,11 @@
#include "../ipdisp.h"
#include "../grpinfo.h"
#include "../process.h"
#include "../load.h"
#include "../setup.h"
#include "../sounds.h"
#include "../state.h"
#include "../uqmdebug.h"
#include "../save.h"
#include "options.h"
#include "libs/graphics/gfx_common.h"
#include "libs/mathlib.h"
+1 -1
View File
@@ -30,8 +30,8 @@
#include "supermelee/melee.h"
#include "resinst.h"
#include "nameref.h"
#include "save.h"
#include "settings.h"
#include "load.h"
#include "setup.h"
#include "sounds.h"
#include "setupmenu.h"
+463 -486
View File
File diff suppressed because it is too large Load Diff
+46 -3
View File
@@ -17,16 +17,59 @@
#ifndef _SAVE_H
#define _SAVE_H
#include "sis.h"
// for SUMMARY_DESC
#include "sis.h" // SUMMARY_DESC includes SIS_STATE in it
#include "globdata.h"
#include "libs/compiler.h"
#if defined(__cplusplus)
extern "C" {
#endif
// XXX: Theoretically, a player can have 17 devices on board without
// cheating. We only provide
// room for 16 below, which is not really a problem since this
// is only used for displaying savegame summaries. There is also
// room for only 16 devices on screen.
#define MAX_EXCLUSIVE_DEVICES 16
#define SAVE_NAME_SIZE 64
// The savefile tag numbers.
#define SAVEFILE_TAG 0x01534d55 // "UMS\x01": UQM Save version 1
#define SUMMARY_TAG 0x6d6d7553 // "Summ": Summary. Must be first!
#define GLOBAL_STATE_TAG 0x74536c47 // "GlSt": Global State. Must be 2nd!
#define GAME_STATE_TAG 0x74536d47 // "GmSt": Game State Bits. Must be 3rd!
#define EVENTS_TAG 0x73747645 // "Evts": Events
#define ENCOUNTERS_TAG 0x74636e45 // "Enct": Encounters
#define RACE_Q_TAG 0x51636152 // "RacQ": avail_race_q
#define IP_GRP_Q_TAG 0x51704749 // "IGpQ": ip_group_q
#define NPC_SHIP_Q_TAG 0x5163704e // "NpcQ": npc_built_ship_q
#define SHIP_Q_TAG 0x51706853 // "ShpQ": built_ship_q
#define STAR_TAG 0x72617453 // "Star": STAR_DESC
#define SCAN_TAG 0x6e616353 // "Scan": Scan Masks (stuff picked up)
#define BATTLE_GROUP_TAG 0x70477442 // "BtGp": Battle Group definition
#define GROUP_LIST_TAG 0x73707247 // "Grps": Group List
typedef struct
{
SIS_STATE SS;
BYTE Activity;
BYTE Flags;
BYTE day_index, month_index;
COUNT year_index;
BYTE MCreditLo, MCreditHi;
BYTE NumShips, NumDevices;
BYTE ShipList[MAX_BUILT_SHIPS];
BYTE DeviceList[MAX_EXCLUSIVE_DEVICES];
UNICODE SaveName[SAVE_NAME_SIZE];
} SUMMARY_DESC;
extern ACTIVITY NextActivity;
extern BOOLEAN LoadGame (COUNT which_game, SUMMARY_DESC *summary_desc);
extern BOOLEAN LoadLegacyGame (COUNT which_game, SUMMARY_DESC *summary_desc);
extern void SaveProblem (void);
extern BOOLEAN SaveGame (COUNT which_game, SUMMARY_DESC *summary_desc);
extern BOOLEAN SaveGame (COUNT which_game, SUMMARY_DESC *summary_desc, const char *name);
#if defined(__cplusplus)
}
-20
View File
@@ -154,26 +154,6 @@ typedef struct
UNICODE PlanetName[SIS_NAME_SIZE];
} SIS_STATE;
// XXX: Theoretically, a player can have 17 devices on board without
// cheating. We only provide
// room for 16 below, which is not really a problem since this
// is only used for displaying savegame summaries. There is also
// room for only 16 devices on screen.
#define MAX_EXCLUSIVE_DEVICES 16
typedef struct
{
SIS_STATE SS;
BYTE Activity;
BYTE Flags;
BYTE day_index, month_index;
COUNT year_index;
BYTE MCreditLo, MCreditHi;
BYTE NumShips, NumDevices;
BYTE ShipList[MAX_BUILT_SHIPS];
BYTE DeviceList[MAX_EXCLUSIVE_DEVICES];
} SUMMARY_DESC;
#define OVERRIDE_LANDER_FLAGS (1 << 7)
#define AFTER_BOMB_INSTALLED (1 << 7)
+1 -1
View File
@@ -22,7 +22,7 @@
#include "starmap.h"
#include "comm.h"
#include "gamestr.h"
#include "load.h"
#include "save.h"
#include "starbase.h"
#include "sis.h"
#include "resinst.h"
+1 -1
View File
@@ -24,10 +24,10 @@
#include "gameev.h"
#include "types.h"
#include "globdata.h"
#include "load.h"
#include "resinst.h"
#include "restart.h"
#include "starbase.h"
#include "save.h"
#include "setup.h"
#include "master.h"
#include "controls.h"