1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-22 22:34:33 +01:00

Merge pull request #22694 from mrmbernardi/park-graphs-upgrade

Park graphs upgrade
This commit is contained in:
Aaron van Geffen
2024-09-26 23:18:59 +02:00
committed by GitHub
12 changed files with 120 additions and 45 deletions

View File

@@ -161,45 +161,40 @@ namespace OpenRCT2::Graph
}
}
void DrawFinanceGraph(DrawPixelInfo& dpi, const GraphProperties<money64>& p)
template<typename T, T TkNoValue>
static void DrawGraph(
DrawPixelInfo& dpi, const GraphProperties<T>& p, const FmtString& labelFmt, const FmtString& tooltipFmt)
{
const FmtString fmt("{BLACK}{CURRENCY2DP}");
DrawYLabels<money64>(dpi, p.internalBounds, p.min, p.max, p.numYLabels, p.yLabelStepPx, p.lineCol, fmt);
DrawMonths<money64, kMoney64Undefined>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx);
DrawLine<money64, kMoney64Undefined, true>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx, p.min, p.max);
DrawLine<money64, kMoney64Undefined, false>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx, p.min, p.max);
DrawYLabels<T>(dpi, p.internalBounds, p.min, p.max, p.numYLabels, p.yLabelStepPx, p.lineCol, labelFmt);
DrawMonths<T, TkNoValue>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx);
DrawLine<T, TkNoValue, true>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx, p.min, p.max);
DrawLine<T, TkNoValue, false>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx, p.min, p.max);
if (p.hoverIdx >= 0 && p.hoverIdx < p.numPoints)
{
const money64 value = p.series[p.hoverIdx];
if (value != kMoney64Undefined)
const T value = p.series[p.hoverIdx];
if (value != TkNoValue)
{
char buffer[64]{};
FormatStringToBuffer(buffer, sizeof(buffer), "{CURRENCY2DP}", value);
DrawHoveredValue<money64>(
FormatStringToBuffer(buffer, sizeof(buffer), tooltipFmt, value);
DrawHoveredValue<T>(
dpi, value, p.hoverIdx, p.internalBounds, p.xStepPx, p.min, p.max, buffer,
p.lineCol.withFlag(ColourFlag::withOutline, true));
}
}
}
void DrawRatingGraph(DrawPixelInfo& dpi, const GraphProperties<uint8_t>& p)
void DrawFinanceGraph(DrawPixelInfo& dpi, const GraphProperties<money64>& p)
{
constexpr uint8_t noValue = kParkRatingHistoryUndefined;
const FmtString fmt("{BLACK}{COMMA32}");
// Since the park rating rating history is divided by 4, we have to fudge the max number here.
DrawYLabels<uint16_t>(dpi, p.internalBounds, p.min, kParkRatingMax, p.numYLabels, p.yLabelStepPx, p.lineCol, fmt);
DrawMonths<uint8_t, noValue>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx);
DrawLine<uint8_t, noValue, true>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx, p.min, p.max);
DrawLine<uint8_t, noValue, false>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx, p.min, p.max);
DrawGraph<money64, kMoney64Undefined>(dpi, p, "{BLACK}{CURRENCY2DP}", "{CURRENCY2DP}");
}
void DrawRatingGraph(DrawPixelInfo& dpi, const GraphProperties<uint16_t>& p)
{
DrawGraph<uint16_t, kParkRatingHistoryUndefined>(dpi, p, "{BLACK}{COMMA32}", "{COMMA32}");
}
void DrawGuestGraph(DrawPixelInfo& dpi, const GraphProperties<uint32_t>& p)
{
constexpr uint32_t noValue = kGuestsInParkHistoryUndefined;
const FmtString fmt("{BLACK}{COMMA32}");
DrawYLabels<uint32_t>(dpi, p.internalBounds, p.min, p.max, p.numYLabels, p.yLabelStepPx, p.lineCol, fmt);
DrawMonths<uint32_t, noValue>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx);
DrawLine<uint32_t, noValue, true>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx, p.min, p.max);
DrawLine<uint32_t, noValue, false>(dpi, p.series, p.numPoints, p.internalBounds, p.xStepPx, p.min, p.max);
DrawGraph<uint32_t, kGuestsInParkHistoryUndefined>(dpi, p, "{BLACK}{COMMA32}", "{COMMA32}");
}
} // namespace OpenRCT2::Graph

View File

@@ -17,7 +17,6 @@
namespace OpenRCT2::Graph
{
constexpr int32_t kYTickMarkPadding = 8;
constexpr int32_t kParkRatingMax = 1000;
template<typename T> struct GraphProperties
{
@@ -68,6 +67,6 @@ namespace OpenRCT2::Graph
};
void DrawFinanceGraph(DrawPixelInfo& dpi, const GraphProperties<money64>& p);
void DrawRatingGraph(DrawPixelInfo& dpi, const GraphProperties<uint8_t>& p);
void DrawRatingGraph(DrawPixelInfo& dpi, const GraphProperties<uint16_t>& p);
void DrawGuestGraph(DrawPixelInfo& dpi, const GraphProperties<uint32_t>& p);
} // namespace OpenRCT2::Graph

View File

@@ -832,7 +832,7 @@ namespace OpenRCT2::Ui::Windows
_graphProps.min = centredGraph ? -max : 0.00_GBP;
_graphProps.max = max;
// dynamic padding for long axis lables:
// dynamic padding for long axis labels:
char buffer[64]{};
FormatStringToBuffer(buffer, sizeof(buffer), "{BLACK}{CURRENCY2DP}", centredGraph ? -max : max);
int32_t maxWidth = GfxGetStringWidth(buffer, FontStyle::Small) + Graph::kYTickMarkPadding + 1;

View File

@@ -39,8 +39,8 @@ namespace OpenRCT2::Ui::Windows
static constexpr StringId WINDOW_TITLE = STR_STRINGID;
static constexpr int32_t WH = 224;
static constexpr ScreenCoordsXY kGraphTopLeftPadding{ 45, 15 };
static constexpr ScreenCoordsXY kGraphBottomRightPadding{ 5, 5 };
static constexpr ScreenCoordsXY kGraphTopLeftPadding{ 45, 20 };
static constexpr ScreenCoordsXY kGraphBottomRightPadding{ 25, 10 };
static constexpr uint8_t kGraphNumYLabels = 6;
enum WindowParkPage
@@ -203,7 +203,7 @@ namespace OpenRCT2::Ui::Windows
int32_t _numberOfRides = -1;
uint8_t _peepAnimationFrame = 0;
Graph::GraphProperties<uint8_t> _ratingProps{};
Graph::GraphProperties<uint16_t> _ratingProps{};
Graph::GraphProperties<uint32_t> _guestProps{};
ScreenRect _ratingGraphBounds;
@@ -685,13 +685,18 @@ namespace OpenRCT2::Ui::Windows
#pragma region Rating page
void OnResizeRating()
{
WindowSetResize(*this, 255, 182, 255, 182);
flags |= WF_RESIZABLE;
WindowSetResize(*this, 268, 174 + 9, 2000, 2000);
}
void OnUpdateRating()
{
frame_no++;
WidgetInvalidate(*this, WIDX_TAB_2);
if (_ratingProps.UpdateHoverIndex())
{
InvalidateWidget(WIDX_BACKGROUND);
}
}
void OnPrepareDrawRating()
@@ -710,14 +715,14 @@ namespace OpenRCT2::Ui::Windows
AnchorBorderWidgets();
_ratingProps.min = 0;
_ratingProps.max = 250;
_ratingProps.max = 1000;
_ratingProps.series = GetGameState().Park.RatingHistory;
const Widget* background = &widgets[WIDX_PAGE_BACKGROUND];
_ratingGraphBounds = { windowPos + ScreenCoordsXY{ background->left + 4, background->top + 15 },
windowPos + ScreenCoordsXY{ background->right - 4, background->bottom - 4 } };
char buffer[64]{};
FormatStringToBuffer(buffer, sizeof(buffer), "{BLACK}{COMMA32}", Graph::kParkRatingMax);
FormatStringToBuffer(buffer, sizeof(buffer), "{BLACK}{COMMA32}", _ratingProps.max);
int32_t maxWidth = GfxGetStringWidth(buffer, FontStyle::Small) + Graph::kYTickMarkPadding + 1;
const ScreenCoordsXY dynamicPadding{ std::max(maxWidth, kGraphTopLeftPadding.x), kGraphTopLeftPadding.y };
@@ -740,6 +745,13 @@ namespace OpenRCT2::Ui::Windows
// Graph border
GfxFillRectInset(dpi, _ratingGraphBounds, colours[1], INSET_RECT_F_30);
// hide resize widget on graph area
constexpr ScreenCoordsXY offset{ 1, 1 };
constexpr ScreenCoordsXY bigOffset{ 5, 5 };
GfxFillRectInset(
dpi, { _ratingGraphBounds.Point2 - bigOffset, _ratingGraphBounds.Point2 - offset }, colours[1],
INSET_RECT_FLAG_FILL_DONT_LIGHTEN | INSET_RECT_FLAG_BORDER_NONE);
Graph::DrawRatingGraph(dpi, _ratingProps);
}
@@ -748,7 +760,8 @@ namespace OpenRCT2::Ui::Windows
#pragma region Guests page
void OnResizeGuests()
{
WindowSetResize(*this, 255, 182, 255, 182);
flags |= WF_RESIZABLE;
WindowSetResize(*this, 268, 174 + 9, 2000, 2000);
}
void OnUpdateGuests()
@@ -756,6 +769,10 @@ namespace OpenRCT2::Ui::Windows
frame_no++;
_peepAnimationFrame = (_peepAnimationFrame + 1) % 24;
WidgetInvalidate(*this, WIDX_TAB_3);
if (_guestProps.UpdateHoverIndex())
{
InvalidateWidget(WIDX_BACKGROUND);
}
}
void OnPrepareDrawGuests()
@@ -815,6 +832,13 @@ namespace OpenRCT2::Ui::Windows
// Graph border
GfxFillRectInset(dpi, _guestGraphBounds, colours[1], INSET_RECT_F_30);
// hide resize widget on graph area
constexpr ScreenCoordsXY offset{ 1, 1 };
constexpr ScreenCoordsXY bigOffset{ 5, 5 };
GfxFillRectInset(
dpi, { _guestGraphBounds.Point2 - bigOffset, _guestGraphBounds.Point2 - offset }, colours[1],
INSET_RECT_FLAG_FILL_DONT_LIGHTEN | INSET_RECT_FLAG_BORDER_NONE);
Graph::DrawGuestGraph(dpi, _guestProps);
}

View File

@@ -910,10 +910,52 @@ namespace OpenRCT2
return true;
});
cs.ReadWriteArray(gameState.Park.RatingHistory, [&cs](uint8_t& value) {
cs.ReadWrite(value);
return true;
});
if (version < k16BitParkHistoryVersion)
{
if (cs.GetMode() == OrcaStream::Mode::READING)
{
uint8_t smallHistory[kParkRatingHistorySize];
cs.ReadWriteArray(smallHistory, [&cs](uint8_t& value) {
cs.ReadWrite(value);
return true;
});
for (int i = 0; i < kParkRatingHistorySize; i++)
{
if (smallHistory[i] == RCT12ParkHistoryUndefined)
gameState.Park.RatingHistory[i] = kParkRatingHistoryUndefined;
else
{
gameState.Park.RatingHistory[i] = static_cast<uint16_t>(
smallHistory[i] * RCT12ParkRatingHistoryFactor);
}
}
}
else
{
uint8_t smallHistory[kParkRatingHistorySize];
for (int i = 0; i < kParkRatingHistorySize; i++)
{
if (gameState.Park.RatingHistory[i] == kParkRatingHistoryUndefined)
smallHistory[i] = RCT12ParkHistoryUndefined;
else
{
smallHistory[i] = static_cast<uint8_t>(
gameState.Park.RatingHistory[i] / RCT12ParkRatingHistoryFactor);
}
}
cs.ReadWriteArray(smallHistory, [&cs](uint8_t& value) {
cs.ReadWrite(value);
return true;
});
}
}
else
{
cs.ReadWriteArray(gameState.Park.RatingHistory, [&cs](uint16_t& value) {
cs.ReadWrite(value);
return true;
});
}
cs.ReadWriteArray(gameState.GuestsInParkHistory, [&cs](uint32_t& value) {
cs.ReadWrite(value);

View File

@@ -11,10 +11,10 @@ namespace OpenRCT2
struct GameState_t;
// Current version that is saved.
constexpr uint32_t PARK_FILE_CURRENT_VERSION = 37;
constexpr uint32_t PARK_FILE_CURRENT_VERSION = 38;
// The minimum version that is forwards compatible with the current version.
constexpr uint32_t PARK_FILE_MIN_VERSION = 33;
constexpr uint32_t PARK_FILE_MIN_VERSION = 38;
// The minimum version that is backwards compatible with the current version.
// If this is increased beyond 0, uncomment the checks in ParkFile.cpp and Context.cpp!
@@ -29,6 +29,7 @@ namespace OpenRCT2
constexpr uint16_t kBlockBrakeImprovementsVersion = 27;
constexpr uint16_t kGigaCoasterInversions = 31;
constexpr uint16_t kWoodenFlatToSteepVersion = 37;
constexpr uint16_t k16BitParkHistoryVersion = 38;
} // namespace OpenRCT2
class ParkFileExporter

View File

@@ -2150,7 +2150,13 @@ namespace OpenRCT2::RCT1
gameState.Park.Rating = _s4.ParkRating;
Park::ResetHistories(gameState);
std::copy(std::begin(_s4.ParkRatingHistory), std::end(_s4.ParkRatingHistory), gameState.Park.RatingHistory);
for (size_t i = 0; i < std::size(_s4.ParkRatingHistory); i++)
{
if (_s4.ParkRatingHistory[i] != RCT12ParkHistoryUndefined)
{
gameState.Park.RatingHistory[i] = _s4.ParkRatingHistory[i] * RCT12ParkRatingHistoryFactor;
}
}
for (size_t i = 0; i < std::size(_s4.GuestsInParkHistory); i++)
{
if (_s4.GuestsInParkHistory[i] != RCT12ParkHistoryUndefined)

View File

@@ -71,6 +71,7 @@ constexpr uint16_t RCT12VehicleTrackTypeMask = 0b1111111111111100;
constexpr uint8_t RCT12PeepThoughtItemNone = std::numeric_limits<uint8_t>::max();
constexpr uint8_t RCT12GuestsInParkHistoryFactor = 20;
constexpr uint8_t RCT12ParkRatingHistoryFactor = 4;
constexpr uint8_t RCT12ParkHistoryUndefined = std::numeric_limits<uint8_t>::max();
constexpr uint8_t kTD46RatingsMultiplier = 10;

View File

@@ -380,7 +380,13 @@ namespace OpenRCT2::RCT2
gameState.Park.Rating = _s6.ParkRating;
Park::ResetHistories(gameState);
std::copy(std::begin(_s6.ParkRatingHistory), std::end(_s6.ParkRatingHistory), gameState.Park.RatingHistory);
for (size_t i = 0; i < std::size(_s6.ParkRatingHistory); i++)
{
if (_s6.ParkRatingHistory[i] != RCT12ParkHistoryUndefined)
{
gameState.Park.RatingHistory[i] = _s6.ParkRatingHistory[i] * RCT12ParkRatingHistoryFactor;
}
}
for (size_t i = 0; i < std::size(_s6.GuestsInParkHistory); i++)
{
if (_s6.GuestsInParkHistory[i] != RCT12ParkHistoryUndefined)

View File

@@ -605,7 +605,7 @@ namespace OpenRCT2::Park
// Update park rating, guests in park and current cash history
constexpr auto ratingHistorySize = std::extent_v<decltype(ParkData::RatingHistory)>;
HistoryPushRecord<uint8_t, ratingHistorySize>(gameState.Park.RatingHistory, gameState.Park.Rating / 4);
HistoryPushRecord<uint16_t, ratingHistorySize>(gameState.Park.RatingHistory, gameState.Park.Rating);
constexpr auto numGuestsHistorySize = std::extent_v<decltype(GameState_t::GuestsInParkHistory)>;
HistoryPushRecord<uint32_t, numGuestsHistorySize>(gameState.GuestsInParkHistory, gameState.NumGuestsInPark);

View File

@@ -14,7 +14,7 @@
constexpr auto MAX_ENTRANCE_FEE = 999.00_GBP;
constexpr uint8_t kParkRatingHistoryUndefined = std::numeric_limits<uint8_t>::max();
constexpr uint16_t kParkRatingHistoryUndefined = std::numeric_limits<uint16_t>::max();
constexpr uint32_t kGuestsInParkHistoryUndefined = std::numeric_limits<uint32_t>::max();
constexpr uint8_t kParkRatingHistorySize = 32;
constexpr uint8_t kGuestsInParkHistorySize = 32;
@@ -61,7 +61,7 @@ namespace OpenRCT2
std::string Name;
uint64_t Flags;
uint16_t Rating;
uint8_t RatingHistory[kParkRatingHistorySize];
uint16_t RatingHistory[kParkRatingHistorySize];
int16_t RatingCasualtyPenalty;
money64 EntranceFee;
std::vector<CoordsXYZD> Entrances;