mirror of https://github.com/OpenRCT2/OpenRCT2.git
implement footpath_connect_edges
This commit is contained in:
parent
ef7603013e
commit
0ab33d67e8
|
@ -1291,7 +1291,7 @@ int track_place_scenery(rct_track_scenery* scenery_start, uint8 rideIndex, int o
|
|||
if (RCT2_GLOBAL(0x00F440D4, uint8) == 5)bl = 41;
|
||||
if (RCT2_GLOBAL(0x00F440D4, uint8) == 4)bl = 105;
|
||||
|
||||
sub_6A6C66(mapCoord.x, mapCoord.y, map_element, bl);
|
||||
footpath_connect_edges(mapCoord.x, mapCoord.y, map_element, bl);
|
||||
sub_6A759F();
|
||||
continue;
|
||||
}
|
||||
|
@ -3888,7 +3888,7 @@ static money32 track_place(int rideIndex, int type, int originX, int originY, in
|
|||
mapElement = surfaceElement;
|
||||
}
|
||||
|
||||
sub_6A6C66(x, y, mapElement, flags);
|
||||
footpath_connect_edges(x, y, mapElement, flags);
|
||||
map_invalidate_tile_full(x, y);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include "scenery.h"
|
||||
|
||||
void footpath_interrupt_peeps(int x, int y, int z);
|
||||
void sub_6A7642(int x, int y, rct_map_element *mapElement);
|
||||
void sub_6A76E9(int rideIndex);
|
||||
|
||||
enum {
|
||||
FOOTPATH_CONSTRUCTION_FLAG_ALLOW_DURING_PAUSED = 1 << 3
|
||||
|
@ -113,7 +115,7 @@ static void loc_6A6620(int flags, int x, int y, rct_map_element *mapElement)
|
|||
}
|
||||
|
||||
if (!(flags & (1 << 7)))
|
||||
sub_6A6C66(x, y, mapElement, flags);
|
||||
footpath_connect_edges(x, y, mapElement, flags);
|
||||
|
||||
sub_6A759F();
|
||||
map_invalidate_tile_full(x, y);
|
||||
|
@ -392,10 +394,15 @@ money32 footpath_remove_real(int x, int y, int z, int flags)
|
|||
*/
|
||||
void game_command_place_footpath(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp)
|
||||
{
|
||||
if (*ebx & (1 << 5))
|
||||
RCT2_CALLFUNC_X(0x006A61DE, eax, ebx, ecx, edx, esi, edi, ebp);
|
||||
else
|
||||
*ebx = footpath_place_real((*edx >> 8) & 0xFF, *eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, (*ebx >> 8) & 0xFF, *ebx & 0xFF, *edi & 0xFF);
|
||||
*ebx = footpath_place_real(
|
||||
(*edx >> 8) & 0xFF,
|
||||
*eax & 0xFFFF,
|
||||
*ecx & 0xFFFF,
|
||||
*edx & 0xFF,
|
||||
(*ebx >> 8) & 0xFF,
|
||||
*ebx & 0xFF,
|
||||
*edi & 0xFF
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -674,13 +681,352 @@ void footpath_interrupt_peeps(int x, int y, int z)
|
|||
}
|
||||
}
|
||||
|
||||
bool sub_6E59DC(int x, int y, int z0, int z1, int direction)
|
||||
{
|
||||
rct_map_element *mapElement;
|
||||
|
||||
mapElement = map_get_first_element_at(x >> 5, y >> 5);
|
||||
do {
|
||||
if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_FENCE)
|
||||
continue;
|
||||
if (mapElement->flags & MAP_ELEMENT_FLAG_GHOST)
|
||||
continue;
|
||||
if (z0 >= mapElement->clearance_height)
|
||||
continue;
|
||||
if (z1 <= mapElement->base_height)
|
||||
continue;
|
||||
if ((mapElement->type & MAP_ELEMENT_DIRECTION_MASK) != direction)
|
||||
continue;
|
||||
|
||||
return true;
|
||||
} while (!map_element_is_last_for_tile(mapElement++));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool map_is_edge(int x, int y)
|
||||
{
|
||||
return (
|
||||
x < 32 ||
|
||||
y < 32 ||
|
||||
x >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16) ||
|
||||
y >= RCT2_GLOBAL(RCT2_ADDRESS_MAP_SIZE_UNITS, uint16)
|
||||
);
|
||||
}
|
||||
|
||||
static rct_map_element *footpath_connect_corners_get_neighbour(int x, int y, int z, int requireEdges)
|
||||
{
|
||||
rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5);
|
||||
do {
|
||||
if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH)
|
||||
continue;
|
||||
if (footpath_element_is_queue(mapElement))
|
||||
continue;
|
||||
if (mapElement->base_height != z)
|
||||
continue;
|
||||
if (!(mapElement->properties.path.edges & requireEdges))
|
||||
continue;
|
||||
|
||||
return mapElement;
|
||||
} while (!map_element_is_last_for_tile(mapElement++));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the corner edges of four path tiles.
|
||||
* The function will search for a path in the direction given, then check clockwise to see if it there is a path and again until
|
||||
* it reaches the initial path. In other words, checks if there are four paths together so that it can set the inner corners of
|
||||
* each one.
|
||||
*
|
||||
* rct2: 0x006A70EB
|
||||
*/
|
||||
static void footpath_connect_corners(int initialX, int initialY, rct_map_element *initialMapElement)
|
||||
{
|
||||
rct_map_element *mapElement[4];
|
||||
|
||||
if (footpath_element_is_queue(initialMapElement))
|
||||
return;
|
||||
if (footpath_element_is_sloped(initialMapElement))
|
||||
return;
|
||||
|
||||
mapElement[0] = initialMapElement;
|
||||
int z = initialMapElement->base_height;
|
||||
for (int initialDirection = 0; initialDirection < 4; initialDirection++) {
|
||||
int x = initialX;
|
||||
int y = initialY;
|
||||
int direction = initialDirection;
|
||||
|
||||
x += TileDirectionDelta[direction].x;
|
||||
y += TileDirectionDelta[direction].y;
|
||||
mapElement[1] = footpath_connect_corners_get_neighbour(x, y, z, (1 << (direction ^ 2)));
|
||||
if (mapElement[1] == NULL)
|
||||
continue;
|
||||
|
||||
direction = (direction + 1) & 3;
|
||||
x += TileDirectionDelta[direction].x;
|
||||
y += TileDirectionDelta[direction].y;
|
||||
mapElement[2] = footpath_connect_corners_get_neighbour(x, y, z, (1 << (direction ^ 2)));
|
||||
if (mapElement[2] == NULL)
|
||||
continue;
|
||||
|
||||
direction = (direction + 1) & 3;
|
||||
x += TileDirectionDelta[direction].x;
|
||||
y += TileDirectionDelta[direction].y;
|
||||
mapElement[3] = footpath_connect_corners_get_neighbour(x, y, z, (1 << (direction ^ 2)) | (1 << (((direction ^ 2) - 1) & 3)));
|
||||
if (mapElement[3] == NULL)
|
||||
continue;
|
||||
|
||||
direction = (direction + 1) & 3;
|
||||
mapElement[3]->properties.path.edges |= (1 << (direction + 4));
|
||||
map_invalidate_element(x, y, mapElement[3]);
|
||||
|
||||
direction = (direction - 1) & 3;
|
||||
mapElement[2]->properties.path.edges |= (1 << (direction + 4));
|
||||
map_invalidate_element(x, y, mapElement[2]);
|
||||
|
||||
direction = (direction - 1) & 3;
|
||||
mapElement[1]->properties.path.edges |= (1 << (direction + 4));
|
||||
map_invalidate_element(x, y, mapElement[1]);
|
||||
|
||||
direction = (direction - 1) & 3;
|
||||
mapElement[0]->properties.path.edges |= (1 << (direction + 4));
|
||||
map_invalidate_element(x, y, mapElement[0]);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint8 order;
|
||||
uint8 direction;
|
||||
} rct_neighbour;
|
||||
|
||||
typedef struct {
|
||||
rct_neighbour items[8];
|
||||
int count;
|
||||
} rct_neighbour_list;
|
||||
|
||||
static int rct_neighbour_compare(const void *a, const void *b)
|
||||
{
|
||||
uint8 va = ((rct_neighbour*)a)->order;
|
||||
uint8 vb = ((rct_neighbour*)b)->order;
|
||||
if (va < vb) return 1;
|
||||
else if (va == vb) return 0;
|
||||
else return -1;
|
||||
}
|
||||
|
||||
static void neighbour_list_init(rct_neighbour_list *neighbourList)
|
||||
{
|
||||
neighbourList->count = 0;
|
||||
}
|
||||
|
||||
static void neighbour_list_push(rct_neighbour_list *neighbourList, int order, int direction)
|
||||
{
|
||||
neighbourList->items[neighbourList->count].order = order;
|
||||
neighbourList->items[neighbourList->count].direction = direction;
|
||||
neighbourList->count++;
|
||||
}
|
||||
|
||||
static bool neighbour_list_pop(rct_neighbour_list *neighbourList, rct_neighbour *outNeighbour)
|
||||
{
|
||||
if (neighbourList->count == 0)
|
||||
return false;
|
||||
|
||||
*outNeighbour = neighbourList->items[0];
|
||||
for (int i = 0; i < neighbourList->count - 1; i++)
|
||||
neighbourList->items[i] = neighbourList->items[i + 1];
|
||||
neighbourList->count--;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void neighbour_list_sort(rct_neighbour_list *neighbourList)
|
||||
{
|
||||
qsort(neighbourList->items, neighbourList->count, sizeof(rct_neighbour), rct_neighbour_compare);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006A6D7E
|
||||
*/
|
||||
static void loc_6A6D7E(
|
||||
int initialX, int initialY, int z, int direction, rct_map_element *initialMapElement,
|
||||
int flags, bool query, rct_neighbour_list *neighbourList
|
||||
) {
|
||||
int x = initialX + TileDirectionDelta[direction].x;
|
||||
int y = initialY + TileDirectionDelta[direction].y;
|
||||
if (((RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_SCENARIO_EDITOR) || gSandboxMode) && map_is_edge(x, y)) {
|
||||
if (query) {
|
||||
neighbour_list_push(neighbourList, 7, direction);
|
||||
}
|
||||
} else {
|
||||
rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5);
|
||||
do {
|
||||
switch (map_element_get_type(mapElement)) {
|
||||
case MAP_ELEMENT_TYPE_PATH:
|
||||
if (z == mapElement->base_height) {
|
||||
if (footpath_element_is_sloped(mapElement) && footpath_element_get_slope_direction(mapElement) != direction) {
|
||||
return;
|
||||
} else {
|
||||
goto loc_6A6F1F;
|
||||
}
|
||||
}
|
||||
if (z + 2 == mapElement->base_height) {
|
||||
if (footpath_element_is_sloped(mapElement)) {
|
||||
if (footpath_element_get_slope_direction(mapElement) != (direction ^ 2)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
goto loc_6A6F1F;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MAP_ELEMENT_TYPE_TRACK:
|
||||
if (z == mapElement->base_height) {
|
||||
rct_ride *ride = GET_RIDE(mapElement->properties.track.ride_index);
|
||||
if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) {
|
||||
continue;
|
||||
}
|
||||
uint16 di = (mapElement->properties.track.sequence & 0x0F) | (mapElement->properties.track.type << 4);
|
||||
if (!(RCT2_ADDRESS(0x0099CA64, uint8)[di] & (1 << 5))) {
|
||||
return;
|
||||
}
|
||||
uint16 dx = (direction - mapElement->type) & 3;
|
||||
if (!(RCT2_ADDRESS(0x0099CA64, uint16)[di / 2] & (1 << dx))) {
|
||||
return;
|
||||
}
|
||||
if (query) {
|
||||
neighbour_list_push(neighbourList, 1, direction);
|
||||
}
|
||||
goto loc_6A6FD2;
|
||||
}
|
||||
break;
|
||||
case MAP_ELEMENT_TYPE_ENTRANCE:
|
||||
if (z == mapElement->base_height) {
|
||||
uint8 cl = (mapElement->properties.entrance.index & 0x0F) | (mapElement->properties.entrance.type << 4);
|
||||
uint8 al = ((direction - mapElement->type) & 3) ^ 2;
|
||||
if (!(RCT2_ADDRESS(0x0097B974, uint16)[cl / 2] & (1 << al))) {
|
||||
return;
|
||||
}
|
||||
if (query) {
|
||||
neighbour_list_push(neighbourList, 8, direction);
|
||||
} else {
|
||||
if (mapElement->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE) {
|
||||
sub_6A76E9(mapElement->properties.entrance.ride_index);
|
||||
}
|
||||
}
|
||||
goto loc_6A6FD2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (!map_element_is_last_for_tile(mapElement++));
|
||||
return;
|
||||
|
||||
loc_6A6F1F:
|
||||
if (query) {
|
||||
if (sub_6E59DC(x, y, mapElement->base_height, mapElement->clearance_height, direction & 2)) {
|
||||
return;
|
||||
}
|
||||
if (footpath_element_is_queue(mapElement)) {
|
||||
if (RCT2_ADDRESS(0x0098D7F0, uint8)[mapElement->properties.path.edges & 0x0F] < 2) {
|
||||
neighbour_list_push(neighbourList, 3, direction);
|
||||
}
|
||||
} else {
|
||||
neighbour_list_push(neighbourList, 2, direction);
|
||||
}
|
||||
} else {
|
||||
mapElement->properties.path.edges |= (1 << (direction ^ 2));
|
||||
if (footpath_element_is_queue(mapElement)) {
|
||||
sub_6A76E9(mapElement->properties.path.ride_index);
|
||||
}
|
||||
}
|
||||
if (!(flags & 0x48)) {
|
||||
footpath_interrupt_peeps(x, y, mapElement->base_height * 8);
|
||||
}
|
||||
map_invalidate_element(x, y, mapElement);
|
||||
}
|
||||
|
||||
loc_6A6FD2:
|
||||
if (map_element_get_type(initialMapElement) == MAP_ELEMENT_TYPE_PATH) {
|
||||
if (!query) {
|
||||
initialMapElement->properties.path.edges |= (1 << direction);
|
||||
map_invalidate_element(initialX, initialY, initialMapElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void loc_6A6C85(
|
||||
int x, int y, int direction, rct_map_element *mapElement,
|
||||
int flags, bool query, rct_neighbour_list *neighbourList
|
||||
) {
|
||||
if (query && sub_6E59DC(x, y, mapElement->base_height, mapElement->clearance_height, direction))
|
||||
return;
|
||||
|
||||
if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE) {
|
||||
uint16 di = (mapElement->properties.entrance.index & 0x0F) | (mapElement->properties.entrance.type << 4);
|
||||
uint16 dx = (direction - mapElement->type) & 3;
|
||||
if (RCT2_ADDRESS(0x0097B974, uint16)[di / 2] & (1 << dx)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_TRACK) {
|
||||
rct_ride *ride = GET_RIDE(mapElement->properties.track.ride_index);
|
||||
if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) {
|
||||
return;
|
||||
}
|
||||
uint16 di = (mapElement->properties.track.sequence & 0x0F) | (mapElement->properties.track.type << 4);
|
||||
if (!(RCT2_ADDRESS(0x0099CA64, uint8)[di] & (1 << 5))) {
|
||||
return;
|
||||
}
|
||||
uint16 dx = (direction - mapElement->type) & 3;
|
||||
if (!(RCT2_ADDRESS(0x0099CA64, uint16)[di / 2] & (1 << dx))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int z = mapElement->base_height;
|
||||
if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) {
|
||||
if (footpath_element_is_sloped(mapElement)) {
|
||||
if ((footpath_element_get_slope_direction(mapElement) - direction) & 1) {
|
||||
return;
|
||||
}
|
||||
if (footpath_element_get_slope_direction(mapElement) == direction) {
|
||||
z += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loc_6A6D7E(x, y, z, direction, mapElement, flags, query, neighbourList);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006A6C66
|
||||
*/
|
||||
void sub_6A6C66(int x, int y, rct_map_element *mapElement, int flags)
|
||||
void footpath_connect_edges(int x, int y, rct_map_element *mapElement, int flags)
|
||||
{
|
||||
RCT2_CALLPROC_X(0x006A6C66, x, flags, y, 0, (int)mapElement, 0, 0);
|
||||
rct_neighbour_list neighbourList;
|
||||
rct_neighbour neighbour;
|
||||
|
||||
neighbour_list_init(&neighbourList);
|
||||
|
||||
sub_6A7642(x, y, mapElement);
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
loc_6A6C85(x, y, direction, mapElement, flags, true, &neighbourList);
|
||||
}
|
||||
|
||||
neighbour_list_sort(&neighbourList);
|
||||
|
||||
if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) {
|
||||
if (footpath_element_is_queue(mapElement)) {
|
||||
neighbourList.count = min(neighbourList.count, 2);
|
||||
}
|
||||
}
|
||||
|
||||
while (neighbour_list_pop(&neighbourList, &neighbour)) {
|
||||
loc_6A6C85(x, y, neighbour.direction, mapElement, flags, false, NULL);
|
||||
}
|
||||
|
||||
if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) {
|
||||
footpath_connect_corners(x, y, mapElement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -58,7 +58,7 @@ void footpath_provisional_update();
|
|||
void footpath_get_coordinates_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement);
|
||||
void footpath_bridge_get_info_from_pos(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement);
|
||||
void footpath_remove_litter(int x, int y, int z);
|
||||
void sub_6A6C66(int x, int y, rct_map_element *mapElement, int flags);
|
||||
void footpath_connect_edges(int x, int y, rct_map_element *mapElement, int flags);
|
||||
void sub_6A759F();
|
||||
void footpath_chain_ride_queue(int rideIndex, int entranceIndex, int x, int y, rct_map_element *mapElement, int direction);
|
||||
|
||||
|
|
|
@ -3528,3 +3528,8 @@ void map_invalidate_tile_full(int x, int y)
|
|||
{
|
||||
map_invalidate_tile(x, y, 0, 2080);
|
||||
}
|
||||
|
||||
void map_invalidate_element(int x, int y, rct_map_element *mapElement)
|
||||
{
|
||||
map_invalidate_tile(x, y, mapElement->base_height, mapElement->clearance_height);
|
||||
}
|
||||
|
|
|
@ -349,5 +349,6 @@ void map_invalidate_tile(int x, int y, int z0, int z1);
|
|||
void map_invalidate_tile_zoom1(int x, int y, int z0, int z1);
|
||||
void map_invalidate_tile_zoom0(int x, int y, int z0, int z1);
|
||||
void map_invalidate_tile_full(int x, int y);
|
||||
void map_invalidate_element(int x, int y, rct_map_element *mapElement);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue