changeset 11970:2286db6ac0bb draft

(svn r16376) -Codechange: Vehicle::Tick() now returns false if the vehicle was deleted
author smatz <smatz@openttd.org>
date Fri, 22 May 2009 13:53:14 +0000
parents d89c33df9b66
children 9daf69237623
files src/aircraft.h src/aircraft_cmd.cpp src/disaster_cmd.cpp src/effectvehicle.cpp src/effectvehicle_base.h src/roadveh.h src/roadveh_cmd.cpp src/ship.h src/ship_cmd.cpp src/train.h src/train_cmd.cpp src/vehicle.cpp src/vehicle_base.h
diffstat 13 files changed, 190 insertions(+), 108 deletions(-) [+]
line wrap: on
line diff
--- 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);
--- 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;
 }
 
 
--- 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();
--- 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)
--- 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 */
--- 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);
--- 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)
--- 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);
--- 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.
--- 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);
--- 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)
--- 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;
--- 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())