From 0e6a90c5deb6ec08cd65805750d671eaebb69db4 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Thu, 29 Jan 2015 21:10:34 +0000 Subject: [PATCH] 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