Map

From Soldat Community Wiki
Revision as of 08:56, 2 May 2018 by Nosejj (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

A map is a file that Soldat uses to recognize a level (e.g., ctf_B2b.pms). These maps, with the .pms filetype extension, can be generated with PolyWorks or Map makers. In versions 1.05b and earlier, Soldat used .PMP extension.


General Components

Maps consist of polygons, scenery, colliders, WayPoints for bots, spawn-points and bonuses.


Properties

Maps also contain properties, which include weather, footstep sound, jet fuel, and background color.


Types

There are many types of maps in Soldat. In order to differentiate what gametypes a map supports, their filenames are prefixed with a 3 letter code, followed by an underscore, then the name of the map, as follows:

  • Normal maps (for Deathmatch, Pointmatch, Teammatch and Rambomatch. No prefix is used for these maps.)
  • Capture the Flag maps (Uses the prefix ctf_)
  • Infiltration maps (Uses the prefix inf_)
  • Hold the Flag maps (Uses the prefix htf_)
  • Climbing maps (Uses the prefix kz_ ctf_kz_ ctf_ and many more)
  • Race maps (Uses the prefix ctf_rce_ or ctf_)
  • Various maps (Either use the prefix var_ or none at all)
  • Dodgeball Maps (Either use the prefix DB_ or none at all)
  • Trenchwars Maps (Either tw_ or ctf_tw_ prefix)


File Structure

Here is the physical structure of the map file. The text below, saved in a file, is usable in Hex Workshop 4.23 to view the components of the map. With a small amount of work, it is possible to convert it to working C++ code or, with a little more work, to convert it to another language.


/*
Soldat PMS file format structure defenition file for Hex Workshop
by: Chrisgbk
*/

//#include "standard-types.hsl" // All the standard deftypes (shown below for clarity)

typedef          char    CHAR ;
typedef signed   __int8  BYTE ;
typedef          BYTE    byte ;
typedef unsigned __int8  UBYTE ;
typedef          UBYTE   ubyte ;
typedef unsigned __int16 WORD ;
typedef          WORD    word ;
typedef unsigned __int16 USHORT ;
typedef          USHORT  ushort ;
typedef          short   SHORT ;
typedef unsigned __int32 DWORD ;
typedef          DWORD   dword ;
typedef          long    LONG ;
typedef unsigned __int32 ULONG ;
typedef          ULONG   ulong ;
typedef signed   __int64 QUAD ;
typedef          QUAD    quad ;
typedef unsigned __int64 UQUAD ;
typedef          UQUAD   uquad ;
typedef          float   FLOAT ;
typedef          double  DOUBLE ;

#pragma maxarray(10000) // default max array size is 128(to protect from corrupt data), need this
#pragma byteorder(little_endian) // Intel

#pragma enumsize(1) // 1 byte
#pragma pack(1)
// note: since #pragma pack(4) isnt supported by hex workshop, I had to pad everything manually
// it may be wise to do it this way, even if your compiler supposrt this pragma, due to uncertanties over how a given compiler will allign the members of the data structures.

typedef enum TRUEFALSE {
	FALSE = 0,
	TRUE
} BOOL; // just... yeah

#pragma hide() // don't make these structs visible in Hex Workshop

typedef enum POLYTYPE {
	ptNORMAL = 0,
	ptONLY_BULLETS_COLLIDE,
	ptONLY_PLAYERS_COLLIDE,
	ptNO_COLLIDE,
	ptICE,
	ptDEADLY,
	ptBLOODY_DEADLY,
	ptHURTS,
	ptREGENERATES,
	ptLAVA,
	ptALPHABULLETS,
        ptALPHAPLAYERS,
	ptBRAVOBULLETS,
        ptBRAVOPLAYERS,
        ptCHARLIEBULLETS,
        ptCHARLIEPLAYERS,
        ptDELTABULLETS,
        ptDELTAPLAYERS,
        ptBOUNCY,
        ptEXPLOSIVE,
        ptHURTFLAGGERS,
        ptFLAGGERCOLLIDES,
        ptNONFLAGGERCOLLIDES,
        ptFLAGCOLLIDES
} PMS_POLYTYPE;

typedef enum DRAWBEHIND {
	dbBEHIND_ALL = 0,
	dbBEHIND_MAP,
	dbBEHIND_NONE
} PMS_DRAWBEHIND;

typedef enum SPECIALACTIONS {
	saNONE = 0,
	saSTOP_AND_CAMP,
	saWAIT_1_SECOND,
	saWAIT_5_SECONDS,
	saWAIT_10_SECONDS,
	saWAIT_15_SECONDS,
	saWAIT_20_SECONDS
} PMS_SPECIALACTIONS;

typedef enum WEATHERTYPE {
	wtNONE = 0,
	wtRAIN,
	wtSANDSTORM,
	wtSNOW
} PMS_WEATHERTYPE;

typedef enum STEPSTYPE {
	stHARD_GROUND = 0,
	stSOFT_GROUND,
	stNONE
} PMS_STEPSTYPE;

#pragma enumsize(4) // 4 byte

typedef enum SPAWNTEAM {
	stGENERAL = 0,
	stALPHA,
	stBRAVO,
	stCHARLIE,
	stDELTA,
	stALPHA_FLAG,
	stBRAVO_FLAG,
	stGRENADES,
	stMEDKITS,
	stCLUSTERS,
	stVEST,
	stFLAMER,
	stBERSERKER,
	stPREDATOR,
	stYELLOW_FLAG,
	stRAMBO_BOW,
	stSTAT_GUN
} PMS_SPAWNTEAM;

typedef struct tagPMS_VECTOR {
	FLOAT x;
	FLOAT y;
	FLOAT z;
} PMS_VECTOR;

typedef struct tagPMS_COLOR {
	UBYTE blue;
	UBYTE green;
	UBYTE red;
	UBYTE alpha;
} PMS_COLOR;

typedef struct tagPMS_HEADER {
	LONG version;
} PMS_HEADER;

typedef struct tagPMS_OPTIONS {
	UBYTE nameLen;
	CHAR name[nameLen];
	CHAR nameFiller[38-nameLen];
	UBYTE texLen;
	CHAR texture[texLen];
	CHAR textureFiller[24 - texLen];
	PMS_COLOR bgColorTop;
	PMS_COLOR bgColorBottom;
	LONG jetAmount;
	UBYTE grenades;
	UBYTE medikits;
	PMS_WEATHERTYPE weather;
	PMS_STEPSTYPE steps;
	LONG randID;
} PMS_OPTIONS;

typedef struct tagPMS_VERTEX {
	FLOAT x;
	FLOAT y;
	FLOAT z;
	FLOAT rhw;
	PMS_COLOR color;
	FLOAT tu;
	FLOAT tv;
} PMS_VERTEX;

typedef struct tagPMS_POLYGON {
	PMS_VERTEX vetex[3];
	PMS_VECTOR perpendicular[3];
	PMS_POLYTYPE polyType;
} PMS_POLYGON;

typedef struct tagPMS_SECTOR {
	WORD polyCount;
	WORD polys[polyCount];
} PMS_SECTOR;

typedef struct tagPMS_PROP {
	BOOL active;
	UBYTE filler1;
	WORD style;
	LONG width;
	LONG height;
	FLOAT x;
	FLOAT y;
	FLOAT rotation;
	FLOAT scaleX;
	FLOAT scaleY;
	UBYTE alpha;
	UBYTE filler2[3];
	PMS_COLOR color;
	PMS_DRAWBEHIND level;
	UBYTE filler3[3];
} PMS_PROP;
/*
found out that these are already defined ^_^

typedef struct tagDOSTIME {
	WORD second  : 5;  
	WORD minute : 6;    
	WORD hour    : 5;   
} DOSTIME;

typedef struct tagDOSDATE {
	WORD day  : 5;  
	WORD month : 4;    
	WORD year    : 7;   
} DOSDATE;
*/
typedef struct tagPMS_TIMESTAMP {
	DOSTIME time;
	DOSDATE date;
} PMS_TIMESTAMP;

typedef struct tagPMS_SCENERY {
	UBYTE nameLen;
	CHAR name[nameLen];
	CHAR nameFiller[50-nameLen];
	PMS_TIMESTAMP timestamp;
} PMS_SCENERY;

typedef struct tagPMS_COLLIDER {
	BOOL active;
	UBYTE filler[3];
	FLOAT x;
	FLOAT y;
	FLOAT radius;
} PMS_COLLIDER;

typedef struct tagPMS_SPAWNPOINT {
	BOOL active;
	UBYTE filler[3];
	LONG x;
	LONG y;
	PMS_SPAWNTEAM team;
} PMS_SPAWNPOINT;

typedef struct tagPMS_WAYPOINT {
	BOOL active;
	UBYTE filler1[3];
	LONG id;
	LONG x;
	LONG y;
	BOOL left;
	BOOL right;
	BOOL up;
	BOOL down;
	BOOL jet;
	UBYTE path;
	PMS_SPECIALACTIONS specialAction;
	UBYTE c2;
	UBYTE c3;
	UBYTE filler2[3];
	LONG numConnections;
	LONG connections[20];
} PMS_WAYPOINT;

#pragma show()

struct PMS_FILE {
	PMS_HEADER header;
	PMS_OPTIONS options;
	LONG polygonCount;
	PMS_POLYGON polygon[polygonCount];
	LONG sectorDivision;
	LONG numSectors;
	//PMS_SECTOR sector[(numSectors*2)+1][(numSectors*2)+1]; // unlike VB/Delphi, can't define the lower bound; only the length. -25 to 25 is the same as 0 to 50, or length of 51 ((2*25)+1)
	PMS_SECTOR sector[((numSectors*2)+1)*((numSectors*2)+1)]; // same as above, but as a single flat array. Use whatever you feel most comfortable with.
	LONG propCount;
	PMS_PROP prop[propCount];
	LONG sceneryCount;
	PMS_SCENERY scenery[sceneryCount];
	LONG colliderCount;
	PMS_COLLIDER collider[colliderCount];
	LONG spawnpointCount;
	PMS_SPAWNPOINT spawnpoint[spawnpointCount];
	LONG waypointCount;
	PMS_WAYPOINT waypoint[waypointCount];
};