clang-format world

This commit is contained in:
clang-format 2018-06-22 23:17:03 +02:00 committed by Hielke Morsink
parent adb69a2fe8
commit 5c55fd6132
42 changed files with 5653 additions and 4671 deletions

View File

@ -7,38 +7,36 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "../network/network.h"
#include "../audio/audio.h"
#include "../network/network.h"
#include "../scenario/Scenario.h"
#include "../util/Util.h"
#include "Sprite.h"
bool rct_sprite::IsBalloon()
{
return this->balloon.sprite_identifier == SPRITE_IDENTIFIER_MISC &&
this->balloon.misc_identifier == SPRITE_MISC_BALLOON;
return this->balloon.sprite_identifier == SPRITE_IDENTIFIER_MISC && this->balloon.misc_identifier == SPRITE_MISC_BALLOON;
}
rct_balloon * rct_sprite::AsBalloon()
rct_balloon* rct_sprite::AsBalloon()
{
rct_balloon * result = nullptr;
rct_balloon* result = nullptr;
if (IsBalloon())
{
result = (rct_balloon *)this;
result = (rct_balloon*)this;
}
return result;
}
void rct_balloon::Update()
{
invalidate_sprite_2((rct_sprite *)this);
invalidate_sprite_2((rct_sprite*)this);
if (popped == 1)
{
frame++;
if (frame >= 5)
{
sprite_remove((rct_sprite *)this);
sprite_remove((rct_sprite*)this);
}
}
else
@ -73,7 +71,7 @@ void rct_balloon::Press()
else
{
int16_t shift = ((random & 0x80000000) ? -6 : 6);
sprite_move(x + shift, y, z, (rct_sprite *)this);
sprite_move(x + shift, y, z, (rct_sprite*)this);
}
}
}
@ -87,7 +85,7 @@ void rct_balloon::Pop()
static money32 game_command_balloon_press(uint16_t spriteIndex, uint8_t flags)
{
rct_sprite * sprite = try_get_sprite(spriteIndex);
rct_sprite* sprite = try_get_sprite(spriteIndex);
if (sprite == nullptr || !sprite->IsBalloon())
{
log_error("Tried getting invalid sprite for balloon: %u", spriteIndex);
@ -97,8 +95,7 @@ static money32 game_command_balloon_press(uint16_t spriteIndex, uint8_t flags)
{
if (flags & GAME_COMMAND_FLAG_APPLY)
{
sprite->AsBalloon()
->Press();
sprite->AsBalloon()->Press();
}
return 0;
}
@ -122,19 +119,19 @@ void create_balloon(int32_t x, int32_t y, int32_t z, int32_t colour, bool isPopp
}
}
void balloon_update(rct_balloon * balloon)
void balloon_update(rct_balloon* balloon)
{
balloon->Update();
}
void game_command_balloon_press(
int32_t * eax,
int32_t * ebx,
[[maybe_unused]] int32_t * ecx,
[[maybe_unused]] int32_t * edx,
[[maybe_unused]] int32_t * esi,
[[maybe_unused]] int32_t * edi,
[[maybe_unused]] int32_t * ebp)
int32_t* eax,
int32_t* ebx,
[[maybe_unused]] int32_t* ecx,
[[maybe_unused]] int32_t* edx,
[[maybe_unused]] int32_t* esi,
[[maybe_unused]] int32_t* edi,
[[maybe_unused]] int32_t* ebp)
{
*ebx = game_command_balloon_press(*eax & 0xFFFF, *ebx & 0xFF);
}

View File

@ -7,29 +7,29 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include <algorithm>
#include <cstring>
#include <limits>
#include "Banner.h"
#include "../Context.h"
#include "../Game.h"
#include "../core/Math.hpp"
#include "../core/Memory.hpp"
#include "../core/Util.hpp"
#include "../core/String.hpp"
#include "../core/Util.hpp"
#include "../interface/Window.h"
#include "../localisation/Localisation.h"
#include "../management/Finance.h"
#include "../network/network.h"
#include "Banner.h"
#include "../ride/Ride.h"
#include "../ride/Track.h"
#include "../windows/Intent.h"
#include "Map.h"
#include "MapAnimation.h"
#include "Park.h"
#include "Scenery.h"
#include "../Game.h"
#include "../interface/Window.h"
#include "../localisation/Localisation.h"
#include "../management/Finance.h"
#include "../ride/Ride.h"
#include "../ride/Track.h"
#include "../windows/Intent.h"
#include "../Context.h"
#include <algorithm>
#include <cstring>
#include <limits>
rct_banner gBanners[MAX_BANNERS];
@ -87,8 +87,8 @@ static money32 BannerRemove(int16_t x, int16_t y, uint8_t baseHeight, uint8_t di
return MONEY32_UNDEFINED;
}
rct_banner *banner = &gBanners[tileElement->properties.banner.index];
rct_scenery_entry *bannerEntry = get_banner_entry(banner->type);
rct_banner* banner = &gBanners[tileElement->properties.banner.index];
rct_scenery_entry* bannerEntry = get_banner_entry(banner->type);
money32 refund = 0;
if (bannerEntry != nullptr)
{
@ -165,7 +165,14 @@ static money32 BannerSetColour(int16_t x, int16_t y, uint8_t baseHeight, uint8_t
}
static money32 BannerPlace(
int16_t x, int16_t y, uint8_t pathBaseHeight, uint8_t direction, uint8_t colour, uint8_t type, BannerIndex* bannerIndex, uint8_t flags)
int16_t x,
int16_t y,
uint8_t pathBaseHeight,
uint8_t direction,
uint8_t colour,
uint8_t type,
BannerIndex* bannerIndex,
uint8_t flags)
{
gCommandPosition.x = x + 16;
gCommandPosition.y = y + 16;
@ -182,7 +189,7 @@ static money32 BannerPlace(
return MONEY32_UNDEFINED;
}
if (!map_is_location_valid({x, y}))
if (!map_is_location_valid({ x, y }))
{
return MONEY32_UNDEFINED;
}
@ -261,7 +268,7 @@ static money32 BannerPlace(
map_animation_create(MAP_ANIMATION_TYPE_BANNER, x, y, newTileElement->base_height);
}
rct_scenery_entry *bannerEntry = get_banner_entry(type);
rct_scenery_entry* bannerEntry = get_banner_entry(type);
if (bannerEntry == nullptr)
{
return MONEY32_UNDEFINED;
@ -358,7 +365,8 @@ static BannerIndex BannerGetNewIndex()
*/
void banner_init()
{
for (auto &banner : gBanners) {
for (auto& banner : gBanners)
{
banner.type = BANNER_NULL;
}
}
@ -396,8 +404,8 @@ BannerIndex create_new_banner(uint8_t flags)
rct_tile_element* banner_get_tile_element(BannerIndex bannerIndex)
{
rct_banner *banner = &gBanners[bannerIndex];
rct_tile_element *tileElement = map_get_first_element_at(banner->x, banner->y);
rct_banner* banner = &gBanners[bannerIndex];
rct_tile_element* tileElement = map_get_first_element_at(banner->x, banner->y);
do
{
if (tile_element_get_banner_index(tileElement) == bannerIndex)
@ -414,20 +422,10 @@ rct_tile_element* banner_get_tile_element(BannerIndex bannerIndex)
*/
uint8_t banner_get_closest_ride_index(int32_t x, int32_t y, int32_t z)
{
Ride *ride;
Ride* ride;
static constexpr const LocationXY16 NeighbourCheckOrder[] =
{
{ 32, 0 },
{ -32, 0 },
{ 0, 32 },
{ 0, -32 },
{ -32, +32 },
{ +32, -32 },
{ +32, +32 },
{ -32, +32 },
{ 0, 0 }
};
static constexpr const LocationXY16 NeighbourCheckOrder[]
= { { 32, 0 }, { -32, 0 }, { 0, 32 }, { 0, -32 }, { -32, +32 }, { +32, -32 }, { +32, +32 }, { -32, +32 }, { 0, 0 } };
for (size_t i = 0; i < (int32_t)Util::CountOf(NeighbourCheckOrder); i++)
{
@ -441,7 +439,7 @@ uint8_t banner_get_closest_ride_index(int32_t x, int32_t y, int32_t z)
uint8_t index;
uint8_t rideIndex = RIDE_ID_NULL;
int32_t resultDistance = std::numeric_limits<int32_t>::max();
FOR_ALL_RIDES(index, ride)
FOR_ALL_RIDES (index, ride)
{
if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IS_SHOP))
continue;
@ -467,7 +465,7 @@ void banner_reset_broken_index()
{
for (BannerIndex bannerIndex = 0; bannerIndex < MAX_BANNERS; bannerIndex++)
{
rct_tile_element *tileElement = banner_get_tile_element(bannerIndex);
rct_tile_element* tileElement = banner_get_tile_element(bannerIndex);
if (tileElement == nullptr)
gBanners[bannerIndex].type = BANNER_NULL;
}
@ -476,8 +474,8 @@ void banner_reset_broken_index()
void fix_duplicated_banners()
{
// For each banner in the map, check if the banner index is in use already, and if so, create a new entry for it
bool activeBanners[Util::CountOf(gBanners)]{};
rct_tile_element * tileElement;
bool activeBanners[Util::CountOf(gBanners)]{};
rct_tile_element* tileElement;
for (int y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++)
{
for (int x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++)
@ -493,7 +491,10 @@ void fix_duplicated_banners()
if (activeBanners[bannerIndex])
{
log_info(
"Duplicated banner with index %d found at x = %d, y = %d and z = %d.", bannerIndex, x, y,
"Duplicated banner with index %d found at x = %d, y = %d and z = %d.",
bannerIndex,
x,
y,
tileElement->base_height);
// Banner index is already in use by another banner, so duplicate it
@ -506,10 +507,10 @@ void fix_duplicated_banners()
Guard::Assert(activeBanners[newBannerIndex] == false);
// Copy over the original banner, but update the location
rct_banner & newBanner = gBanners[newBannerIndex];
newBanner = gBanners[bannerIndex];
newBanner.x = x;
newBanner.y = y;
rct_banner& newBanner = gBanners[newBannerIndex];
newBanner = gBanners[bannerIndex];
newBanner.x = x;
newBanner.y = y;
// Duplicate user string too
rct_string_id stringIdx = newBanner.string_idx;
@ -542,21 +543,15 @@ void fix_duplicated_banners()
* rct2: 0x006BA058
*/
void game_command_remove_banner(
int32_t * eax,
int32_t * ebx,
int32_t * ecx,
int32_t * edx,
[[maybe_unused]] int32_t * esi,
[[maybe_unused]] int32_t * edi,
[[maybe_unused]] int32_t * ebp)
int32_t* eax,
int32_t* ebx,
int32_t* ecx,
int32_t* edx,
[[maybe_unused]] int32_t* esi,
[[maybe_unused]] int32_t* edi,
[[maybe_unused]] int32_t* ebp)
{
*ebx = BannerRemove(
*eax & 0xFFFF,
*ecx & 0xFFFF,
*edx & 0xFF,
(*edx >> 8) & 0xFF,
*ebx & 0xFF
);
*ebx = BannerRemove(*eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, (*edx >> 8) & 0xFF, *ebx & 0xFF);
}
/**
@ -564,22 +559,15 @@ void game_command_remove_banner(
* rct2: 0x006BA16A
*/
void game_command_set_banner_colour(
int32_t * eax,
int32_t * ebx,
int32_t * ecx,
int32_t * edx,
[[maybe_unused]] int32_t * esi,
[[maybe_unused]] int32_t * edi,
int32_t * ebp)
int32_t* eax,
int32_t* ebx,
int32_t* ecx,
int32_t* edx,
[[maybe_unused]] int32_t* esi,
[[maybe_unused]] int32_t* edi,
int32_t* ebp)
{
*ebx = BannerSetColour(
*eax & 0xFFFF,
*ecx & 0xFFFF,
*edx & 0xFF,
(*edx >> 8) & 0xFF,
*ebp & 0xFF,
*ebx & 0xFF
);
*ebx = BannerSetColour(*eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, (*edx >> 8) & 0xFF, *ebp & 0xFF, *ebx & 0xFF);
}
/**
@ -587,7 +575,7 @@ void game_command_set_banner_colour(
* rct2: 0x006B9E6D
*/
void game_command_place_banner(
int32_t * eax, int32_t * ebx, int32_t * ecx, int32_t * edx, [[maybe_unused]] int32_t * esi, int32_t * edi, int32_t * ebp)
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, int32_t* edi, int32_t* ebp)
{
*ebx = BannerPlace(
*eax & 0xFFFF,
@ -597,24 +585,17 @@ void game_command_place_banner(
*ebp & 0xFF,
(*ebx >> 8) & 0xFF,
(BannerIndex*)edi,
*ebx & 0xFF
);
*ebx & 0xFF);
}
void game_command_set_banner_style(
[[maybe_unused]] int32_t * eax,
int32_t * ebx,
int32_t * ecx,
int32_t * edx,
[[maybe_unused]] int32_t * esi,
int32_t * edi,
int32_t * ebp)
[[maybe_unused]] int32_t* eax,
int32_t* ebx,
int32_t* ecx,
int32_t* edx,
[[maybe_unused]] int32_t* esi,
int32_t* edi,
int32_t* ebp)
{
*ebx = BannerSetStyle(
*ecx & 0xFF,
*edx & 0xFF,
*edi & 0xFF,
*ebp & 0xFF,
*ebx & 0xFF
);
*ebx = BannerSetStyle(*ecx & 0xFF, *edx & 0xFF, *edi & 0xFF, *ebp & 0xFF, *ebx & 0xFF);
}

View File

@ -20,7 +20,7 @@ constexpr BannerIndex BANNER_INDEX_NULL = (BannerIndex)-1;
struct rct_banner
{
uint8_t type;
uint8_t flags; // 0x01
uint8_t flags; // 0x01
rct_string_id string_idx; // 0x02
union
{
@ -50,4 +50,5 @@ rct_tile_element* banner_get_tile_element(BannerIndex bannerIndex);
uint8_t banner_get_closest_ride_index(int32_t x, int32_t y, int32_t z);
void banner_reset_broken_index();
void fix_duplicated_banners();
void game_command_callback_place_banner(int32_t eax, int32_t ebx, int32_t ecx, int32_t edx, int32_t esi, int32_t edi, int32_t ebp);
void game_command_callback_place_banner(
int32_t eax, int32_t ebx, int32_t ecx, int32_t edx, int32_t esi, int32_t edi, int32_t ebp);

View File

@ -7,23 +7,24 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "../audio/audio.h"
#include "../audio/AudioMixer.h"
#include "Climate.h"
#include "../Cheats.h"
#include "../Context.h"
#include "../Game.h"
#include "../OpenRCT2.h"
#include "../audio/AudioMixer.h"
#include "../audio/audio.h"
#include "../config/Config.h"
#include "../core/Math.hpp"
#include "../core/Util.hpp"
#include "../drawing/Drawing.h"
#include "../Game.h"
#include "../interface/Window.h"
#include "../localisation/Date.h"
#include "../OpenRCT2.h"
#include "../scenario/Scenario.h"
#include "../sprites.h"
#include "../util/Util.h"
#include "Climate.h"
#include "../windows/Intent.h"
#include "../Context.h"
constexpr int32_t MAX_THUNDER_INSTANCES = 2;
@ -40,26 +41,26 @@ struct WeatherTransition
int8_t Distribution[24];
};
extern const WeatherTransition * ClimateTransitions[4];
extern const WeatherState ClimateWeatherData[6];
extern const FILTER_PALETTE_ID ClimateWeatherGloomColours[4];
extern const WeatherTransition* ClimateTransitions[4];
extern const WeatherState ClimateWeatherData[6];
extern const FILTER_PALETTE_ID ClimateWeatherGloomColours[4];
// Climate data
uint8_t gClimate;
ClimateState gClimateCurrent;
ClimateState gClimateNext;
uint16_t gClimateUpdateTimer;
uint16_t gClimateLightningFlash;
uint8_t gClimate;
ClimateState gClimateCurrent;
ClimateState gClimateNext;
uint16_t gClimateUpdateTimer;
uint16_t gClimateLightningFlash;
// Sound data
static int32_t _rainVolume = 1;
static uint32_t _lightningTimer;
static uint32_t _thunderTimer;
static void * _thunderSoundChannels[MAX_THUNDER_INSTANCES];
static THUNDER_STATUS _thunderStatus[MAX_THUNDER_INSTANCES] = { THUNDER_STATUS::NONE, THUNDER_STATUS::NONE };
static uint32_t _thunderSoundId;
static int32_t _thunderVolume;
static int32_t _thunderStereoEcho = 0;
static int32_t _rainVolume = 1;
static uint32_t _lightningTimer;
static uint32_t _thunderTimer;
static void* _thunderSoundChannels[MAX_THUNDER_INSTANCES];
static THUNDER_STATUS _thunderStatus[MAX_THUNDER_INSTANCES] = { THUNDER_STATUS::NONE, THUNDER_STATUS::NONE };
static uint32_t _thunderSoundId;
static int32_t _thunderVolume;
static int32_t _thunderStereoEcho = 0;
static int8_t climate_step_weather_level(int8_t currentWeatherLevel, int8_t nextWeatherLevel);
static void climate_determine_future_weather(int32_t randomDistribution);
@ -81,8 +82,8 @@ void climate_reset(int32_t climate)
{
uint8_t weather = WEATHER_PARTIALLY_CLOUDY;
int32_t month = date_get_month(gDateMonthsElapsed);
const WeatherTransition * transition = &ClimateTransitions[climate][month];
const WeatherState * weatherState = &ClimateWeatherData[weather];
const WeatherTransition* transition = &ClimateTransitions[climate][month];
const WeatherState* weatherState = &ClimateWeatherData[weather];
gClimate = climate;
gClimateCurrent.Weather = weather;
@ -109,7 +110,8 @@ void climate_reset(int32_t climate)
void climate_update()
{
// Only do climate logic if playing (not in scenario editor or title screen)
if (gScreenFlags & (~SCREEN_FLAGS_PLAYING)) return;
if (gScreenFlags & (~SCREEN_FLAGS_PLAYING))
return;
if (!gCheatsFreezeClimate)
{
@ -141,12 +143,14 @@ void climate_update()
}
else if (gClimateNext.RainLevel <= RAIN_LEVEL_HEAVY)
{
gClimateCurrent.RainLevel = climate_step_weather_level(gClimateCurrent.RainLevel, gClimateNext.RainLevel);
gClimateCurrent.RainLevel
= climate_step_weather_level(gClimateCurrent.RainLevel, gClimateNext.RainLevel);
}
}
else
{
gClimateCurrent.WeatherGloom = climate_step_weather_level(gClimateCurrent.WeatherGloom, gClimateNext.WeatherGloom);
gClimateCurrent.WeatherGloom
= climate_step_weather_level(gClimateCurrent.WeatherGloom, gClimateNext.WeatherGloom);
gfx_invalidate_screen();
}
}
@ -157,7 +161,6 @@ void climate_update()
context_broadcast_intent(&intent);
}
}
}
if (_thunderTimer != 0)
@ -193,13 +196,16 @@ void climate_force_weather(uint8_t weather)
gfx_invalidate_screen();
}
void climate_update_sound()
{
if (gAudioCurrentDevice == -1) return;
if (gGameSoundsOff) return;
if (!gConfigSound.sound_enabled) return;
if (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) return;
if (gAudioCurrentDevice == -1)
return;
if (gGameSoundsOff)
return;
if (!gConfigSound.sound_enabled)
return;
if (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)
return;
climate_update_rain_sound();
climate_update_thunder_sound();
@ -210,7 +216,7 @@ bool climate_is_raining()
return gClimateCurrent.RainLevel != RAIN_LEVEL_NONE;
}
FILTER_PALETTE_ID climate_get_weather_gloom_palette_id(const ClimateState &state)
FILTER_PALETTE_ID climate_get_weather_gloom_palette_id(const ClimateState& state)
{
auto paletteId = PALETTE_NULL;
auto gloom = state.WeatherGloom;
@ -221,7 +227,7 @@ FILTER_PALETTE_ID climate_get_weather_gloom_palette_id(const ClimateState &state
return paletteId;
}
uint32_t climate_get_weather_sprite_id(const ClimateState &state)
uint32_t climate_get_weather_sprite_id(const ClimateState& state)
{
uint32_t spriteId = SPR_WEATHER_SUN;
if (state.Weather < Util::CountOf(ClimateWeatherData))
@ -244,17 +250,18 @@ static int8_t climate_step_weather_level(int8_t currentWeatherLevel, int8_t next
}
/**
* Calculates future weather development.
* RCT2 implements this as discrete probability distributions dependant on month and climate
* for nextWeather. The other weather parameters are then looked up depending only on the
* next weather.
*/
* Calculates future weather development.
* RCT2 implements this as discrete probability distributions dependant on month and climate
* for nextWeather. The other weather parameters are then looked up depending only on the
* next weather.
*/
static void climate_determine_future_weather(int32_t randomDistribution)
{
int8_t month = date_get_month(gDateMonthsElapsed);
// Generate a random variable with values 0 up to DistributionSize-1 and chose weather from the distribution table accordingly
const WeatherTransition * transition = &ClimateTransitions[gClimate][month];
// Generate a random variable with values 0 up to DistributionSize-1 and chose weather from the distribution table
// accordingly
const WeatherTransition* transition = &ClimateTransitions[gClimate][month];
int8_t nextWeather = transition->Distribution[((randomDistribution & 0xFF) * transition->DistributionSize) >> 8];
gClimateNext.Weather = nextWeather;
@ -269,8 +276,7 @@ static void climate_determine_future_weather(int32_t randomDistribution)
static void climate_update_rain_sound()
{
if (gClimateCurrent.WeatherEffect == WEATHER_EFFECT_RAIN ||
gClimateCurrent.WeatherEffect == WEATHER_EFFECT_STORM)
if (gClimateCurrent.WeatherEffect == WEATHER_EFFECT_RAIN || gClimateCurrent.WeatherEffect == WEATHER_EFFECT_STORM)
{
// Start playing the rain sound
if (gRainSoundChannel == nullptr)
@ -324,7 +330,7 @@ static void climate_update_thunder_sound()
{
if (_thunderStatus[i] != THUNDER_STATUS::NONE)
{
void * channel = _thunderSoundChannels[i];
void* channel = _thunderSoundChannels[i];
if (!Mixer_Channel_IsPlaying(channel))
{
Mixer_Stop_Channel(channel);
@ -336,9 +342,12 @@ static void climate_update_thunder_sound()
static void climate_update_lightning()
{
if (_lightningTimer == 0) return;
if (gConfigGeneral.disable_lightning_effect) return;
if (!gConfigGeneral.render_weather_effects && !gConfigGeneral.render_weather_gloom) return;
if (_lightningTimer == 0)
return;
if (gConfigGeneral.disable_lightning_effect)
return;
if (!gConfigGeneral.render_weather_effects && !gConfigGeneral.render_weather_gloom)
return;
_lightningTimer--;
if (gClimateLightningFlash == 0)
@ -358,8 +367,7 @@ static void climate_update_thunder()
uint32_t randomNumber = util_rand();
if (randomNumber & 0x10000)
{
if (_thunderStatus[0] == THUNDER_STATUS::NONE &&
_thunderStatus[1] == THUNDER_STATUS::NONE)
if (_thunderStatus[0] == THUNDER_STATUS::NONE && _thunderStatus[1] == THUNDER_STATUS::NONE)
{
// Play thunder on left side
_thunderSoundId = (randomNumber & 0x20000) ? SOUND_THUNDER_1 : SOUND_THUNDER_2;
@ -384,7 +392,8 @@ static void climate_update_thunder()
static void climate_play_thunder(int32_t instanceIndex, int32_t soundId, int32_t volume, int32_t pan)
{
_thunderSoundChannels[instanceIndex] = Mixer_Play_Effect(soundId, MIXER_LOOP_NONE, DStoMixerVolume(volume), DStoMixerPan(pan), 1, 0);
_thunderSoundChannels[instanceIndex]
= Mixer_Play_Effect(soundId, MIXER_LOOP_NONE, DStoMixerVolume(volume), DStoMixerPan(pan), 1, 0);
if (_thunderSoundChannels[instanceIndex] != nullptr)
{
_thunderStatus[instanceIndex] = THUNDER_STATUS::PLAYING;
@ -393,8 +402,7 @@ static void climate_play_thunder(int32_t instanceIndex, int32_t soundId, int32_t
#pragma region Climate / Weather data tables
const FILTER_PALETTE_ID ClimateWeatherGloomColours[4] =
{
const FILTER_PALETTE_ID ClimateWeatherGloomColours[4] = {
PALETTE_NULL,
PALETTE_DARKEN_1,
PALETTE_DARKEN_2,
@ -402,19 +410,17 @@ const FILTER_PALETTE_ID ClimateWeatherGloomColours[4] =
};
// There is actually a sprite at 0x5A9C for snow but only these weather types seem to be fully implemented
const WeatherState ClimateWeatherData[6] =
{
{ 10, WEATHER_EFFECT_NONE, 0, RAIN_LEVEL_NONE, SPR_WEATHER_SUN }, // Sunny
{ 5, WEATHER_EFFECT_NONE, 0, RAIN_LEVEL_NONE, SPR_WEATHER_SUN_CLOUD }, // Partially Cloudy
{ 0, WEATHER_EFFECT_NONE, 0, RAIN_LEVEL_NONE, SPR_WEATHER_CLOUD }, // Cloudy
{ -2, WEATHER_EFFECT_RAIN, 1, RAIN_LEVEL_LIGHT, SPR_WEATHER_LIGHT_RAIN }, // Rain
{ -4, WEATHER_EFFECT_RAIN, 2, RAIN_LEVEL_HEAVY, SPR_WEATHER_HEAVY_RAIN }, // Heavy Rain
{ 2, WEATHER_EFFECT_STORM, 2, RAIN_LEVEL_HEAVY, SPR_WEATHER_STORM }, // Thunderstorm
const WeatherState ClimateWeatherData[6] = {
{ 10, WEATHER_EFFECT_NONE, 0, RAIN_LEVEL_NONE, SPR_WEATHER_SUN }, // Sunny
{ 5, WEATHER_EFFECT_NONE, 0, RAIN_LEVEL_NONE, SPR_WEATHER_SUN_CLOUD }, // Partially Cloudy
{ 0, WEATHER_EFFECT_NONE, 0, RAIN_LEVEL_NONE, SPR_WEATHER_CLOUD }, // Cloudy
{ -2, WEATHER_EFFECT_RAIN, 1, RAIN_LEVEL_LIGHT, SPR_WEATHER_LIGHT_RAIN }, // Rain
{ -4, WEATHER_EFFECT_RAIN, 2, RAIN_LEVEL_HEAVY, SPR_WEATHER_HEAVY_RAIN }, // Heavy Rain
{ 2, WEATHER_EFFECT_STORM, 2, RAIN_LEVEL_HEAVY, SPR_WEATHER_STORM }, // Thunderstorm
};
static constexpr const WeatherTransition ClimateTransitionsCoolAndWet[] =
{
{ 8, 18, { 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 0, 0, 0, 0, 0 } },
static constexpr const WeatherTransition ClimateTransitionsCoolAndWet[] = {
{ 8, 18, { 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 0, 0, 0, 0, 0 } },
{ 10, 21, { 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 0, 0 } },
{ 14, 17, { 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 0, 0, 0, 0, 0, 0 } },
{ 17, 17, { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 0, 0, 0, 0, 0, 0 } },
@ -437,25 +443,24 @@ static constexpr const WeatherTransition ClimateTransitionsHotAndDry[] = {
{ 12, 15, { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ 14, 12, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ 16, 11, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ 19, 9, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ 19, 9, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ 21, 13, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ 22, 11, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ 21, 12, { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
{ 16, 13, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
};
static constexpr const WeatherTransition ClimateTransitionsCold[] = {
{ 4, 18, { 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 4, 0, 0, 0, 0, 0 } },
{ 5, 21, { 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 0, 0 } },
{ 7, 17, { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 0, 0, 0, 0, 0, 0 } },
{ 9, 17, { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 0, 0, 0, 0, 0, 0 } },
{ 4, 18, { 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 4, 0, 0, 0, 0, 0 } },
{ 5, 21, { 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 0, 0 } },
{ 7, 17, { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 0, 0, 0, 0, 0, 0 } },
{ 9, 17, { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 0, 0, 0, 0, 0, 0 } },
{ 10, 23, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 4 } },
{ 11, 23, { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 5 } },
{ 9, 19, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4, 5, 0, 0, 0, 0 } },
{ 6, 16, { 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0 } },
{ 9, 19, { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4, 5, 0, 0, 0, 0 } },
{ 6, 16, { 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0 } },
};
const WeatherTransition * ClimateTransitions[] =
{
const WeatherTransition* ClimateTransitions[] = {
ClimateTransitionsCoolAndWet,
ClimateTransitionsWarm,
ClimateTransitionsHotAndDry,

View File

@ -10,7 +10,6 @@
#pragma once
#include "../common.h"
#include "../drawing/Drawing.h"
enum CLIMATE
@ -47,11 +46,11 @@ enum RAIN_LEVEL
struct WeatherState
{
int8_t TemperatureDelta;
int8_t EffectLevel;
int8_t GloomLevel;
int8_t RainLevel;
uint32_t SpriteId;
int8_t TemperatureDelta;
int8_t EffectLevel;
int8_t GloomLevel;
int8_t RainLevel;
uint32_t SpriteId;
};
struct ClimateState
@ -63,11 +62,11 @@ struct ClimateState
uint8_t RainLevel;
};
extern uint8_t gClimate;
extern uint8_t gClimate;
extern ClimateState gClimateCurrent;
extern ClimateState gClimateNext;
extern uint16_t gClimateUpdateTimer;
extern uint16_t gClimateLightningFlash;
extern uint16_t gClimateUpdateTimer;
extern uint16_t gClimateLightningFlash;
int32_t climate_celsius_to_fahrenheit(int32_t celsius);
void climate_reset(int32_t climate);
@ -76,5 +75,5 @@ void climate_update_sound();
void climate_force_weather(uint8_t weather);
bool climate_is_raining();
FILTER_PALETTE_ID climate_get_weather_gloom_palette_id(const ClimateState &state);
uint32_t climate_get_weather_sprite_id(const ClimateState &state);
FILTER_PALETTE_ID climate_get_weather_gloom_palette_id(const ClimateState& state);
uint32_t climate_get_weather_sprite_id(const ClimateState& state);

View File

@ -7,18 +7,18 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include <limits>
#include "../Game.h"
#include "../audio/audio.h"
#include "../core/Math.hpp"
#include "../core/Util.hpp"
#include "../sprites.h"
#include "../audio/audio.h"
#include "../Game.h"
#include "../localisation/Date.h"
#include "../scenario/Scenario.h"
#include "../sprites.h"
#include "../world/Surface.h"
#include "Sprite.h"
#include <limits>
// clang-format off
enum DUCK_STATE
{
@ -76,38 +76,38 @@ static constexpr const uint8_t * DuckAnimations[] =
bool rct_sprite::IsDuck()
{
return this->duck.sprite_identifier == SPRITE_IDENTIFIER_MISC &&
this->duck.misc_identifier == SPRITE_MISC_DUCK;
return this->duck.sprite_identifier == SPRITE_IDENTIFIER_MISC && this->duck.misc_identifier == SPRITE_MISC_DUCK;
}
rct_duck * rct_sprite::AsDuck()
rct_duck* rct_sprite::AsDuck()
{
rct_duck * result = nullptr;
rct_duck* result = nullptr;
if (IsDuck())
{
return (rct_duck *)this;
return (rct_duck*)this;
}
return result;
}
void rct_duck::Invalidate()
{
invalidate_sprite_0((rct_sprite *)this);
invalidate_sprite_0((rct_sprite*)this);
}
void rct_duck::Remove()
{
sprite_remove((rct_sprite *)this);
sprite_remove((rct_sprite*)this);
}
void rct_duck::MoveTo(int16_t destX, int16_t destY, int16_t destZ)
{
sprite_move(destX, destY, destZ, (rct_sprite *)this);
sprite_move(destX, destY, destZ, (rct_sprite*)this);
}
void rct_duck::UpdateFlyToWater()
{
if ((gCurrentTicks & 3) != 0) return;
if ((gCurrentTicks & 3) != 0)
return;
frame++;
if (frame >= Util::CountOf(DuckAnimationFlyToWater))
@ -122,7 +122,7 @@ void rct_duck::UpdateFlyToWater()
int32_t newY = y + DuckMoveOffset[direction].y;
int32_t manhattanDistanceN = abs(target_x - newX) + abs(target_y - newY);
rct_tile_element * tileElement = map_get_surface_element_at({target_x, target_y});
rct_tile_element* tileElement = map_get_surface_element_at({ target_x, target_y });
int32_t waterHeight = surface_get_water_height(tileElement);
if (waterHeight == 0)
{
@ -171,7 +171,8 @@ void rct_duck::UpdateFlyToWater()
void rct_duck::UpdateSwim()
{
if (((gCurrentTicks + sprite_index) & 3) != 0) return;
if (((gCurrentTicks + sprite_index) & 3) != 0)
return;
uint32_t randomNumber = scenario_rand();
if ((randomNumber & 0xFFFF) < 0x666)
@ -282,7 +283,7 @@ void rct_duck::UpdateFlyAway()
int32_t newX = x + (DuckMoveOffset[direction].x * 2);
int32_t newY = y + (DuckMoveOffset[direction].y * 2);
int32_t newZ = std::min(z + 2, 496);
if (map_is_location_valid({newX, newY}))
if (map_is_location_valid({ newX, newY }))
{
MoveTo(newX, newY, newZ);
Invalidate();
@ -308,7 +309,7 @@ uint32_t rct_duck::GetFrameImage(int32_t direction) const
void create_duck(int32_t targetX, int32_t targetY)
{
rct_sprite * sprite = create_sprite(2);
rct_sprite* sprite = create_sprite(2);
if (sprite != nullptr)
{
sprite->duck.sprite_identifier = SPRITE_IDENTIFIER_MISC;
@ -322,19 +323,20 @@ void create_duck(int32_t targetX, int32_t targetY)
sprite->duck.target_x = targetX;
sprite->duck.target_y = targetY;
uint8_t direction = scenario_rand() & 3;
switch (direction) {
case 0:
targetX = 8191 - (scenario_rand() & 0x3F);
break;
case 1:
targetY = scenario_rand() & 0x3F;
break;
case 2:
targetX = scenario_rand() & 0x3F;
break;
case 3:
targetY = 8191 - (scenario_rand() & 0x3F);
break;
switch (direction)
{
case 0:
targetX = 8191 - (scenario_rand() & 0x3F);
break;
case 1:
targetY = scenario_rand() & 0x3F;
break;
case 2:
targetX = scenario_rand() & 0x3F;
break;
case 3:
targetY = 8191 - (scenario_rand() & 0x3F);
break;
}
sprite->duck.sprite_direction = direction << 3;
sprite_move(targetX, targetY, 496, sprite);
@ -343,28 +345,29 @@ void create_duck(int32_t targetX, int32_t targetY)
}
}
void duck_update(rct_duck * duck)
void duck_update(rct_duck* duck)
{
switch ((DUCK_STATE)duck->state) {
case DUCK_STATE::FLY_TO_WATER:
duck->UpdateFlyToWater();
break;
case DUCK_STATE::SWIM:
duck->UpdateSwim();
break;
case DUCK_STATE::DRINK:
duck->UpdateDrink();
break;
case DUCK_STATE::DOUBLE_DRINK:
duck->UpdateDoubleDrink();
break;
case DUCK_STATE::FLY_AWAY:
duck->UpdateFlyAway();
break;
switch ((DUCK_STATE)duck->state)
{
case DUCK_STATE::FLY_TO_WATER:
duck->UpdateFlyToWater();
break;
case DUCK_STATE::SWIM:
duck->UpdateSwim();
break;
case DUCK_STATE::DRINK:
duck->UpdateDrink();
break;
case DUCK_STATE::DOUBLE_DRINK:
duck->UpdateDoubleDrink();
break;
case DUCK_STATE::FLY_AWAY:
duck->UpdateFlyAway();
break;
}
}
void duck_press(rct_duck * duck)
void duck_press(rct_duck* duck)
{
audio_play_sound_at_location(SOUND_QUACK, duck->x, duck->y, duck->z);
}
@ -372,19 +375,19 @@ void duck_press(rct_duck * duck)
void duck_remove_all()
{
uint16_t nextSpriteIndex;
for (uint16_t spriteIndex = gSpriteListHead[SPRITE_LIST_MISC]; spriteIndex != SPRITE_INDEX_NULL; spriteIndex = nextSpriteIndex)
for (uint16_t spriteIndex = gSpriteListHead[SPRITE_LIST_MISC]; spriteIndex != SPRITE_INDEX_NULL;
spriteIndex = nextSpriteIndex)
{
rct_unk_sprite * sprite = &(get_sprite(spriteIndex)->unknown);
rct_unk_sprite* sprite = &(get_sprite(spriteIndex)->unknown);
nextSpriteIndex = sprite->next;
if (sprite->misc_identifier == SPRITE_MISC_DUCK)
{
sprite_remove((rct_sprite *)sprite);
sprite_remove((rct_sprite*)sprite);
}
}
}
uint32_t duck_get_frame_image(const rct_duck * duck, int32_t direction)
uint32_t duck_get_frame_image(const rct_duck* duck, int32_t direction)
{
return duck->GetFrameImage(direction);
}

View File

@ -7,21 +7,21 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "../network/network.h"
#include "../OpenRCT2.h"
#include "Entrance.h"
#include "../Cheats.h"
#include "../Game.h"
#include "../OpenRCT2.h"
#include "../localisation/StringIds.h"
#include "../management/Finance.h"
#include "../network/network.h"
#include "../ride/Station.h"
#include "../ride/Track.h"
#include "Footpath.h"
#include "Map.h"
#include "MapAnimation.h"
#include "Park.h"
#include "Sprite.h"
#include "../Cheats.h"
#include "../Game.h"
#include "../localisation/StringIds.h"
#include "../management/Finance.h"
#include "../ride/Track.h"
#include "../ride/Station.h"
bool gParkEntranceGhostExists = false;
LocationXYZ16 gParkEntranceGhostPosition = { 0, 0, 0 };
@ -33,7 +33,7 @@ uint8_t gRideEntranceExitGhostStationIndex;
static void ParkEntranceRemoveSegment(int32_t x, int32_t y, int32_t z)
{
rct_tile_element *tileElement;
rct_tile_element* tileElement;
tileElement = map_get_park_entrance_element_at(x, y, z, true);
if (tileElement == nullptr)
@ -43,7 +43,7 @@ static void ParkEntranceRemoveSegment(int32_t x, int32_t y, int32_t z)
map_invalidate_tile(x, y, tileElement->base_height * 8, tileElement->clearance_height * 8);
tile_element_remove(tileElement);
update_park_fences({x, y});
update_park_fences({ x, y });
}
static money32 ParkEntranceRemove(int16_t x, int16_t y, uint8_t z, uint8_t flags)
@ -78,30 +78,16 @@ static money32 ParkEntranceRemove(int16_t x, int16_t y, uint8_t z, uint8_t flags
ParkEntranceRemoveSegment(x, y, z * 2);
// Left post
ParkEntranceRemoveSegment(
x + CoordsDirectionDelta[direction].x,
y + CoordsDirectionDelta[direction].y,
z * 2
);
ParkEntranceRemoveSegment(x + CoordsDirectionDelta[direction].x, y + CoordsDirectionDelta[direction].y, z * 2);
// Right post
ParkEntranceRemoveSegment(
x - CoordsDirectionDelta[direction].x,
y - CoordsDirectionDelta[direction].y,
z * 2
);
ParkEntranceRemoveSegment(x - CoordsDirectionDelta[direction].x, y - CoordsDirectionDelta[direction].y, z * 2);
return 0;
}
static money32 RideEntranceExitPlace(int16_t x,
int16_t y,
int16_t z,
uint8_t direction,
uint8_t flags,
uint8_t rideIndex,
uint8_t stationNum,
bool isExit)
static money32 RideEntranceExitPlace(
int16_t x, int16_t y, int16_t z, uint8_t direction, uint8_t flags, uint8_t rideIndex, uint8_t 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
@ -136,8 +122,9 @@ static money32 RideEntranceExitPlace(int16_t x,
int16_t 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, CREATE_CROSSING_MODE_NONE))
if (!gCheatsDisableClearanceChecks
&& !map_can_construct_with_clear_at(
x, y, z / 8, clear_z, &map_place_non_scenery_clear_func, 0xF, flags, &cost, CREATE_CROSSING_MODE_NONE))
{
return MONEY32_UNDEFINED;
}
@ -223,14 +210,7 @@ static money32 RideEntranceExitPlace(int16_t x,
if (requiresRemove)
{
money32 success = game_do_command(
removeCoord.x,
flags,
removeCoord.y,
rideIndex,
GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT,
stationNum,
0
);
removeCoord.x, flags, removeCoord.y, rideIndex, GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT, stationNum, 0);
if (success == MONEY32_UNDEFINED)
{
@ -241,9 +221,8 @@ static money32 RideEntranceExitPlace(int16_t x,
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))
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);
@ -256,8 +235,9 @@ static money32 RideEntranceExitPlace(int16_t x,
int8_t 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, CREATE_CROSSING_MODE_NONE))
if (!gCheatsDisableClearanceChecks
&& !map_can_construct_with_clear_at(
x, y, z / 8, clear_z, &map_place_non_scenery_clear_func, 0xF, flags, &cost, CREATE_CROSSING_MODE_NONE))
{
return MONEY32_UNDEFINED;
}
@ -298,11 +278,13 @@ static money32 RideEntranceExitPlace(int16_t x,
if (isExit)
{
ride_set_exit_location(ride, stationNum, { x / 32, y / 32, z / 8, (uint8_t)tile_element_get_direction(tileElement)});
ride_set_exit_location(
ride, stationNum, { x / 32, y / 32, z / 8, (uint8_t)tile_element_get_direction(tileElement) });
}
else
{
ride_set_entrance_location(ride, stationNum, { x / 32, y / 32, z / 8, (uint8_t)tile_element_get_direction(tileElement)});
ride_set_entrance_location(
ride, stationNum, { x / 32, y / 32, z / 8, (uint8_t)tile_element_get_direction(tileElement) });
ride->last_peep_in_queue[stationNum] = SPRITE_INDEX_NULL;
ride->queue_length[stationNum] = 0;
@ -344,9 +326,7 @@ static money32 RideEntranceExitRemove(int16_t x, int16_t y, uint8_t rideIndex, u
if (!(flags & GAME_COMMAND_FLAG_GHOST))
{
if (!(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) &&
game_is_paused() &&
!gCheatsBuildInPauseMode)
if (!(flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED) && game_is_paused() && !gCheatsBuildInPauseMode)
{
gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED;
return MONEY32_UNDEFINED;
@ -395,8 +375,7 @@ static money32 RideEntranceExitRemove(int16_t x, int16_t y, uint8_t rideIndex, u
found = true;
break;
}
while (!(tileElement++)->IsLastForTile());
} while (!(tileElement++)->IsLastForTile());
if (!found)
{
@ -435,21 +414,18 @@ static money32 RideEntranceExitRemove(int16_t x, int16_t y, uint8_t rideIndex, u
return 0;
}
static money32 RideEntranceExitPlaceGhost(uint8_t rideIndex, int16_t x, int16_t y, uint8_t direction, uint8_t placeType, uint8_t stationNum)
static money32 RideEntranceExitPlaceGhost(
uint8_t rideIndex, int16_t x, int16_t y, uint8_t direction, uint8_t placeType, uint8_t 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),
(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
);
0);
}
/**
@ -457,19 +433,15 @@ static money32 RideEntranceExitPlaceGhost(uint8_t rideIndex, int16_t x, int16_t
* rct2: 0x00666A63
*/
void game_command_remove_park_entrance(
int32_t * eax,
int32_t * ebx,
int32_t * ecx,
int32_t * edx,
[[maybe_unused]] int32_t * esi,
[[maybe_unused]] int32_t * edi,
[[maybe_unused]] int32_t * ebp)
int32_t* eax,
int32_t* ebx,
int32_t* ecx,
int32_t* edx,
[[maybe_unused]] int32_t* esi,
[[maybe_unused]] int32_t* edi,
[[maybe_unused]] int32_t* ebp)
{
*ebx = ParkEntranceRemove(
*eax & 0xFFFF,
*ecx & 0xFFFF,
*edx & 0xFF,
*ebx & 0xFF);
*ebx = ParkEntranceRemove(*eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, *ebx & 0xFF);
}
/**
@ -488,8 +460,7 @@ void park_entrance_remove_ghost()
gParkEntranceGhostPosition.z,
GAME_COMMAND_REMOVE_PARK_ENTRANCE,
0,
0
);
0);
}
}
@ -499,9 +470,7 @@ int32_t park_entrance_get_index(int32_t x, int32_t y, int32_t z)
for (i = 0; i < MAX_PARK_ENTRANCES; i++)
{
if (x == gParkEntrances[i].x &&
y == gParkEntrances[i].y &&
z == gParkEntrances[i].z)
if (x == gParkEntrances[i].x && y == gParkEntrances[i].y && z == gParkEntrances[i].z)
{
return i;
}
@ -512,28 +481,30 @@ int32_t park_entrance_get_index(int32_t x, int32_t y, int32_t z)
void reset_park_entrance()
{
for (auto &parkEntrance : gParkEntrances)
for (auto& parkEntrance : gParkEntrances)
{
parkEntrance.x = 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);
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) {
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),
@ -541,22 +512,16 @@ void ride_entrance_exit_remove_ghost()
_currentRideIndex,
GAME_COMMAND_REMOVE_RIDE_ENTRANCE_OR_EXIT,
gRideEntranceExitGhostStationIndex,
0
);
0);
}
}
/**
*
* rct2: 0x006CA28C
*/
money32 ride_entrance_exit_place_ghost(int32_t rideIndex,
int32_t x,
int32_t y,
int32_t direction,
int32_t placeType,
int32_t stationNum)
money32 ride_entrance_exit_place_ghost(
int32_t rideIndex, int32_t x, int32_t y, int32_t direction, int32_t placeType, int32_t stationNum)
{
ride_construction_remove_ghosts();
money32 result = RideEntranceExitPlaceGhost(rideIndex, x, y, direction, placeType, stationNum);
@ -577,13 +542,13 @@ money32 ride_entrance_exit_place_ghost(int32_t rideIndex,
* rct2: 0x006660A8
*/
void game_command_place_ride_entrance_or_exit(
int32_t * eax,
int32_t * ebx,
int32_t * ecx,
int32_t * edx,
[[maybe_unused]] int32_t * esi,
int32_t * edi,
[[maybe_unused]] int32_t * ebp)
int32_t* eax,
int32_t* ebx,
int32_t* ecx,
int32_t* edx,
[[maybe_unused]] int32_t* esi,
int32_t* edi,
[[maybe_unused]] int32_t* ebp)
{
*ebx = RideEntranceExitPlace(
*eax & 0xFFFF,
@ -593,8 +558,7 @@ void game_command_place_ride_entrance_or_exit(
*ebx & 0xFF,
*edx & 0xFF,
*edi & 0xFF,
((*edx >> 8) & 0xFF) != 0
);
((*edx >> 8) & 0xFF) != 0);
}
/**
@ -602,28 +566,22 @@ void game_command_place_ride_entrance_or_exit(
* rct2: 0x0066640B
*/
void game_command_remove_ride_entrance_or_exit(
int32_t * eax,
int32_t * ebx,
int32_t * ecx,
int32_t * edx,
[[maybe_unused]] int32_t * esi,
int32_t * edi,
[[maybe_unused]] int32_t * ebp)
int32_t* eax,
int32_t* ebx,
int32_t* ecx,
int32_t* edx,
[[maybe_unused]] int32_t* esi,
int32_t* edi,
[[maybe_unused]] int32_t* ebp)
{
*ebx = RideEntranceExitRemove(
*eax & 0xFFFF,
*ecx & 0xFFFF,
*edx & 0xFF,
*edi & 0xFF,
*ebx & 0xFF
);
*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(int32_t x, int32_t y, rct_tile_element *tileElement)
void maze_entrance_hedge_replacement(int32_t x, int32_t y, rct_tile_element* tileElement)
{
int32_t direction = tile_element_get_direction(tileElement);
x += CoordsDirectionDelta[direction].x;
@ -632,11 +590,16 @@ void maze_entrance_hedge_replacement(int32_t x, int32_t y, rct_tile_element *til
int32_t rideIndex = track_element_get_ride_index(tileElement);
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) continue;
if (track_element_get_ride_index(tileElement) != rideIndex) continue;
if (tileElement->base_height != z) continue;
if (track_element_get_type(tileElement) != TRACK_ELEM_MAZE) continue;
do
{
if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK)
continue;
if (track_element_get_ride_index(tileElement) != rideIndex)
continue;
if (tileElement->base_height != z)
continue;
if (track_element_get_type(tileElement) != TRACK_ELEM_MAZE)
continue;
// Each maze element is split into 4 sections with 4 different walls
uint8_t mazeSection = direction * 4;
@ -654,7 +617,7 @@ void maze_entrance_hedge_replacement(int32_t x, int32_t y, rct_tile_element *til
* Removes the hedge walls for an entrance placement.
* rct2: 0x00666CBE
*/
void maze_entrance_hedge_removal(int32_t x, int32_t y, rct_tile_element *tileElement)
void maze_entrance_hedge_removal(int32_t x, int32_t y, rct_tile_element* tileElement)
{
int32_t direction = tile_element_get_direction(tileElement);
x += CoordsDirectionDelta[direction].x;
@ -663,11 +626,16 @@ void maze_entrance_hedge_removal(int32_t x, int32_t y, rct_tile_element *tileEle
int32_t rideIndex = track_element_get_ride_index(tileElement);
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK) continue;
if (track_element_get_ride_index(tileElement) != rideIndex) continue;
if (tileElement->base_height != z) continue;
if (track_element_get_type(tileElement) != TRACK_ELEM_MAZE) continue;
do
{
if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK)
continue;
if (track_element_get_ride_index(tileElement) != rideIndex)
continue;
if (tileElement->base_height != z)
continue;
if (track_element_get_type(tileElement) != TRACK_ELEM_MAZE)
continue;
// Each maze element is split into 4 sections with 4 different walls
uint8_t mazeSection = direction * 4;
@ -690,18 +658,14 @@ void maze_entrance_hedge_removal(int32_t x, int32_t y, rct_tile_element *tileEle
void fix_park_entrance_locations(void)
{
// Fix gParkEntrance locations for which the tile_element no longer exists
for (auto &entrance : gParkEntrances)
for (auto& entrance : gParkEntrances)
{
if (entrance.x == LOCATION_NULL)
continue;
if (map_get_park_entrance_element_at(
entrance.x,
entrance.y,
entrance.z >> 3, false) == nullptr)
if (map_get_park_entrance_element_at(entrance.x, entrance.y, entrance.z >> 3, false) == nullptr)
{
entrance.x = LOCATION_NULL;
}
}
}

View File

@ -14,16 +14,18 @@
#include "Location.hpp"
#pragma pack(push, 1)
struct rct_entrance_type {
rct_string_id string_idx; // 0x00
uint32_t image_id; // 0x02
uint8_t scrolling_mode; // 0x06
uint8_t text_height; // 0x07
struct rct_entrance_type
{
rct_string_id string_idx; // 0x00
uint32_t image_id; // 0x02
uint8_t scrolling_mode; // 0x06
uint8_t text_height; // 0x07
};
assert_struct_size(rct_entrance_type, 8);
#pragma pack(pop)
void game_command_remove_park_entrance(int32_t *eax, int32_t *ebx, int32_t *ecx, int32_t *edx, int32_t *esi, int32_t *edi, int32_t *ebp);
void game_command_remove_park_entrance(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
struct rct_tile_element;
@ -43,8 +45,8 @@ money32 park_entrance_place_ghost(int32_t x, int32_t y, int32_t z, int32_t direc
money32 place_park_entrance(int16_t x, int16_t y, int16_t z, uint8_t direction);
void reset_park_entrance();
void maze_entrance_hedge_replacement(int32_t x, int32_t y, rct_tile_element *tileElement);
void maze_entrance_hedge_removal(int32_t x, int32_t y, rct_tile_element *tileElement);
void maze_entrance_hedge_replacement(int32_t x, int32_t y, rct_tile_element* tileElement);
void maze_entrance_hedge_removal(int32_t x, int32_t y, rct_tile_element* tileElement);
void fix_park_entrance_locations();

File diff suppressed because it is too large Load Diff

View File

@ -17,20 +17,21 @@
enum
{
PROVISIONAL_PATH_FLAG_SHOW_ARROW = (1 << 0),
PROVISIONAL_PATH_FLAG_1 = (1 << 1),
PROVISIONAL_PATH_FLAG_2 = (1 << 2),
PROVISIONAL_PATH_FLAG_1 = (1 << 1),
PROVISIONAL_PATH_FLAG_2 = (1 << 2),
};
#define FOOTPATH_ELEMENT_INSERT_QUEUE 0x80
#pragma pack(push, 1)
struct rct_footpath_entry {
rct_string_id string_idx; // 0x00
uint32_t image; // 0x02
uint32_t bridge_image; // 0x06
uint8_t support_type; // 0x0A
uint8_t flags; // 0x0B
uint8_t scrolling_mode; // 0x0C
struct rct_footpath_entry
{
rct_string_id string_idx; // 0x00
uint32_t image; // 0x02
uint32_t bridge_image; // 0x06
uint8_t support_type; // 0x0A
uint8_t flags; // 0x0B
uint8_t scrolling_mode; // 0x0C
};
assert_struct_size(rct_footpath_entry, 13);
#pragma pack(pop)
@ -38,34 +39,34 @@ assert_struct_size(rct_footpath_entry, 13);
// Masks for values stored in rct_tile_element.type
enum
{
FOOTPATH_ELEMENT_TYPE_FLAG_IS_QUEUE = (1 << 0),
FOOTPATH_ELEMENT_TYPE_FLAG_IS_WIDE = (1 << 1),
FOOTPATH_ELEMENT_TYPE_FLAG_IS_QUEUE = (1 << 0),
FOOTPATH_ELEMENT_TYPE_FLAG_IS_WIDE = (1 << 1),
FOOTPATH_ELEMENT_TYPE_DIRECTION_MASK = (1 << 6) | (1 << 7),
};
// Masks and flags for values stored in rct_tile_element.properties.path.type
enum
{
FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK = (1 << 0) | (1 << 1),
FOOTPATH_PROPERTIES_FLAG_IS_SLOPED = (1 << 2),
FOOTPATH_PROPERTIES_SLOPE_DIRECTION_MASK = (1 << 0) | (1 << 1),
FOOTPATH_PROPERTIES_FLAG_IS_SLOPED = (1 << 2),
FOOTPATH_PROPERTIES_FLAG_HAS_QUEUE_BANNER = (1 << 3),
FOOTPATH_PROPERTIES_TYPE_MASK = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7),
FOOTPATH_PROPERTIES_TYPE_MASK = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7),
};
// Masks and flags for values stored in in rct_tile_element.properties.path.edges
enum
{
FOOTPATH_PROPERTIES_EDGES_EDGES_MASK = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3),
FOOTPATH_PROPERTIES_EDGES_EDGES_MASK = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3),
FOOTPATH_PROPERTIES_EDGES_CORNERS_MASK = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7),
};
// Masks and flags for values stored in in rct_tile_element.properties.path.additions
enum
{
FOOTPATH_PROPERTIES_ADDITIONS_TYPE_MASK = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3),
FOOTPATH_PROPERTIES_ADDITIONS_TYPE_MASK = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3),
// The most significant bit in this mask will always be zero, since rides can only have 4 stations
FOOTPATH_PROPERTIES_ADDITIONS_STATION_INDEX_MASK = (1 << 4) | (1 << 5) | (1 << 6),
FOOTPATH_PROPERTIES_ADDITIONS_FLAG_GHOST = (1 << 7),
FOOTPATH_PROPERTIES_ADDITIONS_FLAG_GHOST = (1 << 7),
};
enum
@ -77,8 +78,8 @@ enum
enum
{
FOOTPATH_ENTRY_FLAG_HAS_SUPPORT_BASE_SPRITE = (1 << 0),
FOOTPATH_ENTRY_FLAG_HAS_PATH_BASE_SPRITE = (1 << 1), // When elevated
FOOTPATH_ENTRY_FLAG_HAS_SUPPORT_BASE_SPRITE = (1 << 0),
FOOTPATH_ENTRY_FLAG_HAS_PATH_BASE_SPRITE = (1 << 1), // When elevated
FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR = (1 << 2),
};
@ -97,7 +98,7 @@ enum
enum
{
FOOTPATH_CLEAR_DIRECTIONAL = (1 << 8), // Flag set when direction is used.
FOOTPATH_CLEAR_DIRECTIONAL = (1 << 8), // Flag set when direction is used.
};
enum
@ -123,55 +124,62 @@ extern const LocationXY16 word_981D6C[4];
extern const LocationXY16 BinUseOffsets[4];
extern const LocationXY16 BenchUseOffsets[8];
rct_tile_element *map_get_footpath_element(int32_t x, int32_t y, int32_t z);
rct_tile_element* map_get_footpath_element(int32_t x, int32_t y, int32_t z);
money32 footpath_remove_real(int32_t x, int32_t y, int32_t z, int32_t flags);
void game_command_place_footpath(int32_t * eax, int32_t * ebx, int32_t * ecx, int32_t * edx, int32_t * esi, int32_t * edi, int32_t * ebp);
void game_command_place_footpath_from_track(int32_t * eax, int32_t * ebx, int32_t * ecx, int32_t * edx, int32_t * esi, int32_t * edi, int32_t * ebp);
void game_command_remove_footpath(int32_t * eax, int32_t * ebx, int32_t * ecx, int32_t * edx, int32_t * esi, int32_t * edi, int32_t * ebp);
void game_command_place_footpath(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_place_footpath_from_track(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_remove_footpath(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
money32 footpath_place(int32_t type, int32_t x, int32_t y, int32_t z, int32_t slope, int32_t flags);
money32 footpath_place_remove_intersecting(int32_t type, int32_t x, int32_t y, int32_t z, int32_t slope, int32_t flags, int32_t direction);
money32 footpath_place_remove_intersecting(
int32_t type, int32_t x, int32_t y, int32_t z, int32_t slope, int32_t flags, int32_t direction);
void footpath_remove(int32_t x, int32_t y, int32_t z, int32_t flags);
money32 footpath_provisional_set(int32_t type, int32_t x, int32_t y, int32_t z, int32_t slope);
void footpath_provisional_remove();
void footpath_provisional_update();
void footpath_get_coordinates_from_pos(int32_t screenX, int32_t screenY, int32_t * x, int32_t * y, int32_t * direction, rct_tile_element ** tileElement);
void footpath_bridge_get_info_from_pos(int32_t screenX, int32_t screenY, int32_t * x, int32_t * y, int32_t * direction, rct_tile_element ** tileElement);
void footpath_get_coordinates_from_pos(
int32_t screenX, int32_t screenY, int32_t* x, int32_t* y, int32_t* direction, rct_tile_element** tileElement);
void footpath_bridge_get_info_from_pos(
int32_t screenX, int32_t screenY, int32_t* x, int32_t* y, int32_t* direction, rct_tile_element** tileElement);
void footpath_remove_litter(int32_t x, int32_t y, int32_t z);
void footpath_connect_edges(int32_t x, int32_t y, rct_tile_element * tileElement, int32_t flags);
void footpath_connect_edges(int32_t x, int32_t y, rct_tile_element* tileElement, int32_t flags);
void footpath_update_queue_chains();
bool fence_in_the_way(int32_t x, int32_t y, int32_t z0, int32_t z1, int32_t direction);
void footpath_chain_ride_queue(int32_t rideIndex, int32_t entranceIndex, int32_t x, int32_t y, rct_tile_element * tileElement, int32_t direction);
void footpath_chain_ride_queue(
int32_t rideIndex, int32_t entranceIndex, int32_t x, int32_t y, rct_tile_element* tileElement, int32_t direction);
void footpath_update_path_wide_flags(int32_t x, int32_t y);
bool footpath_is_blocked_by_vehicle(const TileCoordsXYZ& position);
int32_t footpath_is_connected_to_map_edge(int32_t x, int32_t y, int32_t z, int32_t direction, int32_t flags);
bool footpath_element_is_sloped(const rct_tile_element * tileElement);
void footpath_element_set_sloped(rct_tile_element * tileElement, bool isSloped);
uint8_t footpath_element_get_slope_direction(const rct_tile_element * tileElement);
bool footpath_element_is_queue(const rct_tile_element * tileElement);
void footpath_element_set_queue(rct_tile_element * tileElement);
void footpath_element_clear_queue(rct_tile_element * tileElement);
bool footpath_element_has_queue_banner(const rct_tile_element * tileElement);
bool footpath_element_is_wide(const rct_tile_element * tileElement);
uint8_t footpath_element_get_type(const rct_tile_element * tileElement);
void footpath_element_set_type(rct_tile_element * tileElement, uint8_t type);
uint8_t footpath_element_get_direction(const rct_tile_element * tileElement);
void footpath_element_set_direction(rct_tile_element * tileElement, uint8_t direction);
void footpath_element_set_wide(rct_tile_element * tileElement, bool isWide);
bool footpath_element_has_path_scenery(const rct_tile_element * tileElement);
uint8_t footpath_element_get_path_scenery(const rct_tile_element * tileElement);
void footpath_element_set_path_scenery(rct_tile_element * tileElement, uint8_t pathSceneryType);
uint8_t footpath_element_get_path_scenery_index(const rct_tile_element * tileElement);
bool footpath_element_path_scenery_is_ghost(const rct_tile_element * tileElement);
void footpath_scenery_set_is_ghost(rct_tile_element * tileElement, bool isGhost);
void footpath_remove_edges_at(int32_t x, int32_t y, rct_tile_element * tileElement);
int32_t entrance_get_directions(const rct_tile_element * tileElement);
bool footpath_element_is_sloped(const rct_tile_element* tileElement);
void footpath_element_set_sloped(rct_tile_element* tileElement, bool isSloped);
uint8_t footpath_element_get_slope_direction(const rct_tile_element* tileElement);
bool footpath_element_is_queue(const rct_tile_element* tileElement);
void footpath_element_set_queue(rct_tile_element* tileElement);
void footpath_element_clear_queue(rct_tile_element* tileElement);
bool footpath_element_has_queue_banner(const rct_tile_element* tileElement);
bool footpath_element_is_wide(const rct_tile_element* tileElement);
uint8_t footpath_element_get_type(const rct_tile_element* tileElement);
void footpath_element_set_type(rct_tile_element* tileElement, uint8_t type);
uint8_t footpath_element_get_direction(const rct_tile_element* tileElement);
void footpath_element_set_direction(rct_tile_element* tileElement, uint8_t direction);
void footpath_element_set_wide(rct_tile_element* tileElement, bool isWide);
bool footpath_element_has_path_scenery(const rct_tile_element* tileElement);
uint8_t footpath_element_get_path_scenery(const rct_tile_element* tileElement);
void footpath_element_set_path_scenery(rct_tile_element* tileElement, uint8_t pathSceneryType);
uint8_t footpath_element_get_path_scenery_index(const rct_tile_element* tileElement);
bool footpath_element_path_scenery_is_ghost(const rct_tile_element* tileElement);
void footpath_scenery_set_is_ghost(rct_tile_element* tileElement, bool isGhost);
void footpath_remove_edges_at(int32_t x, int32_t y, rct_tile_element* tileElement);
int32_t entrance_get_directions(const rct_tile_element* tileElement);
rct_footpath_entry * get_footpath_entry(int32_t entryIndex);
rct_footpath_entry* get_footpath_entry(int32_t entryIndex);
void footpath_queue_chain_reset();
void footpath_queue_chain_push(uint8_t rideIndex);
uint8_t footpath_get_edges(const rct_tile_element * element);
uint8_t footpath_get_edges(const rct_tile_element* element);
#endif

View File

@ -30,147 +30,132 @@ enum class PATTERN
namespace FOUNTAIN_FLAG
{
const uint32_t FAST = 1 << 0;
const uint32_t GOTO_EDGE = 1 << 1;
const uint32_t SPLIT = 1 << 2;
const uint32_t TERMINATE = 1 << 3;
const uint32_t BOUNCE = 1 << 4;
const uint32_t DIRECTION = 1 << 7;
const uint32_t FAST = 1 << 0;
const uint32_t GOTO_EDGE = 1 << 1;
const uint32_t SPLIT = 1 << 2;
const uint32_t TERMINATE = 1 << 3;
const uint32_t BOUNCE = 1 << 4;
const uint32_t DIRECTION = 1 << 7;
}; // namespace FOUNTAIN_FLAG
static constexpr const LocationXY16 _fountainDirectionsNegative[] = {
{ -32, 0 }, { -32, -32 }, { 0, 0 }, { -32, 0 }, { 0, 0 }, { 0, -32 }, { 0, -32 }, { -32, -32 },
};
static constexpr const LocationXY16 _fountainDirectionsNegative[] =
{
{ -32, 0 },
{ -32, -32 },
{ 0, 0 },
{ -32, 0 },
{ 0, 0 },
{ 0, -32 },
{ 0, -32 },
{ -32, -32 },
};
static constexpr const LocationXY16 _fountainDirectionsPositive[] =
{
{ 32, 0 },
{ 0, 0 },
{ 0, 32 },
{ 32, 32 },
{ 32, 32 },
{ 32, 0 },
{ 0, 0 },
{ 0, 32 }
};
static constexpr const LocationXY16 _fountainDirectionsPositive[]
= { { 32, 0 }, { 0, 0 }, { 0, 32 }, { 32, 32 }, { 32, 32 }, { 32, 0 }, { 0, 0 }, { 0, 32 } };
// rct2: 0x0097F040
const uint8_t _fountainDirections[] = { 0, 1, 2, 3, 0, 1, 2, 3 };
// rct2: 0x0097F048
const uint8_t _fountainDirectionFlags[] = { 0, 0, FOUNTAIN_FLAG::DIRECTION, FOUNTAIN_FLAG::DIRECTION, FOUNTAIN_FLAG::DIRECTION, FOUNTAIN_FLAG::DIRECTION, 0, 0 };
const uint8_t _fountainDirectionFlags[]
= { 0, 0, FOUNTAIN_FLAG::DIRECTION, FOUNTAIN_FLAG::DIRECTION, FOUNTAIN_FLAG::DIRECTION, FOUNTAIN_FLAG::DIRECTION, 0, 0 };
// rct2: 0x0097F050
const uint8_t _fountainPatternFlags[] = {
FOUNTAIN_FLAG::TERMINATE, // CYCLIC_SQUARES
FOUNTAIN_FLAG::FAST | FOUNTAIN_FLAG::GOTO_EDGE, // CONTINUOUS_CHASERS
FOUNTAIN_FLAG::BOUNCE, // BOUNCING_PAIRS
FOUNTAIN_FLAG::FAST | FOUNTAIN_FLAG::SPLIT, // SPROUTING_BLOOMS
FOUNTAIN_FLAG::GOTO_EDGE, // RACING_PAIRS
FOUNTAIN_FLAG::FAST | FOUNTAIN_FLAG::GOTO_EDGE | FOUNTAIN_FLAG::SPLIT, // SPLITTING_CHASERS
0, // DOPEY_JUMPERS
FOUNTAIN_FLAG::FAST // FAST_RANDOM_CHASERS
FOUNTAIN_FLAG::TERMINATE, // CYCLIC_SQUARES
FOUNTAIN_FLAG::FAST | FOUNTAIN_FLAG::GOTO_EDGE, // CONTINUOUS_CHASERS
FOUNTAIN_FLAG::BOUNCE, // BOUNCING_PAIRS
FOUNTAIN_FLAG::FAST | FOUNTAIN_FLAG::SPLIT, // SPROUTING_BLOOMS
FOUNTAIN_FLAG::GOTO_EDGE, // RACING_PAIRS
FOUNTAIN_FLAG::FAST | FOUNTAIN_FLAG::GOTO_EDGE | FOUNTAIN_FLAG::SPLIT, // SPLITTING_CHASERS
0, // DOPEY_JUMPERS
FOUNTAIN_FLAG::FAST // FAST_RANDOM_CHASERS
};
static int32_t jumping_fountain_get_type(const rct_jumping_fountain * jumpingFountain);
static void jumping_fountain_continue(rct_jumping_fountain * jumpingFountain);
static int32_t jumping_fountain_get_type(const rct_jumping_fountain* jumpingFountain);
static void jumping_fountain_continue(rct_jumping_fountain* jumpingFountain);
static bool is_jumping_fountain(int32_t type, int32_t x, int32_t y, int32_t z);
static void jumping_fountain_goto_edge(const rct_jumping_fountain * jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections);
static void jumping_fountain_bounce(rct_jumping_fountain * jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections);
static void jumping_fountain_split(const rct_jumping_fountain * jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections);
static void jumping_fountain_random(const rct_jumping_fountain * jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections);
static void jumping_fountain_create_next(const rct_jumping_fountain * jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t direction);
static void jumping_fountain_goto_edge(
const rct_jumping_fountain* jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections);
static void jumping_fountain_bounce(
rct_jumping_fountain* jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections);
static void jumping_fountain_split(
const rct_jumping_fountain* jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections);
static void jumping_fountain_random(
const rct_jumping_fountain* jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections);
static void jumping_fountain_create_next(
const rct_jumping_fountain* jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t direction);
void jumping_fountain_begin(int32_t type, int32_t x, int32_t y, const rct_tile_element * tileElement)
void jumping_fountain_begin(int32_t type, int32_t x, int32_t y, const rct_tile_element* tileElement)
{
int32_t randomIndex;
int32_t z = tileElement->base_height * 8;
// Change pattern approximately every 51 seconds
uint32_t pattern = (gCurrentTicks >> 11) & 7;
switch ((PATTERN)pattern) {
case PATTERN::CYCLIC_SQUARES:
// 0, 1, 2, 3
for (int32_t i = 0; i < 4; i++)
{
switch ((PATTERN)pattern)
{
case PATTERN::CYCLIC_SQUARES:
// 0, 1, 2, 3
for (int32_t i = 0; i < 4; i++)
{
jumping_fountain_create(
type,
x + _fountainDirectionsPositive[i].x,
y + _fountainDirectionsPositive[i].y,
z,
_fountainDirections[i],
_fountainDirectionFlags[i] | _fountainPatternFlags[pattern],
0);
}
break;
case PATTERN::BOUNCING_PAIRS:
// random [0, 2 or 1, 3]
randomIndex = scenario_rand() & 1;
for (int32_t i = randomIndex; i < 4; i += 2)
{
jumping_fountain_create(
type,
x + _fountainDirectionsPositive[i].x,
y + _fountainDirectionsPositive[i].y,
z,
_fountainDirections[i],
_fountainDirectionFlags[i] | _fountainPatternFlags[pattern],
0);
}
break;
case PATTERN::RACING_PAIRS:
// random [0 - 3 and 4 - 7]
randomIndex = scenario_rand() & 3;
jumping_fountain_create(
type,
x + _fountainDirectionsPositive[i].x,
y + _fountainDirectionsPositive[i].y,
x + _fountainDirectionsPositive[randomIndex].x,
y + _fountainDirectionsPositive[randomIndex].y,
z,
_fountainDirections[i],
_fountainDirectionFlags[i] | _fountainPatternFlags[pattern],
0
);
}
break;
case PATTERN::BOUNCING_PAIRS:
// random [0, 2 or 1, 3]
randomIndex = scenario_rand() & 1;
for (int32_t i = randomIndex; i < 4; i += 2)
{
_fountainDirections[randomIndex],
_fountainDirectionFlags[randomIndex] | _fountainPatternFlags[pattern],
0);
randomIndex += 4;
jumping_fountain_create(
type,
x + _fountainDirectionsPositive[i].x,
y + _fountainDirectionsPositive[i].y,
x + _fountainDirectionsPositive[randomIndex].x,
y + _fountainDirectionsPositive[randomIndex].y,
z,
_fountainDirections[i],
_fountainDirectionFlags[i] | _fountainPatternFlags[pattern],
0
);
}
break;
case PATTERN::RACING_PAIRS:
// random [0 - 3 and 4 - 7]
randomIndex = scenario_rand() & 3;
jumping_fountain_create(
type,
x + _fountainDirectionsPositive[randomIndex].x,
y + _fountainDirectionsPositive[randomIndex].y,
z,
_fountainDirections[randomIndex],
_fountainDirectionFlags[randomIndex] | _fountainPatternFlags[pattern],
0
);
randomIndex += 4;
jumping_fountain_create(
type,
x + _fountainDirectionsPositive[randomIndex].x,
y + _fountainDirectionsPositive[randomIndex].y,
z,
_fountainDirections[randomIndex],
_fountainDirectionFlags[randomIndex] | _fountainPatternFlags[pattern],
0
);
break;
default:
// random [0 - 7]
randomIndex = scenario_rand() & 7;
jumping_fountain_create(
type,
x + _fountainDirectionsPositive[randomIndex].x,
y + _fountainDirectionsPositive[randomIndex].y,
z,
_fountainDirections[randomIndex],
_fountainDirectionFlags[randomIndex] | _fountainPatternFlags[pattern],
0
);
break;
_fountainDirections[randomIndex],
_fountainDirectionFlags[randomIndex] | _fountainPatternFlags[pattern],
0);
break;
default:
// random [0 - 7]
randomIndex = scenario_rand() & 7;
jumping_fountain_create(
type,
x + _fountainDirectionsPositive[randomIndex].x,
y + _fountainDirectionsPositive[randomIndex].y,
z,
_fountainDirections[randomIndex],
_fountainDirectionFlags[randomIndex] | _fountainPatternFlags[pattern],
0);
break;
}
}
void jumping_fountain_create(int32_t type, int32_t x, int32_t y, int32_t z, int32_t direction, int32_t flags, int32_t iteration)
{
rct_jumping_fountain * jumpingFountain = (rct_jumping_fountain *)create_sprite(SPRITE_IDENTIFIER_MISC);
rct_jumping_fountain* jumpingFountain = (rct_jumping_fountain*)create_sprite(SPRITE_IDENTIFIER_MISC);
if (jumpingFountain != nullptr)
{
jumpingFountain->iteration = iteration;
@ -180,16 +165,15 @@ void jumping_fountain_create(int32_t type, int32_t x, int32_t y, int32_t z, int3
jumpingFountain->sprite_height_negative = 36;
jumpingFountain->sprite_height_positive = 12;
jumpingFountain->sprite_identifier = SPRITE_IDENTIFIER_MISC;
sprite_move(x, y, z, (rct_sprite *)jumpingFountain);
jumpingFountain->misc_identifier = type == JUMPING_FOUNTAIN_TYPE_SNOW ?
SPRITE_MISC_JUMPING_FOUNTAIN_SNOW :
SPRITE_MISC_JUMPING_FOUNTAIN_WATER;
sprite_move(x, y, z, (rct_sprite*)jumpingFountain);
jumpingFountain->misc_identifier
= type == JUMPING_FOUNTAIN_TYPE_SNOW ? SPRITE_MISC_JUMPING_FOUNTAIN_SNOW : SPRITE_MISC_JUMPING_FOUNTAIN_WATER;
jumpingFountain->num_ticks_alive = 0;
jumpingFountain->frame = 0;
}
}
void jumping_fountain_update(rct_jumping_fountain * jumpingFountain)
void jumping_fountain_update(rct_jumping_fountain* jumpingFountain)
{
jumpingFountain->num_ticks_alive++;
// Originaly this would not update the frame on the following
@ -201,26 +185,27 @@ void jumping_fountain_update(rct_jumping_fountain * jumpingFountain)
return;
}
invalidate_sprite_0((rct_sprite *)jumpingFountain);
invalidate_sprite_0((rct_sprite*)jumpingFountain);
jumpingFountain->frame++;
switch (jumpingFountain->misc_identifier) {
case SPRITE_MISC_JUMPING_FOUNTAIN_WATER:
if (jumpingFountain->frame == 11 && (jumpingFountain->fountain_flags & FOUNTAIN_FLAG::FAST))
{
jumping_fountain_continue(jumpingFountain);
}
if (jumpingFountain->frame == 16 && !(jumpingFountain->fountain_flags & FOUNTAIN_FLAG::FAST))
{
jumping_fountain_continue(jumpingFountain);
}
break;
case SPRITE_MISC_JUMPING_FOUNTAIN_SNOW:
if (jumpingFountain->frame == 16)
{
jumping_fountain_continue(jumpingFountain);
}
break;
switch (jumpingFountain->misc_identifier)
{
case SPRITE_MISC_JUMPING_FOUNTAIN_WATER:
if (jumpingFountain->frame == 11 && (jumpingFountain->fountain_flags & FOUNTAIN_FLAG::FAST))
{
jumping_fountain_continue(jumpingFountain);
}
if (jumpingFountain->frame == 16 && !(jumpingFountain->fountain_flags & FOUNTAIN_FLAG::FAST))
{
jumping_fountain_continue(jumpingFountain);
}
break;
case SPRITE_MISC_JUMPING_FOUNTAIN_SNOW:
if (jumpingFountain->frame == 16)
{
jumping_fountain_continue(jumpingFountain);
}
break;
}
if (jumpingFountain->frame == 16)
@ -229,16 +214,14 @@ void jumping_fountain_update(rct_jumping_fountain * jumpingFountain)
}
}
static int32_t jumping_fountain_get_type(const rct_jumping_fountain * jumpingFountain)
static int32_t jumping_fountain_get_type(const rct_jumping_fountain* jumpingFountain)
{
int32_t type = jumpingFountain->misc_identifier == SPRITE_MISC_JUMPING_FOUNTAIN_SNOW ?
JUMPING_FOUNTAIN_TYPE_SNOW :
JUMPING_FOUNTAIN_TYPE_WATER;
int32_t type = jumpingFountain->misc_identifier == SPRITE_MISC_JUMPING_FOUNTAIN_SNOW ? JUMPING_FOUNTAIN_TYPE_SNOW
: JUMPING_FOUNTAIN_TYPE_WATER;
return type;
}
static void jumping_fountain_continue(rct_jumping_fountain * jumpingFountain)
static void jumping_fountain_continue(rct_jumping_fountain* jumpingFountain)
{
int32_t type = jumping_fountain_get_type(jumpingFountain);
int32_t direction = (jumpingFountain->sprite_direction >> 3) & 7;
@ -290,31 +273,34 @@ static bool is_jumping_fountain(int32_t type, int32_t x, int32_t y, int32_t z)
{
z = z >> 3;
int32_t pathBitFlagMask = type == JUMPING_FOUNTAIN_TYPE_SNOW ?
PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW :
PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER;
int32_t pathBitFlagMask
= type == JUMPING_FOUNTAIN_TYPE_SNOW ? PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW : PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER;
rct_tile_element * tileElement = map_get_first_element_at(x >> 5, y >> 5);
rct_tile_element* tileElement = map_get_first_element_at(x >> 5, y >> 5);
do
{
if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH) continue;
if (tileElement->base_height != z) continue;
if (footpath_element_path_scenery_is_ghost(tileElement)) continue;
if (!footpath_element_has_path_scenery(tileElement)) continue;
if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH)
continue;
if (tileElement->base_height != z)
continue;
if (footpath_element_path_scenery_is_ghost(tileElement))
continue;
if (!footpath_element_has_path_scenery(tileElement))
continue;
uint8_t additionIndex = footpath_element_get_path_scenery_index(tileElement);
rct_scenery_entry * sceneryEntry = get_footpath_item_entry(additionIndex);
rct_scenery_entry* sceneryEntry = get_footpath_item_entry(additionIndex);
if (sceneryEntry != reinterpret_cast<void*>(-1) && sceneryEntry->path_bit.flags & pathBitFlagMask)
{
return true;
}
}
while (!(tileElement++)->IsLastForTile());
} while (!(tileElement++)->IsLastForTile());
return false;
}
static void jumping_fountain_goto_edge(const rct_jumping_fountain * jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections)
static void jumping_fountain_goto_edge(
const rct_jumping_fountain* jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections)
{
int32_t direction = (jumpingFountain->sprite_direction >> 3) << 1;
if (availableDirections & (1 << direction))
@ -351,7 +337,8 @@ static void jumping_fountain_goto_edge(const rct_jumping_fountain * jumpingFount
jumping_fountain_create_next(jumpingFountain, x, y, z, direction);
}
static void jumping_fountain_bounce(rct_jumping_fountain * jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections)
static void
jumping_fountain_bounce(rct_jumping_fountain* jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections)
{
jumpingFountain->iteration++;
if (jumpingFountain->iteration < 8)
@ -372,7 +359,8 @@ static void jumping_fountain_bounce(rct_jumping_fountain * jumpingFountain, int3
}
}
static void jumping_fountain_split(const rct_jumping_fountain * jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections)
static void jumping_fountain_split(
const rct_jumping_fountain* jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections)
{
if (jumpingFountain->iteration < 3)
{
@ -387,28 +375,31 @@ static void jumping_fountain_split(const rct_jumping_fountain * jumpingFountain,
{
jumping_fountain_create(
type,
x, y, z,
x,
y,
z,
direction >> 1,
jumpingFountain->fountain_flags & ~FOUNTAIN_FLAG::DIRECTION,
jumpingFountain->iteration + 1
);
jumpingFountain->iteration + 1);
}
direction++;
if (availableDirections & (1 << direction))
{
jumping_fountain_create(
type,
x, y, z,
x,
y,
z,
direction >> 1,
jumpingFountain->fountain_flags | FOUNTAIN_FLAG::DIRECTION,
jumpingFountain->iteration + 1
);
jumpingFountain->iteration + 1);
}
}
}
}
static void jumping_fountain_random(const rct_jumping_fountain * jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections)
static void jumping_fountain_random(
const rct_jumping_fountain* jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t availableDirections)
{
uint32_t randomIndex = scenario_rand();
if ((randomIndex & 0xFFFF) >= 0x2000)
@ -422,7 +413,8 @@ static void jumping_fountain_random(const rct_jumping_fountain * jumpingFountain
}
}
static void jumping_fountain_create_next(const rct_jumping_fountain * jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t direction)
static void jumping_fountain_create_next(
const rct_jumping_fountain* jumpingFountain, int32_t x, int32_t y, int32_t z, int32_t direction)
{
int32_t type = jumping_fountain_get_type(jumpingFountain);
int32_t flags = jumpingFountain->fountain_flags & ~FOUNTAIN_FLAG::DIRECTION;

View File

@ -10,7 +10,6 @@
#pragma once
#include "../common.h"
#include "Map.h"
#include "Sprite.h"
@ -20,7 +19,7 @@ enum
JUMPING_FOUNTAIN_TYPE_SNOW
};
void jumping_fountain_begin(int32_t type, int32_t x, int32_t y, const rct_tile_element * tileElement);
void jumping_fountain_create(int32_t type, int32_t x, int32_t y, int32_t z, int32_t direction, int32_t flags, int32_t iteration);
void jumping_fountain_update(rct_jumping_fountain * jumpingFountain);
void jumping_fountain_begin(int32_t type, int32_t x, int32_t y, const rct_tile_element* tileElement);
void jumping_fountain_create(
int32_t type, int32_t x, int32_t y, int32_t z, int32_t direction, int32_t flags, int32_t iteration);
void jumping_fountain_update(rct_jumping_fountain* jumpingFountain);

View File

@ -7,28 +7,29 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "../common.h"
#include "LargeScenery.h"
#include "../common.h"
#include "TileElement.h"
colour_t scenery_large_get_primary_colour(const rct_tile_element * tileElement)
colour_t scenery_large_get_primary_colour(const rct_tile_element* tileElement)
{
return tileElement->properties.scenerymultiple.colour[0] & TILE_ELEMENT_COLOUR_MASK;
}
colour_t scenery_large_get_secondary_colour(const rct_tile_element * tileElement)
colour_t scenery_large_get_secondary_colour(const rct_tile_element* tileElement)
{
return tileElement->properties.scenerymultiple.colour[1] & TILE_ELEMENT_COLOUR_MASK;
}
void scenery_large_set_primary_colour(rct_tile_element * tileElement, colour_t colour)
void scenery_large_set_primary_colour(rct_tile_element* tileElement, colour_t colour)
{
assert(colour <= 31);
tileElement->properties.scenerymultiple.colour[0] &= ~TILE_ELEMENT_COLOUR_MASK;
tileElement->properties.scenerymultiple.colour[0] |= colour;
}
void scenery_large_set_secondary_colour(rct_tile_element * tileElement, colour_t colour)
void scenery_large_set_secondary_colour(rct_tile_element* tileElement, colour_t colour)
{
assert(colour <= 31);
tileElement->properties.scenerymultiple.colour[1] &= ~TILE_ELEMENT_COLOUR_MASK;
@ -37,35 +38,34 @@ void scenery_large_set_secondary_colour(rct_tile_element * tileElement, colour_t
BannerIndex scenery_large_get_banner_id(const rct_tile_element* tileElement)
{
return (tileElement->type & 0xC0) |
(((tileElement->properties.scenerymultiple.colour[0]) &~ TILE_ELEMENT_COLOUR_MASK) >> 2) |
(((tileElement->properties.scenerymultiple.colour[1]) &~ TILE_ELEMENT_COLOUR_MASK) >> 5);
return (tileElement->type & 0xC0) | (((tileElement->properties.scenerymultiple.colour[0]) & ~TILE_ELEMENT_COLOUR_MASK) >> 2)
| (((tileElement->properties.scenerymultiple.colour[1]) & ~TILE_ELEMENT_COLOUR_MASK) >> 5);
}
void scenery_large_set_banner_id(rct_tile_element * tileElement, BannerIndex bannerIndex)
void scenery_large_set_banner_id(rct_tile_element* tileElement, BannerIndex bannerIndex)
{
tileElement->type |= bannerIndex & 0xC0;
tileElement->properties.scenerymultiple.colour[0] |= (bannerIndex & 0x38) << 2;
tileElement->properties.scenerymultiple.colour[1] |= (bannerIndex & 7) << 5;
}
int32_t scenery_large_get_type(const rct_tile_element * tileElement)
int32_t scenery_large_get_type(const rct_tile_element* tileElement)
{
return (tileElement->properties.scenerymultiple.type & TILE_ELEMENT_LARGE_TYPE_MASK);
}
int32_t scenery_large_get_sequence(const rct_tile_element * tileElement)
int32_t scenery_large_get_sequence(const rct_tile_element* tileElement)
{
return (tileElement->properties.scenerymultiple.type >> 10);
}
void scenery_large_set_type(rct_tile_element * tileElement, uint16_t type)
void scenery_large_set_type(rct_tile_element* tileElement, uint16_t type)
{
tileElement->properties.scenerymultiple.type &= ~TILE_ELEMENT_LARGE_TYPE_MASK;
tileElement->properties.scenerymultiple.type |= (type & TILE_ELEMENT_LARGE_TYPE_MASK);
}
void scenery_large_set_sequence(rct_tile_element * tileElement, uint16_t sequence)
void scenery_large_set_sequence(rct_tile_element* tileElement, uint16_t sequence)
{
tileElement->properties.scenerymultiple.type &= TILE_ELEMENT_LARGE_TYPE_MASK;
tileElement->properties.scenerymultiple.type |= (sequence << 10);

View File

@ -13,13 +13,13 @@
#include "Map.h"
#include "TileElement.h"
colour_t scenery_large_get_primary_colour(const rct_tile_element * tileElement);
colour_t scenery_large_get_secondary_colour(const rct_tile_element * tileElement);
void scenery_large_set_primary_colour(rct_tile_element * tileElement, colour_t colour);
void scenery_large_set_secondary_colour(rct_tile_element * tileElement, colour_t colour);
colour_t scenery_large_get_primary_colour(const rct_tile_element* tileElement);
colour_t scenery_large_get_secondary_colour(const rct_tile_element* tileElement);
void scenery_large_set_primary_colour(rct_tile_element* tileElement, colour_t colour);
void scenery_large_set_secondary_colour(rct_tile_element* tileElement, colour_t colour);
BannerIndex scenery_large_get_banner_id(const rct_tile_element* tileElement);
void scenery_large_set_banner_id(rct_tile_element * tileElement, BannerIndex bannerIndex);
int32_t scenery_large_get_type(const rct_tile_element * tileElement);
int32_t scenery_large_get_sequence(const rct_tile_element * tileElement);
void scenery_large_set_type(rct_tile_element * tileElement, uint16_t type);
void scenery_large_set_sequence(rct_tile_element * tileElement, uint16_t sequence);
void scenery_large_set_banner_id(rct_tile_element* tileElement, BannerIndex bannerIndex);
int32_t scenery_large_get_type(const rct_tile_element* tileElement);
int32_t scenery_large_get_sequence(const rct_tile_element* tileElement);
void scenery_large_set_type(rct_tile_element* tileElement, uint16_t type);
void scenery_large_set_sequence(rct_tile_element* tileElement, uint16_t sequence);

View File

@ -11,14 +11,20 @@
#include "../common.h"
#define LOCATION_NULL ((int16_t)(uint16_t)0x8000)
#define LOCATION_NULL ((int16_t)(uint16_t)0x8000)
#define RCT_XY8_UNDEFINED 0xFFFF
#define MakeXY16(x, y) {(int16_t)(x), (int16_t)(y)}
#define MakeXY16(x, y) \
{ \
(int16_t)(x), (int16_t)(y) \
}
#pragma pack(push, 1)
struct LocationXY8 {
union {
struct {
struct LocationXY8
{
union
{
struct
{
uint8_t x, y;
};
uint16_t xy;
@ -26,18 +32,20 @@ struct LocationXY8 {
};
assert_struct_size(LocationXY8, 2);
struct sLocationXY8 {
struct sLocationXY8
{
int8_t x, y;
};
assert_struct_size(sLocationXY8, 2);
struct LocationXY16 {
struct LocationXY16
{
int16_t x, y;
};
assert_struct_size(LocationXY16, 4);
struct LocationXYZ16 {
struct LocationXYZ16
{
int16_t x, y, z;
};
assert_struct_size(LocationXYZ16, 6);
@ -57,8 +65,16 @@ struct CoordsXY
struct TileCoordsXY
{
TileCoordsXY() = default;
TileCoordsXY(int32_t x_, int32_t y_) : x(x_), y(y_) {}
explicit TileCoordsXY(CoordsXY c) : x(c.x / 32), y(c.y / 32) {}
TileCoordsXY(int32_t x_, int32_t y_)
: x(x_)
, y(y_)
{
}
explicit TileCoordsXY(CoordsXY c)
: x(c.x / 32)
, y(c.y / 32)
{
}
TileCoordsXY& operator+=(const TileCoordsXY rhs)
{
x += rhs.x;
@ -76,9 +92,24 @@ struct CoordsXYZ
struct TileCoordsXYZ
{
TileCoordsXYZ() = default;
TileCoordsXYZ(int32_t x_, int32_t y_, int32_t z_) : x(x_), y(y_), z(z_) {}
explicit TileCoordsXYZ(CoordsXY c, int32_t z_) : x(c.x / 32), y(c.y / 32), z(z_) {}
explicit TileCoordsXYZ(CoordsXYZ c) : x(c.x / 32), y(c.y / 32), z(c.z / 8) {}
TileCoordsXYZ(int32_t x_, int32_t y_, int32_t z_)
: x(x_)
, y(y_)
, z(z_)
{
}
explicit TileCoordsXYZ(CoordsXY c, int32_t z_)
: x(c.x / 32)
, y(c.y / 32)
, z(z_)
{
}
explicit TileCoordsXYZ(CoordsXYZ c)
: x(c.x / 32)
, y(c.y / 32)
, z(c.z / 8)
{
}
TileCoordsXYZ& operator+=(const TileCoordsXY rhs)
{
x += rhs.x;
@ -93,7 +124,10 @@ struct CoordsXYZD
int32_t x, y, z;
uint8_t direction;
bool isNull() const { return x == COORDS_NULL; };
bool isNull() const
{
return x == COORDS_NULL;
};
};
struct TileCoordsXYZD
@ -101,5 +135,8 @@ struct TileCoordsXYZD
int32_t x, y, z;
uint8_t direction;
bool isNull() const { return x == COORDS_NULL; };
bool isNull() const
{
return x == COORDS_NULL;
};
};

File diff suppressed because it is too large Load Diff

View File

@ -10,18 +10,19 @@
#ifndef _MAP_H_
#define _MAP_H_
#include <initializer_list>
#include "../common.h"
#include "Location.hpp"
#include "TileElement.h"
#include <initializer_list>
#define MINIMUM_LAND_HEIGHT 2
#define MAXIMUM_LAND_HEIGHT 142
#define MINIMUM_MAP_SIZE_TECHNICAL 15
#define MAXIMUM_MAP_SIZE_TECHNICAL 256
#define MINIMUM_MAP_SIZE_PRACTICAL (MINIMUM_MAP_SIZE_TECHNICAL-2)
#define MAXIMUM_MAP_SIZE_PRACTICAL (MAXIMUM_MAP_SIZE_TECHNICAL-2)
#define MINIMUM_MAP_SIZE_PRACTICAL (MINIMUM_MAP_SIZE_TECHNICAL - 2)
#define MAXIMUM_MAP_SIZE_PRACTICAL (MAXIMUM_MAP_SIZE_TECHNICAL - 2)
#define MAP_MINIMUM_X_Y (-MAXIMUM_MAP_SIZE_TECHNICAL)
@ -39,17 +40,19 @@ typedef CoordsXYZD PeepSpawn;
struct CoordsXYE
{
int32_t x, y;
rct_tile_element * element;
rct_tile_element* element;
};
enum {
MAP_SELECT_FLAG_ENABLE = 1 << 0,
MAP_SELECT_FLAG_ENABLE_CONSTRUCT = 1 << 1,
MAP_SELECT_FLAG_ENABLE_ARROW = 1 << 2,
MAP_SELECT_FLAG_GREEN = 1 << 3,
enum
{
MAP_SELECT_FLAG_ENABLE = 1 << 0,
MAP_SELECT_FLAG_ENABLE_CONSTRUCT = 1 << 1,
MAP_SELECT_FLAG_ENABLE_ARROW = 1 << 2,
MAP_SELECT_FLAG_GREEN = 1 << 3,
};
enum {
enum
{
MAP_SELECT_TYPE_CORNER_0,
MAP_SELECT_TYPE_CORNER_1,
MAP_SELECT_TYPE_CORNER_2,
@ -90,22 +93,22 @@ extern int16_t gMapSize;
extern int16_t gMapSizeMaxXY;
extern int16_t gMapBaseZ;
extern uint16_t gMapSelectFlags;
extern uint16_t gMapSelectType;
extern LocationXY16 gMapSelectPositionA;
extern LocationXY16 gMapSelectPositionB;
extern LocationXYZ16 gMapSelectArrowPosition;
extern uint8_t gMapSelectArrowDirection;
extern uint16_t gMapSelectFlags;
extern uint16_t gMapSelectType;
extern LocationXY16 gMapSelectPositionA;
extern LocationXY16 gMapSelectPositionB;
extern LocationXYZ16 gMapSelectArrowPosition;
extern uint8_t gMapSelectArrowDirection;
extern uint8_t gMapGroundFlags;
extern rct_tile_element gTileElements[MAX_TILE_TILE_ELEMENT_POINTERS * 3];
extern rct_tile_element *gTileElementTilePointers[MAX_TILE_TILE_ELEMENT_POINTERS];
extern rct_tile_element* gTileElementTilePointers[MAX_TILE_TILE_ELEMENT_POINTERS];
extern LocationXY16 gMapSelectionTiles[300];
extern PeepSpawn gPeepSpawns[MAX_PEEP_SPAWNS];
extern rct_tile_element *gNextFreeTileElement;
extern rct_tile_element* gNextFreeTileElement;
extern uint32_t gNextFreeTileElementPointerIndex;
// Used in the land tool window to enable mountain tool / land smoothing
@ -128,19 +131,19 @@ void map_init(int32_t size);
void map_count_remaining_land_rights();
void map_strip_ghost_flag_from_elements();
void map_update_tile_pointers();
rct_tile_element *map_get_first_element_at(int32_t x, int32_t y);
rct_tile_element *map_get_nth_element_at(int32_t x, int32_t y, int32_t n);
void map_set_tile_elements(int32_t x, int32_t y, rct_tile_element *elements);
rct_tile_element* map_get_first_element_at(int32_t x, int32_t y);
rct_tile_element* map_get_nth_element_at(int32_t x, int32_t y, int32_t n);
void map_set_tile_elements(int32_t x, int32_t y, rct_tile_element* elements);
int32_t map_height_from_slope(int32_t x, int32_t y, int32_t slope);
rct_tile_element* map_get_banner_element_at(int32_t x, int32_t y, int32_t z, uint8_t direction);
rct_tile_element *map_get_surface_element_at(int32_t x, int32_t y);
rct_tile_element * map_get_surface_element_at(CoordsXY coords);
rct_tile_element* map_get_surface_element_at(int32_t x, int32_t y);
rct_tile_element* map_get_surface_element_at(CoordsXY coords);
rct_tile_element* map_get_path_element_at(int32_t x, int32_t y, int32_t z);
rct_tile_element *map_get_wall_element_at(int32_t x, int32_t y, int32_t z, int32_t direction);
rct_tile_element *map_get_small_scenery_element_at(int32_t x, int32_t y, int32_t z, int32_t type, uint8_t quadrant);
rct_tile_element *map_get_park_entrance_element_at(int32_t x, int32_t y, int32_t z, bool ghost);
rct_tile_element * map_get_ride_entrance_element_at(int32_t x, int32_t y, int32_t z, bool ghost);
rct_tile_element * map_get_ride_exit_element_at(int32_t x, int32_t y, int32_t z, bool ghost);
rct_tile_element* map_get_wall_element_at(int32_t x, int32_t y, int32_t z, int32_t direction);
rct_tile_element* map_get_small_scenery_element_at(int32_t x, int32_t y, int32_t z, int32_t type, uint8_t quadrant);
rct_tile_element* map_get_park_entrance_element_at(int32_t x, int32_t y, int32_t z, bool ghost);
rct_tile_element* map_get_ride_entrance_element_at(int32_t x, int32_t y, int32_t z, bool ghost);
rct_tile_element* map_get_ride_exit_element_at(int32_t x, int32_t y, int32_t z, bool ghost);
int32_t tile_element_height(int32_t x, int32_t y);
bool map_coord_is_connected(int32_t x, int32_t y, int32_t z, uint8_t faceDirection);
void map_remove_provisional_elements();
@ -153,78 +156,118 @@ bool map_is_location_owned(int32_t x, int32_t y, int32_t z);
bool map_is_location_in_park(CoordsXY coords);
bool map_is_location_owned_or_has_rights(int32_t x, int32_t y);
bool map_surface_is_blocked(int16_t x, int16_t y);
void tile_element_remove(rct_tile_element *tileElement);
void tile_element_remove(rct_tile_element* tileElement);
void map_remove_all_rides();
void map_invalidate_map_selection_tiles();
void map_get_bounding_box(int32_t ax, int32_t ay, int32_t bx, int32_t by, int32_t *left, int32_t *top, int32_t *right, int32_t *bottom);
void map_get_bounding_box(
int32_t ax, int32_t ay, int32_t bx, int32_t by, int32_t* left, int32_t* top, int32_t* right, int32_t* bottom);
void map_invalidate_selection_rect();
void map_reorganise_elements();
bool map_check_free_elements_and_reorganise(int32_t num_elements);
rct_tile_element *tile_element_insert(int32_t x, int32_t y, int32_t z, int32_t flags);
rct_tile_element* tile_element_insert(int32_t x, int32_t y, int32_t z, int32_t flags);
using CLEAR_FUNC = int32_t(*)(rct_tile_element** tile_element, int32_t x, int32_t y, uint8_t flags, money32* price);
using CLEAR_FUNC = int32_t (*)(rct_tile_element** tile_element, int32_t x, int32_t y, uint8_t flags, money32* price);
int32_t map_place_non_scenery_clear_func(rct_tile_element** tile_element, int32_t x, int32_t y, uint8_t flags, money32* price);
int32_t map_place_scenery_clear_func(rct_tile_element** tile_element, int32_t x, int32_t y, uint8_t flags, money32* price);
bool map_can_construct_with_clear_at(int32_t x, int32_t y, int32_t zLow, int32_t zHigh, CLEAR_FUNC clearFunc, uint8_t bl, uint8_t flags, money32 *price, uint8_t crossingMode);
bool map_can_construct_with_clear_at(
int32_t x,
int32_t y,
int32_t zLow,
int32_t zHigh,
CLEAR_FUNC clearFunc,
uint8_t bl,
uint8_t flags,
money32* price,
uint8_t crossingMode);
int32_t map_can_construct_at(int32_t x, int32_t y, int32_t zLow, int32_t zHigh, uint8_t bl);
void rotate_map_coordinates(int16_t *x, int16_t *y, int32_t rotation);
void rotate_map_coordinates(int16_t* x, int16_t* y, int32_t rotation);
LocationXY16 coordinate_3d_to_2d(const LocationXYZ16* coordinate_3d, int32_t rotation);
money32 map_clear_scenery(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t clear, int32_t flags);
money32 lower_water(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t flags);
money32 raise_water(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t flags);
money32 wall_place(int32_t type, int32_t x, int32_t y, int32_t z, int32_t edge, int32_t primaryColour, int32_t secondaryColour, int32_t tertiaryColour, int32_t flags);
money32 wall_place(
int32_t type,
int32_t x,
int32_t y,
int32_t z,
int32_t edge,
int32_t primaryColour,
int32_t secondaryColour,
int32_t tertiaryColour,
int32_t flags);
void game_command_set_land_height(int32_t *eax, int32_t *ebx, int32_t *ecx, int32_t *edx, int32_t *esi, int32_t *edi, int32_t *ebp);
void game_command_set_land_ownership(int32_t *eax, int32_t *ebx, int32_t *ecx, int32_t *edx, int32_t *esi, int32_t *edi, int32_t *ebp);
void game_command_remove_scenery(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_remove_large_scenery(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_remove_banner(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_scenery_colour(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_wall_colour(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_large_scenery_colour(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_banner_colour(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_clear_scenery(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_change_surface_style(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_land_height(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_land_ownership(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_remove_scenery(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_remove_large_scenery(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_remove_banner(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_scenery_colour(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_wall_colour(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_large_scenery_colour(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_banner_colour(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_clear_scenery(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_change_surface_style(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_raise_land(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_lower_land(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_smooth_land(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_raise_water(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_lower_water(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_water_height(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_place_banner(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_place_scenery(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_water_height(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_place_banner(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_place_scenery(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_place_wall(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_place_large_scenery(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_place_park_entrance(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_banner_name(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_banner_style(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_sign_style(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_place_large_scenery(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_place_park_entrance(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_banner_name(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_banner_style(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_sign_style(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_modify_tile(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
struct tile_element_iterator{
struct tile_element_iterator
{
int32_t x;
int32_t y;
rct_tile_element *element;
rct_tile_element* element;
};
#ifdef PLATFORM_32BIT
assert_struct_size(tile_element_iterator, 12);
#endif
void tile_element_iterator_begin(tile_element_iterator *it);
int32_t tile_element_iterator_next(tile_element_iterator *it);
void tile_element_iterator_restart_for_tile(tile_element_iterator *it);
void tile_element_iterator_begin(tile_element_iterator* it);
int32_t tile_element_iterator_next(tile_element_iterator* it);
void tile_element_iterator_restart_for_tile(tile_element_iterator* it);
void wall_remove_intersecting_walls(int32_t x, int32_t y, int32_t z0, int32_t z1, int32_t direction);
void map_update_tiles();
int32_t map_get_highest_z(int32_t tileX, int32_t tileY);
bool tile_element_wants_path_connection_towards(TileCoordsXYZD coords, const rct_tile_element * const elementToBeRemoved);
bool tile_element_wants_path_connection_towards(TileCoordsXYZD coords, const rct_tile_element* const elementToBeRemoved);
void map_remove_out_of_range_elements();
void map_extend_boundary_surface();
bool sign_set_colour(int32_t x, int32_t y, int32_t z, int32_t direction, int32_t sequence, uint8_t mainColour, uint8_t textColour);
bool sign_set_colour(
int32_t x, int32_t y, int32_t z, int32_t direction, int32_t sequence, uint8_t mainColour, uint8_t textColour);
void wall_remove_at(int32_t x, int32_t y, int32_t z0, int32_t z1);
void wall_remove_at_z(int32_t x, int32_t y, int32_t z);
@ -232,7 +275,7 @@ void map_invalidate_tile(int32_t x, int32_t y, int32_t z0, int32_t z1);
void map_invalidate_tile_zoom1(int32_t x, int32_t y, int32_t z0, int32_t z1);
void map_invalidate_tile_zoom0(int32_t x, int32_t y, int32_t z0, int32_t z1);
void map_invalidate_tile_full(int32_t x, int32_t y);
void map_invalidate_element(int32_t x, int32_t y, rct_tile_element *tileElement);
void map_invalidate_element(int32_t x, int32_t y, rct_tile_element* tileElement);
void map_invalidate_region(const LocationXY16& mins, const LocationXY16& maxs);
int32_t map_get_tile_side(int32_t mapX, int32_t mapY);
@ -240,24 +283,32 @@ int32_t map_get_tile_quadrant(int32_t mapX, int32_t mapY);
void map_clear_all_elements();
rct_tile_element *map_get_large_scenery_segment(int32_t x, int32_t y, int32_t z, int32_t direction, int32_t sequence);
rct_tile_element* map_get_large_scenery_segment(int32_t x, int32_t y, int32_t z, int32_t direction, int32_t sequence);
bool map_large_scenery_get_origin(
int32_t x, int32_t y, int32_t z, int32_t direction, int32_t sequence,
int32_t *outX, int32_t *outY, int32_t *outZ, rct_tile_element** outElement
);
int32_t x,
int32_t y,
int32_t z,
int32_t direction,
int32_t sequence,
int32_t* outX,
int32_t* outY,
int32_t* outZ,
rct_tile_element** outElement);
void map_offset_with_rotation(int16_t *x, int16_t *y, int16_t offsetX, int16_t offsetY, uint8_t rotation);
void map_offset_with_rotation(int16_t* x, int16_t* y, int16_t offsetX, int16_t offsetY, uint8_t rotation);
CoordsXY translate_3d_to_2d_with_z(int32_t rotation, CoordsXYZ pos);
rct_tile_element *map_get_track_element_at(int32_t x, int32_t y, int32_t z);
rct_tile_element *map_get_track_element_at_of_type(int32_t x, int32_t y, int32_t z, int32_t trackType);
rct_tile_element *map_get_track_element_at_of_type_seq(int32_t x, int32_t y, int32_t z, int32_t trackType, int32_t sequence);
rct_tile_element *map_get_track_element_at_of_type_from_ride(int32_t x, int32_t y, int32_t z, int32_t trackType, int32_t rideIndex);
rct_tile_element *map_get_track_element_at_from_ride(int32_t x, int32_t y, int32_t z, int32_t rideIndex);
rct_tile_element *map_get_track_element_at_with_direction_from_ride(int32_t x, int32_t y, int32_t z, int32_t direction, int32_t rideIndex);
rct_tile_element* map_get_track_element_at(int32_t x, int32_t y, int32_t z);
rct_tile_element* map_get_track_element_at_of_type(int32_t x, int32_t y, int32_t z, int32_t trackType);
rct_tile_element* map_get_track_element_at_of_type_seq(int32_t x, int32_t y, int32_t z, int32_t trackType, int32_t sequence);
rct_tile_element*
map_get_track_element_at_of_type_from_ride(int32_t x, int32_t y, int32_t z, int32_t trackType, int32_t rideIndex);
rct_tile_element* map_get_track_element_at_from_ride(int32_t x, int32_t y, int32_t z, int32_t rideIndex);
rct_tile_element*
map_get_track_element_at_with_direction_from_ride(int32_t x, int32_t y, int32_t z, int32_t direction, int32_t rideIndex);
bool map_is_location_at_edge(int32_t x, int32_t y);
void map_obstruction_set_error_text(rct_tile_element *tileElement);
void map_obstruction_set_error_text(rct_tile_element* tileElement);
uint32_t map_get_available_peep_spawn_index_list(uint32_t* peepSpawnIndexList);
uint16_t check_max_allowable_land_rights_for_tile(uint8_t x, uint8_t y, uint8_t base_z);
@ -267,6 +318,6 @@ void FixLandOwnershipTilesWithOwnership(std::initializer_list<TileCoordsXY> tile
bool place_peep_spawn(CoordsXYZD location);
uint8_t entrance_element_get_type(const rct_tile_element * tileElement);
uint8_t entrance_element_get_type(const rct_tile_element* tileElement);
#endif

View File

@ -7,24 +7,25 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include <cstring>
#include "MapAnimation.h"
#include "../Game.h"
#include "../interface/Viewport.h"
#include "../ride/Ride.h"
#include "../ride/RideData.h"
#include "../ride/Track.h"
#include "../interface/Viewport.h"
#include "../world/Wall.h"
#include "MapAnimation.h"
#include "Footpath.h"
#include "Map.h"
#include "Scenery.h"
#include "SmallScenery.h"
#include "Sprite.h"
#include "Footpath.h"
#include <cstring>
using map_animation_invalidate_event_handler = bool (*)(int32_t x, int32_t y, int32_t baseZ);
static bool map_animation_invalidate(rct_map_animation *obj);
static bool map_animation_invalidate(rct_map_animation* obj);
uint16_t gNumMapAnimations;
rct_map_animation gAnimatedObjects[MAX_ANIMATED_OBJECTS];
@ -40,13 +41,15 @@ rct_map_animation gAnimatedObjects[MAX_ANIMATED_OBJECTS];
*/
void map_animation_create(int32_t type, int32_t x, int32_t y, int32_t z)
{
rct_map_animation *aobj = &gAnimatedObjects[0];
rct_map_animation* aobj = &gAnimatedObjects[0];
int32_t numAnimatedObjects = gNumMapAnimations;
if (numAnimatedObjects >= MAX_ANIMATED_OBJECTS) {
if (numAnimatedObjects >= MAX_ANIMATED_OBJECTS)
{
log_error("Exceeded the maximum number of animations");
return;
}
for (int32_t i = 0; i < numAnimatedObjects; i++, aobj++) {
for (int32_t i = 0; i < numAnimatedObjects; i++, aobj++)
{
if (aobj->x != x)
continue;
if (aobj->y != y)
@ -73,16 +76,20 @@ void map_animation_create(int32_t type, int32_t x, int32_t y, int32_t z)
*/
void map_animation_invalidate_all()
{
rct_map_animation *aobj = &gAnimatedObjects[0];
rct_map_animation* aobj = &gAnimatedObjects[0];
int32_t numAnimatedObjects = gNumMapAnimations;
while (numAnimatedObjects > 0) {
if (map_animation_invalidate(aobj)) {
while (numAnimatedObjects > 0)
{
if (map_animation_invalidate(aobj))
{
// Remove animated object
gNumMapAnimations--;
numAnimatedObjects--;
if (numAnimatedObjects > 0)
memmove(aobj, aobj + 1, numAnimatedObjects * sizeof(rct_map_animation));
} else {
}
else
{
numAnimatedObjects--;
aobj++;
}
@ -95,12 +102,13 @@ void map_animation_invalidate_all()
*/
static bool map_animation_invalidate_ride_entrance(int32_t x, int32_t y, int32_t baseZ)
{
rct_tile_element *tileElement;
Ride *ride;
const rct_ride_entrance_definition *entranceDefinition;
rct_tile_element* tileElement;
Ride* ride;
const rct_ride_entrance_definition* entranceDefinition;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement->base_height != baseZ)
continue;
if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE)
@ -125,10 +133,11 @@ static bool map_animation_invalidate_ride_entrance(int32_t x, int32_t y, int32_t
*/
static bool map_animation_invalidate_queue_banner(int32_t x, int32_t y, int32_t baseZ)
{
rct_tile_element *tileElement;
rct_tile_element* tileElement;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement->base_height != baseZ)
continue;
if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH)
@ -139,7 +148,8 @@ static bool map_animation_invalidate_queue_banner(int32_t x, int32_t y, int32_t
continue;
int32_t direction = (footpath_element_get_direction(tileElement) + get_current_rotation()) & 3;
if (direction == TILE_ELEMENT_DIRECTION_NORTH || direction == TILE_ELEMENT_DIRECTION_EAST) {
if (direction == TILE_ELEMENT_DIRECTION_NORTH || direction == TILE_ELEMENT_DIRECTION_EAST)
{
baseZ = tileElement->base_height * 8;
map_invalidate_tile_zoom1(x, y, baseZ + 16, baseZ + 30);
}
@ -155,13 +165,14 @@ static bool map_animation_invalidate_queue_banner(int32_t x, int32_t y, int32_t
*/
static bool map_animation_invalidate_small_scenery(int32_t x, int32_t y, int32_t baseZ)
{
rct_tile_element *tileElement;
rct_scenery_entry *sceneryEntry;
rct_sprite *sprite;
rct_peep *peep;
rct_tile_element* tileElement;
rct_scenery_entry* sceneryEntry;
rct_sprite* sprite;
rct_peep* peep;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement->base_height != baseZ)
continue;
if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)
@ -170,7 +181,10 @@ static bool map_animation_invalidate_small_scenery(int32_t x, int32_t y, int32_t
continue;
sceneryEntry = get_small_scenery_entry(tileElement->properties.scenery.type);
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1 | SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4 | SMALL_SCENERY_FLAG_SWAMP_GOO | SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS))
if (scenery_small_entry_has_flag(
sceneryEntry,
SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1 | SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4 | SMALL_SCENERY_FLAG_SWAMP_GOO
| SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS))
{
map_invalidate_tile_zoom1(x, y, tileElement->base_height * 8, tileElement->clearance_height * 8);
return false;
@ -179,13 +193,15 @@ static bool map_animation_invalidate_small_scenery(int32_t x, int32_t y, int32_t
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_IS_CLOCK))
{
// Peep, looking at scenery
if (!(gCurrentTicks & 0x3FF) && game_is_not_paused()) {
if (!(gCurrentTicks & 0x3FF) && game_is_not_paused())
{
int32_t direction = tile_element_get_direction(tileElement);
int32_t x2 = x - CoordsDirectionDelta[direction].x;
int32_t y2 = y - CoordsDirectionDelta[direction].y;
uint16_t spriteIdx = sprite_get_first_in_quadrant(x2, y2);
for (; spriteIdx != SPRITE_INDEX_NULL; spriteIdx = sprite->unknown.next_in_quadrant) {
for (; spriteIdx != SPRITE_INDEX_NULL; spriteIdx = sprite->unknown.next_in_quadrant)
{
sprite = get_sprite(spriteIdx);
if (sprite->unknown.linked_list_type_offset != SPRITE_LIST_PEEP * 2)
continue;
@ -220,10 +236,11 @@ static bool map_animation_invalidate_small_scenery(int32_t x, int32_t y, int32_t
*/
static bool map_animation_invalidate_park_entrance(int32_t x, int32_t y, int32_t baseZ)
{
rct_tile_element *tileElement;
rct_tile_element* tileElement;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement->base_height != baseZ)
continue;
if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE)
@ -247,16 +264,18 @@ static bool map_animation_invalidate_park_entrance(int32_t x, int32_t y, int32_t
*/
static bool map_animation_invalidate_track_waterfall(int32_t x, int32_t y, int32_t baseZ)
{
rct_tile_element *tileElement;
rct_tile_element* tileElement;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement->base_height != baseZ)
continue;
if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK)
continue;
if (track_element_get_type(tileElement) == TRACK_ELEM_WATERFALL) {
if (track_element_get_type(tileElement) == TRACK_ELEM_WATERFALL)
{
int32_t z = tileElement->base_height * 8;
map_invalidate_tile_zoom1(x, y, z + 14, z + 46);
return false;
@ -272,16 +291,18 @@ static bool map_animation_invalidate_track_waterfall(int32_t x, int32_t y, int32
*/
static bool map_animation_invalidate_track_rapids(int32_t x, int32_t y, int32_t baseZ)
{
rct_tile_element *tileElement;
rct_tile_element* tileElement;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement->base_height != baseZ)
continue;
if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK)
continue;
if (track_element_get_type(tileElement) == TRACK_ELEM_RAPIDS) {
if (track_element_get_type(tileElement) == TRACK_ELEM_RAPIDS)
{
int32_t z = tileElement->base_height * 8;
map_invalidate_tile_zoom1(x, y, z + 14, z + 18);
return false;
@ -297,10 +318,11 @@ static bool map_animation_invalidate_track_rapids(int32_t x, int32_t y, int32_t
*/
static bool map_animation_invalidate_track_onridephoto(int32_t x, int32_t y, int32_t baseZ)
{
rct_tile_element *tileElement;
rct_tile_element* tileElement;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement == nullptr)
break;
if (tileElement->base_height != baseZ)
@ -308,15 +330,20 @@ static bool map_animation_invalidate_track_onridephoto(int32_t x, int32_t y, int
if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK)
continue;
if (track_element_get_type(tileElement) == TRACK_ELEM_ON_RIDE_PHOTO) {
if (track_element_get_type(tileElement) == TRACK_ELEM_ON_RIDE_PHOTO)
{
map_invalidate_tile_zoom1(x, y, tileElement->base_height * 8, tileElement->clearance_height * 8);
if (game_is_paused()) {
if (game_is_paused())
{
return false;
}
if (tile_element_is_taking_photo(tileElement)) {
if (tile_element_is_taking_photo(tileElement))
{
tile_element_decrement_onride_photo_timout(tileElement);
return false;
} else {
}
else
{
return true;
}
}
@ -331,16 +358,18 @@ static bool map_animation_invalidate_track_onridephoto(int32_t x, int32_t y, int
*/
static bool map_animation_invalidate_track_whirlpool(int32_t x, int32_t y, int32_t baseZ)
{
rct_tile_element *tileElement;
rct_tile_element* tileElement;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement->base_height != baseZ)
continue;
if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK)
continue;
if (track_element_get_type(tileElement) == TRACK_ELEM_WHIRLPOOL) {
if (track_element_get_type(tileElement) == TRACK_ELEM_WHIRLPOOL)
{
int32_t z = tileElement->base_height * 8;
map_invalidate_tile_zoom1(x, y, z + 14, z + 18);
return false;
@ -356,16 +385,18 @@ static bool map_animation_invalidate_track_whirlpool(int32_t x, int32_t y, int32
*/
static bool map_animation_invalidate_track_spinningtunnel(int32_t x, int32_t y, int32_t baseZ)
{
rct_tile_element *tileElement;
rct_tile_element* tileElement;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement->base_height != baseZ)
continue;
if (tileElement->GetType() != TILE_ELEMENT_TYPE_TRACK)
continue;
if (track_element_get_type(tileElement) == TRACK_ELEM_SPINNING_TUNNEL) {
if (track_element_get_type(tileElement) == TRACK_ELEM_SPINNING_TUNNEL)
{
int32_t z = tileElement->base_height * 8;
map_invalidate_tile_zoom1(x, y, z + 14, z + 32);
return false;
@ -379,7 +410,8 @@ static bool map_animation_invalidate_track_spinningtunnel(int32_t x, int32_t y,
*
* rct2: 0x0068DF8F
*/
static bool map_animation_invalidate_remove([[maybe_unused]] int32_t x, [[maybe_unused]] int32_t y, [[maybe_unused]] int32_t baseZ)
static bool
map_animation_invalidate_remove([[maybe_unused]] int32_t x, [[maybe_unused]] int32_t y, [[maybe_unused]] int32_t baseZ)
{
return true;
}
@ -390,10 +422,11 @@ static bool map_animation_invalidate_remove([[maybe_unused]] int32_t x, [[maybe_
*/
static bool map_animation_invalidate_banner(int32_t x, int32_t y, int32_t baseZ)
{
rct_tile_element *tileElement;
rct_tile_element* tileElement;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement->base_height != baseZ)
continue;
if (tileElement->GetType() != TILE_ELEMENT_TYPE_BANNER)
@ -413,19 +446,21 @@ static bool map_animation_invalidate_banner(int32_t x, int32_t y, int32_t baseZ)
*/
static bool map_animation_invalidate_large_scenery(int32_t x, int32_t y, int32_t baseZ)
{
rct_tile_element *tileElement;
rct_scenery_entry *sceneryEntry;
rct_tile_element* tileElement;
rct_scenery_entry* sceneryEntry;
bool wasInvalidated = false;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement->base_height != baseZ)
continue;
if (tileElement->GetType() != TILE_ELEMENT_TYPE_LARGE_SCENERY)
continue;
sceneryEntry = get_large_scenery_entry(tileElement->properties.scenery.type & 0x3FF);
if (sceneryEntry->large_scenery.flags & LARGE_SCENERY_FLAG_ANIMATED) {
if (sceneryEntry->large_scenery.flags & LARGE_SCENERY_FLAG_ANIMATED)
{
int32_t z = tileElement->base_height * 8;
map_invalidate_tile_zoom1(x, y, z, z + 16);
wasInvalidated = true;
@ -441,15 +476,16 @@ static bool map_animation_invalidate_large_scenery(int32_t x, int32_t y, int32_t
*/
static bool map_animation_invalidate_wall_door(int32_t x, int32_t y, int32_t baseZ)
{
rct_tile_element *tileElement;
rct_scenery_entry *sceneryEntry;
rct_tile_element* tileElement;
rct_scenery_entry* sceneryEntry;
if (gCurrentTicks & 1)
return false;
bool removeAnimation = true;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement->base_height != baseZ)
continue;
if (tileElement->GetType() != TILE_ELEMENT_TYPE_WALL)
@ -459,19 +495,25 @@ static bool map_animation_invalidate_wall_door(int32_t x, int32_t y, int32_t bas
if (!(sceneryEntry->wall.flags & WALL_SCENERY_IS_DOOR))
continue;
if (game_is_paused()) {
if (game_is_paused())
{
return false;
}
bool invalidate = false;
uint8_t currentFrame = wall_get_animation_frame(tileElement);
if (currentFrame != 0) {
if (currentFrame == 15) {
if (currentFrame != 0)
{
if (currentFrame == 15)
{
currentFrame = 0;
} else {
}
else
{
removeAnimation = false;
if (currentFrame != 5) {
if (currentFrame != 5)
{
currentFrame++;
if (currentFrame == 13 && !(sceneryEntry->wall.flags & WALL_SCENERY_LONG_DOOR_ANIMATION))
currentFrame = 15;
@ -481,7 +523,8 @@ static bool map_animation_invalidate_wall_door(int32_t x, int32_t y, int32_t bas
}
}
wall_set_animation_frame(tileElement, currentFrame);
if (invalidate) {
if (invalidate)
{
int32_t z = tileElement->base_height * 8;
map_invalidate_tile_zoom1(x, y, z, z + 32);
}
@ -496,12 +539,13 @@ static bool map_animation_invalidate_wall_door(int32_t x, int32_t y, int32_t bas
*/
static bool map_animation_invalidate_wall(int32_t x, int32_t y, int32_t baseZ)
{
rct_tile_element *tileElement;
rct_scenery_entry *sceneryEntry;
rct_tile_element* tileElement;
rct_scenery_entry* sceneryEntry;
bool wasInvalidated = false;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement->base_height != baseZ)
continue;
if (tileElement->GetType() != TILE_ELEMENT_TYPE_WALL)
@ -524,29 +568,28 @@ static bool map_animation_invalidate_wall(int32_t x, int32_t y, int32_t baseZ)
*
* rct2: 0x009819DC
*/
static constexpr const map_animation_invalidate_event_handler _animatedObjectEventHandlers[MAP_ANIMATION_TYPE_COUNT] = {
map_animation_invalidate_ride_entrance,
map_animation_invalidate_queue_banner,
map_animation_invalidate_small_scenery,
map_animation_invalidate_park_entrance,
map_animation_invalidate_track_waterfall,
map_animation_invalidate_track_rapids,
map_animation_invalidate_track_onridephoto,
map_animation_invalidate_track_whirlpool,
map_animation_invalidate_track_spinningtunnel,
map_animation_invalidate_remove,
map_animation_invalidate_banner,
map_animation_invalidate_large_scenery,
map_animation_invalidate_wall_door,
map_animation_invalidate_wall
};
static constexpr const map_animation_invalidate_event_handler _animatedObjectEventHandlers[MAP_ANIMATION_TYPE_COUNT]
= { map_animation_invalidate_ride_entrance,
map_animation_invalidate_queue_banner,
map_animation_invalidate_small_scenery,
map_animation_invalidate_park_entrance,
map_animation_invalidate_track_waterfall,
map_animation_invalidate_track_rapids,
map_animation_invalidate_track_onridephoto,
map_animation_invalidate_track_whirlpool,
map_animation_invalidate_track_spinningtunnel,
map_animation_invalidate_remove,
map_animation_invalidate_banner,
map_animation_invalidate_large_scenery,
map_animation_invalidate_wall_door,
map_animation_invalidate_wall };
/**
* @returns true if the animation should be removed.
*/
static bool map_animation_invalidate(rct_map_animation *obj)
static bool map_animation_invalidate(rct_map_animation* obj)
{
assert(obj->type < MAP_ANIMATION_TYPE_COUNT);
return _animatedObjectEventHandlers[obj->type](obj->x, obj->y, obj->baseZ);
}

View File

@ -17,7 +17,8 @@
* Animated object
* size: 0x06
*/
struct rct_map_animation {
struct rct_map_animation
{
uint8_t baseZ;
uint8_t type;
uint16_t x;
@ -26,7 +27,8 @@ struct rct_map_animation {
assert_struct_size(rct_map_animation, 6);
#pragma pack(pop)
enum {
enum
{
MAP_ANIMATION_TYPE_RIDE_ENTRANCE,
MAP_ANIMATION_TYPE_QUEUE_BANNER,
MAP_ANIMATION_TYPE_SMALL_SCENERY,

View File

@ -7,83 +7,80 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "../common.h"
#include <cmath>
#include <cstring>
#include <vector>
#include "MapGen.h"
#include "../Context.h"
#include "../Game.h"
#include "../common.h"
#include "../core/Guard.hpp"
#include "../core/Imaging.h"
#include "../core/Math.hpp"
#include "../core/String.hpp"
#include "../core/Util.hpp"
#include "../Game.h"
#include "../core/Imaging.h"
#include "../localisation/StringIds.h"
#include "../object/Object.h"
#include "../platform/platform.h"
#include "../util/Util.h"
#include "Map.h"
#include "MapHelpers.h"
#include "MapGen.h"
#include "Scenery.h"
#include "SmallScenery.h"
#include "Surface.h"
#include <cmath>
#include <cstring>
#include <vector>
#pragma region Height map struct
static struct
{
uint32_t width, height;
uint8_t * mono_bitmap;
} _heightMapData = {
0,
0,
nullptr
};
uint8_t* mono_bitmap;
} _heightMapData = { 0, 0, nullptr };
#pragma endregion Height map struct
#pragma region Random objects
static constexpr const char * GrassTrees[] = {
static constexpr const char* GrassTrees[] = {
// Dark
"TCF ", // Caucasian Fir Tree
"TRF ", // Red Fir Tree
"TRF2 ", // Red Fir Tree
"TSP ", // Scots Pine Tree
"TMZP ", // Montezuma Pine Tree
"TAP ", // Aleppo Pine Tree
"TCRP ", // Corsican Pine Tree
"TBP ", // Black Poplar Tree
"TCF ", // Caucasian Fir Tree
"TRF ", // Red Fir Tree
"TRF2 ", // Red Fir Tree
"TSP ", // Scots Pine Tree
"TMZP ", // Montezuma Pine Tree
"TAP ", // Aleppo Pine Tree
"TCRP ", // Corsican Pine Tree
"TBP ", // Black Poplar Tree
// Light
"TCL ", // Cedar of Lebanon Tree
"TEL ", // European Larch Tree
"TCL ", // Cedar of Lebanon Tree
"TEL ", // European Larch Tree
};
static constexpr const char * DesertTrees[] = {
"TMP ", // Monkey-Puzzle Tree
"THL ", // Honey Locust Tree
"TH1 ", // Canary Palm Tree
"TH2 ", // Palm Tree
"TPM ", // Palm Tree
"TROPT1 ", // Tree
"TBC ", // Cactus
"TSC ", // Cactus
static constexpr const char* DesertTrees[] = {
"TMP ", // Monkey-Puzzle Tree
"THL ", // Honey Locust Tree
"TH1 ", // Canary Palm Tree
"TH2 ", // Palm Tree
"TPM ", // Palm Tree
"TROPT1 ", // Tree
"TBC ", // Cactus
"TSC ", // Cactus
};
static constexpr const char * SnowTrees[] = {
"TCFS ", // Snow-covered Caucasian Fir Tree
"TNSS ", // Snow-covered Norway Spruce Tree
"TRF3 ", // Snow-covered Red Fir Tree
"TRFS ", // Snow-covered Red Fir Tree
static constexpr const char* SnowTrees[] = {
"TCFS ", // Snow-covered Caucasian Fir Tree
"TNSS ", // Snow-covered Norway Spruce Tree
"TRF3 ", // Snow-covered Red Fir Tree
"TRFS ", // Snow-covered Red Fir Tree
};
#pragma endregion
// Randomly chosen base terrains. We rarely want a whole map made out of chequerboard or rock.
static constexpr const uint8_t BaseTerrain[] = {TERRAIN_GRASS, TERRAIN_SAND, TERRAIN_SAND_LIGHT, TERRAIN_DIRT, TERRAIN_ICE};
static constexpr const uint8_t BaseTerrain[] = { TERRAIN_GRASS, TERRAIN_SAND, TERRAIN_SAND_LIGHT, TERRAIN_DIRT, TERRAIN_ICE };
#define BLOB_HEIGHT 255
@ -92,10 +89,10 @@ static void mapgen_set_water_level(int32_t waterLevel);
static void mapgen_smooth_height(int32_t iterations);
static void mapgen_set_height();
static void mapgen_simplex(mapgen_settings * settings);
static void mapgen_simplex(mapgen_settings* settings);
static int32_t _heightSize;
static uint8_t * _height;
static int32_t _heightSize;
static uint8_t* _height;
static int32_t get_height(int32_t x, int32_t y)
{
@ -111,10 +108,10 @@ static void set_height(int32_t x, int32_t y, int32_t height)
_height[x + y * _heightSize] = height;
}
void mapgen_generate_blank(mapgen_settings * settings)
void mapgen_generate_blank(mapgen_settings* settings)
{
int32_t x, y;
rct_tile_element * tileElement;
rct_tile_element* tileElement;
map_clear_all_elements();
@ -126,7 +123,7 @@ void mapgen_generate_blank(mapgen_settings * settings)
tileElement = map_get_surface_element_at(x, y);
surface_set_terrain(tileElement, settings->floor);
surface_set_terrain_edge(tileElement, settings->wall);
tileElement->base_height = settings->height;
tileElement->base_height = settings->height;
tileElement->clearance_height = settings->height;
}
}
@ -134,17 +131,17 @@ void mapgen_generate_blank(mapgen_settings * settings)
mapgen_set_water_level(settings->water_level);
}
void mapgen_generate(mapgen_settings * settings)
void mapgen_generate(mapgen_settings* settings)
{
int32_t x, y, mapSize, floorTexture, wallTexture, waterLevel;
rct_tile_element * tileElement;
rct_tile_element* tileElement;
util_srand((int32_t) platform_get_ticks());
util_srand((int32_t)platform_get_ticks());
mapSize = settings->mapSize;
mapSize = settings->mapSize;
floorTexture = settings->floor;
wallTexture = settings->wall;
waterLevel = settings->water_level;
wallTexture = settings->wall;
waterLevel = settings->water_level;
if (floorTexture == -1)
floorTexture = BaseTerrain[util_rand() % Util::CountOf(BaseTerrain)];
@ -154,15 +151,15 @@ void mapgen_generate(mapgen_settings * settings)
// Base edge type on surface type
switch (floorTexture)
{
case TERRAIN_DIRT:
wallTexture = TERRAIN_EDGE_WOOD_RED;
break;
case TERRAIN_ICE:
wallTexture = TERRAIN_EDGE_ICE;
break;
default:
wallTexture = TERRAIN_EDGE_ROCK;
break;
case TERRAIN_DIRT:
wallTexture = TERRAIN_EDGE_WOOD_RED;
break;
case TERRAIN_ICE:
wallTexture = TERRAIN_EDGE_ICE;
break;
default:
wallTexture = TERRAIN_EDGE_ROCK;
break;
}
}
@ -177,14 +174,14 @@ void mapgen_generate(mapgen_settings * settings)
tileElement = map_get_surface_element_at(x, y);
surface_set_terrain(tileElement, floorTexture);
surface_set_terrain_edge(tileElement, wallTexture);
tileElement->base_height = settings->height;
tileElement->base_height = settings->height;
tileElement->clearance_height = settings->height;
}
}
// Create the temporary height map and initialise
_heightSize = mapSize * 2;
_height = new uint8_t[_heightSize * _heightSize];
_height = new uint8_t[_heightSize * _heightSize];
memset(_height, 0, _heightSize * _heightSize * sizeof(uint8_t));
mapgen_simplex(settings);
@ -195,7 +192,9 @@ void mapgen_generate(mapgen_settings * settings)
delete[] _height;
// Set the tile slopes so that there are no cliffs
while (map_smooth(1, 1, mapSize - 1, mapSize - 1)) {}
while (map_smooth(1, 1, mapSize - 1, mapSize - 1))
{
}
// Add the water
mapgen_set_water_level(waterLevel);
@ -206,12 +205,12 @@ void mapgen_generate(mapgen_settings * settings)
{
switch (util_rand() % 4)
{
case 0:
beachTexture = TERRAIN_SAND;
break;
case 1:
beachTexture = TERRAIN_SAND_LIGHT;
break;
case 0:
beachTexture = TERRAIN_SAND;
break;
case 1:
beachTexture = TERRAIN_SAND_LIGHT;
break;
}
}
for (y = 1; y < mapSize - 1; y++)
@ -235,21 +234,21 @@ void mapgen_generate(mapgen_settings * settings)
static void mapgen_place_tree(int32_t type, int32_t x, int32_t y)
{
int32_t surfaceZ;
rct_tile_element * tileElement;
rct_scenery_entry * sceneryEntry = get_small_scenery_entry(type);
rct_tile_element* tileElement;
rct_scenery_entry* sceneryEntry = get_small_scenery_entry(type);
if (sceneryEntry == nullptr)
{
return;
}
surfaceZ = tile_element_height(x * 32 + 16, y * 32 + 16) / 8;
surfaceZ = tile_element_height(x * 32 + 16, y * 32 + 16) / 8;
tileElement = tile_element_insert(x, y, surfaceZ, (1 | 2 | 4 | 8));
assert(tileElement != nullptr);
tileElement->clearance_height = surfaceZ + (sceneryEntry->small_scenery.height >> 3);
tileElement->type = TILE_ELEMENT_TYPE_SMALL_SCENERY | (util_rand() & 3);
tileElement->type = TILE_ELEMENT_TYPE_SMALL_SCENERY | (util_rand() & 3);
tileElement->properties.scenery.type = type;
tileElement->properties.scenery.age = 0;
tileElement->properties.scenery.age = 0;
scenery_small_set_primary_colour(tileElement, COLOUR_YELLOW);
}
@ -314,7 +313,7 @@ static void mapgen_place_trees()
{
for (int32_t x = 1; x < gMapSize - 1; x++)
{
rct_tile_element * tileElement = map_get_surface_element_at(x, y);
rct_tile_element* tileElement = map_get_surface_element_at(x, y);
// Exclude water tiles
if (surface_get_water_height(tileElement) > 0)
@ -323,7 +322,6 @@ static void mapgen_place_trees()
pos.x = x;
pos.y = y;
availablePositions.push_back(pos);
}
}
@ -335,47 +333,48 @@ static void mapgen_place_trees()
continue;
tmp = availablePositions[i];
availablePositions[i] = availablePositions[rindex];
availablePositions[i] = availablePositions[rindex];
availablePositions[rindex] = tmp;
}
// Place trees
float treeToLandRatio = (10 + (util_rand() % 30)) / 100.0f;
int32_t numTrees = std::min(std::max(4, (int32_t) (availablePositions.size() * treeToLandRatio)), (int32_t)availablePositions.size());
float treeToLandRatio = (10 + (util_rand() % 30)) / 100.0f;
int32_t numTrees
= std::min(std::max(4, (int32_t)(availablePositions.size() * treeToLandRatio)), (int32_t)availablePositions.size());
for (int32_t i = 0; i < numTrees; i++)
{
pos = availablePositions[i];
int32_t type = -1;
rct_tile_element * tileElement = map_get_surface_element_at(pos.x, pos.y);
rct_tile_element* tileElement = map_get_surface_element_at(pos.x, pos.y);
switch (surface_get_terrain(tileElement))
{
case TERRAIN_GRASS:
case TERRAIN_DIRT:
case TERRAIN_GRASS_CLUMPS:
if (grassTreeIds.size() == 0)
case TERRAIN_GRASS:
case TERRAIN_DIRT:
case TERRAIN_GRASS_CLUMPS:
if (grassTreeIds.size() == 0)
break;
type = grassTreeIds[util_rand() % grassTreeIds.size()];
break;
type = grassTreeIds[util_rand() % grassTreeIds.size()];
break;
case TERRAIN_SAND:
case TERRAIN_SAND_DARK:
case TERRAIN_SAND_LIGHT:
if (desertTreeIds.size() == 0)
break;
case TERRAIN_SAND:
case TERRAIN_SAND_DARK:
case TERRAIN_SAND_LIGHT:
if (desertTreeIds.size() == 0)
if (util_rand() % 4 == 0)
type = desertTreeIds[util_rand() % desertTreeIds.size()];
break;
if (util_rand() % 4 == 0)
type = desertTreeIds[util_rand() % desertTreeIds.size()];
break;
case TERRAIN_ICE:
if (snowTreeIds.size() == 0)
break;
case TERRAIN_ICE:
if (snowTreeIds.size() == 0)
type = snowTreeIds[util_rand() % snowTreeIds.size()];
break;
type = snowTreeIds[util_rand() % snowTreeIds.size()];
break;
}
if (type != -1)
@ -389,7 +388,7 @@ static void mapgen_place_trees()
static void mapgen_set_water_level(int32_t waterLevel)
{
int32_t x, y, mapSize;
rct_tile_element * tileElement;
rct_tile_element* tileElement;
mapSize = gMapSize;
@ -411,7 +410,7 @@ static void mapgen_smooth_height(int32_t iterations)
{
int32_t i, x, y, xx, yy, avg;
int32_t arraySize = _heightSize * _heightSize * sizeof(uint8_t);
uint8_t * copyHeight = new uint8_t[arraySize];
uint8_t* copyHeight = new uint8_t[arraySize];
for (i = 0; i < iterations; i++)
{
@ -420,7 +419,7 @@ static void mapgen_smooth_height(int32_t iterations)
{
for (x = 1; x < _heightSize - 1; x++)
{
avg = 0;
avg = 0;
for (yy = -1; yy <= 1; yy++)
{
for (xx = -1; xx <= 1; xx++)
@ -443,10 +442,10 @@ static void mapgen_smooth_height(int32_t iterations)
static void mapgen_set_height()
{
int32_t x, y, heightX, heightY, mapSize;
rct_tile_element * tileElement;
rct_tile_element* tileElement;
mapSize = _heightSize / 2;
for (y = 1; y < mapSize - 1; y++)
for (y = 1; y < mapSize - 1; y++)
{
for (x = 1; x < mapSize - 1; x++)
{
@ -461,7 +460,7 @@ static void mapgen_set_height()
uint8_t baseHeight = (q00 + q01 + q10 + q11) / 4;
tileElement = map_get_surface_element_at(x, y);
tileElement->base_height = std::max(2, baseHeight * 2);
tileElement->base_height = std::max(2, baseHeight * 2);
tileElement->clearance_height = tileElement->base_height;
if (q00 > baseHeight)
@ -493,7 +492,7 @@ static uint8_t perm[512];
static void noise_rand()
{
for (auto &i : perm)
for (auto& i : perm)
{
i = util_rand() & 0xFF;
}
@ -501,9 +500,9 @@ static void noise_rand()
static float fractal_noise(int32_t x, int32_t y, float frequency, int32_t octaves, float lacunarity, float persistence)
{
float total = 0.0f;
float amplitude = persistence;
for (int32_t i = 0; i < octaves; i++)
float total = 0.0f;
float amplitude = persistence;
for (int32_t i = 0; i < octaves; i++)
{
total += generate(x * frequency, y * frequency) * amplitude;
frequency *= lacunarity;
@ -520,13 +519,13 @@ static float generate(float x, float y)
float n0, n1, n2; // Noise contributions from the three corners
// Skew the input space to determine which simplex cell we're in
float s = (x + y) * F2; // Hairy factor for 2D
float xs = x + s;
float ys = y + s;
int32_t i = fast_floor(xs);
int32_t j = fast_floor(ys);
float s = (x + y) * F2; // Hairy factor for 2D
float xs = x + s;
float ys = y + s;
int32_t i = fast_floor(xs);
int32_t j = fast_floor(ys);
float t = (float) (i + j) * G2;
float t = (float)(i + j) * G2;
float X0 = i - t; // Unskew the cell origin back to (x,y) space
float Y0 = j - t;
float x0 = x - X0; // The x,y distances from the cell origin
@ -544,7 +543,7 @@ static float generate(float x, float y)
{
i1 = 0;
j1 = 1;
} // upper triangle, YX order: (0,0)->(0,1)->(1,1)
} // upper triangle, YX order: (0,0)->(0,1)->(1,1)
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
@ -600,25 +599,25 @@ static float generate(float x, float y)
static int32_t fast_floor(float x)
{
return (x > 0) ? ((int32_t) x) : (((int32_t) x) - 1);
return (x > 0) ? ((int32_t)x) : (((int32_t)x) - 1);
}
static float grad(int32_t hash, float x, float y)
{
int32_t h = hash & 7; // Convert low 3 bits of hash code
float u = h < 4 ? x : y; // into 8 simple gradient directions,
float v = h < 4 ? y : x; // and compute the dot product with (x,y).
int32_t h = hash & 7; // Convert low 3 bits of hash code
float u = h < 4 ? x : y; // into 8 simple gradient directions,
float v = h < 4 ? y : x; // and compute the dot product with (x,y).
return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -2.0f * v : 2.0f * v);
}
static void mapgen_simplex(mapgen_settings * settings)
static void mapgen_simplex(mapgen_settings* settings)
{
int32_t x, y;
float freq = settings->simplex_base_freq * (1.0f / _heightSize);
float freq = settings->simplex_base_freq * (1.0f / _heightSize);
int32_t octaves = settings->simplex_octaves;
int32_t low = settings->simplex_low;
int32_t low = settings->simplex_low;
int32_t high = settings->simplex_high;
noise_rand();
@ -626,10 +625,10 @@ static void mapgen_simplex(mapgen_settings * settings)
{
for (x = 0; x < _heightSize; x++)
{
float noiseValue = Math::Clamp(-1.0f, fractal_noise(x, y, freq, octaves, 2.0f, 0.65f), 1.0f);
float noiseValue = Math::Clamp(-1.0f, fractal_noise(x, y, freq, octaves, 2.0f, 0.65f), 1.0f);
float normalisedNoiseValue = (noiseValue + 1.0f) / 2.0f;
set_height(x, y, low + (int32_t) (normalisedNoiseValue * high));
set_height(x, y, low + (int32_t)(normalisedNoiseValue * high));
}
}
}
@ -638,7 +637,7 @@ static void mapgen_simplex(mapgen_settings * settings)
#pragma region Heightmap
bool mapgen_load_heightmap(const utf8 * path)
bool mapgen_load_heightmap(const utf8* path)
{
auto format = Imaging::GetImageFormatFromPath(path);
if (format == IMAGE_FORMAT::PNG)
@ -709,17 +708,17 @@ bool mapgen_load_heightmap(const utf8 * path)
void mapgen_unload_heightmap()
{
SafeDeleteArray(_heightMapData.mono_bitmap);
_heightMapData.width = 0;
_heightMapData.height = 0;
_heightMapData.width = 0;
_heightMapData.height = 0;
}
/**
* Applies box blur to the surface N times
*/
static void mapgen_smooth_heightmap(uint8_t * src, int32_t strength)
static void mapgen_smooth_heightmap(uint8_t* src, int32_t strength)
{
// Create buffer to store one channel
uint8_t * dest = new uint8_t[_heightMapData.width * _heightMapData.height];
uint8_t* dest = new uint8_t[_heightMapData.width * _heightMapData.height];
for (int32_t i = 0; i < strength; i++)
{
@ -737,8 +736,8 @@ static void mapgen_smooth_heightmap(uint8_t * src, int32_t strength)
{
// Clamp x and y so they stay within the image
// This assumes the height map is not tiled, and increases the weight of the edges
const int32_t readX = Math::Clamp((int32_t) x + offsetX, 0, (int32_t) _heightMapData.width - 1);
const int32_t readY = Math::Clamp((int32_t) y + offsetY, 0, (int32_t) _heightMapData.height - 1);
const int32_t readX = Math::Clamp((int32_t)x + offsetX, 0, (int32_t)_heightMapData.width - 1);
const int32_t readY = Math::Clamp((int32_t)y + offsetY, 0, (int32_t)_heightMapData.height - 1);
heightSum += src[readX + readY * _heightMapData.width];
}
}
@ -761,14 +760,14 @@ static void mapgen_smooth_heightmap(uint8_t * src, int32_t strength)
delete[] dest;
}
void mapgen_generate_from_heightmap(mapgen_settings * settings)
void mapgen_generate_from_heightmap(mapgen_settings* settings)
{
openrct2_assert(_heightMapData.width == _heightMapData.height, "Invalid height map size");
openrct2_assert(_heightMapData.mono_bitmap != nullptr, "No height map loaded");
openrct2_assert(settings->simplex_high != settings->simplex_low, "Low and high setting cannot be the same");
// Make a copy of the original height map that we can edit
uint8_t * dest = new uint8_t[_heightMapData.width * _heightMapData.height];
uint8_t* dest = new uint8_t[_heightMapData.width * _heightMapData.height];
memcpy(dest, _heightMapData.mono_bitmap, _heightMapData.width * _heightMapData.width);
map_init(_heightMapData.width + 2); // + 2 for the black tiles around the map
@ -791,8 +790,8 @@ void mapgen_generate_from_heightmap(mapgen_settings * settings)
for (uint32_t x = 0; x < _heightMapData.width; x++)
{
uint8_t value = dest[x + y * _heightMapData.width];
maxValue = std::max(maxValue, value);
minValue = std::min(minValue, value);
maxValue = std::max(maxValue, value);
minValue = std::min(minValue, value);
}
}
@ -807,7 +806,7 @@ void mapgen_generate_from_heightmap(mapgen_settings * settings)
openrct2_assert(maxValue > minValue, "Input range is invalid");
openrct2_assert(settings->simplex_high > settings->simplex_low, "Output range is invalid");
const uint8_t rangeIn = maxValue - minValue;
const uint8_t rangeIn = maxValue - minValue;
const uint8_t rangeOut = settings->simplex_high - settings->simplex_low;
for (uint32_t y = 0; y < _heightMapData.height; y++)
@ -815,12 +814,12 @@ void mapgen_generate_from_heightmap(mapgen_settings * settings)
for (uint32_t x = 0; x < _heightMapData.width; x++)
{
// The x and y axis are flipped in the world, so this uses y for x and x for y.
rct_tile_element * const surfaceElement = map_get_surface_element_at(y + 1, x + 1);
rct_tile_element* const surfaceElement = map_get_surface_element_at(y + 1, x + 1);
// Read value from bitmap, and convert its range
uint8_t value = dest[x + y * _heightMapData.width];
value = (uint8_t) ((float) (value - minValue) / rangeIn * rangeOut) + settings->simplex_low;
surfaceElement->base_height = value;
value = (uint8_t)((float)(value - minValue) / rangeIn * rangeOut) + settings->simplex_low;
surfaceElement->base_height = value;
// Floor to even number
surfaceElement->base_height /= 2;

View File

@ -26,19 +26,19 @@ struct mapgen_settings
// Simplex Noise Parameters
int32_t simplex_low;
int32_t simplex_high;
float simplex_base_freq;
float simplex_base_freq;
int32_t simplex_octaves;
// Height map settings
bool smooth;
bool smooth_height_map;
bool smooth;
bool smooth_height_map;
uint32_t smooth_strength;
bool normalize_height;
bool normalize_height;
};
void mapgen_generate_blank(mapgen_settings * settings);
void mapgen_generate(mapgen_settings * settings);
void mapgen_generate_custom_simplex(mapgen_settings * settings);
bool mapgen_load_heightmap(const utf8 * path);
void mapgen_generate_blank(mapgen_settings* settings);
void mapgen_generate(mapgen_settings* settings);
void mapgen_generate_custom_simplex(mapgen_settings* settings);
bool mapgen_load_heightmap(const utf8* path);
void mapgen_unload_heightmap();
void mapgen_generate_from_heightmap(mapgen_settings * settings);
void mapgen_generate_from_heightmap(mapgen_settings* settings);

View File

@ -7,12 +7,14 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include <algorithm>
#include "MapHelpers.h"
#include "../core/Math.hpp"
#include "Map.h"
#include "MapHelpers.h"
#include "Surface.h"
#include <algorithm>
/**
* Not perfect, this still leaves some particular tiles unsmoothed.
*/
@ -21,8 +23,10 @@ int32_t map_smooth(int32_t l, int32_t t, int32_t r, int32_t b)
int32_t i, x, y, count, doubleCorner, raisedLand = 0;
uint8_t highest, cornerHeights[4];
rct_tile_element *tileElement, *tileElement2;
for (y = t; y < b; y++) {
for (x = l; x < r; x++) {
for (y = t; y < b; y++)
{
for (x = l; x < r; x++)
{
tileElement = map_get_surface_element_at(x, y);
tileElement->properties.surface.slope &= ~TILE_ELEMENT_SURFACE_SLOPE_MASK;
@ -32,7 +36,8 @@ int32_t map_smooth(int32_t l, int32_t t, int32_t r, int32_t b)
highest = std::max(highest, map_get_surface_element_at(x + 1, y + 0)->base_height);
highest = std::max(highest, map_get_surface_element_at(x + 0, y - 1)->base_height);
highest = std::max(highest, map_get_surface_element_at(x + 0, y + 1)->base_height);
if (tileElement->base_height < highest - 2) {
if (tileElement->base_height < highest - 2)
{
raisedLand = 1;
tileElement->base_height = tileElement->clearance_height = highest - 2;
}
@ -47,50 +52,56 @@ int32_t map_smooth(int32_t l, int32_t t, int32_t r, int32_t b)
for (i = 0; i < 4; i++)
highest = std::max(highest, cornerHeights[i]);
if (highest >= tileElement->base_height + 4) {
if (highest >= tileElement->base_height + 4)
{
count = 0;
int32_t canCompensate = 1;
for (i = 0; i < 4; i++)
if (cornerHeights[i] == highest){
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.
int32_t highestOnLowestSide;
switch (i){
default:
case 0:
highestOnLowestSide = std::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 = std::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 = std::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 = std::max(
map_get_surface_element_at(x + 1, y)->base_height,
map_get_surface_element_at(x, y - 1)->base_height);
break;
switch (i)
{
default:
case 0:
highestOnLowestSide = std::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 = std::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 = std::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 = std::max(
map_get_surface_element_at(x + 1, y)->base_height,
map_get_surface_element_at(x, y - 1)->base_height);
break;
}
if (highestOnLowestSide > tileElement->base_height){
if (highestOnLowestSide > tileElement->base_height)
{
tileElement->base_height = tileElement->clearance_height = highestOnLowestSide;
raisedLand = 1;
canCompensate = 0;
}
}
if (count == 1 && canCompensate) {
if (tileElement->base_height < highest - 4) {
if (count == 1 && canCompensate)
{
if (tileElement->base_height < highest - 4)
{
tileElement->base_height = tileElement->clearance_height = highest - 4;
raisedLand = 1;
}
@ -102,31 +113,38 @@ int32_t map_smooth(int32_t l, int32_t t, int32_t r, int32_t b)
doubleCorner = 2;
else if (cornerHeights[3] == highest && cornerHeights[1] <= cornerHeights[3] - 4)
doubleCorner = 3;
} else {
if (tileElement->base_height < highest - 2) {
}
else
{
if (tileElement->base_height < highest - 2)
{
tileElement->base_height = tileElement->clearance_height = highest - 2;
raisedLand = 1;
}
}
}
if (doubleCorner != -1) {
if (doubleCorner != -1)
{
tileElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT;
switch (doubleCorner) {
case 0:
tileElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_N_CORNER_DN;
break;
case 1:
tileElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_W_CORNER_DN;
break;
case 2:
tileElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_S_CORNER_DN;
break;
case 3:
tileElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_E_CORNER_DN;
break;
switch (doubleCorner)
{
case 0:
tileElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_N_CORNER_DN;
break;
case 1:
tileElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_W_CORNER_DN;
break;
case 2:
tileElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_S_CORNER_DN;
break;
case 3:
tileElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_E_CORNER_DN;
break;
}
} else {
}
else
{
// Corners
tileElement2 = map_get_surface_element_at(x + 1, y + 1);
if (tileElement2->base_height > tileElement->base_height)
@ -181,7 +199,7 @@ int32_t map_smooth(int32_t l, int32_t t, int32_t r, int32_t b)
*/
int32_t tile_smooth(int32_t x, int32_t y)
{
rct_tile_element *const surfaceElement = map_get_surface_element_at(x, y);
rct_tile_element* const surfaceElement = map_get_surface_element_at(x, y);
// +-----+-----+-----+
// | W | NW | N |
@ -193,11 +211,12 @@ int32_t tile_smooth(int32_t x, int32_t y)
// | S | SE | E |
// | 7 | 6 | 5 |
// +-----+-----+-----+
union
{
int32_t baseheight[8];
struct {
struct
{
int32_t N;
int32_t NW;
int32_t W;
@ -219,8 +238,9 @@ int32_t tile_smooth(int32_t x, int32_t y)
continue;
// Get neighbour height. If the element is not valid (outside of map) assume the same height
rct_tile_element *neighbour_element = map_get_surface_element_at(x + x_offset, y + y_offset);
neighbourHeightOffset.baseheight[index] = neighbour_element ? neighbour_element->base_height : surfaceElement->base_height;
rct_tile_element* neighbour_element = map_get_surface_element_at(x + x_offset, y + y_offset);
neighbourHeightOffset.baseheight[index]
= neighbour_element ? neighbour_element->base_height : surfaceElement->base_height;
// Make the height relative to the current surface element
neighbourHeightOffset.baseheight[index] -= surfaceElement->base_height;
@ -230,10 +250,14 @@ int32_t tile_smooth(int32_t x, int32_t y)
}
// Count number from the three tiles that is currently higher
int8_t thresholdW = Math::Clamp(0, neighbourHeightOffset.SW, 1) + Math::Clamp(0, neighbourHeightOffset.W, 1) + Math::Clamp(0, neighbourHeightOffset.NW, 1);
int8_t thresholdN = Math::Clamp(0, neighbourHeightOffset.NW, 1) + Math::Clamp(0, neighbourHeightOffset.N, 1) + Math::Clamp(0, neighbourHeightOffset.NE, 1);
int8_t thresholdE = Math::Clamp(0, neighbourHeightOffset.NE, 1) + Math::Clamp(0, neighbourHeightOffset.E, 1) + Math::Clamp(0, neighbourHeightOffset.SE, 1);
int8_t thresholdS = Math::Clamp(0, neighbourHeightOffset.SE, 1) + Math::Clamp(0, neighbourHeightOffset.S, 1) + Math::Clamp(0, neighbourHeightOffset.SW, 1);
int8_t thresholdW = Math::Clamp(0, neighbourHeightOffset.SW, 1) + Math::Clamp(0, neighbourHeightOffset.W, 1)
+ Math::Clamp(0, neighbourHeightOffset.NW, 1);
int8_t thresholdN = Math::Clamp(0, neighbourHeightOffset.NW, 1) + Math::Clamp(0, neighbourHeightOffset.N, 1)
+ Math::Clamp(0, neighbourHeightOffset.NE, 1);
int8_t thresholdE = Math::Clamp(0, neighbourHeightOffset.NE, 1) + Math::Clamp(0, neighbourHeightOffset.E, 1)
+ Math::Clamp(0, neighbourHeightOffset.SE, 1);
int8_t thresholdS = Math::Clamp(0, neighbourHeightOffset.SE, 1) + Math::Clamp(0, neighbourHeightOffset.S, 1)
+ Math::Clamp(0, neighbourHeightOffset.SW, 1);
uint8_t slope = TILE_ELEMENT_SLOPE_FLAT;
slope |= (thresholdW >= 1) ? SLOPE_W_THRESHOLD_FLAGS : 0;
@ -242,10 +266,10 @@ int32_t tile_smooth(int32_t x, int32_t y)
slope |= (thresholdS >= 1) ? SLOPE_S_THRESHOLD_FLAGS : 0;
// Set diagonal when three corners (one corner down) have been raised, and the middle one can be raised one more
if ((slope == TILE_ELEMENT_SLOPE_W_CORNER_DN && neighbourHeightOffset.W >= 4) ||
(slope == TILE_ELEMENT_SLOPE_S_CORNER_DN && neighbourHeightOffset.S >= 4) ||
(slope == TILE_ELEMENT_SLOPE_E_CORNER_DN && neighbourHeightOffset.E >= 4) ||
(slope == TILE_ELEMENT_SLOPE_N_CORNER_DN && neighbourHeightOffset.N >= 4))
if ((slope == TILE_ELEMENT_SLOPE_W_CORNER_DN && neighbourHeightOffset.W >= 4)
|| (slope == TILE_ELEMENT_SLOPE_S_CORNER_DN && neighbourHeightOffset.S >= 4)
|| (slope == TILE_ELEMENT_SLOPE_E_CORNER_DN && neighbourHeightOffset.E >= 4)
|| (slope == TILE_ELEMENT_SLOPE_N_CORNER_DN && neighbourHeightOffset.N >= 4))
{
slope |= TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT;
}

View File

@ -12,7 +12,8 @@
#include "../common.h"
enum {
enum
{
SLOPE_S_THRESHOLD_FLAGS = (1 << 0),
SLOPE_W_THRESHOLD_FLAGS = (1 << 1),
SLOPE_N_THRESHOLD_FLAGS = (1 << 2),

View File

@ -7,20 +7,15 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "../OpenRCT2.h"
#include "../drawing/Drawing.h"
#include "../localisation/Localisation.h"
#include "../interface/Viewport.h"
#include "../interface/Window.h"
#include "../localisation/Localisation.h"
#include "Map.h"
#include "../OpenRCT2.h"
#include "Sprite.h"
static constexpr const LocationXY16 _moneyEffectMoveOffset[] = {
{1, -1},
{1, 1},
{-1, 1},
{-1, -1}
};
static constexpr const LocationXY16 _moneyEffectMoveOffset[] = { { 1, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 } };
/**
*
@ -31,20 +26,20 @@ void money_effect_create_at(money32 value, int32_t x, int32_t y, int32_t z, bool
if (value == MONEY(0, 00))
return;
rct_money_effect * moneyEffect = (rct_money_effect *) create_sprite(2);
rct_money_effect* moneyEffect = (rct_money_effect*)create_sprite(2);
if (moneyEffect == nullptr)
return;
moneyEffect->value = value;
moneyEffect->vertical = (vertical ? 1 : 0);
moneyEffect->sprite_width = 64;
moneyEffect->value = value;
moneyEffect->vertical = (vertical ? 1 : 0);
moneyEffect->sprite_width = 64;
moneyEffect->sprite_height_negative = 20;
moneyEffect->sprite_height_positive = 30;
moneyEffect->sprite_identifier = SPRITE_IDENTIFIER_MISC;
sprite_move(x, y, z, (rct_sprite *) moneyEffect);
moneyEffect->misc_identifier = SPRITE_MISC_MONEY_EFFECT;
moneyEffect->num_movements = 0;
moneyEffect->move_delay = 0;
sprite_move(x, y, z, (rct_sprite*)moneyEffect);
moneyEffect->misc_identifier = SPRITE_MISC_MONEY_EFFECT;
moneyEffect->num_movements = 0;
moneyEffect->move_delay = 0;
int16_t offsetX = 0;
if (!gOpenRCT2NoGraphics)
@ -54,7 +49,7 @@ void money_effect_create_at(money32 value, int32_t x, int32_t y, int32_t z, bool
char buffer[128];
format_string(buffer, 128, stringId, &value);
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
offsetX = -(gfx_get_string_width(buffer) / 2);
offsetX = -(gfx_get_string_width(buffer) / 2);
}
moneyEffect->offset_x = offsetX;
moneyEffect->wiggle = 0;
@ -66,27 +61,21 @@ void money_effect_create_at(money32 value, int32_t x, int32_t y, int32_t z, bool
*/
void money_effect_create(money32 value)
{
LocationXYZ16 mapPosition =
{
gCommandPosition.x,
gCommandPosition.y,
gCommandPosition.z
};
LocationXYZ16 mapPosition = { gCommandPosition.x, gCommandPosition.y, gCommandPosition.z };
if (mapPosition.x == LOCATION_NULL)
{
rct_window * mainWindow = window_get_main();
rct_window* mainWindow = window_get_main();
if (mainWindow == nullptr)
return;
rct_viewport * mainViewport = window_get_viewport(mainWindow);
rct_viewport* mainViewport = window_get_viewport(mainWindow);
screen_get_map_xy(
mainViewport->x + (mainViewport->width / 2),
mainViewport->y + (mainViewport->height / 2),
&mapPosition.x,
&mapPosition.y,
nullptr
);
nullptr);
if (mapPosition.x == LOCATION_NULL)
return;
@ -100,9 +89,9 @@ void money_effect_create(money32 value)
*
* rct2: 0x00673232
*/
void money_effect_update(rct_money_effect * moneyEffect)
void money_effect_update(rct_money_effect* moneyEffect)
{
invalidate_sprite_2((rct_sprite *) moneyEffect);
invalidate_sprite_2((rct_sprite*)moneyEffect);
moneyEffect->wiggle++;
if (moneyEffect->wiggle >= 22)
{
@ -127,7 +116,7 @@ void money_effect_update(rct_money_effect * moneyEffect)
y += _moneyEffectMoveOffset[get_current_rotation()].y;
x += _moneyEffectMoveOffset[get_current_rotation()].x;
sprite_move(x, y, z, (rct_sprite *) moneyEffect);
sprite_move(x, y, z, (rct_sprite*)moneyEffect);
moneyEffect->num_movements++;
if (moneyEffect->num_movements < 55)
@ -135,16 +124,16 @@ void money_effect_update(rct_money_effect * moneyEffect)
return;
}
sprite_remove((rct_sprite *) moneyEffect);
sprite_remove((rct_sprite*)moneyEffect);
}
rct_string_id money_effect_get_string_id(const rct_money_effect * sprite, money32 * outValue)
rct_string_id money_effect_get_string_id(const rct_money_effect* sprite, money32* outValue)
{
bool vertical = (sprite->vertical != 0);
rct_string_id spentStringId = vertical ? STR_MONEY_EFFECT_SPEND_HIGHP : STR_MONEY_EFFECT_SPEND;
bool vertical = (sprite->vertical != 0);
rct_string_id spentStringId = vertical ? STR_MONEY_EFFECT_SPEND_HIGHP : STR_MONEY_EFFECT_SPEND;
rct_string_id receiveStringId = vertical ? STR_MONEY_EFFECT_RECEIVE_HIGHP : STR_MONEY_EFFECT_RECEIVE;
rct_string_id stringId = receiveStringId;
money32 value = sprite->value;
rct_string_id stringId = receiveStringId;
money32 value = sprite->value;
if (value < 0)
{
value *= -1;

View File

@ -7,15 +7,18 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "Park.h"
#include "../Cheats.h"
#include "../Context.h"
#include "../Date.h"
#include "../Game.h"
#include "../GameState.h"
#include "../OpenRCT2.h"
#include "../config/Config.h"
#include "../core/Math.hpp"
#include "../core/Memory.hpp"
#include "../core/Util.hpp"
#include "../Date.h"
#include "../Game.h"
#include "../GameState.h"
#include "../interface/Colour.h"
#include "../interface/Window.h"
#include "../localisation/Localisation.h"
@ -25,7 +28,6 @@
#include "../management/NewsItem.h"
#include "../management/Research.h"
#include "../network/network.h"
#include "../OpenRCT2.h"
#include "../peep/Peep.h"
#include "../peep/Staff.h"
#include "../ride/Ride.h"
@ -35,7 +37,6 @@
#include "../windows/Intent.h"
#include "Entrance.h"
#include "Map.h"
#include "Park.h"
#include "Sprite.h"
#include "Surface.h"
@ -84,7 +85,8 @@ void reset_park_entry()
{
gParkName = 0;
reset_park_entrance();
for (int32_t i = 0; i < MAX_PEEP_SPAWNS; i++) {
for (int32_t i = 0; i < MAX_PEEP_SPAWNS; i++)
{
gPeepSpawns[i].x = PEEP_SPAWN_UNDEFINED;
}
}
@ -96,10 +98,12 @@ static uint32_t get_random_peep_spawn_index()
{
uint32_t spawnIndexList[MAX_PEEP_SPAWNS];
uint32_t numSpawns = map_get_available_peep_spawn_index_list(spawnIndexList);
if (numSpawns > 0) {
if (numSpawns > 0)
{
return spawnIndexList[scenario_rand() % numSpawns];
}
else {
else
{
return 0;
}
}
@ -114,15 +118,16 @@ void park_set_open(int32_t open)
* rct2: 0x00669D4A
*/
void game_command_set_park_open(
[[maybe_unused]] int32_t * eax,
int32_t * ebx,
[[maybe_unused]] int32_t * ecx,
int32_t * edx,
[[maybe_unused]] int32_t * esi,
int32_t * edi,
[[maybe_unused]] int32_t * ebp)
[[maybe_unused]] int32_t* eax,
int32_t* ebx,
[[maybe_unused]] int32_t* ecx,
int32_t* edx,
[[maybe_unused]] int32_t* esi,
int32_t* edi,
[[maybe_unused]] int32_t* ebp)
{
if (!(*ebx & GAME_COMMAND_FLAG_APPLY)) {
if (!(*ebx & GAME_COMMAND_FLAG_APPLY))
{
*ebx = 0;
return;
}
@ -130,36 +135,39 @@ void game_command_set_park_open(
int32_t dh = (*edx >> 8) & 0xFF;
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_PARK_ENTRANCE_TICKETS;
switch (dh) {
case 0:
if (gParkFlags & PARK_FLAGS_PARK_OPEN) {
gParkFlags &= ~PARK_FLAGS_PARK_OPEN;
window_invalidate_by_class(WC_PARK_INFORMATION);
}
break;
case 1:
if (!(gParkFlags & PARK_FLAGS_PARK_OPEN)) {
gParkFlags |= PARK_FLAGS_PARK_OPEN;
window_invalidate_by_class(WC_PARK_INFORMATION);
}
break;
case 2:
gSamePriceThroughoutParkA = *edi;
window_invalidate_by_class(WC_RIDE);
break;
case 3:
gSamePriceThroughoutParkB = *edi;
window_invalidate_by_class(WC_RIDE);
break;
switch (dh)
{
case 0:
if (gParkFlags & PARK_FLAGS_PARK_OPEN)
{
gParkFlags &= ~PARK_FLAGS_PARK_OPEN;
window_invalidate_by_class(WC_PARK_INFORMATION);
}
break;
case 1:
if (!(gParkFlags & PARK_FLAGS_PARK_OPEN))
{
gParkFlags |= PARK_FLAGS_PARK_OPEN;
window_invalidate_by_class(WC_PARK_INFORMATION);
}
break;
case 2:
gSamePriceThroughoutParkA = *edi;
window_invalidate_by_class(WC_RIDE);
break;
case 3:
gSamePriceThroughoutParkB = *edi;
window_invalidate_by_class(WC_RIDE);
break;
}
*ebx = 0;
}
/**
*
* rct2: 0x00664D05
*/
*
* rct2: 0x00664D05
*/
void update_park_fences(const CoordsXY coords)
{
if (map_is_edge(coords))
@ -170,41 +178,49 @@ void update_park_fences(const CoordsXY coords)
return;
uint8_t newOwnership = surfaceElement->properties.surface.ownership & 0xF0;
if ((surfaceElement->properties.surface.ownership & OWNERSHIP_OWNED) == 0) {
if ((surfaceElement->properties.surface.ownership & OWNERSHIP_OWNED) == 0)
{
bool fenceRequired = true;
rct_tile_element* tileElement = map_get_first_element_at(coords.x / 32, coords.y / 32);
// If an entrance element do not place flags around surface
do {
do
{
if (tileElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE)
continue;
if (tileElement->properties.entrance.type != ENTRANCE_TYPE_PARK_ENTRANCE)
continue;
if (!(tileElement->flags & TILE_ELEMENT_FLAG_GHOST)) {
if (!(tileElement->flags & TILE_ELEMENT_FLAG_GHOST))
{
fenceRequired = false;
break;
}
} while (!(tileElement++)->IsLastForTile());
if (fenceRequired) {
if (fenceRequired)
{
// As map_is_location_in_park sets the error text
// will require to back it up.
rct_string_id previous_error = gGameCommandErrorText;
if (map_is_location_in_park({coords.x - 32, coords.y})){
if (map_is_location_in_park({ coords.x - 32, coords.y }))
{
newOwnership |= 0x8;
}
if (map_is_location_in_park({coords.x, coords.y - 32})){
if (map_is_location_in_park({ coords.x, coords.y - 32 }))
{
newOwnership |= 0x4;
}
if (map_is_location_in_park({coords.x + 32, coords.y})){
if (map_is_location_in_park({ coords.x + 32, coords.y }))
{
newOwnership |= 0x2;
}
if (map_is_location_in_park({coords.x, coords.y + 32})){
if (map_is_location_in_park({ coords.x, coords.y + 32 }))
{
newOwnership |= 0x1;
}
@ -212,7 +228,8 @@ void update_park_fences(const CoordsXY coords)
}
}
if (surfaceElement->properties.surface.ownership != newOwnership) {
if (surfaceElement->properties.surface.ownership != newOwnership)
{
int32_t z0 = surfaceElement->base_height * 8;
int32_t z1 = z0 + 16;
map_invalidate_tile(coords.x, coords.y, z0, z1);
@ -223,13 +240,13 @@ void update_park_fences(const CoordsXY coords)
void update_park_fences_around_tile(const CoordsXY coords)
{
update_park_fences(coords);
update_park_fences({coords.x + 32, coords.y});
update_park_fences({coords.x - 32, coords.y});
update_park_fences({coords.x, coords.y + 32});
update_park_fences({coords.x, coords.y - 32});
update_park_fences({ coords.x + 32, coords.y });
update_park_fences({ coords.x - 32, coords.y });
update_park_fences({ coords.x, coords.y + 32 });
update_park_fences({ coords.x, coords.y - 32 });
}
void park_set_name(const char *name)
void park_set_name(const char* name)
{
auto nameId = user_string_allocate(USER_STRING_HIGH_ID_NUMBER, name);
if (nameId != 0)
@ -239,116 +256,141 @@ void park_set_name(const char *name)
}
}
static money32 map_buy_land_rights_for_tile(int32_t x, int32_t y, int32_t setting, int32_t flags) {
rct_tile_element* surfaceElement = map_get_surface_element_at({x, y});
static money32 map_buy_land_rights_for_tile(int32_t x, int32_t y, int32_t setting, int32_t flags)
{
rct_tile_element* surfaceElement = map_get_surface_element_at({ x, y });
if (surfaceElement == nullptr)
return MONEY32_UNDEFINED;
switch (setting) {
case BUY_LAND_RIGHTS_FLAG_BUY_LAND: // 0
if ((surfaceElement->properties.surface.ownership & OWNERSHIP_OWNED) != 0) { // If the land is already owned
switch (setting)
{
case BUY_LAND_RIGHTS_FLAG_BUY_LAND: // 0
if ((surfaceElement->properties.surface.ownership & OWNERSHIP_OWNED) != 0)
{ // If the land is already owned
return 0;
}
if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0
|| (surfaceElement->properties.surface.ownership & OWNERSHIP_AVAILABLE) == 0)
{
gGameCommandErrorText = STR_LAND_NOT_FOR_SALE;
return MONEY32_UNDEFINED;
}
if (flags & GAME_COMMAND_FLAG_APPLY)
{
surfaceElement->properties.surface.ownership |= OWNERSHIP_OWNED;
update_park_fences_around_tile({ x, y });
}
return gLandPrice;
case BUY_LAND_RIGHTS_FLAG_UNOWN_TILE: // 1
if (flags & GAME_COMMAND_FLAG_APPLY)
{
surfaceElement->properties.surface.ownership &= ~(OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED);
update_park_fences_around_tile({ x, y });
}
return 0;
}
case BUY_LAND_RIGHTS_FLAG_BUY_CONSTRUCTION_RIGHTS: // 2
if ((surfaceElement->properties.surface.ownership & (OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)) != 0)
{ // If the land or construction rights are already owned
return 0;
}
if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || (surfaceElement->properties.surface.ownership & OWNERSHIP_AVAILABLE) == 0) {
gGameCommandErrorText = STR_LAND_NOT_FOR_SALE;
return MONEY32_UNDEFINED;
}
if (flags & GAME_COMMAND_FLAG_APPLY) {
surfaceElement->properties.surface.ownership |= OWNERSHIP_OWNED;
update_park_fences_around_tile({x, y});
}
return gLandPrice;
case BUY_LAND_RIGHTS_FLAG_UNOWN_TILE: // 1
if (flags & GAME_COMMAND_FLAG_APPLY) {
surfaceElement->properties.surface.ownership &= ~(OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED);
update_park_fences_around_tile({x, y});
}
return 0;
case BUY_LAND_RIGHTS_FLAG_BUY_CONSTRUCTION_RIGHTS: // 2
if ((surfaceElement->properties.surface.ownership & (OWNERSHIP_OWNED | OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED)) != 0) { // If the land or construction rights are already owned
return 0;
}
if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || (surfaceElement->properties.surface.ownership & OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) == 0) {
gGameCommandErrorText = STR_CONSTRUCTION_RIGHTS_NOT_FOR_SALE;
return MONEY32_UNDEFINED;
}
if (flags & GAME_COMMAND_FLAG_APPLY) {
surfaceElement->properties.surface.ownership |= OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED;
uint16_t baseHeight = surfaceElement->base_height * 8;
map_invalidate_tile(x, y, baseHeight, baseHeight + 16);
}
return gConstructionRightsPrice;
case BUY_LAND_RIGHTS_FLAG_UNOWN_CONSTRUCTION_RIGHTS: // 3
if (flags & GAME_COMMAND_FLAG_APPLY) {
surfaceElement->properties.surface.ownership &= ~OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED;
uint16_t baseHeight = surfaceElement->base_height * 8;
map_invalidate_tile(x, y, baseHeight, baseHeight + 16);
}
return 0;
case BUY_LAND_RIGHTS_FLAG_SET_FOR_SALE: // 4
if (flags & GAME_COMMAND_FLAG_APPLY) {
surfaceElement->properties.surface.ownership |= OWNERSHIP_AVAILABLE;
uint16_t baseHeight = surfaceElement->base_height * 8;
map_invalidate_tile(x, y, baseHeight, baseHeight + 16);
}
return 0;
case BUY_LAND_RIGHTS_FLAG_SET_CONSTRUCTION_RIGHTS_FOR_SALE: // 5
if (flags & GAME_COMMAND_FLAG_APPLY) {
surfaceElement->properties.surface.ownership |= OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE;
uint16_t baseHeight = surfaceElement->base_height * 8;
map_invalidate_tile(x, y, baseHeight, baseHeight + 16);
}
return 0;
case BUY_LAND_RIGHTS_FLAG_SET_OWNERSHIP_WITH_CHECKS:
{
if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode) {
if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0
|| (surfaceElement->properties.surface.ownership & OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) == 0)
{
gGameCommandErrorText = STR_CONSTRUCTION_RIGHTS_NOT_FOR_SALE;
return MONEY32_UNDEFINED;
}
if (x <= 0 || y <= 0) {
if (flags & GAME_COMMAND_FLAG_APPLY)
{
surfaceElement->properties.surface.ownership |= OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED;
uint16_t baseHeight = surfaceElement->base_height * 8;
map_invalidate_tile(x, y, baseHeight, baseHeight + 16);
}
return gConstructionRightsPrice;
case BUY_LAND_RIGHTS_FLAG_UNOWN_CONSTRUCTION_RIGHTS: // 3
if (flags & GAME_COMMAND_FLAG_APPLY)
{
surfaceElement->properties.surface.ownership &= ~OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED;
uint16_t baseHeight = surfaceElement->base_height * 8;
map_invalidate_tile(x, y, baseHeight, baseHeight + 16);
}
return 0;
case BUY_LAND_RIGHTS_FLAG_SET_FOR_SALE: // 4
if (flags & GAME_COMMAND_FLAG_APPLY)
{
surfaceElement->properties.surface.ownership |= OWNERSHIP_AVAILABLE;
uint16_t baseHeight = surfaceElement->base_height * 8;
map_invalidate_tile(x, y, baseHeight, baseHeight + 16);
}
return 0;
case BUY_LAND_RIGHTS_FLAG_SET_CONSTRUCTION_RIGHTS_FOR_SALE: // 5
if (flags & GAME_COMMAND_FLAG_APPLY)
{
surfaceElement->properties.surface.ownership |= OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE;
uint16_t baseHeight = surfaceElement->base_height * 8;
map_invalidate_tile(x, y, baseHeight, baseHeight + 16);
}
return 0;
case BUY_LAND_RIGHTS_FLAG_SET_OWNERSHIP_WITH_CHECKS:
{
if (!(gScreenFlags & SCREEN_FLAGS_EDITOR) && !gCheatsSandboxMode)
{
return MONEY32_UNDEFINED;
}
if (x <= 0 || y <= 0)
{
gGameCommandErrorText = STR_TOO_CLOSE_TO_EDGE_OF_MAP;
return MONEY32_UNDEFINED;
}
if (x >= gMapSizeUnits || y >= gMapSizeUnits) {
if (x >= gMapSizeUnits || y >= gMapSizeUnits)
{
gGameCommandErrorText = STR_TOO_CLOSE_TO_EDGE_OF_MAP;
return MONEY32_UNDEFINED;
}
uint8_t newOwnership = (flags & 0xFF00) >> 4;
if (newOwnership == (surfaceElement->properties.surface.ownership & 0xF0)) {
if (newOwnership == (surfaceElement->properties.surface.ownership & 0xF0))
{
return 0;
}
rct_tile_element* tileElement = map_get_first_element_at(x / 32, y / 32);
do {
if (tileElement->GetType() == TILE_ELEMENT_TYPE_ENTRANCE) {
do
{
if (tileElement->GetType() == TILE_ELEMENT_TYPE_ENTRANCE)
{
// Do not allow ownership of park entrance.
if (newOwnership == OWNERSHIP_OWNED || newOwnership == OWNERSHIP_AVAILABLE)
return 0;
// Allow construction rights available / for sale on park entrances on surface.
// There is no need to check the height if newOwnership is 0 (unowned and no rights available).
if ((newOwnership == OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED ||
newOwnership == OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE) &&
(tileElement->base_height - 3 > surfaceElement->base_height ||
tileElement->base_height < surfaceElement->base_height))
if ((newOwnership == OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED
|| newOwnership == OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE)
&& (tileElement->base_height - 3 > surfaceElement->base_height
|| tileElement->base_height < surfaceElement->base_height))
return 0;
}
} while (!(tileElement++)->IsLastForTile());
if (!(flags & GAME_COMMAND_FLAG_APPLY)) {
if (!(flags & GAME_COMMAND_FLAG_APPLY))
{
return gLandPrice;
}
if ((newOwnership & 0xF0) != 0) {
PeepSpawn *peepSpawns = gPeepSpawns;
if ((newOwnership & 0xF0) != 0)
{
PeepSpawn* peepSpawns = gPeepSpawns;
for (uint8_t i = 0; i < MAX_PEEP_SPAWNS; ++i) {
if (x == (peepSpawns[i].x & 0xFFE0)) {
if (y == (peepSpawns[i].y & 0xFFE0)) {
for (uint8_t i = 0; i < MAX_PEEP_SPAWNS; ++i)
{
if (x == (peepSpawns[i].x & 0xFFE0))
{
if (y == (peepSpawns[i].y & 0xFFE0))
{
peepSpawns[i].x = PEEP_SPAWN_UNDEFINED;
}
}
@ -356,14 +398,14 @@ static money32 map_buy_land_rights_for_tile(int32_t x, int32_t y, int32_t settin
}
surfaceElement->properties.surface.ownership &= 0x0F;
surfaceElement->properties.surface.ownership |= newOwnership;
update_park_fences_around_tile({x, y});
update_park_fences_around_tile({ x, y });
gMapLandRightsUpdateSuccess = true;
return 0;
}
default:
log_warning("Tried calling map_buy_land_rights_for_tile() with an incorrect setting!");
assert(false);
return MONEY32_UNDEFINED;
default:
log_warning("Tried calling map_buy_land_rights_for_tile() with an incorrect setting!");
assert(false);
return MONEY32_UNDEFINED;
}
}
@ -373,7 +415,8 @@ int32_t map_buy_land_rights(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int3
money32 totalCost, cost;
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LAND_PURCHASE;
if (x1 == 0 && y1 == 0) {
if (x1 == 0 && y1 == 0)
{
x1 = x0;
y1 = y0;
}
@ -388,9 +431,12 @@ int32_t map_buy_land_rights(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int3
// Game command modified to accept selection size
totalCost = 0;
gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED;
if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || game_is_not_paused() || gCheatsBuildInPauseMode) {
for (y = y0; y <= y1; y += 32) {
for (x = x0; x <= x1; x += 32) {
if ((gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) != 0 || game_is_not_paused() || gCheatsBuildInPauseMode)
{
for (y = y0; y <= y1; y += 32)
{
for (x = x0; x <= x1; x += 32)
{
cost = map_buy_land_rights_for_tile(x, y, setting, flags);
if (cost != MONEY32_UNDEFINED)
{
@ -404,27 +450,21 @@ int32_t map_buy_land_rights(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int3
}
/**
*
* rct2: 0x006649BD
*/
*
* rct2: 0x006649BD
*/
void game_command_buy_land_rights(
int32_t * eax, int32_t * ebx, int32_t * ecx, int32_t * edx, [[maybe_unused]] int32_t * esi, int32_t * edi, int32_t * ebp)
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, int32_t* edi, int32_t* ebp)
{
int32_t flags = *ebx & 0xFFFF;
*ebx = map_buy_land_rights(
(*eax & 0xFFFF),
(*ecx & 0xFFFF),
(*edi & 0xFFFF),
(*ebp & 0xFFFF),
(*edx & 0x00FF),
flags
);
*ebx = map_buy_land_rights((*eax & 0xFFFF), (*ecx & 0xFFFF), (*edi & 0xFFFF), (*ebp & 0xFFFF), (*edx & 0x00FF), flags);
// Too expensive to always call in map_buy_land_rights.
// It's already counted when the park is loaded, after
// that it should only be called for user actions.
if (flags & GAME_COMMAND_FLAG_APPLY) {
if (flags & GAME_COMMAND_FLAG_APPLY)
{
map_count_remaining_land_rights();
}
}
@ -532,30 +572,25 @@ void Park::Initialise()
gParkEntranceFee = MONEY(10, 00);
for (auto &peepSpawn : gPeepSpawns)
for (auto& peepSpawn : gPeepSpawns)
{
peepSpawn.x = PEEP_SPAWN_UNDEFINED;
}
gResearchPriorities =
(1 << RESEARCH_CATEGORY_TRANSPORT) |
(1 << RESEARCH_CATEGORY_GENTLE) |
(1 << RESEARCH_CATEGORY_ROLLERCOASTER) |
(1 << RESEARCH_CATEGORY_THRILL) |
(1 << RESEARCH_CATEGORY_WATER) |
(1 << RESEARCH_CATEGORY_SHOP) |
(1 << RESEARCH_CATEGORY_SCENERY_GROUP);
gResearchPriorities = (1 << RESEARCH_CATEGORY_TRANSPORT) | (1 << RESEARCH_CATEGORY_GENTLE)
| (1 << RESEARCH_CATEGORY_ROLLERCOASTER) | (1 << RESEARCH_CATEGORY_THRILL) | (1 << RESEARCH_CATEGORY_WATER)
| (1 << RESEARCH_CATEGORY_SHOP) | (1 << RESEARCH_CATEGORY_SCENERY_GROUP);
gResearchFundingLevel = RESEARCH_FUNDING_NORMAL;
gGuestInitialCash = MONEY(50,00);
gGuestInitialCash = MONEY(50, 00);
gGuestInitialHappiness = CalculateGuestInitialHappiness(50);
gGuestInitialHunger = 200;
gGuestInitialThirst = 200;
gScenarioObjectiveType = OBJECTIVE_GUESTS_BY;
gScenarioObjectiveYear = 4;
gScenarioObjectiveNumGuests = 1000;
gLandPrice = MONEY(90,00);
gConstructionRightsPrice = MONEY(40,00);
gLandPrice = MONEY(90, 00);
gConstructionRightsPrice = MONEY(40, 00);
gParkFlags = PARK_FLAGS_NO_MONEY | PARK_FLAGS_SHOW_REAL_GUEST_NAMES;
ResetHistories();
finance_reset_history();
@ -565,7 +600,7 @@ void Park::Initialise()
format_string(gS6Info.details, 256, STR_NO_DETAILS_YET, nullptr);
}
void Park::Update(const Date &date)
void Park::Update(const Date& date)
{
// Every ~13 seconds
if (gCurrentTicks % 512 == 0)
@ -602,7 +637,8 @@ int32_t Park::CalculateParkSize() const
tiles = 0;
tile_element_iterator_begin(&it);
do {
do
{
if (it.element->GetType() == TILE_ELEMENT_TYPE_SURFACE)
{
if (it.element->properties.surface.ownership & (OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED | OWNERSHIP_OWNED))
@ -612,7 +648,8 @@ int32_t Park::CalculateParkSize() const
}
} while (tile_element_iterator_next(&it));
if (tiles != gParkSize) {
if (tiles != gParkSize)
{
gParkSize = tiles;
window_invalidate_by_class(WC_PARK_INFORMATION);
}
@ -642,8 +679,8 @@ int32_t Park::CalculateParkRating() const
int32_t happyGuestCount = 0;
int32_t lostGuestCount = 0;
uint16_t spriteIndex;
rct_peep * peep;
FOR_ALL_GUESTS(spriteIndex, peep)
rct_peep* peep;
FOR_ALL_GUESTS (spriteIndex, peep)
{
if (peep->outside_of_park == 0)
{
@ -651,8 +688,7 @@ int32_t Park::CalculateParkRating() const
{
happyGuestCount++;
}
if ((peep->peep_flags & PEEP_FLAGS_LEAVING_PARK) &&
(peep->peep_is_lost_countdown < 90))
if ((peep->peep_flags & PEEP_FLAGS_LEAVING_PARK) && (peep->peep_is_lost_countdown < 90))
{
lostGuestCount++;
}
@ -682,8 +718,8 @@ int32_t Park::CalculateParkRating() const
int32_t totalRideExcitement = 0;
int32_t i;
Ride * ride;
FOR_ALL_RIDES(i, ride)
Ride* ride;
FOR_ALL_RIDES (i, ride)
{
totalRideUptime += 100 - ride->downtime;
if (ride->excitement != RIDE_RATING_UNDEFINED)
@ -729,9 +765,10 @@ int32_t Park::CalculateParkRating() const
// Litter
{
rct_litter * litter;
rct_litter* litter;
int32_t litterCount = 0;
for (uint16_t spriteIndex = gSpriteListHead[SPRITE_LIST_LITTER]; spriteIndex != SPRITE_INDEX_NULL; spriteIndex = litter->next)
for (uint16_t spriteIndex = gSpriteListHead[SPRITE_LIST_LITTER]; spriteIndex != SPRITE_INDEX_NULL;
spriteIndex = litter->next)
{
litter = &(get_sprite(spriteIndex)->litter);
@ -766,11 +803,10 @@ money32 Park::CalculateParkValue() const
return result;
}
money32 Park::CalculateRideValue(const Ride * ride) const
money32 Park::CalculateRideValue(const Ride* ride) const
{
money32 result = 0;
if (ride->type != RIDE_TYPE_NULL &&
ride->value != RIDE_VALUE_UNDEFINED)
if (ride->type != RIDE_TYPE_NULL && ride->value != RIDE_VALUE_UNDEFINED)
{
result = (ride->value * 10) * (ride_customers_in_last_5_minutes(ride) + rideBonusValue[ride->type] * 4);
}
@ -786,12 +822,15 @@ money16 Park::CalculateTotalRideValueForMoney() const
{
money16 totalRideValue = 0;
int32_t i;
Ride * ride;
FOR_ALL_RIDES(i, ride)
Ride* ride;
FOR_ALL_RIDES (i, ride)
{
if (ride->status != RIDE_STATUS_OPEN) continue;
if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) continue;
if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) continue;
if (ride->status != RIDE_STATUS_OPEN)
continue;
if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)
continue;
if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED)
continue;
// Add ride value
if (ride->value != RIDE_VALUE_UNDEFINED)
@ -812,12 +851,15 @@ uint32_t Park::CalculateSuggestedMaxGuests() const
// TODO combine the two ride loops
int32_t i;
Ride * ride;
FOR_ALL_RIDES(i, ride)
Ride* ride;
FOR_ALL_RIDES (i, ride)
{
if (ride->status != RIDE_STATUS_OPEN) continue;
if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) continue;
if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) continue;
if (ride->status != RIDE_STATUS_OPEN)
continue;
if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)
continue;
if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED)
continue;
// Add guest score for ride type
suggestedMaxGuests += rideBonusValue[ride->type];
@ -827,15 +869,22 @@ uint32_t Park::CalculateSuggestedMaxGuests() const
if (gParkFlags & PARK_FLAGS_DIFFICULT_GUEST_GENERATION)
{
suggestedMaxGuests = std::min<uint32_t>(suggestedMaxGuests, 1000);
FOR_ALL_RIDES(i, ride)
FOR_ALL_RIDES (i, ride)
{
if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED) continue;
if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN) continue;
if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)) continue;
if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK)) continue;
if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_DATA_LOGGING)) continue;
if (ride->length[0] < (600 << 16)) continue;
if (ride->excitement < RIDE_RATING(6, 00)) continue;
if (ride->lifecycle_flags & RIDE_LIFECYCLE_CRASHED)
continue;
if (ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)
continue;
if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED))
continue;
if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_TRACK))
continue;
if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_HAS_DATA_LOGGING))
continue;
if (ride->length[0] < (600 << 16))
continue;
if (ride->excitement < RIDE_RATING(6, 00))
continue;
// Bonus guests for good ride
suggestedMaxGuests += rideBonusValue[ride->type] * 2;
@ -947,7 +996,7 @@ void Park::GenerateGuests()
}
}
rct_peep * Park::GenerateGuestFromCampaign(int32_t campaign)
rct_peep* Park::GenerateGuestFromCampaign(int32_t campaign)
{
auto peep = GenerateGuest();
if (peep != nullptr)
@ -957,9 +1006,9 @@ rct_peep * Park::GenerateGuestFromCampaign(int32_t campaign)
return peep;
}
rct_peep * Park::GenerateGuest()
rct_peep* Park::GenerateGuest()
{
rct_peep * peep = nullptr;
rct_peep* peep = nullptr;
PeepSpawn spawn = gPeepSpawns[get_random_peep_spawn_index()];
if (spawn.x != PEEP_SPAWN_UNDEFINED)
@ -983,8 +1032,7 @@ rct_peep * Park::GenerateGuest()
return peep;
}
template<typename T, size_t TSize>
static void HistoryPushRecord(T history[TSize], T newItem)
template<typename T, size_t TSize> static void HistoryPushRecord(T history[TSize], T newItem)
{
for (size_t i = TSize - 1; i > 0; i--)
{

View File

@ -16,7 +16,7 @@
#define DECRYPT_MONEY(money) ((money32)rol32((money) ^ 0xF4EC9621, 13))
#define ENCRYPT_MONEY(money) ((money32)(ror32((money), 13) ^ 0xF4EC9621))
#define MAX_ENTRANCE_FEE MONEY(200,00)
#define MAX_ENTRANCE_FEE MONEY(200, 00)
struct rct_peep;
@ -37,10 +37,10 @@ enum : uint32_t
PARK_FLAGS_PARK_FREE_ENTRY = (1 << 13),
PARK_FLAGS_DIFFICULT_PARK_RATING = (1 << 14),
PARK_FLAGS_LOCK_REAL_NAMES_OPTION_DEPRECATED = (1 << 15), // Deprecated now we use a persistent 'real names' setting
PARK_FLAGS_NO_MONEY_SCENARIO = (1 << 17), // equivalent to PARK_FLAGS_NO_MONEY, but used in scenario editor
PARK_FLAGS_SPRITES_INITIALISED = (1 << 18), // After a scenario is loaded this prevents edits in the scenario editor
PARK_FLAGS_NO_MONEY_SCENARIO = (1 << 17), // equivalent to PARK_FLAGS_NO_MONEY, but used in scenario editor
PARK_FLAGS_SPRITES_INITIALISED = (1 << 18), // After a scenario is loaded this prevents edits in the scenario editor
PARK_FLAGS_SIX_FLAGS_DEPRECATED = (1 << 19), // Not used anymore
PARK_FLAGS_UNLOCK_ALL_PRICES = (1u << 31), // OpenRCT2 only!
PARK_FLAGS_UNLOCK_ALL_PRICES = (1u << 31), // OpenRCT2 only!
};
struct rct_peep;
@ -58,35 +58,34 @@ namespace OpenRCT2
bool IsOpen() const;
uint16_t GetParkRating() const;
uint16_t GetParkRating() const;
money32 GetParkValue() const;
money32 GetCompanyValue() const;
void Initialise();
void Update(const Date &date);
void Update(const Date& date);
int32_t CalculateParkSize() const;
int32_t CalculateParkRating() const;
money32 CalculateParkValue() const;
money32 CalculateCompanyValue() const;
static uint8_t CalculateGuestInitialHappiness(uint8_t percentage);
int32_t CalculateParkSize() const;
int32_t CalculateParkRating() const;
money32 CalculateParkValue() const;
money32 CalculateCompanyValue() const;
static uint8_t CalculateGuestInitialHappiness(uint8_t percentage);
rct_peep * GenerateGuest();
rct_peep* GenerateGuest();
void ResetHistories();
void UpdateHistories();
private:
money32 CalculateRideValue(const Ride * ride) const;
money16 CalculateTotalRideValueForMoney() const;
uint32_t CalculateSuggestedMaxGuests() const;
uint32_t CalculateGuestGenerationProbability() const;
void GenerateGuests();
rct_peep * GenerateGuestFromCampaign(int32_t campaign);
money32 CalculateRideValue(const Ride* ride) const;
money16 CalculateTotalRideValueForMoney() const;
uint32_t CalculateSuggestedMaxGuests() const;
uint32_t CalculateGuestGenerationProbability() const;
void GenerateGuests();
rct_peep* GenerateGuestFromCampaign(int32_t campaign);
};
}
} // namespace OpenRCT2
enum
{
@ -135,14 +134,17 @@ uint8_t calculate_guest_initial_happiness(uint8_t percentage);
void park_set_open(int32_t open);
int32_t park_entrance_get_index(int32_t x, int32_t y, int32_t z);
void park_set_name(const char *name);
void park_set_name(const char* name);
void park_set_entrance_fee(money32 value);
int32_t map_buy_land_rights(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t setting, int32_t flags);
void game_command_set_park_entrance_fee(int32_t *eax, int32_t *ebx, int32_t *ecx, int32_t *edx, int32_t *esi, int32_t *edi, int32_t *ebp);
void game_command_set_park_open(int32_t *eax, int32_t *ebx, int32_t *ecx, int32_t *edx, int32_t *esi, int32_t *edi, int32_t *ebp);
void game_command_buy_land_rights(int32_t *eax, int32_t *ebx, int32_t *ecx, int32_t *edx, int32_t *esi, int32_t *edi, int32_t *ebp);
void game_command_set_park_entrance_fee(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_set_park_open(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void game_command_buy_land_rights(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
money16 park_get_entrance_fee();

View File

@ -9,8 +9,8 @@
#include "../audio/audio.h"
#include "../core/Util.hpp"
#include "../scenario/Scenario.h"
#include "../paint/sprite/Paint.Sprite.h"
#include "../scenario/Scenario.h"
#include "Sprite.h"
/**
@ -19,27 +19,27 @@
*/
void crashed_vehicle_particle_create(rct_vehicle_colour colours, int32_t x, int32_t y, int32_t z)
{
rct_crashed_vehicle_particle * sprite = (rct_crashed_vehicle_particle *) create_sprite(2);
rct_crashed_vehicle_particle* sprite = (rct_crashed_vehicle_particle*)create_sprite(2);
if (sprite != nullptr)
{
sprite->colour[0] = colours.body_colour;
sprite->colour[1] = colours.trim_colour;
sprite->sprite_width = 8;
sprite->sprite_width = 8;
sprite->sprite_height_negative = 8;
sprite->sprite_height_positive = 8;
sprite->sprite_identifier = SPRITE_IDENTIFIER_MISC;
sprite_move(x, y, z, (rct_sprite *) sprite);
sprite->sprite_identifier = SPRITE_IDENTIFIER_MISC;
sprite_move(x, y, z, (rct_sprite*)sprite);
sprite->misc_identifier = SPRITE_MISC_CRASHED_VEHICLE_PARTICLE;
sprite->frame = (scenario_rand() & 0xFF) * 12;
sprite->time_to_live = (scenario_rand() & 0x7F) + 140;
sprite->frame = (scenario_rand() & 0xFF) * 12;
sprite->time_to_live = (scenario_rand() & 0x7F) + 140;
sprite->crashed_sprite_base = scenario_rand_max((uint32_t)Util::CountOf(vehicle_particle_base_sprites));
sprite->acceleration_x = ((int16_t) (scenario_rand() & 0xFFFF)) * 4;
sprite->acceleration_y = ((int16_t) (scenario_rand() & 0xFFFF)) * 4;
sprite->acceleration_x = ((int16_t)(scenario_rand() & 0xFFFF)) * 4;
sprite->acceleration_y = ((int16_t)(scenario_rand() & 0xFFFF)) * 4;
sprite->acceleration_z = (scenario_rand() & 0xFFFF) * 4 + 0x10000;
sprite->velocity_x = 0;
sprite->velocity_y = 0;
sprite->velocity_z = 0;
sprite->velocity_x = 0;
sprite->velocity_y = 0;
sprite->velocity_z = 0;
}
}
@ -47,13 +47,13 @@ void crashed_vehicle_particle_create(rct_vehicle_colour colours, int32_t x, int3
*
* rct2: 0x00673298
*/
void crashed_vehicle_particle_update(rct_crashed_vehicle_particle * particle)
void crashed_vehicle_particle_update(rct_crashed_vehicle_particle* particle)
{
invalidate_sprite_0((rct_sprite *) particle);
invalidate_sprite_0((rct_sprite*)particle);
particle->time_to_live--;
if (particle->time_to_live == 0)
{
sprite_remove((rct_sprite *) particle);
sprite_remove((rct_sprite*)particle);
return;
}
@ -80,15 +80,15 @@ void crashed_vehicle_particle_update(rct_crashed_vehicle_particle * particle)
// Check collision with land / water
uint32_t waterLand = tile_element_height(x, y);
int16_t landZ = (waterLand & 0xFFFF);
int16_t waterZ = (waterLand >> 16);
int16_t landZ = (waterLand & 0xFFFF);
int16_t waterZ = (waterLand >> 16);
if (waterZ != 0 && particle->z >= waterZ && z <= waterZ)
{
// Splash
audio_play_sound_at_location(SOUND_WATER_2, particle->x, particle->y, waterZ);
crash_splash_create(particle->x, particle->y, waterZ);
sprite_remove((rct_sprite *) particle);
sprite_remove((rct_sprite*)particle);
return;
}
@ -98,8 +98,8 @@ void crashed_vehicle_particle_update(rct_crashed_vehicle_particle * particle)
particle->acceleration_z *= -1;
z = landZ;
}
sprite_move(x, y, z, (rct_sprite *) particle);
invalidate_sprite_0((rct_sprite *) particle);
sprite_move(x, y, z, (rct_sprite*)particle);
invalidate_sprite_0((rct_sprite*)particle);
particle->frame += 85;
if (particle->frame >= 3072)
@ -114,16 +114,16 @@ void crashed_vehicle_particle_update(rct_crashed_vehicle_particle * particle)
*/
void crash_splash_create(int32_t x, int32_t y, int32_t z)
{
rct_unk_sprite * sprite = (rct_unk_sprite *) create_sprite(2);
rct_unk_sprite* sprite = (rct_unk_sprite*)create_sprite(2);
if (sprite != nullptr)
{
sprite->sprite_width = 33;
sprite->sprite_width = 33;
sprite->sprite_height_negative = 51;
sprite->sprite_height_positive = 16;
sprite->sprite_identifier = SPRITE_IDENTIFIER_MISC;
sprite_move(x, y, z + 3, (rct_sprite *) sprite);
sprite->sprite_identifier = SPRITE_IDENTIFIER_MISC;
sprite_move(x, y, z + 3, (rct_sprite*)sprite);
sprite->misc_identifier = SPRITE_MISC_CRASH_SPLASH;
sprite->frame = 0;
sprite->frame = 0;
}
}
@ -131,12 +131,12 @@ void crash_splash_create(int32_t x, int32_t y, int32_t z)
*
* rct2: 0x0067339D
*/
void crash_splash_update(rct_crash_splash * splash)
void crash_splash_update(rct_crash_splash* splash)
{
invalidate_sprite_2((rct_sprite *) splash);
invalidate_sprite_2((rct_sprite*)splash);
splash->frame += 85;
if (splash->frame >= 7168)
{
sprite_remove((rct_sprite *) splash);
sprite_remove((rct_sprite*)splash);
}
}

View File

@ -7,22 +7,23 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "../common.h"
#include "../Context.h"
#include "Scenery.h"
#include "../Cheats.h"
#include "../Context.h"
#include "../Game.h"
#include "../actions/WallRemoveAction.hpp"
#include "../common.h"
#include "../localisation/Localisation.h"
#include "../network/network.h"
#include "../object/ObjectList.h"
#include "../object/ObjectManager.h"
#include "../scenario/Scenario.h"
#include "../actions/WallRemoveAction.hpp"
#include "Climate.h"
#include "Footpath.h"
#include "Fountain.h"
#include "Map.h"
#include "Park.h"
#include "Scenery.h"
#include "SmallScenery.h"
#include "Wall.h"
@ -36,7 +37,7 @@ colour_t gWindowScenerySecondaryColour;
colour_t gWindowSceneryTertiaryColour;
bool gWindowSceneryEyedropperEnabled;
rct_tile_element *gSceneryTileElement;
rct_tile_element* gSceneryTileElement;
uint8_t gSceneryTileElementType;
money32 gSceneryPlaceCost;
@ -64,21 +65,17 @@ uint8_t gSceneryGroundFlags;
money32 gClearSceneryCost;
// rct2: 0x009A3E74
const LocationXY8 ScenerySubTileOffsets[] = {
{ 7, 7 },
{ 7, 23 },
{ 23, 23 },
{ 23, 7 }
};
const LocationXY8 ScenerySubTileOffsets[] = { { 7, 7 }, { 7, 23 }, { 23, 23 }, { 23, 7 } };
void scenery_increase_age(int32_t x, int32_t y, rct_tile_element *tileElement);
void scenery_increase_age(int32_t x, int32_t y, rct_tile_element* tileElement);
void scenery_update_tile(int32_t x, int32_t y)
{
rct_tile_element *tileElement;
rct_tile_element* tileElement;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
// Ghosts are purely this-client-side and should not cause any interaction,
// as that may lead to a desync.
if (network_get_mode() != NETWORK_MODE_NONE)
@ -87,16 +84,23 @@ void scenery_update_tile(int32_t x, int32_t y)
continue;
}
if (tileElement->GetType() == TILE_ELEMENT_TYPE_SMALL_SCENERY) {
if (tileElement->GetType() == TILE_ELEMENT_TYPE_SMALL_SCENERY)
{
scenery_update_age(x, y, tileElement);
} else if (tileElement->GetType() == TILE_ELEMENT_TYPE_PATH) {
if (footpath_element_has_path_scenery(tileElement) && !footpath_element_path_scenery_is_ghost(tileElement)) {
rct_scenery_entry *sceneryEntry = get_footpath_item_entry(footpath_element_get_path_scenery_index(tileElement));
if (sceneryEntry != nullptr) {
if (sceneryEntry->path_bit.flags & PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER) {
}
else if (tileElement->GetType() == TILE_ELEMENT_TYPE_PATH)
{
if (footpath_element_has_path_scenery(tileElement) && !footpath_element_path_scenery_is_ghost(tileElement))
{
rct_scenery_entry* sceneryEntry = get_footpath_item_entry(footpath_element_get_path_scenery_index(tileElement));
if (sceneryEntry != nullptr)
{
if (sceneryEntry->path_bit.flags & PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER)
{
jumping_fountain_begin(JUMPING_FOUNTAIN_TYPE_WATER, x, y, tileElement);
}
else if (sceneryEntry->path_bit.flags & PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW) {
else if (sceneryEntry->path_bit.flags & PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW)
{
jumping_fountain_begin(JUMPING_FOUNTAIN_TYPE_SNOW, x, y, tileElement);
}
}
@ -109,10 +113,10 @@ void scenery_update_tile(int32_t x, int32_t y)
*
* rct2: 0x006E33D9
*/
void scenery_update_age(int32_t x, int32_t y, rct_tile_element *tileElement)
void scenery_update_age(int32_t x, int32_t y, rct_tile_element* tileElement)
{
rct_tile_element *tileElementAbove;
rct_scenery_entry *sceneryEntry;
rct_tile_element* tileElementAbove;
rct_scenery_entry* sceneryEntry;
sceneryEntry = get_small_scenery_entry(tileElement->properties.scenery.type);
if (sceneryEntry == nullptr)
@ -125,19 +129,17 @@ void scenery_update_age(int32_t x, int32_t y, rct_tile_element *tileElement)
return;
}
if (
!scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_CAN_BE_WATERED) ||
(gClimateCurrent.Weather < WEATHER_RAIN) ||
(tileElement->properties.scenery.age < 5)
) {
if (!scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_CAN_BE_WATERED)
|| (gClimateCurrent.Weather < WEATHER_RAIN) || (tileElement->properties.scenery.age < 5))
{
scenery_increase_age(x, y, tileElement);
return;
}
// Check map elements above, presumably to see if map element is blocked from rain
tileElementAbove = tileElement;
while (!(tileElementAbove->flags & 7)) {
while (!(tileElementAbove->flags & 7))
{
tileElementAbove++;
// Ghosts are purely this-client-side and should not cause any interaction,
@ -145,21 +147,22 @@ void scenery_update_age(int32_t x, int32_t y, rct_tile_element *tileElement)
if (tile_element_is_ghost(tileElementAbove))
continue;
switch (tileElementAbove->GetType()) {
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
case TILE_ELEMENT_TYPE_ENTRANCE:
case TILE_ELEMENT_TYPE_PATH:
map_invalidate_tile_zoom1(x, y, tileElementAbove->base_height * 8, tileElementAbove->clearance_height * 8);
scenery_increase_age(x, y, tileElement);
return;
case TILE_ELEMENT_TYPE_SMALL_SCENERY:
sceneryEntry = get_small_scenery_entry(tileElementAbove->properties.scenery.type);
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
switch (tileElementAbove->GetType())
{
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
case TILE_ELEMENT_TYPE_ENTRANCE:
case TILE_ELEMENT_TYPE_PATH:
map_invalidate_tile_zoom1(x, y, tileElementAbove->base_height * 8, tileElementAbove->clearance_height * 8);
scenery_increase_age(x, y, tileElement);
return;
}
break;
case TILE_ELEMENT_TYPE_SMALL_SCENERY:
sceneryEntry = get_small_scenery_entry(tileElementAbove->properties.scenery.type);
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_VOFFSET_CENTRE))
{
scenery_increase_age(x, y, tileElement);
return;
}
break;
}
}
@ -168,18 +171,19 @@ void scenery_update_age(int32_t x, int32_t y, rct_tile_element *tileElement)
map_invalidate_tile_zoom1(x, y, tileElement->base_height * 8, tileElement->clearance_height * 8);
}
void scenery_increase_age(int32_t x, int32_t y, rct_tile_element *tileElement)
void scenery_increase_age(int32_t x, int32_t y, rct_tile_element* tileElement)
{
if (tileElement->flags & SMALL_SCENERY_FLAG_ANIMATED)
return;
if (tileElement->properties.scenery.age < 255) {
if (tileElement->properties.scenery.age < 255)
{
uint8_t newAge = tileElement->properties.scenery.age++;
// Only invalidate tiles when scenery crosses the withering threshholds, and can be withered.
if (newAge == SCENERY_WITHER_AGE_THRESHOLD_1 || newAge == SCENERY_WITHER_AGE_THRESHOLD_2)
{
rct_scenery_entry *entry = get_small_scenery_entry(tileElement->properties.scenery.type);
rct_scenery_entry* entry = get_small_scenery_entry(tileElement->properties.scenery.type);
if (scenery_small_entry_has_flag(entry, SMALL_SCENERY_FLAG_CAN_WITHER))
{
@ -193,29 +197,25 @@ void scenery_increase_age(int32_t x, int32_t y, rct_tile_element *tileElement)
*
* rct2: 0x006E2712
*/
void scenery_remove_ghost_tool_placement(){
void scenery_remove_ghost_tool_placement()
{
int16_t x, y, z;
x = gSceneryGhostPosition.x;
y = gSceneryGhostPosition.y;
z = gSceneryGhostPosition.z;
if (gSceneryGhostType & SCENERY_ENTRY_FLAG_0){
if (gSceneryGhostType & SCENERY_ENTRY_FLAG_0)
{
gSceneryGhostType &= ~SCENERY_ENTRY_FLAG_0;
game_do_command(
x,
105 | (gSceneryTileElementType << 8),
y,
z | (gSceneryPlaceObject << 8),
GAME_COMMAND_REMOVE_SCENERY,
0,
0);
x, 105 | (gSceneryTileElementType << 8), y, z | (gSceneryPlaceObject << 8), GAME_COMMAND_REMOVE_SCENERY, 0, 0);
}
if (gSceneryGhostType & SCENERY_ENTRY_FLAG_1)
{
gSceneryGhostType &= ~SCENERY_ENTRY_FLAG_1;
rct_tile_element * tileElement = map_get_first_element_at(x / 32, y / 32);
rct_tile_element* tileElement = map_get_first_element_at(x / 32, y / 32);
do
{
@ -247,116 +247,104 @@ void scenery_remove_ghost_tool_placement(){
wallRemoveAction.Execute();
}
if (gSceneryGhostType & SCENERY_ENTRY_FLAG_3){
if (gSceneryGhostType & SCENERY_ENTRY_FLAG_3)
{
gSceneryGhostType &= ~SCENERY_ENTRY_FLAG_3;
game_do_command(
x,
105 | (gSceneryPlaceRotation << 8),
y,
z,
GAME_COMMAND_REMOVE_LARGE_SCENERY,
0,
0);
game_do_command(x, 105 | (gSceneryPlaceRotation << 8), y, z, GAME_COMMAND_REMOVE_LARGE_SCENERY, 0, 0);
}
if (gSceneryGhostType & SCENERY_ENTRY_FLAG_4){
if (gSceneryGhostType & SCENERY_ENTRY_FLAG_4)
{
gSceneryGhostType &= ~SCENERY_ENTRY_FLAG_4;
game_do_command(
x,
105,
y,
z | (gSceneryPlaceRotation << 8),
GAME_COMMAND_REMOVE_BANNER,
0,
0);
game_do_command(x, 105, y, z | (gSceneryPlaceRotation << 8), GAME_COMMAND_REMOVE_BANNER, 0, 0);
}
}
rct_scenery_entry *get_small_scenery_entry(int32_t entryIndex)
rct_scenery_entry* get_small_scenery_entry(int32_t entryIndex)
{
rct_scenery_entry * result = nullptr;
rct_scenery_entry* result = nullptr;
auto objMgr = OpenRCT2::GetContext()->GetObjectManager();
if (objMgr != nullptr)
{
auto obj = objMgr->GetLoadedObject(OBJECT_TYPE_SMALL_SCENERY, entryIndex);
if (obj != nullptr)
{
result = (rct_scenery_entry *)obj->GetLegacyData();
result = (rct_scenery_entry*)obj->GetLegacyData();
}
}
return result;
}
rct_scenery_entry *get_large_scenery_entry(int32_t entryIndex)
rct_scenery_entry* get_large_scenery_entry(int32_t entryIndex)
{
rct_scenery_entry * result = nullptr;
rct_scenery_entry* result = nullptr;
auto objMgr = OpenRCT2::GetContext()->GetObjectManager();
if (objMgr != nullptr)
{
auto obj = objMgr->GetLoadedObject(OBJECT_TYPE_LARGE_SCENERY, entryIndex);
if (obj != nullptr)
{
result = (rct_scenery_entry *)obj->GetLegacyData();
result = (rct_scenery_entry*)obj->GetLegacyData();
}
}
return result;
}
rct_scenery_entry *get_wall_entry(int32_t entryIndex)
rct_scenery_entry* get_wall_entry(int32_t entryIndex)
{
rct_scenery_entry * result = nullptr;
rct_scenery_entry* result = nullptr;
auto objMgr = OpenRCT2::GetContext()->GetObjectManager();
if (objMgr != nullptr)
{
auto obj = objMgr->GetLoadedObject(OBJECT_TYPE_WALLS, entryIndex);
if (obj != nullptr)
{
result = (rct_scenery_entry *)obj->GetLegacyData();
result = (rct_scenery_entry*)obj->GetLegacyData();
}
}
return result;
}
rct_scenery_entry *get_banner_entry(int32_t entryIndex)
rct_scenery_entry* get_banner_entry(int32_t entryIndex)
{
rct_scenery_entry * result = nullptr;
rct_scenery_entry* result = nullptr;
auto objMgr = OpenRCT2::GetContext()->GetObjectManager();
if (objMgr != nullptr)
{
auto obj = objMgr->GetLoadedObject(OBJECT_TYPE_BANNERS, entryIndex);
if (obj != nullptr)
{
result = (rct_scenery_entry *)obj->GetLegacyData();
result = (rct_scenery_entry*)obj->GetLegacyData();
}
}
return result;
}
rct_scenery_entry *get_footpath_item_entry(int32_t entryIndex)
rct_scenery_entry* get_footpath_item_entry(int32_t entryIndex)
{
rct_scenery_entry * result = nullptr;
rct_scenery_entry* result = nullptr;
auto objMgr = OpenRCT2::GetContext()->GetObjectManager();
if (objMgr != nullptr)
{
auto obj = objMgr->GetLoadedObject(OBJECT_TYPE_PATH_BITS, entryIndex);
if (obj != nullptr)
{
result = (rct_scenery_entry *)obj->GetLegacyData();
result = (rct_scenery_entry*)obj->GetLegacyData();
}
}
return result;
}
rct_scenery_group_entry *get_scenery_group_entry(int32_t entryIndex)
rct_scenery_group_entry* get_scenery_group_entry(int32_t entryIndex)
{
rct_scenery_group_entry * result = nullptr;
rct_scenery_group_entry* result = nullptr;
auto objMgr = OpenRCT2::GetContext()->GetObjectManager();
if (objMgr != nullptr)
{
auto obj = objMgr->GetLoadedObject(OBJECT_TYPE_SCENERY_GROUP, entryIndex);
if (obj != nullptr)
{
result = (rct_scenery_group_entry *)obj->GetLegacyData();
result = (rct_scenery_group_entry*)obj->GetLegacyData();
}
}
return result;
@ -364,17 +352,24 @@ rct_scenery_group_entry *get_scenery_group_entry(int32_t entryIndex)
int32_t get_scenery_id_from_entry_index(uint8_t objectType, int32_t entryIndex)
{
switch (objectType) {
case OBJECT_TYPE_SMALL_SCENERY: return entryIndex + SCENERY_SMALL_SCENERY_ID_MIN;
case OBJECT_TYPE_PATH_BITS: return entryIndex + SCENERY_PATH_SCENERY_ID_MIN;
case OBJECT_TYPE_WALLS: return entryIndex + SCENERY_WALLS_ID_MIN;
case OBJECT_TYPE_LARGE_SCENERY: return entryIndex + SCENERY_LARGE_SCENERY_ID_MIN;
case OBJECT_TYPE_BANNERS: return entryIndex + SCENERY_BANNERS_ID_MIN;
default: return -1;
switch (objectType)
{
case OBJECT_TYPE_SMALL_SCENERY:
return entryIndex + SCENERY_SMALL_SCENERY_ID_MIN;
case OBJECT_TYPE_PATH_BITS:
return entryIndex + SCENERY_PATH_SCENERY_ID_MIN;
case OBJECT_TYPE_WALLS:
return entryIndex + SCENERY_WALLS_ID_MIN;
case OBJECT_TYPE_LARGE_SCENERY:
return entryIndex + SCENERY_LARGE_SCENERY_ID_MIN;
case OBJECT_TYPE_BANNERS:
return entryIndex + SCENERY_BANNERS_ID_MIN;
default:
return -1;
}
}
int32_t wall_entry_get_door_sound(const rct_scenery_entry * wallEntry)
int32_t wall_entry_get_door_sound(const rct_scenery_entry* wallEntry)
{
return (wallEntry->wall.flags2 & WALL_SCENERY_2_DOOR_SOUND_MASK) >> WALL_SCENERY_2_DOOR_SOUND_SHIFT;
}

View File

@ -10,33 +10,35 @@
#ifndef _SCENERY_H_
#define _SCENERY_H_
#include <limits>
#include "../common.h"
#include "../object/Object.h"
#include "../world/Location.hpp"
#include "TileElement.h"
#define SCENERY_SMALL_SCENERY_ID_MIN 0x0
#define SCENERY_SMALL_SCENERY_ID_MAX 0xFC
#define SCENERY_LARGE_SCENERY_ID_MIN 0x300
#define SCENERY_LARGE_SCENERY_ID_MAX 0x380
#define SCENERY_WALLS_ID_MIN 0x200
#define SCENERY_WALLS_ID_MAX 0x280
#define SCENERY_BANNERS_ID_MIN 0x400
#define SCENERY_BANNERS_ID_MAX 0x420
#define SCENERY_PATH_SCENERY_ID_MIN 0x100
#define SCENERY_PATH_SCENERY_ID_MAX 0x10F
#define SCENERY_WITHER_AGE_THRESHOLD_1 0x28
#define SCENERY_WITHER_AGE_THRESHOLD_2 0x37
#include <limits>
#define SCENERY_SMALL_SCENERY_ID_MIN 0x0
#define SCENERY_SMALL_SCENERY_ID_MAX 0xFC
#define SCENERY_LARGE_SCENERY_ID_MIN 0x300
#define SCENERY_LARGE_SCENERY_ID_MAX 0x380
#define SCENERY_WALLS_ID_MIN 0x200
#define SCENERY_WALLS_ID_MAX 0x280
#define SCENERY_BANNERS_ID_MIN 0x400
#define SCENERY_BANNERS_ID_MAX 0x420
#define SCENERY_PATH_SCENERY_ID_MIN 0x100
#define SCENERY_PATH_SCENERY_ID_MAX 0x10F
#define SCENERY_WITHER_AGE_THRESHOLD_1 0x28
#define SCENERY_WITHER_AGE_THRESHOLD_2 0x37
#pragma pack(push, 1)
struct rct_small_scenery_entry {
struct rct_small_scenery_entry
{
uint32_t flags; // 0x06
uint8_t height; // 0x0A
uint8_t tool_id; // 0x0B
int16_t price; // 0x0C
int16_t removal_price; // 0x0E
uint8_t *frame_offsets; // 0x10
int16_t price; // 0x0C
int16_t removal_price; // 0x0E
uint8_t* frame_offsets; // 0x10
uint16_t animation_delay; // 0x14
uint16_t animation_mask; // 0x16
uint16_t num_frames; // 0x18
@ -46,7 +48,8 @@ struct rct_small_scenery_entry {
assert_struct_size(rct_small_scenery_entry, 21);
#endif
struct rct_large_scenery_tile {
struct rct_large_scenery_tile
{
int16_t x_offset;
int16_t y_offset;
int16_t z_offset;
@ -58,11 +61,12 @@ assert_struct_size(rct_large_scenery_tile, 9);
enum
{
LARGE_SCENERY_TILE_FLAG_NO_SUPPORTS = 0x20,
LARGE_SCENERY_TILE_FLAG_ALLOW_SUPPORTS_ABOVE = 0x40,
LARGE_SCENERY_TILE_FLAG_NO_SUPPORTS = 0x20,
LARGE_SCENERY_TILE_FLAG_ALLOW_SUPPORTS_ABOVE = 0x40,
};
struct rct_large_scenery_text_glyph {
struct rct_large_scenery_text_glyph
{
uint8_t image_offset;
uint8_t width;
uint8_t height;
@ -70,37 +74,41 @@ struct rct_large_scenery_text_glyph {
};
assert_struct_size(rct_large_scenery_text_glyph, 4);
struct rct_large_scenery_text {
LocationXY16 offset[2]; // 0x0
uint16_t max_width; // 0x8
uint16_t pad_A; // 0xA
uint8_t flags; // 0xC
uint8_t num_images; // 0xD
struct rct_large_scenery_text
{
LocationXY16 offset[2]; // 0x0
uint16_t max_width; // 0x8
uint16_t pad_A; // 0xA
uint8_t flags; // 0xC
uint8_t num_images; // 0xD
rct_large_scenery_text_glyph glyphs[256]; // 0xE
};
assert_struct_size(rct_large_scenery_text, 14 + 4 * 256);
enum LARGE_SCENERY_TEXT_FLAGS {
LARGE_SCENERY_TEXT_FLAG_VERTICAL = (1 << 0), // 0x1
LARGE_SCENERY_TEXT_FLAG_TWO_LINE = (1 << 1), // 0x2
enum LARGE_SCENERY_TEXT_FLAGS
{
LARGE_SCENERY_TEXT_FLAG_VERTICAL = (1 << 0), // 0x1
LARGE_SCENERY_TEXT_FLAG_TWO_LINE = (1 << 1), // 0x2
};
struct rct_large_scenery_entry {
uint8_t tool_id; // 0x06
uint8_t flags; // 0x07
int16_t price; // 0x08
int16_t removal_price; // 0x0A
struct rct_large_scenery_entry
{
uint8_t tool_id; // 0x06
uint8_t flags; // 0x07
int16_t price; // 0x08
int16_t removal_price; // 0x0A
rct_large_scenery_tile* tiles; // 0x0C
uint8_t scenery_tab_id; // 0x10
uint8_t scrolling_mode; // 0x11
uint8_t scenery_tab_id; // 0x10
uint8_t scrolling_mode; // 0x11
rct_large_scenery_text* text; // 0x12
uint32_t text_image; // 0x16
uint32_t text_image; // 0x16
};
#ifdef PLATFORM_32BIT
assert_struct_size(rct_large_scenery_entry, 20);
#endif
enum LARGE_SCENERY_FLAGS {
enum LARGE_SCENERY_FLAGS
{
LARGE_SCENERY_FLAG_HAS_PRIMARY_COLOUR = (1 << 0), // 0x1
LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR = (1 << 1), // 0x2
LARGE_SCENERY_FLAG_3D_TEXT = (1 << 2), // 0x4
@ -108,58 +116,64 @@ enum LARGE_SCENERY_FLAGS {
LARGE_SCENERY_FLAG_PHOTOGENIC = (1 << 4), // 0x10
};
struct rct_wall_scenery_entry {
uint8_t tool_id; // 0x06
uint8_t flags; // 0x07
uint8_t height; // 0x08
uint8_t flags2; // 0x09
int16_t price; // 0x0A
uint8_t scenery_tab_id; // 0x0C
uint8_t scrolling_mode; // 0x0D 0xFF if no scrolling
struct rct_wall_scenery_entry
{
uint8_t tool_id; // 0x06
uint8_t flags; // 0x07
uint8_t height; // 0x08
uint8_t flags2; // 0x09
int16_t price; // 0x0A
uint8_t scenery_tab_id; // 0x0C
uint8_t scrolling_mode; // 0x0D 0xFF if no scrolling
};
assert_struct_size(rct_wall_scenery_entry, 8);
enum WALL_SCENERY_FLAGS
{
WALL_SCENERY_HAS_PRIMARY_COLOUR = (1 << 0), // 0x1
WALL_SCENERY_HAS_GLASS = (1 << 1), // 0x2
WALL_SCENERY_CANT_BUILD_ON_SLOPE = (1 << 2), // 0x4
WALL_SCENERY_IS_BANNER = (1 << 3), // 0x8 // Probably indicates translucency
WALL_SCENERY_IS_DOOR = (1 << 4), // 0x10
WALL_SCENERY_LONG_DOOR_ANIMATION = (1 << 5), // 0x20
WALL_SCENERY_HAS_SECONDARY_COLOUR = (1 << 6), // 0x40
WALL_SCENERY_HAS_TERNARY_COLOUR = (1 << 7), // 0x80
WALL_SCENERY_HAS_PRIMARY_COLOUR = (1 << 0), // 0x1
WALL_SCENERY_HAS_GLASS = (1 << 1), // 0x2
WALL_SCENERY_CANT_BUILD_ON_SLOPE = (1 << 2), // 0x4
WALL_SCENERY_IS_BANNER = (1 << 3), // 0x8 // Probably indicates translucency
WALL_SCENERY_IS_DOOR = (1 << 4), // 0x10
WALL_SCENERY_LONG_DOOR_ANIMATION = (1 << 5), // 0x20
WALL_SCENERY_HAS_SECONDARY_COLOUR = (1 << 6), // 0x40
WALL_SCENERY_HAS_TERNARY_COLOUR = (1 << 7), // 0x80
};
enum WALL_SCENERY_2_FLAGS {
WALL_SCENERY_2_NO_SELECT_PRIMARY_COLOUR = (1 << 0), // 0x1
enum WALL_SCENERY_2_FLAGS
{
WALL_SCENERY_2_NO_SELECT_PRIMARY_COLOUR = (1 << 0), // 0x1
WALL_SCENERY_2_DOOR_SOUND_MASK = 0x6,
WALL_SCENERY_2_DOOR_SOUND_SHIFT = 1,
WALL_SCENERY_2_IS_OPAQUE = (1 << 3), // 0x8
WALL_SCENERY_2_ANIMATED = (1 << 4), // 0x10
WALL_SCENERY_2_IS_OPAQUE = (1 << 3), // 0x8
WALL_SCENERY_2_ANIMATED = (1 << 4), // 0x10
};
struct rct_path_bit_scenery_entry {
uint16_t flags; // 0x06
uint8_t draw_type; // 0x08
uint8_t tool_id; // 0x09
int16_t price; // 0x0A
uint8_t scenery_tab_id; // 0x0C
struct rct_path_bit_scenery_entry
{
uint16_t flags; // 0x06
uint8_t draw_type; // 0x08
uint8_t tool_id; // 0x09
int16_t price; // 0x0A
uint8_t scenery_tab_id; // 0x0C
};
assert_struct_size(rct_path_bit_scenery_entry, 7);
struct rct_banner_scenery_entry {
uint8_t scrolling_mode; // 0x06
uint8_t flags; // 0x07
int16_t price; // 0x08
uint8_t scenery_tab_id; // 0x0A
struct rct_banner_scenery_entry
{
uint8_t scrolling_mode; // 0x06
uint8_t flags; // 0x07
int16_t price; // 0x08
uint8_t scenery_tab_id; // 0x0A
};
assert_struct_size(rct_banner_scenery_entry, 5);
struct rct_scenery_entry {
rct_string_id name; // 0x00
uint32_t image; // 0x02
union {
struct rct_scenery_entry
{
rct_string_id name; // 0x00
uint32_t image; // 0x02
union
{
rct_small_scenery_entry small_scenery;
rct_large_scenery_entry large_scenery;
rct_wall_scenery_entry wall;
@ -171,39 +185,43 @@ struct rct_scenery_entry {
assert_struct_size(rct_scenery_entry, 6 + 21);
#endif
struct rct_scenery_group_entry {
struct rct_scenery_group_entry
{
rct_string_id name; // 0x00
uint32_t image; // 0x02
uint16_t scenery_entries[0x80]; // 0x06
uint8_t entry_count; // 0x106
uint32_t image; // 0x02
uint16_t scenery_entries[0x80]; // 0x06
uint8_t entry_count; // 0x106
uint8_t pad_107;
uint8_t priority; // 0x108
uint8_t priority; // 0x108
uint8_t pad_109;
uint32_t entertainer_costumes; // 0x10A
uint32_t entertainer_costumes; // 0x10A
};
assert_struct_size(rct_scenery_group_entry, 14 + 2 * 0x80);
#pragma pack(pop)
enum {
PATH_BIT_FLAG_IS_BIN = 1 << 0,
PATH_BIT_FLAG_IS_BENCH = 1 << 1,
PATH_BIT_FLAG_BREAKABLE = 1 << 2,
PATH_BIT_FLAG_LAMP = 1 << 3,
PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER = 1 << 4,
PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW = 1 << 5,
PATH_BIT_FLAG_DONT_ALLOW_ON_QUEUE = 1 << 6,
PATH_BIT_FLAG_DONT_ALLOW_ON_SLOPE = 1 << 7,
PATH_BIT_FLAG_IS_QUEUE_SCREEN = 1 << 8
enum
{
PATH_BIT_FLAG_IS_BIN = 1 << 0,
PATH_BIT_FLAG_IS_BENCH = 1 << 1,
PATH_BIT_FLAG_BREAKABLE = 1 << 2,
PATH_BIT_FLAG_LAMP = 1 << 3,
PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER = 1 << 4,
PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW = 1 << 5,
PATH_BIT_FLAG_DONT_ALLOW_ON_QUEUE = 1 << 6,
PATH_BIT_FLAG_DONT_ALLOW_ON_SLOPE = 1 << 7,
PATH_BIT_FLAG_IS_QUEUE_SCREEN = 1 << 8
};
enum {
enum
{
PATH_BIT_DRAW_TYPE_LIGHTS,
PATH_BIT_DRAW_TYPE_BINS,
PATH_BIT_DRAW_TYPE_BENCHES,
PATH_BIT_DRAW_TYPE_JUMPING_FOUNTAINS
};
enum {
enum
{
SCENERY_TYPE_SMALL,
SCENERY_TYPE_PATH_ITEM,
SCENERY_TYPE_WALL,
@ -211,7 +229,8 @@ enum {
SCENERY_TYPE_BANNER
};
enum {
enum
{
SCENERY_ENTRY_FLAG_0 = (1 << 0),
SCENERY_ENTRY_FLAG_1 = (1 << 1),
SCENERY_ENTRY_FLAG_2 = (1 << 2),
@ -219,7 +238,8 @@ enum {
SCENERY_ENTRY_FLAG_4 = (1 << 4)
};
enum {
enum
{
SCENERY_GHOST_FLAG_0 = (1 << SCENERY_TYPE_SMALL),
SCENERY_GHOST_FLAG_1 = (1 << SCENERY_TYPE_PATH_ITEM),
SCENERY_GHOST_FLAG_2 = (1 << SCENERY_TYPE_WALL),
@ -245,7 +265,7 @@ extern colour_t gWindowScenerySecondaryColour;
extern colour_t gWindowSceneryTertiaryColour;
extern bool gWindowSceneryEyedropperEnabled;
extern rct_tile_element *gSceneryTileElement;
extern rct_tile_element* gSceneryTileElement;
extern uint8_t gSceneryTileElementType;
extern money32 gSceneryPlaceCost;
@ -276,18 +296,18 @@ extern money32 gClearSceneryCost;
void init_scenery();
void scenery_update_tile(int32_t x, int32_t y);
void scenery_update_age(int32_t x, int32_t y, rct_tile_element *tileElement);
void scenery_update_age(int32_t x, int32_t y, rct_tile_element* tileElement);
void scenery_set_default_placement_configuration();
void scenery_remove_ghost_tool_placement();
rct_scenery_entry *get_small_scenery_entry(int32_t entryIndex);
rct_scenery_entry *get_large_scenery_entry(int32_t entryIndex);
rct_scenery_entry *get_wall_entry(int32_t entryIndex);
rct_scenery_entry *get_banner_entry(int32_t entryIndex);
rct_scenery_entry *get_footpath_item_entry(int32_t entryIndex);
rct_scenery_group_entry *get_scenery_group_entry(int32_t entryIndex);
rct_scenery_entry* get_small_scenery_entry(int32_t entryIndex);
rct_scenery_entry* get_large_scenery_entry(int32_t entryIndex);
rct_scenery_entry* get_wall_entry(int32_t entryIndex);
rct_scenery_entry* get_banner_entry(int32_t entryIndex);
rct_scenery_entry* get_footpath_item_entry(int32_t entryIndex);
rct_scenery_group_entry* get_scenery_group_entry(int32_t entryIndex);
int32_t get_scenery_id_from_entry_index(uint8_t objectType, int32_t entryIndex);
int32_t wall_entry_get_door_sound(const rct_scenery_entry * wallEntry);
int32_t wall_entry_get_door_sound(const rct_scenery_entry* wallEntry);
#endif

View File

@ -7,28 +7,30 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "SmallScenery.h"
#include "../Cheats.h"
#include "../OpenRCT2.h"
#include "../management/Finance.h"
#include "../network/network.h"
#include "../OpenRCT2.h"
#include "../ride/TrackDesign.h"
#include "Footpath.h"
#include "Map.h"
#include "MapAnimation.h"
#include "Park.h"
#include "Scenery.h"
#include "SmallScenery.h"
#include "MapAnimation.h"
#include "Surface.h"
static money32 SmallSceneryRemove(int16_t x, int16_t y, uint8_t baseHeight, uint8_t quadrant, uint8_t sceneryType, uint8_t flags)
static money32
SmallSceneryRemove(int16_t x, int16_t y, uint8_t baseHeight, uint8_t quadrant, uint8_t sceneryType, uint8_t flags)
{
if (!map_is_location_valid({x, y}))
if (!map_is_location_valid({ x, y }))
{
return MONEY32_UNDEFINED;
}
money32 cost;
rct_scenery_entry *entry = get_small_scenery_entry(sceneryType);
rct_scenery_entry* entry = get_small_scenery_entry(sceneryType);
if (entry == nullptr)
{
log_warning("Invalid game command for scenery removal, scenery_type = %u", sceneryType);
@ -41,17 +43,13 @@ static money32 SmallSceneryRemove(int16_t x, int16_t y, uint8_t baseHeight, uint
gCommandPosition.y = y + 16;
gCommandPosition.z = baseHeight * 8;
if (!(flags & GAME_COMMAND_FLAG_GHOST) &&
game_is_paused() &&
!gCheatsBuildInPauseMode)
if (!(flags & GAME_COMMAND_FLAG_GHOST) && game_is_paused() && !gCheatsBuildInPauseMode)
{
gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED;
return MONEY32_UNDEFINED;
}
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) &&
!(flags & GAME_COMMAND_FLAG_GHOST) &&
!gCheatsSandboxMode)
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(flags & GAME_COMMAND_FLAG_GHOST) && !gCheatsSandboxMode)
{
// Check if allowed to remove item
if (gParkFlags & PARK_FLAGS_FORBID_TREE_REMOVAL)
@ -72,7 +70,8 @@ static money32 SmallSceneryRemove(int16_t x, int16_t y, uint8_t baseHeight, uint
bool sceneryFound = false;
rct_tile_element* tileElement = map_get_first_element_at(x / 32, y / 32);
do {
do
{
if (tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)
continue;
if ((tileElement->type >> 6) != quadrant)
@ -81,8 +80,7 @@ static money32 SmallSceneryRemove(int16_t x, int16_t y, uint8_t baseHeight, uint
continue;
if (tileElement->properties.scenery.type != sceneryType)
continue;
if ((flags & GAME_COMMAND_FLAG_GHOST) &&
!(tileElement->flags & TILE_ELEMENT_FLAG_GHOST))
if ((flags & GAME_COMMAND_FLAG_GHOST) && !(tileElement->flags & TILE_ELEMENT_FLAG_GHOST))
continue;
sceneryFound = true;
@ -112,7 +110,15 @@ static money32 SmallSceneryRemove(int16_t x, int16_t y, uint8_t baseHeight, uint
return (gParkFlags & PARK_FLAGS_NO_MONEY) ? 0 : cost;
}
static money32 SmallScenerySetColour(int16_t x, int16_t y, uint8_t baseHeight, uint8_t quadrant, uint8_t sceneryType, uint8_t primaryColour, uint8_t secondaryColour, uint8_t flags)
static money32 SmallScenerySetColour(
int16_t x,
int16_t y,
uint8_t baseHeight,
uint8_t quadrant,
uint8_t sceneryType,
uint8_t primaryColour,
uint8_t secondaryColour,
uint8_t flags)
{
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
int32_t z = baseHeight * 8;
@ -128,7 +134,7 @@ static money32 SmallScenerySetColour(int16_t x, int16_t y, uint8_t baseHeight, u
}
}
rct_tile_element *tileElement = map_get_small_scenery_element_at(x, y, baseHeight, sceneryType, quadrant);
rct_tile_element* tileElement = map_get_small_scenery_element_at(x, y, baseHeight, sceneryType, quadrant);
if (tileElement == nullptr)
{
@ -151,7 +157,8 @@ static money32 SmallScenerySetColour(int16_t x, int16_t y, uint8_t baseHeight, u
return 0;
}
static money32 SmallSceneryPlace(int16_t x,
static money32 SmallSceneryPlace(
int16_t x,
int16_t y,
int16_t targetHeight,
uint8_t quadrant,
@ -209,10 +216,11 @@ static money32 SmallSceneryPlace(int16_t x,
return MONEY32_UNDEFINED;
}
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE) ||
!scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL))
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE)
|| !scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL))
{
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS))
if (scenery_small_entry_has_flag(
sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL | SMALL_SCENERY_FLAG_HALF_SPACE | SMALL_SCENERY_FLAG_THREE_QUARTERS))
{
quadrant = 0;
}
@ -247,11 +255,8 @@ static money32 SmallSceneryPlace(int16_t x,
targetHeight = baseHeight;
}
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) &&
!gCheatsSandboxMode &&
!map_is_location_owned(x, y, targetHeight))
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !map_is_location_owned(x, y, targetHeight))
{
return MONEY32_UNDEFINED;
}
@ -264,7 +269,7 @@ static money32 SmallSceneryPlace(int16_t x,
}
}
rct_tile_element* surfaceElement = map_get_surface_element_at({x, y});
rct_tile_element* surfaceElement = map_get_surface_element_at({ x, y });
if (surfaceElement != nullptr && !gCheatsDisableClearanceChecks && surface_get_water_height(surfaceElement) > 0)
{
@ -294,36 +299,27 @@ static money32 SmallSceneryPlace(int16_t x,
}
}
if (!gCheatsDisableClearanceChecks &&
(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE)) &&
!supportsRequired &&
!isOnWater &&
surfaceElement != nullptr &&
(surfaceElement->properties.surface.slope & TILE_ELEMENT_SURFACE_SLOPE_MASK))
if (!gCheatsDisableClearanceChecks && (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE))
&& !supportsRequired && !isOnWater && surfaceElement != nullptr
&& (surfaceElement->properties.surface.slope & TILE_ELEMENT_SURFACE_SLOPE_MASK))
{
gGameCommandErrorText = STR_LEVEL_LAND_REQUIRED;
return MONEY32_UNDEFINED;
}
if (!gCheatsDisableSupportLimits &&
!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE)) &&
supportsRequired)
if (!gCheatsDisableSupportLimits && !(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_STACKABLE))
&& supportsRequired)
{
if (!isOnWater)
{
if (surfaceElement != nullptr)
{
if (surface_get_water_height(surfaceElement) ||
(surfaceElement->base_height * 8) != targetHeight)
if (surface_get_water_height(surfaceElement) || (surfaceElement->base_height * 8) != targetHeight)
{
gGameCommandErrorText = STR_LEVEL_LAND_REQUIRED;
return MONEY32_UNDEFINED;
}
}
}
else
{
@ -342,8 +338,8 @@ static money32 SmallSceneryPlace(int16_t x,
}
if (!(scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HALF_SPACE)))
{
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL) &&
scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_DIAGONAL)
&& scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_FULL_TILE))
{
if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_THREE_QUARTERS))
{
@ -364,17 +360,17 @@ static money32 SmallSceneryPlace(int16_t x,
blSupports |= 0xF0;
}
if (!gCheatsDisableClearanceChecks &&
!map_can_construct_with_clear_at(
x,
y,
zLow,
zHigh,
&map_place_scenery_clear_func,
blSupports | collisionQuadrants,
flags,
&clearCost,
CREATE_CROSSING_MODE_NONE))
if (!gCheatsDisableClearanceChecks
&& !map_can_construct_with_clear_at(
x,
y,
zLow,
zHigh,
&map_place_scenery_clear_func,
blSupports | collisionQuadrants,
flags,
&clearCost,
CREATE_CROSSING_MODE_NONE))
{
return MONEY32_UNDEFINED;
}
@ -438,22 +434,16 @@ static money32 SmallSceneryPlace(int16_t x,
* rct2: 0x006E0E01
*/
void game_command_remove_scenery(
int32_t * eax,
int32_t * ebx,
int32_t * ecx,
int32_t * edx,
[[maybe_unused]] int32_t * esi,
[[maybe_unused]] int32_t * edi,
[[maybe_unused]] int32_t * ebp)
int32_t* eax,
int32_t* ebx,
int32_t* ecx,
int32_t* edx,
[[maybe_unused]] int32_t* esi,
[[maybe_unused]] int32_t* edi,
[[maybe_unused]] int32_t* ebp)
{
*ebx = SmallSceneryRemove(
*eax & 0xFFFF,
*ecx & 0xFFFF,
*edx & 0xFF,
((*ebx >> 8) & 0xFF) >> 6,
(*edx >> 8) & 0xFF,
*ebx & 0xFF
);
*eax & 0xFFFF, *ecx & 0xFFFF, *edx & 0xFF, ((*ebx >> 8) & 0xFF) >> 6, (*edx >> 8) & 0xFF, *ebx & 0xFF);
}
/**
@ -461,13 +451,13 @@ void game_command_remove_scenery(
* rct2: 0x006E0F26
*/
void game_command_set_scenery_colour(
int32_t * eax,
int32_t * ebx,
int32_t * ecx,
int32_t * edx,
[[maybe_unused]] int32_t * esi,
[[maybe_unused]] int32_t * edi,
int32_t * ebp)
int32_t* eax,
int32_t* ebx,
int32_t* ecx,
int32_t* edx,
[[maybe_unused]] int32_t* esi,
[[maybe_unused]] int32_t* edi,
int32_t* ebp)
{
*ebx = SmallScenerySetColour(
*eax & 0xFFFF,
@ -477,8 +467,7 @@ void game_command_set_scenery_colour(
(*edx >> 8) & 0xFF,
*ebp & 0xFF,
(*ebp >> 8) & 0xFF,
*ebx & 0xFF
);
*ebx & 0xFF);
}
/**
@ -557,7 +546,7 @@ int32_t map_place_non_scenery_clear_func(rct_tile_element** tile_element, int32_
* rct2: 0x006E08F4
*/
void game_command_place_scenery(
int32_t * eax, int32_t * ebx, int32_t * ecx, int32_t * edx, [[maybe_unused]] int32_t * esi, int32_t * edi, int32_t * ebp)
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, int32_t* edi, int32_t* ebp)
{
*ebx = SmallSceneryPlace(
*eax & 0xFFFF,
@ -568,46 +557,44 @@ void game_command_place_scenery(
(*ebx >> 8) & 0xFF,
(*edx >> 8) & 0xFF,
(*edi >> 16) & 0xFF,
*ebx & 0xFF
);
*ebx & 0xFF);
}
int32_t scenery_small_get_primary_colour(const rct_tile_element * tileElement)
int32_t scenery_small_get_primary_colour(const rct_tile_element* tileElement)
{
return tileElement->properties.scenery.colour_1 & TILE_ELEMENT_COLOUR_MASK;
}
int32_t scenery_small_get_secondary_colour(const rct_tile_element * tileElement)
int32_t scenery_small_get_secondary_colour(const rct_tile_element* tileElement)
{
return tileElement->properties.scenery.colour_2 & TILE_ELEMENT_COLOUR_MASK;
}
void scenery_small_set_primary_colour(rct_tile_element * tileElement, uint32_t colour)
void scenery_small_set_primary_colour(rct_tile_element* tileElement, uint32_t colour)
{
assert(colour <= 31);
tileElement->properties.scenery.colour_1 &= ~TILE_ELEMENT_COLOUR_MASK;
tileElement->properties.scenery.colour_1 |= colour;
}
void scenery_small_set_secondary_colour(rct_tile_element * tileElement, uint32_t colour)
void scenery_small_set_secondary_colour(rct_tile_element* tileElement, uint32_t colour)
{
assert(colour <= 31);
tileElement->properties.scenery.colour_2 &= ~TILE_ELEMENT_COLOUR_MASK;
tileElement->properties.scenery.colour_2 |= colour;
}
bool scenery_small_get_supports_needed(const rct_tile_element * tileElement)
bool scenery_small_get_supports_needed(const rct_tile_element* tileElement)
{
return (bool)(tileElement->properties.scenery.colour_1 & MAP_ELEM_SMALL_SCENERY_COLOUR_FLAG_NEEDS_SUPPORTS);
}
void scenery_small_set_supports_needed(rct_tile_element * tileElement)
void scenery_small_set_supports_needed(rct_tile_element* tileElement)
{
tileElement->properties.scenery.colour_1 |= MAP_ELEM_SMALL_SCENERY_COLOUR_FLAG_NEEDS_SUPPORTS;
}
bool scenery_small_entry_has_flag(const rct_scenery_entry * sceneryEntry, uint32_t flags)
bool scenery_small_entry_has_flag(const rct_scenery_entry* sceneryEntry, uint32_t flags)
{
return (bool)(sceneryEntry->small_scenery.flags & flags);
}

View File

@ -15,34 +15,35 @@
enum SMALL_SCENERY_FLAGS
{
SMALL_SCENERY_FLAG_FULL_TILE = (1 << 0), // 0x1
SMALL_SCENERY_FLAG_VOFFSET_CENTRE = (1 << 1), // 0x2
SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE = (1 << 2), // 0x4
SMALL_SCENERY_FLAG_ROTATABLE = (1 << 3), // 0x8; when set, user can set rotation, otherwise rotation is automatic
SMALL_SCENERY_FLAG_ANIMATED = (1 << 4), // 0x10
SMALL_SCENERY_FLAG_CAN_WITHER = (1 << 5), // 0x20
SMALL_SCENERY_FLAG_CAN_BE_WATERED = (1 << 6), // 0x40
SMALL_SCENERY_FLAG_ANIMATED_FG = (1 << 7), // 0x80
SMALL_SCENERY_FLAG_DIAGONAL = (1 << 8), // 0x100
SMALL_SCENERY_FLAG_HAS_GLASS = (1 << 9), // 0x200
SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR = (1 << 10), // 0x400
SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1 = (1 << 11), // 0x800
SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4 = (1 << 12), // 0x1000
SMALL_SCENERY_FLAG_IS_CLOCK = (1 << 13), // 0x2000
SMALL_SCENERY_FLAG_SWAMP_GOO = (1 << 14), // 0x4000
SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS = (1 << 15), // 0x8000
SMALL_SCENERY_FLAG17 = (1 << 16), // 0x10000
SMALL_SCENERY_FLAG_STACKABLE = (1 << 17), // 0x20000; means scenery item can be placed in the air and over water
SMALL_SCENERY_FLAG_NO_WALLS = (1 << 18), // 0x40000
SMALL_SCENERY_FLAG_FULL_TILE = (1 << 0), // 0x1
SMALL_SCENERY_FLAG_VOFFSET_CENTRE = (1 << 1), // 0x2
SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE = (1 << 2), // 0x4
SMALL_SCENERY_FLAG_ROTATABLE = (1 << 3), // 0x8; when set, user can set rotation, otherwise rotation is automatic
SMALL_SCENERY_FLAG_ANIMATED = (1 << 4), // 0x10
SMALL_SCENERY_FLAG_CAN_WITHER = (1 << 5), // 0x20
SMALL_SCENERY_FLAG_CAN_BE_WATERED = (1 << 6), // 0x40
SMALL_SCENERY_FLAG_ANIMATED_FG = (1 << 7), // 0x80
SMALL_SCENERY_FLAG_DIAGONAL = (1 << 8), // 0x100
SMALL_SCENERY_FLAG_HAS_GLASS = (1 << 9), // 0x200
SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR = (1 << 10), // 0x400
SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1 = (1 << 11), // 0x800
SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4 = (1 << 12), // 0x1000
SMALL_SCENERY_FLAG_IS_CLOCK = (1 << 13), // 0x2000
SMALL_SCENERY_FLAG_SWAMP_GOO = (1 << 14), // 0x4000
SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS = (1 << 15), // 0x8000
SMALL_SCENERY_FLAG17 = (1 << 16), // 0x10000
SMALL_SCENERY_FLAG_STACKABLE = (1 << 17), // 0x20000; means scenery item can be placed in the air and over water
SMALL_SCENERY_FLAG_NO_WALLS = (1 << 18), // 0x40000
SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR = (1 << 19), // 0x80000
SMALL_SCENERY_FLAG_NO_SUPPORTS = (1 << 20), // 0x100000
SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED = (1 << 21), // 0x200000
SMALL_SCENERY_FLAG_COG = (1 << 22), // 0x400000
SMALL_SCENERY_FLAG_BUILD_DIRECTLY_ONTOP = (1 << 23), // 0x800000; means supports can be built on this object. Used for base blocks.
SMALL_SCENERY_FLAG_HALF_SPACE = (1 << 24), // 0x1000000
SMALL_SCENERY_FLAG_THREE_QUARTERS = (1 << 25), // 0x2000000
SMALL_SCENERY_FLAG_PAINT_SUPPORTS = (1 << 26), // 0x4000000; used for scenery items which are support structures
SMALL_SCENERY_FLAG27 = (1 << 27), // 0x8000000
SMALL_SCENERY_FLAG_NO_SUPPORTS = (1 << 20), // 0x100000
SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED = (1 << 21), // 0x200000
SMALL_SCENERY_FLAG_COG = (1 << 22), // 0x400000
SMALL_SCENERY_FLAG_BUILD_DIRECTLY_ONTOP
= (1 << 23), // 0x800000; means supports can be built on this object. Used for base blocks.
SMALL_SCENERY_FLAG_HALF_SPACE = (1 << 24), // 0x1000000
SMALL_SCENERY_FLAG_THREE_QUARTERS = (1 << 25), // 0x2000000
SMALL_SCENERY_FLAG_PAINT_SUPPORTS = (1 << 26), // 0x4000000; used for scenery items which are support structures
SMALL_SCENERY_FLAG27 = (1 << 27), // 0x8000000
};
enum
@ -50,11 +51,11 @@ enum
MAP_ELEM_SMALL_SCENERY_COLOUR_FLAG_NEEDS_SUPPORTS = (1 << 5),
};
int32_t scenery_small_get_primary_colour(const rct_tile_element * tileElement);
int32_t scenery_small_get_secondary_colour(const rct_tile_element * tileElement);
void scenery_small_set_primary_colour(rct_tile_element * tileElement, uint32_t colour);
void scenery_small_set_secondary_colour(rct_tile_element * tileElement, uint32_t colour);
bool scenery_small_get_supports_needed(const rct_tile_element * tileElement);
void scenery_small_set_supports_needed(rct_tile_element * tileElement);
int32_t scenery_small_get_primary_colour(const rct_tile_element* tileElement);
int32_t scenery_small_get_secondary_colour(const rct_tile_element* tileElement);
void scenery_small_set_primary_colour(rct_tile_element* tileElement, uint32_t colour);
void scenery_small_set_secondary_colour(rct_tile_element* tileElement, uint32_t colour);
bool scenery_small_get_supports_needed(const rct_tile_element* tileElement);
void scenery_small_set_supports_needed(rct_tile_element* tileElement);
bool scenery_small_entry_has_flag(const rct_scenery_entry * sceneryEntry, uint32_t flags);
bool scenery_small_entry_has_flag(const rct_scenery_entry* sceneryEntry, uint32_t flags);

View File

@ -7,22 +7,24 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include <algorithm>
#include <cmath>
#include "../audio/audio.h"
#include "Sprite.h"
#include "../Cheats.h"
#include "../Game.h"
#include "../OpenRCT2.h"
#include "../audio/audio.h"
#include "../core/Crypt.h"
#include "../core/Guard.hpp"
#include "../core/Math.hpp"
#include "../core/Util.hpp"
#include "../Game.h"
#include "../interface/Viewport.h"
#include "../localisation/Date.h"
#include "../localisation/Localisation.h"
#include "../OpenRCT2.h"
#include "../scenario/Scenario.h"
#include "Fountain.h"
#include "Sprite.h"
#include <algorithm>
#include <cmath>
uint16_t gSpriteListHead[6];
uint16_t gSpriteListCount[6];
@ -34,29 +36,27 @@ static bool _spriteFlashingList[MAX_SPRITES];
uint16_t gSpriteSpatialIndex[0x10001];
const rct_string_id litterNames[12] = {
STR_LITTER_VOMIT,
STR_LITTER_VOMIT,
STR_SHOP_ITEM_SINGULAR_EMPTY_CAN,
STR_SHOP_ITEM_SINGULAR_RUBBISH,
STR_SHOP_ITEM_SINGULAR_EMPTY_BURGER_BOX,
STR_SHOP_ITEM_SINGULAR_EMPTY_CUP,
STR_SHOP_ITEM_SINGULAR_EMPTY_BOX,
STR_SHOP_ITEM_SINGULAR_EMPTY_BOTTLE,
STR_SHOP_ITEM_SINGULAR_EMPTY_BOWL_RED,
STR_SHOP_ITEM_SINGULAR_EMPTY_DRINK_CARTON,
STR_SHOP_ITEM_SINGULAR_EMPTY_JUICE_CUP,
STR_SHOP_ITEM_SINGULAR_EMPTY_BOWL_BLUE
};
const rct_string_id litterNames[12] = { STR_LITTER_VOMIT,
STR_LITTER_VOMIT,
STR_SHOP_ITEM_SINGULAR_EMPTY_CAN,
STR_SHOP_ITEM_SINGULAR_RUBBISH,
STR_SHOP_ITEM_SINGULAR_EMPTY_BURGER_BOX,
STR_SHOP_ITEM_SINGULAR_EMPTY_CUP,
STR_SHOP_ITEM_SINGULAR_EMPTY_BOX,
STR_SHOP_ITEM_SINGULAR_EMPTY_BOTTLE,
STR_SHOP_ITEM_SINGULAR_EMPTY_BOWL_RED,
STR_SHOP_ITEM_SINGULAR_EMPTY_DRINK_CARTON,
STR_SHOP_ITEM_SINGULAR_EMPTY_JUICE_CUP,
STR_SHOP_ITEM_SINGULAR_EMPTY_BOWL_BLUE };
static LocationXYZ16 _spritelocations1[MAX_SPRITES];
static LocationXYZ16 _spritelocations2[MAX_SPRITES];
static size_t GetSpatialIndexOffset(int32_t x, int32_t y);
rct_sprite *try_get_sprite(size_t spriteIndex)
rct_sprite* try_get_sprite(size_t spriteIndex)
{
rct_sprite * sprite = nullptr;
rct_sprite* sprite = nullptr;
if (spriteIndex < MAX_SPRITES)
{
sprite = &_spriteList[spriteIndex];
@ -64,7 +64,7 @@ rct_sprite *try_get_sprite(size_t spriteIndex)
return sprite;
}
rct_sprite *get_sprite(size_t sprite_idx)
rct_sprite* get_sprite(size_t sprite_idx)
{
openrct2_assert(sprite_idx < MAX_SPRITES, "Tried getting sprite %u", sprite_idx);
return &_spriteList[sprite_idx];
@ -76,20 +76,22 @@ uint16_t sprite_get_first_in_quadrant(int32_t x, int32_t y)
return gSpriteSpatialIndex[offset];
}
static void invalidate_sprite_max_zoom(rct_sprite *sprite, int32_t maxZoom)
static void invalidate_sprite_max_zoom(rct_sprite* sprite, int32_t maxZoom)
{
if (sprite->unknown.sprite_left == LOCATION_NULL) return;
if (sprite->unknown.sprite_left == LOCATION_NULL)
return;
for (int32_t i = 0; i < MAX_VIEWPORT_COUNT; i++) {
rct_viewport *viewport = &g_viewport_list[i];
if (viewport->width != 0 && viewport->zoom <= maxZoom) {
for (int32_t i = 0; i < MAX_VIEWPORT_COUNT; i++)
{
rct_viewport* viewport = &g_viewport_list[i];
if (viewport->width != 0 && viewport->zoom <= maxZoom)
{
viewport_invalidate(
viewport,
sprite->unknown.sprite_left,
sprite->unknown.sprite_top,
sprite->unknown.sprite_right,
sprite->unknown.sprite_bottom
);
sprite->unknown.sprite_bottom);
}
}
}
@ -107,7 +109,7 @@ void invalidate_sprite_0(rct_sprite* sprite)
* Invalidate sprite if at closest zoom or next zoom up from closest.
* rct2: 0x006EC53F
*/
void invalidate_sprite_1(rct_sprite *sprite)
void invalidate_sprite_1(rct_sprite* sprite)
{
invalidate_sprite_max_zoom(sprite, 1);
}
@ -118,7 +120,7 @@ void invalidate_sprite_1(rct_sprite *sprite)
*
* @param sprite (esi)
*/
void invalidate_sprite_2(rct_sprite *sprite)
void invalidate_sprite_2(rct_sprite* sprite)
{
invalidate_sprite_max_zoom(sprite, 2);
}
@ -132,7 +134,8 @@ void reset_sprite_list()
gSavedAge = 0;
memset(_spriteList, 0, sizeof(rct_sprite) * MAX_SPRITES);
for (int32_t i = 0; i < NUM_SPRITE_LISTS; i++) {
for (int32_t i = 0; i < NUM_SPRITE_LISTS; i++)
{
gSpriteListHead[i] = SPRITE_INDEX_NULL;
gSpriteListCount[i] = 0;
_spriteFlashingList[i] = false;
@ -140,18 +143,21 @@ void reset_sprite_list()
rct_sprite* previous_spr = (rct_sprite*)SPRITE_INDEX_NULL;
for (int32_t i = 0; i < MAX_SPRITES; ++i){
rct_sprite *spr = get_sprite(i);
for (int32_t i = 0; i < MAX_SPRITES; ++i)
{
rct_sprite* spr = get_sprite(i);
spr->unknown.sprite_identifier = SPRITE_IDENTIFIER_NULL;
spr->unknown.sprite_index = i;
spr->unknown.next = SPRITE_INDEX_NULL;
spr->unknown.linked_list_type_offset = 0;
if (previous_spr != (rct_sprite*)SPRITE_INDEX_NULL){
if (previous_spr != (rct_sprite*)SPRITE_INDEX_NULL)
{
spr->unknown.previous = previous_spr->unknown.sprite_index;
previous_spr->unknown.next = i;
}
else{
else
{
spr->unknown.previous = SPRITE_INDEX_NULL;
gSpriteListHead[SPRITE_LIST_NULL] = i;
}
@ -173,9 +179,11 @@ void reset_sprite_list()
void reset_sprite_spatial_index()
{
std::fill_n(gSpriteSpatialIndex, Util::CountOf(gSpriteSpatialIndex), SPRITE_INDEX_NULL);
for (size_t i = 0; i < MAX_SPRITES; i++) {
rct_sprite *spr = get_sprite(i);
if (spr->unknown.sprite_identifier != SPRITE_IDENTIFIER_NULL) {
for (size_t i = 0; i < MAX_SPRITES; i++)
{
rct_sprite* spr = get_sprite(i);
if (spr->unknown.sprite_identifier != SPRITE_IDENTIFIER_NULL)
{
size_t index = GetSpatialIndexOffset(spr->unknown.x, spr->unknown.y);
uint16_t nextSpriteId = gSpriteSpatialIndex[index];
gSpriteSpatialIndex[index] = spr->unknown.sprite_index;
@ -187,7 +195,8 @@ void reset_sprite_spatial_index()
static size_t GetSpatialIndexOffset(int32_t x, int32_t y)
{
size_t index = SPATIAL_INDEX_LOCATION_NULL;
if (x != LOCATION_NULL) {
if (x != LOCATION_NULL)
{
x = Math::Clamp(0, x, 0xFFFF);
y = Math::Clamp(0, y, 0xFFFF);
@ -202,7 +211,7 @@ static size_t GetSpatialIndexOffset(int32_t x, int32_t y)
#ifndef DISABLE_NETWORK
const char * sprite_checksum()
const char* sprite_checksum()
{
using namespace Crypt;
@ -222,7 +231,8 @@ const char * sprite_checksum()
for (size_t i = 0; i < MAX_SPRITES; i++)
{
auto sprite = get_sprite(i);
if (sprite->unknown.sprite_identifier != SPRITE_IDENTIFIER_NULL && sprite->unknown.sprite_identifier != SPRITE_IDENTIFIER_MISC)
if (sprite->unknown.sprite_identifier != SPRITE_IDENTIFIER_NULL
&& sprite->unknown.sprite_identifier != SPRITE_IDENTIFIER_MISC)
{
auto copy = *sprite;
copy.unknown.sprite_left = copy.unknown.sprite_right = copy.unknown.sprite_top = copy.unknown.sprite_bottom = 0;
@ -230,7 +240,8 @@ const char * sprite_checksum()
if (copy.unknown.sprite_identifier == SPRITE_IDENTIFIER_PEEP)
{
// We set this to 0 because as soon the client selects a guest the window will remove the
// invalidation flags causing the sprite checksum to be different than on server, the flag does not affect game state.
// invalidation flags causing the sprite checksum to be different than on server, the flag does not affect
// game state.
copy.peep.window_invalidate_flags = 0;
}
@ -258,14 +269,14 @@ const char * sprite_checksum()
}
#else
const char * sprite_checksum()
const char* sprite_checksum()
{
return nullptr;
}
#endif // DISABLE_NETWORK
static void sprite_reset(rct_unk_sprite *sprite)
static void sprite_reset(rct_unk_sprite* sprite)
{
// Need to retain how the sprite is linked in lists
uint8_t llto = sprite->linked_list_type_offset;
@ -286,16 +297,17 @@ static void sprite_reset(rct_unk_sprite *sprite)
}
/**
* Clears all the unused sprite memory to zero. Probably so that it can be compressed better when saving.
* rct2: 0x0069EBA4
*/
* Clears all the unused sprite memory to zero. Probably so that it can be compressed better when saving.
* rct2: 0x0069EBA4
*/
void sprite_clear_all_unused()
{
rct_unk_sprite *sprite;
rct_unk_sprite* sprite;
uint16_t spriteIndex, nextSpriteIndex;
spriteIndex = gSpriteListHead[SPRITE_LIST_NULL];
while (spriteIndex != SPRITE_INDEX_NULL) {
while (spriteIndex != SPRITE_INDEX_NULL)
{
sprite = &get_sprite(spriteIndex)->unknown;
nextSpriteIndex = sprite->next;
sprite_reset(sprite);
@ -308,33 +320,40 @@ void sprite_clear_all_unused()
// sprite->next_in_quadrant will only end up as zero owing to corruption
// most likely due to previous builds not preserving it when resetting sprites
// We reset it to SPRITE_INDEX_NULL to prevent cycles in the sprite lists
if (sprite->next_in_quadrant == 0) { sprite->next_in_quadrant = SPRITE_INDEX_NULL; }
if (sprite->next_in_quadrant == 0)
{
sprite->next_in_quadrant = SPRITE_INDEX_NULL;
}
_spriteFlashingList[spriteIndex] = false;
spriteIndex = nextSpriteIndex;
}
}
/*
* rct2: 0x0069EC6B
* bl: if bl & 2 > 0, the sprite ends up in the MISC linked list.
*/
rct_sprite *create_sprite(uint8_t bl)
* rct2: 0x0069EC6B
* bl: if bl & 2 > 0, the sprite ends up in the MISC linked list.
*/
rct_sprite* create_sprite(uint8_t bl)
{
size_t linkedListTypeOffset = SPRITE_LIST_UNKNOWN * 2;
if ((bl & 2) != 0) {
if ((bl & 2) != 0)
{
// 69EC96;
uint16_t cx = 0x12C - gSpriteListCount[SPRITE_LIST_MISC];
if (cx >= gSpriteListCount[SPRITE_LIST_NULL]) {
if (cx >= gSpriteListCount[SPRITE_LIST_NULL])
{
return nullptr;
}
linkedListTypeOffset = SPRITE_LIST_MISC * 2;
} else if (gSpriteListCount[SPRITE_LIST_NULL] == 0) {
}
else if (gSpriteListCount[SPRITE_LIST_NULL] == 0)
{
return nullptr;
}
rct_unk_sprite *sprite = &(get_sprite(gSpriteListHead[SPRITE_LIST_NULL]))->unknown;
rct_unk_sprite* sprite = &(get_sprite(gSpriteListHead[SPRITE_LIST_NULL]))->unknown;
move_sprite_to_list((rct_sprite *)sprite, (uint8_t)linkedListTypeOffset);
move_sprite_to_list((rct_sprite*)sprite, (uint8_t)linkedListTypeOffset);
// Need to reset all sprite data, as the uninitialised values
// may contain garbage and cause a desync later on.
@ -363,36 +382,41 @@ rct_sprite *create_sprite(uint8_t bl)
* of the desired linked list in a uint16_t array. Known valid values are
* 2, 4, 6, 8 or 10 (SPRITE_LIST_... * 2)
*/
void move_sprite_to_list(rct_sprite *sprite, uint8_t newListOffset)
void move_sprite_to_list(rct_sprite* sprite, uint8_t newListOffset)
{
rct_unk_sprite *unkSprite = &sprite->unknown;
rct_unk_sprite* unkSprite = &sprite->unknown;
uint8_t oldListOffset = unkSprite->linked_list_type_offset;
int32_t oldList = oldListOffset >> 1;
int32_t newList = newListOffset >> 1;
// No need to move if the sprite is already in the desired list
if (oldListOffset == newListOffset) {
if (oldListOffset == newListOffset)
{
return;
}
// If the sprite is currently the head of the list, the
// sprite following this one becomes the new head of the list.
if (unkSprite->previous == SPRITE_INDEX_NULL) {
if (unkSprite->previous == SPRITE_INDEX_NULL)
{
gSpriteListHead[oldList] = unkSprite->next;
} else {
}
else
{
// Hook up sprite->previous->next to sprite->next, removing the sprite from its old list
get_sprite(unkSprite->previous)->unknown.next = unkSprite->next;
}
// Similarly, hook up sprite->next->previous to sprite->previous
if (unkSprite->next != SPRITE_INDEX_NULL) {
if (unkSprite->next != SPRITE_INDEX_NULL)
{
get_sprite(unkSprite->next)->unknown.previous = unkSprite->previous;
}
unkSprite->previous = SPRITE_INDEX_NULL; // We become the new head of the target list, so there's no previous sprite
unkSprite->linked_list_type_offset = newListOffset;
unkSprite->next = gSpriteListHead[newList]; // This sprite's next sprite is the old head, since we're the new head
unkSprite->next = gSpriteListHead[newList]; // This sprite's next sprite is the old head, since we're the new head
gSpriteListHead[newList] = unkSprite->sprite_index; // Store this sprite's index as head of its new list
if (unkSprite->next != SPRITE_INDEX_NULL)
@ -411,23 +435,20 @@ void move_sprite_to_list(rct_sprite *sprite, uint8_t newListOffset)
*
* rct2: 0x00673200
*/
static void sprite_steam_particle_update(rct_steam_particle *steam)
static void sprite_steam_particle_update(rct_steam_particle* steam)
{
invalidate_sprite_2((rct_sprite*)steam);
// Move up 1 z every 3 ticks (Starts after 4 ticks)
steam->time_to_move++;
if (steam->time_to_move >= 4) {
if (steam->time_to_move >= 4)
{
steam->time_to_move = 1;
sprite_move(
steam->x,
steam->y,
steam->z + 1,
(rct_sprite*)steam
);
sprite_move(steam->x, steam->y, steam->z + 1, (rct_sprite*)steam);
}
steam->frame += 64;
if (steam->frame >= (56 * 64)) {
if (steam->frame >= (56 * 64))
{
sprite_remove((rct_sprite*)steam);
}
}
@ -438,8 +459,9 @@ static void sprite_steam_particle_update(rct_steam_particle *steam)
*/
void sprite_misc_explosion_cloud_create(int32_t x, int32_t y, int32_t z)
{
rct_unk_sprite *sprite = (rct_unk_sprite*)create_sprite(2);
if (sprite != nullptr) {
rct_unk_sprite* sprite = (rct_unk_sprite*)create_sprite(2);
if (sprite != nullptr)
{
sprite->sprite_width = 44;
sprite->sprite_height_negative = 32;
sprite->sprite_height_positive = 34;
@ -454,11 +476,12 @@ void sprite_misc_explosion_cloud_create(int32_t x, int32_t y, int32_t z)
*
* rct2: 0x00673385
*/
static void sprite_misc_explosion_cloud_update(rct_sprite * sprite)
static void sprite_misc_explosion_cloud_update(rct_sprite* sprite)
{
invalidate_sprite_2(sprite);
sprite->unknown.frame += 128;
if (sprite->unknown.frame >= (36 * 128)) {
if (sprite->unknown.frame >= (36 * 128))
{
sprite_remove(sprite);
}
}
@ -469,8 +492,9 @@ static void sprite_misc_explosion_cloud_update(rct_sprite * sprite)
*/
void sprite_misc_explosion_flare_create(int32_t x, int32_t y, int32_t z)
{
rct_unk_sprite *sprite = (rct_unk_sprite*)create_sprite(2);
if (sprite != nullptr) {
rct_unk_sprite* sprite = (rct_unk_sprite*)create_sprite(2);
if (sprite != nullptr)
{
sprite->sprite_width = 25;
sprite->sprite_height_negative = 85;
sprite->sprite_height_positive = 8;
@ -485,11 +509,12 @@ void sprite_misc_explosion_flare_create(int32_t x, int32_t y, int32_t z)
*
* rct2: 0x006733B4
*/
static void sprite_misc_explosion_flare_update(rct_sprite * sprite)
static void sprite_misc_explosion_flare_update(rct_sprite* sprite)
{
invalidate_sprite_2(sprite);
sprite->unknown.frame += 64;
if (sprite->unknown.frame >= (124 * 64)) {
if (sprite->unknown.frame >= (124 * 64))
{
sprite_remove(sprite);
}
}
@ -498,37 +523,38 @@ static void sprite_misc_explosion_flare_update(rct_sprite * sprite)
*
* rct2: 0x006731CD
*/
static void sprite_misc_update(rct_sprite *sprite)
static void sprite_misc_update(rct_sprite* sprite)
{
switch (sprite->unknown.misc_identifier) {
case SPRITE_MISC_STEAM_PARTICLE:
sprite_steam_particle_update((rct_steam_particle*)sprite);
break;
case SPRITE_MISC_MONEY_EFFECT:
money_effect_update(&sprite->money_effect);
break;
case SPRITE_MISC_CRASHED_VEHICLE_PARTICLE:
crashed_vehicle_particle_update((rct_crashed_vehicle_particle*)sprite);
break;
case SPRITE_MISC_EXPLOSION_CLOUD:
sprite_misc_explosion_cloud_update(sprite);
break;
case SPRITE_MISC_CRASH_SPLASH:
crash_splash_update((rct_crash_splash*)sprite);
break;
case SPRITE_MISC_EXPLOSION_FLARE:
sprite_misc_explosion_flare_update(sprite);
break;
case SPRITE_MISC_JUMPING_FOUNTAIN_WATER:
case SPRITE_MISC_JUMPING_FOUNTAIN_SNOW:
jumping_fountain_update(&sprite->jumping_fountain);
break;
case SPRITE_MISC_BALLOON:
balloon_update(&sprite->balloon);
break;
case SPRITE_MISC_DUCK:
duck_update(&sprite->duck);
break;
switch (sprite->unknown.misc_identifier)
{
case SPRITE_MISC_STEAM_PARTICLE:
sprite_steam_particle_update((rct_steam_particle*)sprite);
break;
case SPRITE_MISC_MONEY_EFFECT:
money_effect_update(&sprite->money_effect);
break;
case SPRITE_MISC_CRASHED_VEHICLE_PARTICLE:
crashed_vehicle_particle_update((rct_crashed_vehicle_particle*)sprite);
break;
case SPRITE_MISC_EXPLOSION_CLOUD:
sprite_misc_explosion_cloud_update(sprite);
break;
case SPRITE_MISC_CRASH_SPLASH:
crash_splash_update((rct_crash_splash*)sprite);
break;
case SPRITE_MISC_EXPLOSION_FLARE:
sprite_misc_explosion_flare_update(sprite);
break;
case SPRITE_MISC_JUMPING_FOUNTAIN_WATER:
case SPRITE_MISC_JUMPING_FOUNTAIN_SNOW:
jumping_fountain_update(&sprite->jumping_fountain);
break;
case SPRITE_MISC_BALLOON:
balloon_update(&sprite->balloon);
break;
case SPRITE_MISC_DUCK:
duck_update(&sprite->duck);
break;
}
}
@ -538,11 +564,12 @@ static void sprite_misc_update(rct_sprite *sprite)
*/
void sprite_misc_update_all()
{
rct_sprite *sprite;
rct_sprite* sprite;
uint16_t spriteIndex;
spriteIndex = gSpriteListHead[SPRITE_LIST_MISC];
while (spriteIndex != SPRITE_INDEX_NULL) {
while (spriteIndex != SPRITE_INDEX_NULL)
{
sprite = get_sprite(spriteIndex);
spriteIndex = sprite->unknown.next;
sprite_misc_update(sprite);
@ -558,21 +585,26 @@ void sprite_misc_update_all()
* @param z (dx)
* @param sprite (esi)
*/
void sprite_move(int16_t x, int16_t y, int16_t z, rct_sprite *sprite)
void sprite_move(int16_t x, int16_t y, int16_t z, rct_sprite* sprite)
{
if (x < 0 || y < 0 || x > 0x1FFF || y > 0x1FFF) {
if (x < 0 || y < 0 || x > 0x1FFF || y > 0x1FFF)
{
x = LOCATION_NULL;
}
size_t newIndex = GetSpatialIndexOffset(x, y);
size_t currentIndex = GetSpatialIndexOffset(sprite->unknown.x, sprite->unknown.y);
if (newIndex != currentIndex) {
uint16_t *spriteIndex = &gSpriteSpatialIndex[currentIndex];
if (*spriteIndex != SPRITE_INDEX_NULL) {
rct_sprite *sprite2 = get_sprite(*spriteIndex);
while (sprite != sprite2) {
if (newIndex != currentIndex)
{
uint16_t* spriteIndex = &gSpriteSpatialIndex[currentIndex];
if (*spriteIndex != SPRITE_INDEX_NULL)
{
rct_sprite* sprite2 = get_sprite(*spriteIndex);
while (sprite != sprite2)
{
spriteIndex = &sprite2->unknown.next_in_quadrant;
if (*spriteIndex == SPRITE_INDEX_NULL) {
if (*spriteIndex == SPRITE_INDEX_NULL)
{
break;
}
sprite2 = get_sprite(*spriteIndex);
@ -585,35 +617,40 @@ void sprite_move(int16_t x, int16_t y, int16_t z, rct_sprite *sprite)
sprite->unknown.next_in_quadrant = tempSpriteIndex;
}
if (x == LOCATION_NULL) {
if (x == LOCATION_NULL)
{
sprite->unknown.sprite_left = LOCATION_NULL;
sprite->unknown.x = x;
sprite->unknown.y = y;
sprite->unknown.z = z;
} else {
}
else
{
sprite_set_coordinates(x, y, z, sprite);
}
}
void sprite_set_coordinates(int16_t x, int16_t y, int16_t z, rct_sprite *sprite){
void sprite_set_coordinates(int16_t x, int16_t y, int16_t z, rct_sprite* sprite)
{
int16_t new_x = x, new_y = y, start_x = x;
switch (get_current_rotation()){
case 0:
new_x = new_y - new_x;
new_y = (new_y + start_x) / 2 - z;
break;
case 1:
new_x = -new_y - new_x;
new_y = (new_y - start_x) / 2 - z;
break;
case 2:
new_x = -new_y + new_x;
new_y = (-new_y - start_x) / 2 - z;
break;
case 3:
new_x = new_y + new_x;
new_y = (-new_y + start_x) / 2 - z;
break;
switch (get_current_rotation())
{
case 0:
new_x = new_y - new_x;
new_y = (new_y + start_x) / 2 - z;
break;
case 1:
new_x = -new_y - new_x;
new_y = (new_y - start_x) / 2 - z;
break;
case 2:
new_x = -new_y + new_x;
new_y = (-new_y - start_x) / 2 - z;
break;
case 3:
new_x = new_y + new_x;
new_y = (-new_y + start_x) / 2 - z;
break;
}
sprite->unknown.sprite_left = new_x - sprite->unknown.sprite_width;
@ -629,7 +666,7 @@ void sprite_set_coordinates(int16_t x, int16_t y, int16_t z, rct_sprite *sprite)
*
* rct2: 0x0069EDB6
*/
void sprite_remove(rct_sprite *sprite)
void sprite_remove(rct_sprite* sprite)
{
move_sprite_to_list(sprite, SPRITE_LIST_NULL * 2);
user_string_free(sprite->unknown.name_string_idx);
@ -637,8 +674,8 @@ void sprite_remove(rct_sprite *sprite)
_spriteFlashingList[sprite->unknown.sprite_index] = false;
size_t quadrantIndex = GetSpatialIndexOffset(sprite->unknown.x, sprite->unknown.y);
uint16_t *spriteIndex = &gSpriteSpatialIndex[quadrantIndex];
rct_sprite *quadrantSprite;
uint16_t* spriteIndex = &gSpriteSpatialIndex[quadrantIndex];
rct_sprite* quadrantSprite;
while (*spriteIndex != SPRITE_INDEX_NULL && (quadrantSprite = get_sprite(*spriteIndex)) != sprite)
{
spriteIndex = &quadrantSprite->unknown.next_in_quadrant;
@ -648,13 +685,14 @@ void sprite_remove(rct_sprite *sprite)
static bool litter_can_be_at(int32_t x, int32_t y, int32_t z)
{
rct_tile_element *tileElement;
rct_tile_element* tileElement;
if (!map_is_location_owned(x & 0xFFE0, y & 0xFFE0, z))
return false;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do {
do
{
if (tileElement->GetType() != TILE_ELEMENT_TYPE_PATH)
continue;
@ -685,25 +723,30 @@ void litter_create(int32_t x, int32_t y, int32_t z, int32_t direction, int32_t t
if (!litter_can_be_at(x, y, z))
return;
if (gSpriteListCount[SPRITE_LIST_LITTER] >= 500) {
rct_litter *newestLitter = nullptr;
if (gSpriteListCount[SPRITE_LIST_LITTER] >= 500)
{
rct_litter* newestLitter = nullptr;
uint32_t newestLitterCreationTick = 0;
for (uint16_t nextSpriteIndex, spriteIndex = gSpriteListHead[SPRITE_LIST_LITTER]; spriteIndex != SPRITE_INDEX_NULL; spriteIndex = nextSpriteIndex) {
rct_litter *litter = &get_sprite(spriteIndex)->litter;
for (uint16_t nextSpriteIndex, spriteIndex = gSpriteListHead[SPRITE_LIST_LITTER]; spriteIndex != SPRITE_INDEX_NULL;
spriteIndex = nextSpriteIndex)
{
rct_litter* litter = &get_sprite(spriteIndex)->litter;
nextSpriteIndex = litter->next;
if (newestLitterCreationTick <= litter->creationTick) {
if (newestLitterCreationTick <= litter->creationTick)
{
newestLitterCreationTick = litter->creationTick;
newestLitter = litter;
}
}
if (newestLitter != nullptr) {
if (newestLitter != nullptr)
{
invalidate_sprite_0((rct_sprite*)newestLitter);
sprite_remove((rct_sprite*)newestLitter);
}
}
rct_litter *litter = (rct_litter*)create_sprite(1);
rct_litter* litter = (rct_litter*)create_sprite(1);
if (litter == nullptr)
return;
@ -726,14 +769,18 @@ void litter_create(int32_t x, int32_t y, int32_t z, int32_t direction, int32_t t
void litter_remove_at(int32_t x, int32_t y, int32_t z)
{
uint16_t spriteIndex = sprite_get_first_in_quadrant(x, y);
while (spriteIndex != SPRITE_INDEX_NULL) {
rct_sprite *sprite = get_sprite(spriteIndex);
while (spriteIndex != SPRITE_INDEX_NULL)
{
rct_sprite* sprite = get_sprite(spriteIndex);
uint16_t nextSpriteIndex = sprite->unknown.next_in_quadrant;
if (sprite->unknown.linked_list_type_offset == SPRITE_LIST_LITTER * 2) {
rct_litter *litter = &sprite->litter;
if (sprite->unknown.linked_list_type_offset == SPRITE_LIST_LITTER * 2)
{
rct_litter* litter = &sprite->litter;
if (abs(litter->z - z) <= 16) {
if (abs(litter->x - x) <= 8 && abs(litter->y - y) <= 8) {
if (abs(litter->z - z) <= 16)
{
if (abs(litter->x - x) <= 8 && abs(litter->y - y) <= 8)
{
invalidate_sprite_0(sprite);
sprite_remove(sprite);
}
@ -746,23 +793,25 @@ void litter_remove_at(int32_t x, int32_t y, int32_t z)
/**
* Determines whether it's worth tweening a sprite or not when frame smoothing is on.
*/
static bool sprite_should_tween(rct_sprite *sprite)
static bool sprite_should_tween(rct_sprite* sprite)
{
switch (sprite->unknown.linked_list_type_offset >> 1) {
case SPRITE_LIST_TRAIN:
case SPRITE_LIST_PEEP:
case SPRITE_LIST_UNKNOWN:
return true;
switch (sprite->unknown.linked_list_type_offset >> 1)
{
case SPRITE_LIST_TRAIN:
case SPRITE_LIST_PEEP:
case SPRITE_LIST_UNKNOWN:
return true;
}
return false;
}
static void store_sprite_locations(LocationXYZ16 * sprite_locations)
static void store_sprite_locations(LocationXYZ16* sprite_locations)
{
for (uint16_t i = 0; i < MAX_SPRITES; i++) {
for (uint16_t i = 0; i < MAX_SPRITES; i++)
{
// skip going through `get_sprite` to not get stalled on assert,
// this can get very expensive for busy parks with uncap FPS option on
const rct_sprite *sprite = &_spriteList[i];
const rct_sprite* sprite = &_spriteList[i];
sprite_locations[i].x = sprite->unknown.x;
sprite_locations[i].y = sprite->unknown.y;
sprite_locations[i].z = sprite->unknown.z;
@ -783,20 +832,22 @@ void sprite_position_tween_all(float alpha)
{
const float inv = (1.0f - alpha);
for (uint16_t i = 0; i < MAX_SPRITES; i++) {
rct_sprite * sprite = get_sprite(i);
if (sprite_should_tween(sprite)) {
for (uint16_t i = 0; i < MAX_SPRITES; i++)
{
rct_sprite* sprite = get_sprite(i);
if (sprite_should_tween(sprite))
{
LocationXYZ16 posA = _spritelocations1[i];
LocationXYZ16 posB = _spritelocations2[i];
if (posA.x == posB.x && posA.y == posB.y && posA.z == posB.z) {
if (posA.x == posB.x && posA.y == posB.y && posA.z == posB.z)
{
continue;
}
sprite_set_coordinates(
std::round(posB.x * alpha + posA.x * inv),
std::round(posB.y * alpha + posA.y * inv),
std::round(posB.z * alpha + posA.z * inv),
sprite
);
sprite);
invalidate_sprite_2(sprite);
}
}
@ -807,9 +858,11 @@ void sprite_position_tween_all(float alpha)
*/
void sprite_position_tween_restore()
{
for (uint16_t i = 0; i < MAX_SPRITES; i++) {
rct_sprite * sprite = get_sprite(i);
if (sprite_should_tween(sprite)) {
for (uint16_t i = 0; i < MAX_SPRITES; i++)
{
rct_sprite* sprite = get_sprite(i);
if (sprite_should_tween(sprite))
{
invalidate_sprite_2(sprite);
LocationXYZ16 pos = _spritelocations2[i];
@ -820,39 +873,37 @@ void sprite_position_tween_restore()
void sprite_position_tween_reset()
{
for (uint16_t i = 0; i < MAX_SPRITES; i++) {
rct_sprite * sprite = get_sprite(i);
_spritelocations1[i].x =
_spritelocations2[i].x = sprite->unknown.x;
_spritelocations1[i].y =
_spritelocations2[i].y = sprite->unknown.y;
_spritelocations1[i].z =
_spritelocations2[i].z = sprite->unknown.z;
for (uint16_t i = 0; i < MAX_SPRITES; i++)
{
rct_sprite* sprite = get_sprite(i);
_spritelocations1[i].x = _spritelocations2[i].x = sprite->unknown.x;
_spritelocations1[i].y = _spritelocations2[i].y = sprite->unknown.y;
_spritelocations1[i].z = _spritelocations2[i].z = sprite->unknown.z;
}
}
void sprite_set_flashing(rct_sprite *sprite, bool flashing)
void sprite_set_flashing(rct_sprite* sprite, bool flashing)
{
assert(sprite->unknown.sprite_index < MAX_SPRITES);
_spriteFlashingList[sprite->unknown.sprite_index] = flashing;
}
bool sprite_get_flashing(rct_sprite *sprite)
bool sprite_get_flashing(rct_sprite* sprite)
{
assert(sprite->unknown.sprite_index < MAX_SPRITES);
return _spriteFlashingList[sprite->unknown.sprite_index];
}
static rct_sprite * find_sprite_list_cycle(uint16_t sprite_idx)
static rct_sprite* find_sprite_list_cycle(uint16_t sprite_idx)
{
if (sprite_idx == SPRITE_INDEX_NULL)
{
return nullptr;
}
const rct_sprite * fast = get_sprite(sprite_idx);
const rct_sprite * slow = fast;
const rct_sprite* fast = get_sprite(sprite_idx);
const rct_sprite* slow = fast;
bool increment_slow = false;
rct_sprite * cycle_start = nullptr;
rct_sprite* cycle_start = nullptr;
while (fast->unknown.sprite_index != SPRITE_INDEX_NULL)
{
// increment fast every time, unless reached the end
@ -860,7 +911,8 @@ static rct_sprite * find_sprite_list_cycle(uint16_t sprite_idx)
{
break;
}
else {
else
{
fast = get_sprite(fast->unknown.next);
}
// increment slow only every second iteration
@ -878,16 +930,16 @@ static rct_sprite * find_sprite_list_cycle(uint16_t sprite_idx)
return cycle_start;
}
static rct_sprite * find_sprite_quadrant_cycle(uint16_t sprite_idx)
static rct_sprite* find_sprite_quadrant_cycle(uint16_t sprite_idx)
{
if (sprite_idx == SPRITE_INDEX_NULL)
{
return nullptr;
}
const rct_sprite * fast = get_sprite(sprite_idx);
const rct_sprite * slow = fast;
const rct_sprite* fast = get_sprite(sprite_idx);
const rct_sprite* slow = fast;
bool increment_slow = false;
rct_sprite * cycle_start = nullptr;
rct_sprite* cycle_start = nullptr;
while (fast->unknown.sprite_index != SPRITE_INDEX_NULL)
{
// increment fast every time, unless reached the end
@ -895,7 +947,8 @@ static rct_sprite * find_sprite_quadrant_cycle(uint16_t sprite_idx)
{
break;
}
else {
else
{
fast = get_sprite(fast->unknown.next_in_quadrant);
}
// increment slow only every second iteration
@ -929,8 +982,9 @@ static bool index_is_in_list(uint16_t index, enum SPRITE_LIST sl)
int32_t check_for_sprite_list_cycles(bool fix)
{
for (int32_t i = 0; i < NUM_SPRITE_LISTS; i++) {
rct_sprite * cycle_start = find_sprite_list_cycle(gSpriteListHead[i]);
for (int32_t i = 0; i < NUM_SPRITE_LISTS; i++)
{
rct_sprite* cycle_start = find_sprite_list_cycle(gSpriteListHead[i]);
if (cycle_start != nullptr)
{
if (fix)
@ -949,7 +1003,7 @@ int32_t check_for_sprite_list_cycles(bool fix)
// Add each sprite to the list until we encounter one that is already part of the list.
while (!index_is_in_list(cycle_next, (SPRITE_LIST)i))
{
rct_sprite * spr = get_sprite(cycle_next);
rct_sprite* spr = get_sprite(cycle_next);
cycle_start->unknown.next = cycle_next;
spr->unknown.previous = cycle_start->unknown.sprite_index;
@ -957,7 +1011,6 @@ int32_t check_for_sprite_list_cycles(bool fix)
spr->unknown.next = SPRITE_INDEX_NULL;
cycle_start = spr;
}
}
return i;
}
@ -975,7 +1028,7 @@ int32_t fix_disjoint_sprites()
// Find reachable sprites
bool reachable[MAX_SPRITES] = { false };
uint16_t sprite_idx = gSpriteListHead[SPRITE_LIST_NULL];
rct_sprite * null_list_tail = nullptr;
rct_sprite* null_list_tail = nullptr;
while (sprite_idx != SPRITE_INDEX_NULL)
{
reachable[sprite_idx] = true;
@ -989,7 +1042,7 @@ int32_t fix_disjoint_sprites()
// Find all null sprites
for (sprite_idx = 0; sprite_idx < MAX_SPRITES; sprite_idx++)
{
rct_sprite * spr = get_sprite(sprite_idx);
rct_sprite* spr = get_sprite(sprite_idx);
if (spr->unknown.sprite_identifier == SPRITE_IDENTIFIER_NULL)
{
openrct2_assert(null_list_tail != nullptr, "Null list is empty, yet found null sprites");
@ -1011,8 +1064,9 @@ int32_t fix_disjoint_sprites()
int32_t check_for_spatial_index_cycles(bool fix)
{
for (int32_t i = 0; i < SPATIAL_INDEX_LOCATION_NULL; i++) {
rct_sprite * cycle_start = find_sprite_quadrant_cycle(gSpriteSpatialIndex[i]);
for (int32_t i = 0; i < SPATIAL_INDEX_LOCATION_NULL; i++)
{
rct_sprite* cycle_start = find_sprite_quadrant_cycle(gSpriteSpatialIndex[i]);
if (cycle_start != nullptr)
{
if (fix)
@ -1027,7 +1081,7 @@ int32_t check_for_spatial_index_cycles(bool fix)
// Add each sprite to the list until we encounter one that is already part of the list.
while (!index_is_in_list(cycle_next, (SPRITE_LIST)i))
{
rct_sprite * spr = get_sprite(cycle_next);
rct_sprite* spr = get_sprite(cycle_next);
cycle_start->unknown.next_in_quadrant = cycle_next;
cycle_next = spr->unknown.next_in_quadrant;

View File

@ -14,11 +14,12 @@
#include "../peep/Peep.h"
#include "../ride/Vehicle.h"
#define SPRITE_INDEX_NULL 0xFFFF
#define MAX_SPRITES 10000
#define NUM_SPRITE_LISTS 6
#define SPRITE_INDEX_NULL 0xFFFF
#define MAX_SPRITES 10000
#define NUM_SPRITE_LISTS 6
enum SPRITE_IDENTIFIER {
enum SPRITE_IDENTIFIER
{
SPRITE_IDENTIFIER_VEHICLE = 0,
SPRITE_IDENTIFIER_PEEP = 1,
SPRITE_IDENTIFIER_MISC = 2,
@ -26,7 +27,8 @@ enum SPRITE_IDENTIFIER {
SPRITE_IDENTIFIER_NULL = 255
};
enum SPRITE_LIST {
enum SPRITE_LIST
{
SPRITE_LIST_NULL,
SPRITE_LIST_TRAIN,
SPRITE_LIST_PEEP,
@ -36,79 +38,82 @@ enum SPRITE_LIST {
};
#pragma pack(push, 1)
struct rct_unk_sprite {
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
struct rct_unk_sprite
{
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
// Height from centre of sprite to bottom
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
// Width from centre of sprite to edge
uint8_t sprite_width; // 0x14
uint8_t sprite_width; // 0x14
// Height from centre of sprite to top
uint8_t sprite_height_positive; // 0x15
int16_t sprite_left; // 0x16
int16_t sprite_top; // 0x18
int16_t sprite_right; // 0x1A
int16_t sprite_bottom; // 0x1C
uint8_t sprite_direction; // 0x1e
uint8_t sprite_height_positive; // 0x15
int16_t sprite_left; // 0x16
int16_t sprite_top; // 0x18
int16_t sprite_right; // 0x1A
int16_t sprite_bottom; // 0x1C
uint8_t sprite_direction; // 0x1e
uint8_t pad_1F[3];
rct_string_id name_string_idx; // 0x22
rct_string_id name_string_idx; // 0x22
uint16_t pad_24;
uint16_t frame; // 0x26
uint16_t frame; // 0x26
};
assert_struct_size(rct_unk_sprite, 0x28);
struct rct_litter {
uint8_t sprite_identifier; // 0x00
uint8_t type; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
struct rct_litter
{
uint8_t sprite_identifier; // 0x00
uint8_t type; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
uint8_t sprite_width; // 0x14
uint8_t sprite_height_positive; // 0x15
uint8_t sprite_width; // 0x14
uint8_t sprite_height_positive; // 0x15
uint8_t pad_16[8];
uint8_t sprite_direction; // 0x1E
uint8_t sprite_direction; // 0x1E
uint8_t pad_1F[5];
uint32_t creationTick; // 0x24
uint32_t creationTick; // 0x24
};
assert_struct_size(rct_litter, 0x28);
struct rct_balloon {
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
struct rct_balloon
{
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
uint8_t sprite_width; // 0x14
uint8_t sprite_height_positive; // 0x15
uint8_t sprite_width; // 0x14
uint8_t sprite_height_positive; // 0x15
uint8_t pad_16[0xE];
uint16_t popped; // 0x24
uint8_t time_to_move; // 0x26
uint8_t frame; // 0x27
uint16_t popped; // 0x24
uint8_t time_to_move; // 0x26
uint8_t frame; // 0x27
uint8_t pad_28[4];
uint8_t colour; // 0x2C
uint8_t colour; // 0x2C
void Update();
void Pop();
@ -116,30 +121,31 @@ struct rct_balloon {
};
assert_struct_size(rct_balloon, 0x2D);
struct rct_duck {
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
struct rct_duck
{
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
uint8_t sprite_width; // 0x14
uint8_t sprite_height_positive; // 0x15
uint8_t sprite_width; // 0x14
uint8_t sprite_height_positive; // 0x15
uint8_t pad_16[0x8];
uint8_t sprite_direction; // 0x1E
uint8_t sprite_direction; // 0x1E
uint8_t pad_1F[0x7];
uint16_t frame;
uint8_t pad_28[0x8];
int16_t target_x; // 0x30
int16_t target_y; // 0x32
int16_t target_x; // 0x30
int16_t target_y; // 0x32
uint8_t pad_34[0x14];
uint8_t state; // 0x48
uint8_t state; // 0x48
void UpdateFlyToWater();
void UpdateSwim();
@ -150,162 +156,166 @@ struct rct_duck {
void Invalidate();
void Remove();
void MoveTo(int16_t x, int16_t y, int16_t z);
};
assert_struct_size(rct_duck, 0x49);
struct rct_jumping_fountain {
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
struct rct_jumping_fountain
{
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8_t sprite_height_negative;
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
uint8_t sprite_width; // 0x14
uint8_t sprite_height_positive; // 0x15
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
uint8_t sprite_width; // 0x14
uint8_t sprite_height_positive; // 0x15
uint8_t pad_16[0x8];
uint8_t sprite_direction; // 0x1E
uint8_t sprite_direction; // 0x1E
uint8_t pad_1F[0x7];
uint8_t num_ticks_alive; // 0x26
uint8_t frame; // 0x27
uint8_t pad_28[0x7]; // 0x28 Originally var_2E was set to direction but it was unused.
uint8_t fountain_flags; // 0x2F
int16_t target_x; // 0x30
int16_t target_y; // 0x32
uint8_t num_ticks_alive; // 0x26
uint8_t frame; // 0x27
uint8_t pad_28[0x7]; // 0x28 Originally var_2E was set to direction but it was unused.
uint8_t fountain_flags; // 0x2F
int16_t target_x; // 0x30
int16_t target_y; // 0x32
uint8_t pad_34[0x12];
uint16_t iteration; // 0x46
uint16_t iteration; // 0x46
};
assert_struct_size(rct_jumping_fountain, 0x48);
struct rct_money_effect {
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
struct rct_money_effect
{
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8_t sprite_height_negative;
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
uint8_t sprite_width; // 0x14
uint8_t sprite_height_positive; // 0x15
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
uint8_t sprite_width; // 0x14
uint8_t sprite_height_positive; // 0x15
uint8_t pad_16[0xE];
uint16_t move_delay; // 0x24
uint8_t num_movements; // 0x26
uint16_t move_delay; // 0x24
uint8_t num_movements; // 0x26
uint8_t vertical;
money32 value; // 0x28
money32 value; // 0x28
uint8_t pad_2C[0x18];
int16_t offset_x; // 0x44
uint16_t wiggle; // 0x46
int16_t offset_x; // 0x44
uint16_t wiggle; // 0x46
};
assert_struct_size(rct_money_effect, 0x48);
struct rct_crashed_vehicle_particle {
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
struct rct_crashed_vehicle_particle
{
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
// Height from centre of sprite to bottom
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
// Width from centre of sprite to edge
uint8_t sprite_width; // 0x14
uint8_t sprite_width; // 0x14
// Height from centre of sprite to top
uint8_t sprite_height_positive; // 0x15
int16_t sprite_left; // 0x16
int16_t sprite_top; // 0x18
int16_t sprite_right; // 0x1A
int16_t sprite_bottom; // 0x1C
uint8_t sprite_direction; //direction of sprite? 0x1e
uint8_t pad_1F[3]; // 0x1f
uint16_t name_string_idx; // 0x22
uint16_t time_to_live; // 0x24
uint16_t frame; // 0x26
uint8_t sprite_height_positive; // 0x15
int16_t sprite_left; // 0x16
int16_t sprite_top; // 0x18
int16_t sprite_right; // 0x1A
int16_t sprite_bottom; // 0x1C
uint8_t sprite_direction; // direction of sprite? 0x1e
uint8_t pad_1F[3]; // 0x1f
uint16_t name_string_idx; // 0x22
uint16_t time_to_live; // 0x24
uint16_t frame; // 0x26
uint8_t pad_28[4];
uint8_t colour[2];
uint16_t crashed_sprite_base; // 0x2E
int16_t velocity_x; // 0x30
int16_t velocity_y; // 0x32
int16_t velocity_z; // 0x34
uint16_t crashed_sprite_base; // 0x2E
int16_t velocity_x; // 0x30
int16_t velocity_y; // 0x32
int16_t velocity_z; // 0x34
uint16_t pad_36;
int32_t acceleration_x; // 0x38
int32_t acceleration_y; // 0x3C
int32_t acceleration_z; // 0x40
int32_t acceleration_x; // 0x38
int32_t acceleration_y; // 0x3C
int32_t acceleration_z; // 0x40
};
assert_struct_size(rct_crashed_vehicle_particle, 0x44);
struct rct_crash_splash {
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
struct rct_crash_splash
{
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
// Height from centre of sprite to bottom
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
// Width from centre of sprite to edge
uint8_t sprite_width; // 0x14
uint8_t sprite_width; // 0x14
// Height from centre of sprite to top
uint8_t sprite_height_positive; // 0x15
int16_t sprite_left; // 0x16
int16_t sprite_top; // 0x18
int16_t sprite_right; // 0x1A
int16_t sprite_bottom; // 0x1C
uint8_t sprite_direction; //direction of sprite? 0x1e
uint8_t pad_1F[3]; // 0x1f
uint16_t name_string_idx; // 0x22
uint8_t sprite_height_positive; // 0x15
int16_t sprite_left; // 0x16
int16_t sprite_top; // 0x18
int16_t sprite_right; // 0x1A
int16_t sprite_bottom; // 0x1C
uint8_t sprite_direction; // direction of sprite? 0x1e
uint8_t pad_1F[3]; // 0x1f
uint16_t name_string_idx; // 0x22
uint16_t pad_24;
uint16_t frame; // 0x26
uint16_t frame; // 0x26
};
assert_struct_size(rct_crash_splash, 0x28);
struct rct_steam_particle {
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
struct rct_steam_particle
{
uint8_t sprite_identifier; // 0x00
uint8_t misc_identifier; // 0x01
uint16_t next_in_quadrant; // 0x02
uint16_t next; // 0x04
uint16_t previous; // 0x06
uint8_t linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
// Height from centre of sprite to bottom
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
uint8_t sprite_height_negative; // 0x09
uint16_t sprite_index; // 0x0A
uint16_t flags; // 0x0C
int16_t x; // 0x0E
int16_t y; // 0x10
int16_t z; // 0x12
// Width from centre of sprite to edge
uint8_t sprite_width; // 0x14
uint8_t sprite_width; // 0x14
// Height from centre of sprite to top
uint8_t sprite_height_positive; // 0x15
int16_t sprite_left; // 0x16
int16_t sprite_top; // 0x18
int16_t sprite_right; // 0x1A
int16_t sprite_bottom; // 0x1C
uint8_t sprite_direction; // 0x1E
uint8_t pad_1F[3]; // 0x1F
uint16_t name_string_idx; // 0x22
uint16_t time_to_move; // 0x24 Moves +1 z every 3 ticks after intitial 4 ticks
uint16_t frame; // 0x26
uint8_t sprite_height_positive; // 0x15
int16_t sprite_left; // 0x16
int16_t sprite_top; // 0x18
int16_t sprite_right; // 0x1A
int16_t sprite_bottom; // 0x1C
uint8_t sprite_direction; // 0x1E
uint8_t pad_1F[3]; // 0x1F
uint16_t name_string_idx; // 0x22
uint16_t time_to_move; // 0x24 Moves +1 z every 3 ticks after intitial 4 ticks
uint16_t frame; // 0x26
};
assert_struct_size(rct_steam_particle, 0x28);
@ -313,7 +323,8 @@ assert_struct_size(rct_steam_particle, 0x28);
* Sprite structure.
* size: 0x0100
*/
union rct_sprite {
union rct_sprite
{
uint8_t pad_00[0x100];
rct_unk_sprite unknown;
rct_peep peep;
@ -330,15 +341,16 @@ union rct_sprite {
bool IsBalloon();
bool IsDuck();
bool IsPeep();
rct_balloon * AsBalloon();
rct_duck * AsDuck();
rct_peep * AsPeep();
rct_balloon* AsBalloon();
rct_duck* AsDuck();
rct_peep* AsPeep();
};
assert_struct_size(rct_sprite, 0x100);
#pragma pack(pop)
enum {
enum
{
SPRITE_MISC_STEAM_PARTICLE,
SPRITE_MISC_MONEY_EFFECT,
SPRITE_MISC_CRASHED_VEHICLE_PARTICLE,
@ -351,13 +363,15 @@ enum {
SPRITE_MISC_JUMPING_FOUNTAIN_SNOW
};
enum {
enum
{
SPRITE_FLAGS_IS_CRASHED_VEHICLE_SPRITE = 1 << 7,
SPRITE_FLAGS_PEEP_VISIBLE = 1 << 8, // Peep is eligible to show in summarized guest list window (is inside park?)
SPRITE_FLAGS_PEEP_VISIBLE = 1 << 8, // Peep is eligible to show in summarized guest list window (is inside park?)
SPRITE_FLAGS_PEEP_FLASHING = 1 << 9, // Deprecated: Use sprite_set_flashing/sprite_get_flashing instead.
};
enum {
enum
{
LITTER_TYPE_SICK,
LITTER_TYPE_SICK_ALT,
LITTER_TYPE_EMPTY_CAN,
@ -372,28 +386,27 @@ enum {
LITTER_TYPE_EMPTY_BOWL_BLUE,
};
rct_sprite *try_get_sprite(size_t spriteIndex);
rct_sprite *get_sprite(size_t sprite_idx);
rct_sprite* try_get_sprite(size_t spriteIndex);
rct_sprite* get_sprite(size_t sprite_idx);
extern uint16_t gSpriteListHead[6];
extern uint16_t gSpriteListCount[6];
extern uint16_t gSpriteSpatialIndex[0x10001];
extern const rct_string_id litterNames[12];
rct_sprite *create_sprite(uint8_t bl);
rct_sprite* create_sprite(uint8_t bl);
void reset_sprite_list();
void reset_sprite_spatial_index();
void sprite_clear_all_unused();
void move_sprite_to_list(rct_sprite *sprite, uint8_t cl);
void move_sprite_to_list(rct_sprite* sprite, uint8_t cl);
void sprite_misc_update_all();
void sprite_move(int16_t x, int16_t y, int16_t z, rct_sprite* sprite);
void sprite_set_coordinates(int16_t x, int16_t y, int16_t z, rct_sprite *sprite);
void sprite_set_coordinates(int16_t x, int16_t y, int16_t z, rct_sprite* sprite);
void invalidate_sprite_0(rct_sprite* sprite);
void invalidate_sprite_1(rct_sprite *sprite);
void invalidate_sprite_2(rct_sprite *sprite);
void sprite_remove(rct_sprite *sprite);
void invalidate_sprite_1(rct_sprite* sprite);
void invalidate_sprite_2(rct_sprite* sprite);
void sprite_remove(rct_sprite* sprite);
void litter_create(int32_t x, int32_t y, int32_t z, int32_t direction, int32_t type);
void litter_remove_at(int32_t x, int32_t y, int32_t z);
void sprite_misc_explosion_cloud_create(int32_t x, int32_t y, int32_t z);
@ -409,38 +422,39 @@ void sprite_position_tween_reset();
// Balloon
///////////////////////////////////////////////////////////////
void create_balloon(int32_t x, int32_t y, int32_t z, int32_t colour, bool isPopped);
void balloon_update(rct_balloon *balloon);
void game_command_balloon_press(int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
void balloon_update(rct_balloon* balloon);
void game_command_balloon_press(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, int32_t* esi, int32_t* edi, int32_t* ebp);
///////////////////////////////////////////////////////////////
// Duck
///////////////////////////////////////////////////////////////
void create_duck(int32_t targetX, int32_t targetY);
void duck_update(rct_duck *duck);
void duck_press(rct_duck *duck);
void duck_update(rct_duck* duck);
void duck_press(rct_duck* duck);
void duck_remove_all();
uint32_t duck_get_frame_image(const rct_duck * duck, int32_t direction);
uint32_t duck_get_frame_image(const rct_duck* duck, int32_t direction);
///////////////////////////////////////////////////////////////
// Money effect
///////////////////////////////////////////////////////////////
void money_effect_create(money32 value);
void money_effect_create_at(money32 value, int32_t x, int32_t y, int32_t z, bool vertical);
void money_effect_update(rct_money_effect *moneyEffect);
rct_string_id money_effect_get_string_id(const rct_money_effect * sprite, money32 * outValue);
void money_effect_update(rct_money_effect* moneyEffect);
rct_string_id money_effect_get_string_id(const rct_money_effect* sprite, money32* outValue);
///////////////////////////////////////////////////////////////
// Crash particles
///////////////////////////////////////////////////////////////
void crashed_vehicle_particle_create(rct_vehicle_colour colours, int32_t x, int32_t y, int32_t z);
void crashed_vehicle_particle_update(rct_crashed_vehicle_particle *particle);
void crashed_vehicle_particle_update(rct_crashed_vehicle_particle* particle);
void crash_splash_create(int32_t x, int32_t y, int32_t z);
void crash_splash_update(rct_crash_splash *splash);
void crash_splash_update(rct_crash_splash* splash);
const char *sprite_checksum();
const char* sprite_checksum();
void sprite_set_flashing(rct_sprite *sprite, bool flashing);
bool sprite_get_flashing(rct_sprite *sprite);
void sprite_set_flashing(rct_sprite* sprite, bool flashing);
bool sprite_get_flashing(rct_sprite* sprite);
int32_t check_for_sprite_list_cycles(bool fix);
int32_t check_for_spatial_index_cycles(bool fix);
int32_t fix_disjoint_sprites();

View File

@ -9,7 +9,7 @@
#include "Surface.h"
int32_t surface_get_terrain(const rct_tile_element * element)
int32_t surface_get_terrain(const rct_tile_element* element)
{
int32_t terrain = (element->properties.surface.terrain >> 5) & 7;
if (element->type & 1)
@ -17,7 +17,7 @@ int32_t surface_get_terrain(const rct_tile_element * element)
return terrain;
}
int32_t surface_get_terrain_edge(const rct_tile_element * element)
int32_t surface_get_terrain_edge(const rct_tile_element* element)
{
int32_t terrain_edge = (element->properties.surface.slope >> 5) & 7;
if (element->type & 128)
@ -25,7 +25,7 @@ int32_t surface_get_terrain_edge(const rct_tile_element * element)
return terrain_edge;
}
void surface_set_terrain(rct_tile_element * element, int32_t terrain)
void surface_set_terrain(rct_tile_element* element, int32_t terrain)
{
// Bit 3 for terrain is stored in element.type bit 0
if (terrain & 8)
@ -38,7 +38,7 @@ void surface_set_terrain(rct_tile_element * element, int32_t terrain)
element->properties.surface.terrain |= (terrain & 7) << 5;
}
void surface_set_terrain_edge(rct_tile_element * element, int32_t terrain)
void surface_set_terrain_edge(rct_tile_element* element, int32_t terrain)
{
// Bit 3 for terrain is stored in element.type bit 7
if (terrain & 8)
@ -51,7 +51,7 @@ void surface_set_terrain_edge(rct_tile_element * element, int32_t terrain)
element->properties.surface.slope |= (terrain & 7) << 5;
}
int32_t surface_get_water_height(const rct_tile_element * tileElement)
int32_t surface_get_water_height(const rct_tile_element* tileElement)
{
return tileElement->properties.surface.terrain & TILE_ELEMENT_SURFACE_WATER_HEIGHT_MASK;
}

View File

@ -12,7 +12,8 @@
#include "../common.h"
#include "TileElement.h"
enum {
enum
{
TERRAIN_GRASS,
TERRAIN_SAND,
TERRAIN_DIRT,
@ -32,7 +33,8 @@ enum {
TERRAIN_UNDERGROUND_VIEW,
};
enum {
enum
{
TERRAIN_EDGE_ROCK,
TERRAIN_EDGE_WOOD_RED,
TERRAIN_EDGE_WOOD_BLACK,
@ -55,7 +57,8 @@ enum {
TERRAIN_EDGE_COUNT
};
enum {
enum
{
GRASS_LENGTH_MOWED,
GRASS_LENGTH_CLEAR_0,
GRASS_LENGTH_CLEAR_1,
@ -65,7 +68,8 @@ enum {
GRASS_LENGTH_CLUMPS_2
};
enum {
enum
{
OWNERSHIP_UNOWNED = 0,
OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED = (1 << 4),
OWNERSHIP_OWNED = (1 << 5),
@ -73,7 +77,8 @@ enum {
OWNERSHIP_AVAILABLE = (1 << 7)
};
enum {
enum
{
TILE_ELEMENT_SLOPE_FLAT = 0x00,
TILE_ELEMENT_SLOPE_ALL_CORNERS_UP = 0x0F,
@ -98,17 +103,19 @@ enum {
};
// Surface
#define TILE_ELEMENT_SURFACE_DIAGONAL_FLAG 0x10 // in rct_tile_element.properties.surface.slope
#define TILE_ELEMENT_SURFACE_DIAGONAL_FLAG 0x10 // in rct_tile_element.properties.surface.slope
#define TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK 0x0F // in rct_tile_element.properties.surface.slope
#define TILE_ELEMENT_SURFACE_SLOPE_MASK (TILE_ELEMENT_SURFACE_DIAGONAL_FLAG | TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) // in rct_tile_element.properties.surface.slope
#define TILE_ELEMENT_SURFACE_EDGE_STYLE_MASK 0xE0 // in rct_tile_tile_element_set_terrainelement.properties.surface.slope
#define TILE_ELEMENT_SURFACE_WATER_HEIGHT_MASK 0x1F // in rct_tile_element.properties.surface.terrain
#define TILE_ELEMENT_SURFACE_TERRAIN_MASK 0xE0 // in rct_tile_element.properties.surface.terrain
#define TILE_ELEMENT_SURFACE_SLOPE_MASK \
(TILE_ELEMENT_SURFACE_DIAGONAL_FLAG \
| TILE_ELEMENT_SURFACE_RAISED_CORNERS_MASK) // in rct_tile_element.properties.surface.slope
#define TILE_ELEMENT_SURFACE_EDGE_STYLE_MASK 0xE0 // in rct_tile_tile_element_set_terrainelement.properties.surface.slope
#define TILE_ELEMENT_SURFACE_WATER_HEIGHT_MASK 0x1F // in rct_tile_element.properties.surface.terrain
#define TILE_ELEMENT_SURFACE_TERRAIN_MASK 0xE0 // in rct_tile_element.properties.surface.terrain
int32_t surface_get_terrain(const rct_tile_element * element);
int32_t surface_get_terrain_edge(const rct_tile_element * element);
void surface_set_terrain(rct_tile_element * element, int32_t terrain);
void surface_set_terrain_edge(rct_tile_element * element, int32_t terrain);
int32_t surface_get_terrain(const rct_tile_element* element);
int32_t surface_get_terrain_edge(const rct_tile_element* element);
void surface_set_terrain(rct_tile_element* element, int32_t terrain);
void surface_set_terrain_edge(rct_tile_element* element, int32_t terrain);
// ~Oli414: Needs to renamed. This function is specific to the surface object.
int32_t surface_get_water_height(const rct_tile_element * tileElement);
int32_t surface_get_water_height(const rct_tile_element* tileElement);

View File

@ -7,13 +7,14 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "TileElement.h"
#include "../core/Guard.hpp"
#include "../interface/Window.h"
#include "../localisation/Localisation.h"
#include "../ride/Track.h"
#include "Banner.h"
#include "LargeScenery.h"
#include "TileElement.h"
#include "Scenery.h"
uint8_t rct_tile_element::GetType() const
@ -58,24 +59,25 @@ uint8_t rct_tile_element::GetSceneryQuadrant() const
return (this->type & TILE_ELEMENT_QUADRANT_MASK) >> 6;
}
int32_t tile_element_get_direction(const rct_tile_element * element)
int32_t tile_element_get_direction(const rct_tile_element* element)
{
return element->GetDirection();
}
int32_t tile_element_get_direction_with_offset(const rct_tile_element * element, uint8_t offset)
int32_t tile_element_get_direction_with_offset(const rct_tile_element* element, uint8_t offset)
{
return element->GetDirectionWithOffset(offset);
}
bool tile_element_is_ghost(const rct_tile_element * element)
bool tile_element_is_ghost(const rct_tile_element* element)
{
return element->IsGhost();
}
bool tile_element_is_underground(rct_tile_element * tileElement)
bool tile_element_is_underground(rct_tile_element* tileElement)
{
do {
do
{
tileElement++;
if ((tileElement - 1)->IsLastForTile())
return false;
@ -87,23 +89,24 @@ BannerIndex tile_element_get_banner_index(rct_tile_element* tileElement)
{
rct_scenery_entry* sceneryEntry;
switch (tileElement->GetType()) {
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
sceneryEntry = get_large_scenery_entry(scenery_large_get_type(tileElement));
if (sceneryEntry->large_scenery.scrolling_mode == 0xFF)
return BANNER_INDEX_NULL;
switch (tileElement->GetType())
{
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
sceneryEntry = get_large_scenery_entry(scenery_large_get_type(tileElement));
if (sceneryEntry->large_scenery.scrolling_mode == 0xFF)
return BANNER_INDEX_NULL;
return scenery_large_get_banner_id(tileElement);
case TILE_ELEMENT_TYPE_WALL:
sceneryEntry = get_wall_entry(tileElement->properties.wall.type);
if (sceneryEntry == nullptr || sceneryEntry->wall.scrolling_mode == 0xFF)
return BANNER_INDEX_NULL;
return scenery_large_get_banner_id(tileElement);
case TILE_ELEMENT_TYPE_WALL:
sceneryEntry = get_wall_entry(tileElement->properties.wall.type);
if (sceneryEntry == nullptr || sceneryEntry->wall.scrolling_mode == 0xFF)
return BANNER_INDEX_NULL;
return tileElement->properties.wall.banner_index;
case TILE_ELEMENT_TYPE_BANNER:
return tileElement->properties.banner.index;
default:
return BANNER_INDEX_NULL;
return tileElement->properties.wall.banner_index;
case TILE_ELEMENT_TYPE_BANNER:
return tileElement->properties.banner.index;
default:
return BANNER_INDEX_NULL;
}
}
@ -111,29 +114,30 @@ void tile_element_set_banner_index(rct_tile_element* tileElement, BannerIndex ba
{
switch (tileElement->GetType())
{
case TILE_ELEMENT_TYPE_WALL:
tileElement->properties.wall.banner_index = bannerIndex;
break;
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
scenery_large_set_banner_id(tileElement, bannerIndex);
break;
case TILE_ELEMENT_TYPE_BANNER:
tileElement->properties.banner.index = bannerIndex;
break;
default:
log_error("Tried to set banner index on unsuitable tile element!");
Guard::Assert(false);
case TILE_ELEMENT_TYPE_WALL:
tileElement->properties.wall.banner_index = bannerIndex;
break;
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
scenery_large_set_banner_id(tileElement, bannerIndex);
break;
case TILE_ELEMENT_TYPE_BANNER:
tileElement->properties.banner.index = bannerIndex;
break;
default:
log_error("Tried to set banner index on unsuitable tile element!");
Guard::Assert(false);
}
}
void tile_element_remove_banner_entry(rct_tile_element * tileElement)
void tile_element_remove_banner_entry(rct_tile_element* tileElement)
{
BannerIndex bannerIndex = tile_element_get_banner_index(tileElement);
if (bannerIndex == BANNER_INDEX_NULL)
return;
rct_banner* banner = &gBanners[bannerIndex];
if (banner->type != BANNER_NULL) {
if (banner->type != BANNER_NULL)
{
rct_windownumber windowNumber = bannerIndex;
window_close_by_number(WC_BANNER, windowNumber);
banner->type = BANNER_NULL;
@ -141,17 +145,17 @@ void tile_element_remove_banner_entry(rct_tile_element * tileElement)
}
}
uint8_t tile_element_get_ride_index(const rct_tile_element * tileElement)
uint8_t tile_element_get_ride_index(const rct_tile_element* tileElement)
{
switch (tileElement->GetType())
{
case TILE_ELEMENT_TYPE_TRACK:
return track_element_get_ride_index(tileElement);
case TILE_ELEMENT_TYPE_ENTRANCE:
return tileElement->properties.entrance.ride_index;
case TILE_ELEMENT_TYPE_PATH:
return tileElement->properties.path.ride_index;
default:
return 0xFF;
case TILE_ELEMENT_TYPE_TRACK:
return track_element_get_ride_index(tileElement);
case TILE_ELEMENT_TYPE_ENTRANCE:
return tileElement->properties.entrance.ride_index;
case TILE_ELEMENT_TYPE_PATH:
return tileElement->properties.path.ride_index;
default:
return 0xFF;
}
}

View File

@ -12,29 +12,35 @@
#include "../common.h"
#pragma pack(push, 1)
struct rct_tile_element_surface_properties {
uint8_t slope; //4 0xE0 Edge Style, 0x1F Slope
uint8_t terrain; //5 0xE0 Terrain Style, 0x1F Water height
uint8_t grass_length; //6
uint8_t ownership; //7
struct rct_tile_element_surface_properties
{
uint8_t slope; // 4 0xE0 Edge Style, 0x1F Slope
uint8_t terrain; // 5 0xE0 Terrain Style, 0x1F Water height
uint8_t grass_length; // 6
uint8_t ownership; // 7
};
assert_struct_size(rct_tile_element_surface_properties, 4);
struct rct_tile_element_path_properties {
uint8_t type; //4 0xF0 Path type, 0x08 Ride sign, 0x04 Set when path is diagonal, 0x03 Rotation
uint8_t additions; //5
uint8_t edges; //6
union {
uint8_t addition_status; //7
struct rct_tile_element_path_properties
{
uint8_t type; // 4 0xF0 Path type, 0x08 Ride sign, 0x04 Set when path is diagonal, 0x03 Rotation
uint8_t additions; // 5
uint8_t edges; // 6
union
{
uint8_t addition_status; // 7
uint8_t ride_index;
};
};
assert_struct_size(rct_tile_element_path_properties, 4);
struct rct_tile_element_track_properties {
uint8_t type; //4
union {
struct {
struct rct_tile_element_track_properties
{
uint8_t type; // 4
union
{
struct
{
// The lower 4 bits are the track sequence.
// The upper 4 bits are either station bits or on-ride photo bits.
//
@ -46,57 +52,64 @@ struct rct_tile_element_track_properties {
// - Bits 7 and 8 are never set
// - Bits 5 and 6 are set when a vehicle triggers the on-ride photo and act like a countdown from 3.
// - If any of the bits 5-8 are set, the game counts it as a photo being taken.
uint8_t sequence; //5.
uint8_t colour; //6
uint8_t sequence; // 5.
uint8_t colour; // 6
};
uint16_t maze_entry; // 5
};
uint8_t ride_index; //7
uint8_t ride_index; // 7
};
assert_struct_size(rct_tile_element_track_properties, 4);
struct rct_tile_element_scenery_properties {
uint8_t type; //4
uint8_t age; //5
uint8_t colour_1; //6
uint8_t colour_2; //7
struct rct_tile_element_scenery_properties
{
uint8_t type; // 4
uint8_t age; // 5
uint8_t colour_1; // 6
uint8_t colour_2; // 7
};
assert_struct_size(rct_tile_element_scenery_properties, 4);
struct rct_tile_element_entrance_properties {
uint8_t type; //4
uint8_t index; //5
uint8_t path_type; //6
uint8_t ride_index; //7
struct rct_tile_element_entrance_properties
{
uint8_t type; // 4
uint8_t index; // 5
uint8_t path_type; // 6
uint8_t ride_index; // 7
};
assert_struct_size(rct_tile_element_entrance_properties, 4);
struct rct_tile_element_wall_properties {
uint8_t type; //4
union {
uint8_t colour_3; //5
struct rct_tile_element_wall_properties
{
uint8_t type; // 4
union
{
uint8_t colour_3; // 5
BannerIndex banner_index; // 5
};
uint8_t colour_1; //6 0b_2221_1111 2 = colour_2 (uses flags for rest of colour2), 1 = colour_1
uint8_t animation; //7 0b_dfff_ft00 d = direction, f = frame num, t = across track flag (not used)
uint8_t colour_1; // 6 0b_2221_1111 2 = colour_2 (uses flags for rest of colour2), 1 = colour_1
uint8_t animation; // 7 0b_dfff_ft00 d = direction, f = frame num, t = across track flag (not used)
};
assert_struct_size(rct_tile_element_wall_properties, 4);
struct rct_tile_element_scenerymultiple_properties {
uint16_t type; //4
uint8_t colour[2]; //6
struct rct_tile_element_scenerymultiple_properties
{
uint16_t type; // 4
uint8_t colour[2]; // 6
};
assert_struct_size(rct_tile_element_scenerymultiple_properties, 4);
struct rct_tile_element_banner_properties {
struct rct_tile_element_banner_properties
{
BannerIndex index; // 4
uint8_t position; //5
uint8_t flags; //6
uint8_t unused; //7
uint8_t position; // 5
uint8_t flags; // 6
uint8_t unused; // 7
};
assert_struct_size(rct_tile_element_banner_properties, 4);
union rct_tile_element_properties {
union rct_tile_element_properties
{
rct_tile_element_surface_properties surface;
rct_tile_element_path_properties path;
rct_tile_element_track_properties track;
@ -109,36 +122,39 @@ union rct_tile_element_properties {
assert_struct_size(rct_tile_element_properties, 4);
/**
* Map element structure
* size: 0x08
*/
struct rct_tile_element {
uint8_t type; //0
uint8_t flags; //1
uint8_t base_height; //2
uint8_t clearance_height; //3
* Map element structure
* size: 0x08
*/
struct rct_tile_element
{
uint8_t type; // 0
uint8_t flags; // 1
uint8_t base_height; // 2
uint8_t clearance_height; // 3
rct_tile_element_properties properties;
uint8_t GetType() const;
void SetType(uint8_t newType);
void SetType(uint8_t newType);
uint8_t GetDirection() const;
void SetDirection(uint8_t direction);
void SetDirection(uint8_t direction);
uint8_t GetDirectionWithOffset(uint8_t offset) const;
bool IsLastForTile() const;
bool IsGhost() const;
bool IsLastForTile() const;
bool IsGhost() const;
uint8_t GetSceneryQuadrant() const;
};
assert_struct_size(rct_tile_element, 8);
#pragma pack(pop)
enum {
enum
{
TILE_ELEMENT_QUADRANT_SW,
TILE_ELEMENT_QUADRANT_NW,
TILE_ELEMENT_QUADRANT_NE,
TILE_ELEMENT_QUADRANT_SE
};
enum {
enum
{
TILE_ELEMENT_TYPE_SURFACE = (0 << 2),
TILE_ELEMENT_TYPE_PATH = (1 << 2),
TILE_ELEMENT_TYPE_TRACK = (2 << 2),
@ -152,18 +168,21 @@ enum {
TILE_ELEMENT_TYPE_CORRUPT = (8 << 2),
};
enum {
enum
{
TILE_ELEMENT_TYPE_FLAG_HIGHLIGHT = (1 << 6)
};
enum {
enum
{
TILE_ELEMENT_DIRECTION_WEST,
TILE_ELEMENT_DIRECTION_NORTH,
TILE_ELEMENT_DIRECTION_EAST,
TILE_ELEMENT_DIRECTION_SOUTH
};
enum {
enum
{
TILE_ELEMENT_FLAG_GHOST = (1 << 4),
TILE_ELEMENT_FLAG_BROKEN = (1 << 5),
TILE_ELEMENT_FLAG_BLOCK_BRAKE_CLOSED = (1 << 5),
@ -172,13 +191,15 @@ enum {
TILE_ELEMENT_FLAG_LAST_TILE = (1 << 7)
};
enum {
enum
{
ENTRANCE_TYPE_RIDE_ENTRANCE,
ENTRANCE_TYPE_RIDE_EXIT,
ENTRANCE_TYPE_PARK_ENTRANCE
};
enum {
enum
{
ELEMENT_IS_ABOVE_GROUND = 1 << 0,
ELEMENT_IS_UNDERGROUND = 1 << 1,
ELEMENT_IS_UNDERWATER = 1 << 2,
@ -189,27 +210,25 @@ enum
MAP_ELEM_TRACK_SEQUENCE_GREEN_LIGHT = (1 << 7),
};
#define TILE_ELEMENT_QUADRANT_MASK 0b11000000
#define TILE_ELEMENT_TYPE_MASK 0b00111100
#define TILE_ELEMENT_QUADRANT_MASK 0b11000000
#define TILE_ELEMENT_TYPE_MASK 0b00111100
#define TILE_ELEMENT_DIRECTION_MASK 0b00000011
#define TILE_ELEMENT_COLOUR_MASK 0b00011111
#define TILE_ELEMENT_COLOUR_MASK 0b00011111
#define MAP_ELEM_TRACK_SEQUENCE_STATION_INDEX_MASK 0b01110000
#define MAP_ELEM_TRACK_SEQUENCE_SEQUENCE_MASK 0b00001111
#define MAP_ELEM_TRACK_SEQUENCE_TAKING_PHOTO_MASK 0b11110000
#define MAP_ELEM_TRACK_SEQUENCE_SEQUENCE_MASK 0b00001111
#define MAP_ELEM_TRACK_SEQUENCE_TAKING_PHOTO_MASK 0b11110000
int32_t tile_element_get_direction(const rct_tile_element * element);
int32_t tile_element_get_direction_with_offset(const rct_tile_element * element, uint8_t offset);
int32_t tile_element_get_direction(const rct_tile_element* element);
int32_t tile_element_get_direction_with_offset(const rct_tile_element* element, uint8_t offset);
BannerIndex tile_element_get_banner_index(rct_tile_element* tileElement);
bool tile_element_is_ghost(const rct_tile_element * element);
bool tile_element_is_underground(rct_tile_element * tileElement);
bool tile_element_is_last_for_tile(const rct_tile_element *element);
bool tile_element_is_ghost(const rct_tile_element* element);
bool tile_element_is_underground(rct_tile_element* tileElement);
bool tile_element_is_last_for_tile(const rct_tile_element* element);
// ~Oli414: The banner functions should probably be part of banner.
void tile_element_set_banner_index(rct_tile_element* tileElement, BannerIndex bannerIndex);
void tile_element_remove_banner_entry(rct_tile_element *tileElement);
void tile_element_remove_banner_entry(rct_tile_element* tileElement);
uint8_t tile_element_get_ride_index(const rct_tile_element * tileElement);
uint8_t tile_element_get_ride_index(const rct_tile_element* tileElement);

View File

@ -7,24 +7,25 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "Banner.h"
#include "../common.h"
#include "TileInspector.h"
#include "../Context.h"
#include "../Game.h"
#include "../common.h"
#include "../core/Guard.hpp"
#include "../interface/Window.h"
#include "../localisation/Localisation.h"
#include "../ride/Station.h"
#include "../ride/Track.h"
#include "../windows/Intent.h"
#include "../windows/tile_inspector.h"
#include "Banner.h"
#include "Footpath.h"
#include "LargeScenery.h"
#include "Map.h"
#include "Park.h"
#include "Scenery.h"
#include "Surface.h"
#include "TileInspector.h"
#include "../ride/Station.h"
#include "Park.h"
using namespace OpenRCT2;
@ -35,8 +36,8 @@ int32_t windowTileInspectorSelectedIndex;
static bool map_swap_elements_at(int32_t x, int32_t y, int16_t first, int16_t second)
{
rct_tile_element * const firstElement = map_get_nth_element_at(x, y, first);
rct_tile_element * const secondElement = map_get_nth_element_at(x, y, second);
rct_tile_element* const firstElement = map_get_nth_element_at(x, y, first);
rct_tile_element* const secondElement = map_get_nth_element_at(x, y, second);
if (firstElement == nullptr)
{
@ -56,8 +57,8 @@ static bool map_swap_elements_at(int32_t x, int32_t y, int16_t first, int16_t se
// Swap their memory
rct_tile_element temp = *firstElement;
*firstElement = *secondElement;
*secondElement = temp;
*firstElement = *secondElement;
*secondElement = temp;
// Swap the 'last map element for tile' flag if either one of them was last
if ((firstElement)->IsLastForTile() || (secondElement)->IsLastForTile())
@ -85,7 +86,7 @@ int32_t tile_inspector_insert_corrupt_at(int32_t x, int32_t y, int16_t elementIn
if (flags & GAME_COMMAND_FLAG_APPLY)
{
// Create new corrupt element
rct_tile_element * corruptElement = tile_element_insert(x, y, -1, 0); // Ugly hack: -1 guarantees this to be placed first
rct_tile_element* corruptElement = tile_element_insert(x, y, -1, 0); // Ugly hack: -1 guarantees this to be placed first
if (corruptElement == nullptr)
{
log_warning("Failed to insert corrupt element.");
@ -94,7 +95,7 @@ int32_t tile_inspector_insert_corrupt_at(int32_t x, int32_t y, int16_t elementIn
corruptElement->type = TILE_ELEMENT_TYPE_CORRUPT;
// Set the base height to be the same as the selected element
rct_tile_element * const selectedElement = map_get_nth_element_at(x, y, elementIndex + 1);
rct_tile_element* const selectedElement = map_get_nth_element_at(x, y, elementIndex + 1);
if (!selectedElement)
{
return MONEY32_UNDEFINED;
@ -117,8 +118,9 @@ int32_t tile_inspector_insert_corrupt_at(int32_t x, int32_t y, int16_t elementIn
map_invalidate_tile_full(x << 5, y << 5);
// Update the tile inspector's list for everyone who has the tile selected
rct_window * const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)
rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX
&& (uint32_t)y == windowTileInspectorTileY)
{
windowTileInspectorElementCount++;
@ -147,7 +149,7 @@ int32_t tile_inspector_remove_element_at(int32_t x, int32_t y, int16_t elementIn
if (flags & GAME_COMMAND_FLAG_APPLY)
{
// Forcefully remove the element
rct_tile_element * const tileElement = map_get_nth_element_at(x, y, elementIndex);
rct_tile_element* const tileElement = map_get_nth_element_at(x, y, elementIndex);
if (!tileElement)
{
return MONEY32_UNDEFINED;
@ -156,8 +158,9 @@ int32_t tile_inspector_remove_element_at(int32_t x, int32_t y, int16_t elementIn
map_invalidate_tile_full(x << 5, y << 5);
// Update the window
rct_window * const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)
rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX
&& (uint32_t)y == windowTileInspectorTileY)
{
windowTileInspectorElementCount--;
@ -188,8 +191,9 @@ int32_t tile_inspector_swap_elements_at(int32_t x, int32_t y, int16_t first, int
map_invalidate_tile_full(x << 5, y << 5);
// Update the window
rct_window * const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)
rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX
&& (uint32_t)y == windowTileInspectorTileY)
{
// If one of them was selected, update selected list item
if (windowTileInspectorSelectedIndex == first)
@ -210,69 +214,69 @@ int32_t tile_inspector_rotate_element_at(int32_t x, int32_t y, int32_t elementIn
{
uint8_t newRotation, pathEdges, pathCorners;
rct_tile_element * const tileElement = map_get_nth_element_at(x, y, elementIndex);
rct_tile_element* const tileElement = map_get_nth_element_at(x, y, elementIndex);
if (!tileElement)
{
return MONEY32_UNDEFINED;
}
switch (tileElement->GetType())
{
case TILE_ELEMENT_TYPE_PATH:
if (footpath_element_is_sloped(tileElement))
case TILE_ELEMENT_TYPE_PATH:
if (footpath_element_is_sloped(tileElement))
{
newRotation = (footpath_element_get_slope_direction(tileElement) + 1) & TILE_ELEMENT_DIRECTION_MASK;
tileElement->properties.path.type &= ~TILE_ELEMENT_DIRECTION_MASK;
tileElement->properties.path.type |= newRotation;
}
pathEdges = tileElement->properties.path.edges & 0x0F;
pathCorners = tileElement->properties.path.edges & 0xF0;
tileElement->properties.path.edges = 0;
tileElement->properties.path.edges |= ((pathEdges << 1) | (pathEdges >> 3)) & 0x0F;
tileElement->properties.path.edges |= ((pathCorners << 1) | (pathCorners >> 3)) & 0xF0;
break;
case TILE_ELEMENT_TYPE_ENTRANCE:
{
newRotation = (footpath_element_get_slope_direction(tileElement) + 1) & TILE_ELEMENT_DIRECTION_MASK;
tileElement->properties.path.type &= ~TILE_ELEMENT_DIRECTION_MASK;
tileElement->properties.path.type |= newRotation;
}
pathEdges = tileElement->properties.path.edges & 0x0F;
pathCorners = tileElement->properties.path.edges & 0xF0;
tileElement->properties.path.edges = 0;
tileElement->properties.path.edges |= ((pathEdges << 1) | (pathEdges >> 3)) & 0x0F;
tileElement->properties.path.edges |= ((pathCorners << 1) | (pathCorners >> 3)) & 0xF0;
break;
case TILE_ELEMENT_TYPE_ENTRANCE:
{
// Update element rotation
newRotation = tile_element_get_direction_with_offset(tileElement, 1);
tileElement->type &= ~TILE_ELEMENT_DIRECTION_MASK;
tileElement->type |= newRotation;
// Update element rotation
newRotation = tile_element_get_direction_with_offset(tileElement, 1);
tileElement->type &= ~TILE_ELEMENT_DIRECTION_MASK;
tileElement->type |= newRotation;
// Update ride's known entrance/exit rotation
Ride * ride = get_ride(tileElement->properties.entrance.ride_index);
uint8_t stationIndex = tileElement->properties.entrance.index;
auto entrance = ride_get_entrance_location(ride, stationIndex);
auto exit = ride_get_exit_location(ride, stationIndex);
uint8_t entranceType = entrance_element_get_type(tileElement);
uint8_t z = tileElement->base_height;
// Update ride's known entrance/exit rotation
Ride* ride = get_ride(tileElement->properties.entrance.ride_index);
uint8_t stationIndex = tileElement->properties.entrance.index;
auto entrance = ride_get_entrance_location(ride, stationIndex);
auto exit = ride_get_exit_location(ride, stationIndex);
uint8_t entranceType = entrance_element_get_type(tileElement);
uint8_t z = tileElement->base_height;
// Make sure this is the correct entrance or exit
if (entranceType == ENTRANCE_TYPE_RIDE_ENTRANCE && entrance.x == x && entrance.y == y && entrance.z == z)
{
ride_set_entrance_location(ride, stationIndex, { entrance.x, entrance.y, entrance.z, newRotation });
// Make sure this is the correct entrance or exit
if (entranceType == ENTRANCE_TYPE_RIDE_ENTRANCE && entrance.x == x && entrance.y == y && entrance.z == z)
{
ride_set_entrance_location(ride, stationIndex, { entrance.x, entrance.y, entrance.z, newRotation });
}
else if (entranceType == ENTRANCE_TYPE_RIDE_EXIT && exit.x == x && exit.y == y && exit.z == z)
{
ride_set_exit_location(ride, stationIndex, { exit.x, exit.y, exit.z, newRotation });
}
break;
}
else if (entranceType == ENTRANCE_TYPE_RIDE_EXIT && exit.x == x && exit.y == y && exit.z == z)
case TILE_ELEMENT_TYPE_TRACK:
case TILE_ELEMENT_TYPE_SMALL_SCENERY:
case TILE_ELEMENT_TYPE_WALL:
newRotation = tile_element_get_direction_with_offset(tileElement, 1);
tileElement->type &= ~TILE_ELEMENT_DIRECTION_MASK;
tileElement->type |= newRotation;
break;
case TILE_ELEMENT_TYPE_BANNER:
{
ride_set_exit_location(ride, stationIndex, { exit.x, exit.y, exit.z, newRotation });
uint8_t unblockedEdges = tileElement->properties.banner.flags & 0xF;
unblockedEdges = (unblockedEdges << 1 | unblockedEdges >> 3) & 0xF;
tileElement->properties.banner.flags &= ~0xF;
tileElement->properties.banner.flags |= unblockedEdges;
tileElement->properties.banner.position++;
tileElement->properties.banner.position &= 3;
break;
}
break;
}
case TILE_ELEMENT_TYPE_TRACK:
case TILE_ELEMENT_TYPE_SMALL_SCENERY:
case TILE_ELEMENT_TYPE_WALL:
newRotation = tile_element_get_direction_with_offset(tileElement, 1);
tileElement->type &= ~TILE_ELEMENT_DIRECTION_MASK;
tileElement->type |= newRotation;
break;
case TILE_ELEMENT_TYPE_BANNER:
{
uint8_t unblockedEdges = tileElement->properties.banner.flags & 0xF;
unblockedEdges = (unblockedEdges << 1 | unblockedEdges >> 3) & 0xF;
tileElement->properties.banner.flags &= ~0xF;
tileElement->properties.banner.flags |= unblockedEdges;
tileElement->properties.banner.position++;
tileElement->properties.banner.position &= 3;
break;
}
}
map_invalidate_tile_full(x << 5, y << 5);
@ -306,10 +310,10 @@ int32_t tile_inspector_paste_element_at(int32_t x, int32_t y, rct_tile_element e
{
return MONEY32_UNDEFINED;
}
rct_banner & newBanner = gBanners[newBannerIndex];
newBanner = gBanners[bannerIndex];
newBanner.x = x;
newBanner.y = y;
rct_banner& newBanner = gBanners[newBannerIndex];
newBanner = gBanners[bannerIndex];
newBanner.x = x;
newBanner.y = y;
// Use the new banner index
tile_element_set_banner_index(&element, newBannerIndex);
@ -329,10 +333,10 @@ int32_t tile_inspector_paste_element_at(int32_t x, int32_t y, rct_tile_element e
}
}
rct_tile_element * const pastedElement = tile_element_insert(x, y, element.base_height, 0);
rct_tile_element* const pastedElement = tile_element_insert(x, y, element.base_height, 0);
bool lastForTile = pastedElement->IsLastForTile();
*pastedElement = element;
*pastedElement = element;
pastedElement->flags &= ~TILE_ELEMENT_FLAG_LAST_TILE;
if (lastForTile)
{
@ -341,8 +345,9 @@ int32_t tile_inspector_paste_element_at(int32_t x, int32_t y, rct_tile_element e
map_invalidate_tile_full(x << 5, y << 5);
rct_window * const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)
rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX
&& (uint32_t)y == windowTileInspectorTileY)
{
windowTileInspectorElementCount++;
@ -364,11 +369,11 @@ int32_t tile_inspector_sort_elements_at(int32_t x, int32_t y, int32_t flags)
{
if (flags & GAME_COMMAND_FLAG_APPLY)
{
const rct_tile_element * const firstElement = map_get_first_element_at(x, y);
const rct_tile_element* const firstElement = map_get_first_element_at(x, y);
// Count elements on tile
int32_t numElement = 0;
const rct_tile_element * elementIterator = firstElement;
int32_t numElement = 0;
const rct_tile_element* elementIterator = firstElement;
do
{
numElement++;
@ -377,15 +382,16 @@ int32_t tile_inspector_sort_elements_at(int32_t x, int32_t y, int32_t flags)
// Bubble sort
for (int32_t loopStart = 1; loopStart < numElement; loopStart++)
{
int32_t currentId = loopStart;
const rct_tile_element * currentElement = firstElement + currentId;
const rct_tile_element * otherElement = currentElement - 1;
int32_t currentId = loopStart;
const rct_tile_element* currentElement = firstElement + currentId;
const rct_tile_element* otherElement = currentElement - 1;
// While current element's base height is lower, or (when their baseheight is the same) the other map element's
// clearance height is lower...
while (currentId > 0 && (otherElement->base_height > currentElement->base_height ||
(otherElement->base_height == currentElement->base_height &&
otherElement->clearance_height > currentElement->clearance_height)))
while (currentId > 0
&& (otherElement->base_height > currentElement->base_height
|| (otherElement->base_height == currentElement->base_height
&& otherElement->clearance_height > currentElement->clearance_height)))
{
if (!map_swap_elements_at(x, y, currentId - 1, currentId))
{
@ -404,8 +410,9 @@ int32_t tile_inspector_sort_elements_at(int32_t x, int32_t y, int32_t flags)
map_invalidate_tile_full(x << 5, y << 5);
// Deselect tile for clients who had it selected
rct_window * const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)
rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX
&& (uint32_t)y == windowTileInspectorTileY)
{
windowTileInspectorSelectedIndex = -1;
window_invalidate(tileInspectorWindow);
@ -417,11 +424,11 @@ int32_t tile_inspector_sort_elements_at(int32_t x, int32_t y, int32_t flags)
int32_t tile_inspector_any_base_height_offset(int32_t x, int32_t y, int16_t elementIndex, int8_t heightOffset, int32_t flags)
{
rct_tile_element * const tileElement = map_get_nth_element_at(x, y, elementIndex);
rct_tile_element* const tileElement = map_get_nth_element_at(x, y, elementIndex);
if (tileElement == nullptr)
return MONEY32_UNDEFINED;
int16_t newBaseHeight = (int16_t)tileElement->base_height + heightOffset;
int16_t newBaseHeight = (int16_t)tileElement->base_height + heightOffset;
int16_t newClearanceHeight = (int16_t)tileElement->clearance_height + heightOffset;
if (newBaseHeight < 0 || newBaseHeight > 0xff || newClearanceHeight < 0 || newClearanceHeight > 0xff)
{
@ -436,10 +443,10 @@ int32_t tile_inspector_any_base_height_offset(int32_t x, int32_t y, int16_t elem
if (entranceType != ENTRANCE_TYPE_PARK_ENTRANCE)
{
// Update the ride's known entrance or exit height
Ride * ride = get_ride(tileElement->properties.entrance.ride_index);
uint8_t entranceIndex = tileElement->properties.entrance.index;
auto entrance = ride_get_entrance_location(ride, entranceIndex);
auto exit = ride_get_exit_location(ride, entranceIndex);
Ride* ride = get_ride(tileElement->properties.entrance.ride_index);
uint8_t entranceIndex = tileElement->properties.entrance.index;
auto entrance = ride_get_entrance_location(ride, entranceIndex);
auto exit = ride_get_exit_location(ride, entranceIndex);
uint8_t z = tileElement->base_height;
// Make sure this is the correct entrance or exit
@ -447,8 +454,7 @@ int32_t tile_inspector_any_base_height_offset(int32_t x, int32_t y, int16_t elem
ride_set_entrance_location(
ride, entranceIndex, { entrance.x, entrance.y, z + heightOffset, entrance.direction });
else if (entranceType == ENTRANCE_TYPE_RIDE_EXIT && exit.x == x && exit.y == y && exit.z == z)
ride_set_exit_location(
ride, entranceIndex, { exit.x, exit.y, z + heightOffset, exit.direction });
ride_set_exit_location(ride, entranceIndex, { exit.x, exit.y, z + heightOffset, exit.direction });
}
}
@ -457,8 +463,9 @@ int32_t tile_inspector_any_base_height_offset(int32_t x, int32_t y, int16_t elem
map_invalidate_tile_full(x << 5, y << 5);
rct_window * const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)
rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX
&& (uint32_t)y == windowTileInspectorTileY)
{
window_invalidate(tileInspectorWindow);
}
@ -469,7 +476,7 @@ int32_t tile_inspector_any_base_height_offset(int32_t x, int32_t y, int16_t elem
int32_t tile_inspector_surface_show_park_fences(int32_t x, int32_t y, bool showFences, int32_t flags)
{
rct_tile_element * const surfaceelement = map_get_surface_element_at(x, y);
rct_tile_element* const surfaceelement = map_get_surface_element_at(x, y);
// No surface element on tile
if (surfaceelement == nullptr)
@ -480,12 +487,13 @@ int32_t tile_inspector_surface_show_park_fences(int32_t x, int32_t y, bool showF
if (!showFences)
surfaceelement->properties.surface.ownership &= ~0x0F;
else
update_park_fences({x << 5, y << 5});
update_park_fences({ x << 5, y << 5 });
map_invalidate_tile_full(x << 5, y << 5);
rct_window * const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)
rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX
&& (uint32_t)y == windowTileInspectorTileY)
{
window_invalidate(tileInspectorWindow);
}
@ -496,7 +504,7 @@ int32_t tile_inspector_surface_show_park_fences(int32_t x, int32_t y, bool showF
int32_t tile_inspector_surface_toggle_corner(int32_t x, int32_t y, int32_t cornerIndex, int32_t flags)
{
rct_tile_element * const surfaceElement = map_get_surface_element_at(x, y);
rct_tile_element* const surfaceElement = map_get_surface_element_at(x, y);
// No surface element on tile
if (surfaceElement == nullptr)
@ -505,7 +513,7 @@ int32_t tile_inspector_surface_toggle_corner(int32_t x, int32_t y, int32_t corne
if (flags & GAME_COMMAND_FLAG_APPLY)
{
const uint8_t originalSlope = surfaceElement->properties.surface.slope;
const bool diagonal = (originalSlope & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) >> 4;
const bool diagonal = (originalSlope & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT) >> 4;
surfaceElement->properties.surface.slope ^= 1 << cornerIndex;
if (surfaceElement->properties.surface.slope & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP)
@ -526,18 +534,18 @@ int32_t tile_inspector_surface_toggle_corner(int32_t x, int32_t y, int32_t corne
{
switch (originalSlope & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP)
{
case TILE_ELEMENT_SLOPE_S_CORNER_DN:
surfaceElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_N_CORNER_UP;
break;
case TILE_ELEMENT_SLOPE_W_CORNER_DN:
surfaceElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_E_CORNER_UP;
break;
case TILE_ELEMENT_SLOPE_N_CORNER_DN:
surfaceElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_S_CORNER_UP;
break;
case TILE_ELEMENT_SLOPE_E_CORNER_DN:
surfaceElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_W_CORNER_UP;
break;
case TILE_ELEMENT_SLOPE_S_CORNER_DN:
surfaceElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_N_CORNER_UP;
break;
case TILE_ELEMENT_SLOPE_W_CORNER_DN:
surfaceElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_E_CORNER_UP;
break;
case TILE_ELEMENT_SLOPE_N_CORNER_DN:
surfaceElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_S_CORNER_UP;
break;
case TILE_ELEMENT_SLOPE_E_CORNER_DN:
surfaceElement->properties.surface.slope |= TILE_ELEMENT_SLOPE_W_CORNER_UP;
break;
}
}
@ -548,8 +556,9 @@ int32_t tile_inspector_surface_toggle_corner(int32_t x, int32_t y, int32_t corne
map_invalidate_tile_full(x << 5, y << 5);
rct_window * const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)
rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX
&& (uint32_t)y == windowTileInspectorTileY)
{
window_invalidate(tileInspectorWindow);
}
@ -560,7 +569,7 @@ int32_t tile_inspector_surface_toggle_corner(int32_t x, int32_t y, int32_t corne
int32_t tile_inspector_surface_toggle_diagonal(int32_t x, int32_t y, int32_t flags)
{
rct_tile_element * const surfaceElement = map_get_surface_element_at(x, y);
rct_tile_element* const surfaceElement = map_get_surface_element_at(x, y);
// No surface element on tile
if (surfaceElement == nullptr)
@ -584,8 +593,9 @@ int32_t tile_inspector_surface_toggle_diagonal(int32_t x, int32_t y, int32_t fla
map_invalidate_tile_full(x << 5, y << 5);
rct_window * const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)
rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX
&& (uint32_t)y == windowTileInspectorTileY)
{
window_invalidate(tileInspectorWindow);
}
@ -596,7 +606,7 @@ int32_t tile_inspector_surface_toggle_diagonal(int32_t x, int32_t y, int32_t fla
int32_t tile_inspector_path_set_sloped(int32_t x, int32_t y, int32_t elementIndex, bool sloped, int32_t flags)
{
rct_tile_element * const pathElement = map_get_nth_element_at(x, y, elementIndex);
rct_tile_element* const pathElement = map_get_nth_element_at(x, y, elementIndex);
if (pathElement == nullptr || pathElement->GetType() != TILE_ELEMENT_TYPE_PATH)
return MONEY32_UNDEFINED;
@ -611,8 +621,9 @@ int32_t tile_inspector_path_set_sloped(int32_t x, int32_t y, int32_t elementInde
map_invalidate_tile_full(x << 5, y << 5);
rct_window * const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)
rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX
&& (uint32_t)y == windowTileInspectorTileY)
{
window_invalidate(tileInspectorWindow);
}
@ -623,7 +634,7 @@ int32_t tile_inspector_path_set_sloped(int32_t x, int32_t y, int32_t elementInde
int32_t tile_inspector_path_toggle_edge(int32_t x, int32_t y, int32_t elementIndex, int32_t edgeIndex, int32_t flags)
{
rct_tile_element * const pathElement = map_get_nth_element_at(x, y, elementIndex);
rct_tile_element* const pathElement = map_get_nth_element_at(x, y, elementIndex);
if (pathElement == nullptr || pathElement->GetType() != TILE_ELEMENT_TYPE_PATH)
return MONEY32_UNDEFINED;
@ -634,8 +645,9 @@ int32_t tile_inspector_path_toggle_edge(int32_t x, int32_t y, int32_t elementInd
map_invalidate_tile_full(x << 5, y << 5);
rct_window * const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)
rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX
&& (uint32_t)y == windowTileInspectorTileY)
{
window_invalidate(tileInspectorWindow);
}
@ -646,12 +658,12 @@ int32_t tile_inspector_path_toggle_edge(int32_t x, int32_t y, int32_t elementInd
int32_t tile_inspector_entrance_make_usable(int32_t x, int32_t y, int32_t elementIndex, int32_t flags)
{
rct_tile_element * const entranceElement = map_get_nth_element_at(x, y, elementIndex);
rct_tile_element* const entranceElement = map_get_nth_element_at(x, y, elementIndex);
if (entranceElement == nullptr || entranceElement->GetType() != TILE_ELEMENT_TYPE_ENTRANCE)
return MONEY32_UNDEFINED;
Ride * ride = get_ride(entranceElement->properties.entrance.ride_index);
Ride* ride = get_ride(entranceElement->properties.entrance.ride_index);
if (ride == nullptr)
return MONEY32_UNDEFINED;
@ -662,16 +674,23 @@ int32_t tile_inspector_entrance_make_usable(int32_t x, int32_t y, int32_t elemen
switch (entranceElement->properties.entrance.type)
{
case ENTRANCE_TYPE_RIDE_ENTRANCE:
ride_set_entrance_location(ride, stationIndex, { x, y, entranceElement->base_height, (uint8_t)tile_element_get_direction(entranceElement) });
break;
case ENTRANCE_TYPE_RIDE_EXIT:
ride_set_exit_location(ride, stationIndex, { x, y, entranceElement->base_height, (uint8_t)tile_element_get_direction(entranceElement) });
break;
case ENTRANCE_TYPE_RIDE_ENTRANCE:
ride_set_entrance_location(
ride,
stationIndex,
{ x, y, entranceElement->base_height, (uint8_t)tile_element_get_direction(entranceElement) });
break;
case ENTRANCE_TYPE_RIDE_EXIT:
ride_set_exit_location(
ride,
stationIndex,
{ x, y, entranceElement->base_height, (uint8_t)tile_element_get_direction(entranceElement) });
break;
}
rct_window * const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)
rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX
&& (uint32_t)y == windowTileInspectorTileY)
{
window_invalidate(tileInspectorWindow);
}
@ -682,7 +701,7 @@ int32_t tile_inspector_entrance_make_usable(int32_t x, int32_t y, int32_t elemen
int32_t tile_inspector_wall_set_slope(int32_t x, int32_t y, int32_t elementIndex, int32_t slopeValue, int32_t flags)
{
rct_tile_element * const wallElement = map_get_nth_element_at(x, y, elementIndex);
rct_tile_element* const wallElement = map_get_nth_element_at(x, y, elementIndex);
if (wallElement == nullptr || wallElement->GetType() != TILE_ELEMENT_TYPE_WALL)
return MONEY32_UNDEFINED;
@ -695,8 +714,9 @@ int32_t tile_inspector_wall_set_slope(int32_t x, int32_t y, int32_t elementIndex
map_invalidate_tile_full(x << 5, y << 5);
rct_window * const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)
rct_window* const tileInspectorWindow = window_find_by_class(WC_TILE_INSPECTOR);
if (tileInspectorWindow != nullptr && (uint32_t)x == windowTileInspectorTileX
&& (uint32_t)y == windowTileInspectorTileY)
{
window_invalidate(tileInspectorWindow);
}
@ -709,7 +729,7 @@ int32_t tile_inspector_wall_set_slope(int32_t x, int32_t y, int32_t elementIndex
// Broxzier: Copied from track_remove and stripped of unneeded code, but I think this should be smaller
int32_t tile_inspector_track_base_height_offset(int32_t x, int32_t y, int32_t elementIndex, int8_t offset, int32_t flags)
{
rct_tile_element * const trackElement = map_get_nth_element_at(x, y, elementIndex);
rct_tile_element* const trackElement = map_get_nth_element_at(x, y, elementIndex);
if (offset == 0)
return 0;
@ -719,35 +739,35 @@ int32_t tile_inspector_track_base_height_offset(int32_t x, int32_t y, int32_t el
if (flags & GAME_COMMAND_FLAG_APPLY)
{
uint8_t type = track_element_get_type(trackElement);
int16_t originX = x << 5;
int16_t originY = y << 5;
int16_t originZ = trackElement->base_height * 8;
uint8_t rotation = tile_element_get_direction(trackElement);
uint8_t rideIndex = track_element_get_ride_index(trackElement);
Ride * ride = get_ride(rideIndex);
const rct_preview_track * trackBlock = get_track_def_from_ride(ride, type);
uint8_t type = track_element_get_type(trackElement);
int16_t originX = x << 5;
int16_t originY = y << 5;
int16_t originZ = trackElement->base_height * 8;
uint8_t rotation = tile_element_get_direction(trackElement);
uint8_t rideIndex = track_element_get_ride_index(trackElement);
Ride* ride = get_ride(rideIndex);
const rct_preview_track* trackBlock = get_track_def_from_ride(ride, type);
trackBlock += tile_element_get_track_sequence(trackElement);
uint8_t originDirection = tile_element_get_direction(trackElement);
switch (originDirection)
{
case 0:
originX -= trackBlock->x;
originY -= trackBlock->y;
break;
case 1:
originX -= trackBlock->y;
originY += trackBlock->x;
break;
case 2:
originX += trackBlock->x;
originY += trackBlock->y;
break;
case 3:
originX += trackBlock->y;
originY -= trackBlock->x;
break;
case 0:
originX -= trackBlock->x;
originY -= trackBlock->y;
break;
case 1:
originX -= trackBlock->y;
originY += trackBlock->x;
break;
case 2:
originX += trackBlock->x;
originY += trackBlock->y;
break;
case 3:
originX += trackBlock->y;
originY -= trackBlock->x;
break;
}
originZ -= trackBlock->z;
@ -759,30 +779,30 @@ int32_t tile_inspector_track_base_height_offset(int32_t x, int32_t y, int32_t el
switch (originDirection)
{
case 0:
elemX += trackBlock->x;
elemY += trackBlock->y;
break;
case 1:
elemX += trackBlock->y;
elemY -= trackBlock->x;
break;
case 2:
elemX -= trackBlock->x;
elemY -= trackBlock->y;
break;
case 3:
elemX -= trackBlock->y;
elemY += trackBlock->x;
break;
case 0:
elemX += trackBlock->x;
elemY += trackBlock->y;
break;
case 1:
elemX += trackBlock->y;
elemY -= trackBlock->x;
break;
case 2:
elemX -= trackBlock->x;
elemY -= trackBlock->y;
break;
case 3:
elemX -= trackBlock->y;
elemY += trackBlock->x;
break;
}
elemZ += trackBlock->z;
map_invalidate_tile_full(elemX, elemY);
bool found = false;
rct_tile_element * tileElement = map_get_first_element_at(elemX >> 5, elemY >> 5);
bool found = false;
rct_tile_element* tileElement = map_get_first_element_at(elemX >> 5, elemY >> 5);
do
{
if (tileElement->base_height != elemZ / 8)
@ -812,8 +832,8 @@ int32_t tile_inspector_track_base_height_offset(int32_t x, int32_t y, int32_t el
// track_remove returns here on failure, not sure when this would ever be hit. Only thing I can think of is for when
// you decrease the map size.
openrct2_assert(map_get_surface_element_at({elemX, elemY}) != nullptr, "No surface at %d,%d", elemX >> 5,
elemY >> 5);
openrct2_assert(
map_get_surface_element_at({ elemX, elemY }) != nullptr, "No surface at %d,%d", elemX >> 5, elemY >> 5);
// Keep?
// invalidate_test_results(rideIndex);
@ -831,10 +851,10 @@ int32_t tile_inspector_track_base_height_offset(int32_t x, int32_t y, int32_t el
// Sets chainlift, optionally for an entire track block
// Broxzier: Basically a copy of the above function, with just two different lines... should probably be combined somehow
int32_t tile_inspector_track_set_chain(int32_t x, int32_t y, int32_t elementIndex, bool entireTrackBlock, bool setChain,
int32_t flags)
int32_t tile_inspector_track_set_chain(
int32_t x, int32_t y, int32_t elementIndex, bool entireTrackBlock, bool setChain, int32_t flags)
{
rct_tile_element * const trackElement = map_get_nth_element_at(x, y, elementIndex);
rct_tile_element* const trackElement = map_get_nth_element_at(x, y, elementIndex);
if (trackElement == nullptr || trackElement->GetType() != TILE_ELEMENT_TYPE_TRACK)
return MONEY32_UNDEFINED;
@ -852,35 +872,35 @@ int32_t tile_inspector_track_set_chain(int32_t x, int32_t y, int32_t elementInde
return 0;
}
uint8_t type = track_element_get_type(trackElement);
int16_t originX = x << 5;
int16_t originY = y << 5;
int16_t originZ = trackElement->base_height * 8;
uint8_t rotation = tile_element_get_direction(trackElement);
uint8_t rideIndex = track_element_get_ride_index(trackElement);
Ride * ride = get_ride(rideIndex);
const rct_preview_track * trackBlock = get_track_def_from_ride(ride, type);
uint8_t type = track_element_get_type(trackElement);
int16_t originX = x << 5;
int16_t originY = y << 5;
int16_t originZ = trackElement->base_height * 8;
uint8_t rotation = tile_element_get_direction(trackElement);
uint8_t rideIndex = track_element_get_ride_index(trackElement);
Ride* ride = get_ride(rideIndex);
const rct_preview_track* trackBlock = get_track_def_from_ride(ride, type);
trackBlock += tile_element_get_track_sequence(trackElement);
uint8_t originDirection = tile_element_get_direction(trackElement);
switch (originDirection)
{
case 0:
originX -= trackBlock->x;
originY -= trackBlock->y;
break;
case 1:
originX -= trackBlock->y;
originY += trackBlock->x;
break;
case 2:
originX += trackBlock->x;
originY += trackBlock->y;
break;
case 3:
originX += trackBlock->y;
originY -= trackBlock->x;
break;
case 0:
originX -= trackBlock->x;
originY -= trackBlock->y;
break;
case 1:
originX -= trackBlock->y;
originY += trackBlock->x;
break;
case 2:
originX += trackBlock->x;
originY += trackBlock->y;
break;
case 3:
originX += trackBlock->y;
originY -= trackBlock->x;
break;
}
originZ -= trackBlock->z;
@ -892,30 +912,30 @@ int32_t tile_inspector_track_set_chain(int32_t x, int32_t y, int32_t elementInde
switch (originDirection)
{
case 0:
elemX += trackBlock->x;
elemY += trackBlock->y;
break;
case 1:
elemX += trackBlock->y;
elemY -= trackBlock->x;
break;
case 2:
elemX -= trackBlock->x;
elemY -= trackBlock->y;
break;
case 3:
elemX -= trackBlock->y;
elemY += trackBlock->x;
break;
case 0:
elemX += trackBlock->x;
elemY += trackBlock->y;
break;
case 1:
elemX += trackBlock->y;
elemY -= trackBlock->x;
break;
case 2:
elemX -= trackBlock->x;
elemY -= trackBlock->y;
break;
case 3:
elemX -= trackBlock->y;
elemY += trackBlock->x;
break;
}
elemZ += trackBlock->z;
map_invalidate_tile_full(elemX, elemY);
bool found = false;
rct_tile_element * tileElement = map_get_first_element_at(elemX >> 5, elemY >> 5);
bool found = false;
rct_tile_element* tileElement = map_get_first_element_at(elemX >> 5, elemY >> 5);
do
{
if (tileElement->base_height != elemZ / 8)
@ -945,8 +965,8 @@ int32_t tile_inspector_track_set_chain(int32_t x, int32_t y, int32_t elementInde
// track_remove returns here on failure, not sure when this would ever be hit. Only thing I can think of is for when
// you decrease the map size.
openrct2_assert(map_get_surface_element_at({elemX, elemY}) != nullptr, "No surface at %d,%d", elemX >> 5,
elemY >> 5);
openrct2_assert(
map_get_surface_element_at({ elemX, elemY }) != nullptr, "No surface at %d,%d", elemX >> 5, elemY >> 5);
// Keep?
// invalidate_test_results(rideIndex);
@ -964,9 +984,10 @@ int32_t tile_inspector_track_set_chain(int32_t x, int32_t y, int32_t elementInde
return 0;
}
int32_t tile_inspector_scenery_set_quarter_location(int32_t x, int32_t y, int32_t elementIndex, int32_t quarterIndex, int32_t flags)
int32_t
tile_inspector_scenery_set_quarter_location(int32_t x, int32_t y, int32_t elementIndex, int32_t quarterIndex, int32_t flags)
{
rct_tile_element * const tileElement = map_get_nth_element_at(x, y, elementIndex);
rct_tile_element* const tileElement = map_get_nth_element_at(x, y, elementIndex);
if (tileElement == nullptr || tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)
return MONEY32_UNDEFINED;
@ -991,9 +1012,10 @@ int32_t tile_inspector_scenery_set_quarter_location(int32_t x, int32_t y, int32_
return 0;
}
int32_t tile_inspector_scenery_set_quarter_collision(int32_t x, int32_t y, int32_t elementIndex, int32_t quarterIndex, int32_t flags)
int32_t tile_inspector_scenery_set_quarter_collision(
int32_t x, int32_t y, int32_t elementIndex, int32_t quarterIndex, int32_t flags)
{
rct_tile_element * const tileElement = map_get_nth_element_at(x, y, elementIndex);
rct_tile_element* const tileElement = map_get_nth_element_at(x, y, elementIndex);
if (tileElement == nullptr || tileElement->GetType() != TILE_ELEMENT_TYPE_SMALL_SCENERY)
return MONEY32_UNDEFINED;
@ -1014,7 +1036,7 @@ int32_t tile_inspector_scenery_set_quarter_collision(int32_t x, int32_t y, int32
int32_t tile_inspector_banner_toggle_blocking_edge(int32_t x, int32_t y, int32_t elementIndex, int32_t edgeIndex, int32_t flags)
{
rct_tile_element * const bannerElement = map_get_nth_element_at(x, y, elementIndex);
rct_tile_element* const bannerElement = map_get_nth_element_at(x, y, elementIndex);
if (bannerElement == nullptr || bannerElement->GetType() != TILE_ELEMENT_TYPE_BANNER)
return MONEY32_UNDEFINED;
@ -1034,7 +1056,7 @@ int32_t tile_inspector_banner_toggle_blocking_edge(int32_t x, int32_t y, int32_t
int32_t tile_inspector_corrupt_clamp(int32_t x, int32_t y, int32_t elementIndex, int32_t flags)
{
rct_tile_element * const corruptElement = map_get_nth_element_at(x, y, elementIndex);
rct_tile_element* const corruptElement = map_get_nth_element_at(x, y, elementIndex);
if (corruptElement == nullptr || corruptElement->GetType() != TILE_ELEMENT_TYPE_CORRUPT)
return MONEY32_UNDEFINED;
@ -1044,7 +1066,7 @@ int32_t tile_inspector_corrupt_clamp(int32_t x, int32_t y, int32_t elementIndex,
if (flags & GAME_COMMAND_FLAG_APPLY)
{
rct_tile_element * const nextElement = corruptElement + 1;
rct_tile_element* const nextElement = corruptElement + 1;
corruptElement->base_height = corruptElement->clearance_height = nextElement->base_height;
if ((uint32_t)x == windowTileInspectorTileX && (uint32_t)y == windowTileInspectorTileY)

View File

@ -12,7 +12,8 @@
#include "../common.h"
#include "Map.h"
enum TILE_INSPECTOR_ELEMENT_TYPE {
enum TILE_INSPECTOR_ELEMENT_TYPE
{
TILE_INSPECTOR_ELEMENT_ANY = 0,
TILE_INSPECTOR_ELEMENT_SURFACE,
TILE_INSPECTOR_ELEMENT_PATH,
@ -25,7 +26,8 @@ enum TILE_INSPECTOR_ELEMENT_TYPE {
TILE_INSPECTOR_ELEMENT_CORRUPT,
};
enum TILE_INSPECTOR_INSTRUCTION_TYPE {
enum TILE_INSPECTOR_INSTRUCTION_TYPE
{
TILE_INSPECTOR_ANY_REMOVE,
TILE_INSPECTOR_ANY_SWAP,
TILE_INSPECTOR_ANY_INSERT_CORRUPT,
@ -63,8 +65,12 @@ int32_t tile_inspector_path_toggle_edge(int32_t x, int32_t y, int32_t elementInd
int32_t tile_inspector_entrance_make_usable(int32_t x, int32_t y, int32_t elementIndex, int32_t flags);
int32_t tile_inspector_wall_set_slope(int32_t x, int32_t y, int32_t elementIndex, int32_t slopeValue, int32_t flags);
int32_t tile_inspector_track_base_height_offset(int32_t x, int32_t y, int32_t elementIndex, int8_t offset, int32_t flags);
int32_t tile_inspector_track_set_chain(int32_t x, int32_t y, int32_t elementIndex, bool entireTrackBlock, bool setChain, int32_t flags);
int32_t tile_inspector_scenery_set_quarter_location(int32_t x, int32_t y, int32_t elementIndex, int32_t quarterIndex, int32_t flags);
int32_t tile_inspector_scenery_set_quarter_collision(int32_t x, int32_t y, int32_t elementIndex, int32_t quarterIndex, int32_t flags);
int32_t tile_inspector_banner_toggle_blocking_edge(int32_t x, int32_t y, int32_t elementIndex, int32_t edgeIndex, int32_t flags);
int32_t tile_inspector_track_set_chain(
int32_t x, int32_t y, int32_t elementIndex, bool entireTrackBlock, bool setChain, int32_t flags);
int32_t tile_inspector_scenery_set_quarter_location(
int32_t x, int32_t y, int32_t elementIndex, int32_t quarterIndex, int32_t flags);
int32_t tile_inspector_scenery_set_quarter_collision(
int32_t x, int32_t y, int32_t elementIndex, int32_t quarterIndex, int32_t flags);
int32_t
tile_inspector_banner_toggle_blocking_edge(int32_t x, int32_t y, int32_t elementIndex, int32_t edgeIndex, int32_t flags);
int32_t tile_inspector_corrupt_clamp(int32_t x, int32_t y, int32_t elementIndex, int32_t flags);

View File

@ -7,14 +7,16 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "../common.h"
#include "../network/network.h"
#include "../OpenRCT2.h"
#include "Wall.h"
#include "../Cheats.h"
#include "../Game.h"
#include "../OpenRCT2.h"
#include "../common.h"
#include "../localisation/StringIds.h"
#include "../management/Finance.h"
#include "../network/network.h"
#include "../ride/RideGroupManager.h"
#include "../ride/Track.h"
#include "../ride/TrackData.h"
#include "Banner.h"
@ -26,7 +28,6 @@
#include "SmallScenery.h"
#include "Surface.h"
#include "Wall.h"
#include "../ride/RideGroupManager.h"
/**
* Gets whether the given track type can have a wall placed on the edge of the given direction.
@ -58,16 +59,13 @@ static bool TrackIsAllowedWallEdges(uint8_t rideType, uint8_t trackType, uint8_t
*
* rct2: 0x006E5CBA
*/
static bool WallCheckObstructionWithTrack(rct_scenery_entry * wall,
int32_t z0,
int32_t edge,
rct_tile_element * trackElement,
bool * wallAcrossTrack)
static bool WallCheckObstructionWithTrack(
rct_scenery_entry* wall, int32_t z0, int32_t edge, rct_tile_element* trackElement, bool* wallAcrossTrack)
{
int32_t trackType = track_element_get_type(trackElement);
int32_t sequence = tile_element_get_track_sequence(trackElement);
int32_t direction = (edge - tile_element_get_direction(trackElement)) & TILE_ELEMENT_DIRECTION_MASK;
Ride * ride = get_ride(track_element_get_ride_index(trackElement));
Ride* ride = get_ride(track_element_get_ride_index(trackElement));
if (TrackIsAllowedWallEdges(ride->type, trackType, sequence, direction))
{
@ -113,7 +111,7 @@ static bool WallCheckObstructionWithTrack(rct_scenery_entry * wall,
direction = tile_element_get_direction_with_offset(trackElement, 2);
if (direction == edge)
{
const rct_preview_track * trackBlock = &TrackBlocks[trackType][sequence];
const rct_preview_track* trackBlock = &TrackBlocks[trackType][sequence];
z = TrackCoordinates[trackType].z_begin;
z = trackElement->base_height + ((z - trackBlock->z) * 8);
if (z == z0)
@ -125,7 +123,7 @@ static bool WallCheckObstructionWithTrack(rct_scenery_entry * wall,
}
}
const rct_preview_track * trackBlock = &TrackBlocks[trackType][sequence + 1];
const rct_preview_track* trackBlock = &TrackBlocks[trackType][sequence + 1];
if (trackBlock->index != 0xFF)
{
return false;
@ -158,17 +156,12 @@ static bool WallCheckObstructionWithTrack(rct_scenery_entry * wall,
*
* rct2: 0x006E5C1A
*/
static bool WallCheckObstruction(rct_scenery_entry * wall,
int32_t x,
int32_t y,
int32_t z0,
int32_t z1,
int32_t edge,
bool * wallAcrossTrack)
static bool WallCheckObstruction(
rct_scenery_entry* wall, int32_t x, int32_t y, int32_t z0, int32_t z1, int32_t edge, bool* wallAcrossTrack)
{
int32_t entryType, sequence;
rct_scenery_entry * entry;
rct_large_scenery_tile * tile;
rct_scenery_entry* entry;
rct_large_scenery_tile* tile;
*wallAcrossTrack = false;
gMapGroundFlags = ELEMENT_IS_ABOVE_GROUND;
@ -178,13 +171,16 @@ static bool WallCheckObstruction(rct_scenery_entry * wall,
return false;
}
rct_tile_element * tileElement = map_get_first_element_at(x / 32, y / 32);
rct_tile_element* tileElement = map_get_first_element_at(x / 32, y / 32);
do
{
int32_t elementType = tileElement->GetType();
if (elementType == TILE_ELEMENT_TYPE_SURFACE) continue;
if (z0 >= tileElement->clearance_height) continue;
if (z1 <= tileElement->base_height) continue;
if (elementType == TILE_ELEMENT_TYPE_SURFACE)
continue;
if (z0 >= tileElement->clearance_height)
continue;
if (z1 <= tileElement->base_height)
continue;
if (elementType == TILE_ELEMENT_TYPE_WALL)
{
int32_t direction = tile_element_get_direction(tileElement);
@ -195,51 +191,52 @@ static bool WallCheckObstruction(rct_scenery_entry * wall,
}
continue;
}
if ((tileElement->flags & 0x0F) == 0) continue;
if ((tileElement->flags & 0x0F) == 0)
continue;
switch (elementType) {
case TILE_ELEMENT_TYPE_ENTRANCE:
map_obstruction_set_error_text(tileElement);
return false;
case TILE_ELEMENT_TYPE_PATH:
if (tileElement->properties.path.edges & (1 << edge))
{
switch (elementType)
{
case TILE_ELEMENT_TYPE_ENTRANCE:
map_obstruction_set_error_text(tileElement);
return false;
}
break;
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
entryType = scenery_large_get_type(tileElement);
sequence = scenery_large_get_sequence(tileElement);
entry = get_large_scenery_entry(entryType);
tile = &entry->large_scenery.tiles[sequence];
{
int32_t direction = ((edge - tile_element_get_direction(tileElement)) & TILE_ELEMENT_DIRECTION_MASK) + 8;
if (!(tile->flags & (1 << direction)))
case TILE_ELEMENT_TYPE_PATH:
if (tileElement->properties.path.edges & (1 << edge))
{
map_obstruction_set_error_text(tileElement);
return false;
}
}
break;
case TILE_ELEMENT_TYPE_SMALL_SCENERY:
entryType = tileElement->properties.scenery.type;
entry = get_small_scenery_entry(entryType);
if (scenery_small_entry_has_flag(entry, SMALL_SCENERY_FLAG_NO_WALLS))
{
map_obstruction_set_error_text(tileElement);
return false;
}
break;
case TILE_ELEMENT_TYPE_TRACK:
if (!WallCheckObstructionWithTrack(wall, z0, edge, tileElement, wallAcrossTrack))
{
return false;
}
break;
break;
case TILE_ELEMENT_TYPE_LARGE_SCENERY:
entryType = scenery_large_get_type(tileElement);
sequence = scenery_large_get_sequence(tileElement);
entry = get_large_scenery_entry(entryType);
tile = &entry->large_scenery.tiles[sequence];
{
int32_t direction = ((edge - tile_element_get_direction(tileElement)) & TILE_ELEMENT_DIRECTION_MASK) + 8;
if (!(tile->flags & (1 << direction)))
{
map_obstruction_set_error_text(tileElement);
return false;
}
}
break;
case TILE_ELEMENT_TYPE_SMALL_SCENERY:
entryType = tileElement->properties.scenery.type;
entry = get_small_scenery_entry(entryType);
if (scenery_small_entry_has_flag(entry, SMALL_SCENERY_FLAG_NO_WALLS))
{
map_obstruction_set_error_text(tileElement);
return false;
}
break;
case TILE_ELEMENT_TYPE_TRACK:
if (!WallCheckObstructionWithTrack(wall, z0, edge, tileElement, wallAcrossTrack))
{
return false;
}
break;
}
}
while (!(tileElement++)->IsLastForTile());
} while (!(tileElement++)->IsLastForTile());
return true;
}
@ -297,15 +294,16 @@ static constexpr const uint8_t EdgeSlopes[][4] = {
#pragma endregion
static money32 WallPlace(uint8_t wallType,
int16_t x,
int16_t y,
int16_t z,
uint8_t edge,
uint8_t primaryColour,
uint8_t secondaryColour,
uint8_t tertiaryColour,
uint8_t flags)
static money32 WallPlace(
uint8_t wallType,
int16_t x,
int16_t y,
int16_t z,
uint8_t edge,
uint8_t primaryColour,
uint8_t secondaryColour,
uint8_t tertiaryColour,
uint8_t flags)
{
LocationXYZ16 position = { x, y, z };
@ -325,14 +323,11 @@ static money32 WallPlace(uint8_t wallType,
return MONEY32_UNDEFINED;
}
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) &&
!(flags & GAME_COMMAND_FLAG_PATH_SCENERY) &&
!gCheatsSandboxMode)
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !(flags & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsSandboxMode)
{
if (position.z == 0)
{
if (!map_is_location_in_park({position.x, position.y}))
if (!map_is_location_in_park({ position.x, position.y }))
{
return MONEY32_UNDEFINED;
}
@ -346,7 +341,7 @@ static money32 WallPlace(uint8_t wallType,
uint8_t edgeSlope = 0;
if (position.z == 0)
{
rct_tile_element * surfaceElement = map_get_surface_element_at({position.x, position.y});
rct_tile_element* surfaceElement = map_get_surface_element_at({ position.x, position.y });
if (surfaceElement == nullptr)
{
return MONEY32_UNDEFINED;
@ -362,7 +357,7 @@ static money32 WallPlace(uint8_t wallType,
}
}
rct_tile_element * surfaceElement = map_get_surface_element_at({position.x, position.y});
rct_tile_element* surfaceElement = map_get_surface_element_at({ position.x, position.y });
if (surfaceElement == nullptr)
{
return MONEY32_UNDEFINED;
@ -449,7 +444,7 @@ static money32 WallPlace(uint8_t wallType,
}
}
BannerIndex bannerIndex = BANNER_INDEX_NULL;
rct_scenery_entry * wallEntry = get_wall_entry(wallType);
rct_scenery_entry* wallEntry = get_wall_entry(wallType);
if (wallEntry == nullptr)
{
@ -465,7 +460,7 @@ static money32 WallPlace(uint8_t wallType,
return MONEY32_UNDEFINED;
}
rct_banner * banner = &gBanners[bannerIndex];
rct_banner* banner = &gBanners[bannerIndex];
if (flags & GAME_COMMAND_FLAG_APPLY)
{
banner->flags |= BANNER_FLAG_IS_WALL;
@ -497,13 +492,7 @@ static money32 WallPlace(uint8_t wallType,
bool wallAcrossTrack = false;
if (!(flags & GAME_COMMAND_FLAG_PATH_SCENERY) && !gCheatsDisableClearanceChecks)
{
if (!WallCheckObstruction(wallEntry,
position.x,
position.y,
position.z / 8,
clearanceHeight,
edge,
&wallAcrossTrack))
if (!WallCheckObstruction(wallEntry, position.x, position.y, position.z / 8, clearanceHeight, edge, &wallAcrossTrack))
{
return MONEY32_UNDEFINED;
}
@ -525,7 +514,7 @@ static money32 WallPlace(uint8_t wallType,
network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord);
}
rct_tile_element * tileElement = tile_element_insert(position.x / 32, position.y / 32, position.z / 8, 0);
rct_tile_element* tileElement = tile_element_insert(position.x / 32, position.y / 32, position.z / 8, 0);
assert(tileElement != nullptr);
map_animation_create(MAP_ANIMATION_TYPE_WALL, position.x, position.y, position.z / 8);
@ -572,14 +561,15 @@ static money32 WallPlace(uint8_t wallType,
}
}
static money32 WallSetColour(int16_t x,
int16_t y,
uint8_t baseHeight,
uint8_t direction,
uint8_t primaryColour,
uint8_t secondaryColour,
uint8_t tertiaryColour,
uint8_t flags)
static money32 WallSetColour(
int16_t x,
int16_t y,
uint8_t baseHeight,
uint8_t direction,
uint8_t primaryColour,
uint8_t secondaryColour,
uint8_t tertiaryColour,
uint8_t flags)
{
gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING;
int32_t z = baseHeight * 8;
@ -588,15 +578,12 @@ static money32 WallSetColour(int16_t x,
gCommandPosition.y = y + 16;
gCommandPosition.z = z;
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) &&
!map_is_location_in_park({x, y}) &&
!gCheatsSandboxMode)
if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !map_is_location_in_park({ x, y }) && !gCheatsSandboxMode)
{
return MONEY32_UNDEFINED;
}
rct_tile_element * wallElement = map_get_wall_element_at(x, y, baseHeight, direction);
rct_tile_element* wallElement = map_get_wall_element_at(x, y, baseHeight, direction);
if (wallElement == nullptr)
{
return 0;
@ -609,7 +596,7 @@ static money32 WallSetColour(int16_t x,
if (flags & GAME_COMMAND_FLAG_APPLY)
{
rct_scenery_entry * scenery_entry = get_wall_entry(wallElement->properties.wall.type);
rct_scenery_entry* scenery_entry = get_wall_entry(wallElement->properties.wall.type);
wall_set_primary_colour(wallElement, primaryColour);
wall_set_secondary_colour(wallElement, secondaryColour);
@ -623,42 +610,42 @@ static money32 WallSetColour(int16_t x,
return 0;
}
uint8_t wall_get_animation_frame(const rct_tile_element * wallElement)
uint8_t wall_get_animation_frame(const rct_tile_element* wallElement)
{
return (wallElement->properties.wall.animation >> 3) & 0xF;
}
void wall_set_animation_frame(rct_tile_element * wallElement, uint8_t frameNum)
void wall_set_animation_frame(rct_tile_element* wallElement, uint8_t frameNum)
{
wallElement->properties.wall.animation &= WALL_ANIMATION_FLAG_ALL_FLAGS;
wallElement->properties.wall.animation |= (frameNum & 0xF) << 3;
}
colour_t wall_get_primary_colour(const rct_tile_element * tileElement)
colour_t wall_get_primary_colour(const rct_tile_element* tileElement)
{
return tileElement->properties.wall.colour_1 & TILE_ELEMENT_COLOUR_MASK;
}
colour_t wall_get_secondary_colour(const rct_tile_element * wallElement)
colour_t wall_get_secondary_colour(const rct_tile_element* wallElement)
{
uint8_t secondaryColour = (wallElement->properties.wall.colour_1 &~ TILE_ELEMENT_COLOUR_MASK) >> 5;
uint8_t secondaryColour = (wallElement->properties.wall.colour_1 & ~TILE_ELEMENT_COLOUR_MASK) >> 5;
secondaryColour |= (wallElement->flags & 0x60) >> 2;
return secondaryColour;
}
colour_t wall_get_tertiary_colour(const rct_tile_element * tileElement)
colour_t wall_get_tertiary_colour(const rct_tile_element* tileElement)
{
return tileElement->properties.wall.colour_3 & TILE_ELEMENT_COLOUR_MASK;
}
void wall_set_primary_colour(rct_tile_element * tileElement, colour_t colour)
void wall_set_primary_colour(rct_tile_element* tileElement, colour_t colour)
{
assert(colour <= 31);
tileElement->properties.wall.colour_1 &= ~TILE_ELEMENT_COLOUR_MASK;
tileElement->properties.wall.colour_1 |= colour;
}
void wall_set_secondary_colour(rct_tile_element * wallElement, colour_t secondaryColour)
void wall_set_secondary_colour(rct_tile_element* wallElement, colour_t secondaryColour)
{
wallElement->properties.wall.colour_1 &= TILE_ELEMENT_COLOUR_MASK;
wallElement->properties.wall.colour_1 |= (secondaryColour & 0x7) << 5;
@ -666,7 +653,7 @@ void wall_set_secondary_colour(rct_tile_element * wallElement, colour_t secondar
wallElement->flags |= (secondaryColour & 0x18) << 2;
}
void wall_set_tertiary_colour(rct_tile_element * tileElement, colour_t colour)
void wall_set_tertiary_colour(rct_tile_element* tileElement, colour_t colour)
{
assert(colour <= 31);
tileElement->properties.wall.colour_3 &= ~TILE_ELEMENT_COLOUR_MASK;
@ -679,7 +666,7 @@ void wall_set_tertiary_colour(rct_tile_element * tileElement, colour_t colour)
*/
void wall_remove_at(int32_t x, int32_t y, int32_t z0, int32_t z1)
{
rct_tile_element * tileElement;
rct_tile_element* tileElement;
z0 /= 8;
z1 /= 8;
@ -698,8 +685,7 @@ repeat:
map_invalidate_tile_zoom1(x, y, tileElement->base_height * 8, tileElement->base_height * 8 + 72);
tile_element_remove(tileElement);
goto repeat;
}
while (!(tileElement++)->IsLastForTile());
} while (!(tileElement++)->IsLastForTile());
}
/**
@ -717,7 +703,7 @@ void wall_remove_at_z(int32_t x, int32_t y, int32_t z)
*/
void wall_remove_intersecting_walls(int32_t x, int32_t y, int32_t z0, int32_t z1, int32_t direction)
{
rct_tile_element * tileElement;
rct_tile_element* tileElement;
tileElement = map_get_first_element_at(x >> 5, y >> 5);
do
@ -735,21 +721,15 @@ void wall_remove_intersecting_walls(int32_t x, int32_t y, int32_t z0, int32_t z1
map_invalidate_tile_zoom1(x, y, tileElement->base_height * 8, tileElement->base_height * 8 + 72);
tile_element_remove(tileElement);
tileElement--;
}
while (!(tileElement++)->IsLastForTile());
} while (!(tileElement++)->IsLastForTile());
}
/**
*
* rct2: 0x006E519A
*/
void game_command_place_wall(int32_t * eax,
int32_t * ebx,
int32_t * ecx,
int32_t * edx,
[[maybe_unused]] int32_t * esi,
int32_t * edi,
int32_t * ebp)
void game_command_place_wall(
int32_t* eax, int32_t* ebx, int32_t* ecx, int32_t* edx, [[maybe_unused]] int32_t* esi, int32_t* edi, int32_t* ebp)
{
*ebx = WallPlace(
(*ebx >> 8) & 0xFF,
@ -760,19 +740,19 @@ void game_command_place_wall(int32_t * eax,
(*edx >> 8) & 0xFF,
*ebp & 0xFF,
(*ebp >> 8) & 0xFF,
*ebx & 0xFF
);
*ebx & 0xFF);
}
money32 wall_place(int32_t type,
int32_t x,
int32_t y,
int32_t z,
int32_t edge,
int32_t primaryColour,
int32_t secondaryColour,
int32_t tertiaryColour,
int32_t flags)
money32 wall_place(
int32_t type,
int32_t x,
int32_t y,
int32_t z,
int32_t edge,
int32_t primaryColour,
int32_t secondaryColour,
int32_t tertiaryColour,
int32_t flags)
{
int32_t eax = x;
int32_t ebx = flags | (type << 8);
@ -789,13 +769,14 @@ money32 wall_place(int32_t type,
*
* rct2: 0x006E56B5
*/
void game_command_set_wall_colour(int32_t * eax,
int32_t * ebx,
int32_t * ecx,
int32_t * edx,
[[maybe_unused]] int32_t * esi,
[[maybe_unused]] int32_t * edi,
int32_t * ebp)
void game_command_set_wall_colour(
int32_t* eax,
int32_t* ebx,
int32_t* ecx,
int32_t* edx,
[[maybe_unused]] int32_t* esi,
[[maybe_unused]] int32_t* edi,
int32_t* ebp)
{
*ebx = WallSetColour(
*eax & 0xFFFF,
@ -805,6 +786,5 @@ void game_command_set_wall_colour(int32_t * eax,
(*ebx >> 8) & 0xFF,
*ebp & 0xFF,
(*ebp >> 8) & 0xFF,
*ebx & 0xFF
);
*ebx & 0xFF);
}

View File

@ -12,20 +12,21 @@
#include "../common.h"
#include "TileElement.h"
enum {
enum
{
WALL_ANIMATION_FLAG_ACROSS_TRACK = (1 << 2),
// 3 - 6 animation frame number
WALL_ANIMATION_FLAG_DIRECTION_BACKWARD = (1 << 7),
WALL_ANIMATION_FLAG_ALL_FLAGS = WALL_ANIMATION_FLAG_ACROSS_TRACK | WALL_ANIMATION_FLAG_DIRECTION_BACKWARD
};
colour_t wall_get_primary_colour(const rct_tile_element * tileElement);
colour_t wall_get_secondary_colour(const rct_tile_element * wallElement);
colour_t wall_get_tertiary_colour(const rct_tile_element * tileElement);
void wall_set_primary_colour(rct_tile_element * tileElement, colour_t colour);
void wall_set_secondary_colour(rct_tile_element * wallElement, colour_t secondaryColour);
void wall_set_tertiary_colour(rct_tile_element * tileElement, colour_t colour);
uint8_t wall_get_animation_frame(const rct_tile_element * fenceElement);
void wall_set_animation_frame(rct_tile_element * wallElement, uint8_t frameNum);
colour_t wall_get_primary_colour(const rct_tile_element* tileElement);
colour_t wall_get_secondary_colour(const rct_tile_element* wallElement);
colour_t wall_get_tertiary_colour(const rct_tile_element* tileElement);
void wall_set_primary_colour(rct_tile_element* tileElement, colour_t colour);
void wall_set_secondary_colour(rct_tile_element* wallElement, colour_t secondaryColour);
void wall_set_tertiary_colour(rct_tile_element* tileElement, colour_t colour);
uint8_t wall_get_animation_frame(const rct_tile_element* fenceElement);
void wall_set_animation_frame(rct_tile_element* wallElement, uint8_t frameNum);
money32 wall_remove(int16_t x, int16_t y, uint8_t baseHeight, uint8_t direction, uint8_t flags);

View File

@ -12,17 +12,19 @@
#include "../common.h"
enum {
enum
{
WATER_FLAGS_ALLOW_DUCKS = (1 << 0)
};
#pragma pack(push, 1)
struct rct_water_type {
rct_string_id string_idx; // 0x00
uint32_t image_id; // 0x02
uint32_t palette_index_1; // 0x06
uint32_t palette_index_2; // 0x0A
uint16_t flags; // 0x0E
struct rct_water_type
{
rct_string_id string_idx; // 0x00
uint32_t image_id; // 0x02
uint32_t palette_index_1; // 0x06
uint32_t palette_index_2; // 0x0A
uint16_t flags; // 0x0E
};
assert_struct_size(rct_water_type, 16);
#pragma pack(pop)