Changeset - r13967:0df597ac93ec
[Not reviewed]
master
0 3 0
rubidium - 15 years ago 2009-12-16 16:23:44
rubidium@openttd.org
(svn r18515) -Change: make it visible when you're to pass the next signal on danger and possible to cancel it
-Fix [FS#2891]: when you pass a signal at danger, in a PBS controlled area, don't try to do the 'safe' thing and stop, but continue going; the user wanted the train to pass the signal at danger so (s)he has to suffer the consequences. Ofcourse one can always stop the train manually.
3 files changed with 43 insertions and 2 deletions:
0 comments (0 inline, 0 general)
src/saveload/afterload.cpp
Show inline comments
 
@@ -1946,48 +1946,57 @@ bool AfterLoadGame()
 
		uint64 aimed_inflation = (_economy.old_max_loan_unround << 16 | _economy.old_max_loan_unround_fract) / _settings_game.difficulty.max_loan;
 

	
 
		/* ... well, just clamp it then. */
 
		if (aimed_inflation > MAX_INFLATION) aimed_inflation = MAX_INFLATION;
 

	
 
		/* Simulate the inflation, so we also get the payment inflation */
 
		while (_economy.inflation_prices < aimed_inflation) {
 
			AddInflation(false);
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(127)) {
 
		Station *st;
 
		FOR_ALL_STATIONS(st) UpdateStationAcceptance(st, false);
 
	}
 

	
 
	if (CheckSavegameVersion(128)) {
 
		const Depot *d;
 
		FOR_ALL_DEPOTS(d) {
 
			_m[d->xy].m2 = d->index;
 
			if (IsTileType(d->xy, MP_WATER)) _m[GetOtherShipDepotTile(d->xy)].m2 = d->index;
 
		}
 
	}
 

	
 
	/* The behaviour of force_proceed has been changed. Now
 
	 * it counts signals instead of some random time out. */
 
	if (CheckSavegameVersion(131)) {
 
		Train *t;
 
		FOR_ALL_TRAINS(t) {
 
			t->force_proceed = min<byte>(t->force_proceed, 1);
 
		}
 
	}
 

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

	
 
	GamelogPrintDebug(1);
 

	
 
	InitializeWindowsAndCaches();
 
	/* Restore the signals */
 
	ResetSignalHandlers();
 
	return true;
 
}
 

	
 
/** Reload all NewGRF files during a running game. This is a cut-down
 
 * version of AfterLoadGame().
 
 * XXX - We need to reset the vehicle position hash because with a non-empty
 
 * hash AfterLoadVehicles() will loop infinitely. We need AfterLoadVehicles()
 
 * to recalculate vehicle data as some NewGRF vehicle sets could have been
 
 * removed or added and changed statistics */
 
void ReloadNewGRFData()
 
{
 
	/* reload grf data */
 
	GfxLoadSprites();
 
	LoadStringWidthTable();
 
	RecomputePrices();
src/train_cmd.cpp
Show inline comments
 
@@ -1969,92 +1969,107 @@ static void ReverseTrainDirection(Train 
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	Train *v = Train::GetIfValid(p1);
 
	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
 

	
 
	if (p2 != 0) {
 
		/* turn a single unit around */
 

	
 
		if (v->IsMultiheaded() || HasBit(EngInfo(v->engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) {
 
			return_cmd_error(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS);
 
		}
 

	
 
		Train *front = v->First();
 
		/* make sure the vehicle is stopped in the depot */
 
		if (!front->IsStoppedInDepot()) {
 
			return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
 
		}
 

	
 
		if (flags & DC_EXEC) {
 
			ToggleBit(v->flags, VRF_REVERSE_DIRECTION);
 
			SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
 
			SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
 
			/* We cancel any 'skip signal at dangers' here */
 
			v->force_proceed = 0;
 
			SetWindowDirty(WC_VEHICLE_VIEW, v->index);
 
		}
 
	} else {
 
		/* turn the whole train around */
 
		if ((v->vehstatus & VS_CRASHED) || v->breakdown_ctr != 0) return CMD_ERROR;
 

	
 
		if (flags & DC_EXEC) {
 
			/* Properly leave the station if we are loading and won't be loading anymore */
 
			if (v->current_order.IsType(OT_LOADING)) {
 
				const Vehicle *last = v;
 
				while (last->Next() != NULL) last = last->Next();
 

	
 
				/* not a station || different station --> leave the station */
 
				if (!IsTileType(last->tile, MP_STATION) || GetStationIndex(last->tile) != GetStationIndex(v->tile)) {
 
					v->LeaveStation();
 
				}
 
			}
 

	
 
			/* We cancel any 'skip signal at dangers' here */
 
			v->force_proceed = 0;
 
			SetWindowDirty(WC_VEHICLE_VIEW, v->index);
 

	
 
			if (_settings_game.vehicle.train_acceleration_model != TAM_ORIGINAL && v->cur_speed != 0) {
 
				ToggleBit(v->flags, VRF_REVERSING);
 
			} else {
 
				v->cur_speed = 0;
 
				SetLastSpeed(v, 0);
 
				HideFillingPercent(&v->fill_percent_te_id);
 
				ReverseTrainDirection(v);
 
			}
 
		}
 
	}
 
	return CommandCost();
 
}
 

	
 
/** Force a train through a red signal
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1 train to ignore the red signal
 
 * @param p2 unused
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	Train *t = Train::GetIfValid(p1);
 
	if (t == NULL || !CheckOwnership(t->owner)) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) t->force_proceed = 0x50;
 
	if (flags & DC_EXEC) {
 
		/* If we are forced to proceed, cancel that order.
 
		 * If we are marked stuck we would want to force the train
 
		 * to proceed to the next signal. In the other cases we
 
		 * would like to pass the signal at danger and run till the
 
		 * next signal we encounter. */
 
		t->force_proceed = t->force_proceed == 2 ? 0 : HasBit(t->flags, VRF_TRAIN_STUCK) || t->IsInDepot() ? 1 : 2;
 
		SetWindowDirty(WC_VEHICLE_VIEW, t->index);
 
	}
 

	
 
	return CommandCost();
 
}
 

	
 
/** Refits a train to the specified cargo type.
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1 vehicle ID of the train to refit
 
 * @param p2 various bitstuffed elements
 
 * - p2 = (bit 0-7) - the new cargo type to refit to
 
 * - p2 = (bit 8-15) - the new cargo subtype to refit to
 
 * - p2 = (bit 16) - refit only this vehicle
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdRefitRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	CargoID new_cid = GB(p2, 0, 8);
 
	byte new_subtype = GB(p2, 8, 8);
 
	bool only_this = HasBit(p2, 16);
 

	
 
	Train *v = Train::GetIfValid(p1);
 
	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
 

	
 
@@ -3327,48 +3342,63 @@ static void TrainController(Train *v, Ve
 

	
 
				TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs;
 
				TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts) & reachable_trackdirs);
 

	
 
				TrackBits bits = TrackdirBitsToTrackBits(trackdirbits);
 
				if (_settings_game.pf.forbid_90_deg && prev == NULL) {
 
					/* We allow wagons to make 90 deg turns, because forbid_90_deg
 
					 * can be switched on halfway a turn */
 
					bits &= ~TrackCrossesTracks(FindFirstTrack(v->track));
 
				}
 

	
 
				if (bits == TRACK_BIT_NONE) goto invalid_rail;
 

	
 
				/* Check if the new tile contrains tracks that are compatible
 
				 * with the current train, if not, bail out. */
 
				if (!CheckCompatibleRail(v, gp.new_tile)) goto invalid_rail;
 

	
 
				TrackBits chosen_track;
 
				if (prev == NULL) {
 
					/* Currently the locomotive is active. Determine which one of the
 
					 * available tracks to choose */
 
					chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, NULL, true));
 
					assert(chosen_track & (bits | GetReservedTrackbits(gp.new_tile)));
 

	
 
					if (v->force_proceed != 0 && IsPlainRailTile(gp.new_tile) && HasSignals(gp.new_tile)) {
 
						/* For each signal we find decrease the counter by one.
 
						 * We start at two, so the first signal we pass decreases
 
						 * this to one, then if we reach the next signal it is
 
						 * decreased to zero and we won't pass that new signal. */
 
						Trackdir dir = FindFirstTrackdir(trackdirbits);
 
						if (GetSignalType(gp.new_tile, TrackdirToTrack(dir)) != SIGTYPE_PBS ||
 
								!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(dir))) {
 
							/* However, we do not want to be stopped by PBS signals
 
							 * entered via the back. */
 
							v->force_proceed--;
 
							SetWindowDirty(WC_VEHICLE_VIEW, v->index);
 
						}
 
					}
 

	
 
					/* Check if it's a red signal and that force proceed is not clicked. */
 
					if ((red_signals & chosen_track) && v->force_proceed == 0) {
 
						/* In front of a red signal */
 
						Trackdir i = FindFirstTrackdir(trackdirbits);
 

	
 
						/* Don't handle stuck trains here. */
 
						if (HasBit(v->flags, VRF_TRAIN_STUCK)) return;
 

	
 
						if (!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(i))) {
 
							v->cur_speed = 0;
 
							v->subspeed = 0;
 
							v->progress = 255 - 100;
 
							if (_settings_game.pf.wait_oneway_signal == 255 || ++v->time_counter < _settings_game.pf.wait_oneway_signal * 20) return;
 
						} else if (HasSignalOnTrackdir(gp.new_tile, i)) {
 
							v->cur_speed = 0;
 
							v->subspeed = 0;
 
							v->progress = 255 - 10;
 
							if (_settings_game.pf.wait_twoway_signal == 255 || ++v->time_counter < _settings_game.pf.wait_twoway_signal * 73) {
 
								DiagDirection exitdir = TrackdirToExitdir(i);
 
								TileIndex o_tile = TileAddByDiagDir(gp.new_tile, exitdir);
 

	
 
								exitdir = ReverseDiagDir(exitdir);
 

	
 
								/* check if a train is waiting on the other side */
 
@@ -3900,49 +3930,48 @@ static bool TrainCheckIfLineEnds(Train *
 

	
 
	/* no suitable trackbits at all || unusable rail (wrong type or owner) */
 
	if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(v, tile)) {
 
		return TrainApproachingLineEnd(v, false);
 
	}
 

	
 
	/* approaching red signal */
 
	if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(v, true);
 

	
 
	/* approaching a rail/road crossing? then make it red */
 
	if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile);
 

	
 
	return true;
 
}
 

	
 

	
 
static bool TrainLocoHandler(Train *v, bool mode)
 
{
 
	/* train has crashed? */
 
	if (v->vehstatus & VS_CRASHED) {
 
		return mode ? true : HandleCrashedTrain(v); // 'this' can be deleted here
 
	}
 

	
 
	if (v->force_proceed != 0) {
 
		v->force_proceed--;
 
		ClrBit(v->flags, VRF_TRAIN_STUCK);
 
		SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
	}
 

	
 
	/* train is broken down? */
 
	if (v->breakdown_ctr != 0) {
 
		if (v->breakdown_ctr <= 2) {
 
			HandleBrokenTrain(v);
 
			return true;
 
		}
 
		if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--;
 
	}
 

	
 
	if (HasBit(v->flags, VRF_REVERSING) && v->cur_speed == 0) {
 
		ReverseTrainDirection(v);
 
	}
 

	
 
	/* exit if train is stopped */
 
	if ((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) return true;
 

	
 
	bool valid_order = !v->current_order.IsType(OT_NOTHING) && v->current_order.GetType() != OT_CONDITIONAL;
 
	if (ProcessOrders(v) && CheckReverseTrain(v)) {
 
		v->time_counter = 0;
 
		v->cur_speed = 0;
 
@@ -3985,48 +4014,50 @@ static bool TrainLocoHandler(Train *v, b
 
						NS_ADVICE,
 
						v->index
 
					);
 
				}
 
				v->time_counter = 0;
 
			}
 
			/* Exit if force proceed not pressed, else reset stuck flag anyway. */
 
			if (v->force_proceed == 0) return true;
 
			ClrBit(v->flags, VRF_TRAIN_STUCK);
 
			v->time_counter = 0;
 
			SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
		}
 
	}
 

	
 
	if (v->current_order.IsType(OT_LEAVESTATION)) {
 
		v->current_order.Free();
 
		SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
		return true;
 
	}
 

	
 
	int j = UpdateTrainSpeed(v);
 

	
 
	/* we need to invalidate the widget if we are stopping from 'Stopping 0 km/h' to 'Stopped' */
 
	if (v->cur_speed == 0 && v->tcache.last_speed == 0 && (v->vehstatus & VS_STOPPED)) {
 
		/* If we manually stopped, we're not force-proceeding anymore. */
 
		v->force_proceed = 0;
 
		SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
	}
 

	
 
	int adv_spd = (v->direction & 1) ? 192 : 256;
 
	if (j < adv_spd) {
 
		/* if the vehicle has speed 0, update the last_speed field. */
 
		if (v->cur_speed == 0) SetLastSpeed(v, v->cur_speed);
 
	} else {
 
		TrainCheckIfLineEnds(v);
 
		/* Loop until the train has finished moving. */
 
		for (;;) {
 
			j -= adv_spd;
 
			TrainController(v, NULL);
 
			/* Don't continue to move if the train crashed. */
 
			if (CheckTrainCollision(v)) break;
 
			/* 192 spd used for going straight, 256 for going diagonally. */
 
			adv_spd = (v->direction & 1) ? 192 : 256;
 

	
 
			/* No more moving this tick */
 
			if (j < adv_spd || v->cur_speed == 0) break;
 

	
 
			OrderType order_type = v->current_order.GetType();
 
			/* Do not skip waypoints (incl. 'via' stations) when passing through at full speed. */
 
			if ((order_type == OT_GOTO_WAYPOINT || order_type == OT_GOTO_STATION) &&
src/vehicle_gui.cpp
Show inline comments
 
@@ -1938,48 +1938,49 @@ public:
 
			case VVW_WIDGET_FORCE_PROCEED:
 
				if (v->type != VEH_TRAIN) {
 
					size->height = 0;
 
					size->width = 0;
 
				} break;
 

	
 
			case VVW_WIDGET_VIEWPORT:
 
				size->width = VV_INITIAL_VIEWPORT_WIDTH;
 
				size->height = (v->type == VEH_TRAIN) ? VV_INITIAL_VIEWPORT_HEIGHT_TRAIN : VV_INITIAL_VIEWPORT_HEIGHT;
 
				break;
 
		}
 
	}
 

	
 
	virtual void OnPaint()
 
	{
 
		const Vehicle *v = Vehicle::Get(this->window_number);
 
		bool is_localcompany = v->owner == _local_company;
 
		bool refitable_and_stopped_in_depot = IsVehicleRefitable(v);
 

	
 
		this->SetWidgetDisabledState(VVW_WIDGET_GOTO_DEPOT, !is_localcompany);
 
		this->SetWidgetDisabledState(VVW_WIDGET_REFIT_VEH, !refitable_and_stopped_in_depot || !is_localcompany);
 
		this->SetWidgetDisabledState(VVW_WIDGET_CLONE_VEH, !is_localcompany);
 

	
 
		if (v->type == VEH_TRAIN) {
 
			this->SetWidgetLoweredState(VVW_WIDGET_FORCE_PROCEED, Train::From(v)->force_proceed == 2);
 
			this->SetWidgetDisabledState(VVW_WIDGET_FORCE_PROCEED, !is_localcompany);
 
			this->SetWidgetDisabledState(VVW_WIDGET_TURN_AROUND, !is_localcompany);
 
		}
 

	
 
		this->DrawWidgets();
 
	}
 

	
 
	virtual void SetStringParameters(int widget) const
 
	{
 
		if (widget != VVW_WIDGET_CAPTION) return;
 

	
 
		const Vehicle *v = Vehicle::Get(this->window_number);
 
		SetDParam(0, v->index);
 
	}
 

	
 
	virtual void DrawWidget(const Rect &r, int widget) const
 
	{
 
		if (widget != VVW_WIDGET_START_STOP_VEH) return;
 

	
 
		const Vehicle *v = Vehicle::Get(this->window_number);
 
		StringID str;
 
		if (v->vehstatus & VS_CRASHED) {
 
			str = STR_VEHICLE_STATUS_CRASHED;
 
		} else if (v->type != VEH_AIRCRAFT && v->breakdown_ctr == 1) { // check for aircraft necessary?
0 comments (0 inline, 0 general)