diff --git a/src/object.h b/src/object.h index 7d0dc72b0e..b3aa0159dd 100644 --- a/src/object.h +++ b/src/object.h @@ -127,6 +127,7 @@ void reset_loaded_objects(); int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8* entry_index); void object_create_identifier_name(char* string_buffer, const rct_object_entry* object); +rct_object_entry *object_list_find_by_name(const char *name); rct_object_entry *object_list_find(rct_object_entry *entry); char *object_get_name(rct_object_entry *entry); diff --git a/src/object_list.c b/src/object_list.c index 082764e7cb..9b8dbcd6cd 100644 --- a/src/object_list.c +++ b/src/object_list.c @@ -606,10 +606,7 @@ uint32 _installedObjectHashTableCollisions; uint32 object_get_hash_code(rct_object_entry *object) { uint32 hash = 5381; - uint8 *byte = (uint8*)object; - int i; - - for (i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) hash = ((hash << 5) + hash) + object->name[i]; return hash; @@ -672,6 +669,24 @@ int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8 return 1; } +rct_object_entry *object_list_find_by_name(const char * name) +{ + rct_object_entry entry; + memcpy(entry.name, name, 8); + + uint32 hash = object_get_hash_code(&entry); + uint32 index = hash % _installedObjectHashTableSize; + + while (_installedObjectHashTable[index] != NULL) { + if (memcmp(_installedObjectHashTable[index]->name, entry.name, 8) == 0) + return _installedObjectHashTable[index]; + + index++; + if (index >= _installedObjectHashTableSize) index = 0; + } + + return NULL; +} rct_object_entry *object_list_find(rct_object_entry *entry) { diff --git a/src/rct1/S4Importer.cpp b/src/rct1/S4Importer.cpp index 4e62c5e52e..5756e17cc9 100644 --- a/src/rct1/S4Importer.cpp +++ b/src/rct1/S4Importer.cpp @@ -25,6 +25,7 @@ extern "C" #include "../world/footpath.h" #include "../world/map_animation.h" #include "../world/park.h" + #include "../world/scenery.h" } void S4Importer::LoadSavedGame(const utf8 * path) @@ -116,6 +117,47 @@ void S4Importer::CreateAvailableObjectMappings() AddAvailableEntriesFromResearchList(); AddAvailableEntriesFromMap(); AddAvailableEntriesFromRides(); + + // Add themes + for (int sceneryTheme = 0; sceneryTheme <= RCT1_SCENERY_THEME_PAGODA; sceneryTheme++) + { + if (sceneryTheme != 0 && + _sceneryThemeTypeToEntryMap[sceneryTheme] == 255) continue; + + List objects = RCT1::GetSceneryObjects(sceneryTheme); + for (const char * objectName : objects) + { + rct_object_entry * foundEntry = object_list_find_by_name(objectName); + if (foundEntry != nullptr) + { + uint8 objectType = foundEntry->flags & 0x0F; + switch (objectType) { + case OBJECT_TYPE_SMALL_SCENERY: + case OBJECT_TYPE_LARGE_SCENERY: + case OBJECT_TYPE_WALLS: + { + List * entries = GetEntryList(objectType); + + // Ran out of available entries + if (entries->GetCount() >= (size_t)object_entry_group_counts[objectType]) + { + break; + } + + size_t index = entries->IndexOf([objectName](const char * x) -> bool + { + return String::Equals(x, objectName, true); + }); + if (index == SIZE_MAX) + { + entries->Add(objectName); + } + break; + } + } + } + } + } } void S4Importer::AddAvailableEntriesFromResearchList() @@ -270,14 +312,19 @@ void S4Importer::AddEntryForWall(uint8 wallType) void S4Importer::AddEntriesForSceneryTheme(uint8 sceneryThemeType) { - if (sceneryThemeType == RCT1_SCENERY_THEME_GENERAL) return; + if (sceneryThemeType == RCT1_SCENERY_THEME_GENERAL || + sceneryThemeType == RCT1_SCENERY_THEME_JUMPING_FOUNTAINS || + sceneryThemeType == RCT1_SCENERY_THEME_GARDEN_CLOCK) + { + _sceneryThemeTypeToEntryMap[sceneryThemeType] = 254; + } + else + { + const char * entryName = RCT1::GetSceneryGroupObject(sceneryThemeType); - const char * entryName = RCT1::GetSceneryGroupObject(sceneryThemeType); - - _sceneryThemeTypeToEntryMap[sceneryThemeType] = (uint8)_sceneryGroupEntries.GetCount(); - _sceneryGroupEntries.Add(entryName); - - // TODO add entries for all scenery items belonging to scenery group + _sceneryThemeTypeToEntryMap[sceneryThemeType] = (uint8)_sceneryGroupEntries.GetCount(); + _sceneryGroupEntries.Add(entryName); + } } void S4Importer::ImportRides() @@ -629,7 +676,9 @@ void S4Importer::ImportResearch() case RCT1_RESEARCH_CATEGORY_THEME: { uint8 rct1SceneryTheme = researchItem->item; - if (rct1SceneryTheme != RCT1_SCENERY_THEME_GENERAL) + if (rct1SceneryTheme != RCT1_SCENERY_THEME_GENERAL && + rct1SceneryTheme != RCT1_SCENERY_THEME_JUMPING_FOUNTAINS && + rct1SceneryTheme != RCT1_SCENERY_THEME_GARDEN_CLOCK) { uint8 sceneryGroupEntryIndex = _sceneryThemeTypeToEntryMap[rct1SceneryTheme]; research_insert_scenery_group_entry(sceneryGroupEntryIndex, researched); @@ -1212,11 +1261,28 @@ void S4Importer::FixMapElementEntryTypes() } case MAP_ELEMENT_TYPE_FENCE: mapElement->properties.fence.type = _wallTypeToEntryMap[mapElement->properties.fence.type]; + if (mapElement->properties.fence.type == 255) + { + map_element_remove(mapElement); + map_element_iterator_restart_for_tile(&it); + } break; } } } +List * S4Importer::GetEntryList(uint8 objectType) +{ + switch (objectType) { + case OBJECT_TYPE_RIDE: return &_rideEntries; + case OBJECT_TYPE_SMALL_SCENERY: return &_smallSceneryEntries; + case OBJECT_TYPE_LARGE_SCENERY: return &_largeSceneryEntries; + case OBJECT_TYPE_WALLS: return &_wallEntries; + case OBJECT_TYPE_SCENERY_SETS: return &_sceneryGroupEntries; + } + return nullptr; +} + const rct1_research_item * S4Importer::GetResearchList(size_t * count) { // Loopy Landscapes stores research items in a different place diff --git a/src/rct1/S4Importer.h b/src/rct1/S4Importer.h index 87d78cd654..09b744d367 100644 --- a/src/rct1/S4Importer.h +++ b/src/rct1/S4Importer.h @@ -91,6 +91,7 @@ private: void FixEntrancePositions(); void FixMapElementEntryTypes(); + List * GetEntryList(uint8 objectType); const rct1_research_item * GetResearchList(size_t * count); int GetSCNumber(); const char * GetUserString(rct_string_id stringId); diff --git a/src/rct1/import.h b/src/rct1/import.h index 53635c4272..9509ac5841 100644 --- a/src/rct1/import.h +++ b/src/rct1/import.h @@ -1,5 +1,8 @@ #pragma once +#include "../common.h" +#include "../core/List.hpp" + namespace RCT1 { colour_t GetColour(colour_t colour); @@ -13,4 +16,6 @@ namespace RCT1 const char * GetLargeSceneryObject(uint8 largeSceneryType); const char * GetWallObject(uint8 wallType); const char * GetSceneryGroupObject(uint8 sceneryGroupType); + + const List GetSceneryObjects(uint8 sceneryType); } diff --git a/src/rct1/tables.cpp b/src/rct1/tables.cpp index 76477bc84f..ebd2b9cf3c 100644 --- a/src/rct1/tables.cpp +++ b/src/rct1/tables.cpp @@ -795,10 +795,12 @@ namespace RCT1 "SCGCLASS", // RCT1_SCENERY_THEME_CLASSICAL_ROMAN "SCGEGYPT", // RCT1_SCENERY_THEME_EGYPTIAN "SCGMART ", // RCT1_SCENERY_THEME_MARTIAN - "SCGWOND ", // RCT1_SCENERY_THEME_TOYLAND + " ", // RCT1_SCENERY_THEME_JUMPING_FOUNTAINS + "SCGWOND ", // RCT1_SCENERY_THEME_WONDERLAND "SCGJURAS", // RCT1_SCENERY_THEME_JURASSIC - "SCGSPOOK", // RCT1_SCENERY_THEME_GRAVEYARD + "SCGSPOOK", // RCT1_SCENERY_THEME_SPOOKY "SCGJUNGL", // RCT1_SCENERY_THEME_JUNGLE + " ", // RCT1_SCENERY_THEME_GARDEN_CLOCK "SCGABSTR", // RCT1_SCENERY_THEME_ABSTRACT "SCGSNOW ", // RCT1_SCENERY_THEME_SNOW_ICE "SCGMEDIE", // RCT1_SCENERY_THEME_MEDIEVAL @@ -917,4 +919,53 @@ namespace RCT1 }; // RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER return preferedRideEntryOrder[rideType]; } + + const List GetSceneryObjects(uint8 sceneryType) + { + static const List map[] = + { + // RCT1_SCENERY_THEME_GENERAL (trees, shrubs, garden, walls, fence, path accessories) + { "TIC ", "TLC ", "TMC ", "TMP ", "TITC ", "TGHC ", "TAC ", "TGHC2 ", "TCJ ", "TMBJ ", "TCF ", "TCL ", "TRF ", "TRF2 ", "TEL ", "TAP ", "TSP ", "TMZP ", "TCRP ", "TBP ", "TLP ", "TWP ", "TAS ", "TMG ", "TWW ", "TSB ", "TVL ", "TCY ", "TNS ", "TWN ", "TCE ", "TCO ", "THL ", "TCC ", "TF1 ", "TF2 ", "TCT ", "TH1 ", "TH2 ", "TPM ", "TROPT1 ", + "TS0 ", "TS1 ", "TS2 ", "TS3 ", "TS4 ", "TS5 ", "TS6 ", "TEF ", "TAL ", "TSQ ", "THT ", "TCB ", "TDM ", "TSD ", "TORN1 ", "TORN2 ", "TGS ", "TUS ", "TBC ", "TSC ", "TWF ", "TSH0 ", "TSH1 ", "TSH2 ", "TSH3 ", "TSH4 ", "TSH5 ", "TDF ", "TSH ", "THRS ", "TSTD ", "TBR ", "TTF ", "WHG ", "WHGG ", "WCH ", "WCHG ", + "TG1 ", "TG2 ", "TG3 ", "TG4 ", "TG5 ", "TG6 ", "TG7 ", "TG8 ", "TG9 ", "TG10 ", "TG11 ", "TG12 ", "TG13 ", "TG14 ", "TG15 ", "TG16 ", "TG17 ", "TG18 ", "TG19 ", "TG20 ", "TG21 ", + "WBR1A ", "WBR2A ", "WALLBB34", "WALLTN32", "TNTROOF1", "WALLBB33", "WALLBB32", "WALLBB16", "WALLBB8 ", "ROOF5 ", "ROOF7 ", "WALLRS32", "WALLRS16", "WALLRS8 ", "WALLBR32", "WALLBR16", "WALLBR8 ", "WALLBRDR", "WALLBRWN", "BRBASE ", "ROOF1 ", "ROOF2 ", "ROOF3 ", "ROOF4 ", "WALLCB32", "WALLCB16", "WALLCB8 ", "WALLCBDR", "WALLCBWN", "BRBASE2 ", "CWBCRV33", "CWBCRV32", "BRCRRF1 ", "ROOF6 ", "ROOF8 ", "WALLCF32", "WALLCF16", "WALLCF8 ", "WALLCFDR", "WALLCFWN", "WALLCFAR", "BRBASE3 ", "CWFCRV33", "CWFCRV32", "BRCRRF2 ", "ROOF9 ", "ROOF11 ", "ROOF10 ", "ROOF12 ", "CORROOF2", "WALLCO16", "CORROOF ", "WALLLT32", "WALLSK16", "WALLSK32", "SKTDW2 ", "SKTDW ", "SKTBASE ", "SKTBASET", "SUPPW2 ", "SUPPW1 ", "SUPPW3 ", "SUPPLEG1", "SUPPLEG2", "SUMRF ", "WALLRH32" + "WMF ", "WMFG ", "WSW ", "WSWG ", "WFW1 ", "WFWG ", "WPF ", "WPFG ", "WSW1 ", "WSW2 ", "WBR1 ", "WBRG ", "WBR2 ", "WBR3 ", "WALLMM16", "WALLMM17", + "LAMP1 ", "LAMP2 ", "LITTER1 ", "BENCH1 ", "QTV1 ", "BN1 ", "WALLPOST", "WALLSIGN", "SSIG1 ", "SSIG2 ", "SSIG3 ", "SSIG4 " }, + // RCT1_SCENERY_THEME_MINE + { "SMH1 ", "SMH2 ", "SMN1 ", "TBW ", "TBR1 ", "TBR2 ", "TML ", "TMW ", "TBR3 ", "TBR4 ", "TMJ ", "BN5 ", "WALLWD8 ", "WALLWD16", "WALLWD32", "WALLWD33", "WALLMN32", "WDBASE ", "MINROOF1", "ROOF13 ", "LITTERMN" }, + // RCT1_SCENERY_THEME_CLASSICAL_ROMAN + { "SCOL ", "TT1 ", "TRMS ", "TRWS ", "TRC ", "TQF ", "WRW ", "WRWA ", "ROMROOF2", "WC3 ", "ROMROOF1", "BN3 " }, + // RCT1_SCENERY_THEME_EGYPTIAN + { "SSPX ", "SCLN ", "SPYR ", "TES1 ", "TEN ", "TERS ", "TERB ", "TEP ", "WEW ", "LAMP3 ", "BN4 ", "BENCHSTN" }, + // RCT1_SCENERY_THEME_MARTIAN + { "SMB ", "TMO1 ", "TMO2 ", "TMO3 ", "TMO4 ", "TMO5 ", "SVLC ", "WMW ", "LAMP4 " }, + // RCT1_SCENERY_THEME_JUMPING_FOUNTAINS (Single researchable scenery item) + { "JUMPFNT1" }, + // RCT1_SCENERY_THEME_WONDERLAND + { "TWH1 ", "TWH2 ", "TST1 ", "TST2 ", "TMS1 ", "TST3 ", "TST4 ", "TST5 ", "TAS1 ", "TAS2 ", "TAS3 ", "TAS4 ", "CHBBASE ", "TP1 ", "TP2 ", "TK1 ", "TK2 ", "TR1 ", "TR2 ", "TQ1 ", "TQ2 ", "TB1 ", "TB2 ", "TK3 ", "TK4 ", "WCW1 ", "WCW2 " }, + // RCT1_SCENERY_THEME_JURASSIC + { "TBN ", "TBN1 ", "TDN4 ", "TDN5 ", "SDN1 ", "SDN2 ", "SDN3 ", "WWTW ", "WMWW ", "WWTWA ", "WBW ", "BN6 " }, + // RCT1_SCENERY_THEME_SPOOKY, + { "SSK1 ", "TDT1 ", "TDT2 ", "TDT3 ", "TMM1 ", "TMM2 ", "TMM3 ", "TGS1 ", "TGS2 ", "TGS3 ", "TGS4 ", "SMSKULL ", "WALLRK32" }, + // RCT1_SCENERY_THEME_JUNGLE + { "TJT1 ", "TJT2 ", "TJB1 ", "TJT3 ", "TJT4 ", "TJP1 ", "TJB2 ", "TJT5 ", "TJB3 ", "TJB4 ", "TJT6 ", "TJP2 ", "TJF ", "WPW1 ", "WPW2 ", "WJF ", "BN2 ", "WALLJN32", "JNGROOF1", "ROOF14 ", "BENCHLOG" }, + // RCT1_SCENERY_THEME_ABSTRACT + { "TGE1 ", "TGE2 ", "TGE3 ", "TGE4 ", "TGE5 ", "TGC1 ", "TGC2 ", "WALLGL8 ", "WALLGL16", "WALLGL32", "GEOROOF1", "WGW2 ", "GEOROOF2" }, + // RCT1_SCENERY_THEME_GARDEN_CLOCK (Single researchable scenery item) + { "TCK " }, + // RCT1_SCENERY_THEME_SNOW_ICE + { "SIP ", "TSM ", "TIG ", "TSF1 ", "TSF2 ", "TSF3 ", "TSNC ", "TSNB ", "WC16 ", "WC17 ", "WC18 ", "JUMPSNW1", "TCFS ", "TRFS ", "TRF3 ", "TNSS ", "BN8 ", "WALLIG16", "WALLIG24", "IGROOF " }, + // RCT1_SCENERY_THEME_MEDIEVAL + { "TCT1 ", "STB1 ", "STB2 ", "WC1 ", "WC4 ", "WC5 ", "WC6 ", "WC7 ", "WC8 ", "WALLCZ32", "WALLCY32", "TCT2 ", "STG1 ", "STG2 ", "WC2 ", "WC9 ", "WC10 ", "WC11 ", "WC12 ", "WC13 ", "WALLCW32", "WALLCX32", "TCN ", "TTG ", "SCT ", "SOH1 ", "SOH2 ", "SOH3 ", "WPW3 ", "WALLCFPC", "WALLCBPC" }, + // RCT1_SCENERY_THEME_SPACE + { "SSR ", "SST ", "SSH ", "TSCP ", "TSPH ", "TSC2 ", "TSP1 ", "TSP2 ", "WALLSP32", "SPCROOF1", "BN9 ", "BENCHSPC", "LITTERSP" }, + // RCT1_SCENERY_THEME_CREEPY + { "TCD ", "TSG ", "TSK ", "TGH1 ", "TGH2 ", "TSMP ", "SGP ", "WC14 ", "WC15 ", "TL0 ", "TL1 ", "TL2 ", "TL3 ", "TM0 ", "TM1 ", "TM2 ", "TM3 " }, + // RCT1_SCENERY_THEME_URBAN + { "SHS1 ", "SHS2 ", "STH ", "SAH ", "SPS ", "SAH2 ", "SAH3 ", "SOB ", "WALLU132", "WALLU232" }, + // RCT1_SCENERY_THEME_PAGODA + { "SPG ", "TLY ", "TGG ", "TOH1 ", "TOH2 ", "TOT1 ", "TOT2 ", "TOS ", "TOT3 ", "TOT4 ", "TOH3 ", "WALLPG32", "PAGROOF1", "BN7 " } + }; + return map[sceneryType]; + } }