From debafcf051b8a554dfe2bb666f2c998d27a4564b Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Thu, 29 Jan 2015 00:16:34 +0000 Subject: [PATCH 01/10] code set ride status, not yet fixed and tested --- src/game.c | 4 +- src/game.h | 2 +- src/localisation/string_ids.h | 9 + src/ride/ride.c | 412 ++++++++++++++++++++++++++++++++++ src/ride/ride.h | 4 +- src/windows/ride.c | 2 +- src/windows/ride_list.c | 4 +- 7 files changed, 430 insertions(+), 7 deletions(-) diff --git a/src/game.c b/src/game.c index 286081b574..1cd3f63fb9 100644 --- a/src/game.c +++ b/src/game.c @@ -867,7 +867,7 @@ static uint32 game_do_command_table[58] = { (uint32)game_load_or_quit, 0x006B3F0F, 0x006B49D9, - 0x006B4EA6, + 0, 0x006B52D4, 0, // 10 0x006B5559, @@ -930,7 +930,7 @@ static GAME_COMMAND_POINTER* new_game_command_table[58] = { game_command_emptysub, game_command_emptysub, game_command_emptysub, - game_command_emptysub, + game_command_set_ride_status, game_command_emptysub, game_command_set_ride_name, // 10 game_command_emptysub, diff --git a/src/game.h b/src/game.h index cdde118d15..ab9be1a8bf 100644 --- a/src/game.h +++ b/src/game.h @@ -30,7 +30,7 @@ enum GAME_COMMAND { GAME_COMMAND_LOAD_OR_QUIT, // 5 GAME_COMMAND_6, GAME_COMMAND_7, - GAME_COMMAND_SET_RIDE_OPEN, // 8 + GAME_COMMAND_SET_RIDE_STATUS, // 8 GAME_COMMAND_9, GAME_COMMAND_SET_RIDE_NAME, GAME_COMMAND_11, diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index 16a169154f..10b6da440e 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -167,6 +167,10 @@ enum { STR_OVERALL_VIEW = 996, STR_VIEW_SELECTION = 997, + STR_REQUIRES_A_STATION_PLATFORM = 999, + STR_TRACK_IS_NOT_A_COMPLETE_CIRCUIT = 1000, + STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN = 1001, + STR_CANT_OPEN = 1002, STR_CANT_TEST = 1003, STR_CANT_CLOSE = 1004, @@ -438,6 +442,9 @@ enum { STR_GUESTS = 1463, STR_STAFF = 1468, + + STR_RIDE_MUST_START_AND_END_WITH_STATIONS = 1469, + STR_STATION_NOT_LONG_ENOUGH = 1470, STR_SPEED = 1471, STR_SPEED_TIP = 1472, @@ -503,6 +510,8 @@ enum { STR_RACE_WON_BY_GUEST = 1739, STR_RACE_WON_BY = 1740, + STR_NOT_YET_CONSTRUCTED = 1741, + STR_MAX_PEOPLE_ON_RIDE = 1742, STR_MAX_PEOPLE_ON_RIDE_TIP = 1743, diff --git a/src/ride/ride.c b/src/ride/ride.c index a3ec11151f..1f7180b4f4 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -2689,6 +2689,418 @@ void ride_music_update_final() #pragma endregion +/** + * + * rct2: 0x006B4CC1 + */ +int ride_mode_check_valid_stations(rct_ride *ride) +{ + return RCT2_CALLPROC_X(0x006B4CC1, 0, 0, 0, 0, (int)ride, 0, 0) & 0x100; +} + +/** + * + * rct2: 0x006B5872 + */ +int ride_check_for_entrance_exit(int rideIndex) +{ + return RCT2_CALLPROC_X(0x006B4CC1, 0, 0, 0, rideIndex, 0, 0, 0) & 0x100; +} + +/** + * + * rct2: 0x006B5952 + */ +void sub_6B5952(int rideIndex) +{ + RCT2_CALLPROC_X(0x006B4CC1, 0, 0, 0, rideIndex, 0, 0, 0); +} + +/** + * + * rct2: 0x006D3319 + */ +int sub_6D3319(rct_map_element *mapElement) +{ + return RCT2_CALLPROC_X(0x006D3319, 0, 0, 0, 0, (int)mapElement, 0, 0) & 0x100; +} + +/** + * + * rct2: 0x006CB149 + */ +int sub_6CB149(rct_map_element *mapElement) +{ + return RCT2_CALLPROC_X(0x006CB149, 0, 0, 0, 0, (int)mapElement, 0, 0) & 0x100; +} + +/** + * + * rct2: 0x006CB1D3 + */ +int sub_6CB1D3(rct_map_element *mapElement) +{ + return RCT2_CALLPROC_X(0x006CB1D3, 0, 0, 0, 0, (int)mapElement, 0, 0) & 0x100; +} + +/** + * + * rct2: 0x006CB25D + */ +int sub_6CB25D(rct_map_element *mapElement) +{ + return RCT2_CALLPROC_X(0x006CB25D, 0, 0, 0, 0, (int)mapElement, 0, 0) & 0x100; +} + +/** + * + * rct2: 0x006CB2DA + */ +int sub_6CB2DA(rct_map_element *mapElement) +{ + return RCT2_CALLPROC_X(0x006CB2DA, 0, 0, 0, 0, (int)mapElement, 0, 0) & 0x100; +} + +/** + * + * rct2: 0x006B4D26 + */ +void sub_6B4D26(int rideIndex) +{ + RCT2_CALLPROC_X(0x006CB2DA, 0, 0, 0, rideIndex, 0, 0, 0); +} + +/** + * + * rct2: 0x006DD84C + */ +int sub_6DD84C(rct_ride *ride) +{ + return RCT2_CALLPROC_X(0x006DD84C, 0, 0, 0, 0, (int)ride, 0, 0) & 0x100; +} + +/** + * + * rct2: 0x006DF4D4 + */ +int sub_6DF4D4(rct_ride *ride) +{ + return RCT2_CALLPROC_X(0x006DF4D4, 0, 0, 0, 0, (int)ride, 0, 0) & 0x100; +} + +/** + * + * rct2: 0x006B51C0 + */ +void loc_6B51C0(int rideIndex) +{ + int i, x, y, z; + rct_ride *ride; + rct_map_element *mapElement; + rct_window *w; + + ride = GET_RIDE(rideIndex); + + if (RCT2_GLOBAL(0x0141F568, uint8) != RCT2_GLOBAL(0x013CA740, uint8)) + return; + + w = window_get_main(); + if (w == NULL) + return; + + uint8 entranceOrExit = -1; + for (i = 0; i < 4; i++) { + if (ride->station_starts[i] == 0xFFFF) + continue; + + if (ride->entrances[i] == 0xFFFF) { + entranceOrExit = 0; + break; + } + + if (ride->exits[i] == 0xFFFF) { + entranceOrExit = 1; + break; + } + } + + if (entranceOrExit == -1) + return; + + if (ride->type != RIDE_TYPE_MAZE) { + x = (ride->station_starts[i] >> 8) * 32; + y = (ride->station_starts[i] & 0xFF) * 32; + z = ride->station_heights[i] * 8; + window_scroll_to_location(w, x, y, z); + + mapElement = sub_6CAF80(rideIndex, &x, &y); + ride_find_track_gap(mapElement, &x, &y); + w = window_get_main(); + rct_viewport *viewport = w->viewport; + ride_modify(mapElement, x, y); + + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL) + window_event_mouse_up_call(w, 29 + entranceOrExit); + } +} + +/** + * + * rct2: 0x006B528A + */ +void loc_6B528A(rct_map_element *mapElement, int x, int y, int z) +{ + rct_ride *ride; + rct_window *w; + + ride = GET_RIDE(mapElement->properties.track.ride_index); + + if (RCT2_GLOBAL(0x0141F568, uint8) != RCT2_GLOBAL(0x013CA740, uint8)) + return; + + w = window_get_main(); + if (w == NULL) + return; + + window_scroll_to_location(w, x, y, z); + ride_modify(mapElement, x, y); +} + +/** + * + * rct2: 0x006B4F6B + */ +rct_map_element *loc_6B4F6B(int rideIndex, int x, int y) +{ + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x, y); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) + continue; + + uint32 unk = mapElement->properties.track.type << 4; + if (RCT2_GLOBAL(0x00F43484, uint32) & 0x80000) { + if (!(RCT2_ADDRESS(0x0099CA64, uint8)[unk] & 0x10)) + continue; + } else { + if (!(RCT2_ADDRESS(0x0099BA64, uint8)[unk] & 0x10)) + continue; + } + + if (mapElement->properties.track.ride_index == rideIndex) + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + + return NULL; +} + +/** + * + * rct2: 0x006B4EEA + */ +int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) +{ + int i, x, y, z, stationIndex; + rct_ride *ride; + rct_map_element *mapElement, *mapElement2; + + ride = GET_RIDE(rideIndex); + + window_close_by_class(WC_RIDE_CONSTRUCTION); + if (!ride_mode_check_valid_stations(ride)) + return 0; + + if (!ride_check_for_entrance_exit(rideIndex)) { + loc_6B51C0(rideIndex); + return 0; + } + + if (goingToBeOpen && isApplying) { + sub_6B5952(rideIndex); + ride->lifecycle_flags |= RIDE_LIFECYCLE_EVER_BEEN_OPENED; + } + + stationIndex = -1; + for (i = 0; i < 4; i++) { + if (ride->station_starts[i] != 0xFFFF) { + stationIndex = i; + break; + } + } + + if (stationIndex == -1) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_NOT_YET_CONSTRUCTED; + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x8000) + return 0; + + if (ride->type == RIDE_TYPE_MAZE) + return 0; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_REQUIRES_A_STATION_PLATFORM; + return 0; + } + + mapElement = loc_6B4F6B(rideIndex, ride->station_starts[i] >> 8, ride->station_starts[i] & 0xFF); + if (mapElement == NULL) + return 0; + + z = ride->station_heights[i] * 8; + if ( + ride->type == RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER || + ride->mode == RIDE_MODE_RACE || + ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT || + ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || + ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED + ) { + mapElement2 = ride_find_track_gap(mapElement, &x, &y); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint32) = STR_TRACK_IS_NOT_A_COMPLETE_CIRCUIT; + if (mapElement2 != NULL) { + loc_6B528A(mapElement, x, y, z); + return 0; + } + } + + if ( + ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || + ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED + ) { + if (sub_6D3319(mapElement)) { + loc_6B528A(mapElement, x, y, z); + return 0; + } + } + + if (ride->subtype != 255) { + rct_ride_type *rideType = GET_RIDE_ENTRY(ride->subtype); + if (rideType->var_008 & 2) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint32) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; + if (sub_6CB149(mapElement)) { + loc_6B528A(mapElement, x, y, z); + return 0; + } + } + if (rideType->var_008 & 4) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint32) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; + if (sub_6CB1D3(mapElement)) { + loc_6B528A(mapElement, x, y, z); + return 0; + } + } + } + + if (ride->mode == RIDE_MODE_STATION_TO_STATION) { + mapElement2 = ride_find_track_gap(mapElement, &x, &y); + if (mapElement2 == NULL) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint32) = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; + return 0; + } + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint32) = STR_STATION_NOT_LONG_ENOUGH; + if (sub_6CB25D(mapElement)) { + loc_6B528A(mapElement, x, y, z); + return 0; + } + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint32) = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; + if (sub_6CB2DA(mapElement)) { + loc_6B528A(mapElement, x, y, z); + return 0; + } + } + + if (isApplying) + sub_6B4D26(rideIndex); + + if ( + !(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x2000) && + (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) + ) { + if (sub_6DD84C(ride)) + return 0; + } + + if ( + (RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint32) & 0x400) && + (ride->lifecycle_flags & RIDE_LIFECYCLE_16) && + (ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT) + ) { + if (sub_6DF4D4(ride)) + return 0; + } + + return 1; +} + +void ride_set_status(int rideIndex, int status) +{ + game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, rideIndex | (status << 8), GAME_COMMAND_SET_RIDE_STATUS, 0, 0); +} + +/** + * + * rct2: 0x006B4EA6 + */ +void game_command_set_ride_status(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp) +{ + int rideIndex, targetStatus; + rct_ride *ride; + + rideIndex = *edx & 0xFF; + targetStatus = (*edx >> 8) & 0xFF; + + RCT2_GLOBAL(0x0141F56C, uint8) = 4; + + ride = GET_RIDE(rideIndex); + RCT2_GLOBAL(0x00F43484, uint32) = RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32); + + switch (targetStatus) { + case RIDE_STATUS_CLOSED: + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + *ebx = 0; + return; + } + + if (ride->status == targetStatus) { + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) { + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; + ride_clear_for_construction(rideIndex); + ride_remove_peeps(rideIndex); + } + } + + 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); + window_invalidate_by_number(WC_RIDE, rideIndex); + *ebx = 0; + return; + case RIDE_STATUS_TESTING: + case RIDE_STATUS_OPEN: + if (ride->status == targetStatus) { + *ebx = 0; + return; + } + + if (!ride_is_valid_for_open(rideIndex, targetStatus == RIDE_STATUS_OPEN, *ebx & GAME_COMMAND_FLAG_APPLY)) { + *ebx = MONEY32_UNDEFINED; + return; + } + + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + ride->race_winner = 0xFFFF; + ride->status = targetStatus; + ride_get_measurement(rideIndex, NULL); + ride->var_14D |= (1 << 2) | (1 << 3); + window_invalidate_by_number(WC_RIDE, rideIndex); + } + *ebx = 0; + return; + } +} + void ride_set_name(int rideIndex, const char *name) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE, uint16) = STR_CANT_RENAME_RIDE_ATTRACTION; diff --git a/src/ride/ride.h b/src/ride/ride.h index 08daaf3599..8044b20dee 100644 --- a/src/ride/ride.h +++ b/src/ride/ride.h @@ -293,7 +293,7 @@ enum { RIDE_LIFECYCLE_MUSIC = 1 << 13, RIDE_LIFECYCLE_INDESTRUCTIBLE = 1 << 14, RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK = 1 << 15, - + RIDE_LIFECYCLE_16 = 1 << 16, RIDE_LIFECYCLE_CABLE_LIFT = 1 << 17, RIDE_LIFECYCLE_18 = 1 << 18, RIDE_LIFECYCLE_19 = 1 << 19 @@ -638,6 +638,8 @@ 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(); +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); void game_command_set_ride_name(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); diff --git a/src/windows/ride.c b/src/windows/ride.c index c5fd0f9447..563ba03d08 100644 --- a/src/windows/ride.c +++ b/src/windows/ride.c @@ -1834,7 +1834,7 @@ static void window_ride_main_dropdown() RCT2_GLOBAL(0x013CE952 + 6, uint16) = ride->overall_view; RCT2_GLOBAL(0x013CE952 + 8, uint32) = ride->name_arguments; - game_do_command(0, 1, 0, w->number | (status << 8), GAME_COMMAND_SET_RIDE_OPEN, 0, 0); + ride_set_status(w->number, status); break; } } diff --git a/src/windows/ride_list.c b/src/windows/ride_list.c index 41fd4aaaec..17ea8b21ce 100644 --- a/src/windows/ride_list.c +++ b/src/windows/ride_list.c @@ -707,7 +707,7 @@ static void window_ride_list_close_all(rct_window *w) RCT2_GLOBAL(0x013CE952 + 6, uint16) = w->scrolls[0].v_top; RCT2_GLOBAL(0x013CE952 + 8, uint32) = w->scrolls[0].v_bottom; - game_do_command(0, 1, 0, i, GAME_COMMAND_SET_RIDE_OPEN, 0, 0); + ride_set_status(i, RIDE_STATUS_CLOSED); } } @@ -724,6 +724,6 @@ static void window_ride_list_open_all(rct_window *w) RCT2_GLOBAL(0x013CE952 + 6, uint16) = w->scrolls[0].v_top; RCT2_GLOBAL(0x013CE952 + 8, uint32) = w->scrolls[0].v_bottom; - game_do_command(0, 1, 0, (1 << 8) | i, GAME_COMMAND_SET_RIDE_OPEN, 0, 0); + ride_set_status(i, RIDE_STATUS_OPEN); } } From 0e6a90c5deb6ec08cd65805750d671eaebb69db4 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Thu, 29 Jan 2015 21:10:34 +0000 Subject: [PATCH 02/10] further testing and progress on set_ride_status --- src/ride/ride.c | 128 ++++++++++++++++++++++++++++------------ src/ride/ride.h | 1 + src/ride/ride_ratings.c | 19 +----- src/ride/track.c | 42 ++++++++++++- src/ride/track.h | 5 +- 5 files changed, 139 insertions(+), 56 deletions(-) diff --git a/src/ride/ride.c b/src/ride/ride.c index dc44dabbdf..287e0e8a76 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -37,6 +37,7 @@ #include "../world/sprite.h" #include "ride.h" #include "ride_data.h" +#include "track.h" #include "station.h" #pragma region Ride classification table @@ -308,6 +309,28 @@ rct_map_element *sub_6CAF80(int rideIndex, int *outX, int *outY) /** * + * rct2: 0x006C60C2 + */ +rct_map_element *track_get_next(rct_map_element *mapElement, int *x, int *y, int *z) +{ + int eax, ebx, ecx, edx, esi, edi, ebp, result; + + eax = *x; + ecx = *y; + esi = (int)mapElement; + result = RCT2_CALLFUNC_X(0x006C60C2, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + *x = *((uint16*)&eax); + *y = *((uint16*)&ecx); + *z = *((uint8*)&edx); + mapElement = (rct_map_element*)esi; + + if (result & 0x100) return NULL; + return mapElement; +} + +/** + * + * Make sure to pass in the x and y of the start track element too. * rct2: 0x006CB02F * ax result x * bx result y @@ -315,19 +338,44 @@ rct_map_element *sub_6CAF80(int rideIndex, int *outX, int *outY) */ rct_map_element *ride_find_track_gap(rct_map_element *startTrackElement, int *outX, int *outY) { - int eax, ebx, ecx, edx, esi, edi, ebp; - esi = (int)startTrackElement; - eax = *outX; - ebx = 0; - ecx = *outY; - edx = 0; - edi = 0; - ebp = 0; - RCT2_CALLFUNC_X(0x006CB02F, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + int rideIndex, x, y, z; + rct_map_element *trackElement, *nextTrackElement, *loopTrackElement; + rct_ride *ride; + rct_window *w; - if (outX != NULL) *outX = eax & 0xFFFF; - if (outY != NULL) *outY = ecx & 0xFFFF; - return (rct_map_element*)esi; + x = *outX; + y = *outY; + rideIndex = startTrackElement->properties.track.ride_index; + ride = GET_RIDE(rideIndex); + + if (ride->type == RIDE_TYPE_MAZE) + return NULL; + + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL && RCT2_GLOBAL(0x00F440A6, uint8) != 0 && RCT2_GLOBAL(0x00F440A7, uint8) == rideIndex) + sub_6C9627(); + + trackElement = startTrackElement; + loopTrackElement = NULL; + while (1) { + nextTrackElement = track_get_next(trackElement, &x, &y, &z); + if (nextTrackElement == NULL) + return trackElement; + + if (!track_is_connected_by_shape(trackElement, nextTrackElement)) { + *outX = x; + *outY = y; + return nextTrackElement; + } + + trackElement = nextTrackElement; + if (loopTrackElement == NULL) + loopTrackElement = trackElement; + else if (trackElement == loopTrackElement) + break; + } + + return NULL; } /** @@ -858,6 +906,7 @@ int ride_modify_maze(rct_map_element *mapElement, int x, int y) int ride_modify(rct_map_element *mapElement, int x, int y) { int rideIndex, z, direction, type; + rct_map_element *endOfTrackElement; rct_ride *ride; rct_window *constructionWindow; @@ -895,7 +944,9 @@ int ride_modify(rct_map_element *mapElement, int x, int y) if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS,uint64)[ride->type] & 0x100) { int outX = x, outY = y; - mapElement = ride_find_track_gap(mapElement, &outX, &outY); + endOfTrackElement = ride_find_track_gap(mapElement, &outX, &outY); + if (endOfTrackElement != NULL) + mapElement = endOfTrackElement; } z = mapElement->base_height * 8; @@ -2696,7 +2747,7 @@ void ride_music_update_final() */ int ride_mode_check_valid_stations(rct_ride *ride) { - return RCT2_CALLPROC_X(0x006B4CC1, 0, 0, 0, 0, (int)ride, 0, 0) & 0x100; + return (RCT2_CALLPROC_X(0x006B4CC1, 0, 0, 0, 0, (int)ride, 0, 0) & 0x100) == 0; } /** @@ -2705,7 +2756,7 @@ int ride_mode_check_valid_stations(rct_ride *ride) */ int ride_check_for_entrance_exit(int rideIndex) { - return RCT2_CALLPROC_X(0x006B4CC1, 0, 0, 0, rideIndex, 0, 0, 0) & 0x100; + return (RCT2_CALLPROC_X(0x006B5872, 0, 0, 0, rideIndex, 0, 0, 0) & 0x100) == 0; } /** @@ -2835,11 +2886,9 @@ void loc_6B51C0(int rideIndex) window_scroll_to_location(w, x, y, z); mapElement = sub_6CAF80(rideIndex, &x, &y); - ride_find_track_gap(mapElement, &x, &y); - w = window_get_main(); - rct_viewport *viewport = w->viewport; + mapElement = ride_find_track_gap(mapElement, &x, &y); ride_modify(mapElement, x, y); - + w = window_find_by_class(WC_RIDE_CONSTRUCTION); if (w != NULL) window_event_mouse_up_call(w, 29 + entranceOrExit); @@ -2876,7 +2925,7 @@ rct_map_element *loc_6B4F6B(int rideIndex, int x, int y) { rct_map_element *mapElement; - mapElement = map_get_first_element_at(x, y); + mapElement = map_get_first_element_at(x / 32, y / 32); do { if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_TRACK) continue; @@ -2914,11 +2963,13 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) return 0; if (!ride_check_for_entrance_exit(rideIndex)) { + // TODO check if this is correct loc_6B51C0(rideIndex); return 0; } if (goingToBeOpen && isApplying) { + // TODO check if this is correct sub_6B5952(rideIndex); ride->lifecycle_flags |= RIDE_LIFECYCLE_EVER_BEEN_OPENED; } @@ -2932,6 +2983,7 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) } if (stationIndex == -1) { + // TODO check if this is correct RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_NOT_YET_CONSTRUCTED; if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x8000) return 0; @@ -2943,11 +2995,14 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) return 0; } - mapElement = loc_6B4F6B(rideIndex, ride->station_starts[i] >> 8, ride->station_starts[i] & 0xFF); + x = (ride->station_starts[i] & 0xFF) * 32; + y = (ride->station_starts[i] >> 8) * 32; + z = ride->station_heights[i] * 8; + + mapElement = loc_6B4F6B(rideIndex, x, y); if (mapElement == NULL) return 0; - z = ride->station_heights[i] * 8; if ( ride->type == RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER || ride->mode == RIDE_MODE_RACE || @@ -2963,6 +3018,8 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) } } + // TODO check if the following is correct + if ( ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED @@ -3059,23 +3116,20 @@ void game_command_set_ride_status(int *eax, int *ebx, int *ecx, int *edx, int *e switch (targetStatus) { case RIDE_STATUS_CLOSED: if (*ebx & GAME_COMMAND_FLAG_APPLY) { - *ebx = 0; - return; - } - - if (ride->status == targetStatus) { - if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) { - ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; - ride_clear_for_construction(rideIndex); - ride_remove_peeps(rideIndex); + if (ride->status == targetStatus) { + if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_BROKEN_DOWN)) { + ride->lifecycle_flags &= ~RIDE_LIFECYCLE_CRASHED; + ride_clear_for_construction(rideIndex); + ride_remove_peeps(rideIndex); + } } + + 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); + window_invalidate_by_number(WC_RIDE, rideIndex); } - - 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); - window_invalidate_by_number(WC_RIDE, rideIndex); *ebx = 0; return; case RIDE_STATUS_TESTING: diff --git a/src/ride/ride.h b/src/ride/ride.h index 8044b20dee..a7cbb2d5ea 100644 --- a/src/ride/ride.h +++ b/src/ride/ride.h @@ -614,6 +614,7 @@ void ride_update_all(); void ride_check_all_reachable(); void ride_update_popularity(rct_ride* ride, uint8 pop_amount); rct_map_element *sub_6CAF80(int rideIndex, int *outX, int *outY); +rct_map_element *track_get_next(rct_map_element *mapElement, int *x, int *y, int *z); rct_map_element *ride_find_track_gap(rct_map_element *startTrackElement, int *outX, int *outY); void ride_construct_new(ride_list_item listItem); void ride_construct(int rideIndex); diff --git a/src/ride/ride_ratings.c b/src/ride/ride_ratings.c index 570bfd1dad..233c5cc948 100644 --- a/src/ride/ride_ratings.c +++ b/src/ride/ride_ratings.c @@ -65,20 +65,6 @@ static int sub_6C6402(rct_map_element *mapElement, int *x, int *y, int *z) return 1; } -static int sub_6C60C2(rct_map_element *mapElement, int *x, int *y, int *z) -{ - int eax, ebx, ecx, edx, esi, edi, ebp; - - eax = *x; - ecx = *y; - esi = (int)mapElement; - RCT2_CALLFUNC_X(0x006C6402, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - *x = *((uint16*)&eax); - *y = *((uint16*)&ecx); - *z = *((uint8*)&edx); - return 1; -} - /** * * rct2: 0x006B5A2A @@ -217,8 +203,7 @@ static void loc_6B5BB2() */ static void ride_ratings_update_state_2() { - // sub_6C6402 returns a carry, CALLFUNC doesn't support this - // so have to wait for sub_6C60C2 to be decompiled + // TODO test this function RCT2_CALLPROC_EBPSAFE(0x006B5C66); return; @@ -257,7 +242,7 @@ static void ride_ratings_update_state_2() x = RCT2_GLOBAL(0x0138B584, uint16); y = RCT2_GLOBAL(0x0138B586, uint16); - if (!sub_6C60C2(mapElement, &x, &y, &z)) { + if ((mapElement = track_get_next(mapElement, &x, &y, &z)) == NULL) { _rideRatingsState = RIDE_RATINGS_STATE_4; return; } diff --git a/src/ride/track.c b/src/ride/track.c index c3956d0ab8..b8735e3a05 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -29,7 +29,10 @@ * * rct2: 0x00997C9D */ -const rct_trackdefinition gTrackDefinitions[] = { +const rct_trackdefinition *gTrackDefinitions = (rct_trackdefinition*)0x00997C9D; + +// TODO This table is incorrect or at least missing 69 elements. There should be 256 in total! +const rct_trackdefinition gTrackDefinitions_INCORRECT[] = { // TYPE VANGLE END VANGLE START BANK END BANK START SPECIAL { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_FLAT { TRACK_FLAT, TRACK_NONE, TRACK_NONE, TRACK_BANK_NONE, TRACK_BANK_NONE, TRACK_NONE }, // ELEM_END_STATION @@ -453,4 +456,41 @@ int track_rename(const char *text) int track_delete() { return (RCT2_CALLPROC_X(0x006D3761, 0, 0, 0, 0, 0, 0, 0) & 0x100) != 0; +} + +/** + * Helper method to determine if a connects to b by its bank and angle, not location. + */ +int track_is_connected_by_shape(rct_map_element *a, rct_map_element *b) +{ + int trackType, aBank, aAngle, bBank, bAngle; + rct_ride *ride; + + ride = GET_RIDE(a->properties.track.ride_index); + trackType = a->properties.track.type; + aBank = gTrackDefinitions[trackType].bank_end; + aAngle = gTrackDefinitions[trackType].vangle_end; + if (RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 8) { + if (a->properties.track.colour & 4) { + if (aBank == TRACK_BANK_NONE) + aBank = TRACK_BANK_UPSIDE_DOWN; + else if (aBank == TRACK_BANK_UPSIDE_DOWN) + aBank = TRACK_BANK_NONE; + } + } + + ride = GET_RIDE(b->properties.track.ride_index); + trackType = b->properties.track.type; + bBank = gTrackDefinitions[trackType].bank_start; + bAngle = gTrackDefinitions[trackType].vangle_start; + if (RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint16) & 8) { + if (b->properties.track.colour & 4) { + if (bBank == TRACK_BANK_NONE) + bBank = TRACK_BANK_UPSIDE_DOWN; + else if (bBank == TRACK_BANK_UPSIDE_DOWN) + bBank = TRACK_BANK_NONE; + } + } + + return aBank == bBank && aAngle == bAngle; } \ No newline at end of file diff --git a/src/ride/track.h b/src/ride/track.h index 10d66427e7..9c7e306e7a 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -22,8 +22,8 @@ #define _TRACK_H_ #include "../common.h" -#include "ride.h" #include "../object.h" +#include "ride.h" typedef struct { uint8 type; @@ -137,11 +137,14 @@ enum { TRACK_CORKSCREW_DOWN = 224 }; +extern const rct_trackdefinition *gTrackDefinitions; + void track_load_list(ride_list_item item); int sub_67726A(const char *path); rct_track_design *track_get_info(int index, uint8** preview); int track_rename(const char *text); int track_delete(); void reset_track_list_cache(); +int track_is_connected_by_shape(rct_map_element *a, rct_map_element *b); #endif \ No newline at end of file From 5b4ec3621a84fb70c0a009dba38956b38453e323 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Fri, 30 Jan 2015 19:20:19 +0000 Subject: [PATCH 03/10] refactor many functions to use rct_xy_element --- src/interface/viewport_interaction.c | 6 +- src/localisation/string_ids.h | 4 + src/ride/ride.c | 287 +++++++++++++++++---------- src/ride/ride.h | 8 +- src/ride/ride_ratings.c | 12 +- src/windows/ride.c | 17 +- src/windows/ride_construction.c | 15 +- src/world/map.h | 5 + 8 files changed, 227 insertions(+), 127 deletions(-) diff --git a/src/interface/viewport_interaction.c b/src/interface/viewport_interaction.c index 8849a2fe02..39f1d3bf42 100644 --- a/src/interface/viewport_interaction.c +++ b/src/interface/viewport_interaction.c @@ -324,6 +324,7 @@ int viewport_interaction_right_over(int x, int y) */ int viewport_interaction_right_click(int x, int y) { + rct_xy_element mapElement; viewport_interaction_info info; switch (viewport_interaction_get_item_right(x, y, &info)) { @@ -335,7 +336,10 @@ int viewport_interaction_right_click(int x, int y) ride_construct(info.sprite->vehicle.ride); break; case VIEWPORT_INTERACTION_ITEM_RIDE: - ride_modify(info.mapElement, info.x, info.y); + mapElement.x = info.x; + mapElement.y = info.y; + mapElement.element = info.mapElement; + ride_modify(&mapElement); break; case VIEWPORT_INTERACTION_ITEM_SCENERY: viewport_interaction_remove_scenery(info.mapElement, info.x, info.y); diff --git a/src/localisation/string_ids.h b/src/localisation/string_ids.h index 10b6da440e..0851eb443a 100644 --- a/src/localisation/string_ids.h +++ b/src/localisation/string_ids.h @@ -1248,6 +1248,10 @@ enum { STR_SET_STARTING_POSITIONS_TIP = 3228, + STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_STATION = 3229, + STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_EACH_OTHER = 3230, + STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_THE_TOP_OF_THIS_LIFT_HILL = 3231, + STR_SCENARIO_OPTIONS_FINANCIAL = 3232, STR_SCENARIO_OPTIONS_GUESTS = 3233, STR_SCENARIO_OPTIONS_PARK = 3234, diff --git a/src/ride/ride.c b/src/ride/ride.c index 287e0e8a76..a2de400f21 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -266,13 +266,13 @@ money32 ride_calculate_income_per_hour(rct_ride *ride) * dl ride index * esi result map element */ -rct_map_element *sub_6CAF80(int rideIndex, int *outX, int *outY) +int sub_6CAF80(int rideIndex, rct_xy_element *output) { map_element_iterator it; rct_map_element *resultMapElement; int foundSpecialTrackPiece; - resultMapElement = (rct_map_element*)-1; + resultMapElement = NULL; foundSpecialTrackPiece = 0; map_element_iterator_begin(&it); @@ -284,48 +284,50 @@ rct_map_element *sub_6CAF80(int rideIndex, int *outX, int *outY) // Found a track piece for target ride - // Check if its a ??? + // Check if its not the station or ??? (but allow end piece of station) int specialTrackPiece = ( - (it.element->properties.track.type != 2 && it.element->properties.track.type != 3) && + it.element->properties.track.type != 2 && + it.element->properties.track.type != 3 && (RCT2_ADDRESS(0x0099BA64, uint8)[it.element->properties.track.type * 16] & 0x10) ); // Set result tile to this track piece if first found track or a ??? - if (resultMapElement == (rct_map_element*)-1 || specialTrackPiece) { + if (resultMapElement == NULL || specialTrackPiece) { resultMapElement = it.element; - if (outX != NULL) *outX = it.x * 32; - if (outY != NULL) *outY = it.y * 32; + if (output != NULL) { + output->element = resultMapElement; + output->x = it.x * 32; + output->y = it.y * 32; + } } if (specialTrackPiece) { foundSpecialTrackPiece = 1; - return resultMapElement; + return 1; } } while (map_element_iterator_next(&it)); - return resultMapElement; + return resultMapElement != NULL; } /** * * rct2: 0x006C60C2 */ -rct_map_element *track_get_next(rct_map_element *mapElement, int *x, int *y, int *z) +int track_get_next(rct_xy_element *input, rct_xy_element *output) { int eax, ebx, ecx, edx, esi, edi, ebp, result; - eax = *x; - ecx = *y; - esi = (int)mapElement; + eax = input->x; + ecx = input->y; + esi = (int)input->element; result = RCT2_CALLFUNC_X(0x006C60C2, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - *x = *((uint16*)&eax); - *y = *((uint16*)&ecx); - *z = *((uint8*)&edx); - mapElement = (rct_map_element*)esi; + output->x = *((uint16*)&eax); + output->y = *((uint16*)&ecx); + output->element = (rct_map_element*)esi; - if (result & 0x100) return NULL; - return mapElement; + return (result & 0x100) == 0; } /** @@ -336,46 +338,45 @@ rct_map_element *track_get_next(rct_map_element *mapElement, int *x, int *y, int * bx result y * esi input / output map element */ -rct_map_element *ride_find_track_gap(rct_map_element *startTrackElement, int *outX, int *outY) +int ride_find_track_gap(rct_xy_element *input, rct_xy_element *output) { - int rideIndex, x, y, z; - rct_map_element *trackElement, *nextTrackElement, *loopTrackElement; + int rideIndex; + rct_xy_element trackElement, nextTrackElement; + rct_map_element *loopTrackElement; rct_ride *ride; rct_window *w; - x = *outX; - y = *outY; - rideIndex = startTrackElement->properties.track.ride_index; + trackElement = *input; + rideIndex = trackElement.element->properties.track.ride_index; ride = GET_RIDE(rideIndex); if (ride->type == RIDE_TYPE_MAZE) - return NULL; + return 0; w = window_find_by_class(WC_RIDE_CONSTRUCTION); if (w != NULL && RCT2_GLOBAL(0x00F440A6, uint8) != 0 && RCT2_GLOBAL(0x00F440A7, uint8) == rideIndex) sub_6C9627(); - trackElement = startTrackElement; loopTrackElement = NULL; while (1) { - nextTrackElement = track_get_next(trackElement, &x, &y, &z); - if (nextTrackElement == NULL) - return trackElement; + if (!track_get_next(&trackElement, &nextTrackElement)) { + *output = trackElement; + return 1; + } - if (!track_is_connected_by_shape(trackElement, nextTrackElement)) { - *outX = x; - *outY = y; - return nextTrackElement; + if (!track_is_connected_by_shape(trackElement.element, nextTrackElement.element)) { + *output = nextTrackElement; + return 1; } trackElement = nextTrackElement; if (loopTrackElement == NULL) - loopTrackElement = trackElement; - else if (trackElement == loopTrackElement) + loopTrackElement = trackElement.element; + else if (loopTrackElement == trackElement.element) break; } - return NULL; + return 0; } /** @@ -903,14 +904,15 @@ int ride_modify_maze(rct_map_element *mapElement, int x, int y) * * rct2: 0x006CC056 */ -int ride_modify(rct_map_element *mapElement, int x, int y) +int ride_modify(rct_xy_element *input) { - int rideIndex, z, direction, type; - rct_map_element *endOfTrackElement; + int rideIndex, x, y, z, direction, type; + rct_xy_element mapElement, endOfTrackElement; rct_ride *ride; rct_window *constructionWindow; - rideIndex = mapElement->properties.track.ride_index; + mapElement = *input; + rideIndex = mapElement.element->properties.track.ride_index; ride = GET_RIDE(rideIndex); if (!ride_check_if_construction_allowed(ride)) @@ -934,26 +936,27 @@ int ride_modify(rct_map_element *mapElement, int x, int y) ride_remove_peeps(rideIndex); // Check if element is a station entrance or exit - if (map_element_get_type(mapElement) == MAP_ELEMENT_TYPE_ENTRANCE) - return ride_modify_entrance_or_exit(mapElement, x, y); + if (map_element_get_type(mapElement.element) == MAP_ELEMENT_TYPE_ENTRANCE) + return ride_modify_entrance_or_exit(mapElement.element, mapElement.x, mapElement.y); constructionWindow = ride_create_or_find_construction_window(rideIndex); if (ride->type == RIDE_TYPE_MAZE) - return ride_modify_maze(mapElement, x, y); + return ride_modify_maze(mapElement.element, mapElement.x, mapElement.y); if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS,uint64)[ride->type] & 0x100) { - int outX = x, outY = y; - endOfTrackElement = ride_find_track_gap(mapElement, &outX, &outY); - if (endOfTrackElement != NULL) + if (ride_find_track_gap(&mapElement, &endOfTrackElement)) mapElement = endOfTrackElement; } - z = mapElement->base_height * 8; - direction = mapElement->type & 3; - type = mapElement->properties.track.type; + x = mapElement.x; + y = mapElement.y; + z = mapElement.element->base_height * 8; + direction = mapElement.element->type & 3; + type = mapElement.element->properties.track.type; - if (sub_6C683D(&x, &y, z, direction, type, 0, 0, 0)) return 0; + if (sub_6C683D(&x, &y, z, direction, type, 0, 0, 0)) + return 0; RCT2_GLOBAL(0x00F440A7, uint8) = rideIndex; RCT2_GLOBAL(0x00F440A6, uint8) = 3; @@ -2772,45 +2775,129 @@ void sub_6B5952(int rideIndex) * * rct2: 0x006D3319 */ -int sub_6D3319(rct_map_element *mapElement) +int ride_check_block_brakes(rct_xy_element *input, rct_xy_element *output) { - return RCT2_CALLPROC_X(0x006D3319, 0, 0, 0, 0, (int)mapElement, 0, 0) & 0x100; + // return RCT2_CALLPROC_X(0x006D3319, x, 0, y, 0, (int)mapElement, 0, 0) & 0x100; + + int rideIndex, type; + rct_xy_element trackElement, nextTrackElement; + rct_map_element *loopTrackElement; + rct_window *w; + + trackElement = *input; + rideIndex = trackElement.element->properties.track.ride_index; + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL && RCT2_GLOBAL(0x00F440A6, uint8) != 0 && RCT2_GLOBAL(0x00F440A7, uint8) == rideIndex) + sub_6C9627(); + + loopTrackElement = NULL; + while (1) { + if (!track_get_next(&trackElement, &nextTrackElement)) { + // Not sure why this is the case... + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_STATION; + return 0; + } + + if (nextTrackElement.element->type == 216) { + type = trackElement.element->properties.track.type; + if (type == 1) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_STATION; + return 0; + } + if (type == 216) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_EACH_OTHER; + return 0; + } + if ((trackElement.element->type & 0x80) && type != 209 && type != 210) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_THE_TOP_OF_THIS_LIFT_HILL; + return 0; + } + } + + trackElement = nextTrackElement; + if (loopTrackElement == NULL) + loopTrackElement = trackElement.element; + else if (loopTrackElement == trackElement.element) + break; + } + + return 1; } /** * * rct2: 0x006CB149 */ -int sub_6CB149(rct_map_element *mapElement) +int ride_check_track_suitability_a(rct_xy_element *input, rct_xy_element *output) { - return RCT2_CALLPROC_X(0x006CB149, 0, 0, 0, 0, (int)mapElement, 0, 0) & 0x100; + int eax, ebx, ecx, edx, esi, edi, ebp, result; + + eax = input->x; + ecx = input->y; + esi = (int)input->element; + result = RCT2_CALLFUNC_X(0x006CB149, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + output->x = eax; + output->y = ecx; + output->element = (rct_map_element*)esi; + + return (result & 0x100) != 0; } /** * * rct2: 0x006CB1D3 */ -int sub_6CB1D3(rct_map_element *mapElement) +int ride_check_track_suitability_b(rct_xy_element *input, rct_xy_element *output) { - return RCT2_CALLPROC_X(0x006CB1D3, 0, 0, 0, 0, (int)mapElement, 0, 0) & 0x100; + int eax, ebx, ecx, edx, esi, edi, ebp, result; + + eax = input->x; + ecx = input->y; + esi = (int)input->element; + result = RCT2_CALLFUNC_X(0x006CB1D3, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + output->x = eax; + output->y = ecx; + output->element = (rct_map_element*)esi; + + return (result & 0x100) != 0; } /** * * rct2: 0x006CB25D */ -int sub_6CB25D(rct_map_element *mapElement) +int ride_check_station_length(rct_xy_element *input, rct_xy_element *output) { - return RCT2_CALLPROC_X(0x006CB25D, 0, 0, 0, 0, (int)mapElement, 0, 0) & 0x100; + int eax, ebx, ecx, edx, esi, edi, ebp, result; + + eax = input->x; + ecx = input->y; + esi = (int)input->element; + result = RCT2_CALLFUNC_X(0x006CB25D, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + output->x = eax; + output->y = ecx; + output->element = (rct_map_element*)esi; + + return (result & 0x100) != 0; } /** * * rct2: 0x006CB2DA */ -int sub_6CB2DA(rct_map_element *mapElement) +int ride_check_start_and_end_is_station(rct_xy_element *input, rct_xy_element *output) { - return RCT2_CALLPROC_X(0x006CB2DA, 0, 0, 0, 0, (int)mapElement, 0, 0) & 0x100; + int eax, ebx, ecx, edx, esi, edi, ebp, result; + + eax = input->x; + ecx = input->y; + esi = (int)input->element; + result = RCT2_CALLFUNC_X(0x006CB2DA, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + output->x = eax; + output->y = ecx; + output->element = (rct_map_element*)esi; + + return (result & 0x100) != 0; } /** @@ -2848,7 +2935,7 @@ void loc_6B51C0(int rideIndex) { int i, x, y, z; rct_ride *ride; - rct_map_element *mapElement; + rct_xy_element trackElement; rct_window *w; ride = GET_RIDE(rideIndex); @@ -2885,9 +2972,9 @@ void loc_6B51C0(int rideIndex) z = ride->station_heights[i] * 8; window_scroll_to_location(w, x, y, z); - mapElement = sub_6CAF80(rideIndex, &x, &y); - mapElement = ride_find_track_gap(mapElement, &x, &y); - ride_modify(mapElement, x, y); + sub_6CAF80(rideIndex, &trackElement); + ride_find_track_gap(&trackElement, &trackElement); + ride_modify(&trackElement); w = window_find_by_class(WC_RIDE_CONSTRUCTION); if (w != NULL) @@ -2899,12 +2986,12 @@ void loc_6B51C0(int rideIndex) * * rct2: 0x006B528A */ -void loc_6B528A(rct_map_element *mapElement, int x, int y, int z) +void loc_6B528A(rct_xy_element *trackElement) { rct_ride *ride; rct_window *w; - ride = GET_RIDE(mapElement->properties.track.ride_index); + ride = GET_RIDE(trackElement->element->properties.track.ride_index); if (RCT2_GLOBAL(0x0141F568, uint8) != RCT2_GLOBAL(0x013CA740, uint8)) return; @@ -2913,8 +3000,8 @@ void loc_6B528A(rct_map_element *mapElement, int x, int y, int z) if (w == NULL) return; - window_scroll_to_location(w, x, y, z); - ride_modify(mapElement, x, y); + window_scroll_to_location(w, trackElement->x, trackElement->y, trackElement->element->base_height * 8); + ride_modify(trackElement); } /** @@ -2952,9 +3039,9 @@ rct_map_element *loc_6B4F6B(int rideIndex, int x, int y) */ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) { - int i, x, y, z, stationIndex; + int i, stationIndex; rct_ride *ride; - rct_map_element *mapElement, *mapElement2; + rct_xy_element trackElement, problematicTrackElement; ride = GET_RIDE(rideIndex); @@ -2994,13 +3081,12 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_REQUIRES_A_STATION_PLATFORM; return 0; } - - x = (ride->station_starts[i] & 0xFF) * 32; - y = (ride->station_starts[i] >> 8) * 32; - z = ride->station_heights[i] * 8; - - mapElement = loc_6B4F6B(rideIndex, x, y); - if (mapElement == NULL) + + // z = ride->station_heights[i] * 8; + trackElement.x = (ride->station_starts[i] & 0xFF) * 32; + trackElement.y = (ride->station_starts[i] >> 8) * 32; + trackElement.element = loc_6B4F6B(rideIndex, trackElement.x, trackElement.y); + if (trackElement.element == NULL) return 0; if ( @@ -3010,60 +3096,59 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED ) { - mapElement2 = ride_find_track_gap(mapElement, &x, &y); - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint32) = STR_TRACK_IS_NOT_A_COMPLETE_CIRCUIT; - if (mapElement2 != NULL) { - loc_6B528A(mapElement, x, y, z); + if (ride_find_track_gap(&trackElement, &problematicTrackElement)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_IS_NOT_A_COMPLETE_CIRCUIT; + loc_6B528A(&problematicTrackElement); return 0; } } - // TODO check if the following is correct - if ( ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED ) { - if (sub_6D3319(mapElement)) { - loc_6B528A(mapElement, x, y, z); + if (!ride_check_block_brakes(&trackElement, &problematicTrackElement)) { + // TODO check if this is correct + loc_6B528A(&problematicTrackElement); return 0; } } + // Check onwards + if (ride->subtype != 255) { rct_ride_type *rideType = GET_RIDE_ENTRY(ride->subtype); if (rideType->var_008 & 2) { - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint32) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; - if (sub_6CB149(mapElement)) { - loc_6B528A(mapElement, x, y, z); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; + if (ride_check_track_suitability_a(&trackElement, &problematicTrackElement)) { + loc_6B528A(&problematicTrackElement); return 0; } } if (rideType->var_008 & 4) { - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint32) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; - if (sub_6CB1D3(mapElement)) { - loc_6B528A(mapElement, x, y, z); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; + if (ride_check_track_suitability_b(&trackElement, &problematicTrackElement)) { + loc_6B528A(&problematicTrackElement); return 0; } } } if (ride->mode == RIDE_MODE_STATION_TO_STATION) { - mapElement2 = ride_find_track_gap(mapElement, &x, &y); - if (mapElement2 == NULL) { - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint32) = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; + if (!ride_find_track_gap(&trackElement, &problematicTrackElement)) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; return 0; } - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint32) = STR_STATION_NOT_LONG_ENOUGH; - if (sub_6CB25D(mapElement)) { - loc_6B528A(mapElement, x, y, z); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_STATION_NOT_LONG_ENOUGH; + if (ride_check_station_length(&trackElement, &problematicTrackElement)) { + loc_6B528A(&problematicTrackElement); return 0; } - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint32) = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; - if (sub_6CB2DA(mapElement)) { - loc_6B528A(mapElement, x, y, z); + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_RIDE_MUST_START_AND_END_WITH_STATIONS; + if (ride_check_start_and_end_is_station(&trackElement, &problematicTrackElement)) { + loc_6B528A(&problematicTrackElement); return 0; } } diff --git a/src/ride/ride.h b/src/ride/ride.h index a7cbb2d5ea..1b4dbb16e5 100644 --- a/src/ride/ride.h +++ b/src/ride/ride.h @@ -613,12 +613,12 @@ void ride_update_favourited_stat(); void ride_update_all(); void ride_check_all_reachable(); void ride_update_popularity(rct_ride* ride, uint8 pop_amount); -rct_map_element *sub_6CAF80(int rideIndex, int *outX, int *outY); -rct_map_element *track_get_next(rct_map_element *mapElement, int *x, int *y, int *z); -rct_map_element *ride_find_track_gap(rct_map_element *startTrackElement, int *outX, int *outY); +int sub_6CAF80(int rideIndex, rct_xy_element *output); +int track_get_next(rct_xy_element *input, rct_xy_element *output); +int ride_find_track_gap(rct_xy_element *input, rct_xy_element *output); void ride_construct_new(ride_list_item listItem); void ride_construct(int rideIndex); -int ride_modify(rct_map_element *trackMapElement, int x, int y); +int ride_modify(rct_xy_element *input); void ride_get_status(int rideIndex, int *formatSecondary, int *argument); rct_peep *ride_get_assigned_mechanic(rct_ride *ride); int ride_get_total_length(rct_ride *ride); diff --git a/src/ride/ride_ratings.c b/src/ride/ride_ratings.c index 233c5cc948..65a760ce11 100644 --- a/src/ride/ride_ratings.c +++ b/src/ride/ride_ratings.c @@ -209,6 +209,7 @@ static void ride_ratings_update_state_2() rct_ride *ride; rct_map_element *mapElement; + rct_xy_element trackElement, nextTrackElement; int x, y, z, trackType, entranceIndex; ride = GET_RIDE(_rideRatingsCurrentRide); @@ -240,13 +241,18 @@ static void ride_ratings_update_state_2() RCT2_CALLPROC_X(0x006B5F9D, 0, 0, 0, 0, (int)mapElement, 0, 0); - x = RCT2_GLOBAL(0x0138B584, uint16); - y = RCT2_GLOBAL(0x0138B586, uint16); - if ((mapElement = track_get_next(mapElement, &x, &y, &z)) == NULL) { + trackElement.x = RCT2_GLOBAL(0x0138B584, uint16); + trackElement.y = RCT2_GLOBAL(0x0138B586, uint16); + trackElement.element = mapElement; + if (!track_get_next(&trackElement, &nextTrackElement)) { _rideRatingsState = RIDE_RATINGS_STATE_4; return; } + x = nextTrackElement.x; + y = nextTrackElement.y; + z = nextTrackElement.element->base_height * 8; + mapElement = nextTrackElement.element; if (x == RCT2_GLOBAL(0x0138B58A, uint16) && y == RCT2_GLOBAL(0x0138B58C, uint16) && z == RCT2_GLOBAL(0x0138B58E, uint16)) { _rideRatingsState = RIDE_RATINGS_STATE_CALCULATE; return; diff --git a/src/windows/ride.c b/src/windows/ride.c index 563ba03d08..84dbbd845b 100644 --- a/src/windows/ride.c +++ b/src/windows/ride.c @@ -1518,24 +1518,21 @@ static void window_ride_init_viewport(rct_window *w) void window_ride_construct(rct_window *w) { int rideIndex = w->number; + rct_xy_element trackElement; window_close_by_class(WC_RIDE_CONSTRUCTION); w = window_find_by_number(WC_RIDE, rideIndex); if (w == NULL) return; - rct_map_element *trackMapElement; - int trackX, trackY; - - trackMapElement = sub_6CAF80(rideIndex, &trackX, &trackY); - if (trackMapElement == (rct_map_element*)-1) { - sub_6CC3FB(rideIndex); - } else { - trackMapElement = ride_find_track_gap(trackMapElement, &trackX, &trackY); + if (sub_6CAF80(rideIndex, &trackElement)) { + ride_find_track_gap(&trackElement, &trackElement); w = window_get_main(); - if (w != NULL && ride_modify(trackMapElement, trackX, trackY)) - window_scroll_to_location(w, trackX, trackY, trackMapElement->base_height * 8); + if (w != NULL && ride_modify(&trackElement)) + window_scroll_to_location(w, trackElement.x, trackElement.y, trackElement.element->base_height * 8); + } else { + sub_6CC3FB(rideIndex); } } diff --git a/src/windows/ride_construction.c b/src/windows/ride_construction.c index 7863f81f81..985f4983e9 100644 --- a/src/windows/ride_construction.c +++ b/src/windows/ride_construction.c @@ -198,8 +198,10 @@ rct_window *window_construction_open() return w; } -void window_construction_close(){ +void window_construction_close() +{ rct_window *w; + rct_xy_element mapElement; window_get_register(w); @@ -211,21 +213,18 @@ void window_construction_close(){ hide_gridlines(); - int x, y; - uint8 ride_id = RCT2_GLOBAL(0xF440A7, uint8); - rct_map_element* map_element = sub_6CAF80(ride_id, &x, &y); - - if ((int)map_element == -1){ + uint8 rideIndex = RCT2_GLOBAL(0xF440A7, uint8); + if (!sub_6CAF80(rideIndex, &mapElement)) { int eax = RCT2_GLOBAL(0x009DEA6E, uint8); RCT2_GLOBAL(0x009DEA6E, uint8) = 0; - game_do_command(0, 9, 0, ride_id, GAME_COMMAND_7, 0, 0); + game_do_command(0, 9, 0, rideIndex, GAME_COMMAND_7, 0, 0); RCT2_GLOBAL(0x009DEA6E, uint8) = eax; return; } - window_ride_main_open(ride_id); + window_ride_main_open(rideIndex); } diff --git a/src/world/map.h b/src/world/map.h index 07ba6b60af..83b5cff06b 100644 --- a/src/world/map.h +++ b/src/world/map.h @@ -213,6 +213,11 @@ typedef struct { sint16 x, y, z; } rct_xyz16; +typedef struct { + int x, y; + rct_map_element *element; +} rct_xy_element; + typedef struct { uint16 x; uint16 y; From 78e3b1aa9541dcc228cf3c89ce1e4b47009a8685 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Sun, 8 Feb 2015 16:53:38 +0000 Subject: [PATCH 04/10] fix a few errors with check-valid-ride --- src/ride/ride.c | 18 ++++++++---------- src/windows/ride_construction.c | 9 +++------ 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/ride/ride.c b/src/ride/ride.c index b75130957d..9e31e24aea 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -2769,7 +2769,7 @@ int ride_check_for_entrance_exit(int rideIndex) */ void sub_6B5952(int rideIndex) { - RCT2_CALLPROC_X(0x006B4CC1, 0, 0, 0, rideIndex, 0, 0, 0); + RCT2_CALLPROC_X(0x006B5952, 0, 0, 0, rideIndex, 0, 0, 0); } /** @@ -2907,7 +2907,7 @@ int ride_check_start_and_end_is_station(rct_xy_element *input, rct_xy_element *o */ void sub_6B4D26(int rideIndex) { - RCT2_CALLPROC_X(0x006CB2DA, 0, 0, 0, rideIndex, 0, 0, 0); + RCT2_CALLPROC_X(0x006B4D26, 0, 0, 0, rideIndex, 0, 0, 0); } /** @@ -3051,13 +3051,11 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) return 0; if (!ride_check_for_entrance_exit(rideIndex)) { - // TODO check if this is correct loc_6B51C0(rideIndex); return 0; } if (goingToBeOpen && isApplying) { - // TODO check if this is correct sub_6B5952(rideIndex); ride->lifecycle_flags |= RIDE_LIFECYCLE_EVER_BEEN_OPENED; } @@ -3071,7 +3069,6 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) } if (stationIndex == -1) { - // TODO check if this is correct RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_NOT_YET_CONSTRUCTED; if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x8000) return 0; @@ -3087,8 +3084,11 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) trackElement.x = (ride->station_starts[i] & 0xFF) * 32; trackElement.y = (ride->station_starts[i] >> 8) * 32; trackElement.element = loc_6B4F6B(rideIndex, trackElement.x, trackElement.y); - if (trackElement.element == NULL) - return 0; + if (trackElement.element == NULL) { + // Maze is strange, station start is 0... investigation required + if (ride->type != RIDE_TYPE_MAZE) + return 0; + } if ( ride->type == RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER || @@ -3109,14 +3109,11 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED ) { if (!ride_check_block_brakes(&trackElement, &problematicTrackElement)) { - // TODO check if this is correct loc_6B528A(&problematicTrackElement); return 0; } } - // Check onwards - if (ride->subtype != 255) { rct_ride_type *rideType = GET_RIDE_ENTRY(ride->subtype); if (rideType->var_008 & 2) { @@ -3161,6 +3158,7 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) !(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x2000) && (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) ) { + // TODO Check if this is correct if (sub_6DD84C(ride)) return 0; } diff --git a/src/windows/ride_construction.c b/src/windows/ride_construction.c index 3000430a2d..0044d8282c 100644 --- a/src/windows/ride_construction.c +++ b/src/windows/ride_construction.c @@ -213,15 +213,12 @@ void window_construction_close() hide_gridlines(); - int x, y; - uint8 ride_id = RCT2_GLOBAL(0xF440A7, uint8); - rct_map_element* map_element = sub_6CAF80(ride_id, &x, &y); - - if ((int)map_element == -1){ + uint8 rideIndex = RCT2_GLOBAL(0x00F440A7, uint8); + if (!sub_6CAF80(rideIndex, &mapElement)) { int eax = RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8); RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = 0; - game_do_command(0, 9, 0, ride_id, GAME_COMMAND_7, 0, 0); + game_do_command(0, 9, 0, rideIndex, GAME_COMMAND_7, 0, 0); RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) = eax; return; From 6911de9085bde0c66dc4731bcdb6e0c51a737801 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Mon, 9 Feb 2015 01:16:51 +0000 Subject: [PATCH 05/10] fix issues with ride-set-status: - vehicles not being created - crash on stop stop - crash on demolish - crash sometimes on open --- src/ride/ride.c | 75 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/src/ride/ride.c b/src/ride/ride.c index 9e31e24aea..e997ffc237 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -1979,7 +1979,7 @@ rct_ride_measurement *ride_get_existing_measurement(int rideIndex) return NULL; } -rct_ride_measurement *ride_get_free_measurement() +int ride_get_free_measurement() { int i; rct_ride_measurement *measurement; @@ -1987,10 +1987,10 @@ rct_ride_measurement *ride_get_free_measurement() for (i = 0; i < MAX_RIDE_MEASUREMENTS; i++) { measurement = GET_RIDE_MEASUREMENT(i); if (measurement->ride_index == 255) - return measurement; + return i; } - return NULL; + return -1; } /** @@ -2016,8 +2016,8 @@ rct_ride_measurement *ride_get_measurement(int rideIndex, rct_string_id *message measurement = ride_get_existing_measurement(rideIndex); if (measurement == NULL) { // Find a free measurement - measurement = ride_get_free_measurement(); - if (measurement == NULL) { + i = ride_get_free_measurement(); + if (i == -1) { // Use last recently used measurement for some other ride lruIndex = 0; lruTicks = 0xFFFFFFFF; @@ -2032,9 +2032,11 @@ rct_ride_measurement *ride_get_measurement(int rideIndex, rct_string_id *message i = lruIndex; measurement = GET_RIDE_MEASUREMENT(i); - ride->measurement_index = 255; + GET_RIDE(measurement->ride_index)->measurement_index = 255; + } else { + measurement = GET_RIDE_MEASUREMENT(i); } - + measurement->ride_index = rideIndex; ride->measurement_index = i; measurement->flags = 0; @@ -2905,27 +2907,63 @@ int ride_check_start_and_end_is_station(rct_xy_element *input, rct_xy_element *o * * rct2: 0x006B4D26 */ -void sub_6B4D26(int rideIndex) +void sub_6B4D26(int rideIndex, rct_xy_element *startElement) { - RCT2_CALLPROC_X(0x006B4D26, 0, 0, 0, rideIndex, 0, 0, 0); + // RCT2_CALLPROC_X(0x006B4D26, element->x, 0, element->y, rideIndex, (int)element->element, 0, 0); + + rct_xy_element currentElement; + rct_ride *ride; + int trackType; + + ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_BUMPER_BOATS) { + + } else if (ride->type != RIDE_TYPE_MAZE) { + + } + + if ( + ( + ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED || + ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED + ) && + !(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) + ) { + // Set flag on track pieces where a train can start + currentElement = *startElement; + do { + trackType = currentElement.element->properties.track.type; + switch (trackType) { + case 1: // end of station + case 123: // cable lift hill + case 9: // 25deg up to flat + case 63: // 60deg up to flat + case 147: // diag 25deg up to flat + case 155: // diag 60deg up to flat + case 216: // block brakes + currentElement.element->flags &= ~(1 << 5); + break; + } + } while (track_get_next(¤tElement, ¤tElement) && currentElement.element != startElement->element); + } } /** * * rct2: 0x006DD84C */ -int sub_6DD84C(rct_ride *ride) +int sub_6DD84C(rct_ride *ride, rct_xy_element *element, int isApplying) { - return RCT2_CALLPROC_X(0x006DD84C, 0, 0, 0, 0, (int)ride, 0, 0) & 0x100; + return RCT2_CALLPROC_X(0x006DD84C, element->x, isApplying, element->y, 0, (int)ride, (int)element->element, 0) & 0x100; } /** * * rct2: 0x006DF4D4 */ -int sub_6DF4D4(rct_ride *ride) +int sub_6DF4D4(rct_ride *ride, rct_xy_element *element, int isApplying) { - return RCT2_CALLPROC_X(0x006DF4D4, 0, 0, 0, 0, (int)ride, 0, 0) & 0x100; + return RCT2_CALLPROC_X(0x006DF4D4, element->x, isApplying, element->y, 0, (int)ride, (int)element->element, 0) & 0x100; } /** @@ -3152,23 +3190,22 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) } if (isApplying) - sub_6B4D26(rideIndex); + sub_6B4D26(rideIndex, &trackElement); if ( !(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x2000) && - (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) + !(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) ) { - // TODO Check if this is correct - if (sub_6DD84C(ride)) + if (sub_6DD84C(ride, &trackElement, isApplying)) return 0; } if ( (RCT2_GLOBAL(0x0097D4F2 + (ride->type * 8), uint32) & 0x400) && (ride->lifecycle_flags & RIDE_LIFECYCLE_16) && - (ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT) + !(ride->lifecycle_flags & RIDE_LIFECYCLE_CABLE_LIFT) ) { - if (sub_6DF4D4(ride)) + if (sub_6DF4D4(ride, &trackElement, isApplying)) return 0; } From 929fd80c651bacc3432efd1bfb85402f1eac9449 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Mon, 9 Feb 2015 11:41:20 +0000 Subject: [PATCH 06/10] fix issues with set-ride-status: - checking of block brakes - location of missing entrance / exit --- src/ride/ride.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ride/ride.c b/src/ride/ride.c index e997ffc237..b6db115d1f 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -2798,21 +2798,25 @@ int ride_check_block_brakes(rct_xy_element *input, rct_xy_element *output) if (!track_get_next(&trackElement, &nextTrackElement)) { // Not sure why this is the case... RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_STATION; + *output = trackElement; return 0; } - if (nextTrackElement.element->type == 216) { + if (nextTrackElement.element->properties.track.type == 216) { type = trackElement.element->properties.track.type; if (type == 1) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_STATION; + *output = nextTrackElement; return 0; } if (type == 216) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_EACH_OTHER; + *output = nextTrackElement; return 0; } if ((trackElement.element->type & 0x80) && type != 209 && type != 210) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_BLOCK_BRAKES_CANNOT_BE_USED_DIRECTLY_AFTER_THE_TOP_OF_THIS_LIFT_HILL; + *output = nextTrackElement; return 0; } } @@ -2909,7 +2913,7 @@ int ride_check_start_and_end_is_station(rct_xy_element *input, rct_xy_element *o */ void sub_6B4D26(int rideIndex, rct_xy_element *startElement) { - // RCT2_CALLPROC_X(0x006B4D26, element->x, 0, element->y, rideIndex, (int)element->element, 0, 0); + RCT2_CALLPROC_X(0x006B4D26, startElement->x, 0, startElement->y, rideIndex, (int)startElement->element, 0, 0); return; rct_xy_element currentElement; rct_ride *ride; @@ -3006,8 +3010,8 @@ void loc_6B51C0(int rideIndex) return; if (ride->type != RIDE_TYPE_MAZE) { - x = (ride->station_starts[i] >> 8) * 32; - y = (ride->station_starts[i] & 0xFF) * 32; + x = (ride->station_starts[i] & 0xFF) * 32; + y = (ride->station_starts[i] >> 8) * 32; z = ride->station_heights[i] * 8; window_scroll_to_location(w, x, y, z); From 461655f3f694e6ee97a7072183d239feb10dee2d Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Wed, 11 Feb 2015 19:59:31 +0000 Subject: [PATCH 07/10] Fix hang caused by no rideIndex being passed --- src/ride/ride.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ride/ride.c b/src/ride/ride.c index b6db115d1f..0568788e9b 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -2956,9 +2956,9 @@ void sub_6B4D26(int rideIndex, rct_xy_element *startElement) * * rct2: 0x006DD84C */ -int sub_6DD84C(rct_ride *ride, rct_xy_element *element, int isApplying) +int sub_6DD84C(rct_ride *ride, int rideIndex, rct_xy_element *element, int isApplying) { - return RCT2_CALLPROC_X(0x006DD84C, element->x, isApplying, element->y, 0, (int)ride, (int)element->element, 0) & 0x100; + return RCT2_CALLPROC_X(0x006DD84C, element->x, isApplying, element->y, rideIndex, (int)ride, (int)element->element, 0) & 0x100; } /** @@ -3200,7 +3200,7 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) !(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x2000) && !(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) ) { - if (sub_6DD84C(ride, &trackElement, isApplying)) + if (sub_6DD84C(ride, rideIndex, &trackElement, isApplying)) return 0; } From abd8e34f2f4fefd8cf949724b162b8e65fd2c91b Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Thu, 12 Feb 2015 19:41:09 +0000 Subject: [PATCH 08/10] Implemented check_valid_stations. Fixed relocation bug --- src/ride/ride.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/ride/ride.c b/src/ride/ride.c index 0568788e9b..d5d0fd5646 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -2753,7 +2753,32 @@ void ride_music_update_final() */ int ride_mode_check_valid_stations(rct_ride *ride) { - return (RCT2_CALLPROC_X(0x006B4CC1, 0, 0, 0, 0, (int)ride, 0, 0) & 0x100) == 0; + uint8 no_stations = 0; + for (uint8 station_index = 0; station_index < 4; ++station_index){ + if (ride->station_starts[station_index] != 0xFFFF)no_stations++; + } + + switch (ride->mode){ + case RIDE_MODE_REVERSE_INCLINE_LAUNCHED_SHUTTLE: + case RIDE_MODE_POWERED_LAUNCH: + case RIDE_MODE_POWERED_LAUNCH_35: + case RIDE_MODE_LIM_POWERED_LAUNCH: + if (no_stations <= 0) return 1; + RCT2_GLOBAL(0x141E9AC, uint16) = 1015; + return 0; + case RIDE_MODE_SHUTTLE: + if (no_stations >= 2) return 1; + RCT2_GLOBAL(0x141E9AC, uint16) = 1016; + return 0; + } + + if (ride->type == RIDE_TYPE_GO_KARTS || ride->type == RIDE_TYPE_MINI_GOLF){ + if (no_stations <= 0) return 1; + RCT2_GLOBAL(0x141E9AC, uint16) = 1015; + return 0; + } + + return 1; } /** @@ -2990,7 +3015,7 @@ void loc_6B51C0(int rideIndex) if (w == NULL) return; - uint8 entranceOrExit = -1; + sint8 entranceOrExit = -1; for (i = 0; i < 4; i++) { if (ride->station_starts[i] == 0xFFFF) continue; From a7f4d44ecea9a63347f0114fd052a32880b3022b Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Thu, 12 Feb 2015 22:30:31 +0000 Subject: [PATCH 09/10] Add check_for_entrance_exit. Fixed ride name not shown --- src/ride/ride.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- src/windows/ride.c | 2 +- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/ride/ride.c b/src/ride/ride.c index d5d0fd5646..6c2e3344f6 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -2763,7 +2763,7 @@ int ride_mode_check_valid_stations(rct_ride *ride) case RIDE_MODE_POWERED_LAUNCH: case RIDE_MODE_POWERED_LAUNCH_35: case RIDE_MODE_LIM_POWERED_LAUNCH: - if (no_stations <= 0) return 1; + if (no_stations <= 1) return 1; RCT2_GLOBAL(0x141E9AC, uint16) = 1015; return 0; case RIDE_MODE_SHUTTLE: @@ -2773,7 +2773,7 @@ int ride_mode_check_valid_stations(rct_ride *ride) } if (ride->type == RIDE_TYPE_GO_KARTS || ride->type == RIDE_TYPE_MINI_GOLF){ - if (no_stations <= 0) return 1; + if (no_stations <= 1) return 1; RCT2_GLOBAL(0x141E9AC, uint16) = 1015; return 0; } @@ -2787,7 +2787,46 @@ int ride_mode_check_valid_stations(rct_ride *ride) */ int ride_check_for_entrance_exit(int rideIndex) { - return (RCT2_CALLPROC_X(0x006B5872, 0, 0, 0, rideIndex, 0, 0, 0) & 0x100) == 0; + rct_ride* ride = GET_RIDE(rideIndex); + + if (RCT2_ADDRESS(RCT2_ADDRESS_RIDE_FLAGS, uint32)[ride->type * 2] & 0x20000) return 1; + + int i; + uint8 entrance = 0; + uint8 exit = 0; + for (i = 0; i < 4; i++) { + if (ride->station_starts[i] == 0xFFFF) + continue; + + if (ride->entrances[i] != 0xFFFF) { + entrance = 2; + } + else if (ride->exits[i] != 0xFFFF) { + exit = 2; + } + else + + // If station start and no entrance/exit + if (entrance == 1 && exit == 1){ + entrance = 0; + break; + } + + if (entrance) entrance = 1; + if (exit) exit = 1; + } + + if (entrance == 0){ + RCT2_GLOBAL(0x141E9AC, uint16) = 1146; + return 0; + } + + if (exit == 0){ + RCT2_GLOBAL(0x141E9AC, uint16) = 1147; + return 0; + } + + return 1; } /** diff --git a/src/windows/ride.c b/src/windows/ride.c index 3abcfcf279..4d6a9a8de8 100644 --- a/src/windows/ride.c +++ b/src/windows/ride.c @@ -1829,7 +1829,7 @@ static void window_ride_main_dropdown() break; } - RCT2_GLOBAL(0x013CE952 + 6, uint16) = ride->overall_view; + RCT2_GLOBAL(0x013CE952 + 6, uint16) = ride->name; RCT2_GLOBAL(0x013CE952 + 8, uint32) = ride->name_arguments; ride_set_status(w->number, status); break; From 22749ece81bc5b147d567b036a61a80f0c49cd44 Mon Sep 17 00:00:00 2001 From: Duncan Frost Date: Sat, 14 Feb 2015 12:07:54 +0000 Subject: [PATCH 10/10] Move station check before exit/entrance check. Found original bug in station to station. --- src/ride/ride.c | 106 ++++++++++++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 43 deletions(-) diff --git a/src/ride/ride.c b/src/ride/ride.c index 6c2e3344f6..795fcd3ed7 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -2751,7 +2751,7 @@ void ride_music_update_final() * * rct2: 0x006B4CC1 */ -int ride_mode_check_valid_stations(rct_ride *ride) +int ride_mode_check_valid_station_numbers(rct_ride *ride) { uint8 no_stations = 0; for (uint8 station_index = 0; station_index < 4; ++station_index){ @@ -2781,6 +2781,33 @@ int ride_mode_check_valid_stations(rct_ride *ride) return 1; } +/* returns stationIndex of first station on success + * -1 on failure. + */ +int ride_mode_check_station_present(rct_ride* ride){ + int stationIndex = -1; + for (int i = 0; i < 4; i++) { + if (ride->station_starts[i] != 0xFFFF) { + stationIndex = i; + break; + } + } + + if (stationIndex == -1) { + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_NOT_YET_CONSTRUCTED; + if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x8000) + return -1; + + if (ride->type == RIDE_TYPE_MAZE) + return -1; + + RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_REQUIRES_A_STATION_PLATFORM; + return -1; + } + + return stationIndex; +} + /** * * rct2: 0x006B5872 @@ -2799,21 +2826,19 @@ int ride_check_for_entrance_exit(int rideIndex) continue; if (ride->entrances[i] != 0xFFFF) { - entrance = 2; + entrance = 1; } - else if (ride->exits[i] != 0xFFFF) { - exit = 2; + + if (ride->exits[i] != 0xFFFF) { + exit = 1; } - else - + // If station start and no entrance/exit - if (entrance == 1 && exit == 1){ + // Sets same error message as no entrance + if (ride->exits[i] == 0xFFFF && ride->entrances[i] == 0xFFFF){ entrance = 0; break; } - - if (entrance) entrance = 1; - if (exit) exit = 1; } if (entrance == 0){ @@ -2907,8 +2932,8 @@ int ride_check_track_suitability_a(rct_xy_element *input, rct_xy_element *output ecx = input->y; esi = (int)input->element; result = RCT2_CALLFUNC_X(0x006CB149, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - output->x = eax; - output->y = ecx; + output->x = (uint16)eax; + output->y = (uint16)ecx; output->element = (rct_map_element*)esi; return (result & 0x100) != 0; @@ -2926,8 +2951,8 @@ int ride_check_track_suitability_b(rct_xy_element *input, rct_xy_element *output ecx = input->y; esi = (int)input->element; result = RCT2_CALLFUNC_X(0x006CB1D3, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - output->x = eax; - output->y = ecx; + output->x = (uint16)eax; + output->y = (uint16)ecx; output->element = (rct_map_element*)esi; return (result & 0x100) != 0; @@ -2941,12 +2966,17 @@ int ride_check_station_length(rct_xy_element *input, rct_xy_element *output) { int eax, ebx, ecx, edx, esi, edi, ebp, result; + // This function has a bug. If the station length is too short and it is + // the last station of a ride it will return a pointer to the map_element + // where the station piece should go. Instead it should pass the map_element + // of the last good station piece. This can cause null pointer dereferences + // and cause the map to move to the top left hand corner. eax = input->x; ecx = input->y; esi = (int)input->element; result = RCT2_CALLFUNC_X(0x006CB25D, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - output->x = eax; - output->y = ecx; + output->x = (uint16)eax; + output->y = (uint16)ecx; output->element = (rct_map_element*)esi; return (result & 0x100) != 0; @@ -2964,8 +2994,8 @@ int ride_check_start_and_end_is_station(rct_xy_element *input, rct_xy_element *o ecx = input->y; esi = (int)input->element; result = RCT2_CALLFUNC_X(0x006CB2DA, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - output->x = eax; - output->y = ecx; + output->x = (uint16)eax; + output->y = (uint16)ecx; output->element = (rct_map_element*)esi; return (result & 0x100) != 0; @@ -3146,14 +3176,18 @@ rct_map_element *loc_6B4F6B(int rideIndex, int x, int y) */ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) { - int i, stationIndex; + int stationIndex; rct_ride *ride; rct_xy_element trackElement, problematicTrackElement; ride = GET_RIDE(rideIndex); window_close_by_class(WC_RIDE_CONSTRUCTION); - if (!ride_mode_check_valid_stations(ride)) + + stationIndex = ride_mode_check_station_present(ride); + if (stationIndex == -1)return 0; + + if (!ride_mode_check_valid_station_numbers(ride)) return 0; if (!ride_check_for_entrance_exit(rideIndex)) { @@ -3165,30 +3199,10 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) sub_6B5952(rideIndex); ride->lifecycle_flags |= RIDE_LIFECYCLE_EVER_BEEN_OPENED; } - - stationIndex = -1; - for (i = 0; i < 4; i++) { - if (ride->station_starts[i] != 0xFFFF) { - stationIndex = i; - break; - } - } - - if (stationIndex == -1) { - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_NOT_YET_CONSTRUCTED; - if (RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x8000) - return 0; - - if (ride->type == RIDE_TYPE_MAZE) - return 0; - - RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_REQUIRES_A_STATION_PLATFORM; - return 0; - } // z = ride->station_heights[i] * 8; - trackElement.x = (ride->station_starts[i] & 0xFF) * 32; - trackElement.y = (ride->station_starts[i] >> 8) * 32; + trackElement.x = (ride->station_starts[stationIndex] & 0xFF) * 32; + trackElement.y = (ride->station_starts[stationIndex] >> 8) * 32; trackElement.element = loc_6B4F6B(rideIndex, trackElement.x, trackElement.y); if (trackElement.element == NULL) { // Maze is strange, station start is 0... investigation required @@ -3246,7 +3260,13 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_STATION_NOT_LONG_ENOUGH; if (ride_check_station_length(&trackElement, &problematicTrackElement)) { - loc_6B528A(&problematicTrackElement); + + // This is to prevent a bug in the check_station_length function + // remove when check_station_length is reveresed and fixed. Prevents + // null dereference. Does not prevent moving screen to top left corner. + if (map_element_get_type(problematicTrackElement.element) != MAP_ELEMENT_TYPE_TRACK) + loc_6B528A(&trackElement); + else loc_6B528A(&problematicTrackElement); return 0; }