mirror of https://github.com/OpenRCT2/OpenRCT2.git
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:
parent
48b71782fe
commit
6acf52ce63
|
@ -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;
|
||||
|
|
168
src/ride/ride.c
168
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4246,3 +4246,31 @@ void game_command_set_brakes_speed(int *eax, int *ebx, int *ecx, int *edx, int *
|
|||
|
||||
*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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue