File diff r13023:9f6499c8d4fb → r13024:48c81d0b078a
src/roadveh_cmd.cpp
Show inline comments
 
@@ -274,49 +274,49 @@ CommandCost CmdBuildRoadVeh(TileIndex ti
 
		v->compatible_roadtypes = RoadTypeToRoadTypes(v->roadtype);
 
		v->rcache.cached_veh_length = 8;
 

	
 
		v->vehicle_flags = 0;
 
		if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
 

	
 
		v->cargo_cap = rvi->capacity;
 

	
 
		AddArticulatedParts(v, VEH_ROAD);
 
		v->InvalidateNewGRFCacheOfChain();
 

	
 
		/* Call various callbacks after the whole consist has been constructed */
 
		for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
 
			u->rcache.cached_veh_length = GetRoadVehLength(u);
 
			/* Cargo capacity is zero if and only if the vehicle cannot carry anything */
 
			if (u->cargo_cap != 0) u->cargo_cap = GetVehicleProperty(u, 0x0F, u->cargo_cap);
 
			v->InvalidateNewGRFCache();
 
			u->InvalidateNewGRFCache();
 
		}
 

	
 
		VehicleMove(v, false);
 

	
 
		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
 
		InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 
		InvalidateWindow(WC_COMPANY, v->owner);
 
		SetWindowDirty(WC_COMPANY, v->owner);
 
		if (IsLocalCompany()) {
 
			InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Road window
 
		}
 

	
 
		Company::Get(_current_company)->num_engines[p1]++;
 

	
 
		CheckConsistencyOfArticulatedVehicle(v);
 
	}
 

	
 
	return cost;
 
}
 

	
 
void ClearSlot(RoadVehicle *v)
 
{
 
	RoadStop *rs = v->slot;
 
	if (v->slot == NULL) return;
 

	
 
	v->slot = NULL;
 
	v->slot_age = 0;
 

	
 
	assert(rs->num_vehicles != 0);
 
	rs->num_vehicles--;
 

	
 
	DEBUG(ms, 3, "Clearing slot at 0x%X", rs->xy);
 
@@ -599,109 +599,109 @@ static Vehicle *EnumCheckRoadVehCrashTra
 
	return
 
		v->type == VEH_TRAIN &&
 
		abs(v->z_pos - u->z_pos) <= 6 &&
 
		abs(v->x_pos - u->x_pos) <= 4 &&
 
		abs(v->y_pos - u->y_pos) <= 4 ?
 
			v : NULL;
 
}
 

	
 
static void RoadVehCrash(RoadVehicle *v)
 
{
 
	uint16 pass = 1;
 

	
 
	v->crashed_ctr++;
 

	
 
	for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
		if (IsCargoInClass(u->cargo_type, CC_PASSENGERS)) pass += u->cargo.Count();
 

	
 
		u->vehstatus |= VS_CRASHED;
 

	
 
		MarkSingleVehicleDirty(u);
 
	}
 

	
 
	ClearSlot(v);
 

	
 
	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
	SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 

	
 
	AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING));
 

	
 
	SetDParam(0, pass);
 
	AddVehicleNewsItem(
 
		(pass == 1) ?
 
			STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER : STR_NEWS_ROAD_VEHICLE_CRASH,
 
		NS_ACCIDENT,
 
		v->index
 
	);
 

	
 
	ModifyStationRatingAround(v->tile, v->owner, -160, 22);
 
	SndPlayVehicleFx(SND_12_EXPLOSION, v);
 
}
 

	
 
static bool RoadVehCheckTrainCrash(RoadVehicle *v)
 
{
 
	for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
 
		if (u->state == RVSB_WORMHOLE) continue;
 

	
 
		TileIndex tile = u->tile;
 

	
 
		if (!IsLevelCrossingTile(tile)) continue;
 

	
 
		if (HasVehicleOnPosXY(v->x_pos, v->y_pos, u, EnumCheckRoadVehCrashTrain)) {
 
			RoadVehCrash(v);
 
			return true;
 
		}
 
	}
 

	
 
	return false;
 
}
 

	
 
static void HandleBrokenRoadVeh(RoadVehicle *v)
 
{
 
	if (v->breakdown_ctr != 1) {
 
		v->breakdown_ctr = 1;
 
		v->cur_speed = 0;
 

	
 
		if (v->breakdowns_since_last_service != 255)
 
			v->breakdowns_since_last_service++;
 

	
 
		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
 
		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 
		SetWindowDirty(WC_VEHICLE_VIEW, v->index);
 
		SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
 

	
 
		if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
 
			SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
 
				SND_0F_VEHICLE_BREAKDOWN : SND_35_COMEDY_BREAKDOWN, v);
 
		}
 

	
 
		if (!(v->vehstatus & VS_HIDDEN)) {
 
			EffectVehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
 
			if (u != NULL) u->animation_state = v->breakdown_delay * 2;
 
		}
 
	}
 

	
 
	if ((v->tick_counter & 1) == 0) {
 
		if (--v->breakdown_delay == 0) {
 
			v->breakdown_ctr = 0;
 
			InvalidateWindow(WC_VEHICLE_VIEW, v->index);
 
			SetWindowDirty(WC_VEHICLE_VIEW, v->index);
 
		}
 
	}
 
}
 

	
 
TileIndex RoadVehicle::GetOrderStationLocation(StationID station)
 
{
 
	if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
 

	
 
	TileIndex dest;
 
	if (YapfFindNearestRoadVehicleCompatibleStop(this, station, &dest)) {
 
		return dest;
 
	} else {
 
		/* There is no stop left at the station, so don't even TRY to go there */
 
		this->IncrementOrderIndex();
 
		return 0;
 
	}
 
}
 

	
 
static void StartRoadVehSound(const RoadVehicle *v)
 
{
 
	if (!PlayVehicleSound(v, VSE_START)) {
 
		SoundID s = RoadVehInfo(v->engine_type)->sfx;
 
		if (s == SND_19_BUS_START_PULL_AWAY && (v->tick_counter & 3) == 0)
 
			s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
 
@@ -815,49 +815,49 @@ static void RoadVehArrivesAt(const RoadV
 

	
 
static int RoadVehAccelerate(RoadVehicle *v)
 
{
 
	uint oldspeed = v->cur_speed;
 
	uint accel = 256 + (v->overtaking != 0 ? 256 : 0);
 
	uint spd = v->subspeed + accel;
 

	
 
	v->subspeed = (uint8)spd;
 

	
 
	int tempmax = v->max_speed;
 
	if (v->cur_speed > v->max_speed) {
 
		tempmax = v->cur_speed - (v->cur_speed / 10) - 1;
 
	}
 

	
 
	v->cur_speed = spd = Clamp(v->cur_speed + ((int)spd >> 8), 0, tempmax);
 

	
 
	/* Apply bridge speed limit */
 
	if (v->state == RVSB_WORMHOLE && !(v->vehstatus & VS_HIDDEN)) {
 
		v->cur_speed = min(v->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed * 2);
 
	}
 

	
 
	/* Update statusbar only if speed has changed to save CPU time */
 
	if (oldspeed != v->cur_speed) {
 
		if (_settings_client.gui.vehicle_speed) {
 
			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
			SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
		}
 
	}
 

	
 
	/* Speed is scaled in the same manner as for trains. @see train_cmd.cpp */
 
	int scaled_spd = spd * 3 >> 2;
 

	
 
	scaled_spd += v->progress;
 
	v->progress = 0;
 
	return scaled_spd;
 
}
 

	
 
static Direction RoadVehGetNewDirection(const RoadVehicle *v, int x, int y)
 
{
 
	static const Direction _roadveh_new_dir[] = {
 
		DIR_N , DIR_NW, DIR_W , INVALID_DIR,
 
		DIR_NE, DIR_N , DIR_SW, INVALID_DIR,
 
		DIR_E , DIR_SE, DIR_S
 
	};
 

	
 
	x = x - v->x_pos + 1;
 
	y = y - v->y_pos + 1;
 

	
 
	if ((uint)x > 2 || (uint)y > 2) return v->direction;
 
	return _roadveh_new_dir[y * 4 + x];
 
@@ -1709,49 +1709,49 @@ again:
 
		} else if (v->slot != NULL) {
 
			/* We are leaving the wrong station
 
			 * XXX The question is .. what to do? Actually we shouldn't be here
 
			 * but I guess we need to clear the slot */
 
			DEBUG(ms, 0, "Vehicle %d (index %d) arrived at wrong stop", v->unitnumber, v->index);
 
			if (v->tile != v->dest_tile) {
 
				DEBUG(ms, 2, " current tile 0x%X is not destination tile 0x%X. Route problem", v->tile, v->dest_tile);
 
			}
 
			if (v->dest_tile != v->slot->xy) {
 
				DEBUG(ms, 2, " stop tile 0x%X is not destination tile 0x%X. Multistop desync", v->slot->xy, v->dest_tile);
 
			}
 
			if (!v->current_order.IsType(OT_GOTO_STATION)) {
 
				DEBUG(ms, 2, " current order type (%d) is not OT_GOTO_STATION", v->current_order.GetType());
 
			} else {
 
				if (v->current_order.GetDestination() != st->index)
 
					DEBUG(ms, 2, " current station %d is not target station in current_order.station (%d)",
 
							st->index, v->current_order.GetDestination());
 
			}
 

	
 
			DEBUG(ms, 2, " force a slot clearing");
 
			ClearSlot(v);
 
		}
 

	
 
		StartRoadVehSound(v);
 
		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
		SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
	}
 

	
 
	/* Check tile position conditions - i.e. stop position in depot,
 
	 * entry onto bridge or into tunnel */
 
	uint32 r = VehicleEnterTile(v, v->tile, x, y);
 
	if (HasBit(r, VETS_CANNOT_ENTER)) {
 
		v->cur_speed = 0;
 
		return false;
 
	}
 

	
 
	if (v->current_order.IsType(OT_LEAVESTATION) && IsDriveThroughStopTile(v->tile)) {
 
		v->current_order.Free();
 
		ClearSlot(v);
 
	}
 

	
 
	/* Move to next frame unless vehicle arrived at a stop position
 
	 * in a depot or entered a tunnel/bridge */
 
	if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->frame++;
 

	
 
	RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
 
	return true;
 
}
 

	
 
static bool RoadVehController(RoadVehicle *v)
 
@@ -1824,67 +1824,67 @@ bool RoadVehicle::Tick()
 
	}
 

	
 
	return true;
 
}
 

	
 
static void CheckIfRoadVehNeedsService(RoadVehicle *v)
 
{
 
	static const uint MAX_ACCEPTABLE_DEPOT_DIST = 16;
 

	
 
	/* If we already got a slot at a stop, use that FIRST, and go to a depot later */
 
	if (v->slot != NULL || Company::Get(v->owner)->settings.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
 
	if (v->IsInDepot()) {
 
		VehicleServiceInDepot(v);
 
		return;
 
	}
 

	
 
	RoadFindDepotData rfdd = FindClosestRoadDepot(v, MAX_ACCEPTABLE_DEPOT_DIST);
 
	/* Only go to the depot if it is not too far out of our way. */
 
	if (rfdd.best_length == UINT_MAX || rfdd.best_length > MAX_ACCEPTABLE_DEPOT_DIST) {
 
		if (v->current_order.IsType(OT_GOTO_DEPOT)) {
 
			/* If we were already heading for a depot but it has
 
			 * suddenly moved farther away, we continue our normal
 
			 * schedule? */
 
			v->current_order.MakeDummy();
 
			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
			SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
		}
 
		return;
 
	}
 

	
 
	DepotID depot = GetDepotIndex(rfdd.tile);
 

	
 
	if (v->current_order.IsType(OT_GOTO_DEPOT) &&
 
			v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS &&
 
			!Chance16(1, 20)) {
 
		return;
 
	}
 

	
 
	if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
 
	ClearSlot(v);
 

	
 
	v->current_order.MakeGoToDepot(depot, ODTFB_SERVICE);
 
	v->dest_tile = rfdd.tile;
 
	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
	SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
}
 

	
 
void RoadVehicle::OnNewDay()
 
{
 
	if (!this->IsRoadVehFront()) return;
 

	
 
	if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
 
	if (this->blocked_ctr == 0) CheckVehicleBreakdown(this);
 

	
 
	AgeVehicle(this);
 
	CheckIfRoadVehNeedsService(this);
 

	
 
	CheckOrders(this);
 

	
 
	/* Current slot has expired */
 
	if (this->current_order.IsType(OT_GOTO_STATION) && this->slot != NULL && this->slot_age-- == 0) {
 
		DEBUG(ms, 3, "Slot expired for vehicle %d (index %d) at stop 0x%X",
 
			this->unitnumber, this->index, this->slot->xy);
 
		ClearSlot(this);
 
	}
 

	
 
	/* update destination */
 
	if (!(this->vehstatus & VS_STOPPED) && this->current_order.IsType(OT_GOTO_STATION) && !(this->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) && this->slot == NULL && !(this->vehstatus & VS_CRASHED)) {
 
		Station *st = Station::Get(this->current_order.GetDestination());
 
@@ -1936,50 +1936,50 @@ void RoadVehicle::OnNewDay()
 
					this->dest_tile = best->xy;
 
					this->slot_age = 14;
 
				} else {
 
					DEBUG(ms, 3, "Could not find a suitable stop");
 
				}
 
			} else {
 
				DEBUG(ms, 5, "Distance from station too far. Postponing slotting for vehicle %d (index %d) at station %d, (0x%X)",
 
						this->unitnumber, this->index, st->index, st->xy);
 
			}
 
		} else {
 
			DEBUG(ms, 4, "No road stop for vehicle %d (index %d) at station %d (0x%X)",
 
					this->unitnumber, this->index, st->index, st->xy);
 
		}
 
	}
 

	
 
	if (this->running_ticks == 0) return;
 

	
 
	CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
 

	
 
	this->profit_this_year -= cost.GetCost();
 
	this->running_ticks = 0;
 

	
 
	SubtractMoneyFromCompanyFract(this->owner, cost);
 

	
 
	InvalidateWindow(WC_VEHICLE_DETAILS, this->index);
 
	InvalidateWindowClasses(WC_ROADVEH_LIST);
 
	SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
 
	SetWindowClassesDirty(WC_ROADVEH_LIST);
 
}
 

	
 
Trackdir RoadVehicle::GetVehicleTrackdir() const
 
{
 
	if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
 

	
 
	if (this->IsInDepot()) {
 
		/* We'll assume the road vehicle is facing outwards */
 
		return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile));
 
	}
 

	
 
	if (IsStandardRoadStopTile(this->tile)) {
 
		/* We'll assume the road vehicle is facing outwards */
 
		return DiagDirToDiagTrackdir(GetRoadStopDir(this->tile)); // Road vehicle in a station
 
	}
 

	
 
	/* Drive through road stops / wormholes (tunnels) */
 
	if (this->state > RVSB_TRACKDIR_MASK) return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
 

	
 
	/* If vehicle's state is a valid track direction (vehicle is not turning around) return it,
 
	 * otherwise transform it into a valid track direction */
 
	return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state);
 
}
 

	
 
@@ -2048,36 +2048,36 @@ CommandCost CmdRefitRoadVeh(TileIndex ti
 
				case CT_PASSENGERS: break;
 
				case CT_MAIL:
 
				case CT_GOODS: capacity *= 2; break;
 
				default:       capacity *= 4; break;
 
			}
 
			switch (new_cid) {
 
				case CT_PASSENGERS: break;
 
				case CT_MAIL:
 
				case CT_GOODS: capacity /= 2; break;
 
				default:       capacity /= 4; break;
 
			}
 
		}
 

	
 
		total_capacity += capacity;
 

	
 
		if (new_cid != v->cargo_type) {
 
			cost.AddCost(GetRefitCost(v->engine_type));
 
		}
 

	
 
		if (flags & DC_EXEC) {
 
			v->cargo_cap = capacity;
 
			v->cargo.Truncate((v->cargo_type == new_cid) ? capacity : 0);
 
			v->cargo_type = new_cid;
 
			v->cargo_subtype = new_subtype;
 
			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 
			InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
			SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
 
			SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
 
			InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 
		}
 
	}
 

	
 
	if (flags & DC_EXEC) RoadVehUpdateCache(RoadVehicle::Get(p1)->First());
 

	
 
	_returned_refit_capacity = total_capacity;
 

	
 
	return cost;
 
}