(svn r10879) [NewGRF_ports] -Feature: Added support for special orders, with addition of <data> byte in FSM command: NewGRF_ports
authorrichk
Mon, 13 Aug 2007 20:01:30 +0000
branchNewGRF_ports
changeset 6805 2b3ed8e47662
parent 6804 2772178ef0d7
child 6806 5ce9f2da4f0f
(svn r10879) [NewGRF_ports] -Feature: Added support for special orders, with addition of <data> byte in FSM command:
7B - force change of heading to <data>
7D - choose helipad from nominated group <data>
7E - choose terminal from nominated group <data>
-Change: Recoded terminal and helipad selection to default to All terms, or use the specific named one.
-Add: Added supporting function CanReserveBlocks. This has different logic to HasBlocks, where if the vehicle already owns some of the blocks, but the "missing" ones are free, then it can reserve those too. HasBlocks was all-or-fail.
-Change: updated airportsbasic.grf to match.
bin/data/airportsbasic.grf
bin/data/sprites/airportsbasic.nfo
src/aircraft_cmd.cpp
src/airport.h
src/fsmblockmap.h
src/newgrf.cpp
Binary file bin/data/airportsbasic.grf has changed
--- a/bin/data/sprites/airportsbasic.nfo	Mon Aug 13 09:21:57 2007 +0000
+++ b/bin/data/sprites/airportsbasic.nfo	Mon Aug 13 20:01:30 2007 +0000
@@ -484,7 +484,7 @@
 	// Large Airport : Position 03
 	\w56 \w20 \w0 02 \wx0007 02  // TERM2
 		04
-			02 02 42 05
+			02 02 00 05
 			41 7E 43 42 7F 02 05
 			51 7E 43 42 7F 02 05
 			40 42 00 05
@@ -492,7 +492,7 @@
 	// Large Airport : Position 04
 	\w38 \w8 \w0 03 \wx000B 03  // TERM3
 		04
-			03 03 42 05
+			03 03 00 05
 			41 7E 43 42 7F 03 05
 			51 7E 43 42 7F 03 05
 			40 42 00 05
@@ -500,8 +500,8 @@
 	// Large Airport : Position 05
 	\w65 \w6 \w0 00 \wx0000 42
 		03
-			02 02 00 03
-			03 03 00 04
+			02 02 42 03
+			03 03 42 04
 			00 42 00 06
 
 	// Large Airport : Position 06
@@ -517,7 +517,7 @@
 		05
 			01 01 42 02
 			41 43 42 08
-			51 00 42 16
+			51 00 00 16
 			40 42 00 01
 			00 42 00 06
 
@@ -551,7 +551,7 @@
 		03
 			7F 00 00 12
 			44 7E 45 44 40 7F 00 0E
-			54 00 00 17
+			54 44 00 17
 
 	// Large Airport : Position 0E
 	\w89 \w87 \w00 44 \wx0080 40  // LANDING
@@ -597,7 +597,7 @@
 	// Large Airport : Position 16
 	\w44 \w63 \w80 51 \wx0000 00  // HELITAKEOFF
 		01
-			00 00 00 00
+			00 00 42 00
 
 	// Large Airport : Position 17
 	\w28 \w74 \w80 54 \wx0030 44  // HELILANDING
--- a/src/aircraft_cmd.cpp	Mon Aug 13 09:21:57 2007 +0000
+++ b/src/aircraft_cmd.cpp	Mon Aug 13 20:01:30 2007 +0000
@@ -67,8 +67,8 @@
 static bool AirportMove(Vehicle *v, const AirportFTAClass *apc);
 static bool AirportSetBlocks(Vehicle *v, AirportFTA *current_pos, const AirportFTAClass *apc);
 static bool AirportHasBlock(Vehicle *v, AirportFTA *current_pos, const AirportFTAClass *apc);
-static bool AirportFindFreeTerminal(Vehicle *v, const AirportFTAClass *apc);
-static bool AirportFindFreeHelipad(Vehicle *v, const AirportFTAClass *apc);
+static bool AirportFindFreeTerminal(Vehicle *v, const AirportFTAClass *apc, const AirportFTA *current);
+static bool AirportFindFreeHelipad(Vehicle *v, const AirportFTAClass *apc, const AirportFTA *current);
 static void CrashAirplane(Vehicle *v);
 
 static void AircraftNextAirportPos_and_Order(Vehicle *v);
@@ -425,7 +425,6 @@
 
 			assert(i != apc->nof_depots);  //asserts if depot not found
 			if (st->airport_tile + ToTileIndexDiff(depots) == tile) {
-				assert(apc->layout[i].heading == HANGAR);
 
 				/* adjust all the initial position data by the orientation of the airport */
 				AirportMovingData amd = RotateAMDbyOrientation(*apc->MovingData(i), st->fsmportsspeclist[1].spec->size_x[st->FSMport_layout_set],
@@ -1632,9 +1631,9 @@
 		/* FindFreeTerminal:
 		 * 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal */
 		if (v->subtype == AIR_HELICOPTER) {
-			if (!AirportFindFreeHelipad(v, apc)) return; // helicopter
+			if (!AirportFindFreeHelipad(v, apc, NULL)) return; // helicopter
 		} else {
-			if (!AirportFindFreeTerminal(v, apc)) return; // airplane
+			if (!AirportFindFreeTerminal(v, apc, NULL)) return; // airplane
 		}
 	} else { // Else prepare for launch.
 		/* airplane goto state takeoff, helicopter to helitakeoff */
@@ -1829,9 +1828,9 @@
 	//if present, select terminal using that instruction, checking blocks first
 	//if not, continue with these default actions
 
-		if (AirportFindFreeTerminal(v, apc)) return;
+		if (AirportFindFreeTerminal(v, apc, &apc->layout[v->u.air.pos])) return;
 	}
-	v->u.air.state = HANGAR;
+	v->u.air.state = (apc->nof_depots != 0) ? HANGAR : TAKEOFF;
 
 }
 
@@ -1848,7 +1847,7 @@
 	 * the reason behind this is that if an airport has a terminal, it also has a hangar. Airplanes
 	 * must go to a hangar. */
 	if (v->current_order.type == OT_GOTO_STATION) {
-		if (AirportFindFreeHelipad(v, apc)) return;
+		if (AirportFindFreeHelipad(v, apc, NULL)) return;
 	}
 	v->u.air.state = (apc->nof_depots != 0) ? HANGAR : HELITAKEOFF;
 }
@@ -1949,9 +1948,31 @@
 	/* there are choices to choose from, choose the one that
 	 * matches our heading */
 	do {
-		if (v->u.air.state == current->heading || current->heading == TO_ALL) {
+		if (v->u.air.state == current->heading || current->heading == TO_ALL || (current->heading >= 0x7B && current->heading <= 0x7E)) {
 			if (st->airport_flags.BlocksAreFree(&current->reserveblock) ||      //if can reserve blocks
-				v->u.air.owned_blocks.HasBlocks(&current->reserveblock)) {      //or vehicle already has blocks
+				v->u.air.owned_blocks.CanReserveBlocks(&current->reserveblock, &st->airport_flags)) {      //or vehicle already has blocks
+
+					/* handle special commands */
+					if (current->heading == 0x7B) { //force change of heading
+						v->u.air.state = current->special;
+					}
+					if (current->heading == 0x7D) { //choose helipad
+						if (v->current_order.type == OT_GOTO_STATION) {
+							if (!AirportFindFreeHelipad(v, apc, current)) {
+								current = current->next;
+								continue;
+							}
+						}
+					}
+					if (current->heading == 0x7E) { //choose terminal
+						if (v->current_order.type == OT_GOTO_STATION) {
+							if (!AirportFindFreeTerminal(v, apc, current)) {
+								current = current->next;
+								continue;
+							}
+						}
+					}
+
 					/* release blocks on airport */
 					v->u.air.owned_blocks.ReleaseBlocks(&current->releaseblock);
 					st->airport_flags.ReleaseBlocks(&current->releaseblock);
@@ -2024,7 +2045,7 @@
 	return num;
 }
 
-static bool AirportFindFreeTerminal(Vehicle *v, const AirportFTAClass *apc)
+static bool AirportFindFreeTerminal(Vehicle *v, const AirportFTAClass *apc, const AirportFTA *current)
 {
 	/* example of more terminalgroups
 	 * {0,HANGAR,NOTHING_block,1}, {0,255,TERM_GROUP1_block,0}, {0,255,TERM_GROUP2_ENTER_block,1}, {0,0,N,1},
@@ -2038,28 +2059,29 @@
 	 */
 	if (apc->terminals[0] > 1) {
 		Station *st = GetStation(v->u.air.targetairport);
-		AirportFTA *temp = apc->layout[v->u.air.pos].next;
-
-		while (temp != NULL) {
-			if (temp->heading == 0x7E) {
-				if (!st->airport_flags.HasBlocks(&temp->reserveblock)) {
-					/* read which group do we want to go to?
-					 * (the first free group) */
-					uint target_group = temp->next_position + 1;
 
-					/* at what terminal does the group start?
-					 * that means, sum up all terminals of
-					 * groups with lower number */
-					uint group_start = 0;
-					for (uint i = 1; i < target_group; i++) {
-						group_start += apc->terminals[i];
-					}
+		/* forget any existing terminal reservations the aircraft has */
+		st->airport_flags.ReleaseLowerBlocks(&v->u.air.owned_blocks);
+		v->u.air.owned_blocks.ReleaseLowerBlocks(&v->u.air.owned_blocks);
 
-					uint group_end = group_start + apc->terminals[target_group];
-					if (FreeTerminal(v, group_start + 1, group_end)) return true;
-				}
+		if (current == NULL) {
+			/* choose from any terminal, no block restrictions */
+			return FreeTerminal(v, 1, GetNumTerminals(apc));
+		} else {
+			/* read which group do we want to go to?
+			 * (the first free group) */
+			uint target_group = current->special + 1;
+
+			/* at what terminal does the group start?
+			 * that means, sum up all terminals of
+			 * groups with lower number */
+			uint group_start = 0;
+			for (uint i = 1; i < target_group; i++) {
+				group_start += apc->terminals[i];
 			}
-			temp = temp->next;
+
+			uint group_end = group_start + apc->terminals[target_group];
+			if (FreeTerminal(v, group_start + 1, group_end)) return true;
 		}
 		return false;
 	}
@@ -2076,37 +2098,37 @@
 }
 
 
-static bool AirportFindFreeHelipad(Vehicle *v, const AirportFTAClass *apc)
+static bool AirportFindFreeHelipad(Vehicle *v, const AirportFTAClass *apc, const AirportFTA *current)
 {
 	/* if an airport doesn't have helipads, use terminals */
-	if (apc->helipads == NULL) return AirportFindFreeTerminal(v, apc);
+	if (apc->helipads == NULL) return AirportFindFreeTerminal(v, apc, current);
 
 	/* if there are more helicoptergroups, pick one, just as in AirportFindFreeTerminal() */
 	if (apc->helipads[0] > 1) {
 		Station* st = GetStation(v->u.air.targetairport);
-		AirportFTA* temp = apc->layout[v->u.air.pos].next;
-
-		while (temp != NULL) {
-			if (temp->heading == 0x7D) {
-				if (!st->airport_flags.HasBlocks(&temp->reserveblock)) {
-
-					/* read which group do we want to go to?
-					 * (the first free group) */
-					uint target_group = temp->next_position + 1;
 
-					/* at what terminal does the group start?
-					 * that means, sum up all terminals of
-					 * groups with lower number */
-					uint group_start = MAX_TERMINALS + 1;
-					for (uint i = 1; i < target_group; i++) {
-						group_start += apc->helipads[i];
-					}
+		/* forget any existing terminal reservations the aircraft has */
+		st->airport_flags.ReleaseLowerBlocks(&v->u.air.owned_blocks);
+		v->u.air.owned_blocks.ReleaseLowerBlocks(&v->u.air.owned_blocks);
 
-					uint group_end = group_start + apc->helipads[target_group];
-					if (FreeTerminal(v, group_start, group_end)) return true;
-				}
+		if (current == NULL) {
+			/* choose from any terminal, no block restrictions */
+			return FreeTerminal(v, 1, GetNumTerminals(apc));
+		} else {
+			/* read which group do we want to go to?
+			 * (the first free group) */
+			uint target_group = current->special + 1;
+
+			/* at what terminal does the group start?
+			 * that means, sum up all terminals of
+			 * groups with lower number */
+			uint group_start = MAX_TERMINALS + 1;
+			for (uint i = 1; i < target_group; i++) {
+				group_start += apc->helipads[i];
 			}
-			temp = temp->next;
+
+			uint group_end = group_start + apc->helipads[target_group];
+			if (FreeTerminal(v, group_start + 1, group_end)) return true;
 		}
 		return false;
 	} else {
--- a/src/airport.h	Mon Aug 13 09:21:57 2007 +0000
+++ b/src/airport.h	Mon Aug 13 20:01:30 2007 +0000
@@ -100,6 +100,7 @@
 	byte position;           // the position that an airplane is at
 	byte next_position;      // next position from this position
 	byte heading;            // heading (current orders), guiding an airplane to its target on an airport
+	byte special;            // used as extra data for special orders 7B, 7C, 7D, 7E
 };
 
 void InitializeAirports();
--- a/src/fsmblockmap.h	Mon Aug 13 09:21:57 2007 +0000
+++ b/src/fsmblockmap.h	Mon Aug 13 20:01:30 2007 +0000
@@ -69,6 +69,12 @@
 		blocks[1] &= ~blockmap->GetUpper();
 	}
 
+	void inline ReleaseLowerBlocks(const FSMblockmap *blockmap)
+	{
+		/* used to forget any existing terminal reservations */
+		blocks[0] &= ~blockmap->GetLower();
+	}
+
 	bool inline BlocksAreFree(const FSMblockmap *blockmap) const
 	{
 		uint64 test_lower = blockmap->GetLower();
@@ -80,6 +86,18 @@
 		return true;
 	}
 
+	bool inline CanReserveBlocks(const FSMblockmap *wantedblockmap, const FSMblockmap *currentblockmap) const
+	{
+		/* currentblockmap->BlocksAreFree((blocks XOR wanted) AND wanted) */
+		uint64 test_lower = (blocks[0] ^ wantedblockmap->GetLower()) & wantedblockmap->GetLower();
+		uint64 test_upper = (blocks[1] ^ wantedblockmap->GetUpper()) & wantedblockmap->GetUpper();
+
+		if ((~currentblockmap->GetLower() & test_lower) != test_lower)  return false;
+		if ((~currentblockmap->GetUpper() & test_upper) != test_upper)  return false;
+
+		return true;
+	}
+
 	bool inline HasBlocks(const FSMblockmap *blockmap) const
 	{
 		uint64 test_lower = blockmap->GetLower();
--- a/src/newgrf.cpp	Mon Aug 13 09:21:57 2007 +0000
+++ b/src/newgrf.cpp	Mon Aug 13 20:01:30 2007 +0000
@@ -2292,6 +2292,9 @@
 					AirportFTA *current = &fsmportspec->portFSM->layout[element];
 					current->position = element;
 					current->heading = grf_load_byte(&buf);
+					if (current->heading >= 0x7B && current->heading <= 0x7E) { //read special byte
+						current->special = grf_load_byte(&buf);
+					}
 					ReadBlocksInto(&current->reserveblock, &buf);
 					ReadBlocksInto(&current->releaseblock, &buf);
 					current->next_position = grf_load_byte(&buf);
@@ -2301,6 +2304,9 @@
 						AirportFTA *newNode = MallocT<AirportFTA>(1);
 						newNode->position = element;
 						newNode->heading = grf_load_byte(&buf);
+						if (newNode->heading >= 0x7B && newNode->heading <= 0x7E) { //read special byte
+							newNode->special = grf_load_byte(&buf);
+						}
 
 						ReadBlocksInto(&newNode->reserveblock, &buf);
 						ReadBlocksInto(&newNode->releaseblock, &buf);