mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-31 10:45:16 +01:00
This commit expands tabs to spaces (ts=4) in all the files under src/ and test/. Until now we had two wildly different code styles with C using tabs and new C++ using spaces. It is painful to maintain as none of the commonly used tools support this kind of setup and in reality is needless, as we can simply convert all the sources to spaces and have opened PRs do the same, where needed. Additionally, trailing whitespace has been removed.
864 lines
26 KiB
C++
864 lines
26 KiB
C++
#pragma region Copyright (c) 2014-2017 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 "../rct2.h"
|
|
#include "../network/network.h"
|
|
|
|
extern "C"
|
|
{
|
|
#include "entrance.h"
|
|
#include "footpath.h"
|
|
#include "map.h"
|
|
#include "park.h"
|
|
#include "../cheats.h"
|
|
#include "../game.h"
|
|
#include "../localisation/string_ids.h"
|
|
#include "../management/finance.h"
|
|
#include "../ride/track.h"
|
|
}
|
|
|
|
bool gParkEntranceGhostExists = false;
|
|
rct_xyz16 gParkEntranceGhostPosition = { 0, 0, 0 };
|
|
uint8 gParkEntranceGhostDirection = 0;
|
|
rct_xyzd16 gParkEntrances[MAX_PARK_ENTRANCES];
|
|
|
|
rct_xyzd16 gRideEntranceExitGhostPosition;
|
|
uint8 gRideEntranceExitGhostStationIndex;
|
|
|
|
static money32 ParkEntrancePlace(sint32 flags, sint16 x, sint16 y, uint8 z, uint8 direction)
|
|
{
|
|
if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode)
|
|
{
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LAND_PURCHASE;
|
|
|
|
gCommandPosition.x = x;
|
|
gCommandPosition.y = y;
|
|
gCommandPosition.z = z * 16;
|
|
|
|
if (!map_check_free_elements_and_reorganise(3))
|
|
{
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (x <= 32 || y <= 32 || x >= (gMapSizeUnits - 32) || y >= (gMapSizeUnits - 32))
|
|
{
|
|
gGameCommandErrorText = STR_TOO_CLOSE_TO_EDGE_OF_MAP;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
sint8 entranceNum = -1;
|
|
for (uint8 i = 0; i < MAX_PARK_ENTRANCES; ++i)
|
|
{
|
|
if (gParkEntrances[i].x == MAP_LOCATION_NULL)
|
|
{
|
|
entranceNum = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (entranceNum == -1)
|
|
{
|
|
gGameCommandErrorText = STR_ERR_TOO_MANY_PARK_ENTRANCES;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (flags & GAME_COMMAND_FLAG_APPLY)
|
|
{
|
|
gParkEntrances[entranceNum].x = x;
|
|
gParkEntrances[entranceNum].y = y;
|
|
gParkEntrances[entranceNum].z = z * 16;
|
|
gParkEntrances[entranceNum].direction = direction;
|
|
}
|
|
|
|
sint8 zLow = z * 2;
|
|
sint8 zHigh = zLow + 12;
|
|
|
|
for (uint8 index = 0; index < 3; index++)
|
|
{
|
|
if (index == 1)
|
|
{
|
|
x += TileDirectionDelta[(direction - 1) & 0x3].x;
|
|
y += TileDirectionDelta[(direction - 1) & 0x3].y;
|
|
}
|
|
else if (index == 2)
|
|
{
|
|
x += TileDirectionDelta[(direction + 1) & 0x3].x * 2;
|
|
y += TileDirectionDelta[(direction + 1) & 0x3].y * 2;
|
|
}
|
|
|
|
if (!gCheatsDisableClearanceChecks)
|
|
{
|
|
if (!map_can_construct_at(x, y, zLow, zHigh, 0xF))
|
|
{
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
}
|
|
|
|
// Check that entrance element does not already exist at this location
|
|
rct_map_element* entranceElement = map_get_park_entrance_element_at(x, y, zLow, false);
|
|
if (entranceElement != NULL)
|
|
{
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (!(flags & GAME_COMMAND_FLAG_APPLY))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (!(flags & GAME_COMMAND_FLAG_GHOST))
|
|
{
|
|
rct_map_element* surfaceElement = map_get_surface_element_at(x / 32, y / 32);
|
|
surfaceElement->properties.surface.ownership = 0;
|
|
}
|
|
|
|
rct_map_element* newElement = map_element_insert(x / 32, y / 32, zLow, 0xF);
|
|
assert(newElement != NULL);
|
|
newElement->clearance_height = zHigh;
|
|
|
|
if (flags & GAME_COMMAND_FLAG_GHOST)
|
|
{
|
|
newElement->flags |= MAP_ELEMENT_FLAG_GHOST;
|
|
}
|
|
|
|
newElement->type = MAP_ELEMENT_TYPE_ENTRANCE;
|
|
newElement->type |= direction;
|
|
newElement->properties.entrance.index = index;
|
|
newElement->properties.entrance.type = ENTRANCE_TYPE_PARK_ENTRANCE;
|
|
newElement->properties.entrance.path_type = gFootpathSelectedId;
|
|
|
|
if (!(flags & GAME_COMMAND_FLAG_GHOST))
|
|
{
|
|
footpath_connect_edges(x, y, newElement, 1);
|
|
}
|
|
|
|
update_park_fences_around_tile(x, y);
|
|
|
|
map_invalidate_tile(x, y, newElement->base_height * 8, newElement->clearance_height * 8);
|
|
|
|
if (index == 0)
|
|
{
|
|
map_animation_create(MAP_ANIMATION_TYPE_PARK_ENTRANCE, x, y, zLow);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void ParkEntranceRemoveSegment(sint32 x, sint32 y, sint32 z)
|
|
{
|
|
rct_map_element *mapElement;
|
|
|
|
mapElement = map_get_park_entrance_element_at(x, y, z, true);
|
|
if (mapElement == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8);
|
|
map_element_remove(mapElement);
|
|
update_park_fences(x, y);
|
|
}
|
|
|
|
static money32 ParkEntranceRemove(sint16 x, sint16 y, uint8 z, uint8 flags)
|
|
{
|
|
sint32 entranceIndex, direction;
|
|
|
|
if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode)
|
|
{
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LAND_PURCHASE;
|
|
gCommandPosition.x = x;
|
|
gCommandPosition.y = y;
|
|
gCommandPosition.z = z * 16;
|
|
|
|
if (!(flags & GAME_COMMAND_FLAG_APPLY))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
entranceIndex = park_entrance_get_index(x, y, z * 16);
|
|
if (entranceIndex == -1)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
gParkEntrances[entranceIndex].x = MAP_LOCATION_NULL;
|
|
direction = (gParkEntrances[entranceIndex].direction - 1) & 3;
|
|
|
|
// Centre (sign)
|
|
ParkEntranceRemoveSegment(x, y, z * 2);
|
|
|
|
// Left post
|
|
ParkEntranceRemoveSegment(
|
|
x + TileDirectionDelta[direction].x,
|
|
y + TileDirectionDelta[direction].y,
|
|
z * 2
|
|
);
|
|
|
|
// Right post
|
|
ParkEntranceRemoveSegment(
|
|
x - TileDirectionDelta[direction].x,
|
|
y - TileDirectionDelta[direction].y,
|
|
z * 2
|
|
);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static money32 RideEntranceExitPlace(sint16 x,
|
|
sint16 y,
|
|
sint16 z,
|
|
uint8 direction,
|
|
uint8 flags,
|
|
uint8 rideIndex,
|
|
uint8 stationNum,
|
|
bool isExit)
|
|
{
|
|
// Remember when in unknown station num mode rideIndex is unknown and z is set
|
|
// When in known station num mode rideIndex is known and z is unknown
|
|
|
|
money32 cost = 0;
|
|
gCommandPosition.x = x;
|
|
gCommandPosition.y = y;
|
|
|
|
if (!map_check_free_elements_and_reorganise(1))
|
|
{
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (!(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) && game_is_paused() && !gCheatsBuildInPauseMode)
|
|
{
|
|
gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (stationNum == 0xFF)
|
|
{
|
|
z *= 16;
|
|
if (flags & GAME_COMMAND_FLAG_APPLY)
|
|
{
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (!gCheatsSandboxMode && !map_is_location_owned(x, y, z))
|
|
{
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
sint16 clear_z = z / 8 + (isExit ? 5 : 7);
|
|
|
|
if (!gCheatsDisableClearanceChecks &&
|
|
!map_can_construct_with_clear_at(x, y, z / 8, clear_z, &map_place_non_scenery_clear_func, 0xF, flags, &cost))
|
|
{
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (gMapGroundFlags & ELEMENT_IS_UNDERWATER)
|
|
{
|
|
gGameCommandErrorText = STR_RIDE_CANT_BUILD_THIS_UNDERWATER;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (z / 8 > 244)
|
|
{
|
|
gGameCommandErrorText = STR_TOO_HIGH;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (rideIndex >= MAX_RIDES)
|
|
{
|
|
log_warning("Invalid game command for ride %u", rideIndex);
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
rct_ride* ride = get_ride(rideIndex);
|
|
if (ride->type == RIDE_TYPE_NULL)
|
|
{
|
|
log_warning("Invalid game command for ride %u", rideIndex);
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (ride->status != RIDE_STATUS_CLOSED)
|
|
{
|
|
gGameCommandErrorText = STR_MUST_BE_CLOSED_FIRST;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK)
|
|
{
|
|
gGameCommandErrorText = STR_NOT_ALLOWED_TO_MODIFY_STATION;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
ride_clear_for_construction(rideIndex);
|
|
ride_remove_peeps(rideIndex);
|
|
|
|
bool requiresRemove = false;
|
|
rct_xy16 removeCoord = { 0, 0 };
|
|
|
|
if (isExit)
|
|
{
|
|
if (ride->exits[stationNum] != 0xFFFF)
|
|
{
|
|
if (flags & GAME_COMMAND_FLAG_GHOST)
|
|
{
|
|
gGameCommandErrorText = 0;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
removeCoord.x = (ride->exits[stationNum] & 0xFF) * 32;
|
|
removeCoord.y = ((ride->exits[stationNum] >> 8) & 0xFF) * 32;
|
|
requiresRemove = true;
|
|
}
|
|
}
|
|
else if (ride->entrances[stationNum] != 0xFFFF)
|
|
{
|
|
if (flags & GAME_COMMAND_FLAG_GHOST)
|
|
{
|
|
gGameCommandErrorText = 0;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
removeCoord.x = (ride->entrances[stationNum] & 0xFF) * 32;
|
|
removeCoord.y = ((ride->entrances[stationNum] >> 8) & 0xFF) * 32;
|
|
requiresRemove = true;
|
|
}
|
|
|
|
if (requiresRemove)
|
|
{
|
|
money32 success = game_do_command(
|
|
removeCoord.x,
|
|
flags,
|
|
removeCoord.y,
|
|
rideIndex,
|
|
GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT,
|
|
stationNum,
|
|
0
|
|
);
|
|
|
|
if (success == MONEY32_UNDEFINED)
|
|
{
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
}
|
|
|
|
z = ride->station_heights[stationNum] * 8;
|
|
gCommandPosition.z = z;
|
|
|
|
if ((flags & GAME_COMMAND_FLAG_APPLY) &&
|
|
!(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) &&
|
|
!(flags & GAME_COMMAND_FLAG_GHOST))
|
|
{
|
|
footpath_remove_litter(x, y, z);
|
|
wall_remove_at_z(x, y, z);
|
|
}
|
|
|
|
if (!gCheatsSandboxMode && !map_is_location_owned(x, y, z))
|
|
{
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
sint8 clear_z = (z / 8) + (isExit ? 5 : 7);
|
|
|
|
if (!gCheatsDisableClearanceChecks &&
|
|
!map_can_construct_with_clear_at(x, y, z / 8, clear_z, &map_place_non_scenery_clear_func, 0xF, flags, &cost))
|
|
{
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (gMapGroundFlags & ELEMENT_IS_UNDERWATER)
|
|
{
|
|
gGameCommandErrorText = STR_RIDE_CANT_BUILD_THIS_UNDERWATER;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (z / 8 > 244)
|
|
{
|
|
gGameCommandErrorText = STR_TOO_HIGH;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (flags & GAME_COMMAND_FLAG_APPLY)
|
|
{
|
|
rct_xyz16 coord;
|
|
coord.x = x + 16;
|
|
coord.y = y + 16;
|
|
coord.z = map_element_height(coord.x, coord.y);
|
|
network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord);
|
|
|
|
rct_map_element* mapElement = map_element_insert(x / 32, y / 32, z / 8, 0xF);
|
|
assert(mapElement != NULL);
|
|
mapElement->clearance_height = clear_z;
|
|
mapElement->properties.entrance.type = isExit;
|
|
mapElement->properties.entrance.index = stationNum << 4;
|
|
mapElement->properties.entrance.ride_index = rideIndex;
|
|
mapElement->type = MAP_ELEMENT_TYPE_ENTRANCE | direction;
|
|
|
|
if (flags & GAME_COMMAND_FLAG_GHOST)
|
|
{
|
|
mapElement->flags |= MAP_ELEMENT_FLAG_GHOST;
|
|
}
|
|
|
|
if (isExit)
|
|
{
|
|
ride->exits[stationNum] = (x / 32) | (y / 32 << 8);
|
|
}
|
|
else
|
|
{
|
|
ride->entrances[stationNum] = (x / 32) | (y / 32 << 8);
|
|
ride->last_peep_in_queue[stationNum] = SPRITE_INDEX_NULL;
|
|
ride->queue_length[stationNum] = 0;
|
|
|
|
map_animation_create(MAP_ANIMATION_TYPE_RIDE_ENTRANCE, x, y, z / 8);
|
|
}
|
|
|
|
footpath_queue_chain_reset();
|
|
|
|
if (!(flags & GAME_COMMAND_FLAG_GHOST))
|
|
{
|
|
maze_entrance_hedge_removal(x, y, mapElement);
|
|
}
|
|
|
|
footpath_connect_edges(x, y, mapElement, flags);
|
|
footpath_update_queue_chains();
|
|
|
|
map_invalidate_tile_full(x, y);
|
|
}
|
|
}
|
|
|
|
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION;
|
|
return cost;
|
|
}
|
|
|
|
static money32 RideEntranceExitRemove(sint16 x, sint16 y, uint8 rideIndex, uint8 stationNum, uint8 flags)
|
|
{
|
|
if (rideIndex >= MAX_RIDES)
|
|
{
|
|
log_warning("Invalid game command for ride %u", rideIndex);
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
rct_ride* ride = get_ride(rideIndex);
|
|
if (ride->type == RIDE_TYPE_NULL)
|
|
{
|
|
log_warning("Invalid ride id %u for entrance/exit removal", rideIndex);
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (!(flags & GAME_COMMAND_FLAG_GHOST))
|
|
{
|
|
if (!(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) &&
|
|
game_is_paused() &&
|
|
!gCheatsBuildInPauseMode)
|
|
{
|
|
gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
}
|
|
|
|
if (ride->status != RIDE_STATUS_CLOSED)
|
|
{
|
|
gGameCommandErrorText = STR_MUST_BE_CLOSED_FIRST;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK)
|
|
{
|
|
gGameCommandErrorText = STR_NOT_ALLOWED_TO_MODIFY_STATION;
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
if (flags & GAME_COMMAND_FLAG_APPLY)
|
|
{
|
|
ride_clear_for_construction(rideIndex);
|
|
ride_remove_peeps(rideIndex);
|
|
invalidate_test_results(rideIndex);
|
|
|
|
bool found = false;
|
|
rct_map_element* mapElement = map_get_first_element_at(x / 32, y / 32);
|
|
if (mapElement == NULL)
|
|
{
|
|
log_warning("Invalid coordinates for entrance/exit removal x = %d, y = %d", x, y);
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
do
|
|
{
|
|
if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_ENTRANCE)
|
|
continue;
|
|
|
|
if (mapElement->base_height != ride->station_heights[stationNum])
|
|
continue;
|
|
|
|
if (flags & GAME_COMMAND_FLAG_5 && !(mapElement->flags & MAP_ELEMENT_FLAG_GHOST))
|
|
continue;
|
|
|
|
found = true;
|
|
break;
|
|
}
|
|
while (!map_element_is_last_for_tile(mapElement++));
|
|
|
|
if (!found)
|
|
{
|
|
return MONEY32_UNDEFINED;
|
|
}
|
|
|
|
rct_xyz16 coord;
|
|
coord.x = x + 16;
|
|
coord.y = y + 16;
|
|
coord.z = map_element_height(coord.x, coord.y);
|
|
network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord);
|
|
|
|
footpath_queue_chain_reset();
|
|
maze_entrance_hedge_replacement(x, y, mapElement);
|
|
footpath_remove_edges_at(x, y, mapElement);
|
|
|
|
bool isExit = mapElement->properties.entrance.type == ENTRANCE_TYPE_RIDE_EXIT;
|
|
|
|
map_element_remove(mapElement);
|
|
|
|
if (isExit)
|
|
{
|
|
ride->exits[stationNum] = 0xFFFF;
|
|
}
|
|
else
|
|
{
|
|
ride->entrances[stationNum] = 0xFFFF;
|
|
}
|
|
|
|
footpath_update_queue_chains();
|
|
|
|
map_invalidate_tile_full(x, y);
|
|
}
|
|
|
|
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION;
|
|
return 0;
|
|
}
|
|
|
|
static money32 RideEntranceExitPlaceGhost(uint8 rideIndex, sint16 x, sint16 y, uint8 direction, uint8 placeType, uint8 stationNum)
|
|
{
|
|
return game_do_command(
|
|
x,
|
|
(GAME_COMMAND_FLAG_APPLY |
|
|
GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED |
|
|
GAME_COMMAND_FLAG_5 |
|
|
GAME_COMMAND_FLAG_GHOST) |
|
|
(direction << 8),
|
|
y,
|
|
rideIndex | (placeType << 8),
|
|
GAME_COMMAND_PLACE_RIDE_ENTRANCE_OR_EXIT,
|
|
stationNum,
|
|
0
|
|
);
|
|
}
|
|
|
|
extern "C"
|
|
{
|
|
/**
|
|
*
|
|
* rct2: 0x006666E7
|
|
*/
|
|
void game_command_place_park_entrance(sint32* eax,
|
|
sint32* ebx,
|
|
sint32* ecx,
|
|
sint32* edx,
|
|
sint32* esi,
|
|
sint32* edi,
|
|
sint32* ebp)
|
|
{
|
|
*ebx = ParkEntrancePlace(
|
|
*ebx & 0xFF,
|
|
*eax & 0xFFFF,
|
|
*ecx & 0xFFFF,
|
|
*edx & 0xFF,
|
|
(*ebx >> 8) & 0xFF);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* rct2: 0x00666A63
|
|
*/
|
|
void game_command_remove_park_entrance(sint32 *eax,
|
|
sint32 *ebx,
|
|
sint32 *ecx,
|
|
sint32 *edx,
|
|
sint32 *esi,
|
|
sint32 *edi,
|
|
sint32 *ebp)
|
|
{
|
|
*ebx = ParkEntranceRemove(
|
|
*eax & 0xFFFF,
|
|
*ecx & 0xFFFF,
|
|
*edx & 0xFF,
|
|
*ebx & 0xFF);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* rct2: 0x00666F9E
|
|
*/
|
|
void park_entrance_remove_ghost()
|
|
{
|
|
if (gParkEntranceGhostExists)
|
|
{
|
|
gParkEntranceGhostExists = false;
|
|
game_do_command(
|
|
gParkEntranceGhostPosition.x,
|
|
GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_5 | GAME_COMMAND_FLAG_APPLY,
|
|
gParkEntranceGhostPosition.y,
|
|
gParkEntranceGhostPosition.z,
|
|
GAME_COMMAND_REMOVE_PARK_ENTRANCE,
|
|
0,
|
|
0
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* rct2: 0x00666F4E
|
|
*/
|
|
money32 park_entrance_place_ghost(sint32 x, sint32 y, sint32 z, sint32 direction)
|
|
{
|
|
money32 result;
|
|
|
|
park_entrance_remove_ghost();
|
|
result = game_do_command(
|
|
x,
|
|
GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED |
|
|
GAME_COMMAND_FLAG_5 |
|
|
GAME_COMMAND_FLAG_GHOST |
|
|
GAME_COMMAND_FLAG_APPLY |
|
|
(direction << 8),
|
|
y,
|
|
z,
|
|
GAME_COMMAND_PLACE_PARK_ENTRANCE,
|
|
0,
|
|
0
|
|
);
|
|
|
|
if (result != MONEY32_UNDEFINED)
|
|
{
|
|
gParkEntranceGhostPosition.x = x;
|
|
gParkEntranceGhostPosition.y = y;
|
|
gParkEntranceGhostPosition.z = z;
|
|
gParkEntranceGhostDirection = direction;
|
|
gParkEntranceGhostExists = true;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
sint32 park_entrance_get_index(sint32 x, sint32 y, sint32 z)
|
|
{
|
|
sint32 i;
|
|
|
|
for (i = 0; i < MAX_PARK_ENTRANCES; i++)
|
|
{
|
|
if (x == gParkEntrances[i].x &&
|
|
y == gParkEntrances[i].y &&
|
|
z == gParkEntrances[i].z)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void reset_park_entrance()
|
|
{
|
|
for (sint32 i = 0; i < MAX_PARK_ENTRANCES; i++)
|
|
{
|
|
gParkEntrances[i].x = MAP_LOCATION_NULL;
|
|
}
|
|
}
|
|
|
|
|
|
void ride_entrance_exit_place_provisional_ghost()
|
|
{
|
|
if (_currentTrackSelectionFlags & TRACK_SELECTION_FLAG_ENTRANCE_OR_EXIT) {
|
|
RideEntranceExitPlaceGhost(_currentRideIndex,
|
|
gRideEntranceExitGhostPosition.x,
|
|
gRideEntranceExitGhostPosition.y,
|
|
gRideEntranceExitGhostPosition.direction,
|
|
gRideEntranceExitPlaceType,
|
|
gRideEntranceExitGhostStationIndex);
|
|
}
|
|
}
|
|
|
|
void ride_entrance_exit_remove_ghost()
|
|
{
|
|
if (_currentTrackSelectionFlags & TRACK_SELECTION_FLAG_ENTRANCE_OR_EXIT) {
|
|
game_do_command(
|
|
gRideEntranceExitGhostPosition.x,
|
|
(GAME_COMMAND_FLAG_5 | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_APPLY),
|
|
gRideEntranceExitGhostPosition.y,
|
|
_currentRideIndex,
|
|
GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT,
|
|
gRideEntranceExitGhostStationIndex,
|
|
0
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
* rct2: 0x006CA28C
|
|
*/
|
|
money32 ride_entrance_exit_place_ghost(sint32 rideIndex,
|
|
sint32 x,
|
|
sint32 y,
|
|
sint32 direction,
|
|
sint32 placeType,
|
|
sint32 stationNum)
|
|
{
|
|
ride_construction_remove_ghosts();
|
|
money32 result = RideEntranceExitPlaceGhost(rideIndex, x, y, direction, placeType, stationNum);
|
|
|
|
if (result != MONEY32_UNDEFINED)
|
|
{
|
|
_currentTrackSelectionFlags |= TRACK_SELECTION_FLAG_ENTRANCE_OR_EXIT;
|
|
gRideEntranceExitGhostPosition.x = x;
|
|
gRideEntranceExitGhostPosition.y = y;
|
|
gRideEntranceExitGhostPosition.direction = direction;
|
|
gRideEntranceExitGhostStationIndex = stationNum & 0xFF;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* rct2: 0x006660A8
|
|
*/
|
|
void game_command_place_ride_entrance_or_exit(sint32 *eax,
|
|
sint32 *ebx,
|
|
sint32 *ecx,
|
|
sint32 *edx,
|
|
sint32 *esi,
|
|
sint32 *edi,
|
|
sint32 *ebp)
|
|
{
|
|
*ebx = RideEntranceExitPlace(
|
|
*eax & 0xFFFF,
|
|
*ecx & 0xFFFF,
|
|
*edx & 0xFF,
|
|
(*ebx >> 8) & 0xFF,
|
|
*ebx & 0xFF,
|
|
*edx & 0xFF,
|
|
*edi & 0xFF,
|
|
((*edx >> 8) & 0xFF) != 0
|
|
);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* rct2: 0x0066640B
|
|
*/
|
|
void game_command_remove_ride_entrance_or_exit(sint32 *eax,
|
|
sint32 *ebx,
|
|
sint32 *ecx,
|
|
sint32 *edx,
|
|
sint32 *esi,
|
|
sint32 *edi,
|
|
sint32 *ebp)
|
|
{
|
|
*ebx = RideEntranceExitRemove(
|
|
*eax & 0xFFFF,
|
|
*ecx & 0xFFFF,
|
|
*edx & 0xFF,
|
|
*edi & 0xFF,
|
|
*ebx & 0xFF
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Replaces the outer hedge walls for an entrance placement removal.
|
|
* rct2: 0x00666D6F
|
|
*/
|
|
void maze_entrance_hedge_replacement(sint32 x, sint32 y, rct_map_element *mapElement)
|
|
{
|
|
sint32 direction = mapElement->type & MAP_ELEMENT_DIRECTION_MASK;
|
|
x += TileDirectionDelta[direction].x;
|
|
y += TileDirectionDelta[direction].y;
|
|
sint32 z = mapElement->base_height;
|
|
sint32 rideIndex = mapElement->properties.track.ride_index;
|
|
|
|
mapElement = map_get_first_element_at(x >> 5, y >> 5);
|
|
do {
|
|
if (mapElement->type != MAP_ELEMENT_TYPE_TRACK) continue;
|
|
if (mapElement->properties.track.ride_index != rideIndex) continue;
|
|
if (mapElement->base_height != z) continue;
|
|
if (mapElement->properties.track.type != TRACK_ELEM_MAZE) continue;
|
|
|
|
// Each maze element is split into 4 sections with 4 different walls
|
|
uint8 mazeSection = direction * 4;
|
|
// Add the top outer wall
|
|
mapElement->properties.track.maze_entry |= (1 << ((mazeSection + 9) & 0x0F));
|
|
// Add the bottom outer wall
|
|
mapElement->properties.track.maze_entry |= (1 << ((mazeSection + 12) & 0x0F));
|
|
|
|
map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8);
|
|
return;
|
|
} while (!map_element_is_last_for_tile(mapElement++));
|
|
}
|
|
|
|
/**
|
|
* Removes the hedge walls for an entrance placement.
|
|
* rct2: 0x00666CBE
|
|
*/
|
|
void maze_entrance_hedge_removal(sint32 x, sint32 y, rct_map_element *mapElement)
|
|
{
|
|
sint32 direction = mapElement->type & MAP_ELEMENT_DIRECTION_MASK;
|
|
x += TileDirectionDelta[direction].x;
|
|
y += TileDirectionDelta[direction].y;
|
|
sint32 z = mapElement->base_height;
|
|
sint32 rideIndex = mapElement->properties.track.ride_index;
|
|
|
|
mapElement = map_get_first_element_at(x >> 5, y >> 5);
|
|
do {
|
|
if (mapElement->type != MAP_ELEMENT_TYPE_TRACK) continue;
|
|
if (mapElement->properties.track.ride_index != rideIndex) continue;
|
|
if (mapElement->base_height != z) continue;
|
|
if (mapElement->properties.track.type != TRACK_ELEM_MAZE) continue;
|
|
|
|
// Each maze element is split into 4 sections with 4 different walls
|
|
uint8 mazeSection = direction * 4;
|
|
// Remove the top outer wall
|
|
mapElement->properties.track.maze_entry &= ~(1 << ((mazeSection + 9) & 0x0F));
|
|
// Remove the bottom outer wall
|
|
mapElement->properties.track.maze_entry &= ~(1 << ((mazeSection + 12) & 0x0F));
|
|
// Remove the intersecting wall
|
|
mapElement->properties.track.maze_entry &= ~(1 << ((mazeSection + 10) & 0x0F));
|
|
// Remove the top hedge section
|
|
mapElement->properties.track.maze_entry &= ~(1 << ((mazeSection + 11) & 0x0F));
|
|
// Remove the bottom hedge section
|
|
mapElement->properties.track.maze_entry &= ~(1 << ((mazeSection + 15) & 0x0F));
|
|
|
|
map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8);
|
|
return;
|
|
} while (!map_element_is_last_for_tile(mapElement++));
|
|
}
|
|
}
|