diff --git a/src/cargomonitor.cpp b/src/cargomonitor.cpp index 5120967854..6435ab1711 100644 --- a/src/cargomonitor.cpp +++ b/src/cargomonitor.cpp @@ -67,7 +67,7 @@ void ClearCargoDeliveryMonitoring(CompanyID company) * @param keep_monitoring After returning from this call, continue monitoring. * @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); if (iter == monitor_map.end()) { @@ -77,7 +77,7 @@ static uint32 GetAmount(CargoMonitorMap &monitor_map, CargoMonitorID monitor, bo } return 0; } else { - uint32 result = iter->second; + int32 result = iter->second; iter->second = 0; if (!keep_monitoring) monitor_map.erase(iter); 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. * @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); } @@ -102,7 +102,7 @@ uint32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring) * @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. */ -uint32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring) +int32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring) { return GetAmount(_cargo_pickups, monitor, keep_monitoring); } diff --git a/src/cargomonitor.h b/src/cargomonitor.h index ce9a8e5d6d..061a1821a4 100644 --- a/src/cargomonitor.h +++ b/src/cargomonitor.h @@ -16,6 +16,7 @@ #include "company_func.h" #include "industry.h" #include "town.h" +#include "core/overflowsafe_type.hpp" #include struct Station; @@ -31,7 +32,7 @@ struct Station; typedef uint32 CargoMonitorID; ///< Type of the cargo monitor number. /** Map type for storing and updating active cargo monitor numbers and their amounts. */ -typedef std::map CargoMonitorMap; +typedef std::map CargoMonitorMap; extern CargoMonitorMap _cargo_pickups; extern CargoMonitorMap _cargo_deliveries; @@ -141,8 +142,8 @@ static inline TownID DecodeMonitorTown(CargoMonitorID num) void ClearCargoPickupMonitoring(CompanyID company = INVALID_OWNER); void ClearCargoDeliveryMonitoring(CompanyID company = INVALID_OWNER); -uint32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring); -uint32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring); +int32 GetDeliveryAmount(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); #endif /* CARGOMONITOR_H */ diff --git a/src/core/overflowsafe_type.hpp b/src/core/overflowsafe_type.hpp index 42ec98bd00..edc25d2755 100644 --- a/src/core/overflowsafe_type.hpp +++ b/src/core/overflowsafe_type.hpp @@ -152,5 +152,6 @@ template inline OverflowSafeInt inline OverflowSafeInt operator / (byte a, OverflowSafeInt b) { return (OverflowSafeInt)a / (int)b; } typedef OverflowSafeInt OverflowSafeInt64; +typedef OverflowSafeInt OverflowSafeInt32; #endif /* OVERFLOWSAFE_TYPE_HPP */ diff --git a/src/ground_vehicle.cpp b/src/ground_vehicle.cpp index 5712b28f96..fcdd4d20d9 100644 --- a/src/ground_vehicle.cpp +++ b/src/ground_vehicle.cpp @@ -106,15 +106,30 @@ int GroundVehicle::GetAcceleration() const { /* Templated class used for function calls for performance reasons. */ 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. */ int32 mass = this->gcache.cached_weight; - /* Power is stored in HP, we need it in watts. */ - int32 power = this->gcache.cached_power * 746; + /* Power is stored in HP, we need it in watts. + * 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; @@ -134,7 +149,9 @@ int GroundVehicle::GetAcceleration() const AccelStatus mode = v->GetAccelerationStatus(); 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 (!maglev) { /* Conversion factor from km/h to m/s is 5/18 to get [N] in the end. */ @@ -158,10 +175,10 @@ int GroundVehicle::GetAcceleration() const * 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 * 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); } else { - return min(-force - resistance, -10000) / mass; + return ClampToI32(min(-force - resistance, -10000) / mass); } } diff --git a/src/ground_vehicle.hpp b/src/ground_vehicle.hpp index 80a88b705f..c38c6c4b7d 100644 --- a/src/ground_vehicle.hpp +++ b/src/ground_vehicle.hpp @@ -113,9 +113,9 @@ struct GroundVehicle : public SpecializedVehicle { * Calculates the total slope resistance for this vehicle. * @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()) { if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) { diff --git a/src/script/api/game_changelog.hpp b/src/script/api/game_changelog.hpp index c075a95cba..14531546ad 100644 --- a/src/script/api/game_changelog.hpp +++ b/src/script/api/game_changelog.hpp @@ -15,6 +15,12 @@ * functions may still be available if you return an older API version * 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 * * No changes diff --git a/src/script/api/script_cargomonitor.cpp b/src/script/api/script_cargomonitor.cpp index e19821bba8..4d8a1bac97 100644 --- a/src/script/api/script_cargomonitor.cpp +++ b/src/script/api/script_cargomonitor.cpp @@ -10,29 +10,52 @@ /** @file script_cargomonitor.cpp Code to monitor cargo pickup and deliveries by companies. */ #include "../../stdafx.h" +#include "script_cargo.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(company), cargo, town_id); + CompanyID cid = static_cast(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); } -/* 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(company), cargo, industry_id); + CompanyID cid = static_cast(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); } -/* 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(company), cargo, town_id); + CompanyID cid = static_cast(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); } -/* 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(company), cargo, industry_id); + CompanyID cid = static_cast(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); } diff --git a/src/script/api/script_cargomonitor.hpp b/src/script/api/script_cargomonitor.hpp index f0fa56be94..175936db26 100644 --- a/src/script/api/script_cargomonitor.hpp +++ b/src/script/api/script_cargomonitor.hpp @@ -50,9 +50,10 @@ public: * @param cargo Cargo type 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. - * @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. @@ -60,9 +61,10 @@ public: * @param cargo Cargo type 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. - * @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. @@ -70,10 +72,11 @@ public: * @param cargo Cargo type 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. - * @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. */ - 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. @@ -81,10 +84,11 @@ public: * @param cargo Cargo type 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. - * @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. */ - 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. */ static void StopAllMonitoring(); diff --git a/src/vehicle.cpp b/src/vehicle.cpp index ceb345f469..f7fc9f306e 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -233,6 +233,9 @@ void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRF const Engine *e = Engine::Get(engine); 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)) { SetBit(grfconfig->grf_bugs, bug_type); SetDParamStr(0, grfconfig->GetName());