Changeset - r20480:93a50078f0bb
[Not reviewed]
master
0 1 0
rubidium - 11 years ago 2013-06-28 18:09:07
rubidium@openttd.org
(svn r25495) -Fix [FS#5553]: when addings bits to a (train) station, the train trying to stop there could overshoot the (new) stop location and not stop at all
1 file changed with 3 insertions and 6 deletions:
0 comments (0 inline, 0 general)
src/station_cmd.cpp
Show inline comments
 
@@ -3031,213 +3031,210 @@ static TrackStatus GetTileTrackStatus_St
 
			/* buoy is coded as a station, it is always on open water */
 
			if (IsBuoy(tile)) {
 
				trackbits = TRACK_BIT_ALL;
 
				/* remove tracks that connect NE map edge */
 
				if (TileX(tile) == 0) trackbits &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT);
 
				/* remove tracks that connect NW map edge */
 
				if (TileY(tile) == 0) trackbits &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER);
 
			}
 
			break;
 

	
 
		case TRANSPORT_ROAD:
 
			if ((GetRoadTypes(tile) & sub_mode) != 0 && IsRoadStop(tile)) {
 
				DiagDirection dir = GetRoadStopDir(tile);
 
				Axis axis = DiagDirToAxis(dir);
 

	
 
				if (side != INVALID_DIAGDIR) {
 
					if (axis != DiagDirToAxis(side) || (IsStandardRoadStopTile(tile) && dir != side)) break;
 
				}
 

	
 
				trackbits = AxisToTrackBits(axis);
 
			}
 
			break;
 

	
 
		default:
 
			break;
 
	}
 

	
 
	return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), TRACKDIR_BIT_NONE);
 
}
 

	
 

	
 
static void TileLoop_Station(TileIndex tile)
 
{
 
	/* FIXME -- GetTileTrackStatus_Station -> animated stationtiles
 
	 * hardcoded.....not good */
 
	switch (GetStationType(tile)) {
 
		case STATION_AIRPORT:
 
			AirportTileAnimationTrigger(Station::GetByTile(tile), tile, AAT_TILELOOP);
 
			break;
 

	
 
		case STATION_DOCK:
 
			if (GetTileSlope(tile) != SLOPE_FLAT) break; // only handle water part
 
			/* FALL THROUGH */
 
		case STATION_OILRIG: //(station part)
 
		case STATION_BUOY:
 
			TileLoop_Water(tile);
 
			break;
 

	
 
		default: break;
 
	}
 
}
 

	
 

	
 
static void AnimateTile_Station(TileIndex tile)
 
{
 
	if (HasStationRail(tile)) {
 
		AnimateStationTile(tile);
 
		return;
 
	}
 

	
 
	if (IsAirport(tile)) {
 
		AnimateAirportTile(tile);
 
	}
 
}
 

	
 

	
 
static bool ClickTile_Station(TileIndex tile)
 
{
 
	const BaseStation *bst = BaseStation::GetByTile(tile);
 

	
 
	if (bst->facilities & FACIL_WAYPOINT) {
 
		ShowWaypointWindow(Waypoint::From(bst));
 
	} else if (IsHangar(tile)) {
 
		const Station *st = Station::From(bst);
 
		ShowDepotWindow(st->airport.GetHangarTile(st->airport.GetHangarNum(tile)), VEH_AIRCRAFT);
 
	} else {
 
		ShowStationViewWindow(bst->index);
 
	}
 
	return true;
 
}
 

	
 
static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, int x, int y)
 
{
 
	if (v->type == VEH_TRAIN) {
 
		StationID station_id = GetStationIndex(tile);
 
		if (!v->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE;
 
		if (!IsRailStation(tile) || !v->IsFrontEngine()) return VETSB_CONTINUE;
 

	
 
		int station_ahead;
 
		int station_length;
 
		int stop = GetTrainStopLocation(station_id, tile, Train::From(v), &station_ahead, &station_length);
 

	
 
		/* Stop whenever that amount of station ahead + the distance from the
 
		 * begin of the platform to the stop location is longer than the length
 
		 * of the platform. Station ahead 'includes' the current tile where the
 
		 * vehicle is on, so we need to subtract that. */
 
		if (!IsInsideBS(stop + station_ahead, station_length, TILE_SIZE)) return VETSB_CONTINUE;
 
		if (stop + station_ahead - (int)TILE_SIZE >= station_length) return VETSB_CONTINUE;
 

	
 
		DiagDirection dir = DirToDiagDir(v->direction);
 

	
 
		x &= 0xF;
 
		y &= 0xF;
 

	
 
		if (DiagDirToAxis(dir) != AXIS_X) Swap(x, y);
 
		if (y == TILE_SIZE / 2) {
 
			if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
 
			stop &= TILE_SIZE - 1;
 

	
 
			if (x == stop) return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
 
			if (x < stop) {
 
				uint16 spd;
 
			if (x >= stop) return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
 

	
 
				v->vehstatus |= VS_TRAIN_SLOWING;
 
				spd = max(0, (stop - x) * 20 - 15);
 
			uint16 spd = max(0, (stop - x) * 20 - 15);
 
				if (spd < v->cur_speed) v->cur_speed = spd;
 
			}
 
		}
 
	} else if (v->type == VEH_ROAD) {
 
		RoadVehicle *rv = RoadVehicle::From(v);
 
		if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)rv->state) && rv->frame == 0) {
 
			if (IsRoadStop(tile) && rv->IsFrontEngine()) {
 
				/* Attempt to allocate a parking bay in a road stop */
 
				return RoadStop::GetByTile(tile, GetRoadStopType(tile))->Enter(rv) ? VETSB_CONTINUE : VETSB_CANNOT_ENTER;
 
			}
 
		}
 
	}
 

	
 
	return VETSB_CONTINUE;
 
}
 

	
 
/**
 
 * Run the watched cargo callback for all houses in the catchment area.
 
 * @param st Station.
 
 */
 
void TriggerWatchedCargoCallbacks(Station *st)
 
{
 
	/* Collect cargoes accepted since the last big tick. */
 
	uint cargoes = 0;
 
	for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
 
		if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(cargoes, cid);
 
	}
 

	
 
	/* Anything to do? */
 
	if (cargoes == 0) return;
 

	
 
	/* Loop over all houses in the catchment. */
 
	Rect r = st->GetCatchmentRect();
 
	TileArea ta(TileXY(r.left, r.top), TileXY(r.right, r.bottom));
 
	TILE_AREA_LOOP(tile, ta) {
 
		if (IsTileType(tile, MP_HOUSE)) {
 
			WatchedCargoCallback(tile, cargoes);
 
		}
 
	}
 
}
 

	
 
/**
 
 * This function is called for each station once every 250 ticks.
 
 * Not all stations will get the tick at the same time.
 
 * @param st the station receiving the tick.
 
 * @return true if the station is still valid (wasn't deleted)
 
 */
 
static bool StationHandleBigTick(BaseStation *st)
 
{
 
	if (!st->IsInUse()) {
 
		if (++st->delete_ctr >= 8) delete st;
 
		return false;
 
	}
 

	
 
	if (Station::IsExpected(st)) {
 
		TriggerWatchedCargoCallbacks(Station::From(st));
 

	
 
		for (CargoID i = 0; i < NUM_CARGO; i++) {
 
			ClrBit(Station::From(st)->goods[i].acceptance_pickup, GoodsEntry::GES_ACCEPTED_BIGTICK);
 
		}
 
	}
 

	
 

	
 
	if ((st->facilities & FACIL_WAYPOINT) == 0) UpdateStationAcceptance(Station::From(st), true);
 

	
 
	return true;
 
}
 

	
 
static inline void byte_inc_sat(byte *p)
 
{
 
	byte b = *p + 1;
 
	if (b != 0) *p = b;
 
}
 

	
 
static void UpdateStationRating(Station *st)
 
{
 
	bool waiting_changed = false;
 

	
 
	byte_inc_sat(&st->time_since_load);
 
	byte_inc_sat(&st->time_since_unload);
 

	
 
	const CargoSpec *cs;
 
	FOR_ALL_CARGOSPECS(cs) {
 
		GoodsEntry *ge = &st->goods[cs->Index()];
 
		/* Slowly increase the rating back to his original level in the case we
 
		 *  didn't deliver cargo yet to this station. This happens when a bribe
 
		 *  failed while you didn't moved that cargo yet to a station. */
 
		if (!ge->HasRating() && ge->rating < INITIAL_STATION_RATING) {
 
			ge->rating++;
 
		}
 

	
 
		/* Only change the rating if we are moving this cargo */
 
		if (ge->HasRating()) {
 
			byte_inc_sat(&ge->time_since_pickup);
 

	
 
			bool skip = false;
 
			int rating = 0;
 
			uint waiting = ge->cargo.TotalCount();
 

	
0 comments (0 inline, 0 general)