mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-07 07:04:36 +01:00
Merge pull request #11715 from hdpoliveira/newsitem_queue_split
Create NewsItemQueue class
This commit is contained in:
@@ -150,7 +150,7 @@ static void window_news_update(rct_window* w)
|
||||
|
||||
j = w->news.var_480;
|
||||
w->news.var_480 = -1;
|
||||
for (i = 11; i < 61; i++)
|
||||
for (i = NEWS_ITEM_HISTORY_START; i < MAX_NEWS_ITEMS; i++)
|
||||
{
|
||||
if (news_item_is_empty(i))
|
||||
return;
|
||||
@@ -188,7 +188,7 @@ static void window_news_scrollgetsize(rct_window* w, int32_t scrollIndex, int32_
|
||||
int32_t itemHeight = window_news_get_item_height();
|
||||
|
||||
*height = 0;
|
||||
for (int32_t i = 11; i < 61; i++)
|
||||
for (int32_t i = NEWS_ITEM_HISTORY_START; i < MAX_NEWS_ITEMS; i++)
|
||||
{
|
||||
if (news_item_is_empty(i))
|
||||
break;
|
||||
@@ -208,7 +208,7 @@ static void window_news_scrollmousedown(rct_window* w, int32_t scrollIndex, cons
|
||||
|
||||
buttonIndex = 0;
|
||||
auto mutableScreenCoords = screenCoords;
|
||||
for (i = 11; i < 61; i++)
|
||||
for (i = NEWS_ITEM_HISTORY_START; i < MAX_NEWS_ITEMS; i++)
|
||||
{
|
||||
if (news_item_is_empty(i))
|
||||
break;
|
||||
@@ -238,7 +238,7 @@ static void window_news_scrollmousedown(rct_window* w, int32_t scrollIndex, cons
|
||||
|
||||
if (buttonIndex != 0)
|
||||
{
|
||||
w->news.var_480 = i - 11;
|
||||
w->news.var_480 = i - NEWS_ITEM_HISTORY_START;
|
||||
w->news.var_482 = buttonIndex;
|
||||
w->news.var_484 = 4;
|
||||
w->Invalidate();
|
||||
@@ -266,7 +266,7 @@ static void window_news_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32
|
||||
int32_t i, x, y, yy, press;
|
||||
|
||||
y = 0;
|
||||
for (i = 11; i < 61; i++)
|
||||
for (i = NEWS_ITEM_HISTORY_START; i < MAX_NEWS_ITEMS; i++)
|
||||
{
|
||||
NewsItem* const newsItem = news_item_get(i);
|
||||
if (news_item_is_empty(i))
|
||||
@@ -301,7 +301,7 @@ static void window_news_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32
|
||||
press = 0;
|
||||
if (w->news.var_480 != -1)
|
||||
{
|
||||
const uint8_t idx = 11 + w->news.var_480;
|
||||
const uint8_t idx = NEWS_ITEM_HISTORY_START + w->news.var_480;
|
||||
news_item_is_valid_idx(idx);
|
||||
if (i == idx && w->news.var_482 == 1)
|
||||
press = INSET_RECT_FLAG_BORDER_INSET;
|
||||
@@ -378,7 +378,7 @@ static void window_news_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32
|
||||
press = 0;
|
||||
if (w->news.var_480 != -1)
|
||||
{
|
||||
const uint8_t idx = 11 + w->news.var_480;
|
||||
const uint8_t idx = NEWS_ITEM_HISTORY_START + w->news.var_480;
|
||||
news_item_is_valid_idx(idx);
|
||||
if (i == idx && w->news.var_482 == 2)
|
||||
press = 0x20;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "../windows/Intent.h"
|
||||
#include "../world/Sprite.h"
|
||||
|
||||
NewsItem gNewsItems[MAX_NEWS_ITEMS];
|
||||
NewsItemQueue gNewsItems;
|
||||
|
||||
/** rct2: 0x0097BE7C */
|
||||
const uint8_t news_type_properties[] = {
|
||||
@@ -39,7 +39,25 @@ const uint8_t news_type_properties[] = {
|
||||
NEWS_TYPE_HAS_SUBJECT, // NEWS_ITEM_GRAPH
|
||||
};
|
||||
|
||||
static int32_t news_item_get_new_history_slot();
|
||||
NewsItem& NewsItemQueue::Current()
|
||||
{
|
||||
return Recent[0];
|
||||
}
|
||||
|
||||
const NewsItem& NewsItemQueue::Current() const
|
||||
{
|
||||
return Recent[0];
|
||||
}
|
||||
|
||||
NewsItem& NewsItemQueue::Oldest()
|
||||
{
|
||||
return Archived[0];
|
||||
}
|
||||
|
||||
const NewsItem& NewsItemQueue::Oldest() const
|
||||
{
|
||||
return Archived[0];
|
||||
}
|
||||
|
||||
bool news_item_is_valid_idx(int32_t index)
|
||||
{
|
||||
@@ -52,10 +70,33 @@ bool news_item_is_valid_idx(int32_t index)
|
||||
}
|
||||
|
||||
NewsItem* news_item_get(int32_t index)
|
||||
{
|
||||
return gNewsItems.At(index);
|
||||
}
|
||||
|
||||
NewsItem& NewsItemQueue::operator[](size_t index)
|
||||
{
|
||||
return const_cast<NewsItem&>(const_cast<const NewsItemQueue&>(*this)[index]);
|
||||
}
|
||||
|
||||
const NewsItem& NewsItemQueue::operator[](size_t index) const
|
||||
{
|
||||
if (index < NEWS_ITEM_HISTORY_START)
|
||||
return Recent[index];
|
||||
else
|
||||
return Archived[index - NEWS_ITEM_HISTORY_START];
|
||||
}
|
||||
|
||||
NewsItem* NewsItemQueue::At(int32_t index)
|
||||
{
|
||||
return const_cast<NewsItem*>(const_cast<const NewsItemQueue&>(*this).At(index));
|
||||
}
|
||||
|
||||
const NewsItem* NewsItemQueue::At(int32_t index) const
|
||||
{
|
||||
if (news_item_is_valid_idx(index))
|
||||
{
|
||||
return &gNewsItems[index];
|
||||
return &(*this)[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -65,23 +106,33 @@ NewsItem* news_item_get(int32_t index)
|
||||
|
||||
bool news_item_is_empty(int32_t index)
|
||||
{
|
||||
NewsItem* news = news_item_get(index);
|
||||
return news != nullptr && news->Type == NEWS_ITEM_NULL;
|
||||
NewsItem* news = gNewsItems.At(index);
|
||||
return news != nullptr && news->IsEmpty();
|
||||
}
|
||||
|
||||
bool news_item_is_queue_empty()
|
||||
{
|
||||
return news_item_is_empty(0);
|
||||
return gNewsItems.IsEmpty();
|
||||
}
|
||||
|
||||
bool NewsItemQueue::IsEmpty() const
|
||||
{
|
||||
return Current().IsEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x0066DF32
|
||||
*/
|
||||
void NewsItemQueue::Init()
|
||||
{
|
||||
Current().Type = NEWS_ITEM_NULL;
|
||||
Oldest().Type = NEWS_ITEM_NULL;
|
||||
}
|
||||
|
||||
void news_item_init_queue()
|
||||
{
|
||||
news_item_get(0)->Type = NEWS_ITEM_NULL;
|
||||
news_item_get(NEWS_ITEM_HISTORY_START)->Type = NEWS_ITEM_NULL;
|
||||
gNewsItems.Init();
|
||||
|
||||
// Throttles for warning types (PEEP_*_WARNING)
|
||||
for (auto& warningThrottle : gPeepWarningThrottle)
|
||||
@@ -93,10 +144,14 @@ void news_item_init_queue()
|
||||
context_broadcast_intent(&intent);
|
||||
}
|
||||
|
||||
uint16_t NewsItemQueue::IncrementTicks()
|
||||
{
|
||||
return ++Current().Ticks;
|
||||
}
|
||||
|
||||
static void news_item_tick_current()
|
||||
{
|
||||
int32_t ticks;
|
||||
ticks = ++news_item_get(0)->Ticks;
|
||||
int32_t ticks = gNewsItems.IncrementTicks();
|
||||
// Only play news item sound when in normal playing mode
|
||||
if (ticks == 1 && (gScreenFlags == SCREEN_FLAGS_PLAYING))
|
||||
{
|
||||
@@ -105,15 +160,18 @@ static void news_item_tick_current()
|
||||
}
|
||||
}
|
||||
|
||||
static bool news_item_is_current_old()
|
||||
int32_t NewsItemQueue::RemoveTime() const
|
||||
{
|
||||
int32_t remove_time = 320;
|
||||
if (!news_item_is_empty(5) && !news_item_is_empty(4) && !news_item_is_empty(3) && !news_item_is_empty(2))
|
||||
if (!Recent[5].IsEmpty() && !Recent[4].IsEmpty() && !Recent[3].IsEmpty() && !Recent[2].IsEmpty())
|
||||
{
|
||||
remove_time = 256;
|
||||
return 256;
|
||||
}
|
||||
return 320;
|
||||
}
|
||||
|
||||
return news_item_get(0)->Ticks >= remove_time;
|
||||
bool NewsItemQueue::CurrentShouldBeArchived() const
|
||||
{
|
||||
return Current().Ticks >= RemoveTime();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,7 +181,7 @@ static bool news_item_is_current_old()
|
||||
void news_item_update_current()
|
||||
{
|
||||
// Check if there is a current news item
|
||||
if (news_item_is_queue_empty())
|
||||
if (gNewsItems.IsEmpty())
|
||||
return;
|
||||
|
||||
auto intent = Intent(INTENT_ACTION_INVALIDATE_TICKER_NEWS);
|
||||
@@ -133,8 +191,8 @@ void news_item_update_current()
|
||||
news_item_tick_current();
|
||||
|
||||
// Removal of current news item
|
||||
if (news_item_is_current_old())
|
||||
news_item_close_current();
|
||||
if (gNewsItems.CurrentShouldBeArchived())
|
||||
gNewsItems.ArchiveCurrent();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,62 +201,48 @@ void news_item_update_current()
|
||||
*/
|
||||
void news_item_close_current()
|
||||
{
|
||||
int32_t i;
|
||||
NewsItem* newsItems = gNewsItems;
|
||||
gNewsItems.ArchiveCurrent();
|
||||
}
|
||||
|
||||
void NewsItemQueue::ArchiveCurrent()
|
||||
{
|
||||
// Check if there is a current message
|
||||
if (news_item_is_queue_empty())
|
||||
if (IsEmpty())
|
||||
return;
|
||||
|
||||
// Find an available history news item slot for current message
|
||||
i = news_item_get_new_history_slot();
|
||||
|
||||
// Set the history news item slot to the current news item
|
||||
newsItems[i] = newsItems[0];
|
||||
|
||||
// Set the end of the end of the history list
|
||||
if (i < MAX_NEWS_ITEMS - 1)
|
||||
newsItems[i + 1].Type = NEWS_ITEM_NULL;
|
||||
AppendToArchive(Current());
|
||||
|
||||
// Invalidate the news window
|
||||
window_invalidate_by_class(WC_RECENT_NEWS);
|
||||
|
||||
// Dequeue the current news item, shift news up
|
||||
for (i = 0; i < NEWS_ITEM_HISTORY_START - 1; i++)
|
||||
{
|
||||
newsItems[i] = newsItems[i + 1];
|
||||
}
|
||||
newsItems[NEWS_ITEM_HISTORY_START - 1].Type = NEWS_ITEM_NULL;
|
||||
memmove(Recent, Recent + 1, sizeof(NewsItem) * (std::size(Recent) - 1));
|
||||
Recent[NEWS_ITEM_HISTORY_START - 1].Type = NEWS_ITEM_NULL;
|
||||
|
||||
// Invalidate current news item bar
|
||||
auto intent = Intent(INTENT_ACTION_INVALIDATE_TICKER_NEWS);
|
||||
context_broadcast_intent(&intent);
|
||||
}
|
||||
|
||||
static void news_item_shift_history_up()
|
||||
{
|
||||
const int32_t history_idx = NEWS_ITEM_HISTORY_START;
|
||||
NewsItem* history_start = news_item_get(history_idx);
|
||||
const size_t count = sizeof(NewsItem) * (MAX_NEWS_ITEMS - 1 - history_idx);
|
||||
memmove(history_start, history_start + 1, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a spare history slot or replaces an existing one if there are no spare
|
||||
* slots available.
|
||||
*/
|
||||
static int32_t news_item_get_new_history_slot()
|
||||
void NewsItemQueue::AppendToArchive(NewsItem& item)
|
||||
{
|
||||
// Find an available history news item slot
|
||||
for (int32_t i = NEWS_ITEM_HISTORY_START; i < MAX_NEWS_ITEMS; i++)
|
||||
auto it = std::find_if(std::begin(Archived), std::end(Archived), [](const auto& newsItem) { return newsItem.IsEmpty(); });
|
||||
if (it != std::end(Archived))
|
||||
{
|
||||
if (news_item_is_empty(i))
|
||||
return i;
|
||||
*it = item;
|
||||
++it;
|
||||
if (it != std::end(Archived))
|
||||
it->Type = NEWS_ITEM_NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Dequeue the first history news item, shift history up
|
||||
news_item_shift_history_up();
|
||||
return MAX_NEWS_ITEMS - 1;
|
||||
memmove(Archived, Archived + 1, sizeof(NewsItem) * (std::size(Archived) - 1));
|
||||
Archived[MAX_NEWS_ITEMS_ARCHIVE - 1] = item;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,18 +339,17 @@ std::optional<CoordsXYZ> news_item_get_subject_location(int32_t type, int32_t su
|
||||
return subjectLoc;
|
||||
}
|
||||
|
||||
static NewsItem* news_item_first_open_queue_slot()
|
||||
NewsItem* NewsItemQueue::FirstOpenOrNewSlot()
|
||||
{
|
||||
NewsItem* newsItem = gNewsItems;
|
||||
|
||||
while (newsItem->Type != NEWS_ITEM_NULL)
|
||||
auto it = std::begin(Recent);
|
||||
for (; !it->IsEmpty();)
|
||||
{
|
||||
if (newsItem + 1 >= &gNewsItems[NEWS_ITEM_HISTORY_START - 1])
|
||||
news_item_close_current();
|
||||
if (it + 2 >= std::end(Recent))
|
||||
ArchiveCurrent();
|
||||
else
|
||||
newsItem++;
|
||||
it++;
|
||||
}
|
||||
return newsItem;
|
||||
return &*it;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -325,7 +368,7 @@ NewsItem* news_item_add_to_queue(uint8_t type, rct_string_id string_id, uint32_t
|
||||
|
||||
NewsItem* news_item_add_to_queue_raw(uint8_t type, const utf8* text, uint32_t assoc)
|
||||
{
|
||||
NewsItem* newsItem = news_item_first_open_queue_slot();
|
||||
NewsItem* newsItem = gNewsItems.FirstOpenOrNewSlot();
|
||||
newsItem->Type = type;
|
||||
newsItem->Flags = 0;
|
||||
newsItem->Assoc = assoc;
|
||||
@@ -438,48 +481,30 @@ void news_item_open_subject(int32_t type, int32_t subject)
|
||||
void news_item_disable_news(uint8_t type, uint32_t assoc)
|
||||
{
|
||||
// TODO: write test invalidating windows
|
||||
for (int32_t i = 0; i < NEWS_ITEM_HISTORY_START; i++)
|
||||
{
|
||||
if (!news_item_is_empty(i))
|
||||
gNewsItems.ForeachRecentNews([type, assoc](auto& newsItem) {
|
||||
if (type == newsItem.Type && assoc == newsItem.Assoc)
|
||||
{
|
||||
NewsItem* const newsItem = news_item_get(i);
|
||||
if (type == newsItem->Type && assoc == newsItem->Assoc)
|
||||
newsItem.Flags |= NEWS_FLAG_HAS_BUTTON;
|
||||
if (&newsItem == &gNewsItems.Current())
|
||||
{
|
||||
newsItem->Flags |= NEWS_FLAG_HAS_BUTTON;
|
||||
if (i == 0)
|
||||
{
|
||||
auto intent = Intent(INTENT_ACTION_INVALIDATE_TICKER_NEWS);
|
||||
context_broadcast_intent(&intent);
|
||||
}
|
||||
auto intent = Intent(INTENT_ACTION_INVALIDATE_TICKER_NEWS);
|
||||
context_broadcast_intent(&intent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (int32_t i = NEWS_ITEM_HISTORY_START; i < MAX_NEWS_ITEMS; i++)
|
||||
{
|
||||
if (!news_item_is_empty(i))
|
||||
gNewsItems.ForeachArchivedNews([type, assoc](auto& newsItem) {
|
||||
if (type == newsItem.Type && assoc == newsItem.Assoc)
|
||||
{
|
||||
NewsItem* const newsItem = news_item_get(i);
|
||||
if (type == newsItem->Type && assoc == newsItem->Assoc)
|
||||
{
|
||||
newsItem->Flags |= NEWS_FLAG_HAS_BUTTON;
|
||||
window_invalidate_by_class(WC_RECENT_NEWS);
|
||||
}
|
||||
newsItem.Flags |= NEWS_FLAG_HAS_BUTTON;
|
||||
window_invalidate_by_class(WC_RECENT_NEWS);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void news_item_add_to_queue_custom(NewsItem* newNewsItem)
|
||||
{
|
||||
NewsItem* newsItem = news_item_first_open_queue_slot();
|
||||
NewsItem* newsItem = gNewsItems.FirstOpenOrNewSlot();
|
||||
*newsItem = *newNewsItem;
|
||||
newsItem++;
|
||||
newsItem->Type = NEWS_ITEM_NULL;
|
||||
|
||||
@@ -52,14 +52,65 @@ struct NewsItem
|
||||
uint16_t MonthYear;
|
||||
uint8_t Day;
|
||||
utf8 Text[256];
|
||||
|
||||
constexpr bool IsEmpty() const noexcept
|
||||
{
|
||||
return Type == NEWS_ITEM_NULL;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr int32_t NEWS_ITEM_HISTORY_START = 11;
|
||||
constexpr int32_t MAX_NEWS_ITEMS = 61;
|
||||
constexpr int32_t MAX_NEWS_ITEMS_ARCHIVE = 50;
|
||||
constexpr int32_t MAX_NEWS_ITEMS = NEWS_ITEM_HISTORY_START + MAX_NEWS_ITEMS_ARCHIVE;
|
||||
|
||||
extern const uint8_t news_type_properties[10];
|
||||
|
||||
extern NewsItem gNewsItems[MAX_NEWS_ITEMS];
|
||||
struct NewsItemQueue
|
||||
{
|
||||
NewsItem& operator[](size_t index);
|
||||
const NewsItem& operator[](size_t index) const;
|
||||
NewsItem* At(int32_t index);
|
||||
const NewsItem* At(int32_t index) const;
|
||||
bool IsEmpty() const;
|
||||
void Init();
|
||||
uint16_t IncrementTicks();
|
||||
NewsItem& Current();
|
||||
const NewsItem& Current() const;
|
||||
NewsItem& Oldest();
|
||||
const NewsItem& Oldest() const;
|
||||
bool CurrentShouldBeArchived() const;
|
||||
void ArchiveCurrent();
|
||||
NewsItem* FirstOpenOrNewSlot();
|
||||
|
||||
template<typename Predicate> void ForeachRecentNews(Predicate&& p)
|
||||
{
|
||||
for (auto& newsItem : Recent)
|
||||
{
|
||||
if (newsItem.IsEmpty())
|
||||
break;
|
||||
p(newsItem);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Predicate> void ForeachArchivedNews(Predicate&& p)
|
||||
{
|
||||
for (auto& newsItem : Archived)
|
||||
{
|
||||
if (newsItem.IsEmpty())
|
||||
break;
|
||||
p(newsItem);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t RemoveTime() const;
|
||||
void AppendToArchive(NewsItem& item);
|
||||
|
||||
NewsItem Recent[NEWS_ITEM_HISTORY_START];
|
||||
NewsItem Archived[MAX_NEWS_ITEMS_ARCHIVE];
|
||||
};
|
||||
|
||||
extern NewsItemQueue gNewsItems;
|
||||
|
||||
void news_item_init_queue();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user