diff --git a/changelog.txt b/changelog.txt index 4b12d92ec6..ea65030c0d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -14,7 +14,7 @@ - Fix: Pay for the rail/road when constructing tunnels, bridges, depots and stations [FS#3859, FS#3827] (r19925, r19887, r19881) - Fix: Closing chatbox could cause glitches when news message was shown [FS#3865] (r19921) - Fix: [YAPP] Inform the pathfinder as well about the fact that the backside of an one-way path signal can be a safe waiting point [FS#3803] (r19896) -- Fix: Allow loading savegames from the console without specifying the ".sav" extension, i.e. make it consistent with saving savegames from the console [FS#3761] (r19885) +- Fix: Allow loading savegames from the console without specifying the '.sav' extension, i.e. make it consistent with saving savegames from the console [FS#3761] (r19885) - Fix: Dropdowns did affect positioning of new windows because they were not yet removed when the new windows were positioned [FS#3812] (r19883) - Fix: [NoAI] AIEngine::IsValidEngine() and AIEngine::IsBuildable() returned false positives. Especially wagons of unavailable railtypes were reported available (r19880) - Fix: Default vehicle group texts were drawn one pixel too low [FS#3851] (r19878) @@ -140,7 +140,7 @@ - Fix: [NoAI] The AI Debug window did not open if an AI or library fails to compile when loading a savegame [FS#3669] (r19395) - Fix: One could not level the whole map anymore at once (r19392) - Fix: Only show the 'No AIs available' error message when explicitly changing the number of AI opponents [FS3676] (r19389) -- Fix: [NoAI] When reloading a savegame, an AI failing to compile could trigger (trying) to read the not yet loaded information of another AI via the AI Debug window and its "open with the most recently used AI" feature [FS#3666] (r19388) +- Fix: [NoAI] When reloading a savegame, an AI failing to compile could trigger (trying) to read the not yet loaded information of another AI via the AI Debug window and its 'open with the most recently used AI' feature [FS#3666] (r19388) - Fix: Close all orders windows when switching companies [FS#3671] (r19387) - Fix: [IPv6] Netmask calculations were wrong if cidr >= 32 [FS#3684] (r19385) - Fix: Overbuilding bridges, rail stations did not properly update PBS reservation [FS#3680] (r19384, r19383) @@ -209,7 +209,7 @@ - Fix: Crash when a baseset has an empty metadata field (r19095) - Fix: Possible read/write after free when the client triggered the server to close the connection [FS#3599] (r19072) - Fix: Remove Bidi control characters from the reordered text so they are not drawn [FS#3604] (r19067) -- Fix: [NewGRF] Settings that are part of the "TTPatch flags" can cause desyncs if they are changed in network games (r19066) +- Fix: [NewGRF] Settings that are part of the 'TTPatch flags' can cause desyncs if they are changed in network games (r19066) - Fix: When banning yourself via rcon do not send the 'command response' to the client as the connection has already been terminated [FS#3598] (r19054) - Fix: Mass stopping/starting/autoreplacing gave empty errors when there were no vehicles [FS#3577] (r19024) - Fix: City airport introduction date had become 5 years later (r19023) diff --git a/src/ai/api/ai_changelog.hpp b/src/ai/api/ai_changelog.hpp index db675e1a53..33ce11ce16 100644 --- a/src/ai/api/ai_changelog.hpp +++ b/src/ai/api/ai_changelog.hpp @@ -14,6 +14,11 @@ * functions may still be available if you return an older API version * in GetAPIVersion() in info.nut. * + * \b 1.0.3 + * + * API additions: + * \li AIRail::ERR_RAILTYPE_DISALLOWS_CROSSING + * * \b 1.0.2 * * Other changes: diff --git a/src/ai/api/ai_rail.hpp b/src/ai/api/ai_rail.hpp index 5a8a3d111a..d86cb517c4 100644 --- a/src/ai/api/ai_rail.hpp +++ b/src/ai/api/ai_rail.hpp @@ -38,6 +38,9 @@ public: /** Non-uniform stations is diabled */ ERR_NONUNIFORM_STATIONS_DISABLED, // [STR_ERROR_NONUNIFORM_STATIONS_DISALLOWED] + + /** This railtype cannot have crossings */ + ERR_RAILTYPE_DISALLOWS_CROSSING, // [STR_ERROR_CROSSING_DISALLOWED] }; /** diff --git a/src/ai/api/ai_rail.hpp.sq b/src/ai/api/ai_rail.hpp.sq index d39571ad20..8135e36923 100644 --- a/src/ai/api/ai_rail.hpp.sq +++ b/src/ai/api/ai_rail.hpp.sq @@ -42,6 +42,7 @@ void SQAIRail_Register(Squirrel *engine) SQAIRail.DefSQConst(engine, AIRail::ERR_CROSSING_ON_ONEWAY_ROAD, "ERR_CROSSING_ON_ONEWAY_ROAD"); SQAIRail.DefSQConst(engine, AIRail::ERR_UNSUITABLE_TRACK, "ERR_UNSUITABLE_TRACK"); SQAIRail.DefSQConst(engine, AIRail::ERR_NONUNIFORM_STATIONS_DISABLED, "ERR_NONUNIFORM_STATIONS_DISABLED"); + SQAIRail.DefSQConst(engine, AIRail::ERR_RAILTYPE_DISALLOWS_CROSSING, "ERR_RAILTYPE_DISALLOWS_CROSSING"); SQAIRail.DefSQConst(engine, AIRail::RAILTYPE_INVALID, "RAILTYPE_INVALID"); SQAIRail.DefSQConst(engine, AIRail::RAILTRACK_NE_SW, "RAILTRACK_NE_SW"); SQAIRail.DefSQConst(engine, AIRail::RAILTRACK_NW_SE, "RAILTRACK_NW_SE"); @@ -71,10 +72,12 @@ void SQAIRail_Register(Squirrel *engine) AIError::RegisterErrorMap(STR_ERROR_CROSSING_ON_ONEWAY_ROAD, AIRail::ERR_CROSSING_ON_ONEWAY_ROAD); AIError::RegisterErrorMap(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK, AIRail::ERR_UNSUITABLE_TRACK); AIError::RegisterErrorMap(STR_ERROR_NONUNIFORM_STATIONS_DISALLOWED, AIRail::ERR_NONUNIFORM_STATIONS_DISABLED); + AIError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED, AIRail::ERR_RAILTYPE_DISALLOWS_CROSSING); AIError::RegisterErrorMapString(AIRail::ERR_CROSSING_ON_ONEWAY_ROAD, "ERR_CROSSING_ON_ONEWAY_ROAD"); AIError::RegisterErrorMapString(AIRail::ERR_UNSUITABLE_TRACK, "ERR_UNSUITABLE_TRACK"); AIError::RegisterErrorMapString(AIRail::ERR_NONUNIFORM_STATIONS_DISABLED, "ERR_NONUNIFORM_STATIONS_DISABLED"); + AIError::RegisterErrorMapString(AIRail::ERR_RAILTYPE_DISALLOWS_CROSSING, "ERR_RAILTYPE_DISALLOWS_CROSSING"); SQAIRail.DefSQStaticMethod(engine, &AIRail::IsRailTile, "IsRailTile", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &AIRail::IsLevelCrossingTile, "IsLevelCrossingTile", 2, ".i"); diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 9a8bcc7b2e..c165ae5387 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -374,15 +374,13 @@ public: uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_FUND_MORE_TEXT, 0, 0, NULL, this->selected_type, INVALID_TILE); if (callback_res != CALLBACK_FAILED) { // Did it fail? str = GetGRFStringID(indsp->grf_prop.grffile->grfid, 0xD000 + callback_res); // No. here's the new string + if (str != STR_UNDEFINED) { + PrepareTextRefStackUsage(6); + DrawStringMultiLine(left, right, y, bottom, str); + StopTextRefStackUsage(); + } } } - - /* Draw the Additional purchase text, provided by newgrf callback, if any. - * Otherwhise, will print Nothing */ - if (str != STR_NULL && str != STR_UNDEFINED) { - SetDParam(0, str); - DrawStringMultiLine(left, right, y, bottom, STR_JUST_STRING); - } } break; } } diff --git a/src/lang/english.txt b/src/lang/english.txt index 47b3818084..179cdf7399 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3498,6 +3498,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Must rem STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}No suitable railway track STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Must remove railway track first STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Road is one way or blocked +STR_ERROR_CROSSING_DISALLOWED :{WHITE}Level crossings not allowed for this rail type STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Can't build signals here... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Can't build railway track here... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Can't remove railway track from here... diff --git a/src/network/core/tcp_content.cpp b/src/network/core/tcp_content.cpp index 3c999c4dc2..93ef9043c5 100644 --- a/src/network/core/tcp_content.cpp +++ b/src/network/core/tcp_content.cpp @@ -27,6 +27,21 @@ ContentInfo::~ContentInfo() free(this->tags); } +/** + * Copy data from other #ContentInfo and take ownership of allocated stuff. + * @param other Source to copy from. #dependencies and #tags will be NULLed. + */ +void ContentInfo::TransferFrom(ContentInfo *other) +{ + if (other != this) { + free(this->dependencies); + free(this->tags); + memcpy(this, other, sizeof(ContentInfo)); + other->dependencies = NULL; + other->tags = NULL; + } +} + size_t ContentInfo::Size() const { size_t len = 0; diff --git a/src/network/core/tcp_content.h b/src/network/core/tcp_content.h index 3b82696df7..24b87f16f8 100644 --- a/src/network/core/tcp_content.h +++ b/src/network/core/tcp_content.h @@ -88,6 +88,8 @@ struct ContentInfo { /** Free everything allocated */ ~ContentInfo(); + void TransferFrom(ContentInfo *other); + /** * Get the size of the data as send over the network. * @return the size. diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp index 6360597de9..81359ab561 100644 --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -132,10 +132,16 @@ DEF_CONTENT_RECEIVE_COMMAND(Client, PACKET_CONTENT_SERVER_INFO) if (StrEmpty(ci->name)) strecpy(ci->name, ici->name, lastof(ci->name)); if (ici->IsSelected()) ci->state = ici->state; - delete ici; - *iter = ci; + /* + * As ici might be selected by the content window we cannot delete that. + * However, we want to keep most of the values of ci, except the values + * we (just) already preserved. + * So transfer data and ownership of allocated memory from ci to ici. + */ + ici->TransferFrom(ci); + delete ci; - this->OnReceiveContentInfo(ci); + this->OnReceiveContentInfo(ici); return true; } } diff --git a/src/rail.h b/src/rail.h index cf7b482f65..2744b40464 100644 --- a/src/rail.h +++ b/src/rail.h @@ -20,13 +20,13 @@ #include "slope_type.h" #include "strings_type.h" -enum RailTypeFlag { - RTF_CATENARY = 0, ///< Set if the rail type should have catenary drawn -}; - enum RailTypeFlags { - RTFB_NONE = 0, - RTFB_CATENARY = 1 << RTF_CATENARY, + RTF_CATENARY = 0, ///< Bit number for drawing a catenary. + RTF_NO_LEVEL_CROSSING = 1, ///< Bit number for disallowing level crossings. + + RTFB_NONE = 0, ///< All flags cleared. + RTFB_CATENARY = 1 << RTF_CATENARY, ///< Value for drawing a catenary. + RTFB_NO_LEVEL_CROSSING = 1 << RTF_NO_LEVEL_CROSSING, ///< Value for disallowing level crossings. }; DECLARE_ENUM_AS_BIT_SET(RailTypeFlags); @@ -258,6 +258,16 @@ static inline bool HasPowerOnRail(RailType enginetype, RailType tiletype) return HasBit(GetRailTypeInfo(enginetype)->powered_railtypes, tiletype); } +/** + * Test if a RailType disallows build of level crossings. + * @param rt The RailType to check. + * @return Whether level crossings are not allowed. + */ +static inline bool RailNoLevelCrossings(RailType rt) +{ + return HasBit(GetRailTypeInfo(rt)->flags, RTF_NO_LEVEL_CROSSING); +} + /** * Returns the cost of building the specified railtype. * @param railtype The railtype being built. diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index e7af8aec01..7ed1d19ab0 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -431,6 +431,8 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERROR_CROSSING_ON_ONEWAY_ROAD); + if (RailNoLevelCrossings(railtype)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED); + RoadTypes roadtypes = GetRoadTypes(tile); RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD); RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM); diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index cf414153b2..c22b68db06 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -532,6 +532,10 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (GetRailTileType(tile) != RAIL_TILE_NORMAL) goto do_clear; + if (RailNoLevelCrossings(GetRailType(tile))) { + return_cmd_error(STR_ERROR_CROSSING_DISALLOWED); + } + Axis roaddir; switch (GetTrackBits(tile)) { case TRACK_BIT_X: diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index dd9b9b3001..0b35f8492b 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -1864,6 +1864,10 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo } _sl.excpt_uninit = NULL; + _sl.bufe = _sl.bufp = NULL; + _sl.offs_base = 0; + _sl.action = (mode != 0) ? SLA_SAVE : SLA_LOAD; + try { _sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb); @@ -1875,10 +1879,6 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE); } - _sl.bufe = _sl.bufp = NULL; - _sl.offs_base = 0; - _sl.action = (mode != 0) ? SLA_SAVE : SLA_LOAD; - /* General tactic is to first save the game to memory, then use an available writer * to write it to file, either in threaded mode if possible, or single-threaded */ if (mode == SL_SAVE) { // SAVE game