コード例 #1
0
ファイル: npf.cpp プロジェクト: oshepherd/openttd-progsigs
/**
 * Tests if a tile can be entered or left only from one side.
 *
 * Depots, non-drive-through roadstops, and tiles with single trambits are tested.
 *
 * @param tile The tile of interest.
 * @param type The transporttype of the vehicle.
 * @param subtype For TRANSPORT_ROAD the compatible RoadTypes of the vehicle.
 * @return The single entry/exit-direction of the tile, or INVALID_DIAGDIR if there are more or less directions
 */
static DiagDirection GetTileSingleEntry(TileIndex tile, TransportType type, uint subtype)
{
	if (type != TRANSPORT_WATER && IsDepotTypeTile(tile, type)) return GetDepotDirection(tile, type);

	if (type == TRANSPORT_ROAD) {
		if (IsStandardRoadStopTile(tile)) return GetRoadStopDir(tile);
		if (HasBit(subtype, ROADTYPE_TRAM)) return GetSingleTramBit(tile);
	}

	return INVALID_DIAGDIR;
}
コード例 #2
0
/**
 * 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)->gcache.cached_total_length;
	}
}
コード例 #3
0
/**
 * 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;
}
コード例 #4
0
/**
 * 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;
}