diff options
| author | inspectredc <inspectredc@gmail.com> | 2024-04-02 14:55:56 +0100 |
|---|---|---|
| committer | Lywx <kiritodev01@gmail.com> | 2024-04-02 08:12:06 -0600 |
| commit | 513251ec9bb56aa26b86e9287034bef5087ae90b (patch) | |
| tree | ea4c2322ad501637dad760278e358d214a3f46b6 | |
| parent | c567193d17d7fb9b706d5ca2d000520def55f3f8 (diff) | |
sm64 collision factory
| -rw-r--r-- | src/Companion.cpp | 2 | ||||
| -rw-r--r-- | src/factories/sm64/CollisionFactory.cpp | 470 | ||||
| -rw-r--r-- | src/factories/sm64/CollisionFactory.h | 82 | ||||
| -rw-r--r-- | src/factories/sm64/collision/SpecialPresetNames.h | 385 | ||||
| -rw-r--r-- | src/factories/sm64/collision/SurfaceTerrains.h | 672 |
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 |
