implement ride_check_track_contains_inversions, ride_check_track_contains_banked, refactor track circuit iteration and fix window event bug with hook

This commit is contained in:
IntelOrca 2015-07-11 22:51:11 +01:00
parent 48b71782fe
commit 6acf52ce63
5 changed files with 137 additions and 81 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}
}
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);
}
}

View File

@ -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