Changeset - r13865:208a75ffd2fd
[Not reviewed]
master
0 16 0
rubidium - 15 years ago 2009-12-04 20:52:19
rubidium@openttd.org
(svn r18404) -Codechange: link drive through stops better together
-Feature: make penalty for road stop occupancy user configurable
-Fix [FS#1944]: road vehicles would not pick an empty drive through stop. Now they will *if* the penalty for driving around is less than the occupancy penalty
-Fix [FS#1495]: long (articulated) road vehicles could block loading of others when the following road vehicle already got 'permission' to go to the next bay even when it could not reach it
-Change: improve the throughput of the drive through road stops by letting them stop closer together
16 files changed with 459 insertions and 50 deletions:
0 comments (0 inline, 0 general)
src/openttd.cpp
Show inline comments
 
@@ -1096,6 +1096,16 @@ void StateGameLoop()
 
		CallWindowTickEvent();
 
		NewsLoop();
 
	} else {
 
		/* Temporary strict checking of the road stop cache entries */
 
		const RoadStop *rs;
 
		FOR_ALL_ROADSTOPS(rs) {
 
			if (IsStandardRoadStopTile(rs->xy)) continue;
 

	
 
			assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW));
 
			rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs);
 
			rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs);
 
		}
 

	
 
		if (_debug_desync_level > 1) {
 
			Vehicle *v;
 
			FOR_ALL_VEHICLES(v) {
src/order_cmd.cpp
Show inline comments
 
@@ -21,12 +21,12 @@
 
#include "timetable.h"
 
#include "vehicle_func.h"
 
#include "depot_base.h"
 
#include "roadstop_base.h"
 
#include "core/pool_func.hpp"
 
#include "aircraft.h"
 
#include "roadveh.h"
 
#include "station_base.h"
 
#include "waypoint_base.h"
 
#include "roadstop_base.h"
 

	
 
#include "table/strings.h"
 

	
src/pathfinder/npf/npf.cpp
Show inline comments
 
@@ -351,10 +351,21 @@ static int32 NPFRoadPathCost(AyStar *as,
 

	
 
		case MP_STATION: {
 
			cost = NPF_TILE_LENGTH;
 
			/* Increase the cost for drive-through road stops */
 
			if (IsDriveThroughStopTile(tile)) cost += _settings_game.pf.npf.npf_road_drive_through_penalty;
 
			RoadStop *rs = RoadStop::GetByTile(tile, GetRoadStopType(tile));
 
			cost += 8 * NPF_TILE_LENGTH * ((!rs->IsFreeBay(0)) + (!rs->IsFreeBay(1)));
 
			const RoadStop *rs = RoadStop::GetByTile(tile, GetRoadStopType(tile));
 
			if (IsDriveThroughStopTile(tile)) {
 
				/* Increase the cost for drive-through road stops */
 
				cost += _settings_game.pf.npf.npf_road_drive_through_penalty;
 
				DiagDirection dir = TrackdirToExitdir(current->direction);
 
				if (!RoadStop::IsDriveThroughRoadStopContinuation(tile, tile - TileOffsByDiagDir(dir))) {
 
					/* When we're the first road stop in a 'queue' of them we increase
 
					 * cost based on the fill percentage of the whole queue. */
 
					const RoadStop::Entry *entry = rs->GetEntry(dir);
 
					cost += entry->GetOccupied() * _settings_game.pf.npf.npf_road_dt_occupied_penalty / entry->GetLength();
 
				}
 
			} else {
 
				/* Increase cost for filled road stops */
 
				cost += _settings_game.pf.npf.npf_road_bay_occupied_penalty * (!rs->IsFreeBay(0) + !rs->IsFreeBay(1)) / 2;
 
			}
 
		} break;
 

	
 
		default:
src/pathfinder/yapf/yapf_road.cpp
Show inline comments
 
@@ -66,9 +66,21 @@ protected:
 
					break;
 

	
 
				case MP_STATION: {
 
					if (IsDriveThroughStopTile(tile)) cost += Yapf().PfGetSettings().road_stop_penalty;
 
					RoadStop *rs = RoadStop::GetByTile(tile, GetRoadStopType(tile));
 
					cost += 8 * YAPF_TILE_LENGTH * ((!rs->IsFreeBay(0)) + (!rs->IsFreeBay(1)));
 
					const RoadStop *rs = RoadStop::GetByTile(tile, GetRoadStopType(tile));
 
					if (IsDriveThroughStopTile(tile)) {
 
						/* Increase the cost for drive-through road stops */
 
						cost += Yapf().PfGetSettings().road_stop_penalty;
 
						DiagDirection dir = TrackdirToExitdir(trackdir);
 
						if (!RoadStop::IsDriveThroughRoadStopContinuation(tile, tile - TileOffsByDiagDir(dir))) {
 
							/* When we're the first road stop in a 'queue' of them we increase
 
							 * cost based on the fill percentage of the whole queue. */
 
							const RoadStop::Entry *entry = rs->GetEntry(dir);
 
							cost += entry->GetOccupied() * Yapf().PfGetSettings().road_stop_occupied_penalty / entry->GetLength();
 
						}
 
					} else {
 
						/* Increase cost for filled road stops */
 
						cost += Yapf().PfGetSettings().road_stop_bay_occupied_penalty * (!rs->IsFreeBay(0) + !rs->IsFreeBay(1)) / 2;
 
					}
 
				} break;
 

	
 
				default:
src/roadstop.cpp
Show inline comments
 
@@ -14,6 +14,8 @@
 
#include "core/pool_func.hpp"
 
#include "roadstop_base.h"
 
#include "station_base.h"
 
#include "vehicle_func.h"
 
#include "landscape.h"
 

	
 
RoadStopPool _roadstop_pool("RoadStop");
 
INSTANTIATE_POOL_METHODS(RoadStop)
 
@@ -23,6 +25,12 @@ INSTANTIATE_POOL_METHODS(RoadStop)
 
 */
 
RoadStop::~RoadStop()
 
{
 
	/* When we are the head we need to free the entries */
 
	if (HasBit(this->status, RSSFB_BASE_ENTRY)) {
 
		delete this->east;
 
		delete this->west;
 
	}
 

	
 
	if (CleaningPool()) return;
 
}
 

	
 
@@ -47,18 +55,174 @@ RoadStop *RoadStop::GetNextRoadStop(cons
 
}
 

	
 
/**
 
 * Join this road stop to another 'base' road stop if possible;
 
 * fill all necessary data to become an actual drive through road stop.
 
 * Also update the length etc.
 
 */
 
void RoadStop::MakeDriveThrough()
 
{
 
	assert(this->east == NULL && this->west == NULL);
 

	
 
	RoadStopType rst = GetRoadStopType(this->xy);
 
	DiagDirection dir = GetRoadStopDir(this->xy);
 
	/* Use absolute so we always go towards the nortern tile */
 
	TileIndexDiff offset = abs(TileOffsByDiagDir(dir));
 

	
 
	/* Information about the tile north of us */
 
	TileIndex north_tile = this->xy - offset;
 
	bool north = IsDriveThroughRoadStopContinuation(this->xy, north_tile);
 
	RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : NULL;
 

	
 
	/* Information about the tile south of us */
 
	TileIndex south_tile = this->xy + offset;
 
	bool south = IsDriveThroughRoadStopContinuation(this->xy, south_tile);
 
	RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : NULL;
 

	
 
	/* Amount of road stops that will be added to the 'northern' head */
 
	int added = 1;
 
	if (north && rs_north->east != NULL) { // (east != NULL) == (west != NULL)
 
		/* There is a more nothern one, so this can join them */
 
		this->east = rs_north->east;
 
		this->west = rs_north->west;
 

	
 
		if (south && rs_south->east != NULL) { // (east != NULL) == (west != NULL)
 
			/* There more southern tiles too, they must 'join' us too */
 
			ClrBit(rs_south->status, RSSFB_BASE_ENTRY);
 
			this->east->occupied += rs_south->east->occupied;
 
			this->west->occupied += rs_south->west->occupied;
 

	
 
			/* Free the now unneeded entry structs */
 
			delete rs_south->east;
 
			delete rs_south->west;
 

	
 
			/* Make all 'children' of the southern tile take the new master */
 
			for (; IsDriveThroughRoadStopContinuation(this->xy, south_tile); south_tile += offset) {
 
				rs_south = RoadStop::GetByTile(south_tile, rst);
 
				if (rs_south->east == NULL) break;
 
				rs_south->east = rs_north->east;
 
				rs_south->west = rs_north->west;
 
				added++;
 
			}
 
		}
 
	} else if (south && rs_south->east != NULL) { // (east != NULL) == (west != NULL)
 
		/* There is one to the south, but not to the north... so we become 'parent' */
 
		this->east = rs_south->east;
 
		this->west = rs_south->west;
 
		SetBit(this->status, RSSFB_BASE_ENTRY);
 
		ClrBit(rs_south->status, RSSFB_BASE_ENTRY);
 
	} else {
 
		/* We are the only... so we are automatically the master */
 
		this->east = new Entry();
 
		this->west = new Entry();
 
		SetBit(this->status, RSSFB_BASE_ENTRY);
 
	}
 

	
 
	/* Now update the lengths */
 
	added *= TILE_SIZE;
 
	this->east->length += added;
 
	this->west->length += added;
 
}
 

	
 
/**
 
 * Prepare for removal of this stop; update other neighbouring stops
 
 * if needed. Also update the length etc.
 
 */
 
void RoadStop::ClearDriveThrough()
 
{
 
	assert(this->east != NULL && this->west != NULL);
 

	
 
	RoadStopType rst = GetRoadStopType(this->xy);
 
	DiagDirection dir = GetRoadStopDir(this->xy);
 
	/* Use absolute so we always go towards the nortern tile */
 
	TileIndexDiff offset = abs(TileOffsByDiagDir(dir));
 

	
 
	/* Information about the tile north of us */
 
	TileIndex north_tile = this->xy - offset;
 
	bool north = IsDriveThroughRoadStopContinuation(this->xy, north_tile);
 
	RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : NULL;
 

	
 
	/* Information about the tile south of us */
 
	TileIndex south_tile = this->xy + offset;
 
	bool south = IsDriveThroughRoadStopContinuation(this->xy, south_tile);
 
	RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : NULL;
 

	
 
	/* Must only be cleared after we determined which neighbours are
 
	 * part of our little entry 'queue' */
 
	DoClearSquare(this->xy);
 

	
 
	if (north) {
 
		/* There is a tile to the north, so we can't clear ourselves. */
 
		if (south) {
 
			/* There are more southern tiles too, they must be split;
 
			 * first make the new southern 'base' */
 
			SetBit(rs_south->status, RSSFB_BASE_ENTRY);
 
			rs_south->east = new Entry();
 
			rs_south->west = new Entry();
 

	
 
			/* Keep track of the base because we need it later on */
 
			RoadStop *rs_south_base = rs_south;
 
			TileIndex base_tile = south_tile;
 

	
 
			/* Make all (even more) southern stops part of the new entry queue */
 
			for (south_tile += offset; IsDriveThroughRoadStopContinuation(base_tile, south_tile); south_tile += offset) {
 
				rs_south = RoadStop::GetByTile(south_tile, rst);
 
				rs_south->east = rs_south_base->east;
 
				rs_south->west = rs_south_base->west;
 
			}
 

	
 
			/* Find the other end; the northern most tile */
 
			for (; IsDriveThroughRoadStopContinuation(base_tile, north_tile); north_tile -= offset) {
 
				rs_north = RoadStop::GetByTile(north_tile, rst);
 
			}
 

	
 
			/* We have to rebuild the entries because we cannot easily determine
 
			 * how full each part is. So instead of keeping and maintaining a list
 
			 * of vehicles and using that to 'rebuild' the occupied state we just
 
			 * rebuild it from scratch as that removes lots of maintainance code
 
			 * for the vehicle list and it's faster in real games as long as you
 
			 * do not keep split and merge road stop every tick by the millions. */
 
			rs_south_base->east->Rebuild(rs_south_base);
 
			rs_south_base->west->Rebuild(rs_south_base);
 

	
 
			assert(HasBit(rs_north->status, RSSFB_BASE_ENTRY));
 
			rs_north->east->Rebuild(rs_north);
 
			rs_north->west->Rebuild(rs_north);
 
		} else {
 
			/* Only we left, so simple update the length. */
 
			rs_north->east->length -= TILE_SIZE;
 
			rs_north->west->length -= TILE_SIZE;
 
		}
 
	} else if (south) {
 
		/* There is only something to the south. Hand over the base entry */
 
		SetBit(rs_south->status, RSSFB_BASE_ENTRY);
 
		rs_south->east->length -= TILE_SIZE;
 
		rs_south->west->length -= TILE_SIZE;
 
	} else {
 
		/* We were the last */
 
		delete this->east;
 
		delete this->west;
 
	}
 

	
 
	/* Make sure we don't get used for something 'incorrect' */
 
	ClrBit(this->status, RSSFB_BASE_ENTRY);
 
	this->east = NULL;
 
	this->west = NULL;
 
}
 

	
 
/**
 
 * Leave the road stop
 
 * @param rv the vehicle that leaves the stop
 
 */
 
void RoadStop::Leave(RoadVehicle *rv)
 
{
 
	/* Vehicle is leaving a road stop tile, mark bay as free
 
	 * For drive-through stops, only do it if the vehicle stopped here */
 
	if (IsStandardRoadStopTile(rv->tile) || HasBit(rv->state, RVS_IS_STOPPING)) {
 
	if (IsStandardRoadStopTile(rv->tile)) {
 
		/* Vehicle is leaving a road stop tile, mark bay as free */
 
		this->FreeBay(HasBit(rv->state, RVS_USING_SECOND_BAY));
 
		ClrBit(rv->state, RVS_IS_STOPPING);
 
		this->SetEntranceBusy(false);
 
	} else {
 
		/* Otherwise just leave the drive through's entry cache. */
 
		this->GetEntry(DirToDiagDir(rv->direction))->Leave(rv);
 
	}
 
	if (IsStandardRoadStopTile(rv->tile)) this->SetEntranceBusy(false);
 
}
 

	
 
/**
 
@@ -85,19 +249,8 @@ bool RoadStop::Enter(RoadVehicle *rv)
 
	}
 

	
 
	/* Vehicles entering a drive-through stop from the 'normal' side use first bay (bay 0). */
 
	byte side = ((DirToDiagDir(rv->direction) == ReverseDiagDir(GetRoadStopDir(this->xy))) == (rv->overtaking == 0)) ? 0 : 1;
 

	
 
	if (!this->IsFreeBay(side)) return false;
 
	this->GetEntry(DirToDiagDir(rv->direction))->Enter(rv);
 

	
 
	/* Check if the vehicle is stopping at this road stop */
 
	if (GetRoadStopType(this->xy) == (rv->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
 
			rv->current_order.ShouldStopAtStation(rv, GetStationIndex(this->xy))) {
 
		SetBit(rv->state, RVS_IS_STOPPING);
 
		this->AllocateDriveThroughBay(side);
 
	}
 

	
 
	/* Indicate if vehicle is using second bay. */
 
	if (side == 1) SetBit(rv->state, RVS_USING_SECOND_BAY);
 
	/* Indicate a drive-through stop */
 
	SetBit(rv->state, RVS_IN_DT_ROAD_STOP);
 
	return true;
 
@@ -120,6 +273,121 @@ bool RoadStop::Enter(RoadVehicle *rv)
 
	}
 
}
 

	
 
/**
 
 * Leave the road stop
 
 * @param rv the vehicle that leaves the stop
 
 */
 
void RoadStop::Entry::Leave(const RoadVehicle *rv)
 
{
 
	this->occupied -= rv->rcache.cached_veh_length;
 
	assert(this->occupied >= 0);
 
}
 

	
 
/**
 
 * Enter the road stop
 
 * @param rv the vehicle that enters the stop
 
 */
 
void RoadStop::Entry::Enter(const RoadVehicle *rv)
 
{
 
	assert(this->occupied < this->length);
 
	this->occupied += rv->rcache.cached_veh_length;
 
}
 

	
 
/**
 
 * Checks whether the 'next' tile is still part of the road same drive through
 
 * stop 'rs' in the same direction for the same vehicle.
 
 * @param rs   the road stop tile to check against
 
 * @param next the 'next' tile to check
 
 * @return true if the 'next' tile is part of the road stop at 'next'.
 
 */
 
/* static */ bool RoadStop::IsDriveThroughRoadStopContinuation(TileIndex rs, TileIndex next)
 
{
 
	return IsTileType(next, MP_STATION) &&
 
			GetStationIndex(next) == GetStationIndex(rs) &&
 
			GetStationType(next) == GetStationType(rs) &&
 
			GetRoadStopDir(next) == GetRoadStopDir(rs) &&
 
			IsDriveThroughStopTile(next);
 
}
 

	
 
typedef std::list<const RoadVehicle *> RVList; ///< A list of road vehicles
 

	
 
/** Helper for finding RVs in a road stop. */
 
struct RoadStopEntryRebuilderHelper {
 
	RVList vehicles;   ///< The list of vehicles to possibly add to.
 
	DiagDirection dir; ///< The direction the vehicle has to face to be added.
 
};
 

	
 
/**
 
 * Add road vehicles to the station's list if needed.
 
 * @param v the found vehicle
 
 * @param data the extra data used to make our decision
 
 * @return always NULL
 
 */
 
Vehicle *FindVehiclesInRoadStop(Vehicle *v, void *data)
 
{
 
	RoadStopEntryRebuilderHelper *rserh = (RoadStopEntryRebuilderHelper*)data;
 
	/* Not a RV or not in the right direction or crashed :( */
 
	if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != rserh->dir || !v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) return NULL;
 

	
 
	RoadVehicle *rv = RoadVehicle::From(v);
 
	/* Don't add ones not in a road stop */
 
	if (rv->state < RVSB_IN_ROAD_STOP) return NULL;
 

	
 
	/* Do not add duplicates! */
 
	for (RVList::iterator it = rserh->vehicles.begin(); it != rserh->vehicles.end(); it++) {
 
		if (rv == *it) return NULL;
 
	}
 

	
 
	rserh->vehicles.push_back(rv);
 
	return NULL;
 
}
 

	
 
/**
 
 * Rebuild, from scratch, the vehicles and other metadata on this stop.
 
 * @param rs   the roadstop this entry is part of
 
 * @param side the side of the road stop to look at
 
 */
 
void RoadStop::Entry::Rebuild(const RoadStop *rs, int side)
 
{
 
	assert(HasBit(rs->status, RSSFB_BASE_ENTRY));
 

	
 
	DiagDirection dir = GetRoadStopDir(rs->xy);
 
	if (side == -1) side = (rs->east == this);
 

	
 
	RoadStopEntryRebuilderHelper rserh;
 
	rserh.dir = side ? dir : ReverseDiagDir(dir);
 

	
 
	this->length = 0;
 
	TileIndexDiff offset = abs(TileOffsByDiagDir(dir));
 
	for (TileIndex tile = rs->xy; IsDriveThroughRoadStopContinuation(rs->xy, tile); tile += offset) {
 
		this->length += TILE_SIZE;
 
		FindVehicleOnPos(tile, &rserh, FindVehiclesInRoadStop);
 
	}
 

	
 
	this->occupied = 0;
 
	for (RVList::iterator it = rserh.vehicles.begin(); it != rserh.vehicles.end(); it++) {
 
		this->occupied += (*it)->rcache.cached_veh_length;
 
	}
 
}
 

	
 

	
 
/**
 
 * Check the integrity of the data in this struct.
 
 * @param rs the roadstop this entry is part of
 
 */
 
void RoadStop::Entry::CheckIntegrity(const RoadStop *rs) const
 
{
 
	if (!HasBit(rs->status, RSSFB_BASE_ENTRY)) return;
 

	
 
	/* The tile 'before' the road stop must not be part of this 'line' */
 
	assert(!IsDriveThroughRoadStopContinuation(rs->xy, rs->xy - abs(TileOffsByDiagDir(GetRoadStopDir(rs->xy)))));
 

	
 
	Entry temp;
 
	temp.Rebuild(rs, rs->east == this);
 
	if (temp.length != this->length || temp.occupied != this->occupied) NOT_REACHED();
 
}
 

	
 

	
 
void InitializeRoadStops()
 
{
 
	_roadstop_pool.CleanPool();
src/roadstop_base.h
Show inline comments
 
@@ -25,9 +25,46 @@ struct RoadStop : RoadStopPool::PoolItem
 
		RSSFB_BAY0_FREE  = 0, ///< Non-zero when bay 0 is free
 
		RSSFB_BAY1_FREE  = 1, ///< Non-zero when bay 1 is free
 
		RSSFB_BAY_COUNT  = 2, ///< Max. number of bays
 
		RSSFB_BASE_ENTRY = 6, ///< Non-zero when the entries on this road stop are the primary, i.e. the ones to delete
 
		RSSFB_ENTRY_BUSY = 7, ///< Non-zero when roadstop entry is busy
 
	};
 

	
 
	/** Container for each entry point of a drive through road stop */
 
	struct Entry {
 
	private:
 
		int length;      ///< The length of the stop in tile 'units'
 
		int occupied;    ///< The amount of occupied stop in tile 'units'
 

	
 
	public:
 
		friend class RoadStop; ///< Oh yeah, the road stop may play with me.
 

	
 
		/** Create an entry */
 
		Entry() : length(0), occupied(0) {}
 

	
 
		/**
 
		 * Get the length of this drive through stop.
 
		 * @return the length in tile units.
 
		 */
 
		FORCEINLINE int GetLength() const
 
		{
 
			return this->length;
 
		}
 

	
 
		/**
 
		 * Get the amount of occupied space in this drive through stop.
 
		 * @return the occupied space in tile units.
 
		 */
 
		FORCEINLINE int GetOccupied() const
 
		{
 
			return this->occupied;
 
		}
 

	
 
		void Leave(const RoadVehicle *rv);
 
		void Enter(const RoadVehicle *rv);
 
		void CheckIntegrity(const RoadStop *rs) const;
 
		void Rebuild(const RoadStop *rs, int side = -1);
 
	};
 

	
 
	static const uint LIMIT           = 16;  ///< The maximum amount of roadstops that are allowed at a single station
 

	
 
	TileIndex        xy;                    ///< Position on the map
 
@@ -80,6 +117,29 @@ struct RoadStop : RoadStopPool::PoolItem
 
		SB(this->status, RSSFB_ENTRY_BUSY, 1, busy);
 
	}
 

	
 
	/**
 
	 * Get the drive through road stop entry struct for the given direction.
 
	 * @param direction the direciton to get the entry for
 
	 * @return the entry
 
	 */
 
	FORCEINLINE const Entry *GetEntry(DiagDirection dir) const
 
	{
 
		return HasBit((int)dir, 1) ? this->west : this->east;
 
	}
 

	
 
	/**
 
	 * Get the drive through road stop entry struct for the given direction.
 
	 * @param direction the direciton to get the entry for
 
	 * @return the entry
 
	 */
 
	FORCEINLINE Entry *GetEntry(DiagDirection dir)
 
	{
 
		return HasBit((int)dir, 1) ? this->west : this->east;
 
	}
 

	
 
	void MakeDriveThrough();
 
	void ClearDriveThrough();
 

	
 
	void Leave(RoadVehicle *rv);
 
	bool Enter(RoadVehicle *rv);
 

	
 
@@ -87,7 +147,12 @@ struct RoadStop : RoadStopPool::PoolItem
 

	
 
	static RoadStop *GetByTile(TileIndex tile, RoadStopType type);
 

	
 
	static bool IsDriveThroughRoadStopContinuation(TileIndex rs, TileIndex next);
 

	
 
private:
 
	Entry *east; ///< The vehicles that entered from the east
 
	Entry *west; ///< The vehicles that entered from the west
 

	
 
	/**
 
	 * Allocates a bay
 
	 * @return the allocated bay number
src/roadveh.h
Show inline comments
 
@@ -39,7 +39,6 @@ enum RoadVehicleStates {
 

	
 
	/* Bit numbers */
 
	RVS_USING_SECOND_BAY         =    1,                      ///< Only used while in a road stop
 
	RVS_IS_STOPPING              =    2,                      ///< Only used for drive-through stops. Vehicle will stop here
 
	RVS_DRIVE_SIDE               =    4,                      ///< Only used when retrieving move data
 
	RVS_IN_ROAD_STOP             =    5,                      ///< The vehicle is in a road stop
 
	RVS_IN_DT_ROAD_STOP          =    6,                      ///< The vehicle is in a drive-through road stop
 
@@ -70,7 +69,7 @@ enum {
 
	RVC_START_FRAME_AFTER_LONG_TRAM        = 21,
 
	RVC_TURN_AROUND_START_FRAME_SHORT_TRAM = 16,
 
	/* Stop frame for a vehicle in a drive-through stop */
 
	RVC_DRIVE_THROUGH_STOP_FRAME           =  7,
 
	RVC_DRIVE_THROUGH_STOP_FRAME           = 11,
 
	RVC_DEPOT_STOP_FRAME                   = 11,
 
};
 

	
src/roadveh_cmd.cpp
Show inline comments
 
@@ -463,18 +463,14 @@ void RoadVehicle::UpdateDeltaXY(Directio
 
	this->z_extent      = 6;
 
}
 

	
 
static void ClearCrashedStation(RoadVehicle *v)
 
{
 
	RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
 
}
 

	
 
static void DeleteLastRoadVeh(RoadVehicle *v)
 
{
 
	Vehicle *u = v;
 
	for (; v->Next() != NULL; v = v->Next()) u = v;
 
	u->SetNext(NULL);
 

	
 
	if (IsTileType(v->tile, MP_STATION)) ClearCrashedStation(v);
 
	/* Only leave the road stop when we're really gone. */
 
	if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
 

	
 
	delete v;
 
}
 
@@ -540,7 +536,14 @@ static Vehicle *EnumCheckRoadVehCrashTra
 
uint RoadVehicle::Crash(bool flooded)
 
{
 
	uint pass = Vehicle::Crash(flooded);
 
	if (this->IsRoadVehFront()) pass += 1; // driver
 
	if (this->IsRoadVehFront()) {
 
		pass += 1; // driver
 

	
 
		/* If we're in a drive through road stop we ought to leave it */
 
		if (IsInsideMM(this->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
 
			RoadStop::GetByTile(this->tile, GetRoadStopType(this->tile))->Leave(this);
 
		}
 
	}
 
	this->crashed_ctr = flooded ? 2000 : 1; // max 2220, disappear pretty fast when flooded
 
	return pass;
 
}
 
@@ -1413,6 +1416,17 @@ again:
 
			/* There is a vehicle in front overtake it if possible */
 
			if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
 
			if (v->overtaking == 0) v->cur_speed = u->cur_speed;
 

	
 
			/* In case an RV is stopped in a road stop, why not try to load? */
 
			if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
 
					v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
 
					v->owner == GetTileOwner(v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
 
					GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) {
 
				Station *st = Station::GetByTile(v->tile);
 
				v->last_station_visited = st->index;
 
				RoadVehArrivesAt(v, st);
 
				v->BeginLoading();
 
			}
 
			return false;
 
		}
 
	}
 
@@ -1455,20 +1469,12 @@ again:
 

	
 
			if (IsDriveThroughStopTile(v->tile)) {
 
				TileIndex next_tile = TILE_ADD(v->tile, TileOffsByDir(v->direction));
 
				RoadStopType type = v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK;
 

	
 
				/* Check if next inline bay is free */
 
				if (IsDriveThroughStopTile(next_tile) && (GetRoadStopType(next_tile) == type) && GetStationIndex(v->tile) == GetStationIndex(next_tile)) {
 
					RoadStop *rs_n = RoadStop::GetByTile(next_tile, type);
 

	
 
					if (rs_n->IsFreeBay(HasBit(v->state, RVS_USING_SECOND_BAY))) {
 
						/* Bay in next stop along is free - use it */
 
						v->dest_tile = rs_n->xy;
 

	
 
						v->frame++;
 
						RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, false));
 
						return true;
 
					}
 
				if (RoadStop::IsDriveThroughRoadStopContinuation(v->tile, next_tile)) {
 
					v->frame++;
 
					RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, false));
 
					return true;
 
				}
 
			}
 

	
src/saveload/afterload.cpp
Show inline comments
 
@@ -1360,7 +1360,7 @@ bool AfterLoadGame()
 
		RoadVehicle *rv;
 
		FOR_ALL_ROADVEHICLES(rv) {
 
			if (rv->state == 250 || rv->state == 251) {
 
				SetBit(rv->state, RVS_IS_STOPPING);
 
				SetBit(rv->state, 2);
 
			}
 
		}
 
	}
 
@@ -1959,6 +1959,8 @@ bool AfterLoadGame()
 
		}
 
	}
 

	
 
	/* Road stops is 'only' updating some caches */
 
	AfterLoadRoadStops();
 
	AfterLoadLabelMaps();
 

	
 
	GamelogPrintDebug(1);
src/saveload/oldloader_sl.cpp
Show inline comments
 
@@ -190,7 +190,7 @@ void FixOldVehicles()
 
		if (v->type == VEH_ROAD) {
 
			RoadVehicle *rv = RoadVehicle::From(v);
 
			if (rv->state != RVSB_IN_DEPOT && rv->state != RVSB_WORMHOLE) {
 
				ClrBit(rv->state, RVS_IS_STOPPING);
 
				ClrBit(rv->state, 2);
 
			}
 
		}
 

	
src/saveload/saveload.cpp
Show inline comments
 
@@ -47,7 +47,7 @@
 

	
 
#include "saveload_internal.h"
 

	
 
extern const uint16 SAVEGAME_VERSION = 129;
 
extern const uint16 SAVEGAME_VERSION = 130;
 

	
 
SavegameType _savegame_type; ///< type of savegame we are loading
 

	
src/saveload/saveload_internal.h
Show inline comments
 
@@ -29,6 +29,7 @@ const SaveLoad *GetBaseStationDescriptio
 

	
 
void AfterLoadVehicles(bool part_of_load);
 
void AfterLoadStations();
 
void AfterLoadRoadStops();
 
void AfterLoadLabelMaps();
 
void UpdateHousesAndTowns();
 

	
src/saveload/station_sl.cpp
Show inline comments
 
@@ -15,6 +15,7 @@
 
#include "../roadstop_base.h"
 
#include "../vehicle_base.h"
 
#include "../newgrf_station.h"
 
#include "../station_map.h"
 

	
 
#include "saveload.h"
 
#include "table/strings.h"
 
@@ -108,6 +109,25 @@ void AfterLoadStations()
 
	}
 
}
 

	
 
/**
 
 * (Re)building of road stop caches after loading a savegame.
 
 */
 
void AfterLoadRoadStops()
 
{
 
	/* First construct the drive through entries */
 
	RoadStop *rs;
 
	FOR_ALL_ROADSTOPS(rs) {
 
		if (IsDriveThroughStopTile(rs->xy)) rs->MakeDriveThrough();
 
	}
 
	/* And then rebuild the data in those entries */
 
	FOR_ALL_ROADSTOPS(rs) {
 
		if (!HasBit(rs->status, RoadStop::RSSFB_BASE_ENTRY)) continue;
 

	
 
		rs->GetEntry(DIAGDIR_NE)->Rebuild(rs);
 
		rs->GetEntry(DIAGDIR_NW)->Rebuild(rs);
 
	}
 
}
 

	
 
static const SaveLoad _roadstop_desc[] = {
 
	SLE_VAR(RoadStop, xy,           SLE_UINT32),
 
	SLE_CONDNULL(1, 0, 44),
src/settings_type.h
Show inline comments
 
@@ -223,6 +223,8 @@ struct NPFSettings {
 
	uint32 npf_road_curve_penalty;           ///< the penalty for curves
 
	uint32 npf_crossing_penalty;             ///< the penalty for level crossings
 
	uint32 npf_road_drive_through_penalty;   ///< the penalty for going through a drive-through road stop
 
	uint32 npf_road_dt_occupied_penalty;     ///< the penalty multiplied by the fill percentage of a drive-through road stop
 
	uint32 npf_road_bay_occupied_penalty;    ///< the penalty multiplied by the fill percentage of a road bay
 
};
 

	
 
/** Settings related to the yet another pathfinder. */
 
@@ -236,6 +238,8 @@ struct YAPFSettings {
 
	uint32 road_curve_penalty;               ///< penalty for curves
 
	uint32 road_crossing_penalty;            ///< penalty for level crossing
 
	uint32 road_stop_penalty;                ///< penalty for going through a drive-through road stop
 
	uint32 road_stop_occupied_penalty;       ///< penalty multiplied by the fill percentage of a drive-through road stop
 
	uint32 road_stop_bay_occupied_penalty;   ///< penalty multiplied by the fill percentage of a road bay
 
	bool   rail_firstred_twoway_eol;         ///< treat first red two-way signal as dead end
 
	uint32 rail_firstred_penalty;            ///< penalty for first red signal
 
	uint32 rail_firstred_exit_penalty;       ///< penalty for first red exit signal
src/station_cmd.cpp
Show inline comments
 
@@ -1638,6 +1638,7 @@ CommandCost CmdBuildRoadStop(TileIndex t
 
		RoadStopType rs_type = type ? ROADSTOP_TRUCK : ROADSTOP_BUS;
 
		if (is_drive_through) {
 
			MakeDriveThroughRoadStop(tile, st->owner, road_owner, tram_owner, st->index, rs_type, rts, (Axis)p1);
 
			road_stop->MakeDriveThrough();
 
		} else {
 
			MakeRoadStop(tile, st->owner, st->index, rs_type, rts, (DiagDirection)p1);
 
		}
 
@@ -1721,6 +1722,13 @@ static CommandCost RemoveRoadStop(TileIn
 
			pred->next = cur_stop->next;
 
		}
 

	
 
		if (IsDriveThroughStopTile(tile)) {
 
			/* Clears the tile for us */
 
			cur_stop->ClearDriveThrough();
 
		} else {
 
			DoClearSquare(tile);
 
		}
 

	
 
		SetWindowWidgetDirty(WC_STATION_VIEW, st->index, SVW_ROADVEHS);
 
		delete cur_stop;
 

	
 
@@ -1733,7 +1741,6 @@ static CommandCost RemoveRoadStop(TileIn
 
			}
 
		}
 

	
 
		DoClearSquare(tile);
 
		st->rect.AfterRemoveTile(st, tile);
 

	
 
		st->UpdateVirtCoord();
src/table/settings.h
Show inline comments
 
@@ -473,6 +473,8 @@ const SettingDesc _settings[] = {
 
	     SDT_VAR(GameSettings, pf.npf.npf_road_curve_penalty,                  SLE_UINT,                     0, 0, 1,                         0,  100000, 0, STR_NULL,         NULL),
 
	     SDT_VAR(GameSettings, pf.npf.npf_crossing_penalty,                    SLE_UINT,                     0, 0, (  3 * NPF_TILE_LENGTH),   0,  100000, 0, STR_NULL,         NULL),
 
	 SDT_CONDVAR(GameSettings, pf.npf.npf_road_drive_through_penalty,          SLE_UINT, 47, SL_MAX_VERSION, 0, 0, (  8 * NPF_TILE_LENGTH),   0,  100000, 0, STR_NULL,         NULL),
 
	 SDT_CONDVAR(GameSettings, pf.npf.npf_road_dt_occupied_penalty,            SLE_UINT,130, SL_MAX_VERSION, 0, 0, (  8 * NPF_TILE_LENGTH),   0,  100000, 0, STR_NULL,         NULL),
 
	 SDT_CONDVAR(GameSettings, pf.npf.npf_road_bay_occupied_penalty,           SLE_UINT,130, SL_MAX_VERSION, 0, 0, ( 15 * NPF_TILE_LENGTH),   0,  100000, 0, STR_NULL,         NULL),
 

	
 

	
 
	SDT_CONDBOOL(GameSettings, pf.yapf.disable_node_optimization,                        28, SL_MAX_VERSION, 0, 0, false,                                    STR_NULL,         NULL),
 
@@ -504,6 +506,8 @@ const SettingDesc _settings[] = {
 
	 SDT_CONDVAR(GameSettings, pf.yapf.road_curve_penalty,                     SLE_UINT, 33, SL_MAX_VERSION, 0, 0,     1 * YAPF_TILE_LENGTH,  0, 1000000, 0, STR_NULL,         NULL),
 
	 SDT_CONDVAR(GameSettings, pf.yapf.road_crossing_penalty,                  SLE_UINT, 33, SL_MAX_VERSION, 0, 0,     3 * YAPF_TILE_LENGTH,  0, 1000000, 0, STR_NULL,         NULL),
 
	 SDT_CONDVAR(GameSettings, pf.yapf.road_stop_penalty,                      SLE_UINT, 47, SL_MAX_VERSION, 0, 0,     8 * YAPF_TILE_LENGTH,  0, 1000000, 0, STR_NULL,         NULL),
 
	 SDT_CONDVAR(GameSettings, pf.yapf.road_stop_occupied_penalty,             SLE_UINT,130, SL_MAX_VERSION, 0, 0,     8 * YAPF_TILE_LENGTH,  0, 1000000, 0, STR_NULL,         NULL),
 
	 SDT_CONDVAR(GameSettings, pf.yapf.road_stop_bay_occupied_penalty,         SLE_UINT,130, SL_MAX_VERSION, 0, 0,    15 * YAPF_TILE_LENGTH,  0, 1000000, 0, STR_NULL,         NULL),
 

	
 
	 SDT_CONDVAR(GameSettings, game_creation.land_generator,                  SLE_UINT8, 30, SL_MAX_VERSION, 0,MS,     1,                     0,       1, 0, STR_CONFIG_SETTING_LAND_GENERATOR,        NULL),
 
	 SDT_CONDVAR(GameSettings, game_creation.oil_refinery_limit,              SLE_UINT8, 30, SL_MAX_VERSION, 0, 0,    32,                    12,      48, 0, STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE, NULL),
0 comments (0 inline, 0 general)