summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorinspectredc <inspectredc@gmail.com>2025-01-06 13:29:49 +0000
committerLywx <kiritodev01@gmail.com>2025-01-06 09:03:36 -0600
commitef48a4bf5c8731c1cb5120e2deb64eaa05551ad4 (patch)
tree13a9948aa907b96be944e6cef5af021096d7fc01 /src
parent4459958deed7af3c9ed7343914789709d6ef6ef1 (diff)
F-Zero Course Track Segment Info Docs
Diffstat (limited to 'src')
-rw-r--r--src/factories/fzerox/CourseFactory.cpp179
-rw-r--r--src/factories/fzerox/course/Course.h222
2 files changed, 392 insertions, 9 deletions
diff --git a/src/factories/fzerox/CourseFactory.cpp b/src/factories/fzerox/CourseFactory.cpp
index 071cdaa..786bb8f 100644
--- a/src/factories/fzerox/CourseFactory.cpp
+++ b/src/factories/fzerox/CourseFactory.cpp
@@ -10,10 +10,6 @@
#define ARRAY_COUNT(arr) (int32_t)(sizeof(arr) / sizeof(arr[0]))
-#define TRACK_SEGMENT_JOINT_MASK 0x600
-#define TRACK_SEGMENT_FORM_MASK 0x38000
-#define TRACK_SEGMENT_FLAG_CONTINUE 0x40000000
-
#define FORMAT_HEX(x, w) std::hex << std::setfill('0') << std::setw(w) << x
#define FORMAT_FLOAT(x, w, p) std::dec << std::setfill(' ') << std::fixed << std::setprecision(p) << std::setw(w) << x
@@ -23,9 +19,9 @@ uint32_t FZX::CourseData::CalculateChecksum(void) {
for (const auto& controlPointInfo : mControlPointInfos) {
int32_t trackSegmentInfo = controlPointInfo.controlPoint.trackSegmentInfo;
- trackSegmentInfo &= ~TRACK_SEGMENT_JOINT_MASK;
- trackSegmentInfo &= ~TRACK_SEGMENT_FORM_MASK;
- trackSegmentInfo &= ~TRACK_SEGMENT_FLAG_CONTINUE;
+ trackSegmentInfo &= ~TRACK_JOIN_MASK;
+ trackSegmentInfo &= ~TRACK_FORM_MASK;
+ trackSegmentInfo &= ~TRACK_FLAG_CONTINUOUS;
checksum += (int32_t) ((controlPointInfo.controlPoint.pos.x + ((1.1f + (0.7f * counter)) * controlPointInfo.controlPoint.pos.y)) +
((2.2f + (1.2f * counter)) * controlPointInfo.controlPoint.pos.z * (4.4f + (0.9f * counter))) +
@@ -99,8 +95,173 @@ ExportResult FZX::CourseCodeExporter::Export(std::ostream &write, std::shared_pt
Vec3f pos(controlPointInfo.controlPoint.pos.x, controlPointInfo.controlPoint.pos.y, controlPointInfo.controlPoint.pos.z);
write << "{ { " << FORMAT_FLOAT(pos, 6, 4) << "}, ";
write << controlPointInfo.controlPoint.radiusLeft << ", ";
- write << controlPointInfo.controlPoint.radiusRight << ", ";
- write << "0x" << std::hex << controlPointInfo.controlPoint.trackSegmentInfo << std::dec;
+ write << controlPointInfo.controlPoint.radiusRight << ",\n";
+ write << fourSpaceTab << fourSpaceTab << " ";
+ int32_t trackSegmentInfo = controlPointInfo.controlPoint.trackSegmentInfo;
+ bool hasFlags = false;
+ if (trackSegmentInfo & TRACK_FLAG_20000000) {
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_FLAG_20000000";
+ hasFlags = true;
+ trackSegmentInfo &= ~TRACK_FLAG_20000000;
+ }
+
+ if (trackSegmentInfo & TRACK_FLAG_JOINABLE) {
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_FLAG_JOINABLE";
+ hasFlags = true;
+ trackSegmentInfo &= ~TRACK_FLAG_JOINABLE;
+ }
+
+ if (trackSegmentInfo & TRACK_FLAG_8000000) {
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_FLAG_8000000";
+ hasFlags = true;
+ trackSegmentInfo &= ~TRACK_FLAG_8000000;
+ }
+
+ switch (trackSegmentInfo & TRACK_FORM_MASK) {
+ case TRACK_FORM_STRAIGHT:
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_FORM_STRAIGHT";
+ break;
+ case TRACK_FORM_LEFT:
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_FORM_LEFT";
+ break;
+ case TRACK_FORM_RIGHT:
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_FORM_RIGHT";
+ break;
+ case TRACK_FORM_S:
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_FORM_S";
+ break;
+ case TRACK_FORM_S_FLIPPED:
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_FORM_S_FLIPPED";
+ break;
+ }
+ trackSegmentInfo &= ~TRACK_FORM_MASK;
+
+ switch (trackSegmentInfo & TRACK_SHAPE_MASK) {
+ case TRACK_SHAPE_ROAD:
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_SHAPE_ROAD";
+ trackSegmentInfo &= ~TRACK_SHAPE_MASK;
+ if ((trackSegmentInfo & TRACK_TYPE_MASK) == TRACK_TYPE_NONE) {
+ write << " | TRACK_TYPE_NONE";
+ } else {
+ write << " | " << static_cast<Road>(trackSegmentInfo & TRACK_TYPE_MASK);
+ }
+ break;
+ case TRACK_SHAPE_WALLED_ROAD:
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_SHAPE_WALLED_ROAD";
+ trackSegmentInfo &= ~TRACK_SHAPE_MASK;
+ if ((trackSegmentInfo & TRACK_TYPE_MASK) == TRACK_TYPE_NONE) {
+ write << " | TRACK_TYPE_NONE";
+ } else {
+ write << " | " << static_cast<WalledRoad>(trackSegmentInfo & TRACK_TYPE_MASK);
+ }
+ break;
+ case TRACK_SHAPE_PIPE:
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_SHAPE_PIPE";
+ trackSegmentInfo &= ~TRACK_SHAPE_MASK;
+ if ((trackSegmentInfo & TRACK_TYPE_MASK) == TRACK_TYPE_NONE) {
+ write << " | TRACK_TYPE_NONE";
+ } else {
+ write << " | " << static_cast<Pipe>(trackSegmentInfo & TRACK_TYPE_MASK);
+ }
+ break;
+ case TRACK_SHAPE_CYLINDER:
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_SHAPE_CYLINDER";
+ trackSegmentInfo &= ~TRACK_SHAPE_MASK;
+ if ((trackSegmentInfo & TRACK_TYPE_MASK) == TRACK_TYPE_NONE) {
+ write << " | TRACK_TYPE_NONE";
+ } else {
+ write << " | " << static_cast<Cylinder>(trackSegmentInfo & TRACK_TYPE_MASK);
+ }
+ break;
+ case TRACK_SHAPE_HALF_PIPE:
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_SHAPE_HALF_PIPE";
+ trackSegmentInfo &= ~TRACK_SHAPE_MASK;
+ if ((trackSegmentInfo & TRACK_TYPE_MASK) == TRACK_TYPE_NONE) {
+ write << " | TRACK_TYPE_NONE";
+ } else {
+ write << " | " << static_cast<HalfPipe>(trackSegmentInfo & TRACK_TYPE_MASK);
+ }
+ break;
+ case TRACK_SHAPE_TUNNEL:
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_SHAPE_TUNNEL";
+ trackSegmentInfo &= ~TRACK_SHAPE_MASK;
+ if ((trackSegmentInfo & TRACK_TYPE_MASK) == TRACK_TYPE_NONE) {
+ write << " | TRACK_TYPE_NONE";
+ } else {
+ write << " | " << static_cast<Tunnel>(trackSegmentInfo & TRACK_TYPE_MASK);
+ }
+ break;
+ case TRACK_SHAPE_AIR:
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_SHAPE_AIR";
+ trackSegmentInfo &= ~TRACK_SHAPE_MASK;
+ if ((trackSegmentInfo & TRACK_TYPE_MASK) == TRACK_TYPE_NONE) {
+ write << " | TRACK_TYPE_NONE";
+ }
+ break;
+ case TRACK_SHAPE_BORDERLESS_ROAD:
+ if (hasFlags) {
+ write << " | ";
+ }
+ write << "TRACK_SHAPE_BORDERLESS_ROAD";
+ trackSegmentInfo &= ~TRACK_SHAPE_MASK;
+ if ((trackSegmentInfo & TRACK_TYPE_MASK) == TRACK_TYPE_NONE) {
+ write << " | TRACK_TYPE_NONE";
+ } else {
+ write << " | " << static_cast<BorderlessRoad>(trackSegmentInfo & TRACK_TYPE_MASK);
+ }
+ break;
+ }
+ trackSegmentInfo &= ~TRACK_TYPE_MASK;
+
+ if (trackSegmentInfo != 0) {
+ SPDLOG_WARN("Invalid Track Segment Information Found: 0x{:X}", trackSegmentInfo);
+ }
+
write << " },\n";
} else {
diff --git a/src/factories/fzerox/course/Course.h b/src/factories/fzerox/course/Course.h
index 4c393c7..03f6afb 100644
--- a/src/factories/fzerox/course/Course.h
+++ b/src/factories/fzerox/course/Course.h
@@ -6,6 +6,37 @@
#define CREATOR_NINTENDO 4
+#define TRACK_TYPE_NONE 0x3F
+#define TRACK_TYPE_MASK 0x3F
+
+#define TRACK_SHAPE_ROAD 0x0
+#define TRACK_SHAPE_WALLED_ROAD 0x40
+#define TRACK_SHAPE_PIPE 0x80
+#define TRACK_SHAPE_CYLINDER 0xC0
+#define TRACK_SHAPE_HALF_PIPE 0x100
+#define TRACK_SHAPE_TUNNEL 0x140
+#define TRACK_SHAPE_AIR 0x180
+#define TRACK_SHAPE_BORDERLESS_ROAD 0x1C0
+
+#define TRACK_SHAPE_MASK 0x1C0
+
+#define TRACK_JOIN_PREVIOUS 0x200
+#define TRACK_JOIN_NEXT 0x400
+#define TRACK_JOIN_MASK 0x600
+
+#define TRACK_FORM_STRAIGHT 0x00008000
+#define TRACK_FORM_LEFT 0x00010000
+#define TRACK_FORM_RIGHT 0x00018000
+#define TRACK_FORM_S 0x00020000
+#define TRACK_FORM_S_FLIPPED 0x00028000
+
+#define TRACK_FORM_MASK 0x00038000
+
+#define TRACK_FLAG_8000000 0x8000000
+#define TRACK_FLAG_JOINABLE 0x10000000
+#define TRACK_FLAG_20000000 0x20000000
+#define TRACK_FLAG_CONTINUOUS 0x40000000
+
namespace FZX {
enum class Venue {
/* 0 */ VENUE_MUTE_CITY,
@@ -111,6 +142,57 @@ enum class Sign {
/* 4 */ SIGN_OVERHEAD,
};
+enum class Road {
+ /* 0 */ ROAD_START_LINE,
+ /* 1 */ ROAD_1,
+ /* 2 */ ROAD_2,
+ /* 3 */ ROAD_3,
+ /* 4 */ ROAD_4,
+ /* 5 */ ROAD_5,
+ /* 6 */ ROAD_6,
+ /* 7 */ ROAD_7,
+};
+
+enum class WalledRoad {
+ /* 0 */ WALLED_ROAD_0,
+ /* 1 */ WALLED_ROAD_1,
+ /* 2 */ WALLED_ROAD_2,
+};
+
+enum class Pipe {
+ /* 0 */ PIPE_0,
+ /* 1 */ PIPE_1,
+ /* 2 */ PIPE_2,
+ /* 3 */ PIPE_3,
+};
+
+enum class Cylinder {
+ /* 0 */ CYLINDER_0,
+ /* 1 */ CYLINDER_1,
+ /* 2 */ CYLINDER_2,
+ /* 3 */ CYLINDER_3,
+};
+
+enum class HalfPipe {
+ /* 0 */ HALF_PIPE_0,
+ /* 1 */ HALF_PIPE_1,
+ /* 2 */ HALF_PIPE_2,
+ /* 3 */ HALF_PIPE_3,
+};
+
+enum class Tunnel {
+ /* 0 */ TUNNEL_0,
+ /* 1 */ TUNNEL_1,
+ /* 2 */ TUNNEL_2,
+ /* 3 */ TUNNEL_3,
+};
+
+enum class BorderlessRoad {
+ /* 0 */ BORDERLESS_ROAD_0,
+ /* 1 */ BORDERLESS_ROAD_1,
+ /* 2 */ BORDERLESS_ROAD_2,
+};
+
inline std::ostream& operator<<(std::ostream& out, const Venue& venue) {
std::string output;
switch (venue) {
@@ -400,4 +482,144 @@ inline std::ostream& operator<<(std::ostream& out, const Sign& sign) {
}
return out << output;
}
+
+inline std::ostream& operator<<(std::ostream& out, const Road& road) {
+ std::string output;
+ switch (road) {
+ case Road::ROAD_START_LINE:
+ output = "ROAD_START_LINE";
+ break;
+ case Road::ROAD_1:
+ output = "ROAD_1";
+ break;
+ case Road::ROAD_2:
+ output = "ROAD_2";
+ break;
+ case Road::ROAD_3:
+ output = "ROAD_3";
+ break;
+ case Road::ROAD_4:
+ output = "ROAD_4";
+ break;
+ case Road::ROAD_5:
+ output = "ROAD_5";
+ break;
+ case Road::ROAD_6:
+ output = "ROAD_6";
+ break;
+ case Road::ROAD_7:
+ output = "ROAD_7";
+ break;
+ }
+ return out << output;
+}
+
+inline std::ostream& operator<<(std::ostream& out, const WalledRoad& walledRoad) {
+ std::string output;
+ switch (walledRoad) {
+ case WalledRoad::WALLED_ROAD_0:
+ output = "WALLED_ROAD_0";
+ break;
+ case WalledRoad::WALLED_ROAD_1:
+ output = "WALLED_ROAD_1";
+ break;
+ case WalledRoad::WALLED_ROAD_2:
+ output = "WALLED_ROAD_2";
+ break;
+ }
+ return out << output;
+}
+
+inline std::ostream& operator<<(std::ostream& out, const Pipe& pipe) {
+ std::string output;
+ switch (pipe) {
+ case Pipe::PIPE_0:
+ output = "PIPE_0";
+ break;
+ case Pipe::PIPE_1:
+ output = "PIPE_1";
+ break;
+ case Pipe::PIPE_2:
+ output = "PIPE_2";
+ break;
+ case Pipe::PIPE_3:
+ output = "PIPE_3";
+ break;
+ }
+ return out << output;
+}
+
+inline std::ostream& operator<<(std::ostream& out, const Cylinder& cylinder) {
+ std::string output;
+ switch (cylinder) {
+ case Cylinder::CYLINDER_0:
+ output = "CYLINDER_0";
+ break;
+ case Cylinder::CYLINDER_1:
+ output = "CYLINDER_1";
+ break;
+ case Cylinder::CYLINDER_2:
+ output = "CYLINDER_2";
+ break;
+ case Cylinder::CYLINDER_3:
+ output = "CYLINDER_3";
+ break;
+ }
+ return out << output;
+}
+
+inline std::ostream& operator<<(std::ostream& out, const HalfPipe& halfPipe) {
+ std::string output;
+ switch (halfPipe) {
+ case HalfPipe::HALF_PIPE_0:
+ output = "HALF_PIPE_0";
+ break;
+ case HalfPipe::HALF_PIPE_1:
+ output = "HALF_PIPE_1";
+ break;
+ case HalfPipe::HALF_PIPE_2:
+ output = "HALF_PIPE_2";
+ break;
+ case HalfPipe::HALF_PIPE_3:
+ output = "HALF_PIPE_3";
+ break;
+ }
+ return out << output;
+}
+
+inline std::ostream& operator<<(std::ostream& out, const Tunnel& tunnel) {
+ std::string output;
+ switch (tunnel) {
+ case Tunnel::TUNNEL_0:
+ output = "TUNNEL_0";
+ break;
+ case Tunnel::TUNNEL_1:
+ output = "TUNNEL_1";
+ break;
+ case Tunnel::TUNNEL_2:
+ output = "TUNNEL_2";
+ break;
+ case Tunnel::TUNNEL_3:
+ output = "TUNNEL_3";
+ break;
+ }
+ return out << output;
+}
+
+inline std::ostream& operator<<(std::ostream& out, const BorderlessRoad& borderlessRoad) {
+ std::string output;
+ switch (borderlessRoad) {
+ case BorderlessRoad::BORDERLESS_ROAD_0:
+ output = "BORDERLESS_ROAD_0";
+ break;
+ case BorderlessRoad::BORDERLESS_ROAD_1:
+ output = "BORDERLESS_ROAD_1";
+ break;
+ case BorderlessRoad::BORDERLESS_ROAD_2:
+ output = "BORDERLESS_ROAD_2";
+ break;
+ }
+ return out << output;
+}
+
}