(svn r2255) - Fix: [ 9680363 ] [NPF] Broken buoy handling for ships
authormatthijs
Mon, 02 May 2005 22:13:20 +0000
changeset 1751 009a240d035a
parent 1750 4590f0ae89a5
child 1752 d65cd19f7117
(svn r2255) - Fix: [ 9680363 ] [NPF] Broken buoy handling for ships
Buoys will now try to get within 3 tiles of a buoy instead of a the actual buoy tile. This gets ships to got past buoys in a realistic (IMO) way instead of barging right through them.
- Fix: [NPF] Trains get curves penalties sometimes even when the track is straight.
- Add: [NPF] Ships get a penalty for going over buoys now, so they will try to go around.
- Add: [NPF] Ships get a penalty for curves too, yay for straight lines.
- Add: TrackdirToTrack(), TrackToTrackdir(), IsDiagonalTrack() and IsDiagonalTrackdir() helper functions.
- Add: IsBuoy() and IsBuoyTile() helper functions.
- Codechange: Rearranged part of the control flow of ShipController(), removing a goto.
npf.c
npf.h
order_cmd.c
settings.c
ship_cmd.c
ship_gui.c
station.h
station_cmd.c
variables.h
--- a/npf.c	Mon May 02 21:56:01 2005 +0000
+++ b/npf.c	Mon May 02 22:13:20 2005 +0000
@@ -36,6 +36,11 @@
 	0x0520, 0x2A00, 0x2A00, 0x0520, 0x2A00, 0x1009
 };
 
+const uint16 _next_trackdir[14] = {
+	0,  1,  3,  2,  5,  4, 0, 0,
+	8,  9,  11, 10, 13, 12
+};
+
 /* Maps a trackdir to all trackdirs that make 90 deg turns with it. */
 const uint16 _trackdir_crosses_trackdirs[14] = {
 	0x0202, 0x0101, 0x3030, 0x3030, 0x0C0C, 0x0C0C, 0, 0,
@@ -273,7 +278,13 @@
 
 	cost = _trackdir_length[trackdir]; /* Should be different for diagonal tracks */
 
-	/* TODO Penalties? */
+	if (IsBuoyTile(current->tile) && IsDiagonalTrackdir(current->direction))
+		cost += _patches.npf_buoy_penalty; /* A small penalty for going over buoys */
+
+	if (current->direction != _next_trackdir[parent->path.node.direction])
+		cost += _patches.npf_water_curve_penalty;
+
+	/* TODO More penalties? */
 
 	return cost;
 }
@@ -385,7 +396,7 @@
 	cost += NPFSlopeCost(current);
 
 	/* Check for turns */
-	if (current->direction != parent->path.node.direction)
+	if (current->direction != _next_trackdir[parent->path.node.direction])
 		cost += _patches.npf_rail_curve_penalty;
 	//TODO, with realistic acceleration, also the amount of straight track between
 	//      curves should be taken into account, as this affects the speed limit.
--- a/npf.h	Mon May 02 21:56:01 2005 +0000
+++ b/npf.h	Mon May 02 22:13:20 2005 +0000
@@ -118,6 +118,11 @@
 const uint16 _trackdir_reaches_trackdirs[14];
 
 /**
+ * Maps a trackdir to the trackdir that you will end up on if you go straight
+ * ahead. This will be the same trackdir for diagonal trackdirs, but a
+ * different (alternating) one for straight trackdirs */
+const uint16 _next_trackdir[14];
+/**
  * Maps a trackdir to all trackdirs that make 90 deg turns with it.
  */
 const uint16 _trackdir_crosses_trackdirs[14];
@@ -161,6 +166,23 @@
  */
 const byte _reverse_trackdir[14];
 
+/* Returns the Track that a given Trackdir represents */
+static inline byte TrackdirToTrack(byte trackdir) { return trackdir & 0x7; }
+
+/* Returns a Trackdir for the given Track. Since every Track corresponds to
+ * two Trackdirs, we choose the one which points between N and SE.
+ * Note that the actual implementation is quite futile, but this might change
+ * in the future.
+ */
+static inline byte TrackToTrackdir(byte track) { return track; }
+
+/* Checks if a given Track is diagonal */
+static inline bool IsDiagonalTrack(byte track) { return track == 0x0 || track == 0x1; }
+
+/* Checks if a given Trackdir is diagonal. */
+static inline bool IsDiagonalTrackdir(byte trackdir) { return IsDiagonalTrack(TrackdirToTrack(trackdir)); }
+
+
 #define REVERSE_TRACKDIR(trackdir) (trackdir ^ 0x8)
 
 #endif // NPF_H
--- a/order_cmd.c	Mon May 02 21:56:01 2005 +0000
+++ b/order_cmd.c	Mon May 02 22:13:20 2005 +0000
@@ -166,7 +166,7 @@
 			st = GetStation(new_order.station);
 
 			if (!IsValidStation(st) ||
-					(st->airport_type != AT_OILRIG && !(st->had_vehicle_of_type & HVOT_BUOY) && !CheckOwnership(st->owner))) {
+					(st->airport_type != AT_OILRIG && !(IsBuoy(st)) && !CheckOwnership(st->owner))) {
 				return CMD_ERROR;
 			}
 
--- a/settings.c	Mon May 02 21:56:01 2005 +0000
+++ b/settings.c	Mon May 02 22:13:20 2005 +0000
@@ -944,8 +944,8 @@
 	* penalty will further prevent this.
 	* We give presignal exits (and combo's) a different (larger) penalty, because we really
 	* don't want trains waiting in front of a presignal exit. */
-	{"npf_rail_firstred_penalty",   SDT_UINT32, (void*)(10 * NPF_TILE_LENGTH),  &_patches.npf_rail_firstred_penalty,		NULL},
-	{"npf_rail_firstred_exit_penalty", SDT_UINT32, (void*)(100 * NPF_TILE_LENGTH),	&_patches.npf_rail_firstred_exit_penalty,		NULL},
+	{"npf_rail_firstred_penalty",   SDT_UINT32, (void*)(10 * NPF_TILE_LENGTH),  &_patches.npf_rail_firstred_penalty,    NULL},
+	{"npf_rail_firstred_exit_penalty", SDT_UINT32, (void*)(100 * NPF_TILE_LENGTH), &_patches.npf_rail_firstred_exit_penalty, NULL},
 	/* This penalty is for when the last signal before the target is red.
 	 * This is useful for train stations, where there are multiple
 	 * platforms to choose from, which lie in different signal blocks.
@@ -960,11 +960,19 @@
 	* a penalty of 1 tile for every station tile passed, the route will
 	* be around it.
 	*/
-	{"npf_rail_station_penalty",    SDT_UINT32, (void*)(1 * NPF_TILE_LENGTH),   &_patches.npf_rail_station_penalty, 		NULL},
-	{"npf_rail_slope_penalty",      SDT_UINT32, (void*)(1 * NPF_TILE_LENGTH),   &_patches.npf_rail_slope_penalty,				NULL},
-	{"npf_rail_curve_penalty",      SDT_UINT32, (void*)(1),                     &_patches.npf_rail_curve_penalty,				NULL},
+	{"npf_rail_station_penalty",    SDT_UINT32, (void*)(1 * NPF_TILE_LENGTH),   &_patches.npf_rail_station_penalty,     NULL},
+	{"npf_rail_slope_penalty",      SDT_UINT32, (void*)(1 * NPF_TILE_LENGTH),   &_patches.npf_rail_slope_penalty,       NULL},
+	/* This penalty is applied when a train makes a turn. Its value of 1 makes
+	 * sure that it has a minimal impact on the pathfinding, only when two
+	 * paths have equal length it will make a difference */
+	{"npf_rail_curve_penalty",      SDT_UINT32, (void*)(1),                     &_patches.npf_rail_curve_penalty,       NULL},
+	{"npf_buoy_penalty",            SDT_UINT32, (void*)(2 * NPF_TILE_LENGTH),   &_patches.npf_buoy_penalty,             NULL},
+	/* This penalty is applied when a ship makes a turn. It is bigger than the
+	 * rail curve penalty, since ships (realisticly) have more trouble with
+	 * making turns */
+	{"npf_water_curve_penalty",     SDT_UINT32, (void*)(NPF_TILE_LENGTH / 4),   &_patches.npf_water_curve_penalty,      NULL},
 
-	{NULL,									0,					NULL,					NULL,																						NULL}
+	{NULL,                          0,          NULL,                           NULL,                                   NULL}
 };
 
 static const SettingDesc currency_settings[] = {
--- a/ship_cmd.c	Mon May 02 21:56:01 2005 +0000
+++ b/ship_cmd.c	Mon May 02 22:13:20 2005 +0000
@@ -714,46 +714,58 @@
 			r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
 			if (r & 0x8) goto reverse_direction;
 
-			if (v->dest_tile != 0 && v->dest_tile == gp.new_tile) {
-				if (v->current_order.type == OT_GOTO_DEPOT) {
-					if ((gp.x&0xF)==8 && (gp.y&0xF)==8) {
-						ShipEnterDepot(v);
-						return;
-					}
-				} else if (v->current_order.type == OT_GOTO_STATION) {
-					Station *st;
-
-					v->last_station_visited = v->current_order.station;
-
-					/* Process station in the orderlist. Don't do that for buoys (HVOT_BUOY) */
-					st = GetStation(v->current_order.station);
-					if (!(st->had_vehicle_of_type & HVOT_BUOY)
-							&& (st->facilities & FACIL_DOCK)) { /* ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations */
-						v->current_order.type = OT_LOADING;
-						v->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD;
-						v->current_order.flags |= OF_NON_STOP;
-						ShipArrivesAt(v, st);
-
-						SET_EXPENSES_TYPE(EXPENSES_SHIP_INC);
-						if (LoadUnloadVehicle(v)) {
-							InvalidateWindow(WC_SHIPS_LIST, v->owner);
-							MarkShipDirty(v);
-						}
-						InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-					} else { /* leave buoys right aways */
-						v->current_order.type = OT_LEAVESTATION;
-						v->current_order.flags = 0;
-						v->cur_order_index++;
-						InvalidateVehicleOrder(v);
-					}
-					goto else_end;
-				}
-			}
-
+			/* A leave station order only needs one tick to get processed, so we can
+			 * always skip ahead. */
 			if (v->current_order.type == OT_LEAVESTATION) {
 				v->current_order.type = OT_NOTHING;
 				v->current_order.flags = 0;
 				InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+			} else if (v->dest_tile != 0) {
+				/* We have a target, let's see if we reached it... */
+				if (v->current_order.type == OT_GOTO_STATION &&
+						IsBuoyTile(v->dest_tile) &&
+						DistanceManhattan(v->dest_tile, gp.new_tile) <= 3) {
+					/* We got within 3 tiles of our target buoy, so let's skip to our
+					 * next order */
+					v->cur_order_index++;
+					v->current_order.type = OT_DUMMY;
+					InvalidateVehicleOrder(v);
+				} else {
+					/* Non-buoy orders really need to reach the tile */
+					if (v->dest_tile == gp.new_tile) {
+						if (v->current_order.type == OT_GOTO_DEPOT) {
+							if ((gp.x&0xF)==8 && (gp.y&0xF)==8) {
+								ShipEnterDepot(v);
+								return;
+							}
+						} else if (v->current_order.type == OT_GOTO_STATION) {
+							Station *st;
+
+							v->last_station_visited = v->current_order.station;
+
+							/* Process station in the orderlist. */
+							st = GetStation(v->current_order.station);
+							if (st->facilities & FACIL_DOCK) { /* ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations */
+								v->current_order.type = OT_LOADING;
+								v->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD;
+								v->current_order.flags |= OF_NON_STOP;
+								ShipArrivesAt(v, st);
+
+								SET_EXPENSES_TYPE(EXPENSES_SHIP_INC);
+								if (LoadUnloadVehicle(v)) {
+									InvalidateWindow(WC_SHIPS_LIST, v->owner);
+									MarkShipDirty(v);
+								}
+								InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+							} else { /* leave stations without docks right aways */
+								v->current_order.type = OT_LEAVESTATION;
+								v->current_order.flags = 0;
+								v->cur_order_index++;
+								InvalidateVehicleOrder(v);
+							}
+						}
+					}
+				}
 			}
 		}
 	} else {
@@ -789,7 +801,6 @@
 
 		v->direction = b[2];
 	}
-else_end:;
 
 	/* update image of ship, as well as delta XY */
 	dir = ShipGetNewDirection(v, gp.x, gp.y);
--- a/ship_gui.c	Mon May 02 21:56:01 2005 +0000
+++ b/ship_gui.c	Mon May 02 22:13:20 2005 +0000
@@ -890,7 +890,7 @@
 		sel--;
 
 		if (order->type == OT_GOTO_STATION) {
-			if (!(GetStation(order->station)->had_vehicle_of_type & HVOT_BUOY)) {
+			if (!IsBuoy(GetStation(order->station))){
 				SetDParam(0, order->station);
 				DrawString(x, y, STR_A036, 0);
 
--- a/station.h	Mon May 02 21:56:01 2005 +0000
+++ b/station.h	Mon May 02 22:13:20 2005 +0000
@@ -103,6 +103,8 @@
 	HVOT_TRUCK = 1 << 3,
 	HVOT_AIRCRAFT = 1 << 4,
 	HVOT_SHIP = 1 << 5,
+	/* This bit is used to mark stations. No, it does not belong here, but what
+	 * can we do? ;-) */
 	HVOT_BUOY = 1 << 6
 };
 
@@ -290,7 +292,7 @@
 		(_map5[tile] & 0x01) == (_map5[ref] & 0x01); // same direction?
 }
 
-static inline bool IsRoadStationTile(uint tile) {
+static inline bool IsRoadStationTile(TileIndex tile) {
 	return IsTileType(tile, MP_STATION) && IS_BYTE_INSIDE(_map5[tile], 0x43, 0x4B);
 }
 
@@ -302,6 +304,15 @@
 	return st->xy != 0; /* XXX: Replace by INVALID_TILE someday */
 }
 
+static inline bool IsBuoy(const Station* st)
+{
+	return st->had_vehicle_of_type & HVOT_BUOY; /* XXX: We should really ditch this ugly coding and switch to something sane... */
+}
+
+static inline bool IsBuoyTile(TileIndex tile) {
+	return IsTileType(tile, MP_STATION) && _map5[tile] == 0x52;
+}
+
 /* Get's the direction the station exit points towards. Ie, returns 0 for a
  * station with the exit NE. */
 static inline byte GetRoadStationDir(uint tile) {
--- a/station_cmd.c	Mon May 02 21:56:01 2005 +0000
+++ b/station_cmd.c	Mon May 02 22:13:20 2005 +0000
@@ -642,7 +642,7 @@
 	rect.min_y = MapSizeY();
 	rect.max_x = rect.max_y = 0;
 	// Don't update acceptance for a buoy
-	if (st->had_vehicle_of_type & HVOT_BUOY)
+	if (IsBuoy(st))
 		return;
 
 	/* old accepted goods types */
@@ -1855,6 +1855,8 @@
 		StationInitialize(st, ti.tile);
 		st->dock_tile = ti.tile;
 		st->facilities |= FACIL_DOCK;
+		/* Buoys are marked in the Station struct by this flag. Yes, it is this
+		 * braindead.. */
 		st->had_vehicle_of_type |= HVOT_BUOY;
 		st->owner = OWNER_NONE;
 
@@ -1913,6 +1915,8 @@
 
 	if (flags & DC_EXEC) {
 		st->dock_tile = 0;
+		/* Buoys are marked in the Station struct by this flag. Yes, it is this
+		 * braindead.. */
 		st->facilities &= ~FACIL_DOCK;
 		st->had_vehicle_of_type &= ~HVOT_BUOY;
 
@@ -2706,7 +2710,7 @@
 			for(i=0; i!=8; i++)	{
 				if (around[i] == INVALID_STATION) {
 					st = GetStation(st_index);
-					if ((st->had_vehicle_of_type & HVOT_BUOY) == 0 &&
+					if (!IsBuoy(st) &&
 							( !st->town->exclusive_counter || (st->town->exclusivity == st->owner) ) && // check exclusive transport rights
 							st->goods[type].rating != 0 &&
 							(!_patches.selectgoods || st->goods[type].last_speed) && // if last_speed is 0, no vehicle has been there.
--- a/variables.h	Mon May 02 21:56:01 2005 +0000
+++ b/variables.h	Mon May 02 22:13:20 2005 +0000
@@ -211,6 +211,8 @@
 	uint32 npf_rail_station_penalty; /* The penalty for station tiles */
 	uint32 npf_rail_slope_penalty; /* The penalty for sloping upwards */
 	uint32 npf_rail_curve_penalty; /* The penalty for curves */
+	uint32 npf_buoy_penalty; /* The penalty for going over (through) a buoy */
+	uint32 npf_water_curve_penalty; /* The penalty for curves */
 
 	bool population_in_label; // Show the population of a town in his label?
 } Patches;