mirror of https://github.com/OpenRCT2/OpenRCT2.git
322 lines
12 KiB
C
322 lines
12 KiB
C
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
|
|
/*****************************************************************************
|
|
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
|
*
|
|
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
|
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
|
*
|
|
* OpenRCT2 is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* A full copy of the GNU General Public License can be found in licence.txt
|
|
*****************************************************************************/
|
|
#pragma endregion
|
|
|
|
#include "map.h"
|
|
#include "map_helpers.h"
|
|
|
|
/**
|
|
* Not perfect, this still leaves some particular tiles unsmoothed.
|
|
*/
|
|
int map_smooth(int l, int t, int r, int b)
|
|
{
|
|
int i, x, y, highest, count, cornerHeights[4], doubleCorner, raisedLand = 0;
|
|
rct_map_element *mapElement, *mapElement2;
|
|
for (y = t; y < b; y++) {
|
|
for (x = l; x < r; x++) {
|
|
mapElement = map_get_surface_element_at(x, y);
|
|
mapElement->properties.surface.slope &= ~0x1F;
|
|
|
|
// Raise to edge height - 2
|
|
highest = mapElement->base_height;
|
|
highest = max(highest, map_get_surface_element_at(x - 1, y + 0)->base_height);
|
|
highest = max(highest, map_get_surface_element_at(x + 1, y + 0)->base_height);
|
|
highest = max(highest, map_get_surface_element_at(x + 0, y - 1)->base_height);
|
|
highest = max(highest, map_get_surface_element_at(x + 0, y + 1)->base_height);
|
|
if (mapElement->base_height < highest - 2) {
|
|
raisedLand = 1;
|
|
mapElement->base_height = mapElement->clearance_height = highest - 2;
|
|
}
|
|
|
|
// Check corners
|
|
doubleCorner = -1;
|
|
cornerHeights[0] = map_get_surface_element_at(x - 1, y - 1)->base_height;
|
|
cornerHeights[1] = map_get_surface_element_at(x + 1, y - 1)->base_height;
|
|
cornerHeights[2] = map_get_surface_element_at(x + 1, y + 1)->base_height;
|
|
cornerHeights[3] = map_get_surface_element_at(x - 1, y + 1)->base_height;
|
|
highest = mapElement->base_height;
|
|
for (i = 0; i < 4; i++)
|
|
highest = max(highest, cornerHeights[i]);
|
|
|
|
if (highest >= mapElement->base_height + 4) {
|
|
count = 0;
|
|
int canCompensate = 1;
|
|
for (i = 0; i < 4; i++)
|
|
if (cornerHeights[i] == highest){
|
|
count++;
|
|
|
|
// Check if surrounding corners aren't too high. The current tile
|
|
// can't compensate for all the height differences anymore if it has
|
|
// the extra height slope.
|
|
int highestOnLowestSide;
|
|
switch (i){
|
|
case 0:
|
|
highestOnLowestSide = max(
|
|
map_get_surface_element_at(x + 1, y)->base_height,
|
|
map_get_surface_element_at(x, y + 1)->base_height);
|
|
break;
|
|
case 1:
|
|
highestOnLowestSide = max(
|
|
map_get_surface_element_at(x - 1, y)->base_height,
|
|
map_get_surface_element_at(x, y + 1)->base_height);
|
|
break;
|
|
case 2:
|
|
highestOnLowestSide = max(
|
|
map_get_surface_element_at(x - 1, y)->base_height,
|
|
map_get_surface_element_at(x, y - 1)->base_height);
|
|
break;
|
|
case 3:
|
|
highestOnLowestSide = max(
|
|
map_get_surface_element_at(x + 1, y)->base_height,
|
|
map_get_surface_element_at(x, y - 1)->base_height);
|
|
break;
|
|
}
|
|
|
|
if (highestOnLowestSide > mapElement->base_height){
|
|
mapElement->base_height = mapElement->clearance_height = highestOnLowestSide;
|
|
raisedLand = 1;
|
|
canCompensate = 0;
|
|
}
|
|
}
|
|
|
|
if (count == 1 && canCompensate) {
|
|
if (mapElement->base_height < highest - 4) {
|
|
mapElement->base_height = mapElement->clearance_height = highest - 4;
|
|
raisedLand = 1;
|
|
}
|
|
if (cornerHeights[0] == highest && cornerHeights[2] <= cornerHeights[0] - 4)
|
|
doubleCorner = 0;
|
|
else if (cornerHeights[1] == highest && cornerHeights[3] <= cornerHeights[1] - 4)
|
|
doubleCorner = 1;
|
|
else if (cornerHeights[2] == highest && cornerHeights[0] <= cornerHeights[2] - 4)
|
|
doubleCorner = 2;
|
|
else if (cornerHeights[3] == highest && cornerHeights[1] <= cornerHeights[3] - 4)
|
|
doubleCorner = 3;
|
|
} else {
|
|
if (mapElement->base_height < highest - 2) {
|
|
mapElement->base_height = mapElement->clearance_height = highest - 2;
|
|
raisedLand = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (doubleCorner != -1) {
|
|
mapElement->properties.surface.slope |= 16;
|
|
switch (doubleCorner) {
|
|
case 0:
|
|
mapElement->properties.surface.slope |= 2 | 4 | 8;
|
|
break;
|
|
case 1:
|
|
mapElement->properties.surface.slope |= 1 | 2 | 4;
|
|
break;
|
|
case 2:
|
|
mapElement->properties.surface.slope |= 1 | 2 | 8;
|
|
break;
|
|
case 3:
|
|
mapElement->properties.surface.slope |= 1 | 4 | 8;
|
|
break;
|
|
}
|
|
} else {
|
|
// Corners
|
|
mapElement2 = map_get_surface_element_at(x + 1, y + 1);
|
|
if (mapElement2->base_height > mapElement->base_height)
|
|
mapElement->properties.surface.slope |= 1;
|
|
|
|
mapElement2 = map_get_surface_element_at(x - 1, y + 1);
|
|
if (mapElement2->base_height > mapElement->base_height)
|
|
mapElement->properties.surface.slope |= 8;
|
|
|
|
mapElement2 = map_get_surface_element_at(x + 1, y - 1);
|
|
if (mapElement2->base_height > mapElement->base_height)
|
|
mapElement->properties.surface.slope |= 2;
|
|
|
|
mapElement2 = map_get_surface_element_at(x - 1, y - 1);
|
|
if (mapElement2->base_height > mapElement->base_height)
|
|
mapElement->properties.surface.slope |= 4;
|
|
|
|
// Sides
|
|
mapElement2 = map_get_surface_element_at(x + 1, y + 0);
|
|
if (mapElement2->base_height > mapElement->base_height)
|
|
mapElement->properties.surface.slope |= 1 | 2;
|
|
|
|
mapElement2 = map_get_surface_element_at(x - 1, y + 0);
|
|
if (mapElement2->base_height > mapElement->base_height)
|
|
mapElement->properties.surface.slope |= 4 | 8;
|
|
|
|
mapElement2 = map_get_surface_element_at(x + 0, y - 1);
|
|
if (mapElement2->base_height > mapElement->base_height)
|
|
mapElement->properties.surface.slope |= 2 | 4;
|
|
|
|
mapElement2 = map_get_surface_element_at(x + 0, y + 1);
|
|
if (mapElement2->base_height > mapElement->base_height)
|
|
mapElement->properties.surface.slope |= 1 | 8;
|
|
|
|
// Raise
|
|
if (mapElement->properties.surface.slope == (1 | 2 | 4 | 8)) {
|
|
mapElement->properties.surface.slope &= ~0x1F;
|
|
mapElement->base_height = mapElement->clearance_height += 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return raisedLand;
|
|
}
|
|
|
|
static int map_get_corner_height(int x, int y, int corner)
|
|
{
|
|
rct_map_element *mapElement = map_get_surface_element_at(x, y);
|
|
int baseHeight = mapElement->base_height;
|
|
int slope = mapElement->properties.surface.slope;
|
|
int doubleCorner = slope & 16;
|
|
if (doubleCorner) {
|
|
if (!(slope & 1)) doubleCorner = 4;
|
|
else if (!(slope & 2)) doubleCorner = 8;
|
|
else if (!(slope & 4)) doubleCorner = 1;
|
|
else if (!(slope & 8)) doubleCorner = 2;
|
|
}
|
|
|
|
switch (corner) {
|
|
case 0:
|
|
return baseHeight + (slope & 1 ? (doubleCorner == 1 ? 4 : 2) : 0);
|
|
case 1:
|
|
return baseHeight + (slope & 8 ? (doubleCorner == 8 ? 4 : 2) : 0);
|
|
case 2:
|
|
return baseHeight + (slope & 2 ? (doubleCorner == 2 ? 4 : 2) : 0);
|
|
case 3:
|
|
return baseHeight + (slope & 4 ? (doubleCorner == 4 ? 4 : 2) : 0);
|
|
default:
|
|
return baseHeight;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* There are non-smoothed tiles with this version, but diagonal land blocks end up being wavy.
|
|
*/
|
|
static int map_smooth_wavy(int l, int t, int r, int b)
|
|
{
|
|
int i, x, y, highest, count, cornerHeights[4], doubleCorner, raisedLand = 0;
|
|
rct_map_element *mapElement;
|
|
for (y = t; y < b; y++) {
|
|
for (x = l; x < r; x++) {
|
|
mapElement = map_get_surface_element_at(x, y);
|
|
mapElement->properties.surface.slope &= ~0x1F;
|
|
|
|
// Raise to edge height - 2
|
|
highest = mapElement->base_height;
|
|
highest = max(highest, map_get_surface_element_at(x - 1, y + 0)->base_height);
|
|
highest = max(highest, map_get_surface_element_at(x + 1, y + 0)->base_height);
|
|
highest = max(highest, map_get_surface_element_at(x + 0, y - 1)->base_height);
|
|
highest = max(highest, map_get_surface_element_at(x + 0, y + 1)->base_height);
|
|
if (mapElement->base_height < highest - 2) {
|
|
raisedLand = 1;
|
|
mapElement->base_height = mapElement->clearance_height = highest - 2;
|
|
}
|
|
|
|
// Check corners
|
|
doubleCorner = -1;
|
|
cornerHeights[0] = max(map_get_corner_height(x - 1, y - 1, 0), max(map_get_corner_height(x + 1, y + 0, 1), map_get_corner_height(x + 0, y + 1, 2)));
|
|
cornerHeights[1] = max(map_get_corner_height(x + 1, y - 1, 1), max(map_get_corner_height(x - 1, y + 0, 0), map_get_corner_height(x + 0, y + 1, 3)));
|
|
cornerHeights[2] = max(map_get_corner_height(x + 1, y + 1, 3), max(map_get_corner_height(x + 1, y + 0, 3), map_get_corner_height(x + 0, y - 1, 0)));
|
|
cornerHeights[3] = max(map_get_corner_height(x - 1, y + 1, 2), max(map_get_corner_height(x - 1, y + 0, 2), map_get_corner_height(x + 0, y - 1, 1)));
|
|
highest = mapElement->base_height;
|
|
for (i = 0; i < 4; i++)
|
|
highest = max(highest, cornerHeights[i]);
|
|
|
|
if (highest >= mapElement->base_height + 4) {
|
|
count = 0;
|
|
for (i = 0; i < 4; i++)
|
|
if (cornerHeights[i] == highest)
|
|
count++;
|
|
|
|
if (count == 1) {
|
|
if (mapElement->base_height < highest - 4) {
|
|
mapElement->base_height = mapElement->clearance_height = highest - 4;
|
|
raisedLand = 1;
|
|
}
|
|
if (cornerHeights[0] == highest && cornerHeights[2] <= cornerHeights[0] - 4)
|
|
doubleCorner = 0;
|
|
else if (cornerHeights[1] == highest && cornerHeights[3] <= cornerHeights[1] - 4)
|
|
doubleCorner = 1;
|
|
else if (cornerHeights[2] == highest && cornerHeights[0] <= cornerHeights[2] - 4)
|
|
doubleCorner = 2;
|
|
else if (cornerHeights[3] == highest && cornerHeights[1] <= cornerHeights[3] - 4)
|
|
doubleCorner = 3;
|
|
} else {
|
|
if (mapElement->base_height < highest - 2) {
|
|
mapElement->base_height = mapElement->clearance_height = highest - 2;
|
|
raisedLand = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (doubleCorner != -1) {
|
|
mapElement->properties.surface.slope |= 16;
|
|
switch (doubleCorner) {
|
|
case 0:
|
|
mapElement->properties.surface.slope |= 2 | 4 | 8;
|
|
break;
|
|
case 1:
|
|
mapElement->properties.surface.slope |= 1 | 2 | 4;
|
|
break;
|
|
case 2:
|
|
mapElement->properties.surface.slope |= 1 | 2 | 8;
|
|
break;
|
|
case 3:
|
|
mapElement->properties.surface.slope |= 1 | 4 | 8;
|
|
break;
|
|
}
|
|
} else {
|
|
// Corners
|
|
if (
|
|
map_get_corner_height(x + 1, y + 1, 3) > mapElement->base_height ||
|
|
map_get_corner_height(x + 1, y + 0, 1) > mapElement->base_height ||
|
|
map_get_corner_height(x + 0, y + 1, 2) > mapElement->base_height
|
|
)
|
|
mapElement->properties.surface.slope |= 1;
|
|
|
|
if (
|
|
map_get_corner_height(x - 1, y + 1, 2) > mapElement->base_height ||
|
|
map_get_corner_height(x - 1, y + 0, 0) > mapElement->base_height ||
|
|
map_get_corner_height(x + 0, y + 1, 3) > mapElement->base_height
|
|
)
|
|
mapElement->properties.surface.slope |= 8;
|
|
|
|
if (
|
|
map_get_corner_height(x + 1, y - 1, 1) > mapElement->base_height ||
|
|
map_get_corner_height(x + 1, y + 0, 3) > mapElement->base_height ||
|
|
map_get_corner_height(x + 0, y - 1, 0) > mapElement->base_height
|
|
)
|
|
mapElement->properties.surface.slope |= 2;
|
|
|
|
if (
|
|
map_get_corner_height(x - 1, y - 1, 0) > mapElement->base_height ||
|
|
map_get_corner_height(x - 1, y + 0, 2) > mapElement->base_height ||
|
|
map_get_corner_height(x + 0, y - 1, 1) > mapElement->base_height
|
|
)
|
|
mapElement->properties.surface.slope |= 4;
|
|
|
|
// Raise
|
|
if (mapElement->properties.surface.slope == (1 | 2 | 4 | 8)) {
|
|
mapElement->properties.surface.slope &= ~0x1F;
|
|
mapElement->base_height = mapElement->clearance_height += 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return raisedLand;
|
|
}
|