home *** CD-ROM | disk | FTP | other *** search
/ Game Killer / Game_Killer.bin / 518.WGLOBAL.C < prev    next >
C/C++ Source or Header  |  1992-10-20  |  28KB  |  1,002 lines

  1. /*
  2.  
  3. ---------------------------------------------------------------------------
  4. | MapGlobal class              |    (c) Oct 1992 Sysma Automatisering     |
  5. ---------------------------------------------------------------------------
  6. | Version 1.0         06/10/92 | First implementation.                    |
  7. |                              | J.P. Dijkstra, M.Sc.                     |
  8. | Version 1.01        07/10/92 | Added automatic renaming of the game     |
  9. |                              | maps file during format conversions.     |
  10. |                              | J.P. Dijkstra, M.Sc.                     |
  11. | Version 1.05        11/10/92 | Removed all explicit references to far   |
  12. |                              | pointers and changed the memory model to |
  13. |                              | large.                                   |
  14. |                              | J.P. Dijkstra, M.Sc.                     |
  15. | Version 1.5         12/10/92 | Added functions which enable copying and |
  16. |                              | storing modified GameMaps inside a       |
  17. |                              | MapGlobalRec instance.                   |
  18. |                              | J.P. Dijkstra, M.Sc.                     |
  19. | Version 1.6         20/10/92 | Removed the list of map headers from the |
  20. |                              | map data, since it was only used by one  |
  21. |                              | command and saves about 2K of memory.    |
  22. |                              | J.P. Dijkstra, M.Sc.                     |
  23. ---------------------------------------------------------------------------
  24. | The MapGlobal class contains the logic to process the map files as a    |
  25. | single unit. In those files the actual maps are stored. A map consists  |
  26. | of four separate data blocks. Each block is stored in the maps file     |
  27. | separately. The header block contains the sizes and start offsets of    |
  28. | the other three blocks, together with some descriptive information      |
  29. | about the map itself. The size of the header is fixed and it's start    |
  30. | offset is stored in the map head file.                                  |
  31. | The other three blocks contain compressed data. The first block         |
  32. | contains the maze data, the second one the objects inside the maze. The |
  33. | function of the third block is unknown at present and contains at the   |
  34. | moment only zeros for all maps.                                         |
  35. | As stated, the start offsets of all map headers is stored in the map    |
  36. | head file. The format is an array of long ints, preseded by a word      |
  37. | containing the so called magic value, used in the (de)compression       |
  38. | algorithms of the version 1.0 format.                                   |
  39. | The logic in this class consists of routines to open, create and close  |
  40. | the map files, and to load, save and (de)compress single maps.          |
  41. ---------------------------------------------------------------------------
  42.  
  43. */
  44.  
  45. #include "wolfmap.h"
  46. #include "dos.h"
  47. #include "io.h"
  48. #include "fcntl.h"
  49. #include "alloc.h"
  50. #include "string.h"
  51. #include "errno.h"
  52.  
  53. /*
  54.  
  55. ---------------------------------------------------------------------------
  56. | Local data structures and constants                                     |
  57. ---------------------------------------------------------------------------
  58. | Struct / Class name         | Description.                              |
  59. |   Field name                | Description.                              |
  60. ---------------------------------------------------------------------------
  61. | Struct / Class name         | Description.                              |
  62. |   Field name                | Description.                              |
  63. ---------------------------------------------------------------------------
  64.  
  65. */
  66.  
  67. #define WorkGameMaps   "GameMaps.Wrk"
  68. #define WorkMapHead    "MapHead.Wrk"
  69. #define BackupGameMaps "GameMaps.Bak"
  70. #define BackupMapHead  "MapHead.Bak"
  71. #define lGameMaps      "GameMaps.Loc"
  72. #define lMapHead       "MapHead.Loc"
  73. #define c11GameMaps    "GameMaps.Wl6"
  74. #define c10GameMaps    "MapTemp.Wl6"
  75. #define cMapHead       "MapHead.Wl6"
  76. #define s11GameMaps    "GameMaps.Wl1"
  77. #define s10GameMaps    "MapTemp.Wl1"
  78. #define sMapHead       "MapHead.Wl1"
  79.  
  80. static unsigned long Id        = 0x21444921;
  81. const  unsigned      IdSize    = 4;
  82.  
  83. /*
  84.  
  85. ---------------------------------------------------------------------------
  86. | Local functions to implement elementary operations.                     |
  87. ---------------------------------------------------------------------------
  88. | CopyWorkFiles               | This function takes care of copying the   |
  89. |                             | origional files to the backup files, the  |
  90. |                             | work files to the origional files and to  |
  91. |                             | delete the work files upon success.       |
  92. ---------------------------------------------------------------------------
  93.  
  94. */
  95.  
  96. static int CopyWorkFiles (char *GameMapsName, char *MapHeadName)
  97. {
  98.   //
  99.   //   Try to delete the backups of the origional files, because they may
  100.   //   have been left over from a previous session.
  101.   //
  102.   if ( unlink (BackupGameMaps) == -1 && errno != ENOENT)
  103.   {
  104.     return errDelete;
  105.   }
  106.  
  107.   if ( unlink (BackupMapHead) == -1 && errno != ENOENT)
  108.   {
  109.     return errDelete;
  110.   }
  111.  
  112.   //
  113.   //   The backup files have been deleted. Now rename the origionals to
  114.   //   their backup names.
  115.   //
  116.   if ( rename (GameMapsName, BackupGameMaps) == -1 && errno != ENOENT )
  117.   {
  118.     return errBackup;
  119.   }
  120.  
  121.   if ( rename (MapHeadName, BackupMapHead) == -1 && errno != ENOENT )
  122.   {
  123.     //
  124.     //   Renaming of the MapHead file failed, so reverse the renaming of
  125.     //   the GameMaps file.
  126.     //
  127.     rename (BackupGameMaps, GameMapsName);
  128.     return errBackup;
  129.   }
  130.  
  131.   //
  132.   //   The origional files have been renamed to their respective backup
  133.   //   names, so now rename the temp files to the origional names.
  134.   //
  135.   if ( rename (WorkGameMaps, GameMapsName) == -1 )
  136.   {
  137.     //
  138.     //   Renaming the GameMaps file failed, so we rename the backup files
  139.     //   back to their respective origional names. We don't test for
  140.     //   success or failure here, since these files have already been
  141.     //   successfully renamed once.
  142.     //
  143.     rename (BackupGameMaps, GameMapsName);
  144.     rename (BackupMapHead, MapHeadName);
  145.     return errCopy;
  146.   }
  147.  
  148.   if ( rename (WorkMapHead, MapHeadName) == -1 )
  149.   {
  150.     //
  151.     //   Renaming of the MapHead file failed, so we rename the backup
  152.     //   files back to their respective origional names. We don't test
  153.     //   for success or failure, since these files have already been
  154.     //   renamed once.
  155.     //
  156.     rename (GameMapsName, WorkGameMaps);
  157.     rename (BackupGameMaps, GameMapsName);
  158.     rename (BackupMapHead, MapHeadName);
  159.     return errCopy;
  160.   }
  161.  
  162.   //
  163.   //   All files have been renamed successfully, so we now have a set of
  164.   //   backup files, a new set of origionals and no temp files left.
  165.   //
  166.   return errOk;
  167. }
  168.  
  169. /*
  170.  
  171. ---------------------------------------------------------------------------
  172. | Public functions to implement the desired API.                          |
  173. ---------------------------------------------------------------------------
  174. | Function name               | Description.                              |
  175. ---------------------------------------------------------------------------
  176.  
  177. */
  178.  
  179. MapGlobalRec::MapGlobalRec ()
  180. {
  181.   //
  182.   //   Initialize all fields with default values.
  183.   //
  184.   NrMaps         = 0;
  185.   NrMapsStored   = 0;
  186.   Offsets        = NULL;
  187.   MapStore       = NULL;
  188.   MagicValue     = 0x0000;
  189.   MapsHandle     = -1;
  190.   WorkMapsHandle = -1;
  191.   ErrorCode      = errOk;
  192.   CurrentVersion = cUndetermined;
  193. }
  194.  
  195. MapGlobalRec::~MapGlobalRec ()
  196. {
  197.   //
  198.   //   Use the Close () function to shutdown this instance.
  199.   //
  200.   Close ();
  201. }
  202.  
  203. int MapGlobalRec::SetError (int Error)
  204. {
  205.   int OldError = ErrorCode;
  206.   ErrorCode    = Error;
  207.   return OldError;
  208. }
  209.  
  210. int MapGlobalRec::MapPossible (unsigned MapNr)
  211. {
  212.   //
  213.   //   Determine if the given map slot is possible to load or save from.
  214.   //
  215.   return MapNr < NrMaps && Offsets != NULL ? cTrue : cFalse;
  216. }
  217.  
  218. int MapGlobalRec::MapAvailable (unsigned MapNr)
  219. {
  220.   //
  221.   //   Determine if the given map slot is in fact available in the maps file.
  222.   //
  223.   return MapPossible (MapNr) && Offsets [MapNr] != 0 ? cTrue : cFalse;
  224. }
  225.  
  226. int MapGlobalRec::Open (unsigned Version)
  227. {
  228.   int Handle = -1;
  229.  
  230.   //
  231.   //   If the version is not determined yet, try the complete version first.
  232.   //
  233.   if (Version == cUndetermined)
  234.   {
  235.     //
  236.     //   Set version and file names.
  237.     //
  238.     CurrentVersion = cComplete;
  239.     strcpy (MapHeadName,  cMapHead);
  240.     strcpy (GameMapsName, c11GameMaps);
  241.  
  242.     //
  243.     //   Try opening the two files.
  244.     //
  245.     Handle     = _open (MapHeadName,  O_RDONLY);
  246.     MapsHandle = _open (GameMapsName, O_RDONLY);
  247.  
  248.     //
  249.     //   Continue processing if the two files are opened.
  250.     //
  251.     if (Handle != -1 && MapsHandle != -1) goto FilesOpened;
  252.     if (Handle != -1)
  253.     {
  254.       //
  255.       //   The map head file is open, so try the second possible name for
  256.       //   the game maps file.
  257.       //
  258.       strcpy (GameMapsName, c10GameMaps);
  259.       MapsHandle = _open (GameMapsName, O_RDONLY);
  260.  
  261.       //
  262.       //   This time successfull, so continue processing.
  263.       //
  264.       if (MapsHandle != -1) goto FilesOpened;
  265.  
  266.       close (Handle);
  267.     }
  268.  
  269.     //
  270.     //   The complete version could not be opened, so try the shareware
  271.     //   version now.
  272.     //
  273.     Version = cShareware;
  274.   }
  275.  
  276.   //
  277.   //   Set the correct file names for the requested version.
  278.   //
  279.   switch (Version)
  280.   {
  281.     case cComplete:
  282.       strcpy (MapHeadName,  cMapHead);
  283.       strcpy (GameMapsName, c11GameMaps);
  284.       break;
  285.     case cShareware:
  286.       strcpy (MapHeadName,  sMapHead);
  287.       strcpy (GameMapsName, s11GameMaps);
  288.       break;
  289.     case cLocal:
  290.       strcpy (MapHeadName,  lMapHead);
  291.       strcpy (GameMapsName, lGameMaps);
  292.       break;
  293.     default:
  294.       SetError (errNoSuchVersion);
  295.       return errNoSuchVersion;
  296.   }
  297.  
  298.   //
  299.   //   Set the version and try opening the two files.
  300.   //
  301.   CurrentVersion = Version;
  302.   Handle         = _open (MapHeadName,  O_RDONLY);
  303.   MapsHandle     = _open (GameMapsName, O_RDONLY);
  304.  
  305.   //
  306.   //   Continue processing if the two files are opened.
  307.   //
  308.   if (Handle != -1 && MapsHandle != -1) goto FilesOpened;
  309.   if (Handle != -1)
  310.   {
  311.     //
  312.     //   The map head file is open, so try the second possible name for the
  313.     //   game maps file.
  314.     //
  315.     switch (Version)
  316.     {
  317.       case cComplete:  strcpy (GameMapsName, c10GameMaps); break;
  318.       case cShareware: strcpy (GameMapsName, s10GameMaps); break;
  319.     }
  320.     MapsHandle = _open (GameMapsName, O_RDONLY);
  321.  
  322.     //
  323.     //   This time successfull, so continue processing.
  324.     //
  325.     if (MapsHandle != -1) goto FilesOpened;
  326.  
  327.     close (Handle);
  328.   }
  329.  
  330.   //
  331.   //   The requested version is not available, so return an error.
  332.   //
  333.   SetError (errNoSuchVersion);
  334.   return errNoSuchVersion;
  335.  
  336. FilesOpened:
  337.   //
  338.   //   From this point on the map head file and the game maps file are both
  339.   //   opened for reading. Now first determine the size of the map head file,
  340.   //   as this determines the max. number of maps stored.
  341.   //
  342.   long Size  = lseek (Handle, 0, SEEK_END);
  343.   int  Error = errOk;
  344.  
  345.   //
  346.   //   Allocate memory, but only if the map head file checks out ok.
  347.   //
  348.   if ( ((Size-2) & 0x0003) == 0)
  349.   {
  350.     NrMaps   = (Size - 2) >> 2;
  351.     Offsets  = (long *)        calloc (NrMaps, sizeof (long) );
  352.     MapStore = (GameMapRec **) calloc (NrMaps, sizeof (GameMapRec *) );
  353.  
  354.     if (Offsets == NULL || MapStore == NULL)
  355.     {
  356.       Error = errNoMemory;
  357.     }
  358.   }
  359.   else
  360.   {
  361.     Error = errNoMapHeadFile;
  362.   }
  363.  
  364.   //
  365.   //   Read the magic value and the start positions of every map header from
  366.   //   the map head file.
  367.   //
  368.   if (Error == errOk) Error = ReadData (Handle, 0, &MagicValue, 2);
  369.   if (Error == errOk) Error = ReadData (Handle, 2, Offsets, NrMaps * sizeof (long) );
  370.  
  371.   //
  372.   //   Close the map head file and return the error status.
  373.   //
  374.   close (Handle);
  375.   if (Error != errOk) SetError (Error);
  376.   return Error;
  377. }
  378.  
  379. int MapGlobalRec::Create (unsigned Version)
  380. {
  381.   int Error = errOk;
  382.  
  383.   //
  384.   //   Set the correct file names for the two files to reflect the chosen
  385.   //   version.
  386.   //
  387.   switch (Version)
  388.   {
  389.     case cComplete:
  390.       strcpy (MapHeadName,  cMapHead);
  391.       strcpy (GameMapsName, c11GameMaps);
  392.       break;
  393.     case cShareware:
  394.       strcpy (MapHeadName,  sMapHead);
  395.       strcpy (GameMapsName, s11GameMaps);
  396.       break;
  397.     case cLocal:
  398.       strcpy (MapHeadName,  lMapHead);
  399.       strcpy (GameMapsName, lGameMaps);
  400.       break;
  401.     default:
  402.       Error = errNoSuchVersion;
  403.       break;
  404.   }
  405.  
  406.   if (Error == errOk)
  407.   {
  408.     //
  409.     //   Set the created version and try creating the game maps work file.
  410.     //
  411.     CurrentVersion = Version;
  412.     WorkMapsHandle = _creat (WorkGameMaps, 0);
  413.  
  414.     //
  415.     //   If the work file is created, create the memory blocks and write a
  416.     //   leader of our own to this work file.
  417.     //
  418.     if (WorkMapsHandle != -1)
  419.     {
  420.       NrMaps     = cMapCount;
  421.       MagicValue = cMagicValue;
  422.       Offsets    = (long *)        calloc (NrMaps, sizeof (long) );
  423.       MapStore   = (GameMapRec **) calloc (NrMaps, sizeof (GameMapRec *) );
  424.  
  425.       if (Offsets != NULL && MapStore != NULL)
  426.       {
  427.         //
  428.         //   The memory blocks are allocated. Now write our own leader.
  429.         //
  430.         long Pos;
  431.         char Signature [256];
  432.  
  433.         sprintf (Signature, "Maps created with %s\r\n%s\r\n\X1A", cVersion, cCopyright);
  434.         Error = WriteData (WorkMapsHandle, &Pos, Signature, strlen (Signature) + 1);
  435.       }
  436.       else
  437.       {
  438.         Error = errNoMemory;
  439.       }
  440.     }
  441.     else
  442.     {
  443.       Error = errCreate;
  444.     }
  445.   }
  446.  
  447.   //
  448.   //   If an error occured, process it. Then return the error status.
  449.   //
  450.   if (Error != errOk) SetError (Error);
  451.   return Error;
  452. }
  453.  
  454. int MapGlobalRec::OpenWork ()
  455. {
  456.   //
  457.   //   Try creating the maps work file.
  458.   //
  459.   WorkMapsHandle = _creat (WorkGameMaps, 0);
  460.  
  461.   //
  462.   //   If the work file is created, copy the leader of the origional file to
  463.   //   this work file.
  464.   //
  465.   int   Error = WorkMapsHandle == -1 ? errCreate : errOk;
  466.   long *Pos   = Offsets;
  467.   int   Count = MapCount ();
  468.   long  Size  = 0x7FFFFFFF;
  469.  
  470.   while (Error == errOk && Count-- > 0)
  471.   {
  472.     //
  473.     //   Only track maps that are actually present.
  474.     //
  475.     if (*Pos != 0)
  476.     {
  477.       MapHeaderRec Hdr;
  478.  
  479.       Error = ReadData (MapsHandle, *Pos, &Hdr, sizeof (MapHeaderRec) );
  480.  
  481.       if (Error == errOk)
  482.       {
  483.         if (Size > Hdr.StartMaze)    Size = Hdr.StartMaze;
  484.         if (Size > Hdr.StartObjects) Size = Hdr.StartObjects;
  485.         if (Size > Hdr.StartUnknown) Size = Hdr.StartUnknown;
  486.         if (Size > *Pos)             Size = *Pos;
  487.       }
  488.     }
  489.  
  490.     Pos++;
  491.   }
  492.  
  493.   //
  494.   //   Copy the leader, if there is one.
  495.   //
  496.   if (Error == errOk && Size > 0)
  497.   {
  498.     //
  499.     //   Allocate a temporary block to hold the leader.
  500.     //
  501.     char *Leader = (char *) malloc (Size);
  502.  
  503.     //
  504.     //   Copy the leader from the maps file to the work file, using the
  505.     //   temporary memory block. Then free the block again.
  506.     //
  507.     if (Leader != NULL)
  508.     {
  509.       long Pos;
  510.  
  511.       if (Error == errOk) Error = ReadData (MapsHandle, 0, Leader, Size);
  512.       if (Error == errOk) Error = WriteData (WorkMapsHandle, &Pos, Leader, Size);
  513.  
  514.       free (Leader);
  515.     }
  516.     else
  517.     {
  518.       Error = errNoMemory;
  519.     }
  520.   }
  521.  
  522.   //
  523.   //   If an error occured, process it. Then return the error status.
  524.   //
  525.   if (Error != errOk) SetError (Error);
  526.   return Error;
  527. }
  528.  
  529. int MapGlobalRec::ConvertName (unsigned NewFormat)
  530. {
  531.   //
  532.   //   This function is intended for format conversion only. The name of the
  533.   //   game maps file of Wolf3D version 1.0 differs from the one in other
  534.   //   Wolf3D versions. This function changes this name by setting the new
  535.   //   name in the local name slot.
  536.   //   At this moment we only do this for the shareware version, since we
  537.   //   don't know if the same holds true for the commercial version.
  538.   //
  539.   if (CurrentVersion == cShareware)
  540.   {
  541.     switch (NewFormat)
  542.     {
  543.       case cFormat10:
  544.         strcpy (GameMapsName, s10GameMaps);
  545.         break;
  546.       case cFormat11:
  547.         strcpy (GameMapsName, s11GameMaps);
  548.         break;
  549.     }
  550.   }
  551.  
  552.   //
  553.   //   Return Ok to indicate success.
  554.   //
  555.   return errOk;
  556. }
  557.  
  558. int MapGlobalRec::Close ()
  559. {
  560.   int Error = errOk;
  561.  
  562.   //
  563.   //   Close the maps file, if it is open.
  564.   //
  565.   if (MapsHandle != -1) close (MapsHandle);
  566.  
  567.   //
  568.   //   Close the maps work file, if it is open. Then process the files.
  569.   //
  570.   if (WorkMapsHandle != -1)
  571.   {
  572.     close (WorkMapsHandle);
  573.  
  574.     //
  575.     //   The maps work file is closed. Now create, save and close the offsets
  576.     //   work file.
  577.     //
  578.     int Handle = _creat (WorkMapHead, 0);
  579.     if (Handle != -1)
  580.     {
  581.       long Pos;
  582.  
  583.       if (Error == errOk) Error = WriteData (Handle, &Pos, &MagicValue, 2);
  584.       if (Error == errOk) Error = WriteData (Handle, &Pos, Offsets, NrMaps * sizeof (long));
  585.  
  586.       close (Handle);
  587.     }
  588.     else
  589.     {
  590.       Error = errCreate;
  591.     }
  592.  
  593.     //
  594.     //   Now process the work files.
  595.     //
  596.     if (Error == errOk) Error = CopyWorkFiles (GameMapsName, MapHeadName);
  597.  
  598.     //
  599.     //   During the processing of the work files an error has occured. We
  600.     //   will simply discard any changes in this case by deleting the work
  601.     //   files.
  602.     //
  603.     if (Error != errOk)
  604.     {
  605.       unlink (WorkGameMaps);
  606.       unlink (WorkMapHead);
  607.     }
  608.   }
  609.  
  610.   //
  611.   //   Free any stored game maps in the maps store and free the store itself.
  612.   //
  613.   if (MapStore != NULL)
  614.   {
  615.     unsigned Map = 0;
  616.     while (Map < NrMaps)
  617.     {
  618.       if (MapStore [Map] != NULL) delete MapStore [Map];
  619.       Map++;
  620.     }
  621.  
  622.     free (MapStore);
  623.   }
  624.  
  625.   //
  626.   //   Deallocate the memory, if allocated.
  627.   //
  628.   if (Offsets != NULL) free (Offsets);
  629.  
  630.   //
  631.   //   Initialize all fields to their default values.
  632.   //
  633.   Offsets        = NULL;
  634.   MapStore       = NULL;
  635.   MapsHandle     = -1;
  636.   WorkMapsHandle = -1;
  637.   CurrentVersion = cUndetermined;
  638.   MagicValue     = 0x0000;
  639.   NrMaps         = 0;
  640.   NrMapsStored   = 0;
  641.  
  642.   //
  643.   //   If an error occured, process it. Then return the error status.
  644.   //
  645.   if (Error != errOk) SetError (Error);
  646.   return Error;
  647. }
  648.  
  649. int MapGlobalRec::Load (GameMapRec *Map, unsigned MapNr)
  650. {
  651.   //
  652.   //   Load the map using the open file handle and the Load member function
  653.   //   of the GameMap, but only if the map is actually in the file.
  654.   //
  655.   int Error = MapAvailable (MapNr) ? Map->Load (MapsHandle, Offsets [MapNr]) : errMapNotPresent;
  656.  
  657.   //
  658.   //   If an error occured, process it. Then return the error status.
  659.   //
  660.   if (Error != errOk) SetError (Error);
  661.   return Error;
  662. }
  663.  
  664. int MapGlobalRec::Save (GameMapRec *Map, unsigned MapNr)
  665. {
  666.   //
  667.   //   Save the map using the open file handle and the Load member function
  668.   //   of the GameMap, adjusting the offset of map header in the process.
  669.   //
  670.   int Error = MapPossible (MapNr) ? Map->Save (WorkMapsHandle, &Offsets [MapNr]) : errMapNotPresent;
  671.  
  672.   //
  673.   //   If an error occured, process it. Then return the error status.
  674.   //
  675.   if (Error != errOk) SetError (Error);
  676.   return Error;
  677. }
  678.  
  679. int MapGlobalRec::Compress (GameMapRec *Map, unsigned NewFormat)
  680. {
  681.   //
  682.   //   Determine current format if not done so already.
  683.   //
  684.   int      Error     = Map->Format () == cUndetermined ? Map->DetermineFormat () : errOk;
  685.   unsigned OldFormat = Map->Format ();
  686.  
  687.   //
  688.   //   Convert to the requested format. Since v1.1 format compression is done
  689.   //   over v1.0 compressed data, we use a while loop to cover each stage.
  690.   //
  691.   while (Error == errOk && NewFormat != OldFormat)
  692.   {
  693.     if (NewFormat < OldFormat)
  694.     {
  695.       //
  696.       //   Decompression is needed.
  697.       //
  698.       if (OldFormat == cFormat11) Error = Map->DecompressFormat11 ();
  699.       if (OldFormat == cFormat10) Error = Map->DecompressFormat10 (MagicValue);
  700.  
  701.       if (Error == errOk) OldFormat--;
  702.     }
  703.     else
  704.     {
  705.       //
  706.       //   Compression is needed.
  707.       //
  708.       if (OldFormat == cFormat10)     Error = Map->CompressFormat11 ();
  709.       if (OldFormat == cDecompressed) Error = Map->CompressFormat10 (MagicValue);
  710.  
  711.       if (Error == errOk) OldFormat++;
  712.     }
  713.  
  714.     //
  715.     //   If no error occured in this stage, set the new format in the GameMap.
  716.     //
  717.     if (Error == errOk) Map->SetFormat (OldFormat);
  718.   }
  719.  
  720.   //
  721.   //   If an error occured, process it. Then return the error status.
  722.   //
  723.   if (Error != errOk) SetError (Error);
  724.   return Error;
  725. }
  726.  
  727. int MapGlobalRec::Add (GameMapRec *Map, unsigned MapNr)
  728. {
  729.   int Error = errOk;
  730.  
  731.   //
  732.   //   Store the requested map. If another one is present, deallocate that
  733.   //   one.
  734.   //
  735.   if ( MapPossible (MapNr) )
  736.   {
  737.     //
  738.     //   First make sure we have a new, empty GameMapRec allocated.
  739.     //
  740.     if (MapStore [MapNr] != NULL)
  741.     {
  742.       MapStore [MapNr]->Close ();
  743.       NrMapsStored--;
  744.     }
  745.     else
  746.     {
  747.       MapStore [MapNr] = new GameMapRec;
  748.       if (MapStore [MapNr] == NULL) Error = errNoMemory;
  749.     }
  750.  
  751.     //
  752.     //   When the allocation is successfull, move the contents of the given
  753.     //   source map to the newly created one.
  754.     //
  755.     if (Error == errOk)
  756.     {
  757.       Error = MapStore [MapNr]->Copy (Map);
  758.       if (Error == errOk) NrMapsStored++;
  759.     }
  760.   }
  761.   else
  762.   {
  763.     Error = errMapNotPresent;
  764.   }
  765.  
  766.   //
  767.   //   If an error occured, process it. Then return the error status.
  768.   //
  769.   if (Error != errOk) SetError (Error);
  770.   return Error;
  771. }
  772.  
  773. int MapGlobalRec::InStore (unsigned MapNr)
  774. {
  775.   return MapPossible (MapNr) && MapStore [MapNr] != NULL;
  776. }
  777.  
  778. int MapGlobalRec::Copy (GameMapRec *Map, unsigned MapNr)
  779. {
  780.   int Error = errOk;
  781.  
  782.   //
  783.   //   Deallocate the requested map if it is indeed stored.
  784.   //
  785.   if ( MapPossible (MapNr) )
  786.   {
  787.     if (MapStore [MapNr] != NULL)
  788.     {
  789.       Error = Map->Copy (MapStore [MapNr]);
  790.     }
  791.   }
  792.   else
  793.   {
  794.     Error = errMapNotPresent;
  795.   }
  796.  
  797.   //
  798.   //   If an error occured, process it. Then return the error status.
  799.   //
  800.   if (Error != errOk) SetError (Error);
  801.   return Error;
  802. }
  803.  
  804. int MapGlobalRec::Delete (unsigned MapNr)
  805. {
  806.   int Error = errOk;
  807.  
  808.   //
  809.   //   Deallocate the requested map if it is indeed stored.
  810.   //
  811.   if ( MapPossible (MapNr) )
  812.   {
  813.     if (MapStore [MapNr] != NULL)
  814.     {
  815.       delete MapStore [MapNr];
  816.       MapStore [MapNr] = NULL;
  817.       NrMapsStored--;
  818.     }
  819.   }
  820.   else
  821.   {
  822.     Error = errMapNotPresent;
  823.   }
  824.  
  825.   //
  826.   //   If an error occured, process it. Then return the error status.
  827.   //
  828.   if (Error != errOk) SetError (Error);
  829.   return Error;
  830. }
  831.  
  832. int MapGlobalRec::DisplayHeaders (FILE *Stream, unsigned Columns)
  833. {
  834.   //
  835.   //   Initialize the various pointers and counters.
  836.   //
  837.   long     *Ofs     = Offsets;
  838.   unsigned  MapNr   = 0;
  839.   unsigned  Count   = 0;
  840.   unsigned  Printed = 0;
  841.   int       Error   = errOk;
  842.  
  843.   //
  844.   //   First, determine how many maps are actually present.
  845.   //
  846.   while (MapNr++ < NrMaps)
  847.   {
  848.     if (*(Ofs++) != 0) Count++;
  849.   }
  850.  
  851.   //
  852.   //   Reinitialize the pointers.
  853.   //
  854.   Ofs   = Offsets;
  855.   MapNr = 0;
  856.  
  857.   //
  858.   //   Simply display a message when no maps are present.
  859.   //
  860.   if (Count == 0)
  861.   {
  862.     fprintf (Stream, "Sorry, there are no maps present in this version.\n");
  863.   }
  864.   else
  865.   {
  866.     switch (Columns)
  867.     {
  868.       //
  869.       //   Display the header information in one column.
  870.       //
  871.       case cOneColumn:
  872.         //
  873.         //   Display column banner.
  874.         //
  875.         fprintf (Stream, "Map #   Title              Size\n");
  876.         fprintf (Stream, "=====   ================   =======\n\n");
  877.  
  878.         //
  879.         //   Walk every map and display information on present maps.
  880.         //
  881.         while (Error == errOk && MapNr < NrMaps)
  882.         {
  883.           if (*Ofs != 0)
  884.           {
  885.             MapHeaderRec Hdr;
  886.  
  887.             Error = ReadData (MapsHandle, *Ofs, &Hdr, sizeof (MapHeaderRec) );
  888.  
  889.             if (Error == errOk) fprintf (Stream, "%5u   %-16Fs   [%02u,%02u]\n", MapNr, Hdr.Title, Hdr.SizeX, Hdr.SizeY);
  890.           }
  891.  
  892.           Ofs++;
  893.           MapNr++;
  894.         }
  895.  
  896.         break;
  897.  
  898.       //
  899.       //   Display the header information in two columns.
  900.       //
  901.       case cTwoColumns:
  902.         //
  903.         //   Display column banners.
  904.         //
  905.         fprintf (Stream, "Map #   Title              Size         Map #   Title              Size\n");
  906.         fprintf (Stream, "=====   ================   =======      =====   ================   =======\n\n");
  907.  
  908.         //
  909.         //   Walk every map and display information on present maps.
  910.         //
  911.         while (Error == errOk && MapNr < NrMaps)
  912.         {
  913.           if (*Ofs != 0)
  914.           {
  915.             MapHeaderRec Hdr;
  916.  
  917.             Error = ReadData (MapsHandle, *Ofs, &Hdr, sizeof (MapHeaderRec) );
  918.  
  919.             if (Error == errOk)
  920.             {
  921.               if ( (Printed & 1) == 0 )
  922.               {
  923.                 fprintf (Stream, "%5u   %-16Fs   [%02u,%02u]      ", MapNr, Hdr.Title, Hdr.SizeX, Hdr.SizeY);
  924.               }
  925.               else
  926.               {
  927.                 fprintf (Stream, "%5u   %-16Fs   [%02u,%02u]\n", MapNr, Hdr.Title, Hdr.SizeX, Hdr.SizeY);
  928.               }
  929.             }
  930.  
  931.             Printed++;
  932.           }
  933.  
  934.           Ofs++;
  935.           MapNr++;
  936.         }
  937.  
  938.         //
  939.         //   Force a new line if not done so already.
  940.         //
  941.         if ( (Printed & 1) != 0 ) fprintf (Stream, "\n");
  942.  
  943.         break;
  944.  
  945.       //
  946.       //   Display short header information in three columns.
  947.       //
  948.       case cThreeColumns:
  949.         //
  950.         //   Display column banners.
  951.         //
  952.         fprintf (Stream, "Map #  Title               Map #  Title               Map #  Title\n");
  953.         fprintf (Stream, "=====  ================    =====  ================    =====  ================\n\n");
  954.  
  955.         //
  956.         //   Walk every map and display information on present maps.
  957.         //
  958.         while (Error == errOk && MapNr < NrMaps)
  959.         {
  960.           if (*Ofs != 0)
  961.           {
  962.             MapHeaderRec Hdr;
  963.  
  964.             Error = ReadData (MapsHandle, *Ofs, &Hdr, sizeof (MapHeaderRec) );
  965.  
  966.             if (Error == errOk)
  967.             {
  968.               if ( (Printed % 3) != 2 )
  969.               {
  970.                 fprintf (Stream, "%5u  %-16Fs    ", MapNr, Hdr.Title);
  971.               }
  972.               else
  973.               {
  974.                 fprintf (Stream, "%5u  %-16Fs\n", MapNr, Hdr.Title);
  975.               }
  976.             }
  977.  
  978.             Printed++;
  979.           }
  980.  
  981.           //
  982.           //   Advance to next map.
  983.           //
  984.           Ofs++;
  985.           MapNr++;
  986.         }
  987.  
  988.         //
  989.         //   Force a new line if not done so already.
  990.         //
  991.         if ( (Printed % 3) != 0 ) fprintf (Stream, "\n");
  992.  
  993.         break;
  994.     }
  995.   }
  996.  
  997.   //
  998.   //   Return Ok to indicate success.
  999.   //
  1000.   return errOk;
  1001. }
  1002.