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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user