mirror of https://github.com/OpenTTD/OpenTTD
(svn r19646) [1.0] -Backport from trunk:
- Change: Log the _date and _date_fract in the desync log for saved games (r19638) - Fix: Do not allow building cacti outside of the desert or rain forest trees outside of the rain forest area. This to prevent people from thinking planting rain forest trees makes the rain forest bigger and thus adds more place to build a lumber mill [FS#3728] (r19644, r19635, r19634) - Fix: Industry generation failed for large maps and lots of industry types (r19643) - Fix: Desync when taking over companies (r19636) - Fix: Chat message caused glitch when rejoining a network game [FS#3757] (r19629)release/1.0
parent
7c3487501c
commit
4fada121bd
|
@ -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
|
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
|
and GNOME's. With the XFCE's and LXDE's window managers the resize
|
||||||
event is sent when the user releases the mouse.
|
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.
|
||||||
|
|
|
@ -248,7 +248,7 @@
|
||||||
{
|
{
|
||||||
EnforcePrecondition(false, ::IsValidTile(tile));
|
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)
|
/* static */ bool AITile::PlantTreeRectangle(TileIndex tile, uint width, uint height)
|
||||||
|
@ -258,7 +258,7 @@
|
||||||
EnforcePrecondition(false, height >= 1 && height <= 20);
|
EnforcePrecondition(false, height >= 1 && height <= 20);
|
||||||
TileIndex end_tile = tile + ::TileDiffXY(width - 1, height - 1);
|
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)
|
/* static */ bool AITile::IsWithinTownInfluence(TileIndex tile, TownID town_id)
|
||||||
|
|
|
@ -591,14 +591,11 @@ static void HandleBankruptcyTakeover(Company *c)
|
||||||
|
|
||||||
SetBit(c->bankrupt_asked, best->index);
|
SetBit(c->bankrupt_asked, best->index);
|
||||||
|
|
||||||
if (IsInteractiveCompany(best->index)) {
|
c->bankrupt_timeout = TAKE_OVER_TIMEOUT;
|
||||||
c->bankrupt_timeout = TAKE_OVER_TIMEOUT;
|
|
||||||
ShowBuyCompanyDialog(c->index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (best->is_ai) {
|
if (best->is_ai) {
|
||||||
AI::NewEvent(best->index, new AIEventCompanyAskMerger(c->index, ClampToI32(c->bankrupt_value)));
|
AI::NewEvent(best->index, new AIEventCompanyAskMerger(c->index, ClampToI32(c->bankrupt_value)));
|
||||||
|
} else if (IsInteractiveCompany(best->index)) {
|
||||||
|
ShowBuyCompanyDialog(c->index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ uint32 DoRandom(int line, const char *file)
|
||||||
|
|
||||||
uint DoRandomRange(uint max, 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;
|
return GB(DoRandom(line, file), 0, 16) * max >> 16;
|
||||||
}
|
}
|
||||||
#endif /* RANDOM_DEBUG */
|
#endif /* RANDOM_DEBUG */
|
||||||
|
|
|
@ -99,8 +99,9 @@ void SetRandomSeed(uint32 seed);
|
||||||
return _random.Next();
|
return _random.Next();
|
||||||
}
|
}
|
||||||
|
|
||||||
static FORCEINLINE uint32 RandomRange(uint16 max)
|
static FORCEINLINE uint32 RandomRange(uint max)
|
||||||
{
|
{
|
||||||
|
assert(max <= UINT16_MAX);
|
||||||
return _random.Next(max);
|
return _random.Next(max);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1892,7 +1892,8 @@ void GenerateIndustries()
|
||||||
|
|
||||||
/* Add the remaining industries according to their probabilities */
|
/* Add the remaining industries according to their probabilities */
|
||||||
for (uint i = 0; i < total_amount; i++) {
|
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;
|
IndustryType it = 0;
|
||||||
while (it < NUM_INDUSTRYTYPES && r >= industry_probs[it]) {
|
while (it < NUM_INDUSTRYTYPES && r >= industry_probs[it]) {
|
||||||
r -= industry_probs[it];
|
r -= industry_probs[it];
|
||||||
|
|
|
@ -3508,6 +3508,7 @@ STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Can't bu
|
||||||
|
|
||||||
# Tree related errors
|
# Tree related errors
|
||||||
STR_ERROR_TREE_ALREADY_HERE :{WHITE}... tree already here
|
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...
|
STR_ERROR_CAN_T_PLANT_TREE_HERE :{WHITE}Can't plant tree here...
|
||||||
|
|
||||||
# Bridge related errors
|
# Bridge related errors
|
||||||
|
|
|
@ -116,14 +116,15 @@ void CDECL NetworkAddChatMessage(TextColour colour, uint8 duration, const char *
|
||||||
|
|
||||||
void NetworkInitChatMessage()
|
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_list = ReallocT(_chatmsg_list, _settings_client.gui.network_chat_box_height);
|
||||||
_chatmsg_box.x = 10;
|
_chatmsg_box.x = 10;
|
||||||
_chatmsg_box.y = 3 * FONT_HEIGHT_NORMAL;
|
_chatmsg_box.y = 3 * FONT_HEIGHT_NORMAL;
|
||||||
_chatmsg_box.width = _settings_client.gui.network_chat_box_width;
|
_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;
|
_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_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++) {
|
for (uint i = 0; i < MAX_CHAT_MESSAGES; i++) {
|
||||||
_chatmsg_list[i].message[0] = '\0';
|
_chatmsg_list[i].message[0] = '\0';
|
||||||
|
|
|
@ -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
|
/* 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 */
|
* to write it to file, either in threaded mode if possible, or single-threaded */
|
||||||
if (mode == SL_SAVE) { // SAVE game
|
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.write_bytes = WriteMem;
|
||||||
_sl.excpt_uninit = UnInitMem;
|
_sl.excpt_uninit = UnInitMem;
|
||||||
|
|
|
@ -336,7 +336,7 @@ void GenerateTrees()
|
||||||
/** Plant a tree.
|
/** Plant a tree.
|
||||||
* @param tile start tile of area-drag of tree plantation
|
* @param tile start tile of area-drag of tree plantation
|
||||||
* @param flags type of operation
|
* @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 p2 end tile of area-drag
|
||||||
* @param text unused
|
* @param text unused
|
||||||
* @return the cost of this operation or an error
|
* @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;
|
StringID msg = INVALID_STRING_ID;
|
||||||
CommandCost cost(EXPENSES_OTHER);
|
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;
|
if (p2 >= MapSize()) return CMD_ERROR;
|
||||||
/* Check the tree type. It can be random or some valid value within the current climate */
|
/* Check the tree type 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;
|
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);
|
TileArea ta(tile, p2);
|
||||||
TILE_AREA_LOOP(tile, ta) {
|
TILE_AREA_LOOP(tile, ta) {
|
||||||
|
@ -374,12 +375,25 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* FALL THROUGH */
|
/* FALL THROUGH */
|
||||||
case MP_CLEAR:
|
case MP_CLEAR: {
|
||||||
if (IsBridgeAbove(tile)) {
|
if (IsBridgeAbove(tile)) {
|
||||||
msg = STR_ERROR_SITE_UNSUITABLE;
|
msg = STR_ERROR_SITE_UNSUITABLE;
|
||||||
continue;
|
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)) {
|
if (IsTileType(tile, MP_CLEAR)) {
|
||||||
/* Remove fields or rocks. Note that the ground will get barrened */
|
/* Remove fields or rocks. Note that the ground will get barrened */
|
||||||
switch (GetRawClearGround(tile)) {
|
switch (GetRawClearGround(tile)) {
|
||||||
|
@ -401,9 +415,6 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
TreeType treetype;
|
|
||||||
|
|
||||||
treetype = (TreeType)p1;
|
|
||||||
if (treetype == TREE_INVALID) {
|
if (treetype == TREE_INVALID) {
|
||||||
treetype = GetRandomTreeType(tile, GB(Random(), 24, 8));
|
treetype = GetRandomTreeType(tile, GB(Random(), 24, 8));
|
||||||
if (treetype == TREE_INVALID) treetype = TREE_CACTUS;
|
if (treetype == TREE_INVALID) treetype = TREE_CACTUS;
|
||||||
|
@ -414,11 +425,12 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
||||||
MarkTileDirtyByTile(tile);
|
MarkTileDirtyByTile(tile);
|
||||||
|
|
||||||
/* When planting rainforest-trees, set tropiczone to rainforest in editor. */
|
/* 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);
|
SetTropicZone(tile, TROPICZONE_RAINFOREST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cost.AddCost(_price[PR_BUILD_TREES]);
|
cost.AddCost(_price[PR_BUILD_TREES]);
|
||||||
break;
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
msg = STR_ERROR_SITE_UNSUITABLE;
|
msg = STR_ERROR_SITE_UNSUITABLE;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "company_base.h"
|
#include "company_base.h"
|
||||||
#include "command_func.h"
|
#include "command_func.h"
|
||||||
#include "sound_func.h"
|
#include "sound_func.h"
|
||||||
|
#include "tree_map.h"
|
||||||
|
|
||||||
#include "table/sprites.h"
|
#include "table/sprites.h"
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
@ -50,7 +51,7 @@ class BuildTreesWindow : public Window
|
||||||
{
|
{
|
||||||
uint16 base; ///< Base tree number used for drawing the window.
|
uint16 base; ///< Base tree number used for drawing the window.
|
||||||
uint16 count; ///< Number of different trees available.
|
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:
|
public:
|
||||||
BuildTreesWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
|
BuildTreesWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
|
||||||
|
@ -105,13 +106,13 @@ public:
|
||||||
if (widget - BTW_TYPE_11 >= this->count) break;
|
if (widget - BTW_TYPE_11 >= this->count) break;
|
||||||
|
|
||||||
if (HandlePlacePushButton(this, widget, SPR_CURSOR_TREE, HT_RECT, NULL)) {
|
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;
|
break;
|
||||||
|
|
||||||
case BTW_TYPE_RANDOM: // tree of random type.
|
case BTW_TYPE_RANDOM: // tree of random type.
|
||||||
if (HandlePlacePushButton(this, BTW_TYPE_RANDOM, SPR_CURSOR_TREE, HT_RECT, NULL)) {
|
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;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -22,17 +22,15 @@
|
||||||
* offsets from the grfs files. These points to the start of
|
* offsets from the grfs files. These points to the start of
|
||||||
* the tree list for a landscape. See the TREE_COUNT_* enumerations
|
* the tree list for a landscape. See the TREE_COUNT_* enumerations
|
||||||
* for the amount of different trees for a specific landscape.
|
* 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 {
|
enum TreeType {
|
||||||
TREE_INVALID = -1, ///< An invalid tree
|
|
||||||
TREE_TEMPERATE = 0x00, ///< temperate tree
|
TREE_TEMPERATE = 0x00, ///< temperate tree
|
||||||
TREE_SUB_ARCTIC = 0x0C, ///< tree on a sub_arctic landscape
|
TREE_SUB_ARCTIC = 0x0C, ///< tree on a sub_arctic landscape
|
||||||
TREE_RAINFOREST = 0x14, ///< tree on the 'green part' on a sub-tropical map
|
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_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_SUB_TROPICAL = 0x1C, ///< tree on a sub-tropical map, non-rainforest, non-desert
|
||||||
TREE_TOYLAND = 0x20, ///< tree on a toyland map
|
TREE_TOYLAND = 0x20, ///< tree on a toyland map
|
||||||
|
TREE_INVALID = 0xFF, ///< An invalid tree
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue