Exemplo n.º 1
0
/**
 * 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 ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
		(MayHaveBridgeAbove(tile2) && 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);
	}

	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;
}
/**
 * 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 ((MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) ||
		(MayHaveBridgeAbove(tile2) && IsBridgeAbove(tile2))) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);

	if (GetTileSlope(tile, NULL) != SLOPE_FLAT || GetTileSlope(tile2, NULL) != SLOPE_FLAT) {
		/* 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);
	}

	if (flags & DC_EXEC) {
		Depot *depot = new Depot(tile);
		depot->build_date = _date;

		MakeShipDepot(tile,  _current_company, depot->index, DEPOT_NORTH, axis, wc1);
		MakeShipDepot(tile2, _current_company, depot->index, DEPOT_SOUTH, axis, wc2);
		MarkTileDirtyByTile(tile);
		MarkTileDirtyByTile(tile2);
		MakeDefaultName(depot);
	}

	return cost;
}
Exemplo n.º 3
0
/**
 * Finds the distance for the closest tile with water/land given a tile
 * @param tile  the tile to find the distance too
 * @param water whether to find water or land
 * @return distance to nearest water (max 0x7F) / land (max 0x1FF; 0x200 if there is no land)
 */
uint GetClosestWaterDistance(TileIndex tile, bool water)
{
	if (HasTileWaterGround(tile) == water) return 0;

	uint max_dist = water ? 0x7F : 0x200;

	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--;

		/* going counter-clockwise around this square */
		for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
			static const int8 ddx[DIAGDIR_END] = { -1,  1,  1, -1};
			static const int8 ddy[DIAGDIR_END] = {  1,  1, -1, -1};

			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 [min; max) for IsInsideMM())*/
				if (IsInsideMM(x, min_xy, max_x) && IsInsideMM(y, min_xy, max_y)) {
					TileIndex t = TileXY(x, y);
					if (HasTileWaterGround(t) == water) return dist;
				}
				x += dx;
				y += dy;
			}
		}
	}

	if (!water) {
		/* no land found - is this a water-only map? */
		for (TileIndex t = 0; t < MapSize(); t++) {
			if (!IsTileType(t, MP_VOID) && !IsTileType(t, MP_WATER)) return 0x1FF;
		}
	}

	return max_dist;
}
Exemplo n.º 4
0
/**
 * Build a buoy.
 * @param tile tile where to place the buoy
 * @param flags operation to perform
 * @param p1 unused
 * @param p2 unused
 * @param text unused
 * @return the cost of this operation or an error
 */
CommandCost CmdBuildBuoy(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
	if (tile == 0) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);

	WaterClass wc;
	if ((flags & DC_PASTE) && !(flags & DC_EXEC)) {
		/* When pasting a buoy, there may be no water yet (a canal will be placed when DC_EXE'ing).
		 * Ignore that there is no water so we can calculate the cost more precisely. */
		wc = WATER_CLASS_INVALID;
	} else {
		if (!HasTileWaterGround(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
		wc = GetWaterClass(tile);
	}

	if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);

	if (!IsTileFlat(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);

	/* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */
	Waypoint *wp = FindDeletedWaypointCloseTo(tile, STR_SV_STNAME_BUOY, OWNER_NONE);
	if (wp == NULL && !Waypoint::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);

	CommandCost cost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_WAYPOINT_BUOY]);
	if (!IsWaterTile(tile)) {
		CommandCost ret = DoCommand(tile, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
		if (ret.Failed()) return ret;
		cost.AddCost(ret);
	}

	if (flags & DC_EXEC) {
		if (wp == NULL) {
			wp = new Waypoint(tile);
		} else {
			/* Move existing (recently deleted) buoy to the new location */
			wp->xy = tile;
			InvalidateWindowData(WC_WAYPOINT_VIEW, wp->index);
		}
		wp->rect.BeforeAddTile(tile, StationRect::ADD_TRY);

		wp->string_id = STR_SV_STNAME_BUOY;

		wp->facilities |= FACIL_DOCK;
		wp->owner = OWNER_NONE;

		wp->build_date = _date;

		if (wp->town == NULL) MakeDefaultName(wp);

		assert(wc != WATER_CLASS_INVALID);
		MakeBuoy(tile, wp->index, wc);

		wp->UpdateVirtCoord();
		InvalidateWindowData(WC_WAYPOINT_VIEW, wp->index);
	}

	return cost;
}
Exemplo n.º 5
0
void CopyPastePlaceBuoy(GenericTileIndex tile, StationID sid, WaterClass wc)
{
	if (IsMainMapTile(tile)) {
		TileIndex t = AsMainMapTile(tile);
		/* build a piece of canal if not on water */
		if (!HasTileWaterGround(t)) {
			CopyPastePlaceCannal(tile);
			if (_current_pasting->last_result.Failed()) return;
		}
		/* build the buoy */
		_current_pasting->DoCommand(t, 0, 0, CMD_BUILD_BUOY | CMD_MSG(STR_ERROR_CAN_T_POSITION_BUOY_HERE));
	} else {
		SetTileOwner(tile, OWNER_NONE);
		MakeBuoy(tile, sid, wc);
		_clipboard_stations_builder.AddPart(sid);
	}
}
Exemplo n.º 6
0
/**
 * Build a buoy.
 * @param tile tile where to place the buoy
 * @param flags operation to perform
 * @param p1 unused
 * @param p2 unused
 * @param text unused
 * @return the cost of this operation or an error
 */
CommandCost CmdBuildBuoy(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
	if (tile == 0 || !HasTileWaterGround(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);

	if (GetTileSlope(tile) != SLOPE_FLAT) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);

	/* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */
	Waypoint *wp = FindDeletedWaypointCloseTo(tile, STR_SV_STNAME_BUOY, OWNER_NONE);
	if (wp == NULL && !Waypoint::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);

	CommandCost cost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_WAYPOINT_BUOY]);
	if (!IsWaterTile(tile)) {
		CommandCost ret = DoCommand(tile, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR);
		if (ret.Failed()) return ret;
		cost.AddCost(ret);
	}

	if (flags & DC_EXEC) {
		if (wp == NULL) {
			wp = new Waypoint(tile);
		} else {
			/* Move existing (recently deleted) buoy to the new location */
			wp->xy = tile;
			InvalidateWindowData(WC_WAYPOINT_VIEW, wp->index);
		}
		wp->rect.BeforeAddTile(tile, StationRect::ADD_TRY);

		wp->string_id = STR_SV_STNAME_BUOY;

		wp->facilities |= FACIL_DOCK;
		wp->owner = OWNER_NONE;

		wp->build_date = _date;

		if (wp->town == NULL) MakeDefaultName(wp);

		MakeBuoy(tile, wp->index, GetWaterClass(tile));

		wp->UpdateVirtCoord();
		InvalidateWindowData(WC_WAYPOINT_VIEW, wp->index);
	}

	return cost;
}