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

  1. /*
  2.  
  3. ---------------------------------------------------------------------------
  4. | WolfMap Processing           |    (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.5         12/10/92 | Added a graphical, interactive map       |
  12. |                              | viewer/editor.                           |
  13. |                              | J.P. Dijkstra, M.Sc.                     |
  14. | Version 1.6         20/10/92 | The editor will now create a specified   |
  15. |                              | version of the map files, if it doesn't  |
  16. |                              | exist.                                   |
  17. |                              | Adjusted the naming of newly created     |
  18. |                              | maps to be in sync with the origional    |
  19. |                              | map names.                               |
  20. |                              | J.P. Dijkstra, M.Sc.                     |
  21. ---------------------------------------------------------------------------
  22. | This program processes the Wolf-3D map files in various ways. It can    |
  23. | show the map names, the number of maps stored, convert from version 1.0 |
  24. | to 1.1 format and vice versa, print out any map in ASCII format to      |
  25. | stdout (to allow redirection) or a file.                                |
  26. |                                                                         |
  27. | The maze / objects data is stored in a compressed format, wordwize. The |
  28. | first word is the number of bytes the decompressed data will occupy in  |
  29. | memory. The compressed data follows immediately.                        |
  30. | The start of the level headers in the GAMEMAPS file are stores in the   |
  31. | MAPHEAD file. The first word in this file is the magic word preceding a |
  32. | repeat count in the compressed data in the GAMEMAPS file. This word is  |
  33. | followed by a sequence of long words, one for each level.               |
  34. ---------------------------------------------------------------------------
  35.  
  36. */
  37.  
  38. #include "wolfmap.H"
  39. #include "stdio.h"
  40.  
  41. /*
  42.  
  43. ---------------------------------------------------------------------------
  44. | Local data structures and constants                                     |
  45. ---------------------------------------------------------------------------
  46. | FlagsRec                    | Contains the processed command line flags |
  47. |   Version                   | Contains the maps file version to use.    |
  48. |                             | For import and export specifies the       |
  49. |                             | target and source respectively.           |
  50. |   Format                    | Contains the compression format to use.   |
  51. |                             | For import and export specifies the new   |
  52. |                             | format to convert the maps to. For the    |
  53. |                             | other commands this field overrides the   |
  54. |                             | autodetection of the maps format. Use     |
  55. |                             | with care !!!!                            |
  56. |   Output                    | Contains the output target to print data  |
  57. |                             | to.                                       |
  58. |   Columns                   | Specifies the number of columns to use    |
  59. |                             | when displaying information on stdout.    |
  60. |   Legend                    | Specifies whether or not to print the map |
  61. |                             | legend. Only relevant for single file     |
  62. |                             | output.                                   |
  63. |   MapNrGiven                | Specifies whether a map number was given  |
  64. |                             | on the command line.                      |
  65. |   MapChosen                 | Each bit specifies whether or not the     |
  66. |                             | accompanying map number was specified.    |
  67. |   LowestMap                 | Holds the first map number specified.     |
  68. ---------------------------------------------------------------------------
  69.  
  70. */
  71.  
  72. const int cMaxMaps  = 400;
  73. const int cMaxBytes = (cMaxMaps + 7) >> 3;
  74.  
  75. char *cCopyright = "Copyright (c) 1992 Sysma Automatisering     All rights reserved.";
  76. char *cVersion   = "WolfMap v1.6";
  77.  
  78. struct FlagsRec
  79. {
  80.   unsigned Version    :3;
  81.   unsigned Format     :2;
  82.   unsigned Output     :2;
  83.   unsigned Columns    :2;
  84.   unsigned Legend     :1;
  85.   unsigned MapNrGiven :1;
  86.   char     MapChosen  [ cMaxBytes ];
  87.   unsigned LowestMap;
  88. };
  89.  
  90. const int cNoCommand     = 0;
  91. const int cHelp          = 1;
  92. const int cExportMaps    = 2;
  93. const int cImportMaps    = 3;
  94. const int cConvert10     = 4;
  95. const int cConvert11     = 5;
  96. const int cPrintMaps     = 6;
  97. const int cPrintMapStats = 7;
  98. const int cPrintLegend   = 8;
  99. const int cDisplayTitles = 9;
  100. const int cDisplayStats  = 10;
  101. const int cModify        = 11;
  102.  
  103. /*
  104.  
  105. ---------------------------------------------------------------------------
  106. | Local functions to implement elementary operations.                     |
  107. ---------------------------------------------------------------------------
  108. | SetMapNr                    | Marks the given map number as chosen.     |
  109. | MapChosen                   | Returns true if the given map number is   |
  110. |                             | indeed chosen.                            |
  111. | ResetAllMaps                | Resets the mark for all map numbers.      |
  112. | SetAllMaps                  | Sets the chosen mark for all map numbers. |
  113. | Message                     | Writes an error message to stderr for the |
  114. |                             | given error code.                         |
  115. | ProcessParameters           | Scans the command line and sets the       |
  116. |                             | appropriate values for flags, commands    |
  117. |                             | map numbers.                              |
  118. | ShowHelp                    | Displays generic information about this   |
  119. |                             | program.                                  |
  120. | ShowCommands                | Displays the correct program usage,       |
  121. |                             | including possible flags and commands.    |
  122. | Export                      | Copies the chosen maps from the given     |
  123. |                             | maps file version to the intermediate     |
  124. |                             | maps file.                                |
  125. | Import                      | Copies the chosen maps from the local (or |
  126. |                             | intermediate) maps file to the given maps |
  127. |                             | file.                                     |
  128. | ConvertFormat               | Converts ALL maps in the given maps file  |
  129. |                             | to the specified compression format.      |
  130. | PrintMaps                   | Prints the chosen maps to the specified   |
  131. |                             | output stream, separated by form feeds.   |
  132. | PrintMapStatistics          | Prints statistics from the chosen maps to |
  133. |                             | the specified output stream, two map      |
  134. |                             | statistics per page, separated by form    |
  135. |                             | feeds.                                    |
  136. | PrintLegend                 | Prints the legend of the symbols, used in |
  137. |                             | the prints of a map, to a separate file   |
  138. |                             | or to the given output stream.            |
  139. | DisplayTitles               | Displays the titles of all the maps in    |
  140. |                             | given version.                            |
  141. | DisplayStatistics           | Displays statistics about the maps in the |
  142. |                             | given version.                            |
  143. | main                        | The actual program.                       |
  144. ---------------------------------------------------------------------------
  145.  
  146. */
  147.  
  148. void SetMapNr (FlagsRec *Flags, unsigned MapNr)
  149. {
  150.   if (MapNr < cMaxMaps)
  151.   {
  152.     unsigned Bit  = 0x01 << (MapNr & 0x07);
  153.     unsigned Byte = MapNr >> 3;
  154.     Flags->MapChosen [Byte] |= Bit;
  155.     if (Flags->MapNrGiven == cFalse || MapNr < Flags->LowestMap)
  156.     {
  157.       Flags->LowestMap  = MapNr;
  158.       Flags->MapNrGiven = cTrue;
  159.     }
  160.   }
  161. }
  162.  
  163. int MapChosen (FlagsRec *Flags, unsigned MapNr)
  164. {
  165.   if (MapNr < cMaxMaps)
  166.   {
  167.     unsigned Bit  = 0x01 << (MapNr & 0x07);
  168.     unsigned Byte = MapNr >> 3;
  169.     return (Flags->MapChosen [Byte] & Bit) != 0 ? cTrue : cFalse;
  170.   }
  171.  
  172.   return cFalse;
  173. }
  174.  
  175. void ResetAllMaps (FlagsRec *Flags)
  176. {
  177.   unsigned Byte = 0;
  178.   while (Byte < cMaxBytes)
  179.   {
  180.     Flags->MapChosen [Byte++] = 0x00;
  181.   }
  182.   Flags->MapNrGiven = cFalse;
  183.   Flags->LowestMap  = 0;
  184. }
  185.  
  186. void SetAllMaps (FlagsRec *Flags)
  187. {
  188.   unsigned Byte = 0;
  189.   while (Byte < cMaxBytes)
  190.   {
  191.     Flags->MapChosen [Byte++] = 0xFF;
  192.   }
  193. }
  194.  
  195. #pragma argsused
  196. void Message (unsigned ErrCode, unsigned MapNr, int IgnoreChange)
  197. {
  198.   fprintf (stderr, "WolfMap: ");
  199.  
  200.   switch (ErrCode)
  201.   {
  202.     case errNoMemory:
  203.       fprintf (stderr, "Not enough memory left.\n");
  204.       break;
  205.     case errMemoryCorrupted:
  206.       fprintf (stderr, "Fatal error. Memory corrupted.\n");
  207.       break;
  208.     case errSeek:
  209.       fprintf (stderr, "Error locating the correct position in the files.\n");
  210.       break;
  211.     case errRead:
  212.       fprintf (stderr, "Error reading from file.\n");
  213.       break;
  214.     case errWrite:
  215.       fprintf (stderr, "Error writing to the work file.\n");
  216.       break;
  217.     case errLeaderTooLarge:
  218.       fprintf (stderr, "Non-map part of the maps file > 64K.\n");
  219.       break;
  220.     case errNoSuchFile:
  221.       fprintf (stderr, "Requested version does not exist.\n");
  222.       break;
  223.     case errNoMapHeadFile:
  224.       fprintf (stderr, "Requested version is not in the correct format.\n");
  225.       break;
  226.     case errNoSuchVersion:
  227.       fprintf (stderr, "Requested an unknown version.\n");
  228.       break;
  229.     case errDelete:
  230.       fprintf (stderr, "Error deleting the previous backup files.\n");
  231.       break;
  232.     case errBackup:
  233.       fprintf (stderr, "Error backing up the origional files.\n");
  234.       break;
  235.     case errCopy:
  236.       fprintf (stderr, "Error copying the work files to the origionals.\n");
  237.       break;
  238.     case errCreate:
  239.       fprintf (stderr, "Error creating the work files.\n");
  240.       break;
  241.     case errNotOpen:
  242.       fprintf (stderr, "Attempt to read or write from a closed file.\n");
  243.       break;
  244.     case errLocalIsTarget:
  245.       fprintf (stderr, "Local version may not be specified for this command.\n");
  246.       break;
  247.     case errMapNotPresent:
  248.       fprintf (stderr, "Attempt to load or save a non existing map.\n");
  249.       break;
  250.     case errNotAllocated:
  251.       fprintf (stderr, "Attempt to use a non allocated memory block.\n");
  252.       break;
  253.     case errCreateOutput:
  254.       fprintf (stderr, "Error creating the output file.\n");
  255.       break;
  256.     case errNoDefFile:
  257.       fprintf (stderr, "Error opening the legend definition files.\n");
  258.       break;
  259.     case errIllegalLegend:
  260.       fprintf (stderr, "Syntax error reading legend definition line.\n");
  261.       break;
  262.     case errIllegalMaze:
  263.       fprintf (stderr, "Illegal map sizes specified when creating a new map.\n");
  264.       break;
  265.     case errInitializeGraph:
  266.       fprintf (stderr, "Error loading the VGA graphics driver.\n");
  267.       break;
  268.   }
  269.  
  270.   if ( IgnoreChange )
  271.   {
  272.     fprintf (stderr, "         Changes will NOT be written.\n");
  273.   }
  274. }
  275.  
  276. int ProcessParameters (int argc, char **argv, FlagsRec *Flags)
  277. {
  278.   //
  279.   //   This function processes the parameters passed to the program and
  280.   //   sets any global variables accordingly.
  281.   //
  282.   int Arg     = 0;
  283.   int Command = cNoCommand;
  284.  
  285.   ResetAllMaps (Flags);
  286.   Flags->Format  = cUndetermined;
  287.   Flags->Version = cUndetermined;
  288.   Flags->Output  = cSingle;
  289.   Flags->Legend  = cFalse;
  290.   Flags->Columns = cOneColumn;
  291.  
  292.   //
  293.   //   Scan every command line parameter to figure out what it is. In the
  294.   //   switch blocks the continue statement is used whenever a paremeter is
  295.   //   recognized. This is done to enable error processing for nested
  296.   //   switch statements.
  297.   //
  298.   while (++Arg < argc)
  299.   {
  300.     if (**(++argv) == '-' || **argv == '/')
  301.     {
  302.       //
  303.       //   Possible flag detected. Figure out which one.
  304.       //
  305.       switch ( (*argv) [1] )
  306.       {
  307.         //   Actually help command.
  308.         case '?':
  309.           return cHelp;
  310.  
  311.         //   Actually help command.
  312.         case 'h':
  313.           return cHelp;
  314.  
  315.         //   Compression format specifier.
  316.         case 'f':
  317.           switch ( (*argv) [2] )
  318.           {
  319.             case '0':
  320.               Flags->Format = cFormat10;
  321.               continue;
  322.             case '1':
  323.               Flags->Format = cFormat11;
  324.               continue;
  325.             case '2':
  326.               Flags->Format = cFormat11;
  327.               continue;
  328.             case '\0':
  329.               Flags->Format = cUndetermined;
  330.               continue;
  331.           }
  332.           break;
  333.  
  334.         //   Output file specifiers.
  335.         case 'o':
  336.           switch ( (*argv) [2] )
  337.           {
  338.             case 'u':
  339.               Flags->Output = cSeparate;
  340.               continue;
  341.             case 's':
  342.               Flags->Output = cSingle;
  343.               continue;
  344.             case 'o':
  345.               Flags->Output = cStdout;
  346.               continue;
  347.             case '\0':
  348.               Flags->Output = cSingle;
  349.               continue;
  350.             case 'l':
  351.               Flags->Legend = cTrue;
  352.               continue;
  353.           }
  354.           break;
  355.  
  356.         //   File version.
  357.         case 's':
  358.           Flags->Version = cShareware;
  359.           continue;
  360.         case 'c':
  361.           Flags->Version = cComplete;
  362.           continue;
  363.         case 'l':
  364.           Flags->Version = cLocal;
  365.           continue;
  366.  
  367.         //   Number of columns.
  368.         case 'w':
  369.           Flags->Columns = cThreeColumns;
  370.           continue;
  371.         case '2':
  372.           Flags->Columns = cTwoColumns;
  373.           continue;
  374.         case '1':
  375.           Flags->Columns = cOneColumn;
  376.           continue;
  377.       }
  378.  
  379.       //
  380.       //   At this point not legal flag could be recognized. Therefore the
  381.       //   offending flag will be printed and NoCommand will returned
  382.       //   immediately.
  383.       //
  384.       fprintf (stderr, "WolfMap: Unknown flag '%s'\n", (*argv)+1);
  385.       fprintf (stderr, "         Type 'wolfmap -h' for a complete list of flags.\n");
  386.       return cNoCommand;
  387.     }
  388.  
  389.     //
  390.     //   At this point the current parameter cannot be a flag. Two other
  391.     //   possibilities remain, either a map number or a command. Here we
  392.     //   check for a map number.
  393.     //
  394.     if (**argv >= '0' && **argv <= '9')
  395.     {
  396.       unsigned MapNr = 0;
  397.  
  398.       //
  399.       //   Process digits into a map number.
  400.       //
  401.       char *Str = *argv;
  402.       while (*Str >= '0' && *Str <= '9')
  403.       {
  404.         MapNr = MapNr * 10 + (*(Str++) - '0');
  405.       }
  406.  
  407.       //
  408.       //   If the digits are terminated correctly, process the number and
  409.       //   continue with the next parameter.
  410.       //
  411.       if (*Str == '\0')
  412.       {
  413.         SetMapNr (Flags, MapNr);
  414.         continue;
  415.       }
  416.  
  417.       //
  418.       //   If the next non digit character is a minus sign, we have
  419.       //   encountered a range of map numbers. Note that this cannot be
  420.       //   a space character, since in that case the startup code would have
  421.       //   interpreted this as a parameter separator.
  422.       //
  423.       if (*(Str++) == '-')
  424.       {
  425.         unsigned SecondNr = 0;
  426.  
  427.         //
  428.         //   Process the digits into the second map number for the upper
  429.         //   limit of the range.
  430.         //
  431.         while (*Str >= '0' && *Str <= '9')
  432.         {
  433.           SecondNr = SecondNr * 10 + (*(Str++) - '0');
  434.         }
  435.  
  436.         //
  437.         //   The range is legal only when the second sequence of digits is
  438.         //   terminated correctly.
  439.         //
  440.         if (*Str == '\0')
  441.         {
  442.           //
  443.           //   Process the range, but only if the first number is not
  444.           //   greater than the second one.
  445.           //
  446.           if (MapNr <= SecondNr)
  447.           {
  448.             while (MapNr <= SecondNr)
  449.             {
  450.               SetMapNr (Flags, MapNr++);
  451.             }
  452.             continue;
  453.           }
  454.  
  455.           //
  456.           //   At this point the range is given incorrectly. Currently we
  457.           //   consider this a fatal error.
  458.           //
  459.           fprintf (stderr, "WolfMap: Range [%s] is specified incorrectly.\n", *argv);
  460.           return cNoCommand;
  461.         }
  462.       }
  463.  
  464.       //
  465.       //   At this point not legal number could be recognized. Therefore the
  466.       //   offending parameter will be printed and NoCommand will returned
  467.       //   immediately.
  468.       //
  469.       fprintf (stderr, "WolfMap: [%s] is not a legal map number.'\n", *argv);
  470.       return cNoCommand;
  471.     }
  472.  
  473.     //
  474.     //   At this point the decision has been made that the parameter is
  475.     //   not a flag or a map number. Now figure out if it is a command. Only
  476.     //   the first command given is taken, others will be ignored. This is
  477.     //   done because flags can appear anywhere in the command line and this
  478.     //   method saves scanning the command line twice.
  479.     //
  480.     if (Command == cNoCommand)
  481.     {
  482.       switch (**argv)
  483.       {
  484.         //   Conversion command. Figure out to which format.
  485.         case 'c':
  486.           switch ( (*argv) [1] )
  487.           {
  488.             case '0':
  489.               Command = cConvert10;
  490.               continue;
  491.             case '1':
  492.               Command = cConvert11;
  493.               continue;
  494.             case '2':
  495.               Command = cConvert11;
  496.               continue;
  497.           }
  498.           break;
  499.  
  500.         //   Print commands.
  501.         case 'p':
  502.           switch ( (*argv) [1] )
  503.           {
  504.             case 'm':
  505.               Command = cPrintMaps;
  506.               continue;
  507.             case 's':
  508.               Command = cPrintMapStats;
  509.               continue;
  510.             case 'l':
  511.               Command = cPrintLegend;
  512.               continue;
  513.             case '\0':
  514.               Command = cPrintMaps;
  515.               continue;
  516.           }
  517.           break;
  518.  
  519.         //   Display commands.
  520.         case 'd':
  521.           switch ( (*argv) [1] )
  522.           {
  523.             case 't':
  524.               Command = cDisplayTitles;
  525.               continue;
  526.             case 's':
  527.               Command = cDisplayStats;
  528.               continue;
  529.             case '\0':
  530.               Command = cDisplayTitles;
  531.               continue;
  532.           }
  533.           break;
  534.  
  535.         //   Export map command.
  536.         case 'e':
  537.           Command = cExportMaps;
  538.           continue;
  539.  
  540.         //   Import map command.
  541.         case 'i':
  542.           Command = cImportMaps;
  543.           continue;
  544.  
  545.         //   Modify (edit) map command.
  546.         case 'm':
  547.           Command = cModify;
  548.           continue;
  549.  
  550.         //   Help command.
  551.         case 'h':
  552.           Command = cHelp;
  553.           continue;
  554.         case '?':
  555.           Command = cHelp;
  556.           continue;
  557.       }
  558.  
  559.       //
  560.       //   At this point an unknown command was encountered, so print an
  561.       //   error message and return NoCommand immediately.
  562.       //
  563.       fprintf (stderr, "WolfMap: Unknown command %s.\n", *argv);
  564.       fprintf (stderr, "         Type 'wolfmap -h' for a complete list of commands.\n");
  565.       return cNoCommand;
  566.     }
  567.   }
  568.  
  569.   //
  570.   //   Return the command recognized, if any.
  571.   //
  572.   if (Command == cNoCommand)
  573.   {
  574.     fprintf (stderr, "WolfMap: No command has been issued.\n");
  575.     fprintf (stderr, "         Type 'wolfmap -h' for a complete list of commands.\n");
  576.   }
  577.  
  578.   if (Flags->MapNrGiven == cFalse) SetAllMaps (Flags);
  579.  
  580.   return Command;
  581. }
  582.  
  583. int ShowBanner ()
  584. {
  585.   //
  586.   //   Display banner on the screen.
  587.   //
  588.   fprintf (stderr, "%s   -   Processes Wolfenstein-3D maps.\n%s\n\n", cVersion, cCopyright);
  589.  
  590.   return cOk;
  591. }
  592.  
  593. int ShowHelp ()
  594. {
  595.   fprintf (stderr, "WolfMap processes the level maps of Wolf-3D versions 1.0, 1.1 and 1.2\n");
  596.   fprintf (stderr, "It can show essential level information, print out a map of any level,\n");
  597.   fprintf (stderr, "reveiling doors, guards, secret rooms and much more. Also, it is able\n");
  598.   fprintf (stderr, "to convert the map formats from one Wolf-3D version 1.0 to another.\n");
  599.   fprintf (stderr, "Finally, WolfMap contains an interactive, graphical map editor.\n\n");
  600.   fprintf (stderr, "Use WolfMap -h for a detailed list of commands.\n");
  601.   return cOk;
  602. }
  603.  
  604. int ShowCommands ()
  605. {
  606.   fprintf (stderr, "Syntax: Wolfmap [flags] [command] [mapnr | mapnr-mapnr]\n\n");
  607.   fprintf (stderr, "Allowable flags are:              Allowable commands are:\n\n");
  608.   fprintf (stderr, "-h   Show this information.       h   Show this information.\n");
  609.   fprintf (stderr, "-?   Same as -h.                  ?   Same as h.\n");
  610.   fprintf (stderr, "-f0  Use v1.0 format.             c0  Convert to v1.0 format.\n");
  611.   fprintf (stderr, "-f1  Use v1.1 format.             c1  Convert to v1.1 format.\n");
  612.   fprintf (stderr, "-f2  Use v1.2 format.             c2  Convert to v1.2 format.\n");
  613.   fprintf (stderr, "-s   Use shareware version.       e   Export maps to local version.\n");
  614.   fprintf (stderr, "-c   Use complete version.        i   Import maps from local version.\n");
  615.   fprintf (stderr, "-l   Use local version.           m   Modify (edit) maps.\n");
  616.   fprintf (stderr, "-w   Use wide display.            dt  Display map titles.\n");
  617.   fprintf (stderr, "-2   Use two column display.      ds  Display map statistics.\n");
  618.   fprintf (stderr, "-ou  Print to unique files.       pm  Print maps.\n");
  619.   fprintf (stderr, "-os  Print to single file.        ps  Print map statistics.\n");
  620.   fprintf (stderr, "-oo  Print to stdout.             pl  Print the legend of map symbols.\n");
  621.   fprintf (stderr, "-ol  Print legend of maps.\n");
  622.   return cOk;
  623. }
  624.  
  625. int Export (FlagsRec *Flags)
  626. {
  627.   MapGlobalRec FromGlobals;
  628.   MapGlobalRec ToGlobals;
  629.  
  630.   //
  631.   //   Try opening the requested maps version and open the local version for
  632.   //   writing.
  633.   //
  634.   int Error = Flags->Version == cLocal ? errLocalIsTarget : errOk;
  635.  
  636.   if (Error == errOk) Error = FromGlobals.Open (Flags->Version);
  637.   if (Error == errOk) Error = ToGlobals.Create (cLocal);
  638.  
  639.   //
  640.   //   Process all requested maps, one at a time.
  641.   //
  642.   unsigned MapNr    = 0;
  643.   unsigned Exported = 0;
  644.  
  645.   while (Error == errOk && MapNr < FromGlobals.MapCount () )
  646.   {
  647.     //
  648.     //   Check if this map is requested for exporting. Check only real,
  649.     //   available maps.
  650.     //
  651.     if (FromGlobals.MapAvailable (MapNr) && MapChosen (Flags, MapNr) )
  652.     {
  653.       //
  654.       //   This map was requested, so process it.
  655.       //
  656.       GameMapRec Map;
  657.  
  658.       //
  659.       //   First, read the map from the requested version and determine the
  660.       //   target format.
  661.       //
  662.       if (Error == errOk) Error = FromGlobals.Load    (&Map, MapNr);
  663.       if (Error == errOk) Error = Map.DetermineFormat ();
  664.  
  665.       unsigned Format = Flags->Format == cUndetermined ? Map.Format () : Flags->Format;
  666.  
  667.       //
  668.       //   Now, convert the map to the target format and save it.
  669.       //
  670.       if (Error == errOk) Error = FromGlobals.Compress (&Map, cDecompressed);
  671.       if (Error == errOk) Error = ToGlobals.Compress   (&Map, Format);
  672.       if (Error == errOk) Error = ToGlobals.Save       (&Map, MapNr);
  673.  
  674.       Exported++;
  675.     }
  676.  
  677.     //
  678.     //   Advance to the next map, but only if no errors occured.
  679.     //
  680.     if (Error == errOk) MapNr++;
  681.   }
  682.  
  683.   //
  684.   //   Close the maps and the local maps.
  685.   //
  686.   if (Error == errOk) Error = ToGlobals.Close ();
  687.   if (Error == errOk) Error = FromGlobals.Close ();
  688.  
  689.   //
  690.   //   Display the number of maps exported if no errors occured. Otherwise,
  691.   //   display the correct error message.
  692.   //
  693.   if (Error == errOk)
  694.   {
  695.     fprintf (stderr, "Exported %d %s to the intermediate version.\n",
  696.              Exported, Exported == 1 ? "map" : "maps"
  697.             );
  698.     return cOk;
  699.   }
  700.   else
  701.   {
  702.     Message (Error, MapNr, cTrue);
  703.     return cError;
  704.   }
  705. }
  706.  
  707. int Import (FlagsRec *Flags)
  708. {
  709.   MapGlobalRec FromGlobals;
  710.   MapGlobalRec ToGlobals;
  711.  
  712.   //
  713.   //   Try opening the requested maps version for writing / updating and open
  714.   //   the local version for reading.
  715.   //
  716.   int Error = Flags->Version == cLocal ? errLocalIsTarget : errOk;
  717.  
  718.   if (Error == errOk) Error = FromGlobals.Open (cLocal);
  719.   if (Error == errOk)
  720.   {
  721.     Error = ToGlobals.Open (Flags->Version);
  722.  
  723.     if (Error == errOk)
  724.     {
  725.       Error = ToGlobals.OpenWork ();
  726.     }
  727.     else if (Error == errNoSuchVersion)
  728.     {
  729.       Error = ToGlobals.Create (Flags->Version);
  730.     }
  731.   }
  732.  
  733.   //
  734.   //   Process all requested maps, one at a time.
  735.   //
  736.   unsigned MapNr    = 0;
  737.   unsigned Imported = 0;
  738.  
  739.   while (Error == errOk && MapNr < FromGlobals.MapCount () )
  740.   {
  741.     //
  742.     //   Since this is importing, every map must be processed.
  743.     //
  744.     GameMapRec Map;
  745.  
  746.     //
  747.     //   Determine if the current map is to imported, or (in case it is not)
  748.     //   if the current map is available in the target maps file.
  749.     //
  750.     if (FromGlobals.MapAvailable (MapNr) && MapChosen (Flags, MapNr) )
  751.     {
  752.       if (Error == errOk) Error = FromGlobals.Load    (&Map, MapNr);
  753.       if (Error == errOk) Error = Map.DetermineFormat ();
  754.  
  755.       unsigned Format = Flags->Format == cUndetermined ? Map.Format () : Flags->Format;
  756.  
  757.       //
  758.       //   Now, convert the map to the target format and save it.
  759.       //
  760.       if (Error == errOk) Error = FromGlobals.Compress (&Map, cDecompressed);
  761.       if (Error == errOk) Error = ToGlobals.Compress   (&Map, Format);
  762.       if (Error == errOk) Error = ToGlobals.Save       (&Map, MapNr);
  763.  
  764.       Imported++;
  765.     }
  766.     else
  767.     {
  768.       if (ToGlobals.MapAvailable (MapNr))
  769.       {
  770.         //
  771.         //   The current map is not imported, but is present. Therefore we
  772.         //   transfer it to the work file.
  773.         //
  774.         if (Error == errOk) Error = ToGlobals.Load (&Map, MapNr);
  775.  
  776.         if (Error == errOk && Flags->Format != cUndetermined)
  777.         {
  778.           Error = ToGlobals.Compress (&Map, Flags->Format);
  779.         }
  780.  
  781.         if (Error == errOk) Error = ToGlobals.Save (&Map, MapNr);
  782.       }
  783.     }
  784.  
  785.     //
  786.     //   Advance to the next map, but only if no errors occured.
  787.     //
  788.     if (Error == errOk) MapNr++;
  789.   }
  790.  
  791.   //
  792.   //   Close the maps and the local maps.
  793.   //
  794.   if (Error == errOk) Error = ToGlobals.Close ();
  795.   if (Error == errOk) Error = FromGlobals.Close ();
  796.  
  797.   //
  798.   //   Display the number of maps exported if no errors occured. Otherwise,
  799.   //   display the correct error message.
  800.   //
  801.   if (Error == errOk)
  802.   {
  803.     fprintf (stderr, "Imported %d %s from the intermediate version.\n",
  804.              Imported, Imported == 1 ? "map" : "maps"
  805.             );
  806.     return cOk;
  807.   }
  808.   else
  809.   {
  810.     Message (Error, MapNr, cTrue);
  811.     return cError;
  812.   }
  813. }
  814.  
  815. int ConvertFormat (FlagsRec *Flags, unsigned NewFormat)
  816. {
  817.   MapGlobalRec Globals;
  818.  
  819.   //
  820.   //   Try opening the requested maps version.
  821.   //
  822.   int                 Error = Globals.Open (Flags->Version);
  823.   if (Error == errOk) Error = Globals.OpenWork ();
  824.  
  825.   //
  826.   //   Walk every map in the maps file.
  827.   //
  828.   unsigned MapNr     = 0;
  829.   unsigned Converted = 0;
  830.  
  831.   while (Error == errOk && MapNr < Globals.MapCount () )
  832.   {
  833.     //
  834.     //   Convert the current map to the new format, but only if it is
  835.     //   actually present in the maps file.
  836.     //
  837.     if ( Globals.MapAvailable (MapNr) )
  838.     {
  839.       //
  840.       //   Process to current map.
  841.       //
  842.       GameMapRec Map;
  843.       Map.SetFormat (Flags->Format);
  844.  
  845.       if (Error == errOk) Error = Globals.Load     (&Map, MapNr);
  846.       if (Error == errOk) Error = Globals.Compress (&Map, NewFormat);
  847.       if (Error == errOk) Error = Globals.Save     (&Map, MapNr);
  848.  
  849.       Converted++;
  850.     }
  851.  
  852.     //
  853.     //   Advance to the next map, but only if no errors occured.
  854.     //
  855.     if (Error == errOk) MapNr++;
  856.   }
  857.  
  858.   //
  859.   //   Close the maps and convert the game maps filename if necessary.
  860.   //
  861.   if (Error == errOk) Error = Globals.ConvertName (NewFormat);
  862.   if (Error == errOk) Error = Globals.Close ();
  863.  
  864.   //
  865.   //   Display the number of maps converted if no errors occured. Otherwise,
  866.   //   display the correct error message.
  867.   //
  868.   if (Error == errOk)
  869.   {
  870.     fprintf (stderr, "Converted %d %s to v1.%d format.\n",
  871.              Converted, Converted == 1 ? "map" : "maps",
  872.              NewFormat == cFormat10 ? 0 : 1
  873.             );
  874.     return cOk;
  875.   }
  876.   else
  877.   {
  878.     Message (Error, MapNr, cTrue);
  879.     return cError;
  880.   }
  881. }
  882.  
  883. int PrintMaps (FlagsRec *Flags, FILE *Stream)
  884. {
  885.   MapGlobalRec Globals;
  886.  
  887.   //
  888.   //   Try opening the requested maps version.
  889.   //
  890.   int Error = Globals.Open (Flags->Version);
  891.  
  892.   //
  893.   //   Open the single output file, if requested.
  894.   //
  895.   if (Flags->Output == cSingle)
  896.   {
  897.     Stream = fopen ("LEVELS.MAP", "wt");
  898.     if (Stream == NULL) Error = errCreateOutput;
  899.   }
  900.  
  901.   //
  902.   //   Process all requested maps, one at a time.
  903.   //
  904.   unsigned MapNr   = 0;
  905.   unsigned Printed = 0;
  906.  
  907.   while (Error == errOk && MapNr < Globals.MapCount () )
  908.   {
  909.     //
  910.     //   Check if this map is requested for printing. Check only real,
  911.     //   available maps.
  912.     //
  913.     if (Globals.MapAvailable (MapNr) && MapChosen (Flags, MapNr) )
  914.     {
  915.       //
  916.       //   This map was requested, so process it.
  917.       //
  918.       GameMapRec Map;
  919.       Map.SetFormat (Flags->Format);
  920.  
  921.       //
  922.       //   If output goes to unique files, open a unique output file for
  923.       //   this map.
  924.       //
  925.       if (Flags->Output == cSeparate)
  926.       {
  927.         char LevelName [13];
  928.         sprintf (LevelName, "LEVEL%03d.MAP", MapNr);
  929.         Stream = fopen (LevelName, "wt");
  930.         if (Stream == NULL) Error = errCreateOutput;
  931.       }
  932.  
  933.       //
  934.       //   Print the current map, if the output stream is opened.
  935.       //
  936.       if (Error == errOk) Error = Globals.Load     (&Map, MapNr);
  937.       if (Error == errOk) Error = Globals.Compress (&Map, cDecompressed);
  938.       if (Error == errOk) Error = Map.Print        (Stream, MapNr);
  939.       if (Error == errOk) fprintf (Stream, "\f");
  940.  
  941.       //
  942.       //   If a separate output file is open, close it.
  943.       //
  944.       if (Flags->Output == cSeparate) fclose (Stream);
  945.  
  946.       Printed++;
  947.     }
  948.  
  949.     //
  950.     //   Advance to the next map, but only if no errors occured.
  951.     //
  952.     if (Error == errOk) MapNr++;
  953.   }
  954.  
  955.   //
  956.   //   Close the maps.
  957.   //
  958.   if (Error == errOk) Error = Globals.Close ();
  959.  
  960.   //
  961.   //   Print a legend to the (possible separate) output stream if requested.
  962.   //   legend to the file if one was requested.
  963.   //
  964.   if (Flags->Legend)
  965.   {
  966.     //
  967.     //   Open a legend file if separate files are requested.
  968.     //
  969.     if (Flags->Output == cSeparate)
  970.     {
  971.       Stream = fopen ("LEGEND.MAP", "wt");
  972.       if (Stream == NULL) Error = errCreateOutput;
  973.     }
  974.  
  975.     //
  976.     //   Print the legend, followed by a form feed.
  977.     //
  978.     if (Error == errOk) Error = PrintLegend (Stream);
  979.     if (Error == errOk) fprintf (Stream, "\f");
  980.  
  981.     //
  982.     //   If a separate legend file is open, close it.
  983.     //
  984.     if (Flags->Output == cSeparate) fclose (Stream);
  985.   }
  986.  
  987.   //
  988.   //   Close the output stream if the single output file was open.
  989.   //
  990.   if (Flags->Output == cSingle) fclose (Stream);
  991.  
  992.   //
  993.   //   Display the number of maps printed if no errors occured. Otherwise,
  994.   //   display the correct error message.
  995.   //
  996.   if (Error == errOk)
  997.   {
  998.     fprintf (stderr, "Printed %d %s.\n",
  999.              Printed, Printed == 1 ? "map" : "maps"
  1000.             );
  1001.     return cOk;
  1002.   }
  1003.   else
  1004.   {
  1005.     Message (Error, MapNr, cFalse);
  1006.     return cError;
  1007.   }
  1008. }
  1009.  
  1010. int PrintMapStatistics (FlagsRec *Flags, FILE *Stream)
  1011. {
  1012.   MapGlobalRec Globals;
  1013.  
  1014.   //
  1015.   //   Try opening the requested maps version.
  1016.   //
  1017.   int Error = Globals.Open (Flags->Version);
  1018.  
  1019.   //
  1020.   //   Open the single output file, if requested.
  1021.   //
  1022.   if (Flags->Output == cSingle)
  1023.   {
  1024.     Stream = fopen ("LEVELS.STA", "wt");
  1025.     if (Stream == NULL) Error = errCreateOutput;
  1026.   }
  1027.  
  1028.   //
  1029.   //   Process all requested maps, one at a time.
  1030.   //
  1031.   unsigned MapNr   = 0;
  1032.   unsigned Printed = 0;
  1033.  
  1034.   while (Error == errOk && MapNr < Globals.MapCount () )
  1035.   {
  1036.     //
  1037.     //   Check if this map is requested for printing. Check only real,
  1038.     //   available maps.
  1039.     //
  1040.     if (Globals.MapAvailable (MapNr) && MapChosen (Flags, MapNr) )
  1041.     {
  1042.       //
  1043.       //   This map was requested, so process it.
  1044.       //
  1045.       GameMapRec Map;
  1046.       Map.SetFormat (Flags->Format);
  1047.  
  1048.       //
  1049.       //   Open a unique output file for this map, if requested.
  1050.       //
  1051.       if (Flags->Output == cSeparate)
  1052.       {
  1053.         char LevelName [13];
  1054.         sprintf (LevelName, "LEVEL%03d.STA", MapNr);
  1055.         Stream = fopen (LevelName, "wt");
  1056.         if (Stream == NULL) Error = errCreateOutput;
  1057.       }
  1058.  
  1059.       if (Error == errOk) Error = Globals.Load        (&Map, MapNr);
  1060.       if (Error == errOk) Error = Globals.Compress    (&Map, cDecompressed);
  1061.       if (Error == errOk) Error = Map.Statistics      ();
  1062.       if (Error == errOk) Error = Map.PrintStatistics (Stream, MapNr);
  1063.       if (Error == errOk) fprintf (Stream, "\n\n\n\n");
  1064.  
  1065.       Printed++;
  1066.  
  1067.       //
  1068.       //   Print a copyright notice on the bottom of every page.
  1069.       //
  1070.       if (Flags->Output == cSeparate || (Printed & 1) == 0)
  1071.       {
  1072.         if (Error == errOk) fprintf (Stream, "Printed with %s.\n%s\n\f", cVersion, cCopyright);
  1073.       }
  1074.  
  1075.       //
  1076.       //   Close the output stream if output goes to separate files.
  1077.       //
  1078.       if (Flags->Output == cSeparate) fclose (Stream);
  1079.     }
  1080.  
  1081.     //
  1082.     //   Advance to the next map, but only if no errors occured.
  1083.     //
  1084.     if (Error == errOk) MapNr++;
  1085.   }
  1086.  
  1087.   //
  1088.   //   Close the maps.
  1089.   //
  1090.   if (Error == errOk) Error = Globals.Close ();
  1091.  
  1092.   //
  1093.   //   Close the output stream if the single output file was open.
  1094.   //
  1095.   if (Flags->Output == cSingle)
  1096.   {
  1097.     fclose (Stream);
  1098.   }
  1099.  
  1100.   //
  1101.   //   Display the number of maps printed if no errors occured. Otherwise,
  1102.   //   display the correct error message.
  1103.   //
  1104.   if (Error == errOk)
  1105.   {
  1106.     fprintf (stderr, "Printed statistics of %d %s.\n",
  1107.              Printed, Printed == 1 ? "map" : "maps"
  1108.             );
  1109.     return cOk;
  1110.   }
  1111.   else
  1112.   {
  1113.     Message (Error, MapNr, cFalse);
  1114.     return cError;
  1115.   }
  1116. }
  1117.  
  1118. int PrintLegend (FlagsRec *Flags, FILE *Stream)
  1119. {
  1120.   int Error = errOk;
  1121.  
  1122.   //
  1123.   //   Open the single output file, if requested.
  1124.   //
  1125.   if (Flags->Output == cSingle || Flags->Output == cSeparate)
  1126.   {
  1127.     Stream = fopen ("LEGEND.MAP", "wt");
  1128.     if (Stream == NULL) Error = errCreateOutput;
  1129.   }
  1130.  
  1131.   if (Error == errOk) Error = PrintLegend (Stream);
  1132.   if (Error == errOk) fprintf (Stream, "\f");
  1133.  
  1134.   if (Flags->Output == cSingle || Flags->Output == cSeparate)
  1135.   {
  1136.     fclose (Stream);
  1137.   }
  1138.  
  1139.   //
  1140.   //   Display a message indicating sucecss if no errors occured. Otherwise,
  1141.   //   display the correct error message.
  1142.   //
  1143.   if (Error == errOk)
  1144.   {
  1145.     fprintf (stderr, "Printed the legend of the maps.\n");
  1146.     return cOk;
  1147.   }
  1148.   else
  1149.   {
  1150.     Message (Error, 0, cFalse);
  1151.     return cError;
  1152.   }
  1153. }
  1154.  
  1155. int DisplayTitles (FlagsRec *Flags)
  1156. {
  1157.   MapGlobalRec Globals;
  1158.  
  1159.   //
  1160.   //   Open the requested version, display the titles and close the version
  1161.   //   again.
  1162.   //
  1163.   int                 Error = Globals.Open (Flags->Version);
  1164.   if (Error == errOk) Error = Globals.DisplayHeaders (stdout, Flags->Columns);
  1165.   if (Error == errOk) Error = Globals.Close ();
  1166.  
  1167.   //
  1168.   //   If an error occured, display the correct error message.
  1169.   //
  1170.   if (Error != errOk)
  1171.   {
  1172.     Message (Error, 0, cFalse);
  1173.     return cError;
  1174.   }
  1175.  
  1176.   //
  1177.   //   No errors, so return Ok.
  1178.   //
  1179.   return cOk;
  1180. }
  1181.  
  1182. int DisplayStatistics (FlagsRec *Flags)
  1183. {
  1184.   MapGlobalRec Globals;
  1185.  
  1186.   //
  1187.   //   Open the requested version.
  1188.   //
  1189.   int Error = Globals.Open (Flags->Version);
  1190.  
  1191.   unsigned MapNr = 0;
  1192.   unsigned Count = 0;
  1193.  
  1194.   //
  1195.   //   Determine the number of maps actually present.
  1196.   //
  1197.   while (MapNr < Globals.MapCount () )
  1198.   {
  1199.     if (Globals.MapAvailable (MapNr) ) Count++;
  1200.     MapNr++;
  1201.   }
  1202.  
  1203.   //
  1204.   //   Display a message if no maps are available. Otherwise, display the
  1205.   //   column headers.
  1206.   //
  1207.   if (Error == errOk)
  1208.   {
  1209.     if (Count == 0)
  1210.     {
  1211.       fprintf (stdout, "Sorry, there are no maps present in this version.\n");
  1212.     }
  1213.     else
  1214.     {
  1215.       fprintf (stdout, "Map #   Title              Door Lock Secr Elev Trea Lvl1 Lvl3 Lvl4 Huge\n");
  1216.       fprintf (stdout, "=====   ================   ==== ==== ==== ==== ==== ==== ==== ==== ====\n\n");
  1217.     }
  1218.   }
  1219.  
  1220.   MapNr = 0;
  1221.  
  1222.   //
  1223.   //   Walk every map. If the current map is available, read and decompress
  1224.   //   it and display a line with statistics about this map.
  1225.   //
  1226.   while (Error == errOk && MapNr < Globals.MapCount () )
  1227.   {
  1228.     if (Globals.MapAvailable (MapNr) )
  1229.     {
  1230.       GameMapRec Map;
  1231.       Map.SetFormat (Flags->Format);
  1232.  
  1233.       if (Error == errOk) Error = Globals.Load     (&Map, MapNr);
  1234.       if (Error == errOk) Error = Globals.Compress (&Map, cDecompressed);
  1235.       if (Error == errOk) Error = Map.Statistics   ();
  1236.       if (Error == errOk)
  1237.       {
  1238.         //
  1239.         //   Determine the totals of the actors in the map.
  1240.         //
  1241.         unsigned sActors1 = Map.Actors (oGuard1) + Map.Actors (oOfficer1) + Map.Actors (oSS1) + Map.Actors (oUndead1);
  1242.         unsigned mActors1 = Map.Actors (omGuard1)+ Map.Actors (omOfficer1)+ Map.Actors (omSS1)+ Map.Actors (omUndead1)+ Map.Actors (oDog1);
  1243.         unsigned sActors3 = Map.Actors (oGuard3) + Map.Actors (oOfficer3) + Map.Actors (oSS3) + Map.Actors (oUndead3);
  1244.         unsigned mActors3 = Map.Actors (omGuard3)+ Map.Actors (omOfficer3)+ Map.Actors (omSS3)+ Map.Actors (omUndead3)+ Map.Actors (oDog3);
  1245.         unsigned sActors4 = Map.Actors (oGuard4) + Map.Actors (oOfficer4) + Map.Actors (oSS4) + Map.Actors (oUndead4);
  1246.         unsigned mActors4 = Map.Actors (omGuard4)+ Map.Actors (omOfficer4)+ Map.Actors (omSS4)+ Map.Actors (omUndead4)+ Map.Actors (oDog4);
  1247.  
  1248.         //
  1249.         //   Display one line of information.
  1250.         //
  1251.         fprintf (stdout, "%5u   %-16s   %4u %4u %4u %4u %4u %4u %4u %4u %4u\n",
  1252.                  MapNr,
  1253.                  Map.Title (),
  1254.                  Map.Doors (),
  1255.                  Map.LockedDoors (),
  1256.                  Map.SecretDoors (),
  1257.                  Map.Elevators (),
  1258.                  Map.Treasures (),
  1259.                  sActors1 + mActors1,
  1260.                  sActors1 + mActors1 + sActors3 + mActors3,
  1261.                  sActors1 + mActors1 + sActors3 + mActors3 + sActors4 + mActors4,
  1262.                  Map.HugeActors ()
  1263.                 );
  1264.       }
  1265.     }
  1266.  
  1267.     if (Error == errOk) MapNr++;
  1268.   }
  1269.  
  1270.   //
  1271.   //   Close the opened version.
  1272.   //
  1273.   if (Error == errOk) Error = Globals.Close ();
  1274.  
  1275.   //
  1276.   //   If an error occured, display the correct error message.
  1277.   //
  1278.   if (Error != errOk)
  1279.   {
  1280.     Message (Error, MapNr, cFalse);
  1281.     return cError;
  1282.   }
  1283.  
  1284.   //
  1285.   //   No errors, so return Ok.
  1286.   //
  1287.   return cOk;
  1288. }
  1289.  
  1290. int ModifyMaps (FlagsRec *Flags)
  1291. {
  1292.   MapGlobalRec Globals;
  1293.   GraphRec     Editor;
  1294.  
  1295.   int Error    = errOk;
  1296.   int Changed  = cFalse;
  1297.   int Command  = cNone;
  1298.   int MapNr    = 0;
  1299.   int Episode  = 0;
  1300.   int Finished = cFalse;
  1301.   int Modified = 0;
  1302.   int Created  = cFalse;
  1303.  
  1304.   //
  1305.   //   Open the requested version of the maps files and the graphics editor.
  1306.   //   If a specific version is given but non existing, it will be created.
  1307.   //
  1308.   Error = Globals.Open (Flags->Version);
  1309.  
  1310.   if (Error == errNoSuchVersion)
  1311.   {
  1312.     Error   = Globals.Create (Flags->Version);
  1313.     Created = cTrue;
  1314.   }
  1315.  
  1316.   if (Error == errOk) Error = Editor.Open ();
  1317.  
  1318.   //
  1319.   //   Display / Edit one map and execute the resulting command.
  1320.   //
  1321.   while (Error == errOk && !Finished)
  1322.   {
  1323.     GameMapRec Map;
  1324.     unsigned   Format = Flags->Format;
  1325.  
  1326.     //
  1327.     //   Get the requested map in the local GameMap class instance. First,
  1328.     //   check if a modified copy already exists in the store. If not, check
  1329.     //   if the map is in the file. If not, create a new one from scratch.
  1330.     //
  1331.     if (Globals.InStore (Episode*10 + MapNr) )
  1332.     {
  1333.       Error  = Globals.Copy (&Map, Episode*10 + MapNr);
  1334.       Format = Map.Format ();
  1335.     }
  1336.     else
  1337.     {
  1338.       if (Globals.MapAvailable (Episode*10 + MapNr) )
  1339.       {
  1340.         Error = Globals.Load (&Map, Episode*10 + MapNr);
  1341.         if (Error == errOk)          Error  = Map.DetermineFormat ();
  1342.         if (Format == cUndetermined) Format = Map.Format ();
  1343.       }
  1344.       else
  1345.       {
  1346.         if (Globals.MapPossible (Episode*10 + MapNr) )
  1347.         {
  1348.           char Title [16];
  1349.           if (MapNr == 9) sprintf (Title, "Wolf%d Secret", Episode+1);
  1350.           if (MapNr == 8) sprintf (Title, "Wolf%d Boss", Episode+1);
  1351.           if (MapNr <= 7) sprintf (Title, "Wolf%d Map%d", Episode+1, MapNr+1);
  1352.  
  1353.           Error = Map.Create (64, 64, Title);
  1354.           if (Format == cUndetermined) Format = cFormat11;
  1355.         }
  1356.       }
  1357.     }
  1358.  
  1359.     //
  1360.     //   Show the map, modify it and catch the resulting command.
  1361.     //
  1362.     Changed = cFalse;
  1363.     Command = cNone;
  1364.  
  1365.     if (Error == errOk) Error = Globals.Compress (&Map, cDecompressed);
  1366.     if (Error == errOk) Error = Editor.Display (&Map, Episode, MapNr);
  1367.     if (Error == errOk) Error = Editor.Modify (&Map, &Changed, &Command);
  1368.  
  1369.     //
  1370.     //   Process the resulting command.
  1371.     //
  1372.     int NewEpisode = Episode;
  1373.     int NewMapNr   = MapNr;
  1374.  
  1375.     switch (Command)
  1376.     {
  1377.       case cMap0:        NewMapNr   = 0; break;
  1378.       case cMap1:        NewMapNr   = 1; break;
  1379.       case cMap2:        NewMapNr   = 2; break;
  1380.       case cMap3:        NewMapNr   = 3; break;
  1381.       case cMap4:        NewMapNr   = 4; break;
  1382.       case cMap5:        NewMapNr   = 5; break;
  1383.       case cMap6:        NewMapNr   = 6; break;
  1384.       case cMap7:        NewMapNr   = 7; break;
  1385.       case cMap8:        NewMapNr   = 8; break;
  1386.       case cMap9:        NewMapNr   = 9; break;
  1387.       case cNextMap:     NewMapNr   = MapNr == 9 ? 0 : MapNr + 1; break;
  1388.       case cPrevMap:     NewMapNr   = MapNr == 0 ? 9 : MapNr - 1; break;
  1389.       case cNextEpisode: NewEpisode = Episode == 5 ? 0 : Episode + 1; NewMapNr = 0; break;
  1390.       case cPrevEpisode: NewEpisode = Episode == 0 ? 5 : Episode - 1; NewMapNr = 0; break;
  1391.       case cBreak:
  1392.         Changed  = cFalse;
  1393.         Finished = cTrue;
  1394.         Modified = 0;
  1395.         break;
  1396.       case cExit:
  1397.         Finished = cTrue;
  1398.         break;
  1399.       case cEscape:
  1400.         Changed = cFalse;
  1401.         break;
  1402.       case cDiscard:
  1403.         Error   = Globals.Delete (Episode*10 + MapNr);
  1404.         Changed = cFalse;
  1405.         break;
  1406.     }
  1407.  
  1408.     //
  1409.     //   If the current map has been modified, compress it again and store it.
  1410.     //
  1411.     if (Changed)
  1412.     {
  1413.       if (Error == errOk) Error = Globals.Compress (&Map, Format);
  1414.       if (Error == errOk) Error = Globals.Add (&Map, Episode*10 + MapNr);
  1415.       Modified = Globals.MapsStored ();
  1416.     }
  1417.  
  1418.     //
  1419.     //   Advance to the selected map / episode.
  1420.     //
  1421.     Episode = NewEpisode;
  1422.     MapNr   = NewMapNr;
  1423.   }
  1424.  
  1425.   //
  1426.   //   Close the editor and redisplay the banner.
  1427.   //
  1428.   if (Error != errInitializeGraph)
  1429.   {
  1430.     Editor.Close ();
  1431.     ShowBanner ();
  1432.   }
  1433.  
  1434.   //
  1435.   //   Write any changed maps back into the maps files.
  1436.   //
  1437.   if (Modified != 0)
  1438.   {
  1439.     //
  1440.     //   Open the work files.
  1441.     //
  1442.     if (Error == errOk && !Created) Error = Globals.OpenWork ();
  1443.  
  1444.     MapNr = 0;
  1445.     while (Error == errOk && MapNr < Globals.MapCount () )
  1446.     {
  1447.       GameMapRec Map;
  1448.  
  1449.       //
  1450.       //   Save and delete the map in the store, if one is available.
  1451.       //   Otherwise, copy the map from the origional file unchanged.
  1452.       //
  1453.       if ( Globals.InStore (MapNr) )
  1454.       {
  1455.         if (Error == errOk) Error = Globals.Copy (&Map, MapNr);
  1456.         if (Error == errOk) Error = Globals.Save (&Map, MapNr);
  1457.         if (Error == errOk) Error = Globals.Delete (MapNr);
  1458.       }
  1459.       else if ( Globals.MapAvailable (MapNr) )
  1460.       {
  1461.         if (Error == errOk) Error = Globals.Load (&Map, MapNr);
  1462.         if (Error == errOk) Error = Globals.Save (&Map, MapNr);
  1463.       }
  1464.  
  1465.       //
  1466.       //   Advance to the next map.
  1467.       //
  1468.       MapNr++;
  1469.     }
  1470.   }
  1471.  
  1472.   //
  1473.   //   Close the maps file.
  1474.   //
  1475.   if (Error == errOk) Error = Globals.Close ();
  1476.  
  1477.   //
  1478.   //   Display the number of maps modified if no errors occured. Otherwise,
  1479.   //   display the correct error message.
  1480.   //
  1481.   if (Error == errOk)
  1482.   {
  1483.     fprintf (stderr, "Modified and saved %d %s.\n", Modified, Modified == 1 ? "map" : "maps");
  1484.     return cOk;
  1485.   }
  1486.   else
  1487.   {
  1488.     Message (Error, 0, cFalse);
  1489.     return cError;
  1490.   }
  1491. }
  1492.  
  1493. int main (int argc, char **argv)
  1494. {
  1495.   //
  1496.   //   Display banner on the screen.
  1497.   //
  1498.   ShowBanner ();
  1499.  
  1500.   //
  1501.   //   If no arguments are passed on the command line, show a complete
  1502.   //   description of this program and exit.
  1503.   //
  1504.   if (argc == 1)
  1505.   {
  1506.     ShowHelp ();
  1507.     return cNoCommands;
  1508.   }
  1509.  
  1510.   //
  1511.   //   Process the arguments. If an error has been detected, show the
  1512.   //   correct usage on the screen and exit.
  1513.   //
  1514.   FlagsRec Flags;
  1515.   int      Command = ProcessParameters (argc, argv, &Flags);
  1516.  
  1517.   //
  1518.   //   The command line has been processed. Now process the given command.
  1519.   //
  1520.   switch (Command)
  1521.   {
  1522.     case cHelp:          return ShowCommands       ();
  1523.     case cConvert10:     return ConvertFormat      (&Flags, cFormat10);
  1524.     case cConvert11:     return ConvertFormat      (&Flags, cFormat11);
  1525.     case cPrintMaps:     return PrintMaps          (&Flags, stdout);
  1526.     case cPrintMapStats: return PrintMapStatistics (&Flags, stdout);
  1527.     case cPrintLegend:   return PrintLegend        (&Flags, stdout);
  1528.     case cDisplayTitles: return DisplayTitles      (&Flags);
  1529.     case cDisplayStats:  return DisplayStatistics  (&Flags);
  1530.     case cModify:        return ModifyMaps         (&Flags);
  1531.     case cExportMaps:    return Export             (&Flags);
  1532.     case cImportMaps:    return Import             (&Flags);
  1533.     default:             return cIllegalCommand;
  1534.   }
  1535. }
  1536.  
  1537.