1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 19:13:07 +01:00

Do not import garbage data in RCT1/2 news queues

This commit is contained in:
Gymnasiast
2025-03-18 23:24:50 +01:00
parent ccd86f1730
commit 79d4de341b
5 changed files with 84 additions and 53 deletions

View File

@@ -889,7 +889,8 @@ namespace OpenRCT2::RCT1
uint8_t TargetWeatherGloom;
uint8_t Rain;
uint8_t TargetRain;
RCT12NewsItem Messages[Limits::MaxNewsItems];
RCT12NewsItem recentMessages[Limits::kMaxRecentNewsItems];
RCT12NewsItem archivedMessages[Limits::kMaxArchivedNewsItems];
char ScenarioName[62];
uint16_t ScenarioSlotIndex;
uint32_t ScenarioFlags;

View File

@@ -2192,6 +2192,46 @@ namespace OpenRCT2::RCT1
park.Name = std::move(parkName);
}
std::vector<OpenRCT2::News::Item> convertNewsQueue(const RCT12NewsItem* queue, uint8_t size)
{
std::vector<OpenRCT2::News::Item> output{};
const RCT12NewsItem* src = queue;
for (uint8_t i = 0; i < size; i++)
{
News::Item dst{};
if (src->Type == 0)
break;
dst.Type = static_cast<News::ItemType>(src->Type);
dst.Flags = src->Flags;
dst.Ticks = src->Ticks;
dst.MonthYear = src->MonthYear;
dst.Day = src->Day;
dst.Text = ConvertFormattedStringToOpenRCT2(std::string_view(src->Text, sizeof(src->Text)));
if (dst.Type == News::ItemType::Research)
{
uint8_t researchItem = src->Assoc & 0x000000FF;
uint8_t researchType = (src->Assoc & 0x00FF0000) >> 16;
::ResearchItem tmpResearchItem = {};
ConvertResearchEntry(&tmpResearchItem, researchItem, researchType);
dst.Assoc = tmpResearchItem.rawValue;
}
else
{
dst.Assoc = src->Assoc;
}
output.emplace_back(dst);
src++;
}
return output;
}
void ImportParkFlags(GameState_t& gameState)
{
// Date and srand
@@ -2241,32 +2281,9 @@ namespace OpenRCT2::RCT1
}
// News items
for (size_t i = 0; i < Limits::MaxNewsItems; i++)
{
const RCT12NewsItem* src = &_s4.Messages[i];
News::Item* dst = &gameState.NewsItems[i];
dst->Type = static_cast<News::ItemType>(src->Type);
dst->Flags = src->Flags;
dst->Ticks = src->Ticks;
dst->MonthYear = src->MonthYear;
dst->Day = src->Day;
dst->Text = ConvertFormattedStringToOpenRCT2(std::string_view(src->Text, sizeof(src->Text)));
if (dst->Type == News::ItemType::Research)
{
uint8_t researchItem = src->Assoc & 0x000000FF;
uint8_t researchType = (src->Assoc & 0x00FF0000) >> 16;
::ResearchItem tmpResearchItem = {};
ConvertResearchEntry(&tmpResearchItem, researchItem, researchType);
dst->Assoc = tmpResearchItem.rawValue;
}
else
{
dst->Assoc = src->Assoc;
}
}
auto recentMessages = convertNewsQueue(_s4.recentMessages, std::size(_s4.recentMessages));
auto archivedMessages = convertNewsQueue(_s4.archivedMessages, std::size(_s4.archivedMessages));
News::importNewsItems(gameState, recentMessages, archivedMessages);
// Initial guest status
gameState.GuestInitialCash = ToMoney64(_s4.GuestInitialCash);

View File

@@ -16,7 +16,8 @@ namespace OpenRCT2::RCT12::Limits
constexpr uint8_t kMaxRidesInPark = 255;
constexpr uint8_t kMaxAwards = 4;
constexpr uint8_t MaxNewsItems = 61;
constexpr uint8_t kMaxRecentNewsItems = 11;
constexpr uint8_t kMaxArchivedNewsItems = 50;
constexpr uint8_t kMaxStationsPerRide = 4;
constexpr uint8_t kMaxPeepSpawns = 2;
constexpr uint8_t kMaxParkEntrances = 4;

View File

@@ -990,7 +990,8 @@ namespace OpenRCT2::RCT2
uint8_t NextWeatherGloom;
uint8_t CurrentWeatherLevel;
uint8_t NextWeatherLevel;
RCT12NewsItem NewsItems[Limits::MaxNewsItems];
RCT12NewsItem recentMessages[Limits::kMaxRecentNewsItems];
RCT12NewsItem archivedMessages[Limits::kMaxArchivedNewsItems];
char RCT1ScenarioName[62]; // Unused in RCT2
uint16_t RCT1ScenarioSlotIndex; // Unused in RCT2
uint32_t RCT1ScenarioFlags; // Unused in RCT2

View File

@@ -320,6 +320,38 @@ namespace OpenRCT2::RCT2
return {};
}
std::vector<OpenRCT2::News::Item> convertNewsQueue(const RCT12NewsItem* queue, uint8_t size)
{
std::vector<OpenRCT2::News::Item> output{};
const RCT12NewsItem* src = queue;
for (uint8_t i = 0; i < size; i++)
{
if (src->Type == 0)
break;
if (src->Type >= News::ItemTypeCount)
{
LOG_ERROR("Invalid news type 0x%x for news item %d, ignoring remaining news items", src->Type, i);
break;
}
News::Item dst{};
dst.Type = static_cast<News::ItemType>(src->Type);
dst.Flags = src->Flags;
dst.Assoc = src->Assoc;
dst.Ticks = src->Ticks;
dst.MonthYear = src->MonthYear;
dst.Day = src->Day;
dst.Text = ConvertFormattedStringToOpenRCT2(std::string_view(src->Text, sizeof(src->Text)));
output.emplace_back(dst);
src++;
}
return output;
}
void Import(GameState_t& gameState) override
{
Initialise(gameState);
@@ -573,30 +605,9 @@ namespace OpenRCT2::RCT2
};
// News items
News::InitQueue();
for (size_t i = 0; i < Limits::MaxNewsItems; i++)
{
const RCT12NewsItem* src = &_s6.NewsItems[i];
News::Item* dst = &gameState.NewsItems[i];
if (src->Type < News::ItemTypeCount)
{
dst->Type = static_cast<News::ItemType>(src->Type);
dst->Flags = src->Flags;
dst->Assoc = src->Assoc;
dst->Ticks = src->Ticks;
dst->MonthYear = src->MonthYear;
dst->Day = src->Day;
dst->Text = ConvertFormattedStringToOpenRCT2(std::string_view(src->Text, sizeof(src->Text)));
}
else
{
// In case where news item type is broken, consider all remaining news items invalid.
LOG_ERROR("Invalid news type 0x%x for news item %d, ignoring remaining news items", src->Type, i);
// Still need to set the correct type to properly terminate the queue
dst->Type = News::ItemType::Null;
break;
}
}
auto recentMessages = convertNewsQueue(_s6.recentMessages, std::size(_s6.recentMessages));
auto archivedMessages = convertNewsQueue(_s6.archivedMessages, std::size(_s6.archivedMessages));
News::importNewsItems(gameState, recentMessages, archivedMessages);
// Pad13CE730
// rct1_scenario_flags