home *** CD-ROM | disk | FTP | other *** search
/ Game Killer / Game_Killer.bin / 530.WGAMEMAP.C < prev    next >
C/C++ Source or Header  |  1992-10-13  |  25KB  |  734 lines

  1. /*
  2.  
  3. ---------------------------------------------------------------------------
  4. | GameMap 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.05        11/10/92 | Removed all explicit references to far   |
  9. |                              | pointers and changed the memory model to |
  10. |                              | large.                                   |
  11. |                              | J.P. Dijkstra, M.Sc.                     |
  12. | Version 1.5         12/10/92 | Added a function which copies the entire |
  13. |                              | contents of one GameMap to another.      |
  14. |                              | J.P. Dijkstra, M.Sc.                     |
  15. | Version 1.51        13/10/92 | Fixed a bug in the Create member         |
  16. |                              | function. The Clear member function did  |
  17. |                              | not execute after field initialization,  |
  18. |                              | resulting in system crashes.             |
  19. |                              | J.P. Dijkstra, M.Sc.                     |
  20. ---------------------------------------------------------------------------
  21. | The GameMap class contains the logic to do the actual processing upon   |
  22. | one single map. It contains the storage space for the four blocks each  |
  23. | map consists of.                                                        |
  24. | Routines are provided for the following services. (De)compression for   |
  25. | the three compressed blocks for each format, loading and saving the of  |
  26. | the four blocks, calculating statistics information, and printing of    |
  27. | both the map and the map statistics.                                    |
  28. ---------------------------------------------------------------------------
  29.  
  30. */
  31.  
  32. #include "wolfmap.h"
  33. #include "stdio.h"
  34. #include "string.h"
  35. #include "bios.h"
  36.  
  37. /*
  38.  
  39. ---------------------------------------------------------------------------
  40. | Public functions to implement the desired API.                          |
  41. ---------------------------------------------------------------------------
  42. | Function name               | Description.                              |
  43. ---------------------------------------------------------------------------
  44.  
  45. */
  46.  
  47. GameMapRec::GameMapRec ()
  48. : Maze (), Objects (), Unknown ()
  49. {
  50.   //
  51.   //   Initialize the fields of this class.
  52.   //
  53.   ErrorCode       = errOk;
  54.   CurrentFormat   = cUndetermined;
  55.   HugeActorCount  = 0;
  56.   SecretDoorCount = 0;
  57.   LockedDoorCount = 0;
  58.   DoorCount       = 0;
  59.   ElevatorCount   = 0;
  60.   TreasureCount   = 0;
  61.  
  62.   //
  63.   //   Initialize the actor counters.
  64.   //
  65.   int Actor = oLastActor - oFirstActor + 1;
  66.   while (Actor-- > 0) ActorCount [Actor] = 0;
  67. }
  68.  
  69. GameMapRec::~GameMapRec ()
  70. {
  71.   Close ();
  72. }
  73.  
  74. int GameMapRec::SetError (int Error)
  75. {
  76.   //
  77.   //   Return the previous error code and set the error code to the
  78.   //   specified one.
  79.   //
  80.   int OldError = ErrorCode;
  81.   ErrorCode    = Error;
  82.   return OldError;
  83. }
  84.  
  85. unsigned GameMapRec::SetFormat (unsigned NewFormat)
  86. {
  87.   //
  88.   //   Return the previous compression format and set the compression format
  89.   //   to the specified one.
  90.   //
  91.   unsigned OldFormat = CurrentFormat;
  92.   CurrentFormat      = NewFormat;
  93.   return OldFormat;
  94. }
  95.  
  96. int GameMapRec::DetermineFormat ()
  97. {
  98.   //
  99.   //   First, determine this maze matrix size, in bytes.
  100.   //
  101.   unsigned MazeSize = (Header.SizeX * Header.SizeY) << 1;
  102.  
  103.   //
  104.   //   If all sizes are equal to the maze matrix size, the format is
  105.   //   uncompressed.
  106.   //
  107.   if (Maze.DataSize () == MazeSize && Objects.DataSize () == MazeSize && Unknown.DataSize () == MazeSize)
  108.   {
  109.     CurrentFormat = cDecompressed;
  110.     return errOk;
  111.   }
  112.  
  113.   //
  114.   //   The format was not uncompressed. Now determine the maze size for one
  115.   //   level of decompression. Currently, this size is stored in the first
  116.   //   word of the memory block. If this size equals the maze matrix size,
  117.   //   the compression format is v1.0 format, otherwise the format is assumed
  118.   //   to be v1.1 format.
  119.   //
  120.   unsigned MazeFormat    = *Maze.Data ()    == MazeSize ? cFormat10 : cFormat11;
  121.   unsigned ObjectsFormat = *Objects.Data () == MazeSize ? cFormat10 : cFormat11;
  122.   unsigned UnknownFormat = *Unknown.Data () == MazeSize ? cFormat10 : cFormat11;
  123.  
  124.   //
  125.   //   One last check. If the formats for the three memory blocks do not
  126.   //   agree to the same format, v1.1 format is assumed.
  127.   //   Note, however, that this probably indicates an error.
  128.   //
  129.   CurrentFormat = MazeFormat == ObjectsFormat && MazeFormat == UnknownFormat ? MazeFormat : cFormat11;
  130.  
  131.   return errOk;
  132. }
  133.  
  134. int GameMapRec::CompressFormat10 (unsigned MagicValue)
  135. {
  136.   //
  137.   //   Compress the three data blocks to the v1.0 format.
  138.   //
  139.   int                 Error = Maze.CompressFormat10    (MagicValue);
  140.   if (Error == errOk) Error = Objects.CompressFormat10 (MagicValue);
  141.   if (Error == errOk) Error = Unknown.CompressFormat10 (MagicValue);
  142.  
  143.   //
  144.   //   Return the result of this function.
  145.   //
  146.   if (Error != errOk) SetError (Error);
  147.  
  148.   return Error;
  149. }
  150.  
  151. int GameMapRec::CompressFormat11 ()
  152. {
  153.   //
  154.   //   Compress the three data blocks to the v1.1 format.
  155.   //
  156.   int                 Error = Maze.CompressFormat11    ();
  157.   if (Error == errOk) Error = Objects.CompressFormat11 ();
  158.   if (Error == errOk) Error = Unknown.CompressFormat11 ();
  159.  
  160.   //
  161.   //   Return the result of this function.
  162.   //
  163.   if (Error != errOk) SetError (Error);
  164.  
  165.   return Error;
  166. }
  167.  
  168. int GameMapRec::DecompressFormat10 (unsigned MagicValue)
  169. {
  170.   //
  171.   //   Decompress the three data blocks from the v1.0 format.
  172.   //
  173.   int                 Error = Maze.DecompressFormat10    (MagicValue);
  174.   if (Error == errOk) Error = Objects.DecompressFormat10 (MagicValue);
  175.   if (Error == errOk) Error = Unknown.DecompressFormat10 (MagicValue);
  176.  
  177.   //
  178.   //   Return the result of this function.
  179.   //
  180.   if (Error != errOk) SetError (Error);
  181.  
  182.   return Error;
  183. }
  184.  
  185. int GameMapRec::DecompressFormat11 ()
  186. {
  187.   //
  188.   //   Decompress the three data blocks from the v1.1 format.
  189.   //
  190.   int                 Error = Maze.DecompressFormat11    ();
  191.   if (Error == errOk) Error = Objects.DecompressFormat11 ();
  192.   if (Error == errOk) Error = Unknown.DecompressFormat11 ();
  193.  
  194.   //
  195.   //   Return the result of this function.
  196.   //
  197.   if (Error != errOk) SetError (Error);
  198.  
  199.   return Error;
  200. }
  201.  
  202. int GameMapRec::Load (int Handle, long HeaderPos)
  203. {
  204.   //
  205.   //   First, read the map header into memory.
  206.   //
  207.   int Error = ReadData (Handle, HeaderPos, &Header, sizeof (MapHeaderRec) );
  208.  
  209.   //
  210.   //   Now allocate enough memory to hold the three data blocks.
  211.   //
  212.   if (Error == errOk) Error = Maze.Allocate (Header.SizeMaze);
  213.   if (Error == errOk) Error = Objects.Allocate (Header.SizeObjects);
  214.   if (Error == errOk) Error = Unknown.Allocate (Header.SizeUnknown);
  215.  
  216.   //
  217.   //   Now read the three data blocks into the allocated memory.
  218.   //
  219.   if (Error == errOk) Error = ReadData (Handle, Header.StartMaze, Maze.Data (), Header.SizeMaze);
  220.   if (Error == errOk) Error = ReadData (Handle, Header.StartObjects, Objects.Data (), Header.SizeObjects);
  221.   if (Error == errOk) Error = ReadData (Handle, Header.StartUnknown, Unknown.Data (), Header.SizeUnknown);
  222.  
  223.   //
  224.   //   Finally, process the error if one occured and return the result.
  225.   //
  226.   if (Error != errOk) SetError (Error);
  227.  
  228.   return Error;
  229. }
  230.  
  231. int GameMapRec::Save (int Handle, long *HeaderPos)
  232. {
  233.   //
  234.   //   First, set the data block sizes in the header structure to the correct
  235.   //   values.
  236.   //
  237.   int Error = errOk;
  238.  
  239.   Header.SizeMaze    = Maze.DataSize ();
  240.   Header.SizeObjects = Objects.DataSize ();
  241.   Header.SizeUnknown = Unknown.DataSize ();
  242.  
  243.   //
  244.   //   Now write the three data blocks from the allocated memory to the file.
  245.   //   The header will be adjusted to reflect the correct starting positions
  246.   //   for each of the three data blocks.
  247.   //
  248.   if (Error == errOk) Error = WriteData (Handle, &Header.StartMaze, Maze.Data (), Header.SizeMaze);
  249.   if (Error == errOk) Error = WriteData (Handle, &Header.StartObjects, Objects.Data (), Header.SizeObjects);
  250.   if (Error == errOk) Error = WriteData (Handle, &Header.StartUnknown, Unknown.Data (), Header.SizeUnknown);
  251.  
  252.   //
  253.   //   Now write the map header to the file.
  254.   //
  255.   Error = WriteData (Handle, HeaderPos, &Header, sizeof (MapHeaderRec) );
  256.  
  257.   //
  258.   //   Finally, process the error if one occured and return the result.
  259.   //
  260.   if (Error != errOk) SetError (Error);
  261.   return Error;
  262. }
  263.  
  264. int GameMapRec::Copy (GameMapRec *Source)
  265. {
  266.   int Error = errOk;
  267.  
  268.   //
  269.   //   Only copy when the source is allocated.
  270.   //
  271.   if (Source->Maze.Data () != NULL && Source->Objects.Data () != NULL && Source->Unknown.Data () != NULL)
  272.   {
  273.     //
  274.     //   First copy the three data blocks.
  275.     //
  276.     if (Error == errOk) Error = Maze.Copy (&Source->Maze);
  277.     if (Error == errOk) Error = Objects.Copy (&Source->Objects);
  278.     if (Error == errOk) Error = Unknown.Copy (&Source->Unknown);
  279.  
  280.     //
  281.     //   Now copy the private fields.
  282.     //
  283.     if (Error == errOk)
  284.     {
  285.       CurrentFormat   = Source->CurrentFormat;
  286.       HugeActorCount  = Source->HugeActorCount;
  287.       SecretDoorCount = Source->SecretDoorCount;
  288.       LockedDoorCount = Source->LockedDoorCount;
  289.       DoorCount       = Source->DoorCount;
  290.       ElevatorCount   = Source->ElevatorCount;
  291.       TreasureCount   = Source->TreasureCount;
  292.       Header          = Source->Header;
  293.  
  294.       int Actor = oLastActor - oFirstActor + 1;
  295.       while (Actor-- > 0) ActorCount [Actor] = Source->ActorCount [Actor];
  296.     }
  297.   }
  298.  
  299.   //
  300.   //   Finally, process the error if one occured and return the result.
  301.   //
  302.   if (Error != errOk) SetError (Error);
  303.   return Error;
  304. }
  305.  
  306. int GameMapRec::Close ()
  307. {
  308.   //
  309.   //   Free the memory blocks and reinitialize the private fields.
  310.   //
  311.   Maze.Free ();
  312.   Objects.Free ();
  313.   Unknown.Free ();
  314.  
  315.   CurrentFormat   = cUndetermined;
  316.   HugeActorCount  = 0;
  317.   SecretDoorCount = 0;
  318.   LockedDoorCount = 0;
  319.   DoorCount       = 0;
  320.   ElevatorCount   = 0;
  321.   TreasureCount   = 0;
  322.  
  323.   //
  324.   //   Reinitialize the actor counters.
  325.   //
  326.   int Actor = oLastActor - oFirstActor + 1;
  327.   while (Actor-- > 0) ActorCount [Actor] = 0;
  328.  
  329.   //
  330.   //   Return Ok to indicate success.
  331.   //
  332.   return errOk;
  333. }
  334.  
  335. int GameMapRec::Print (FILE *Stream, unsigned MapNr)
  336. {
  337.   //
  338.   //   Print a banner on the output stream.
  339.   //
  340.   fprintf (Stream, "WOLFENSTEIN 3D   -   Map #%u: %s\n\n", MapNr, Header.Title);
  341.  
  342.   //
  343.   //   Initialize the line counter and the pointers in the source data.
  344.   //
  345.   unsigned *MazeValue   = Maze.Data ();
  346.   unsigned *ObjectValue = Objects.Data ();
  347.   unsigned  PosY        = Header.SizeY;
  348.  
  349.   //
  350.   //   Process the maze, one line at a time.
  351.   //
  352.   while (PosY-- > 0)
  353.   {
  354.     //
  355.     //   Initialize the output line.
  356.     //
  357.     char Buffer [256];
  358.     char *Str     = Buffer;
  359.     unsigned PosX = Header.SizeX;
  360.  
  361.     //
  362.     //   Fill the output line, one maze cell at a time.
  363.     //
  364.     while (PosX-- > 0)
  365.     {
  366.       char First;
  367.       char Second;
  368.  
  369.       //
  370.       //   First figure out what maze cell we have.
  371.       //
  372.       switch ( DetermineMaze (*MazeValue) )
  373.       {
  374.         case mEntrance: First = 0xAE; Second = 0xAF; break;
  375.         case mElevator: First = 0xDB; Second = 0xDB; break;
  376.         case mvDoor:    First = 0xB3; Second = ' ';  break;
  377.         case mhDoor:    First = 0xC4; Second = 0xC4; break;
  378.         case mlyvDoor:  First = 0xBA; Second = ' ';  break;
  379.         case mlyhDoor:  First = 0xCD; Second = 0xCD; break;
  380.         case mlbvDoor:  First = 0xBA; Second = ' ';  break;
  381.         case mlbhDoor:  First = 0xCD; Second = 0xCD; break;
  382.         case mevDoor:   First = 0xC6; Second = 0xB5; break;
  383.         case mehDoor:   First = 0xC6; Second = 0xB5; break;
  384.         case mFloor:    First = ' ';  Second = ' ';  break;
  385.         case mWall:     First = 0xB2; Second = 0xB2; break;
  386.         default:        First = '*';  Second = '*';  break;
  387.       }
  388.  
  389.       //
  390.       //   Now figure out what object is standing in the maze cell. If it
  391.       //   is an importand object, we superimpose it over the maze
  392.       //   characters.
  393.       //
  394.       switch ( DetermineObject (*ObjectValue) )
  395.       {
  396.         case ouStart:      First = 0x18; Second = 0x18; break;
  397.         case orStart:      First = '-';  Second = '>';  break;
  398.         case odStart:      First = 0x19; Second = 0x19; break;
  399.         case olStart:      First = '<';  Second = '-';  break;
  400.         case oSecretDoor:  First = '[';  Second = ']';  break;
  401.         case oEndgame:     First = '%';  Second = '%';  break;
  402.         case oMachineGun:  First = 'm';  Second = 'g';  break;
  403.         case oGattlingGun: First = 'g';  Second = 'g';  break;
  404.         case oAmmunition:  First = 'a';  Second = ' ';  break;
  405.         case oFood:        First = 'f';  Second = ' ';  break;
  406.         case oFirstAid:    First = '+';  Second = ' ';  break;
  407.         case oTreasure:    First = 't';  Second = ' ';  break;
  408.         case oBlueKey:     First = 'b';  Second = 'k';  break;
  409.         case oYellowKey:   First = 'y';  Second = 'k';  break;
  410.         case oObstacle:    First = 'o';  Second = ' ';  break;
  411.         case oDeadGuard:   First = 'D';  Second = 'G';  break;
  412.         case oHans:        First = 'H';  Second = 'A';  break;
  413.         case oSchabbs:     First = 'D';  Second = 'S';  break;
  414.         case oGhostHitler: First = 'G';  Second = 'A';  break;
  415.         case oHitler:      First = 'A';  Second = 'H';  break;
  416.         case oGiftmacher:  First = 'O';  Second = 'G';  break;
  417.         case oGretel:      First = 'G';  Second = 'R';  break;
  418.         case oFettgesicht: First = 'G';  Second = 'F';  break;
  419.         case oGuard1:      First = 'G';  Second = '1';  break;
  420.         case oGuard3:      First = 'G';  Second = '3';  break;
  421.         case oGuard4:      First = 'G';  Second = '4';  break;
  422.         case oOfficer1:    First = 'O';  Second = '1';  break;
  423.         case oOfficer3:    First = 'O';  Second = '3';  break;
  424.         case oOfficer4:    First = 'O';  Second = '4';  break;
  425.         case oSS1:         First = 'S';  Second = '1';  break;
  426.         case oSS3:         First = 'S';  Second = '3';  break;
  427.         case oSS4:         First = 'S';  Second = '4';  break;
  428.         case oUndead1:     First = 'U';  Second = '1';  break;
  429.         case oUndead3:     First = 'U';  Second = '3';  break;
  430.         case oUndead4:     First = 'U';  Second = '4';  break;
  431.         case oDog1:        First = 'D';  Second = '1';  break;
  432.         case oDog3:        First = 'D';  Second = '3';  break;
  433.         case oDog4:        First = 'D';  Second = '4';  break;
  434.         case omGuard1:     First = 'G';  Second = '1';  break;
  435.         case omGuard3:     First = 'G';  Second = '3';  break;
  436.         case omGuard4:     First = 'G';  Second = '4';  break;
  437.         case omOfficer1:   First = 'O';  Second = '1';  break;
  438.         case omOfficer3:   First = 'O';  Second = '3';  break;
  439.         case omOfficer4:   First = 'O';  Second = '4';  break;
  440.         case omSS1:        First = 'S';  Second = '1';  break;
  441.         case omSS3:        First = 'S';  Second = '3';  break;
  442.         case omSS4:        First = 'S';  Second = '4';  break;
  443.         case omUndead1:    First = 'U';  Second = '1';  break;
  444.         case omUndead3:    First = 'U';  Second = '3';  break;
  445.         case omUndead4:    First = 'U';  Second = '4';  break;
  446.         case oPacman:      First = 'P';  Second = 'G';  break;
  447.       }
  448.  
  449.       //
  450.       //   Add the converted cell code to the buffer and advance the
  451.       //   pointers.
  452.       //
  453.       *(Str++) = First;
  454.       *(Str++) = Second;
  455.       MazeValue++;
  456.       ObjectValue++;
  457.     }
  458.  
  459.     //
  460.     //   Append the terminator to the line and output the filled line to
  461.     //   the output stream.
  462.     //
  463.     *Str = '\0';
  464.     fprintf (Stream, "%s\n", Buffer);
  465.   }
  466.  
  467.   //
  468.   //   The maze has been printed without any errors, so return Ok.
  469.   //
  470.   return errOk;
  471. }
  472.  
  473. int GameMapRec::PrintStatistics (FILE *Stream, unsigned MapNr)
  474. {
  475.   //
  476.   //   Print a banner on the output stream.
  477.   //
  478.   fprintf (Stream, "WOLFENSTEIN 3D   -   Statistics of map #%u: %s\n\n", MapNr, Header.Title);
  479.  
  480.   //
  481.   //   Print maze statistics.
  482.   //
  483.   fprintf (Stream, "Maze Size:           [%d,%d]\n", Header.SizeX, Header.SizeY);
  484.   fprintf (Stream, "Doors:               %d\n", Doors () );
  485.   fprintf (Stream, "Locked Doors:        %d\n", LockedDoors () );
  486.   fprintf (Stream, "Secret Doors:        %d\n", SecretDoors () );
  487.   fprintf (Stream, "Elevators:           %d\n", Elevators () );
  488.   fprintf (Stream, "Treasures:           %d\n", Treasures () );
  489.   fprintf (Stream, "Huge Guards:         %d\n\n", HugeActors () + Actors (oPacman) );
  490.  
  491.   //
  492.   //   Print the totals for stationary normal actors.
  493.   //
  494.   fprintf (Stream, "Statianory Actor     Level 1     Level 3     Level 4     Total 3     Total 4\n");
  495.   fprintf (Stream, "================     =======     =======     =======     =======     =======\n");
  496.   fprintf (Stream, "Brown Guard             %4u        %4u        %4u        %4u        %4u\n",
  497.            Actors (oGuard1), Actors (oGuard3), Actors (oGuard4),
  498.            Actors (oGuard1) + Actors (oGuard3),
  499.            Actors (oGuard1) + Actors (oGuard3) + Actors (oGuard4)
  500.           );
  501.   fprintf (Stream, "White Officer           %4u        %4u        %4u        %4u        %4u\n",
  502.            Actors (oOfficer1), Actors (oOfficer3), Actors (oOfficer4),
  503.            Actors (oOfficer1) + Actors (oOfficer3),
  504.            Actors (oOfficer1) + Actors (oOfficer3) + Actors (oOfficer4)
  505.           );
  506.   fprintf (Stream, "Blue SS Officer         %4u        %4u        %4u        %4u        %4u\n",
  507.            Actors (oSS1), Actors (oSS3), Actors (oSS4),
  508.            Actors (oSS1) + Actors (oSS3),
  509.            Actors (oSS1) + Actors (oSS3) + Actors (oSS4)
  510.           );
  511.   fprintf (Stream, "Undead                  %4u        %4u        %4u        %4u        %4u\n\n",
  512.            Actors (oUndead1), Actors (oUndead3), Actors (oUndead4),
  513.            Actors (oUndead1) + Actors (oUndead3),
  514.            Actors (oUndead1) + Actors (oUndead3) + Actors (oUndead4)
  515.           );
  516.  
  517.   //
  518.   //   Print the totals for moving actors.
  519.   //
  520.   fprintf (Stream, "Moving Actor         Level 1     Level 3     Level 4     Total 3     Total 4\n");
  521.   fprintf (Stream, "================     =======     =======     =======     =======     =======\n");
  522.   fprintf (Stream, "Brown Guard             %4u        %4u        %4u        %4u        %4u\n",
  523.            Actors (omGuard1), Actors (omGuard3), Actors (omGuard4),
  524.            Actors (omGuard1) + Actors (omGuard3),
  525.            Actors (omGuard1) + Actors (omGuard3) + Actors (omGuard4)
  526.           );
  527.   fprintf (Stream, "White Officer           %4u        %4u        %4u        %4u        %4u\n",
  528.            Actors (omOfficer1), Actors (omOfficer3), Actors (omOfficer4),
  529.            Actors (omOfficer1) + Actors (omOfficer3),
  530.            Actors (omOfficer1) + Actors (omOfficer3) + Actors (omOfficer4)
  531.           );
  532.   fprintf (Stream, "Blue SS Officer         %4u        %4u        %4u        %4u        %4u\n",
  533.            Actors (omSS1), Actors (omSS3), Actors (omSS4),
  534.            Actors (omSS1) + Actors (omSS3),
  535.            Actors (omSS1) + Actors (omSS3) + Actors (omSS4)
  536.           );
  537.   fprintf (Stream, "Undead                  %4u        %4u        %4u        %4u        %4u\n",
  538.            Actors (omUndead1), Actors (omUndead3), Actors (omUndead4),
  539.            Actors (omUndead1) + Actors (omUndead3),
  540.            Actors (omUndead1) + Actors (omUndead3) + Actors (omUndead4)
  541.           );
  542.   fprintf (Stream, "Dog                     %4u        %4u        %4u        %4u        %4u\n",
  543.            Actors (oDog1), Actors (oDog3), Actors (oDog4),
  544.            Actors (oDog1) + Actors (oDog3),
  545.            Actors (oDog1) + Actors (oDog3) + Actors (oDog4)
  546.           );
  547.  
  548.   //
  549.   //   Return Ok to indicate success.
  550.   //
  551.   return errOk;
  552. }
  553.  
  554. int GameMapRec::Statistics ()
  555. {
  556.   //
  557.   //   Initialize the line counter and the pointers in the source data.
  558.   //
  559.   unsigned *MazeValue   = Maze.Data ();
  560.   unsigned *ObjectValue = Objects.Data ();
  561.   unsigned  PosY        = Header.SizeY;
  562.  
  563.   //
  564.   //   Process the maze, one line at a time.
  565.   //
  566.   while (PosY-- > 0)
  567.   {
  568.     unsigned PosX = Header.SizeX;
  569.  
  570.     //
  571.     //   Process the current maze row, one maze cell at a time.
  572.     //
  573.     while (PosX-- > 0)
  574.     {
  575.       //
  576.       //   First count the doors. They can all be found in the maze data,
  577.       //   except for the secret doors.
  578.       //
  579.       switch ( DetermineMaze (*MazeValue) )
  580.       {
  581.         case mvDoor:   DoorCount++;       break;
  582.         case mhDoor:   DoorCount++;       break;
  583.         case mlyvDoor: LockedDoorCount++; break;
  584.         case mlyhDoor: LockedDoorCount++; break;
  585.         case mlbvDoor: LockedDoorCount++; break;
  586.         case mlbhDoor: LockedDoorCount++; break;
  587.         case mevDoor:  ElevatorCount++;   break;
  588.         case mehDoor:  ElevatorCount++;   break;
  589.       }
  590.  
  591.       //
  592.       //   Now count the actors, treasures and secret doors.
  593.       //
  594.       switch ( DetermineObject (*ObjectValue) )
  595.       {
  596.         case oSecretDoor:  SecretDoorCount++; break;
  597.         case oTreasure:    TreasureCount++;   break;
  598.         case oHans:        HugeActorCount++;  break;
  599.         case oSchabbs:     HugeActorCount++;  break;
  600.         case oGhostHitler: HugeActorCount++;  break;
  601.         case oHitler:      HugeActorCount++;  break;
  602.         case oGiftmacher:  HugeActorCount++;  break;
  603.         case oGretel:      HugeActorCount++;  break;
  604.         case oFettgesicht: HugeActorCount++;  break;
  605.         default:
  606.           int Actor = DetermineObject (*ObjectValue);
  607.           if (Actor >= oFirstActor && Actor <= oLastActor)
  608.           {
  609.             ActorCount [Actor - oFirstActor]++;
  610.           }
  611.       }
  612.  
  613.       //
  614.       //   The current cell has been processed, so advance to the next one.
  615.       //   pointers.
  616.       //
  617.       MazeValue++;
  618.       ObjectValue++;
  619.     }
  620.   }
  621.  
  622.   //
  623.   //   The maze has been processed without any errors, so return Ok.
  624.   //
  625.   return errOk;
  626. }
  627.  
  628. int GameMapRec::Clear ()
  629. {
  630.   //
  631.   //   Initialize the pointers.
  632.   //
  633.   unsigned *MazePtr    = Maze.Data ();
  634.   unsigned *ObjectPtr  = Objects.Data ();
  635.   unsigned *UnknownPtr = Unknown.Data ();
  636.   unsigned  PosY       = 0;
  637.  
  638.   //
  639.   //   Walk the entire maze, one row at a time.
  640.   //
  641.   while (PosY < Header.SizeY)
  642.   {
  643.     //
  644.     //   Walk every cell in a row, one cell at a time.
  645.     //
  646.     unsigned PosX = 0;
  647.  
  648.     while (PosX < Header.SizeX)
  649.     {
  650.       //
  651.       //   Erase the object.
  652.       //
  653.       *ObjectPtr  = 0x0000;
  654.       *UnknownPtr = 0x0000;
  655.  
  656.       //
  657.       //   Set the maze to grey brick if the cell is on the border of the
  658.       //   maze. Otherwise, set the cell to be a floor.
  659.       //
  660.       if (PosX == 0 || PosX == Header.SizeX-1)
  661.       {
  662.         *MazePtr = 0x0001;
  663.       }
  664.       else
  665.       {
  666.         if (PosY == 0 || PosY == Header.SizeY-1)
  667.         {
  668.           *MazePtr = 0x0001;
  669.         }
  670.         else
  671.         {
  672.           *MazePtr = 0x006B;
  673.         }
  674.       }
  675.  
  676.       //
  677.       //   Advance to the next cell.
  678.       //
  679.       PosX++;
  680.       MazePtr++;
  681.       ObjectPtr++;
  682.       UnknownPtr++;
  683.     }
  684.  
  685.     //
  686.     //   Advance to the next row.
  687.     //
  688.     PosY++;
  689.   }
  690.  
  691.   //
  692.   //   Return Ok to indicate success.
  693.   //
  694.   return errOk;
  695. }
  696.  
  697. int GameMapRec::Create (unsigned SizeX, unsigned SizeY, char *Title)
  698. {
  699.   //
  700.   //   Check the specified sizes and calculate the memory block size.
  701.   //
  702.   int      Error   = SizeX == 0 || SizeX > 64 || SizeY == 0 || SizeY > 64 ? errIllegalMaze : errOk;
  703.   unsigned MemSize = (SizeX * SizeY) << 1;
  704.  
  705.   //
  706.   //   Allocate the three data blocks.
  707.   //
  708.   if (Error == errOk) Error = Maze.Allocate (MemSize);
  709.   if (Error == errOk) Error = Objects.Allocate (MemSize);
  710.   if (Error == errOk) Error = Unknown.Allocate (MemSize);
  711.  
  712.   //
  713.   //   If allocation and initialization is successfull, set the header to
  714.   //   reflect the map specifications. Then initialize the map.
  715.   //
  716.   if (Error == errOk)
  717.   {
  718.     strncpy (Header.Title, Title, 16);
  719.     Header.Title [15] = '\0';
  720.     Header.SizeX      = SizeX;
  721.     Header.SizeY      = SizeY;
  722.     CurrentFormat     = cDecompressed;
  723.  
  724.     Error = Clear ();
  725.   }
  726.  
  727.   //
  728.   //   Process an error and return the error state.
  729.   //
  730.   if (Error != errOk) SetError (Error);
  731.   return Error;
  732. }
  733.  
  734.