(svn r10824) [NewGRF_ports] -Feature: Added basic code for seaplane airport support. NewGRF_ports
authorrichk
Tue, 07 Aug 2007 23:15:28 +0000
branchNewGRF_ports
changeset 6770 8400b517b905
parent 6769 32594799d0bc
child 6771 5bb52a8ad34e
(svn r10824) [NewGRF_ports] -Feature: Added basic code for seaplane airport support.
Adds prop23 to the FSM spec, which sets a placement mask. Bit 7 of each byte in mask decides whether the tile must be placed on water. Non-water tiles in mask must be placed on non-water. Thus allowing some of FSMport to be on land, some on water.
Airport does not flood, but any aircraft on water at reload of a save will explode!
Added seaplaneport.grf as experiment/proof of concept based on small airport. This uses movement orders to a -8 altitude, relative to airport_tile height.
WARNING: There are no restrictions on what kind of aircraft may currently use airport. So it aint realistic... OK :)
bin/data/seaplaneport.grf
bin/data/sprites/seaplaneport.nfo
bin/data/sprites/seaplaneport.pcx
src/airport_gui.cpp
src/newgrf.cpp
src/newgrf_fsmports.h
src/station.h
src/station_cmd.cpp
src/water_cmd.cpp
Binary file bin/data/seaplaneport.grf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/data/sprites/seaplaneport.nfo	Tue Aug 07 23:15:28 2007 +0000
@@ -0,0 +1,385 @@
+// Automatically generated by GRFCODEC. Do not modify!
+// (Info version 7)
+// Format: spritenum pcxfile xpos ypos compression ysize xsize xrel yrel
+
+// Length of GRF in sprites
+	0 * 4	 74 00 00 00
+// if version of TTDPatch higher than X, skip two sprites
+	1 * 9	 07 8B 04 \7> 02 0A D2 00 02
+// bail out: version too low
+	2 * 20	 0B 03 1F 00 "2.0.1r Alpha 22" 00
+// fail safe when action 0B is not implemented, bail out
+	3 * 9	 07 8B 04 \7< 02 0A DC 00 00
+// check for newstations bit, if set, skip two sprites
+	4 * 6	 07 85 01 \71 52 02
+// bail out: newstation bit not set
+	5 * 19	 0B 03 1F 02 "newstations on" 00
+// fail safe when action 0B is not implemented, bail out
+	6 * 6	 07 85 01 \70 52 00
+// if not in temperate, bail out
+	7 * 6	 07 83 01 \7! 00 00
+// define GRF ID
+	8 * 68	 08 06 C0 DE D0 0D "Seaplane Airport" 00 "Adds a Small Seaplane Airport" 00
+
+// 12 properties to change, 1 station to change, station id = 0
+	9 * 655	 00 0D 0C 01 00
+// Small Seaplane Airport
+// uses normal small airport state machine. Runway moved to lower position
+
+// Class ID
+	08 "SEAP"
+
+// Sprite layout, of 13 sprites
+		09 0D
+// 00 Old Term Left
+			69 0A 00 00
+				80
+// 01 Old Term Mid
+			6A 0A 00 00
+				80
+// 02 Old Term Right
+			6B 0A 00 00
+					00 00 00 0F 0F 1F 6C 8A 00 80 // upper section
+				80
+// 03 Old Hangar
+			4A 0A 00 00  //tarmac below
+					0E 00 00 02 10 1C E7 8F 00 80 // hangar front
+					00 00 00 02 10 1C EB 8F 00 80 // hangar side
+				80
+// 04 Hangar exit
+			DD 0F 00 00
+					0F 00 00 01 10 06 67 8A 00 80 // fence west
+				80
+// 05 grass mid-left
+			DD 0F 00 00
+				80
+// 06 grass mid-right
+			DD 0F 00 00
+				80
+// 07 windsock
+			DD 0F 00 00
+					00 00 00 01 10 06 67 8A 00 80 // fence east
+					04 0B 00 01 01 14 74 8A 00 80 // windsock
+				80
+// 08 Runway start with 04 number
+			DD 0F 00 00
+					0A 02 00 00 00 00 41 04 00 00 // 0 in NE direction
+					08 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
+// 09 Middle runway X
+			DD 0F 00 00
+					00 0F 00 10 01 06 68 8A 00 80 // fence south
+				80
+// 0A Runway mid right
+			DD 0F 00 00
+					00 0F 00 10 01 06 68 8A 00 80 // fence south
+				80
+// 0B Runway start
+			DD 0F 00 00
+					00 0F 00 10 01 06 68 8A 00 80 // fence south
+				80
+// 0C Small Airport mini pic (use commuter to prove its using different graphic set)
+			8C 04 00 08
+				80
+
+//callback mask
+		0B 01 //has a station availability
+
+// Define custom layouts
+		0E 01   //one layouts
+			01  //NE facing
+			04 03 0C  // X, y, minipic ID
+				02 01 00 03
+				07 06 05 04
+				0B 0A 09 08
+			00 00
+
+// Prop19 Vehicle Type
+		19 03 //Air
+
+// Define Finite State Machine
+		1A 16  // positions 00-15
+
+	// Small Airport : Position 00
+	\w53 \w3 \w0 40 \wx0007 00
+		03
+			40 40 00 01
+			51 26 00 01
+			00 40 00 01
+
+	// Small Airport : Position 01
+	\w53 \w27 \wxFFF8 00 \wx0000 40
+		05
+			40 00 00 00
+			01 01 40 02
+			02 00 00 04
+			51 00 00 13
+			00 00 00 06
+
+	// Small Airport : Position 02
+	\w32 \w23 \wxFFF8 01 \wx000F 01
+		05
+			01 01 00 04
+			40 40 01 01
+			41 40 01 01
+			51 40 01 01
+			00 00 00 02
+
+	// Small Airport : Position 03
+	\w10 \w23 \wxFFF8 02 \wx000F 02
+		05
+			02 02 00 05
+			40 40 02 05
+			41 40 02 05
+			51 40 02 05
+			00 00 00 03
+
+	// Small Airport : Position 04
+	\w43 \w37 \wxFFF8 00 \wx0000 40
+		04
+			02 00 00 05
+			40 00 00 01
+			41 00 00 06
+			51 00 00 01
+
+	// Small Airport : Position 05
+	\w24 \w37 \wxFFF8 00 \wx0000 40
+		02
+			02 02 00 03
+			00 00 00 04
+
+	// Small Airport : Position 06
+	\w53 \w37 \wxFFF8 00 \wx0000 40
+		01
+			00 40 00 07
+
+	// Small Airport : Position 07
+	\w61 \w40 \wxFFF8 41 \wx0003 40
+		01
+			00 40 00 08
+
+	// Small Airport : Position 08
+	\w3 \w40 \wxFFF8 42 \wx0010 40
+		01
+			00 00 40 09
+
+	// Small Airport : Position 09
+	\wxFFB1 \w40 \w80 43 \wx0010 40
+		01
+			00 00 00 00
+
+	// Small Airport : Position 0A
+	\w137 \w40 \w80 7F \wx00B0 00
+		03
+			7F 00 00 0F
+			44 40 00 0B
+			54 40 00 14
+
+	// Small Airport : Position 0B
+	\w56 \w40 \wxFFF8 44 \wx0090 40
+		01
+			00 40 00 0C
+
+	// Small Airport : Position 0C
+	\w3 \w40 \wxFFF8 00 \wx00D0 40
+		01
+			00 40 00 0D
+
+	// Small Airport : Position 0D
+	\w7 \w40 \wxFFF8 45 \wx0000 40
+		03
+			45 40 00 0E
+			02 00 00 05
+			00 00 00 0E
+
+	// Small Airport : Position 0E
+	\w53 \w40 \wxFFF8 00 \wx0000 40
+		01
+			00 40 00 01
+
+	// Small Airport : Position 0F
+	\wxFFE1 \w193 \w80 00 \wx00B0 00
+		01
+			00 00 00 10
+
+	// Small Airport : Position 10
+	\w1 \w1 \w80 00 \wx00B0 00
+		01
+			00 00 00 11
+
+	// Small Airport : Position 11
+	\w257 \w1 \w80 00 \wx00B0 00
+		01
+			00 00 00 12
+
+	// Small Airport : Position 12
+	\w273 \w49 \w80 00 \wx00B0 00
+		01
+			00 00 00 0A
+
+	// Small Airport : Position 13
+	\w44 \w37 \w80 51 \wx0000 00
+		01
+			51 00 00 00
+
+	// Small Airport : Position 14
+	\w44 \w40 \w80 54 \wx0030 40
+		01
+			00 40 00 15
+
+	// Small Airport : Position 15
+	\w44 \w40 \wxFFF8 55 \wx0000 40
+		01
+			00 40 00 01
+
+// Prop1C Vehicle Entry Points
+		1C 10 10 10 10
+
+// Prop1D Hangar/Depot Locations
+		1D 01 03 00
+
+// Prop1E Terminal Groups
+		1E 01 02
+
+// Prop20 Port Subtype
+//		20 07
+
+// Prop22 Catchment Area
+		22 04
+
+// Define placement layout mask
+// similar format to custom layout, but gives tile info for placement checks
+// set order must match custom layout order and orientations.
+// custom layout x&y used for x&y info
+		23 01   //one layouts
+			01  //NE facing
+				01 01 01 01
+				80 80 80 80
+				80 80 80 80
+			00 00
+
+
+// Define a sprite set for stations, one set, 95 views
+	10 * 4	 01 0D 01 61
+   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
+   14 data\sprites/rb_airport2.pcx 434 8 09 31 64 -31 0
+   15 data\sprites/rb_airport2.pcx 514 8 09 31 64 -31 0
+   16 data\sprites/rb_airport2.pcx 594 8 09 31 64 -31 0
+   17 data\sprites/rb_airport2.pcx 674 8 09 55 64 -2 -38
+   18 data\sprites/rb_airport2.pcx 754 8 09 17 18 16 -1
+   19 data\sprites/rb_airport2.pcx 2 88 09 55 64 -2 -38
+   20 data\sprites/rb_airport2.pcx 82 88 09 17 18 -30 1
+   21 data\sprites/rb_airport2.pcx 114 88 09 55 64 -2 -38
+   22 data\sprites/rb_airport2.pcx 194 88 09 55 64 -2 -38
+   23 data\sprites/rb_airport2.pcx 274 88 09 14 24 -11 8
+   24 data\sprites/rb_airport2.pcx 306 88 09 31 64 -31 0
+   25 data\sprites/rb_airport2.pcx 386 88 09 31 64 -31 0
+   26 data\sprites/rb_airport2.pcx 466 88 09 31 64 -31 0
+   27 data\sprites/rb_airport2.pcx 546 88 09 31 64 -31 0
+   28 data\sprites/rb_airport2.pcx 626 88 09 8 18 0 0
+   29 data\sprites/rb_airport2.pcx 658 88 09 7 14 4 1
+   30 data\sprites/rb_airport2.pcx 690 88 09 8 12 0 0
+   31 data\sprites/rb_airport2.pcx 722 88 09 8 18 0 0
+   32 data\sprites/rb_airport2.pcx 754 88 09 5 12 4 2
+   33 data\sprites/rb_airport2.pcx 2 168 09 8 18 0 0
+   34 data\sprites/rb_airport2.pcx 34 168 09 8 18 0 0
+   35 data\sprites/rb_airport2.pcx 66 168 09 7 12 0 2
+   36 data\sprites/rb_airport2.pcx 98 168 09 8 18 0 0
+   37 data\sprites/rb_airport2.pcx 130 168 09 7 18 0 1
+   38 data\sprites/rb_airport2.pcx 162 168 09 6 16 2 0
+   39 data\sprites/rb_airport2.pcx 194 168 09 8 18 0 0
+   40 data\sprites/rb_airport2.pcx 226 168 09 8 16 2 0
+   41 data\sprites/rb_airport2.pcx 258 168 09 8 18 0 0
+   42 data\sprites/rb_airport2.pcx 290 168 09 7 14 0 0
+   43 data\sprites/rb_airport2.pcx 322 168 09 8 12 6 0
+   44 data\sprites/rb_airport2.pcx 354 168 09 8 18 0 0
+   45 data\sprites/rb_airport2.pcx 386 168 09 5 12 2 1
+   46 data\sprites/rb_airport2.pcx 418 168 09 8 18 0 0
+   47 data\sprites/rb_airport2.pcx 450 168 09 8 18 0 0
+   48 data\sprites/rb_airport2.pcx 482 168 09 7 12 6 -1
+   49 data\sprites/rb_airport2.pcx 514 168 09 8 18 0 0
+   50 data\sprites/rb_airport2.pcx 546 168 09 7 18 0 0
+   51 data\sprites/rb_airport2.pcx 578 168 09 6 16 0 2
+   52 data\sprites/rb_airport2.pcx 610 168 09 8 18 0 0
+   53 data\sprites/rb_airport2.pcx 642 168 09 8 16 0 0
+   54 data\sprites/rb_airport2.pcx 674 168 09 8 17 0 0
+   55 data\sprites/rb_airport2.pcx 706 168 09 7 15 3 0
+   56 data\sprites/rb_airport2.pcx 738 168 09 5 18 0 3
+   57 data\sprites/rb_airport2.pcx 770 168 09 8 18 0 0
+   58 data\sprites/rb_airport2.pcx 2 200 09 5 12 4 1
+   59 data\sprites/rb_airport2.pcx 34 200 09 8 18 0 0
+   60 data\sprites/rb_airport2.pcx 66 200 09 8 18 0 0
+   61 data\sprites/rb_airport2.pcx 98 200 09 7 13 5 1
+   62 data\sprites/rb_airport2.pcx 130 200 09 8 18 0 0
+   63 data\sprites/rb_airport2.pcx 162 200 09 8 15 3 0
+   64 data\sprites/rb_airport2.pcx 194 200 09 8 12 0 0
+   65 data\sprites/rb_airport2.pcx 226 200 09 8 18 0 0
+   66 data\sprites/rb_airport2.pcx 258 200 09 7 16 0 0
+   67 data\sprites/rb_airport2.pcx 290 200 09 8 17 1 0
+   68 data\sprites/rb_airport2.pcx 322 200 09 7 15 0 1
+   69 data\sprites/rb_airport2.pcx 354 200 09 5 18 0 0
+   70 data\sprites/rb_airport2.pcx 386 200 09 8 18 0 0
+   71 data\sprites/rb_airport2.pcx 418 200 09 5 12 2 2
+   72 data\sprites/rb_airport2.pcx 450 200 09 8 18 0 0
+   73 data\sprites/rb_airport2.pcx 482 200 09 8 18 0 0
+   74 data\sprites/rb_airport2.pcx 514 200 09 7 13 0 0
+   75 data\sprites/rb_airport2.pcx 546 200 09 8 18 0 0
+   76 data\sprites/rb_airport2.pcx 578 200 09 8 15 0 0
+   77 data\sprites/rb_airport2.pcx 610 200 09 8 12 6 0
+   78 data\sprites/rb_airport2.pcx 642 200 09 8 18 0 0
+   79 data\sprites/rb_airport2.pcx 674 200 09 7 16 2 1
+   80 data\sprites/rb_airport2.pcx 706 200 09 31 64 -31 0
+   81 data\sprites/rb_airport2.pcx 2 248 09 31 64 -31 0
+   82 data\sprites/rb_airport2.pcx 82 248 09 31 64 -31 0
+   83 data\sprites/rb_airport2.pcx 162 248 09 31 64 -31 0
+   84 data\sprites/rb_airport2.pcx 242 248 09 31 64 -31 0
+   85 data\sprites/rb_airport2.pcx 322 248 09 31 64 -31 0
+   86 data\sprites/rb_airport2.pcx 402 248 09 20 64 -31 0
+   87 data\sprites/rb_airport2.pcx 482 248 09 20 64 -31 11
+   88 data\sprites/rb_airport2.pcx 562 248 09 31 36 -3 0
+   89 data\sprites/rb_airport2.pcx 610 248 09 31 36 -31 0
+   90 data\sprites/rb_airport2.pcx 658 248 09 4 63 -30 12
+   91 data\sprites/rb_airport2.pcx 738 248 09 32 1 1 -1
+   92 data\sprites/rb_airport2.pcx 2 296 09 31 64 -31 0
+   93 data\sprites/rb_airport2.pcx 82 296 09 31 64 -31 0
+   94 data\sprites/rb_airport2.pcx 162 296 09 31 64 -31 0
+   95 data\sprites/rb_airport2.pcx 242 296 09 31 64 -31 0
+   96 data\sprites/rb_airport2.pcx 322 296 09 31 64 -31 0
+   97 data\sprites/rb_airport2.pcx 402 296 09 31 64 -31 0
+   98 data\sprites/rb_airport2.pcx 482 296 09 31 64 -31 0
+   99 data\sprites/rb_airport2.pcx 562 296 09 31 64 -31 0
+  100 data\sprites/rb_airport2.pcx 642 296 09 31 64 -31 0
+  101 data\sprites/rb_airport2.pcx 722 296 09 31 64 -31 0
+  102 data\sprites/rb_airport2.pcx 2 344 09 31 64 -31 0
+  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
+  107 data\sprites/rb_airport2.pcx 510 344 09 64 96 0 0
+// Define a graphics set ID (cargo ID = 0
+	108 * 7	 02 0D 00
+// Little/lots set
+		00 01
+// Set to define the graphics for (set #0)
+		00 00
+
+//availability date varaction2
+//small airport available from 1931 (1920+11) to 1975 (1920+55)
+	110 * 14	 02 0D 02 81 01 00 FF 01 00 00 0B 37 00 FF
+
+// Use graphics ID (1 station, ID 0, 0 cargo specific graphics, default cargo = 0)
+	112 * 7	 03 0D 01 00 00 02 00
+
+// Name
+// Set the name of the station; all languages, 1 string, offset of CD 00, because 'generic strings' flag is set it's a word.
+	114 * 21	 04 0D 9F 01 00 CD "Seaplane airports" 00
+	115 * 20	 04 0D 9F 01 00 CE "Small Seaplane 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
+//					00 00 00 01 10 06 67 8A 00 80 // fence east
+//					00 0F 00 10 01 06 68 8A 00 80 // fence south
Binary file bin/data/sprites/seaplaneport.pcx has changed
--- a/src/airport_gui.cpp	Tue Aug 07 15:11:52 2007 +0000
+++ b/src/airport_gui.cpp	Tue Aug 07 23:15:28 2007 +0000
@@ -53,7 +53,7 @@
 		DoCommandP(tile,
 				_airport.layout_set | (_airport.numtracks << 8) | (_airport.platlength << 16) | (_ctrl_pressed << 24),
 				0x80 | (_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));
+				CMD_BUILD_AIRPORT | CMD_AUTO | CMD_MSG(STR_A001_CAN_T_BUILD_AIRPORT_HERE));
 }
 
 static void PlaceAir_DemolishArea(TileIndex tile)
--- a/src/newgrf.cpp	Tue Aug 07 15:11:52 2007 +0000
+++ b/src/newgrf.cpp	Tue Aug 07 23:15:28 2007 +0000
@@ -2354,10 +2354,37 @@
 				break;
 
 			case 0x22: // Catchment Area
-				fsmportspec->portFSM->catchment = grf_load_word(&buf);
+				fsmportspec->portFSM->catchment = grf_load_byte(&buf);
 				ret = true;
 				break;
 
+			case 0x23: // Define placement layout mask
+				{
+					byte numlayouts = grf_load_byte(&buf);
+					fsmportspec->layout_mask = ReallocT(fsmportspec->layout_mask, numlayouts);
+					for (uint set = 0; set < numlayouts; set++)
+					{
+						byte orientation = grf_load_byte(&buf);
+						byte x = fsmportspec->size_x[set];
+						byte y = fsmportspec->size_y[set];
+
+						fsmportspec->layout_mask[set] = MallocT<FSMportsLayout>((x*y) + 2);
+						memset(fsmportspec->layout_mask[set], 0, ((x*y) + 2));
+
+						FSMportsLayout layout;
+						layout = MallocT<byte>((x * y) + 2);
+						layout[0] = orientation;
+						layout[1] = 0x00; //no minipic sprite ID
+						for (byte l = 2; l < (x*y)+2; l++) {
+							layout[l] = grf_load_byte(&buf);
+						}
+						fsmportspec->layout_mask[set] = (FSMportsLayout*)layout;
+					}
+					grf_load_byte(&buf);
+					grf_load_byte(&buf);
+				}
+				break;
+
 			default:
 				ret = true;
 				break;
--- a/src/newgrf_fsmports.h	Tue Aug 07 15:11:52 2007 +0000
+++ b/src/newgrf_fsmports.h	Tue Aug 07 23:15:28 2007 +0000
@@ -73,6 +73,8 @@
 	FSMportsLayout **layouts;
 	bool copied_layouts;
 
+	FSMportsLayout **layout_mask;
+
 	AirportFTAClass *portFSM;
 
 	/**
--- a/src/station.h	Tue Aug 07 15:11:52 2007 +0000
+++ b/src/station.h	Tue Aug 07 23:15:28 2007 +0000
@@ -144,6 +144,7 @@
 	byte airport_type;
 	byte FSMport_layout_set;  /* indicates which layout set (S) of several in an FSMport spec->layouts[S] to use */
 	byte FSMport_orientation; /* direction of orientation of station for use with FSMports */
+	bool FSMport_flood_protected;     /* prevents flooding destroying water based FSMports */
 
 	/* trainstation width/height */
 	byte trainst_w, trainst_h;
--- a/src/station_cmd.cpp	Tue Aug 07 15:11:52 2007 +0000
+++ b/src/station_cmd.cpp	Tue Aug 07 23:15:28 2007 +0000
@@ -665,7 +665,7 @@
 
 // Tries to clear the given area. Returns the cost in case of success.
 // Or an error code if it failed.
-CommandCost CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, StationID* station, bool check_clear = true)
+CommandCost CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, StationID* station, bool FSMlayoutMask, bool check_clear = true)
 {
 	CommandCost cost;
 	int allowed_z = -1;
@@ -728,7 +728,10 @@
 			// first tile
 			allowed_z = flat_z;
 		} else if (do_tile_test && (allowed_z != flat_z)) {
-			return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
+			/* test here whether build on height permitted. for FSM ports with layout masks, this is not an error
+			 * land checking is done in airport placement
+			 */
+			if (!FSMlayoutMask) return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
 		}
 
 		if (do_tile_test) {
@@ -757,6 +760,11 @@
 	return cost;
 }
 
+CommandCost CheckFlatLandBelow(TileIndex tile, uint w, uint h, uint flags, uint invalid_dirs, StationID* station, bool check_clear = true)
+{
+	return CheckFlatLandBelow(tile, w, h, flags, invalid_dirs, station, false, check_clear);
+}
+
 static bool CanExpandRailroadStation(const Station* st, uint* fin, Axis axis)
 {
 	uint curw = st->trainst_w;
@@ -1352,7 +1360,7 @@
 		/* Do not remove roadtypes! */
 		rts |= cur_rts;
 	}
-	cost = CheckFlatLandBelow(tile, 1, 1, flags, is_drive_through ? 5 << p1 : 1 << p1, NULL, !build_over_road);
+	cost = CheckFlatLandBelow(tile, 1, 1, flags, is_drive_through ? 5 << p1 : 1 << p1, NULL, false, !build_over_road);
 	if (CmdFailed(cost)) return cost;
 
 	Station *st = NULL;
@@ -1654,8 +1662,45 @@
 		}
 	}
 
-
-	CommandCost ret = CheckFlatLandBelow(tile, w, h, flags, airport_type_for_flat_check, NULL);
+	flags |= DC_NO_WATER;
+	/* do FSM layout mask checks
+	 * These allow placement on water, and irregular heights within layout.
+	 * If building on water is allowed for one tile, permit it for whole airport. This is not the problem it appears.
+	 * This routine does all the other tile validations, so although CMD_NO_WATER is cleared, it has already verified that
+	 * the tiles have the correct land/water statuses.
+	 */
+	if (fsmportsspec->layout_mask != NULL) {
+		byte *mask_ptr;
+		byte mask;
+		mask_ptr = (byte*)alloca((w * h) + 2);
+		memcpy(mask_ptr, fsmportsspec->layout_mask[layout_set], (w * h) + 2);  // width*length flagbytes, plus orientation byte
+		mask_ptr++; //skip orientation
+		mask_ptr++; //skip 0x00
+		BEGIN_TILE_LOOP(tile_cur, w, h, tile) {
+			mask = *mask_ptr++;
+			if (mask & 0x80) {
+				/* do water tests */
+				if (IsTileType(tile_cur, MP_WATER) && IsClearWaterTile(tile_cur)) {
+					if (!IsCoast(tile_cur)) {
+						flags &= ~DC_NO_WATER;
+						st->FSMport_flood_protected = true;
+					}
+				} else {
+					_error_message = STR_304B_SITE_UNSUITABLE;
+					return CMD_ERROR;
+				}
+			} else {
+				if (IsTileType(tile_cur, MP_WATER) && IsClearWaterTile(tile_cur)) {
+					/* tile should be land, but is water */
+					_error_message = STR_3807_CAN_T_BUILD_ON_WATER;
+					return CMD_ERROR;
+				}
+			}
+			//TODO: add height comparison & validation code here
+		} END_TILE_LOOP(tile_cur, w, h, tile)
+	}
+
+	CommandCost ret = CheckFlatLandBelow(tile, w, h, flags, airport_type_for_flat_check, NULL, fsmportsspec->layout_mask != NULL, true);
 	if (CmdFailed(ret)) return ret;
 	CommandCost cost(ret.GetCost());
 
--- a/src/water_cmd.cpp	Tue Aug 07 15:11:52 2007 +0000
+++ b/src/water_cmd.cpp	Tue Aug 07 23:15:28 2007 +0000
@@ -362,7 +362,7 @@
 					return false;
 			}
 
-		case MP_STATION: return IsOilRig(tile) || IsDock(tile) || IsBuoy(tile);
+		case MP_STATION: return IsCustomFSMportsSpecIndex(tile) || IsOilRig(tile) || IsDock(tile) || IsBuoy(tile);
 		default:         return false;
 	}
 }
@@ -542,6 +542,12 @@
 	/* type of this tile mustn't be water already. */
 	if (IsTileType(target, MP_WATER)) return;
 
+	/* Ensure sea-level FSMports do not flood */
+	if ((IsTileType(target, MP_STATION)))
+	{
+		if (GetStationByTile(target)->FSMport_flood_protected) return;
+	}
+
 	if (TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[1]))) != 0 ||
 			TileHeight(TILE_ADD(tile, ToTileIndexDiff(offs[2]))) != 0) {
 		return;