(svn r4259) -[multistop] Fix/Feature/Codechange:
authorcelestar
Mon, 03 Apr 2006 14:25:32 +0000
changeset 3431 0d7fa19d0b4a
parent 3430 b283bb956a36
child 3432 507fa7fd189d
(svn r4259) -[multistop] Fix/Feature/Codechange:
1) Improved the road vehicle allocation (aka slotting) for multistop. Stops can now accept unlimited, er... 256, vehicles.
2) Removed the "wait for stop" feature, because it did not work in practise.
3) Slotting now ignores unreachable stations. Uses NPF at the moment because the old pathfinder cannot do it (yet)
4) Now matter how many vehicles approach a station, they will always be distributed evenly over existing stops.
5) Hopefully the last fundamental change to multistop
console_cmds.c
lang/english.txt
oldloader.c
openttd.c
roadveh_cmd.c
roadveh_gui.c
saveload.c
station.h
station_cmd.c
vehicle.c
vehicle.h
--- a/console_cmds.c	Mon Apr 03 13:35:19 2006 +0000
+++ b/console_cmds.c	Mon Apr 03 14:25:32 2006 +0000
@@ -92,30 +92,6 @@
 	IConsolePrintF(_icolour_warn, "- %s", str);
 }
 
-DEF_CONSOLE_CMD(ConResetSlots)
-{
-	Vehicle *v;
-	RoadStop *rs;
-	if (argc == 0) {
-		IConsoleHelp("Resets all slots in the game. For debugging only. Usage: 'clearslots'");
-		return true;
-	}
-
-	FOR_ALL_VEHICLES(v) {
-		if (IsValidVehicle(v)) {
-			if (v->type == VEH_Road)
-				ClearSlot(v);
-		}
-	}
-
-	FOR_ALL_ROADSTOPS(rs) {
-		int i;
-		for (i = 0; i < NUM_SLOTS; i++) rs->slot[i] = INVALID_VEHICLE;
-	}
-
-	return true;
-}
-
 DEF_CONSOLE_CMD(ConStopAllVehicles)
 {
 	Vehicle* v;
@@ -1389,7 +1365,6 @@
 	IConsoleCmdRegister("cd",           ConChangeDirectory);
 	IConsoleCmdRegister("pwd",          ConPrintWorkingDirectory);
 	IConsoleCmdRegister("clear",        ConClearBuffer);
-	IConsoleCmdRegister("clearslots",   ConResetSlots);
 	IConsoleCmdRegister("stopall",      ConStopAllVehicles);
 
 	IConsoleAliasRegister("dir",      "ls");
--- a/lang/english.txt	Mon Apr 03 13:35:19 2006 +0000
+++ b/lang/english.txt	Mon Apr 03 14:25:32 2006 +0000
@@ -2494,7 +2494,6 @@
 STR_8861_STOPPED                                                :{RED}Stopped
 STR_8862_CAN_T_MAKE_TRAIN_PASS_SIGNAL                           :{WHITE}Can't make train pass signal at danger...
 STR_8863_CRASHED                                                :{RED}Crashed!
-STR_8864_WAIT_FOR_SLOT                                          :{YELLOW}Waiting for a free stop
 
 STR_8865_NAME_TRAIN                                             :{WHITE}Name train
 STR_8866_CAN_T_NAME_TRAIN                                       :{WHITE}Can't name train...
--- a/oldloader.c	Mon Apr 03 13:35:19 2006 +0000
+++ b/oldloader.c	Mon Apr 03 14:25:32 2006 +0000
@@ -356,7 +356,6 @@
 static void FixOldStations(void)
 {
 	Station *st;
-	int i;
 
 	FOR_ALL_STATIONS(st) {
 		/* Check if we need to swap width and height for the station */
@@ -373,7 +372,7 @@
 			st->bus_stops->station = st->index;
 			st->bus_stops->next = NULL;
 			st->bus_stops->prev = NULL;
-			for (i = 0; i < NUM_SLOTS; i++) st->bus_stops->slot[i] = INVALID_VEHICLE;
+			st->bus_stops->num_vehicles = 0;
 		}
 
 		if (st->lorry_tile_obsolete != 0) {
@@ -384,7 +383,7 @@
 			st->truck_stops->station = st->index;
 			st->truck_stops->next = NULL;
 			st->truck_stops->prev = NULL;
-			for (i = 0; i < NUM_SLOTS; i++) st->truck_stops->slot[i] = INVALID_VEHICLE;
+			st->truck_stops->num_vehicles = 0;
 		}
 	}
 }
--- a/openttd.c	Mon Apr 03 13:35:19 2006 +0000
+++ b/openttd.c	Mon Apr 03 14:25:32 2006 +0000
@@ -1391,6 +1391,17 @@
 
 	if (CheckSavegameVersion(22))  UpdatePatches();
 
+	if (CheckSavegameVersion(25)) {
+		Vehicle *v;
+		FOR_ALL_VEHICLES(v) {
+			if (v->type == VEH_Road) {
+				v->vehstatus &= ~0x40;
+				v->u.road.slot = NULL;
+				v->u.road.slot_age = 0;
+			}
+		}
+	}
+
 	FOR_ALL_PLAYERS(p) p->avail_railtypes = GetPlayerRailtypes(p->index);
 
 	return true;
--- a/roadveh_cmd.c	Mon Apr 03 13:35:19 2006 +0000
+++ b/roadveh_cmd.c	Mon Apr 03 14:25:32 2006 +0000
@@ -1,5 +1,6 @@
 /* $Id$ */
 
+#include <limits.h>
 #include "stdafx.h"
 #include "openttd.h"
 #include "debug.h"
@@ -164,10 +165,6 @@
 //	v->u.road.unk2 = 0;
 //	v->u.road.overtaking = 0;
 
-		v->u.road.slot = NULL;
-		v->u.road.slotindex = 0;
-		v->u.road.slot_age = 0;
-
 		v->last_station_visited = INVALID_STATION;
 		v->max_speed = rvi->max_speed;
 		v->engine_type = (byte)p1;
@@ -238,10 +235,10 @@
 	v->u.road.slot = NULL;
 	v->u.road.slot_age = 0;
 
-	// check that the slot is indeed assigned to the same vehicle
-	assert(rs->slot[v->u.road.slotindex] == v->index);
-	rs->slot[v->u.road.slotindex] = INVALID_VEHICLE;
-	DEBUG(ms, 3) ("Multistop: Clearing slot %d at 0x%x", v->u.road.slotindex, rs->xy);
+	assert(rs->num_vehicles != 0);
+	rs->num_vehicles--;
+
+	DEBUG(ms, 3) ("Multistop: Clearing slot at 0x%x", rs->xy);
 }
 
 /** Sell a road vehicle.
@@ -382,7 +379,6 @@
 
 	if (flags & DC_EXEC) {
 		ClearSlot(v);
-		v->vehstatus &= ~VS_WAIT_FOR_SLOT;
 		v->current_order.type = OT_GOTO_DEPOT;
 		v->current_order.flags = OF_NON_STOP | OF_HALT_IN_DEPOT;
 		v->current_order.station = dep->index;
@@ -408,7 +404,7 @@
 
 	if (v->type != VEH_Road || !CheckOwnership(v->owner)) return CMD_ERROR;
 
-	if (v->vehstatus & (VS_HIDDEN | VS_STOPPED | VS_WAIT_FOR_SLOT) ||
+	if (v->vehstatus & (VS_HIDDEN | VS_STOPPED) ||
 			v->u.road.crashed_ctr != 0 ||
 			v->breakdown_ctr != 0 ||
 			v->u.road.overtaking != 0 ||
@@ -633,7 +629,6 @@
 		v->current_order.flags = 0;
 		v->dest_tile = 0;
 		ClearSlot(v);
-		v->vehstatus &= ~VS_WAIT_FOR_SLOT;
 		return;
 	}
 
@@ -645,8 +640,6 @@
 
 	v->current_order = *order;
 	v->dest_tile = 0;
-	/* We have changed the destination STATION, so resume movement */
-	v->vehstatus &= ~VS_WAIT_FOR_SLOT;
 
 	if (order->type == OT_GOTO_STATION) {
 		const Station* st = GetStation(order->station);
@@ -907,7 +900,7 @@
 	od.u = u;
 
 	if (u->max_speed >= v->max_speed &&
-			!(u->vehstatus & (VS_STOPPED | VS_WAIT_FOR_SLOT)) &&
+			!(u->vehstatus & VS_STOPPED) &&
 			u->cur_speed != 0) {
 		return;
 	}
@@ -929,7 +922,7 @@
 	od.tile = v->tile + TileOffsByDir(DirToDiagDir(v->direction));
 	if (FindRoadVehToOvertake(&od)) return;
 
-	if (od.u->cur_speed == 0 || od.u->vehstatus& (VS_STOPPED | VS_WAIT_FOR_SLOT)) {
+	if (od.u->cur_speed == 0 || od.u->vehstatus& VS_STOPPED) {
 		v->u.road.overtaking_ctr = 0x11;
 		v->u.road.overtaking = 0x10;
 	} else {
@@ -1133,7 +1126,6 @@
 	return best_track;
 }
 
-#if 0 /* Commented out until NPF works properly here */
 static uint RoadFindPathToStop(const Vehicle *v, TileIndex tile)
 {
 	NPFFindStationOrTileData fstd;
@@ -1145,7 +1137,6 @@
 
 	return NPFRouteToStationOrTile(v->tile, trackdir, &fstd, TRANSPORT_ROAD, v->owner, INVALID_RAILTYPE).best_path_dist;
 }
-#endif
 
 typedef struct RoadDriveEntry {
 	byte x,y;
@@ -1191,7 +1182,7 @@
 		v->breakdown_ctr--;
 	}
 
-	if (v->vehstatus & (VS_STOPPED | VS_WAIT_FOR_SLOT)) return;
+	if (v->vehstatus & VS_STOPPED) return;
 
 	ProcessRoadVehOrder(v);
 	HandleRoadVehLoading(v);
@@ -1454,7 +1445,6 @@
 			v->current_order.type = OT_NOTHING;
 			v->current_order.flags = 0;
 			ClearSlot(v);
-			v->vehstatus &= ~VS_WAIT_FOR_SLOT;
 		}
 		SETBIT(rs->status, 7);
 
@@ -1560,7 +1550,7 @@
 
 	if (_patches.servint_roadveh == 0) return;
 	if (!VehicleNeedsService(v)) return;
-	if (v->vehstatus & (VS_STOPPED | VS_WAIT_FOR_SLOT)) return;
+	if (v->vehstatus & VS_STOPPED) return;
 	if (_patches.gotodepot && VehicleHasDepotOrders(v)) return;
 
 	// Don't interfere with a depot visit scheduled by the user, or a
@@ -1610,82 +1600,57 @@
 	CheckOrders(v);
 
 	//Current slot has expired
-	if (v->u.road.slot_age-- == 0 && v->u.road.slot != NULL) {
-		DEBUG(ms, 2) ("Multistop: Slot %d expired for vehicle %d (index %d) at stop 0x%x",
-			v->u.road.slotindex, v->unitnumber, v->index, v->u.road.slot->xy
-		);
+	if (v->current_order.type == OT_GOTO_STATION && v->u.road.slot_age-- == 0 && v->u.road.slot != NULL) {
+		DEBUG(ms, 2) ("Multistop: Slot expired for vehicle %d (index %d) at stop 0x%x",
+			v->unitnumber, v->index, v->u.road.slot->xy);
 		ClearSlot(v);
 	}
 
 	if (v->vehstatus & VS_STOPPED) return;
 
 	/* update destination */
-	if (v->current_order.type == OT_GOTO_STATION &&
-			v->u.road.slot == NULL &&
-			!IsLevelCrossing(v->tile) &&
-			v->u.road.overtaking == 0 &&
-			!(v->vehstatus & VS_CRASHED)) {
-		RoadStopType type = (v->cargo_type == CT_PASSENGERS) ? RS_BUS : RS_TRUCK;
+	if (v->current_order.type == OT_GOTO_STATION && v->u.road.slot == NULL && !(v->vehstatus & VS_CRASHED)) {
 		RoadStop *rs;
-		uint mindist = 0xFFFFFFFF;
-		int i;
-		RoadStop *nearest = NULL;
+		RoadStop *best = NULL;
 
 		st = GetStation(v->current_order.station);
-		rs = GetPrimaryRoadStop(st, type);
+		rs = GetPrimaryRoadStop(st, v->cargo_type == CT_PASSENGERS ? RS_BUS : RS_TRUCK);
 
 		if (rs != NULL) {
 			if (DistanceManhattan(v->tile, st->xy) < 16) {
-				int new_slot = -1;
+				uint dist, badness;
+				uint minbadness = UINT_MAX;
 
 				DEBUG(ms, 2) ("Multistop: Attempting to obtain a slot for vehicle %d (index %d) at station %d (0x%x)", v->unitnumber,
 						v->index, st->index, st->xy);
 				/* Now we find the nearest road stop that has a free slot */
-				for (i = 0; rs != NULL; rs = rs->next, i++) {
-					uint dist = 0xFFFFFFFF;
-					bool is_slot_free = false;
-					int k;
-					int last_free = -1;
-
-					for (k = 0; k < NUM_SLOTS; k++)
-						if (rs->slot[k] == INVALID_VEHICLE) {
-							is_slot_free = true;
-							last_free = k;
-							dist = DistanceManhattan(v->tile, st->xy);
-							break;
-						}
-
-					if (!is_slot_free) {
-						DEBUG(ms, 4) ("Multistop: ---- stop %d is full", i);
+				for (; rs != NULL; rs = rs->next) {
+					dist = RoadFindPathToStop(v, rs->xy);
+					if (dist == UINT_MAX) {
+						DEBUG(ms, 4) (" ---- stop 0x%x is not reachable, not treating further", rs->xy);
 						continue;
 					}
+					badness = (rs->num_vehicles + 1) * (rs->num_vehicles + 1) + dist / NPF_TILE_LENGTH;
 
-					DEBUG(ms, 4) ("Multistop: ---- distance to stop %d is %d", i, dist);
-					if (dist < mindist) {
-						nearest = rs;
-						mindist = dist;
-						new_slot = last_free;
+					DEBUG(ms, 4) (" ---- stop 0x%x has %d vehicle%s waiting", rs->xy, rs->num_vehicles, rs->num_vehicles == 1 ? "":"s");
+					DEBUG(ms, 4) (" ---- Distance is %u", dist);
+					DEBUG(ms, 4) (" -- Badness %u", badness);
+
+					if (badness < minbadness) {
+						best = rs;
+						minbadness = badness;
 					}
 				}
 
-				if (nearest != NULL) { /* We have a suitable stop */
-					DEBUG(ms, 3) ("Multistop: -- Slot %d of stop at 0x%x assinged.", new_slot, nearest->xy);
-					nearest->slot[new_slot] = v->index;
-
-					v->u.road.slot = nearest;
-					v->dest_tile = nearest->xy;
-					v->u.road.slot_age = 14;
-					v->u.road.slotindex = new_slot;
+				if (best != NULL) {
+					best->num_vehicles++;
+					DEBUG(ms, 3) (" -- Assigned to stop 0x%x", best->xy);
 
-					if (v->vehstatus & VS_WAIT_FOR_SLOT) {
-						DEBUG(ms, 4) ("Multistop: ---- stopped vehicle got a slot. resuming movement");
-						v->vehstatus &= ~VS_WAIT_FOR_SLOT;
-						InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
-					}
+					v->u.road.slot = best;
+					v->dest_tile = best->xy;
+					v->u.road.slot_age = 14;
 				} else {
-					DEBUG(ms, 2) ("Multistop -- No free slot at station. Waiting");
-					v->vehstatus |= VS_WAIT_FOR_SLOT;
-					InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
+					DEBUG(ms, 3) (" -- Could not find a suitable stop");
 				}
 			} else {
 				DEBUG(ms, 5) ("Multistop: --- Distance from station too far. Postponing slotting for vehicle %d (index %d) at station %d, (0x%x)",
--- a/roadveh_gui.c	Mon Apr 03 13:35:19 2006 +0000
+++ b/roadveh_gui.c	Mon Apr 03 14:25:32 2006 +0000
@@ -247,8 +247,6 @@
 			str = STR_885C_BROKEN_DOWN;
 		} else if (v->vehstatus & VS_STOPPED) {
 			str = STR_8861_STOPPED;
-		} else if (v->vehstatus & VS_WAIT_FOR_SLOT) {
-			str = STR_8864_WAIT_FOR_SLOT;
 		} else {
 			switch (v->current_order.type) {
 			case OT_GOTO_STATION: {
--- a/saveload.c	Mon Apr 03 13:35:19 2006 +0000
+++ b/saveload.c	Mon Apr 03 14:25:32 2006 +0000
@@ -30,7 +30,7 @@
 #include "variables.h"
 #include <setjmp.h>
 
-const uint16 SAVEGAME_VERSION = 24;
+const uint16 SAVEGAME_VERSION = 25;
 uint16 _sl_version;       /// the major savegame version identifier
 byte   _sl_minor_version; /// the minor savegame version, DO NOT USE!
 
--- a/station.h	Mon Apr 03 13:35:19 2006 +0000
+++ b/station.h	Mon Apr 03 14:25:32 2006 +0000
@@ -28,7 +28,6 @@
 
 enum {
 	INVALID_STATION = 0xFFFF,
-	NUM_SLOTS = 2,
 	ROAD_STOP_LIMIT = 16,
 };
 
@@ -37,7 +36,7 @@
 	bool used;
 	byte status;
 	uint32 index;
-	VehicleID slot[NUM_SLOTS];
+	byte num_vehicles;
 	StationID station;
 	uint8 type;
 	struct RoadStop *next;
--- a/station_cmd.c	Mon Apr 03 13:35:19 2006 +0000
+++ b/station_cmd.c	Mon Apr 03 14:25:32 2006 +0000
@@ -87,15 +87,13 @@
 
 static void InitializeRoadStop(RoadStop *road_stop, RoadStop *previous, TileIndex tile, StationID index)
 {
-	int i;
 	road_stop->xy = tile;
 	road_stop->used = true;
 	road_stop->status = 3; //stop is free
 	road_stop->next = NULL;
 	road_stop->prev = previous;
 	road_stop->station = index;
-
-	for (i = 0; i < NUM_SLOTS; i++) road_stop->slot[i] = INVALID_VEHICLE;
+	road_stop->num_vehicles = 0;
 }
 
 RoadStop* GetPrimaryRoadStop(const Station* st, RoadStopType type)
@@ -1412,17 +1410,8 @@
 	if (!EnsureNoVehicle(tile)) return CMD_ERROR;
 
 	if (flags & DC_EXEC) {
-		uint i;
 		DoClearSquare(tile);
 
-		/* Clear all vehicles destined for this station */
-		for (i = 0; i != NUM_SLOTS; i++) {
-			if (cur_stop->slot[i] != INVALID_VEHICLE) {
-				Vehicle *v = GetVehicle(cur_stop->slot[i]);
-				ClearSlot(v);
-			}
-		}
-
 		cur_stop->used = false;
 		if (cur_stop->prev != NULL) cur_stop->prev->next = cur_stop->next;
 		if (cur_stop->next != NULL) cur_stop->next->prev = cur_stop->prev;
@@ -2254,27 +2243,6 @@
 	}
 }
 
-static void CheckOrphanedSlots(const Station *st, RoadStopType rst)
-{
-	RoadStop *rs;
-	uint k;
-
-	for (rs = GetPrimaryRoadStop(st, rst); rs != NULL; rs = rs->next) {
-		for (k = 0; k < NUM_SLOTS; k++) {
-			if (rs->slot[k] != INVALID_VEHICLE) {
-				const Vehicle *v = GetVehicle(rs->slot[k]);
-
-				if (v->type != VEH_Road || v->u.road.slot != rs) {
-					DEBUG(ms, 0) (
-						"Multistop: Orphaned %s slot at 0x%X of station %d (don't panic)",
-						(rst == RS_BUS) ? "bus" : "truck", rs->xy, st->index);
-					rs->slot[k] = INVALID_VEHICLE;
-				}
-			}
-		}
-	}
-}
-
 /* this function is called for one station each tick */
 static void StationHandleBigTick(Station *st)
 {
@@ -2282,9 +2250,6 @@
 
 	if (st->facilities == 0 && ++st->delete_ctr >= 8) DeleteStation(st);
 
-	// Here we saveguard against orphaned slots
-	CheckOrphanedSlots(st, RS_BUS);
-	CheckOrphanedSlots(st, RS_TRUCK);
 }
 
 static inline void byte_inc_sat(byte *p) { byte b = *p + 1; if (b != 0) *p = b; }
@@ -2783,7 +2748,8 @@
 	SLE_REF(RoadStop,next,         REF_ROADSTOPS),
 	SLE_REF(RoadStop,prev,         REF_ROADSTOPS),
 
-	SLE_ARR(RoadStop,slot,         SLE_UINT16, NUM_SLOTS),
+	SLE_CONDNULL(4, 0, 24),
+	SLE_CONDVAR(RoadStop, num_vehicles, SLE_UINT8, 25, SL_MAX_VERSION),
 
 	SLE_END()
 };
@@ -2952,6 +2918,7 @@
 			error("RoadStops: failed loading savegame: too many RoadStops");
 
 		rs = GetRoadStop(index);
+		rs->num_vehicles = 0;
 		SlObject(rs, _roadstop_desc);
 	}
 }
--- a/vehicle.c	Mon Apr 03 13:35:19 2006 +0000
+++ b/vehicle.c	Mon Apr 03 14:25:32 2006 +0000
@@ -2213,7 +2213,7 @@
 	SLE_VARX(offsetof(Vehicle,u)+offsetof(VehicleRoad,reverse_ctr),			SLE_UINT8),
 
 	SLE_CONDREFX(offsetof(Vehicle,u)+offsetof(VehicleRoad,slot), REF_ROADSTOPS, 6, SL_MAX_VERSION),
-	SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRoad,slotindex), SLE_UINT8, 6, SL_MAX_VERSION),
+	SLE_CONDNULL(1, 6, SL_MAX_VERSION),
 	SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRoad,slot_age), SLE_UINT8, 6, SL_MAX_VERSION),
 	// reserve extra space in savegame here. (currently 16 bytes)
 	SLE_CONDNULL(16, 2, SL_MAX_VERSION),
--- a/vehicle.h	Mon Apr 03 13:35:19 2006 +0000
+++ b/vehicle.h	Mon Apr 03 14:25:32 2006 +0000
@@ -24,7 +24,6 @@
 	VS_TRAIN_SLOWING = 0x10,
 	VS_DISASTER = 0x20,
 	VS_AIRCRAFT_BROKEN = 0x40,
-	VS_WAIT_FOR_SLOT = 0x40,
 	VS_CRASHED = 0x80,
 };
 
@@ -111,7 +110,6 @@
 	uint16 crashed_ctr;
 	byte reverse_ctr;
 	struct RoadStop *slot;
-	byte slotindex;
 	byte slot_age;
 } VehicleRoad;