|
|
|
|
@@ -14,7 +14,6 @@
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
|
|
#include "../addresses.h"
|
|
|
|
|
#include "../audio/audio.h"
|
|
|
|
|
#include "../cheats.h"
|
|
|
|
|
#include "../config.h"
|
|
|
|
|
@@ -96,10 +95,11 @@ rct_map_element *gMapElementTilePointers[MAX_TILE_MAP_ELEMENT_POINTERS];
|
|
|
|
|
rct_map_element *gMapElements = RCT2_ADDRESS(RCT2_ADDRESS_MAP_ELEMENTS, rct_map_element);
|
|
|
|
|
rct_map_element **gMapElementTilePointers = RCT2_ADDRESS(RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS, rct_map_element*);
|
|
|
|
|
#endif
|
|
|
|
|
rct_xy16 *gMapSelectionTiles = RCT2_ADDRESS(0x009DE596, rct_xy16);
|
|
|
|
|
rct2_peep_spawn *gPeepSpawns = RCT2_ADDRESS(RCT2_ADDRESS_PEEP_SPAWNS, rct2_peep_spawn);
|
|
|
|
|
rct_xy16 gMapSelectionTiles[300];
|
|
|
|
|
rct2_peep_spawn gPeepSpawns[2];
|
|
|
|
|
|
|
|
|
|
rct_map_element *gNextFreeMapElement;
|
|
|
|
|
uint32 gNextFreeMapElementPointerIndex;
|
|
|
|
|
|
|
|
|
|
bool gLandMountainMode;
|
|
|
|
|
bool gLandPaintMode;
|
|
|
|
|
@@ -121,6 +121,8 @@ rct_xyz16 gCommandPosition;
|
|
|
|
|
|
|
|
|
|
uint8 gUnk9E2E28;
|
|
|
|
|
|
|
|
|
|
static uint8 _unk141F725;
|
|
|
|
|
|
|
|
|
|
static void map_update_grass_length(int x, int y, rct_map_element *mapElement);
|
|
|
|
|
static void map_set_grass_length(int x, int y, rct_map_element *mapElement, int length);
|
|
|
|
|
static void clear_elements_at(int x, int y);
|
|
|
|
|
@@ -360,7 +362,7 @@ void map_init(int size)
|
|
|
|
|
|
|
|
|
|
date_reset();
|
|
|
|
|
gNumMapAnimations = 0;
|
|
|
|
|
RCT2_GLOBAL(0x010E63B8, sint32) = 0;
|
|
|
|
|
gNextFreeMapElementPointerIndex = 0;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_TILE_MAP_ELEMENT_POINTERS; i++) {
|
|
|
|
|
map_element = &gMapElements[i];
|
|
|
|
|
@@ -569,13 +571,13 @@ void sub_68B089()
|
|
|
|
|
if (gTrackDesignSaveMode)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
i = RCT2_GLOBAL(0x0010E63B8, uint32);
|
|
|
|
|
i = gNextFreeMapElementPointerIndex;
|
|
|
|
|
do {
|
|
|
|
|
i++;
|
|
|
|
|
if (i >= MAX_TILE_MAP_ELEMENT_POINTERS)
|
|
|
|
|
i = 0;
|
|
|
|
|
} while (gMapElementTilePointers[i] == TILE_UNDEFINED_MAP_ELEMENT);
|
|
|
|
|
RCT2_GLOBAL(0x0010E63B8, uint32) = i;
|
|
|
|
|
gNextFreeMapElementPointerIndex = i;
|
|
|
|
|
|
|
|
|
|
mapElementFirst = mapElement = gMapElementTilePointers[i];
|
|
|
|
|
do {
|
|
|
|
|
@@ -1515,20 +1517,22 @@ static money32 map_change_surface_style(int x0, int y0, int x1, int y1, uint8 su
|
|
|
|
|
gCommandPosition.x = xMid;
|
|
|
|
|
gCommandPosition.y = yMid;
|
|
|
|
|
gCommandPosition.z = heightMid;
|
|
|
|
|
RCT2_GLOBAL(0x009E32B4, uint32) = 0;
|
|
|
|
|
|
|
|
|
|
money32 cost = 0;
|
|
|
|
|
|
|
|
|
|
// Do nothing during pause
|
|
|
|
|
if (game_is_paused() && !gCheatsBuildInPauseMode) {
|
|
|
|
|
cost += RCT2_GLOBAL(0x009E32B4, uint32);
|
|
|
|
|
return (gParkFlags & PARK_FLAGS_NO_MONEY) ? 0 : cost;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES) {
|
|
|
|
|
cost += RCT2_GLOBAL(0x009E32B4, uint32);
|
|
|
|
|
return (gParkFlags & PARK_FLAGS_NO_MONEY) ? 0 : cost;
|
|
|
|
|
// Do nothing if not in editor, sandbox mode or landscaping is forbidden
|
|
|
|
|
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) &&
|
|
|
|
|
!gCheatsSandboxMode &&
|
|
|
|
|
(gParkFlags & PARK_FLAGS_FORBID_LANDSCAPE_CHANGES)
|
|
|
|
|
) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
money32 surfaceCost = 0;
|
|
|
|
|
money32 edgeCost = 0;
|
|
|
|
|
for (int x = x0; x <= x1; x += 32) {
|
|
|
|
|
for (int y = y0; y <= y1; y += 32) {
|
|
|
|
|
if (x > 0x1FFF) continue;
|
|
|
|
|
@@ -1546,7 +1550,7 @@ static money32 map_change_surface_style(int x0, int y0, int x1, int y1, uint8 su
|
|
|
|
|
(mapElement->properties.surface.terrain >> 5);
|
|
|
|
|
|
|
|
|
|
if (surfaceStyle != cur_terrain) {
|
|
|
|
|
RCT2_GLOBAL(0x009E32B4, uint32) += TerrainPricing[surfaceStyle & 0x1F];
|
|
|
|
|
surfaceCost += TerrainPricing[surfaceStyle & 0x1F];
|
|
|
|
|
if (flags & 1){
|
|
|
|
|
mapElement->properties.surface.terrain &= MAP_ELEMENT_WATER_HEIGHT_MASK;
|
|
|
|
|
mapElement->type &= MAP_ELEMENT_QUADRANT_MASK | MAP_ELEMENT_TYPE_MASK;
|
|
|
|
|
@@ -1569,7 +1573,7 @@ static money32 map_change_surface_style(int x0, int y0, int x1, int y1, uint8 su
|
|
|
|
|
(mapElement->properties.surface.slope >> 5);
|
|
|
|
|
|
|
|
|
|
if (edgeStyle != currentEdge){
|
|
|
|
|
cost++;
|
|
|
|
|
edgeCost += 100;
|
|
|
|
|
|
|
|
|
|
if (flags & 1){
|
|
|
|
|
mapElement->properties.surface.slope &= MAP_ELEMENT_SLOPE_MASK;
|
|
|
|
|
@@ -1606,9 +1610,7 @@ static money32 map_change_surface_style(int x0, int y0, int x1, int y1, uint8 su
|
|
|
|
|
network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cost *= 100;
|
|
|
|
|
cost += RCT2_GLOBAL(0x009E32B4, uint32);
|
|
|
|
|
return (gParkFlags & PARK_FLAGS_NO_MONEY) ? 0 : cost;
|
|
|
|
|
return (gParkFlags & PARK_FLAGS_NO_MONEY) ? 0 : surfaceCost + edgeCost;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -1706,14 +1708,14 @@ static money32 map_set_land_height(int flags, int x, int y, int height, int styl
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RCT2_GLOBAL(0x9E2E18, money32) = MONEY(0, 0);
|
|
|
|
|
money32 cost = MONEY(0, 0);
|
|
|
|
|
if(flags & GAME_COMMAND_FLAG_APPLY)
|
|
|
|
|
{
|
|
|
|
|
footpath_remove_litter(x, y, map_element_height(x, y));
|
|
|
|
|
if(!gCheatsDisableClearanceChecks)
|
|
|
|
|
map_remove_walls_at(x, y, height * 8 - 16, height * 8 + 32);
|
|
|
|
|
}
|
|
|
|
|
RCT2_GLOBAL(0x9E2E18, money32) += MONEY(20, 0);
|
|
|
|
|
cost += MONEY(20, 0);
|
|
|
|
|
|
|
|
|
|
if (!gCheatsDisableClearanceChecks) {
|
|
|
|
|
//Check for obstructing scenery
|
|
|
|
|
@@ -1731,7 +1733,7 @@ static money32 map_set_land_height(int flags, int x, int y, int height, int styl
|
|
|
|
|
map_obstruction_set_error_text(mapElement);
|
|
|
|
|
return MONEY32_UNDEFINED;
|
|
|
|
|
}
|
|
|
|
|
RCT2_GLOBAL(0x9E2E18, money32) += MONEY(sceneryEntry->small_scenery.removal_price, 0);
|
|
|
|
|
cost += MONEY(sceneryEntry->small_scenery.removal_price, 0);
|
|
|
|
|
if (flags & GAME_COMMAND_FLAG_APPLY)
|
|
|
|
|
map_element_remove(mapElement--);
|
|
|
|
|
} while (!map_element_is_last_for_tile(mapElement++));
|
|
|
|
|
@@ -1849,7 +1851,7 @@ static money32 map_set_land_height(int flags, int x, int y, int height, int styl
|
|
|
|
|
}
|
|
|
|
|
if(gParkFlags & PARK_FLAGS_NO_MONEY)
|
|
|
|
|
return 0;
|
|
|
|
|
return RCT2_GLOBAL(0x9E2E18, money32);
|
|
|
|
|
return cost;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void game_command_set_land_height(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp)
|
|
|
|
|
@@ -2974,7 +2976,7 @@ void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi
|
|
|
|
|
uint8 flags = *ebx & 0xFF;
|
|
|
|
|
uint8 quadrant = *edx;
|
|
|
|
|
uint8 colour1 = *edx >> 8;
|
|
|
|
|
RCT2_GLOBAL(0x00F64F26, money32) = 0;
|
|
|
|
|
money32 clearCost = 0;
|
|
|
|
|
int F64F1D = 0;
|
|
|
|
|
int F64EC8 = z;
|
|
|
|
|
int base_height = map_element_height(x, y);
|
|
|
|
|
@@ -3094,7 +3096,7 @@ void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi
|
|
|
|
|
bl |= 0xF0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(gCheatsDisableClearanceChecks || map_can_construct_with_clear_at(x, y, zLow, zHigh, &map_place_scenery_clear_func, bl, flags, RCT2_ADDRESS(0x00F64F26, money32))){
|
|
|
|
|
if(gCheatsDisableClearanceChecks || map_can_construct_with_clear_at(x, y, zLow, zHigh, &map_place_scenery_clear_func, bl, flags, &clearCost)){
|
|
|
|
|
gSceneryGroundFlags = gMapGroundFlags & (ELEMENT_IS_1 | ELEMENT_IS_UNDERGROUND);
|
|
|
|
|
if(flags & GAME_COMMAND_FLAG_APPLY){
|
|
|
|
|
if (gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST)) {
|
|
|
|
|
@@ -3128,7 +3130,7 @@ void game_command_place_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi
|
|
|
|
|
map_animation_create(2, x, y, new_map_element->base_height);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*ebx = (scenery_entry->small_scenery.price * 10) + RCT2_GLOBAL(0x00F64F26, money32);
|
|
|
|
|
*ebx = (scenery_entry->small_scenery.price * 10) + clearCost;
|
|
|
|
|
if(gParkFlags & PARK_FLAGS_NO_MONEY){
|
|
|
|
|
*ebx = 0;
|
|
|
|
|
}
|
|
|
|
|
@@ -3202,7 +3204,7 @@ static bool map_place_fence_check_obstruction_with_track(rct_scenery_entry *wall
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RCT2_GLOBAL(0x0141F725, uint8) |= 1;
|
|
|
|
|
_unk141F725 |= 1;
|
|
|
|
|
if (z0 & 1) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@@ -3266,7 +3268,7 @@ static bool map_place_fence_check_obstruction(rct_scenery_entry *wall, int x, in
|
|
|
|
|
rct_scenery_entry *entry;
|
|
|
|
|
rct_large_scenery_tile *tile;
|
|
|
|
|
|
|
|
|
|
RCT2_GLOBAL(0x0141F725, uint8) = 0;
|
|
|
|
|
_unk141F725 = 0;
|
|
|
|
|
gMapGroundFlags = ELEMENT_IS_1;
|
|
|
|
|
if (map_is_location_at_edge(x, y)) {
|
|
|
|
|
gGameCommandErrorText = STR_OFF_EDGE_OF_MAP;
|
|
|
|
|
@@ -3394,13 +3396,7 @@ void game_command_place_fence(int* eax, int* ebx, int* ecx, int* edx, int* esi,
|
|
|
|
|
uint8 tertiary_colour = (*ebp >> 8) & 0xFF;
|
|
|
|
|
uint8 edge = *edx & 0xFF;
|
|
|
|
|
|
|
|
|
|
// *not used*
|
|
|
|
|
RCT2_GLOBAL(0x00141F726, uint8) = secondary_colour;
|
|
|
|
|
// *not used*
|
|
|
|
|
RCT2_GLOBAL(0x00141F727, uint8) = tertiary_colour;
|
|
|
|
|
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
|
|
|
|
|
// Banner index *not used*
|
|
|
|
|
RCT2_GLOBAL(0x00141F728, uint8) = 0xFF;
|
|
|
|
|
gCommandPosition.x = position.x + 16;
|
|
|
|
|
gCommandPosition.y = position.y + 16;
|
|
|
|
|
gCommandPosition.z = position.z;
|
|
|
|
|
@@ -3447,10 +3443,6 @@ void game_command_place_fence(int* eax, int* ebx, int* ecx, int* edx, int* esi,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RCT2_GLOBAL(0x00141F721, uint16) = position.z / 8;
|
|
|
|
|
RCT2_GLOBAL(0x00141F720, uint8) = primary_colour;
|
|
|
|
|
RCT2_GLOBAL(0x00141F723, uint8) = bp;
|
|
|
|
|
|
|
|
|
|
rct_map_element* map_element = map_get_surface_element_at(position.x / 32, position.y / 32);
|
|
|
|
|
if (map_element == NULL){
|
|
|
|
|
*ebx = MONEY32_UNDEFINED;
|
|
|
|
|
@@ -3539,7 +3531,6 @@ void game_command_place_fence(int* eax, int* ebx, int* ecx, int* edx, int* esi,
|
|
|
|
|
if (fence->wall.var_0D != 0xFF){
|
|
|
|
|
banner_index = create_new_banner(fence->wall.var_0D);
|
|
|
|
|
|
|
|
|
|
RCT2_GLOBAL(0x00141F728, uint8) = banner_index;
|
|
|
|
|
if (banner_index == 0xFF){
|
|
|
|
|
*ebx = MONEY32_UNDEFINED;
|
|
|
|
|
return;
|
|
|
|
|
@@ -3560,21 +3551,19 @@ void game_command_place_fence(int* eax, int* ebx, int* ecx, int* edx, int* esi,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bp = RCT2_GLOBAL(0x00141F723, uint8);
|
|
|
|
|
|
|
|
|
|
RCT2_GLOBAL(0x00141F722, uint8) = position.z / 8;
|
|
|
|
|
uint8 clearanceHeight = position.z / 8;
|
|
|
|
|
if (bp & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS)) {
|
|
|
|
|
if (fence->wall.flags & WALL_SCENERY_CANT_BUILD_ON_SLOPE){
|
|
|
|
|
gGameCommandErrorText = STR_ERR_UNABLE_TO_BUILD_THIS_ON_SLOPE;
|
|
|
|
|
*ebx = MONEY32_UNDEFINED;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
RCT2_GLOBAL(0x00141F722, uint8) += 2;
|
|
|
|
|
clearanceHeight += 2;
|
|
|
|
|
}
|
|
|
|
|
RCT2_GLOBAL(0x00141F722, uint8) += fence->wall.height;
|
|
|
|
|
clearanceHeight += fence->wall.height;
|
|
|
|
|
|
|
|
|
|
if (!(flags & (1 << 7)) && !gCheatsDisableClearanceChecks){
|
|
|
|
|
if (!map_place_fence_check_obstruction(fence, position.x, position.y, RCT2_GLOBAL(0x00141F721, uint8), RCT2_GLOBAL(0x00141F722, uint8), edge)) {
|
|
|
|
|
if (!map_place_fence_check_obstruction(fence, position.x, position.y, position.z / 8, clearanceHeight, edge)) {
|
|
|
|
|
*ebx = MONEY32_UNDEFINED;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@@ -3599,7 +3588,7 @@ void game_command_place_fence(int* eax, int* ebx, int* ecx, int* edx, int* esi,
|
|
|
|
|
|
|
|
|
|
map_animation_create(MAP_ANIMATION_TYPE_WALL, position.x, position.y, position.z / 8);
|
|
|
|
|
|
|
|
|
|
map_element->clearance_height = RCT2_GLOBAL(0x00141F722, uint8);
|
|
|
|
|
map_element->clearance_height = clearanceHeight;
|
|
|
|
|
|
|
|
|
|
map_element->type = bp | edge | MAP_ELEMENT_TYPE_FENCE;
|
|
|
|
|
|
|
|
|
|
@@ -3607,7 +3596,7 @@ void game_command_place_fence(int* eax, int* ebx, int* ecx, int* edx, int* esi,
|
|
|
|
|
map_element->properties.fence.item[1] |= (secondary_colour & 7) << 5;
|
|
|
|
|
map_element->flags |= (secondary_colour & 0x18) << 2;
|
|
|
|
|
|
|
|
|
|
if (RCT2_GLOBAL(0x00141F725, uint8) & 1){
|
|
|
|
|
if (_unk141F725 & 1) {
|
|
|
|
|
map_element->properties.fence.item[2] |= (1 << 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -3672,9 +3661,7 @@ void game_command_place_large_scenery(int* eax, int* ebx, int* ecx, int* edx, in
|
|
|
|
|
gCommandPosition.z = base_height;
|
|
|
|
|
gSceneryGroundFlags = 0;
|
|
|
|
|
uint8 banner_id = 0xFF;
|
|
|
|
|
|
|
|
|
|
// Supports cost
|
|
|
|
|
RCT2_GLOBAL(0x00F4389A, money32) = 0;
|
|
|
|
|
money32 supportsCost = 0;
|
|
|
|
|
|
|
|
|
|
if (game_is_paused() && !gCheatsBuildInPauseMode) {
|
|
|
|
|
gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED;
|
|
|
|
|
@@ -3792,9 +3779,7 @@ void game_command_place_large_scenery(int* eax, int* ebx, int* ecx, int* edx, in
|
|
|
|
|
bl |= bh;
|
|
|
|
|
uint8 F43887 = bl;
|
|
|
|
|
|
|
|
|
|
RCT2_GLOBAL(0x00F43892, sint16) = curTile.x;
|
|
|
|
|
RCT2_GLOBAL(0x00F43894, sint16) = curTile.y;
|
|
|
|
|
if (!gCheatsDisableClearanceChecks && !map_can_construct_with_clear_at(curTile.x, curTile.y, zLow, zHigh, &map_place_scenery_clear_func, bl, flags, RCT2_ADDRESS(0x00F4389A, money32))) {
|
|
|
|
|
if (!gCheatsDisableClearanceChecks && !map_can_construct_with_clear_at(curTile.x, curTile.y, zLow, zHigh, &map_place_scenery_clear_func, bl, flags, &supportsCost)) {
|
|
|
|
|
*ebx = MONEY32_UNDEFINED;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@@ -3876,7 +3861,7 @@ void game_command_place_large_scenery(int* eax, int* ebx, int* ecx, int* edx, in
|
|
|
|
|
// Force ride construction to recheck area
|
|
|
|
|
_currentTrackSelectionFlags |= 8;
|
|
|
|
|
|
|
|
|
|
*ebx = (scenery_entry->large_scenery.price * 10) + RCT2_GLOBAL(0x00F4389A, money32);
|
|
|
|
|
*ebx = (scenery_entry->large_scenery.price * 10) + supportsCost;
|
|
|
|
|
if(gParkFlags & PARK_FLAGS_NO_MONEY){
|
|
|
|
|
*ebx = 0;
|
|
|
|
|
}
|
|
|
|
|
|