mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-29 01:35:06 +01:00
Merge pull request #4620 from marijnvdwerf/clean/testpaint-1
Start cleanup of testpaint
This commit is contained in:
@@ -19,10 +19,23 @@
|
||||
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 */; };
|
||||
85B468FC1D96822F000F1DB5 /* paint_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 85B468FB1D96822F000F1DB5 /* paint_helpers.c */; };
|
||||
85B468FD1D96822F000F1DB5 /* paint_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = 85B468FB1D96822F000F1DB5 /* paint_helpers.c */; };
|
||||
85B5C0B01D81D912001B99A8 /* intercept_2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 85B5C0AF1D81D912001B99A8 /* intercept_2.cpp */; };
|
||||
C606CCBE1DB4054000FE4015 /* compat.c in Sources */ = {isa = PBXBuildFile; fileRef = C606CCAB1DB4054000FE4015 /* compat.c */; };
|
||||
C606CCBF1DB4054000FE4015 /* data.c in Sources */ = {isa = PBXBuildFile; fileRef = C606CCAC1DB4054000FE4015 /* data.c */; };
|
||||
C606CCC01DB4054000FE4015 /* FunctionCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCAE1DB4054000FE4015 /* FunctionCall.cpp */; };
|
||||
C606CCC11DB4054000FE4015 /* generate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCB01DB4054000FE4015 /* generate.cpp */; };
|
||||
C606CCC41DB4054000FE4015 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCB41DB4054000FE4015 /* main.cpp */; };
|
||||
C606CCC51DB4054000FE4015 /* PaintIntercept.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCB51DB4054000FE4015 /* PaintIntercept.cpp */; };
|
||||
C606CCC61DB4054000FE4015 /* Printer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCB61DB4054000FE4015 /* Printer.cpp */; };
|
||||
C606CCC71DB4054000FE4015 /* String.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCB81DB4054000FE4015 /* String.cpp */; };
|
||||
C606CCC81DB4054000FE4015 /* TestTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCBA1DB4054000FE4015 /* TestTrack.cpp */; };
|
||||
C606CCC91DB4054000FE4015 /* Utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCBC1DB4054000FE4015 /* Utils.cpp */; };
|
||||
C606CCCE1DB427A000FE4015 /* GeneralSupportHeightCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCCA1DB427A000FE4015 /* GeneralSupportHeightCall.cpp */; };
|
||||
C606CCCF1DB427A000FE4015 /* SegmentSupportHeightCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCCC1DB427A000FE4015 /* SegmentSupportHeightCall.cpp */; };
|
||||
C606CCD21DB4D7C800FE4015 /* SideTunnelCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCD01DB4D7C800FE4015 /* SideTunnelCall.cpp */; };
|
||||
C606CCD51DB4DD6C00FE4015 /* VerticalTunnelCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCD31DB4DD6C00FE4015 /* VerticalTunnelCall.cpp */; };
|
||||
C606CD261DB5120C00FE4015 /* TestPaint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CD231DB5120900FE4015 /* TestPaint.cpp */; };
|
||||
C612A8991D64825300B634CA /* vehicle_data.c in Sources */ = {isa = PBXBuildFile; fileRef = C612A8971D64825300B634CA /* vehicle_data.c */; };
|
||||
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 */; };
|
||||
@@ -106,9 +119,6 @@
|
||||
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 */; };
|
||||
@@ -392,7 +402,6 @@
|
||||
D44272A51CC81B3200D84D28 /* particle.c in Sources */ = {isa = PBXBuildFile; fileRef = D44271EF1CC81B3200D84D28 /* particle.c */; };
|
||||
D44272A61CC81B3200D84D28 /* scenery.c in Sources */ = {isa = PBXBuildFile; fileRef = D44271F01CC81B3200D84D28 /* scenery.c */; };
|
||||
D44272A71CC81B3200D84D28 /* sprite.c in Sources */ = {isa = PBXBuildFile; fileRef = D44271F21CC81B3200D84D28 /* sprite.c */; };
|
||||
D452919B1DAA204200C11788 /* generate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D45291991DAA202C00C11788 /* generate.cpp */; };
|
||||
D45A38BC1CF3006400659A24 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B31CF3006400659A24 /* libcrypto.dylib */; };
|
||||
D45A38BE1CF3006400659A24 /* libjansson.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B51CF3006400659A24 /* libjansson.dylib */; };
|
||||
D45A38C01CF3006400659A24 /* libSDL2_ttf.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B71CF3006400659A24 /* libSDL2_ttf.dylib */; };
|
||||
@@ -494,19 +503,39 @@
|
||||
791166F91D7486EF005912EA /* NetworkServerAdvertiser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkServerAdvertiser.cpp; sourceTree = "<group>"; };
|
||||
791166FA1D7486EF005912EA /* NetworkServerAdvertiser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkServerAdvertiser.h; sourceTree = "<group>"; };
|
||||
8594C05F1D885CF600235E93 /* track_data_old.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = track_data_old.c; sourceTree = "<group>"; };
|
||||
85AFA20F1D7DB83E00221B42 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
|
||||
85AFA2101D7DB83E00221B42 /* intercept.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = intercept.h; sourceTree = "<group>"; };
|
||||
85AFA2141D7DDFA100221B42 /* data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = data.h; sourceTree = "<group>"; };
|
||||
85B468FB1D96822F000F1DB5 /* paint_helpers.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = paint_helpers.c; sourceTree = "<group>"; };
|
||||
85B5C0AF1D81D912001B99A8 /* intercept_2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = intercept_2.cpp; sourceTree = "<group>"; };
|
||||
C606CCAB1DB4054000FE4015 /* compat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compat.c; sourceTree = "<group>"; };
|
||||
C606CCAC1DB4054000FE4015 /* data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = data.c; sourceTree = "<group>"; };
|
||||
C606CCAD1DB4054000FE4015 /* data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = data.h; sourceTree = "<group>"; };
|
||||
C606CCAE1DB4054000FE4015 /* FunctionCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FunctionCall.cpp; sourceTree = "<group>"; };
|
||||
C606CCAF1DB4054000FE4015 /* FunctionCall.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FunctionCall.hpp; sourceTree = "<group>"; };
|
||||
C606CCB01DB4054000FE4015 /* generate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = generate.cpp; sourceTree = "<group>"; };
|
||||
C606CCB41DB4054000FE4015 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
|
||||
C606CCB51DB4054000FE4015 /* PaintIntercept.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PaintIntercept.cpp; sourceTree = "<group>"; };
|
||||
C606CCB61DB4054000FE4015 /* Printer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Printer.cpp; sourceTree = "<group>"; };
|
||||
C606CCB71DB4054000FE4015 /* Printer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Printer.hpp; sourceTree = "<group>"; };
|
||||
C606CCB81DB4054000FE4015 /* String.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = String.cpp; sourceTree = "<group>"; };
|
||||
C606CCB91DB4054000FE4015 /* String.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = String.hpp; sourceTree = "<group>"; };
|
||||
C606CCBA1DB4054000FE4015 /* TestTrack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestTrack.cpp; sourceTree = "<group>"; };
|
||||
C606CCBB1DB4054000FE4015 /* TestTrack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TestTrack.hpp; sourceTree = "<group>"; };
|
||||
C606CCBC1DB4054000FE4015 /* Utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Utils.cpp; sourceTree = "<group>"; };
|
||||
C606CCBD1DB4054000FE4015 /* Utils.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Utils.hpp; sourceTree = "<group>"; };
|
||||
C606CCCA1DB427A000FE4015 /* GeneralSupportHeightCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GeneralSupportHeightCall.cpp; sourceTree = "<group>"; };
|
||||
C606CCCB1DB427A000FE4015 /* GeneralSupportHeightCall.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = GeneralSupportHeightCall.hpp; sourceTree = "<group>"; };
|
||||
C606CCCC1DB427A000FE4015 /* SegmentSupportHeightCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SegmentSupportHeightCall.cpp; sourceTree = "<group>"; };
|
||||
C606CCCD1DB427A000FE4015 /* SegmentSupportHeightCall.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SegmentSupportHeightCall.hpp; sourceTree = "<group>"; };
|
||||
C606CCD01DB4D7C800FE4015 /* SideTunnelCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SideTunnelCall.cpp; sourceTree = "<group>"; };
|
||||
C606CCD11DB4D7C800FE4015 /* SideTunnelCall.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SideTunnelCall.hpp; sourceTree = "<group>"; };
|
||||
C606CCD31DB4DD6C00FE4015 /* VerticalTunnelCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VerticalTunnelCall.cpp; sourceTree = "<group>"; };
|
||||
C606CCD41DB4DD6C00FE4015 /* VerticalTunnelCall.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = VerticalTunnelCall.hpp; sourceTree = "<group>"; };
|
||||
C606CCD61DB4E1CD00FE4015 /* PaintIntercept.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PaintIntercept.hpp; sourceTree = "<group>"; };
|
||||
C606CD231DB5120900FE4015 /* TestPaint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestPaint.cpp; sourceTree = "<group>"; };
|
||||
C606CD241DB5120900FE4015 /* TestPaint.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TestPaint.hpp; sourceTree = "<group>"; };
|
||||
C612A8971D64825300B634CA /* vehicle_data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vehicle_data.c; sourceTree = "<group>"; };
|
||||
C612A8981D64825300B634CA /* vehicle_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vehicle_data.h; sourceTree = "<group>"; };
|
||||
C61FB7221CF86356004CE991 /* NetworkUser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkUser.cpp; sourceTree = "<group>"; usesTabs = 0; };
|
||||
C61FB7231CF86356004CE991 /* NetworkUser.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = NetworkUser.h; sourceTree = "<group>"; 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 = "<group>"; };
|
||||
C64FDAC71D6DA72400F259B9 /* intercept.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = intercept.c; sourceTree = "<group>"; };
|
||||
C64FDAC91D6DA92D00F259B9 /* data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = data.c; sourceTree = "<group>"; };
|
||||
C650B2151CCABBDD00B4D91C /* S4Importer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = S4Importer.cpp; sourceTree = "<group>"; usesTabs = 0; };
|
||||
C650B2161CCABBDD00B4D91C /* S4Importer.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = S4Importer.h; sourceTree = "<group>"; usesTabs = 0; };
|
||||
C650B2171CCABBDD00B4D91C /* tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tables.cpp; sourceTree = "<group>"; usesTabs = 0; };
|
||||
@@ -908,7 +937,6 @@
|
||||
D44271F21CC81B3200D84D28 /* sprite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sprite.c; sourceTree = "<group>"; };
|
||||
D44271F31CC81B3200D84D28 /* sprite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sprite.h; sourceTree = "<group>"; };
|
||||
D44271F41CC81B3200D84D28 /* water.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = water.h; sourceTree = "<group>"; };
|
||||
D45291991DAA202C00C11788 /* generate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = generate.cpp; sourceTree = "<group>"; };
|
||||
D45A38B31CF3006400659A24 /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libcrypto.dylib; sourceTree = "<group>"; };
|
||||
D45A38B41CF3006400659A24 /* libfreetype.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libfreetype.dylib; sourceTree = "<group>"; };
|
||||
D45A38B51CF3006400659A24 /* libjansson.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libjansson.dylib; sourceTree = "<group>"; };
|
||||
@@ -1167,14 +1195,33 @@
|
||||
C64FDA5E1D6D99F400F259B9 /* Paint */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C64FDAC41D6DA55E00F259B9 /* compat.c */,
|
||||
C64FDAC91D6DA92D00F259B9 /* data.c */,
|
||||
85AFA2141D7DDFA100221B42 /* data.h */,
|
||||
D45291991DAA202C00C11788 /* generate.cpp */,
|
||||
85B5C0AF1D81D912001B99A8 /* intercept_2.cpp */,
|
||||
C64FDAC71D6DA72400F259B9 /* intercept.c */,
|
||||
85AFA2101D7DB83E00221B42 /* intercept.h */,
|
||||
85AFA20F1D7DB83E00221B42 /* main.cpp */,
|
||||
C606CCAB1DB4054000FE4015 /* compat.c */,
|
||||
C606CCAC1DB4054000FE4015 /* data.c */,
|
||||
C606CCAD1DB4054000FE4015 /* data.h */,
|
||||
C606CCAE1DB4054000FE4015 /* FunctionCall.cpp */,
|
||||
C606CCAF1DB4054000FE4015 /* FunctionCall.hpp */,
|
||||
C606CCCA1DB427A000FE4015 /* GeneralSupportHeightCall.cpp */,
|
||||
C606CCCB1DB427A000FE4015 /* GeneralSupportHeightCall.hpp */,
|
||||
C606CCB01DB4054000FE4015 /* generate.cpp */,
|
||||
C606CCB41DB4054000FE4015 /* main.cpp */,
|
||||
C606CCB51DB4054000FE4015 /* PaintIntercept.cpp */,
|
||||
C606CCD61DB4E1CD00FE4015 /* PaintIntercept.hpp */,
|
||||
C606CCB61DB4054000FE4015 /* Printer.cpp */,
|
||||
C606CCB71DB4054000FE4015 /* Printer.hpp */,
|
||||
C606CCCC1DB427A000FE4015 /* SegmentSupportHeightCall.cpp */,
|
||||
C606CCCD1DB427A000FE4015 /* SegmentSupportHeightCall.hpp */,
|
||||
C606CCD01DB4D7C800FE4015 /* SideTunnelCall.cpp */,
|
||||
C606CCD11DB4D7C800FE4015 /* SideTunnelCall.hpp */,
|
||||
C606CCB81DB4054000FE4015 /* String.cpp */,
|
||||
C606CCB91DB4054000FE4015 /* String.hpp */,
|
||||
C606CD231DB5120900FE4015 /* TestPaint.cpp */,
|
||||
C606CD241DB5120900FE4015 /* TestPaint.hpp */,
|
||||
C606CCBA1DB4054000FE4015 /* TestTrack.cpp */,
|
||||
C606CCBB1DB4054000FE4015 /* TestTrack.hpp */,
|
||||
C606CCBC1DB4054000FE4015 /* Utils.cpp */,
|
||||
C606CCBD1DB4054000FE4015 /* Utils.hpp */,
|
||||
C606CCD31DB4DD6C00FE4015 /* VerticalTunnelCall.cpp */,
|
||||
C606CCD41DB4DD6C00FE4015 /* VerticalTunnelCall.hpp */,
|
||||
);
|
||||
name = Paint;
|
||||
path = test/testpaint;
|
||||
@@ -2360,12 +2407,13 @@
|
||||
C64FDAC01D6D9E3B00F259B9 /* track_data.c in Sources */,
|
||||
C64FDABF1D6D9CEA00F259B9 /* map_element.c in Sources */,
|
||||
C64FDABE1D6D9CD900F259B9 /* ride_data.c in Sources */,
|
||||
C606CCD21DB4D7C800FE4015 /* SideTunnelCall.cpp in Sources */,
|
||||
C64FDABC1D6D9C8800F259B9 /* addresses.c in Sources */,
|
||||
C64FDA641D6D9A2100F259B9 /* air_powered_vertical_coaster.c in Sources */,
|
||||
C606CCD51DB4DD6C00FE4015 /* VerticalTunnelCall.cpp 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 */,
|
||||
@@ -2373,27 +2421,29 @@
|
||||
C64FDA6C1D6D9A2100F259B9 /* inverted_impulse_coaster.c in Sources */,
|
||||
C64FDA6D1D6D9A2100F259B9 /* inverted_roller_coaster.c in Sources */,
|
||||
C64FDA6E1D6D9A2100F259B9 /* junior_roller_coaster.c in Sources */,
|
||||
C606CCCF1DB427A000FE4015 /* SegmentSupportHeightCall.cpp 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 */,
|
||||
C606CCBE1DB4054000FE4015 /* compat.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 */,
|
||||
C606CCC61DB4054000FE4015 /* Printer.cpp 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 */,
|
||||
C606CCC41DB4054000FE4015 /* main.cpp in Sources */,
|
||||
C64FDA821D6D9A2100F259B9 /* wooden_roller_coaster.c in Sources */,
|
||||
C64FDA831D6D9A2100F259B9 /* wooden_wild_mouse.c in Sources */,
|
||||
C64FDA841D6D9A2100F259B9 /* car_ride.c in Sources */,
|
||||
@@ -2402,26 +2452,29 @@
|
||||
85060FD31D8C17CC00DFA2B3 /* track_data_old.c in Sources */,
|
||||
C64FDA871D6D9A2100F259B9 /* dodgems.c in Sources */,
|
||||
C64FDA881D6D9A2100F259B9 /* ferris_wheel.c in Sources */,
|
||||
D452919B1DAA204200C11788 /* generate.cpp in Sources */,
|
||||
C64FDA891D6D9A2100F259B9 /* flying_saucers.c in Sources */,
|
||||
C606CCC11DB4054000FE4015 /* generate.cpp in Sources */,
|
||||
C64FDA8A1D6D9A2100F259B9 /* ghost_train.c in Sources */,
|
||||
C606CCBF1DB4054000FE4015 /* data.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 */,
|
||||
C606CCC81DB4054000FE4015 /* TestTrack.cpp in Sources */,
|
||||
C64FDA8F1D6D9A2100F259B9 /* mini_helicopters.c in Sources */,
|
||||
C606CCC51DB4054000FE4015 /* PaintIntercept.cpp in Sources */,
|
||||
C64FDA901D6D9A2100F259B9 /* monorail_cycles.c in Sources */,
|
||||
85B5C0B01D81D912001B99A8 /* intercept_2.cpp in Sources */,
|
||||
C606CCCE1DB427A000FE4015 /* GeneralSupportHeightCall.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 */,
|
||||
C606CCC01DB4054000FE4015 /* FunctionCall.cpp in Sources */,
|
||||
C64FDA9A1D6D9A2100F259B9 /* launched_freefall.c in Sources */,
|
||||
C64FDA9B1D6D9A2100F259B9 /* magic_carpet.c in Sources */,
|
||||
C64FDA9C1D6D9A2100F259B9 /* motion_simulator.c in Sources */,
|
||||
@@ -2430,7 +2483,9 @@
|
||||
C64FDA9F1D6D9A2100F259B9 /* swinging_inverter_ship.c in Sources */,
|
||||
C64FDAA01D6D9A2100F259B9 /* top_spin.c in Sources */,
|
||||
C64FDAA11D6D9A2100F259B9 /* twist.c in Sources */,
|
||||
C606CD261DB5120C00FE4015 /* TestPaint.cpp in Sources */,
|
||||
C64FDAA21D6D9A2100F259B9 /* chairlift.c in Sources */,
|
||||
C606CCC71DB4054000FE4015 /* String.cpp in Sources */,
|
||||
C64FDAA31D6D9A2100F259B9 /* lift.c in Sources */,
|
||||
C64FDAA41D6D9A2100F259B9 /* miniature_railway.c in Sources */,
|
||||
C64FDAA51D6D9A2100F259B9 /* monorail.c in Sources */,
|
||||
@@ -2440,6 +2495,7 @@
|
||||
C64FDAA81D6D9A2100F259B9 /* dingy_slide.c in Sources */,
|
||||
C64FDAA91D6D9A2100F259B9 /* log_flume.c in Sources */,
|
||||
C64FDAAA1D6D9A2100F259B9 /* river_rafts.c in Sources */,
|
||||
C606CCC91DB4054000FE4015 /* Utils.cpp in Sources */,
|
||||
C64FDAAB1D6D9A2100F259B9 /* river_rapids.c in Sources */,
|
||||
C64FDAAC1D6D9A2100F259B9 /* splash_boats.c in Sources */,
|
||||
C64FDAAD1D6D9A2100F259B9 /* submarine_ride.c in Sources */,
|
||||
|
||||
@@ -69,6 +69,13 @@ pushd build
|
||||
chmod g+s $(pwd)
|
||||
# CMAKE and MAKE opts from environment
|
||||
docker run -v $PARENT:/work/openrct2 -w /work/openrct2/build -i -t openrct2/openrct2:64bit-only bash -c "cmake ../ $OPENRCT2_CMAKE_OPTS && make $OPENRCT_MAKE_OPTS"
|
||||
elif [[ $TARGET == "linux" ]]
|
||||
then
|
||||
cmake $OPENRCT2_CMAKE_OPTS .. -DCMAKE_BUILD_TYPE=debug
|
||||
# NOT the same variable as above
|
||||
# this target also includes building & running of testpaint
|
||||
make $OPENRCT2_MAKE_OPTS testpaint
|
||||
./testpaint --quiet || if [[ $? -eq 1 ]] ; then echo Allowing failed tests to pass ; else false; fi
|
||||
else
|
||||
cmake $OPENRCT2_CMAKE_OPTS ..
|
||||
# NOT the same variable as above
|
||||
|
||||
@@ -38,9 +38,9 @@ uint16 gUnk141E9DC;
|
||||
rct_xy16 gPaintMapPosition;
|
||||
bool gDidPassSurface;
|
||||
rct_map_element * gSurfaceElement;
|
||||
tunnel_entry gLeftTunnels[65];
|
||||
tunnel_entry gLeftTunnels[TUNNEL_MAX_COUNT];
|
||||
uint8 gLeftTunnelCount;
|
||||
tunnel_entry gRightTunnels[65];
|
||||
tunnel_entry gRightTunnels[TUNNEL_MAX_COUNT];
|
||||
uint8 gRightTunnelCount;
|
||||
uint8 gVerticalTunnelHeight;
|
||||
#endif
|
||||
|
||||
@@ -80,15 +80,17 @@ enum
|
||||
G141E9DB_FLAG_2 = 2,
|
||||
};
|
||||
|
||||
#define TUNNEL_MAX_COUNT 65
|
||||
|
||||
#ifdef NO_RCT2
|
||||
extern uint8 g141E9DB;
|
||||
extern uint16 gUnk141E9DC;
|
||||
extern rct_xy16 gPaintMapPosition;
|
||||
extern bool gDidPassSurface;
|
||||
extern rct_map_element * gSurfaceElement;
|
||||
extern tunnel_entry gLeftTunnels[65];
|
||||
extern tunnel_entry gLeftTunnels[TUNNEL_MAX_COUNT];
|
||||
extern uint8 gLeftTunnelCount;
|
||||
extern tunnel_entry gRightTunnels[65];
|
||||
extern tunnel_entry gRightTunnels[TUNNEL_MAX_COUNT];
|
||||
extern uint8 gRightTunnelCount;
|
||||
extern uint8 gVerticalTunnelHeight;
|
||||
#else
|
||||
|
||||
@@ -634,7 +634,7 @@ static void viewport_surface_draw_land_side_bottom(enum edge edge, uint8 height,
|
||||
// Normal walls
|
||||
while (curHeight > tunnelArray[0].height) {
|
||||
// TODO: Should probably be done by just keeping track of the current index
|
||||
memmove(&tunnelArray[0], &tunnelArray[1], sizeof(tunnel_entry) * 64);
|
||||
memmove(&tunnelArray[0], &tunnelArray[1], sizeof(tunnel_entry) * (TUNNEL_MAX_COUNT - 1));
|
||||
}
|
||||
|
||||
if (curHeight != tunnelArray[0].height) {
|
||||
@@ -682,7 +682,7 @@ static void viewport_surface_draw_land_side_bottom(enum edge edge, uint8 height,
|
||||
curHeight += stru_97B570[tunnelType][0];
|
||||
|
||||
// TODO: Should probably be done by just keeping track of the current index
|
||||
memmove(&tunnelArray[0], &tunnelArray[1], sizeof(tunnel_entry) * 64);
|
||||
memmove(&tunnelArray[0], &tunnelArray[1], sizeof(tunnel_entry) * (TUNNEL_MAX_COUNT - 1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -906,7 +906,7 @@ static void viewport_surface_draw_water_side_bottom(enum edge edge, uint8 height
|
||||
// Normal walls
|
||||
while (curHeight > tunnelArray[0].height) {
|
||||
// TODO: Should probably be done by just keeping track of the current index
|
||||
memmove(&tunnelArray[0], &tunnelArray[1], sizeof(tunnel_entry) * 64);
|
||||
memmove(&tunnelArray[0], &tunnelArray[1], sizeof(tunnel_entry) * (TUNNEL_MAX_COUNT - 1));
|
||||
}
|
||||
|
||||
sub_98196C(base_image_id, offset.x, offset.y, bounds.x, bounds.y, 15, curHeight * 16, rotation);
|
||||
@@ -952,7 +952,7 @@ static void viewport_surface_draw_water_side_bottom(enum edge edge, uint8 height
|
||||
curHeight += stru_97B570[tunnelType][0];
|
||||
|
||||
// TODO: Should probably be done by just keeping track of the current index
|
||||
memmove(&tunnelArray[0], &tunnelArray[1], sizeof(tunnel_entry) * 64);
|
||||
memmove(&tunnelArray[0], &tunnelArray[1], sizeof(tunnel_entry) * (TUNNEL_MAX_COUNT - 1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1316,18 +1316,18 @@ void surface_paint(uint8 direction, uint16 height, rct_map_element * mapElement)
|
||||
log_verbose("eax: %d", eax);
|
||||
}
|
||||
|
||||
tunnel_entry backupLeftTunnels[65];
|
||||
tunnel_entry backupRightTunnels[65];
|
||||
tunnel_entry backupLeftTunnels[TUNNEL_MAX_COUNT];
|
||||
tunnel_entry backupRightTunnels[TUNNEL_MAX_COUNT];
|
||||
|
||||
#ifdef __MINGW32__
|
||||
// The other code crashes mingw 4.8.2, as available on Travis
|
||||
for (int i = 0; i < 65; i++) {
|
||||
for (int i = 0; i < TUNNEL_MAX_COUNT; i++) {
|
||||
backupLeftTunnels[i] = gLeftTunnels[i];
|
||||
backupRightTunnels[i] = gRightTunnels[i];
|
||||
}
|
||||
#else
|
||||
memcpy(backupLeftTunnels, gLeftTunnels, sizeof(tunnel_entry) * 65);
|
||||
memcpy(backupRightTunnels, gRightTunnels, sizeof(tunnel_entry) * 65);
|
||||
memcpy(backupLeftTunnels, gLeftTunnels, sizeof(tunnel_entry) * TUNNEL_MAX_COUNT);
|
||||
memcpy(backupRightTunnels, gRightTunnels, sizeof(tunnel_entry) * TUNNEL_MAX_COUNT);
|
||||
#endif
|
||||
|
||||
viewport_surface_draw_land_side_top(EDGE_TOPLEFT, height / 16, eax / 32, tileDescriptors[0], tileDescriptors[3]);
|
||||
@@ -1338,13 +1338,13 @@ void surface_paint(uint8 direction, uint16 height, rct_map_element * mapElement)
|
||||
|
||||
#ifdef __MINGW32__
|
||||
// The other code crashes mingw 4.8.2, as available on Travis
|
||||
for (int i = 0; i < 65; i++) {
|
||||
for (int i = 0; i < TUNNEL_MAX_COUNT; i++) {
|
||||
gLeftTunnels[i] = backupLeftTunnels[i];
|
||||
gRightTunnels[i] = backupRightTunnels[i];
|
||||
}
|
||||
#else
|
||||
memcpy(gLeftTunnels, backupLeftTunnels, sizeof(tunnel_entry) * 65);
|
||||
memcpy(gRightTunnels, backupRightTunnels, sizeof(tunnel_entry) * 65);
|
||||
memcpy(gLeftTunnels, backupLeftTunnels, sizeof(tunnel_entry) * TUNNEL_MAX_COUNT);
|
||||
memcpy(gRightTunnels, backupRightTunnels, sizeof(tunnel_entry) * TUNNEL_MAX_COUNT);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -687,7 +687,7 @@ bool wooden_b_supports_paint_setup(int supportType, int special, int height, uin
|
||||
* @param imageColourFlags (ebp)
|
||||
* rct2: 0x00663105
|
||||
*/
|
||||
bool metal_a_supports_paint_setup(int supportType, int segment, int special, int height, uint32 imageColourFlags)
|
||||
bool metal_a_supports_paint_setup(uint8 supportType, uint8 segment, int special, int height, uint32 imageColourFlags)
|
||||
{
|
||||
if (gCurrentViewportFlags & VIEWPORT_FLAG_INVISIBLE_SUPPORTS) {
|
||||
return false;
|
||||
@@ -876,7 +876,7 @@ bool metal_a_supports_paint_setup(int supportType, int segment, int special, int
|
||||
*
|
||||
* @return (Carry Flag)
|
||||
*/
|
||||
bool metal_b_supports_paint_setup(int supportType, uint8 segment, int special, int height, uint32 imageColourFlags)
|
||||
bool metal_b_supports_paint_setup(uint8 supportType, uint8 segment, int special, int height, uint32 imageColourFlags)
|
||||
{
|
||||
#ifndef NO_RCT2
|
||||
if (gUseOriginalRidePaint) {
|
||||
|
||||
@@ -28,8 +28,8 @@ extern paint_struct * gWoodenSupportsPrependTo;
|
||||
|
||||
bool wooden_a_supports_paint_setup(int supportType, int special, int height, uint32 imageColourFlags, bool* underground);
|
||||
bool wooden_b_supports_paint_setup(int supportType, int special, int height, uint32 imageColourFlags, bool* underground);
|
||||
bool metal_a_supports_paint_setup(int supportType, int segment, int special, int height, uint32 imageColourFlags);
|
||||
bool metal_b_supports_paint_setup(int supportType, uint8 segment, int special, int height, uint32 imageColourFlags);
|
||||
bool metal_a_supports_paint_setup(uint8 supportType, uint8 segment, int special, int height, uint32 imageColourFlags);
|
||||
bool metal_b_supports_paint_setup(uint8 supportType, uint8 segment, int special, int height, uint32 imageColourFlags);
|
||||
bool path_a_supports_paint_setup(int supportType, int special, int height, uint32 imageColourFlags, rct_footpath_entry * pathEntry, bool * underground);
|
||||
bool path_b_supports_paint_setup(int supportType, int special, int height, uint32 imageColourFlags, rct_footpath_entry * pathEntry);
|
||||
|
||||
|
||||
140
test/testpaint/FunctionCall.cpp
Normal file
140
test/testpaint/FunctionCall.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
#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 "FunctionCall.hpp"
|
||||
|
||||
enum SpriteGroup {
|
||||
SPRITEGROUP_NONE,
|
||||
|
||||
SPRITEGROUP_FENCE_METAL_A, // 14568
|
||||
SPRITEGROUP_FENCE_METAL_B, // 14990
|
||||
SPRITEGROUP_FENCE_SPIRAL_SLIDE, // 20564
|
||||
SPRITEGROUP_FLOOR_CORK, // 22134
|
||||
SPRITEGROUP_FENCE_ROPE, // 22138
|
||||
};
|
||||
|
||||
static void canonicalizeFunctionCall(function_call *call);
|
||||
static SpriteGroup getSpriteGroup(uint16 spriteIndex);
|
||||
|
||||
bool FunctionCall::AssertsEquals(std::vector<function_call> expected, std::vector<function_call> actual) {
|
||||
if (expected.size() != actual.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < expected.size(); i++) {
|
||||
function_call expectedCall = expected[i];
|
||||
function_call actualCall = actual[i];
|
||||
|
||||
if (!AssertsEquals(expectedCall, actualCall)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FunctionCall::AssertsEquals(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 (function == SET_SEGMENT_HEIGHT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (expected.paint.image_id != actual.paint.image_id) {
|
||||
SpriteGroup expectedSpriteGroup = getSpriteGroup(expected.paint.image_id & 0x7FFFF);
|
||||
SpriteGroup 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 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 SpriteGroup 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 >= 20564 && spriteIndex <= 20567) {
|
||||
return SPRITEGROUP_FENCE_SPIRAL_SLIDE;
|
||||
}
|
||||
|
||||
if (spriteIndex >= 22134 && spriteIndex <= 22137) {
|
||||
return SPRITEGROUP_FLOOR_CORK;
|
||||
}
|
||||
|
||||
if (spriteIndex >= 22138 && spriteIndex <= 22141) {
|
||||
return SPRITEGROUP_FENCE_ROPE;
|
||||
}
|
||||
|
||||
return SPRITEGROUP_NONE;
|
||||
}
|
||||
63
test/testpaint/FunctionCall.hpp
Normal file
63
test/testpaint/FunctionCall.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../src/common.h"
|
||||
#include "TestPaint.hpp"
|
||||
|
||||
enum
|
||||
{
|
||||
PAINT_98196C,
|
||||
PAINT_98197C,
|
||||
PAINT_98198C,
|
||||
PAINT_98199C,
|
||||
|
||||
SUPPORTS_METAL_A,
|
||||
SUPPORTS_METAL_B,
|
||||
SUPPORTS_WOOD_A,
|
||||
SUPPORTS_WOOD_B,
|
||||
|
||||
SET_SEGMENT_HEIGHT,
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
class FunctionCall {
|
||||
public:
|
||||
static bool AssertsEquals(function_call expected, function_call actual);
|
||||
static bool AssertsEquals(std::vector<function_call> expected, std::vector<function_call> actual);
|
||||
};
|
||||
79
test/testpaint/GeneralSupportHeightCall.cpp
Normal file
79
test/testpaint/GeneralSupportHeightCall.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#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 <map>
|
||||
|
||||
#include "GeneralSupportHeightCall.hpp"
|
||||
|
||||
bool GeneralSupportHeightCall::CallsMatch(SupportCall tileSupportCalls[4]) {
|
||||
SupportCall baseCall = tileSupportCalls[0];
|
||||
for (int i = 1; i < 4; i++) {
|
||||
if (tileSupportCalls[i] != baseCall) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GeneralSupportHeightCall::FindMostCommonSupportCall(SupportCall calls[4], SupportCall *out) {
|
||||
std::map<SupportCall, int> map;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (map.count(calls[i]) == 0) {
|
||||
map[calls[i]] = 1;
|
||||
} else {
|
||||
map[calls[i]] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (map.size() == 1) {
|
||||
(*out) = calls[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (map.size() == 2) {
|
||||
for (auto &&item : map) {
|
||||
if (item.second == 3) {
|
||||
(*out) = item.first;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (map.size() == 3) {
|
||||
for (auto &&item : map) {
|
||||
if (item.second == 2) {
|
||||
(*out) = item.first;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GeneralSupportHeightCall::AssertEquals(const SupportCall *lhs, const SupportCall *rhs) {
|
||||
if (lhs == nullptr && rhs == nullptr) return true;
|
||||
if (lhs == nullptr || rhs == nullptr) return false;
|
||||
|
||||
if (lhs->height != rhs->height) return false;
|
||||
if (lhs->slope != rhs->slope) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
51
test/testpaint/GeneralSupportHeightCall.hpp
Normal file
51
test/testpaint/GeneralSupportHeightCall.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../src/common.h"
|
||||
|
||||
struct SupportCall {
|
||||
sint32 height;
|
||||
sint16 slope;
|
||||
|
||||
friend bool operator==(const SupportCall& lhs, const SupportCall& rhs) {
|
||||
if (lhs.height != rhs.height) return false;
|
||||
if (lhs.slope != rhs.slope) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator!=(const SupportCall &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool operator<(const SupportCall &other) const {
|
||||
if (height != other.height) {
|
||||
return height < other.height;
|
||||
}
|
||||
|
||||
return slope < other.slope;
|
||||
}
|
||||
};
|
||||
|
||||
namespace GeneralSupportHeightCall {
|
||||
bool CallsMatch(SupportCall tileSupportCalls[4]);
|
||||
|
||||
bool FindMostCommonSupportCall(SupportCall calls[4], SupportCall *out);
|
||||
|
||||
bool AssertEquals(const SupportCall *lhs, const SupportCall *rhs);
|
||||
};
|
||||
341
test/testpaint/PaintIntercept.cpp
Normal file
341
test/testpaint/PaintIntercept.cpp
Normal file
@@ -0,0 +1,341 @@
|
||||
#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 "PaintIntercept.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "../../src/common.h"
|
||||
#include "../../src/hook.h"
|
||||
#include "../../src/interface/viewport.h"
|
||||
#include "../../src/paint/supports.h"
|
||||
}
|
||||
|
||||
static bool _woodenSupports = false;
|
||||
static uint8 _callCount = 0;
|
||||
static function_call _calls[256] = {0};
|
||||
|
||||
namespace PaintIntercept {
|
||||
static uint32 InterceptWoodenASupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp);
|
||||
static uint32 InterceptWoodenBSupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp);
|
||||
static uint32 InterceptMetalASupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp);
|
||||
static uint32 InterceptMetalBSupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp);
|
||||
static uint32 InterceptPaint6C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp);
|
||||
static uint32 InterceptPaint7C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp);
|
||||
static uint32 InterceptPaint8C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp);
|
||||
static uint32 InterceptPaint9C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp);
|
||||
static uint32 InterceptPaintFull(uint8 function, uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp);
|
||||
bool PaintMetalSupports(uint8 function, int supportType, uint8 segment, int special, int height, uint32 imageColourFlags);
|
||||
bool PaintWoodenSupports(uint8 function, int supportType, int special, int height, uint32 imageColourFlags, bool *underground);
|
||||
static void CheckSegmentSupportHeight();
|
||||
|
||||
void InitHooks() {
|
||||
int supportsRegisterArgs[] = {EAX, EBX, EDX, EDI, EBP, END};
|
||||
addhook(0x006629BC, (int) InterceptWoodenASupports, 0, supportsRegisterArgs, 0, EAX);
|
||||
addhook(0x00662D5C, (int) InterceptWoodenBSupports, 0, supportsRegisterArgs, 0, EAX);
|
||||
|
||||
addhook(0x00663105, (int) InterceptMetalASupports, 0, supportsRegisterArgs, 0, EAX);
|
||||
addhook(0x00663584, (int) InterceptMetalBSupports, 0, supportsRegisterArgs, 0, EAX);
|
||||
|
||||
int paintRegisterArgs[] = {EAX, EBX, ECX, EDX, ESI, EDI, EBP, END};
|
||||
addhook(0x006861AC, (int) InterceptPaint6C, 0, paintRegisterArgs, 0, EBP);
|
||||
addhook(0x00686337, (int) InterceptPaint6C, 0, paintRegisterArgs, 0, EBP);
|
||||
addhook(0x006864D0, (int) InterceptPaint6C, 0, paintRegisterArgs, 0, EBP);
|
||||
addhook(0x0068666B, (int) InterceptPaint6C, 0, paintRegisterArgs, 0, EBP);
|
||||
|
||||
addhook(0x00686806, (int) InterceptPaint7C, 0, paintRegisterArgs, 0, EBP);
|
||||
addhook(0x006869B2, (int) InterceptPaint7C, 0, paintRegisterArgs, 0, EBP);
|
||||
addhook(0x00686B6F, (int) InterceptPaint7C, 0, paintRegisterArgs, 0, EBP);
|
||||
addhook(0x00686D31, (int) InterceptPaint7C, 0, paintRegisterArgs, 0, EBP);
|
||||
|
||||
addhook(0x00686EF0, (int) InterceptPaint8C, 0, paintRegisterArgs, 0, EBP);
|
||||
addhook(0x00687056, (int) InterceptPaint8C, 0, paintRegisterArgs, 0, EBP);
|
||||
addhook(0x006871C8, (int) InterceptPaint8C, 0, paintRegisterArgs, 0, EBP);
|
||||
addhook(0x0068733C, (int) InterceptPaint8C, 0, paintRegisterArgs, 0, EBP);
|
||||
|
||||
addhook(0x006874B0, (int) InterceptPaint9C, 0, paintRegisterArgs, 0, EBP);
|
||||
addhook(0x00687618, (int) InterceptPaint9C, 0, paintRegisterArgs, 0, EBP);
|
||||
addhook(0x0068778C, (int) InterceptPaint9C, 0, paintRegisterArgs, 0, EBP);
|
||||
addhook(0x00687902, (int) InterceptPaint9C, 0, paintRegisterArgs, 0, EBP);
|
||||
}
|
||||
|
||||
bool PaintWoodenSupports(uint8 function, int supportType, int special, int height, uint32 imageColourFlags, bool *underground) {
|
||||
function_call call = {0};
|
||||
call.function = function;
|
||||
call.supports.type = supportType;
|
||||
call.supports.special = special;
|
||||
call.supports.height = height;
|
||||
call.supports.colour_flags = imageColourFlags;
|
||||
|
||||
_calls[_callCount] = call;
|
||||
_callCount++;
|
||||
|
||||
return _woodenSupports;
|
||||
}
|
||||
|
||||
bool PaintMetalSupports(uint8 function, int supportType, uint8 segment, int special, int height, uint32 imageColourFlags) {
|
||||
CheckSegmentSupportHeight();
|
||||
|
||||
function_call call = {0};
|
||||
call.function = function;
|
||||
call.supports.type = supportType;
|
||||
call.supports.segment = segment;
|
||||
call.supports.special = special;
|
||||
call.supports.height = height;
|
||||
call.supports.colour_flags = imageColourFlags;
|
||||
|
||||
_calls[_callCount] = call;
|
||||
_callCount++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static paint_struct *Paint6C(
|
||||
uint32 imageID,
|
||||
sint8 xOffset, sint8 yOffset,
|
||||
sint16 boundBoxLengthX, sint16 boundBoxLengthY, sint8 boundBoxLengthZ,
|
||||
sint16 zOffset,
|
||||
uint32 rotation
|
||||
) {
|
||||
function_call call = {0};
|
||||
call.function = PAINT_98196C;
|
||||
call.paint.image_id = imageID;
|
||||
call.paint.offset = {xOffset, yOffset};
|
||||
call.paint.bound_box_length = {boundBoxLengthX, boundBoxLengthY, boundBoxLengthZ};
|
||||
call.paint.z_offset = zOffset;
|
||||
call.paint.rotation = rotation;
|
||||
|
||||
_calls[_callCount] = call;
|
||||
_callCount++;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static paint_struct *PaintFull(
|
||||
uint8 function,
|
||||
uint32 imageID,
|
||||
sint8 xOffset, sint8 yOffset,
|
||||
sint16 boundBoxLengthX, sint16 boundBoxLengthY, sint8 boundBoxLengthZ,
|
||||
sint16 zOffset,
|
||||
sint16 boundBoxOffsetX, sint16 boundBoxOffsetY, sint16 boundBoxOffsetZ,
|
||||
uint32 rotation
|
||||
) {
|
||||
function_call call = {0};
|
||||
call.function = function;
|
||||
call.paint.image_id = imageID;
|
||||
call.paint.offset = {xOffset, yOffset};
|
||||
call.paint.bound_box_length = {boundBoxLengthX, boundBoxLengthY, boundBoxLengthZ};
|
||||
call.paint.bound_box_offset = {boundBoxOffsetX, boundBoxOffsetY, boundBoxOffsetZ};
|
||||
call.paint.z_offset = zOffset;
|
||||
call.paint.rotation = rotation;
|
||||
|
||||
_calls[_callCount] = call;
|
||||
_callCount++;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ClearCalls() {
|
||||
_callCount = 0;
|
||||
memset(_calls, 0, sizeof(_calls));
|
||||
}
|
||||
|
||||
int GetCalls(function_call *buffer) {
|
||||
memcpy(buffer, _calls, _callCount * sizeof(function_call));
|
||||
return _callCount;
|
||||
}
|
||||
|
||||
void SetSimulateWoodenSupports(bool enabled) {
|
||||
_woodenSupports = enabled;
|
||||
}
|
||||
|
||||
static uint32 InterceptMetalASupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp) {
|
||||
bool output = PaintMetalSupports(SUPPORTS_METAL_A, edi, ebx, (sint16) (eax & 0xFFFF), (edx & 0xFFFF), ebp);
|
||||
|
||||
return output ? 1 : 0;
|
||||
}
|
||||
|
||||
static uint32 InterceptMetalBSupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp) {
|
||||
bool output = PaintMetalSupports(SUPPORTS_METAL_B, edi, ebx, (sint16) (eax & 0xFFFF), (edx & 0xFFFF), ebp);
|
||||
|
||||
return output ? 1 : 0;
|
||||
}
|
||||
|
||||
static void CheckSegmentSupportHeight() {
|
||||
bool hasChanged = false;
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (gSupportSegments[i].height != 0) hasChanged = true;
|
||||
if (gSupportSegments[i].slope != 0xFF) hasChanged = true;
|
||||
}
|
||||
|
||||
if (!hasChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
function_call call = {0};
|
||||
call.function = SET_SEGMENT_HEIGHT;
|
||||
|
||||
_calls[_callCount] = call;
|
||||
_callCount++;
|
||||
}
|
||||
|
||||
static uint32 InterceptWoodenASupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp) {
|
||||
bool output = PaintWoodenSupports(SUPPORTS_WOOD_A, edi, eax & 0xFFFF, edx & 0xFFFF, ebp, nullptr);
|
||||
|
||||
return output ? 1 : 0;
|
||||
}
|
||||
|
||||
static uint32 InterceptWoodenBSupports(uint32 eax, uint32 ebx, uint32 edx, uint32 edi, uint32 ebp) {
|
||||
bool output = PaintWoodenSupports(SUPPORTS_WOOD_B, edi, eax & 0xFFFF, edx & 0xFFFF, ebp, nullptr);
|
||||
|
||||
return output ? 1 : 0;
|
||||
}
|
||||
|
||||
static uint32 InterceptPaint6C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp) {
|
||||
if ((ebp & 0x03) != get_current_rotation()) {
|
||||
// Log error
|
||||
log_error("Ebp is different from current rotation");
|
||||
}
|
||||
|
||||
return (uintptr_t) Paint6C(
|
||||
ebx,
|
||||
(sint8) (eax & 0xFF), (sint8) (ecx & 0xFF),
|
||||
(sint16) (edi & 0xFFFF), (sint16) (esi & 0xFFFF), (sint8) ((eax >> 8) & 0xFF),
|
||||
edx & 0xFFFF,
|
||||
ebp & 0x03
|
||||
);
|
||||
}
|
||||
|
||||
static uint32 InterceptPaint7C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp) {
|
||||
return InterceptPaintFull(PAINT_98197C, eax, ebx, ecx, edx, esi, edi, ebp);
|
||||
}
|
||||
|
||||
static uint32 InterceptPaint8C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp) {
|
||||
return InterceptPaintFull(PAINT_98198C, eax, ebx, ecx, edx, esi, edi, ebp);
|
||||
}
|
||||
|
||||
static uint32 InterceptPaint9C(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp) {
|
||||
return InterceptPaintFull(PAINT_98199C, eax, ebx, ecx, edx, esi, edi, ebp);
|
||||
}
|
||||
|
||||
static uint32 InterceptPaintFull(uint8 function, uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 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 (uintptr_t) PaintFull(
|
||||
function,
|
||||
ebx,
|
||||
(sint8) (eax & 0xFF), (sint8) (ecx & 0xFF),
|
||||
(sint16) (edi & 0xFFFF), (sint16) (esi & 0xFFFF), (sint8) ((eax >> 8) & 0xFF),
|
||||
edx & 0xFFFF,
|
||||
boundOffset.x, boundOffset.y, boundOffset.z,
|
||||
ebp & 0x03
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
extern "C" {
|
||||
bool wooden_a_supports_paint_setup(int supportType, int special, int height, uint32 imageColourFlags, bool *underground) {
|
||||
return PaintIntercept::PaintWoodenSupports(SUPPORTS_WOOD_A, supportType, special, height, imageColourFlags, underground);
|
||||
}
|
||||
|
||||
bool wooden_b_supports_paint_setup(int supportType, int special, int height, uint32 imageColourFlags, bool *underground) {
|
||||
return PaintIntercept::PaintWoodenSupports(SUPPORTS_WOOD_B, supportType, special, height, imageColourFlags, underground);
|
||||
}
|
||||
|
||||
bool metal_a_supports_paint_setup(uint8 supportType, uint8 segment, int special, int height, uint32 imageColourFlags) {
|
||||
return PaintIntercept::PaintMetalSupports(SUPPORTS_METAL_A, supportType, segment, special, height, imageColourFlags);
|
||||
}
|
||||
|
||||
bool metal_b_supports_paint_setup(uint8 supportType, uint8 segment, int special, int height, uint32 imageColourFlags) {
|
||||
return PaintIntercept::PaintMetalSupports(SUPPORTS_METAL_B, supportType, segment, special, height, imageColourFlags);
|
||||
}
|
||||
|
||||
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) {
|
||||
return PaintIntercept::Paint6C(image_id, x_offset, y_offset, bound_box_length_x, bound_box_length_y, bound_box_length_z, z_offset, rotation);
|
||||
}
|
||||
|
||||
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
|
||||
) {
|
||||
return PaintIntercept::PaintFull(
|
||||
PAINT_98197C,
|
||||
image_id,
|
||||
x_offset, y_offset,
|
||||
bound_box_length_x, bound_box_length_y, bound_box_length_z,
|
||||
z_offset,
|
||||
bound_box_offset_x, bound_box_offset_y, bound_box_offset_z,
|
||||
rotation
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
) {
|
||||
return PaintIntercept::PaintFull(
|
||||
PAINT_98198C,
|
||||
image_id,
|
||||
x_offset, y_offset,
|
||||
bound_box_length_x, bound_box_length_y, bound_box_length_z,
|
||||
z_offset,
|
||||
bound_box_offset_x, bound_box_offset_y, bound_box_offset_z,
|
||||
rotation
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
) {
|
||||
return PaintIntercept::PaintFull(
|
||||
PAINT_98199C,
|
||||
image_id,
|
||||
x_offset, y_offset,
|
||||
bound_box_length_x, bound_box_length_y, bound_box_length_z,
|
||||
z_offset,
|
||||
bound_box_offset_x, bound_box_offset_y, bound_box_offset_z,
|
||||
rotation
|
||||
);
|
||||
}
|
||||
|
||||
bool paint_attach_to_previous_ps(uint32 image_id, uint16 x, uint16 y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
29
test/testpaint/PaintIntercept.hpp
Normal file
29
test/testpaint/PaintIntercept.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../src/common.h"
|
||||
#include "FunctionCall.hpp"
|
||||
|
||||
namespace PaintIntercept {
|
||||
void InitHooks();
|
||||
|
||||
void ClearCalls();
|
||||
int GetCalls(function_call *buffer);
|
||||
|
||||
void SetSimulateWoodenSupports(bool enabled);
|
||||
};
|
||||
253
test/testpaint/Printer.cpp
Normal file
253
test/testpaint/Printer.cpp
Normal file
@@ -0,0 +1,253 @@
|
||||
#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 "Printer.hpp"
|
||||
#include "String.hpp"
|
||||
#include "../../src/core/Util.hpp"
|
||||
|
||||
namespace Printer {
|
||||
|
||||
static const char *functionNames[] = {
|
||||
"sub_98196C",
|
||||
"sub_98197C",
|
||||
"sub_98198C",
|
||||
"sub_98199C",
|
||||
"metal_a_supports_paint_setup",
|
||||
"metal_b_supports_paint_setup",
|
||||
"wooden_a_supports_paint_setup",
|
||||
"wooden_b_supports_paint_setup",
|
||||
"paint_util_set_segment_support_height",
|
||||
};
|
||||
|
||||
static std::string GetImageIdString(uint32 imageId);
|
||||
|
||||
static std::string GetOffsetExpressionString(int offset);
|
||||
|
||||
static std::string PrintSegmentSupportHeightCall(SegmentSupportCall call);
|
||||
|
||||
static std::string PrintSideTunnelEdge(TunnelCall edge);
|
||||
|
||||
std::string PrintFunctionCalls(std::vector<function_call> calls, uint16 baseHeight) {
|
||||
std::string out;
|
||||
|
||||
for (auto &&call : calls) {
|
||||
out += PrintFunctionCall(call, baseHeight).c_str();
|
||||
out += "\n";
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string PrintFunctionCall(function_call call, uint16 baseHeight) {
|
||||
std::string imageId = GetImageIdString(call.supports.colour_flags);
|
||||
assert(call.function < Util::CountOf(functionNames));
|
||||
const char *functionName = functionNames[call.function];
|
||||
|
||||
switch (call.function) {
|
||||
case SUPPORTS_WOOD_A:
|
||||
case SUPPORTS_WOOD_B:
|
||||
return String::Format(
|
||||
"%s(%d, %d, %s, %s)", functionName, call.supports.type, call.supports.special,
|
||||
PrintHeightOffset(call.supports.height, baseHeight).c_str(), imageId.c_str()
|
||||
);
|
||||
|
||||
case SUPPORTS_METAL_A:
|
||||
case SUPPORTS_METAL_B:
|
||||
return String::Format(
|
||||
"%s(%d, %d, %d, %s, %s)", functionName, call.supports.type, call.supports.segment, call.supports.special,
|
||||
PrintHeightOffset(call.supports.height, baseHeight).c_str(), imageId.c_str()
|
||||
);
|
||||
|
||||
case SET_SEGMENT_HEIGHT:
|
||||
return "paint_util_set_segment_support_height";
|
||||
}
|
||||
|
||||
std::string s = String::Format("%s(", functionName);
|
||||
|
||||
imageId = GetImageIdString(call.paint.image_id);
|
||||
s += String::Format("%s, ", imageId.c_str());
|
||||
s += String::Format("%d, %d, ", call.paint.offset.x, call.paint.offset.y);
|
||||
s += String::Format(
|
||||
"%d, %d, %d, ",
|
||||
call.paint.bound_box_length.x, call.paint.bound_box_length.y, call.paint.bound_box_length.z
|
||||
);
|
||||
s += String::Format("%s, ", PrintHeightOffset(call.paint.z_offset, baseHeight).c_str());
|
||||
|
||||
if (call.function != PAINT_98196C) {
|
||||
s += String::Format(
|
||||
"%d, %d, %s, ",
|
||||
call.paint.bound_box_offset.x, call.paint.bound_box_offset.y,
|
||||
PrintHeightOffset(call.paint.bound_box_offset.z, baseHeight).c_str()
|
||||
);
|
||||
}
|
||||
|
||||
s += String::Format("%d)", call.paint.rotation);
|
||||
|
||||
|
||||
if (call.function != PAINT_98196C) {
|
||||
s += String::Format(
|
||||
" = { %d, %d, %s }, { %d, %d, %s }, { %d, %d, %d }",
|
||||
call.paint.offset.x, call.paint.offset.y, PrintHeightOffset(call.paint.z_offset, baseHeight).c_str(),
|
||||
call.paint.bound_box_offset.x, call.paint.bound_box_offset.y,
|
||||
PrintHeightOffset(call.paint.bound_box_offset.z, baseHeight).c_str(),
|
||||
call.paint.bound_box_length.x, call.paint.bound_box_length.y, call.paint.bound_box_length.z);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string PrintSegmentSupportHeightCalls(std::vector<SegmentSupportCall> calls) {
|
||||
std::string out = "";
|
||||
|
||||
for (auto &&call : calls) {
|
||||
out += PrintSegmentSupportHeightCall(call);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::string PrintSegmentSupportHeightCall(SegmentSupportCall call) {
|
||||
std::string out = "";
|
||||
|
||||
int segmentsPrinted = 0;
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (call.segments & segment_offsets[i]) {
|
||||
if (segmentsPrinted > 0) {
|
||||
out += " | ";
|
||||
}
|
||||
out += String::Format("SEGMENT_%02X", 0xB4 + 4 * i);
|
||||
segmentsPrinted++;
|
||||
}
|
||||
}
|
||||
|
||||
if (call.height == 0xFFFF) {
|
||||
out += ", 0xFFFF";
|
||||
} else {
|
||||
out += String::Format(", %d", call.height);
|
||||
}
|
||||
|
||||
out += String::Format(", 0x%02X\n", call.slope);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string PrintSideTunnelCalls(TunnelCall tunnelCalls[4][4]) {
|
||||
std::string s;
|
||||
|
||||
for (int direction = 0; direction < 4; ++direction) {
|
||||
s += " + ";
|
||||
}
|
||||
s += "\n";
|
||||
|
||||
for (int direction = 0; direction < 4; ++direction) {
|
||||
std::string leftEdge = PrintSideTunnelEdge(tunnelCalls[direction][2]);
|
||||
std::string rightEdge = PrintSideTunnelEdge(tunnelCalls[direction][3]);
|
||||
s += String::Format(" %s %s ", leftEdge.c_str(), rightEdge.c_str());
|
||||
}
|
||||
s += "\n";
|
||||
|
||||
for (int direction = 0; direction < 4; ++direction) {
|
||||
s += " + + ";
|
||||
}
|
||||
s += "\n";
|
||||
|
||||
for (int direction = 0; direction < 4; ++direction) {
|
||||
std::string leftEdge = PrintSideTunnelEdge(tunnelCalls[direction][0]);
|
||||
std::string rightEdge = PrintSideTunnelEdge(tunnelCalls[direction][1]);
|
||||
s += String::Format(" %s %s ", leftEdge.c_str(), rightEdge.c_str());
|
||||
}
|
||||
s += "\n";
|
||||
|
||||
for (int direction = 0; direction < 4; ++direction) {
|
||||
s += " + ";
|
||||
}
|
||||
s += "\n";
|
||||
|
||||
for (int direction = 0; direction < 4; ++direction) {
|
||||
s += String::Format(" direction %d ", direction);
|
||||
}
|
||||
s += "\n";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static std::string PrintSideTunnelEdge(TunnelCall edge) {
|
||||
std::string s;
|
||||
|
||||
switch (edge.call) {
|
||||
case TUNNELCALL_SKIPPED:
|
||||
s = " ";
|
||||
break;
|
||||
|
||||
case TUNNELCALL_NONE:
|
||||
s = " - ";
|
||||
break;
|
||||
|
||||
case TUNNELCALL_CALL:
|
||||
std::string offset;
|
||||
|
||||
if (edge.offset <= 0) {
|
||||
offset = String::Format("%d", edge.offset);
|
||||
} else {
|
||||
offset = String::Format("+%d", edge.offset);
|
||||
}
|
||||
s = String::Format("%3s/%X ", offset.c_str(), edge.type);
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static std::string GetImageIdString(uint32 imageId)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
uint32 image = imageId & 0x7FFFF;
|
||||
uint32 palette = imageId & ~0x7FFFF;
|
||||
|
||||
std::string paletteName;
|
||||
if (palette == TestPaint::DEFAULT_SCHEME_TRACK) paletteName = "SCHEME_TRACK";
|
||||
else if (palette == TestPaint::DEFAULT_SCHEME_SUPPORTS) paletteName = "SCHEME_SUPPORTS";
|
||||
else if (palette == TestPaint::DEFAULT_SCHEME_MISC) paletteName = "SCHEME_MISC";
|
||||
else if (palette == TestPaint::DEFAULT_SCHEME_3) paletteName = "SCHEME_3";
|
||||
else {
|
||||
paletteName = String::Format("0x%08X", palette);
|
||||
}
|
||||
|
||||
if (image == 0) {
|
||||
result = paletteName;
|
||||
} else if (image & 0x70000) {
|
||||
result = String::Format("%s | vehicle.base_image_id + %d", paletteName.c_str(), image & ~0x70000);
|
||||
} else {
|
||||
result = String::Format("%s | %d", paletteName.c_str(), image);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string PrintHeightOffset(uint16 height, uint16 baseHeight) {
|
||||
int offset = height - baseHeight;
|
||||
|
||||
return String::Format("height%s", GetOffsetExpressionString(offset).c_str());
|
||||
}
|
||||
|
||||
static std::string GetOffsetExpressionString(int offset)
|
||||
{
|
||||
if (offset < 0) return std::string(" - ") + std::to_string(-offset);
|
||||
if (offset > 0) return std::string(" + ") + std::to_string(offset);
|
||||
return std::string();
|
||||
}
|
||||
};
|
||||
35
test/testpaint/Printer.hpp
Normal file
35
test/testpaint/Printer.hpp
Normal file
@@ -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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "FunctionCall.hpp"
|
||||
#include "SideTunnelCall.hpp"
|
||||
#include "SegmentSupportHeightCall.hpp"
|
||||
|
||||
namespace Printer {
|
||||
std::string PrintFunctionCall(function_call call, uint16 baseHeight);
|
||||
std::string PrintFunctionCalls(std::vector <function_call> calls, uint16 baseHeight);
|
||||
|
||||
std::string PrintSegmentSupportHeightCalls(std::vector<SegmentSupportCall> calls);
|
||||
|
||||
std::string PrintSideTunnelCalls(TunnelCall tunnelCalls[4][4]);
|
||||
|
||||
std::string PrintHeightOffset(uint16 height, uint16 baseHeight);
|
||||
}
|
||||
152
test/testpaint/SegmentSupportHeightCall.cpp
Normal file
152
test/testpaint/SegmentSupportHeightCall.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
#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 <map>
|
||||
#include <algorithm>
|
||||
|
||||
#include "SegmentSupportHeightCall.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "../../src/paint/map_element/map_element.h"
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
std::vector<SegmentSupportCall> SegmentSupportHeightCall::getSegmentCalls(support_height *supports, 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<SegmentSupportCall> calls;
|
||||
|
||||
while (positionsRemaining != 0) {
|
||||
SegmentSupportCall call = {0};
|
||||
call.height = -1;
|
||||
call.slope = -1;
|
||||
|
||||
support_height referenceSupport = { 0 };
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool SegmentSupportHeightCall::CallsMatch(std::vector<SegmentSupportCall> tileSegmentSupportCalls[4])
|
||||
{
|
||||
std::vector<SegmentSupportCall> baseCallList = tileSegmentSupportCalls[0];
|
||||
for (int i = 1; i < 4; i++) {
|
||||
if (!CallsEqual(baseCallList, tileSegmentSupportCalls[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SegmentSupportHeightCall::CallsEqual(std::vector<SegmentSupportCall> lhs, std::vector<SegmentSupportCall> 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;
|
||||
}
|
||||
|
||||
bool SegmentSupportHeightCall::FindMostCommonSupportCall(std::vector<SegmentSupportCall> calls[4], std::vector<SegmentSupportCall> *out) {
|
||||
std::map<std::vector<SegmentSupportCall>, int> map;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
map[calls[i]] += 1;
|
||||
}
|
||||
|
||||
if (map.size() == 1) {
|
||||
(*out) = calls[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (map.size() == 2) {
|
||||
for (auto &&item : map) {
|
||||
if (item.second == 3) {
|
||||
(*out) = item.first;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (map.size() == 3) {
|
||||
for (auto &&item : map) {
|
||||
if (item.second == 2) {
|
||||
(*out) = item.first;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
52
test/testpaint/SegmentSupportHeightCall.hpp
Normal file
52
test/testpaint/SegmentSupportHeightCall.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../../src/common.h"
|
||||
|
||||
extern "C" {
|
||||
#include "../../src/paint/paint.h"
|
||||
}
|
||||
|
||||
struct SegmentSupportCall
|
||||
{
|
||||
uint16 segments;
|
||||
sint32 height;
|
||||
sint16 slope;
|
||||
|
||||
bool operator<(const SegmentSupportCall &other) const {
|
||||
if (height != other.height) {
|
||||
return height < other.height;
|
||||
}
|
||||
|
||||
if (segments != other.segments) {
|
||||
return segments < other.segments;
|
||||
}
|
||||
|
||||
return slope < other.slope;
|
||||
}
|
||||
};
|
||||
|
||||
class SegmentSupportHeightCall {
|
||||
public:
|
||||
static std::vector<SegmentSupportCall> getSegmentCalls(support_height supports[9], uint8 rotation);
|
||||
static bool CallsMatch(std::vector<SegmentSupportCall> tileSegmentSupportCalls[4]);
|
||||
static bool CallsEqual(std::vector<SegmentSupportCall> lhs, std::vector<SegmentSupportCall> rhs);
|
||||
static bool FindMostCommonSupportCall(std::vector<SegmentSupportCall> calls[4], std::vector<SegmentSupportCall> * out);
|
||||
};
|
||||
106
test/testpaint/SideTunnelCall.cpp
Normal file
106
test/testpaint/SideTunnelCall.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#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 "SideTunnelCall.hpp"
|
||||
|
||||
sint16 SideTunnelCall::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;
|
||||
}
|
||||
|
||||
|
||||
TunnelCall SideTunnelCall::ExtractTunnelCalls(tunnel_entry *calls, uint8 count, uint16 baseHeight, bool *error) {
|
||||
TunnelCall tunnelCall = {0};
|
||||
|
||||
if (count == 0) {
|
||||
tunnelCall.call = TUNNELCALL_NONE;
|
||||
return tunnelCall;
|
||||
}
|
||||
|
||||
if (count == 3) {
|
||||
tunnelCall.call = TUNNELCALL_CALL;
|
||||
tunnelCall.offset = GetTunnelOffset(baseHeight, calls);
|
||||
tunnelCall.type = calls[0].type;
|
||||
return tunnelCall;
|
||||
}
|
||||
|
||||
*error = true;
|
||||
return tunnelCall;
|
||||
}
|
||||
|
||||
|
||||
bool SideTunnelCall::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;
|
||||
}
|
||||
|
||||
void SideTunnelCall::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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SideTunnelCall::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;
|
||||
}
|
||||
44
test/testpaint/SideTunnelCall.hpp
Normal file
44
test/testpaint/SideTunnelCall.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../src/common.h"
|
||||
|
||||
extern "C" {
|
||||
#include "../../src/paint/map_element/map_element.h"
|
||||
}
|
||||
|
||||
enum {
|
||||
TUNNELCALL_SKIPPED,
|
||||
TUNNELCALL_NONE,
|
||||
TUNNELCALL_CALL,
|
||||
};
|
||||
|
||||
struct TunnelCall {
|
||||
uint8 call;
|
||||
sint16 offset;
|
||||
uint8 type;
|
||||
};
|
||||
|
||||
namespace SideTunnelCall {
|
||||
sint16 GetTunnelOffset(uint32 baseHeight, tunnel_entry calls[3]);
|
||||
TunnelCall ExtractTunnelCalls(tunnel_entry * list, uint8 count, uint16 baseHeight, bool * error);
|
||||
|
||||
bool TunnelPatternsMatch(TunnelCall expected[4], TunnelCall actual[4]);
|
||||
void GetTunnelCallReferencePattern(TunnelCall tunnelCalls[4][4], TunnelCall (*out)[4]);
|
||||
bool TunnelCallsLineUp(TunnelCall tunnelCalls[4][4]);
|
||||
};
|
||||
34
test/testpaint/String.cpp
Normal file
34
test/testpaint/String.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#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 <cstdarg>
|
||||
|
||||
#include "String.hpp"
|
||||
|
||||
namespace String {
|
||||
std::string Format(const char * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buffer[512];
|
||||
|
||||
va_start(args, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
va_end(args);
|
||||
|
||||
return std::string(buffer);
|
||||
}
|
||||
};
|
||||
|
||||
23
test/testpaint/String.hpp
Normal file
23
test/testpaint/String.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace String {
|
||||
std::string Format(const char *format, ...);
|
||||
}
|
||||
151
test/testpaint/TestPaint.cpp
Normal file
151
test/testpaint/TestPaint.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
#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 <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "TestPaint.hpp"
|
||||
#include "GeneralSupportHeightCall.hpp"
|
||||
#include "Printer.hpp"
|
||||
#include "SegmentSupportHeightCall.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
extern "C" {
|
||||
#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 TestPaint
|
||||
{
|
||||
void ResetEnvironment() {
|
||||
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_ride ride = {0};
|
||||
ride.entrance_style = RIDE_ENTRANCE_STYLE_PLAIN;
|
||||
|
||||
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;
|
||||
|
||||
g141E9DB = G141E9DB_FLAG_1 | G141E9DB_FLAG_2;
|
||||
}
|
||||
|
||||
void ResetTunnels() {
|
||||
gLeftTunnelCount = 0;
|
||||
gRightTunnelCount = 0;
|
||||
|
||||
for (int i = 0; i < TUNNEL_MAX_COUNT; i++) {
|
||||
gLeftTunnels[i].height = 0;
|
||||
gLeftTunnels[i].type = 0;
|
||||
gRightTunnels[i].height = 0;
|
||||
gRightTunnels[i].type = 0;
|
||||
}
|
||||
|
||||
gLeftTunnels[0].height = 0xFF;
|
||||
gLeftTunnels[0].type = 0xFF;
|
||||
gRightTunnels[0].height = 0xFF;
|
||||
gRightTunnels[0].type = 0xFF;
|
||||
}
|
||||
|
||||
void ResetSupportHeights() {
|
||||
for (int s = 0; s < 9; ++s)
|
||||
{
|
||||
gSupportSegments[s].height = 0;
|
||||
gSupportSegments[s].slope = 0xFF;
|
||||
}
|
||||
|
||||
gSupport.height = 0;
|
||||
gSupport.slope = 0xFF;
|
||||
}
|
||||
|
||||
struct IgnoredEntry
|
||||
{
|
||||
uint8 Direction;
|
||||
uint8 TrackSequence;
|
||||
};
|
||||
|
||||
static bool _ignoredAll;
|
||||
static std::vector<IgnoredEntry> _ignoredEntries;
|
||||
|
||||
static void testClearIgnore()
|
||||
{
|
||||
_ignoredAll = false;
|
||||
_ignoredEntries.clear();
|
||||
}
|
||||
|
||||
static void testIgnore(uint8 direction, uint8 trackSequence)
|
||||
{
|
||||
_ignoredEntries.push_back({ direction, trackSequence });
|
||||
}
|
||||
|
||||
static void testIgnoreAll()
|
||||
{
|
||||
_ignoredAll = true;
|
||||
}
|
||||
|
||||
static bool testIsIgnored(uint8 direction, uint8 trackSequence)
|
||||
{
|
||||
if (_ignoredAll) return true;
|
||||
for (const IgnoredEntry &entry : _ignoredEntries)
|
||||
{
|
||||
if (entry.Direction == direction &&
|
||||
entry.TrackSequence == trackSequence)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void testpaint_clear_ignore()
|
||||
{
|
||||
TestPaint::testClearIgnore();
|
||||
}
|
||||
|
||||
void testpaint_ignore(uint8 direction, uint8 trackSequence)
|
||||
{
|
||||
TestPaint::testIgnore(direction, trackSequence);
|
||||
}
|
||||
|
||||
void testpaint_ignore_all()
|
||||
{
|
||||
TestPaint::testIgnoreAll();
|
||||
}
|
||||
|
||||
bool testpaint_is_ignored(uint8 direction, uint8 trackSequence)
|
||||
{
|
||||
return TestPaint::testIsIgnored(direction, trackSequence);
|
||||
}
|
||||
|
||||
}
|
||||
59
test/testpaint/TestPaint.hpp
Normal file
59
test/testpaint/TestPaint.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../../src/common.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../../src/interface/colour.h"
|
||||
#include "../../src/paint/paint.h"
|
||||
#include "../../src/paint/map_element/map_element.h"
|
||||
}
|
||||
|
||||
#define gRideEntries RCT2_ADDRESS(RCT2_ADDRESS_RIDE_ENTRIES, rct_ride_entry*)
|
||||
#define gCurrentRotation RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)
|
||||
|
||||
enum {
|
||||
TEST_SUCCESS,
|
||||
TEST_FAILED,
|
||||
TEST_SKIPPED,
|
||||
};
|
||||
|
||||
namespace TestPaint
|
||||
{
|
||||
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;
|
||||
|
||||
void ResetEnvironment();
|
||||
void ResetTunnels();
|
||||
void ResetSupportHeights();
|
||||
}
|
||||
|
||||
enum Verbosity {
|
||||
QUIET,
|
||||
NORMAL,
|
||||
};
|
||||
|
||||
extern "C"
|
||||
{
|
||||
int generatePaintCode(uint8 rideType);
|
||||
}
|
||||
751
test/testpaint/TestTrack.cpp
Normal file
751
test/testpaint/TestTrack.cpp
Normal file
@@ -0,0 +1,751 @@
|
||||
#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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include "TestPaint.hpp"
|
||||
#include "FunctionCall.hpp"
|
||||
#include "GeneralSupportHeightCall.hpp"
|
||||
#include "PaintIntercept.hpp"
|
||||
#include "Printer.hpp"
|
||||
#include "SegmentSupportHeightCall.hpp"
|
||||
#include "SideTunnelCall.hpp"
|
||||
#include "String.hpp"
|
||||
#include "TestTrack.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "VerticalTunnelCall.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "../../src/ride/ride.h"
|
||||
#include "../../src/ride/track.h"
|
||||
#include "../../src/ride/track_data.h"
|
||||
}
|
||||
|
||||
interface ITestTrackFilter {
|
||||
public:
|
||||
virtual ~ITestTrackFilter() {}
|
||||
|
||||
virtual bool AppliesTo(uint8 rideType, uint8 trackType) abstract;
|
||||
|
||||
virtual int Variations(uint8 rideType, uint8 trackType) abstract;
|
||||
|
||||
virtual std::string VariantName(uint8 rideType, uint8 trackType, int variant) abstract;
|
||||
|
||||
virtual void ApplyTo(uint8 rideType, uint8 trackType, int variant,
|
||||
rct_map_element *mapElement, rct_map_element *surfaceElement,
|
||||
rct_ride *ride, rct_ride_entry *rideEntry
|
||||
) abstract;
|
||||
};
|
||||
|
||||
class CableLiftFilter : public ITestTrackFilter {
|
||||
public:
|
||||
bool AppliesTo(uint8 rideType, uint8 trackType) {
|
||||
return rideType == RIDE_TYPE_GIGA_COASTER;
|
||||
}
|
||||
|
||||
int Variations(uint8 rideType, uint8 trackType) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::string VariantName(uint8 rideType, uint8 trackType, int variant) {
|
||||
return String::Format("cableLift:%d", variant);
|
||||
}
|
||||
|
||||
virtual void ApplyTo(uint8 rideType, uint8 trackType, int variant,
|
||||
rct_map_element *mapElement, rct_map_element *surfaceElement,
|
||||
rct_ride *ride, rct_ride_entry *rideEntry
|
||||
) {
|
||||
if (variant == 0) {
|
||||
mapElement->properties.track.colour &= ~TRACK_ELEMENT_COLOUR_FLAG_CABLE_LIFT;
|
||||
} else {
|
||||
mapElement->properties.track.colour |= TRACK_ELEMENT_COLOUR_FLAG_CABLE_LIFT;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ChainLiftFilter : public ITestTrackFilter {
|
||||
public:
|
||||
bool AppliesTo(uint8 rideType, uint8 trackType) {
|
||||
return !ride_type_has_flag(rideType, RIDE_TYPE_FLAG_FLAT_RIDE);
|
||||
}
|
||||
|
||||
int Variations(uint8 rideType, uint8 trackType) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::string VariantName(uint8 rideType, uint8 trackType, int variant) {
|
||||
return String::Format("chainLift:%d", variant);
|
||||
}
|
||||
|
||||
virtual void ApplyTo(uint8 rideType, uint8 trackType, int variant,
|
||||
rct_map_element *mapElement, rct_map_element *surfaceElement,
|
||||
rct_ride *ride, rct_ride_entry *rideEntry
|
||||
) {
|
||||
if (variant == 0) {
|
||||
mapElement->type &= ~TRACK_ELEMENT_FLAG_CHAIN_LIFT;
|
||||
} else {
|
||||
mapElement->type |= TRACK_ELEMENT_FLAG_CHAIN_LIFT;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class InvertedFilter : public ITestTrackFilter {
|
||||
public:
|
||||
bool AppliesTo(uint8 rideType, uint8 trackType) {
|
||||
if (rideType == RIDE_TYPE_MULTI_DIMENSION_ROLLER_COASTER ||
|
||||
rideType == RIDE_TYPE_FLYING_ROLLER_COASTER ||
|
||||
rideType == RIDE_TYPE_LAY_DOWN_ROLLER_COASTER) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int Variations(uint8 rideType, uint8 trackType) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::string VariantName(uint8 rideType, uint8 trackType, int variant) {
|
||||
return String::Format("inverted:%d", variant);
|
||||
}
|
||||
|
||||
virtual void ApplyTo(uint8 rideType, uint8 trackType, int variant,
|
||||
rct_map_element *mapElement, rct_map_element *surfaceElement,
|
||||
rct_ride *ride, rct_ride_entry *rideEntry
|
||||
) {
|
||||
if (variant == 0) {
|
||||
mapElement->properties.track.colour &= ~TRACK_ELEMENT_COLOUR_FLAG_INVERTED;
|
||||
} else {
|
||||
mapElement->properties.track.colour |= TRACK_ELEMENT_COLOUR_FLAG_INVERTED;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class EntranceStyleFilter : public ITestTrackFilter {
|
||||
public:
|
||||
bool AppliesTo(uint8 rideType, uint8 trackType) {
|
||||
if (trackType == TRACK_ELEM_BEGIN_STATION ||
|
||||
trackType == TRACK_ELEM_MIDDLE_STATION ||
|
||||
trackType == TRACK_ELEM_END_STATION) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int Variations(uint8 rideType, uint8 trackType) {
|
||||
return RIDE_ENTRANCE_STYLE_COUNT - 1;
|
||||
}
|
||||
|
||||
std::string VariantName(uint8 rideType, uint8 trackType, int variant) {
|
||||
return String::Format("entranceStyle:%d", variant);
|
||||
}
|
||||
|
||||
virtual void ApplyTo(uint8 rideType, uint8 trackType, int variant,
|
||||
rct_map_element *mapElement, rct_map_element *surfaceElement,
|
||||
rct_ride *ride, rct_ride_entry *rideEntry
|
||||
) {
|
||||
ride->entrance_style = variant;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void CallOriginal(
|
||||
uint8 rideType,
|
||||
uint8 trackType,
|
||||
uint8 direction,
|
||||
uint8 trackSequence,
|
||||
uint16 height,
|
||||
rct_map_element *mapElement
|
||||
) {
|
||||
uint32 *trackDirectionList = (uint32 *) RideTypeTrackPaintFunctionsOld[rideType][trackType];
|
||||
const uint8 rideIndex = 0;
|
||||
|
||||
// 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
|
||||
);
|
||||
}
|
||||
|
||||
static void CallNew(
|
||||
uint8 rideType,
|
||||
uint8 trackType,
|
||||
uint8 direction,
|
||||
uint8 trackSequence,
|
||||
uint16 height,
|
||||
rct_map_element *mapElement
|
||||
) {
|
||||
TRACK_PAINT_FUNCTION_GETTER newPaintFunctionGetter = RideTypeTrackPaintFunctions[rideType];
|
||||
TRACK_PAINT_FUNCTION newPaintFunction = newPaintFunctionGetter(trackType, direction);
|
||||
|
||||
newPaintFunction(0, trackSequence, direction, height, mapElement);
|
||||
}
|
||||
|
||||
typedef uint8 (*TestFunction)(uint8, uint8, uint8, std::string *);
|
||||
|
||||
static uint8 TestTrackElementPaintCalls(uint8 rideType, uint8 trackType, uint8 trackSequence, std::string *error);
|
||||
|
||||
static uint8 TestTrackElementSegmentSupportHeight(uint8 rideType, uint8 trackType, uint8 trackSequence, std::string *error);
|
||||
|
||||
static uint8 TestTrackElementGeneralSupportHeight(uint8 rideType, uint8 trackType, uint8 trackSequence, std::string *error);
|
||||
|
||||
static uint8 TestTrackElementSideTunnels(uint8 rideType, uint8 trackType, uint8 trackSequence, std::string *error);
|
||||
|
||||
static uint8 TestTrackElementVerticalTunnels(uint8 rideType, uint8 trackType, uint8 trackSequence, std::string *error);
|
||||
|
||||
uint8 TestTrack::TestPaintTrackElement(uint8 rideType, uint8 trackType, std::string *out) {
|
||||
if (!Utils::rideSupportsTrackType(rideType, trackType)) {
|
||||
return TEST_FAILED;
|
||||
}
|
||||
|
||||
if (rideType == RIDE_TYPE_CHAIRLIFT) {
|
||||
if (trackType == TRACK_ELEM_BEGIN_STATION || trackType == TRACK_ELEM_MIDDLE_STATION ||
|
||||
trackType == TRACK_ELEM_END_STATION) {
|
||||
// These rides check neighbouring tiles for tracks
|
||||
return TEST_SKIPPED;
|
||||
}
|
||||
}
|
||||
|
||||
int sequenceCount = Utils::getTrackSequenceCount(rideType, trackType);
|
||||
std::string error = String::Format("rct2: 0x%08X\n", RideTypeTrackPaintFunctionsOld[rideType][trackType]);
|
||||
|
||||
uint8 retVal = TEST_SUCCESS;
|
||||
|
||||
static TestFunction functions[] = {
|
||||
TestTrackElementPaintCalls,
|
||||
TestTrackElementSegmentSupportHeight,
|
||||
TestTrackElementGeneralSupportHeight,
|
||||
TestTrackElementSideTunnels,
|
||||
TestTrackElementVerticalTunnels,
|
||||
};
|
||||
|
||||
for (int trackSequence = 0; trackSequence < sequenceCount; trackSequence++) {
|
||||
for (auto &&function : functions) {
|
||||
retVal = function(rideType, trackType, trackSequence, &error);
|
||||
|
||||
if (retVal != TEST_SUCCESS) {
|
||||
*out += error + "\n";
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static uint8 TestTrackElementPaintCalls(uint8 rideType, uint8 trackType, uint8 trackSequence, std::string *error) {
|
||||
uint8 rideIndex = 0;
|
||||
uint16 height = 3 * 16;
|
||||
|
||||
rct_map_element mapElement = {0};
|
||||
mapElement.flags |= MAP_ELEMENT_FLAG_LAST_TILE;
|
||||
mapElement.properties.track.type = trackType;
|
||||
mapElement.base_height = height / 16;
|
||||
g_currently_drawn_item = &mapElement;
|
||||
|
||||
rct_map_element surfaceElement = {0};
|
||||
surfaceElement.type = MAP_ELEMENT_TYPE_SURFACE;
|
||||
surfaceElement.base_height = 2;
|
||||
gSurfaceElement = &surfaceElement;
|
||||
gDidPassSurface = true;
|
||||
|
||||
TestPaint::ResetEnvironment();
|
||||
TestPaint::ResetTunnels();
|
||||
|
||||
function_call callBuffer[256] = {0};
|
||||
int callCount = 0;
|
||||
|
||||
// TODO: test supports
|
||||
// TODO: test flat rides
|
||||
// TODO: test mazes
|
||||
// TODO: test underground (Wooden RC)
|
||||
// TODO: test station fences
|
||||
|
||||
std::vector<ITestTrackFilter *> filters;
|
||||
filters.push_back(new CableLiftFilter());
|
||||
filters.push_back(new ChainLiftFilter());
|
||||
filters.push_back(new InvertedFilter());
|
||||
filters.push_back(new EntranceStyleFilter());
|
||||
|
||||
std::vector<ITestTrackFilter *> activeFilters;
|
||||
|
||||
for (auto &&filter : filters) {
|
||||
if (filter->AppliesTo(rideType, trackType)) {
|
||||
activeFilters.push_back(filter);
|
||||
}
|
||||
}
|
||||
|
||||
// Add an element so there's always something to add to
|
||||
std::vector<uint8> filler;
|
||||
filler.push_back(0);
|
||||
|
||||
std::vector<std::vector<uint8>> argumentPermutations;
|
||||
argumentPermutations.push_back(filler);
|
||||
for (size_t filterIndex = 0; filterIndex < activeFilters.size(); ++filterIndex) {
|
||||
ITestTrackFilter *filter = activeFilters[filterIndex];
|
||||
uint8 variantCount = filter->Variations(rideType, trackType);
|
||||
|
||||
std::vector<std::vector<uint8>> newArgumentPermutations;
|
||||
for (int variant = 0; variant < variantCount; variant++) {
|
||||
for (auto &&oldPermutation : argumentPermutations) {
|
||||
std::vector<uint8> permutation;
|
||||
permutation.insert(permutation.begin(), oldPermutation.begin(), oldPermutation.end());
|
||||
permutation.push_back(variant);
|
||||
newArgumentPermutations.push_back(permutation);
|
||||
}
|
||||
}
|
||||
|
||||
argumentPermutations.clear();
|
||||
argumentPermutations.insert(argumentPermutations.begin(), newArgumentPermutations.begin(),
|
||||
newArgumentPermutations.end());
|
||||
}
|
||||
|
||||
for (auto &&arguments : argumentPermutations) {
|
||||
std::string baseCaseName = "[";
|
||||
|
||||
for (size_t filterIndex = 0; filterIndex < activeFilters.size(); ++filterIndex) {
|
||||
uint8 &variant = arguments[1 + filterIndex];
|
||||
baseCaseName += activeFilters[filterIndex]->VariantName(rideType, trackType, variant);
|
||||
baseCaseName += " ";
|
||||
|
||||
activeFilters[filterIndex]->ApplyTo(rideType, trackType, variant, &mapElement, &surfaceElement, &(gRideList[0]), gRideEntries[0]);
|
||||
}
|
||||
|
||||
|
||||
for (int currentRotation = 0; currentRotation < 4; currentRotation++) {
|
||||
gCurrentRotation = currentRotation;
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
RCT2_GLOBAL(0x009DE56A, sint16) = 64; // x
|
||||
RCT2_GLOBAL(0x009DE56E, sint16) = 64; // y
|
||||
|
||||
std::string caseName = String::Format(
|
||||
"%srotation:%d direction:%d trackSequence:%d]",
|
||||
baseCaseName.c_str(), currentRotation, direction, trackSequence
|
||||
);
|
||||
|
||||
PaintIntercept::ClearCalls();
|
||||
TestPaint::ResetSupportHeights();
|
||||
|
||||
CallOriginal(rideType, trackType, direction, trackSequence, height, &mapElement);
|
||||
|
||||
callCount = PaintIntercept::GetCalls(callBuffer);
|
||||
std::vector<function_call> oldCalls;
|
||||
oldCalls.insert(oldCalls.begin(), callBuffer, callBuffer + callCount);
|
||||
|
||||
PaintIntercept::ClearCalls();
|
||||
testpaint_clear_ignore();
|
||||
TestPaint::ResetSupportHeights();
|
||||
|
||||
CallNew(rideType, trackType, direction, trackSequence, height, &mapElement);
|
||||
|
||||
if (testpaint_is_ignored(direction, trackSequence)) {
|
||||
*error += String::Format("[ IGNORED ] %s\n", caseName.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
callCount = PaintIntercept::GetCalls(callBuffer);
|
||||
std::vector<function_call> newCalls;
|
||||
newCalls.insert(newCalls.begin(), callBuffer, callBuffer + callCount);
|
||||
|
||||
bool sucess = true;
|
||||
if (oldCalls.size() != newCalls.size()) {
|
||||
*error += String::Format(
|
||||
"Call counts don't match (was %d, expected %d). %s\n",
|
||||
newCalls.size(), oldCalls.size(), caseName.c_str()
|
||||
);
|
||||
sucess = false;
|
||||
} else if (!FunctionCall::AssertsEquals(oldCalls, newCalls)) {
|
||||
*error += String::Format("Calls don't match. %s\n", caseName.c_str());
|
||||
sucess = false;
|
||||
}
|
||||
|
||||
if (!sucess) {
|
||||
*error += " Expected:\n";
|
||||
*error += Printer::PrintFunctionCalls(oldCalls, height);
|
||||
*error += " Actual:\n";
|
||||
*error += Printer::PrintFunctionCalls(newCalls, height);
|
||||
|
||||
return TEST_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TEST_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8 TestTrackElementSegmentSupportHeight(uint8 rideType, uint8 trackType, uint8 trackSequence, std::string *error) {
|
||||
uint8 rideIndex = 0;
|
||||
uint16 height = 3 * 16;
|
||||
|
||||
rct_map_element mapElement = {0};
|
||||
mapElement.flags |= MAP_ELEMENT_FLAG_LAST_TILE;
|
||||
mapElement.properties.track.type = trackType;
|
||||
mapElement.base_height = height / 16;
|
||||
g_currently_drawn_item = &mapElement;
|
||||
|
||||
rct_map_element surfaceElement = {0};
|
||||
surfaceElement.type = MAP_ELEMENT_TYPE_SURFACE;
|
||||
surfaceElement.base_height = 2;
|
||||
gSurfaceElement = &surfaceElement;
|
||||
gDidPassSurface = true;
|
||||
|
||||
TestPaint::ResetEnvironment();
|
||||
TestPaint::ResetTunnels();
|
||||
|
||||
// TODO: Test Chainlift
|
||||
// TODO: Test Maze
|
||||
// TODO: Allow skip
|
||||
|
||||
std::string state = String::Format("[trackSequence:%d chainLift:%d]", trackSequence, 0);
|
||||
|
||||
std::vector<SegmentSupportCall> tileSegmentSupportCalls[4];
|
||||
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
TestPaint::ResetSupportHeights();
|
||||
|
||||
CallOriginal(rideType, trackType, direction, trackSequence, height, &mapElement);
|
||||
|
||||
tileSegmentSupportCalls[direction] = SegmentSupportHeightCall::getSegmentCalls(gSupportSegments, direction);
|
||||
}
|
||||
|
||||
std::vector<SegmentSupportCall> referenceCalls = tileSegmentSupportCalls[0];
|
||||
|
||||
if (!SegmentSupportHeightCall::CallsMatch(tileSegmentSupportCalls)) {
|
||||
bool success = SegmentSupportHeightCall::FindMostCommonSupportCall(tileSegmentSupportCalls, &referenceCalls);
|
||||
if (!success) {
|
||||
*error += String::Format("Original segment calls didn't match. %s\n", state.c_str());
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
*error += String::Format("# %d\n", direction);
|
||||
*error += Printer::PrintSegmentSupportHeightCalls(tileSegmentSupportCalls[direction]);
|
||||
}
|
||||
return TEST_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
TestPaint::ResetSupportHeights();
|
||||
|
||||
testpaint_clear_ignore();
|
||||
CallNew(rideType, trackType, direction, trackSequence, height, &mapElement);
|
||||
if (testpaint_is_ignored(direction, trackSequence)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<SegmentSupportCall> newCalls = SegmentSupportHeightCall::getSegmentCalls(gSupportSegments,
|
||||
direction);
|
||||
if (!SegmentSupportHeightCall::CallsEqual(referenceCalls, newCalls)) {
|
||||
*error += String::Format(
|
||||
"Segment support heights didn't match. [direction:%d] %s\n",
|
||||
direction, state.c_str()
|
||||
);
|
||||
*error += " Expected:\n";
|
||||
*error += Printer::PrintSegmentSupportHeightCalls(referenceCalls);
|
||||
*error += " Actual:\n";
|
||||
*error += Printer::PrintSegmentSupportHeightCalls(newCalls);
|
||||
|
||||
return TEST_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return TEST_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8 TestTrackElementGeneralSupportHeight(uint8 rideType, uint8 trackType, uint8 trackSequence, std::string *error) {
|
||||
uint8 rideIndex = 0;
|
||||
uint16 height = 3 * 16;
|
||||
|
||||
rct_map_element mapElement = {0};
|
||||
mapElement.flags |= MAP_ELEMENT_FLAG_LAST_TILE;
|
||||
mapElement.properties.track.type = trackType;
|
||||
mapElement.base_height = height / 16;
|
||||
g_currently_drawn_item = &mapElement;
|
||||
|
||||
rct_map_element surfaceElement = {0};
|
||||
surfaceElement.type = MAP_ELEMENT_TYPE_SURFACE;
|
||||
surfaceElement.base_height = 2;
|
||||
gSurfaceElement = &surfaceElement;
|
||||
gDidPassSurface = true;
|
||||
|
||||
TestPaint::ResetEnvironment();
|
||||
TestPaint::ResetTunnels();
|
||||
|
||||
// TODO: Test Chainlift
|
||||
// TODO: Test Maze
|
||||
// TODO: Allow skip
|
||||
|
||||
std::string state = String::Format("[trackSequence:%d chainLift:%d]", trackSequence, 0);
|
||||
|
||||
SupportCall tileGeneralSupportCalls[4];
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
TestPaint::ResetSupportHeights();
|
||||
|
||||
CallOriginal(rideType, trackType, direction, trackSequence, height, &mapElement);
|
||||
|
||||
tileGeneralSupportCalls[direction].height = -1;
|
||||
tileGeneralSupportCalls[direction].slope = -1;
|
||||
if (gSupport.height != 0) {
|
||||
tileGeneralSupportCalls[direction].height = gSupport.height;
|
||||
}
|
||||
if (gSupport.slope != 0xFF) {
|
||||
tileGeneralSupportCalls[direction].slope = gSupport.slope;
|
||||
}
|
||||
}
|
||||
|
||||
SupportCall referenceCall = tileGeneralSupportCalls[0];
|
||||
if (!GeneralSupportHeightCall::CallsMatch(tileGeneralSupportCalls)) {
|
||||
bool success = GeneralSupportHeightCall::FindMostCommonSupportCall(tileGeneralSupportCalls, &referenceCall);
|
||||
if (!success) {
|
||||
*error += String::Format("Original support calls didn't match. %s\n", state.c_str());
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
*error += String::Format("[%d, 0x%02X] ", tileGeneralSupportCalls[i].height, tileGeneralSupportCalls[i].slope);
|
||||
}
|
||||
*error += "\n";
|
||||
return TEST_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
TestPaint::ResetSupportHeights();
|
||||
|
||||
testpaint_clear_ignore();
|
||||
CallNew(rideType, trackType, direction, trackSequence, height, &mapElement);
|
||||
if (testpaint_is_ignored(direction, trackSequence)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (referenceCall.height != -1) {
|
||||
if (gSupport.height != referenceCall.height) {
|
||||
*error += String::Format(
|
||||
"General support heights didn't match. (expected height + %d, actual: height + %d) [direction:%d] %s\n",
|
||||
referenceCall.height - height,
|
||||
gSupport.height - height,
|
||||
direction,
|
||||
state.c_str()
|
||||
);
|
||||
return TEST_FAILED;
|
||||
}
|
||||
}
|
||||
if (referenceCall.slope != -1) {
|
||||
if (gSupport.slope != referenceCall.slope) {
|
||||
*error += String::Format(
|
||||
"General support slopes didn't match. (expected 0x%02X, actual: 0x%02X) [direction:%d] %s\n",
|
||||
referenceCall.slope,
|
||||
gSupport.slope,
|
||||
direction,
|
||||
state.c_str()
|
||||
);
|
||||
return TEST_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TEST_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8 TestTrackElementSideTunnels(uint8 rideType, uint8 trackType, uint8 trackSequence, std::string *error) {
|
||||
uint8 rideIndex = 0;
|
||||
uint16 height = 3 * 16;
|
||||
|
||||
rct_map_element mapElement = {0};
|
||||
mapElement.flags |= MAP_ELEMENT_FLAG_LAST_TILE;
|
||||
mapElement.properties.track.type = trackType;
|
||||
mapElement.base_height = height / 16;
|
||||
g_currently_drawn_item = &mapElement;
|
||||
|
||||
rct_map_element surfaceElement = {0};
|
||||
surfaceElement.type = MAP_ELEMENT_TYPE_SURFACE;
|
||||
surfaceElement.base_height = 2;
|
||||
gSurfaceElement = &surfaceElement;
|
||||
gDidPassSurface = true;
|
||||
|
||||
TestPaint::ResetEnvironment();
|
||||
TestPaint::ResetTunnels();
|
||||
|
||||
TunnelCall tileTunnelCalls[4][4];
|
||||
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
TestPaint::ResetTunnels();
|
||||
|
||||
for (sint8 offset = -8; offset <= 8; offset += 8) {
|
||||
CallOriginal(rideType, trackType, direction, trackSequence, height + offset, &mapElement);
|
||||
}
|
||||
|
||||
uint8 rightIndex = (4 - direction) % 4;
|
||||
uint8 leftIndex = (rightIndex + 1) % 4;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
tileTunnelCalls[direction][i].call = TUNNELCALL_SKIPPED;
|
||||
}
|
||||
|
||||
bool err = false;
|
||||
tileTunnelCalls[direction][rightIndex] = SideTunnelCall::ExtractTunnelCalls(gRightTunnels, gRightTunnelCount, height,
|
||||
&err);
|
||||
|
||||
tileTunnelCalls[direction][leftIndex] = SideTunnelCall::ExtractTunnelCalls(gLeftTunnels, gLeftTunnelCount, height,
|
||||
&err);
|
||||
|
||||
if (err) {
|
||||
*error += "Multiple tunnels on one side aren't supported.\n";
|
||||
return TEST_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
TunnelCall newTileTunnelCalls[4][4];
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
TestPaint::ResetTunnels();
|
||||
|
||||
testpaint_clear_ignore();
|
||||
|
||||
for (sint8 offset = -8; offset <= 8; offset += 8) {
|
||||
// TODO: move tunnel pushing to interface so we don't have to check the output 3 times
|
||||
CallNew(rideType, trackType, direction, trackSequence, 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;
|
||||
}
|
||||
|
||||
bool err = false;
|
||||
newTileTunnelCalls[direction][rightIndex] = SideTunnelCall::ExtractTunnelCalls(gRightTunnels, gRightTunnelCount, height,
|
||||
&err);
|
||||
|
||||
newTileTunnelCalls[direction][leftIndex] = SideTunnelCall::ExtractTunnelCalls(gLeftTunnels, gLeftTunnelCount, height,
|
||||
&err);
|
||||
|
||||
if (err) {
|
||||
*error += "Multiple tunnels on one side aren't supported.\n";
|
||||
return TEST_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!SideTunnelCall::TunnelCallsLineUp(tileTunnelCalls)) {
|
||||
*error += String::Format(
|
||||
"Original tunnel calls don\'t line up. Skipping tunnel validation [trackSequence:%d].\n",
|
||||
trackSequence
|
||||
);
|
||||
*error += Printer::PrintSideTunnelCalls(tileTunnelCalls);
|
||||
|
||||
if (!SideTunnelCall::TunnelCallsLineUp(newTileTunnelCalls)) {
|
||||
*error += String::Format("Decompiled tunnel calls don\'t line up. [trackSequence:%d].\n", trackSequence);
|
||||
*error += Printer::PrintSideTunnelCalls(newTileTunnelCalls);
|
||||
return TEST_FAILED;
|
||||
}
|
||||
|
||||
return TEST_SUCCESS;
|
||||
}
|
||||
|
||||
TunnelCall referencePattern[4];
|
||||
SideTunnelCall::GetTunnelCallReferencePattern(tileTunnelCalls, &referencePattern);
|
||||
|
||||
TunnelCall actualPattern[4];
|
||||
SideTunnelCall::GetTunnelCallReferencePattern(newTileTunnelCalls, &actualPattern);
|
||||
|
||||
if (!SideTunnelCall::TunnelPatternsMatch(referencePattern, actualPattern)) {
|
||||
*error += String::Format("Tunnel calls don't match expected pattern. [trackSequence:%d]\n", trackSequence);
|
||||
*error += " Expected:\n";
|
||||
*error += Printer::PrintSideTunnelCalls(tileTunnelCalls);
|
||||
*error += " Actual:\n";
|
||||
*error += Printer::PrintSideTunnelCalls(newTileTunnelCalls);
|
||||
return TEST_FAILED;
|
||||
}
|
||||
|
||||
return TEST_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8 TestTrackElementVerticalTunnels(uint8 rideType, uint8 trackType, uint8 trackSequence, std::string *error) {
|
||||
uint8 rideIndex = 0;
|
||||
uint16 height = 3 * 16;
|
||||
|
||||
rct_map_element mapElement = {0};
|
||||
mapElement.flags |= MAP_ELEMENT_FLAG_LAST_TILE;
|
||||
mapElement.properties.track.type = trackType;
|
||||
mapElement.base_height = height / 16;
|
||||
g_currently_drawn_item = &mapElement;
|
||||
|
||||
rct_map_element surfaceElement = {0};
|
||||
surfaceElement.type = MAP_ELEMENT_TYPE_SURFACE;
|
||||
surfaceElement.base_height = 2;
|
||||
gSurfaceElement = &surfaceElement;
|
||||
gDidPassSurface = true;
|
||||
|
||||
TestPaint::ResetEnvironment();
|
||||
TestPaint::ResetTunnels();
|
||||
|
||||
uint8 verticalTunnelHeight[4];
|
||||
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
gVerticalTunnelHeight = 0;
|
||||
CallOriginal(rideType, trackType, direction, trackSequence, height, &mapElement);
|
||||
verticalTunnelHeight[direction] = gVerticalTunnelHeight;
|
||||
}
|
||||
|
||||
if (!VerticalTunnelCall::HeightIsConsistent(verticalTunnelHeight)) {
|
||||
*error += String::Format(
|
||||
"Original vertical tunnel height is inconsistent, skipping test. [trackSequence:%d]\n",
|
||||
trackSequence
|
||||
);
|
||||
return TEST_SUCCESS;
|
||||
}
|
||||
|
||||
uint8 referenceHeight = verticalTunnelHeight[0];
|
||||
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
gVerticalTunnelHeight = 0;
|
||||
|
||||
testpaint_clear_ignore();
|
||||
CallOriginal(rideType, trackType, direction, trackSequence, height, &mapElement);
|
||||
if (testpaint_is_ignored(direction, trackSequence)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (gVerticalTunnelHeight != referenceHeight) {
|
||||
if (gVerticalTunnelHeight == 0) {
|
||||
*error += String::Format(
|
||||
"Expected no tunnel. Actual: %d [trackSequence:%d]\n",
|
||||
gVerticalTunnelHeight, trackSequence
|
||||
);
|
||||
return TEST_FAILED;
|
||||
}
|
||||
|
||||
*error += String::Format(
|
||||
"Expected vertical tunnel height to be `%s`, was `%s`. [trackSequence:%d direction:%d]\n",
|
||||
Printer::PrintHeightOffset((referenceHeight * 16), height).c_str(),
|
||||
Printer::PrintHeightOffset((gVerticalTunnelHeight * 16), height).c_str(),
|
||||
trackSequence,
|
||||
direction
|
||||
);
|
||||
|
||||
return TEST_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return TEST_SUCCESS;
|
||||
}
|
||||
26
test/testpaint/TestTrack.hpp
Normal file
26
test/testpaint/TestTrack.hpp
Normal file
@@ -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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "../../src/common.h"
|
||||
|
||||
class TestTrack {
|
||||
public:
|
||||
static uint8 TestPaintTrackElement(uint8 rideType, uint8 trackType, std::string *out);
|
||||
};
|
||||
69
test/testpaint/Utils.cpp
Normal file
69
test/testpaint/Utils.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#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 "Utils.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "../../src/ride/ride.h"
|
||||
#include "../../src/ride/track.h"
|
||||
#include "../../src/ride/track_data.h"
|
||||
}
|
||||
|
||||
namespace Utils {
|
||||
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(uint8 rideType, uint8 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;
|
||||
}
|
||||
|
||||
bool rideIsImplemented(uint8 rideType) {
|
||||
TRACK_PAINT_FUNCTION_GETTER newPaintGetter = RideTypeTrackPaintFunctions[rideType];
|
||||
return (newPaintGetter != 0);
|
||||
}
|
||||
}
|
||||
25
test/testpaint/Utils.hpp
Normal file
25
test/testpaint/Utils.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../src/common.h"
|
||||
|
||||
namespace Utils {
|
||||
int getTrackSequenceCount(uint8 rideType, uint8 trackType);
|
||||
bool rideSupportsTrackType(uint8 rideType, uint8 trackType);
|
||||
bool rideIsImplemented(uint8 rideType);
|
||||
}
|
||||
25
test/testpaint/VerticalTunnelCall.cpp
Normal file
25
test/testpaint/VerticalTunnelCall.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#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 "VerticalTunnelCall.hpp"
|
||||
|
||||
bool VerticalTunnelCall::HeightIsConsistent(uint8 heights[4]) {
|
||||
for (int i = 1; i < 4; ++i) {
|
||||
if (heights[i] != heights[0]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
23
test/testpaint/VerticalTunnelCall.hpp
Normal file
23
test/testpaint/VerticalTunnelCall.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../src/common.h"
|
||||
|
||||
namespace VerticalTunnelCall {
|
||||
bool HeightIsConsistent(uint8 heights[4]);
|
||||
};
|
||||
@@ -18,7 +18,12 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "intercept.h"
|
||||
#include "FunctionCall.hpp"
|
||||
#include "PaintIntercept.hpp"
|
||||
#include "SegmentSupportHeightCall.hpp"
|
||||
#include "SideTunnelCall.hpp"
|
||||
#include "String.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -172,7 +177,7 @@ private:
|
||||
|
||||
void GenerateTrackFunctionBody(int tabs, int trackType)
|
||||
{
|
||||
int numSequences = getTrackSequenceCount(_rideType, trackType);
|
||||
int numSequences = Utils::getTrackSequenceCount(_rideType, trackType);
|
||||
if (numSequences > 1)
|
||||
{
|
||||
WriteLine(tabs, "switch (trackSequence) {");
|
||||
@@ -397,9 +402,9 @@ private:
|
||||
bool blockSegmentsBeforeSupports = false;
|
||||
|
||||
std::vector<function_call> calls[4], chainLiftCalls[4], cableLiftCalls[4];
|
||||
Intercept2::TunnelCall tileTunnelCalls[4][4];
|
||||
TunnelCall tileTunnelCalls[4][4];
|
||||
sint16 verticalTunnelHeights[4];
|
||||
std::vector<Intercept2::SegmentSupportCall> segmentSupportCalls[4];
|
||||
std::vector<SegmentSupportCall> segmentSupportCalls[4];
|
||||
support_height generalSupports[4] = { 0 };
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
rct_map_element mapElement = { 0 };
|
||||
@@ -417,9 +422,9 @@ private:
|
||||
RCT2_GLOBAL(0x009DE56E, sint16) = 64;
|
||||
|
||||
function_call callBuffer[256] = { 0 };
|
||||
intercept_clear_calls();
|
||||
PaintIntercept::ClearCalls();
|
||||
CallOriginal(trackType, direction, trackSequence, height, &mapElement);
|
||||
int numCalls = intercept_get_calls(callBuffer);
|
||||
int numCalls = PaintIntercept::GetCalls(callBuffer);
|
||||
calls[direction].insert(calls[direction].begin(), callBuffer, callBuffer + numCalls);
|
||||
|
||||
for (auto &&call : calls[direction]) {
|
||||
@@ -429,7 +434,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
segmentSupportCalls[direction] = Intercept2::getSegmentCalls(gSupportSegments, direction);
|
||||
segmentSupportCalls[direction] = SegmentSupportHeightCall::getSegmentCalls(gSupportSegments, direction);
|
||||
generalSupports[direction] = gSupport;
|
||||
if (gSupport.slope != 0xFF && gSupport.height != 0)
|
||||
{
|
||||
@@ -438,9 +443,9 @@ private:
|
||||
|
||||
// Get chain lift calls
|
||||
mapElement.type |= 0x80;
|
||||
intercept_clear_calls();
|
||||
PaintIntercept::ClearCalls();
|
||||
CallOriginal(trackType, direction, trackSequence, height, &mapElement);
|
||||
numCalls = intercept_get_calls(callBuffer);
|
||||
numCalls = PaintIntercept::GetCalls(callBuffer);
|
||||
chainLiftCalls[direction].insert(chainLiftCalls[direction].begin(), callBuffer, callBuffer + numCalls);
|
||||
|
||||
// Get cable lift calls (giga coaster only)
|
||||
@@ -448,9 +453,9 @@ private:
|
||||
{
|
||||
mapElement.type = 0;
|
||||
mapElement.properties.track.colour |= TRACK_ELEMENT_COLOUR_FLAG_CABLE_LIFT;
|
||||
intercept_clear_calls();
|
||||
PaintIntercept::ClearCalls();
|
||||
CallOriginal(trackType, direction, trackSequence, height, &mapElement);
|
||||
numCalls = intercept_get_calls(callBuffer);
|
||||
numCalls = PaintIntercept::GetCalls(callBuffer);
|
||||
cableLiftCalls[direction].insert(cableLiftCalls[direction].begin(), callBuffer, callBuffer + numCalls);
|
||||
}
|
||||
|
||||
@@ -461,9 +466,9 @@ private:
|
||||
RCT2_GLOBAL(0x009DE56E, sint16) = 64;
|
||||
mapElement.type = 0;
|
||||
mapElement.properties.track.colour &= ~TRACK_ELEMENT_COLOUR_FLAG_CABLE_LIFT;
|
||||
intercept_clear_calls();
|
||||
PaintIntercept::ClearCalls();
|
||||
CallOriginal(trackType, direction, trackSequence, height, &mapElement);
|
||||
numCalls = intercept_get_calls(callBuffer);
|
||||
numCalls = PaintIntercept::GetCalls(callBuffer);
|
||||
std::vector<function_call> checkCalls = std::vector<function_call>(callBuffer, callBuffer + numCalls);
|
||||
if (!CompareFunctionCalls(checkCalls, calls[direction]))
|
||||
{
|
||||
@@ -630,17 +635,17 @@ private:
|
||||
{
|
||||
const char * funcName = GetFunctionCallName(call.function);
|
||||
std::string imageId = GetImageIdString(call.paint.image_id);
|
||||
std::string s = StringFormat("%s_rotated(direction, %s, ", funcName, imageId.c_str());
|
||||
std::string s = String::Format("%s_rotated(direction, %s, ", funcName, imageId.c_str());
|
||||
s += FormatXYSwap(call.paint.offset.x, call.paint.offset.y, direction);
|
||||
s += ", ";
|
||||
s += FormatXYSwap(call.paint.bound_box_length.x, call.paint.bound_box_length.y, direction);
|
||||
s += StringFormat(", %d, height%s", call.paint.bound_box_length.z, GetOffsetExpressionString(call.paint.z_offset - height).c_str());
|
||||
s += String::Format(", %d, height%s", call.paint.bound_box_length.z, GetOffsetExpressionString(call.paint.z_offset - height).c_str());
|
||||
|
||||
if (call.function != PAINT_98196C)
|
||||
{
|
||||
s += ", ";
|
||||
s += FormatXYSwap(call.paint.bound_box_offset.x, call.paint.bound_box_offset.y, direction);
|
||||
s += StringFormat(", height%s", GetOffsetExpressionString(call.paint.bound_box_offset.z - height).c_str());
|
||||
s += String::Format(", height%s", GetOffsetExpressionString(call.paint.bound_box_offset.z - height).c_str());
|
||||
}
|
||||
|
||||
s += ");";
|
||||
@@ -651,11 +656,11 @@ private:
|
||||
{
|
||||
if (direction & 1)
|
||||
{
|
||||
return StringFormat("%d, %d", y, x);
|
||||
return String::Format("%d, %d", y, x);
|
||||
}
|
||||
else
|
||||
{
|
||||
return StringFormat("%d, %d", x, y);
|
||||
return String::Format("%d, %d", x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -711,7 +716,7 @@ private:
|
||||
|
||||
bool CompareFunctionCall(const function_call a, const function_call &b)
|
||||
{
|
||||
return assertFunctionCallEquals(a, b);
|
||||
return FunctionCall::AssertsEquals(a, b);
|
||||
}
|
||||
|
||||
const char * GetFunctionCallName(int function)
|
||||
@@ -734,11 +739,11 @@ private:
|
||||
int trackSequence,
|
||||
int height,
|
||||
rct_map_element * mapElement,
|
||||
Intercept2::TunnelCall tileTunnelCalls[4][4],
|
||||
TunnelCall tileTunnelCalls[4][4],
|
||||
sint16 verticalTunnelHeights[4])
|
||||
{
|
||||
gLeftTunnelCount = 0;
|
||||
gRightTunnelCount = 0;
|
||||
TestPaint::ResetTunnels();
|
||||
|
||||
for (int offset = -8; offset <= 8; offset += 8)
|
||||
{
|
||||
CallOriginal(trackType, direction, trackSequence, height + offset, mapElement);
|
||||
@@ -748,13 +753,13 @@ private:
|
||||
uint8 leftIndex = (rightIndex + 1) % 4;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
tileTunnelCalls[direction][i].call = Intercept2::TUNNELCALL_SKIPPED;
|
||||
tileTunnelCalls[direction][i].call = TUNNELCALL_SKIPPED;
|
||||
}
|
||||
if (gRightTunnelCount == 0) {
|
||||
tileTunnelCalls[direction][rightIndex].call = Intercept2::TUNNELCALL_NONE;
|
||||
tileTunnelCalls[direction][rightIndex].call = TUNNELCALL_NONE;
|
||||
} else if (gRightTunnelCount == 3) {
|
||||
tileTunnelCalls[direction][rightIndex].call = Intercept2::TUNNELCALL_CALL;
|
||||
tileTunnelCalls[direction][rightIndex].offset = Intercept2::getTunnelOffset(height, gRightTunnels);
|
||||
tileTunnelCalls[direction][rightIndex].call = TUNNELCALL_CALL;
|
||||
tileTunnelCalls[direction][rightIndex].offset = SideTunnelCall::GetTunnelOffset(height, gRightTunnels);
|
||||
tileTunnelCalls[direction][rightIndex].type = gRightTunnels[0].type;
|
||||
} else {
|
||||
printf("Multiple tunnels on one side aren't supported.\n");
|
||||
@@ -762,10 +767,10 @@ private:
|
||||
}
|
||||
|
||||
if (gLeftTunnelCount == 0) {
|
||||
tileTunnelCalls[direction][leftIndex].call = Intercept2::TUNNELCALL_NONE;
|
||||
tileTunnelCalls[direction][leftIndex].call = TUNNELCALL_NONE;
|
||||
} else if (gLeftTunnelCount == 3) {
|
||||
tileTunnelCalls[direction][leftIndex].call = Intercept2::TUNNELCALL_CALL;
|
||||
tileTunnelCalls[direction][leftIndex].offset = Intercept2::getTunnelOffset(height, gLeftTunnels);
|
||||
tileTunnelCalls[direction][leftIndex].call = TUNNELCALL_CALL;
|
||||
tileTunnelCalls[direction][leftIndex].offset = SideTunnelCall::GetTunnelOffset(height, gLeftTunnels);
|
||||
tileTunnelCalls[direction][leftIndex].type = gLeftTunnels[0].type;
|
||||
} else {
|
||||
printf("Multiple tunnels on one side aren't supported.\n");
|
||||
@@ -785,7 +790,7 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
void GenerateTunnelCall(int tabs, Intercept2::TunnelCall tileTunnelCalls[4][4], sint16 verticalTunnelHeights[4])
|
||||
void GenerateTunnelCall(int tabs, TunnelCall tileTunnelCalls[4][4], sint16 verticalTunnelHeights[4])
|
||||
{
|
||||
constexpr uint8 TunnelLeft = 0;
|
||||
constexpr uint8 TunnelRight = 1;
|
||||
@@ -806,7 +811,7 @@ private:
|
||||
for (int side = 0; side < 4; side++)
|
||||
{
|
||||
auto tunnel = tileTunnelCalls[direction][side];
|
||||
if (tunnel.call == Intercept2::TUNNELCALL_CALL)
|
||||
if (tunnel.call == TUNNELCALL_CALL)
|
||||
{
|
||||
tunnelOffset[direction] = tunnel.offset;
|
||||
tunnelType[direction] = tunnel.type;
|
||||
@@ -854,7 +859,7 @@ private:
|
||||
WriteLine(tabs, "case %d:", i);
|
||||
for (int side = 0; side < 4; side++)
|
||||
{
|
||||
if (tileTunnelCalls[i][side].call == Intercept2::TUNNELCALL_CALL)
|
||||
if (tileTunnelCalls[i][side].call == TUNNELCALL_CALL)
|
||||
{
|
||||
GenerateTunnelCall(tabs + 1, tileTunnelCalls[i][side].offset, tileTunnelCalls[i][side].type, dsToWay[i][side]);
|
||||
}
|
||||
@@ -892,7 +897,7 @@ private:
|
||||
WriteLine(tabs, "paint_util_push_tunnel_rotated(direction, height%s, TUNNEL_%d);", GetOffsetExpressionString(offset).c_str(), type);
|
||||
}
|
||||
|
||||
void GenerateSegmentSupportCall(int tabs, std::vector<Intercept2::SegmentSupportCall> segmentSupportCalls[4])
|
||||
void GenerateSegmentSupportCall(int tabs, std::vector<SegmentSupportCall> segmentSupportCalls[4])
|
||||
{
|
||||
for (size_t i = 0; i < segmentSupportCalls[0].size(); i++)
|
||||
{
|
||||
@@ -912,12 +917,12 @@ private:
|
||||
if (ssh.height == 0xFFFF)
|
||||
{
|
||||
szCall += "0xFFFF";
|
||||
szCall += StringFormat(", 0);", ssh.slope);
|
||||
szCall += String::Format(", 0);", ssh.slope);
|
||||
}
|
||||
else
|
||||
{
|
||||
szCall += std::to_string(ssh.height);
|
||||
szCall += StringFormat(", 0x%02X);", ssh.slope);
|
||||
szCall += String::Format(", 0x%02X);", ssh.slope);
|
||||
}
|
||||
WriteLine(tabs, szCall);
|
||||
}
|
||||
@@ -948,20 +953,20 @@ private:
|
||||
uint32 palette = imageId & ~0x7FFFF;
|
||||
|
||||
std::string paletteName;
|
||||
if (palette == Intercept2::DEFAULT_SCHEME_TRACK) paletteName = "gTrackColours[SCHEME_TRACK]";
|
||||
else if (palette == Intercept2::DEFAULT_SCHEME_SUPPORTS) paletteName = "gTrackColours[SCHEME_SUPPORTS]";
|
||||
else if (palette == Intercept2::DEFAULT_SCHEME_MISC) paletteName = "gTrackColours[SCHEME_MISC]";
|
||||
else if (palette == Intercept2::DEFAULT_SCHEME_3) paletteName = "gTrackColours[SCHEME_3]";
|
||||
if (palette == TestPaint::DEFAULT_SCHEME_TRACK) paletteName = "gTrackColours[SCHEME_TRACK]";
|
||||
else if (palette == TestPaint::DEFAULT_SCHEME_SUPPORTS) paletteName = "gTrackColours[SCHEME_SUPPORTS]";
|
||||
else if (palette == TestPaint::DEFAULT_SCHEME_MISC) paletteName = "gTrackColours[SCHEME_MISC]";
|
||||
else if (palette == TestPaint::DEFAULT_SCHEME_3) paletteName = "gTrackColours[SCHEME_3]";
|
||||
else {
|
||||
paletteName = StringFormat("0x%08X", palette);
|
||||
paletteName = String::Format("0x%08X", palette);
|
||||
}
|
||||
|
||||
if (image == 0) {
|
||||
result = paletteName;
|
||||
} else if (image & 0x70000) {
|
||||
result = StringFormat("%s | vehicle.base_image_id + %d", paletteName.c_str(), image & ~0x70000);
|
||||
result = String::Format("%s | vehicle.base_image_id + %d", paletteName.c_str(), image & ~0x70000);
|
||||
} else {
|
||||
result = StringFormat("%s | %d", paletteName.c_str(), image);
|
||||
result = String::Format("%s | %d", paletteName.c_str(), image);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -982,7 +987,7 @@ private:
|
||||
if (segmentsPrinted > 0) {
|
||||
s += " | ";
|
||||
}
|
||||
s += StringFormat("SEGMENT_%02X", 0xB4 + 4 * i);
|
||||
s += String::Format("SEGMENT_%02X", 0xB4 + 4 * i);
|
||||
segmentsPrinted++;
|
||||
}
|
||||
}
|
||||
@@ -1004,35 +1009,8 @@ private:
|
||||
|
||||
void CallOriginal(int trackType, int direction, int trackSequence, int height, rct_map_element *mapElement)
|
||||
{
|
||||
gPaintInteractionType = VIEWPORT_INTERACTION_ITEM_RIDE;
|
||||
gTrackColours[SCHEME_TRACK] = Intercept2::DEFAULT_SCHEME_TRACK;
|
||||
gTrackColours[SCHEME_SUPPORTS] = Intercept2::DEFAULT_SCHEME_SUPPORTS;
|
||||
gTrackColours[SCHEME_MISC] = Intercept2::DEFAULT_SCHEME_MISC;
|
||||
gTrackColours[SCHEME_3] = Intercept2::DEFAULT_SCHEME_3;
|
||||
|
||||
rct_drawpixelinfo dpi = { 0 };
|
||||
dpi.zoom_level = 1;
|
||||
unk_140E9A8 = &dpi;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
TestPaint::ResetEnvironment();
|
||||
TestPaint::ResetSupportHeights();
|
||||
|
||||
uint32 *trackDirectionList = (uint32 *)RideTypeTrackPaintFunctionsOld[_rideType][trackType];
|
||||
// Have to call from this point as it pushes esi and expects callee to pop it
|
||||
@@ -1120,18 +1098,6 @@ private:
|
||||
}
|
||||
fprintf(_file, "%s\n", s.c_str());
|
||||
}
|
||||
|
||||
static std::string StringFormat(const char * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buffer[512];
|
||||
|
||||
va_start(args, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
va_end(args);
|
||||
|
||||
return std::string(buffer);
|
||||
}
|
||||
};
|
||||
|
||||
extern "C"
|
||||
|
||||
@@ -1,820 +0,0 @@
|
||||
#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;
|
||||
|
||||
#define BLANK_SUPPORT {.height = 0, .slope = 0xFF}
|
||||
static const support_height DefaultSegmentHeight[9] = {
|
||||
BLANK_SUPPORT, BLANK_SUPPORT, BLANK_SUPPORT,
|
||||
BLANK_SUPPORT, BLANK_SUPPORT, BLANK_SUPPORT,
|
||||
BLANK_SUPPORT, BLANK_SUPPORT, BLANK_SUPPORT
|
||||
};
|
||||
|
||||
extern const utf8string RideNames[91];
|
||||
extern const utf8string TrackNames[256];
|
||||
extern const utf8string FlatTrackNames[256];
|
||||
|
||||
static bool _woodenSupports;
|
||||
static uint8 callCount;
|
||||
static function_call calls[256];
|
||||
|
||||
void intercept_clear_calls()
|
||||
{
|
||||
callCount = 0;
|
||||
memset(calls, 0, sizeof(calls));
|
||||
}
|
||||
|
||||
int intercept_get_calls(function_call * buffer)
|
||||
{
|
||||
memcpy(buffer, calls, 256);
|
||||
return callCount;
|
||||
}
|
||||
|
||||
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 _woodenSupports;
|
||||
}
|
||||
|
||||
bool wooden_b_supports_paint_setup(int supportType, int special, int height, uint32 imageColourFlags, bool *underground) {
|
||||
|
||||
function_call call = {
|
||||
.function = SUPPORTS_WOOD_B,
|
||||
.supports = {
|
||||
.type = supportType,
|
||||
.special = special,
|
||||
.height = height,
|
||||
.colour_flags = imageColourFlags,
|
||||
}
|
||||
};
|
||||
|
||||
calls[callCount] = call;
|
||||
callCount++;
|
||||
return _woodenSupports;
|
||||
}
|
||||
|
||||
static void check_support_height()
|
||||
{
|
||||
// First get last known support height state
|
||||
if (memcmp(gSupportSegments, &DefaultSegmentHeight, sizeof(support_height) * 9) == 0) {
|
||||
// Nothing changed
|
||||
return;
|
||||
}
|
||||
|
||||
function_call call = {
|
||||
.function = SET_SEGMENT_HEIGHT
|
||||
};
|
||||
|
||||
calls[callCount] = call;
|
||||
callCount++;
|
||||
}
|
||||
|
||||
bool metal_a_supports_paint_setup(int supportType, int segment, int special, int height, uint32 imageColourFlags) {
|
||||
|
||||
check_support_height();
|
||||
|
||||
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) {
|
||||
|
||||
check_support_height();
|
||||
|
||||
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_FENCE_SPIRAL_SLIDE, // 20564
|
||||
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 >= 20564 && spriteIndex <= 20567) {
|
||||
return SPRITEGROUP_FENCE_SPIRAL_SLIDE;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 (function == SET_SEGMENT_HEIGHT) {
|
||||
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, size_t len) {
|
||||
uint32 image = input & 0x7FFFF;
|
||||
uint32 palette = input & ~0x7FFFF;
|
||||
|
||||
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);
|
||||
snprintf(paletteName, 16, "0x%08X", palette);
|
||||
}
|
||||
|
||||
if (image == 0) {
|
||||
snprintf(out, len, "%s", paletteName);
|
||||
} else if (image & 0x70000) {
|
||||
snprintf(out, len, "%s | vehicle.base_image_id + %d", paletteName, image & ~0x70000);
|
||||
} else {
|
||||
snprintf(out, len, "%s | %d", paletteName, image);
|
||||
}
|
||||
}
|
||||
|
||||
static void printFunctionCall(utf8string out, size_t len, function_call call) {
|
||||
utf8string imageId = malloc(64);
|
||||
printImageId(call.supports.colour_flags, imageId, 64);
|
||||
switch (call.function) {
|
||||
case SUPPORTS_WOOD_A:
|
||||
snprintf(out, len, "wooden_a_supports_paint_setup(%d, %d, %d, %s)", call.supports.type, call.supports.special, call.supports.height, imageId);
|
||||
return;
|
||||
case SUPPORTS_WOOD_B:
|
||||
snprintf(out, len, "wooden_b_supports_paint_setup(%d, %d, %d, %s)", call.supports.type, call.supports.special, call.supports.height, imageId);
|
||||
return;
|
||||
|
||||
case SUPPORTS_METAL_A:
|
||||
snprintf(out, len, "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:
|
||||
snprintf(out, len, "metal_b_supports_paint_setup(%d, %d, %d, %d, %s)", call.supports.type, call.supports.segment, call.supports.special, call.supports.height, imageId);
|
||||
return;
|
||||
|
||||
case SET_SEGMENT_HEIGHT:
|
||||
snprintf(out, len, "paint_util_set_segment_support_height");
|
||||
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;
|
||||
}
|
||||
|
||||
size_t slen;
|
||||
|
||||
printImageId(call.paint.image_id, imageId, 64);
|
||||
slen = snprintf(
|
||||
out,
|
||||
len,
|
||||
"%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 (slen >= len) return;
|
||||
|
||||
if (call.function != PAINT_98196C) {
|
||||
if (slen < len)
|
||||
slen += snprintf(
|
||||
out + slen,
|
||||
len - slen,
|
||||
"%d, %d, %d, ",
|
||||
call.paint.bound_box_offset.x, call.paint.bound_box_offset.y, call.paint.bound_box_offset.z
|
||||
);
|
||||
}
|
||||
|
||||
if (slen < len)
|
||||
slen += snprintf(out + slen, len - slen, "%d)", call.paint.rotation);
|
||||
|
||||
if (call.function != PAINT_98196C) {
|
||||
if (slen < len)
|
||||
snprintf(out + slen, len - slen, " = { %d, %d, %d }, { %d, %d, %d }, { %d, %d, %d }",
|
||||
call.paint.offset.x, call.paint.offset.y, call.paint.z_offset - 48,
|
||||
call.paint.bound_box_offset.x, call.paint.bound_box_offset.y, call.paint.bound_box_offset.z - 48,
|
||||
call.paint.bound_box_length.x, call.paint.bound_box_length.y, call.paint.bound_box_length.z);
|
||||
}
|
||||
}
|
||||
|
||||
static void printFunctionCallArray(utf8string out, size_t len, function_call calls[], uint8 count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
utf8string callOut = malloc(1024);
|
||||
printFunctionCall(callOut, 1024, calls[i]);
|
||||
size_t slen = strlen(out);
|
||||
if (slen < len)
|
||||
snprintf(out + slen, len - slen, "%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, size_t len) {
|
||||
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
|
||||
snprintf(error, len, "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_ride ride = { 0 };
|
||||
ride.entrance_style = RIDE_ENTRANCE_STYLE_CANVAS_TENT;
|
||||
|
||||
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;
|
||||
|
||||
snprintf(error, len, "rct2: 0x%08X\n", RideTypeTrackPaintFunctionsOld[rideType][trackType]);
|
||||
|
||||
TRACK_PAINT_FUNCTION_GETTER newPaintGetter = RideTypeTrackPaintFunctions[rideType];
|
||||
int sequenceCount = getTrackSequenceCount(rideType, trackType);
|
||||
|
||||
for (int supports = 0; supports < 2; supports++) {
|
||||
if (supports == 0) {
|
||||
_woodenSupports = false;
|
||||
} else {
|
||||
_woodenSupports = true;
|
||||
}
|
||||
for (int inverted = 0; inverted < 2; inverted++) {
|
||||
if (inverted == 0) {
|
||||
mapElement.properties.track.colour &= ~TRACK_ELEMENT_COLOUR_FLAG_INVERTED;
|
||||
} else {
|
||||
mapElement.properties.track.colour |= TRACK_ELEMENT_COLOUR_FLAG_INVERTED;
|
||||
}
|
||||
for (int chainLift = 0; chainLift < 2; chainLift++) {
|
||||
if (chainLift == 0) {
|
||||
mapElement.type &= ~0x80;
|
||||
} else {
|
||||
mapElement.type |= 0x80;
|
||||
}
|
||||
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));
|
||||
|
||||
memcpy(gSupportSegments, DefaultSegmentHeight, sizeof(support_height) * 9);
|
||||
|
||||
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;
|
||||
|
||||
testpaint_clear_ignore();
|
||||
memcpy(gSupportSegments, DefaultSegmentHeight, sizeof(support_height) * 9);
|
||||
newPaintFunction(rideIndex, trackSequence, direction, height, &mapElement);
|
||||
if (testpaint_is_ignored(direction, trackSequence)) {
|
||||
snprintf(error, len, "[ IGNORED ] [direction:%d trackSequence:%d chainLift:%d inverted:%d]\n",
|
||||
direction, trackSequence, chainLift, inverted);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8 newCallCount = callCount;
|
||||
function_call newCalls[256];
|
||||
memcpy(&newCalls, &calls, sizeof(calls));
|
||||
|
||||
if (!assertFunctionCallArrayEquals(oldCalls, oldCallCount, newCalls, newCallCount)) {
|
||||
utf8string diff = malloc(2048);
|
||||
|
||||
snprintf(diff, 2048, "<<< EXPECTED\n");
|
||||
printFunctionCallArray(diff, 2048, oldCalls, oldCallCount);
|
||||
|
||||
size_t slen = strlen(diff);
|
||||
if (slen < 2048)
|
||||
snprintf(diff + slen, 2048 - slen, "====\n");
|
||||
printFunctionCallArray(diff, 2048, newCalls, newCallCount);
|
||||
|
||||
slen = strlen(diff);
|
||||
if (slen < 2048)
|
||||
snprintf(diff + slen, 2048 - slen, ">>> ACTUAL\n");
|
||||
|
||||
if (oldCallCount != newCallCount) {
|
||||
slen = strlen(error);
|
||||
if (slen < len)
|
||||
snprintf(error + slen, len - slen, "Call counts don't match (was %d, expected %d) [direction:%d trackSequence:%d chainLift:%d inverted:%d]",
|
||||
newCallCount, oldCallCount, direction, trackSequence, chainLift, inverted);
|
||||
} else {
|
||||
slen = strlen(error);
|
||||
if (slen < len)
|
||||
snprintf(error + slen, len - slen, "Calls don't match [direction:%d trackSequence:%d chainLift:%d inverted:%d]",
|
||||
direction, trackSequence, chainLift, inverted);
|
||||
}
|
||||
|
||||
slen = strlen(error);
|
||||
if (slen < len)
|
||||
snprintf(error + slen, len - slen, "\n%s", diff);
|
||||
|
||||
free(diff);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, 2048);
|
||||
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};
|
||||
bool output = wooden_a_supports_paint_setup(regs.edi, (sint16) regs.ax, regs.dx, (uint32) regs.ebp, NULL);
|
||||
|
||||
return output ? 1 : 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};
|
||||
bool output = wooden_b_supports_paint_setup(regs.edi, (sint16) regs.ax, regs.dx, (uint32) regs.ebp, NULL);
|
||||
|
||||
return output ? 1 : 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);
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
#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"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
#include "../../src/interface/colour.h"
|
||||
#include "../../src/paint/paint.h"
|
||||
#include "../../src/paint/map_element/map_element.h"
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define gRideEntries RCT2_ADDRESS(RCT2_ADDRESS_RIDE_ENTRIES, rct_ride_entry*)
|
||||
#define gCurrentRotation RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)
|
||||
|
||||
enum
|
||||
{
|
||||
PAINT_98196C,
|
||||
PAINT_98197C,
|
||||
PAINT_98198C,
|
||||
PAINT_98199C,
|
||||
|
||||
SUPPORTS_METAL_A,
|
||||
SUPPORTS_METAL_B,
|
||||
SUPPORTS_WOOD_A,
|
||||
SUPPORTS_WOOD_B,
|
||||
|
||||
SET_SEGMENT_HEIGHT,
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
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);
|
||||
void intercept_clear_calls();
|
||||
int intercept_get_calls(function_call * buffer);
|
||||
bool assertFunctionCallEquals(function_call expected, function_call actual);
|
||||
|
||||
int generatePaintCode(uint8 rideType);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <vector>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
sint16 getTunnelOffset(uint32 baseHeight, tunnel_entry calls[3]);
|
||||
std::vector<SegmentSupportCall> getSegmentCalls(support_height supports[9], uint8 rotation);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // #endif _TEST_PAINT_INTERCEPT_H_
|
||||
@@ -1,872 +0,0 @@
|
||||
#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 <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "intercept.h"
|
||||
|
||||
extern "C" {
|
||||
#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 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;
|
||||
}
|
||||
|
||||
std::vector<SegmentSupportCall> 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<SegmentSupportCall> calls;
|
||||
|
||||
while (positionsRemaining != 0) {
|
||||
SegmentSupportCall call = {0};
|
||||
call.height = -1;
|
||||
call.slope = -1;
|
||||
|
||||
support_height referenceSupport = { 0 };
|
||||
|
||||
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<SegmentSupportCall> lhs, std::vector<SegmentSupportCall> 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<SegmentSupportCall> tileSegmentSupportCalls[4])
|
||||
{
|
||||
std::vector<SegmentSupportCall> 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, size_t len, std::vector<SegmentSupportCall> segmentCalls)
|
||||
{
|
||||
for (auto &&call : segmentCalls) {
|
||||
int segmentsPrinted = 0;
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (call.segments & segment_offsets[i]) {
|
||||
if (segmentsPrinted > 0) {
|
||||
size_t slen = strlen(out);
|
||||
if (slen < len)
|
||||
snprintf(out + slen, len - slen, " | ");
|
||||
}
|
||||
size_t slen = strlen(out);
|
||||
if (slen < len)
|
||||
snprintf(out + slen, slen - len, "SEGMENT_%02X", 0xB4 + 4 * i);
|
||||
segmentsPrinted++;
|
||||
}
|
||||
}
|
||||
|
||||
if (call.height == 0xFFFF) {
|
||||
size_t slen = strlen(out);
|
||||
if (slen < len)
|
||||
snprintf(out + slen, len - slen, ", 0xFFFF");
|
||||
} else {
|
||||
size_t slen = strlen(out);
|
||||
if (slen < len)
|
||||
snprintf(out + slen, len - slen, ", %d", call.height);
|
||||
}
|
||||
|
||||
size_t slen = strlen(out);
|
||||
if (slen < len)
|
||||
snprintf(out + slen, len - slen, ", 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[32];
|
||||
|
||||
switch (edge.call) {
|
||||
case TUNNELCALL_SKIPPED:
|
||||
snprintf(out, 32, "%s", " ");
|
||||
break;
|
||||
|
||||
case TUNNELCALL_NONE:
|
||||
snprintf(out, 32, "%s", " - ");
|
||||
break;
|
||||
|
||||
case TUNNELCALL_CALL:
|
||||
if (edge.offset == 0) {
|
||||
snprintf(out, 32, " 0/%X ", edge.type);
|
||||
} else {
|
||||
utf8string offset = new utf8[16];
|
||||
if (edge.offset < 0) {
|
||||
snprintf(offset, 16, "%d", edge.offset);
|
||||
} else {
|
||||
snprintf(offset, 16, "+%d", edge.offset);
|
||||
}
|
||||
|
||||
snprintf(out, 32, "%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_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 chainLift = 0; chainLift < 2; chainLift++) {
|
||||
if (chainLift == 0) {
|
||||
mapElement.type &= ~0x80;
|
||||
} else {
|
||||
mapElement.type |= 0x80;
|
||||
}
|
||||
|
||||
for (int trackSequence = 0; trackSequence < sequenceCount; trackSequence++) {
|
||||
std::vector<SegmentSupportCall> 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 chainLift:%d]\n", trackSequence, chainLift);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
for (int s = 0; s < 9; ++s) {
|
||||
gSupportSegments[s].height = 0;
|
||||
gSupportSegments[s].slope = 0xFF;
|
||||
}
|
||||
|
||||
testpaint_clear_ignore();
|
||||
TRACK_PAINT_FUNCTION newPaintFunction = newPaintGetter(trackType, direction);
|
||||
newPaintFunction(rideIndex, trackSequence, direction, height, &mapElement);
|
||||
if (testpaint_is_ignored(direction, trackSequence)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<SegmentSupportCall> newCalls = getSegmentCalls(gSupportSegments, direction);
|
||||
|
||||
if (!SegmentCallEquals(tileSegmentSupportCalls[0], newCalls)) {
|
||||
// TODO put this into *error
|
||||
utf8string diff = new utf8[2048];
|
||||
snprintf(diff, 2048, "<<< EXPECTED\n");
|
||||
printSegmentSupports(diff, 2048, tileSegmentSupportCalls[0]);
|
||||
|
||||
size_t slen = strlen(diff);
|
||||
if (slen < 2048)
|
||||
snprintf(diff + slen, 2048 - slen, "====\n");
|
||||
printSegmentSupports(diff, 2048, newCalls);
|
||||
|
||||
slen = strlen(diff);
|
||||
if (slen < 2048)
|
||||
snprintf(diff + strlen(diff), 2048 - slen, ">>> ACTUAL\n");
|
||||
|
||||
printf("Segment support heights didn't match. [direction:%d trackSequence:%d chainLift:%d]\n", direction,
|
||||
trackSequence, chainLift);
|
||||
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 chainLift:%d]\n", trackSequence, chainLift);
|
||||
continue;
|
||||
}
|
||||
|
||||
SupportCall referenceGeneralSupportCall = tileGeneralSupportCalls[0];
|
||||
|
||||
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
gSupport.height = 0;
|
||||
gSupport.slope = 0xFF;
|
||||
|
||||
testpaint_clear_ignore();
|
||||
TRACK_PAINT_FUNCTION newPaintFunction = newPaintGetter(trackType, direction);
|
||||
newPaintFunction(rideIndex, trackSequence, direction, height, &mapElement);
|
||||
if (testpaint_is_ignored(direction, trackSequence)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (referenceGeneralSupportCall.height != -1) {
|
||||
if (gSupport.height != referenceGeneralSupportCall.height) {
|
||||
printf("General support heights didn't match. (expected height + %d, actual: height + %d) [direction:%d trackSequence:%d chainLift:%d]\n",
|
||||
referenceGeneralSupportCall.height - height,
|
||||
gSupport.height - height,
|
||||
direction,
|
||||
trackSequence,
|
||||
chainLift);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (referenceGeneralSupportCall.slope != -1) {
|
||||
if (gSupport.slope != referenceGeneralSupportCall.slope) {
|
||||
printf("General support slopes didn't match. [direction:%d trackSequence:%d chainLift:%d]\n", direction,
|
||||
trackSequence, chainLift);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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_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;
|
||||
|
||||
testpaint_clear_ignore();
|
||||
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] = { 0 };
|
||||
getTunnelCallReferencePattern(tileTunnelCalls, &referencePattern);
|
||||
|
||||
TunnelCall actualPattern[4] = { 0 };
|
||||
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, size_t len, sint16 height)
|
||||
{
|
||||
if (height == 0) {
|
||||
snprintf(out, len, "height");
|
||||
return;
|
||||
}
|
||||
|
||||
if (height > 0) {
|
||||
snprintf(out, len, "height + %d", height);
|
||||
return;
|
||||
}
|
||||
|
||||
if (height < 0) {
|
||||
snprintf(out, len, "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;
|
||||
|
||||
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_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;
|
||||
|
||||
testpaint_clear_ignore();
|
||||
TRACK_PAINT_FUNCTION newPaintFunction = newPaintGetter(trackType, direction);
|
||||
newPaintFunction(rideIndex, trackSequence, direction, height, &mapElement);
|
||||
if (testpaint_is_ignored(direction, trackSequence)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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, 16, (referenceHeight * 16) - 48);
|
||||
printRelativeHeight(strActualTunnelHeight, 16, (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;
|
||||
}
|
||||
|
||||
struct IgnoredEntry
|
||||
{
|
||||
uint8 Direction;
|
||||
uint8 TrackSequence;
|
||||
};
|
||||
|
||||
static bool _ignoredAll;
|
||||
static std::vector<IgnoredEntry> _ignoredEntries;
|
||||
|
||||
static void testClearIgnore()
|
||||
{
|
||||
_ignoredAll = false;
|
||||
_ignoredEntries.clear();
|
||||
}
|
||||
|
||||
static void testIgnore(uint8 direction, uint8 trackSequence)
|
||||
{
|
||||
_ignoredEntries.push_back({ direction, trackSequence });
|
||||
}
|
||||
|
||||
static void testIgnoreAll()
|
||||
{
|
||||
_ignoredAll = true;
|
||||
}
|
||||
|
||||
static bool testIsIgnored(uint8 direction, uint8 trackSequence)
|
||||
{
|
||||
if (_ignoredAll) return true;
|
||||
for (const IgnoredEntry &entry : _ignoredEntries)
|
||||
{
|
||||
if (entry.Direction == direction &&
|
||||
entry.TrackSequence == trackSequence)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void testpaint_clear_ignore()
|
||||
{
|
||||
Intercept2::testClearIgnore();
|
||||
}
|
||||
|
||||
void testpaint_ignore(uint8 direction, uint8 trackSequence)
|
||||
{
|
||||
Intercept2::testIgnore(direction, trackSequence);
|
||||
}
|
||||
|
||||
void testpaint_ignore_all()
|
||||
{
|
||||
Intercept2::testIgnoreAll();
|
||||
}
|
||||
|
||||
bool testpaint_is_ignored(uint8 direction, uint8 trackSequence)
|
||||
{
|
||||
return Intercept2::testIsIgnored(direction, trackSequence);
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,9 @@
|
||||
#include <sys/mman.h>
|
||||
#endif // defined(__unix__)
|
||||
|
||||
#include "intercept.h"
|
||||
#include "PaintIntercept.hpp"
|
||||
#include "TestTrack.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include "data.h"
|
||||
@@ -42,10 +44,12 @@ typedef struct {
|
||||
enum CLIColour {
|
||||
DEFAULT,
|
||||
RED,
|
||||
YELLOW,
|
||||
GREEN,
|
||||
};
|
||||
|
||||
bool gTestColor = true;
|
||||
Verbosity _verbosity = NORMAL;
|
||||
|
||||
static bool CStringEquals(const char *lhs, const char *rhs) {
|
||||
if (lhs == NULL) return rhs == NULL;
|
||||
@@ -96,6 +100,8 @@ static const char* GetAnsiColorCode(CLIColour color) {
|
||||
switch (color) {
|
||||
case RED: return "1";
|
||||
case GREEN: return "2";
|
||||
case YELLOW:
|
||||
return "3";
|
||||
default: return NULL;
|
||||
};
|
||||
}
|
||||
@@ -114,16 +120,16 @@ static WORD GetWindowsConsoleAttribute(CLIColour color, WORD defaultAttr)
|
||||
switch (color) {
|
||||
case RED: return FOREGROUND_RED;
|
||||
case GREEN: return FOREGROUND_GREEN;
|
||||
case YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
|
||||
default: return defaultAttr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void ColouredPrintF(CLIColour colour, const char* fmt, ...)
|
||||
static void Write_VA(Verbosity verbosity, CLIColour colour, const char *fmt, va_list args)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
if (_verbosity < verbosity) return;
|
||||
|
||||
COLOUR_METHOD colourMethod = GetColourMethod();
|
||||
|
||||
@@ -142,6 +148,37 @@ static void ColouredPrintF(CLIColour colour, const char* fmt, ...)
|
||||
SetConsoleTextAttribute(hStdOut, defaultAttr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void Write(Verbosity verbosity, CLIColour colour, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Write_VA(verbosity, colour, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void Write(Verbosity verbosity, const char * fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Write_VA(verbosity, DEFAULT, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void Write(CLIColour colour, const char * fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Write_VA(NORMAL, colour, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
static void Write(const char * fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Write_VA(NORMAL, DEFAULT, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@@ -340,7 +377,7 @@ static void PrintRideTypes()
|
||||
{
|
||||
for (uint8 rideType = 0; rideType < 91; rideType++) {
|
||||
CLIColour colour = CLIColour::DEFAULT;
|
||||
bool implemented = rideIsImplemented(rideType);
|
||||
bool implemented = Utils::rideIsImplemented(rideType);
|
||||
const char * rideName = RideNames[rideType];
|
||||
const char * status = "";
|
||||
if (implemented) {
|
||||
@@ -348,11 +385,48 @@ static void PrintRideTypes()
|
||||
colour = CLIColour::GREEN;
|
||||
}
|
||||
|
||||
ColouredPrintF(colour, "%2d: %-30s%s\n", rideType, rideName, status);
|
||||
Write(colour, "%2d: %-30s%s\n", rideType, rideName, status);
|
||||
}
|
||||
}
|
||||
|
||||
#include "GeneralSupportHeightCall.hpp"
|
||||
|
||||
static void TestGeneralSupportHeightCall() {
|
||||
SupportCall callA = {16, 0x20};
|
||||
SupportCall callB = {32, 0x20};
|
||||
SupportCall callC = {48, 0x20};
|
||||
SupportCall callD = {48, 0x1F};
|
||||
|
||||
SupportCall out = {0,0};
|
||||
bool success;
|
||||
|
||||
SupportCall groupA[4] = {callA, callA, callA, callA};
|
||||
success = GeneralSupportHeightCall::FindMostCommonSupportCall(groupA, &out);
|
||||
assert(success);
|
||||
assert(out == callA);
|
||||
|
||||
SupportCall groupB[4] = {callB, callA, callA, callA};
|
||||
success = GeneralSupportHeightCall::FindMostCommonSupportCall(groupB, &out);
|
||||
assert(success);
|
||||
assert(out == callA);
|
||||
|
||||
SupportCall groupC[4] = {callB, callA, callB, callA};
|
||||
success = GeneralSupportHeightCall::FindMostCommonSupportCall(groupC, &out);
|
||||
assert(!success);
|
||||
|
||||
SupportCall groupD[4] = {callB, callC, callB, callA};
|
||||
success = GeneralSupportHeightCall::FindMostCommonSupportCall(groupD, &out);
|
||||
assert(success);
|
||||
assert(out == callB);
|
||||
|
||||
SupportCall groupE[4] = {callD, callC, callB, callA};
|
||||
success = GeneralSupportHeightCall::FindMostCommonSupportCall(groupE, &out);
|
||||
assert(!success);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
TestGeneralSupportHeightCall();
|
||||
|
||||
std::vector<TestCase> testCases;
|
||||
|
||||
bool generate = false;
|
||||
@@ -362,6 +436,9 @@ int main(int argc, char *argv[]) {
|
||||
if (strcmp(arg, "--gtest_color=no") == 0) {
|
||||
gTestColor = false;
|
||||
}
|
||||
else if (strcmp(arg, "--quiet") == 0) {
|
||||
_verbosity = Verbosity::QUIET;
|
||||
}
|
||||
else if (strcmp(arg, "--ride-type") == 0) {
|
||||
if (i + 1 < argc) {
|
||||
i++;
|
||||
@@ -383,7 +460,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
openrct2_setup_rct2_segment();
|
||||
initHooks();
|
||||
PaintIntercept::InitHooks();
|
||||
|
||||
return generatePaintCode(specificRideType);
|
||||
}
|
||||
@@ -393,7 +470,7 @@ int main(int argc, char *argv[]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rideIsImplemented(rideType)) {
|
||||
if (!Utils::rideIsImplemented(rideType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -404,7 +481,7 @@ int main(int argc, char *argv[]) {
|
||||
testCase.trackTypes.push_back(RideConstructionDefaultTrackType[rideType]);
|
||||
} else {
|
||||
for (int trackType = 0; trackType < 256; trackType++) {
|
||||
if (rideSupportsTrackType(rideType, trackType)) {
|
||||
if (Utils::rideSupportsTrackType(rideType, trackType)) {
|
||||
testCase.trackTypes.push_back(trackType);
|
||||
}
|
||||
}
|
||||
@@ -419,20 +496,20 @@ int main(int argc, char *argv[]) {
|
||||
testCount += tc.trackTypes.size();
|
||||
}
|
||||
|
||||
ColouredPrintF(CLIColour::GREEN, "[==========] ");
|
||||
printf("Running %d tests from %d test cases.\n", testCount, testCaseCount);
|
||||
Write(CLIColour::GREEN, "[==========] ");
|
||||
Write("Running %d tests from %d test cases.\n", testCount, testCaseCount);
|
||||
|
||||
ColouredPrintF(CLIColour::GREEN, "[----------] ");
|
||||
printf("Global test environment set-up.\n");
|
||||
Write(CLIColour::GREEN, "[----------] ");
|
||||
Write("Global test environment set-up.\n");
|
||||
openrct2_setup_rct2_segment();
|
||||
initHooks();
|
||||
PaintIntercept::InitHooks();
|
||||
|
||||
int successCount = 0;
|
||||
std::vector<utf8string> 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);
|
||||
Write(CLIColour::GREEN, "[----------] ");
|
||||
Write("%d tests from %s\n", (int)tc.trackTypes.size(), rideTypeName);
|
||||
|
||||
for (auto &&trackType : tc.trackTypes) {
|
||||
utf8string trackTypeName;
|
||||
@@ -442,50 +519,65 @@ int main(int argc, char *argv[]) {
|
||||
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];
|
||||
snprintf(testCaseName, 64, "%s.%s", rideTypeName, trackTypeName);
|
||||
Write(CLIColour::GREEN, "[ RUN ] ");
|
||||
Write("%s.%s\n", 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++;
|
||||
std::string out;
|
||||
int retVal = TestTrack::TestPaintTrackElement(tc.rideType, trackType, &out);
|
||||
Write("%s", out.c_str());
|
||||
switch (retVal) {
|
||||
case TEST_SUCCESS:
|
||||
Write(CLIColour::GREEN, "[ OK ] ");
|
||||
Write("%s.%s (0 ms)\n", rideTypeName, trackTypeName);
|
||||
successCount++;
|
||||
break;
|
||||
|
||||
case TEST_SKIPPED:
|
||||
Write("Skipped\n");
|
||||
// Outputting this as OK because CLion only allows FAILED or OK
|
||||
Write(CLIColour::YELLOW, "[ OK ] ");
|
||||
Write("%s.%s (0 ms)\n", rideTypeName, trackTypeName);
|
||||
successCount++;
|
||||
break;
|
||||
|
||||
case TEST_FAILED:
|
||||
utf8string testCaseName = new utf8[64];
|
||||
snprintf(testCaseName, 64, "%s.%s", rideTypeName, trackTypeName);
|
||||
|
||||
Write(CLIColour::RED, "[ FAILED ] ");
|
||||
Write("%s (0 ms)\n", testCaseName);
|
||||
failures.push_back(testCaseName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ColouredPrintF(CLIColour::GREEN, "[----------] ");
|
||||
printf("%d tests from %s (0 ms total)\n", (int)tc.trackTypes.size(), rideTypeName);
|
||||
Write(CLIColour::GREEN, "[----------] ");
|
||||
Write("%d tests from %s (0 ms total)\n", (int)tc.trackTypes.size(), rideTypeName);
|
||||
}
|
||||
printf("\n");
|
||||
Write("\n");
|
||||
|
||||
ColouredPrintF(CLIColour::GREEN, "[----------] ");
|
||||
printf("Global test environment tear-down\n");
|
||||
Write(CLIColour::GREEN, "[----------] ");
|
||||
Write("Global test environment tear-down\n");
|
||||
|
||||
ColouredPrintF(CLIColour::GREEN, "[==========] ");
|
||||
printf("%d tests from %d test cases ran. (0 ms total).\n", testCount, testCaseCount);
|
||||
Write(CLIColour::GREEN, "[==========] ");
|
||||
Write("%d tests from %d test cases ran. (0 ms total).\n", testCount, testCaseCount);
|
||||
|
||||
ColouredPrintF(CLIColour::GREEN, "[ PASSED ] ");
|
||||
printf("%d tests.\n", successCount);
|
||||
Write(Verbosity::QUIET, CLIColour::GREEN, "[ PASSED ] ");
|
||||
Write(Verbosity::QUIET, "%d tests.\n", successCount);
|
||||
|
||||
if (failures.size() > 0) {
|
||||
ColouredPrintF(CLIColour::RED, "[ FAILED ] ");
|
||||
printf("%d tests, listed below:\n", (int)failures.size());
|
||||
Write(Verbosity::QUIET, CLIColour::RED, "[ FAILED ] ");
|
||||
Write(Verbosity::QUIET, "%d tests, listed below:\n", (int)failures.size());
|
||||
|
||||
for (auto &&failure : failures) {
|
||||
ColouredPrintF(CLIColour::RED, "[ FAILED ] ");
|
||||
printf("%s\n", failure);
|
||||
Write(Verbosity::QUIET, CLIColour::RED, "[ FAILED ] ");
|
||||
Write(Verbosity::QUIET, "%s\n", failure);
|
||||
delete [] failure;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
Write(Verbosity::QUIET, "\n");
|
||||
|
||||
printf("%d FAILED TESTS\n", (int)failures.size());
|
||||
Write(Verbosity::QUIET, "%d FAILED TESTS\n", (int)failures.size());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -95,10 +95,19 @@
|
||||
<ClCompile Include="..\..\src\paint\paint_helpers.c" />
|
||||
<ClCompile Include="compat.c" />
|
||||
<ClCompile Include="data.c" />
|
||||
<ClCompile Include="FunctionCall.cpp" />
|
||||
<ClCompile Include="GeneralSupportHeightCall.cpp" />
|
||||
<ClCompile Include="generate.cpp" />
|
||||
<ClCompile Include="intercept.c" />
|
||||
<ClCompile Include="intercept_2.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="PaintIntercept.cpp" />
|
||||
<ClCompile Include="Printer.cpp" />
|
||||
<ClCompile Include="SegmentSupportHeightCall.cpp" />
|
||||
<ClCompile Include="SideTunnelCall.cpp" />
|
||||
<ClCompile Include="String.cpp" />
|
||||
<ClCompile Include="TestPaint.cpp" />
|
||||
<ClCompile Include="TestTrack.cpp" />
|
||||
<ClCompile Include="Utils.cpp" />
|
||||
<ClCompile Include="VerticalTunnelCall.cpp" />
|
||||
<ClCompile Include="..\..\src\addresses.c" />
|
||||
<ClCompile Include="..\..\src\diagnostic.c" />
|
||||
<ClCompile Include="..\..\src\hook.c" />
|
||||
|
||||
Reference in New Issue
Block a user