implement footpath_connect_edges

This commit is contained in:
IntelOrca 2015-07-07 19:09:12 +01:00
parent ef7603013e
commit 0ab33d67e8
5 changed files with 362 additions and 10 deletions

View File

@ -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);
}

View File

@ -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);
}
}
/**

View File

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

View File

@ -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);
}

View File

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