1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-10 09:32:29 +01:00

Merge branch 'set-ride-status' into develop

Conflicts:
	src/ride/track.h
This commit is contained in:
IntelOrca
2015-02-17 17:00:47 +00:00
13 changed files with 824 additions and 95 deletions

View File

@@ -840,7 +840,7 @@ static uint32 game_do_command_table[58] = {
0,
0x006B3F0F,
0x006B49D9,
0x006B4EA6,
0,
0x006B52D4,
0, // 10
0x006B5559,
@@ -903,7 +903,7 @@ static GAME_COMMAND_POINTER* new_game_command_table[58] = {
game_load_or_quit,
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,

View File

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

View File

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

View File

@@ -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,
@@ -1255,6 +1264,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,

View File

@@ -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
@@ -265,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);
@@ -283,51 +284,99 @@ 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
*/
int track_get_next(rct_xy_element *input, rct_xy_element *output)
{
int eax, ebx, ecx, edx, esi, edi, ebp, result;
eax = input->x;
ecx = input->y;
esi = (int)input->element;
result = RCT2_CALLFUNC_X(0x006C60C2, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp);
output->x = *((uint16*)&eax);
output->y = *((uint16*)&ecx);
output->element = (rct_map_element*)esi;
return (result & 0x100) == 0;
}
/**
*
* Make sure to pass in the x and y of the start track element too.
* rct2: 0x006CB02F
* ax result x
* 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 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;
rct_xy_element trackElement, nextTrackElement;
rct_map_element *loopTrackElement;
rct_ride *ride;
rct_window *w;
if (outX != NULL) *outX = eax & 0xFFFF;
if (outY != NULL) *outY = ecx & 0xFFFF;
return (rct_map_element*)esi;
trackElement = *input;
rideIndex = trackElement.element->properties.track.ride_index;
ride = GET_RIDE(rideIndex);
if (ride->type == RIDE_TYPE_MAZE)
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();
loopTrackElement = NULL;
while (1) {
if (!track_get_next(&trackElement, &nextTrackElement)) {
*output = trackElement;
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;
}
return 0;
}
/**
@@ -855,13 +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;
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))
@@ -885,24 +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;
mapElement = ride_find_track_gap(mapElement, &outX, &outY);
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;
@@ -1924,7 +1978,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;
@@ -1932,10 +1986,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;
}
/**
@@ -1961,8 +2015,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;
@@ -1977,9 +2031,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;
@@ -2690,6 +2746,624 @@ void ride_music_update_final()
#pragma endregion
/**
*
* rct2: 0x006B4CC1
*/
int ride_mode_check_valid_station_numbers(rct_ride *ride)
{
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 <= 1) 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 <= 1) return 1;
RCT2_GLOBAL(0x141E9AC, uint16) = 1015;
return 0;
}
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
*/
int ride_check_for_entrance_exit(int rideIndex)
{
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 = 1;
}
if (ride->exits[i] != 0xFFFF) {
exit = 1;
}
// If station start and no entrance/exit
// Sets same error message as no entrance
if (ride->exits[i] == 0xFFFF && ride->entrances[i] == 0xFFFF){
entrance = 0;
break;
}
}
if (entrance == 0){
RCT2_GLOBAL(0x141E9AC, uint16) = 1146;
return 0;
}
if (exit == 0){
RCT2_GLOBAL(0x141E9AC, uint16) = 1147;
return 0;
}
return 1;
}
/**
*
* rct2: 0x006B5952
*/
void sub_6B5952(int rideIndex)
{
RCT2_CALLPROC_X(0x006B5952, 0, 0, 0, rideIndex, 0, 0, 0);
}
/**
*
* rct2: 0x006D3319
*/
int ride_check_block_brakes(rct_xy_element *input, rct_xy_element *output)
{
// 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;
*output = trackElement;
return 0;
}
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;
}
}
trackElement = nextTrackElement;
if (loopTrackElement == NULL)
loopTrackElement = trackElement.element;
else if (loopTrackElement == trackElement.element)
break;
}
return 1;
}
/**
*
* rct2: 0x006CB149
*/
int ride_check_track_suitability_a(rct_xy_element *input, rct_xy_element *output)
{
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 = (uint16)eax;
output->y = (uint16)ecx;
output->element = (rct_map_element*)esi;
return (result & 0x100) != 0;
}
/**
*
* rct2: 0x006CB1D3
*/
int ride_check_track_suitability_b(rct_xy_element *input, rct_xy_element *output)
{
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 = (uint16)eax;
output->y = (uint16)ecx;
output->element = (rct_map_element*)esi;
return (result & 0x100) != 0;
}
/**
*
* rct2: 0x006CB25D
*/
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 = (uint16)eax;
output->y = (uint16)ecx;
output->element = (rct_map_element*)esi;
return (result & 0x100) != 0;
}
/**
*
* rct2: 0x006CB2DA
*/
int ride_check_start_and_end_is_station(rct_xy_element *input, rct_xy_element *output)
{
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 = (uint16)eax;
output->y = (uint16)ecx;
output->element = (rct_map_element*)esi;
return (result & 0x100) != 0;
}
/**
*
* rct2: 0x006B4D26
*/
void sub_6B4D26(int rideIndex, rct_xy_element *startElement)
{
RCT2_CALLPROC_X(0x006B4D26, startElement->x, 0, startElement->y, rideIndex, (int)startElement->element, 0, 0); return;
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(&currentElement, &currentElement) && currentElement.element != startElement->element);
}
}
/**
*
* rct2: 0x006DD84C
*/
int sub_6DD84C(rct_ride *ride, int rideIndex, rct_xy_element *element, int isApplying)
{
return RCT2_CALLPROC_X(0x006DD84C, element->x, isApplying, element->y, rideIndex, (int)ride, (int)element->element, 0) & 0x100;
}
/**
*
* rct2: 0x006DF4D4
*/
int sub_6DF4D4(rct_ride *ride, rct_xy_element *element, int isApplying)
{
return RCT2_CALLPROC_X(0x006DF4D4, element->x, isApplying, element->y, 0, (int)ride, (int)element->element, 0) & 0x100;
}
/**
*
* rct2: 0x006B51C0
*/
void loc_6B51C0(int rideIndex)
{
int i, x, y, z;
rct_ride *ride;
rct_xy_element trackElement;
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;
sint8 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] & 0xFF) * 32;
y = (ride->station_starts[i] >> 8) * 32;
z = ride->station_heights[i] * 8;
window_scroll_to_location(w, x, y, z);
sub_6CAF80(rideIndex, &trackElement);
ride_find_track_gap(&trackElement, &trackElement);
ride_modify(&trackElement);
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_xy_element *trackElement)
{
rct_ride *ride;
rct_window *w;
ride = GET_RIDE(trackElement->element->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, trackElement->x, trackElement->y, trackElement->element->base_height * 8);
ride_modify(trackElement);
}
/**
*
* rct2: 0x006B4F6B
*/
rct_map_element *loc_6B4F6B(int rideIndex, int x, int y)
{
rct_map_element *mapElement;
mapElement = map_get_first_element_at(x / 32, y / 32);
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 stationIndex;
rct_ride *ride;
rct_xy_element trackElement, problematicTrackElement;
ride = GET_RIDE(rideIndex);
window_close_by_class(WC_RIDE_CONSTRUCTION);
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)) {
loc_6B51C0(rideIndex);
return 0;
}
if (goingToBeOpen && isApplying) {
sub_6B5952(rideIndex);
ride->lifecycle_flags |= RIDE_LIFECYCLE_EVER_BEEN_OPENED;
}
// z = ride->station_heights[i] * 8;
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
if (ride->type != RIDE_TYPE_MAZE)
return 0;
}
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
) {
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;
}
}
if (
ride->mode == RIDE_MODE_CONTINUOUS_CIRCUIT_BLOCK_SECTIONED ||
ride->mode == RIDE_MODE_POWERED_LAUNCH_BLOCK_SECTIONED
) {
if (!ride_check_block_brakes(&trackElement, &problematicTrackElement)) {
loc_6B528A(&problematicTrackElement);
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, 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, 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) {
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, uint16) = STR_STATION_NOT_LONG_ENOUGH;
if (ride_check_station_length(&trackElement, &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;
}
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;
}
}
if (isApplying)
sub_6B4D26(rideIndex, &trackElement);
if (
!(RCT2_GLOBAL(RCT2_ADDRESS_RIDE_FLAGS + (ride->type * 8), uint32) & 0x2000) &&
!(ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)
) {
if (sub_6DD84C(ride, rideIndex, &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)
) {
if (sub_6DF4D4(ride, &trackElement, isApplying))
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) {
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;

View File

@@ -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
@@ -613,11 +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 *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);
@@ -638,6 +639,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);

View File

@@ -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,13 +203,13 @@ 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;
rct_ride *ride;
rct_map_element *mapElement;
rct_xy_element trackElement, nextTrackElement;
int x, y, z, trackType, entranceIndex;
ride = GET_RIDE(_rideRatingsCurrentRide);
@@ -255,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 (!sub_6C60C2(mapElement, &x, &y, &z)) {
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;

View File

@@ -34,7 +34,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
@@ -540,10 +543,10 @@ rct_track_td6* load_track_design(const char *path)
uint8* track_element = track_elements;
while (*track_element != 255) {
track_element += 2;
}
}
track_element++;
memset(track_element, 255, final_track_element_location - track_element);
}
}
// Edit the colours to use the new versions
// Unsure why it is 67
@@ -1029,7 +1032,7 @@ rct_track_design *track_get_info(int index, uint8** preview)
}
trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, rct_track_design*)[i];
// Copy the track design apart from the preview image
memcpy(&trackDesign->track_td6, loaded_track, sizeof(rct_track_td6));
// Load in a new preview image, calculate cost variable, calculate var_06
@@ -1124,3 +1127,40 @@ int track_delete()
window_invalidate(w);
return 1;
}
/**
* 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;
}

View File

@@ -22,8 +22,8 @@
#define _TRACK_H_
#include "../common.h"
#include "ride.h"
#include "../object.h"
#include "ride.h"
typedef struct {
uint8 type;
@@ -204,6 +204,8 @@ 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);
@@ -211,6 +213,7 @@ rct_track_td6* load_track_design(const char *path);
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);
int sub_6D01B3(int bl, int x, int y, int z);
#endif

View File

@@ -1531,24 +1531,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);
}
}
@@ -1845,9 +1842,9 @@ 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;
game_do_command(0, 1, 0, w->number | (status << 8), GAME_COMMAND_SET_RIDE_OPEN, 0, 0);
ride_set_status(w->number, status);
break;
}
}

View File

@@ -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(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;
}
window_ride_main_open(ride_id);
window_ride_main_open(rideIndex);
}

View File

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

View File

@@ -217,6 +217,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;