# HG changeset patch # User smatz # Date 1243000394 0 # Node ID 2286db6ac0bba31177337f46756eea40be45d910 # Parent d89c33df9b66e9cee7d64173aaf28cce747aac4c (svn r16376) -Codechange: Vehicle::Tick() now returns false if the vehicle was deleted diff --git a/src/aircraft.h b/src/aircraft.h --- a/src/aircraft.h +++ b/src/aircraft.h @@ -106,7 +106,7 @@ int GetDisplayMaxSpeed() const { return this->max_speed; } Money GetRunningCost() const; bool IsInDepot() const { return (this->vehstatus & VS_HIDDEN) != 0 && IsHangarTile(this->tile); } - void Tick(); + bool Tick(); void OnNewDay(); TileIndex GetOrderStationLocation(StationID station); bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse); diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -1137,7 +1137,7 @@ } -static void HandleCrashedAircraft(Vehicle *v) +static bool HandleCrashedAircraft(Vehicle *v) { v->u.air.crashed_counter += 3; @@ -1182,7 +1182,11 @@ } delete v; + + return false; } + + return true; } static void HandleBrokenAircraft(Vehicle *v) @@ -1988,16 +1992,15 @@ return false; // it shouldn't get here anytime, but just to be sure } -static void AircraftEventHandler(Vehicle *v, int loop) +static bool AircraftEventHandler(Vehicle *v, int loop) { v->tick_counter++; if (v->vehstatus & VS_CRASHED) { - HandleCrashedAircraft(v); - return; + return HandleCrashedAircraft(v); } - if (v->vehstatus & VS_STOPPED) return; + if (v->vehstatus & VS_STOPPED) return true; /* aircraft is broken down? */ if (v->breakdown_ctr != 0) { @@ -2012,14 +2015,16 @@ ProcessOrders(v); v->HandleLoading(loop != 0); - if (v->current_order.IsType(OT_LOADING) || v->current_order.IsType(OT_LEAVESTATION)) return; + if (v->current_order.IsType(OT_LOADING) || v->current_order.IsType(OT_LEAVESTATION)) return true; AirportGoToNextPosition(v); + + return true; } -void Aircraft::Tick() +bool Aircraft::Tick() { - if (!IsNormalAircraft(this)) return; + if (!IsNormalAircraft(this)) return true; if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++; @@ -2030,10 +2035,13 @@ this->current_order_time++; for (uint i = 0; i != 2; i++) { - AircraftEventHandler(this, i); - if (this->type != VEH_AIRCRAFT) // In case it was deleted - break; + /* stop if the aircraft was deleted */ + if (!AircraftEventHandler(this, i)) return false; + assert(this->IsValid()); + assert(IsNormalAircraft(this)); } + + return true; } diff --git a/src/disaster_cmd.cpp b/src/disaster_cmd.cpp --- a/src/disaster_cmd.cpp +++ b/src/disaster_cmd.cpp @@ -180,12 +180,12 @@ * 2: Clear the runway after some time and remove crashed zeppeliner * If not airport was found, only state 0 is reached until zeppeliner leaves map */ -static void DisasterTick_Zeppeliner(Vehicle *v) +static bool DisasterTick_Zeppeliner(Vehicle *v) { v->tick_counter++; if (v->current_order.GetDestination() < 2) { - if (HasBit(v->tick_counter, 0)) return; + if (HasBit(v->tick_counter, 0)) return true; GetNewVehiclePosResult gp = GetNewVehiclePos(v); @@ -215,12 +215,16 @@ } } - if (v->y_pos >= ((int)MapSizeY() + 9) * TILE_SIZE - 1) delete v; - return; + if (v->y_pos >= ((int)MapSizeY() + 9) * TILE_SIZE - 1) { + delete v; + return false; + } + + return true; } if (v->current_order.GetDestination() > 2) { - if (++v->age <= 13320) return; + if (++v->age <= 13320) return true; if (IsValidTile(v->tile) && IsTileType(v->tile, MP_STATION) && @@ -232,7 +236,7 @@ SetDisasterVehiclePos(v, v->x_pos, v->y_pos, v->z_pos); delete v; - return; + return false; } int x = v->x_pos; @@ -267,6 +271,8 @@ IsAirport(v->tile)) { SETBITS(GetStationByTile(v->tile)->airport_flags, RUNWAY_IN_block); } + + return true; } /** @@ -275,7 +281,7 @@ * 1: Home in on a road vehicle and crash it >:) * If not road vehicle was found, only state 0 is used and Ufo disappears after a while */ -static void DisasterTick_Ufo(Vehicle *v) +static bool DisasterTick_Ufo(Vehicle *v) { v->u.disaster.image_override = (HasBit(++v->tick_counter, 3)) ? SPR_UFO_SMALL_SCOUT_DARKER : SPR_UFO_SMALL_SCOUT; @@ -287,11 +293,11 @@ v->direction = GetDirectionTowards(v, x, y); GetNewVehiclePosResult gp = GetNewVehiclePos(v); SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); - return; + return true; } if (++v->age < 6) { v->dest_tile = RandomTile(); - return; + return true; } v->current_order.SetDestination(1); @@ -300,17 +306,18 @@ if (u->type == VEH_ROAD && IsRoadVehFront(u)) { v->dest_tile = u->index; v->age = 0; - return; + return true; } } delete v; + return false; } else { /* Target a vehicle */ Vehicle *u = Vehicle::Get(v->dest_tile); if (u->type != VEH_ROAD || !IsRoadVehFront(u)) { delete v; - return; + return false; } uint dist = Delta(v->x_pos, u->x_pos) + Delta(v->y_pos, u->y_pos); @@ -351,8 +358,11 @@ CreateEffectVehicleRel(v, 0, 7, 8, EV_EXPLOSION_LARGE); SndPlayVehicleFx(SND_12_EXPLOSION, v); delete v; + return false; } } + + return true; } static void DestructIndustry(Industry *i) @@ -378,7 +388,7 @@ * @param news_message The string that's used as news message. * @param industry_flag Only attack industries that have this flag set. */ -static void DisasterTick_Aircraft(Vehicle *v, uint16 image_override, bool leave_at_top, StringID news_message, IndustryBehaviour industry_flag) +static bool DisasterTick_Aircraft(Vehicle *v, uint16 image_override, bool leave_at_top, StringID news_message, IndustryBehaviour industry_flag) { v->tick_counter++; v->u.disaster.image_override = (v->current_order.GetDestination() == 1 && HasBit(v->tick_counter, 2)) ? image_override : 0; @@ -388,7 +398,7 @@ if ((leave_at_top && gp.x < (-10 * TILE_SIZE)) || (!leave_at_top && gp.x > (int)MapSizeX() * TILE_SIZE + 9 * TILE_SIZE - 1)) { delete v; - return; + return false; } if (v->current_order.GetDestination() == 2) { @@ -422,10 +432,10 @@ int x = v->x_pos - (15 * TILE_SIZE); int y = v->y_pos; - if ((uint)x > MapMaxX() * TILE_SIZE - 1) return; + if ((uint)x > MapMaxX() * TILE_SIZE - 1) return true; TileIndex tile = TileVirtXY(x, y); - if (!IsTileType(tile, MP_INDUSTRY)) return; + if (!IsTileType(tile, MP_INDUSTRY)) return true; IndustryID ind = GetIndustryIndex(tile); v->dest_tile = ind; @@ -435,29 +445,33 @@ v->age = 0; } } + + return true; } /** Airplane handling. */ -static void DisasterTick_Airplane(Vehicle *v) +static bool DisasterTick_Airplane(Vehicle *v) { - DisasterTick_Aircraft(v, SPR_F_15_FIRING, true, STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY, INDUSTRYBEH_AIRPLANE_ATTACKS); + return DisasterTick_Aircraft(v, SPR_F_15_FIRING, true, STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY, INDUSTRYBEH_AIRPLANE_ATTACKS); } /** Helicopter handling. */ -static void DisasterTick_Helicopter(Vehicle *v) +static bool DisasterTick_Helicopter(Vehicle *v) { - DisasterTick_Aircraft(v, SPR_AH_64A_FIRING, false, STR_NEWS_DISASTER_HELICOPTER_FACTORY, INDUSTRYBEH_CHOPPER_ATTACKS); + return DisasterTick_Aircraft(v, SPR_AH_64A_FIRING, false, STR_NEWS_DISASTER_HELICOPTER_FACTORY, INDUSTRYBEH_CHOPPER_ATTACKS); } /** Helicopter rotor blades; keep these spinning */ -static void DisasterTick_Helicopter_Rotors(Vehicle *v) +static bool DisasterTick_Helicopter_Rotors(Vehicle *v) { v->tick_counter++; - if (HasBit(v->tick_counter, 0)) return; + if (HasBit(v->tick_counter, 0)) return true; if (++v->cur_image > SPR_ROTOR_MOVING_3) v->cur_image = SPR_ROTOR_MOVING_1; VehicleMove(v, true); + + return true; } /** @@ -466,7 +480,7 @@ * 1: Land there and breakdown all trains in a radius of 12 tiles; and now we wait... * because as soon as the Ufo lands, a fighter jet, a Skyranger, is called to clear up the mess */ -static void DisasterTick_Big_Ufo(Vehicle *v) +static bool DisasterTick_Big_Ufo(Vehicle *v) { v->tick_counter++; @@ -478,19 +492,19 @@ GetNewVehiclePosResult gp = GetNewVehiclePos(v); SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); - return; + return true; } if (!IsValidTile(v->dest_tile)) { /* Make sure we don't land outside the map. */ delete v; - return; + return false; } byte z = GetSlopeZ(v->x_pos, v->y_pos); if (z < v->z_pos) { SetDisasterVehiclePos(v, v->x_pos, v->y_pos, v->z_pos - 1); - return; + return true; } v->current_order.SetDestination(2); @@ -514,7 +528,7 @@ if (!Vehicle::CanAllocateItem(2)) { delete v; - return; + return false; } u = new DisasterVehicle(); @@ -533,12 +547,12 @@ v->direction = GetDirectionTowards(v, x, y); GetNewVehiclePosResult gp = GetNewVehiclePos(v); SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); - return; + return true; } if (++v->age < 6) { v->dest_tile = RandomTile(); - return; + return true; } v->current_order.SetDestination(1); @@ -554,13 +568,15 @@ v->dest_tile = tile; v->age = 0; } + + return true; } /** * Skyranger destroying (Big) Ufo handling, v->current_order.dest states: * 0: Home in on landed Ufo and shoot it down */ -static void DisasterTick_Big_Ufo_Destroyer(Vehicle *v) +static bool DisasterTick_Big_Ufo_Destroyer(Vehicle *v) { v->tick_counter++; @@ -569,12 +585,12 @@ if (gp.x > (int)MapSizeX() * TILE_SIZE + 9 * TILE_SIZE - 1) { delete v; - return; + return false; } if (v->current_order.GetDestination() == 0) { Vehicle *u = Vehicle::Get(v->u.disaster.big_ufo_destroyer_target); - if (Delta(v->x_pos, u->x_pos) > TILE_SIZE) return; + if (Delta(v->x_pos, u->x_pos) > TILE_SIZE) return true; v->current_order.SetDestination(1); CreateEffectVehicleRel(u, 0, 7, 8, EV_EXPLOSION_LARGE); @@ -598,22 +614,24 @@ } } } + + return true; } /** * Submarine, v->current_order.dest states: * Unused, just float around aimlessly and pop up at different places, turning around */ -static void DisasterTick_Submarine(Vehicle *v) +static bool DisasterTick_Submarine(Vehicle *v) { v->tick_counter++; if (++v->age > 8880) { delete v; - return; + return false; } - if (!HasBit(v->tick_counter, 0)) return; + if (!HasBit(v->tick_counter, 0)) return true; TileIndex tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction)); if (IsValidTile(tile)) { @@ -621,16 +639,22 @@ if (trackbits == TRACK_BIT_ALL && !Chance16(1, 90)) { GetNewVehiclePosResult gp = GetNewVehiclePos(v); SetDisasterVehiclePos(v, gp.x, gp.y, v->z_pos); - return; + return true; } } v->direction = ChangeDir(v->direction, GB(Random(), 0, 1) ? DIRDIFF_90RIGHT : DIRDIFF_90LEFT); + + return true; } -static void DisasterTick_NULL(Vehicle *v) {} -typedef void DisasterVehicleTickProc(Vehicle *v); +static bool DisasterTick_NULL(Vehicle *v) +{ + return true; +} + +typedef bool DisasterVehicleTickProc(Vehicle *v); static DisasterVehicleTickProc * const _disastervehicle_tick_procs[] = { DisasterTick_Zeppeliner, DisasterTick_NULL, @@ -644,9 +668,9 @@ }; -void DisasterVehicle::Tick() +bool DisasterVehicle::Tick() { - _disastervehicle_tick_procs[this->subtype](this); + return _disastervehicle_tick_procs[this->subtype](this); } typedef void DisasterInitProc(); diff --git a/src/effectvehicle.cpp b/src/effectvehicle.cpp --- a/src/effectvehicle.cpp +++ b/src/effectvehicle.cpp @@ -20,7 +20,7 @@ v->progress = GB(r, 16, 3); } -static void ChimneySmokeTick(Vehicle *v) +static bool ChimneySmokeTick(Vehicle *v) { if (v->progress > 0) { v->progress--; @@ -28,7 +28,7 @@ TileIndex tile = TileVirtXY(v->x_pos, v->y_pos); if (!IsTileType(tile, MP_INDUSTRY)) { delete v; - return; + return false; } if (v->cur_image != SPR_CHIMNEY_SMOKE_7) { @@ -39,6 +39,8 @@ v->progress = 7; VehicleMove(v, true); } + + return true; } static void SteamSmokeInit(Vehicle *v) @@ -47,7 +49,7 @@ v->progress = 12; } -static void SteamSmokeTick(Vehicle *v) +static bool SteamSmokeTick(Vehicle *v) { bool moved = false; @@ -63,12 +65,14 @@ v->cur_image++; } else { delete v; - return; + return false; } moved = true; } if (moved) VehicleMove(v, true); + + return true; } static void DieselSmokeInit(Vehicle *v) @@ -77,7 +81,7 @@ v->progress = 0; } -static void DieselSmokeTick(Vehicle *v) +static bool DieselSmokeTick(Vehicle *v) { v->progress++; @@ -90,8 +94,11 @@ VehicleMove(v, true); } else { delete v; + return false; } } + + return true; } static void ElectricSparkInit(Vehicle *v) @@ -100,7 +107,7 @@ v->progress = 1; } -static void ElectricSparkTick(Vehicle *v) +static bool ElectricSparkTick(Vehicle *v) { if (v->progress < 2) { v->progress++; @@ -111,8 +118,11 @@ VehicleMove(v, true); } else { delete v; + return false; } } + + return true; } static void SmokeInit(Vehicle *v) @@ -121,7 +131,7 @@ v->progress = 12; } -static void SmokeTick(Vehicle *v) +static bool SmokeTick(Vehicle *v) { bool moved = false; @@ -137,12 +147,14 @@ v->cur_image++; } else { delete v; - return; + return false; } moved = true; } if (moved) VehicleMove(v, true); + + return true; } static void ExplosionLargeInit(Vehicle *v) @@ -151,7 +163,7 @@ v->progress = 0; } -static void ExplosionLargeTick(Vehicle *v) +static bool ExplosionLargeTick(Vehicle *v) { v->progress++; if ((v->progress & 3) == 0) { @@ -160,8 +172,11 @@ VehicleMove(v, true); } else { delete v; + return false; } } + + return true; } static void BreakdownSmokeInit(Vehicle *v) @@ -170,7 +185,7 @@ v->progress = 0; } -static void BreakdownSmokeTick(Vehicle *v) +static bool BreakdownSmokeTick(Vehicle *v) { v->progress++; if ((v->progress & 7) == 0) { @@ -185,7 +200,10 @@ v->u.effect.animation_state--; if (v->u.effect.animation_state == 0) { delete v; + return false; } + + return true; } static void ExplosionSmallInit(Vehicle *v) @@ -194,7 +212,7 @@ v->progress = 0; } -static void ExplosionSmallTick(Vehicle *v) +static bool ExplosionSmallTick(Vehicle *v) { v->progress++; if ((v->progress & 3) == 0) { @@ -203,8 +221,11 @@ VehicleMove(v, true); } else { delete v; + return false; } } + + return true; } static void BulldozerInit(Vehicle *v) @@ -254,7 +275,7 @@ { 0, -1 } }; -static void BulldozerTick(Vehicle *v) +static bool BulldozerTick(Vehicle *v) { v->progress++; if ((v->progress & 7) == 0) { @@ -271,11 +292,13 @@ v->u.effect.animation_state++; if (v->u.effect.animation_state == lengthof(_bulldozer_movement)) { delete v; - return; + return false; } } VehicleMove(v, true); } + + return true; } static void BubbleInit(Vehicle *v) @@ -435,18 +458,18 @@ _bubble_absorb, }; -static void BubbleTick(Vehicle *v) +static bool BubbleTick(Vehicle *v) { uint anim_state; v->progress++; - if ((v->progress & 3) != 0) return; + if ((v->progress & 3) != 0) return true; if (v->spritenum == 0) { v->cur_image++; if (v->cur_image < SPR_BUBBLE_GENERATE_3) { VehicleMove(v, true); - return; + return true; } if (v->u.effect.animation_substate != 0) { v->spritenum = GB(Random(), 0, 2) + 1; @@ -462,7 +485,7 @@ if (b->y == 4 && b->x == 0) { delete v; - return; + return false; } if (b->y == 4 && b->x == 1) { @@ -492,11 +515,13 @@ v->cur_image = SPR_BUBBLE_0 + b->image; VehicleMove(v, true); + + return true; } typedef void EffectInitProc(Vehicle *v); -typedef void EffectTickProc(Vehicle *v); +typedef bool EffectTickProc(Vehicle *v); static EffectInitProc * const _effect_init_procs[] = { ChimneySmokeInit, @@ -558,9 +583,9 @@ return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type); } -void EffectVehicle::Tick() +bool EffectVehicle::Tick() { - _effect_tick_procs[this->subtype](this); + return _effect_tick_procs[this->subtype](this); } void EffectVehicle::UpdateDeltaXY(Direction direction) diff --git a/src/effectvehicle_base.h b/src/effectvehicle_base.h --- a/src/effectvehicle_base.h +++ b/src/effectvehicle_base.h @@ -31,7 +31,7 @@ const char *GetTypeString() const { return "special vehicle"; } void UpdateDeltaXY(Direction direction); - void Tick(); + bool Tick(); }; #endif /* EFFECTVEHICLE_BASE_H */ diff --git a/src/roadveh.h b/src/roadveh.h --- a/src/roadveh.h +++ b/src/roadveh.h @@ -99,7 +99,7 @@ Money GetRunningCost() const { return RoadVehInfo(this->engine_type)->running_cost * GetPriceByIndex(RoadVehInfo(this->engine_type)->running_cost_class); } bool IsInDepot() const { return this->u.road.state == RVSB_IN_DEPOT; } bool IsStoppedInDepot() const; - void Tick(); + bool Tick(); void OnNewDay(); TileIndex GetOrderStationLocation(StationID station); bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse); diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -540,7 +540,7 @@ } while ((v = v->Next()) != NULL); } -static void RoadVehIsCrashed(Vehicle *v) +static bool RoadVehIsCrashed(Vehicle *v) { v->u.road.crashed_ctr++; if (v->u.road.crashed_ctr == 2) { @@ -548,8 +548,12 @@ } else if (v->u.road.crashed_ctr <= 45) { if ((v->tick_counter & 7) == 0) RoadVehSetRandomDirection(v); } else if (v->u.road.crashed_ctr >= 2220 && !(v->tick_counter & 0x1F)) { + bool ret = v->Next() != NULL; DeleteLastRoadVeh(v); + return ret; } + + return true; } static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data) @@ -1735,7 +1739,7 @@ return true; } -static void RoadVehController(Vehicle *v) +static bool RoadVehController(Vehicle *v) { /* decrease counters */ v->tick_counter++; @@ -1744,8 +1748,7 @@ /* handle crashed */ if (v->vehstatus & VS_CRASHED) { - RoadVehIsCrashed(v); - return; + return RoadVehIsCrashed(v); } RoadVehCheckTrainCrash(v); @@ -1754,19 +1757,19 @@ if (v->breakdown_ctr != 0) { if (v->breakdown_ctr <= 2) { HandleBrokenRoadVeh(v); - return; + return true; } if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--; } - if (v->vehstatus & VS_STOPPED) return; + if (v->vehstatus & VS_STOPPED) return true; ProcessOrders(v); v->HandleLoading(); - if (v->current_order.IsType(OT_LOADING)) return; + if (v->current_order.IsType(OT_LOADING)) return true; - if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return; + if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return true; /* Check how far the vehicle needs to proceed */ int j = RoadVehAccelerate(v); @@ -1796,6 +1799,8 @@ } if (v->progress == 0) v->progress = j; + + return true; } static void AgeRoadVehCargo(Vehicle *v) @@ -1804,14 +1809,16 @@ v->cargo.AgeCargo(); } -void RoadVehicle::Tick() +bool RoadVehicle::Tick() { AgeRoadVehCargo(this); if (IsRoadVehFront(this)) { if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++; - RoadVehController(this); + return RoadVehController(this); } + + return true; } static void CheckIfRoadVehNeedsService(Vehicle *v) diff --git a/src/ship.h b/src/ship.h --- a/src/ship.h +++ b/src/ship.h @@ -40,7 +40,7 @@ int GetDisplayMaxSpeed() const { return this->max_speed / 2; } Money GetRunningCost() const; bool IsInDepot() const { return this->u.ship.state == TRACK_BIT_DEPOT; } - void Tick(); + bool Tick(); void OnNewDay(); TileIndex GetOrderStationLocation(StationID station); bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse); diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -708,12 +708,14 @@ v->cargo.AgeCargo(); } -void Ship::Tick() +bool Ship::Tick() { if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++; AgeShipCargo(this); ShipController(this); + + return true; } /** Build a ship. diff --git a/src/train.h b/src/train.h --- a/src/train.h +++ b/src/train.h @@ -329,7 +329,7 @@ Money GetRunningCost() const; bool IsInDepot() const { return CheckTrainInDepot(this, false) != -1; } bool IsStoppedInDepot() const { return CheckTrainStoppedInDepot(this) >= 0; } - void Tick(); + bool Tick(); void OnNewDay(); TileIndex GetOrderStationLocation(StationID station); bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -4022,7 +4022,7 @@ } while ((v = v->Next()) != NULL); } -static void HandleCrashedTrain(Vehicle *v) +static bool HandleCrashedTrain(Vehicle *v) { int state = ++v->u.rail.crash_anim_pos; @@ -4052,9 +4052,13 @@ if (state <= 240 && !(v->tick_counter & 3)) ChangeTrainDirRandomly(v); if (state >= 4440 && !(v->tick_counter & 0x1F)) { + bool ret = v->Next() != NULL; DeleteLastWagon(v); InvalidateWindow(WC_REPLACE_VEHICLE, (v->group_id << 16) | VEH_TRAIN); + return ret; } + + return true; } static void HandleBrokenTrain(Vehicle *v) @@ -4249,12 +4253,11 @@ } -static void TrainLocoHandler(Vehicle *v, bool mode) +static bool TrainLocoHandler(Vehicle *v, bool mode) { /* train has crashed? */ if (v->vehstatus & VS_CRASHED) { - if (!mode) HandleCrashedTrain(v); - return; + return mode ? true : HandleCrashedTrain(v); // 'this' can be deleted here } if (v->u.rail.force_proceed != 0) { @@ -4267,7 +4270,7 @@ if (v->breakdown_ctr != 0) { if (v->breakdown_ctr <= 2) { HandleBrokenTrain(v); - return; + return true; } if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--; } @@ -4277,7 +4280,7 @@ } /* exit if train is stopped */ - if (v->vehstatus & VS_STOPPED && v->cur_speed == 0) return; + if (v->vehstatus & VS_STOPPED && v->cur_speed == 0) return true; bool valid_order = v->current_order.IsValid() && v->current_order.GetType() != OT_CONDITIONAL; if (ProcessOrders(v) && CheckReverseTrain(v)) { @@ -4285,14 +4288,14 @@ v->cur_speed = 0; v->subspeed = 0; ReverseTrainDirection(v); - return; + return true; } v->HandleLoading(mode); - if (v->current_order.IsType(OT_LOADING)) return; - - if (CheckTrainStayInDepot(v)) return; + if (v->current_order.IsType(OT_LOADING)) return true; + + if (CheckTrainStayInDepot(v)) return true; if (!mode) HandleLocomotiveSmokeCloud(v); @@ -4308,7 +4311,7 @@ /* Should we try reversing this tick if still stuck? */ bool turn_around = v->load_unload_time_rem % (_settings_game.pf.wait_for_pbs_path * DAY_TICKS) == 0 && _settings_game.pf.wait_for_pbs_path < 255; - if (!turn_around && v->load_unload_time_rem % _settings_game.pf.path_backoff_interval != 0 && v->u.rail.force_proceed == 0) return; + if (!turn_around && v->load_unload_time_rem % _settings_game.pf.path_backoff_interval != 0 && v->u.rail.force_proceed == 0) return true; if (!TryPathReserve(v)) { /* Still stuck. */ if (turn_around) ReverseTrainDirection(v); @@ -4326,7 +4329,7 @@ v->load_unload_time_rem = 0; } /* Exit if force proceed not pressed, else reset stuck flag anyway. */ - if (v->u.rail.force_proceed == 0) return; + if (v->u.rail.force_proceed == 0) return true; ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK); v->load_unload_time_rem = 0; InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); @@ -4336,7 +4339,7 @@ if (v->current_order.IsType(OT_LEAVESTATION)) { v->current_order.Free(); InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); - return; + return true; } int j = UpdateTrainSpeed(v); @@ -4387,6 +4390,8 @@ } if (v->progress == 0) v->progress = j; // Save unused spd for next time, if TrainController didn't set progress + + return true; } @@ -4412,7 +4417,7 @@ } -void Train::Tick() +bool Train::Tick() { if (_age_cargo_skip_counter == 0) this->cargo.AgeCargo(); @@ -4420,17 +4425,25 @@ if (IsFrontEngine(this)) { if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++; + this->current_order_time++; - TrainLocoHandler(this, false); + if (!TrainLocoHandler(this, false)) return false; /* make sure vehicle wasn't deleted. */ - if (this->type == VEH_TRAIN && IsFrontEngine(this)) - TrainLocoHandler(this, true); + assert(this->IsValid()); + assert(IsFrontEngine(this)); + + return TrainLocoHandler(this, true); } else if (IsFreeWagon(this) && HASBITS(this->vehstatus, VS_CRASHED)) { /* Delete flooded standalone wagon chain */ - if (++this->u.rail.crash_anim_pos >= 4400) delete this; + if (++this->u.rail.crash_anim_pos >= 4400) { + delete this; + return false; + } } + + return true; } static void CheckIfTrainNeedsService(Vehicle *v) diff --git a/src/vehicle.cpp b/src/vehicle.cpp --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -604,7 +604,10 @@ Vehicle *v; FOR_ALL_VEHICLES(v) { - v->Tick(); + /* Vehicle could be deleted in this tick */ + if (!v->Tick()) continue; + + assert(v->IsValid()); switch (v->type) { default: break; diff --git a/src/vehicle_base.h b/src/vehicle_base.h --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -423,8 +423,9 @@ /** * Calls the tick handler of the vehicle + * @return is this vehicle still valid? */ - virtual void Tick() {}; + virtual bool Tick() { return true; }; /** * Calls the new day handler of the vehicle @@ -620,7 +621,7 @@ const char *GetTypeString() const { return "disaster vehicle"; } void UpdateDeltaXY(Direction direction); - void Tick(); + bool Tick(); }; /** @@ -639,7 +640,6 @@ virtual ~InvalidVehicle() {} const char *GetTypeString() const { return "invalid vehicle"; } - void Tick() {} }; #define FOR_ALL_VEHICLES_FROM(v, start) for (v = Vehicle::Get(start); v != NULL; v = (v->index + 1U < Vehicle::GetPoolSize()) ? Vehicle::Get(v->index + 1) : NULL) if (v->IsValid())