1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-19 04:53:12 +01:00

Merge pull request #11972 from Gymnasiast/fix/7324

Fix #7324: Research window shows vehicle name instead of ride name
This commit is contained in:
Michael Steenbeek
2020-06-20 13:46:31 +02:00
committed by GitHub
11 changed files with 228 additions and 72 deletions

View File

@@ -3670,6 +3670,8 @@ STR_6372 :The specified path contains a RollerCoaster Tycoon 1 installation,
STR_6373 :Toggle clearance checks
STR_6374 :C
STR_6375 :Unknown Ride
STR_6376 :{WINDOW_COLOUR_2}Ride vehicle:{NEWLINE}{BLACK}{STRINGID} for {STRINGID}
STR_6377 :{WINDOW_COLOUR_2}Type: {BLACK}{STRINGID} for {STRINGID}
#############
# Scenarios #

View File

@@ -22,6 +22,7 @@
- Fix: [#5451] Guests scream on every descent, no matter how small.
- Fix: [#6119] Advertising campaign for ride window not updated properly (original bug).
- Fix: [#7006] Submarine Ride is in the wrong research group.
- Fix: [#7324] Research window shows vehicle name instead of ride name.
- Fix: [#10634] Guests are unable to use uphill paths out of toilets.
- Fix: [#10876] When removing a path, its guest entry point is not removed.
- Fix: [#10876] There can be multiple peep spawns on the same location.

View File

@@ -16,6 +16,7 @@
#include <openrct2/management/Finance.h>
#include <openrct2/management/NewsItem.h>
#include <openrct2/management/Research.h>
#include <openrct2/ride/RideData.h>
#include <openrct2/sprites.h>
#include <openrct2/world/Park.h>
#include <openrct2/world/Scenery.h>
@@ -362,16 +363,33 @@ void window_research_development_page_paint(rct_window* w, rct_drawpixelinfo* dp
else
{
// Research type
stringId = STR_RESEARCH_UNKNOWN;
std::array<rct_string_id, 2> strings = { STR_RESEARCH_UNKNOWN, 0 };
rct_string_id label = STR_RESEARCH_TYPE_LABEL;
if (gResearchProgressStage != RESEARCH_STAGE_INITIAL_RESEARCH)
{
stringId = ResearchCategoryNames[gResearchNextItem->category];
strings[0] = ResearchCategoryNames[gResearchNextItem->category];
if (gResearchProgressStage != RESEARCH_STAGE_DESIGNING)
{
stringId = gResearchNextItem->GetName();
strings[0] = gResearchNextItem->GetName();
if (gResearchNextItem->type == RESEARCH_ENTRY_TYPE_RIDE)
{
auto rtd = RideTypeDescriptors[gResearchNextItem->baseRideType];
if (!rtd.HasFlag(RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY))
{
if (gResearchNextItem->flags & RESEARCH_ENTRY_FLAG_FIRST_OF_TYPE)
{
strings[0] = rtd.Naming.Name;
}
else
{
strings[1] = rtd.Naming.Name;
label = STR_RESEARCH_TYPE_LABEL_VEHICLE;
}
}
}
}
}
gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_TYPE_LABEL, COLOUR_BLACK);
gfx_draw_string_left_wrapped(dpi, &strings, x, y, 296, label, COLOUR_BLACK);
y += 25;
// Progress
@@ -399,14 +417,34 @@ void window_research_development_page_paint(rct_window* w, rct_drawpixelinfo* dp
x = w->windowPos.x + 10;
y = w->windowPos.y + w->widgets[WIDX_LAST_DEVELOPMENT_GROUP + baseWidgetIndex].top + 12;
rct_string_id lastDevelopmentFormat;
if (gResearchLastItem.has_value())
{
stringId = gResearchLastItem->GetName();
rct_string_id lastDevelopmentFormat = STR_EMPTY;
std::array<rct_string_id, 2> strings = { gResearchLastItem->GetName(), 0 };
uint8_t type = gResearchLastItem->type;
lastDevelopmentFormat = (type == RESEARCH_ENTRY_TYPE_RIDE) ? STR_RESEARCH_RIDE_LABEL : STR_RESEARCH_SCENERY_LABEL;
if (type == RESEARCH_ENTRY_TYPE_SCENERY)
{
lastDevelopmentFormat = STR_RESEARCH_SCENERY_LABEL;
}
else
{
lastDevelopmentFormat = STR_RESEARCH_RIDE_LABEL;
auto rtd = RideTypeDescriptors[gResearchLastItem->baseRideType];
if (!rtd.HasFlag(RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY))
{
if (gResearchLastItem->flags & RESEARCH_ENTRY_FLAG_FIRST_OF_TYPE)
{
strings[0] = rtd.Naming.Name;
}
else
{
strings[1] = rtd.Naming.Name;
lastDevelopmentFormat = STR_RESEARCH_VEHICLE_LABEL;
}
}
}
gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 266, lastDevelopmentFormat, COLOUR_BLACK);
gfx_draw_string_left_wrapped(dpi, &strings, x, y, 266, lastDevelopmentFormat, COLOUR_BLACK);
}
}

View File

@@ -3911,6 +3911,9 @@ enum
STR_UNKNOWN_RIDE = 6375,
STR_RESEARCH_VEHICLE_LABEL = 6376,
STR_RESEARCH_TYPE_LABEL_VEHICLE = 6377,
// Have to include resource strings (from scenarios and objects) for the time being now that language is partially working
/* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings
};

View File

@@ -201,21 +201,8 @@ void research_finish_item(ResearchItem* researchItem)
if (rideEntry != nullptr && base_ride_type != RIDE_TYPE_NULL)
{
bool ride_group_was_invented_before = false;
bool ride_type_was_invented_before = ride_type_is_invented(base_ride_type);
rct_string_id availabilityString;
// Determine if the ride group this entry belongs to was invented before.
if (RideTypeDescriptors[base_ride_type].HasFlag(RIDE_TYPE_FLAG_HAS_RIDE_GROUPS))
{
const RideGroup* rideGroup = RideGroupManager::GetRideGroup(base_ride_type, rideEntry);
if (rideGroup->IsInvented())
{
ride_group_was_invented_before = true;
}
}
ride_type_set_invented(base_ride_type);
openrct2_assert(base_ride_type < RIDE_TYPE_COUNT, "Invalid base_ride_type = %d", base_ride_type);
@@ -256,17 +243,10 @@ void research_finish_item(ResearchItem* researchItem)
auto ft = Formatter::Common();
// If a vehicle should be listed separately (maze, mini golf, flat rides, shops)
if (RideTypeDescriptors[base_ride_type].HasFlag(RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY))
{
availabilityString = STR_NEWS_ITEM_RESEARCH_NEW_RIDE_AVAILABLE;
ft.Add<rct_string_id>(rideEntry->naming.Name);
}
// If a vehicle is the first to be invented for its ride group, show the ride group name.
else if (
!ride_type_was_invented_before
|| (RideTypeDescriptors[base_ride_type].HasFlag(RIDE_TYPE_FLAG_HAS_RIDE_GROUPS)
&& !ride_group_was_invented_before))
// If a vehicle is the first to be invented for its ride type or group, show the ride type/group name.
// Independently listed vehicles (like all flat rides and shops) should always be announced as such.
if (RideTypeDescriptors[base_ride_type].HasFlag(RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY)
|| researchItem->flags & RESEARCH_ENTRY_FLAG_FIRST_OF_TYPE)
{
RideNaming naming = get_ride_naming(base_ride_type, rideEntry);
availabilityString = STR_NEWS_ITEM_RESEARCH_NEW_RIDE_AVAILABLE;
@@ -740,11 +720,11 @@ void research_remove_flags()
{
for (auto& researchItem : gResearchItemsUninvented)
{
researchItem.flags = 0;
researchItem.flags &= ~(RESEARCH_ENTRY_FLAG_RIDE_ALWAYS_RESEARCHED | RESEARCH_ENTRY_FLAG_SCENERY_SET_ALWAYS_RESEARCHED);
}
for (auto& researchItem : gResearchItemsInvented)
{
researchItem.flags = 0;
researchItem.flags &= ~(RESEARCH_ENTRY_FLAG_RIDE_ALWAYS_RESEARCHED | RESEARCH_ENTRY_FLAG_SCENERY_SET_ALWAYS_RESEARCHED);
}
}
@@ -910,3 +890,121 @@ bool ResearchItem::Exists() const
}
return false;
}
static std::bitset<RIDE_TYPE_COUNT> _seenRideType = {};
static std::bitset<RIDE_TYPE_COUNT* MAX_RIDE_GROUPS_PER_RIDE_TYPE> _seenRideGroup = {};
static void research_update_first_of_type(ResearchItem* researchItem)
{
if (researchItem->IsNull())
return;
if (researchItem->type != RESEARCH_ENTRY_TYPE_RIDE)
return;
auto rideType = researchItem->baseRideType;
if (rideType >= RIDE_TYPE_COUNT)
{
log_error("Research item has non-existant ride type index %d", rideType);
return;
}
const auto& rtd = RideTypeDescriptors[rideType];
if (rtd.HasFlag(RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY))
{
researchItem->flags |= RESEARCH_ENTRY_FLAG_FIRST_OF_TYPE;
return;
}
if (!rtd.HasFlag(RIDE_TYPE_FLAG_HAS_RIDE_GROUPS))
{
if (!_seenRideType[rideType])
researchItem->flags |= RESEARCH_ENTRY_FLAG_FIRST_OF_TYPE;
_seenRideType[rideType] = true;
}
else
{
const auto& entry = get_ride_entry(researchItem->entryIndex);
if (entry != nullptr)
{
auto rideGroupIndex = RideGroupManager::GetRideGroupIndex(rideType, entry);
assert(rideGroupIndex < MAX_RIDE_GROUPS_PER_RIDE_TYPE);
if (!_seenRideGroup[rideType * rideGroupIndex])
researchItem->flags |= RESEARCH_ENTRY_FLAG_FIRST_OF_TYPE;
_seenRideGroup[rideType * rideGroupIndex] = true;
}
}
}
static void research_mark_ride_type_as_seen(const ResearchItem& researchItem)
{
auto rideType = researchItem.baseRideType;
if (rideType >= RIDE_TYPE_COUNT)
return;
const auto& rtd = RideTypeDescriptors[rideType];
if (!rtd.HasFlag(RIDE_TYPE_FLAG_HAS_RIDE_GROUPS))
{
_seenRideType[rideType] = true;
}
else
{
const auto& entry = get_ride_entry(researchItem.entryIndex);
if (entry != nullptr)
{
auto rideGroupIndex = RideGroupManager::GetRideGroupIndex(rideType, entry);
assert(rideGroupIndex < MAX_RIDE_GROUPS_PER_RIDE_TYPE);
_seenRideGroup[rideType * rideGroupIndex] = true;
}
}
}
void research_determine_first_of_type()
{
_seenRideType.reset();
_seenRideGroup.reset();
for (const auto& researchItem : gResearchItemsInvented)
{
if (researchItem.type != RESEARCH_ENTRY_TYPE_RIDE)
continue;
auto rideType = researchItem.baseRideType;
if (rideType >= RIDE_TYPE_COUNT)
continue;
const auto& rtd = RideTypeDescriptors[rideType];
if (rtd.HasFlag(RIDE_TYPE_FLAG_LIST_VEHICLES_SEPARATELY))
continue;
// The last research item will also be present in gResearchItemsInvented.
// Avoid marking its ride type as "invented" prematurely.
if (gResearchLastItem.has_value() && !gResearchLastItem->IsNull() && researchItem.Equals(&gResearchLastItem.value()))
continue;
// The next research item is also present in gResearchItemsInvented, even though it isn't invented yet(!)
if (gResearchNextItem.has_value() && !gResearchNextItem->IsNull() && researchItem.Equals(&gResearchNextItem.value()))
continue;
research_mark_ride_type_as_seen(researchItem);
}
if (gResearchLastItem.has_value())
{
research_update_first_of_type(&gResearchLastItem.value());
research_mark_ride_type_as_seen(gResearchLastItem.value());
}
if (gResearchNextItem.has_value())
{
research_update_first_of_type(&gResearchNextItem.value());
research_mark_ride_type_as_seen(gResearchNextItem.value());
}
for (auto& researchItem : gResearchItemsUninvented)
{
research_update_first_of_type(&researchItem);
}
}

View File

@@ -17,6 +17,19 @@
struct rct_ride_entry;
enum
{
RESEARCH_ENTRY_TYPE_SCENERY = 0,
RESEARCH_ENTRY_TYPE_RIDE = 1,
};
enum
{
RESEARCH_ENTRY_FLAG_FIRST_OF_TYPE = (1 << 0),
RESEARCH_ENTRY_FLAG_SCENERY_SET_ALWAYS_RESEARCHED = (1 << 5),
RESEARCH_ENTRY_FLAG_RIDE_ALWAYS_RESEARCHED = (1 << 6),
};
struct ResearchItem
{
union
@@ -67,7 +80,7 @@ struct ResearchItem
retItem.entryIndex = OpenRCT2EntryIndexToRCTEntryIndex(entryIndex);
retItem.baseRideType = baseRideType;
retItem.type = type;
retItem.flags = flags;
retItem.flags = (flags & ~RESEARCH_ENTRY_FLAG_FIRST_OF_TYPE);
retItem.category = category;
}
@@ -95,18 +108,6 @@ struct ResearchItem
}
};
enum
{
RESEARCH_ENTRY_TYPE_SCENERY = 0,
RESEARCH_ENTRY_TYPE_RIDE = 1,
};
enum
{
RESEARCH_ENTRY_FLAG_SCENERY_SET_ALWAYS_RESEARCHED = (1 << 5),
RESEARCH_ENTRY_FLAG_RIDE_ALWAYS_RESEARCHED = (1 << 6),
};
// Only used to mark as null nowadays. Deprecated. TODO: remove.
#define RESEARCH_ITEM_NULL 0xFFFFFFFF
@@ -192,3 +193,8 @@ void research_fix();
void research_items_make_all_unresearched();
void research_items_make_all_researched();
void research_items_shuffle();
/**
* Determines if a newly invented ride entry should be listed as a new ride
* or as a new vehicle for a pre-existing ride.
*/
void research_determine_first_of_type();

View File

@@ -399,31 +399,7 @@ void RideObject::SetRepositoryItem(ObjectRepositoryItem* item) const
}
item->RideInfo.RideFlags = 0;
// Determines the ride group. Will fall back to 0 if there is none found.
uint8_t rideGroupIndex = 0;
const RideGroup* rideGroup = RideGroupManager::GetRideGroup(firstRideType, &_legacyType);
// If the ride group is nullptr, the track type does not have ride groups.
if (rideGroup != nullptr)
{
for (uint8_t i = rideGroupIndex + 1; i < MAX_RIDE_GROUPS_PER_RIDE_TYPE; i++)
{
const RideGroup* irg = RideGroupManager::RideGroupFind(firstRideType, i);
if (irg != nullptr)
{
if (irg->Equals(rideGroup))
{
rideGroupIndex = i;
break;
}
}
}
}
item->RideInfo.RideGroupIndex = rideGroupIndex;
item->RideInfo.RideGroupIndex = RideGroupManager::GetRideGroupIndex(firstRideType, &_legacyType);
}
void RideObject::ReadLegacyVehicle(

View File

@@ -210,6 +210,7 @@ public:
game_convert_news_items_to_utf8();
map_count_remaining_land_rights();
research_determine_first_of_type();
}
bool GetDetails(scenario_index_entry* dst) override

View File

@@ -487,6 +487,8 @@ public:
OWNERSHIP_OWNED);
// clang-format on
}
research_determine_first_of_type();
}
void ImportRides()

View File

@@ -245,3 +245,30 @@ const RideGroup* RideGroupManager::RideGroupFind(const uint8_t rideType, const u
return nullptr;
}
}
uint8_t RideGroupManager::GetRideGroupIndex(const uint8_t rideType, const rct_ride_entry* rideEntry)
{
uint8_t rideGroupIndex = 0;
const RideGroup* rideGroup = RideGroupManager::GetRideGroup(rideType, rideEntry);
// If the ride group is nullptr, the track type does not have ride groups.
if (rideGroup != nullptr)
{
for (uint8_t i = rideGroupIndex + 1; i < MAX_RIDE_GROUPS_PER_RIDE_TYPE; i++)
{
const RideGroup* irg = RideGroupManager::RideGroupFind(rideType, i);
if (irg != nullptr)
{
if (irg->Equals(rideGroup))
{
rideGroupIndex = i;
break;
}
}
}
}
return rideGroupIndex;
}

View File

@@ -32,6 +32,8 @@ class RideGroupManager
{
public:
static const RideGroup* GetRideGroup(const uint8_t trackType, const rct_ride_entry* rideEntry);
/** Will fall back to 0 if there is none found. */
static uint8_t GetRideGroupIndex(const uint8_t trackType, const rct_ride_entry* rideEntry);
static const RideGroup* RideGroupFind(const uint8_t rideType, const uint8_t index);
};