Fix #8829: invalid read in window_guest_open

This commit is contained in:
Ted John 2019-03-09 12:29:33 +00:00
parent d708234489
commit ca023f7c5e
15 changed files with 102 additions and 135 deletions

View File

@ -153,7 +153,7 @@ rct_window* window_banner_open(rct_windownumber number)
viewportWidget = &window_banner_widgets[WIDX_VIEWPORT]; viewportWidget = &window_banner_widgets[WIDX_VIEWPORT];
viewport_create( viewport_create(
w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 2, w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 2,
(viewportWidget->bottom - viewportWidget->top) - 2, 0, view_x, view_y, view_z, 0, -1); (viewportWidget->bottom - viewportWidget->top) - 2, 0, view_x, view_y, view_z, 0, SPRITE_INDEX_NULL);
w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0; w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
window_invalidate(w); window_invalidate(w);
@ -345,7 +345,7 @@ static void window_banner_viewport_rotate(rct_window* w)
rct_widget* viewportWidget = &window_banner_widgets[WIDX_VIEWPORT]; rct_widget* viewportWidget = &window_banner_widgets[WIDX_VIEWPORT];
viewport_create( viewport_create(
w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 1, w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 1,
(viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, -1); (viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, SPRITE_INDEX_NULL);
w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0; w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
window_invalidate(w); window_invalidate(w);

View File

@ -13,6 +13,7 @@
#include <openrct2/Context.h> #include <openrct2/Context.h>
#include <openrct2/localisation/StringIds.h> #include <openrct2/localisation/StringIds.h>
#include <openrct2/world/Footpath.h> #include <openrct2/world/Footpath.h>
#include <openrct2/world/Sprite.h>
static void window_editor_main_paint(rct_window* w, rct_drawpixelinfo* dpi); static void window_editor_main_paint(rct_window* w, rct_drawpixelinfo* dpi);
@ -65,7 +66,7 @@ rct_window* window_editor_main_open()
WC_MAIN_WINDOW, WF_STICK_TO_BACK); WC_MAIN_WINDOW, WF_STICK_TO_BACK);
window->widgets = window_editor_main_widgets; window->widgets = window_editor_main_widgets;
viewport_create(window, window->x, window->y, window->width, window->height, 0, 0x0FFF, 0x0FFF, 0, 0x1, -1); viewport_create(window, window->x, window->y, window->width, window->height, 0, 0x0FFF, 0x0FFF, 0, 0x1, SPRITE_INDEX_NULL);
window->viewport->flags |= 0x0400; window->viewport->flags |= 0x0400;
gCurrentRotation = 0; gCurrentRotation = 0;

View File

@ -701,98 +701,38 @@ void window_guest_viewport_init(rct_window* w)
if (w->page != WINDOW_GUEST_OVERVIEW) if (w->page != WINDOW_GUEST_OVERVIEW)
return; return;
union auto peep = GET_PEEP(w->number);
if (peep != nullptr)
{ {
sprite_focus sprite; auto focus = viewport_update_smart_guest_follow(w, peep);
coordinate_focus coordinate; bool reCreateViewport = false;
} focus = {}; // The focus will be either a sprite or a coordinate. uint16_t origViewportFlags{};
if (w->viewport != nullptr)
focus.sprite.sprite_id = w->number;
Peep* peep = GET_PEEP(w->number);
if (peep->state == PEEP_STATE_PICKED)
{
focus.sprite.sprite_id = SPRITE_INDEX_NULL;
}
else
{
uint8_t final_check = 1;
if (peep->state == PEEP_STATE_ON_RIDE || peep->state == PEEP_STATE_ENTERING_RIDE
|| (peep->state == PEEP_STATE_LEAVING_RIDE && peep->x == LOCATION_NULL))
{ {
Ride* ride = get_ride(peep->current_ride); // Check all combos, for now skipping y and rot
if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) if (focus.coordinate.x == w->viewport_focus_coordinates.x
{ && (focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK) == w->viewport_focus_coordinates.y
rct_vehicle* train = GET_VEHICLE(ride->vehicles[peep->current_train]); && focus.coordinate.z == w->viewport_focus_coordinates.z
int32_t car = peep->current_car; && focus.coordinate.rotation == w->viewport_focus_coordinates.rotation)
return;
for (; car != 0; car--) origViewportFlags = w->viewport->flags;
{
train = GET_VEHICLE(train->next_vehicle_on_train);
}
focus.sprite.sprite_id = train->sprite_index; reCreateViewport = true;
final_check = 0; w->viewport->width = 0;
} w->viewport = nullptr;
} }
if (peep->x == LOCATION_NULL && final_check)
window_event_invalidate_call(w);
w->viewport_focus_coordinates.x = focus.coordinate.x;
w->viewport_focus_coordinates.y = focus.coordinate.y;
w->viewport_focus_coordinates.z = focus.coordinate.z;
w->viewport_focus_coordinates.rotation = focus.coordinate.rotation;
if (peep->state != PEEP_STATE_PICKED && w->viewport == nullptr)
{ {
Ride* ride = get_ride(peep->current_ride); auto view_widget = &w->widgets[WIDX_VIEWPORT];
int32_t x = ride->overall_view.x * 32 + 16;
int32_t y = ride->overall_view.y * 32 + 16;
int32_t height = tile_element_height(x, y);
height += 32;
focus.coordinate.x = x;
focus.coordinate.y = y;
focus.coordinate.z = height;
focus.sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE;
}
else
{
focus.sprite.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE;
focus.sprite.pad_486 &= 0xFFFF;
}
focus.coordinate.rotation = get_current_rotation();
}
uint16_t viewport_flags;
if (w->viewport)
{
// Check all combos, for now skipping y and rot
if (focus.coordinate.x == w->viewport_focus_coordinates.x
&& (focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK) == w->viewport_focus_coordinates.y
&& focus.coordinate.z == w->viewport_focus_coordinates.z
&& focus.coordinate.rotation == w->viewport_focus_coordinates.rotation)
return;
viewport_flags = w->viewport->flags;
w->viewport->width = 0;
w->viewport = nullptr;
}
else
{
viewport_flags = 0;
if (gConfigGeneral.always_show_gridlines)
{
viewport_flags |= VIEWPORT_FLAG_GRIDLINES;
}
}
window_event_invalidate_call(w);
w->viewport_focus_coordinates.x = focus.coordinate.x;
w->viewport_focus_coordinates.y = focus.coordinate.y;
w->viewport_focus_coordinates.z = focus.coordinate.z;
w->viewport_focus_coordinates.rotation = focus.coordinate.rotation;
if (peep->state != PEEP_STATE_PICKED)
{
if (!(w->viewport))
{
rct_widget* view_widget = &w->widgets[WIDX_VIEWPORT];
int32_t x = view_widget->left + 1 + w->x; int32_t x = view_widget->left + 1 + w->x;
int32_t y = view_widget->top + 1 + w->y; int32_t y = view_widget->top + 1 + w->y;
int32_t width = view_widget->right - view_widget->left - 1; int32_t width = view_widget->right - view_widget->left - 1;
@ -801,15 +741,15 @@ void window_guest_viewport_init(rct_window* w)
viewport_create( viewport_create(
w, x, y, width, height, 0, focus.coordinate.x, focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK, focus.coordinate.z, w, x, y, width, height, 0, focus.coordinate.x, focus.coordinate.y & VIEWPORT_FOCUS_Y_MASK, focus.coordinate.z,
focus.sprite.type & VIEWPORT_FOCUS_TYPE_MASK, focus.sprite.sprite_id); focus.sprite.type & VIEWPORT_FOCUS_TYPE_MASK, focus.sprite.sprite_id);
if (w->viewport != nullptr && reCreateViewport)
{
w->viewport->flags = origViewportFlags;
}
w->flags |= WF_NO_SCROLLING; w->flags |= WF_NO_SCROLLING;
window_invalidate(w); window_invalidate(w);
} }
window_invalidate(w);
} }
if (w->viewport)
w->viewport->flags = viewport_flags;
window_invalidate(w);
} }
/** /**

View File

@ -13,6 +13,7 @@
#include <openrct2/Context.h> #include <openrct2/Context.h>
#include <openrct2/localisation/StringIds.h> #include <openrct2/localisation/StringIds.h>
#include <openrct2/world/Footpath.h> #include <openrct2/world/Footpath.h>
#include <openrct2/world/Sprite.h>
// clang-format off // clang-format off
static rct_widget window_main_widgets[] = { static rct_widget window_main_widgets[] = {
@ -67,7 +68,7 @@ rct_window* window_main_open()
WF_STICK_TO_BACK); WF_STICK_TO_BACK);
window->widgets = window_main_widgets; window->widgets = window_main_widgets;
viewport_create(window, window->x, window->y, window->width, window->height, 0, 0x0FFF, 0x0FFF, 0, 0x1, -1); viewport_create(window, window->x, window->y, window->width, window->height, 0, 0x0FFF, 0x0FFF, 0, 0x1, SPRITE_INDEX_NULL);
window->viewport->flags |= VIEWPORT_FLAG_SOUND_ON; window->viewport->flags |= VIEWPORT_FLAG_SOUND_ON;
gCurrentRotation = 0; gCurrentRotation = 0;
gShowGridLinesRefCount = 0; gShowGridLinesRefCount = 0;

View File

@ -923,7 +923,7 @@ static void window_park_init_viewport(rct_window* w)
viewport_create( viewport_create(
w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1,
(viewportWidget->right - viewportWidget->left) - 1, (viewportWidget->bottom - viewportWidget->top) - 1, 0, x, y, (viewportWidget->right - viewportWidget->left) - 1, (viewportWidget->bottom - viewportWidget->top) - 1, 0, x, y,
z, w->viewport_focus_sprite.type & VIEWPORT_FOCUS_TYPE_MASK, -1); z, w->viewport_focus_sprite.type & VIEWPORT_FOCUS_TYPE_MASK, SPRITE_INDEX_NULL);
w->flags |= (1 << 2); w->flags |= (1 << 2);
window_invalidate(w); window_invalidate(w);
} }

View File

@ -565,7 +565,7 @@ static void window_player_set_page(rct_window* w, int32_t page)
{ {
if (w->viewport == nullptr) if (w->viewport == nullptr)
{ {
viewport_create(w, w->x, w->y, w->width, w->height, 0, 128 * 32, 128 * 32, 0, 1, -1); viewport_create(w, w->x, w->y, w->width, w->height, 0, 128 * 32, 128 * 32, 0, 1, SPRITE_INDEX_NULL);
w->flags |= WF_NO_SCROLLING; w->flags |= WF_NO_SCROLLING;
window_event_invalidate_call(w); window_event_invalidate_call(w);
window_player_update_viewport(w, false); window_player_update_viewport(w, false);

View File

@ -188,7 +188,7 @@ rct_window* window_sign_open(rct_windownumber number)
viewportWidget = &window_sign_widgets[WIDX_VIEWPORT]; viewportWidget = &window_sign_widgets[WIDX_VIEWPORT];
viewport_create( viewport_create(
w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 1, w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 1,
(viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, -1); (viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, SPRITE_INDEX_NULL);
w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0; w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
window_invalidate(w); window_invalidate(w);
@ -381,7 +381,7 @@ static void window_sign_viewport_rotate(rct_window* w)
rct_widget* viewportWidget = &window_sign_widgets[WIDX_VIEWPORT]; rct_widget* viewportWidget = &window_sign_widgets[WIDX_VIEWPORT];
viewport_create( viewport_create(
w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 1, w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 1,
(viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, -1); (viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, SPRITE_INDEX_NULL);
w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0; w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
window_invalidate(w); window_invalidate(w);
@ -445,7 +445,7 @@ rct_window* window_sign_small_open(rct_windownumber number)
viewportWidget = &window_sign_widgets[WIDX_VIEWPORT]; viewportWidget = &window_sign_widgets[WIDX_VIEWPORT];
viewport_create( viewport_create(
w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 1, w, w->x + viewportWidget->left + 1, w->y + viewportWidget->top + 1, (viewportWidget->right - viewportWidget->left) - 1,
(viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, -1); (viewportWidget->bottom - viewportWidget->top) - 1, 0, view_x, view_y, view_z, 0, SPRITE_INDEX_NULL);
w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0; w->viewport->flags = gConfigGeneral.always_show_gridlines ? VIEWPORT_FLAG_GRIDLINES : 0;
w->flags |= WF_NO_SCROLLING; w->flags |= WF_NO_SCROLLING;

View File

@ -251,7 +251,8 @@ void window_title_command_editor_open(TitleSequence* sequence, int32_t index, bo
rct_widget* const viewportWidget = &window_title_command_editor_widgets[WIDX_VIEWPORT]; rct_widget* const viewportWidget = &window_title_command_editor_widgets[WIDX_VIEWPORT];
viewport_create( viewport_create(
window, window->x + viewportWidget->left + 1, window->y + viewportWidget->top + 1, window, window->x + viewportWidget->left + 1, window->y + viewportWidget->top + 1,
viewportWidget->right - viewportWidget->left - 1, viewportWidget->bottom - viewportWidget->top - 1, 0, 0, 0, 0, 0, -1); viewportWidget->right - viewportWidget->left - 1, viewportWidget->bottom - viewportWidget->top - 1, 0, 0, 0, 0, 0,
SPRITE_INDEX_NULL);
_window_title_command_editor_index = index; _window_title_command_editor_index = index;
_window_title_command_editor_insert = insert; _window_title_command_editor_insert = insert;

View File

@ -94,7 +94,7 @@ rct_window* window_viewport_open()
w->number = _viewportNumber++; w->number = _viewportNumber++;
// Create viewport // Create viewport
viewport_create(w, w->x, w->y, w->width, w->height, 0, 128 * 32, 128 * 32, 0, 1, -1); viewport_create(w, w->x, w->y, w->width, w->height, 0, 128 * 32, 128 * 32, 0, 1, SPRITE_INDEX_NULL);
rct_window* mainWindow = window_get_main(); rct_window* mainWindow = window_get_main();
if (mainWindow != nullptr) if (mainWindow != nullptr)
{ {

View File

@ -145,7 +145,7 @@ void centre_2d_coordinates(int32_t x, int32_t y, int32_t z, int32_t* out_x, int3
*/ */
void viewport_create( void viewport_create(
rct_window* w, int32_t x, int32_t y, int32_t width, int32_t height, int32_t zoom, int32_t centre_x, int32_t centre_y, rct_window* w, int32_t x, int32_t y, int32_t width, int32_t height, int32_t zoom, int32_t centre_x, int32_t centre_y,
int32_t centre_z, char flags, int16_t sprite) int32_t centre_z, char flags, uint16_t sprite)
{ {
rct_viewport* viewport = nullptr; rct_viewport* viewport = nullptr;
for (int32_t i = 0; i < MAX_VIEWPORT_COUNT; i++) for (int32_t i = 0; i < MAX_VIEWPORT_COUNT; i++)
@ -686,55 +686,53 @@ void viewport_update_smart_sprite_follow(rct_window* window)
} }
} }
void viewport_update_smart_guest_follow(rct_window* window, Peep* peep) viewport_focus viewport_update_smart_guest_follow(rct_window* window, Peep* peep)
{ {
union viewport_focus focus{};
{ focus.type = VIEWPORT_FOCUS_TYPE_SPRITE;
sprite_focus sprite; focus.sprite.sprite_id = peep->sprite_index;
coordinate_focus coordinate;
} focus = {}; // The focus will be either a sprite or a coordinate.
focus.sprite.sprite_id = window->viewport_smart_follow_sprite;
if (peep->state == PEEP_STATE_PICKED) if (peep->state == PEEP_STATE_PICKED)
{ {
// focus.sprite.sprite_id = SPRITE_INDEX_NULL; focus.sprite.sprite_id = SPRITE_INDEX_NULL;
window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL; window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL;
window->viewport_target_sprite = SPRITE_INDEX_NULL; window->viewport_target_sprite = SPRITE_INDEX_NULL;
return; return focus;
} }
else else
{ {
uint8_t final_check = 1; bool overallFocus = true;
if (peep->state == PEEP_STATE_ON_RIDE || peep->state == PEEP_STATE_ENTERING_RIDE if (peep->state == PEEP_STATE_ON_RIDE || peep->state == PEEP_STATE_ENTERING_RIDE
|| (peep->state == PEEP_STATE_LEAVING_RIDE && peep->x == LOCATION_NULL)) || (peep->state == PEEP_STATE_LEAVING_RIDE && peep->x == LOCATION_NULL))
{ {
Ride* ride = get_ride(peep->current_ride); Ride* ride = get_ride(peep->current_ride);
if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK)
{ {
rct_vehicle* train = GET_VEHICLE(ride->vehicles[peep->current_train]); auto train = GET_VEHICLE(ride->vehicles[peep->current_train]);
int32_t car = peep->current_car; if (train != nullptr)
for (; car != 0; car--)
{ {
train = GET_VEHICLE(train->next_vehicle_on_train); auto car = train->GetCar(peep->current_car);
if (car != nullptr)
{
focus.sprite.sprite_id = car->sprite_index;
overallFocus = false;
}
} }
focus.sprite.sprite_id = train->sprite_index;
final_check = 0;
} }
} }
if (peep->x == LOCATION_NULL && final_check) if (peep->x == LOCATION_NULL && overallFocus)
{ {
Ride* ride = get_ride(peep->current_ride); auto ride = get_ride(peep->current_ride);
int32_t x = ride->overall_view.x * 32 + 16; if (ride != nullptr)
int32_t y = ride->overall_view.y * 32 + 16; {
int32_t height = tile_element_height(x, y); auto x = (int32_t)ride->overall_view.x * 32 + 16;
height += 32; auto y = (int32_t)ride->overall_view.y * 32 + 16;
focus.coordinate.x = x; focus.type = VIEWPORT_FOCUS_TYPE_COORDINATE;
focus.coordinate.y = y; focus.coordinate.x = x;
focus.coordinate.z = height; focus.coordinate.y = y;
focus.sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE; focus.coordinate.z = tile_element_height(x, y) + 32;
focus.sprite.type |= VIEWPORT_FOCUS_TYPE_COORDINATE;
}
} }
else else
{ {
@ -746,6 +744,7 @@ void viewport_update_smart_guest_follow(rct_window* window, Peep* peep)
window->viewport_focus_sprite = focus.sprite; window->viewport_focus_sprite = focus.sprite;
window->viewport_target_sprite = window->viewport_focus_sprite.sprite_id; window->viewport_target_sprite = window->viewport_focus_sprite.sprite_id;
return focus;
} }
void viewport_update_smart_staff_follow(rct_window* window, Peep* peep) void viewport_update_smart_staff_follow(rct_window* window, Peep* peep)

View File

@ -122,11 +122,11 @@ void viewport_init_all();
void centre_2d_coordinates(int32_t x, int32_t y, int32_t z, int32_t* out_x, int32_t* out_y, rct_viewport* viewport); void centre_2d_coordinates(int32_t x, int32_t y, int32_t z, int32_t* out_x, int32_t* out_y, rct_viewport* viewport);
void viewport_create( void viewport_create(
rct_window* w, int32_t x, int32_t y, int32_t width, int32_t height, int32_t zoom, int32_t centre_x, int32_t centre_y, rct_window* w, int32_t x, int32_t y, int32_t width, int32_t height, int32_t zoom, int32_t centre_x, int32_t centre_y,
int32_t centre_z, char flags, int16_t sprite); int32_t centre_z, char flags, uint16_t sprite);
void viewport_update_position(rct_window* window); void viewport_update_position(rct_window* window);
void viewport_update_sprite_follow(rct_window* window); void viewport_update_sprite_follow(rct_window* window);
void viewport_update_smart_sprite_follow(rct_window* window); void viewport_update_smart_sprite_follow(rct_window* window);
void viewport_update_smart_guest_follow(rct_window* window, Peep* peep); viewport_focus viewport_update_smart_guest_follow(rct_window* window, Peep* peep);
void viewport_update_smart_staff_follow(rct_window* window, Peep* peep); void viewport_update_smart_staff_follow(rct_window* window, Peep* peep);
void viewport_update_smart_vehicle_follow(rct_window* window); void viewport_update_smart_vehicle_follow(rct_window* window);
void viewport_render( void viewport_render(

View File

@ -148,13 +148,23 @@ struct sprite_focus
}; };
#define VIEWPORT_FOCUS_TYPE_MASK 0xC0 #define VIEWPORT_FOCUS_TYPE_MASK 0xC0
enum enum VIEWPORT_FOCUS_TYPE : uint8_t
{ {
VIEWPORT_FOCUS_TYPE_COORDINATE = (1 << 6), VIEWPORT_FOCUS_TYPE_COORDINATE = (1 << 6),
VIEWPORT_FOCUS_TYPE_SPRITE = (1 << 7) VIEWPORT_FOCUS_TYPE_SPRITE = (1 << 7)
}; };
#define VIEWPORT_FOCUS_Y_MASK 0x3FFF #define VIEWPORT_FOCUS_Y_MASK 0x3FFF
struct viewport_focus
{
VIEWPORT_FOCUS_TYPE type{};
union
{
sprite_focus sprite;
coordinate_focus coordinate;
};
};
struct rct_window_event_list struct rct_window_event_list
{ {
void (*close)(struct rct_window*); void (*close)(struct rct_window*);

View File

@ -10002,3 +10002,13 @@ const rct_vehicle* rct_vehicle::GetHead() const
{ {
return ((rct_vehicle*)this)->GetHead(); return ((rct_vehicle*)this)->GetHead();
} }
const rct_vehicle* rct_vehicle::GetCar(size_t carIndex) const
{
auto car = this;
for (; carIndex != 0; carIndex--)
{
car = GET_VEHICLE(car->next_vehicle_on_train);
}
return car;
}

View File

@ -233,6 +233,7 @@ struct rct_vehicle : rct_sprite_common
} }
rct_vehicle* GetHead(); rct_vehicle* GetHead();
const rct_vehicle* GetHead() const; const rct_vehicle* GetHead() const;
const rct_vehicle* GetCar(size_t carIndex) const;
}; };
struct train_ref struct train_ref

View File

@ -80,6 +80,10 @@ rct_sprite* try_get_sprite(size_t spriteIndex)
rct_sprite* get_sprite(size_t sprite_idx) rct_sprite* get_sprite(size_t sprite_idx)
{ {
if (sprite_idx == SPRITE_INDEX_NULL)
{
return nullptr;
}
openrct2_assert(sprite_idx < MAX_SPRITES, "Tried getting sprite %u", sprite_idx); openrct2_assert(sprite_idx < MAX_SPRITES, "Tried getting sprite %u", sprite_idx);
return &_spriteList[sprite_idx]; return &_spriteList[sprite_idx];
} }