mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-15 11:03:00 +01:00
import research list as best as possible
This commit is contained in:
@@ -576,3 +576,21 @@ void game_command_set_research_funding(int* eax, int* ebx, int* ecx, int* edx, i
|
||||
|
||||
*ebx = 0;
|
||||
}
|
||||
|
||||
void research_insert_ride_entry(uint8 entryIndex, bool researched)
|
||||
{
|
||||
rct_ride_entry *rideEntry = get_ride_entry(entryIndex);
|
||||
uint8 category = rideEntry->category[0];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
uint8 rideType = rideEntry->ride_type[i];
|
||||
if (rideType != 255) {
|
||||
research_insert(researched, 0x10000 | (rideType << 8) | entryIndex, category);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void research_insert_scenery_group_entry(uint8 entryIndex, bool researched)
|
||||
{
|
||||
rct_scenery_set_entry *scenerySetEntry = g_scenerySetEntries[entryIndex];
|
||||
research_insert(researched, entryIndex, RESEARCH_CATEGORY_SCENERYSET);
|
||||
}
|
||||
|
||||
@@ -85,4 +85,7 @@ void research_finish_item(sint32 entryIndex);
|
||||
void research_insert(int researched, int entryIndex, int category);
|
||||
void research_remove(sint32 entryIndex);
|
||||
|
||||
void research_insert_ride_entry(uint8 entryIndex, bool researched);
|
||||
void research_insert_scenery_group_entry(uint8 entryIndex, bool researched);
|
||||
|
||||
#endif
|
||||
|
||||
217
src/rct1.c
217
src/rct1.c
@@ -222,7 +222,6 @@ void rct1_fix_landscape()
|
||||
rct1_load_default_objects();
|
||||
reset_loaded_objects();
|
||||
rct1_fix_walls();
|
||||
rct1_fix_scenery();
|
||||
rct1_fix_terrain();
|
||||
rct1_fix_entrance_positions();
|
||||
rct1_reset_research();
|
||||
@@ -390,34 +389,6 @@ static void rct1_fix_terrain()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006A2956
|
||||
*/
|
||||
static void rct1_fix_scenery()
|
||||
{
|
||||
rct_map_element *element;
|
||||
map_element_iterator it;
|
||||
|
||||
map_element_iterator_begin(&it);
|
||||
while (map_element_iterator_next(&it)) {
|
||||
element = it.element;
|
||||
|
||||
if (map_element_get_type(element) != MAP_ELEMENT_TYPE_SCENERY)
|
||||
continue;
|
||||
|
||||
switch (element->properties.scenery.type) {
|
||||
case 157: // TGE1 (Geometric Sculpture)
|
||||
case 162: // TGE2 (Geometric Sculpture)
|
||||
case 168: // TGE3 (Geometric Sculpture)
|
||||
case 170: // TGE4 (Geometric Sculpture)
|
||||
case 171: // TGE5 (Geometric Sculpture)
|
||||
element->properties.scenery.colour_2 = COLOUR_WHITE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This isn't really RCT1 specific anymore.
|
||||
* rct2: 0x006A2A68
|
||||
@@ -671,6 +642,17 @@ static void rct1_fix_colours()
|
||||
colour = RCT1ColourConversionTable[mapElement->properties.scenery.colour_1 & 0x1F];
|
||||
mapElement->properties.scenery.colour_1 &= 0xE0;
|
||||
mapElement->properties.scenery.colour_1 |= colour;
|
||||
|
||||
// Copied from [rct2: 0x006A2956]
|
||||
switch (mapElement->properties.scenery.type) {
|
||||
case 157: // TGE1 (Geometric Sculpture)
|
||||
case 162: // TGE2 (Geometric Sculpture)
|
||||
case 168: // TGE3 (Geometric Sculpture)
|
||||
case 170: // TGE4 (Geometric Sculpture)
|
||||
case 171: // TGE5 (Geometric Sculpture)
|
||||
mapElement->properties.scenery.colour_2 = COLOUR_WHITE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MAP_ELEMENT_TYPE_FENCE:
|
||||
colour = RCT1ColourConversionTable[
|
||||
@@ -1684,14 +1666,29 @@ static const rct_object_entry RCT1DefaultObjectsPathBits[] = {
|
||||
|
||||
static const rct_object_entry RCT1DefaultObjectsSceneryGroup[] = {
|
||||
{ 0x00000087, { "SCGTREES" }, 0 },
|
||||
{ 0x00000087, { "SCGPATHX" }, 0 },
|
||||
{ 0x00000087, { "SCGSHRUB" }, 0 },
|
||||
{ 0x00000087, { "SCGGARDN" }, 0 },
|
||||
{ 0x00000087, { "SCGPATHX" }, 0 },
|
||||
{ 0x00000087, { "SCGFENCE" }, 0 },
|
||||
{ 0x00000087, { "SCGMART " }, 0 },
|
||||
{ 0x00000087, { "SCGWOND " }, 0 },
|
||||
{ 0x00000087, { "SCGSNOW " }, 0 },
|
||||
{ 0x00000087, { "SCGWALLS" }, 0 }
|
||||
{ 0x00000087, { "SCGWALLS" }, 0 },
|
||||
|
||||
{ 0x00000087, { "SCGMINE " }, 0 }, // RCT1_SCENERY_THEME_MINE_THEME
|
||||
{ 0x00000087, { "SCGCLASS" }, 0 }, // RCT1_SCENERY_THEME_CLASSICAL_ROMAN
|
||||
{ 0x00000087, { "SCGEGYPT" }, 0 }, // RCT1_SCENERY_THEME_EGYPTIAN
|
||||
{ 0x00000087, { "SCGMART " }, 0 }, // RCT1_SCENERY_THEME_MARTIAN
|
||||
{ 0x00000087, { "SCGWOND " }, 0 }, // RCT1_SCENERY_THEME_TOYLAND
|
||||
{ 0x00000087, { "SCGJURAS" }, 0 }, // RCT1_SCENERY_THEME_JURASSIC
|
||||
{ 0x00000087, { "SCGSPOOK" }, 0 }, // RCT1_SCENERY_THEME_GRAVEYARD
|
||||
{ 0x00000087, { "SCGJUNGL" }, 0 }, // RCT1_SCENERY_THEME_JUNGLE
|
||||
{ 0x00000087, { "SCGABSTR" }, 0 }, // RCT1_SCENERY_THEME_ABSTRACT
|
||||
{ 0x00000087, { "SCGSNOW " }, 0 }, // RCT1_SCENERY_THEME_SNOW_ICE
|
||||
{ 0x00000087, { "SCGMEDIE" }, 0 }, // RCT1_SCENERY_THEME_MEDIEVAL
|
||||
{ 0x00000087, { "SCGSPACE" }, 0 }, // RCT1_SCENERY_THEME_SPACE
|
||||
{ 0x00000087, { "SCGHALLO" }, 0 }, // RCT1_SCENERY_THEME_CREEPY
|
||||
|
||||
// Not enough space to fit these last two themes (think about doing dynamic list)
|
||||
// { 0x00000087, { "SCGURBAN" }, 0 }, // RCT1_SCENERY_THEME_URBAN
|
||||
// { 0x00000087, { "SCGORIEN" }, 0 }, // RCT1_SCENERY_THEME_PAGODA
|
||||
};
|
||||
|
||||
static const rct_object_entry RCT1DefaultObjectsParkEntrance[] = {
|
||||
@@ -2011,6 +2008,27 @@ bool rideTypeShouldLoseSeparateFlag(rct_ride_entry *ride)
|
||||
return remove_flag;
|
||||
}
|
||||
|
||||
const uint8 RCT1SceneryGroupConvertTable[] = {
|
||||
255, // RCT1_SCENERY_THEME_GENERAL
|
||||
6, // RCT1_SCENERY_THEME_MINE_THEME
|
||||
7, // RCT1_SCENERY_THEME_CLASSICAL_ROMAN
|
||||
8, // RCT1_SCENERY_THEME_EGYPTIAN
|
||||
9, // RCT1_SCENERY_THEME_MARTIAN
|
||||
255, // RCT1_SCENERY_THEME_JUMPING_FOUNTAINS
|
||||
10, // RCT1_SCENERY_THEME_WONDERLAND
|
||||
11, // RCT1_SCENERY_THEME_JURASSIC
|
||||
12, // RCT1_SCENERY_THEME_SPOOKY
|
||||
13, // RCT1_SCENERY_THEME_JUNGLE
|
||||
14, // RCT1_SCENERY_THEME_ABSTRACT
|
||||
255, // RCT1_SCENERY_THEME_GARDEN_CLOCK
|
||||
15, // RCT1_SCENERY_THEME_SNOW_ICE
|
||||
16, // RCT1_SCENERY_THEME_MEDIEVAL
|
||||
17, // RCT1_SCENERY_THEME_SPACE
|
||||
18, // RCT1_SCENERY_THEME_CREEPY
|
||||
255, // RCT1_SCENERY_THEME_URBAN
|
||||
255 // RCT1_SCENERY_THEME_PAGODA
|
||||
};
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region RCT1 Scenario / Saved Game Import
|
||||
@@ -2192,7 +2210,6 @@ static void rct1_import_map_elements(rct1_s4 *s4)
|
||||
rct1_fix_paths();
|
||||
rct1_fix_walls();
|
||||
rct1_fix_banners(s4);
|
||||
rct1_fix_scenery();
|
||||
rct1_fix_terrain();
|
||||
rct1_fix_entrance_positions();
|
||||
|
||||
@@ -2363,6 +2380,134 @@ static void rct1_import_ride(rct1_s4 *s4, rct_ride *dst, rct1_ride *src)
|
||||
dst->excitement = (ride_rating)-1;
|
||||
}
|
||||
|
||||
static uint8 rct1_convert_vehicle_to_ride_entry_index(uint8 rct1RideType, uint8 vehicle)
|
||||
{
|
||||
uint8 rideEntryIndex = rct1RideType;
|
||||
if (vehicle < countof(RCT1AlternativeVehicleMappings)) {
|
||||
vehicle = RCT1AlternativeVehicleMappings[vehicle];
|
||||
if (vehicle != USE_DEFAULT_VEHICLE) {
|
||||
rideEntryIndex = vehicle;
|
||||
}
|
||||
}
|
||||
return rideEntryIndex;
|
||||
}
|
||||
|
||||
static bool _rct1ResearchRideEntryUsed[128];
|
||||
static bool _rct1ResearchRideTypeUsed[128];
|
||||
|
||||
static void rct1_research_insert_vehicle(const rct1_research_item *researchItem, bool researched)
|
||||
{
|
||||
uint8 rct1RideType = researchItem->related_ride;
|
||||
uint8 vehicle = researchItem->item;
|
||||
|
||||
uint8 rideEntryIndex = rct1_convert_vehicle_to_ride_entry_index(rct1RideType, vehicle);
|
||||
if (!_rct1ResearchRideEntryUsed[rideEntryIndex]) {
|
||||
_rct1ResearchRideEntryUsed[rideEntryIndex] = true;
|
||||
research_insert_ride_entry(rideEntryIndex, researched);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In RollerCoaster Tycoon 1 the research was divided up into scenery themes,
|
||||
* rides, vehicles for rides and special track pieces for rides. Currently
|
||||
* OpenRCT2 does not support researching of special track pieces and whether
|
||||
* vehicles are research-able depends on the vehicle object.
|
||||
*
|
||||
* TODO We might probably want to sort the researched items by the prefered
|
||||
* RCT1 order so the right image shows in the new ride window. This is
|
||||
* only relevant if RCT1 ride sorting is turned off.
|
||||
*/
|
||||
static void rct1_import_research_list(const rct1_s4 *s4)
|
||||
{
|
||||
int maxResearchItems = countof(s4->research_items);
|
||||
const rct1_research_item *researchItems = s4->research_items;
|
||||
|
||||
// Loopy Landscapes stores research items in a different place
|
||||
int gameVersion = sawyercoding_detect_rct1_version(s4->game_version) & FILE_VERSION_MASK;
|
||||
if (gameVersion == FILE_VERSION_RCT1_LL) {
|
||||
maxResearchItems = countof(s4->research_items_LL);
|
||||
researchItems = s4->research_items_LL;
|
||||
}
|
||||
|
||||
// Initialise the "seen" tables
|
||||
memset(_rct1ResearchRideEntryUsed, 0, sizeof(_rct1ResearchRideEntryUsed));
|
||||
memset(_rct1ResearchRideTypeUsed, 0, sizeof(_rct1ResearchRideTypeUsed));
|
||||
|
||||
// The first six scenery groups are always available
|
||||
for (int i = 0; i < 6; i++) {
|
||||
research_insert_scenery_group_entry(i, true);
|
||||
}
|
||||
|
||||
bool researched = true;
|
||||
for (int i = 0; i < maxResearchItems; i++) {
|
||||
const rct1_research_item *researchItem = &researchItems[i];
|
||||
if (researchItem->item == RCT1_RESEARCH_END_AVAILABLE) {
|
||||
researched = false;
|
||||
} else if (researchItem->item == RCT1_RESEARCH_END_RESEARCHABLE || researchItem->item == RCT1_RESEARCH_END) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (researchItem->category) {
|
||||
case RCT1_RESEARCH_CATEGORY_THEME:
|
||||
{
|
||||
uint8 rct1SceneryTheme = researchItem->item;
|
||||
uint8 sceneryGroupEntryIndex = RCT1SceneryGroupConvertTable[rct1SceneryTheme];
|
||||
if (sceneryGroupEntryIndex != 255) {
|
||||
research_insert_scenery_group_entry(sceneryGroupEntryIndex, researched);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RCT1_RESEARCH_CATEGORY_RIDE:
|
||||
{
|
||||
uint8 rct1RideType = researchItem->item;
|
||||
uint8 rideEntryIndex = rct1RideType;
|
||||
rct_ride_entry *rideEntry = get_ride_entry(rideEntryIndex);
|
||||
|
||||
// Add all vehicles for this ride type that are researched or before this research item
|
||||
uint32 numVehicles = 0;
|
||||
for (int j = 0; j < maxResearchItems; j++) {
|
||||
const rct1_research_item *researchItem2 = &researchItems[j];
|
||||
if (researchItem2->item == RCT1_RESEARCH_END_AVAILABLE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (researchItem->category == RCT1_RESEARCH_CATEGORY_VEHICLE &&
|
||||
researchItem->related_ride == rct1RideType
|
||||
) {
|
||||
// Only add the vehicles that were listed before this ride, otherwise we might
|
||||
// change the research order
|
||||
if (j < i) {
|
||||
rct1_research_insert_vehicle(researchItem, researched);
|
||||
}
|
||||
numVehicles++;
|
||||
}
|
||||
}
|
||||
|
||||
if (numVehicles == 0) {
|
||||
// No vehicles found so just add the default for this ride
|
||||
if (!_rct1ResearchRideEntryUsed[rideEntryIndex]) {
|
||||
_rct1ResearchRideEntryUsed[rideEntryIndex] = true;
|
||||
research_insert_ride_entry(rideEntryIndex, researched);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RCT1_RESEARCH_CATEGORY_VEHICLE:
|
||||
// Only add vehicle if the related ride has been seen, this to make sure that vehicles
|
||||
// are researched only after the ride has been researched
|
||||
if (_rct1ResearchRideTypeUsed[researchItem->related_ride]) {
|
||||
rct1_research_insert_vehicle(researchItem, researched);
|
||||
}
|
||||
break;
|
||||
case RCT1_RESEARCH_CATEGORY_SPECIAL:
|
||||
// Not supported
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
research_remove_non_separate_vehicle_types();
|
||||
}
|
||||
|
||||
static void rct1_import_s4_properly(rct1_s4 *s4)
|
||||
{
|
||||
int mapSize = s4->map_size == 0 ? 128 : s4->map_size;
|
||||
@@ -2396,7 +2541,7 @@ static void rct1_import_s4_properly(rct1_s4 *s4)
|
||||
|
||||
// Fix object availability
|
||||
research_reset_items();
|
||||
research_populate_list_researched();
|
||||
rct1_import_research_list(s4);
|
||||
|
||||
// Map elements
|
||||
rct1_import_map_elements(s4);
|
||||
|
||||
77
src/rct1.h
77
src/rct1.h
@@ -165,6 +165,14 @@ typedef struct {
|
||||
uint8 unk_17A[230];
|
||||
} rct1_ride;
|
||||
|
||||
typedef struct {
|
||||
uint8 item;
|
||||
uint8 related_ride;
|
||||
uint8 category;
|
||||
uint8 flags;
|
||||
uint8 expenditure_area;
|
||||
} rct1_research_item;
|
||||
|
||||
/**
|
||||
* RCT1,AA,LL scenario / saved game structure.
|
||||
* size: 0x1F850C
|
||||
@@ -226,7 +234,7 @@ typedef struct {
|
||||
uint8 last_research_ride;
|
||||
uint8 last_research_category;
|
||||
uint8 last_research_flag;
|
||||
rct_research_item research_items[200];
|
||||
rct1_research_item research_items[200];
|
||||
uint8 next_research_item;
|
||||
uint8 next_research_ride;
|
||||
uint8 next_research_category;
|
||||
@@ -291,7 +299,7 @@ typedef struct {
|
||||
uint8 unk_199C96[3];
|
||||
uint8 water_colour;
|
||||
uint16 unk_199C9A;
|
||||
rct_research_item research_items_LL[180];
|
||||
rct1_research_item research_items_LL[180];
|
||||
uint8 unk_19A020[5468];
|
||||
rct_banner banners[100];
|
||||
char string_table[1024][32];
|
||||
@@ -527,6 +535,71 @@ enum{
|
||||
|
||||
};
|
||||
|
||||
enum {
|
||||
RCT1_SCENERY_THEME_GENERAL,
|
||||
RCT1_SCENERY_THEME_MINE,
|
||||
RCT1_SCENERY_THEME_CLASSICAL_ROMAN,
|
||||
RCT1_SCENERY_THEME_EGYPTIAN,
|
||||
RCT1_SCENERY_THEME_MARTIAN,
|
||||
RCT1_SCENERY_THEME_JUMPING_FOUNTAINS, // Single researchable scenery item
|
||||
RCT1_SCENERY_THEME_WONDERLAND,
|
||||
RCT1_SCENERY_THEME_JURASSIC,
|
||||
RCT1_SCENERY_THEME_SPOOKY,
|
||||
RCT1_SCENERY_THEME_JUNGLE,
|
||||
RCT1_SCENERY_THEME_ABSTRACT,
|
||||
RCT1_SCENERY_THEME_GARDEN_CLOCK, // Single researchable scenery item
|
||||
RCT1_SCENERY_THEME_SNOW_ICE,
|
||||
RCT1_SCENERY_THEME_MEDIEVAL,
|
||||
RCT1_SCENERY_THEME_SPACE,
|
||||
RCT1_SCENERY_THEME_CREEPY,
|
||||
RCT1_SCENERY_THEME_URBAN,
|
||||
RCT1_SCENERY_THEME_PAGODA,
|
||||
};
|
||||
|
||||
enum {
|
||||
RCT1_RESEARCH_END_AVAILABLE = 0xFF,
|
||||
RCT1_RESEARCH_END_RESEARCHABLE = 0xFE,
|
||||
RCT1_RESEARCH_END = 0xFD,
|
||||
};
|
||||
|
||||
enum {
|
||||
RCT1_RESEARCH_CATEGORY_THEME,
|
||||
RCT1_RESEARCH_CATEGORY_RIDE,
|
||||
RCT1_RESEARCH_CATEGORY_VEHICLE,
|
||||
RCT1_RESEARCH_CATEGORY_SPECIAL,
|
||||
};
|
||||
|
||||
enum {
|
||||
RCT1_RESEARCH_EXPENDITURE_ROLLERCOASTERS,
|
||||
RCT1_RESEARCH_EXPENDITURE_THRILL_RIDES,
|
||||
RCT1_RESEARCH_EXPENDITURE_GENTLE_TRANSPORT_RIDES,
|
||||
RCT1_RESEARCH_EXPENDITURE_SHOPS,
|
||||
RCT1_RESEARCH_EXPENDITURE_SCENERY_THEMEING,
|
||||
RCT1_RESEARCH_EXPENDITURE_RIDE_IMPROVEMENTS,
|
||||
};
|
||||
|
||||
// Unconfirmed special track elements for research
|
||||
enum {
|
||||
RCT1_RESEARCH_SPECIAL_BANKED_CURVES = 0x06,
|
||||
RCT1_RESEARCH_SPECIAL_VERTICAL_LOOP = 0x07,
|
||||
RCT1_RESEARCH_SPECIAL_STEEP_TWIST = 0x0C,
|
||||
RCT1_RESEARCH_SPECIAL_INLINE_TWIST = 0x11,
|
||||
RCT1_RESEARCH_SPECIAL_HALF_LOOP = 0x12,
|
||||
RCT1_RESEARCH_SPECIAL_CORKSCREW = 0x13,
|
||||
RCT1_RESEARCH_SPECIAL_BANKED_HELIX_A = 0x15,
|
||||
RCT1_RESEARCH_SPECIAL_BANKED_HELIX_B = 0x16,
|
||||
RCT1_RESEARCH_SPECIAL_HELIX = 0x17,
|
||||
RCT1_RESEARCH_SPECIAL_ON_RIDE_PHOTO = 0x1A,
|
||||
RCT1_RESEARCH_SPECIAL_WATER_SPLASH = 0x1B,
|
||||
RCT1_RESEARCH_SPECIAL_VERTICAL_DROP = 0x1C,
|
||||
RCT1_RESEARCH_SPECIAL_BARREL_ROLL = 0x1D,
|
||||
RCT1_RESEARCH_SPECIAL_LAUNCHED_LIFT_HILL = 0x1E,
|
||||
RCT1_RESEARCH_SPECIAL_LARGE_LOOP_AND_HALF = 0x1F,
|
||||
RCT1_RESEARCH_SPECIAL_REVERSER_TURNTABLE = 0x21,
|
||||
RCT1_RESEARCH_SPECIAL_HEARTLINE_ROLL = 0x22,
|
||||
RCT1_RESEARCH_SPECIAL_REVERSING_SECTIONS = 0x23,
|
||||
};
|
||||
|
||||
typedef struct{
|
||||
uint8 type; // 0x00
|
||||
uint8 vehicle_type; // 0x01
|
||||
|
||||
@@ -168,11 +168,8 @@ typedef struct {
|
||||
uint8 guest_count_change_modifier;
|
||||
uint8 current_research_level;
|
||||
uint8 pad_01357400[4];
|
||||
uint32 dword_01357404;
|
||||
uint32 dword_01357408;
|
||||
uint32 dword_0135740C;
|
||||
uint32 dword_01357410[5];
|
||||
uint32 dword_01357424[8];
|
||||
uint32 ride_types_researched[8];
|
||||
uint32 ride_entries_researched[8];
|
||||
uint32 dword_01357444[128];
|
||||
uint32 dword_01357644[128];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user