Map file format  
Index: [ C ] [ Borland ] [ Map header C ] [ Map Format C ] [ Build Docs ]
(C)  1998 R.T.C.M.   An R.T.C.M. Document RTCM v11-22-99

  This is the map format for duke, Included are the
structures and variables, and some loading and saving functions.
  Information Provided by James Ferry, Author of Build Touch.



-------------------- #include <stdio.h> 
#include <dir.h> 




long mapversion,posx,posy,posz; 
int ang,cursectnum,numsectors,numwalls,numsprites; 




typedef struct 
{ 
   short wallptr, wallnum; 
   long ceilingz, floorz; 
   short ceilingstat, floorstat; 
   short ceilingpicnum, ceilingheinum; 
   signed char ceilingshade; 
   char ceilingpal, ceilingxpanning, ceilingypanning; 
   short floorpicnum, floorheinum; 
   signed char floorshade; 
   char floorpal, floorxpanning, floorypanning; 
   char visibility, filler; 
   short lotag, hitag, extra; 
} sectortype; 
sectortype sector[1024]; 




typedef struct 
{ 
   long x, y; 
   short point2, nextwall, nextsector, cstat; 
   short picnum, overpicnum; 
   signed char shade; 
   char pal, xrepeat, yrepeat, xpanning, ypanning; 
   short lotag, hitag, extra; 
} walltype; 
walltype wall[8192]; 




typedef struct 
{ 
   long x, y, z; 
//   short cstat, picnum; 
   unsigned short cstat, picnum; 
   signed char shade; 
   char pal, clipdist, filler; 
   unsigned char xrepeat, yrepeat; 
   signed char xoffset, yoffset; 
   short sectnum, statnum; 
   short ang, owner, xvel, yvel, zvel; 
   short lotag, hitag, extra; 
} spritetype; 
spritetype sprite[4096]; 
















char szItemName[80]; 
char file[80]; 
int load(void) 
{ 
	FILE *fil; 
   if ((fil=fopen(file,"rb")) == NULL) 
   { 
	if (chdir(file)) 
	{ 
		printf("Sorry, I could not open the file %c%s%c.",34,file,34); 
		return 1; 
	} 
	else return 2; 
   } 
   else 
   { 
      //Load map version number (current version is 7L) 
   fread(&mapversion,4,1,fil); 
      //Load starting position 
   fread(&posx,4,1,fil); 
   fread(&posy,4,1,fil); 
   fread(&posz,4,1,fil);          //Note: Z coordinates are all shifted up 4 
   fread(&ang,2,1,fil);           //All angles are from 0-2047, clockwise 
   fread(&cursectnum,2,1,fil);    //Sector of starting point 
      //Load all sectors (see sector structure described below) 
   fread(&numsectors,2,1,fil); 
   fread(sector,sizeof(sectortype),numsectors,fil); 
      //Load all walls (see wall structure described below) 
   fread(&numwalls,2,1,fil); 
   fread(wall,sizeof(walltype),numwalls,fil); 
      //Load all sprites (see sprite structure described below) 
   fread(&numsprites,2,1,fil); 
   fread(sprite,sizeof(spritetype),numsprites,fil); 
   fclose(fil); 
   } 
   return 0; 
} 




void save(void) 
{ 
	FILE *fil; 
   if ((fil=fopen(file,"wb")) == NULL) 
   { 
	printf("Sorry, I cannot open that file."); 
   } 
   else 
   { 








   fwrite(&mapversion,4,1,fil); 




      //Load starting position 
   fwrite(&posx,4,1,fil); 
   fwrite(&posy,4,1,fil); 
   fwrite(&posz,4,1,fil);          //Note: Z coordinates are all shifted up 4 
   fwrite(&ang,2,1,fil);           //All angles are from 0-2047, clockwise 
   fwrite(&cursectnum,2,1,fil);    //Sector of starting point 
      //Load all sectors (see sector structure described below) 
   fwrite(&numsectors,2,1,fil); 
   fwrite(sector,sizeof(sectortype),numsectors,fil); 
      //Load all walls (see wall structure described below) 
   fwrite(&numwalls,2,1,fil); 
   fwrite(wall,sizeof(walltype),numwalls,fil); 
      //Load all sprites (see sprite structure described below) 
   fwrite(&numsprites,2,1,fil); 
   fwrite(sprite,sizeof(spritetype),numsprites,fil); 
   fclose(fil); 
   } 
} 

Borland .MAP File Format
========================


The MAP file is simply a list of the segments contained in the 
compiled program together with information about the segment type 
and where it appears in the compiled code.




Here is an example of a .MAP file for a TASM prog i wrote:


 Start  Stop   Length Name               Class


 00000H 00000H 00000H _TEXT              CODE
 00000H 00356H 00357H _CODESEG           CODE
 00358H 00358H 00000H _DATA              DATA
 00360H 00EE9H 00B8AH _VARSEG            DATA
 00EF0H 108EFH 0FA00H _SCRNSEG           SCRN
 108F0H 1092FH 00040H _STACKSEG          STACK


Program entry point at 0000:02C7
Warning: No stack


First it displays headings for each column (start, stop, length, name,
and class).. then it lists all the segments in the order they appear in
the executable... the start is how far into the code (in hex) that the
segment starts at, stop is how far into the code the segment ends.. and
the length is stop - start.  Under name is just the name of the segment
that the programmer gave it when programming it.. (default segs are
_TEXT and _DATA if you just use .CODE and .DATA to start your segs) and
class is the alias that you give the seg.. for example.. if you declare
the seg like the following in your program:


_SCRNSEG	SEGMENT PUBLIC 'SCRN'
_SCRNSEG	ENDS


the name will be _SCRNSEG and the class will be SCRN.  The program entry
point is the state of CS:IP upon entry to the program (CS will be offset
however depending on where in memory the program is loaded).. after that
it lists any warnings or errors in the program.. in this case it gave a
no stack warning because i manually declared a stack seg rather than
using the conventional .STACK <SIZE> directive.


--------------------------------
Brad Kimmel
intrepid@accessv.com
Mississauga, Ontario, Canada
--------------------------------

Map Header C
============
/*

   MAP.H

   Oliver Kraus
   kraus@lrs.e-technik.uni-erlangen.de

*/


#ifndef _MAP_H
#define _MAP_H

#include <stdio.h>

struct _map_player_struct
{
   long x;
   long y;
   long z;           /* Note: Z coordinates are all shifted up 4 */
   short ang;        /* All angles are from 0-2047, clockwise */
   short secnum;     /* Sector of starting point */
};
typedef struct _map_player_struct map_player_struct;
typedef struct _map_player_struct *map_player_type;

struct _map_sector_struct
{
   short wallptr;             /* index to first wall of sector */
   short wallnum;             /* number of walls in sector */
   long ceilingz;             /* z coordinate (height) of ceiling */
   long floorz;               /* floor at first point of sector */
   /*
   bit 0: 1 = parallaxing, 0 = not                                 "P"
   bit 1: 1 = sloped, 0 = not
   bit 2: 1 = swap x&y, 0 = not                                    "F"
   bit 3: 1 = double smooshiness                                   "E"
   bit 4: 1 = x-flip                                               "F"
   bit 5: 1 = y-flip                                               "F"
   bit 6: 1 = Align texture to first wall of sector                "R"
   bits 7-15: reserved
   */
   short ceilingstat;
   short floorstat;

   short ceilingpicnum;       /* texture index into art file */
   short ceilingheinum;       /* slope value (rise/run) (0-parallel to floor, 4096-45 degrees) */

   signed char ceilingshade;  /* shade offset of ceiling/floor */
   char ceilingpal;           /* palette lookup table number (0 - use std colors) */
   char ceilingxpanning;      /* used to align textures or to do texture panning */
   char ceilingypanning;      /* used to align textures or to do texture panning */
   short floorpicnum;         /* texture index into art file */
   short floorheinum;         /* slope value (rise/run) (0-parallel to floor, 4096-45 degrees) */
   signed char floorshade;    /* shade offset of ceiling/floor */
   char floorpal;             /* palette lookup table number (0 - use std colors) */
   char floorxpanning;        /* used to align textures or to do texture panning */
   char floorypanning;        /* used to align textures or to do texture panning */
   char visibility;           /* determines how fast an area changes shade relative to distance */
   char filler;               /* useless byte to make structure aligned */
   short lotag;
   short hitag;
   short extra;
};
typedef struct _map_sector_struct map_sector_struct;
typedef struct _map_sector_struct *map_sector_type;

struct _map_wall_struct
{
   long x;            /* Coordinate of left side of wall, get right */
   long y;            /* side from next wall's left side            */
   short point2;      /* Index to next wall on the right (always in the same sector) */
   short nextwall;    /* Index to wall on other side of wall (-1 if there is no sector) */
   short nextsector;  /* Index to sector on other side of wall (-1 if there is no sector) */
   /*
      bit 0: 1 = Blocking wall (use with clipmove, getzrange)         "B"
      bit 1: 1 = bottoms of invisible walls swapped, 0 = not          "2"
      bit 2: 1 = align picture on bottom (for doors), 0 = top         "O"
      bit 3: 1 = x-flipped, 0 = normal                                "F"
      bit 4: 1 = masking wall, 0 = not                                "M"
      bit 5: 1 = 1-way wall, 0 = not                                  "1"
      bit 6: 1 = Blocking wall (use with hitscan / cliptype 1)        "H"
      bit 7: 1 = Transluscence, 0 = not                               "T"
      bit 8: 1 = y-flipped, 0 = normal                                "F"
      bit 9: 1 = Transluscence reversing, 0 = normal                  "T"
      bits 10-15: reserved
   */
   short cstat;
   short picnum;        /* texture index into art file */
   short overpicnum;    /* texture index into art file for masked walls / 1-way walls */
   signed char shade;   /* shade offset of wall */
   char pal;            /* palette lookup table number (0 - use standard colors) */
   char xrepeat;        /* used to change the size of pixels (stretch textures) */
   char yrepeat;        /* used to change the size of pixels (stretch textures) */
   char xpanning;       /* used to align textures or to do texture panning */
   char ypanning;       /* used to align textures or to do texture panning */
   short lotag;
   short hitag;
   short extra;
};
typedef struct _map_wall_struct map_wall_struct;
typedef struct _map_wall_struct *map_wall_type;

struct _map_sprite_struct
{
   long x;                 /* position of sprite - can be defined */
   long y;                 /* at center bottom or center          */
   long z;
   /*
      bit 0: 1 = Blocking sprite (use with clipmove, getzrange)       "B"
      bit 1: 1 = transluscence, 0 = normal                            "T"
      bit 2: 1 = x-flipped, 0 = normal                                "F"
      bit 3: 1 = y-flipped, 0 = normal                                "F"
      bits 5-4: 00 = FACE sprite (default)                            "R"
                01 = WALL sprite (like masked walls)
                10 = FLOOR sprite (parallel to ceilings&floors)
      bit 6: 1 = 1-sided sprite, 0 = normal                           "1"
      bit 7: 1 = Real centered centering, 0 = foot center             "C"
      bit 8: 1 = Blocking sprite (use with hitscan / cliptype 1)      "H"
      bit 9: 1 = Transluscence reversing, 0 = normal                  "T"
      bits 10-14: reserved       (ok: seems to be always zero)
      bit 15: 1 = Invisible sprite, 0 = not invisible
   */
   short cstat;
   short picnum;           /* texture index into art file */
   signed char shade;      /* shade offset of sprite */
   char pal;               /* palette lookup table number (0 - use standard colors) */
   char clipdist;          /* the size of the movement clipping square (face sprites only) */
   char filler;            /* useless byte to make structure aligned */
   unsigned char xrepeat;  /* used to change the size of pixels (stretch textures) */
   unsigned char yrepeat;
   signed char xoffset;    /* used to center the animation of sprites */
   signed char yoffset;
   short sectnum;          /* current sector of sprite */
   short statnum;          /* current status of sprite (inactive/monster/bullet, etc.) */
   short ang;              /* angle the sprite is facing */
   short owner;
   short xvel;
   short yvel;
   short zvel;
   short lotag;
   short hitag;
   short extra;
};
typedef struct _map_sprite_struct map_sprite_struct;
typedef struct _map_sprite_struct *map_sprite_type;


struct _map_struct
{
   char *fname;
   FILE *fp;
   int is_close_fp;

   long version;                 /* should be 7 */

   map_player_struct player;

   short sec_cnt;
   map_sector_struct *sec_list;

   short wall_cnt;
   map_wall_struct *wall_list;

   short sprite_cnt;
   map_sprite_struct *sprite_list;

   long min_x;
   long min_y;
   long max_x;
   long max_y;

   int legend_item_cnt;

   int  is_monster;
   int  is_card;
};
typedef struct _map_struct map_struct;
typedef struct _map_struct *map_type;

#define map_SetMonster(map) ((map)->is_monster = 1)
#define map_ClrMonster(map) ((map)->is_monster = 0)
#define map_SetCard(map) ((map)->is_card = 1)
#define map_ClrCard(map) ((map)->is_card = 0)

#define MAP_TYP_MONSTER 1
#define MAP_TYP_CARD    2
#define MAP_TYP_EXIT    3

char *map_get_item_id(int idx);
char *map_get_item_string(int idx);
int map_get_item_typ(int idx);
int map_get_item_cnt(int idx);
int map_get_info_idx(short picnum, short palette);

int is_map_file(char *name);
int map_name_compare(char *n1, char *n2);

map_type map_Open(char *fname, FILE *fp);
void map_Close(map_type map);
int map_Read(map_type map, long pos);
int map_CalculateSize(map_type map);

int map_cnt_sprites(map_type map);

#endif

Map Format C
============
/*

   MAP.C

   Oliver Kraus
   kraus@lrs.e-technik.uni-erlangen.de

*/

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "map.h"
#include "names.h"

#define MAP_NONE              0
#define MAP_ASSAULT_TROOPER   1
#define MAP_ASSAULT_CAPTAIN   2
#define MAP_PIC_COP           3
#define MAP_RECON_PATROL      4
#define MAP_OCTABRAIN         5
#define MAP_ENFORCER          6
#define MAP_SENTRY_DRONE      7
#define MAP_ASSAULT_COMMANDER 8
#define MAP_PROTOZOID_SLIMER  9
#define MAP_BATTLELORD       10
#define MAP_OVERLORD         11
#define MAP_CYCLOID_EMPEROR  12
#define MAP_TURRET           13
#define MAP_EGG              14
#define MAP_ROTATE_GUN       15        /* same as MAP_TURRET? */

#define MAP_BLUE_CARD       100
#define MAP_RED_CARD        101
#define MAP_YELLOW_CARD     102

#define MAP_EXIT            200
#define MAP_BONUS_EXIT      201

struct _map_sprite_to_item
{
   short picnum;
   short palette;
   short item;
};
typedef struct _map_sprite_to_item map_sprite_to_item;

struct _map_item_info_struct
{
   short typ;
   short item;
   long cnt;
   char *id;
   char *name;
   char *altname;
};
typedef struct _map_item_info_struct map_item_info_struct;

map_item_info_struct map_item_info[] =
{
   { 0              , MAP_NONE              , 0L, "??", "unknown"              , NULL          },
   { MAP_TYP_MONSTER, MAP_ASSAULT_CAPTAIN   , 0L, "AC", "Assault Captain"      , "Lizman"      },
   { MAP_TYP_MONSTER, MAP_ASSAULT_COMMANDER , 0L, "AM", "Assault Commander"    , NULL          },
   { MAP_TYP_MONSTER, MAP_ASSAULT_TROOPER   , 0L, "AT", "Assault Trooper"      , "Liztroop"    },
   { MAP_TYP_MONSTER, MAP_BATTLELORD        , 0L, "BL", "Battlelord"           , "Boss 1"      },
   { MAP_TYP_MONSTER, MAP_CYCLOID_EMPEROR   , 0L, "CE", "Cycloid Emperor"      , "Boss 3"      },
   { MAP_TYP_MONSTER, MAP_EGG               , 0L, "EG", "Egg"                  , NULL          },
   { MAP_TYP_MONSTER, MAP_ENFORCER          , 0L, "EN", "Enforcer"             , "Mini Boss 1" },
   { MAP_TYP_MONSTER, MAP_OCTABRAIN         , 0L, "OB", "Octabrain"            , NULL          },
   { MAP_TYP_MONSTER, MAP_OVERLORD          , 0L, "OL", "Overlord"             , "Boss 2"      },
   { MAP_TYP_MONSTER, MAP_PIC_COP           , 0L, "PC", "Pic Cop"              , NULL          },
   { MAP_TYP_MONSTER, MAP_PROTOZOID_SLIMER  , 0L, "PS", "Protozoid Slimer"     , NULL          },
   { MAP_TYP_MONSTER, MAP_ROTATE_GUN        , 0L, "RG", "Rotate Gun"           , NULL          },
   { MAP_TYP_MONSTER, MAP_RECON_PATROL      , 0L, "RP", "Recon Patrol Car"     , NULL          },
   { MAP_TYP_MONSTER, MAP_SENTRY_DRONE      , 0L, "SD", "Sentry Drone"         , NULL          },
   { MAP_TYP_MONSTER, MAP_TURRET            , 0L, "TU", "Turret"               , NULL          },

   { MAP_TYP_CARD,    MAP_BLUE_CARD         , 0L, "BC", "Blue Card"            , NULL          },
   { MAP_TYP_CARD,    MAP_RED_CARD          , 0L, "RC", "Red Card"             , NULL          },
   { MAP_TYP_CARD,    MAP_YELLOW_CARD       , 0L, "YC", "Yellow Card"          , NULL          },

   { -1             , MAP_NONE              , 0L, NULL, NULL                  }
};

char *map_get_item_id(int idx)
{
   if ( idx < 0 )
      return "";
   return map_item_info[idx].id;
}


char *map_get_item_string(int idx)
{
   if ( idx < 0 )
      return "";
   return map_item_info[idx].name;
}

int map_get_item_typ(int idx)
{
   if ( idx < 0 )
      return 0;
   return (int)map_item_info[idx].typ;
}

int map_get_item_cnt(int idx)
{
   if ( idx < 0 )
      return 0;
   return (int)map_item_info[idx].cnt;
}


map_sprite_to_item map_to_item[] =
{
   { LIZTROOP          , -1,  MAP_ASSAULT_TROOPER    },
   { LIZTROOPRUNNING   , -1,  MAP_ASSAULT_TROOPER    },
   { LIZTROOPSTAYPUT   , -1,  MAP_ASSAULT_TROOPER    },
   { LIZTOP            , -1,  MAP_ASSAULT_TROOPER    },
   { LIZTROOPSHOOT     , -1,  MAP_ASSAULT_TROOPER    },
   { LIZTROOPJETPACK   , -1,  MAP_ASSAULT_TROOPER    },
   { LIZTROOPDSPRITE   , -1,  MAP_ASSAULT_TROOPER    },
   { LIZTROOPONTOILET  , -1,  MAP_ASSAULT_TROOPER    },
   { LIZTROOPDUCKING   , -1,  MAP_ASSAULT_TROOPER    },

   { OCTABRAIN         , -1,  MAP_OCTABRAIN          },
   { OCTABRAINSTAYPUT  , -1,  MAP_OCTABRAIN          },
   { OCTATOP           , -1,  MAP_OCTABRAIN          },

   { DRONE             , -1,  MAP_SENTRY_DRONE       },

   { COMMANDER         , -1,  MAP_ASSAULT_COMMANDER  },
   { COMMANDERSTAYPUT  , -1,  MAP_ASSAULT_COMMANDER  },

   { RECON             , -1,  MAP_RECON_PATROL       },

   { PIGCOP            , -1,  MAP_PIC_COP            },
   { PIGCOPSTAYPUT     , -1,  MAP_PIC_COP            },
   { PIGCOPDIVE        , -1,  MAP_PIC_COP            },
   { PIGTOP            , -1,  MAP_PIC_COP            },

   { LIZMAN            , -1,  MAP_ASSAULT_CAPTAIN    },
   { LIZMANSTAYPUT     , -1,  MAP_ASSAULT_CAPTAIN    },
   { LIZMANSPITTING    , -1,  MAP_ASSAULT_CAPTAIN    },
   { LIZMANFEEDING     , -1,  MAP_ASSAULT_CAPTAIN    },
   { LIZMANJUMP        , -1,  MAP_ASSAULT_CAPTAIN    },

   { BOSS1             , -1,  MAP_BATTLELORD         },
   { BOSS1STAYPUT      , -1,  MAP_BATTLELORD         },
   { BOSS1SHOOT        , -1,  MAP_BATTLELORD         },
   { BOSS1LOB          , -1,  MAP_BATTLELORD         },
   { BOSSTOP           , -1,  MAP_BATTLELORD         },

   { BOSS3             , -1,  MAP_OVERLORD           },   /* strange BOSS2/BOSS3 */

   { BOSS2             , -1,  MAP_CYCLOID_EMPEROR    },

   { EGG               , -1,  MAP_EGG                },

   { ROTATEGUN         , -1,  MAP_ROTATE_GUN         },

   { ACCESSCARD        ,  0,  MAP_BLUE_CARD          },
   { ACCESSCARD        , 21,  MAP_RED_CARD           },
   { ACCESSCARD        , 23,  MAP_YELLOW_CARD        },

   { -1, -1, -1}
};

int map_get_info_idx(short picnum, short palette)
{
   int i, j;
   i = 0;
   while ( map_to_item[i].item >= 0 )
   {
      if ( map_to_item[i].picnum == picnum )
      {
         if ( map_to_item[i].palette < 0 )
            break;
         if ( map_to_item[i].palette == palette )
            break;
      }
      i++;
   }
   if ( map_to_item[i].item < 0 )
      return -1;
   j = 0;
   while ( map_item_info[j].typ >= 0  )
   {
      if ( map_item_info[j].item == map_to_item[i].item )
         break;
      j++;
   }
   if ( map_item_info[j].typ < 0  )
      return -1;
   return j;
}

int is_map_file(char *name)
{
   long lval, pos;
   short sval;
   map_player_struct pl;
   FILE *fp;

   pos = 0L;
   fp = fopen(name, "rb");
   if ( fp == NULL )
      return 0;

   if ( fread(&lval, sizeof(long), 1, fp) != 1 )
   {
      fclose(fp);
      return 0;
   }
   pos += sizeof(long);

   /* check version number */
   if ( lval < 7 )
   {
      fclose(fp);
      return 0;
   }
   if ( lval > 100 )
   {
      fclose(fp);
      return 0;
   }


   if ( fread(&pl, sizeof(map_player_struct), 1, fp) != 1 )
   {
      fclose(fp);
      return 0;
   }
   if ( pl.ang >= 2048 )
   {
      fclose(fp);
      return 0;
   }
   pos += sizeof(map_player_struct);

   if ( fread(&sval, sizeof(short), 1, fp) != 1 )
   {
      fclose(fp);
      return 0;
   }
   if ( sval < 0 )
   {
      fclose(fp);
      return 0;
   }
   pos += (long)sizeof(short);
   pos += (long)sizeof(map_sector_struct)*(long)sval;
   if ( fseek(fp, pos, SEEK_SET) != 0 )
   {
      fclose(fp);
      return 0;
   }
   if ( ftell(fp) != pos )
   {
      fclose(fp);
      return 0;
   }

   if ( fread(&sval, sizeof(short), 1, fp) != 1 )
   {
      fclose(fp);
      return 0;
   }
   if ( sval < 0 )
   {
      fclose(fp);
      return 0;
   }
   pos += (long)sizeof(short);
   pos += (long)sizeof(map_wall_struct)*(long)sval;
   if ( fseek(fp, pos, SEEK_SET) != 0 )
   {
      fclose(fp);
      return 0;
   }
   if ( ftell(fp) != pos )
   {
      fclose(fp);
      return 0;
   }

   if ( fread(&sval, sizeof(short), 1, fp) != 1 )
   {
      fclose(fp);
      return 0;
   }
   if ( sval < 0 )
   {
      fclose(fp);
      return 0;
   }
   pos += (long)sizeof(short);
   pos += (long)sizeof(map_sprite_struct)*(long)sval;
   if ( fseek(fp, pos, SEEK_SET) != 0 )
   {
      fclose(fp);
      return 0;
   }
   if ( ftell(fp) != pos )
   {
      fclose(fp);
      return 0;
   }

   if ( fgetc(fp) != EOF )
   {
      fclose(fp);
      return 0;
   }

   fclose(fp);
   return 1;
}

void map_name_cut(char *s)
{
   size_t i = 0;
   while( s[i] != '\0' )
   {
      if ( s[i] == '.' )
      {
         s[i] = '\0';
         break;
      }
      i++;
   }

}

int map_name_split(char *dest, long *val, char *src)
{
   size_t len, i;
   len = strlen(src);
   i = len;
   while( i > 0 )
   {
      i--;
      if ( !isdigit(src[i]) )
      {
         i++;
         break;
      }
   }
   strncpy(dest, src, i);
   dest[i] = '\0';
   if ( i == len )
      return 0;
   *val = atol(src+i);
   return 1;
}

int map_name_compare(char *n1, char *n2)
{
   int ret, r1, r2;
   long v1, v2;
   static char s1[14];
   static char s2[14];
   static char t1[14];
   static char t2[14];

   strncpy(t1, n1, 12);
   strncpy(t2, n2, 12);
   t1[12] = '\0';
   t2[12] = '\0';
   map_name_cut(t1);
   map_name_cut(t2);

   r1 = map_name_split(s1, &v1, t1);
   r2 = map_name_split(s2, &v2, t2);

   if ( r1 != 0 && r2 != 0 )
   {
      ret = strcmp(s1, s2);
      if ( ret == 0 )
      {
         if ( v1 < v2 )
            ret = -1;
         else if ( v1 > v2 )
            ret = 1;
      }
   }
   else
   {
      ret = strcmp(t1, t2);
   }
   return ret;
}

/*
   if 'fp' is NULL, a filepointer is generated with
   fopen and fname
*/
map_type map_Open(char *fname, FILE *fp)
{
   map_type map;
   int is_close_fp = 0;

   if ( fname == NULL )
      return NULL;

   if ( fp == NULL )
   {
      fp = fopen(fname, "rb");
      if ( fp == NULL )
         return NULL;
      is_close_fp = 1;
   }

   map = (map_type)malloc(sizeof(map_struct));
   if ( map != NULL )
   {
      map->fname = (char *)malloc(strlen(fname)+1);
      if ( map->fname != NULL )
      {
         strcpy(map->fname, fname);
         map->is_close_fp = is_close_fp;
         map->fp = fp;
         map->sec_list = NULL;
         map->wall_list = NULL;
         map->sprite_list = NULL;
         map_SetMonster(map);
         map_SetCard(map);
         return map;
      }
      free(map);
   }

   if ( is_close_fp != 0 )
      fclose(fp);
   return NULL;
}

void map_Close(map_type map)
{
   if ( map != NULL )
   {
      if ( map->sec_list != NULL )
         free(map->sec_list);
      if ( map->wall_list != NULL )
         free(map->wall_list);
      if ( map->sprite_list != NULL )
         free(map->sprite_list);
      if ( map->is_close_fp != 0 )
         fclose(map->fp);
      free(map->fname);
      free(map);
   }
}

short map_GetShort(map_type map)
{
   short x;
   if ( fread(&x, sizeof(short), 1, map->fp) != 1 )
   {
      perror("read 16 Bit");
      return -1;
   }
   return x;
}

int map_read_version(map_type map)
{
   char *task = "read version";
   if ( fread(&(map->version), sizeof(long), 1, map->fp) != 1 )
   {
      perror(task);
      return 0;
   }
   return 1;
}


int map_read_player_pos(map_type map)
{
   char *task = "read player pos";
   if ( fread(&(map->player), sizeof(map_player_struct), 1, map->fp) != 1 )
   {
      perror(task);
      return 0;
   }
   return 1;
}

int map_read_sector_list(map_type map)
{
   char *task = "read sector list";
   map->sec_cnt = map_GetShort(map);
   if ( map->sec_cnt < 0 )
      return 0;
   if ( map->sec_list != NULL )
      free(map->sec_list);
   map->sec_list = (map_sector_struct *)
      malloc(sizeof(map_sector_struct)*(size_t)map->sec_cnt);
   if ( map->sec_list == NULL )
   {
      fprintf( map->fp, "%s: out of memory\n", task);
      return 0;
   }
   if ( fread((void *)(map->sec_list),
        sizeof(map_sector_struct),
        (size_t)map->sec_cnt, map->fp) != map->sec_cnt )
   {
      perror(task);
      return 0;
   }
   return 1;
}

int map_read_wall_list(map_type map)
{
   char *task = "read wall list";
   map->wall_cnt = map_GetShort(map);
   if ( map->wall_cnt < 0 )
      return 0;
   if ( map->wall_list != NULL )
      free(map->wall_list);
   map->wall_list = (map_wall_struct *)
      malloc(sizeof(map_wall_struct)*(size_t)map->wall_cnt);
   if ( map->wall_list == NULL )
   {
      fprintf( map->fp, "%s: out of memory\n", task);
      return 0;
   }
   if ( fread((void *)(map->wall_list),
        sizeof(map_wall_struct),
        (size_t)map->wall_cnt, map->fp) != map->wall_cnt )
   {
      perror(task);
      return 0;
   }
   return 1;
}

int map_read_sprite_list(map_type map)
{
   char *task = "read sprite list";
   map->sprite_cnt = map_GetShort(map);
   if ( map->sprite_cnt < 0 )
      return 0;
   if ( map->sprite_list != NULL )
      free(map->sprite_list);
   map->sprite_list = (map_sprite_struct *)
      malloc(sizeof(map_sprite_struct)*(size_t)map->sprite_cnt);
   if ( map->sprite_list == NULL )
   {
      fprintf( map->fp, "%s: out of memory\n", task);
      return 0;
   }
   if ( fread((void *)(map->sprite_list),
        sizeof(map_sprite_struct),
        (size_t)map->sprite_cnt, map->fp) != map->sprite_cnt )
   {
      perror(task);
      return 0;
   }
   return 1;
}

int map_Read(map_type map, long pos)
{
   if ( fseek(map->fp, pos, SEEK_SET) != 0 )
   {
      perror("file seek");
      return 0;
   }
   if ( map_read_version(map) == 0 )
      return 0;
   if ( map_read_player_pos(map) == 0 )
      return 0;
   if ( map_read_sector_list(map) == 0 )
      return 0;
   if ( map_read_wall_list(map) == 0 )
      return 0;
   if ( map_read_sprite_list(map) == 0 )
      return 0;
   return 1;
}

/* calculate the size of the map, ignoring texture 0 walls */
int map_CalculateSize(map_type map)
{
   short i, j;
   short wallnum, wallidx;
   long x, y;

   map->min_x = 0x07fffffffL;
   map->min_y = 0x07fffffffL;
   map->max_x = -0x07fffffffL;
   map->max_y = -0x07fffffffL;

   for( i = 0; i < map->sec_cnt; i++ )
   {
      wallnum = map->sec_list[i].wallnum;
      wallidx = map->sec_list[i].wallptr;
      if (
            map->sec_list[i].ceilingstat != 0 ||
            map->sec_list[i].floorstat != 0 ||
            map->sec_list[i].ceilingshade != 0 ||
            map->sec_list[i].ceilingpal != 0 ||
            map->sec_list[i].ceilingxpanning != 0 ||
            map->sec_list[i].ceilingypanning != 0 ||
            map->sec_list[i].floorshade != 0 ||
            map->sec_list[i].floorpal != 0 ||
            map->sec_list[i].floorxpanning != 0 ||
            map->sec_list[i].floorypanning != 0 ||
            map->sec_list[i].visibility != 0 ||
            map->sec_list[i].filler != 0 ||
            map->sec_list[i].lotag != 0 ||
            map->sec_list[i].hitag != 0
          )
      {
         for( j = 0; j < wallnum; j++ )
         {
            x = map->wall_list[wallidx].x;
            y = map->wall_list[wallidx].y;

            /* NOTE: To ignore logos on the map, art with idx 0 is ignored */
            /* hopeing, that nobody assigns textures to his logo */
            /* well... wrong see e3l2.map of duke3d: checking more stuff */
            if ( map->wall_list[wallidx].picnum != 0 )
            {
               if ( map->min_x > x )
                  map->min_x = x;
               if ( map->min_y > y )
                  map->min_y = y;
               if ( map->max_x < x )
                  map->max_x = x;
               if ( map->max_y < y )
                  map->max_y = y;
            }
            wallidx = map->wall_list[wallidx].point2;
         }
      }
   }

   /*
   for( i = 0; i < map->wall_cnt; i++ )
   {
      if ( map->min_x > map->wall_list[i].x )
         map->min_x = map->wall_list[i].x;
      if ( map->min_y > map->wall_list[i].y )
         map->min_y = map->wall_list[i].y;
      if ( map->max_x < map->wall_list[i].x )
         map->max_x = map->wall_list[i].x;
      if ( map->max_y < map->wall_list[i].y )
         map->max_y = map->wall_list[i].y;
   }
   */
   return 1;
}

int map_cnt_sprites(map_type map)
{
   int j;
   int idx;
   map_sprite_struct *sprite;
   short i;

   j = 0;
   while ( map_item_info[j].typ >= 0  )
   {
      map_item_info[j].cnt = 0L;
      j++;
   }

   for( i = 0; i < map->sprite_cnt; i++ )
   {
      sprite = map->sprite_list+i;
      idx = map_get_info_idx(sprite->picnum, sprite->pal);
      if ( idx >= 0 )
      {
              

         if ( map_get_item_typ(idx) == MAP_TYP_MONSTER &&
              map->is_monster == 0 )
            continue;

         if ( map_get_item_typ(idx) == MAP_TYP_CARD &&
              map->is_card == 0 )
            continue;

         map_item_info[idx].cnt++;
      }
   }

   map->legend_item_cnt = 0;

   j = 0;
   while ( map_item_info[j].typ >= 0  )
   {
      if ( map_item_info[j].cnt != 0L )
         map->legend_item_cnt++;
      j++;
   }

   return map->legend_item_cnt;
}

=======================================
Extracted from Duke 3D Bitmap Generator
=======================================

-Some words from Klaus about MAP.H and MAP.C(Sorry about the structure layout-corv)

My sourcecode MAP.C and MAP.H
give a very clear overview. Look at the map_Read() function for example:

int map_Read(map_type map, long pos)
{
if ( fseek(map->fp, pos, SEEK_SET) != 0 )
{
perror("file seek");
return 0;
}
if ( map_read_version(map) == 0 )
return 0;
if ( map_read_player_pos(map) == 0 )
return 0;
if ( map_read_sector_list(map) == 0 )
return 0;
if ( map_read_wall_list(map) == 0 )
return 0;
if ( map_read_sprite_list(map) == 0 )
return 0;
return 1;
}

a complete map has 5 sections:
1. version
2. player position
3. sector list
4. wall list
5. sprite list

each of this lists are loaded into RAM and are available
as member variables of my map-structure:

this is a part of MAP.H:

long version; /* should be 7 */

map_player_struct player;

short sec_cnt;
map_sector_struct *sec_list;

short wall_cnt;
map_wall_struct *wall_list;

short sprite_cnt;
map_sprite_struct *sprite_list;

now suppose you want to count the number of DM starting points.
You need to know the PICNUM of the player (this is APLAYER)
and some infos about the lotag and hitag information...
well in this case DM startpoints are APLAYER sprits with lotag == 0:
cnt is init'ed with 1, because the normal start point is also
used as DM start.

cnt = 1;
for( i = 0; i < map->sprite_cnt; i++ )
{
sprite = map->sprite_list+i;
if ( sprite->picnum == APLAYER )
{
if ( sprite->lotag == 0 )
{
cnt++;
}
}
}

after that, cnt has the total number of starting points...

isn't it easy????

indeed doom is much more complicated... :-)

-Klaus


                            +-----------------------------------------------+
                            ¦  BUILD MAP FORMAT  from buildhlp.exe(ATOMIC)  ¦
                            +-----------------------------------------------+

Here's how you should read a BUILD map file:

{
   fil = open(???);

      //Load map version number (current version is 7L)
   read(fil,&mapversion,4);

      //Load starting position
   read(fil,posx,4);
   read(fil,posy,4);
   read(fil,posz,4);          //Note: Z coordinates are all shifted up 4
   read(fil,ang,2);           //All angles are from 0-2047, clockwise
   read(fil,cursectnum,2);    //Sector of starting point

      //Load all sectors (see sector structure described below)
   read(fil,&numsectors,2);
   read(fil,&sector[0],sizeof(sectortype)*numsectors);

      //Load all walls (see wall structure described below)
   read(fil,&numwalls,2);
   read(fil,&wall[0],sizeof(walltype)*numwalls);

      //Load all sprites (see sprite structure described below)
   read(fil,&numsprites,2);
   read(fil,&sprite[0],sizeof(spritetype)*numsprites);

   close(fil);
}

Sector Information:

   //sizeof(sectortype) = 40
typedef struct
{
   short wallptr, wallnum;
   long ceilingz, floorz;
   short ceilingstat, floorstat;
   short ceilingpicnum, ceilingheinum;
   signed char ceilingshade;
   char ceilingpal, ceilingxpanning, ceilingypanning;
   short floorpicnum, floorheinum;
   signed char floorshade;
   char floorpal, floorxpanning, floorypanning;
   char visibility, filler;
   short lotag, hitag, extra;
} sectortype;
sectortype sector[1024];

wallptr - index to first wall of sector
wallnum - number of walls in sector
z's - z coordinate (height) of ceiling / floor at first point of sector
stat's
   bit 0: 1 = parallaxing, 0 = not                                 "P"
   bit 1: 1 = sloped, 0 = not
   bit 2: 1 = swap x&y, 0 = not                                    "F"
   bit 3: 1 = double smooshiness                                   "E"
   bit 4: 1 = x-flip                                               "F"
   bit 5: 1 = y-flip                                               "F"
   bit 6: 1 = Align texture to first wall of sector                "R"
   bits 7-15: reserved
picnum's - texture index into art file
heinum's - slope value (rise/run) (0-parallel to floor, 4096-45 degrees)
shade's - shade offset of ceiling/floor
pal's - palette lookup table number (0 - use standard colors)
panning's - used to align textures or to do texture panning
visibility - determines how fast an area changes shade relative to distance
filler - useless byte to make structure aligned
lotag, hitag, extra - These variables used by the game programmer only

Wall Information:

   //sizeof(walltype) = 32
typedef struct
{
   long x, y;
   short point2, nextwall, nextsector, cstat;
   short picnum, overpicnum;
   signed char shade;
   char pal, xrepeat, yrepeat, xpanning, ypanning;
   short lotag, hitag, extra;
} walltype;
walltype wall[8192];

x, y: Coordinate of left side of wall, get right side from next wall's left side
point2: Index to next wall on the right (always in the same sector)
nextwall: Index to wall on other side of wall (-1 if there is no sector)
nextsector: Index to sector on other side of wall (-1 if there is no sector)
cstat:
   bit 0: 1 = Blocking wall (use with clipmove, getzrange)         "B"
   bit 1: 1 = bottoms of invisible walls swapped, 0 = not          "2"
   bit 2: 1 = align picture on bottom (for doors), 0 = top         "O"
   bit 3: 1 = x-flipped, 0 = normal                                "F"
   bit 4: 1 = masking wall, 0 = not                                "M"
   bit 5: 1 = 1-way wall, 0 = not                                  "1"
   bit 6: 1 = Blocking wall (use with hitscan / cliptype 1)        "H"
   bit 7: 1 = Transluscence, 0 = not                               "T"
   bit 8: 1 = y-flipped, 0 = normal                                "F"
   bit 9: 1 = Transluscence reversing, 0 = normal                  "T"
   bits 10-15: reserved
picnum - texture index into art file
overpicnum - texture index into art file for masked walls / 1-way walls
shade - shade offset of wall
pal - palette lookup table number (0 - use standard colors)
repeat's - used to change the size of pixels (stretch textures)
pannings - used to align textures or to do texture panning
lotag, hitag, extra - These variables used by the game programmer only

Sprite Information:

   //sizeof(spritetype) = 44
typedef struct
{
   long x, y, z;
   short cstat, picnum;
   signed char shade;
   char pal, clipdist, filler;
   unsigned char xrepeat, yrepeat;
   signed char xoffset, yoffset;
   short sectnum, statnum;
   short ang, owner, xvel, yvel, zvel;
   short lotag, hitag, extra;
} spritetype;
spritetype sprite[4096];
x, y, z - position of sprite - can be defined at center bottom or center
cstat:
   bit 0: 1 = Blocking sprite (use with clipmove, getzrange)       "B"
   bit 1: 1 = transluscence, 0 = normal                            "T"
   bit 2: 1 = x-flipped, 0 = normal                                "F"
   bit 3: 1 = y-flipped, 0 = normal                                "F"
   bits 5-4: 00 = FACE sprite (default)                            "R"
             01 = WALL sprite (like masked walls)
             10 = FLOOR sprite (parallel to ceilings&floors)
   bit 6: 1 = 1-sided sprite, 0 = normal                           "1"
   bit 7: 1 = Real centered centering, 0 = foot center             "C"
   bit 8: 1 = Blocking sprite (use with hitscan / cliptype 1)      "H"
   bit 9: 1 = Transluscence reversing, 0 = normal                  "T"
   bits 10-14: reserved
   bit 15: 1 = Invisible sprite, 0 = not invisible
picnum - texture index into art file
shade - shade offset of sprite
pal - palette lookup table number (0 - use standard colors)
clipdist - the size of the movement clipping square (face sprites only)
filler - useless byte to make structure aligned
repeat's - used to change the size of pixels (stretch textures)
offset's - used to center the animation of sprites
sectnum - current sector of sprite
statnum - current status of sprite (inactive/monster/bullet, etc.)

ang - angle the sprite is facing
owner, xvel, yvel, zvel, lotag, hitag, extra - These variables used by the
                                               game programmer only