Changeset - r10855:5a3c2f38f98e
[Not reviewed]
src/ai/api/ai_tile.cpp
Show inline comments
 
@@ -187,28 +187,28 @@
 
{
 
	return AIMap::DistanceSquare(tile_from, tile_to);
 
}
 

	
 
/* static */ bool AITile::RaiseTile(TileIndex tile, int32 slope)
 
{
 
	EnforcePrecondition(false, ::IsValidTile(tile));
 
	EnforcePrecondition(false, tile < ::MapSize());
 

	
 
	return AIObject::DoCommand(tile, slope, 1, CMD_TERRAFORM_LAND);
 
}
 

	
 
/* static */ bool AITile::LowerTile(TileIndex tile, int32 slope)
 
{
 
	EnforcePrecondition(false, ::IsValidTile(tile));
 
	EnforcePrecondition(false, tile < ::MapSize());
 

	
 
	return AIObject::DoCommand(tile, slope, 0, CMD_TERRAFORM_LAND);
 
}
 

	
 
/* static */ bool AITile::LevelTiles(TileIndex start_tile, TileIndex end_tile)
 
{
 
	EnforcePrecondition(false, ::IsValidTile(start_tile));
 
	EnforcePrecondition(false, ::IsValidTile(end_tile));
 
	EnforcePrecondition(false, start_tile < ::MapSize());
 
	EnforcePrecondition(false, end_tile < ::MapSize());
 

	
 
	return AIObject::DoCommand(end_tile, start_tile, 0, CMD_LEVEL_LAND);
 
}
 

	
 
/* static */ bool AITile::DemolishTile(TileIndex tile)
 
{
src/ai/api/ai_tile.hpp
Show inline comments
 
@@ -288,26 +288,26 @@ public:
 

	
 
	/**
 
	 * Raise the given corners of the tile. The corners can be combined,
 
	 *  for example: SLOPE_N | SLOPE_W (= SLOPE_NW)
 
	 * @param tile The tile to raise.
 
	 * @param slope Corners to raise (SLOPE_xxx).
 
	 * @pre AIMap::IsValidTile(tile).
 
	 * @pre tile < AIMap::GetMapSize().
 
	 * @exception AIError::ERR_AREA_NOT_CLEAR
 
	 * @exception AIError::ERR_TOO_CLOSE_TO_EDGE
 
	 * @exception AITile::ERR_TILE_TOO_HIGH
 
	 * @return 0 means failed, 1 means success.
 
	 */
 
	static bool RaiseTile(TileIndex tile, int32 slope);
 

	
 
	/**
 
	 * Lower the given corners of the tile. The corners can be combined,
 
	 *  for example: SLOPE_N | SLOPE_W (= SLOPE_NW)
 
	 * @param tile The tile to lower.
 
	 * @param slope Corners to lower (SLOPE_xxx).
 
	 * @pre AIMap::IsValidTile(tile).
 
	 * @pre tile < AIMap::GetMapSize().
 
	 * @exception AIError::ERR_AREA_NOT_CLEAR
 
	 * @exception AIError::ERR_TOO_CLOSE_TO_EDGE
 
	 * @exception AITile::ERR_TILE_TOO_LOW
 
	 * @return 0 means failed, 1 means success.
 
	 */
 
	static bool LowerTile(TileIndex tile, int32 slope);
src/clear_cmd.cpp
Show inline comments
 
@@ -15,12 +15,13 @@
 
#include "water_map.h"
 
#include "tile_cmd.h"
 
#include "functions.h"
 
#include "economy_func.h"
 
#include "viewport_func.h"
 
#include "settings_type.h"
 
#include "water.h"
 

	
 
#include "table/strings.h"
 
#include "table/sprites.h"
 
#include "table/clear_land.h"
 

	
 
static CommandCost ClearTile_Clear(TileIndex tile, byte flags)
 
@@ -213,12 +214,22 @@ static void TileLoopClearDesert(TileInde
 

	
 
	MarkTileDirtyByTile(tile);
 
}
 

	
 
static void TileLoop_Clear(TileIndex tile)
 
{
 
	/* If the tile is at any edge flood it to prevent maps without water. */
 
	if (_settings_game.construction.freeform_edges && DistanceFromEdge(tile) == 1) {
 
		uint z;
 
		Slope slope = GetTileSlope(tile, &z);
 
		if (z == 0 && slope == SLOPE_FLAT) {
 
			DoFloodTile(tile);
 
			MarkTileDirtyByTile(tile);
 
			return;
 
		}
 
	}
 
	TileLoopClearHelper(tile);
 

	
 
	switch (_settings_game.game_creation.landscape) {
 
		case LT_TROPIC: TileLoopClearDesert(tile); break;
 
		case LT_ARCTIC: TileLoopClearAlps(tile);   break;
 
	}
src/command.cpp
Show inline comments
 
@@ -211,13 +211,13 @@ static const Command _command_proc_table
 
	{CmdLandscapeClear,                             0}, /* CMD_LANDSCAPE_CLEAR */
 
	{CmdBuildBridge,                         CMD_AUTO}, /* CMD_BUILD_BRIDGE */
 
	{CmdBuildRailroadStation, CMD_NO_WATER | CMD_AUTO}, /* CMD_BUILD_RAILROAD_STATION */
 
	{CmdBuildTrainDepot,      CMD_NO_WATER | CMD_AUTO}, /* CMD_BUILD_TRAIN_DEPOT */
 
	{CmdBuildSingleSignal,                   CMD_AUTO}, /* CMD_BUILD_SIGNALS */
 
	{CmdRemoveSingleSignal,                  CMD_AUTO}, /* CMD_REMOVE_SIGNALS */
 
	{CmdTerraformLand,                       CMD_AUTO}, /* CMD_TERRAFORM_LAND */
 
	{CmdTerraformLand,       CMD_ALL_TILES | CMD_AUTO}, /* CMD_TERRAFORM_LAND */
 
	{CmdPurchaseLandArea,     CMD_NO_WATER | CMD_AUTO}, /* CMD_PURCHASE_LAND_AREA */
 
	{CmdSellLandArea,                               0}, /* CMD_SELL_LAND_AREA */
 
	{CmdBuildTunnel,                         CMD_AUTO}, /* CMD_BUILD_TUNNEL */
 
	{CmdRemoveFromRailroadStation,                  0}, /* CMD_REMOVE_FROM_RAILROAD_STATION */
 
	{CmdConvertRail,                                0}, /* CMD_CONVERT_RAILD */
 
	{CmdBuildTrainWaypoint,                         0}, /* CMD_BUILD_TRAIN_WAYPOINT */
 
@@ -308,13 +308,13 @@ static const Command _command_proc_table
 
	{CmdClearArea,                        CMD_NO_TEST}, /* CMD_CLEAR_AREA; destroying multi-tile houses makes town rating differ between test and execution */
 

	
 
	{CmdMoneyCheat,                       CMD_OFFLINE}, /* CMD_MONEY_CHEAT */
 
	{CmdBuildCanal,                          CMD_AUTO}, /* CMD_BUILD_CANAL */
 
	{CmdCompanyCtrl,                                0}, /* CMD_COMPANY_CTRL */
 

	
 
	{CmdLevelLand,             CMD_NO_TEST | CMD_AUTO}, /* CMD_LEVEL_LAND; test run might clear tiles multiple times, in execution that only happens once */
 
	{CmdLevelLand, CMD_ALL_TILES | CMD_NO_TEST | CMD_AUTO}, /* CMD_LEVEL_LAND; test run might clear tiles multiple times, in execution that only happens once */
 

	
 
	{CmdRefitRailVehicle,                           0}, /* CMD_REFIT_RAIL_VEHICLE */
 
	{CmdRestoreOrderIndex,                          0}, /* CMD_RESTORE_ORDER_INDEX */
 
	{CmdBuildLock,                           CMD_AUTO}, /* CMD_BUILD_LOCK */
 

	
 
	{CmdBuildSignalTrack,                    CMD_AUTO}, /* CMD_BUILD_SIGNAL_TRACK */
 
@@ -400,13 +400,13 @@ CommandCost DoCommand(const CommandConta
 
 */
 
CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint32 cmd, const char *text)
 
{
 
	CommandCost res;
 

	
 
	/* Do not even think about executing out-of-bounds tile-commands */
 
	if (!IsValidTile(tile)) return CMD_ERROR;
 
	if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (flags & DC_ALL_TILES) == 0))) return CMD_ERROR;
 

	
 
	CommandProc *proc = _command_proc_table[cmd].proc;
 

	
 
	if (_docommand_recursive == 0) _error_message = INVALID_STRING_ID;
 

	
 
	_docommand_recursive++;
 
@@ -494,15 +494,12 @@ bool DoCommandP(const CommandContainer *
 
 * @return true if the command succeeded, else false
 
 */
 
bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd)
 
{
 
	assert(_docommand_recursive == 0);
 

	
 
	/* Do not even think about executing out-of-bounds tile-commands */
 
	if (!IsValidTile(tile)) return false;
 

	
 
	CommandCost res, res2;
 

	
 
	int x = TileX(tile) * TILE_SIZE;
 
	int y = TileY(tile) * TILE_SIZE;
 

	
 
	_error_message = INVALID_STRING_ID;
 
@@ -525,12 +522,15 @@ bool DoCommandP(TileIndex tile, uint32 p
 

	
 
	/* Command flags are used internally */
 
	uint cmd_flags = GetCommandFlags(cmd);
 
	/* Flags get send to the DoCommand */
 
	uint32 flags = CommandFlagsToDCFlags(cmd_flags);
 

	
 
	/* Do not even think about executing out-of-bounds tile-commands */
 
	if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (cmd_flags & CMD_ALL_TILES) == 0))) return false;
 

	
 
	bool notest = (cmd_flags & CMD_NO_TEST) != 0;
 

	
 
	_docommand_recursive = 1;
 

	
 
	/* cost estimation only? */
 
	if (!IsGeneratingWorld() &&
src/command_func.h
Show inline comments
 
@@ -93,10 +93,11 @@ Money GetAvailableMoneyForCommand();
 
 */
 
static inline uint32 CommandFlagsToDCFlags(uint cmd_flags)
 
{
 
	uint32 flags = 0;
 
	if (cmd_flags & CMD_NO_WATER) flags |= DC_NO_WATER;
 
	if (cmd_flags & CMD_AUTO) flags |= DC_AUTO;
 
	if (cmd_flags & CMD_ALL_TILES) flags |= DC_ALL_TILES;
 
	return flags;
 
}
 

	
 
#endif /* COMMAND_FUNC_H */
src/command_type.h
Show inline comments
 
@@ -301,12 +301,13 @@ enum {
 
	DC_QUERY_COST      = 0x004, ///< query cost only,  don't build.
 
	DC_NO_WATER        = 0x008, ///< don't allow building on water
 
	DC_NO_RAIL_OVERLAP = 0x010, ///< don't allow overlap of rails (used in buildrail)
 
	DC_NO_TOWN_RATING  = 0x020, ///< town rating does not disallow you from building
 
	DC_BANKRUPT        = 0x040, ///< company bankrupts, skip money check, skip vehicle on tile check in some cases
 
	DC_AUTOREPLACE     = 0x080, ///< autoreplace/autorenew is in progress, this shall disable vehicle limits when building, and ignore certain restrictions when undoing things (like vehicle attach callback)
 
	DC_ALL_TILES       = 0x100, ///< allow this command also on MP_VOID tiles
 
};
 

	
 
/**
 
 * Used to combine a StringID with the command.
 
 *
 
 * This macro can be used to add a StringID (the error message to show) on a command-id
 
@@ -337,12 +338,13 @@ enum {
 
enum {
 
	CMD_SERVER   = 0x01, ///< the command can only be initiated by the server
 
	CMD_OFFLINE  = 0x02, ///< the command cannot be executed in a multiplayer game; single-player only
 
	CMD_AUTO     = 0x04, ///< set the DC_AUTO flag on this command
 
	CMD_NO_TEST  = 0x08, ///< the command's output may differ between test and execute due to town rating changes etc.
 
	CMD_NO_WATER = 0x10, ///< set the DC_NO_WATER flag on this command
 
	CMD_ALL_TILES= 0x20, ///< allow this command also on MP_VOID tiles
 
};
 

	
 
/**
 
 * Defines the callback type for all command handler functions.
 
 *
 
 * This type defines the function header for all functions which handles a CMD_* command.
src/genworld.cpp
Show inline comments
 
@@ -25,12 +25,13 @@
 
#include "settings_type.h"
 
#include "newgrf_storage.h"
 
#include "water.h"
 
#include "blitter/factory.hpp"
 
#include "tilehighlight_func.h"
 
#include "saveload/saveload.h"
 
#include "void_map.h"
 

	
 
#include "table/sprites.h"
 

	
 
void GenerateClearTile();
 
void GenerateIndustries();
 
void GenerateUnmovables();
 
@@ -103,12 +104,18 @@ static void _GenerateWorld(void *arg)
 
		StartupEconomy();
 

	
 
		/* Don't generate landscape items when in the scenario editor. */
 
		if (_gw.mode == GW_EMPTY) {
 
			SetGeneratingWorldProgress(GWP_UNMOVABLE, 1);
 

	
 
			/* Make sure the tiles at the north border are void tiles if needed. */
 
			if (_settings_game.construction.freeform_edges) {
 
				for (uint row = 0; row < MapSizeY(); row++) MakeVoid(TileXY(0, row));
 
				for (uint col = 0; col < MapSizeX(); col++) MakeVoid(TileXY(col, 0));
 
			}
 

	
 
			/* Make the map the height of the patch setting */
 
			if (_game_mode != GM_MENU) FlatEmptyWorld(_settings_game.game_creation.se_flat_world_height);
 

	
 
			ConvertGroundTilesIntoWaterTiles();
 
			IncreaseGeneratingWorldProgress(GWP_UNMOVABLE);
 
		} else {
src/genworld_gui.cpp
Show inline comments
 
@@ -95,19 +95,20 @@ enum GenerateLandscapeWindowWidgets {
 

	
 
	GLAND_TERRAIN_TEXT,
 
	GLAND_TERRAIN_PULLDOWN,
 
	GLAND_WATER_TEXT,
 
	GLAND_WATER_PULLDOWN,
 
	GLAND_SMOOTHNESS_TEXT,
 
	GLAND_SMOOTHNESS_PULLDOWN
 
	GLAND_SMOOTHNESS_PULLDOWN,
 
	GLAND_WATER_BORDERS_PULLDOWN,
 
};
 

	
 
static const Widget _generate_landscape_widgets[] = {
 
{  WWT_CLOSEBOX,  RESIZE_NONE, COLOUR_BROWN,    0,  10,   0,  13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION, RESIZE_NONE, COLOUR_BROWN,   11, 337,   0,  13, STR_WORLD_GENERATION_CAPTION, STR_NULL},
 
{      WWT_PANEL, RESIZE_NONE, COLOUR_BROWN,    0, 337,  14, 267, 0x0,                          STR_NULL},
 
{      WWT_PANEL, RESIZE_NONE, COLOUR_BROWN,    0, 337,  14, 285, 0x0,                          STR_NULL},
 

	
 
/* Landscape selection */
 
{   WWT_IMGBTN_2, RESIZE_NONE, COLOUR_ORANGE,  10,  86,  24,  78, SPR_SELECT_TEMPERATE,         STR_030E_SELECT_TEMPERATE_LANDSCAPE},    // GLAND_TEMPERATE
 
{   WWT_IMGBTN_2, RESIZE_NONE, COLOUR_ORANGE,  90, 166,  24,  78, SPR_SELECT_SUB_ARCTIC,        STR_030F_SELECT_SUB_ARCTIC_LANDSCAPE},   // GLAND_ARCTIC
 
{   WWT_IMGBTN_2, RESIZE_NONE, COLOUR_ORANGE, 170, 246,  24,  78, SPR_SELECT_SUB_TROPICAL,      STR_0310_SELECT_SUB_TROPICAL_LANDSCAPE}, // GLAND_TROPICAL
 
{   WWT_IMGBTN_2, RESIZE_NONE, COLOUR_ORANGE, 250, 326,  24,  78, SPR_SELECT_TOYLAND,           STR_0311_SELECT_TOYLAND_LANDSCAPE},      // GLAND_TOYLAND
 
@@ -163,12 +164,15 @@ static const Widget _generate_landscape_
 
{       WWT_TEXT, RESIZE_NONE, COLOUR_ORANGE,  12, 110, 229, 239, STR_QUANTITY_OF_SEA_LAKES,    STR_NULL},                               // GLAND_WATER_TEXT
 
{   WWT_DROPDOWN, RESIZE_NONE, COLOUR_ORANGE, 114, 231, 228, 239, 0x0,                          STR_NULL},                               // GLAND_WATER_PULLDOWN
 

	
 
/* Map smoothness */
 
{       WWT_TEXT, RESIZE_NONE, COLOUR_ORANGE,  12, 110, 245, 257, STR_SMOOTHNESS,               STR_NULL},                               // GLAND_SMOOTHNESS_TEXT
 
{   WWT_DROPDOWN, RESIZE_NONE, COLOUR_ORANGE, 114, 231, 246, 257, 0x0,                          STR_NULL},                               // GLAND_SMOOTHNESS_PULLDOWN
 

	
 
/* Water borders */
 
{   WWT_DROPDOWN, RESIZE_NONE, COLOUR_ORANGE,  12, 326, 264, 275, 0x0,                          STR_NULL},                               // GLAND_WATER_BORDERS_PULLDOWN
 
{   WIDGETS_END},
 
};
 

	
 
static const Widget _heightmap_load_widgets[] = {
 
{   WWT_CLOSEBOX, RESIZE_NONE, COLOUR_BROWN,    0,  10,   0,  13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION, RESIZE_NONE, COLOUR_BROWN,   11, 337,   0,  13, STR_WORLD_GENERATION_CAPTION, STR_NULL},
 
@@ -266,12 +270,31 @@ static const StringID _sea_lakes[]   = {
 
static const StringID _smoothness[]  = {STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH, STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_SMOOTH, STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_ROUGH, STR_CONFIG_PATCHES_ROUGHNESS_OF_TERRAIN_VERY_ROUGH, INVALID_STRING_ID};
 
static const StringID _tree_placer[] = {STR_CONFIG_PATCHES_TREE_PLACER_NONE, STR_CONFIG_PATCHES_TREE_PLACER_ORIGINAL, STR_CONFIG_PATCHES_TREE_PLACER_IMPROVED, INVALID_STRING_ID};
 
static const StringID _rotation[]    = {STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE, STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION_CLOCKWISE, INVALID_STRING_ID};
 
static const StringID _landscape[]   = {STR_CONFIG_PATCHES_LAND_GENERATOR_ORIGINAL, STR_CONFIG_PATCHES_LAND_GENERATOR_TERRA_GENESIS, INVALID_STRING_ID};
 
static const StringID _num_towns[]   = {STR_NUM_VERY_LOW, STR_6816_LOW, STR_6817_NORMAL, STR_6818_HIGH, INVALID_STRING_ID};
 
static const StringID _num_inds[]    = {STR_NONE, STR_NUM_VERY_LOW, STR_6816_LOW, STR_6817_NORMAL, STR_6818_HIGH, INVALID_STRING_ID};
 
static const StringID _water_borders[] = {
 
	STR_CONFIG_PATCHES_WATER_BORDER_NONE,
 
	STR_CONFIG_PATCHES_WATER_BORDER_NE,
 
	STR_CONFIG_PATCHES_WATER_BORDER_SE,
 
	STR_CONFIG_PATCHES_WATER_BORDER_SE_NE,
 
	STR_CONFIG_PATCHES_WATER_BORDER_SW,
 
	STR_CONFIG_PATCHES_WATER_BORDER_SW_NE,
 
	STR_CONFIG_PATCHES_WATER_BORDER_SW_SE,
 
	STR_CONFIG_PATCHES_WATER_BORDER_SW_SE_NE,
 
	STR_CONFIG_PATCHES_WATER_BORDER_NW,
 
	STR_CONFIG_PATCHES_WATER_BORDER_NW_NE,
 
	STR_CONFIG_PATCHES_WATER_BORDER_NW_SE,
 
	STR_CONFIG_PATCHES_WATER_BORDER_NW_SE_NE,
 
	STR_CONFIG_PATCHES_WATER_BORDER_NW_SW,
 
	STR_CONFIG_PATCHES_WATER_BORDER_NW_SW_NE,
 
	STR_CONFIG_PATCHES_WATER_BORDER_NW_SW_SE,
 
	STR_CONFIG_PATCHES_WATER_BORDER_NW_SW_SE_NE,
 
	INVALID_STRING_ID
 
};
 

	
 
struct GenerateLandscapeWindow : public QueryStringBaseWindow {
 
	uint widget_id;
 
	uint x;
 
	uint y;
 
	char name[64];
 
@@ -291,15 +314,16 @@ struct GenerateLandscapeWindow : public 
 

	
 
		this->FindWindowPlacementAndResize(desc);
 
	}
 

	
 
	virtual void OnPaint()
 
	{
 
		/* You can't select smoothness if not terragenesis */
 
		/* You can't select smoothness / non-water borders if not terragenesis */
 
		if (mode == GLWP_GENERATE) {
 
			this->SetWidgetDisabledState(GLAND_SMOOTHNESS_PULLDOWN, _settings_newgame.game_creation.land_generator == 0);
 
			this->SetWidgetDisabledState(GLAND_WATER_BORDERS_PULLDOWN, _settings_newgame.game_creation.land_generator == 0 || !_settings_newgame.construction.freeform_edges);
 
		}
 
		/* Disable snowline if not hilly */
 
		this->SetWidgetDisabledState(GLAND_SNOW_LEVEL_TEXT, _settings_newgame.game_creation.landscape != LT_ARCTIC);
 
		/* Disable town, industry and trees in SE */
 
		this->SetWidgetDisabledState(GLAND_TOWN_PULLDOWN,     _game_mode == GM_EDITOR);
 
		this->SetWidgetDisabledState(GLAND_INDUSTRY_PULLDOWN, _game_mode == GM_EDITOR);
 
@@ -326,12 +350,13 @@ struct GenerateLandscapeWindow : public 
 
		if (mode == GLWP_GENERATE) {
 
			this->widget[GLAND_LANDSCAPE_PULLDOWN].data  = _landscape[_settings_newgame.game_creation.land_generator];
 
			this->widget[GLAND_TREE_PULLDOWN].data       = _tree_placer[_settings_newgame.game_creation.tree_placer];
 
			this->widget[GLAND_TERRAIN_PULLDOWN].data    = _elevations[_settings_newgame.difficulty.terrain_type];
 
			this->widget[GLAND_WATER_PULLDOWN].data      = _sea_lakes[_settings_newgame.difficulty.quantity_sea_lakes];
 
			this->widget[GLAND_SMOOTHNESS_PULLDOWN].data = _smoothness[_settings_newgame.game_creation.tgen_smoothness];
 
			this->widget[GLAND_WATER_BORDERS_PULLDOWN].data = _settings_newgame.construction.freeform_edges ? _water_borders[_settings_newgame.game_creation.water_borders] : STR_CONFIG_PATCHES_WATER_BORDER_NW_SW_SE_NE;
 
		} else {
 
			this->widget[GLAND_TREE_PULLDOWN].data               = _tree_placer[_settings_newgame.game_creation.tree_placer];
 
			this->widget[GLAND_HEIGHTMAP_ROTATION_PULLDOWN].data = _rotation[_settings_newgame.game_creation.heightmap_rotation];
 
		}
 

	
 
		/* Set parameters for widget text that requires them. */
 
@@ -480,12 +505,16 @@ struct GenerateLandscapeWindow : public 
 
				ShowDropDownMenu(this, _sea_lakes, _settings_newgame.difficulty.quantity_sea_lakes, GLAND_WATER_PULLDOWN, 0, 0);
 
				break;
 

	
 
			case GLAND_SMOOTHNESS_PULLDOWN: // Map smoothness
 
				ShowDropDownMenu(this, _smoothness, _settings_newgame.game_creation.tgen_smoothness, GLAND_SMOOTHNESS_PULLDOWN, 0, 0);
 
				break;
 

	
 
			case GLAND_WATER_BORDERS_PULLDOWN: // Water borders
 
				ShowDropDownMenu(this, _water_borders, _settings_newgame.game_creation.water_borders, GLAND_WATER_BORDERS_PULLDOWN, 0, 0);
 
				break;
 
		}
 
	}
 

	
 
	virtual void OnMouseLoop()
 
	{
 
		this->HandleEditBox(GLAND_RANDOM_EDITBOX);
 
@@ -508,12 +537,13 @@ struct GenerateLandscapeWindow : public 
 
	{
 
		switch (widget) {
 
			case GLAND_MAPSIZE_X_PULLDOWN:  _settings_newgame.game_creation.map_x = index; break;
 
			case GLAND_MAPSIZE_Y_PULLDOWN:  _settings_newgame.game_creation.map_y = index; break;
 
			case GLAND_TREE_PULLDOWN:       _settings_newgame.game_creation.tree_placer = index; break;
 
			case GLAND_SMOOTHNESS_PULLDOWN: _settings_newgame.game_creation.tgen_smoothness = index;  break;
 
			case GLAND_WATER_BORDERS_PULLDOWN: _settings_newgame.game_creation.water_borders = index;  break;
 

	
 
			case GLAND_TOWN_PULLDOWN:
 
				_settings_newgame.difficulty.number_towns = index;
 
				if (_settings_newgame.difficulty.diff_level != 3) ShowErrorMessage(INVALID_STRING_ID, STR_DIFFICULTY_TO_CUSTOM, 0, 0);
 
				IConsoleSetPatchSetting("difficulty.number_towns", _settings_newgame.difficulty.number_towns);
 
				break;
 
@@ -568,13 +598,13 @@ struct GenerateLandscapeWindow : public 
 
			this->SetDirty();
 
		}
 
	}
 
};
 

	
 
static const WindowDesc _generate_landscape_desc = {
 
	WDP_CENTER, WDP_CENTER, 338, 268, 338, 268,
 
	WDP_CENTER, WDP_CENTER, 338, 286, 338, 286,
 
	WC_GENERATE_LANDSCAPE, WC_NONE,
 
	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 
	_generate_landscape_widgets,
 
};
 

	
 
static const WindowDesc _heightmap_load_desc = {
src/heightmap.cpp
Show inline comments
 
@@ -316,23 +316,28 @@ static void GrayscaleToMapHeights(uint i
 
	} else {
 
		/* Image is taller than map - center horizontally */
 
		img_scale = (height * num_div) / img_height;
 
		col_pad = (1 + width - ((img_width * img_scale) / num_div)) / 2;
 
	}
 

	
 
	if (_settings_game.construction.freeform_edges) {
 
		for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
 
		for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
 
	}
 

	
 
	/* Form the landscape */
 
	for (row = 0; row < height - 1; row++) {
 
		for (col = 0; col < width - 1; col++) {
 
	for (row = 0; row < height; row++) {
 
		for (col = 0; col < width; col++) {
 
			switch (_settings_game.game_creation.heightmap_rotation) {
 
				default: NOT_REACHED();
 
				case HM_COUNTER_CLOCKWISE: tile = TileXY(col, row); break;
 
				case HM_CLOCKWISE:         tile = TileXY(row, col); break;
 
			}
 

	
 
			/* Check if current tile is within the 1-pixel map edge or padding regions */
 
			if ((DistanceFromEdge(tile) <= 1) ||
 
			if ((!_settings_game.construction.freeform_edges && DistanceFromEdge(tile) <= 1) ||
 
					(row < row_pad) || (row >= (height - row_pad - 1)) ||
 
					(col < col_pad) || (col >= (width  - col_pad - 1))) {
 
				SetTileHeight(tile, 0);
 
			} else {
 
				/* Use nearest neighbor resizing to scale map data.
 
				 *  We rotate the map 45 degrees (counter)clockwise */
 
@@ -350,56 +355,71 @@ static void GrayscaleToMapHeights(uint i
 
				assert(img_row < img_height);
 
				assert(img_col < img_width);
 

	
 
				/* Color scales from 0 to 255, OpenTTD height scales from 0 to 15 */
 
				SetTileHeight(tile, map[img_row * img_width + img_col] / 16);
 
			}
 
			/* Only clear the tiles within the map area. */
 
			if (TileX(tile) != MapMaxX() && TileY(tile) != MapMaxY() &&
 
					(!_settings_game.construction.freeform_edges || (TileX(tile) != 0 && TileY(tile) != 0))) {
 
			MakeClear(tile, CLEAR_GRASS, 3);
 
		}
 
	}
 
}
 
}
 

	
 
/**
 
 * This function takes care of the fact that land in OpenTTD can never differ
 
 * more than 1 in height
 
 */
 
static void FixSlopes()
 
{
 
	uint width, height;
 
	uint row, col;
 
	int row, col;
 
	byte current_tile;
 

	
 
	/* Adjust height difference to maximum one horizontal/vertical change. */
 
	width   = MapSizeX();
 
	height  = MapSizeY();
 

	
 
	/* Top and left edge */
 
	for (row = 1; row < height - 2; row++) {
 
		for (col = 1; col < width - 2; col++) {
 
	for (row = 0; (uint)row < height; row++) {
 
		for (col = 0; (uint)col < width; col++) {
 
			current_tile = MAX_TILE_HEIGHT;
 
			if (col != 0) {
 
			/* Find lowest tile; either the top or left one */
 
			current_tile = TileHeight(TileXY(col - 1, row)); // top edge
 
			}
 
			if (row != 0) {
 
			if (TileHeight(TileXY(col, row - 1)) < current_tile) {
 
				current_tile = TileHeight(TileXY(col, row - 1)); // left edge
 
			}
 
			}
 

	
 
			/* Does the height differ more than one? */
 
			if (TileHeight(TileXY(col, row)) >= (uint)current_tile + 2) {
 
				/* Then change the height to be no more than one */
 
				SetTileHeight(TileXY(col, row), current_tile + 1);
 
			}
 
		}
 
	}
 

	
 
	/* Bottom and right edge */
 
	for (row = height - 2; row > 0; row--) {
 
		for (col = width - 2; col > 0; col--) {
 
	for (row = height - 1; row >= 0; row--) {
 
		for (col = width - 1; col >= 0; col--) {
 
			current_tile = MAX_TILE_HEIGHT;
 
			if ((uint)col != width - 1) {
 
			/* Find lowest tile; either the bottom and right one */
 
			current_tile = TileHeight(TileXY(col + 1, row)); // bottom edge
 
			}
 

	
 
			if ((uint)row != height - 1) {
 
			if (TileHeight(TileXY(col, row + 1)) < current_tile) {
 
				current_tile = TileHeight(TileXY(col, row + 1)); // right edge
 
			}
 
			}
 

	
 
			/* Does the height differ more than one? */
 
			if (TileHeight(TileXY(col, row)) >= (uint)current_tile + 2) {
 
				/* Then change the height to be no more than one */
 
				SetTileHeight(TileXY(col, row), current_tile + 1);
 
			}
 
@@ -444,20 +464,15 @@ void LoadHeightmap(char *filename)
 
	FixSlopes();
 
	MarkWholeScreenDirty();
 
}
 

	
 
void FlatEmptyWorld(byte tile_height)
 
{
 
	uint width, height;
 
	uint row, col;
 

	
 
	width  = MapSizeX();
 
	height = MapSizeY();
 

	
 
	for (row = 2; row < height - 2; row++) {
 
		for (col = 2; col < width - 2; col++) {
 
	int edge_distance = _settings_game.construction.freeform_edges ? 0 : 2;
 
	for (uint row = edge_distance; row < MapSizeY() - edge_distance; row++) {
 
		for (uint col = edge_distance; col < MapSizeX() - edge_distance; col++) {
 
			SetTileHeight(TileXY(col, row), tile_height);
 
		}
 
	}
 

	
 
	FixSlopes();
 
	MarkWholeScreenDirty();
src/industry_cmd.cpp
Show inline comments
 
@@ -927,12 +927,14 @@ static void PlantFarmField(TileIndex til
 
	size_x = GB(r, 0, 8);
 
	size_y = GB(r, 8, 8);
 

	
 
	/* offset tile to match size */
 
	tile -= TileDiffXY(size_x / 2, size_y / 2);
 

	
 
	if (TileX(tile) + size_x >= MapSizeX() || TileY(tile) + size_y >= MapSizeY()) return;
 

	
 
	/* check the amount of bad tiles */
 
	count = 0;
 
	BEGIN_TILE_LOOP(cur_tile, size_x, size_y, tile)
 
		cur_tile = TILE_MASK(cur_tile);
 
		count += IsBadFarmFieldTile(cur_tile);
 
	END_TILE_LOOP(cur_tile, size_x, size_y, tile)
 
@@ -1176,25 +1178,12 @@ static CheckNewIndustryProc * const _che
 
	CheckNewIndustry_Water,
 
	CheckNewIndustry_Lumbermill,
 
	CheckNewIndustry_BubbleGen,
 
	CheckNewIndustry_OilRig
 
};
 

	
 
static bool CheckSuitableIndustryPos(TileIndex tile)
 
{
 
	uint x = TileX(tile);
 
	uint y = TileY(tile);
 

	
 
	if (x < 2 || y < 2 || x > MapMaxX() - 3 || y > MapMaxY() - 3) {
 
		_error_message = STR_0239_SITE_UNSUITABLE;
 
		return false;
 
	}
 

	
 
	return true;
 
}
 

	
 
static const Town *CheckMultipleIndustryInTown(TileIndex tile, int type)
 
{
 
	const Town *t;
 
	const Industry *i;
 

	
 
	t = ClosestTownFromTile(tile, UINT_MAX);
 
@@ -1234,12 +1223,14 @@ static bool CheckIfIndustryTilesAreFree(
 
	_error_message = STR_0239_SITE_UNSUITABLE;
 
	bool refused_slope = false;
 
	bool custom_shape = false;
 

	
 
	do {
 
		IndustryGfx gfx = GetTranslatedIndustryTileID(it->gfx);
 
		if (TileX(tile) + it->ti.x >= MapSizeX()) return false;
 
		if (TileY(tile) + it->ti.y >= MapSizeY()) return false;
 
		TileIndex cur_tile = tile + ToTileIndexDiff(it->ti);
 

	
 
		if (!IsValidTile(cur_tile)) {
 
			if (gfx == GFX_WATERTILE_SPECIALCHECK) continue;
 
			return false;
 
		}
 
@@ -1339,13 +1330,13 @@ static bool CheckCanTerraformSurrounding
 
		if (internal != 0 && Delta(curh, height) > 1) return false;
 

	
 
		/* Different height, so the surrounding tiles of this tile
 
		 *  has to be correct too (in level, or almost in level)
 
		 *  else you get a chain-reaction of terraforming. */
 
		if (internal == 0 && curh != height) {
 
			if (!CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1))
 
			if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1))
 
				return false;
 
		}
 
	} END_TILE_LOOP(tile_walk, size_x, size_y, tile);
 

	
 
	return true;
 
}
 
@@ -1370,20 +1361,21 @@ static bool CheckIfCanLevelIndustryPlatf
 
		if (it->ti.y > max_y) max_y = it->ti.y;
 
	} while ((++it)->ti.x != MKEND);
 

	
 
	/* Remember level height */
 
	h = TileHeight(tile);
 

	
 
	if (TileX(tile) <= 1 || TileY(tile) <= 1) return false;
 
	/* Check that all tiles in area and surrounding are clear
 
	 * this determines that there are no obstructing items */
 
	cur_tile = tile + TileDiffXY(-1, -1);
 
	size_x = max_x + 4;
 
	size_y = max_y + 4;
 

	
 
	/* Check if we don't leave the map */
 
	if (TileX(cur_tile) == 0 || TileY(cur_tile) == 0 || TileX(cur_tile) + size_x >= MapMaxX() || TileY(cur_tile) + size_y >= MapMaxY()) return false;
 
	if (TileX(cur_tile) + size_x >= MapMaxX() || TileY(cur_tile) + size_y >= MapMaxY()) return false;
 

	
 
	/* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry.
 
	 * Perform terraforming as OWNER_TOWN to disable autoslope. */
 
	CompanyID old_company = _current_company;
 
	_current_company = OWNER_TOWN;
 

	
 
@@ -1629,13 +1621,12 @@ static Industry *CreateNewIndustryHelper
 
	if (!CheckIfFarEnoughFromIndustry(tile, type)) return NULL;
 

	
 
	const Town *t = CheckMultipleIndustryInTown(tile, type);
 
	if (t == NULL) return NULL;
 

	
 
	if (!CheckIfIndustryIsAllowed(tile, type, t)) return NULL;
 
	if (!CheckSuitableIndustryPos(tile)) return NULL;
 

	
 
	if (!Industry::CanAllocateItem()) return NULL;
 

	
 
	if (flags & DC_EXEC) {
 
		Industry *i = new Industry(tile);
 
		if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_EXEC, it, type);
src/landscape.cpp
Show inline comments
 
@@ -687,15 +687,15 @@ void InitializeLandscape()
 
{
 
	uint maxx = MapMaxX();
 
	uint maxy = MapMaxY();
 
	uint sizex = MapSizeX();
 

	
 
	uint y;
 
	for (y = 0; y < maxy; y++) {
 
	for (y = _settings_game.construction.freeform_edges ? 1 : 0; y < maxy; y++) {
 
		uint x;
 
		for (x = 0; x < maxx; x++) {
 
		for (x = _settings_game.construction.freeform_edges ? 1 : 0; x < maxx; x++) {
 
			MakeClear(sizex * y + x, CLEAR_GRASS, 3);
 
			SetTileHeight(sizex * y + x, 0);
 
			SetTropicZone(sizex * y + x, TROPICZONE_NORMAL);
 
			ClearBridgeMiddle(sizex * y + x);
 
		}
 
		MakeVoid(sizex * y + x);
src/lang/english.txt
Show inline comments
 
@@ -1087,12 +1087,35 @@ STR_CONFIG_PATCHES_TREE_PLACER_NONE     
 
STR_CONFIG_PATCHES_TREE_PLACER_ORIGINAL                         :Original
 
STR_CONFIG_PATCHES_TREE_PLACER_IMPROVED                         :Improved
 
STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION                           :{LTBLUE}Heightmap rotation: {ORANGE}{STRING1}
 
STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE         :Counter clockwise
 
STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION_CLOCKWISE                 :Clockwise
 
STR_CONFIG_PATCHES_SE_FLAT_WORLD_HEIGHT                         :{LTBLUE}The height level a flat scenario map gets: {ORANGE}{STRING1}
 
STR_CONFIG_PATCHES_ENABLE_FREEFORM_EDGES                        :{LTBLUE}Enable terraforming the tiles at the map borders
 
STR_CONFIG_PATCHES_EDGES_NOT_EMPTY                              :{WHITE}One or more tiles at the northern edge are not empty
 
STR_CONFIG_PATCHES_EDGES_NOT_WATER                              :{WHITE}One or more tiles at one of the edges is not water
 

	
 
# Start of map water border strings.
 
# DON'T ADD OR REMOVE LINES HERE
 
STR_CONFIG_PATCHES_WATER_BORDER_NONE                            :Land at all borders
 
STR_CONFIG_PATCHES_WATER_BORDER_NE                              :Water at north-east border only
 
STR_CONFIG_PATCHES_WATER_BORDER_SE                              :Water at south-east border only
 
STR_CONFIG_PATCHES_WATER_BORDER_SE_NE                           :Water at north-east and south-east borders
 
STR_CONFIG_PATCHES_WATER_BORDER_SW                              :Water at south-west border only
 
STR_CONFIG_PATCHES_WATER_BORDER_SW_NE                           :Water at north-east and south-west borders
 
STR_CONFIG_PATCHES_WATER_BORDER_SW_SE                           :Water at south-east and south-west borders
 
STR_CONFIG_PATCHES_WATER_BORDER_SW_SE_NE                        :Land only at north-west border
 
STR_CONFIG_PATCHES_WATER_BORDER_NW                              :Water at north-west border only
 
STR_CONFIG_PATCHES_WATER_BORDER_NW_NE                           :Water at north-west and north-east borders
 
STR_CONFIG_PATCHES_WATER_BORDER_NW_SE                           :Water at north-west and south-east borders
 
STR_CONFIG_PATCHES_WATER_BORDER_NW_SE_NE                        :Land only at south-west border
 
STR_CONFIG_PATCHES_WATER_BORDER_NW_SW                           :Water at north-west and south-west borders
 
STR_CONFIG_PATCHES_WATER_BORDER_NW_SW_NE                        :Land only at south-east border
 
STR_CONFIG_PATCHES_WATER_BORDER_NW_SW_SE                        :Land only at north-east border
 
STR_CONFIG_PATCHES_WATER_BORDER_NW_SW_SE_NE                     :Water at all borders
 
# End of map water border strings.
 

	
 
STR_CONFIG_PATCHES_STATION_SPREAD                               :{LTBLUE}Max station spread: {ORANGE}{STRING1} {RED}Warning: High setting slows game
 
STR_CONFIG_PATCHES_SERVICEATHELIPAD                             :{LTBLUE}Service helicopters at helipads automatically: {ORANGE}{STRING1}
 
STR_CONFIG_PATCHES_LINK_TERRAFORM_TOOLBAR                       :{LTBLUE}Link landscape toolbar to rail/road/water/airport toolbars: {ORANGE}{STRING1}
 
STR_CONFIG_PATCHES_REVERSE_SCROLLING                            :{LTBLUE}Reverse scroll direction: {ORANGE}{STRING1}
 
STR_CONFIG_PATCHES_SMOOTH_SCROLLING                             :{LTBLUE}Smooth viewport scrolling: {ORANGE}{STRING1}
 
@@ -2115,12 +2138,13 @@ STR_INDUSTRY_PROD_GOUP                  
 
STR_INDUSTRY_PROD_GODOWN                                        :{BLACK}{BIGFONT}{STRING} production at {INDUSTRY} decreases {COMMA}%!
 

	
 
##id 0x5000
 
STR_5000_TRAIN_IN_TUNNEL                                        :{WHITE}Train in tunnel
 
STR_5001_ROAD_VEHICLE_IN_TUNNEL                                 :{WHITE}Road vehicle in tunnel
 
STR_5003_ANOTHER_TUNNEL_IN_THE_WAY                              :{WHITE}Another tunnel in the way
 
STR_TUNNEL_THROUGH_MAP_BORDER                                   :{WHITE}Tunnel would end out of the map
 
STR_5005_UNABLE_TO_EXCAVATE_LAND                                :{WHITE}Unable to excavate land for other end of tunnel
 
STR_5006_MUST_DEMOLISH_TUNNEL_FIRST                             :{WHITE}Must demolish tunnel first
 
STR_5007_MUST_DEMOLISH_BRIDGE_FIRST                             :{WHITE}Must demolish bridge first
 
STR_5008_CANNOT_START_AND_END_ON                                :{WHITE}Can't start and end in the same spot
 
STR_BRIDGEHEADS_NOT_SAME_HEIGHT                                 :{WHITE}Bridge heads not at the same level
 
STR_BRIDGE_TOO_LOW_FOR_TERRAIN                                  :{WHITE}Bridge is too low for the terrain
src/newgrf_industries.cpp
Show inline comments
 
@@ -56,12 +56,13 @@ static uint GetClosestWaterDistance(Tile
 

	
 
	int x = TileX(tile);
 
	int y = TileY(tile);
 

	
 
	uint max_x = MapMaxX();
 
	uint max_y = MapMaxY();
 
	uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
 

	
 
	/* go in a 'spiral' with increasing manhattan distance in each iteration */
 
	for (uint dist = 1; dist < max_dist; dist++) {
 
		/* next 'diameter' */
 
		y--;
 

	
 
@@ -72,14 +73,14 @@ static uint GetClosestWaterDistance(Tile
 

	
 
			int dx = ddx[dir];
 
			int dy = ddy[dir];
 

	
 
			/* each side of this square has length 'dist' */
 
			for (uint a = 0; a < dist; a++) {
 
				/* MP_VOID tiles are not checked (interval is [0; max) for IsInsideMM())*/
 
				if (IsInsideMM(x, 0, max_x) && IsInsideMM(y, 0, max_y)) {
 
				/* MP_VOID tiles are not checked (interval is [min; max) for IsInsideMM())*/
 
				if (IsInsideMM(x, min_xy, max_x) && IsInsideMM(y, min_xy, max_y)) {
 
					TileIndex t = TileXY(x, y);
 
					if (IsTileType(t, MP_WATER) == water) return dist;
 
				}
 
				x += dx;
 
				y += dy;
 
			}
src/saveload/afterload.cpp
Show inline comments
 
@@ -656,12 +656,17 @@ bool AfterLoadGame()
 

	
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	/* Force the freeform edges to false for old savegames. */
 
	if (CheckSavegameVersion(111)) {
 
		_settings_game.construction.freeform_edges = false;
 
	}
 

	
 
	/* From version 9.0, we update the max passengers of a town (was sometimes negative
 
	 *  before that. */
 
	if (CheckSavegameVersion(9)) {
 
		Town *t;
 
		FOR_ALL_TOWNS(t) UpdateTownMaxPass(t);
 
	}
src/saveload/saveload.cpp
Show inline comments
 
@@ -39,13 +39,13 @@
 

	
 
#include "saveload.h"
 
#include "saveload_internal.h"
 

	
 
#include <list>
 

	
 
extern const uint16 SAVEGAME_VERSION = 110;
 
extern const uint16 SAVEGAME_VERSION = 111;
 

	
 
SavegameType _savegame_type; ///< type of savegame we are loading
 

	
 
uint32 _ttdp_version;     ///< version of TTDP savegame (if applicable)
 
uint16 _sl_version;       ///< the major savegame version identifier
 
byte   _sl_minor_version; ///< the minor savegame version, DO NOT USE!
src/settings.cpp
Show inline comments
 
@@ -65,12 +65,16 @@
 
#include "settings_func.h"
 
#include "ini_type.h"
 
#include "ai/ai.hpp"
 
#include "ai/ai_config.hpp"
 
#include "ai/ai_info.hpp"
 

	
 
#include "tile_map.h"
 
#include "void_map.h"
 
#include "station_base.h"
 

	
 
#include "table/strings.h"
 

	
 
ClientSettings _settings_client;
 
GameSettings _settings_game;
 
GameSettings _settings_newgame;
 

	
 
@@ -1076,12 +1080,77 @@ static int32 CheckNoiseToleranceLevel(co
 
	for (uint16 i = 0; i < lengthof(s->economy.town_noise_population); i++) {
 
		s->economy.town_noise_population[i] = max(uint16(200 * (i + 1)), s->economy.town_noise_population[i]);
 
	}
 
	return 0;
 
}
 

	
 
static int32 CheckFreeformEdges(int32 p1)
 
{
 
	if (_game_mode == GM_MENU) return 0;
 
	if (p1 != 0) {
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_SHIP && (TileX(v->tile) == 0 || TileY(v->tile) == 0)) {
 
				ShowErrorMessage(INVALID_STRING_ID, STR_CONFIG_PATCHES_EDGES_NOT_EMPTY, 0, 0);
 
				_settings_game.construction.freeform_edges = false;
 
				return 0;
 
			}
 
		}
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			if (TileX(st->xy) == 0 || TileY(st->xy) == 0) {
 
				ShowErrorMessage(INVALID_STRING_ID, STR_CONFIG_PATCHES_EDGES_NOT_EMPTY, 0, 0);
 
				_settings_game.construction.freeform_edges = false;
 
				return 0;
 
			}
 
		}
 
		for (uint i = 0; i < MapSizeX(); i++) MakeVoid(TileXY(i, 0));
 
		for (uint i = 0; i < MapSizeY(); i++) MakeVoid(TileXY(0, i));
 
	} else {
 
		for (uint i = 0; i < MapMaxX(); i++) {
 
			if (TileHeight(TileXY(i, 1)) != 0) {
 
				ShowErrorMessage(INVALID_STRING_ID, STR_CONFIG_PATCHES_EDGES_NOT_WATER, 0, 0);
 
				_settings_game.construction.freeform_edges = true;
 
				return 0;
 
			}
 
		}
 
		for (uint i = 1; i < MapMaxX(); i++) {
 
			if (!IsTileType(TileXY(i, MapMaxY() - 1), MP_WATER) || TileHeight(TileXY(1, MapMaxY())) != 0) {
 
				ShowErrorMessage(INVALID_STRING_ID, STR_CONFIG_PATCHES_EDGES_NOT_WATER, 0, 0);
 
				_settings_game.construction.freeform_edges = true;
 
				return 0;
 
			}
 
		}
 
		for (uint i = 0; i < MapMaxY(); i++) {
 
			if (TileHeight(TileXY(1, i)) != 0) {
 
				ShowErrorMessage(INVALID_STRING_ID, STR_CONFIG_PATCHES_EDGES_NOT_WATER, 0, 0);
 
				_settings_game.construction.freeform_edges = true;
 
				return 0;
 
			}
 
		}
 
		for (uint i = 1; i < MapMaxY(); i++) {
 
			if (!IsTileType(TileXY(MapMaxX() - 1, i), MP_WATER) || TileHeight(TileXY(MapMaxX(), i)) != 0) {
 
				ShowErrorMessage(INVALID_STRING_ID, STR_CONFIG_PATCHES_EDGES_NOT_WATER, 0, 0);
 
				_settings_game.construction.freeform_edges = true;
 
				return 0;
 
			}
 
		}
 
		/* Make tiles at the border water again. */
 
		for (uint i = 0; i < MapMaxX(); i++) {
 
			SetTileHeight(TileXY(i, 0), 0);
 
			SetTileType(TileXY(i, 0), MP_WATER);
 
		}
 
		for (uint i = 0; i < MapMaxY(); i++) {
 
			SetTileHeight(TileXY(0, i), 0);
 
			SetTileType(TileXY(0, i), MP_WATER);
 
		}
 
	}
 
	MarkWholeScreenDirty();
 
	return 0;
 
}
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
static int32 UpdateMinActiveClients(int32 p1)
 
{
 
	CheckMinActiveClients();
 
	return 0;
 
@@ -1393,12 +1462,14 @@ const SettingDesc _patch_settings[] = {
 
	 SDT_CONDVAR(GameSettings, game_creation.tree_placer,                     SLE_UINT8, 30, SL_MAX_VERSION, 0,MS,     2,                     0,       2, 0, STR_CONFIG_PATCHES_TREE_PLACER,           NULL),
 
	     SDT_VAR(GameSettings, game_creation.heightmap_rotation,              SLE_UINT8,                     S,MS,     0,                     0,       1, 0, STR_CONFIG_PATCHES_HEIGHTMAP_ROTATION,    NULL),
 
	     SDT_VAR(GameSettings, game_creation.se_flat_world_height,            SLE_UINT8,                     S, 0,     0,                     0,      15, 0, STR_CONFIG_PATCHES_SE_FLAT_WORLD_HEIGHT,  NULL),
 

	
 
	     SDT_VAR(GameSettings, game_creation.map_x,                           SLE_UINT8,                     S, 0,     8,                     6,      11, 0, STR_CONFIG_PATCHES_MAP_X,                 NULL),
 
	     SDT_VAR(GameSettings, game_creation.map_y,                           SLE_UINT8,                     S, 0,     8,                     6,      11, 0, STR_CONFIG_PATCHES_MAP_Y,                 NULL),
 
	SDT_CONDBOOL(GameSettings, construction.freeform_edges,                             111, SL_MAX_VERSION, 0, 0, false,                                    STR_CONFIG_PATCHES_ENABLE_FREEFORM_EDGES, CheckFreeformEdges),
 
	 SDT_CONDVAR(GameSettings, game_creation.water_borders,                   SLE_UINT8,111, SL_MAX_VERSION, 0, 0,    15,                     0,      15, 0, STR_NULL,                                 NULL),
 

	
 
 SDT_CONDOMANY(GameSettings, locale.currency,                               SLE_UINT8, 97, SL_MAX_VERSION, N, 0, 0, CUSTOM_CURRENCY_ID, "GBP|USD|EUR|YEN|ATS|BEF|CHF|CZK|DEM|DKK|ESP|FIM|FRF|GRD|HUF|ISK|ITL|NLG|NOK|PLN|ROL|RUR|SIT|SEK|YTL|SKK|BRR|custom", STR_NULL, NULL, NULL),
 
 SDT_CONDOMANY(GameSettings, locale.units,                                  SLE_UINT8, 97, SL_MAX_VERSION, N, 0, 1, 2, "imperial|metric|si", STR_NULL, NULL, NULL),
 

	
 
	/***************************************************************************/
 
	/* Unsaved patch variables. */
src/settings_gui.cpp
Show inline comments
 
@@ -1063,12 +1063,13 @@ static PatchEntry _patches_construction[
 
	PatchEntry(&_patches_construction_signals_page, STR_CONFIG_PATCHES_CONSTRUCTION_SIGNALS),
 
	PatchEntry("construction.build_on_slopes"),
 
	PatchEntry("construction.autoslope"),
 
	PatchEntry("construction.extra_dynamite"),
 
	PatchEntry("construction.longbridges"),
 
	PatchEntry("station.always_small_airport"),
 
	PatchEntry("construction.freeform_edges"),
 
};
 
/** Construction sub-page */
 
static PatchPage _patches_construction_page = {_patches_construction, lengthof(_patches_construction)};
 

	
 
static PatchEntry _patches_stations_cargo[] = {
 
	PatchEntry("order.improved_load"),
src/settings_type.h
Show inline comments
 
@@ -151,23 +151,25 @@ struct GameCreationSettings {
 
	byte   tree_placer;                      ///< the tree placer algorithm
 
	byte   heightmap_rotation;               ///< rotation director for the heightmap
 
	byte   se_flat_world_height;             ///< land height a flat world gets in SE
 
	byte   town_name;                        ///< the town name generator used for town names
 
	byte   landscape;                        ///< the landscape we're currently in
 
	byte   snow_line;                        ///< the snowline level in this game
 
	byte   water_borders;                    ///< bitset of the borders that are water
 
};
 

	
 
/** Settings related to construction in-game */
 
struct ConstructionSettings {
 
	bool   build_on_slopes;                  ///< allow building on slopes
 
	bool   autoslope;                        ///< allow terraforming under things
 
	bool   longbridges;                      ///< allow 100 tile long bridges
 
	bool   signal_side;                      ///< show signals on right side
 
	bool   extra_dynamite;                   ///< extra dynamite
 
	bool   road_stop_on_town_road;           ///< allow building of drive-through road stops on town owned roads
 
	uint8  raw_industry_construction;        ///< type of (raw) industry construction (none, "normal", prospecting)
 
	bool   freeform_edges;                   ///< allow terraforming the tiles at the map edges
 
};
 

	
 
/** Settings related to the AI. */
 
struct AISettings {
 
	bool   ai_in_multiplayer;                ///< so we allow AIs in multiplayer
 
	bool   ai_disable_veh_train;             ///< disable types for AI
src/sound.cpp
Show inline comments
 
@@ -234,14 +234,14 @@ static void SndPlayScreenCoordFx(SoundFx
 
	}
 
}
 

	
 
void SndPlayTileFx(SoundFx sound, TileIndex tile)
 
{
 
	/* emits sound from center of the tile */
 
	int x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
 
	int y = TileY(tile) * TILE_SIZE - TILE_SIZE / 2;
 
	int x = min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2;
 
	int y = min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2;
 
	uint z = (y < 0 ? 0 : GetSlopeZ(x, y));
 
	Point pt = RemapCoords(x, y, z);
 
	y += 2 * TILE_SIZE;
 
	Point pt2 = RemapCoords(x, y, GetSlopeZ(x, y));
 
	SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y);
 
}
src/terraform_cmd.cpp
Show inline comments
 
@@ -127,15 +127,16 @@ static void TerraformAddDirtyTile(Terraf
 
 * @param ts TerraformerState.
 
 * @param tile Tile.
 
 * @ingroup dirty
 
 */
 
static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile)
 
{
 
	TerraformAddDirtyTile(ts, tile + TileDiffXY( 0, -1));
 
	TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, -1));
 
	TerraformAddDirtyTile(ts, tile + TileDiffXY(-1,  0));
 
	/* Make sure all tiles passed to TerraformAddDirtyTile are within [0, MapSize()] */
 
	if (TileY(tile) >= 1) TerraformAddDirtyTile(ts, tile + TileDiffXY( 0, -1));
 
	if (TileY(tile) >= 1 && TileX(tile) >= 1) TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, -1));
 
	if (TileX(tile) >= 1) TerraformAddDirtyTile(ts, tile + TileDiffXY(-1,  0));
 
	TerraformAddDirtyTile(ts, tile);
 
}
 

	
 
/**
 
 * Terraform the north corner of a tile to a specific height.
 
 *
 
@@ -156,16 +157,16 @@ static CommandCost TerraformTileHeight(T
 
	 * Check if the terraforming has any effect.
 
	 * This can only be true, if multiple corners of the start-tile are terraformed (i.e. the terraforming is done by towns/industries etc.).
 
	 * In this case the terraforming should fail. (Don't know why.)
 
	 */
 
	if (height == TerraformGetHeightOfTile(ts, tile)) return CMD_ERROR;
 

	
 
	/* Check "too close to edge of map" */
 
	/* Check "too close to edge of map". Only possible when freeform-edges is off. */
 
	uint x = TileX(tile);
 
	uint y = TileY(tile);
 
	if ((x <= 1) || (y <= 1) || (x >= MapMaxX() - 1) || (y >= MapMaxY() - 1)) {
 
	if (!_settings_game.construction.freeform_edges && ((x <= 1) || (y <= 1) || (x >= MapMaxX() - 1) || (y >= MapMaxY() - 1))) {
 
		/*
 
		 * Determine a sensible error tile
 
		 */
 
		if (x == 1) x = 0;
 
		if (y == 1) y = 0;
 
		_terraform_err_tile = TileXY(x, y);
 
@@ -184,22 +185,28 @@ static CommandCost TerraformTileHeight(T
 
	total_cost.AddCost(_price.terraform);
 

	
 
	/* Recurse to neighboured corners if height difference is larger than 1 */
 
	{
 
		const TileIndexDiffC *ttm;
 

	
 
		TileIndex orig_tile = tile;
 
		static const TileIndexDiffC _terraform_tilepos[] = {
 
			{ 1,  0}, // move to tile in SE
 
			{-2,  0}, // undo last move, and move to tile in NW
 
			{ 1,  1}, // undo last move, and move to tile in SW
 
			{ 0, -2}  // undo last move, and move to tile in NE
 
		};
 

	
 
		for (ttm = _terraform_tilepos; ttm != endof(_terraform_tilepos); ttm++) {
 
			tile += ToTileIndexDiff(*ttm);
 

	
 
			if (tile >= MapSize()) continue;
 
			/* Make sure we don't wrap around the map */
 
			if (Delta(TileX(orig_tile), TileX(tile)) == MapSizeX() - 1) continue;
 
			if (Delta(TileY(orig_tile), TileY(tile)) == MapSizeY() - 1) continue;
 

	
 
			/* Get TileHeight of neighboured tile as of current terraform progress */
 
			int r = TerraformGetHeightOfTile(ts, tile);
 
			int height_diff = height - r;
 

	
 
			/* Is the height difference to the neighboured corner greater than 1? */
 
			if (abs(height_diff) > 1) {
 
@@ -221,15 +228,12 @@ static CommandCost TerraformTileHeight(T
 
 * @param p1 corners to terraform (SLOPE_xxx)
 
 * @param p2 direction; eg up (non-zero) or down (zero)
 
 * @return error or cost of terraforming
 
 */
 
CommandCost CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	/* Make an extra check for map-bounds cause we add tiles to the originating tile */
 
	if (tile + TileDiffXY(1, 1) >= MapSize()) return CMD_ERROR;
 

	
 
	_terraform_err_tile = INVALID_TILE;
 

	
 
	CommandCost total_cost(EXPENSES_CONSTRUCTION);
 
	int direction = (p2 != 0 ? 1 : -1);
 
	TerraformerState ts;
 

	
 
@@ -268,12 +272,17 @@ CommandCost CmdTerraformLand(TileIndex t
 
	{
 
		TileIndex *ti = ts.tile_table;
 

	
 
		for (int count = ts.tile_table_count; count != 0; count--, ti++) {
 
			TileIndex tile = *ti;
 

	
 
			assert(tile < MapSize());
 
			/* MP_VOID tiles can be terraformed but as tunnels and bridges
 
			 * cannot go under / over these tiles they don't need checking. */
 
			if (IsTileType(tile, MP_VOID)) continue;
 

	
 
			/* Find new heights of tile corners */
 
			uint z_N = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0));
 
			uint z_W = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0));
 
			uint z_S = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
 
			uint z_E = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
 

	
src/terraform_gui.cpp
Show inline comments
 
@@ -110,16 +110,18 @@ static void GenerateRockyArea(TileIndex 
 
 * @return Returns true if the action was found and handled, and false otherwise. This
 
 * allows for additional implements that are more local. For example X_Y drag
 
 * of convertrail which belongs in rail_gui.cpp and not terraform_gui.cpp
 
 **/
 
bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile)
 
{
 
	/* When end_tile is MP_VOID, the DoCommandP checks will deny this command without any
 
	 * user-visible reason. This happens when terraforming at the southern border. */
 
	if (!_settings_game.construction.freeform_edges) {
 
		/* When end_tile is MP_VOID, the error tile will not be visible to the
 
		 * user. This happens when terraforming at the southern border. */
 
	if (TileX(end_tile) == MapMaxX()) end_tile += TileDiffXY(-1, 0);
 
	if (TileY(end_tile) == MapMaxY()) end_tile += TileDiffXY(0, -1);
 
	}
 

	
 
	switch (proc) {
 
		case DDSP_DEMOLISH_AREA:
 
			DoCommandP(end_tile, start_tile, 0, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA), CcPlaySound10);
 
			break;
 
		case DDSP_RAISE_AND_LEVEL_AREA:
 
@@ -375,14 +377,14 @@ static void CommonRaiseLowerBigLand(Tile
 
			mode ? STR_0808_CAN_T_RAISE_LAND_HERE : STR_0809_CAN_T_LOWER_LAND_HERE;
 

	
 
		DoCommandP(tile, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND | CMD_MSG(msg), CcTerraform);
 
	} else {
 
		assert(_terraform_size != 0);
 
		/* check out for map overflows */
 
		sizex = min(MapSizeX() - TileX(tile) - 1, _terraform_size);
 
		sizey = min(MapSizeY() - TileY(tile) - 1, _terraform_size);
 
		sizex = min(MapSizeX() - TileX(tile), _terraform_size);
 
		sizey = min(MapSizeY() - TileY(tile), _terraform_size);
 

	
 
		if (sizex == 0 || sizey == 0) return;
 

	
 
		SndPlayTileFx(SND_1F_SPLAT, tile);
 

	
 
		if (mode != 0) {
src/tgp.cpp
Show inline comments
 
@@ -549,12 +549,19 @@ static void HeightMapAdjustWaterLevel(am
 

	
 
	free(hist_buf);
 
}
 

	
 
static double perlin_coast_noise_2D(const double x, const double y, const double p, const int prime);
 

	
 
enum Borders {
 
	BORDER_NE = 0,
 
	BORDER_SE = 1,
 
	BORDER_SW = 2,
 
	BORDER_NW = 3,
 
};
 

	
 
/**
 
 * This routine sculpts in from the edge a random amount, again a Perlin
 
 * sequence, to avoid the rigid flat-edge slopes that were present before. The
 
 * Perlin noise map doesnt know where we are going to slice across, and so we
 
 * often cut straight through high terrain. the smoothing routine makes it
 
 * legal, gradually increasing up from the edge to the original terrain height.
 
@@ -569,59 +576,66 @@ static double perlin_coast_noise_2D(cons
 
 * though the map has been built for the map size, rather than a slice through
 
 * a larger map.
 
 *
 
 * Please note that all the small numbers; 53, 101, 167, etc. are small primes
 
 * to help give the perlin noise a bit more of a random feel.
 
 */
 
static void HeightMapCoastLines()
 
static void HeightMapCoastLines(uint8 water_borders)
 
{
 
	int smallest_size = min(_settings_game.game_creation.map_x, _settings_game.game_creation.map_y);
 
	const int margin = 4;
 
	uint y, x;
 
	double max_x;
 
	double max_y;
 

	
 
	/* Lower to sea level */
 
	for (y = 0; y <= _height_map.size_y; y++) {
 
		if (HasBit(water_borders, BORDER_NE)) {
 
		/* Top right */
 
		max_x = abs((perlin_coast_noise_2D(_height_map.size_y - y, y, 0.9, 53) + 0.25) * 5 + (perlin_coast_noise_2D(y, y, 0.35, 179) + 1) * 12);
 
		max_x = max((smallest_size * smallest_size / 16) + max_x, (smallest_size * smallest_size / 16) + margin - max_x);
 
		if (smallest_size < 8 && max_x > 5) max_x /= 1.5;
 
		for (x = 0; x < max_x; x++) {
 
			_height_map.height(x, y) = 0;
 
		}
 
		}
 

	
 
		if (HasBit(water_borders, BORDER_SW)) {
 
		/* Bottom left */
 
		max_x = abs((perlin_coast_noise_2D(_height_map.size_y - y, y, 0.85, 101) + 0.3) * 6 + (perlin_coast_noise_2D(y, y, 0.45,  67) + 0.75) * 8);
 
		max_x = max((smallest_size * smallest_size / 16) + max_x, (smallest_size * smallest_size / 16) + margin - max_x);
 
		if (smallest_size < 8 && max_x > 5) max_x /= 1.5;
 
		for (x = _height_map.size_x; x > (_height_map.size_x - 1 - max_x); x--) {
 
			_height_map.height(x, y) = 0;
 
		}
 
	}
 
	}
 

	
 
	/* Lower to sea level */
 
	for (x = 0; x <= _height_map.size_x; x++) {
 
		if (HasBit(water_borders, BORDER_NW)) {
 
		/* Top left */
 
		max_y = abs((perlin_coast_noise_2D(x, _height_map.size_y / 2, 0.9, 167) + 0.4) * 5 + (perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.4, 211) + 0.7) * 9);
 
		max_y = max((smallest_size * smallest_size / 16) + max_y, (smallest_size * smallest_size / 16) + margin - max_y);
 
		if (smallest_size < 8 && max_y > 5) max_y /= 1.5;
 
		for (y = 0; y < max_y; y++) {
 
			_height_map.height(x, y) = 0;
 
		}
 
		}
 

	
 

	
 
		if (HasBit(water_borders, BORDER_SE)) {
 
		/* Bottom right */
 
		max_y = abs((perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.85, 71) + 0.25) * 6 + (perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.35, 193) + 0.75) * 12);
 
		max_y = max((smallest_size * smallest_size / 16) + max_y, (smallest_size * smallest_size / 16) + margin - max_y);
 
		if (smallest_size < 8 && max_y > 5) max_y /= 1.5;
 
		for (y = _height_map.size_y; y > (_height_map.size_y - 1 - max_y); y--) {
 
			_height_map.height(x, y) = 0;
 
		}
 
	}
 
}
 
}
 

	
 
/** Start at given point, move in given direction, find and Smooth coast in that direction */
 
static void HeightMapSmoothCoastInDirection(int org_x, int org_y, int dir_x, int dir_y)
 
{
 
	const int max_coast_dist_from_edge = 35;
 
	const int max_coast_Smooth_depth = 35;
 
@@ -655,24 +669,24 @@ static void HeightMapSmoothCoastInDirect
 
		_height_map.height(x, y) = h;
 
		h_prev = h;
 
	}
 
}
 

	
 
/** Smooth coasts by modulating height of tiles close to map edges with cosine of distance from edge */
 
static void HeightMapSmoothCoasts()
 
static void HeightMapSmoothCoasts(uint8 water_borders)
 
{
 
	uint x, y;
 
	/* First Smooth NW and SE coasts (y close to 0 and y close to size_y) */
 
	for (x = 0; x < _height_map.size_x; x++) {
 
		HeightMapSmoothCoastInDirection(x, 0, 0, 1);
 
		HeightMapSmoothCoastInDirection(x, _height_map.size_y - 1, 0, -1);
 
		if (HasBit(water_borders, BORDER_NW)) HeightMapSmoothCoastInDirection(x, 0, 0, 1);
 
		if (HasBit(water_borders, BORDER_SE)) HeightMapSmoothCoastInDirection(x, _height_map.size_y - 1, 0, -1);
 
	}
 
	/* First Smooth NE and SW coasts (x close to 0 and x close to size_x) */
 
	for (y = 0; y < _height_map.size_y; y++) {
 
		HeightMapSmoothCoastInDirection(0, y, 1, 0);
 
		HeightMapSmoothCoastInDirection(_height_map.size_x - 1, y, -1, 0);
 
		if (HasBit(water_borders, BORDER_NE)) HeightMapSmoothCoastInDirection(0, y, 1, 0);
 
		if (HasBit(water_borders, BORDER_SW)) HeightMapSmoothCoastInDirection(_height_map.size_x - 1, y, -1, 0);
 
	}
 
}
 

	
 
/**
 
 * This routine provides the essential cleanup necessary before OTTD can
 
 * display the terrain. When generated, the terrain heights can jump more than
 
@@ -680,21 +694,21 @@ static void HeightMapSmoothCoasts()
 
 * the most it can change is one level. When OTTD can support cliffs, this
 
 * routine may not be necessary.
 
 */
 
static void HeightMapSmoothSlopes(height_t dh_max)
 
{
 
	int x, y;
 
	for (y = 1; y <= (int)_height_map.size_y; y++) {
 
		for (x = 1; x <= (int)_height_map.size_x; x++) {
 
			height_t h_max = min(_height_map.height(x - 1, y), _height_map.height(x, y - 1)) + dh_max;
 
	for (y = 0; y <= (int)_height_map.size_y; y++) {
 
		for (x = 0; x <= (int)_height_map.size_x; x++) {
 
			height_t h_max = min(_height_map.height(x > 0 ? x - 1 : x, y), _height_map.height(x, y > 0 ? y - 1 : y)) + dh_max;
 
			if (_height_map.height(x, y) > h_max) _height_map.height(x, y) = h_max;
 
		}
 
	}
 
	for (y = _height_map.size_y - 1; y >= 0; y--) {
 
		for (x = _height_map.size_x - 1; x >= 0; x--) {
 
			height_t h_max = min(_height_map.height(x + 1, y), _height_map.height(x, y + 1)) + dh_max;
 
	for (y = _height_map.size_y; y >= 0; y--) {
 
		for (x = _height_map.size_x; x >= 0; x--) {
 
			height_t h_max = min(_height_map.height((uint)x < _height_map.size_x ? x + 1 : x, y), _height_map.height(x, (uint)y < _height_map.size_y ? y + 1 : y)) + dh_max;
 
			if (_height_map.height(x, y) > h_max) _height_map.height(x, y) = h_max;
 
		}
 
	}
 
}
 

	
 
/** Height map terraform post processing:
 
@@ -707,16 +721,18 @@ static void HeightMapNormalize()
 
	const amplitude_t water_percent = _water_percent[_settings_game.difficulty.quantity_sea_lakes];
 
	const height_t h_max_new = I2H(_max_height[_settings_game.difficulty.terrain_type]);
 
	const height_t roughness = 7 + 3 * _settings_game.game_creation.tgen_smoothness;
 

	
 
	HeightMapAdjustWaterLevel(water_percent, h_max_new);
 

	
 
	HeightMapCoastLines();
 
	byte water_borders = _settings_game.construction.freeform_edges ? _settings_game.game_creation.water_borders : 0xF;
 

	
 
	HeightMapCoastLines(water_borders);
 
	HeightMapSmoothSlopes(roughness);
 

	
 
	HeightMapSmoothCoasts();
 
	HeightMapSmoothCoasts(water_borders);
 
	HeightMapSmoothSlopes(roughness);
 

	
 
	HeightMapSineTransform(12, h_max_new);
 
	HeightMapSmoothSlopes(16);
 
}
 

	
 
@@ -814,14 +830,19 @@ static double perlin_coast_noise_2D(cons
 

	
 

	
 
/** A small helper function to initialize the terrain */
 
static void TgenSetTileHeight(TileIndex tile, int height)
 
{
 
	SetTileHeight(tile, height);
 

	
 
	/* Only clear the tiles within the map area. */
 
	if (TileX(tile) != MapMaxX() && TileY(tile) != MapMaxY() &&
 
			(!_settings_game.construction.freeform_edges || (TileX(tile) != 0 && TileY(tile) != 0))) {
 
	MakeClear(tile, CLEAR_GRASS, 3);
 
}
 
}
 

	
 
/**
 
 * The main new land generator using Perlin noise. Desert landscape is handled
 
 * different to all others to give a desert valley between two high mountains.
 
 * Clearly if a low height terrain (flat/very flat) is chosen, then the tropic
 
 * areas wont be high enough, and there will be very little tropic on the map.
 
@@ -839,25 +860,27 @@ void GenerateTerrainPerlin()
 
	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
 

	
 
	HeightMapNormalize();
 

	
 
	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
 

	
 
	/* First make sure the tiles at the north border are void tiles if needed. */
 
	if (_settings_game.construction.freeform_edges) {
 
		for (y = 0; y < _height_map.size_y - 1; y++) MakeVoid(_height_map.size_x * y);
 
		for (x = 0; x < _height_map.size_x;     x++) MakeVoid(x);
 
	}
 

	
 
	/* Transfer height map into OTTD map */
 
	for (y = 2; y < _height_map.size_y - 2; y++) {
 
		for (x = 2; x < _height_map.size_x - 2; x++) {
 
	for (y = 0; y < _height_map.size_y; y++) {
 
		for (x = 0; x < _height_map.size_x; x++) {
 
			int height = H2I(_height_map.height(x, y));
 
			if (height < 0) height = 0;
 
			if (height > 15) height = 15;
 
			TgenSetTileHeight(TileXY(x, y), height);
 
		}
 
	}
 

	
 
	IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
 

	
 
	/* Recreate void tiles at the border in case they have been affected by generation */
 
	for (y = 0; y < _height_map.size_y - 1; y++) MakeVoid(_height_map.size_x * y + _height_map.size_x - 1);
 
	for (x = 0; x < _height_map.size_x;     x++) MakeVoid(_height_map.size_x * y + x);
 

	
 
	FreeHeightMap();
 
	GenerateWorldSetAbortCallback(NULL);
 
}
src/tile_map.cpp
Show inline comments
 
@@ -13,14 +13,15 @@
 
 * @param h    If not \c NULL, pointer to storage of z height
 
 * @return Slope of the tile, except for the HALFTILE part */
 
Slope GetTileSlope(TileIndex tile, uint *h)
 
{
 
	assert(tile < MapSize());
 

	
 
	if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) {
 
		if (h != NULL) *h = 0;
 
	if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY() ||
 
			(_settings_game.construction.freeform_edges && (TileX(tile) == 0 || TileY(tile) == 0))) {
 
		if (h != NULL) *h = TileHeight(tile) * TILE_HEIGHT;
 
		return SLOPE_FLAT;
 
	}
 

	
 
	uint a = TileHeight(tile); // Height of the N corner
 
	uint min = a; // Minimal height of all corners examined so far
 
	uint b = TileHeight(tile + TileDiffXY(1, 0)); // Height of the W corner
src/tile_map.h
Show inline comments
 
@@ -7,12 +7,13 @@
 

	
 
#include "tile_type.h"
 
#include "slope_type.h"
 
#include "company_type.h"
 
#include "map_func.h"
 
#include "core/bitmath_func.hpp"
 
#include "settings_type.h"
 

	
 
/**
 
 * Returns the height of a tile
 
 *
 
 * This function returns the height of the northern corner of a tile.
 
 * This is saved in the global map-array. It does not take affect by
 
@@ -84,14 +85,15 @@ static inline TileType GetTileType(TileI
 
 * @pre type MP_VOID <=> tile is on the south-east or south-west edge.
 
 */
 
static inline void SetTileType(TileIndex tile, TileType type)
 
{
 
	assert(tile < MapSize());
 
	/* VOID tiles (and no others) are exactly allowed at the lower left and right
 
	 * edges of the map */
 
	assert((TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) == (type == MP_VOID));
 
	 * edges of the map. If _settings_game.construction.freeform_edges is true,
 
	 * the upper edges of the map are also VOID tiles. */
 
	assert((TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY() || (_settings_game.construction.freeform_edges && (TileX(tile) == 0 || TileY(tile) == 0))) == (type == MP_VOID));
 
	SB(_m[tile].type_height, 4, 4, type);
 
}
 

	
 
/**
 
 * Checks if a tile is a give tiletype.
 
 *
src/town_cmd.cpp
Show inline comments
 
@@ -756,13 +756,13 @@ static bool IsNeighborRoadTile(TileIndex
 
		 * for each uneven value the left TileIndexDiff
 
		 * for each with 2nd bit set (2,3,6,7,..) add the reversed TileIndexDiff */
 
		cur += tid_lt[(pos & 1) ? 0 : 1];
 
		if (pos & 2) cur += tid_lt[2];
 

	
 
		cur = (uint)(pos / 4) * cur; // Multiply for the fitting distance
 
		if (GetTownRoadBits(TILE_ADD(tile, cur)) & DiagDirToRoadBits((pos & 2) ? dir : ReverseDiagDir(dir))) return true;
 
		if (IsValidTile(tile + TileXY(TileX(cur) / 2, TileY(cur) / 2)) && IsValidTile(tile + cur) && GetTownRoadBits(TILE_ADD(tile, cur)) & DiagDirToRoadBits((pos & 2) ? dir : ReverseDiagDir(dir))) return true;
 
	}
 
	return false;
 
}
 

	
 
/**
 
 * Check if a Road is allowed on a given tile
 
@@ -1132,12 +1132,14 @@ static void GrowTownInTile(TileIndex *ti
 
		/* This is the tile we will reach if we extend to this direction. */
 
		TileIndex house_tile = TileAddByDiagDir(tile, target_dir); // position of a possible house
 

	
 
		/* Don't walk into water. */
 
		if (IsWaterTile(house_tile)) return;
 

	
 
		if (!IsValidTile(house_tile) || !IsValidTile(house_tile + TileOffsByDiagDir(target_dir))) return;
 

	
 
		switch (t1->GetActiveLayout()) {
 
			default: NOT_REACHED();
 

	
 
			case TL_NO_ROADS:
 
				allow_house = true;
 
				break;
src/tunnel_map.cpp
Show inline comments
 
@@ -44,12 +44,13 @@ bool IsTunnelInWayDir(TileIndex tile, ui
 
{
 
	TileIndexDiff delta = TileOffsByDiagDir(dir);
 
	uint height;
 

	
 
	do {
 
		tile -= delta;
 
		if (!IsValidTile(tile)) return false;
 
		height = GetTileZ(tile);
 
	} while (z < height);
 

	
 
	return
 
		z == height &&
 
		IsTunnelTile(tile) &&
src/tunnelbridge_cmd.cpp
Show inline comments
 
@@ -524,12 +524,13 @@ CommandCost CmdBuildTunnel(TileIndex sta
 
	int tiles = 0;
 
	/** Number of tiles at which the cost increase coefficient per tile is halved */
 
	int tiles_bump = 25;
 

	
 
	for (;;) {
 
		end_tile += delta;
 
		if (!IsValidTile(end_tile)) return_cmd_error(STR_TUNNEL_THROUGH_MAP_BORDER);
 
		end_tileh = GetTileSlope(end_tile, &end_z);
 

	
 
		if (start_z == end_z) break;
 

	
 
		if (!_cheats.crossing_tunnels.value && IsTunnelInWayDir(end_tile, start_z, tunnel_in_way_dir)) {
 
			return_cmd_error(STR_5003_ANOTHER_TUNNEL_IN_THE_WAY);
src/unmovable_cmd.cpp
Show inline comments
 
@@ -364,28 +364,47 @@ static bool ClickTile_Unmovable(TileInde
 
}
 

	
 

	
 
/* checks, if a radio tower is within a 9x9 tile square around tile */
 
static bool IsRadioTowerNearby(TileIndex tile)
 
{
 
	TileIndex tile_s = tile - TileDiffXY(4, 4);
 
	TileIndex tile_s = tile - TileDiffXY(min(TileX(tile), 4U), min(TileY(tile), 4U));
 
	uint w = min(TileX(tile), 4U) + 1 + min(MapMaxX() - TileX(tile), 4U);
 
	uint h = min(TileY(tile), 4U) + 1 + min(MapMaxY() - TileY(tile), 4U);
 

	
 
	BEGIN_TILE_LOOP(tile, 9, 9, tile_s)
 
	BEGIN_TILE_LOOP(tile, w, h, tile_s)
 
		if (IsTransmitterTile(tile)) return true;
 
	END_TILE_LOOP(tile, 9, 9, tile_s)
 
	END_TILE_LOOP(tile, w, h, tile_s)
 

	
 
	return false;
 
}
 

	
 
void GenerateUnmovables()
 
{
 
	if (_settings_game.game_creation.landscape == LT_TOYLAND) return;
 

	
 
	/* add radio tower */
 
	int radiotowser_to_build = ScaleByMapSize(15); // maximum number of radio towers on the map
 
	int lighthouses_to_build = _settings_game.game_creation.landscape == LT_TROPIC ? 0 : ScaleByMapSize1D((Random() & 3) + 7);
 

	
 
	/* Scale the amount of lighthouses with the amount of land at the borders. */
 
	if (_settings_game.construction.freeform_edges) {
 
		uint num_water_tiles = 0;
 
		for (uint x = 0; x < MapMaxX(); x++) {
 
			if (IsTileType(TileXY(x, 1), MP_WATER)) num_water_tiles++;
 
			if (IsTileType(TileXY(x, MapMaxY() - 1), MP_WATER)) num_water_tiles++;
 
		}
 
		for (uint y = 1; y < MapMaxY() - 1; y++) {
 
			if (IsTileType(TileXY(1, y), MP_WATER)) num_water_tiles++;
 
			if (IsTileType(TileXY(MapMaxX() - 1, y), MP_WATER)) num_water_tiles++;
 
		}
 
		/* The -6 is because the top borders are MP_VOID (-2) and all corners
 
		 * are counted twice (-4). */
 
		lighthouses_to_build = lighthouses_to_build * num_water_tiles / (2 * MapMaxY() + 2 * MapMaxX() - 6);
 
	}
 

	
 
	SetGeneratingWorldProgress(GWP_UNMOVABLE, radiotowser_to_build + lighthouses_to_build);
 

	
 
	for (uint i = ScaleByMapSize(1000); i != 0; i--) {
 
		TileIndex tile = RandomTile();
 

	
 
		uint h;
 
@@ -413,19 +432,22 @@ void GenerateUnmovables()
 
			perimeter -= (DiagDirToAxis(dir) == AXIS_X) ? maxx : maxy;
 
		}
 

	
 
		TileIndex tile;
 
		switch (dir) {
 
			default:
 
			case DIAGDIR_NE: tile = TileXY(maxx,     r % maxy); break;
 
			case DIAGDIR_SE: tile = TileXY(r % maxx, 0);        break;
 
			case DIAGDIR_SW: tile = TileXY(0,        r % maxy); break;
 
			case DIAGDIR_NW: tile = TileXY(r % maxx, maxy);     break;
 
			case DIAGDIR_NE: tile = TileXY(maxx - 1, r % maxy); break;
 
			case DIAGDIR_SE: tile = TileXY(r % maxx, 1); break;
 
			case DIAGDIR_SW: tile = TileXY(1,        r % maxy); break;
 
			case DIAGDIR_NW: tile = TileXY(r % maxx, maxy - 1); break;
 
		}
 

	
 
		for (int j = 0; j < 20; j++) {
 
		/* Only build lighthouses at tiles where the border is sea. */
 
		if (!IsTileType(tile, MP_WATER)) continue;
 

	
 
		for (int j = 0; j < 19; j++) {
 
			uint h;
 
			if (IsTileType(tile, MP_CLEAR) && GetTileSlope(tile, &h) == SLOPE_FLAT && h <= TILE_HEIGHT * 2 && !IsBridgeAbove(tile)) {
 
				MakeLighthouse(tile);
 
				IncreaseGeneratingWorldProgress(GWP_UNMOVABLE);
 
				lighthouses_to_build--;
 
				assert(tile == TILE_MASK(tile));
src/viewport.cpp
Show inline comments
 
@@ -379,29 +379,32 @@ static Point TranslateXYToTileCoord(cons
 
	a = y - x;
 
	b = y + x;
 

	
 
	/* we need to move variables in to the valid range, as the
 
	 * GetTileZoomCenterWindow() function can call here with invalid x and/or y,
 
	 * when the user tries to zoom out along the sides of the map */
 
	a = Clamp(a, 0, (int)(MapMaxX() * TILE_SIZE) - 1);
 
	b = Clamp(b, 0, (int)(MapMaxY() * TILE_SIZE) - 1);
 
	a = Clamp(a, -4 * TILE_SIZE, (int)(MapMaxX() * TILE_SIZE) - 1);
 
	b = Clamp(b, -4 * TILE_SIZE, (int)(MapMaxY() * TILE_SIZE) - 1);
 

	
 
	/* (a, b) is the X/Y-world coordinate that belongs to (x,y) if the landscape would be completely flat on height 0.
 
	 * Now find the Z-world coordinate by fix point iteration.
 
	 * This is a bit tricky because the tile height is non-continuous at foundations.
 
	 * The clicked point should be approached from the back, otherwise there are regions that are not clickable.
 
	 * (FOUNDATION_HALFTILE_LOWER on SLOPE_STEEP_S hides north halftile completely)
 
	 * So give it a z-malus of 4 in the first iterations.
 
	 */
 
	z = 0;
 
	for (int i = 0; i < 5; i++) z = GetSlopeZ(a + max(z, 4u) - 4, b + max(z, 4u) - 4) / 2;
 
	for (uint malus = 3; malus > 0; malus--) z = GetSlopeZ(a + max(z, malus) - malus, b + max(z, malus) - malus) / 2;
 
	for (int i = 0; i < 5; i++) z = GetSlopeZ(a + z, b + z) / 2;
 

	
 
	pt.x = a + z;
 
	pt.y = b + z;
 

	
 
	int min_coord = _settings_game.construction.freeform_edges ? TILE_SIZE : 0;
 

	
 
	for (int i = 0; i < 5; i++) z = GetSlopeZ(Clamp(a + (int)max(z, 4u) - 4, min_coord, MapMaxX() * TILE_SIZE - 1), Clamp(b + (int)max(z, 4u) - 4, min_coord, MapMaxY() * TILE_SIZE - 1)) / 2;
 
	for (uint malus = 3; malus > 0; malus--) z = GetSlopeZ(Clamp(a + (int)max(z, malus) - (int)malus, min_coord, MapMaxX() * TILE_SIZE - 1), Clamp(b + (int)max(z, malus) - (int)malus, min_coord, MapMaxY() * TILE_SIZE - 1)) / 2;
 
	for (int i = 0; i < 5; i++) z = GetSlopeZ(Clamp(a + (int)z, min_coord, MapMaxX() * TILE_SIZE - 1), Clamp(b + (int)z, min_coord, MapMaxY() * TILE_SIZE - 1)) / 2;
 

	
 
	pt.x = Clamp(a + (int)z, min_coord, MapMaxX() * TILE_SIZE - 1);
 
	pt.y = Clamp(b + (int)z, min_coord, MapMaxY() * TILE_SIZE - 1);
 

	
 
	return pt;
 
}
 

	
 
/* When used for zooming, check area below current coordinates (x,y)
 
 * and return the tile of the zoomed out/in position (zoom_x, zoom_y)
 
@@ -966,41 +969,59 @@ static void ViewportAddLandscape()
 
	do {
 
		int width_cur = width;
 
		int x_cur = x;
 
		int y_cur = y;
 

	
 
		do {
 
			TileType tt;
 
			TileType tt = MP_VOID;
 

	
 
			ti.x = x_cur;
 
			ti.y = y_cur;
 
			if (0 <= x_cur && x_cur < (int)MapSizeX() * TILE_SIZE &&
 
					0 <= y_cur && y_cur < (int)MapSizeY() * TILE_SIZE) {
 

	
 
			ti.z = 0;
 

	
 
			ti.tileh = SLOPE_FLAT;
 
			ti.tile = INVALID_TILE;
 

	
 
			if (0 <= x_cur && x_cur < (int)MapMaxX() * TILE_SIZE &&
 
					0 <= y_cur && y_cur < (int)MapMaxY() * TILE_SIZE) {
 
				TileIndex tile = TileVirtXY(x_cur, y_cur);
 

	
 
				if (!_settings_game.construction.freeform_edges || (TileX(tile) != 0 && TileY(tile) != 0)) {
 
					if (x_cur == ((int)MapMaxX() - 1) * TILE_SIZE || y_cur == ((int)MapMaxY() - 1) * TILE_SIZE) {
 
						uint maxh = max<uint>(TileHeight(tile), 1);
 
						for (uint h = 0; h < maxh; h++) {
 
							DrawGroundSpriteAt(SPR_SHADOW_CELL, PAL_NONE, ti.x, ti.y, h * TILE_HEIGHT);
 
						}
 
					}
 

	
 
				ti.tile = tile;
 
				ti.tileh = GetTileSlope(tile, &ti.z);
 
				tt = GetTileType(tile);
 
			} else {
 
				ti.tileh = SLOPE_FLAT;
 
				ti.tile = INVALID_TILE;
 
				ti.z = 0;
 
				tt = MP_VOID;
 
			}
 

	
 
			y_cur += 0x10;
 
			x_cur -= 0x10;
 
			}
 

	
 
			_vd.foundation_part = FOUNDATION_PART_NONE;
 
			_vd.foundation[0] = -1;
 
			_vd.foundation[1] = -1;
 
			_vd.last_foundation_child[0] = NULL;
 
			_vd.last_foundation_child[1] = NULL;
 

	
 
			_tile_type_procs[tt]->draw_tile_proc(&ti);
 

	
 
			if ((x_cur == (int)MapMaxX() * TILE_SIZE && IsInsideMM(y_cur, 0, MapMaxY() * TILE_SIZE)) ||
 
				(y_cur == (int)MapMaxY() * TILE_SIZE && IsInsideMM(x_cur, 0, MapMaxX() * TILE_SIZE))) {
 
				TileIndex tile = TileVirtXY(x_cur, y_cur);
 
				ti.tile = tile;
 
				ti.tileh = GetTileSlope(tile, &ti.z);
 
				tt = GetTileType(tile);
 
			}
 
			if (ti.tile != INVALID_TILE) DrawTileSelection(&ti);
 

	
 
			y_cur += 0x10;
 
			x_cur -= 0x10;
 
		} while (--width_cur);
 

	
 
		if ((direction ^= 1) != 0) {
 
			y += 0x10;
 
		} else {
 
			x += 0x10;
src/water.h
Show inline comments
 
@@ -4,12 +4,13 @@
 

	
 
#ifndef WATER_H
 
#define WATER_H
 

	
 
void TileLoop_Water(TileIndex tile);
 
bool FloodHalftile(TileIndex t);
 
void DoFloodTile(TileIndex target);
 

	
 
void ConvertGroundTilesIntoWaterTiles();
 

	
 
void DrawShipDepotSprite(int x, int y, int image);
 
void DrawWaterClassGround(const struct TileInfo *ti);
 
void DrawShoreTile(Slope tileh);
src/water_cmd.cpp
Show inline comments
 
@@ -355,15 +355,15 @@ CommandCost CmdBuildCanal(TileIndex tile
 
static CommandCost ClearTile_Water(TileIndex tile, byte flags)
 
{
 
	switch (GetWaterTileType(tile)) {
 
		case WATER_TILE_CLEAR:
 
			if (flags & DC_NO_WATER) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
 

	
 
			/* Make sure it's not an edge tile. */
 
			if (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
 
					!IsInsideMM(TileY(tile), 1, MapMaxY() - 1)) {
 
			/* Make sure freeform edges are allowed or it's not an edge tile. */
 
			if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) ||
 
					!IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) {
 
				return_cmd_error(STR_0002_TOO_CLOSE_TO_EDGE_OF_MAP);
 
			}
 

	
 
			/* Make sure no vehicle is on the tile */
 
			if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
 

	
 
@@ -902,13 +902,13 @@ static FloodingBehaviour GetFloodingBeha
 
	}
 
}
 

	
 
/**
 
 * Floods a tile.
 
 */
 
static void DoFloodTile(TileIndex target)
 
void DoFloodTile(TileIndex target)
 
{
 
	assert(!IsTileType(target, MP_WATER));
 

	
 
	bool flooded = false; // Will be set to true if something is changed.
 

	
 
	_current_company = OWNER_WATER;
0 comments (0 inline, 0 general)