mirror of https://github.com/OpenTTD/OpenTTD.git
(svn r15701) -Fix [FS#2595]: Blame NewGRFs returning inconsistent information in purchase-list/after building before users have a chance to blame OpenTTD for incorrectly autorenewing/-replacing.
This commit is contained in:
parent
e6353a1a22
commit
4129b418cc
|
@ -9,6 +9,8 @@
|
|||
#include "newgrf_engine.h"
|
||||
#include "vehicle_func.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
static const uint MAX_ARTICULATED_PARTS = 100; ///< Maximum of articulated parts per vehicle, i.e. when to abort calling the articulated vehicle callback.
|
||||
|
||||
uint CountArticulatedParts(EngineID engine_type, bool purchase_window)
|
||||
|
@ -238,6 +240,64 @@ bool IsArticulatedVehicleCarryingDifferentCargos(const Vehicle *v, CargoID *carg
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the specs of freshly build articulated vehicles are consistent with the information specified in the purchase list.
|
||||
* Only essential information is checked to leave room for magic tricks/workarounds to grfcoders.
|
||||
* It checks:
|
||||
* For autoreplace/-renew:
|
||||
* - Default cargo type (without capacity)
|
||||
* - intersection and union of refit masks.
|
||||
*/
|
||||
void CheckConsistencyOfArticulatedVehicle(const Vehicle *v)
|
||||
{
|
||||
const Engine *engine = GetEngine(v->engine_type);
|
||||
|
||||
uint32 purchase_refit_union = GetUnionOfArticulatedRefitMasks(v->engine_type, v->type, true);
|
||||
uint32 purchase_refit_intersection = GetIntersectionOfArticulatedRefitMasks(v->engine_type, v->type, true);
|
||||
uint16 *purchase_default_capacity = GetCapacityOfArticulatedParts(v->engine_type, v->type);
|
||||
|
||||
uint32 real_refit_union = 0;
|
||||
uint32 real_refit_intersection = UINT_MAX;
|
||||
uint16 real_default_capacity[NUM_CARGO];
|
||||
memset(real_default_capacity, 0, sizeof(real_default_capacity));
|
||||
|
||||
do {
|
||||
uint32 refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, v->type, true);
|
||||
real_refit_union |= refit_mask;
|
||||
if (refit_mask != 0) real_refit_intersection &= refit_mask;
|
||||
|
||||
assert(v->cargo_type < NUM_CARGO);
|
||||
real_default_capacity[v->cargo_type] += v->cargo_cap;
|
||||
|
||||
switch (v->type) {
|
||||
case VEH_TRAIN:
|
||||
v = (EngineHasArticPart(v) ? GetNextArticPart(v) : NULL);
|
||||
break;
|
||||
|
||||
case VEH_ROAD:
|
||||
v = (RoadVehHasArticPart(v) ? v->Next() : NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
v = NULL;
|
||||
break;
|
||||
}
|
||||
} while (v != NULL);
|
||||
|
||||
/* Check whether the vehicle carries more cargos than expected */
|
||||
bool carries_more = false;
|
||||
for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
|
||||
if (real_default_capacity[cid] != 0 && purchase_default_capacity[cid] == 0) {
|
||||
carries_more = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* show a warning once for each GRF after each game load */
|
||||
if (real_refit_union != purchase_refit_union || real_refit_intersection != purchase_refit_intersection || carries_more) {
|
||||
ShowNewGrfVehicleError(engine->index, STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_ARTICULATED_CARGO, GBUG_VEH_REFIT, false);
|
||||
}
|
||||
}
|
||||
|
||||
void AddArticulatedParts(Vehicle **vl, VehicleType type)
|
||||
{
|
||||
|
|
|
@ -15,5 +15,7 @@ uint32 GetUnionOfArticulatedRefitMasks(EngineID engine, VehicleType type, bool i
|
|||
uint32 GetIntersectionOfArticulatedRefitMasks(EngineID engine, VehicleType type, bool include_initial_cargo_type);
|
||||
bool IsArticulatedVehicleCarryingDifferentCargos(const Vehicle *v, CargoID *cargo_type);
|
||||
bool IsArticulatedVehicleRefittable(EngineID engine);
|
||||
void CheckConsistencyOfArticulatedVehicle(const Vehicle *v);
|
||||
|
||||
|
||||
#endif /* ARTICULATED_VEHICLES_H */
|
||||
|
|
|
@ -3170,6 +3170,9 @@ STR_NEWGRF_BROKEN :{WHITE}Behaviou
|
|||
STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}It changes 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.
|
||||
STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Cargo/refit information for '{1:ENGINE}' differs from purchase list after construction. This might cause autorenew/-replace to fail refitting correctly.
|
||||
|
||||
STR_LOADGAME_REMOVED_TRAMS :{WHITE}Game was saved in version without tram support. All trams have been removed.
|
||||
|
||||
STR_CURRENCY_WINDOW :{WHITE}Custom currency
|
||||
|
|
|
@ -31,6 +31,7 @@ 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
|
||||
};
|
||||
|
||||
/** Status of post-gameload GRF compatibility check */
|
||||
|
|
|
@ -275,10 +275,13 @@ CommandCost CmdBuildRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
|
|||
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
|
||||
InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
|
||||
InvalidateWindow(WC_COMPANY, v->owner);
|
||||
if (IsLocalCompany())
|
||||
if (IsLocalCompany()) {
|
||||
InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Road window
|
||||
}
|
||||
|
||||
GetCompany(_current_company)->num_engines[p1]++;
|
||||
|
||||
CheckConsistencyOfArticulatedVehicle(v);
|
||||
}
|
||||
|
||||
return cost;
|
||||
|
|
|
@ -178,23 +178,7 @@ static void RailVehicleLengthChanged(const Vehicle *u)
|
|||
uint32 grfid = engine->grffile->grfid;
|
||||
GRFConfig *grfconfig = GetGRFConfig(grfid);
|
||||
if (GamelogGRFBugReverse(grfid, engine->internal_id) || !HasBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH)) {
|
||||
SetBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH);
|
||||
SetDParamStr(0, grfconfig->name);
|
||||
SetDParam(1, u->engine_type);
|
||||
ShowErrorMessage(STR_NEWGRF_BROKEN_VEHICLE_LENGTH, STR_NEWGRF_BROKEN, 0, 0);
|
||||
|
||||
/* debug output */
|
||||
char buffer[512];
|
||||
|
||||
SetDParamStr(0, grfconfig->name);
|
||||
GetString(buffer, STR_NEWGRF_BROKEN, lastof(buffer));
|
||||
DEBUG(grf, 0, "%s", buffer + 3);
|
||||
|
||||
SetDParam(1, u->engine_type);
|
||||
GetString(buffer, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, lastof(buffer));
|
||||
DEBUG(grf, 0, "%s", buffer + 3);
|
||||
|
||||
if (!_networking) _pause_game = -1;
|
||||
ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GBUG_VEH_LENGTH, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -678,6 +662,8 @@ static CommandCost CmdBuildRailWagon(EngineID engine, TileIndex tile, DoCommandF
|
|||
InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window
|
||||
}
|
||||
GetCompany(_current_company)->num_engines[engine]++;
|
||||
|
||||
CheckConsistencyOfArticulatedVehicle(v);
|
||||
}
|
||||
|
||||
return value;
|
||||
|
@ -857,6 +843,8 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
|||
}
|
||||
|
||||
GetCompany(_current_company)->num_engines[p1]++;
|
||||
|
||||
CheckConsistencyOfArticulatedVehicle(v);
|
||||
}
|
||||
|
||||
return value;
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
/** @file vehicle.cpp Base implementations of all vehicles. */
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "gui.h"
|
||||
#include "openttd.h"
|
||||
#include "debug.h"
|
||||
#include "roadveh.h"
|
||||
#include "ship.h"
|
||||
#include "spritecache.h"
|
||||
|
@ -36,6 +38,7 @@
|
|||
#include "core/smallmap_type.hpp"
|
||||
#include "depot_func.h"
|
||||
#include "settings_type.h"
|
||||
#include "network/network.h"
|
||||
|
||||
#include "table/sprites.h"
|
||||
#include "table/strings.h"
|
||||
|
@ -101,6 +104,40 @@ bool Vehicle::NeedsAutomaticServicing() const
|
|||
return NeedsServicing();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 part1 Part 1 of the error message, taking the grfname as parameter 1
|
||||
* @param part2 Part 2 of the error message, taking the engine as parameter 2
|
||||
* @param bug_type Flag to check and set in grfconfig
|
||||
* @param critical Shall the "OpenTTD might crash"-message be shown when the player tries to unpause?
|
||||
*/
|
||||
void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical)
|
||||
{
|
||||
const Engine *e = GetEngine(engine);
|
||||
uint32 grfid = e->grffile->grfid;
|
||||
GRFConfig *grfconfig = GetGRFConfig(grfid);
|
||||
|
||||
if (!HasBit(grfconfig->grf_bugs, bug_type)) {
|
||||
SetBit(grfconfig->grf_bugs, bug_type);
|
||||
SetDParamStr(0, grfconfig->name);
|
||||
SetDParam(1, engine);
|
||||
ShowErrorMessage(part2, part1, 0, 0);
|
||||
if (!_networking) _pause_game = (critical ? -1 : 1);
|
||||
}
|
||||
|
||||
/* debug output */
|
||||
char buffer[512];
|
||||
|
||||
SetDParamStr(0, grfconfig->name);
|
||||
GetString(buffer, part1, lastof(buffer));
|
||||
DEBUG(grf, 0, "%s", buffer + 3);
|
||||
|
||||
SetDParam(1, engine);
|
||||
GetString(buffer, part2, lastof(buffer));
|
||||
DEBUG(grf, 0, "%s", buffer + 3);
|
||||
}
|
||||
|
||||
StringID VehicleInTheWayErrMsg(const Vehicle *v)
|
||||
{
|
||||
switch (v->type) {
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "vehicle_type.h"
|
||||
#include "engine_type.h"
|
||||
#include "transport_type.h"
|
||||
#include "newgrf_config.h"
|
||||
|
||||
#define is_custom_sprite(x) (x >= 0xFD)
|
||||
#define IS_CUSTOM_FIRSTHEAD_SPRITE(x) (x == 0xFD)
|
||||
|
@ -46,6 +47,7 @@ void ViewportAddVehicles(DrawPixelInfo *dpi);
|
|||
|
||||
SpriteID GetRotorImage(const Vehicle *v);
|
||||
|
||||
void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical);
|
||||
StringID VehicleInTheWayErrMsg(const Vehicle *v);
|
||||
bool HasVehicleOnTunnelBridge(TileIndex tile, TileIndex endtile, const Vehicle *ignore = NULL);
|
||||
|
||||
|
|
Loading…
Reference in New Issue