1
0
Fork 0

(svn r20521) [1.0] -Backport from trunk:

- Fix: Desync when vehicles change NewGRF properties such as visual effect when changing railtype [FS#3978] (r20505, r20504, r20503, r20502)
release/1.0
rubidium 2010-08-16 23:15:33 +00:00
parent d6e34c9ad0
commit 0dc153f022
6 changed files with 70 additions and 33 deletions

View File

@ -2402,7 +2402,8 @@ STR_NEWGRF_UNPAUSE_WARNING :{WHITE}Unpausin
# NewGRF 'it's broken' warnings
STR_NEWGRF_BROKEN :{WHITE}Behaviour of NewGRF '{0:RAW_STRING}' is likely to cause desyncs and/or crashes.
STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}It changes vehicle length for '{1:ENGINE}' when not inside a depot.
STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}It changed powered-wagon state for '{1:ENGINE}' when not inside a depot.
STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}It changed vehicle length for '{1:ENGINE}' when not inside a depot.
STR_BROKEN_VEHICLE_LENGTH :{WHITE}Train '{VEHICLE}' belonging to '{COMPANY}' has invalid length. It is probably caused by problems with NewGRFs. Game may desync or crash.
STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:RAW_STRING}' provides incorrect information.

View File

@ -38,8 +38,9 @@ enum GRFStatus {
/** Encountered GRF bugs */
enum GRFBugs {
GBUG_VEH_LENGTH, ///< Length of rail vehicle changes when not inside a depot
GBUG_VEH_REFIT, ///< Articulated vehicles carry different cargos resp. are differently refittable than specified in purchase list
GBUG_VEH_LENGTH, ///< Length of rail vehicle changes when not inside a depot
GBUG_VEH_REFIT, ///< Articulated vehicles carry different cargos resp. are differently refittable than specified in purchase list
GBUG_VEH_POWERED_WAGON, ///< Powered wagon changed poweredness state when not inside a depot
};
/** Status of post-gameload GRF compatibility check */

View File

@ -691,9 +691,10 @@ static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, by
if (v->type == VEH_TRAIN) {
const Train *t = Train::From(v);
const Train *u = t->IsWagon() && HasBit(t->vehicle_flags, VRF_POWEREDWAGON) ? t->First() : t;
bool is_powered_wagon = HasBit(t->flags, VRF_POWEREDWAGON);
const Train *u = is_powered_wagon ? t->First() : t; // for powered wagons the engine defines the type of engine (i.e. railtype)
RailType railtype = GetRailType(v->tile);
bool powered = t->IsEngine() || (t->IsWagon() && HasBit(t->vehicle_flags, VRF_POWEREDWAGON));
bool powered = t->IsEngine() || is_powered_wagon;
bool has_power = HasPowerOnRail(u->railtype, railtype);
if (powered && has_power) SetBit(modflags, 5);

View File

@ -1346,7 +1346,6 @@ static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
{
if (v->type != VEH_TRAIN) return NULL;
/* Similar checks as in Train::PowerChanged() */
TrainList *affected_trains = static_cast<TrainList*>(data);
affected_trains->Include(Train::From(v)->First());
@ -1532,8 +1531,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
if (flags & DC_EXEC) {
/* Railtype changed, update trains as when entering different track */
for (Train **v = affected_trains.Begin(); v != affected_trains.End(); v++) {
(*v)->PowerChanged();
(*v)->UpdateAcceleration();
(*v)->RailtypeChanged();
}
}

View File

@ -161,6 +161,8 @@ struct Train : public SpecializedVehicle<Train, VEH_TRAIN> {
void CargoChanged();
void PowerChanged();
void RailtypeChanged();
int UpdateSpeed();
void UpdateAcceleration();
@ -389,6 +391,8 @@ struct Train : public SpecializedVehicle<Train, VEH_TRAIN> {
protected: // These functions should not be called outside acceleration code.
void UpdateVisualEffect(bool allow_power_change);
/**
* Allows to know the power value that this vehicle will use.
* @return Power value from the engine in HP, or zero if the vehicle is not powered.
@ -412,7 +416,8 @@ protected: // These functions should not be called outside acceleration code.
*/
FORCEINLINE uint16 GetPoweredPartPower(const Train *head) const
{
if (HasBit(this->flags, VRF_POWEREDWAGON) && HasPowerOnRail(head->railtype, GetRailType(head->tile))) {
/* For powered wagons the engine defines the type of engine (i.e. railtype) */
if (HasBit(this->flags, VRF_POWEREDWAGON) && HasPowerOnRail(head->railtype, GetRailType(this->tile))) {
return RailVehInfo(this->tcache.first_engine)->pow_wag_power;
}

View File

@ -196,6 +196,57 @@ void CheckTrainsLengths()
}
}
/**
* Update visual effect, power and acceleration caches.
* Called when a vehicle in the consist enters a different railtype.
*/
void Train::RailtypeChanged()
{
for (Train *u = this; u != NULL; u = u->Next()) {
/* The wagon-is-powered-state should not change, so the weight does not change. */
u->UpdateVisualEffect(false);
}
this->PowerChanged();
if (this->IsFrontEngine()) this->UpdateAcceleration();
}
/**
* Update the cached visual effect.
* @param allow_power_change true if the wagon-is-powered-state may change.
*/
void Train::UpdateVisualEffect(bool allow_power_change)
{
byte powered_before = this->tcache.cached_vis_effect & 0x80;
const Engine *e = Engine::Get(this->engine_type);
if (e->u.rail.visual_effect != 0) {
this->tcache.cached_vis_effect = e->u.rail.visual_effect;
} else {
if (this->IsWagon() || this->IsArticulatedPart()) {
/* Wagons and articulated parts have no effect by default */
this->tcache.cached_vis_effect = 0x40;
} else if (e->u.rail.engclass == 0) {
/* Steam is offset by -4 units */
this->tcache.cached_vis_effect = 4;
} else {
/* Diesel fumes and sparks come from the centre */
this->tcache.cached_vis_effect = 8;
}
}
/* Check powered wagon / visual effect callback */
if (HasBit(e->info.callback_mask, CBM_TRAIN_WAGON_POWER)) {
uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, this->engine_type, this);
if (callback != CALLBACK_FAILED) this->tcache.cached_vis_effect = GB(callback, 0, 8);
}
if (!allow_power_change && powered_before != (this->tcache.cached_vis_effect & 0x80)) {
this->tcache.cached_vis_effect ^= 0x80;
ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false);
}
}
/**
* Recalculates the cached stuff of a train. Should be called each time a vehicle is added
* to/removed from the chain, and when the game is loaded.
@ -252,27 +303,8 @@ void Train::ConsistChanged(bool same_length)
/* Reset colour map */
u->colourmap = PAL_NONE;
if (rvi_u->visual_effect != 0) {
u->tcache.cached_vis_effect = rvi_u->visual_effect;
} else {
if (u->IsWagon() || u->IsArticulatedPart()) {
/* Wagons and articulated parts have no effect by default */
u->tcache.cached_vis_effect = 0x40;
} else if (rvi_u->engclass == 0) {
/* Steam is offset by -4 units */
u->tcache.cached_vis_effect = 4;
} else {
/* Diesel fumes and sparks come from the centre */
u->tcache.cached_vis_effect = 8;
}
}
/* Check powered wagon / visual effect callback */
if (HasBit(e_u->info.callback_mask, CBM_TRAIN_WAGON_POWER)) {
uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, u->engine_type, u);
if (callback != CALLBACK_FAILED) u->tcache.cached_vis_effect = GB(callback, 0, 8);
}
/* Update powered-wagon-status and visual effect */
u->UpdateVisualEffect(true);
if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON &&
UsesWagonOverride(u) && !HasBit(u->tcache.cached_vis_effect, 7)) {
@ -1669,7 +1701,7 @@ static void ReverseTrainSwapVeh(Train *v, int l, int r)
}
/* Update train's power incase tiles were different rail type */
v->PowerChanged();
v->RailtypeChanged();
}
@ -3450,8 +3482,7 @@ static void TrainController(Train *v, Vehicle *nomove)
v->tile = gp.new_tile;
if (GetTileRailType(gp.new_tile) != GetTileRailType(gp.old_tile)) {
v->First()->PowerChanged();
v->First()->UpdateAcceleration();
v->First()->RailtypeChanged();
}
v->track = chosen_track;