Changeset - r11346:032b1fd8218f
[Not reviewed]
master
0 8 0
frosch - 16 years ago 2009-03-13 21:28:40
frosch@openttd.org
(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.
8 files changed with 114 insertions and 18 deletions:
0 comments (0 inline, 0 general)
src/articulated_vehicles.cpp
Show inline comments
 
@@ -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 IsArticulatedVehicleCarryingDiffere
 
	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)
 
{
src/articulated_vehicles.h
Show inline comments
 
@@ -15,5 +15,7 @@ uint32 GetUnionOfArticulatedRefitMasks(E
 
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 */
src/lang/english.txt
Show inline comments
 
@@ -3170,6 +3170,9 @@ STR_NEWGRF_BROKEN                       
 
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
src/newgrf_config.h
Show inline comments
 
@@ -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 */
src/roadveh_cmd.cpp
Show inline comments
 
@@ -275,10 +275,13 @@ CommandCost CmdBuildRoadVeh(TileIndex ti
 
		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;
src/train_cmd.cpp
Show inline comments
 
@@ -178,23 +178,7 @@ static void RailVehicleLengthChanged(con
 
	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(Eng
 
			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(TileInde
 
		}
 

	
 
		GetCompany(_current_company)->num_engines[p1]++;
 

	
 
		CheckConsistencyOfArticulatedVehicle(v);
 
	}
 

	
 
	return value;
src/vehicle.cpp
Show inline comments
 
@@ -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() 
 
	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) {
src/vehicle_func.h
Show inline comments
 
@@ -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 *
 

	
 
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);
 

	
0 comments (0 inline, 0 general)