Changeset - r2574:7236c646b1d7
[Not reviewed]
master
0 7 0
bjarni - 18 years ago 2005-10-31 12:59:47
bjarni@openttd.org
(svn r3111) -Fix: [autoreplace] [ 1341783 ] Assertion failure in vehicle.c line 378
running MaybeReplaceVehicle() is now delayed until after the loop in CallVehicleTicks()
This avoids selling the vehicle the loop currently works with (and continues to work with afterwards)
7 files changed with 54 insertions and 17 deletions:
0 comments (0 inline, 0 general)
aircraft_cmd.c
Show inline comments
 
@@ -1299,14 +1299,12 @@ static void AircraftEnterHangar(Vehicle 
 
{
 
	Order old_order;
 

	
 
	ServiceAircraft(v);
 
	InvalidateWindowClasses(WC_AIRCRAFT_LIST);
 

	
 
	v = MaybeReplaceVehicle(v);
 

	
 
	TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
 

	
 
	if (v->current_order.type == OT_GOTO_DEPOT) {
 
		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
 

	
 
		old_order = v->current_order;
engine.c
Show inline comments
 
@@ -715,12 +715,18 @@ static void DoTriggerVehicle(Vehicle *ve
 
	if (group == NULL && veh->cargo_type != GC_DEFAULT) {
 
		// This group turned out to be empty but perhaps there'll be a default one.
 
		group = TriggerVehicleSpriteGroup(engine_custom_sprites[veh->engine_type][GC_DEFAULT], veh, 0,
 
		                                  (resolve_callback) TriggerVehicleSpriteGroup);
 
	}
 

	
 
	if (trigger == VEHICLE_TRIGGER_DEPOT) {
 
		// store that the vehicle entered a depot this tick
 
		// it needs to be before all possible return statements;
 
		VehicleEnteredDepotThisTick(veh);
 
	}
 

	
 
	if (group == NULL)
 
		return;
 

	
 
	assert(group->type == SGT_REAL);
 
	rsg = &group->g.real;
 

	
roadveh_cmd.c
Show inline comments
 
@@ -1519,14 +1519,12 @@ void RoadVehEnterDepot(Vehicle *v)
 
{
 
	v->u.road.state = 254;
 
	v->vehstatus |= VS_HIDDEN;
 

	
 
	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 

	
 
	v = MaybeReplaceVehicle(v);
 

	
 
	VehicleServiceInDepot(v);
 

	
 
	TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
 

	
 
	if (v->current_order.type == OT_GOTO_DEPOT) {
 
		Order t;
ship_cmd.c
Show inline comments
 
@@ -411,14 +411,12 @@ static void ShipEnterDepot(Vehicle *v)
 
	RecalcShipStuff(v);
 

	
 
	VehicleServiceInDepot(v);
 

	
 
	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 

	
 
	v = MaybeReplaceVehicle(v);
 

	
 
	TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
 

	
 
	if (v->current_order.type == OT_GOTO_DEPOT) {
 
		Order t;
 

	
 
		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
train_cmd.c
Show inline comments
 
@@ -3325,14 +3325,12 @@ void TrainEnterDepot(Vehicle *v, TileInd
 

	
 
	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 

	
 
	v->load_unload_time_rem = 0;
 
	v->cur_speed = 0;
 

	
 
	v = MaybeReplaceVehicle(v);
 

	
 
	TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
 

	
 
	if (v->current_order.type == OT_GOTO_DEPOT) {
 
		Order t;
 

	
 
		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
vehicle.c
Show inline comments
 
@@ -261,12 +261,13 @@ static Vehicle *InitializeVehicle(Vehicl
 
	v->first = NULL;
 
	v->next = NULL;
 
	v->next_hash = INVALID_VEHICLE;
 
	v->string_id = 0;
 
	v->next_shared = NULL;
 
	v->prev_shared = NULL;
 
	v->depot_list  = NULL;
 
	/* random_bits is used to pick out a random sprite for vehicles
 
	    which are technical the same (newgrf stuff).
 
	   Because RandomRange() results in desyncs, and because it does
 
	    not really matter that one client has other visual vehicles than
 
	    the other, it can be InteractiveRandomRange() without any problem
 
	*/
 
@@ -512,12 +513,30 @@ void DeleteVehicleChain(Vehicle *v)
 
void Aircraft_Tick(Vehicle *v);
 
void RoadVeh_Tick(Vehicle *v);
 
void Ship_Tick(Vehicle *v);
 
void Train_Tick(Vehicle *v);
 
static void EffectVehicle_Tick(Vehicle *v);
 
void DisasterVehicle_Tick(Vehicle *v);
 
static void MaybeReplaceVehicle(Vehicle *v);
 

	
 
// head of the linked list to tell what vehicles that visited a depot in a tick
 
Vehicle *_first_veh_in_depot_list;
 

	
 
/** Adds a vehicle to the list of vehicles, that visited a depot this tick
 
* @param *v vehicle to add
 
*/
 
void VehicleEnteredDepotThisTick(Vehicle *v)
 
{
 
	if (_first_veh_in_depot_list == NULL) {
 
		_first_veh_in_depot_list = v;
 
	} else {
 
		Vehicle *w = _first_veh_in_depot_list;
 
		while (w->depot_list != NULL) w = w->depot_list;
 
		w->depot_list = v;
 
	}
 
}
 

	
 
VehicleTickProc *_vehicle_tick_procs[] = {
 
	Train_Tick,
 
	RoadVeh_Tick,
 
	Ship_Tick,
 
	Aircraft_Tick,
 
@@ -526,15 +545,27 @@ VehicleTickProc *_vehicle_tick_procs[] =
 
};
 

	
 
void CallVehicleTicks(void)
 
{
 
	Vehicle *v;
 

	
 
	_first_veh_in_depot_list = NULL;	// now we are sure it's initialized at the start of each tick
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type != 0)
 
		if (v->type != 0) {
 
			_vehicle_tick_procs[v->type - 0x10](v);
 
		}
 
	}
 

	
 
	// now we handle all the vehicles that entered a depot this tick
 
	v = _first_veh_in_depot_list;
 
	while (v != NULL) {
 
		Vehicle *w = v->depot_list;
 
		v->depot_list = NULL;	// it should always be NULL at the end of each tick
 
		MaybeReplaceVehicle(v);
 
		v = w;
 
	}
 
}
 

	
 
static bool CanFillVehicle_FullLoadAny(Vehicle *v)
 
{
 
	uint32 full = 0, not_full = 0;
 
@@ -1563,24 +1594,27 @@ static int32 ReplaceVehicle(Vehicle **w,
 

	
 
/** replaces a vehicle if it's set for autoreplace or is too old(used to be called autorenew)
 
* @param v The vehicle to replace
 
*	if the vehicle is a train, v needs to be the front engine
 
*	return value is a pointer to the new vehicle, which is the same as the argument if nothing happened
 
*/
 
Vehicle * MaybeReplaceVehicle(Vehicle *v)
 
static void MaybeReplaceVehicle(Vehicle *v)
 
{
 
	Vehicle *w;
 
	const Player *p = GetPlayer(v->owner);
 
	byte flags = 0;
 
	int32 cost = 0, temp_cost = 0;
 
	bool stopped = false;
 

	
 
	_current_player = v->owner;
 

	
 
	assert(v->type == VEH_Train || v->type == VEH_Road || v->type == VEH_Ship || v->type == VEH_Aircraft);
 

	
 
	DoCommand(0, 0, v->index, 0, DC_EXEC, CMD_STARTSTOP_VEH(v->type));
 
	if (!(v->vehstatus&VS_STOPPED)) {
 
		stopped = true;	// we stop the vehicle to do this, so we have to remember to start it again when we are done
 
		DoCommand(0, 0, v->index, 0, DC_EXEC, CMD_STARTSTOP_VEH(v->type));
 
	}
 

	
 
	while (true) {
 
		w = v;
 
		do {
 
			// check if the vehicle should be replaced
 
			if (!p->engine_renew || w->age - w->max_age < (p->engine_renew_months * 30)		//replace if engine is too old
 
@@ -1623,14 +1657,15 @@ Vehicle * MaybeReplaceVehicle(Vehicle *v
 
						// This should never happen
 
					default: NOT_REACHED(); message = 0; break;
 
				}
 

	
 
				AddNewsItem(message, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
 
			}
 
			DoCommand(0, 0, v->index, 0, DC_EXEC, CMD_STARTSTOP_VEH(v->type));	//we start the vehicle again
 
			return v;
 
			if (stopped)
 
				DoCommand(0, 0, v->index, 0, DC_EXEC, CMD_STARTSTOP_VEH(v->type));	//we start the vehicle again
 
			return;
 
		}
 

	
 
		if (flags & DC_EXEC) {
 
			break;	// we are done replacing since the loop ran once with DC_EXEC
 
		}
 
		// now we redo the loop, but this time we actually do stuff since we know that we can do it
 
@@ -1638,15 +1673,15 @@ Vehicle * MaybeReplaceVehicle(Vehicle *v
 
	}
 

	
 
	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
 
	SubtractMoneyFromPlayer(cost);
 
	if (IsLocalPlayer()) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost);
 

	
 
	DoCommand(0, 0, v->index, 0, DC_EXEC, CMD_STARTSTOP_VEH(v->type));	//we start the vehicle again
 
	if (stopped)
 
		DoCommand(0, 0, v->index, 0, DC_EXEC, CMD_STARTSTOP_VEH(v->type));	//we start the vehicle again
 
	_current_player = OWNER_NONE;
 
	return v;
 
}
 

	
 

	
 
/** Give a custom name to your vehicle
 
 * @param x,y unused
 
 * @param p1 vehicle ID to name
vehicle.h
Show inline comments
 
@@ -150,23 +150,25 @@ struct Vehicle {
 
	byte subtype;     // subtype (Filled with values from EffectVehicles or TrainSubTypes)(Filled with values from EffectVehicles or TrainSubTypes)
 

	
 
	VehicleID index;	// NOSAVE: Index in vehicle array
 

	
 
	Vehicle *next;		// next
 
	Vehicle *first;   // NOSAVE: pointer to the first vehicle in the chain
 
	Vehicle *depot_list;	//NOSAVE: linked list to tell what vehicles entered a depot during the last tick. Used by autoreplace
 

	
 
	StringID string_id; // Displayed string
 

	
 
	UnitID unitnumber;	// unit number, for display purposes only
 
	PlayerID owner;				// which player owns the vehicle?
 

	
 
	TileIndex tile;		// Current tile index
 
	TileIndex dest_tile; // Heading for this tile
 

	
 
	int32 x_pos;			// coordinates
 
	int32 y_pos;
 

	
 
	byte z_pos;
 
	byte direction;		// facing
 

	
 
	byte spritenum; // currently displayed sprite index
 
	                // 0xfd == custom sprite, 0xfe == custom second head sprite
 
	                // 0xff == reserved for another custom sprite
 
@@ -237,12 +239,14 @@ struct Vehicle {
 
	uint16 load_unload_time_rem;
 

	
 
	int32 profit_this_year;
 
	int32 profit_last_year;
 
	uint32 value;
 

	
 

	
 

	
 
	union {
 
		VehicleRail rail;
 
		VehicleAir air;
 
		VehicleRoad road;
 
		VehicleSpecial special;
 
		VehicleDisaster disaster;
 
@@ -306,13 +310,13 @@ void SetSignalsOnBothDir(TileIndex tile,
 

	
 
Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y);
 

	
 
void DecreaseVehicleValue(Vehicle *v);
 
void CheckVehicleBreakdown(Vehicle *v);
 
void AgeVehicle(Vehicle *v);
 
Vehicle * MaybeReplaceVehicle(Vehicle *v);
 
void VehicleEnteredDepotThisTick(Vehicle *v);
 

	
 
void BeginVehicleMove(Vehicle *v);
 
void EndVehicleMove(Vehicle *v);
 

	
 
bool IsAircraftHangarTile(TileIndex tile);
 
void ShowAircraftViewWindow(const Vehicle* v);
0 comments (0 inline, 0 general)