/**
* Build a ship depot.
* @param tile tile where ship depot is built
* @param flags type of operation
* @param p1 bit 0 depot orientation (Axis)
* @param p2 unused
* @param text unused
* @return the cost of this operation or an error
*/
CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
Axis axis = Extract<Axis, 0, 1>(p1);
TileIndex tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
if (!HasTileWaterGround(tile) || !HasTileWaterGround(tile2)) {
return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER);
}
if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
if (!IsTileFlat(tile) || !IsTileFlat(tile2)) {
/* Prevent depots on rapids */
return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
}
if (!Depot::CanAllocateItem()) return CMD_ERROR;
WaterClass wc1 = GetWaterClass(tile);
WaterClass wc2 = GetWaterClass(tile2);
CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_DEPOT_SHIP]);
bool add_cost = !IsWaterTile(tile);
CommandCost ret = DoCommand(tile, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
if (ret.Failed()) return ret;
if (add_cost) {
cost.AddCost(ret);
}
add_cost = !IsWaterTile(tile2);
ret = DoCommand(tile2, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
if (ret.Failed()) return ret;
if (add_cost) {
cost.AddCost(ret);
}
byte diag_dir_mask = (axis == AXIS_X) ? (1 << DIAGDIR_SE | 1 << DIAGDIR_NW) : (1 << DIAGDIR_NE | 1 << DIAGDIR_SW);
ret = EnsureNoShipFromDiagDirByte(tile, diag_dir_mask);
if (ret.Failed()) return ret;
ret = EnsureNoShipFromDiagDirByte(tile2, diag_dir_mask);
if (ret.Failed()) return ret;
// DiagDirection dir_rotate = axis == AXIS_X ? DIAGDIR_SE : DIAGDIR_NE;
// TileIndex tc = tile + (axis == AXIS_X ? TileDiffXY(0, -1) : TileDiffXY(1, 0));
// ret = EnsureNoShipFromDiagDir(tc, dir_rotate);
// if (ret.Failed()) return ret;
//
// tc = tile2 + (axis == AXIS_X ? TileDiffXY(0, -1) : TileDiffXY(1, 0));
// ret = EnsureNoShipFromDiagDir(tc, dir_rotate);
// if (ret.Failed()) return ret;
//
// dir_rotate = ReverseDiagDir(dir_rotate);
// tc = tile + (axis == AXIS_X ? TileDiffXY(0, 1) : TileDiffXY(-1, 0));
// ret = EnsureNoShipFromDiagDir(tc, dir_rotate);
// if (ret.Failed()) return ret;
//
// tc = tile2 + (axis == AXIS_X ? TileDiffXY(0, 1) : TileDiffXY(-1, 0));
// ret = EnsureNoShipFromDiagDir(tc, dir_rotate);
// if (ret.Failed()) return ret;
//
if (flags & DC_EXEC) {
Depot *depot = new Depot(tile);
depot->build_date = _date;
if (wc1 == WATER_CLASS_CANAL || wc2 == WATER_CLASS_CANAL) {
/* Update infrastructure counts after the unconditional clear earlier. */
Company::Get(_current_company)->infrastructure.water += wc1 == WATER_CLASS_CANAL && wc2 == WATER_CLASS_CANAL ? 2 : 1;
}
Company::Get(_current_company)->infrastructure.water += 2 * LOCK_DEPOT_TILE_FACTOR;
DirtyCompanyInfrastructureWindows(_current_company);
MakeShipDepot(tile, _current_company, depot->index, DEPOT_PART_NORTH, axis, wc1);
MakeShipDepot(tile2, _current_company, depot->index, DEPOT_PART_SOUTH, axis, wc2);
MarkTileDirtyByTile(tile);
MarkTileDirtyByTile(tile2);
MakeDefaultName(depot);
}
return cost;
}
/** Temporary data storage for testing track. */
struct ShipTrackChecker {
TrackBits tb; ///< Tracks to check against.
int z; ///< Tile height.
};
static Vehicle *NoShipOnTrack(Vehicle *v, void *data)
{
if (v->type != VEH_SHIP) return NULL;
ShipTrackChecker *stc = (ShipTrackChecker *)data;
if (v->z_pos > stc->z) return NULL;
if (Ship::From(v)->state & stc->tb) return v;
return NULL;
}
CommandCost EnsureNoShipFromDiagDirByte(TileIndex tile, byte diag_dir_byte)
{
TrackBits tile_tb = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0));
if ((tile_tb & TRACK_BIT_ALL) != TRACK_BIT_NONE) {
for (DiagDirection diag_dir = DIAGDIR_BEGIN; diag_dir != DIAGDIR_END; diag_dir++) {
if (diag_dir_byte & 1 << diag_dir) {
TileIndex tc = TileAddByDiagDir(tile, diag_dir);
TrackBits tc_tb = TrackStatusToTrackBits(GetTileTrackStatus(tc, TRANSPORT_WATER, 0)) & DiagdirReachesTracks(DiagdirBetweenTiles(tile, tc));
if (tc_tb && !IsShipDepotTile(tc) && !(IsTileType(tc, MP_WATER) && IsLock(tc)) &&
!(IsTileType(tc, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tc) == TRANSPORT_WATER)) {
ShipTrackChecker stc;
stc.z = GetTileMaxPixelZ(tc);
stc.tb = tc_tb;
if (HasVehicleOnPos(tc, &stc, NoShipOnTrack)) {
return_cmd_error(STR_ERROR_SHIP_IN_THE_WAY);
}
}
}
}
}
return CommandCost();
}