Merge pull request #6 from IntelOrca/develop

Fast forward
This commit is contained in:
Michael Steenbeek 2015-03-26 21:42:53 +01:00
commit 801db92a17
61 changed files with 4932 additions and 639 deletions

View File

@ -3,8 +3,5 @@
set -ev
sudo rm -rf /usr/local/cross-tools/i686-w64-mingw32
#rm -rf .cache
rm -rf .cache/*.patch
rm -rf .cache/SDL2-2.0.3
rm -rf .cache/i686-w64-mingw32-pkg-config
rm -rf .cache
rm -rf build

View File

@ -20,4 +20,5 @@
- Feature: RollerCoaster Tycoon 1 scenarios can now be opened in the scenario editor or by using the 'edit' command line action.
- Feature: Title sequence music can now be disabled or changed to the RollerCoaster Tycoon 1 theme music.
- Feature: (Random) map generator available in scenario editor, accessible via the view menu.
- Feature: Looping RollerCoaster now supports both "Powered launch (passing station)" and "Powered launch (without passing station)"
- Fix: Litter bins now get full and require emptying by handymen.

View File

@ -55,7 +55,7 @@ if [[ `uname` == "Darwin" ]]; then
if [[ ! -f $cachedir/$mingw_tar ]]; then
wget "https://downloads.sourceforge.net/project/mingw-w64/Toolchains targetting Win32/Automated Builds/$mingw_tar" --output-document $cachedir/$mingw_tar
fi
if [[ ! -d $ming_path ]]; then
if [[ ! -d "$mingw_path" ]]; then
pushd /usr/local/
sudo mkdir $mingw_name

View File

@ -141,6 +141,7 @@
<ClCompile Include="..\src\world\map_animation.c" />
<ClCompile Include="..\src\world\map_helpers.c" />
<ClCompile Include="..\src\world\park.c" />
<ClCompile Include="..\src\world\scenery.c" />
<ClCompile Include="..\src\world\sprite.c" />
</ItemGroup>
<ItemGroup>
@ -203,6 +204,7 @@
<ClInclude Include="..\src\world\climate.h" />
<ClInclude Include="..\src\world\entrance.h" />
<ClInclude Include="..\src\world\footpath.h" />
<ClInclude Include="..\src\world\fountain.h" />
<ClInclude Include="..\src\world\map.h" />
<ClInclude Include="..\src\world\mapgen.h" />
<ClInclude Include="..\src\world\map_animation.h" />

View File

@ -351,11 +351,9 @@
<ClCompile Include="..\src\windows\sign.c">
<Filter>Source\Windows</Filter>
</ClCompile>
<ClCompile Include="..\lib\lodepng\lodepng.c" />
<ClCompile Include="..\src\ride\station.c">
<Filter>Source\Ride</Filter>
</ClCompile>
<ClCompile Include="..\lib\lodepng\lodepng.c" />
<ClCompile Include="..\src\windows\ride_construction.c">
<Filter>Source\Windows</Filter>
</ClCompile>
@ -374,7 +372,7 @@
<ClCompile Include="..\src\diagnostic.c">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="..\lib\libspeex\resample.c;..\lib\lodepng\lodepng.c" />
<ClCompile Include="..\lib\lodepng\lodepng.c" />
<ClCompile Include="..\src\windows\editor_bottom_toolbar.c">
<Filter>Source\Windows</Filter>
</ClCompile>
@ -384,7 +382,7 @@
<ClCompile Include="..\src\windows\editor_object_selection.c">
<Filter>Source\Windows</Filter>
</ClCompile>
<ClCompile Include="..\lib\libspeex\resample.c;..\lib\lodepng\lodepng.c" />
<ClCompile Include="..\lib\lodepng\lodepng.c" />
<ClCompile Include="..\src\localisation\user.c">
<Filter>Source\Localisation</Filter>
</ClCompile>
@ -429,6 +427,9 @@
<ClCompile Include="..\src\world\map_animation.c">
<Filter>Source\World</Filter>
</ClCompile>
<ClCompile Include="..\src\world\scenery.c">
<Filter>Source\World</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\management\award.h">
@ -632,5 +633,8 @@
<ClInclude Include="..\src\world\map_animation.h">
<Filter>Source\World</Filter>
</ClInclude>
<ClInclude Include="..\src\world\fountain.h">
<Filter>Source\World</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -14,7 +14,7 @@ An open source clone of RollerCoaster Tycoon 2 built by decompiling the original
- 1.1 - [Background](#11-background)
- 1.2 - [Decompiling the game](#12-decompiling-the-game)
- 1.3 - [Progress](#13-progress)
- 1.4 - [Aim](#14-aim)
- 1.4 - [Aim](#14-aim)
- 2 - [Downloading the game / Building the source code](#2-building-the-source-code)
- 2.1 - [Prerequisites](#21-prerequisites)
- 2.2 - [Compiling and running](#22-compiling-and-running)
@ -29,7 +29,7 @@ An open source clone of RollerCoaster Tycoon 2 built by decompiling the original
# 1 Introduction
## 1.1 Background
**OpenRCT2** is an attempt to decompile RollerCoaster Tycoon 2 into C. RollerCoaster Tycoon 2 was originally written in MASM and Visual C++ where functions related to interfacing with the operating system were written in C (supposedly 1%), with the rest of the game being written in pure x86 assembly. For an example of this method, OpenTTD was formed through a similar procedure; the original game, Transport Tycoon Deluxe, was decompiled into C which allowed for the addition of thousands of features to the game. RollerCoaster Tycoon 2 uses the third version of Chris Sawyer's engine, which shares some code with Transport Tycoon. This is reflected in the usage of OpenTTD 0.1 code such as the windowing system and graphics rendering. While the version of the engine used in Chris Sawyer's Locomotion is newer, OpenRCT2 is currently targeting the RollerCoaster Tycoon 2 engine to ease the decompilation process.
**OpenRCT2** is an attempt to decompile RollerCoaster Tycoon 2 into C. RollerCoaster Tycoon 2 was originally written in MASM and Visual C++ where functions related to interfacing with the operating system were written in C (supposedly 1%), with the rest of the game being written in pure x86 assembly. For an example of this method, OpenTTD was formed through a similar procedure; the original game, Transport Tycoon Deluxe, was decompiled into C which allowed for the addition of thousands of features to the game. RollerCoaster Tycoon 2 uses the third version of Chris Sawyer's engine, which shares some code with Transport Tycoon. This is reflected in the usage of OpenTTD 0.1 code such as the windowing system and graphics rendering. While the version of the engine used in Chris Sawyer's Locomotion is newer, OpenRCT2 is currently targeting the RollerCoaster Tycoon 2 engine to ease the decompilation process.
## 1.2 Decompiling the game
In order to decompile the game gradually without introducing new bugs, each procedure in RollerCoaster Tycoon 2 is to be re-written in C on an individual basis. To test the accuracy of the re-written procedures, the decompiled C procedures are compiled into a DLL (*openrct2.dll*) which exports an entry procedure mimicking the WinMain function in RollerCoaster Tycoon 2. The original executable *rct2.exe* has been patched so that *openrct2.dll* and WinMain are in the DLL import table and the WinMain export procedure in *openrct2.dll* is called at the start of the WinMain procedure in *rct2.exe* before returning. With this system implemented, starting rct2.exe calls the new DLL as part of its initialization; the DLL can then run all the decompiled code whilst still being able to read / write to the *rct2.exe* memory model and run *rct2.exe* procedures.
@ -42,17 +42,19 @@ Currently, the windowing system, graphics rendering and basic game loop are bein
As of 16th August 2014, various UI improvements have already been made, settings are now stored in a local INI file. More drawing functions have now been decompiled but still remain cryptic C, much of the game management have been decompiled (e.g. peep generation, awards, cash out) and almost half of the windows. A rough estimate based on number of functions in the original game and number of functions now in C tells us that the project is approximately 25% complete of its target goal of having the game run on 100% C code. More information can be found in [changes to original game](https://github.com/IntelOrca/OpenRCT2/wiki/Changes-to-original-game) and [window progress](https://github.com/IntelOrca/OpenRCT2/wiki/Window-progress).
## 1.4 Aim
The aim is to completely decompile RollerCoaster Tycoon 2 into C so that cross-platform support, new features, and new gameplay can be added in a similar fashion to OpenTTD. With the addition of SDL2, the game can already be run in a resizeable window (which was not possible originally). Once the game has been fully decompiled, additional gameplay features, gameplay tweaks, and improvements can be introduced. The following is only a brief, non-exhaustive list of the possibilities - there is much more possible:
The aim is to completely decompile RollerCoaster Tycoon 2 into C so that cross-platform support, new features, and new gameplay can be added in a similar fashion to OpenTTD. With the addition of SDL2, the game can already be run in a resizeable window (which was not possible originally). Once the game has been fully decompiled, additional gameplay features, gameplay tweaks, and improvements can be introduced. The following is only a brief, non-exhaustive list of the possibilities - there are many more:
- Improved peep path-finding
- Increased window / ride / object / map / construction limits
- More sandbox-friendly gameplay
- Editing available objects
- Improved title sequence
- Re-introduction of RollerCoaster Tycoon 1 mechanics
- Shuttle Loop compatibility
- Have Fun! objective
- Finish building five coasters objective
- Using the mountain tool during the game
- Translation into more languages
- Re-introduction of RollerCoaster Tycoon 1 mechanics:
- Shuttle Loop compatibility
- Have Fun! objective
- Finish building five coasters objective
- Using the mountain tool during the game
# 2 Downloading the game / Building the source code
@ -122,7 +124,7 @@ In general, small changes that improve code quality and make it easier to reason
While decompilation is an ongoing process, this does not prohibit changes being made to the game. New features or bugfixes can be added, with caution, if the underlying code has been decompiled. When implementing these changes, ensure that comments are added to clearly identify where code has been intentionally changed so that it functions differently to the original game; this is essential to ensuring all research from reverse-engineering can still be applied.
## 3.5 Translation
You can translate the game into other languages by editing the language files in the data directory. Please join discussions and submit pull requests to https://github.com/OpenRCT2/Localisation.
Translations are in progress for German, Dutch, French, Hungarian, Polish, Spanish, Swedish, Italian, and more. You can translate the game into other languages by editing the language files in the data directory. Please join discussions and submit pull requests to https://github.com/OpenRCT2/Localisation.
# 4 License
**OpenRCT2** is licensed under the GNU General Public License version 3.

View File

@ -67,6 +67,7 @@
#define RCT2_ADDRESS_DSOUND_GUID 0x009AAC5D
#define RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER 0x009AAC6E
// When all sounds reversed replace with gConfigSound.ride_music
#define RCT2_ADDRESS_CONFIG_MUSIC 0x009AAC72
#define RCT2_ADDRESS_CONFIG_FLAGS 0x009AAC74
@ -309,7 +310,7 @@
#define RCT2_ADDRESS_SPRITES_NEXT_INDEX 0x013573BC
#define RCT2_ADDRESS_SPRITES_START_VEHICLE 0x013573BE
#define RCT2_ADDRESS_SPRITES_START_PEEP 0x013573C0
#define RCT2_ADDRESS_SPRITES_START_TEXTFX 0x013573C2
#define RCT2_ADDRESS_SPRITES_START_MISC 0x013573C2
#define RCT2_ADDRESS_SPRITES_START_LITTER 0x013573C4
#define RCT2_ADDRESS_PARK_NAME 0x013573D4
@ -396,6 +397,8 @@
#define RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION 0x0138869E
#define RCT2_ADDRESS_RIDE_MEASUREMENTS 0x0138B60C
#define RCT2_ADDRESS_GRASS_SCENERY_TILEPOS 0x013B0E70
#define RCT2_ADDRESS_CLIMATE 0x013CA746
#define RCT2_ADDRESS_CURRENT_WEATHER 0x013CA74A
#define RCT2_ADDRESS_NEXT_WEATHER 0x013CA74B

View File

@ -1768,6 +1768,18 @@ void audio_init2(int device)
RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) |= 1 << 4;
config_save_default();
}
// When all sound code is reversed this can be removed.
if (!gConfigSound.sound){
toggle_all_sounds();
}
// When all sound code is reversed this can be removed.
if (!gConfigSound.ride_music){
RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) ^= 1;
if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) == 0)
stop_ride_music();
}
}
/**
@ -1794,19 +1806,34 @@ void audio_close()
}
}
/* rct2: 0x006BAB8A */
void toggle_all_sounds(){
// When all sound code is reversed replace with gConfigSound.sound
RCT2_GLOBAL(0x009AF59D, uint8) ^= 1;
if (RCT2_GLOBAL(0x009AF59D, uint8) == 0) {
stop_title_music();
pause_sounds();
}
else{
unpause_sounds();
}
}
/**
*
* rct2: 0x006BABB4
*/
void pause_sounds()
{
if (++RCT2_GLOBAL(0x009AF59C, uint8) == 1) {
// When all sound code is reversed replace with gConfigSound.sound
RCT2_GLOBAL(0x009AF59C, uint8) = 1;
if (RCT2_GLOBAL(0x009AF59C, uint8) == 1) {
stop_other_sounds();
stop_vehicle_sounds();
stop_ride_music();
stop_crowd_sound();
}
g_sounds_disabled = 1;
gConfigSound.sound = 0;
}
/**
@ -1815,8 +1842,9 @@ void pause_sounds()
*/
void unpause_sounds()
{
RCT2_GLOBAL(0x009AF59C, uint8)--;
g_sounds_disabled = 0;
// When all sound code is reversed replace with gConfigSound.sound
RCT2_GLOBAL(0x009AF59C, uint8) = 0;
gConfigSound.sound = 1;
}
/**

View File

@ -218,13 +218,10 @@ void audio_init1();
void audio_init2(int device);
void audio_close();
void pause_sounds();
void toggle_all_sounds();
void unpause_sounds();
void stop_vehicle_sounds();
// 0x009AF59C probably does the same job
// once it's confirmed and calls in pause_sounds() are reversed, it can be used instead of this
int g_sounds_disabled;
typedef enum {
SOUND_LIFT_1 = 0,
SOUND_TRACK_FRICTION_1 = 1,

View File

@ -172,6 +172,8 @@ config_property_definition _soundDefinitions[] = {
{ offsetof(sound_configuration, forced_software_buffering), "forced_software_buffering", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL },
{ offsetof(sound_configuration, sound_quality), "sound_quality", CONFIG_VALUE_TYPE_UINT8, 2, NULL },
{ offsetof(sound_configuration, title_music), "title_music", CONFIG_VALUE_TYPE_UINT8, 2, NULL },
{ offsetof(sound_configuration, sound), "sound", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL },
{ offsetof(sound_configuration, ride_music), "ride_music", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL },
};
config_section_definition _sectionDefinitions[] = {

View File

@ -141,6 +141,8 @@ typedef struct {
sint8 forced_software_buffering;
sint8 sound_quality;
uint8 title_music;
uint8 sound;
uint8 ride_music;
} sound_configuration;
typedef struct {

View File

@ -707,7 +707,7 @@ static int editor_read_s4(rct1_s4 *src)
read((void*)0x0135A8F4, &src->string_table, 0x2F51C);
memset((void*)0x013CA672, 0, 204);
read((void*)0x0138B580, &src->animated_objects, 0x258F2);
read((void*)0x0138B580, &src->map_animations, 0x258F2);
read((void*)0x013C6A72, &src->patrol_areas, sizeof(src->patrol_areas));
char *esi = (char*)0x13C6A72;

View File

@ -308,11 +308,11 @@ void game_logic_update()
sub_68B089();
scenario_update();
climate_update();
fountain_update_all();
map_update_tiles();
sub_6A876D();
peep_update_all();
vehicle_update_all();
texteffect_update_all();
sprite_misc_update_all();
ride_update_all();
park_update();
research_update();

View File

@ -751,20 +751,55 @@ void sub_688485(){
}
int sub_0x686806(rct_sprite* sprite, int eax, int ecx, int edx){
int sub_0x686806(rct_sprite* sprite, int eax, int image_id, int ecx, int edx){
int ebp = (eax >> 8) & 0xFF;
edx <<= 16;
ebp += RCT2_GLOBAL(0x9DEA56, uint16);
RCT2_GLOBAL(0xF1AD28, uint32) = 0;
RCT2_GLOBAL(0xF1AD2C, uint32) = 0;
edx = (edx >> 16) | (ebp << 16);
ebp = RCT2_GLOBAL(0xEE7888, uint32);
if ((uint32)ebp >= RCT2_GLOBAL(0xEE7880, uint32)) return 1;
//686840 not finished
//Not a paint struct but something similar
paint_struct* ps = RCT2_GLOBAL(0xEE7888, paint_struct*);
if ((uint32)ps >= RCT2_GLOBAL(0xEE7880, uint32)) return 1;
ps->image_id = image_id;
rct_g1_element *g1Element = &RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[image_id & 0x7FFFF];
eax = (eax & 0xFF) + RCT2_GLOBAL(0x9DE568, uint16);
ecx = (ecx & 0xFF) + RCT2_GLOBAL(0x9DE56C, uint16);
int x = ecx - eax;
int y = (ecx + eax) / 2 - (edx & 0xFFFF);
ps->x = x;
ps->y = y;
int left = x + g1Element->x_offset;
int bottom = y + g1Element->y_offset;
int right = left + g1Element->width;
int top = bottom + g1Element->height;
RCT2_GLOBAL(0xF1AD1C, uint16) = left;
RCT2_GLOBAL(0xF1AD1E, uint16) = bottom;
rct_drawpixelinfo* dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*);
if (right <= dpi->x)return 1;
if (top <= dpi->y)return 1;
if (left > dpi->x + dpi->width) return 1;
if (bottom > dpi->y + dpi->height) return 1;
RCT2_GLOBAL(0x9DE568, uint16);
//686918 not finished
return 0;
}
/**
* Litter Paint Setup??
* rct2: 0x006736FC
@ -829,8 +864,8 @@ void sub_0x69E8B0(uint32 eax, uint32 ecx){
eax = (eax & 0x1FE0) << 3 | (ecx >> 5);
int sprite_idx = RCT2_ADDRESS(0xF1EF60, uint16)[eax];
if (sprite_idx == SPRITE_INDEX_NULL) return;
for (rct_sprite* spr = &g_sprite_list[sprite_idx]; sprite_idx != SPRITE_INDEX_NULL; sprite_idx = spr->unknown.var_02){
for (rct_sprite* spr = &g_sprite_list[sprite_idx]; sprite_idx != SPRITE_INDEX_NULL; sprite_idx = spr->unknown.next_in_quadrant){
spr = &g_sprite_list[sprite_idx];
dpi = RCT2_GLOBAL(0x140E9A8, rct_drawpixelinfo*);
@ -858,7 +893,7 @@ void sub_0x69E8B0(uint32 eax, uint32 ecx){
case SPRITE_IDENTIFIER_PEEP:
RCT2_CALLPROC_X(0x68F0FB, eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp);
break;
case SPRITE_IDENTIFIER_FLOATING_TEXT:
case SPRITE_IDENTIFIER_MISC:
RCT2_CALLPROC_X(0x672AC9, eax, ebx, ecx, edx, (int)spr, (int)dpi, ebp);
break;
case SPRITE_IDENTIFIER_LITTER:

View File

@ -67,7 +67,7 @@ int viewport_interaction_get_item_left(int x, int y, viewport_interaction_info *
switch (sprite->unknown.sprite_identifier) {
case SPRITE_IDENTIFIER_VEHICLE:
vehicle = &(sprite->vehicle);
if (vehicle->var_D6 != 255)
if (vehicle->ride_subtype != 255)
vehicle_set_map_toolbar(vehicle);
else
info->type = VIEWPORT_INTERACTION_ITEM_NONE;
@ -131,8 +131,17 @@ int viewport_interaction_left_click(int x, int y)
case SPRITE_IDENTIFIER_PEEP:
window_guest_open(info.peep);
break;
case SPRITE_IDENTIFIER_FLOATING_TEXT:
balloon_pop(info.sprite);
case SPRITE_IDENTIFIER_MISC:
if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) == 0) {
switch (info.sprite->unknown.misc_identifier) {
case SPRITE_MISC_BALLOON:
balloon_press(&info.sprite->balloon);
break;
case SPRITE_MISC_DUCK:
duck_press(&info.sprite->duck);
break;
}
}
break;
}
return 1;
@ -399,7 +408,7 @@ static void viewport_interaction_remove_footpath(rct_map_element *mapElement, in
w = window_find_by_class(WC_FOOTPATH);
if (w != NULL)
sub_6A7831();
footpath_provisional_update();
mapElement2 = map_get_first_element_at(x / 32, y / 32);
do {

View File

@ -128,27 +128,7 @@ rct_widget *window_get_scroll_widget(rct_window *w, int scrollIndex)
return NULL;
}
static void RCT2_CALLPROC_WE_UPDATE(int address, rct_window* w)
{
#ifdef _MSC_VER
__asm {
push address
push w
mov esi, w
call[esp + 4]
add esp, 8
}
#else
__asm__ ( "\
push %[address]\n\
mov eax, %[w] \n\
push eax \n\
mov esi, %[w] \n\
call [esp+4] \n\
add esp, 8 \n\
" : [address] "+m" (address), [w] "+m" (w) : : "eax", "esi" );
#endif
}
/**
*
* rct2: 0x006ED7B0
@ -160,7 +140,7 @@ void window_dispatch_update_all()
RCT2_GLOBAL(0x01423604, sint32)++;
RCT2_GLOBAL(RCT2_ADDRESS_TOOLTIP_NOT_SHOWN_TICKS, sint16)++;
for (w = RCT2_LAST_WINDOW; w >= g_window_list; w--)
RCT2_CALLPROC_WE_UPDATE(w->event_handlers[WE_UPDATE], w);
window_event_update_call(w);
RCT2_CALLPROC_EBPSAFE(0x006EE411); // handle_text_input
}
@ -1691,6 +1671,33 @@ void window_event_invalidate_call(rct_window* w)
RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0);
}
static void window_event_call_address(int address, rct_window *w)
{
#ifdef _MSC_VER
__asm {
push address
push w
mov esi, w
call[esp + 4]
add esp, 8
}
#else
__asm__ ( "\
push %[address]\n\
mov eax, %[w] \n\
push eax \n\
mov esi, %[w] \n\
call [esp+4] \n\
add esp, 8 \n\
" : [address] "+m" (address), [w] "+m" (w) : : "eax", "esi" );
#endif
}
void window_event_update_call(rct_window *w)
{
window_event_call_address(w->event_handlers[WE_UPDATE], w);
}
/**
* rct2: New function not from rct2
* Bubbles an item one position up in the window list.

View File

@ -579,6 +579,7 @@ void window_event_mouse_up_call(rct_window* w, int widgetIndex);
void window_event_resize_call(rct_window* w);
void window_event_mouse_down_call(rct_window* w, int widgetIndex);
void window_event_invalidate_call(rct_window* w);
void window_event_update_call(rct_window *w);
void sub_6EA73F();

View File

@ -127,14 +127,14 @@ void finance_pay_ride_upkeep()
FOR_ALL_RIDES(i, ride) {
if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_EVER_BEEN_OPENED)) {
ride->build_date = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16);
ride->var_196 = 25855; // durability?
ride->reliability = RIDE_INITIAL_RELIABILITY;
}
if (ride->status != RIDE_STATUS_CLOSED && !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) {
sint16 upkeep = ride->upkeep_cost;
if (upkeep != -1) {
ride->total_profit -= upkeep;
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
finance_payment(upkeep, RCT_EXPENDITURE_TYPE_RIDE_RUNNING_COSTS);
}
}
@ -297,4 +297,4 @@ void game_command_set_current_loan(int* eax, int* ebx, int* ecx, int* edx, int*
}
*ebx = 0;
}
}

View File

@ -92,8 +92,9 @@ void marketing_update()
// This sets the string parameters for the marketing types that have an argument.
if (campaign == ADVERTISING_CAMPAIGN_RIDE_FREE || campaign == ADVERTISING_CAMPAIGN_RIDE) {
RCT2_GLOBAL(0x013CE952, uint16) = RCT2_GLOBAL(0x01362942 + 304 * campaignItem, uint16);
RCT2_GLOBAL(0x013CE954, uint32) = RCT2_GLOBAL(0x01362944 + 152 * campaignItem, uint32);
rct_ride* ride = GET_RIDE(campaignItem);
RCT2_GLOBAL(0x013CE952, uint16) = ride->name;
RCT2_GLOBAL(0x013CE954, uint32) = ride->name_arguments;
} else if (campaign == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE) {
campaignItem += 2016;
if (campaignItem >= 2048)

View File

@ -439,7 +439,7 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp
chunk += 0x60;
}
uint8* peep_loading_positions = chunk;
sint8* peep_loading_positions = chunk;
// Peep loading positions variable size
// 4 different vehicle subtypes are available
for (int i = 0; i < 4; ++i){
@ -644,7 +644,7 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp
no_positions = *((uint16*)peep_loading_positions);
peep_loading_positions += 2;
}
rideVehicleEntry->var_61 = (uint32)peep_loading_positions;
rideVehicleEntry->peep_loading_positions = peep_loading_positions;
peep_loading_positions += no_positions;
}
}
@ -718,7 +718,7 @@ int paint_ride_entry(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo* dp
}
rideVehicleEntry->var_02 = 0;
rideVehicleEntry->var_03 = 0;
rideVehicleEntry->var_61 = 0;
rideVehicleEntry->peep_loading_positions = 0;
}
ride_type->var_1AE = 0;
@ -839,18 +839,18 @@ int paint_small_scenery(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo*
int image_id = scenery_type->image;
if (scenery_type->small_scenery.flags & SMALL_SCENERY_HAS_PRIMARY_COLOUR){
if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR){
image_id |= 0x20D00000;
if (scenery_type->small_scenery.flags & SMALL_SCENERY_HAS_SECONDARY_COLOUR)
if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR)
image_id |= 0x92000000;
}
x = 56;
y = scenery_type->small_scenery.height / 4 + 78;
if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG1){
if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG2){
if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE){
if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG_VOFFSET_CENTRE){
y -= 12;
}
}
@ -860,7 +860,7 @@ int paint_small_scenery(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo*
if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG10){
image_id = scenery_type->image + 0x44500004;
if (scenery_type->small_scenery.flags & SMALL_SCENERY_HAS_SECONDARY_COLOUR)
if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR)
image_id |= 0x92000000;
gfx_draw_sprite(dpi, image_id, x, y, 0);
@ -869,7 +869,7 @@ int paint_small_scenery(int flags, int ebx, int ecx, int edx, rct_drawpixelinfo*
if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG8){
image_id = scenery_type->image + 4;
if (scenery_type->small_scenery.flags & SMALL_SCENERY_HAS_SECONDARY_COLOUR)
if (scenery_type->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR)
image_id |= 0x92000000;
gfx_draw_sprite(dpi, image_id, x, y, 0);

File diff suppressed because it is too large Load Diff

View File

@ -209,6 +209,7 @@ enum PEEP_STATE {
};
enum PEEP_ACTION_EVENTS {
PEEP_ACTION_CHECK_TIME = 0,
// If no food then check watch
PEEP_ACTION_EAT_FOOD = 1,
PEEP_ACTION_SHAKE_HEAD = 2,
@ -344,18 +345,21 @@ typedef struct {
typedef struct {
uint8 sprite_identifier; // 0x00
uint8 var_01;
uint16 var_02; // 0x02
uint16 next_in_quadrant; // 0x02
uint16 next; // 0x04
uint16 previous; // 0x06
uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8 var_09; // 0x09
// Height from center of sprite to bottom
uint8 sprite_height_negative; // 0x09
uint16 sprite_index; // 0x0A
uint16 var_0C;
sint16 x; // 0x0E
sint16 y; // 0x10
sint16 z; // 0x12
uint8 var_14; // 0x14
uint8 var_15; // 0x15
// Width from center of sprite to edge
uint8 sprite_width; // 0x14
// Height from center of sprite to top
uint8 sprite_height_positive; // 0x15
sint16 sprite_left; // 0x16
sint16 sprite_top; // 0x18
sint16 sprite_right; // 0x1A
@ -391,12 +395,13 @@ typedef struct {
uint8 hunger; // 0x3E
uint8 thirst; // 0x3F
uint8 bathroom; // 0x40
uint8 pad_41[0x2];
uint8 var_41;
uint8 var_42;
uint8 intensity; // 0x43
uint8 nausea_tolerance; // 0x44
uint8 var_45; // Some sort of flags?
money16 paid_on_drink; // 0x46
uint8 pad_48[0x10];
uint8 var_48[16];
uint32 item_extra_flags; // 0x58
uint8 photo2_ride_ref; // 0x5C
uint8 photo3_ride_ref; // 0x5D
@ -407,28 +412,34 @@ typedef struct {
uint8 current_train; // 0x6A
union{
struct{
uint8 current_car; // 0x6B
uint8 current_seat; // 0x6C
uint8 current_car; // 0x6B
uint8 current_seat; // 0x6C
};
uint16 time_to_sitdown; //0x6B
uint16 time_to_sitdown; //0x6B
struct{
uint8 time_to_stand; //0x6B
uint8 standing_flags; //0x6C
};
};
uint8 var_6D; // 0x6D
uint8 var_6E; // 0x6E
uint8 action_sprite_type; // 0x6E
uint8 var_6F;
uint8 var_70;
uint8 action_sprite_image_offset; // 0x70
uint8 action; // 0x71
uint8 action_frame; // 0x72
uint8 var_73;
uint16 var_74;
union {
uint16 var_74; // time getting to ride to fix
uint16 next_in_queue; // 0x74
};
uint8 var_76;
uint8 pad_77;
uint8 var_78;
uint8 pad_79;
uint16 var_7A; // time waiting in line possibly
union{
uint8 maze_last_edge; // 0x78
uint8 var_78;
};
uint8 var_79;
uint16 time_in_queue; // 0x7A
uint8 rides_been_on[32]; // 0x7C
// 255 bit bitmap of every ride the peep has been on see
// window_peep_rides_update for how to use.
@ -436,7 +447,7 @@ typedef struct {
money32 cash_in_pocket; // 0xA0
money32 cash_spent; // 0xA4
sint32 time_in_park; // 0xA8
uint8 var_AC; // 0xAC
sint8 var_AC; // 0xAC
uint8 previous_ride; // 0xAD
uint16 previous_ride_time_out; // 0xAE
rct_peep_thought thoughts[PEEP_MAX_THOUGHTS]; // 0xB0
@ -454,7 +465,7 @@ typedef struct {
uint32 flags; // 0xC8
uint32 var_CC;
uint8 pad_D0[0x10];
uint8 var_E0; // 0xE0
uint8 no_action_frame_no; // 0xE0
uint8 var_E1;
uint8 var_E2; // 0xE2
uint8 var_E3;
@ -479,10 +490,10 @@ typedef struct {
uint8 no_of_food; // 0xEC
uint8 no_of_drinks; // 0xED
uint8 no_of_souvenirs; // 0xEE
uint8 pad_EF;
uint8 var_EF;
uint8 voucher_type; // 0xF0
uint8 voucher_arguments; // 0xF1 ride_id or string_offset_id
uint8 pad_F2;
uint8 var_F2;
uint8 var_F3;
uint8 var_F4;
uint8 days_in_queue; // 0xF5
@ -490,7 +501,8 @@ typedef struct {
uint8 umbrella_colour; // 0xF7
uint8 hat_colour; // 0xF8
uint8 favourite_ride; // 0xF9
uint16 pad_FA;
uint8 var_FA;
uint8 pad_FB;
uint32 item_standard_flags; // 0xFC
} rct_peep;

View File

@ -107,9 +107,9 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx,
move_sprite_to_list((rct_sprite *)newPeep, SPRITE_LINKEDLIST_OFFSET_PEEP);
newPeep->sprite_identifier = 1;
newPeep->var_09 = 0x0F;
newPeep->var_15 = 5;
newPeep->var_14 = 8;
newPeep->sprite_height_negative = 0x0F;
newPeep->sprite_height_positive = 5;
newPeep->sprite_width = 8;
newPeep->sprite_direction = 0;
sprite_move(_ax, *ecx, _dx, (rct_sprite*)newPeep);
@ -122,9 +122,9 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx,
newPeep->var_45 = 0;
newPeep->action = 0xFF;
newPeep->var_6D = 0;
newPeep->var_70 = 0;
newPeep->var_E0 = 0;
newPeep->var_6E = 0;
newPeep->action_sprite_image_offset = 0;
newPeep->no_action_frame_no = 0;
newPeep->action_sprite_type = 0;
newPeep->var_C4 = 0;
newPeep->type = PEEP_TYPE_STAFF;
newPeep->var_2A = 0;
@ -176,9 +176,9 @@ void game_command_hire_new_staff_member(int* eax, int* ebx, int* ecx, int* edx,
newPeep->sprite_type = _eax;
_edx = RCT2_ADDRESS(0x0098270C, uint32)[_eax * 2];
newPeep->var_14 = *((uint8*)_edx);
newPeep->var_09 = *((uint8*)(_edx + 1));
newPeep->var_15 = *((uint8*)(_edx + 2));
newPeep->sprite_width = *((uint8*)_edx);
newPeep->sprite_height_negative = *((uint8*)(_edx + 1));
newPeep->sprite_height_positive = *((uint8*)(_edx + 2));
sprite_move( newPeep->x, newPeep->y, newPeep->z, (rct_sprite*)newPeep);
invalidate_sprite((rct_sprite*)newPeep);

View File

@ -40,6 +40,13 @@ enum STAFF_TYPE {
STAFF_TYPE_ENTERTAINER
};
enum STAFF_ORDERS{
STAFF_ORDERS_SWEEPING = (1 << 0),
STAFF_ORDERS_WATER_FLOWERS = (1 << 1),
STAFF_ORDERS_EMPTY_BINS = (1 << 2),
STAFF_ORDERS_MOWING = (1 << 3)
};
void game_command_update_staff_colour(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp);
void game_command_hire_new_staff_member(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp);

View File

@ -174,8 +174,8 @@ typedef struct {
uint16 view_y;
uint8 view_zoom;
uint8 view_rotation;
uint8 animated_objects[6000];
uint32 num_animated_objects;
uint8 map_animations[6000];
uint32 num_map_animations;
uint8 unk_1CADBC[12];
uint16 scrolling_text_step;
uint32 unk_1CADCA;

View File

@ -210,7 +210,7 @@ void ride_update_favourited_stat()
if (peep->favourite_ride != 0xff) {
ride = &g_ride_list[peep->favourite_ride];
ride->guests_favourite++;
ride->var_14D |= 1;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_CUSTOMER;
}
@ -667,7 +667,7 @@ static void ride_clear_for_construction(int rideIndex)
ride_measurement_clear(ride);
ride->lifecycle_flags &= ~(RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN);
ride->var_14D |= 0x0C;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
ride_remove_cable_lift(ride);
ride_remove_vehicles(ride);
@ -764,7 +764,7 @@ static void ride_remove_peeps(int rideIndex)
ride->num_riders = 0;
ride->var_15D = 0;
ride->var_14D |= 4;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN;
}
int sub_6C683D(int* x, int* y, int z, int direction, int type, int esi, int edi, int ebp)
@ -1136,10 +1136,10 @@ static void ride_update(int rideIndex)
ride->var_126 = ride->var_124;
ride->var_124 = ride->var_120;
ride->var_120 = 0;
ride->var_14D |= 1;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_CUSTOMER;
ride->income_per_hour = ride_calculate_income_per_hour(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
if (ride->upkeep_cost != (money16)0xFFFF)
ride->profit = (ride->income_per_hour - ((money32)ride->upkeep_cost * 16));
@ -1208,7 +1208,7 @@ void ride_update_popularity(rct_ride* ride, uint8 pop_amount){
ride->popularity = ride->popularity_next;
ride->popularity_next = 0;
ride->popularity_time_out = 0;
ride->var_14D |= 1;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_CUSTOMER;
}
/**
@ -1245,10 +1245,12 @@ static void ride_spiral_slide_update(rct_ride *ride)
mapElement = ride_get_station_start_track_element(ride, i);
int rotation = ((mapElement->type & 3) << 2) | RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8);
x += RCT2_GLOBAL(0x0098DDB8 + (rotation * 4), uint16);
y += RCT2_GLOBAL(0x0098DDBA + (rotation * 4), uint16);
x *= 32;
y *= 32;
x += RCT2_GLOBAL(0x0098DDB8 + (rotation * 4), sint16);
y += RCT2_GLOBAL(0x0098DDBA + (rotation * 4), sint16);
map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8);
gfx_invalidate_scrollingtext(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8);
}
}
@ -1309,13 +1311,35 @@ static void ride_inspection_update(rct_ride *ride)
}
}
static int get_age_penalty(rct_ride *ride) {
int years;
years = date_get_year(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16) - ride->build_date);
switch (years) {
case 0:
return 0;
case 1:
return ride->unreliability_factor / 8;
case 2:
return ride->unreliability_factor / 4;
case 3:
case 4:
return ride->unreliability_factor / 2;
case 5:
case 6:
case 7:
return ride->unreliability_factor;
default:
return ride->unreliability_factor * 2;
}
}
/**
*
* rct2: 0x006AC622
*/
static void ride_breakdown_update(int rideIndex)
{
int agePenalty, years, ax, breakdownReason;
int breakdownReason, unreliabilityAccumulator;
rct_ride *ride = GET_RIDE(rideIndex);
if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 255)
@ -1335,7 +1359,7 @@ static void ride_breakdown_update(int rideIndex)
ride->var_1A0 +
ride->var_1A2 +
ride->var_1A3;
ride->var_199 = min(ax / 2, 100);
ride->downtime = min(ax / 2, 100);
ride->var_1A3 = ride->var_1A2;
ride->var_1A2 = ride->var_1A1;
@ -1345,7 +1369,7 @@ static void ride_breakdown_update(int rideIndex)
ride->var_19E = ride->var_19D;
ride->var_19D = ride->var_19C;
ride->var_19C = 0;
ride->var_14D |= 32;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE;
}
if (ride->lifecycle_flags & (RIDE_LIFECYCLE_BREAKDOWN_PENDING | RIDE_LIFECYCLE_BROKEN_DOWN | RIDE_LIFECYCLE_CRASHED))
@ -1354,38 +1378,17 @@ static void ride_breakdown_update(int rideIndex)
return;
// Calculate breakdown probability?
ax = ride->var_198;
agePenalty;
years = date_get_year(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16) - ride->build_date);
switch (years) {
case 0:
agePenalty = 0;
break;
case 1:
agePenalty = ax >> 3;
break;
case 2:
agePenalty = ax >> 2;
break;
case 3:
case 4:
agePenalty = ax >> 1;
break;
case 5:
case 6:
case 7:
agePenalty = ax >> 0;
break;
default:
agePenalty = ax << 1;
break;
}
ax += agePenalty;
ride->var_196 = max(0, ride->var_196 - ax);
ride->var_14D |= 32;
unreliabilityAccumulator = ride->unreliability_factor + get_age_penalty(ride);
ride->reliability = max(0, ride->reliability - unreliabilityAccumulator);
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE;
// Random probability of a breakdown
if (ride->var_196 == 0 || (int)(scenario_rand() & 0x2FFFFF) <= 25856 - ride->var_196) {
// Random probability of a breakdown. Roughly this is 1 in
//
// (25000 - reliability) / 3 000 000
//
// a 0.8% chance, less the breakdown factor which accumulates as the game
// continues.
if (ride->reliability == 0 || (int)(scenario_rand() & 0x2FFFFF) <= 1 + RIDE_INITIAL_RELIABILITY - ride->reliability) {
breakdownReason = ride_get_new_breakdown_problem(ride);
if (breakdownReason != -1)
ride_prepare_breakdown(rideIndex, breakdownReason);
@ -1443,9 +1446,8 @@ static int ride_get_new_breakdown_problem(rct_ride *ride)
if (ride->num_vehicles != 1)
return -1;
// Again the probability is lower, this time if young or two other unknown reasons...
monthsOld = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint8) - ride->build_date;
if (monthsOld < 16 || ride->var_196 > 12800 || ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS)
if (monthsOld < 16 || ride->reliability > (50 << 8) || ride->lifecycle_flags & RIDE_LIFECYCLE_SIX_FLAGS)
return -1;
return BREAKDOWN_BRAKES_FAILURE;
@ -1580,7 +1582,7 @@ static void ride_mechanic_status_update(int rideIndex, int mechanicStatus)
breakdownReason == BREAKDOWN_CONTROL_FAILURE
) {
ride->lifecycle_flags |= RIDE_LIFECYCLE_BROKEN_DOWN;
ride->var_14D |= 0x2C;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE | RIDE_INVALIDATE_RIDE_LIST | RIDE_INVALIDATE_RIDE_MAIN;
ride->mechanic_status = RIDE_MECHANIC_STATUS_CALLING;
ride->breakdown_reason = breakdownReason;
ride_breakdown_add_news_item(rideIndex);
@ -1602,7 +1604,7 @@ static void ride_mechanic_status_update(int rideIndex, int mechanicStatus)
mechanic->current_ride != rideIndex
) {
ride->mechanic_status = RIDE_MECHANIC_STATUS_CALLING;
ride->var_14D |= 0x20;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE;
ride_mechanic_status_update(rideIndex, RIDE_MECHANIC_STATUS_CALLING);
}
break;
@ -1618,7 +1620,7 @@ static void ride_mechanic_status_update(int rideIndex, int mechanicStatus)
)
) {
ride->mechanic_status = RIDE_MECHANIC_STATUS_CALLING;
ride->var_14D |= 0x20;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE;
ride_mechanic_status_update(rideIndex, RIDE_MECHANIC_STATUS_CALLING);
}
break;
@ -1639,7 +1641,7 @@ static void ride_call_mechanic(int rideIndex, rct_peep *mechanic, int forInspect
peep_window_state_update(mechanic);
mechanic->sub_state = 0;
ride->mechanic_status = RIDE_MECHANIC_STATUS_HEADING;
ride->var_14D |= 0x20;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAINTENANCE;
ride->mechanic = mechanic->sprite_index;
mechanic->current_ride = rideIndex;
mechanic->current_ride_station = ride->inspection_station;
@ -1882,7 +1884,7 @@ void ride_measurement_update(rct_ride_measurement *measurement)
return;
measurement->flags &= ~RIDE_MEASUREMENT_FLAG_UNLOADING;
if (measurement->var_0B == vehicle->var_4B)
if (measurement->current_station == vehicle->current_station)
measurement->current_item = 0;
}
@ -1966,7 +1968,7 @@ void ride_measurements_update()
vehicle = &(g_sprite_list[spriteIndex].vehicle);
if (vehicle->status == VEHICLE_STATUS_DEPARTING || vehicle->status == VEHICLE_STATUS_STOPPING) {
measurement->vehicle_index = j;
measurement->var_0B = vehicle->var_4B;
measurement->current_station = vehicle->current_station;
measurement->flags |= RIDE_MEASUREMENT_FLAG_RUNNING;
measurement->flags &= ~RIDE_MEASUREMENT_FLAG_UNLOADING;
ride_measurement_update(measurement);
@ -3479,7 +3481,7 @@ void game_command_set_ride_status(int *eax, int *ebx, int *ecx, int *edx, int *e
ride->status = RIDE_STATUS_CLOSED;
ride->lifecycle_flags &= ~RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING;
ride->race_winner = 0xFFFF;
ride->var_14D |= (1 << 2) | (1 << 3);
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
window_invalidate_by_number(WC_RIDE, rideIndex);
}
*ebx = 0;
@ -3500,7 +3502,7 @@ void game_command_set_ride_status(int *eax, int *ebx, int *ecx, int *edx, int *e
ride->race_winner = 0xFFFF;
ride->status = targetStatus;
ride_get_measurement(rideIndex, NULL);
ride->var_14D |= (1 << 2) | (1 << 3);
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
window_invalidate_by_number(WC_RIDE, rideIndex);
}
*ebx = 0;

View File

@ -82,12 +82,14 @@ typedef struct{
uint32 var_4C; // 0x4C , 0x66
uint32 no_vehicle_images; // 0x50 , 0x6A
uint8 no_seating_rows; // 0x54 , 0x6E
uint8 pad_55[0x7];
uint8 pad_55[0x5];
uint8 var_5A; // 0x5A , 0x74
uint8 pad_5B; // 0x5B , 0x75
uint8 var_5C; // 0x5C , 0x76
uint8 var_5D; // 0x5D , 0x77
uint8 pad_5E[0x2];
uint8 var_60; // 0x60 , 0x7A
uint32 var_61; // 0x61 , 0x7B
sint8* peep_loading_positions; // 0x61 , 0x7B
} rct_ride_type_vehicle;
/**
@ -103,12 +105,13 @@ typedef struct {
uint8 var_00C;
uint8 var_00D;
uint8 var_00E;
uint8 var_00F;
uint8 var_010;
uint8 min_cars_in_train; // 0x00F
uint8 max_cars_in_train; // 0x010
uint8 var_011;
uint8 var_012;
uint8 var_013;
uint8 pad_014[0x6];
uint8 var_014;
uint8 pad_015[0x5];
rct_ride_type_vehicle vehicles[4]; // 0x1A
uint32 var_1AE;
sint8 excitement_multipler; // 0x1B2
@ -148,7 +151,8 @@ typedef struct {
uint8 var_066[4];
uint16 entrances[4]; // 0x06A
uint16 exits[4]; // 0x072
uint8 pad_07A[0x0C];
uint16 first_peep_in_queue[4]; // 0x07A
uint8 pad_082[4];
uint16 vehicles[32]; // 0x086 Points to the first car in the train
uint8 depart_flags; // 0x0C6
@ -218,12 +222,13 @@ typedef struct {
ride_rating nausea; // 0x144
};
};
uint16 reliability; // 0x146
uint16 value; // 0x146
uint16 var_148;
uint8 satisfaction; // 0x14A
uint8 satisfaction_time_out; // 0x14B
uint8 satisfaction_next; // 0x14C
uint8 var_14D;
// Various flags stating whether a window needs to be refreshed
uint8 window_invalidate_flags; // 0x14D
uint8 pad_14E[0x02];
uint32 total_customers; // 0x150
money32 total_profit; // 0x154
@ -237,7 +242,9 @@ typedef struct {
uint16 slide_peep; // 0x15E
uint16 maze_tiles; // 0x15E
};
uint8 pad_160[0x16];
uint8 pad_160[0xE];
uint8 slide_peep_t_shirt_colour;// 0x16E
uint8 pad_16F[0x7];
uint8 var_176;
uint8 pad_177[0x9];
sint16 build_date; // 0x180
@ -253,10 +260,14 @@ typedef struct {
uint8 broken_car; // 0x192
uint8 breakdown_reason; // 0x193
money16 price_secondary; // 0x194
uint16 var_196;
// used in computing excitement, nausea, etc
uint8 var_198;
uint8 var_199;
// Starts at RIDE_INITIAL_RELIABILITY and decreases from there. Right shift
// this number by 8 to get a reliability percentage 0-100
uint16 reliability;
// Small constant used to increase the unreliability as the game continues,
// making breakdowns more and more likely.
uint8 unreliability_factor;
// Range from [0, 100]
uint8 downtime; // 0x199
uint8 inspection_interval; // 0x19A
uint8 last_inspection; // 0x19B
uint8 var_19C;
@ -309,7 +320,7 @@ typedef struct {
uint16 num_items; // 0x0006
uint16 current_item; // 0x0008
uint8 vehicle_index; // 0x000A
uint8 var_0B;
uint8 current_station; // 0x000B
sint8 vertical[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x000C
sint8 lateral[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x12CC
uint8 velocity[RIDE_MEASUREMENT_MAX_ITEMS]; // 0x258C
@ -358,7 +369,7 @@ enum {
RIDE_TYPE_MINI_SUSPENDED_COASTER,
RIDE_TYPE_BUMPER_BOATS,
RIDE_TYPE_WOODEN_WILD_MOUSE,
RIDE_TYPE_STEEPLECHASE,
RIDE_TYPE_STEEPLECHASE = 10,
RIDE_TYPE_CAR_RIDE,
RIDE_TYPE_LAUNCHED_FREEFALL,
RIDE_TYPE_BOBSLEIGH_COASTER,
@ -368,7 +379,7 @@ enum {
RIDE_TYPE_MINE_TRAIN_COASTER,
RIDE_TYPE_CHAIRLIFT,
RIDE_TYPE_CORKSCREW_ROLLER_COASTER,
RIDE_TYPE_MAZE,
RIDE_TYPE_MAZE = 20,
RIDE_TYPE_SPIRAL_SLIDE,
RIDE_TYPE_GO_KARTS,
RIDE_TYPE_LOG_FLUME,
@ -378,7 +389,7 @@ enum {
RIDE_TYPE_SWINGING_INVERTER_SHIP,
RIDE_TYPE_FOOD_STALL,
RIDE_TYPE_1D,
RIDE_TYPE_DRINK_STALL,
RIDE_TYPE_DRINK_STALL = 30,
RIDE_TYPE_1F,
RIDE_TYPE_SHOP,
RIDE_TYPE_MERRY_GO_ROUND,
@ -388,7 +399,7 @@ enum {
RIDE_TYPE_FERRIS_WHEEL,
RIDE_TYPE_MOTION_SIMULATOR,
RIDE_TYPE_3D_CINEMA,
RIDE_TYPE_TOP_SPIN,
RIDE_TYPE_TOP_SPIN = 40,
RIDE_TYPE_SPACE_RINGS,
RIDE_TYPE_REVERSE_FREEFALL_COASTER,
RIDE_TYPE_ELEVATOR,
@ -398,7 +409,7 @@ enum {
RIDE_TYPE_HAUNTED_HOUSE,
RIDE_TYPE_FIRST_AID,
RIDE_TYPE_CIRCUS_SHOW,
RIDE_TYPE_GHOST_TRAIN,
RIDE_TYPE_GHOST_TRAIN = 50,
RIDE_TYPE_TWISTER_ROLLER_COASTER,
RIDE_TYPE_WOODEN_ROLLER_COASTER,
RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER,
@ -408,7 +419,7 @@ enum {
RIDE_TYPE_FLYING_ROLLER_COASTER,
RIDE_TYPE_3A,
RIDE_TYPE_VIRGINIA_REEL,
RIDE_TYPE_SPLASH_BOATS,
RIDE_TYPE_SPLASH_BOATS = 60,
RIDE_TYPE_MINI_HELICOPTERS,
RIDE_TYPE_LAY_DOWN_ROLLER_COASTER,
RIDE_TYPE_SUSPENDED_MONORAIL,
@ -418,7 +429,7 @@ enum {
RIDE_TYPE_MINI_GOLF,
RIDE_TYPE_GIGA_COASTER,
RIDE_TYPE_ROTO_DROP,
RIDE_TYPE_FLYING_SAUCERS,
RIDE_TYPE_FLYING_SAUCERS = 70,
RIDE_TYPE_CROOKED_HOUSE,
RIDE_TYPE_MONORAIL_CYCLES,
RIDE_TYPE_COMPACT_INVERTED_COASTER,
@ -428,7 +439,7 @@ enum {
RIDE_TYPE_MAGIC_CARPET,
RIDE_TYPE_SUBMARINE_RIDE,
RIDE_TYPE_RIVER_RAFTS,
RIDE_TYPE_50,
RIDE_TYPE_50 = 80,
RIDE_TYPE_ENTERPRISE,
RIDE_TYPE_52,
RIDE_TYPE_53,
@ -438,7 +449,7 @@ enum {
RIDE_TYPE_MINI_ROLLER_COASTER,
RIDE_TYPE_MINE_RIDE,
RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER,
RIDE_TYPE_90
RIDE_TYPE_90 = 90
};
enum {
@ -605,6 +616,16 @@ enum {
RIDE_INSPECTION_NEVER
};
// Flags used by ride->window_invalidate_flags
enum {
RIDE_INVALIDATE_RIDE_CUSTOMER = 1,
RIDE_INVALIDATE_RIDE_INCOME = 1 << 1,
RIDE_INVALIDATE_RIDE_MAIN = 1 << 2,
RIDE_INVALIDATE_RIDE_LIST = 1 << 3,
RIDE_INVALIDATE_RIDE_OPERATING = 1 << 4,
RIDE_INVALIDATE_RIDE_MAINTENANCE = 1 << 5,
};
typedef struct {
uint8 main;
uint8 additional;
@ -661,7 +682,8 @@ enum {
#define MAX_RIDES 255
#define MAX_RIDE_MEASUREMENTS 8
#define RIDE_RELIABILITY_UNDEFINED 0xFFFF
#define RIDE_VALUE_UNDEFINED 0xFFFF
#define RIDE_INITIAL_RELIABILITY ((100 << 8) - 1)
#define STATION_DEPART_FLAG (1 << 7)
#define STATION_DEPART_MASK (~STATION_DEPART_FLAG)
@ -721,7 +743,8 @@ int sub_6C683D(int* x, int* y, int z, int direction, int type, int esi, int edi,
void ride_set_map_tooltip(rct_map_element *mapElement);
int ride_music_params_update(sint16 x, sint16 y, sint16 z, uint8 rideIndex, uint16 sampleRate, uint32 position, uint8 *tuneId);
void ride_music_update_final();
rct_map_element *ride_get_station_start_track_element(rct_ride *ride, int stationIndex);
rct_map_element *ride_get_station_exit_element(rct_ride *ride, int x, int y, int z);
void ride_set_status(int rideIndex, int status);
void game_command_set_ride_status(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp);
void ride_set_name(int rideIndex, const char *name);

View File

@ -49,7 +49,7 @@ static void ride_ratings_update_state_4();
static void ride_ratings_update_state_5();
static void loc_6B5BB2();
static void ride_ratings_calculate(rct_ride *ride);
static void ride_ratings_reliability_calculate(rct_ride *ride);
static void ride_ratings_calculate_value(rct_ride *ride);
static int sub_6C6402(rct_map_element *mapElement, int *x, int *y, int *z)
{
@ -283,7 +283,7 @@ static void ride_ratings_update_state_3()
ride_ratings_calculate(ride);
RCT2_CALLPROC_X(0x00655F64, 0, 0, 0, 0, 0, (int)ride, 0);
ride_ratings_reliability_calculate(ride);
ride_ratings_calculate_value(ride);
window_invalidate_by_number(WC_RIDE, _rideRatingsCurrentRide);
_rideRatingsState = RIDE_RATINGS_STATE_FIND_NEXT_RIDE;
@ -372,7 +372,7 @@ static void ride_ratings_calculate(rct_ride *ride)
}
}
static void ride_ratings_reliability_calculate(rct_ride *ride)
static void ride_ratings_calculate_value(rct_ride *ride)
{
rct_ride *ride2;
int i, otherRidesOfSameType;
@ -380,7 +380,7 @@ static void ride_ratings_reliability_calculate(rct_ride *ride)
if (ride->excitement == (ride_rating)0xFFFF)
return;
int reliability =
int value =
(((ride->excitement * RCT2_GLOBAL(0x0097CD1E + (ride->type * 6), sint16)) * 32) >> 15) +
(((ride->intensity * RCT2_GLOBAL(0x0097CD20 + (ride->type * 6), sint16)) * 32) >> 15) +
(((ride->nausea * RCT2_GLOBAL(0x0097CD22 + (ride->type * 6), sint16)) * 32) >> 15);
@ -389,19 +389,19 @@ static void ride_ratings_reliability_calculate(rct_ride *ride)
// New ride reward
if (monthsOld <= 12) {
reliability += 10;
value += 10;
if (monthsOld <= 4)
reliability += 20;
value += 20;
}
// Old ride penalty
if (monthsOld >= 40) reliability -= reliability / 4;
if (monthsOld >= 64) reliability -= reliability / 4;
if (monthsOld >= 40) value -= value / 4;
if (monthsOld >= 64) value -= value / 4;
if (monthsOld < 200) {
if (monthsOld >= 88) reliability -= reliability / 4;
if (monthsOld >= 104) reliability -= reliability / 4;
if (monthsOld >= 120) reliability -= reliability / 2;
if (monthsOld >= 128) reliability -= reliability / 2;
if (monthsOld >= 88) value -= value / 4;
if (monthsOld >= 104) value -= value / 4;
if (monthsOld >= 120) value -= value / 2;
if (monthsOld >= 128) value -= value / 2;
}
// Other ride of same type penalty
@ -411,9 +411,9 @@ static void ride_ratings_reliability_calculate(rct_ride *ride)
otherRidesOfSameType++;
}
if (otherRidesOfSameType > 1)
reliability -= reliability / 4;
value -= value / 4;
ride->reliability = max(0, reliability);
ride->value = max(0, value);
}
/**
@ -564,12 +564,16 @@ static void ride_ratings_apply_intensity_penalty(rating_tuple *ratings)
}
/**
*
* rct2: 0x00655FD6
*/
static void sub_655FD6(rct_ride *ride)
static void set_unreliability_factor(rct_ride *ride)
{
ride->var_198 += (ride->lift_hill_speed - RCT2_ADDRESS(0x0097D7C9, uint8)[ride->type * 4]) * 2;
// The higher the number, the lower the breakdown
// possibility. Range is [3, 7]. values are here:
// https://gist.github.com/kevinburke/123977c4884ccadbec70. Consider
// inlining this per ride
uint8 lift_speed_adjustment = RCT2_ADDRESS(0x0097D7C9, uint8)[ride->type * 4];
ride->unreliability_factor += (ride->lift_hill_speed - lift_speed_adjustment) * 2;
}
/**
@ -752,13 +756,13 @@ static void ride_ratings_calculate_mine_train_coaster(rct_ride *ride)
if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED))
return;
ride->var_198 = 16;
sub_655FD6(ride);
ride->unreliability_factor = 16;
set_unreliability_factor(ride);
// Base ratings
ratings.excitement = RIDE_RATING(2,90);
ratings.intensity = RIDE_RATING(2,30);
ratings.nausea = RIDE_RATING(2,10);
ratings.excitement = RIDE_RATING(2,90);
ratings.intensity = RIDE_RATING(2,30);
ratings.nausea = RIDE_RATING(2,10);
// Apply length of ride factor
totalLength = (ride->length[0] + ride->length[1] + ride->length[2] + ride->length[3]) >> 16;
@ -856,7 +860,7 @@ static void ride_ratings_calculate_mine_train_coaster(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= sub_65E72D(ride) << 5;
@ -868,8 +872,8 @@ static void ride_ratings_calculate_maze(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 8;
sub_655FD6(ride);
ride->unreliability_factor = 8;
set_unreliability_factor(ride);
// Base ratings
ratings.excitement = RIDE_RATING(1,30);
@ -889,7 +893,7 @@ static void ride_ratings_calculate_maze(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 0 << 5;
@ -901,8 +905,8 @@ static void ride_ratings_calculate_spiral_slide(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 8;
sub_655FD6(ride);
ride->unreliability_factor = 8;
set_unreliability_factor(ride);
// Base ratings
ratings.excitement = RIDE_RATING(1,50);
@ -924,7 +928,7 @@ static void ride_ratings_calculate_spiral_slide(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 2 << 5;
@ -936,8 +940,8 @@ static void ride_ratings_calculate_pirate_ship(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 10;
sub_655FD6(ride);
ride->unreliability_factor = 10;
set_unreliability_factor(ride);
// Base ratings
ratings.excitement = RIDE_RATING(1,50);
@ -956,7 +960,7 @@ static void ride_ratings_calculate_pirate_ship(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 0 << 5;
@ -968,8 +972,8 @@ static void ride_ratings_calculate_inverter_ship(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 16;
sub_655FD6(ride);
ride->unreliability_factor = 16;
set_unreliability_factor(ride);
// Base ratings
ratings.excitement = RIDE_RATING(2,50);
@ -988,7 +992,7 @@ static void ride_ratings_calculate_inverter_ship(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 0 << 5;
@ -997,19 +1001,19 @@ static void ride_ratings_calculate_inverter_ship(rct_ride *ride)
static void ride_ratings_calculate_food_stall(rct_ride *ride)
{
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
}
static void ride_ratings_calculate_drink_stall(rct_ride *ride)
{
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
}
static void ride_ratings_calculate_shop(rct_ride *ride)
{
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
}
static void ride_ratings_calculate_merry_go_round(rct_ride *ride)
@ -1018,8 +1022,8 @@ static void ride_ratings_calculate_merry_go_round(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 16;
sub_655FD6(ride);
ride->unreliability_factor = 16;
set_unreliability_factor(ride);
int unk = ride->var_0D0 * 5;
ratings.excitement = unk + RIDE_RATING(0,60) + ((ride_ratings_get_scenery_score(ride) * 19521) >> 16);
@ -1032,7 +1036,7 @@ static void ride_ratings_calculate_merry_go_round(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 7 << 5;
@ -1041,13 +1045,13 @@ static void ride_ratings_calculate_merry_go_round(rct_ride *ride)
static void ride_ratings_calculate_information_kiosk(rct_ride *ride)
{
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
}
static void ride_ratings_calculate_bathroom(rct_ride *ride)
{
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
}
static void ride_ratings_calculate_ferris_wheel(rct_ride *ride)
@ -1056,8 +1060,8 @@ static void ride_ratings_calculate_ferris_wheel(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 16;
sub_655FD6(ride);
ride->unreliability_factor = 16;
set_unreliability_factor(ride);
int unk = ride->var_0D0 * 25;
ratings.excitement = unk + RIDE_RATING(0,60) + ((ride_ratings_get_scenery_score(ride) * 41831) >> 16);
@ -1070,7 +1074,7 @@ static void ride_ratings_calculate_ferris_wheel(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 0 << 5;
@ -1082,8 +1086,8 @@ static void ride_ratings_calculate_motion_simulator(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 21;
sub_655FD6(ride);
ride->unreliability_factor = 21;
set_unreliability_factor(ride);
// Base ratings
if (ride->mode == RIDE_MODE_FILM_THRILL_RIDERS) {
@ -1102,7 +1106,7 @@ static void ride_ratings_calculate_motion_simulator(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 7 << 5;
@ -1114,8 +1118,8 @@ static void ride_ratings_calculate_3d_cinema(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 21;
sub_655FD6(ride);
ride->unreliability_factor = 21;
set_unreliability_factor(ride);
// Base ratings
switch (ride->mode) {
@ -1143,7 +1147,7 @@ static void ride_ratings_calculate_3d_cinema(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 7 << 5;
@ -1155,8 +1159,8 @@ static void ride_ratings_calculate_top_spin(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 19;
sub_655FD6(ride);
ride->unreliability_factor = 19;
set_unreliability_factor(ride);
// Base ratings
switch (ride->mode) {
@ -1186,7 +1190,7 @@ static void ride_ratings_calculate_top_spin(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 0 << 5;
@ -1198,8 +1202,8 @@ static void ride_ratings_calculate_space_rings(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 7;
sub_655FD6(ride);
ride->unreliability_factor = 7;
set_unreliability_factor(ride);
// Base ratings
ratings.excitement = RIDE_RATING(1,50);
@ -1214,7 +1218,7 @@ static void ride_ratings_calculate_space_rings(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 0 << 5;
@ -1228,8 +1232,8 @@ static void ride_ratings_calculate_elevator(rct_ride *ride)
if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED))
return;
ride->var_198 = 15;
sub_655FD6(ride);
ride->unreliability_factor = 15;
set_unreliability_factor(ride);
// Base ratings
ratings.excitement = RIDE_RATING(1,11);
@ -1249,7 +1253,7 @@ static void ride_ratings_calculate_elevator(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 7 << 5;
@ -1261,7 +1265,7 @@ static void ride_ratings_calculate_elevator(rct_ride *ride)
static void ride_ratings_calculate_atm(rct_ride *ride)
{
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
}
static void ride_ratings_calculate_twist(rct_ride *ride)
@ -1270,8 +1274,8 @@ static void ride_ratings_calculate_twist(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 16;
sub_655FD6(ride);
ride->unreliability_factor = 16;
set_unreliability_factor(ride);
// Base ratings
ratings.excitement = RIDE_RATING(1,13);
@ -1290,7 +1294,7 @@ static void ride_ratings_calculate_twist(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 0 << 5;
@ -1302,8 +1306,8 @@ static void ride_ratings_calculate_haunted_house(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 8;
sub_655FD6(ride);
ride->unreliability_factor = 8;
set_unreliability_factor(ride);
ratings.excitement = RIDE_RATING(3,41);
ratings.intensity = RIDE_RATING(1,53);
@ -1315,7 +1319,7 @@ static void ride_ratings_calculate_haunted_house(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 0xE0;
@ -1330,8 +1334,8 @@ static void ride_ratings_calculate_mini_golf(rct_ride *ride)
if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED))
return;
ride->var_198 = 0;
sub_655FD6(ride);
ride->unreliability_factor = 0;
set_unreliability_factor(ride);
// Base ratings
ratings.excitement = RIDE_RATING(1,50);
@ -1373,7 +1377,7 @@ static void ride_ratings_calculate_mini_golf(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= sub_65E72D(ride) << 5;
@ -1382,7 +1386,7 @@ static void ride_ratings_calculate_mini_golf(rct_ride *ride)
static void ride_ratings_calculate_first_aid(rct_ride *ride)
{
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
}
static void ride_ratings_calculate_circus_show(rct_ride *ride)
@ -1391,8 +1395,8 @@ static void ride_ratings_calculate_circus_show(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 9;
sub_655FD6(ride);
ride->unreliability_factor = 9;
set_unreliability_factor(ride);
ratings.excitement = RIDE_RATING(2,10);
ratings.intensity = RIDE_RATING(0,30);
@ -1404,7 +1408,7 @@ static void ride_ratings_calculate_circus_show(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 7 << 5;
@ -1416,8 +1420,8 @@ static void ride_ratings_calculate_crooked_house(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 5;
sub_655FD6(ride);
ride->unreliability_factor = 5;
set_unreliability_factor(ride);
ratings.excitement = RIDE_RATING(2,15);
ratings.intensity = RIDE_RATING(0,62);
@ -1429,7 +1433,7 @@ static void ride_ratings_calculate_crooked_house(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 0xE0;
@ -1441,8 +1445,8 @@ static void ride_ratings_calculate_magic_carpet(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 16;
sub_655FD6(ride);
ride->unreliability_factor = 16;
set_unreliability_factor(ride);
// Base ratings
ratings.excitement = RIDE_RATING(2,45);
@ -1461,7 +1465,7 @@ static void ride_ratings_calculate_magic_carpet(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 0 << 5;
@ -1473,8 +1477,8 @@ static void ride_ratings_calculate_enterprise(rct_ride *ride)
ride->lifecycle_flags |= RIDE_LIFECYCLE_TESTED;
ride->lifecycle_flags |= RIDE_LIFECYCLE_NO_RAW_STATS;
ride->var_198 = 22;
sub_655FD6(ride);
ride->unreliability_factor = 22;
set_unreliability_factor(ride);
// Base ratings
ratings.excitement = RIDE_RATING(3,60);
@ -1493,7 +1497,7 @@ static void ride_ratings_calculate_enterprise(rct_ride *ride)
ride->ratings = ratings;
ride->upkeep_cost = ride_compute_upkeep(ride);
ride->var_14D |= 2;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_INCOME;
ride->inversions &= 0x1F;
ride->inversions |= 3 << 5;

View File

@ -128,7 +128,7 @@ static void ride_update_station_bumpercar(rct_ride *ride, int stationIndex)
// Begin the match
ride->lifecycle_flags |= RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING;
ride->station_depart[stationIndex] |= STATION_DEPART_FLAG;
ride->var_14D |= 12;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
}
}
@ -188,7 +188,7 @@ static void ride_update_station_race(rct_ride *ride, int stationIndex)
if (vehicle->num_peeps != 0) {
peep = &(g_sprite_list[vehicle->peep[0]].peep);
ride->race_winner = peep->sprite_index;
ride->var_14D |= 12;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
}
// Race is over
@ -214,7 +214,7 @@ static void ride_update_station_race(rct_ride *ride, int stationIndex)
ride_race_init_vehicle_speeds(ride);
ride->lifecycle_flags |= RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING;
ride->station_depart[stationIndex] |= STATION_DEPART_FLAG;
ride->var_14D |= 12;
ride->window_invalidate_flags |= RIDE_INVALIDATE_RIDE_MAIN | RIDE_INVALIDATE_RIDE_LIST;
}
}
@ -234,9 +234,9 @@ static void ride_race_init_vehicle_speeds(rct_ride *ride)
vehicle = &g_sprite_list[ride->vehicles[i]].vehicle;
vehicle->var_48 &= ~(1 << 6);
rideEntry = GET_RIDE_ENTRY(vehicle->var_D6);
rideEntry = GET_RIDE_ENTRY(vehicle->ride_subtype);
vehicle->speed = (scenario_rand() & 16) - 8 + rideEntry->vehicles[vehicle->var_31].var_5C;
vehicle->speed = (scenario_rand() & 16) - 8 + rideEntry->vehicles[vehicle->vehicle_type].var_5C;
if (vehicle->num_peeps != 0) {
rct_peep *peep = &g_sprite_list[vehicle->peep[0]].peep;
@ -315,4 +315,4 @@ rct_map_element *ride_get_station_exit_element(rct_ride *ride, int x, int y, int
} while (!map_element_is_last_for_tile(mapElement++));
return NULL;
}
}

View File

@ -735,7 +735,7 @@ void load_track_scenery_objects(){
object_load(-1, &scenery_entry->scenery_object, 0);
}
// Skip object and location/direction/colour
scenery_entry += sizeof(rct_track_scenery);
track_elements += sizeof(rct_track_scenery);
}
reset_loaded_objects();
@ -1227,7 +1227,7 @@ int copy_scenery_to_track(uint8** track_pointer){
{
int temp_y = y;
y = x;
x = -y;
x = -temp_y;
}
break;
case 2:
@ -1238,7 +1238,7 @@ int copy_scenery_to_track(uint8** track_pointer){
{
int temp_x = x;
x = y;
y = -x;
y = -temp_x;
}
break;
}

View File

@ -216,6 +216,196 @@ enum {
TRACK_CORKSCREW_DOWN = 224
};
enum {
TRACK_ELEM_FLAT,
TRACK_ELEM_END_STATION,
TRACK_ELEM_BEGIN_STATION,
TRACK_ELEM_MIDDLE_STATION,
TRACK_ELEM_25_DEG_UP,
TRACK_ELEM_60_DEG_UP,
TRACK_ELEM_FLAT_TO_25_DEG_UP,
TRACK_ELEM_25_DEG_UP_TO_60_DEG_UP,
TRACK_ELEM_60_DEG_UP_TO_25_DEG_UP,
TRACK_ELEM_25_DEG_UP_TO_FLAT,
TRACK_ELEM_25_DEG_DOWN,
TRACK_ELEM_60_DEG_DOWN,
TRACK_ELEM_FLAT_TO_25_DEG_DOWN,
TRACK_ELEM_25_DEG_DOWN_TO_60_DEG_DOWN,
TRACK_ELEM_60_DEG_DOWN_TO_25_DEG_DOWN,
TRACK_ELEM_25_DEG_DOWN_TO_FLAT,
TRACK_ELEM_LEFT_QUARTER_TURN_5_TILES,
TRACK_ELEM_RIGHT_QUARTER_TURN_5_TILES,
TRACK_ELEM_FLAT_TO_LEFT_BANK,
TRACK_ELEM_FLAT_TO_RIGHT_BANK,
TRACK_ELEM_LEFT_BANK_TO_FLAT,
TRACK_ELEM_RIGHT_BANK_TO_FLAT,
TRACK_ELEM_BANKED_LEFT_QUARTER_TURN_5_TILES,
TRACK_ELEM_BANKED_RIGHT_QUARTER_TURN_5_TILES,
TRACK_ELEM_LEFT_BANK_TO_25_DEG_UP,
TRACK_ELEM_RIGHT_BANK_TO_25_DEG_UP,
TRACK_ELEM_25_DEG_UP_TO_LEFT_BANK,
TRACK_ELEM_25_DEG_UP_TO_RIGHT_BANK,
TRACK_ELEM_LEFT_BANK_TO_25_DEG_DOWN,
TRACK_ELEM_RIGHT_BANK_TO_25_DEG_DOWN,
TRACK_ELEM_25_DEG_DOWN_TO_LEFT_BANK,
TRACK_ELEM_25_DEG_DOWN_TO_RIGHT_BANK,
TRACK_ELEM_LEFT_BANK,
TRACK_ELEM_RIGHT_BANK,
TRACK_ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_UP,
TRACK_ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_UP,
TRACK_ELEM_LEFT_QUARTER_TURN_5_TILES_25_DEG_DOWN,
TRACK_ELEM_RIGHT_QUARTER_TURN_5_TILES_25_DEG_DOWN,
TRACK_ELEM_S_BEND_LEFT,
TRACK_ELEM_S_BEND_RIGHT,
TRACK_ELEM_LEFT_VERTICAL_LOOP,
TRACK_ELEM_RIGHT_VERTICAL_LOOP,
TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES,
TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES,
TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_BANK,
TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_BANK,
TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP,
TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP,
TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN,
TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN,
TRACK_ELEM_LEFT_QUARTER_TURN_1_TILE,
TRACK_ELEM_RIGHT_QUARTER_TURN_1_TILE,
TRACK_ELEM_LEFT_TWIST_DOWN_TO_UP,
TRACK_ELEM_RIGHT_TWIST_DOWN_TO_UP,
TRACK_ELEM_LEFT_TWIST_UP_TO_DOWN,
TRACK_ELEM_RIGHT_TWIST_UP_TO_DOWN,
TRACK_ELEM_HALF_LOOP_UP,
TRACK_ELEM_HALF_LOOP_DOWN,
TRACK_ELEM_LEFT_CORKSCREW_UP,
TRACK_ELEM_RIGHT_CORKSCREW_UP,
TRACK_ELEM_LEFT_CORKSCREW_DOWN,
TRACK_ELEM_RIGHT_CORKSCREW_DOWN,
TRACK_ELEM_FLAT_TO_60_DEG_UP,
TRACK_ELEM_60_DEG_UP_TO_FLAT,
TRACK_ELEM_FLAT_TO_60_DEG_DOWN,
TRACK_ELEM_60_DEG_DOWN_TO_FLAT,
TRACK_ELEM_TOWER_BASE,
TRACK_ELEM_TOWER_SECTION,
TRACK_ELEM_FLAT_COVERED,
TRACK_ELEM_25_DEG_UP_COVERED,
TRACK_ELEM_60_DEG_UP_COVERED,
TRACK_ELEM_FLAT_TO_25_DEG_UP_COVERED,
TRACK_ELEM_25_DEG_UP_TO_60_DEG_UP_COVERED,
TRACK_ELEM_60_DEG_UP_TO_25_DEG_UP_COVERED,
TRACK_ELEM_25_DEG_UP_TO_FLAT_COVERED,
TRACK_ELEM_25_DEG_DOWN_COVERED,
TRACK_ELEM_60_DEG_DOWN_COVERED,
TRACK_ELEM_FLAT_TO_25_DEG_DOWN_COVERED,
TRACK_ELEM_25_DEG_DOWN_TO_60_DEG_DOWN_COVERED,
TRACK_ELEM_60_DEG_DOWN_TO_25_DEG_DOWN_COVERED,
TRACK_ELEM_25_DEG_DOWN_TO_FLAT_COVERED,
TRACK_ELEM_LEFT_QUARTER_TURN_5_TILES_COVERED,
TRACK_ELEM_RIGHT_QUARTER_TURN_5_TILES_COVERED,
TRACK_ELEM_S_BEND_LEFT_COVERED,
TRACK_ELEM_S_BEND_RIGHT_COVERED,
TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_COVERED,
TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_COVERED,
TRACK_ELEM_LEFT_HALF_BANKED_HELIX_UP_SMALL,
TRACK_ELEM_RIGHT_HALF_BANKED_HELIX_UP_SMALL,
TRACK_ELEM_LEFT_HALF_BANKED_HELIX_DOWN_SMALL,
TRACK_ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_SMALL,
TRACK_ELEM_LEFT_HALF_BANKED_HELIX_UP_LARGE,
TRACK_ELEM_RIGHT_HALF_BANKED_HELIX_UP_LARGE,
TRACK_ELEM_LEFT_HALF_BANKED_HELIX_DOWN_LARGE,
TRACK_ELEM_RIGHT_HALF_BANKED_HELIX_DOWN_LARGE,
TRACK_ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_UP,
TRACK_ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_UP,
TRACK_ELEM_LEFT_QUARTER_TURN_1_TILE_60_DEG_DOWN,
TRACK_ELEM_RIGHT_QUARTER_TURN_1_TILE_60_DEG_DOWN,
TRACK_ELEM_BRAKES,
TRACK_ELEM_ROTATION_CONTROL_TOGGLE,
TRACK_ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP,
TRACK_ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_UP,
TRACK_ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_UP,
TRACK_ELEM_LEFT_QUARTER_BANKED_HELIX_LARGE_DOWN,
TRACK_ELEM_RIGHT_QUARTER_BANKED_HELIX_LARGE_DOWN,
TRACK_ELEM_LEFT_QUARTER_HELIX_LARGE_UP,
TRACK_ELEM_RIGHT_QUARTER_HELIX_LARGE_UP,
TRACK_ELEM_LEFT_QUARTER_HELIX_LARGE_DOWN,
TRACK_ELEM_RIGHT_QUARTER_HELIX_LARGE_DOWN,
TRACK_ELEM_25_DEG_UP_LEFT_BANKED,
TRACK_ELEM_25_DEG_UP_RIGHT_BANKED,
TRACK_ELEM_WATERFALL,
TRACK_ELEM_RAPIDS,
TRACK_ELEM_ON_RIDE_PHOTO,
TRACK_ELEM_25_DEG_DOWN_LEFT_BANKED,
TRACK_ELEM_25_DEG_DOWN_RIGHT_BANKED,
TRACK_ELEM_WATER_SPLASH,
TRACK_ELEM_FLAT_TO_60_DEG_UP_LONG_BASE,
TRACK_ELEM_60_DEG_UP_TO_FLAT_LONG_BASE,
TRACK_ELEM_WHIRLPOOL,
TRACK_ELEM_FLAT_TO_60_DEG_DOWN_LONG_BASE,
TRACK_ELEM_60_DEG_UP_TO_FLAT_LONG_BASE_122,
TRACK_ELEM_CABLE_LIFT_HILL,
TRACK_ELEM_REVERSE_WHOA_BELLY_SLOPE,
TRACK_ELEM_REVERSE_WHOA_BELLY_VERTICAL,
TRACK_ELEM_90_DEG_UP,
TRACK_ELEM_90_DEG_DOWN,
TRACK_ELEM_60_DEG_UP_TO_90_DEG_UP,
TRACK_ELEM_90_DEG_DOWN_TO_60_DEG_DOWN,
TRACK_ELEM_90_DEG_UP_TO_60_DEG_UP,
TRACK_ELEM_60_DEG_DOWN_TO_90_DEG_DOWN,
TRACK_ELEM_BRAKE_FOR_DROP,
TRACK_ELEM_LEFT_EIGHTH_TO_DIAG,
TRACK_ELEM_RIGHT_EIGHTH_TO_DIAG,
TRACK_ELEM_LEFT_EIGHTH_TO_ORTHOGONAL,
TRACK_ELEM_RIGHT_EIGHTH_TO_ORTHOGONAL,
TRACK_ELEM_LEFT_EIGHTH_BANK_TO_DIAG,
TRACK_ELEM_RIGHT_EIGHTH_BANK_TO_DIAG,
TRACK_ELEM_LEFT_EIGHTH_BANK_TO_ORTHOGONAL,
TRACK_ELEM_RIGHT_EIGHTH_BANK_TO_ORTHOGONAL,
TRACK_ELEM_DIAG_FLAT,
TRACK_ELEM_DIAG_25_DEG_UP,
TRACK_ELEM_DIAG_60_DEG_UP,
TRACK_ELEM_DIAG_FLAT_TO_25_DEG_UP,
TRACK_ELEM_DIAG_25_DEG_UP_TO_60_DEG_UP,
TRACK_ELEM_DIAG_60_DEG_UP_TO_25_DEG_UP,
TRACK_ELEM_DIAG_25_DEG_UP_TO_FLAT,
TRACK_ELEM_DIAG_25_DEG_DOWN,
TRACK_ELEM_DIAG_60_DEG_DOWN,
TRACK_ELEM_DIAG_FLAT_TO_25_DEG_DOWN,
TRACK_ELEM_DIAG_25_DEG_DOWN_TO_60_DEG_DOWN,
TRACK_ELEM_DIAG_60_DEG_DOWN_TO_25_DEG_DOWN,
TRACK_ELEM_DIAG_25_DEG_DOWN_TO_FLAT,
TRACK_ELEM_DIAG_FLAT_TO_60_DEG_UP,
TRACK_ELEM_DIAG_60_DEG_UP_TO_FLAT,
TRACK_ELEM_DIAG_FLAT_TO_60_DEG_DOWN,
TRACK_ELEM_DIAG_60_DEG_DOWN_TO_FLAT,
TRACK_ELEM_DIAG_FLAT_TO_LEFT_BANK,
TRACK_ELEM_DIAG_FLAT_TO_RIGHT_BANK,
TRACK_ELEM_DIAG_LEFT_BANK_TO_FLAT,
TRACK_ELEM_DIAG_RIGHT_BANK_TO_FLAT,
TRACK_ELEM_DIAG_LEFT_BANK_TO_25_DEG_UP,
TRACK_ELEM_DIAG_RIGHT_BANK_TO_25_DEG_UP,
TRACK_ELEM_DIAG_25_DEG_UP_TO_LEFT_BANK,
TRACK_ELEM_DIAG_25_DEG_UP_TO_RIGHT_BANK,
TRACK_ELEM_DIAG_LEFT_BANK_TO_25_DEG_DOWN,
TRACK_ELEM_DIAG_RIGHT_BANK_TO_25_DEG_DOWN,
TRACK_ELEM_DIAG_25_DEG_DOWN_TO_LEFT_BANK,
TRACK_ELEM_DIAG_25_DEG_DOWN_TO_RIGHT_BANK,
TRACK_ELEM_DIAG_LEFT_BANK,
TRACK_ELEM_DIAG_RIGHT_BANK,
TRACK_ELEM_LOG_FLUME_REVERSER,
TRACK_ELEM_SPINNING_TUNNEL,
TRACK_ELEM_LEFT_BARREL_ROLL_UP_TO_DOWN,
TRACK_ELEM_RIGHT_BARREL_ROLL_UP_TO_DOWN,
TRACK_ELEM_LEFT_BARREL_ROLL_DOWN_TO_UP,
TRACK_ELEM_RIGHT_BARREL_ROLL_DOWN_TO_UP,
TRACK_ELEM_LEFT_BANK_TO_LEFT_QUARTER_TURN_3_TILES_25_DEG_UP,
TRACK_ELEM_RIGHT_BANK_TO_RIGHT_QUARTER_TURN_3_TILES_25_DEG_UP,
TRACK_ELEM_LEFT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_LEFT_BANK,
TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN_TO_RIGHT_BANK,
TRACK_ELEM_POWERED_LIFT,
TRACK_ELEM_LEFT_LARGE_HALF_LOOP_UP,
TRACK_ELEM_RIGHT_LARGE_HALF_LOOP_UP,
TRACK_ELEM_RIGHT_LARGE_HALF_LOOP_DOWN,
TRACK_ELEM_LEFT_LARGE_HALF_LOOP_DOWN
};
extern const rct_trackdefinition *gTrackDefinitions;
void track_load_list(ride_list_item item);

View File

@ -99,9 +99,8 @@ void vehicle_update_sound_params(rct_vehicle* vehicle)
sint32 v19 = vehicle->velocity;
int testaddr = (vehicle->var_31 * 0x65);
testaddr += (int)RCT2_ADDRESS(0x009ACFA4, rct_ride_type*)[vehicle->var_D6];
uint8 test = ((uint8*)testaddr)[0x74];
rct_ride_type* ride_type = GET_RIDE_ENTRY(vehicle->ride_subtype);
uint8 test = ride_type->vehicles[vehicle->vehicle_type].var_5A;
if (test & 1) {
v19 *= 2;
@ -633,4 +632,9 @@ rct_vehicle *vehicle_get_head(rct_vehicle *vehicle)
}
return vehicle;
}
int vehicle_is_used_in_pairs(rct_vehicle *vehicle)
{
return vehicle->num_seats & VEHICLE_SEAT_PAIR_FLAG;
}

View File

@ -26,31 +26,41 @@
typedef struct {
uint8 sprite_identifier; // 0x00
uint8 var_01;
uint8 pad_02[0x02];
uint16 next_in_quadrant; // 0x02
uint16 next; // 0x04
uint16 previous; // 0x06
uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8 pad_09;
// Height from center of sprite to bottom
uint8 sprite_height_negative; // 0x09
uint16 sprite_index; // 0x0A
uint8 pad_0C[2];
sint16 x; // 0x0E
sint16 y; // 0x10
sint16 z; // 0x12
uint8 pad_14[0x02];
// Width from center of sprite to edge
uint8 sprite_width; // 0x14
// Height from center of sprite to top
uint8 sprite_height_positive; // 0x15
sint16 sprite_left; // 0x16
sint16 sprite_top; // 0x18
sint16 sprite_right; // 0x1A
sint16 sprite_bottom; // 0x1C
uint8 sprite_direction; // 0x1E
uint8 pad_1F[0x09];
uint8 var_1F;
uint8 pad_20[0x08];
sint32 velocity; // 0x28
uint8 pad_2C[0x04];
uint8 ride; // 0x30
uint8 var_31;
uint8 vehicle_type; // 0x31
uint8 pad_32[0x02];
uint16 var_34;
sint16 var_36;
uint8 pad_38[0x06];
//x related
uint16 var_38;
// y related
uint16 var_3A;
// z related
uint16 var_3C;
uint16 next_vehicle_on_train; // 0x3E
uint16 prev_vehicle_on_train; // 0x40
uint16 pad_42;
@ -58,14 +68,16 @@ typedef struct {
uint16 var_46;
uint16 var_48;
uint8 pad_4A;
uint8 var_4B;
uint8 current_station; // 0x4B
uint8 pad_4C[0x4];
uint8 status; // 0x50
uint8 var_51;
uint16 peep[32]; // 0x52
uint8 pad_92[0x21];
uint8 peep_tshirt_colours[32]; // 0x92
uint8 num_seats; // 0xB2
uint8 num_peeps; // 0xB3
uint8 pad_B4[0x07];
uint8 next_free_seat; // 0xB4
uint8 pad_B5[0x06];
uint8 sound1_id; // 0xBB
uint8 sound1_volume; // 0xBC
uint8 sound2_id; // 0xBD
@ -78,10 +90,11 @@ typedef struct {
uint8 var_CD;
union {
uint8 var_CE;
uint8 num_laps; // 0xCE
uint8 num_laps; // 0xCE
};
uint8 pad_CF[0x07];
uint8 var_D6;
uint8 pad_CF[0x06];
uint8 var_D5;
uint8 ride_subtype; // 0xD6
} rct_vehicle;
enum {
@ -118,13 +131,16 @@ enum {
VEHICLE_STATUS_STOPPED_BY_BLOCK_BRAKES
};
#define VEHICLE_SEAT_PAIR_FLAG 0x80
#define VEHICLE_SEAT_NUM_MASK 0x7F
void vehicle_update_all();
int sub_6BC2F3(rct_vehicle* vehicle);
void sub_6BB9FF(rct_vehicle* vehicle);
void vehicle_sounds_update();
void vehicle_get_g_forces(rct_vehicle *vehicle, int *verticalG, int *lateralG);
void vehicle_set_map_toolbar(rct_vehicle *vehicle);
int vehicle_is_used_in_pairs(rct_vehicle *vehicle);
rct_vehicle *vehicle_get_head(rct_vehicle *vehicle);
/** Helper macro until rides are stored in this module. */

View File

@ -281,9 +281,9 @@ typedef struct {
uint16 saved_view_x;
uint16 saved_view_y;
uint16 saved_view_zoom_and_rotation;
uint8 byte_013886A0[6000];
uint8 map_animations[6000];
uint8 byte_01389E10[6000];
uint16 word_0138B580;
uint16 num_map_animations;
uint8 pad_0138B580[2];
uint16 word_0138B584;
uint16 word_0138B586;

View File

@ -266,7 +266,6 @@ static void DrawOpenRCT2(int x, int y)
void game_handle_input();
void title_update()
{
screenshot_check();
title_handle_keyboard_input();

View File

@ -355,7 +355,12 @@ static void cheat_renew_rides()
rct_ride *ride;
FOR_ALL_RIDES(i, ride)
{
// Set build date to current date (so the ride is brand new)
ride->build_date = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16);
// Set reliability to 100
ride->reliability = (100 << 8);
}
window_invalidate_by_class(WC_RIDE);
}

View File

@ -223,7 +223,7 @@ static void window_footpath_close()
window_get_register(w);
sub_6A7831();
footpath_provisional_update();
viewport_set_visibility(0);
map_invalidate_map_selection_tiles();
RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~2;
@ -258,7 +258,7 @@ static void window_footpath_mouseup()
_window_footpath_cost = MONEY32_UNDEFINED;
tool_cancel();
sub_6A7831();
footpath_provisional_update();
map_invalidate_map_selection_tiles();
RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~2;
RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) = PATH_CONSTRUCTION_MODE_LAND;
@ -273,7 +273,7 @@ static void window_footpath_mouseup()
_window_footpath_cost = MONEY32_UNDEFINED;
tool_cancel();
sub_6A7831();
footpath_provisional_update();
map_invalidate_map_selection_tiles();
RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~2;
RCT2_GLOBAL(RCT2_ADDRESS_PATH_CONSTRUCTION_MODE, uint8) = PATH_CONSTRUCTION_MODE_BRIDGE_OR_TUNNEL_TOOL;
@ -369,7 +369,7 @@ static void window_footpath_dropdown()
// Set selected path id
RCT2_GLOBAL(RCT2_ADDRESS_SELECTED_PATH_ID, sint16) = pathId;
sub_6A7831();
footpath_provisional_update();
_window_footpath_cost = MONEY32_UNDEFINED;
window_invalidate(w);
}
@ -424,7 +424,7 @@ static void window_footpath_tooldrag()
window_tool_get_registers(w, widgetIndex, x, y);
if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) {
RCT2_CALLPROC_X(0x006A82C5, x, y, 0, 0, (int)w, 0, 0);
window_footpath_place_path_at_point(x, y);
}
}
@ -441,7 +441,8 @@ static void window_footpath_toolup()
window_tool_get_registers(w, widgetIndex, x, y);
if (widgetIndex == WIDX_CONSTRUCT_ON_LAND) {
RCT2_CALLPROC_X(0x006A8380, x, y, 0, 0, (int)w, 0, 0);
// The function at 0x006A8380 in rct2 is just the following:
RCT2_GLOBAL(RCT2_ADDRESS_PATH_ERROR_OCCURED, uint8) = 0;
}
}
@ -641,7 +642,7 @@ static void window_footpath_show_footpath_types_dialog(rct_window *w, rct_widget
*/
static void window_footpath_mousedown_direction(int direction)
{
sub_6A7831();
footpath_provisional_update();
RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8) = (direction - RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint32)) & 3;
_window_footpath_cost = MONEY32_UNDEFINED;
window_footpath_set_enabled_and_pressed_widgets();
@ -653,7 +654,7 @@ static void window_footpath_mousedown_direction(int direction)
*/
static void window_footpath_mousedown_slope(int slope)
{
sub_6A7831();
footpath_provisional_update();
RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8) = slope;
_window_footpath_cost = MONEY32_UNDEFINED;
window_footpath_set_enabled_and_pressed_widgets();
@ -675,7 +676,7 @@ static void window_footpath_set_provisional_path_at_point(int x, int y)
if (z == 0) {
RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~(1 << 0);
sub_6A7831();
footpath_provisional_update();
} else {
// Check for change
if ((RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) & (1 << 1)) && RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_X, uint16) == x && RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Y, uint16) == y && RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_Z, uint8) == mapElement->base_height)
@ -689,7 +690,7 @@ static void window_footpath_set_provisional_path_at_point(int x, int y)
RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_X, uint16) = x;
RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_B_Y, uint16) = y;
sub_6A7831();
footpath_provisional_update();
// Set provisional path
slope = RCT2_ADDRESS(0x0098D8B4, uint8)[mapElement->properties.surface.slope & 0x1F];
@ -714,7 +715,7 @@ static void window_footpath_place_path_at_point(int x, int y)
if (RCT2_GLOBAL(RCT2_ADDRESS_PATH_ERROR_OCCURED, uint8) != 0)
return;
sub_6A7831();
footpath_provisional_update();
get_map_coordinates_from_pos(x, y, 0xFFDE, &x, &y, &z, &mapElement);
if (z == 0)
@ -755,14 +756,17 @@ static void window_footpath_start_bridge_at_point(int screenX, int screenY)
return;
if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_SURFACE) {
// ?
uint8 dl = ((mapElement->properties.surface.slope & 0x0F) << direction) & 0xFF;
uint8 dh = dl;
dl = (dl >> 4) & 0x0F;
dh = (dh & 0x0F) | dl;
// If we start the path on a slope, the arrow is slightly raised, so we
// expect the path to be slightly raised as well.
uint8_t slope = mapElement->properties.surface.slope;
z = mapElement->base_height;
if ((dh & 0x0C) == 0x0C)
if (slope & 0x10) {
// Steep diagonal slope
z += 4;
} else if (slope & 0x0f) {
// Normal slope
z += 2;
}
} else {
z = mapElement->base_height;
if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) {
@ -787,12 +791,66 @@ static void window_footpath_start_bridge_at_point(int screenX, int screenY)
}
/**
*
* Construct a piece of footpath while in bridge building mode.
* rct2: 0x006A79B7
*/
static void window_footpath_construct()
{
RCT2_CALLPROC_EBPSAFE(0x006A79B7);
_window_footpath_cost = MONEY32_UNDEFINED;
footpath_provisional_update();
int type, x, y, z, slope;
footpath_get_next_path_info(&type, &x, &y, &z, &slope);
// Try to place the path at the desired location
RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 0x498;
money32 cost = footpath_place(type, x, y, z, slope, 0);
if (cost != MONEY32_UNDEFINED) {
// It is possible, let's remove walls between the old and new piece of path
uint8 direction = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8);
map_remove_intersecting_walls(x, y, z, z + 4 + (slope & 0xf ? 2 : 0), direction ^ 2);
map_remove_intersecting_walls(
x - TileDirectionDelta[direction].x,
y - TileDirectionDelta[direction].y,
z, z + 4, direction
);
}
// Actually place the path now
RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = 0x498;
cost = footpath_place(type, x, y, z, slope, GAME_COMMAND_FLAG_APPLY);
if (cost != MONEY32_UNDEFINED) {
sound_play_panned(
SOUND_PLACE_ITEM,
0x8001,
RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16),
RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16),
RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Z, uint16)
);
if (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8) == 0) {
RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_VALID_DIRECTIONS, uint8) = 0xff;
} else {
RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_VALID_DIRECTIONS, uint8) = RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_DIRECTION, uint8);
}
if (RCT2_GLOBAL(0x00F3EFA4, uint8) & 2)
viewport_set_visibility(1);
// If we have just built an upwards slope, the next path to construct is
// a bit higher. Note that the z returned by footpath_get_next_path_info
// already is lowered if we are building a downwards slope.
if (RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_SLOPE, uint8) == 2)
z += 2;
RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_X, uint16) = x;
RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Y, uint16) = y;
RCT2_GLOBAL(RCT2_ADDRESS_CONSTRUCT_PATH_FROM_Z, uint16) = z << 3;
}
window_footpath_set_enabled_and_pressed_widgets();
}
/**
@ -894,7 +952,7 @@ static void window_footpath_remove()
rct_map_element *mapElement;
_window_footpath_cost = MONEY32_UNDEFINED;
sub_6A7831();
footpath_provisional_update();
mapElement = footpath_get_map_element_to_remove();
if (mapElement != NULL)

View File

@ -1235,8 +1235,8 @@ void window_guest_overview_tool_down(){
peep_window_state_update(peep);
peep->action = 0xFF;
peep->var_6D = 0;
peep->var_70 = 0;
peep->var_6E = 0xFF;
peep->action_sprite_image_offset = 0;
peep->action_sprite_type = 0xFF;
peep->var_C4 = 0;
peep->happiness_growth_rate -= 10;
@ -1268,8 +1268,8 @@ void window_guest_overview_tool_abort(){
peep_window_state_update(peep);
peep->action = 0xFF;
peep->var_6D = 0;
peep->var_70 = 0;
peep->var_6E = 0;
peep->action_sprite_image_offset = 0;
peep->action_sprite_type = 0;
peep->var_C4 = 0;
}
@ -2152,7 +2152,7 @@ void window_guest_inventory_paint(){
no_items++;
RCT2_GLOBAL(0x13CE952, uint32) = 5089 + i;
RCT2_GLOBAL(0x13CE956, uint16) = 2188;
RCT2_GLOBAL(0x13CE956, uint16) = 2188 + i;
RCT2_GLOBAL(0x13CE958, uint16) = RCT2_GLOBAL(0x13573D4, uint16);
RCT2_GLOBAL(0x13CE95A, uint32) = RCT2_GLOBAL(0x13573D8, uint32);

View File

@ -100,13 +100,13 @@ static void* window_new_campaign_events[] = {
uint8 window_new_campaign_rides[MAX_RIDES];
uint8 window_new_campaign_shop_items[64];
int ride_reliability_compare(const void *a, const void *b)
int ride_value_compare(const void *a, const void *b)
{
rct_ride *rideA, *rideB;
rideA = GET_RIDE(*((uint8*)a));
rideB = GET_RIDE(*((uint8*)b));
return rideB->reliability - rideA->reliability;
return rideB->value - rideA->value;
}
int ride_name_compare(const void *a, const void *b)
@ -179,7 +179,7 @@ void window_new_campaign_open(sint16 campaignType)
// Take top 40 most reliable rides
if (numApplicableRides > 40) {
qsort(window_new_campaign_rides, countof(window_new_campaign_rides), sizeof(uint8), ride_reliability_compare);
qsort(window_new_campaign_rides, countof(window_new_campaign_rides), sizeof(uint8), ride_value_compare);
numApplicableRides = 40;
}
@ -413,4 +413,4 @@ static void window_new_campaign_paint()
// Total price
money32 totalPrice = AdvertisingCampaignPricePerWeek[w->campaign.campaign_type] * w->campaign.no_weeks;
gfx_draw_string_left(dpi, STR_MARKETING_TOTAL_COST, &totalPrice, 0, x, y);
}
}

View File

@ -446,7 +446,7 @@ void window_new_ride_focus(ride_list_item rideItem)
ride_list_item *listItem = (ride_list_item*)0x00F43523;
while (listItem->type != RIDE_TYPE_NULL) {
if (listItem->type == rideItem.type && listItem->entry_index == rideItem.type) {
if (listItem->type == rideItem.type && listItem->entry_index == rideItem.entry_index) {
RCT2_GLOBAL(0x00F43825, uint8) = rideItem.type;
RCT2_GLOBAL(0x00F43826, uint8) = rideItem.entry_index;
w->new_ride.highlighted_ride_id = (rideItem.entry_index << 8) | rideItem.type;

View File

@ -345,14 +345,17 @@ static void window_options_mouseup()
window_invalidate(w);
break;
case WIDX_SOUND_CHECKBOX:
if (g_sounds_disabled)
unpause_sounds();
else
pause_sounds();
toggle_all_sounds();
config_save_default();
window_invalidate(w);
break;
case WIDX_MUSIC_CHECKBOX:
RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) ^= 1;
if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8) == 0)
stop_ride_music();
gConfigSound.ride_music ^= 1;
config_save_default();
window_invalidate(w);
break;
}
@ -730,7 +733,7 @@ static void window_options_invalidate()
// sound quality: low/medium/high
RCT2_GLOBAL(0x013CE952 + 10, uint16) = STR_SOUND_LOW + gConfigSound.sound_quality;
widget_set_checkbox_value(w, WIDX_SOUND_CHECKBOX, !g_sounds_disabled);
widget_set_checkbox_value(w, WIDX_SOUND_CHECKBOX, gConfigSound.sound);
widget_set_checkbox_value(w, WIDX_MUSIC_CHECKBOX, RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8));
window_options_widgets[WIDX_SOUND].type = WWT_DROPDOWN;

View File

@ -1568,7 +1568,7 @@ static void window_park_stats_paint()
y += 10;
// Draw number of rides / attractions
if (w->list_information_type != -1) {
if (w->list_information_type != (uint16)-1) {
RCT2_GLOBAL(0x013CE952, uint32) = w->list_information_type;
gfx_draw_string_left(dpi, STR_NUMBER_OF_RIDES_LABEL, (void*)0x013CE952, 0, x, y);
}
@ -1941,8 +1941,9 @@ static void window_park_set_page(rct_window *w, int page)
window_park_set_disabled_tabs(w);
window_invalidate(w);
RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0);
RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0);
window_event_resize_call(w);
window_event_invalidate_call(w);
window_event_update_call(w);
if (listen != 0 && w->viewport != NULL)
w->viewport->flags |= VIEWPORT_FLAG_SOUND_ON;
}

View File

@ -1901,7 +1901,7 @@ static void window_ride_main_update(rct_window *w)
// Update status
ride = GET_RIDE(w->number);
if (!(ride->var_14D & 4)) {
if (!(ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_MAIN)) {
if (w->ride.view == 0)
return;
@ -1923,7 +1923,7 @@ static void window_ride_main_update(rct_window *w)
}
}
ride->var_14D &= ~4;
ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_MAIN;
widget_invalidate(w, WIDX_STATUS);
}
@ -2070,7 +2070,7 @@ static rct_string_id window_ride_get_status_vehicle(rct_window *w, void *argumen
stringId += 23;
RCT2_GLOBAL((int)arguments + 4, uint16) = RideNameConvention[ride->type].station_name;
RCT2_GLOBAL((int)arguments + 6, uint16) = vehicle->var_4B + 1;
RCT2_GLOBAL((int)arguments + 6, uint16) = vehicle->current_station + 1;
if (ride->num_stations > 1)
RCT2_GLOBAL((int)arguments + 4, uint16) += 6;
@ -2390,7 +2390,7 @@ static void window_ride_vehicle_dropdown()
break;
case WIDX_VEHICLE_CARS_PER_TRAIN_DROPDOWN:
RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, rct_string_id) = 1019;
game_do_command(0, (1 << 8) | 1, 0, ((rideEntry->var_00F + dropdownIndex) << 8) | w->number, GAME_COMMAND_9, 0, 0);
game_do_command(0, (1 << 8) | 1, 0, ((rideEntry->min_cars_in_train + dropdownIndex) << 8) | w->number, GAME_COMMAND_9, 0, 0);
break;
}
}
@ -2461,7 +2461,7 @@ static void window_ride_vehicle_invalidate()
}
// Cars per train
if (rideEntry->var_012 + 1 < rideEntry->var_010) {
if (rideEntry->var_012 + 1 < rideEntry->max_cars_in_train) {
window_ride_vehicle_widgets[WIDX_VEHICLE_CARS_PER_TRAIN].image = carsPerTrain > 1 ? 1023 : 1022;
window_ride_vehicle_widgets[WIDX_VEHICLE_CARS_PER_TRAIN].type = WWT_DROPDOWN;
window_ride_vehicle_widgets[WIDX_VEHICLE_CARS_PER_TRAIN_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
@ -2950,8 +2950,8 @@ static void window_ride_operating_update(rct_window *w)
widget_invalidate(w, WIDX_TAB_3);
ride = GET_RIDE(w->number);
if (ride->var_14D & 10) {
ride->var_14D &= ~10;
if (ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_OPERATING) {
ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_OPERATING;
window_invalidate(w);
}
}
@ -3360,8 +3360,8 @@ static void window_ride_maintenance_update(rct_window *w)
widget_invalidate(w, WIDX_TAB_4);
ride = GET_RIDE(w->number);
if (ride->var_14D & 20) {
ride->var_14D &= ~20;
if (ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_MAINTENANCE) {
ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_MAINTENANCE;
window_invalidate(w);
}
}
@ -3434,13 +3434,12 @@ static void window_ride_maintenance_paint()
x = w->x + widget->left + 4;
y = w->y + widget->top + 4;
reliability = ride->var_196 >> 8;
reliability = ride->reliability >> 8;
gfx_draw_string_left(dpi, STR_RELIABILITY_LABEL_1757, &reliability, 0, x, y);
window_ride_maintenance_draw_bar(w, dpi, x + 103, y, max(10, reliability), 14);
y += 11;
// Down time
downTime = ride->var_199;
downTime = ride->downtime;
gfx_draw_string_left(dpi, STR_DOWN_TIME_LABEL_1889, &downTime, 0, x, y);
window_ride_maintenance_draw_bar(w, dpi, x + 103, y, downTime, 28);
y += 26;
@ -3740,7 +3739,7 @@ static void window_ride_colour_mousedown(int widgetIndex, rct_window *w, rct_wid
dropdownWidget->bottom - dropdownWidget->top + 1,
w->colours[1],
0,
rideEntry->var_010 > 1 ? 3 : 2,
rideEntry->max_cars_in_train > 1 ? 3 : 2,
widget->right - dropdownWidget->left
);
@ -5452,8 +5451,8 @@ static void window_ride_income_update(rct_window *w)
widget_invalidate(w, WIDX_TAB_9);
ride = GET_RIDE(w->number);
if (ride->var_14D & 2) {
ride->var_14D &= ~2;
if (ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_INCOME) {
ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_INCOME;
window_invalidate(w);
}
}
@ -5736,8 +5735,8 @@ static void window_ride_customer_update(rct_window *w)
widget_invalidate(w, WIDX_TAB_10);
ride = GET_RIDE(w->number);
if (ride->var_14D & 1) {
ride->var_14D &= ~1;
if (ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_CUSTOMER) {
ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_CUSTOMER;
window_invalidate(w);
}
}

View File

@ -507,13 +507,13 @@ static void window_ride_list_scrollpaint()
case INFORMATION_TYPE_RELIABILITY:
// edx = RCT2_GLOBAL(0x009ACFA4 + (ride->var_001 * 4), uint32);
RCT2_GLOBAL(0x013CE952 + 2, uint16) = ride->var_196 >> 8;
RCT2_GLOBAL(0x013CE952 + 2, uint16) = ride->reliability >> 8;
formatSecondary = STR_RELIABILITY_LABEL;
break;
case INFORMATION_TYPE_DOWN_TIME:
// edx = RCT2_GLOBAL(0x009ACFA4 + (ride->var_001 * 4), uint32);
RCT2_GLOBAL(0x013CE952 + 2, uint16) = ride->var_199;
RCT2_GLOBAL(0x013CE952 + 2, uint16) = ride->downtime;
formatSecondary = STR_DOWN_TIME_LABEL;
break;
case INFORMATION_TYPE_GUESTS_FAVOURITE:
@ -579,8 +579,8 @@ static void window_ride_list_refresh_list(rct_window *w)
continue;
countA++;
if (ride->var_14D & 8) {
ride->var_14D &= ~8;
if (ride->window_invalidate_flags & RIDE_INVALIDATE_RIDE_LIST) {
ride->window_invalidate_flags &= ~RIDE_INVALIDATE_RIDE_LIST;
countB++;
}
}
@ -661,7 +661,7 @@ static void window_ride_list_refresh_list(rct_window *w)
case INFORMATION_TYPE_RELIABILITY:
while (--current_list_position >= 0) {
otherRide = &g_ride_list[w->list_item_positions[current_list_position]];
if (ride->var_196 >> 8 <= otherRide->var_196 >> 8)
if (ride->reliability >> 8 <= otherRide->reliability >> 8)
break;
window_bubble_list_item(w, current_list_position);
@ -670,7 +670,7 @@ static void window_ride_list_refresh_list(rct_window *w)
case INFORMATION_TYPE_DOWN_TIME:
while (--current_list_position >= 0) {
otherRide = &g_ride_list[w->list_item_positions[current_list_position]];
if (ride->var_199 <= otherRide->var_199)
if (ride->downtime <= otherRide->downtime)
break;
window_bubble_list_item(w, current_list_position);

View File

@ -931,10 +931,10 @@ void window_scenery_invalidate()
} else if (tabSelectedSceneryId < 0x100) {
sceneryEntry = g_smallSceneryEntries[tabSelectedSceneryId];
if (sceneryEntry->small_scenery.flags & (SMALL_SCENERY_HAS_PRIMARY_COLOUR | SMALL_SCENERY_FLAG10)) {
if (sceneryEntry->small_scenery.flags & (SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR | SMALL_SCENERY_FLAG10)) {
window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WWT_COLORBTN;
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_HAS_SECONDARY_COLOUR)
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR)
window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WWT_COLORBTN;
}
}
@ -1145,18 +1145,18 @@ void window_scenery_scrollpaint()
uint32 imageId = sceneryEntry->image + window_scenery_rotation;
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_HAS_PRIMARY_COLOUR) {
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR) {
imageId |= (window_scenery_primary_colour << 19) | 0x20000000;
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_HAS_SECONDARY_COLOUR) {
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR) {
imageId |= (window_scenery_secondary_colour << 24) | 0x80000000;
}
}
uint16 spriteTop = (sceneryEntry->small_scenery.height / 4) + 0x2B;
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG1 &&
sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG2) {
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_FULL_TILE &&
sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_VOFFSET_CENTRE) {
spriteTop -= 0x0C;
}

View File

@ -641,7 +641,7 @@ static void window_sign_small_dropdown()
((w->var_492 & 0x7) << 5);
map_element->flags |= ((w->var_492 & 0x18) << 2);
RCT2_CALLPROC_X(0x6EC847, x, 0, y, 0, map_element->clearance_height << 3, map_element->base_height << 3, 0);
sub_6EC847(x, y, map_element->base_height * 8, map_element->clearance_height * 8);
window_invalidate(w);
}

View File

@ -1158,8 +1158,8 @@ void window_staff_overview_tool_down(){
peep_window_state_update(peep);
peep->action = 0xFF;
peep->var_6D = 0;
peep->var_70 = 0;
peep->var_6E = 0;
peep->action_sprite_image_offset = 0;
peep->action_sprite_type = 0;
peep->var_C4 = 0;
tool_cancel();
@ -1196,8 +1196,8 @@ void window_staff_overview_tool_abort(){
peep_window_state_update(peep);
peep->action = 0xFF;
peep->var_6D = 0;
peep->var_70 = 0;
peep->var_6E = 0;
peep->action_sprite_image_offset = 0;
peep->action_sprite_type = 0;
peep->var_C4 = 0;
}

View File

@ -459,7 +459,7 @@ void footpath_provisional_remove()
*
* rct2: 0x006A7831
*/
void sub_6A7831()
void footpath_provisional_update()
{
if (RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) & PROVISIONAL_PATH_FLAG_SHOW_ARROW) {
RCT2_GLOBAL(RCT2_ADDRESS_PROVISIONAL_PATH_FLAGS, uint8) &= ~PROVISIONAL_PATH_FLAG_SHOW_ARROW;

View File

@ -45,7 +45,7 @@ money32 footpath_place(int type, int x, int y, int z, int slope, int flags);
void footpath_remove(int x, int y, int z, int flags);
money32 footpath_provisional_set(int type, int x, int y, int z, int slope);
void footpath_provisional_remove();
void sub_6A7831();
void footpath_provisional_update();
void sub_68A0C9(int screenX, int screenY, int *x, int *y, int *direction, rct_map_element **mapElement);
#endif

View File

@ -1,5 +1,5 @@
/*****************************************************************************
* Copyright (c) 2014 Ted John, Peter Hill
* Copyright (c) 2014 Ted John
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* This file is part of OpenRCT2.
@ -19,19 +19,427 @@
*****************************************************************************/
#include "../addresses.h"
#include "../game.h"
#include "../common.h"
#include "../scenario.h"
#include "fountain.h"
#include "map.h"
#include "scenery.h"
#include "sprite.h"
enum {
PATTERN_CYCLIC_SQUARES,
PATTERN_CONTINUOUS_CHASERS,
PATTERN_BOUNCING_PAIRS,
PATTERN_SPROUTING_BLOOMS,
PATTERN_RACING_PAIRS,
PATTERN_SPLITTING_CHASERS,
PATTERN_DOPEY_JUMPERS,
PATTERN_FAST_RANDOM_CHASERS
};
enum {
FOUNTAIN_FLAG_FAST = 1 << 0,
FOUNTAIN_FLAG_GOTO_EDGE = 1 << 1,
FOUNTAIN_FLAG_SPLIT = 1 << 2,
FOUNTAIN_FLAG_TERMINATE = 1 << 3,
FOUNTAIN_FLAG_BOUNCE = 1 << 4,
FOUNTAIN_FLAG_7 = 1 << 7
};
const rct_xy16 dword_97F000[] = {
{ -32, 0 },
{ -32, -32 },
{ 0, 0 },
{ -32, 0 },
{ 0, 0 },
{ 0, -32 },
{ 0, -32 },
{ -32, -32 },
};
const rct_xy16 dword_97F020[] = {
{ 32, 0 },
{ 0, 0 },
{ 0, 32 },
{ 32, 32 },
{ 32, 32 },
{ 32, 0 },
{ 0, 0 },
{ 0, 32 }
};
// rct2: 0x0097F040
const uint8 _fountainDirections[] = { 0, 1, 2, 3, 0, 1, 2, 3 };
// rct2: 0x0097F048
const uint8 _fountainDirectionFlags[] = { 0, 0, FOUNTAIN_FLAG_7, FOUNTAIN_FLAG_7, FOUNTAIN_FLAG_7, FOUNTAIN_FLAG_7, 0, 0 };
// rct2: 0x0097F050
const uint8 _fountainPatternFlags[] = {
FOUNTAIN_FLAG_TERMINATE, // PATTERN_CYCLIC_SQUARES
FOUNTAIN_FLAG_FAST | FOUNTAIN_FLAG_GOTO_EDGE, // PATTERN_CONTINUOUS_CHASERS
FOUNTAIN_FLAG_BOUNCE, // PATTERN_BOUNCING_PAIRS
FOUNTAIN_FLAG_FAST | FOUNTAIN_FLAG_SPLIT, // PATTERN_SPROUTING_BLOOMS
FOUNTAIN_FLAG_GOTO_EDGE, // PATTERN_RACING_PAIRS
FOUNTAIN_FLAG_FAST | FOUNTAIN_FLAG_GOTO_EDGE | FOUNTAIN_FLAG_SPLIT, // PATTERN_SPLITTING_CHASERS
0, // PATTERN_DOPEY_JUMPERS
FOUNTAIN_FLAG_FAST // PATTERN_FAST_RANDOM_CHASERS
};
static void jumping_fountain_continue(rct_jumping_fountain *jumpingFountain);
static bool is_jumping_fountain(int type, int x, int y, int z);
static void jumping_fountain_goto_edge(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections);
static void jumping_fountain_bounce(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections);
static void jumping_fountain_split(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections);
static void jumping_fountain_random(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections);
static void jumping_fountain_create_next(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int direction);
/**
*
* rct2: 0x006646E1
* rct2: 0x00673DBA (water)
* rct2: 0x00673F51 (snow)
*/
void fountain_update_all()
void jumping_fountain_begin(int type, int x, int y, rct_map_element *mapElement)
{
int ignoreScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR | SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER;
if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & ignoreScreenFlags)
int i, randomIndex;
int z = mapElement->base_height * 8;
// Change pattern approximately every 51 seconds
int pattern = (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) >> 11) & 7;
switch (pattern) {
case PATTERN_CYCLIC_SQUARES:
// 0, 1, 2, 3
for (i = 0; i < 4; i++) {
jumping_fountain_create(
type,
x + dword_97F020[i].x,
y + dword_97F020[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 (i = randomIndex; i < 4; i += 2) {
jumping_fountain_create(
type,
x + dword_97F020[i].x,
y + dword_97F020[i].y,
z,
_fountainDirections[i],
_fountainDirectionFlags[i] | _fountainPatternFlags[pattern],
0
);
}
break;
case PATTERN_RACING_PAIRS:
// random [0 - 3 and 4 - 7]
z = mapElement->base_height * 8;
randomIndex = scenario_rand() & 3;
jumping_fountain_create(
type,
x + dword_97F020[randomIndex].x,
y + dword_97F020[randomIndex].y,
z,
_fountainDirections[randomIndex],
_fountainDirectionFlags[randomIndex] | _fountainPatternFlags[pattern],
0
);
randomIndex += 4;
jumping_fountain_create(
type,
x + dword_97F020[randomIndex].x,
y + dword_97F020[randomIndex].y,
z,
_fountainDirections[randomIndex],
_fountainDirectionFlags[randomIndex] | _fountainPatternFlags[pattern],
0
);
break;
default:
// random [0 - 7]
randomIndex = scenario_rand() & 7;
jumping_fountain_create(
type,
x + dword_97F020[randomIndex].x,
y + dword_97F020[randomIndex].y,
z,
_fountainDirections[randomIndex],
_fountainDirectionFlags[randomIndex] | _fountainPatternFlags[pattern],
0
);
break;
}
}
/**
*
* rct2: 0x0067396A (water)
* rct2: 0x006739A4 (snow)
*/
void jumping_fountain_create(int type, int x, int y, int z, int direction, int flags, int iteration)
{
rct_jumping_fountain *jumpingFountain;
jumpingFountain = (rct_jumping_fountain*)create_sprite(SPRITE_IDENTIFIER_MISC);
if (jumpingFountain == NULL)
return;
// Probably not just fountains... may include scenery aging and grass growth.
RCT2_CALLPROC_EBPSAFE(0x006646EE);
jumpingFountain->iteration = iteration;
jumpingFountain->var_2E = direction;
jumpingFountain->flags = flags;
jumpingFountain->sprite_direction = direction << 3;
jumpingFountain->var_14 = 33;
jumpingFountain->var_09 = 36;
jumpingFountain->var_15 = 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;
jumpingFountain->var_26 = 0;
}
/**
*
* rct: 0x006733CB (water)
* rct: 0x00673407 (snow)
*/
void jumping_fountain_update(rct_jumping_fountain *jumpingFountain)
{
int original_var_26a = jumpingFountain->var_26a;
jumpingFountain->var_26a += 160;
if (original_var_26a <= 255 - 160)
return;
sub_6EC60B((rct_sprite*)jumpingFountain);
jumpingFountain->var_26b++;
switch (jumpingFountain->misc_identifier) {
case SPRITE_MISC_JUMPING_FOUNTAIN_WATER:
if (jumpingFountain->var_26b == 11 && (jumpingFountain->flags & FOUNTAIN_FLAG_FAST))
jumping_fountain_continue(jumpingFountain);
if (jumpingFountain->var_26b == 16 && !(jumpingFountain->flags & FOUNTAIN_FLAG_FAST))
jumping_fountain_continue(jumpingFountain);
break;
case SPRITE_MISC_JUMPING_FOUNTAIN_SNOW:
if (jumpingFountain->var_26b == 16)
jumping_fountain_continue(jumpingFountain);
break;
}
if (jumpingFountain->var_26b == 16)
sprite_remove((rct_sprite*)jumpingFountain);
}
/**
*
* rct2: 0x006739DE (water)
* rct2: 0x00673BCC (snow)
*/
static void jumping_fountain_continue(rct_jumping_fountain *jumpingFountain)
{
int direction = (jumpingFountain->sprite_direction >> 3) & 7;
int x = jumpingFountain->x + TileDirectionDelta[direction].x;
int y = jumpingFountain->y + TileDirectionDelta[direction].y;
int z = jumpingFountain->z;
int type = jumpingFountain->misc_identifier == SPRITE_MISC_JUMPING_FOUNTAIN_SNOW ?
JUMPING_FOUNTAIN_TYPE_SNOW :
JUMPING_FOUNTAIN_TYPE_WATER;
int availableDirections = 0;
for (int i = 0; i < 8; i++) {
if (is_jumping_fountain(type, x + dword_97F000[i].x, y + dword_97F000[i].y, z))
availableDirections |= 1 << i;
}
if (availableDirections == 0)
return;
if (jumpingFountain->flags & FOUNTAIN_FLAG_TERMINATE)
return;
if (jumpingFountain->flags & FOUNTAIN_FLAG_GOTO_EDGE) {
jumping_fountain_goto_edge(jumpingFountain, x, y, z, availableDirections);
return;
}
if (jumpingFountain->flags & FOUNTAIN_FLAG_BOUNCE) {
jumping_fountain_bounce(jumpingFountain, x, y, z, availableDirections);
return;
}
if (jumpingFountain->flags & FOUNTAIN_FLAG_SPLIT) {
jumping_fountain_split(jumpingFountain, x, y, z, availableDirections);
return;
}
jumping_fountain_random(jumpingFountain, x, y, z, availableDirections);
}
static bool is_jumping_fountain(int type, int x, int y, int z)
{
z = z >> 3;
int pathBitFlagMask = type == JUMPING_FOUNTAIN_TYPE_SNOW ?
PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW :
PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER;
rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5);
do {
if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_PATH)
continue;
if (mapElement->base_height != z)
continue;
if (mapElement->properties.path.additions & 0x80)
continue;
int additions = mapElement->properties.path.additions & 0x0F;
if (additions == 0)
continue;
rct_scenery_entry *sceneryEntry = g_pathBitSceneryEntries[additions - 1];
if (!(sceneryEntry->path_bit.var_06 & pathBitFlagMask))
continue;
return true;
} while (!map_element_is_last_for_tile(mapElement++));
return false;
}
/**
*
* rct: 0x00673B6E
*/
static void jumping_fountain_goto_edge(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections)
{
int direction = (jumpingFountain->sprite_direction >> 3) << 1;
if (availableDirections & (1 << direction)) {
jumping_fountain_create_next(jumpingFountain, x, y, z, direction);
return;
}
direction++;
if (availableDirections & (1 << direction)) {
jumping_fountain_create_next(jumpingFountain, x, y, z, direction);
return;
}
uint32 randomIndex = scenario_rand();
if ((randomIndex & 0xFFFF) < 0x3333)
return;
if (jumpingFountain->flags & FOUNTAIN_FLAG_SPLIT) {
jumping_fountain_split(jumpingFountain, x, y, z, availableDirections);
return;
}
direction = randomIndex & 7;
while (!(availableDirections & (1 << direction)))
direction = (direction + 1) & 7;
jumping_fountain_create_next(jumpingFountain, x, y, z, direction);
}
/**
*
* rct: 0x00673B45
*/
static void jumping_fountain_bounce(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections)
{
jumpingFountain->iteration++;
if (jumpingFountain->iteration >= 8)
return;
int direction = ((jumpingFountain->sprite_direction >> 3) ^ 2) << 1;
if (availableDirections & (1 << direction)) {
jumping_fountain_create_next(jumpingFountain, x, y, z, direction);
return;
}
direction++;
if (availableDirections & (1 << direction))
jumping_fountain_create_next(jumpingFountain, x, y, z, direction);
}
/**
*
* rct: 0x00673ACE
*/
static void jumping_fountain_split(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections)
{
if (jumpingFountain->iteration >= 3)
return;
int type = jumpingFountain->misc_identifier == SPRITE_MISC_JUMPING_FOUNTAIN_SNOW ?
JUMPING_FOUNTAIN_TYPE_SNOW :
JUMPING_FOUNTAIN_TYPE_WATER;
int direction = ((jumpingFountain->sprite_direction >> 3) ^ 2) << 1;
availableDirections &= ~(1 << direction);
direction++;
availableDirections &= ~(1 << direction);
for (direction = 0; direction < 8; direction++) {
if (availableDirections & (1 << direction)) {
jumping_fountain_create(
type,
x, y, z,
direction >> 1,
jumpingFountain->flags & ~FOUNTAIN_FLAG_7,
jumpingFountain->iteration + 1
);
}
direction++;
if (availableDirections & (1 << direction)) {
jumping_fountain_create(
type,
x, y, z,
direction >> 1,
jumpingFountain->flags | FOUNTAIN_FLAG_7,
jumpingFountain->iteration + 1
);
}
}
}
/**
*
* rct: 0x00673AAC
*/
static void jumping_fountain_random(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int availableDirections)
{
uint32 randomIndex = scenario_rand();
if ((randomIndex & 0xFFFF) < 0x2000)
return;
int direction = randomIndex & 7;
while (!(availableDirections & (1 << direction)))
direction = (direction + 1) & 7;
jumping_fountain_create_next(jumpingFountain, x, y, z, direction);
}
/**
*
* rct: 0x00673B45
*/
static void jumping_fountain_create_next(rct_jumping_fountain *jumpingFountain, int x, int y, int z, int direction)
{
int flags = jumpingFountain->flags & ~FOUNTAIN_FLAG_7;
if (direction & 1)
flags |= FOUNTAIN_FLAG_7;
int type = jumpingFountain->misc_identifier == SPRITE_MISC_JUMPING_FOUNTAIN_SNOW ?
JUMPING_FOUNTAIN_TYPE_SNOW :
JUMPING_FOUNTAIN_TYPE_WATER;
jumping_fountain_create(type, x, y, z, direction >> 1, flags, jumpingFountain->iteration);
}

37
src/world/fountain.h Normal file
View File

@ -0,0 +1,37 @@
/*****************************************************************************
* Copyright (c) 2014 Ted John
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* This file is part of OpenRCT2.
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#ifndef _WORLD_FOUNTAIN_H_
#define _WORLD_FOUNTAIN_H_
#include "../common.h"
#include "map.h"
#include "sprite.h"
enum {
JUMPING_FOUNTAIN_TYPE_WATER,
JUMPING_FOUNTAIN_TYPE_SNOW
};
void jumping_fountain_begin(int type, int x, int y, rct_map_element *mapElement);
void jumping_fountain_create(int type, int x, int y, int z, int direction, int flags, int iteration);
void jumping_fountain_update(rct_jumping_fountain *jumpingFountain);
#endif

View File

@ -24,6 +24,7 @@
#include "../localisation/date.h"
#include "../localisation/localisation.h"
#include "../management/finance.h"
#include "../scenario.h"
#include "banner.h"
#include "climate.h"
#include "map.h"
@ -48,6 +49,8 @@ int _sub_6A876D_save_y;
static void tiles_init();
static void sub_6A87BB(int x, int y);
static void map_update_grass_length(int x, int y, rct_map_element *mapElement);
static void map_set_grass_length(int x, int y, rct_map_element *mapElement, int length);
void map_element_iterator_begin(map_element_iterator *it)
{
@ -194,7 +197,7 @@ void map_init(int size)
map_element_set_terrain_edge(map_element, TERRAIN_EDGE_ROCK);
}
RCT2_GLOBAL(0x013B0E70, sint16) = 0;
RCT2_GLOBAL(RCT2_ADDRESS_GRASS_SCENERY_TILEPOS, sint16) = 0;
_sub_6A876D_save_x = 0;
_sub_6A876D_save_y = 0;
RCT2_GLOBAL(0x01358830, sint16) = size * 32 - 32;
@ -1117,4 +1120,110 @@ void map_remove_intersecting_walls(int x, int y, int z0, int z1, int direction)
map_element_remove(mapElement);
mapElement -= 1;
} while (!map_element_is_last_for_tile(mapElement++));
}
/**
* Updates grass length, scenery age and jumping fountains.
*
* rct2: 0x006646E1
*/
void map_update_tiles()
{
int ignoreScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR | SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER;
if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & ignoreScreenFlags)
return;
// Update 43 more tiles
for (int j = 0; j < 43; j++) {
int x = 0;
int y = 0;
uint16 interleaved_xy = RCT2_GLOBAL(RCT2_ADDRESS_GRASS_SCENERY_TILEPOS, sint16);
for (int i = 0; i < 8; i++) {
x = (x << 1) | (interleaved_xy & 1);
interleaved_xy >>= 1;
y = (y << 1) | (interleaved_xy & 1);
interleaved_xy >>= 1;
}
rct_map_element *mapElement = map_get_surface_element_at(x, y);
if (mapElement != NULL) {
map_update_grass_length(x * 32, y * 32, mapElement);
scenery_update_tile(x * 32, y * 32);
}
RCT2_GLOBAL(RCT2_ADDRESS_GRASS_SCENERY_TILEPOS, sint16)++;
RCT2_GLOBAL(RCT2_ADDRESS_GRASS_SCENERY_TILEPOS, sint16) &= 0xFFFF;
}
}
/**
*
* rct2: 0x006647A1
*/
static void map_update_grass_length(int x, int y, rct_map_element *mapElement)
{
// Check if tile is grass
if ((mapElement->properties.surface.terrain & 0xE0) && !(mapElement->type & 3))
return;
int grassLength = mapElement->properties.surface.grass_length & 7;
// Check if grass is underwater or outside park
int waterHeight = (mapElement->properties.surface.terrain & 0x1F) * 2;
if (waterHeight > mapElement->base_height || !map_is_location_in_park(x, y)) {
if (grassLength != GRASS_LENGTH_CLEAR_0)
map_set_grass_length(x, y, mapElement, GRASS_LENGTH_CLEAR_0);
return;
}
// Grass can't grow any further
if (grassLength == GRASS_LENGTH_CLUMPS_2)
return;
int z0 = mapElement->base_height;
int z1 = mapElement->base_height + 2;
if (mapElement->properties.surface.slope & 0x10)
z1 += 2;
// Check objects above grass
rct_map_element *mapElementAbove = mapElement;
for (;;) {
if (mapElementAbove->flags & MAP_ELEMENT_FLAG_LAST_TILE) {
// Grow grass
if (mapElement->properties.surface.grass_length < 0xF0) {
mapElement->properties.surface.grass_length += 0x10;
} else {
mapElement->properties.surface.grass_length += 0x10;
mapElement->properties.surface.grass_length ^= 8;
if (mapElement->properties.surface.grass_length & 8) {
// Random growth rate
mapElement->properties.surface.grass_length |= scenario_rand() & 0x70;
} else {
// Increase length
map_set_grass_length(x, y, mapElement, grassLength + 1);
}
}
} else {
mapElementAbove++;
if (map_element_get_type(mapElementAbove) == MAP_ELEMENT_TYPE_FENCE)
continue;
if (z0 >= mapElementAbove->clearance_height)
continue;
if (z1 < mapElementAbove->base_height)
continue;
}
break;
}
}
static void map_set_grass_length(int x, int y, rct_map_element *mapElement, int length)
{
int z0, z1;
mapElement->properties.surface.grass_length = length;
z0 = mapElement->base_height * 8;
z1 = z0 + 16;
sub_6EC847(x, y, z0, z1);
}

View File

@ -39,8 +39,13 @@ typedef struct {
typedef struct {
uint8 type; //4
uint8 sequence; //5
uint8 colour; //6
union{
struct{
uint8 sequence; //5
uint8 colour; //6
};
uint16 maze_entry; // 5
};
uint8 ride_index; //7
} rct_map_element_track_properties;
@ -267,8 +272,6 @@ rct_map_element *map_element_insert(int x, int y, int z, int flags);
int map_can_construct_with_clear_at(int x, int y, int zLow, int zHigh, void *clearFunc, uint8 bl);
int map_can_construct_at(int x, int y, int zLow, int zHigh, uint8 bl);
void fountain_update_all();
void game_command_clear_scenery(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp);
void game_command_change_surface_style(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp);
@ -286,5 +289,6 @@ int map_element_iterator_next(map_element_iterator *it);
void map_element_iterator_restart_for_tile(map_element_iterator *it);
void map_remove_intersecting_walls(int x, int y, int z0, int z1, int direction);
void map_update_tiles();
#endif

View File

@ -21,45 +21,52 @@
#include "../addresses.h"
#include "../ride/ride.h"
#include "../ride/ride_data.h"
#include "../ride/track.h"
#include "map_animation.h"
#include "map.h"
#include "scenery.h"
#include "sprite.h"
rct_animated_object *gAnimatedObjects = (rct_animated_object*)0x013886A0;
typedef bool (*map_animation_invalidate_event_handler)(int x, int y, int baseZ);
static bool map_animation_invalidate_ride_entrance(int x, int y, int baseZ);
static bool map_animation_invalidate_queue_banner(int x, int y, int baseZ);
static bool map_animation_invalidate_small_scenery(int x, int y, int baseZ);
static bool map_animation_invalidate_park_entrance(int x, int y, int baseZ);
static bool map_animation_invalidate_remove(int x, int y, int baseZ);
static bool map_animation_invalidate_banner(int x, int y, int baseZ);
static bool map_animation_invalidate_large_scenery(int x, int y, int baseZ);
static bool sub_6E5B50(int x, int y, int baseZ);
static bool map_animation_invalidate_wall(int x, int y, int baseZ);
static bool map_animation_invalidate(rct_map_animation *obj);
/** rct2: 0x009819DC */
const uint32 _animatedObjectEventHandlers[] = {
(uint32)map_animation_invalidate_ride_entrance, // ride entrance
(uint32)map_animation_invalidate_queue_banner, // queue banner
(uint32)map_animation_invalidate_small_scenery, // small scenery + peep
(uint32)map_animation_invalidate_park_entrance, // park entrance
0x006CE29E, // track
0x006CE2F3, // track
0x006CE39D, // track
0x006CE348, // track
0x006CE3FA, // track
(uint32)map_animation_invalidate_remove, // simply return true
(uint32)map_animation_invalidate_banner, // banner
(uint32)map_animation_invalidate_large_scenery, // large scenery
(uint32)sub_6E5B50, // wall
(uint32)map_animation_invalidate_wall // wall
};
static const map_animation_invalidate_event_handler _animatedObjectEventHandlers[MAP_ANIMATION_TYPE_COUNT];
rct_map_animation *gAnimatedObjects = (rct_map_animation*)0x013886A0;
static bool map_animation_invalidate(rct_animated_object *obj);
/**
*
* rct2: 0x0068AF67
*
* @param type (dh)
* @param x (ax)
* @param y (cx)
* @param z (dl)
*/
void map_animation_create(int type, int x, int y, int z)
{
rct_map_animation *aobj = &gAnimatedObjects[0];
int numAnimatedObjects = RCT2_GLOBAL(0x0138B580, uint16);
for (; numAnimatedObjects > 0; aobj++) {
if (aobj->x != x)
continue;
if (aobj->y != y)
continue;
if (aobj->baseZ != z)
continue;
// Animation already exists
return;
}
// Create new animation
RCT2_GLOBAL(0x0138B580, uint16)++;
aobj->type = type;
aobj->x = x;
aobj->y = y;
aobj->baseZ = z;
}
/**
*
@ -67,7 +74,7 @@ static bool map_animation_invalidate(rct_animated_object *obj);
*/
void map_animation_invalidate_all()
{
rct_animated_object *aobj = &gAnimatedObjects[0];
rct_map_animation *aobj = &gAnimatedObjects[0];
int numAnimatedObjects = RCT2_GLOBAL(0x0138B580, uint16);
while (numAnimatedObjects > 0) {
if (map_animation_invalidate(aobj)) {
@ -86,16 +93,11 @@ void map_animation_invalidate_all()
/**
* @returns true if the animation should be removed.
*/
static bool map_animation_invalidate(rct_animated_object *obj)
static bool map_animation_invalidate(rct_map_animation *obj)
{
uint32 address = _animatedObjectEventHandlers[obj->type];
if (((address >> 20) & 0xFFF) == 0x006) {
int result = RCT2_CALLPROC_X(address, obj->x, 0, obj->y, obj->baseZ, 0, 0, 0);
return (result & 0x100) != 0;
} else {
map_animation_invalidate_event_handler handler = (map_animation_invalidate_event_handler)address;
return handler(obj->x, obj->y, obj->baseZ);
}
assert(obj->type < MAP_ANIMATION_TYPE_COUNT);
return _animatedObjectEventHandlers[obj->type](obj->x, obj->y, obj->baseZ);
}
/**
@ -147,7 +149,7 @@ static bool map_animation_invalidate_queue_banner(int x, int y, int baseZ)
if (!(mapElement->properties.path.type & PATH_FLAG_QUEUE_BANNER))
continue;
int direction = ((mapElement->type >> 6) & 3) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8);
int direction = ((mapElement->type >> 6) + RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)) & 3;
if (direction == MAP_ELEMENT_DIRECTION_NORTH || direction == MAP_ELEMENT_DIRECTION_EAST) {
baseZ = mapElement->base_height * 8;
map_invalidate_tile(x, y, baseZ + 16, baseZ + 30);
@ -184,14 +186,15 @@ static bool map_animation_invalidate_small_scenery(int x, int y, int baseZ)
return false;
}
if (sceneryEntry->small_scenery.flags & 0x2000) {
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_IS_CLOCK) {
// Peep, looking at scenery
if (!(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 0x3FF)) {
int direction = mapElement->type & 3;
int x2 = x - TileDirectionDelta[direction].x;
int y2 = y - TileDirectionDelta[direction].y;
uint16 spriteIdx = RCT2_ADDRESS(0x00F1EF60, uint16)[((x2 & 0x1FE0) << 3) | (y2 >> 5)];
for (; spriteIdx != 0xFFFF; spriteIdx = sprite->unknown.var_02) {
for (; spriteIdx != 0xFFFF; spriteIdx = sprite->unknown.next_in_quadrant) {
sprite = &g_sprite_list[spriteIdx];
if (sprite->unknown.linked_list_type_offset != SPRITE_LINKEDLIST_OFFSET_PEEP)
continue;
@ -204,9 +207,9 @@ static bool map_animation_invalidate_small_scenery(int x, int y, int baseZ)
if (peep->action < PEEP_ACTION_NONE_1)
continue;
peep->action = 0;
peep->action = PEEP_ACTION_CHECK_TIME;
peep->action_frame = 0;
peep->var_70 = 0;
peep->action_sprite_image_offset = 0;
sub_693B58(peep);
RCT2_CALLPROC_X(0x006EC53F, 0, 0, 0, 0, (int)peep, 0, 0);
break;
@ -246,6 +249,137 @@ static bool map_animation_invalidate_park_entrance(int x, int y, int baseZ)
return true;
}
/**
*
* rct2: 0x006CE29E
*/
static bool map_animation_invalidate_track_waterfall(int x, int y, int baseZ)
{
rct_map_element *mapElement;
mapElement = map_get_first_element_at(x >> 5, y >> 5);
do {
if (mapElement->base_height != baseZ)
continue;
if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK)
continue;
if (mapElement->properties.track.type == TRACK_ELEM_WATERFALL) {
int z = mapElement->base_height * 8;
map_invalidate_tile(x, y, z + 14, z + 46);
return false;
}
} while (!map_element_is_last_for_tile(mapElement++));
return true;
}
/**
*
* rct2: 0x006CE2F3
*/
static bool map_animation_invalidate_track_rapids(int x, int y, int baseZ)
{
rct_map_element *mapElement;
mapElement = map_get_first_element_at(x >> 5, y >> 5);
do {
if (mapElement->base_height != baseZ)
continue;
if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK)
continue;
if (mapElement->properties.track.type == TRACK_ELEM_RAPIDS) {
int z = mapElement->base_height * 8;
map_invalidate_tile(x, y, z + 14, z + 18);
return false;
}
} while (!map_element_is_last_for_tile(mapElement++));
return true;
}
/**
*
* rct2: 0x006CE39D
*/
static bool map_animation_invalidate_track_onridephoto(int x, int y, int baseZ)
{
rct_map_element *mapElement;
bool wasInvalidated = false;
mapElement = map_get_first_element_at(x >> 5, y >> 5);
do {
if (mapElement->base_height != baseZ)
continue;
if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK)
continue;
if (mapElement->properties.track.type == TRACK_ELEM_ON_RIDE_PHOTO) {
int z = mapElement->base_height * 8;
map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8);
if (mapElement->properties.track.sequence & 0xF0) {
mapElement->properties.track.sequence -= 0x10;
return false;
} else {
return true;
}
}
} while (!map_element_is_last_for_tile(mapElement++));
return true;
}
/**
*
* rct2: 0x006CE348
*/
static bool map_animation_invalidate_track_whirlpool(int x, int y, int baseZ)
{
rct_map_element *mapElement;
mapElement = map_get_first_element_at(x >> 5, y >> 5);
do {
if (mapElement->base_height != baseZ)
continue;
if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK)
continue;
if (mapElement->properties.track.type == TRACK_ELEM_WHIRLPOOL) {
int z = mapElement->base_height * 8;
map_invalidate_tile(x, y, z + 14, z + 18);
return false;
}
} while (!map_element_is_last_for_tile(mapElement++));
return true;
}
/**
*
* rct2: 0x006CE3FA
*/
static bool map_animation_invalidate_track_spinningtunnel(int x, int y, int baseZ)
{
rct_map_element *mapElement;
mapElement = map_get_first_element_at(x >> 5, y >> 5);
do {
if (mapElement->base_height != baseZ)
continue;
if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK)
continue;
if (mapElement->properties.track.type == TRACK_ELEM_SPINNING_TUNNEL) {
int z = mapElement->base_height * 8;
map_invalidate_tile(x, y, z + 14, z + 32);
return false;
}
} while (!map_element_is_last_for_tile(mapElement++));
return true;
}
/**
*
* rct2: 0x0068DF8F
@ -310,7 +444,7 @@ static bool map_animation_invalidate_large_scenery(int x, int y, int baseZ)
*
* rct2: 0x006E5B50
*/
static bool sub_6E5B50(int x, int y, int baseZ)
static bool map_animation_invalidate_wall_unknown(int x, int y, int baseZ)
{
rct_map_element *mapElement;
rct_scenery_entry *sceneryEntry;
@ -389,4 +523,22 @@ static bool map_animation_invalidate_wall(int x, int y, int baseZ)
} while (!map_element_is_last_for_tile(mapElement++));
return !wasInvalidated;
}
}
/** rct2: 0x009819DC */
static 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_unknown,
map_animation_invalidate_wall
};

View File

@ -32,10 +32,29 @@ typedef struct {
uint8 type;
uint16 x;
uint16 y;
} rct_animated_object;
} rct_map_animation;
extern rct_animated_object *gAnimatedObjects;
enum {
MAP_ANIMATION_TYPE_RIDE_ENTRANCE,
MAP_ANIMATION_TYPE_QUEUE_BANNER,
MAP_ANIMATION_TYPE_SMALL_SCENERY,
MAP_ANIMATION_TYPE_PARK_ENTRANCE,
MAP_ANIMATION_TYPE_TRACK_WATERFALL,
MAP_ANIMATION_TYPE_TRACK_RAPIDS,
MAP_ANIMATION_TYPE_TRACK_ONRIDEPHOTO,
MAP_ANIMATION_TYPE_TRACK_WHIRLPOOL,
MAP_ANIMATION_TYPE_TRACK_SPINNINGTUNNEL,
MAP_ANIMATION_TYPE_REMOVE,
MAP_ANIMATION_TYPE_BANNER,
MAP_ANIMATION_TYPE_LARGE_SCENERY,
MAP_ANIMATION_TYPE_WALL_UNKNOWN,
MAP_ANIMATION_TYPE_WALL,
MAP_ANIMATION_TYPE_COUNT
};
extern rct_map_animation *gAnimatedObjects;
void map_animation_create(int type, int x, int y, int z);
void map_animation_invalidate_all();
#endif

View File

@ -203,15 +203,13 @@ int calculate_park_rating()
// Rides
{
int i;
short _ax, total_ride_intensity = 0, total_ride_excitement = 0, average_intensity, average_excitement;
short total_ride_uptime = 0, total_ride_intensity = 0, total_ride_excitement = 0, average_intensity, average_excitement;
int num_rides, num_exciting_rides = 0;
rct_ride* ride;
//
_ax = 0;
num_rides = 0;
FOR_ALL_RIDES(i, ride) {
_ax += 100 - ride->var_199;
total_ride_uptime += 100 - ride->downtime;
if (ride->excitement != -1){
total_ride_excitement += ride->excitement / 8;
@ -222,7 +220,7 @@ int calculate_park_rating()
}
result -= 200;
if (num_rides > 0)
result += (_ax / num_rides) * 2;
result += (total_ride_uptime / num_rides) * 2;
result -= 100;
@ -276,11 +274,11 @@ money32 calculate_ride_value(rct_ride *ride)
{
if (ride->type == RIDE_TYPE_NULL)
return 0;
if (ride->reliability == 0xFFFF)
if (ride->value == RIDE_VALUE_UNDEFINED)
return 0;
// Reliability * (...)
return (ride->reliability * 10) * (
// Fair value * (...)
return (ride->value * 10) * (
ride->var_124 + ride->var_126 + ride->var_128 + ride->var_12A +
ride->var_12C + ride->var_12E + ride->age + ride->running_cost +
ride->var_134 + ride->var_136 +
@ -369,8 +367,8 @@ static int park_calculate_guest_generation_probability()
suggestedMaxGuests += RCT2_GLOBAL(0x0097D21E + (ride->type * 8), uint8);
// Add ride value
if (ride->reliability != RIDE_RELIABILITY_UNDEFINED) {
int rideValue = ride->reliability - ride->price;
if (ride->value != RIDE_VALUE_UNDEFINED) {
int rideValue = ride->value - ride->price;
if (rideValue > 0)
totalRideValue += rideValue * 2;
}
@ -802,4 +800,4 @@ void game_command_set_park_name(int *eax, int *ebx, int *ecx, int *edx, int *esi
}
*ebx = 0;
}
}

View File

@ -70,4 +70,6 @@ void game_command_set_park_open(int *eax, int *ebx, int *ecx, int *edx, int *esi
void game_command_remove_park_entrance(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp);
void game_command_set_park_name(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp);
void sub_6EC847(int x, int y, int z0, int z1);
#endif

112
src/world/scenery.c Normal file
View File

@ -0,0 +1,112 @@
/*****************************************************************************
* Copyright (c) 2014 Ted John
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* This file is part of OpenRCT2.
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include "../addresses.h"
#include "../game.h"
#include "../common.h"
#include "../localisation/localisation.h"
#include "../scenario.h"
#include "climate.h"
#include "fountain.h"
#include "map.h"
#include "park.h"
#include "scenery.h"
void scenery_increase_age(int x, int y, rct_map_element *mapElement);
void scenery_update_tile(int x, int y)
{
rct_map_element *mapElement;
mapElement = map_get_first_element_at(x >> 5, y >> 5);
do {
if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_SCENERY) {
scenery_update_age(x, y, mapElement);
} else if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_PATH) {
int additions = mapElement->properties.path.additions & 0x0F;
if (additions != 0 && !(mapElement->properties.path.additions & 0x80)) {
rct_scenery_entry *sceneryEntry;
sceneryEntry = g_pathBitSceneryEntries[additions - 1];
if (sceneryEntry->path_bit.var_06 & PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER) {
jumping_fountain_begin(JUMPING_FOUNTAIN_TYPE_WATER, x, y, mapElement);
} else if (sceneryEntry->path_bit.var_06 & PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW) {
jumping_fountain_begin(JUMPING_FOUNTAIN_TYPE_SNOW, x, y, mapElement);
}
}
}
} while (!map_element_is_last_for_tile(mapElement++));
}
/**
*
* rct2: 0x006E33D9
*/
void scenery_update_age(int x, int y, rct_map_element *mapElement)
{
rct_map_element *mapElementAbove;
rct_scenery_entry *sceneryEntry;
sceneryEntry = g_smallSceneryEntries[mapElement->properties.scenery.type];
if (
!(sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_CAN_BE_WATERED) ||
(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_WEATHER, uint8) < WEATHER_RAIN) ||
(mapElement->properties.scenery.age < 5)
) {
scenery_increase_age(x, y, mapElement);
return;
}
// Check map elements above, presumebly to see if map element is blocked from rain
mapElementAbove = mapElement;
while (!(mapElementAbove->flags & 7)) {
mapElementAbove++;
switch (map_element_get_type(mapElementAbove)) {
case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE:
case MAP_ELEMENT_TYPE_ENTRANCE:
case MAP_ELEMENT_TYPE_PATH:
map_invalidate_tile(x, y, mapElementAbove->base_height * 8, mapElementAbove->clearance_height * 8);
scenery_increase_age(x, y, mapElement);
return;
case MAP_ELEMENT_TYPE_SCENERY:
sceneryEntry = g_smallSceneryEntries[mapElementAbove->properties.scenery.type];
if (sceneryEntry->small_scenery.flags & SMALL_SCENERY_FLAG_VOFFSET_CENTRE) {
scenery_increase_age(x, y, mapElement);
return;
}
break;
}
}
// Reset age / water plant
mapElement->properties.scenery.age = 0;
map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8);
}
void scenery_increase_age(int x, int y, rct_map_element *mapElement)
{
if (mapElement->flags & SMALL_SCENERY_FLAG_ANIMATED)
return;
if (mapElement->properties.scenery.age < 255) {
mapElement->properties.scenery.age++;
map_invalidate_tile(x, y, mapElement->base_height * 8, mapElement->clearance_height * 8);
}
}

View File

@ -36,26 +36,26 @@ typedef struct {
} rct_small_scenery_entry;
typedef enum {
SMALL_SCENERY_FLAG1 = (1 << 0), // 0x1
SMALL_SCENERY_FLAG2 = (1 << 1), // 0x2
SMALL_SCENERY_FLAG3 = (1 << 2), // 0x4
SMALL_SCENERY_FLAG4 = (1 << 3), // 0x8
SMALL_SCENERY_FLAG5 = (1 << 4), // 0x10
SMALL_SCENERY_FLAG6 = (1 << 5), // 0x20
SMALL_SCENERY_FLAG7 = (1 << 6), // 0x40
SMALL_SCENERY_FLAG8 = (1 << 7), // 0x80
SMALL_SCENERY_FLAG9 = (1 << 8), // 0x100
SMALL_SCENERY_FLAG10 = (1 << 9), // 0x200
SMALL_SCENERY_HAS_PRIMARY_COLOUR = (1 << 10), // 0x400
SMALL_SCENERY_FLAG12 = (1 << 11), // 0x800
SMALL_SCENERY_FLAG13 = (1 << 12), // 0x1000
SMALL_SCENERY_FLAG14 = (1 << 13), // 0x2000
SMALL_SCENERY_FLAG15 = (1 << 14), // 0x4000
SMALL_SCENERY_FLAG16 = (1 << 15), // 0x8000
SMALL_SCENERY_FLAG17 = (1 << 16), // 0x10000
SMALL_SCENERY_FLAG18 = (1 << 17), // 0x20000
SMALL_SCENERY_FLAG19 = (1 << 18), // 0x40000
SMALL_SCENERY_HAS_SECONDARY_COLOUR = (1 << 19), // 0x80000
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_FLAG4 = (1 << 3), // 0x8
SMALL_SCENERY_FLAG_ANIMATED = (1 << 4), // 0x10
SMALL_SCENERY_FLAG6 = (1 << 5), // 0x20
SMALL_SCENERY_FLAG_CAN_BE_WATERED = (1 << 6), // 0x40
SMALL_SCENERY_FLAG8 = (1 << 7), // 0x80
SMALL_SCENERY_FLAG9 = (1 << 8), // 0x100
SMALL_SCENERY_FLAG10 = (1 << 9), // 0x200
SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR = (1 << 10), // 0x400
SMALL_SCENERY_FLAG12 = (1 << 11), // 0x800
SMALL_SCENERY_FLAG13 = (1 << 12), // 0x1000
SMALL_SCENERY_FLAG_IS_CLOCK = (1 << 13), // 0x2000
SMALL_SCENERY_FLAG15 = (1 << 14), // 0x4000
SMALL_SCENERY_FLAG16 = (1 << 15), // 0x8000
SMALL_SCENERY_FLAG17 = (1 << 16), // 0x10000
SMALL_SCENERY_FLAG18 = (1 << 17), // 0x20000
SMALL_SCENERY_FLAG19 = (1 << 18), // 0x40000
SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR = (1 << 19), // 0x80000
} SMALL_SCENERY_FLAGS;
typedef struct {
@ -130,6 +130,11 @@ typedef struct {
uint32 var_10A;
} rct_scenery_set_entry;
enum {
PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER = 1 << 4,
PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW = 1 << 5
};
#define g_smallSceneryEntries ((rct_scenery_entry**)object_entry_groups[OBJECT_TYPE_SMALL_SCENERY].chunks)
#define g_largeSceneryEntries ((rct_scenery_entry**)object_entry_groups[OBJECT_TYPE_LARGE_SCENERY].chunks)
#define g_wallSceneryEntries ((rct_scenery_entry**)object_entry_groups[OBJECT_TYPE_WALLS].chunks)
@ -138,5 +143,7 @@ typedef struct {
#define g_scenerySetEntries ((rct_scenery_set_entry**)object_entry_groups[OBJECT_TYPE_SCENERY_SETS].chunks)
void init_scenery();
void scenery_update_tile(int x, int y);
void scenery_update_age(int x, int y, rct_map_element *mapElement);
#endif

View File

@ -19,17 +19,34 @@
*****************************************************************************/
#include "../addresses.h"
#include "../audio/audio.h"
#include "../interface/viewport.h"
#include "sprite.h"
#include "../localisation/date.h"
#include "../scenario.h"
#include "fountain.h"
#include "sprite.h"
enum {
DUCK_STATE_FLY_TO_WATER,
DUCK_STATE_SWIM,
DUCK_STATE_DRINK,
DUCK_STATE_DOUBLE_DRINK,
DUCK_STATE_FLY_AWAY
};
rct_sprite* g_sprite_list = RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite);
static void duck_update_fly_to_water(rct_duck *duck);
static void duck_update_swim(rct_duck *duck);
static void duck_update_drink(rct_duck *duck);
static void duck_update_double_drink(rct_duck *duck);
static void duck_update_fly_away(rct_duck *duck);
/**
*
* rct2: 0x006736C7
*/
void create_balloon(int x, int y, int z, int colour)
void create_balloon(int x, int y, int z, int colour, uint8 bl)
{
rct_sprite* sprite = create_sprite(2);
if (sprite != NULL)
@ -37,15 +54,94 @@ void create_balloon(int x, int y, int z, int colour)
sprite->balloon.var_14 = 13;
sprite->balloon.var_09 = 22;
sprite->balloon.var_15 = 11;
sprite->balloon.sprite_identifier = 2;
sprite->balloon.sprite_identifier = SPRITE_IDENTIFIER_MISC;
sprite_move(x, y, z, sprite);
sprite->balloon.var_01 = 7;
sprite->balloon.misc_identifier = SPRITE_MISC_BALLOON;
sprite->balloon.var_26 = 0;
sprite->balloon.colour = colour;
sprite->balloon.var_24 = 0;
sprite->balloon.popped = bl;
}
}
void balloon_pop(rct_balloon *balloon)
{
balloon->popped = 1;
balloon->var_26 = 0;
sound_play_panned(SOUND_BALLOON_POP, 0x8001, balloon->x, balloon->y, balloon->z);
}
/**
*
* rct: 0x0067342C
*/
void balloon_update(rct_balloon *balloon)
{
invalidate_sprite((rct_sprite*)balloon);
if (balloon->popped == 1) {
balloon->var_26 += 256;
if (balloon->var_26 >= 1280)
sprite_remove((rct_sprite*)balloon);
return;
}
int original_var26a = balloon->var_26a;
balloon->var_26a += 85;
if (original_var26a < 255 - 85)
return;
balloon->var_26b++;
sprite_move(balloon->x, balloon->y, balloon->z + 1, (rct_sprite*)balloon);
int maxZ = 1967 - ((balloon->x ^ balloon->y) & 31);
if (balloon->z < maxZ)
return;
balloon_pop(balloon);
}
/**
*
* rct2: 0x006E88ED
*/
void balloon_press(rct_balloon *balloon)
{
if (balloon->popped == 1)
return;
uint32 random = scenario_rand();
if ((balloon->var_0A & 7) || (random & 0xFFFF) < 0x2000) {
balloon_pop(balloon);
return;
}
sprite_move(
balloon->x + ((random & 0x80000000) ? -6 : 6),
balloon->y,
balloon->z,
(rct_sprite*)balloon
);
}
// rct2: 0x009A3B04
static const rct_xy16 duck_move_offset[] = {
{ -1, 0 },
{ 0, 1 },
{ 1, 0 },
{ 0, -1 }
};
// rct2: 0x0097F073
static const uint8 duck_drink_animation[] = {
1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 255
};
// rct2: 0x0097F08C
static const uint8 duck_double_drink_animation[] = {
4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6,
6, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 0, 0, 0, 0, 255
};
/**
*
* rct2: 0x0067440F
@ -53,10 +149,9 @@ void create_balloon(int x, int y, int z, int colour)
void create_duck(int targetX, int targetY)
{
rct_sprite* sprite = create_sprite(2);
if (sprite != NULL)
{
sprite->duck.sprite_identifier = 2;
sprite->duck.var_01 = 8;
if (sprite != NULL) {
sprite->duck.sprite_identifier = SPRITE_IDENTIFIER_MISC;
sprite->duck.misc_identifier = SPRITE_MISC_DUCK;
sprite->duck.var_14 = 9;
sprite->duck.var_09 = 0xC;
sprite->duck.var_15 = 9;
@ -83,12 +178,264 @@ void create_duck(int targetX, int targetY)
}
sprite->duck.sprite_direction = direction << 3;
sprite_move(targetX, targetY, 496, sprite);
sprite->duck.var_48 = 0;
sprite->duck.state = DUCK_STATE_FLY_TO_WATER;
sprite->duck.var_26 = 0;
}
}
/* rct2: 0x006EC473 */
/**
*
* rct: 0x006740E8
*/
void duck_update(rct_duck *duck)
{
switch (duck->state) {
case DUCK_STATE_FLY_TO_WATER:
duck_update_fly_to_water(duck);
break;
case DUCK_STATE_SWIM:
duck_update_swim(duck);
break;
case DUCK_STATE_DRINK:
duck_update_drink(duck);
break;
case DUCK_STATE_DOUBLE_DRINK:
duck_update_double_drink(duck);
break;
case DUCK_STATE_FLY_AWAY:
duck_update_fly_away(duck);
break;
}
}
static void duck_invalidate(rct_duck *duck)
{
sub_6EC60B((rct_sprite*)duck);
}
/**
*
* rct: 0x00674108
*/
static void duck_update_fly_to_water(rct_duck *duck)
{
if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 3)
return;
duck->var_26++;
if (duck->var_26 >= 6)
duck->var_26 = 0;
duck_invalidate(duck);
int manhattanDistance = abs(duck->target_x - duck->x) + abs(duck->target_y - duck->y);
int direction = duck->sprite_direction >> 3;
int x = duck->x + duck_move_offset[direction].x;
int y = duck->y + duck_move_offset[direction].y;
int manhattanDistanceN = abs(duck->target_x - x) + abs(duck->target_y - y);
rct_map_element *mapElement = map_get_surface_element_at(duck->target_x >> 5, duck->target_y >> 5);
int waterHeight = mapElement->properties.surface.terrain & 0x1F;
if (waterHeight == 0) {
duck->state = DUCK_STATE_FLY_AWAY;
duck_update_fly_away(duck);
return;
}
waterHeight <<= 4;
int z = abs(duck->z - waterHeight);
if (manhattanDistanceN <= manhattanDistance) {
if (z > manhattanDistanceN) {
z = duck->z - 2;
if (waterHeight >= duck->z)
z += 4;
duck->var_26 = 1;
} else {
z = duck->z;
}
sprite_move(x, y, z, (rct_sprite*)duck);
duck_invalidate(duck);
} else {
if (z > 4) {
duck->state = DUCK_STATE_FLY_AWAY;
duck_update_fly_away(duck);
} else {
duck->state = DUCK_STATE_SWIM;
duck->var_26 = 0;
duck_update_swim(duck);
}
}
}
/**
*
* rct: 0x00674282
*/
static void duck_update_swim(rct_duck *duck)
{
if ((RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) + duck->var_0A) & 3)
return;
uint32 randomNumber = scenario_rand();
if ((randomNumber & 0xFFFF) < 0x666) {
if (randomNumber & 0x80000000) {
duck->state = DUCK_STATE_DOUBLE_DRINK;
duck->var_26 = -1;
duck_update_double_drink(duck);
} else {
duck->state = DUCK_STATE_DRINK;
duck->var_26 = -1;
duck_update_drink(duck);
}
return;
}
int currentMonth = date_get_month(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONTH_YEAR, uint16));
if (currentMonth >= MONTH_SEPTEMBER && (randomNumber >> 16) < 218) {
duck->state = DUCK_STATE_FLY_AWAY;
duck_update_fly_away(duck);
return;
}
duck_invalidate(duck);
int landZ = map_element_height(duck->x, duck->y);
int waterZ = (landZ >> 16) & 0xFFFF;
landZ &= 0xFFFF;
if (duck->z < landZ || waterZ == 0) {
duck->state = DUCK_STATE_FLY_AWAY;
duck_update_fly_away(duck);
return;
}
duck->z = waterZ;
randomNumber = scenario_rand();
if ((randomNumber & 0xFFFF) <= 0xAAA) {
randomNumber >>= 16;
duck->sprite_direction = randomNumber & 0x18;
}
int direction = duck->sprite_direction >> 3;
int x = duck->x + duck_move_offset[direction].x;
int y = duck->y + duck_move_offset[direction].y;
landZ = map_element_height(x, y);
waterZ = (landZ >> 16) & 0xFFFF;
landZ &= 0xFFFF;
if (duck->z < landZ || duck->z != waterZ)
return;
sprite_move(x, y, waterZ, (rct_sprite*)duck);
duck_invalidate(duck);
}
/**
*
* rct: 0x00674357
*/
static void duck_update_drink(rct_duck *duck)
{
duck->var_26++;
if (duck_drink_animation[duck->var_26] == 255) {
duck->state = DUCK_STATE_SWIM;
duck->var_26 = 0;
duck_update_swim(duck);
} else {
duck_invalidate(duck);
}
}
/**
*
* rct: 0x00674372
*/
static void duck_update_double_drink(rct_duck *duck)
{
duck->var_26++;
if (duck_double_drink_animation[duck->var_26] == 255) {
duck->state = DUCK_STATE_SWIM;
duck->var_26 = 0;
duck_update_swim(duck);
} else {
duck_invalidate(duck);
}
}
/**
*
* rct: 0x0067438D
*/
static void duck_update_fly_away(rct_duck *duck)
{
if (RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) & 3)
return;
duck->var_26++;
if (duck->var_26 >= 6)
duck->var_26 = 0;
duck_invalidate(duck);
int direction = duck->sprite_direction >> 3;
int x = duck->x + (duck_move_offset[direction].x * 2);
int y = duck->y + (duck_move_offset[direction].y * 2);
if (x < 0 || y < 0 || x >= (32 * 256) || y >= (32 * 256)) {
sprite_remove((rct_sprite*)duck);
return;
}
int z = z = min(duck->z + 2, 496);
sprite_move(x, y, z, (rct_sprite*)duck);
duck_invalidate(duck);
}
/**
*
* rct: 0x006E895D
*/
void duck_press(rct_duck *duck)
{
sound_play_panned(SOUND_QUACK, 0x8001, duck->x, duck->y, duck->z);
}
static const rct_xy16 _moneyEffectMoveOffset[] = {
{ 1, -1 },
{ 1, 1 },
{ -1, 1 },
{ -1, -1 }
};
/**
*
* rct: 0x00673232
*/
void money_effect_update(rct_money_effect *moneyEffect)
{
invalidate_sprite((rct_sprite*)moneyEffect);
moneyEffect->wiggle++;
if (moneyEffect->wiggle >= 22)
moneyEffect->wiggle = 0;
moneyEffect->move_delay++;
if (moneyEffect->move_delay < 2)
return;
moneyEffect->move_delay = 0;
int x = moneyEffect->x + _moneyEffectMoveOffset[RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)].x;
int y = moneyEffect->y + _moneyEffectMoveOffset[RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)].y;
int z = moneyEffect->z;
sprite_move(x, y, z, (rct_sprite*)moneyEffect);
moneyEffect->num_movements++;
if (moneyEffect->num_movements < 55)
return;
sprite_remove((rct_sprite*)moneyEffect);
}
/*
*
* rct2: 0x006EC473
*/
void invalidate_sprite(rct_sprite* sprite){
if (sprite->unknown.sprite_left == (sint16)0x8000) return;
@ -130,6 +477,15 @@ void invalidate_sprite(rct_sprite* sprite){
}
}
/**
* Similar to invalidate sprite...
* rct2: 0x006EC60B
*/
void sub_6EC60B(rct_sprite* sprite)
{
RCT2_CALLPROC_X(0x006EC60B, 0, 0, 0, 0, (int)sprite, 0, 0);
}
/*
*
* rct2: 0x0069EB13
@ -198,14 +554,14 @@ void reset_0x69EBE4(){
}
uint16 ax = RCT2_ADDRESS(0xF1EF60,uint16)[edi];
RCT2_ADDRESS(0xF1EF60,uint16)[edi] = spr->unknown.sprite_index;
spr->unknown.var_02 = ax;
spr->unknown.next_in_quadrant = ax;
}
}
}
/*
* rct2: 0x0069EC6B
* bl: if bl & 2 > 0, the sprite ends up in the FLOATING_TEXT linked list.
* bl: if bl & 2 > 0, the sprite ends up in the MISC linked list.
*/
rct_sprite *create_sprite(uint8 bl)
{
@ -220,7 +576,7 @@ rct_sprite *create_sprite(uint8 bl)
return NULL;
}
linkedListTypeOffset = SPRITE_LINKEDLIST_OFFSET_FLOATING_TEXT;
linkedListTypeOffset = SPRITE_LINKEDLIST_OFFSET_MISC;
}
else if (RCT2_GLOBAL(0x13573C8, uint16) <= 0)
{
@ -235,14 +591,14 @@ rct_sprite *create_sprite(uint8 bl)
sprite->y = SPRITE_LOCATION_NULL;
sprite->z = 0;
sprite->name_string_idx = 0;
sprite->var_14 = 0x10;
sprite->var_09 = 0x14;
sprite->var_15 = 0x8;
sprite->pad_0C[0] = 0x0;
sprite->sprite_width = 0x10;
sprite->sprite_height_negative = 0x14;
sprite->sprite_height_positive = 0x8;
sprite->var_0C = 0;
sprite->sprite_left = SPRITE_LOCATION_NULL;
sprite->var_02 = RCT2_GLOBAL(0xF3EF60, uint16);
RCT2_GLOBAL(0xF3EF60, uint16) = sprite->sprite_index;
sprite->next_in_quadrant = RCT2_ADDRESS(0xF1EF60, uint16)[0x10000];
RCT2_ADDRESS(0xF1EF60, uint16)[0x10000] = sprite->sprite_index;
return (rct_sprite*)sprite;
}
@ -299,13 +655,59 @@ void move_sprite_to_list(rct_sprite *sprite, uint8 cl)
++(RCT2_GLOBAL(0x13573C8 + cl, uint16));
}
/**
*
* rct: 0x006731CD
*/
void sprite_misc_update(rct_sprite *sprite)
{
switch (sprite->unknown.misc_identifier) {
case SPRITE_MISC_0:
RCT2_CALLPROC_X(0x00673200, 0, 0, 0, 0, (int)sprite, 0, 0);
break;
case SPRITE_MISC_MONEY_EFFECT:
money_effect_update(&sprite->money_effect);
break;
case SPRITE_MISC_2:
RCT2_CALLPROC_X(0x00673298, 0, 0, 0, 0, (int)sprite, 0, 0);
break;
case SPRITE_MISC_3:
RCT2_CALLPROC_X(0x00673385, 0, 0, 0, 0, (int)sprite, 0, 0);
break;
case SPRITE_MISC_4:
RCT2_CALLPROC_X(0x0067339D, 0, 0, 0, 0, (int)sprite, 0, 0);
break;
case SPRITE_MISC_5:
RCT2_CALLPROC_X(0x006733B4, 0, 0, 0, 0, (int)sprite, 0, 0);
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;
}
}
/**
*
* rct: 0x00672AA4
*/
void texteffect_update_all()
void sprite_misc_update_all()
{
RCT2_CALLPROC_EBPSAFE(0x00672AA4);
rct_sprite *sprite;
uint16 spriteIndex;
spriteIndex = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_MISC, uint16);
while (spriteIndex != SPRITE_INDEX_NULL) {
sprite = &g_sprite_list[spriteIndex];
spriteIndex = sprite->unknown.next;
sprite_misc_update(sprite);
}
}
/**
@ -334,14 +736,14 @@ void sprite_move(int x, int y, int z, rct_sprite* sprite){
uint16* sprite_idx = &RCT2_ADDRESS(0xF1EF60, uint16)[current_position];
rct_sprite* sprite2 = &g_sprite_list[*sprite_idx];
while (sprite != sprite2){
sprite_idx = &sprite2->unknown.var_02;
sprite_idx = &sprite2->unknown.next_in_quadrant;
sprite2 = &g_sprite_list[*sprite_idx];
}
*sprite_idx = sprite->unknown.var_02;
*sprite_idx = sprite->unknown.next_in_quadrant;
int temp_sprite_idx = RCT2_ADDRESS(0xF1EF60, uint16)[new_position];
RCT2_ADDRESS(0xF1EF60, uint16)[new_position] = sprite->unknown.sprite_index;
sprite->unknown.var_02 = temp_sprite_idx;
sprite->unknown.next_in_quadrant = temp_sprite_idx;
}
if (x == 0x8000){
@ -371,24 +773,15 @@ void sprite_move(int x, int y, int z, rct_sprite* sprite){
break;
}
sprite->unknown.sprite_left = new_x - sprite->unknown.var_14;
sprite->unknown.sprite_right = new_x + sprite->unknown.var_14;
sprite->unknown.sprite_top = new_y - sprite->unknown.var_09;
sprite->unknown.sprite_bottom = new_y + sprite->unknown.var_15;
sprite->unknown.sprite_left = new_x - sprite->unknown.sprite_width;
sprite->unknown.sprite_right = new_x + sprite->unknown.sprite_width;
sprite->unknown.sprite_top = new_y - sprite->unknown.sprite_height_negative;
sprite->unknown.sprite_bottom = new_y + sprite->unknown.sprite_height_positive;
sprite->unknown.x = x;
sprite->unknown.y = y;
sprite->unknown.z = z;
}
/**
*
* rct2: 0x006E88D7
*/
void balloon_pop(rct_sprite *sprite)
{
RCT2_CALLPROC_X(0x006E88D7, 0, 0, 0, (int)sprite, 0, 0, 0);
}
/**
*
* rct2: 0x0069EDB6

View File

@ -32,33 +32,36 @@
enum SPRITE_IDENTIFIER{
SPRITE_IDENTIFIER_VEHICLE = 0,
SPRITE_IDENTIFIER_PEEP = 1,
SPRITE_IDENTIFIER_FLOATING_TEXT = 2,
SPRITE_IDENTIFIER_MISC = 2,
SPRITE_IDENTIFIER_LITTER = 3,
};
typedef enum {
SPRITE_LINKEDLIST_OFFSET_VEHICLE = 2,
SPRITE_LINKEDLIST_OFFSET_PEEP = 4,
SPRITE_LINKEDLIST_OFFSET_FLOATING_TEXT = 6,
SPRITE_LINKEDLIST_OFFSET_FLOATING_LITTER = 8,
SPRITE_LINKEDLIST_OFFSET_MISC = 6,
SPRITE_LINKEDLIST_OFFSET_LITTER = 8,
SPRITE_LINKEDLIST_OFFSET_UNKNOWN = 10
} SPRITE_LINKEDLIST_OFFSET;
typedef struct {
uint8 sprite_identifier; // 0x00
uint8 pad_01;
uint16 var_02;
uint8 misc_identifier; // 0x01
uint16 next_in_quadrant; // 0x02
uint16 next; // 0x04
uint16 previous; // 0x06
uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8 var_09;
// Height from center of sprite to bottom
uint8 sprite_height_negative; // 0x09
uint16 sprite_index; // 0x0A
uint8 pad_0C[2];
uint16 var_0C;
sint16 x; // 0x0E
sint16 y; // 0x10
sint16 z; // 0x12
uint8 var_14; // 0x14
uint8 var_15; // 0x15
// Width from center of sprite to edge
uint8 sprite_width; // 0x14
// Height from center of sprite to top
uint8 sprite_height_positive; // 0x15
sint16 sprite_left; // 0x16
sint16 sprite_top; // 0x18
sint16 sprite_right; // 0x1A
@ -73,46 +76,63 @@ typedef struct {
} rct_unk_sprite;
typedef struct {
uint8 sprite_identifier; // 0x00
uint8 sprite_identifier; // 0x00
uint8 var_01; // 0x01
uint16 var_02; // 0x02
uint16 next_in_quadrant; // 0x02
uint16 next; // 0x04
uint16 previous; // 0x06
uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8 pad_09;
uint16 sprite_index; // 0x0A
uint8 pad_0B[0x19];
uint16 pad_0C;
sint16 x; // 0x0E
sint16 y; // 0x10
sint16 z; // 0x12
uint8 pad_14[0x10];
uint32 var_24;
} rct_litter;
typedef struct {
uint8 sprite_identifier; // 0x00
uint8 var_01; // 0x01
uint16 var_02; // 0x02
uint8 sprite_identifier; // 0x00
uint8 misc_identifier; // 0x01
uint16 next_in_quadrant; // 0x02
uint16 next; // 0x04
uint16 previous; // 0x06
uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8 var_09; // 0x09
uint8 pad_0A[0xA];
uint16 var_0A;
uint8 pad_0C[0x2];
sint16 x; // 0x0E
sint16 y; // 0x10
sint16 z; // 0x12
uint8 var_14; // 0x14
uint8 var_15; // 0x15
uint8 pad_16[0xE];
uint8 var_24; // 0x24
uint8 pad_25;
uint16 var_26; // 0x26
uint16 popped; // 0x24
union {
uint16 var_26;
struct {
uint8 var_26a;
uint8 var_26b;
};
};
uint8 pad_28[4];
uint8 colour; // 0x2C
} rct_balloon;
typedef struct {
uint8 sprite_identifier; // 0x00
uint8 var_01; // 0x01
uint16 var_02; // 0x02
uint8 sprite_identifier; // 0x00
uint8 misc_identifier; // 0x01
uint16 next_in_quadrant; // 0x02
uint16 next; // 0x04
uint16 previous; // 0x06
uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8 var_09; // 0x09
uint8 pad_0A[0xA];
uint16 var_0A;
uint8 pad_0C[0x2];
sint16 x; // 0x0E
sint16 y; // 0x10
sint16 z; // 0x12
uint8 var_14; // 0x14
uint8 var_15; // 0x15
uint8 pad_16[0x8];
@ -123,9 +143,61 @@ typedef struct {
sint16 target_x; // 0x30
sint16 target_y; // 0x32
uint8 pad_34[0x14];
uint8 var_48; // 0x48
uint8 state; // 0x48
} rct_duck;
typedef struct {
uint8 sprite_identifier; // 0x00
uint8 misc_identifier; // 0x01
uint16 next_in_quadrant; // 0x02
uint16 next; // 0x04
uint16 previous; // 0x06
uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8 var_09;
uint8 pad_0A[0x4];
sint16 x; // 0x0E
sint16 y; // 0x10
sint16 z; // 0x12
uint8 var_14;
uint8 var_15;
uint8 pad_16[0x8];
uint8 sprite_direction; // 0x1E
uint8 pad_1F[0x7];
union {
uint16 var_26;
struct {
uint8 var_26a;
uint8 var_26b;
};
};
uint8 pad_28[0x6];
uint8 var_2E;
uint8 flags;
sint16 target_x; // 0x30
sint16 target_y; // 0x32
uint8 pad_34[0x12];
uint16 iteration; // 0x46
} rct_jumping_fountain;
typedef struct {
uint8 sprite_identifier; // 0x00
uint8 misc_identifier; // 0x01
uint16 var_02; // 0x02
uint16 next; // 0x04
uint16 previous; // 0x06
uint8 linked_list_type_offset; // 0x08 Valid values are SPRITE_LINKEDLIST_OFFSET_...
uint8 var_09;
uint8 pad_0A[0x4];
sint16 x; // 0x0E
sint16 y; // 0x10
sint16 z; // 0x12
uint8 pad_14[0x10];
uint16 move_delay; // 0x24
uint16 num_movements; // 0x26
uint8 pad_28[0x1E];
uint16 wiggle; // 0x46
} rct_money_effect;
/**
* Sprite structure.
* size: 0x0100
@ -138,21 +210,38 @@ typedef union {
rct_vehicle vehicle;
rct_balloon balloon;
rct_duck duck;
rct_jumping_fountain jumping_fountain;
rct_money_effect money_effect;
} rct_sprite;
enum {
SPRITE_MISC_0,
SPRITE_MISC_MONEY_EFFECT,
SPRITE_MISC_2, // (related to vehicle crash, probably crash particles)
SPRITE_MISC_3, // (related to vehicle crash, probably crash particles)
SPRITE_MISC_4, // (related to vehicle crash, probably crash particles)
SPRITE_MISC_5, // (related to vehicle crash, probably crash particles)
SPRITE_MISC_JUMPING_FOUNTAIN_WATER,
SPRITE_MISC_BALLOON,
SPRITE_MISC_DUCK,
SPRITE_MISC_JUMPING_FOUNTAIN_SNOW
};
// rct2: 0x010E63BC
extern rct_sprite* g_sprite_list;
void create_balloon(int x, int y, int z, int colour);
void create_balloon(int x, int y, int z, int colour, uint8 bl);
void balloon_press(rct_balloon *balloon);
void create_duck(int targetX, int targetY);
void duck_press(rct_duck *duck);
rct_sprite *create_sprite(uint8 bl);
void reset_sprite_list();
void reset_0x69EBE4();
void move_sprite_to_list(rct_sprite *sprite, uint8 cl);
void texteffect_update_all();
void sprite_misc_update_all();
void sprite_move(int x, int y, int z, rct_sprite* sprite);
void balloon_pop(rct_sprite *sprite);
void invalidate_sprite(rct_sprite *sprite);
void sub_6EC60B(rct_sprite* sprite);
void sprite_remove(rct_sprite *sprite);
#endif