OpenRCT2/src/openrct2-ui/windows/Guest.cpp

1940 lines
60 KiB
C++
Raw Normal View History

2014-06-24 23:12:26 +02:00
/*****************************************************************************
* Copyright (c) 2014-2023 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
2014-06-24 23:12:26 +02:00
2022-07-03 22:00:37 +02:00
#include <array>
#include <openrct2-ui/interface/Dropdown.h>
2018-06-22 23:21:44 +02:00
#include <openrct2-ui/interface/Viewport.h>
#include <openrct2-ui/interface/Widget.h>
2017-10-06 23:21:00 +02:00
#include <openrct2-ui/windows/Window.h>
2017-10-22 01:22:08 +02:00
#include <openrct2/Context.h>
2017-11-30 18:17:06 +01:00
#include <openrct2/Game.h>
#include <openrct2/GameState.h>
2017-12-12 14:52:57 +01:00
#include <openrct2/Input.h>
Split actions hpp files into separate h and cpp files (#13548) * Split up SmallSceneryPlace/Remove Added undo function for Remove Scenery * Refactor: Balloon and Banner actions hpp=>h/cpp * Refactor: rename all action *.hpp files to *.cpp This is preparation for separation in later commits. Note that without the complete set of commits in this branch, the code will not build. * Refactor Clear, Climate, Custom, and Footpath actions hpp=>h/cpp * VSCode: add src subdirectories to includePath * Refactor Guest actions hpp=>h/cpp * Refactor Land actions hpp=>h/cpp * Refactor LargeScenery actions hpp=>h/cpp * Refactor Load, Maze, Network actions hpp=>h/cpp * Refactor Park actions hpp=>h/cpp * Refactor/style: move private function declarations in actions *.h Previous action .h files included private function declarations with private member variables, before public function declarations. This commit re-orders the header files to the following order: - public member variables - private member variables - public functions - private functions * Refactor Pause action hpp=>h/cpp * Refactor Peep, Place, Player actions hpp=>h/cpp * Refactor Ride actions hpp=>h/cpp * Refactor Scenario, Set*, Sign* actions hpp=>h/cpp * Refactor SmallScenerySetColourAction hpp=>h/cpp * Refactor Staff actions hpp=>h/cpp * Refactor Surface, Tile, Track* actions hpp=>h/cpp * Refactor Wall and Water actions hpp=>h/cpp * Fix various includes and other compile errors Update includes for tests. Move static function declarations to .h files Add explicit includes to various files that were previously implicit (the required header was a nested include in an action hpp file, and the action .h file does not include that header) Move RideSetStatus string enum to the cpp file to avoid unused imports * Xcode: modify project file for actions refactor * Cleanup whitespace and end-of-file newlines Co-authored-by: duncanspumpkin <duncans_pumpkin@hotmail.co.uk>
2020-12-10 07:39:10 +01:00
#include <openrct2/actions/GuestSetFlagsAction.h>
2022-08-11 00:00:58 +02:00
#include <openrct2/actions/GuestSetNameAction.h>
Split actions hpp files into separate h and cpp files (#13548) * Split up SmallSceneryPlace/Remove Added undo function for Remove Scenery * Refactor: Balloon and Banner actions hpp=>h/cpp * Refactor: rename all action *.hpp files to *.cpp This is preparation for separation in later commits. Note that without the complete set of commits in this branch, the code will not build. * Refactor Clear, Climate, Custom, and Footpath actions hpp=>h/cpp * VSCode: add src subdirectories to includePath * Refactor Guest actions hpp=>h/cpp * Refactor Land actions hpp=>h/cpp * Refactor LargeScenery actions hpp=>h/cpp * Refactor Load, Maze, Network actions hpp=>h/cpp * Refactor Park actions hpp=>h/cpp * Refactor/style: move private function declarations in actions *.h Previous action .h files included private function declarations with private member variables, before public function declarations. This commit re-orders the header files to the following order: - public member variables - private member variables - public functions - private functions * Refactor Pause action hpp=>h/cpp * Refactor Peep, Place, Player actions hpp=>h/cpp * Refactor Ride actions hpp=>h/cpp * Refactor Scenario, Set*, Sign* actions hpp=>h/cpp * Refactor SmallScenerySetColourAction hpp=>h/cpp * Refactor Staff actions hpp=>h/cpp * Refactor Surface, Tile, Track* actions hpp=>h/cpp * Refactor Wall and Water actions hpp=>h/cpp * Fix various includes and other compile errors Update includes for tests. Move static function declarations to .h files Add explicit includes to various files that were previously implicit (the required header was a nested include in an action hpp file, and the action .h file does not include that header) Move RideSetStatus string enum to the cpp file to avoid unused imports * Xcode: modify project file for actions refactor * Cleanup whitespace and end-of-file newlines Co-authored-by: duncanspumpkin <duncans_pumpkin@hotmail.co.uk>
2020-12-10 07:39:10 +01:00
#include <openrct2/actions/PeepPickupAction.h>
2018-06-22 23:21:44 +02:00
#include <openrct2/config/Config.h>
2021-11-25 22:47:24 +01:00
#include <openrct2/entity/Guest.h>
#include <openrct2/entity/Staff.h>
2021-12-12 00:06:06 +01:00
#include <openrct2/localisation/Formatter.h>
#include <openrct2/localisation/Formatting.h>
2018-01-06 18:32:25 +01:00
#include <openrct2/localisation/Localisation.h>
2017-10-11 21:38:26 +02:00
#include <openrct2/management/Marketing.h>
2017-10-22 01:22:08 +02:00
#include <openrct2/network/network.h>
2018-01-10 00:00:09 +01:00
#include <openrct2/ride/RideData.h>
#include <openrct2/ride/ShopItem.h>
2018-06-22 23:21:44 +02:00
#include <openrct2/scenario/Scenario.h>
2017-10-06 23:21:00 +02:00
#include <openrct2/sprites.h>
2017-12-13 13:02:24 +01:00
#include <openrct2/util/Util.h>
2017-10-21 16:03:33 +02:00
#include <openrct2/windows/Intent.h>
2018-01-11 10:59:26 +01:00
#include <openrct2/world/Footpath.h>
2018-03-19 23:28:40 +01:00
#include <openrct2/world/Park.h>
2014-06-24 23:12:26 +02:00
2022-07-31 14:22:58 +02:00
static constexpr const StringId WINDOW_TITLE = STR_STRINGID;
2020-05-05 22:26:14 +02:00
static constexpr const int32_t WH = 157;
static constexpr const int32_t WW = 192;
enum WindowGuestPage
{
WINDOW_GUEST_OVERVIEW,
WINDOW_GUEST_STATS,
WINDOW_GUEST_RIDES,
WINDOW_GUEST_FINANCE,
WINDOW_GUEST_THOUGHTS,
WINDOW_GUEST_INVENTORY,
2022-07-03 22:00:37 +02:00
WINDOW_GUEST_DEBUG,
WINDOW_GUEST_PAGE_COUNT,
2014-06-25 19:01:10 +02:00
};
enum WindowGuestWidgetIdx
{
WIDX_BACKGROUND,
WIDX_TITLE,
WIDX_CLOSE,
WIDX_PAGE_BACKGROUND,
WIDX_TAB_1,
WIDX_TAB_2,
WIDX_TAB_3,
WIDX_TAB_4,
WIDX_TAB_5,
WIDX_TAB_6,
WIDX_TAB_7,
WIDX_MARQUEE = 11,
WIDX_VIEWPORT,
WIDX_ACTION_LBL,
WIDX_PICKUP,
WIDX_RENAME,
WIDX_LOCATE,
WIDX_TRACK,
WIDX_RIDE_SCROLL = 11
2014-06-25 19:01:10 +02:00
};
2017-10-06 23:21:00 +02:00
validate_global_widx(WC_PEEP, WIDX_PICKUP);
static constexpr int32_t TabWidth = 30;
#define MAIN_GUEST_WIDGETS \
WINDOW_SHIM(WINDOW_TITLE, WW, WH), \
MakeWidget({ 0, 43 }, { 192, 114 }, WindowWidgetType::Resize, WindowColour::Secondary), /* Resize */ \
MakeTab({ 3, 17 }, STR_SHOW_GUEST_VIEW_TIP), /* Tab 1 */ \
MakeTab({ 34, 17 }, STR_SHOW_GUEST_NEEDS_TIP), /* Tab 2 */ \
MakeTab({ 65, 17 }, STR_SHOW_GUEST_VISITED_RIDES_TIP), /* Tab 3 */ \
MakeTab({ 96, 17 }, STR_SHOW_GUEST_FINANCE_TIP), /* Tab 4 */ \
MakeTab({ 127, 17 }, STR_SHOW_GUEST_THOUGHTS_TIP), /* Tab 5 */ \
MakeTab({ 158, 17 }, STR_SHOW_GUEST_ITEMS_TIP), /* Tab 6 */ \
MakeTab({ 189, 17 }, STR_DEBUG_TIP) /* Tab 7 */
2019-05-04 17:01:51 +02:00
// clang-format off
2022-12-24 16:50:29 +01:00
static Widget _guestWindowWidgetsOverview[] = {
2019-05-04 17:01:51 +02:00
MAIN_GUEST_WIDGETS,
MakeWidget({ 3, 45}, {164, 12}, WindowWidgetType::LabelCentred, WindowColour::Secondary ), // Label Thought marquee
MakeWidget({ 3, 57}, {164, 87}, WindowWidgetType::Viewport, WindowColour::Secondary ), // Viewport
MakeWidget({ 3, 144}, {164, 11}, WindowWidgetType::LabelCentred, WindowColour::Secondary ), // Label Action
MakeWidget({167, 45}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_PICKUP_BTN), STR_PICKUP_TIP ), // Pickup Button
MakeWidget({167, 69}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_RENAME), STR_NAME_GUEST_TIP ), // Rename Button
MakeWidget({167, 93}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_LOCATE), STR_LOCATE_SUBJECT_TIP ), // Locate Button
MakeWidget({167, 117}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, ImageId(SPR_TRACK_PEEP), STR_TOGGLE_GUEST_TRACKING_TIP), // Track Button
2021-09-26 11:11:42 +02:00
WIDGETS_END,
2014-06-24 23:12:26 +02:00
};
// clang-format on
2014-06-24 23:12:26 +02:00
2022-12-24 16:50:29 +01:00
static Widget _guestWindowWidgetsStats[] = {
2019-05-04 17:01:51 +02:00
MAIN_GUEST_WIDGETS,
2021-09-26 11:11:42 +02:00
WIDGETS_END,
};
2014-08-25 17:47:01 +02:00
2022-12-24 16:50:29 +01:00
static Widget _guestWindowWidgetsRides[] = {
2019-05-04 17:01:51 +02:00
MAIN_GUEST_WIDGETS,
MakeWidget({ 3, 57 }, { 186, 87 }, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL),
2021-09-26 11:11:42 +02:00
WIDGETS_END,
2014-08-26 13:30:06 +02:00
};
2022-12-24 16:50:29 +01:00
static Widget _guestWindowWidgetsFinance[] = {
2019-05-04 17:01:51 +02:00
MAIN_GUEST_WIDGETS,
2021-09-26 11:11:42 +02:00
WIDGETS_END,
2014-08-26 13:30:06 +02:00
};
2022-12-24 16:50:29 +01:00
static Widget _guestWindowWidgetsThoughts[] = {
2019-05-04 17:01:51 +02:00
MAIN_GUEST_WIDGETS,
2021-09-26 11:11:42 +02:00
WIDGETS_END,
2014-08-26 13:30:06 +02:00
};
2022-12-24 16:50:29 +01:00
static Widget _guestWindowWidgetsInventory[] = {
2019-05-04 17:01:51 +02:00
MAIN_GUEST_WIDGETS,
2021-09-26 11:11:42 +02:00
WIDGETS_END,
};
2022-12-24 16:50:29 +01:00
static Widget _guestWindowWidgetsDebug[] = {
2019-05-04 17:01:51 +02:00
MAIN_GUEST_WIDGETS,
2021-09-26 11:11:42 +02:00
WIDGETS_END,
2014-08-26 13:30:06 +02:00
};
// clang-format off
2022-07-03 22:00:37 +02:00
static constexpr std::array _guestWindowPageWidgets = {
_guestWindowWidgetsOverview,
_guestWindowWidgetsStats,
_guestWindowWidgetsRides,
_guestWindowWidgetsFinance,
_guestWindowWidgetsThoughts,
_guestWindowWidgetsInventory,
_guestWindowWidgetsDebug,
2014-06-25 19:01:10 +02:00
};
2022-07-03 22:00:37 +02:00
static_assert(_guestWindowPageWidgets.size() == WINDOW_GUEST_PAGE_COUNT);
// clang-format on
2014-06-25 19:01:10 +02:00
2022-07-03 22:00:37 +02:00
static constexpr const std::array _guestWindowPageSizes = {
std::array{ ScreenSize{ 192, 159 }, ScreenSize{ 500, 450 } }, // WINDOW_GUEST_OVERVIEW
std::array{ ScreenSize{ 192, 180 }, ScreenSize{ 192, 180 } }, // WINDOW_GUEST_STATS
std::array{ ScreenSize{ 192, 180 }, ScreenSize{ 500, 400 } }, // WINDOW_GUEST_RIDES
std::array{ ScreenSize{ 210, 148 }, ScreenSize{ 210, 148 } }, // WINDOW_GUEST_FINANCE
std::array{ ScreenSize{ 192, 159 }, ScreenSize{ 500, 450 } }, // WINDOW_GUEST_THOUGHTS
std::array{ ScreenSize{ 192, 159 }, ScreenSize{ 500, 450 } }, // WINDOW_GUEST_INVENTORY
std::array{ ScreenSize{ 192, 171 }, ScreenSize{ 192, 171 } }, // WINDOW_GUEST_DEBUG
2019-05-04 18:23:29 +02:00
};
2022-07-03 22:00:37 +02:00
static_assert(_guestWindowPageSizes.size() == WINDOW_GUEST_PAGE_COUNT);
2014-06-25 19:01:10 +02:00
2022-07-03 22:00:37 +02:00
class GuestWindow final : public Window
{
2022-07-03 22:00:37 +02:00
private:
uint16_t _marqueePosition = 0;
uint16_t _beingWatchedTimer = 0;
uint16_t _guestAnimationFrame = 0;
int16_t _pickedPeepX = LOCATION_NULL; // entity->x gets set to 0x8000 on pickup, this is the old value
public:
void OnOpen() override
{
2022-07-03 22:00:37 +02:00
widgets = _guestWindowWidgetsOverview;
page = WINDOW_GUEST_OVERVIEW;
frame_no = 0;
_marqueePosition = 0;
picked_peep_frame = 0;
min_width = width;
min_height = 157;
max_width = 500;
max_height = 450;
no_list_items = 0;
selected_list_item = -1;
}
2022-07-03 22:00:37 +02:00
void Init(EntityId id)
{
2022-07-03 22:00:37 +02:00
number = id.ToUnderlying();
page = -1; // Set Page to something invalid so that SetPage doesn't set audio on viewport
SetPage(WINDOW_GUEST_OVERVIEW);
}
2022-07-03 22:00:37 +02:00
void OnClose() override
2018-06-22 23:21:44 +02:00
{
if (InputTestFlag(INPUT_FLAG_TOOL_ACTIVE))
2022-07-03 22:00:37 +02:00
{
if (classification == gCurrentToolWidget.window_classification && number == gCurrentToolWidget.window_number)
ToolCancel();
2022-07-03 22:00:37 +02:00
}
}
2022-08-21 18:49:23 +02:00
void OnMouseUp(WidgetIndex widx) override
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
switch (widx)
{
case WIDX_CLOSE:
Close();
return;
2022-07-03 22:00:37 +02:00
case WIDX_TAB_1:
case WIDX_TAB_2:
case WIDX_TAB_3:
case WIDX_TAB_4:
case WIDX_TAB_5:
case WIDX_TAB_6:
case WIDX_TAB_7:
SetPage(widx - WIDX_TAB_1);
return;
2022-07-03 22:00:37 +02:00
}
2019-05-04 18:23:29 +02:00
2022-07-03 22:00:37 +02:00
switch (page)
{
case WINDOW_GUEST_OVERVIEW:
OnMouseUpOverview(widx);
break;
}
}
2022-08-21 18:49:23 +02:00
void OnMouseDown(WidgetIndex widx) override
2019-05-04 18:23:29 +02:00
{
2022-07-03 22:00:37 +02:00
if (page == WINDOW_GUEST_OVERVIEW)
2019-05-04 18:23:29 +02:00
{
2022-07-03 22:00:37 +02:00
OnMouseDownOverview(widx);
2019-05-04 18:23:29 +02:00
}
}
2022-08-21 18:49:23 +02:00
void OnDropdown(WidgetIndex widgetIndex, int32_t selectedIndex) override
2019-05-04 16:40:45 +02:00
{
2022-07-03 22:00:37 +02:00
if (page == WINDOW_GUEST_OVERVIEW)
{
OnDropdownOverview(widgetIndex, selectedIndex);
}
2019-05-04 16:40:45 +02:00
}
2022-07-03 22:00:37 +02:00
void OnResize() override
{
2022-07-03 22:00:37 +02:00
switch (page)
{
case WINDOW_GUEST_OVERVIEW:
OnResizeOverview();
break;
case WINDOW_GUEST_STATS:
case WINDOW_GUEST_RIDES:
case WINDOW_GUEST_FINANCE:
case WINDOW_GUEST_THOUGHTS:
case WINDOW_GUEST_INVENTORY:
case WINDOW_GUEST_DEBUG:
OnResizeCommon();
break;
}
}
2022-07-03 22:00:37 +02:00
void OnUpdate() override
{
switch (page)
{
case WINDOW_GUEST_OVERVIEW:
OnUpdateOverview();
break;
case WINDOW_GUEST_STATS:
OnUpdateStats();
break;
case WINDOW_GUEST_RIDES:
OnUpdateRides();
break;
case WINDOW_GUEST_FINANCE:
OnUpdateFinance();
break;
case WINDOW_GUEST_THOUGHTS:
OnUpdateThoughts();
break;
case WINDOW_GUEST_INVENTORY:
OnUpdateInventory();
break;
case WINDOW_GUEST_DEBUG:
OnUpdateDebug();
break;
}
}
2022-08-21 18:49:23 +02:00
void OnToolUpdate(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) override
{
2022-07-03 22:00:37 +02:00
if (page == WINDOW_GUEST_OVERVIEW)
{
OnToolUpdateOverview(widgetIndex, screenCoords);
}
}
2022-08-21 18:49:23 +02:00
void OnToolDown(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) override
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
if (page == WINDOW_GUEST_OVERVIEW)
{
OnToolDownOverview(widgetIndex, screenCoords);
}
}
2022-08-21 18:49:23 +02:00
void OnToolAbort(WidgetIndex widgetIndex) override
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
if (page == WINDOW_GUEST_OVERVIEW)
{
OnToolAbortOverview(widgetIndex);
}
}
2022-08-21 18:49:23 +02:00
void OnTextInput(WidgetIndex widgetIndex, std::string_view text) override
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
if (page == WINDOW_GUEST_OVERVIEW)
{
OnTextInputOverview(widgetIndex, text);
}
}
2022-07-03 22:00:37 +02:00
void OnViewportRotate() override
{
2022-07-03 22:00:37 +02:00
if (page == WINDOW_GUEST_OVERVIEW)
{
OnViewportRotateOverview();
}
}
void OnDraw(DrawPixelInfo& dpi) override
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
switch (page)
{
case WINDOW_GUEST_OVERVIEW:
OnDrawOverview(dpi);
break;
case WINDOW_GUEST_STATS:
OnDrawStats(dpi);
break;
case WINDOW_GUEST_RIDES:
OnDrawRides(dpi);
break;
case WINDOW_GUEST_FINANCE:
OnDrawFinance(dpi);
break;
case WINDOW_GUEST_THOUGHTS:
OnDrawThoughts(dpi);
break;
case WINDOW_GUEST_INVENTORY:
OnDrawInventory(dpi);
break;
case WINDOW_GUEST_DEBUG:
OnDrawDebug(dpi);
break;
}
}
2022-07-03 22:00:37 +02:00
void OnPrepareDraw() override
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
OnPrepareDrawCommon();
switch (page)
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
case WINDOW_GUEST_OVERVIEW:
OnPrepareDrawOverview();
break;
case WINDOW_GUEST_RIDES:
OnPrepareDrawRides();
break;
}
}
2022-07-03 22:00:37 +02:00
ScreenSize OnScrollGetSize(int32_t scrollIndex) override
{
2022-07-03 22:00:37 +02:00
if (page == WINDOW_GUEST_RIDES)
{
return OnScrollGetSizeRides(scrollIndex);
}
return {};
}
2022-07-03 22:00:37 +02:00
void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
if (page == WINDOW_GUEST_RIDES)
{
2022-07-03 22:00:37 +02:00
OnScrollMouseOverRides(scrollIndex, screenCoords);
}
2022-07-03 22:00:37 +02:00
}
void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override
{
if (page == WINDOW_GUEST_RIDES)
2019-07-21 21:44:19 +02:00
{
2022-07-03 22:00:37 +02:00
OnScrollMouseDownRides(scrollIndex, screenCoords);
2019-07-21 21:44:19 +02:00
}
2022-07-03 22:00:37 +02:00
}
void OnScrollDraw(int32_t scrollIndex, DrawPixelInfo& dpi) override
2022-07-03 22:00:37 +02:00
{
if (page == WINDOW_GUEST_RIDES)
{
2022-07-03 22:00:37 +02:00
OnScrollDrawRides(scrollIndex, dpi);
}
}
2014-08-21 17:45:01 +02:00
2022-07-03 22:00:37 +02:00
private:
Guest* GetGuest()
{
2022-07-03 22:00:37 +02:00
auto guest = GetEntity<Guest>(EntityId::FromUnderlying(number));
if (guest == nullptr)
{
Close();
return nullptr;
}
return guest;
}
2022-07-03 22:00:37 +02:00
void OnResizeCommon()
{
2022-07-03 22:00:37 +02:00
// Get page specific min and max size
int32_t minWidth = _guestWindowPageSizes[page][0].width;
int32_t minHeight = _guestWindowPageSizes[page][0].height;
int32_t maxWidth = _guestWindowPageSizes[page][1].width;
int32_t maxHeight = _guestWindowPageSizes[page][1].height;
// Ensure min size is large enough for all tabs to fit
for (int32_t i = WIDX_TAB_1; i <= WIDX_TAB_7; i++)
{
if (!WidgetIsDisabled(*this, i))
{
2022-07-03 22:00:37 +02:00
minWidth = std::max(minWidth, widgets[i].right + 3);
}
}
2022-07-03 22:00:37 +02:00
maxWidth = std::max(minWidth, maxWidth);
WindowSetResize(*this, minWidth, minHeight, maxWidth, maxHeight);
}
2022-07-03 22:00:37 +02:00
void OnPrepareDrawCommon()
{
if (_guestWindowPageWidgets[page] != widgets)
{
widgets = _guestWindowPageWidgets[page];
InitScrollWidgets();
}
2022-10-17 19:21:18 +02:00
pressed_widgets |= 1uLL << (page + WIDX_TAB_1);
2014-08-23 11:39:15 +02:00
2022-07-03 22:00:37 +02:00
const auto peep = GetGuest();
if (peep == nullptr)
{
return;
}
auto ft = Formatter::Common();
peep->FormatNameTo(ft);
2014-08-27 13:48:29 +02:00
2022-11-06 10:29:40 +01:00
ResizeFrameWithPage();
WindowAlignTabs(this, WIDX_TAB_1, WIDX_TAB_7);
}
2022-07-03 22:00:37 +02:00
void DisableWidgets()
{
2022-07-03 22:00:37 +02:00
const auto peep = GetGuest();
if (peep == nullptr)
{
return;
2022-07-03 22:00:37 +02:00
}
uint64_t newDisabledWidgets = 0;
2022-07-03 22:00:37 +02:00
if (peep->CanBePickedUp())
{
if (WidgetIsDisabled(*this, WIDX_PICKUP))
2022-07-03 22:00:37 +02:00
Invalidate();
}
else
{
2022-10-17 19:21:18 +02:00
newDisabledWidgets = (1uLL << WIDX_PICKUP);
if (!WidgetIsDisabled(*this, WIDX_PICKUP))
2022-07-03 22:00:37 +02:00
Invalidate();
}
if (gParkFlags & PARK_FLAGS_NO_MONEY)
{
2022-10-17 19:21:18 +02:00
newDisabledWidgets |= (1uLL << WIDX_TAB_4); // Disable finance tab if no money
2022-07-03 22:00:37 +02:00
}
if (!gConfigGeneral.DebuggingTools)
2022-07-03 22:00:37 +02:00
{
2022-10-17 19:21:18 +02:00
newDisabledWidgets |= (1uLL << WIDX_TAB_7); // Disable debug tab when debug tools not turned on
2022-07-03 22:00:37 +02:00
}
disabled_widgets = newDisabledWidgets;
}
2022-07-03 22:00:37 +02:00
void SetPage(int32_t newPage)
{
if (InputTestFlag(INPUT_FLAG_TOOL_ACTIVE))
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
if (number == gCurrentToolWidget.window_number && classification == gCurrentToolWidget.window_classification)
ToolCancel();
2022-07-03 22:00:37 +02:00
}
int32_t listen = 0;
if (newPage == WINDOW_GUEST_OVERVIEW && page == WINDOW_GUEST_OVERVIEW && viewport != nullptr)
{
if (!(viewport->flags & VIEWPORT_FLAG_SOUND_ON))
listen = 1;
}
2022-07-03 22:00:37 +02:00
page = newPage;
frame_no = 0;
no_list_items = 0;
selected_list_item = -1;
2022-07-03 22:00:37 +02:00
RemoveViewport();
2022-07-03 22:00:37 +02:00
hold_down_widgets = 0;
pressed_widgets = 0;
widgets = _guestWindowPageWidgets[page];
DisableWidgets();
Invalidate();
OnResize();
OnPrepareDraw();
InitScrollWidgets();
Invalidate();
2022-07-03 22:00:37 +02:00
if (listen && viewport != nullptr)
viewport->flags |= VIEWPORT_FLAG_SOUND_ON;
}
2022-07-03 22:00:37 +02:00
#pragma region Overview
void OverviewTabDraw(DrawPixelInfo& dpi)
2018-06-22 23:21:44 +02:00
{
if (WidgetIsDisabled(*this, WIDX_TAB_1))
2022-07-03 22:00:37 +02:00
return;
2022-07-03 22:00:37 +02:00
const auto& widget = widgets[WIDX_TAB_1];
int32_t widgWidth = widget.width() - 1;
int32_t widgHeight = widget.height() - 1;
auto screenCoords = windowPos + ScreenCoordsXY{ widget.left + 1, widget.top + 1 };
if (page == WINDOW_GUEST_OVERVIEW)
widgHeight++;
DrawPixelInfo clipDpi;
if (!ClipDrawPixelInfo(&clipDpi, &dpi, screenCoords, widgWidth, widgHeight))
{
2022-07-03 22:00:37 +02:00
return;
}
2022-07-03 22:00:37 +02:00
screenCoords = ScreenCoordsXY{ 14, 20 };
2022-07-03 22:00:37 +02:00
const auto* peep = GetGuest();
if (peep == nullptr)
{
2022-07-03 22:00:37 +02:00
return;
}
2022-07-03 22:00:37 +02:00
int32_t animationFrame = GetPeepAnimation(peep->SpriteType).base_image + 1;
2022-07-03 22:00:37 +02:00
int32_t animationFrameOffset = 0;
2022-07-03 22:00:37 +02:00
if (page == WINDOW_GUEST_OVERVIEW)
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
animationFrameOffset = _guestAnimationFrame;
animationFrameOffset &= 0xFFFC;
}
2022-07-03 22:00:37 +02:00
animationFrame += animationFrameOffset;
2022-07-03 22:00:37 +02:00
auto spriteId = ImageId(animationFrame, peep->TshirtColour, peep->TrousersColour);
GfxDrawSprite(&clipDpi, spriteId, screenCoords);
2022-07-03 22:00:37 +02:00
auto* guest = peep->As<Guest>();
if (guest != nullptr)
{
// If holding a balloon
if (animationFrame >= 0x2A1D && animationFrame < 0x2A3D)
{
GfxDrawSprite(&clipDpi, ImageId(animationFrame + 32, guest->BalloonColour), screenCoords);
2022-07-03 22:00:37 +02:00
}
2022-07-03 22:00:37 +02:00
// If holding umbrella
if (animationFrame >= 0x2BBD && animationFrame < 0x2BDD)
{
GfxDrawSprite(&clipDpi, ImageId(animationFrame + 32, guest->UmbrellaColour), screenCoords);
2022-07-03 22:00:37 +02:00
}
2022-07-03 22:00:37 +02:00
// If wearing hat
if (animationFrame >= 0x29DD && animationFrame < 0x29FD)
{
GfxDrawSprite(&clipDpi, ImageId(animationFrame + 32, guest->HatColour), screenCoords);
2022-07-03 22:00:37 +02:00
}
}
}
2022-07-03 22:00:37 +02:00
void OnResizeOverview()
{
DisableWidgets();
OnPrepareDraw();
WidgetInvalidate(*this, WIDX_MARQUEE);
2022-07-03 22:00:37 +02:00
OnResizeCommon();
2022-07-03 22:00:37 +02:00
if (viewport != nullptr)
{
auto reqViewportWidth = width - 30;
auto reqViewportHeight = height - 72;
if (viewport->width != reqViewportWidth || viewport->height != reqViewportHeight)
{
viewport->width = reqViewportWidth;
viewport->height = reqViewportHeight;
viewport->view_width = viewport->zoom.ApplyInversedTo(viewport->width);
viewport->view_height = viewport->zoom.ApplyInversedTo(viewport->height);
}
}
OnViewportRotate();
}
2022-08-21 18:49:23 +02:00
void OnMouseUpOverview(WidgetIndex widgetIndex)
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
const auto peep = GetGuest();
if (peep == nullptr)
{
return;
}
2022-07-03 22:00:37 +02:00
switch (widgetIndex)
{
case WIDX_PICKUP:
{
if (!peep->CanBePickedUp())
{
return;
}
_pickedPeepX = peep->x;
CoordsXYZ nullLoc{};
nullLoc.SetNull();
PeepPickupAction pickupAction{ PeepPickupType::Pickup, EntityId::FromUnderlying(number), nullLoc,
NetworkGetCurrentPlayerId() };
2022-07-03 22:00:37 +02:00
pickupAction.SetCallback([peepnum = number](const GameAction* ga, const GameActions::Result* result) {
if (result->Error != GameActions::Status::Ok)
return;
WindowBase* wind = WindowFindByNumber(WindowClass::Peep, peepnum);
2022-07-03 22:00:37 +02:00
if (wind != nullptr)
{
ToolSet(*wind, WC_PEEP__WIDX_PICKUP, Tool::Picker);
2022-07-03 22:00:37 +02:00
}
});
GameActions::Execute(&pickupAction);
}
break;
case WIDX_RENAME:
{
auto peepName = peep->GetName();
WindowTextInputRawOpen(
this, widgetIndex, STR_GUEST_RENAME_TITLE, STR_GUEST_RENAME_PROMPT, {}, peepName.c_str(), 32);
break;
}
case WIDX_TRACK:
{
uint32_t guestFlags = peep->PeepFlags ^ PEEP_FLAGS_TRACKING;
2022-07-03 22:00:37 +02:00
auto guestSetFlagsAction = GuestSetFlagsAction(EntityId::FromUnderlying(number), guestFlags);
GameActions::Execute(&guestSetFlagsAction);
}
break;
}
}
2022-08-21 18:49:23 +02:00
void OnMouseDownOverview(WidgetIndex widgetIndex)
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
switch (widgetIndex)
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
case WIDX_LOCATE:
ShowLocateDropdown(widgets[widgetIndex]);
break;
}
}
2022-08-21 18:49:23 +02:00
void OnDropdownOverview(WidgetIndex widgetIndex, int32_t dropdownIndex)
{
2022-07-03 22:00:37 +02:00
switch (widgetIndex)
{
case WIDX_LOCATE:
{
if (dropdownIndex == 0)
{
ScrollToViewport();
}
else if (dropdownIndex == 1)
{
GuestFollow();
}
break;
}
}
}
2022-12-24 16:50:29 +01:00
void ShowLocateDropdown(Widget& widget)
{
2022-07-03 22:00:37 +02:00
gDropdownItems[0].Format = STR_LOCATE_SUBJECT_TIP;
gDropdownItems[1].Format = STR_FOLLOW_SUBJECT_TIP;
WindowDropdownShowText({ windowPos.x + widget.left, windowPos.y + widget.top }, widget.height() + 1, colours[1], 0, 2);
gDropdownDefaultIndex = 0;
}
2022-07-03 22:00:37 +02:00
void GuestFollow()
2018-06-22 23:21:44 +02:00
{
WindowBase* main = WindowGetMain();
WindowFollowSprite(*main, EntityId::FromUnderlying(number));
}
2022-07-03 22:00:37 +02:00
void OnViewportRotateOverview()
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
const auto peep = GetGuest();
if (peep == nullptr)
2018-06-22 23:21:44 +02:00
{
return;
}
2022-07-03 22:00:37 +02:00
2023-01-16 21:14:50 +01:00
ViewportUpdateSmartFollowGuest(this, peep);
2022-07-03 22:00:37 +02:00
bool reCreateViewport = false;
uint16_t origViewportFlags{};
if (viewport != nullptr)
{
if (focus.has_value())
return;
origViewportFlags = viewport->flags;
reCreateViewport = true;
RemoveViewport();
}
2022-07-03 22:00:37 +02:00
OnPrepareDraw();
2022-07-03 22:00:37 +02:00
if (peep->State != PeepState::Picked && viewport == nullptr)
{
const auto& viewWidget = widgets[WIDX_VIEWPORT];
auto screenPos = ScreenCoordsXY{ viewWidget.left + 1 + windowPos.x, viewWidget.top + 1 + windowPos.y };
int32_t widgWidth = viewWidget.width() - 1;
int32_t widgHeight = viewWidget.height() - 1;
2023-01-16 21:14:50 +01:00
ViewportCreate(this, screenPos, widgWidth, widgHeight, focus.value());
2022-07-03 22:00:37 +02:00
if (viewport != nullptr && reCreateViewport)
{
viewport->flags = origViewportFlags;
}
flags |= WF_NO_SCROLLING;
Invalidate();
}
Invalidate();
}
2022-07-03 22:00:37 +02:00
void OnDrawOverview(DrawPixelInfo& dpi)
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
DrawWidgets(dpi);
OverviewTabDraw(dpi);
StatsTabDraw(dpi);
RidesTabDraw(dpi);
FinanceTabDraw(dpi);
ThoughtsTabDraw(dpi);
InventoryTabDraw(dpi);
DebugTabDraw(dpi);
2022-07-03 22:00:37 +02:00
// Draw the viewport no sound sprite
if (viewport != nullptr)
{
WindowDrawViewport(&dpi, *this);
2022-07-03 22:00:37 +02:00
if (viewport->flags & VIEWPORT_FLAG_SOUND_ON)
{
GfxDrawSprite(&dpi, ImageId(SPR_HEARING_VIEWPORT), windowPos + ScreenCoordsXY{ 2, 2 });
2022-07-03 22:00:37 +02:00
}
}
2014-08-27 13:14:52 +02:00
2022-07-03 22:00:37 +02:00
// Draw the centred label
const auto* peep = GetGuest();
if (peep == nullptr)
{
return;
}
2022-07-03 22:00:37 +02:00
const auto& actionLabelWidget = widgets[WIDX_ACTION_LBL];
auto screenPos = windowPos + ScreenCoordsXY{ actionLabelWidget.midX(), actionLabelWidget.top - 1 };
2014-08-27 13:14:52 +02:00
2022-07-03 22:00:37 +02:00
{
auto ft = Formatter();
peep->FormatActionTo(ft);
int32_t textWidth = actionLabelWidget.width();
2023-02-24 22:05:07 +01:00
DrawTextEllipsised(dpi, screenPos, textWidth, STR_BLACK_STRING, ft, { TextAlignment::CENTRE });
2022-07-03 22:00:37 +02:00
}
2014-08-27 13:14:52 +02:00
2022-07-03 22:00:37 +02:00
// Draw the marquee thought
const auto& marqueeWidget = widgets[WIDX_MARQUEE];
auto marqWidth = marqueeWidget.width() - 3;
int32_t left = marqueeWidget.left + 2 + windowPos.x;
int32_t top = marqueeWidget.top + windowPos.y;
int32_t marqHeight = marqueeWidget.height();
DrawPixelInfo dpiMarquee;
if (!ClipDrawPixelInfo(&dpiMarquee, &dpi, { left, top }, marqWidth, marqHeight))
2022-07-03 22:00:37 +02:00
{
return;
}
2022-07-03 22:00:37 +02:00
int32_t i = 0;
for (; i < PEEP_MAX_THOUGHTS; ++i)
{
if (peep->Thoughts[i].type == PeepThoughtType::None)
{
_marqueePosition = 0;
return;
}
if (peep->Thoughts[i].freshness == 1)
{ // If a fresh thought
break;
}
}
if (i == PEEP_MAX_THOUGHTS)
{
_marqueePosition = 0;
return;
}
2022-07-03 22:00:37 +02:00
screenPos.x = marqueeWidget.width() - _marqueePosition;
{
auto ft = Formatter();
PeepThoughtSetFormatArgs(&peep->Thoughts[i], ft);
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpiMarquee, { screenPos.x, 0 }, STR_WINDOW_COLOUR_2_STRINGID, ft, { FontStyle::Small });
2022-07-03 22:00:37 +02:00
}
}
2022-07-03 22:00:37 +02:00
void OnPrepareDrawOverview()
{
2022-07-03 22:00:37 +02:00
const auto peep = GetGuest();
if (peep == nullptr)
{
return;
}
2022-10-17 19:21:18 +02:00
pressed_widgets &= ~(1uLL << WIDX_TRACK);
2022-07-03 22:00:37 +02:00
if (peep->PeepFlags & PEEP_FLAGS_TRACKING)
{
2022-10-17 19:21:18 +02:00
pressed_widgets |= (1uLL << WIDX_TRACK);
2022-07-03 22:00:37 +02:00
}
widgets[WIDX_VIEWPORT].right = width - 26;
widgets[WIDX_VIEWPORT].bottom = height - 14;
widgets[WIDX_ACTION_LBL].top = height - 12;
widgets[WIDX_ACTION_LBL].bottom = height - 3;
widgets[WIDX_ACTION_LBL].right = width - 24;
widgets[WIDX_MARQUEE].right = width - 24;
widgets[WIDX_PICKUP].right = width - 2;
widgets[WIDX_RENAME].right = width - 2;
widgets[WIDX_LOCATE].right = width - 2;
widgets[WIDX_TRACK].right = width - 2;
widgets[WIDX_PICKUP].left = width - 25;
widgets[WIDX_RENAME].left = width - 25;
widgets[WIDX_LOCATE].left = width - 25;
widgets[WIDX_TRACK].left = width - 25;
}
2022-07-03 22:00:37 +02:00
void OnUpdateOverview()
{
2022-07-03 22:00:37 +02:00
int32_t newAnimationFrame = _guestAnimationFrame;
newAnimationFrame++;
newAnimationFrame %= 24;
_guestAnimationFrame = newAnimationFrame;
WidgetInvalidate(*this, WIDX_TAB_1);
WidgetInvalidate(*this, WIDX_TAB_2);
2022-07-03 22:00:37 +02:00
const auto peep = GetGuest();
if (peep == nullptr)
{
return;
}
if (peep->WindowInvalidateFlags & PEEP_INVALIDATE_PEEP_ACTION)
{
peep->WindowInvalidateFlags &= ~PEEP_INVALIDATE_PEEP_ACTION;
WidgetInvalidate(*this, WIDX_ACTION_LBL);
2022-07-03 22:00:37 +02:00
}
2022-07-03 22:00:37 +02:00
_marqueePosition += 2;
2022-07-03 22:00:37 +02:00
_beingWatchedTimer++;
2022-07-03 22:00:37 +02:00
// Disable peep watching thought for multiplayer as it's client specific
if (NetworkGetMode() == NETWORK_MODE_NONE)
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
// Create the "I have the strangest feeling I am being watched thought"
if (_beingWatchedTimer >= 3840)
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
if (!(_beingWatchedTimer & 0x3FF))
2018-06-22 23:21:44 +02:00
{
int32_t random = UtilRand() & 0xFFFF;
2022-07-03 22:00:37 +02:00
if (random <= 0x2AAA)
{
peep->InsertNewThought(PeepThoughtType::Watched);
}
}
}
}
}
2014-09-09 19:08:34 +02:00
2022-08-21 18:49:23 +02:00
void OnTextInputOverview(WidgetIndex widgetIndex, std::string_view text)
2022-07-03 22:00:37 +02:00
{
if (widgetIndex != WIDX_RENAME)
return;
2022-07-03 22:00:37 +02:00
if (text.empty())
return;
std::string sText(text);
2022-08-11 00:00:58 +02:00
auto gameAction = GuestSetNameAction(EntityId::FromUnderlying(number), sText);
GameActions::Execute(&gameAction);
2022-07-03 22:00:37 +02:00
}
2022-08-21 18:49:23 +02:00
void OnToolUpdateOverview(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
if (widgetIndex != WIDX_PICKUP)
return;
MapInvalidateSelectionRect();
2022-07-03 22:00:37 +02:00
gMapSelectFlags &= ~MAP_SELECT_FLAG_ENABLE;
2022-10-04 08:51:27 +02:00
auto mapCoords = FootpathGetCoordinatesFromPos({ screenCoords.x, screenCoords.y + 16 }, nullptr, nullptr);
2022-07-03 22:00:37 +02:00
if (!mapCoords.IsNull())
{
gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE;
gMapSelectType = MAP_SELECT_TYPE_FULL;
gMapSelectPositionA = mapCoords;
gMapSelectPositionB = mapCoords;
MapInvalidateSelectionRect();
2022-07-03 22:00:37 +02:00
}
2022-07-03 22:00:37 +02:00
gPickupPeepImage = ImageId();
2023-01-16 21:14:50 +01:00
auto info = GetMapCoordinatesFromPos(screenCoords, ViewportInteractionItemAll);
2022-07-03 22:00:37 +02:00
if (info.SpriteType == ViewportInteractionItem::None)
return;
2022-07-03 22:00:37 +02:00
gPickupPeepX = screenCoords.x - 1;
gPickupPeepY = screenCoords.y + 16;
picked_peep_frame++;
if (picked_peep_frame >= 48)
{
picked_peep_frame = 0;
}
2022-07-03 22:00:37 +02:00
const auto peep = GetGuest();
if (peep == nullptr)
{
return;
}
2016-10-18 21:33:43 +02:00
2022-07-03 22:00:37 +02:00
auto baseImageId = GetPeepAnimation(peep->SpriteType, PeepActionSpriteType::Ui).base_image;
baseImageId += picked_peep_frame >> 2;
gPickupPeepImage = ImageId(baseImageId, peep->TshirtColour, peep->TrousersColour);
}
2016-10-18 21:33:43 +02:00
2022-08-21 18:49:23 +02:00
void OnToolDownOverview(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords)
2022-07-03 22:00:37 +02:00
{
if (widgetIndex != WIDX_PICKUP)
return;
2022-07-03 22:00:37 +02:00
TileElement* tileElement;
2022-10-04 08:51:27 +02:00
auto destCoords = FootpathGetCoordinatesFromPos({ screenCoords.x, screenCoords.y + 16 }, nullptr, &tileElement);
2022-07-03 22:00:37 +02:00
if (destCoords.IsNull())
return;
PeepPickupAction pickupAction{ PeepPickupType::Place,
EntityId::FromUnderlying(number),
{ destCoords, tileElement->GetBaseZ() },
NetworkGetCurrentPlayerId() };
2022-07-03 22:00:37 +02:00
pickupAction.SetCallback([](const GameAction* ga, const GameActions::Result* result) {
if (result->Error != GameActions::Status::Ok)
return;
ToolCancel();
2022-07-03 22:00:37 +02:00
gPickupPeepImage = ImageId();
});
GameActions::Execute(&pickupAction);
}
2022-08-21 18:49:23 +02:00
void OnToolAbortOverview(WidgetIndex widgetIndex)
{
2022-07-03 22:00:37 +02:00
if (widgetIndex != WIDX_PICKUP)
return;
PeepPickupAction pickupAction{
PeepPickupType::Cancel, EntityId::FromUnderlying(number), { _pickedPeepX, 0, 0 }, NetworkGetCurrentPlayerId()
2022-07-03 22:00:37 +02:00
};
GameActions::Execute(&pickupAction);
}
2022-07-03 22:00:37 +02:00
#pragma endregion
2022-07-03 22:00:37 +02:00
#pragma region Stats
void StatsTabDraw(DrawPixelInfo& dpi)
{
if (WidgetIsDisabled(*this, WIDX_TAB_2))
2022-07-03 22:00:37 +02:00
return;
2022-07-03 22:00:37 +02:00
const auto& widget = widgets[WIDX_TAB_2];
auto screenCoords = windowPos + ScreenCoordsXY{ widget.left, widget.top };
2022-07-03 22:00:37 +02:00
const auto peep = GetGuest();
if (peep == nullptr)
{
return;
}
int32_t imageId = GetPeepFaceSpriteLarge(peep);
2022-07-03 22:00:37 +02:00
if (page == WINDOW_GUEST_STATS)
{
// If currently viewing this tab animate tab
// if it is very sick or angry.
switch (imageId)
{
case SPR_PEEP_LARGE_FACE_VERY_VERY_SICK_0:
imageId += (frame_no / 4) & 0xF;
break;
case SPR_PEEP_LARGE_FACE_VERY_SICK_0:
imageId += (frame_no / 8) & 0x3;
break;
case SPR_PEEP_LARGE_FACE_ANGRY_0:
imageId += (frame_no / 8) & 0x3;
break;
}
}
GfxDrawSprite(&dpi, ImageId(imageId), screenCoords);
2022-07-03 22:00:37 +02:00
}
2022-07-03 22:00:37 +02:00
void OnUpdateStats()
{
frame_no++;
auto peep = GetGuest();
if (peep == nullptr)
{
return;
2022-07-03 22:00:37 +02:00
}
peep->WindowInvalidateFlags &= ~PEEP_INVALIDATE_PEEP_STATS;
2014-09-20 12:12:45 +02:00
2022-07-03 22:00:37 +02:00
Invalidate();
}
2014-09-20 12:12:45 +02:00
void StatsBarsDraw(int32_t value, const ScreenCoordsXY& origCoords, DrawPixelInfo& dpi, int32_t colour, bool blinkFlag)
{
2022-07-03 22:00:37 +02:00
auto coords = origCoords;
if (FontGetLineHeight(FontStyle::Medium) > 10)
2022-07-03 22:00:37 +02:00
{
coords.y += 1;
}
GfxFillRectInset(
2022-07-03 22:00:37 +02:00
&dpi, { coords + ScreenCoordsXY{ 61, 1 }, coords + ScreenCoordsXY{ 61 + 121, 9 } }, colours[1], INSET_RECT_F_30);
if (!blinkFlag || GameIsPaused() || (gCurrentRealTimeTicks & 8) == 0)
2022-07-03 22:00:37 +02:00
{
value *= 118;
value >>= 8;
2022-07-03 22:00:37 +02:00
if (value <= 2)
return;
GfxFillRectInset(
2022-07-03 22:00:37 +02:00
&dpi, { coords + ScreenCoordsXY{ 63, 2 }, coords + ScreenCoordsXY{ 63 + value - 1, 8 } }, colour, 0);
}
}
2022-07-03 22:00:37 +02:00
/**
* Takes a guest stat value (scaled to currMax) and adjusts it to be scaled out of 255.
* Then clamp the value to between newMin and 255.
*/
int32_t NormalizeGuestStatValue(int32_t value, int32_t currMax, int32_t newMin) const
{
int32_t newValue = (value * 255) / currMax;
return std::clamp(newValue, newMin, 255);
}
void OnDrawStats(DrawPixelInfo& dpi)
2022-07-03 22:00:37 +02:00
{
DrawWidgets(dpi);
OverviewTabDraw(dpi);
StatsTabDraw(dpi);
RidesTabDraw(dpi);
FinanceTabDraw(dpi);
ThoughtsTabDraw(dpi);
InventoryTabDraw(dpi);
DebugTabDraw(dpi);
2022-07-03 22:00:37 +02:00
// ebx
const auto peep = GetGuest();
if (peep == nullptr)
{
return;
}
2022-07-03 22:00:37 +02:00
// Not sure why this is not stats widgets
// cx dx
auto screenCoords = windowPos
+ ScreenCoordsXY{ widgets[WIDX_PAGE_BACKGROUND].left + 4, widgets[WIDX_PAGE_BACKGROUND].top + 4 };
2022-07-03 22:00:37 +02:00
// Happiness
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_STAT_HAPPINESS_LABEL);
2022-07-03 22:00:37 +02:00
int32_t happiness = NormalizeGuestStatValue(peep->Happiness, PEEP_MAX_HAPPINESS, 10);
int32_t barColour = COLOUR_BRIGHT_GREEN;
bool barBlink = happiness < 50;
StatsBarsDraw(happiness, screenCoords, dpi, barColour, barBlink);
2022-07-03 22:00:37 +02:00
// Energy
screenCoords.y += LIST_ROW_HEIGHT;
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_STAT_ENERGY_LABEL);
2022-07-03 22:00:37 +02:00
int32_t energy = NormalizeGuestStatValue(peep->Energy - PEEP_MIN_ENERGY, PEEP_MAX_ENERGY - PEEP_MIN_ENERGY, 10);
barColour = COLOUR_BRIGHT_GREEN;
barBlink = energy < 50;
StatsBarsDraw(energy, screenCoords, dpi, barColour, barBlink);
2022-07-03 22:00:37 +02:00
// Hunger
screenCoords.y += LIST_ROW_HEIGHT;
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_STAT_HUNGER_LABEL);
2022-07-03 22:00:37 +02:00
int32_t hunger = NormalizeGuestStatValue(peep->Hunger - 32, 158, 0);
hunger = 255 - hunger; // the bar should be longer when peep->Hunger is low
barColour = COLOUR_BRIGHT_RED;
barBlink = hunger > 170;
StatsBarsDraw(hunger, screenCoords, dpi, barColour, barBlink);
2022-07-03 22:00:37 +02:00
// Thirst
screenCoords.y += LIST_ROW_HEIGHT;
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_STAT_THIRST_LABEL);
2022-07-03 22:00:37 +02:00
int32_t thirst = NormalizeGuestStatValue(peep->Thirst - 32, 158, 0);
thirst = 255 - thirst; // the bar should be longer when peep->Thirst is low
barColour = COLOUR_BRIGHT_RED;
barBlink = thirst > 170;
StatsBarsDraw(thirst, screenCoords, dpi, barColour, barBlink);
2022-07-03 22:00:37 +02:00
// Nausea
screenCoords.y += LIST_ROW_HEIGHT;
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_STAT_NAUSEA_LABEL);
2022-07-03 22:00:37 +02:00
int32_t nausea = NormalizeGuestStatValue(peep->Nausea - 32, 223, 0);
barColour = COLOUR_BRIGHT_RED;
barBlink = nausea > 120;
StatsBarsDraw(nausea, screenCoords, dpi, barColour, barBlink);
2022-07-03 22:00:37 +02:00
// Toilet
screenCoords.y += LIST_ROW_HEIGHT;
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_STAT_TOILET_LABEL);
2022-07-03 22:00:37 +02:00
int32_t toilet = NormalizeGuestStatValue(peep->Toilet - 64, 178, 0);
barColour = COLOUR_BRIGHT_RED;
barBlink = toilet > 160;
StatsBarsDraw(toilet, screenCoords, dpi, barColour, barBlink);
2022-07-03 22:00:37 +02:00
// Time in park
screenCoords.y += LIST_ROW_HEIGHT + 1;
int32_t guestEntryTime = peep->GetParkEntryTime();
if (guestEntryTime != -1)
{
int32_t timeInPark = (gCurrentTicks - guestEntryTime) >> 11;
auto ft = Formatter();
ft.Add<uint16_t>(timeInPark & 0xFFFF);
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_STAT_TIME_IN_PARK, ft);
2022-07-03 22:00:37 +02:00
}
2022-07-03 22:00:37 +02:00
screenCoords.y += LIST_ROW_HEIGHT + 9;
GfxFillRectInset(
2022-07-03 22:00:37 +02:00
&dpi, { screenCoords - ScreenCoordsXY{ 0, 6 }, screenCoords + ScreenCoordsXY{ 179, -5 } }, colours[1],
INSET_RECT_FLAG_BORDER_INSET);
2022-07-03 22:00:37 +02:00
// Preferred Ride
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_STAT_PREFERRED_RIDE);
2022-07-03 22:00:37 +02:00
screenCoords.y += LIST_ROW_HEIGHT;
2022-07-03 22:00:37 +02:00
// Intensity
{
2022-07-03 22:00:37 +02:00
auto ft = Formatter();
auto maxIntensity = peep->Intensity.GetMaximum();
int32_t string_id = STR_GUEST_STAT_PREFERRED_INTESITY_BELOW;
if (peep->Intensity.GetMinimum() != 0)
{
ft.Add<uint16_t>(peep->Intensity.GetMinimum());
ft.Add<uint16_t>(maxIntensity);
string_id = STR_GUEST_STAT_PREFERRED_INTESITY_BETWEEN;
if (maxIntensity == 15)
string_id = STR_GUEST_STAT_PREFERRED_INTESITY_ABOVE;
}
else
{
ft.Add<uint16_t>(maxIntensity);
}
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords + ScreenCoordsXY{ 4, 0 }, string_id, ft);
}
2022-07-03 22:00:37 +02:00
// Nausea tolerance
{
2022-07-31 14:22:58 +02:00
static constexpr const StringId _nauseaTolerances[] = {
2022-07-03 22:00:37 +02:00
STR_PEEP_STAT_NAUSEA_TOLERANCE_NONE,
STR_PEEP_STAT_NAUSEA_TOLERANCE_LOW,
STR_PEEP_STAT_NAUSEA_TOLERANCE_AVERAGE,
STR_PEEP_STAT_NAUSEA_TOLERANCE_HIGH,
};
screenCoords.y += LIST_ROW_HEIGHT;
auto nausea_tolerance = EnumValue(peep->NauseaTolerance) & 0x3;
auto ft = Formatter();
2022-07-31 14:22:58 +02:00
ft.Add<StringId>(_nauseaTolerances[nausea_tolerance]);
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_STAT_NAUSEA_TOLERANCE, ft);
2022-07-03 22:00:37 +02:00
}
}
2022-07-03 22:00:37 +02:00
#pragma endregion
2022-07-03 22:00:37 +02:00
#pragma region Rides
void RidesTabDraw(DrawPixelInfo& dpi)
2018-06-22 23:21:44 +02:00
{
if (WidgetIsDisabled(*this, WIDX_TAB_3))
2022-07-03 22:00:37 +02:00
return;
2022-07-03 22:00:37 +02:00
const auto& widget = widgets[WIDX_TAB_3];
auto screenCoords = windowPos + ScreenCoordsXY{ widget.left, widget.top };
2022-07-03 22:00:37 +02:00
int32_t imageId = SPR_TAB_RIDE_0;
2022-07-03 22:00:37 +02:00
if (page == WINDOW_GUEST_RIDES)
{
imageId += (frame_no / 4) & 0xF;
}
GfxDrawSprite(&dpi, ImageId(imageId), screenCoords);
}
2022-07-03 22:00:37 +02:00
void OnUpdateRides()
{
frame_no++;
WidgetInvalidate(*this, WIDX_TAB_2);
WidgetInvalidate(*this, WIDX_TAB_3);
2022-07-03 22:00:37 +02:00
const auto guest = GetGuest();
if (guest == nullptr)
{
return;
}
2022-07-03 22:00:37 +02:00
// Every 2048 ticks do a full window_invalidate
int32_t numTicks = gCurrentTicks - guest->GetParkEntryTime();
if (!(numTicks & 0x7FF))
Invalidate();
2022-07-03 22:00:37 +02:00
uint8_t currListPosition = 0;
for (const auto& r : GetRideManager())
{
if (r.IsRide() && guest->HasRidden(r))
2022-07-03 22:00:37 +02:00
{
list_item_positions[currListPosition] = r.id.ToUnderlying();
currListPosition++;
}
}
2022-07-03 22:00:37 +02:00
// If there are new items
if (no_list_items != currListPosition)
{
no_list_items = currListPosition;
Invalidate();
}
}
2022-07-03 22:00:37 +02:00
ScreenSize OnScrollGetSizeRides(int32_t scrollIndex)
{
ScreenSize newSize;
newSize.height = no_list_items * 10;
2022-07-03 22:00:37 +02:00
if (selected_list_item != -1)
{
selected_list_item = -1;
Invalidate();
}
2022-07-03 22:00:37 +02:00
int32_t visableHeight = newSize.height - widgets[WIDX_RIDE_SCROLL].bottom + widgets[WIDX_RIDE_SCROLL].top + 21;
2022-07-03 22:00:37 +02:00
if (visableHeight < 0)
visableHeight = 0;
if (visableHeight < scrolls[0].v_top)
{
scrolls[0].v_top = visableHeight;
Invalidate();
}
return newSize;
}
void OnScrollMouseDownRides(int32_t scrollIndex, const ScreenCoordsXY& screenCoords)
{
2022-07-03 22:00:37 +02:00
auto index = screenCoords.y / 10;
if (index >= no_list_items)
return;
auto intent = Intent(WindowClass::Ride);
intent.PutExtra(INTENT_EXTRA_RIDE_ID, list_item_positions[index]);
2022-11-06 21:49:07 +01:00
ContextOpenIntent(&intent);
}
2022-07-03 22:00:37 +02:00
void OnScrollMouseOverRides(int32_t scrollIndex, const ScreenCoordsXY& screenCoords)
{
auto index = screenCoords.y / 10;
if (index >= no_list_items)
return;
2022-07-03 22:00:37 +02:00
if (index == selected_list_item)
return;
selected_list_item = index;
2022-07-03 22:00:37 +02:00
Invalidate();
}
2022-07-03 22:00:37 +02:00
void OnPrepareDrawRides()
{
2022-07-03 22:00:37 +02:00
widgets[WIDX_RIDE_SCROLL].right = width - 4;
widgets[WIDX_RIDE_SCROLL].bottom = height - 15;
}
2022-07-03 22:00:37 +02:00
void OnDrawRides(DrawPixelInfo& dpi)
{
2022-07-03 22:00:37 +02:00
DrawWidgets(dpi);
OverviewTabDraw(dpi);
StatsTabDraw(dpi);
RidesTabDraw(dpi);
FinanceTabDraw(dpi);
ThoughtsTabDraw(dpi);
InventoryTabDraw(dpi);
DebugTabDraw(dpi);
2022-07-03 22:00:37 +02:00
const auto peep = GetGuest();
if (peep == nullptr)
{
return;
}
2022-07-03 22:00:37 +02:00
// cx dx
auto screenCoords = windowPos
+ ScreenCoordsXY{ widgets[WIDX_PAGE_BACKGROUND].left + 2, widgets[WIDX_PAGE_BACKGROUND].top + 2 };
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_LABEL_RIDES_BEEN_ON);
2022-07-03 22:00:37 +02:00
screenCoords.y = windowPos.y + widgets[WIDX_PAGE_BACKGROUND].bottom - 12;
auto ft = Formatter();
auto* r = GetRide(peep->FavouriteRide);
2022-07-03 22:00:37 +02:00
if (r != nullptr)
{
2022-07-03 22:00:37 +02:00
r->FormatNameTo(ft);
}
2022-07-03 22:00:37 +02:00
else
{
2022-07-31 14:22:58 +02:00
ft.Add<StringId>(STR_PEEP_FAVOURITE_RIDE_NOT_AVAILABLE);
}
2023-02-24 22:05:07 +01:00
DrawTextEllipsised(dpi, screenCoords, width - 14, STR_FAVOURITE_RIDE, ft);
2022-07-03 22:00:37 +02:00
}
void OnScrollDrawRides(int32_t scrollIndex, DrawPixelInfo& dpi)
{
2022-07-03 22:00:37 +02:00
auto colour = ColourMapA[colours[1]].mid_light;
GfxFillRect(&dpi, { { dpi.x, dpi.y }, { dpi.x + dpi.width - 1, dpi.y + dpi.height - 1 } }, colour);
2022-07-03 22:00:37 +02:00
for (int32_t listIndex = 0; listIndex < no_list_items; listIndex++)
{
auto y = listIndex * 10;
2022-07-31 14:22:58 +02:00
StringId stringId = STR_BLACK_STRING;
2022-07-03 22:00:37 +02:00
if (listIndex == selected_list_item)
{
GfxFilterRect(&dpi, { 0, y, 800, y + 9 }, FilterPaletteID::PaletteDarken1);
2022-07-03 22:00:37 +02:00
stringId = STR_WINDOW_COLOUR_2_STRINGID;
}
2022-07-03 22:00:37 +02:00
const auto rId = RideId::FromUnderlying(list_item_positions[listIndex]);
auto* r = GetRide(rId);
2022-07-03 22:00:37 +02:00
if (r != nullptr)
{
auto ft = Formatter();
r->FormatNameTo(ft);
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, { 0, y - 1 }, stringId, ft);
2022-07-03 22:00:37 +02:00
}
}
}
2022-07-03 22:00:37 +02:00
#pragma endregion
2022-07-03 22:00:37 +02:00
#pragma region Finance
void FinanceTabDraw(DrawPixelInfo& dpi)
{
if (WidgetIsDisabled(*this, WIDX_TAB_4))
2022-07-03 22:00:37 +02:00
return;
const auto& widget = widgets[WIDX_TAB_4];
auto screenCoords = windowPos + ScreenCoordsXY{ widget.left, widget.top };
int32_t imageId = SPR_TAB_FINANCES_SUMMARY_0;
if (page == WINDOW_GUEST_FINANCE)
{
imageId += (frame_no / 2) & 0x7;
}
GfxDrawSprite(&dpi, ImageId(imageId), screenCoords);
2022-07-03 22:00:37 +02:00
}
2022-07-03 22:00:37 +02:00
void OnUpdateFinance()
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
frame_no++;
WidgetInvalidate(*this, WIDX_TAB_2);
WidgetInvalidate(*this, WIDX_TAB_4);
}
2022-07-03 22:00:37 +02:00
void OnDrawFinance(DrawPixelInfo& dpi)
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
DrawWidgets(dpi);
OverviewTabDraw(dpi);
StatsTabDraw(dpi);
RidesTabDraw(dpi);
FinanceTabDraw(dpi);
ThoughtsTabDraw(dpi);
InventoryTabDraw(dpi);
DebugTabDraw(dpi);
const auto peep = GetGuest();
if (peep == nullptr)
{
2022-07-03 22:00:37 +02:00
return;
}
2022-07-03 22:00:37 +02:00
// cx dx
auto screenCoords = windowPos
+ ScreenCoordsXY{ widgets[WIDX_PAGE_BACKGROUND].left + 4, widgets[WIDX_PAGE_BACKGROUND].top + 4 };
// Cash in pocket
{
2022-07-03 22:00:37 +02:00
auto ft = Formatter();
ft.Add<money64>(peep->CashInPocket);
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_STAT_CASH_IN_POCKET, ft);
2022-07-03 22:00:37 +02:00
screenCoords.y += LIST_ROW_HEIGHT;
}
2022-07-03 22:00:37 +02:00
// Cash spent
{
2022-07-03 22:00:37 +02:00
auto ft = Formatter();
ft.Add<money64>(peep->CashSpent);
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_STAT_CASH_SPENT, ft);
2022-07-03 22:00:37 +02:00
screenCoords.y += LIST_ROW_HEIGHT * 2;
}
2022-07-03 22:00:37 +02:00
GfxFillRectInset(
2022-07-03 22:00:37 +02:00
&dpi, { screenCoords - ScreenCoordsXY{ 0, 6 }, screenCoords + ScreenCoordsXY{ 179, -5 } }, colours[1],
INSET_RECT_FLAG_BORDER_INSET);
// Paid to enter
{
2022-07-03 22:00:37 +02:00
auto ft = Formatter();
ft.Add<money64>(peep->PaidToEnter);
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_EXPENSES_ENTRANCE_FEE, ft);
2022-07-03 22:00:37 +02:00
screenCoords.y += LIST_ROW_HEIGHT;
}
2022-07-03 22:00:37 +02:00
// Paid on rides
{
2022-07-03 22:00:37 +02:00
auto ft = Formatter();
ft.Add<money64>(peep->PaidOnRides);
ft.Add<uint16_t>(peep->GuestNumRides);
if (peep->GuestNumRides != 1)
{
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_EXPENSES_RIDE_PLURAL, ft);
2022-07-03 22:00:37 +02:00
}
else
{
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_EXPENSES_RIDE, ft);
2022-07-03 22:00:37 +02:00
}
screenCoords.y += LIST_ROW_HEIGHT;
}
2022-07-03 22:00:37 +02:00
// Paid on food
{
2022-07-03 22:00:37 +02:00
auto ft = Formatter();
ft.Add<money64>(peep->PaidOnFood);
ft.Add<uint16_t>(peep->AmountOfFood);
if (peep->AmountOfFood != 1)
{
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_EXPENSES_FOOD_PLURAL, ft);
2022-07-03 22:00:37 +02:00
}
else
{
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_EXPENSES_FOOD, ft);
2022-07-03 22:00:37 +02:00
}
screenCoords.y += LIST_ROW_HEIGHT;
}
2022-07-03 22:00:37 +02:00
// Paid on drinks
{
2022-07-03 22:00:37 +02:00
auto ft = Formatter();
ft.Add<money64>(peep->PaidOnDrink);
ft.Add<uint16_t>(peep->AmountOfDrinks);
if (peep->AmountOfDrinks != 1)
{
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_EXPENSES_DRINK_PLURAL, ft);
2022-07-03 22:00:37 +02:00
}
else
{
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_EXPENSES_DRINK, ft);
2022-07-03 22:00:37 +02:00
}
screenCoords.y += LIST_ROW_HEIGHT;
}
2022-07-03 22:00:37 +02:00
// Paid on souvenirs
{
2022-07-03 22:00:37 +02:00
auto ft = Formatter();
ft.Add<money64>(peep->PaidOnSouvenirs);
ft.Add<uint16_t>(peep->AmountOfSouvenirs);
if (peep->AmountOfSouvenirs != 1)
{
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_EXPENSES_SOUVENIR_PLURAL, ft);
2022-07-03 22:00:37 +02:00
}
else
{
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_EXPENSES_SOUVENIR, ft);
2022-07-03 22:00:37 +02:00
}
}
}
2022-07-03 22:00:37 +02:00
#pragma endregion
2014-09-14 22:56:45 +02:00
2022-07-03 22:00:37 +02:00
#pragma region Thoughts
void ThoughtsTabDraw(DrawPixelInfo& dpi)
2022-07-03 22:00:37 +02:00
{
if (WidgetIsDisabled(*this, WIDX_TAB_5))
2022-07-03 22:00:37 +02:00
return;
2014-09-14 22:56:45 +02:00
2022-07-03 22:00:37 +02:00
const auto& widget = widgets[WIDX_TAB_5];
auto screenCoords = windowPos + ScreenCoordsXY{ widget.left, widget.top };
2014-09-14 22:56:45 +02:00
2022-07-03 22:00:37 +02:00
int32_t imageId = SPR_TAB_THOUGHTS_0;
if (page == WINDOW_GUEST_THOUGHTS)
{
imageId += (frame_no / 2) & 0x7;
}
GfxDrawSprite(&dpi, ImageId(imageId), screenCoords);
2019-05-04 18:23:29 +02:00
}
2014-09-14 22:56:45 +02:00
2022-07-03 22:00:37 +02:00
void OnUpdateThoughts()
{
2022-07-03 22:00:37 +02:00
frame_no++;
WidgetInvalidate(*this, WIDX_TAB_2);
WidgetInvalidate(*this, WIDX_TAB_5);
2022-07-03 22:00:37 +02:00
auto peep = GetGuest();
if (peep == nullptr)
{
return;
}
if (peep->WindowInvalidateFlags & PEEP_INVALIDATE_PEEP_THOUGHTS)
{
peep->WindowInvalidateFlags &= ~PEEP_INVALIDATE_PEEP_THOUGHTS;
Invalidate();
}
}
void OnDrawThoughts(DrawPixelInfo& dpi)
2018-06-22 23:21:44 +02:00
{
2022-07-03 22:00:37 +02:00
DrawWidgets(dpi);
OverviewTabDraw(dpi);
StatsTabDraw(dpi);
RidesTabDraw(dpi);
FinanceTabDraw(dpi);
ThoughtsTabDraw(dpi);
InventoryTabDraw(dpi);
DebugTabDraw(dpi);
const auto peep = GetGuest();
if (peep == nullptr)
{
2018-06-22 23:21:44 +02:00
return;
2022-07-03 22:00:37 +02:00
}
2022-07-03 22:00:37 +02:00
// cx dx
auto screenCoords = windowPos
+ ScreenCoordsXY{ widgets[WIDX_PAGE_BACKGROUND].left + 4, widgets[WIDX_PAGE_BACKGROUND].top + 4 };
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_GUEST_RECENT_THOUGHTS_LABEL);
2022-07-03 22:00:37 +02:00
screenCoords.y += 10;
for (const auto& thought : peep->Thoughts)
{
if (thought.type == PeepThoughtType::None)
return;
if (thought.freshness == 0)
continue;
2022-07-03 22:00:37 +02:00
int32_t widgWidth = widgets[WIDX_PAGE_BACKGROUND].right - widgets[WIDX_PAGE_BACKGROUND].left - 8;
2022-07-03 22:00:37 +02:00
auto ft = Formatter();
PeepThoughtSetFormatArgs(&thought, ft);
2023-02-24 22:05:07 +01:00
screenCoords.y += DrawTextWrapped(dpi, screenCoords, widgWidth, STR_BLACK_STRING, ft, { FontStyle::Small });
2022-07-03 22:00:37 +02:00
// If this is the last visible line end drawing.
if (screenCoords.y > windowPos.y + widgets[WIDX_PAGE_BACKGROUND].bottom - 32)
return;
}
}
#pragma endregion
#pragma region Inventory
void InventoryTabDraw(DrawPixelInfo& dpi)
{
if (WidgetIsDisabled(*this, WIDX_TAB_6))
2022-07-03 22:00:37 +02:00
return;
const auto& widget = widgets[WIDX_TAB_6];
auto screenCoords = windowPos + ScreenCoordsXY{ widget.left, widget.top };
GfxDrawSprite(&dpi, ImageId(SPR_TAB_GUEST_INVENTORY), screenCoords);
}
2022-07-03 22:00:37 +02:00
void OnUpdateInventory()
2019-05-04 18:23:29 +02:00
{
2022-07-03 22:00:37 +02:00
frame_no++;
WidgetInvalidate(*this, WIDX_TAB_2);
WidgetInvalidate(*this, WIDX_TAB_6);
2022-07-03 22:00:37 +02:00
auto peep = GetGuest();
if (peep == nullptr)
{
return;
}
if (peep->WindowInvalidateFlags & PEEP_INVALIDATE_PEEP_INVENTORY)
{
peep->WindowInvalidateFlags &= ~PEEP_INVALIDATE_PEEP_INVENTORY;
Invalidate();
}
2019-05-04 18:23:29 +02:00
}
2022-07-31 14:22:58 +02:00
std::pair<StringId, Formatter> InventoryFormatItem(Guest& guest, ShopItem item) const
2022-07-03 22:00:37 +02:00
{
auto& park = OpenRCT2::GetContext()->GetGameState()->GetPark();
auto parkName = park.Name.c_str();
2022-07-03 22:00:37 +02:00
// Default arguments
auto ft = Formatter();
ft.Add<uint32_t>(GetShopItemDescriptor(item).Image);
2022-07-31 14:22:58 +02:00
ft.Add<StringId>(GetShopItemDescriptor(item).Naming.Display);
ft.Add<StringId>(STR_STRING);
2022-07-03 22:00:37 +02:00
ft.Add<const char*>(parkName);
// Special overrides
Ride* invRide{};
switch (item)
{
case ShopItem::Balloon:
ft.Rewind();
ft.Add<uint32_t>(ImageId(GetShopItemDescriptor(item).Image, (guest.BalloonColour)).ToUInt32());
2022-07-03 22:00:37 +02:00
break;
case ShopItem::Photo:
invRide = GetRide(guest.Photo1RideRef);
2022-07-03 22:00:37 +02:00
if (invRide != nullptr)
{
2020-06-03 12:54:39 +02:00
ft.Rewind();
ft.Increment(6);
2022-07-03 22:00:37 +02:00
invRide->FormatNameTo(ft);
}
break;
case ShopItem::Umbrella:
ft.Rewind();
ft.Add<uint32_t>(ImageId(GetShopItemDescriptor(item).Image, (guest.UmbrellaColour)).ToUInt32());
2022-07-03 22:00:37 +02:00
break;
case ShopItem::Voucher:
switch (guest.VoucherType)
{
case VOUCHER_TYPE_PARK_ENTRY_FREE:
2020-06-03 12:54:39 +02:00
ft.Rewind();
ft.Increment(6);
2022-07-31 14:22:58 +02:00
ft.Add<StringId>(STR_PEEP_INVENTORY_VOUCHER_PARK_ENTRY_FREE);
ft.Add<StringId>(STR_STRING);
2022-07-03 22:00:37 +02:00
ft.Add<const char*>(parkName);
break;
case VOUCHER_TYPE_RIDE_FREE:
invRide = GetRide(guest.VoucherRideId);
2022-07-03 22:00:37 +02:00
if (invRide != nullptr)
{
ft.Rewind();
ft.Increment(6);
2022-07-31 14:22:58 +02:00
ft.Add<StringId>(STR_PEEP_INVENTORY_VOUCHER_RIDE_FREE);
2022-07-03 22:00:37 +02:00
invRide->FormatNameTo(ft);
}
break;
case VOUCHER_TYPE_PARK_ENTRY_HALF_PRICE:
ft.Rewind();
ft.Increment(6);
2022-07-31 14:22:58 +02:00
ft.Add<StringId>(STR_PEEP_INVENTORY_VOUCHER_PARK_ENTRY_HALF_PRICE);
ft.Add<StringId>(STR_STRING);
2022-07-03 22:00:37 +02:00
ft.Add<const char*>(parkName);
break;
case VOUCHER_TYPE_FOOD_OR_DRINK_FREE:
ft.Rewind();
ft.Increment(6);
2022-07-31 14:22:58 +02:00
ft.Add<StringId>(STR_PEEP_INVENTORY_VOUCHER_FOOD_OR_DRINK_FREE);
ft.Add<StringId>(GetShopItemDescriptor(guest.VoucherShopItem).Naming.Singular);
2022-07-03 22:00:37 +02:00
break;
}
break;
case ShopItem::Hat:
ft.Rewind();
ft.Add<uint32_t>(ImageId(GetShopItemDescriptor(item).Image, (guest.HatColour)).ToUInt32());
2022-07-03 22:00:37 +02:00
break;
case ShopItem::TShirt:
ft.Rewind();
ft.Add<uint32_t>(ImageId(GetShopItemDescriptor(item).Image, (guest.TshirtColour)).ToUInt32());
2022-07-03 22:00:37 +02:00
break;
case ShopItem::Photo2:
invRide = GetRide(guest.Photo2RideRef);
2022-07-03 22:00:37 +02:00
if (invRide != nullptr)
{
2020-06-03 12:54:39 +02:00
ft.Rewind();
ft.Increment(6);
2022-07-03 22:00:37 +02:00
invRide->FormatNameTo(ft);
}
break;
case ShopItem::Photo3:
invRide = GetRide(guest.Photo3RideRef);
2022-07-03 22:00:37 +02:00
if (invRide != nullptr)
{
2020-06-03 12:54:39 +02:00
ft.Rewind();
ft.Increment(6);
2022-07-03 22:00:37 +02:00
invRide->FormatNameTo(ft);
}
break;
case ShopItem::Photo4:
invRide = GetRide(guest.Photo4RideRef);
2022-07-03 22:00:37 +02:00
if (invRide != nullptr)
{
ft.Rewind();
ft.Increment(6);
invRide->FormatNameTo(ft);
}
break;
default:
// This switch handles only items visible in peep window
break;
}
return std::make_pair(STR_GUEST_ITEM_FORMAT, ft);
}
void OnDrawInventory(DrawPixelInfo& dpi)
2022-07-03 22:00:37 +02:00
{
DrawWidgets(dpi);
OverviewTabDraw(dpi);
StatsTabDraw(dpi);
RidesTabDraw(dpi);
FinanceTabDraw(dpi);
ThoughtsTabDraw(dpi);
InventoryTabDraw(dpi);
DebugTabDraw(dpi);
2015-08-05 20:17:37 +02:00
2022-07-03 22:00:37 +02:00
const auto guest = GetGuest();
if (guest == nullptr)
{
return;
}
2022-12-24 16:50:29 +01:00
Widget* pageBackgroundWidget = &widgets[WIDX_PAGE_BACKGROUND];
2022-07-03 22:00:37 +02:00
auto screenCoords = windowPos + ScreenCoordsXY{ pageBackgroundWidget->left + 4, pageBackgroundWidget->top + 2 };
int32_t itemNameWidth = pageBackgroundWidget->width() - 8;
2022-07-03 22:00:37 +02:00
int32_t maxY = windowPos.y + height - 22;
int32_t numItems = 0;
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_CARRYING);
2022-07-03 22:00:37 +02:00
screenCoords.y += 10;
2022-07-03 22:00:37 +02:00
for (ShopItem item = ShopItem::Balloon; item < ShopItem::Count; item++)
{
if (screenCoords.y >= maxY)
break;
if (!guest->HasItem(item))
continue;
2022-07-03 22:00:37 +02:00
auto [stringId, ft] = InventoryFormatItem(*guest, item);
2023-02-24 22:05:07 +01:00
screenCoords.y += DrawTextWrapped(dpi, screenCoords, itemNameWidth, stringId, ft);
2022-07-03 22:00:37 +02:00
numItems++;
}
2022-07-03 22:00:37 +02:00
if (numItems == 0)
{
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_NOTHING);
2022-07-03 22:00:37 +02:00
}
}
2022-07-03 22:00:37 +02:00
#pragma endregion
2022-07-03 22:00:37 +02:00
#pragma region Debug
void DebugTabDraw(DrawPixelInfo& dpi)
{
if (WidgetIsDisabled(*this, WIDX_TAB_7))
2022-07-03 22:00:37 +02:00
return;
2022-07-03 22:00:37 +02:00
const auto& widget = widgets[WIDX_TAB_7];
auto screenCoords = windowPos + ScreenCoordsXY{ widget.left, widget.top };
2019-05-04 16:53:25 +02:00
2022-07-03 22:00:37 +02:00
int32_t imageId = SPR_TAB_GEARS_0;
if (page == WINDOW_GUEST_DEBUG)
{
imageId += (frame_no / 2) & 0x3;
}
GfxDrawSprite(&dpi, ImageId(imageId), screenCoords);
}
2022-07-03 22:00:37 +02:00
void OnUpdateDebug()
{
2022-07-03 22:00:37 +02:00
frame_no++;
Invalidate();
}
2022-07-03 22:00:37 +02:00
void OnDrawDebug(DrawPixelInfo& dpi)
{
2022-07-03 22:00:37 +02:00
char buffer[512]{};
char buffer2[512]{};
DrawWidgets(dpi);
OverviewTabDraw(dpi);
StatsTabDraw(dpi);
RidesTabDraw(dpi);
FinanceTabDraw(dpi);
ThoughtsTabDraw(dpi);
InventoryTabDraw(dpi);
DebugTabDraw(dpi);
const auto peep = GetGuest();
if (peep == nullptr)
{
2022-07-03 22:00:37 +02:00
return;
}
2022-07-03 22:00:37 +02:00
auto screenCoords = windowPos
+ ScreenCoordsXY{ widgets[WIDX_PAGE_BACKGROUND].left + 4, widgets[WIDX_PAGE_BACKGROUND].top + 4 };
{
2022-07-03 22:00:37 +02:00
auto ft = Formatter();
2023-01-27 18:18:44 +01:00
ft.Add<uint32_t>(peep->Id);
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_PEEP_DEBUG_SPRITE_INDEX, ft);
}
2022-07-03 22:00:37 +02:00
screenCoords.y += LIST_ROW_HEIGHT;
{
auto ft = Formatter();
ft.Add<int32_t>(peep->x);
ft.Add<int32_t>(peep->y);
ft.Add<int32_t>(peep->z);
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_PEEP_DEBUG_POSITION, ft);
2022-07-03 22:00:37 +02:00
}
screenCoords.y += LIST_ROW_HEIGHT;
{
auto ft = Formatter();
ft.Add<int32_t>(peep->NextLoc.x);
ft.Add<int32_t>(peep->NextLoc.y);
ft.Add<int32_t>(peep->NextLoc.z);
OpenRCT2::FormatStringLegacy(buffer, sizeof(buffer), STR_PEEP_DEBUG_NEXT, ft.Data());
2022-07-03 22:00:37 +02:00
if (peep->GetNextIsSurface())
{
OpenRCT2::FormatStringLegacy(buffer2, sizeof(buffer2), STR_PEEP_DEBUG_NEXT_SURFACE, nullptr);
SafeStrCat(buffer, buffer2, sizeof(buffer));
2022-07-03 22:00:37 +02:00
}
if (peep->GetNextIsSloped())
{
auto ft2 = Formatter();
ft2.Add<int32_t>(peep->GetNextDirection());
OpenRCT2::FormatStringLegacy(buffer2, sizeof(buffer2), STR_PEEP_DEBUG_NEXT_SLOPE, ft2.Data());
SafeStrCat(buffer, buffer2, sizeof(buffer));
2022-07-03 22:00:37 +02:00
}
2023-02-24 22:05:07 +01:00
GfxDrawString(dpi, screenCoords, buffer, {});
2022-07-03 22:00:37 +02:00
}
screenCoords.y += LIST_ROW_HEIGHT;
{
auto ft = Formatter();
ft.Add<int32_t>(peep->DestinationX);
ft.Add<int32_t>(peep->DestinationY);
ft.Add<int32_t>(peep->DestinationTolerance);
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_PEEP_DEBUG_DEST, ft);
2022-07-03 22:00:37 +02:00
}
screenCoords.y += LIST_ROW_HEIGHT;
{
auto ft = Formatter();
ft.Add<int32_t>(peep->PathfindGoal.x);
ft.Add<int32_t>(peep->PathfindGoal.y);
ft.Add<int32_t>(peep->PathfindGoal.z);
ft.Add<int32_t>(peep->PathfindGoal.direction);
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_PEEP_DEBUG_PATHFIND_GOAL, ft);
2022-07-03 22:00:37 +02:00
}
screenCoords.y += LIST_ROW_HEIGHT;
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_PEEP_DEBUG_PATHFIND_HISTORY);
2022-07-03 22:00:37 +02:00
screenCoords.y += LIST_ROW_HEIGHT;
screenCoords.x += 10;
for (auto& point : peep->PathfindHistory)
{
auto ft = Formatter();
ft.Add<int32_t>(point.x);
ft.Add<int32_t>(point.y);
ft.Add<int32_t>(point.z);
ft.Add<int32_t>(point.direction);
2023-02-24 22:05:07 +01:00
DrawTextBasic(dpi, screenCoords, STR_PEEP_DEBUG_PATHFIND_HISTORY_ITEM, ft);
2022-07-03 22:00:37 +02:00
screenCoords.y += LIST_ROW_HEIGHT;
}
screenCoords.x -= 10;
}
2022-07-03 22:00:37 +02:00
#pragma endregion
};
/**
*
* rct2: 0x006989E9
*
*/
WindowBase* WindowGuestOpen(Peep* peep)
2022-07-03 22:00:37 +02:00
{
if (peep == nullptr)
{
2022-07-03 22:00:37 +02:00
return nullptr;
}
2022-07-03 22:00:37 +02:00
if (peep->Is<Staff>())
{
2022-07-03 22:00:37 +02:00
return WindowStaffOpen(peep);
}
2023-01-27 18:18:44 +01:00
auto* window = static_cast<GuestWindow*>(WindowBringToFrontByNumber(WindowClass::Peep, peep->Id.ToUnderlying()));
2022-07-03 22:00:37 +02:00
if (window == nullptr)
{
2022-07-03 22:00:37 +02:00
int32_t windowWidth = 192;
if (gConfigGeneral.DebuggingTools)
2022-07-03 22:00:37 +02:00
windowWidth += TabWidth;
window = WindowCreate<GuestWindow>(WindowClass::Peep, windowWidth, 157, WF_RESIZABLE);
2022-07-03 22:00:37 +02:00
if (window == nullptr)
{
return nullptr;
}
}
2022-07-03 22:00:37 +02:00
2023-01-27 18:18:44 +01:00
window->Init(peep->Id);
2022-07-03 22:00:37 +02:00
return window;
}