From 6acf52ce63bcb4af67a7ffa31e1f99df36cdd720 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Sat, 11 Jul 2015 22:51:11 +0100 Subject: [PATCH] implement ride_check_track_contains_inversions, ride_check_track_contains_banked, refactor track circuit iteration and fix window event bug with hook --- src/openrct2.c | 3 +- src/ride/ride.c | 168 +++++++++++++++++++++++++---------------------- src/ride/ride.h | 4 +- src/ride/track.c | 30 ++++++++- src/ride/track.h | 13 ++++ 5 files changed, 137 insertions(+), 81 deletions(-) diff --git a/src/openrct2.c b/src/openrct2.c index 2aadec9c2b..a64cbef838 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -189,7 +189,8 @@ bool openrct2_initialise() // Hooks to allow RCT2 to call OpenRCT2 functions instead addhook(0x006E732D, (int)gfx_set_dirty_blocks, 0, (int[]){ EAX, EBX, EDX, EBP, END }, 0); // remove after all drawing is decompiled addhook(0x006E7499, (int)gfx_redraw_screen_rect, 0, (int[]){ EAX, EBX, EDX, EBP, END }, 0); // remove when 0x6E7FF3 is decompiled - addhook(0x006B752C, (int)ride_crash, 0, (int[]){ EDX, EBX, END }, 0); // remove when callers are decompiled + addhook(0x006B752C, (int)ride_crash, 0, (int[]){ EDX, EBX, END }, 0); // remove when all callers are decompiled + addhook(0x0069A42F, (int)peep_window_state_update, 0, (int[]){ ESI }, 0); // remove when all callers are decompiled if (!rct2_init()) return false; diff --git a/src/ride/ride.c b/src/ride/ride.c index ef1a305386..8cd38dbb0e 100644 --- a/src/ride/ride.c +++ b/src/ride/ride.c @@ -609,14 +609,12 @@ bool track_block_get_previous(int x, int y, rct_map_element *mapElement, track_b */ int ride_find_track_gap(rct_xy_element *input, rct_xy_element *output) { - int rideIndex; - rct_xy_element trackElement, nextTrackElement; - rct_map_element *loopTrackElement; - rct_ride *ride; rct_window *w; + rct_ride *ride; + track_circuit_iterator it; + int rideIndex; - trackElement = *input; - rideIndex = trackElement.element->properties.track.ride_index; + rideIndex = input->element->properties.track.ride_index; ride = GET_RIDE(rideIndex); if (ride->type == RIDE_TYPE_MAZE) @@ -626,23 +624,16 @@ int ride_find_track_gap(rct_xy_element *input, rct_xy_element *output) if (w != NULL && _rideConstructionState != RIDE_CONSTRUCTION_STATE_0 && _currentRideIndex == rideIndex) sub_6C9627(); - loopTrackElement = NULL; - while (1) { - if (!track_block_get_next(&trackElement, &nextTrackElement, NULL, NULL)) { - *output = trackElement; + track_circuit_iterator_begin(&it, *input); + while (track_circuit_iterator_next(&it)) { + if (!track_is_connected_by_shape(it.last.element, it.current.element)) { + *output = it.current; return 1; } - - if (!track_is_connected_by_shape(trackElement.element, nextTrackElement.element)) { - *output = nextTrackElement; - return 1; - } - - trackElement = nextTrackElement; - if (loopTrackElement == NULL) - loopTrackElement = trackElement.element; - else if (loopTrackElement == trackElement.element) - break; + } + if (!it.looped) { + *output = it.last; + return 1; } return 0; @@ -3722,91 +3713,114 @@ void sub_6B5952(int rideIndex) */ int ride_check_block_brakes(rct_xy_element *input, rct_xy_element *output) { - int rideIndex, type; - rct_xy_element trackElement, nextTrackElement; - rct_map_element *loopTrackElement; rct_window *w; + track_circuit_iterator it; + int rideIndex, type; - trackElement = *input; - rideIndex = trackElement.element->properties.track.ride_index; + rideIndex = input->element->properties.track.ride_index; w = window_find_by_class(WC_RIDE_CONSTRUCTION); if (w != NULL && _rideConstructionState != RIDE_CONSTRUCTION_STATE_0 && _currentRideIndex == rideIndex) sub_6C9627(); - loopTrackElement = NULL; - while (1) { - if (!track_block_get_next(&trackElement, &nextTrackElement, NULL, NULL)) { - // 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->properties.track.type == 216) { - type = trackElement.element->properties.track.type; + track_circuit_iterator_begin(&it, *input); + while (track_circuit_iterator_next(&it)) { + if (it.current.element->properties.track.type == 216) { + type = it.last.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; + *output = it.current; 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; + *output = it.current; return 0; } - if ((trackElement.element->type & 0x80) && type != 209 && type != 210) { + if ((it.last.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; + *output = it.current; return 0; } } - - trackElement = nextTrackElement; - if (loopTrackElement == NULL) - loopTrackElement = trackElement.element; - else if (loopTrackElement == trackElement.element) - break; + } + if (!it.looped) { + // 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 = it.last; + return 0; } return 1; } /** - * + * Iterates along the track until an inversion (loop, corkscrew, barrel roll etc.) track piece is reached. + * @param input The start track element and position. + * @param output The first track element and position which is classified as an inversion. + * @returns true if an inversion track piece is found, otherwise false. * rct2: 0x006CB149 */ -int ride_check_track_suitability_a(rct_xy_element *input, rct_xy_element *output) +bool ride_check_track_contains_inversions(rct_xy_element *input, rct_xy_element *output) { - int eax, ebx, ecx, edx, esi, edi, ebp, result; + rct_window *w; + rct_ride *ride; + int rideIndex, trackType; + track_circuit_iterator it; - eax = input->x; - ecx = input->y; - esi = (int)input->element; - result = RCT2_CALLFUNC_X(0x006CB149, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - output->x = (uint16)eax; - output->y = (uint16)ecx; - output->element = (rct_map_element*)esi; + rideIndex = input->element->properties.track.ride_index; + ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_MAZE) + return true; - return (result & 0x100) != 0; + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL && _rideConstructionState != RIDE_CONSTRUCTION_STATE_0 && rideIndex == _currentRideIndex) { + sub_6C9627(); + } + + track_circuit_iterator_begin(&it, *input); + while (track_circuit_iterator_next(&it)) { + trackType = output->element->properties.track.type; + if (RCT2_ADDRESS(0x0099423C, uint16)[trackType] & 0x4000) { + *output = it.current; + return true; + } + } + return false; } /** - * + * Iterates along the track until a banked track piece is reached. + * @param input The start track element and position. + * @param output The first track element and position which is banked. + * @returns true if a banked track piece is found, otherwise false. * rct2: 0x006CB1D3 */ -int ride_check_track_suitability_b(rct_xy_element *input, rct_xy_element *output) +bool ride_check_track_contains_banked(rct_xy_element *input, rct_xy_element *output) { - int eax, ebx, ecx, edx, esi, edi, ebp, result; + rct_window *w; + rct_ride *ride; + int rideIndex, trackType; + track_circuit_iterator it; - eax = input->x; - ecx = input->y; - esi = (int)input->element; - result = RCT2_CALLFUNC_X(0x006CB1D3, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - output->x = (uint16)eax; - output->y = (uint16)ecx; - output->element = (rct_map_element*)esi; + rideIndex = input->element->properties.track.ride_index; + ride = GET_RIDE(rideIndex); + if (ride->type == RIDE_TYPE_MAZE) + return true; - return (result & 0x100) != 0; + w = window_find_by_class(WC_RIDE_CONSTRUCTION); + if (w != NULL && _rideConstructionState != RIDE_CONSTRUCTION_STATE_0 && rideIndex == _currentRideIndex) { + sub_6C9627(); + } + + track_circuit_iterator_begin(&it, *input); + while (track_circuit_iterator_next(&it)) { + trackType = output->element->properties.track.type; + if (RCT2_ADDRESS(0x0099423C, uint16)[trackType] & 0x8000) { + *output = it.current; + return true; + } + } + return false; } /** @@ -4108,16 +4122,16 @@ int ride_is_valid_for_test(int rideIndex, int goingToBeOpen, int isApplying) if (ride->subtype != 255) { rct_ride_type *rideType = GET_RIDE_ENTRY(ride->subtype); - if (rideType->flags & RIDE_ENTRY_FLAG_1) { + if (rideType->flags & RIDE_ENTRY_FLAG_NO_INVERSIONS) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; - if (ride_check_track_suitability_a(&trackElement, &problematicTrackElement)) { + if (ride_check_track_contains_inversions(&trackElement, &problematicTrackElement)) { loc_6B528A(&problematicTrackElement); return 0; } } - if (rideType->flags & RIDE_ENTRY_FLAG_2) { + if (rideType->flags & RIDE_ENTRY_FLAG_NO_BANKED_TRACK) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; - if (ride_check_track_suitability_b(&trackElement, &problematicTrackElement)) { + if (ride_check_track_contains_banked(&trackElement, &problematicTrackElement)) { loc_6B528A(&problematicTrackElement); return 0; } @@ -4231,16 +4245,16 @@ int ride_is_valid_for_open(int rideIndex, int goingToBeOpen, int isApplying) if (ride->subtype != 255) { rct_ride_type *rideType = GET_RIDE_ENTRY(ride->subtype); - if (rideType->flags & RIDE_ENTRY_FLAG_1) { + if (rideType->flags & RIDE_ENTRY_FLAG_NO_INVERSIONS) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; - if (ride_check_track_suitability_a(&trackElement, &problematicTrackElement)) { + if (ride_check_track_contains_inversions(&trackElement, &problematicTrackElement)) { loc_6B528A(&problematicTrackElement); return 0; } } - if (rideType->flags & RIDE_ENTRY_FLAG_2) { + if (rideType->flags & RIDE_ENTRY_FLAG_NO_BANKED_TRACK) { RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT, uint16) = STR_TRACK_UNSUITABLE_FOR_TYPE_OF_TRAIN; - if (ride_check_track_suitability_b(&trackElement, &problematicTrackElement)) { + if (ride_check_track_contains_banked(&trackElement, &problematicTrackElement)) { loc_6B528A(&problematicTrackElement); return 0; } diff --git a/src/ride/ride.h b/src/ride/ride.h index 6b96976888..2bbd5998cd 100644 --- a/src/ride/ride.h +++ b/src/ride/ride.h @@ -393,8 +393,8 @@ enum { // Constants used by the ride_type->flags property at 0x008 enum { RIDE_ENTRY_FLAG_0 = 1 << 0, // 0x1 - RIDE_ENTRY_FLAG_1 = 1 << 1, // 0x2 - RIDE_ENTRY_FLAG_2 = 1 << 2, // 0x4 + RIDE_ENTRY_FLAG_NO_INVERSIONS = 1 << 1, // 0x2 + RIDE_ENTRY_FLAG_NO_BANKED_TRACK = 1 << 2, // 0x4 RIDE_ENTRY_FLAG_3 = 1 << 3, // 0x8 RIDE_ENTRY_FLAG_4 = 1 << 4, // 0x10 RIDE_ENTRY_FLAG_5 = 1 << 5, // 0x20 diff --git a/src/ride/track.c b/src/ride/track.c index 3479b7d600..95ac0c2378 100644 --- a/src/ride/track.c +++ b/src/ride/track.c @@ -4245,4 +4245,32 @@ void game_command_set_brakes_speed(int *eax, int *ebx, int *ecx, int *edx, int * } while (!map_element_is_last_for_tile(mapElement++)); *ebx = 0; -} \ No newline at end of file +} + +void track_circuit_iterator_begin(track_circuit_iterator *it, rct_xy_element first) +{ + it->last = first; + it->first = NULL; + it->firstIteration = true; + it->looped = false; +} + +bool track_circuit_iterator_next(track_circuit_iterator *it) +{ + if (it->first == NULL) { + if (!track_block_get_next(&it->last, &it->current, &it->currentZ, &it->currentDirection)) + return false; + + it->first = it->current.element; + return true; + } else { + if (!it->firstIteration && it->first == it->current.element) { + it->looped = true; + return false; + } + + it->firstIteration = false; + it->last = it->current; + return track_block_get_next(&it->last, &it->current, &it->currentZ, &it->currentDirection); + } +} diff --git a/src/ride/track.h b/src/ride/track.h index 98b43c27dc..a45588ac9c 100644 --- a/src/ride/track.h +++ b/src/ride/track.h @@ -480,6 +480,16 @@ enum { TRACK_ELEM_LEFT_LARGE_HALF_LOOP_DOWN }; +typedef struct { + rct_xy_element last; + rct_xy_element current; + int currentZ; + int currentDirection; + rct_map_element *first; + bool firstIteration; + bool looped; +} track_circuit_iterator; + extern const rct_trackdefinition *gTrackDefinitions; void track_load_list(ride_list_item item); @@ -509,4 +519,7 @@ void game_command_place_track(int *eax, int *ebx, int *ecx, int *edx, int *esi, void game_command_remove_track(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); void game_command_set_brakes_speed(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); +void track_circuit_iterator_begin(track_circuit_iterator *it, rct_xy_element first); +bool track_circuit_iterator_next(track_circuit_iterator *it); + #endif