Example #1
0
/**
 * Test if this is safe to copy and paste contents of the map instantly, without
 * using an intermediate buffer.
 *
 * If the copy and the paste areas are close enough (especially when they intersect),
 * sequential copy-pasting may alter at some point of time those tile of the copy
 * area which hasn't been copied yet. In this case, further copy-pasting will read
 * modified values, not the original and this is somthing we don't want to happen.
 * We can deal with it by firstly copying all the content to the clipboard buffer and
 * then pasting it onto the map. This function tels us whether we should use the
 * clipboard as an intermediate buffer because there may happen such a colision.
 *
 * @param copy_paste What, where and how we are copying.
 * @return \c true if intermediate buffer might be required, \c false if it's surely not required
 *
 * @pre booth the source area and the destination area are on the main map
 *
 * @see CalcMaxPasteRange
 */
static bool CopyPasteAreasMayColide(const CopyPasteParams &copy_paste)
{
	/* No need to check surroundings if we are not terraforming. Just test for content intersection. */
	if ((copy_paste.mode & CPM_TERRAFORM_MASK) == CPM_TERRAFORM_NONE) return copy_paste.src_area.Intersects(copy_paste.dst_area);

	/* As we are interested in tile heights, increase areas to include all tile
	 * corners, also these at SW and SE borders. */
	TileArea src_corner_area(AsMainMapTile(copy_paste.src_area.tile), copy_paste.src_area.w + 1, copy_paste.src_area.h + 1);
	TileArea dst_corner_area(AsMainMapTile(copy_paste.dst_area.tile), copy_paste.dst_area.w + 1, copy_paste.dst_area.h + 1);

	DirTransformation inv_transformation = InvertDirTransform(copy_paste.transformation);
	/* source of the destination area most northern tile corner */
	TileIndex source_of_north = dst_corner_area.TransformedNorth(src_corner_area.tile, inv_transformation);

	/* calculate current and new heights on destination area corners */
	/* N */
	TileIndex dst_corner = dst_corner_area.tile;
	TileIndex src_corner = source_of_north;
	uint curr_n = TileHeight(dst_corner);
	uint new_n = TileHeight(src_corner) + copy_paste.height_delta;
	/* W */
	dst_corner = TILE_ADDXY(dst_corner_area.tile, dst_corner_area.w, 0);
	src_corner = dst_corner_area.TransformTile(dst_corner, source_of_north, inv_transformation);
	uint curr_w = TileHeight(dst_corner);
	uint new_w = TileHeight(src_corner) + copy_paste.height_delta;
	/* S */
	dst_corner = TILE_ADDXY(dst_corner_area.tile, dst_corner_area.w, dst_corner_area.h);
	src_corner = dst_corner_area.TransformTile(dst_corner, source_of_north, inv_transformation);
	uint curr_s = TileHeight(dst_corner);
	uint new_s = TileHeight(src_corner) + copy_paste.height_delta;
	/* E */
	dst_corner = TILE_ADDXY(dst_corner_area.tile, 0, dst_corner_area.h);
	src_corner = dst_corner_area.TransformTile(dst_corner, source_of_north, inv_transformation);
	uint curr_e = TileHeight(dst_corner);
	uint new_e = TileHeight(src_corner) + copy_paste.height_delta;

	/* calculate how far tiles can be altered beyon the paste area (safe approximation) */
	uint range_ne = CalcMaxPasteRange(curr_n, new_n, curr_e, new_e, dst_corner_area.h - 1);
	uint range_sw = CalcMaxPasteRange(curr_s, new_s, curr_w, new_w, dst_corner_area.h - 1);
	uint range_nw = CalcMaxPasteRange(curr_n, new_n, curr_w, new_w, dst_corner_area.w - 1);
	uint range_se = CalcMaxPasteRange(curr_s, new_s, curr_e, new_e, dst_corner_area.w - 1);

	/* calculate the exact area which may be altered by the paste process */
	uint x = TileX(dst_corner_area.tile);
	uint y = TileY(dst_corner_area.tile);
	range_ne = max(range_ne, x); // cut the area at the NE border (don't let x to go below 0)
	range_nw = max(range_nw, y); // cut the area at the NW border (don't let y to go below 0)
	TileArea forbidden_area(
			TileXY(x - range_ne, y - range_nw),
			dst_corner_area.w + range_ne + range_sw,
			dst_corner_area.h + range_nw + range_se);

	/* test if the source area is within the paste range */
	return src_corner_area.Intersects(forbidden_area);
}
Example #2
0
void CopyPastePlaceRailWaypoint(GenericTileIndex tile, StationID sid, Axis axis, RailType rt, StationGfx gfx, StationClassID stat_class, byte stat_type, int specindex, bool adjacent)
{
	if (IsMainMapTile(tile)) {
		TileIndex t = AsMainMapTile(tile);
		/* check if required track is already there, try to build one if not */
		if (!IsTileOwner(t, _current_company) ||
				(!IsRailWaypointTile(tile) && !IsPlainRailTile(tile)) ||
				GetRailType(t) != rt ||
				(IsTileType(t, MP_STATION) ? GetRailStationAxis(tile) != axis : !HasBit(GetTrackBits(t), AxisToTrack(axis)))) {
			CopyPastePlaceTracks(tile, rt, AxisToTrackBits(axis));
			if (_current_pasting->last_result.Failed()) return;
		}
		/* build the waypoint */
		_station_cmd_specindex_to_paste = specindex;
		uint32 p1 = 0;
		SB(p1, 0, 4, rt);
		SB(p1, 4, 1, axis);
		SB(p1, 8, 8, 1);  // width
		SB(p1, 16, 8, 1); // height
		SB(p1, 24, 1, adjacent);
		uint32 p2 = 0;
		SB(p2, 0, 8, stat_class);
		SB(p2, 8, 8, stat_type);
		SB(p2, 16, 16, sid);
		_current_pasting->DoCommand(t, p1, p2, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT));
	} else {
		MakeRailWaypoint(tile, OWNER_NONE, sid, axis, gfx & ~1, rt);
		assert(IsInsideMM(specindex, 0, MAX_UVALUE(byte) + 1));
		SetCustomStationSpecIndex(tile, (byte)specindex);
		_clipboard_stations_builder.AddRailPart(sid, stat_class, stat_type, (byte)specindex);
	}
}
Example #3
0
/**
 * Copy and paste heights from one map to another.
 *
 * @param src_area Area to read heights from. It consists of tiles, not of tile corners
 *                  e.g. if you pass a single tile area then 4 corners will be terraformed.
 * @param dst_area_north Norhern tile of the area to write heigths at.
 * @param transformation Transformation to perform on tile indices.
 * @param height_delta Offset, number of units to add to each height.
 */
void CopyPasteHeights(const GenericTileArea &src_area, GenericTileIndex dst_area_north, DirTransformation transformation, int height_delta)
{
	/* include also corners at SW and SE edges */
	GenericTileArea src_corners(src_area.tile, src_area.w + 1, src_area.h + 1);
	/* transform the most northern corner */
	GenericTileIndex transformed_north_corner = src_corners.TransformedNorth(dst_area_north, transformation);

#ifdef WITH_ASSERT
	{
		assert(IsValidTileIndex(dst_area_north));
		uint x = TileX(dst_area_north);
		uint y = TileY(dst_area_north);
		assert(!IsMainMapTile(dst_area_north) || !_settings_game.construction.freeform_edges || (x > 0 && y > 0));
		Dimension dst_dim = { src_corners.w, src_corners.h };
		dst_dim = TransformDimension(dst_dim, transformation);
		assert(x + dst_dim.width <= MapSizeX(MapOf(dst_area_north)) && y + dst_dim.height <= MapSizeY(MapOf(dst_area_north)));
	}
#endif /* WITH_ASSERT */

	if (IsMainMapTile(dst_area_north)) {
		HeightsCopyPastingIterator iter(src_corners, AsMainMapTile(transformed_north_corner), transformation, height_delta);
		TerraformPasteTiles(&iter);
	} else {
		for (TransformationTileIteratorT<true, true> iter(src_corners, transformed_north_corner, transformation); IsValidTileIndex(iter); ++iter) {
			SetTileHeight(iter.DstTile(), TileHeight(iter.SrcTile()));
		}
	}
}
Example #4
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);
	}
}