mirror of https://github.com/OpenTTD/OpenTTD
(svn r18402) -Codechange: unify/centralise the code for crashing vehicles
parent
c22f9679b5
commit
19fa38601d
|
@ -102,6 +102,7 @@ struct Aircraft : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
|
||||||
bool IsInDepot() const { return (this->vehstatus & VS_HIDDEN) != 0 && IsHangarTile(this->tile); }
|
bool IsInDepot() const { return (this->vehstatus & VS_HIDDEN) != 0 && IsHangarTile(this->tile); }
|
||||||
bool Tick();
|
bool Tick();
|
||||||
void OnNewDay();
|
void OnNewDay();
|
||||||
|
uint Crash(bool flooded = false);
|
||||||
TileIndex GetOrderStationLocation(StationID station);
|
TileIndex GetOrderStationLocation(StationID station);
|
||||||
bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
|
bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
|
||||||
|
|
||||||
|
|
|
@ -1238,19 +1238,21 @@ void Aircraft::MarkDirty()
|
||||||
if (this->subtype == AIR_HELICOPTER) this->Next()->Next()->cur_image = GetRotorImage(this);
|
if (this->subtype == AIR_HELICOPTER) this->Next()->Next()->cur_image = GetRotorImage(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint Aircraft::Crash(bool flooded)
|
||||||
|
{
|
||||||
|
uint pass = Vehicle::Crash(flooded) + 2; // pilots
|
||||||
|
this->crashed_counter = flooded ? 9000 : 0; // max 10000, disappear pretty fast when flooded
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
static void CrashAirplane(Aircraft *v)
|
static void CrashAirplane(Aircraft *v)
|
||||||
{
|
{
|
||||||
v->vehstatus |= VS_CRASHED;
|
|
||||||
v->crashed_counter = 0;
|
|
||||||
|
|
||||||
CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
|
CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
|
||||||
|
|
||||||
v->MarkDirty();
|
uint pass = v->Crash();
|
||||||
SetWindowDirty(WC_VEHICLE_VIEW, v->index);
|
SetDParam(0, pass);
|
||||||
|
|
||||||
uint amt = 2;
|
|
||||||
if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) amt += v->cargo.Count();
|
|
||||||
SetDParam(0, amt);
|
|
||||||
|
|
||||||
v->cargo.Truncate(0);
|
v->cargo.Truncate(0);
|
||||||
v->Next()->cargo.Truncate(0);
|
v->Next()->cargo.Truncate(0);
|
||||||
|
|
|
@ -340,18 +340,13 @@ static bool DisasterTick_Ufo(DisasterVehicle *v)
|
||||||
if (z <= u->z_pos && (u->vehstatus & VS_HIDDEN) == 0) {
|
if (z <= u->z_pos && (u->vehstatus & VS_HIDDEN) == 0) {
|
||||||
v->age++;
|
v->age++;
|
||||||
if (u->crashed_ctr == 0) {
|
if (u->crashed_ctr == 0) {
|
||||||
u->crashed_ctr++;
|
u->Crash();
|
||||||
|
|
||||||
AddVehicleNewsItem(STR_NEWS_DISASTER_SMALL_UFO,
|
AddVehicleNewsItem(STR_NEWS_DISASTER_SMALL_UFO,
|
||||||
NS_ACCIDENT,
|
NS_ACCIDENT,
|
||||||
u->index); // delete the news, when the roadvehicle is gone
|
u->index); // delete the news, when the roadvehicle is gone
|
||||||
|
|
||||||
AI::NewEvent(u->owner, new AIEventVehicleCrashed(u->index, u->tile, AIEventVehicleCrashed::CRASH_RV_UFO));
|
AI::NewEvent(u->owner, new AIEventVehicleCrashed(u->index, u->tile, AIEventVehicleCrashed::CRASH_RV_UFO));
|
||||||
|
|
||||||
for (Vehicle *w = u; w != NULL; w = w->Next()) {
|
|
||||||
w->vehstatus |= VS_CRASHED;
|
|
||||||
MarkSingleVehicleDirty(w);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,7 @@ struct RoadVehicle : public SpecializedVehicle<RoadVehicle, VEH_ROAD> {
|
||||||
bool IsStoppedInDepot() const;
|
bool IsStoppedInDepot() const;
|
||||||
bool Tick();
|
bool Tick();
|
||||||
void OnNewDay();
|
void OnNewDay();
|
||||||
|
uint Crash(bool flooded = false);
|
||||||
Trackdir GetVehicleTrackdir() const;
|
Trackdir GetVehicleTrackdir() const;
|
||||||
TileIndex GetOrderStationLocation(StationID station);
|
TileIndex GetOrderStationLocation(StationID station);
|
||||||
bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
|
bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
|
||||||
|
|
|
@ -537,21 +537,17 @@ static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data)
|
||||||
v : NULL;
|
v : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint RoadVehicle::Crash(bool flooded)
|
||||||
|
{
|
||||||
|
uint pass = Vehicle::Crash(flooded);
|
||||||
|
if (this->IsRoadVehFront()) pass += 1; // driver
|
||||||
|
this->crashed_ctr = flooded ? 2000 : 1; // max 2220, disappear pretty fast when flooded
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
static void RoadVehCrash(RoadVehicle *v)
|
static void RoadVehCrash(RoadVehicle *v)
|
||||||
{
|
{
|
||||||
uint16 pass = 1;
|
uint pass = v->Crash();
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING));
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,7 @@ struct Train : public SpecializedVehicle<Train, VEH_TRAIN> {
|
||||||
bool IsStoppedInDepot() const { return CheckTrainStoppedInDepot(this) >= 0; }
|
bool IsStoppedInDepot() const { return CheckTrainStoppedInDepot(this) >= 0; }
|
||||||
bool Tick();
|
bool Tick();
|
||||||
void OnNewDay();
|
void OnNewDay();
|
||||||
|
uint Crash(bool flooded = false);
|
||||||
Trackdir GetVehicleTrackdir() const;
|
Trackdir GetVehicleTrackdir() const;
|
||||||
TileIndex GetOrderStationLocation(StationID station);
|
TileIndex GetOrderStationLocation(StationID station);
|
||||||
bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
|
bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
|
||||||
|
|
|
@ -3188,56 +3188,34 @@ void Train::ReserveTrackUnderConsist() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetVehicleCrashed(Train *v)
|
uint Train::Crash(bool flooded)
|
||||||
{
|
{
|
||||||
if (v->crash_anim_pos != 0) return;
|
uint pass = 0;
|
||||||
|
if (this->IsFrontEngine()) {
|
||||||
|
pass += 4; // driver
|
||||||
|
|
||||||
if (v->IsFrontEngine()) {
|
|
||||||
/* Remove the reserved path in front of the train if it is not stuck.
|
/* Remove the reserved path in front of the train if it is not stuck.
|
||||||
* Also clear all reserved tracks the train is currently on. */
|
* Also clear all reserved tracks the train is currently on. */
|
||||||
if (!HasBit(v->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v);
|
if (!HasBit(this->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(this);
|
||||||
for (const Train *u = v; u != NULL; u = u->Next()) {
|
for (const Train *v = this; v != NULL; v = v->Next()) {
|
||||||
ClearPathReservation(u, u->tile, u->GetVehicleTrackdir());
|
ClearPathReservation(v, v->tile, v->GetVehicleTrackdir());
|
||||||
if (IsTileType(u->tile, MP_TUNNELBRIDGE)) {
|
if (IsTileType(v->tile, MP_TUNNELBRIDGE)) {
|
||||||
/* ClearPathReservation will not free the wormhole exit
|
/* ClearPathReservation will not free the wormhole exit
|
||||||
* if the train has just entered the wormhole. */
|
* if the train has just entered the wormhole. */
|
||||||
SetTunnelBridgeReservation(GetOtherTunnelBridgeEnd(u->tile), false);
|
SetTunnelBridgeReservation(GetOtherTunnelBridgeEnd(v->tile), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* we may need to update crossing we were approaching,
|
||||||
|
* but must be updated after the train has been marked crashed */
|
||||||
|
TileIndex crossing = TrainApproachingCrossingTile(this);
|
||||||
|
if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we may need to update crossing we were approaching */
|
pass += Vehicle::Crash(flooded);
|
||||||
TileIndex crossing = TrainApproachingCrossingTile(v);
|
|
||||||
|
|
||||||
v->crash_anim_pos++;
|
this->crash_anim_pos = flooded ? 4000 : 1; // max 4440, disappear pretty fast when flooded
|
||||||
|
return pass;
|
||||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
|
|
||||||
SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
|
|
||||||
|
|
||||||
if (v->track == TRACK_BIT_DEPOT) {
|
|
||||||
SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
|
|
||||||
}
|
|
||||||
|
|
||||||
InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
|
|
||||||
|
|
||||||
for (; v != NULL; v = v->Next()) {
|
|
||||||
v->vehstatus |= VS_CRASHED;
|
|
||||||
MarkSingleVehicleDirty(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* must be updated after the train has been marked crashed */
|
|
||||||
if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint CountPassengersInTrain(const Train *v)
|
|
||||||
{
|
|
||||||
uint num = 0;
|
|
||||||
|
|
||||||
for (; v != NULL; v = v->Next()) {
|
|
||||||
if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) num += v->cargo.Count();
|
|
||||||
}
|
|
||||||
|
|
||||||
return num;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3252,10 +3230,7 @@ static uint TrainCrashed(Train *v)
|
||||||
|
|
||||||
/* do not crash train twice */
|
/* do not crash train twice */
|
||||||
if (!(v->vehstatus & VS_CRASHED)) {
|
if (!(v->vehstatus & VS_CRASHED)) {
|
||||||
/* two drivers + passengers */
|
num = v->Crash();
|
||||||
num = 2 + CountPassengersInTrain(v);
|
|
||||||
|
|
||||||
SetVehicleCrashed(v);
|
|
||||||
AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_TRAIN));
|
AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_TRAIN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,29 @@ bool Vehicle::NeedsAutomaticServicing() const
|
||||||
return NeedsServicing();
|
return NeedsServicing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint Vehicle::Crash(bool flooded)
|
||||||
|
{
|
||||||
|
assert((this->vehstatus & VS_CRASHED) == 0);
|
||||||
|
assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains
|
||||||
|
|
||||||
|
uint pass = 0;
|
||||||
|
/* crash all wagons, and count passengers */
|
||||||
|
for (Vehicle *v = this; v != NULL; v = v->Next()) {
|
||||||
|
if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.Count();
|
||||||
|
v->vehstatus |= VS_CRASHED;
|
||||||
|
MarkSingleVehicleDirty(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dirty some windows */
|
||||||
|
InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
|
||||||
|
SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
|
||||||
|
SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
|
||||||
|
SetWindowDirty(WC_VEHICLE_DEPOT, this->tile);
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays a "NewGrf Bug" error message for a engine, and pauses the game if not networking.
|
* Displays a "NewGrf Bug" error message for a engine, and pauses the game if not networking.
|
||||||
* @param engine The engine that caused the problem
|
* @param engine The engine that caused the problem
|
||||||
|
|
|
@ -323,6 +323,13 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void OnNewDay() {};
|
virtual void OnNewDay() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crash the (whole) vehicle chain.
|
||||||
|
* @param flooded whether the cause of the crash is flooding or not.
|
||||||
|
* @return the number of lost souls.
|
||||||
|
*/
|
||||||
|
virtual uint Crash(bool flooded = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update vehicle sprite- and position caches
|
* Update vehicle sprite- and position caches
|
||||||
* @param moved Was the vehicle moved?
|
* @param moved Was the vehicle moved?
|
||||||
|
|
|
@ -789,8 +789,8 @@ static void FloodVehicle(Vehicle *v)
|
||||||
|
|
||||||
if (v->type == VEH_AIRCRAFT) {
|
if (v->type == VEH_AIRCRAFT) {
|
||||||
/* Crashing aircraft are always at z_pos == 1, never on z_pos == 0,
|
/* Crashing aircraft are always at z_pos == 1, never on z_pos == 0,
|
||||||
* because that's always the shadow. Except for the heliport, because
|
* because that's always the shadow. Except for the heliport, because
|
||||||
* that station has a big z_offset for the aircraft. */
|
* that station has a big z_offset for the aircraft. */
|
||||||
if (!IsTileType(v->tile, MP_STATION) || !IsAirport(v->tile) || GetTileMaxZ(v->tile) != 0) return;
|
if (!IsTileType(v->tile, MP_STATION) || !IsAirport(v->tile) || GetTileMaxZ(v->tile) != 0) return;
|
||||||
const Station *st = Station::GetByTile(v->tile);
|
const Station *st = Station::GetByTile(v->tile);
|
||||||
const AirportFTAClass *airport = st->Airport();
|
const AirportFTAClass *airport = st->Airport();
|
||||||
|
@ -800,47 +800,7 @@ static void FloodVehicle(Vehicle *v)
|
||||||
v = v->First();
|
v = v->First();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint pass = 0;
|
uint pass = v->Crash(true);
|
||||||
/* crash all wagons, and count passengers */
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (v->type) {
|
|
||||||
default: NOT_REACHED();
|
|
||||||
case VEH_TRAIN: {
|
|
||||||
Train *t = Train::From(v);
|
|
||||||
if (t->IsFrontEngine()) {
|
|
||||||
pass += 4; // driver
|
|
||||||
/* FreeTrainTrackReservation() calls GetVehicleTrackdir() that doesn't like crashed vehicles.
|
|
||||||
* In this case, v->direction matches v->u.rail.track, so we can do this (it wasn't crashed before) */
|
|
||||||
t->vehstatus &= ~VS_CRASHED;
|
|
||||||
if (!HasBit(t->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(t);
|
|
||||||
t->vehstatus |= VS_CRASHED;
|
|
||||||
}
|
|
||||||
t->crash_anim_pos = 4000; // max 4440, disappear pretty fast
|
|
||||||
InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case VEH_ROAD: {
|
|
||||||
RoadVehicle *rv = RoadVehicle::From(v);
|
|
||||||
if (rv->IsRoadVehFront()) pass += 1; // driver
|
|
||||||
rv->crashed_ctr = 2000; // max 2220, disappear pretty fast
|
|
||||||
InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case VEH_AIRCRAFT:
|
|
||||||
pass += 2; // driver
|
|
||||||
Aircraft::From(v)->crashed_counter = 9000; // max 10000, disappear pretty fast
|
|
||||||
InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
|
|
||||||
SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
|
|
||||||
|
|
||||||
AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
|
AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
|
||||||
SetDParam(0, pass);
|
SetDParam(0, pass);
|
||||||
|
|
Loading…
Reference in New Issue