mirror of https://github.com/OpenTTD/OpenTTD
Feature: Add the ability to clone an area with structures
parent
fa82dd6096
commit
c39d3f6053
Binary file not shown.
|
@ -1 +1 @@
|
||||||
4f03553f614a06d86dc06376db3353c7
|
24445cdf8f7f93cfe1fa864252bda7b7
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -4,7 +4,7 @@
|
||||||
// See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
// See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
-1 * 0 0C "OpenTTD GUI graphics"
|
-1 * 0 0C "OpenTTD GUI graphics"
|
||||||
-1 * 3 05 15 \b 191 // OPENTTD_SPRITE_COUNT
|
-1 * 3 05 15 \b 195 // OPENTTD_SPRITE_COUNT
|
||||||
-1 sprites/openttdgui.png 8bpp 66 8 64 31 -31 7 normal
|
-1 sprites/openttdgui.png 8bpp 66 8 64 31 -31 7 normal
|
||||||
-1 sprites/openttdgui.png 8bpp 146 8 64 31 -31 7 normal
|
-1 sprites/openttdgui.png 8bpp 146 8 64 31 -31 7 normal
|
||||||
-1 sprites/openttdgui.png 8bpp 226 8 64 31 -31 7 normal
|
-1 sprites/openttdgui.png 8bpp 226 8 64 31 -31 7 normal
|
||||||
|
@ -196,3 +196,7 @@
|
||||||
-1 sprites/openttdgui.png 8bpp 567 440 12 10 0 0 normal
|
-1 sprites/openttdgui.png 8bpp 567 440 12 10 0 0 normal
|
||||||
-1 sprites/openttdgui.png 8bpp 581 440 10 10 0 0 normal
|
-1 sprites/openttdgui.png 8bpp 581 440 10 10 0 0 normal
|
||||||
-1 sprites/openttdgui.png 8bpp 593 440 10 10 0 0 normal
|
-1 sprites/openttdgui.png 8bpp 593 440 10 10 0 0 normal
|
||||||
|
-1 sprites/clone_area.png 8bpp 3 9 20 20 0 0 normal
|
||||||
|
-1 sprites/clone_area.png 8bpp 35 9 20 20 0 0 normal
|
||||||
|
-1 sprites/clone_area.png 8bpp 67 9 32 32 0 0 normal
|
||||||
|
-1 sprites/clone_area.png 8bpp 115 9 32 32 0 0 normal
|
||||||
|
|
|
@ -94,6 +94,8 @@ add_files(
|
||||||
clear_cmd.cpp
|
clear_cmd.cpp
|
||||||
clear_func.h
|
clear_func.h
|
||||||
clear_map.h
|
clear_map.h
|
||||||
|
clone_area_cmd.cpp
|
||||||
|
clone_area_cmd.h
|
||||||
command.cpp
|
command.cpp
|
||||||
command_func.h
|
command_func.h
|
||||||
command_type.h
|
command_type.h
|
||||||
|
|
|
@ -0,0 +1,533 @@
|
||||||
|
/*
|
||||||
|
* This file is part of OpenTTD.
|
||||||
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||||
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file clone_area_cmd.cpp Commands related to clone area. */
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "command_func.h"
|
||||||
|
#include "viewport_func.h"
|
||||||
|
#include "company_base.h"
|
||||||
|
#include "clone_area_cmd.h"
|
||||||
|
#include "newgrf_station.h"
|
||||||
|
#include "safeguards.h"
|
||||||
|
#include "road.h"
|
||||||
|
#include "road_internal.h"
|
||||||
|
#include "depot_base.h"
|
||||||
|
#include "tunnelbridge_map.h"
|
||||||
|
#include "sound_func.h"
|
||||||
|
#include "rail_cmd.h"
|
||||||
|
#include "tunnelbridge_cmd.h"
|
||||||
|
#include "station_cmd.h"
|
||||||
|
#include "terraform_cmd.h"
|
||||||
|
|
||||||
|
TileIndex selected_tile;
|
||||||
|
TileIndex selected_start_tile;
|
||||||
|
bool selected_diagonal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate by an angle using the formula for rotating a point on a plane.
|
||||||
|
*
|
||||||
|
* @param point Rotating point.
|
||||||
|
* @param angle Rotate an angle.
|
||||||
|
*/
|
||||||
|
TileIndexDiffC Rotate(TileIndexDiffC point, DiagDirDiff angle) {
|
||||||
|
switch (angle) {
|
||||||
|
case DIAGDIRDIFF_90LEFT: return {int16_t(-point.y), point.x};
|
||||||
|
case DIAGDIRDIFF_REVERSE: return {int16_t(-point.x), int16_t(-point.y)};
|
||||||
|
case DIAGDIRDIFF_90RIGHT: return {point.y, int16_t(-point.x)};
|
||||||
|
default: return point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusting the position of the rotated point, since the tile has four corners.
|
||||||
|
*
|
||||||
|
* @param rotated Rotated point setting.
|
||||||
|
* @param angle Angle of rotation.
|
||||||
|
*/
|
||||||
|
TileIndexDiffC FixAfterRotate(TileIndexDiffC rotated, DiagDirDiff angle) {
|
||||||
|
switch (angle) {
|
||||||
|
case DIAGDIRDIFF_90LEFT:
|
||||||
|
rotated.x -= 1;
|
||||||
|
break;
|
||||||
|
case DIAGDIRDIFF_REVERSE:
|
||||||
|
rotated.x -= 1;
|
||||||
|
rotated.y -= 1;
|
||||||
|
break;
|
||||||
|
case DIAGDIRDIFF_90RIGHT:
|
||||||
|
rotated.y -= 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return rotated;
|
||||||
|
}
|
||||||
|
return rotated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate Track by an angle using the formula for rotating a point on a plane.
|
||||||
|
*
|
||||||
|
* @param track Rotating track.
|
||||||
|
* @param angle Rotate an angle.
|
||||||
|
*/
|
||||||
|
Track Rotate(Track track, DiagDirDiff angle) {
|
||||||
|
switch (angle) {
|
||||||
|
case DIAGDIRDIFF_90LEFT:
|
||||||
|
if (track == TRACK_X || track == TRACK_Y) {
|
||||||
|
return TrackToOppositeTrack(track);
|
||||||
|
}
|
||||||
|
switch (track) {
|
||||||
|
case TRACK_UPPER: return TRACK_LEFT;
|
||||||
|
case TRACK_LOWER: return TRACK_RIGHT;
|
||||||
|
case TRACK_LEFT: return TRACK_LOWER;
|
||||||
|
case TRACK_RIGHT: return TRACK_UPPER;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DIAGDIRDIFF_REVERSE:
|
||||||
|
if (track != TRACK_X && track != TRACK_Y) {
|
||||||
|
return TrackToOppositeTrack(track);
|
||||||
|
}
|
||||||
|
return track;
|
||||||
|
break;
|
||||||
|
case DIAGDIRDIFF_90RIGHT:
|
||||||
|
if (track == TRACK_X || track == TRACK_Y) {
|
||||||
|
return TrackToOppositeTrack(track);
|
||||||
|
}
|
||||||
|
switch (track) {
|
||||||
|
case TRACK_UPPER: return TRACK_RIGHT;
|
||||||
|
case TRACK_LOWER: return TRACK_LEFT;
|
||||||
|
case TRACK_LEFT: return TRACK_UPPER;
|
||||||
|
case TRACK_RIGHT: return TRACK_LOWER;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return track;
|
||||||
|
}
|
||||||
|
return track;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate DiagDirection by an angle using the formula for rotating a point on a plane.
|
||||||
|
*
|
||||||
|
* @param dir Rotating DiagDirection.
|
||||||
|
* @param angle Rotate an angle.
|
||||||
|
*/
|
||||||
|
DiagDirection Rotate(DiagDirection dir, DiagDirDiff angle) {
|
||||||
|
switch (angle) {
|
||||||
|
case DIAGDIRDIFF_90LEFT:
|
||||||
|
dir = (DiagDirection)(dir - 1);
|
||||||
|
if (dir == INVALID_DIAGDIR) {
|
||||||
|
dir = DIAGDIR_NW;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DIAGDIRDIFF_REVERSE:
|
||||||
|
dir = (DiagDirection)(dir ^ 2);
|
||||||
|
break;
|
||||||
|
case DIAGDIRDIFF_90RIGHT:
|
||||||
|
dir = (DiagDirection)(dir + 1);
|
||||||
|
if (dir == DIAGDIR_END) {
|
||||||
|
dir = DIAGDIR_NE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotate Axis by an angle using the formula for rotating a point on a plane.
|
||||||
|
*
|
||||||
|
* @param axis Rotating axis.
|
||||||
|
* @param angle Rotate an angle.
|
||||||
|
*/
|
||||||
|
Axis Rotate(Axis axis, DiagDirDiff angle) {
|
||||||
|
if (angle == DIAGDIRDIFF_90LEFT || angle == DIAGDIRDIFF_90RIGHT) {
|
||||||
|
return (Axis)(axis ^ 1);
|
||||||
|
}
|
||||||
|
return axis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finding an angle using the formula for the angle between two straight lines
|
||||||
|
*
|
||||||
|
* @param first First line vector.
|
||||||
|
* @param second Second line vector.
|
||||||
|
*/
|
||||||
|
DiagDirDiff AngleBetweenTwoLines(TileIndexDiffC first, TileIndexDiffC second) {
|
||||||
|
if (second.x == 0 && second.y == 0) {
|
||||||
|
return DIAGDIRDIFF_SAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
first.x = first.x > 0 ? 1 : -1;
|
||||||
|
first.y = first.y > 0 ? 1 : -1;
|
||||||
|
second.x = second.x > 0 ? 1 : -1;
|
||||||
|
second.y = second.y > 0 ? 1 : -1;
|
||||||
|
|
||||||
|
int16_t value = first.x * second.x + first.y * second.y;
|
||||||
|
if (value > 0) {
|
||||||
|
return DIAGDIRDIFF_SAME;
|
||||||
|
} else if (value < 0) {
|
||||||
|
return DIAGDIRDIFF_REVERSE;
|
||||||
|
}
|
||||||
|
TileIndexDiffC third = Rotate(first, DIAGDIRDIFF_90LEFT);
|
||||||
|
|
||||||
|
value = third.x * second.x + third.y * second.y;
|
||||||
|
if (value > 0) {
|
||||||
|
return DIAGDIRDIFF_90LEFT;
|
||||||
|
}
|
||||||
|
return DIAGDIRDIFF_90RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command callback. If the region cannot be inserted, an error message will be displayed.
|
||||||
|
* @param result Result of the command.
|
||||||
|
* @param tile Tile where the industry is placed.
|
||||||
|
*/
|
||||||
|
void CcCloneArea(Commands, const CommandCost &result, Money, TileIndex tile)
|
||||||
|
{
|
||||||
|
if (result.Succeeded()) {
|
||||||
|
if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER, tile);
|
||||||
|
} else {
|
||||||
|
SetRedErrorSquare(tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark the selected area on the map to copy
|
||||||
|
* @param flags for this command type
|
||||||
|
* @param tile end tile of area-drag
|
||||||
|
* @param start_tile start tile of area drag
|
||||||
|
* @param diagonal Whether to use the Orthogonal (false) or Diagonal (true) iterator.
|
||||||
|
* @return the cost of this operation or an error
|
||||||
|
*/
|
||||||
|
std::tuple<CommandCost, Money, TileIndex> CmdCloneAreaCopy([[maybe_unused]] DoCommandFlag flags, TileIndex tile, TileIndex start_tile, bool diagonal)
|
||||||
|
{
|
||||||
|
if (start_tile >= Map::Size()) return { CMD_ERROR, 0, INVALID_TILE };
|
||||||
|
|
||||||
|
selected_tile = tile;
|
||||||
|
selected_start_tile = start_tile;
|
||||||
|
selected_diagonal = diagonal;
|
||||||
|
|
||||||
|
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||||
|
return { cost, 0, tile };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paste the selected area on the map
|
||||||
|
* @param flags for this command type
|
||||||
|
* @param tile end tile of area-drag
|
||||||
|
* @param start_tile start tile of area drag
|
||||||
|
* @param diagonal Whether to use the Orthogonal (false) or Diagonal (true) iterator.
|
||||||
|
* @return the cost of this operation or an error
|
||||||
|
*/
|
||||||
|
std::tuple<CommandCost, Money, TileIndex> CmdCloneAreaPaste(DoCommandFlag flags, TileIndex tile, TileIndex start_tile, bool diagonal)
|
||||||
|
{
|
||||||
|
if (start_tile >= Map::Size()) return { CMD_ERROR, 0, INVALID_TILE };
|
||||||
|
|
||||||
|
Money money = GetAvailableMoneyForCommand();
|
||||||
|
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||||
|
CommandCost last_error(STR_ERROR_ALREADY_BUILT);
|
||||||
|
bool had_success = false;
|
||||||
|
bool terraform_problem = false;
|
||||||
|
TileIndex terraform_problem_tile = INVALID_TILE;
|
||||||
|
CommandCost terraform_error(STR_ERROR_ALREADY_BUILT);
|
||||||
|
|
||||||
|
const Company *c = Company::GetIfValid(_current_company);
|
||||||
|
int limit = (c == nullptr ? INT32_MAX : GB(c->terraform_limit, 16, 16));
|
||||||
|
if (limit == 0) return { CommandCost(STR_ERROR_TERRAFORM_LIMIT_REACHED), 0, INVALID_TILE };
|
||||||
|
|
||||||
|
TileIndexDiffC origin_direction = TileIndexToTileIndexDiffC(selected_start_tile, selected_tile);
|
||||||
|
TileIndexDiffC dest_direction = TileIndexToTileIndexDiffC(start_tile, tile);
|
||||||
|
DiagDirDiff angle = AngleBetweenTwoLines(origin_direction, dest_direction);
|
||||||
|
|
||||||
|
int16_t position_selected_tile_x = TileX(selected_start_tile);
|
||||||
|
int16_t position_selected_tile_y = TileY(selected_start_tile);
|
||||||
|
int16_t dest_position_x = TileX(start_tile);
|
||||||
|
int16_t dest_position_y = TileY(start_tile);
|
||||||
|
uint origin_main_height = TileHeight(selected_start_tile);
|
||||||
|
uint dest_main_height = TileHeight(start_tile);
|
||||||
|
uint difference_height = dest_main_height - origin_main_height;
|
||||||
|
|
||||||
|
TileIndexDiffC dest_point;
|
||||||
|
|
||||||
|
TileIndex error_tile = INVALID_TILE;
|
||||||
|
std::unique_ptr<TileIterator> iter = TileIterator::Create(selected_start_tile, selected_tile, selected_diagonal);
|
||||||
|
for (; *iter != INVALID_TILE; ++(*iter)) {
|
||||||
|
TileIndex iter_tile = *iter;
|
||||||
|
|
||||||
|
dest_point.x = TileX(iter_tile) - position_selected_tile_x;
|
||||||
|
dest_point.y = TileY(iter_tile) - position_selected_tile_y;
|
||||||
|
dest_point = Rotate(dest_point, angle);
|
||||||
|
dest_point.x += dest_position_x;
|
||||||
|
dest_point.y += dest_position_y;
|
||||||
|
|
||||||
|
TileIndex dest_tile = TileXY(dest_point.x, dest_point.y);
|
||||||
|
|
||||||
|
uint origin_height = TileHeight(iter_tile) + difference_height;
|
||||||
|
uint dest_height = TileHeight(dest_tile);
|
||||||
|
|
||||||
|
while (dest_height != origin_height) {
|
||||||
|
CommandCost ret;
|
||||||
|
std::tie(ret, std::ignore, error_tile) = Command<CMD_TERRAFORM_LAND>::Do(flags & ~DC_EXEC, dest_tile, SLOPE_N, dest_height <= origin_height);
|
||||||
|
if (ret.Failed()) {
|
||||||
|
last_error = ret;
|
||||||
|
|
||||||
|
if (!terraform_problem) {
|
||||||
|
terraform_problem_tile = error_tile;
|
||||||
|
terraform_error = last_error;
|
||||||
|
terraform_problem = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Did we reach the limit? */
|
||||||
|
if (ret.GetErrorMessage() == STR_ERROR_TERRAFORM_LIMIT_REACHED) limit = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
|
money -= ret.GetCost();
|
||||||
|
if (money < 0) {
|
||||||
|
return { cost, ret.GetCost(), error_tile };
|
||||||
|
}
|
||||||
|
Command<CMD_TERRAFORM_LAND>::Do(flags, dest_tile, SLOPE_N, dest_height <= origin_height);
|
||||||
|
} else {
|
||||||
|
/* When we're at the terraform limit we better bail (unneeded) testing as well.
|
||||||
|
* This will probably cause the terraforming cost to be underestimated, but only
|
||||||
|
* when it's near the terraforming limit. Even then, the estimation is
|
||||||
|
* completely off due to it basically counting terraforming double, so it being
|
||||||
|
* cut off earlier might even give a better estimate in some cases. */
|
||||||
|
if (--limit <= 0) {
|
||||||
|
had_success = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cost.AddCost(ret);
|
||||||
|
dest_height += (dest_height > origin_height) ? -1 : 1;
|
||||||
|
had_success = true;
|
||||||
|
}
|
||||||
|
if (limit <= 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (terraform_problem) {
|
||||||
|
return { terraform_error, 0, terraform_problem_tile };
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandCost ret;
|
||||||
|
std::tie(ret, std::ignore, error_tile) = CmdCloneAreaPasteProperty(flags, tile, start_tile, diagonal);
|
||||||
|
if (ret.Failed()) {
|
||||||
|
last_error = ret;
|
||||||
|
} else {
|
||||||
|
had_success = true;
|
||||||
|
}
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
|
money -= ret.GetCost();
|
||||||
|
if (money < 0) {
|
||||||
|
return { cost, ret.GetCost(), error_tile };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandCost cc_ret = had_success ? cost : last_error;
|
||||||
|
return { cc_ret, 0, cc_ret.Succeeded() ? tile : error_tile };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert structures into the selected area on the map.
|
||||||
|
* @param flags operation to perform
|
||||||
|
* @param tile end tile of rail conversion drag
|
||||||
|
* @param area_start start tile of drag
|
||||||
|
* @param diagonal build diagonally or not.
|
||||||
|
* @return the cost of this operation or an error
|
||||||
|
*/
|
||||||
|
std::tuple<CommandCost, Money, TileIndex> CmdCloneAreaPasteProperty(DoCommandFlag flags, TileIndex tile, TileIndex area_start, [[maybe_unused]] bool diagonal)
|
||||||
|
{
|
||||||
|
if (area_start >= Map::Size()) return { CMD_ERROR, 0, INVALID_TILE };
|
||||||
|
|
||||||
|
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||||
|
CommandCost last_error(INVALID_STRING_ID);
|
||||||
|
bool had_success = false;
|
||||||
|
bool auto_remove_signals = true;
|
||||||
|
bool signals_copy = true;
|
||||||
|
CommandCost error = CommandCost(STR_ERROR_CAN_T_BUILD_HERE);
|
||||||
|
|
||||||
|
TileIndexDiffC origin_direction = TileIndexToTileIndexDiffC(selected_start_tile, selected_tile);
|
||||||
|
TileIndexDiffC dest_direction = TileIndexToTileIndexDiffC(area_start, tile);
|
||||||
|
|
||||||
|
DiagDirDiff angle = AngleBetweenTwoLines(origin_direction, dest_direction);
|
||||||
|
uint position_selected_tile_x = TileX(selected_start_tile);
|
||||||
|
uint position_selected_tile_y = TileY(selected_start_tile);
|
||||||
|
int16_t dest_position_x = TileX(area_start);
|
||||||
|
int16_t dest_position_y = TileY(area_start);
|
||||||
|
|
||||||
|
TileIndexDiffC dest_point;
|
||||||
|
TileIndex iter_tile;
|
||||||
|
TileIndex error_tile = INVALID_TILE;
|
||||||
|
|
||||||
|
uint x_max = std::max(position_selected_tile_x, TileX(selected_tile)) - 1;
|
||||||
|
uint y_max = std::max(position_selected_tile_y, TileY(selected_tile)) - 1;
|
||||||
|
|
||||||
|
std::map<StationID, StationID> station_map;
|
||||||
|
std::unique_ptr<TileIterator> iter = TileIterator::Create(selected_start_tile, selected_tile, selected_diagonal);
|
||||||
|
for (; (iter_tile = *iter) != INVALID_TILE; ++(*iter)) {
|
||||||
|
if (TileX(iter_tile) > x_max || TileY(iter_tile) > y_max) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TileType iter_tile_type = GetTileType(iter_tile);
|
||||||
|
switch (iter_tile_type) {
|
||||||
|
case MP_RAILWAY:
|
||||||
|
break;
|
||||||
|
case MP_STATION:
|
||||||
|
if (!HasStationRail(iter_tile)) continue;
|
||||||
|
break;
|
||||||
|
case MP_ROAD:
|
||||||
|
if (!IsLevelCrossing(iter_tile)) continue;
|
||||||
|
break;
|
||||||
|
case MP_TUNNELBRIDGE:
|
||||||
|
if (GetTunnelBridgeTransportType(iter_tile) != TRANSPORT_RAIL) continue;
|
||||||
|
break;
|
||||||
|
default: continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest_point.x = TileX(iter_tile) - position_selected_tile_x;
|
||||||
|
dest_point.y = TileY(iter_tile) - position_selected_tile_y;
|
||||||
|
dest_point = Rotate(dest_point, angle);
|
||||||
|
dest_point = FixAfterRotate(dest_point, angle);
|
||||||
|
dest_point.x += dest_position_x;
|
||||||
|
dest_point.y += dest_position_y;
|
||||||
|
TileIndex dest_tile = TileXY(dest_point.x, dest_point.y);
|
||||||
|
|
||||||
|
CommandCost ret = CheckTileOwnership(iter_tile);
|
||||||
|
if (ret.Failed()) {
|
||||||
|
error = ret;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RailType railtype2;
|
||||||
|
DiagDirection entrance_dir;
|
||||||
|
if (iter_tile_type == MP_RAILWAY) {
|
||||||
|
switch (GetRailTileType(iter_tile)) {
|
||||||
|
case RAIL_TILE_DEPOT:
|
||||||
|
railtype2 = GetRailType(iter_tile);
|
||||||
|
entrance_dir = GetRailDepotDirection(iter_tile);
|
||||||
|
entrance_dir = Rotate(entrance_dir, angle);
|
||||||
|
ret = Command<CMD_BUILD_TRAIN_DEPOT>::Do(flags, dest_tile, railtype2, entrance_dir);
|
||||||
|
if (ret.Failed()) {
|
||||||
|
last_error = ret;
|
||||||
|
} else {
|
||||||
|
had_success = true;
|
||||||
|
cost.AddCost(ret);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: // RAIL_TILE_NORMAL, RAIL_TILE_SIGNALS
|
||||||
|
RailType rail_type = GetRailType(iter_tile);
|
||||||
|
TrackBits trackBits = GetTrackBits(iter_tile);
|
||||||
|
Track track;
|
||||||
|
while ((track = RemoveFirstTrack(&trackBits)) != INVALID_TRACK) {
|
||||||
|
Track track_dest = Rotate(track, angle);
|
||||||
|
ret = Command<CMD_BUILD_SINGLE_RAIL>::Do(flags, dest_tile, rail_type, track_dest, auto_remove_signals);
|
||||||
|
if (ret.Failed()) {
|
||||||
|
last_error = ret;
|
||||||
|
} else {
|
||||||
|
had_success = true;
|
||||||
|
cost.AddCost(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signals_copy) {
|
||||||
|
if (HasSignalOnTrack(iter_tile, track)) {
|
||||||
|
SignalType sigtype = GetSignalType(iter_tile, track);
|
||||||
|
SignalVariant sigvar = GetSignalVariant(iter_tile, track);
|
||||||
|
ret = Command<CMD_BUILD_SINGLE_SIGNAL>::Do(flags, dest_tile, track_dest, sigtype, sigvar, false, false, false, SIGTYPE_BLOCK, SIGTYPE_BLOCK, 0, 0);
|
||||||
|
if (ret.Failed()) {
|
||||||
|
last_error = ret;
|
||||||
|
} else {
|
||||||
|
had_success = true;
|
||||||
|
cost.AddCost(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iter_tile_type == MP_TUNNELBRIDGE) {
|
||||||
|
if (IsTunnel(iter_tile)) {
|
||||||
|
RailType rail_type = GetRailType(iter_tile);
|
||||||
|
ret = Command<CMD_BUILD_TUNNEL>::Do(flags, dest_tile, TRANSPORT_RAIL, rail_type);
|
||||||
|
if (ret.Failed()) {
|
||||||
|
last_error = ret;
|
||||||
|
} else {
|
||||||
|
had_success = true;
|
||||||
|
cost.AddCost(ret);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
RailType rail_type = GetRailType(iter_tile);
|
||||||
|
BridgeType type = GetBridgeType(iter_tile);
|
||||||
|
TileIndex endIterTile = GetOtherTunnelBridgeEnd(iter_tile);
|
||||||
|
|
||||||
|
TileIndexDiffC end_dest_point;
|
||||||
|
end_dest_point.x = TileX(endIterTile) - position_selected_tile_x;
|
||||||
|
end_dest_point.y = TileY(endIterTile) - position_selected_tile_y;
|
||||||
|
end_dest_point = Rotate(end_dest_point, angle);
|
||||||
|
end_dest_point = FixAfterRotate(end_dest_point, angle);
|
||||||
|
end_dest_point.x += dest_position_x;
|
||||||
|
end_dest_point.y += dest_position_y;
|
||||||
|
TileIndex end_dest_tile = TileXY(end_dest_point.x, end_dest_point.y);
|
||||||
|
|
||||||
|
ret = Command<CMD_BUILD_BRIDGE>::Do(flags, end_dest_tile, dest_tile, TRANSPORT_RAIL, type, rail_type);
|
||||||
|
if (ret.Failed()) {
|
||||||
|
last_error = ret;
|
||||||
|
} else {
|
||||||
|
had_success = true;
|
||||||
|
cost.AddCost(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iter_tile_type == MP_STATION) {
|
||||||
|
if (HasStationRail(iter_tile)) {
|
||||||
|
RailType rail_type = GetRailType(iter_tile);
|
||||||
|
StationID origin_station_id = GetStationIndex(iter_tile);
|
||||||
|
StationID dest_station_id;
|
||||||
|
if (station_map.contains(origin_station_id)) {
|
||||||
|
dest_station_id = station_map[origin_station_id];
|
||||||
|
} else {
|
||||||
|
dest_station_id = NEW_STATION;
|
||||||
|
}
|
||||||
|
Axis origin_axis = GetRailStationAxis(iter_tile);
|
||||||
|
Axis dest_axis = Rotate(origin_axis, angle);
|
||||||
|
ret = Command<CMD_BUILD_RAIL_STATION>::Do(flags, dest_tile, rail_type, dest_axis, 1, 1, STAT_CLASS_DFLT, STATION_RAIL, dest_station_id, false);
|
||||||
|
if (ret.Failed()) {
|
||||||
|
last_error = ret;
|
||||||
|
} else {
|
||||||
|
had_success = true;
|
||||||
|
cost.AddCost(ret);
|
||||||
|
if (flags & DC_EXEC) {
|
||||||
|
if (dest_station_id == NEW_STATION) {
|
||||||
|
dest_station_id = GetStationIndex(dest_tile);
|
||||||
|
station_map[origin_station_id] = dest_station_id;
|
||||||
|
}
|
||||||
|
StationGfx station_gfx = GetStationGfx(iter_tile);
|
||||||
|
if (origin_axis != dest_axis) {
|
||||||
|
ToggleBit(station_gfx, 0);
|
||||||
|
}
|
||||||
|
if (angle == DIAGDIRDIFF_90RIGHT || angle == DIAGDIRDIFF_REVERSE) {
|
||||||
|
ToggleBit(station_gfx, 1);
|
||||||
|
}
|
||||||
|
SetStationGfx(dest_tile, station_gfx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandCost cc_ret = had_success ? cost : last_error;
|
||||||
|
return { cc_ret, 0, cc_ret.Succeeded() ? tile : error_tile };
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* This file is part of OpenTTD.
|
||||||
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||||
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file clone_area_cmd.h Command definitions related to cloning area. */
|
||||||
|
|
||||||
|
#ifndef CLONE_AREA_CMD_H
|
||||||
|
#define CLONE_AREA_CMD_H
|
||||||
|
std::tuple<CommandCost, Money, TileIndex> CmdCloneAreaCopy(DoCommandFlag flags, TileIndex tile, TileIndex start_tile, bool diagonal);
|
||||||
|
std::tuple<CommandCost, Money, TileIndex> CmdCloneAreaPaste(DoCommandFlag flags, TileIndex tile, TileIndex start_tile, bool diagonal);
|
||||||
|
std::tuple<CommandCost, Money, TileIndex> CmdCloneAreaPasteProperty(DoCommandFlag flags, TileIndex tile, TileIndex area_start, bool diagonal);
|
||||||
|
|
||||||
|
DEF_CMD_TRAIT(CMD_CLONE_AREA_COPY, CmdCloneAreaCopy, CMD_NO_TEST, CMDT_LANDSCAPE_CONSTRUCTION)
|
||||||
|
DEF_CMD_TRAIT(CMD_CLONE_AREA_PASTE, CmdCloneAreaPaste, CMD_ALL_TILES | CMD_AUTO | CMD_NO_TEST, CMDT_LANDSCAPE_CONSTRUCTION)
|
||||||
|
|
||||||
|
void CcCloneArea(Commands cmd, const CommandCost &result, Money, TileIndex tile);
|
||||||
|
|
||||||
|
#endif /* CLONE_AREA_CMD_H */
|
|
@ -58,6 +58,7 @@
|
||||||
#include "waypoint_cmd.h"
|
#include "waypoint_cmd.h"
|
||||||
#include "misc/endian_buffer.hpp"
|
#include "misc/endian_buffer.hpp"
|
||||||
#include "string_func.h"
|
#include "string_func.h"
|
||||||
|
#include "clone_area_cmd.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
|
|
|
@ -317,6 +317,8 @@ enum Commands : uint16_t {
|
||||||
CMD_STORY_PAGE_BUTTON, ///< selection via story page button
|
CMD_STORY_PAGE_BUTTON, ///< selection via story page button
|
||||||
|
|
||||||
CMD_LEVEL_LAND, ///< level land
|
CMD_LEVEL_LAND, ///< level land
|
||||||
|
CMD_CLONE_AREA_COPY, ///< Clone land
|
||||||
|
CMD_CLONE_AREA_PASTE, ///< Clone land
|
||||||
|
|
||||||
CMD_BUILD_LOCK, ///< build a lock
|
CMD_BUILD_LOCK, ///< build a lock
|
||||||
|
|
||||||
|
|
|
@ -2966,6 +2966,8 @@ STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND :{BLACK}Lower a
|
||||||
STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}Raise a corner of land. Click+Drag to raise the first selected corner and level the selected area to the new corner height. Ctrl+Click+Drag to select the area diagonally. Also press Shift to show cost estimate only
|
STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}Raise a corner of land. Click+Drag to raise the first selected corner and level the selected area to the new corner height. Ctrl+Click+Drag to select the area diagonally. Also press Shift to show cost estimate only
|
||||||
STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Level an area of land to the height of the first selected corner. Ctrl+Click+Drag to select the area diagonally. Also press Shift to show cost estimate only
|
STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Level an area of land to the height of the first selected corner. Ctrl+Click+Drag to select the area diagonally. Also press Shift to show cost estimate only
|
||||||
STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Purchase land for future use. Ctrl+Click+Drag to select the area diagonally. Also press Shift to show cost estimate only
|
STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Purchase land for future use. Ctrl+Click+Drag to select the area diagonally. Also press Shift to show cost estimate only
|
||||||
|
STR_LANDSCAPING_TOOLTIP_CLONE_AREA_COPY :{BLACK}Copy Area
|
||||||
|
STR_LANDSCAPING_TOOLTIP_CLONE_AREA_PASTE :{BLACK}Paste Area
|
||||||
|
|
||||||
# Object construction window
|
# Object construction window
|
||||||
STR_OBJECT_BUILD_CAPTION :{WHITE}Object Selection
|
STR_OBJECT_BUILD_CAPTION :{WHITE}Object Selection
|
||||||
|
@ -4971,6 +4973,8 @@ STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... tree
|
||||||
STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}Name must be unique
|
STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}Name must be unique
|
||||||
STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} in the way
|
STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} in the way
|
||||||
STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}Not allowed while paused
|
STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}Not allowed while paused
|
||||||
|
STR_ERROR_CAN_T_CLONE_AREA_COPY :{WHITE}Can't Copy this area...
|
||||||
|
STR_ERROR_CAN_T_CLONE_AREA_PASTE :{WHITE}Can't Paste this area...
|
||||||
|
|
||||||
# Local authority errors
|
# Local authority errors
|
||||||
STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS :{WHITE}{TOWN} local authority refuses to allow this
|
STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS :{WHITE}{TOWN} local authority refuses to allow this
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "../story_cmd.h"
|
#include "../story_cmd.h"
|
||||||
#include "../subsidy_cmd.h"
|
#include "../subsidy_cmd.h"
|
||||||
#include "../terraform_cmd.h"
|
#include "../terraform_cmd.h"
|
||||||
|
#include "../clone_area_cmd.h"
|
||||||
#include "../timetable_cmd.h"
|
#include "../timetable_cmd.h"
|
||||||
#include "../town_cmd.h"
|
#include "../town_cmd.h"
|
||||||
#include "../train_cmd.h"
|
#include "../train_cmd.h"
|
||||||
|
@ -74,6 +75,7 @@ static constexpr auto _callback_tuple = std::make_tuple(
|
||||||
&CcPlaySound_CONSTRUCTION_RAIL,
|
&CcPlaySound_CONSTRUCTION_RAIL,
|
||||||
&CcStation,
|
&CcStation,
|
||||||
&CcTerraform,
|
&CcTerraform,
|
||||||
|
&CcCloneArea,
|
||||||
&CcAI,
|
&CcAI,
|
||||||
&CcCloneVehicle,
|
&CcCloneVehicle,
|
||||||
&CcCreateGroup,
|
&CcCreateGroup,
|
||||||
|
|
|
@ -140,6 +140,8 @@ public:
|
||||||
SPBC_RAISELAND = ::SPBC_RAISELAND,
|
SPBC_RAISELAND = ::SPBC_RAISELAND,
|
||||||
SPBC_PICKSTATION = ::SPBC_PICKSTATION,
|
SPBC_PICKSTATION = ::SPBC_PICKSTATION,
|
||||||
SPBC_BUILDSIGNALS = ::SPBC_BUILDSIGNALS,
|
SPBC_BUILDSIGNALS = ::SPBC_BUILDSIGNALS,
|
||||||
|
SPBC_CLONE_AREA_COPY = ::SPBC_CLONE_AREA_COPY,
|
||||||
|
SPBC_CLONE_AREA_PASTE = ::SPBC_CLONE_AREA_PASTE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -98,6 +98,8 @@ enum StoryPageButtonCursor : uint8_t {
|
||||||
SPBC_CLONE_ROADVEH,
|
SPBC_CLONE_ROADVEH,
|
||||||
SPBC_CLONE_SHIP,
|
SPBC_CLONE_SHIP,
|
||||||
SPBC_CLONE_AIRPLANE,
|
SPBC_CLONE_AIRPLANE,
|
||||||
|
SPBC_CLONE_AREA_COPY,
|
||||||
|
SPBC_CLONE_AREA_PASTE,
|
||||||
SPBC_DEMOLISH,
|
SPBC_DEMOLISH,
|
||||||
SPBC_LOWERLAND,
|
SPBC_LOWERLAND,
|
||||||
SPBC_RAISELAND,
|
SPBC_RAISELAND,
|
||||||
|
|
|
@ -1033,6 +1033,8 @@ static CursorID TranslateStoryPageButtonCursor(StoryPageButtonCursor cursor)
|
||||||
case SPBC_CLONE_ROADVEH: return SPR_CURSOR_CLONE_ROADVEH;
|
case SPBC_CLONE_ROADVEH: return SPR_CURSOR_CLONE_ROADVEH;
|
||||||
case SPBC_CLONE_SHIP: return SPR_CURSOR_CLONE_SHIP;
|
case SPBC_CLONE_SHIP: return SPR_CURSOR_CLONE_SHIP;
|
||||||
case SPBC_CLONE_AIRPLANE: return SPR_CURSOR_CLONE_AIRPLANE;
|
case SPBC_CLONE_AIRPLANE: return SPR_CURSOR_CLONE_AIRPLANE;
|
||||||
|
case SPBC_CLONE_AREA_COPY: return SPR_CURSOR_CLONE_AREA_COPY;
|
||||||
|
case SPBC_CLONE_AREA_PASTE: return SPR_CURSOR_CLONE_AREA_PASTE;
|
||||||
case SPBC_DEMOLISH: return ANIMCURSOR_DEMOLISH;
|
case SPBC_DEMOLISH: return ANIMCURSOR_DEMOLISH;
|
||||||
case SPBC_LOWERLAND: return ANIMCURSOR_LOWERLAND;
|
case SPBC_LOWERLAND: return ANIMCURSOR_LOWERLAND;
|
||||||
case SPBC_RAISELAND: return ANIMCURSOR_RAISELAND;
|
case SPBC_RAISELAND: return ANIMCURSOR_RAISELAND;
|
||||||
|
|
|
@ -54,7 +54,7 @@ static const SpriteID SPR_LARGE_SMALL_WINDOW = 682;
|
||||||
|
|
||||||
/** Extra graphic spritenumbers */
|
/** Extra graphic spritenumbers */
|
||||||
static const SpriteID SPR_OPENTTD_BASE = 4896;
|
static const SpriteID SPR_OPENTTD_BASE = 4896;
|
||||||
static const uint16_t OPENTTD_SPRITE_COUNT = 191;
|
static const uint16_t OPENTTD_SPRITE_COUNT = 195;
|
||||||
|
|
||||||
/* Halftile-selection sprites */
|
/* Halftile-selection sprites */
|
||||||
static const SpriteID SPR_HALFTILE_SELECTION_FLAT = SPR_OPENTTD_BASE;
|
static const SpriteID SPR_HALFTILE_SELECTION_FLAT = SPR_OPENTTD_BASE;
|
||||||
|
@ -174,6 +174,11 @@ static const SpriteID SPR_PLAYER_HOST = SPR_OPENTTD_BASE + 190;
|
||||||
|
|
||||||
static const SpriteID SPR_IMG_CARGOFLOW = SPR_OPENTTD_BASE + 174;
|
static const SpriteID SPR_IMG_CARGOFLOW = SPR_OPENTTD_BASE + 174;
|
||||||
|
|
||||||
|
static const SpriteID SPR_IMG_CLONE_AREA_COPY = SPR_OPENTTD_BASE + 191;
|
||||||
|
static const SpriteID SPR_IMG_CLONE_AREA_PASTE = SPR_OPENTTD_BASE + 192;
|
||||||
|
static const CursorID SPR_CURSOR_CLONE_AREA_COPY = SPR_OPENTTD_BASE + 193;
|
||||||
|
static const CursorID SPR_CURSOR_CLONE_AREA_PASTE = SPR_OPENTTD_BASE + 194;
|
||||||
|
|
||||||
static const SpriteID SPR_SIGNALS_BASE = SPR_OPENTTD_BASE + OPENTTD_SPRITE_COUNT;
|
static const SpriteID SPR_SIGNALS_BASE = SPR_OPENTTD_BASE + OPENTTD_SPRITE_COUNT;
|
||||||
static const uint16_t PRESIGNAL_SPRITE_COUNT = 48;
|
static const uint16_t PRESIGNAL_SPRITE_COUNT = 48;
|
||||||
static const uint16_t PRESIGNAL_AND_SEMAPHORE_SPRITE_COUNT = 112;
|
static const uint16_t PRESIGNAL_AND_SEMAPHORE_SPRITE_COUNT = 112;
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "landscape_cmd.h"
|
#include "landscape_cmd.h"
|
||||||
#include "terraform_cmd.h"
|
#include "terraform_cmd.h"
|
||||||
#include "object_cmd.h"
|
#include "object_cmd.h"
|
||||||
|
#include "clone_area_cmd.h"
|
||||||
|
|
||||||
#include "widgets/terraform_widget.h"
|
#include "widgets/terraform_widget.h"
|
||||||
|
|
||||||
|
@ -131,6 +132,12 @@ bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_t
|
||||||
case DDSP_LEVEL_AREA:
|
case DDSP_LEVEL_AREA:
|
||||||
Command<CMD_LEVEL_LAND>::Post(STR_ERROR_CAN_T_LEVEL_LAND_HERE, CcTerraform, end_tile, start_tile, _ctrl_pressed, LM_LEVEL);
|
Command<CMD_LEVEL_LAND>::Post(STR_ERROR_CAN_T_LEVEL_LAND_HERE, CcTerraform, end_tile, start_tile, _ctrl_pressed, LM_LEVEL);
|
||||||
break;
|
break;
|
||||||
|
case DDSP_CLONE_AREA_COPY:
|
||||||
|
Command<CMD_CLONE_AREA_COPY>::Post(STR_ERROR_CAN_T_CLONE_AREA_COPY, CcCloneArea, end_tile, start_tile, _ctrl_pressed);
|
||||||
|
break;
|
||||||
|
case DDSP_CLONE_AREA_PASTE:
|
||||||
|
Command<CMD_CLONE_AREA_PASTE>::Post(STR_ERROR_CAN_T_CLONE_AREA_PASTE, CcCloneArea, end_tile, start_tile, _ctrl_pressed);
|
||||||
|
break;
|
||||||
case DDSP_CREATE_ROCKS:
|
case DDSP_CREATE_ROCKS:
|
||||||
GenerateRockyArea(end_tile, start_tile);
|
GenerateRockyArea(end_tile, start_tile);
|
||||||
break;
|
break;
|
||||||
|
@ -162,6 +169,7 @@ struct TerraformToolbarWindow : Window {
|
||||||
/* This is needed as we like to have the tree available on OnInit. */
|
/* This is needed as we like to have the tree available on OnInit. */
|
||||||
this->CreateNestedTree();
|
this->CreateNestedTree();
|
||||||
this->FinishInitNested(window_number);
|
this->FinishInitNested(window_number);
|
||||||
|
this->DisableWidget(WID_TT_CLONE_AREA_PASTE);
|
||||||
this->last_user_action = INVALID_WID_TT;
|
this->last_user_action = INVALID_WID_TT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,6 +204,16 @@ struct TerraformToolbarWindow : Window {
|
||||||
this->last_user_action = widget;
|
this->last_user_action = widget;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WID_TT_CLONE_AREA_COPY: // Copy area button
|
||||||
|
HandlePlacePushButton(this, WID_TT_CLONE_AREA_COPY, SPR_CURSOR_CLONE_AREA_COPY, HT_POINT | HT_DIAGONAL);
|
||||||
|
this->last_user_action = widget;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WID_TT_CLONE_AREA_PASTE: // Paste area button
|
||||||
|
HandlePlacePushButton(this, WID_TT_CLONE_AREA_PASTE, SPR_CURSOR_CLONE_AREA_PASTE, HT_POINT | HT_DIAGONAL);
|
||||||
|
this->last_user_action = widget;
|
||||||
|
break;
|
||||||
|
|
||||||
case WID_TT_DEMOLISH: // Demolish aka dynamite button
|
case WID_TT_DEMOLISH: // Demolish aka dynamite button
|
||||||
HandlePlacePushButton(this, WID_TT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
|
HandlePlacePushButton(this, WID_TT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
|
||||||
this->last_user_action = widget;
|
this->last_user_action = widget;
|
||||||
|
@ -238,6 +256,14 @@ struct TerraformToolbarWindow : Window {
|
||||||
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LEVEL_AREA);
|
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LEVEL_AREA);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WID_TT_CLONE_AREA_COPY: // Clone area button
|
||||||
|
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CLONE_AREA_COPY);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WID_TT_CLONE_AREA_PASTE: // Clone area button
|
||||||
|
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CLONE_AREA_PASTE);
|
||||||
|
break;
|
||||||
|
|
||||||
case WID_TT_DEMOLISH: // Demolish aka dynamite button
|
case WID_TT_DEMOLISH: // Demolish aka dynamite button
|
||||||
PlaceProc_DemolishArea(tile);
|
PlaceProc_DemolishArea(tile);
|
||||||
break;
|
break;
|
||||||
|
@ -275,6 +301,11 @@ struct TerraformToolbarWindow : Window {
|
||||||
case DDSP_RAISE_AND_LEVEL_AREA:
|
case DDSP_RAISE_AND_LEVEL_AREA:
|
||||||
case DDSP_LOWER_AND_LEVEL_AREA:
|
case DDSP_LOWER_AND_LEVEL_AREA:
|
||||||
case DDSP_LEVEL_AREA:
|
case DDSP_LEVEL_AREA:
|
||||||
|
case DDSP_CLONE_AREA_PASTE:
|
||||||
|
GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
|
||||||
|
break;
|
||||||
|
case DDSP_CLONE_AREA_COPY:
|
||||||
|
this->CloneAreaPasteWidgetEnable(true);
|
||||||
GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
|
GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
|
||||||
break;
|
break;
|
||||||
case DDSP_BUILD_OBJECT:
|
case DDSP_BUILD_OBJECT:
|
||||||
|
@ -296,6 +327,13 @@ struct TerraformToolbarWindow : Window {
|
||||||
this->RaiseButtons();
|
this->RaiseButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CloneAreaPasteWidgetEnable(bool value)
|
||||||
|
{
|
||||||
|
this->SetWidgetDisabledState(WID_TT_CLONE_AREA_PASTE, !value);
|
||||||
|
this->RaiseWidget(WID_TT_CLONE_AREA_PASTE);
|
||||||
|
this->SetWidgetDirty(WID_TT_CLONE_AREA_PASTE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for global hotkeys of the TerraformToolbarWindow.
|
* Handler for global hotkeys of the TerraformToolbarWindow.
|
||||||
* @param hotkey Hotkey
|
* @param hotkey Hotkey
|
||||||
|
@ -345,6 +383,12 @@ static constexpr NWidgetPart _nested_terraform_widgets[] = {
|
||||||
SetFill(0, 1), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES),
|
SetFill(0, 1), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES),
|
||||||
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_PLACE_SIGN), SetMinimalSize(22, 22),
|
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_PLACE_SIGN), SetMinimalSize(22, 22),
|
||||||
SetFill(0, 1), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN),
|
SetFill(0, 1), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN),
|
||||||
|
|
||||||
|
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_CLONE_AREA_COPY), SetMinimalSize(22, 22),
|
||||||
|
SetFill(0, 1), SetDataTip(SPR_IMG_CLONE_AREA_COPY, STR_LANDSCAPING_TOOLTIP_CLONE_AREA_COPY),
|
||||||
|
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_CLONE_AREA_PASTE), SetMinimalSize(22, 22),
|
||||||
|
SetFill(0, 1), SetDataTip(SPR_IMG_CLONE_AREA_PASTE, STR_LANDSCAPING_TOOLTIP_CLONE_AREA_PASTE),
|
||||||
|
|
||||||
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_TT_SHOW_PLACE_OBJECT),
|
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_TT_SHOW_PLACE_OBJECT),
|
||||||
NWidget(WWT_PUSHIMGBTN, COLOUR_DARK_GREEN, WID_TT_PLACE_OBJECT), SetMinimalSize(22, 22),
|
NWidget(WWT_PUSHIMGBTN, COLOUR_DARK_GREEN, WID_TT_PLACE_OBJECT), SetMinimalSize(22, 22),
|
||||||
SetFill(0, 1), SetDataTip(SPR_IMG_TRANSMITTER, STR_SCENEDIT_TOOLBAR_PLACE_OBJECT),
|
SetFill(0, 1), SetDataTip(SPR_IMG_TRANSMITTER, STR_SCENEDIT_TOOLBAR_PLACE_OBJECT),
|
||||||
|
|
|
@ -120,6 +120,8 @@ enum ViewportDragDropSelectionProcess {
|
||||||
DDSP_PLANT_TREES, ///< Plant trees
|
DDSP_PLANT_TREES, ///< Plant trees
|
||||||
DDSP_BUILD_BRIDGE, ///< Bridge placement
|
DDSP_BUILD_BRIDGE, ///< Bridge placement
|
||||||
DDSP_BUILD_OBJECT, ///< Build an object
|
DDSP_BUILD_OBJECT, ///< Build an object
|
||||||
|
DDSP_CLONE_AREA_COPY, ///< Copy area
|
||||||
|
DDSP_CLONE_AREA_PASTE, ///< Paste area
|
||||||
|
|
||||||
/* Rail specific actions */
|
/* Rail specific actions */
|
||||||
DDSP_PLACE_RAIL, ///< Rail placement
|
DDSP_PLACE_RAIL, ///< Rail placement
|
||||||
|
|
|
@ -22,6 +22,8 @@ enum TerraformToolbarWidgets : WidgetID {
|
||||||
WID_TT_PLANT_TREES, ///< Plant trees button (note: opens separate window, no place-push-button).
|
WID_TT_PLANT_TREES, ///< Plant trees button (note: opens separate window, no place-push-button).
|
||||||
WID_TT_PLACE_SIGN, ///< Place sign button.
|
WID_TT_PLACE_SIGN, ///< Place sign button.
|
||||||
WID_TT_PLACE_OBJECT, ///< Place object button.
|
WID_TT_PLACE_OBJECT, ///< Place object button.
|
||||||
|
WID_TT_CLONE_AREA_COPY, ///< Copy area button.
|
||||||
|
WID_TT_CLONE_AREA_PASTE, ///< Paste area button.
|
||||||
|
|
||||||
INVALID_WID_TT = -1,
|
INVALID_WID_TT = -1,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue