mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-06 06:32:56 +01:00
Extract Side tunnels
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
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 */; };
|
||||
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 */; };
|
||||
@@ -526,6 +527,8 @@
|
||||
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>"; };
|
||||
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; };
|
||||
@@ -1208,6 +1211,8 @@
|
||||
C606CCB71DB4054000FE4015 /* Printer.hpp */,
|
||||
C606CCCC1DB427A000FE4015 /* SegmentSupportHeightCall.cpp */,
|
||||
C606CCCD1DB427A000FE4015 /* SegmentSupportHeightCall.hpp */,
|
||||
C606CCD01DB4D7C800FE4015 /* SideTunnelCall.cpp */,
|
||||
C606CCD11DB4D7C800FE4015 /* SideTunnelCall.hpp */,
|
||||
C606CCB81DB4054000FE4015 /* String.cpp */,
|
||||
C606CCB91DB4054000FE4015 /* String.hpp */,
|
||||
C606CCBA1DB4054000FE4015 /* TestTrack.cpp */,
|
||||
@@ -2399,6 +2404,7 @@
|
||||
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 */,
|
||||
C64FDA651D6D9A2100F259B9 /* bobsleigh_coaster.c in Sources */,
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace Printer {
|
||||
|
||||
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;
|
||||
|
||||
@@ -140,6 +142,73 @@ namespace Printer {
|
||||
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) {
|
||||
printf(" + + ");
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "intercept.h"
|
||||
#include "SideTunnelCall.hpp"
|
||||
#include "SegmentSupportHeightCall.hpp"
|
||||
|
||||
namespace Printer {
|
||||
@@ -27,4 +28,6 @@ namespace Printer {
|
||||
std::string PrintFunctionCalls(std::vector <function_call> calls, uint16 baseHeight);
|
||||
|
||||
std::string PrintSegmentSupportHeightCalls(std::vector<SegmentSupportCall> calls);
|
||||
|
||||
std::string PrintSideTunnelCalls(TunnelCall tunnelCalls[4][4]);
|
||||
}
|
||||
|
||||
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]);
|
||||
};
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "GeneralSupportHeightCall.hpp"
|
||||
#include "Printer.hpp"
|
||||
#include "SegmentSupportHeightCall.hpp"
|
||||
#include "SideTunnelCall.hpp"
|
||||
#include "String.hpp"
|
||||
#include "TestTrack.hpp"
|
||||
#include "Utils.hpp"
|
||||
@@ -78,6 +79,8 @@ static uint8 TestTrackElementSegmentSupportHeight(uint8 rideType, uint8 trackTyp
|
||||
|
||||
static uint8 TestTrackElementGeneralSupportHeight(uint8 rideType, uint8 trackType, uint8 trackSequence, std::string *error);
|
||||
|
||||
static uint8 TestTrackElementSideTunnels(uint8 rideType, uint8 trackType, uint8 trackSequence, std::string *error);
|
||||
|
||||
uint8 TestTrack::TestPaintTrackElement(uint8 rideType, uint8 trackType) {
|
||||
if (!Utils::rideSupportsTrackType(rideType, trackType)) {
|
||||
return TEST_FAILED;
|
||||
@@ -99,7 +102,8 @@ uint8 TestTrack::TestPaintTrackElement(uint8 rideType, uint8 trackType) {
|
||||
static TestFunction functions[] = {
|
||||
TestTrackElementPaintCalls,
|
||||
TestTrackElementSegmentSupportHeight,
|
||||
TestTrackElementGeneralSupportHeight
|
||||
TestTrackElementGeneralSupportHeight,
|
||||
TestTrackElementSideTunnels,
|
||||
};
|
||||
|
||||
for (int trackSequence = 0; trackSequence < sequenceCount; trackSequence++) {
|
||||
@@ -380,3 +384,117 @@ static uint8 TestTrackElementGeneralSupportHeight(uint8 rideType, uint8 trackTyp
|
||||
|
||||
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;
|
||||
|
||||
Intercept2::ResetEnvironment();
|
||||
Intercept2::ResetTunnels();
|
||||
|
||||
TunnelCall tileTunnelCalls[4][4];
|
||||
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
Intercept2::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++) {
|
||||
Intercept2::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;
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "intercept.h"
|
||||
#include "SegmentSupportHeightCall.hpp"
|
||||
#include "SideTunnelCall.hpp"
|
||||
#include "String.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
@@ -400,7 +401,7 @@ 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<SegmentSupportCall> segmentSupportCalls[4];
|
||||
support_height generalSupports[4] = { 0 };
|
||||
@@ -737,7 +738,7 @@ private:
|
||||
int trackSequence,
|
||||
int height,
|
||||
rct_map_element * mapElement,
|
||||
Intercept2::TunnelCall tileTunnelCalls[4][4],
|
||||
TunnelCall tileTunnelCalls[4][4],
|
||||
sint16 verticalTunnelHeights[4])
|
||||
{
|
||||
intercept_reset_tunnels();
|
||||
@@ -751,13 +752,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");
|
||||
@@ -765,10 +766,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");
|
||||
@@ -788,7 +789,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;
|
||||
@@ -809,7 +810,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;
|
||||
@@ -857,7 +858,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]);
|
||||
}
|
||||
|
||||
@@ -107,19 +107,7 @@ namespace Intercept2
|
||||
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;
|
||||
|
||||
enum {
|
||||
TUNNELCALL_SKIPPED,
|
||||
TUNNELCALL_NONE,
|
||||
TUNNELCALL_CALL,
|
||||
};
|
||||
|
||||
struct TunnelCall {
|
||||
uint8 call;
|
||||
sint16 offset;
|
||||
uint8 type;
|
||||
};
|
||||
|
||||
sint16 getTunnelOffset(uint32 baseHeight, tunnel_entry calls[3]);
|
||||
|
||||
void ResetEnvironment();
|
||||
void ResetTunnels();
|
||||
|
||||
@@ -86,295 +86,6 @@ namespace Intercept2
|
||||
gSupport.slope = 0xFF;
|
||||
}
|
||||
|
||||
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 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;
|
||||
|
||||
ResetEnvironment();
|
||||
|
||||
int height = 48;
|
||||
|
||||
TRACK_PAINT_FUNCTION_GETTER newPaintGetter = RideTypeTrackPaintFunctions[rideType];
|
||||
int sequenceCount = Utils::getTrackSequenceCount(rideType, trackType);
|
||||
|
||||
|
||||
for (int trackSequence = 0; trackSequence < sequenceCount; trackSequence++) {
|
||||
TunnelCall tileTunnelCalls[4][4];
|
||||
|
||||
for (int direction = 0; direction < 4; direction++) {
|
||||
ResetTunnels();
|
||||
|
||||
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) {
|
||||
@@ -539,11 +250,6 @@ namespace Intercept2
|
||||
|
||||
extern "C"
|
||||
{
|
||||
bool testTunnels(uint8 rideType, uint8 trackType)
|
||||
{
|
||||
return Intercept2::testTunnels(rideType, trackType);
|
||||
}
|
||||
|
||||
bool testVerticalTunnels(uint8 rideType, uint8 trackType)
|
||||
{
|
||||
return Intercept2::testVerticalTunnels(rideType, trackType);
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
<ClCompile Include="PaintIntercept.cpp" />
|
||||
<ClCompile Include="Printer.cpp" />
|
||||
<ClCompile Include="SegmentSupportHeightCall.cpp" />
|
||||
<ClCompile Include="SideTunnelCall.cpp" />
|
||||
<ClCompile Include="String.cpp" />
|
||||
<ClCompile Include="TestTrack.cpp" />
|
||||
<ClCompile Include="Utils.cpp" />
|
||||
|
||||
Reference in New Issue
Block a user