diff --git a/CMakeLists.txt b/CMakeLists.txt index 943d9eb082..f01b8ca80d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -219,6 +219,7 @@ if (APPLE) set_source_files_properties(${ORCT2_MM_SOURCES} PROPERTIES COMPILE_FLAGS "-x objective-c -fmodules") endif (APPLE) + if (APPLE AND NOT USE_MMAP) set(PIE_FLAG "-fno-pie") else () @@ -340,6 +341,7 @@ endif (UNIX AND NOT APPLE) # libopenrct2.dll -> openrct2.dll set_target_properties(${PROJECT} PROPERTIES PREFIX "") +set_target_properties(${PROJECT} PROPERTIES COMPILE_FLAGS "-Wundef") # Link shared libs first TARGET_LINK_LIBRARIES(${PROJECT} ${GLLIBS}) @@ -363,6 +365,16 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/g2.dat" DESTINATION share/${PROJECT}) install(DIRECTORY data/ DESTINATION share/${PROJECT}) install(FILES ${DOC_FILES} DESTINATION share/doc/${PROJECT}) +if (UNIX AND (NOT USE_MMAP) AND (NOT DISABLE_RCT2) AND (NOT FORCE64)) + file(GLOB_RECURSE ORCT2_RIDE_SOURCES "src/ride/*/*.c") + file(GLOB_RECURSE ORCT2_RIDE_DEP_SOURCES "src/ride/ride_data.c" "src/ride/track_data.c" "src/ride/track_data_old.c" "src/ride/track_paint.c" "src/addresses.c" "src/diagnostic.c" "src/hook.c" "src/paint/map_element/map_element.c") + file(GLOB_RECURSE ORCT2_TESTPAINT_SOURCES "test/testpaint/*.c" "test/testpaint/*.cpp" "test/testpaint/*.h") + + add_executable(testpaint EXCLUDE_FROM_ALL ${ORCT2_RIDE_SOURCES} ${ORCT2_RIDE_DEP_SOURCES} ${ORCT2_TESTPAINT_SOURCES} ${RCT2_SECTIONS}) + set_target_properties(testpaint PROPERTIES COMPILE_FLAGS "-DNO_VEHICLES") + add_dependencies(testpaint segfiles) +endif () + set(CPACK_PACKAGE_VERSION_MAJOR 0) set(CPACK_PACKAGE_VERSION_MINOR 0) set(CPACK_PACKAGE_VERSION_PATCH 5) diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 4d3aff2c87..b01faed27b 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -17,11 +17,99 @@ 008BF72C1CDAA5C30019A2AD /* track_design.c in Sources */ = {isa = PBXBuildFile; fileRef = 008BF7281CDAA5C30019A2AD /* track_design.c */; }; 00EFEE721CF1D80B0035213B /* NetworkKey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00EFEE701CF1D80B0035213B /* NetworkKey.cpp */; }; 791166FB1D7486EF005912EA /* NetworkServerAdvertiser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 791166F91D7486EF005912EA /* NetworkServerAdvertiser.cpp */; }; + 85060FD31D8C17CC00DFA2B3 /* track_data_old.c in Sources */ = {isa = PBXBuildFile; fileRef = 8594C05F1D885CF600235E93 /* track_data_old.c */; }; 8594C0601D885CF600235E93 /* track_data_old.c in Sources */ = {isa = PBXBuildFile; fileRef = 8594C05F1D885CF600235E93 /* track_data_old.c */; }; + 85AFA2111D7DB83E00221B42 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 85AFA20F1D7DB83E00221B42 /* main.cpp */; }; + 85B5C0B01D81D912001B99A8 /* intercept_2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 85B5C0AF1D81D912001B99A8 /* intercept_2.cpp */; }; C612A8991D64825300B634CA /* vehicle_data.c in Sources */ = {isa = PBXBuildFile; fileRef = C612A8971D64825300B634CA /* vehicle_data.c */; }; C61FB7201CF6180C004CE991 /* libssl.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38BA1CF3006400659A24 /* libssl.dylib */; }; C61FB7211CF618BA004CE991 /* libssl.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38BA1CF3006400659A24 /* libssl.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; C61FB7241CF86356004CE991 /* NetworkUser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C61FB7221CF86356004CE991 /* NetworkUser.cpp */; }; + C64FDA641D6D9A2100F259B9 /* air_powered_vertical_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8BB1CDBC3B7009F9BFC /* air_powered_vertical_coaster.c */; }; + C64FDA651D6D9A2100F259B9 /* bobsleigh_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8BC1CDBC3B7009F9BFC /* bobsleigh_coaster.c */; }; + C64FDA661D6D9A2100F259B9 /* compact_inverted_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8BD1CDBC3B7009F9BFC /* compact_inverted_coaster.c */; }; + C64FDA671D6D9A2100F259B9 /* corkscrew_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8BE1CDBC3B7009F9BFC /* corkscrew_roller_coaster.c */; }; + C64FDA681D6D9A2100F259B9 /* flying_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8BF1CDBC3B7009F9BFC /* flying_roller_coaster.c */; }; + C64FDA691D6D9A2100F259B9 /* giga_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8C01CDBC3B7009F9BFC /* giga_coaster.c */; }; + C64FDA6A1D6D9A2100F259B9 /* heartline_twister_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8C11CDBC3B7009F9BFC /* heartline_twister_coaster.c */; }; + C64FDA6B1D6D9A2100F259B9 /* inverted_hairpin_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8C21CDBC3B7009F9BFC /* inverted_hairpin_coaster.c */; }; + C64FDA6C1D6D9A2100F259B9 /* inverted_impulse_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8C31CDBC3B7009F9BFC /* inverted_impulse_coaster.c */; }; + C64FDA6D1D6D9A2100F259B9 /* inverted_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8C41CDBC3B7009F9BFC /* inverted_roller_coaster.c */; }; + C64FDA6E1D6D9A2100F259B9 /* junior_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8C51CDBC3B7009F9BFC /* junior_roller_coaster.c */; }; + C64FDA6F1D6D9A2100F259B9 /* lay_down_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8C61CDBC3B7009F9BFC /* lay_down_roller_coaster.c */; }; + C64FDA701D6D9A2100F259B9 /* lim_launched_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8C71CDBC3B7009F9BFC /* lim_launched_roller_coaster.c */; }; + C64FDA711D6D9A2100F259B9 /* looping_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8C81CDBC3B7009F9BFC /* looping_roller_coaster.c */; }; + C64FDA721D6D9A2100F259B9 /* mine_ride.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8C91CDBC3B7009F9BFC /* mine_ride.c */; }; + C64FDA731D6D9A2100F259B9 /* mine_train_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8CA1CDBC3B7009F9BFC /* mine_train_coaster.c */; }; + C64FDA741D6D9A2100F259B9 /* mini_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8CB1CDBC3B7009F9BFC /* mini_roller_coaster.c */; }; + C64FDA751D6D9A2100F259B9 /* mini_suspended_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8CC1CDBC3B7009F9BFC /* mini_suspended_coaster.c */; }; + C64FDA761D6D9A2100F259B9 /* multi_dimension_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8CD1CDBC3B7009F9BFC /* multi_dimension_roller_coaster.c */; }; + C64FDA771D6D9A2100F259B9 /* reverse_freefall_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8CE1CDBC3B7009F9BFC /* reverse_freefall_coaster.c */; }; + C64FDA781D6D9A2100F259B9 /* reverser_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8CF1CDBC3B7009F9BFC /* reverser_roller_coaster.c */; }; + C64FDA791D6D9A2100F259B9 /* side_friction_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8D01CDBC3B7009F9BFC /* side_friction_roller_coaster.c */; }; + C64FDA7A1D6D9A2100F259B9 /* spiral_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8D11CDBC3B7009F9BFC /* spiral_roller_coaster.c */; }; + C64FDA7B1D6D9A2100F259B9 /* stand_up_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8D21CDBC3B7009F9BFC /* stand_up_roller_coaster.c */; }; + C64FDA7C1D6D9A2100F259B9 /* steeplechase.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8D31CDBC3B7009F9BFC /* steeplechase.c */; }; + C64FDA7D1D6D9A2100F259B9 /* suspended_swinging_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8D41CDBC3B7009F9BFC /* suspended_swinging_coaster.c */; }; + C64FDA7E1D6D9A2100F259B9 /* twister_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8D51CDBC3B7009F9BFC /* twister_roller_coaster.c */; }; + C64FDA7F1D6D9A2100F259B9 /* vertical_drop_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8D61CDBC3B7009F9BFC /* vertical_drop_roller_coaster.c */; }; + C64FDA801D6D9A2100F259B9 /* virginia_reel.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8D71CDBC3B7009F9BFC /* virginia_reel.c */; }; + C64FDA811D6D9A2100F259B9 /* wild_mouse.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8D81CDBC3B7009F9BFC /* wild_mouse.c */; }; + C64FDA821D6D9A2100F259B9 /* wooden_roller_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8D91CDBC3B7009F9BFC /* wooden_roller_coaster.c */; }; + C64FDA831D6D9A2100F259B9 /* wooden_wild_mouse.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8DA1CDBC3B7009F9BFC /* wooden_wild_mouse.c */; }; + C64FDA841D6D9A2100F259B9 /* car_ride.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8DC1CDBC3B7009F9BFC /* car_ride.c */; }; + C64FDA851D6D9A2100F259B9 /* circus_show.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8DD1CDBC3B7009F9BFC /* circus_show.c */; }; + C64FDA861D6D9A2100F259B9 /* crooked_house.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8DE1CDBC3B7009F9BFC /* crooked_house.c */; }; + C64FDA871D6D9A2100F259B9 /* dodgems.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8DF1CDBC3B7009F9BFC /* dodgems.c */; }; + C64FDA881D6D9A2100F259B9 /* ferris_wheel.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8E01CDBC3B7009F9BFC /* ferris_wheel.c */; }; + C64FDA891D6D9A2100F259B9 /* flying_saucers.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8E11CDBC3B7009F9BFC /* flying_saucers.c */; }; + C64FDA8A1D6D9A2100F259B9 /* ghost_train.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8E21CDBC3B7009F9BFC /* ghost_train.c */; }; + C64FDA8B1D6D9A2100F259B9 /* haunted_house.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8E31CDBC3B7009F9BFC /* haunted_house.c */; }; + C64FDA8C1D6D9A2100F259B9 /* maze.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8E41CDBC3B7009F9BFC /* maze.c */; }; + C64FDA8D1D6D9A2100F259B9 /* merry_go_round.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8E51CDBC3B7009F9BFC /* merry_go_round.c */; }; + C64FDA8E1D6D9A2100F259B9 /* mini_golf.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8E61CDBC3B7009F9BFC /* mini_golf.c */; }; + C64FDA8F1D6D9A2100F259B9 /* mini_helicopters.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8E71CDBC3B7009F9BFC /* mini_helicopters.c */; }; + C64FDA901D6D9A2100F259B9 /* monorail_cycles.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8E81CDBC3B7009F9BFC /* monorail_cycles.c */; }; + C64FDA911D6D9A2100F259B9 /* observation_tower.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8E91CDBC3B7009F9BFC /* observation_tower.c */; }; + C64FDA921D6D9A2100F259B9 /* space_rings.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8EA1CDBC3B7009F9BFC /* space_rings.c */; }; + C64FDA931D6D9A2100F259B9 /* spiral_slide.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8EB1CDBC3B7009F9BFC /* spiral_slide.c */; }; + C64FDA941D6D9A2100F259B9 /* facility.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8ED1CDBC3B7009F9BFC /* facility.c */; }; + C64FDA951D6D9A2100F259B9 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8EE1CDBC3B7009F9BFC /* misc.c */; }; + C64FDA961D6D9A2100F259B9 /* shop.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8EF1CDBC3B7009F9BFC /* shop.c */; }; + C64FDA971D6D9A2100F259B9 /* 3d_cinema.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8F11CDBC3B7009F9BFC /* 3d_cinema.c */; }; + C64FDA981D6D9A2100F259B9 /* enterprise.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8F21CDBC3B7009F9BFC /* enterprise.c */; }; + C64FDA991D6D9A2100F259B9 /* go_karts.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8F31CDBC3B7009F9BFC /* go_karts.c */; }; + C64FDA9A1D6D9A2100F259B9 /* launched_freefall.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8F41CDBC3B7009F9BFC /* launched_freefall.c */; }; + C64FDA9B1D6D9A2100F259B9 /* magic_carpet.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8F51CDBC3B7009F9BFC /* magic_carpet.c */; }; + C64FDA9C1D6D9A2100F259B9 /* motion_simulator.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8F61CDBC3B7009F9BFC /* motion_simulator.c */; }; + C64FDA9D1D6D9A2100F259B9 /* pirate_ship.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8F71CDBC3B7009F9BFC /* pirate_ship.c */; }; + C64FDA9E1D6D9A2100F259B9 /* roto_drop.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8F81CDBC3B7009F9BFC /* roto_drop.c */; }; + C64FDA9F1D6D9A2100F259B9 /* swinging_inverter_ship.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8F91CDBC3B7009F9BFC /* swinging_inverter_ship.c */; }; + C64FDAA01D6D9A2100F259B9 /* top_spin.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8FA1CDBC3B7009F9BFC /* top_spin.c */; }; + C64FDAA11D6D9A2100F259B9 /* twist.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8FB1CDBC3B7009F9BFC /* twist.c */; }; + C64FDAA21D6D9A2100F259B9 /* chairlift.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8FD1CDBC3B7009F9BFC /* chairlift.c */; }; + C64FDAA31D6D9A2100F259B9 /* lift.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8FE1CDBC3B7009F9BFC /* lift.c */; }; + C64FDAA41D6D9A2100F259B9 /* minature_railway.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F8FF1CDBC3B7009F9BFC /* minature_railway.c */; }; + C64FDAA51D6D9A2100F259B9 /* monorail.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9001CDBC3B7009F9BFC /* monorail.c */; }; + C64FDAA61D6D9A2100F259B9 /* suspended_monorail.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9011CDBC3B7009F9BFC /* suspended_monorail.c */; }; + C64FDAA71D6D9A2100F259B9 /* boat_ride.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9031CDBC3B7009F9BFC /* boat_ride.c */; }; + C64FDAA81D6D9A2100F259B9 /* dingy_slide.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9041CDBC3B7009F9BFC /* dingy_slide.c */; }; + C64FDAA91D6D9A2100F259B9 /* log_flume.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9051CDBC3B7009F9BFC /* log_flume.c */; }; + C64FDAAA1D6D9A2100F259B9 /* river_rafts.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9061CDBC3B7009F9BFC /* river_rafts.c */; }; + C64FDAAB1D6D9A2100F259B9 /* river_rapids.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9071CDBC3B7009F9BFC /* river_rapids.c */; }; + C64FDAAC1D6D9A2100F259B9 /* splash_boats.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9081CDBC3B7009F9BFC /* splash_boats.c */; }; + C64FDAAD1D6D9A2100F259B9 /* submarine_ride.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9091CDBC3B7009F9BFC /* submarine_ride.c */; }; + C64FDAAE1D6D9A2100F259B9 /* water_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F90A1CDBC3B7009F9BFC /* water_coaster.c */; }; + C64FDABC1D6D9C8800F259B9 /* addresses.c in Sources */ = {isa = PBXBuildFile; fileRef = D44270CD1CC81B3200D84D28 /* addresses.c */; }; + C64FDABE1D6D9CD900F259B9 /* ride_data.c in Sources */ = {isa = PBXBuildFile; fileRef = D44271731CC81B3200D84D28 /* ride_data.c */; }; + C64FDABF1D6D9CEA00F259B9 /* map_element.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F89B1CDBC37E009F9BFC /* map_element.c */; }; + C64FDAC01D6D9E3B00F259B9 /* track_data.c in Sources */ = {isa = PBXBuildFile; fileRef = D442717B1CC81B3200D84D28 /* track_data.c */; }; + C64FDAC21D6DA0B800F259B9 /* diagnostic.c in Sources */ = {isa = PBXBuildFile; fileRef = D44270FE1CC81B3200D84D28 /* diagnostic.c */; }; + C64FDAC31D6DA41000F259B9 /* track_paint.c in Sources */ = {isa = PBXBuildFile; fileRef = D442717D1CC81B3200D84D28 /* track_paint.c */; }; + C64FDAC51D6DA55E00F259B9 /* compat.c in Sources */ = {isa = PBXBuildFile; fileRef = C64FDAC41D6DA55E00F259B9 /* compat.c */; }; + C64FDAC81D6DA72400F259B9 /* intercept.c in Sources */ = {isa = PBXBuildFile; fileRef = C64FDAC71D6DA72400F259B9 /* intercept.c */; }; + C64FDACA1D6DA92D00F259B9 /* data.c in Sources */ = {isa = PBXBuildFile; fileRef = C64FDAC91D6DA92D00F259B9 /* data.c */; }; + C64FDACB1D6DBCC700F259B9 /* hook.c in Sources */ = {isa = PBXBuildFile; fileRef = D44271121CC81B3200D84D28 /* hook.c */; }; C650B2191CCABBDD00B4D91C /* S4Importer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C650B2151CCABBDD00B4D91C /* S4Importer.cpp */; }; C650B21A1CCABBDD00B4D91C /* tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C650B2171CCABBDD00B4D91C /* tables.cpp */; }; C650B21C1CCABC4400B4D91C /* ConvertCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C650B21B1CCABC4400B4D91C /* ConvertCommand.cpp */; }; @@ -356,6 +444,15 @@ /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ + C64FDA5B1D6D99F400F259B9 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; D41B74201C210B190080A7B9 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -397,10 +494,18 @@ 791166F91D7486EF005912EA /* NetworkServerAdvertiser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkServerAdvertiser.cpp; sourceTree = ""; }; 791166FA1D7486EF005912EA /* NetworkServerAdvertiser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkServerAdvertiser.h; sourceTree = ""; }; 8594C05F1D885CF600235E93 /* track_data_old.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = track_data_old.c; sourceTree = ""; }; + 85AFA20F1D7DB83E00221B42 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 85AFA2101D7DB83E00221B42 /* intercept.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = intercept.h; sourceTree = ""; }; + 85AFA2141D7DDFA100221B42 /* data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = data.h; sourceTree = ""; }; + 85B5C0AF1D81D912001B99A8 /* intercept_2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = intercept_2.cpp; sourceTree = ""; }; C612A8971D64825300B634CA /* vehicle_data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vehicle_data.c; sourceTree = ""; }; C612A8981D64825300B634CA /* vehicle_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vehicle_data.h; sourceTree = ""; }; C61FB7221CF86356004CE991 /* NetworkUser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkUser.cpp; sourceTree = ""; usesTabs = 0; }; C61FB7231CF86356004CE991 /* NetworkUser.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = NetworkUser.h; sourceTree = ""; usesTabs = 0; }; + C64FDA5D1D6D99F400F259B9 /* PaintTest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = PaintTest; sourceTree = BUILT_PRODUCTS_DIR; }; + C64FDAC41D6DA55E00F259B9 /* compat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compat.c; sourceTree = ""; }; + C64FDAC71D6DA72400F259B9 /* intercept.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intercept.c; sourceTree = ""; }; + C64FDAC91D6DA92D00F259B9 /* data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = data.c; sourceTree = ""; }; C650B2151CCABBDD00B4D91C /* S4Importer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = S4Importer.cpp; sourceTree = ""; usesTabs = 0; }; C650B2161CCABBDD00B4D91C /* S4Importer.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = S4Importer.h; sourceTree = ""; usesTabs = 0; }; C650B2171CCABBDD00B4D91C /* tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tables.cpp; sourceTree = ""; usesTabs = 0; }; @@ -1022,6 +1127,13 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + C64FDA5A1D6D99F400F259B9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; D497D0751C20FD52002BF46A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1042,6 +1154,29 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 8546F74A1D7E1D220004004C /* Tests */ = { + isa = PBXGroup; + children = ( + C64FDA5E1D6D99F400F259B9 /* Paint */, + ); + name = Tests; + sourceTree = ""; + }; + C64FDA5E1D6D99F400F259B9 /* Paint */ = { + isa = PBXGroup; + children = ( + C64FDAC41D6DA55E00F259B9 /* compat.c */, + C64FDAC91D6DA92D00F259B9 /* data.c */, + 85AFA2141D7DDFA100221B42 /* data.h */, + 85B5C0AF1D81D912001B99A8 /* intercept_2.cpp */, + C64FDAC71D6DA72400F259B9 /* intercept.c */, + 85AFA2101D7DB83E00221B42 /* intercept.h */, + 85AFA20F1D7DB83E00221B42 /* main.cpp */, + ); + name = Paint; + path = test/testpaint; + sourceTree = ""; + }; C650B2141CCABBDD00B4D91C /* rct1 */ = { isa = PBXGroup; children = ( @@ -1940,6 +2075,7 @@ children = ( D41B72431C21015A0080A7B9 /* Sources */, D497D07A1C20FD52002BF46A /* Resources */, + 8546F74A1D7E1D220004004C /* Tests */, D41B73ED1C21017D0080A7B9 /* Libraries */, D497D0791C20FD52002BF46A /* Products */, ); @@ -1950,6 +2086,7 @@ isa = PBXGroup; children = ( D497D0781C20FD52002BF46A /* OpenRCT2.app */, + C64FDA5D1D6D99F400F259B9 /* PaintTest */, ); name = Products; sourceTree = ""; @@ -2018,6 +2155,24 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + C64FDA5C1D6D99F400F259B9 /* PaintTest */ = { + isa = PBXNativeTarget; + buildConfigurationList = C64FDA631D6D99F400F259B9 /* Build configuration list for PBXNativeTarget "PaintTest" */; + buildPhases = ( + C64FDAC61D6DA64A00F259B9 /* Create Segment Files */, + C64FDA591D6D99F400F259B9 /* Sources */, + C64FDA5A1D6D99F400F259B9 /* Frameworks */, + C64FDA5B1D6D99F400F259B9 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PaintTest; + productName = PaintTest; + productReference = C64FDA5D1D6D99F400F259B9 /* PaintTest */; + productType = "com.apple.product-type.tool"; + }; D497D0771C20FD52002BF46A /* OpenRCT2 */ = { isa = PBXNativeTarget; buildConfigurationList = D497D0891C20FD53002BF46A /* Build configuration list for PBXNativeTarget "OpenRCT2" */; @@ -2050,6 +2205,9 @@ LastUpgradeCheck = 0800; ORGANIZATIONNAME = OpenRCT2; TargetAttributes = { + C64FDA5C1D6D99F400F259B9 = { + CreatedOnToolsVersion = 7.3.1; + }; D497D0771C20FD52002BF46A = { CreatedOnToolsVersion = 7.2; }; @@ -2069,6 +2227,7 @@ projectRoot = ""; targets = ( D497D0771C20FD52002BF46A /* OpenRCT2 */, + C64FDA5C1D6D99F400F259B9 /* PaintTest */, ); }; /* End PBXProject section */ @@ -2090,6 +2249,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + C64FDAC61D6DA64A00F259B9 /* Create Segment Files */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/openrct2.exe", + ); + name = "Create Segment Files"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/openrct2_text", + "$(DERIVED_FILE_DIR)/openrct2_data", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "dd if=\"${SRCROOT}/openrct2.exe\" of=\"${DERIVED_FILE_DIR}/openrct2_text\" bs=4096 skip=1 count=1187\ndd if=\"${SRCROOT}/openrct2.exe\" of=\"${DERIVED_FILE_DIR}/openrct2_data\" bs=4096 skip=1188 count=318\ndd if=/dev/zero of=\"${DERIVED_FILE_DIR}/openrct2_data\" bs=4096 seek=318 count=2630 conv=notrunc\ndd if=\"${SRCROOT}/openrct2.exe\" of=\"${DERIVED_FILE_DIR}/openrct2_data\" bs=4096 skip=1506 seek=2948 count=1 conv=notrunc"; + }; D40F4E1D1C2528D5009582C9 /* Create Segment Files */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -2186,6 +2362,101 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + C64FDA591D6D99F400F259B9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C64FDACB1D6DBCC700F259B9 /* hook.c in Sources */, + C64FDAC31D6DA41000F259B9 /* track_paint.c in Sources */, + C64FDAC21D6DA0B800F259B9 /* diagnostic.c in Sources */, + C64FDAC01D6D9E3B00F259B9 /* track_data.c in Sources */, + C64FDABF1D6D9CEA00F259B9 /* map_element.c in Sources */, + C64FDABE1D6D9CD900F259B9 /* ride_data.c in Sources */, + C64FDABC1D6D9C8800F259B9 /* addresses.c in Sources */, + C64FDA641D6D9A2100F259B9 /* air_powered_vertical_coaster.c in Sources */, + C64FDA651D6D9A2100F259B9 /* bobsleigh_coaster.c in Sources */, + C64FDA661D6D9A2100F259B9 /* compact_inverted_coaster.c in Sources */, + C64FDA671D6D9A2100F259B9 /* corkscrew_roller_coaster.c in Sources */, + 85AFA2111D7DB83E00221B42 /* main.cpp in Sources */, + C64FDA681D6D9A2100F259B9 /* flying_roller_coaster.c in Sources */, + C64FDA691D6D9A2100F259B9 /* giga_coaster.c in Sources */, + C64FDA6A1D6D9A2100F259B9 /* heartline_twister_coaster.c in Sources */, + C64FDA6B1D6D9A2100F259B9 /* inverted_hairpin_coaster.c in Sources */, + C64FDA6C1D6D9A2100F259B9 /* inverted_impulse_coaster.c in Sources */, + C64FDA6D1D6D9A2100F259B9 /* inverted_roller_coaster.c in Sources */, + C64FDA6E1D6D9A2100F259B9 /* junior_roller_coaster.c in Sources */, + C64FDA6F1D6D9A2100F259B9 /* lay_down_roller_coaster.c in Sources */, + C64FDA701D6D9A2100F259B9 /* lim_launched_roller_coaster.c in Sources */, + C64FDA711D6D9A2100F259B9 /* looping_roller_coaster.c in Sources */, + C64FDAC81D6DA72400F259B9 /* intercept.c in Sources */, + C64FDA721D6D9A2100F259B9 /* mine_ride.c in Sources */, + C64FDA731D6D9A2100F259B9 /* mine_train_coaster.c in Sources */, + C64FDA741D6D9A2100F259B9 /* mini_roller_coaster.c in Sources */, + C64FDA751D6D9A2100F259B9 /* mini_suspended_coaster.c in Sources */, + C64FDA761D6D9A2100F259B9 /* multi_dimension_roller_coaster.c in Sources */, + C64FDA771D6D9A2100F259B9 /* reverse_freefall_coaster.c in Sources */, + C64FDA781D6D9A2100F259B9 /* reverser_roller_coaster.c in Sources */, + C64FDA791D6D9A2100F259B9 /* side_friction_roller_coaster.c in Sources */, + C64FDACA1D6DA92D00F259B9 /* data.c in Sources */, + C64FDA7A1D6D9A2100F259B9 /* spiral_roller_coaster.c in Sources */, + C64FDA7B1D6D9A2100F259B9 /* stand_up_roller_coaster.c in Sources */, + C64FDA7C1D6D9A2100F259B9 /* steeplechase.c in Sources */, + C64FDA7D1D6D9A2100F259B9 /* suspended_swinging_coaster.c in Sources */, + C64FDA7E1D6D9A2100F259B9 /* twister_roller_coaster.c in Sources */, + C64FDA7F1D6D9A2100F259B9 /* vertical_drop_roller_coaster.c in Sources */, + C64FDA801D6D9A2100F259B9 /* virginia_reel.c in Sources */, + C64FDA811D6D9A2100F259B9 /* wild_mouse.c in Sources */, + C64FDA821D6D9A2100F259B9 /* wooden_roller_coaster.c in Sources */, + C64FDA831D6D9A2100F259B9 /* wooden_wild_mouse.c in Sources */, + C64FDA841D6D9A2100F259B9 /* car_ride.c in Sources */, + C64FDA851D6D9A2100F259B9 /* circus_show.c in Sources */, + C64FDA861D6D9A2100F259B9 /* crooked_house.c in Sources */, + 85060FD31D8C17CC00DFA2B3 /* track_data_old.c in Sources */, + C64FDA871D6D9A2100F259B9 /* dodgems.c in Sources */, + C64FDA881D6D9A2100F259B9 /* ferris_wheel.c in Sources */, + C64FDA891D6D9A2100F259B9 /* flying_saucers.c in Sources */, + C64FDA8A1D6D9A2100F259B9 /* ghost_train.c in Sources */, + C64FDA8B1D6D9A2100F259B9 /* haunted_house.c in Sources */, + C64FDA8C1D6D9A2100F259B9 /* maze.c in Sources */, + C64FDA8D1D6D9A2100F259B9 /* merry_go_round.c in Sources */, + C64FDA8E1D6D9A2100F259B9 /* mini_golf.c in Sources */, + C64FDA8F1D6D9A2100F259B9 /* mini_helicopters.c in Sources */, + C64FDA901D6D9A2100F259B9 /* monorail_cycles.c in Sources */, + 85B5C0B01D81D912001B99A8 /* intercept_2.cpp in Sources */, + C64FDA911D6D9A2100F259B9 /* observation_tower.c in Sources */, + C64FDA921D6D9A2100F259B9 /* space_rings.c in Sources */, + C64FDA931D6D9A2100F259B9 /* spiral_slide.c in Sources */, + C64FDA941D6D9A2100F259B9 /* facility.c in Sources */, + C64FDAC51D6DA55E00F259B9 /* compat.c in Sources */, + C64FDA951D6D9A2100F259B9 /* misc.c in Sources */, + C64FDA961D6D9A2100F259B9 /* shop.c in Sources */, + C64FDA971D6D9A2100F259B9 /* 3d_cinema.c in Sources */, + C64FDA981D6D9A2100F259B9 /* enterprise.c in Sources */, + C64FDA991D6D9A2100F259B9 /* go_karts.c in Sources */, + C64FDA9A1D6D9A2100F259B9 /* launched_freefall.c in Sources */, + C64FDA9B1D6D9A2100F259B9 /* magic_carpet.c in Sources */, + C64FDA9C1D6D9A2100F259B9 /* motion_simulator.c in Sources */, + C64FDA9D1D6D9A2100F259B9 /* pirate_ship.c in Sources */, + C64FDA9E1D6D9A2100F259B9 /* roto_drop.c in Sources */, + C64FDA9F1D6D9A2100F259B9 /* swinging_inverter_ship.c in Sources */, + C64FDAA01D6D9A2100F259B9 /* top_spin.c in Sources */, + C64FDAA11D6D9A2100F259B9 /* twist.c in Sources */, + C64FDAA21D6D9A2100F259B9 /* chairlift.c in Sources */, + C64FDAA31D6D9A2100F259B9 /* lift.c in Sources */, + C64FDAA41D6D9A2100F259B9 /* minature_railway.c in Sources */, + C64FDAA51D6D9A2100F259B9 /* monorail.c in Sources */, + C64FDAA61D6D9A2100F259B9 /* suspended_monorail.c in Sources */, + C64FDAA71D6D9A2100F259B9 /* boat_ride.c in Sources */, + C64FDAA81D6D9A2100F259B9 /* dingy_slide.c in Sources */, + C64FDAA91D6D9A2100F259B9 /* log_flume.c in Sources */, + C64FDAAA1D6D9A2100F259B9 /* river_rafts.c in Sources */, + C64FDAAB1D6D9A2100F259B9 /* river_rapids.c in Sources */, + C64FDAAC1D6D9A2100F259B9 /* splash_boats.c in Sources */, + C64FDAAD1D6D9A2100F259B9 /* submarine_ride.c in Sources */, + C64FDAAE1D6D9A2100F259B9 /* water_coaster.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; D497D0741C20FD52002BF46A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2518,6 +2789,112 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ + C64FDA611D6D99F400F259B9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "-"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + "NO_VEHICLES=1", + ); + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/libxc/include", + "$(SRCROOT)/libxc/include/SDL2", + ); + LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/libxc/lib"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + OTHER_LDFLAGS = ( + "-sectcreate", + rct2_text, + __text, + "$(DERIVED_FILE_DIR)/openrct2_text", + "-segaddr", + rct2_text, + 0x401000, + "-segprot", + rct2_text, + rwx, + rx, + "-sectcreate", + rct2_data, + __data, + "$(DERIVED_FILE_DIR)/openrct2_data", + "-segaddr", + rct2_data, + 0x8a4000, + "-segprot", + rct2_data, + rw, + rw, + "-segaddr", + __TEXT, + 0x2000000, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + C64FDA621D6D99F400F259B9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_IDENTITY = "-"; + GCC_PREPROCESSOR_DEFINITIONS = ( + OPENGL_NO_LINK, + "OPENRCT2_BUILD_INFO_HEADER=\"\\\"$(DERIVED_FILE_DIR)/gitversion.h\\\"\"", + "NO_VEHICLES=1", + ); + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(SRCROOT)/libxc/include", + "$(SRCROOT)/libxc/include/SDL2", + ); + LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/libxc/lib"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + OTHER_LDFLAGS = ( + "-sectcreate", + rct2_text, + __text, + "$(DERIVED_FILE_DIR)/openrct2_text", + "-segaddr", + rct2_text, + 0x401000, + "-segprot", + rct2_text, + rwx, + rx, + "-sectcreate", + rct2_data, + __data, + "$(DERIVED_FILE_DIR)/openrct2_data", + "-segaddr", + rct2_data, + 0x8a4000, + "-segprot", + rct2_data, + rw, + rw, + "-segaddr", + __TEXT, + 0x2000000, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; D497D0871C20FD53002BF46A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2716,6 +3093,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + C64FDA631D6D99F400F259B9 /* Build configuration list for PBXNativeTarget "PaintTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C64FDA611D6D99F400F259B9 /* Debug */, + C64FDA621D6D99F400F259B9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; D497D0731C20FD52002BF46A /* Build configuration list for PBXProject "OpenRCT2" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/OpenRCT2.xcodeproj/xcshareddata/xcschemes/PaintTest.xcscheme b/OpenRCT2.xcodeproj/xcshareddata/xcschemes/PaintTest.xcscheme new file mode 100644 index 0000000000..4262704c01 --- /dev/null +++ b/OpenRCT2.xcodeproj/xcshareddata/xcschemes/PaintTest.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openrct2.proj b/openrct2.proj index d036d7468f..73dd8ca493 100644 --- a/openrct2.proj +++ b/openrct2.proj @@ -13,10 +13,9 @@ - - - + Debug + Win32 $(COMPUTERNAME) $(GIT_COMMIT_SHA1.Substring(0, 7)) @@ -36,12 +35,13 @@ $(MsBuildThisFileDirectory) $(RootDir)distribution\ $(RootDir)artifacts\ + $(RootDir)bin\ $(DistDir)windows\install.nsi $(TargetDir)openrct2.dll $(TargetDir)openrct2.exe - $(TargetPath) + $(TargetDir)openrct2_x64.exe $(TargetDir)openrct2_data $(TargetDir)data\g2.dat @@ -75,7 +75,7 @@ - + @@ -141,7 +141,7 @@ - + @@ -154,9 +154,10 @@ + - + $(GIT_COMMIT_SHA1_SHORT) $(BuildString) ($(GIT_BRANCH)) @@ -169,6 +170,20 @@ + + + + + + + + + + + + + + diff --git a/openrct2.sln b/openrct2.sln index a23532f33a..a9f6803221 100644 --- a/openrct2.sln +++ b/openrct2.sln @@ -5,6 +5,12 @@ VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openrct2", "openrct2.vcxproj", "{D24D94F6-2A74-480C-B512-629C306CE92F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testpaint", "test\testpaint\testpaint.vcxproj", "{57E60BA1-FB76-4316-909E-C1449C142327}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2202A816-377D-4FA0-A7AF-7D4105F8A4FB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{480B577D-4E4A-4757-9A42-28A9AD33E6B0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -21,8 +27,18 @@ Global {D24D94F6-2A74-480C-B512-629C306CE92F}.Release|Win32.Build.0 = Release|Win32 {D24D94F6-2A74-480C-B512-629C306CE92F}.Release|x64.ActiveCfg = Release|x64 {D24D94F6-2A74-480C-B512-629C306CE92F}.Release|x64.Build.0 = Release|x64 + {57E60BA1-FB76-4316-909E-C1449C142327}.Debug|Win32.ActiveCfg = Debug|Win32 + {57E60BA1-FB76-4316-909E-C1449C142327}.Debug|Win32.Build.0 = Debug|Win32 + {57E60BA1-FB76-4316-909E-C1449C142327}.Debug|x64.ActiveCfg = Debug|Win32 + {57E60BA1-FB76-4316-909E-C1449C142327}.Release|Win32.ActiveCfg = Release|Win32 + {57E60BA1-FB76-4316-909E-C1449C142327}.Release|Win32.Build.0 = Release|Win32 + {57E60BA1-FB76-4316-909E-C1449C142327}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D24D94F6-2A74-480C-B512-629C306CE92F} = {2202A816-377D-4FA0-A7AF-7D4105F8A4FB} + {57E60BA1-FB76-4316-909E-C1449C142327} = {480B577D-4E4A-4757-9A42-28A9AD33E6B0} + EndGlobalSection EndGlobal diff --git a/src/openrct2.c b/src/openrct2.c index 94a9546c67..44c980e5c7 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -594,7 +594,7 @@ bool openrct2_setup_rct2_segment() } #if !defined(USE_MMAP) // section: text - err = mprotect((void *)0x401000, 0x8a4000 - 0x401000, PROT_READ | PROT_EXEC); + err = mprotect((void *)0x401000, 0x8a4000 - 0x401000, PROT_READ | PROT_EXEC | PROT_WRITE); if (err != 0) { perror("mprotect"); diff --git a/src/ride/coaster/junior_roller_coaster.c b/src/ride/coaster/junior_roller_coaster.c index d0f1adce1c..3c0c3a9c3c 100644 --- a/src/ride/coaster/junior_roller_coaster.c +++ b/src/ride/coaster/junior_roller_coaster.c @@ -4570,15 +4570,6 @@ TRACK_PAINT_FUNCTION get_track_paint_function_junior_rc(int trackType, int direc case TRACK_ELEM_RIGHT_QUARTER_TURN_3_TILES_25_DEG_DOWN: return junior_rc_right_quarter_turn_3_tiles_25_deg_down_paint_setup; - case TRACK_ELEM_FLAT_TO_60_DEG_UP: - return junior_rc_flat_to_60_deg_up_paint_setup; - case TRACK_ELEM_60_DEG_UP_TO_FLAT: - return junior_rc_60_deg_up_to_flat_paint_setup; - case TRACK_ELEM_FLAT_TO_60_DEG_DOWN: - return junior_rc_flat_to_60_deg_down_paint_setup; - case TRACK_ELEM_60_DEG_DOWN_TO_FLAT: - return junior_rc_60_deg_down_to_flat_paint_setup; - case TRACK_ELEM_LEFT_HALF_BANKED_HELIX_UP_SMALL: return junior_rc_left_half_banked_helix_up_small_paint_setup; case TRACK_ELEM_RIGHT_HALF_BANKED_HELIX_UP_SMALL: diff --git a/src/ride/coaster/reverser_roller_coaster.c b/src/ride/coaster/reverser_roller_coaster.c index 4644c323de..fbcfd0ca7e 100644 --- a/src/ride/coaster/reverser_roller_coaster.c +++ b/src/ride/coaster/reverser_roller_coaster.c @@ -21,6 +21,7 @@ #include "../../paint/paint.h" #include "../vehicle_paint.h" +#ifndef NO_VEHICLES /** * * rct2: 0x006D4453 @@ -36,3 +37,4 @@ void vehicle_visual_reverser(int x, int imageDirection, int y, int z, rct_vehicl gUnk9DE56C = y; vehicle_visual_default(x, imageDirection, y, z, vehicle, vehicleEntry); } +#endif diff --git a/src/ride/track_data_old.c b/src/ride/track_data_old.c index 86d3bfe498..d8530f1aa6 100644 --- a/src/ride/track_data_old.c +++ b/src/ride/track_data_old.c @@ -3204,8 +3204,8 @@ static const uint32 _OldLaunchedFreefallTrackPaintFunctions[256] = { 0, 0, 0, - 0, - 0, + 0x006FD1F8, // TRACK_ELEM_TOWER_BASE + 0x006FD208, // TRACK_ELEM_TOWER_SECTION 0, 0, 0, diff --git a/src/ride/water/river_rapids.c b/src/ride/water/river_rapids.c index fb7d67c7fd..8faa3da43e 100644 --- a/src/ride/water/river_rapids.c +++ b/src/ride/water/river_rapids.c @@ -183,6 +183,7 @@ static const uint32 river_rapids_track_pieces_25_deg_down_to_flat[][2] = { {SPR_RIVER_RAPIDS_25_DEG_DOWN_TO_FLAT_SE_NW, SPR_RIVER_RAPIDS_25_DEG_DOWN_TO_FLAT_FRONT_SE_NW}, }; +#ifndef NO_VEHICLES /** * * rct2: 0x006D5889 @@ -248,6 +249,7 @@ void vehicle_visual_river_rapids(int x, int imageDirection, int y, int z, rct_ve vehicle_visual_splash_effect(z, vehicle, vehicleEntry); } +#endif /** rct2: 0x00757650 */ static void paint_river_rapids_track_flat(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element * mapElement) diff --git a/src/ride/water/splash_boats.c b/src/ride/water/splash_boats.c index 9bb7eb7877..f73c941482 100644 --- a/src/ride/water/splash_boats.c +++ b/src/ride/water/splash_boats.c @@ -21,6 +21,7 @@ #include "../../paint/paint.h" #include "../vehicle_paint.h" +#ifndef NO_VEHICLES /** * * rct2: 0x006D4295 @@ -38,3 +39,4 @@ void vehicle_visual_splash_boats_or_water_coaster(int x, int imageDirection, int gUnk9DE56C = vehicle->y; vehicle_paint(vehicle, imageDirection); } +#endif diff --git a/src/ride/water/submarine_ride.c b/src/ride/water/submarine_ride.c index 6284169b99..f1e4f95f4e 100644 --- a/src/ride/water/submarine_ride.c +++ b/src/ride/water/submarine_ride.c @@ -23,6 +23,7 @@ #include "../../paint/supports.h" #include "../ride_data.h" +#ifndef NO_VEHICLES /** * * rct2: 0x006D44D5 @@ -66,6 +67,7 @@ void vehicle_visual_submarine(int x, int imageDirection, int y, int z, rct_vehic assert(vehicleEntry->effect_visual == 1); } +#endif static void submarine_ride_paint_track_station(uint8 rideIndex, uint8 trackSequence, uint8 direction, int height, rct_map_element * mapElement) { diff --git a/test/testpaint/compat.c b/test/testpaint/compat.c new file mode 100644 index 0000000000..5ff4bd9855 --- /dev/null +++ b/test/testpaint/compat.c @@ -0,0 +1,153 @@ +#pragma region Copyright (c) 2014-2016 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 "../../src/config.h" +#include "../../src/object.h" +#include "../../src/interface/colour.h" +#include "../../src/interface/viewport.h" +#include "../../src/ride/ride.h" +#include "../../src/ride/track.h" +#include "../../src/world/sprite.h" +#include "../../src/paint/map_element/map_element.h" + +#define RCT2_ADDRESS_SPRITE_LIST 0x010E63BC + +#define gRideEntries RCT2_ADDRESS(RCT2_ADDRESS_RIDE_ENTRIES, rct_ride_entry*) +#define gCurrentRotation RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8) + +rct_map_element *gMapElements = (rct_map_element *) RCT2_ADDRESS_MAP_ELEMENTS; +rct_map_element **gMapElementTilePointers = (rct_map_element **) RCT2_ADDRESS_TILE_MAP_ELEMENT_POINTERS; +rct_ride *gRideList = RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride); +rct_sprite *sprite_list = RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite); +sint16 gMapSizeUnits; +sint16 gMapBaseZ; +bool gTrackDesignSaveMode = false; +uint8 gTrackDesignSaveRideIndex = 255; + +const rct_xy16 TileDirectionDelta[] = { + {-32, 0}, + {0, +32}, + {+32, 0}, + {0, -32}, + {-32, +32}, + {+32, +32}, + {+32, -32}, + {-32, -32} +}; + +uint8 get_current_rotation() { + return gCurrentRotation & 3; +} + +const uint32 construction_markers[] = { + COLOUR_DARK_GREEN << 19 | COLOUR_GREY << 24 | IMAGE_TYPE_REMAP, // White + 2 << 19 | 0b110000 << 19 | IMAGE_TYPE_TRANSPARENT, // Translucent +}; + +int object_entry_group_counts[] = { + 128, // rides + 252, // small scenery + 128, // large scenery + 128, // walls + 32, // banners + 16, // paths + 15, // path bits + 19, // scenery sets + 1, // park entrance + 1, // water + 1 // scenario text +}; + + +general_configuration gConfigGeneral; +uint32 gCurrentViewportFlags = 0; +uint16 gMapSelectFlags; +uint16 gMapSelectType; +rct_xy16 gMapSelectPositionA; +rct_xy16 gMapSelectPositionB; +rct_xyz16 gMapSelectArrowPosition; +uint8 gMapSelectArrowDirection; + +void entrance_paint(uint8 direction, int height, rct_map_element *map_element) { } +void banner_paint(uint8 direction, int height, rct_map_element *map_element) { } +void surface_paint(uint8 direction, uint16 height, rct_map_element *mapElement) { } +void path_paint(uint8 direction, uint16 height, rct_map_element *mapElement) { } +void scenery_paint(uint8 direction, int height, rct_map_element *mapElement) { } +void fence_paint(uint8 direction, int height, rct_map_element *mapElement) { } +void scenery_multiple_paint(uint8 direction, uint16 height, rct_map_element *mapElement) { } + +rct_ride *get_ride(int index) { + if (index < 0 || index >= MAX_RIDES) { + log_error("invalid index %d for ride", index); + return NULL; + } + return &gRideList[index]; +} + +rct_ride_entry *get_ride_entry(int index) { + if (index < 0 || index >= object_entry_group_counts[OBJECT_TYPE_RIDE]) { + log_error("invalid index %d for ride type", index); + return NULL; + } + return gRideEntries[index]; +} + +rct_ride_entry *get_ride_entry_by_ride(rct_ride *ride) { + rct_ride_entry *type = get_ride_entry(ride->subtype); + if (type == NULL) { + log_error("Invalid ride subtype for ride"); + } + return type; +} + +rct_sprite *get_sprite(size_t sprite_idx) { + assert(sprite_idx < MAX_SPRITES); + return &sprite_list[sprite_idx]; +} + +int map_element_is_last_for_tile(const rct_map_element *element) { + return element->flags & MAP_ELEMENT_FLAG_LAST_TILE; +} + +int map_element_get_type(const rct_map_element *element) { + return element->type & MAP_ELEMENT_TYPE_MASK; +} + +int map_element_get_direction(const rct_map_element *element) { + return element->type & MAP_ELEMENT_DIRECTION_MASK; +} + +rct_map_element *map_get_first_element_at(int x, int y) { + if (x < 0 || y < 0 || x > 255 || y > 255) { + log_error("Trying to access element outside of range"); + return NULL; + } + return gMapElementTilePointers[x + y * 256]; +} + +int map_get_station(rct_map_element *mapElement) { + return (mapElement->properties.track.sequence & 0x70) >> 4; +} + +bool ride_type_has_flag(int rideType, int flag) +{ + return (RideProperties[rideType].flags & flag) != 0; +} + +sint16 get_height_marker_offset() +{ + return 0; +} diff --git a/test/testpaint/data.c b/test/testpaint/data.c new file mode 100644 index 0000000000..39b98da4a8 --- /dev/null +++ b/test/testpaint/data.c @@ -0,0 +1,628 @@ +#pragma region Copyright (c) 2014-2016 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 "../../src/common.h" + +const utf8string RideNames[91] = { + "SpiralRollerCoaster", + "StandUpRollerCoaster", + "SuspendedSwingingCoaster", + "InvertedRollerCoaster", + "JuniorRollerCoaster", + "MiniatureRailway", + "Monorail", + "MiniSuspendedCoaster", + "BoatRide", + "WoodenWildMouse", + "Steeplechase", + "CarRide", + "LaunchedFreefall", + "BobsleighCoaster", + "ObservationTower", + "LoopingRollerCoaster", + "DinghySlide", + "MineTrainCoaster", + "Chairlift", + "CorkscrewRollerCoaster", + "Maze", + "SpiralSlide", + "GoKarts", + "LogFlume", + "RiverRapids", + "Dodgems", + "PirateShip", + "SwingingInverterShip", + "FoodStall", + "1D", + "DrinkStall", + "1F", + "Shop", + "MerryGoRound", + "22", + "InformationKiosk", + "Toilets", + "FerrisWheel", + "MotionSimulator", + "3DCinema", + "TopSpin", + "SpaceRings", + "ReverseFreefallCoaster", + "Lift", + "VerticalDropRollerCoaster", + "CashMachine", + "Twist", + "HauntedHouse", + "FirstAid", + "CircusShow", + "GhostTrain", + "TwisterRollerCoaster", + "WoodenRollerCoaster", + "SideFrictionRollerCoaster", + "WildMouse", + "MultiDimensionRollerCoaster", + "MultiDimensionRollerCoasterAlt", + "FlyingRollerCoaster", + "FlyingRollerCoasterAlt", + "VirginiaReel", + "SplashBoats", + "MiniHelicopters", + "LayDownRollerCoaster", + "SuspendedMonorail", + "LayDownRollerCoasterAlt", + "ReverserRollerCoaster", + "HeartlineTwisterCoaster", + "MiniGolf", + "GigaCoaster", + "RoToDrop", + "FlyingSaucers", + "CrookedHouse", + "MonorailCycles", + "CompactInvertedCoaster", + "WaterCoaster", + "AirPoweredVerticalCoaster", + "InvertedHairpinCoaster", + "MagicCarpet", + "SubmarineRide", + "RiverRafts", + "50", + "Enterprise", + "52", + "53", + "54", + "55", + "InvertedImpulseCoaster", + "MiniRollerCoaster", + "MineRide", + "59", + "LimLaunchedRollerCoaster", +}; + +const utf8string TrackNames[256] = { + "Flat", + "EndStation", + "BeginStation", + "MiddleStation", + "25DegUp", + "60DegUp", + "FlatTo25DegUp", + "25DegUpTo60DegUp", + "60DegUpTo25DegUp", + "25DegUpToFlat", + "25DegDown", + "60DegDown", + "FlatTo25DegDown", + "25DegDownTo60DegDown", + "60DegDownTo25DegDown", + "25DegDownToFlat", + "LeftQuarterTurn5Tiles", + "RightQuarterTurn5Tiles", + "FlatToLeftBank", + "FlatToRightBank", + "LeftBankToFlat", + "RightBankToFlat", + "BankedLeftQuarterTurn5Tiles", + "BankedRightQuarterTurn5Tiles", + "LeftBankTo25DegUp", + "RightBankTo25DegUp", + "25DegUpToLeftBank", + "25DegUpToRightBank", + "LeftBankTo25DegDown", + "RightBankTo25DegDown", + "25DegDownToLeftBank", + "25DegDownToRightBank", + "LeftBank", + "RightBank", + "LeftQuarterTurn5Tiles25DegUp", + "RightQuarterTurn5Tiles25DegUp", + "LeftQuarterTurn5Tiles25DegDown", + "RightQuarterTurn5Tiles25DegDown", + "SBendLeft", + "SBendRight", + "LeftVerticalLoop", + "RightVerticalLoop", + "LeftQuarterTurn3Tiles", + "RightQuarterTurn3Tiles", + "LeftQuarterTurn3TilesBank", + "RightQuarterTurn3TilesBank", + "LeftQuarterTurn3Tiles25DegUp", + "RightQuarterTurn3Tiles25DegUp", + "LeftQuarterTurn3Tiles25DegDown", + "RightQuarterTurn3Tiles25DegDown", + "LeftQuarterTurn1Tile", + "RightQuarterTurn1Tile", + "LeftTwistDownToUp", + "RightTwistDownToUp", + "LeftTwistUpToDown", + "RightTwistUpToDown", + "HalfLoopUp", + "HalfLoopDown", + "LeftCorkscrewUp", + "RightCorkscrewUp", + "LeftCorkscrewDown", + "RightCorkscrewDown", + "FlatTo60DegUp", + "60DegUpToFlat", + "FlatTo60DegDown", + "60DegDownToFlat", + "TowerBase", + "TowerSection", + "FlatCovered", + "25DegUpCovered", + "60DegUpCovered", + "FlatTo25DegUpCovered", + "25DegUpTo60DegUpCovered", + "60DegUpTo25DegUpCovered", + "25DegUpToFlatCovered", + "25DegDownCovered", + "60DegDownCovered", + "FlatTo25DegDownCovered", + "25DegDownTo60DegDownCovered", + "60DegDownTo25DegDownCovered", + "25DegDownToFlatCovered", + "LeftQuarterTurn5TilesCovered", + "RightQuarterTurn5TilesCovered", + "SBendLeftCovered", + "SBendRightCovered", + "LeftQuarterTurn3TilesCovered", + "RightQuarterTurn3TilesCovered", + "LeftHalfBankedHelixUpSmall", + "RightHalfBankedHelixUpSmall", + "LeftHalfBankedHelixDownSmall", + "RightHalfBankedHelixDownSmall", + "LeftHalfBankedHelixUpLarge", + "RightHalfBankedHelixUpLarge", + "LeftHalfBankedHelixDownLarge", + "RightHalfBankedHelixDownLarge", + "LeftQuarterTurn1Tile60DegUp", + "RightQuarterTurn1Tile60DegUp", + "LeftQuarterTurn1Tile60DegDown", + "RightQuarterTurn1Tile60DegDown", + "Brakes", + "RotationControlToggle", + "Inverted90DegUpToFlatQuarterLoop_Maze", + "LeftQuarterBankedHelixLargeUp", + "RightQuarterBankedHelixLargeUp", + "LeftQuarterBankedHelixLargeDown", + "RightQuarterBankedHelixLargeDown", + "LeftQuarterHelixLargeUp", + "RightQuarterHelixLargeUp", + "LeftQuarterHelixLargeDown", + "RightQuarterHelixLargeDown", + "25DegUpLeftBanked", + "25DegUpRightBanked", + "Waterfall", + "Rapids", + "OnRidePhoto", + "25DegDownLeftBanked", + "25DegDownRightBanked", + "WaterSplash", + "FlatTo60DegUpLongBase", + "60DegUpToFlatLongBase", + "Whirlpool", + "FlatTo60DegDownLongBase", + "60DegUpToFlatLongBase122", + "CableLiftHill", + "ReverseWhoaBellySlope", + "ReverseWhoaBellyVertical", + "90DegUp", + "90DegDown", + "60DegUpTo90DegUp", + "90DegDownTo60DegDown", + "90DegUpTo60DegUp", + "60DegDownTo90DegDown", + "BrakeForDrop", + "LeftEighthToDiag", + "RightEighthToDiag", + "LeftEighthToOrthogonal", + "RightEighthToOrthogonal", + "LeftEighthBankToDiag", + "RightEighthBankToDiag", + "LeftEighthBankToOrthogonal", + "RightEighthBankToOrthogonal", + "DiagFlat", + "Diag25DegUp", + "Diag60DegUp", + "DiagFlatTo25DegUp", + "Diag25DegUpTo60DegUp", + "Diag60DegUpTo25DegUp", + "Diag25DegUpToFlat", + "Diag25DegDown", + "Diag60DegDown", + "DiagFlatTo25DegDown", + "Diag25DegDownTo60DegDown", + "Diag60DegDownTo25DegDown", + "Diag25DegDownToFlat", + "DiagFlatTo60DegUp", + "Diag60DegUpToFlat", + "DiagFlatTo60DegDown", + "Diag60DegDownToFlat", + "DiagFlatToLeftBank", + "DiagFlatToRightBank", + "DiagLeftBankToFlat", + "DiagRightBankToFlat", + "DiagLeftBankTo25DegUp", + "DiagRightBankTo25DegUp", + "Diag25DegUpToLeftBank", + "Diag25DegUpToRightBank", + "DiagLeftBankTo25DegDown", + "DiagRightBankTo25DegDown", + "Diag25DegDownToLeftBank", + "Diag25DegDownToRightBank", + "DiagLeftBank", + "DiagRightBank", + "LogFlumeReverser", + "SpinningTunnel", + "LeftBarrelRollUpToDown", + "RightBarrelRollUpToDown", + "LeftBarrelRollDownToUp", + "RightBarrelRollDownToUp", + "LeftBankToLeftQuarterTurn3Tiles25DegUp", + "RightBankToRightQuarterTurn3Tiles25DegUp", + "LeftQuarterTurn3Tiles25DegDownToLeftBank", + "RightQuarterTurn3Tiles25DegDownToRightBank", + "PoweredLift", + "LeftLargeHalfLoopUp", + "RightLargeHalfLoopUp", + "RightLargeHalfLoopDown", + "LeftLargeHalfLoopDown", + "LeftFlyerTwistUp", + "RightFlyerTwistUp", + "LeftFlyerTwistDown", + "RightFlyerTwistDown", + "FlyerHalfLoopUp", + "FlyerHalfLoopDown", + "LeftFlyerCorkscrewUp", + "RightFlyerCorkscrewUp", + "LeftFlyerCorkscrewDown", + "RightFlyerCorkscrewDown", + "HeartlineTransferUp", + "HeartlineTransferDown", + "LeftHeartlineRoll", + "RightHeartlineRoll", + "MiniGolfHoleA", + "MiniGolfHoleB", + "MiniGolfHoleC", + "MiniGolfHoleD", + "MiniGolfHoleE", + "MultidimInvertedFlatTo90DegQuarterLoopDown", + "90DegToInvertedFlatQuarterLoopUp", + "InvertedFlatTo90DegQuarterLoopDown", + "LeftCurvedLiftHill", + "RightCurvedLiftHill", + "LeftReverser", + "RightReverser", + "AirThrustTopCap", + "AirThrustVerticalDown", + "AirThrustVerticalDownToLevel", + "BlockBrakes", + "LeftBankedQuarterTurn3Tile25DegUp", + "RightBankedQuarterTurn3Tile25DegUp", + "LeftBankedQuarterTurn3Tile25DegDown", + "RightBankedQuarterTurn3Tile25DegDown", + "LeftBankedQuarterTurn5Tile25DegUp", + "RightBankedQuarterTurn5Tile25DegUp", + "LeftBankedQuarterTurn5Tile25DegDown", + "RightBankedQuarterTurn5Tile25DegDown", + "25DegUpToLeftBanked25DegUp", + "25DegUpToRightBanked25DegUp", + "LeftBanked25DegUpTo25DegUp", + "RightBanked25DegUpTo25DegUp", + "25DegDownToLeftBanked25DegDown", + "25DegDownToRightBanked25DegDown", + "LeftBanked25DegDownTo25DegDown", + "RightBanked25DegDownTo25DegDown", + "LeftBankedFlatToLeftBanked25DegUp", + "RightBankedFlatToRightBanked25DegUp", + "LeftBanked25DegUpToLeftBankedFlat", + "RightBanked25DegUpToRightBankedFlat", + "LeftBankedFlatToLeftBanked25DegDown", + "RightBankedFlatToRightBanked25DegDown", + "LeftBanked25DegDownToLeftBankedFlat", + "RightBanked25DegDownToRightBankedFlat", + "FlatToLeftBanked25DegUp", + "FlatToRightBanked25DegUp", + "LeftBanked25DegUpToFlat", + "RightBanked25DegUpToFlat", + "FlatToLeftBanked25DegDown", + "FlatToRightBanked25DegDown", + "LeftBanked25DegDownToFlat", + "RightBanked25DegDownToFlat", + "LeftQuarterTurn1Tile90DegUp", + "RightQuarterTurn1Tile90DegUp", + "LeftQuarterTurn1Tile90DegDown", + "RightQuarterTurn1Tile90DegDown", + "Multidim90DegUpToInvertedFlatQuarterLoop", + "MultidimFlatTo90DegDownQuarterLoop", +}; + +const utf8string FlatTrackNames[256] = { + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "1x4_A", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "2x2", + "4x4", + "", + "", + "", + "", + "1x5", + "", + "1x1_A", + "1x4_B", + "", + "1x1_B", + "1x4_C", + "3x3", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", +}; diff --git a/test/testpaint/data.h b/test/testpaint/data.h new file mode 100644 index 0000000000..9e685786ed --- /dev/null +++ b/test/testpaint/data.h @@ -0,0 +1,26 @@ +#pragma region Copyright (c) 2014-2016 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 + +#ifndef _TEST_PAINT_DATA_H_ +#define _TEST_PAINT_DATA_H_ + +#include "../../src/common.h" + +extern const utf8string RideNames[91]; +extern const utf8string TrackNames[256]; +extern const utf8string FlatTrackNames[256]; + +#endif // #endif _TEST_PAINT_DATA_H_ diff --git a/test/testpaint/intercept.c b/test/testpaint/intercept.c new file mode 100644 index 0000000000..6a44c3423e --- /dev/null +++ b/test/testpaint/intercept.c @@ -0,0 +1,747 @@ +#pragma region Copyright (c) 2014-2016 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 "intercept.h" +#include "../../src/paint/paint.h" +#include "../../src/paint/supports.h" +#include "../../src/ride/track_data.h" +#include "../../src/interface/viewport.h" +#include "../../src/hook.h" + + +static const uint32 DEFAULT_SCHEME_TRACK = COLOUR_GREY << 19 | COLOUR_WHITE << 24 | 0xA0000000; +static const uint32 DEFAULT_SCHEME_SUPPORTS = COLOUR_LIGHT_BLUE << 19 | COLOUR_ICY_BLUE << 24 | 0xA0000000; +static const uint32 DEFAULT_SCHEME_MISC = COLOUR_DARK_PURPLE << 19 | COLOUR_LIGHT_PURPLE << 24 | 0xA0000000; +static const uint32 DEFAULT_SCHEME_3 = COLOUR_BRIGHT_PURPLE << 19 | COLOUR_DARK_BLUE << 24 | 0xA0000000; + +extern const utf8string RideNames[91]; +extern const utf8string TrackNames[256]; +extern const utf8string FlatTrackNames[256]; + +enum +{ + PAINT_98196C, + PAINT_98197C, + PAINT_98198C, + PAINT_98199C, + + SUPPORTS_METAL_A, + SUPPORTS_METAL_B, + SUPPORTS_WOOD_A, + SUPPORTS_WOOD_B, +}; + +typedef struct +{ + uint8 function; + struct paint + { + uint32 image_id; + rct_xy16 offset; + rct_xyz16 bound_box_length; + sint16 z_offset; + rct_xyz16 bound_box_offset; + uint32 rotation; + } paint; + struct supports + { + int type; + uint8 segment; + int special; + int height; + uint32 colour_flags; + } supports; +} function_call; + +static uint8 callCount; +static bool assertFunctionCallEquals(function_call expected, function_call actual); +static function_call calls[256]; + +bool paint_attach_to_previous_ps(uint32 image_id, uint16 x, uint16 y) { + return false; +} + +paint_struct *sub_98196C( + uint32 image_id, + sint8 x_offset, sint8 y_offset, + sint16 bound_box_length_x, sint16 bound_box_length_y, sint8 bound_box_length_z, + sint16 z_offset, + uint32 rotation +) { + function_call call = { + .function = PAINT_98196C, + .paint = { + .image_id = image_id, + .offset = {x_offset, y_offset}, + .bound_box_length = {bound_box_length_x, bound_box_length_y, bound_box_length_z}, + .z_offset = z_offset, + .rotation = rotation + }, + }; + + calls[callCount] = call; + callCount++; + + return NULL; +} + +paint_struct *sub_98197C( + uint32 image_id, + sint8 x_offset, sint8 y_offset, + sint16 bound_box_length_x, sint16 bound_box_length_y, sint8 bound_box_length_z, + sint16 z_offset, + sint16 bound_box_offset_x, sint16 bound_box_offset_y, sint16 bound_box_offset_z, + uint32 rotation +) { + function_call call = { + .function = PAINT_98197C, + .paint = { + .image_id = image_id, + .offset = {x_offset, y_offset}, + .bound_box_length = {bound_box_length_x, bound_box_length_y, bound_box_length_z}, + .bound_box_offset = {bound_box_offset_x, bound_box_offset_y, bound_box_offset_z}, + .z_offset = z_offset, + .rotation = rotation, + }, + }; + + calls[callCount] = call; + callCount++; + + return NULL; +} + +paint_struct *sub_98198C( + uint32 image_id, + sint8 x_offset, sint8 y_offset, + sint16 bound_box_length_x, sint16 bound_box_length_y, sint8 bound_box_length_z, + sint16 z_offset, + sint16 bound_box_offset_x, sint16 bound_box_offset_y, sint16 bound_box_offset_z, + uint32 rotation +) { + function_call call = { + .function = PAINT_98198C, + .paint = { + .image_id = image_id, + .offset = {x_offset, y_offset}, + .bound_box_length = {bound_box_length_x, bound_box_length_y, bound_box_length_z}, + .bound_box_offset = {bound_box_offset_x, bound_box_offset_y, bound_box_offset_z}, + .z_offset = z_offset, + .rotation = rotation, + }, + }; + + calls[callCount] = call; + callCount++; + + return NULL; +} + +paint_struct *sub_98199C( + uint32 image_id, + sint8 x_offset, sint8 y_offset, + sint16 bound_box_length_x, sint16 bound_box_length_y, sint8 bound_box_length_z, + sint16 z_offset, + sint16 bound_box_offset_x, sint16 bound_box_offset_y, sint16 bound_box_offset_z, + uint32 rotation +) { + function_call call = { + .function = PAINT_98199C, + .paint = { + .image_id = image_id, + .offset = {x_offset, y_offset}, + .bound_box_length = {bound_box_length_x, bound_box_length_y, bound_box_length_z}, + .bound_box_offset = {bound_box_offset_x, bound_box_offset_y, bound_box_offset_z}, + .z_offset = z_offset, + .rotation = rotation, + }, + }; + + calls[callCount] = call; + callCount++; + + return NULL; +} + +bool wooden_a_supports_paint_setup(int supportType, int special, int height, uint32 imageColourFlags, bool *underground) { + + function_call call = { + .function = SUPPORTS_WOOD_A, + .supports = { + .type = supportType, + .special = special, + .height = height, + .colour_flags = imageColourFlags, + } + }; + + calls[callCount] = call; + callCount++; + return false; +} + +bool wooden_b_supports_paint_setup(int supportType, int special, int height, uint32 imageColourFlags) { + + function_call call = { + .function = SUPPORTS_WOOD_B, + .supports = { + .type = supportType, + .special = special, + .height = height, + .colour_flags = imageColourFlags, + } + }; + + calls[callCount] = call; + callCount++; + return false; +} + +bool metal_a_supports_paint_setup(int supportType, int segment, int special, int height, uint32 imageColourFlags) { + + function_call call = { + .function = SUPPORTS_METAL_A, + .supports = { + .type = supportType, + .segment = segment, + .special = special, + .height = height, + .colour_flags = imageColourFlags, + } + }; + + calls[callCount] = call; + callCount++; + return false; +} + +bool metal_b_supports_paint_setup(int supportType, uint8 segment, int special, int height, uint32 imageColourFlags) { + + function_call call = { + .function = SUPPORTS_METAL_B, + .supports = { + .type = supportType, + .segment = segment, + .special = special, + .height = height, + .colour_flags = imageColourFlags, + } + }; + + calls[callCount] = call; + callCount++; + return false; +} + +enum { + SPRITEGROUP_NONE, + + SPRITEGROUP_FENCE_METAL_A, // 14568 + SPRITEGROUP_FENCE_METAL_B, // 14990 + SPRITEGROUP_FLOOR_CORK, // 22134 + SPRITEGROUP_FENCE_ROPE, // 22138 + +}; + +static int getSpriteGroup(uint16 spriteIndex) { + if (spriteIndex >= 14568 && spriteIndex <= 14571) { + return SPRITEGROUP_FENCE_METAL_A; + } + + if (spriteIndex >= 14990 && spriteIndex <= 14993) { + return SPRITEGROUP_FENCE_METAL_B; + } + + if (spriteIndex >= 22134 && spriteIndex <= 22137) { + return SPRITEGROUP_FLOOR_CORK; + } + + if (spriteIndex >= 22138 && spriteIndex <= 22141) { + return SPRITEGROUP_FENCE_ROPE; + } + + return SPRITEGROUP_NONE; +} + +static void canonicalizeFunctionCall(function_call *call) { + if (call->function != PAINT_98197C) return; + if (call->paint.offset.x != call->paint.bound_box_offset.x) return; + if (call->paint.offset.y != call->paint.bound_box_offset.y) return; + if (call->paint.z_offset != call->paint.bound_box_offset.z) return; + + call->function = PAINT_98196C; +} + +static bool assertFunctionCallEquals(function_call expected, function_call actual) { + canonicalizeFunctionCall(&actual); + canonicalizeFunctionCall(&expected); + + if (expected.function != actual.function) { + return false; + } + + uint8 function = expected.function; + + if (function == SUPPORTS_WOOD_A || function == SUPPORTS_WOOD_B) { + if (expected.supports.type != actual.supports.type) return false; + if (expected.supports.special != actual.supports.special) return false; + if (expected.supports.height != actual.supports.height) return false; + if (expected.supports.colour_flags != actual.supports.colour_flags) return false; + + return true; + } + + if (function == SUPPORTS_METAL_A || function == SUPPORTS_METAL_B) { + if (expected.supports.type != actual.supports.type) return false; + if (expected.supports.segment != actual.supports.segment) return false; + if (expected.supports.special != actual.supports.special) return false; + if (expected.supports.height != actual.supports.height) return false; + if (expected.supports.colour_flags != actual.supports.colour_flags) return false; + + return true; + } + + if (expected.paint.image_id != actual.paint.image_id) { + int expectedSpriteGroup = getSpriteGroup(expected.paint.image_id & 0x7FFFF); + int actualSpriteGroup = getSpriteGroup(actual.paint.image_id & 0x7FFFF); + + if (expectedSpriteGroup != actualSpriteGroup) return false; + + if (expectedSpriteGroup == SPRITEGROUP_NONE) return false; + + return true; + } + + if (expected.paint.offset.x != actual.paint.offset.x) return false; + if (expected.paint.offset.y != actual.paint.offset.y) return false; + if (expected.paint.bound_box_length.x != actual.paint.bound_box_length.x) return false; + if (expected.paint.bound_box_length.y != actual.paint.bound_box_length.y) return false; + if (expected.paint.bound_box_length.z != actual.paint.bound_box_length.z) return false; + if (function != PAINT_98196C) { + if (expected.paint.bound_box_offset.x != actual.paint.bound_box_offset.x) return false; + if (expected.paint.bound_box_offset.y != actual.paint.bound_box_offset.y) return false; + if (expected.paint.bound_box_offset.z != actual.paint.bound_box_offset.z) return false; + } + if (expected.paint.z_offset != actual.paint.z_offset) return false; + if (expected.paint.rotation != actual.paint.rotation) return false; + + return true; +} + +static bool assertFunctionCallArrayEquals(function_call expected[], uint8 expectedCount, function_call actual[], uint8 actualCount) { + if (expectedCount != actualCount) { + return false; + } + + for (int i = 0; i < expectedCount; i++) { + function_call expectedCall = expected[i]; + function_call actualCall = actual[i]; + + if (!assertFunctionCallEquals(expectedCall, actualCall)) { + return false; + } + } + + return true; +} + +static void printImageId(uint32 input, utf8string *out) { + uint32 image = input & 0x7FFFF; + uint32 palette = input & ~0x7FFFF; + + bool allocated = false; + utf8string paletteName; + if (palette == DEFAULT_SCHEME_TRACK)paletteName = "SCHEME_TRACK"; + else if (palette == DEFAULT_SCHEME_SUPPORTS)paletteName = "SCHEME_SUPPORTS"; + else if (palette == DEFAULT_SCHEME_MISC)paletteName = "SCHEME_MISC"; + else if (palette == DEFAULT_SCHEME_3)paletteName = "SCHEME_3"; + else { + paletteName = malloc(16); + sprintf(paletteName, "0x%08X", palette); + } + + if (image == 0) { + sprintf(*out, "%s", paletteName); + } else if (image & 0x70000) { + sprintf(*out, "%s | vehicle.base_image_id + %d", paletteName, image & ~0x70000); + } else { + sprintf(*out, "%s | %d", paletteName, image); + } +} + +static void printFunctionCall(utf8string *out, function_call call) { + utf8string imageId = malloc(64); + printImageId(call.supports.colour_flags, &imageId); + switch (call.function) { + case SUPPORTS_WOOD_A: + sprintf(*out, "wooden_a_supports_paint_setup(%d, %d, %d, %s)", call.supports.type, call.supports.special, call.supports.height, imageId); + return; + case SUPPORTS_WOOD_B: + sprintf(*out, "wooden_a_supports_paint_setup(%d, %d, %d, %s)", call.supports.type, call.supports.special, call.supports.height, imageId); + return; + + case SUPPORTS_METAL_A: + sprintf(*out, "metal_a_supports_paint_setup(%d, %d, %d, %d, %s)", call.supports.type, call.supports.segment, call.supports.special, call.supports.height, imageId); + return; + case SUPPORTS_METAL_B: + sprintf(*out, "metal_b_supports_paint_setup(%d, %d, %d, %d, %s)", call.supports.type, call.supports.segment, call.supports.special, call.supports.height, imageId); + return; + } + + utf8string name = "_default"; + switch (call.function) { + case PAINT_98196C: + name = "sub_98196C"; + break; + case PAINT_98197C: + name = "sub_98197C"; + break; + case PAINT_98198C: + name = "sub_98198C"; + break; + case PAINT_98199C: + name = "sub_98199C"; + break; + } + + int strlen; + + printImageId(call.paint.image_id, &imageId); + strlen = sprintf( + *out, + "%s(%s, %d, %d, %d, %d, %d, %d, ", + name, + imageId, + call.paint.offset.x, call.paint.offset.y, + call.paint.bound_box_length.x, call.paint.bound_box_length.y, call.paint.bound_box_length.z, + call.paint.z_offset + ); + + if (call.function != PAINT_98196C) { + strlen += sprintf( + *out + strlen, + "%d, %d, %d, ", + call.paint.bound_box_offset.x, call.paint.bound_box_offset.y, call.paint.bound_box_offset.z + ); + } + + sprintf(*out + strlen, "%d)", call.paint.rotation); +} + +static void printFunctionCallArray(utf8string *out, function_call calls[], uint8 count) { + for (int i = 0; i < count; i++) { + utf8string callOut = malloc(128); + printFunctionCall(&callOut, calls[i]); + sprintf(*out + strlen(*out), "%s\n", callOut); + } +} + +int getTrackSequenceCount(uint8 rideType, uint8 trackType) { + int sequenceCount = 0; + const rct_preview_track **trackBlocks; + + if (ride_type_has_flag(rideType, RIDE_TYPE_FLAG_FLAT_RIDE)) { + trackBlocks = FlatRideTrackBlocks; + } else { + trackBlocks = TrackBlocks; + } + + for (int i = 0; i < 256; i++) { + if (trackBlocks[trackType][i].index == 0xFF) { + break; + } + + sequenceCount++; + } + + return sequenceCount; +} + +bool rideSupportsTrackType(int rideType, int trackType) +{ + TRACK_PAINT_FUNCTION_GETTER newPaintGetter = RideTypeTrackPaintFunctions[rideType]; + + if (newPaintGetter == NULL) { + return false; + } + + if (newPaintGetter(trackType, 0) == NULL) { + return false; + } + + if (RideTypeTrackPaintFunctionsOld[rideType][trackType] == 0) { + return false; + } + + return true; +} + + +extern bool testSupportSegments(uint8 rideType, uint8 trackType); +extern bool testTunnels(uint8 rideType, uint8 trackType); +extern bool testVerticalTunnels(uint8 rideType, uint8 trackType); + +static bool testTrackElement(uint8 rideType, uint8 trackType, utf8string *error) { + if (rideType == RIDE_TYPE_CHAIRLIFT) { + if (trackType == TRACK_ELEM_BEGIN_STATION || trackType == TRACK_ELEM_MIDDLE_STATION || trackType == TRACK_ELEM_END_STATION) { + // These rides chechk neighbouring tiles for tracks + sprintf(*error, "Skipped"); + return false; + } + } + uint8 rideIndex = 0; + rct_map_element mapElement = { 0 }; + mapElement.flags |= MAP_ELEMENT_FLAG_LAST_TILE; + mapElement.properties.track.type = trackType; + mapElement.base_height = 3; + + g_currently_drawn_item = &mapElement; + + rct_map_element surfaceElement = { 0 }; + surfaceElement.type = MAP_ELEMENT_TYPE_SURFACE; + surfaceElement.base_height = 2; + + gPaintInteractionType = VIEWPORT_INTERACTION_ITEM_RIDE; + gTrackColours[SCHEME_TRACK] = DEFAULT_SCHEME_TRACK; + gTrackColours[SCHEME_SUPPORTS] = DEFAULT_SCHEME_SUPPORTS; + gTrackColours[SCHEME_MISC] = DEFAULT_SCHEME_MISC; + gTrackColours[SCHEME_3] = DEFAULT_SCHEME_3; + + rct_drawpixelinfo dpi = {.zoom_level = 1}; + unk_140E9A8 = &dpi; + + rct_vehicle vehicle = { 0 }; + rct_ride ride = { 0 }; + + rct_ride_entry rideEntry = { 0 }; + rct_ride_entry_vehicle vehicleEntry = {.base_image_id = 0x70000}; + rideEntry.vehicles[0] = vehicleEntry; + + + gRideList[0] = ride; + gRideEntries[0] = &rideEntry; + + int height = 48; + + sprintf(*error, "rct2: 0x%08X\n", RideTypeTrackPaintFunctionsOld[rideType][trackType]); + + TRACK_PAINT_FUNCTION_GETTER newPaintGetter = RideTypeTrackPaintFunctions[rideType]; + int sequenceCount = getTrackSequenceCount(rideType, trackType); + for (int currentRotation = 0; currentRotation < 4; currentRotation++) { + gCurrentRotation = currentRotation; + for (int direction = 0; direction < 4; direction++) { + TRACK_PAINT_FUNCTION newPaintFunction = newPaintGetter(trackType, direction); + for (int trackSequence = 0; trackSequence < sequenceCount; trackSequence++) { + RCT2_GLOBAL(0x009DE56A, sint16) = 64; // x + RCT2_GLOBAL(0x009DE56E, sint16) = 64; // y + gDidPassSurface = true; // Above surface + gSurfaceElement = &surfaceElement; + g141E9DB = G141E9DB_FLAG_1 | G141E9DB_FLAG_2; + + callCount = 0; + memset(&calls, 0, sizeof(calls)); + + uint32 *trackDirectionList = (uint32 *)RideTypeTrackPaintFunctionsOld[rideType][trackType]; + + // Have to call from this point as it pushes esi and expects callee to pop it + RCT2_CALLPROC_X( + 0x006C4934, + rideType, + (int) trackDirectionList, + direction, + height, + (int) &mapElement, + rideIndex * sizeof(rct_ride), + trackSequence + ); + // segment heights + // tunnels + + uint8 oldCallCount = callCount; + function_call oldCalls[256]; + memcpy(&oldCalls, &calls, sizeof(calls)); + + callCount = 0; + + newPaintFunction(rideIndex, trackSequence, direction, height, &mapElement); + + uint8 newCallCount = callCount; + function_call newCalls[256]; + memcpy(&newCalls, &calls, sizeof(calls)); + + if (!assertFunctionCallArrayEquals(oldCalls, oldCallCount, newCalls, newCallCount)) { + utf8string diff = malloc(2048); + + sprintf(diff, "<<< EXPECTED\n"); + printFunctionCallArray(&diff, oldCalls, oldCallCount); + sprintf(diff + strlen(diff), "====\n"); + printFunctionCallArray(&diff, newCalls, newCallCount); + sprintf(diff + strlen(diff), ">>> ACTUAL\n"); + + if (oldCallCount != newCallCount) { + sprintf(*error + strlen(*error), "Call counts don't match (was %d, expected %d) [direction:%d trackSequence:%d]", newCallCount, oldCallCount, direction, trackSequence); + } else { + sprintf(*error + strlen(*error), "Calls don't match [direction:%d trackSequence:%d]", direction, trackSequence); + } + + sprintf(*error + strlen(*error), "\n%s", diff); + + free(diff); + + return false; + } + + } + } + } + + sprintf(*error + strlen(*error), ""); + + bool segmentSuccess = testSupportSegments(rideType, trackType); + if (!segmentSuccess) { + return false; + } + + bool tunnelSuccess = testTunnels(rideType, trackType); + if (!tunnelSuccess) { + return false; + } + + bool verticalTunnelSuccess = testVerticalTunnels(rideType, trackType); + if (!verticalTunnelSuccess) { + return false; + } + return true; +} + +bool rideIsImplemented(int rideType) { + TRACK_PAINT_FUNCTION_GETTER newPaintGetter = RideTypeTrackPaintFunctions[rideType]; + return (newPaintGetter != 0); +} + +bool testTrackPainting(int rideType, int trackType) { + TRACK_PAINT_FUNCTION_GETTER newPaintGetter = RideTypeTrackPaintFunctions[rideType]; + if (newPaintGetter == NULL) { + return false; + } + + if (newPaintGetter(trackType, 0) == NULL) { + return false; + } + + utf8string error = malloc(2048); + bool success = testTrackElement(rideType, trackType, &error); + if (!success) { + printf("%s\n", error); + } + free(error); + + return success; +} + +static int intercept_draw_6c(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp) { + registers regs = {.eax =eax, .ebx = ebx, .ecx = ecx, .edx = edx, .esi = esi, .edi = edi, .ebp = ebp}; + if ((ebp & 0x03) != get_current_rotation()) { + // Log error + log_error("Ebp is different from current rotation"); + } + + return (int) sub_98196C(ebx, regs.al, regs.cl, regs.di, regs.si, regs.ah, regs.dx, regs.ebp & 0x03); +} + +static int intercept_draw_7c(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp) { + registers regs = {.eax =eax, .ebx = ebx, .ecx = ecx, .edx = edx, .esi = esi, .edi = edi, .ebp = ebp}; + if ((ebp & 0x03) != get_current_rotation()) { + // Log error + log_error("Ebp is different from current rotation"); + } + + rct_xyz16 boundOffset = { + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_BOUNDBOX_OFFSET_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_BOUNDBOX_OFFSET_Y, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_BOUNDBOX_OFFSET_Z, sint16) + }; + + return (int) sub_98197C(ebx, regs.al, regs.cl, regs.di, regs.si, regs.ah, regs.dx, boundOffset.x, boundOffset.y, boundOffset.z, regs.ebp & 0x03); +} + +static int intercept_draw_9c(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp) { + registers regs = {.eax =eax, .ebx = ebx, .ecx = ecx, .edx = edx, .esi = esi, .edi = edi, .ebp = ebp}; + if ((ebp & 0x03) != get_current_rotation()) { + // Log error + log_error("Ebp is different from current rotation"); + } + + rct_xyz16 boundOffset = { + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_BOUNDBOX_OFFSET_X, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_BOUNDBOX_OFFSET_Y, sint16), + RCT2_GLOBAL(RCT2_ADDRESS_PAINT_BOUNDBOX_OFFSET_Z, sint16) + }; + + return (int) sub_98199C(ebx, regs.al, regs.cl, regs.di, regs.si, regs.ah, regs.dx, boundOffset.x, boundOffset.y, boundOffset.z, regs.ebp & 0x03); +} + +static uint32 intercept_wooden_a_supports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp) { + registers regs = {.eax =eax, .ebx = ebx, .edx = edx, .edi = edi, .ebp = ebp}; + wooden_a_supports_paint_setup(regs.edi, (sint16) regs.ax, regs.dx, (uint32) regs.ebp, NULL); + + return 0; +} + +static uint32 intercept_wooden_b_supports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp) { + registers regs = {.eax =eax, .ebx = ebx, .edx = edx, .edi = edi, .ebp = ebp}; + wooden_b_supports_paint_setup(regs.edi, (sint16) regs.ax, regs.dx, (uint32) regs.ebp); + + return 0; +} + +static uint32 intercept_metal_a_supports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp) { + registers regs = {.eax =eax, .ebx = ebx, .edx = edx, .edi = edi, .ebp = ebp}; + metal_a_supports_paint_setup(regs.edi, regs.ebx, (sint16) regs.ax, regs.dx, (uint32) regs.ebp); + + return 0; +} + +static uint32 intercept_metal_b_supports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp) { + registers regs = {.eax =eax, .ebx = ebx, .edx = edx, .edi = edi, .ebp = ebp}; + metal_b_supports_paint_setup(regs.edi, regs.ebx, (sint16) regs.ax, regs.dx, (uint32) regs.ebp); + + return 0; +} + + +void initHooks() { + addhook(0x00686806, (int) intercept_draw_7c, 0, (int[]) {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END}, 0, EBP); + addhook(0x006869B2, (int) intercept_draw_7c, 0, (int[]) {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END}, 0, EBP); + addhook(0x00686B6F, (int) intercept_draw_7c, 0, (int[]) {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END}, 0, EBP); + addhook(0x00686D31, (int) intercept_draw_7c, 0, (int[]) {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END}, 0, EBP); + + addhook(0x006861AC, (int) intercept_draw_6c, 0, (int[]) {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END}, 0, EBP); + addhook(0x00686337, (int) intercept_draw_6c, 0, (int[]) {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END}, 0, EBP); + addhook(0x006864D0, (int) intercept_draw_6c, 0, (int[]) {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END}, 0, EBP); + addhook(0x0068666B, (int) intercept_draw_6c, 0, (int[]) {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END}, 0, EBP); + + addhook(0x006874B0, (int) intercept_draw_9c, 0, (int[]) {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END}, 0, EBP); + addhook(0x00687618, (int) intercept_draw_9c, 0, (int[]) {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END}, 0, EBP); + addhook(0x0068778C, (int) intercept_draw_9c, 0, (int[]) {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END}, 0, EBP); + addhook(0x00687902, (int) intercept_draw_9c, 0, (int[]) {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END}, 0, EBP); + + addhook(0x006629BC, (int) intercept_wooden_a_supports, 0, (int[]) {EAX, EBX, EDX, EDI, EBP, END}, 0, EAX); + addhook(0x00662D5C, (int) intercept_wooden_b_supports, 0, (int[]) {EAX, EBX, EDX, EDI, EBP, END}, 0, EAX); + + addhook(0x00663105, (int) intercept_metal_a_supports, 0, (int[]) {EAX, EBX, EDX, EDI, EBP, END}, 0, EAX); + addhook(0x00663584, (int) intercept_metal_b_supports, 0, (int[]) {EAX, EBX, EDX, EDI, EBP, END}, 0, EAX); +} diff --git a/test/testpaint/intercept.h b/test/testpaint/intercept.h new file mode 100644 index 0000000000..3d008443e7 --- /dev/null +++ b/test/testpaint/intercept.h @@ -0,0 +1,35 @@ +#pragma region Copyright (c) 2014-2016 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 + +#ifndef _TEST_PAINT_INTERCEPT_H_ +#define _TEST_PAINT_INTERCEPT_H_ + +#include "../../src/common.h" + +#define gRideEntries RCT2_ADDRESS(RCT2_ADDRESS_RIDE_ENTRIES, rct_ride_entry*) +#define gCurrentRotation RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8) + +bool testRide(int rideType); +void initHooks(); +int getTrackSequenceCount(uint8 rideType, uint8 trackType); +bool rideIsImplemented(int rideType); +bool rideSupportsTrackType(int rideType, int trackType); +bool testTrackPainting(int rideType, int trackType); +bool testSupportSegments(uint8 rideType, uint8 trackType); +bool testTunnels(uint8 rideType, uint8 trackType); +bool testVerticalTunnels(uint8 rideType, uint8 trackType); + +#endif // #endif _TEST_PAINT_INTERCEPT_H_ diff --git a/test/testpaint/intercept_2.cpp b/test/testpaint/intercept_2.cpp new file mode 100644 index 0000000000..47db93ee5d --- /dev/null +++ b/test/testpaint/intercept_2.cpp @@ -0,0 +1,817 @@ +#pragma region Copyright (c) 2014-2016 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 +#include + +extern "C" { + #include "intercept.h" + #include "../../src/paint/paint.h" + #include "../../src/paint/supports.h" + #include "../../src/ride/track_data.h" + #include "../../src/interface/viewport.h" + #include "../../src/hook.h" +} + +namespace Intercept2 +{ + + static const uint32 DEFAULT_SCHEME_TRACK = COLOUR_GREY << 19 | COLOUR_WHITE << 24 | 0xA0000000; + static const uint32 DEFAULT_SCHEME_SUPPORTS = COLOUR_LIGHT_BLUE << 19 | COLOUR_ICY_BLUE << 24 | 0xA0000000; + static const uint32 DEFAULT_SCHEME_MISC = COLOUR_DARK_PURPLE << 19 | COLOUR_LIGHT_PURPLE << 24 | 0xA0000000; + static const uint32 DEFAULT_SCHEME_3 = COLOUR_BRIGHT_PURPLE << 19 | COLOUR_DARK_BLUE << 24 | 0xA0000000; + + struct SegmentSupportCall + { + uint16 segments; + sint32 height; + sint16 slope; + }; + + struct SupportCall + { + sint32 height; + sint16 slope; + }; + + enum { + TUNNELCALL_SKIPPED, + TUNNELCALL_NONE, + TUNNELCALL_CALL, + }; + + struct TunnelCall { + uint8 call; + sint16 offset; + uint8 type; + }; + + static bool SortSegmentSupportCalls(SegmentSupportCall lhs, SegmentSupportCall rhs) + { + if (lhs.height != rhs.height) { + return lhs.height < rhs.height; + } + + if (lhs.slope != rhs.slope) { + return lhs.slope < rhs.slope; + } + + return lhs.segments < rhs.segments; + } + + static std::vector getSegmentCalls(support_height supports[9], uint8 rotation) + { + uint16 positionsRemaining = SEGMENTS_ALL; + + for (int i = 0; i < 9; i++) { + if (supports[i].height == 0 && supports[i].slope == 0xFF) { + positionsRemaining &= ~segment_offsets[i]; + } + } + + std::vector calls; + + while (positionsRemaining != 0) { + SegmentSupportCall call = {0}; + call.height = -1; + call.slope = -1; + + support_height referenceSupport; + + for (int i = 0; i < 9; i++) { + if (positionsRemaining & segment_offsets[i]) { + referenceSupport = supports[i]; + if (supports[i].height != 0) { + call.height = supports[i].height; + } + if (supports[i].slope != 0xFF) { + call.slope = supports[i].slope; + } + break; + } + } + + uint16 positionsMatched = 0; + for (int i = 0; i < 9; i++) { + if (supports[i].height == referenceSupport.height && supports[i].slope == referenceSupport.slope) { + positionsMatched |= segment_offsets[i]; + } + } + positionsRemaining &= ~positionsMatched; + + call.segments = paint_util_rotate_segments(positionsMatched, (4 - rotation) % 4); + + calls.push_back(call); + } + + if (calls.size() > 1) { + std::sort(calls.begin(), calls.end(), SortSegmentSupportCalls); + } + + return calls; + } + + static bool SegmentCallEquals(std::vector lhs, std::vector rhs) + { + if (lhs.size() != rhs.size()) return false; + for (size_t i = 0; i < lhs.size(); ++i) { + if (lhs[i].segments != rhs[i].segments) + return false; + if (lhs[i].height != rhs[i].height) + return false; + if (lhs[i].slope != rhs[i].slope) + return false; + } + + return true; + } + + static bool segmentCallsMatch(std::vector tileSegmentSupportCalls[4]) + { + std::vector baseCallList = tileSegmentSupportCalls[0]; + for (int i = 1; i < 4; i++) { + if (!SegmentCallEquals(baseCallList, tileSegmentSupportCalls[i])) { + return false; + } + } + + return true; + } + + static bool supportCallsMatch(SupportCall tileSupportCalls[4]) + { + SupportCall baseCall = tileSupportCalls[0]; + for (int i = 1; i < 4; i++) { + if (tileSupportCalls[i].height != baseCall.height) return false; + if (tileSupportCalls[i].slope != baseCall.slope) return false; + } + + return true; + } + + static void printSegmentSupports(utf8string * out, std::vector segmentCalls) + { + for (auto &&call : segmentCalls) { + int segmentsPrinted = 0; + for (int i = 0; i < 9; i++) { + if (call.segments & segment_offsets[i]) { + if (segmentsPrinted > 0) { + sprintf(*out + strlen(*out), " | "); + } + sprintf(*out + strlen(*out), "SEGMENT_%02X", 0xB4 + 4 * i); + segmentsPrinted++; + } + } + + if (call.height == 0xFFFF) { + sprintf(*out + strlen(*out), ", 0xFFFF"); + } else { + sprintf(*out + strlen(*out), ", %d", call.height); + } + + sprintf(*out + strlen(*out), ", 0x%02X\n", call.slope); + } + } + + static bool tunnelCallsLineUp(TunnelCall tunnelCalls[4][4]) + { + for (int side = 0; side < 4; ++side) { + TunnelCall * referenceCall = nullptr; + for (int direction = 0; direction < 4; ++direction) { + if (tunnelCalls[direction][side].call == TUNNELCALL_SKIPPED) { + continue; + } + + if (referenceCall == nullptr) { + referenceCall = &tunnelCalls[direction][side]; + continue; + } + + if (referenceCall->call != tunnelCalls[direction][side].call) return false; + + if (referenceCall->call == TUNNELCALL_CALL) { + if (referenceCall->type != tunnelCalls[direction][side].type) return false; + if (referenceCall->offset != tunnelCalls[direction][side].offset) return false; + } + } + } + + return true; + } + + static void getTunnelCallReferencePattern(TunnelCall tunnelCalls[4][4], TunnelCall (*out)[4]) + { + for (int side = 0; side < 4; ++side) { + for (int direction = 0; direction < 4; ++direction) { + if (tunnelCalls[direction][side].call == TUNNELCALL_SKIPPED) { + continue; + } + + (*out)[side].call = tunnelCalls[direction][side].call; + (*out)[side].type = tunnelCalls[direction][side].type; + (*out)[side].offset = tunnelCalls[direction][side].offset; + } + } + } + + static utf8string getTunnelEdgeString(TunnelCall edge) + { + utf8string out = new utf8[6]; + + switch (edge.call) { + case TUNNELCALL_SKIPPED: + sprintf(out, "%s", " "); + break; + + case TUNNELCALL_NONE: + sprintf(out, "%s", " - "); + break; + + case TUNNELCALL_CALL: + if (edge.offset == 0) { + sprintf(out, " 0/%X ", edge.type); + } else { + utf8string offset = new utf8[3]; + if (edge.offset < 0) { + sprintf(offset, "%d", edge.offset); + } else { + sprintf(offset, "+%d", edge.offset); + } + + sprintf(out, "%3s/%X ", offset, edge.type); + + delete[] offset; + } + break; + } + + return out; + } + + static void printTunnelCalls(TunnelCall tunnelCalls[4][4]) + { + for (int direction = 0; direction < 4; ++direction) { + printf(" + "); + } + printf("\n"); + + for (int direction = 0; direction < 4; ++direction) { + utf8string tlEdge = getTunnelEdgeString(tunnelCalls[direction][2]); + utf8string trEdge = getTunnelEdgeString(tunnelCalls[direction][3]); + printf(" %s %s ", tlEdge, trEdge); + delete [] tlEdge; + delete [] trEdge; + } + printf("\n"); + + for (int direction = 0; direction < 4; ++direction) { + printf(" + + "); + } + printf("\n"); + + for (int direction = 0; direction < 4; ++direction) { + utf8string brEdge = getTunnelEdgeString(tunnelCalls[direction][0]); + utf8string blEdge = getTunnelEdgeString(tunnelCalls[direction][1]); + printf(" %s %s ", blEdge, brEdge); + delete [] blEdge; + delete [] brEdge; + } + printf("\n"); + + for (int direction = 0; direction < 4; ++direction) { + printf(" + "); + } + printf("\n"); + + for (int direction = 0; direction < 4; ++direction) { + printf(" direction %d ", direction); + } + printf("\n"); + } + + static bool testSupportSegments(uint8 rideType, uint8 trackType) + { + uint8 rideIndex = 0; + rct_map_element mapElement = {0}; + mapElement.flags |= MAP_ELEMENT_FLAG_LAST_TILE; + mapElement.properties.track.type = trackType; + mapElement.base_height = 3; + + g_currently_drawn_item = &mapElement; + + rct_map_element surfaceElement = {0}; + surfaceElement.flags |= MAP_ELEMENT_FLAG_LAST_TILE; + surfaceElement.type = MAP_ELEMENT_TYPE_SURFACE; + surfaceElement.base_height = 2; + + gPaintInteractionType = VIEWPORT_INTERACTION_ITEM_RIDE; + gTrackColours[SCHEME_TRACK] = DEFAULT_SCHEME_TRACK; + gTrackColours[SCHEME_SUPPORTS] = DEFAULT_SCHEME_SUPPORTS; + gTrackColours[SCHEME_MISC] = DEFAULT_SCHEME_MISC; + gTrackColours[SCHEME_3] = DEFAULT_SCHEME_3; + + rct_drawpixelinfo dpi = { 0 }; + dpi.zoom_level = 1; + unk_140E9A8 = &dpi; + + rct_vehicle vehicle = {0}; + rct_ride ride = {0}; + + rct_ride_entry rideEntry = {0}; + rct_ride_entry_vehicle vehicleEntry { 0 }; + vehicleEntry.base_image_id = 0x70000; + rideEntry.vehicles[0] = vehicleEntry; + + + gRideList[0] = ride; + gRideEntries[0] = &rideEntry; + + int height = 48; + + TRACK_PAINT_FUNCTION_GETTER newPaintGetter = RideTypeTrackPaintFunctions[rideType]; + int sequenceCount = getTrackSequenceCount(rideType, trackType); + + + for (int trackSequence = 0; trackSequence < sequenceCount; trackSequence++) { + std::vector tileSegmentSupportCalls[4]; + SupportCall tileGeneralSupportCalls[4]; + + for (int direction = 0; direction < 4; direction++) { + for (int s = 0; s < 9; ++s) { + gSupportSegments[s].height = 0; + gSupportSegments[s].slope = 0xFF; + } + + gSupport.height = 0; + gSupport.slope = 0xFF; + g141E9DB = G141E9DB_FLAG_1 | G141E9DB_FLAG_2; + + uint32 *trackDirectionList = (uint32 *)RideTypeTrackPaintFunctionsOld[rideType][trackType]; + + // Have to call from this point as it pushes esi and expects callee to pop it + RCT2_CALLPROC_X( + 0x006C4934, + rideType, + (int) trackDirectionList, + direction, + height, + (int) &mapElement, + rideIndex * sizeof(rct_ride), + trackSequence + ); + + tileSegmentSupportCalls[direction] = getSegmentCalls(gSupportSegments, direction); + + tileGeneralSupportCalls[direction].height = -1; + tileGeneralSupportCalls[direction].slope = -1; + if (gSupport.height != 0) { + tileGeneralSupportCalls[direction].height = gSupport.height; + } + if (gSupport.slope != 0xFF) { + tileGeneralSupportCalls[direction].height = gSupport.height; + } + } + + if (!segmentCallsMatch(tileSegmentSupportCalls)) { + // TODO: if 3 directions do share the same mask, use that call list as a reference. + printf("Original segment calls didn't match. [trackSequence:%d]\n", trackSequence); + continue; + } + + for (int direction = 0; direction < 4; direction++) { + for (int s = 0; s < 9; ++s) { + gSupportSegments[s].height = 0; + gSupportSegments[s].slope = 0xFF; + } + + TRACK_PAINT_FUNCTION newPaintFunction = newPaintGetter(trackType, direction); + newPaintFunction(rideIndex, trackSequence, direction, height, &mapElement); + + std::vector newCalls = getSegmentCalls(gSupportSegments, direction); + + if (!SegmentCallEquals(tileSegmentSupportCalls[0], newCalls)) { + // TODO put this into *error + utf8string diff = new utf8[2048]; + sprintf(diff, "<<< EXPECTED\n"); + printSegmentSupports(&diff, tileSegmentSupportCalls[0]); + sprintf(diff + strlen(diff), "====\n"); + printSegmentSupports(&diff, newCalls); + sprintf(diff + strlen(diff), ">>> ACTUAL\n"); + + printf("Segment support heights didn't match. [direction:%d trackSequence:%d]\n", direction, + trackSequence); + printf("%s", diff); + delete[] diff; + return false; + } + } + + if (!supportCallsMatch(tileGeneralSupportCalls)) { + // TODO: if 3 directions do share the output, use that. + printf("Original support calls didn't match. [trackSequence:%d]\n", trackSequence); + continue; + } + + SupportCall referenceGeneralSupportCall = tileGeneralSupportCalls[0]; + + + for (int direction = 0; direction < 4; direction++) { + gSupport.height = 0; + gSupport.slope = 0xFF; + + TRACK_PAINT_FUNCTION newPaintFunction = newPaintGetter(trackType, direction); + newPaintFunction(rideIndex, trackSequence, direction, height, &mapElement); + + if (referenceGeneralSupportCall.height != -1) { + if (gSupport.height != referenceGeneralSupportCall.height) { + printf("General support heights didn't match. (expected %d, actual: %d) [direction:%d trackSequence:%d]\n", referenceGeneralSupportCall.height,gSupport.height, direction, + trackSequence); + return false; + } + } + if (referenceGeneralSupportCall.slope != -1) { + if (gSupport.slope != referenceGeneralSupportCall.slope) { + printf("General support slopes didn't match. [direction:%d trackSequence:%d]\n", direction, + trackSequence); + return false; + } + } + } + + } + + return true; + } + + static bool tunnelPatternsMatch(TunnelCall expected[4], TunnelCall actual[4]) + { + for (int side = 0; side < 4; side++) { + if (expected[side].call != actual[side].call) return false; + + if (expected[side].call == TUNNELCALL_CALL) { + if (expected[side].type != actual[side].type) return false; + if (expected[side].offset != actual[side].offset) return false; + } + } + + return true; + } + + static sint16 getTunnelOffset(uint32 baseHeight, tunnel_entry calls[3]) + { + for (sint16 offset = -56; offset <= 56; offset += 8) { + if (calls[0].height != (baseHeight - 8 + offset) / 16) continue; + if (calls[1].height != (baseHeight + 0 + offset) / 16) continue; + if (calls[2].height != (baseHeight + 8 + offset) / 16) continue; + + return offset; + } + + log_error("Unknown tunnel height. (%d, %d, %d)", calls[0].height, calls[1].height, calls[2].height); + return 0; + } + + static bool testTunnels(uint8 rideType, uint8 trackType) + { + uint8 rideIndex = 0; + rct_map_element mapElement = {0}; + mapElement.flags |= MAP_ELEMENT_FLAG_LAST_TILE; + mapElement.properties.track.type = trackType; + mapElement.base_height = 3; + + g_currently_drawn_item = &mapElement; + + rct_map_element surfaceElement = {0}; + surfaceElement.type = MAP_ELEMENT_TYPE_SURFACE; + surfaceElement.base_height = 2; + + gPaintInteractionType = VIEWPORT_INTERACTION_ITEM_RIDE; + gTrackColours[SCHEME_TRACK] = DEFAULT_SCHEME_TRACK; + gTrackColours[SCHEME_SUPPORTS] = DEFAULT_SCHEME_SUPPORTS; + gTrackColours[SCHEME_MISC] = DEFAULT_SCHEME_MISC; + gTrackColours[SCHEME_3] = DEFAULT_SCHEME_3; + + rct_drawpixelinfo dpi { 0 }; + dpi.zoom_level = 1; + unk_140E9A8 = &dpi; + + rct_vehicle vehicle = {0}; + rct_ride ride = {0}; + + rct_ride_entry rideEntry = {0}; + rct_ride_entry_vehicle vehicleEntry { 0 }; + vehicleEntry.base_image_id = 0x70000; + rideEntry.vehicles[0] = vehicleEntry; + + + gRideList[0] = ride; + gRideEntries[0] = &rideEntry; + + int height = 48; + + TRACK_PAINT_FUNCTION_GETTER newPaintGetter = RideTypeTrackPaintFunctions[rideType]; + int sequenceCount = getTrackSequenceCount(rideType, trackType); + + + for (int trackSequence = 0; trackSequence < sequenceCount; trackSequence++) { + TunnelCall tileTunnelCalls[4][4]; + + for (int direction = 0; direction < 4; direction++) { + gLeftTunnelCount = 0; + gRightTunnelCount = 0; + + uint32 *trackDirectionList = (uint32 *)RideTypeTrackPaintFunctionsOld[rideType][trackType]; + + for (int offset = -8; offset <= 8; offset += 8) { + // Have to call from this point as it pushes esi and expects callee to pop it + RCT2_CALLPROC_X( + 0x006C4934, + rideType, + (int) trackDirectionList, + direction, + height + offset, + (int) &mapElement, + rideIndex * sizeof(rct_ride), + trackSequence + ); + } + + uint8 rightIndex = (4 - direction) % 4; + uint8 leftIndex = (rightIndex + 1) % 4; + + for (int i = 0; i < 4; ++i) { + tileTunnelCalls[direction][i].call = TUNNELCALL_SKIPPED; + } + if (gRightTunnelCount == 0) { + tileTunnelCalls[direction][rightIndex].call = TUNNELCALL_NONE; + } else if (gRightTunnelCount == 3) { + tileTunnelCalls[direction][rightIndex].call = TUNNELCALL_CALL; + tileTunnelCalls[direction][rightIndex].offset = getTunnelOffset(height, gRightTunnels); + tileTunnelCalls[direction][rightIndex].type = gRightTunnels[0].type; + } else { + printf("Multiple tunnels on one side aren't supported.\n"); + return false; + } + + if (gLeftTunnelCount == 0) { + tileTunnelCalls[direction][leftIndex].call = TUNNELCALL_NONE; + } else if (gLeftTunnelCount == 3) { + tileTunnelCalls[direction][leftIndex].call = TUNNELCALL_CALL; + tileTunnelCalls[direction][leftIndex].offset = getTunnelOffset(height, gLeftTunnels); + tileTunnelCalls[direction][leftIndex].type = gLeftTunnels[0].type; + } else { + printf("Multiple tunnels on one side aren't supported.\n"); + return false; + } + } + + TunnelCall newTileTunnelCalls[4][4]; + for (int direction = 0; direction < 4; direction++) { + gLeftTunnelCount = 0; + gRightTunnelCount = 0; + + TRACK_PAINT_FUNCTION newPaintFunction = newPaintGetter(trackType, direction); + + for (int offset = -8; offset <= 8; offset += 8) { + // TODO: move tunnel pushing to interface so we don't have to check the output 3 times + newPaintFunction(rideIndex, trackSequence, direction, height + offset, &mapElement); + } + + uint8 rightIndex = (4 - direction) % 4; + uint8 leftIndex = (rightIndex + 1) % 4; + + for (int i = 0; i < 4; ++i) { + newTileTunnelCalls[direction][i].call = TUNNELCALL_SKIPPED; + } + + if (gRightTunnelCount == 0) { + newTileTunnelCalls[direction][rightIndex].call = TUNNELCALL_NONE; + } else if (gRightTunnelCount == 3) { + newTileTunnelCalls[direction][rightIndex].call = TUNNELCALL_CALL; + newTileTunnelCalls[direction][rightIndex].offset = getTunnelOffset(height, gRightTunnels); + newTileTunnelCalls[direction][rightIndex].type = gRightTunnels[0].type; + } else { + printf("Multiple tunnels on one side aren't supported.\n"); + return false; + } + + if (gLeftTunnelCount == 0) { + newTileTunnelCalls[direction][leftIndex].call = TUNNELCALL_NONE; + } else if (gLeftTunnelCount == 3) { + newTileTunnelCalls[direction][leftIndex].call = TUNNELCALL_CALL; + newTileTunnelCalls[direction][leftIndex].offset = getTunnelOffset(height, gLeftTunnels); + newTileTunnelCalls[direction][leftIndex].type = gLeftTunnels[0].type; + } else { + printf("Multiple tunnels on one side aren't supported.\n"); + return false; + } + } + + + if (!tunnelCallsLineUp(tileTunnelCalls)) { + printf("Original tunnel calls don\'t line up. Skipping tunnel validation [trackSequence:%d].\n", + trackSequence); + printTunnelCalls(tileTunnelCalls); + + if (!tunnelCallsLineUp(newTileTunnelCalls)) { + printf("Decompiled tunnel calls don\'t line up. [trackSequence:%d].\n", trackSequence); + printTunnelCalls(newTileTunnelCalls); + return false; + } + continue; + } + + TunnelCall referencePattern[4]; + getTunnelCallReferencePattern(tileTunnelCalls, &referencePattern); + + TunnelCall actualPattern[4]; + getTunnelCallReferencePattern(newTileTunnelCalls, &actualPattern); + + if (!tunnelPatternsMatch(referencePattern, actualPattern)) { + printf("Tunnel calls don't match expected pattern. [trackSequence:%d]\n", trackSequence); + printf("expected:\n"); + printTunnelCalls(tileTunnelCalls); + printf("actual:\n"); + printTunnelCalls(newTileTunnelCalls); + return false; + } + + } + return true; + } + + static bool verticalTunnelHeightIsConsistent(uint8 heights[4]) + { + for (int i = 1; i < 4; ++i) { + if (heights[i] != heights[0]) return false; + } + + return true; + } + + static void printRelativeHeight(utf8string out, sint16 height) + { + if (height == 0) { + sprintf(out, "height"); + return; + } + + if (height > 0) { + sprintf(out, "height + %d", height); + return; + } + + if (height < 0) { + sprintf(out, "height - %d", int(abs(height))); + return; + } + } + + static bool testVerticalTunnels(uint8 rideType, uint8 trackType) + { + uint8 rideIndex = 0; + rct_map_element mapElement = {0}; + mapElement.flags |= MAP_ELEMENT_FLAG_LAST_TILE; + mapElement.properties.track.type = trackType; + mapElement.base_height = 3; + + g_currently_drawn_item = &mapElement; + + rct_map_element surfaceElement = {0}; + surfaceElement.type = MAP_ELEMENT_TYPE_SURFACE; + surfaceElement.base_height = 2; + + gPaintInteractionType = VIEWPORT_INTERACTION_ITEM_RIDE; + gTrackColours[SCHEME_TRACK] = DEFAULT_SCHEME_TRACK; + gTrackColours[SCHEME_SUPPORTS] = DEFAULT_SCHEME_SUPPORTS; + gTrackColours[SCHEME_MISC] = DEFAULT_SCHEME_MISC; + gTrackColours[SCHEME_3] = DEFAULT_SCHEME_3; + + rct_drawpixelinfo dpi = { 0 }; + dpi.zoom_level = 1; + unk_140E9A8 = &dpi; + + rct_vehicle vehicle = {0}; + rct_ride ride = {0}; + + rct_ride_entry rideEntry = {0}; + rct_ride_entry_vehicle vehicleEntry = { 0 }; + vehicleEntry.base_image_id = 0x70000; + rideEntry.vehicles[0] = vehicleEntry; + + + gRideList[0] = ride; + gRideEntries[0] = &rideEntry; + + int height = 48; + + TRACK_PAINT_FUNCTION_GETTER newPaintGetter = RideTypeTrackPaintFunctions[rideType]; + int sequenceCount = getTrackSequenceCount(rideType, trackType); + + + for (int trackSequence = 0; trackSequence < sequenceCount; trackSequence++) { + uint8 verticalTunnelHeight[4]; + + for (int direction = 0; direction < 4; direction++) { + gVerticalTunnelHeight = 0; + + uint32 *trackDirectionList = (uint32 *)RideTypeTrackPaintFunctionsOld[rideType][trackType]; + + // Have to call from this point as it pushes esi and expects callee to pop it + RCT2_CALLPROC_X( + 0x006C4934, + rideType, + (int) trackDirectionList, + direction, + height, + (int) &mapElement, + rideIndex * sizeof(rct_ride), + trackSequence + ); + + verticalTunnelHeight[direction] = gVerticalTunnelHeight; + } + + if (!verticalTunnelHeightIsConsistent(verticalTunnelHeight)) { + printf( + "Original vertical tunnel height is inconsistent, skipping test. [trackSequence:%d]\n", + trackSequence + ); + continue; + } + + uint8 referenceHeight = verticalTunnelHeight[0]; + for (int direction = 0; direction < 4; direction++) { + gVerticalTunnelHeight = 0; + + TRACK_PAINT_FUNCTION newPaintFunction = newPaintGetter(trackType, direction); + newPaintFunction(rideIndex, trackSequence, direction, height, &mapElement); + + if (gVerticalTunnelHeight != referenceHeight) { + if (referenceHeight == 0) { + printf( + "Expected no vertical tunnel. [trackSequence:%d direction:%d]\n", + trackSequence, + direction + ); + + return false; + } + + utf8string strExpectedTunnelHeight = new utf8[16]; + utf8string strActualTunnelHeight = new utf8[16]; + printRelativeHeight(strExpectedTunnelHeight, (referenceHeight * 16) - 48); + printRelativeHeight(strActualTunnelHeight, (gVerticalTunnelHeight * 16) - 48); + + printf( + "Expected vertical tunnel height to be `%s`, was `%s`. [trackSequence:%d direction:%d]\n", + strExpectedTunnelHeight, + strActualTunnelHeight, + trackSequence, + direction + ); + + delete []strExpectedTunnelHeight; + delete []strActualTunnelHeight; + + return false; + } + } + } + + return true; + } + +} + +extern "C" +{ + bool testSupportSegments(uint8 rideType, uint8 trackType) + { + return Intercept2::testSupportSegments(rideType, trackType); + } + + bool testTunnels(uint8 rideType, uint8 trackType) + { + return Intercept2::testTunnels(rideType, trackType); + } + + bool testVerticalTunnels(uint8 rideType, uint8 trackType) + { + return Intercept2::testVerticalTunnels(rideType, trackType); + } + +} diff --git a/test/testpaint/main.cpp b/test/testpaint/main.cpp new file mode 100644 index 0000000000..06191c9d3e --- /dev/null +++ b/test/testpaint/main.cpp @@ -0,0 +1,332 @@ +#pragma region Copyright (c) 2014-2016 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 +#include +#include + +#if defined(__unix__) +#include +#include +#endif // defined(__unix__) + +extern "C" { +#include "data.h" +#include "intercept.h" +#include "../../src/rct2.h" +#include "../../src/ride/ride.h" +#include "../../src/ride/ride_data.h" +#include "../../src/ride/track.h" +#include "../../src/ride/track_data.h" +} + +typedef struct { + uint8 rideType; + std::vector trackTypes; +} TestCase; + +enum CLIColour { + RED, + GREEN, +}; + +bool gTestColor = true; + +static bool CStringEquals(const char *lhs, const char *rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + + return strcmp(lhs, rhs) == 0; +} + +static bool ShouldUseColor() { + if (gTestColor == false) { + return false; + } + + const char* const term = getenv("TERM"); + const bool term_supports_color = + CStringEquals(term, "xterm") || + CStringEquals(term, "xterm-color") || + CStringEquals(term, "xterm-256color") || + CStringEquals(term, "screen") || + CStringEquals(term, "screen-256color") || + CStringEquals(term, "tmux") || + CStringEquals(term, "tmux-256color") || + CStringEquals(term, "rxvt-unicode") || + CStringEquals(term, "rxvt-unicode-256color") || + CStringEquals(term, "linux") || + CStringEquals(term, "cygwin"); + + return term_supports_color; +} + +static const char* GetAnsiColorCode(CLIColour color) { + switch (color) { + case RED: return "1"; + case GREEN: return "2"; + default: return NULL; + }; +} + +static void ColouredPrintF(CLIColour colour, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + + if(!ShouldUseColor()) { + vprintf(fmt, args); + va_end(args); + return; + } + + printf("\033[0;3%sm", GetAnsiColorCode(colour)); + vprintf(fmt, args); + printf("\033[m"); + va_end(args); +} + +#if defined(__WINDOWS__) +int main(int argc, char *argv[]); + +#define OPENRCT2_DLL_MODULE_NAME "openrct2.dll" + +static HMODULE _dllModule = NULL; + +BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) +{ + _dllModule = (HMODULE)hModule; + return TRUE; +} + +__declspec(dllexport) int StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + + if (_dllModule == NULL) { + _dllModule = GetModuleHandleA(OPENRCT2_DLL_MODULE_NAME); + } + + int gExitCode = main(0, NULL); + + exit(gExitCode); + return gExitCode; +} + +#endif + +char *segments = (char *)(GOOD_PLACE_FOR_DATA_SEGMENT); + +static uint32 sawyercoding_calculate_checksum(const uint8* buffer, size_t length) +{ + size_t i; + uint32 checksum = 0; + for (i = 0; i < length; i++) + checksum += buffer[i]; + + return checksum; +} + +/** + * Loads RCT2's data model and remaps the addresses. + * @returns true if the data integrity check succeeded, otherwise false. + */ +static bool openrct2_setup_rct2_segment() +{ + // OpenRCT2 on Linux and macOS is wired to have the original Windows PE sections loaded + // necessary. Windows does not need to do this as OpenRCT2 runs as a DLL loaded from the Windows PE. + int len = 0x01429000 - 0x8a4000; // 0xB85000, 12079104 bytes or around 11.5MB + int err = 0; + +#if defined(__unix__) + int pageSize = getpagesize(); + int numPages = (len + pageSize - 1) / pageSize; + unsigned char *dummy = (unsigned char *)malloc(numPages); + + err = mincore((void *)segments, len, dummy); + bool pagesMissing = false; + if (err != 0) + { + err = errno; +#ifdef __LINUX__ + // On Linux ENOMEM means all requested range is unmapped + if (err != ENOMEM) + { + pagesMissing = true; + perror("mincore"); + } +#else + pagesMissing = true; + perror("mincore"); +#endif // __LINUX__ + } else { + for (int i = 0; i < numPages; i++) + { + if (dummy[i] != 1) + { + pagesMissing = true; + void *start = (void *)(segments + i * pageSize); + void *end = (void *)(segments + (i + 1) * pageSize - 1); + log_warning("required page %p - %p is not in memory!", start, end); + } + } + } + free(dummy); + if (pagesMissing) + { + log_error("At least one of required pages was not found in memory. This can cause segfaults later on."); + } + + // section: text + err = mprotect((void *)0x401000, 0x8a4000 - 0x401000, PROT_READ | PROT_EXEC | PROT_WRITE); + if (err != 0) + { + perror("mprotect"); + } + + // section: rw data + err = mprotect((void *)segments, 0x01429000 - 0x8a4000, PROT_READ | PROT_WRITE); + if (err != 0) + { + perror("mprotect"); + } +#endif // defined(__unix__) + + // Check that the expected data is at various addresses. + // Start at 0x9a6000, which is start of .data, to skip the region containing addresses to DLL + // calls, which can be changed by windows/wine loader. + const uint32 c1 = sawyercoding_calculate_checksum((const uint8*)(segments + (uintptr_t)(0x009A6000 - 0x8a4000)), 0x009E0000 - 0x009A6000); + const uint32 c2 = sawyercoding_calculate_checksum((const uint8*)(segments + (uintptr_t)(0x01428000 - 0x8a4000)), 0x014282BC - 0x01428000); + const uint32 exp_c1 = 10114815; + const uint32 exp_c2 = 23564; + if (c1 != exp_c1 || c2 != exp_c2) { + log_warning("c1 = %u, expected %u, match %d", c1, exp_c1, c1 == exp_c1); + log_warning("c2 = %u, expected %u, match %d", c2, exp_c2, c2 == exp_c2); + return false; + } + + return true; +} + +int main(int argc, char *argv[]) { + std::vector testCases; + + for (int i = 0; i < argc; ++i) { + char *arg = argv[i]; + if (strcmp(arg, "--gtest_color=no") == 0) { + gTestColor = false; + } + } + + for (uint8 rideType = 0; rideType < 91; rideType++) { + if (!rideIsImplemented(rideType)) { + continue; + } + + TestCase testCase = {0}; + testCase.rideType = rideType; + + if (ride_type_has_flag(rideType, RIDE_TYPE_FLAG_FLAT_RIDE)) { + testCase.trackTypes.push_back(RideConstructionDefaultTrackType[rideType]); + } else { + for (int trackType = 0; trackType < 256; trackType++) { + if (rideSupportsTrackType(rideType, trackType)) { + testCase.trackTypes.push_back(trackType); + } + } + } + + testCases.push_back(testCase); + } + + int testCaseCount = (int) testCases.size(); + int testCount = 0; + for (auto &&tc : testCases) { + testCount += tc.trackTypes.size(); + } + + ColouredPrintF(CLIColour::GREEN, "[==========] "); + printf("Running %d tests from %d test cases.\n", testCount, testCaseCount); + + ColouredPrintF(CLIColour::GREEN, "[----------] "); + printf("Global test environment set-up.\n"); + openrct2_setup_rct2_segment(); + initHooks(); + + int successCount = 0; + std::vector failures; + for (auto &&tc : testCases) { + const utf8string rideTypeName = RideNames[tc.rideType]; + ColouredPrintF(CLIColour::GREEN, "[----------] "); + printf("%d tests from %s\n", (int)tc.trackTypes.size(), rideTypeName); + + for (auto &&trackType : tc.trackTypes) { + utf8string trackTypeName; + if (ride_type_has_flag(tc.rideType, RIDE_TYPE_FLAG_FLAT_RIDE)) { + trackTypeName = FlatTrackNames[trackType]; + } else { + trackTypeName = TrackNames[trackType]; + } + + ColouredPrintF(CLIColour::GREEN, "[ RUN ] "); + printf("%s.%s\n", rideTypeName, trackTypeName); + bool success = testTrackPainting(tc.rideType, trackType); + if (!success) { + utf8string testCaseName = new utf8[64]; + sprintf(testCaseName, "%s.%s", rideTypeName, trackTypeName); + + ColouredPrintF(CLIColour::RED, "[ FAILED ] "); + printf("%s (0 ms)\n", testCaseName); + failures.push_back(testCaseName); + } else { + ColouredPrintF(CLIColour::GREEN, "[ OK ] "); + printf("%s.%s (0 ms)\n", rideTypeName, trackTypeName); + successCount++; + } + } + + ColouredPrintF(CLIColour::GREEN, "[----------] "); + printf("%d tests from %s (0 ms total)\n", (int)tc.trackTypes.size(), rideTypeName); + } + printf("\n"); + + ColouredPrintF(CLIColour::GREEN, "[----------] "); + printf("Global test environment tear-down\n"); + + ColouredPrintF(CLIColour::GREEN, "[==========] "); + printf("%d tests from %d test cases ran. (0 ms total).\n", testCount, testCaseCount); + + ColouredPrintF(CLIColour::GREEN, "[ PASSED ] "); + printf("%d tests.\n", successCount); + + if (failures.size() > 0) { + ColouredPrintF(CLIColour::RED, "[ FAILED ] "); + printf("%d tests, listed below:\n", (int)failures.size()); + + for (auto &&failure : failures) { + ColouredPrintF(CLIColour::RED, "[ FAILED ] "); + printf("%s\n", failure); + delete [] failure; + } + + printf("\n"); + + printf("%d FAILED TESTS\n", (int)failures.size()); + + return 1; + } + + return 0; +} diff --git a/test/testpaint/testpaint.vcxproj b/test/testpaint/testpaint.vcxproj new file mode 100644 index 0000000000..94cf7fbaf2 --- /dev/null +++ b/test/testpaint/testpaint.vcxproj @@ -0,0 +1,181 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {57E60BA1-FB76-4316-909E-C1449C142327} + testpaint + 8.1 + + + + DynamicLibrary + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + $(SolutionDir)bin\testpaint\ + $(SolutionDir)obj\$(ProjectName)\$(Configuration)\ + openrct2 + $(SolutionDir)lib\include;$(SolutionDir)lib\include\breakpad;$(SolutionDir)lib\include\libspeex;$(SolutionDir)lib\include\sdl;$(SolutionDir)lib\include\jansson;$(SolutionDir)lib\include\sdl_ttf;$(SolutionDir)lib\include\libpng;$(SolutionDir)lib\include\zlib;$(IncludePath) + $(SolutionDir)lib;$(LibraryPath) + + + $(SolutionDir)bin\testpaint\ + $(SolutionDir)obj\$(ProjectName)\$(Configuration)\ + openrct2 + $(SolutionDir)lib\include;$(SolutionDir)lib\include\breakpad;$(SolutionDir)lib\include\libspeex;$(SolutionDir)lib\include\sdl;$(SolutionDir)lib\include\jansson;$(SolutionDir)lib\include\sdl_ttf;$(SolutionDir)lib\include\libpng;$(SolutionDir)lib\include\zlib;$(IncludePath) + $(SolutionDir)lib;$(LibraryPath) + + + + Level3 + Disabled + true + $(OpenRCT2_DEFINES);DEBUG;NO_VEHICLES;OPENGL_NO_LINK;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;CURL_STATICLIB;SDL_MAIN_HANDLED;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + true + 4200 + + + + + Level3 + MaxSpeed + true + true + true + $(OpenRCT2_DEFINES);NO_VEHICLES;OPENGL_NO_LINK;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;CURL_STATICLIB;SDL_MAIN_HANDLED;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions) + true + 4200 + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/testpaint/testpaint.vcxproj.user b/test/testpaint/testpaint.vcxproj.user new file mode 100644 index 0000000000..2d0a6983e6 --- /dev/null +++ b/test/testpaint/testpaint.vcxproj.user @@ -0,0 +1,11 @@ + + + + $(TargetDir)\openrct2.exe + $(TargetDir) + WindowsLocalDebugger + + + true + + \ No newline at end of file