/**
* Build a piece of canal.
* @param tile end tile of stretch-dragging
* @param flags type of operation
* @param p1 start tile of stretch-dragging
* @param p2 waterclass to build. sea and river can only be built in scenario editor
* @param text unused
* @return the cost of this operation or an error
*/
CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
WaterClass wc = Extract<WaterClass, 0, 2>(p2);
if (p1 >= MapSize() || wc == WATER_CLASS_INVALID) return CMD_ERROR;
/* Outside of the editor you can only build canals, not oceans */
if (wc != WATER_CLASS_CANAL && _game_mode != GM_EDITOR) return CMD_ERROR;
TileArea ta(tile, p1);
/* Outside the editor you can only drag canals, and not areas */
if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR;
Axis axis = INVALID_AXIS;
int delta = 0;
TileIndex tile_next = min(tile, p1);
int rem = 1;
if (ta.w == 1 && ta.h > 1) {
rem = ta.h;
axis = AXIS_Y;
}
if (ta.w > 1 && ta.h == 1) {
rem = ta.w;
axis = AXIS_X;
}
if (ta.w > 1 && ta.h > 1) rem = -1;
if (axis != INVALID_AXIS) delta = TileOffsByDiagDir(AxisToDiagDir(axis));
bool built_lock = false;
CommandCost cost(EXPENSES_CONSTRUCTION);
TILE_AREA_LOOP(tile, ta) {
if (rem > 0) rem--;
tile_next += delta;
if (built_lock) {
built_lock = false;
continue;
}
CommandCost ret;
Slope slope = GetTileSlope(tile);
Slope slope_next = GetTileSlope(tile_next);
// if (slope != SLOPE_FLAT && (wc != WATER_CLASS_RIVER || !IsInclinedSlope(slope))) {
// return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
// }
if (slope != SLOPE_FLAT && !IsInclinedSlope(slope)) {
return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
}
/* can't make water of water! */
if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || wc == WATER_CLASS_SEA)) continue;
bool river = HasTileWaterClass(tile) && GetWaterClass(tile) == WATER_CLASS_RIVER;
if (rem > 0 && wc == WATER_CLASS_CANAL && slope == SLOPE_FLAT && IsInclinedSlope(slope_next) && DiagDirToAxis(GetInclinedSlopeDirection(slope_next)) == axis) {
continue;
} else {
bool water = IsWaterTile(tile);
ret = DoCommand(tile, 0, 0, flags | DC_FORCE_CLEAR_TILE, CMD_LANDSCAPE_CLEAR);
if (ret.Failed()) return ret;
if (!water) cost.AddCost(ret);
}
/* Try to build a lock on inclined tile. */
if (rem >= 0) {
if (wc == WATER_CLASS_CANAL && IsInclinedSlope(slope) && (axis == INVALID_AXIS || DiagDirToAxis(GetInclinedSlopeDirection(slope)) == axis)) {
if (rem == 0 && axis == INVALID_AXIS || IsTileFlat(tile + TileOffsByDiagDir(GetInclinedSlopeDirection(slope))) && IsTileFlat(tile - TileOffsByDiagDir(GetInclinedSlopeDirection(slope)))) {
/* Mark the tile as already cleared for the lock command.
* Do this for all tiles (like trees), not only objects. */
ClearedObjectArea *coa = FindClearedObject(tile);
if (coa == NULL) {
coa = _cleared_object_areas.Append();
coa->first_tile = tile;
coa->area = TileArea(tile, 1, 1);
}
/* Hide the tile from the lock command */
TileIndex tile_lock_before = coa->first_tile;
coa->first_tile = INVALID_TILE;
ret = DoCommand(tile, river ? 1 : 0, 0, flags, CMD_BUILD_LOCK);
coa->first_tile = tile_lock_before;
if (ret.Failed()) return ret;
cost.AddCost(ret);
built_lock = true;
} else {
return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
}
} else {
if (wc == WATER_CLASS_CANAL && IsInclinedSlope(slope) && axis != INVALID_AXIS && DiagDirToAxis(GetInclinedSlopeDirection(slope)) != axis) {
return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
} //else {
// if (wc == WATER_CLASS_CANAL && rem == 0 && axis == INVALID_AXIS && _game_mode == GM_EDITOR && slope != SLOPE_FLAT) {
// return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
// }
// }
}
} else {
if (slope != SLOPE_FLAT && wc != WATER_CLASS_RIVER) {
return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED);
}
}
if (flags & DC_EXEC) {
switch (wc) {
case WATER_CLASS_RIVER:
MakeRiver(tile, Random());
if (_game_mode == GM_EDITOR) {
TileIndex tile2 = tile;
CircularTileSearch(&tile2, 5, RiverModifyDesertZone, NULL);
}
break;
case WATER_CLASS_SEA:
if (TileHeight(tile) == 0) {
MakeSea(tile);
break;
}
/* FALL THROUGH */
default:
if (!IsInclinedSlope(slope)) {
MakeCanal(tile, _current_company, Random());
if (river) SetCanalOnRiver(tile);
if (Company::IsValidID(_current_company)) {
Company::Get(_current_company)->infrastructure.water++;
DirtyCompanyInfrastructureWindows(_current_company);
}
}
break;
}
MarkTileDirtyByTile(tile);
MarkCanalsAndRiversAroundDirty(tile);
}
if (!built_lock) cost.AddCost(_price[PR_BUILD_CANAL]);
}
if (cost.GetCost() == 0) {
return_cmd_error(STR_ERROR_ALREADY_BUILT);
} else {
return cost;
}
}