Merge branch 'master' of ssh://git.code.sf.net/p/sc2/uqm
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
.DS_Store
|
||||
*.app
|
||||
build.vars
|
||||
config.state
|
||||
config_unix.h
|
||||
obj
|
||||
uqm-debug
|
||||
uqm-wrapper
|
||||
uqm
|
||||
@@ -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)
|
||||
|
||||
@@ -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=''
|
||||
|
||||
|
||||
@@ -1831,7 +1831,7 @@ Empty Slot
|
||||
|
||||
|
||||
#(Saved Game - Date:)
|
||||
Saved Game - Date:
|
||||
Saved Game
|
||||
|
||||
|
||||
#(Sound) -- OPTION_STRING_BASE
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+46
-3
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user