mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #7310 from OpenRCT2/json-objects
Add support for new JSON object format
This commit is contained in:
commit
0ab3d0955c
|
@ -1,19 +1,22 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "C++ Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/openrct2",
|
||||
"program": "${workspaceFolder}/bin/openrct2",
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceRoot}/bin",
|
||||
"cwd": "${workspaceFolder}/bin",
|
||||
"environment": [],
|
||||
"externalConsole": true,
|
||||
"setupCommands": [
|
||||
{
|
||||
"text": "-enable-pretty-printing"
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"linux": {
|
||||
|
@ -30,7 +33,7 @@
|
|||
"name": "C++ Attach",
|
||||
"type": "cppdbg",
|
||||
"request": "attach",
|
||||
"program": "${workspaceRoot}/bin/openrct2",
|
||||
"program": "${workspaceFolder}/bin/openrct2",
|
||||
"processId": "${command:pickProcess}",
|
||||
"setupCommands": [
|
||||
{
|
||||
|
|
|
@ -16,10 +16,14 @@ set(CMAKE_MACOSX_RPATH 1)
|
|||
set(TITLE_SEQUENCE_URL "https://github.com/OpenRCT2/title-sequences/releases/download/v0.1.2/title-sequence-v0.1.2.zip")
|
||||
set(TITLE_SEQUENCE_SHA1 "1136ef92bfb05cd1cba9831ba6dc4a653d87a246")
|
||||
|
||||
set(OBJECTS_URL "https://github.com/OpenRCT2/objects/releases/download/v1.0/objects.zip")
|
||||
set(OBJECTS_SHA1 "4f670859b5f37f85e0c3d755b1cb75e839c989a6")
|
||||
|
||||
option(FORCE32 "Force 32-bit build. It will add `-m32` to compiler flags.")
|
||||
option(WITH_TESTS "Build tests")
|
||||
option(PORTABLE "Create a portable build (-rpath=$ORIGIN)" OFF)
|
||||
option(DOWNLOAD_TITLE_SEQUENCES "Download title sequences during installation." ON)
|
||||
option(DOWNLOAD_OBJECTS "Download objects during installation." ON)
|
||||
|
||||
# Options
|
||||
option(STATIC "Create a static build.")
|
||||
|
@ -208,6 +212,17 @@ if (DOWNLOAD_TITLE_SEQUENCES)
|
|||
file(REMOVE \$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT}/title/title-sequences.zip)\n\
|
||||
endif ()")
|
||||
endif ()
|
||||
if (DOWNLOAD_OBJECTS)
|
||||
# If rct2.wtrcyan.json or data/object/ exists, assume all the objects are already present
|
||||
install(CODE
|
||||
"if (EXISTS \"\$ENV{DESTDIR}/${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT}/object/rct2/water/rct2.wtrcyan.json\" OR EXISTS ${CMAKE_SOURCE_DIR}/data/object/)\n\
|
||||
message(\"Using cached objects\")\n\
|
||||
else () \n\
|
||||
file(DOWNLOAD ${OBJECTS_URL} \$ENV{DESTDIR}/${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT}/object/objects.zip EXPECTED_HASH SHA1=${OBJECTS_SHA1} SHOW_PROGRESS)\n\
|
||||
execute_process(COMMAND \"${CMAKE_COMMAND}\" -E chdir \$ENV{DESTDIR}/${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT}/object/ \"${CMAKE_COMMAND}\" -E tar xvf objects.zip)\n\
|
||||
file(REMOVE \$ENV{DESTDIR}/${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT}/object/objects.zip)\n\
|
||||
endif ()")
|
||||
endif ()
|
||||
install(TARGETS "libopenrct2" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
install(TARGETS "openrct2" RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
|
|
|
@ -21,10 +21,13 @@
|
|||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
4C1A53ED205FD1A0000F8EF5 /* SceneryObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C1A53EC205FD19F000F8EF5 /* SceneryObject.cpp */; };
|
||||
4C3B4236205914F7000C5BB7 /* InGameConsole.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C3B4234205914F7000C5BB7 /* InGameConsole.cpp */; };
|
||||
4C3B423820591513000C5BB7 /* StdInOutConsole.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C3B423720591513000C5BB7 /* StdInOutConsole.cpp */; };
|
||||
4C93F1AD1F8CD9F000A9330D /* Input.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C93F1AC1F8CD9F000A9330D /* Input.cpp */; };
|
||||
4C93F1AF1F8CD9F600A9330D /* KeyboardShortcut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C93F1AE1F8CD9F600A9330D /* KeyboardShortcut.cpp */; };
|
||||
4CE9AAAD1FDA7B14004093C6 /* ObjectJsonHelpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CE9AAAB1FDA7B14004093C6 /* ObjectJsonHelpers.cpp */; };
|
||||
4CF67197206B7E720034ADDD /* object in Resources */ = {isa = PBXBuildFile; fileRef = 4CF67196206B7E720034ADDD /* object */; };
|
||||
C61ADB1F1FB6A0A70024F2EF /* TopToolbar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C61ADB1E1FB6A0A60024F2EF /* TopToolbar.cpp */; };
|
||||
C61ADB211FB7DC060024F2EF /* Scenery.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C61ADB201FB7DC060024F2EF /* Scenery.cpp */; };
|
||||
C61ADB231FBBCB8B0024F2EF /* GameBottomToolbar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C61ADB221FBBCB8A0024F2EF /* GameBottomToolbar.cpp */; };
|
||||
|
@ -586,6 +589,7 @@
|
|||
|
||||
/* Begin PBXFileReference section */
|
||||
4C04D69F2056AA9600F82EBA /* linenoise.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = linenoise.hpp; sourceTree = "<group>"; };
|
||||
4C1A53EC205FD19F000F8EF5 /* SceneryObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SceneryObject.cpp; sourceTree = "<group>"; };
|
||||
4C3B4234205914F7000C5BB7 /* InGameConsole.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InGameConsole.cpp; sourceTree = "<group>"; };
|
||||
4C3B4235205914F7000C5BB7 /* InGameConsole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InGameConsole.h; sourceTree = "<group>"; };
|
||||
4C3B423720591513000C5BB7 /* StdInOutConsole.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StdInOutConsole.cpp; sourceTree = "<group>"; };
|
||||
|
@ -847,6 +851,9 @@
|
|||
4CE462461FD1613D0001CD98 /* Platform.Linux.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Platform.Linux.cpp; sourceTree = "<group>"; };
|
||||
4CE462481FD1613D0001CD98 /* Platform.Posix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Platform.Posix.cpp; sourceTree = "<group>"; };
|
||||
4CE462491FD1613D0001CD98 /* Platform.Win32.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Platform.Win32.cpp; sourceTree = "<group>"; };
|
||||
4CE9AAAB1FDA7B14004093C6 /* ObjectJsonHelpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectJsonHelpers.cpp; sourceTree = "<group>"; };
|
||||
4CE9AAAC1FDA7B14004093C6 /* ObjectJsonHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectJsonHelpers.h; sourceTree = "<group>"; };
|
||||
4CF67196206B7E720034ADDD /* object */ = {isa = PBXFileReference; lastKnownFileType = folder; name = object; path = data/object; sourceTree = "<group>"; };
|
||||
4CFE4E7B1F90A3F1005243C2 /* Peep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Peep.cpp; sourceTree = "<group>"; };
|
||||
4CFE4E7C1F90A3F1005243C2 /* Peep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Peep.h; sourceTree = "<group>"; };
|
||||
4CFE4E7D1F90A3F1005243C2 /* PeepData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PeepData.cpp; sourceTree = "<group>"; };
|
||||
|
@ -1676,6 +1683,7 @@
|
|||
D497D06F1C20FD52002BF46A = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CF67196206B7E720034ADDD /* object */,
|
||||
D41B72431C21015A0080A7B9 /* Sources */,
|
||||
D497D07A1C20FD52002BF46A /* Resources */,
|
||||
D41B73ED1C21017D0080A7B9 /* Libraries */,
|
||||
|
@ -2083,6 +2091,8 @@
|
|||
4C7B53A21FFC15ED00A52E21 /* ObjectLimits.h */,
|
||||
4C7B53A31FFC180400A52E21 /* ObjectList.cpp */,
|
||||
4C7B53A41FFC180400A52E21 /* ObjectList.h */,
|
||||
4CE9AAAB1FDA7B14004093C6 /* ObjectJsonHelpers.cpp */,
|
||||
4CE9AAAC1FDA7B14004093C6 /* ObjectJsonHelpers.h */,
|
||||
F76C84221EC4E7CC00FA49E2 /* ObjectManager.cpp */,
|
||||
F76C84231EC4E7CC00FA49E2 /* ObjectManager.h */,
|
||||
F76C84241EC4E7CC00FA49E2 /* ObjectRepository.cpp */,
|
||||
|
@ -2091,6 +2101,7 @@
|
|||
F76C84271EC4E7CC00FA49E2 /* RideObject.h */,
|
||||
F76C84281EC4E7CC00FA49E2 /* SceneryGroupObject.cpp */,
|
||||
F76C84291EC4E7CC00FA49E2 /* SceneryGroupObject.h */,
|
||||
4C1A53EC205FD19F000F8EF5 /* SceneryObject.cpp */,
|
||||
F76C842A1EC4E7CC00FA49E2 /* SceneryObject.h */,
|
||||
F76C842B1EC4E7CC00FA49E2 /* SmallSceneryObject.cpp */,
|
||||
F76C842C1EC4E7CC00FA49E2 /* SmallSceneryObject.h */,
|
||||
|
@ -2717,6 +2728,7 @@
|
|||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D497D0891C20FD53002BF46A /* Build configuration list for PBXNativeTarget "OpenRCT2" */;
|
||||
buildPhases = (
|
||||
4CF67195206B7BEF0034ADDD /* Download JSON objects */,
|
||||
D4E09E831E049C0600F53CE3 /* Download Title Sequences */,
|
||||
D4EC012A1C25532B00DAFE69 /* Setup AppIcon */,
|
||||
D4CA88671D4E962100060C11 /* Get Git Variables */,
|
||||
|
@ -2828,6 +2840,7 @@
|
|||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4CF67197206B7E720034ADDD /* object in Resources */,
|
||||
D41B74731C2125E50080A7B9 /* Assets.xcassets in Resources */,
|
||||
D4EC48E61C2637710024B507 /* g2.dat in Resources */,
|
||||
D4EC48E71C2637710024B507 /* language in Resources */,
|
||||
|
@ -2847,6 +2860,20 @@
|
|||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
4CF67195206B7BEF0034ADDD /* Download JSON objects */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Download JSON objects";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "version=\"1.0\"\nzipname=\"objects.zip\"\nliburl=\"https://github.com/OpenRCT2/objects/releases/download/v$version/$zipname\"\n\n[[ ! -d \"${SRCROOT}/data/object\" || ! -e \"${SRCROOT}/objectsversion\" || $(head -n 1 \"${SRCROOT}/objectsversion\") != $version ]]\noutdated=$?\n\nif [[ $outdated -eq 0 ]]; then\nif [[ -d \"${SRCROOT}/data/object\" ]]; then rm -r \"${SRCROOT}/data/object\"; fi\nmkdir -p \"${SRCROOT}/data/object\"\n\ncurl -L -o \"${SRCROOT}/data/object/$zipname\" \"$liburl\"\nunzip -uaq -d \"${SRCROOT}/data/object\" \"${SRCROOT}/data/object/$zipname\"\nrm \"${SRCROOT}/data/object/$zipname\"\n\necho $version > \"${SRCROOT}/objectsversion\"\nfi";
|
||||
};
|
||||
C68B2D471EC790710020651C /* Download Libraries */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
@ -3003,6 +3030,7 @@
|
|||
C68313C81FDB4ED4006DB3D8 /* MouseInput.cpp in Sources */,
|
||||
C68878C920289B710084B384 /* TextureCache.cpp in Sources */,
|
||||
C61ADB1F1FB6A0A70024F2EF /* TopToolbar.cpp in Sources */,
|
||||
4C1A53ED205FD1A0000F8EF5 /* SceneryObject.cpp in Sources */,
|
||||
F76C887B1EC5324E00FA49E2 /* FileAudioSource.cpp in Sources */,
|
||||
C68878CA20289B710084B384 /* TransparencyDepth.cpp in Sources */,
|
||||
C64644FD1F3FA4120026AC2D /* Land.cpp in Sources */,
|
||||
|
@ -3043,6 +3071,7 @@
|
|||
C68313D51FDB4F4C006DB3D8 /* Graph.cpp in Sources */,
|
||||
C685E51D1F8907850090598F /* Research.cpp in Sources */,
|
||||
C64644FB1F3FA4120026AC2D /* EditorScenarioOptions.cpp in Sources */,
|
||||
4CE9AAAD1FDA7B14004093C6 /* ObjectJsonHelpers.cpp in Sources */,
|
||||
C654DF321F69C0430040F43D /* InstallTrack.cpp in Sources */,
|
||||
C64644FF1F3FA4120026AC2D /* StaffList.cpp in Sources */,
|
||||
C6D2BEE81F9BAACE008B557C /* MazeConstruction.cpp in Sources */,
|
||||
|
|
|
@ -1600,7 +1600,7 @@ STR_1594 :{SMALLFONT}{OPENQUOTES}This wonton soup from {STRINGID} is really g
|
|||
STR_1595 :{SMALLFONT}{OPENQUOTES}This meatball soup from {STRINGID} is really good value{ENDQUOTES}
|
||||
STR_1596 :{SMALLFONT}{OPENQUOTES}This fruit juice from {STRINGID} is really good value{ENDQUOTES}
|
||||
STR_1597 :{SMALLFONT}{OPENQUOTES}This soybean milk from {STRINGID} is really good value{ENDQUOTES}
|
||||
STR_1598 :{SMALLFONT}{OPENQUOTES}This sujongkwa from {STRINGID} is really good value{ENDQUOTES}
|
||||
STR_1598 :{SMALLFONT}{OPENQUOTES}This sujeonggwa from {STRINGID} is really good value{ENDQUOTES}
|
||||
STR_1599 :{SMALLFONT}{OPENQUOTES}This sub sandwich from {STRINGID} is really good value{ENDQUOTES}
|
||||
STR_1600 :{SMALLFONT}{OPENQUOTES}This cookie from {STRINGID} is really good value{ENDQUOTES}
|
||||
STR_1601 :
|
||||
|
@ -1632,7 +1632,7 @@ STR_1626 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for wonton soup fro
|
|||
STR_1627 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for meatball soup from {STRINGID}{ENDQUOTES}
|
||||
STR_1628 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for fruit juice from {STRINGID}{ENDQUOTES}
|
||||
STR_1629 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for soybean milk from {STRINGID}{ENDQUOTES}
|
||||
STR_1630 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for sujongkwa from {STRINGID}{ENDQUOTES}
|
||||
STR_1630 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for sujeonggwa from {STRINGID}{ENDQUOTES}
|
||||
STR_1631 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a sub sandwich from {STRINGID}{ENDQUOTES}
|
||||
STR_1632 :{SMALLFONT}{OPENQUOTES}I'm not paying that much for a cookie from {STRINGID}{ENDQUOTES}
|
||||
STR_1633 :
|
||||
|
@ -2118,7 +2118,7 @@ STR_2110 :{WINDOW_COLOUR_2}Wonton Soup price:
|
|||
STR_2111 :{WINDOW_COLOUR_2}Meatball Soup price:
|
||||
STR_2112 :{WINDOW_COLOUR_2}Fruit Juice price:
|
||||
STR_2113 :{WINDOW_COLOUR_2}Soybean Milk price:
|
||||
STR_2114 :{WINDOW_COLOUR_2}Sujongkwa price:
|
||||
STR_2114 :{WINDOW_COLOUR_2}Sujeonggwa price:
|
||||
STR_2115 :{WINDOW_COLOUR_2}Sub Sandwich price:
|
||||
STR_2116 :{WINDOW_COLOUR_2}Cookie price:
|
||||
STR_2117 :{WINDOW_COLOUR_2}
|
||||
|
@ -2140,7 +2140,7 @@ STR_2132 :Wonton Soup
|
|||
STR_2133 :Meatball Soup
|
||||
STR_2134 :Fruit Juice
|
||||
STR_2135 :Soybean Milk
|
||||
STR_2136 :Sujongkwa
|
||||
STR_2136 :Sujeonggwa
|
||||
STR_2137 :Sub Sandwich
|
||||
STR_2138 :Cookie
|
||||
STR_2139 :Empty Bowl
|
||||
|
@ -2162,7 +2162,7 @@ STR_2154 :Wonton Soups
|
|||
STR_2155 :Meatball Soups
|
||||
STR_2156 :Fruit Juices
|
||||
STR_2157 :Soybean Milks
|
||||
STR_2158 :Sujongkwa
|
||||
STR_2158 :Sujeonggwa
|
||||
STR_2159 :Sub Sandwiches
|
||||
STR_2160 :Cookies
|
||||
STR_2161 :Empty Bowls
|
||||
|
@ -2184,7 +2184,7 @@ STR_2176 :some Wonton Soup
|
|||
STR_2177 :some Meatball Soup
|
||||
STR_2178 :a Fruit Juice
|
||||
STR_2179 :some Soybean Milk
|
||||
STR_2180 :some Sujongkwa
|
||||
STR_2180 :some Sujeonggwa
|
||||
STR_2181 :a Sub Sandwich
|
||||
STR_2182 :a Cookie
|
||||
STR_2183 :an Empty Bowl
|
||||
|
@ -2206,7 +2206,7 @@ STR_2198 :Wonton Soup
|
|||
STR_2199 :Meatball Soup
|
||||
STR_2200 :Fruit Juice
|
||||
STR_2201 :Soybean Milk
|
||||
STR_2202 :Sujongkwa
|
||||
STR_2202 :Sujeonggwa
|
||||
STR_2203 :Sub Sandwich
|
||||
STR_2204 :Cookie
|
||||
STR_2205 :Empty Bowl
|
||||
|
@ -4988,411 +4988,10 @@ STR_SCNR :Fort Anachronism
|
|||
STR_PARK :Fort Anachronism
|
||||
STR_DTLS :
|
||||
|
||||
#####################
|
||||
# Rides/attractions #
|
||||
#####################
|
||||
|
||||
#RCT2
|
||||
[TOPSP1]
|
||||
STR_NAME :Top Spin
|
||||
STR_DESC :Passengers ride in a gondola suspended by large rotating arms, rotating forwards and backwards head-over-heels
|
||||
STR_CPTY :8 passengers
|
||||
|
||||
[BMSD]
|
||||
STR_NAME :Twister Trains
|
||||
STR_DESC :A spacious train with shoulder restraints
|
||||
|
||||
[BMSU]
|
||||
STR_NAME :Stand-up Twister Trains
|
||||
STR_DESC :A train with shoulder restraints, in which the riders stand up
|
||||
|
||||
[BMFL]
|
||||
STR_NAME :Floorless Twister Trains
|
||||
STR_DESC :A spacious train with shoulder restraints and no floor, making for a more exciting ride
|
||||
|
||||
[WMMINE]
|
||||
STR_NAME :Mine Cars
|
||||
STR_DESC :Cars shaped like an old mine cart
|
||||
|
||||
[WMOUSE]
|
||||
STR_NAME :Mouse Cars
|
||||
STR_DESC :Indivual cars shaped like a mouse
|
||||
|
||||
[STEEP1]
|
||||
STR_NAME :Horses
|
||||
STR_DESC :Single cars shaped like a horse
|
||||
|
||||
[STEEP2]
|
||||
STR_NAME :Motorbikes
|
||||
STR_DESC :Single cars shaped like a motorbike
|
||||
|
||||
[SBOX]
|
||||
STR_NAME :Soap boxes
|
||||
STR_DESC :Single cars shaped like a soap box
|
||||
|
||||
[BOB1]
|
||||
STR_NAME :Bobsleigh Trains
|
||||
STR_DESC :A train consisting of 2-seater cars where the riders are behind each other
|
||||
|
||||
[INTBOB]
|
||||
STR_NAME :6-seater Bobsleighs
|
||||
STR_DESC :Bobsleighs with three seating rows, with room for two people on each
|
||||
|
||||
[LIFT1]
|
||||
STR_NAME :Lift Cabin
|
||||
STR_DESC :Steel lift cabin
|
||||
|
||||
[ARRT1]
|
||||
STR_NAME :Corkscrew Roller Coaster Trains
|
||||
STR_DESC :Roller coaster train with shoulder restraints
|
||||
|
||||
[ARRT2]
|
||||
STR_NAME :Hypercoaster Trains
|
||||
STR_DESC :Comfortable trains with only lap bar restraints
|
||||
|
||||
[MONBK]
|
||||
STR_NAME :Bicycles
|
||||
|
||||
[OBS1]
|
||||
STR_NAME :Single-deck Cabin
|
||||
|
||||
[OBS2]
|
||||
STR_NAME :Double-deck Cabin
|
||||
|
||||
[GTC]
|
||||
STR_NAME :Ghost Train Cars
|
||||
|
||||
[HMCAR]
|
||||
STR_NAME :Haunted Mansion Cars
|
||||
|
||||
[VREEL]
|
||||
STR_NAME :Virginia Reel tubs
|
||||
|
||||
[WMSPIN]
|
||||
STR_NAME :Spinning Mouse Cars
|
||||
|
||||
[AMT1]
|
||||
STR_NAME :Mine Trains
|
||||
|
||||
[SLCT]
|
||||
STR_NAME :Compact Inverted Coaster Trains
|
||||
|
||||
[SLCFO]
|
||||
STR_NAME :Face-off Cars
|
||||
|
||||
[VEKDV]
|
||||
STR_NAME :Vertical Shuttle Cars
|
||||
|
||||
[THCAR]
|
||||
STR_NAME :Air Powered Vertical Coaster Trains
|
||||
|
||||
[SSC1]
|
||||
STR_NAME :Launched Freefall car
|
||||
|
||||
[DING1]
|
||||
STR_NAME :Dinghies
|
||||
|
||||
[LFB1]
|
||||
STR_NAME :Logs
|
||||
|
||||
[RFTBOAT]
|
||||
STR_NAME :Rafts
|
||||
|
||||
[IVMC1]
|
||||
STR_NAME :Four-seater Cars
|
||||
|
||||
[SPDRCR]
|
||||
STR_NAME :Spiral Roller Coaster Trains
|
||||
|
||||
[TOGST]
|
||||
STR_NAME :Stand-up Roller Coaster Trains
|
||||
|
||||
[PREMT1]
|
||||
STR_NAME :LIM Launched Roller Coaster Trains
|
||||
|
||||
[PMT1]
|
||||
STR_NAME :Powered mine train
|
||||
|
||||
[BMAIR]
|
||||
STR_NAME :Flying Roller Coaster Trains
|
||||
|
||||
[INTINV]
|
||||
STR_NAME :Impulse Trains
|
||||
|
||||
[INTST]
|
||||
STR_NAME :Giga Coaster Trains
|
||||
|
||||
[NEMT]
|
||||
STR_NAME :4-across Inverted Roller Coaster Trains
|
||||
|
||||
[VEKST]
|
||||
STR_NAME :Lay-down Roller Coaster Trains
|
||||
|
||||
[REVCAR]
|
||||
STR_NAME :Reverser Cars
|
||||
STR_DESC :Bogied cars capable of turning around on special reversing sections
|
||||
|
||||
[SKYTR]
|
||||
STR_NAME :Lay-down Cars
|
||||
|
||||
[BMVD]
|
||||
STR_NAME :Six-seater Twister Trains
|
||||
|
||||
[SUBMAR]
|
||||
STR_NAME :Submarines
|
||||
|
||||
#WW
|
||||
[CONDORRD]
|
||||
STR_NAME :Condor Trains
|
||||
STR_DESC :Riding in special harnesses below the track, riders experience the feeling of flight as they swoop through the air in Condor-shaped trains
|
||||
STR_CPTY :4 passengers per car
|
||||
|
||||
#WW
|
||||
[CONGAEEL]
|
||||
STR_NAME :Conger Eel Trains
|
||||
STR_DESC :Trains with shoulder restraints, in the shape of a Conger Eel.
|
||||
|
||||
#WW
|
||||
[MINELIFT]
|
||||
STR_NAME :Mine Lift Cabin
|
||||
STR_DESC :A steel lift cabin commonly used in mines
|
||||
|
||||
#WW
|
||||
[ANACONDA]
|
||||
STR_NAME :Anaconda Trains
|
||||
|
||||
#WW
|
||||
[CROCFLUM]
|
||||
STR_NAME :Crocodile boats
|
||||
|
||||
#WW
|
||||
[WHICGRUB]
|
||||
STR_NAME :Witchity Grub Trains
|
||||
|
||||
#WW
|
||||
[GRATWHTE]
|
||||
STR_NAME :Great White Shark Trains
|
||||
STR_DESC :Trains with shoulder restraints, in the shape of a Great White Shark
|
||||
|
||||
#WW
|
||||
[BOMERANG]
|
||||
STR_NAME :Boomerang Trains
|
||||
|
||||
#WW
|
||||
[KOLARIDE]
|
||||
STR_NAME :Koala car
|
||||
|
||||
#WW
|
||||
[MANTARAY]
|
||||
STR_NAME :Manta Ray boats
|
||||
STR_DESC :Coaster boats in the shape of a Manta Ray
|
||||
|
||||
#WW
|
||||
[TUTLBOAT]
|
||||
STR_NAME :Turtle boats
|
||||
|
||||
#WW, for the Wooden RC
|
||||
[MINECART]
|
||||
STR_NAME :Mine Cart Trains
|
||||
|
||||
#WW
|
||||
[LIONRIDE]
|
||||
STR_NAME :Lion Cars
|
||||
|
||||
#WW
|
||||
[RHINORID]
|
||||
STR_NAME :Rhino Trains
|
||||
|
||||
#WW
|
||||
[OSTRICH]
|
||||
STR_NAME :Ostrich Trains
|
||||
|
||||
#WW
|
||||
[GORILLA]
|
||||
STR_NAME :Gorilla Trains
|
||||
|
||||
#WW
|
||||
[FOOTBALL]
|
||||
STR_NAME :Football Trains
|
||||
|
||||
#WW
|
||||
[TIGRTWST]
|
||||
STR_NAME :Bengal Tiger Cars
|
||||
|
||||
#WW
|
||||
[TAXICSTR]
|
||||
STR_NAME :Yellow Taxi Trains
|
||||
|
||||
#WW
|
||||
[OUTRIGGR]
|
||||
STR_NAME :Outrigger canoes
|
||||
|
||||
#WW
|
||||
[SANFTRAM]
|
||||
STR_NAME :San Francisco Trams
|
||||
|
||||
#WW
|
||||
[PENGUINB]
|
||||
STR_NAME :Penguin Trains
|
||||
|
||||
#WW
|
||||
[POLARBER]
|
||||
STR_NAME :Polar Bear Trains
|
||||
|
||||
#WW
|
||||
[LONDONBS]
|
||||
STR_NAME :Routemaster buses
|
||||
STR_DESC :Replicas of the famous London Routemaster bus
|
||||
|
||||
#WW
|
||||
[BLACKCAB]
|
||||
STR_NAME :Black Cabs
|
||||
|
||||
#WW
|
||||
[TGVTRAIN]
|
||||
STR_NAME :TGV Trains
|
||||
|
||||
#WW
|
||||
[ROCKET]
|
||||
STR_NAME :1950's Rockets
|
||||
|
||||
#WW
|
||||
[SPUTNIKR]
|
||||
STR_NAME :Sputnik Cars
|
||||
|
||||
#WW
|
||||
[DHOWWATR]
|
||||
STR_NAME :Dhow boats
|
||||
|
||||
#WW
|
||||
[SURFBRDC]
|
||||
STR_NAME :Surfing Trains
|
||||
|
||||
#WW
|
||||
[KILLWHAL]
|
||||
STR_NAME :Killer Whale Submarines
|
||||
|
||||
#WW
|
||||
[HIPPORID]
|
||||
STR_NAME :Hippo Submarines
|
||||
|
||||
#WW
|
||||
[DOLPHINR]
|
||||
STR_NAME :Dolphin boats
|
||||
|
||||
#WW
|
||||
[MANDARIN]
|
||||
STR_NAME :Mandarin Duck Boats
|
||||
STR_DESC :Duck shaped boat, propelled by the pedalling front seat passengers
|
||||
|
||||
#TT
|
||||
[BATTRRAM]
|
||||
STR_NAME :Battering Ram Trains
|
||||
|
||||
#TT
|
||||
[BLCKDETH]
|
||||
STR_NAME :Black Death Trains
|
||||
|
||||
#TT
|
||||
[JOUSTING]
|
||||
STR_NAME :Jousting Knights
|
||||
|
||||
#TT
|
||||
[OAKBAREL]
|
||||
STR_NAME :Oak Barrels
|
||||
|
||||
#TT
|
||||
[STAMPHRD]
|
||||
STR_NAME :Stampeding Herd Trains
|
||||
|
||||
#TT
|
||||
[DRAGNFLY]
|
||||
STR_NAME :Dragonfly Cars
|
||||
|
||||
#TT
|
||||
[PTERODAC]
|
||||
STR_NAME :Pterodactyl Trains
|
||||
|
||||
#TT
|
||||
[PEGASUSX]
|
||||
STR_NAME :Pegasus Cars
|
||||
|
||||
#TT
|
||||
[CERBERUS]
|
||||
STR_NAME :Cerberus Trains
|
||||
|
||||
#TT
|
||||
[HARPIESX]
|
||||
STR_NAME :Harpies Trains
|
||||
|
||||
#TT
|
||||
[VALKYRIE]
|
||||
STR_NAME :Valkyries Trains
|
||||
|
||||
#TT
|
||||
[RIVRSTYX]
|
||||
STR_NAME :River Styx boats
|
||||
|
||||
#TT
|
||||
[TELEPTER]
|
||||
STR_NAME :Teleporter Cabin
|
||||
|
||||
#TT
|
||||
[HOVERCAR]
|
||||
STR_NAME :Hover Cars
|
||||
|
||||
#TT
|
||||
[HOVRBORD]
|
||||
STR_NAME :Hoverboards
|
||||
|
||||
#TT
|
||||
[HOVERBKE]
|
||||
STR_NAME :Hover Bikes
|
||||
|
||||
#TT, Reverser RC
|
||||
[POLICECR]
|
||||
STR_NAME :Police Cars
|
||||
|
||||
#TT, Looping RC
|
||||
[POLCHASE]
|
||||
STR_NAME :Police Car Trains
|
||||
|
||||
#TT
|
||||
[GANSTRCR]
|
||||
STR_NAME :Gangster Cars
|
||||
|
||||
#TT
|
||||
[SEAPLANE]
|
||||
STR_NAME :Suspended Seaplane Cars
|
||||
|
||||
#TT
|
||||
[BARNSTRM]
|
||||
STR_NAME :BarnStorming Cars
|
||||
|
||||
#TT
|
||||
[FLYGBOAT]
|
||||
STR_NAME :Flying boats
|
||||
|
||||
#TT
|
||||
[BMVOCTPS]
|
||||
STR_NAME :Blob from Outer Space
|
||||
|
||||
#TT
|
||||
[JETPLANE]
|
||||
STR_NAME :Jet Plane Cars
|
||||
|
||||
#TT
|
||||
[HOTRODXX]
|
||||
STR_NAME :Hot Rod Cars
|
||||
|
||||
###########
|
||||
# Scenery #
|
||||
###########
|
||||
|
||||
#Bulrushes was spelt incorrectly
|
||||
[TBR]
|
||||
STR_NAME :Bulrushes
|
||||
|
||||
## Start OpenRCT2 Official
|
||||
[XXBBBR01]
|
||||
STR_NAME :Base Block
|
||||
|
|
|
@ -71,6 +71,8 @@
|
|||
<GtestSha1>667f873ab7a4d246062565fad32fb6d8e203ee73</GtestSha1>
|
||||
<TitleSequencesUrl>https://github.com/OpenRCT2/title-sequences/releases/download/v0.1.2/title-sequence-v0.1.2.zip</TitleSequencesUrl>
|
||||
<TitleSequencesSha1>1136ef92bfb05cd1cba9831ba6dc4a653d87a246</TitleSequencesSha1>
|
||||
<ObjectsUrl>https://github.com/OpenRCT2/objects/releases/download/v1.0/objects.zip</ObjectsUrl>
|
||||
<ObjectsSha1>4f670859b5f37f85e0c3d755b1cb75e839c989a6</ObjectsSha1>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -214,6 +216,15 @@
|
|||
OutputDirectory="$(TargetDir)data\title" />
|
||||
</Target>
|
||||
|
||||
<!-- Target to download the objects -->
|
||||
<Target Name="DownloadObjects" AfterTargets="Build">
|
||||
<DownloadDependency Name="Objects"
|
||||
Url="$(ObjectsUrl)"
|
||||
Sha1="$(ObjectsSha1)"
|
||||
CheckFile="$(DependenciesCheckFile)"
|
||||
OutputDirectory="$(TargetDir)data\object" />
|
||||
</Target>
|
||||
|
||||
<!-- Target to sign OpenRCT2
|
||||
This requires the project parameter SIGN_PASSWORD to be set -->
|
||||
<Target Name="Sign" AfterTargets="Build" Inputs="@(SignItems)" Outputs="%(SignItems.Identity).signed"
|
||||
|
|
|
@ -90,6 +90,14 @@ android.applicationVariants.all { variant ->
|
|||
from zipTree(new File(buildDir, 'title-sequence.zip'))
|
||||
into "$variant.mergeAssets.outputDir/data/title"
|
||||
}
|
||||
download {
|
||||
src 'https://github.com/OpenRCT2/objects/releases/download/v1.0/objects.zip'
|
||||
dest new File(buildDir, 'objects.zip')
|
||||
}
|
||||
copy {
|
||||
from zipTree(new File(buildDir, 'objects.zip'))
|
||||
into "$variant.mergeAssets.outputDir/data/object"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <openrct2/audio/audio.h>
|
||||
#include <openrct2/config/Config.h>
|
||||
#include <openrct2/Context.h>
|
||||
#include <openrct2/core/String.hpp>
|
||||
#include <openrct2/Editor.h>
|
||||
#include <openrct2/EditorObjectSelectionSession.h>
|
||||
#include <openrct2/Game.h>
|
||||
|
@ -304,7 +305,7 @@ static bool visible_list_sort_ride_type(const list_item &a, const list_item &b)
|
|||
{
|
||||
auto rideTypeA = language_get_string(get_ride_type_string_id(a.repositoryItem));
|
||||
auto rideTypeB = language_get_string(get_ride_type_string_id(b.repositoryItem));
|
||||
sint32 result = strcmp(rideTypeA, rideTypeB);
|
||||
sint32 result = String::Compare(rideTypeA, rideTypeB);
|
||||
return result != 0 ?
|
||||
result < 0 :
|
||||
visible_list_sort_ride_name(a, b);
|
||||
|
|
|
@ -3370,7 +3370,6 @@ static void window_ride_operating_invalidate(rct_window *w)
|
|||
{
|
||||
rct_widget *widgets;
|
||||
Ride *ride;
|
||||
rct_ride_entry *rideEntry;
|
||||
rct_string_id format, caption, tooltip;
|
||||
|
||||
widgets = window_ride_page_widgets[w->page];
|
||||
|
@ -3382,7 +3381,6 @@ static void window_ride_operating_invalidate(rct_window *w)
|
|||
window_ride_set_pressed_tab(w);
|
||||
|
||||
ride = get_ride(w->number);
|
||||
rideEntry = get_ride_entry_by_ride(ride);
|
||||
|
||||
set_format_arg(0, rct_string_id, ride->name);
|
||||
set_format_arg(2, uint32, ride->name_arguments);
|
||||
|
@ -3397,8 +3395,8 @@ static void window_ride_operating_invalidate(rct_window *w)
|
|||
);
|
||||
|
||||
// Lift hill speed
|
||||
if ((rideEntry->enabledTrackPieces & (1ULL << TRACK_LIFT_HILL)) &&
|
||||
track_piece_is_available_for_ride_type(ride->type, TRACK_LIFT_HILL)) {
|
||||
if (track_piece_is_available_for_ride_type(ride->type, TRACK_LIFT_HILL))
|
||||
{
|
||||
window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED_LABEL].type = WWT_LABEL;
|
||||
window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED].type = WWT_SPINNER;
|
||||
window_ride_operating_widgets[WIDX_LIFT_HILL_SPEED_INCREASE].type = WWT_BUTTON;
|
||||
|
|
|
@ -301,12 +301,15 @@ namespace OpenRCT2
|
|||
// return false;
|
||||
// } //This comment was relocated so it would stay where it was in relation to the following lines of code.
|
||||
|
||||
auto rct2InstallPath = GetOrPromptRCT2Path();
|
||||
if (rct2InstallPath.empty())
|
||||
if (!gOpenRCT2Headless)
|
||||
{
|
||||
return false;
|
||||
auto rct2InstallPath = GetOrPromptRCT2Path();
|
||||
if (rct2InstallPath.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_env->SetBasePath(DIRBASE::RCT2, rct2InstallPath);
|
||||
}
|
||||
_env->SetBasePath(DIRBASE::RCT2, rct2InstallPath);
|
||||
|
||||
_objectRepository = CreateObjectRepository(_env);
|
||||
_objectManager = CreateObjectManager(_objectRepository);
|
||||
|
|
|
@ -80,9 +80,9 @@ namespace String
|
|||
|
||||
sint32 Compare(const utf8 * a, const utf8 * b, bool ignoreCase)
|
||||
{
|
||||
if (a == b) return true;
|
||||
if (a == nullptr || b == nullptr) return false;
|
||||
|
||||
if (a == b) return 0;
|
||||
if (a == nullptr) a = "";
|
||||
if (b == nullptr) b = "";
|
||||
if (ignoreCase)
|
||||
{
|
||||
return _stricmp(a, b);
|
||||
|
|
|
@ -56,6 +56,7 @@ enum {
|
|||
G1_FLAG_BMP = (1 << 0), // Image data is encoded as raw pixels (no transparency)
|
||||
G1_FLAG_1 = (1 << 1),
|
||||
G1_FLAG_RLE_COMPRESSION = (1 << 2), // Image data is encoded using RCT2's form of run length encoding
|
||||
G1_FLAG_PALETTE = (1 << 3), // Image data is a sequence of palette entries R8G8B8
|
||||
G1_FLAG_HAS_ZOOM_SPRITE = (1 << 4), // Use a different sprite for higher zoom levels
|
||||
G1_FLAG_NO_ZOOM_DRAW = (1 << 5), // Does not get drawn at higher zoom levels (only zoom 0)
|
||||
};
|
||||
|
@ -339,6 +340,7 @@ void scrolling_text_initialise_bitmaps();
|
|||
sint32 scrolling_text_setup(struct paint_session * session, rct_string_id stringId, uint16 scroll, uint16 scrollingMode);
|
||||
|
||||
rct_size16 FASTCALL gfx_get_sprite_size(uint32 image_id);
|
||||
size_t g1_calculate_data_size(const rct_g1_element * g1);
|
||||
|
||||
void mask_scalar(sint32 width, sint32 height, const uint8 * RESTRICT maskSrc, const uint8 * RESTRICT colourSrc,
|
||||
uint8 * RESTRICT dst, sint32 maskWrap, sint32 colourWrap, sint32 dstWrap);
|
||||
|
|
|
@ -379,7 +379,10 @@ bool gfx_load_csg()
|
|||
{
|
||||
_csg.elements[i].offset += (uintptr_t)_csg.data;
|
||||
// RCT1 used zoomed offsets that counted from the beginning of the file, rather than from the current sprite.
|
||||
_csg.elements[i].zoomed_offset = i - (SPR_CSG_BEGIN + _csg.elements[i].zoomed_offset);
|
||||
if (_csg.elements[i].zoomed_offset != 0)
|
||||
{
|
||||
_csg.elements[i].zoomed_offset = i - (SPR_CSG_BEGIN + _csg.elements[i].zoomed_offset);
|
||||
}
|
||||
}
|
||||
_csgLoaded = true;
|
||||
return true;
|
||||
|
@ -858,3 +861,36 @@ rct_size16 FASTCALL gfx_get_sprite_size(uint32 image_id)
|
|||
return size;
|
||||
}
|
||||
|
||||
size_t g1_calculate_data_size(const rct_g1_element * g1)
|
||||
{
|
||||
if (g1->flags & G1_FLAG_PALETTE)
|
||||
{
|
||||
return g1->width * 3;
|
||||
}
|
||||
else if (g1->flags & G1_FLAG_RLE_COMPRESSION)
|
||||
{
|
||||
if (g1->offset == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16 * offsets = (uint16 *)g1->offset;
|
||||
uint8 * ptr = g1->offset + offsets[g1->height - 1];
|
||||
bool endOfLine = false;
|
||||
do
|
||||
{
|
||||
uint8 chunk0 = *ptr++;
|
||||
ptr++; // offset
|
||||
uint8 chunkSize = chunk0 & 0x7F;
|
||||
ptr += chunkSize;
|
||||
endOfLine = (chunk0 & 0x80) != 0;
|
||||
} while (!endOfLine);
|
||||
return ptr - g1->offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return g1->width * g1->height;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,20 @@ void utf8_remove_format_codes(utf8 * text, bool allowcolours)
|
|||
*dstCh = 0;
|
||||
}
|
||||
|
||||
uint8 language_get_id_from_locale(const char * locale)
|
||||
{
|
||||
uint8 i = 0;
|
||||
for (const auto &langDesc : LanguagesDescriptors)
|
||||
{
|
||||
if (String::Equals(locale, langDesc.locale))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return LANGUAGE_UNDEFINED;
|
||||
}
|
||||
|
||||
const char * language_get_string(rct_string_id id)
|
||||
{
|
||||
const char * result = nullptr;
|
||||
|
|
|
@ -94,6 +94,7 @@ extern const utf8 BlackLeftArrowString[];
|
|||
extern const utf8 BlackRightArrowString[];
|
||||
extern const utf8 CheckBoxMarkString[];
|
||||
|
||||
uint8 language_get_id_from_locale(const char * locale);
|
||||
const char *language_get_string(rct_string_id id);
|
||||
bool language_open(sint32 id);
|
||||
void language_close_all();
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
#pragma endregion
|
||||
|
||||
#include "../core/IStream.hpp"
|
||||
#include "BannerObject.h"
|
||||
|
||||
#include "../drawing/Drawing.h"
|
||||
#include "../localisation/Language.h"
|
||||
#include "../object/Object.h"
|
||||
#include "BannerObject.h"
|
||||
#include "ObjectJsonHelpers.h"
|
||||
#include "ObjectList.h"
|
||||
|
||||
void BannerObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
||||
|
@ -31,12 +31,12 @@ void BannerObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
|||
_legacyType.banner.scenery_tab_id = stream->ReadValue<uint8>();
|
||||
stream->Seek(1, STREAM_SEEK_CURRENT);
|
||||
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
|
||||
rct_object_entry sgEntry = stream->ReadValue<rct_object_entry>();
|
||||
SetPrimarySceneryGroup(&sgEntry);
|
||||
|
||||
GetImageTable()->Read(context, stream);
|
||||
GetImageTable().Read(context, stream);
|
||||
|
||||
// Validate properties
|
||||
if (_legacyType.large_scenery.price <= 0)
|
||||
|
@ -61,15 +61,15 @@ void BannerObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
|||
|
||||
void BannerObject::Load()
|
||||
{
|
||||
GetStringTable()->Sort();
|
||||
GetStringTable().Sort();
|
||||
_legacyType.name = language_allocate_object_string(GetName());
|
||||
_legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount());
|
||||
_legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount());
|
||||
}
|
||||
|
||||
void BannerObject::Unload()
|
||||
{
|
||||
language_free_object_string(_legacyType.name);
|
||||
gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount());
|
||||
gfx_object_free_images(_legacyType.image, GetImageTable().GetCount());
|
||||
|
||||
_legacyType.name = 0;
|
||||
_legacyType.image = 0;
|
||||
|
@ -84,3 +84,18 @@ void BannerObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 hei
|
|||
gfx_draw_sprite(dpi, imageId + 0, x - 12, y + 8, 0);
|
||||
gfx_draw_sprite(dpi, imageId + 1, x - 12, y + 8, 0);
|
||||
}
|
||||
|
||||
void BannerObject::ReadJson(IReadObjectContext * context, const json_t * root)
|
||||
{
|
||||
auto properties = json_object_get(root, "properties");
|
||||
|
||||
_legacyType.banner.scrolling_mode = json_integer_value(json_object_get(properties, "scrollingMode"));
|
||||
_legacyType.banner.price = json_integer_value(json_object_get(properties, "price"));
|
||||
_legacyType.banner.flags = ObjectJsonHelpers::GetFlags<uint8>(properties, {
|
||||
{ "hasPrimaryColour", BANNER_ENTRY_FLAG_HAS_PRIMARY_COLOUR }});
|
||||
|
||||
SetPrimarySceneryGroup(ObjectJsonHelpers::GetString(json_object_get(properties, "sceneryGroup")));
|
||||
|
||||
ObjectJsonHelpers::LoadStrings(root, GetStringTable());
|
||||
ObjectJsonHelpers::LoadImages(context, root, GetImageTable());
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ public:
|
|||
void * GetLegacyData() override { return &_legacyType; }
|
||||
|
||||
void ReadLegacy(IReadObjectContext * context, IStream * stream) override;
|
||||
void ReadJson(IReadObjectContext * context, const json_t * root) override;
|
||||
void Load() override;
|
||||
void Unload() override;
|
||||
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
|
||||
#include "../core/IStream.hpp"
|
||||
#include "../core/String.hpp"
|
||||
#include "EntranceObject.h"
|
||||
|
||||
#include "../drawing/Drawing.h"
|
||||
#include "../localisation/Localisation.h"
|
||||
#include "EntranceObject.h"
|
||||
#include "ObjectJsonHelpers.h"
|
||||
|
||||
void EntranceObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
||||
{
|
||||
|
@ -27,8 +27,8 @@ void EntranceObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
|||
_legacyType.scrolling_mode = stream->ReadValue<uint8>();
|
||||
_legacyType.text_height = stream->ReadValue<uint8>();
|
||||
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetImageTable()->Read(context, stream);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetImageTable().Read(context, stream);
|
||||
|
||||
// Fix issue #1705: The Medieval entrance from Time Twister has a straight banner,
|
||||
// but scrolls its text as if it a curved one.
|
||||
|
@ -41,15 +41,15 @@ void EntranceObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
|||
|
||||
void EntranceObject::Load()
|
||||
{
|
||||
GetStringTable()->Sort();
|
||||
GetStringTable().Sort();
|
||||
_legacyType.string_idx = language_allocate_object_string(GetName());
|
||||
_legacyType.image_id = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount());
|
||||
_legacyType.image_id = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount());
|
||||
}
|
||||
|
||||
void EntranceObject::Unload()
|
||||
{
|
||||
language_free_object_string(_legacyType.string_idx);
|
||||
gfx_object_free_images(_legacyType.image_id, GetImageTable()->GetCount());
|
||||
gfx_object_free_images(_legacyType.image_id, GetImageTable().GetCount());
|
||||
|
||||
_legacyType.string_idx = 0;
|
||||
_legacyType.image_id = 0;
|
||||
|
@ -65,3 +65,13 @@ void EntranceObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 h
|
|||
gfx_draw_sprite(dpi, imageId + 0, x + 0, y + 28, 0);
|
||||
gfx_draw_sprite(dpi, imageId + 2, x + 32, y + 44, 0);
|
||||
}
|
||||
|
||||
void EntranceObject::ReadJson(IReadObjectContext * context, const json_t * root)
|
||||
{
|
||||
auto properties = json_object_get(root, "properties");
|
||||
_legacyType.scrolling_mode = json_integer_value(json_object_get(properties, "scrollingMode"));
|
||||
_legacyType.text_height = json_integer_value(json_object_get(properties, "textHeight"));
|
||||
|
||||
ObjectJsonHelpers::LoadStrings(root, GetStringTable());
|
||||
ObjectJsonHelpers::LoadImages(context, root, GetImageTable());
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ public:
|
|||
void * GetLegacyData() override { return &_legacyType; }
|
||||
|
||||
void ReadLegacy(IReadObjectContext * context, IStream * stream) override;
|
||||
void ReadJson(IReadObjectContext * context, const json_t * root) override;
|
||||
void Load() override;
|
||||
void Unload() override;
|
||||
|
||||
|
|
|
@ -14,13 +14,15 @@
|
|||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#include <unordered_map>
|
||||
#include "../core/IStream.hpp"
|
||||
#include "FootpathItemObject.h"
|
||||
|
||||
#include "../drawing/Drawing.h"
|
||||
#include "../interface/Cursors.h"
|
||||
#include "../localisation/Localisation.h"
|
||||
#include "../object/Object.h"
|
||||
#include "ObjectList.h"
|
||||
#include "FootpathItemObject.h"
|
||||
#include "ObjectJsonHelpers.h"
|
||||
|
||||
void FootpathItemObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
||||
{
|
||||
|
@ -32,12 +34,12 @@ void FootpathItemObject::ReadLegacy(IReadObjectContext * context, IStream * stre
|
|||
_legacyType.path_bit.scenery_tab_id = stream->ReadValue<uint8>();
|
||||
stream->Seek(1, STREAM_SEEK_CURRENT);
|
||||
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
|
||||
rct_object_entry sgEntry = stream->ReadValue<rct_object_entry>();
|
||||
SetPrimarySceneryGroup(&sgEntry);
|
||||
|
||||
GetImageTable()->Read(context, stream);
|
||||
GetImageTable().Read(context, stream);
|
||||
|
||||
// Validate properties
|
||||
if (_legacyType.large_scenery.price <= 0)
|
||||
|
@ -62,9 +64,9 @@ void FootpathItemObject::ReadLegacy(IReadObjectContext * context, IStream * stre
|
|||
|
||||
void FootpathItemObject::Load()
|
||||
{
|
||||
GetStringTable()->Sort();
|
||||
GetStringTable().Sort();
|
||||
_legacyType.name = language_allocate_object_string(GetName());
|
||||
_legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount());
|
||||
_legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount());
|
||||
|
||||
_legacyType.path_bit.scenery_tab_id = 0xFF;
|
||||
}
|
||||
|
@ -72,7 +74,7 @@ void FootpathItemObject::Load()
|
|||
void FootpathItemObject::Unload()
|
||||
{
|
||||
language_free_object_string(_legacyType.name);
|
||||
gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount());
|
||||
gfx_object_free_images(_legacyType.image, GetImageTable().GetCount());
|
||||
|
||||
_legacyType.name = 0;
|
||||
_legacyType.image = 0;
|
||||
|
@ -84,3 +86,37 @@ void FootpathItemObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint
|
|||
sint32 y = height / 2;
|
||||
gfx_draw_sprite(dpi, _legacyType.image, x - 22, y - 24, 0);
|
||||
}
|
||||
|
||||
static uint8 ParseDrawType(const std::string &s)
|
||||
{
|
||||
if (s == "lamp") return PATH_BIT_DRAW_TYPE_LIGHTS;
|
||||
if (s == "bin") return PATH_BIT_DRAW_TYPE_BINS;
|
||||
if (s == "bench") return PATH_BIT_DRAW_TYPE_BENCHES;
|
||||
if (s == "fountain") return PATH_BIT_DRAW_TYPE_JUMPING_FOUNTAINS;
|
||||
return PATH_BIT_DRAW_TYPE_LIGHTS;
|
||||
}
|
||||
|
||||
void FootpathItemObject::ReadJson(IReadObjectContext * context, const json_t * root)
|
||||
{
|
||||
auto properties = json_object_get(root, "properties");
|
||||
_legacyType.path_bit.draw_type = ParseDrawType(ObjectJsonHelpers::GetString(properties, "renderAs"));
|
||||
_legacyType.path_bit.tool_id = ObjectJsonHelpers::ParseCursor(ObjectJsonHelpers::GetString(properties, "cursor"), CURSOR_LAMPPOST_DOWN);
|
||||
_legacyType.path_bit.price = json_integer_value(json_object_get(properties, "price"));
|
||||
|
||||
SetPrimarySceneryGroup(ObjectJsonHelpers::GetString(json_object_get(properties, "sceneryGroup")));
|
||||
|
||||
// Flags
|
||||
_legacyType.path_bit.flags = ObjectJsonHelpers::GetFlags<uint16>(properties, {
|
||||
{ "isBin", PATH_BIT_FLAG_IS_BIN },
|
||||
{ "isBench", PATH_BIT_FLAG_IS_BENCH },
|
||||
{ "isBreakable", PATH_BIT_FLAG_BREAKABLE },
|
||||
{ "isLamp", PATH_BIT_FLAG_LAMP },
|
||||
{ "isJumpingFountainWater", PATH_BIT_FLAG_JUMPING_FOUNTAIN_WATER },
|
||||
{ "isJumpingFountainSnow", PATH_BIT_FLAG_JUMPING_FOUNTAIN_SNOW },
|
||||
{ "isAllowedOnQueue", PATH_BIT_FLAG_DONT_ALLOW_ON_QUEUE },
|
||||
{ "isAllowedOnSlope", PATH_BIT_FLAG_DONT_ALLOW_ON_SLOPE },
|
||||
{ "isTelevision", PATH_BIT_FLAG_IS_QUEUE_SCREEN }});
|
||||
|
||||
ObjectJsonHelpers::LoadStrings(root, GetStringTable());
|
||||
ObjectJsonHelpers::LoadImages(context, root, GetImageTable());
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ public:
|
|||
void * GetLegacyData() override { return &_legacyType; }
|
||||
|
||||
void ReadLegacy(IReadObjectContext * context, IStream * stream) override;
|
||||
void ReadJson(IReadObjectContext * context, const json_t * root) override;
|
||||
void Load() override;
|
||||
void Unload() override;
|
||||
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
#pragma endregion
|
||||
|
||||
#include "../core/IStream.hpp"
|
||||
#include "FootpathObject.h"
|
||||
|
||||
#include "../drawing/Drawing.h"
|
||||
#include "../localisation/Language.h"
|
||||
#include "../world/Footpath.h"
|
||||
#include "FootpathObject.h"
|
||||
#include "ObjectJsonHelpers.h"
|
||||
|
||||
void FootpathObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
||||
{
|
||||
|
@ -29,8 +29,8 @@ void FootpathObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
|||
_legacyType.scrolling_mode = stream->ReadValue<uint8>();
|
||||
stream->Seek(1, STREAM_SEEK_CURRENT);
|
||||
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetImageTable()->Read(context, stream);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetImageTable().Read(context, stream);
|
||||
|
||||
// Validate properties
|
||||
if (_legacyType.support_type >= FOOTPATH_ENTRY_SUPPORT_TYPE_COUNT)
|
||||
|
@ -41,16 +41,16 @@ void FootpathObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
|||
|
||||
void FootpathObject::Load()
|
||||
{
|
||||
GetStringTable()->Sort();
|
||||
GetStringTable().Sort();
|
||||
_legacyType.string_idx = language_allocate_object_string(GetName());
|
||||
_legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount());
|
||||
_legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount());
|
||||
_legacyType.bridge_image = _legacyType.image + 109;
|
||||
}
|
||||
|
||||
void FootpathObject::Unload()
|
||||
{
|
||||
language_free_object_string(_legacyType.string_idx);
|
||||
gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount());
|
||||
gfx_object_free_images(_legacyType.image, GetImageTable().GetCount());
|
||||
|
||||
_legacyType.string_idx = 0;
|
||||
_legacyType.image = 0;
|
||||
|
@ -63,3 +63,25 @@ void FootpathObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 h
|
|||
gfx_draw_sprite(dpi, _legacyType.image + 71, x - 49, y - 17, 0);
|
||||
gfx_draw_sprite(dpi, _legacyType.image + 72, x + 4, y - 17, 0);
|
||||
}
|
||||
|
||||
static uint8 ParseSupportType(const std::string &s)
|
||||
{
|
||||
if (s == "pole") return FOOTPATH_ENTRY_SUPPORT_TYPE_POLE;
|
||||
else /* if (s == "box") */ return FOOTPATH_ENTRY_SUPPORT_TYPE_BOX;
|
||||
}
|
||||
|
||||
void FootpathObject::ReadJson(IReadObjectContext * context, const json_t * root)
|
||||
{
|
||||
auto properties = json_object_get(root, "properties");
|
||||
_legacyType.support_type = ParseSupportType(ObjectJsonHelpers::GetString(json_object_get(properties, "supportType")));
|
||||
_legacyType.scrolling_mode = json_integer_value(json_object_get(properties, "scrollingMode"));
|
||||
|
||||
// Flags
|
||||
_legacyType.flags = ObjectJsonHelpers::GetFlags<uint8>(properties, {
|
||||
{ "hasSupportImages", FOOTPATH_ENTRY_FLAG_HAS_SUPPORT_BASE_SPRITE },
|
||||
{ "hasElevatedPathImages", FOOTPATH_ENTRY_FLAG_HAS_PATH_BASE_SPRITE },
|
||||
{ "editorOnly", FOOTPATH_ENTRY_FLAG_SHOW_ONLY_IN_SCENARIO_EDITOR } });
|
||||
|
||||
ObjectJsonHelpers::LoadStrings(root, GetStringTable());
|
||||
ObjectJsonHelpers::LoadImages(context, root, GetImageTable());
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ public:
|
|||
void * GetLegacyData() override { return &_legacyType; }
|
||||
|
||||
void ReadLegacy(IReadObjectContext * context, IStream * stream) override;
|
||||
void ReadJson(IReadObjectContext * context, const json_t * root) override;
|
||||
void Load() override;
|
||||
void Unload() override;
|
||||
|
||||
|
|
|
@ -15,18 +15,22 @@
|
|||
#pragma endregion
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include "../core/IStream.hpp"
|
||||
#include "../core/Memory.hpp"
|
||||
#include "../OpenRCT2.h"
|
||||
#include "ImageTable.h"
|
||||
#include "Object.h"
|
||||
|
||||
ImageTable::~ImageTable()
|
||||
{
|
||||
Memory::Free(_data);
|
||||
_data = nullptr;
|
||||
_dataSize = 0;
|
||||
if (_data == nullptr)
|
||||
{
|
||||
for (auto &entry : _entries)
|
||||
{
|
||||
delete [] entry.offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImageTable::Read(IReadObjectContext * context, IStream * stream)
|
||||
|
@ -49,16 +53,17 @@ void ImageTable::Read(IReadObjectContext * context, IStream * stream)
|
|||
imageDataSize = (uint32)remainingBytes;
|
||||
}
|
||||
|
||||
_dataSize = imageDataSize;
|
||||
_data = Memory::Reallocate(_data, _dataSize);
|
||||
if (_data == nullptr)
|
||||
auto dataSize = (size_t)imageDataSize;
|
||||
auto data = std::make_unique<uint8[]>(dataSize);
|
||||
if (data == nullptr)
|
||||
{
|
||||
context->LogError(OBJECT_ERROR_BAD_IMAGE_TABLE, "Image table too large.");
|
||||
throw std::runtime_error("Image table too large.");
|
||||
}
|
||||
|
||||
// Read g1 element headers
|
||||
uintptr_t imageDataBase = (uintptr_t)_data;
|
||||
uintptr_t imageDataBase = (uintptr_t)data.get();
|
||||
std::vector<rct_g1_element> newEntries;
|
||||
for (uint32 i = 0; i < numImages; i++)
|
||||
{
|
||||
rct_g1_element g1Element;
|
||||
|
@ -73,23 +78,22 @@ void ImageTable::Read(IReadObjectContext * context, IStream * stream)
|
|||
g1Element.flags = stream->ReadValue<uint16>();
|
||||
g1Element.zoomed_offset = stream->ReadValue<uint16>();
|
||||
|
||||
_entries.push_back(g1Element);
|
||||
newEntries.push_back(g1Element);
|
||||
}
|
||||
|
||||
// Read g1 element data
|
||||
size_t readBytes = (size_t)stream->TryRead(_data, _dataSize);
|
||||
size_t readBytes = (size_t)stream->TryRead(data.get(), dataSize);
|
||||
|
||||
// If data is shorter than expected (some custom objects are unfortunately like that)
|
||||
size_t unreadBytes = _dataSize - readBytes;
|
||||
size_t unreadBytes = dataSize - readBytes;
|
||||
if (unreadBytes > 0)
|
||||
{
|
||||
uint8 * ptr = (uint8*)(((uintptr_t)_data) + readBytes);
|
||||
std::fill_n(ptr, unreadBytes, 0);
|
||||
|
||||
std::fill_n(data.get() + readBytes, unreadBytes, 0);
|
||||
context->LogWarning(OBJECT_ERROR_BAD_IMAGE_TABLE, "Image table size shorter than expected.");
|
||||
}
|
||||
|
||||
// TODO validate the image data to prevent crashes in-game
|
||||
_data = std::move(data);
|
||||
_entries.insert(_entries.end(), newEntries.begin(), newEntries.end());
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
|
@ -97,3 +101,19 @@ void ImageTable::Read(IReadObjectContext * context, IStream * stream)
|
|||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void ImageTable::AddImage(const rct_g1_element * g1)
|
||||
{
|
||||
rct_g1_element newg1 = *g1;
|
||||
auto length = g1_calculate_data_size(g1);
|
||||
if (length == 0)
|
||||
{
|
||||
newg1.offset = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
newg1.offset = new uint8[length];
|
||||
std::copy_n(g1->offset, length, newg1.offset);
|
||||
}
|
||||
_entries.push_back(newg1);
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "../common.h"
|
||||
|
||||
#include "../drawing/Drawing.h"
|
||||
|
||||
interface IReadObjectContext;
|
||||
|
@ -27,14 +27,17 @@ interface IStream;
|
|||
class ImageTable
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<uint8[]> _data;
|
||||
std::vector<rct_g1_element> _entries;
|
||||
void * _data = nullptr;
|
||||
size_t _dataSize = 0;
|
||||
|
||||
public:
|
||||
ImageTable() = default;
|
||||
ImageTable(const ImageTable &) = delete;
|
||||
ImageTable & operator=(const ImageTable &) = delete;
|
||||
~ImageTable();
|
||||
|
||||
void Read(IReadObjectContext * context, IStream * stream);
|
||||
const rct_g1_element * GetImages() const { return _entries.data(); }
|
||||
uint32 GetCount() const { return (uint32)_entries.size(); }
|
||||
void AddImage(const rct_g1_element * g1);
|
||||
};
|
||||
|
|
|
@ -14,12 +14,17 @@
|
|||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#pragma warning(disable : 4706) // assignment within conditional expression
|
||||
|
||||
#include <algorithm>
|
||||
#include "../core/IStream.hpp"
|
||||
#include "../core/Memory.hpp"
|
||||
#include "LargeSceneryObject.h"
|
||||
|
||||
#include "../core/Util.hpp"
|
||||
#include "../drawing/Drawing.h"
|
||||
#include "../interface/Cursors.h"
|
||||
#include "../localisation/Language.h"
|
||||
#include "LargeSceneryObject.h"
|
||||
#include "ObjectJsonHelpers.h"
|
||||
|
||||
void LargeSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
||||
{
|
||||
|
@ -33,7 +38,7 @@ void LargeSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre
|
|||
_legacyType.large_scenery.scrolling_mode = stream->ReadValue<uint8>();
|
||||
stream->Seek(4, STREAM_SEEK_CURRENT);
|
||||
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
|
||||
rct_object_entry sgEntry = stream->ReadValue<rct_object_entry>();
|
||||
SetPrimarySceneryGroup(&sgEntry);
|
||||
|
@ -47,7 +52,7 @@ void LargeSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre
|
|||
|
||||
_tiles = ReadTiles(stream);
|
||||
|
||||
GetImageTable()->Read(context, stream);
|
||||
GetImageTable().Read(context, stream);
|
||||
|
||||
// Validate properties
|
||||
if (_legacyType.large_scenery.price <= 0)
|
||||
|
@ -67,9 +72,9 @@ void LargeSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre
|
|||
|
||||
void LargeSceneryObject::Load()
|
||||
{
|
||||
GetStringTable()->Sort();
|
||||
GetStringTable().Sort();
|
||||
_legacyType.name = language_allocate_object_string(GetName());
|
||||
_baseImageId = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount());
|
||||
_baseImageId = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount());
|
||||
_legacyType.image = _baseImageId;
|
||||
|
||||
_legacyType.large_scenery.tiles = _tiles.data();
|
||||
|
@ -79,19 +84,20 @@ void LargeSceneryObject::Load()
|
|||
_legacyType.large_scenery.text_image = _legacyType.image;
|
||||
if (_3dFont->flags & LARGE_SCENERY_TEXT_FLAG_VERTICAL)
|
||||
{
|
||||
_legacyType.image += _3dFont->var_D * 2;
|
||||
_legacyType.image += _3dFont->num_images * 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
_legacyType.image += _3dFont->var_D * 4;
|
||||
_legacyType.image += _3dFont->num_images * 4;
|
||||
}
|
||||
_legacyType.large_scenery.text = _3dFont.get();
|
||||
}
|
||||
}
|
||||
|
||||
void LargeSceneryObject::Unload()
|
||||
{
|
||||
language_free_object_string(_legacyType.name);
|
||||
gfx_object_free_images(_baseImageId, GetImageTable()->GetCount());
|
||||
gfx_object_free_images(_baseImageId, GetImageTable().GetCount());
|
||||
|
||||
_legacyType.name = 0;
|
||||
_legacyType.image = 0;
|
||||
|
@ -118,3 +124,147 @@ std::vector<rct_large_scenery_tile> LargeSceneryObject::ReadTiles(IStream * stre
|
|||
tiles.push_back({ -1, -1, -1, 255, 0xFFFF });
|
||||
return tiles;
|
||||
}
|
||||
|
||||
void LargeSceneryObject::ReadJson(IReadObjectContext * context, const json_t * root)
|
||||
{
|
||||
auto properties = json_object_get(root, "properties");
|
||||
|
||||
_legacyType.large_scenery.tool_id = ObjectJsonHelpers::ParseCursor(ObjectJsonHelpers::GetString(properties, "cursor"), CURSOR_STATUE_DOWN);
|
||||
_legacyType.large_scenery.price = json_integer_value(json_object_get(properties, "price"));
|
||||
_legacyType.large_scenery.removal_price = json_integer_value(json_object_get(properties, "removalPrice"));
|
||||
|
||||
auto jScrollingMode = json_object_get(properties, "scrollingMode");
|
||||
_legacyType.large_scenery.scrolling_mode = jScrollingMode != nullptr ?
|
||||
json_integer_value(jScrollingMode) :
|
||||
-1;
|
||||
|
||||
// Flags
|
||||
_legacyType.large_scenery.flags = ObjectJsonHelpers::GetFlags<uint8>(properties, {
|
||||
{ "hasPrimaryColour", LARGE_SCENERY_FLAG_HAS_PRIMARY_COLOUR },
|
||||
{ "hasSecondaryColour", LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR },
|
||||
{ "isAnimated", LARGE_SCENERY_FLAG_ANIMATED },
|
||||
{ "isPhotogenic", LARGE_SCENERY_FLAG_PHOTOGENIC } });
|
||||
|
||||
// Tiles
|
||||
auto jTiles = json_object_get(properties, "tiles");
|
||||
if (jTiles != nullptr)
|
||||
{
|
||||
_tiles = ReadJsonTiles(jTiles);
|
||||
}
|
||||
|
||||
// Read text
|
||||
auto j3dFont = json_object_get(properties, "3dFont");
|
||||
if (j3dFont != nullptr)
|
||||
{
|
||||
_3dFont = ReadJson3dFont(j3dFont);
|
||||
_legacyType.large_scenery.flags |= LARGE_SCENERY_FLAG_3D_TEXT;
|
||||
}
|
||||
|
||||
SetPrimarySceneryGroup(ObjectJsonHelpers::GetString(json_object_get(properties, "sceneryGroup")));
|
||||
|
||||
ObjectJsonHelpers::LoadStrings(root, GetStringTable());
|
||||
ObjectJsonHelpers::LoadImages(context, root, GetImageTable());
|
||||
}
|
||||
|
||||
std::vector<rct_large_scenery_tile> LargeSceneryObject::ReadJsonTiles(const json_t * jTiles)
|
||||
{
|
||||
std::vector<rct_large_scenery_tile> tiles;
|
||||
size_t index;
|
||||
const json_t * jTile;
|
||||
json_array_foreach(jTiles, index, jTile)
|
||||
{
|
||||
rct_large_scenery_tile tile = { 0 };
|
||||
tile.x_offset = json_integer_value(json_object_get(jTile, "x"));
|
||||
tile.y_offset = json_integer_value(json_object_get(jTile, "y"));
|
||||
tile.z_offset = json_integer_value(json_object_get(jTile, "z"));
|
||||
tile.z_clearance = json_integer_value(json_object_get(jTile, "clearance"));
|
||||
if (!ObjectJsonHelpers::GetBoolean(jTile, "hasSupports"))
|
||||
{
|
||||
tile.flags |= LARGE_SCENERY_TILE_FLAG_NO_SUPPORTS;
|
||||
}
|
||||
if (ObjectJsonHelpers::GetBoolean(jTile, "allowSupportsAbove"))
|
||||
{
|
||||
tile.flags |= LARGE_SCENERY_TILE_FLAG_ALLOW_SUPPORTS_ABOVE;
|
||||
}
|
||||
|
||||
// All corners are by default occupied
|
||||
auto jCorners = json_object_get(jTile, "corners");
|
||||
auto corners = 0xF;
|
||||
if (jCorners != nullptr)
|
||||
{
|
||||
corners = json_integer_value(jCorners);
|
||||
}
|
||||
tile.flags |= (corners & 0xFF) << 12;
|
||||
|
||||
auto walls = json_integer_value(json_object_get(jTile, "walls"));
|
||||
tile.flags |= (walls & 0xFF) << 8;
|
||||
|
||||
tiles.push_back(tile);
|
||||
}
|
||||
|
||||
// HACK Add end of tiles marker
|
||||
// We should remove this later by improving the code base to use tiles array length
|
||||
tiles.push_back({ -1, -1, -1, 0xFF, 0xFFFF });
|
||||
|
||||
return tiles;
|
||||
}
|
||||
|
||||
std::unique_ptr<rct_large_scenery_text> LargeSceneryObject::ReadJson3dFont(const json_t * j3dFont)
|
||||
{
|
||||
auto font = std::make_unique<rct_large_scenery_text>();
|
||||
|
||||
auto jOffsets = json_object_get(j3dFont, "offsets");
|
||||
if (jOffsets != nullptr)
|
||||
{
|
||||
auto offsets = ReadJsonOffsets(jOffsets);
|
||||
auto numOffsets = std::min(Util::CountOf(font->offset), offsets.size());
|
||||
std::copy_n(offsets.data(), numOffsets, font->offset);
|
||||
}
|
||||
|
||||
font->max_width = json_integer_value(json_object_get(j3dFont, "maxWidth"));
|
||||
font->num_images = json_integer_value(json_object_get(j3dFont, "numImages"));
|
||||
font->flags = ObjectJsonHelpers::GetFlags<uint8>(j3dFont, {
|
||||
{ "isVertical", LARGE_SCENERY_TEXT_FLAG_VERTICAL },
|
||||
{ "isTwoLine", LARGE_SCENERY_TEXT_FLAG_TWO_LINE } });
|
||||
|
||||
auto jGlyphs = json_object_get(j3dFont, "glyphs");
|
||||
if (jGlyphs != nullptr)
|
||||
{
|
||||
auto glyphs = ReadJsonGlyphs(jGlyphs);
|
||||
auto numGlyphs = std::min(Util::CountOf(font->glyphs), glyphs.size());
|
||||
std::copy_n(glyphs.data(), numGlyphs, font->glyphs);
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
std::vector<LocationXY16> LargeSceneryObject::ReadJsonOffsets(const json_t * jOffsets)
|
||||
{
|
||||
std::vector<LocationXY16> offsets;
|
||||
size_t index;
|
||||
const json_t * jOffset;
|
||||
json_array_foreach(jOffsets, index, jOffset)
|
||||
{
|
||||
LocationXY16 offset = { 0 };
|
||||
offset.x = json_integer_value(json_object_get(jOffset, "x"));
|
||||
offset.y = json_integer_value(json_object_get(jOffset, "y"));
|
||||
offsets.push_back(offset);
|
||||
}
|
||||
return offsets;
|
||||
}
|
||||
|
||||
std::vector<rct_large_scenery_text_glyph> LargeSceneryObject::ReadJsonGlyphs(const json_t * jGlpyhs)
|
||||
{
|
||||
std::vector<rct_large_scenery_text_glyph> glyphs;
|
||||
size_t index;
|
||||
const json_t * jGlyph;
|
||||
json_array_foreach(jGlpyhs, index, jGlyph)
|
||||
{
|
||||
rct_large_scenery_text_glyph glyph;
|
||||
glyph.image_offset = json_integer_value(json_object_get(jGlyph, "image"));
|
||||
glyph.width = json_integer_value(json_object_get(jGlyph, "width"));
|
||||
glyph.height = json_integer_value(json_object_get(jGlyph, "height"));
|
||||
glyphs.push_back(glyph);
|
||||
}
|
||||
return glyphs;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ public:
|
|||
void * GetLegacyData() override { return &_legacyType; }
|
||||
|
||||
void ReadLegacy(IReadObjectContext * context, IStream * stream) override;
|
||||
void ReadJson(IReadObjectContext * context, const json_t * root) override;
|
||||
void Load() override;
|
||||
void Unload() override;
|
||||
|
||||
|
@ -42,4 +43,8 @@ public:
|
|||
|
||||
private:
|
||||
static std::vector<rct_large_scenery_tile> ReadTiles(IStream * stream);
|
||||
static std::vector<rct_large_scenery_tile> ReadJsonTiles(const json_t * jTiles);
|
||||
static std::unique_ptr<rct_large_scenery_text> ReadJson3dFont(const json_t * j3dFont);
|
||||
static std::vector<LocationXY16> ReadJsonOffsets(const json_t * jOffsets);
|
||||
static std::vector<rct_large_scenery_text_glyph> ReadJsonGlyphs(const json_t * jGlpyhs);
|
||||
};
|
||||
|
|
|
@ -71,7 +71,7 @@ std::string Object::GetString(uint8 index) const
|
|||
auto sz = GetOverrideString(index);
|
||||
if (sz.empty())
|
||||
{
|
||||
sz = GetStringTable()->GetString(index);
|
||||
sz = GetStringTable().GetString(index);
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../common.h"
|
||||
#include "../core/Json.hpp"
|
||||
#include "ImageTable.h"
|
||||
#include "StringTable.h"
|
||||
|
||||
|
@ -110,16 +111,6 @@ struct rct_object_filters {
|
|||
assert_struct_size(rct_object_filters, 3);
|
||||
#pragma pack(pop)
|
||||
|
||||
enum OBJ_STRING_ID
|
||||
{
|
||||
OBJ_STRING_ID_NAME,
|
||||
OBJ_STRING_ID_DESCRIPTION,
|
||||
OBJ_STRING_ID_SCENARIO_NAME = 0,
|
||||
OBJ_STRING_ID_PARK_NAME = 1,
|
||||
OBJ_STRING_ID_SCENARIO_DETAILS = 2,
|
||||
OBJ_STRING_ID_CAPACITY = 2,
|
||||
};
|
||||
|
||||
interface IStream;
|
||||
struct ObjectRepositoryItem;
|
||||
struct rct_drawpixelinfo;
|
||||
|
@ -128,6 +119,8 @@ interface IReadObjectContext
|
|||
{
|
||||
virtual ~IReadObjectContext() = default;
|
||||
|
||||
virtual bool ShouldLoadImages() abstract;
|
||||
|
||||
virtual void LogWarning(uint32 code, const utf8 * text) abstract;
|
||||
virtual void LogError(uint32 code, const utf8 * text) abstract;
|
||||
};
|
||||
|
@ -146,9 +139,9 @@ private:
|
|||
ImageTable _imageTable;
|
||||
|
||||
protected:
|
||||
StringTable * GetStringTable() { return &_stringTable; }
|
||||
const StringTable * GetStringTable() const { return &_stringTable; }
|
||||
ImageTable * GetImageTable() { return &_imageTable; }
|
||||
StringTable & GetStringTable() { return _stringTable; }
|
||||
const StringTable & GetStringTable() const { return _stringTable; }
|
||||
ImageTable & GetImageTable() { return _imageTable; }
|
||||
|
||||
std::string GetOverrideString(uint8 index) const;
|
||||
std::string GetString(uint8 index) const;
|
||||
|
@ -168,6 +161,7 @@ public:
|
|||
const rct_object_entry * GetObjectEntry() const { return &_objectEntry; }
|
||||
virtual void * GetLegacyData() abstract;
|
||||
|
||||
virtual void ReadJson(IReadObjectContext * context, const json_t * root) { }
|
||||
virtual void ReadLegacy(IReadObjectContext * context, IStream * stream) abstract;
|
||||
virtual void Load() abstract;
|
||||
virtual void Unload() abstract;
|
||||
|
@ -179,6 +173,8 @@ public:
|
|||
|
||||
virtual void SetRepositoryItem(ObjectRepositoryItem * item) const { }
|
||||
|
||||
const ImageTable & GetImageTable() const { return _imageTable; }
|
||||
|
||||
rct_object_entry GetScgWallsHeader();
|
||||
rct_object_entry GetScgPathXHeader();
|
||||
rct_object_entry CreateHeader(const char name[9], uint32 flags, uint32 checksum);
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
|
||||
#include "../core/Console.hpp"
|
||||
#include "../core/FileStream.hpp"
|
||||
#include "../core/Json.hpp"
|
||||
#include "../core/Memory.hpp"
|
||||
#include "../core/MemoryStream.h"
|
||||
#include "../core/String.hpp"
|
||||
#include "../OpenRCT2.h"
|
||||
#include "../rct12/SawyerChunkReader.h"
|
||||
#include "BannerObject.h"
|
||||
#include "EntranceObject.h"
|
||||
|
@ -39,23 +41,24 @@
|
|||
class ReadObjectContext : public IReadObjectContext
|
||||
{
|
||||
private:
|
||||
utf8 * _objectName;
|
||||
bool _wasWarning = false;
|
||||
bool _wasError = false;
|
||||
std::string _objectName;
|
||||
bool _loadImages;
|
||||
bool _wasWarning = false;
|
||||
bool _wasError = false;
|
||||
|
||||
public:
|
||||
bool WasWarning() const { return _wasWarning; }
|
||||
bool WasError() const { return _wasError; }
|
||||
|
||||
explicit ReadObjectContext(const utf8 * objectFileName)
|
||||
ReadObjectContext(const std::string &objectName, bool loadImages)
|
||||
: _objectName(objectName),
|
||||
_loadImages(loadImages)
|
||||
{
|
||||
_objectName = String::Duplicate(objectFileName);
|
||||
}
|
||||
|
||||
~ReadObjectContext() override
|
||||
bool ShouldLoadImages() override
|
||||
{
|
||||
Memory::Free(_objectName);
|
||||
_objectName = nullptr;
|
||||
return _loadImages;
|
||||
}
|
||||
|
||||
void LogWarning(uint32 code, const utf8 * text) override
|
||||
|
@ -64,7 +67,7 @@ public:
|
|||
|
||||
if (!String::IsNullOrEmpty(text))
|
||||
{
|
||||
log_verbose("[%s] Warning: %s", _objectName, text);
|
||||
Console::Error::WriteLine("[%s] Warning: %s", _objectName.c_str(), text);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +77,7 @@ public:
|
|||
|
||||
if (!String::IsNullOrEmpty(text))
|
||||
{
|
||||
Console::Error::WriteLine("[%s] Error: %s", _objectName, text);
|
||||
Console::Error::WriteLine("[%s] Error: %s", _objectName.c_str(), text);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -119,7 +122,7 @@ namespace ObjectFactory
|
|||
log_verbose(" size: %zu", chunk->GetLength());
|
||||
|
||||
auto chunkStream = MemoryStream(chunk->GetData(), chunk->GetLength());
|
||||
auto readContext = ReadObjectContext(objectName);
|
||||
auto readContext = ReadObjectContext(objectName, !gOpenRCT2Headless);
|
||||
ReadObjectLegacy(result, &readContext, &chunkStream);
|
||||
if (readContext.WasError())
|
||||
{
|
||||
|
@ -128,8 +131,6 @@ namespace ObjectFactory
|
|||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
Console::Error::WriteLine("Unable to open or read '%s'", path);
|
||||
|
||||
delete result;
|
||||
result = nullptr;
|
||||
}
|
||||
|
@ -147,7 +148,7 @@ namespace ObjectFactory
|
|||
utf8 objectName[DAT_NAME_LENGTH + 1];
|
||||
object_entry_get_name_fixed(objectName, sizeof(objectName), entry);
|
||||
|
||||
auto readContext = ReadObjectContext(objectName);
|
||||
auto readContext = ReadObjectContext(objectName, !gOpenRCT2Headless);
|
||||
auto chunkStream = MemoryStream(data, dataSize);
|
||||
ReadObjectLegacy(result, &readContext, &chunkStream);
|
||||
|
||||
|
@ -203,4 +204,68 @@ namespace ObjectFactory
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint8 ParseObjectType(const std::string &s)
|
||||
{
|
||||
if (s == "ride") return OBJECT_TYPE_RIDE;
|
||||
if (s == "footpath") return OBJECT_TYPE_PATHS;
|
||||
if (s == "footpath_banner") return OBJECT_TYPE_BANNERS;
|
||||
if (s == "footpath_item") return OBJECT_TYPE_PATH_BITS;
|
||||
if (s == "scenery_small") return OBJECT_TYPE_SMALL_SCENERY;
|
||||
if (s == "scenery_large") return OBJECT_TYPE_LARGE_SCENERY;
|
||||
if (s == "scenery_wall") return OBJECT_TYPE_WALLS;
|
||||
if (s == "scenery_group") return OBJECT_TYPE_SCENERY_GROUP;
|
||||
if (s == "park_entrance") return OBJECT_TYPE_PARK_ENTRANCE;
|
||||
if (s == "water") return OBJECT_TYPE_WATER;
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
Object * CreateObjectFromJsonFile(const std::string &path)
|
||||
{
|
||||
log_verbose("CreateObjectFromJsonFile(\"%s\")", path.c_str());
|
||||
|
||||
Object * result = nullptr;
|
||||
try
|
||||
{
|
||||
auto jRoot = Json::ReadFromFile(path.c_str());
|
||||
auto jObjectType = json_object_get(jRoot, "objectType");
|
||||
if (json_is_string(jObjectType))
|
||||
{
|
||||
auto objectType = ParseObjectType(json_string_value(jObjectType));
|
||||
if (objectType != 0xFF)
|
||||
{
|
||||
auto id = json_string_value(json_object_get(jRoot, "id"));
|
||||
|
||||
rct_object_entry entry = { 0 };
|
||||
auto originalId = String::ToStd(json_string_value(json_object_get(jRoot, "originalId")));
|
||||
auto originalName = originalId;
|
||||
if (originalId.length() == 8 + 1 + 8 + 1 + 8)
|
||||
{
|
||||
entry.flags = std::stoul(originalId.substr(0, 8), 0, 16);
|
||||
originalName = originalId.substr(9, 8);
|
||||
entry.checksum = std::stoul(originalId.substr(18, 8), 0, 16);
|
||||
}
|
||||
auto minLength = std::min<size_t>(8, originalName.length());
|
||||
memcpy(entry.name, originalName.c_str(), minLength);
|
||||
|
||||
result = CreateObject(entry);
|
||||
auto readContext = ReadObjectContext(id, !gOpenRCT2Headless);
|
||||
result->ReadJson(&readContext, jRoot);
|
||||
if (readContext.WasError())
|
||||
{
|
||||
throw std::runtime_error("Object has errors");
|
||||
}
|
||||
}
|
||||
}
|
||||
json_decref(jRoot);
|
||||
}
|
||||
catch (const std::runtime_error &err)
|
||||
{
|
||||
Console::Error::WriteLine("Unable to open or read '%s': %s", path.c_str(), err.what());
|
||||
|
||||
delete result;
|
||||
result = nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,4 +26,6 @@ namespace ObjectFactory
|
|||
Object * CreateObjectFromLegacyFile(const utf8 * path);
|
||||
Object * CreateObjectFromLegacyData(const rct_object_entry * entry, const void * data, size_t dataSize);
|
||||
Object * CreateObject(const rct_object_entry &entry);
|
||||
|
||||
Object * CreateObjectFromJsonFile(const std::string &path);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,377 @@
|
|||
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
|
||||
/*****************************************************************************
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* A full copy of the GNU General Public License can be found in licence.txt
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#pragma warning(disable : 4706) // assignment within conditional expression
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <unordered_map>
|
||||
#include "../Context.h"
|
||||
#include "../core/File.h"
|
||||
#include "../core/FileScanner.h"
|
||||
#include "../core/Math.hpp"
|
||||
#include "../core/Memory.hpp"
|
||||
#include "../core/Path.hpp"
|
||||
#include "../core/String.hpp"
|
||||
#include "../interface/Cursors.h"
|
||||
#include "../localisation/Language.h"
|
||||
#include "../PlatformEnvironment.h"
|
||||
#include "../sprites.h"
|
||||
#include "Object.h"
|
||||
#include "ObjectFactory.h"
|
||||
#include "ObjectJsonHelpers.h"
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
namespace ObjectJsonHelpers
|
||||
{
|
||||
bool GetBoolean(const json_t * obj, const std::string &name, bool defaultValue)
|
||||
{
|
||||
auto value = json_object_get(obj, name.c_str());
|
||||
return json_is_boolean(value) ?
|
||||
json_boolean_value(value) :
|
||||
defaultValue;
|
||||
}
|
||||
|
||||
std::string GetString(const json_t * value)
|
||||
{
|
||||
return json_is_string(value) ?
|
||||
std::string(json_string_value(value)) :
|
||||
std::string();
|
||||
}
|
||||
|
||||
std::string GetString(const json_t * obj, const std::string &name, const std::string &defaultValue)
|
||||
{
|
||||
auto value = json_object_get(obj, name.c_str());
|
||||
return json_is_string(value) ?
|
||||
json_string_value(value) :
|
||||
defaultValue;
|
||||
}
|
||||
|
||||
sint32 GetInteger(const json_t * obj, const std::string &name, const sint32 &defaultValue)
|
||||
{
|
||||
auto value = json_object_get(obj, name.c_str());
|
||||
if (json_is_integer(value))
|
||||
{
|
||||
sint64 val = json_integer_value(value);
|
||||
if (val >= std::numeric_limits<sint32>::min() &&
|
||||
val <= std::numeric_limits<sint32>::max())
|
||||
{
|
||||
return static_cast<sint32>(val);
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
float GetFloat(const json_t * obj, const std::string &name, const float &defaultValue)
|
||||
{
|
||||
auto value = json_object_get(obj, name.c_str());
|
||||
return json_is_number(value) ?
|
||||
json_number_value(value) :
|
||||
defaultValue;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetJsonStringArray(const json_t * arr)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
if (json_is_array(arr))
|
||||
{
|
||||
auto count = json_array_size(arr);
|
||||
result.reserve(count);
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
auto element = json_string_value(json_array_get(arr, i));
|
||||
result.push_back(element);
|
||||
}
|
||||
}
|
||||
else if (json_is_string(arr))
|
||||
{
|
||||
result.push_back(json_string_value(arr));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<sint32> GetJsonIntegerArray(const json_t * arr)
|
||||
{
|
||||
std::vector<sint32> result;
|
||||
if (json_is_array(arr))
|
||||
{
|
||||
auto count = json_array_size(arr);
|
||||
result.reserve(count);
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
auto element = json_integer_value(json_array_get(arr, i));
|
||||
result.push_back(element);
|
||||
}
|
||||
}
|
||||
else if (json_is_integer(arr))
|
||||
{
|
||||
result.push_back(json_integer_value(arr));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8 ParseCursor(const std::string &s, uint8 defaultValue)
|
||||
{
|
||||
static const std::unordered_map<std::string, uint8> LookupTable
|
||||
{
|
||||
{ "CURSOR_BLANK", CURSOR_BLANK },
|
||||
{ "CURSOR_UP_ARROW", CURSOR_UP_ARROW },
|
||||
{ "CURSOR_UP_DOWN_ARROW", CURSOR_UP_DOWN_ARROW },
|
||||
{ "CURSOR_HAND_POINT", CURSOR_HAND_POINT },
|
||||
{ "CURSOR_ZZZ", CURSOR_ZZZ },
|
||||
{ "CURSOR_DIAGONAL_ARROWS", CURSOR_DIAGONAL_ARROWS },
|
||||
{ "CURSOR_PICKER", CURSOR_PICKER },
|
||||
{ "CURSOR_TREE_DOWN", CURSOR_TREE_DOWN },
|
||||
{ "CURSOR_FOUNTAIN_DOWN", CURSOR_FOUNTAIN_DOWN },
|
||||
{ "CURSOR_STATUE_DOWN", CURSOR_STATUE_DOWN },
|
||||
{ "CURSOR_BENCH_DOWN", CURSOR_BENCH_DOWN },
|
||||
{ "CURSOR_CROSS_HAIR", CURSOR_CROSS_HAIR },
|
||||
{ "CURSOR_BIN_DOWN", CURSOR_BIN_DOWN },
|
||||
{ "CURSOR_LAMPPOST_DOWN", CURSOR_LAMPPOST_DOWN },
|
||||
{ "CURSOR_FENCE_DOWN", CURSOR_FENCE_DOWN },
|
||||
{ "CURSOR_FLOWER_DOWN", CURSOR_FLOWER_DOWN },
|
||||
{ "CURSOR_PATH_DOWN", CURSOR_PATH_DOWN },
|
||||
{ "CURSOR_DIG_DOWN", CURSOR_DIG_DOWN },
|
||||
{ "CURSOR_WATER_DOWN", CURSOR_WATER_DOWN },
|
||||
{ "CURSOR_HOUSE_DOWN", CURSOR_HOUSE_DOWN },
|
||||
{ "CURSOR_VOLCANO_DOWN", CURSOR_VOLCANO_DOWN },
|
||||
{ "CURSOR_WALK_DOWN", CURSOR_WALK_DOWN },
|
||||
{ "CURSOR_PAINT_DOWN", CURSOR_PAINT_DOWN },
|
||||
{ "CURSOR_ENTRANCE_DOWN", CURSOR_ENTRANCE_DOWN },
|
||||
{ "CURSOR_HAND_OPEN", CURSOR_HAND_OPEN },
|
||||
{ "CURSOR_HAND_CLOSED", CURSOR_HAND_CLOSED },
|
||||
{ "CURSOR_ARROW", CURSOR_ARROW },
|
||||
};
|
||||
|
||||
auto result = LookupTable.find(s);
|
||||
return (result != LookupTable.end()) ?
|
||||
result->second :
|
||||
defaultValue;
|
||||
}
|
||||
|
||||
rct_object_entry ParseObjectEntry(const std::string & s)
|
||||
{
|
||||
rct_object_entry entry = { 0 };
|
||||
std::fill_n(entry.name, sizeof(entry.name), ' ');
|
||||
auto copyLen = std::min<size_t>(8, s.size());
|
||||
std::copy_n(s.c_str(), copyLen, entry.name);
|
||||
return entry;
|
||||
}
|
||||
|
||||
static std::vector<sint32> ParseRange(std::string s)
|
||||
{
|
||||
// Currently only supports [###] or [###..###]
|
||||
std::vector<sint32> result = { };
|
||||
if (s.length() >= 3 && s[0] == '[' && s[s.length() - 1] == ']')
|
||||
{
|
||||
s = s.substr(1, s.length() - 2);
|
||||
auto parts = String::Split(s, "..");
|
||||
if (parts.size() == 1)
|
||||
{
|
||||
result.push_back(std::stoi(parts[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto left = std::stoi(parts[0]);
|
||||
auto right = std::stoi(parts[1]);
|
||||
if (left <= right)
|
||||
{
|
||||
for (auto i = left; i <= right; i++)
|
||||
{
|
||||
result.push_back(i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto i = right; i >= left; i--)
|
||||
{
|
||||
result.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string FindLegacyObject(const std::string &name)
|
||||
{
|
||||
const auto env = GetContext()->GetPlatformEnvironment();
|
||||
auto objectsPath = env->GetDirectoryPath(DIRBASE::RCT2, DIRID::OBJECT);
|
||||
auto objectPath = Path::Combine(objectsPath, name);
|
||||
#ifndef _WIN32
|
||||
if (!File::Exists(objectPath))
|
||||
{
|
||||
// UNIX based systems need to search for any files with the same name
|
||||
// due to case sensitivity.
|
||||
auto filter = Path::Combine(objectsPath, "*.dat");
|
||||
auto scanner = std::unique_ptr<IFileScanner>(Path::ScanDirectory(filter, false));
|
||||
while (scanner->Next())
|
||||
{
|
||||
auto relativePath = scanner->GetPathRelative();
|
||||
if (String::Equals(relativePath, name, true))
|
||||
{
|
||||
objectPath = scanner->GetPath();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return objectPath;
|
||||
}
|
||||
|
||||
static std::vector<rct_g1_element> LoadObjectImages(IReadObjectContext * context, const std::string &name, const std::vector<sint32> &range)
|
||||
{
|
||||
std::vector<rct_g1_element> result;
|
||||
auto objectPath = FindLegacyObject(name);
|
||||
auto obj = ObjectFactory::CreateObjectFromLegacyFile(objectPath.c_str());
|
||||
if (obj != nullptr)
|
||||
{
|
||||
auto &imgTable = static_cast<const Object *>(obj)->GetImageTable();
|
||||
auto numImages = (sint32)imgTable.GetCount();
|
||||
auto images = imgTable.GetImages();
|
||||
size_t placeHoldersAdded = 0;
|
||||
for (auto i : range)
|
||||
{
|
||||
if (i >= 0 && i < numImages)
|
||||
{
|
||||
auto &objg1 = images[i];
|
||||
auto length = g1_calculate_data_size(&objg1);
|
||||
auto g1 = objg1;
|
||||
g1.offset = (uint8 *)std::malloc(length);
|
||||
std::memcpy(g1.offset, objg1.offset, length);
|
||||
result.push_back(g1);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto g1 = rct_g1_element{};
|
||||
result.push_back(g1);
|
||||
placeHoldersAdded++;
|
||||
}
|
||||
}
|
||||
delete obj;
|
||||
|
||||
// Log place holder information
|
||||
if (placeHoldersAdded > 0)
|
||||
{
|
||||
std::string msg = "Adding " + std::to_string(placeHoldersAdded) + " placeholders";
|
||||
context->LogWarning(OBJECT_ERROR_INVALID_PROPERTY, msg.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string msg = "Unable to open '" + objectPath + "'";
|
||||
context->LogWarning(OBJECT_ERROR_INVALID_PROPERTY, msg.c_str());
|
||||
result.resize(range.size());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::vector<rct_g1_element> ParseImages(IReadObjectContext * context, std::string s)
|
||||
{
|
||||
std::vector<rct_g1_element> result;
|
||||
if (s.empty())
|
||||
{
|
||||
rct_g1_element emptyg1 = { 0 };
|
||||
result.push_back(emptyg1);
|
||||
}
|
||||
else if (String::StartsWith(s, "$CSG"))
|
||||
{
|
||||
if (is_csg_loaded())
|
||||
{
|
||||
auto range = ParseRange(s.substr(4));
|
||||
if (range.size() > 0)
|
||||
{
|
||||
for (auto i : range)
|
||||
{
|
||||
auto &csg1 = *gfx_get_g1_element(SPR_CSG_BEGIN + i);
|
||||
auto length = g1_calculate_data_size(&csg1);
|
||||
auto g1 = csg1;
|
||||
g1.offset = (uint8 *)std::malloc(length);
|
||||
std::memcpy(g1.offset, csg1.offset, length);
|
||||
result.push_back(g1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (String::StartsWith(s, "$RCT2:OBJDATA/"))
|
||||
{
|
||||
auto name = s.substr(14);
|
||||
auto rangeStart = name.find('[');
|
||||
if (rangeStart != std::string::npos)
|
||||
{
|
||||
auto rangeString = name.substr(rangeStart);
|
||||
auto range = ParseRange(name.substr(rangeStart));
|
||||
name = name.substr(0, rangeStart);
|
||||
result = LoadObjectImages(context, name, range);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint8 ParseStringId(const std::string &s)
|
||||
{
|
||||
if (s == "name") return OBJ_STRING_ID_NAME;
|
||||
if (s == "description") return OBJ_STRING_ID_DESCRIPTION;
|
||||
if (s == "capacity") return OBJ_STRING_ID_CAPACITY;
|
||||
if (s == "vehicleName") return OBJ_STRING_ID_VEHICLE_NAME;
|
||||
return OBJ_STRING_ID_UNKNOWN;
|
||||
}
|
||||
|
||||
void LoadStrings(const json_t * root, StringTable &stringTable)
|
||||
{
|
||||
auto jsonStrings = json_object_get(root, "strings");
|
||||
const char * key;
|
||||
json_t * jlanguages;
|
||||
json_object_foreach(jsonStrings, key, jlanguages)
|
||||
{
|
||||
auto stringId = ParseStringId(key);
|
||||
if (stringId != OBJ_STRING_ID_UNKNOWN)
|
||||
{
|
||||
const char * locale;
|
||||
json_t * jstring;
|
||||
json_object_foreach(jlanguages, locale, jstring)
|
||||
{
|
||||
auto langId = language_get_id_from_locale(locale);
|
||||
if (langId != LANGUAGE_UNDEFINED)
|
||||
{
|
||||
auto string = json_string_value(jstring);
|
||||
stringTable.SetString(stringId, langId, string);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stringTable.Sort();
|
||||
}
|
||||
|
||||
void LoadImages(IReadObjectContext * context, const json_t * root, ImageTable &imageTable)
|
||||
{
|
||||
if (context->ShouldLoadImages())
|
||||
{
|
||||
auto jsonImages = json_object_get(root, "images");
|
||||
auto imageElements = GetJsonStringArray(jsonImages);
|
||||
for (const auto &ie : imageElements)
|
||||
{
|
||||
auto images = ParseImages(context, ie);
|
||||
for (const auto &g1 : images)
|
||||
{
|
||||
imageTable.AddImage(&g1);
|
||||
std::free(g1.offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#pragma region Copyright (c) 2014-2018 OpenRCT2 Developers
|
||||
/*****************************************************************************
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* A full copy of the GNU General Public License can be found in licence.txt
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../common.h"
|
||||
#include "../core/Json.hpp"
|
||||
#include "../drawing/Drawing.h"
|
||||
#include "../object/Object.h"
|
||||
#include "ImageTable.h"
|
||||
#include "StringTable.h"
|
||||
|
||||
namespace ObjectJsonHelpers
|
||||
{
|
||||
bool GetBoolean(const json_t * obj, const std::string &name, bool defaultValue = false);
|
||||
std::string GetString(const json_t * value);
|
||||
std::string GetString(const json_t * obj, const std::string &name, const std::string &defaultValue = "");
|
||||
sint32 GetInteger(const json_t * obj, const std::string &name, const sint32 &defaultValue = 0);
|
||||
float GetFloat(const json_t * obj, const std::string &name, const float &defaultValue = 0);
|
||||
std::vector<std::string> GetJsonStringArray(const json_t * arr);
|
||||
std::vector<sint32> GetJsonIntegerArray(const json_t * arr);
|
||||
uint8 ParseCursor(const std::string &s, uint8 defaultValue);
|
||||
rct_object_entry ParseObjectEntry(const std::string & s);
|
||||
void LoadStrings(const json_t * root, StringTable &stringTable);
|
||||
void LoadImages(IReadObjectContext * context, const json_t * root, ImageTable &imageTable);
|
||||
|
||||
template<typename T>
|
||||
static T GetFlags(const json_t * obj, std::initializer_list<std::pair<std::string, T>> list)
|
||||
{
|
||||
T flags = 0;
|
||||
for (const auto &item : list)
|
||||
{
|
||||
if (GetBoolean(obj, item.first))
|
||||
{
|
||||
flags |= item.second;
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
};
|
|
@ -80,7 +80,7 @@ class ObjectFileIndex final : public FileIndex<ObjectRepositoryItem>
|
|||
private:
|
||||
static constexpr uint32 MAGIC_NUMBER = 0x5844494F; // OIDX
|
||||
static constexpr uint16 VERSION = 17;
|
||||
static constexpr auto PATTERN = "*.dat;*.pob";
|
||||
static constexpr auto PATTERN = "*.dat;*.pob;*.json";
|
||||
|
||||
public:
|
||||
explicit ObjectFileIndex(IPlatformEnvironment * env) :
|
||||
|
@ -90,7 +90,7 @@ public:
|
|||
env->GetFilePath(PATHID::CACHE_OBJECTS),
|
||||
std::string(PATTERN),
|
||||
std::vector<std::string>({
|
||||
env->GetDirectoryPath(DIRBASE::RCT2, DIRID::OBJECT),
|
||||
env->GetDirectoryPath(DIRBASE::OPENRCT2, DIRID::OBJECT),
|
||||
env->GetDirectoryPath(DIRBASE::USER, DIRID::OBJECT) }))
|
||||
{
|
||||
}
|
||||
|
@ -98,21 +98,36 @@ public:
|
|||
public:
|
||||
std::tuple<bool, ObjectRepositoryItem> Create(const std::string &path) const override
|
||||
{
|
||||
auto object = ObjectFactory::CreateObjectFromLegacyFile(path.c_str());
|
||||
if (object != nullptr)
|
||||
auto extension = Path::GetExtension(path);
|
||||
if (String::Equals(extension, ".json", true))
|
||||
{
|
||||
ObjectRepositoryItem item = { 0 };
|
||||
item.ObjectEntry = *object->GetObjectEntry();
|
||||
item.Path = String::Duplicate(path);
|
||||
item.Name = String::Duplicate(object->GetName());
|
||||
object->SetRepositoryItem(&item);
|
||||
delete object;
|
||||
return std::make_tuple(true, item);
|
||||
auto object = ObjectFactory::CreateObjectFromJsonFile(path);
|
||||
if (object != nullptr)
|
||||
{
|
||||
ObjectRepositoryItem item = { 0 };
|
||||
item.ObjectEntry = *object->GetObjectEntry();
|
||||
item.Path = String::Duplicate(path);
|
||||
item.Name = String::Duplicate(object->GetName());
|
||||
object->SetRepositoryItem(&item);
|
||||
delete object;
|
||||
return std::make_tuple(true, item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::make_tuple(false, ObjectRepositoryItem());
|
||||
auto object = ObjectFactory::CreateObjectFromLegacyFile(path.c_str());
|
||||
if (object != nullptr)
|
||||
{
|
||||
ObjectRepositoryItem item = { 0 };
|
||||
item.ObjectEntry = *object->GetObjectEntry();
|
||||
item.Path = String::Duplicate(path);
|
||||
item.Name = String::Duplicate(object->GetName());
|
||||
object->SetRepositoryItem(&item);
|
||||
delete object;
|
||||
return std::make_tuple(true, item);
|
||||
}
|
||||
}
|
||||
return std::make_tuple(false, ObjectRepositoryItem());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -260,8 +275,15 @@ public:
|
|||
{
|
||||
Guard::ArgumentNotNull(ori, GUARD_LINE);
|
||||
|
||||
Object * object = ObjectFactory::CreateObjectFromLegacyFile(ori->Path);
|
||||
return object;
|
||||
auto extension = Path::GetExtension(ori->Path);
|
||||
if (String::Equals(extension, ".json", true))
|
||||
{
|
||||
return ObjectFactory::CreateObjectFromJsonFile(ori->Path);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ObjectFactory::CreateObjectFromLegacyFile(ori->Path);
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterLoadedObject(const ObjectRepositoryItem * ori, Object * object) override
|
||||
|
|
|
@ -14,27 +14,27 @@
|
|||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#pragma warning(disable : 4706) // assignment within conditional expression
|
||||
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include "../core/IStream.hpp"
|
||||
#include "../core/Math.hpp"
|
||||
#include "../core/Memory.hpp"
|
||||
#include "../core/String.hpp"
|
||||
#include "../OpenRCT2.h"
|
||||
#include "ObjectRepository.h"
|
||||
#include "RideObject.h"
|
||||
#include "../core/Util.hpp"
|
||||
#include "../ride/RideGroupManager.h"
|
||||
|
||||
#include "../drawing/Drawing.h"
|
||||
#include "../localisation/Language.h"
|
||||
#include "../rct2/RCT2.h"
|
||||
#include "../ride/Ride.h"
|
||||
#include "../ride/Track.h"
|
||||
#include "../OpenRCT2.h"
|
||||
#include "ObjectJsonHelpers.h"
|
||||
#include "ObjectRepository.h"
|
||||
#include "RideObject.h"
|
||||
|
||||
RideObject::~RideObject()
|
||||
{
|
||||
for (auto &peepLoadingPosition : _peepLoadingPositions)
|
||||
{
|
||||
Memory::Free(peepLoadingPosition);
|
||||
}
|
||||
}
|
||||
using namespace OpenRCT2;
|
||||
|
||||
void RideObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
||||
{
|
||||
|
@ -70,9 +70,9 @@ void RideObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
|||
_legacyType.shop_item = stream->ReadValue<uint8>();
|
||||
_legacyType.shop_item_secondary = stream->ReadValue<uint8>();
|
||||
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_DESCRIPTION);
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_CAPACITY);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_DESCRIPTION);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_CAPACITY);
|
||||
|
||||
// Read preset colours, by default there are 32
|
||||
_presetColours.count = stream->ReadValue<uint8>();
|
||||
|
@ -98,11 +98,13 @@ void RideObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
|||
{
|
||||
numPeepLoadingPositions = stream->ReadValue<uint16>();
|
||||
}
|
||||
_peepLoadingPositions[i] = stream->ReadArray<sint8>(numPeepLoadingPositions);
|
||||
_peepLoadingPositionsCount[i] = numPeepLoadingPositions;
|
||||
|
||||
auto data = stream->ReadArray<sint8>(numPeepLoadingPositions);
|
||||
_peepLoadingPositions[i] = std::vector<sint8>(data, data + numPeepLoadingPositions);
|
||||
Memory::Free(data);
|
||||
}
|
||||
|
||||
GetImageTable()->Read(context, stream);
|
||||
GetImageTable().Read(context, stream);
|
||||
|
||||
// Validate properties
|
||||
if (_legacyType.excitement_multiplier > 75)
|
||||
|
@ -117,17 +119,17 @@ void RideObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
|||
{
|
||||
context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Nausea multiplier too high.");
|
||||
}
|
||||
|
||||
PerformFixes();
|
||||
}
|
||||
|
||||
void RideObject::Load()
|
||||
{
|
||||
GetStringTable()->Sort();
|
||||
_legacyType.obj = this;
|
||||
|
||||
GetStringTable().Sort();
|
||||
_legacyType.naming.name = language_allocate_object_string(GetName());
|
||||
_legacyType.naming.description = language_allocate_object_string(GetDescription());
|
||||
_legacyType.capacity = language_allocate_object_string(GetCapacity());
|
||||
_legacyType.images_offset = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount());
|
||||
_legacyType.images_offset = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount());
|
||||
_legacyType.vehicle_preset_list = &_presetColours;
|
||||
|
||||
sint32 cur_vehicle_images_offset = _legacyType.images_offset + MAX_RIDE_TYPES_PER_RIDE_ENTRY;
|
||||
|
@ -281,8 +283,11 @@ void RideObject::Load()
|
|||
set_vehicle_type_image_max_sizes(vehicleEntry, num_images);
|
||||
}
|
||||
}
|
||||
vehicleEntry->peep_loading_positions = _peepLoadingPositions[i];
|
||||
vehicleEntry->peep_loading_positions_count = _peepLoadingPositionsCount[i];
|
||||
|
||||
if (!_peepLoadingPositions[i].empty())
|
||||
{
|
||||
vehicleEntry->peep_loading_positions = std::move(_peepLoadingPositions[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -292,7 +297,7 @@ void RideObject::Unload()
|
|||
language_free_object_string(_legacyType.naming.name);
|
||||
language_free_object_string(_legacyType.naming.description);
|
||||
language_free_object_string(_legacyType.capacity);
|
||||
gfx_object_free_images(_legacyType.images_offset, GetImageTable()->GetCount());
|
||||
gfx_object_free_images(_legacyType.images_offset, GetImageTable().GetCount());
|
||||
|
||||
_legacyType.naming.name = 0;
|
||||
_legacyType.naming.description = 0;
|
||||
|
@ -371,8 +376,7 @@ void RideObject::SetRepositoryItem(ObjectRepositoryItem * item) const
|
|||
void RideObject::ReadLegacyVehicle(IReadObjectContext * context, IStream * stream, rct_ride_entry_vehicle * vehicle)
|
||||
{
|
||||
vehicle->rotation_frame_mask = stream->ReadValue<uint16>();
|
||||
vehicle->num_vertical_frames = stream->ReadValue<uint8>();
|
||||
vehicle->num_horizontal_frames = stream->ReadValue<uint8>();
|
||||
stream->Seek(2 * 1, STREAM_SEEK_CURRENT);
|
||||
vehicle->spacing = stream->ReadValue<uint32>();
|
||||
vehicle->car_mass = stream->ReadValue<uint16>();
|
||||
vehicle->tab_height = stream->ReadValue<sint8>();
|
||||
|
@ -384,21 +388,7 @@ void RideObject::ReadLegacyVehicle(IReadObjectContext * context, IStream * strea
|
|||
vehicle->animation = stream->ReadValue<uint8>();
|
||||
vehicle->flags = stream->ReadValue<uint32>();
|
||||
vehicle->base_num_frames = stream->ReadValue<uint16>();
|
||||
stream->Seek(4, STREAM_SEEK_CURRENT);
|
||||
vehicle->restraint_image_id = stream->ReadValue<uint32>();
|
||||
vehicle->gentle_slope_image_id = stream->ReadValue<uint32>();
|
||||
vehicle->steep_slope_image_id = stream->ReadValue<uint32>();
|
||||
vehicle->vertical_slope_image_id = stream->ReadValue<uint32>();
|
||||
vehicle->diagonal_slope_image_id = stream->ReadValue<uint32>();
|
||||
vehicle->banked_image_id = stream->ReadValue<uint32>();
|
||||
vehicle->inline_twist_image_id = stream->ReadValue<uint32>();
|
||||
vehicle->flat_to_gentle_bank_image_id = stream->ReadValue<uint32>();
|
||||
vehicle->diagonal_to_gentle_slope_bank_image_id = stream->ReadValue<uint32>();
|
||||
vehicle->gentle_slope_to_bank_image_id = stream->ReadValue<uint32>();
|
||||
vehicle->gentle_slope_bank_turn_image_id = stream->ReadValue<uint32>();
|
||||
vehicle->flat_bank_to_gentle_slope_image_id = stream->ReadValue<uint32>();
|
||||
vehicle->corkscrew_image_id = stream->ReadValue<uint32>();
|
||||
vehicle->no_vehicle_images = stream->ReadValue<uint32>();
|
||||
stream->Seek(15 * 4, STREAM_SEEK_CURRENT);
|
||||
vehicle->no_seating_rows = stream->ReadValue<uint8>();
|
||||
vehicle->spinning_inertia = stream->ReadValue<uint8>();
|
||||
vehicle->spinning_friction = stream->ReadValue<uint8>();
|
||||
|
@ -415,54 +405,6 @@ void RideObject::ReadLegacyVehicle(IReadObjectContext * context, IStream * strea
|
|||
stream->Seek(4, STREAM_SEEK_CURRENT);
|
||||
}
|
||||
|
||||
void RideObject::PerformFixes()
|
||||
{
|
||||
std::string identifier = GetIdentifier();
|
||||
|
||||
// Add boosters if the track type is eligible
|
||||
for (auto rideType : _legacyType.ride_type)
|
||||
{
|
||||
if (ride_type_supports_boosters(rideType))
|
||||
{
|
||||
_legacyType.enabledTrackPieces |= (1ULL << TRACK_BOOSTER);
|
||||
}
|
||||
}
|
||||
|
||||
// The rocket cars could take 3 cars per train in RCT1. Restore this.
|
||||
if (String::Equals(identifier, "RCKC "))
|
||||
{
|
||||
_legacyType.max_cars_in_train = 3 + _legacyType.zero_cars;
|
||||
}
|
||||
// The Wooden Roller Coaster could take 7 cars per train in RCT1.
|
||||
else if (String::Equals(identifier, "PTCT1 "))
|
||||
{
|
||||
_legacyType.max_cars_in_train = 7 + _legacyType.zero_cars;
|
||||
}
|
||||
// The Looping Roller Coaster could take 8 cars per train in RCT1.
|
||||
else if (String::Equals(identifier, "SCHT1 "))
|
||||
{
|
||||
_legacyType.max_cars_in_train = 8 + _legacyType.zero_cars;
|
||||
}
|
||||
// The Steel Twister could take 8 cars per train in RCT1. (The other two vehicles are already correct.)
|
||||
else if (String::Equals(identifier, "BMSD ") || String::Equals(identifier, "BMSU "))
|
||||
{
|
||||
_legacyType.max_cars_in_train = 8 + _legacyType.zero_cars;
|
||||
}
|
||||
// Wacky Worlds' Crocodile Ride (a log flume vehicle) is incorrectly locked to 5 cars.
|
||||
else if (String::Equals(identifier, "CROCFLUM"))
|
||||
{
|
||||
_legacyType.cars_per_flat_ride = 0xFF;
|
||||
}
|
||||
// All vanilla/WW/OCC Junior RC vehicles incorrectly have this flag set
|
||||
else if (String::Equals(identifier, "ZLDB ") ||
|
||||
String::Equals(identifier, "ZLOG ") ||
|
||||
String::Equals(identifier, "ZPANDA ") ||
|
||||
String::Equals(identifier, "WHICGRUB"))
|
||||
{
|
||||
_legacyType.enabledTrackPieces &= ~(1ULL << TRACK_SLOPE_STEEP);
|
||||
}
|
||||
}
|
||||
|
||||
uint8 RideObject::CalculateNumVerticalFrames(const rct_ride_entry_vehicle * vehicleEntry)
|
||||
{
|
||||
// 0x6DE90B
|
||||
|
@ -532,3 +474,642 @@ uint8 RideObject::CalculateNumHorizontalFrames(const rct_ride_entry_vehicle * ve
|
|||
|
||||
return numHorizontalFrames;
|
||||
}
|
||||
|
||||
void RideObject::ReadJson(IReadObjectContext * context, const json_t * root)
|
||||
{
|
||||
auto properties = json_object_get(root, "properties");
|
||||
|
||||
auto rideTypes = ObjectJsonHelpers::GetJsonStringArray(json_object_get(properties, "type"));
|
||||
for (size_t i = 0; i < MAX_RIDE_TYPES_PER_RIDE_ENTRY; i++)
|
||||
{
|
||||
uint8 rideType = RIDE_TYPE_NULL;
|
||||
if (i < rideTypes.size())
|
||||
{
|
||||
rideType = ParseRideType(rideTypes[i]);
|
||||
if (rideType == RIDE_TYPE_NULL)
|
||||
{
|
||||
context->LogError(OBJECT_ERROR_INVALID_PROPERTY, "Unknown ride type");
|
||||
}
|
||||
}
|
||||
|
||||
_legacyType.ride_type[i] = rideType;
|
||||
}
|
||||
|
||||
auto rideCategories = ObjectJsonHelpers::GetJsonStringArray(json_object_get(properties, "category"));
|
||||
if (rideCategories.size() >= 1)
|
||||
{
|
||||
_legacyType.category[0] = ParseRideCategory(rideCategories[0]);
|
||||
_legacyType.category[1] = _legacyType.category[0];
|
||||
}
|
||||
if (rideCategories.size() >= 2)
|
||||
{
|
||||
_legacyType.category[1] = ParseRideCategory(rideCategories[1]);
|
||||
}
|
||||
|
||||
_legacyType.max_height = ObjectJsonHelpers::GetInteger(properties, "maxHeight");
|
||||
|
||||
// This needs to be set for both shops/facilities _and_ regular rides.
|
||||
_legacyType.shop_item = SHOP_ITEM_NONE;
|
||||
_legacyType.shop_item_secondary = SHOP_ITEM_NONE;
|
||||
|
||||
if (IsRideTypeShopOrFacility(_legacyType.ride_type[0]))
|
||||
{
|
||||
// Standard car info for a shop
|
||||
auto &car = _legacyType.vehicles[0];
|
||||
car.spacing = 544;
|
||||
car.sprite_flags = VEHICLE_SPRITE_FLAG_FLAT;
|
||||
car.sprite_width = 1;
|
||||
car.sprite_height_negative = 1;
|
||||
car.sprite_height_positive = 1;
|
||||
car.flags = VEHICLE_ENTRY_FLAG_SPINNING;
|
||||
car.car_visual = VEHICLE_VISUAL_FLAT_RIDE_OR_CAR_RIDE;
|
||||
car.friction_sound_id = 0xFF;
|
||||
car.sound_range = 0xFF;
|
||||
car.draw_order = 6;
|
||||
|
||||
// Shop item
|
||||
auto rideSells = ObjectJsonHelpers::GetJsonStringArray(json_object_get(json_object_get(root, "properties"), "sells"));
|
||||
for (size_t i = 0; i < rideSells.size(); i++)
|
||||
{
|
||||
auto shopItem = ParseShopItem(rideSells[i]);
|
||||
if (shopItem == SHOP_ITEM_NONE)
|
||||
{
|
||||
context->LogWarning(OBJECT_ERROR_INVALID_PROPERTY, "Unknown shop item");
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
_legacyType.shop_item = ParseShopItem(rideSells[0]);
|
||||
}
|
||||
else if (i == 1)
|
||||
{
|
||||
_legacyType.shop_item_secondary = ParseShopItem(rideSells[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// More than 2 shop items not supported yet!
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ReadJsonVehicleInfo(context, properties);
|
||||
|
||||
auto swingMode = ObjectJsonHelpers::GetInteger(properties, "swingMode");
|
||||
if (swingMode == 1)
|
||||
{
|
||||
_legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_SWING_MODE_1;
|
||||
}
|
||||
else if (swingMode == 2)
|
||||
{
|
||||
_legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_SWING_MODE_1;
|
||||
_legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_SWING_MODE_2;
|
||||
}
|
||||
|
||||
auto rotationMode = ObjectJsonHelpers::GetInteger(properties, "rotationMode");
|
||||
if (rotationMode == 1)
|
||||
{
|
||||
_legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_ROTATION_MODE_1;
|
||||
}
|
||||
else if (rotationMode == 2)
|
||||
{
|
||||
_legacyType.flags |= RIDE_ENTRY_FLAG_ALTERNATIVE_ROTATION_MODE_2;
|
||||
}
|
||||
|
||||
auto ratingMultiplier = json_object_get(properties, "ratingMultipler");
|
||||
if (ratingMultiplier != nullptr)
|
||||
{
|
||||
_legacyType.excitement_multiplier = ObjectJsonHelpers::GetInteger(ratingMultiplier, "excitement");
|
||||
_legacyType.intensity_multiplier = ObjectJsonHelpers::GetInteger(ratingMultiplier, "intensity");
|
||||
_legacyType.nausea_multiplier = ObjectJsonHelpers::GetInteger(ratingMultiplier, "nausea");
|
||||
}
|
||||
|
||||
auto availableTrackPieces = ObjectJsonHelpers::GetJsonStringArray(json_object_get(properties, "availableTrackPieces"));
|
||||
_presetColours = ReadJsonCarColours(json_object_get(properties, "carColours"));
|
||||
}
|
||||
|
||||
_legacyType.flags |= ObjectJsonHelpers::GetFlags<uint32>(properties, {
|
||||
{ "noInversions", RIDE_ENTRY_FLAG_NO_INVERSIONS },
|
||||
{ "noBanking", RIDE_ENTRY_FLAG_NO_BANKED_TRACK },
|
||||
{ "playDepartSound", RIDE_ENTRY_FLAG_PLAY_DEPART_SOUND },
|
||||
{ "RIDE_ENTRY_FLAG_7", RIDE_ENTRY_FLAG_7 },
|
||||
{ "playSplashSound", RIDE_ENTRY_FLAG_PLAY_SPLASH_SOUND },
|
||||
{ "playSplashSoundSlide", RIDE_ENTRY_FLAG_PLAY_SPLASH_SOUND_SLIDE },
|
||||
{ "hasShelter", RIDE_ENTRY_FLAG_COVERED_RIDE },
|
||||
{ "limitAirTimeBonus", RIDE_ENTRY_FLAG_LIMIT_AIRTIME_BONUS },
|
||||
{ "disableBreakdown", RIDE_ENTRY_FLAG_CANNOT_BREAK_DOWN },
|
||||
{ "RIDE_ENTRY_FLAG_16", RIDE_ENTRY_FLAG_16 },
|
||||
{ "RIDE_ENTRY_FLAG_18", RIDE_ENTRY_FLAG_18 },
|
||||
{ "disablePainting", RIDE_ENTRY_FLAG_DISABLE_COLOUR_TAB } });
|
||||
|
||||
ObjectJsonHelpers::LoadStrings(root, GetStringTable());
|
||||
ObjectJsonHelpers::LoadImages(context, root, GetImageTable());
|
||||
}
|
||||
|
||||
void RideObject::ReadJsonVehicleInfo(IReadObjectContext * context, const json_t * properties)
|
||||
{
|
||||
_legacyType.min_cars_in_train = ObjectJsonHelpers::GetInteger(properties, "minCarsPerTrain", 1);
|
||||
_legacyType.max_cars_in_train = ObjectJsonHelpers::GetInteger(properties, "maxCarsPerTrain", 1);
|
||||
_legacyType.cars_per_flat_ride = ObjectJsonHelpers::GetInteger(properties, "carsPerFlatRide", 255);
|
||||
_legacyType.zero_cars = json_integer_value(json_object_get(properties, "numEmptyCars"));
|
||||
|
||||
// Train formation from car indices
|
||||
_legacyType.default_vehicle = json_integer_value(json_object_get(properties, "defaultCar"));
|
||||
_legacyType.tab_vehicle = json_integer_value(json_object_get(properties, "tabCar"));
|
||||
auto tabScale = ObjectJsonHelpers::GetFloat(properties, "tabScale");
|
||||
if (tabScale != 0 && ObjectJsonHelpers::GetFloat(properties, "tabScale") <= 0.5f)
|
||||
{
|
||||
_legacyType.flags |= RIDE_ENTRY_FLAG_VEHICLE_TAB_SCALE_HALF;
|
||||
}
|
||||
|
||||
// 0xFF means N/A.
|
||||
_legacyType.front_vehicle = 0xFF;
|
||||
_legacyType.second_vehicle = 0xFF;
|
||||
_legacyType.third_vehicle = 0xFF;
|
||||
_legacyType.rear_vehicle = 0xFF;
|
||||
|
||||
auto headCars = ObjectJsonHelpers::GetJsonIntegerArray(json_object_get(properties, "headCars"));
|
||||
if (headCars.size() >= 1)
|
||||
{
|
||||
_legacyType.front_vehicle = headCars[0];
|
||||
}
|
||||
if (headCars.size() >= 2)
|
||||
{
|
||||
_legacyType.second_vehicle = headCars[1];
|
||||
}
|
||||
if (headCars.size() >= 3)
|
||||
{
|
||||
_legacyType.third_vehicle = headCars[2];
|
||||
}
|
||||
if (headCars.size() >= 4)
|
||||
{
|
||||
// More than 3 head cars not supported yet!
|
||||
}
|
||||
|
||||
auto tailCars = ObjectJsonHelpers::GetJsonIntegerArray(json_object_get(properties, "tailCars"));
|
||||
if (tailCars.size() >= 1)
|
||||
{
|
||||
_legacyType.rear_vehicle = tailCars[0];
|
||||
}
|
||||
if (tailCars.size() >= 2)
|
||||
{
|
||||
// More than 1 tail car not supported yet!
|
||||
}
|
||||
|
||||
auto cars = ReadJsonCars(json_object_get(properties, "cars"));
|
||||
auto numCars = std::min(Util::CountOf(_legacyType.vehicles), cars.size());
|
||||
for (size_t i = 0; i < numCars; i++)
|
||||
{
|
||||
_legacyType.vehicles[i] = cars[i];
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<rct_ride_entry_vehicle> RideObject::ReadJsonCars(const json_t * jCars)
|
||||
{
|
||||
std::vector<rct_ride_entry_vehicle> cars;
|
||||
|
||||
if (json_is_array(jCars))
|
||||
{
|
||||
json_t * jCar;
|
||||
size_t index;
|
||||
json_array_foreach(jCars, index, jCar)
|
||||
{
|
||||
auto car = ReadJsonCar(jCar);
|
||||
cars.push_back(car);
|
||||
}
|
||||
}
|
||||
else if (json_is_object(jCars))
|
||||
{
|
||||
auto car = ReadJsonCar(jCars);
|
||||
cars.push_back(car);
|
||||
}
|
||||
return cars;
|
||||
}
|
||||
|
||||
rct_ride_entry_vehicle RideObject::ReadJsonCar(const json_t * jCar)
|
||||
{
|
||||
rct_ride_entry_vehicle car = { 0 };
|
||||
car.rotation_frame_mask = ObjectJsonHelpers::GetInteger(jCar, "rotationFrameMask");
|
||||
car.spacing = ObjectJsonHelpers::GetInteger(jCar, "spacing");
|
||||
car.car_mass = ObjectJsonHelpers::GetInteger(jCar, "mass");
|
||||
car.tab_height = ObjectJsonHelpers::GetInteger(jCar, "tabOffset");
|
||||
car.num_seats = ObjectJsonHelpers::GetInteger(jCar, "numSeats");
|
||||
if (ObjectJsonHelpers::GetBoolean(jCar, "seatsInPairs"))
|
||||
{
|
||||
car.num_seats |= 0x80;
|
||||
}
|
||||
|
||||
car.sprite_width = ObjectJsonHelpers::GetInteger(jCar, "spriteWidth");
|
||||
car.sprite_height_negative = ObjectJsonHelpers::GetInteger(jCar, "spriteHeightNegative");
|
||||
car.sprite_height_positive = ObjectJsonHelpers::GetInteger(jCar, "spriteHeightPositive");
|
||||
car.animation = ObjectJsonHelpers::GetInteger(jCar, "animation");
|
||||
car.base_num_frames = ObjectJsonHelpers::GetInteger(jCar, "baseNumFrames");
|
||||
car.no_vehicle_images = ObjectJsonHelpers::GetInteger(jCar, "numImages");
|
||||
car.no_seating_rows = ObjectJsonHelpers::GetInteger(jCar, "numSeatRows");
|
||||
car.spinning_inertia = ObjectJsonHelpers::GetInteger(jCar, "spinningInertia");
|
||||
car.spinning_friction = ObjectJsonHelpers::GetInteger(jCar, "spinningFriction");
|
||||
car.friction_sound_id = ObjectJsonHelpers::GetInteger(jCar, "frictionSoundId", 255);
|
||||
car.log_flume_reverser_vehicle_type = ObjectJsonHelpers::GetInteger(jCar, "logFlumeReverserVehicleType");
|
||||
car.sound_range = ObjectJsonHelpers::GetInteger(jCar, "soundRange", 255);
|
||||
car.double_sound_frequency = ObjectJsonHelpers::GetInteger(jCar, "doubleSoundFrequency");
|
||||
car.powered_acceleration = ObjectJsonHelpers::GetInteger(jCar, "poweredAcceleration");
|
||||
car.powered_max_speed = ObjectJsonHelpers::GetInteger(jCar, "poweredMaxSpeed");
|
||||
car.car_visual = ObjectJsonHelpers::GetInteger(jCar, "carVisual");
|
||||
car.effect_visual = ObjectJsonHelpers::GetInteger(jCar, "effectVisual", 1);
|
||||
car.draw_order = ObjectJsonHelpers::GetInteger(jCar, "drawOrder");
|
||||
car.num_vertical_frames_override = ObjectJsonHelpers::GetInteger(jCar, "numVerticalFramesOverride");
|
||||
|
||||
auto& peepLoadingPositions = car.peep_loading_positions;
|
||||
auto jLoadingPositions = json_object_get(jCar, "loadingPositions");
|
||||
if (json_is_array(jLoadingPositions))
|
||||
{
|
||||
auto arr = ObjectJsonHelpers::GetJsonIntegerArray(jLoadingPositions);
|
||||
for (auto x : arr)
|
||||
{
|
||||
peepLoadingPositions.push_back(x);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto jLoadingWaypoints = json_object_get(jCar, "loadingWaypoints");
|
||||
if (json_is_array(jLoadingWaypoints))
|
||||
{
|
||||
car.flags |= VEHICLE_ENTRY_FLAG_26;
|
||||
|
||||
auto numSegments = ObjectJsonHelpers::GetInteger(jCar, "numSegments");
|
||||
if (numSegments == 8)
|
||||
{
|
||||
peepLoadingPositions.push_back(1);
|
||||
}
|
||||
else if (numSegments == 4)
|
||||
{
|
||||
peepLoadingPositions.push_back(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
peepLoadingPositions.push_back(0);
|
||||
}
|
||||
|
||||
size_t i;
|
||||
json_t * route;
|
||||
json_array_foreach(jLoadingWaypoints, i, route)
|
||||
{
|
||||
if (json_is_array(route))
|
||||
{
|
||||
size_t j;
|
||||
json_t * waypoint;
|
||||
json_array_foreach(route, j, waypoint)
|
||||
{
|
||||
if (json_is_array(waypoint) && json_array_size(waypoint) >= 2)
|
||||
{
|
||||
auto x = json_integer_value(json_array_get(waypoint, 0));
|
||||
auto y = json_integer_value(json_array_get(waypoint, 1));
|
||||
peepLoadingPositions.push_back(x);
|
||||
peepLoadingPositions.push_back(y);
|
||||
}
|
||||
}
|
||||
peepLoadingPositions.push_back(0);
|
||||
peepLoadingPositions.push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto jFrames = json_object_get(jCar, "frames");
|
||||
car.sprite_flags = ObjectJsonHelpers::GetFlags<uint16>(jFrames, {
|
||||
{ "flat", VEHICLE_SPRITE_FLAG_FLAT },
|
||||
{ "gentleSlopes", VEHICLE_SPRITE_FLAG_GENTLE_SLOPES },
|
||||
{ "steepSlopes", VEHICLE_SPRITE_FLAG_STEEP_SLOPES },
|
||||
{ "verticalSlopes", VEHICLE_SPRITE_FLAG_VERTICAL_SLOPES },
|
||||
{ "diagonalSlopes", VEHICLE_SPRITE_FLAG_DIAGONAL_SLOPES },
|
||||
{ "flatBanked", VEHICLE_SPRITE_FLAG_FLAT_BANKED },
|
||||
{ "inlineTwists", VEHICLE_SPRITE_FLAG_INLINE_TWISTS },
|
||||
{ "flatToGentleSlopeBankedTransitions", VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_BANKED_TRANSITIONS },
|
||||
{ "diagonalGentleSlopeBankedTransitions", VEHICLE_SPRITE_FLAG_DIAGONAL_GENTLE_SLOPE_BANKED_TRANSITIONS },
|
||||
{ "gentleSlopeBankedTransitions", VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TRANSITIONS },
|
||||
{ "gentleSlopeBankedTurns", VEHICLE_SPRITE_FLAG_GENTLE_SLOPE_BANKED_TURNS },
|
||||
{ "flatToGentleSlopeWhileBankedTransitions", VEHICLE_SPRITE_FLAG_FLAT_TO_GENTLE_SLOPE_WHILE_BANKED_TRANSITIONS },
|
||||
{ "corkscrews", VEHICLE_SPRITE_FLAG_CORKSCREWS },
|
||||
{ "restraintAnimation", VEHICLE_SPRITE_FLAG_RESTRAINT_ANIMATION },
|
||||
{ "curvedLiftHill", VEHICLE_SPRITE_FLAG_CURVED_LIFT_HILL },
|
||||
{ "VEHICLE_SPRITE_FLAG_15", VEHICLE_SPRITE_FLAG_15 } });
|
||||
|
||||
car.flags |= ObjectJsonHelpers::GetFlags<uint32>(jCar, {
|
||||
{ "VEHICLE_ENTRY_FLAG_POWERED_RIDE_UNRESTRICTED_GRAVITY", VEHICLE_ENTRY_FLAG_POWERED_RIDE_UNRESTRICTED_GRAVITY },
|
||||
{ "VEHICLE_ENTRY_FLAG_NO_UPSTOP_WHEELS", VEHICLE_ENTRY_FLAG_NO_UPSTOP_WHEELS },
|
||||
{ "VEHICLE_ENTRY_FLAG_NO_UPSTOP_BOBSLEIGH", VEHICLE_ENTRY_FLAG_NO_UPSTOP_BOBSLEIGH },
|
||||
{ "VEHICLE_ENTRY_FLAG_MINI_GOLF", VEHICLE_ENTRY_FLAG_MINI_GOLF },
|
||||
{ "VEHICLE_ENTRY_FLAG_4", VEHICLE_ENTRY_FLAG_4 },
|
||||
{ "VEHICLE_ENTRY_FLAG_5", VEHICLE_ENTRY_FLAG_5 },
|
||||
{ "VEHICLE_ENTRY_FLAG_HAS_INVERTED_SPRITE_SET", VEHICLE_ENTRY_FLAG_HAS_INVERTED_SPRITE_SET },
|
||||
{ "VEHICLE_ENTRY_FLAG_DODGEM_INUSE_LIGHTS", VEHICLE_ENTRY_FLAG_DODGEM_INUSE_LIGHTS },
|
||||
{ "VEHICLE_ENTRY_FLAG_ALLOW_DOORS_DEPRECATED", VEHICLE_ENTRY_FLAG_ALLOW_DOORS_DEPRECATED },
|
||||
{ "VEHICLE_ENTRY_FLAG_ENABLE_ADDITIONAL_COLOUR_2", VEHICLE_ENTRY_FLAG_ENABLE_ADDITIONAL_COLOUR_2 },
|
||||
{ "VEHICLE_ENTRY_FLAG_10", VEHICLE_ENTRY_FLAG_10 },
|
||||
{ "VEHICLE_ENTRY_FLAG_11", VEHICLE_ENTRY_FLAG_11 },
|
||||
{ "VEHICLE_ENTRY_FLAG_OVERRIDE_NUM_VERTICAL_FRAMES", VEHICLE_ENTRY_FLAG_OVERRIDE_NUM_VERTICAL_FRAMES },
|
||||
{ "VEHICLE_ENTRY_FLAG_13", VEHICLE_ENTRY_FLAG_13 },
|
||||
{ "VEHICLE_ENTRY_FLAG_SPINNING_ADDITIONAL_FRAMES", VEHICLE_ENTRY_FLAG_SPINNING_ADDITIONAL_FRAMES },
|
||||
{ "VEHICLE_ENTRY_FLAG_15", VEHICLE_ENTRY_FLAG_15 },
|
||||
{ "VEHICLE_ENTRY_FLAG_ENABLE_ADDITIONAL_COLOUR_1", VEHICLE_ENTRY_FLAG_ENABLE_ADDITIONAL_COLOUR_1 },
|
||||
{ "VEHICLE_ENTRY_FLAG_SWINGING", VEHICLE_ENTRY_FLAG_SWINGING },
|
||||
{ "VEHICLE_ENTRY_FLAG_SPINNING", VEHICLE_ENTRY_FLAG_SPINNING },
|
||||
{ "VEHICLE_ENTRY_FLAG_POWERED", VEHICLE_ENTRY_FLAG_POWERED },
|
||||
{ "VEHICLE_ENTRY_FLAG_RIDERS_SCREAM", VEHICLE_ENTRY_FLAG_RIDERS_SCREAM },
|
||||
{ "VEHICLE_ENTRY_FLAG_21", VEHICLE_ENTRY_FLAG_21 },
|
||||
{ "VEHICLE_ENTRY_FLAG_BOAT_HIRE_COLLISION_DETECTION", VEHICLE_ENTRY_FLAG_BOAT_HIRE_COLLISION_DETECTION },
|
||||
{ "VEHICLE_ENTRY_FLAG_VEHICLE_ANIMATION", VEHICLE_ENTRY_FLAG_VEHICLE_ANIMATION },
|
||||
{ "VEHICLE_ENTRY_FLAG_RIDER_ANIMATION", VEHICLE_ENTRY_FLAG_RIDER_ANIMATION },
|
||||
{ "VEHICLE_ENTRY_FLAG_25", VEHICLE_ENTRY_FLAG_25 },
|
||||
{ "VEHICLE_ENTRY_FLAG_SLIDE_SWING", VEHICLE_ENTRY_FLAG_SLIDE_SWING },
|
||||
{ "VEHICLE_ENTRY_FLAG_CHAIRLIFT", VEHICLE_ENTRY_FLAG_CHAIRLIFT },
|
||||
{ "VEHICLE_ENTRY_FLAG_WATER_RIDE", VEHICLE_ENTRY_FLAG_WATER_RIDE },
|
||||
{ "VEHICLE_ENTRY_FLAG_GO_KART", VEHICLE_ENTRY_FLAG_GO_KART },
|
||||
{ "VEHICLE_ENTRY_FLAG_DODGEM_CAR_PLACEMENT", VEHICLE_ENTRY_FLAG_DODGEM_CAR_PLACEMENT } });
|
||||
return car;
|
||||
}
|
||||
|
||||
vehicle_colour_preset_list RideObject::ReadJsonCarColours(const json_t * jCarColours)
|
||||
{
|
||||
// The JSON supports multiple configurations of per car colours, but
|
||||
// the ride entry structure currently doesn't allow for it. Assume that
|
||||
// a single configuration with multiple colour entries is per car scheme.
|
||||
if (json_array_size(jCarColours) == 1)
|
||||
{
|
||||
auto firstElement = json_array_get(jCarColours, 0);
|
||||
auto numColours = json_array_size(firstElement);
|
||||
if (numColours >= 2)
|
||||
{
|
||||
// Read all colours from first config
|
||||
auto config = ReadJsonColourConfiguration(firstElement);
|
||||
vehicle_colour_preset_list list = { 0 };
|
||||
list.count = 255;
|
||||
std::copy_n(config.data(), std::min<size_t>(numColours, 32), list.list);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
// Read first colour for each config
|
||||
vehicle_colour_preset_list list = { 0 };
|
||||
size_t index;
|
||||
const json_t * jConfiguration;
|
||||
json_array_foreach(jCarColours, index, jConfiguration)
|
||||
{
|
||||
auto config = ReadJsonColourConfiguration(jConfiguration);
|
||||
if (config.size() >= 1)
|
||||
{
|
||||
list.list[index] = config[0];
|
||||
list.count++;
|
||||
|
||||
if (list.count == 254)
|
||||
{
|
||||
// Reached maximum number of configurations
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
std::vector<vehicle_colour> RideObject::ReadJsonColourConfiguration(const json_t * jColourConfig)
|
||||
{
|
||||
std::vector<vehicle_colour> config;
|
||||
size_t index;
|
||||
const json_t * jColours;
|
||||
json_array_foreach(jColourConfig, index, jColours)
|
||||
{
|
||||
vehicle_colour carColour = { 0 };
|
||||
auto colours = ObjectJsonHelpers::GetJsonStringArray(jColours);
|
||||
if (colours.size() >= 1)
|
||||
{
|
||||
carColour.main = ParseColour(colours[0]);
|
||||
carColour.additional_1 = carColour.main;
|
||||
carColour.additional_2 = carColour.main;
|
||||
if (colours.size() >= 2)
|
||||
{
|
||||
carColour.additional_1 = ParseColour(colours[1]);
|
||||
}
|
||||
if (colours.size() >= 3)
|
||||
{
|
||||
carColour.additional_2 = ParseColour(colours[2]);
|
||||
}
|
||||
}
|
||||
config.push_back(carColour);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
bool RideObject::IsRideTypeShopOrFacility(uint8 rideType)
|
||||
{
|
||||
switch (rideType)
|
||||
{
|
||||
case RIDE_TYPE_TOILETS:
|
||||
case RIDE_TYPE_SHOP:
|
||||
case RIDE_TYPE_DRINK_STALL:
|
||||
case RIDE_TYPE_FOOD_STALL:
|
||||
case RIDE_TYPE_INFORMATION_KIOSK:
|
||||
case RIDE_TYPE_CASH_MACHINE:
|
||||
case RIDE_TYPE_FIRST_AID:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 RideObject::ParseRideType(const std::string &s)
|
||||
{
|
||||
static const std::unordered_map<std::string, uint8> LookupTable
|
||||
{
|
||||
{ "spiral_rc", RIDE_TYPE_SPIRAL_ROLLER_COASTER },
|
||||
{ "stand_up_rc", RIDE_TYPE_STAND_UP_ROLLER_COASTER },
|
||||
{ "suspended_swinging_rc", RIDE_TYPE_SUSPENDED_SWINGING_COASTER },
|
||||
{ "inverted_rc", RIDE_TYPE_INVERTED_ROLLER_COASTER },
|
||||
{ "junior_rc", RIDE_TYPE_JUNIOR_ROLLER_COASTER },
|
||||
{ "miniature_railway", RIDE_TYPE_MINIATURE_RAILWAY },
|
||||
{ "monorail", RIDE_TYPE_MONORAIL },
|
||||
{ "mini_suspended_rc", RIDE_TYPE_MINI_SUSPENDED_COASTER },
|
||||
{ "boat_hire", RIDE_TYPE_BOAT_HIRE },
|
||||
{ "wooden_wild_mouse", RIDE_TYPE_WOODEN_WILD_MOUSE },
|
||||
{ "steeplechase", RIDE_TYPE_STEEPLECHASE },
|
||||
{ "car_ride", RIDE_TYPE_CAR_RIDE },
|
||||
{ "launched_freefall", RIDE_TYPE_LAUNCHED_FREEFALL },
|
||||
{ "bobsleigh_rc", RIDE_TYPE_BOBSLEIGH_COASTER },
|
||||
{ "observation_tower", RIDE_TYPE_OBSERVATION_TOWER },
|
||||
{ "looping_rc", RIDE_TYPE_LOOPING_ROLLER_COASTER },
|
||||
{ "dinghy_slide", RIDE_TYPE_DINGHY_SLIDE },
|
||||
{ "mine_train_rc", RIDE_TYPE_MINE_TRAIN_COASTER },
|
||||
{ "chairlift", RIDE_TYPE_CHAIRLIFT },
|
||||
{ "corkscrew_rc", RIDE_TYPE_CORKSCREW_ROLLER_COASTER },
|
||||
{ "maze", RIDE_TYPE_MAZE },
|
||||
{ "spiral_slide", RIDE_TYPE_SPIRAL_SLIDE },
|
||||
{ "go_karts", RIDE_TYPE_GO_KARTS },
|
||||
{ "log_flume", RIDE_TYPE_LOG_FLUME },
|
||||
{ "river_rapids", RIDE_TYPE_RIVER_RAPIDS },
|
||||
{ "dodgems", RIDE_TYPE_DODGEMS },
|
||||
{ "swinging_ship", RIDE_TYPE_SWINGING_SHIP },
|
||||
{ "swinging_inverter_ship", RIDE_TYPE_SWINGING_INVERTER_SHIP },
|
||||
{ "food_stall", RIDE_TYPE_FOOD_STALL },
|
||||
{ "drink_stall", RIDE_TYPE_DRINK_STALL },
|
||||
{ "shop", RIDE_TYPE_SHOP },
|
||||
{ "merry_go_round", RIDE_TYPE_MERRY_GO_ROUND },
|
||||
{ "information_kiosk", RIDE_TYPE_INFORMATION_KIOSK },
|
||||
{ "toilets", RIDE_TYPE_TOILETS },
|
||||
{ "ferris_wheel", RIDE_TYPE_FERRIS_WHEEL },
|
||||
{ "motion_simulator", RIDE_TYPE_MOTION_SIMULATOR },
|
||||
{ "3d_cinema", RIDE_TYPE_3D_CINEMA },
|
||||
{ "top_spin", RIDE_TYPE_TOP_SPIN },
|
||||
{ "space_rings", RIDE_TYPE_SPACE_RINGS },
|
||||
{ "reverse_freefall_rc", RIDE_TYPE_REVERSE_FREEFALL_COASTER },
|
||||
{ "lift", RIDE_TYPE_LIFT },
|
||||
{ "vertical_drop_rc", RIDE_TYPE_VERTICAL_DROP_ROLLER_COASTER },
|
||||
{ "cash_machine", RIDE_TYPE_CASH_MACHINE },
|
||||
{ "twist", RIDE_TYPE_TWIST },
|
||||
{ "haunted_house", RIDE_TYPE_HAUNTED_HOUSE },
|
||||
{ "first_aid", RIDE_TYPE_FIRST_AID },
|
||||
{ "circus", RIDE_TYPE_CIRCUS },
|
||||
{ "ghost_train", RIDE_TYPE_GHOST_TRAIN },
|
||||
{ "twister_rc", RIDE_TYPE_TWISTER_ROLLER_COASTER },
|
||||
{ "wooden_rc", RIDE_TYPE_WOODEN_ROLLER_COASTER },
|
||||
{ "side_friction_rc", RIDE_TYPE_SIDE_FRICTION_ROLLER_COASTER },
|
||||
{ "steel_wild_mouse", RIDE_TYPE_STEEL_WILD_MOUSE },
|
||||
{ "multi_dimension_rc", RIDE_TYPE_MULTI_DIMENSION_ROLLER_COASTER },
|
||||
{ "flying_rc", RIDE_TYPE_FLYING_ROLLER_COASTER },
|
||||
{ "virginia_reel", RIDE_TYPE_VIRGINIA_REEL },
|
||||
{ "splash_boats", RIDE_TYPE_SPLASH_BOATS },
|
||||
{ "mini_helicopters", RIDE_TYPE_MINI_HELICOPTERS },
|
||||
{ "lay_down_rc", RIDE_TYPE_LAY_DOWN_ROLLER_COASTER },
|
||||
{ "suspended_monorail", RIDE_TYPE_SUSPENDED_MONORAIL },
|
||||
{ "reverser_rc", RIDE_TYPE_REVERSER_ROLLER_COASTER },
|
||||
{ "heartline_twister_rc", RIDE_TYPE_HEARTLINE_TWISTER_COASTER },
|
||||
{ "mini_golf", RIDE_TYPE_MINI_GOLF },
|
||||
{ "giga_rc", RIDE_TYPE_GIGA_COASTER },
|
||||
{ "roto_drop", RIDE_TYPE_ROTO_DROP },
|
||||
{ "flying_saucers", RIDE_TYPE_FLYING_SAUCERS },
|
||||
{ "crooked_house", RIDE_TYPE_CROOKED_HOUSE },
|
||||
{ "monorail_cycles", RIDE_TYPE_MONORAIL_CYCLES },
|
||||
{ "compact_inverted_rc", RIDE_TYPE_COMPACT_INVERTED_COASTER },
|
||||
{ "water_coaster", RIDE_TYPE_WATER_COASTER },
|
||||
{ "air_powered_vertical_rc", RIDE_TYPE_AIR_POWERED_VERTICAL_COASTER },
|
||||
{ "inverted_hairpin_rc", RIDE_TYPE_INVERTED_HAIRPIN_COASTER },
|
||||
{ "magic_carpet", RIDE_TYPE_MAGIC_CARPET },
|
||||
{ "submarine_ride", RIDE_TYPE_SUBMARINE_RIDE },
|
||||
{ "river_rafts", RIDE_TYPE_RIVER_RAFTS },
|
||||
{ "enterprise", RIDE_TYPE_ENTERPRISE },
|
||||
{ "inverted_impulse_rc", RIDE_TYPE_INVERTED_IMPULSE_COASTER },
|
||||
{ "mini_rc", RIDE_TYPE_MINI_ROLLER_COASTER },
|
||||
{ "mine_ride", RIDE_TYPE_MINE_RIDE },
|
||||
{ "lim_launched_rc", RIDE_TYPE_LIM_LAUNCHED_ROLLER_COASTER },
|
||||
};
|
||||
auto result = LookupTable.find(s);
|
||||
return (result != LookupTable.end()) ?
|
||||
result->second :
|
||||
RIDE_TYPE_NULL;
|
||||
}
|
||||
|
||||
uint8 RideObject::ParseRideCategory(const std::string &s)
|
||||
{
|
||||
static const std::unordered_map<std::string, uint8> LookupTable
|
||||
{
|
||||
{ "transport", RIDE_CATEGORY_TRANSPORT },
|
||||
{ "gentle", RIDE_CATEGORY_GENTLE },
|
||||
{ "rollercoaster", RIDE_CATEGORY_ROLLERCOASTER },
|
||||
{ "thrill", RIDE_CATEGORY_THRILL },
|
||||
{ "water", RIDE_CATEGORY_WATER },
|
||||
{ "stall", RIDE_CATEGORY_SHOP },
|
||||
};
|
||||
auto result = LookupTable.find(s);
|
||||
return (result != LookupTable.end()) ?
|
||||
result->second :
|
||||
RIDE_CATEGORY_TRANSPORT;
|
||||
}
|
||||
|
||||
uint8 RideObject::ParseShopItem(const std::string &s)
|
||||
{
|
||||
static const std::unordered_map<std::string, uint8> LookupTable
|
||||
{
|
||||
{ "burger", SHOP_ITEM_BURGER },
|
||||
{ "chips", SHOP_ITEM_CHIPS },
|
||||
{ "ice_cream", SHOP_ITEM_ICE_CREAM },
|
||||
{ "candyfloss", SHOP_ITEM_CANDYFLOSS },
|
||||
{ "pizza", SHOP_ITEM_PIZZA },
|
||||
{ "popcorn", SHOP_ITEM_POPCORN },
|
||||
{ "hot_dog", SHOP_ITEM_HOT_DOG },
|
||||
{ "tentacle", SHOP_ITEM_TENTACLE },
|
||||
{ "toffee_apple", SHOP_ITEM_TOFFEE_APPLE },
|
||||
{ "doughnut", SHOP_ITEM_DOUGHNUT },
|
||||
{ "chicken", SHOP_ITEM_CHICKEN },
|
||||
{ "pretzel", SHOP_ITEM_PRETZEL },
|
||||
{ "funnel_cake", SHOP_ITEM_FUNNEL_CAKE },
|
||||
{ "beef_noodles", SHOP_ITEM_BEEF_NOODLES },
|
||||
{ "fried_rice_noodles", SHOP_ITEM_FRIED_RICE_NOODLES },
|
||||
{ "wonton_soup", SHOP_ITEM_WONTON_SOUP },
|
||||
{ "meatball_soup", SHOP_ITEM_MEATBALL_SOUP },
|
||||
{ "sub_sandwich", SHOP_ITEM_SUB_SANDWICH },
|
||||
{ "cookie", SHOP_ITEM_COOKIE },
|
||||
{ "roast_sausage", SHOP_ITEM_ROAST_SAUSAGE },
|
||||
{ "drink", SHOP_ITEM_DRINK },
|
||||
{ "coffee", SHOP_ITEM_COFFEE },
|
||||
{ "lemonade", SHOP_ITEM_LEMONADE },
|
||||
{ "chocolate", SHOP_ITEM_CHOCOLATE },
|
||||
{ "iced_tea", SHOP_ITEM_ICED_TEA },
|
||||
{ "fruit_juice", SHOP_ITEM_FRUIT_JUICE },
|
||||
{ "soybean_milk", SHOP_ITEM_SOYBEAN_MILK },
|
||||
{ "sujeonggwa", SHOP_ITEM_SUJEONGGWA },
|
||||
{ "balloon", SHOP_ITEM_BALLOON },
|
||||
{ "toy", SHOP_ITEM_TOY },
|
||||
{ "map", SHOP_ITEM_MAP },
|
||||
{ "photo", SHOP_ITEM_PHOTO },
|
||||
{ "umbrella", SHOP_ITEM_UMBRELLA },
|
||||
{ "voucher", SHOP_ITEM_VOUCHER },
|
||||
{ "hat", SHOP_ITEM_HAT },
|
||||
{ "tshirt", SHOP_ITEM_TSHIRT },
|
||||
{ "sunglasses", SHOP_ITEM_SUNGLASSES },
|
||||
};
|
||||
auto result = LookupTable.find(s);
|
||||
return (result != LookupTable.end()) ?
|
||||
result->second :
|
||||
SHOP_ITEM_NONE;
|
||||
}
|
||||
|
||||
colour_t RideObject::ParseColour(const std::string &s)
|
||||
{
|
||||
static const std::unordered_map<std::string, colour_t> LookupTable
|
||||
{
|
||||
{ "black", COLOUR_BLACK },
|
||||
{ "grey", COLOUR_GREY },
|
||||
{ "white", COLOUR_WHITE },
|
||||
{ "dark_purple", COLOUR_DARK_PURPLE },
|
||||
{ "light_purple", COLOUR_LIGHT_PURPLE },
|
||||
{ "bright_purple", COLOUR_BRIGHT_PURPLE },
|
||||
{ "dark_blue", COLOUR_DARK_BLUE },
|
||||
{ "light_blue", COLOUR_LIGHT_BLUE },
|
||||
{ "icy_blue", COLOUR_ICY_BLUE },
|
||||
{ "teal", COLOUR_TEAL },
|
||||
{ "aquamarine", COLOUR_AQUAMARINE },
|
||||
{ "saturated_green", COLOUR_SATURATED_GREEN },
|
||||
{ "dark_green", COLOUR_DARK_GREEN },
|
||||
{ "moss_green", COLOUR_MOSS_GREEN },
|
||||
{ "bright_green", COLOUR_BRIGHT_GREEN },
|
||||
{ "olive_green", COLOUR_OLIVE_GREEN },
|
||||
{ "dark_olive_green", COLOUR_DARK_OLIVE_GREEN },
|
||||
{ "bright_yellow", COLOUR_BRIGHT_YELLOW },
|
||||
{ "yellow", COLOUR_YELLOW },
|
||||
{ "dark_yellow", COLOUR_DARK_YELLOW },
|
||||
{ "light_orange", COLOUR_LIGHT_ORANGE },
|
||||
{ "dark_orange", COLOUR_DARK_ORANGE },
|
||||
{ "light_brown", COLOUR_LIGHT_BROWN },
|
||||
{ "saturated_brown", COLOUR_SATURATED_BROWN },
|
||||
{ "dark_brown", COLOUR_DARK_BROWN },
|
||||
{ "salmon_pink", COLOUR_SALMON_PINK },
|
||||
{ "bordeaux_red", COLOUR_BORDEAUX_RED },
|
||||
{ "saturated_red", COLOUR_SATURATED_RED },
|
||||
{ "bright_red", COLOUR_BRIGHT_RED },
|
||||
{ "dark_pink", COLOUR_DARK_PINK },
|
||||
{ "bright_pink", COLOUR_BRIGHT_PINK },
|
||||
{ "light_pink", COLOUR_LIGHT_PINK },
|
||||
};
|
||||
auto result = LookupTable.find(s);
|
||||
return (result != LookupTable.end()) ?
|
||||
result->second :
|
||||
COLOUR_BLACK;
|
||||
}
|
||||
|
|
|
@ -16,24 +16,23 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
#include <vector>
|
||||
#include "../ride/Ride.h"
|
||||
#include "Object.h"
|
||||
|
||||
class RideObject final : public Object
|
||||
{
|
||||
private:
|
||||
rct_ride_entry _legacyType = { };
|
||||
vehicle_colour_preset_list _presetColours = { 0 };
|
||||
sint8 * _peepLoadingPositions[4] = { nullptr };
|
||||
uint16 _peepLoadingPositionsCount[4] = { 0 };
|
||||
std::vector<sint8> _peepLoadingPositions[MAX_VEHICLES_PER_RIDE_ENTRY];
|
||||
|
||||
public:
|
||||
explicit RideObject(const rct_object_entry &entry) : Object(entry) { }
|
||||
~RideObject();
|
||||
|
||||
void * GetLegacyData() override { return &_legacyType; }
|
||||
|
||||
void ReadJson(IReadObjectContext * context, const json_t * root) override;
|
||||
void ReadLegacy(IReadObjectContext * context, IStream * stream) override;
|
||||
void Load() override;
|
||||
void Unload() override;
|
||||
|
@ -47,8 +46,19 @@ public:
|
|||
|
||||
private:
|
||||
void ReadLegacyVehicle(IReadObjectContext * context, IStream * stream, rct_ride_entry_vehicle * vehicle);
|
||||
void PerformFixes();
|
||||
|
||||
void ReadJsonVehicleInfo(IReadObjectContext * context, const json_t * properties);
|
||||
std::vector<rct_ride_entry_vehicle> ReadJsonCars(const json_t * jCars);
|
||||
rct_ride_entry_vehicle ReadJsonCar(const json_t * jCar);
|
||||
vehicle_colour_preset_list ReadJsonCarColours(const json_t * jCarColours);
|
||||
std::vector<vehicle_colour> ReadJsonColourConfiguration(const json_t * jColourConfig);
|
||||
|
||||
static uint8 CalculateNumVerticalFrames(const rct_ride_entry_vehicle * vehicleEntry);
|
||||
static uint8 CalculateNumHorizontalFrames(const rct_ride_entry_vehicle * vehicleEntry);
|
||||
|
||||
static bool IsRideTypeShopOrFacility(uint8 rideType);
|
||||
static uint8 ParseRideType(const std::string &s);
|
||||
static uint8 ParseRideCategory(const std::string &s);
|
||||
static uint8 ParseShopItem(const std::string &s);
|
||||
static colour_t ParseColour(const std::string &s);
|
||||
};
|
||||
|
|
|
@ -14,15 +14,20 @@
|
|||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#pragma warning(disable : 4706) // assignment within conditional expression
|
||||
|
||||
#include <unordered_map>
|
||||
#include "../core/IStream.hpp"
|
||||
#include "../core/Memory.hpp"
|
||||
#include "../core/String.hpp"
|
||||
#include "../drawing/Drawing.h"
|
||||
#include "../localisation/Language.h"
|
||||
#include "../peep/Staff.h"
|
||||
#include "ObjectJsonHelpers.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "ObjectRepository.h"
|
||||
#include "SceneryGroupObject.h"
|
||||
|
||||
#include "../drawing/Drawing.h"
|
||||
#include "../localisation/Language.h"
|
||||
|
||||
void SceneryGroupObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
||||
{
|
||||
stream->Seek(6, STREAM_SEEK_CURRENT);
|
||||
|
@ -33,23 +38,23 @@ void SceneryGroupObject::ReadLegacy(IReadObjectContext * context, IStream * stre
|
|||
_legacyType.pad_109 = stream->ReadValue<uint8>();
|
||||
_legacyType.entertainer_costumes = stream->ReadValue<uint32>();
|
||||
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
_items = ReadItems(stream);
|
||||
GetImageTable()->Read(context, stream);
|
||||
GetImageTable().Read(context, stream);
|
||||
}
|
||||
|
||||
void SceneryGroupObject::Load()
|
||||
{
|
||||
GetStringTable()->Sort();
|
||||
GetStringTable().Sort();
|
||||
_legacyType.name = language_allocate_object_string(GetName());
|
||||
_legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount());
|
||||
_legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount());
|
||||
_legacyType.entry_count = 0;
|
||||
}
|
||||
|
||||
void SceneryGroupObject::Unload()
|
||||
{
|
||||
language_free_object_string(_legacyType.name);
|
||||
gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount());
|
||||
gfx_object_free_images(_legacyType.image, GetImageTable().GetCount());
|
||||
|
||||
_legacyType.name = 0;
|
||||
_legacyType.image = 0;
|
||||
|
@ -79,17 +84,20 @@ void SceneryGroupObject::UpdateEntryIndexes()
|
|||
uint16 sceneryEntry = objectManager->GetLoadedObjectEntryIndex(ori->LoadedObject);
|
||||
Guard::Assert(sceneryEntry != UINT8_MAX, GUARD_LINE);
|
||||
|
||||
uint8 objectType = objectEntry.flags & 0x0F;
|
||||
auto objectType = ori->ObjectEntry.flags & 0x0F;
|
||||
switch (objectType) {
|
||||
case OBJECT_TYPE_SMALL_SCENERY: break;
|
||||
case OBJECT_TYPE_LARGE_SCENERY: sceneryEntry |= 0x300; break;
|
||||
case OBJECT_TYPE_WALLS: sceneryEntry |= 0x200; break;
|
||||
case OBJECT_TYPE_PATH_BITS: sceneryEntry |= 0x100; break;
|
||||
default: sceneryEntry |= 0x400; break;
|
||||
case OBJECT_TYPE_WALLS: sceneryEntry |= 0x200; break;
|
||||
case OBJECT_TYPE_LARGE_SCENERY: sceneryEntry |= 0x300; break;
|
||||
case OBJECT_TYPE_BANNERS: sceneryEntry |= 0x400; break;
|
||||
default: sceneryEntry = 0xFFFF; break;
|
||||
}
|
||||
if (sceneryEntry != 0xFFFF)
|
||||
{
|
||||
_legacyType.scenery_entries[_legacyType.entry_count] = sceneryEntry;
|
||||
_legacyType.entry_count++;
|
||||
}
|
||||
|
||||
_legacyType.scenery_entries[_legacyType.entry_count] = sceneryEntry;
|
||||
_legacyType.entry_count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,8 +119,80 @@ std::vector<rct_object_entry> SceneryGroupObject::ReadItems(IStream * stream)
|
|||
while (stream->ReadValue<uint8>() != 0xFF)
|
||||
{
|
||||
stream->Seek(-1, STREAM_SEEK_CURRENT);
|
||||
rct_object_entry entry = stream->ReadValue<rct_object_entry>();
|
||||
auto entry = stream->ReadValue<rct_object_entry>();
|
||||
items.push_back(entry);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
void SceneryGroupObject::ReadJson(IReadObjectContext * context, const json_t * root)
|
||||
{
|
||||
auto properties = json_object_get(root, "properties");
|
||||
_legacyType.priority = json_integer_value(json_object_get(properties, "priority"));
|
||||
|
||||
// Entertainer cosumes
|
||||
auto jCostumes = json_object_get(properties, "entertainerCostumes");
|
||||
if (jCostumes != nullptr)
|
||||
{
|
||||
_legacyType.entertainer_costumes = ReadJsonEntertainerCostumes(jCostumes);
|
||||
}
|
||||
|
||||
auto jEntries = json_object_get(properties, "entries");
|
||||
if (jEntries != nullptr)
|
||||
{
|
||||
_items = ReadJsonEntries(jEntries);
|
||||
}
|
||||
|
||||
ObjectJsonHelpers::LoadStrings(root, GetStringTable());
|
||||
ObjectJsonHelpers::LoadImages(context, root, GetImageTable());
|
||||
}
|
||||
|
||||
uint32 SceneryGroupObject::ReadJsonEntertainerCostumes(const json_t * jCostumes)
|
||||
{
|
||||
uint32 costumes = 0;
|
||||
size_t index;
|
||||
json_t * jCostume;
|
||||
json_array_foreach(jCostumes, index, jCostume)
|
||||
{
|
||||
auto costume = ObjectJsonHelpers::GetString(jCostume);
|
||||
auto entertainer = ParseEntertainerCostume(costume);
|
||||
|
||||
// For some reason the flags are +4 from the actual costume IDs
|
||||
// See staff_get_available_entertainer_costumes
|
||||
costumes |= 1 << (entertainer + 4);
|
||||
}
|
||||
return costumes;
|
||||
}
|
||||
|
||||
uint32 SceneryGroupObject::ParseEntertainerCostume(const std::string &s)
|
||||
{
|
||||
if (s == "panda") return ENTERTAINER_COSTUME_PANDA;
|
||||
if (s == "tiger") return ENTERTAINER_COSTUME_TIGER;
|
||||
if (s == "elephant") return ENTERTAINER_COSTUME_ELEPHANT;
|
||||
if (s == "roman") return ENTERTAINER_COSTUME_ROMAN;
|
||||
if (s == "gorilla") return ENTERTAINER_COSTUME_GORILLA;
|
||||
if (s == "snowman") return ENTERTAINER_COSTUME_SNOWMAN;
|
||||
if (s == "knight") return ENTERTAINER_COSTUME_KNIGHT;
|
||||
if (s == "astronaut") return ENTERTAINER_COSTUME_ASTRONAUT;
|
||||
if (s == "bandit") return ENTERTAINER_COSTUME_BANDIT;
|
||||
if (s == "sheriff") return ENTERTAINER_COSTUME_SHERIFF;
|
||||
if (s == "pirate") return ENTERTAINER_COSTUME_PIRATE;
|
||||
return ENTERTAINER_COSTUME_PANDA;
|
||||
}
|
||||
|
||||
std::vector<rct_object_entry> SceneryGroupObject::ReadJsonEntries(const json_t * jEntries)
|
||||
{
|
||||
std::vector<rct_object_entry> entries;
|
||||
size_t index;
|
||||
json_t * jEntry;
|
||||
json_array_foreach(jEntries, index, jEntry)
|
||||
{
|
||||
auto entryId = json_string_value(jEntry);
|
||||
if (entryId != nullptr)
|
||||
{
|
||||
auto entry = ObjectJsonHelpers::ParseObjectEntry(entryId);
|
||||
entries.push_back(entry);
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
explicit SceneryGroupObject(const rct_object_entry &entry) : Object(entry) { }
|
||||
|
||||
void * GetLegacyData() override { return &_legacyType; }
|
||||
void ReadJson(IReadObjectContext * context, const json_t * root) override;
|
||||
|
||||
void ReadLegacy(IReadObjectContext * context, IStream * stream) override;
|
||||
void Load() override;
|
||||
|
@ -44,4 +45,7 @@ public:
|
|||
|
||||
private:
|
||||
static std::vector<rct_object_entry> ReadItems(IStream * stream);
|
||||
static uint32 ReadJsonEntertainerCostumes(const json_t * jCostumes);
|
||||
static uint32 ParseEntertainerCostume(const std::string &s);
|
||||
static std::vector<rct_object_entry> ReadJsonEntries(const json_t * jEntries);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
|
||||
/*****************************************************************************
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* A full copy of the GNU General Public License can be found in licence.txt
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#include "ObjectJsonHelpers.h"
|
||||
#include "SceneryObject.h"
|
||||
|
||||
void SceneryObject::SetPrimarySceneryGroup(const std::string &s)
|
||||
{
|
||||
if (!s.empty())
|
||||
{
|
||||
auto sgEntry = ObjectJsonHelpers::ParseObjectEntry(s);
|
||||
SetPrimarySceneryGroup(&sgEntry);
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "Object.h"
|
||||
|
||||
class SceneryObject : public Object
|
||||
|
@ -31,4 +32,5 @@ public:
|
|||
|
||||
protected:
|
||||
void SetPrimarySceneryGroup(const rct_object_entry * entry) { _primarySceneryGroupEntry = *entry; }
|
||||
void SetPrimarySceneryGroup(const std::string &s);
|
||||
};
|
||||
|
|
|
@ -14,16 +14,19 @@
|
|||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#pragma warning(disable : 4706) // assignment within conditional expression
|
||||
|
||||
#include "../core/IStream.hpp"
|
||||
#include "../core/Math.hpp"
|
||||
#include "../core/Memory.hpp"
|
||||
#include "../core/String.hpp"
|
||||
#include "SmallSceneryObject.h"
|
||||
|
||||
#include "../drawing/Drawing.h"
|
||||
#include "../interface/Cursors.h"
|
||||
#include "../localisation/Language.h"
|
||||
#include "../world/Scenery.h"
|
||||
#include "../world/SmallScenery.h"
|
||||
#include "SmallSceneryObject.h"
|
||||
#include "ObjectJsonHelpers.h"
|
||||
|
||||
void SmallSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
||||
{
|
||||
|
@ -39,7 +42,7 @@ void SmallSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre
|
|||
_legacyType.small_scenery.num_frames = stream->ReadValue<uint16>();
|
||||
_legacyType.small_scenery.scenery_tab_id = 0xFF;
|
||||
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
|
||||
rct_object_entry sgEntry = stream->ReadValue<rct_object_entry>();
|
||||
SetPrimarySceneryGroup(&sgEntry);
|
||||
|
@ -49,7 +52,7 @@ void SmallSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre
|
|||
_frameOffsets = ReadFrameOffsets(stream);
|
||||
}
|
||||
|
||||
GetImageTable()->Read(context, stream);
|
||||
GetImageTable().Read(context, stream);
|
||||
|
||||
// Validate properties
|
||||
if (_legacyType.small_scenery.price <= 0)
|
||||
|
@ -69,9 +72,9 @@ void SmallSceneryObject::ReadLegacy(IReadObjectContext * context, IStream * stre
|
|||
|
||||
void SmallSceneryObject::Load()
|
||||
{
|
||||
GetStringTable()->Sort();
|
||||
GetStringTable().Sort();
|
||||
_legacyType.name = language_allocate_object_string(GetName());
|
||||
_legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount());
|
||||
_legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount());
|
||||
|
||||
_legacyType.small_scenery.scenery_tab_id = 0xFF;
|
||||
|
||||
|
@ -86,7 +89,7 @@ void SmallSceneryObject::Load()
|
|||
void SmallSceneryObject::Unload()
|
||||
{
|
||||
language_free_object_string(_legacyType.name);
|
||||
gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount());
|
||||
gfx_object_free_images(_legacyType.image, GetImageTable().GetCount());
|
||||
|
||||
_legacyType.name = 0;
|
||||
_legacyType.image = 0;
|
||||
|
@ -231,3 +234,92 @@ rct_object_entry SmallSceneryObject::GetScgAbstrHeader()
|
|||
{
|
||||
return Object::CreateHeader("SCGABSTR", 207140231, 932253451);
|
||||
}
|
||||
|
||||
void SmallSceneryObject::ReadJson(IReadObjectContext * context, const json_t * root)
|
||||
{
|
||||
auto properties = json_object_get(root, "properties");
|
||||
|
||||
_legacyType.small_scenery.height = json_integer_value(json_object_get(properties, "height"));
|
||||
_legacyType.small_scenery.tool_id = ObjectJsonHelpers::ParseCursor(ObjectJsonHelpers::GetString(properties, "cursor"), CURSOR_STATUE_DOWN);
|
||||
_legacyType.small_scenery.price = json_integer_value(json_object_get(properties, "price"));
|
||||
_legacyType.small_scenery.removal_price = json_integer_value(json_object_get(properties, "removalPrice"));
|
||||
_legacyType.small_scenery.animation_delay = json_integer_value(json_object_get(properties, "animationDelay"));
|
||||
_legacyType.small_scenery.animation_mask = json_integer_value(json_object_get(properties, "animationMask"));
|
||||
_legacyType.small_scenery.num_frames = json_integer_value(json_object_get(properties, "numFrames"));
|
||||
|
||||
// Flags
|
||||
_legacyType.small_scenery.flags = ObjectJsonHelpers::GetFlags<uint32>(properties, {
|
||||
{ "SMALL_SCENERY_FLAG_VOFFSET_CENTRE", SMALL_SCENERY_FLAG_VOFFSET_CENTRE },
|
||||
{ "requiresFlatSurface", SMALL_SCENERY_FLAG_REQUIRE_FLAT_SURFACE },
|
||||
{ "isRotatable", SMALL_SCENERY_FLAG_ROTATABLE },
|
||||
{ "isAnimated", SMALL_SCENERY_FLAG_ANIMATED },
|
||||
{ "canWither", SMALL_SCENERY_FLAG_CAN_WITHER },
|
||||
{ "canBeWatered", SMALL_SCENERY_FLAG_CAN_BE_WATERED },
|
||||
{ "hasOverlayImage", SMALL_SCENERY_FLAG_ANIMATED_FG },
|
||||
{ "hasGlass", SMALL_SCENERY_FLAG_HAS_GLASS },
|
||||
{ "hasPrimaryColour", SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR },
|
||||
{ "SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1", SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_1 },
|
||||
{ "SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4", SMALL_SCENERY_FLAG_FOUNTAIN_SPRAY_4 },
|
||||
{ "isClock", SMALL_SCENERY_FLAG_IS_CLOCK },
|
||||
{ "SMALL_SCENERY_FLAG_SWAMP_GOO", SMALL_SCENERY_FLAG_SWAMP_GOO },
|
||||
{ "SMALL_SCENERY_FLAG17", SMALL_SCENERY_FLAG17 },
|
||||
{ "isStackable", SMALL_SCENERY_FLAG_STACKABLE },
|
||||
{ "prohibitWalls", SMALL_SCENERY_FLAG_NO_WALLS },
|
||||
{ "hasSecondaryColour", SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR },
|
||||
{ "hasNoSupports", SMALL_SCENERY_FLAG_NO_SUPPORTS },
|
||||
{ "SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED", SMALL_SCENERY_FLAG_VISIBLE_WHEN_ZOOMED },
|
||||
{ "SMALL_SCENERY_FLAG_COG", SMALL_SCENERY_FLAG_COG },
|
||||
{ "allowSupportsAbove", SMALL_SCENERY_FLAG_BUILD_DIRECTLY_ONTOP },
|
||||
{ "supportsHavePrimaryColour", SMALL_SCENERY_FLAG_PAINT_SUPPORTS },
|
||||
{ "SMALL_SCENERY_FLAG27", SMALL_SCENERY_FLAG27 } });
|
||||
|
||||
// Determine shape flags from a shape string
|
||||
auto shape = ObjectJsonHelpers::GetString(properties, "shape");
|
||||
if (!shape.empty())
|
||||
{
|
||||
auto quarters = shape.substr(0, 3);
|
||||
if (quarters == "2/4")
|
||||
{
|
||||
_legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_FULL_TILE | SMALL_SCENERY_FLAG_HALF_SPACE;
|
||||
}
|
||||
else if (quarters == "3/4")
|
||||
{
|
||||
_legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_FULL_TILE | SMALL_SCENERY_FLAG_THREE_QUARTERS;
|
||||
}
|
||||
else if (quarters == "4/4")
|
||||
{
|
||||
_legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_FULL_TILE;
|
||||
}
|
||||
if (shape.size() >= 5)
|
||||
{
|
||||
if ((shape.substr(3) == "+D"))
|
||||
{
|
||||
_legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_DIAGONAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto jFrameOffsets = json_object_get(properties, "frameOffsets");
|
||||
if (jFrameOffsets != nullptr)
|
||||
{
|
||||
_frameOffsets = ReadJsonFrameOffsets(jFrameOffsets);
|
||||
_legacyType.small_scenery.flags |= SMALL_SCENERY_FLAG_HAS_FRAME_OFFSETS;
|
||||
}
|
||||
|
||||
SetPrimarySceneryGroup(ObjectJsonHelpers::GetString(json_object_get(properties, "sceneryGroup")));
|
||||
|
||||
ObjectJsonHelpers::LoadStrings(root, GetStringTable());
|
||||
ObjectJsonHelpers::LoadImages(context, root, GetImageTable());
|
||||
}
|
||||
|
||||
std::vector<uint8> SmallSceneryObject::ReadJsonFrameOffsets(const json_t * jFrameOffsets)
|
||||
{
|
||||
std::vector<uint8> offsets;
|
||||
size_t index;
|
||||
const json_t * jOffset;
|
||||
json_array_foreach(jFrameOffsets, index, jOffset)
|
||||
{
|
||||
offsets.push_back(json_integer_value(jOffset));
|
||||
}
|
||||
return offsets;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
void * GetLegacyData() override { return &_legacyType; }
|
||||
|
||||
void ReadLegacy(IReadObjectContext * context, IStream * stream) override;
|
||||
void ReadJson(IReadObjectContext * context, const json_t * root) override;
|
||||
void Load() override;
|
||||
void Unload() override;
|
||||
|
||||
|
@ -39,6 +40,7 @@ public:
|
|||
|
||||
private:
|
||||
static std::vector<uint8> ReadFrameOffsets(IStream * stream);
|
||||
static std::vector<uint8> ReadJsonFrameOffsets(const json_t * jFrameOffsets);
|
||||
void PerformFixes();
|
||||
rct_object_entry GetScgPiratHeader();
|
||||
rct_object_entry GetScgMineHeader();
|
||||
|
|
|
@ -25,14 +25,14 @@ void StexObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
|||
_legacyType.var_06 = stream->ReadValue<uint8>();
|
||||
stream->Seek(1, STREAM_SEEK_CURRENT);
|
||||
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_SCENARIO_NAME);
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_PARK_NAME);
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_SCENARIO_DETAILS);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_SCENARIO_NAME);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_PARK_NAME);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_SCENARIO_DETAILS);
|
||||
}
|
||||
|
||||
void StexObject::Load()
|
||||
{
|
||||
GetStringTable()->Sort();
|
||||
GetStringTable().Sort();
|
||||
_legacyType.scenario_name = language_allocate_object_string(GetScenarioName());
|
||||
_legacyType.park_name = language_allocate_object_string(GetParkName());
|
||||
_legacyType.details = language_allocate_object_string(GetScenarioDetails());
|
||||
|
@ -64,15 +64,15 @@ std::string StexObject::GetName() const
|
|||
|
||||
std::string StexObject::GetScenarioName() const
|
||||
{
|
||||
return GetStringTable()->GetString(OBJ_STRING_ID_SCENARIO_NAME);
|
||||
return GetStringTable().GetString(OBJ_STRING_ID_SCENARIO_NAME);
|
||||
}
|
||||
|
||||
std::string StexObject::GetScenarioDetails() const
|
||||
{
|
||||
return GetStringTable()->GetString(OBJ_STRING_ID_SCENARIO_DETAILS);
|
||||
return GetStringTable().GetString(OBJ_STRING_ID_SCENARIO_DETAILS);
|
||||
}
|
||||
|
||||
std::string StexObject::GetParkName() const
|
||||
{
|
||||
return GetStringTable()->GetString(OBJ_STRING_ID_PARK_NAME);
|
||||
return GetStringTable().GetString(OBJ_STRING_ID_PARK_NAME);
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ std::string StringTable::GetString(uint8 id) const
|
|||
return string.Text;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void StringTable::SetString(uint8 id, uint8 language, const std::string &text)
|
||||
|
|
|
@ -19,14 +19,27 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include "../common.h"
|
||||
#include "../localisation/Language.h"
|
||||
|
||||
interface IReadObjectContext;
|
||||
interface IStream;
|
||||
|
||||
enum OBJ_STRING_ID : uint8
|
||||
{
|
||||
OBJ_STRING_ID_UNKNOWN = 255,
|
||||
OBJ_STRING_ID_NAME = 0,
|
||||
OBJ_STRING_ID_DESCRIPTION,
|
||||
OBJ_STRING_ID_SCENARIO_NAME = 0,
|
||||
OBJ_STRING_ID_PARK_NAME = 1,
|
||||
OBJ_STRING_ID_SCENARIO_DETAILS = 2,
|
||||
OBJ_STRING_ID_CAPACITY = 2,
|
||||
OBJ_STRING_ID_VEHICLE_NAME = 3,
|
||||
};
|
||||
|
||||
struct StringTableEntry
|
||||
{
|
||||
uint8 Id;
|
||||
uint8 LanguageId;
|
||||
uint8 Id = OBJ_STRING_ID_UNKNOWN;
|
||||
uint8 LanguageId = LANGUAGE_UNDEFINED;
|
||||
std::string Text;
|
||||
};
|
||||
|
||||
|
@ -36,6 +49,10 @@ private:
|
|||
std::vector<StringTableEntry> _strings;
|
||||
|
||||
public:
|
||||
StringTable() = default;
|
||||
StringTable(const StringTable &) = delete;
|
||||
StringTable & operator=(const StringTable &) = delete;
|
||||
|
||||
void Read(IReadObjectContext * context, IStream * stream, uint8 id);
|
||||
void Sort();
|
||||
std::string GetString(uint8 id) const;
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
#pragma endregion
|
||||
|
||||
#include "../core/IStream.hpp"
|
||||
#include "WallObject.h"
|
||||
|
||||
#include "../drawing/Drawing.h"
|
||||
#include "../interface/Cursors.h"
|
||||
#include "../localisation/Language.h"
|
||||
#include "ObjectJsonHelpers.h"
|
||||
#include "WallObject.h"
|
||||
|
||||
void WallObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
||||
{
|
||||
|
@ -31,12 +32,12 @@ void WallObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
|||
_legacyType.wall.scenery_tab_id = stream->ReadValue<uint8>();
|
||||
_legacyType.wall.scrolling_mode = stream->ReadValue<uint8>();
|
||||
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
|
||||
rct_object_entry sgEntry = stream->ReadValue<rct_object_entry>();
|
||||
SetPrimarySceneryGroup(&sgEntry);
|
||||
|
||||
GetImageTable()->Read(context, stream);
|
||||
GetImageTable().Read(context, stream);
|
||||
|
||||
// Validate properties
|
||||
if (_legacyType.wall.price <= 0)
|
||||
|
@ -47,15 +48,15 @@ void WallObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
|||
|
||||
void WallObject::Load()
|
||||
{
|
||||
GetStringTable()->Sort();
|
||||
GetStringTable().Sort();
|
||||
_legacyType.name = language_allocate_object_string(GetName());
|
||||
_legacyType.image = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount());
|
||||
_legacyType.image = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount());
|
||||
}
|
||||
|
||||
void WallObject::Unload()
|
||||
{
|
||||
language_free_object_string(_legacyType.name);
|
||||
gfx_object_free_images(_legacyType.image, GetImageTable()->GetCount());
|
||||
gfx_object_free_images(_legacyType.image, GetImageTable().GetCount());
|
||||
|
||||
_legacyType.name = 0;
|
||||
_legacyType.image = 0;
|
||||
|
@ -88,3 +89,61 @@ void WallObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 heigh
|
|||
gfx_draw_sprite(dpi, imageId, x, y, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void WallObject::ReadJson(IReadObjectContext * context, const json_t * root)
|
||||
{
|
||||
auto properties = json_object_get(root, "properties");
|
||||
|
||||
_legacyType.wall.tool_id = ObjectJsonHelpers::ParseCursor(ObjectJsonHelpers::GetString(properties, "cursor"), CURSOR_FENCE_DOWN);
|
||||
_legacyType.wall.height = json_integer_value(json_object_get(properties, "height"));
|
||||
_legacyType.wall.price = json_integer_value(json_object_get(properties, "price"));
|
||||
|
||||
auto jScrollingMode = json_object_get(properties, "scrollingMode");
|
||||
_legacyType.wall.scrolling_mode = jScrollingMode != nullptr ?
|
||||
json_integer_value(jScrollingMode) :
|
||||
-1;
|
||||
|
||||
SetPrimarySceneryGroup(ObjectJsonHelpers::GetString(json_object_get(properties, "sceneryGroup")));
|
||||
|
||||
// Flags
|
||||
_legacyType.wall.flags = ObjectJsonHelpers::GetFlags<uint8>(properties, {
|
||||
{ "hasPrimaryColour", WALL_SCENERY_HAS_PRIMARY_COLOUR },
|
||||
{ "hasSecondaryColour", WALL_SCENERY_HAS_SECONDARY_COLOUR },
|
||||
{ "hasTernaryColour", WALL_SCENERY_HAS_TERNARY_COLOUR },
|
||||
{ "hasGlass", WALL_SCENERY_HAS_GLASS },
|
||||
{ "isBanner", WALL_SCENERY_IS_BANNER },
|
||||
{ "isDoor", WALL_SCENERY_IS_DOOR },
|
||||
{ "isLongDoorAnimation", WALL_SCENERY_LONG_DOOR_ANIMATION }});
|
||||
_legacyType.wall.flags2 = ObjectJsonHelpers::GetFlags<uint8>(properties, {
|
||||
{ "isOpaque", WALL_SCENERY_2_IS_OPAQUE },
|
||||
{ "isAnimated", WALL_SCENERY_2_ANIMATED }});
|
||||
|
||||
// HACK To avoid 'negated' properties in JSON, handle this separately until
|
||||
// flag is inverted in this code base.
|
||||
if (!ObjectJsonHelpers::GetBoolean(properties, "isAllowedOnSlope", false))
|
||||
{
|
||||
_legacyType.wall.flags |= WALL_SCENERY_CANT_BUILD_ON_SLOPE;
|
||||
}
|
||||
|
||||
// HACK WALL_SCENERY_HAS_PRIMARY_COLOUR actually means, has any colour but we simplify the
|
||||
// JSON and handle this on load. We should change code base in future to reflect the JSON.
|
||||
if (!(_legacyType.wall.flags & WALL_SCENERY_HAS_PRIMARY_COLOUR))
|
||||
{
|
||||
if ((_legacyType.wall.flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) ||
|
||||
(_legacyType.wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR))
|
||||
{
|
||||
_legacyType.wall.flags2 |= WALL_SCENERY_2_NO_SELECT_PRIMARY_COLOUR;
|
||||
}
|
||||
}
|
||||
|
||||
// Door sound
|
||||
auto jDoorSound = json_object_get(properties, "scrollingMode");
|
||||
if (jDoorSound != nullptr)
|
||||
{
|
||||
auto doorSound = json_integer_value(jDoorSound);
|
||||
_legacyType.wall.flags2 |= (doorSound << WALL_SCENERY_2_DOOR_SOUND_SHIFT) & WALL_SCENERY_2_DOOR_SOUND_MASK;
|
||||
}
|
||||
|
||||
ObjectJsonHelpers::LoadStrings(root, GetStringTable());
|
||||
ObjectJsonHelpers::LoadImages(context, root, GetImageTable());
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ public:
|
|||
void * GetLegacyData() override { return &_legacyType; }
|
||||
|
||||
void ReadLegacy(IReadObjectContext * context, IStream * stream) override;
|
||||
void ReadJson(IReadObjectContext * context, const json_t * root) override;
|
||||
void Load() override;
|
||||
void Unload() override;
|
||||
|
||||
|
|
|
@ -14,10 +14,14 @@
|
|||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#pragma warning(disable : 4706) // assignment within conditional expression
|
||||
|
||||
#include <memory>
|
||||
#include "../core/IStream.hpp"
|
||||
#include "../localisation/Language.h"
|
||||
#include "../localisation/StringIds.h"
|
||||
#include "../OpenRCT2.h"
|
||||
#include "ObjectJsonHelpers.h"
|
||||
#include "WaterObject.h"
|
||||
|
||||
void WaterObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
||||
|
@ -25,15 +29,15 @@ void WaterObject::ReadLegacy(IReadObjectContext * context, IStream * stream)
|
|||
stream->Seek(14, STREAM_SEEK_CURRENT);
|
||||
_legacyType.flags = stream->ReadValue<uint16>();
|
||||
|
||||
GetStringTable()->Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetImageTable()->Read(context, stream);
|
||||
GetStringTable().Read(context, stream, OBJ_STRING_ID_NAME);
|
||||
GetImageTable().Read(context, stream);
|
||||
}
|
||||
|
||||
void WaterObject::Load()
|
||||
{
|
||||
GetStringTable()->Sort();
|
||||
GetStringTable().Sort();
|
||||
_legacyType.string_idx = language_allocate_object_string(GetName());
|
||||
_legacyType.image_id = gfx_object_allocate_images(GetImageTable()->GetImages(), GetImageTable()->GetCount());
|
||||
_legacyType.image_id = gfx_object_allocate_images(GetImageTable().GetImages(), GetImageTable().GetCount());
|
||||
_legacyType.palette_index_1 = _legacyType.image_id + 1;
|
||||
_legacyType.palette_index_2 = _legacyType.image_id + 4;
|
||||
|
||||
|
@ -42,7 +46,7 @@ void WaterObject::Load()
|
|||
|
||||
void WaterObject::Unload()
|
||||
{
|
||||
gfx_object_free_images(_legacyType.image_id, GetImageTable()->GetCount());
|
||||
gfx_object_free_images(_legacyType.image_id, GetImageTable().GetCount());
|
||||
language_free_object_string(_legacyType.string_idx);
|
||||
|
||||
_legacyType.string_idx = 0;
|
||||
|
@ -55,3 +59,85 @@ void WaterObject::DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 heig
|
|||
sint32 y = height / 2;
|
||||
gfx_draw_string_centred(dpi, STR_WINDOW_NO_IMAGE, x, y, COLOUR_BLACK, nullptr);
|
||||
}
|
||||
|
||||
void WaterObject::ReadJson(IReadObjectContext * context, const json_t * root)
|
||||
{
|
||||
auto properties = json_object_get(root, "properties");
|
||||
_legacyType.flags = ObjectJsonHelpers::GetFlags<uint16>(properties, {
|
||||
{ "allowDucks", WATER_FLAGS_ALLOW_DUCKS }});
|
||||
|
||||
ObjectJsonHelpers::LoadStrings(root, GetStringTable());
|
||||
|
||||
// Images which are actually palette data
|
||||
static const char * paletteNames[] =
|
||||
{
|
||||
"general",
|
||||
"waves-0",
|
||||
"waves-1",
|
||||
"waves-2",
|
||||
"sparkles-0",
|
||||
"sparkles-1",
|
||||
"sparkles-2"
|
||||
};
|
||||
for (auto paletteName : paletteNames)
|
||||
{
|
||||
auto jPalettes = json_object_get(properties, "palettes");
|
||||
if (jPalettes != nullptr)
|
||||
{
|
||||
auto jPalette = json_object_get(jPalettes, paletteName);
|
||||
if (jPalette != nullptr)
|
||||
{
|
||||
ReadJsonPalette(jPalette);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WaterObject::ReadJsonPalette(const json_t * jPalette)
|
||||
{
|
||||
auto paletteStartIndex = json_integer_value(json_object_get(jPalette, "index"));
|
||||
auto jColours = json_object_get(jPalette, "colours");
|
||||
auto numColours = json_array_size(jColours);
|
||||
|
||||
auto data = std::make_unique<uint8[]>(numColours * 3);
|
||||
size_t dataIndex = 0;
|
||||
|
||||
size_t index;
|
||||
const json_t * jColour;
|
||||
json_array_foreach(jColours, index, jColour)
|
||||
{
|
||||
auto szColour = json_string_value(jColour);
|
||||
if (szColour != nullptr)
|
||||
{
|
||||
auto colour = ParseColour(szColour);
|
||||
data[dataIndex + 0] = (colour >> 16) & 0xFF;
|
||||
data[dataIndex + 1] = (colour >> 8) & 0xFF;
|
||||
data[dataIndex + 2] = colour & 0xFF;
|
||||
}
|
||||
dataIndex += 3;
|
||||
}
|
||||
|
||||
rct_g1_element g1 = { 0 };
|
||||
g1.offset = data.get();
|
||||
g1.width = (sint16)numColours;
|
||||
g1.x_offset = (sint16)paletteStartIndex;
|
||||
g1.flags = G1_FLAG_PALETTE;
|
||||
|
||||
auto &imageTable = GetImageTable();
|
||||
imageTable.AddImage(&g1);
|
||||
}
|
||||
|
||||
uint32 WaterObject::ParseColour(const std::string &s) const
|
||||
{
|
||||
uint8 r = 0;
|
||||
uint8 g = 0;
|
||||
uint8 b = 0;
|
||||
if (s[0] == '#' && s.size() == 7)
|
||||
{
|
||||
// Expect #RRGGBB
|
||||
r = std::stoul(s.substr(1, 2), nullptr, 16) & 0xFF;
|
||||
g = std::stoul(s.substr(3, 2), nullptr, 16) & 0xFF;
|
||||
b = std::stoul(s.substr(5, 2), nullptr, 16) & 0xFF;
|
||||
}
|
||||
return (b << 16) | (g << 8) | r;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
#include <tuple>
|
||||
#include "../world/Water.h"
|
||||
#include "Object.h"
|
||||
|
||||
class WaterObject final : public Object
|
||||
{
|
||||
|
@ -30,9 +30,14 @@ public:
|
|||
|
||||
void * GetLegacyData() override { return &_legacyType; }
|
||||
|
||||
void ReadJson(IReadObjectContext * context, const json_t * root) override;
|
||||
void ReadLegacy(IReadObjectContext * context, IStream * stream) override;
|
||||
void Load() override;
|
||||
void Unload() override;
|
||||
|
||||
void DrawPreview(rct_drawpixelinfo * dpi, sint32 width, sint32 height) const override;
|
||||
|
||||
private:
|
||||
void ReadJsonPalette(const json_t * jPalette);
|
||||
uint32 ParseColour(const std::string &s) const;
|
||||
};
|
||||
|
|
|
@ -39,7 +39,7 @@ static void large_scenery_paint_supports(
|
|||
uint32 dword_F4387C,
|
||||
rct_large_scenery_tile * tile)
|
||||
{
|
||||
if (tile->var_7 & 0x20) {
|
||||
if (tile->flags & LARGE_SCENERY_TILE_FLAG_NO_SUPPORTS) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ static void large_scenery_paint_supports(
|
|||
|
||||
sint32 clearanceHeight = ceil2(tileElement->clearance_height * 8 + 15, 16);
|
||||
|
||||
if (tile->var_7 & 0x40) {
|
||||
if (tile->flags & LARGE_SCENERY_TILE_FLAG_ALLOW_SUPPORTS_ABOVE) {
|
||||
paint_util_set_segment_support_height(session, SEGMENTS_ALL, clearanceHeight, 0x20);
|
||||
} else {
|
||||
paint_util_set_segment_support_height(session, SEGMENTS_ALL, 0xFFFF, 0);
|
||||
|
@ -232,7 +232,7 @@ void large_scenery_paint(paint_session * session, uint8 direction, uint16 height
|
|||
ah = 0x80;
|
||||
}
|
||||
ah -= 3;
|
||||
uint16 edi = tile->var_7;
|
||||
uint16 edi = tile->flags;
|
||||
sint32 esi = 16;
|
||||
if (edi & 0xF00) {
|
||||
edi &= 0xF000;
|
||||
|
|
|
@ -850,7 +850,7 @@ static constexpr const uint8 byte_9822F4[] = {
|
|||
110, // SHOP_ITEM_MEATBALL_SOUP
|
||||
110, // SHOP_ITEM_FRUIT_JUICE
|
||||
90, // SHOP_ITEM_SOYBEAN_MILK
|
||||
100, // SHOP_ITEM_SU_JONGKWA
|
||||
100, // SHOP_ITEM_SUJEONGGWA
|
||||
130, // SHOP_ITEM_SUB_SANDWICH
|
||||
75, // SHOP_ITEM_COOKIE
|
||||
0, // SHOP_ITEM_EMPTY_BOWL_RED
|
||||
|
@ -3021,7 +3021,7 @@ static void peep_update_ride_sub_state_1(rct_peep * peep)
|
|||
if (ride->type != RIDE_TYPE_ENTERPRISE)
|
||||
direction_track *= 2;
|
||||
|
||||
if (*vehicle_type->peep_loading_positions == 0)
|
||||
if (vehicle_type->peep_loading_positions[0] == 0)
|
||||
{
|
||||
direction_track /= 2;
|
||||
cl = 0;
|
||||
|
@ -3063,7 +3063,7 @@ static void peep_update_ride_sub_state_1(rct_peep * peep)
|
|||
|
||||
sint8 load_position = 0;
|
||||
// Safe, in case current seat > number of loading positions
|
||||
uint16 numSeatPositions = vehicle_type->peep_loading_positions_count;
|
||||
auto numSeatPositions = vehicle_type->peep_loading_positions.size();
|
||||
if (numSeatPositions != 0)
|
||||
{
|
||||
size_t loadPositionIndex = numSeatPositions - 1;
|
||||
|
@ -3563,7 +3563,7 @@ static void peep_update_ride_sub_state_7(rct_peep * peep)
|
|||
if (ride->type != RIDE_TYPE_ENTERPRISE)
|
||||
station_direction *= 2;
|
||||
|
||||
if (*vehicle_type->peep_loading_positions == 0)
|
||||
if (vehicle_type->peep_loading_positions[0] == 0)
|
||||
{
|
||||
station_direction /= 2;
|
||||
cl = 0;
|
||||
|
|
|
@ -7709,7 +7709,7 @@ bool shop_item_is_food_or_drink(sint32 shopItem)
|
|||
case SHOP_ITEM_MEATBALL_SOUP:
|
||||
case SHOP_ITEM_FRUIT_JUICE:
|
||||
case SHOP_ITEM_SOYBEAN_MILK:
|
||||
case SHOP_ITEM_SU_JONGKWA:
|
||||
case SHOP_ITEM_SUJEONGGWA:
|
||||
case SHOP_ITEM_SUB_SANDWICH:
|
||||
case SHOP_ITEM_COOKIE:
|
||||
case SHOP_ITEM_ROAST_SAUSAGE:
|
||||
|
@ -7758,7 +7758,7 @@ bool shop_item_is_drink(sint32 shopItem)
|
|||
case SHOP_ITEM_ICED_TEA:
|
||||
case SHOP_ITEM_FRUIT_JUICE:
|
||||
case SHOP_ITEM_SOYBEAN_MILK:
|
||||
case SHOP_ITEM_SU_JONGKWA:
|
||||
case SHOP_ITEM_SUJEONGGWA:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
@ -126,6 +126,7 @@ struct rct_ride_entry {
|
|||
uint8 shop_item; // 0x1C0
|
||||
uint8 shop_item_secondary; // 0x1C1
|
||||
rct_string_id capacity;
|
||||
void * obj;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
@ -856,7 +857,7 @@ enum {
|
|||
SHOP_ITEM_MEATBALL_SOUP,
|
||||
SHOP_ITEM_FRUIT_JUICE,
|
||||
SHOP_ITEM_SOYBEAN_MILK,
|
||||
SHOP_ITEM_SU_JONGKWA,
|
||||
SHOP_ITEM_SUJEONGGWA,
|
||||
SHOP_ITEM_SUB_SANDWICH,
|
||||
SHOP_ITEM_COOKIE,
|
||||
SHOP_ITEM_EMPTY_BOWL_RED,
|
||||
|
|
|
@ -1460,7 +1460,7 @@ const money8 DefaultShopItemPrice[SHOP_ITEM_COUNT] = {
|
|||
MONEY(1,50), // SHOP_ITEM_MEATBALL_SOUP
|
||||
MONEY(1,20), // SHOP_ITEM_FRUIT_JUICE
|
||||
MONEY(1,20), // SHOP_ITEM_SOYBEAN_MILK
|
||||
MONEY(1,20), // SHOP_ITEM_SU_JONGKWA
|
||||
MONEY(1,20), // SHOP_ITEM_SUJEONGGWA
|
||||
MONEY(1,50), // SHOP_ITEM_SUB_SANDWICH
|
||||
MONEY(0,70), // SHOP_ITEM_COOKIE
|
||||
MONEY(0,00), // SHOP_ITEM_EMPTY_BOWL_RED
|
||||
|
@ -1576,7 +1576,7 @@ const uint32 ShopItemImage[SHOP_ITEM_COUNT] = {
|
|||
SPR_SHOP_ITEM_MEATBALL_SOUP,
|
||||
SPR_SHOP_ITEM_FRUIT_JUICE,
|
||||
SPR_SHOP_ITEM_SOYBEAN_MILK,
|
||||
SPR_SHOP_ITEM_SU_JONGKWA,
|
||||
SPR_SHOP_ITEM_SUJEONGGWA,
|
||||
SPR_SHOP_ITEM_SUB_SANDWICH,
|
||||
SPR_SHOP_ITEM_COOKIE,
|
||||
SPR_SHOP_ITEM_EMPTY_BOWL_RED,
|
||||
|
@ -1629,7 +1629,7 @@ const rct_ride_entry_vehicle CableLiftVehicle = {
|
|||
/* .effect_visual = */ 1,
|
||||
/* .draw_order = */ 14,
|
||||
/* .num_vertical_frames_override = */ 0,
|
||||
/* .peep_loading_positions = */ nullptr
|
||||
/* .peep_loading_positions = */
|
||||
};
|
||||
|
||||
/* rct2: 0x009A0AA0 */
|
||||
|
@ -2482,7 +2482,7 @@ const rct_shop_item_stats ShopItemStats[SHOP_ITEM_COUNT] = {
|
|||
{ 5, 14, 14, 16 }, // SHOP_ITEM_MEATBALL_SOUP
|
||||
{ 4, 11, 19, 11 }, // SHOP_ITEM_FRUIT_JUICE
|
||||
{ 4, 10, 14, 10 }, // SHOP_ITEM_SOYBEAN_MILK
|
||||
{ 3, 11, 14, 11 }, // SHOP_ITEM_SU_JONGKWA
|
||||
{ 3, 11, 14, 11 }, // SHOP_ITEM_SUJEONGGWA
|
||||
{ 5, 19, 19, 17 }, // SHOP_ITEM_SUB_SANDWICH
|
||||
{ 4, 8, 8, 8 }, // SHOP_ITEM_COOKIE
|
||||
{ 0, 0, 0, 0 }, // SHOP_ITEM_EMPTY_BOWL_RED
|
||||
|
|
|
@ -108,7 +108,7 @@ const RideGroup * RideGroupManager::GetRideGroup(const uint8 rideType, const rct
|
|||
switch (rideType)
|
||||
{
|
||||
case RIDE_TYPE_CORKSCREW_ROLLER_COASTER:
|
||||
if (rideEntry->enabledTrackPieces & (1ULL << TRACK_VERTICAL_LOOP))
|
||||
if (ride_entry_get_supported_track_pieces(rideEntry) & (1ULL << TRACK_VERTICAL_LOOP))
|
||||
return &ride_group_corkscrew_rc;
|
||||
else
|
||||
return &ride_group_hypercoaster;
|
||||
|
@ -118,17 +118,17 @@ const RideGroup * RideGroupManager::GetRideGroup(const uint8 rideType, const rct
|
|||
else
|
||||
return &ride_group_junior_rc;
|
||||
case RIDE_TYPE_CAR_RIDE:
|
||||
if (rideEntry->enabledTrackPieces & (1ULL << TRACK_SLOPE_STEEP))
|
||||
if (ride_entry_get_supported_track_pieces(rideEntry) & (1ULL << TRACK_SLOPE_STEEP))
|
||||
return &ride_group_monster_trucks;
|
||||
else
|
||||
return &ride_group_car_ride;
|
||||
case RIDE_TYPE_TWISTER_ROLLER_COASTER:
|
||||
if (rideEntry->enabledTrackPieces & (1ULL << TRACK_VERTICAL_LOOP))
|
||||
if (!(rideEntry->flags & RIDE_ENTRY_FLAG_NO_INVERSIONS))
|
||||
return &ride_group_steel_twister_rc;
|
||||
else
|
||||
return &ride_group_hyper_twister;
|
||||
case RIDE_TYPE_STEEL_WILD_MOUSE:
|
||||
if (rideEntry->enabledTrackPieces & (1ULL << TRACK_SLOPE_STEEP))
|
||||
if (ride_entry_get_supported_track_pieces(rideEntry) & (1ULL << TRACK_SLOPE_STEEP))
|
||||
return &ride_group_steel_wild_mouse;
|
||||
else
|
||||
return &ride_group_spinning_wild_mouse;
|
||||
|
|
|
@ -1004,7 +1004,6 @@ static money32 track_place(sint32 rideIndex,
|
|||
direction &= 3;
|
||||
gTrackGroundFlags = 0;
|
||||
|
||||
uint64 enabledTrackPieces = rideEntry->enabledTrackPieces & RideTypePossibleTrackConfigurations[ride->type];
|
||||
uint32 rideTypeFlags = RideProperties[ride->type].flags;
|
||||
|
||||
if ((ride->lifecycle_flags & RIDE_LIFECYCLE_INDESTRUCTIBLE_TRACK) && type == TRACK_ELEM_END_STATION)
|
||||
|
@ -1047,7 +1046,7 @@ static money32 track_place(sint32 rideIndex,
|
|||
}
|
||||
// Backwards steep lift hills are allowed, even on roller coasters that do not support forwards steep lift hills.
|
||||
if ((liftHillAndAlternativeState & CONSTRUCTION_LIFT_HILL_SELECTED) &&
|
||||
!(enabledTrackPieces & (1ULL << TRACK_LIFT_HILL_STEEP)) &&
|
||||
!(RideTypePossibleTrackConfigurations[ride->type] & (1ULL << TRACK_LIFT_HILL_STEEP)) &&
|
||||
!gCheatsEnableChainLiftOnAllTrack)
|
||||
{
|
||||
if (TrackFlags[type] & TRACK_ELEM_FLAG_IS_STEEP_UP)
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#ifndef _VEHICLE_H_
|
||||
#define _VEHICLE_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include "../common.h"
|
||||
#include "../world/Location.hpp"
|
||||
|
||||
|
@ -25,7 +27,9 @@ struct rct_vehicle_colour {
|
|||
uint8 trim_colour;
|
||||
};
|
||||
|
||||
#ifdef __TESTPAINT__
|
||||
#pragma pack(push, 1)
|
||||
#endif // __TESTPAINT__
|
||||
/**
|
||||
* Ride type vehicle structure.
|
||||
* size: 0x65
|
||||
|
@ -76,10 +80,20 @@ struct rct_ride_entry_vehicle {
|
|||
uint8 effect_visual;
|
||||
uint8 draw_order;
|
||||
uint8 num_vertical_frames_override; // 0x60 , 0x7A, A custom number that can be used rather than letting RCT2 determine it. Needs the VEHICLE_ENTRY_FLAG_OVERRIDE_NUM_VERTICAL_FRAMES flag to be set.
|
||||
sint8* peep_loading_positions; // 0x61 , 0x7B
|
||||
uint16 peep_loading_positions_count;
|
||||
uint8 pad_61[7]; // 0x61 , 0x7B
|
||||
|
||||
std::vector<sint8> peep_loading_positions;
|
||||
};
|
||||
#ifdef __TESTPAINT__
|
||||
#pragma pack(pop)
|
||||
#endif // __TESTPAINT__
|
||||
#ifdef PLATFORM_32BIT
|
||||
static_assert(offsetof(rct_ride_entry_vehicle, peep_loading_positions) % 4 == 0, "Invalid struct layout");
|
||||
static_assert(sizeof(rct_ride_entry_vehicle) % 4 == 0, "Invalid struct size");
|
||||
#else
|
||||
static_assert(offsetof(rct_ride_entry_vehicle, peep_loading_positions) % 8 == 0, "Invalid struct layout");
|
||||
static_assert(sizeof(rct_ride_entry_vehicle) % 8 == 0, "Invalid struct size");
|
||||
#endif
|
||||
|
||||
struct rct_vehicle {
|
||||
uint8 sprite_identifier; // 0x00
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#ifndef _SPRITES_H_
|
||||
#define _SPRITES_H_
|
||||
|
||||
#include "rct1/RCT1.h"
|
||||
|
||||
enum {
|
||||
SPR_NONE = -1,
|
||||
|
||||
|
@ -99,7 +101,7 @@ enum {
|
|||
SPR_SHOP_ITEM_MEATBALL_SOUP = 5100,
|
||||
SPR_SHOP_ITEM_FRUIT_JUICE = 5101,
|
||||
SPR_SHOP_ITEM_SOYBEAN_MILK = 5102,
|
||||
SPR_SHOP_ITEM_SU_JONGKWA = 5103,
|
||||
SPR_SHOP_ITEM_SUJEONGGWA = 5103,
|
||||
SPR_SHOP_ITEM_SUB_SANDWICH = 5104,
|
||||
SPR_SHOP_ITEM_COOKIE = 5105,
|
||||
SPR_SHOP_ITEM_EMPTY_BOWL_RED = 5106,
|
||||
|
@ -872,6 +874,13 @@ enum {
|
|||
SPR_CSG_WALL_TEXTURE_STONE_GREY = SPR_CSG_BEGIN + 47376,
|
||||
SPR_CSG_WALL_TEXTURE_SKYSCRAPER_A = SPR_CSG_BEGIN + 47377,
|
||||
SPR_CSG_WALL_TEXTURE_SKYSCRAPER_B = SPR_CSG_BEGIN + 47378,
|
||||
|
||||
SPR_CSG_ICE_CREAM_STALL_BEGIN = SPR_CSG_BEGIN + 60625,
|
||||
SPR_CSG_TOILETS_BEGIN = SPR_CSG_BEGIN + 61289,
|
||||
|
||||
SPR_CSG_RIDE_PREVIEWS_BEGIN = SPR_CSG_BEGIN + 64195,
|
||||
SPR_CSG_RIDE_PREVIEW_ICE_CREAM_STALL = SPR_CSG_RIDE_PREVIEWS_BEGIN + RCT1_RIDE_TYPE_ICE_CREAM_STALL,
|
||||
SPR_CSG_RIDE_PREVIEW_TOILETS = SPR_CSG_RIDE_PREVIEWS_BEGIN + RCT1_RIDE_TYPE_TOILETS,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2822,7 +2822,7 @@ void game_command_place_large_scenery(sint32* eax, sint32* ebx, sint32* ecx, sin
|
|||
sint32 zLow = (tile->z_offset + maxHeight) / 8;
|
||||
sint32 zHigh = (tile->z_clearance / 8) + zLow;
|
||||
|
||||
sint32 bx = tile->var_7 >> 12;
|
||||
sint32 bx = tile->flags >> 12;
|
||||
bx <<= rotation;
|
||||
uint8 bl = bx;
|
||||
uint8 bh = bl >> 4;
|
||||
|
|
|
@ -56,15 +56,22 @@ struct rct_large_scenery_tile {
|
|||
sint16 y_offset;
|
||||
sint16 z_offset;
|
||||
uint8 z_clearance;
|
||||
uint16 var_7;
|
||||
// CCCC WWWW 0SS0 0000
|
||||
uint16 flags;
|
||||
};
|
||||
assert_struct_size(rct_large_scenery_tile, 9);
|
||||
|
||||
enum
|
||||
{
|
||||
LARGE_SCENERY_TILE_FLAG_NO_SUPPORTS = 0x20,
|
||||
LARGE_SCENERY_TILE_FLAG_ALLOW_SUPPORTS_ABOVE = 0x40,
|
||||
};
|
||||
|
||||
struct rct_large_scenery_text_glyph {
|
||||
uint8 image_offset;
|
||||
uint8 width;
|
||||
uint8 height;
|
||||
uint8 var_3;
|
||||
uint8 pad_3;
|
||||
};
|
||||
assert_struct_size(rct_large_scenery_text_glyph, 4);
|
||||
|
||||
|
@ -73,7 +80,7 @@ struct rct_large_scenery_text {
|
|||
uint16 max_width; // 0x8
|
||||
uint16 pad_A; // 0xA
|
||||
uint8 flags; // 0xC
|
||||
uint8 var_D; // 0xD
|
||||
uint8 num_images; // 0xD
|
||||
rct_large_scenery_text_glyph glyphs[256]; // 0xE
|
||||
};
|
||||
assert_struct_size(rct_large_scenery_text, 14 + 4 * 256);
|
||||
|
|
|
@ -222,7 +222,7 @@ static bool WallCheckObstruction(rct_scenery_entry * wall,
|
|||
tile = &entry->large_scenery.tiles[sequence];
|
||||
{
|
||||
sint32 direction = ((edge - tile_element_get_direction(tileElement)) & TILE_ELEMENT_DIRECTION_MASK) + 8;
|
||||
if (!(tile->var_7 & (1 << direction)))
|
||||
if (!(tile->flags & (1 << direction)))
|
||||
{
|
||||
map_obstruction_set_error_text(tileElement);
|
||||
return false;
|
||||
|
|
Loading…
Reference in New Issue