LYT FILES : Live for Speed 0.8A
=========
Live for Speed Layout File Format
This document refers to the .LYT files created in the Layout Editor
The OBJECT BLOCK is also used in related InSim packets
Changes in 0.6H
===============
Floating objects allowed
Added custom start positions
Adjustable concrete objects included
Zchar changed to Zbyte - negative values no longer used
Index 255 now refers only to route checkers
Index 254 now refers to a restricted area
Changes to Flags byte in NOTE1 below
The flags byte in the file header has also changed
Changes in 0.8A
===============
Updated layout objects
- various objects now have a colour and mapping (in Flags - see NOTE1)
- 38 of the old objects are replaced by another object + colour or mapping
- for example AXO_CONE_GREEN is now AXO_CONE1 with colour '3'
- see the table in NOTE6 for information about the conversion
File header 'flags' byte changed to a layout revision number 'mini_rev'
New marshal object with Index 240 replaces marshals in restricted areas
TYPES
=====
short : 16 bit signed integer
word : 16 bit unsigned
char : 8 bit signed
byte : 8 bit unsigned
FILE DESCRIPTION
================
num unit offset description
--- ---- ------ -----------
HEADER BLOCK
6 char 0 LFSLYT : do not read file if no match
1 byte 6 version : do not read file if > 0
1 byte 7 revision : do not read file if > 252
1 word 8 num added objects : number of OBJECT BLOCKS
1 byte 10 laps : number
1 byte 11 mini_rev : 9 in new files - see NOTE4
......OBJECT BLOCKS
OBJECT BLOCK
1 short 0 X : position (1 metre = 16)
1 short 2 Y : position (1 metre = 16)
1 byte 4 Zbyte : height (1m = 4) - see NOTE3
1 byte 5 Flags : various - see NOTE1
1 byte 6 Index : object index - see NOTE1/5
1 byte 7 Heading : heading - see NOTE2
NOTE1
-----
For all objects except the concrete objects AXO_CONCRETE_SLAB etc.
if (Flags & 0x80) // highest bit of Flags is set
{
// floating object - remains at altitude specified by Zbyte
}
How to distinguish between physical objects and special control objects
like start positions, checkpoints, finish line and marshal circles.
if (Index==0) // special control object
{
// Heading has its usual meaning
// Flags byte :
// bits 0 to 1 :
// 00 = Start position (if width = 0) or finish line (if width > 0)
// 01 = Checkpoint 1
// 10 = Checkpoint 2
// 11 = Checkpoint 3
// bits 2 to 6 :
// half width in metres (1 to 31 - shifted left by 2 bits)
}
if (Index >= 4 && Index < 192) // an object from the list in NOTE5
{
// Heading has its usual meaning
if (Index >= AXO_TYRE_SINGLE && Index <= AXO_TYRE_STACK4_BIG)
{
// Tyres - 3 bits for colour
int c_num = Flags & 0x07; // BLACK, WHITE, RED, BLUE, GREEN, YELLOW
}
else if (Index >= AXO_CHALK_LINE && Index <= AXO_CHALK_RIGHT3)
{
// Chalk - 2 bits for colour
int c_num = Flags & 0x03; // WHITE, RED, BLUE, YELLOW
}
else if (Index >= AXO_START_POSITION && Index <= AXO_PIT_START_POINT)
{
// Start position - 6 bits for position index
int x_num = Flags & 0x3f; // 0 to 47 (start pos 1 to 48)
}
else if (Index >= AXO_PAINT_LETTERS && Index <= AXO_PAINT_ARROWS)
{
int c_num = Flags & 0x01; // 1 bit for colour (white/yellow)
int m_num = (Flags & 0x7e) >> 1; // 6 bits for mapping
}
else if (Index >= AXO_CONCRETE_SLAB && Index <= AXO_CONCRETE_RAMP_WALL)
{
// Concrete objects - always floating regardless of 0x80 bit
// Flags byte contains various attributes depending on the object
// In this version each concrete object has three attributes
Attributes:
NAME BITS VALUES
Width : 0x03 >> 0 : 2, 4, 8, 16
Length : 0x0c >> 2 : 2, 4, 8, 16
Size X : 0x03 >> 0 : 0.25, 0.5, 0.75, 1
Size Y : 0x0c >> 2 : 0.25, 0.5, 0.75, 1
Height : 0xf0 >> 4 : 0.25 to 4 in steps of 0.25
Pitch : 0xf0 >> 4 : 0 to 90 in steps of 6 degrees
Colour : 0x03 >> 0 : grey / red / blue / yellow
Angle : 0xf0 >> 4 : 5.625 to 90 in steps of 5.625 deg
Attributes used by each object:
AXO_CONCRETE_SLAB : Width / Length / Pitch
AXO_CONCRETE_RAMP : Width / Length / Height
AXO_CONCRETE_WALL : Colour / Length / Height
AXO_CONCRETE_PILLAR : Size X / Size Y / Height
AXO_CONCRETE_SLAB_WALL : Colour / Length / Pitch
AXO_CONCRETE_RAMP_WALL : Colour / Length / Height
AXO_CONCRETE_SHORT_SLAB_WALL : Colour / Size Y / Pitch
AXO_CONCRETE_WEDGE : Colour / Length / Angle
}
else if (Index >= AXO_LETTER_BOARD_WY && Index <= AXO_LETTER_BOARD_RB)
{
int c_num = Flags & 0x01; // 1 bit for colour
int m_num = (Flags & 0x7e) >> 1; // 6 bits for mapping
}
else if (main_index < AXO_NUM) // default bits for other objects
{
int c_num = Flags & 0x07; // 3 bits for colour
int m_num = (Flags & 0x78) >> 3; // 4 bits for mapping
}
}
if (Index==240) // a marshal
{
// Flags byte :
// bits 0 to 1 :
// 00 = standing marshal
// 01 = marshal pointing left
// 10 = marshal pointing right
}
if (Index==252) // InSim checkpoint
{
// Checkpoint index is stored in Flags bits 0 and 1
// 00 = finish line
// 01 = 1st checkpoint
// 10 = 2nd checkpoint
// 11 = 3rd checkpoint
}
if (Index==253) // InSim circle
{
// Circle index is stored in the Heading byte
}
if (Index==254) // a restricted area circle
{
// Flags byte :
// bits 2 to 6 :
// radius in metres (1 to 31 - shifted left by 2 bits)
}
if (Index==255) // route checker circle
{
// Route index is stored in the Heading byte
// Flags byte :
// bits 2 to 6 :
// radius in metres (1 to 31 - shifted left by 2 bits)
}
NOTE2
-----
Heading represents 360 degrees in 256 values.
Heading = (heading_in_degrees + 180) * 256 / 360
128 : heading of zero
192 : heading of 90 degrees
0 : heading of 180 degrees
64 : heading of -90 degrees
NOTE3
-----
About Zbyte, the approximate altitude :
LFS does contact checks to place objects accurately on the ground.
For output purposes : Zbyte indicates the approximate altitude with a value
from 0 to 240 (60 metres).
For input purposes : The ground check is performed with a test ray starting
from 2 metres above Zbyte. Using a value lower than 240 allows objects to
be placed on the road below a bridge, for example. If you are creating
objects from scratch and you are not sure of the approximate altitude, you
can set Zbyte to its maximum value (240). This will place the object on
the first physical surface detected below that point.
NOTE4
-----
If the file is saved in the most recent format, the mini_rev byte is 9.
mini_rev < 1 : correct for the Blackwood scaling (multiply by 0.927)
mini_rev < 3 : convert to universal layout objects (new in 0.5Z34)
mini_rev < 7 : convert to the 0.6H file format (introduced in 0.6G3)
mini_rev < 8 : Blackwood car park layouts subtract 40 metres from X
mini_rev < 9 : convert to 0.8A objects with colours and mappings (NOTE6)
NOTE5
-----
The first valid object index is 4 (AXO_CHALK_LINE).
The gaps are to allow for future objects.
Valid object indices are all less than 192.
Comments "// was AXO_x" : see conversion table (NOTE6).
AXO_NULL,
AXO_1,
AXO_2,
AXO_3,
AXO_CHALK_LINE,
AXO_CHALK_LINE2,
AXO_CHALK_AHEAD,
AXO_CHALK_AHEAD2,
AXO_CHALK_LEFT,
AXO_CHALK_LEFT2,
AXO_CHALK_LEFT3,
AXO_CHALK_RIGHT,
AXO_CHALK_RIGHT2,
AXO_CHALK_RIGHT3,
AXO_14,
AXO_15,
AXO_PAINT_LETTERS,
AXO_PAINT_ARROWS,
AXO_18,
AXO_19,
AXO_CONE1,
AXO_CONE2,
AXO_22, // was AXO_CONE_RED3
AXO_23, // was AXO_CONE_BLUE
AXO_24, // was AXO_CONE_BLUE2
AXO_25, // was AXO_CONE_GREEN
AXO_26, // was AXO_CONE_GREEN2
AXO_27, // was AXO_CONE_ORANGE
AXO_28, // was AXO_CONE_WHITE
AXO_29, // was AXO_CONE_YELLOW
AXO_30, // was AXO_CONE_YELLOW2
AXO_31,
AXO_CONE_TALL1,
AXO_CONE_TALL2,
AXO_34,
AXO_35,
AXO_36,
AXO_37,
AXO_38,
AXO_39,
AXO_CONE_POINTER,
AXO_41, // was AXO_CONE_PTR_BLUE
AXO_42, // was AXO_CONE_PTR_GREEN
AXO_43, // was AXO_CONE_PTR_YELLOW
AXO_44,
AXO_45,
AXO_46,
AXO_47,
AXO_TYRE_SINGLE,
AXO_TYRE_STACK2,
AXO_TYRE_STACK3,
AXO_TYRE_STACK4,
AXO_TYRE_SINGLE_BIG,
AXO_TYRE_STACK2_BIG,
AXO_TYRE_STACK3_BIG,
AXO_TYRE_STACK4_BIG,
AXO_56,
AXO_57,
AXO_58,
AXO_59,
AXO_60,
AXO_61,
AXO_62,
AXO_63,
AXO_MARKER_CORNER,
AXO_65, // was AXO_MARKER_CURVE_R
AXO_66, // was AXO_MARKER_L
AXO_67, // was AXO_MARKER_R
AXO_68, // was AXO_MARKER_HARD_L
AXO_69, // was AXO_MARKER_HARD_R
AXO_70, // was AXO_MARKER_L_R
AXO_71, // was AXO_MARKER_R_L
AXO_72, // was AXO_MARKER_S_L
AXO_73, // was AXO_MARKER_S_R
AXO_74, // was AXO_MARKER_S2_L
AXO_75, // was AXO_MARKER_S2_R
AXO_76, // was AXO_MARKER_U_L
AXO_77, // was AXO_MARKER_U_R
AXO_78,
AXO_79,
AXO_80,
AXO_81,
AXO_82,
AXO_83,
AXO_MARKER_DISTANCE,
AXO_85, // was AXO_DIST50
AXO_86, // was AXO_DIST75
AXO_87, // was AXO_DIST100
AXO_88, // was AXO_DIST125
AXO_89, // was AXO_DIST150
AXO_90, // was AXO_DIST200
AXO_91, // was AXO_DIST250
AXO_LETTER_BOARD_WY,
AXO_LETTER_BOARD_RB,
AXO_94,
AXO_95,
AXO_ARMCO1,
AXO_ARMCO3,
AXO_ARMCO5,
AXO_99,
AXO_100,
AXO_101,
AXO_102,
AXO_103,
AXO_BARRIER_LONG,
AXO_BARRIER_RED,
AXO_BARRIER_WHITE,
AXO_107,
AXO_108,
AXO_109,
AXO_110,
AXO_111,
AXO_BANNER,
AXO_113, // was AXO_BANNER2
AXO_114,
AXO_115,
AXO_116,
AXO_117,
AXO_118,
AXO_119,
AXO_RAMP1,
AXO_RAMP2,
AXO_122,
AXO_123,
AXO_VEH_SUV,
AXO_VEH_VAN,
AXO_VEH_TRUCK,
AXO_VEH_AMBULANCE,
AXO_SPEED_HUMP_10M,
AXO_SPEED_HUMP_6M,
AXO_SPEED_HUMP_2M,
AXO_SPEED_HUMP_1M,
AXO_KERB,
AXO_133,
AXO_134,
AXO_135,
AXO_POST,
AXO_137, // was AXO_POST_ORANGE
AXO_138, // was AXO_POST_RED
AXO_139, // was AXO_POST_WHITE
AXO_MARQUEE,
AXO_141,
AXO_142,
AXO_143,
AXO_BALE,
AXO_BIN1,
AXO_BIN2,
AXO_RAILING1,
AXO_RAILING2,
AXO_START_LIGHTS1,
AXO_START_LIGHTS2,
AXO_START_LIGHTS3,
AXO_152,
AXO_153,
AXO_154,
AXO_155,
AXO_156,
AXO_157,
AXO_158,
AXO_159,
AXO_SIGN_METAL,
AXO_161, // was AXO_SIGN_KEEP_RIGHT
AXO_162,
AXO_163,
AXO_SIGN_CHEVRON_LEFT,
AXO_SIGN_CHEVRON_RIGHT,
AXO_166,
AXO_167,
AXO_SIGN_SPEED,
AXO_169, // was AXO_SIGN_SPEED_50
AXO_170,
AXO_171,
AXO_CONCRETE_SLAB,
AXO_CONCRETE_RAMP,
AXO_CONCRETE_WALL,
AXO_CONCRETE_PILLAR,
AXO_CONCRETE_SLAB_WALL,
AXO_CONCRETE_RAMP_WALL,
AXO_CONCRETE_SHORT_SLAB_WALL,
AXO_CONCRETE_WEDGE,
AXO_180,
AXO_181,
AXO_182,
AXO_183,
AXO_START_POSITION,
AXO_PIT_START_POINT,
AXO_PIT_STOP_BOX,
AXO_187,
AXO_188,
AXO_189,
AXO_190,
AXO_191,
NOTE6
-----
Conversion to 0.8A objects
struct ObjConvert_U1
{
byte OldIndex;
byte NewIndex;
byte NewAXCol; // Flags & 0x07
byte NewMapping; // (Flags & 0x78) >> 3
};
const int OC_UPDATE_NUM = 38; // 38 old style objects are mapped to new ones
ObjConvert_U1 OC_UPDATE[OC_UPDATE_NUM] =
{
{ 22, AXO_CONE1, 0, 0 }, // AXO_CONE_RED3
{ 23, AXO_CONE1, 1, 0 }, // AXO_CONE_BLUE
{ 24, AXO_CONE2, 2, 0 }, // AXO_CONE_BLUE2
{ 25, AXO_CONE1, 3, 0 }, // AXO_CONE_GREEN
{ 26, AXO_CONE2, 3, 0 }, // AXO_CONE_GREEN2
{ 27, AXO_CONE2, 4, 0 }, // AXO_CONE_ORANGE
{ 28, AXO_CONE1, 5, 0 }, // AXO_CONE_WHITE
{ 29, AXO_CONE1, 6, 0 }, // AXO_CONE_YELLOW
{ 30, AXO_CONE2, 6, 0 }, // AXO_CONE_YELLOW2
{ 41, AXO_CONE_POINTER, 2, 0 }, // AXO_CONE_PTR_BLUE
{ 42, AXO_CONE_POINTER, 3, 0 }, // AXO_CONE_PTR_GREEN
{ 43, AXO_CONE_POINTER, 6, 0 }, // AXO_CONE_PTR_YELLOW
{ 65, AXO_MARKER_CORNER, 0, 1 }, // AXO_MARKER_CURVE_R
{ 66, AXO_MARKER_CORNER, 0, 2 }, // AXO_MARKER_L
{ 67, AXO_MARKER_CORNER, 0, 3 }, // AXO_MARKER_R
{ 68, AXO_MARKER_CORNER, 0, 4 }, // AXO_MARKER_HARD_L
{ 69, AXO_MARKER_CORNER, 0, 5 }, // AXO_MARKER_HARD_R
{ 70, AXO_MARKER_CORNER, 0, 6 }, // AXO_MARKER_L_R
{ 71, AXO_MARKER_CORNER, 0, 7 }, // AXO_MARKER_R_L
{ 72, AXO_MARKER_CORNER, 0, 8 }, // AXO_MARKER_S_L
{ 73, AXO_MARKER_CORNER, 0, 9 }, // AXO_MARKER_S_R
{ 74, AXO_MARKER_CORNER, 0, 10 }, // AXO_MARKER_S2_L
{ 75, AXO_MARKER_CORNER, 0, 11 }, // AXO_MARKER_S2_R
{ 76, AXO_MARKER_CORNER, 0, 12 }, // AXO_MARKER_U_L
{ 77, AXO_MARKER_CORNER, 0, 13 }, // AXO_MARKER_U_R
{ 85, AXO_MARKER_DISTANCE, 0, 1 }, // AXO_DIST50
{ 86, AXO_MARKER_DISTANCE, 0, 2 }, // AXO_DIST75
{ 87, AXO_MARKER_DISTANCE, 0, 3 }, // AXO_DIST100
{ 88, AXO_MARKER_DISTANCE, 0, 4 }, // AXO_DIST125
{ 89, AXO_MARKER_DISTANCE, 0, 5 }, // AXO_DIST150
{ 90, AXO_MARKER_DISTANCE, 0, 6 }, // AXO_DIST200
{ 91, AXO_MARKER_DISTANCE, 0, 7 }, // AXO_DIST250
{ 113, AXO_BANNER, 0, 1 }, // AXO_BANNER2
{ 137, AXO_POST, 1, 0 }, // AXO_POST_ORANGE
{ 138, AXO_POST, 2, 0 }, // AXO_POST_RED
{ 139, AXO_POST, 3, 0 }, // AXO_POST_WHITE
{ 161, AXO_SIGN_METAL, 0, 1 }, // AXO_SIGN_KEEP_RIGHT
{ 169, AXO_SIGN_SPEED, 0, 1 }, // AXO_SIGN_SPEED_50
};
// only call if (info->Index >= 22 && info->Index < 172 && info->Flags==0)
void ConvertObject(ObjectInfo *info)
{
ObjConvert_U1 *oc = OC_UPDATE;
for (int i=0; i<OC_UPDATE_NUM; i++)
{
if (info->Index==oc->OldIndex) // should be replaced
{
info->Index = oc->NewIndex;
info->Flags = oc->NewAXCol | oc->NewMapping << 3;
}
oc++;
}
}
NOTE7
-----
Colours and names for mappings as displayed in the layout editor
Col kerb_button_cols[16] =
{
{ 222, 225, 222 }, // white
{ 200, 202, 202 },
{ 101, 108, 113 }, // grey
{ 99, 106, 112 },
{ 190, 75, 69 }, // red
{ 175, 74, 69 },
{ 72, 115, 179 }, // blue
{ 69, 106, 165 },
{ 51, 175, 203 }, // cyan
{ 52, 163, 190 },
{ 52, 176, 89 }, // green
{ 55, 156, 86 },
{ 215, 116, 62 }, // orange
{ 182, 109, 66 },
{ 209, 169, 58 }, // yellow
{ 179, 149, 62 },
};
ccs axo_name_arrows[7] =
{
"Left",
"Right",
"Straight L",
"Straight R",
"Curve L",
"Curve R",
"Straight On",
};
ccs axo_name_letters[49] =
{
"A", "B", "C", "D", "E", "F", "G", "H",
"I", "J", "K", "L", "M", "N", "O", "P",
"Q", "R", "S", "T", "U", "V", "W", "X",
"Y", "Z", Char::DigL, Char::DigR, Char::DigU, Char::DigD, "#", "@",
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", ".", ":", "/", "(", ")", "&",
"blank"
};
ccs axo_name_marker_corner[16] =
{
"Curve L",
"Curve R",
"L",
"R",
"Hard L",
"Hard R",
"L R",
"R L",
"S L",
"S R",
"S2 L",
"S2 R",
"U L",
"U R",
"Kink L",
"Kink R",
};
ccs axo_name_marker_distance[8] =
{
"25",
"50",
"75",
"100",
"125",
"150",
"200",
"250",
};
ccs axo_name_sign_metal[8] =
{
"Keep Left",
"Keep Right",
"Left",
"Right",
"Up Left",
"Up Right",
"Forward",
"No Entry",
};
ccs axo_name_sign_speed[4] =
{
"80 km/h",
"50 km/h",
"50 mph",
"40 mph",
};
-----------
www.lfs.net