diff --git a/aircraft_cmd.c b/aircraft_cmd.c --- a/aircraft_cmd.c +++ b/aircraft_cmd.c @@ -1302,8 +1302,6 @@ static void AircraftEnterHangar(Vehicle ServiceAircraft(v); InvalidateWindowClasses(WC_AIRCRAFT_LIST); - v = MaybeReplaceVehicle(v); - TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT); if (v->current_order.type == OT_GOTO_DEPOT) { diff --git a/engine.c b/engine.c --- a/engine.c +++ b/engine.c @@ -718,6 +718,12 @@ static void DoTriggerVehicle(Vehicle *ve (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; diff --git a/roadveh_cmd.c b/roadveh_cmd.c --- a/roadveh_cmd.c +++ b/roadveh_cmd.c @@ -1522,8 +1522,6 @@ void RoadVehEnterDepot(Vehicle *v) InvalidateWindow(WC_VEHICLE_DETAILS, v->index); - v = MaybeReplaceVehicle(v); - VehicleServiceInDepot(v); TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT); diff --git a/ship_cmd.c b/ship_cmd.c --- a/ship_cmd.c +++ b/ship_cmd.c @@ -414,8 +414,6 @@ static void ShipEnterDepot(Vehicle *v) InvalidateWindow(WC_VEHICLE_DETAILS, v->index); - v = MaybeReplaceVehicle(v); - TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT); if (v->current_order.type == OT_GOTO_DEPOT) { diff --git a/train_cmd.c b/train_cmd.c --- a/train_cmd.c +++ b/train_cmd.c @@ -3328,8 +3328,6 @@ void TrainEnterDepot(Vehicle *v, TileInd 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) { diff --git a/vehicle.c b/vehicle.c --- a/vehicle.c +++ b/vehicle.c @@ -264,6 +264,7 @@ static Vehicle *InitializeVehicle(Vehicl 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 @@ -515,6 +516,24 @@ 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, @@ -529,9 +548,21 @@ 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; } } @@ -1566,18 +1597,21 @@ static int32 ReplaceVehicle(Vehicle **w, * 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; @@ -1626,8 +1660,9 @@ Vehicle * MaybeReplaceVehicle(Vehicle *v 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) { @@ -1641,9 +1676,9 @@ Vehicle * MaybeReplaceVehicle(Vehicle *v 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; } diff --git a/vehicle.h b/vehicle.h --- a/vehicle.h +++ b/vehicle.h @@ -153,6 +153,7 @@ struct Vehicle { 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 @@ -164,6 +165,7 @@ struct Vehicle { int32 x_pos; // coordinates int32 y_pos; + byte z_pos; byte direction; // facing @@ -240,6 +242,8 @@ struct Vehicle { int32 profit_last_year; uint32 value; + + union { VehicleRail rail; VehicleAir air; @@ -309,7 +313,7 @@ Vehicle *CheckClickOnVehicle(const ViewP 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);