diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 400338d5bf..7daad8021b 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -4488,8 +4488,14 @@ STR_6178 :Load{MOVE_X}{87}{RED}Missing scenario STR_6179 :Select STR_6180 :No scenario selected STR_6181 :{RED}Missing scenario -STR_6182 :Follow sprite -STR_6183 :Select sprite +STR_6182 :Follow{MOVE_X}{87}{STRING} +STR_6183 :Follow{MOVE_X}{87}No sprite selected +STR_6184 :Follow Sprite +STR_6185 :Select Sprite +STR_6186 :No sprite selected +STR_6187 :{MEDIUMFONT}{OUTLINE}{WINDOW_COLOUR_2}{STRING} +STR_6188 :Vomit +STR_6189 :Duck ############# # Scenarios # diff --git a/distribution/changelog.txt b/distribution/changelog.txt index f2d1a1ac9f..5bb817f62d 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -2,6 +2,7 @@ ------------------------------------------------------------------------ - Feature: [#3510] Auto-append extension if none is specified. - Feature: [#3994] Show bottom toolbar with map tooltip (theme option). +- Feature: [#4906] Add follow sprite command to title sequences. - Feature: [#5826] Add the show_limits command to show map data counts and limits. - Feature: [#6078] Game now converts mp.dat to SC21.SC4 (Mega Park) automatically. - Feature: [#6125] Path can now be placed in park entrances. diff --git a/src/openrct2-ui/input/MouseInput.cpp b/src/openrct2-ui/input/MouseInput.cpp index 210009c035..59509c7354 100644 --- a/src/openrct2-ui/input/MouseInput.cpp +++ b/src/openrct2-ui/input/MouseInput.cpp @@ -531,6 +531,7 @@ static void input_viewport_drag_begin(rct_window * w, sint32 x, sint32 y) context_get_cursor_position(&gInputDragLastX, &gInputDragLastY); context_hide_cursor(); + window_unfollow_sprite(w); // gInputFlags |= INPUT_FLAG_5; } diff --git a/src/openrct2-ui/windows/TitleCommandEditor.cpp b/src/openrct2-ui/windows/TitleCommandEditor.cpp index 1372e18743..966fc9ed93 100644 --- a/src/openrct2-ui/windows/TitleCommandEditor.cpp +++ b/src/openrct2-ui/windows/TitleCommandEditor.cpp @@ -106,7 +106,7 @@ static rct_widget window_title_command_editor_widgets[] = { { WWT_DROPDOWN_BUTTON, 1, WS+WHA+12, WW-WS-1, BY2-14, BY2-3, STR_TITLE_COMMAND_EDITOR_ACTION_SELECT_SCENARIO, STR_NONE }, // Select scenario { WWT_DROPDOWN_BUTTON, 1, WS, WW-WS-1, BY2-14, BY2-3, STR_TITLE_COMMAND_EDITOR_SELECT_SPRITE, STR_NONE }, // Select sprite - { WWT_VIEWPORT, 1, WS, WW-WS - 1, BY2, BY2+22, STR_NONE, STR_NONE }, // Viewport + { WWT_VIEWPORT, 1, WS, WW-WS-1, BY2, BY2+22, STR_NONE, STR_NONE }, // Viewport { WWT_DROPDOWN_BUTTON, 1, 10, 80, WH-21, WH-10, STR_OK, STR_NONE }, // OKAY { WWT_DROPDOWN_BUTTON, 1, WW-80, WW-10, WH-21, WH-10, STR_CANCEL, STR_NONE }, // Cancel @@ -173,7 +173,7 @@ static void scenario_select_callback(const utf8 * path) static sint32 get_command_info_index(sint32 index) { - for (sint32 i = 0; i < NUM_COMMANDS; i++) + for (sint32 i = 0; i < (sint32)NUM_COMMANDS; i++) { if (_window_title_command_editor_orders[i].command == index) return i; @@ -183,7 +183,7 @@ static sint32 get_command_info_index(sint32 index) static TITLE_COMMAND_ORDER get_command_info(sint32 index) { - for (sint32 i = 0; i < NUM_COMMANDS; i++) + for (sint32 i = 0; i < (sint32)NUM_COMMANDS; i++) { if (_window_title_command_editor_orders[i].command == index) return _window_title_command_editor_orders[i]; @@ -267,7 +267,7 @@ void window_title_command_editor_open(TitleSequence * sequence, sint32 index, bo window_init_scroll_widgets(window); rct_widget *const viewportWidget = &window_title_command_editor_widgets[WIDX_VIEWPORT]; - viewport_create(window, window->x + viewportWidget->left, window->y + viewportWidget->top, viewportWidget->right - viewportWidget->left, viewportWidget->bottom - viewportWidget->top, 0, 0, 0, 0, 0, -1); + viewport_create(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); _window_title_command_editor_index = index; _window_title_command_editor_insert = insert; @@ -293,6 +293,12 @@ void window_title_command_editor_open(TitleSequence * sequence, sint32 index, bo case TITLE_SCRIPT_WAIT: snprintf(textbox1Buffer, BUF_SIZE, "%d", command.Milliseconds); break; + case TITLE_SCRIPT_FOLLOW: + if (command.SpriteIndex != SPRITE_INDEX_NULL) + { + window_follow_sprite(window, (size_t)command.SpriteIndex); + } + break; } } @@ -391,8 +397,8 @@ static void window_title_command_editor_mousedown(rct_window * w, rct_widgetinde { case WIDX_COMMAND_DROPDOWN: { - sint32 numItems = NUM_COMMANDS; - for (sint32 i = 0; i < numItems; i++) + size_t numItems = NUM_COMMANDS; + for (size_t i = 0; i < numItems; i++) { gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; gDropdownItemsArgs[i] = _window_title_command_editor_orders[i].nameStringId; @@ -432,7 +438,8 @@ static void window_title_command_editor_mousedown(rct_window * w, rct_widgetinde widget->right - widget->left - 3); dropdown_set_checked(command.Speed - 1, true); - } else if (command.Type == TITLE_SCRIPT_LOAD) + } + else if (command.Type == TITLE_SCRIPT_LOAD) { sint32 numItems = (sint32)_sequence->NumSaves; for (sint32 i = 0; i < numItems; i++) @@ -471,6 +478,10 @@ static void window_title_command_editor_dropdown(rct_window * w, rct_widgetindex switch (widgetIndex) { case WIDX_COMMAND_DROPDOWN: + if (command.SpriteIndex != SPRITE_INDEX_NULL) + { + window_unfollow_sprite(w); + } if (dropdownIndex == get_command_info_index(command.Type)) { break; @@ -497,6 +508,9 @@ static void window_title_command_editor_dropdown(rct_window * w, rct_widgetindex break; case TITLE_SCRIPT_FOLLOW: command.SpriteIndex = SPRITE_INDEX_NULL; + command.SpriteName[0] = '\0'; + window_unfollow_sprite(w); + w->viewport->flags &= ~VIEWPORT_FOCUS_TYPE_SPRITE; break; case TITLE_SCRIPT_SPEED: command.Speed = 1; @@ -626,9 +640,56 @@ static void window_title_command_editor_tool_down(rct_window * w, rct_widgetinde if (info.type == VIEWPORT_INTERACTION_ITEM_SPRITE) { - command.SpriteIndex = info.sprite->unknown.sprite_index; - w->viewport_target_sprite = command.SpriteIndex; - w->viewport->flags |= VIEWPORT_FOCUS_TYPE_SPRITE; + uint16 spriteIndex = info.sprite->unknown.sprite_index; + uint16 spriteIdentifier = info.sprite->unknown.sprite_identifier; + bool validSprite = false; + if (spriteIdentifier == SPRITE_IDENTIFIER_PEEP) + { + validSprite = true; + rct_peep * peep = GET_PEEP(spriteIndex); + format_string(command.SpriteName, USER_STRING_MAX_LENGTH, peep->name_string_idx, &peep->id); + } + else if (spriteIdentifier == SPRITE_IDENTIFIER_VEHICLE) + { + validSprite = true; + rct_vehicle * vehicle = GET_VEHICLE(spriteIndex); + Ride * ride = get_ride(vehicle->ride); + set_format_arg(16, uint32, ride->name_arguments); + format_string(command.SpriteName, USER_STRING_MAX_LENGTH, ride->name, &ride->name_arguments); + } + else if (spriteIdentifier == SPRITE_IDENTIFIER_LITTER) + { + rct_litter * litter = &(get_sprite(spriteIndex)->litter); + if (litter->type < Util::CountOf(litterNames)) + { + validSprite = true; + format_string(command.SpriteName, USER_STRING_MAX_LENGTH, litterNames[litter->type], nullptr); + } + } + else if (spriteIdentifier == SPRITE_IDENTIFIER_MISC) + { + if (info.sprite->IsBalloon()) + { + validSprite = true; + format_string(command.SpriteName, USER_STRING_MAX_LENGTH, STR_SHOP_ITEM_SINGULAR_BALLOON, nullptr); + } + else if (info.sprite->IsDuck()) + { + validSprite = true; + format_string(command.SpriteName, USER_STRING_MAX_LENGTH, STR_DUCK, nullptr); + } + } + if (validSprite) + { + command.SpriteIndex = spriteIndex; + window_follow_sprite(w, (size_t)command.SpriteIndex); + } + else + { + command.SpriteIndex = SPRITE_INDEX_NULL; + command.SpriteName[0] = '\0'; + window_unfollow_sprite(w); + } tool_cancel(); window_invalidate(w); } @@ -674,17 +735,20 @@ static void window_title_command_editor_invalidate(rct_window * w) case TITLE_SCRIPT_FOLLOW: window_title_command_editor_widgets[WIDX_SELECT_SPRITE].type = WWT_DROPDOWN_BUTTON; window_title_command_editor_widgets[WIDX_VIEWPORT].type = WWT_VIEWPORT; + // Draw button pressed while the tool is active - w->pressed_widgets &= ~(1 << WIDX_SELECT_SPRITE); if (sprite_selector_tool_is_active()) w->pressed_widgets |= (1 << WIDX_SELECT_SPRITE); + else + w->pressed_widgets &= ~(1 << WIDX_SELECT_SPRITE); + break; } if ((gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) == SCREEN_FLAGS_TITLE_DEMO) - w->disabled_widgets |= (1 << WIDX_GET); + w->disabled_widgets |= (1 << WIDX_GET) | (1 << WIDX_SELECT_SPRITE); else - w->disabled_widgets &= ~(1 << WIDX_GET); + w->disabled_widgets &= ~((1 << WIDX_GET) | (1 << WIDX_SELECT_SPRITE)); } static void window_title_command_editor_paint(rct_window * w, rct_drawpixelinfo * dpi) @@ -722,7 +786,32 @@ static void window_title_command_editor_paint(rct_window * w, rct_drawpixelinfo } if (command.Type == TITLE_SCRIPT_FOLLOW) { - window_draw_viewport(dpi, w); + uint8 colour = COLOUR_BLACK; + rct_string_id spriteString = STR_TITLE_COMMAND_EDITOR_FORMAT_SPRITE_NAME; + if (command.SpriteIndex != SPRITE_INDEX_NULL) + { + window_draw_viewport(dpi, w); + set_format_arg(0, uintptr_t, (uintptr_t)command.SpriteName); + } + else + { + colour = w->colours[1]; + spriteString = STR_TITLE_COMMAND_EDITOR_FOLLOW_NO_SPRITE; + } + + gfx_set_dirty_blocks( + w->x + w->widgets[WIDX_VIEWPORT].left, + w->y + w->widgets[WIDX_VIEWPORT].top, + w->x + w->widgets[WIDX_VIEWPORT].right, + w->y + w->widgets[WIDX_VIEWPORT].bottom); + gfx_draw_string_left_clipped( + dpi, + spriteString, + gCommonFormatArgs, + colour, + w->x + w->widgets[WIDX_VIEWPORT].left + 2, + w->y + w->widgets[WIDX_VIEWPORT].top + 1, + w->widgets[WIDX_VIEWPORT].right - w->widgets[WIDX_VIEWPORT].left - 2); } else if (command.Type == TITLE_SCRIPT_LOAD) { diff --git a/src/openrct2-ui/windows/TitleEditor.cpp b/src/openrct2-ui/windows/TitleEditor.cpp index 87a660dd49..e24a374d2f 100644 --- a/src/openrct2-ui/windows/TitleEditor.cpp +++ b/src/openrct2-ui/windows/TitleEditor.cpp @@ -979,7 +979,15 @@ static void window_title_editor_scrollpaint_commands(rct_window * w, rct_drawpix set_format_arg(0, rct_string_id, SpeedNames[command->Speed - 1]); break; case TITLE_SCRIPT_FOLLOW: - commandName = STR_TITLE_EDITOR_COMMAND_TYPE_FOLLOW; + commandName = STR_TITLE_EDITOR_COMMAND_FOLLOW; + if (command->SpriteIndex == SPRITE_INDEX_NULL) + { + commandName = STR_TITLE_EDITOR_COMMAND_FOLLOW_NO_SPRITE; + } + else + { + set_format_arg(0, uintptr_t, (uintptr_t)command->SpriteName); + } break; case TITLE_SCRIPT_WAIT: commandName = STR_TITLE_EDITOR_COMMAND_WAIT; diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index d40a1ebd08..9c913c197e 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -1345,8 +1345,13 @@ void game_load_init() { viewport_init_all(); game_create_windows(); + mainWindow = window_get_main(); + } + else + { + mainWindow = window_get_main(); + window_unfollow_sprite(mainWindow); } - mainWindow = window_get_main(); if (mainWindow != nullptr) { diff --git a/src/openrct2/interface/viewport.c b/src/openrct2/interface/viewport.c index 370199028b..f80e3bb63f 100644 --- a/src/openrct2/interface/viewport.c +++ b/src/openrct2/interface/viewport.c @@ -517,6 +517,11 @@ void viewport_update_position(rct_window * window) rct_viewport * viewport = window->viewport; if (!viewport) return; + if (window->viewport_smart_follow_sprite != SPRITE_INDEX_NULL) + { + viewport_update_smart_sprite_follow(window); + } + if (window->viewport_target_sprite != SPRITE_INDEX_NULL) { viewport_update_sprite_follow(window); @@ -620,10 +625,144 @@ void viewport_update_sprite_follow(rct_window *window) centre_2d_coordinates(sprite->unknown.x, sprite->unknown.y, sprite->unknown.z, ¢re_x, ¢re_y, window->viewport); + window->saved_view_x = centre_x; + window->saved_view_y = centre_y; viewport_move(centre_x, centre_y, window, window->viewport); } } +void viewport_update_smart_sprite_follow(rct_window * window) +{ + rct_sprite * sprite = try_get_sprite(window->viewport_smart_follow_sprite); + if (sprite == NULL) + { + window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL; + window->viewport_target_sprite = SPRITE_INDEX_NULL; + } + else if (sprite->unknown.sprite_identifier == SPRITE_IDENTIFIER_PEEP) + { + rct_peep * peep = GET_PEEP(window->viewport_smart_follow_sprite); + + if (peep->type == PEEP_TYPE_GUEST) + viewport_update_smart_guest_follow(window, peep); + else if (peep->type == PEEP_TYPE_STAFF) + viewport_update_smart_staff_follow(window, peep); + } + else if (sprite->unknown.sprite_identifier == SPRITE_IDENTIFIER_VEHICLE) + { + rct_vehicle * vehicle = GET_VEHICLE(window->viewport_smart_follow_sprite); + viewport_update_smart_vehicle_follow(window, vehicle); + } + else if (sprite->unknown.sprite_identifier == SPRITE_IDENTIFIER_MISC || + sprite->unknown.sprite_identifier == SPRITE_IDENTIFIER_LITTER) + { + window->viewport_focus_sprite.sprite_id = window->viewport_smart_follow_sprite; + window->viewport_target_sprite = window->viewport_smart_follow_sprite; + } + else + { + window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL; + window->viewport_target_sprite = SPRITE_INDEX_NULL; + } +} + +void viewport_update_smart_guest_follow(rct_window * window, rct_peep * peep) +{ + union + { + sprite_focus sprite; + coordinate_focus coordinate; + } focus = { 0 }; // 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) + { + //focus.sprite.sprite_id = SPRITE_INDEX_NULL; + window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL; + window->viewport_target_sprite = SPRITE_INDEX_NULL; + return; + } + else + { + uint8 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); + if (ride->lifecycle_flags & RIDE_LIFECYCLE_ON_TRACK) + { + rct_vehicle * train = GET_VEHICLE(ride->vehicles[peep->current_train]); + sint32 car = peep->current_car; + + for (; car != 0; car--) + { + train = GET_VEHICLE(train->next_vehicle_on_train); + } + + focus.sprite.sprite_id = train->sprite_index; + final_check = 0; + } + } + if (peep->x == LOCATION_NULL && final_check) + { + Ride * ride = get_ride(peep->current_ride); + sint32 x = ride->overall_view.x * 32 + 16; + sint32 y = ride->overall_view.y * 32 + 16; + sint32 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(); + } + + window->viewport_focus_sprite = focus.sprite; + window->viewport_target_sprite = window->viewport_focus_sprite.sprite_id; +} + +void viewport_update_smart_staff_follow(rct_window * window, rct_peep * peep) +{ + sprite_focus focus = { 0 }; + + focus.sprite_id = window->viewport_smart_follow_sprite; + + if (peep->state == PEEP_STATE_PICKED) + { + //focus.sprite.sprite_id = SPRITE_INDEX_NULL; + window->viewport_smart_follow_sprite = SPRITE_INDEX_NULL; + window->viewport_target_sprite = SPRITE_INDEX_NULL; + return; + } + else + { + focus.type |= VIEWPORT_FOCUS_TYPE_SPRITE | VIEWPORT_FOCUS_TYPE_COORDINATE; + } + + window->viewport_focus_sprite = focus; + window->viewport_target_sprite = window->viewport_focus_sprite.sprite_id; +} + +void viewport_update_smart_vehicle_follow(rct_window * window, rct_vehicle * vehicle) +{ + // Can be expanded in the future if needed + sprite_focus focus = { 0 }; + + focus.sprite_id = window->viewport_smart_follow_sprite; + + window->viewport_focus_sprite = focus; + window->viewport_target_sprite = window->viewport_focus_sprite.sprite_id; +} + /** * * rct2: 0x00685C02 diff --git a/src/openrct2/interface/viewport.h b/src/openrct2/interface/viewport.h index 54d5cb1ebc..0a60d54561 100644 --- a/src/openrct2/interface/viewport.h +++ b/src/openrct2/interface/viewport.h @@ -120,6 +120,10 @@ void viewport_create(rct_window *w, sint32 x, sint32 y, sint32 width, sint32 hei void viewport_update_pointers(); void viewport_update_position(rct_window *window); void viewport_update_sprite_follow(rct_window *window); +void viewport_update_smart_sprite_follow(rct_window * window); +void viewport_update_smart_guest_follow(rct_window * window, rct_peep * peep); +void viewport_update_smart_staff_follow(rct_window * window, rct_peep * peep); +void viewport_update_smart_vehicle_follow(rct_window * window, rct_vehicle * vehicle); void viewport_render(rct_drawpixelinfo *dpi, rct_viewport *viewport, sint32 left, sint32 top, sint32 right, sint32 bottom); void viewport_paint(rct_viewport* viewport, rct_drawpixelinfo* dpi, sint16 left, sint16 top, sint16 right, sint16 bottom); diff --git a/src/openrct2/interface/window.c b/src/openrct2/interface/window.c index 3f356d6198..7805c06ed0 100644 --- a/src/openrct2/interface/window.c +++ b/src/openrct2/interface/window.c @@ -473,6 +473,7 @@ rct_window *window_create(sint32 x, sint32 y, sint32 width, sint32 height, rct_w w->var_492 = 0; w->selected_tab = 0; w->var_4AE = 0; + w->viewport_smart_follow_sprite = SPRITE_INDEX_NULL; RCT2_NEW_WINDOW++; colour_scheme_update(w); @@ -1359,6 +1360,9 @@ void window_scroll_to_location(rct_window *w, sint32 x, sint32 y, sint32 z) }; assert(w != NULL); + + window_unfollow_sprite(w); + if (w->viewport) { sint16 height = tile_element_height(x, y); if (z < height - 16) { @@ -2683,3 +2687,17 @@ void window_init_all() gWindowNextSlot = g_window_list; } + +void window_follow_sprite(rct_window * w, size_t spriteIndex) +{ + if (spriteIndex < MAX_SPRITES || spriteIndex == SPRITE_INDEX_NULL) + { + w->viewport_smart_follow_sprite = (uint16)spriteIndex; + } +} + +void window_unfollow_sprite(rct_window * w) +{ + w->viewport_smart_follow_sprite = SPRITE_INDEX_NULL; + w->viewport_target_sprite = SPRITE_INDEX_NULL; +} diff --git a/src/openrct2/interface/window.h b/src/openrct2/interface/window.h index 21aa8bd454..340ea30bdd 100644 --- a/src/openrct2/interface/window.h +++ b/src/openrct2/interface/window.h @@ -319,6 +319,7 @@ typedef struct rct_window { sint8 var_4B9; uint8 colours[6]; // 0x4BA uint8 visibility; // VISIBILITY_CACHE + uint16 viewport_smart_follow_sprite; // Smart following of sprites. Handles setting viewport target sprite etc } rct_window; #define RCT_WINDOW_RIGHT(w) (w->x + w->width) @@ -794,6 +795,9 @@ void window_ride_construction_keyboard_shortcut_next_track(); void window_ride_construction_keyboard_shortcut_build_current(); void window_ride_construction_keyboard_shortcut_demolish_current(); +void window_follow_sprite(rct_window * w, size_t spriteIndex); +void window_unfollow_sprite(rct_window * w); + bool sub_6CA2DF(sint32 *trackType, sint32 *trackDirection, sint32 *rideIndex, sint32 *_liftHillAndAlternativeState, sint32 *x, sint32 *y, sint32 *z, sint32 *properties); money32 place_provisional_track_piece(sint32 rideIndex, sint32 trackType, sint32 trackDirection, sint32 liftHillAndAlternativeState, sint32 x, sint32 y, sint32 z); diff --git a/src/openrct2/localisation/string_ids.h b/src/openrct2/localisation/string_ids.h index ade8ce949c..20412f8c6a 100644 --- a/src/openrct2/localisation/string_ids.h +++ b/src/openrct2/localisation/string_ids.h @@ -3831,8 +3831,14 @@ enum { STR_TITLE_COMMAND_EDITOR_NO_SCENARIO_SELECTED = 6180, STR_TITLE_COMMAND_EDITOR_MISSING_SCENARIO = 6181, - STR_TITLE_EDITOR_COMMAND_TYPE_FOLLOW = 6182, - STR_TITLE_COMMAND_EDITOR_SELECT_SPRITE = 6183, + STR_TITLE_EDITOR_COMMAND_FOLLOW = 6182, + STR_TITLE_EDITOR_COMMAND_FOLLOW_NO_SPRITE = 6183, + STR_TITLE_EDITOR_COMMAND_TYPE_FOLLOW = 6184, + STR_TITLE_COMMAND_EDITOR_SELECT_SPRITE = 6185, + STR_TITLE_COMMAND_EDITOR_FOLLOW_NO_SPRITE = 6186, + STR_TITLE_COMMAND_EDITOR_FORMAT_SPRITE_NAME = 6187, + STR_LITTER_VOMIT = 6188, + STR_DUCK = 6189, // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working STR_COUNT = 32768 diff --git a/src/openrct2/title/TitleScreen.cpp b/src/openrct2/title/TitleScreen.cpp index 504b821536..37de990f2f 100644 --- a/src/openrct2/title/TitleScreen.cpp +++ b/src/openrct2/title/TitleScreen.cpp @@ -384,7 +384,8 @@ extern "C" gfx_draw_string(dpi, buffer, COLOUR_BLACK, x + 5, y + 5 - 13); // Invalidate screen area - gfx_set_dirty_blocks(x, y, x + 500, y + 30); + sint16 width = (sint16)gfx_get_string_width(buffer); + gfx_set_dirty_blocks(x, y, x + width, y + 30); // 30 is an arbitrary height to catch both strings // Write platform information snprintf(ch, 256 - (ch - buffer), "%s (%s)", OPENRCT2_PLATFORM, OPENRCT2_ARCHITECTURE); diff --git a/src/openrct2/title/TitleSequence.cpp b/src/openrct2/title/TitleSequence.cpp index ed1b616ee1..094d885729 100644 --- a/src/openrct2/title/TitleSequence.cpp +++ b/src/openrct2/title/TitleSequence.cpp @@ -460,6 +460,7 @@ static std::vector LegacyScriptRead(utf8 * script, size_t scriptLe { command.Type = TITLE_SCRIPT_FOLLOW; command.SpriteIndex = atoi(part1) & 0xFFFF; + safe_strcpy(command.SpriteName, part2, USER_STRING_MAX_LENGTH); } else if (_stricmp(token, "WAIT") == 0) { @@ -513,7 +514,8 @@ static void LegacyScriptGetLine(IStream * stream, char * parts) sint32 cindex = 0; sint32 whitespace = 1; sint32 comment = 0; - sint32 load = 0; + bool load = false; + bool sprite = false; for (; part < 3;) { sint32 c = 0; @@ -531,7 +533,7 @@ static void LegacyScriptGetLine(IStream * stream, char * parts) parts[part * 128 + cindex] = 0; comment = 1; } - else if (c == ' ' && !comment && !load) + else if (c == ' ' && !comment && !load && (!sprite || part != 2)) { if (!whitespace) { @@ -540,6 +542,10 @@ static void LegacyScriptGetLine(IStream * stream, char * parts) { load = true; } + else if (part == 0 && cindex == 6 && _strnicmp(parts, "FOLLOW", 6) == 0) + { + sprite = true; + } parts[part * 128 + cindex] = 0; part++; cindex = 0; @@ -608,7 +614,8 @@ static utf8 * LegacyScriptWrite(TitleSequence * seq) if (command->SaveIndex == 0xFF) { sb.Append("LOAD "); - } else + } + else { sb.Append("LOAD "); sb.Append(seq->Saves[command->SaveIndex]); @@ -638,8 +645,9 @@ static utf8 * LegacyScriptWrite(TitleSequence * seq) sb.Append(buffer); break; case TITLE_SCRIPT_FOLLOW: - String::Format(buffer, sizeof(buffer), "FOLLOW %u", command->SpriteIndex); + String::Format(buffer, sizeof(buffer), "FOLLOW %u ", command->SpriteIndex); sb.Append(buffer); + sb.Append(command->SpriteName); break; case TITLE_SCRIPT_SPEED: String::Format(buffer, sizeof(buffer), "SPEED %u", command->Speed); diff --git a/src/openrct2/title/TitleSequence.h b/src/openrct2/title/TitleSequence.h index 34069a3665..5437c1db05 100644 --- a/src/openrct2/title/TitleSequence.h +++ b/src/openrct2/title/TitleSequence.h @@ -17,6 +17,7 @@ #pragma once #include "../common.h" +#include "../localisation/localisation.h" #define TITLE_COMMAND_SCENARIO_LENGTH 64 @@ -32,7 +33,11 @@ typedef struct TitleCommand }; uint8 Rotations; // ROTATE (counter-clockwise) uint8 Zoom; // ZOOM - uint16 SpriteIndex; // FOLLOW + struct // FOLLOW + { + uint16 SpriteIndex; + utf8 SpriteName[USER_STRING_MAX_LENGTH]; + }; uint8 Speed; // SPEED uint16 Milliseconds; // WAIT utf8 Scenario[TITLE_COMMAND_SCENARIO_LENGTH]; // LOADSC diff --git a/src/openrct2/title/TitleSequencePlayer.cpp b/src/openrct2/title/TitleSequencePlayer.cpp index 6ca2963aea..17e4ddfaee 100644 --- a/src/openrct2/title/TitleSequencePlayer.cpp +++ b/src/openrct2/title/TitleSequencePlayer.cpp @@ -382,11 +382,21 @@ private: } } - void FollowSprite(uint16 SpriteIndex) { - rct_window *const MainWindow = window_get_main(); - if (MainWindow != nullptr) + void FollowSprite(uint16 spriteIndex) + { + rct_window * w = window_get_main(); + if (w != nullptr) { - MainWindow->viewport_target_sprite = SpriteIndex; + window_follow_sprite(w, spriteIndex); + } + } + + void UnfollowSprite() + { + rct_window * w = window_get_main(); + if (w != nullptr) + { + window_unfollow_sprite(w); } } @@ -547,9 +557,6 @@ private: _lastScreenHeight = w->height; _viewCentreLocation.x = x; _viewCentreLocation.y = y; - - // Stop following sprites - w->viewport_target_sprite = SPRITE_INDEX_NULL; } } diff --git a/src/openrct2/world/sprite.c b/src/openrct2/world/sprite.c index 6f035ff6de..6f4285e83f 100644 --- a/src/openrct2/world/sprite.c +++ b/src/openrct2/world/sprite.c @@ -35,6 +35,21 @@ static bool _spriteFlashingList[MAX_SPRITES]; uint16 gSpriteSpatialIndex[0x10001]; +const rct_string_id litterNames[12] = { + STR_LITTER_VOMIT, + STR_LITTER_VOMIT, + STR_SHOP_ITEM_SINGULAR_EMPTY_CAN, + STR_SHOP_ITEM_SINGULAR_RUBBISH, + STR_SHOP_ITEM_SINGULAR_EMPTY_BURGER_BOX, + STR_SHOP_ITEM_SINGULAR_EMPTY_CUP, + STR_SHOP_ITEM_SINGULAR_EMPTY_BOX, + STR_SHOP_ITEM_SINGULAR_EMPTY_BOTTLE, + STR_SHOP_ITEM_SINGULAR_EMPTY_BOWL_RED, + STR_SHOP_ITEM_SINGULAR_EMPTY_DRINK_CARTON, + STR_SHOP_ITEM_SINGULAR_EMPTY_JUICE_CUP, + STR_SHOP_ITEM_SINGULAR_EMPTY_BOWL_BLUE +}; + static LocationXYZ16 _spritelocations1[MAX_SPRITES]; static LocationXYZ16 _spritelocations2[MAX_SPRITES]; diff --git a/src/openrct2/world/sprite.h b/src/openrct2/world/sprite.h index 75432314fd..1e0dc29ec4 100644 --- a/src/openrct2/world/sprite.h +++ b/src/openrct2/world/sprite.h @@ -396,6 +396,9 @@ extern uint16 gSpriteListHead[6]; extern uint16 gSpriteListCount[6]; extern uint16 gSpriteSpatialIndex[0x10001]; + +extern const rct_string_id litterNames[12]; + rct_sprite *create_sprite(uint8 bl); void reset_sprite_list(); void reset_sprite_spatial_index();