Skip to content

Commit

Permalink
Feature: Raise a corner of land automatically when building aqueducts
Browse files Browse the repository at this point in the history
  • Loading branch information
SamuXarick committed Apr 1, 2019
1 parent cb44904 commit 2904498
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 7 deletions.
12 changes: 9 additions & 3 deletions src/bridge_gui.cpp
Expand Up @@ -24,6 +24,7 @@
#include "cmd_helper.h"
#include "tunnelbridge_map.h"
#include "road_gui.h"
#include "viewport_func.h"

#include "widgets/bridge_widget.h"

Expand Down Expand Up @@ -60,11 +61,16 @@ typedef GUIList<BuildBridgeData> GUIBridgeList; ///< List of bridges, used in #B
*/
void CcBuildBridge(const CommandCost &result, TileIndex end_tile, uint32 p1, uint32 p2)
{
if (result.Failed()) return;
if (_settings_client.sound.confirm) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, end_tile);

TransportType transport_type = Extract<TransportType, 15, 2>(p2);

if (result.Failed()) {
if (transport_type == TRANSPORT_WATER) {
SetRedErrorSquare(_build_tunnel_endtile);
}
return;
}
if (_settings_client.sound.confirm) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, end_tile);

if (transport_type == TRANSPORT_ROAD) {
DiagDirection end_direction = ReverseDiagDir(GetTunnelBridgeDirection(end_tile));
ConnectRoadToStructure(end_tile, end_direction);
Expand Down
1 change: 1 addition & 0 deletions src/lang/english.txt
Expand Up @@ -4435,6 +4435,7 @@ STR_ERROR_CAN_T_BUILD_ON_CANAL :{WHITE}... can'
STR_ERROR_CAN_T_BUILD_ON_RIVER :{WHITE}... can't build on river
STR_ERROR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}Must demolish canal first
STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Can't build aqueduct here...
STR_ERROR_UNABLE_TO_LEVEL_LAND_AQUEDUCT :{WHITE}Unable to level land for other end of aqueduct

# Tree related errors
STR_ERROR_TREE_ALREADY_HERE :{WHITE}... tree already here
Expand Down
103 changes: 99 additions & 4 deletions src/tunnelbridge_cmd.cpp
Expand Up @@ -239,6 +239,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u

TransportType transport_type = Extract<TransportType, 15, 2>(p2);

_build_tunnel_endtile = 0;
/* type of bridge */
switch (transport_type) {
case TRANSPORT_ROAD:
Expand Down Expand Up @@ -377,17 +378,111 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
if (ret.Failed()) return ret;
cost = ret;

if (terraform_cost_north.Failed() || (terraform_cost_north.GetCost() != 0 && !allow_on_slopes)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
cost.AddCost(terraform_cost_north);
if (transport_type != TRANSPORT_WATER) {
if (terraform_cost_north.Failed() || (terraform_cost_north.GetCost() != 0 && !allow_on_slopes)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
cost.AddCost(terraform_cost_north);
} else {
Slope tileh_north_aqueduct = GetTileSlope(tile_start);
if (tileh_north_aqueduct != ComplementSlope(tileh_end)) {
if (!IsInclinedSlope(GetTileSlope(end_tile))) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
if (IsSteepSlope(tileh_north_aqueduct)) {
tileh_north_aqueduct = SlopeWithOneCornerRaised(OppositeCorner(GetHighestSlopeCorner((tileh_north_aqueduct ^ (SLOPE_ELEVATED | SLOPE_STEEP)) ^ tileh_end)));
} else {
tileh_north_aqueduct = ComplementSlope(tileh_end) ^ tileh_north_aqueduct;
}
/* Mark the tile as already cleared for the terraform command.
* Do this for all tiles (like trees), not only objects. */
ClearedObjectArea *coa = FindClearedObject(tile_start);
if (coa == NULL) {
/*C++17: coa = &*/ _cleared_object_areas.push_back({tile_start, TileArea(tile_start, 1, 1)});
coa = &_cleared_object_areas.back();
}

/* Hide the tile from the terraforming command. */
TileIndex old_first_tile = coa->first_tile;
coa->first_tile = INVALID_TILE;

/* CMD_TERRAFORM_LAND may append further items to _cleared_object_areas,
* however it will never erase or re-order existing items.
* _cleared_object_areas is a value-type SmallVector, therefore appending items
* may result in a backing-store re-allocation, which would invalidate the coa pointer.
* The index of the coa pointer into the _cleared_object_areas vector remains valid,
* and can be used safely after the CMD_TERRAFORM_LAND operation.
* Deliberately clear the coa pointer to avoid leaving dangling pointers which could
* inadvertently be dereferenced.
*/
ClearedObjectArea *begin = _cleared_object_areas.data();
assert(coa >= begin && coa < begin + _cleared_object_areas.size());
size_t coa_index = coa - begin;
assert(coa_index < UINT_MAX); // more than 2**32 cleared areas would be a bug in itself
coa = NULL;

ret = DoCommand(tile_start, tileh_north_aqueduct, 1, flags & ~DC_NO_WATER, CMD_TERRAFORM_LAND);
_cleared_object_areas[(uint)coa_index].first_tile = old_first_tile;
if (ret.Failed()) {
/* if the command fails from here on we want the end tile to be highlighted */
_build_tunnel_endtile = tile_start;
return_cmd_error(STR_ERROR_UNABLE_TO_LEVEL_LAND_AQUEDUCT);
}
cost.AddCost(ret);
}
}

/* Try and clear the end landscape */
ret = DoCommand(tile_end, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (ret.Failed()) return ret;
cost.AddCost(ret);

/* false - end tile slope check */
if (terraform_cost_south.Failed() || (terraform_cost_south.GetCost() != 0 && !allow_on_slopes)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
cost.AddCost(terraform_cost_south);
if (transport_type != TRANSPORT_WATER) {
if (terraform_cost_south.Failed() || (terraform_cost_south.GetCost() != 0 && !allow_on_slopes)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
cost.AddCost(terraform_cost_south);
} else {
Slope tileh_south_aqueduct = GetTileSlope(tile_end);
if (tileh_south_aqueduct != ComplementSlope(tileh_start)) {
if (!IsInclinedSlope(GetTileSlope(end_tile))) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
if (IsSteepSlope(tileh_south_aqueduct)) {
tileh_south_aqueduct = SlopeWithOneCornerRaised(OppositeCorner(GetHighestSlopeCorner((tileh_south_aqueduct ^ (SLOPE_ELEVATED | SLOPE_STEEP)) ^ tileh_start)));
} else {
tileh_south_aqueduct = ComplementSlope(tileh_start) ^ tileh_south_aqueduct;
}
/* Mark the tile as already cleared for the terraform command.
* Do this for all tiles (like trees), not only objects. */
ClearedObjectArea *coa = FindClearedObject(tile_end);
if (coa == NULL) {
/*C++17: coa = &*/ _cleared_object_areas.push_back({tile_end, TileArea(tile_end, 1, 1)});
coa = &_cleared_object_areas.back();
}

/* Hide the tile from the terraforming command. */
TileIndex old_first_tile = coa->first_tile;
coa->first_tile = INVALID_TILE;

/* CMD_TERRAFORM_LAND may append further items to _cleared_object_areas,
* however it will never erase or re-order existing items.
* _cleared_object_areas is a value-type SmallVector, therefore appending items
* may result in a backing-store re-allocation, which would invalidate the coa pointer.
* The index of the coa pointer into the _cleared_object_areas vector remains valid,
* and can be used safely after the CMD_TERRAFORM_LAND operation.
* Deliberately clear the coa pointer to avoid leaving dangling pointers which could
* inadvertently be dereferenced.
*/
ClearedObjectArea *begin = _cleared_object_areas.data();
assert(coa >= begin && coa < begin + _cleared_object_areas.size());
size_t coa_index = coa - begin;
assert(coa_index < UINT_MAX); // more than 2**32 cleared areas would be a bug in itself
coa = NULL;

ret = DoCommand(tile_end, tileh_south_aqueduct, 1, flags & ~DC_NO_WATER, CMD_TERRAFORM_LAND);
_cleared_object_areas[(uint)coa_index].first_tile = old_first_tile;
if (ret.Failed()) {
/* if the command fails from here on we want the end tile to be highlighted */
_build_tunnel_endtile = tile_end;
return_cmd_error(STR_ERROR_UNABLE_TO_LEVEL_LAND_AQUEDUCT);
}
cost.AddCost(ret);
}
}

const TileIndex heads[] = {tile_start, tile_end};
for (int i = 0; i < 2; i++) {
Expand Down

0 comments on commit 2904498

Please sign in to comment.