home *** CD-ROM | disk | FTP | other *** search
- /*
- Sample source code to read and write Bolo map files.
-
- Notes:
-
- The variable end_pillboxes is a pointer to the next free element in an array
- of pillbox information structures, which you should define as you need. eg.
-
- typedef struct { MAP_X x; MAP_Y y; BYTE owner; BYTE armour; BYTE speed; } PILLBOX;
- PILLBOX pillboxes[MAX_PILLS]; // MAX_PILLS is 16 at the moment
- end_pillboxes = &pillboxes[0];
-
- read_pillinfo increments end_pillboxes to the next element each time it
- reads one into the array, finishing with your array initialized for you.
-
- Likewise for refbases and start squares.
-
- The global mapknown (type WORD) indicates how far we have loaded the map so far
- -- it starts at zero and finishes when mapknown == 0xFFFF. The high byte is the
- row we are on (ie Y) and the low byte is the position within the row (ie X).
-
- You must provide a routine to return the terrain code for each map square,
- GetTypeOfTerrainAtMapSquare(x,y), and it must return the following codes:
- 0 Building 1 River 2 Swamp 3 Crater 4 Road 5 Forest 6 Rubble 7 Grass
- 8 Shot building 9 River with boat, and 10-15 are 2-7 with mines on them.
- For DEEP SEA, return the value 0xFF
-
- You must also provide a routine for the file reading routine to call:
- SetTerrainAtMapSquare(MAP_X x, MAP_Y y, BYTE t). This is called for
- each map square read from the file, for you to store the map square in
- whatever internal representation you use. The terrain codes passed in
- 't' are as listed above, except for DEEP SEA. Your routine will never be
- called with a terrain value 0xFF -- instead, any square for which your
- routine is not called is deemed to contain DEEP SEA.
-
- The easiest storage is just a 256x256 array of bytes (64K) to store the
- map, but you may choose to be smarter about memory allocation if you wish.
- */
-
- #include "BoloMapFile.h"
-
- local const BMAP_preamble bmap_preamble = { "BMAPBOLO", CURRENT_MAP_VERSION, 0, 0, 0 };
- local BMAP_file_header bmap_header;
-
- export BYTE *make_pillinfo(BYTE *number, BYTE *data)
- {
- PILLBOX *p;
- for (p=&pillbox[0], *number = 0; p<end_pillboxes; p++, (*number)++)
- {
- BMAP_pill_info *ptr = (BMAP_pill_info *)data;
- ptr->x = p->x;
- ptr->y = p->y;
- ptr->owner = p->owner;
- ptr->armour = p->armour;
- ptr->speed = p->speed;
- data += sizeofBMAP_pill_info;
- }
- return(data);
- }
-
- export void read_pillinfo(BYTE number, BYTE *data)
- {
- for (num_pillboxes=0; num_pillboxes<number; num_pillboxes++)
- {
- BMAP_pill_info *ptr = (BMAP_pill_info *)data;
- end_pillboxes->x = ptr->x;
- end_pillboxes->y = ptr->y;
- end_pillboxes->owner = ptr->owner;
- end_pillboxes->armour = ptr->armour;
- end_pillboxes->speed = ptr->speed;
- end_pillboxes++;
- data += sizeofBMAP_pill_info;
- }
- }
-
- export BYTE *make_baseinfo(BYTE *number, BYTE *data)
- {
- REFBASE *p;
- for (p=&refbase[0], *number = 0; p<end_refbases; p++, (*number)++)
- {
- BMAP_base_info *ptr = (BMAP_base_info *)data;
- ptr->x = p->x;
- ptr->y = p->y;
- ptr->owner = p->owner;
- ptr->armour = p->armour;
- ptr->shells = p->shells;
- ptr->mines = p->mines;
- data += sizeofBMAP_base_info;
- }
- return(data);
- }
-
- export void read_baseinfo(BYTE number, BYTE *data)
- {
- for (num_refbases=0; num_refbases<number; num_refbases++)
- {
- BMAP_base_info *ptr = (BMAP_base_info *)data;
- end_refbases->x = ptr->x;
- end_refbases->y = ptr->y;
- end_refbases->owner = ptr->owner;
- end_refbases->armour = ptr->armour;
- end_refbases->shells = ptr->shells;
- end_refbases->mines = ptr->mines;
- end_refbases++;
- data += sizeofBMAP_base_info;
- }
- }
-
- export BYTE *make_startinfo(BYTE *number, BYTE *data)
- {
- STARTINFO *p;
- for (p=&startinfo[0], *number = 0; p<end_starts; p++, (*number)++)
- {
- BMAP_start_info *ptr = (BMAP_start_info *)data;
- ptr->x = p->x;
- ptr->y = p->y;
- ptr->dir = p->dir;
- data += sizeofBMAP_start_info;
- }
- return(data);
- }
-
- export void read_startinfo(BYTE number, BYTE *data)
- {
- for (num_starts=0; num_starts<number; num_starts++)
- {
- BMAP_start_info *ptr = (BMAP_start_info *)data;
- end_starts->x = ptr->x;
- end_starts->y = ptr->y;
- end_starts->dir = ptr->dir;
- end_starts++;
- data += sizeofBMAP_start_info;
- }
- }
-
- local Boolean nibble_flag;
- local BYTE *nibble_data;
- #define get_nibble() (!nibble_flag ? (nibble_flag = TRUE, *nibble_data >> 4) :\
- (nibble_flag = FALSE, *nibble_data++ & 0xF))
-
- #define put_nibble(X) (!nibble_flag ? (nibble_flag = TRUE, *nibble_data = (X)<<4) :\
- (nibble_flag = FALSE, *nibble_data++ |= (X) & 0xF))
-
- local BYTE cmc(MAP_X x, MAP_Y y) // get terrain
- {
- if (x == 0xFF || y == 0xFF) return(0xFF);
- else return(GetTypeOfTerrainAtMapSquare(x,y));
- }
-
- export long make_run(BMAP_run *run, MAP_X *xp, MAP_Y *yp)
- {
- BYTE t;
- MAP_X x = *xp;
- MAP_Y y = *yp;
- nibble_flag = 0;
- nibble_data = run->data;
-
- // Search for non-DEEPSEA terrain
- while (cmc(x,y) == 0xFF) if (x<0xFF) x++; else if (y<0xFF) { x=0; y++; } else break;
-
- run->startx = x;
- if (y<0xFF) // OK, we've found some terrain
- {
- while((t = cmc(x,y)) != 0xFF)
- {
- if (t == cmc(x+1,y)) // two squares the same
- {
- BYTE code = 8; // code 8 means 2 squares the same
- x+=2; // so skip over the two squares we have found
- while (code < 15 && cmc(x,y) == t) { code++; x++; }
- put_nibble(code);
- put_nibble(t);
- }
- else
- {
- BYTE code = 0; // code 0 means 1 individual square
- MAP_X ds = x++; // record where the difference run starts
- while (code < 7 && cmc(x,y) != 0xFF && cmc(x,y) != cmc(x+1,y)) { code++; x++; }
- put_nibble(code);
- do put_nibble(cmc(ds++, y)); while (ds<x);
- }
- }
- if (nibble_flag) put_nibble(0); // round it up to whole number of bytes
- }
- *xp = run->endx = x;
- *yp = run->y = y;
- return(run->datalen = nibble_data - (BYTE*)run);
- }
-
- export OSErr read_run(BMAP_run *run)
- {
- MAP_Y y = run->y;
- MAP_X x = run->startx;
- MAP_X endx = run->endx;
- BYTE *data_end = (BYTE*)run + run->datalen;
- WORD new_known = ((WORD)y<<8) | endx;
- nibble_flag = 0;
- nibble_data = run->data;
- while (x < endx && nibble_data < data_end)
- {
- NIBBLE code = get_nibble();
- if (code < 8) do SetTerrainAtMapSquare(x++,y,get_nibble()); while (code-->0);
- else { BYTE t = get_nibble(); do SetTerrainAtMapSquare(x++,y,t); while (code-->7); }
- }
- if (nibble_flag) nibble_data++; // round up to next whole byte, for check below:
- if(x != endx || nibble_data != data_end) return(1); // ERROR!
- if (mapknown < new_known) mapknown = new_known;
- return(noErr);
- }
-
- export OSErr writemapfile(short refnum)
- {
- MAP_Y y = 0;
- MAP_X x = 0;
- BMAP_run run;
- OSErr result;
- long len;
-
- bmap_header.preamble = bmap_preamble;
- make_pillinfo (&bmap_header.preamble.num_pills, (BYTE*)bmap_header.pills);
- make_baseinfo (&bmap_header.preamble.num_bases, (BYTE*)bmap_header.bases);
- make_startinfo(&bmap_header.preamble.num_starts, (BYTE*)bmap_header.starts);
-
- len = sizeof(bmap_header.preamble);
- if (result = FSWrite(refnum, &len, &bmap_header.preamble)) return(result);
-
- len = bmap_header.preamble.num_pills * sizeofBMAP_pill_info;
- if (result = FSWrite(refnum, &len, &bmap_header.pills)) return(result);
-
- len = bmap_header.preamble.num_bases * sizeofBMAP_base_info;
- if (result = FSWrite(refnum, &len, &bmap_header.bases)) return(result);
-
- len = bmap_header.preamble.num_starts * sizeofBMAP_start_info;
- if (result = FSWrite(refnum, &len, &bmap_header.starts)) return(result);
-
- while (y<0xFF)
- {
- len = make_run(&run, &x, &y);
- if (result = FSWrite(refnum, &len, &run)) break;
- }
- return(result);
- }
-
- export OSErr readmapfile(short refnum)
- {
- int i;
- BMAP_run run;
- OSErr result;
- long len = sizeof(bmap_header.preamble);
- if (result = FSRead(refnum, &len, &bmap_header.preamble)) return(result);
-
- for (i=0; i<sizeof(bmap_preamble.id); i++)
- if (bmap_header.preamble.id[i] != bmap_preamble.id[i]) return(1);
-
- if (bmap_header.preamble.version != CURRENT_MAP_VERSION ||
- bmap_header.preamble.num_pills > MAX_PILLS ||
- bmap_header.preamble.num_bases > MAX_BASES ||
- bmap_header.preamble.num_starts > MAX_STARTS ) return(1);
-
- len = bmap_header.preamble.num_pills * sizeofBMAP_pill_info;
- if (result = FSRead(refnum, &len, bmap_header.pills)) return(result);
-
- len = bmap_header.preamble.num_bases * sizeofBMAP_base_info;
- if (result = FSRead(refnum, &len, bmap_header.bases)) return(result);
-
- len = bmap_header.preamble.num_starts * sizeofBMAP_start_info;
- if (result = FSRead(refnum, &len, bmap_header.starts)) return(result);
-
- end_pillboxes = &pillbox[0];
- end_refbases = &refbase[0];
- end_starts = &startinfo[0];
- num_pillboxes = num_refbases = num_starts = 0;
-
- read_pillinfo (bmap_header.preamble.num_pills, (BYTE *)bmap_header.pills);
- read_baseinfo (bmap_header.preamble.num_bases, (BYTE *)bmap_header.bases);
- read_startinfo(bmap_header.preamble.num_starts, (BYTE *)bmap_header.starts);
-
- while (mapknown < 0xFFFF)
- {
- len = 4;
- if (result = FSRead(refnum, &len, &run)) break;
- len = run.datalen - 4;
- if (result = FSRead(refnum, &len, run.data)) break;
- result = read_run(&run);
- if (result) break;
- }
- return(result);
- }
-