mirror of https://github.com/OpenTTD/OpenTTD.git
(svn r26714) [1.4] -Backport from trunk:
- Fix: Integer overflows in acceleration code causing either too low acceleration or too high acceleration [FS#6067] (r26702) - Fix: Do not crash when trying to show an error about vehicle in a NewGRF and the NewGRF was not loaded at all (r26699) - Fix: Tighten parameter bound checks on GSCargoMonitor functions, and return -1 on out-of-bound parameters (r26685)
This commit is contained in:
parent
3630a2cc4e
commit
3614c4447f
|
@ -67,7 +67,7 @@ void ClearCargoDeliveryMonitoring(CompanyID company)
|
||||||
* @param keep_monitoring After returning from this call, continue monitoring.
|
* @param keep_monitoring After returning from this call, continue monitoring.
|
||||||
* @return Amount collected since last query/activation for the monitored combination.
|
* @return Amount collected since last query/activation for the monitored combination.
|
||||||
*/
|
*/
|
||||||
static uint32 GetAmount(CargoMonitorMap &monitor_map, CargoMonitorID monitor, bool keep_monitoring)
|
static int32 GetAmount(CargoMonitorMap &monitor_map, CargoMonitorID monitor, bool keep_monitoring)
|
||||||
{
|
{
|
||||||
CargoMonitorMap::iterator iter = monitor_map.find(monitor);
|
CargoMonitorMap::iterator iter = monitor_map.find(monitor);
|
||||||
if (iter == monitor_map.end()) {
|
if (iter == monitor_map.end()) {
|
||||||
|
@ -77,7 +77,7 @@ static uint32 GetAmount(CargoMonitorMap &monitor_map, CargoMonitorID monitor, bo
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
uint32 result = iter->second;
|
int32 result = iter->second;
|
||||||
iter->second = 0;
|
iter->second = 0;
|
||||||
if (!keep_monitoring) monitor_map.erase(iter);
|
if (!keep_monitoring) monitor_map.erase(iter);
|
||||||
return result;
|
return result;
|
||||||
|
@ -90,7 +90,7 @@ static uint32 GetAmount(CargoMonitorMap &monitor_map, CargoMonitorID monitor, bo
|
||||||
* @param keep_monitoring After returning from this call, continue monitoring.
|
* @param keep_monitoring After returning from this call, continue monitoring.
|
||||||
* @return Amount of delivered cargo for the monitored combination.
|
* @return Amount of delivered cargo for the monitored combination.
|
||||||
*/
|
*/
|
||||||
uint32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring)
|
int32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring)
|
||||||
{
|
{
|
||||||
return GetAmount(_cargo_deliveries, monitor, keep_monitoring);
|
return GetAmount(_cargo_deliveries, monitor, keep_monitoring);
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ uint32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring)
|
||||||
* @return Amount of picked up cargo for the monitored combination.
|
* @return Amount of picked up cargo for the monitored combination.
|
||||||
* @note Cargo pick up is counted on final delivery, to prevent users getting credit for picking up cargo without delivering it.
|
* @note Cargo pick up is counted on final delivery, to prevent users getting credit for picking up cargo without delivering it.
|
||||||
*/
|
*/
|
||||||
uint32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring)
|
int32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring)
|
||||||
{
|
{
|
||||||
return GetAmount(_cargo_pickups, monitor, keep_monitoring);
|
return GetAmount(_cargo_pickups, monitor, keep_monitoring);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "company_func.h"
|
#include "company_func.h"
|
||||||
#include "industry.h"
|
#include "industry.h"
|
||||||
#include "town.h"
|
#include "town.h"
|
||||||
|
#include "core/overflowsafe_type.hpp"
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
struct Station;
|
struct Station;
|
||||||
|
@ -31,7 +32,7 @@ struct Station;
|
||||||
typedef uint32 CargoMonitorID; ///< Type of the cargo monitor number.
|
typedef uint32 CargoMonitorID; ///< Type of the cargo monitor number.
|
||||||
|
|
||||||
/** Map type for storing and updating active cargo monitor numbers and their amounts. */
|
/** Map type for storing and updating active cargo monitor numbers and their amounts. */
|
||||||
typedef std::map<CargoMonitorID, uint32> CargoMonitorMap;
|
typedef std::map<CargoMonitorID, OverflowSafeInt32> CargoMonitorMap;
|
||||||
|
|
||||||
extern CargoMonitorMap _cargo_pickups;
|
extern CargoMonitorMap _cargo_pickups;
|
||||||
extern CargoMonitorMap _cargo_deliveries;
|
extern CargoMonitorMap _cargo_deliveries;
|
||||||
|
@ -141,8 +142,8 @@ static inline TownID DecodeMonitorTown(CargoMonitorID num)
|
||||||
|
|
||||||
void ClearCargoPickupMonitoring(CompanyID company = INVALID_OWNER);
|
void ClearCargoPickupMonitoring(CompanyID company = INVALID_OWNER);
|
||||||
void ClearCargoDeliveryMonitoring(CompanyID company = INVALID_OWNER);
|
void ClearCargoDeliveryMonitoring(CompanyID company = INVALID_OWNER);
|
||||||
uint32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring);
|
int32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring);
|
||||||
uint32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring);
|
int32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring);
|
||||||
void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st);
|
void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st);
|
||||||
|
|
||||||
#endif /* CARGOMONITOR_H */
|
#endif /* CARGOMONITOR_H */
|
||||||
|
|
|
@ -152,5 +152,6 @@ template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_
|
||||||
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator / (byte a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return (OverflowSafeInt<T, T_MAX, T_MIN>)a / (int)b; }
|
template <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_MIN> operator / (byte a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return (OverflowSafeInt<T, T_MAX, T_MIN>)a / (int)b; }
|
||||||
|
|
||||||
typedef OverflowSafeInt<int64, INT64_MAX, INT64_MIN> OverflowSafeInt64;
|
typedef OverflowSafeInt<int64, INT64_MAX, INT64_MIN> OverflowSafeInt64;
|
||||||
|
typedef OverflowSafeInt<int32, INT32_MAX, INT32_MIN> OverflowSafeInt32;
|
||||||
|
|
||||||
#endif /* OVERFLOWSAFE_TYPE_HPP */
|
#endif /* OVERFLOWSAFE_TYPE_HPP */
|
||||||
|
|
|
@ -106,15 +106,30 @@ int GroundVehicle<T, Type>::GetAcceleration() const
|
||||||
{
|
{
|
||||||
/* Templated class used for function calls for performance reasons. */
|
/* Templated class used for function calls for performance reasons. */
|
||||||
const T *v = T::From(this);
|
const T *v = T::From(this);
|
||||||
int32 speed = v->GetCurrentSpeed(); // [km/h-ish]
|
/* Speed is used squared later on, so U16 * U16, and then multiplied by other values. */
|
||||||
|
int64 speed = v->GetCurrentSpeed(); // [km/h-ish]
|
||||||
|
|
||||||
/* Weight is stored in tonnes. */
|
/* Weight is stored in tonnes. */
|
||||||
int32 mass = this->gcache.cached_weight;
|
int32 mass = this->gcache.cached_weight;
|
||||||
|
|
||||||
/* Power is stored in HP, we need it in watts. */
|
/* Power is stored in HP, we need it in watts.
|
||||||
int32 power = this->gcache.cached_power * 746;
|
* Each vehicle can have U16 power, 128 vehicles, HP -> watt
|
||||||
|
* and km/h to m/s conversion below result in a maxium of
|
||||||
|
* about 1.1E11, way more than 4.3E9 of int32. */
|
||||||
|
int64 power = this->gcache.cached_power * 746ll;
|
||||||
|
|
||||||
int32 resistance = 0;
|
/* This is constructed from:
|
||||||
|
* - axle resistance: U16 power * 10 for 128 vehicles.
|
||||||
|
* * 8.3E7
|
||||||
|
* - rolling friction: U16 power * 144 for 128 vehicles.
|
||||||
|
* * 1.2E9
|
||||||
|
* - slope resistance: U16 weight * 100 * 10 (steepness) for 128 vehicles.
|
||||||
|
* * 8.4E9
|
||||||
|
* - air drag: 28 * (U8 drag + 3 * U8 drag * 128 vehicles / 20) * U16 speed * U16 speed
|
||||||
|
* * 6.2E14 before dividing by 1000
|
||||||
|
* Sum is 6.3E11, more than 4.3E9 of int32, so int64 is needed.
|
||||||
|
*/
|
||||||
|
int64 resistance = 0;
|
||||||
|
|
||||||
bool maglev = v->GetAccelerationType() == 2;
|
bool maglev = v->GetAccelerationType() == 2;
|
||||||
|
|
||||||
|
@ -134,7 +149,9 @@ int GroundVehicle<T, Type>::GetAcceleration() const
|
||||||
AccelStatus mode = v->GetAccelerationStatus();
|
AccelStatus mode = v->GetAccelerationStatus();
|
||||||
|
|
||||||
const int max_te = this->gcache.cached_max_te; // [N]
|
const int max_te = this->gcache.cached_max_te; // [N]
|
||||||
int force;
|
/* Constructued from power, with need to multiply by 18 and assuming
|
||||||
|
* low speed, it needs to be a 64 bit integer too. */
|
||||||
|
int64 force;
|
||||||
if (speed > 0) {
|
if (speed > 0) {
|
||||||
if (!maglev) {
|
if (!maglev) {
|
||||||
/* Conversion factor from km/h to m/s is 5/18 to get [N] in the end. */
|
/* Conversion factor from km/h to m/s is 5/18 to get [N] in the end. */
|
||||||
|
@ -158,10 +175,10 @@ int GroundVehicle<T, Type>::GetAcceleration() const
|
||||||
* down hill will never slow down enough, and a vehicle that came up
|
* down hill will never slow down enough, and a vehicle that came up
|
||||||
* a hill will never speed up enough to (eventually) get back to the
|
* a hill will never speed up enough to (eventually) get back to the
|
||||||
* same (maximum) speed. */
|
* same (maximum) speed. */
|
||||||
int accel = (force - resistance) / (mass * 4);
|
int accel = ClampToI32((force - resistance) / (mass * 4));
|
||||||
return force < resistance ? min(-1, accel) : max(1, accel);
|
return force < resistance ? min(-1, accel) : max(1, accel);
|
||||||
} else {
|
} else {
|
||||||
return min(-force - resistance, -10000) / mass;
|
return ClampToI32(min(-force - resistance, -10000) / mass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -113,9 +113,9 @@ struct GroundVehicle : public SpecializedVehicle<T, Type> {
|
||||||
* Calculates the total slope resistance for this vehicle.
|
* Calculates the total slope resistance for this vehicle.
|
||||||
* @return Slope resistance.
|
* @return Slope resistance.
|
||||||
*/
|
*/
|
||||||
inline int32 GetSlopeResistance() const
|
inline int64 GetSlopeResistance() const
|
||||||
{
|
{
|
||||||
int32 incl = 0;
|
int64 incl = 0;
|
||||||
|
|
||||||
for (const T *u = T::From(this); u != NULL; u = u->Next()) {
|
for (const T *u = T::From(this); u != NULL; u = u->Next()) {
|
||||||
if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) {
|
if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) {
|
||||||
|
|
|
@ -15,6 +15,12 @@
|
||||||
* functions may still be available if you return an older API version
|
* functions may still be available if you return an older API version
|
||||||
* in GetAPIVersion() in info.nut.
|
* in GetAPIVersion() in info.nut.
|
||||||
*
|
*
|
||||||
|
* \b 1.4.2
|
||||||
|
*
|
||||||
|
* Other changes:
|
||||||
|
* \li GSCargoMonitor delivery and pickup monitor functions have improved boundary checking for
|
||||||
|
* their parameters, and return \c -1 if they are found out of bounds.
|
||||||
|
*
|
||||||
* \b 1.4.1
|
* \b 1.4.1
|
||||||
*
|
*
|
||||||
* No changes
|
* No changes
|
||||||
|
|
|
@ -10,29 +10,52 @@
|
||||||
/** @file script_cargomonitor.cpp Code to monitor cargo pickup and deliveries by companies. */
|
/** @file script_cargomonitor.cpp Code to monitor cargo pickup and deliveries by companies. */
|
||||||
|
|
||||||
#include "../../stdafx.h"
|
#include "../../stdafx.h"
|
||||||
|
#include "script_cargo.hpp"
|
||||||
#include "script_cargomonitor.hpp"
|
#include "script_cargomonitor.hpp"
|
||||||
|
#include "../../town.h"
|
||||||
|
#include "../../industry.h"
|
||||||
|
|
||||||
/* static */ uint32 ScriptCargoMonitor::GetTownDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring)
|
/* static */ int32 ScriptCargoMonitor::GetTownDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring)
|
||||||
{
|
{
|
||||||
CargoMonitorID monitor = EncodeCargoTownMonitor(static_cast<CompanyID>(company), cargo, town_id);
|
CompanyID cid = static_cast<CompanyID>(company);
|
||||||
|
if (cid < OWNER_BEGIN || cid >= MAX_COMPANIES) return -1;
|
||||||
|
if (!ScriptCargo::IsValidCargo(cargo)) return -1;
|
||||||
|
if (!::Town::IsValidID(town_id)) return -1;
|
||||||
|
|
||||||
|
CargoMonitorID monitor = EncodeCargoTownMonitor(cid, cargo, town_id);
|
||||||
return GetDeliveryAmount(monitor, keep_monitoring);
|
return GetDeliveryAmount(monitor, keep_monitoring);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ uint32 ScriptCargoMonitor::GetIndustryDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring)
|
/* static */ int32 ScriptCargoMonitor::GetIndustryDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring)
|
||||||
{
|
{
|
||||||
CargoMonitorID monitor = EncodeCargoIndustryMonitor(static_cast<CompanyID>(company), cargo, industry_id);
|
CompanyID cid = static_cast<CompanyID>(company);
|
||||||
|
if (cid < OWNER_BEGIN || cid >= MAX_COMPANIES) return -1;
|
||||||
|
if (!ScriptCargo::IsValidCargo(cargo)) return -1;
|
||||||
|
if (!::Industry::IsValidID(industry_id)) return -1;
|
||||||
|
|
||||||
|
CargoMonitorID monitor = EncodeCargoIndustryMonitor(cid, cargo, industry_id);
|
||||||
return GetDeliveryAmount(monitor, keep_monitoring);
|
return GetDeliveryAmount(monitor, keep_monitoring);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ uint32 ScriptCargoMonitor::GetTownPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring)
|
/* static */ int32 ScriptCargoMonitor::GetTownPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring)
|
||||||
{
|
{
|
||||||
CargoMonitorID monitor = EncodeCargoTownMonitor(static_cast<CompanyID>(company), cargo, town_id);
|
CompanyID cid = static_cast<CompanyID>(company);
|
||||||
|
if (cid < OWNER_BEGIN || cid >= MAX_COMPANIES) return -1;
|
||||||
|
if (!ScriptCargo::IsValidCargo(cargo)) return -1;
|
||||||
|
if (!::Town::IsValidID(town_id)) return -1;
|
||||||
|
|
||||||
|
CargoMonitorID monitor = EncodeCargoTownMonitor(cid, cargo, town_id);
|
||||||
return GetPickupAmount(monitor, keep_monitoring);
|
return GetPickupAmount(monitor, keep_monitoring);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ uint32 ScriptCargoMonitor::GetIndustryPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring)
|
/* static */ int32 ScriptCargoMonitor::GetIndustryPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring)
|
||||||
{
|
{
|
||||||
CargoMonitorID monitor = EncodeCargoIndustryMonitor(static_cast<CompanyID>(company), cargo, industry_id);
|
CompanyID cid = static_cast<CompanyID>(company);
|
||||||
|
if (cid < OWNER_BEGIN || cid >= MAX_COMPANIES) return -1;
|
||||||
|
if (!ScriptCargo::IsValidCargo(cargo)) return -1;
|
||||||
|
if (!::Industry::IsValidID(industry_id)) return -1;
|
||||||
|
|
||||||
|
CargoMonitorID monitor = EncodeCargoIndustryMonitor(cid, cargo, industry_id);
|
||||||
return GetPickupAmount(monitor, keep_monitoring);
|
return GetPickupAmount(monitor, keep_monitoring);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,10 @@ public:
|
||||||
* @param cargo Cargo type to query.
|
* @param cargo Cargo type to query.
|
||||||
* @param town_id %Town to query.
|
* @param town_id %Town to query.
|
||||||
* @param keep_monitoring If \c true, the given combination continues to be monitored for the next call. If \c false, monitoring ends.
|
* @param keep_monitoring If \c true, the given combination continues to be monitored for the next call. If \c false, monitoring ends.
|
||||||
* @return Amount of delivered cargo of the given cargo type to the given town by the given company since the last call.
|
* @return Amount of delivered cargo of the given cargo type to the given town by the given company since the last call, or
|
||||||
|
* \c -1 if a parameter is out-of-bound.
|
||||||
*/
|
*/
|
||||||
static uint32 GetTownDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring);
|
static int32 GetTownDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the amount of cargo delivered to an industry by a company since the last query, and update the monitoring state.
|
* Get the amount of cargo delivered to an industry by a company since the last query, and update the monitoring state.
|
||||||
|
@ -60,9 +61,10 @@ public:
|
||||||
* @param cargo Cargo type to query.
|
* @param cargo Cargo type to query.
|
||||||
* @param industry_id %Industry to query.
|
* @param industry_id %Industry to query.
|
||||||
* @param keep_monitoring If \c true, the given combination continues to be monitored for the next call. If \c false, monitoring ends.
|
* @param keep_monitoring If \c true, the given combination continues to be monitored for the next call. If \c false, monitoring ends.
|
||||||
* @return Amount of delivered cargo of the given cargo type to the given industry by the given company since the last call.
|
* @return Amount of delivered cargo of the given cargo type to the given industry by the given company since the last call, or
|
||||||
|
* \c -1 if a parameter is out-of-bound.
|
||||||
*/
|
*/
|
||||||
static uint32 GetIndustryDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring);
|
static int32 GetIndustryDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the amount of cargo picked up (and delivered) from a town by a company since the last query, and update the monitoring state.
|
* Get the amount of cargo picked up (and delivered) from a town by a company since the last query, and update the monitoring state.
|
||||||
|
@ -70,10 +72,11 @@ public:
|
||||||
* @param cargo Cargo type to query.
|
* @param cargo Cargo type to query.
|
||||||
* @param town_id %Town to query.
|
* @param town_id %Town to query.
|
||||||
* @param keep_monitoring If \c true, the given combination continues to be monitored for the next call. If \c false, monitoring ends.
|
* @param keep_monitoring If \c true, the given combination continues to be monitored for the next call. If \c false, monitoring ends.
|
||||||
* @return Amount of picked up cargo of the given cargo type to the given town by the given company since the last call.
|
* @return Amount of picked up cargo of the given cargo type to the given town by the given company since the last call, or
|
||||||
|
* \c -1 if a parameter is out-of-bound.
|
||||||
* @note Amounts of picked-up cargo are added during final delivery of it, to prevent users from getting credit for picking up without delivering it.
|
* @note Amounts of picked-up cargo are added during final delivery of it, to prevent users from getting credit for picking up without delivering it.
|
||||||
*/
|
*/
|
||||||
static uint32 GetTownPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring);
|
static int32 GetTownPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the amount of cargo picked up (and delivered) from an industry by a company since the last query, and update the monitoring state.
|
* Get the amount of cargo picked up (and delivered) from an industry by a company since the last query, and update the monitoring state.
|
||||||
|
@ -81,10 +84,11 @@ public:
|
||||||
* @param cargo Cargo type to query.
|
* @param cargo Cargo type to query.
|
||||||
* @param industry_id %Industry to query.
|
* @param industry_id %Industry to query.
|
||||||
* @param keep_monitoring If \c true, the given combination continues to be monitored for the next call. If \c false, monitoring ends.
|
* @param keep_monitoring If \c true, the given combination continues to be monitored for the next call. If \c false, monitoring ends.
|
||||||
* @return Amount of picked up cargo of the given cargo type to the given industry by the given company since the last call.
|
* @return Amount of picked up cargo of the given cargo type to the given industry by the given company since the last call, or
|
||||||
|
* \c -1 if a parameter is out-of-bound.
|
||||||
* @note Amounts of picked-up cargo are added during final delivery of it, to prevent users from getting credit for picking up without delivering it.
|
* @note Amounts of picked-up cargo are added during final delivery of it, to prevent users from getting credit for picking up without delivering it.
|
||||||
*/
|
*/
|
||||||
static uint32 GetIndustryPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring);
|
static int32 GetIndustryPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring);
|
||||||
|
|
||||||
/** Stop monitoring everything. */
|
/** Stop monitoring everything. */
|
||||||
static void StopAllMonitoring();
|
static void StopAllMonitoring();
|
||||||
|
|
|
@ -233,6 +233,9 @@ void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRF
|
||||||
const Engine *e = Engine::Get(engine);
|
const Engine *e = Engine::Get(engine);
|
||||||
GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID());
|
GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID());
|
||||||
|
|
||||||
|
/* Missing GRF. Nothing useful can be done in this situation. */
|
||||||
|
if (grfconfig == NULL) return;
|
||||||
|
|
||||||
if (!HasBit(grfconfig->grf_bugs, bug_type)) {
|
if (!HasBit(grfconfig->grf_bugs, bug_type)) {
|
||||||
SetBit(grfconfig->grf_bugs, bug_type);
|
SetBit(grfconfig->grf_bugs, bug_type);
|
||||||
SetDParamStr(0, grfconfig->GetName());
|
SetDParamStr(0, grfconfig->GetName());
|
||||||
|
|
Loading…
Reference in New Issue