summaryrefslogtreecommitdiff
path: root/src/landscape.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/landscape.cpp')
-rw-r--r--src/landscape.cpp51
1 files changed, 51 insertions, 0 deletions
diff --git a/src/landscape.cpp b/src/landscape.cpp
index 18f27807d..eb1e404f0 100644
--- a/src/landscape.cpp
+++ b/src/landscape.cpp
@@ -90,6 +90,57 @@ extern const byte _slope_to_sprite_offset[32] = {
static SnowLine *_snow_line = NULL;
/**
+ * Map 2D viewport or smallmap coordinate to 3D world or tile coordinate.
+ * Function takes into account height of tiles and foundations.
+ *
+ * @param x X viewport 2D coordinate.
+ * @param y Y viewport 2D coordinate.
+ * @param clamp_to_map Clamp the coordinate outside of the map to the closest, non-void tile within the map.
+ * @return 3D world coordinate of point visible at the given screen coordinate (3D perspective).
+ *
+ * @note Inverse of #RemapCoords2 function. Smaller values may get rounded.
+ * @see InverseRemapCoords
+ */
+Point InverseRemapCoords2(int x, int y, bool clamp_to_map)
+{
+ /* Initial x/y world coordinate is like if the landscape
+ * was completely flat on height 0. */
+ Point pt = InverseRemapCoords(x, y);
+
+ const uint min_coord = _settings_game.construction.freeform_edges ? TILE_SIZE : 0;
+ const uint max_x = MapMaxX() * TILE_SIZE - 1;
+ const uint max_y = MapMaxY() * TILE_SIZE - 1;
+
+ if (clamp_to_map) {
+ /* Bring the coordinates near to a valid range. At the top we allow a number
+ * of extra tiles. This is mostly due to the tiles on the north side of
+ * the map possibly being drawn higher due to the extra height levels. */
+ int extra_tiles = CeilDiv(_settings_game.construction.max_heightlevel * TILE_HEIGHT, TILE_PIXELS);
+ pt.x = Clamp(pt.x, -extra_tiles * TILE_SIZE, max_x);
+ pt.y = Clamp(pt.y, -extra_tiles * TILE_SIZE, max_y);
+ }
+
+ /* Now find the Z-world coordinate by fix point iteration.
+ * This is a bit tricky because the tile height is non-continuous at foundations.
+ * The clicked point should be approached from the back, otherwise there are regions that are not clickable.
+ * (FOUNDATION_HALFTILE_LOWER on SLOPE_STEEP_S hides north halftile completely)
+ * So give it a z-malus of 4 in the first iterations. */
+ int z = 0;
+ for (int i = 0; i < 5; i++) z = GetSlopePixelZ(Clamp(pt.x + max(z, 4) - 4, min_coord, max_x), Clamp(pt.y + max(z, 4) - 4, min_coord, max_y)) / 2;
+ for (int m = 3; m > 0; m--) z = GetSlopePixelZ(Clamp(pt.x + max(z, m) - m, min_coord, max_x), Clamp(pt.y + max(z, m) - m, min_coord, max_y)) / 2;
+ for (int i = 0; i < 5; i++) z = GetSlopePixelZ(Clamp(pt.x + z, min_coord, max_x), Clamp(pt.y + z, min_coord, max_y)) / 2;
+
+ pt.x += z;
+ pt.y += z;
+ if (clamp_to_map) {
+ pt.x = Clamp(pt.x, min_coord, max_x);
+ pt.y = Clamp(pt.y, min_coord, max_y);
+ }
+
+ return pt;
+}
+
+/**
* Applies a foundation to a slope.
*
* @pre Foundation and slope must be valid combined.