From 41b7a04a680196dc7d579ca9a88fbe9c8c28f60a Mon Sep 17 00:00:00 2001 From: frosch Date: Fri, 7 Feb 2014 23:48:56 +0000 Subject: [PATCH] (svn r26317) -Fix [FS#5897]: Check whether NewGRF change vehicle capacity when they are not supposed to, and truncate cargo appropiately if they are allowed to. --- src/autoreplace_cmd.cpp | 2 +- src/elrail.cpp | 2 +- src/lang/english.txt | 1 + src/newgrf_config.h | 1 + src/openttd.cpp | 2 +- src/rail_cmd.cpp | 2 +- src/saveload/afterload.cpp | 2 +- src/saveload/vehicle_sl.cpp | 4 ++-- src/settings.cpp | 2 +- src/train.h | 18 +++++++++++++++- src/train_cmd.cpp | 41 ++++++++++++++++++++++--------------- src/vehicle.cpp | 2 +- src/vehicle_cmd.cpp | 2 +- 13 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index 27d6fddcd3..2e13caffba 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -160,7 +160,7 @@ static void TransferCargo(Vehicle *old_veh, Vehicle *new_head, bool part_of_chai } /* Update train weight etc., the old vehicle will be sold anyway */ - if (part_of_chain && new_head->type == VEH_TRAIN) Train::From(new_head)->ConsistChanged(true); + if (part_of_chain && new_head->type == VEH_TRAIN) Train::From(new_head)->ConsistChanged(CCF_LOADUNLOAD); } /** diff --git a/src/elrail.cpp b/src/elrail.cpp index 80f095d809..a431837920 100644 --- a/src/elrail.cpp +++ b/src/elrail.cpp @@ -627,7 +627,7 @@ bool SettingsDisableElrail(int32 p1) FOR_ALL_TRAINS(t) { /* power and acceleration is cached only for front engines */ if (t->IsFrontEngine()) { - t->ConsistChanged(true); + t->ConsistChanged(CCF_TRACK); } } diff --git a/src/lang/english.txt b/src/lang/english.txt index ee2827663e..52fa8c2281 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2877,6 +2877,7 @@ STR_NEWGRF_LIST_MISSING :{RED}Missing fi STR_NEWGRF_BROKEN :{WHITE}Behaviour of NewGRF '{0:RAW_STRING}' is likely to cause desyncs and/or crashes 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_NEWGRF_BROKEN_CAPACITY :{WHITE}It changed vehicle capacity for '{1:ENGINE}' when not inside a depot or refitting 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 diff --git a/src/newgrf_config.h b/src/newgrf_config.h index ed35c144e3..906f9620d1 100644 --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -46,6 +46,7 @@ enum GRFBugs { GBUG_VEH_REFIT, ///< Articulated vehicles carry different cargoes resp. are differently refittable than specified in purchase list GBUG_VEH_POWERED_WAGON, ///< Powered wagon changed poweredness state when not inside a depot GBUG_UNKNOWN_CB_RESULT, ///< A callback returned an unknown/invalid result + GBUG_VEH_CAPACITY, ///< Capacity of vehicle changes when not refitting or arranging }; /** Status of post-gameload GRF compatibility check */ diff --git a/src/openttd.cpp b/src/openttd.cpp index 7a3f84eea4..6092805eb4 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1276,7 +1276,7 @@ static void CheckCaches() } switch (v->type) { - case VEH_TRAIN: Train::From(v)->ConsistChanged(true); break; + case VEH_TRAIN: Train::From(v)->ConsistChanged(CCF_TRACK); break; case VEH_ROAD: RoadVehUpdateCache(RoadVehicle::From(v)); break; case VEH_AIRCRAFT: UpdateAircraftCache(Aircraft::From(v)); break; case VEH_SHIP: Ship::From(v)->UpdateCache(); break; diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 61adedfa28..4dd4659bb6 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -1718,7 +1718,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)->ConsistChanged(true); + (*v)->ConsistChanged(CCF_TRACK); } } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index ab34a0c076..87754d6b52 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -1221,7 +1221,7 @@ bool AfterLoadGame() } FOR_ALL_TRAINS(v) { - if (v->IsFrontEngine() || v->IsFreeWagon()) v->ConsistChanged(true); + if (v->IsFrontEngine() || v->IsFreeWagon()) v->ConsistChanged(CCF_TRACK); } } diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 3ee6ce99c4..ad8ef08315 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -376,7 +376,7 @@ void AfterLoadVehicles(bool part_of_load) Train *t = Train::From(v); if (t->IsFrontEngine() || t->IsFreeWagon()) { t->gcache.last_speed = t->cur_speed; // update displayed train speed - t->ConsistChanged(false); + t->ConsistChanged(CCF_SAVELOAD); } break; } @@ -547,7 +547,7 @@ void FixupTrainLengths() } /* Update all cached properties after moving the vehicle chain around. */ - Train::From(v)->ConsistChanged(true); + Train::From(v)->ConsistChanged(CCF_TRACK); } } } diff --git a/src/settings.cpp b/src/settings.cpp index 825e3cbcaa..970c169b4a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -869,7 +869,7 @@ static bool UpdateConsists(int32 p1) Train *t; FOR_ALL_TRAINS(t) { /* Update the consist of all trains so the maximum speed is set correctly. */ - if (t->IsFrontEngine() || t->IsFreeWagon()) t->ConsistChanged(true); + if (t->IsFrontEngine() || t->IsFreeWagon()) t->ConsistChanged(CCF_TRACK); } InvalidateWindowClassesData(WC_BUILD_VEHICLE, 0); return true; diff --git a/src/train.h b/src/train.h index 8f4bc2a9b8..280d59ebdd 100644 --- a/src/train.h +++ b/src/train.h @@ -12,6 +12,8 @@ #ifndef TRAIN_H #define TRAIN_H +#include "core/enum_type.hpp" + #include "newgrf_engine.h" #include "cargotype.h" #include "rail.h" @@ -41,6 +43,20 @@ enum TrainForceProceeding { }; typedef SimpleTinyEnumT TrainForceProceedingByte; +/** Flags for Train::ConsistChanged */ +enum ConsistChangeFlags { + CCF_LENGTH = 0x01, ///< Allow vehicles to change length. + CCF_CAPACITY = 0x02, ///< Allow vehicles to change capacity. + + CCF_TRACK = 0, ///< Valid changes while vehicle is driving, and possibly changing tracks. + CCF_LOADUNLOAD = 0, ///< Valid changes while vehicle is loading/unloading. + CCF_AUTOREFIT = CCF_CAPACITY, ///< Valid changes for autorefitting in stations. + CCF_REFIT = CCF_LENGTH | CCF_CAPACITY, ///< Valid changes for refitting in a depot. + CCF_ARRANGE = CCF_LENGTH | CCF_CAPACITY, ///< Valid changes for arranging the consist in a depot. + CCF_SAVELOAD = CCF_LENGTH, ///< Valid changes when loading a savegame. (Everything that is not stored in the save.) +}; +DECLARE_ENUM_AS_BIT_SET(ConsistChangeFlags) + byte FreightWagonMult(CargoID cargo); void CheckTrainsLengths(); @@ -115,7 +131,7 @@ struct Train FINAL : public GroundVehicle { int GetCurveSpeedLimit() const; - void ConsistChanged(bool same_length); + void ConsistChanged(ConsistChangeFlags allowed_changes); int UpdateSpeed(); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 4e9ab2a15d..0198ac58cb 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -122,9 +122,9 @@ void CheckTrainsLengths() * 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. * Note: this needs to be called too for 'wagon chains' (in the depot, without an engine) - * @param same_length should length of vehicles stay the same? + * @param allowed_changes Stuff that is allowed to change. */ -void Train::ConsistChanged(bool same_length) +void Train::ConsistChanged(ConsistChangeFlags allowed_changes) { uint16 max_speed = UINT16_MAX; @@ -207,8 +207,15 @@ void Train::ConsistChanged(bool same_length) } uint16 new_cap = e_u->DetermineCapacity(u); - u->refit_cap = min(new_cap, u->refit_cap); - u->cargo_cap = new_cap; + if (allowed_changes & CCF_CAPACITY) { + /* Update vehicle capacity. */ + if (u->cargo_cap > new_cap) u->cargo.Truncate(new_cap); + u->refit_cap = min(new_cap, u->refit_cap); + u->cargo_cap = new_cap; + } else { + /* Verify capacity hasn't changed. */ + if (new_cap != u->cargo_cap) ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_CAPACITY, GBUG_VEH_CAPACITY, true); + } u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_TRAIN_CARGO_AGE_PERIOD, e_u->info.cargo_age_period); /* check the vehicle length (callback) */ @@ -227,11 +234,13 @@ void Train::ConsistChanged(bool same_length) if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor; veh_len = VEHICLE_LENGTH - Clamp(veh_len, 0, VEHICLE_LENGTH - 1); - /* verify length hasn't changed */ - if (same_length && veh_len != u->gcache.cached_veh_length) VehicleLengthChanged(u); - - /* update vehicle length? */ - if (!same_length) u->gcache.cached_veh_length = veh_len; + if (allowed_changes & CCF_LENGTH) { + /* Update vehicle length. */ + u->gcache.cached_veh_length = veh_len; + } else { + /* Verify length hasn't changed. */ + if (veh_len != u->gcache.cached_veh_length) VehicleLengthChanged(u); + } this->gcache.cached_total_length += u->gcache.cached_veh_length; this->InvalidateNewGRFCache(); @@ -632,7 +641,7 @@ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const _new_vehicle_id = v->index; VehicleUpdatePosition(v); - v->First()->ConsistChanged(false); + v->First()->ConsistChanged(CCF_ARRANGE); UpdateTrainGroupID(v->First()); CheckConsistencyOfArticulatedVehicle(v); @@ -774,7 +783,7 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engin AddArticulatedParts(v); } - v->ConsistChanged(false); + v->ConsistChanged(CCF_ARRANGE); UpdateTrainGroupID(v); if (!HasBit(data, 0) && !(flags & DC_AUTOREPLACE)) { // check if the cars should be added to the new vehicle @@ -1120,7 +1129,7 @@ static void NormaliseTrainHead(Train *head) if (head == NULL) return; /* Tell the 'world' the train changed. */ - head->ConsistChanged(false); + head->ConsistChanged(CCF_ARRANGE); UpdateTrainGroupID(head); /* Not a front engine, i.e. a free wagon chain. No need to do more. */ @@ -1824,7 +1833,7 @@ void ReverseTrainDirection(Train *v) ClrBit(v->flags, VRF_REVERSING); /* recalculate cached data */ - v->ConsistChanged(true); + v->ConsistChanged(CCF_TRACK); /* update all images */ for (Train *u = v; u != NULL; u = u->Next()) u->UpdateViewport(false, false); @@ -1908,7 +1917,7 @@ CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 if (flags & DC_EXEC) { ToggleBit(v->flags, VRF_REVERSE_DIRECTION); - front->ConsistChanged(false); + front->ConsistChanged(CCF_ARRANGE); SetWindowDirty(WC_VEHICLE_DEPOT, front->tile); SetWindowDirty(WC_VEHICLE_DETAILS, front->index); SetWindowDirty(WC_VEHICLE_VIEW, front->index); @@ -3271,7 +3280,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) v->tile = gp.new_tile; if (GetTileRailType(gp.new_tile) != GetTileRailType(gp.old_tile)) { - v->First()->ConsistChanged(true); + v->First()->ConsistChanged(CCF_TRACK); } v->track = chosen_track; @@ -3437,7 +3446,7 @@ static void DeleteLastWagon(Train *v) if (first != v) { /* Recalculate cached train properties */ - first->ConsistChanged(false); + first->ConsistChanged(CCF_ARRANGE); /* Update the depot window if the first vehicle is in depot - * if v == first, then it is updated in PreDestructor() */ if (first->track == TRACK_BIT_DEPOT) { diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 2037da7cd1..ceb345f469 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1355,7 +1355,7 @@ void VehicleEnterDepot(Vehicle *v) t->wait_counter = 0; t->force_proceed = TFP_NONE; ClrBit(t->flags, VRF_TOGGLE_REVERSE); - t->ConsistChanged(true); + t->ConsistChanged(CCF_ARRANGE); break; } diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index f45bd4b5ab..78c62d20a2 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -463,7 +463,7 @@ CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint /* Update the cached variables */ switch (v->type) { case VEH_TRAIN: - Train::From(front)->ConsistChanged(auto_refit); + Train::From(front)->ConsistChanged(auto_refit ? CCF_AUTOREFIT : CCF_REFIT); break; case VEH_ROAD: RoadVehUpdateCache(RoadVehicle::From(front), auto_refit);