diff --git a/known-bugs.txt b/known-bugs.txt index 9e2eb76e73..4af6ddda12 100644 --- a/known-bugs.txt +++ b/known-bugs.txt @@ -177,3 +177,11 @@ OpenTTD not properly resizing with SDL on X [FS#3305] Window managers that are known to exhibit this behaviour are KDE's and GNOME's. With the XFCE's and LXDE's window managers the resize event is sent when the user releases the mouse. + +Content files not properly extracted with zlib 1.2.3.5-1.2.4 [FS#3753] + With zlib 1.2.3.5 up to and including 1.2.4 the function "gzeof", + which tells when we read the whole file, is broken in such a way + that OpenTTD thinks it has extracted and written the whole file + while the last few hundred/thousand bytes are not extracted yet. + This causes problems for everything that is downloaded from the + online content system when using one of those versions of zlib. diff --git a/src/ai/api/ai_tile.cpp b/src/ai/api/ai_tile.cpp index 5ae15b83d2..969ba9c0ca 100644 --- a/src/ai/api/ai_tile.cpp +++ b/src/ai/api/ai_tile.cpp @@ -248,7 +248,7 @@ { EnforcePrecondition(false, ::IsValidTile(tile)); - return AIObject::DoCommand(tile, UINT_MAX, tile, CMD_PLANT_TREE); + return AIObject::DoCommand(tile, TREE_INVALID, tile, CMD_PLANT_TREE); } /* static */ bool AITile::PlantTreeRectangle(TileIndex tile, uint width, uint height) @@ -258,7 +258,7 @@ EnforcePrecondition(false, height >= 1 && height <= 20); TileIndex end_tile = tile + ::TileDiffXY(width - 1, height - 1); - return AIObject::DoCommand(tile, UINT_MAX, end_tile, CMD_PLANT_TREE); + return AIObject::DoCommand(tile, TREE_INVALID, end_tile, CMD_PLANT_TREE); } /* static */ bool AITile::IsWithinTownInfluence(TileIndex tile, TownID town_id) diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 1439df596d..7189db70b1 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -591,14 +591,11 @@ static void HandleBankruptcyTakeover(Company *c) SetBit(c->bankrupt_asked, best->index); - if (IsInteractiveCompany(best->index)) { - c->bankrupt_timeout = TAKE_OVER_TIMEOUT; - ShowBuyCompanyDialog(c->index); - return; - } - + c->bankrupt_timeout = TAKE_OVER_TIMEOUT; if (best->is_ai) { AI::NewEvent(best->index, new AIEventCompanyAskMerger(c->index, ClampToI32(c->bankrupt_value))); + } else if (IsInteractiveCompany(best->index)) { + ShowBuyCompanyDialog(c->index); } } diff --git a/src/core/random_func.cpp b/src/core/random_func.cpp index dfdf9c869a..588bcb7b28 100644 --- a/src/core/random_func.cpp +++ b/src/core/random_func.cpp @@ -57,6 +57,7 @@ uint32 DoRandom(int line, const char *file) uint DoRandomRange(uint max, int line, const char *file) { + assert(max <= UINT16_MAX); return GB(DoRandom(line, file), 0, 16) * max >> 16; } #endif /* RANDOM_DEBUG */ diff --git a/src/core/random_func.hpp b/src/core/random_func.hpp index d0e12ba924..03d49d718b 100644 --- a/src/core/random_func.hpp +++ b/src/core/random_func.hpp @@ -99,8 +99,9 @@ void SetRandomSeed(uint32 seed); return _random.Next(); } - static FORCEINLINE uint32 RandomRange(uint16 max) + static FORCEINLINE uint32 RandomRange(uint max) { + assert(max <= UINT16_MAX); return _random.Next(max); } #endif diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index ec62c41a93..13d11c8cbf 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -1892,7 +1892,8 @@ void GenerateIndustries() /* Add the remaining industries according to their probabilities */ for (uint i = 0; i < total_amount; i++) { - uint32 r = RandomRange(total_prob); + /* RandomRange() can only deal with 16 bit, which is not enough here. */ + uint32 r = ((uint64)Random() * (uint64)total_prob) >> 32; IndustryType it = 0; while (it < NUM_INDUSTRYTYPES && r >= industry_probs[it]) { r -= industry_probs[it]; diff --git a/src/lang/english.txt b/src/lang/english.txt index 48d8a40e17..ea562c450f 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3508,6 +3508,7 @@ STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Can't bu # Tree related errors STR_ERROR_TREE_ALREADY_HERE :{WHITE}... tree already here +STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE :{WHITE}... wrong terrain for tree type STR_ERROR_CAN_T_PLANT_TREE_HERE :{WHITE}Can't plant tree here... # Bridge related errors diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index e9f92b7845..10ed4e20c3 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -116,14 +116,15 @@ void CDECL NetworkAddChatMessage(TextColour colour, uint8 duration, const char * void NetworkInitChatMessage() { - MAX_CHAT_MESSAGES = _settings_client.gui.network_chat_box_height; + MAX_CHAT_MESSAGES = _settings_client.gui.network_chat_box_height; - _chatmsg_list = ReallocT(_chatmsg_list, _settings_client.gui.network_chat_box_height); - _chatmsg_box.x = 10; - _chatmsg_box.y = 3 * FONT_HEIGHT_NORMAL; - _chatmsg_box.width = _settings_client.gui.network_chat_box_width; - _chatmsg_box.height = _settings_client.gui.network_chat_box_height * (FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING) + 2; - _chatmessage_backup = ReallocT(_chatmessage_backup, _chatmsg_box.width * _chatmsg_box.height * BlitterFactoryBase::GetCurrentBlitter()->GetBytesPerPixel()); + _chatmsg_list = ReallocT(_chatmsg_list, _settings_client.gui.network_chat_box_height); + _chatmsg_box.x = 10; + _chatmsg_box.y = 3 * FONT_HEIGHT_NORMAL; + _chatmsg_box.width = _settings_client.gui.network_chat_box_width; + _chatmsg_box.height = _settings_client.gui.network_chat_box_height * (FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING) + 2; + _chatmessage_backup = ReallocT(_chatmessage_backup, _chatmsg_box.width * _chatmsg_box.height * BlitterFactoryBase::GetCurrentBlitter()->GetBytesPerPixel()); + _chatmessage_visible = false; for (uint i = 0; i < MAX_CHAT_MESSAGES; i++) { _chatmsg_list[i].message[0] = '\0'; diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 4e0228657b..dd9b9b3001 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -1882,7 +1882,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo /* 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 - DEBUG(desync, 1, "save: %s", filename); + DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename); _sl.write_bytes = WriteMem; _sl.excpt_uninit = UnInitMem; diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index 3c127e0ae3..1a3fe87f5a 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -336,7 +336,7 @@ void GenerateTrees() /** Plant a tree. * @param tile start tile of area-drag of tree plantation * @param flags type of operation - * @param p1 tree type, -1 means random. + * @param p1 tree type, TREE_INVALID means random. * @param p2 end tile of area-drag * @param text unused * @return the cost of this operation or an error @@ -345,10 +345,11 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 { StringID msg = INVALID_STRING_ID; CommandCost cost(EXPENSES_OTHER); + const byte tree_to_plant = GB(p1, 0, 8); // We cannot use Extract as min and max are climate specific. if (p2 >= MapSize()) return CMD_ERROR; - /* Check the tree type. It can be random or some valid value within the current climate */ - if (p1 != UINT_MAX && p1 - _tree_base_by_landscape[_settings_game.game_creation.landscape] >= _tree_count_by_landscape[_settings_game.game_creation.landscape]) return CMD_ERROR; + /* Check the tree type within the current climate */ + if (tree_to_plant != TREE_INVALID && !IsInsideBS(tree_to_plant, _tree_base_by_landscape[_settings_game.game_creation.landscape], _tree_count_by_landscape[_settings_game.game_creation.landscape])) return CMD_ERROR; TileArea ta(tile, p2); TILE_AREA_LOOP(tile, ta) { @@ -374,12 +375,25 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 continue; } /* FALL THROUGH */ - case MP_CLEAR: + case MP_CLEAR: { if (IsBridgeAbove(tile)) { msg = STR_ERROR_SITE_UNSUITABLE; continue; } + TreeType treetype = (TreeType)tree_to_plant; + /* Be a bit picky about which trees go where. */ + if (_settings_game.game_creation.landscape == LT_TROPIC && treetype != TREE_INVALID && ( + /* No cacti outside the desert */ + (treetype == TREE_CACTUS && GetTropicZone(tile) != TROPICZONE_DESERT) || + /* No rain forest trees outside the rain forest, except in the editor mode where it makes those tiles rain forest tile */ + (IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS) && GetTropicZone(tile) != TROPICZONE_RAINFOREST && _game_mode != GM_EDITOR) || + /* And no subtropical trees in the desert/rain forest */ + (IsInsideMM(treetype, TREE_SUB_TROPICAL, TREE_TOYLAND) && GetTropicZone(tile) != TROPICZONE_NORMAL))) { + msg = STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE; + continue; + } + if (IsTileType(tile, MP_CLEAR)) { /* Remove fields or rocks. Note that the ground will get barrened */ switch (GetRawClearGround(tile)) { @@ -401,9 +415,6 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } if (flags & DC_EXEC) { - TreeType treetype; - - treetype = (TreeType)p1; if (treetype == TREE_INVALID) { treetype = GetRandomTreeType(tile, GB(Random(), 24, 8)); if (treetype == TREE_INVALID) treetype = TREE_CACTUS; @@ -414,11 +425,12 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 MarkTileDirtyByTile(tile); /* When planting rainforest-trees, set tropiczone to rainforest in editor. */ - if (_game_mode == GM_EDITOR && IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS)) + if (_game_mode == GM_EDITOR && IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS)) { SetTropicZone(tile, TROPICZONE_RAINFOREST); + } } cost.AddCost(_price[PR_BUILD_TREES]); - break; + } break; default: msg = STR_ERROR_SITE_UNSUITABLE; diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index 7d8a04c6db..0c69e5008d 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -18,6 +18,7 @@ #include "company_base.h" #include "command_func.h" #include "sound_func.h" +#include "tree_map.h" #include "table/sprites.h" #include "table/strings.h" @@ -50,7 +51,7 @@ class BuildTreesWindow : public Window { uint16 base; ///< Base tree number used for drawing the window. uint16 count; ///< Number of different trees available. - uint tree_to_plant; ///< Tree number to plant, \c UINT_MAX for a random tree. + TreeType tree_to_plant; ///< Tree number to plant, \c TREE_INVALID for a random tree. public: BuildTreesWindow(const WindowDesc *desc, WindowNumber window_number) : Window() @@ -105,13 +106,13 @@ public: if (widget - BTW_TYPE_11 >= this->count) break; if (HandlePlacePushButton(this, widget, SPR_CURSOR_TREE, HT_RECT, NULL)) { - this->tree_to_plant = this->base + widget - BTW_TYPE_11; + this->tree_to_plant = (TreeType)(this->base + widget - BTW_TYPE_11); } break; case BTW_TYPE_RANDOM: // tree of random type. if (HandlePlacePushButton(this, BTW_TYPE_RANDOM, SPR_CURSOR_TREE, HT_RECT, NULL)) { - this->tree_to_plant = UINT_MAX; + this->tree_to_plant = TREE_INVALID; } break; diff --git a/src/tree_map.h b/src/tree_map.h index 05315ca253..840517218f 100644 --- a/src/tree_map.h +++ b/src/tree_map.h @@ -22,17 +22,15 @@ * offsets from the grfs files. These points to the start of * the tree list for a landscape. See the TREE_COUNT_* enumerations * for the amount of different trees for a specific landscape. - * - * @note TREE_INVALID may be 0xFF according to the coding style, not -1 (Progman) */ enum TreeType { - TREE_INVALID = -1, ///< An invalid tree TREE_TEMPERATE = 0x00, ///< temperate tree TREE_SUB_ARCTIC = 0x0C, ///< tree on a sub_arctic landscape TREE_RAINFOREST = 0x14, ///< tree on the 'green part' on a sub-tropical map TREE_CACTUS = 0x1B, ///< a catus for the 'desert part' on a sub-tropical map TREE_SUB_TROPICAL = 0x1C, ///< tree on a sub-tropical map, non-rainforest, non-desert TREE_TOYLAND = 0x20, ///< tree on a toyland map + TREE_INVALID = 0xFF, ///< An invalid tree }; /**