(svn r10783) [NewGRF_ports] -Feature: Added placing FSMport in any of up to 4 different orientations. GUI now has a preview image for each orientation - not interactive, just a screenshot stored. NewGRF_ports
authorrichk
Sat, 04 Aug 2007 17:26:22 +0000
branchNewGRF_ports
changeset 6745 f45a41940079
parent 6744 e7bf3233928b
child 6746 837a9ca5a2f0
(svn r10783) [NewGRF_ports] -Feature: Added placing FSMport in any of up to 4 different orientations. GUI now has a preview image for each orientation - not interactive, just a screenshot stored.
Next to modify the vehicle movement to account for the station orientation. Need to add saveload ability.
Commuter Airport rb_airport2.grf now includes 2 orientations.
airports.grf modified to include direction arrows.
bin/data/airports.grf
bin/data/rb_airport2.grf
bin/data/sprites/rb_airport2.nfo
bin/data/sprites/rb_airport2.pcx
src/airport_gui.cpp
src/newgrf.cpp
src/newgrf_fsmports.cpp
src/newgrf_fsmports.h
src/station.h
src/station_cmd.cpp
src/table/sprites.h
Binary file bin/data/airports.grf has changed
Binary file bin/data/rb_airport2.grf has changed
--- a/bin/data/sprites/rb_airport2.nfo	Fri Aug 03 18:24:48 2007 +0000
+++ b/bin/data/sprites/rb_airport2.nfo	Sat Aug 04 17:26:22 2007 +0000
@@ -24,8 +24,8 @@
 	9 * 1149	 00 0D 09 01 00
 // Class ID
 	08 "DFLT"
-// Sprite layout, of 21 sprites
-		09 15
+// Sprite layout, of 22 sprites
+		09 16
 // Hangar X
 			4A 0A 00 00
 					0E 00 00 02 10 1C 5F 8A 00 80 // Hangar part 1
@@ -112,13 +112,31 @@
 					0C 07 00 00 00 00 45 04 00 00 // 4 in NE direction
 					00 0F 00 10 01 06 68 8A 00 80 // fence south
 				80
+// Commuter Airport mini pic
+			8C 04 00 08
+				80
 // Define custom layouts
-		0E
-			05 04
+		0E 02   //two layouts
+			01  //NE facing
+			05 04 15  // X, y, minipic ID
 				06 04 12 12 00
 				0E 08 08 08 10
 				0E 02 02 02 10
 				0A 0C 0C 14 0A
+			03  //SE facing
+			04 05 15
+				01 08 08 0B
+				13 08 02 0D
+				13 08 02 0D
+				05 08 02 0D
+				07 08 08 0B
+//			07  //NW facing
+//			04 05
+//				0B 08 08 07
+//				0D 02 08 05
+//				0D 02 08 13
+//				0D 02 08 13
+//				0B 08 08 01
 			00 00
 
 // Define Finite State Machine
@@ -375,7 +393,7 @@
 		22 04
 
 // Define a sprite set for stations, one set, 95 views
-	10 * 4	 01 0D 01 5F
+	10 * 4	 01 0D 01 60
    11 data\sprites/rb_airport2.pcx 194 8 09 31 64 -31 0
    12 data\sprites/rb_airport2.pcx 274 8 09 31 64 -31 0
    13 data\sprites/rb_airport2.pcx 354 8 09 31 64 -31 0
@@ -471,17 +489,18 @@
   103 data\sprites/rb_airport2.pcx 82 344 09 31 64 -31 0
   104 data\sprites/rb_airport2.pcx 162 344 09 31 64 -31 0
   105 data\sprites/rb_airport2.pcx 242 344 09 31 64 -31 0
+  106 data\sprites/rb_airport2.pcx 402 344 09 64 96 0 0
 // Define a graphics set ID (cargo ID = 0
-	106 * 7	 02 0D 00
+	107 * 7	 02 0D 00
 // Little/lots set
 		00 01
 // Set to define the graphics for (set #0)
 		00 00
 // Use graphics ID (1 station, ID 0, 0 cargo specific graphics, default cargo = 0)
-	107 * 7	 03 0D 01 00 00 00 00
+	108 * 7	 03 0D 01 00 00 00 00
 // Set the name of the station; all languages, 1 string, offset of C5 00, because 'generic strings' flag is set it's a word.
-	108 * 21	 04 0D 9F 01 00 CD "Small airports" 00
-	109 * 23	 04 0D 9F 01 00 CE "Commuter airport" 00
+	109 * 21	 04 0D 9F 01 00 CD "Small airports" 00
+	110 * 23	 04 0D 9F 01 00 CE "Commuter airport" 00
 // The Fence Layouts
 //					0F 00 00 01 10 06 67 8A 00 80 // fence west
 //					00 00 00 10 01 06 68 8A 00 80 // fence north
Binary file bin/data/sprites/rb_airport2.pcx has changed
--- a/src/airport_gui.cpp	Fri Aug 03 18:24:48 2007 +0000
+++ b/src/airport_gui.cpp	Sat Aug 04 17:26:22 2007 +0000
@@ -34,7 +34,7 @@
 	FSMportsClassIDByte fsmports_class;
 	byte station_type;
 	byte station_count;
-} _railstation;
+} _airport;
 //TODO: remove above after conversion
 
 
@@ -56,8 +56,8 @@
 {
 	//DoCommandP(tile, _selected_airport_type, _ctrl_pressed, CcBuildAirport, CMD_BUILD_AIRPORT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_A001_CAN_T_BUILD_AIRPORT_HERE));
 		DoCommandP(tile,
-				_railstation.orientation | (_railstation.numtracks << 8) | (_railstation.platlength << 16) | (_ctrl_pressed << 24),
-				_selected_airport_type | ((_railstation.newstation_selected)? 0x80 : 0x00) | (_railstation.fsmports_class << 8) | (_railstation.station_type << 16), CcBuildAirport,
+				_airport.orientation | (_airport.numtracks << 8) | (_airport.platlength << 16) | (_ctrl_pressed << 24),
+				_selected_airport_type | ((_airport.newstation_selected)? 0x80 : 0x00) | (_airport.fsmports_class << 8) | (_airport.station_type << 16), CcBuildAirport,
 				CMD_BUILD_AIRPORT | CMD_NO_WATER | CMD_AUTO | CMD_MSG(STR_A001_CAN_T_BUILD_AIRPORT_HERE));
 }
 
@@ -176,8 +176,9 @@
 
 	case WE_PAINT: {
 		bool newstations = (GetNumFSMportsClasses() != 0);
+		//DrawPixelInfo tmp_dpi, *old_dpi;
 		int y_offset;
-		const FSMportsSpec *fsmportspec = newstations ? GetCustomFSMportsSpec(_railstation.fsmports_class, _railstation.station_type) : NULL;
+		const FSMportsSpec *fsmportspec = newstations ? GetCustomFSMportsSpec(_airport.fsmports_class, _airport.station_type) : NULL;
 
 		int i; // airport enabling loop
 		uint32 avail_airports;
@@ -199,31 +200,61 @@
 		 * This should be part of newgrf-airports, i suppose
 		 */
 		for (i = 0; i < 9; i++) SetWindowWidgetDisabledState(w, i + 7, !HASBIT(avail_airports, i));
-
 		airport = GetAirport(_selected_airport_type);
 
-		if (_railstation.newstation_selected) {
-			int x = _railstation.platlength;
-			int y = _railstation.numtracks;
-			if (_railstation.orientation == 0) Swap(x, y);
+		//if (_airport.newstation_selected) {
+			int x = fsmportspec->size_x[_airport.orientation];
+			int y = fsmportspec->size_y[_airport.orientation];
+			//if (_airport.orientation == 0) Swap(x, y);
 			SetTileSelectSize(x, y);
-		} else {
 
-			// select default the coverage area to 'Off' (16)
-			SetTileSelectSize(airport->size_x, airport->size_y);
+		for (byte j = 0; j < 4; j++)
+		{
+			SetWindowWidgetDisabledState(w, 28 + j, true);
+			RaiseWindowWidget(w, 28 + j);
+			w->widget[28 + _airport.orientation].data = SPR_IMG_ARROW_NE_WHITE + j;  //reset arrows to white
 		}
 
+
+		byte preview_sprite = 0xFF;
+		for (byte j = 0; j < fsmportspec->numlayouts; j++)
+		{
+			if (fsmportspec->layouts[j] == NULL) break;
+			/* enable the permitted orientations */
+			byte *layout_ptr = (byte*)alloca(x*y + 1);
+			memcpy(layout_ptr, fsmportspec->layouts[j], (x * y) + 1);
+			SetWindowWidgetDisabledState(w, 28 + GB((byte)*layout_ptr,1,2), false);
+			if (j == _airport.orientation) {
+				layout_ptr++;
+				preview_sprite = *layout_ptr;
+			}
+		}
+		LowerWindowWidget(w, 28 + _airport.orientation);
+		w->widget[28 + _airport.orientation].data = SPR_IMG_ARROW_NE_YELLOW + _airport.orientation;  //show in yellow
+
 		_thd.airport = _selected_airport_type;
 		_thd.airport_template = true;
 
-		int rad = _patches.modified_catchment ? ((_railstation.newstation_selected)? fsmportspec->portFSM->catchment : airport->catchment) : 4;
+		int rad = _patches.modified_catchment ? ((_airport.newstation_selected)? fsmportspec->portFSM->catchment : airport->catchment) : 4;
 
 		if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
 
-		SetDParam(0, GetFSMportsClassName(_railstation.fsmports_class));
+		SetDParam(0, GetFSMportsClassName(_airport.fsmports_class));
 		DrawWindowWidgets(w);
 
-		y_offset = newstations ? 90 : 0;
+		/* Set up a clipping area for the preview */
+		DrawFSMportsTile(9, 106, preview_sprite, _airport.fsmports_class, _airport.station_type);
+
+		//if (FillDrawPixelInfo(&tmp_dpi, 9, 106, 96, 64)) {
+			//old_dpi = _cur_dpi;
+			//_cur_dpi = &tmp_dpi;
+			//if (!DrawStationTile(32, 16, _cur_railtype, AXIS_X, _airport.station_class, _airport.station_type)) {
+			//	StationPickerDrawSprite(32, 16, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2);
+			//}
+			//_cur_dpi = old_dpi;
+		//}
+
+		y_offset = newstations ? 170 : 0;
 
 		// strings such as 'Size' and 'Coverage Area'
 		// 'Coverage Area'
@@ -233,17 +264,17 @@
 			uint16 i;
 			uint y = 35;
 
-			for (i = w->vscroll.pos; i < _railstation.station_count && i < (uint)(w->vscroll.pos + w->vscroll.cap); i++) {
-				const FSMportsSpec *fsmportspec = GetCustomFSMportsSpec(_railstation.fsmports_class, i);
+			for (i = w->vscroll.pos; i < _airport.station_count && i < (uint)(w->vscroll.pos + w->vscroll.cap); i++) {
+				const FSMportsSpec *fsmportspec = GetCustomFSMportsSpec(_airport.fsmports_class, i);
 
 				if (fsmportspec != NULL && fsmportspec->name != 0) {
 					if (HASBIT(fsmportspec->callbackmask, CBM_STATION_AVAIL) && GetFSMportsCallback(CBID_STATION_AVAILABILITY, 0, 0, fsmportspec, NULL, INVALID_TILE) == 0) {
 						GfxFillRect(8, y - 2, 127, y + 10, (1 << PALETTE_MODIFIER_GREYOUT));
 					}
 
-					DrawStringTruncated(9, y, fsmportspec->name, i == _railstation.station_type ? 12 : 16, 118);
+					DrawStringTruncated(9, y, fsmportspec->name, i == _airport.station_type ? 12 : 16, 118);
 				} else {
-					DrawStringTruncated(9, y, STR_STAT_CLASS_DFLT, i == _railstation.station_type ? 12 : 16, 118);
+					DrawStringTruncated(9, y, STR_STAT_CLASS_DFLT, i == _airport.station_type ? 12 : 16, 118);
 				}
 
 				y += 14;
@@ -259,7 +290,7 @@
 		case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15:
 			RaiseWindowWidget(w, _selected_airport_type + 7);
 			_selected_airport_type = e->we.click.widget - 7;
-			_railstation.newstation_selected = false;
+			if (GetNumFSMportsClasses() == 0) _airport.newstation_selected = false;
 			LowerWindowWidget(w, _selected_airport_type + 7);
 			SndPlayFx(SND_15_BEEP);
 			SetWindowDirty(w);
@@ -273,7 +304,7 @@
 			break;
 		case 23:
 		case 24:
-			ShowDropDownMenu(w, BuildFSMportsClassDropdown(), _railstation.fsmports_class, 24, 0, 1 << FSMPORTS_CLASS_WAYP);
+			ShowDropDownMenu(w, BuildFSMportsClassDropdown(), _airport.fsmports_class, 24, 0, 1 << FSMPORTS_CLASS_WAYP);
 			break;
 
 		case 25: {
@@ -282,34 +313,44 @@
 
 			if (y >= w->vscroll.cap) return;
 			y += w->vscroll.pos;
-			if (y >= _railstation.station_count) return;
+			if (y >= _airport.station_count) return;
 
 			/* Check station availability callback */
-			fsmportspec = GetCustomFSMportsSpec(_railstation.fsmports_class, y);
+			fsmportspec = GetCustomFSMportsSpec(_airport.fsmports_class, y);
 			if (fsmportspec != NULL &&
 				HASBIT(fsmportspec->callbackmask, CBM_STATION_AVAIL) &&
 				GetFSMportsCallback(CBID_STATION_AVAILABILITY, 0, 0, fsmportspec, NULL, INVALID_TILE) == 0) return;
 
-			_railstation.station_type = y;
-			_railstation.numtracks = fsmportspec->width;
-			_railstation.platlength = fsmportspec->lengths;
-			_railstation.newstation_selected = true;
+			_airport.station_type = y;
+			_airport.platlength= fsmportspec->size_y[_airport.orientation];
+			_airport.numtracks = fsmportspec->size_x[_airport.orientation];
+			_airport.newstation_selected = true;
 
 			SndPlayFx(SND_15_BEEP);
 			SetWindowDirty(w);
 			break;
 			}
+		case 28: case 29: case 30: case 31:
+			w->widget[28 + _airport.orientation].data = SPR_IMG_ARROW_NE_WHITE + _airport.orientation;  //reset arrow to white
+			_airport.orientation = (e->we.click.widget - 28);
+			SetWindowWidgetLoweredState(w, 28, (_airport.orientation == 0));
+			SetWindowWidgetLoweredState(w, 29, (_airport.orientation == 1));
+			SetWindowWidgetLoweredState(w, 30, (_airport.orientation == 2));
+			SetWindowWidgetLoweredState(w, 31, (_airport.orientation == 3));
+			SndPlayFx(SND_15_BEEP);
+			SetWindowDirty(w);
+			break;
 		}
 	} break;
 
 	case WE_DROPDOWN_SELECT: {
-		if (_railstation.fsmports_class != e->we.dropdown.index) {
-			_railstation.fsmports_class = (FSMportsClassID)e->we.dropdown.index;
-			_railstation.station_type  = 0;
-			_railstation.station_count = GetNumCustomFSMports(_railstation.fsmports_class);
+		if (_airport.fsmports_class != e->we.dropdown.index) {
+			_airport.fsmports_class = (FSMportsClassID)e->we.dropdown.index;
+			_airport.station_type  = 0;
+			_airport.station_count = GetNumCustomFSMports(_airport.fsmports_class);
 
-			w->vscroll.count = _railstation.station_count;
-			w->vscroll.pos   = _railstation.station_type;
+			w->vscroll.count = _airport.station_count;
+			w->vscroll.pos   = _airport.station_type;
 		}
 
 		SndPlayFx(SND_15_BEEP);
@@ -362,33 +403,40 @@
 static const Widget _newports_build_airport_picker_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
 {    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_3001_AIRPORT_SELECTION,       STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,   142, 0x0,                              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,   143,   179, 0x0,                              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,   180,   217, 0x0,                              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,   218,   267, 0x0,                              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,   268,   329, 0x0,                              STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   117,   128, STR_SMALL_AIRPORT,                STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   155,   166, STR_CITY_AIRPORT,                 STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   231,   242, STR_HELIPORT,                     STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   167,   178, STR_METRO_AIRPORT ,               STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   193,   204, STR_INTERNATIONAL_AIRPORT,        STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   129,   140, STR_COMMUTER_AIRPORT,             STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   255,   266, STR_HELIDEPOT,                    STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   205,   216, STR_INTERCONTINENTAL_AIRPORT,     STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   243,   254, STR_HELISTATION,                  STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,   281,   292, STR_02DB_OFF,                     STR_3065_DON_T_HIGHLIGHT_COVERAGE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,   281,   292, STR_02DA_ON,                      STR_3064_HIGHLIGHT_COVERAGE_AREA},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   104,   117, STR_SMALL_AIRPORTS,               STR_NULL},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   142,   155, STR_LARGE_AIRPORTS,               STR_NULL},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   180,   193, STR_HUB_AIRPORTS,                 STR_NULL},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   218,   231, STR_HELIPORTS,                    STR_NULL},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   268,   281, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,   222, 0x0,                              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,   223,   259, 0x0,                              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,   260,   297, 0x0,                              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,   298,   347, 0x0,                              STR_NULL},
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,   348,   409, 0x0,                              STR_NULL},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   197,   208, STR_SMALL_AIRPORT,                STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   235,   246, STR_CITY_AIRPORT,                 STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   311,   322, STR_HELIPORT,                     STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   247,   258, STR_METRO_AIRPORT ,               STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   273,   284, STR_INTERNATIONAL_AIRPORT,        STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   209,   220, STR_COMMUTER_AIRPORT,             STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   335,   346, STR_HELIDEPOT,                    STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   285,   296, STR_INTERCONTINENTAL_AIRPORT,     STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   145,   323,   334, STR_HELISTATION,                  STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,   361,   372, STR_02DB_OFF,                     STR_3065_DON_T_HIGHLIGHT_COVERAGE},
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,   361,   372, STR_02DA_ON,                      STR_3064_HIGHLIGHT_COVERAGE_AREA},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   184,   197, STR_SMALL_AIRPORTS,               STR_NULL},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   222,   235, STR_LARGE_AIRPORTS,               STR_NULL},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   260,   273, STR_HUB_AIRPORTS,                 STR_NULL},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   298,   311, STR_HELIPORTS,                    STR_NULL},
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,   348,   361, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
 /* newstations gui additions */
 //TODO: modify for airport specific texts
 {      WWT_INSET,   RESIZE_NONE,    14,     7,   140,    17,    28, STR_02BD,                        STR_SELECT_STATION_CLASS_TIP},
 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   129,   139,    18,    27, STR_0225,                        STR_SELECT_STATION_CLASS_TIP},
 {     WWT_MATRIX,   RESIZE_NONE,    14,     7,   128,    32,   102, 0x501,                           STR_SELECT_STATION_TYPE_TIP},
 {  WWT_SCROLLBAR,   RESIZE_NONE,    14,   129,   140,    32,   102, 0x0,                             STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{      WWT_INSET,   RESIZE_NONE,     7,     7,   107,   104,   172, 0x0,                             STR_NULL},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   109,   140,   104,   119, SPR_IMG_ARROW_NE_WHITE,          STR_NULL},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   109,   140,   120,   135, SPR_IMG_ARROW_SE_WHITE,          STR_NULL},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   109,   140,   136,   151, SPR_IMG_ARROW_SW_WHITE,          STR_NULL},
+{     WWT_IMGBTN,   RESIZE_NONE,    14,   109,   140,   152,   167, SPR_IMG_ARROW_NW_WHITE,          STR_NULL},
+
+
 {   WIDGETS_END},
 };
 
@@ -401,7 +449,7 @@
 };
 
 static const WindowDesc _newports_build_airport_desc = {
-	WDP_AUTO, WDP_AUTO, 148, 330, 148, 330,
+	WDP_AUTO, WDP_AUTO, 148, 410, 148, 410,
 	WC_BUILD_STATION, WC_BUILD_TOOLBAR,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_newports_build_airport_picker_widgets,
@@ -413,16 +461,19 @@
 	Window *w;
 	if (GetNumFSMportsClasses() == 0) {
 		w = AllocateWindowDesc(&_build_airport_desc);
-		_railstation.newstations = false;
+		_airport.station_type = 0;
+		_airport.newstations = false;
 	} else
 	{
 		w = AllocateWindowDesc(&_newports_build_airport_desc);
-		_railstation.newstations = true;
-		_railstation.station_count = GetNumCustomFSMports(_railstation.fsmports_class);
+		_airport.station_type = 0;
+		_airport.newstation_selected = true;
+		_airport.newstations = true;
+		_airport.station_count = GetNumCustomFSMports(_airport.fsmports_class);
 
-		w->vscroll.count = _railstation.station_count;
+		w->vscroll.count = _airport.station_count;
 		w->vscroll.cap   = 5;
-		w->vscroll.pos   = clamp(_railstation.station_type - 2, 0, w->vscroll.count - w->vscroll.cap);
+		w->vscroll.pos   = clamp(_airport.station_type - 2, 0, w->vscroll.count - w->vscroll.cap);
 	}
 }
 
--- a/src/newgrf.cpp	Fri Aug 03 18:24:48 2007 +0000
+++ b/src/newgrf.cpp	Sat Aug 04 17:26:22 2007 +0000
@@ -2183,43 +2183,40 @@
 
 			case 0x0E: // Define custom layout
 				fsmportspec->copied_layouts = false;
-
-				while (buf < *bufp + len) {
-					byte length = grf_load_byte(&buf);
-					byte number = grf_load_byte(&buf);
-					FSMportsLayout layout;
-					uint l, p;
-
-					if (length == 0 || number == 0) break;
-
-					l = length - 1; // index is zero-based
-
-					//debug("l %d > %d ?", length, fsmportspec->lengths);
-					if (length > fsmportspec->lengths) {
-						fsmportspec->layouts = ReallocT(fsmportspec->layouts, length);
-						memset(fsmportspec->layouts + fsmportspec->lengths, 0,
-						       (length - fsmportspec->lengths) * sizeof(*fsmportspec->layouts));
-
-						/* reallocate memory for graphics layout */
-						fsmportspec->layouts[l] = ReallocT(fsmportspec->layouts[l], number);
-						memset(fsmportspec->layouts[l] + number - 1, 0, (sizeof(**fsmportspec->layouts)));
+				{
+					fsmportspec->numlayouts = grf_load_byte(&buf);
+					fsmportspec->size_x = ReallocT(fsmportspec->size_x, fsmportspec->numlayouts);
+					memset(fsmportspec->size_x, 0, fsmportspec->numlayouts);
+					fsmportspec->size_y = ReallocT(fsmportspec->size_y, fsmportspec->numlayouts);
+					memset(fsmportspec->size_y, 0, fsmportspec->numlayouts);
+					fsmportspec->layouts = ReallocT(fsmportspec->layouts, fsmportspec->numlayouts);
+					for (uint set = 0; set < fsmportspec->numlayouts; set++)
+					{
+						byte orientation = grf_load_byte(&buf);
+						byte x = grf_load_byte(&buf);
+						byte y = grf_load_byte(&buf);
+						FSMportsLayout layout;
+
+						if (x == 0 || y == 0) break;
+
+						fsmportspec->layouts[set] = MallocT<FSMportsLayout>((x*y) + 2);
+						memset(fsmportspec->layouts[set], 0, ((x*y) + 2));
+
+						fsmportspec->size_x[set] = x;
+						fsmportspec->size_y[set] = y;
+
+						layout = MallocT<byte>((x * y) + 2);
+						layout[0] = orientation;
+						layout[1] = grf_load_byte(&buf); //minipic sprite ID
+						for (byte l = 2; l < (x*y)+2; l++) {
+							layout[l] = grf_load_byte(&buf);
+						}
+
+//						free(fsmportspec->layouts[set][l][p]);
+						fsmportspec->layouts[set] = (FSMportsLayout*)layout;
 					}
-
-					fsmportspec->lengths = number;
-					fsmportspec->width = length;
-
-					p = 0;
-					layout = MallocT<byte>(length * number);
-					for (l = 0; l < length; l++) {
-						for (p = 0; p < number; p++) {
-							layout[l * number + p] = grf_load_byte(&buf);
-						}
-					}
-
-					l--;
-					p--;
-					free(fsmportspec->layouts[l][p]);
-					fsmportspec->layouts[l][p] = layout;
+					grf_load_byte(&buf);
+					grf_load_byte(&buf);
 				}
 				break;
 
@@ -2227,8 +2224,8 @@
 				byte srcid = grf_load_byte(&buf);
 				const FSMportsSpec *srcfsmportspec = _cur_grffile->fsmports[srcid];
 
-				fsmportspec->lengths   = srcfsmportspec->lengths;
-				fsmportspec->width     = srcfsmportspec->width;
+				fsmportspec->size_x   = srcfsmportspec->size_x;
+				fsmportspec->size_y     = srcfsmportspec->size_y;
 				fsmportspec->layouts   = srcfsmportspec->layouts;
 				fsmportspec->copied_layouts = true;
 			} break;
@@ -2260,8 +2257,8 @@
 				fsmportspec->portFSM->nofelements = grf_load_byte(&buf);
 				fsmportspec->portFSM->layout = MallocT<AirportFTA>(fsmportspec->portFSM->nofelements);
 				fsmportspec->portFSM->moving_data = MallocT<AirportMovingData>(fsmportspec->portFSM->nofelements);
-				fsmportspec->portFSM->size_x = fsmportspec->width;
-				fsmportspec->portFSM->size_y = fsmportspec->lengths;
+				fsmportspec->portFSM->size_x = fsmportspec->size_x[0];
+				fsmportspec->portFSM->size_y = fsmportspec->size_y[0];
 				for (byte element = 0; element < fsmportspec->portFSM->nofelements; element++)
 				{
 					//TODO: this will load into a totally new structure for the FSMport controller to handle generically
--- a/src/newgrf_fsmports.cpp	Fri Aug 03 18:24:48 2007 +0000
+++ b/src/newgrf_fsmports.cpp	Sat Aug 04 17:26:22 2007 +0000
@@ -576,57 +576,37 @@
 /** Draw representation of a station tile for GUI purposes.
  * @param x Position x of image.
  * @param y Position y of image.
- * @param axis Axis.
- * @param railtype Rail type.
+ * @param tile tile ID from action 1 set
  * @param sclass, station Type of station.
  * @param station station ID
  * @return True if the tile was drawn (allows for fallback to default graphic)
  */
-bool DrawFSMportsTile(int x, int y, RailType railtype, Axis axis, FSMportsClassID sclass, uint station)
+bool DrawFSMportsTile(int x, int y, byte tile, FSMportsClassID sclass, uint FSMports)
 {
 	const FSMportsSpec *fsmportsspec;
 	const DrawTileSprites *sprites;
 	const DrawTileSeqStruct *seq;
-	const RailtypeInfo *rti = GetRailTypeInfo(railtype);
 	SpriteID relocation;
 	SpriteID image;
 	SpriteID pal = PLAYER_SPRITE_COLOR(_local_player);
-	uint tile = 2;
 
-	fsmportsspec = GetCustomFSMportsSpec(sclass, station);
+	fsmportsspec = GetCustomFSMportsSpec(sclass, FSMports);
 	if (fsmportsspec == NULL) return false;
 
 	relocation = GetCustomFSMportsRelocation(fsmportsspec, NULL, INVALID_TILE);
 
-	if (HASBIT(fsmportsspec->callbackmask, CBM_CUSTOM_LAYOUT)) {
-		uint16 callback = GetFSMportsCallback(CBID_STATION_SPRITE_LAYOUT, 0x2110000, 0, fsmportsspec, NULL, INVALID_TILE);
-		if (callback != CALLBACK_FAILED) tile = callback;
-	}
+	assert(fsmportsspec->renderdata != NULL);
 
-	if (fsmportsspec->renderdata == NULL) {
-		sprites = GetStationTileLayout(STATION_AIRPORT, tile + axis);
-	} else {
-		sprites = &fsmportsspec->renderdata[(tile < fsmportsspec->tiles) ? tile + axis : (uint)axis];
-	}
+	sprites = &fsmportsspec->renderdata[tile];
 
 	image = sprites->ground_sprite;
-	if (HASBIT(image, SPRITE_MODIFIER_USE_OFFSET)) {
-		image += GetCustomFSMportsGroundRelocation(fsmportsspec, NULL, INVALID_TILE);
-		image += rti->custom_ground_offset;
-	} else {
-		image += rti->total_offset;
-	}
-
+	image += relocation;
 	DrawSprite(image, PAL_NONE, x, y);
 
 	foreach_draw_tile_seq(seq, sprites->seq) {
 		Point pt;
 		image = seq->image;
-		if (HASBIT(image, SPRITE_MODIFIER_USE_OFFSET)) {
-			image += rti->total_offset;
-		} else {
-			image += relocation;
-		}
+		image += relocation;
 
 		if ((byte)seq->delta_z != 0x80) {
 			pt = RemapCoords(seq->delta_x, seq->delta_y, seq->delta_z);
--- a/src/newgrf_fsmports.h	Fri Aug 03 18:24:48 2007 +0000
+++ b/src/newgrf_fsmports.h	Sat Aug 04 17:26:22 2007 +0000
@@ -77,9 +77,10 @@
 
 	byte flags; ///< Bitmask of flags, bit 0: use different sprite set; bit 1: divide cargo about by FSMports size
 
-	byte lengths;
-	byte width;
+	byte *size_x;
+	byte *size_y;
 
+	byte numlayouts;
 	FSMportsLayout **layouts;
 	bool copied_layouts;
 
@@ -148,6 +149,6 @@
 }
 
 /* Draw representation of a FSMports tile for GUI purposes. */
-bool DrawFSMportsTile(int x, int y, RailType railtype, Axis axis, FSMportsClassID sclass, uint FSMports);
+bool DrawFSMportsTile(int x, int y, byte tile, FSMportsClassID sclass, uint FSMports);
 
 #endif /* NEWGRF_FSMPORTS_H */
--- a/src/station.h	Fri Aug 03 18:24:48 2007 +0000
+++ b/src/station.h	Sat Aug 04 17:26:22 2007 +0000
@@ -142,6 +142,7 @@
 	PlayerByte owner;
 	byte facilities;
 	byte airport_type;
+	byte FSMport_layout_set;  /* indicates which layout set (S) of several in an FSMport spec->layouts[S] to use */
 
 	/* trainstation width/height */
 	byte trainst_w, trainst_h;
--- a/src/station_cmd.cpp	Fri Aug 03 18:24:48 2007 +0000
+++ b/src/station_cmd.cpp	Sat Aug 04 17:26:22 2007 +0000
@@ -1516,12 +1516,12 @@
 	return ret;
 }
 
-static void GetFSMportsLayout(byte *layout, int width, int length, const FSMportsSpec *fsmportspec)
+static void GetFSMportsLayout(byte *layout, int width, int length, const FSMportsSpec *fsmportspec, byte set)
 {
 	if (fsmportspec != NULL) {
 		/* Custom layout defined, follow it. */
-		memcpy(layout, fsmportspec->layouts[width - 1][length - 1],
-			length * width);
+		memcpy(layout, fsmportspec->layouts[set],
+			(length * width) + 2);  // width*length sprites, plus orientation byte, and preview minipic sprite
 		return;
 	}
 
@@ -1535,7 +1535,7 @@
  * @param tile tile where airport will be built
  * @param flags operation to perform
  * @param p1 various bitstuffed elements
- * - p1 = (bit  0)    - orientation (Axis)
+ * - p1 = (bit  0-2)  - layout_set for newgrf
  * - p1 = (bit  8-15) - length
  * - p1 = (bit 16-23) - width
  * - p1 = (bit 24)    - allow stations directly adjacent to other stations.
@@ -1551,6 +1551,7 @@
 	const uint airport_type_for_flat_check = 0x80 | (GB(p2, 0, 4) << 3);
 	bool newfsmairport = (HASBIT(p2, 7));
 	byte original_airport_type = GB(p2, 0, 4);
+	byte layout_set = GB(p1, 0, 3);
 
 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 
@@ -1577,8 +1578,8 @@
 	}
 
 	const AirportFTAClass *afc = GetAirport(original_airport_type);
-	int w = afc->size_x;
-	int h = afc->size_y;
+	byte w = afc->size_x;
+	byte h = afc->size_y;
 
 	Station *st = NULL;
 
@@ -1590,8 +1591,8 @@
 
 	if (newfsmairport) {
 		/* Perform NewStation checks */
-		w = fsmportsspec->width;
-		h = fsmportsspec->lengths;
+		w = fsmportsspec->size_x[layout_set];
+		h = fsmportsspec->size_y[layout_set];
 
 		/* Check if the station is buildable */
 		if (HASBIT(fsmportsspec->callbackmask, CBM_STATION_AVAIL) && GetFSMportsCallback(CBID_STATION_AVAILABILITY, 0, 0, fsmportsspec, NULL, INVALID_TILE) == 0) {
@@ -1665,6 +1666,7 @@
 		st->AddFacility(FACIL_AIRPORT, tile);
 		st->airport_type = (byte)original_airport_type;
 		st->airport_flags.ResetAll();
+		st->FSMport_layout_set = layout_set;
 
 		st->rect.BeforeAddRect(tile, w, h, StationRect::ADD_TRY);
 
@@ -1681,8 +1683,10 @@
 			fsmportspecindex = AllocateFSMportsSpecToStation(fsmportsspec, st, flags & DC_EXEC);
 			if (fsmportspecindex == -1) return CMD_ERROR;
 
-			layout_ptr = (byte*)alloca(w * h);
-			GetFSMportsLayout(layout_ptr, w, h, fsmportsspec);
+			layout_ptr = (byte*)alloca((w * h) + 2);
+			GetFSMportsLayout(layout_ptr, w, h, fsmportsspec, layout_set);
+			layout_ptr++; //skip orientation
+			layout_ptr++; //skip minipic ID
 		} else {
 			layout_ptr = (byte*)_airport_sections[original_airport_type];
 		}
@@ -1713,6 +1717,7 @@
 	int w, h;
 	const FSMportsSpec *fsmportsspec;
 	const AirportFTAClass *afc;
+	byte layout_set = st->FSMport_layout_set;
 
 	if (_current_player != OWNER_WATER && !CheckOwnership(st->owner))
 		return CMD_ERROR;
@@ -1722,8 +1727,8 @@
 
 	if (newfsmairport) {
 		fsmportsspec = st->fsmportsspeclist[GetCustomStationSpecIndex(tile)].spec;
-		w = fsmportsspec->width;
-		h = fsmportsspec->lengths;
+		w = fsmportsspec->size_x[layout_set];
+		h = fsmportsspec->size_y[layout_set];
 	} else {
 		afc = st->Airport();
 		w = afc->size_x;
@@ -1743,8 +1748,10 @@
 	byte layout;
 
 	if (newfsmairport) {
-		layout_ptr = (byte*)alloca(w * h);
-		GetFSMportsLayout(layout_ptr, w, h, fsmportsspec);
+		layout_ptr = (byte*)alloca((w * h) + 2);
+		GetFSMportsLayout(layout_ptr, w, h, fsmportsspec, layout_set);
+		layout_ptr++; //skip orientation
+		layout_ptr++; //skip minipic ID
 	} else {
 		layout_ptr = (byte*)_airport_sections[st->airport_type];
 	}
--- a/src/table/sprites.h	Fri Aug 03 18:24:48 2007 +0000
+++ b/src/table/sprites.h	Sat Aug 04 17:26:22 2007 +0000
@@ -122,8 +122,15 @@
 	SPR_NEWHELIPAD = SPR_AIRPORTX_BASE + 12,
 	SPR_GRASS_RIGHT = SPR_AIRPORTX_BASE + 13,
 	SPR_GRASS_LEFT = SPR_AIRPORTX_BASE + 14,
-
-	SPR_ROADSTOP_BASE = SPR_AIRPORTX_BASE + 15, // The sprites used for drive-through road stops
+	SPR_IMG_ARROW_NE_YELLOW = SPR_AIRPORTX_BASE + 15,
+	SPR_IMG_ARROW_SE_YELLOW = SPR_AIRPORTX_BASE + 16,
+	SPR_IMG_ARROW_SW_YELLOW = SPR_AIRPORTX_BASE + 17,
+	SPR_IMG_ARROW_NW_YELLOW = SPR_AIRPORTX_BASE + 18,
+	SPR_IMG_ARROW_NE_WHITE = SPR_AIRPORTX_BASE + 19,
+	SPR_IMG_ARROW_SE_WHITE = SPR_AIRPORTX_BASE + 20,
+	SPR_IMG_ARROW_SW_WHITE = SPR_AIRPORTX_BASE + 21,
+	SPR_IMG_ARROW_NW_WHITE = SPR_AIRPORTX_BASE + 22,
+	SPR_ROADSTOP_BASE = SPR_AIRPORTX_BASE + 23, // The sprites used for drive-through road stops
 	SPR_BUS_STOP_DT_Y_W = SPR_ROADSTOP_BASE,
 	SPR_BUS_STOP_DT_Y_E = SPR_ROADSTOP_BASE + 1,
 	SPR_BUS_STOP_DT_X_W = SPR_ROADSTOP_BASE + 2,