home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Game Killer
/
Game_Killer.bin
/
518.WGLOBAL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-20
|
28KB
|
1,002 lines
/*
---------------------------------------------------------------------------
| MapGlobal class | (c) Oct 1992 Sysma Automatisering |
---------------------------------------------------------------------------
| Version 1.0 06/10/92 | First implementation. |
| | J.P. Dijkstra, M.Sc. |
| Version 1.01 07/10/92 | Added automatic renaming of the game |
| | maps file during format conversions. |
| | J.P. Dijkstra, M.Sc. |
| Version 1.05 11/10/92 | Removed all explicit references to far |
| | pointers and changed the memory model to |
| | large. |
| | J.P. Dijkstra, M.Sc. |
| Version 1.5 12/10/92 | Added functions which enable copying and |
| | storing modified GameMaps inside a |
| | MapGlobalRec instance. |
| | J.P. Dijkstra, M.Sc. |
| Version 1.6 20/10/92 | Removed the list of map headers from the |
| | map data, since it was only used by one |
| | command and saves about 2K of memory. |
| | J.P. Dijkstra, M.Sc. |
---------------------------------------------------------------------------
| The MapGlobal class contains the logic to process the map files as a |
| single unit. In those files the actual maps are stored. A map consists |
| of four separate data blocks. Each block is stored in the maps file |
| separately. The header block contains the sizes and start offsets of |
| the other three blocks, together with some descriptive information |
| about the map itself. The size of the header is fixed and it's start |
| offset is stored in the map head file. |
| The other three blocks contain compressed data. The first block |
| contains the maze data, the second one the objects inside the maze. The |
| function of the third block is unknown at present and contains at the |
| moment only zeros for all maps. |
| As stated, the start offsets of all map headers is stored in the map |
| head file. The format is an array of long ints, preseded by a word |
| containing the so called magic value, used in the (de)compression |
| algorithms of the version 1.0 format. |
| The logic in this class consists of routines to open, create and close |
| the map files, and to load, save and (de)compress single maps. |
---------------------------------------------------------------------------
*/
#include "wolfmap.h"
#include "dos.h"
#include "io.h"
#include "fcntl.h"
#include "alloc.h"
#include "string.h"
#include "errno.h"
/*
---------------------------------------------------------------------------
| Local data structures and constants |
---------------------------------------------------------------------------
| Struct / Class name | Description. |
| Field name | Description. |
---------------------------------------------------------------------------
| Struct / Class name | Description. |
| Field name | Description. |
---------------------------------------------------------------------------
*/
#define WorkGameMaps "GameMaps.Wrk"
#define WorkMapHead "MapHead.Wrk"
#define BackupGameMaps "GameMaps.Bak"
#define BackupMapHead "MapHead.Bak"
#define lGameMaps "GameMaps.Loc"
#define lMapHead "MapHead.Loc"
#define c11GameMaps "GameMaps.Wl6"
#define c10GameMaps "MapTemp.Wl6"
#define cMapHead "MapHead.Wl6"
#define s11GameMaps "GameMaps.Wl1"
#define s10GameMaps "MapTemp.Wl1"
#define sMapHead "MapHead.Wl1"
static unsigned long Id = 0x21444921;
const unsigned IdSize = 4;
/*
---------------------------------------------------------------------------
| Local functions to implement elementary operations. |
---------------------------------------------------------------------------
| CopyWorkFiles | This function takes care of copying the |
| | origional files to the backup files, the |
| | work files to the origional files and to |
| | delete the work files upon success. |
---------------------------------------------------------------------------
*/
static int CopyWorkFiles (char *GameMapsName, char *MapHeadName)
{
//
// Try to delete the backups of the origional files, because they may
// have been left over from a previous session.
//
if ( unlink (BackupGameMaps) == -1 && errno != ENOENT)
{
return errDelete;
}
if ( unlink (BackupMapHead) == -1 && errno != ENOENT)
{
return errDelete;
}
//
// The backup files have been deleted. Now rename the origionals to
// their backup names.
//
if ( rename (GameMapsName, BackupGameMaps) == -1 && errno != ENOENT )
{
return errBackup;
}
if ( rename (MapHeadName, BackupMapHead) == -1 && errno != ENOENT )
{
//
// Renaming of the MapHead file failed, so reverse the renaming of
// the GameMaps file.
//
rename (BackupGameMaps, GameMapsName);
return errBackup;
}
//
// The origional files have been renamed to their respective backup
// names, so now rename the temp files to the origional names.
//
if ( rename (WorkGameMaps, GameMapsName) == -1 )
{
//
// Renaming the GameMaps file failed, so we rename the backup files
// back to their respective origional names. We don't test for
// success or failure here, since these files have already been
// successfully renamed once.
//
rename (BackupGameMaps, GameMapsName);
rename (BackupMapHead, MapHeadName);
return errCopy;
}
if ( rename (WorkMapHead, MapHeadName) == -1 )
{
//
// Renaming of the MapHead file failed, so we rename the backup
// files back to their respective origional names. We don't test
// for success or failure, since these files have already been
// renamed once.
//
rename (GameMapsName, WorkGameMaps);
rename (BackupGameMaps, GameMapsName);
rename (BackupMapHead, MapHeadName);
return errCopy;
}
//
// All files have been renamed successfully, so we now have a set of
// backup files, a new set of origionals and no temp files left.
//
return errOk;
}
/*
---------------------------------------------------------------------------
| Public functions to implement the desired API. |
---------------------------------------------------------------------------
| Function name | Description. |
---------------------------------------------------------------------------
*/
MapGlobalRec::MapGlobalRec ()
{
//
// Initialize all fields with default values.
//
NrMaps = 0;
NrMapsStored = 0;
Offsets = NULL;
MapStore = NULL;
MagicValue = 0x0000;
MapsHandle = -1;
WorkMapsHandle = -1;
ErrorCode = errOk;
CurrentVersion = cUndetermined;
}
MapGlobalRec::~MapGlobalRec ()
{
//
// Use the Close () function to shutdown this instance.
//
Close ();
}
int MapGlobalRec::SetError (int Error)
{
int OldError = ErrorCode;
ErrorCode = Error;
return OldError;
}
int MapGlobalRec::MapPossible (unsigned MapNr)
{
//
// Determine if the given map slot is possible to load or save from.
//
return MapNr < NrMaps && Offsets != NULL ? cTrue : cFalse;
}
int MapGlobalRec::MapAvailable (unsigned MapNr)
{
//
// Determine if the given map slot is in fact available in the maps file.
//
return MapPossible (MapNr) && Offsets [MapNr] != 0 ? cTrue : cFalse;
}
int MapGlobalRec::Open (unsigned Version)
{
int Handle = -1;
//
// If the version is not determined yet, try the complete version first.
//
if (Version == cUndetermined)
{
//
// Set version and file names.
//
CurrentVersion = cComplete;
strcpy (MapHeadName, cMapHead);
strcpy (GameMapsName, c11GameMaps);
//
// Try opening the two files.
//
Handle = _open (MapHeadName, O_RDONLY);
MapsHandle = _open (GameMapsName, O_RDONLY);
//
// Continue processing if the two files are opened.
//
if (Handle != -1 && MapsHandle != -1) goto FilesOpened;
if (Handle != -1)
{
//
// The map head file is open, so try the second possible name for
// the game maps file.
//
strcpy (GameMapsName, c10GameMaps);
MapsHandle = _open (GameMapsName, O_RDONLY);
//
// This time successfull, so continue processing.
//
if (MapsHandle != -1) goto FilesOpened;
close (Handle);
}
//
// The complete version could not be opened, so try the shareware
// version now.
//
Version = cShareware;
}
//
// Set the correct file names for the requested version.
//
switch (Version)
{
case cComplete:
strcpy (MapHeadName, cMapHead);
strcpy (GameMapsName, c11GameMaps);
break;
case cShareware:
strcpy (MapHeadName, sMapHead);
strcpy (GameMapsName, s11GameMaps);
break;
case cLocal:
strcpy (MapHeadName, lMapHead);
strcpy (GameMapsName, lGameMaps);
break;
default:
SetError (errNoSuchVersion);
return errNoSuchVersion;
}
//
// Set the version and try opening the two files.
//
CurrentVersion = Version;
Handle = _open (MapHeadName, O_RDONLY);
MapsHandle = _open (GameMapsName, O_RDONLY);
//
// Continue processing if the two files are opened.
//
if (Handle != -1 && MapsHandle != -1) goto FilesOpened;
if (Handle != -1)
{
//
// The map head file is open, so try the second possible name for the
// game maps file.
//
switch (Version)
{
case cComplete: strcpy (GameMapsName, c10GameMaps); break;
case cShareware: strcpy (GameMapsName, s10GameMaps); break;
}
MapsHandle = _open (GameMapsName, O_RDONLY);
//
// This time successfull, so continue processing.
//
if (MapsHandle != -1) goto FilesOpened;
close (Handle);
}
//
// The requested version is not available, so return an error.
//
SetError (errNoSuchVersion);
return errNoSuchVersion;
FilesOpened:
//
// From this point on the map head file and the game maps file are both
// opened for reading. Now first determine the size of the map head file,
// as this determines the max. number of maps stored.
//
long Size = lseek (Handle, 0, SEEK_END);
int Error = errOk;
//
// Allocate memory, but only if the map head file checks out ok.
//
if ( ((Size-2) & 0x0003) == 0)
{
NrMaps = (Size - 2) >> 2;
Offsets = (long *) calloc (NrMaps, sizeof (long) );
MapStore = (GameMapRec **) calloc (NrMaps, sizeof (GameMapRec *) );
if (Offsets == NULL || MapStore == NULL)
{
Error = errNoMemory;
}
}
else
{
Error = errNoMapHeadFile;
}
//
// Read the magic value and the start positions of every map header from
// the map head file.
//
if (Error == errOk) Error = ReadData (Handle, 0, &MagicValue, 2);
if (Error == errOk) Error = ReadData (Handle, 2, Offsets, NrMaps * sizeof (long) );
//
// Close the map head file and return the error status.
//
close (Handle);
if (Error != errOk) SetError (Error);
return Error;
}
int MapGlobalRec::Create (unsigned Version)
{
int Error = errOk;
//
// Set the correct file names for the two files to reflect the chosen
// version.
//
switch (Version)
{
case cComplete:
strcpy (MapHeadName, cMapHead);
strcpy (GameMapsName, c11GameMaps);
break;
case cShareware:
strcpy (MapHeadName, sMapHead);
strcpy (GameMapsName, s11GameMaps);
break;
case cLocal:
strcpy (MapHeadName, lMapHead);
strcpy (GameMapsName, lGameMaps);
break;
default:
Error = errNoSuchVersion;
break;
}
if (Error == errOk)
{
//
// Set the created version and try creating the game maps work file.
//
CurrentVersion = Version;
WorkMapsHandle = _creat (WorkGameMaps, 0);
//
// If the work file is created, create the memory blocks and write a
// leader of our own to this work file.
//
if (WorkMapsHandle != -1)
{
NrMaps = cMapCount;
MagicValue = cMagicValue;
Offsets = (long *) calloc (NrMaps, sizeof (long) );
MapStore = (GameMapRec **) calloc (NrMaps, sizeof (GameMapRec *) );
if (Offsets != NULL && MapStore != NULL)
{
//
// The memory blocks are allocated. Now write our own leader.
//
long Pos;
char Signature [256];
sprintf (Signature, "Maps created with %s\r\n%s\r\n\X1A", cVersion, cCopyright);
Error = WriteData (WorkMapsHandle, &Pos, Signature, strlen (Signature) + 1);
}
else
{
Error = errNoMemory;
}
}
else
{
Error = errCreate;
}
}
//
// If an error occured, process it. Then return the error status.
//
if (Error != errOk) SetError (Error);
return Error;
}
int MapGlobalRec::OpenWork ()
{
//
// Try creating the maps work file.
//
WorkMapsHandle = _creat (WorkGameMaps, 0);
//
// If the work file is created, copy the leader of the origional file to
// this work file.
//
int Error = WorkMapsHandle == -1 ? errCreate : errOk;
long *Pos = Offsets;
int Count = MapCount ();
long Size = 0x7FFFFFFF;
while (Error == errOk && Count-- > 0)
{
//
// Only track maps that are actually present.
//
if (*Pos != 0)
{
MapHeaderRec Hdr;
Error = ReadData (MapsHandle, *Pos, &Hdr, sizeof (MapHeaderRec) );
if (Error == errOk)
{
if (Size > Hdr.StartMaze) Size = Hdr.StartMaze;
if (Size > Hdr.StartObjects) Size = Hdr.StartObjects;
if (Size > Hdr.StartUnknown) Size = Hdr.StartUnknown;
if (Size > *Pos) Size = *Pos;
}
}
Pos++;
}
//
// Copy the leader, if there is one.
//
if (Error == errOk && Size > 0)
{
//
// Allocate a temporary block to hold the leader.
//
char *Leader = (char *) malloc (Size);
//
// Copy the leader from the maps file to the work file, using the
// temporary memory block. Then free the block again.
//
if (Leader != NULL)
{
long Pos;
if (Error == errOk) Error = ReadData (MapsHandle, 0, Leader, Size);
if (Error == errOk) Error = WriteData (WorkMapsHandle, &Pos, Leader, Size);
free (Leader);
}
else
{
Error = errNoMemory;
}
}
//
// If an error occured, process it. Then return the error status.
//
if (Error != errOk) SetError (Error);
return Error;
}
int MapGlobalRec::ConvertName (unsigned NewFormat)
{
//
// This function is intended for format conversion only. The name of the
// game maps file of Wolf3D version 1.0 differs from the one in other
// Wolf3D versions. This function changes this name by setting the new
// name in the local name slot.
// At this moment we only do this for the shareware version, since we
// don't know if the same holds true for the commercial version.
//
if (CurrentVersion == cShareware)
{
switch (NewFormat)
{
case cFormat10:
strcpy (GameMapsName, s10GameMaps);
break;
case cFormat11:
strcpy (GameMapsName, s11GameMaps);
break;
}
}
//
// Return Ok to indicate success.
//
return errOk;
}
int MapGlobalRec::Close ()
{
int Error = errOk;
//
// Close the maps file, if it is open.
//
if (MapsHandle != -1) close (MapsHandle);
//
// Close the maps work file, if it is open. Then process the files.
//
if (WorkMapsHandle != -1)
{
close (WorkMapsHandle);
//
// The maps work file is closed. Now create, save and close the offsets
// work file.
//
int Handle = _creat (WorkMapHead, 0);
if (Handle != -1)
{
long Pos;
if (Error == errOk) Error = WriteData (Handle, &Pos, &MagicValue, 2);
if (Error == errOk) Error = WriteData (Handle, &Pos, Offsets, NrMaps * sizeof (long));
close (Handle);
}
else
{
Error = errCreate;
}
//
// Now process the work files.
//
if (Error == errOk) Error = CopyWorkFiles (GameMapsName, MapHeadName);
//
// During the processing of the work files an error has occured. We
// will simply discard any changes in this case by deleting the work
// files.
//
if (Error != errOk)
{
unlink (WorkGameMaps);
unlink (WorkMapHead);
}
}
//
// Free any stored game maps in the maps store and free the store itself.
//
if (MapStore != NULL)
{
unsigned Map = 0;
while (Map < NrMaps)
{
if (MapStore [Map] != NULL) delete MapStore [Map];
Map++;
}
free (MapStore);
}
//
// Deallocate the memory, if allocated.
//
if (Offsets != NULL) free (Offsets);
//
// Initialize all fields to their default values.
//
Offsets = NULL;
MapStore = NULL;
MapsHandle = -1;
WorkMapsHandle = -1;
CurrentVersion = cUndetermined;
MagicValue = 0x0000;
NrMaps = 0;
NrMapsStored = 0;
//
// If an error occured, process it. Then return the error status.
//
if (Error != errOk) SetError (Error);
return Error;
}
int MapGlobalRec::Load (GameMapRec *Map, unsigned MapNr)
{
//
// Load the map using the open file handle and the Load member function
// of the GameMap, but only if the map is actually in the file.
//
int Error = MapAvailable (MapNr) ? Map->Load (MapsHandle, Offsets [MapNr]) : errMapNotPresent;
//
// If an error occured, process it. Then return the error status.
//
if (Error != errOk) SetError (Error);
return Error;
}
int MapGlobalRec::Save (GameMapRec *Map, unsigned MapNr)
{
//
// Save the map using the open file handle and the Load member function
// of the GameMap, adjusting the offset of map header in the process.
//
int Error = MapPossible (MapNr) ? Map->Save (WorkMapsHandle, &Offsets [MapNr]) : errMapNotPresent;
//
// If an error occured, process it. Then return the error status.
//
if (Error != errOk) SetError (Error);
return Error;
}
int MapGlobalRec::Compress (GameMapRec *Map, unsigned NewFormat)
{
//
// Determine current format if not done so already.
//
int Error = Map->Format () == cUndetermined ? Map->DetermineFormat () : errOk;
unsigned OldFormat = Map->Format ();
//
// Convert to the requested format. Since v1.1 format compression is done
// over v1.0 compressed data, we use a while loop to cover each stage.
//
while (Error == errOk && NewFormat != OldFormat)
{
if (NewFormat < OldFormat)
{
//
// Decompression is needed.
//
if (OldFormat == cFormat11) Error = Map->DecompressFormat11 ();
if (OldFormat == cFormat10) Error = Map->DecompressFormat10 (MagicValue);
if (Error == errOk) OldFormat--;
}
else
{
//
// Compression is needed.
//
if (OldFormat == cFormat10) Error = Map->CompressFormat11 ();
if (OldFormat == cDecompressed) Error = Map->CompressFormat10 (MagicValue);
if (Error == errOk) OldFormat++;
}
//
// If no error occured in this stage, set the new format in the GameMap.
//
if (Error == errOk) Map->SetFormat (OldFormat);
}
//
// If an error occured, process it. Then return the error status.
//
if (Error != errOk) SetError (Error);
return Error;
}
int MapGlobalRec::Add (GameMapRec *Map, unsigned MapNr)
{
int Error = errOk;
//
// Store the requested map. If another one is present, deallocate that
// one.
//
if ( MapPossible (MapNr) )
{
//
// First make sure we have a new, empty GameMapRec allocated.
//
if (MapStore [MapNr] != NULL)
{
MapStore [MapNr]->Close ();
NrMapsStored--;
}
else
{
MapStore [MapNr] = new GameMapRec;
if (MapStore [MapNr] == NULL) Error = errNoMemory;
}
//
// When the allocation is successfull, move the contents of the given
// source map to the newly created one.
//
if (Error == errOk)
{
Error = MapStore [MapNr]->Copy (Map);
if (Error == errOk) NrMapsStored++;
}
}
else
{
Error = errMapNotPresent;
}
//
// If an error occured, process it. Then return the error status.
//
if (Error != errOk) SetError (Error);
return Error;
}
int MapGlobalRec::InStore (unsigned MapNr)
{
return MapPossible (MapNr) && MapStore [MapNr] != NULL;
}
int MapGlobalRec::Copy (GameMapRec *Map, unsigned MapNr)
{
int Error = errOk;
//
// Deallocate the requested map if it is indeed stored.
//
if ( MapPossible (MapNr) )
{
if (MapStore [MapNr] != NULL)
{
Error = Map->Copy (MapStore [MapNr]);
}
}
else
{
Error = errMapNotPresent;
}
//
// If an error occured, process it. Then return the error status.
//
if (Error != errOk) SetError (Error);
return Error;
}
int MapGlobalRec::Delete (unsigned MapNr)
{
int Error = errOk;
//
// Deallocate the requested map if it is indeed stored.
//
if ( MapPossible (MapNr) )
{
if (MapStore [MapNr] != NULL)
{
delete MapStore [MapNr];
MapStore [MapNr] = NULL;
NrMapsStored--;
}
}
else
{
Error = errMapNotPresent;
}
//
// If an error occured, process it. Then return the error status.
//
if (Error != errOk) SetError (Error);
return Error;
}
int MapGlobalRec::DisplayHeaders (FILE *Stream, unsigned Columns)
{
//
// Initialize the various pointers and counters.
//
long *Ofs = Offsets;
unsigned MapNr = 0;
unsigned Count = 0;
unsigned Printed = 0;
int Error = errOk;
//
// First, determine how many maps are actually present.
//
while (MapNr++ < NrMaps)
{
if (*(Ofs++) != 0) Count++;
}
//
// Reinitialize the pointers.
//
Ofs = Offsets;
MapNr = 0;
//
// Simply display a message when no maps are present.
//
if (Count == 0)
{
fprintf (Stream, "Sorry, there are no maps present in this version.\n");
}
else
{
switch (Columns)
{
//
// Display the header information in one column.
//
case cOneColumn:
//
// Display column banner.
//
fprintf (Stream, "Map # Title Size\n");
fprintf (Stream, "===== ================ =======\n\n");
//
// Walk every map and display information on present maps.
//
while (Error == errOk && MapNr < NrMaps)
{
if (*Ofs != 0)
{
MapHeaderRec Hdr;
Error = ReadData (MapsHandle, *Ofs, &Hdr, sizeof (MapHeaderRec) );
if (Error == errOk) fprintf (Stream, "%5u %-16Fs [%02u,%02u]\n", MapNr, Hdr.Title, Hdr.SizeX, Hdr.SizeY);
}
Ofs++;
MapNr++;
}
break;
//
// Display the header information in two columns.
//
case cTwoColumns:
//
// Display column banners.
//
fprintf (Stream, "Map # Title Size Map # Title Size\n");
fprintf (Stream, "===== ================ ======= ===== ================ =======\n\n");
//
// Walk every map and display information on present maps.
//
while (Error == errOk && MapNr < NrMaps)
{
if (*Ofs != 0)
{
MapHeaderRec Hdr;
Error = ReadData (MapsHandle, *Ofs, &Hdr, sizeof (MapHeaderRec) );
if (Error == errOk)
{
if ( (Printed & 1) == 0 )
{
fprintf (Stream, "%5u %-16Fs [%02u,%02u] ", MapNr, Hdr.Title, Hdr.SizeX, Hdr.SizeY);
}
else
{
fprintf (Stream, "%5u %-16Fs [%02u,%02u]\n", MapNr, Hdr.Title, Hdr.SizeX, Hdr.SizeY);
}
}
Printed++;
}
Ofs++;
MapNr++;
}
//
// Force a new line if not done so already.
//
if ( (Printed & 1) != 0 ) fprintf (Stream, "\n");
break;
//
// Display short header information in three columns.
//
case cThreeColumns:
//
// Display column banners.
//
fprintf (Stream, "Map # Title Map # Title Map # Title\n");
fprintf (Stream, "===== ================ ===== ================ ===== ================\n\n");
//
// Walk every map and display information on present maps.
//
while (Error == errOk && MapNr < NrMaps)
{
if (*Ofs != 0)
{
MapHeaderRec Hdr;
Error = ReadData (MapsHandle, *Ofs, &Hdr, sizeof (MapHeaderRec) );
if (Error == errOk)
{
if ( (Printed % 3) != 2 )
{
fprintf (Stream, "%5u %-16Fs ", MapNr, Hdr.Title);
}
else
{
fprintf (Stream, "%5u %-16Fs\n", MapNr, Hdr.Title);
}
}
Printed++;
}
//
// Advance to next map.
//
Ofs++;
MapNr++;
}
//
// Force a new line if not done so already.
//
if ( (Printed % 3) != 0 ) fprintf (Stream, "\n");
break;
}
}
//
// Return Ok to indicate success.
//
return errOk;
}