From 1595413545653e75d2346e9937cf7795b2aa0528 Mon Sep 17 00:00:00 2001 From: rubidium Date: Mon, 30 Mar 2009 23:22:13 +0000 Subject: [PATCH] (svn r15904) [0.7] -Backport from trunk: - Feature: Watermark crash.sav and do not generate crash information if a loaded crash.sav causes a crash so the real crash report does not get overwritten (r15893) - Feature: Add autoclean_novehicles setting which will, when autoclean_companies is true, remove any company with no vehicles and no active client after autoclean_novehicles-months (r15848) - Add: [NoAI] AIIndustryType::IsBuiltOnWater(), HasHeliport() and HasDock(). Just like AIIndustry (r15901) - Add: [NoAI] AIBridge::GetBridgeID() so AIs can get the type of bridge that are already build (r15875) - Add: [NoAI] AIRoad::GetRoadVehicleTypeForCargo() to tell whether a certain cargo needs a bus- or a truckstop (r15860) --- bin/ai/regression/regression.nut | 7 ++++ bin/ai/regression/regression.txt | 55 +++++++++++++++++++++++++++++++ src/ai/api/ai_bridge.cpp | 6 ++++ src/ai/api/ai_bridge.hpp | 8 +++++ src/ai/api/ai_bridge.hpp.sq | 1 + src/ai/api/ai_cargo.hpp | 9 ++++- src/ai/api/ai_industrytype.cpp | 21 ++++++++++++ src/ai/api/ai_industrytype.hpp | 24 ++++++++++++++ src/ai/api/ai_industrytype.hpp.sq | 3 ++ src/ai/api/ai_road.cpp | 6 ++++ src/ai/api/ai_road.hpp | 8 +++++ src/ai/api/ai_road.hpp.sq | 1 + src/gamelog.cpp | 29 ++++++++++++++++ src/gamelog.h | 4 +++ src/gamelog_internal.h | 1 + src/network/network_server.cpp | 19 ++++++++++- src/saveload/gamelog_sl.cpp | 5 +++ src/saveload/saveload.cpp | 2 +- src/settings.cpp | 1 + src/settings_type.h | 1 + src/win32.cpp | 11 +++++++ 21 files changed, 219 insertions(+), 3 deletions(-) diff --git a/bin/ai/regression/regression.nut b/bin/ai/regression/regression.nut index 4a2e8433f5..02f2e55bfc 100644 --- a/bin/ai/regression/regression.nut +++ b/bin/ai/regression/regression.nut @@ -256,12 +256,15 @@ function Regression::Bridge() print(" Valid Bridges: " + j); print(" IsBridgeTile(): " + AIBridge.IsBridgeTile(33160)); + print(" GetBridgeID(): " + AIBridge.GetBridgeID(33160)); print(" RemoveBridge(): " + AIBridge.RemoveBridge(33155)); print(" GetLastErrorString(): " + AIError.GetLastErrorString()); print(" GetOtherBridgeEnd(): " + AIBridge.GetOtherBridgeEnd(33160)); print(" BuildBridge(): " + AIBridge.BuildBridge(AIVehicle.VT_ROAD, 5, 33160, 33155)); print(" IsBridgeTile(): " + AIBridge.IsBridgeTile(33160)); + print(" GetBridgeID(): " + AIBridge.GetBridgeID(33160)); print(" IsBridgeTile(): " + AIBridge.IsBridgeTile(33155)); + print(" GetBridgeID(): " + AIBridge.GetBridgeID(33155)); print(" GetOtherBridgeEnd(): " + AIBridge.GetOtherBridgeEnd(33160)); print(" BuildBridge(): " + AIBridge.BuildBridge(AIVehicle.VT_ROAD, 5, 33160, 33155)); print(" GetLastErrorString(): " + AIError.GetLastErrorString()); @@ -329,6 +332,7 @@ function Regression::Cargo() print(" GetCargoIncome(10, 10): " + AICargo.GetCargoIncome(i, 10, 10)); print(" GetCargoIncome(100, 10): " + AICargo.GetCargoIncome(i, 100, 10)); print(" GetCargoIncome(10, 100): " + AICargo.GetCargoIncome(i, 10, 100)); + print(" GetRoadVehicleTypeForCargo(): " + AIRoad.GetRoadVehicleTypeForCargo(i)); } } @@ -631,6 +635,9 @@ function Regression::IndustryTypeList() print(" GetName(): " + AIIndustryType.GetName(i)); print(" CanBuildIndustry(): " + AIIndustryType.CanBuildIndustry(i)); print(" CanProspectIndustry(): " + AIIndustryType.CanProspectIndustry(i)); + print(" IsBuiltOnWater(): " + AIIndustryType.IsBuiltOnWater(i)); + print(" HasHeliport(): " + AIIndustryType.HasHeliport(i)); + print(" HasDock(): " + AIIndustryType.HasDock(i)); } } diff --git a/bin/ai/regression/regression.txt b/bin/ai/regression/regression.txt index f0b28de8a1..c3c7931791 100644 --- a/bin/ai/regression/regression.txt +++ b/bin/ai/regression/regression.txt @@ -743,12 +743,15 @@ GetMinLength(): -1 Valid Bridges: 10 IsBridgeTile(): false + GetBridgeID(): -1 RemoveBridge(): false GetLastErrorString(): ERR_PRECONDITION_FAILED GetOtherBridgeEnd(): -1 BuildBridge(): true IsBridgeTile(): true + GetBridgeID(): 5 IsBridgeTile(): true + GetBridgeID(): 5 GetOtherBridgeEnd(): 33155 BuildBridge(): false GetLastErrorString(): ERR_ALREADY_BUILT @@ -824,6 +827,7 @@ GetCargoIncome(10, 10): -1 GetCargoIncome(100, 10): -1 GetCargoIncome(10, 100): -1 + GetRoadVehicleTypeForCargo(): 1 Cargo 0 IsValidCargo(): true GetCargoLabel(): 'PASS' @@ -834,6 +838,7 @@ GetCargoIncome(10, 10): 3 GetCargoIncome(100, 10): 39 GetCargoIncome(10, 100): 3 + GetRoadVehicleTypeForCargo(): 0 Cargo 1 IsValidCargo(): true GetCargoLabel(): 'COAL' @@ -844,6 +849,7 @@ GetCargoIncome(10, 10): 7 GetCargoIncome(100, 10): 75 GetCargoIncome(10, 100): 6 + GetRoadVehicleTypeForCargo(): 1 Cargo 2 IsValidCargo(): true GetCargoLabel(): 'MAIL' @@ -854,6 +860,7 @@ GetCargoIncome(10, 10): 5 GetCargoIncome(100, 10): 58 GetCargoIncome(10, 100): 5 + GetRoadVehicleTypeForCargo(): 1 Cargo 3 IsValidCargo(): true GetCargoLabel(): 'OIL_' @@ -864,6 +871,7 @@ GetCargoIncome(10, 10): 5 GetCargoIncome(100, 10): 56 GetCargoIncome(10, 100): 5 + GetRoadVehicleTypeForCargo(): 1 Cargo 4 IsValidCargo(): true GetCargoLabel(): 'LVST' @@ -874,6 +882,7 @@ GetCargoIncome(10, 10): 5 GetCargoIncome(100, 10): 55 GetCargoIncome(10, 100): 4 + GetRoadVehicleTypeForCargo(): 1 Cargo 5 IsValidCargo(): true GetCargoLabel(): 'GOOD' @@ -884,6 +893,7 @@ GetCargoIncome(10, 10): 7 GetCargoIncome(100, 10): 78 GetCargoIncome(10, 100): 6 + GetRoadVehicleTypeForCargo(): 1 Cargo 6 IsValidCargo(): true GetCargoLabel(): 'GRAI' @@ -894,6 +904,7 @@ GetCargoIncome(10, 10): 6 GetCargoIncome(100, 10): 60 GetCargoIncome(10, 100): 5 + GetRoadVehicleTypeForCargo(): 1 Cargo 7 IsValidCargo(): true GetCargoLabel(): 'WOOD' @@ -904,6 +915,7 @@ GetCargoIncome(10, 10): 6 GetCargoIncome(100, 10): 63 GetCargoIncome(10, 100): 5 + GetRoadVehicleTypeForCargo(): 1 Cargo 8 IsValidCargo(): true GetCargoLabel(): 'IORE' @@ -914,6 +926,7 @@ GetCargoIncome(10, 10): 6 GetCargoIncome(100, 10): 65 GetCargoIncome(10, 100): 5 + GetRoadVehicleTypeForCargo(): 1 Cargo 9 IsValidCargo(): true GetCargoLabel(): 'STEL' @@ -924,6 +937,7 @@ GetCargoIncome(10, 10): 7 GetCargoIncome(100, 10): 72 GetCargoIncome(10, 100): 6 + GetRoadVehicleTypeForCargo(): 1 Cargo 10 IsValidCargo(): true GetCargoLabel(): 'VALU' @@ -934,6 +948,7 @@ GetCargoIncome(10, 10): 9 GetCargoIncome(100, 10): 94 GetCargoIncome(10, 100): 7 + GetRoadVehicleTypeForCargo(): 1 Cargo 11 IsValidCargo(): false GetCargoLabel(): '(null : 0x00000000)' @@ -944,6 +959,7 @@ GetCargoIncome(10, 10): -1 GetCargoIncome(100, 10): -1 GetCargoIncome(10, 100): -1 + GetRoadVehicleTypeForCargo(): 1 Cargo 12 IsValidCargo(): false GetCargoLabel(): '(null : 0x00000000)' @@ -954,6 +970,7 @@ GetCargoIncome(10, 10): -1 GetCargoIncome(100, 10): -1 GetCargoIncome(10, 100): -1 + GetRoadVehicleTypeForCargo(): 1 Cargo 13 IsValidCargo(): false GetCargoLabel(): '(null : 0x00000000)' @@ -964,6 +981,7 @@ GetCargoIncome(10, 10): -1 GetCargoIncome(100, 10): -1 GetCargoIncome(10, 100): -1 + GetRoadVehicleTypeForCargo(): 1 Cargo 14 IsValidCargo(): false GetCargoLabel(): '(null : 0x00000000)' @@ -974,6 +992,7 @@ GetCargoIncome(10, 10): -1 GetCargoIncome(100, 10): -1 GetCargoIncome(10, 100): -1 + GetRoadVehicleTypeForCargo(): 1 --CargoList-- Count(): 11 @@ -6907,6 +6926,9 @@ GetName(): Farm CanBuildIndustry(): false CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false Id: 5 IsRawIndustry(): true ProductionCanIncrease(): true @@ -6914,6 +6936,9 @@ GetName(): Oil Rig CanBuildIndustry(): false CanProspectIndustry(): false + IsBuiltOnWater(): true + HasHeliport(): true + HasDock(): true Id: 12 IsRawIndustry(): false ProductionCanIncrease(): true @@ -6921,6 +6946,9 @@ GetName(): Bank CanBuildIndustry(): true CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false Id: 11 IsRawIndustry(): true ProductionCanIncrease(): false @@ -6928,6 +6956,9 @@ GetName(): Oil Wells CanBuildIndustry(): false CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false Id: 1 IsRawIndustry(): false ProductionCanIncrease(): true @@ -6935,6 +6966,9 @@ GetName(): Power Station CanBuildIndustry(): true CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false Id: 3 IsRawIndustry(): true ProductionCanIncrease(): true @@ -6942,6 +6976,9 @@ GetName(): Forest CanBuildIndustry(): false CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false Id: 2 IsRawIndustry(): false ProductionCanIncrease(): true @@ -6949,6 +6986,9 @@ GetName(): Sawmill CanBuildIndustry(): true CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false Id: 18 IsRawIndustry(): true ProductionCanIncrease(): true @@ -6956,6 +6996,9 @@ GetName(): Iron Ore Mine CanBuildIndustry(): false CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false Id: 0 IsRawIndustry(): true ProductionCanIncrease(): true @@ -6963,6 +7006,9 @@ GetName(): Coal Mine CanBuildIndustry(): false CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false Id: 8 IsRawIndustry(): false ProductionCanIncrease(): true @@ -6970,6 +7016,9 @@ GetName(): Steel Mill CanBuildIndustry(): true CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false Id: 4 IsRawIndustry(): false ProductionCanIncrease(): true @@ -6977,6 +7026,9 @@ GetName(): Oil Refinery CanBuildIndustry(): true CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false Id: 6 IsRawIndustry(): false ProductionCanIncrease(): true @@ -6984,6 +7036,9 @@ GetName(): Factory CanBuildIndustry(): true CanProspectIndustry(): false + IsBuiltOnWater(): false + HasHeliport(): false + HasDock(): false --Map-- GetMapSize(): 65536 diff --git a/src/ai/api/ai_bridge.cpp b/src/ai/api/ai_bridge.cpp index 58c52245e3..032841a8fa 100644 --- a/src/ai/api/ai_bridge.cpp +++ b/src/ai/api/ai_bridge.cpp @@ -23,6 +23,12 @@ return ::IsBridgeTile(tile); } +/* static */ BridgeID AIBridge::GetBridgeID(TileIndex tile) +{ + if (!IsBridgeTile(tile)) return -1; + return (BridgeID)::GetBridgeType(tile); +} + static void _DoCommandReturnBuildBridge2(class AIInstance *instance) { if (!AIBridge::_BuildBridgeRoad2()) { diff --git a/src/ai/api/ai_bridge.hpp b/src/ai/api/ai_bridge.hpp index f53ee23396..58cc9d60b7 100644 --- a/src/ai/api/ai_bridge.hpp +++ b/src/ai/api/ai_bridge.hpp @@ -51,6 +51,14 @@ public: */ static bool IsBridgeTile(TileIndex tile); + /** + * Get the BridgeID of a bridge at a given tile. + * @param tile The tile to get the BridgeID from. + * @pre IsBridgeTile(tile). + * @return The BridgeID from the bridge at tile 'tile'. + */ + static BridgeID GetBridgeID(TileIndex tile); + /** * Get the name of a bridge. * @param bridge_id The bridge to get the name of. diff --git a/src/ai/api/ai_bridge.hpp.sq b/src/ai/api/ai_bridge.hpp.sq index 1a41174573..eddd4f5daa 100644 --- a/src/ai/api/ai_bridge.hpp.sq +++ b/src/ai/api/ai_bridge.hpp.sq @@ -36,6 +36,7 @@ void SQAIBridge_Register(Squirrel *engine) { SQAIBridge.DefSQStaticMethod(engine, &AIBridge::IsValidBridge, "IsValidBridge", 2, ".i"); SQAIBridge.DefSQStaticMethod(engine, &AIBridge::IsBridgeTile, "IsBridgeTile", 2, ".i"); + SQAIBridge.DefSQStaticMethod(engine, &AIBridge::GetBridgeID, "GetBridgeID", 2, ".i"); SQAIBridge.DefSQStaticMethod(engine, &AIBridge::GetName, "GetName", 2, ".i"); SQAIBridge.DefSQStaticMethod(engine, &AIBridge::GetMaxSpeed, "GetMaxSpeed", 2, ".i"); SQAIBridge.DefSQStaticMethod(engine, &AIBridge::GetPrice, "GetPrice", 3, ".ii"); diff --git a/src/ai/api/ai_cargo.hpp b/src/ai/api/ai_cargo.hpp index 381f4f7e2d..cc71713e61 100644 --- a/src/ai/api/ai_cargo.hpp +++ b/src/ai/api/ai_cargo.hpp @@ -18,7 +18,7 @@ public: * The classes of cargo (from newgrf_cargo.h). */ enum CargoClass { - CC_PASSENGERS = 1 << 0, //!< Passengers + CC_PASSENGERS = 1 << 0, //!< Passengers. Cargos of this class appear at bus stops. Cargos not of this class appear at truck stops. CC_MAIL = 1 << 1, //!< Mail CC_EXPRESS = 1 << 2, //!< Express cargo (Goods, Food, Candy, but also possible for passengers) CC_ARMOURED = 1 << 3, //!< Armoured cargo (Valuables, Gold, Diamonds) @@ -52,6 +52,7 @@ public: /** * Gets the string representation of the cargo label. * @param cargo_type The cargo to get the string representation of. + * @pre AICargo::IsValidCargo(cargo_type). * @return The cargo label. * @note Never use this to check if it is a certain cargo. NewGRF can * redefine all of the names. @@ -60,7 +61,10 @@ public: /** * Checks whether the give cargo is a freight or not. + * This defines whether the "freight train weight multiplier" will apply to + * trains transporting this cargo. * @param cargo_type The cargo to check on. + * @pre AICargo::IsValidCargo(cargo_type). * @return True if and only if the cargo is freight. */ static bool IsFreight(CargoID cargo_type); @@ -68,6 +72,7 @@ public: /** * Check if this cargo is in the requested cargo class. * @param cargo_type The cargo to check on. + * @pre AICargo::IsValidCargo(cargo_type). * @param cargo_class The class to check for. * @return True if and only if the cargo is in the cargo class. */ @@ -76,6 +81,7 @@ public: /** * Get the effect this cargo has on a town. * @param cargo_type The cargo to check on. + * @pre AICargo::IsValidCargo(cargo_type). * @return The effect this cargo has on a town, or TE_NONE if it has no effect. */ static TownEffect GetTownEffect(CargoID cargo_type); @@ -84,6 +90,7 @@ public: * Get the income for transporting a piece of cargo over the * given distance within the specified time. * @param cargo_type The cargo to transport. + * @pre AICargo::IsValidCargo(cargo_type). * @param distance The distance the cargo travels from begin to end. * @param days_in_transit Amount of (game) days the cargo is in transit. The max value of this variable is 637. Any value higher returns the same as 637 would. * @return The amount of money that would be earned by this trip. diff --git a/src/ai/api/ai_industrytype.cpp b/src/ai/api/ai_industrytype.cpp index 83d356a3cd..cc2e2abaee 100644 --- a/src/ai/api/ai_industrytype.cpp +++ b/src/ai/api/ai_industrytype.cpp @@ -111,3 +111,24 @@ uint32 seed = ::InteractiveRandom(); return AIObject::DoCommand(0, industry_type, seed, CMD_BUILD_INDUSTRY); } + +/* static */ bool AIIndustryType::IsBuiltOnWater(IndustryType industry_type) +{ + if (!IsValidIndustryType(industry_type)) return false; + + return (::GetIndustrySpec(industry_type)->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0; +} + +/* static */ bool AIIndustryType::HasHeliport(IndustryType industry_type) +{ + if (!IsValidIndustryType(industry_type)) return false; + + return (::GetIndustrySpec(industry_type)->behaviour & INDUSTRYBEH_AI_AIRSHIP_ROUTES) != 0; +} + +/* static */ bool AIIndustryType::HasDock(IndustryType industry_type) +{ + if (!IsValidIndustryType(industry_type)) return false; + + return (::GetIndustrySpec(industry_type)->behaviour & INDUSTRYBEH_AI_AIRSHIP_ROUTES) != 0; +} diff --git a/src/ai/api/ai_industrytype.hpp b/src/ai/api/ai_industrytype.hpp index 2b92417452..2d1063b6ca 100644 --- a/src/ai/api/ai_industrytype.hpp +++ b/src/ai/api/ai_industrytype.hpp @@ -113,6 +113,30 @@ public: * @note If true is returned the money is paid, whether a new industry was build or not. */ static bool ProspectIndustry(IndustryType industry_type); + + /** + * Is this type of industry built on water. + * @param industry_type The type of the industry. + * @pre IsValidIndustryType(industry_type). + * @return True when this type is built on water. + */ + static bool IsBuiltOnWater(IndustryType industry_type); + + /** + * Does this type of industry have a heliport? + * @param industry_type The type of the industry. + * @pre IsValidIndustryType(industry_type). + * @return True when this type has a heliport. + */ + static bool HasHeliport(IndustryType industry_type); + + /** + * Does this type of industry have a dock? + * @param industry_type The type of the industry. + * @pre IsValidIndustryType(industry_type). + * @return True when this type has a dock. + */ + static bool HasDock(IndustryType industry_type); }; #endif /* AI_INDUSTRYTYPE_HPP */ diff --git a/src/ai/api/ai_industrytype.hpp.sq b/src/ai/api/ai_industrytype.hpp.sq index 0d4c607872..a84cc24892 100644 --- a/src/ai/api/ai_industrytype.hpp.sq +++ b/src/ai/api/ai_industrytype.hpp.sq @@ -28,6 +28,9 @@ void SQAIIndustryType_Register(Squirrel *engine) { SQAIIndustryType.DefSQStaticMethod(engine, &AIIndustryType::CanProspectIndustry, "CanProspectIndustry", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &AIIndustryType::BuildIndustry, "BuildIndustry", 3, ".ii"); SQAIIndustryType.DefSQStaticMethod(engine, &AIIndustryType::ProspectIndustry, "ProspectIndustry", 2, ".i"); + SQAIIndustryType.DefSQStaticMethod(engine, &AIIndustryType::IsBuiltOnWater, "IsBuiltOnWater", 2, ".i"); + SQAIIndustryType.DefSQStaticMethod(engine, &AIIndustryType::HasHeliport, "HasHeliport", 2, ".i"); + SQAIIndustryType.DefSQStaticMethod(engine, &AIIndustryType::HasDock, "HasDock", 2, ".i"); SQAIIndustryType.PostRegister(engine); } diff --git a/src/ai/api/ai_road.cpp b/src/ai/api/ai_road.cpp index 4cced8873c..4cbce4a689 100644 --- a/src/ai/api/ai_road.cpp +++ b/src/ai/api/ai_road.cpp @@ -5,12 +5,18 @@ #include "ai_road.hpp" #include "ai_map.hpp" #include "ai_station.hpp" +#include "ai_cargo.hpp" #include "../../station_map.h" #include "../../command_type.h" #include "../../settings_type.h" #include "../../company_func.h" #include "../../script/squirrel_helper_type.hpp" +/* static */ AIRoad::RoadVehicleType AIRoad::GetRoadVehicleTypeForCargo(CargoID cargo_type) +{ + return AICargo::HasCargoClass(cargo_type, AICargo::CC_PASSENGERS) ? ROADVEHTYPE_BUS : ROADVEHTYPE_TRUCK; +} + /* static */ bool AIRoad::IsRoadTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; diff --git a/src/ai/api/ai_road.hpp b/src/ai/api/ai_road.hpp index e899af7714..7bd26922df 100644 --- a/src/ai/api/ai_road.hpp +++ b/src/ai/api/ai_road.hpp @@ -56,6 +56,14 @@ public: ROADVEHTYPE_TRUCK, //!< Build objects useable for trucks and cargo trams }; + /** + * Determines whether a busstop or a truckstop is needed to transport a certain cargo. + * @param cargo_type The cargo to test. + * @pre AICargo::IsValidCargo(cargo_type). + * @return The road vehicle type needed to transport the cargo. + */ + static RoadVehicleType GetRoadVehicleTypeForCargo(CargoID cargo_type); + /** * Checks whether the given tile is actually a tile with road that can be * used to traverse a tile. This excludes road depots and 'normal' road diff --git a/src/ai/api/ai_road.hpp.sq b/src/ai/api/ai_road.hpp.sq index b495dbba7f..4c89d93a49 100644 --- a/src/ai/api/ai_road.hpp.sq +++ b/src/ai/api/ai_road.hpp.sq @@ -46,6 +46,7 @@ void SQAIRoad_Register(Squirrel *engine) { AIError::RegisterErrorMapString(AIRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, "ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD"); AIError::RegisterErrorMapString(AIRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, "ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS"); + SQAIRoad.DefSQStaticMethod(engine, &AIRoad::GetRoadVehicleTypeForCargo, "GetRoadVehicleTypeForCargo", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &AIRoad::IsRoadTile, "IsRoadTile", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &AIRoad::IsRoadDepotTile, "IsRoadDepotTile", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &AIRoad::IsRoadStationTile, "IsRoadStationTile", 2, ".i"); diff --git a/src/gamelog.cpp b/src/gamelog.cpp index 5fefb4a60d..e47a19f0a2 100644 --- a/src/gamelog.cpp +++ b/src/gamelog.cpp @@ -135,6 +135,7 @@ static const char *la_text[] = { "cheat was used", "settings changed", "GRF bug triggered", + "emergency savegame", }; assert_compile(lengthof(la_text) == GLAT_END); @@ -249,6 +250,9 @@ void GamelogPrint(GamelogPrintProc *proc) PrintGrfFilename(buf, lc->grfbug.grfid); break; } + + case GLCT_EMERGENCY: + break; } proc(buf); @@ -317,6 +321,31 @@ static LoggedChange *GamelogChange(GamelogChangeType ct) } +/** Logs a emergency savegame + */ +void GamelogEmergency() +{ + assert(_gamelog_action_type == GLAT_EMERGENCY); + GamelogChange(GLCT_EMERGENCY); +} + +/** Finds out if current game is a loaded emergency savegame. + */ +bool GamelogTestEmergency() +{ + const LoggedChange *emergency = NULL; + + const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; + for (const LoggedAction *la = _gamelog_action; la != laend; la++) { + const LoggedChange *lcend = &la->change[la->changes]; + for (const LoggedChange *lc = la->change; lc != lcend; lc++) { + if (lc->ct == GLCT_EMERGENCY) emergency = lc; + } + } + + return (emergency != NULL); +} + /** Logs a change in game revision * @param revision new revision string */ diff --git a/src/gamelog.h b/src/gamelog.h index 75a5f7f648..419ec9d920 100644 --- a/src/gamelog.h +++ b/src/gamelog.h @@ -14,6 +14,7 @@ enum GamelogActionType { GLAT_CHEAT, ///< Cheat was used GLAT_SETTING, ///< Setting changed GLAT_GRFBUG, ///< GRF bug was triggered + GLAT_EMERGENCY, ///< Emergency savegame GLAT_END, ///< So we know how many GLATs are there GLAT_NONE = 0xFF, ///< No logging active; in savegames, end of list }; @@ -29,6 +30,9 @@ void GamelogPrint(GamelogPrintProc *proc); // needed for WIN32 / WINCE crash.log void GamelogPrintDebug(int level); void GamelogPrintConsole(); +void GamelogEmergency(); +bool GamelogTestEmergency(); + void GamelogRevision(); void GamelogMode(); void GamelogOldver(); diff --git a/src/gamelog_internal.h b/src/gamelog_internal.h index fb5fb4e681..1300429e45 100644 --- a/src/gamelog_internal.h +++ b/src/gamelog_internal.h @@ -19,6 +19,7 @@ enum GamelogChangeType { GLCT_GRFPARAM, ///< GRF parameter changed GLCT_GRFMOVE, ///< GRF order changed GLCT_GRFBUG, ///< GRF bug triggered + GLCT_EMERGENCY, ///< Emergency savegame GLCT_END, ///< So we know how many GLCTs are there GLCT_NONE = 0xFF, ///< In savegames, end of list }; diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 85fa2b3a7f..16695c46b6 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -1418,6 +1418,7 @@ static void NetworkAutoCleanCompanies() const NetworkClientInfo *ci; const Company *c; bool clients_in_company[MAX_COMPANIES]; + int vehicles_in_company[MAX_COMPANIES]; if (!_settings_client.network.autoclean_companies) return; @@ -1433,6 +1434,16 @@ static void NetworkAutoCleanCompanies() if (IsValidCompanyID(ci->client_playas)) clients_in_company[ci->client_playas] = true; } + if (_settings_client.network.autoclean_novehicles != 0) { + memset(vehicles_in_company, 0, sizeof(vehicles_in_company)); + + const Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (!IsValidCompanyID(v->owner) || !v->IsPrimaryVehicle()) continue; + vehicles_in_company[v->owner]++; + } + } + /* Go through all the comapnies */ FOR_ALL_COMPANIES(c) { /* Skip the non-active once */ @@ -1446,7 +1457,7 @@ static void NetworkAutoCleanCompanies() if (_settings_client.network.autoclean_unprotected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_unprotected && StrEmpty(_network_company_states[c->index].password)) { /* Shut the company down */ DoCommandP(0, 2, c->index, CMD_COMPANY_CTRL); - IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d", c->index + 1); + IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no password", c->index + 1); } /* Is the company empty for autoclean_protected-months, and there is a protection? */ if (_settings_client.network.autoclean_protected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_protected && !StrEmpty(_network_company_states[c->index].password)) { @@ -1456,6 +1467,12 @@ static void NetworkAutoCleanCompanies() _network_company_states[c->index].months_empty = 0; NetworkServerUpdateCompanyPassworded(c->index, false); } + /* Is the company empty for autoclean_novehicles-months, and has no vehicles? */ + if (_settings_client.network.autoclean_novehicles != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_novehicles && vehicles_in_company[c->index] == 0) { + /* Shut the company down */ + DoCommandP(0, 2, c->index, CMD_COMPANY_CTRL); + IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no vehicles", c->index + 1); + } } else { /* It is not empty, reset the date */ _network_company_states[c->index].months_empty = 0; diff --git a/src/saveload/gamelog_sl.cpp b/src/saveload/gamelog_sl.cpp index 67f05d55e9..e913e2dd1f 100644 --- a/src/saveload/gamelog_sl.cpp +++ b/src/saveload/gamelog_sl.cpp @@ -76,6 +76,10 @@ static const SaveLoad _glog_grfbug_desc[] = { SLE_END() }; +static const SaveLoad _glog_emergency_desc[] = { + SLE_END() +}; + static const SaveLoad *_glog_desc[] = { _glog_mode_desc, _glog_revision_desc, @@ -87,6 +91,7 @@ static const SaveLoad *_glog_desc[] = { _glog_grfparam_desc, _glog_grfmove_desc, _glog_grfbug_desc, + _glog_emergency_desc, }; assert_compile(lengthof(_glog_desc) == GLCT_END); diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 04b6499e70..e8030896e8 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -40,7 +40,7 @@ #include "saveload_internal.h" -extern const uint16 SAVEGAME_VERSION = 115; +extern const uint16 SAVEGAME_VERSION = 116; SavegameType _savegame_type; ///< type of savegame we are loading diff --git a/src/settings.cpp b/src/settings.cpp index 6de90a5f4d..4f3eda5473 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1567,6 +1567,7 @@ const SettingDesc _settings[] = { SDTC_BOOL(network.autoclean_companies, S, NO, false, STR_NULL, NULL), SDTC_VAR(network.autoclean_unprotected, SLE_UINT8, S,D0|NO, 12, 0, 240, 0, STR_NULL, NULL), SDTC_VAR(network.autoclean_protected, SLE_UINT8, S,D0|NO, 36, 0, 240, 0, STR_NULL, NULL), + SDTC_VAR(network.autoclean_novehicles, SLE_UINT8, S,D0|NO, 0, 0, 240, 0, STR_NULL, NULL), SDTC_VAR(network.max_companies, SLE_UINT8, S, NO, 8, 1,MAX_COMPANIES,0, STR_NULL, UpdateClientConfigValues), SDTC_VAR(network.max_clients, SLE_UINT8, S, NO, 16, 2, MAX_CLIENTS, 0, STR_NULL, NULL), SDTC_VAR(network.max_spectators, SLE_UINT8, S, NO, 8, 0, MAX_CLIENTS, 0, STR_NULL, UpdateClientConfigValues), diff --git a/src/settings_type.h b/src/settings_type.h index e96a25802e..e3f52600db 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -126,6 +126,7 @@ struct NetworkSettings { bool autoclean_companies; ///< automatically remove companies that are not in use uint8 autoclean_unprotected; ///< remove passwordless companies after this many months uint8 autoclean_protected; ///< remove the password from passworded companies after this many months + uint8 autoclean_novehicles; ///< remove companies with no vehicles after this many months uint8 max_companies; ///< maximum amount of companies uint8 max_clients; ///< maximum amount of clients uint8 max_spectators; ///< maximum amount of spectators diff --git a/src/win32.cpp b/src/win32.cpp index 2b08579017..066ea628bc 100644 --- a/src/win32.cpp +++ b/src/win32.cpp @@ -234,8 +234,15 @@ static const TCHAR _save_succeeded[] = _T("Be aware that critical parts of the internal game state may have become ") _T("corrupted. The saved game is not guaranteed to work."); +static const TCHAR _emergency_crash[] = + _T("A serious fault condition occured in the game. The game will shut down.\n") + _T("As you loaded an emergency savegame no crash information will be generated.\n"); + static bool EmergencySave() { + GamelogStartAction(GLAT_EMERGENCY); + GamelogEmergency(); + GamelogStopAction(); SaveOrLoad("crash.sav", SL_SAVE, BASE_DIR); return true; } @@ -471,6 +478,10 @@ static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep) static bool had_exception = false; if (had_exception) ExitProcess(0); + if (GamelogTestEmergency()) { + MessageBox(NULL, _emergency_crash, _T("Fatal Application Failure"), MB_ICONERROR); + ExitProcess(0); + } had_exception = true; _ident = GetTickCount(); // something pretty unique