#ifndef _ISPACKETS_H_
#define _ISPACKETS_H_
/////////////////////

// InSim for Live for Speed : (Version : S2 ALPHA 0.5X)

// InSim allows communication between an external program and LFS.exe.

// TCP or UDP packets can be sent in either direction, LFS reporting various
// things about its state, and the external program requesting info and
// controlling LFS with special packets, text commands or keypresses.

// NOTE : This text file was written with a TAB size equal to 4 spaces


// INSIM VERSION NUMBER (updated for this 0.5X version)
// ====================

const int INSIM_VERSION = 4;


// TYPES : (all multi-byte types are PC style - lowest byte first)
// =====

// char			1-byte character
// byte			1-byte unsigned integer
// word			2-byte unsigned integer
// short		2-byte signed integer
// unsigned		4-byte unsigned integer
// int			4-byte signed integerz
// float		4-byte float

// RaceLaps (rl) : (various meanings depending on range)

// 0       : practice
// 1-99    : number of laps...   laps  = rl
// 100-190 : 100 to 1000 laps... laps  = (rl - 100) * 10 + 100
// 191-238 : 1 to 48 hours...    hours = rl - 190


// InSim PACKETS
// =============

// All InSim packets use a four byte header

// Size : total packet size - a multiple of 4
// Type : packet identifier from the ISP_ enum (see below)
// ReqI : non zero if the packet is a packet request or a reply to a request
// Data : the first data byte


// INITIALISING InSim
// ==================

// To initialise the InSim system, type into LFS : /insim xxxxx
// where xxxxx is the TCP and UDP port you want LFS to open.

// OR start LFS with the command line option : LFS /insim=xxxxx
// This will make LFS listen for packets on that TCP and UDP port.


// TO START COMMUNICATION
// ======================

// TCP : Connect to LFS using a TCP connection, then send this packet :
// UDP : No connection required, just send this packet to LFS :

struct IS_ISI // InSim Init - packet to initialise the InSim system
{
	byte	Size;		// 44
	byte	Type;		// ISP_ISI
	byte	ReqI;		// If non-zero LFS will send an IS_VER packet
	byte	Zero;		// 0

	word	UDPPort;	// Port for UDP replies from LFS (0 to 65535)
	word	Flags;		// Bit flags for options (see below)

	byte	Sp0;		// 0
	byte	Prefix;		// Special host message prefix character
	word	Interval;	// Time in ms between NLP or MCI (0 = none)

	char	Admin[16];	// Admin password (if set in LFS)
	char	IName[16];	// A short name for your program
};

// NOTE 1) UDPPort field when you connect using UDP :

// zero     : LFS sends all packets to the port of the incoming packet
// non-zero : LFS sends all packets to the specified UDPPort

// NOTE 2) UDPPort field when you connect using TCP :

// zero     : LFS sends NLP / MCI packets using your TCP connection
// non-zero : LFS sends NLP / MCI packets to the specified UDPPort

// NOTE 3) Flags field (set the relevant bits to turn on the option) :

#define ISF_RES_0		1	// bit 0 : spare
#define ISF_RES_1		2	// bit 1 : spare
#define ISF_LOCAL		4	// bit 2 : guest or single player
#define ISF_MSO_COLS	8	// bit 3 : keep colours in MSO text
#define ISF_NLP			16	// bit 4 : receive NLP packets
#define ISF_MCI			32	// bit 5 : receive MCI packets

// In most cases you should not set both ISF_NLP and ISF_MCI flags
// because all IS_NLP information is included in the IS_MCI packet.

// The ISF_LOCAL flag is important if your program creates buttons.
// It should be set if your program is not a host control system.
// If set, then buttons are created in the local button area, so
// avoiding conflict with the host buttons and allowing the user
// to switch them with SHIFT+B rather than SHIFT+I.

// NOTE 4) Prefix field, if set when initialising InSim on a host :

// Messages typed with this prefix will be sent to your InSim program
// on the host (in IS_MSO) and not displayed on anyone's screen.


// ENUMERATIONS FOR PACKET TYPES
// =============================

enum // the second byte in all packets is one of these
{
	ISP_NONE,		//  0					: not used
	ISP_ISI,		//  1 - instruction		: insim initialise
	ISP_VER,		//  2 - info			: version info
	ISP_TINY,		//  3 - both ways		: multi purpose
	ISP_SMALL,		//  4 - both ways		: multi purpose
	ISP_STA,		//  5 - info			: state info
	ISP_SCH,		//  6 - instruction		: single character
	ISP_SFP,		//  7 - instruction		: state flags pack
	ISP_SCC,		//  8 - instruction		: set car camera
	ISP_CPP,		//  9 - both ways		: cam pos pack
	ISP_ISM,		// 10 - info			: start multiplayer
	ISP_MSO,		// 11 - info			: message out
	ISP_III,		// 12 - info			: hidden /i message
	ISP_MST,		// 13 - instruction		: type message or /command
	ISP_MTC,		// 14 - instruction		: message to a connection
	ISP_MOD,		// 15 - instruction		: set screen mode
	ISP_VTN,		// 16 - info			: vote notification
	ISP_RST,		// 17 - info			: race start
	ISP_NCN,		// 18 - info			: new connection
	ISP_CNL,		// 19 - info			: connection left
	ISP_CPR,		// 20 - info			: connection renamed
	ISP_NPL,		// 21 - info			: new player (joined race)
	ISP_PLP,		// 22 - info			: player pit (keeps slot in race)
	ISP_PLL,		// 23 - info			: player leave (spectate - loses slot)
	ISP_LAP,		// 24 - info			: lap time
	ISP_SPX,		// 25 - info			: split x time
	ISP_PIT,		// 26 - info			: pit stop start
	ISP_PSF,		// 27 - info			: pit stop finish
	ISP_PLA,		// 28 - info			: pit lane enter / leave
	ISP_CCH,		// 29 - info			: camera changed
	ISP_PEN,		// 30 - info			: penalty given or cleared
	ISP_TOC,		// 31 - info			: take over car
	ISP_FLG,		// 32 - info			: flag (yellow or blue)
	ISP_PFL,		// 33 - info			: player flags (help flags)
	ISP_FIN,		// 34 - info			: finished race
	ISP_RES,		// 35 - info			: result confirmed
	ISP_REO,		// 36 - both ways		: reorder (info or instruction)
	ISP_NLP,		// 37 - info			: node and lap packet
	ISP_MCI,		// 38 - info			: multi car info
	ISP_MSX,		// 39 - instruction		: type message
	ISP_MSL,		// 40 - instruction		: message to local computer
	ISP_CRS,		// 41 - info			: car reset
	ISP_BFN,		// 42 - both ways		: delete buttons / receive button requests
	ISP_43,			// 43
	ISP_44,			// 44
	ISP_BTN,		// 45 - instruction		: show a button on local or remote screen
	ISP_BTC,		// 46 - info			: sent when a user clicks a button
	ISP_BTT,		// 47 - info			: sent after typing into a button
};

enum // the fourth byte of IS_TINY packets is one of these
{
	TINY_NONE,		//  0					: see "maintaining the connection"
	TINY_VER,		//  1 - info request	: get version
	TINY_CLOSE,		//  2 - instruction		: close insim
	TINY_PING,		//  3 - ping request	: external progam requesting a reply
	TINY_REPLY,		//  4 - ping reply		: reply to a ping request
	TINY_VTC,		//  5 - info			: vote cancelled
	TINY_SCP,		//  6 - info request	: send camera pos
	TINY_SST,		//  7 - info request	: send state info
	TINY_GTH,		//  8 - info request	: get time in hundredths (i.e. SMALL_RTP)
	TINY_MPE,		//  9 - info			: multi player end
	TINY_ISM,		// 10 - info request	: get multiplayer info (i.e. ISP_ISM)
	TINY_REN,		// 11 - info			: race end (return to game setup screen)
	TINY_CLR,		// 12 - info			: all players cleared from race
	TINY_NCN,		// 13 - info			: get all connections
	TINY_NPL,		// 14 - info			: get all players
	TINY_RES,		// 15 - info			: get all results
	TINY_NLP,		// 16 - info request	: send an IS_NLP packet
	TINY_MCI,		// 17 - info request	: send an IS_MCI packet
	TINY_REO,		// 18 - info request	: send an IS_REO packet
	TINY_RST,		// 19 - info request	: send an IS_RST packet
};

enum // the fourth byte of IS_SMALL packets is one of these
{
	SMALL_NONE,		//  0					: not used
	SMALL_SSP,		//  1 - instruction		: start sending positions
	SMALL_SSG,		//  2 - instruction		: start sending gauges
	SMALL_VTA,		//  3 - report			: vote action
	SMALL_TMS,		//  4 - instruction		: time stop
	SMALL_STP,		//  5 - instruction		: time step
	SMALL_RTP,		//  6 - info			: race time packet (reply to GTH)
	SMALL_NLI,		//  7 - instruction		: set node lap interval
};


// GENERAL PURPOSE PACKETS - IS_TINY (4 bytes) and IS_SMALL (8 bytes)
// =======================

// To avoid defining several packet structures that are exactly the same, and to avoid
// wasting the ISP_ enumeration, IS_TINY is used at various times when no additional data
// other than SubT is required.  IS_SMALL is used when an additional integer is needed.

// IS_TINY - used for various requests, replies and reports

struct IS_TINY // General purpose 4 byte packet
{
	byte Size;		// always 4
	byte Type;		// always ISP_TINY
	byte ReqI;		// 0 unless it is an info request or a reply to an info request
	byte SubT;		// subtype, from TINY_ enumeration (e.g. TINY_RACE_END)
};

// IS_SMALL - used for various requests, replies and reports

struct IS_SMALL // General purpose 8 byte packet
{
	byte Size;		// always 8
	byte Type;		// always ISP_SMALL
	byte ReqI;		// 0 unless it is an info request or a reply to an info request
	byte SubT;		// subtype, from SMALL_ enumeration (e.g. SMALL_SSP)

	unsigned UVal;	// value (e.g. for SMALL_SSP this would be the OutSim packet rate)
};


// VERSION REQUEST
// ===============

// It is advisable to request version information as soon as you have connected, to
// avoid problems when connecting to a host with a later or earlier version.  You will
// be sent a version packet on connection if you set ReqI in the IS_ISI packet.

// This version packet can be sent on request :

struct IS_VER // VERsion
{
	byte	Size;			// 20
	byte	Type;			// ISP_VERSION
	byte	ReqI;			// ReqI as received in the request packet
	byte	Zero;

	char	Version[8];		// LFS version, e.g. 0.3G
	char	Product[6];		// Product : DEMO or S1
	word	InSimVer;		// InSim Version : increased when InSim packets change
};

// To request an InSimVersion packet at any time, send this IS_TINY :

// ReqI : non-zero		(returned in the reply)
// SubT : TINY_VER		(request an IS_VER)


// CLOSING InSim
// =============

// You can send this IS_TINY to close the InSim connection to your program :

// ReqI : 0
// SubT : TINY_CLOSE	(close this connection)

// Another InSimInit packet is then required to start operating again.

// You can shut down InSim completely and stop it listening at all by typing /insim=0
// into LFS (or send a MsgTypePack to do the same thing).


// MAINTAINING THE CONNECTION - IMPORTANT
// ==========================

// If InSim does not receive a packet for 70 seconds, it will close your connection.
// To open it again you would need to send another InSimInit packet.

// LFS will send a blank IS_TINY packet like this every 30 seconds :

// ReqI : 0
// SubT : TINY_NONE		(keep alive packet)

// You should reply with a blank IS_TINY packet :

// ReqI : 0
// SubT : TINY_NONE		(has no effect other than resetting the timeout)

// NOTE : If you want to request a reply from LFS to check the connection
// at any time, you can send this IS_TINY :

// ReqI : non-zero		(returned in the reply)
// SubT : TINY_PING		(request a TINY_REPLY)

// LFS will reply with this IS_TINY :

// ReqI : non-zero		(as received in the request packet)
// SubT : TINY_REPLY	(reply to ping)


// STATE REPORTING AND REQUESTS
// ============================

// LFS will send a StatePack any time the info in the StatePack changes.

struct IS_STA // STAte
{
	byte	Size;			// 28
	byte	Type;			// ISP_STA
	byte	ReqI;			// ReqI if replying to a request packet
	byte	Zero;

	float	ReplaySpeed;	// 4-byte float - 1.0 is normal speed

	word	Flags;			// ISS state flags (see below)
	byte	InGameCam;		// Which type of camera is selected (see below)
	byte	ViewPLID;		// Unique ID of viewed player (0 = none)

	byte	NumP;			// Number of players in race
	byte	NumConns;		// Number of connections including host
	byte	NumFinished;	// Number finished or qualified
	byte	RaceInProg;		// 0 - no race / 1 - race / 2 - qualifying

	byte	QualMins;
	byte	RaceLaps;		// see "RaceLaps" near the top of this document
	byte	Spare2;
	byte	Spare3;

	char	Track[6];		// short name for track e.g. FE2R
	byte	Weather;		// 0,1,2...
	byte	Wind;			// 0=off 1=weak 2=strong
};

// InGameCam is the in-game selected camera mode (which is
// still selected even if LFS is actually in SHIFT+U mode).
// For InGameCam's values, see "View identifiers" below.

// ISS state flags

#define ISS_GAME			1		// in game (or MPR)
#define ISS_REPLAY			2		// in SPR
#define ISS_PAUSED			4		// paused
#define ISS_SHIFTU			8		// SHIFT+U mode
#define ISS_SHIFTU_HIGH		16		// HIGH view
#define ISS_SHIFTU_FOLLOW	32		// following car
#define ISS_SHIFTU_NO_OPT	64		// SHIFT+U buttons hidden
#define ISS_SHOW_2D			128		// showing 2d display
#define ISS_FRONT_END		256		// entry screen
#define ISS_MULTI			512		// multiplayer mode
#define ISS_MPSPEEDUP		1024	// multiplayer speedup option
#define ISS_WINDOWED		2048	// LFS is running in a window
#define ISS_SOUND_MUTE		4096	// sound is switched off
#define ISS_VIEW_OVERRIDE	8192	// override user view
#define ISS_VISIBLE			16384	// InSim buttons visible

// To request a StatePack at any time, send this IS_TINY :

// ReqI : non-zero		(returned in the reply)
// SubT : TINY_SST		(Send STate)

// Setting states

// These states can be set by a special packet :

// ISS_SHIFTU_FOLLOW	- following car
// ISS_SHIFTU_NO_OPT	- SHIFT+U buttons hidden
// ISS_SHOW_2D			- showing 2d display
// ISS_MPSPEEDUP		- multiplayer speedup option
// ISS_SOUND_MUTE		- sound is switched off

struct IS_SFP // State Flags Pack
{
	byte	Size;		// 8
	byte	Type;		// ISP_SFP
	byte	ReqI;		// 0
	byte	Zero;

	word	Flag;		// the state to set
	byte	OffOn;		// 0 = off / 1 = on
	byte	Sp3;		// spare
};

// Other states must be set by using keypresses or messages (see below)


// SCREEN MODE
// ===========

// You can send this packet to LFS to set the screen mode :

struct IS_MOD // MODe : send to LFS to change screen mode
{
	byte	Size;		// 20
	byte	Type;		// ISP_MOD
	byte	ReqI;		// 0
	byte	Zero;

	int		Bits16;		// set to choose 16-bit
	int		RR;			// refresh rate - zero for default
	int		Width;		// 0 means go to window
	int		Height;		// 0 means go to window
};

// The refresh rate actually selected by LFS will be the highest available rate
// that is less than or equal to the specified refresh rate.  Refresh rate can
// be specified as zero in which case the default refresh rate will be used.

// If Width and Height are both zero, LFS will switch to windowed mode.


// TEXT MESSAGES AND KEY PRESSES
// ==============================

// You can send 64-byte text messages to LFS as if the user had typed them in.
// Messages that appear on LFS screen (up to 128 bytes) are reported to the
// external program.  You can also send simulated keypresses to LFS.

// MESSAGES OUT (FROM LFS)
// ------------

struct IS_MSO // MSg Out - system messages and user messages 
{
	byte	Size;		// 136
	byte	Type;		// ISP_MSO
	byte	ReqI;		// 0
	byte	Zero;

	byte	UCID;		// connection's unique id (0 = host)
	byte	PLID;		// player's unique id (if zero, use UCID)
	byte	UserType;	// set if typed by a user (see User Values below) 
	byte	TextStart;	// first character of the actual text (after player name)

	char	Msg[128];
};

// User Values (for UserType byte)

enum
{
	MSO_SYSTEM,			// 0 - system message
	MSO_USER,			// 1 - normal visible user message
	MSO_PREFIX,			// 2 - hidden message starting with special prefix (see ISI)
	MSO_O,				// 3 - hidden message typed on local pc with /o command
	MSO_NUM
};

// NOTE : Typing "/o MESSAGE" into LFS will send an IS_MSO with UserType = MSO_O

struct IS_III // InsIm Info - /i message from user to host's InSim
{
	byte	Size;		// 72
	byte	Type;		// ISP_III
	byte	ReqI;		// 0
	byte	Zero;

	byte	UCID;		// connection's unique id (0 = host)
	byte	PLID;		// player's unique id (if zero, use UCID)
	byte	Sp2;
	byte	Sp3;

	char	Msg[64];
};

// MESSAGES IN (TO LFS)
// -----------

struct IS_MST // MSg Type - send to LFS to type message or command
{
	byte	Size;		// 68
	byte	Type;		// ISP_MST
	byte	ReqI;		// 0
	byte	Zero;

	char	Msg[64];	// last byte must be zero
};

struct IS_MSX // MSg eXtended - like MST but longer (not for commands)
{
	byte	Size;		// 100
	byte	Type;		// ISP_MSX
	byte	ReqI;		// 0
	byte	Zero;

	char	Msg[96];	// last byte must be zero
};

struct IS_MSL // MSg Local - message to appear on local computer only
{
	byte	Size;		// 132
	byte	Type;		// ISP_MSL
	byte	ReqI;		// 0
	byte	Sound;		// sound effect (see Message Sounds below)

	char	Msg[128];	// last byte must be zero
};

struct IS_MTC // Msg To Connection - hosts only - send to a connection or a player
{
	byte	Size;		// 72
	byte	Type;		// ISP_MTC
	byte	ReqI;		// 0
	byte	Zero;

	byte	UCID;		// connection's unique id (0 = host)
	byte	PLID;		// player's unique id (if zero, use UCID)
	byte	Sp2;
	byte	Sp3;

	char	Msg[64];	// last byte must be zero
};

struct IS_SCH // Single CHaracter - send to simulate single character
{
	byte	Size;		// 8
	byte	Type;		// ISP_SCH
	byte	ReqI;		// 0
	byte	Zero;

	byte	CharB;		// key to press
	byte	Flags;		// bit 0 : SHIFT / bit 1 : CTRL
	byte	Spare2;
	byte	Spare3;
};

// Message Sounds (for Sound byte)

enum
{
	SND_SILENT,
	SND_MESSAGE,
	SND_SYSMESSAGE,
	SND_INVALIDKEY,
	SND_ERROR,
	SND_NUM
};


// MULTIPLAYER NOTIFICATION
// ========================

// LFS will send this packet when a host is started or joined :

struct IS_ISM // InSim Multi
{
	byte	Size;		// 40
	byte	Type;		// ISP_ISM
	byte	ReqI;		// usually 0 / or if a reply : ReqI as received in the TINY_ISM
	byte	Zero;

	byte	Host;		// 0 = guest / 1 = host
	byte	Sp1;
	byte	Sp2;
	byte	Sp3;

	char	HName[32];	// the name of the host joined or started
};

// On ending or leaving a host, LFS will send this IS_TINY :

// ReqI : 0
// SubT : TINY_MPE		(MultiPlayerEnd)

// To request an IS_ISM packet at any time, send this IS_TINY :

// ReqI : non-zero		(returned in the reply)
// SubT : TINY_ISM		(request an IS_ISM)

// NOTE : If LFS is not in multiplayer mode, the host name in the ISM will be empty.


// VOTE NOTIFY AND CANCEL
// ======================

// LFS notifies the external program of any votes to restart or qualify

// The Vote Actions are defined as :

enum
{
	VOTE_NONE,			// 0 - no vote
	VOTE_END,			// 1 - end race
	VOTE_RESTART,		// 2 - restart
	VOTE_QUALIFY,		// 3 - qualify
	VOTE_NUM
};

struct IS_VTN // VoTe Notify
{
	byte	Size;		// 8
	byte	Type;		// ISP_VTN
	byte	ReqI;		// 0
	byte	Zero;

	byte	UCID;		// connection's unique id
	byte	Action;		// VOTE_X (Vote Action as defined above)
	byte	Spare2;
	byte	Spare3;
};

// When a vote is cancelled, LFS sends this IS_TINY

// ReqI : 0
// SubT : TINY_VTC		(VoTe Cancelled)

// When a vote is completed, LFS sends this IS_SMALL

// ReqI : 0
// SubT : SMALL_VTA  	(VoTe Action)
// UVal : action 		(VOTE_X - Vote Action as defined above)

// You can instruct LFS host to cancel a vote using an IS_TINY

// ReqI : 0
// SubT : TINY_VTC		(VoTe Cancel)


// RACE TRACKING
// =============

// In LFS there is a list of connections AND a list of players in the race
// Some packets are related to connections, some players, some both

// If you are making a multiplayer InSim program, you must maintain two lists
// You should use the unique identifier UCID to identify a connection

// Each player has a unique identifier PLID from the moment he joins the race, until he
// leaves.  It's not possible for PLID and UCID to be the same thing, for two reasons :

// 1) there may be more than one player per connection if AI drivers are used
// 2) a player can swap between connections, in the case of a driver swap (IS_TOC)

// When all players are cleared from race (e.g. /clear) LFS sends this IS_TINY

// ReqI : 0
// SubT : TINY_CLR		(CLear Race)

// When a race ends (return to game setup screen) LFS sends this IS_TINY

// ReqI : 0
// SubT : TINY_REN  	(Race ENd)

// You can instruct LFS host to cancel a vote using an IS_TINY

// ReqI : 0
// SubT : TINY_VTC		(VoTe Cancel)


struct IS_RST // Race STart
{
	byte	Size;		// 28
	byte	Type;		// ISP_RST
	byte	ReqI;		// 0 unless this is a reply to an TINY_RST request
	byte	Zero;

	byte	RaceLaps;	// 0 if qualifying
	byte	QualMins;	// 0 if race
	byte	NumP;		// number of players in race
	byte	Spare;

	char	Track[6];	// short track name
	byte	Weather;
	byte	Wind;

	word	Flags;		// race flags (must pit, can reset, etc - see below)
	word	NumNodes;	// total number of nodes in the path
	word	Finish;		// node index - finish line
	word	Split1;		// node index - split 1
	word	Split2;		// node index - split 2
	word	Split3;		// node index - split 3
};

// To request an IS_RST packet at any time, send this IS_TINY :

// ReqI : non-zero		(returned in the reply)
// SubT : TINY_RST		(request an IS_RST)

struct IS_NCN // New ConN
{
	byte	Size;		// 56
	byte	Type;		// ISP_NCN
	byte	ReqI;		// 0 unless this is a reply to a TINY_NCN request
	byte	UCID;		// new connection's unique id (0 = host)

	char	UName[24];	// username
	char	PName[24];	// nickname

	byte	Admin;		// 1 if admin
	byte	Total;		// number of connections including host
	byte	Flags;		// bit 2 : remote
	byte	Sp3;
};

struct IS_CNL // ConN Leave
{
	byte	Size;		// 8
	byte	Type;		// ISP_CNL
	byte	ReqI;		// 0
	byte	UCID;		// unique id of the connection which left

	byte	Reason;		// leave reason (see below)
	byte	Total;		// number of connections including host
	byte	Sp2;
	byte	Sp3;
};

struct IS_CPR // Conn Player Rename
{
	byte	Size;		// 36
	byte	Type;		// ISP_CPR
	byte	ReqI;		// 0
	byte	UCID;		// unique id of the connection

	char	PName[24];	// new name
	char	Plate[8];	// number plate - NO ZERO AT END!
};

struct IS_NPL // New PLayer joining race (if PLID already exists, then leaving pits)
{
	byte	Size;		// 76
	byte	Type;		// ISP_NPL
	byte	ReqI;		// 0 unless this is a reply to an TINY_NPL request
	byte	PLID;		// player's newly assigned unique id

	byte	UCID;		// connection's unique id
	byte	PType;		// bit 0 : female / bit 1 : AI / bit 2 : remote
	word	Flags;		// player flags

	char	PName[24];	// nickname
	char	Plate[8];	// number plate - NO ZERO AT END!

	char	CName[4];	// car name
	char	SName[16];	// skin name - MAX_CAR_TEX_NAME
	byte	Tyres[4];	// compounds

	byte	H_Mass;		// added mass (kg)
	byte	H_TRes;		// intake restriction
	byte	SpB;
	byte	Pass;		// passengers byte

	int		Spare;

	byte	Sp0;
	byte	NumP;		// number in race (same when leaving pits, 1 more if new)
	byte	Sp2;
	byte	Sp3;
};

struct IS_PLP // PLayer Pits (go to settings - stays in player list)
{
	byte	Size;		// 4
	byte	Type;		// ISP_PLP
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id
};

struct IS_PLL // PLayer Leave race (spectate - removed from player list)
{
	byte	Size;		// 4
	byte	Type;		// ISP_PLL
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id
};

struct IS_CRS // Car ReSet
{
	byte	Size;		// 4
	byte	Type;		// ISP_CRS
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id
};

struct IS_LAP // LAP time
{
	byte	Size;		// 20
	byte	Type;		// ISP_LAP
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id

	unsigned	LTime;	// lap time (ms)
	unsigned	ETime;	// total time (ms)

	word	LapsDone;	// laps completed
	word	Flags;		// player flags

	byte	Sp0;
	byte	Penalty;	// current penalty value (see below)
	byte	NumStops;	// number of pit stops
	byte	Sp3;
};

struct IS_SPX // SPlit X time
{
	byte	Size;		// 16
	byte	Type;		// ISP_SPX
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id

	unsigned	STime;	// split time (ms)
	unsigned	ETime;	// total time (ms)

	byte	Split;		// split number 1, 2, 3
	byte	Penalty;	// current penalty value (see below)
	byte	NumStops;	// number of pit stops
	byte	Sp3;
};

struct IS_PIT // PIT stop (stop at pit garage)
{
	byte	Size;		// 24
	byte	Type;		// ISP_PIT
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id

	word	LapsDone;	// laps completed
	word	Flags;		// player flags

	byte	Sp0;
	byte	Penalty;	// current penalty value (see below)
	byte	NumStops;	// number of pit stops
	byte	Sp3;

	byte	Tyres[4];	// tyres changed

	unsigned	Work;	// pit work
	unsigned	Spare;
};

struct IS_PSF // Pit Stop Finished
{
	byte	Size;		// 12
	byte	Type;		// ISP_PSF
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id

	unsigned	STime;	// stop time (ms)
	unsigned	Spare;
};

struct IS_PLA // Pit LAne
{
	byte	Size;		// 8
	byte	Type;		// ISP_PLA
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id

	byte	Fact;		// pit lane fact (see below)
	byte	Sp1;
	byte	Sp2;
	byte	Sp3;
};

// IS_CCH : Camera CHange

// To track cameras you need to consider 3 points

// 1) The default camera : VIEW_DRIVER
// 2) Player flags : CUSTOM_VIEW means VIEW_CUSTOM at start or pit exit
// 3) IS_CCH : sent when an existing driver changes camera

struct IS_CCH // Camera CHange
{
	byte	Size;		// 8
	byte	Type;		// ISP_CCH
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id

	byte	Camera;		// view identifier (see below)
	byte	Sp1;
	byte	Sp2;
	byte	Sp3;
};

struct IS_PEN // PENalty (given or cleared)
{
	byte	Size;		// 8
	byte	Type;		// ISP_PEN
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id

	byte	OldPen;		// old penalty value (see below)
	byte	NewPen;		// new penalty value (see below)
	byte	Reason;		// penalty reason (see below)
	byte	Sp3;
};

struct IS_TOC // Take Over Car
{
	byte	Size;		// 8
	byte	Type;		// ISP_TOC
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id

	byte	OldUCID;	// old connection's unique id
	byte	NewUCID;	// new connection's unique id
	byte	Sp2;
	byte	Sp3;
};

struct IS_FLG // FLaG (yellow or blue flag changed)
{
	byte	Size;		// 8
	byte	Type;		// ISP_FLG
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id

	byte	OffOn;		// 0 = off / 1 = on
	byte	Flag;		// 1 = given blue / 2 = causing yellow
	byte	CarBehind;	// unique id of obstructed player
	byte	Sp3;
};

struct IS_PFL // Player FLags (help flags changed)
{
	byte	Size;		// 8
	byte	Type;		// ISP_PFL
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id

	word	Flags;		// player flags (see below)
	word	Spare;
};

struct IS_FIN // FINished race notification (not a final result - use IS_RES)
{
	byte	Size;		// 20
	byte	Type;		// ISP_FIN
	byte	ReqI;		// 0
	byte	PLID;		// player's unique id (0 = player left before result was sent)

	unsigned	TTime;	// race time (ms)
	unsigned	BTime;	// best lap (ms)

	byte	SpA;
	byte	NumStops;	// number of pit stops
	byte	Confirm;	// confirmation flags : disqualified etc - see below
	byte	SpB;

	word	LapsDone;	// laps completed
	word	Flags;		// player flags : help settings etc - see below
};

struct IS_RES // RESult (qualify or confirmed finish)
{
	byte	Size;		// 84
	byte	Type;		// ISP_RES
	byte	ReqI;		// 0 unless this is a reply to a TINY_RES request
	byte	PLID;		// player's unique id (0 = player left before result was sent)

	char	UName[24];	// username
	char	PName[24];	// nickname
	char	Plate[8];	// number plate - NO ZERO AT END!
	char	CName[4];	// skin prefix

	unsigned	TTime;	// race time (ms)
	unsigned	BTime;	// best lap (ms)

	byte	SpA;
	byte	NumStops;	// number of pit stops
	byte	Confirm;	// confirmation flags : disqualified etc - see below
	byte	SpB;

	word	LapsDone;	// laps completed
	word	Flags;		// player flags : help settings etc - see below

	byte	ResultNum;	// finish or qualify pos (0 = win / 255 = not added to table)
	byte	NumRes;		// total number of results (qualify doesn't always add a new one)
	word	PSeconds;	// penalty time in seconds (already included in race time)
};

// IS_REO : REOrder - this packet can be sent in either direction

// LFS sends one at the start of every race or qualifying session, listing the start order

// You can send one to LFS before a race start, to specify the starting order.
// It may be a good idea to avoid conflict by using /start=fixed (LFS setting).
// Alternatively, you can leave the LFS setting, but make sure you send your IS_REO
// AFTER you receive the IS_VTA.  LFS does its default grid reordering at the same time
// as it sends the IS_VTA (VoTe Action) and you can override this by sending an IS_REO.

struct IS_REO // REOrder (when race restarts after qualifying)
{
	byte	Size;		// 36
	byte	Type;		// ISP_REO
	byte	ReqI;		// 0 unless this is a reply to an TINY_REO request
	byte	NumP;		// number of players in race

	byte	PLID[32];	// all PLIDs in new order
};

// To request an IS_REO packet at any time, send this IS_TINY :

// ReqI : non-zero		(returned in the reply)
// SubT : TINY_REO		(request an IS_REO)

// Pit Lane Facts

enum
{
	PITLANE_EXIT,		// 0 - left pit lane
	PITLANE_ENTER,		// 1 - entered pit lane
	PITLANE_NO_PURPOSE,	// 2 - entered for no purpose
	PITLANE_DT,			// 3 - entered for drive-through
	PITLANE_SG,			// 4 - entered for stop-go
	PITLANE_NUM
};

// Pit Work Flags

enum
{
	PSE_NOTHING,		// bit 0 (1)
	PSE_STOP,			// bit 1 (2)
	PSE_FR_DAM,			// bit 2 (4)
	PSE_FR_WHL,			// etc...
	PSE_LE_FR_DAM,
	PSE_LE_FR_WHL,
	PSE_RI_FR_DAM,
	PSE_RI_FR_WHL,
	PSE_RE_DAM,
	PSE_RE_WHL,
	PSE_LE_RE_DAM,
	PSE_LE_RE_WHL,
	PSE_RI_RE_DAM,
	PSE_RI_RE_WHL,
	PSE_BODY_MINOR,
	PSE_BODY_MAJOR,
	PSE_SETUP,
	PSE_REFUEL,
};

// View identifiers

enum
{
	VIEW_FOLLOW,	// 0 - arcade
	VIEW_HELI,		// 1 - helicopter
	VIEW_CAM,		// 2 - tv camera
	VIEW_DRIVER,	// 3 - cockpit
	VIEW_CUSTOM,	// 4 - custom
	VIEW_MAX
};

const int VIEW_ANOTHER = 255; // viewing another car

// Leave reasons

enum
{
	LEAVR_DISCO,		// 0 - disconnect
	LEAVR_TIMEOUT,		// 1 - timed out
	LEAVR_LOSTCONN,		// 2 - lost connection
	LEAVR_KICKED,		// 3 - kicked
	LEAVR_BANNED,		// 4 - banned
	LEAVR_SECURITY,		// 5 - OOS or cheat protection
	LEAVR_NUM
};

// Penalty values (VALID means the penalty can now be cleared)

enum
{
	PENALTY_NONE,		// 0		
	PENALTY_DT,			// 1
	PENALTY_DT_VALID,	// 2
	PENALTY_SG,			// 3
	PENALTY_SG_VALID,	// 4
	PENALTY_30,			// 5
	PENALTY_45,			// 6
	PENALTY_NUM
};

// Penalty reasons

enum
{
	PENR_UNKNOWN,		// 0 - unknown or cleared penalty
	PENR_ADMIN,			// 1 - penalty given by admin
	PENR_WRONG_WAY,		// 2 - wrong way driving
	PENR_FALSE_START,	// 3 - starting before green light
	PENR_SPEEDING,		// 4 - speeding in pit lane
	PENR_STOP_SHORT,	// 5 - stop-go pit stop too short
	PENR_STOP_LATE,		// 6 - compulsory stop is too late
	PENR_NUM
};

// Player flags

#define PIF_SWAPSIDE		1
#define PIF_GC_CUT			2
#define PIF_GC_BLIP			4
#define PIF_AUTOGEARS		8
#define PIF_SHIFTER			16
#define PIF_RESERVED		32
#define PIF_HELP_B			64
#define PIF_AXIS_CLUTCH		128
#define PIF_INPITS			256
#define PIF_AUTOCLUTCH		512
#define PIF_MOUSE			1024
#define PIF_KB_NO_HELP		2048
#define PIF_KB_STABILISED	4096
#define PIF_CUSTOM_VIEW		8192

// Tyre compounds (4 byte order : rear L, rear R, front L, front R)

enum
{
	TYRE_R1,			// 0
	TYRE_R2,			// 1
	TYRE_R3,			// 2
	TYRE_R4,			// 3
	TYRE_ROAD_SUPER,	// 4
	TYRE_ROAD_NORMAL,	// 5
	TYRE_HYBRID,		// 6
	TYRE_KNOBBLY,		// 7
	TYRE_NUM
};

const int NOT_CHANGED = 255;

// Confirmation flags

#define CONF_MENTIONED		1
#define CONF_CONFIRMED		2
#define CONF_PENALTY_DT		4
#define CONF_PENALTY_SG		8
#define CONF_PENALTY_30		16
#define CONF_PENALTY_45		32
#define CONF_DID_NOT_PIT	64

#define CONF_DISQ	(CONF_PENALTY_DT | CONF_PENALTY_SG | CONF_DID_NOT_PIT)
#define CONF_TIME	(CONF_PENALTY_30 | CONF_PENALTY_45)

// Race flags

// HOSTF_CAN_VOTE		1
// HOSTF_CAN_SELECT		2
// HOSTF_MID_RACE		32
// HOSTF_MUST_PIT		64
// HOSTF_CAN_RESET		128

// Passengers byte

// bit 0 female
// bit 1 front
// bit 2 female
// bit 3 rear left
// bit 4 female
// bit 5 rear middle
// bit 6 female
// bit 7 rear right


// TRACKING PACKET REQUESTS
// ========================

// To request players, connections, results or a single NLP or MCI, send an IS_TINY

// In each case, ReqI must be non-zero, and will be returned in the reply packet

// SubT : TINT_NCN - request all connections
// SubT : TINY_NPL - request all players
// SubT : TINY_RES - request all results
// SubT : TINY_NLP - request a single IS_NLP
// SubT : TINY_MCI - request a set of IS_MCI


// CAR TRACKING PACKETS - car position info sent at constant intervals
// ====================

// IS_NLP - compact, all cars in 1 variable sized packet
// IS_MCI - detailed, max 8 cars per variable sized packet

// To receive IS_NLP or IS_MCI packets at a specified interval :

// 1) Set the Interval field in the IS_ISI (InSimInit) packet
// 2) Set one of the flags ISF_NLP or ISF_MCI in the IS_ISI packet

// If ISF_NLP flag is set, one IS_NLP packet is sent...

struct NodeLap // Car info in 6 bytes - there is an array of these in the NLP (below)
{
	word	Node;		// current path node
	word	Lap;		// current lap
	byte	PLID;		// player's unique id
	byte	Position;	// current race position : 0 = unknown, 1 = leader, etc...
};

struct IS_NLP // Node and Lap Packet - variable size
{
	byte	Size;		// 4 + NumP * 6 (PLUS 2 if needed to make it a multiple of 4)
	byte	Type;		// ISP_NLP
	byte	ReqI;		// 0 unless this is a reply to an TINY_NLP request
	byte	NumP;		// number of players in race

	NodeLap	Info[32];	// node and lap of each player, 1 to 32 of these (NumP)
};

// If ISF_MCI flag is set, a set of IS_MCI packets is sent...

struct CompCar // Car info in 28 bytes - there is an array of these in the MCI (below)
{
	word	Node;		// current path node
	word	Lap;		// current lap
	byte	PLID;		// player's unique id
	byte	Position;	// current race position : 0 = unknown, 1 = leader, etc...
	byte	Info;		// flags and other info - see below
	byte	Sp3;
	int		X;			// X map (65536 = 1 metre)
	int		Y;			// Y map (65536 = 1 metre)
	int		Z;			// Z alt (65536 = 1 metre)
	word	Speed;		// speed (32768 = 100 m/s)
	word	Direction;	// direction of car's motion : 0 = world y direction, 32768 = 180 deg
	word	Heading;	// direction of forward axis : 0 = world y direction, 32768 = 180 deg
	short	AngVel;		// signed, rate of change of heading : (16384 = 360 deg/s)
};

// NOTE 1) Info byte - the bits in this byte have the following meanings :

#define CCI_BLUE		1		// this car is in the way of a driver who is a lap ahead
#define CCI_YELLOW		2		// this car is slow or stopped and in a dangerous place
#define CCI_FIRST		64		// this is the first compcar in this set of MCI packets
#define CCI_LAST		128		// this is the last compcar in this set of MCI packets

// NOTE 2) Heading : 0 = world y axis direction, 32768 = 180 degrees, anticlockwise from above
// NOTE 3) AngVel  : 0 = no change in heading,    8192 = 180 degrees per second anticlockwise

struct IS_MCI // Multi Car Info - if more than 8 in race then more than one of these is sent
{
	byte	Size;		// 4 + NumP * 28
	byte	Type;		// ISP_MCI
	byte	ReqI;		// 0 unless this is a reply to an TINY_MCI request
	byte	NumC;		// number of valid CompCar structs in this packet

	CompCar	Info[8];	// car info for each player, 1 to 8 of these (NumC)
};

// You can change the rate of NLP or MCI after initialisation by sending this IS_SMALL :

// ReqI : 0
// SubT : SMALL_NLI		(Node Lap Interval)
// UVal : interval      (0 means stop, otherwise interval in ms, 100 to 8000)


// CAR POSITION PACKETS (Initialising OutSim from InSim - See "OutSim" below)
// ====================

// To request Car Positions from the currently viewed car, send this IS_SMALL :

// ReqI : 0
// SubT : SMALL_SSP		(Start Sending Positions)
// UVal : interval		(time between updates - zero means stop sending)

// The SSP packet makes LFS start sending UDP packets if in game, using the OutSim
// system as documented near the end of this text file.

// You do not need to set any OutSim values in LFS cfg.txt as OutSim is automatically
// initialised by the SSP packet.

// The OutSim packets will be sent to the UDP port specified in the InSimInit packet.

// NOTE : OutSim packets are not InSim packets and don't have a 4-byte header.


// DASHBOARD PACKETS (Initialising OutGauge from InSim - See "OutGauge" below)
// =================

// To request Dashboard Packets from the currently viewed car, send this IS_SMALL :

// ReqI : 0
// SubT : SMALL_SSG		(Start Sending Gauges)
// UVal : interval		(time between updates - zero means stop sending)

// The SSG packet makes LFS start sending UDP packets if in game, using the OutGauge
// system as documented near the end of this text file.

// You do not need to set any OutGauge values in LFS cfg.txt as OutSim is automatically
// initialised by the SSG packet.

// The OutGauge packets will be sent to the UDP port specified in the InSimInit packet.

// NOTE : OutGauge packets are not InSim packets and don't have a 4-byte header.


// CAMERA CONTROL
// ==============

// IN GAME camera control
// ----------------------

// You can set the viewed car and selected camera directly with a special packet
// These are the states normally set in-game by using the TAB and V keys

struct IS_SCC // Set Car Camera - Simplified camera packet (not SHIFT+U mode)
{
	byte	Size;		// 8
	byte	Type;		// ISP_SCC
	byte	ReqI;		// 0
	byte	Zero;

	byte	ViewPLID;	// UniqueID of player to view
	byte	InGameCam;	// InGameCam (as reported in StatePack)
	byte	Sp2;
	byte	Sp3;
};

// NOTE : Set InGameCam or ViewPLID to 255 to leave that option unchanged.

// DIRECT camera control
// ---------------------

// A Camera Position Packet can be used for LFS to report a camera position and state.
// An InSim program can also send one to set LFS camera position in game or SHIFT+U mode.

// Type : "Vec" : 3 ints (X, Y, Z) - 65536 means 1 metre

struct IS_CPP // Cam Pos Pack - Full camera packet (in car OR SHIFT+U mode)
{
	byte	Size;		// 32
	byte	Type;		// ISP_CPP
	byte	ReqI;		// instruction : 0 / or reply : ReqI as received in the TINY_SCP
	byte	Zero;

	Vec		Pos;		// Position vector

	word	Heading;	// 0 points along Y axis
	word	Pitch;		// 0 means looking at horizon

	word	Roll;		// 0 means no roll
	byte	ViewPLID;	// Unique ID of viewed player (0 = none)
	byte	InGameCam;	// InGameCam (as reported in StatePack)

	float	FOV;		// 4-byte float : FOV in radians

	word	Time;		// Time to get there (0 means instant + reset)
	word	Flags;		// ISS state flags (see below)
};

// The ISS state flags that can be set are :

// ISS_SHIFTU			- in SHIFT+U mode
// ISS_SHIFTU_HIGH		- HIGH view
// ISS_SHIFTU_FOLLOW	- following car
// ISS_VIEW_OVERRIDE	- override user view

// On receiving this packet, LFS will set up the camera to match the values in the packet,
// including switching into or out of SHIFT+U mode depending on the ISS_SHIFTU flag.

// If ISS_SHIFTU is not set, then ViewPLID and InGameCam will be used.

// If ISS_VIEW_OVERRIDE is set, the in-car view Heading Pitch and Roll will be taken
// from the values in this packet.  Otherwise normal in-game control will be used.

// Position vector (Vec Pos) - ignored for in-game (not SHIFT+U) cameras.

// For SHIFT+U cameras, Pos can be either relative or absolute.

// If ISS_SHIFTU_FOLLOW is set, that means it's a following camera, so the position
// is relative to the selected car.  Otherwise, the position is an absolute camera
// position, as used in normal SHIFT+U mode.

// NOTE : Set InGameCam or ViewPLID to 255 to leave that option unchanged.

// SMOOTH CAMERA POSITIONING
// --------------------------

// The "Time" value in the packet is used for camera smoothing.  A zero Time means instant
// positioning.  Any other value (milliseconds) will cause the camera to move smoothly to
// the requested position in that time.  This is most useful in SHIFT+U camera modes or
// for smooth changes of internal view when using the ISS_VIEW_OVERRIDE flag.

// NOTE : You can use frequently updated camera positions with a longer "Time" than your
// updates.  For example, sending a camera position every 100 ms, with a Time value of
// 1000 ms.  LFS will make a smooth motion from these "rough" inputs.

// If the requested camera mode is different from the one LFS is already in, it cannot
// move smoothly to the new position, so in this case the "Time" value is ignored.

// GETTING A CAMERA PACKET
// -----------------------

// To GET a CamPosPack from LFS, send this IS_TINY :

// ReqI : non-zero		(returned in the reply)
// SubT : TINY_SCP		(Send Cam Pos)

// LFS will reply with a CamPosPack as described above.  You can store this packet
// and later send back exactly the same packet to LFS and it will try to replicate
// that camera position.


// TIME CONTROL
// ============

// You can Stop or Start Time in LFS and while it is stopped you can make LFS move
// in time steps in multiples of 100th of a second.  Warning : unlike pausing, this
// is a "trick" to LFS and the program is unaware of time passing, so you must not
// leave it stopped because LFS is unusable in that state.  You must never use this
// packet in multiplayer mode.

// Request the current time at any point with this IS_TINY :

// ReqI : non-zero		(returned in the reply)
// SubT : TINY_GTH		(Get Time in Hundredths)

// The time will be sent back in this IS_SMALL :

// ReqI : non-zero		(as received in the request packet)
// SubT : SMALL_RTP		(Race Time Packet)
// UVal	: Time			(hundredths of a second since start of race or replay)

// Stop and Start with this IS_SMALL :

// ReqI : 0
// SubT : SMALL_TMS		(TiMe Stop)
// UVal	: stop			(1 - stop / 0 - carry on)

// When STOPPED, make time step updates with this IS_SMALL :

// ReqI : 0
// SubT : SMALL_STP		(STeP)
// UVal : number		(number of hundredths of a second to update)


// BUTTONS
// =======

// You can make up to 240 buttons appear on the host or guests (ID = 0 to 239).
// You should set the ISF_LOCAL flag (in IS_ISI) if your program is not a host control
// system, to make sure your buttons do not conflict with any buttons sent by the host.

// LFS can display normal buttons in these four screens :

// - main entry screen
// - game setup screen
// - in game
// - SHIFT+U mode

// The recommended area for most buttons is defined by :

#define IS_X_MIN 0
#define IS_X_MAX 110

#define IS_Y_MIN 30
#define IS_Y_MAX 170

// If you draw buttons in this area, the area will be kept clear to
// avoid overlapping LFS buttons with your InSim program's buttons.
// Buttons outside that area will not have a space kept clear.
// You can also make buttons visible in all screens - see below.

// To delete one button or clear all buttons, send this packet :

struct IS_BFN // Button FunctioN - delete buttons / receive button requests
{
	byte	Size;		// 8
	byte	Type;		// ISP_BFN
	byte	ReqI;		// 0
	byte	SubT;		// subtype, from BFN_ enumeration (see below)

	byte	UCID;		// connection to send to or from (0 = local / 255 = all)
	byte	ClickID;	// ID of button to delete (if SubT is BFN_DEL_BTN)
	byte	Inst;		// used internally by InSim
	byte	Sp3;
};

enum // the fourth byte of IS_BFN packets is one of these
{
	BFN_DEL_BTN,		//  0 - instruction     : delete one button (must set ClickID)
	BFN_CLEAR,			//  1 - instruction		: clear all buttons made by this insim instance
	BFN_USER_CLEAR,		//  2 - info            : user cleared this insim instance's buttons
	BFN_REQUEST,		//  3 - user request    : SHIFT+B or SHIFT+I - request for buttons
};

// NOTE : BFN_REQUEST allows the user to bring up buttons with SHIFT+B or SHIFT+I

// SHIFT+I clears all host buttons if any - or sends a BFN_REQUEST to host instances
// SHIFT+B is the same but for local buttons and local instances

// To send a button to LFS, send this variable sized packet

struct IS_BTN // BuTtoN - button header - followed by 0 to 240 characters
{
	byte	Size;		// 12 + TEXT_SIZE (a multiple of 4)
	byte	Type;		// ISP_BTN
	byte	ReqI;		// non-zero (returned in IS_BTC and IS_BTT packets)
	byte	UCID;		// connection to display the button (0 = local / 255 = all)

	byte	ClickID;	// button ID (0 to 239)
	byte	Inst;		// some extra flags - see below
	byte	BStyle;		// button style flags - see below
	byte	TypeIn;		// max chars to type in - see below

	byte	L;			// left   : 0 - 200
	byte	T;			// top    : 0 - 200
	byte	W;			// width  : 0 - 200
	byte	H;			// height : 0 - 200

//	char	Text[TEXT_SIZE]; // 0 to 240 characters of text
};

// ClickID byte : this value is returned in IS_BTC and IS_BTT packets.

// Host buttons and local buttons are stored separately, so there is no chance of a conflict between
// a host control system and a local system (although the buttons could overlap on screen).

// Programmers of local InSim programs may wish to consider using a configurable button range and
// possibly screen position, in case their users will use more than one local InSim program at once.

// TypeIn byte : if set, the user can click this button to type in text.

// Lowest 7 bits are the maximum number of characters to type in (0 to 95)
// Highest bit (128) can be set to initialise dialog with the button's text

// On clicking the button, a text entry dialog will be opened, allowing the specified number of
// characters to be typed in.  The caption on the text entry dialog is optionally customisable using
// Text in the IS_BTN packet.  If the first character of IS_BTN's Text field is zero, LFS will read
// the caption up to the second zero.  The visible button text then follows that second zero.

// Text : 0-65-66-0 would display button text "AB" and no caption

// Text : 0-65-66-67-0-68-69-70-71-0-0-0 would display button text "DEFG" and caption "ABC"

// Inst byte : mainly used internally by InSim but also provides some extra user flags

#define INST_ALWAYS_ON	128		// if this bit is set the button is visible in all screens

// NOTE : You should not use INST_ALWAYS_ON for most buttons.  This is a special flag for buttons
// that really must be on in all screens (including the garage and options screens).  You will
// probably need to confine these buttons to the top or bottom edge of the screen, to avoid
// overwriting LFS buttons.  Most buttons should be defined without this flag, and positioned
// in the recommended area so LFS can keep a space clear in the main screens.

// BStyle byte : style flags for the button

#define ISB_C1			1		// you can choose a standard
#define ISB_C2			2		// interface colour using
#define ISB_C4			4		// these 3 lowest bits - see below
#define ISB_CLICK		8		// click this button to send IS_BTC
#define ISB_LIGHT		16		// light button
#define ISB_DARK		32		// dark button
#define ISB_LEFT		64		// align text to left
#define ISB_RIGHT		128		// align text to right

// colour 0 : light grey		(not user editable)
// colour 1 : title colour		(default:yellow)
// colour 2 : unselected text	(default:black)
// colour 3 : selected text		(default:white)
// colour 4 : ok				(default:green)
// colour 5 : cancel			(default:red)
// colour 6 : text string		(default:pale blue)
// colour 7 : unavailable		(default:grey)

// NOTE : If width or height are zero, this would normally be an invalid button.  But in that case if
// there is an existing button with the same ClickID, all the packet contents are ignored except the
// Text field.  This can be useful for updating the text in a button without knowing its position.
// For example, you might reply to an IS_BTT using an IS_BTN with zero W and H to update the text.

// Replies : If the user clicks on a clickable button, this packet will be sent :

struct IS_BTC // BuTton Click - sent back when user clicks a button
{
	byte	Size;		// 8
	byte	Type;		// ISP_BTC
	byte	ReqI;		// ReqI as received in the IS_BTN
	byte	UCID;		// connection that clicked the button (zero if local)

	byte	ClickID;	// button identifier originally sent in IS_BTN
	byte	Inst;		// used internally by InSim
	byte	CFlags;		// button click flags - see below
	byte	Sp3;
};

// CFlags byte : click flags

#define ISB_LMB			1		// left click
#define ISB_RMB			2		// right click
#define ISB_CTRL		4		// ctrl + click
#define ISB_SHIFT		8		// shift + click

// If the TypeIn byte is set in IS_BTN the user can type text into the button
// In that case no IS_BTC is sent - an IS_BTT is sent when the user presses ENTER

struct IS_BTT // BuTton Type - sent back when user types into a text entry button
{
	byte	Size;		// 104
	byte	Type;		// ISP_BTT
	byte	ReqI;		// ReqI as received in the IS_BTN
	byte	UCID;		// connection that typed into the button (zero if local)

	byte	ClickID;	// button identifier originally sent in IS_BTN
	byte	Inst;		// used internally by InSim
	byte	TypeIn;		// from original button specification
	byte	Sp3;

	char	Text[96];	// typed text, zero to TypeIn specified in IS_BTN
};


// OutSim - MOTION SIMULATOR SUPPORT
// ======

// The user's car in multiplayer or the viewed car in single player or
// single player replay can output information to a motion system while
// viewed from an internal view.

// This can be controlled by 5 lines in the cfg.txt file :

// OutSim Mode 0        :0-off 1-driving 2-driving+replay
// OutSim Delay 1       :minimum delay between packets (100ths of a sec)
// OutSim IP 0.0.0.0    :IP address to send the UDP packet
// OutSim Port 0        :IP port
// OutSim ID 0          :if not zero, adds an identifier to the packet

// Each update sends the following UDP packet :

struct OutSimPack
{
	unsigned	Time;	// time in milliseconds (to check order)

	Vector	AngVel;		// 3 floats, angular velocity vector
	float	Heading;	// anticlockwise from above (Z)
	float	Pitch;		// anticlockwise from right (X)
	float	Roll;		// anticlockwise from front (Y)
	Vector	Accel;		// 3 floats X, Y, Z
	Vector	Vel;		// 3 floats X, Y, Z
	Vec		Pos;		// 3 ints   X, Y, Z (1m = 65536)

	int		ID;			// optional - only if GameID is specified
};

// NOTE 1) X and Y axes are on the ground, Z is up.

// NOTE 2) Motion simulators can be dangerous.  The Live for Speed developers do
// not support any motion systems in particular and cannot accept responsibility
// for injuries or deaths connected with the use of such machinery.


// OutGauge - EXTERNAL DASHBOARD SUPPORT
// ========

// The user's car in multiplayer or the viewed car in single player or
// single player replay can output information to a dashboard system
// while viewed from an internal view.

// This can be controlled by 5 lines in the cfg.txt file :

// OutGauge Mode 0        :0-off 1-driving 2-driving+replay
// OutGauge Delay 1       :minimum delay between packets (100ths of a sec)
// OutGauge IP 0.0.0.0    :IP address to send the UDP packet
// OutGauge Port 0        :IP port
// OutGauge ID 0          :if not zero, adds an identifier to the packet

// Each update sends the following UDP packet :

struct OutGaugePack
{
	unsigned	Time;		// time in milliseconds (to check order)

	char	Car[4];			// Car name
	word	Flags;			// OG_FLAGS (see below)
	byte	Gear;			// Reverse:0, Neutral:1, First:2...
	byte	SpareB;
	float	Speed;			// M/S
	float	RPM;			// RPM
	float	Turbo;			// BAR
	float	EngTemp;		// C
	float	Fuel;			// 0 to 1
	float	OilPress;		// BAR
	float	Spare1;
	float	Spare2;
	float	Spare3;
	float	Throttle;		// 0 to 1
	float	Brake;			// 0 to 1
	float	Clutch;			// 0 to 1
	char	Display1[16];	// Usually Fuel
	char	Display2[16];	// Usually Settings

	int		ID;				// optional - only if GameID is specified
};

#define OG_SHIFTLIGHT	1
#define OG_FULLBEAM		2
#define OG_HANDBRAKE	4
#define OG_PITSPEED		8
#define OG_TC			16
#define OG_HEADLIGHTS	32
#define OG_SIGNAL_L		64
#define OG_SIGNAL_R		128
#define OG_REDLINE		256
#define OG_OILWARN		512
#define OG_1			1024
#define OG_2			2048
#define OG_3			4096
#define OG_4			8192
#define OG_KM			16384
#define OG_BAR			32768

//////
#endif