Merge pull request #9437 from Gymnasiast/nog-eens-research

Move research to vectors
This commit is contained in:
Michael Steenbeek 2019-08-24 10:45:58 +02:00 committed by GitHub
commit e11f2d965a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 326 additions and 420 deletions

View File

@ -84,7 +84,7 @@ static void window_editor_inventions_list_drag_cursor(rct_window *w, rct_widgeti
static void window_editor_inventions_list_drag_moved(rct_window* w, int32_t x, int32_t y);
static void window_editor_inventions_list_drag_paint(rct_window *w, rct_drawpixelinfo *dpi);
static rct_string_id window_editor_inventions_list_prepare_name(const rct_research_item * researchItem, bool withGap);
static rct_string_id window_editor_inventions_list_prepare_name(const ResearchItem * researchItem, bool withGap);
// 0x0098177C
static rct_window_event_list window_editor_inventions_list_events = {
@ -152,7 +152,7 @@ static rct_window_event_list window_editor_inventions_list_drag_events = {
#pragma endregion
static rct_research_item *_editorInventionsListDraggedItem;
static ResearchItem _editorInventionsListDraggedItem;
static constexpr const rct_string_id EditorInventionsResearchCategories[] = {
STR_RESEARCH_NEW_TRANSPORT_RIDES,
@ -165,8 +165,8 @@ static constexpr const rct_string_id EditorInventionsResearchCategories[] = {
};
// clang-format on
static void window_editor_inventions_list_drag_open(rct_research_item* researchItem);
static void move_research_item(rct_research_item* beforeItem);
static void window_editor_inventions_list_drag_open(ResearchItem* researchItem);
static void move_research_item(ResearchItem* beforeItem, int32_t scrollIndex);
/**
*
@ -196,72 +196,47 @@ static void research_rides_setup()
*
* rct2: 0x006855E7
*/
static void move_research_item(rct_research_item* beforeItem)
static void move_research_item(ResearchItem* beforeItem, int32_t scrollIndex)
{
rct_window* w;
rct_research_item *researchItem, draggedItem;
if (_editorInventionsListDraggedItem + 1 == beforeItem)
return;
// Back up the dragged item
draggedItem = *_editorInventionsListDraggedItem;
// Remove dragged item from list
researchItem = _editorInventionsListDraggedItem;
do
{
*researchItem = *(researchItem + 1);
researchItem++;
} while (researchItem->rawValue != RESEARCHED_ITEMS_END_2);
// At end of this researchItem points to the end of the list
if (beforeItem > _editorInventionsListDraggedItem)
beforeItem--;
// Add dragged item to list
do
{
*researchItem = *(researchItem - 1);
researchItem--;
} while (researchItem != beforeItem);
*researchItem = draggedItem;
w = window_find_by_class(WC_EDITOR_INVENTION_LIST);
auto w = window_find_by_class(WC_EDITOR_INVENTION_LIST);
if (w != nullptr)
{
w->research_item = nullptr;
w->Invalidate();
}
research_remove(&_editorInventionsListDraggedItem);
auto& researchList = scrollIndex == 0 ? gResearchItemsInvented : gResearchItemsUninvented;
if (beforeItem != nullptr)
{
for (size_t i = 0; i < researchList.size(); i++)
{
if (researchList[i].Equals(beforeItem))
{
researchList.insert((researchList.begin() + i), _editorInventionsListDraggedItem);
return;
}
}
}
// Still not found? Append to end of list.
researchList.push_back(_editorInventionsListDraggedItem);
}
/**
*
* rct2: 0x0068558E
*/
static rct_research_item* window_editor_inventions_list_get_item_from_scroll_y(int32_t scrollIndex, int32_t y)
static ResearchItem* window_editor_inventions_list_get_item_from_scroll_y(int32_t scrollIndex, int32_t y)
{
rct_research_item* researchItem;
researchItem = gResearchItems;
if (scrollIndex != 0)
{
// Skip pre-researched items
for (; researchItem->rawValue != RESEARCHED_ITEMS_SEPARATOR; researchItem++)
{
}
researchItem++;
}
for (; researchItem->rawValue != RESEARCHED_ITEMS_SEPARATOR && researchItem->rawValue != RESEARCHED_ITEMS_END;
researchItem++)
auto& researchList = scrollIndex == 0 ? gResearchItemsInvented : gResearchItemsUninvented;
for (auto& researchItem : researchList)
{
y -= SCROLLABLE_ROW_HEIGHT;
if (y < 0)
{
return researchItem;
return &researchItem;
}
}
@ -272,35 +247,21 @@ static rct_research_item* window_editor_inventions_list_get_item_from_scroll_y(i
*
* rct2: 0x006855BB
*/
static rct_research_item* window_editor_inventions_list_get_item_from_scroll_y_include_seps(int32_t scrollIndex, int32_t y)
static ResearchItem* window_editor_inventions_list_get_item_from_scroll_y_include_seps(int32_t scrollIndex, int32_t y)
{
rct_research_item* researchItem;
researchItem = gResearchItems;
if (scrollIndex != 0)
{
// Skip pre-researched items
for (; researchItem->rawValue != RESEARCHED_ITEMS_SEPARATOR; researchItem++)
{
}
researchItem++;
}
for (; researchItem->rawValue != RESEARCHED_ITEMS_SEPARATOR && researchItem->rawValue != RESEARCHED_ITEMS_END;
researchItem++)
auto& researchList = scrollIndex == 0 ? gResearchItemsInvented : gResearchItemsUninvented;
for (auto& researchItem : researchList)
{
y -= SCROLLABLE_ROW_HEIGHT;
if (y < 0)
{
return researchItem;
return &researchItem;
}
}
return researchItem;
return nullptr;
}
static rct_research_item* get_research_item_at(int32_t x, int32_t y)
static ResearchItem* get_research_item_at(int32_t x, int32_t y, int32_t* outScrollId)
{
rct_window* w = window_find_by_class(WC_EDITOR_INVENTION_LIST);
if (w != nullptr && w->x <= x && w->y < y && w->x + w->width > x && w->y + w->height > y)
@ -310,18 +271,19 @@ static rct_research_item* get_research_item_at(int32_t x, int32_t y)
if (widgetIndex == WIDX_PRE_RESEARCHED_SCROLL || widgetIndex == WIDX_RESEARCH_ORDER_SCROLL)
{
gPressedWidget.widget_index = widgetIndex;
int32_t outX, outY, outScrollArea, outScrollId;
widget_scroll_get_part(w, widget, x, y, &outX, &outY, &outScrollArea, &outScrollId);
int32_t outX, outY, outScrollArea;
widget_scroll_get_part(w, widget, x, y, &outX, &outY, &outScrollArea, outScrollId);
if (outScrollArea == SCROLL_PART_VIEW)
{
outScrollId = outScrollId == 0 ? 0 : 1;
*outScrollId = *outScrollId == 0 ? 0 : 1;
int32_t scrollY = y - (w->y + widget->top) + w->scrolls[outScrollId].v_top + 5;
return window_editor_inventions_list_get_item_from_scroll_y_include_seps(outScrollId, scrollY);
int32_t scrollY = y - (w->y + widget->top) + w->scrolls[*outScrollId].v_top + 5;
return window_editor_inventions_list_get_item_from_scroll_y_include_seps(*outScrollId, scrollY);
}
}
}
*outScrollId = -1;
return nullptr;
}
@ -348,7 +310,7 @@ rct_window* window_editor_inventions_list_open()
w->var_4AE = 0;
w->selected_tab = 0;
w->research_item = nullptr;
_editorInventionsListDraggedItem = nullptr;
_editorInventionsListDraggedItem.rawValue = -1;
w->min_width = WW;
w->min_height = WH;
@ -427,13 +389,13 @@ static void window_editor_inventions_list_update(rct_window* w)
window_event_invalidate_call(w);
widget_invalidate(w, WIDX_TAB_1);
if (_editorInventionsListDraggedItem == nullptr)
if (_editorInventionsListDraggedItem.IsInventedEndMarker())
return;
if (window_find_by_class(WC_EDITOR_INVENTION_LIST_DRAG) != nullptr)
return;
_editorInventionsListDraggedItem = nullptr;
_editorInventionsListDraggedItem.rawValue = -1;
w->Invalidate();
}
@ -443,22 +405,14 @@ static void window_editor_inventions_list_update(rct_window* w)
*/
static void window_editor_inventions_list_scrollgetheight(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height)
{
rct_research_item* researchItem;
*height = 0;
// Count / skip pre-researched items
for (researchItem = gResearchItems; researchItem->rawValue != RESEARCHED_ITEMS_SEPARATOR; researchItem++)
*height += SCROLLABLE_ROW_HEIGHT;
if (scrollIndex == 1)
if (scrollIndex == 0)
{
researchItem++;
// Count non pre-researched items
*height = 0;
for (; researchItem->rawValue != RESEARCHED_ITEMS_END; researchItem++)
*height += SCROLLABLE_ROW_HEIGHT;
*height += (int32_t)gResearchItemsInvented.size() * SCROLLABLE_ROW_HEIGHT;
}
else
{
*height += (int32_t)gResearchItemsUninvented.size() * SCROLLABLE_ROW_HEIGHT;
}
}
@ -468,14 +422,14 @@ static void window_editor_inventions_list_scrollgetheight(rct_window* w, int32_t
*/
static void window_editor_inventions_list_scrollmousedown(rct_window* w, int32_t scrollIndex, int32_t x, int32_t y)
{
rct_research_item* researchItem;
ResearchItem* researchItem;
researchItem = window_editor_inventions_list_get_item_from_scroll_y(scrollIndex, y);
if (researchItem == nullptr)
return;
// Disallow picking up always-researched items
if (researchItem->rawValue < RESEARCHED_ITEMS_END_2 || research_item_is_always_researched(researchItem))
if (research_item_is_always_researched(researchItem))
return;
w->Invalidate();
@ -488,7 +442,7 @@ static void window_editor_inventions_list_scrollmousedown(rct_window* w, int32_t
*/
static void window_editor_inventions_list_scrollmouseover(rct_window* w, int32_t scrollIndex, int32_t x, int32_t y)
{
rct_research_item* researchItem;
ResearchItem* researchItem;
researchItem = window_editor_inventions_list_get_item_from_scroll_y(scrollIndex, y);
if (researchItem != w->research_item)
@ -511,7 +465,7 @@ static void window_editor_inventions_list_scrollmouseover(rct_window* w, int32_t
static void window_editor_inventions_list_cursor(
rct_window* w, rct_widgetindex widgetIndex, int32_t x, int32_t y, int32_t* cursorId)
{
rct_research_item* researchItem;
ResearchItem* researchItem;
int32_t scrollIndex;
switch (widgetIndex)
@ -528,8 +482,7 @@ static void window_editor_inventions_list_cursor(
// Use the open hand as cursor for items that can be picked up
researchItem = window_editor_inventions_list_get_item_from_scroll_y(scrollIndex, y);
if (researchItem != nullptr && researchItem->rawValue >= RESEARCHED_ITEMS_END_2
&& !research_item_is_always_researched(researchItem))
if (researchItem != nullptr && !research_item_is_always_researched(researchItem))
{
*cursorId = CURSOR_HAND_OPEN;
}
@ -589,7 +542,7 @@ static void window_editor_inventions_list_invalidate(rct_window* w)
static void window_editor_inventions_list_paint(rct_window* w, rct_drawpixelinfo* dpi)
{
rct_widget* widget;
rct_research_item* researchItem;
ResearchItem* researchItem;
rct_string_id stringId;
int32_t x, y, width;
@ -616,8 +569,8 @@ static void window_editor_inventions_list_paint(rct_window* w, rct_drawpixelinfo
dpi, w->x + widget->left + 1, w->y + widget->top + 1, w->x + widget->right - 1, w->y + widget->bottom - 1,
ColourMapA[w->colours[1]].darkest);
researchItem = _editorInventionsListDraggedItem;
if (researchItem == nullptr)
researchItem = &_editorInventionsListDraggedItem;
if (researchItem->IsInventedEndMarker())
researchItem = w->research_item;
// If the research item is null or a list separator.
if (researchItem == nullptr || researchItem->rawValue < 0)
@ -676,36 +629,21 @@ static void window_editor_inventions_list_scrollpaint(rct_window* w, rct_drawpix
uint8_t paletteIndex = ColourMapA[w->colours[1]].mid_light;
gfx_clear(dpi, paletteIndex);
rct_research_item* researchItem = gResearchItems;
int32_t researchItemEndMarker;
if (scrollIndex == 1)
{
// Skip pre-researched items
for (; researchItem->rawValue != RESEARCHED_ITEMS_SEPARATOR; researchItem++)
{
}
researchItem++;
researchItemEndMarker = RESEARCHED_ITEMS_END;
}
else
{
researchItemEndMarker = RESEARCHED_ITEMS_SEPARATOR;
}
int16_t boxWidth = (w->widgets[WIDX_RESEARCH_ORDER_SCROLL].right - w->widgets[WIDX_RESEARCH_ORDER_SCROLL].left);
int16_t columnSplitOffset = boxWidth / 2;
int32_t itemY = -SCROLLABLE_ROW_HEIGHT;
do
const auto& researchList = scrollIndex == 0 ? gResearchItemsInvented : gResearchItemsUninvented;
for (const auto& researchItem : researchList)
{
itemY += SCROLLABLE_ROW_HEIGHT;
if (itemY + SCROLLABLE_ROW_HEIGHT < dpi->y || itemY >= dpi->y + dpi->height)
continue;
if (w->research_item == researchItem)
if (w->research_item == &researchItem)
{
int32_t top, bottom;
if (_editorInventionsListDraggedItem == nullptr)
if (_editorInventionsListDraggedItem.IsInventedEndMarker())
{
// Highlight
top = itemY;
@ -721,10 +659,7 @@ static void window_editor_inventions_list_scrollpaint(rct_window* w, rct_drawpix
gfx_filter_rect(dpi, 0, top, boxWidth, bottom, PALETTE_DARKEN_1);
}
if (researchItem->rawValue == RESEARCHED_ITEMS_SEPARATOR || researchItem->rawValue == RESEARCHED_ITEMS_END)
continue;
if (researchItem == _editorInventionsListDraggedItem)
if (researchItem.Equals(&_editorInventionsListDraggedItem))
continue;
utf8 groupNameBuffer[256], vehicleNameBuffer[256];
@ -732,9 +667,9 @@ static void window_editor_inventions_list_scrollpaint(rct_window* w, rct_drawpix
utf8* vehicleNamePtr = vehicleNameBuffer;
uint8_t colour;
if (research_item_is_always_researched(researchItem))
if (research_item_is_always_researched(&researchItem))
{
if (w->research_item == researchItem && _editorInventionsListDraggedItem == nullptr)
if (w->research_item == &researchItem && _editorInventionsListDraggedItem.IsInventedEndMarker())
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM_EXTRA_DARK;
else
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM_DARK;
@ -750,13 +685,13 @@ static void window_editor_inventions_list_scrollpaint(rct_window* w, rct_drawpix
vehicleNamePtr = utf8_write_codepoint(vehicleNamePtr, colour);
}
rct_string_id itemNameId = research_item_get_name(researchItem);
rct_string_id itemNameId = research_item_get_name(&researchItem);
if (researchItem->type == RESEARCH_ENTRY_TYPE_RIDE
&& !RideGroupManager::RideTypeIsIndependent(researchItem->baseRideType))
if (researchItem.type == RESEARCH_ENTRY_TYPE_RIDE
&& !RideGroupManager::RideTypeIsIndependent(researchItem.baseRideType))
{
const auto rideEntry = get_ride_entry(researchItem->entryIndex);
const rct_string_id rideGroupName = get_ride_naming(researchItem->baseRideType, rideEntry).name;
const auto rideEntry = get_ride_entry(researchItem.entryIndex);
const rct_string_id rideGroupName = get_ride_naming(researchItem.baseRideType, rideEntry).name;
format_string(
groupNamePtr, std::size(groupNameBuffer), STR_INVENTIONS_LIST_RIDE_AND_VEHICLE_NAME, (void*)&rideGroupName);
format_string(vehicleNamePtr, std::size(vehicleNameBuffer), itemNameId, nullptr);
@ -777,7 +712,7 @@ static void window_editor_inventions_list_scrollpaint(rct_window* w, rct_drawpix
gfx_clip_string(vehicleNameBuffer, columnSplitOffset - 11);
gfx_draw_string(dpi, vehicleNameBuffer, colour, columnSplitOffset + 1, itemY);
}
} while (researchItem++->rawValue != researchItemEndMarker);
}
}
#pragma region Drag item
@ -786,14 +721,14 @@ static void window_editor_inventions_list_scrollpaint(rct_window* w, rct_drawpix
*
* rct2: 0x006852F4
*/
static void window_editor_inventions_list_drag_open(rct_research_item* researchItem)
static void window_editor_inventions_list_drag_open(ResearchItem* researchItem)
{
char buffer[256], *ptr;
int32_t stringWidth;
rct_window* w;
window_close_by_class(WC_EDITOR_INVENTION_LIST_DRAG);
_editorInventionsListDraggedItem = researchItem;
_editorInventionsListDraggedItem = *researchItem;
rct_string_id stringId = research_item_get_name(researchItem);
ptr = buffer;
@ -833,7 +768,8 @@ static void window_editor_inventions_list_drag_cursor(
rct_window* inventionListWindow = window_find_by_class(WC_EDITOR_INVENTION_LIST);
if (inventionListWindow != nullptr)
{
rct_research_item* researchItem = get_research_item_at(x, y);
int32_t scrollId;
ResearchItem* researchItem = get_research_item_at(x, y, &scrollId);
if (researchItem != inventionListWindow->research_item)
{
inventionListWindow->Invalidate();
@ -849,20 +785,23 @@ static void window_editor_inventions_list_drag_cursor(
*/
static void window_editor_inventions_list_drag_moved(rct_window* w, int32_t x, int32_t y)
{
rct_research_item* researchItem;
ResearchItem* researchItem;
int32_t scrollId;
// Skip always researched items, so that the dragged item gets placed underneath them
do
{
researchItem = get_research_item_at(x, y);
researchItem = get_research_item_at(x, y, &scrollId);
y += LIST_ROW_HEIGHT;
} while (researchItem != nullptr && researchItem->rawValue >= 0 && research_item_is_always_researched(researchItem));
} while (researchItem != nullptr && research_item_is_always_researched(researchItem));
if (researchItem != nullptr)
move_research_item(researchItem);
if (scrollId != -1)
{
move_research_item(researchItem, scrollId);
}
window_close(w);
_editorInventionsListDraggedItem = nullptr;
_editorInventionsListDraggedItem.rawValue = -1;
window_invalidate_by_class(WC_EDITOR_INVENTION_LIST);
}
@ -877,11 +816,11 @@ static void window_editor_inventions_list_drag_paint(rct_window* w, rct_drawpixe
x = w->x;
y = w->y + 2;
drawString = window_editor_inventions_list_prepare_name(_editorInventionsListDraggedItem, true);
drawString = window_editor_inventions_list_prepare_name(&_editorInventionsListDraggedItem, true);
gfx_draw_string_left(dpi, drawString, gCommonFormatArgs, COLOUR_BLACK | COLOUR_FLAG_OUTLINE, x, y);
}
static rct_string_id window_editor_inventions_list_prepare_name(const rct_research_item* researchItem, bool withGap)
static rct_string_id window_editor_inventions_list_prepare_name(const ResearchItem* researchItem, bool withGap)
{
rct_string_id drawString;
rct_string_id stringId = research_item_get_name(researchItem);

View File

@ -292,7 +292,7 @@ static void remove_selected_objects_from_research(const rct_object_entry* instal
for (auto rideType : rideEntry->ride_type)
{
rct_research_item tmp = {};
ResearchItem tmp = {};
tmp.type = RESEARCH_ENTRY_TYPE_RIDE;
tmp.entryIndex = entry_index;
tmp.baseRideType = rideType;
@ -301,7 +301,7 @@ static void remove_selected_objects_from_research(const rct_object_entry* instal
}
else if (entry_type == OBJECT_TYPE_SCENERY_GROUP)
{
rct_research_item tmp = {};
ResearchItem tmp = {};
tmp.type = RESEARCH_ENTRY_TYPE_SCENERY;
tmp.entryIndex = entry_index;
research_remove(&tmp);

View File

@ -14,7 +14,7 @@
#include <list>
#include <memory>
struct rct_research_item;
struct ResearchItem;
struct rct_object_entry;
/**
@ -79,7 +79,7 @@ struct rct_window
{ // 0x494
uint32_t highlighted_item;
uint16_t ride_colour;
rct_research_item* research_item;
ResearchItem* research_item;
rct_object_entry* object_entry;
const scenario_index_entry* highlighted_scenario;
struct

View File

@ -46,13 +46,15 @@ uint8_t gResearchFundingLevel;
uint8_t gResearchPriorities;
uint16_t gResearchProgress;
uint8_t gResearchProgressStage;
rct_research_item gResearchLastItem;
ResearchItem gResearchLastItem;
uint8_t gResearchExpectedMonth;
uint8_t gResearchExpectedDay;
rct_research_item gResearchNextItem;
ResearchItem gResearchNextItem;
// 0x01358844[500]
rct_research_item gResearchItems[MAX_RESEARCH_ITEMS];
ResearchItem gResearchItems[MAX_RESEARCH_ITEMS];
std::vector<ResearchItem> gResearchItemsUninvented;
std::vector<ResearchItem> gResearchItemsInvented;
// 0x00EE787C
uint8_t gResearchUncompletedCategories;
@ -69,9 +71,8 @@ bool gSilentResearch = false;
*/
void research_reset_items()
{
gResearchItems[0].rawValue = RESEARCHED_ITEMS_SEPARATOR;
gResearchItems[1].rawValue = RESEARCHED_ITEMS_END;
gResearchItems[2].rawValue = RESEARCHED_ITEMS_END_2;
gResearchItemsUninvented.clear();
gResearchItemsInvented.clear();
}
/**
@ -81,13 +82,10 @@ void research_reset_items()
void research_update_uncompleted_types()
{
int32_t uncompletedResearchTypes = 0;
rct_research_item* researchItem = gResearchItems;
while (researchItem++->rawValue != RESEARCHED_ITEMS_SEPARATOR)
;
for (; researchItem->rawValue != RESEARCHED_ITEMS_END; researchItem++)
for (auto const& researchItem : gResearchItemsUninvented)
{
uncompletedResearchTypes |= (1 << researchItem->category);
uncompletedResearchTypes |= (1 << researchItem.category);
}
gResearchUncompletedCategories = uncompletedResearchTypes;
@ -127,64 +125,62 @@ static void research_invalidate_related_windows()
window_invalidate_by_class(WC_RESEARCH);
}
static void research_mark_as_fully_completed()
{
gResearchProgress = 0;
gResearchProgressStage = RESEARCH_STAGE_FINISHED_ALL;
research_invalidate_related_windows();
// Reset funding to 0 if no more rides.
auto gameAction = ParkSetResearchFundingAction(gResearchPriorities, 0);
GameActions::Execute(&gameAction);
}
/**
*
* rct2: 0x00684BE5
*/
static void research_next_design()
{
rct_research_item *firstUnresearchedItem, *researchItem, tmp;
int32_t ignoreActiveResearchTypes;
// Skip already researched items
firstUnresearchedItem = gResearchItems;
while (firstUnresearchedItem->rawValue != RESEARCHED_ITEMS_SEPARATOR)
if (gResearchItemsUninvented.empty())
{
firstUnresearchedItem++;
research_mark_as_fully_completed();
return;
}
ignoreActiveResearchTypes = 0;
researchItem = firstUnresearchedItem;
ResearchItem researchItem;
bool ignoreActiveResearchTypes = false;
auto it = gResearchItemsUninvented.begin();
for (;;)
{
researchItem++;
if (researchItem->rawValue == RESEARCHED_ITEMS_END)
researchItem = *it;
if (it == gResearchItemsUninvented.end())
{
if (!ignoreActiveResearchTypes)
{
ignoreActiveResearchTypes = 1;
researchItem = firstUnresearchedItem;
ignoreActiveResearchTypes = true;
it = gResearchItemsUninvented.begin();
continue;
}
else
{
gResearchProgress = 0;
gResearchProgressStage = RESEARCH_STAGE_FINISHED_ALL;
research_invalidate_related_windows();
// Reset funding to 0 if no more rides.
auto gameAction = ParkSetResearchFundingAction(gResearchPriorities, 0);
GameActions::Execute(&gameAction);
research_mark_as_fully_completed();
return;
}
}
else if (ignoreActiveResearchTypes || (gResearchPriorities & (1 << researchItem->category)))
else if (ignoreActiveResearchTypes || (gResearchPriorities & (1 << researchItem.category)))
{
break;
}
it++;
}
gResearchNextItem = *researchItem;
gResearchNextItem = researchItem;
gResearchProgress = 0;
gResearchProgressStage = RESEARCH_STAGE_DESIGNING;
// Bubble research item up until it is above the researched items separator
do
{
tmp = *researchItem;
*researchItem = *(researchItem - 1);
*(researchItem - 1) = tmp;
researchItem--;
} while ((researchItem + 1)->rawValue != RESEARCHED_ITEMS_SEPARATOR);
gResearchItemsUninvented.erase(it);
gResearchItemsInvented.push_back(researchItem);
research_invalidate_related_windows();
}
@ -193,7 +189,7 @@ static void research_next_design()
*
* rct2: 0x006848D4
*/
void research_finish_item(rct_research_item* researchItem)
void research_finish_item(ResearchItem* researchItem)
{
gResearchLastItem = *researchItem;
research_invalidate_related_windows();
@ -229,15 +225,15 @@ void research_finish_item(rct_research_item* researchItem)
ride_entry_set_invented(rideEntryIndex);
bool seenRideEntry[MAX_RIDE_OBJECTS]{};
rct_research_item* researchItem2 = gResearchItems;
for (; researchItem2->rawValue != RESEARCHED_ITEMS_END; researchItem2++)
for (auto const& researchItem3 : gResearchItemsUninvented)
{
if (researchItem2->rawValue != RESEARCHED_ITEMS_SEPARATOR && researchItem2->type == RESEARCH_ENTRY_TYPE_RIDE)
{
uint8_t index = researchItem2->entryIndex;
seenRideEntry[index] = true;
}
uint8_t index = researchItem3.entryIndex;
seenRideEntry[index] = true;
}
for (auto const& researchItem3 : gResearchItemsInvented)
{
uint8_t index = researchItem3.entryIndex;
seenRideEntry[index] = true;
}
// RCT2 made non-separated vehicles available at once, by removing all but one from research.
@ -386,54 +382,12 @@ void research_update()
}
}
void research_process_random_items()
{
rct_research_item* research = gResearchItems;
for (; research->rawValue != RESEARCHED_ITEMS_END; research++)
{
}
research++;
for (; research->rawValue != RESEARCHED_ITEMS_END_2; research += 2)
{
if (scenario_rand() & 1)
{
continue;
}
rct_research_item* edx = nullptr;
rct_research_item* ebp = nullptr;
rct_research_item* inner_research = gResearchItems;
do
{
if (research->rawValue == inner_research->rawValue)
{
edx = inner_research;
}
if ((research + 1)->rawValue == inner_research->rawValue)
{
ebp = inner_research;
}
} while ((inner_research++)->rawValue != RESEARCHED_ITEMS_END);
assert(edx != nullptr);
edx->rawValue = research->rawValue;
assert(ebp != nullptr);
ebp->rawValue = (research + 1)->rawValue;
uint8_t cat = edx->category;
edx->category = ebp->category;
ebp->category = cat;
}
}
/**
*
* rct2: 0x00684AC3
*/
void research_reset_current_item()
{
research_process_random_items();
set_every_ride_type_not_invented();
set_every_ride_entry_not_invented();
@ -441,9 +395,9 @@ void research_reset_current_item()
set_all_scenery_items_invented();
set_all_scenery_groups_not_invented();
for (rct_research_item* research = gResearchItems; research->rawValue != RESEARCHED_ITEMS_SEPARATOR; research++)
for (auto& researchItem : gResearchItemsInvented)
{
research_finish_item(research);
research_finish_item(&researchItem);
}
gResearchLastItem.rawValue = RESEARCHED_ITEMS_SEPARATOR;
@ -455,29 +409,9 @@ void research_reset_current_item()
*
* rct2: 0x006857FA
*/
static void research_insert_unresearched(int32_t rawValue, int32_t category)
static void research_insert_unresearched(int32_t rawValue, uint8_t category)
{
rct_research_item *researchItem, *researchItem2;
researchItem = gResearchItems;
do
{
if (researchItem->rawValue == RESEARCHED_ITEMS_END)
{
// Insert slot
researchItem2 = researchItem;
while (researchItem2->rawValue != RESEARCHED_ITEMS_END_2)
{
researchItem2++;
}
memmove(researchItem + 1, researchItem, (researchItem2 - researchItem + 1) * sizeof(rct_research_item));
// Place new item
researchItem->rawValue = rawValue;
researchItem->category = category;
break;
}
} while (rawValue != (researchItem++)->rawValue);
gResearchItemsUninvented.push_back({ rawValue, category });
}
/**
@ -486,52 +420,37 @@ static void research_insert_unresearched(int32_t rawValue, int32_t category)
*/
static void research_insert_researched(int32_t rawValue, uint8_t category)
{
rct_research_item *researchItem, *researchItem2;
researchItem = gResearchItems;
// First check to make sure that entry is not already accounted for
for (; researchItem->rawValue != RESEARCHED_ITEMS_END; researchItem++)
ResearchItem item = { rawValue, category };
if (item.Exists())
{
if ((researchItem->rawValue & 0xFFFFFF) == (rawValue & 0xFFFFFF))
{
return;
}
return;
}
researchItem = gResearchItems;
do
{
if (researchItem->rawValue == RESEARCHED_ITEMS_SEPARATOR)
{
// Insert slot
researchItem2 = researchItem;
while (researchItem2->rawValue != RESEARCHED_ITEMS_END_2)
{
researchItem2++;
}
memmove(researchItem + 1, researchItem, (researchItem2 - researchItem + 1) * sizeof(rct_research_item));
// Place new item
researchItem->rawValue = rawValue;
researchItem->category = category;
break;
}
} while (rawValue != (researchItem++)->rawValue);
gResearchItemsInvented.push_back(item);
}
/**
*
* rct2: 0x006857CF
*/
void research_remove(rct_research_item* researchItem)
void research_remove(ResearchItem* researchItem)
{
for (rct_research_item* researchItem2 = gResearchItems; researchItem2->rawValue != RESEARCHED_ITEMS_END; researchItem2++)
for (auto it = gResearchItemsUninvented.begin(); it != gResearchItemsUninvented.end(); it++)
{
if (researchItem2->rawValue == researchItem->rawValue)
auto& researchItem2 = *it;
if (researchItem2.Equals(researchItem))
{
do
{
*researchItem2 = *(researchItem2 + 1);
} while (researchItem2++->rawValue != RESEARCHED_ITEMS_END_2);
gResearchItemsUninvented.erase(it);
return;
}
}
for (auto it = gResearchItemsInvented.begin(); it != gResearchItemsInvented.end(); it++)
{
auto& researchItem2 = *it;
if (researchItem2.Equals(researchItem))
{
gResearchItemsInvented.erase(it);
return;
}
}
@ -773,7 +692,7 @@ void set_every_ride_entry_not_invented()
*
* rct2: 0x0068563D
*/
rct_string_id research_item_get_name(const rct_research_item* researchItem)
rct_string_id research_item_get_name(const ResearchItem* researchItem)
{
if (researchItem->type == RESEARCH_ENTRY_TYPE_RIDE)
{
@ -821,54 +740,76 @@ rct_string_id research_get_friendly_base_ride_type_name(uint8_t trackType, rct_r
*
* rct2: 0x00685A79
* Do not use the research list outside of the inventions list window with the flags
* Clears flags like "always researched".
*/
void research_remove_flags()
{
for (rct_research_item* research = gResearchItems; research->rawValue != RESEARCHED_ITEMS_END_2; research++)
for (auto& researchItem : gResearchItemsUninvented)
{
// Clear the always researched flags.
if (research->rawValue > RESEARCHED_ITEMS_SEPARATOR)
{
research->flags = 0;
}
researchItem.flags = 0;
}
for (auto& researchItem : gResearchItemsInvented)
{
researchItem.flags = 0;
}
}
void research_fix()
{
// Fix invalid research items
for (int32_t i = 0; i < MAX_RESEARCH_ITEMS; i++)
for (auto it = gResearchItemsInvented.begin(); it != gResearchItemsInvented.end();)
{
rct_research_item* researchItem = &gResearchItems[i];
if (researchItem->rawValue == RESEARCHED_ITEMS_SEPARATOR)
continue;
if (researchItem->rawValue == RESEARCHED_ITEMS_END)
auto& researchItem = *it;
if (researchItem.type == RESEARCH_ENTRY_TYPE_RIDE)
{
if (i == MAX_RESEARCH_ITEMS - 1)
{
(--researchItem)->rawValue = RESEARCHED_ITEMS_END;
}
(++researchItem)->rawValue = RESEARCHED_ITEMS_END_2;
break;
}
if (researchItem->rawValue == RESEARCHED_ITEMS_END_2)
break;
if (researchItem->type == RESEARCH_ENTRY_TYPE_RIDE)
{
rct_ride_entry* rideEntry = get_ride_entry(researchItem->entryIndex);
rct_ride_entry* rideEntry = get_ride_entry(researchItem.entryIndex);
if (rideEntry == nullptr)
{
research_remove(researchItem);
i--;
it = gResearchItemsInvented.erase(it);
}
else
{
it++;
}
}
else
{
rct_scenery_group_entry* sceneryGroupEntry = get_scenery_group_entry(researchItem->rawValue);
rct_scenery_group_entry* sceneryGroupEntry = get_scenery_group_entry(researchItem.rawValue);
if (sceneryGroupEntry == nullptr)
{
research_remove(researchItem);
i--;
it = gResearchItemsInvented.erase(it);
}
else
{
it++;
}
}
}
for (auto it = gResearchItemsUninvented.begin(); it != gResearchItemsUninvented.end();)
{
auto& researchItem = *it;
if (researchItem.type == RESEARCH_ENTRY_TYPE_RIDE)
{
rct_ride_entry* rideEntry = get_ride_entry(researchItem.entryIndex);
if (rideEntry == nullptr)
{
it = gResearchItemsUninvented.erase(it);
}
else
{
it++;
}
}
else
{
rct_scenery_group_entry* sceneryGroupEntry = get_scenery_group_entry(researchItem.rawValue);
if (sceneryGroupEntry == nullptr)
{
it = gResearchItemsUninvented.erase(it);
}
else
{
it++;
}
}
}
@ -914,51 +855,18 @@ void research_fix()
void research_items_make_all_unresearched()
{
rct_research_item *researchItem, *nextResearchItem, researchItemTemp;
int32_t sorted;
do
{
sorted = 1;
for (researchItem = gResearchItems; researchItem->rawValue != RESEARCHED_ITEMS_SEPARATOR; researchItem++)
{
if (research_item_is_always_researched(researchItem))
continue;
nextResearchItem = researchItem + 1;
if (nextResearchItem->rawValue == RESEARCHED_ITEMS_SEPARATOR
|| research_item_is_always_researched(nextResearchItem))
{
// Bubble up always researched item or separator
researchItemTemp = *researchItem;
*researchItem = *nextResearchItem;
*nextResearchItem = researchItemTemp;
sorted = 0;
if (researchItem->rawValue == RESEARCHED_ITEMS_SEPARATOR)
break;
}
}
} while (!sorted);
gResearchItemsUninvented.insert(
gResearchItemsUninvented.end(), std::make_move_iterator(gResearchItemsInvented.begin()),
std::make_move_iterator(gResearchItemsInvented.end()));
gResearchItemsInvented.clear();
}
void research_items_make_all_researched()
{
rct_research_item *researchItem, researchItemTemp;
// Find separator
for (researchItem = gResearchItems; researchItem->rawValue != RESEARCHED_ITEMS_SEPARATOR; researchItem++)
{
}
// Move separator below all items
for (; (researchItem + 1)->rawValue != RESEARCHED_ITEMS_END; researchItem++)
{
// Swap separator with research item
researchItemTemp = *researchItem;
*researchItem = *(researchItem + 1);
*(researchItem + 1) = researchItemTemp;
}
gResearchItemsInvented.insert(
gResearchItemsInvented.end(), std::make_move_iterator(gResearchItemsUninvented.begin()),
std::make_move_iterator(gResearchItemsUninvented.end()));
gResearchItemsUninvented.clear();
}
/**
@ -967,52 +875,41 @@ void research_items_make_all_researched()
*/
void research_items_shuffle()
{
rct_research_item *researchItem, *researchOrderBase, researchItemTemp;
int32_t i, numNonResearchedItems;
// Skip pre-researched items
for (researchItem = gResearchItems; researchItem->rawValue != RESEARCHED_ITEMS_SEPARATOR; researchItem++)
{
}
researchItem++;
researchOrderBase = researchItem;
// Count non pre-researched items
numNonResearchedItems = 0;
for (; researchItem->rawValue != RESEARCHED_ITEMS_END; researchItem++)
numNonResearchedItems++;
// Shuffle list
for (i = 0; i < numNonResearchedItems; i++)
{
int32_t ri = util_rand() % numNonResearchedItems;
if (ri == i)
continue;
researchItemTemp = researchOrderBase[i];
researchOrderBase[i] = researchOrderBase[ri];
researchOrderBase[ri] = researchItemTemp;
}
std::shuffle(std::begin(gResearchItemsUninvented), std::end(gResearchItemsUninvented), std::default_random_engine{});
}
bool research_item_is_always_researched(rct_research_item* researchItem)
bool research_item_is_always_researched(const ResearchItem* researchItem)
{
return (researchItem->flags
& (RESEARCH_ENTRY_FLAG_RIDE_ALWAYS_RESEARCHED | RESEARCH_ENTRY_FLAG_SCENERY_SET_ALWAYS_RESEARCHED))
!= 0;
}
bool rct_research_item::IsInventedEndMarker() const
bool ResearchItem::IsInventedEndMarker() const
{
return rawValue == RESEARCHED_ITEMS_SEPARATOR;
}
bool rct_research_item::IsUninventedEndMarker() const
bool ResearchItem::Equals(const ResearchItem* otherItem) const
{
return rawValue == RESEARCHED_ITEMS_END;
return (entryIndex == otherItem->entryIndex && baseRideType == otherItem->baseRideType && type == otherItem->type);
}
bool rct_research_item::IsRandomEndMarker() const
bool ResearchItem::Exists() const
{
return rawValue == RESEARCHED_ITEMS_END_2;
for (auto const& researchItem : gResearchItemsUninvented)
{
if (researchItem.Equals(this))
{
return true;
}
}
for (auto const& researchItem : gResearchItemsInvented)
{
if (researchItem.Equals(this))
{
return true;
}
}
return false;
}

View File

@ -15,8 +15,7 @@
struct rct_ride_entry;
#pragma pack(push, 1)
struct rct_research_item
struct ResearchItem
{
// Bit 16 (0: scenery entry, 1: ride entry)
union
@ -33,11 +32,9 @@ struct rct_research_item
uint8_t category;
bool IsInventedEndMarker() const;
bool IsRandomEndMarker() const;
bool IsUninventedEndMarker() const;
bool Equals(const ResearchItem* otherItem) const;
bool Exists() const;
};
assert_struct_size(rct_research_item, 5);
#pragma pack(pop)
enum
{
@ -100,10 +97,11 @@ extern uint16_t gResearchProgress;
extern uint8_t gResearchProgressStage;
extern uint8_t gResearchExpectedMonth;
extern uint8_t gResearchExpectedDay;
extern rct_research_item gResearchLastItem;
extern rct_research_item gResearchNextItem;
extern ResearchItem gResearchLastItem;
extern ResearchItem gResearchNextItem;
extern rct_research_item gResearchItems[MAX_RESEARCH_ITEMS];
extern std::vector<ResearchItem> gResearchItemsUninvented;
extern std::vector<ResearchItem> gResearchItemsInvented;
extern uint8_t gResearchUncompletedCategories;
extern bool gSilentResearch;
@ -113,11 +111,10 @@ void research_update();
void research_reset_current_item();
void research_populate_list_random();
void research_populate_list_researched();
void research_process_random_items();
void research_finish_item(rct_research_item* researchItem);
void research_finish_item(ResearchItem* researchItem);
void research_insert(int32_t researched, int32_t rawValue, uint8_t category);
void research_remove(rct_research_item* researchItem);
void research_remove(ResearchItem* researchItem);
void research_insert_ride_entry(uint8_t entryIndex, bool researched);
void research_insert_scenery_group_entry(uint8_t entryIndex, bool researched);
@ -139,7 +136,7 @@ void set_every_ride_type_invented();
void set_every_ride_type_not_invented();
void set_every_ride_entry_invented();
void set_every_ride_entry_not_invented();
rct_string_id research_item_get_name(const rct_research_item* researchItem);
rct_string_id research_item_get_name(const ResearchItem* researchItem);
rct_string_id research_get_friendly_base_ride_type_name(uint8_t trackType, rct_ride_entry* rideEntry);
void research_remove_flags();
void research_fix();
@ -147,4 +144,4 @@ void research_fix();
void research_items_make_all_unresearched();
void research_items_make_all_researched();
void research_items_shuffle();
bool research_item_is_always_researched(rct_research_item* researchItem);
bool research_item_is_always_researched(const ResearchItem* researchItem);

View File

@ -2496,7 +2496,7 @@ private:
uint8_t researchItem = src->Assoc & 0x000000FF;
uint8_t researchType = (src->Assoc & 0x00FF0000) >> 16;
rct_research_item tmpResearchItem = {};
ResearchItem tmpResearchItem = {};
ConvertResearchEntry(&tmpResearchItem, researchItem, researchType);
dst->Assoc = (uint32_t)tmpResearchItem.rawValue;
}
@ -2540,7 +2540,7 @@ private:
gTotalRideValueForMoney = _s4.total_ride_value_for_money;
}
void ConvertResearchEntry(rct_research_item* dst, uint8_t srcItem, uint8_t srcType)
void ConvertResearchEntry(ResearchItem* dst, uint8_t srcItem, uint8_t srcType)
{
dst->rawValue = RESEARCHED_ITEMS_SEPARATOR;
if (srcType == RCT1_RESEARCH_TYPE_RIDE)

View File

@ -915,3 +915,18 @@ void RCT12BannerElement::SetAllowedEdges(uint8_t newEdges)
flags &= ~0b00001111;
flags |= (newEdges & 0b00001111);
}
bool RCT12ResearchItem::IsInventedEndMarker() const
{
return rawValue == RCT12_RESEARCHED_ITEMS_SEPARATOR;
}
bool RCT12ResearchItem::IsUninventedEndMarker() const
{
return rawValue == RCT12_RESEARCHED_ITEMS_END;
}
bool RCT12ResearchItem::IsRandomEndMarker() const
{
return rawValue == RCT12_RESEARCHED_ITEMS_END_2;
}

View File

@ -57,6 +57,13 @@ enum class RCT12TrackDesignVersion : uint8_t
unknown
};
// Everything before this point has been researched
#define RCT12_RESEARCHED_ITEMS_SEPARATOR (-1)
// Everything before this point and after separator still requires research
#define RCT12_RESEARCHED_ITEMS_END (-2)
// Extra end of list entry. Leftover from RCT1.
#define RCT12_RESEARCHED_ITEMS_END_2 (-3)
#pragma pack(push, 1)
/* Maze Element entry size: 0x04 */
@ -658,6 +665,28 @@ struct RCT12MapAnimation
};
assert_struct_size(RCT12MapAnimation, 6);
struct RCT12ResearchItem
{
// Bit 16 (0: scenery entry, 1: ride entry)
union
{
int32_t rawValue;
struct
{
uint8_t entryIndex;
uint8_t baseRideType;
uint8_t type; // 0: scenery entry, 1: ride entry
uint8_t flags;
};
};
uint8_t category;
bool IsInventedEndMarker() const;
bool IsRandomEndMarker() const;
bool IsUninventedEndMarker() const;
};
assert_struct_size(RCT12ResearchItem, 5);
#pragma pack(pop)
bool is_user_string_id(rct_string_id stringId);

View File

@ -848,7 +848,18 @@ void S6Exporter::ExportResearchedSceneryItems()
void S6Exporter::ExportResearchList()
{
std::memcpy(_s6.research_items, gResearchItems, sizeof(_s6.research_items));
size_t i = 0;
for (const auto& researchItem : gResearchItemsInvented)
{
_s6.research_items[i++] = RCT12ResearchItem{ researchItem.rawValue, researchItem.category };
}
_s6.research_items[i++] = { RCT12_RESEARCHED_ITEMS_SEPARATOR, 0 };
for (const auto& researchItem : gResearchItemsUninvented)
{
_s6.research_items[i++] = RCT12ResearchItem{ researchItem.rawValue, researchItem.category };
}
_s6.research_items[i++] = { RCT12_RESEARCHED_ITEMS_END, 0 };
_s6.research_items[i] = { RCT12_RESEARCHED_ITEMS_END_2, 0 };
}
void S6Exporter::ExportMarketingCampaigns()

View File

@ -850,7 +850,25 @@ public:
void ImportResearchList()
{
std::memcpy(gResearchItems, _s6.research_items, sizeof(_s6.research_items));
bool invented = true;
for (size_t i = 0; i < sizeof(_s6.research_items); i++)
{
if (_s6.research_items[i].IsInventedEndMarker())
{
invented = false;
continue;
}
else if (_s6.research_items[i].IsUninventedEndMarker() || _s6.research_items[i].IsRandomEndMarker())
{
break;
}
RCT12ResearchItem* ri = &_s6.research_items[i];
if (invented)
gResearchItemsInvented.push_back(ResearchItem{ ri->rawValue, ri->category });
else
gResearchItemsUninvented.push_back(ResearchItem{ ri->rawValue, ri->category });
}
}
void ImportBanner(Banner* dst, const RCT12Banner* src)

View File

@ -238,7 +238,7 @@ struct rct_s6_data
uint8_t last_entrance_style;
uint8_t rct1_water_colour;
uint8_t pad_01358842[2];
rct_research_item research_items[MAX_RESEARCH_ITEMS];
RCT12ResearchItem research_items[MAX_RESEARCH_ITEMS];
uint16_t map_base_z;
char scenario_name[64];
char scenario_description[256];