summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorinspectredc <inspectredc@gmail.com>2024-04-02 14:55:56 +0100
committerLywx <kiritodev01@gmail.com>2024-04-02 08:12:06 -0600
commit513251ec9bb56aa26b86e9287034bef5087ae90b (patch)
treeea4c2322ad501637dad760278e358d214a3f46b6
parentc567193d17d7fb9b706d5ca2d000520def55f3f8 (diff)
sm64 collision factory
-rw-r--r--src/Companion.cpp2
-rw-r--r--src/factories/sm64/CollisionFactory.cpp470
-rw-r--r--src/factories/sm64/CollisionFactory.h82
-rw-r--r--src/factories/sm64/collision/SpecialPresetNames.h385
-rw-r--r--src/factories/sm64/collision/SurfaceTerrains.h672
5 files changed, 1611 insertions, 0 deletions
diff --git a/src/Companion.cpp b/src/Companion.cpp
index e632f01..172ad81 100644
--- a/src/Companion.cpp
+++ b/src/Companion.cpp
@@ -29,6 +29,7 @@
#include "factories/Vec3sFactory.h"
#include "factories/sm64/AnimationFactory.h"
+#include "factories/sm64/CollisionFactory.h"
#include "factories/sm64/DialogFactory.h"
#include "factories/sm64/DictionaryFactory.h"
#include "factories/sm64/TextFactory.h"
@@ -86,6 +87,7 @@ void Companion::Init(const ExportType type) {
this->RegisterFactory("SM64:TEXT", std::make_shared<SM64::TextFactory>());
this->RegisterFactory("SM64:DICTIONARY", std::make_shared<SM64::DictionaryFactory>());
this->RegisterFactory("SM64:ANIM", std::make_shared<SM64::AnimationFactory>());
+ this->RegisterFactory("SM64:COLLISION", std::make_shared<SM64::CollisionFactory>());
this->RegisterFactory("SM64:GEO_LAYOUT", std::make_shared<SM64::GeoLayoutFactory>());
// MK64 specific
diff --git a/src/factories/sm64/CollisionFactory.cpp b/src/factories/sm64/CollisionFactory.cpp
new file mode 100644
index 0000000..826a218
--- /dev/null
+++ b/src/factories/sm64/CollisionFactory.cpp
@@ -0,0 +1,470 @@
+#include "CollisionFactory.h"
+#include "Companion.h"
+#include "spdlog/spdlog.h"
+
+#define FORMAT_HEX(x) std::hex << x << std::dec
+
+std::unordered_map<int16_t, SpecialPresetTypes> specialPresetMap = {
+ { 0x00, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x01, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x02, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x03, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x04, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x05, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x06, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x07, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x08, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x09, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x0A, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x0B, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x0C, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x0D, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x0E, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x0F, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x10, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x11, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x12, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x13, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x14, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x15, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x16, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x17, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x18, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x19, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x1A, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x1B, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x1C, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x1D, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x1E, SpecialPresetTypes::SPTYPE_UNKNOWN },
+ { 0x1F, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x20, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x21, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x22, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x23, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x24, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x25, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x26, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x27, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x28, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x65, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x66, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x67, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x68, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x69, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x6A, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x6B, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x6C, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x6D, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x6E, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x6F, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x70, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x71, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x72, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x73, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x74, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x75, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x76, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x77, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x78, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x79, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x7A, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x7B, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x7C, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x7D, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+ { 0x89, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x7E, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x7F, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x80, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x81, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x82, SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS },
+ { 0x8A, SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT },
+ { 0x8B, SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT },
+ { 0x8C, SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT },
+ { 0x8D, SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT },
+ { 0x88, SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT },
+ { 0x83, SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT },
+ { 0x84, SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT },
+ { 0x85, SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT },
+ { 0x86, SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT },
+ { 0x87, SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT },
+ { 0xFF, SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS },
+};
+
+ExportResult SM64::CollisionCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ auto symbol = GetSafeNode(node, "symbol", entryName);
+ auto offset = GetSafeNode<uint32_t>(node, "offset");
+ const auto collision = std::static_pointer_cast<Collision>(data).get();
+ uint32_t count = 0;
+
+ write << "Collision " << symbol << "[] = {\n";
+
+ write << fourSpaceTab;
+
+ write << "COL_INIT(),\n";
+ ++count;
+
+ // Vertices
+ if (collision->mVertices.size() > 0) {
+ write << fourSpaceTab;
+ write << "COL_VERTEX_INIT(" << FORMAT_HEX(collision->mVertices.size()) << "),\n";
+ ++count;
+ }
+ for (auto &vertex : collision->mVertices) {
+ write << fourSpaceTab;
+ write << "COL_VERTEX(";
+ write << vertex.x << ", ";
+ write << vertex.y << ", ";
+ write << vertex.z << "),\n";
+ count += 3;
+ }
+
+ // Surfaces
+ for (auto &surface : collision->mSurfaces) {
+ // size check is probably not necessary here
+ if (surface.tris.size() > 0) {
+ write << fourSpaceTab;
+ write << "COL_TRI_INIT(";
+ write << surface.surfaceType << ", ";
+ write << surface.tris.size() << "),\n";
+ count += 2;
+ }
+ bool hasForce = false;
+ switch (surface.surfaceType) {
+ case SurfaceType::SURFACE_0004:
+ case SurfaceType::SURFACE_FLOWING_WATER:
+ case SurfaceType::SURFACE_DEEP_MOVING_QUICKSAND:
+ case SurfaceType::SURFACE_SHALLOW_MOVING_QUICKSAND:
+ case SurfaceType::SURFACE_MOVING_QUICKSAND:
+ case SurfaceType::SURFACE_HORIZONTAL_WIND:
+ case SurfaceType::SURFACE_INSTANT_MOVING_QUICKSAND:
+ hasForce = true;
+ break;
+ default:
+ break;
+ }
+ for (auto &tri : surface.tris) {
+ write << fourSpaceTab;
+ if (hasForce) {
+ write << "COL_TRI_SPECIAL(";
+ } else {
+ write << "COL_TRI(";
+ }
+
+ write << tri.x << ", ";
+ write << tri.y << ", ";
+ if (hasForce) {
+ write << tri.z << ", ";
+ write << tri.force << "),\n";
+ count += 4;
+ } else {
+ write << tri.z << "),\n";
+ count += 3;
+ }
+ }
+ }
+ if (collision->mSurfaces.size()) {
+ write << fourSpaceTab;
+ write << "COL_TRI_STOP()";
+ ++count;
+ }
+
+ // Special Objects
+ if (collision->mSpecialObjects.size() > 0) {
+ write << fourSpaceTab;
+ write << "COL_SPECIAL_INIT(" << collision->mSpecialObjects.size() << "),\n";
+ count += 2;
+ }
+ for (auto &specialObject : collision->mSpecialObjects) {
+ write << fourSpaceTab;
+ if (specialPresetMap.find((int16_t)specialObject.presetId) == specialPresetMap.end()) {
+ throw std::runtime_error("Special Preset Id has no associated Type");
+ }
+ SpecialPresetTypes type = specialPresetMap.at((int16_t)specialObject.presetId);
+ switch (type) {
+ case SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS:
+ case SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT:
+ write << "SPECIAL_OBJECT_WITH_YAW(";
+ break;
+ case SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT:
+ write << "SPECIAL_OBJECT_WITH_YAW_AND_PARAM(";
+ break;
+ case SpecialPresetTypes::SPTYPE_UNKNOWN:
+ break;
+ default:
+ write << "SPECIAL_OBJECT(";
+ break;
+ }
+ write << specialObject.presetId << ", ";
+ write << specialObject.x << ", ";
+ write << specialObject.y << ", ";
+ write << specialObject.z;
+ count += 4;
+
+ for (int16_t extraParam : specialObject.extraParams) {
+ write << ", ";
+ write << extraParam;
+ ++count;
+ }
+
+ if (type != SpecialPresetTypes::SPTYPE_UNKNOWN) {
+ write << ")";
+ }
+ write << ",\n";
+ }
+
+ // Environment Region Boxes
+ if (collision->mEnvRegionBoxes.size() > 0) {
+ write << fourSpaceTab;
+ write << "COL_WATER_BOX_INIT(" << collision->mEnvRegionBoxes.size() << "),\n";
+ count += 2;
+ }
+ for (auto &envRegionBox : collision->mEnvRegionBoxes) {
+ write << fourSpaceTab;
+ write << envRegionBox.id << ", ";
+ write << envRegionBox.x1 << ", ";
+ write << envRegionBox.z1 << ", ";
+ write << envRegionBox.x2 << ", ";
+ write << envRegionBox.z2 << ", ";
+ write << envRegionBox.height << "),\n";
+ count += 6;
+ }
+
+ if (Companion::Instance->IsDebug()) {
+ write << "// size: 0x" << std::hex << std::uppercase << "" << "\n";
+ }
+
+ return offset + count * sizeof(int16_t);
+}
+
+ExportResult SM64::CollisionHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ const auto symbol = GetSafeNode(node, "symbol", entryName);
+
+ if(Companion::Instance->IsOTRMode()){
+ write << "static const char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n";
+ return std::nullopt;
+ }
+
+ write << "extern " << "Collision " << symbol << "[];\n";
+ return std::nullopt;
+}
+
+ExportResult SM64::CollisionBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node &node, std::string* replacement ) {
+ const auto collision = std::static_pointer_cast<Collision>(data).get();
+
+ auto writer = LUS::BinaryWriter();
+ writer.SetEndianness(LUS::Endianness::Big);
+
+ writer.Write((int16_t)COL_INIT());
+
+ // Vertices
+ if (collision->mVertices.size() > 0) {
+ writer.Write((int16_t)COL_VERTEX_INIT(collision->mVertices.size()));
+ }
+ for (auto &vertex : collision->mVertices) {
+ writer.Write(vertex.x);
+ writer.Write(vertex.y);
+ writer.Write(vertex.z);
+ }
+
+ // Surfaces
+ for (auto &surface : collision->mSurfaces) {
+ // size check is probably not necessary here
+ if (surface.tris.size() > 0) {
+ writer.Write((int16_t)surface.surfaceType);
+ writer.Write((int16_t)surface.tris.size());
+ }
+ bool hasForce = false;
+ switch (surface.surfaceType) {
+ case SurfaceType::SURFACE_0004:
+ case SurfaceType::SURFACE_FLOWING_WATER:
+ case SurfaceType::SURFACE_DEEP_MOVING_QUICKSAND:
+ case SurfaceType::SURFACE_SHALLOW_MOVING_QUICKSAND:
+ case SurfaceType::SURFACE_MOVING_QUICKSAND:
+ case SurfaceType::SURFACE_HORIZONTAL_WIND:
+ case SurfaceType::SURFACE_INSTANT_MOVING_QUICKSAND:
+ hasForce = true;
+ break;
+ default:
+ break;
+ }
+ for (auto &tri : surface.tris) {
+ writer.Write(tri.x);
+ writer.Write(tri.y);
+ writer.Write(tri.z);
+ if (hasForce) {
+ writer.Write(tri.force);
+ }
+ }
+ }
+ if (collision->mSurfaces.size()) {
+ writer.Write((int16_t)COL_TRI_STOP());
+ }
+
+ // Special Objects
+ if (collision->mSpecialObjects.size() > 0) {
+ writer.Write((int16_t)TERRAIN_LOAD_OBJECTS);
+ writer.Write((int16_t)collision->mSpecialObjects.size());
+ }
+ for (auto &specialObject : collision->mSpecialObjects) {
+ writer.Write((int16_t)specialObject.presetId);
+ writer.Write(specialObject.x);
+ writer.Write(specialObject.y);
+ writer.Write(specialObject.z);
+ for (int16_t extraParam : specialObject.extraParams) {
+ writer.Write(extraParam);
+ }
+ }
+
+ // Environment Region Boxes
+ if (collision->mEnvRegionBoxes.size() > 0) {
+ writer.Write((int16_t)TERRAIN_LOAD_ENVIRONMENT);
+ writer.Write((int16_t)collision->mEnvRegionBoxes.size());
+ }
+ for (auto &envRegionBox : collision->mEnvRegionBoxes) {
+ writer.Write(envRegionBox.id);
+ writer.Write(envRegionBox.x1);
+ writer.Write(envRegionBox.z1);
+ writer.Write(envRegionBox.x2);
+ writer.Write(envRegionBox.z2);
+ writer.Write(envRegionBox.height);
+ }
+
+ std::vector<char> buffer = writer.ToVector();
+ writer.Close();
+
+ LUS::BinaryWriter output = LUS::BinaryWriter();
+ WriteHeader(output, LUS::ResourceType::Blob, 0);
+
+ output.Write(static_cast<uint32_t>(buffer.size()));
+ output.Write(buffer.data(), buffer.size());
+ output.Finish(write);
+ output.Close();
+ return std::nullopt;
+}
+
+std::optional<std::shared_ptr<IParsedData>> SM64::CollisionFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
+ std::vector<CollisionVertex> vertices;
+ std::vector<CollisionSurface> surfaces;
+ std::vector<SpecialObject> specialObjects;
+ std::vector<EnvRegionBox> envRegionBoxes;
+ bool processing = true;
+ auto [_, segment] = Decompressor::AutoDecode(node, buffer);
+ auto cmd = segment.data;
+ LUS::BinaryReader reader(segment.data, segment.size);
+ reader.SetEndianness(LUS::Endianness::Big);
+
+ while (processing) {
+ int16_t terrainLoadType = reader.ReadInt16();
+
+ if (TERRAIN_LOAD_IS_SURFACE_TYPE_LOW(terrainLoadType)) {
+ SurfaceType surfaceType = static_cast<SurfaceType>(terrainLoadType);
+ bool hasForce = false;
+ switch (surfaceType) {
+ case SurfaceType::SURFACE_0004:
+ case SurfaceType::SURFACE_FLOWING_WATER:
+ case SurfaceType::SURFACE_DEEP_MOVING_QUICKSAND:
+ case SurfaceType::SURFACE_SHALLOW_MOVING_QUICKSAND:
+ case SurfaceType::SURFACE_MOVING_QUICKSAND:
+ case SurfaceType::SURFACE_HORIZONTAL_WIND:
+ case SurfaceType::SURFACE_INSTANT_MOVING_QUICKSAND:
+ hasForce = true;
+ break;
+ default:
+ break;
+ }
+ int16_t numSurfaces = reader.ReadInt16();
+ std::vector<CollisionTri> tris;
+ for (int16_t i = 0; i < numSurfaces; ++i) {
+ int16_t x = reader.ReadInt16();
+ int16_t y = reader.ReadInt16();
+ int16_t z = reader.ReadInt16();
+ int16_t force = hasForce ? reader.ReadInt16() : -1;
+ tris.emplace_back(x, y, z, force);
+ }
+ surfaces.emplace_back(surfaceType, tris);
+ } else if (terrainLoadType == TERRAIN_LOAD_VERTICES) {
+ int16_t numVertices = reader.ReadInt16();
+ for (int16_t i = 0; i < numVertices; ++i) {
+ int16_t x = reader.ReadInt16();
+ int16_t y = reader.ReadInt16();
+ int16_t z = reader.ReadInt16();
+ vertices.emplace_back(x, y, z);
+ }
+ } else if (terrainLoadType == TERRAIN_LOAD_OBJECTS) {
+ int16_t numSpecialObjects = reader.ReadInt16();
+ for (int16_t i = 0; i < numSpecialObjects; ++i) {
+ int16_t presetId = reader.ReadInt16();
+ int16_t x = reader.ReadInt16();
+ int16_t y = reader.ReadInt16();
+ int16_t z = reader.ReadInt16();
+ if (specialPresetMap.find(presetId) == specialPresetMap.end()) {
+ throw std::runtime_error("Special Preset Id has no associated Type");
+ }
+ SpecialPresets specialPresetId = static_cast<SpecialPresets>(presetId);
+ SpecialPresetTypes type = specialPresetMap.at(presetId);
+ std::vector<int16_t> extraParams;
+ switch (type) {
+ case SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS:
+ extraParams.emplace_back(reader.ReadInt16());
+ case SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT:
+ extraParams.emplace_back(reader.ReadInt16());
+ extraParams.emplace_back(reader.ReadInt16());
+ case SpecialPresetTypes::SPTYPE_UNKNOWN:
+ extraParams.emplace_back(reader.ReadInt16());
+ extraParams.emplace_back(reader.ReadInt16());
+ extraParams.emplace_back(reader.ReadInt16());
+ break;
+ case SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT:
+ extraParams.emplace_back(reader.ReadInt16());
+ break;
+ default:
+ break;
+ }
+ specialObjects.emplace_back(specialPresetId, x, y, z, extraParams);
+ }
+ } else if (terrainLoadType == TERRAIN_LOAD_ENVIRONMENT) {
+ int16_t numRegions = reader.ReadInt16();
+ for (int16_t i = 0; i < numRegions; ++i) {
+ int16_t id = reader.ReadInt16();
+ int16_t x1 = reader.ReadInt16();
+ int16_t z1 = reader.ReadInt16();
+ int16_t x2 = reader.ReadInt16();
+ int16_t z2 = reader.ReadInt16();
+ int16_t height = reader.ReadInt16();
+ envRegionBoxes.emplace_back(id, x1, z1, x2, z2, height);
+ }
+ } else if (terrainLoadType == TERRAIN_LOAD_CONTINUE) {
+ // need to figure out a way to handle when this should appear in exporters. seems to always be after vertices
+ } else if (terrainLoadType == TERRAIN_LOAD_END) {
+ processing = false;
+ } else if (TERRAIN_LOAD_IS_SURFACE_TYPE_HIGH(terrainLoadType)) {
+ SurfaceType surfaceType = static_cast<SurfaceType>(terrainLoadType);
+ bool hasForce = false;
+ switch (surfaceType) {
+ case SurfaceType::SURFACE_0004:
+ case SurfaceType::SURFACE_FLOWING_WATER:
+ case SurfaceType::SURFACE_DEEP_MOVING_QUICKSAND:
+ case SurfaceType::SURFACE_SHALLOW_MOVING_QUICKSAND:
+ case SurfaceType::SURFACE_MOVING_QUICKSAND:
+ case SurfaceType::SURFACE_HORIZONTAL_WIND:
+ case SurfaceType::SURFACE_INSTANT_MOVING_QUICKSAND:
+ hasForce = true;
+ break;
+ default:
+ break;
+ }
+ int16_t numSurfaces = reader.ReadInt16();
+ std::vector<CollisionTri> tris;
+ for (int16_t i = 0; i < numSurfaces; ++i) {
+ int16_t x = reader.ReadInt16();
+ int16_t y = reader.ReadInt16();
+ int16_t z = reader.ReadInt16();
+ int16_t force = hasForce ? reader.ReadInt16() : -1;
+ tris.emplace_back(x, y, z, force);
+ }
+ surfaces.emplace_back(surfaceType, tris);
+ }
+ }
+
+ return std::make_shared<Collision>(vertices, surfaces, specialObjects, envRegionBoxes);
+} \ No newline at end of file
diff --git a/src/factories/sm64/CollisionFactory.h b/src/factories/sm64/CollisionFactory.h
new file mode 100644
index 0000000..dcf7aba
--- /dev/null
+++ b/src/factories/sm64/CollisionFactory.h
@@ -0,0 +1,82 @@
+#pragma once
+
+#include "../BaseFactory.h"
+#include "collision/SpecialPresetNames.h"
+#include "collision/SurfaceTerrains.h"
+
+namespace SM64 {
+
+struct CollisionVertex {
+ int16_t x;
+ int16_t y;
+ int16_t z;
+ CollisionVertex(int16_t x, int16_t y, int16_t z) : x(x), y(y), z(z) {};
+};
+
+struct CollisionTri {
+ int16_t x;
+ int16_t y;
+ int16_t z;
+ int16_t force;
+ CollisionTri(int16_t x, int16_t y, int16_t z, int16_t force) : x(x), y(y), z(z), force(force) {};
+};
+
+struct CollisionSurface {
+ SurfaceType surfaceType;
+ std::vector<CollisionTri> tris;
+ CollisionSurface(SurfaceType surfaceType, std::vector<CollisionTri> tris) : surfaceType(surfaceType), tris(std::move(tris)) {};
+};
+
+struct SpecialObject {
+ SpecialPresets presetId;
+ int16_t x;
+ int16_t y;
+ int16_t z;
+ std::vector<int16_t> extraParams; // e.g. y-rot
+ SpecialObject(SpecialPresets presetId, int16_t x, int16_t y, int16_t z, std::vector<int16_t> extraParams) : presetId(presetId), x(x), y(y), z(z), extraParams(std::move(extraParams)) {};
+};
+
+struct EnvRegionBox {
+ int16_t id;
+ int16_t x1;
+ int16_t z1;
+ int16_t x2;
+ int16_t z2;
+ int16_t height;
+ EnvRegionBox(int16_t id, int16_t x1, int16_t z1, int16_t x2, int16_t z2, int16_t height) : id(id), x1(x1), z1(z1), x2(x2), z2(z2), height(height) {};
+}; // e.g. water-box
+
+class Collision : public IParsedData {
+public:
+ std::vector<CollisionVertex> mVertices;
+ std::vector<CollisionSurface> mSurfaces;
+ std::vector<SpecialObject> mSpecialObjects;
+ std::vector<EnvRegionBox> mEnvRegionBoxes;
+
+ explicit Collision(std::vector<CollisionVertex> vertices, std::vector<CollisionSurface> surfaces, std::vector<SpecialObject> specialObjects, std::vector<EnvRegionBox> envRegionBoxes) : mVertices(std::move(vertices)), mSurfaces(std::move(surfaces)), mSpecialObjects(std::move(specialObjects)), mEnvRegionBoxes(std::move(envRegionBoxes)) {}
+};
+
+class CollisionCodeExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class CollisionHeaderExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class CollisionBinaryExporter : public BaseExporter {
+ ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
+};
+
+class CollisionFactory : public BaseFactory {
+public:
+ std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
+ std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
+ return {
+ REGISTER(Header, CollisionHeaderExporter)
+ REGISTER(Binary, CollisionBinaryExporter)
+ REGISTER(Code, CollisionCodeExporter)
+ };
+ }
+};
+}
diff --git a/src/factories/sm64/collision/SpecialPresetNames.h b/src/factories/sm64/collision/SpecialPresetNames.h
new file mode 100644
index 0000000..32df987
--- /dev/null
+++ b/src/factories/sm64/collision/SpecialPresetNames.h
@@ -0,0 +1,385 @@
+#pragma once
+
+#include <string>
+#include <spdlog/spdlog.h>
+#include <spdlog/fmt/ostr.h>
+
+enum class SpecialPresetTypes {
+ SPTYPE_NO_YROT_OR_PARAMS,
+ SPTYPE_YROT_NO_PARAMS,
+ SPTYPE_PARAMS_AND_YROT,
+ SPTYPE_UNKNOWN,
+ SPTYPE_DEF_PARAM_AND_YROT,
+};
+
+inline std::ostream& operator<<(std::ostream& out, const SpecialPresetTypes& type) {
+ std::string output;
+ switch (type) {
+ case SpecialPresetTypes::SPTYPE_NO_YROT_OR_PARAMS:
+ output = "SPTYPE_NO_YROT_OR_PARAMS";
+ break;
+ case SpecialPresetTypes::SPTYPE_YROT_NO_PARAMS:
+ output = "SPTYPE_YROT_NO_PARAMS";
+ break;
+ case SpecialPresetTypes::SPTYPE_PARAMS_AND_YROT:
+ output = "SPTYPE_PARAMS_AND_YROT";
+ break;
+ case SpecialPresetTypes::SPTYPE_UNKNOWN:
+ output = "SPTYPE_UNKNOWN";
+ break;
+ case SpecialPresetTypes::SPTYPE_DEF_PARAM_AND_YROT:
+ output = "SPTYPE_DEF_PARAM_AND_YROT";
+ break;
+ default:
+ throw std::runtime_error("Unknown Special Preset Type");
+ }
+ return out << output;
+}
+
+enum class SpecialPresets {
+ special_null_start,
+ special_yellow_coin,
+ special_yellow_coin_2,
+ special_unknown_3,
+ special_boo,
+ special_unknown_5,
+ special_lll_moving_octagonal_mesh_platform,
+ special_snow_ball,
+ special_lll_drawbridge_spawner,
+ special_empty_9,
+ special_lll_rotating_block_with_fire_bars,
+ special_lll_floating_wood_bridge,
+ special_tumbling_platform,
+ special_lll_rotating_hexagonal_ring,
+ special_lll_sinking_rectangular_platform,
+ special_lll_sinking_square_platforms,
+ special_lll_tilting_square_platform,
+ special_lll_bowser_puzzle,
+ special_mr_i,
+ special_small_bully,
+ special_big_bully,
+ special_empty_21,
+ special_empty_22,
+ special_empty_23,
+ special_empty_24,
+ special_empty_25,
+ special_moving_blue_coin,
+ special_jrb_chest,
+ special_water_ring,
+ special_mine,
+ special_empty_30,
+ special_empty_31,
+ special_butterfly,
+ special_bowser,
+ special_wf_rotating_wooden_platform,
+ special_small_bomp,
+ special_wf_sliding_platform,
+ special_tower_platform_group,
+ special_rotating_counter_clockwise,
+ special_wf_tumbling_bridge,
+ special_large_bomp,
+
+ special_level_geo_03 = 0x65,
+ special_level_geo_04,
+ special_level_geo_05,
+ special_level_geo_06,
+ special_level_geo_07,
+ special_level_geo_08,
+ special_level_geo_09,
+ special_level_geo_0A,
+ special_level_geo_0B,
+ special_level_geo_0C,
+ special_level_geo_0D,
+ special_level_geo_0E,
+ special_level_geo_0F,
+ special_level_geo_10,
+ special_level_geo_11,
+ special_level_geo_12,
+ special_level_geo_13,
+ special_level_geo_14,
+ special_level_geo_15,
+ special_level_geo_16,
+ special_bubble_tree,
+ special_spiky_tree,
+ special_snow_tree,
+ special_unknown_tree,
+ special_palm_tree,
+ special_wooden_door,
+ special_haunted_door = special_wooden_door,
+ special_unknown_door,
+ special_metal_door,
+ special_hmc_door,
+ special_unknown2_door,
+ special_wooden_door_warp,
+ special_unknown1_door_warp,
+ special_metal_door_warp,
+ special_unknown2_door_warp,
+ special_unknown3_door_warp,
+ special_castle_door_warp,
+ special_castle_door,
+ special_0stars_door,
+ special_1star_door,
+ special_3star_door,
+ special_key_door,
+
+ special_null_end = 0xFF
+};
+
+inline std::ostream& operator<<(std::ostream& out, const SpecialPresets& preset) {
+ std::string output;
+ switch (preset) {
+ case SpecialPresets::special_null_start:
+ output = "special_null_start";
+ break;
+ case SpecialPresets::special_yellow_coin:
+ output = "special_yellow_coin";
+ break;
+ case SpecialPresets::special_yellow_coin_2:
+ output = "special_yellow_coin_2";
+ break;
+ case SpecialPresets::special_unknown_3:
+ output = "special_unknown_3";
+ break;
+ case SpecialPresets::special_boo:
+ output = "special_boo";
+ break;
+ case SpecialPresets::special_unknown_5:
+ output = "special_unknown_5";
+ break;
+ case SpecialPresets::special_lll_moving_octagonal_mesh_platform:
+ output = "special_lll_moving_octagonal_mesh_platform";
+ break;
+ case SpecialPresets::special_snow_ball:
+ output = "special_snow_ball";
+ break;
+ case SpecialPresets::special_lll_drawbridge_spawner:
+ output = "special_lll_drawbridge_spawner";
+ break;
+ case SpecialPresets::special_empty_9:
+ output = "special_empty_9";
+ break;
+ case SpecialPresets::special_lll_rotating_block_with_fire_bars:
+ output = "special_lll_rotating_block_with_fire_bars";
+ break;
+ case SpecialPresets::special_lll_floating_wood_bridge:
+ output = "special_lll_floating_wood_bridge";
+ break;
+ case SpecialPresets::special_tumbling_platform:
+ output = "special_tumbling_platform";
+ break;
+ case SpecialPresets::special_lll_rotating_hexagonal_ring:
+ output = "special_lll_rotating_hexagonal_ring";
+ break;
+ case SpecialPresets::special_lll_sinking_rectangular_platform:
+ output = "special_lll_sinking_rectangular_platform";
+ break;
+ case SpecialPresets::special_lll_sinking_square_platforms:
+ output = "special_lll_sinking_square_platforms";
+ break;
+ case SpecialPresets::special_lll_tilting_square_platform:
+ output = "special_lll_tilting_square_platform";
+ break;
+ case SpecialPresets::special_lll_bowser_puzzle:
+ output = "special_lll_bowser_puzzle";
+ break;
+ case SpecialPresets::special_mr_i:
+ output = "special_mr_i";
+ break;
+ case SpecialPresets::special_small_bully:
+ output = "special_small_bully";
+ break;
+ case SpecialPresets::special_big_bully:
+ output = "special_big_bully";
+ break;
+ case SpecialPresets::special_empty_21:
+ output = "special_empty_21";
+ break;
+ case SpecialPresets::special_empty_22:
+ output = "special_empty_22";
+ break;
+ case SpecialPresets::special_empty_23:
+ output = "special_empty_23";
+ break;
+ case SpecialPresets::special_empty_24:
+ output = "special_empty_24";
+ break;
+ case SpecialPresets::special_empty_25:
+ output = "special_empty_25";
+ break;
+ case SpecialPresets::special_moving_blue_coin:
+ output = "special_moving_blue_coin";
+ break;
+ case SpecialPresets::special_jrb_chest:
+ output = "special_jrb_chest";
+ break;
+ case SpecialPresets::special_water_ring:
+ output = "special_water_ring";
+ break;
+ case SpecialPresets::special_mine:
+ output = "special_mine";
+ break;
+ case SpecialPresets::special_empty_30:
+ output = "special_empty_30";
+ break;
+ case SpecialPresets::special_empty_31:
+ output = "special_empty_31";
+ break;
+ case SpecialPresets::special_butterfly:
+ output = "special_butterfly";
+ break;
+ case SpecialPresets::special_bowser:
+ output = "special_bowser";
+ break;
+ case SpecialPresets::special_wf_rotating_wooden_platform:
+ output = "special_wf_rotating_wooden_platform";
+ break;
+ case SpecialPresets::special_small_bomp:
+ output = "special_small_bomp";
+ break;
+ case SpecialPresets::special_wf_sliding_platform:
+ output = "special_wf_sliding_platform";
+ break;
+ case SpecialPresets::special_tower_platform_group:
+ output = "special_tower_platform_group";
+ break;
+ case SpecialPresets::special_rotating_counter_clockwise:
+ output = "special_rotating_counter_clockwise";
+ break;
+ case SpecialPresets::special_wf_tumbling_bridge:
+ output = "special_wf_tumbling_bridge";
+ break;
+ case SpecialPresets::special_large_bomp:
+ output = "special_large_bomp";
+ break;
+ case SpecialPresets::special_level_geo_03:
+ output = "special_level_geo_03";
+ break;
+ case SpecialPresets::special_level_geo_04:
+ output = "special_level_geo_04";
+ break;
+ case SpecialPresets::special_level_geo_05:
+ output = "special_level_geo_05";
+ break;
+ case SpecialPresets::special_level_geo_06:
+ output = "special_level_geo_06";
+ break;
+ case SpecialPresets::special_level_geo_07:
+ output = "special_level_geo_07";
+ break;
+ case SpecialPresets::special_level_geo_08:
+ output = "special_level_geo_08";
+ break;
+ case SpecialPresets::special_level_geo_09:
+ output = "special_level_geo_09";
+ break;
+ case SpecialPresets::special_level_geo_0A:
+ output = "special_level_geo_0A";
+ break;
+ case SpecialPresets::special_level_geo_0B:
+ output = "special_level_geo_0B";
+ break;
+ case SpecialPresets::special_level_geo_0C:
+ output = "special_level_geo_0C";
+ break;
+ case SpecialPresets::special_level_geo_0D:
+ output = "special_level_geo_0D";
+ break;
+ case SpecialPresets::special_level_geo_0E:
+ output = "special_level_geo_0E";
+ break;
+ case SpecialPresets::special_level_geo_0F:
+ output = "special_level_geo_0F";
+ break;
+ case SpecialPresets::special_level_geo_10:
+ output = "special_level_geo_10";
+ break;
+ case SpecialPresets::special_level_geo_11:
+ output = "special_level_geo_11";
+ break;
+ case SpecialPresets::special_level_geo_12:
+ output = "special_level_geo_12";
+ break;
+ case SpecialPresets::special_level_geo_13:
+ output = "special_level_geo_13";
+ break;
+ case SpecialPresets::special_level_geo_14:
+ output = "special_level_geo_14";
+ break;
+ case SpecialPresets::special_level_geo_15:
+ output = "special_level_geo_15";
+ break;
+ case SpecialPresets::special_level_geo_16:
+ output = "special_level_geo_16";
+ break;
+ case SpecialPresets::special_bubble_tree:
+ output = "special_bubble_tree";
+ break;
+ case SpecialPresets::special_spiky_tree:
+ output = "special_spiky_tree";
+ break;
+ case SpecialPresets::special_snow_tree:
+ output = "special_snow_tree";
+ break;
+ case SpecialPresets::special_unknown_tree:
+ output = "special_unknown_tree";
+ break;
+ case SpecialPresets::special_palm_tree:
+ output = "special_palm_tree";
+ break;
+ case SpecialPresets::special_wooden_door:
+ output = "special_wooden_door";
+ break;
+ case SpecialPresets::special_unknown_door:
+ output = "special_unknown_door";
+ break;
+ case SpecialPresets::special_metal_door:
+ output = "special_metal_door";
+ break;
+ case SpecialPresets::special_hmc_door:
+ output = "special_hmc_door";
+ break;
+ case SpecialPresets::special_unknown2_door:
+ output = "special_unknown2_door";
+ break;
+ case SpecialPresets::special_wooden_door_warp:
+ output = "special_wooden_door_warp";
+ break;
+ case SpecialPresets::special_unknown1_door_warp:
+ output = "special_unknown1_door_warp";
+ break;
+ case SpecialPresets::special_metal_door_warp:
+ output = "special_metal_door_warp";
+ break;
+ case SpecialPresets::special_unknown2_door_warp:
+ output = "special_unknown2_door_warp";
+ break;
+ case SpecialPresets::special_unknown3_door_warp:
+ output = "special_unknown3_door_warp";
+ break;
+ case SpecialPresets::special_castle_door_warp:
+ output = "special_castle_door_warp";
+ break;
+ case SpecialPresets::special_castle_door:
+ output = "special_castle_door";
+ break;
+ case SpecialPresets::special_0stars_door:
+ output = "special_0stars_door";
+ break;
+ case SpecialPresets::special_1star_door:
+ output = "special_1star_door";
+ break;
+ case SpecialPresets::special_3star_door:
+ output = "special_3star_door";
+ break;
+ case SpecialPresets::special_key_door:
+ output = "special_key_door";
+ break;
+ case SpecialPresets::special_null_end:
+ output = "special_null_end";
+ break;
+ default:
+ throw std::runtime_error("Unknown Special Preset");
+ }
+
+ return out << output;
+}
diff --git a/src/factories/sm64/collision/SurfaceTerrains.h b/src/factories/sm64/collision/SurfaceTerrains.h
new file mode 100644
index 0000000..0d70d4a
--- /dev/null
+++ b/src/factories/sm64/collision/SurfaceTerrains.h
@@ -0,0 +1,672 @@
+#pragma once
+
+// Surface Types
+enum class SurfaceType {
+ SURFACE_DEFAULT = 0x0000, // Environment default
+ SURFACE_BURNING = 0x0001, // Lava / Frostbite (in SL), but is used mostly for Lava
+ SURFACE_0004 = 0x0004, // Unused, has no function and has parameters
+ SURFACE_HANGABLE = 0x0005, // Ceiling that Mario can climb on
+ SURFACE_SLOW = 0x0009, // Slow down Mario, unused
+ SURFACE_DEATH_PLANE = 0x000A, // Death floor
+ SURFACE_CLOSE_CAMERA = 0x000B, // Close camera
+ SURFACE_WATER = 0x000D, // Water, has no action, used on some waterboxes below
+ SURFACE_FLOWING_WATER = 0x000E, // Water (flowing), has parameters
+ SURFACE_INTANGIBLE = 0x0012, // Intangible (Separates BBH mansion from merry-go-round, for room usage)
+ SURFACE_VERY_SLIPPERY = 0x0013, // Very slippery, mostly used for slides
+ SURFACE_SLIPPERY = 0x0014, // Slippery
+ SURFACE_NOT_SLIPPERY = 0x0015, // Non-slippery, climbable
+ SURFACE_TTM_VINES = 0x0016, // TTM vines, has no action defined
+ SURFACE_MGR_MUSIC = 0x001A, // Plays the Merry go round music, see handle_merry_go_round_music in bbh_merry_go_round.inc.c for more details
+ SURFACE_INSTANT_WARP_1B = 0x001B, // Instant warp to another area, used to warp between areas in WDW and the endless stairs to warp back
+ SURFACE_INSTANT_WARP_1C = 0x001C, // Instant warp to another area, used to warp between areas in WDW
+ SURFACE_INSTANT_WARP_1D = 0x001D, // Instant warp to another area, used to warp between areas in DDD, SSL and TTM
+ SURFACE_INSTANT_WARP_1E = 0x001E, // Instant warp to another area, used to warp between areas in DDD, SSL and TTM
+ SURFACE_SHALLOW_QUICKSAND = 0x0021, // Shallow Quicksand (depth of 10 units)
+ SURFACE_DEEP_QUICKSAND = 0x0022, // Quicksand (lethal, slow, depth of 160 units)
+ SURFACE_INSTANT_QUICKSAND = 0x0023, // Quicksand (lethal, instant)
+ SURFACE_DEEP_MOVING_QUICKSAND = 0x0024, // Moving quicksand (flowing, depth of 160 units)
+ SURFACE_SHALLOW_MOVING_QUICKSAND = 0x0025, // Moving quicksand (flowing, depth of 25 units)
+ SURFACE_QUICKSAND = 0x0026, // Moving quicksand (60 units)
+ SURFACE_MOVING_QUICKSAND = 0x0027, // Moving quicksand (flowing, depth of 60 units)
+ SURFACE_WALL_MISC = 0x0028, // Used for some walls, Cannon to adjust the camera, and some objects like Warp Pipe
+ SURFACE_NOISE_DEFAULT = 0x0029, // Default floor with noise
+ SURFACE_NOISE_SLIPPERY = 0x002A, // Slippery floor with noise
+ SURFACE_HORIZONTAL_WIND = 0x002C, // Horizontal wind, has parameters
+ SURFACE_INSTANT_MOVING_QUICKSAND = 0x002D, // Quicksand (lethal, flowing)
+ SURFACE_ICE = 0x002E, // Slippery Ice, in snow levels and THI's water floor
+ SURFACE_LOOK_UP_WARP = 0x002F, // Look up and warp (Wing cap entrance)
+ SURFACE_HARD = 0x0030, // Hard floor (Always has fall damage)
+ SURFACE_WARP = 0x0032, // Surface warp
+ SURFACE_TIMER_START = 0x0033, // Timer start (Peach's secret slide)
+ SURFACE_TIMER_END = 0x0034, // Timer stop (Peach's secret slide)
+ SURFACE_HARD_SLIPPERY = 0x0035, // Hard and slippery (Always has fall damage)
+ SURFACE_HARD_VERY_SLIPPERY = 0x0036, // Hard and very slippery (Always has fall damage)
+ SURFACE_HARD_NOT_SLIPPERY = 0x0037, // Hard and Non-slippery (Always has fall damage)
+ SURFACE_VERTICAL_WIND = 0x0038, // Death at bottom with vertical wind
+ SURFACE_BOSS_FIGHT_CAMERA = 0x0065, // Wide camera for BoB and WF bosses
+ SURFACE_CAMERA_FREE_ROAM = 0x0066, // Free roam camera for THI and TTC
+ SURFACE_THI3_WALLKICK = 0x0068, // Surface where there's a wall kick section in THI 3rd area, has no action defined
+ SURFACE_CAMERA_8_DIR = 0x0069, // Surface that enables far camera for platforms, used in THI
+ SURFACE_CAMERA_MIDDLE = 0x006E, // Surface camera that returns to the middle, used on the 4 pillars of SSL
+ SURFACE_CAMERA_ROTATE_RIGHT = 0x006F, // Surface camera that rotates to the right (Bowser 1 & THI)
+ SURFACE_CAMERA_ROTATE_LEFT = 0x0070, // Surface camera that rotates to the left (BoB & TTM)
+ SURFACE_CAMERA_BOUNDARY = 0x0072, // Intangible Area, only used to restrict camera movement
+ SURFACE_NOISE_VERY_SLIPPERY_73 = 0x0073, // Very slippery floor with noise, unused
+ SURFACE_NOISE_VERY_SLIPPERY_74 = 0x0074, // Very slippery floor with noise, unused
+ SURFACE_NOISE_VERY_SLIPPERY = 0x0075, // Very slippery floor with noise, used in CCM
+ SURFACE_NO_CAM_COLLISION = 0x0076, // Surface with no cam collision flag
+ SURFACE_NO_CAM_COLLISION_77 = 0x0077, // Surface with no cam collision flag, unused
+ SURFACE_NO_CAM_COL_VERY_SLIPPERY = 0x0078, // Surface with no cam collision flag, very slippery with noise (THI)
+ SURFACE_NO_CAM_COL_SLIPPERY = 0x0079, // Surface with no cam collision flag, slippery with noise (CCM, PSS and TTM slides)
+ SURFACE_SWITCH = 0x007A, // Surface with no cam collision flag, non-slippery with noise, used by switches and Dorrie
+ SURFACE_VANISH_CAP_WALLS = 0x007B, // Vanish cap walls, pass through them with Vanish Cap
+ SURFACE_PAINTING_WOBBLE_A6 = 0x00A6, // Painting wobble (BoB Left)
+ SURFACE_PAINTING_WOBBLE_A7 = 0x00A7, // Painting wobble (BoB Middle)
+ SURFACE_PAINTING_WOBBLE_A8 = 0x00A8, // Painting wobble (BoB Right)
+ SURFACE_PAINTING_WOBBLE_A9 = 0x00A9, // Painting wobble (CCM Left)
+ SURFACE_PAINTING_WOBBLE_AA = 0x00AA, // Painting wobble (CCM Middle)
+ SURFACE_PAINTING_WOBBLE_AB = 0x00AB, // Painting wobble (CCM Right)
+ SURFACE_PAINTING_WOBBLE_AC = 0x00AC, // Painting wobble (WF Left)
+ SURFACE_PAINTING_WOBBLE_AD = 0x00AD, // Painting wobble (WF Middle)
+ SURFACE_PAINTING_WOBBLE_AE = 0x00AE, // Painting wobble (WF Right)
+ SURFACE_PAINTING_WOBBLE_AF = 0x00AF, // Painting wobble (JRB Left)
+ SURFACE_PAINTING_WOBBLE_B0 = 0x00B0, // Painting wobble (JRB Middle)
+ SURFACE_PAINTING_WOBBLE_B1 = 0x00B1, // Painting wobble (JRB Right)
+ SURFACE_PAINTING_WOBBLE_B2 = 0x00B2, // Painting wobble (LLL Left)
+ SURFACE_PAINTING_WOBBLE_B3 = 0x00B3, // Painting wobble (LLL Middle)
+ SURFACE_PAINTING_WOBBLE_B4 = 0x00B4, // Painting wobble (LLL Right)
+ SURFACE_PAINTING_WOBBLE_B5 = 0x00B5, // Painting wobble (SSL Left)
+ SURFACE_PAINTING_WOBBLE_B6 = 0x00B6, // Painting wobble (SSL Middle)
+ SURFACE_PAINTING_WOBBLE_B7 = 0x00B7, // Painting wobble (SSL Right)
+ SURFACE_PAINTING_WOBBLE_B8 = 0x00B8, // Painting wobble (Unused - Left)
+ SURFACE_PAINTING_WOBBLE_B9 = 0x00B9, // Painting wobble (Unused - Middle)
+ SURFACE_PAINTING_WOBBLE_BA = 0x00BA, // Painting wobble (Unused - Right)
+ SURFACE_PAINTING_WOBBLE_BB = 0x00BB, // Painting wobble (DDD - Left), makes the painting wobble if touched
+ SURFACE_PAINTING_WOBBLE_BC = 0x00BC, // Painting wobble (Unused, DDD - Middle)
+ SURFACE_PAINTING_WOBBLE_BD = 0x00BD, // Painting wobble (Unused, DDD - Right)
+ SURFACE_PAINTING_WOBBLE_BE = 0x00BE, // Painting wobble (WDW Left)
+ SURFACE_PAINTING_WOBBLE_BF = 0x00BF, // Painting wobble (WDW Middle)
+ SURFACE_PAINTING_WOBBLE_C0 = 0x00C0, // Painting wobble (WDW Right)
+ SURFACE_PAINTING_WOBBLE_C1 = 0x00C1, // Painting wobble (THI Tiny - Left)
+ SURFACE_PAINTING_WOBBLE_C2 = 0x00C2, // Painting wobble (THI Tiny - Middle)
+ SURFACE_PAINTING_WOBBLE_C3 = 0x00C3, // Painting wobble (THI Tiny - Right)
+ SURFACE_PAINTING_WOBBLE_C4 = 0x00C4, // Painting wobble (TTM Left)
+ SURFACE_PAINTING_WOBBLE_C5 = 0x00C5, // Painting wobble (TTM Middle)
+ SURFACE_PAINTING_WOBBLE_C6 = 0x00C6, // Painting wobble (TTM Right)
+ SURFACE_PAINTING_WOBBLE_C7 = 0x00C7, // Painting wobble (Unused, TTC - Left)
+ SURFACE_PAINTING_WOBBLE_C8 = 0x00C8, // Painting wobble (Unused, TTC - Middle)
+ SURFACE_PAINTING_WOBBLE_C9 = 0x00C9, // Painting wobble (Unused, TTC - Right)
+ SURFACE_PAINTING_WOBBLE_CA = 0x00CA, // Painting wobble (Unused, SL - Left)
+ SURFACE_PAINTING_WOBBLE_CB = 0x00CB, // Painting wobble (Unused, SL - Middle)
+ SURFACE_PAINTING_WOBBLE_CC = 0x00CC, // Painting wobble (Unused, SL - Right)
+ SURFACE_PAINTING_WOBBLE_CD = 0x00CD, // Painting wobble (THI Huge - Left)
+ SURFACE_PAINTING_WOBBLE_CE = 0x00CE, // Painting wobble (THI Huge - Middle)
+ SURFACE_PAINTING_WOBBLE_CF = 0x00CF, // Painting wobble (THI Huge - Right)
+ SURFACE_PAINTING_WOBBLE_D0 = 0x00D0, // Painting wobble (HMC & COTMC - Left), makes the painting wobble if touched
+ SURFACE_PAINTING_WOBBLE_D1 = 0x00D1, // Painting wobble (Unused, HMC & COTMC - Middle)
+ SURFACE_PAINTING_WOBBLE_D2 = 0x00D2, // Painting wobble (Unused, HMC & COTMC - Right)
+ SURFACE_PAINTING_WARP_D3 = 0x00D3, // Painting warp (BoB Left)
+ SURFACE_PAINTING_WARP_D4 = 0x00D4, // Painting warp (BoB Middle)
+ SURFACE_PAINTING_WARP_D5 = 0x00D5, // Painting warp (BoB Right)
+ SURFACE_PAINTING_WARP_D6 = 0x00D6, // Painting warp (CCM Left)
+ SURFACE_PAINTING_WARP_D7 = 0x00D7, // Painting warp (CCM Middle)
+ SURFACE_PAINTING_WARP_D8 = 0x00D8, // Painting warp (CCM Right)
+ SURFACE_PAINTING_WARP_D9 = 0x00D9, // Painting warp (WF Left)
+ SURFACE_PAINTING_WARP_DA = 0x00DA, // Painting warp (WF Middle)
+ SURFACE_PAINTING_WARP_DB = 0x00DB, // Painting warp (WF Right)
+ SURFACE_PAINTING_WARP_DC = 0x00DC, // Painting warp (JRB Left)
+ SURFACE_PAINTING_WARP_DD = 0x00DD, // Painting warp (JRB Middle)
+ SURFACE_PAINTING_WARP_DE = 0x00DE, // Painting warp (JRB Right)
+ SURFACE_PAINTING_WARP_DF = 0x00DF, // Painting warp (LLL Left)
+ SURFACE_PAINTING_WARP_E0 = 0x00E0, // Painting warp (LLL Middle)
+ SURFACE_PAINTING_WARP_E1 = 0x00E1, // Painting warp (LLL Right)
+ SURFACE_PAINTING_WARP_E2 = 0x00E2, // Painting warp (SSL Left)
+ SURFACE_PAINTING_WARP_E3 = 0x00E3, // Painting warp (SSL Medium)
+ SURFACE_PAINTING_WARP_E4 = 0x00E4, // Painting warp (SSL Right)
+ SURFACE_PAINTING_WARP_E5 = 0x00E5, // Painting warp (Unused - Left)
+ SURFACE_PAINTING_WARP_E6 = 0x00E6, // Painting warp (Unused - Medium)
+ SURFACE_PAINTING_WARP_E7 = 0x00E7, // Painting warp (Unused - Right)
+ SURFACE_PAINTING_WARP_E8 = 0x00E8, // Painting warp (DDD - Left)
+ SURFACE_PAINTING_WARP_E9 = 0x00E9, // Painting warp (DDD - Middle)
+ SURFACE_PAINTING_WARP_EA = 0x00EA, // Painting warp (DDD - Right)
+ SURFACE_PAINTING_WARP_EB = 0x00EB, // Painting warp (WDW Left)
+ SURFACE_PAINTING_WARP_EC = 0x00EC, // Painting warp (WDW Middle)
+ SURFACE_PAINTING_WARP_ED = 0x00ED, // Painting warp (WDW Right)
+ SURFACE_PAINTING_WARP_EE = 0x00EE, // Painting warp (THI Tiny - Left)
+ SURFACE_PAINTING_WARP_EF = 0x00EF, // Painting warp (THI Tiny - Middle)
+ SURFACE_PAINTING_WARP_F0 = 0x00F0, // Painting warp (THI Tiny - Right)
+ SURFACE_PAINTING_WARP_F1 = 0x00F1, // Painting warp (TTM Left)
+ SURFACE_PAINTING_WARP_F2 = 0x00F2, // Painting warp (TTM Middle)
+ SURFACE_PAINTING_WARP_F3 = 0x00F3, // Painting warp (TTM Right)
+ SURFACE_TTC_PAINTING_1 = 0x00F4, // Painting warp (TTC Left)
+ SURFACE_TTC_PAINTING_2 = 0x00F5, // Painting warp (TTC Medium)
+ SURFACE_TTC_PAINTING_3 = 0x00F6, // Painting warp (TTC Right)
+ SURFACE_PAINTING_WARP_F7 = 0x00F7, // Painting warp (SL Left)
+ SURFACE_PAINTING_WARP_F8 = 0x00F8, // Painting warp (SL Middle)
+ SURFACE_PAINTING_WARP_F9 = 0x00F9, // Painting warp (SL Right)
+ SURFACE_PAINTING_WARP_FA = 0x00FA, // Painting warp (THI Tiny - Left)
+ SURFACE_PAINTING_WARP_FB = 0x00FB, // Painting warp (THI Tiny - Middle)
+ SURFACE_PAINTING_WARP_FC = 0x00FC, // Painting warp (THI Tiny - Right)
+ SURFACE_WOBBLING_WARP = 0x00FD, // Pool warp (HMC & DDD)
+ SURFACE_TRAPDOOR = 0x00FF, // Bowser Left trapdoor, has no action defined
+};
+
+inline std::ostream& operator<<(std::ostream& out, const SurfaceType& surfaceType) {
+ std::string output;
+ switch (surfaceType) {
+ case SurfaceType::SURFACE_DEFAULT:
+ output = "SURFACE_DEFAULT";
+ break;
+ case SurfaceType::SURFACE_BURNING:
+ output = "SURFACE_BURNING";
+ break;
+ case SurfaceType::SURFACE_0004:
+ output = "SURFACE_0004";
+ break;
+ case SurfaceType::SURFACE_HANGABLE:
+ output = "SURFACE_HANGABLE";
+ break;
+ case SurfaceType::SURFACE_SLOW:
+ output = "SURFACE_SLOW";
+ break;
+ case SurfaceType::SURFACE_DEATH_PLANE:
+ output = "SURFACE_DEATH_PLANE";
+ break;
+ case SurfaceType::SURFACE_CLOSE_CAMERA:
+ output = "SURFACE_CLOSE_CAMERA";
+ break;
+ case SurfaceType::SURFACE_WATER:
+ output = "SURFACE_WATER";
+ break;
+ case SurfaceType::SURFACE_FLOWING_WATER:
+ output = "SURFACE_FLOWING_WATER";
+ break;
+ case SurfaceType::SURFACE_INTANGIBLE:
+ output = "SURFACE_INTANGIBLE";
+ break;
+ case SurfaceType::SURFACE_VERY_SLIPPERY:
+ output = "SURFACE_VERY_SLIPPERY";
+ break;
+ case SurfaceType::SURFACE_SLIPPERY:
+ output = "SURFACE_SLIPPERY";
+ break;
+ case SurfaceType::SURFACE_NOT_SLIPPERY:
+ output = "SURFACE_NOT_SLIPPERY";
+ break;
+ case SurfaceType::SURFACE_TTM_VINES:
+ output = "SURFACE_TTM_VINES";
+ break;
+ case SurfaceType::SURFACE_MGR_MUSIC:
+ output = "SURFACE_MGR_MUSIC";
+ break;
+ case SurfaceType::SURFACE_INSTANT_WARP_1B:
+ output = "SURFACE_INSTANT_WARP_1B";
+ break;
+ case SurfaceType::SURFACE_INSTANT_WARP_1C:
+ output = "SURFACE_INSTANT_WARP_1C";
+ break;
+ case SurfaceType::SURFACE_INSTANT_WARP_1D:
+ output = "SURFACE_INSTANT_WARP_1D";
+ break;
+ case SurfaceType::SURFACE_INSTANT_WARP_1E:
+ output = "SURFACE_INSTANT_WARP_1E";
+ break;
+ case SurfaceType::SURFACE_SHALLOW_QUICKSAND:
+ output = "SURFACE_SHALLOW_QUICKSAND";
+ break;
+ case SurfaceType::SURFACE_DEEP_QUICKSAND:
+ output = "SURFACE_DEEP_QUICKSAND";
+ break;
+ case SurfaceType::SURFACE_INSTANT_QUICKSAND:
+ output = "SURFACE_INSTANT_QUICKSAND";
+ break;
+ case SurfaceType::SURFACE_DEEP_MOVING_QUICKSAND:
+ output = "SURFACE_DEEP_MOVING_QUICKSAND";
+ break;
+ case SurfaceType::SURFACE_SHALLOW_MOVING_QUICKSAND:
+ output = "SURFACE_SHALLOW_MOVING_QUICKSAND";
+ break;
+ case SurfaceType::SURFACE_QUICKSAND:
+ output = "SURFACE_QUICKSAND";
+ break;
+ case SurfaceType::SURFACE_MOVING_QUICKSAND:
+ output = "SURFACE_MOVING_QUICKSAND";
+ break;
+ case SurfaceType::SURFACE_WALL_MISC:
+ output = "SURFACE_WALL_MISC";
+ break;
+ case SurfaceType::SURFACE_NOISE_DEFAULT:
+ output = "SURFACE_NOISE_DEFAULT";
+ break;
+ case SurfaceType::SURFACE_NOISE_SLIPPERY:
+ output = "SURFACE_NOISE_SLIPPERY";
+ break;
+ case SurfaceType::SURFACE_HORIZONTAL_WIND:
+ output = "SURFACE_HORIZONTAL_WIND";
+ break;
+ case SurfaceType::SURFACE_INSTANT_MOVING_QUICKSAND:
+ output = "SURFACE_INSTANT_MOVING_QUICKSAND";
+ break;
+ case SurfaceType::SURFACE_ICE:
+ output = "SURFACE_ICE";
+ break;
+ case SurfaceType::SURFACE_LOOK_UP_WARP:
+ output = "SURFACE_LOOK_UP_WARP";
+ break;
+ case SurfaceType::SURFACE_HARD:
+ output = "SURFACE_HARD";
+ break;
+ case SurfaceType::SURFACE_WARP:
+ output = "SURFACE_WARP";
+ break;
+ case SurfaceType::SURFACE_TIMER_START:
+ output = "SURFACE_TIMER_START";
+ break;
+ case SurfaceType::SURFACE_TIMER_END:
+ output = "SURFACE_TIMER_END";
+ break;
+ case SurfaceType::SURFACE_HARD_SLIPPERY:
+ output = "SURFACE_HARD_SLIPPERY";
+ break;
+ case SurfaceType::SURFACE_HARD_VERY_SLIPPERY:
+ output = "SURFACE_HARD_VERY_SLIPPERY";
+ break;
+ case SurfaceType::SURFACE_HARD_NOT_SLIPPERY:
+ output = "SURFACE_HARD_NOT_SLIPPERY";
+ break;
+ case SurfaceType::SURFACE_VERTICAL_WIND:
+ output = "SURFACE_VERTICAL_WIND";
+ break;
+ case SurfaceType::SURFACE_BOSS_FIGHT_CAMERA:
+ output = "SURFACE_BOSS_FIGHT_CAMERA";
+ break;
+ case SurfaceType::SURFACE_CAMERA_FREE_ROAM:
+ output = "SURFACE_CAMERA_FREE_ROAM";
+ break;
+ case SurfaceType::SURFACE_THI3_WALLKICK:
+ output = "SURFACE_THI3_WALLKICK";
+ break;
+ case SurfaceType::SURFACE_CAMERA_8_DIR:
+ output = "SURFACE_CAMERA_8_DIR";
+ break;
+ case SurfaceType::SURFACE_CAMERA_MIDDLE:
+ output = "SURFACE_CAMERA_MIDDLE";
+ break;
+ case SurfaceType::SURFACE_CAMERA_ROTATE_RIGHT:
+ output = "SURFACE_CAMERA_ROTATE_RIGHT";
+ break;
+ case SurfaceType::SURFACE_CAMERA_ROTATE_LEFT:
+ output = "SURFACE_CAMERA_ROTATE_LEFT";
+ break;
+ case SurfaceType::SURFACE_CAMERA_BOUNDARY:
+ output = "SURFACE_CAMERA_BOUNDARY";
+ break;
+ case SurfaceType::SURFACE_NOISE_VERY_SLIPPERY_73:
+ output = "SURFACE_NOISE_VERY_SLIPPERY_73";
+ break;
+ case SurfaceType::SURFACE_NOISE_VERY_SLIPPERY_74:
+ output = "SURFACE_NOISE_VERY_SLIPPERY_74";
+ break;
+ case SurfaceType::SURFACE_NOISE_VERY_SLIPPERY:
+ output = "SURFACE_NOISE_VERY_SLIPPERY";
+ break;
+ case SurfaceType::SURFACE_NO_CAM_COLLISION:
+ output = "SURFACE_NO_CAM_COLLISION";
+ break;
+ case SurfaceType::SURFACE_NO_CAM_COLLISION_77:
+ output = "SURFACE_NO_CAM_COLLISION_77";
+ break;
+ case SurfaceType::SURFACE_NO_CAM_COL_VERY_SLIPPERY:
+ output = "SURFACE_NO_CAM_COL_VERY_SLIPPERY";
+ break;
+ case SurfaceType::SURFACE_NO_CAM_COL_SLIPPERY:
+ output = "SURFACE_NO_CAM_COL_SLIPPERY";
+ break;
+ case SurfaceType::SURFACE_SWITCH:
+ output = "SURFACE_SWITCH";
+ break;
+ case SurfaceType::SURFACE_VANISH_CAP_WALLS:
+ output = "SURFACE_VANISH_CAP_WALLS";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_A6:
+ output = "SURFACE_PAINTING_WOBBLE_A6";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_A7:
+ output = "SURFACE_PAINTING_WOBBLE_A7";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_A8:
+ output = "SURFACE_PAINTING_WOBBLE_A8";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_A9:
+ output = "SURFACE_PAINTING_WOBBLE_A9";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_AA:
+ output = "SURFACE_PAINTING_WOBBLE_AA";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_AB:
+ output = "SURFACE_PAINTING_WOBBLE_AB";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_AC:
+ output = "SURFACE_PAINTING_WOBBLE_AC";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_AD:
+ output = "SURFACE_PAINTING_WOBBLE_AD";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_AE:
+ output = "SURFACE_PAINTING_WOBBLE_AE";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_AF:
+ output = "SURFACE_PAINTING_WOBBLE_AF";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_B0:
+ output = "SURFACE_PAINTING_WOBBLE_B0";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_B1:
+ output = "SURFACE_PAINTING_WOBBLE_B1";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_B2:
+ output = "SURFACE_PAINTING_WOBBLE_B2";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_B3:
+ output = "SURFACE_PAINTING_WOBBLE_B3";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_B4:
+ output = "SURFACE_PAINTING_WOBBLE_B4";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_B5:
+ output = "SURFACE_PAINTING_WOBBLE_B5";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_B6:
+ output = "SURFACE_PAINTING_WOBBLE_B6";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_B7:
+ output = "SURFACE_PAINTING_WOBBLE_B7";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_B8:
+ output = "SURFACE_PAINTING_WOBBLE_B8";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_B9:
+ output = "SURFACE_PAINTING_WOBBLE_B9";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_BA:
+ output = "SURFACE_PAINTING_WOBBLE_BA";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_BB:
+ output = "SURFACE_PAINTING_WOBBLE_BB";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_BC:
+ output = "SURFACE_PAINTING_WOBBLE_BC";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_BD:
+ output = "SURFACE_PAINTING_WOBBLE_BD";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_BE:
+ output = "SURFACE_PAINTING_WOBBLE_BE";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_BF:
+ output = "SURFACE_PAINTING_WOBBLE_BF";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_C0:
+ output = "SURFACE_PAINTING_WOBBLE_C0";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_C1:
+ output = "SURFACE_PAINTING_WOBBLE_C1";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_C2:
+ output = "SURFACE_PAINTING_WOBBLE_C2";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_C3:
+ output = "SURFACE_PAINTING_WOBBLE_C3";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_C4:
+ output = "SURFACE_PAINTING_WOBBLE_C4";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_C5:
+ output = "SURFACE_PAINTING_WOBBLE_C5";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_C6:
+ output = "SURFACE_PAINTING_WOBBLE_C6";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_C7:
+ output = "SURFACE_PAINTING_WOBBLE_C7";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_C8:
+ output = "SURFACE_PAINTING_WOBBLE_C8";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_C9:
+ output = "SURFACE_PAINTING_WOBBLE_C9";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_CA:
+ output = "SURFACE_PAINTING_WOBBLE_CA";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_CB:
+ output = "SURFACE_PAINTING_WOBBLE_CB";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_CC:
+ output = "SURFACE_PAINTING_WOBBLE_CC";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_CD:
+ output = "SURFACE_PAINTING_WOBBLE_CD";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_CE:
+ output = "SURFACE_PAINTING_WOBBLE_CE";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_CF:
+ output = "SURFACE_PAINTING_WOBBLE_CF";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_D0:
+ output = "SURFACE_PAINTING_WOBBLE_D0";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_D1:
+ output = "SURFACE_PAINTING_WOBBLE_D1";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WOBBLE_D2:
+ output = "SURFACE_PAINTING_WOBBLE_D2";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_D3:
+ output = "SURFACE_PAINTING_WARP_D3";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_D4:
+ output = "SURFACE_PAINTING_WARP_D4";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_D5:
+ output = "SURFACE_PAINTING_WARP_D5";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_D6:
+ output = "SURFACE_PAINTING_WARP_D6";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_D7:
+ output = "SURFACE_PAINTING_WARP_D7";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_D8:
+ output = "SURFACE_PAINTING_WARP_D8";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_D9:
+ output = "SURFACE_PAINTING_WARP_D9";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_DA:
+ output = "SURFACE_PAINTING_WARP_DA";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_DB:
+ output = "SURFACE_PAINTING_WARP_DB";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_DC:
+ output = "SURFACE_PAINTING_WARP_DC";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_DD:
+ output = "SURFACE_PAINTING_WARP_DD";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_DE:
+ output = "SURFACE_PAINTING_WARP_DE";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_DF:
+ output = "SURFACE_PAINTING_WARP_DF";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_E0:
+ output = "SURFACE_PAINTING_WARP_E0";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_E1:
+ output = "SURFACE_PAINTING_WARP_E1";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_E2:
+ output = "SURFACE_PAINTING_WARP_E2";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_E3:
+ output = "SURFACE_PAINTING_WARP_E3";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_E4:
+ output = "SURFACE_PAINTING_WARP_E4";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_E5:
+ output = "SURFACE_PAINTING_WARP_E5";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_E6:
+ output = "SURFACE_PAINTING_WARP_E6";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_E7:
+ output = "SURFACE_PAINTING_WARP_E7";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_E8:
+ output = "SURFACE_PAINTING_WARP_E8";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_E9:
+ output = "SURFACE_PAINTING_WARP_E9";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_EA:
+ output = "SURFACE_PAINTING_WARP_EA";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_EB:
+ output = "SURFACE_PAINTING_WARP_EB";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_EC:
+ output = "SURFACE_PAINTING_WARP_EC";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_ED:
+ output = "SURFACE_PAINTING_WARP_ED";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_EE:
+ output = "SURFACE_PAINTING_WARP_EE";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_EF:
+ output = "SURFACE_PAINTING_WARP_EF";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_F0:
+ output = "SURFACE_PAINTING_WARP_F0";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_F1:
+ output = "SURFACE_PAINTING_WARP_F1";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_F2:
+ output = "SURFACE_PAINTING_WARP_F2";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_F3:
+ output = "SURFACE_PAINTING_WARP_F3";
+ break;
+ case SurfaceType::SURFACE_TTC_PAINTING_1:
+ output = "SURFACE_TTC_PAINTING_1";
+ break;
+ case SurfaceType::SURFACE_TTC_PAINTING_2:
+ output = "SURFACE_TTC_PAINTING_2";
+ break;
+ case SurfaceType::SURFACE_TTC_PAINTING_3:
+ output = "SURFACE_TTC_PAINTING_3";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_F7:
+ output = "SURFACE_PAINTING_WARP_F7";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_F8:
+ output = "SURFACE_PAINTING_WARP_F8";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_F9:
+ output = "SURFACE_PAINTING_WARP_F9";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_FA:
+ output = "SURFACE_PAINTING_WARP_FA";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_FB:
+ output = "SURFACE_PAINTING_WARP_FB";
+ break;
+ case SurfaceType::SURFACE_PAINTING_WARP_FC:
+ output = "SURFACE_PAINTING_WARP_FC";
+ break;
+ case SurfaceType::SURFACE_WOBBLING_WARP:
+ output = "SURFACE_WOBBLING_WARP";
+ break;
+ case SurfaceType::SURFACE_TRAPDOOR:
+ output = "SURFACE_TRAPDOOR";
+ break;
+ default:
+ throw std::runtime_error("Unknown Surface Type");
+ }
+ return out << output;
+}
+
+#define SURFACE_IS_QUICKSAND(cmd) (cmd >= 0x21 && cmd < 0x28) // Doesn't include SURFACE_INSTANT_MOVING_QUICKSAND
+#define SURFACE_IS_NOT_HARD(cmd) (cmd != SurfaceType::SURFACE_HARD && \
+ !(cmd >= 0x35 && cmd <= 0x37))
+#define SURFACE_IS_PAINTING_WARP(cmd) (cmd >= 0xD3 && cmd < 0xFD)
+
+#define SURFACE_CLASS_DEFAULT 0x0000
+#define SURFACE_CLASS_VERY_SLIPPERY 0x0013
+#define SURFACE_CLASS_SLIPPERY 0x0014
+#define SURFACE_CLASS_NOT_SLIPPERY 0x0015
+
+#define SURFACE_FLAG_DYNAMIC (1 << 0)
+#define SURFACE_FLAG_NO_CAM_COLLISION (1 << 1)
+#define SURFACE_FLAG_X_PROJECTION (1 << 3)
+
+// These are effectively unique "surface" types like those defined higher
+// And they are used as collision commands to load certain functions
+#define TERRAIN_LOAD_VERTICES 0x0040 // Begins vertices list for collision triangles
+#define TERRAIN_LOAD_CONTINUE 0x0041 // Stop loading vertices but continues to load other collision commands
+#define TERRAIN_LOAD_END 0x0042 // End the collision list
+#define TERRAIN_LOAD_OBJECTS 0x0043 // Loads in certain objects for level start
+#define TERRAIN_LOAD_ENVIRONMENT 0x0044 // Loads water/HMC gas
+
+#define TERRAIN_LOAD_IS_SURFACE_TYPE_LOW(cmd) (cmd < 0x40)
+#define TERRAIN_LOAD_IS_SURFACE_TYPE_HIGH(cmd) (cmd >= 0x65)
+
+// Terrain types defined by the level script command terrain_type (cmd_31)
+#define TERRAIN_GRASS 0x0000
+#define TERRAIN_STONE 0x0001
+#define TERRAIN_SNOW 0x0002
+#define TERRAIN_SAND 0x0003
+#define TERRAIN_SPOOKY 0x0004
+#define TERRAIN_WATER 0x0005
+#define TERRAIN_SLIDE 0x0006
+#define TERRAIN_MASK 0x0007
+
+// These collision commands are unique "surface" types like those defined higher
+
+// Collision Data Routine Initiate
+#define COL_INIT() TERRAIN_LOAD_VERTICES
+
+// Collision Vertices Read Initiate
+#define COL_VERTEX_INIT(vtxNum) vtxNum
+
+// Collision Vertex
+#define COL_VERTEX(x, y, z) x, y, z
+
+// Collision Tris Initiate
+#define COL_TRI_INIT(surfType, triNum) surfType, triNum
+
+// Collision Tri
+#define COL_TRI(v1, v2, v3) v1, v2, v3
+
+// Collision Tri With Special Params
+#define COL_TRI_SPECIAL(v1, v2, v3, param) v1, v2, v3, param
+
+// Collision Tris Stop Loading
+#define COL_TRI_STOP() TERRAIN_LOAD_CONTINUE
+
+// End Collision Data
+#define COL_END() TERRAIN_LOAD_END
+
+// Special Object Initiate
+#define COL_SPECIAL_INIT(num) TERRAIN_LOAD_OBJECTS, num
+
+// Water Boxes Initiate
+#define COL_WATER_BOX_INIT(num) TERRAIN_LOAD_ENVIRONMENT, num
+
+// Water Box
+#define COL_WATER_BOX(id, x1, z1, x2, z2, y) id, x1, z1, x2, z2, y