home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / Games / Bolo 0.99.6 / More information / Sample Code / Map File Format / BoloMapFile.c next >
Encoding:
C/C++ Source or Header  |  1993-09-18  |  8.9 KB  |  289 lines  |  [TEXT/ttxt]

  1. /*
  2. Sample source code to read and write Bolo map files.
  3.  
  4. Notes:
  5.  
  6. The variable end_pillboxes is a pointer to the next free element in an array
  7. of pillbox information structures, which you should define as you need. eg.
  8.  
  9. typedef struct { MAP_X x; MAP_Y y; BYTE owner; BYTE armour; BYTE speed; } PILLBOX;
  10. PILLBOX pillboxes[MAX_PILLS];        // MAX_PILLS is 16 at the moment
  11. end_pillboxes = &pillboxes[0];
  12.  
  13. read_pillinfo increments end_pillboxes to the next element each time it
  14. reads one into the array, finishing with your array initialized for you.
  15.  
  16. Likewise for refbases and start squares.
  17.  
  18. The global mapknown (type WORD) indicates how far we have loaded the map so far
  19. -- it starts at zero and finishes when mapknown == 0xFFFF. The high byte is the
  20. row we are on (ie Y) and the low byte is the position within the row (ie X).
  21.  
  22. You must provide a routine to return the terrain code for each map square,
  23. GetTypeOfTerrainAtMapSquare(x,y), and it must return the following codes:
  24. 0 Building 1 River 2 Swamp 3 Crater 4 Road 5 Forest 6 Rubble 7 Grass
  25. 8 Shot building 9 River with boat, and 10-15 are 2-7 with mines on them.
  26. For DEEP SEA, return the value 0xFF
  27.  
  28. You must also provide a routine for the file reading routine to call:
  29. SetTerrainAtMapSquare(MAP_X x, MAP_Y y, BYTE t). This is called for
  30. each map square read from the file, for you to store the map square in
  31. whatever internal representation you use. The terrain codes passed in
  32. 't' are as listed above, except for DEEP SEA. Your routine will never be
  33. called with a terrain value 0xFF -- instead, any square for which your
  34. routine is not called is deemed to contain DEEP SEA.
  35.  
  36. The easiest storage is just a 256x256 array of bytes (64K) to store the
  37. map, but you may choose to be smarter about memory allocation if you wish.
  38. */
  39.  
  40. #include "BoloMapFile.h"
  41.  
  42. local const BMAP_preamble bmap_preamble = { "BMAPBOLO", CURRENT_MAP_VERSION, 0, 0, 0 };
  43. local BMAP_file_header bmap_header;
  44.  
  45. export BYTE *make_pillinfo(BYTE *number, BYTE *data)
  46.     {
  47.     PILLBOX *p;
  48.     for (p=&pillbox[0], *number = 0; p<end_pillboxes; p++, (*number)++)
  49.         {
  50.         BMAP_pill_info *ptr = (BMAP_pill_info *)data;
  51.         ptr->x      = p->x;
  52.         ptr->y      = p->y;
  53.         ptr->owner  = p->owner;
  54.         ptr->armour = p->armour;
  55.         ptr->speed  = p->speed;
  56.         data += sizeofBMAP_pill_info;
  57.         }
  58.     return(data);
  59.     }
  60.  
  61. export void read_pillinfo(BYTE number, BYTE *data)
  62.     {
  63.     for (num_pillboxes=0; num_pillboxes<number; num_pillboxes++)
  64.         {
  65.         BMAP_pill_info *ptr = (BMAP_pill_info *)data;
  66.         end_pillboxes->x      = ptr->x;
  67.         end_pillboxes->y      = ptr->y;
  68.         end_pillboxes->owner  = ptr->owner;
  69.         end_pillboxes->armour = ptr->armour;
  70.         end_pillboxes->speed  = ptr->speed;
  71.         end_pillboxes++;
  72.         data += sizeofBMAP_pill_info;
  73.         }
  74.     }
  75.  
  76. export BYTE *make_baseinfo(BYTE *number, BYTE *data)
  77.     {
  78.     REFBASE *p;
  79.     for (p=&refbase[0], *number = 0; p<end_refbases; p++, (*number)++)
  80.         {
  81.         BMAP_base_info *ptr = (BMAP_base_info *)data;
  82.         ptr->x      = p->x;
  83.         ptr->y      = p->y;
  84.         ptr->owner  = p->owner;
  85.         ptr->armour = p->armour;
  86.         ptr->shells = p->shells;
  87.         ptr->mines  = p->mines;
  88.         data += sizeofBMAP_base_info;
  89.         }
  90.     return(data);
  91.     }
  92.  
  93. export void read_baseinfo(BYTE number, BYTE *data)
  94.     {
  95.     for (num_refbases=0; num_refbases<number; num_refbases++)
  96.         {
  97.         BMAP_base_info *ptr = (BMAP_base_info *)data;
  98.         end_refbases->x      = ptr->x;
  99.         end_refbases->y      = ptr->y;
  100.         end_refbases->owner  = ptr->owner;
  101.         end_refbases->armour = ptr->armour;
  102.         end_refbases->shells = ptr->shells;
  103.         end_refbases->mines  = ptr->mines;
  104.         end_refbases++;
  105.         data += sizeofBMAP_base_info;
  106.         }
  107.     }
  108.  
  109. export BYTE *make_startinfo(BYTE *number, BYTE *data)
  110.     {
  111.     STARTINFO *p;
  112.     for (p=&startinfo[0], *number = 0; p<end_starts; p++, (*number)++)
  113.         {
  114.         BMAP_start_info *ptr = (BMAP_start_info *)data;
  115.         ptr->x   = p->x;
  116.         ptr->y   = p->y;
  117.         ptr->dir = p->dir;
  118.         data += sizeofBMAP_start_info;
  119.         }
  120.     return(data);
  121.     }
  122.  
  123. export void read_startinfo(BYTE number, BYTE *data)
  124.     {
  125.     for (num_starts=0; num_starts<number; num_starts++)
  126.         {
  127.         BMAP_start_info *ptr = (BMAP_start_info *)data;
  128.         end_starts->x   = ptr->x;
  129.         end_starts->y   = ptr->y;
  130.         end_starts->dir = ptr->dir;
  131.         end_starts++;
  132.         data += sizeofBMAP_start_info;
  133.         }
  134.     }
  135.  
  136. local Boolean nibble_flag;
  137. local BYTE *nibble_data;
  138. #define get_nibble()  (!nibble_flag ? (nibble_flag = TRUE,  *nibble_data >> 4) :\
  139.                                       (nibble_flag = FALSE, *nibble_data++ & 0xF))
  140.  
  141. #define put_nibble(X) (!nibble_flag ? (nibble_flag = TRUE,  *nibble_data = (X)<<4) :\
  142.                                       (nibble_flag = FALSE, *nibble_data++ |= (X) & 0xF))
  143.  
  144. local BYTE cmc(MAP_X x, MAP_Y y)    // get terrain
  145.     {
  146.     if (x == 0xFF || y == 0xFF) return(0xFF);
  147.     else return(GetTypeOfTerrainAtMapSquare(x,y));
  148.     }
  149.  
  150. export long make_run(BMAP_run *run, MAP_X *xp, MAP_Y *yp)
  151.     {
  152.     BYTE t;
  153.     MAP_X x = *xp;
  154.     MAP_Y y = *yp;
  155.     nibble_flag = 0;
  156.     nibble_data = run->data;
  157.     
  158.     // Search for non-DEEPSEA terrain
  159.     while (cmc(x,y) == 0xFF) if (x<0xFF) x++; else if (y<0xFF) { x=0; y++; } else break;
  160.  
  161.     run->startx = x;
  162.     if (y<0xFF) // OK, we've found some terrain
  163.         {
  164.         while((t = cmc(x,y)) != 0xFF)
  165.             {
  166.             if (t == cmc(x+1,y))    // two squares the same
  167.                 {
  168.                 BYTE code = 8;    // code 8 means 2 squares the same
  169.                 x+=2;            // so skip over the two squares we have found
  170.                 while (code < 15 && cmc(x,y) == t) { code++; x++; }
  171.                 put_nibble(code);
  172.                 put_nibble(t);
  173.                 }
  174.             else
  175.                 {
  176.                 BYTE code = 0;    // code 0 means 1 individual square
  177.                 MAP_X ds = x++;    // record where the difference run starts
  178.                 while (code < 7 && cmc(x,y) != 0xFF && cmc(x,y) != cmc(x+1,y)) { code++; x++; }
  179.                 put_nibble(code);
  180.                 do put_nibble(cmc(ds++, y)); while (ds<x);
  181.                 }
  182.             }
  183.         if (nibble_flag) put_nibble(0);    // round it up to whole number of bytes
  184.         }
  185.     *xp = run->endx = x;
  186.     *yp = run->y    = y;
  187.     return(run->datalen = nibble_data - (BYTE*)run);
  188.     }
  189.  
  190. export OSErr read_run(BMAP_run *run)
  191.     {
  192.     MAP_Y y = run->y;
  193.     MAP_X x = run->startx;
  194.     MAP_X endx = run->endx;
  195.     BYTE *data_end = (BYTE*)run + run->datalen;
  196.     WORD new_known = ((WORD)y<<8) | endx;
  197.     nibble_flag = 0;
  198.     nibble_data = run->data;
  199.     while (x < endx && nibble_data < data_end)
  200.         {
  201.         NIBBLE code = get_nibble();
  202.         if (code < 8) do SetTerrainAtMapSquare(x++,y,get_nibble()); while (code-->0);
  203.         else { BYTE t = get_nibble(); do SetTerrainAtMapSquare(x++,y,t); while (code-->7); }
  204.         }
  205.     if (nibble_flag) nibble_data++; // round up to next whole byte, for check below:
  206.     if(x != endx || nibble_data != data_end) return(1);    // ERROR!
  207.     if (mapknown < new_known) mapknown = new_known;
  208.     return(noErr);
  209.     }
  210.  
  211. export OSErr writemapfile(short refnum)
  212.     {
  213.     MAP_Y y = 0;
  214.     MAP_X x = 0;
  215.     BMAP_run run;
  216.     OSErr result;
  217.     long len;
  218.  
  219.     bmap_header.preamble = bmap_preamble;
  220.     make_pillinfo (&bmap_header.preamble.num_pills,  (BYTE*)bmap_header.pills);
  221.     make_baseinfo (&bmap_header.preamble.num_bases,  (BYTE*)bmap_header.bases);
  222.     make_startinfo(&bmap_header.preamble.num_starts, (BYTE*)bmap_header.starts);
  223.     
  224.     len = sizeof(bmap_header.preamble);
  225.     if (result = FSWrite(refnum, &len, &bmap_header.preamble)) return(result);
  226.         
  227.     len = bmap_header.preamble.num_pills * sizeofBMAP_pill_info;
  228.     if (result = FSWrite(refnum, &len, &bmap_header.pills)) return(result);
  229.     
  230.     len = bmap_header.preamble.num_bases * sizeofBMAP_base_info;
  231.     if (result = FSWrite(refnum, &len, &bmap_header.bases)) return(result);
  232.     
  233.     len = bmap_header.preamble.num_starts * sizeofBMAP_start_info;
  234.     if (result = FSWrite(refnum, &len, &bmap_header.starts)) return(result);
  235.  
  236.     while (y<0xFF)
  237.         {
  238.         len = make_run(&run, &x, &y);
  239.         if (result = FSWrite(refnum, &len, &run)) break;
  240.         }
  241.     return(result);
  242.     }
  243.  
  244. export OSErr readmapfile(short refnum)
  245.     {
  246.     int i;
  247.     BMAP_run run;
  248.     OSErr result;
  249.     long len = sizeof(bmap_header.preamble);
  250.     if (result = FSRead(refnum, &len, &bmap_header.preamble)) return(result);
  251.  
  252.     for (i=0; i<sizeof(bmap_preamble.id); i++)
  253.         if (bmap_header.preamble.id[i] != bmap_preamble.id[i]) return(1);
  254.     
  255.     if (bmap_header.preamble.version != CURRENT_MAP_VERSION ||
  256.         bmap_header.preamble.num_pills  > MAX_PILLS ||
  257.         bmap_header.preamble.num_bases  > MAX_BASES ||
  258.         bmap_header.preamble.num_starts > MAX_STARTS ) return(1);
  259.     
  260.     len = bmap_header.preamble.num_pills * sizeofBMAP_pill_info;
  261.     if (result = FSRead(refnum, &len, bmap_header.pills)) return(result);
  262.     
  263.     len = bmap_header.preamble.num_bases * sizeofBMAP_base_info;
  264.     if (result = FSRead(refnum, &len, bmap_header.bases)) return(result);
  265.     
  266.     len = bmap_header.preamble.num_starts * sizeofBMAP_start_info;
  267.     if (result = FSRead(refnum, &len, bmap_header.starts)) return(result);
  268.     
  269.     end_pillboxes = &pillbox[0];
  270.     end_refbases  = &refbase[0];
  271.     end_starts    = &startinfo[0];
  272.     num_pillboxes = num_refbases = num_starts = 0;
  273.  
  274.     read_pillinfo (bmap_header.preamble.num_pills,  (BYTE *)bmap_header.pills);
  275.     read_baseinfo (bmap_header.preamble.num_bases,  (BYTE *)bmap_header.bases);
  276.     read_startinfo(bmap_header.preamble.num_starts, (BYTE *)bmap_header.starts);
  277.  
  278.     while (mapknown < 0xFFFF)
  279.         {
  280.         len = 4;
  281.         if (result = FSRead(refnum, &len, &run)) break;
  282.         len = run.datalen - 4;
  283.         if (result = FSRead(refnum, &len, run.data)) break;
  284.         result = read_run(&run);
  285.         if (result) break;
  286.         }
  287.     return(result);
  288.     }
  289.