1
0
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:
Tulio Leao
2020-05-30 18:53:38 -03:00
committed by GitHub
3 changed files with 175 additions and 99 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();