From be4fc5cd77f649c0505ce5da2919036d7917f494 Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Fri, 20 Oct 2023 20:16:05 -0400 Subject: [PATCH 01/55] Fixes for new ZAPD (#8) * Fixes for new ZAPD * Vertex fix * remove MSVC Hack --------- Co-authored-by: Nicholas Estelami --- OTRExporter/CollisionExporter.cpp | 22 +- OTRExporter/CutsceneExporter.cpp | 287 ++++++++++++++------------- OTRExporter/DisplayListExporter.cpp | 19 +- OTRExporter/RoomExporter.cpp | 24 +-- OTRExporter/RoomExporter.h | 4 +- OTRExporter/SkeletonLimbExporter.cpp | 42 ++-- extract_assets.py | 2 +- 7 files changed, 201 insertions(+), 199 deletions(-) diff --git a/OTRExporter/CollisionExporter.cpp b/OTRExporter/CollisionExporter.cpp index 8b86122..9722cba 100644 --- a/OTRExporter/CollisionExporter.cpp +++ b/OTRExporter/CollisionExporter.cpp @@ -38,26 +38,26 @@ void OTRExporter_Collision::Save(ZResource* res, const fs::path& outPath, Binary writer->Write(col->polygons[i].dist); } - writer->Write((uint32_t)col->PolygonTypes.size()); + writer->Write((uint32_t)col->polygonTypes.size()); - for (uint16_t i = 0; i < col->PolygonTypes.size(); i++) { - writer->Write(col->PolygonTypes[i].data[1]); - writer->Write(col->PolygonTypes[i].data[0]); + for (uint16_t i = 0; i < col->polygonTypes.size(); i++) { + writer->Write(col->polygonTypes[i].data[1]); + writer->Write(col->polygonTypes[i].data[0]); } writer->Write((uint32_t)col->camData->entries.size()); for (auto entry : col->camData->entries) { - auto camPosDecl = col->parent->GetDeclarationRanged(Seg2Filespace(entry->cameraPosDataSeg, col->parent->baseAddress)); + auto camPosDecl = col->parent->GetDeclarationRanged(Seg2Filespace(entry.cameraPosDataSeg, col->parent->baseAddress)); int idx = 0; if (camPosDecl != nullptr) - idx = ((entry->cameraPosDataSeg & 0x00FFFFFF) - camPosDecl->address) / 6; + idx = ((entry.cameraPosDataSeg & 0x00FFFFFF) - camPosDecl->address) / 6; - writer->Write(entry->cameraSType); - writer->Write(entry->numData); + writer->Write(entry.cameraSType); + writer->Write(entry.numData); writer->Write((uint32_t)idx); } @@ -65,9 +65,9 @@ void OTRExporter_Collision::Save(ZResource* res, const fs::path& outPath, Binary for (auto entry : col->camData->cameraPositionData) { - writer->Write(entry->x); - writer->Write(entry->y); - writer->Write(entry->z); + writer->Write(entry.x); + writer->Write(entry.y); + writer->Write(entry.z); } writer->Write((uint32_t)col->waterBoxes.size()); diff --git a/OTRExporter/CutsceneExporter.cpp b/OTRExporter/CutsceneExporter.cpp index b4e2d53..f9d24a6 100644 --- a/OTRExporter/CutsceneExporter.cpp +++ b/OTRExporter/CutsceneExporter.cpp @@ -17,17 +17,17 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW { switch (cs->commands[i]->commandID) { - case (uint32_t)CutsceneCommands::SetCameraPos: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE_SPLINE: { - CutsceneCommandSetCameraPos* cmdCamPos = (CutsceneCommandSetCameraPos*)cs->commands[i]; + CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; writer->Write(CS_CMD_CAM_EYE); - writer->Write(CMD_HH(0x0001, ((CutsceneCommandSetCameraPos*)cs->commands[i])->startFrame)); + writer->Write(CMD_HH(0x0001, ((CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i])->startFrame)); writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); for (const auto& e : cs->commands[i]->entries) { - CutsceneCameraPoint* point = (CutsceneCameraPoint*)e; + CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); writer->Write(point->viewAngle); writer->Write(CMD_HH(point->posX, point->posY)); @@ -35,9 +35,9 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW } } break; - case (uint32_t)CutsceneCommands::SetCameraFocus: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE: { - CutsceneCommandSetCameraPos* cmdCamPos = (CutsceneCommandSetCameraPos*)cs->commands[i]; + CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; writer->Write(CS_CMD_CAM_AT); writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); @@ -45,7 +45,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW for (const auto& e : cs->commands[i]->entries) { - CutsceneCameraPoint* point = (CutsceneCameraPoint*)e; + CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); writer->Write(point->viewAngle); writer->Write(CMD_HH(point->posX, point->posY)); @@ -53,13 +53,13 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW } break; } - case (uint32_t)CutsceneCommands::Misc: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_MISC: { writer->Write(CS_CMD_MISC); writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); for (const auto& e : cs->commands[i]->entries) //All in OOT seem to only have 1 entry { - CutsceneSubCommandEntry_GenericCmd* cmd = (CutsceneSubCommandEntry_GenericCmd*)e; + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; writer->Write(CMD_HH(cmd->base, cmd->startFrame)); writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); writer->Write(CMD_W(cmd->unused1)); @@ -75,13 +75,13 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW } break; } - case (uint32_t)CutsceneCommands::SetLighting: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_LIGHT_SETTING: { writer->Write(CS_CMD_SET_LIGHTING); writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); for (const auto& e : cs->commands[i]->entries) { - CutsceneSubCommandEntry_GenericCmd* cmd = (CutsceneSubCommandEntry_GenericCmd*)e; + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; writer->Write(CMD_HH(cmd->base, cmd->startFrame)); writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); writer->Write(CMD_W(cmd->unused1)); @@ -97,17 +97,17 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW } break; } - case (uint32_t)CutsceneCommands::SetCameraPosLink: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE_SPLINE_REL_TO_PLAYER: { - CutsceneCommandSetCameraPos* cmdCamPos = (CutsceneCommandSetCameraPos*)cs->commands[i]; + CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; writer->Write(CS_CMD_CAM_EYE_REL_TO_PLAYER); - writer->Write(CMD_HH(0x0001, ((CutsceneCommandSetCameraPos*)cs->commands[i])->startFrame)); + writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); for (const auto& e : cs->commands[i]->entries) { - CutsceneCameraPoint* point = (CutsceneCameraPoint*)e; + CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); writer->Write(point->viewAngle); writer->Write(CMD_HH(point->posX, point->posY)); @@ -115,17 +115,17 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW } break; } - case (uint32_t)CutsceneCommands::SetCameraFocusLink: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE_REL_TO_PLAYER: { - CutsceneCommandSetCameraPos* cmdCamPos = (CutsceneCommandSetCameraPos*)cs->commands[i]; + CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; writer->Write(CS_CMD_CAM_AT_REL_TO_PLAYER); - writer->Write(CMD_HH(0x0001, ((CutsceneCommandSetCameraPos*)cs->commands[i])->startFrame)); + writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); for (const auto& e : cs->commands[i]->entries) { - CutsceneCameraPoint* point = (CutsceneCameraPoint*)e; + CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); writer->Write(point->viewAngle); writer->Write(CMD_HH(point->posX, point->posY)); @@ -134,27 +134,27 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW break; } - case (uint32_t)CutsceneCommands::Cmd07: // Not used in OOT + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE: // Not used in OOT break; - case (uint32_t)CutsceneCommands::Cmd08: // Not used in OOT + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT: // Not used in OOT break; - case (uint32_t)CutsceneCommands::Cmd09: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_RUMBLE_CONTROLLER: { writer->Write(CS_CMD_09); - writer->Write((uint32_t)CMD_W(((CutsceneCommand_Rumble*)cs->commands[i])->entries.size())); + writer->Write((uint32_t)CMD_W(((CutsceneOoTCommand_Rumble*)cs->commands[i])->entries.size())); for (const auto& e : cs->commands[i]->entries) { - CutsceneSubCommandEntry_Rumble* r = (CutsceneSubCommandEntry_Rumble*)e; + CutsceneOoTSubCommandEntry_Rumble* r = (CutsceneOoTSubCommandEntry_Rumble*)e; writer->Write(CMD_HH(r->base, r->startFrame)); - writer->Write(CMD_HBB(e->endFrame, r->unk_06, r->unk_07)); - writer->Write(CMD_BBH(r->unk_08, r->unk_09, r->unk_0A)); + writer->Write(CMD_HBB(e->endFrame, r->sourceStrength, r->duration)); + writer->Write(CMD_BBH(r->decreaseRate, r->unk_09, r->unk_0A)); } break; } - case 0x15://Both unused in OoT - case 0x1A://(uint32_t)CutsceneCommands::Unknown: + //case 0x15://Both unused in OoT + //case 0x1A://(uint32_t)CutsceneOoT_CommandType::Unknown: { #if 0 CutsceneCommandUnknown* cmdUnk = (CutsceneCommandUnknown*)cs->commands[i]; @@ -179,14 +179,14 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW #endif } break; - case (uint32_t)CutsceneCommands::Textbox: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TEXT: { writer->Write(CS_CMD_TEXTBOX); writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); for (const auto& e : cs->commands[i]->entries) { - CutsceneSubCommandEntry_TextBox* textBox = (CutsceneSubCommandEntry_TextBox*)e; + CutsceneOoTSubCommandEntry_Text* textBox = (CutsceneOoTSubCommandEntry_Text*)e; if (textBox->base == 0xFFFF) // CS_TEXT_NONE { writer->Write(CMD_HH(0xFFFF, textBox->startFrame)); @@ -202,110 +202,110 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW } break; } - case 10: //ActorAction0 - case (uint32_t)CutsceneCommands::SetActorAction1: - case 17: - case 18: - case 23: - case 34: - case 39: - case 46: - case 76: - case 85: - case 93: - case 105: - case 107: - case 110: - case 119: - case 123: - case 138: - case 139: - case 144: - case (uint32_t)CutsceneCommands::SetActorAction2: - case 16: - case 24: - case 35: - case 40: - case 48: - case 64: - case 68: - case 70: - case 78: - case 80: - case 94: - case 116: - case 118: - case 120: - case 125: - case 131: - case 141: - case (uint32_t)CutsceneCommands::SetActorAction3: - case 36: - case 41: - case 50: - case 67: - case 69: - case 72: - case 74: - case 81: - case 106: - case 117: - case 121: - case 126: - case 132: - case (uint32_t)CutsceneCommands::SetActorAction4: - case 37: - case 42: - case 51: - case 53: - case 63: - case 65: - case 66: - case 75: - case 82: - case 108: - case 127: - case 133: - case (uint32_t)CutsceneCommands::SetActorAction5: - case 38: - case 43: - case 47: - case 54: - case 79: - case 83: - case 128: - case 135: - case (uint32_t)CutsceneCommands::SetActorAction6: - case 55: - case 77: - case 84: - case 90: - case 129: - case 136: - case (uint32_t)CutsceneCommands::SetActorAction7: - case 52: - case 57: - case 58: - case 88: - case 115: - case 130: - case 137: - case (uint32_t)CutsceneCommands::SetActorAction8: - case 60: - case 89: - case 111: - case 114: - case 134: - case 142: - case (uint32_t)CutsceneCommands::SetActorAction9: - case (uint32_t)CutsceneCommands::SetActorAction10: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_PLAYER_CUE: //ActorAction0 + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_9: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_10: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_11: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_12: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_13: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_14: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_15: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_16: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_17: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_9: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_10: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_11: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_12: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_13: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_14: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_15: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_16: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_17: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_9: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_10: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_11: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_12: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_13: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_9: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_10: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_11: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_12: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_8_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_9_0: { - writer->Write((uint32_t)(CutsceneCommands)cs->commands[i]->commandID); + writer->Write((uint32_t)cs->commands[i]->commandID); writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); for (const auto& e : cs->commands[i]->entries) { - CutsceneSubCommandEntry_ActorAction* actorAct = (CutsceneSubCommandEntry_ActorAction*)e; + CutsceneOoTSubCommandEntry_ActorCue* actorAct = (CutsceneOoTSubCommandEntry_ActorCue*)e; writer->Write(CMD_HH(actorAct->base, actorAct->startFrame)); writer->Write(CMD_HH(actorAct->endFrame, actorAct->rotX)); writer->Write(CMD_HH(actorAct->rotY, actorAct->rotZ)); @@ -322,24 +322,24 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW break; } - case (uint32_t)CutsceneCommands::SetSceneTransFX: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TRANSITION: { - CutsceneCommandSceneTransFX* cmdTFX = (CutsceneCommandSceneTransFX*)cs->commands[i]; + CutsceneOoTCommand_Transition* cmdTFX = (CutsceneOoTCommand_Transition*)cs->commands[i]; writer->Write(CS_CMD_SCENE_TRANS_FX); writer->Write((uint32_t)1); - writer->Write(CMD_HH((((CutsceneCommandSceneTransFX*)cs->commands[i])->base), ((CutsceneCommandSceneTransFX*)cs->commands[i])->startFrame)); - writer->Write(CMD_HH((((CutsceneCommandSceneTransFX*)cs->commands[i])->endFrame), ((CutsceneCommandSceneTransFX*)cs->commands[i])->endFrame)); + writer->Write(CMD_HH((cmdTFX->base), cmdTFX->startFrame)); + writer->Write(CMD_HH((cmdTFX->endFrame), cmdTFX->endFrame)); break; } - case (uint32_t)CutsceneCommands::PlayBGM: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_START_SEQ: { writer->Write(CS_CMD_PLAYBGM); writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); for (const auto& e : cs->commands[i]->entries) { - CutsceneSubCommandEntry_GenericCmd* cmd = (CutsceneSubCommandEntry_GenericCmd*)e; + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; writer->Write(CMD_HH(cmd->base, cmd->startFrame)); writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); writer->Write(CMD_W(cmd->unused1)); @@ -355,14 +355,14 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW } break; } - case (uint32_t)CutsceneCommands::StopBGM: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_STOP_SEQ: { writer->Write(CS_CMD_STOPBGM); writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); for (const auto& e : cs->commands[i]->entries) { - CutsceneSubCommandEntry_GenericCmd* cmd = (CutsceneSubCommandEntry_GenericCmd*)e; + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; writer->Write(CMD_HH(cmd->base, cmd->startFrame)); writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); writer->Write(CMD_W(cmd->unused1)); @@ -378,14 +378,14 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW } break; } - case (uint32_t)CutsceneCommands::FadeBGM: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_FADE_OUT_SEQ: { writer->Write(CS_CMD_FADEBGM); writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); for (const auto& e : cs->commands[i]->entries) { - CutsceneSubCommandEntry_GenericCmd* cmd = (CutsceneSubCommandEntry_GenericCmd*)e; + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; writer->Write(CMD_HH(cmd->base, cmd->startFrame)); writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); writer->Write(CMD_W(cmd->unused1)); @@ -401,7 +401,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW } break; } - case (uint32_t)CutsceneCommands::SetTime: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TIME: { writer->Write(CS_CMD_SETTIME); writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); @@ -411,13 +411,14 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW CutsceneSubCommandEntry_SetTime* t = (CutsceneSubCommandEntry_SetTime*)e; writer->Write(CMD_HH(t->base, t->startFrame)); writer->Write(CMD_HBB(t->endFrame, t->hour, t->minute)); - writer->Write((uint32_t)CMD_W(t->unk_08)); + writer->Write((uint32_t)0); + //writer->Write((uint32_t)CMD_W(t->unk_08)); } break; } - case (uint32_t)CutsceneCommands::Terminator: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_DESTINATION: { - CutsceneCommand_Terminator* t = (CutsceneCommand_Terminator*)cs->commands[i]; + CutsceneOoTCommand_Destination* t = (CutsceneOoTCommand_Destination*)cs->commands[i]; writer->Write(CS_CMD_TERMINATOR); writer->Write((uint32_t)1); writer->Write(CMD_HH(t->base, t->startFrame)); diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index f35464a..6927f6d 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -14,6 +14,7 @@ #include #include "VersionInfo.h" + #define GFX_SIZE 8 #define gsDPSetCombineLERP_NoMacros(a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, \ @@ -58,7 +59,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina // DEBUG: Write in a marker Declaration* dbgDecl = dList->parent->GetDeclaration(dList->GetRawDataIndex()); - std::string dbgName = StringHelper::Sprintf("%s/%s", GetParentFolderName(res).c_str(), dbgDecl->varName.c_str()); + std::string dbgName = StringHelper::Sprintf("%s/%s", GetParentFolderName(res).c_str(), dbgDecl->declName.c_str()); uint64_t hash = CRC64(dbgName.c_str()); writer->Write((uint32_t)(G_MARKER << 24)); writer->Write((uint32_t)0xBEEFBEEF); @@ -230,7 +231,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina if (mtxDecl != nullptr) { - std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), mtxDecl->varName.c_str()); + std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), mtxDecl->declName.c_str()); uint64_t hash = CRC64(vName.c_str()); @@ -334,7 +335,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina if (dListDecl != nullptr) { - std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str()); + std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), dListDecl->declName.c_str()); uint64_t hash = CRC64(vName.c_str()); @@ -355,7 +356,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina if (dListDecl2 != nullptr) { //std::string fName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), dListDecl2->varName.c_str()); - std::string fName = OTRExporter_DisplayList::GetPathToRes(res, dListDecl2->varName.c_str()); + std::string fName = OTRExporter_DisplayList::GetPathToRes(res, dListDecl2->declName.c_str()); if (files.find(fName) == files.end() && !DiskFile::Exists("Extract/" + fName)) { @@ -420,7 +421,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina if (dListDecl != nullptr) { - std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str()); + std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), dListDecl->declName.c_str()); uint64_t hash = CRC64(vName.c_str()); @@ -441,7 +442,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina if (dListDecl2 != nullptr) { //std::string fName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), dListDecl2->varName.c_str()); - std::string fName = OTRExporter_DisplayList::GetPathToRes(res, dListDecl2->varName.c_str()); + std::string fName = OTRExporter_DisplayList::GetPathToRes(res, dListDecl2->declName.c_str()); if (files.find(fName) == files.end() && !DiskFile::Exists("Extract/" + fName)) { @@ -747,7 +748,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t aa = (data & 0x000000FF00000000ULL) >> 32; int32_t nn = (data & 0x000FF00000000000ULL) >> 44; - if (vtxDecl != nullptr && vtxDecl->varType != "Gfx") + if (vtxDecl != nullptr && vtxDecl->declName != "Gfx") { uint32_t diff = segOffset - vtxDecl->address; @@ -761,7 +762,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina writer->Write(word0); writer->Write(word1); - std::string fName = OTRExporter_DisplayList::GetPathToRes(res, vtxDecl->varName); + std::string fName = OTRExporter_DisplayList::GetPathToRes(res, vtxDecl->declName); uint64_t hash = CRC64(fName.c_str()); @@ -776,7 +777,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int arrCnt = 0; - auto split = StringHelper::Split(vtxDecl->text, "\n"); + auto split = StringHelper::Split(vtxDecl->declBody, "\n"); for (size_t i = 0; i < split.size(); i++) { diff --git a/OTRExporter/RoomExporter.cpp b/OTRExporter/RoomExporter.cpp index 1928ab0..bdee958 100644 --- a/OTRExporter/RoomExporter.cpp +++ b/OTRExporter/RoomExporter.cpp @@ -187,7 +187,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite if (cmdMesh->meshHeaderType == 0 || cmdMesh->meshHeaderType == 2) { - PolygonType2* poly = (PolygonType2*)cmdMesh->polyType.get(); + RoomShapeCullable* poly = (RoomShapeCullable*)cmdMesh->polyType.get(); writer->Write(poly->num); @@ -200,17 +200,17 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite writer->Write(poly->format); - auto test = (PolygonDlist*)&poly->polyDLists[0]; + auto test = (RoomShapeDListsEntry*)&poly->polyDLists[0]; Declaration* dListDeclOpa = poly->parent->GetDeclaration(GETSEGOFFSET(test->opa)); Declaration* dListDeclXlu = poly->parent->GetDeclaration(GETSEGOFFSET(test->xlu)); if (test->opa != 0) - writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str())); + writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->declName.c_str())); else writer->Write(""); if (test->xlu != 0) - writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclXlu->varName.c_str())); + writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclXlu->declName.c_str())); else writer->Write(""); @@ -225,7 +225,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite Declaration* bgDecl = poly->parent->GetDeclarationRanged(GETSEGOFFSET(poly->multiList[i].source)); - writer->Write(OTRExporter_DisplayList::GetPathToRes(poly->multiList[i].sourceBackground, bgDecl->varName)); + writer->Write(OTRExporter_DisplayList::GetPathToRes(poly->multiList[i].sourceBackground, bgDecl->declName)); writer->Write(poly->multiList[i].unk_0C); writer->Write(poly->multiList[i].tlut); @@ -246,7 +246,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite Declaration* bgDecl = poly->parent->GetDeclarationRanged(GETSEGOFFSET(poly->single.source)); - writer->Write(OTRExporter_DisplayList::GetPathToRes(poly->single.sourceBackground, bgDecl->varName)); + writer->Write(OTRExporter_DisplayList::GetPathToRes(poly->single.sourceBackground, bgDecl->declName)); writer->Write(poly->single.unk_0C); writer->Write(poly->single.tlut); @@ -349,7 +349,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite SetCollisionHeader* cmdCollHeader = (SetCollisionHeader*)cmd; Declaration* colHeaderDecl = room->parent->GetDeclaration(cmdCollHeader->segmentOffset); - std::string path = OTRExporter_DisplayList::GetPathToRes(room, colHeaderDecl->varName); + std::string path = OTRExporter_DisplayList::GetPathToRes(room, colHeaderDecl->declName); writer->Write(path); } break; @@ -359,7 +359,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite writer->Write((uint32_t)cmdEntrance->entrances.size()); - for (EntranceEntry entry : cmdEntrance->entrances) + for (Spawn entry : cmdEntrance->entrances) { writer->Write((uint8_t)entry.startPositionIndex); writer->Write((uint8_t)entry.roomToLoad); @@ -464,7 +464,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite { Declaration* decl = room->parent->GetDeclaration(GETSEGOFFSET(cmdSetPathways->pathwayList.pathways[i].listSegmentAddress)); //std::string path = StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), decl->varName.c_str()); - std::string path = OTRExporter_DisplayList::GetPathToRes(room, decl->varName); + std::string path = OTRExporter_DisplayList::GetPathToRes(room, decl->declName); writer->Write(path); MemoryStream* pathStream = new MemoryStream(); @@ -486,7 +486,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite } } -void OTRExporter_Room::WritePolyDList(BinaryWriter* writer, ZRoom* room, PolygonDlist* dlist) +void OTRExporter_Room::WritePolyDList(BinaryWriter* writer, ZRoom* room, RoomShapeDListsEntry* dlist) { writer->Write(dlist->polyType); @@ -504,7 +504,7 @@ void OTRExporter_Room::WritePolyDList(BinaryWriter* writer, ZRoom* room, Polygon if (dlist->opaDList != nullptr) { auto opaDecl = room->parent->GetDeclaration(GETSEGOFFSET(dlist->opaDList->GetRawDataIndex())); - writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), opaDecl->varName.c_str())); + writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), opaDecl->declName.c_str())); } else writer->Write(""); @@ -512,7 +512,7 @@ void OTRExporter_Room::WritePolyDList(BinaryWriter* writer, ZRoom* room, Polygon if (dlist->xluDList != nullptr) { auto xluDecl = room->parent->GetDeclaration(GETSEGOFFSET(dlist->xluDList->GetRawDataIndex())); - writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), xluDecl->varName.c_str())); + writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), xluDecl->declName.c_str())); } else writer->Write(""); diff --git a/OTRExporter/RoomExporter.h b/OTRExporter/RoomExporter.h index f748658..bb4471a 100644 --- a/OTRExporter/RoomExporter.h +++ b/OTRExporter/RoomExporter.h @@ -4,11 +4,11 @@ #include "Exporter.h" #include "ZRoom/ZRoom.h" -class PolygonDlist; +class RoomShapeDListsEntry; class OTRExporter_Room : public OTRExporter { public: - void WritePolyDList(BinaryWriter* writer, ZRoom* room, PolygonDlist* dlist); + void WritePolyDList(BinaryWriter* writer, ZRoom* room, RoomShapeDListsEntry* dlist); virtual void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override; }; \ No newline at end of file diff --git a/OTRExporter/SkeletonLimbExporter.cpp b/OTRExporter/SkeletonLimbExporter.cpp index d95c84d..9534d8f 100644 --- a/OTRExporter/SkeletonLimbExporter.cpp +++ b/OTRExporter/SkeletonLimbExporter.cpp @@ -12,12 +12,12 @@ void OTRExporter_SkeletonLimb::Save(ZResource* res, const fs::path& outPath, Bin writer->Write((uint8_t)limb->type); writer->Write((uint8_t)limb->skinSegmentType); - if (limb->skinSegmentType == ZLimbSkinType::SkinType_DList && limb->type == ZLimbType::Skin) + if (limb->skinSegmentType == ZLimbSkinType::SkinType_Normal && limb->type == ZLimbType::Skin) { auto childDecl = limb->parent->GetDeclaration(GETSEGOFFSET(limb->skinSegment)); if (childDecl != nullptr) - writer->Write(OTRExporter_DisplayList::GetPathToRes(limb, childDecl->varName)); + writer->Write(OTRExporter_DisplayList::GetPathToRes(limb, childDecl->declName)); else writer->Write(""); } @@ -26,45 +26,45 @@ void OTRExporter_SkeletonLimb::Save(ZResource* res, const fs::path& outPath, Bin writer->Write(""); } - writer->Write((uint16_t)limb->segmentStruct.unk_0); - writer->Write((uint32_t)limb->segmentStruct.unk_4_arr.size()); + writer->Write((uint16_t)limb->segmentStruct.totalVtxCount); + writer->Write((uint32_t)limb->segmentStruct.limbModifications_arr.size()); - for (auto item : limb->segmentStruct.unk_4_arr) + for (auto item : limb->segmentStruct.limbModifications_arr) { writer->Write(item.unk_4); - writer->Write((uint32_t)item.unk_8_arr.size()); + writer->Write((uint32_t)item.skinVertices_arr.size()); - for (auto item2 : item.unk_8_arr) + for (auto item2 : item.skinVertices_arr) { - writer->Write(item2.unk_0); - writer->Write(item2.unk_2); - writer->Write(item2.unk_4); - writer->Write(item2.unk_6); - writer->Write(item2.unk_7); - writer->Write(item2.unk_8); - writer->Write(item2.unk_9); + writer->Write(item2.index); + writer->Write(item2.s); + writer->Write(item2.t); + writer->Write(item2.normX); + writer->Write(item2.normY); + writer->Write(item2.normZ); + writer->Write(item2.alpha); } - writer->Write((uint32_t)item.unk_C_arr.size()); + writer->Write((uint32_t)item.limbTransformations_arr.size()); - for (auto item2 : item.unk_C_arr) + for (auto item2 : item.limbTransformations_arr) { - writer->Write(item2.unk_0); + writer->Write(item2.limbIndex); writer->Write(item2.x); writer->Write(item2.y); writer->Write(item2.z); - writer->Write(item2.unk_8); + writer->Write(item2.scale); } } - if (limb->segmentStruct.unk_8 != 0) + if (limb->segmentStruct.dlist != SEGMENTED_NULL) { - auto skinGfxDecl = limb->parent->GetDeclaration(GETSEGOFFSET(limb->segmentStruct.unk_8)); + auto skinGfxDecl = limb->parent->GetDeclaration(GETSEGOFFSET(limb->segmentStruct.dlist)); if (skinGfxDecl != nullptr) { - writer->Write(OTRExporter_DisplayList::GetPathToRes(limb, skinGfxDecl->varName)); + writer->Write(OTRExporter_DisplayList::GetPathToRes(limb, skinGfxDecl->declName)); } else { diff --git a/extract_assets.py b/extract_assets.py index 63b64a2..aa84ae5 100755 --- a/extract_assets.py +++ b/extract_assets.py @@ -12,7 +12,7 @@ def BuildOTR(xmlPath, rom, zapd_exe=None, genHeaders=None, customAssetsPath=None if not zapd_exe: zapd_exe = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out" - exec_cmd = [zapd_exe, "ed", "-i", xmlPath, "-b", rom, "-fl", "CFG/filelists", + exec_cmd = [zapd_exe, "ed", "-eh", "-i", xmlPath, "-b", rom, "-fl", "CFG/filelists", "-o", "placeholder", "-osf", "placeholder", "-rconf", "CFG/Config.xml"] # generate headers, but not otrs by excluding the otr exporter From 0819df4515a8fe3e4bc76b18821b3f6697f712cb Mon Sep 17 00:00:00 2001 From: Louis <35883445+louist103@users.noreply.github.com> Date: Sun, 22 Oct 2023 11:36:31 -0400 Subject: [PATCH 02/55] MM cutscene exporter --- CFG/ActorList_MM.txt | 691 +++++++++++++ CFG/Config.xml | 10 +- CFG/ObjectList_MM.txt | 643 +++++++++++++ CFG/SymbolMap_MM.txt | 1 + CFG/filelists/mm.txt | 1552 ++++++++++++++++++++++++++++++ OTRExporter/CMakeLists.txt | 10 +- OTRExporter/CutsceneExporter.cpp | 1109 ++++++++++++--------- OTRExporter/CutsceneExporter.h | 2 + OTRExporter/Main.cpp | 2 +- OTRExporter/RoomExporter.cpp | 47 +- OTRExporter/RoomExporter.h | 3 +- extract_assets.py | 16 +- 12 files changed, 3622 insertions(+), 464 deletions(-) create mode 100644 CFG/ActorList_MM.txt create mode 100644 CFG/ObjectList_MM.txt create mode 100644 CFG/SymbolMap_MM.txt create mode 100644 CFG/filelists/mm.txt diff --git a/CFG/ActorList_MM.txt b/CFG/ActorList_MM.txt new file mode 100644 index 0000000..f899e9a --- /dev/null +++ b/CFG/ActorList_MM.txt @@ -0,0 +1,691 @@ +ACTOR_PLAYER +ACTOR_EN_TEST +ACTOR_EN_GIRLA +ACTOR_EN_PART +ACTOR_EN_LIGHT +ACTOR_EN_DOOR +ACTOR_EN_BOX +ACTOR_EN_PAMETFROG +ACTOR_EN_OKUTA +ACTOR_EN_BOM +ACTOR_EN_WALLMAS +ACTOR_EN_DODONGO +ACTOR_EN_FIREFLY +ACTOR_EN_HORSE +ACTOR_EN_ITEM00 +ACTOR_EN_ARROW +ACTOR_EN_ELF +ACTOR_EN_NIW +ACTOR_EN_TITE +ACTOR_UNSET_13 +ACTOR_EN_PEEHAT +ACTOR_EN_BUTTE +ACTOR_EN_INSECT +ACTOR_EN_FISH +ACTOR_EN_HOLL +ACTOR_EN_DINOFOS +ACTOR_EN_HATA +ACTOR_EN_ZL1 +ACTOR_EN_VIEWER +ACTOR_EN_BUBBLE +ACTOR_DOOR_SHUTTER +ACTOR_UNSET_1F +ACTOR_EN_BOOM +ACTOR_EN_TORCH2 +ACTOR_EN_MINIFROG +ACTOR_UNSET_23 +ACTOR_EN_ST +ACTOR_UNSET_25 +ACTOR_EN_A_OBJ +ACTOR_OBJ_WTURN +ACTOR_EN_RIVER_SOUND +ACTOR_UNSET_29 +ACTOR_EN_OSSAN +ACTOR_UNSET_2B +ACTOR_UNSET_2C +ACTOR_EN_FAMOS +ACTOR_UNSET_2E +ACTOR_EN_BOMBF +ACTOR_UNSET_30 +ACTOR_UNSET_31 +ACTOR_EN_AM +ACTOR_EN_DEKUBABA +ACTOR_EN_M_FIRE1 +ACTOR_EN_M_THUNDER +ACTOR_BG_BREAKWALL +ACTOR_UNSET_37 +ACTOR_DOOR_WARP1 +ACTOR_OBJ_SYOKUDAI +ACTOR_ITEM_B_HEART +ACTOR_EN_DEKUNUTS +ACTOR_EN_BBFALL +ACTOR_ARMS_HOOK +ACTOR_EN_BB +ACTOR_BG_KEIKOKU_SPR +ACTOR_UNSET_40 +ACTOR_EN_WOOD02 +ACTOR_UNSET_42 +ACTOR_EN_DEATH +ACTOR_EN_MINIDEATH +ACTOR_UNSET_45 +ACTOR_UNSET_46 +ACTOR_EN_VM +ACTOR_DEMO_EFFECT +ACTOR_DEMO_KANKYO +ACTOR_EN_FLOORMAS +ACTOR_UNSET_4B +ACTOR_EN_RD +ACTOR_BG_F40_FLIFT +ACTOR_UNSET_4E +ACTOR_OBJ_MURE +ACTOR_EN_SW +ACTOR_OBJECT_KANKYO +ACTOR_UNSET_52 +ACTOR_UNSET_53 +ACTOR_EN_HORSE_LINK_CHILD +ACTOR_DOOR_ANA +ACTOR_UNSET_56 +ACTOR_UNSET_57 +ACTOR_UNSET_58 +ACTOR_UNSET_59 +ACTOR_UNSET_5A +ACTOR_EN_ENCOUNT1 +ACTOR_DEMO_TRE_LGT +ACTOR_UNSET_5D +ACTOR_UNSET_5E +ACTOR_EN_ENCOUNT2 +ACTOR_EN_FIRE_ROCK +ACTOR_BG_CTOWER_ROT +ACTOR_MIR_RAY +ACTOR_UNSET_63 +ACTOR_EN_SB +ACTOR_EN_BIGSLIME +ACTOR_EN_KAREBABA +ACTOR_EN_IN +ACTOR_UNSET_68 +ACTOR_EN_RU +ACTOR_EN_BOM_CHU +ACTOR_EN_HORSE_GAME_CHECK +ACTOR_EN_RR +ACTOR_UNSET_6D +ACTOR_UNSET_6E +ACTOR_UNSET_6F +ACTOR_UNSET_70 +ACTOR_UNSET_71 +ACTOR_UNSET_72 +ACTOR_EN_FR +ACTOR_UNSET_74 +ACTOR_UNSET_75 +ACTOR_UNSET_76 +ACTOR_UNSET_77 +ACTOR_UNSET_78 +ACTOR_UNSET_79 +ACTOR_OBJ_OSHIHIKI +ACTOR_EFF_DUST +ACTOR_BG_UMAJUMP +ACTOR_ARROW_FIRE +ACTOR_ARROW_ICE +ACTOR_ARROW_LIGHT +ACTOR_ITEM_ETCETERA +ACTOR_OBJ_KIBAKO +ACTOR_OBJ_TSUBO +ACTOR_UNSET_83 +ACTOR_EN_IK +ACTOR_UNSET_85 +ACTOR_UNSET_86 +ACTOR_UNSET_87 +ACTOR_UNSET_88 +ACTOR_DEMO_SHD +ACTOR_EN_DNS +ACTOR_ELF_MSG +ACTOR_EN_HONOTRAP +ACTOR_EN_TUBO_TRAP +ACTOR_OBJ_ICE_POLY +ACTOR_EN_FZ +ACTOR_EN_KUSA +ACTOR_OBJ_BEAN +ACTOR_OBJ_BOMBIWA +ACTOR_OBJ_SWITCH +ACTOR_UNSET_94 +ACTOR_OBJ_LIFT +ACTOR_OBJ_HSBLOCK +ACTOR_EN_OKARINA_TAG +ACTOR_UNSET_98 +ACTOR_EN_GOROIWA +ACTOR_UNSET_9A +ACTOR_UNSET_9B +ACTOR_EN_DAIKU +ACTOR_EN_NWC +ACTOR_ITEM_INBOX +ACTOR_EN_GE1 +ACTOR_OBJ_BLOCKSTOP +ACTOR_EN_SDA +ACTOR_EN_CLEAR_TAG +ACTOR_UNSET_A3 +ACTOR_EN_GM +ACTOR_EN_MS +ACTOR_EN_HS +ACTOR_BG_INGATE +ACTOR_EN_KANBAN +ACTOR_UNSET_A9 +ACTOR_EN_ATTACK_NIW +ACTOR_UNSET_AB +ACTOR_UNSET_AC +ACTOR_UNSET_AD +ACTOR_EN_MK +ACTOR_EN_OWL +ACTOR_EN_ISHI +ACTOR_OBJ_HANA +ACTOR_OBJ_LIGHTSWITCH +ACTOR_OBJ_MURE2 +ACTOR_UNSET_B4 +ACTOR_EN_FU +ACTOR_UNSET_B6 +ACTOR_UNSET_B7 +ACTOR_EN_STREAM +ACTOR_EN_MM +ACTOR_UNSET_BA +ACTOR_UNSET_BB +ACTOR_EN_WEATHER_TAG +ACTOR_EN_ANI +ACTOR_UNSET_BE +ACTOR_EN_JS +ACTOR_UNSET_C0 +ACTOR_UNSET_C1 +ACTOR_UNSET_C2 +ACTOR_UNSET_C3 +ACTOR_EN_OKARINA_EFFECT +ACTOR_EN_MAG +ACTOR_ELF_MSG2 +ACTOR_BG_F40_SWLIFT +ACTOR_UNSET_C8 +ACTOR_UNSET_C9 +ACTOR_EN_KAKASI +ACTOR_OBJ_MAKEOSHIHIKI +ACTOR_OCEFF_SPOT +ACTOR_UNSET_CD +ACTOR_EN_TORCH +ACTOR_UNSET_CF +ACTOR_SHOT_SUN +ACTOR_UNSET_D1 +ACTOR_UNSET_D2 +ACTOR_OBJ_ROOMTIMER +ACTOR_EN_SSH +ACTOR_UNSET_D5 +ACTOR_OCEFF_WIPE +ACTOR_OCEFF_STORM +ACTOR_OBJ_DEMO +ACTOR_EN_MINISLIME +ACTOR_EN_NUTSBALL +ACTOR_UNSET_DB +ACTOR_UNSET_DC +ACTOR_UNSET_DD +ACTOR_UNSET_DE +ACTOR_OCEFF_WIPE2 +ACTOR_OCEFF_WIPE3 +ACTOR_UNSET_E1 +ACTOR_EN_DG +ACTOR_EN_SI +ACTOR_OBJ_COMB +ACTOR_OBJ_KIBAKO2 +ACTOR_UNSET_E6 +ACTOR_EN_HS2 +ACTOR_OBJ_MURE3 +ACTOR_EN_TG +ACTOR_UNSET_EA +ACTOR_UNSET_EB +ACTOR_EN_WF +ACTOR_EN_SKB +ACTOR_UNSET_EE +ACTOR_EN_GS +ACTOR_OBJ_SOUND +ACTOR_EN_CROW +ACTOR_UNSET_F2 +ACTOR_EN_COW +ACTOR_UNSET_F4 +ACTOR_UNSET_F5 +ACTOR_OCEFF_WIPE4 +ACTOR_UNSET_F7 +ACTOR_EN_ZO +ACTOR_OBJ_MAKEKINSUTA +ACTOR_EN_GE3 +ACTOR_UNSET_FB +ACTOR_OBJ_HAMISHI +ACTOR_EN_ZL4 +ACTOR_EN_MM2 +ACTOR_UNSET_FF +ACTOR_DOOR_SPIRAL +ACTOR_UNSET_101 +ACTOR_OBJ_PZLBLOCK +ACTOR_OBJ_TOGE +ACTOR_UNSET_104 +ACTOR_OBJ_ARMOS +ACTOR_OBJ_BOYO +ACTOR_UNSET_107 +ACTOR_UNSET_108 +ACTOR_EN_GRASSHOPPER +ACTOR_UNSET_10A +ACTOR_OBJ_GRASS +ACTOR_OBJ_GRASS_CARRY +ACTOR_OBJ_GRASS_UNIT +ACTOR_UNSET_10E +ACTOR_UNSET_10F +ACTOR_BG_FIRE_WALL +ACTOR_EN_BU +ACTOR_EN_ENCOUNT3 +ACTOR_EN_JSO +ACTOR_OBJ_CHIKUWA +ACTOR_EN_KNIGHT +ACTOR_EN_WARP_TAG +ACTOR_EN_AOB_01 +ACTOR_EN_BOJ_01 +ACTOR_EN_BOJ_02 +ACTOR_EN_BOJ_03 +ACTOR_EN_ENCOUNT4 +ACTOR_EN_BOM_BOWL_MAN +ACTOR_EN_SYATEKI_MAN +ACTOR_UNSET_11E +ACTOR_BG_ICICLE +ACTOR_EN_SYATEKI_CROW +ACTOR_EN_BOJ_04 +ACTOR_EN_CNE_01 +ACTOR_EN_BBA_01 +ACTOR_EN_BJI_01 +ACTOR_BG_SPDWEB +ACTOR_UNSET_126 +ACTOR_UNSET_127 +ACTOR_EN_MT_TAG +ACTOR_BOSS_01 +ACTOR_BOSS_02 +ACTOR_BOSS_03 +ACTOR_BOSS_04 +ACTOR_BOSS_05 +ACTOR_BOSS_06 +ACTOR_BOSS_07 +ACTOR_BG_DY_YOSEIZO +ACTOR_UNSET_131 +ACTOR_EN_BOJ_05 +ACTOR_UNSET_133 +ACTOR_UNSET_134 +ACTOR_EN_SOB1 +ACTOR_UNSET_136 +ACTOR_UNSET_137 +ACTOR_EN_GO +ACTOR_UNSET_139 +ACTOR_EN_RAF +ACTOR_OBJ_FUNEN +ACTOR_OBJ_RAILLIFT +ACTOR_BG_NUMA_HANA +ACTOR_OBJ_FLOWERPOT +ACTOR_OBJ_SPINYROLL +ACTOR_DM_HINA +ACTOR_EN_SYATEKI_WF +ACTOR_OBJ_SKATEBLOCK +ACTOR_OBJ_ICEBLOCK +ACTOR_EN_BIGPAMET +ACTOR_EN_SYATEKI_DEKUNUTS +ACTOR_ELF_MSG3 +ACTOR_EN_FG +ACTOR_DM_RAVINE +ACTOR_DM_SA +ACTOR_EN_SLIME +ACTOR_EN_PR +ACTOR_OBJ_TOUDAI +ACTOR_OBJ_ENTOTU +ACTOR_OBJ_BELL +ACTOR_EN_SYATEKI_OKUTA +ACTOR_UNSET_150 +ACTOR_OBJ_SHUTTER +ACTOR_DM_ZL +ACTOR_EN_ELFGRP +ACTOR_DM_TSG +ACTOR_EN_BAGUO +ACTOR_OBJ_VSPINYROLL +ACTOR_OBJ_SMORK +ACTOR_EN_TEST2 +ACTOR_EN_TEST3 +ACTOR_EN_TEST4 +ACTOR_EN_BAT +ACTOR_EN_SEKIHI +ACTOR_EN_WIZ +ACTOR_EN_WIZ_BROCK +ACTOR_EN_WIZ_FIRE +ACTOR_EFF_CHANGE +ACTOR_DM_STATUE +ACTOR_OBJ_FIRESHIELD +ACTOR_BG_LADDER +ACTOR_EN_MKK +ACTOR_DEMO_GETITEM +ACTOR_UNSET_166 +ACTOR_EN_DNB +ACTOR_EN_DNH +ACTOR_EN_DNK +ACTOR_EN_DNQ +ACTOR_UNSET_16B +ACTOR_BG_KEIKOKU_SAKU +ACTOR_OBJ_HUGEBOMBIWA +ACTOR_EN_FIREFLY2 +ACTOR_EN_RAT +ACTOR_EN_WATER_EFFECT +ACTOR_EN_KUSA2 +ACTOR_BG_SPOUT_FIRE +ACTOR_UNSET_173 +ACTOR_BG_DBLUE_MOVEBG +ACTOR_EN_DY_EXTRA +ACTOR_EN_BAL +ACTOR_EN_GINKO_MAN +ACTOR_EN_WARP_UZU +ACTOR_OBJ_DRIFTICE +ACTOR_EN_LOOK_NUTS +ACTOR_EN_MUSHI2 +ACTOR_EN_FALL +ACTOR_EN_MM3 +ACTOR_BG_CRACE_MOVEBG +ACTOR_EN_DNO +ACTOR_EN_PR2 +ACTOR_EN_PRZ +ACTOR_EN_JSO2 +ACTOR_OBJ_ETCETERA +ACTOR_EN_EGOL +ACTOR_OBJ_MINE +ACTOR_OBJ_PURIFY +ACTOR_EN_TRU +ACTOR_EN_TRT +ACTOR_UNSET_189 +ACTOR_UNSET_18A +ACTOR_EN_TEST5 +ACTOR_EN_TEST6 +ACTOR_EN_AZ +ACTOR_EN_ESTONE +ACTOR_BG_HAKUGIN_POST +ACTOR_DM_OPSTAGE +ACTOR_DM_STK +ACTOR_DM_CHAR00 +ACTOR_DM_CHAR01 +ACTOR_DM_CHAR02 +ACTOR_DM_CHAR03 +ACTOR_DM_CHAR04 +ACTOR_DM_CHAR05 +ACTOR_DM_CHAR06 +ACTOR_DM_CHAR07 +ACTOR_DM_CHAR08 +ACTOR_DM_CHAR09 +ACTOR_OBJ_TOKEIDAI +ACTOR_UNSET_19D +ACTOR_EN_MNK +ACTOR_EN_EGBLOCK +ACTOR_EN_GUARD_NUTS +ACTOR_BG_HAKUGIN_BOMBWALL +ACTOR_OBJ_TOKEI_TOBIRA +ACTOR_BG_HAKUGIN_ELVPOLE +ACTOR_EN_MA4 +ACTOR_EN_TWIG +ACTOR_EN_PO_FUSEN +ACTOR_EN_DOOR_ETC +ACTOR_EN_BIGOKUTA +ACTOR_BG_ICEFLOE +ACTOR_OBJ_OCARINALIFT +ACTOR_EN_TIME_TAG +ACTOR_BG_OPEN_SHUTTER +ACTOR_BG_OPEN_SPOT +ACTOR_BG_FU_KAITEN +ACTOR_OBJ_AQUA +ACTOR_EN_ELFORG +ACTOR_EN_ELFBUB +ACTOR_UNSET_1B2 +ACTOR_EN_FU_MATO +ACTOR_EN_FU_KAGO +ACTOR_EN_OSN +ACTOR_BG_CTOWER_GEAR +ACTOR_EN_TRT2 +ACTOR_OBJ_TOKEI_STEP +ACTOR_BG_LOTUS +ACTOR_EN_KAME +ACTOR_OBJ_TAKARAYA_WALL +ACTOR_BG_FU_MIZU +ACTOR_EN_SELLNUTS +ACTOR_BG_DKJAIL_IVY +ACTOR_UNSET_1BF +ACTOR_OBJ_VISIBLOCK +ACTOR_EN_TAKARAYA +ACTOR_EN_TSN +ACTOR_EN_DS2N +ACTOR_EN_FSN +ACTOR_EN_SHN +ACTOR_UNSET_1C6 +ACTOR_EN_STOP_HEISHI +ACTOR_OBJ_BIGICICLE +ACTOR_EN_LIFT_NUTS +ACTOR_EN_TK +ACTOR_UNSET_1CB +ACTOR_BG_MARKET_STEP +ACTOR_OBJ_LUPYGAMELIFT +ACTOR_EN_TEST7 +ACTOR_OBJ_LIGHTBLOCK +ACTOR_MIR_RAY2 +ACTOR_EN_WDHAND +ACTOR_EN_GAMELUPY +ACTOR_BG_DANPEI_MOVEBG +ACTOR_EN_SNOWWD +ACTOR_EN_PM +ACTOR_EN_GAKUFU +ACTOR_ELF_MSG4 +ACTOR_ELF_MSG5 +ACTOR_EN_COL_MAN +ACTOR_EN_TALK_GIBUD +ACTOR_EN_GIANT +ACTOR_OBJ_SNOWBALL +ACTOR_BOSS_HAKUGIN +ACTOR_EN_GB2 +ACTOR_EN_ONPUMAN +ACTOR_BG_TOBIRA01 +ACTOR_EN_TAG_OBJ +ACTOR_OBJ_DHOUSE +ACTOR_OBJ_HAKAISI +ACTOR_BG_HAKUGIN_SWITCH +ACTOR_UNSET_1E5 +ACTOR_EN_SNOWMAN +ACTOR_TG_SW +ACTOR_EN_PO_SISTERS +ACTOR_EN_PP +ACTOR_EN_HAKUROCK +ACTOR_EN_HANABI +ACTOR_OBJ_DOWSING +ACTOR_OBJ_WIND +ACTOR_EN_RACEDOG +ACTOR_EN_KENDO_JS +ACTOR_BG_BOTIHASIRA +ACTOR_EN_FISH2 +ACTOR_EN_PST +ACTOR_EN_POH +ACTOR_OBJ_SPIDERTENT +ACTOR_EN_ZORAEGG +ACTOR_EN_KBT +ACTOR_EN_GG +ACTOR_EN_MARUTA +ACTOR_OBJ_SNOWBALL2 +ACTOR_EN_GG2 +ACTOR_OBJ_GHAKA +ACTOR_EN_DNP +ACTOR_EN_DAI +ACTOR_BG_GORON_OYU +ACTOR_EN_KGY +ACTOR_EN_INVADEPOH +ACTOR_EN_GK +ACTOR_EN_AN +ACTOR_UNSET_203 +ACTOR_EN_BEE +ACTOR_EN_OT +ACTOR_EN_DRAGON +ACTOR_OBJ_DORA +ACTOR_EN_BIGPO +ACTOR_OBJ_KENDO_KANBAN +ACTOR_OBJ_HARIKO +ACTOR_EN_STH +ACTOR_BG_SINKAI_KABE +ACTOR_BG_HAKA_CURTAIN +ACTOR_BG_KIN2_BOMBWALL +ACTOR_BG_KIN2_FENCE +ACTOR_BG_KIN2_PICTURE +ACTOR_BG_KIN2_SHELF +ACTOR_EN_RAIL_SKB +ACTOR_EN_JG +ACTOR_EN_TRU_MT +ACTOR_OBJ_UM +ACTOR_EN_NEO_REEBA +ACTOR_BG_MBAR_CHAIR +ACTOR_BG_IKANA_BLOCK +ACTOR_BG_IKANA_MIRROR +ACTOR_BG_IKANA_ROTARYROOM +ACTOR_BG_DBLUE_BALANCE +ACTOR_BG_DBLUE_WATERFALL +ACTOR_EN_KAIZOKU +ACTOR_EN_GE2 +ACTOR_EN_MA_YTS +ACTOR_EN_MA_YTO +ACTOR_OBJ_TOKEI_TURRET +ACTOR_BG_DBLUE_ELEVATOR +ACTOR_OBJ_WARPSTONE +ACTOR_EN_ZOG +ACTOR_OBJ_ROTLIFT +ACTOR_OBJ_JG_GAKKI +ACTOR_BG_INIBS_MOVEBG +ACTOR_EN_ZOT +ACTOR_OBJ_TREE +ACTOR_OBJ_Y2LIFT +ACTOR_OBJ_Y2SHUTTER +ACTOR_OBJ_BOAT +ACTOR_OBJ_TARU +ACTOR_OBJ_HUNSUI +ACTOR_EN_JC_MATO +ACTOR_MIR_RAY3 +ACTOR_EN_ZOB +ACTOR_ELF_MSG6 +ACTOR_OBJ_NOZOKI +ACTOR_EN_TOTO +ACTOR_EN_RAILGIBUD +ACTOR_EN_BABA +ACTOR_EN_SUTTARI +ACTOR_EN_ZOD +ACTOR_EN_KUJIYA +ACTOR_EN_GEG +ACTOR_OBJ_KINOKO +ACTOR_OBJ_YASI +ACTOR_EN_TANRON1 +ACTOR_EN_TANRON2 +ACTOR_EN_TANRON3 +ACTOR_OBJ_CHAN +ACTOR_EN_ZOS +ACTOR_EN_S_GORO +ACTOR_EN_NB +ACTOR_EN_JA +ACTOR_BG_F40_BLOCK +ACTOR_BG_F40_SWITCH +ACTOR_EN_PO_COMPOSER +ACTOR_EN_GURUGURU +ACTOR_OCEFF_WIPE5 +ACTOR_EN_STONE_HEISHI +ACTOR_OCEFF_WIPE6 +ACTOR_EN_SCOPENUTS +ACTOR_EN_SCOPECROW +ACTOR_OCEFF_WIPE7 +ACTOR_EFF_KAMEJIMA_WAVE +ACTOR_EN_HG +ACTOR_EN_HGO +ACTOR_EN_ZOV +ACTOR_EN_AH +ACTOR_OBJ_HGDOOR +ACTOR_BG_IKANA_BOMBWALL +ACTOR_BG_IKANA_RAY +ACTOR_BG_IKANA_SHUTTER +ACTOR_BG_HAKA_BOMBWALL +ACTOR_BG_HAKA_TOMB +ACTOR_EN_SC_RUPPE +ACTOR_BG_IKNV_DOUKUTU +ACTOR_BG_IKNV_OBJ +ACTOR_EN_PAMERA +ACTOR_OBJ_HSSTUMP +ACTOR_EN_HIDDEN_NUTS +ACTOR_EN_ZOW +ACTOR_EN_TALK +ACTOR_EN_AL +ACTOR_EN_TAB +ACTOR_EN_NIMOTSU +ACTOR_EN_HIT_TAG +ACTOR_EN_RUPPECROW +ACTOR_EN_TANRON4 +ACTOR_EN_TANRON5 +ACTOR_EN_TANRON6 +ACTOR_EN_DAIKU2 +ACTOR_EN_MUTO +ACTOR_EN_BAISEN +ACTOR_EN_HEISHI +ACTOR_EN_DEMO_HEISHI +ACTOR_EN_DT +ACTOR_EN_CHA +ACTOR_OBJ_DINNER +ACTOR_EFF_LASTDAY +ACTOR_BG_IKANA_DHARMA +ACTOR_EN_AKINDONUTS +ACTOR_EFF_STK +ACTOR_EN_IG +ACTOR_EN_RG +ACTOR_EN_OSK +ACTOR_EN_STH2 +ACTOR_EN_YB +ACTOR_EN_RZ +ACTOR_EN_SCOPECOIN +ACTOR_EN_BJT +ACTOR_EN_BOMJIMA +ACTOR_EN_BOMJIMB +ACTOR_EN_BOMBERS +ACTOR_EN_BOMBERS2 +ACTOR_EN_BOMBAL +ACTOR_OBJ_MOON_STONE +ACTOR_OBJ_MU_PICT +ACTOR_BG_IKNINSIDE +ACTOR_EFF_ZORABAND +ACTOR_OBJ_KEPN_KOYA +ACTOR_OBJ_USIYANE +ACTOR_EN_NNH +ACTOR_OBJ_KZSAKU +ACTOR_OBJ_MILK_BIN +ACTOR_EN_KITAN +ACTOR_BG_ASTR_BOMBWALL +ACTOR_BG_IKNIN_SUSCEIL +ACTOR_EN_BSB +ACTOR_EN_RECEPGIRL +ACTOR_EN_THIEFBIRD +ACTOR_EN_JGAME_TSN +ACTOR_OBJ_JGAME_LIGHT +ACTOR_OBJ_YADO +ACTOR_DEMO_SYOTEN +ACTOR_DEMO_MOONEND +ACTOR_BG_LBFSHOT +ACTOR_BG_LAST_BWALL +ACTOR_EN_AND +ACTOR_EN_INVADEPOH_DEMO +ACTOR_OBJ_DANPEILIFT +ACTOR_EN_FALL2 +ACTOR_DM_AL +ACTOR_DM_AN +ACTOR_DM_AH +ACTOR_DM_NB +ACTOR_EN_DRS +ACTOR_EN_ENDING_HERO +ACTOR_DM_BAL +ACTOR_EN_PAPER +ACTOR_EN_HINT_SKB +ACTOR_DM_TAG +ACTOR_EN_BH +ACTOR_EN_ENDING_HERO2 +ACTOR_EN_ENDING_HERO3 +ACTOR_EN_ENDING_HERO4 +ACTOR_EN_ENDING_HERO5 +ACTOR_EN_ENDING_HERO6 +ACTOR_DM_GM +ACTOR_OBJ_SWPRIZE +ACTOR_EN_INVISIBLE_RUPPE +ACTOR_OBJ_ENDING +ACTOR_EN_RSN +ACTOR_ID_MAX \ No newline at end of file diff --git a/CFG/Config.xml b/CFG/Config.xml index adec174..02656c7 100644 --- a/CFG/Config.xml +++ b/CFG/Config.xml @@ -1,8 +1,8 @@ - - - - - + + + + + diff --git a/CFG/ObjectList_MM.txt b/CFG/ObjectList_MM.txt new file mode 100644 index 0000000..93c17e2 --- /dev/null +++ b/CFG/ObjectList_MM.txt @@ -0,0 +1,643 @@ +OBJECT_UNSET_0 +GAMEPLAY_KEEP +GAMEPLAY_FIELD_KEEP +GAMEPLAY_DANGEON_KEEP +OBJECT_NB +OBJECT_OKUTA +OBJECT_CROW +OBJECT_AH +OBJECT_DY_OBJ +OBJECT_WALLMASTER +OBJECT_DODONGO +OBJECT_FIREFLY +OBJECT_BOX +OBJECT_AL +OBJECT_BUBBLE +OBJECT_NIW +OBJECT_LINK_BOY +OBJECT_LINK_CHILD +OBJECT_TITE +OBJECT_TAB +OBJECT_PH +OBJECT_AND +OBJECT_MSMO +OBJECT_DINOFOS +OBJECT_DRS +OBJECT_ZL1 +OBJECT_AN4 +OBJECT_UNSET_1B +OBJECT_TEST3 +OBJECT_FAMOS +OBJECT_UNSET_1E +OBJECT_UNSET_1F +OBJECT_ST +OBJECT_UNSET_21 +OBJECT_THIEFBIRD +OBJECT_UNSET_23 +OBJECT_UNSET_24 +OBJECT_UNSET_25 +OBJECT_UNSET_26 +OBJECT_UNSET_27 +OBJECT_UNSET_28 +OBJECT_UNSET_29 +OBJECT_BOMBF +OBJECT_UNSET_2B +OBJECT_UNSET_2C +OBJECT_UNSET_2D +OBJECT_UNSET_2E +OBJECT_UNSET_2F +OBJECT_AM +OBJECT_DEKUBABA +OBJECT_UNSET_32 +OBJECT_UNSET_33 +OBJECT_UNSET_34 +OBJECT_UNSET_35 +OBJECT_UNSET_36 +OBJECT_UNSET_37 +OBJECT_UNSET_38 +OBJECT_UNSET_39 +OBJECT_UNSET_3A +OBJECT_UNSET_3B +OBJECT_UNSET_3C +OBJECT_UNSET_3D +OBJECT_WARP1 +OBJECT_B_HEART +OBJECT_DEKUNUTS +OBJECT_UNSET_41 +OBJECT_UNSET_42 +OBJECT_UNSET_43 +OBJECT_UNSET_44 +OBJECT_UNSET_45 +OBJECT_UNSET_46 +OBJECT_UNSET_47 +OBJECT_UNSET_48 +OBJECT_UNSET_49 +OBJECT_UNSET_4A +OBJECT_UNSET_4B +OBJECT_UNSET_4C +OBJECT_UNSET_4D +OBJECT_UNSET_4E +OBJECT_UNSET_4F +OBJECT_UNSET_50 +OBJECT_BB +OBJECT_DEATH +OBJECT_UNSET_53 +OBJECT_UNSET_54 +OBJECT_UNSET_55 +OBJECT_UNSET_56 +OBJECT_UNSET_57 +OBJECT_UNSET_58 +OBJECT_UNSET_59 +OBJECT_UNSET_5A +OBJECT_UNSET_5B +OBJECT_F40_OBJ +OBJECT_PO_COMPOSER +OBJECT_UNSET_5E +OBJECT_HATA +OBJECT_UNSET_60 +OBJECT_WOOD02 +OBJECT_UNSET_62 +OBJECT_UNSET_63 +OBJECT_TRAP +OBJECT_UNSET_65 +OBJECT_UNSET_66 +OBJECT_UNSET_67 +OBJECT_UNSET_68 +OBJECT_UNSET_69 +OBJECT_VM +OBJECT_UNSET_6B +OBJECT_UNSET_6C +OBJECT_UNSET_6D +OBJECT_UNSET_6E +OBJECT_UNSET_6F +OBJECT_EFC_STAR_FIELD +OBJECT_UNSET_71 +OBJECT_UNSET_72 +OBJECT_UNSET_73 +OBJECT_UNSET_74 +OBJECT_RD +OBJECT_YUKIMURA_OBJ +OBJECT_HEAVY_OBJECT +OBJECT_UNSET_78 +OBJECT_UNSET_79 +OBJECT_UNSET_7A +OBJECT_UNSET_7B +OBJECT_UNSET_7C +OBJECT_HORSE_LINK_CHILD +OBJECT_UNSET_7E +OBJECT_UNSET_7F +OBJECT_SYOKUDAI +OBJECT_UNSET_81 +OBJECT_UNSET_82 +OBJECT_UNSET_83 +OBJECT_EFC_TW +OBJECT_UNSET_85 +OBJECT_GI_KEY +OBJECT_MIR_RAY +OBJECT_CTOWER_ROT +OBJECT_UNSET_89 +OBJECT_BDOOR +OBJECT_UNSET_8B +OBJECT_UNSET_8C +OBJECT_UNSET_8D +OBJECT_SB +OBJECT_GI_MELODY +OBJECT_GI_HEART +OBJECT_GI_COMPASS +OBJECT_GI_BOSSKEY +OBJECT_UNSET_93 +OBJECT_GI_NUTS +OBJECT_UNSET_95 +OBJECT_GI_HEARTS +OBJECT_GI_ARROWCASE +OBJECT_GI_BOMBPOUCH +OBJECT_IN +OBJECT_UNSET_9A +OBJECT_UNSET_9B +OBJECT_UNSET_9C +OBJECT_OS_ANIME +OBJECT_GI_BOTTLE +OBJECT_GI_STICK +OBJECT_GI_MAP +OBJECT_OF1D_MAP +OBJECT_RU2 +OBJECT_UNSET_A3 +OBJECT_GI_MAGICPOT +OBJECT_GI_BOMB_1 +OBJECT_UNSET_A6 +OBJECT_MA2 +OBJECT_GI_PURSE +OBJECT_UNSET_A9 +OBJECT_UNSET_AA +OBJECT_RR +OBJECT_UNSET_AC +OBJECT_UNSET_AD +OBJECT_UNSET_AE +OBJECT_GI_ARROW +OBJECT_GI_BOMB_2 +OBJECT_UNSET_B1 +OBJECT_UNSET_B2 +OBJECT_GI_SHIELD_2 +OBJECT_GI_HOOKSHOT +OBJECT_GI_OCARINA +OBJECT_GI_MILK +OBJECT_MA1 +OBJECT_UNSET_B8 +OBJECT_UNSET_B9 +OBJECT_UNSET_BA +OBJECT_NY +OBJECT_FR +OBJECT_UNSET_BD +OBJECT_UNSET_BE +OBJECT_GI_BOW +OBJECT_GI_GLASSES +OBJECT_GI_LIQUID +OBJECT_ANI +OBJECT_GI_SHIELD_3 +OBJECT_UNSET_C4 +OBJECT_UNSET_C5 +OBJECT_GI_BEAN +OBJECT_GI_FISH +OBJECT_UNSET_C8 +OBJECT_UNSET_C9 +OBJECT_UNSET_CA +OBJECT_GI_LONGSWORD +OBJECT_UNSET_CC +OBJECT_UNSET_CD +OBJECT_UNSET_CE +OBJECT_UNSET_CF +OBJECT_ZO +OBJECT_UNSET_D1 +OBJECT_UMAJUMP +OBJECT_UNSET_D3 +OBJECT_UNSET_D4 +OBJECT_MASTERGOLON +OBJECT_MASTERZOORA +OBJECT_AOB +OBJECT_IK +OBJECT_AHG +OBJECT_CNE +OBJECT_UNSET_DB +OBJECT_UNSET_DC +OBJECT_AN3 +OBJECT_BJI +OBJECT_BBA +OBJECT_AN2 +OBJECT_UNSET_E1 +OBJECT_AN1 +OBJECT_BOJ +OBJECT_FZ +OBJECT_BOB +OBJECT_GE1 +OBJECT_YABUSAME_POINT +OBJECT_UNSET_E8 +OBJECT_UNSET_E9 +OBJECT_UNSET_EA +OBJECT_UNSET_EB +OBJECT_D_HSBLOCK +OBJECT_D_LIFT +OBJECT_MAMENOKI +OBJECT_GOROIWA +OBJECT_TORYO +OBJECT_DAIKU +OBJECT_NWC +OBJECT_GM +OBJECT_MS +OBJECT_HS +OBJECT_UNSET_F6 +OBJECT_LIGHTSWITCH +OBJECT_KUSA +OBJECT_TSUBO +OBJECT_UNSET_FA +OBJECT_UNSET_FB +OBJECT_KANBAN +OBJECT_OWL +OBJECT_MK +OBJECT_FU +OBJECT_GI_KI_TAN_MASK +OBJECT_UNSET_101 +OBJECT_GI_MASK18 +OBJECT_GI_RABIT_MASK +OBJECT_GI_TRUTH_MASK +OBJECT_UNSET_105 +OBJECT_STREAM +OBJECT_MM +OBJECT_UNSET_108 +OBJECT_UNSET_109 +OBJECT_UNSET_10A +OBJECT_UNSET_10B +OBJECT_UNSET_10C +OBJECT_UNSET_10D +OBJECT_UNSET_10E +OBJECT_JS +OBJECT_CS +OBJECT_UNSET_111 +OBJECT_UNSET_112 +OBJECT_GI_SOLDOUT +OBJECT_UNSET_114 +OBJECT_MAG +OBJECT_UNSET_116 +OBJECT_UNSET_117 +OBJECT_UNSET_118 +OBJECT_GI_GOLONMASK +OBJECT_GI_ZORAMASK +OBJECT_UNSET_11B +OBJECT_UNSET_11C +OBJECT_KA +OBJECT_UNSET_11E +OBJECT_ZG +OBJECT_UNSET_120 +OBJECT_GI_M_ARROW +OBJECT_DS2 +OBJECT_UNSET_123 +OBJECT_FISH +OBJECT_GI_SUTARU +OBJECT_UNSET_126 +OBJECT_SSH +OBJECT_BIGSLIME +OBJECT_BG +OBJECT_BOMBIWA +OBJECT_HINTNUTS +OBJECT_RS +OBJECT_UNSET_12D +OBJECT_GLA +OBJECT_UNSET_12F +OBJECT_GELDB +OBJECT_UNSET_131 +OBJECT_DOG +OBJECT_KIBAKO2 +OBJECT_DNS +OBJECT_DNK +OBJECT_UNSET_136 +OBJECT_GI_INSECT +OBJECT_UNSET_138 +OBJECT_GI_GHOST +OBJECT_GI_SOUL +OBJECT_UNSET_13B +OBJECT_UNSET_13C +OBJECT_UNSET_13D +OBJECT_UNSET_13E +OBJECT_GI_RUPY +OBJECT_MU +OBJECT_WF +OBJECT_SKB +OBJECT_GS +OBJECT_PS +OBJECT_OMOYA_OBJ +OBJECT_COW +OBJECT_UNSET_147 +OBJECT_GI_SWORD_1 +OBJECT_UNSET_149 +OBJECT_UNSET_14A +OBJECT_ZL4 +OBJECT_LINK_GORON +OBJECT_LINK_ZORA +OBJECT_GRASSHOPPER +OBJECT_BOYO +OBJECT_UNSET_150 +OBJECT_UNSET_151 +OBJECT_UNSET_152 +OBJECT_FWALL +OBJECT_LINK_NUTS +OBJECT_JSO +OBJECT_KNIGHT +OBJECT_ICICLE +OBJECT_SPDWEB +OBJECT_UNSET_159 +OBJECT_BOSS01 +OBJECT_BOSS02 +OBJECT_BOSS03 +OBJECT_BOSS04 +OBJECT_BOSS05 +OBJECT_BOSS06 +OBJECT_BOSS07 +OBJECT_RAF +OBJECT_FUNEN +OBJECT_RAILLIFT +OBJECT_NUMA_OBJ +OBJECT_FLOWERPOT +OBJECT_SPINYROLL +OBJECT_ICE_BLOCK +OBJECT_UNSET_168 +OBJECT_KEIKOKU_DEMO +OBJECT_SLIME +OBJECT_PR +OBJECT_F52_OBJ +OBJECT_F53_OBJ +OBJECT_UNSET_16E +OBJECT_KIBAKO +OBJECT_SEK +OBJECT_GMO +OBJECT_BAT +OBJECT_SEKIHIL +OBJECT_SEKIHIG +OBJECT_SEKIHIN +OBJECT_SEKIHIZ +OBJECT_UNSET_177 +OBJECT_WIZ +OBJECT_LADDER +OBJECT_MKK +OBJECT_UNSET_17B +OBJECT_UNSET_17C +OBJECT_UNSET_17D +OBJECT_KEIKOKU_OBJ +OBJECT_SICHITAI_OBJ +OBJECT_DEKUCITY_ANA_OBJ +OBJECT_RAT +OBJECT_WATER_EFFECT +OBJECT_UNSET_183 +OBJECT_DBLUE_OBJECT +OBJECT_BAL +OBJECT_WARP_UZU +OBJECT_DRIFTICE +OBJECT_FALL +OBJECT_HANAREYAMA_OBJ +OBJECT_CRACE_OBJECT +OBJECT_DNO +OBJECT_OBJ_TOKEIDAI +OBJECT_EG +OBJECT_TRU +OBJECT_TRT +OBJECT_HAKUGIN_OBJ +OBJECT_HORSE_GAME_CHECK +OBJECT_STK +OBJECT_UNSET_193 +OBJECT_UNSET_194 +OBJECT_MNK +OBJECT_GI_BOTTLE_RED +OBJECT_TOKEI_TOBIRA +OBJECT_AZ +OBJECT_TWIG +OBJECT_DEKUCITY_OBJ +OBJECT_PO_FUSEN +OBJECT_RACETSUBO +OBJECT_HA +OBJECT_BIGOKUTA +OBJECT_OPEN_OBJ +OBJECT_FU_KAITEN +OBJECT_FU_MATO +OBJECT_MTORIDE +OBJECT_OSN +OBJECT_TOKEI_STEP +OBJECT_LOTUS +OBJECT_TL +OBJECT_DKJAIL_OBJ +OBJECT_VISIBLOCK +OBJECT_TSN +OBJECT_DS2N +OBJECT_FSN +OBJECT_SHN +OBJECT_BIGICICLE +OBJECT_GI_BOTTLE_15 +OBJECT_TK +OBJECT_MARKET_OBJ +OBJECT_GI_RESERVE00 +OBJECT_GI_RESERVE01 +OBJECT_LIGHTBLOCK +OBJECT_TAKARAYA_OBJECTS +OBJECT_WDHAND +OBJECT_SDN +OBJECT_SNOWWD +OBJECT_GIANT +OBJECT_COMB +OBJECT_HANA +OBJECT_BOSS_HAKUGIN +OBJECT_MEGANEANA_OBJ +OBJECT_GI_NUTSMASK +OBJECT_STK2 +OBJECT_SPOT11_OBJ +OBJECT_DANPEI_OBJECT +OBJECT_DHOUSE +OBJECT_HAKAISI +OBJECT_PO +OBJECT_SNOWMAN +OBJECT_PO_SISTERS +OBJECT_PP +OBJECT_GORONSWITCH +OBJECT_DELF +OBJECT_BOTIHASIRA +OBJECT_GI_BIGBOMB +OBJECT_PST +OBJECT_BSMASK +OBJECT_SPIDERTENT +OBJECT_ZORAEGG +OBJECT_KBT +OBJECT_GG +OBJECT_MARUTA +OBJECT_GHAKA +OBJECT_OYU +OBJECT_DNQ +OBJECT_DAI +OBJECT_KGY +OBJECT_FB +OBJECT_TAISOU +OBJECT_MASK_BU_SAN +OBJECT_MASK_KI_TAN +OBJECT_MASK_RABIT +OBJECT_MASK_SKJ +OBJECT_MASK_BAKURETU +OBJECT_MASK_TRUTH +OBJECT_GK +OBJECT_HAKA_OBJ +OBJECT_MASK_GORON +OBJECT_MASK_ZORA +OBJECT_MASK_NUTS +OBJECT_MASK_BOY +OBJECT_DNT +OBJECT_YUKIYAMA +OBJECT_ICEFLOE +OBJECT_GI_GOLD_DUST +OBJECT_GI_BOTTLE_16 +OBJECT_GI_BOTTLE_22 +OBJECT_BEE +OBJECT_OT +OBJECT_UTUBO +OBJECT_DORA +OBJECT_GI_LOACH +OBJECT_GI_SEAHORSE +OBJECT_BIGPO +OBJECT_HARIKO +OBJECT_DNJ +OBJECT_SINKAI_KABE +OBJECT_KIN2_OBJ +OBJECT_ISHI +OBJECT_HAKUGIN_DEMO +OBJECT_JG +OBJECT_GI_SWORD_2 +OBJECT_GI_SWORD_3 +OBJECT_GI_SWORD_4 +OBJECT_UM +OBJECT_MASK_GIBUDO +OBJECT_MASK_JSON +OBJECT_MASK_KERFAY +OBJECT_MASK_BIGELF +OBJECT_RB +OBJECT_MBAR_OBJ +OBJECT_IKANA_OBJ +OBJECT_KZ +OBJECT_TOKEI_TURRET +OBJECT_ZOG +OBJECT_ROTLIFT +OBJECT_POSTHOUSE_OBJ +OBJECT_GI_MASK09 +OBJECT_GI_MASK14 +OBJECT_GI_MASK15 +OBJECT_INIBS_OBJECT +OBJECT_TREE +OBJECT_KAIZOKU_OBJ +OBJECT_GI_RESERVE_B_00 +OBJECT_GI_RESERVE_C_00 +OBJECT_ZOB +OBJECT_MILKBAR +OBJECT_DMASK +OBJECT_MASK_KYOJIN +OBJECT_GI_RESERVE_C_01 +OBJECT_ZOD +OBJECT_KUMO30 +OBJECT_OBJ_YASI +OBJECT_MASK_ROMERNY +OBJECT_TANRON1 +OBJECT_TANRON2 +OBJECT_TANRON3 +OBJECT_GI_MAGICMUSHROOM +OBJECT_OBJ_CHAN +OBJECT_GI_MASK10 +OBJECT_ZOS +OBJECT_MASK_POSTHAT +OBJECT_F40_SWITCH +OBJECT_LODMOON +OBJECT_TRO +OBJECT_GI_MASK12 +OBJECT_GI_MASK23 +OBJECT_GI_BOTTLE_21 +OBJECT_GI_CAMERA +OBJECT_KAMEJIMA +OBJECT_HARFGIBUD +OBJECT_ZOV +OBJECT_HGDOOR +OBJECT_UNSET_22D +OBJECT_UNSET_22E +OBJECT_UNSET_22F +OBJECT_DOR01 +OBJECT_DOR02 +OBJECT_DOR03 +OBJECT_DOR04 +OBJECT_LAST_OBJ +OBJECT_REDEAD_OBJ +OBJECT_IKNINSIDE_OBJ +OBJECT_IKNV_OBJ +OBJECT_PAMERA +OBJECT_HSSTUMP +OBJECT_ZM +OBJECT_BIG_FWALL +OBJECT_SECOM_OBJ +OBJECT_HUNSUI +OBJECT_UCH +OBJECT_TANRON4 +OBJECT_TANRON5 +OBJECT_DT +OBJECT_GI_MASK03 +OBJECT_CHA +OBJECT_OBJ_DINNER +OBJECT_GI_RESERVE_B_01 +OBJECT_LASTDAY +OBJECT_BAI +OBJECT_IN2 +OBJECT_IKN_DEMO +OBJECT_YB +OBJECT_RZ +OBJECT_MASK_ZACHO +OBJECT_GI_FIELDMAP +OBJECT_MASK_STONE +OBJECT_BJT +OBJECT_TARU +OBJECT_MOONSTON +OBJECT_MASK_BREE +OBJECT_GI_SCHEDULE +OBJECT_GI_STONEMASK +OBJECT_ZORABAND +OBJECT_KEPN_KOYA +OBJECT_OBJ_USIYANE +OBJECT_GI_MASK05 +OBJECT_GI_MASK11 +OBJECT_GI_MASK20 +OBJECT_NNH +OBJECT_MASK_GERO +OBJECT_MASK_YOFUKASI +OBJECT_MASK_MEOTO +OBJECT_MASK_DANCER +OBJECT_KZSAKU +OBJECT_OBJ_MILK_BIN +OBJECT_RANDOM_OBJ +OBJECT_KUJIYA +OBJECT_KITAN +OBJECT_GI_MASK06 +OBJECT_GI_MASK16 +OBJECT_ASTR_OBJ +OBJECT_BSB +OBJECT_FALL2 +OBJECT_STH +OBJECT_GI_MSSA +OBJECT_SMTOWER +OBJECT_GI_MASK21 +OBJECT_YADO_OBJ +OBJECT_SYOTEN +OBJECT_MOONEND +OBJECT_OB +OBJECT_GI_BOTTLE_04 +OBJECT_OBJ_DANPEILIFT +OBJECT_WDOR01 +OBJECT_WDOR02 +OBJECT_WDOR03 +OBJECT_STK3 +OBJECT_KINSTA1_OBJ +OBJECT_KINSTA2_OBJ +OBJECT_BH +OBJECT_WDOR04 +OBJECT_WDOR05 +OBJECT_GI_MASK17 +OBJECT_GI_MASK22 +OBJECT_LBFSHOT +OBJECT_FUSEN +OBJECT_ENDING_OBJ +OBJECT_GI_MASK13 diff --git a/CFG/SymbolMap_MM.txt b/CFG/SymbolMap_MM.txt new file mode 100644 index 0000000..2a215dc --- /dev/null +++ b/CFG/SymbolMap_MM.txt @@ -0,0 +1 @@ +801D1DE0 gIdentityMtx \ No newline at end of file diff --git a/CFG/filelists/mm.txt b/CFG/filelists/mm.txt new file mode 100644 index 0000000..598a67c --- /dev/null +++ b/CFG/filelists/mm.txt @@ -0,0 +1,1552 @@ +makerom +boot +dmadata +Audiobank +Audioseq +Audiotable +kanji +link_animetion +icon_item_static_syms +icon_item_24_static_syms +icon_item_field_static +icon_item_dungeon_static +icon_item_gameover_static +icon_item_jpn_static +icon_item_vtx_static +map_i_static +map_grand_static +item_name_static +map_name_static +icon_item_static_yar +icon_item_24_static_yar +schedule_dma_static_syms +schedule_dma_static_yar +schedule_static +story_static +do_action_static +message_static +message_texture_static +nes_font_static +message_data_static +staff_message_data_static +code +ovl_title +ovl_select +ovl_opening +ovl_file_choose +ovl_daytelop +ovl_kaleido_scope +ovl_player_actor +ovl_En_Test +ovl_En_GirlA +ovl_En_Part +ovl_En_Light +ovl_En_Door +ovl_En_Box +ovl_En_Pametfrog +ovl_En_Okuta +ovl_En_Bom +ovl_En_Wallmas +ovl_En_Dodongo +ovl_En_Firefly +ovl_En_Horse +ovl_En_Arrow +ovl_En_Elf +ovl_En_Niw +ovl_En_Tite +ovl_En_Peehat +ovl_En_Holl +ovl_En_Dinofos +ovl_En_Hata +ovl_En_Zl1 +ovl_En_Viewer +ovl_En_Bubble +ovl_Door_Shutter +ovl_En_Boom +ovl_En_Torch2 +ovl_En_Minifrog +ovl_En_St +ovl_Obj_Wturn +ovl_En_River_Sound +ovl_En_Ossan +ovl_En_Famos +ovl_En_Bombf +ovl_En_Am +ovl_En_Dekubaba +ovl_En_M_Fire1 +ovl_En_M_Thunder +ovl_Bg_Breakwall +ovl_Door_Warp1 +ovl_Obj_Syokudai +ovl_Item_B_Heart +ovl_En_Dekunuts +ovl_En_Bbfall +ovl_Arms_Hook +ovl_En_Bb +ovl_Bg_Keikoku_Spr +ovl_En_Wood02 +ovl_En_Death +ovl_En_Minideath +ovl_En_Vm +ovl_Demo_Effect +ovl_Demo_Kankyo +ovl_En_Floormas +ovl_En_Rd +ovl_Bg_F40_Flift +ovl_Obj_Mure +ovl_En_Sw +ovl_Object_Kankyo +ovl_En_Horse_Link_Child +ovl_Door_Ana +ovl_En_Encount1 +ovl_Demo_Tre_Lgt +ovl_En_Encount2 +ovl_En_Fire_Rock +ovl_Bg_Ctower_Rot +ovl_Mir_Ray +ovl_En_Sb +ovl_En_Bigslime +ovl_En_Karebaba +ovl_En_In +ovl_En_Bom_Chu +ovl_En_Horse_Game_Check +ovl_En_Rr +ovl_En_Fr +ovl_En_Fishing +ovl_Obj_Oshihiki +ovl_Eff_Dust +ovl_Bg_Umajump +ovl_En_Insect +ovl_En_Butte +ovl_En_Fish +ovl_Item_Etcetera +ovl_Arrow_Fire +ovl_Arrow_Ice +ovl_Arrow_Light +ovl_Obj_Kibako +ovl_Obj_Tsubo +ovl_En_Ik +ovl_Demo_Shd +ovl_En_Dns +ovl_Elf_Msg +ovl_En_Honotrap +ovl_En_Tubo_Trap +ovl_Obj_Ice_Poly +ovl_En_Fz +ovl_En_Kusa +ovl_Obj_Bean +ovl_Obj_Bombiwa +ovl_Obj_Switch +ovl_Obj_Lift +ovl_Obj_Hsblock +ovl_En_Okarina_Tag +ovl_En_Goroiwa +ovl_En_Daiku +ovl_En_Nwc +ovl_Item_Inbox +ovl_En_Ge1 +ovl_Obj_Blockstop +ovl_En_Sda +ovl_En_Clear_Tag +ovl_En_Gm +ovl_En_Ms +ovl_En_Hs +ovl_Bg_Ingate +ovl_En_Kanban +ovl_En_Attack_Niw +ovl_En_Mk +ovl_En_Owl +ovl_En_Ishi +ovl_Obj_Hana +ovl_Obj_Lightswitch +ovl_Obj_Mure2 +ovl_En_Fu +ovl_En_Stream +ovl_En_Mm +ovl_En_Weather_Tag +ovl_En_Ani +ovl_En_Js +ovl_En_Okarina_Effect +ovl_En_Mag +ovl_Elf_Msg2 +ovl_Bg_F40_Swlift +ovl_En_Kakasi +ovl_Obj_Makeoshihiki +ovl_Oceff_Spot +ovl_En_Torch +ovl_Shot_Sun +ovl_Obj_Roomtimer +ovl_En_Ssh +ovl_Oceff_Wipe +ovl_Effect_Ss_Dust +ovl_Effect_Ss_Kirakira +ovl_Effect_Ss_Bomb2 +ovl_Effect_Ss_Blast +ovl_Effect_Ss_G_Spk +ovl_Effect_Ss_D_Fire +ovl_Effect_Ss_Bubble +ovl_Effect_Ss_G_Ripple +ovl_Effect_Ss_G_Splash +ovl_Effect_Ss_G_Fire +ovl_Effect_Ss_Lightning +ovl_Effect_Ss_Dt_Bubble +ovl_Effect_Ss_Hahen +ovl_Effect_Ss_Stick +ovl_Effect_Ss_Sibuki +ovl_Effect_Ss_Stone1 +ovl_Effect_Ss_Hitmark +ovl_Effect_Ss_Fhg_Flash +ovl_Effect_Ss_K_Fire +ovl_Effect_Ss_Solder_Srch_Ball +ovl_Effect_Ss_Kakera +ovl_Effect_Ss_Ice_Piece +ovl_Effect_Ss_En_Ice +ovl_Effect_Ss_Fire_Tail +ovl_Effect_Ss_En_Fire +ovl_Effect_Ss_Extra +ovl_Effect_Ss_Dead_Db +ovl_Effect_Ss_Dead_Dd +ovl_Effect_Ss_Dead_Ds +ovl_Oceff_Storm +ovl_Obj_Demo +ovl_En_Minislime +ovl_En_Nutsball +ovl_Oceff_Wipe2 +ovl_Oceff_Wipe3 +ovl_En_Dg +ovl_En_Si +ovl_Obj_Comb +ovl_Obj_Kibako2 +ovl_En_Hs2 +ovl_Obj_Mure3 +ovl_En_Tg +ovl_En_Wf +ovl_En_Skb +ovl_En_Gs +ovl_Obj_Sound +ovl_En_Crow +ovl_En_Cow +ovl_Oceff_Wipe4 +ovl_En_Zo +ovl_Effect_Ss_Ice_Smoke +ovl_Obj_Makekinsuta +ovl_En_Ge3 +ovl_Obj_Hamishi +ovl_En_Zl4 +ovl_En_Mm2 +ovl_Door_Spiral +ovl_Obj_Pzlblock +ovl_Obj_Toge +ovl_Obj_Armos +ovl_Obj_Boyo +ovl_En_Grasshopper +ovl_Obj_Grass +ovl_Obj_Grass_Carry +ovl_Obj_Grass_Unit +ovl_Bg_Fire_Wall +ovl_En_Bu +ovl_En_Encount3 +ovl_En_Jso +ovl_Obj_Chikuwa +ovl_En_Knight +ovl_En_Warp_tag +ovl_En_Aob_01 +ovl_En_Boj_01 +ovl_En_Boj_02 +ovl_En_Boj_03 +ovl_En_Encount4 +ovl_En_Bom_Bowl_Man +ovl_En_Syateki_Man +ovl_Bg_Icicle +ovl_En_Syateki_Crow +ovl_En_Boj_04 +ovl_En_Cne_01 +ovl_En_Bba_01 +ovl_En_Bji_01 +ovl_Bg_Spdweb +ovl_En_Mt_tag +ovl_Boss_01 +ovl_Boss_02 +ovl_Boss_03 +ovl_Boss_04 +ovl_Boss_05 +ovl_Boss_06 +ovl_Boss_07 +ovl_Bg_Dy_Yoseizo +ovl_En_Boj_05 +ovl_En_Sob1 +ovl_En_Go +ovl_En_Raf +ovl_Obj_Funen +ovl_Obj_Raillift +ovl_Bg_Numa_Hana +ovl_Obj_Flowerpot +ovl_Obj_Spinyroll +ovl_Dm_Hina +ovl_En_Syateki_Wf +ovl_Obj_Skateblock +ovl_Effect_En_Ice_Block +ovl_Obj_Iceblock +ovl_En_Bigpamet +ovl_Bg_Dblue_Movebg +ovl_En_Syateki_Dekunuts +ovl_Elf_Msg3 +ovl_En_Fg +ovl_Dm_Ravine +ovl_Dm_Sa +ovl_En_Slime +ovl_En_Pr +ovl_Obj_Toudai +ovl_Obj_Entotu +ovl_Obj_Bell +ovl_En_Syateki_Okuta +ovl_Obj_Shutter +ovl_Dm_Zl +ovl_En_Ru +ovl_En_Elfgrp +ovl_Dm_Tsg +ovl_En_Baguo +ovl_Obj_Vspinyroll +ovl_Obj_Smork +ovl_En_Test2 +ovl_En_Test3 +ovl_En_Test4 +ovl_En_Bat +ovl_En_Sekihi +ovl_En_Wiz +ovl_En_Wiz_Brock +ovl_En_Wiz_Fire +ovl_Eff_Change +ovl_Dm_Statue +ovl_Obj_Fireshield +ovl_Bg_Ladder +ovl_En_Mkk +ovl_Demo_Getitem +ovl_En_Dnb +ovl_En_Dnh +ovl_En_Dnk +ovl_En_Dnq +ovl_Bg_Keikoku_Saku +ovl_Obj_Hugebombiwa +ovl_En_Firefly2 +ovl_En_Rat +ovl_En_Water_Effect +ovl_En_Kusa2 +ovl_Bg_Spout_Fire +ovl_En_Dy_Extra +ovl_En_Bal +ovl_En_Ginko_Man +ovl_En_Warp_Uzu +ovl_Obj_Driftice +ovl_En_Look_Nuts +ovl_En_Mushi2 +ovl_En_Fall +ovl_En_Mm3 +ovl_Bg_Crace_Movebg +ovl_En_Dno +ovl_En_Pr2 +ovl_En_Prz +ovl_En_Jso2 +ovl_Obj_Etcetera +ovl_En_Egol +ovl_Obj_Mine +ovl_Obj_Purify +ovl_En_Tru +ovl_En_Trt +ovl_En_Test5 +ovl_En_Test6 +ovl_En_Az +ovl_En_Estone +ovl_Bg_Hakugin_Post +ovl_Dm_Opstage +ovl_Dm_Stk +ovl_Dm_Char00 +ovl_Dm_Char01 +ovl_Dm_Char02 +ovl_Dm_Char03 +ovl_Dm_Char04 +ovl_Dm_Char05 +ovl_Dm_Char06 +ovl_Dm_Char07 +ovl_Dm_Char08 +ovl_Dm_Char09 +ovl_Obj_Tokeidai +ovl_En_Mnk +ovl_En_Egblock +ovl_En_Guard_Nuts +ovl_Bg_Hakugin_Bombwall +ovl_Obj_Tokei_Tobira +ovl_Bg_Hakugin_Elvpole +ovl_En_Ma4 +ovl_En_Twig +ovl_En_Po_Fusen +ovl_En_Door_Etc +ovl_En_Bigokuta +ovl_Bg_Icefloe +ovl_fbdemo_triforce +ovl_fbdemo_wipe1 +ovl_fbdemo_wipe3 +ovl_fbdemo_wipe4 +ovl_fbdemo_wipe5 +ovl_Effect_Ss_Sbn +ovl_Obj_Ocarinalift +ovl_En_Time_Tag +ovl_Bg_Open_Shutter +ovl_Bg_Open_Spot +ovl_Bg_Fu_Kaiten +ovl_Obj_Aqua +ovl_En_Elforg +ovl_En_Elfbub +ovl_En_Fu_Mato +ovl_En_Fu_Kago +ovl_En_Osn +ovl_Bg_Ctower_Gear +ovl_En_Trt2 +ovl_Obj_Tokei_Step +ovl_Bg_Lotus +ovl_En_Kame +ovl_Obj_Takaraya_Wall +ovl_Bg_Fu_Mizu +ovl_En_Sellnuts +ovl_Bg_Dkjail_Ivy +ovl_Obj_Visiblock +ovl_En_Takaraya +ovl_En_Tsn +ovl_En_Ds2n +ovl_En_Fsn +ovl_En_Shn +ovl_En_Stop_heishi +ovl_Obj_Bigicicle +ovl_En_Lift_Nuts +ovl_En_Tk +ovl_Bg_Market_Step +ovl_Obj_Lupygamelift +ovl_En_Test7 +ovl_Obj_Lightblock +ovl_Mir_Ray2 +ovl_En_Wdhand +ovl_En_Gamelupy +ovl_Bg_Danpei_Movebg +ovl_En_Snowwd +ovl_En_Pm +ovl_En_Gakufu +ovl_Elf_Msg4 +ovl_Elf_Msg5 +ovl_En_Col_Man +ovl_En_Talk_Gibud +ovl_En_Giant +ovl_Obj_Snowball +ovl_Boss_Hakugin +ovl_En_Gb2 +ovl_En_Onpuman +ovl_Bg_Tobira01 +ovl_En_Tag_Obj +ovl_Obj_Dhouse +ovl_Obj_Hakaisi +ovl_Bg_Hakugin_Switch +ovl_En_Snowman +ovl_TG_Sw +ovl_En_Po_Sisters +ovl_En_Pp +ovl_En_Hakurock +ovl_En_Hanabi +ovl_Obj_Dowsing +ovl_Obj_Wind +ovl_En_Racedog +ovl_En_Kendo_Js +ovl_Bg_Botihasira +ovl_En_Fish2 +ovl_En_Pst +ovl_En_Poh +ovl_Obj_Spidertent +ovl_En_Zoraegg +ovl_En_Kbt +ovl_En_Gg +ovl_En_Maruta +ovl_Obj_Snowball2 +ovl_En_Gg2 +ovl_Obj_Ghaka +ovl_En_Dnp +ovl_En_Dai +ovl_Bg_Goron_Oyu +ovl_En_Kgy +ovl_En_Invadepoh +ovl_En_Gk +ovl_En_An +ovl_En_Bee +ovl_En_Ot +ovl_En_Dragon +ovl_Obj_Dora +ovl_En_Bigpo +ovl_Obj_Kendo_Kanban +ovl_Obj_Hariko +ovl_En_Sth +ovl_Bg_Sinkai_Kabe +ovl_Bg_Haka_Curtain +ovl_Bg_Kin2_Bombwall +ovl_Bg_Kin2_Fence +ovl_Bg_Kin2_Picture +ovl_Bg_Kin2_Shelf +ovl_En_Rail_Skb +ovl_En_Jg +ovl_En_Tru_Mt +ovl_Obj_Um +ovl_En_Neo_Reeba +ovl_Bg_Mbar_Chair +ovl_Bg_Ikana_Block +ovl_Bg_Ikana_Mirror +ovl_Bg_Ikana_Rotaryroom +ovl_Bg_Dblue_Balance +ovl_Bg_Dblue_Waterfall +ovl_En_Kaizoku +ovl_En_Ge2 +ovl_En_Ma_Yts +ovl_En_Ma_Yto +ovl_Obj_Tokei_Turret +ovl_Bg_Dblue_Elevator +ovl_Obj_Warpstone +ovl_En_Zog +ovl_Obj_Rotlift +ovl_Obj_Jg_Gakki +ovl_Bg_Inibs_Movebg +ovl_En_Zot +ovl_Obj_Tree +ovl_Obj_Y2lift +ovl_Obj_Y2shutter +ovl_Obj_Boat +ovl_Obj_Taru +ovl_Obj_Hunsui +ovl_En_Jc_Mato +ovl_Mir_Ray3 +ovl_En_Zob +ovl_Elf_Msg6 +ovl_Obj_Nozoki +ovl_En_Toto +ovl_En_Railgibud +ovl_En_Baba +ovl_En_Suttari +ovl_En_Zod +ovl_En_Kujiya +ovl_En_Geg +ovl_Obj_Kinoko +ovl_Obj_Yasi +ovl_En_Tanron1 +ovl_En_Tanron2 +ovl_En_Tanron3 +ovl_Obj_Chan +ovl_En_Zos +ovl_En_S_Goro +ovl_En_Nb +ovl_En_Ja +ovl_Bg_F40_Block +ovl_Bg_F40_Switch +ovl_En_Po_Composer +ovl_En_Guruguru +ovl_Oceff_Wipe5 +ovl_En_Stone_heishi +ovl_Oceff_Wipe6 +ovl_En_Scopenuts +ovl_En_Scopecrow +ovl_Oceff_Wipe7 +ovl_Eff_Kamejima_Wave +ovl_En_Hg +ovl_En_Hgo +ovl_En_Zov +ovl_En_Ah +ovl_Obj_Hgdoor +ovl_Bg_Ikana_Bombwall +ovl_Bg_Ikana_Ray +ovl_Bg_Ikana_Shutter +ovl_Bg_Haka_Bombwall +ovl_Bg_Haka_Tomb +ovl_En_Sc_Ruppe +ovl_Bg_Iknv_Doukutu +ovl_Bg_Iknv_Obj +ovl_En_Pamera +ovl_Obj_HsStump +ovl_En_Hidden_Nuts +ovl_En_Zow +ovl_En_Talk +ovl_En_Al +ovl_En_Tab +ovl_En_Nimotsu +ovl_En_Hit_Tag +ovl_En_Ruppecrow +ovl_En_Tanron4 +ovl_En_Tanron5 +ovl_En_Tanron6 +ovl_En_Daiku2 +ovl_En_Muto +ovl_En_Baisen +ovl_En_Heishi +ovl_En_Demo_heishi +ovl_En_Dt +ovl_En_Cha +ovl_Obj_Dinner +ovl_Eff_Lastday +ovl_Bg_Ikana_Dharma +ovl_En_Akindonuts +ovl_Eff_Stk +ovl_En_Ig +ovl_En_Rg +ovl_En_Osk +ovl_En_Sth2 +ovl_En_Yb +ovl_En_Rz +ovl_En_Scopecoin +ovl_En_Bjt +ovl_En_Bomjima +ovl_En_Bomjimb +ovl_En_Bombers +ovl_En_Bombers2 +ovl_En_Bombal +ovl_Obj_Moon_Stone +ovl_Obj_Mu_Pict +ovl_Bg_Ikninside +ovl_Eff_Zoraband +ovl_Obj_Kepn_Koya +ovl_Obj_Usiyane +ovl_En_Nnh +ovl_Obj_Kzsaku +ovl_Obj_Milk_Bin +ovl_En_Kitan +ovl_Bg_Astr_Bombwall +ovl_Bg_Iknin_Susceil +ovl_En_Bsb +ovl_En_Recepgirl +ovl_En_Thiefbird +ovl_En_Jgame_Tsn +ovl_Obj_Jgame_Light +ovl_Obj_Yado +ovl_Demo_Syoten +ovl_Demo_Moonend +ovl_Bg_Lbfshot +ovl_Bg_Last_Bwall +ovl_En_And +ovl_En_Invadepoh_Demo +ovl_Obj_Danpeilift +ovl_En_Fall2 +ovl_Dm_Al +ovl_Dm_An +ovl_Dm_Ah +ovl_Dm_Nb +ovl_En_Drs +ovl_En_Ending_Hero +ovl_Dm_Bal +ovl_En_Paper +ovl_En_Hint_Skb +ovl_Dm_Tag +ovl_En_Bh +ovl_En_Ending_Hero2 +ovl_En_Ending_Hero3 +ovl_En_Ending_Hero4 +ovl_En_Ending_Hero5 +ovl_En_Ending_Hero6 +ovl_Dm_Gm +ovl_Obj_Swprize +ovl_En_Invisible_Ruppe +ovl_Obj_Ending +ovl_En_Rsn +gameplay_keep +gameplay_field_keep +gameplay_dangeon_keep +gameplay_object_exchange_static +object_link_boy +object_link_child +object_link_goron +object_link_zora +object_link_nuts +object_mask_ki_tan +object_mask_rabit +object_mask_skj +object_mask_truth +object_mask_gibudo +object_mask_json +object_mask_kerfay +object_mask_bigelf +object_mask_kyojin +object_mask_romerny +object_mask_posthat +object_mask_zacho +object_mask_stone +object_mask_bree +object_mask_gero +object_mask_yofukasi +object_mask_meoto +object_mask_dancer +object_mask_bakuretu +object_mask_bu_san +object_mask_goron +object_mask_zora +object_mask_nuts +object_mask_boy +object_box +object_okuta +object_wallmaster +object_dy_obj +object_firefly +object_dodongo +object_niw +object_tite +object_ph +object_dinofos +object_zl1 +object_bubble +object_test3 +object_famos +object_st +object_thiefbird +object_bombf +object_am +object_dekubaba +object_warp1 +object_b_heart +object_dekunuts +object_bb +object_death +object_hata +object_wood02 +object_trap +object_vm +object_efc_star_field +object_rd +object_yukimura_obj +object_horse_link_child +object_syokudai +object_efc_tw +object_gi_key +object_mir_ray +object_ctower_rot +object_bdoor +object_sb +object_gi_melody +object_gi_heart +object_gi_compass +object_gi_bosskey +object_gi_nuts +object_gi_hearts +object_gi_arrowcase +object_gi_bombpouch +object_in +object_os_anime +object_gi_bottle +object_gi_stick +object_gi_map +object_oF1d_map +object_ru2 +object_gi_magicpot +object_gi_bomb_1 +object_ma2 +object_gi_purse +object_rr +object_gi_arrow +object_gi_bomb_2 +object_gi_shield_2 +object_gi_hookshot +object_gi_ocarina +object_gi_milk +object_ma1 +object_ny +object_fr +object_gi_bow +object_gi_glasses +object_gi_liquid +object_ani +object_gi_shield_3 +object_gi_bean +object_gi_fish +object_gi_longsword +object_zo +object_umajump +object_mastergolon +object_masterzoora +object_aob +object_ik +object_ahg +object_cne +object_bji +object_bba +object_an1 +object_boj +object_fz +object_bob +object_ge1 +object_yabusame_point +object_d_hsblock +object_d_lift +object_mamenoki +object_goroiwa +object_toryo +object_daiku +object_nwc +object_gm +object_ms +object_hs +object_lightswitch +object_kusa +object_tsubo +object_kanban +object_owl +object_mk +object_fu +object_gi_ki_tan_mask +object_gi_mask18 +object_gi_rabit_mask +object_gi_truth_mask +object_stream +object_mm +object_js +object_cs +object_gi_soldout +object_mag +object_gi_golonmask +object_gi_zoramask +object_ka +object_zg +object_gi_m_arrow +object_ds2 +object_fish +object_gi_sutaru +object_ssh +object_bigslime +object_bg +object_bombiwa +object_hintnuts +object_rs +object_gla +object_geldb +object_dog +object_kibako2 +object_dns +object_dnk +object_gi_insect +object_gi_ghost +object_gi_soul +object_f40_obj +object_gi_rupy +object_po_composer +object_mu +object_wf +object_skb +object_gs +object_ps +object_omoya_obj +object_crow +object_cow +object_gi_sword_1 +object_zl4 +object_grasshopper +object_boyo +object_fwall +object_jso +object_knight +object_icicle +object_spdweb +object_boss01 +object_boss02 +object_boss03 +object_boss04 +object_boss05 +object_boss07 +object_raf +object_funen +object_raillift +object_numa_obj +object_flowerpot +object_spinyroll +object_ice_block +object_keikoku_demo +object_slime +object_pr +object_f52_obj +object_f53_obj +object_kibako +object_sek +object_gmo +object_bat +object_sekihil +object_sekihig +object_sekihin +object_sekihiz +object_wiz +object_ladder +object_mkk +object_keikoku_obj +object_sichitai_obj +object_dekucity_ana_obj +object_rat +object_water_effect +object_dblue_object +object_bal +object_warp_uzu +object_driftice +object_fall +object_hanareyama_obj +object_crace_object +object_dno +object_obj_tokeidai +object_eg +object_tru +object_trt +object_hakugin_obj +object_horse_game_check +object_stk +object_mnk +object_gi_bottle_red +object_tokei_tobira +object_az +object_twig +object_dekucity_obj +object_po_fusen +object_racetsubo +object_ha +object_bigokuta +object_open_obj +object_fu_kaiten +object_fu_mato +object_mtoride +object_osn +object_tokei_step +object_lotus +object_tl +object_dkjail_obj +object_visiblock +object_tsn +object_ds2n +object_fsn +object_shn +object_bigicicle +object_gi_bottle_15 +object_tk +object_market_obj +object_gi_reserve00 +object_gi_reserve01 +object_lightblock +object_takaraya_objects +object_wdhand +object_sdn +object_snowwd +object_giant +object_comb +object_hana +object_boss_hakugin +object_meganeana_obj +object_gi_nutsmask +object_stk2 +object_spot11_obj +object_danpei_object +object_dhouse +object_hakaisi +object_po +object_snowman +object_po_sisters +object_pp +object_goronswitch +object_delf +object_botihasira +object_gi_bigbomb +object_pst +object_bsmask +object_spidertent +object_zoraegg +object_kbt +object_gg +object_maruta +object_ghaka +object_oyu +object_dnq +object_dai +object_kgy +object_fb +object_taisou +object_gk +object_haka_obj +object_dnt +object_yukiyama +object_icefloe +object_gi_gold_dust +object_gi_bottle_16 +object_gi_bottle_22 +object_bee +object_ot +object_utubo +object_dora +object_gi_loach +object_gi_seahorse +object_bigpo +object_hariko +object_dnj +object_sinkai_kabe +object_kin2_obj +object_ishi +object_hakugin_demo +object_jg +object_gi_sword_2 +object_gi_sword_3 +object_gi_sword_4 +object_um +object_rb +object_mbar_obj +object_ikana_obj +object_kz +object_tokei_turret +object_zog +object_rotlift +object_posthouse_obj +object_gi_mask09 +object_gi_mask14 +object_gi_mask15 +object_inibs_object +object_tree +object_kaizoku_obj +object_gi_reserve_b_00 +object_gi_reserve_c_00 +object_zob +object_milkbar +object_dmask +object_gi_reserve_c_01 +object_zod +object_kumo30 +object_obj_yasi +object_tanron1 +object_tanron2 +object_tanron3 +object_gi_magicmushroom +object_obj_chan +object_gi_mask10 +object_zos +object_an2 +object_an3 +object_f40_switch +object_lodmoon +object_tro +object_gi_mask12 +object_gi_mask23 +object_gi_bottle_21 +object_gi_camera +object_kamejima +object_nb +object_harfgibud +object_zov +object_ah +object_hgdoor +object_dor01 +object_dor02 +object_dor03 +object_dor04 +object_last_obj +object_redead_obj +object_ikninside_obj +object_iknv_obj +object_pamera +object_hsstump +object_zm +object_al +object_tab +object_secom_obj +object_dt +object_gi_mask03 +object_cha +object_obj_dinner +object_gi_reserve_b_01 +object_lastday +object_bai +object_ikn_demo +object_gi_fieldmap +object_big_fwall +object_hunsui +object_uch +object_tanron4 +object_tanron5 +object_in2 +object_yb +object_rz +object_bjt +object_taru +object_moonston +object_gi_schedule +object_gi_stonemask +object_zoraband +object_kepn_koya +object_obj_usiyane +object_gi_mask05 +object_gi_mask11 +object_gi_mask20 +object_nnh +object_kzsaku +object_obj_milk_bin +object_random_obj +object_kujiya +object_kitan +object_gi_mask06 +object_gi_mask16 +object_astr_obj +object_bsb +object_fall2 +object_sth +object_gi_mssa +object_smtower +object_gi_mask21 +object_yado_obj +object_syoten +object_moonend +object_ob +object_gi_bottle_04 +object_and +object_obj_danpeilift +object_drs +object_msmo +object_an4 +object_wdor01 +object_wdor02 +object_wdor03 +object_wdor04 +object_wdor05 +object_stk3 +object_kinsta1_obj +object_kinsta2_obj +object_bh +object_gi_mask17 +object_gi_mask22 +object_lbfshot +object_fusen +object_ending_obj +object_gi_mask13 +scene_texture_01 +scene_texture_02 +scene_texture_03 +scene_texture_04 +scene_texture_05 +scene_texture_06 +scene_texture_07 +scene_texture_08 +nintendo_rogo_static +title_static +memerrmsg +locerrmsg +parameter_static +week_static +daytelop_static +ger_daytelop_static +fra_daytelop_static +esp_daytelop_static +d2_fine_static +d2_cloud_static +d2_fine_pal_static +elf_message_field +elf_message_ydan +Z2_20SICHITAI2 +Z2_20SICHITAI2_room_00 +Z2_20SICHITAI2_room_01 +Z2_20SICHITAI2_room_02 +Z2_WITCH_SHOP +Z2_WITCH_SHOP_room_00 +Z2_LAST_BS +Z2_LAST_BS_room_00 +Z2_HAKASHITA +Z2_HAKASHITA_room_00 +Z2_HAKASHITA_room_01 +Z2_HAKASHITA_room_02 +Z2_HAKASHITA_room_03 +Z2_HAKASHITA_room_04 +Z2_AYASHIISHOP +Z2_AYASHIISHOP_room_00 +Z2_AYASHIISHOP_room_01 +Z2_OMOYA +Z2_OMOYA_room_00 +Z2_OMOYA_room_01 +Z2_OMOYA_room_02 +Z2_BOWLING +Z2_BOWLING_room_00 +Z2_SONCHONOIE +Z2_SONCHONOIE_room_00 +Z2_SONCHONOIE_room_01 +Z2_SONCHONOIE_room_02 +Z2_SONCHONOIE_room_03 +Z2_IKANA +Z2_IKANA_room_00 +Z2_IKANA_room_01 +Z2_IKANA_room_02 +Z2_IKANA_room_03 +Z2_IKANA_room_04 +Z2_KAIZOKU +Z2_KAIZOKU_room_00 +Z2_MILK_BAR +Z2_MILK_BAR_room_00 +Z2_INISIE_N +Z2_INISIE_N_room_00 +Z2_INISIE_N_room_01 +Z2_INISIE_N_room_02 +Z2_INISIE_N_room_03 +Z2_INISIE_N_room_04 +Z2_INISIE_N_room_05 +Z2_INISIE_N_room_06 +Z2_INISIE_N_room_07 +Z2_INISIE_N_room_08 +Z2_INISIE_N_room_09 +Z2_INISIE_N_room_10 +Z2_INISIE_N_room_11 +Z2_TAKARAYA +Z2_TAKARAYA_room_00 +Z2_INISIE_R +Z2_INISIE_R_room_00 +Z2_INISIE_R_room_01 +Z2_INISIE_R_room_02 +Z2_INISIE_R_room_03 +Z2_INISIE_R_room_04 +Z2_INISIE_R_room_05 +Z2_INISIE_R_room_06 +Z2_INISIE_R_room_07 +Z2_INISIE_R_room_08 +Z2_INISIE_R_room_09 +Z2_INISIE_R_room_10 +Z2_INISIE_R_room_11 +Z2_OKUJOU +Z2_OKUJOU_room_00 +Z2_OPENINGDAN +Z2_OPENINGDAN_room_00 +Z2_OPENINGDAN_room_01 +Z2_MITURIN +Z2_MITURIN_room_00 +Z2_MITURIN_room_01 +Z2_MITURIN_room_02 +Z2_MITURIN_room_03 +Z2_MITURIN_room_04 +Z2_MITURIN_room_05 +Z2_MITURIN_room_06 +Z2_MITURIN_room_07 +Z2_MITURIN_room_08 +Z2_MITURIN_room_09 +Z2_MITURIN_room_10 +Z2_MITURIN_room_11 +Z2_MITURIN_room_12 +Z2_13HUBUKINOMITI +Z2_13HUBUKINOMITI_room_00 +Z2_CASTLE +Z2_CASTLE_room_00 +Z2_CASTLE_room_01 +Z2_CASTLE_room_02 +Z2_CASTLE_room_03 +Z2_CASTLE_room_04 +Z2_CASTLE_room_05 +Z2_CASTLE_room_06 +Z2_CASTLE_room_07 +Z2_CASTLE_room_08 +Z2_CASTLE_room_09 +Z2_DEKUTES +Z2_DEKUTES_room_00 +Z2_MITURIN_BS +Z2_MITURIN_BS_room_00 +Z2_SYATEKI_MIZU +Z2_SYATEKI_MIZU_room_00 +Z2_HAKUGIN +Z2_HAKUGIN_room_00 +Z2_HAKUGIN_room_01 +Z2_HAKUGIN_room_02 +Z2_HAKUGIN_room_03 +Z2_HAKUGIN_room_04 +Z2_HAKUGIN_room_05 +Z2_HAKUGIN_room_06 +Z2_HAKUGIN_room_07 +Z2_HAKUGIN_room_08 +Z2_HAKUGIN_room_09 +Z2_HAKUGIN_room_10 +Z2_HAKUGIN_room_11 +Z2_HAKUGIN_room_12 +Z2_HAKUGIN_room_13 +Z2_ROMANYMAE +Z2_ROMANYMAE_room_00 +Z2_PIRATE +Z2_PIRATE_room_00 +Z2_PIRATE_room_01 +Z2_PIRATE_room_02 +Z2_PIRATE_room_03 +Z2_PIRATE_room_04 +Z2_PIRATE_room_05 +Z2_PIRATE_room_06 +Z2_PIRATE_room_07 +Z2_PIRATE_room_08 +Z2_PIRATE_room_09 +Z2_PIRATE_room_10 +Z2_PIRATE_room_11 +Z2_PIRATE_room_12 +Z2_PIRATE_room_13 +Z2_PIRATE_room_14 +Z2_SYATEKI_MORI +Z2_SYATEKI_MORI_room_00 +Z2_SINKAI +Z2_SINKAI_room_00 +Z2_YOUSEI_IZUMI +Z2_YOUSEI_IZUMI_room_00 +Z2_YOUSEI_IZUMI_room_01 +Z2_YOUSEI_IZUMI_room_02 +Z2_YOUSEI_IZUMI_room_03 +Z2_YOUSEI_IZUMI_room_04 +Z2_KINSTA1 +Z2_KINSTA1_room_00 +Z2_KINSTA1_room_01 +Z2_KINSTA1_room_02 +Z2_KINSTA1_room_03 +Z2_KINSTA1_room_04 +Z2_KINSTA1_room_05 +Z2_KINDAN2 +Z2_KINDAN2_room_00 +Z2_KINDAN2_room_01 +Z2_KINDAN2_room_02 +Z2_KINDAN2_room_03 +Z2_KINDAN2_room_04 +Z2_KINDAN2_room_05 +Z2_TENMON_DAI +Z2_TENMON_DAI_room_00 +Z2_TENMON_DAI_room_01 +Z2_LAST_DEKU +Z2_LAST_DEKU_room_00 +Z2_LAST_DEKU_room_01 +Z2_22DEKUCITY +Z2_22DEKUCITY_room_00 +Z2_22DEKUCITY_room_01 +Z2_22DEKUCITY_room_02 +Z2_KAJIYA +Z2_KAJIYA_room_00 +Z2_00KEIKOKU +Z2_00KEIKOKU_room_00 +Z2_POSTHOUSE +Z2_POSTHOUSE_room_00 +Z2_LABO +Z2_LABO_room_00 +Z2_DANPEI2TEST +Z2_DANPEI2TEST_room_00 +Z2_DANPEI2TEST_room_01 +Z2_16GORON_HOUSE +Z2_16GORON_HOUSE_room_00 +Z2_16GORON_HOUSE_room_01 +Z2_33ZORACITY +Z2_33ZORACITY_room_00 +Z2_8ITEMSHOP +Z2_8ITEMSHOP_room_00 +Z2_F01 +Z2_F01_room_00 +Z2_INISIE_BS +Z2_INISIE_BS_room_00 +Z2_30GYOSON +Z2_30GYOSON_room_00 +Z2_31MISAKI +Z2_31MISAKI_room_00 +Z2_TAKARAKUJI +Z2_TAKARAKUJI_room_00 +Z2_TORIDE +Z2_TORIDE_room_00 +Z2_FISHERMAN +Z2_FISHERMAN_room_00 +Z2_GORONSHOP +Z2_GORONSHOP_room_00 +Z2_DEKU_KING +Z2_DEKU_KING_room_00 +Z2_LAST_GORON +Z2_LAST_GORON_room_00 +Z2_LAST_GORON_room_01 +Z2_24KEMONOMITI +Z2_24KEMONOMITI_room_00 +Z2_F01_B +Z2_F01_B_room_00 +Z2_F01C +Z2_F01C_room_00 +Z2_BOTI +Z2_BOTI_room_00 +Z2_BOTI_room_01 +Z2_HAKUGIN_BS +Z2_HAKUGIN_BS_room_00 +Z2_20SICHITAI +Z2_20SICHITAI_room_00 +Z2_20SICHITAI_room_01 +Z2_20SICHITAI_room_02 +Z2_21MITURINMAE +Z2_21MITURINMAE_room_00 +Z2_LAST_ZORA +Z2_LAST_ZORA_room_00 +Z2_11GORONNOSATO2 +Z2_11GORONNOSATO2_room_00 +Z2_11GORONNOSATO2_room_01 +Z2_SEA +Z2_SEA_room_00 +Z2_SEA_room_01 +Z2_SEA_room_02 +Z2_SEA_room_03 +Z2_SEA_room_04 +Z2_SEA_room_05 +Z2_SEA_room_06 +Z2_SEA_room_07 +Z2_SEA_room_08 +Z2_SEA_room_09 +Z2_SEA_room_10 +Z2_SEA_room_11 +Z2_SEA_room_12 +Z2_SEA_room_13 +Z2_SEA_room_14 +Z2_SEA_room_15 +Z2_35TAKI +Z2_35TAKI_room_00 +Z2_REDEAD +Z2_REDEAD_room_00 +Z2_REDEAD_room_01 +Z2_REDEAD_room_02 +Z2_REDEAD_room_03 +Z2_REDEAD_room_04 +Z2_REDEAD_room_05 +Z2_REDEAD_room_06 +Z2_REDEAD_room_07 +Z2_REDEAD_room_08 +Z2_REDEAD_room_09 +Z2_REDEAD_room_10 +Z2_REDEAD_room_11 +Z2_REDEAD_room_12 +Z2_REDEAD_room_13 +Z2_BANDROOM +Z2_BANDROOM_room_00 +Z2_BANDROOM_room_01 +Z2_BANDROOM_room_02 +Z2_BANDROOM_room_03 +Z2_BANDROOM_room_04 +Z2_11GORONNOSATO +Z2_11GORONNOSATO_room_00 +Z2_11GORONNOSATO_room_01 +Z2_GORON_HAKA +Z2_GORON_HAKA_room_00 +Z2_SECOM +Z2_SECOM_room_00 +Z2_SECOM_room_01 +Z2_10YUKIYAMANOMURA +Z2_10YUKIYAMANOMURA_room_00 +Z2_TOUGITES +Z2_TOUGITES_room_00 +Z2_DANPEI +Z2_DANPEI_room_00 +Z2_DANPEI_room_01 +Z2_DANPEI_room_02 +Z2_DANPEI_room_03 +Z2_DANPEI_room_04 +Z2_DANPEI_room_05 +Z2_DANPEI_room_06 +Z2_DANPEI_room_07 +Z2_DANPEI_room_08 +Z2_IKANAMAE +Z2_IKANAMAE_room_00 +Z2_DOUJOU +Z2_DOUJOU_room_00 +Z2_MUSICHOUSE +Z2_MUSICHOUSE_room_00 +Z2_IKNINSIDE +Z2_IKNINSIDE_room_00 +Z2_IKNINSIDE_room_01 +Z2_MAP_SHOP +Z2_MAP_SHOP_room_00 +Z2_F40 +Z2_F40_room_00 +Z2_F41 +Z2_F41_room_00 +Z2_10YUKIYAMANOMURA2 +Z2_10YUKIYAMANOMURA2_room_00 +Z2_10YUKIYAMANOMURA2_room_01 +Z2_14YUKIDAMANOMITI +Z2_14YUKIDAMANOMITI_room_00 +Z2_12HAKUGINMAE +Z2_12HAKUGINMAE_room_00 +Z2_17SETUGEN +Z2_17SETUGEN_room_00 +Z2_17SETUGEN2 +Z2_17SETUGEN2_room_00 +Z2_SEA_BS +Z2_SEA_BS_room_00 +Z2_RANDOM +Z2_RANDOM_room_00 +Z2_RANDOM_room_01 +Z2_RANDOM_room_02 +Z2_RANDOM_room_03 +Z2_RANDOM_room_04 +Z2_RANDOM_room_05 +Z2_YADOYA +Z2_YADOYA_room_00 +Z2_YADOYA_room_01 +Z2_YADOYA_room_02 +Z2_YADOYA_room_03 +Z2_YADOYA_room_04 +Z2_KONPEKI_ENT +Z2_KONPEKI_ENT_room_00 +Z2_INSIDETOWER +Z2_INSIDETOWER_room_00 +Z2_INSIDETOWER_room_01 +Z2_26SARUNOMORI +Z2_26SARUNOMORI_room_00 +Z2_26SARUNOMORI_room_01 +Z2_26SARUNOMORI_room_02 +Z2_26SARUNOMORI_room_03 +Z2_26SARUNOMORI_room_04 +Z2_26SARUNOMORI_room_05 +Z2_26SARUNOMORI_room_06 +Z2_26SARUNOMORI_room_07 +Z2_26SARUNOMORI_room_08 +Z2_LOST_WOODS +Z2_LOST_WOODS_room_00 +Z2_LOST_WOODS_room_01 +Z2_LOST_WOODS_room_02 +Z2_LAST_LINK +Z2_LAST_LINK_room_00 +Z2_LAST_LINK_room_01 +Z2_LAST_LINK_room_02 +Z2_LAST_LINK_room_03 +Z2_LAST_LINK_room_04 +Z2_LAST_LINK_room_05 +Z2_LAST_LINK_room_06 +Z2_LAST_LINK_room_07 +Z2_SOUGEN +Z2_SOUGEN_room_00 +Z2_BOMYA +Z2_BOMYA_room_00 +Z2_KYOJINNOMA +Z2_KYOJINNOMA_room_00 +Z2_KOEPONARACE +Z2_KOEPONARACE_room_00 +Z2_GORONRACE +Z2_GORONRACE_room_00 +Z2_TOWN +Z2_TOWN_room_00 +Z2_ICHIBA +Z2_ICHIBA_room_00 +Z2_BACKTOWN +Z2_BACKTOWN_room_00 +Z2_CLOCKTOWER +Z2_CLOCKTOWER_room_00 +Z2_ALLEY +Z2_ALLEY_room_00 +SPOT00 +SPOT00_room_00 +KAKUSIANA +KAKUSIANA_room_00 +KAKUSIANA_room_01 +KAKUSIANA_room_02 +KAKUSIANA_room_03 +KAKUSIANA_room_04 +KAKUSIANA_room_05 +KAKUSIANA_room_06 +KAKUSIANA_room_07 +KAKUSIANA_room_08 +KAKUSIANA_room_09 +KAKUSIANA_room_10 +KAKUSIANA_room_11 +KAKUSIANA_room_12 +KAKUSIANA_room_13 +KAKUSIANA_room_14 +bump_texture_static +anime_model_1_static +anime_model_2_static +anime_model_3_static +anime_model_4_static +anime_model_5_static +anime_model_6_static +anime_texture_1_static +anime_texture_2_static +anime_texture_3_static +anime_texture_4_static +anime_texture_5_static +anime_texture_6_static +softsprite_matrix_static diff --git a/OTRExporter/CMakeLists.txt b/OTRExporter/CMakeLists.txt index c582148..87d640f 100644 --- a/OTRExporter/CMakeLists.txt +++ b/OTRExporter/CMakeLists.txt @@ -80,7 +80,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows") set_target_properties(${PROJECT_NAME} PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE "TRUE" ) - elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x86") + elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") set_target_properties(${PROJECT_NAME} PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE "TRUE" ) @@ -91,7 +91,7 @@ endif() ################################################################################ if (CMAKE_SYSTEM_NAME STREQUAL "Windows") get_property(MSVC_RUNTIME_LIBRARY_DEFAULT TARGET ${PROJECT_NAME} PROPERTY MSVC_RUNTIME_LIBRARY) - if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") + if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") string(CONCAT "MSVC_RUNTIME_LIBRARY_STR" $<$: MultiThreadedDebug @@ -120,7 +120,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows") "_CRT_SECURE_NO_WARNINGS;" STORMLIB_NO_AUTO_LINK ) - elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x86") + elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") target_compile_definitions(${PROJECT_NAME} PRIVATE "$<$:" "_DEBUG;" @@ -183,7 +183,7 @@ if(MSVC) ${DEFAULT_CXX_DEBUG_INFORMATION_FORMAT}; ${DEFAULT_CXX_EXCEPTION_HANDLING} ) - elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x86") + elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") target_compile_options(${PROJECT_NAME} PRIVATE $<$: /Oi; @@ -204,7 +204,7 @@ if(MSVC) > /SUBSYSTEM:CONSOLE ) - elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x86") + elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") target_link_options(${PROJECT_NAME} PRIVATE $<$: /DEBUG; diff --git a/OTRExporter/CutsceneExporter.cpp b/OTRExporter/CutsceneExporter.cpp index f9d24a6..6da70a5 100644 --- a/OTRExporter/CutsceneExporter.cpp +++ b/OTRExporter/CutsceneExporter.cpp @@ -3,443 +3,684 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) { - ZCutscene* cs = (ZCutscene*)res; + ZCutscene* cs = (ZCutscene*)res; WriteHeader(cs, outPath, writer, static_cast(SOH::ResourceType::SOH_Cutscene)); - writer->Write((uint32_t)0); - - const auto currentStream = writer->GetBaseAddress(); - - writer->Write(CS_BEGIN_CUTSCENE(cs->numCommands, cs->endFrame)); - - for (size_t i = 0; i < cs->commands.size(); i++) - { - switch (cs->commands[i]->commandID) - { - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE_SPLINE: - { - CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; - - writer->Write(CS_CMD_CAM_EYE); - writer->Write(CMD_HH(0x0001, ((CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i])->startFrame)); - writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; - writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); - writer->Write(point->viewAngle); - writer->Write(CMD_HH(point->posX, point->posY)); - writer->Write(CMD_HH(point->posZ, point->unused)); - } - } - break; - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE: - { - CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; - - writer->Write(CS_CMD_CAM_AT); - writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); - writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; - writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); - writer->Write(point->viewAngle); - writer->Write(CMD_HH(point->posX, point->posY)); - writer->Write(CMD_HH(point->posZ, point->unused)); - } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_MISC: - { - writer->Write(CS_CMD_MISC); - writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); - for (const auto& e : cs->commands[i]->entries) //All in OOT seem to only have 1 entry - { - CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); - writer->Write(CMD_W(cmd->unused1)); - writer->Write(CMD_W(cmd->unused2)); - writer->Write(CMD_W(cmd->unused3)); - writer->Write(CMD_W(cmd->unused4)); - writer->Write(CMD_W(cmd->unused5)); - writer->Write(CMD_W(cmd->unused6)); - writer->Write(CMD_W(cmd->unused7)); - writer->Write(CMD_W(cmd->unused8)); - writer->Write(CMD_W(cmd->unused9)); - writer->Write(CMD_W(cmd->unused10)); - } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_LIGHT_SETTING: - { - writer->Write(CS_CMD_SET_LIGHTING); - writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); - writer->Write(CMD_W(cmd->unused1)); - writer->Write(CMD_W(cmd->unused2)); - writer->Write(CMD_W(cmd->unused3)); - writer->Write(CMD_W(cmd->unused4)); - writer->Write(CMD_W(cmd->unused5)); - writer->Write(CMD_W(cmd->unused6)); - writer->Write(CMD_W(cmd->unused7)); - writer->Write((uint32_t)0x0); - writer->Write((uint32_t)0x0); - writer->Write((uint32_t)0x0); - } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE_SPLINE_REL_TO_PLAYER: - { - CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; - - writer->Write(CS_CMD_CAM_EYE_REL_TO_PLAYER); - writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); - writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; - writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); - writer->Write(point->viewAngle); - writer->Write(CMD_HH(point->posX, point->posY)); - writer->Write(CMD_HH(point->posZ, point->unused)); - } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE_REL_TO_PLAYER: - { - CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; - - writer->Write(CS_CMD_CAM_AT_REL_TO_PLAYER); - writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); - writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; - writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); - writer->Write(point->viewAngle); - writer->Write(CMD_HH(point->posX, point->posY)); - writer->Write(CMD_HH(point->posZ, point->unused)); - } - break; - } - - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE: // Not used in OOT - break; - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT: // Not used in OOT - break; - - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_RUMBLE_CONTROLLER: - { - writer->Write(CS_CMD_09); - writer->Write((uint32_t)CMD_W(((CutsceneOoTCommand_Rumble*)cs->commands[i])->entries.size())); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_Rumble* r = (CutsceneOoTSubCommandEntry_Rumble*)e; - writer->Write(CMD_HH(r->base, r->startFrame)); - writer->Write(CMD_HBB(e->endFrame, r->sourceStrength, r->duration)); - writer->Write(CMD_BBH(r->decreaseRate, r->unk_09, r->unk_0A)); - } - break; - } - //case 0x15://Both unused in OoT - //case 0x1A://(uint32_t)CutsceneOoT_CommandType::Unknown: - { + writer->Write((uint32_t)0); + + const auto currentStream = writer->GetBaseAddress(); + + writer->Write(CS_BEGIN_CUTSCENE(cs->numCommands, cs->endFrame)); + + SaveMM(cs, writer); + + //CS_END + writer->Write(0xFFFFFFFF); + writer->Write((uint32_t)0); + + const auto endStream = writer->GetBaseAddress(); + writer->Seek((uint32_t)currentStream - 4, SeekOffsetType::Start); + writer->Write((uint32_t)((endStream - currentStream) / 4)); + writer->Seek((uint32_t)endStream, SeekOffsetType::Start); +} + +void OTRExporter_Cutscene::SaveOot(ZCutscene* cs, BinaryWriter* writer) { + + for (size_t i = 0; i < cs->commands.size(); i++) + { + switch (cs->commands[i]->commandID) + { + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE_SPLINE: + { + CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; + + writer->Write(CS_CMD_CAM_EYE); + writer->Write(CMD_HH(0x0001, ((CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i])->startFrame)); + writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); + + for (const auto& e : cs->commands[i]->entries) + { + CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; + writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); + writer->Write(point->viewAngle); + writer->Write(CMD_HH(point->posX, point->posY)); + writer->Write(CMD_HH(point->posZ, point->unused)); + } + } + break; + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE: + { + CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; + + writer->Write(CS_CMD_CAM_AT); + writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); + writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); + + for (const auto& e : cs->commands[i]->entries) + { + CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; + writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); + writer->Write(point->viewAngle); + writer->Write(CMD_HH(point->posX, point->posY)); + writer->Write(CMD_HH(point->posZ, point->unused)); + } + break; + } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_MISC: + { + writer->Write(CS_CMD_MISC); + writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); + for (const auto& e : cs->commands[i]->entries) //All in OOT seem to only have 1 entry + { + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); + writer->Write(CMD_W(cmd->unused1)); + writer->Write(CMD_W(cmd->unused2)); + writer->Write(CMD_W(cmd->unused3)); + writer->Write(CMD_W(cmd->unused4)); + writer->Write(CMD_W(cmd->unused5)); + writer->Write(CMD_W(cmd->unused6)); + writer->Write(CMD_W(cmd->unused7)); + writer->Write(CMD_W(cmd->unused8)); + writer->Write(CMD_W(cmd->unused9)); + writer->Write(CMD_W(cmd->unused10)); + } + break; + } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_LIGHT_SETTING: + { + writer->Write(CS_CMD_SET_LIGHTING); + writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); + for (const auto& e : cs->commands[i]->entries) + { + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); + writer->Write(CMD_W(cmd->unused1)); + writer->Write(CMD_W(cmd->unused2)); + writer->Write(CMD_W(cmd->unused3)); + writer->Write(CMD_W(cmd->unused4)); + writer->Write(CMD_W(cmd->unused5)); + writer->Write(CMD_W(cmd->unused6)); + writer->Write(CMD_W(cmd->unused7)); + writer->Write((uint32_t)0x0); + writer->Write((uint32_t)0x0); + writer->Write((uint32_t)0x0); + } + break; + } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE_SPLINE_REL_TO_PLAYER: + { + CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; + + writer->Write(CS_CMD_CAM_EYE_REL_TO_PLAYER); + writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); + writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); + + for (const auto& e : cs->commands[i]->entries) + { + CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; + writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); + writer->Write(point->viewAngle); + writer->Write(CMD_HH(point->posX, point->posY)); + writer->Write(CMD_HH(point->posZ, point->unused)); + } + break; + } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE_REL_TO_PLAYER: + { + CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; + + writer->Write(CS_CMD_CAM_AT_REL_TO_PLAYER); + writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); + writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); + + for (const auto& e : cs->commands[i]->entries) + { + CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; + writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); + writer->Write(point->viewAngle); + writer->Write(CMD_HH(point->posX, point->posY)); + writer->Write(CMD_HH(point->posZ, point->unused)); + } + break; + } + + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE: // Not used in OOT + break; + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT: // Not used in OOT + break; + + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_RUMBLE_CONTROLLER: + { + writer->Write(CS_CMD_09); + writer->Write((uint32_t)CMD_W(((CutsceneOoTCommand_Rumble*)cs->commands[i])->entries.size())); + + for (const auto& e : cs->commands[i]->entries) + { + CutsceneOoTSubCommandEntry_Rumble* r = (CutsceneOoTSubCommandEntry_Rumble*)e; + writer->Write(CMD_HH(r->base, r->startFrame)); + writer->Write(CMD_HBB(e->endFrame, r->sourceStrength, r->duration)); + writer->Write(CMD_BBH(r->decreaseRate, r->unk_09, r->unk_0A)); + } + break; + } + //case 0x15://Both unused in OoT + //case 0x1A://(uint32_t)CutsceneOoT_CommandType::Unknown: + { #if 0 - CutsceneCommandUnknown* cmdUnk = (CutsceneCommandUnknown*)cs->commands[i]; - writer->Write((uint32_t)cs->commands[i]->commandID); - writer->Write((uint32_t)cmdUnk->entries.size()); - - for (const auto e : cmdUnk->entries) - { - writer->Write(CMD_W(e->unused0)); - writer->Write(CMD_W(e->unused1)); - writer->Write(CMD_W(e->unused2)); - writer->Write(CMD_W(e->unused3)); - writer->Write(CMD_W(e->unused4)); - writer->Write(CMD_W(e->unused5)); - writer->Write(CMD_W(e->unused6)); - writer->Write(CMD_W(e->unused7)); - writer->Write(CMD_W(e->unused8)); - writer->Write(CMD_W(e->unused9)); - writer->Write(CMD_W(e->unused10)); - writer->Write(CMD_W(e->unused11)); - } + CutsceneCommandUnknown* cmdUnk = (CutsceneCommandUnknown*)cs->commands[i]; + writer->Write((uint32_t)cs->commands[i]->commandID); + writer->Write((uint32_t)cmdUnk->entries.size()); + + for (const auto e : cmdUnk->entries) + { + writer->Write(CMD_W(e->unused0)); + writer->Write(CMD_W(e->unused1)); + writer->Write(CMD_W(e->unused2)); + writer->Write(CMD_W(e->unused3)); + writer->Write(CMD_W(e->unused4)); + writer->Write(CMD_W(e->unused5)); + writer->Write(CMD_W(e->unused6)); + writer->Write(CMD_W(e->unused7)); + writer->Write(CMD_W(e->unused8)); + writer->Write(CMD_W(e->unused9)); + writer->Write(CMD_W(e->unused10)); + writer->Write(CMD_W(e->unused11)); + } #endif - } - break; - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TEXT: - { - writer->Write(CS_CMD_TEXTBOX); - writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_Text* textBox = (CutsceneOoTSubCommandEntry_Text*)e; - if (textBox->base == 0xFFFF) // CS_TEXT_NONE - { - writer->Write(CMD_HH(0xFFFF, textBox->startFrame)); - writer->Write(CMD_HH(textBox->endFrame, 0xFFFF)); - writer->Write(CMD_HH(0xFFFF, 0xFFFF)); - } - else // CS_TEXT_DISPLAY_TEXTBOX - { - writer->Write(CMD_HH(textBox->base, textBox->startFrame)); - writer->Write(CMD_HH(textBox->endFrame, textBox->type)); - writer->Write(CMD_HH(textBox->textId1, textBox->textId2)); - } - } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_PLAYER_CUE: //ActorAction0 - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_7: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_8: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_9: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_10: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_11: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_12: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_13: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_14: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_15: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_16: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_17: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_7: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_8: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_9: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_10: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_11: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_12: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_13: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_14: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_15: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_16: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_17: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_7: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_8: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_9: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_10: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_11: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_12: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_13: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_7: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_8: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_9: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_10: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_11: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_12: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_7: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_8: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_7: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_8_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_9_0: - { - writer->Write((uint32_t)cs->commands[i]->commandID); - writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_ActorCue* actorAct = (CutsceneOoTSubCommandEntry_ActorCue*)e; - writer->Write(CMD_HH(actorAct->base, actorAct->startFrame)); - writer->Write(CMD_HH(actorAct->endFrame, actorAct->rotX)); - writer->Write(CMD_HH(actorAct->rotY, actorAct->rotZ)); - writer->Write(CMD_W(actorAct->startPosX)); - writer->Write(CMD_W(actorAct->startPosY)); - writer->Write(CMD_W(actorAct->startPosZ)); - writer->Write(CMD_W(actorAct->endPosX)); - writer->Write(CMD_W(actorAct->endPosY)); - writer->Write(CMD_W(actorAct->endPosZ)); - writer->Write(CMD_W(actorAct->normalX)); - writer->Write(CMD_W(actorAct->normalY)); - writer->Write(CMD_W(actorAct->normalZ)); - } - - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TRANSITION: - { - CutsceneOoTCommand_Transition* cmdTFX = (CutsceneOoTCommand_Transition*)cs->commands[i]; - - writer->Write(CS_CMD_SCENE_TRANS_FX); - writer->Write((uint32_t)1); - writer->Write(CMD_HH((cmdTFX->base), cmdTFX->startFrame)); - writer->Write(CMD_HH((cmdTFX->endFrame), cmdTFX->endFrame)); - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_START_SEQ: - { - writer->Write(CS_CMD_PLAYBGM); - writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); - writer->Write(CMD_W(cmd->unused1)); - writer->Write(CMD_W(cmd->unused2)); - writer->Write(CMD_W(cmd->unused3)); - writer->Write(CMD_W(cmd->unused4)); - writer->Write(CMD_W(cmd->unused5)); - writer->Write(CMD_W(cmd->unused6)); - writer->Write(CMD_W(cmd->unused7)); - writer->Write((uint32_t)0); - writer->Write((uint32_t)0); - writer->Write((uint32_t)0); - } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_STOP_SEQ: - { - writer->Write(CS_CMD_STOPBGM); - writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); - writer->Write(CMD_W(cmd->unused1)); - writer->Write(CMD_W(cmd->unused2)); - writer->Write(CMD_W(cmd->unused3)); - writer->Write(CMD_W(cmd->unused4)); - writer->Write(CMD_W(cmd->unused5)); - writer->Write(CMD_W(cmd->unused6)); - writer->Write(CMD_W(cmd->unused7)); - writer->Write((uint32_t)0); - writer->Write((uint32_t)0); - writer->Write((uint32_t)0); - } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_FADE_OUT_SEQ: - { - writer->Write(CS_CMD_FADEBGM); - writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); - writer->Write(CMD_W(cmd->unused1)); - writer->Write(CMD_W(cmd->unused2)); - writer->Write(CMD_W(cmd->unused3)); - writer->Write(CMD_W(cmd->unused4)); - writer->Write(CMD_W(cmd->unused5)); - writer->Write(CMD_W(cmd->unused6)); - writer->Write(CMD_W(cmd->unused7)); - writer->Write((uint32_t)0); - writer->Write((uint32_t)0); - writer->Write((uint32_t)0); - } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TIME: - { - writer->Write(CS_CMD_SETTIME); - writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneSubCommandEntry_SetTime* t = (CutsceneSubCommandEntry_SetTime*)e; - writer->Write(CMD_HH(t->base, t->startFrame)); - writer->Write(CMD_HBB(t->endFrame, t->hour, t->minute)); - writer->Write((uint32_t)0); - //writer->Write((uint32_t)CMD_W(t->unk_08)); - } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_DESTINATION: - { - CutsceneOoTCommand_Destination* t = (CutsceneOoTCommand_Destination*)cs->commands[i]; - writer->Write(CS_CMD_TERMINATOR); - writer->Write((uint32_t)1); - writer->Write(CMD_HH(t->base, t->startFrame)); - writer->Write(CMD_HH(t->endFrame, t->endFrame)); - break; - } - default: - { - //writer->Write((uint32_t)cs->commands[i]->commandID); - printf("Undefined CS Opcode: %04X\n", cs->commands[i]->commandID); - } - break; - } - } - - //CS_END - writer->Write(0xFFFFFFFF); - writer->Write((uint32_t)0); - - const auto endStream = writer->GetBaseAddress(); - writer->Seek((uint32_t)currentStream - 4, SeekOffsetType::Start); - writer->Write((uint32_t)((endStream - currentStream) / 4)); - writer->Seek((uint32_t)endStream, SeekOffsetType::Start); + } + break; + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TEXT: + { + writer->Write(CS_CMD_TEXTBOX); + writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); + + for (const auto& e : cs->commands[i]->entries) + { + CutsceneOoTSubCommandEntry_Text* textBox = (CutsceneOoTSubCommandEntry_Text*)e; + if (textBox->base == 0xFFFF) // CS_TEXT_NONE + { + writer->Write(CMD_HH(0xFFFF, textBox->startFrame)); + writer->Write(CMD_HH(textBox->endFrame, 0xFFFF)); + writer->Write(CMD_HH(0xFFFF, 0xFFFF)); + } + else // CS_TEXT_DISPLAY_TEXTBOX + { + writer->Write(CMD_HH(textBox->base, textBox->startFrame)); + writer->Write(CMD_HH(textBox->endFrame, textBox->type)); + writer->Write(CMD_HH(textBox->textId1, textBox->textId2)); + } + } + break; + } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_PLAYER_CUE: //ActorAction0 + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_9: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_10: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_11: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_12: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_13: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_14: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_15: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_16: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_17: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_9: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_10: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_11: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_12: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_13: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_14: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_15: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_16: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_17: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_9: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_10: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_11: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_12: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_13: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_9: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_10: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_11: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_12: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_8_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_9_0: + { + writer->Write((uint32_t)cs->commands[i]->commandID); + writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); + + for (const auto& e : cs->commands[i]->entries) + { + CutsceneOoTSubCommandEntry_ActorCue* actorAct = (CutsceneOoTSubCommandEntry_ActorCue*)e; + writer->Write(CMD_HH(actorAct->base, actorAct->startFrame)); + writer->Write(CMD_HH(actorAct->endFrame, actorAct->rotX)); + writer->Write(CMD_HH(actorAct->rotY, actorAct->rotZ)); + writer->Write(CMD_W(actorAct->startPosX)); + writer->Write(CMD_W(actorAct->startPosY)); + writer->Write(CMD_W(actorAct->startPosZ)); + writer->Write(CMD_W(actorAct->endPosX)); + writer->Write(CMD_W(actorAct->endPosY)); + writer->Write(CMD_W(actorAct->endPosZ)); + writer->Write(CMD_W(actorAct->normalX)); + writer->Write(CMD_W(actorAct->normalY)); + writer->Write(CMD_W(actorAct->normalZ)); + } + + break; + } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TRANSITION: + { + CutsceneOoTCommand_Transition* cmdTFX = (CutsceneOoTCommand_Transition*)cs->commands[i]; + + writer->Write(CS_CMD_SCENE_TRANS_FX); + writer->Write((uint32_t)1); + writer->Write(CMD_HH((cmdTFX->base), cmdTFX->startFrame)); + writer->Write(CMD_HH((cmdTFX->endFrame), cmdTFX->endFrame)); + break; + } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_START_SEQ: + { + writer->Write(CS_CMD_PLAYBGM); + writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); + + for (const auto& e : cs->commands[i]->entries) + { + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); + writer->Write(CMD_W(cmd->unused1)); + writer->Write(CMD_W(cmd->unused2)); + writer->Write(CMD_W(cmd->unused3)); + writer->Write(CMD_W(cmd->unused4)); + writer->Write(CMD_W(cmd->unused5)); + writer->Write(CMD_W(cmd->unused6)); + writer->Write(CMD_W(cmd->unused7)); + writer->Write((uint32_t)0); + writer->Write((uint32_t)0); + writer->Write((uint32_t)0); + } + break; + } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_STOP_SEQ: + { + writer->Write(CS_CMD_STOPBGM); + writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); + + for (const auto& e : cs->commands[i]->entries) + { + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); + writer->Write(CMD_W(cmd->unused1)); + writer->Write(CMD_W(cmd->unused2)); + writer->Write(CMD_W(cmd->unused3)); + writer->Write(CMD_W(cmd->unused4)); + writer->Write(CMD_W(cmd->unused5)); + writer->Write(CMD_W(cmd->unused6)); + writer->Write(CMD_W(cmd->unused7)); + writer->Write((uint32_t)0); + writer->Write((uint32_t)0); + writer->Write((uint32_t)0); + } + break; + } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_FADE_OUT_SEQ: + { + writer->Write(CS_CMD_FADEBGM); + writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); + + for (const auto& e : cs->commands[i]->entries) + { + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); + writer->Write(CMD_W(cmd->unused1)); + writer->Write(CMD_W(cmd->unused2)); + writer->Write(CMD_W(cmd->unused3)); + writer->Write(CMD_W(cmd->unused4)); + writer->Write(CMD_W(cmd->unused5)); + writer->Write(CMD_W(cmd->unused6)); + writer->Write(CMD_W(cmd->unused7)); + writer->Write((uint32_t)0); + writer->Write((uint32_t)0); + writer->Write((uint32_t)0); + } + break; + } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TIME: + { + writer->Write(CS_CMD_SETTIME); + writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); + + for (const auto& e : cs->commands[i]->entries) + { + CutsceneSubCommandEntry_SetTime* t = (CutsceneSubCommandEntry_SetTime*)e; + writer->Write(CMD_HH(t->base, t->startFrame)); + writer->Write(CMD_HBB(t->endFrame, t->hour, t->minute)); + writer->Write((uint32_t)0); + //writer->Write((uint32_t)CMD_W(t->unk_08)); + } + break; + } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_DESTINATION: + { + CutsceneOoTCommand_Destination* t = (CutsceneOoTCommand_Destination*)cs->commands[i]; + writer->Write(CS_CMD_TERMINATOR); + writer->Write((uint32_t)1); + writer->Write(CMD_HH(t->base, t->startFrame)); + writer->Write(CMD_HH(t->endFrame, t->endFrame)); + break; + } + default: + { + //writer->Write((uint32_t)cs->commands[i]->commandID); + printf("Undefined CS Opcode: %04X\n", cs->commands[i]->commandID); + } + break; + } + } +} + +typedef enum { + /* -1 */ CS_TEXT_TYPE_NONE = -1, + /* 0 */ CS_TEXT_TYPE_DEFAULT, + /* 1 */ CS_TEXT_TYPE_1, + /* 2 */ CS_TEXT_OCARINA_ACTION, + /* 3 */ CS_TEXT_TYPE_3, + /* 4 */ CS_TEXT_TYPE_BOSSES_REMAINS, // use `altText1` in the Giant Cutscene if all remains are already obtained + /* 5 */ CS_TEXT_TYPE_ALL_NORMAL_MASKS +} CutsceneTextType; + +#define WRITE_CMD_PROLOG(cmd) writer->Write((uint32_t)cmd); writer->Write((uint32_t)cs->commands[i]->entries.size()); + +void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { + for (size_t i = 0; i < cs->commands.size(); i++) { + if (((cs->commands[i]->commandID >= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_100) && + (cs->commands[i]->commandID <= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_149)) || + (cs->commands[i]->commandID == (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_201) || + ((cs->commands[i]->commandID >= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_450) && + (cs->commands[i]->commandID <= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_599))) + { + WRITE_CMD_PROLOG(cs->commands[i]->commandID); + goto actorCue; + } + switch ((CutsceneMM_CommandType)cs->commands[i]->commandID) { + case CutsceneMM_CommandType::CS_CMD_TEXT: { + writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_TEXT); + writer->Write((uint32_t)cs->commands[i]->entries.size()); + for (const auto& e : cs->commands[i]->entries) { + auto* cmd = (CutsceneMMSubCommandEntry_Text*)e; + + switch ((CutsceneTextType)cmd->type) { + case CS_TEXT_TYPE_DEFAULT: // 0 + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->type)); + writer->Write(CMD_HH(cmd->textId1, cmd->textId2)); + break; + case CS_TEXT_TYPE_1: // 1 + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->type)); + writer->Write(CMD_HH(cmd->textId1, cmd->textId2)); + break; + case CS_TEXT_OCARINA_ACTION: //2 + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->type)); + writer->Write(CMD_HH(cmd->textId1, 0xFFFF)); + break; + case CS_TEXT_TYPE_3: // 3 + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->type)); + writer->Write(CMD_HH(cmd->textId1, cmd->textId2)); + break; + case CS_TEXT_TYPE_BOSSES_REMAINS: // 4 + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->type)); + writer->Write(CMD_HH(cmd->textId1, 0xFFFF)); + break; + case CS_TEXT_TYPE_ALL_NORMAL_MASKS: // 5 + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->type)); + writer->Write(CMD_HH(cmd->textId1, 0xFFFF)); + break; + case CS_TEXT_TYPE_NONE: // -1 + writer->Write(CMD_HH(0xFFFF, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, 0xFFFF)); + writer->Write(CMD_HH(0xFFFF, 0xFFFF)); + } + } + break; + } + + // BENTODO: Can these stay consilidated? + case CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE: { + writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE); + writer->Write((uint32_t)cs->commands[i]->entries.size()); + for (const auto e : cs->commands[i]->entries) { + auto* cmd = (CutsceneSubCommandEntry_Camera*)e; + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + } + break; + } + case CutsceneMM_CommandType::CS_CMD_MISC: { + writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_MISC); + writer->Write((uint32_t)cs->commands[i]->entries.size()); + for (const auto e : cs->commands[i]->entries) { + writer->Write(CMD_HH(e->base, e->startFrame)); + writer->Write(CMD_HH(e->endFrame, e->pad)); + } + break; + } + case CutsceneMM_CommandType::CS_CMD_LIGHT_SETTING: { + writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_LIGHT_SETTING); + writer->Write((uint32_t)cs->commands[i]->entries.size()); + for (const auto e : cs->commands[i]->entries) { + writer->Write(CMD_BBH(0, e->base, e->startFrame)); + writer->Write(CMD_HH(e->endFrame, e->endFrame)); + } + break; + } + + case CutsceneMM_CommandType::CS_CMD_TRANSITION: { + WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_TRANSITION); + + for (const auto e : cs->commands[i]->entries) { + writer->Write(CMD_HH(e->base, e->startFrame)); + writer->Write(CMD_HH(e->endFrame, e->endFrame)); + } + break; + } + case CutsceneMM_CommandType::CS_CMD_MOTION_BLUR: { + WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_MOTION_BLUR); + + for (const auto e : cs->commands[i]->entries) { + writer->Write(CMD_HH(e->base, e->startFrame)); + writer->Write(CMD_HH(e->endFrame, e->endFrame)); + } + break; + } + case CutsceneMM_CommandType::CS_CMD_GIVE_TATL: { + WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_GIVE_TATL); + + for (const auto e : cs->commands[i]->entries) { + writer->Write(CMD_HH(e->base, e->startFrame)); + writer->Write(CMD_HH(e->endFrame, e->endFrame)); + } + break; + } + case CutsceneMM_CommandType::CS_CMD_STOP_SEQ: + case CutsceneMM_CommandType::CS_CMD_START_SEQ: { + WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_START_SEQ); + for (const auto e : cs->commands[i]->entries) { + writer->Write(CMD_BBH(0, e->base, e->startFrame)); + writer->Write(CMD_HH(e->endFrame, e->endFrame)); + } + break; + } + case CutsceneMM_CommandType::CS_CMD_SFX_REVERB_INDEX_2: + case CutsceneMM_CommandType::CS_CMD_SFX_REVERB_INDEX_1: + case CutsceneMM_CommandType::CS_CMD_MODIFY_SEQ: + + case CutsceneMM_CommandType::CS_CMD_START_AMBIENCE: + case CutsceneMM_CommandType::CS_CMD_FADE_OUT_AMBIENCE: + case CutsceneMM_CommandType::CS_CMD_DESTINATION: + case CutsceneMM_CommandType::CS_CMD_CHOOSE_CREDITS_SCENES: + + case CutsceneMM_CommandType::CS_CMD_UNK_DATA_FA: + case CutsceneMM_CommandType::CS_CMD_UNK_DATA_FE: + case CutsceneMM_CommandType::CS_CMD_UNK_DATA_FF: + case CutsceneMM_CommandType::CS_CMD_UNK_DATA_100: + case CutsceneMM_CommandType::CS_CMD_UNK_DATA_101: + case CutsceneMM_CommandType::CS_CMD_UNK_DATA_102: + case CutsceneMM_CommandType::CS_CMD_UNK_DATA_103: + case CutsceneMM_CommandType::CS_CMD_UNK_DATA_104: + case CutsceneMM_CommandType::CS_CMD_UNK_DATA_105: + case CutsceneMM_CommandType::CS_CMD_UNK_DATA_108: + case CutsceneMM_CommandType::CS_CMD_UNK_DATA_109: { + writer->Write((uint32_t)cs->commands[i]->commandID); + writer->Write((uint32_t)cs->commands[i]->entries.size()); + for (const auto e : cs->commands[i]->entries) { + writer->Write(CMD_BBH(0, e->base, e->startFrame)); + writer->Write(CMD_HH(e->endFrame, e->endFrame)); + } + break; + } + case CutsceneMM_CommandType::CS_CMD_TRANSITION_GENERAL:{ + WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_TRANSITION_GENERAL); + + for (const auto e : cs->commands[i]->entries) { + auto* cmd = (CutsceneSubCommandEntry_TransitionGeneral*)e; + + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HBB(cmd->endFrame, cmd->unk_06, cmd->unk_07)); + writer->Write(CMD_BBBB(cmd->unk_08, 0, 0, 0)); + } + break; + } + case CutsceneMM_CommandType::CS_CMD_FADE_OUT_SEQ: { + WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_FADE_OUT_SEQ); + + for (const auto e : cs->commands[i]->entries) { + writer->Write(CMD_HH(e->base, e->startFrame)); + writer->Write(CMD_HH(e->endFrame, 0)); + } + break; + } + case CutsceneMM_CommandType::CS_CMD_TIME: { + WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_TIME); + + for (const auto e : cs->commands[i]->entries) { + auto* cmd = (CutsceneSubCommandEntry_SetTime*)e; + + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HBB(cmd->endFrame, cmd->hour, cmd->minute)); + // Skipping the zero word + } + break; + } + case CutsceneMM_CommandType::CS_CMD_PLAYER_CUE: { + WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_PLAYER_CUE); +actorCue: + for (const auto e : cs->commands[i]->entries) { + auto* cmd = (CutsceneMMSubCommandEntry_ActorCue*)e; + + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->rotX)); + writer->Write(CMD_HH(cmd->rotY, cmd->rotZ)); + writer->Write(CMD_W(cmd->startPosX)); + writer->Write(CMD_W(cmd->startPosY)); + writer->Write(CMD_W(cmd->startPosZ)); + writer->Write(CMD_F(cmd->normalX)); + writer->Write(CMD_F(cmd->normalY)); + writer->Write(CMD_F(cmd->normalZ)); + } + break; + } + case CutsceneMM_CommandType::CS_CMD_RUMBLE: { + WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_RUMBLE); + + for (const auto e : cs->commands[i]->entries) { + auto* cmd = (CutsceneMMSubCommandEntry_Rumble*)e; + + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HBB(cmd->endFrame, cmd->intensity, cmd->decayTimer)); + writer->Write(CMD_BBBB(cmd->decayStep, 0, 0, 0)); + } + break; + } + default: + { + //writer->Write((uint32_t)cs->commands[i]->commandID); + printf("Undefined CS Opcode: %04X\n", cs->commands[i]->commandID); + break; + } + } + } } \ No newline at end of file diff --git a/OTRExporter/CutsceneExporter.h b/OTRExporter/CutsceneExporter.h index 96903fd..1afd985 100644 --- a/OTRExporter/CutsceneExporter.h +++ b/OTRExporter/CutsceneExporter.h @@ -8,4 +8,6 @@ class OTRExporter_Cutscene : public OTRExporter { public: virtual void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override; + void SaveOot(ZCutscene* res, BinaryWriter* writer); + void SaveMM(ZCutscene* res, BinaryWriter* writer); }; \ No newline at end of file diff --git a/OTRExporter/Main.cpp b/OTRExporter/Main.cpp index f4e2a00..1df1373 100644 --- a/OTRExporter/Main.cpp +++ b/OTRExporter/Main.cpp @@ -26,7 +26,7 @@ #include #include -std::string otrFileName = "oot.otr"; +std::string otrFileName = "mm.otr"; std::string customOtrFileName = ""; std::string customAssetsPath = ""; std::string portVersionString = "0.0.0"; diff --git a/OTRExporter/RoomExporter.cpp b/OTRExporter/RoomExporter.cpp index bdee958..43e4185 100644 --- a/OTRExporter/RoomExporter.cpp +++ b/OTRExporter/RoomExporter.cpp @@ -1,3 +1,5 @@ +#define NO_GDI +#define WIN32_LEAN_AND_MEAN #include "RoomExporter.h" #include "Utils/BinaryWriter.h" #include "Utils/MemoryStream.h" @@ -35,6 +37,7 @@ #include "PathExporter.h" #undef FindResource + void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) { ZRoom* room = (ZRoom*)res; @@ -441,17 +444,39 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite SetCutscenes* cmdSetCutscenes = (SetCutscenes*)cmd; std::string listName; - Globals::Instance->GetSegmentedPtrName(cmdSetCutscenes->cmdArg2, room->parent, "CutsceneData", listName, res->parent->workerID); - std::string fName = OTRExporter_DisplayList::GetPathToRes(room, listName); - //std::string fName = StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), listName.c_str()); - writer->Write(fName); - - MemoryStream* csStream = new MemoryStream(); - BinaryWriter csWriter = BinaryWriter(csStream); - OTRExporter_Cutscene cs; - cs.Save(cmdSetCutscenes->cutscenes[0], "", &csWriter); - - AddFile(fName, csStream->ToVector()); + if (Globals::Instance->game == ZGame::MM_RETAIL) { + writer->Seek(-1, SeekOffsetType::Current); + writer->Write((uint8_t)RoomCommand::SetCutscenesMM); + writer->Write(cmdSetCutscenes->numCutscenes); + for (size_t i = 0; i < cmdSetCutscenes->cutsceneEntries.size(); i++) { + Globals::Instance->GetSegmentedPtrName(cmdSetCutscenes->cutsceneEntries[i].segmentPtr, room->parent, "CutsceneData", listName, res->parent->workerID); + std::string fName = OTRExporter_DisplayList::GetPathToRes(room, listName); + writer->Write(fName); + writer->Write(cmdSetCutscenes->cutsceneEntries[i].exit); + writer->Write(cmdSetCutscenes->cutsceneEntries[i].entrance); + writer->Write(cmdSetCutscenes->cutsceneEntries[i].flag); + + MemoryStream* csStream = new MemoryStream(); + BinaryWriter csWriter = BinaryWriter(csStream); + OTRExporter_Cutscene cs; + ZResource* newCs = res->parent->FindResource(cmdSetCutscenes->cutsceneEntries[i].segmentPtr & 0x00FFFFFF); + cs.Save((ZCutscene*)newCs, "", &csWriter); + + AddFile(fName, csStream->ToVector()); + } + } + else { + Globals::Instance->GetSegmentedPtrName(cmdSetCutscenes->cmdArg2, room->parent, "CutsceneData", listName, res->parent->workerID); + std::string fName = OTRExporter_DisplayList::GetPathToRes(room, listName); + writer->Write(fName); + + MemoryStream* csStream = new MemoryStream(); + BinaryWriter csWriter = BinaryWriter(csStream); + OTRExporter_Cutscene cs; + cs.Save(cmdSetCutscenes->cutscenes[0], "", &csWriter); + + AddFile(fName, csStream->ToVector()); + } } break; case RoomCommand::SetPathways: diff --git a/OTRExporter/RoomExporter.h b/OTRExporter/RoomExporter.h index bb4471a..08306b7 100644 --- a/OTRExporter/RoomExporter.h +++ b/OTRExporter/RoomExporter.h @@ -1,5 +1,6 @@ #pragma once - +#define NO_GDI +#define WIN32_LEAN_AND_MEAN #include "ZResource.h" #include "Exporter.h" #include "ZRoom/ZRoom.h" diff --git a/extract_assets.py b/extract_assets.py index aa84ae5..931384b 100755 --- a/extract_assets.py +++ b/extract_assets.py @@ -10,7 +10,7 @@ def BuildOTR(xmlPath, rom, zapd_exe=None, genHeaders=None, customAssetsPath=None, customOtrFile=None, portVer=None): if not zapd_exe: - zapd_exe = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out" + zapd_exe = "Debug\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out" exec_cmd = [zapd_exe, "ed", "-eh", "-i", xmlPath, "-b", rom, "-fl", "CFG/filelists", "-o", "placeholder", "-osf", "placeholder", "-rconf", "CFG/Config.xml"] @@ -22,7 +22,7 @@ def BuildOTR(xmlPath, rom, zapd_exe=None, genHeaders=None, customAssetsPath=None # generate otrs, but not headers exec_cmd.extend(["-gsf", "0", "-se", "OTR", "--customAssetsPath", customAssetsPath, "--customOtrFile", customOtrFile, "--otrfile", - "oot-mq.otr" if Z64Rom.isMqRom(rom) else "oot.otr"]) + "oot-mq.otr" if Z64Rom.isMqRom(rom) else "mm.otr"]) if portVer: exec_cmd.extend(["--portVer", portVer]) @@ -37,7 +37,7 @@ def BuildOTR(xmlPath, rom, zapd_exe=None, genHeaders=None, customAssetsPath=None def BuildCustomOtr(zapd_exe=None, assets_path=None, otrfile=None, portVer=None): if not zapd_exe: - zapd_exe = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out" + zapd_exe = "Debug\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out" if not assets_path or not otrfile: print("\n") @@ -77,10 +77,12 @@ def main(): BuildCustomOtr(args.zapd_exe, args.custom_assets_path, args.custom_otr_file, portVer=args.port_ver) return - roms = [ Z64Rom(args.rom) ] if args.rom else rom_chooser.chooseROM(args.verbose, args.non_interactive) - for rom in roms: - BuildOTR(os.path.join(args.xml_root, rom.version.xml_ver), rom.file_path, zapd_exe=args.zapd_exe, genHeaders=args.gen_headers, - customAssetsPath=args.custom_assets_path, customOtrFile=args.custom_otr_file, portVer=args.port_ver) +# //roms = [ Z64Rom(args.rom) ] if args.rom else rom_chooser.chooseROM(args.verbose, args.non_interactive) +# //for rom in roms: +# // if (os.path.exists("Extract")): +# // shutil.rmtree("Extract") + + BuildOTR("../mm/assets/xml/", baserom_uncompressed.z64, zapd_exe=args.zapd_exe, genHeaders=args.gen_headers) if __name__ == "__main__": main() From 5953da0476546ecdd6e0e0addb74c24a69aa5ec8 Mon Sep 17 00:00:00 2001 From: Louis <35883445+louist103@users.noreply.github.com> Date: Sat, 28 Oct 2023 01:17:47 -0400 Subject: [PATCH 03/55] MM Runnings --- OTRExporter/AnimationExporter.cpp | 19 ++++- OTRExporter/CMakeLists.txt | 2 + OTRExporter/DisplayListExporter.cpp | 29 ++++--- OTRExporter/Main.cpp | 7 +- OTRExporter/RoomExporter.cpp | 7 +- OTRExporter/TextureAnimationExporter.cpp | 99 ++++++++++++++++++++++++ OTRExporter/TextureAnimationExporter.h | 12 +++ 7 files changed, 156 insertions(+), 19 deletions(-) create mode 100644 OTRExporter/TextureAnimationExporter.cpp create mode 100644 OTRExporter/TextureAnimationExporter.h diff --git a/OTRExporter/AnimationExporter.cpp b/OTRExporter/AnimationExporter.cpp index bc8c473..32e47d0 100644 --- a/OTRExporter/AnimationExporter.cpp +++ b/OTRExporter/AnimationExporter.cpp @@ -1,5 +1,9 @@ #include "AnimationExporter.h" #include +#include +#include "DisplayListExporter.h" +#undef FindResource + void OTRExporter_Animation::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) { @@ -14,7 +18,20 @@ void OTRExporter_Animation::Save(ZResource* res, const fs::path& outPath, Binary { writer->Write((uint32_t)SOH::AnimationType::Link); writer->Write((uint16_t)linkAnim->frameCount); - writer->Write((uint32_t)linkAnim->segmentAddress); + std::string name; + bool found = Globals::Instance->GetSegmentedPtrName((linkAnim->segmentAddress), res->parent, "", name, res->parent->workerID); + if (found) + { + if (name.at(0) == '&') + name.erase(0, 1); + + writer->Write(StringHelper::Sprintf("__OTR__misc/link_animetion/%s", name.c_str())); + } + else + { + writer->Write(""); + } + //writer->Write((uint32_t)linkAnim->segmentAddress); } else if (curveAnim != nullptr) { diff --git a/OTRExporter/CMakeLists.txt b/OTRExporter/CMakeLists.txt index 87d640f..819d30e 100644 --- a/OTRExporter/CMakeLists.txt +++ b/OTRExporter/CMakeLists.txt @@ -24,6 +24,7 @@ set(Header_Files "SkeletonLimbExporter.h" "TextExporter.h" "TextureExporter.h" + "TextureAnimationExporter.h" "VersionInfo.h" "VtxExporter.h" "z64cutscene.h" @@ -51,6 +52,7 @@ set(Source_Files "SkeletonLimbExporter.cpp" "TextExporter.cpp" "TextureExporter.cpp" + "TextureAnimationExporter.cpp" "VersionInfo.cpp" "VtxExporter.cpp" ) diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index 6927f6d..00a7e60 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -869,7 +869,10 @@ std::string OTRExporter_DisplayList::GetParentFolderName(ZResource* res) } else if (StringHelper::Contains(oName, "_room")) { - oName = StringHelper::Split(oName, "_room")[0] + "_scene"; + if (Globals::Instance->game != ZGame::MM_RETAIL) + oName = StringHelper::Split(oName, "_room")[0] + "_scene"; + else + oName = StringHelper::Split(oName, "_room")[0]; } if (prefix != "") @@ -883,21 +886,15 @@ std::string OTRExporter_DisplayList::GetPrefix(ZResource* res) std::string oName = res->parent->GetOutName(); std::string prefix = ""; std::string xmlPath = StringHelper::Replace(res->parent->GetXmlFilePath().string(), "\\", "/"); - - if (StringHelper::Contains(oName, "_scene") || StringHelper::Contains(oName, "_room")) { - prefix = "scenes/shared"; - - // Regex for xml paths that are dungeons with unique MQ variants (only the main dungeon, not boss rooms) - std::regex dungeonsWithMQ(R"(((ydan)|(ddan)|(bdan)|(Bmori1)|(HIDAN)|(MIZUsin)|(jyasinzou)|(HAKAdan)|(HAKAdanCH)|(ice_doukutu)|(men)|(ganontika))\.xml)"); - - if (StringHelper::Contains(xmlPath, "dungeons/") && std::regex_search(xmlPath, dungeonsWithMQ)) { - if (Globals::Instance->rom->IsMQ()) { - prefix = "scenes/mq"; - } else { - prefix = "scenes/nonmq"; - } - } - } + // BENTODO bring in the existing OTRExporter changes from SoHs + if (StringHelper::Contains(oName, "_scene") || StringHelper::Contains(oName, "_room") || (StringHelper::Contains(res->parent->GetXmlFilePath().string(), "/scenes/") || StringHelper::Contains(res->parent->GetXmlFilePath().string(), "\\scenes\\"))) { + prefix = "scenes"; + if (Globals::Instance->rom->IsMQ()) { + prefix += "/mq"; + } else { + prefix += "/nonmq"; + } + } else if (StringHelper::Contains(xmlPath, "objects/")) prefix = "objects"; else if (StringHelper::Contains(xmlPath, "textures/")) diff --git a/OTRExporter/Main.cpp b/OTRExporter/Main.cpp index 1df1373..bac4eab 100644 --- a/OTRExporter/Main.cpp +++ b/OTRExporter/Main.cpp @@ -17,6 +17,7 @@ #include "BlobExporter.h" #include "MtxExporter.h" #include "AudioExporter.h" +#include "TextureAnimationExporter.h" #include #include #include @@ -298,7 +299,10 @@ static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer) } else if (StringHelper::Contains(oName, "_room")) { - oName = StringHelper::Split(oName, "_room")[0] + "_scene"; + if (Globals::Instance->game != ZGame::MM_RETAIL) + oName = StringHelper::Split(oName, "_room")[0] + "_scene"; + else + oName = StringHelper::Split(oName, "_room")[0]; } std::string fName = ""; @@ -383,6 +387,7 @@ void ImportExporters() exporterSet->exporters[ZResourceType::Blob] = new OTRExporter_Blob(); exporterSet->exporters[ZResourceType::Mtx] = new OTRExporter_MtxExporter(); exporterSet->exporters[ZResourceType::Audio] = new OTRExporter_Audio(); + exporterSet->exporters[ZResourceType::TextureAnimation] = new OTRExporter_TextureAnimation(); Globals::AddExporter("OTR", exporterSet); diff --git a/OTRExporter/RoomExporter.cpp b/OTRExporter/RoomExporter.cpp index 43e4185..db301ff 100644 --- a/OTRExporter/RoomExporter.cpp +++ b/OTRExporter/RoomExporter.cpp @@ -340,7 +340,12 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite for (size_t i = 0;i < cmdRoom->romfile->numRooms; i++) { //std::string roomName = StringHelper::Sprintf("%s/%s_room_%i", (StringHelper::Split(room->GetName(), "_")[0] + "_scene").c_str(), StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i); - std::string roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%i", StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i)); + std::string roomName; + if (Globals::Instance->game != ZGame::MM_RETAIL) + roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%i", StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i)); + else + roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%02d", StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i)); + writer->Write(roomName); writer->Write(cmdRoom->romfile->rooms[i].virtualAddressStart); writer->Write(cmdRoom->romfile->rooms[i].virtualAddressEnd); diff --git a/OTRExporter/TextureAnimationExporter.cpp b/OTRExporter/TextureAnimationExporter.cpp new file mode 100644 index 0000000..52acde9 --- /dev/null +++ b/OTRExporter/TextureAnimationExporter.cpp @@ -0,0 +1,99 @@ +#define NO_GDI +#define WIN32_LEAN_AND_MEAN +#include "ZFile.h" +#include +#include "TextureAnimationExporter.h" +#include "DisplayListExporter.h" + +#undef FindResource + +void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) +{ + auto* anim = (ZTextureAnimation*)res; + WriteHeader(res, outPath, writer, LUS::ResourceType::TSH_TexAnim, 0); + + for (const auto& e : anim->entries) { + if (GETSEGNUM(e.paramsPtr) == 0x80) + int bp = 0; + auto* params = (ZTextureAnimationParams*)res->parent->FindResource(Seg2Filespace(e.paramsPtr, res->parent->baseAddress)); + writer->Write(e.segment); + writer->Write((uint8_t)e.type); + switch ((TextureAnimationParamsType)e.type) { + case TextureAnimationParamsType::SingleScroll: + case TextureAnimationParamsType::DualScroll: { + auto* scrollParams = (TextureScrollingParams*)params; + + writer->Write(scrollParams->count); + writer->Write(scrollParams->rows[0].xStep); + writer->Write(scrollParams->rows[0].yStep); + writer->Write(scrollParams->rows[0].width); + writer->Write(scrollParams->rows[0].height); + if (scrollParams->count == 2) { + writer->Write(scrollParams->rows[1].xStep); + writer->Write(scrollParams->rows[1].yStep); + writer->Write(scrollParams->rows[1].width); + writer->Write(scrollParams->rows[1].height); + } + break; + } + + case TextureAnimationParamsType::ColorChange: + case TextureAnimationParamsType::ColorChangeLERP: + case TextureAnimationParamsType::ColorChangeLagrange: { + auto* colorParams = (TextureColorChangingParams*)params; + writer->Write(colorParams->animLength); + for (const auto f : colorParams->frameDataList) { + writer->Write(f); + } + writer->Write(colorParams->primColorList.size()); + for (const auto prim : colorParams->primColorList) { + writer->Write(prim.r); + writer->Write(prim.g); + writer->Write(prim.b); + writer->Write(prim.a); + writer->Write(prim.lodFrac); + } + writer->Write(colorParams->envColorList.size()); + for (const auto env : colorParams->envColorList) { + writer->Write(env.r); + writer->Write(env.g); + writer->Write(env.b); + writer->Write(env.a); + } + break; + } + case TextureAnimationParamsType::TextureCycle: { + auto* cycleParams = (TextureCyclingParams*)params; + + writer->Write(cycleParams->cycleLength); + writer->Write(cycleParams->textureList.size()); + + for (const auto t : cycleParams->textureList) { + std::string name; + //ZTexture* tex = (ZTexture*)res->parent->FindResource(t & 0x00FFFFFF); + bool found = Globals::Instance->GetSegmentedPtrName(GETSEGOFFSET(t), res->parent, "", name, res->parent->workerID); + if (found) + { + if (name.at(0) == '&') + name.erase(0, 1); + + writer->Write(OTRExporter_DisplayList::GetPathToRes(res, name)); + } + else + { + writer->Write(""); + } + } + writer->Write(cycleParams->textureIndexList.size()); + for (const auto index : cycleParams->textureIndexList) { + writer->Write(index); + } + break; + } + case TextureAnimationParamsType::Empty: { + writer->Write(SEGMENTED_NULL); + break; + } + } + } +} \ No newline at end of file diff --git a/OTRExporter/TextureAnimationExporter.h b/OTRExporter/TextureAnimationExporter.h new file mode 100644 index 0000000..40b1983 --- /dev/null +++ b/OTRExporter/TextureAnimationExporter.h @@ -0,0 +1,12 @@ +#pragma once + +#include "ZResource.h" +#include "ZTextureAnimation.h" +#include "Exporter.h" +#include + +class OTRExporter_TextureAnimation : public OTRExporter +{ +public: + virtual void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override; +}; \ No newline at end of file From 20bf8ea91b10c4e97ec211fb7b5db4bf9c5a31f0 Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Mon, 30 Oct 2023 23:58:21 -0400 Subject: [PATCH 04/55] room and tex anim work --- OTRExporter/CutsceneExporter.cpp | 4 ++-- OTRExporter/RoomExporter.cpp | 24 ++++++++++++++++++++++-- OTRExporter/TextureAnimationExporter.cpp | 10 +++++----- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/OTRExporter/CutsceneExporter.cpp b/OTRExporter/CutsceneExporter.cpp index 6da70a5..e7c782d 100644 --- a/OTRExporter/CutsceneExporter.cpp +++ b/OTRExporter/CutsceneExporter.cpp @@ -448,8 +448,8 @@ void OTRExporter_Cutscene::SaveOot(ZCutscene* cs, BinaryWriter* writer) { } } } - -typedef enum { +// MUST be uint16_t for -1 +typedef enum : uint16_t{ /* -1 */ CS_TEXT_TYPE_NONE = -1, /* 0 */ CS_TEXT_TYPE_DEFAULT, /* 1 */ CS_TEXT_TYPE_1, diff --git a/OTRExporter/RoomExporter.cpp b/OTRExporter/RoomExporter.cpp index db301ff..7d82c50 100644 --- a/OTRExporter/RoomExporter.cpp +++ b/OTRExporter/RoomExporter.cpp @@ -34,6 +34,7 @@ #include #include "CutsceneExporter.h" #include +#include #include "PathExporter.h" #undef FindResource @@ -450,8 +451,8 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite std::string listName; if (Globals::Instance->game == ZGame::MM_RETAIL) { - writer->Seek(-1, SeekOffsetType::Current); - writer->Write((uint8_t)RoomCommand::SetCutscenesMM); + writer->Seek(-4, SeekOffsetType::Current); + writer->Write((uint32_t)RoomCommand::SetCutscenesMM); writer->Write(cmdSetCutscenes->numCutscenes); for (size_t i = 0; i < cmdSetCutscenes->cutsceneEntries.size(); i++) { Globals::Instance->GetSegmentedPtrName(cmdSetCutscenes->cutsceneEntries[i].segmentPtr, room->parent, "CutsceneData", listName, res->parent->workerID); @@ -508,6 +509,25 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite break; case RoomCommand::EndMarker: break; + case RoomCommand::SetActorCutsceneList: + { + SetActorCutsceneList* list = (SetActorCutsceneList*)cmd; + writer->Write((uint32_t)list->cutscenes.size()); + + for (const auto& e : list->cutscenes) { + writer->Write(e.priority); + writer->Write(e.length); + writer->Write(e.csCamId); + writer->Write(e.scriptIndex); + writer->Write(e.additionalCsId); + writer->Write(e.endSfx); + writer->Write(e.customValue); + writer->Write(e.hudVisibility); + writer->Write(e.endCam); + writer->Write(e.letterboxSize); + } + break; + } default: printf("UNIMPLEMENTED COMMAND: 0x%02X\n", (int)cmd->cmdID); diff --git a/OTRExporter/TextureAnimationExporter.cpp b/OTRExporter/TextureAnimationExporter.cpp index 52acde9..99bde28 100644 --- a/OTRExporter/TextureAnimationExporter.cpp +++ b/OTRExporter/TextureAnimationExporter.cpp @@ -11,10 +11,9 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, { auto* anim = (ZTextureAnimation*)res; WriteHeader(res, outPath, writer, LUS::ResourceType::TSH_TexAnim, 0); + writer->Write((uint32_t)anim->entries.size()); for (const auto& e : anim->entries) { - if (GETSEGNUM(e.paramsPtr) == 0x80) - int bp = 0; auto* params = (ZTextureAnimationParams*)res->parent->FindResource(Seg2Filespace(e.paramsPtr, res->parent->baseAddress)); writer->Write(e.segment); writer->Write((uint8_t)e.type); @@ -42,10 +41,10 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, case TextureAnimationParamsType::ColorChangeLagrange: { auto* colorParams = (TextureColorChangingParams*)params; writer->Write(colorParams->animLength); + writer->Write((uint16_t)colorParams->primColorList.size()); for (const auto f : colorParams->frameDataList) { writer->Write(f); } - writer->Write(colorParams->primColorList.size()); for (const auto prim : colorParams->primColorList) { writer->Write(prim.r); writer->Write(prim.g); @@ -53,7 +52,7 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, writer->Write(prim.a); writer->Write(prim.lodFrac); } - writer->Write(colorParams->envColorList.size()); + writer->Write((uint16_t)colorParams->envColorList.size()); for (const auto env : colorParams->envColorList) { writer->Write(env.r); writer->Write(env.g); @@ -65,8 +64,9 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, case TextureAnimationParamsType::TextureCycle: { auto* cycleParams = (TextureCyclingParams*)params; + // cycleLength is the same langth writer->Write(cycleParams->cycleLength); - writer->Write(cycleParams->textureList.size()); + //writer->Write(cycleParams->textureList.size()); for (const auto t : cycleParams->textureList) { std::string name; From 5dec3ea952d24c86a063a23d79730becdfbb62da Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Tue, 31 Oct 2023 23:09:23 -0400 Subject: [PATCH 05/55] tex anim exporter --- OTRExporter/RoomExporter.cpp | 21 +++++++++++++++++++++ OTRExporter/TextureAnimationExporter.cpp | 6 ++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/OTRExporter/RoomExporter.cpp b/OTRExporter/RoomExporter.cpp index 7d82c50..e57d9e9 100644 --- a/OTRExporter/RoomExporter.cpp +++ b/OTRExporter/RoomExporter.cpp @@ -35,6 +35,8 @@ #include "CutsceneExporter.h" #include #include +#include +#include "TextureAnimationExporter.h" #include "PathExporter.h" #undef FindResource @@ -528,6 +530,25 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite } break; } + case RoomCommand::SetAnimatedMaterialList: { + SetAnimatedMaterialList* list = (SetAnimatedMaterialList*)cmd; + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmd->cmdArg2, cmd->parent, "AnimatedMaterial", listName, + res->parent->workerID); + listName = OTRExporter_DisplayList::GetPathToRes(room, listName); + writer->Write(listName); + + MemoryStream* animatedMatStream = new MemoryStream(); + BinaryWriter animatedMatWriter = BinaryWriter(animatedMatStream); + OTRExporter_TextureAnimation texAnim; + + texAnim.Save(&list->textureAnimation, outPath, &animatedMatWriter); + + AddFile(listName, animatedMatStream->ToVector()); + + break; + } + default: printf("UNIMPLEMENTED COMMAND: 0x%02X\n", (int)cmd->cmdID); diff --git a/OTRExporter/TextureAnimationExporter.cpp b/OTRExporter/TextureAnimationExporter.cpp index 99bde28..b5841ae 100644 --- a/OTRExporter/TextureAnimationExporter.cpp +++ b/OTRExporter/TextureAnimationExporter.cpp @@ -22,7 +22,6 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, case TextureAnimationParamsType::DualScroll: { auto* scrollParams = (TextureScrollingParams*)params; - writer->Write(scrollParams->count); writer->Write(scrollParams->rows[0].xStep); writer->Write(scrollParams->rows[0].yStep); writer->Write(scrollParams->rows[0].width); @@ -41,10 +40,13 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, case TextureAnimationParamsType::ColorChangeLagrange: { auto* colorParams = (TextureColorChangingParams*)params; writer->Write(colorParams->animLength); - writer->Write((uint16_t)colorParams->primColorList.size()); + writer->Write(colorParams->colorListCount); + + writer->Write((uint32_t)colorParams->frameDataList.size()); for (const auto f : colorParams->frameDataList) { writer->Write(f); } + writer->Write((uint32_t)colorParams->primColorList.size()); for (const auto prim : colorParams->primColorList) { writer->Write(prim.r); writer->Write(prim.g); From 9384b0157d2d45d5eafd36fc5e39f0c68a72e04a Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Wed, 1 Nov 2023 23:50:44 -0400 Subject: [PATCH 06/55] minimap lists --- OTRExporter/RoomExporter.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/OTRExporter/RoomExporter.cpp b/OTRExporter/RoomExporter.cpp index e57d9e9..be3990a 100644 --- a/OTRExporter/RoomExporter.cpp +++ b/OTRExporter/RoomExporter.cpp @@ -36,6 +36,8 @@ #include #include #include +#include +#include #include "TextureAnimationExporter.h" #include "PathExporter.h" #undef FindResource @@ -548,7 +550,36 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite break; } + case RoomCommand::SetMinimapList: { + SetMinimapList* list = (SetMinimapList*)cmd; + writer->Write((uint32_t)list->minimaps.size()); + writer->Write(list->scale); + + for (const auto& m : list->minimaps) { + writer->Write(m.unk0); + writer->Write(m.unk2); + writer->Write(m.unk4); + writer->Write(m.unk6); + writer->Write(m.unk8); + } + + break; + } + case RoomCommand::SetMinimapChests: { + SetMinimapChests* chests = (SetMinimapChests*)cmd; + + writer->Write((uint32_t)chests->chests.size()); + + for (const auto& c : chests->chests) { + writer->Write(c.unk0); + writer->Write(c.unk2); + writer->Write(c.unk4); + writer->Write(c.unk6); + writer->Write(c.unk8); + } + break; + } default: printf("UNIMPLEMENTED COMMAND: 0x%02X\n", (int)cmd->cmdID); From 4091ed160efb4a81560b67b287475a2bb9c20ae8 Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Thu, 2 Nov 2023 23:15:11 -0400 Subject: [PATCH 07/55] exporters --- OTRExporter/DisplayListExporter.cpp | 8 ++++++++ OTRExporter/RoomExporter.cpp | 24 +++++++++--------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index 00a7e60..2aa7c0f 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -67,6 +67,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina writer->Write((uint32_t)(hash & 0xFFFFFFFF)); auto dlStart = std::chrono::steady_clock::now(); + uint8_t lastOpCode; //for (auto data : dList->instructions) for (size_t dataIdx = 0; dataIdx < dList->instructions.size(); dataIdx++) @@ -837,6 +838,13 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina writer->Write(word0); writer->Write(word1); + lastOpCode = opcode; + } + + if (lastOpCode != G_ENDDL) { + Gfx value = { gsSPEndDisplayList() }; + writer->Write(value.words.w0); + writer->Write(value.words.w1); } auto dlEnd = std::chrono::steady_clock::now(); diff --git a/OTRExporter/RoomExporter.cpp b/OTRExporter/RoomExporter.cpp index be3990a..fe1b2e3 100644 --- a/OTRExporter/RoomExporter.cpp +++ b/OTRExporter/RoomExporter.cpp @@ -168,21 +168,15 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite SetCsCamera* cmdCsCam = (SetCsCamera*)cmd; writer->Write((uint32_t)cmdCsCam->cameras.size()); - - for (size_t i = 0; i < cmdCsCam->cameras.size(); i++) - { - writer->Write(cmdCsCam->cameras[i].baseOffset); - writer->Write(cmdCsCam->cameras[i].type); - writer->Write(cmdCsCam->cameras[i].numPoints); - } - - writer->Write((uint32_t)cmdCsCam->points.size()); - - for (size_t i = 0; i < cmdCsCam->points.size(); i++) - { - writer->Write(cmdCsCam->points[i].scalars[0].scalarData.s16); - writer->Write(cmdCsCam->points[i].scalars[1].scalarData.s16); - writer->Write(cmdCsCam->points[i].scalars[2].scalarData.s16); + segptr_t arrBase = cmdCsCam->cameras[0].baseOffset; + for (const auto& c : cmdCsCam->cameras) { + writer->Write(c.type); + writer->Write(c.numPoints); + for (size_t i = 0; i < c.numPoints; i++) { + writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[0].scalarData.s16); + writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[1].scalarData.s16); + writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[2].scalarData.s16); + } } } break; From a299689c6e5e2a2bdeb5702c14ff32bfa1d4980a Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Tue, 7 Nov 2023 20:36:31 -0500 Subject: [PATCH 08/55] Path fix for MM --- OTRExporter/PathExporter.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OTRExporter/PathExporter.cpp b/OTRExporter/PathExporter.cpp index 2c64308..1574cb7 100644 --- a/OTRExporter/PathExporter.cpp +++ b/OTRExporter/PathExporter.cpp @@ -1,5 +1,6 @@ #include "PathExporter.h" #include "../ZAPD/ZFile.h" +#include "Globals.h" void OTRExporter_Path::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) { @@ -12,7 +13,10 @@ void OTRExporter_Path::Save(ZResource* res, const fs::path& outPath, BinaryWrite for (size_t k = 0; k < path->pathways.size(); k++) { writer->Write((uint32_t)path->pathways[k].points.size()); - + if (Globals::Instance->game == ZGame::MM_RETAIL) { + writer->Write(path->pathways[k].unk1); + writer->Write(path->pathways[k].unk2); + } for (size_t i = 0; i < path->pathways[k].points.size(); i++) { writer->Write(path->pathways[k].points[i].scalars[0].scalarData.s16); From d9cc6088cefde1fd22799482f4e61a7cd7ee680f Mon Sep 17 00:00:00 2001 From: Nicholas Estelami Date: Tue, 7 Nov 2023 20:29:28 -0500 Subject: [PATCH 09/55] Fixed issue with matrices that would not export --- OTRExporter/DisplayListExporter.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index 2aa7c0f..5d6465f 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -13,7 +13,7 @@ #include "MtxExporter.h" #include #include "VersionInfo.h" - +#undef FindResource #define GFX_SIZE 8 @@ -238,6 +238,24 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina word0 = hash >> 32; word1 = hash & 0xFFFFFFFF; + + // Write the Matrix + for (ZMtx mtx : dList->mtxList) + { + if (mtx.GetRawDataIndex() == mtxDecl->address) + { + MemoryStream* mtxStream = new MemoryStream(); + BinaryWriter mtxWriter = BinaryWriter(mtxStream); + + OTRExporter_MtxExporter mtxExporter; + + //printf("Adding MTX %s\n", vName.c_str()); + + mtxExporter.Save(&mtx, "", &mtxWriter); + AddFile(vName, mtxStream->ToVector()); + break; + } + } } else { From 057f3c0e37d9f87ce179d5f8a48d81f6b6643075 Mon Sep 17 00:00:00 2001 From: Nicholas Estelami Date: Sat, 11 Nov 2023 22:40:18 -0500 Subject: [PATCH 10/55] MM Text Exporter --- OTRExporter/Main.cpp | 2 ++ OTRExporter/TextMMExporter.cpp | 23 +++++++++++++++++++++++ OTRExporter/TextMMExporter.h | 12 ++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 OTRExporter/TextMMExporter.cpp create mode 100644 OTRExporter/TextMMExporter.h diff --git a/OTRExporter/Main.cpp b/OTRExporter/Main.cpp index bac4eab..42bfe76 100644 --- a/OTRExporter/Main.cpp +++ b/OTRExporter/Main.cpp @@ -14,6 +14,7 @@ #include "CutsceneExporter.h" #include "PathExporter.h" #include "TextExporter.h" +#include "TextMMExporter.h" #include "BlobExporter.h" #include "MtxExporter.h" #include "AudioExporter.h" @@ -384,6 +385,7 @@ void ImportExporters() exporterSet->exporters[ZResourceType::Array] = new OTRExporter_Array(); exporterSet->exporters[ZResourceType::Path] = new OTRExporter_Path(); exporterSet->exporters[ZResourceType::Text] = new OTRExporter_Text(); + exporterSet->exporters[ZResourceType::TextMM] = new OTRExporter_TextMM(); exporterSet->exporters[ZResourceType::Blob] = new OTRExporter_Blob(); exporterSet->exporters[ZResourceType::Mtx] = new OTRExporter_MtxExporter(); exporterSet->exporters[ZResourceType::Audio] = new OTRExporter_Audio(); diff --git a/OTRExporter/TextMMExporter.cpp b/OTRExporter/TextMMExporter.cpp new file mode 100644 index 0000000..b022b63 --- /dev/null +++ b/OTRExporter/TextMMExporter.cpp @@ -0,0 +1,23 @@ +#include "TextMMExporter.h" +#include "../ZAPD/ZFile.h" + +void OTRExporter_TextMM::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) +{ + ZTextMM* txt = (ZTextMM*)res; + + WriteHeader(txt, outPath, writer, LUS::ResourceType::SOH_TextMM); + + writer->Write((uint32_t)txt->messages.size()); + + for (size_t i = 0; i < txt->messages.size(); i++) + { + writer->Write(txt->messages[i].id); + writer->Write(txt->messages[i].textboxType); + writer->Write(txt->messages[i].textboxYPos); + writer->Write(txt->messages[i].icon); + writer->Write(txt->messages[i].nextMessageID); + writer->Write(txt->messages[i].firstItemCost); + writer->Write(txt->messages[i].secondItemCost); + writer->Write(txt->messages[i].msg); + } +} diff --git a/OTRExporter/TextMMExporter.h b/OTRExporter/TextMMExporter.h new file mode 100644 index 0000000..4df80a1 --- /dev/null +++ b/OTRExporter/TextMMExporter.h @@ -0,0 +1,12 @@ +#pragma once + +#include "ZResource.h" +#include "ZTextMM.h" +#include "Exporter.h" +#include + +class OTRExporter_TextMM : public OTRExporter +{ +public: + virtual void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override; +}; \ No newline at end of file From 331b021883b6fca7c3a1836877a0fcf8e883ebe5 Mon Sep 17 00:00:00 2001 From: Louis <35883445+louist103@users.noreply.github.com> Date: Tue, 14 Nov 2023 22:45:23 -0500 Subject: [PATCH 11/55] Add missing cmake lists --- OTRExporter/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OTRExporter/CMakeLists.txt b/OTRExporter/CMakeLists.txt index 819d30e..854430e 100644 --- a/OTRExporter/CMakeLists.txt +++ b/OTRExporter/CMakeLists.txt @@ -23,6 +23,7 @@ set(Header_Files "SkeletonExporter.h" "SkeletonLimbExporter.h" "TextExporter.h" + "TextMMExporter.h" "TextureExporter.h" "TextureAnimationExporter.h" "VersionInfo.h" @@ -51,6 +52,7 @@ set(Source_Files "SkeletonExporter.cpp" "SkeletonLimbExporter.cpp" "TextExporter.cpp" + "TextMMExporter.cpp" "TextureExporter.cpp" "TextureAnimationExporter.cpp" "VersionInfo.cpp" From c39d88d2782460be8085875686967d1438f6b5fe Mon Sep 17 00:00:00 2001 From: Random <28494085+Random06457@users.noreply.github.com> Date: Thu, 16 Nov 2023 00:50:31 +0100 Subject: [PATCH 12/55] Linux/GCC related fixes (#1) * linux fixes Fixes case sensitive path, -1 used in a uint16_t enum, CMD_F and soh include path * fix type correctness --- OTRExporter/CMakeLists.txt | 2 +- OTRExporter/CutsceneExporter.cpp | 4 ++-- OTRExporter/RoomExporter.cpp | 2 +- OTRExporter/TextureAnimationExporter.h | 2 +- OTRExporter/command_macros_base.h | 4 ---- 5 files changed, 5 insertions(+), 9 deletions(-) diff --git a/OTRExporter/CMakeLists.txt b/OTRExporter/CMakeLists.txt index 854430e..7817190 100644 --- a/OTRExporter/CMakeLists.txt +++ b/OTRExporter/CMakeLists.txt @@ -170,7 +170,7 @@ target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/spdlog/include ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/nlohmann-json/include ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src/resource - ${CMAKE_CURRENT_SOURCE_DIR}/../../soh/soh + ${CMAKE_CURRENT_SOURCE_DIR}/../../mm/2s2h . ) diff --git a/OTRExporter/CutsceneExporter.cpp b/OTRExporter/CutsceneExporter.cpp index e7c782d..42d2d4f 100644 --- a/OTRExporter/CutsceneExporter.cpp +++ b/OTRExporter/CutsceneExporter.cpp @@ -450,8 +450,8 @@ void OTRExporter_Cutscene::SaveOot(ZCutscene* cs, BinaryWriter* writer) { } // MUST be uint16_t for -1 typedef enum : uint16_t{ - /* -1 */ CS_TEXT_TYPE_NONE = -1, - /* 0 */ CS_TEXT_TYPE_DEFAULT, + /* -1 */ CS_TEXT_TYPE_NONE = (uint16_t)-1, + /* 0 */ CS_TEXT_TYPE_DEFAULT = 0, /* 1 */ CS_TEXT_TYPE_1, /* 2 */ CS_TEXT_OCARINA_ACTION, /* 3 */ CS_TEXT_TYPE_3, diff --git a/OTRExporter/RoomExporter.cpp b/OTRExporter/RoomExporter.cpp index fe1b2e3..0357d90 100644 --- a/OTRExporter/RoomExporter.cpp +++ b/OTRExporter/RoomExporter.cpp @@ -172,7 +172,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite for (const auto& c : cmdCsCam->cameras) { writer->Write(c.type); writer->Write(c.numPoints); - for (size_t i = 0; i < c.numPoints; i++) { + for (int16_t i = 0; i < c.numPoints; i++) { writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[0].scalarData.s16); writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[1].scalarData.s16); writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[2].scalarData.s16); diff --git a/OTRExporter/TextureAnimationExporter.h b/OTRExporter/TextureAnimationExporter.h index 40b1983..1ac12d3 100644 --- a/OTRExporter/TextureAnimationExporter.h +++ b/OTRExporter/TextureAnimationExporter.h @@ -3,7 +3,7 @@ #include "ZResource.h" #include "ZTextureAnimation.h" #include "Exporter.h" -#include +#include class OTRExporter_TextureAnimation : public OTRExporter { diff --git a/OTRExporter/command_macros_base.h b/OTRExporter/command_macros_base.h index 3067d2c..1506c78 100644 --- a/OTRExporter/command_macros_base.h +++ b/OTRExporter/command_macros_base.h @@ -25,11 +25,7 @@ #define CMD_W(a) (a) -#if defined(__GNUC__) -#define CMD_F(a) {.f = (a)} -#else #define CMD_F(a) {(a)} -#endif #define CMD_PTR(a) (u32)(a) From 97bdb7aab9ade9624d20311117b51af26b144b50 Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Wed, 22 Nov 2023 21:22:58 -0500 Subject: [PATCH 13/55] fix cutscenes and cmake lists --- CMakeLists.txt | 3 +- OTRExporter/CMakeLists.txt | 10 +- OTRExporter/CutsceneExporter.cpp | 831 +++++++++++++++---------------- 3 files changed, 410 insertions(+), 434 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e759cd1..10a66c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,7 @@ cmake_minimum_required(VERSION 3.16.0 FATAL_ERROR) set(CMAKE_SYSTEM_VERSION 10.0 CACHE STRING "" FORCE) set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use") -#set(CMAKE_C_STANDARD 11 CACHE STRING "The C standard to use") -set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD 11 CACHE STRING "The C standard to use") project(OTRExporter C CXX) diff --git a/OTRExporter/CMakeLists.txt b/OTRExporter/CMakeLists.txt index 7817190..35d060e 100644 --- a/OTRExporter/CMakeLists.txt +++ b/OTRExporter/CMakeLists.txt @@ -177,6 +177,10 @@ target_include_directories(${PROJECT_NAME} PRIVATE if(MSVC) if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") target_compile_options(${PROJECT_NAME} PRIVATE + $<$: + /Od; + /Oi- + > $<$: /Oi; /Gy @@ -189,7 +193,11 @@ if(MSVC) ) elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") target_compile_options(${PROJECT_NAME} PRIVATE - $<$: + $<$: + /Od; + /Oi- + > + $<$: /Oi; /Gy > diff --git a/OTRExporter/CutsceneExporter.cpp b/OTRExporter/CutsceneExporter.cpp index 42d2d4f..53c9340 100644 --- a/OTRExporter/CutsceneExporter.cpp +++ b/OTRExporter/CutsceneExporter.cpp @@ -1,8 +1,7 @@ #include "CutsceneExporter.h" #include -void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) -{ +void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) { ZCutscene* cs = (ZCutscene*)res; WriteHeader(cs, outPath, writer, static_cast(SOH::ResourceType::SOH_Cutscene)); @@ -15,7 +14,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW SaveMM(cs, writer); - //CS_END + // CS_END writer->Write(0xFFFFFFFF); writer->Write((uint32_t)0); @@ -27,149 +26,133 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW void OTRExporter_Cutscene::SaveOot(ZCutscene* cs, BinaryWriter* writer) { - for (size_t i = 0; i < cs->commands.size(); i++) - { - switch (cs->commands[i]->commandID) - { - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE_SPLINE: - { - CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; - - writer->Write(CS_CMD_CAM_EYE); - writer->Write(CMD_HH(0x0001, ((CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i])->startFrame)); - writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; - writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); - writer->Write(point->viewAngle); - writer->Write(CMD_HH(point->posX, point->posY)); - writer->Write(CMD_HH(point->posZ, point->unused)); - } - } - break; - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE: - { - CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; - - writer->Write(CS_CMD_CAM_AT); - writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); - writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; - writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); - writer->Write(point->viewAngle); - writer->Write(CMD_HH(point->posX, point->posY)); - writer->Write(CMD_HH(point->posZ, point->unused)); + for (size_t i = 0; i < cs->commands.size(); i++) { + switch (cs->commands[i]->commandID) { + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE_SPLINE: { + CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; + + writer->Write(CS_CMD_CAM_EYE); + writer->Write(CMD_HH(0x0001, ((CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i])->startFrame)); + writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); + + for (const auto& e : cs->commands[i]->entries) { + CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; + writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); + writer->Write(point->viewAngle); + writer->Write(CMD_HH(point->posX, point->posY)); + writer->Write(CMD_HH(point->posZ, point->unused)); + } + } break; + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE: { + CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; + + writer->Write(CS_CMD_CAM_AT); + writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); + writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); + + for (const auto& e : cs->commands[i]->entries) { + CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; + writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); + writer->Write(point->viewAngle); + writer->Write(CMD_HH(point->posX, point->posY)); + writer->Write(CMD_HH(point->posZ, point->unused)); + } + break; } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_MISC: - { - writer->Write(CS_CMD_MISC); - writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); - for (const auto& e : cs->commands[i]->entries) //All in OOT seem to only have 1 entry - { - CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); - writer->Write(CMD_W(cmd->unused1)); - writer->Write(CMD_W(cmd->unused2)); - writer->Write(CMD_W(cmd->unused3)); - writer->Write(CMD_W(cmd->unused4)); - writer->Write(CMD_W(cmd->unused5)); - writer->Write(CMD_W(cmd->unused6)); - writer->Write(CMD_W(cmd->unused7)); - writer->Write(CMD_W(cmd->unused8)); - writer->Write(CMD_W(cmd->unused9)); - writer->Write(CMD_W(cmd->unused10)); + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_MISC: { + writer->Write(CS_CMD_MISC); + writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); + for (const auto& e : cs->commands[i]->entries) // All in OOT seem to only have 1 entry + { + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); + writer->Write(CMD_W(cmd->unused1)); + writer->Write(CMD_W(cmd->unused2)); + writer->Write(CMD_W(cmd->unused3)); + writer->Write(CMD_W(cmd->unused4)); + writer->Write(CMD_W(cmd->unused5)); + writer->Write(CMD_W(cmd->unused6)); + writer->Write(CMD_W(cmd->unused7)); + writer->Write(CMD_W(cmd->unused8)); + writer->Write(CMD_W(cmd->unused9)); + writer->Write(CMD_W(cmd->unused10)); + } + break; } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_LIGHT_SETTING: - { - writer->Write(CS_CMD_SET_LIGHTING); - writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); - writer->Write(CMD_W(cmd->unused1)); - writer->Write(CMD_W(cmd->unused2)); - writer->Write(CMD_W(cmd->unused3)); - writer->Write(CMD_W(cmd->unused4)); - writer->Write(CMD_W(cmd->unused5)); - writer->Write(CMD_W(cmd->unused6)); - writer->Write(CMD_W(cmd->unused7)); - writer->Write((uint32_t)0x0); - writer->Write((uint32_t)0x0); - writer->Write((uint32_t)0x0); + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_LIGHT_SETTING: { + writer->Write(CS_CMD_SET_LIGHTING); + writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); + for (const auto& e : cs->commands[i]->entries) { + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); + writer->Write(CMD_W(cmd->unused1)); + writer->Write(CMD_W(cmd->unused2)); + writer->Write(CMD_W(cmd->unused3)); + writer->Write(CMD_W(cmd->unused4)); + writer->Write(CMD_W(cmd->unused5)); + writer->Write(CMD_W(cmd->unused6)); + writer->Write(CMD_W(cmd->unused7)); + writer->Write((uint32_t)0x0); + writer->Write((uint32_t)0x0); + writer->Write((uint32_t)0x0); + } + break; } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE_SPLINE_REL_TO_PLAYER: - { - CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; - - writer->Write(CS_CMD_CAM_EYE_REL_TO_PLAYER); - writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); - writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; - writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); - writer->Write(point->viewAngle); - writer->Write(CMD_HH(point->posX, point->posY)); - writer->Write(CMD_HH(point->posZ, point->unused)); + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE_SPLINE_REL_TO_PLAYER: { + CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; + + writer->Write(CS_CMD_CAM_EYE_REL_TO_PLAYER); + writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); + writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); + + for (const auto& e : cs->commands[i]->entries) { + CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; + writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); + writer->Write(point->viewAngle); + writer->Write(CMD_HH(point->posX, point->posY)); + writer->Write(CMD_HH(point->posZ, point->unused)); + } + break; } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE_REL_TO_PLAYER: - { - CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; - - writer->Write(CS_CMD_CAM_AT_REL_TO_PLAYER); - writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); - writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; - writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); - writer->Write(point->viewAngle); - writer->Write(CMD_HH(point->posX, point->posY)); - writer->Write(CMD_HH(point->posZ, point->unused)); + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT_SPLINE_REL_TO_PLAYER: { + CutsceneOoTCommand_GenericCameraCmd* cmdCamPos = (CutsceneOoTCommand_GenericCameraCmd*)cs->commands[i]; + + writer->Write(CS_CMD_CAM_AT_REL_TO_PLAYER); + writer->Write(CMD_HH(0x0001, cmdCamPos->startFrame)); + writer->Write(CMD_HH(cmdCamPos->endFrame, 0x0000)); + + for (const auto& e : cs->commands[i]->entries) { + CutsceneOoTCommand_CameraPoint* point = (CutsceneOoTCommand_CameraPoint*)e; + writer->Write(CMD_BBH(point->continueFlag, point->cameraRoll, point->nextPointFrame)); + writer->Write(point->viewAngle); + writer->Write(CMD_HH(point->posX, point->posY)); + writer->Write(CMD_HH(point->posZ, point->unused)); + } + break; } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE: // Not used in OOT - break; - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT: // Not used in OOT - break; + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_EYE: // Not used in OOT + break; + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_CAM_AT: // Not used in OOT + break; - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_RUMBLE_CONTROLLER: - { - writer->Write(CS_CMD_09); - writer->Write((uint32_t)CMD_W(((CutsceneOoTCommand_Rumble*)cs->commands[i])->entries.size())); + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_RUMBLE_CONTROLLER: { + writer->Write(CS_CMD_09); + writer->Write((uint32_t)CMD_W(((CutsceneOoTCommand_Rumble*)cs->commands[i])->entries.size())); - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_Rumble* r = (CutsceneOoTSubCommandEntry_Rumble*)e; - writer->Write(CMD_HH(r->base, r->startFrame)); - writer->Write(CMD_HBB(e->endFrame, r->sourceStrength, r->duration)); - writer->Write(CMD_BBH(r->decreaseRate, r->unk_09, r->unk_0A)); + for (const auto& e : cs->commands[i]->entries) { + CutsceneOoTSubCommandEntry_Rumble* r = (CutsceneOoTSubCommandEntry_Rumble*)e; + writer->Write(CMD_HH(r->base, r->startFrame)); + writer->Write(CMD_HBB(e->endFrame, r->sourceStrength, r->duration)); + writer->Write(CMD_BBH(r->decreaseRate, r->unk_09, r->unk_0A)); + } + break; } - break; - } - //case 0x15://Both unused in OoT - //case 0x1A://(uint32_t)CutsceneOoT_CommandType::Unknown: - { + // case 0x15://Both unused in OoT + // case 0x1A://(uint32_t)CutsceneOoT_CommandType::Unknown: + { #if 0 CutsceneCommandUnknown* cmdUnk = (CutsceneCommandUnknown*)cs->commands[i]; writer->Write((uint32_t)cs->commands[i]->commandID); @@ -191,267 +174,250 @@ void OTRExporter_Cutscene::SaveOot(ZCutscene* cs, BinaryWriter* writer) { writer->Write(CMD_W(e->unused11)); } #endif - } - break; - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TEXT: - { - writer->Write(CS_CMD_TEXTBOX); - writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_Text* textBox = (CutsceneOoTSubCommandEntry_Text*)e; - if (textBox->base == 0xFFFF) // CS_TEXT_NONE - { - writer->Write(CMD_HH(0xFFFF, textBox->startFrame)); - writer->Write(CMD_HH(textBox->endFrame, 0xFFFF)); - writer->Write(CMD_HH(0xFFFF, 0xFFFF)); } - else // CS_TEXT_DISPLAY_TEXTBOX - { - writer->Write(CMD_HH(textBox->base, textBox->startFrame)); - writer->Write(CMD_HH(textBox->endFrame, textBox->type)); - writer->Write(CMD_HH(textBox->textId1, textBox->textId2)); + break; + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TEXT: { + writer->Write(CS_CMD_TEXTBOX); + writer->Write((uint32_t)CMD_W((cs->commands[i])->entries.size())); + + for (const auto& e : cs->commands[i]->entries) { + CutsceneOoTSubCommandEntry_Text* textBox = (CutsceneOoTSubCommandEntry_Text*)e; + if (textBox->base == 0xFFFF) // CS_TEXT_NONE + { + writer->Write(CMD_HH(0xFFFF, textBox->startFrame)); + writer->Write(CMD_HH(textBox->endFrame, 0xFFFF)); + writer->Write(CMD_HH(0xFFFF, 0xFFFF)); + } else // CS_TEXT_DISPLAY_TEXTBOX + { + writer->Write(CMD_HH(textBox->base, textBox->startFrame)); + writer->Write(CMD_HH(textBox->endFrame, textBox->type)); + writer->Write(CMD_HH(textBox->textId1, textBox->textId2)); + } } + break; } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_PLAYER_CUE: //ActorAction0 - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_7: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_8: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_9: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_10: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_11: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_12: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_13: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_14: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_15: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_16: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_17: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_7: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_8: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_9: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_10: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_11: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_12: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_13: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_14: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_15: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_16: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_17: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_7: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_8: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_9: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_10: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_11: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_12: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_13: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_7: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_8: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_9: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_10: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_11: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_12: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_7: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_8: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_7: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_1: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_2: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_3: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_4: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_5: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_6: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_8_0: - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_9_0: - { - writer->Write((uint32_t)cs->commands[i]->commandID); - writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_PLAYER_CUE: // ActorAction0 + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_9: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_10: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_11: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_12: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_13: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_14: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_15: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_16: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_0_17: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_9: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_10: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_11: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_12: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_13: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_14: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_15: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_16: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_1_17: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_9: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_10: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_11: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_12: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_2_13: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_9: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_10: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_11: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_3_12: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_4_8: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_5_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_6_7: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_1: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_2: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_3: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_4: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_5: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_7_6: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_8_0: + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_ACTOR_CUE_9_0: { + writer->Write((uint32_t)cs->commands[i]->commandID); + writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); + + for (const auto& e : cs->commands[i]->entries) { + CutsceneOoTSubCommandEntry_ActorCue* actorAct = (CutsceneOoTSubCommandEntry_ActorCue*)e; + writer->Write(CMD_HH(actorAct->base, actorAct->startFrame)); + writer->Write(CMD_HH(actorAct->endFrame, actorAct->rotX)); + writer->Write(CMD_HH(actorAct->rotY, actorAct->rotZ)); + writer->Write(CMD_W(actorAct->startPosX)); + writer->Write(CMD_W(actorAct->startPosY)); + writer->Write(CMD_W(actorAct->startPosZ)); + writer->Write(CMD_W(actorAct->endPosX)); + writer->Write(CMD_W(actorAct->endPosY)); + writer->Write(CMD_W(actorAct->endPosZ)); + writer->Write(CMD_W(actorAct->normalX)); + writer->Write(CMD_W(actorAct->normalY)); + writer->Write(CMD_W(actorAct->normalZ)); + } - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_ActorCue* actorAct = (CutsceneOoTSubCommandEntry_ActorCue*)e; - writer->Write(CMD_HH(actorAct->base, actorAct->startFrame)); - writer->Write(CMD_HH(actorAct->endFrame, actorAct->rotX)); - writer->Write(CMD_HH(actorAct->rotY, actorAct->rotZ)); - writer->Write(CMD_W(actorAct->startPosX)); - writer->Write(CMD_W(actorAct->startPosY)); - writer->Write(CMD_W(actorAct->startPosZ)); - writer->Write(CMD_W(actorAct->endPosX)); - writer->Write(CMD_W(actorAct->endPosY)); - writer->Write(CMD_W(actorAct->endPosZ)); - writer->Write(CMD_W(actorAct->normalX)); - writer->Write(CMD_W(actorAct->normalY)); - writer->Write(CMD_W(actorAct->normalZ)); + break; } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TRANSITION: { + CutsceneOoTCommand_Transition* cmdTFX = (CutsceneOoTCommand_Transition*)cs->commands[i]; - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TRANSITION: - { - CutsceneOoTCommand_Transition* cmdTFX = (CutsceneOoTCommand_Transition*)cs->commands[i]; - - writer->Write(CS_CMD_SCENE_TRANS_FX); - writer->Write((uint32_t)1); - writer->Write(CMD_HH((cmdTFX->base), cmdTFX->startFrame)); - writer->Write(CMD_HH((cmdTFX->endFrame), cmdTFX->endFrame)); - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_START_SEQ: - { - writer->Write(CS_CMD_PLAYBGM); - writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); - - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); - writer->Write(CMD_W(cmd->unused1)); - writer->Write(CMD_W(cmd->unused2)); - writer->Write(CMD_W(cmd->unused3)); - writer->Write(CMD_W(cmd->unused4)); - writer->Write(CMD_W(cmd->unused5)); - writer->Write(CMD_W(cmd->unused6)); - writer->Write(CMD_W(cmd->unused7)); - writer->Write((uint32_t)0); - writer->Write((uint32_t)0); - writer->Write((uint32_t)0); + writer->Write(CS_CMD_SCENE_TRANS_FX); + writer->Write((uint32_t)1); + writer->Write(CMD_HH((cmdTFX->base), cmdTFX->startFrame)); + writer->Write(CMD_HH((cmdTFX->endFrame), cmdTFX->endFrame)); + break; } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_STOP_SEQ: - { - writer->Write(CS_CMD_STOPBGM); - writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_START_SEQ: { + writer->Write(CS_CMD_PLAYBGM); + writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); - writer->Write(CMD_W(cmd->unused1)); - writer->Write(CMD_W(cmd->unused2)); - writer->Write(CMD_W(cmd->unused3)); - writer->Write(CMD_W(cmd->unused4)); - writer->Write(CMD_W(cmd->unused5)); - writer->Write(CMD_W(cmd->unused6)); - writer->Write(CMD_W(cmd->unused7)); - writer->Write((uint32_t)0); - writer->Write((uint32_t)0); - writer->Write((uint32_t)0); + for (const auto& e : cs->commands[i]->entries) { + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); + writer->Write(CMD_W(cmd->unused1)); + writer->Write(CMD_W(cmd->unused2)); + writer->Write(CMD_W(cmd->unused3)); + writer->Write(CMD_W(cmd->unused4)); + writer->Write(CMD_W(cmd->unused5)); + writer->Write(CMD_W(cmd->unused6)); + writer->Write(CMD_W(cmd->unused7)); + writer->Write((uint32_t)0); + writer->Write((uint32_t)0); + writer->Write((uint32_t)0); + } + break; } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_FADE_OUT_SEQ: - { - writer->Write(CS_CMD_FADEBGM); - writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_STOP_SEQ: { + writer->Write(CS_CMD_STOPBGM); + writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); - for (const auto& e : cs->commands[i]->entries) - { - CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); - writer->Write(CMD_W(cmd->unused1)); - writer->Write(CMD_W(cmd->unused2)); - writer->Write(CMD_W(cmd->unused3)); - writer->Write(CMD_W(cmd->unused4)); - writer->Write(CMD_W(cmd->unused5)); - writer->Write(CMD_W(cmd->unused6)); - writer->Write(CMD_W(cmd->unused7)); - writer->Write((uint32_t)0); - writer->Write((uint32_t)0); - writer->Write((uint32_t)0); + for (const auto& e : cs->commands[i]->entries) { + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); + writer->Write(CMD_W(cmd->unused1)); + writer->Write(CMD_W(cmd->unused2)); + writer->Write(CMD_W(cmd->unused3)); + writer->Write(CMD_W(cmd->unused4)); + writer->Write(CMD_W(cmd->unused5)); + writer->Write(CMD_W(cmd->unused6)); + writer->Write(CMD_W(cmd->unused7)); + writer->Write((uint32_t)0); + writer->Write((uint32_t)0); + writer->Write((uint32_t)0); + } + break; } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TIME: - { - writer->Write(CS_CMD_SETTIME); - writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_FADE_OUT_SEQ: { + writer->Write(CS_CMD_FADEBGM); + writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); - for (const auto& e : cs->commands[i]->entries) - { - CutsceneSubCommandEntry_SetTime* t = (CutsceneSubCommandEntry_SetTime*)e; + for (const auto& e : cs->commands[i]->entries) { + CutsceneOoTSubCommandEntry_GenericCmd* cmd = (CutsceneOoTSubCommandEntry_GenericCmd*)e; + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->pad)); + writer->Write(CMD_W(cmd->unused1)); + writer->Write(CMD_W(cmd->unused2)); + writer->Write(CMD_W(cmd->unused3)); + writer->Write(CMD_W(cmd->unused4)); + writer->Write(CMD_W(cmd->unused5)); + writer->Write(CMD_W(cmd->unused6)); + writer->Write(CMD_W(cmd->unused7)); + writer->Write((uint32_t)0); + writer->Write((uint32_t)0); + writer->Write((uint32_t)0); + } + break; + } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_TIME: { + writer->Write(CS_CMD_SETTIME); + writer->Write((uint32_t)CMD_W(cs->commands[i]->entries.size())); + + for (const auto& e : cs->commands[i]->entries) { + CutsceneSubCommandEntry_SetTime* t = (CutsceneSubCommandEntry_SetTime*)e; + writer->Write(CMD_HH(t->base, t->startFrame)); + writer->Write(CMD_HBB(t->endFrame, t->hour, t->minute)); + writer->Write((uint32_t)0); + // writer->Write((uint32_t)CMD_W(t->unk_08)); + } + break; + } + case (uint32_t)CutsceneOoT_CommandType::CS_CMD_DESTINATION: { + CutsceneOoTCommand_Destination* t = (CutsceneOoTCommand_Destination*)cs->commands[i]; + writer->Write(CS_CMD_TERMINATOR); + writer->Write((uint32_t)1); writer->Write(CMD_HH(t->base, t->startFrame)); - writer->Write(CMD_HBB(t->endFrame, t->hour, t->minute)); - writer->Write((uint32_t)0); - //writer->Write((uint32_t)CMD_W(t->unk_08)); + writer->Write(CMD_HH(t->endFrame, t->endFrame)); + break; } - break; - } - case (uint32_t)CutsceneOoT_CommandType::CS_CMD_DESTINATION: - { - CutsceneOoTCommand_Destination* t = (CutsceneOoTCommand_Destination*)cs->commands[i]; - writer->Write(CS_CMD_TERMINATOR); - writer->Write((uint32_t)1); - writer->Write(CMD_HH(t->base, t->startFrame)); - writer->Write(CMD_HH(t->endFrame, t->endFrame)); - break; - } - default: - { - //writer->Write((uint32_t)cs->commands[i]->commandID); - printf("Undefined CS Opcode: %04X\n", cs->commands[i]->commandID); - } - break; + default: { + // writer->Write((uint32_t)cs->commands[i]->commandID); + printf("Undefined CS Opcode: %04X\n", cs->commands[i]->commandID); + } break; } } } // MUST be uint16_t for -1 -typedef enum : uint16_t{ - /* -1 */ CS_TEXT_TYPE_NONE = (uint16_t)-1, - /* 0 */ CS_TEXT_TYPE_DEFAULT = 0, +typedef enum : uint16_t { + /* -1 */ CS_TEXT_TYPE_NONE = -1, + /* 0 */ CS_TEXT_TYPE_DEFAULT, /* 1 */ CS_TEXT_TYPE_1, /* 2 */ CS_TEXT_OCARINA_ACTION, /* 3 */ CS_TEXT_TYPE_3, @@ -459,61 +425,62 @@ typedef enum : uint16_t{ /* 5 */ CS_TEXT_TYPE_ALL_NORMAL_MASKS } CutsceneTextType; -#define WRITE_CMD_PROLOG(cmd) writer->Write((uint32_t)cmd); writer->Write((uint32_t)cs->commands[i]->entries.size()); +#define WRITE_CMD_PROLOG(cmd) \ + writer->Write((uint32_t)cmd); \ + writer->Write((uint32_t)cs->commands[i]->entries.size()); void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { for (size_t i = 0; i < cs->commands.size(); i++) { if (((cs->commands[i]->commandID >= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_100) && - (cs->commands[i]->commandID <= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_149)) || + (cs->commands[i]->commandID <= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_149)) || (cs->commands[i]->commandID == (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_201) || ((cs->commands[i]->commandID >= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_450) && - (cs->commands[i]->commandID <= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_599))) - { + (cs->commands[i]->commandID <= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_599))) { WRITE_CMD_PROLOG(cs->commands[i]->commandID); goto actorCue; } switch ((CutsceneMM_CommandType)cs->commands[i]->commandID) { case CutsceneMM_CommandType::CS_CMD_TEXT: { - writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_TEXT); - writer->Write((uint32_t)cs->commands[i]->entries.size()); - for (const auto& e : cs->commands[i]->entries) { - auto* cmd = (CutsceneMMSubCommandEntry_Text*)e; - - switch ((CutsceneTextType)cmd->type) { - case CS_TEXT_TYPE_DEFAULT: // 0 - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->type)); - writer->Write(CMD_HH(cmd->textId1, cmd->textId2)); - break; - case CS_TEXT_TYPE_1: // 1 - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->type)); - writer->Write(CMD_HH(cmd->textId1, cmd->textId2)); - break; - case CS_TEXT_OCARINA_ACTION: //2 - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->type)); - writer->Write(CMD_HH(cmd->textId1, 0xFFFF)); - break; - case CS_TEXT_TYPE_3: // 3 - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->type)); - writer->Write(CMD_HH(cmd->textId1, cmd->textId2)); - break; - case CS_TEXT_TYPE_BOSSES_REMAINS: // 4 - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->type)); - writer->Write(CMD_HH(cmd->textId1, 0xFFFF)); - break; - case CS_TEXT_TYPE_ALL_NORMAL_MASKS: // 5 - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->type)); - writer->Write(CMD_HH(cmd->textId1, 0xFFFF)); - break; - case CS_TEXT_TYPE_NONE: // -1 - writer->Write(CMD_HH(0xFFFF, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, 0xFFFF)); - writer->Write(CMD_HH(0xFFFF, 0xFFFF)); + writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_TEXT); + writer->Write((uint32_t)cs->commands[i]->entries.size()); + for (const auto& e : cs->commands[i]->entries) { + auto* cmd = (CutsceneMMSubCommandEntry_Text*)e; + + switch ((CutsceneTextType)cmd->type) { + case CS_TEXT_TYPE_DEFAULT: // 0 + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->type)); + writer->Write(CMD_HH(cmd->textId1, cmd->textId2)); + break; + case CS_TEXT_TYPE_1: // 1 + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->type)); + writer->Write(CMD_HH(cmd->textId1, cmd->textId2)); + break; + case CS_TEXT_OCARINA_ACTION: // 2 + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->type)); + writer->Write(CMD_HH(cmd->textId1, 0xFFFF)); + break; + case CS_TEXT_TYPE_3: // 3 + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->type)); + writer->Write(CMD_HH(cmd->textId1, cmd->textId2)); + break; + case CS_TEXT_TYPE_BOSSES_REMAINS: // 4 + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->type)); + writer->Write(CMD_HH(cmd->textId1, 0xFFFF)); + break; + case CS_TEXT_TYPE_ALL_NORMAL_MASKS: // 5 + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->type)); + writer->Write(CMD_HH(cmd->textId1, 0xFFFF)); + break; + case CS_TEXT_TYPE_NONE: // -1 + writer->Write(CMD_HH(0xFFFF, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, 0xFFFF)); + writer->Write(CMD_HH(0xFFFF, 0xFFFF)); } } break; @@ -522,7 +489,7 @@ void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { // BENTODO: Can these stay consilidated? case CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE: { writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE); - writer->Write((uint32_t)cs->commands[i]->entries.size()); + writer->Write((uint32_t)cs->commands[i]->entries.size() * sizeof(uint32_t)); for (const auto e : cs->commands[i]->entries) { auto* cmd = (CutsceneSubCommandEntry_Camera*)e; writer->Write(CMD_HH(cmd->base, cmd->startFrame)); @@ -612,7 +579,7 @@ void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { } break; } - case CutsceneMM_CommandType::CS_CMD_TRANSITION_GENERAL:{ + case CutsceneMM_CommandType::CS_CMD_TRANSITION_GENERAL: { WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_TRANSITION_GENERAL); for (const auto e : cs->commands[i]->entries) { @@ -647,7 +614,7 @@ void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { } case CutsceneMM_CommandType::CS_CMD_PLAYER_CUE: { WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_PLAYER_CUE); -actorCue: + actorCue: for (const auto e : cs->commands[i]->entries) { auto* cmd = (CutsceneMMSubCommandEntry_ActorCue*)e; @@ -657,6 +624,9 @@ void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { writer->Write(CMD_W(cmd->startPosX)); writer->Write(CMD_W(cmd->startPosY)); writer->Write(CMD_W(cmd->startPosZ)); + writer->Write(CMD_W(cmd->endPosX)); + writer->Write(CMD_W(cmd->endPosY)); + writer->Write(CMD_W(cmd->endPosZ)); writer->Write(CMD_F(cmd->normalX)); writer->Write(CMD_F(cmd->normalY)); writer->Write(CMD_F(cmd->normalZ)); @@ -675,12 +645,11 @@ void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { } break; } - default: - { - //writer->Write((uint32_t)cs->commands[i]->commandID); + default: { + // writer->Write((uint32_t)cs->commands[i]->commandID); printf("Undefined CS Opcode: %04X\n", cs->commands[i]->commandID); break; } } } -} \ No newline at end of file +} From 7c227180f1534b93881898f5bbdefa16613816a3 Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Sat, 25 Nov 2023 19:25:02 -0500 Subject: [PATCH 14/55] tex anim and room fixes --- OTRExporter/RoomExporter.cpp | 1141 +++++++++++----------- OTRExporter/TextureAnimationExporter.cpp | 2 +- 2 files changed, 577 insertions(+), 566 deletions(-) diff --git a/OTRExporter/RoomExporter.cpp b/OTRExporter/RoomExporter.cpp index 0357d90..ce6292d 100644 --- a/OTRExporter/RoomExporter.cpp +++ b/OTRExporter/RoomExporter.cpp @@ -45,573 +45,584 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) { - ZRoom* room = (ZRoom*)res; - - WriteHeader(res, outPath, writer, static_cast(SOH::ResourceType::SOH_Room)); - - writer->Write((uint32_t)room->commands.size()); - - for (size_t i = 0; i < room->commands.size(); i++) - { - ZRoomCommand* cmd = room->commands[i]; - - writer->Write((uint32_t)cmd->cmdID); - - switch (cmd->cmdID) - { - case RoomCommand::SetTransitionActorList: - { - SetTransitionActorList* cmdTrans = (SetTransitionActorList*)cmd; - - writer->Write((uint32_t)cmdTrans->transitionActors.size()); - - for (const TransitionActorEntry& entry : cmdTrans->transitionActors) - { - writer->Write(entry.frontObjectRoom); - writer->Write(entry.frontTransitionReaction); - writer->Write(entry.backObjectRoom); - writer->Write(entry.backTransitionReaction); - writer->Write(entry.actorNum); - writer->Write(entry.posX); - writer->Write(entry.posY); - writer->Write(entry.posZ); - writer->Write(entry.rotY); - writer->Write(entry.initVar); - } - } - break; - case RoomCommand::SetActorList: - { - SetActorList* cmdSetActorList = (SetActorList*)cmd; - - // There are instance of the amount of actors in the file differing from the size listed in the command. - // This can cause issues if we export actors with garbage data, so let's trust the command size - writer->Write((uint32_t)cmdSetActorList->numActors); - - for (const auto& entry : cmdSetActorList->actorList->actors) - { - writer->Write(entry.actorNum); - writer->Write(entry.posX); - writer->Write(entry.posY); - writer->Write(entry.posZ); - writer->Write(entry.rotX); - writer->Write(entry.rotY); - writer->Write(entry.rotZ); - writer->Write(entry.params); - } - } - break; - case RoomCommand::SetWind: - { - SetWind* cmdSetWind = (SetWind*)cmd; - - writer->Write(cmdSetWind->windWest); // 0x04 - writer->Write(cmdSetWind->windVertical); // 0x05 - writer->Write(cmdSetWind->windSouth); // 0x06 - writer->Write(cmdSetWind->clothFlappingStrength); // 0x07 - } - break; - case RoomCommand::SetTimeSettings: - { - SetTimeSettings* cmdTime = (SetTimeSettings*)cmd; - - writer->Write(cmdTime->hour); // 0x04 - writer->Write(cmdTime->min); // 0x05 - writer->Write(cmdTime->unk); // 0x06 - } - break; - case RoomCommand::SetSkyboxModifier: - { - SetSkyboxModifier* cmdSkybox = (SetSkyboxModifier*)cmd; - - writer->Write(cmdSkybox->disableSky); // 0x04 - writer->Write(cmdSkybox->disableSunMoon); // 0x05 - } - break; - case RoomCommand::SetEchoSettings: - { - SetEchoSettings* cmdEcho = (SetEchoSettings*)cmd; - - writer->Write((uint8_t)cmdEcho->echo); // 0x07 - } - break; - case RoomCommand::SetSoundSettings: - { - SetSoundSettings* cmdSound = (SetSoundSettings*)cmd; - - writer->Write((uint8_t)cmdSound->reverb); // 0x01 - - writer->Write(cmdSound->nightTimeSFX); // 0x06 - writer->Write(cmdSound->musicSequence); // 0x07 - } - break; - case RoomCommand::SetSkyboxSettings: - { - SetSkyboxSettings* cmdSkybox = (SetSkyboxSettings*)cmd; - - writer->Write((uint8_t)cmdSkybox->unk1); // 0x01 - writer->Write((uint8_t)cmdSkybox->skyboxNumber); // 0x04 - writer->Write((uint8_t)cmdSkybox->cloudsType); // 0x05 - writer->Write((uint8_t)cmdSkybox->isIndoors); // 0x06 - } - break; - case RoomCommand::SetRoomBehavior: - { - SetRoomBehavior* cmdRoom = (SetRoomBehavior*)cmd; - - writer->Write((uint8_t)cmdRoom->gameplayFlags); // 0x01 - writer->Write(cmdRoom->gameplayFlags2); // 0x04 - } - break; - case RoomCommand::SetCsCamera: - { - SetCsCamera* cmdCsCam = (SetCsCamera*)cmd; - - writer->Write((uint32_t)cmdCsCam->cameras.size()); - segptr_t arrBase = cmdCsCam->cameras[0].baseOffset; - for (const auto& c : cmdCsCam->cameras) { - writer->Write(c.type); - writer->Write(c.numPoints); - for (int16_t i = 0; i < c.numPoints; i++) { - writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[0].scalarData.s16); - writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[1].scalarData.s16); - writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[2].scalarData.s16); - } - } - } - break; - case RoomCommand::SetMesh: - { - SetMesh* cmdMesh = (SetMesh*)cmd; - - writer->Write((uint8_t)cmdMesh->data); // 0x01 - writer->Write(cmdMesh->meshHeaderType); - - if (cmdMesh->meshHeaderType == 0 || cmdMesh->meshHeaderType == 2) - { - RoomShapeCullable* poly = (RoomShapeCullable*)cmdMesh->polyType.get(); - - writer->Write(poly->num); - - for (int i = 0; i < poly->num; i++) - WritePolyDList(writer, room, &poly->polyDLists[i]); - } - else if (cmdMesh->meshHeaderType == 1) - { - PolygonType1* poly = (PolygonType1*)cmdMesh->polyType.get(); - - writer->Write(poly->format); - - auto test = (RoomShapeDListsEntry*)&poly->polyDLists[0]; - Declaration* dListDeclOpa = poly->parent->GetDeclaration(GETSEGOFFSET(test->opa)); - Declaration* dListDeclXlu = poly->parent->GetDeclaration(GETSEGOFFSET(test->xlu)); - - if (test->opa != 0) - writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->declName.c_str())); - else - writer->Write(""); - - if (test->xlu != 0) - writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclXlu->declName.c_str())); - else - writer->Write(""); - - if (poly->format == 2) - { - writer->Write((uint32_t)poly->count); - - for (int i = 0; i < poly->count; i++) - { - writer->Write(poly->multiList[i].unk_00); - writer->Write(poly->multiList[i].id); - - Declaration* bgDecl = poly->parent->GetDeclarationRanged(GETSEGOFFSET(poly->multiList[i].source)); - - writer->Write(OTRExporter_DisplayList::GetPathToRes(poly->multiList[i].sourceBackground, bgDecl->declName)); - - writer->Write(poly->multiList[i].unk_0C); - writer->Write(poly->multiList[i].tlut); - writer->Write(poly->multiList[i].width); - writer->Write(poly->multiList[i].height); - writer->Write(poly->multiList[i].fmt); - writer->Write(poly->multiList[i].siz); - writer->Write(poly->multiList[i].mode0); - writer->Write(poly->multiList[i].tlutCount); - } - } - else - { - writer->Write((uint32_t)1); - - writer->Write(poly->single.unk_00); - writer->Write(poly->single.id); - - Declaration* bgDecl = poly->parent->GetDeclarationRanged(GETSEGOFFSET(poly->single.source)); - - writer->Write(OTRExporter_DisplayList::GetPathToRes(poly->single.sourceBackground, bgDecl->declName)); - - writer->Write(poly->single.unk_0C); - writer->Write(poly->single.tlut); - writer->Write(poly->single.width); - writer->Write(poly->single.height); - writer->Write(poly->single.fmt); - writer->Write(poly->single.siz); - writer->Write(poly->single.mode0); - writer->Write(poly->single.tlutCount); - } - - if (poly->dlist != 0) - WritePolyDList(writer, room, &poly->polyDLists[0]); - } - } - break; - case RoomCommand::SetCameraSettings: - { - SetCameraSettings* cmdCam = (SetCameraSettings*)cmd; - - writer->Write((uint8_t)cmdCam->cameraMovement); // 0x01 - writer->Write(cmdCam->mapHighlight); // 0x04 - } - break; - case RoomCommand::SetLightList: - { - SetLightList* cmdLight = (SetLightList*)cmd; - - writer->Write((uint32_t)cmdLight->lights.size()); - - for (size_t i = 0; i < cmdLight->lights.size(); i++) - { - writer->Write(cmdLight->lights[i].type); - writer->Write(cmdLight->lights[i].x); - writer->Write(cmdLight->lights[i].y); - writer->Write(cmdLight->lights[i].z); - writer->Write(cmdLight->lights[i].r); - writer->Write(cmdLight->lights[i].g); - writer->Write(cmdLight->lights[i].b); - writer->Write(cmdLight->lights[i].drawGlow); - writer->Write(cmdLight->lights[i].radius); - } - } - break; - case RoomCommand::SetLightingSettings: - { - SetLightingSettings* cmdLight = (SetLightingSettings*)cmd; - - writer->Write((uint32_t)cmdLight->settings.size()); // 0x01 - - for (const LightingSettings& setting : cmdLight->settings) - { - writer->Write(setting.ambientClrR); - writer->Write(setting.ambientClrG); - writer->Write(setting.ambientClrB); - - writer->Write(setting.diffuseClrA_R); - writer->Write(setting.diffuseClrA_G); - writer->Write(setting.diffuseClrA_B); - - writer->Write(setting.diffuseDirA_X); - writer->Write(setting.diffuseDirA_Y); - writer->Write(setting.diffuseDirA_Z); - - writer->Write(setting.diffuseClrB_R); - writer->Write(setting.diffuseClrB_G); - writer->Write(setting.diffuseClrB_B); - - writer->Write(setting.diffuseDirB_X); - writer->Write(setting.diffuseDirB_Y); - writer->Write(setting.diffuseDirB_Z); - - writer->Write(setting.fogClrR); - writer->Write(setting.fogClrG); - writer->Write(setting.fogClrB); - - writer->Write(setting.unk); - writer->Write(setting.drawDistance); - } - } - break; - case RoomCommand::SetRoomList: - { - SetRoomList* cmdRoom = (SetRoomList*)cmd; - - writer->Write((uint32_t)cmdRoom->romfile->numRooms); // 0x01 - - for (size_t i = 0;i < cmdRoom->romfile->numRooms; i++) - { - //std::string roomName = StringHelper::Sprintf("%s/%s_room_%i", (StringHelper::Split(room->GetName(), "_")[0] + "_scene").c_str(), StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i); - std::string roomName; - if (Globals::Instance->game != ZGame::MM_RETAIL) - roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%i", StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i)); - else - roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%02d", StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i)); - - writer->Write(roomName); - writer->Write(cmdRoom->romfile->rooms[i].virtualAddressStart); - writer->Write(cmdRoom->romfile->rooms[i].virtualAddressEnd); - } - } - break; - case RoomCommand::SetCollisionHeader: - { - SetCollisionHeader* cmdCollHeader = (SetCollisionHeader*)cmd; - - Declaration* colHeaderDecl = room->parent->GetDeclaration(cmdCollHeader->segmentOffset); - std::string path = OTRExporter_DisplayList::GetPathToRes(room, colHeaderDecl->declName); - writer->Write(path); - } - break; - case RoomCommand::SetEntranceList: - { - SetEntranceList* cmdEntrance = (SetEntranceList*)cmd; - - writer->Write((uint32_t)cmdEntrance->entrances.size()); - - for (Spawn entry : cmdEntrance->entrances) - { - writer->Write((uint8_t)entry.startPositionIndex); - writer->Write((uint8_t)entry.roomToLoad); - } - } - break; - case RoomCommand::SetSpecialObjects: - { - SetSpecialObjects* cmdSpecObj = (SetSpecialObjects*)cmd; - - writer->Write((uint8_t)cmdSpecObj->elfMessage); // 0x01 - writer->Write((uint16_t)cmdSpecObj->globalObject); // 0x06 - } - break; - case RoomCommand::SetStartPositionList: - { - SetStartPositionList* cmdStartPos = (SetStartPositionList*)cmd; - - uint32_t baseStreamEnd = writer->GetStream().get()->GetLength(); - - writer->Write((uint32_t)cmdStartPos->actors.size()); // 0x01 - - for (const ActorSpawnEntry& entry : cmdStartPos->actors) - { - writer->Write(entry.actorNum); - writer->Write(entry.posX); - writer->Write(entry.posY); - writer->Write(entry.posZ); - writer->Write(entry.rotX); - writer->Write(entry.rotY); - writer->Write(entry.rotZ); - writer->Write(entry.params); - } - } - break; - case RoomCommand::SetAlternateHeaders: - { - SetAlternateHeaders* cmdHeaders = (SetAlternateHeaders*)cmd; - - writer->Write((uint32_t)cmdHeaders->headers.size()); - - for (size_t i = 0; i < cmdHeaders->headers.size(); i++) - { - uint32_t seg = cmdHeaders->headers[i] & 0xFFFFFFFF; - std::string headerName = ""; - bool foundDecl = Globals::Instance->GetSegmentedPtrName(seg, room->parent, "", headerName, res->parent->workerID); - if (headerName == "NULL") - writer->Write(""); - else - { - std::string name = OTRExporter_DisplayList::GetPathToRes(room, headerName); - writer->Write(name); - } - } - } - break; - case RoomCommand::SetExitList: - { - SetExitList* cmdExit = (SetExitList*)cmd; - - writer->Write((uint32_t)cmdExit->exits.size()); - - for (size_t i = 0; i < cmdExit->exits.size(); i++) - writer->Write(cmdExit->exits[i]); - } - break; - case RoomCommand::SetObjectList: - { - SetObjectList* cmdSetObjectList = (SetObjectList*)cmd; - - writer->Write((uint32_t)cmdSetObjectList->objects.size()); - - for (size_t i = 0; i < cmdSetObjectList->objects.size(); i++) - writer->Write(cmdSetObjectList->objects[i]); - } - break; - case RoomCommand::SetCutscenes: - { - SetCutscenes* cmdSetCutscenes = (SetCutscenes*)cmd; - - std::string listName; - if (Globals::Instance->game == ZGame::MM_RETAIL) { - writer->Seek(-4, SeekOffsetType::Current); - writer->Write((uint32_t)RoomCommand::SetCutscenesMM); - writer->Write(cmdSetCutscenes->numCutscenes); - for (size_t i = 0; i < cmdSetCutscenes->cutsceneEntries.size(); i++) { - Globals::Instance->GetSegmentedPtrName(cmdSetCutscenes->cutsceneEntries[i].segmentPtr, room->parent, "CutsceneData", listName, res->parent->workerID); - std::string fName = OTRExporter_DisplayList::GetPathToRes(room, listName); - writer->Write(fName); - writer->Write(cmdSetCutscenes->cutsceneEntries[i].exit); - writer->Write(cmdSetCutscenes->cutsceneEntries[i].entrance); - writer->Write(cmdSetCutscenes->cutsceneEntries[i].flag); - - MemoryStream* csStream = new MemoryStream(); - BinaryWriter csWriter = BinaryWriter(csStream); - OTRExporter_Cutscene cs; - ZResource* newCs = res->parent->FindResource(cmdSetCutscenes->cutsceneEntries[i].segmentPtr & 0x00FFFFFF); - cs.Save((ZCutscene*)newCs, "", &csWriter); - - AddFile(fName, csStream->ToVector()); - } - } - else { - Globals::Instance->GetSegmentedPtrName(cmdSetCutscenes->cmdArg2, room->parent, "CutsceneData", listName, res->parent->workerID); - std::string fName = OTRExporter_DisplayList::GetPathToRes(room, listName); - writer->Write(fName); - - MemoryStream* csStream = new MemoryStream(); - BinaryWriter csWriter = BinaryWriter(csStream); - OTRExporter_Cutscene cs; - cs.Save(cmdSetCutscenes->cutscenes[0], "", &csWriter); - - AddFile(fName, csStream->ToVector()); - } - } - break; - case RoomCommand::SetPathways: - { - SetPathways* cmdSetPathways = (SetPathways*)cmd; - - writer->Write((uint32_t)cmdSetPathways->pathwayList.pathways.size()); - - for (size_t i = 0; i < cmdSetPathways->pathwayList.pathways.size(); i++) - { - Declaration* decl = room->parent->GetDeclaration(GETSEGOFFSET(cmdSetPathways->pathwayList.pathways[i].listSegmentAddress)); - //std::string path = StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), decl->varName.c_str()); - std::string path = OTRExporter_DisplayList::GetPathToRes(room, decl->declName); - writer->Write(path); - - MemoryStream* pathStream = new MemoryStream(); - BinaryWriter pathWriter = BinaryWriter(pathStream); - OTRExporter_Path pathExp; - pathExp.Save(&cmdSetPathways->pathwayList, outPath, &pathWriter); - - AddFile(path, pathStream->ToVector()); - } - } - break; - case RoomCommand::EndMarker: - break; - case RoomCommand::SetActorCutsceneList: - { - SetActorCutsceneList* list = (SetActorCutsceneList*)cmd; - writer->Write((uint32_t)list->cutscenes.size()); - - for (const auto& e : list->cutscenes) { - writer->Write(e.priority); - writer->Write(e.length); - writer->Write(e.csCamId); - writer->Write(e.scriptIndex); - writer->Write(e.additionalCsId); - writer->Write(e.endSfx); - writer->Write(e.customValue); - writer->Write(e.hudVisibility); - writer->Write(e.endCam); - writer->Write(e.letterboxSize); - } - break; - } - case RoomCommand::SetAnimatedMaterialList: { - SetAnimatedMaterialList* list = (SetAnimatedMaterialList*)cmd; - std::string listName; - Globals::Instance->GetSegmentedPtrName(cmd->cmdArg2, cmd->parent, "AnimatedMaterial", listName, - res->parent->workerID); - listName = OTRExporter_DisplayList::GetPathToRes(room, listName); - writer->Write(listName); - - MemoryStream* animatedMatStream = new MemoryStream(); - BinaryWriter animatedMatWriter = BinaryWriter(animatedMatStream); - OTRExporter_TextureAnimation texAnim; - - texAnim.Save(&list->textureAnimation, outPath, &animatedMatWriter); - - AddFile(listName, animatedMatStream->ToVector()); - - break; - } - case RoomCommand::SetMinimapList: { - SetMinimapList* list = (SetMinimapList*)cmd; - - writer->Write((uint32_t)list->minimaps.size()); - writer->Write(list->scale); - - for (const auto& m : list->minimaps) { - writer->Write(m.unk0); - writer->Write(m.unk2); - writer->Write(m.unk4); - writer->Write(m.unk6); - writer->Write(m.unk8); - } - - break; - } - case RoomCommand::SetMinimapChests: { - SetMinimapChests* chests = (SetMinimapChests*)cmd; - - writer->Write((uint32_t)chests->chests.size()); - - for (const auto& c : chests->chests) { - writer->Write(c.unk0); - writer->Write(c.unk2); - writer->Write(c.unk4); - writer->Write(c.unk6); - writer->Write(c.unk8); - } - break; - } - default: - printf("UNIMPLEMENTED COMMAND: 0x%02X\n", (int)cmd->cmdID); - - break; - } - } + ZRoom* room = (ZRoom*)res; + + WriteHeader(res, outPath, writer, static_cast(SOH::ResourceType::SOH_Room)); + + writer->Write((uint32_t)room->commands.size()); + + for (size_t i = 0; i < room->commands.size(); i++) + { + ZRoomCommand* cmd = room->commands[i]; + + writer->Write((uint32_t)cmd->cmdID); + + switch (cmd->cmdID) + { + case RoomCommand::SetTransitionActorList: + { + SetTransitionActorList* cmdTrans = (SetTransitionActorList*)cmd; + + writer->Write((uint32_t)cmdTrans->transitionActors.size()); + + for (const TransitionActorEntry& entry : cmdTrans->transitionActors) + { + writer->Write(entry.frontObjectRoom); + writer->Write(entry.frontTransitionReaction); + writer->Write(entry.backObjectRoom); + writer->Write(entry.backTransitionReaction); + writer->Write(entry.actorNum); + writer->Write(entry.posX); + writer->Write(entry.posY); + writer->Write(entry.posZ); + writer->Write(entry.rotY); + writer->Write(entry.initVar); + } + } + break; + case RoomCommand::SetActorList: + { + SetActorList* cmdSetActorList = (SetActorList*)cmd; + + // There are instance of the amount of actors in the file differing from the size listed in the command. + // This can cause issues if we export actors with garbage data, so let's trust the command size + writer->Write((uint32_t)cmdSetActorList->numActors); + + for (const auto& entry : cmdSetActorList->actorList->actors) + { + writer->Write(entry.actorNum); + writer->Write(entry.posX); + writer->Write(entry.posY); + writer->Write(entry.posZ); + writer->Write(entry.rotX); + writer->Write(entry.rotY); + writer->Write(entry.rotZ); + writer->Write(entry.params); + } + } + break; + case RoomCommand::SetWind: + { + SetWind* cmdSetWind = (SetWind*)cmd; + + writer->Write(cmdSetWind->windWest); // 0x04 + writer->Write(cmdSetWind->windVertical); // 0x05 + writer->Write(cmdSetWind->windSouth); // 0x06 + writer->Write(cmdSetWind->clothFlappingStrength); // 0x07 + } + break; + case RoomCommand::SetTimeSettings: + { + SetTimeSettings* cmdTime = (SetTimeSettings*)cmd; + + writer->Write(cmdTime->hour); // 0x04 + writer->Write(cmdTime->min); // 0x05 + writer->Write(cmdTime->unk); // 0x06 + } + break; + case RoomCommand::SetSkyboxModifier: + { + SetSkyboxModifier* cmdSkybox = (SetSkyboxModifier*)cmd; + + writer->Write(cmdSkybox->disableSky); // 0x04 + writer->Write(cmdSkybox->disableSunMoon); // 0x05 + } + break; + case RoomCommand::SetEchoSettings: + { + SetEchoSettings* cmdEcho = (SetEchoSettings*)cmd; + + writer->Write((uint8_t)cmdEcho->echo); // 0x07 + } + break; + case RoomCommand::SetSoundSettings: + { + SetSoundSettings* cmdSound = (SetSoundSettings*)cmd; + + writer->Write((uint8_t)cmdSound->reverb); // 0x01 + + writer->Write(cmdSound->nightTimeSFX); // 0x06 + writer->Write(cmdSound->musicSequence); // 0x07 + } + break; + case RoomCommand::SetSkyboxSettings: + { + SetSkyboxSettings* cmdSkybox = (SetSkyboxSettings*)cmd; + + writer->Write((uint8_t)cmdSkybox->unk1); // 0x01 + writer->Write((uint8_t)cmdSkybox->skyboxNumber); // 0x04 + writer->Write((uint8_t)cmdSkybox->cloudsType); // 0x05 + writer->Write((uint8_t)cmdSkybox->isIndoors); // 0x06 + } + break; + case RoomCommand::SetRoomBehavior: + { + SetRoomBehavior* cmdRoom = (SetRoomBehavior*)cmd; + if (Globals::Instance->game == ZGame::MM_RETAIL) { + writer->Write(cmdRoom->gameplayFlags); + writer->Write(cmdRoom->currRoomUnk2); + writer->Write(cmdRoom->currRoomUnk5); + writer->Write(cmdRoom->msgCtxUnk); + writer->Write(cmdRoom->enablePosLights); + writer->Write(cmdRoom->kankyoContextUnkE2); + } else { + writer->Write((uint8_t)cmdRoom->gameplayFlags); // 0x01 + writer->Write(cmdRoom->gameplayFlags2); // 0x04 + } + } + break; + case RoomCommand::SetCsCamera: + { + SetCsCamera* cmdCsCam = (SetCsCamera*)cmd; + + writer->Write((uint32_t)cmdCsCam->cameras.size()); + segptr_t arrBase = cmdCsCam->cameras[0].baseOffset; + for (const auto& c : cmdCsCam->cameras) { + writer->Write(c.type); + writer->Write(c.numPoints); + for (int16_t i = 0; i < c.numPoints; i++) { + writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[0].scalarData.s16); + writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[1].scalarData.s16); + writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[2].scalarData.s16); + } + } + } + break; + case RoomCommand::SetMesh: + { + SetMesh* cmdMesh = (SetMesh*)cmd; + + writer->Write((uint8_t)cmdMesh->data); // 0x01 + writer->Write(cmdMesh->meshHeaderType); + + if (cmdMesh->meshHeaderType == 0 || cmdMesh->meshHeaderType == 2) + { + RoomShapeCullable* poly = (RoomShapeCullable*)cmdMesh->polyType.get(); + + writer->Write(poly->num); + + for (int i = 0; i < poly->num; i++) + WritePolyDList(writer, room, &poly->polyDLists[i]); + } + else if (cmdMesh->meshHeaderType == 1) + { + PolygonType1* poly = (PolygonType1*)cmdMesh->polyType.get(); + + writer->Write(poly->format); + + auto test = (RoomShapeDListsEntry*)&poly->polyDLists[0]; + Declaration* dListDeclOpa = poly->parent->GetDeclaration(GETSEGOFFSET(test->opa)); + Declaration* dListDeclXlu = poly->parent->GetDeclaration(GETSEGOFFSET(test->xlu)); + + if (test->opa != 0) + writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->declName.c_str())); + else + writer->Write(""); + + if (test->xlu != 0) + writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclXlu->declName.c_str())); + else + writer->Write(""); + + if (poly->format == 2) + { + writer->Write((uint32_t)poly->count); + + for (int i = 0; i < poly->count; i++) + { + writer->Write(poly->multiList[i].unk_00); + writer->Write(poly->multiList[i].id); + + Declaration* bgDecl = poly->parent->GetDeclarationRanged(GETSEGOFFSET(poly->multiList[i].source)); + + writer->Write(OTRExporter_DisplayList::GetPathToRes(poly->multiList[i].sourceBackground, bgDecl->declName)); + + writer->Write(poly->multiList[i].unk_0C); + writer->Write(poly->multiList[i].tlut); + writer->Write(poly->multiList[i].width); + writer->Write(poly->multiList[i].height); + writer->Write(poly->multiList[i].fmt); + writer->Write(poly->multiList[i].siz); + writer->Write(poly->multiList[i].mode0); + writer->Write(poly->multiList[i].tlutCount); + } + } + else + { + writer->Write((uint32_t)1); + + writer->Write(poly->single.unk_00); + writer->Write(poly->single.id); + + Declaration* bgDecl = poly->parent->GetDeclarationRanged(GETSEGOFFSET(poly->single.source)); + + writer->Write(OTRExporter_DisplayList::GetPathToRes(poly->single.sourceBackground, bgDecl->declName)); + + writer->Write(poly->single.unk_0C); + writer->Write(poly->single.tlut); + writer->Write(poly->single.width); + writer->Write(poly->single.height); + writer->Write(poly->single.fmt); + writer->Write(poly->single.siz); + writer->Write(poly->single.mode0); + writer->Write(poly->single.tlutCount); + } + + if (poly->dlist != 0) + WritePolyDList(writer, room, &poly->polyDLists[0]); + } + } + break; + case RoomCommand::SetCameraSettings: + //case RoomCommand::SetWorldMapVisited: MM command but you can't have 0x19 twice in a switch + { + if (Globals::Instance->game != ZGame::MM_RETAIL) { + SetCameraSettings* cmdCam = (SetCameraSettings*)cmd; + + writer->Write((uint8_t)cmdCam->cameraMovement); // 0x01 + writer->Write(cmdCam->mapHighlight); // 0x04 + } + } + break; + case RoomCommand::SetLightList: + { + SetLightList* cmdLight = (SetLightList*)cmd; + + writer->Write((uint32_t)cmdLight->lights.size()); + + for (size_t i = 0; i < cmdLight->lights.size(); i++) + { + writer->Write(cmdLight->lights[i].type); + writer->Write(cmdLight->lights[i].x); + writer->Write(cmdLight->lights[i].y); + writer->Write(cmdLight->lights[i].z); + writer->Write(cmdLight->lights[i].r); + writer->Write(cmdLight->lights[i].g); + writer->Write(cmdLight->lights[i].b); + writer->Write(cmdLight->lights[i].drawGlow); + writer->Write(cmdLight->lights[i].radius); + } + } + break; + case RoomCommand::SetLightingSettings: + { + SetLightingSettings* cmdLight = (SetLightingSettings*)cmd; + + writer->Write((uint32_t)cmdLight->settings.size()); // 0x01 + + for (const LightingSettings& setting : cmdLight->settings) + { + writer->Write(setting.ambientClrR); + writer->Write(setting.ambientClrG); + writer->Write(setting.ambientClrB); + + writer->Write(setting.diffuseClrA_R); + writer->Write(setting.diffuseClrA_G); + writer->Write(setting.diffuseClrA_B); + + writer->Write(setting.diffuseDirA_X); + writer->Write(setting.diffuseDirA_Y); + writer->Write(setting.diffuseDirA_Z); + + writer->Write(setting.diffuseClrB_R); + writer->Write(setting.diffuseClrB_G); + writer->Write(setting.diffuseClrB_B); + + writer->Write(setting.diffuseDirB_X); + writer->Write(setting.diffuseDirB_Y); + writer->Write(setting.diffuseDirB_Z); + + writer->Write(setting.fogClrR); + writer->Write(setting.fogClrG); + writer->Write(setting.fogClrB); + + writer->Write(setting.unk); + writer->Write(setting.drawDistance); + } + } + break; + case RoomCommand::SetRoomList: + { + SetRoomList* cmdRoom = (SetRoomList*)cmd; + + writer->Write((uint32_t)cmdRoom->romfile->numRooms); // 0x01 + + for (size_t i = 0;i < cmdRoom->romfile->numRooms; i++) + { + //std::string roomName = StringHelper::Sprintf("%s/%s_room_%i", (StringHelper::Split(room->GetName(), "_")[0] + "_scene").c_str(), StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i); + std::string roomName; + if (Globals::Instance->game != ZGame::MM_RETAIL) + roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%i", StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i)); + else + roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%02d", StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i)); + + writer->Write(roomName); + writer->Write(cmdRoom->romfile->rooms[i].virtualAddressStart); + writer->Write(cmdRoom->romfile->rooms[i].virtualAddressEnd); + } + } + break; + case RoomCommand::SetCollisionHeader: + { + SetCollisionHeader* cmdCollHeader = (SetCollisionHeader*)cmd; + + Declaration* colHeaderDecl = room->parent->GetDeclaration(cmdCollHeader->segmentOffset); + std::string path = OTRExporter_DisplayList::GetPathToRes(room, colHeaderDecl->declName); + writer->Write(path); + } + break; + case RoomCommand::SetEntranceList: + { + SetEntranceList* cmdEntrance = (SetEntranceList*)cmd; + + writer->Write((uint32_t)cmdEntrance->entrances.size()); + + for (Spawn entry : cmdEntrance->entrances) + { + writer->Write((uint8_t)entry.startPositionIndex); + writer->Write((uint8_t)entry.roomToLoad); + } + } + break; + case RoomCommand::SetSpecialObjects: + { + SetSpecialObjects* cmdSpecObj = (SetSpecialObjects*)cmd; + + writer->Write((uint8_t)cmdSpecObj->elfMessage); // 0x01 + writer->Write((uint16_t)cmdSpecObj->globalObject); // 0x06 + } + break; + case RoomCommand::SetStartPositionList: + { + SetStartPositionList* cmdStartPos = (SetStartPositionList*)cmd; + + uint32_t baseStreamEnd = writer->GetStream().get()->GetLength(); + + writer->Write((uint32_t)cmdStartPos->actors.size()); // 0x01 + + for (const ActorSpawnEntry& entry : cmdStartPos->actors) + { + writer->Write(entry.actorNum); + writer->Write(entry.posX); + writer->Write(entry.posY); + writer->Write(entry.posZ); + writer->Write(entry.rotX); + writer->Write(entry.rotY); + writer->Write(entry.rotZ); + writer->Write(entry.params); + } + } + break; + case RoomCommand::SetAlternateHeaders: + { + SetAlternateHeaders* cmdHeaders = (SetAlternateHeaders*)cmd; + + writer->Write((uint32_t)cmdHeaders->headers.size()); + + for (size_t i = 0; i < cmdHeaders->headers.size(); i++) + { + uint32_t seg = cmdHeaders->headers[i] & 0xFFFFFFFF; + std::string headerName = ""; + bool foundDecl = Globals::Instance->GetSegmentedPtrName(seg, room->parent, "", headerName, res->parent->workerID); + if (headerName == "NULL") + writer->Write(""); + else + { + std::string name = OTRExporter_DisplayList::GetPathToRes(room, headerName); + writer->Write(name); + } + } + } + break; + case RoomCommand::SetExitList: + { + SetExitList* cmdExit = (SetExitList*)cmd; + + writer->Write((uint32_t)cmdExit->exits.size()); + + for (size_t i = 0; i < cmdExit->exits.size(); i++) + writer->Write(cmdExit->exits[i]); + } + break; + case RoomCommand::SetObjectList: + { + SetObjectList* cmdSetObjectList = (SetObjectList*)cmd; + + writer->Write((uint32_t)cmdSetObjectList->objects.size()); + + for (size_t i = 0; i < cmdSetObjectList->objects.size(); i++) + writer->Write(cmdSetObjectList->objects[i]); + } + break; + case RoomCommand::SetCutscenes: + { + SetCutscenes* cmdSetCutscenes = (SetCutscenes*)cmd; + + std::string listName; + if (Globals::Instance->game == ZGame::MM_RETAIL) { + writer->Seek(-4, SeekOffsetType::Current); + writer->Write((uint32_t)RoomCommand::SetCutscenesMM); + writer->Write(cmdSetCutscenes->numCutscenes); + for (size_t i = 0; i < cmdSetCutscenes->cutsceneEntries.size(); i++) { + Globals::Instance->GetSegmentedPtrName(cmdSetCutscenes->cutsceneEntries[i].segmentPtr, room->parent, "CutsceneData", listName, res->parent->workerID); + std::string fName = OTRExporter_DisplayList::GetPathToRes(room, listName); + writer->Write(fName); + writer->Write(cmdSetCutscenes->cutsceneEntries[i].exit); + writer->Write(cmdSetCutscenes->cutsceneEntries[i].entrance); + writer->Write(cmdSetCutscenes->cutsceneEntries[i].flag); + + MemoryStream* csStream = new MemoryStream(); + BinaryWriter csWriter = BinaryWriter(csStream); + OTRExporter_Cutscene cs; + ZResource* newCs = res->parent->FindResource(cmdSetCutscenes->cutsceneEntries[i].segmentPtr & 0x00FFFFFF); + cs.Save((ZCutscene*)newCs, "", &csWriter); + + AddFile(fName, csStream->ToVector()); + } + } + else { + Globals::Instance->GetSegmentedPtrName(cmdSetCutscenes->cmdArg2, room->parent, "CutsceneData", listName, res->parent->workerID); + std::string fName = OTRExporter_DisplayList::GetPathToRes(room, listName); + writer->Write(fName); + + MemoryStream* csStream = new MemoryStream(); + BinaryWriter csWriter = BinaryWriter(csStream); + OTRExporter_Cutscene cs; + cs.Save(cmdSetCutscenes->cutscenes[0], "", &csWriter); + + AddFile(fName, csStream->ToVector()); + } + } + break; + case RoomCommand::SetPathways: + { + SetPathways* cmdSetPathways = (SetPathways*)cmd; + + writer->Write((uint32_t)cmdSetPathways->pathwayList.pathways.size()); + + for (size_t i = 0; i < cmdSetPathways->pathwayList.pathways.size(); i++) + { + Declaration* decl = room->parent->GetDeclaration(GETSEGOFFSET(cmdSetPathways->pathwayList.pathways[i].listSegmentAddress)); + //std::string path = StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), decl->varName.c_str()); + std::string path = OTRExporter_DisplayList::GetPathToRes(room, decl->declName); + writer->Write(path); + + MemoryStream* pathStream = new MemoryStream(); + BinaryWriter pathWriter = BinaryWriter(pathStream); + OTRExporter_Path pathExp; + pathExp.Save(&cmdSetPathways->pathwayList, outPath, &pathWriter); + + AddFile(path, pathStream->ToVector()); + } + } + break; + case RoomCommand::EndMarker: + break; + case RoomCommand::SetActorCutsceneList: + { + SetActorCutsceneList* list = (SetActorCutsceneList*)cmd; + writer->Write((uint32_t)list->cutscenes.size()); + + for (const auto& e : list->cutscenes) { + writer->Write(e.priority); + writer->Write(e.length); + writer->Write(e.csCamId); + writer->Write(e.scriptIndex); + writer->Write(e.additionalCsId); + writer->Write(e.endSfx); + writer->Write(e.customValue); + writer->Write(e.hudVisibility); + writer->Write(e.endCam); + writer->Write(e.letterboxSize); + } + break; + } + case RoomCommand::SetAnimatedMaterialList: { + SetAnimatedMaterialList* list = (SetAnimatedMaterialList*)cmd; + std::string listName; + Globals::Instance->GetSegmentedPtrName(cmd->cmdArg2, cmd->parent, "AnimatedMaterial", listName, + res->parent->workerID); + listName = OTRExporter_DisplayList::GetPathToRes(room, listName); + writer->Write(listName); + + MemoryStream* animatedMatStream = new MemoryStream(); + BinaryWriter animatedMatWriter = BinaryWriter(animatedMatStream); + OTRExporter_TextureAnimation texAnim; + + texAnim.Save(&list->textureAnimation, outPath, &animatedMatWriter); + + AddFile(listName, animatedMatStream->ToVector()); + + break; + } + case RoomCommand::SetMinimapList: { + SetMinimapList* list = (SetMinimapList*)cmd; + + writer->Write((uint32_t)list->minimaps.size()); + writer->Write(list->scale); + + for (const auto& m : list->minimaps) { + writer->Write(m.unk0); + writer->Write(m.unk2); + writer->Write(m.unk4); + writer->Write(m.unk6); + writer->Write(m.unk8); + } + + break; + } + case RoomCommand::SetMinimapChests: { + SetMinimapChests* chests = (SetMinimapChests*)cmd; + + writer->Write((uint32_t)chests->chests.size()); + + for (const auto& c : chests->chests) { + writer->Write(c.unk0); + writer->Write(c.unk2); + writer->Write(c.unk4); + writer->Write(c.unk6); + writer->Write(c.unk8); + } + break; + } + default: + printf("UNIMPLEMENTED COMMAND: 0x%02X\n", (int)cmd->cmdID); + + break; + } + } } void OTRExporter_Room::WritePolyDList(BinaryWriter* writer, ZRoom* room, RoomShapeDListsEntry* dlist) { - writer->Write(dlist->polyType); - - switch (dlist->polyType) - { - case 2: - writer->Write(dlist->x); - writer->Write(dlist->y); - writer->Write(dlist->z); - writer->Write(dlist->unk_06); - [[fallthrough]]; - default: - //writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str())); - - if (dlist->opaDList != nullptr) - { - auto opaDecl = room->parent->GetDeclaration(GETSEGOFFSET(dlist->opaDList->GetRawDataIndex())); - writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), opaDecl->declName.c_str())); - } - else - writer->Write(""); - - if (dlist->xluDList != nullptr) - { - auto xluDecl = room->parent->GetDeclaration(GETSEGOFFSET(dlist->xluDList->GetRawDataIndex())); - writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), xluDecl->declName.c_str())); - } - else - writer->Write(""); - break; - } + writer->Write(dlist->polyType); + + switch (dlist->polyType) + { + case 2: + writer->Write(dlist->x); + writer->Write(dlist->y); + writer->Write(dlist->z); + writer->Write(dlist->unk_06); + [[fallthrough]]; + default: + //writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str())); + + if (dlist->opaDList != nullptr) + { + auto opaDecl = room->parent->GetDeclaration(GETSEGOFFSET(dlist->opaDList->GetRawDataIndex())); + writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), opaDecl->declName.c_str())); + } + else + writer->Write(""); + + if (dlist->xluDList != nullptr) + { + auto xluDecl = room->parent->GetDeclaration(GETSEGOFFSET(dlist->xluDList->GetRawDataIndex())); + writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), xluDecl->declName.c_str())); + } + else + writer->Write(""); + break; + } } diff --git a/OTRExporter/TextureAnimationExporter.cpp b/OTRExporter/TextureAnimationExporter.cpp index b5841ae..4c5712c 100644 --- a/OTRExporter/TextureAnimationExporter.cpp +++ b/OTRExporter/TextureAnimationExporter.cpp @@ -86,7 +86,7 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, writer->Write(""); } } - writer->Write(cycleParams->textureIndexList.size()); + //writer->Write(cycleParams->textureIndexList.size()); for (const auto index : cycleParams->textureIndexList) { writer->Write(index); } From 899d615f0856fe0a4b8928cc5342b8e9725a36e3 Mon Sep 17 00:00:00 2001 From: Random <28494085+Random06457@users.noreply.github.com> Date: Tue, 19 Dec 2023 04:00:16 +0100 Subject: [PATCH 15/55] add hack to load gSunDL textures corretly (#2) --- OTRExporter/CutsceneExporter.cpp | 4 ++-- OTRExporter/DisplayListExporter.cpp | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/OTRExporter/CutsceneExporter.cpp b/OTRExporter/CutsceneExporter.cpp index 53c9340..0074bc1 100644 --- a/OTRExporter/CutsceneExporter.cpp +++ b/OTRExporter/CutsceneExporter.cpp @@ -416,8 +416,8 @@ void OTRExporter_Cutscene::SaveOot(ZCutscene* cs, BinaryWriter* writer) { } // MUST be uint16_t for -1 typedef enum : uint16_t { - /* -1 */ CS_TEXT_TYPE_NONE = -1, - /* 0 */ CS_TEXT_TYPE_DEFAULT, + /* -1 */ CS_TEXT_TYPE_NONE = (uint16_t)-1, + /* 0 */ CS_TEXT_TYPE_DEFAULT = 0, /* 1 */ CS_TEXT_TYPE_1, /* 2 */ CS_TEXT_OCARINA_ACTION, /* 3 */ CS_TEXT_TYPE_3, diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index 5d6465f..4ff3c4f 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -274,6 +274,12 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t xxx = (data & 0x0000000000FFF000) >> 12; int32_t ddd = (data & 0x0000000000000FFF); + // gSunDL Textures are rendered as i8 instead of i4 + if (res->GetName() == "gSunDL" && ttt != G_TX_LOADTILE) + { + xxx = (xxx+1)/2-1; + } + Gfx value = {gsDPLoadBlock(i, sss, ttt, xxx, ddd)}; word0 = value.words.w0; word1 = value.words.w1; @@ -604,6 +610,12 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t bbbb = (data & 0b0000000000000000000000000000000000000000000000000000000011110000) >> 4; int32_t uuuu = (data & 0b0000000000000000000000000000000000000000000000000000000000001111); + // gSunDL Textures are rendered as i8 instead of i4 + if (res->GetName() == "gSunDL" && ttt != G_TX_LOADTILE) + { + ii = G_IM_SIZ_4b; + } + Gfx value = {gsDPSetTile(fff, ii, nnnnnnnnn, mmmmmmmmm, ttt, pppp, cc, aaaa, ssss, dd, bbbb, uuuu)}; word0 = value.words.w0; word1 = value.words.w1; From 1a615823b039b9524c3ecfdcce268971d806ddf9 Mon Sep 17 00:00:00 2001 From: Nicholas Estelami Date: Thu, 4 Jan 2024 20:40:15 -0500 Subject: [PATCH 16/55] Fixed cs camera exporter --- OTRExporter/RoomExporter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OTRExporter/RoomExporter.cpp b/OTRExporter/RoomExporter.cpp index ce6292d..ebefd23 100644 --- a/OTRExporter/RoomExporter.cpp +++ b/OTRExporter/RoomExporter.cpp @@ -176,14 +176,14 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite SetCsCamera* cmdCsCam = (SetCsCamera*)cmd; writer->Write((uint32_t)cmdCsCam->cameras.size()); - segptr_t arrBase = cmdCsCam->cameras[0].baseOffset; + segptr_t arrBase = cmdCsCam->cameras[0].segmentOffset; for (const auto& c : cmdCsCam->cameras) { writer->Write(c.type); writer->Write(c.numPoints); for (int16_t i = 0; i < c.numPoints; i++) { - writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[0].scalarData.s16); - writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[1].scalarData.s16); - writer->Write(cmdCsCam->points[((c.baseOffset - arrBase) / 6) + i].scalars[2].scalarData.s16); + writer->Write(cmdCsCam->points[((c.segmentOffset - arrBase) / 6) + i].scalars[0].scalarData.s16); + writer->Write(cmdCsCam->points[((c.segmentOffset - arrBase) / 6) + i].scalars[1].scalarData.s16); + writer->Write(cmdCsCam->points[((c.segmentOffset - arrBase) / 6) + i].scalars[2].scalarData.s16); } } } From 4b5da168afef89c525662211a986dc818ccf042f Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Fri, 5 Jan 2024 09:36:27 -0600 Subject: [PATCH 17/55] Changes to build on mac --- OTRExporter/CutsceneExporter.cpp | 2 +- OTRExporter/DisplayListExporter.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OTRExporter/CutsceneExporter.cpp b/OTRExporter/CutsceneExporter.cpp index 0074bc1..d4e9345 100644 --- a/OTRExporter/CutsceneExporter.cpp +++ b/OTRExporter/CutsceneExporter.cpp @@ -489,7 +489,7 @@ void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { // BENTODO: Can these stay consilidated? case CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE: { writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE); - writer->Write((uint32_t)cs->commands[i]->entries.size() * sizeof(uint32_t)); + writer->Write((uint32_t)(cs->commands[i]->entries.size() * sizeof(uint32_t))); for (const auto e : cs->commands[i]->entries) { auto* cmd = (CutsceneSubCommandEntry_Camera*)e; writer->Write(CMD_HH(cmd->base, cmd->startFrame)); diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index 4ff3c4f..8f65bf7 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -873,8 +873,8 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina if (lastOpCode != G_ENDDL) { Gfx value = { gsSPEndDisplayList() }; - writer->Write(value.words.w0); - writer->Write(value.words.w1); + writer->Write((uint32_t)value.words.w0); + writer->Write((uint32_t)value.words.w1); } auto dlEnd = std::chrono::steady_clock::now(); From 1503937d90c4fd885d49007f17c652e972401d2e Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Tue, 9 Jan 2024 20:59:04 -0500 Subject: [PATCH 18/55] new config and new exporter --- CFG/Config.xml | 4 +- CFG/EnumData.xml | 718 +++++++++++++++++++++++++++++++ OTRExporter/CutsceneExporter.cpp | 52 ++- 3 files changed, 769 insertions(+), 5 deletions(-) create mode 100644 CFG/EnumData.xml diff --git a/CFG/Config.xml b/CFG/Config.xml index 02656c7..f43ba62 100644 --- a/CFG/Config.xml +++ b/CFG/Config.xml @@ -2,7 +2,7 @@ - + - + \ No newline at end of file diff --git a/CFG/EnumData.xml b/CFG/EnumData.xml new file mode 100644 index 0000000..2ade5b3 --- /dev/null +++ b/CFG/EnumData.xml @@ -0,0 +1,718 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/CutsceneExporter.cpp b/OTRExporter/CutsceneExporter.cpp index d4e9345..23d0162 100644 --- a/OTRExporter/CutsceneExporter.cpp +++ b/OTRExporter/CutsceneExporter.cpp @@ -425,6 +425,13 @@ typedef enum : uint16_t { /* 5 */ CS_TEXT_TYPE_ALL_NORMAL_MASKS } CutsceneTextType; +typedef enum : uint8_t { + /* 0 */ Header, + /* 1 */ CamPoint, + /* 2 */ CamMisc, + /* 3 */ Footer, +} CutsceneSplineType; + #define WRITE_CMD_PROLOG(cmd) \ writer->Write((uint32_t)cmd); \ writer->Write((uint32_t)cs->commands[i]->entries.size()); @@ -490,10 +497,49 @@ void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { case CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE: { writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE); writer->Write((uint32_t)(cs->commands[i]->entries.size() * sizeof(uint32_t))); - for (const auto e : cs->commands[i]->entries) { - auto* cmd = (CutsceneSubCommandEntry_Camera*)e; - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + // monkaS + size_t j = 0; + for (;;) { + auto* header = dynamic_cast(cs->commands[i]->entries[j]); + + //Debugging check, can probably remove after testing + assert(header != nullptr); + uint32_t numEntries = header->numEntries; + writer->Write(CMD_HH(header->numEntries, header->unused0)); + writer->Write(CMD_HH(header->unused1, header->duration)); + + for (size_t k = 0; k < numEntries * 2; k++) { + auto* element = + dynamic_cast(cs->commands[i]->entries[++j]); + // Debugging check, can probably remove after testing + assert(element != nullptr); + writer->Write(CMD_BBH(element->interpType, element->weight, element->duration)); + writer->Write(CMD_HH(element->posX, element->posY)); + writer->Write(CMD_HH(element->posZ, element->relTo)); + } + for (size_t k = 0; k < numEntries; k++) { + auto* element = + dynamic_cast(cs->commands[i]->entries[++j]); + // Debugging check, can probably remove after testing + assert(element != nullptr); + writer->Write(CMD_HH(element->unused0, element->roll)); + writer->Write(CMD_HH(element->fov, element->unused1)); + } + + auto* header2 = dynamic_cast(cs->commands[i]->entries[++j]); + if (header2 != nullptr) { + if (header2->base == 0xFFFF) { + break; + } + } } + + // The footer exists as an error checking type and a way to output an empty macro. It holds no actual data. + auto* footer = dynamic_cast(cs->commands[i]->entries[j]); + assert(footer != nullptr); + writer->Write((uint16_t)0xFFFF); + writer->Write((uint16_t)0x0004); + //i += j; break; } case CutsceneMM_CommandType::CS_CMD_MISC: { From 66587f278e72b2b25b5db393601032824b3eaaa7 Mon Sep 17 00:00:00 2001 From: Archez Date: Tue, 9 Jan 2024 21:38:56 -0500 Subject: [PATCH 19/55] make otrexporter support mm better (#4) --- CFG/Config.xml | 4 ++-- extract_assets.py | 13 ++++++++----- rom_info.py | 24 ++++++++++++++++++------ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/CFG/Config.xml b/CFG/Config.xml index f43ba62..867b5fa 100644 --- a/CFG/Config.xml +++ b/CFG/Config.xml @@ -3,6 +3,6 @@ - + - \ No newline at end of file + diff --git a/extract_assets.py b/extract_assets.py index 931384b..1e31109 100755 --- a/extract_assets.py +++ b/extract_assets.py @@ -77,12 +77,15 @@ def main(): BuildCustomOtr(args.zapd_exe, args.custom_assets_path, args.custom_otr_file, portVer=args.port_ver) return -# //roms = [ Z64Rom(args.rom) ] if args.rom else rom_chooser.chooseROM(args.verbose, args.non_interactive) -# //for rom in roms: -# // if (os.path.exists("Extract")): -# // shutil.rmtree("Extract") + roms = [ Z64Rom(args.rom) ] if args.rom else rom_chooser.chooseROM(args.verbose, args.non_interactive) + for rom in roms: + if (not rom.isMMRom): + continue - BuildOTR("../mm/assets/xml/", baserom_uncompressed.z64, zapd_exe=args.zapd_exe, genHeaders=args.gen_headers) + if (os.path.exists("Extract")): + shutil.rmtree("Extract") + + BuildOTR("../mm/assets/xml/", rom.file_path, zapd_exe=args.zapd_exe, genHeaders=args.gen_headers) if __name__ == "__main__": main() diff --git a/rom_info.py b/rom_info.py index 897b145..d532d1e 100644 --- a/rom_info.py +++ b/rom_info.py @@ -20,16 +20,21 @@ class Checksums(Enum): OOT_PAL_GC_MQ_DBG = "917D18F6" OOT_IQUE_TW = "3D81FB3E" OOT_IQUE_CN = "B1E1E07B" - OOT_UNKNOWN = "FFFFFFFF" + + MM_US_10 = "5354631C" + MM_US_10_UNCOMPRESSED = "DA6983E7" + + UNKNOWN = "FFFFFFFF" @classmethod def has_value(self, value): return value in self._value2member_map_ class RomVersion: - def __init__(self, file_table_path, file_table_off, xml_ver): + def __init__(self, file_table_path, file_table_off, xml_ver, is_mm=False): self.file_table_off = file_table_off self.xml_ver = xml_ver + self.is_mm = is_mm with open(file_table_path, 'r') as f: self.file_table = [line.strip('\n') for line in f] @@ -41,6 +46,9 @@ def __init__(self, file_table_path, file_table_off, xml_ver): ROM_INFO_TABLE[Checksums.OOT_PAL_10] = RomVersion("CFG/filelists/pal_oot.txt", 0x7950, "N64_PAL_10") ROM_INFO_TABLE[Checksums.OOT_PAL_11] = RomVersion("CFG/filelists/pal_oot.txt", 0x7950, "N64_PAL_11") +ROM_INFO_TABLE[Checksums.MM_US_10] = RomVersion("CFG/filelists/mm.txt", 0x1A500, "N64_PAL_11", is_mm=True) +ROM_INFO_TABLE[Checksums.MM_US_10_UNCOMPRESSED] = RomVersion("CFG/filelists/mm.txt", 0x1A500, "N64_PAL_11", is_mm=True) + class RomDmaEntry: def __init__(self, rom, i): @@ -71,12 +79,12 @@ def __init__(self, file_path): # get checkum checksum_str = self.rom_data[16:16+4].hex().upper() - self.checksum = Checksums(checksum_str) if Checksums.has_value(checksum_str) else Checksums.OOT_UNKNOWN + self.checksum = Checksums(checksum_str) if Checksums.has_value(checksum_str) else Checksums.UNKNOWN - if self.checksum == Checksums.OOT_UNKNOWN: + if self.checksum == Checksums.UNKNOWN: self.is_valid = False return - + if self.checksum in [Checksums.OOT_NTSC_JP_MQ, Checksums.OOT_NTSC_US_MQ, Checksums.OOT_PAL_GC_MQ_DBG, Checksums.OOT_PAL_MQ]: self.isMq = True else: @@ -94,7 +102,11 @@ def readDmaEntry(self, entry): @staticmethod def isValidRom(rom_path): return Z64Rom(rom_path).is_valid - + @staticmethod def isMqRom(rom_path): return Z64Rom(rom_path).isMq + + @staticmethod + def isMMRom(rom_path): + return Z64Rom(rom_path).version.is_mm From b6c2ee9cb4aa27eaaf4c87fc59c6dced99871f7a Mon Sep 17 00:00:00 2001 From: Louis <35883445+louist103@users.noreply.github.com> Date: Thu, 11 Jan 2024 21:39:54 -0500 Subject: [PATCH 20/55] 64 bit fixes --- CFG/EnumData.xml | 1436 ++++++++++++++++++------------------ OTRExporter/CMakeLists.txt | 2 +- 2 files changed, 719 insertions(+), 719 deletions(-) diff --git a/CFG/EnumData.xml b/CFG/EnumData.xml index 2ade5b3..8343a0b 100644 --- a/CFG/EnumData.xml +++ b/CFG/EnumData.xml @@ -1,718 +1,718 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OTRExporter/CMakeLists.txt b/OTRExporter/CMakeLists.txt index 35d060e..12e11fe 100644 --- a/OTRExporter/CMakeLists.txt +++ b/OTRExporter/CMakeLists.txt @@ -95,7 +95,7 @@ endif() ################################################################################ if (CMAKE_SYSTEM_NAME STREQUAL "Windows") get_property(MSVC_RUNTIME_LIBRARY_DEFAULT TARGET ${PROJECT_NAME} PROPERTY MSVC_RUNTIME_LIBRARY) - if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") + if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32" OR "${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") string(CONCAT "MSVC_RUNTIME_LIBRARY_STR" $<$: MultiThreadedDebug From 906ddd81fd04e9e2b819a16fd6e6c1134c60e3ad Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sun, 14 Jan 2024 02:53:34 +0000 Subject: [PATCH 21/55] Fix issue with dlists referencing offsets outside of their own file (#5) --- OTRExporter/DisplayListExporter.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index 8f65bf7..5f84abe 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -455,9 +455,24 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina } else { - word0 = 0; - word1 = 0; - spdlog::error(StringHelper::Sprintf("dListDecl == nullptr! Addr = {:08X}", GETSEGOFFSET(data))); + // If we can't find the display list in this file, try looking in other files based on the segment number + uint32_t seg = data & 0xFFFFFFFF; + std::string resourceName = ""; + bool foundDecl = Globals::Instance->GetSegmentedPtrName(seg, dList->parent, "", resourceName, res->parent->workerID); + if (foundDecl) { + ZFile* assocFile = Globals::Instance->GetSegment(GETSEGNUM(seg), res->parent->workerID); + std::string assocFileName = assocFile->GetName(); + std::string fName = GetPathToRes(assocFile->resources[0], resourceName.c_str()); + + uint64_t hash = CRC64(fName.c_str()); + + word0 = hash >> 32; + word1 = hash & 0xFFFFFFFF; + } else { + word0 = 0; + word1 = 0; + spdlog::error(StringHelper::Sprintf("dListDecl == nullptr! Addr = {:08X}", GETSEGOFFSET(data))); + } } for (size_t i = 0; i < dList->otherDLists.size(); i++) From fb78ffd5ddc18d03f07991002bb2a756beaef528 Mon Sep 17 00:00:00 2001 From: Louis <35883445+louist103@users.noreply.github.com> Date: Sat, 13 Jan 2024 23:49:07 -0500 Subject: [PATCH 22/55] Fix for splines --- OTRExporter/CutsceneExporter.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OTRExporter/CutsceneExporter.cpp b/OTRExporter/CutsceneExporter.cpp index 23d0162..dcb31aa 100644 --- a/OTRExporter/CutsceneExporter.cpp +++ b/OTRExporter/CutsceneExporter.cpp @@ -496,7 +496,11 @@ void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { // BENTODO: Can these stay consilidated? case CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE: { writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE); - writer->Write((uint32_t)(cs->commands[i]->entries.size() * sizeof(uint32_t))); + // This command uses 4 different macros that are all different sizes and uses the number of bytes of the + // whole command instead of entries like most other commands. numEntries isn't actually the number of entries in the command + // rather the number of bytes the command will take up in the rom. We also can not simply use GetCommandSize because it returns + // a larger size to help ZAPD know where to start reading for the next command. + writer->Write(cs->commands[i]->numEntries); // monkaS size_t j = 0; for (;;) { From 9cf49d9a868e55bcdcf18462ae7e809477440274 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sun, 14 Jan 2024 05:07:56 +0000 Subject: [PATCH 23/55] Fix for dlist referencing vtx outside of their own file (#6) --- OTRExporter/DisplayListExporter.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index 5f84abe..f5dcb41 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -793,6 +793,22 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina int32_t aa = (data & 0x000000FF00000000ULL) >> 32; int32_t nn = (data & 0x000FF00000000000ULL) >> 44; + bool isSegmentedPtr = false; + std::string fName = ""; + + // If we can't find the display list in this file, try looking in other files based on the segment number + if (vtxDecl == nullptr) { + uint32_t seg = data & 0xFFFFFFFF; + std::string resourceName = ""; + isSegmentedPtr = Globals::Instance->GetSegmentedPtrName(seg, dList->parent, "", resourceName, res->parent->workerID); + + if (isSegmentedPtr) { + ZFile* assocFile = Globals::Instance->GetSegment(GETSEGNUM(seg), res->parent->workerID); + std::string assocFileName = assocFile->GetName(); + fName = GetPathToRes(assocFile->resources[0], resourceName.c_str()); + vtxDecl = assocFile->GetDeclarationRanged(segOffset); + } + } if (vtxDecl != nullptr && vtxDecl->declName != "Gfx") { @@ -808,7 +824,9 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina writer->Write(word0); writer->Write(word1); - std::string fName = OTRExporter_DisplayList::GetPathToRes(res, vtxDecl->declName); + if (!isSegmentedPtr) { + fName = OTRExporter_DisplayList::GetPathToRes(res, vtxDecl->declName); + } uint64_t hash = CRC64(fName.c_str()); From a43066bcced50032a092d45dd9b50bcbd829b0a0 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Mon, 15 Jan 2024 20:12:08 +0000 Subject: [PATCH 24/55] Fix cycle animated textures (#7) --- OTRExporter/TextureAnimationExporter.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/OTRExporter/TextureAnimationExporter.cpp b/OTRExporter/TextureAnimationExporter.cpp index 4c5712c..2acca8a 100644 --- a/OTRExporter/TextureAnimationExporter.cpp +++ b/OTRExporter/TextureAnimationExporter.cpp @@ -4,6 +4,7 @@ #include #include "TextureAnimationExporter.h" #include "DisplayListExporter.h" +#include #undef FindResource @@ -16,7 +17,7 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, for (const auto& e : anim->entries) { auto* params = (ZTextureAnimationParams*)res->parent->FindResource(Seg2Filespace(e.paramsPtr, res->parent->baseAddress)); writer->Write(e.segment); - writer->Write((uint8_t)e.type); + writer->Write((int16_t)e.type); switch ((TextureAnimationParamsType)e.type) { case TextureAnimationParamsType::SingleScroll: case TextureAnimationParamsType::DualScroll: { @@ -72,8 +73,15 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, for (const auto t : cycleParams->textureList) { std::string name; - //ZTexture* tex = (ZTexture*)res->parent->FindResource(t & 0x00FFFFFF); bool found = Globals::Instance->GetSegmentedPtrName(GETSEGOFFSET(t), res->parent, "", name, res->parent->workerID); + + if (!found) { + ZTexture* tex = (ZTexture*)res->parent->FindResource(t & 0x00FFFFFF); + if (tex != nullptr) { + name = tex->GetName(); + found = true; + } + } if (found) { if (name.at(0) == '&') @@ -83,6 +91,7 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, } else { + spdlog::error("Texture not found: 0x{:X}", t); writer->Write(""); } } From 5194bd96f0102e1206f59aaba403ebd3b1f7a516 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Thu, 18 Jan 2024 02:34:47 +0000 Subject: [PATCH 25/55] Fix some textures (#8) --- OTRExporter/DisplayListExporter.cpp | 40 +++++++++++++++++++---------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index f5dcb41..031c88e 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -723,9 +723,6 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina } else { - std::string texName = ""; - bool foundDecl = Globals::Instance->GetSegmentedPtrName(seg, dList->parent, "", texName, res->parent->workerID); - int32_t __ = (data & 0x00FF000000000000) >> 48; int32_t www = (data & 0x00000FFF00000000) >> 32; @@ -741,18 +738,35 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina writer->Write(word0); writer->Write(word1); - if (foundDecl) - { - ZFile* assocFile = Globals::Instance->GetSegment(GETSEGNUM(seg), res->parent->workerID); - std::string assocFileName = assocFile->GetName(); - std::string fName = ""; + bool foundDecl = false; + std::string resourcePath = ""; - if (GETSEGNUM(seg) == SEGMENT_SCENE || GETSEGNUM(seg) == SEGMENT_ROOM) - fName = GetPathToRes(res, texName.c_str()); - else - fName = GetPathToRes(assocFile->resources[0], texName.c_str()); + // First check current file + if (res->parent->segment == GETSEGNUM(seg)) { + uint32_t segmentOffset = GETSEGOFFSET(seg); + Declaration* resourceDecl = dList->parent->GetDeclaration(segmentOffset); - uint64_t hash = CRC64(fName.c_str()); + if (resourceDecl != nullptr) + { + foundDecl = true; + resourcePath = OTRExporter_DisplayList::GetPathToRes(res, resourceDecl->declName); + } + } + + // Then check in global resources + if (!foundDecl) { + foundDecl = Globals::Instance->GetSegmentedPtrName(seg, dList->parent, "", resourcePath, res->parent->workerID); + + if (foundDecl) { + ZFile* assocFile = Globals::Instance->GetSegment(GETSEGNUM(seg), res->parent->workerID); + std::string assocFileName = assocFile->GetName(); + resourcePath = GetPathToRes(assocFile->resources[0], resourcePath); + } + } + + if (foundDecl) + { + uint64_t hash = CRC64(resourcePath.c_str()); word0 = hash >> 32; word1 = hash & 0xFFFFFFFF; From 6fa3aaf3d484e6ba3f3cbeea71fef5d7640ba591 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Thu, 18 Jan 2024 02:35:05 +0000 Subject: [PATCH 26/55] Fix alternate scene header room paths (#9) --- OTRExporter/RoomExporter.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/OTRExporter/RoomExporter.cpp b/OTRExporter/RoomExporter.cpp index ebefd23..979a98b 100644 --- a/OTRExporter/RoomExporter.cpp +++ b/OTRExporter/RoomExporter.cpp @@ -354,7 +354,13 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite if (Globals::Instance->game != ZGame::MM_RETAIL) roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%i", StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i)); else - roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%02d", StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i)); + { + // Alt headers use the rooms from their parent room. For example we want SPOT00/SPOT00_room_00, not SPOT00/SPOT00Set_00A050_room_00 + if (room->zroomType == ZResourceType::AltHeader) + roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%02d", cmd->parent->GetName().c_str(), i)); + else + roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%02d", StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i)); + } writer->Write(roomName); writer->Write(cmdRoom->romfile->rooms[i].virtualAddressStart); From 0c572f2883ebf0c550f561a1661023ed55cdae7b Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sat, 20 Jan 2024 02:08:18 +0000 Subject: [PATCH 27/55] Fix incorrect cutscene write types (#10) --- OTRExporter/CutsceneExporter.cpp | 155 +++++-------------------------- 1 file changed, 25 insertions(+), 130 deletions(-) diff --git a/OTRExporter/CutsceneExporter.cpp b/OTRExporter/CutsceneExporter.cpp index dcb31aa..0e19a0c 100644 --- a/OTRExporter/CutsceneExporter.cpp +++ b/OTRExporter/CutsceneExporter.cpp @@ -432,75 +432,38 @@ typedef enum : uint8_t { /* 3 */ Footer, } CutsceneSplineType; -#define WRITE_CMD_PROLOG(cmd) \ - writer->Write((uint32_t)cmd); \ - writer->Write((uint32_t)cs->commands[i]->entries.size()); - void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { for (size_t i = 0; i < cs->commands.size(); i++) { + writer->Write((uint32_t)cs->commands[i]->commandID); + if (((cs->commands[i]->commandID >= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_100) && (cs->commands[i]->commandID <= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_149)) || (cs->commands[i]->commandID == (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_201) || ((cs->commands[i]->commandID >= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_450) && (cs->commands[i]->commandID <= (uint32_t)CutsceneMM_CommandType::CS_CMD_ACTOR_CUE_599))) { - WRITE_CMD_PROLOG(cs->commands[i]->commandID); goto actorCue; } + switch ((CutsceneMM_CommandType)cs->commands[i]->commandID) { case CutsceneMM_CommandType::CS_CMD_TEXT: { - writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_TEXT); writer->Write((uint32_t)cs->commands[i]->entries.size()); for (const auto& e : cs->commands[i]->entries) { auto* cmd = (CutsceneMMSubCommandEntry_Text*)e; - switch ((CutsceneTextType)cmd->type) { - case CS_TEXT_TYPE_DEFAULT: // 0 - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->type)); - writer->Write(CMD_HH(cmd->textId1, cmd->textId2)); - break; - case CS_TEXT_TYPE_1: // 1 - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->type)); - writer->Write(CMD_HH(cmd->textId1, cmd->textId2)); - break; - case CS_TEXT_OCARINA_ACTION: // 2 - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->type)); - writer->Write(CMD_HH(cmd->textId1, 0xFFFF)); - break; - case CS_TEXT_TYPE_3: // 3 - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->type)); - writer->Write(CMD_HH(cmd->textId1, cmd->textId2)); - break; - case CS_TEXT_TYPE_BOSSES_REMAINS: // 4 - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->type)); - writer->Write(CMD_HH(cmd->textId1, 0xFFFF)); - break; - case CS_TEXT_TYPE_ALL_NORMAL_MASKS: // 5 - writer->Write(CMD_HH(cmd->base, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, cmd->type)); - writer->Write(CMD_HH(cmd->textId1, 0xFFFF)); - break; - case CS_TEXT_TYPE_NONE: // -1 - writer->Write(CMD_HH(0xFFFF, cmd->startFrame)); - writer->Write(CMD_HH(cmd->endFrame, 0xFFFF)); - writer->Write(CMD_HH(0xFFFF, 0xFFFF)); - } + writer->Write(CMD_HH(cmd->base, cmd->startFrame)); + writer->Write(CMD_HH(cmd->endFrame, cmd->type)); + writer->Write(CMD_HH(cmd->textId1, cmd->textId2)); } break; } // BENTODO: Can these stay consilidated? case CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE: { - writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_CAMERA_SPLINE); // This command uses 4 different macros that are all different sizes and uses the number of bytes of the // whole command instead of entries like most other commands. numEntries isn't actually the number of entries in the command // rather the number of bytes the command will take up in the rom. We also can not simply use GetCommandSize because it returns // a larger size to help ZAPD know where to start reading for the next command. - writer->Write(cs->commands[i]->numEntries); + writer->Write((uint32_t)cs->commands[i]->numEntries); // monkaS size_t j = 0; for (;;) { @@ -546,92 +509,31 @@ void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { //i += j; break; } - case CutsceneMM_CommandType::CS_CMD_MISC: { - writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_MISC); - writer->Write((uint32_t)cs->commands[i]->entries.size()); - for (const auto e : cs->commands[i]->entries) { - writer->Write(CMD_HH(e->base, e->startFrame)); - writer->Write(CMD_HH(e->endFrame, e->pad)); - } - break; - } - case CutsceneMM_CommandType::CS_CMD_LIGHT_SETTING: { - writer->Write((uint32_t)CutsceneMM_CommandType::CS_CMD_LIGHT_SETTING); - writer->Write((uint32_t)cs->commands[i]->entries.size()); - for (const auto e : cs->commands[i]->entries) { - writer->Write(CMD_BBH(0, e->base, e->startFrame)); - writer->Write(CMD_HH(e->endFrame, e->endFrame)); - } - break; - } - - case CutsceneMM_CommandType::CS_CMD_TRANSITION: { - WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_TRANSITION); - - for (const auto e : cs->commands[i]->entries) { - writer->Write(CMD_HH(e->base, e->startFrame)); - writer->Write(CMD_HH(e->endFrame, e->endFrame)); - } - break; - } - case CutsceneMM_CommandType::CS_CMD_MOTION_BLUR: { - WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_MOTION_BLUR); - - for (const auto e : cs->commands[i]->entries) { - writer->Write(CMD_HH(e->base, e->startFrame)); - writer->Write(CMD_HH(e->endFrame, e->endFrame)); - } - break; - } - case CutsceneMM_CommandType::CS_CMD_GIVE_TATL: { - WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_GIVE_TATL); - - for (const auto e : cs->commands[i]->entries) { - writer->Write(CMD_HH(e->base, e->startFrame)); - writer->Write(CMD_HH(e->endFrame, e->endFrame)); - } - break; - } + case CutsceneMM_CommandType::CS_CMD_MISC: + case CutsceneMM_CommandType::CS_CMD_LIGHT_SETTING: + case CutsceneMM_CommandType::CS_CMD_TRANSITION: + case CutsceneMM_CommandType::CS_CMD_MOTION_BLUR: + case CutsceneMM_CommandType::CS_CMD_GIVE_TATL: case CutsceneMM_CommandType::CS_CMD_STOP_SEQ: - case CutsceneMM_CommandType::CS_CMD_START_SEQ: { - WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_START_SEQ); - for (const auto e : cs->commands[i]->entries) { - writer->Write(CMD_BBH(0, e->base, e->startFrame)); - writer->Write(CMD_HH(e->endFrame, e->endFrame)); - } - break; - } + case CutsceneMM_CommandType::CS_CMD_START_SEQ: case CutsceneMM_CommandType::CS_CMD_SFX_REVERB_INDEX_2: case CutsceneMM_CommandType::CS_CMD_SFX_REVERB_INDEX_1: case CutsceneMM_CommandType::CS_CMD_MODIFY_SEQ: - case CutsceneMM_CommandType::CS_CMD_START_AMBIENCE: case CutsceneMM_CommandType::CS_CMD_FADE_OUT_AMBIENCE: case CutsceneMM_CommandType::CS_CMD_DESTINATION: case CutsceneMM_CommandType::CS_CMD_CHOOSE_CREDITS_SCENES: - - case CutsceneMM_CommandType::CS_CMD_UNK_DATA_FA: - case CutsceneMM_CommandType::CS_CMD_UNK_DATA_FE: - case CutsceneMM_CommandType::CS_CMD_UNK_DATA_FF: - case CutsceneMM_CommandType::CS_CMD_UNK_DATA_100: - case CutsceneMM_CommandType::CS_CMD_UNK_DATA_101: - case CutsceneMM_CommandType::CS_CMD_UNK_DATA_102: - case CutsceneMM_CommandType::CS_CMD_UNK_DATA_103: - case CutsceneMM_CommandType::CS_CMD_UNK_DATA_104: - case CutsceneMM_CommandType::CS_CMD_UNK_DATA_105: - case CutsceneMM_CommandType::CS_CMD_UNK_DATA_108: - case CutsceneMM_CommandType::CS_CMD_UNK_DATA_109: { - writer->Write((uint32_t)cs->commands[i]->commandID); + default: + { writer->Write((uint32_t)cs->commands[i]->entries.size()); for (const auto e : cs->commands[i]->entries) { - writer->Write(CMD_BBH(0, e->base, e->startFrame)); - writer->Write(CMD_HH(e->endFrame, e->endFrame)); + writer->Write(CMD_HH(e->base, e->startFrame)); + writer->Write(CMD_HH(e->endFrame, e->pad)); } break; } case CutsceneMM_CommandType::CS_CMD_TRANSITION_GENERAL: { - WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_TRANSITION_GENERAL); - + writer->Write((uint32_t)cs->commands[i]->entries.size()); for (const auto e : cs->commands[i]->entries) { auto* cmd = (CutsceneSubCommandEntry_TransitionGeneral*)e; @@ -642,29 +544,28 @@ void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { break; } case CutsceneMM_CommandType::CS_CMD_FADE_OUT_SEQ: { - WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_FADE_OUT_SEQ); - + writer->Write((uint32_t)cs->commands[i]->entries.size()); for (const auto e : cs->commands[i]->entries) { writer->Write(CMD_HH(e->base, e->startFrame)); - writer->Write(CMD_HH(e->endFrame, 0)); + writer->Write(CMD_HH(e->endFrame, e->pad)); + writer->Write(CMD_W(0)); } break; } case CutsceneMM_CommandType::CS_CMD_TIME: { - WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_TIME); - + writer->Write((uint32_t)cs->commands[i]->entries.size()); for (const auto e : cs->commands[i]->entries) { auto* cmd = (CutsceneSubCommandEntry_SetTime*)e; writer->Write(CMD_HH(cmd->base, cmd->startFrame)); writer->Write(CMD_HBB(cmd->endFrame, cmd->hour, cmd->minute)); - // Skipping the zero word + writer->Write(CMD_W(0)); } break; } case CutsceneMM_CommandType::CS_CMD_PLAYER_CUE: { - WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_PLAYER_CUE); actorCue: + writer->Write((uint32_t)cs->commands[i]->entries.size()); for (const auto e : cs->commands[i]->entries) { auto* cmd = (CutsceneMMSubCommandEntry_ActorCue*)e; @@ -684,8 +585,7 @@ void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { break; } case CutsceneMM_CommandType::CS_CMD_RUMBLE: { - WRITE_CMD_PROLOG(CutsceneMM_CommandType::CS_CMD_RUMBLE); - + writer->Write((uint32_t)cs->commands[i]->entries.size()); for (const auto e : cs->commands[i]->entries) { auto* cmd = (CutsceneMMSubCommandEntry_Rumble*)e; @@ -695,11 +595,6 @@ void OTRExporter_Cutscene::SaveMM(ZCutscene* cs, BinaryWriter* writer) { } break; } - default: { - // writer->Write((uint32_t)cs->commands[i]->commandID); - printf("Undefined CS Opcode: %04X\n", cs->commands[i]->commandID); - break; - } } } } From a86929b240164af481fe1fca2d0ac19c5f206be4 Mon Sep 17 00:00:00 2001 From: Garrett Cox Date: Sun, 21 Jan 2024 22:26:00 +0000 Subject: [PATCH 28/55] Write size of animated texture cycle list (#11) --- OTRExporter/TextureAnimationExporter.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/OTRExporter/TextureAnimationExporter.cpp b/OTRExporter/TextureAnimationExporter.cpp index 2acca8a..50e32a3 100644 --- a/OTRExporter/TextureAnimationExporter.cpp +++ b/OTRExporter/TextureAnimationExporter.cpp @@ -67,9 +67,9 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, case TextureAnimationParamsType::TextureCycle: { auto* cycleParams = (TextureCyclingParams*)params; - // cycleLength is the same langth writer->Write(cycleParams->cycleLength); - //writer->Write(cycleParams->textureList.size()); + // Texture list may or may not be the same size as the index list, so we need to write the size of the list for the importer + writer->Write((uint32_t)cycleParams->textureList.size()); for (const auto t : cycleParams->textureList) { std::string name; @@ -95,7 +95,6 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, writer->Write(""); } } - //writer->Write(cycleParams->textureIndexList.size()); for (const auto index : cycleParams->textureIndexList) { writer->Write(index); } From 2c959105cd720930303f5e3aa67a5c0871b070f8 Mon Sep 17 00:00:00 2001 From: Louis <35883445+louist103@users.noreply.github.com> Date: Mon, 29 Jan 2024 23:46:57 -0500 Subject: [PATCH 29/55] CKeyFrame Exporter --- OTRExporter/CKeyFrameExporter.cpp | 103 ++++++++++++++++++++++++++++++ OTRExporter/CKeyFrameExporter.h | 18 ++++++ OTRExporter/CMakeLists.txt | 2 + OTRExporter/Main.cpp | 4 +- 4 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 OTRExporter/CKeyFrameExporter.cpp create mode 100644 OTRExporter/CKeyFrameExporter.h diff --git a/OTRExporter/CKeyFrameExporter.cpp b/OTRExporter/CKeyFrameExporter.cpp new file mode 100644 index 0000000..9b3320a --- /dev/null +++ b/OTRExporter/CKeyFrameExporter.cpp @@ -0,0 +1,103 @@ +#include "CKeyFrameExporter.h" +#include "DisplayListExporter.h" +#include "Globals.h" +#include "spdlog/spdlog.h" + +// The Win32 API defines this function for its own uses. +#ifdef FindResource +#undef FindResource +#endif + +void OTRExporter_CKeyFrameSkel::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) { + ZKeyFrameSkel* skel = (ZKeyFrameSkel*)res; + ZKeyFrameLimbList* list = skel->limbList.get(); + + WriteHeader(res, outPath, writer, LUS::ResourceType::TSH_CKeyFrameSkel); + + writer->Write(skel->limbCount); + writer->Write(skel->dListCount); + writer->Write((uint8_t)skel->limbType); + writer->Write(list->numLimbs); + + + for (size_t i = 0; i < list->limbs.size(); i++) { + ZKeyFrameLimb* limb = list->limbs[i]; + std::string name = ""; + if (GETSEGOFFSET(limb->dlist) != SEGMENTED_NULL) { + bool found = Globals::Instance->GetSegmentedPtrName(GETSEGOFFSET(limb->dlist), res->parent, "", name, + res->parent->workerID); + + if (!found) { + ZDisplayList* dl = (ZDisplayList*)res->parent->FindResource(limb->dlist & 0x00FFFFFF); + if (dl != nullptr) { + name = dl->GetName(); + found = true; + } + } + if (found) { + if (name.at(0) == '&') + name.erase(0, 1); + + name = OTRExporter_DisplayList::GetPathToRes(res, name); + } else { + spdlog::error("Texture not found: 0x{:X}", limb->dlist); + //writer->Write(""); + name = ""; + } + } + writer->Write(name); + writer->Write(limb->numChildren); + writer->Write(limb->flags); + + if (skel->limbType == ZKeyframeSkelType::Normal) { + ZKeyFrameStandardLimb* stdLimb = (ZKeyFrameStandardLimb*)limb; + + writer->Write(stdLimb->translation.x); + writer->Write(stdLimb->translation.y); + writer->Write(stdLimb->translation.z); + } else { + ZKeyFrameFlexLimb* flexLimb = (ZKeyFrameFlexLimb*)limb; + + writer->Write(flexLimb->callbackIndex); + } + } +} + +void OTRExporter_CKeyFrameAnim::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) { + ZKeyFrameAnim* anim = (ZKeyFrameAnim*)res; + + WriteHeader(res, outPath, writer, LUS::ResourceType::TSH_CKeyFrameAnim); + + writer->Write((uint8_t)anim->skel->limbType); + if (anim->skel->limbType == ZKeyframeSkelType::Normal) { + writer->Write((uint32_t)anim->bitFlags.size()); + for (const auto b : anim->bitFlags) { + writer->Write(b); + } + } else { + writer->Write((uint32_t)anim->bitFlagsFLex.size()); + for (const auto b : anim->bitFlagsFLex) { + writer->Write(b); + } + } + + writer->Write((uint32_t)anim->keyFrames.size()); + for (const auto k : anim->keyFrames) { + writer->Write(k.frame); + writer->Write(k.value); + writer->Write(k.velocity); + } + + writer->Write((uint32_t)anim->kfNums.size()); + for (const auto kf : anim->kfNums) { + writer->Write(kf); + } + + writer->Write((uint32_t)anim->presentValues.size()); + for (const auto pv : anim->presentValues) { + writer->Write(pv); + } + + writer->Write(anim->unk_10); + writer->Write(anim->duration); +} diff --git a/OTRExporter/CKeyFrameExporter.h b/OTRExporter/CKeyFrameExporter.h new file mode 100644 index 0000000..1c690e7 --- /dev/null +++ b/OTRExporter/CKeyFrameExporter.h @@ -0,0 +1,18 @@ +#pragma once + +#include "ZResource.h" +#include "ZCKeyFrame.h" +#include "ZCkeyFrameAnim.h" +#include "Exporter.h" +#include + +class OTRExporter_CKeyFrameSkel : public OTRExporter +{ +public: + virtual void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override; +}; + +class OTRExporter_CKeyFrameAnim : public OTRExporter { + public: + virtual void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override; +}; diff --git a/OTRExporter/CMakeLists.txt b/OTRExporter/CMakeLists.txt index 12e11fe..f7b89fd 100644 --- a/OTRExporter/CMakeLists.txt +++ b/OTRExporter/CMakeLists.txt @@ -9,6 +9,7 @@ set(Header_Files "AudioExporter.h" "BackgroundExporter.h" "BlobExporter.h" + "CKeyFrameExporter.h" "CollisionExporter.h" "command_macros_base.h" "CutsceneExporter.h" @@ -40,6 +41,7 @@ set(Source_Files "BackgroundExporter.cpp" "BlobExporter.cpp" "CollisionExporter.cpp" + "CKeyFrameExporter.cpp" "CutsceneExporter.cpp" "DisplayListExporter.cpp" "Exporter.cpp" diff --git a/OTRExporter/Main.cpp b/OTRExporter/Main.cpp index 42bfe76..99e8693 100644 --- a/OTRExporter/Main.cpp +++ b/OTRExporter/Main.cpp @@ -19,6 +19,7 @@ #include "MtxExporter.h" #include "AudioExporter.h" #include "TextureAnimationExporter.h" +#include "CKeyFrameExporter.h" #include #include #include @@ -390,7 +391,8 @@ void ImportExporters() exporterSet->exporters[ZResourceType::Mtx] = new OTRExporter_MtxExporter(); exporterSet->exporters[ZResourceType::Audio] = new OTRExporter_Audio(); exporterSet->exporters[ZResourceType::TextureAnimation] = new OTRExporter_TextureAnimation(); - + exporterSet->exporters[ZResourceType::KeyFrameSkel] = new OTRExporter_CKeyFrameSkel(); + exporterSet->exporters[ZResourceType::KeyFrameAnimation] = new OTRExporter_CKeyFrameAnim(); Globals::AddExporter("OTR", exporterSet); InitVersionInfo(); From 5e29bf2d7030dfe834a8352a456bde40d1aa6bef Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Tue, 30 Jan 2024 19:14:55 -0500 Subject: [PATCH 30/55] KeyFrameExporter --- OTRExporter/CKeyFrameExporter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OTRExporter/CKeyFrameExporter.cpp b/OTRExporter/CKeyFrameExporter.cpp index 9b3320a..8828ce0 100644 --- a/OTRExporter/CKeyFrameExporter.cpp +++ b/OTRExporter/CKeyFrameExporter.cpp @@ -75,8 +75,8 @@ void OTRExporter_CKeyFrameAnim::Save(ZResource* res, const fs::path& outPath, Bi writer->Write(b); } } else { - writer->Write((uint32_t)anim->bitFlagsFLex.size()); - for (const auto b : anim->bitFlagsFLex) { + writer->Write((uint32_t)anim->bitFlagsFlex.size()); + for (const auto b : anim->bitFlagsFlex) { writer->Write(b); } } @@ -93,8 +93,8 @@ void OTRExporter_CKeyFrameAnim::Save(ZResource* res, const fs::path& outPath, Bi writer->Write(kf); } - writer->Write((uint32_t)anim->presentValues.size()); - for (const auto pv : anim->presentValues) { + writer->Write((uint32_t)anim->presetValues.size()); + for (const auto pv : anim->presetValues) { writer->Write(pv); } From b9d4f4d841f7c6f5ee8efc006d4cc8c683ec1088 Mon Sep 17 00:00:00 2001 From: Louis <35883445+louist103@users.noreply.github.com> Date: Tue, 30 Jan 2024 21:45:10 -0500 Subject: [PATCH 31/55] u != U --- OTRExporter/CKeyFrameExporter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OTRExporter/CKeyFrameExporter.h b/OTRExporter/CKeyFrameExporter.h index 1c690e7..6e8fe45 100644 --- a/OTRExporter/CKeyFrameExporter.h +++ b/OTRExporter/CKeyFrameExporter.h @@ -4,7 +4,7 @@ #include "ZCKeyFrame.h" #include "ZCkeyFrameAnim.h" #include "Exporter.h" -#include +#include class OTRExporter_CKeyFrameSkel : public OTRExporter { From 199dc67d2c7e0f342a8f21d59f1c78ab7ffb865d Mon Sep 17 00:00:00 2001 From: Archez Date: Sun, 18 Feb 2024 14:34:15 -0500 Subject: [PATCH 32/55] handle all sgement lookups for vtx commands (#12) --- OTRExporter/DisplayListExporter.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index 031c88e..e6a8031 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -782,17 +782,15 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina break; case G_VTX: { - if (GETSEGNUM(data) == 0xC || GETSEGNUM(data) == 0x8) + if (!Globals::Instance->HasSegment(GETSEGNUM(data), res->parent->workerID)) { - // hack for dynamic verticies used in en_ganon_mant and en_jsjutan - // TODO is there a better way? int32_t aa = (data & 0x000000FF00000000ULL) >> 32; int32_t nn = (data & 0x000FF00000000000ULL) >> 44; - Gfx value = {gsSPVertex(data & 0xFFFFFFFF, nn, ((aa >> 1) - nn))}; + Gfx value = {gsSPVertex((data & 0xFFFFFFFF) + 1, nn, ((aa >> 1) - nn))}; word0 = value.words.w0; - word1 = value.words.w1 | 1; + word1 = value.words.w1; } else { From ccfa54711a6239deeff58621fddab1c25dbec4e0 Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Sun, 3 Mar 2024 12:15:19 -0500 Subject: [PATCH 33/55] Fix files from MM --- OTRExporter/CKeyFrameExporter.cpp | 4 +- OTRExporter/Exporter.h | 2 +- OTRExporter/TextMMExporter.cpp | 2 +- OTRExporter/TextureAnimationExporter.cpp | 2 +- OTRExporter/VersionInfo.cpp | 2 +- .../accessibility/texts/filechoose_eng.json | 29 ++ .../accessibility/texts/filechoose_fra.json | 29 ++ .../accessibility/texts/filechoose_ger.json | 29 ++ .../accessibility/texts/kaleidoscope_eng.json | 231 ++++++++++++ .../accessibility/texts/kaleidoscope_fra.json | 231 ++++++++++++ .../accessibility/texts/kaleidoscope_ger.json | 231 ++++++++++++ assets/accessibility/texts/misc_eng.json | 24 ++ assets/accessibility/texts/misc_fra.json | 24 ++ assets/accessibility/texts/misc_ger.json | 24 ++ assets/accessibility/texts/scenes_eng.json | 112 ++++++ assets/accessibility/texts/scenes_fra.json | 112 ++++++ assets/accessibility/texts/scenes_ger.json | 112 ++++++ assets/fonts/Fipps-Regular.otf | Bin 0 -> 34220 bytes assets/fonts/PressStart2P-Regular.ttf | Bin 0 -> 116008 bytes .../cosmetics/gEndGrayscaleAndEndDlistDL | 5 + ...stmasGreenTreasureChestFrontTex.rgb5a1.png | Bin 0 -> 2917 bytes ...GreenTreasureChestSideAndTopTex.rgb5a1.png | Bin 0 -> 1111 bytes ...ristmasRedTreasureChestFrontTex.rgb5a1.png | Bin 0 -> 3518 bytes ...asRedTreasureChestSideAndTopTex.rgb5a1.png | Bin 0 -> 1661 bytes .../gGoldTreasureChestFrontTex.rgb5a1.png | Bin 0 -> 4727 bytes ...gGoldTreasureChestSideAndTopTex.rgb5a1.png | Bin 0 -> 2338 bytes .../gKeyTreasureChestFrontTex.rgb5a1.png | Bin 0 -> 4233 bytes .../gKeyTreasureChestSideAndTopTex.rgb5a1.png | Bin 0 -> 2184 bytes .../gSkullTreasureChestFrontTex.rgb5a1.png | Bin 0 -> 4265 bytes ...SkullTreasureChestSideAndTopTex.rgb5a1.png | Bin 0 -> 1979 bytes .../gTitleBossRushSubtitleTex.rgba32.png | Bin 0 -> 6291 bytes .../gTitleRandomizerSubtitleTex.rgba32.png | Bin 0 -> 6971 bytes .../gTriforcePieceCompletedDL | 13 + .../gTriforcePieceCompletedDL_tri_0 | 58 +++ .../gTriforcePieceCompletedDL_tri_1 | 7 + .../gTriforcePieceCompletedDL_vtx_0 | 54 +++ .../gTriforcePieceCompletedDL_vtx_1 | 8 + ...rcePieceCompletedDL_f3dlite_triforce_edges | 21 ++ ...ePieceCompletedDL_f3dlite_triforce_surface | 21 ++ .../object_triforce_completed/noise_tex | Bin 0 -> 2140 bytes .../object_triforce_piece_0/gTriforcePiece0DL | 15 + .../gTriforcePiece0DL_tri_0 | 17 + .../gTriforcePiece0DL_tri_1 | 18 + .../gTriforcePiece0DL_tri_2 | 51 +++ .../gTriforcePiece0DL_vtx_0 | 18 + .../gTriforcePiece0DL_vtx_1 | 22 ++ .../gTriforcePiece0DL_vtx_2 | 49 +++ .../mat_gTriforcePiece0DL_f3dlite_shard_edge | 21 ++ ...t_gTriforcePiece0DL_f3dlite_triforce_edges | 21 ++ ...gTriforcePiece0DL_f3dlite_triforce_surface | 21 ++ .../objects/object_triforce_piece_0/noise_tex | Bin 0 -> 2140 bytes .../object_triforce_piece_1/gTriforcePiece1DL | 13 + .../gTriforcePiece1DL_tri_0 | 20 ++ .../gTriforcePiece1DL_tri_1 | 25 ++ .../gTriforcePiece1DL_vtx_0 | 23 ++ .../gTriforcePiece1DL_vtx_1 | 34 ++ .../mat_gTriforcePiece1DL_f3dlite_shard_edge | 21 ++ ...gTriforcePiece1DL_f3dlite_triforce_surface | 21 ++ .../objects/object_triforce_piece_1/noise_tex | Bin 0 -> 2140 bytes .../object_triforce_piece_2/gTriforcePiece2DL | 15 + .../gTriforcePiece2DL_tri_0 | 29 ++ .../gTriforcePiece2DL_tri_1 | 11 + .../gTriforcePiece2DL_tri_2 | 19 + .../gTriforcePiece2DL_vtx_0 | 36 ++ .../gTriforcePiece2DL_vtx_1 | 12 + .../gTriforcePiece2DL_vtx_2 | 18 + .../mat_gTriforcePiece2DL_f3dlite_shard_edge | 21 ++ ...t_gTriforcePiece2DL_f3dlite_triforce_edges | 21 ++ ...gTriforcePiece2DL_f3dlite_triforce_surface | 21 ++ .../objects/object_triforce_piece_2/noise_tex | Bin 0 -> 2140 bytes .../scenes/nonmq/syotes_scene/syotes_room_0 | Bin 0 -> 211 bytes assets/textures/buttons/ABtn.png | Bin 0 -> 10967 bytes assets/textures/buttons/BBtn.png | Bin 0 -> 1300 bytes assets/textures/buttons/CDown.png | Bin 0 -> 11241 bytes assets/textures/buttons/CLeft.png | Bin 0 -> 11232 bytes assets/textures/buttons/CRight.png | Bin 0 -> 11284 bytes assets/textures/buttons/CUp.png | Bin 0 -> 11219 bytes assets/textures/buttons/LBtn.png | Bin 0 -> 355 bytes assets/textures/buttons/RBtn.png | Bin 0 -> 379 bytes assets/textures/buttons/StartBtn.png | Bin 0 -> 11868 bytes assets/textures/buttons/ZBtn.png | Bin 0 -> 1241 bytes assets/textures/icons/gIcon.png | Bin 0 -> 932 bytes assets/textures/nintendo_rogo_static/SoHShiny | Bin 0 -> 1116 bytes .../textures/nintendo_rogo_static/gShipLogoDL | 21 ++ .../nintendo_rogo_static/gShipLogoDL_tri_0 | 241 +++++++++++++ .../nintendo_rogo_static/gShipLogoDL_tri_1 | 80 +++++ .../nintendo_rogo_static/gShipLogoDL_tri_2 | 259 ++++++++++++++ .../nintendo_rogo_static/gShipLogoDL_tri_3 | 118 ++++++ .../nintendo_rogo_static/gShipLogoDL_vtx_0 | 335 ++++++++++++++++++ .../nintendo_rogo_static/gShipLogoDL_vtx_1 | 98 +++++ .../nintendo_rogo_static/gShipLogoDL_vtx_2 | 323 +++++++++++++++++ .../nintendo_rogo_static/gShipLogoDL_vtx_3 | 128 +++++++ .../mat_gShipLogoDL_f3d_material | 20 ++ .../mat_gShipLogoDL_f3d_material_001 | 20 ++ .../mat_gShipLogoDL_f3d_material_002 | 20 ++ .../mat_gShipLogoDL_f3d_material_003 | 20 ++ .../mat_revert_gShipLogoDL_f3d_material | 8 + .../mat_revert_gShipLogoDL_f3d_material_001 | 8 + .../mat_revert_gShipLogoDL_f3d_material_002 | 8 + .../mat_revert_gShipLogoDL_f3d_material_003 | 8 + .../nintendo_rogo_static_Tex_LUS_000000 | Bin 0 -> 6291548 bytes .../parameter_static/gArrowDown.ia16.png | Bin 0 -> 17227 bytes .../parameter_static/gArrowUp.ia16.png | Bin 0 -> 17217 bytes .../textures/parameter_static/gDPad.ia16.png | Bin 0 -> 1017 bytes .../gTriforcePiece.rgba32.png | Bin 0 -> 1761 bytes .../gFileSelBossRushSettingsENGTex.ia8.png | Bin 0 -> 4004 bytes .../gFileSelBossRushSettingsFRATex.ia8.png | Bin 0 -> 3942 bytes .../gFileSelBossRushSettingsGERTex.ia8.png | Bin 0 -> 3884 bytes .../title_static/gFileSelMQButtonTex.ia16.png | Bin 0 -> 883 bytes .../gFileSelPleaseChooseAQuestENGTex.ia8.png | Bin 0 -> 3682 bytes .../gFileSelPleaseChooseAQuestFRATex.ia8.png | Bin 0 -> 3852 bytes .../gFileSelPleaseChooseAQuestGERTex.ia8.png | Bin 0 -> 3666 bytes .../gFileSelRANDButtonTex.ia16.png | Bin 0 -> 1045 bytes .../textures/virtual/gEmptyTexture.rgba32.png | Bin 0 -> 194 bytes extract_assets.py | 18 +- 115 files changed, 3715 insertions(+), 18 deletions(-) create mode 100644 assets/accessibility/texts/filechoose_eng.json create mode 100644 assets/accessibility/texts/filechoose_fra.json create mode 100644 assets/accessibility/texts/filechoose_ger.json create mode 100644 assets/accessibility/texts/kaleidoscope_eng.json create mode 100644 assets/accessibility/texts/kaleidoscope_fra.json create mode 100644 assets/accessibility/texts/kaleidoscope_ger.json create mode 100644 assets/accessibility/texts/misc_eng.json create mode 100644 assets/accessibility/texts/misc_fra.json create mode 100644 assets/accessibility/texts/misc_ger.json create mode 100644 assets/accessibility/texts/scenes_eng.json create mode 100644 assets/accessibility/texts/scenes_fra.json create mode 100644 assets/accessibility/texts/scenes_ger.json create mode 100644 assets/fonts/Fipps-Regular.otf create mode 100644 assets/fonts/PressStart2P-Regular.ttf create mode 100644 assets/helpers/cosmetics/gEndGrayscaleAndEndDlistDL create mode 100644 assets/objects/object_box/gChristmasGreenTreasureChestFrontTex.rgb5a1.png create mode 100644 assets/objects/object_box/gChristmasGreenTreasureChestSideAndTopTex.rgb5a1.png create mode 100644 assets/objects/object_box/gChristmasRedTreasureChestFrontTex.rgb5a1.png create mode 100644 assets/objects/object_box/gChristmasRedTreasureChestSideAndTopTex.rgb5a1.png create mode 100644 assets/objects/object_box/gGoldTreasureChestFrontTex.rgb5a1.png create mode 100644 assets/objects/object_box/gGoldTreasureChestSideAndTopTex.rgb5a1.png create mode 100644 assets/objects/object_box/gKeyTreasureChestFrontTex.rgb5a1.png create mode 100644 assets/objects/object_box/gKeyTreasureChestSideAndTopTex.rgb5a1.png create mode 100644 assets/objects/object_box/gSkullTreasureChestFrontTex.rgb5a1.png create mode 100644 assets/objects/object_box/gSkullTreasureChestSideAndTopTex.rgb5a1.png create mode 100644 assets/objects/object_mag/gTitleBossRushSubtitleTex.rgba32.png create mode 100644 assets/objects/object_mag/gTitleRandomizerSubtitleTex.rgba32.png create mode 100644 assets/objects/object_triforce_completed/gTriforcePieceCompletedDL create mode 100644 assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_tri_0 create mode 100644 assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_tri_1 create mode 100644 assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_vtx_0 create mode 100644 assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_vtx_1 create mode 100644 assets/objects/object_triforce_completed/mat_gTriforcePieceCompletedDL_f3dlite_triforce_edges create mode 100644 assets/objects/object_triforce_completed/mat_gTriforcePieceCompletedDL_f3dlite_triforce_surface create mode 100644 assets/objects/object_triforce_completed/noise_tex create mode 100644 assets/objects/object_triforce_piece_0/gTriforcePiece0DL create mode 100644 assets/objects/object_triforce_piece_0/gTriforcePiece0DL_tri_0 create mode 100644 assets/objects/object_triforce_piece_0/gTriforcePiece0DL_tri_1 create mode 100644 assets/objects/object_triforce_piece_0/gTriforcePiece0DL_tri_2 create mode 100644 assets/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_0 create mode 100644 assets/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_1 create mode 100644 assets/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_2 create mode 100644 assets/objects/object_triforce_piece_0/mat_gTriforcePiece0DL_f3dlite_shard_edge create mode 100644 assets/objects/object_triforce_piece_0/mat_gTriforcePiece0DL_f3dlite_triforce_edges create mode 100644 assets/objects/object_triforce_piece_0/mat_gTriforcePiece0DL_f3dlite_triforce_surface create mode 100644 assets/objects/object_triforce_piece_0/noise_tex create mode 100644 assets/objects/object_triforce_piece_1/gTriforcePiece1DL create mode 100644 assets/objects/object_triforce_piece_1/gTriforcePiece1DL_tri_0 create mode 100644 assets/objects/object_triforce_piece_1/gTriforcePiece1DL_tri_1 create mode 100644 assets/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_0 create mode 100644 assets/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_1 create mode 100644 assets/objects/object_triforce_piece_1/mat_gTriforcePiece1DL_f3dlite_shard_edge create mode 100644 assets/objects/object_triforce_piece_1/mat_gTriforcePiece1DL_f3dlite_triforce_surface create mode 100644 assets/objects/object_triforce_piece_1/noise_tex create mode 100644 assets/objects/object_triforce_piece_2/gTriforcePiece2DL create mode 100644 assets/objects/object_triforce_piece_2/gTriforcePiece2DL_tri_0 create mode 100644 assets/objects/object_triforce_piece_2/gTriforcePiece2DL_tri_1 create mode 100644 assets/objects/object_triforce_piece_2/gTriforcePiece2DL_tri_2 create mode 100644 assets/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_0 create mode 100644 assets/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_1 create mode 100644 assets/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_2 create mode 100644 assets/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_f3dlite_shard_edge create mode 100644 assets/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_f3dlite_triforce_edges create mode 100644 assets/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_f3dlite_triforce_surface create mode 100644 assets/objects/object_triforce_piece_2/noise_tex create mode 100644 assets/scenes/nonmq/syotes_scene/syotes_room_0 create mode 100644 assets/textures/buttons/ABtn.png create mode 100644 assets/textures/buttons/BBtn.png create mode 100644 assets/textures/buttons/CDown.png create mode 100644 assets/textures/buttons/CLeft.png create mode 100644 assets/textures/buttons/CRight.png create mode 100644 assets/textures/buttons/CUp.png create mode 100644 assets/textures/buttons/LBtn.png create mode 100644 assets/textures/buttons/RBtn.png create mode 100644 assets/textures/buttons/StartBtn.png create mode 100644 assets/textures/buttons/ZBtn.png create mode 100644 assets/textures/icons/gIcon.png create mode 100644 assets/textures/nintendo_rogo_static/SoHShiny create mode 100644 assets/textures/nintendo_rogo_static/gShipLogoDL create mode 100644 assets/textures/nintendo_rogo_static/gShipLogoDL_tri_0 create mode 100644 assets/textures/nintendo_rogo_static/gShipLogoDL_tri_1 create mode 100644 assets/textures/nintendo_rogo_static/gShipLogoDL_tri_2 create mode 100644 assets/textures/nintendo_rogo_static/gShipLogoDL_tri_3 create mode 100644 assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_0 create mode 100644 assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_1 create mode 100644 assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_2 create mode 100644 assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_3 create mode 100644 assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material create mode 100644 assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_001 create mode 100644 assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_002 create mode 100644 assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_003 create mode 100644 assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material create mode 100644 assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_001 create mode 100644 assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_002 create mode 100644 assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_003 create mode 100644 assets/textures/nintendo_rogo_static/nintendo_rogo_static_Tex_LUS_000000 create mode 100644 assets/textures/parameter_static/gArrowDown.ia16.png create mode 100644 assets/textures/parameter_static/gArrowUp.ia16.png create mode 100644 assets/textures/parameter_static/gDPad.ia16.png create mode 100644 assets/textures/parameter_static/gTriforcePiece.rgba32.png create mode 100644 assets/textures/title_static/gFileSelBossRushSettingsENGTex.ia8.png create mode 100644 assets/textures/title_static/gFileSelBossRushSettingsFRATex.ia8.png create mode 100644 assets/textures/title_static/gFileSelBossRushSettingsGERTex.ia8.png create mode 100644 assets/textures/title_static/gFileSelMQButtonTex.ia16.png create mode 100644 assets/textures/title_static/gFileSelPleaseChooseAQuestENGTex.ia8.png create mode 100644 assets/textures/title_static/gFileSelPleaseChooseAQuestFRATex.ia8.png create mode 100644 assets/textures/title_static/gFileSelPleaseChooseAQuestGERTex.ia8.png create mode 100644 assets/textures/title_static/gFileSelRANDButtonTex.ia16.png create mode 100644 assets/textures/virtual/gEmptyTexture.rgba32.png diff --git a/OTRExporter/CKeyFrameExporter.cpp b/OTRExporter/CKeyFrameExporter.cpp index 8828ce0..30c3e40 100644 --- a/OTRExporter/CKeyFrameExporter.cpp +++ b/OTRExporter/CKeyFrameExporter.cpp @@ -12,7 +12,7 @@ void OTRExporter_CKeyFrameSkel::Save(ZResource* res, const fs::path& outPath, Bi ZKeyFrameSkel* skel = (ZKeyFrameSkel*)res; ZKeyFrameLimbList* list = skel->limbList.get(); - WriteHeader(res, outPath, writer, LUS::ResourceType::TSH_CKeyFrameSkel); + WriteHeader(res, outPath, writer, static_cast(SOH::ResourceType::TSH_CKeyFrameSkel)); writer->Write(skel->limbCount); writer->Write(skel->dListCount); @@ -66,7 +66,7 @@ void OTRExporter_CKeyFrameSkel::Save(ZResource* res, const fs::path& outPath, Bi void OTRExporter_CKeyFrameAnim::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) { ZKeyFrameAnim* anim = (ZKeyFrameAnim*)res; - WriteHeader(res, outPath, writer, LUS::ResourceType::TSH_CKeyFrameAnim); + WriteHeader(res, outPath, writer, static_cast(SOH::ResourceType::TSH_CKeyFrameAnim)); writer->Write((uint8_t)anim->skel->limbType); if (anim->skel->limbType == ZKeyframeSkelType::Normal) { diff --git a/OTRExporter/Exporter.h b/OTRExporter/Exporter.h index 0844c54..4f5b84a 100644 --- a/OTRExporter/Exporter.h +++ b/OTRExporter/Exporter.h @@ -5,7 +5,7 @@ #include #include #include "VersionInfo.h" -#include "../../soh/soh/resource/type/SohResourceType.h" +#include "../../mm/2s2h/resource/type/2shResourceType.h" class OTRExporter : public ZResourceExporter { diff --git a/OTRExporter/TextMMExporter.cpp b/OTRExporter/TextMMExporter.cpp index b022b63..c7c424a 100644 --- a/OTRExporter/TextMMExporter.cpp +++ b/OTRExporter/TextMMExporter.cpp @@ -5,7 +5,7 @@ void OTRExporter_TextMM::Save(ZResource* res, const fs::path& outPath, BinaryWri { ZTextMM* txt = (ZTextMM*)res; - WriteHeader(txt, outPath, writer, LUS::ResourceType::SOH_TextMM); + WriteHeader(txt, outPath, writer, static_cast(SOH::ResourceType::TSH_TextMM)); writer->Write((uint32_t)txt->messages.size()); diff --git a/OTRExporter/TextureAnimationExporter.cpp b/OTRExporter/TextureAnimationExporter.cpp index 50e32a3..ba4376c 100644 --- a/OTRExporter/TextureAnimationExporter.cpp +++ b/OTRExporter/TextureAnimationExporter.cpp @@ -11,7 +11,7 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) { auto* anim = (ZTextureAnimation*)res; - WriteHeader(res, outPath, writer, LUS::ResourceType::TSH_TexAnim, 0); + WriteHeader(res, outPath, writer, static_cast(SOH::ResourceType::TSH_TexAnim), 0); writer->Write((uint32_t)anim->entries.size()); for (const auto& e : anim->entries) { diff --git a/OTRExporter/VersionInfo.cpp b/OTRExporter/VersionInfo.cpp index 1dbc3df..7e643d5 100644 --- a/OTRExporter/VersionInfo.cpp +++ b/OTRExporter/VersionInfo.cpp @@ -1,6 +1,6 @@ #include "VersionInfo.h" #include -#include "../../soh/soh/resource/type/SohResourceType.h" +#include "../../mm/2s2h/resource/type/2shResourceType.h" std::map resourceVersions; diff --git a/assets/accessibility/texts/filechoose_eng.json b/assets/accessibility/texts/filechoose_eng.json new file mode 100644 index 0000000..b437199 --- /dev/null +++ b/assets/accessibility/texts/filechoose_eng.json @@ -0,0 +1,29 @@ +{ + "file1": "File 1", + "file2": "File 2", + "file3": "File 3", + "options": "Options", + "copy": "Copy", + "erase": "Erase", + "quit": "Quit", + "confirm": "Yes", + "end": "End", + "hyphen": "Hyphen", + "period": "Period", + "space": "Space", + "backspace": "Backspace", + "capital_letter": "Capital $0", + "audio_stereo": "Sound - Stereo", + "audio_mono": "Sound - Mono", + "audio_headset": "Sound - Headset", + "audio_surround": "Sound - Surround", + "target_switch": "Targeting Mode - Switch", + "target_hold": "Targeting Mode - Hold", + "language_english": "Language - English", + "language_german": "Language - German", + "language_french": "Language - French", + "quest_sel_vanilla": "Quest - Original", + "quest_sel_mq": "Quest - Master Quest", + "quest_sel_randomizer": "Quest - Randomizer", + "quest_sel_boss_rush": "Quest - Boss Rush" +} \ No newline at end of file diff --git a/assets/accessibility/texts/filechoose_fra.json b/assets/accessibility/texts/filechoose_fra.json new file mode 100644 index 0000000..f76861f --- /dev/null +++ b/assets/accessibility/texts/filechoose_fra.json @@ -0,0 +1,29 @@ +{ + "file1": "Fichier 1", + "file2": "Fichier 2", + "file3": "Fichier 3", + "options": "Options", + "copy": "Copier", + "erase": "Effacer", + "quit": "Retour", + "confirm": "Oui", + "end": "Fin", + "hyphen": "Trait d'union", + "period": "Point", + "space": "Espace", + "backspace": "Retour arrière", + "capital_letter": "Majuscule $0", + "audio_stereo": "Son - Stéréo", + "audio_mono": "Son - Mono", + "audio_headset": "Son - Casque", + "audio_surround": "Son - Surround", + "target_switch": "Visée - Fixe", + "target_hold": "Visée - Maintenue", + "language_english": "Langue - Anglaise", + "language_german": "Langue - Allemande", + "language_french": "Langue - Français", + "quest_sel_vanilla": "Quête - Originale", + "quest_sel_mq": "Quête - Master Quest", + "quest_sel_randomizer": "Quête - Randomizer", + "quest_sel_boss_rush": "Quête - Boss Rush" +} \ No newline at end of file diff --git a/assets/accessibility/texts/filechoose_ger.json b/assets/accessibility/texts/filechoose_ger.json new file mode 100644 index 0000000..2ad1322 --- /dev/null +++ b/assets/accessibility/texts/filechoose_ger.json @@ -0,0 +1,29 @@ +{ + "file1": "Datei 1", + "file2": "Datei 2", + "file3": "Datei 3", + "options": "Optionen", + "copy": "Kopieren", + "erase": "Löschen", + "quit": "Zurück", + "confirm": "Ja", + "end": "Ende", + "hyphen": "Bindestrich", + "period": "Punkt", + "space": "Raum", + "backspace": "Rücktaste", + "capital_letter": "Großbuchstabe $0", + "audio_stereo": "Sound - Stereo", + "audio_mono": "Sound - Mono", + "audio_headset": "Sound - Kopfhörer", + "audio_surround": "Sound - Surround", + "target_switch": "Zielerfassung - Einmal drücken", + "target_hold": "Zielerfassung - Trigger halten", + "language_english": "Sprache - Englisch", + "language_german": "Sprache - Deutsch", + "language_french": "Sprache - Französisch", + "quest_sel_vanilla": "Quest - Original", + "quest_sel_mq": "Quest - Master Quest", + "quest_sel_randomizer": "Quest - Randomizer", + "quest_sel_boss_rush": "Quest - Bosse Rush" +} \ No newline at end of file diff --git a/assets/accessibility/texts/kaleidoscope_eng.json b/assets/accessibility/texts/kaleidoscope_eng.json new file mode 100644 index 0000000..10b016b --- /dev/null +++ b/assets/accessibility/texts/kaleidoscope_eng.json @@ -0,0 +1,231 @@ +{ + "health": "Health - $0 Hearts", + "magic": "Magic - $0", + "rupees": "Rupees - $0", + "floor": "Floor $0", + "basement": "Basement $0", + "item_menu": "Select Item", + "map_menu": "Map - $0", + "quest_menu": "Quest Status", + "equip_menu": "Equipment", + "overworld": "Overworld", + "equipped": "$0 - Equipped", + "save_prompt": "Would you like to save?", + "game_saved": "Game saved", + "assigned_to": "Assigned to $0", + "0": "Deku Stick - $0", + "1": "Deku Nut - $0", + "2": "Bomb - $0", + "3": "Fairy Bow - $0", + "4": "Fire Arrow", + "5": "Din's Fire", + "6": "Fairy Slingshot - $0", + "7": "Fairy Ocarina", + "8": "Ocarina of Time", + "9": "Bombchu - $0", + "10": "Hookshot", + "11": "Longshot", + "12": "Ice Arrow", + "13": "Farore's Wind", + "14": "Boomerang", + "15": "Lens of Truth", + "16": "Magic Beans - $0", + "17": "Megaton Hammer", + "18": "Light Arrow", + "19": "Nayru's Love", + "20": "Empty Bottle", + "21": "Red Potion", + "22": "Green Potion", + "23": "Blue Potion", + "24": "Fairy", + "25": "Fish", + "26": "Milk Bottle", + "27": "Ruto's Letter", + "28": "Blue Fire", + "29": "Bugs", + "30": "Big Poe", + "31": "Milk Bottle (Half)", + "32": "Poe", + "33": "Weird Egg", + "34": "Chicken", + "35": "Zelda's Letter", + "36": "Keaton Mask", + "37": "Skull Mask", + "38": "Spooky Mask", + "39": "Bunny Mask", + "40": "Goron Mask", + "41": "Zora Mask", + "42": "Gerudo Mask", + "43": "Mask of Truth", + "44": "Sold Out", + "45": "Pocket Egg", + "46": "Pocket Cucco", + "47": "Cojiro", + "48": "Odd Mushroom", + "49": "Odd Potion", + "50": "Saw", + "51": "Broken Sword", + "52": "Prescription", + "53": "Eyeball Frog", + "54": "Eyedrops", + "55": "Claim Check", + "56": "Bow Fire Arrow", + "57": "Bow Ice Arrow", + "58": "Bow Light Arrow", + "59": "Kokiri Sword", + "60": "Master Sword", + "61": "Giant's Knife", + "62": "Deku Shield", + "63": "Hylian Shield", + "64": "Mirror Shield", + "65": "Kokiri Tunic", + "66": "Goron Tunic", + "67": "Zora Tunic", + "68": "Kokiri Boots", + "69": "Iron Boots", + "70": "Hover Boots", + "71": "Bullet Bag (Holds 30)", + "72": "Bullet Bag (Holds 40)", + "73": "Bullet Bag (Holds 50)", + "74": "Quiver (Holds 30)", + "75": "Quiver (Holds 40)", + "76": "Quiver (Holds 50)", + "77": "Bomb Bag (Holds 20)", + "78": "Bomb Bag (Holds 30)", + "79": "Bomb Bag (Holds 40)", + "80": "Goron's Bracelet", + "81": "Silver Gauntlets", + "82": "Golden Gauntlets", + "83": "Silver Scale", + "84": "Golden Scale", + "85": "Giant's Knife (Broken)", + "86": "WALLET ADULT", + "87": "Giant's Wallet", + "88": "Deku Seeds", + "89": "Fishing Pole", + "90": "Minuet of Forest", + "91": "Bolero of Fire", + "92": "Serenade of Water", + "93": "Requiem of Spirit", + "94": "Nocturne of Shadow", + "95": "Prelude of Light", + "96": "Zelda's Lullaby", + "97": "Epona's Song", + "98": "Saria's Song", + "99": "Sun's Song", + "100": "Song of Time", + "101": "Song of Storms", + "102": "Forest Medallion", + "103": "Fire Medallion", + "104": "Water Medallion", + "105": "Spirit Medallion", + "106": "Shadow Medallion", + "107": "Light Medallion", + "108": "Kokiri's Emerald", + "109": "Goron's Ruby", + "110": "Zora Sapphire", + "111": "Stone of Agony", + "112": "Gerudo's Card", + "113": "Skulltula Token - $0", + "114": "Piece of Heart - $0", + "115": "Piece of Heart", + "116": "Boss Key", + "117": "Compass", + "118": "Dungeon Map", + "119": "Small Key", + "120": "MAGIC SMALL", + "121": "MAGIC LARGE", + "122": "Biggoron's Sword", + "123": "INVALID 1", + "124": "INVALID 2", + "125": "INVALID 3", + "126": "INVALID 4", + "127": "INVALID 5", + "128": "INVALID 6", + "129": "INVALID 7", + "130": "Milk", + "131": "Recovery Heart", + "132": "Green Rupee", + "133": "Blue Rupee", + "134": "Red Rupee", + "135": "Purple Rupee", + "136": "Gold Rupee", + "137": "INVALID 8", + "138": "STICKS 5", + "139": "STICKS 10", + "140": "NUTS 5", + "141": "NUTS 10", + "142": "BOMBS 5", + "143": "BOMBS 10", + "144": "BOMBS 20", + "145": "BOMBS 30", + "146": "ARROWS SMALL", + "147": "ARROWS MEDIUM", + "148": "ARROWS LARGE", + "149": "SEEDS 30", + "150": "BOMBCHUS 5", + "151": "BOMBCHUS 20", + "152": "STICK UPGRADE 20", + "153": "STICK UPGRADE 30", + "154": "NUT UPGRADE 30", + "155": "NUT UPGRADE 40", + "255": "", + "256": "Haunted Wasteland", + "257": "Gerudos Fortress", + "258": "Gerudo Valley", + "259": "Hylia Lakeside", + "260": "Lon Lon Ranch", + "261": "Market", + "262": "Hyrule Field", + "263": "Death Mountain", + "264": "Kakariko Village", + "265": "Lost Woods", + "266": "Kokiri Forest", + "267": "Zoras Domain", + "268": "", + "269": "", + "270": "", + "271": "", + "272": "", + "273": "", + "274": "", + "275": "", + "276": "", + "277": "", + "278": "", + "279": "", + "280": "", + "281": "", + "282": "", + "283": "", + "284": "", + "285": "", + "286": "", + "287": "", + "288": "", + "289": "", + "290": "", + "291": "", + "292": "Hyrule Field", + "293": "Kakariko Village", + "294": "Graveyard", + "295": "Zoras River", + "296": "Kokiri Forest", + "297": "Sacred Forest Meadow", + "298": "Lake Hylia", + "299": "Zoras Domain", + "300": "Zoras Fountain", + "301": "Gerudo Valley", + "302": "Lost Woods", + "303": "Desert Colossus", + "304": "Gerudo's Fortress", + "305": "Haunted Wasteland", + "306": "Market", + "307": "Hyrule Castle", + "308": "Death Mountain Trail", + "309": "Death Mountain Crater", + "310": "Goron City", + "311": "Lon Lon Ranch", + "312": "Question Mark", + "313": "Ganon's Castle" +} diff --git a/assets/accessibility/texts/kaleidoscope_fra.json b/assets/accessibility/texts/kaleidoscope_fra.json new file mode 100644 index 0000000..820eb4c --- /dev/null +++ b/assets/accessibility/texts/kaleidoscope_fra.json @@ -0,0 +1,231 @@ +{ + "health": "Vie - $0 Coeurs", + "magic": "Magie - $0", + "rupees": "Rubis - $0", + "floor": "Étage $0", + "basement": "Sous-sol $0", + "item_menu": "Inventaire", + "map_menu": "Carte - $0", + "quest_menu": "Statut de la quête", + "equip_menu": "Equipment", + "overworld": "Surmonde", + "equipped": "$0 - Équipé", + "save_prompt": "Voulez-vous sauvegarder?", + "game_saved": "Jeu sauvegardé", + "assigned_to": "Assigné au $0", + "0": "Bâton Mojo - $0", + "1": "Noix Mojo - $0", + "2": "Bombes - $0", + "3": "Arc des Fées - $0", + "4": "Flèche de Feu", + "5": "Feu de Din", + "6": "Lance-Pierre des Fées - $0", + "7": "Ocarina des Fées", + "8": "Ocarina of Temps", + "9": "Missiles Teigneux - $0", + "10": "Grappin", + "11": "Super Grappin", + "12": "Flèche de Glace", + "13": "Vent de Farore", + "14": "Boomerang", + "15": "Monocle de Vérité", + "16": "Haricot Magique - $0", + "17": "Masse des Titans", + "18": "Flèche de Lumière", + "19": "Amour de Nayru", + "20": "Bouteille Vide", + "21": "Potion Rouge", + "22": "Potion Verte", + "23": "Potion Bleue", + "24": "Fée", + "25": "Poisson", + "26": "Lait de Lon Lon", + "27": "Lettre de Ruto", + "28": "Flammme Bleue", + "29": "Insectes", + "30": "Âme", + "31": "Lait de Lon Lon (moitié)", + "32": "Esprit", + "33": "Oeuf Curieux", + "34": "Poulet", + "35": "Lettre de Zelda", + "36": "Masque du Renard", + "37": "Masque de Mort", + "38": "Masque d'Effroi", + "39": "Masque du Lapin", + "40": "Masque de Goron", + "41": "Masque de Zora", + "42": "Masque de Gerudo", + "43": "Masque de Vérité", + "44": "VENDU", + "45": "Oeuf de Poche", + "46": "Cocotte de poche", + "47": "P'tit Poulet", + "48": "Champignon suspect", + "49": "Mixture suspecte", + "50": "Scie du chasseur", + "51": "Épée de Goron (brisée)", + "52": "Ordonnance", + "53": "Crapaud-qui-louche", + "54": "Gouttes", + "55": "Certificat", + "56": "Arc et Flèche de Feu", + "57": "Arc et Flèche de Glace", + "58": "Arc et Flèche de Lumière", + "59": "Épée Kokiri", + "60": "Épée de Légende", + "61": "Lame des Géants", + "62": "Bouclier Mojo", + "63": "Bouclier Hylien", + "64": "Bouclier Miroir", + "65": "Tunique Kokiri", + "66": "Tunique Goron", + "67": "Tunique Zora", + "68": "Bottes Kokiri", + "69": "Bottes de plomb", + "70": "Bottes des airs", + "71": "Sac de graines (Contient 30)", + "72": "Sac de graines (Contient 40)", + "73": "Sac de graines (Contient 50)", + "74": "Carquois (Contient 30)", + "75": "Carquois (Contient 40)", + "76": "Carquois (Contient 50)", + "77": "Sac de bombes (Contient 20)", + "78": "Sac de bombes (Contient 30)", + "79": "Sac de bombes (Contient 40)", + "80": "Bracelet Goron", + "81": "Gantelets d'argent", + "82": "Gentelets d'or", + "83": "Écaille d'argent", + "84": "Écaille d'or", + "85": "Lame des Géants (Brisée)", + "86": "GRANDE BOURSE", + "87": "Bourse de Géant", + "88": "Deku Seeds", + "89": "Canne à pèche", + "90": "Menuet des Bois", + "91": "Boléro du Feu", + "92": "Sérénade de l'Eau", + "93": "Requiem des Esprits", + "94": "Nocturne de l'Ombre", + "95": "Prélude de la Lumière", + "96": "Berceuse de Zelda", + "97": "Chant d'Epona", + "98": "Chant de Saria", + "99": "Chant du Soleil", + "100": "Chant du Temps", + "101": "Chant des Tempêtes", + "102": "Médaillon de la Forêt", + "103": "Médaillon du Feu", + "104": "Médaillon de l'Eau", + "105": "Médaillon de l'Esprit", + "106": "Médaillon de l'Ombre", + "107": "Médaillon de la Lumière", + "108": "Émeraude Kokiri", + "109": "Rubis Goron", + "110": "Saphir Zora", + "111": "Pierre de Souffrance", + "112": "Carte Gerudo", + "113": "Skulltula d'or - $0", + "114": "Quart de Coeur - $0", + "115": "Quart de Coeur", + "116": "Clé d'or", + "117": "Boussole", + "118": "Carte du Donjon", + "119": "Petite Clé", + "120": "PETITE BOUTEILLE DE MAGIE", + "121": "GRANDE BOUTEILLE DE MAGIE", + "122": "Épée de Biggoron", + "123": "INVALIDE 1", + "124": "INVALIDE 2", + "125": "INVALIDE 3", + "126": "INVALIDE 4", + "127": "INVALIDE 5", + "128": "INVALIDE 6", + "129": "INVALIDE 7", + "130": "Lait de Lon Lon", + "131": "Coeur de Vie", + "132": "Rubis Vert", + "133": "Rubis Bleu", + "134": "Rubis Rouge", + "135": "Rubis Pourpre", + "136": "Énorme Rubis", + "137": "INVALIDE 8", + "138": "BÂTON MOJO 5", + "139": "BÂTON MOJO 10", + "140": "NOIX MOJO 5", + "141": "NOIX MOJO 10", + "142": "BOMBES 5", + "143": "BOMBES 10", + "144": "BOMBES 20", + "145": "BOMBES 30", + "146": "ARROWS SMALL", + "147": "ARROWS MEDIUM", + "148": "ARROWS LARGE", + "149": "GRAINES MOJO 30", + "150": "MISSILES TEIGNEUX 5", + "151": "MISSILES TEIGNEUX 20", + "152": "AMÉLIORATION BÂTON MOJO 20", + "153": "AMÉLIORATION BÂTON MOJO 30", + "154": "AMÉLIORATION NOIX MOJO 30", + "155": "AMÉLIORATION NOIX MOJO 40", + "255": "", + "256": "Désert Hanté", + "257": "Forteresse Gerudo", + "258": "Vallée Gerudo", + "259": "Laboratoire du Lac", + "260": "Ranch Lon Lon", + "261": "Place du Marché", + "262": "Plaine d'Hyrule", + "263": "Montagne du Péril", + "264": "Village Cocorico", + "265": "Bois Perdus", + "266": "Forêt Kokiri", + "267": "Domaine Zora", + "268": "", + "269": "", + "270": "", + "271": "", + "272": "", + "273": "", + "274": "", + "275": "", + "276": "", + "277": "", + "278": "", + "279": "", + "280": "", + "281": "", + "282": "", + "283": "", + "284": "", + "285": "", + "286": "", + "287": "", + "288": "", + "289": "", + "290": "", + "291": "", + "292": "Plaine d'Hyrule", + "293": "Village Cocorico", + "294": "Cimetière", + "295": "Rivière Zora", + "296": "Forêt Kokiri", + "297": "Bosquet Sacré", + "298": "Lac Hylia", + "299": "Domaine Zora", + "300": "Fountaine Zora", + "301": "Vallée Gerudo", + "302": "Bois Perdus", + "303": "Colosse du Désert", + "304": "Forteresse Gerudo", + "305": "Désert Hanté", + "306": "Place du Marché", + "307": "Château d'Hyrule", + "308": "Chemin du Péril", + "309": "Cratère du Péril", + "310": "Village Goron", + "311": "Ranch Lon Lon", + "312": "Point d'interrogation", + "313": "Château de Ganon" +} diff --git a/assets/accessibility/texts/kaleidoscope_ger.json b/assets/accessibility/texts/kaleidoscope_ger.json new file mode 100644 index 0000000..630d933 --- /dev/null +++ b/assets/accessibility/texts/kaleidoscope_ger.json @@ -0,0 +1,231 @@ +{ + "health": "Energie - $0 Herzen", + "magic": "Magie - $0", + "rupees": "Rubine - $0", + "floor": "Etage $0", + "basement": "Keller $0", + "item_menu": "Gegenstände", + "map_menu": "Karte - $0", + "quest_menu": "Quest Status", + "equip_menu": "Ausrüstung", + "overworld": "Ãœberwelt", + "equipped": "$0 - Ausgerüstet", + "save_prompt": "Spielstand sichern?", + "game_saved": "Spielstand gesichert", + "assigned_to": "$0 zugeordnet", + "0": "Deku-Stab - $0", + "1": "Deku-Nuß - $0", + "2": "Bombe - $0", + "3": "Feen-Bogen - $0", + "4": "Feuer-Pfeil", + "5": "Dins Feuerinferno", + "6": "Feen-Schleuder - $0", + "7": "Feen-Okarina", + "8": "Okarina der Zeit", + "9": "Krabbelmine - $0", + "10": "Fanghaken", + "11": "Enterhaken", + "12": "Eis-Pfeil", + "13": "Farores Donnersturm", + "14": "Bumerang", + "15": "Auge der Wahrheit", + "16": "Wundererbsen - $0", + "17": "Stahlhammer", + "18": "Licht-Pfeil", + "19": "Nayrus Umarmung", + "20": "Flasche", + "21": "Rotes Elixier", + "22": "Grünes Elixier", + "23": "Blaues Elixier", + "24": "Fee", + "25": "Fisch", + "26": "Milch", + "27": "Brief", + "28": "Blaues Feuer", + "29": "Käfer", + "30": "Nachtschwärmer", + "31": "Milch (1/2)", + "32": "Irrlicht", + "33": "Seltsames Ei", + "34": "Huhn", + "35": "Zeldas Brief", + "36": "Fuchs-Maske", + "37": "Schädel-Maske", + "38": "Geister-Maske", + "39": "Hasenohren", + "40": "Goronen-Maske", + "41": "Zora-Maske", + "42": "Gerudo-Maske", + "43": "Maske des Wissens", + "44": "Verkauft", + "45": "Ei", + "46": "Kiki", + "47": "Henni", + "48": "Schimmelpilz", + "49": "Modertrank", + "50": "Säge", + "51": "Goronen-Schwert (zerbrochen)", + "52": "Rezept", + "53": "Glotzfrosch", + "54": "Augentropfen", + "55": "Zertifikat", + "56": "Bogen Feuer-Pfeil", + "57": "Bogen Eis-Pfeil", + "58": "Bogen Licht-Pfeil", + "59": "Kokiri-Schwert", + "60": "Master-Schwert", + "61": "Langschwert", + "62": "Deku-schild", + "63": "Hylia-Schild", + "64": "Spiegel-Schild", + "65": "Kokiri-Rüstung", + "66": "Goronen-Rüstung", + "67": "Zora-Rüstung", + "68": "Lederstiefel", + "69": "Eisenstiefel", + "70": "Gleitstiefel", + "71": "Munitionstasche (30)", + "72": "Munitionstasche (40)", + "73": "Munitionstasche (50)", + "74": "Köcher (30)", + "75": "Köcher (40)", + "76": "Köcher (50)", + "77": "Bombentasche (20)", + "78": "Bombentasche (30)", + "79": "Bombentasche (40)", + "80": "Goronen-Armband", + "81": "Krafthandschuh", + "82": "Titanhandschuh", + "83": "Silberschuppe", + "84": "Goldschuppe", + "85": "Langschwert (gebrochen)", + "86": "Große Börse", + "87": "Riesenbörse", + "88": "Deku-Kerne", + "89": "Angel", + "90": "Menuett des Waldes", + "91": "Bolero des Feuers", + "92": "Serenade des Wassers", + "93": "Requiem der Geister", + "94": "Nocturne des Schattens", + "95": "Kantate des Lichts", + "96": "Zeldas Wiegenlied", + "97": "Eponas Lied", + "98": "Salias Lied", + "99": "Hymne der Sonne", + "100": "Hymne der Zeit", + "101": "Song of Storms", + "102": "Amulett des Waldes", + "103": "Amulett des Feuers", + "104": "Amulett des Wassers", + "105": "Amulett der Geister", + "106": "Amulett des Schattens", + "107": "Amulett des Lichts", + "108": "Kokiri-Smaragd", + "109": "Goronen-Opal", + "110": "Zora-Saphir", + "111": "Stein des Wissens", + "112": "Gerudo-Paß", + "113": "Skulltula-Symbol - $0", + "114": "Herzteil - $0", + "115": "Herzteil", + "116": "Master-Schlüssel", + "117": "Kompaß", + "118": "Labyrinth-Karte", + "119": "Kleiner Schlüssel", + "120": "MAGIE KLEIN", + "121": "MAGIE GROß", + "122": "Biggoron-Schwert", + "123": "UNGÃœLTIG 1", + "124": "UNGÃœLTIG 2", + "125": "UNGÃœLTIG 3", + "126": "UNGÃœLTIG 4", + "127": "UNGÃœLTIG 5", + "128": "UNGÃœLTIG 6", + "129": "UNGÃœLTIG 7", + "130": "Milch", + "131": "Herz", + "132": "ein Rubin", + "133": "5 Rubine", + "134": "20 Rubine", + "135": "50 Rubine", + "136": "200 Rubine", + "137": "UNGÃœLTIG 8", + "138": "STÄBE 5", + "139": "STÄBE 10", + "140": "NÃœSSE 5", + "141": "NÃœSSE 10", + "142": "BOMBEN 5", + "143": "BOMBEN 10", + "144": "BOMBEN 20", + "145": "BOMBEN 30", + "146": "PFEILE KLEIN", + "147": "PFEILE MITTEL", + "148": "PFEILE GROß", + "149": "KERNE 30", + "150": "KRABBELMINEN 5", + "151": "KRABBELMINEN 20", + "152": "STAB UPGRADE 20", + "153": "STAB UPGRADE 30", + "154": "NUß UPGRADE 30", + "155": "NUß UPGRADE 40", + "255": "", + "256": "Gespensterwüste", + "257": "Gerudo-Festung", + "258": "Gerudotal", + "259": "Hylia-See", + "260": "Lon Lon-Farm", + "261": "Marktplatz", + "262": "Hylianische Steppe", + "263": "Todesberg", + "264": "Kakariko", + "265": "Verlorene Wälder", + "266": "Kokiri-Wald", + "267": "Zoras Reich", + "268": "", + "269": "", + "270": "", + "271": "", + "272": "", + "273": "", + "274": "", + "275": "", + "276": "", + "277": "", + "278": "", + "279": "", + "280": "", + "281": "", + "282": "", + "283": "", + "284": "", + "285": "", + "286": "", + "287": "", + "288": "", + "289": "", + "290": "", + "291": "", + "292": "Hylianische Steppe", + "293": "Kakariko", + "294": "Friedhof", + "295": "Zora-Fluss", + "296": "Kokiri-Wald", + "297": "Heilige Lichtung", + "298": "Hylia-See", + "299": "Zoras Reich", + "300": "Zoras Quelle", + "301": "Gerudotal", + "302": "Verlorene Wälder", + "303": "Wüstenkoloss", + "304": "Gerudo-Festung", + "305": "Gespensterwüste", + "306": "Marktplatz", + "307": "Schloß Hyrule", + "308": "Pfad zum Todesberg", + "309": "Todeskrater", + "310": "Goronia", + "311": "Lon Lon-Farm", + "312": "Fragezeichen", + "313": "Teufelsturm" +} diff --git a/assets/accessibility/texts/misc_eng.json b/assets/accessibility/texts/misc_eng.json new file mode 100644 index 0000000..6bff3b3 --- /dev/null +++ b/assets/accessibility/texts/misc_eng.json @@ -0,0 +1,24 @@ +{ + "minutes_plural" : "$0 minutes", + "minutes_singular" : "$0 minute", + "seconds_plural" : "$0 seconds", + "seconds_singular" : "$0 second", + "input_button_a": "the A button", + "input_button_b": "the B button", + "input_button_c": "the C button", + "input_button_l": "the L button", + "input_button_r": "the R button", + "input_button_z": "the Z button", + "input_button_c_up": "C Up", + "input_button_c_down": "C Down", + "input_button_c_left": "C Left", + "input_button_c_right": "C Right", + "input_analog_stick": "the Analog Stick", + "input_d_pad": "the D-Pad", + "input_d_pad_up": "D-Pad Up", + "input_d_pad_down": "D-Pad Down", + "input_d_pad_left": "D-Pad Left", + "input_d_pad_right": "D-Pad Right", + "yes": "Yes", + "no": "No" +} diff --git a/assets/accessibility/texts/misc_fra.json b/assets/accessibility/texts/misc_fra.json new file mode 100644 index 0000000..0d9073e --- /dev/null +++ b/assets/accessibility/texts/misc_fra.json @@ -0,0 +1,24 @@ +{ + "minutes_plural" : "$0 minutes", + "minutes_singular" : "$0 minute", + "seconds_plural" : "$0 secondes", + "seconds_singular" : "$0 seconde", + "input_button_a": "le bouton A", + "input_button_b": "le bouton B", + "input_button_c": "le bouton C", + "input_button_l": "le bouton L", + "input_button_r": "le bouton R", + "input_button_z": "le bouton Z", + "input_button_c_up": "C Haut", + "input_button_c_down": "C Bas", + "input_button_c_left": "C Gauche", + "input_button_c_right": "C Droit", + "input_analog_stick": "le Stick Analogique", + "input_d_pad": "D-Pad", + "input_d_pad_up": "D-Pad Haut", + "input_d_pad_down": "D-Pad Bas", + "input_d_pad_left": "D-Pad Gauche", + "input_d_pad_right": "D-Pad Droit", + "yes": "Oui", + "no": "Non" +} diff --git a/assets/accessibility/texts/misc_ger.json b/assets/accessibility/texts/misc_ger.json new file mode 100644 index 0000000..2e07143 --- /dev/null +++ b/assets/accessibility/texts/misc_ger.json @@ -0,0 +1,24 @@ +{ + "minutes_plural" : "$0 Minuten", + "minutes_singular" : "eine Minute", + "seconds_plural" : "$0 Sekunden", + "seconds_singular" : "eine Sekunde", + "input_button_a": "den A-Knopf", + "input_button_b": "den B-Knopf", + "input_button_c": "den C-Knopf", + "input_button_l": "den L-Knopf", + "input_button_r": "den R-Knopf", + "input_button_z": "den Z-Knopf", + "input_button_c_up": "C Oben", + "input_button_c_down": "C Unten", + "input_button_c_left": "C Links", + "input_button_c_right": "C Rechts", + "input_analog_stick": "den Analog-Stick", + "input_d_pad": "das Steuerkreuz", + "input_d_pad_up": "Steuerkreuz Oben", + "input_d_pad_down": "Steuerkreuz Unten", + "input_d_pad_left": "Steuerkreuz Links", + "input_d_pad_right": "Steuerkreuz Rechts", + "yes": "Ja", + "no": "Nein" +} diff --git a/assets/accessibility/texts/scenes_eng.json b/assets/accessibility/texts/scenes_eng.json new file mode 100644 index 0000000..7f9397b --- /dev/null +++ b/assets/accessibility/texts/scenes_eng.json @@ -0,0 +1,112 @@ +{ + "0": "Inside the Deku Tree", + "1": "Dodongo's Cavern", + "2": "Inside Jabu-Jabu's Belly", + "3": "Forest Temple", + "4": "Fire Temple", + "5": "Water Temple", + "6": "Spirit Temple", + "7": "Shadow Temple", + "8": "Bottom of The Well", + "9": "Ice Cavern", + "10": "", // Stairs to Ganondorf's Lair (No title card) + "11": "Gerudo Training Ground", + "12": "Thieves' Hideout", + "13": "Ganon's Castle", + "14": "", // Escape from Ganon's Castle (No title card) + "15": "", // Escape from Ganon's Castle 5 (No title card)x + "16": "Treasure Box Shop", + "17": "Parasitic Armored Arachnid - Gohma", + "18": "Infernal Dinosaur - King Dodongo", + "19": "Bio-electric Anemone - Barinade", + "20": "Evil Spirit from Beyond - Phantom Ganon", + "21": "Subterranean Lava Dragon - Volvagia", + "22": "Giant Aquatic Amoeba - Morpha", + "23": "Sorceress Sisters - Twinrova", + "24": "Phantom Shadow Beast - Bongo Bongo", + "25": "Great King of Evil - Ganondorf", + "26": "", + "27": "", // Entrance to Market (No title card) + "28": "", + "29": "", + "30": "Back Alley", + "31": "Back Alley", + "32": "Market", + "33": "Market", + "34": "Market", + "35": "", // Temple of Time Exterior (No title card) + "36": "SCENE_SHRINE_N", + "37": "SCENE_SHRINE_R", + "38": "", // House of the Know-it-All Brothers (No title card) + "39": "", // House of Twins (No title card) + "40": "", // House of the Great Mido (No title card) + "41": "", // Saria's House (No title card) + "42": "", // Kakariko House 1 (No title card) + "43": "", // Back Alley House 1 (No title card) + "44": "Bazaar", + "45": "Kokiri Shop", + "46": "Goron Shop", + "47": "Zora Shop", + "48": "", // Closed Shop (No title card) + "49": "Potion Shop", + "50": "", // Bombchu Shop (No title card) + "51": "Happy Mask Shop", + "52": "", // Link's House (No title card) + "53": "", // Dog Lady's House (No title card) + "54": "Stable", + "55": "", // Impa's House (No title card) + "56": "Lakeside Laboratory", + "57": "", // Running Man's Tent (No title card) + "58": "Gravekeepers Hut", + "59": "Great Fairy's Fountain", + "60": "Fairy's Fountain", + "61": "Great Fairy's Fountain", + "62": "", // Grottos (No title card) + "63": "", // Tomb 1 (No title card) + "64": "", // Tomb 2 (No title card) + "65": "Royal Family's Tomb", + "66": "Shooting Gallery", + "67": "Temple of Time", + "68": "Chamber of The Sages", + "69": "Castle Courtyard", + "70": "Castle Courtyard", + "71": "", // Goddesses Cutscene (No title card) + "72": "Unknown Place", + "73": "Fishing Pond", + "74": "Castle Courtyard", + "75": "Bombchu Bowling Alley", + "76": "", // Lon Lon Ranch House/Silo (No title card) + "77": "", // Guard House (No title card) + "78": "", // Potion Shop (No title card) + "79": "Ganon", + "80": "House of Skulltula", + "81": "Hyrule Field", + "82": "Kakariko Village", + "83": "Graveyard", + "84": "Zora's River", + "85": "Kokiri Forest", + "86": "Sacred Forest Meadow", + "87": "Lake Hylia", + "88": "Zoras Domain", + "89": "Zoras Fountain", + "90": "Gerudo Valley", + "91": "Lost Woods", + "92": "Desert Colossus", + "93": "Gerudo's Fortress", + "94": "Haunted Wasteland", + "95": "Hyrule Castle", + "96": "Death Mountain Trail", + "97": "Death Mountain Crater", + "98": "Goron City", + "99": "Lon Lon Ranch", + "100": "", + "101": "", // Debug: Test Map (No title card) + "102": "", // Debug: Test Room (No title card) + "103": "", // Debug: Depth Test (No title card) + "104": "", // Debug: Stalfos Miniboss Room (No title card) + "105": "", // Debug: Stalfos Boss Room (No title card) + "106": "", // Debug: Dark Link Room (No title card) + "107": "", + "108": "", // Debug: SRD Room (No title card) + "109": "" // Debug: Treasure Chest Warp (No title card) +} \ No newline at end of file diff --git a/assets/accessibility/texts/scenes_fra.json b/assets/accessibility/texts/scenes_fra.json new file mode 100644 index 0000000..fa36c88 --- /dev/null +++ b/assets/accessibility/texts/scenes_fra.json @@ -0,0 +1,112 @@ +{ + "0": "Abre Mojo", + "1": "Caverne Dodongo", + "2": "Ventre de Jabu-Jabu", + "3": "Temple de la Forêt", + "4": "Temple du Feu", + "5": "Temple de l'Eau", + "6": "Temple de l'Esprit", + "7": "Temple de l'Ombre", + "8": "Puits", + "9": "Caverne Polaire", + "10": "", // Escaliers vers le Repaire de Ganondorf (No title card) + "11": "Gymnase Gerudo", + "12": "Repaire des Voleurs", + "13": "Tour de Ganon", + "14": "", // Fuite du Château de Ganon (No title card) + "15": "", // Fuite du Château de Ganon 5 (No title card) + "16": "Chasse aux Trésors", + "17": "Monstre Insectoide Géant - Gohma", + "18": "Dinosaure Infernal - King Dodongo", + "19": "Anémone Bio-Electrique - Barinade", + "20": "Esprit Maléfique de l'Au-Delà - Ganon Spectral", + "21": "Dragon des Profondeurs - Volcania", + "22": "Amibe Aquatique Géante - Morpha", + "23": "Sorcières Jumelles - Duo Maléfique", + "24": "Monstre de l'Ombre - Bongo Bongo", + "25": "Seigneur du Malin - Ganondorf", + "26": "", + "27": "", // Entrée vers le Marché (No title card) + "28": "", + "29": "", + "30": "Ruelle", + "31": "Ruelle", + "32": "Place du Marché", + "33": "Place du Marché", + "34": "Place du Marché", + "35": "", // Extérieur du Temple du Temps (No title card) + "36": "SCENE_SHRINE_N", + "37": "SCENE_SHRINE_R", + "38": "", // Cabane des Frères Je-Sais-Tout (No title card) + "39": "", // Cabane des Jumelles (No title card) + "40": "", // Cabane du Grand Mido (No title card) + "41": "", // Cabane de Saria (No title card) + "42": "", // Maison du Village Cocorico 1 (No title card) + "43": "", // Maison de la Ruelle 1 (No title card) + "44": "Bazar", + "45": "Boutique Kokiri", + "46": "Boutique Goron", + "47": "Boutique Zora", + "48": "", // Magasin Fermé (No title card) + "49": "Apothicaire", + "50": "", // Magasin de Missiles (No title card) + "51": "Foire aux Masques", + "52": "", // Cabane de Link (No title card) + "53": "", // Dog Lady's House (No title card) + "54": "Étable", + "55": "", // Maison d'Impa (No title card) + "56": "Laboratoire du Lac", + "57": "", // Tente du Marathonien (No title card) + "58": "Cabane du fossoyeur", + "59": "Fountaine Royale des Fées", + "60": "Fountaine des Fées", + "61": "Fountaine Royale des Fées", + "62": "", // Grottes (No title card) + "63": "", // Tombe 1 (No title card) + "64": "", // Tombe 2 (No title card) + "65": "Tombe Royale", + "66": "Jeu d'adresse", + "67": "Temple du Temps", + "68": "Sanctuaire des Sages", + "69": "Cour du Château", + "70": "Cour du Château", + "71": "", // Goddesses Cutscene (No title card) + "72": "Endroit Inconnu", + "73": "Étang", + "74": "Cour du Château", + "75": "Bowling Teigneux", + "76": "", // Lon Lon Ranch House/Silo (No title card) + "77": "", // Guard House (No title card) + "78": "", // Potion Shop (No title card) + "79": "Ganon", + "80": "Maison des Araignées", + "81": "Plaine d'Hyrule", + "82": "Village Cocorico", + "83": "Cimetière", + "84": "Fleuve Zora", + "85": "Forêt Kokiri", + "86": "Bosquet Sacré", + "87": "Lac Hylia", + "88": "Domaine Zora", + "89": "Fontaine Zora", + "90": "Vallée Gerudo", + "91": "Bois Perdu", + "92": "Colosse du Désert", + "93": "Forteresse Gerudo", + "94": "Désert Hanté", + "95": "Château d'Hyrule", + "96": "Chemin du Péril", + "97": "Cratère du Péril", + "98": "Village Goron", + "99": "Ranch Lon Lon", + "100": "", + "101": "", // Debug: Test Map (No title card) + "102": "", // Debug: Test Room (No title card) + "103": "", // Debug: Depth Test (No title card) + "104": "", // Debug: Stalfos Miniboss Room (No title card) + "105": "", // Debug: Stalfos Boss Room (No title card) + "106": "", // Debug: Dark Link Room (No title card) + "107": "", + "108": "", // Debug: SRD Room (No title card) + "109": "" // Debug: Treasure Chest Warp (No title card) +} \ No newline at end of file diff --git a/assets/accessibility/texts/scenes_ger.json b/assets/accessibility/texts/scenes_ger.json new file mode 100644 index 0000000..a3f7370 --- /dev/null +++ b/assets/accessibility/texts/scenes_ger.json @@ -0,0 +1,112 @@ +{ + "0": "Im Deku-Baum", + "1": "Dodongos Höhle", + "2": "Jabu-Jabus Bauch", + "3": "Waldtempel", + "4": "Feuertempel", + "5": "Wassertempel", + "6": "Geistertempel", + "7": "Schattentempel", + "8": "Grund des Brunnens", + "9": "Eishöhle", + "10": "", // Treppe zu Ganondorfs Verließ (Keine Title-Card) + "11": "Gerudo-Arena", + "12": "Diebesversteck", + "13": "Ganons Schloß", + "14": "", // Flucht aus Ganons Schloß (Keine Title-Card) + "15": "", // Flucht aus Ganons Schloß 5 (Keine Title-Card) + "16": "Truhenlotterie", + "17": "Gepanzerter Spinnenparasit - Gohma", + "18": "Infernosaurus - King Dodongo", + "19": "Elektroterristrisches Biotentakel - Barinade", + "20": "Reitendes Unheil - Phantom-Ganon", + "21": "Subterraner Lavadrachoid - Volvagia", + "22": "Aquamöbes Wassertentakel - Morpha", + "23": "Höllische Hexenarmada - Killa Ohmaz", + "24": "Bestialische Schattenmonstrosität - Bongo Bongo", + "25": "Großmeister des Bösen - Ganondorf", + "26": "", + "27": "", // Eingang zum Marktplatz (Keine Title-Card) + "28": "", + "29": "", + "30": "Seitenstraße", + "31": "Seitenstraße", + "32": "Marktplatz", + "33": "Marktplatz", + "34": "Marktplatz", + "35": "", // Vor der Zitadelle der Zeit (Keine Title-Card) + "36": "SCENE_SHRINE_N", + "37": "SCENE_SHRINE_R", + "38": "", // Haus der Allwissenden Brüder (Keine Title-Card) + "39": "", // Haus der Zwillinge (Keine Title-Card) + "40": "", // Midos Haus (Keine Title-Card) + "41": "", // Salias Haus (Keine Title-Card) + "42": "", // Kakariko Haus 1 (Keine Title-Card) + "43": "", // Steinstraßen Haus 1 (Keine Title-Card) + "44": "Basar", + "45": "Kokiri-Laden", + "46": "Goronen-Laden", + "47": "Zora-Laden", + "48": "", // Geschlossener Laden (Keine Title-Card) + "49": "Magie-Laden", + "50": "", // Krabbelminen-Laden (Keine Title-Card) + "51": "Maskenhändler", + "52": "", // Links Haus (Keine Title-Card) + "53": "", // Haus der Hunde-Dame (Keine Title-Card) + "54": "Stall", + "55": "", // Impas Haus (Keine Title-Card) + "56": "Hylia-See Laboratorium", + "57": "", // Zelt des Rennläufers (Keine Title-Card) + "58": "Hütte des Totengräbers", + "59": "Feen-Quelle", + "60": "Feen-Brunnen", + "61": "Feen-Quelle", + "62": "", // Grotten (Keine Title-Card) + "63": "", // Grab 1 (Keine Title-Card) + "64": "", // Grab 2 (Keine Title-Card) + "65": "Königsgrab", + "66": "Schießbude", + "67": "Zitadelle der Zeit", + "68": "Halle der Weisen", + "69": "Burghof", + "70": "Burghof", + "71": "", // Göttinnen Cutscene (Keine Title-Card) + "72": "Unbekannter Ort", + "73": "Fischweiher", + "74": "Burghof", + "75": "Minenbowlingbahn", + "76": "", // Lon Lon-Farm Haus/Silo (Keine Title-Card) + "77": "", // Wachposten (Keine Title-Card) + "78": "", // Magie-Laden (Keine Title-Card) + "79": "Ganon", + "80": "Skulltulas Haus", + "81": "Hylianische Steppe", + "82": "Kakariko", + "83": "Friedhof", + "84": "Zora-Fluß", + "85": "Kokiri-Wald", + "86": "Waldlichtung", + "87": "Hylia-See", + "88": "Zoras Reich", + "89": "Zoras Quelle", + "90": "Gerudotal", + "91": "Verlorene Wälder", + "92": "Wüstenkoloss", + "93": "Gerudo-Festung", + "94": "Geisterwüste", + "95": "Schloß Hyrule", + "96": "Pfad zum Todesberg", + "97": "Todeskrater", + "98": "Goronia", + "99": "Lon Lon-Farm", + "100": "", + "101": "", // Debug: Test Karte (Keine Title-Card) + "102": "", // Debug: Test Raum (Keine Title-Card) + "103": "", // Debug: Tiefen Test (Keine Title-Card) + "104": "", // Debug: Stalfos-Ritter Miniboss Raum (Keine Title-Card) + "105": "", // Debug: Stalfos-Ritter Boss Raum (Keine Title-Card) + "106": "", // Debug: Schwarzer Link Raum (Keine Title-Card) + "107": "", + "108": "", // Debug: SRD Raum (Keine Title-Card) + "109": "" // Debug: Schatzkisten Teleport (Keine Title-Card) +} \ No newline at end of file diff --git a/assets/fonts/Fipps-Regular.otf b/assets/fonts/Fipps-Regular.otf new file mode 100644 index 0000000000000000000000000000000000000000..9334dad594277ba8339786217d75260e58436dc8 GIT binary patch literal 34220 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 z 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∓eYz|5P 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 + + + + diff --git a/assets/objects/object_box/gChristmasGreenTreasureChestFrontTex.rgb5a1.png b/assets/objects/object_box/gChristmasGreenTreasureChestFrontTex.rgb5a1.png new file mode 100644 index 0000000000000000000000000000000000000000..03dac76dd9ad786e9ee25bd396521d206c97c6c3 GIT binary patch literal 2917 zcmV-r3!3zaP)sd^^WMI<`*yc2!+^}F8^Nv2N)TM??8KFSg8m(XD9p;eD`8fG zyIF`J2*WVL*o|}hJ}c{$S(%mR5fLupM4UKPeH$0r2NEhXE93inKfWRF{^N(9{@Gl; z#@}}wo}A#sVYe373TCEZ?8o%M8nkFFHu(%^82g|=?dT4O!fx&w=L(OR(9P%5JkDEKUzcCe8hw zoBf+K|0Zy2Jw++_{)ny}pXD65c2LB0_1KI`lPvHMDAzm!hYXMeWQqaY^@?gObk3)2 zGP5DR6wVM|N`u6zm4WXzHl&veZcs|tZymdJKv-XP?A8`jND|U^p7qrb?XI_~HUfK} zUPfhADOw>Z2?t`gCps0i&JvrjjOHH$PGsAG?iZabj@J zv%R&+saL?>) zM|VBpaO#+z?J?dI53ID6NjUt#=Y1h|z}zi5o3O-zP%uC8T-~;a^4wk?&~6L5dcmvf zDF)SzQq5;VY;P?}35Um;+f^|6^30%(q=J+WAG#3gGH4FqJHRT?2Y7C{c|T|SW{KSx zC_J}KjWLxxvVgUoa-vdK%zHsKQ=`Dlr(pm$(_y|raGl`m8Y&&!_im28EJ1lxX{pN{ zroFryrD2@!Z0k8#YLteXi;m-`1(O~;x+0&LV-f0{r<)4mpxeWGQ)6$0cVC^*T}@Fl zi<)*=t1!-Cq#RE@vArfAE9vuFM!WS?t8j#K9hsKJ!imaXY3=*wqXrZI;>`8rTFEq z-}0ZASL|OO^7a=WvE9Ds-+uO%zx$gBc3pAu@eO*?p~PXj&E2RHnj&a#vRTplAtguq zLF)(K#}T{`{^94Wn;S@dXSe)I{>@}M!k14ZKYzl$U1|FF_ z2lfuyIt-W(x1^#1XBE{{u{H4XU)}N3a>0w|o*(_eF}k{=T6#{aEvx$iqpEQb61MEo zbN#O6_-QdR`KF)wmuH5Xi{Wo^p&`}xj-Tu=;S(^|LbY=o>wC^Vzh*L5Y_A=3f|03y z)D4{_X_s>Wxyj?qpKnTOGcwS%P&?OKMfl@CIfj*GI<47nJa4`{!@3sJ-8Lg%I~!Lh z;rd7BWD@?Q5rP#|i+NfpR z6>a;!BeT-j=0nLYrwVO^?b`CU|9;8ss^hQ!ykc>vI9v+Gn$Ucl%hM^#1RwUns9hXV z;`{uG74za{h^uE`RAExmVPvajipfmz$wwtsshCa#^KIJPUUZM5JQqZipwwXU_rGaI zmRP-N)8INk)@kuMJ1kIr(=)mQjo@W4pL0Ex(tW$xmG0+27v{e_6=OM1Glm-kt3(hF zbYRN)EZ1-FdFMHLQl!Y%M$#b>JPo9MU3m6I6{c!E9&W7lp>pxsADWbj*!#Q z%(nB1J$XpQ#EIBsT8DZv%nnKo0iI);`l5M2Pzx zB$CpE{xX@VR9$mSW0vKpp^-MZAOo@mO-rut`yLh^<>G&31pZfwmk9!(ac9r z3X~24#Ik(ytUznw;_C)e2v0sMS$*B&oagvSfpebQzBw&UO`03Rycrmn9P=?--fNSF zj6%44-6oS?zHWmSWta^D2^G#*y=u^fusk<-57%$Q@4N@>P+M}$5nJB1KDFZr{?Ozx z%A;FcVpRPo^+b`#Ea!YutZO|v<|DSeYeVXklc2eGp~6LzKmY9tXFcy{%s z+45M+l@?a78lJo;Q@@Cp7`e&w#&!I(Kos1(@0iXN&IaxwE;%{o2ifwNVv#S1b3i1s zb-xLB*_4#ejgdI&p1t4{rQ& z@K}QJ!96}dJHz}STi&&P#1DKEc#AX}ca$cEBy1^2^d z6f0`ZF*-MFRXL_97KbB#AhP9GZ`%L!Yr8ZhFY-e4pcJoOHOXX;FD`j-aTypC8BJ3I z!xAaI@x>+Nm?O6Q@Bf1Ths*2c(dBiHIbzGv-_6x=jyYn>ao>#qIp+TWqA@z1pUZ>! P00000NkvXXu0mjfOx?9X literal 0 HcmV?d00001 diff --git a/assets/objects/object_box/gChristmasGreenTreasureChestSideAndTopTex.rgb5a1.png b/assets/objects/object_box/gChristmasGreenTreasureChestSideAndTopTex.rgb5a1.png new file mode 100644 index 0000000000000000000000000000000000000000..ee03c1343a034c2477862518d38671d46b631fab GIT binary patch literal 1111 zcmV-d1gQIoP)_;GNYzstwv5As3DA*pgHDy<)qc4i3VzyS%)jx47#7kPI%Xrh5` z!1TxOzZll%*WVuT>UF}^wSX94A+P|4Bcqgd45sxjas4YoAO?u)=VdlnKaMgRRQqQw z*3KqMsRyP0r#jE~;wKx&AwX6L)ZCAkkDhJSC(|IKE^^qQ=NFTcbFF69J|M zEfu_Fz0~iv;QmM^VEroDRqhvHgJgo1`Xcd2`CjG@?me-scLbM20HJ}i5Rx3Hen1Wl z-0SF+69Kn>&ou~uw;%F%)!QjQ-7M|h%65&Lw1nFh0}E;fWUUM$)G}~-=gFEHR1M`^ z>*`tirM=@F+=0#N#S^qs#7ro&!PLN++Y4UrvRIQ?11~nv93>Vrj!JXJSb!wQJajHG zwM?GUw|~}BDeuf!mzbYfOVTo5%i3ft;gY-pGgo~}uECLt;Tzl6BATxoS3Oaq;NUHK0QXC$97@1a!B02KkhufAd7rCMG2!mx zJlL%_+V#8ClJK(n@BS=vuws+31T27^FTuULT~-lX0%KS&;!V13#CfXV%(cG~gJX|k znJW19*3}g+!CfVOS!TKzR$fX~yGSTarzL#BQ0>8NbkN;;Z;i!ikGenKYnvsmEH6VU zXAN2MMX>m^x~+q13-0R4xt^muFKOR4n%VR9-hwZ)Asv1^hODeD zA*KMyH!PKV>0-UzPxk8Ve&I3)fHXfm>^7W)F3-oV?bd8-Nu~#F02T&QY}{?ue#Q() zcriMa2(|goZS(0(zll-BRCv$c^%ke@=siJLT8! z(uH>{v*GKhv|$$6Nt|so6!lg6($#>PwQJwIyscl<+3@#cy(4(v2d-pyWX76qDKCpX zDKXW$#+$A67TPtp=7elKZmj@5- literal 0 HcmV?d00001 diff --git a/assets/objects/object_box/gChristmasRedTreasureChestFrontTex.rgb5a1.png b/assets/objects/object_box/gChristmasRedTreasureChestFrontTex.rgb5a1.png new file mode 100644 index 0000000000000000000000000000000000000000..0ea4b9fe2c276cf1875acea68b032c0a36f746ba GIT binary patch literal 3518 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 Hu0mjfR4h1* literal 0 HcmV?d00001 diff --git a/assets/objects/object_box/gGoldTreasureChestFrontTex.rgb5a1.png b/assets/objects/object_box/gGoldTreasureChestFrontTex.rgb5a1.png new file mode 100644 index 0000000000000000000000000000000000000000..d63811e9c8e2499857682632fb907852a7c4cdfa GIT binary patch literal 4727 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 FV1jt(8%O{E literal 0 HcmV?d00001 diff --git a/assets/objects/object_box/gGoldTreasureChestSideAndTopTex.rgb5a1.png b/assets/objects/object_box/gGoldTreasureChestSideAndTopTex.rgb5a1.png new file mode 100644 index 0000000000000000000000000000000000000000..b2e914b4949ab3dfd798cea12a6aa6b7861c64f6 GIT binary patch literal 2338 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 literal 0 HcmV?d00001 diff --git a/assets/objects/object_box/gKeyTreasureChestSideAndTopTex.rgb5a1.png b/assets/objects/object_box/gKeyTreasureChestSideAndTopTex.rgb5a1.png new file mode 100644 index 0000000000000000000000000000000000000000..8d320f250aeadcc995df6067173f071c068f054f GIT binary patch literal 2184 zcmV;32zU31P)&9GPgm7`EeHGbx!s8a3)W;)wQKEft@VB1R&T%kwrH)f*6zbOcPDPv zj4>Ev&|0IE;^wKfQfsA@Le80-GbyDzakG|lrj)Y(Mgu6N_Mx@D6E|zO-?{yW$fu&# z`hTqf*xMT`rTFcyUI(QRsdyhigq#y1V64Gf%P-&j4WE2&HvRDrULlu^0u(UCh;t4^ z&_<(mL$KBgfO_Yhcf=U8huK=ouiy9u^I6By;Q={CrfFieT9I>M7)KtgFPNstTfh6m z9?I8VeVLpRi^ZJ7gB2I+hm2!HL>Q+L=K|Ima?U8F5fO~hj}Ta|*E~Ew=d({f$@hQs zGrsi9GdO4Q&VYb*7OfPiU@!E$A?fW#uzFPr%08G)*5FFRVpIvN+^gx z@DBCvyYI?ovtc|x=h@AM-=CiHh0{}xo_dNOeg75iogAUH1}fGVQc8pnxE@9>HkbVR zt>5wT3(v8f_jDnUVq|r&B7~0n_wRFjd_q6#n8uNu3o#~2$$((3ZwO2uf6TMnEyL4K z^VJVN;1AAm{JGDejY1pE#lp8Pm;2`Y*4MvA@Se-}66@ke9$@&_OA=X>{f{PD+8z;dzR)Y5P~P?La7C%G~4YpQZq3o7Rx0(_81Lt$SD(3L@7nd8E*~F?+}=so?^V`-LB({ zr>7jAp7O(2zs+j7;OyfwoOg&+taUi=&`P6}km7`M4(|faIS!T!Qi?e5nT8Q`}&h3X(A*M*mh3jFY)=El=m@-q!Xr&)b!EM6%&6_{xi=Tgr<#NV2wjair&|1-V z9mY8{aQhOSEGFO*dj*br5Y&J}jAhqH`zzl|yz9;k@B^Ln3aYQLa*L9R~3jwV) zKmX}#%=;d#C$__YwH9Lx)&~UP@_HcWOBCRItG~6D`Fy_HSkr|-6=}7X$~cZVZyBc% zjiT>bxpL0L7_ql$cDo%gN^^ZZP-{U%aL%>_m7<@`2+om9q2$bVd(AXW7^8_Pk#nI7 zo?#g1`koLvE-p40>(N@1a^dRwg2UATwN{k6RRXOwhX+gUog4v*7^nRS8+$222mok- zuJ4dqDYamX!TUhhYn-u!uE#oyRH2WFI1Q~Y0IM}u+bc>bjSFt;z zYbBS0Qs8WZuJ1Yop(;3Bt(am&D@{xh4U|%d(}=YWYYjfk$SF}uLv@-WT^I1)wG!-= zPuNSUNZnIy-N|Q)5$8Npi~!`Eu{#|pJCvGaYsPUxq@t9f)`q0_eqTC~c9=T|TwPre zoY`%jP)d<=CFP7UdfzAYwn7@qG)*|?n}UX>|4J#GGbp90Q^cCagg2!~DN}{JJ@EGr zKf*ar@RpP^&e?YIT(HLM63VR)^rP>bZAovhhjz-+`Xa>yyZwzZZF-#Dn-~%9PQjo4 z@>jm|((|kqbAX+W!!V45;4#J^B9vO8RmhrP4WD6YqWE_BUqA*2{V zDU{aK(vnQ6ojQcTG(}1&jN`aRU>pa!uBVjxX;b>@%P*oebUx5`JqpEQK1V4o2_f+B|NMv5V!=3#EEjXM(mYtN zG5Qm7{F5Jkj~p{8HusZj!DvfLiOuGcS>Mxl9m6m*OD%%$I)e9%(}Y4;Ef#z2(7Q%E zJXmpjc-Rc9RJ78J)2<}95m>L+oPOq*m?9$FA|1_>PdN^+4(t( z`HWKA{UA;gRiNtvo%ammNUens0@gbE*^F@*@A8229<41(Tci{~aeckT7)Qz(+1&wB zZobc1Llt&orr2JOh}tn`g({V+>k(@$DQBEDY_0}MsZ23ZYrb28;2a@1j5Z_$&>S5d z>=GGRt(F+w#;lgYxbuW5rDoZ3#%R-SL#Ev~wb58(Sg$wqoyS>2%7w3eGgpC0000< KMNUMnLSTY;0y@C} literal 0 HcmV?d00001 diff --git a/assets/objects/object_box/gSkullTreasureChestFrontTex.rgb5a1.png b/assets/objects/object_box/gSkullTreasureChestFrontTex.rgb5a1.png new file mode 100644 index 0000000000000000000000000000000000000000..00f0b39e44bfeb54234336642b70db3e275bb799 GIT binary patch literal 4265 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 LNkvXXu0mjfHpe@` literal 0 HcmV?d00001 diff --git a/assets/objects/object_box/gSkullTreasureChestSideAndTopTex.rgb5a1.png b/assets/objects/object_box/gSkullTreasureChestSideAndTopTex.rgb5a1.png new file mode 100644 index 0000000000000000000000000000000000000000..0a09e2b6f160a1971f004210f0dcd161e9e7bf4e GIT binary patch literal 1979 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 Jt=gUY{{wF#Q49b8 literal 0 HcmV?d00001 diff --git a/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL b/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL new file mode 100644 index 0000000..966bef2 --- /dev/null +++ b/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_tri_0 b/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_tri_0 new file mode 100644 index 0000000..dea4770 --- /dev/null +++ b/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_tri_0 @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_tri_1 b/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_tri_1 new file mode 100644 index 0000000..36be433 --- /dev/null +++ b/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_tri_1 @@ -0,0 +1,7 @@ + + + + + + + diff --git a/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_vtx_0 b/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_vtx_0 new file mode 100644 index 0000000..6ca96db --- /dev/null +++ b/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_vtx_0 @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_vtx_1 b/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_vtx_1 new file mode 100644 index 0000000..3a65396 --- /dev/null +++ b/assets/objects/object_triforce_completed/gTriforcePieceCompletedDL_vtx_1 @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/objects/object_triforce_completed/mat_gTriforcePieceCompletedDL_f3dlite_triforce_edges b/assets/objects/object_triforce_completed/mat_gTriforcePieceCompletedDL_f3dlite_triforce_edges new file mode 100644 index 0000000..52591df --- /dev/null +++ b/assets/objects/object_triforce_completed/mat_gTriforcePieceCompletedDL_f3dlite_triforce_edges @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_completed/mat_gTriforcePieceCompletedDL_f3dlite_triforce_surface b/assets/objects/object_triforce_completed/mat_gTriforcePieceCompletedDL_f3dlite_triforce_surface new file mode 100644 index 0000000..06193ae --- /dev/null +++ b/assets/objects/object_triforce_completed/mat_gTriforcePieceCompletedDL_f3dlite_triforce_surface @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_completed/noise_tex b/assets/objects/object_triforce_completed/noise_tex new file mode 100644 index 0000000000000000000000000000000000000000..a6d6cf945e1bd755148a4d4dcbb52a7547cff5fe GIT binary patch literal 2140 zcma)-p;iK66oglkuRxQ?Q<%&agGb`VjYNupNF+ksxY6os*d%WB6=crmckY4&-2)5j zKXYg1-v6g*n&##4`RV3#|Na=h@;ZI|_uuVl<^Asq(Az`PoL+ZL(=FG>ZM*At{kGk< zoB8^f@B6V|^o#wtA9sD8b<1}4`pMPKy5;JSt6Sz1_+WFbkE_FGzU#q*&dPQML+cGs(0eCWBAFIAB+{qL)^;J{#(*^U779F9Cck7oMvyi7MiAz1X(~0sQ40!#}eYwJr z)w$3!#TWA08q`zmoX`3-iMlqu)Ut1KlNXALA#>#Hnt0flT_;zLs4+)eg_T-0z2Jv# z==wz%=q<_ft_t{={8V=eviFAWeF#3h{wM3p2TJs82JFS)hc4641%p29MHs>^6Wz%( z_P%H)*j`R&0VaIl)cQF&g7^Hu`S~RA&8l$%2Rru~ep=hPLVc9b!Em_yQawC50ZL_7 zkVWyC0UUWR_wL|gup?AW- + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_tri_0 b/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_tri_0 new file mode 100644 index 0000000..09e44f1 --- /dev/null +++ b/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_tri_0 @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_tri_1 b/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_tri_1 new file mode 100644 index 0000000..48001e3 --- /dev/null +++ b/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_tri_1 @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_tri_2 b/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_tri_2 new file mode 100644 index 0000000..e35e344 --- /dev/null +++ b/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_tri_2 @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_0 b/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_0 new file mode 100644 index 0000000..a86fa98 --- /dev/null +++ b/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_0 @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_1 b/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_1 new file mode 100644 index 0000000..230fbb7 --- /dev/null +++ b/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_1 @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_2 b/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_2 new file mode 100644 index 0000000..86d1238 --- /dev/null +++ b/assets/objects/object_triforce_piece_0/gTriforcePiece0DL_vtx_2 @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_0/mat_gTriforcePiece0DL_f3dlite_shard_edge b/assets/objects/object_triforce_piece_0/mat_gTriforcePiece0DL_f3dlite_shard_edge new file mode 100644 index 0000000..f626317 --- /dev/null +++ b/assets/objects/object_triforce_piece_0/mat_gTriforcePiece0DL_f3dlite_shard_edge @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_0/mat_gTriforcePiece0DL_f3dlite_triforce_edges b/assets/objects/object_triforce_piece_0/mat_gTriforcePiece0DL_f3dlite_triforce_edges new file mode 100644 index 0000000..9355e70 --- /dev/null +++ b/assets/objects/object_triforce_piece_0/mat_gTriforcePiece0DL_f3dlite_triforce_edges @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_0/mat_gTriforcePiece0DL_f3dlite_triforce_surface b/assets/objects/object_triforce_piece_0/mat_gTriforcePiece0DL_f3dlite_triforce_surface new file mode 100644 index 0000000..e863b31 --- /dev/null +++ b/assets/objects/object_triforce_piece_0/mat_gTriforcePiece0DL_f3dlite_triforce_surface @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_0/noise_tex b/assets/objects/object_triforce_piece_0/noise_tex new file mode 100644 index 0000000000000000000000000000000000000000..a6d6cf945e1bd755148a4d4dcbb52a7547cff5fe GIT binary patch literal 2140 zcma)-p;iK66oglkuRxQ?Q<%&agGb`VjYNupNF+ksxY6os*d%WB6=crmckY4&-2)5j zKXYg1-v6g*n&##4`RV3#|Na=h@;ZI|_uuVl<^Asq(Az`PoL+ZL(=FG>ZM*At{kGk< zoB8^f@B6V|^o#wtA9sD8b<1}4`pMPKy5;JSt6Sz1_+WFbkE_FGzU#q*&dPQML+cGs(0eCWBAFIAB+{qL)^;J{#(*^U779F9Cck7oMvyi7MiAz1X(~0sQ40!#}eYwJr z)w$3!#TWA08q`zmoX`3-iMlqu)Ut1KlNXALA#>#Hnt0flT_;zLs4+)eg_T-0z2Jv# z==wz%=q<_ft_t{={8V=eviFAWeF#3h{wM3p2TJs82JFS)hc4641%p29MHs>^6Wz%( z_P%H)*j`R&0VaIl)cQF&g7^Hu`S~RA&8l$%2Rru~ep=hPLVc9b!Em_yQawC50ZL_7 zkVWyC0UUWR_wL|gup?AW- + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_1/gTriforcePiece1DL_tri_0 b/assets/objects/object_triforce_piece_1/gTriforcePiece1DL_tri_0 new file mode 100644 index 0000000..5f33f73 --- /dev/null +++ b/assets/objects/object_triforce_piece_1/gTriforcePiece1DL_tri_0 @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_1/gTriforcePiece1DL_tri_1 b/assets/objects/object_triforce_piece_1/gTriforcePiece1DL_tri_1 new file mode 100644 index 0000000..43df649 --- /dev/null +++ b/assets/objects/object_triforce_piece_1/gTriforcePiece1DL_tri_1 @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_0 b/assets/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_0 new file mode 100644 index 0000000..e078b82 --- /dev/null +++ b/assets/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_0 @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_1 b/assets/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_1 new file mode 100644 index 0000000..e046019 --- /dev/null +++ b/assets/objects/object_triforce_piece_1/gTriforcePiece1DL_vtx_1 @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_1/mat_gTriforcePiece1DL_f3dlite_shard_edge b/assets/objects/object_triforce_piece_1/mat_gTriforcePiece1DL_f3dlite_shard_edge new file mode 100644 index 0000000..b9e6129 --- /dev/null +++ b/assets/objects/object_triforce_piece_1/mat_gTriforcePiece1DL_f3dlite_shard_edge @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_1/mat_gTriforcePiece1DL_f3dlite_triforce_surface b/assets/objects/object_triforce_piece_1/mat_gTriforcePiece1DL_f3dlite_triforce_surface new file mode 100644 index 0000000..5f8dc51 --- /dev/null +++ b/assets/objects/object_triforce_piece_1/mat_gTriforcePiece1DL_f3dlite_triforce_surface @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_1/noise_tex b/assets/objects/object_triforce_piece_1/noise_tex new file mode 100644 index 0000000000000000000000000000000000000000..a6d6cf945e1bd755148a4d4dcbb52a7547cff5fe GIT binary patch literal 2140 zcma)-p;iK66oglkuRxQ?Q<%&agGb`VjYNupNF+ksxY6os*d%WB6=crmckY4&-2)5j zKXYg1-v6g*n&##4`RV3#|Na=h@;ZI|_uuVl<^Asq(Az`PoL+ZL(=FG>ZM*At{kGk< zoB8^f@B6V|^o#wtA9sD8b<1}4`pMPKy5;JSt6Sz1_+WFbkE_FGzU#q*&dPQML+cGs(0eCWBAFIAB+{qL)^;J{#(*^U779F9Cck7oMvyi7MiAz1X(~0sQ40!#}eYwJr z)w$3!#TWA08q`zmoX`3-iMlqu)Ut1KlNXALA#>#Hnt0flT_;zLs4+)eg_T-0z2Jv# z==wz%=q<_ft_t{={8V=eviFAWeF#3h{wM3p2TJs82JFS)hc4641%p29MHs>^6Wz%( z_P%H)*j`R&0VaIl)cQF&g7^Hu`S~RA&8l$%2Rru~ep=hPLVc9b!Em_yQawC50ZL_7 zkVWyC0UUWR_wL|gup?AW- + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_tri_0 b/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_tri_0 new file mode 100644 index 0000000..b54e182 --- /dev/null +++ b/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_tri_0 @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_tri_1 b/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_tri_1 new file mode 100644 index 0000000..00a32bf --- /dev/null +++ b/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_tri_1 @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_tri_2 b/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_tri_2 new file mode 100644 index 0000000..0993c1c --- /dev/null +++ b/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_tri_2 @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_0 b/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_0 new file mode 100644 index 0000000..bf7dfca --- /dev/null +++ b/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_0 @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_1 b/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_1 new file mode 100644 index 0000000..e3237ab --- /dev/null +++ b/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_1 @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_2 b/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_2 new file mode 100644 index 0000000..ec4e737 --- /dev/null +++ b/assets/objects/object_triforce_piece_2/gTriforcePiece2DL_vtx_2 @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_f3dlite_shard_edge b/assets/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_f3dlite_shard_edge new file mode 100644 index 0000000..c222fe6 --- /dev/null +++ b/assets/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_f3dlite_shard_edge @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_f3dlite_triforce_edges b/assets/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_f3dlite_triforce_edges new file mode 100644 index 0000000..5968068 --- /dev/null +++ b/assets/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_f3dlite_triforce_edges @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_f3dlite_triforce_surface b/assets/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_f3dlite_triforce_surface new file mode 100644 index 0000000..d903f00 --- /dev/null +++ b/assets/objects/object_triforce_piece_2/mat_gTriforcePiece2DL_f3dlite_triforce_surface @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/objects/object_triforce_piece_2/noise_tex b/assets/objects/object_triforce_piece_2/noise_tex new file mode 100644 index 0000000000000000000000000000000000000000..a6d6cf945e1bd755148a4d4dcbb52a7547cff5fe GIT binary patch literal 2140 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 v@qKsBw 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 a-T&@2YJoFO%U-?#^v9T38ecYa-}N5>&$}J~ literal 0 HcmV?d00001 diff --git a/assets/textures/buttons/CUp.png b/assets/textures/buttons/CUp.png new file mode 100644 index 0000000000000000000000000000000000000000..6c0e29d2de653af5f5518cfd1c6a5d3b956b1e33 GIT binary patch literal 11219 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 literal 0 HcmV?d00001 diff --git a/assets/textures/buttons/ZBtn.png b/assets/textures/buttons/ZBtn.png new file mode 100644 index 0000000000000000000000000000000000000000..def8d9a6da2fcab6486b6106064d9fcd11dd47ba GIT binary patch literal 1241 zcmd^7;fvb@6o0p#W-OllP&8n64z!-JE+(X)vKtE{9js;Vf8EX$%O3WC7%d^Ve9S=K|x zSrm&?(;VtXPt{sVp(e={K?-@n<#>zDYBVELR4$!iNs=OZji^&AwW>iQ@@gd~4(y6= zm0csWb>C7wv*74*QIpJqpvyT;;%lK5d0J=}JX0!aIYZ%8k(G0_A6Sm77j4zB6ipWu zH76;YAY~EV`9vRg<-M41`AlqNN;2VcfRhP!yBNpl`)HadNysn=umHFNFa{U^^Z?ob z4S*P+3=jag07U=;U^c^kADc~#B6MBUG!%ryJc&S(i9o_ms0l9wumLojPjKADevEA& z>jp+52K2s5&7JhLm>!$tKqvN8=qS*V0db7jMvM?`Laox7yY_tk=gIf%qo)9#`0M?v`Zx4T z><_y)E_`?O1>!Oi7k7B}p>t2ay!`d*t>=6=f9%hd^)>U;o%pVAmmWTUJM}lvza;hA z(cv38M|?_9rj`P~oKp8a)c Yb??E?_CD!fN=}5$jjjCd`nlKt0XEX>4Tx04R}tkv&MmKpe$iQ%j3f9IPPXkfA!+MMVUcT7@E12(?114kp)6Xws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;tBaGOiUPOWvu?>ZqU!3o%+XQcR?2KjGmYcKi~#6mnI- z$gzMLRLG7W{11M2YZfOb+@x><2)x+#$0!io1zHW;{yw(t)(PN$2ClS@zt#k1K1pwM zwCEAgzYSbmcQj=WxZDATo^;ue9m!8qC>DYDGy0|+FmMa>uDQLn_i_3FWT>mu4RCM> zjFl*R-Q(S%?%w`A)9&vFiqLYfsZ*;V0000pP)t-s006Ef7Y$Pw1wSksW-A6tIVG(x zFI-45gh38zS3R3h38z~MwPy^&cMp$`jIpz@$jZkcHAig#0004WQchC&G0sSOa5;;t1?OaI$n`0uc_7t@fqCKi>wt?=fQn;`f|DHMCO!vBaul3Pk}sJq z5th%iAQoQUf_j4%ei{I4*J%K9Zou$Q2`wEE$A4<gz4{Zfih2m+X4VSwB_Y-B;>A->{k zUP@R5gSxp-Y))!ydQM?+>%vXj>S`AsJ%8ckwu#a1MfGLAx{MNPdN!_3cFr#D(T&q) zO?L^Ick;}>$!Q)29)(T0zG{MU>RL7-p@B~3=AKEFHK}4&Jv$FB&NCKKbjc`4a?sQ@ zv$XMu&4_X~RMRnY_cUgd4egxXmTV>_Z6BW&?e6Fk9vbMMQkw0lDJ`p@C@;vuD(94v zo#>(}X&ROs7Z#hImm43HQdJhIBPuQ~%FoHlE~4WV74B`JW#k?i9i5bsnGqS1)!v=w zC?+f+$j!pY!l!EC=IiR>?BpKc=VD`K@9LY=I&F4Cu(E)d5E~N%6PJvhp|O=mSbS1i zYK)Vdkakr2?D=!*L$!qk1c34^d{VM9lDYw@IpsBN-R16z_W9FRubxrnttQ4Nz{SkO zAuK5)t7+vE7M>(#DBP}K4;^E@x5)_}76crj3S2AgCdw%=s!>3N}>I>G=Fx1yKxAP2*ODQVP zP7Lu6iOQckZ+3h4=F{g-Zs`ru(y;fkwv^HLPOfP0tSv}S&n|3TxMjoqIor=&yRdg! zl%9rDWTZKRj6-5+ePeA^ZFOzytWA4&ty{hK+TFVsSLa(;1jT0s2%^O|dU`;QZ}jwl z9^dHc0X@Fa(*t^Zqo)V-_-0|1M@bJT@h!m3#>yqGi<};i<6BgagPD<4NYxxEJ)p!l zP@aK>M_kJQkseUuTabr^k(FCSLK=}CP~)4QlZk_0SV9Jo9?;`kPC;H#9VtDa$2WR< UK#y + + + + + + + + + + + + + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_0 b/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_0 new file mode 100644 index 0000000..2986de7 --- /dev/null +++ b/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_0 @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_1 b/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_1 new file mode 100644 index 0000000..2aa9bea --- /dev/null +++ b/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_1 @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_2 b/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_2 new file mode 100644 index 0000000..2b8fe0d --- /dev/null +++ b/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_2 @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_3 b/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_3 new file mode 100644 index 0000000..53edaf7 --- /dev/null +++ b/assets/textures/nintendo_rogo_static/gShipLogoDL_tri_3 @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_0 b/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_0 new file mode 100644 index 0000000..2c2ee79 --- /dev/null +++ b/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_0 @@ -0,0 +1,335 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_1 b/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_1 new file mode 100644 index 0000000..ec462b1 --- /dev/null +++ b/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_1 @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_2 b/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_2 new file mode 100644 index 0000000..cc906e2 --- /dev/null +++ b/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_2 @@ -0,0 +1,323 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_3 b/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_3 new file mode 100644 index 0000000..68e4bab --- /dev/null +++ b/assets/textures/nintendo_rogo_static/gShipLogoDL_vtx_3 @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material b/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material new file mode 100644 index 0000000..e48b335 --- /dev/null +++ b/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_001 b/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_001 new file mode 100644 index 0000000..e986403 --- /dev/null +++ b/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_001 @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_002 b/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_002 new file mode 100644 index 0000000..b2db72d --- /dev/null +++ b/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_002 @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_003 b/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_003 new file mode 100644 index 0000000..be60fd4 --- /dev/null +++ b/assets/textures/nintendo_rogo_static/mat_gShipLogoDL_f3d_material_003 @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material b/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material new file mode 100644 index 0000000..3cda02a --- /dev/null +++ b/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_001 b/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_001 new file mode 100644 index 0000000..3cda02a --- /dev/null +++ b/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_001 @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_002 b/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_002 new file mode 100644 index 0000000..3cda02a --- /dev/null +++ b/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_002 @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_003 b/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_003 new file mode 100644 index 0000000..3cda02a --- /dev/null +++ b/assets/textures/nintendo_rogo_static/mat_revert_gShipLogoDL_f3d_material_003 @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/textures/nintendo_rogo_static/nintendo_rogo_static_Tex_LUS_000000 b/assets/textures/nintendo_rogo_static/nintendo_rogo_static_Tex_LUS_000000 new file mode 100644 index 0000000000000000000000000000000000000000..2edcaacb3c9433e786162171be988e44cf246adb GIT binary patch literal 6291548 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 z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N 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 Axc~qF literal 0 HcmV?d00001 diff --git a/assets/textures/parameter_static/gArrowDown.ia16.png b/assets/textures/parameter_static/gArrowDown.ia16.png new file mode 100644 index 0000000000000000000000000000000000000000..cdb51d79ceb47ccc3fde8107e3206157c95bfb38 GIT binary patch literal 17227 zcmeI4TWB0r7=R~&MWYpIOBEk<*rM?^JGY&g-C?t(W*ZZ9YfPg_P_T13lZ@S+8D}QR zCLn0r2U|t4MHChFLBtDKwLS>q4XYwzTkuk%0oPYi^53_w}!;Qp9fa$rA%Z5-j+Vj5tOwX( z5V%vm0oG5$p{(gN`XC$zt=YkF1=Tw`3TP$y*kH6lBxjP1#aJsR6N4Nt-WlU3QJBXxl;8afUKo1G;Zr zmZ|HYVCsOe^1QoS|D<_yTCkr_gqJx_Sp$6;#uGZPqDu!#hks>#Od*-($9aX!L z>O9R4K(vv2Gs#Xyxe=wl$fl7HRLzKzWXXuO2QZ85yw=ubAL455XAmd=8MOe znFP+swpZ+`p|!Y^z_r2|%?Ily;0nRn`LWmeX6^2aY;;qp+W*BwxXv{2PiHFNglq7I z4E&&E`EHFyyO<7LTJyZBZD`RPv(t{*yuG2Vk<53>$NxCiK$~9TlH*N_%L9=SWQk{V zF()y305_pzig`nj6!44%mevL#u9VpxSjGQNK_bM5z0GIPyDzvTRKij)#%9h8ES zDLgaz#RR^6IvFN)l}3VzZsgRnXUt2^sd!acyq(C-jO(Jf9++R5C6(*KN-jDBt7*{`El$w|#!_G*-K?e! zD=K<csbkI~`MGmXOMwL|Ji|m57 zl($CTSX5b8ry7;BB5?4-^3mU>X}Y`Jbo}I|>F##ZmgQ}Z9hQVlwKun04B2&19V^@LOcg|D172?0w0Cqg9AC^Z)zLJJw@vCR`?_c zK7?Y?Q>fIOp|i-pFSJJV@B2m`Nf3krMWSAsvDXp}-LcE*wfohu}gea0G%2hZ52uxDW~)f#AZS zgmeflgaSt(xNs;T9fAv?z!3;897;%s;6f;H1cD2P64D{K5DFZD;KHGVbOW8{}2g~b5>fb!S>!ypgau=4L-Syp; zJ?|erwDsZ@`Uk7`J?dQc+2^|-+p+3!{u%8DUU=9z@<F0i)2mif%Kkl< ze?4+!`FFqn`Nfs@DcgTLa`dHb*WEdA?cJ*{|K!$vgWYr23O#$jJb08I?ed|R!1PKA?eU-|UecfW$; Pp$6A)D8G8crY(O1i2dBp literal 0 HcmV?d00001 diff --git a/assets/textures/parameter_static/gArrowUp.ia16.png b/assets/textures/parameter_static/gArrowUp.ia16.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed3f1cdd9596322cc34c09509428082949304a8 GIT binary patch literal 17217 zcmeI4PmI)57{H4}ql+X4Vnkv>GlT?$Zu{D4XQs{$vOB;oGRwNGVV4A?e_nSRX4;|c z?#!-62#ASBFC_kn!FUj(2Sbb=OeCV4pk9mzVq(yEkwnFV9EcLb0bi%nH{ID;cnC^J z-Xyd0?d$ia@Atj;^=l7(acFSs(yon^ux4?HYG7W4~o%G6$ zQ!@=7mSF`tfsgD!N4x5T8@T?2yFf^Mc)`FZC#4dO-SK=Ym5!nPVDl70&_vqN(jS?w zLVg(f?xbhH%~NP9t2@o!4~AhYI|QzfdPhfrZ7tv@JhC7JShp823y(x*jWrdeI**{K zeIC>T*Bf!&av@r-Lvb$HzP`rtWY_Mp9n-D(>+*cNNo(P>yuqRtz=9~CwFpE`P)0yj z6=YS+trvhQ2ni>VW}A_g%NnG?Z?D5`0oieSAUVjl_3b{}XXnp&U{c}eOf z{FsJnxn4yJ3U);shkVr;&-1OpgeG2|YM)znJ#<>IAm#Z^!wIX#l2r#BKhPWl4ipP$ zpxd@h)lxvtl!3t+Izp(Y(}2?rN#-O8Xu2hunjqyG5KE<``8?M}*O&~q9daF2DAP5N z`_^fh0+0k?iJX-M84dtwa(Xr=ah4^^8BG_htP*7l1xh%Z7ifoPqXMdx6FT8sOcc!2 zv!ZUH5I|A@r|D^n({-qE8DOPFQxOy~jYD*BGcQ!X?W5H?omj!XjBP!tDXgJU?f&bz0c6X=cw)CmDjsf5Lp> z7_|xLTx)wpt{PekJMmpBsA(SDG>%pX$i(7TaTpoDAa zf($*sV0mtZ#k-gdTvn@A%eJ9~Ip(Jvvw3;LTO-bQ!pHwOS6`dD$t4F&OUOcr6BQX1 z4=F8kS%@~FY)V-}R5D6NPRCQcp(PhrV~|m0pn_~%jc?zQYwcKLLUYEUS>WTD#RGRz z=AdMnCaRE}EGiNQL0aQbxrCf$rZb`;T8as@cz*vXbM4nrnz?47zv=pNostq(9bAIq z6yBctVnWZpkqVPIOC!d_HfrjfGv}MGsbpPQw4LbAjQXOeADG*j#hvT?PATpve{#^(<<2qf<>d>lDkq*@ilb(!otDTAYUj?nK*`4{tP8)RCj^u+b$IK%SpB zmhjd%HX3%;<;h0poDl`|;X(MfX_`FTZaQ{t)8yfH)0X8^jvW-lX0*29gjIMq9Nntz zL{ETVL6K!i&hzcV?G{6J9hOInHoB+s!+QguG;P`sbTk}W$S`rBX&7yr#Iu@4Vxm#> zBnUl(;_*|cM9%QN$gLMzGrIM@u}2yNqaYC|E)q&uhvLF0NCb+Dgc8=FxG)M5f#M>e zgmow`jDkd3f<&OW zNGM?)iVLG45hyMaN?3>D!YD`tii?C2)}gpC3KD_hBB6wJC@zeGM4-4xC}ACn3!@+r zC@vC8Scl@mC`bf~i-Z!^p|~`p3(p@elPE{uXiptwjVVI7JKqaYC|E)q&uhvLF0 zNCb+Dgc8=FxG)M5f#M>egmow`jDkeCCa$j5dmW&IUgl6kZ*7=)J3WZr_`n+d!zG59 zS;H`gjxfyMSJCeUhM5!?=J$OJqrSl~54p#l{&EY_{dAzXX{7$c@nf@HXW09TUw?S; z$=M_IwMSF+%jd7~&u#tdqixD7Q|FGK39P;EO@8z8x$kygIlJe3SUA7o$nN#bZ$}q1 zmEv;1u+JY_aXxTYK5Ly=(tBx-{lXugt-8GKU4Hq1wygZ4a`v&=(-%jVZGY+1!*QT w_2JhJ{(QE7HWIsT@LQeSvfxsRl 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 D?WQyR literal 0 HcmV?d00001 diff --git a/assets/textures/title_static/gFileSelBossRushSettingsENGTex.ia8.png b/assets/textures/title_static/gFileSelBossRushSettingsENGTex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..e7a7aaa88ad66b0f28c94559bfb4030518c8bf17 GIT binary patch literal 4004 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 R^pmb8q_UP$`4j7~{{a|frUw83 literal 0 HcmV?d00001 diff --git a/assets/textures/title_static/gFileSelBossRushSettingsFRATex.ia8.png b/assets/textures/title_static/gFileSelBossRushSettingsFRATex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..8cbf6339cb3380fa37e0f7f6c2374b4bd232e7ad GIT binary patch literal 3942 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 literal 0 HcmV?d00001 diff --git a/assets/textures/title_static/gFileSelBossRushSettingsGERTex.ia8.png b/assets/textures/title_static/gFileSelBossRushSettingsGERTex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..455390170f0ab2abc2bbb0937250548aa66ddb23 GIT binary patch literal 3884 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 D4SR)& literal 0 HcmV?d00001 diff --git a/assets/textures/title_static/gFileSelMQButtonTex.ia16.png b/assets/textures/title_static/gFileSelMQButtonTex.ia16.png new file mode 100644 index 0000000000000000000000000000000000000000..076b9365f2c790d9e9bac24124591ca71894fe29 GIT binary patch literal 883 zcmV-(1C0EMP)vuTZw1`k|ronKMsd{uR-N&uLcm>6?9oqy)@ zdA_3E+}toaI{L%yc26mXhK9b+&(Hs*R4U2ka$geI>-A!_T7MG+0U;a?7tLlfvMjT( zuz*^vrn0iK^u6@eYIVt1DwW8xOfHvu^Z!WurS`I~P$;0$XwYi4Xti2&Ivs)_@bK`! z@$oSg$z&2qlJIyus8p&C&w6KPhpw)!H~P`h5%u-;)Ya9MwA0g5VzC&7LIIP>L~Cnn zSu1QX7+79jCY4H20g%mR%L-t#*~sVfSglr;mX=Do)9J+T_XDuIyNk=^!sGG$YmDLH zVVawpKb$j_N&!3pmt*O4n&-nA3WZ+PeIO7hwIxZy=ko#3)6;{);UJ&ScLS`iua{td-YHQOF&d4yTrR4st1+2O^!N9p zQmKeUBCpEk)4+*Df@m~KCX@M4fR&XMG#U+VxBHbY%Q65B4Glyh5sJkk0EI#Uy+==e>tya&i)Yjg1Wey1Tn+YH9-D+qZ83+~41$R4SR7nPF;bs&ozjv|8=219x_I z($Ud@PN&0QF#PA>v9U1#78e&w{_|=+LtR~6v9+~DdwV<4Xq4&cX(UNPp-|A+*!b(f zH!&KG1cN~w4hI&C1-spjEXxcI4zj(yO*kB;qN0LOC`2NWKomtTFE7gm7EVr1 ziU$V=h@wbMP0j!IH0$+xip3(COop|!H7phj0|NsD0)cm*=GE0z9v>f{fLmKzzxVa^ z{S9z+9&(a&V#4sf-RHUYzVE&Fx$iya{Lk;4`@+cJ9>aOA^AHGx0ik`@1f0=ezj%%s9Otb< zo{3^Q!nu?Cp#vRCXD4CUSIVpFLpb4qT$xkkPbs?__3LPZ|vuFKyer88CTx z93m@>{Ya51v}mk38Q+=KIbNYTxx%v;EXb^Tu8=kyE@DI)nOMFb1y`_N^GR#a_Mm@X z*|`ZIxZ%CHof} zoT!OJWj^i_t*vVsYmz2>LlD(!=k>2v}j+j?r~^lY=DfNM9SP6_sfgyPs%-i6QX z)ZOQBychR7fWA?O4pD29l&5N~8BR*SL#dztCWg&gU7C z=Hf5Gu%vGPQPIP^+iGt1xOJ|BgIAU(wwX~-rgisry&bn65ENQpZR-FCgpT>&4u$08 zaX=vSafrL>W*#w{*^x$5mchNMXq66r7FNn9l>B^5!dk1{Of1j28j5T!(~L6W^)-Sn zGdniI^R;f43k{d#W3=+`rt2+B8`E;>OIH|=@vvfyWmzlf&zWnR@!gHMHZb_#-X?E5 zJMUAsy2|gwk*#cJ5_wDEaCTd{Jz!Mf@V3M3Yi%bs>5&L_BieL`X2+mVHRUv;-AeM4 z+kR)qXX=JNKYL*6`_En%ViYcUbdm^j$$6 zbbKL4$TDB=>6m@`;Ti861$5)X8KHz(?&=m22kb7(UK< zL*f{DbkxRn6-x=jDC9>&9;c3Bn&xt+um!}c=F zOTW#u)q306NzRvrL`~u*W%M7j`a+t|bHi$*Apznw7n&)!X);51q8PZLTSt zyQF}sYGF#sMRdw>O{_C_oD_Oc=l~z>w0SS4dserS27Ln~8#Em;|IF{I?oh}en-olV z2(Hqr{S6Wg+n~l#<0#jl*TA-d$M1dBm4Z_GOErY(=JRztrDbN}=6-+Y86yH)YLNfK zo-!plIaw=-yF3O)W8=y$F<+$qL>4tIJ-XBSH7x4ncP}dw(_%l8Le}@ES|W#xhKh>H z6shhC2QPIMY<;{ed1+~B#rKxto9ofh(Skxkq5=Y4Q*-*1Db>~0mo8mm;o|a2~p`xN9rWvZF3V`QrrlVY4j>L+t7_~={S$KK3UyxO|>iihLP!PuM z@tQB-B3HM!t9N#M!}G!6@6pkDBXEuN$`x;-63yG_v(xzG+ zTbrDt(^gN^dT z`EWz*26bkPBeU_ACV<_MmKBX>(^o^j5^Q{y|m;4mzNilk}@N;&-CEe_{UjXQc*5PcdNdA!+#EiqIjPsB_1>gk1t0|)rv{%ToP*^T{Z zKnf!6C0}W%X-5r^C5lc?A`m9#<{9Le=y(`C=Z(AAz=I9zRbW76rT+2ZHha<6uO^7E zM}K|=Ep}36WMvH!1HFKDuq7WqDoWVY_jQg7QtT5(E;srtc&p08;eMnYXKY%UQh!NV zS-?KQSmlVo-;>0ntD!+bBoaX+p8^+*O-=QzPgX#+b#AOz9UKHhE-^D(e|jVX{7~P} zkeZsRjzo%8x1TD4p zpP$gs($l*gY<$P?s^XZ}&}fK>iOF?waktR|1k7(VCo`EN^bMLLdqg>11n-Mg4j<=9^3+M8tUa6Bs1vx=Uo zcJz5hjEkdA2PBJStGE1bX3`hrCa?w3??9c_gd} z5yRR9{+f~iuNRS(HS_fJd{u z(0i>H#WB~|C$JbYSetv#`dtssH!Q7|EPoDhV-F4|eL+yP>bLEo(g!%aRUMhu1eyg(Q zmzGWe>~aWQW&QEvM_+&cwHr5fqlO@7`(4b2lu5j*DiD6S#6i7&**T}MSA#6^G~Tn0 zFmA;_ZSN*q+eXwF4R1uz)Re_=uDqdcmSl#&=0dw8yQE!;06>!mNC;6WsVtx-b@iC_ zU%v!7Gyc#?eY%QJ^jms5AByLhoSO1F+?vb8kMuS>03PXLjje3{boKH^ivx=%zkLHz zwf#}!`~;MO75^4lm#*gqOhrHkAkbrTts#I3Wt%figPXy~*=9d3<*<6tGuYVLHawh> zo1B>N*jpQ>sCVsUM0{QR?^#A(o_Nt%y)BtA_F9lLl-v;mJ3!dA23N+OAuz~Sk=Vh3 z0n~{FbXsQ_v5EmO42O67! zs-E23+|6M(cX#AsXKXNOi$M62#G^#nx9IBuV$)c)-G1g^TB^tN#k+tHeTKncCM+Ez z?+*gM%!r8c^WSOmS!fJx4c^55w@5IdEPeBa2w2%T3;KYSKt-zS!op?a!w-gY;1sfv zM}gsnpiZ)DaZr(lW@c>hqlH;+B^qLZ__Z~gxPo}&h&iqsZqL1tNI_1|#+H`v!D!G& z5kYammVo%?-}37WhNx}hj;j&}SN*?tZ^yHWfeIkVS?;sklXzh63rOeRItR+t%61@H zyGTS_TyJb_EK@yRnRHA(Ibq@9c{m66f$r|@nfm+Jg31Rte;+SbHV(>@Y;0_7x%+5= z4gz6pWCYp^YHCqI!S21PdHUHuySpYR)O&#SRXpDP_tYb&mp%_sgfFjjw6%Ba0(jPV zR3s$yFQ}f>z@y})rH#O%>oZN&(g9&kPDLiBrf`ohS4SPX7}Y>Z=olCrY&^4Fu{yodQ#Elq0#9 z^N6311#1>otmjJg0^Tz*{@J0Tr6*TV4nuER3D(Fwo#`>marF1oKjI!_wv@}=gt zR2)){q&^9e2bT5bopoNfkP4_)T1V7L=NK$N50yF`Fb=)u^!Fs-e%tVGk2qgn3xvH^ zBh#4TZ(v3U3;}0#(ovLLj3;fLhjbk#0jCNd|B|9hRmI7d>RRf8eoY;>CV(k)_cLlc jC;A)lv?;kT|CDAOscHLoo!<%kra%yy26wA8oF4xV1CcBk literal 0 HcmV?d00001 diff --git a/assets/textures/title_static/gFileSelPleaseChooseAQuestFRATex.ia8.png b/assets/textures/title_static/gFileSelPleaseChooseAQuestFRATex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..8bc17292b26f703123ee26b2ade96d2acfacaa13 GIT binary patch literal 3852 zcmWkx2RxMjAHPGc%!DY?FjE<2W^b45pKK>v$;{cDR7VauBzuJW8&TOKM6x@w$2oG{ zS!ZR>|F`G$`aa|JdY-<@IaGtRUh=xF* zFWfaWjQmV=)UUy{G-M>@Wn}K$6_bQOL=ycI@weI^^L8Sp+|uv7iTeFX%7DM_ViROcNUm>xD<-deS)?X-#LCO`B<51-s zWjqD?RG^f!^%~msC)P@Y+Z(ULHNC^d`}{Y}ilmmgYa2V;QanE7cF|YrJ-?CN!vHB^ zYy-_Zp*dr%kvDBgZ9}D6Bcv;HNI`bJvpMHNq;DGS{T!Zm4wsg$)+OeQaBO z&fNLbqT5aWagcnr4N|Lk*s=M0S|9#Z2eNlbU0Cxi#IuOol}RNE)3u6Yy?X4MZ*Zh~ zGyL6)@1kEy%kn-yOlQ(+$}iX5DHu;)fTvlG_MMzkOS3O;rc^4>4(xewuPJRxPpwxv zb0c(KZ}>6Q2-o$Q&oiPWj;x{BU{5L9kn>H~qo4shf5A z14!EV4qv?JZl=S3)e z?&Kq%mV5XWiX}dH)C%A0rL=6>$Wtpx6Akl(rbb4#R<=TN8S2!=X2pd6mvrz)tY?WK zA2q0Y#hWVDl-+9K>JC{_NZjQZSV-Paz_6l}T2CS3v?;1{#2X@=q393wHvO9Q2h zz9-`b2CmMdLjK zQc|*~yL*t`P%$soKAo8nY^;s2@O6y-mMNh zL`Iz!#*?U%)x8UbdkW+GA#+9vd`kaWS&71}YCW@-X&KL+m0;17pA8VcZr7@xn^#j) zgPZUm?`_PJNTg{Bh0-}(Yzj9tlnvBC^{euII)l#Oo%fh8J3KfzaFEHEXz;()-{1ef z-z9i^NlRDvtV?AYpHeVn3vwaLaWm`gi>zm~cMJ~3JgdBg@!k}y#%fLGJK$qI-x7ZGQJhD5Xq=<-6kX)=*VV&F19OiqB6* zL@(a9Xsu{D>4{+%-aA;X0O>PO5kA%UNxXr}{6O8>Og&s}G?ew48IGidy&S66{k2@t zGLy(CzK9Z1ZEkK(mvYA*Y%k+d?SkQ0sqmw~J62V?SdI%9ZnREL?6LF+;NrvshFc;| z!#TOQYH>IkE`{G$B^_S&x%lA@Ub9~H4Ez?~V@3J#sA15mK?2R{{atCbDx+%K;*`av zB{q|BmFh`oD2_Nip^@^QRpt7cpRexj?yh}^W+C;tM?g-P7W&fem6ViR$So)kfd7hS z<0nxlxF{HFk4vTd{ExWJt*zv4Cv1m9;)KV$)YR157h|zltkm-bBg@+tJ32c2gCPz6 z%S9xT)5zG^^6a;$&A)$5jf~!c_ewLB!zLw=^6`yzgG3?%#=>jl?_WJyX88eyf>4Pq zh?b+x*v-vNr)nz@o3QH4%*+FQ{gi%}A&^Tcr>^tR2XMGC5?KS$e=nid8Gpsp*}3ph znZDcOeXu5#uE{UvuheC`?> zGw<&1o~(J65zi~1&&VYvA|#}ZYHDh#avu_!@Q|TS)fy^=>~MIG*PjTf9v^HEtr8mj zH-2k{t$%~{^!Ib-9vy{#w5c~ijaDGm@^=@9bn5HtODZbH(xso0=H~MJmq&}MtIf8z zx6_qEY9MzI%{J1~()YuU>U`|O*@upAdwcRbo~u6}smQH&Itt$HA^CE8AiJ(W;S9UZ|J)WVSWZ zSI5>i%Lnqyhb|6mlPb{dQVGZ2;ODOfIDwlyd-ib!+4$zo8@h#$wKG@&X(=gP?6PXu z_K5ixtB*AQ85!jk6$z!Jq!bqxYMq>%Ojf!kh>D8R)sd|ch<^yaymQ1hFxQSYv#=0R z)q8h4QDA$OV12kl^_z%T9=(%w-~R#11)oi|(f}?2+-S_Ow@#rzDFxslaBRWmrZ4ng ze#re9XGHk<+qDe!^pXgk0Uc1s&iD~rPPi!iiKpl2biJQ6a>W8}VriLXWo=DxY@mE& zyA<_TxgU>*UAuAP1)!-x)_pBKJ;uSo!P|&t-lXpD`+q5t8U0kHF2t*a1vg(`Uv3!> zZUy8@tA~tZwbjPXj!RGSO-Px==QevhtzGl(Oh`;@EWe6M4gg(t#7R)<*SNU2m#<%c z0dmO~L}EMGTGR*)RWvg*+gc;$BqwvUwY72Ib&Bq#H#9T^`Tt*8nbQx^{E_v;3yu?3VcpQ zgvYeBs1U;fcID*n-%sy|<+|t6$1P^p6g}bLva>QVUFQ?kpCOx+nfdVfb17GRw&3mC znB?T-onTwo>|G;IkvI&-X&_e(aC4~A)sQdZ$cK#2!2>jKD+Wp!8ynkNq75G3O^bf> zCcnHqes3>OJDwL_>q%H&U$-AAF|(=jjvOg9r{#qz)4Yg^irU!Pa$1}DDkUqMl$aPv z@Py4Sjg$_Lj+z)7LsfTI36~`7Au1<({4yDFfM5`i1{;}iDze67LLKNZK>unaf+tfU zAf8NiL7ld;p{F?koQ8*ojf{;W(P-E%F+xQsDdrrzkdd{uo`*--;bm%}pehOT4J5DHBRd|GZ8dd^Rv(w6wGoI3Fi_mYKPONW98h&)zg0 z$Ow)@L`!(q__&3ll2SJwPZ|Aa9T*(!OX^~)@gn{N(2(~dWAxGz5?Be10c$-Cb@sJW z`}>rfi8>#C*Poer1qCmyYds|+PD1Hf`T9uRNk9vspXTeb%WWIUT^n>~&OqbE$K@bb z@`{UNU{^!Wqh`K_(6SiL#j~m$z4dB2eg}l^qL_`YmDOZc-=mNhz>;bzSv)2`|AvXF zseIT$)ge6v$~IPkfaRKtcaE%t-tjN#eSeszf!_NaD=s1?Mg~^J!U48YXG+a0z65VS zNwve_dQnq+kl8MP0r{ZKf?hK+DD?2KrjLbc>pkO7+eUi#_9N2Q#odOr$y@*O+l zt)r#}jf{*O9vRu_yNCbe`{w}-E$#kL&WWb8v*6>$j|Bt;eeg=V?<0d+|MaGc`~B(R zEYi==c5t`>D)4x{juZ8M!l*;P zO@mJ~79SstaqTUYRv?3ZR##Uyt+z4Wwyx=0XkbbPePL*PylZQ5C{6n5ql~AcPpU!x zwybhv1A_(RKXY@x#b1KJH+MI;*{pz>$AELFc7AOwElJO5IR*v>n-JM2!y+=zCY_?6 zxqE%MGyu?OtA;_N(GWoafvR%@n1xNC8opMM$ z%|A^fc%}+WP?6@JYM(Ful4)Q%0CHyg90(#8BGed#O-d4k7Z(>Zu&^M{q+qK8*6bV+ z_wuNmZ($s`!opWpw=V)Yc}w@{xDu}%+v59&;e&SE?}fn+Br=&M-s17kO!-hSW^GZY zxJpMJxVztsiHYG=Kr%HF3_$&~w6vt8q>RkWwEX?0K@u>0O6ipB5SG{ub!}~WH8nK> zA)y-iM16gIh`yX1%_%lJTlsh(PeVXJz{tWv*TqGMnVDH}y_FW?GbNF#^Di6M=r_H6(*wnNg$e(1|!-r{iU$wQV z1NEb=WxqGks@MDO4o_A}N=L3*RCGc@K!@O3^Pw2!XVwSv3Of!Cj`j6+R@%2fA%lYC z+1S`Xo;LesiIC*x}FeV`ZS5=h^B!It|b9{V;7Sg0O<)l%P zbaK6xoo@`qDd#(=lPQ()xAuY@xy%~n_w!&^?iZHE*IO}Unq3+}iz7^GchhA1Rj#RI zeZicZ`d2QS%BDp?PZ&Ex#%B9HWE1e2v0hsdu(BT;xYUg!j`drgilV9y?!~X6(war3*pCJXN5OG>e*lQetW`9q-h+GR0&zjpnQbX4A=TDGThto@8K1cJ5 z@rMet%S=C}e%V$W*6r+QLX-pEa>3k&iu4cW&{r|~AzYojQIiv{v)wGDDq@TGY^1`% nal}znYYwp}&M{ov`4onY<16G9gI)kXR1mn9fo8e7{fqwtC=am* literal 0 HcmV?d00001 diff --git a/assets/textures/title_static/gFileSelPleaseChooseAQuestGERTex.ia8.png b/assets/textures/title_static/gFileSelPleaseChooseAQuestGERTex.ia8.png new file mode 100644 index 0000000000000000000000000000000000000000..25f96cc2bd9398e4e5dcbe64e8bf8a7fd46018dd GIT binary patch literal 3666 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 literal 0 HcmV?d00001 diff --git a/assets/textures/title_static/gFileSelRANDButtonTex.ia16.png b/assets/textures/title_static/gFileSelRANDButtonTex.ia16.png new file mode 100644 index 0000000000000000000000000000000000000000..f43114e81968d6937e6c17c9589a00b3b26c2780 GIT binary patch literal 1045 zcmV+w1nT>VP)lW`cszSvotJ>Tb0--V}EYdwee>Hq%U|MM;ZpslU#kFKt+KCjoy zSG3d9Q(9VDzE4k2|0&kg)O;Hl82C#RMIIg=z9it;*;!IjQhpNz0paNA=t-l|;PH4E z85u#TR1y#nAU`jCrBW&TqA23=czAet@Ogja`(^B9?(y-Fpr9avgM$eU4n~qB1VO;* zbh5U#hX3W|C2qHynVA_B3dK)%X|Y(a+wCY63jF>35k(P=Mng(U$}eZsX0wr;oGkll zwHkxLfXn5=AK?D}{>=sl2M07ZHvTYIP*A|==qQJWhra~u)YKGKtCjirdCX?B9Cx`~ z0RIAh&n_-508pt^6c!c&;PrYj8jYAtCRSHhiI0zGWo3n(ogF+L4^dH3=xBL;Z*MOum5Rp3Mpjo>IX*td>2#t}sTdp_#B4Ux+1dFfV88zdlu9KL5fP-O zrVS`)0D}6Mbl$1nMQp49=rL?q^p`jrpNqU7vSYKa%T3lS@`udvi@bEABYaSmTmp3b< zr>B1_DJl6Iz+^Jp{kNy85}Sb4q9e0K@ViY5)KL literal 0 HcmV?d00001 diff --git a/extract_assets.py b/extract_assets.py index 1e31109..bc32572 100755 --- a/extract_assets.py +++ b/extract_assets.py @@ -10,9 +10,9 @@ def BuildOTR(xmlPath, rom, zapd_exe=None, genHeaders=None, customAssetsPath=None, customOtrFile=None, portVer=None): if not zapd_exe: - zapd_exe = "Debug\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out" + zapd_exe = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out" - exec_cmd = [zapd_exe, "ed", "-eh", "-i", xmlPath, "-b", rom, "-fl", "CFG/filelists", + exec_cmd = [zapd_exe, "ed", "-i", xmlPath, "-b", rom, "-fl", "CFG/filelists", "-o", "placeholder", "-osf", "placeholder", "-rconf", "CFG/Config.xml"] # generate headers, but not otrs by excluding the otr exporter @@ -21,8 +21,7 @@ def BuildOTR(xmlPath, rom, zapd_exe=None, genHeaders=None, customAssetsPath=None else: # generate otrs, but not headers exec_cmd.extend(["-gsf", "0", "-se", "OTR", "--customAssetsPath", customAssetsPath, - "--customOtrFile", customOtrFile, "--otrfile", - "oot-mq.otr" if Z64Rom.isMqRom(rom) else "mm.otr"]) + "--customOtrFile", customOtrFile, "--otrfile", "mm.otr"]) if portVer: exec_cmd.extend(["--portVer", portVer]) @@ -37,7 +36,7 @@ def BuildOTR(xmlPath, rom, zapd_exe=None, genHeaders=None, customAssetsPath=None def BuildCustomOtr(zapd_exe=None, assets_path=None, otrfile=None, portVer=None): if not zapd_exe: - zapd_exe = "Debug\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out" + zapd_exe = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out" if not assets_path or not otrfile: print("\n") @@ -79,13 +78,8 @@ def main(): roms = [ Z64Rom(args.rom) ] if args.rom else rom_chooser.chooseROM(args.verbose, args.non_interactive) for rom in roms: - if (not rom.isMMRom): - continue - - if (os.path.exists("Extract")): - shutil.rmtree("Extract") - - BuildOTR("../mm/assets/xml/", rom.file_path, zapd_exe=args.zapd_exe, genHeaders=args.gen_headers) + BuildOTR(os.path.join(args.xml_root, rom.version.xml_ver), rom.file_path, zapd_exe=args.zapd_exe, genHeaders=args.gen_headers, + customAssetsPath=args.custom_assets_path, customOtrFile=args.custom_otr_file, portVer=args.port_ver) if __name__ == "__main__": main() From 5c48f3411cd404c3ad1a945d7f7cd10d41cb5e4a Mon Sep 17 00:00:00 2001 From: Archez Date: Sun, 3 Mar 2024 21:16:58 -0500 Subject: [PATCH 34/55] remove xml version for mm (#13) --- rom_info.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rom_info.py b/rom_info.py index d532d1e..3ac0aca 100644 --- a/rom_info.py +++ b/rom_info.py @@ -46,8 +46,8 @@ def __init__(self, file_table_path, file_table_off, xml_ver, is_mm=False): ROM_INFO_TABLE[Checksums.OOT_PAL_10] = RomVersion("CFG/filelists/pal_oot.txt", 0x7950, "N64_PAL_10") ROM_INFO_TABLE[Checksums.OOT_PAL_11] = RomVersion("CFG/filelists/pal_oot.txt", 0x7950, "N64_PAL_11") -ROM_INFO_TABLE[Checksums.MM_US_10] = RomVersion("CFG/filelists/mm.txt", 0x1A500, "N64_PAL_11", is_mm=True) -ROM_INFO_TABLE[Checksums.MM_US_10_UNCOMPRESSED] = RomVersion("CFG/filelists/mm.txt", 0x1A500, "N64_PAL_11", is_mm=True) +ROM_INFO_TABLE[Checksums.MM_US_10] = RomVersion("CFG/filelists/mm.txt", 0x1A500, "", is_mm=True) +ROM_INFO_TABLE[Checksums.MM_US_10_UNCOMPRESSED] = RomVersion("CFG/filelists/mm.txt", 0x1A500, "", is_mm=True) class RomDmaEntry: def __init__(self, rom, i): From 257134050aa0caeab6a1957b3303d0b0b2cb25e3 Mon Sep 17 00:00:00 2001 From: Archez Date: Tue, 26 Mar 2024 23:22:05 -0400 Subject: [PATCH 35/55] handle segment addresses for other files in limb dlists (#14) --- OTRExporter/SkeletonLimbExporter.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/OTRExporter/SkeletonLimbExporter.cpp b/OTRExporter/SkeletonLimbExporter.cpp index 9534d8f..0e8b19c 100644 --- a/OTRExporter/SkeletonLimbExporter.cpp +++ b/OTRExporter/SkeletonLimbExporter.cpp @@ -134,7 +134,9 @@ void OTRExporter_SkeletonLimb::Save(ZResource* res, const fs::path& outPath, Bin if (name.at(0) == '&') name.erase(0, 1); - writer->Write(OTRExporter_DisplayList::GetPathToRes(limb, name)); + ZFile* assocFile = Globals::Instance->GetSegment(GETSEGNUM(limb->dListPtr), res->parent->workerID); + + writer->Write(OTRExporter_DisplayList::GetPathToRes(assocFile->resources[0], name)); } else { @@ -155,7 +157,9 @@ void OTRExporter_SkeletonLimb::Save(ZResource* res, const fs::path& outPath, Bin if (name.at(0) == '&') name.erase(0, 1); - writer->Write(OTRExporter_DisplayList::GetPathToRes(limb, name)); + ZFile* assocFile = Globals::Instance->GetSegment(GETSEGNUM(limb->dList2Ptr), res->parent->workerID); + + writer->Write(OTRExporter_DisplayList::GetPathToRes(assocFile->resources[0], name)); } else { @@ -173,4 +177,4 @@ void OTRExporter_SkeletonLimb::Save(ZResource* res, const fs::path& outPath, Bin writer->Write(limb->childIndex); writer->Write(limb->siblingIndex); -} \ No newline at end of file +} From e01065396f09eac96340b6cc7b72394cda0c4855 Mon Sep 17 00:00:00 2001 From: Archez Date: Tue, 26 Mar 2024 23:23:53 -0400 Subject: [PATCH 36/55] use custom opcode for non-zero DL segment offsets (#15) --- OTRExporter/DisplayListExporter.cpp | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index e6a8031..fc06e3d 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -413,12 +413,28 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina Gfx value; - u32 dListVal = (data & 0x0FFFFFFF) + 1; + u32 segNum = GETSEGNUM(data); + u32 segOffset = GETSEGOFFSET(data); + + // Use regular DL opcode for 0 offsets + if (segOffset == 0) { + u32 dListVal = (data & 0x0FFFFFFF) + 1; + + if (pp != 0) + value = {gsSPBranchList(dListVal)}; + else + value = {gsSPDisplayList(dListVal)}; + } else { + // Convert the offset value to an index value by diving by the original size for Gfx on hardware + // Adding 1 for seg addr flow will be handled on the renderer side + u32 dListVal = (segNum << 24) | (segOffset / (sizeof(u32) * 2)); + + if (pp != 0) + value = {gsSPBranchListIndex(dListVal)}; + else + value = {gsSPDisplayListIndex(dListVal)}; + } - if (pp != 0) - value = {gsSPBranchList(dListVal)}; - else - value = {gsSPDisplayList(dListVal)}; word0 = value.words.w0; word1 = value.words.w1; From 741fb6b9fc73423418bb8c7d0014c2bad88d614f Mon Sep 17 00:00:00 2001 From: Archez Date: Tue, 26 Mar 2024 23:28:16 -0400 Subject: [PATCH 37/55] handle null lists in animated texture color params (#16) --- OTRExporter/TextureAnimationExporter.cpp | 47 ++++++++++++++++-------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/OTRExporter/TextureAnimationExporter.cpp b/OTRExporter/TextureAnimationExporter.cpp index ba4376c..b5acf89 100644 --- a/OTRExporter/TextureAnimationExporter.cpp +++ b/OTRExporter/TextureAnimationExporter.cpp @@ -43,25 +43,40 @@ void OTRExporter_TextureAnimation::Save(ZResource* res, const fs::path& outPath, writer->Write(colorParams->animLength); writer->Write(colorParams->colorListCount); - writer->Write((uint32_t)colorParams->frameDataList.size()); - for (const auto f : colorParams->frameDataList) { - writer->Write(f); + if (colorParams->frameDataListAddress != 0) { // NULL + writer->Write((uint16_t)colorParams->frameDataList.size()); + for (const auto f : colorParams->frameDataList) { + writer->Write(f); + } + } else { + writer->Write((uint16_t)0); } - writer->Write((uint32_t)colorParams->primColorList.size()); - for (const auto prim : colorParams->primColorList) { - writer->Write(prim.r); - writer->Write(prim.g); - writer->Write(prim.b); - writer->Write(prim.a); - writer->Write(prim.lodFrac); + + if (colorParams->primColorListAddress != 0) { // NULL + writer->Write((uint16_t)colorParams->primColorList.size()); + for (const auto prim : colorParams->primColorList) { + writer->Write(prim.r); + writer->Write(prim.g); + writer->Write(prim.b); + writer->Write(prim.a); + writer->Write(prim.lodFrac); + } + } else { + writer->Write((uint16_t)0); } - writer->Write((uint16_t)colorParams->envColorList.size()); - for (const auto env : colorParams->envColorList) { - writer->Write(env.r); - writer->Write(env.g); - writer->Write(env.b); - writer->Write(env.a); + + if (colorParams->envColorListAddress != 0) { // NULL + writer->Write((uint16_t)colorParams->envColorList.size()); + for (const auto env : colorParams->envColorList) { + writer->Write(env.r); + writer->Write(env.g); + writer->Write(env.b); + writer->Write(env.a); + } + } else { + writer->Write((uint16_t)0); } + break; } case TextureAnimationParamsType::TextureCycle: { From 6182c0aedd28dc8f335c98c0ce9acd795a0fb90c Mon Sep 17 00:00:00 2001 From: inspectredc <78732756+inspectredc@users.noreply.github.com> Date: Fri, 26 Apr 2024 22:08:26 +0100 Subject: [PATCH 38/55] Fix Branching DisplayLists (#18) Co-authored by: Nicholas Estelami --- OTRExporter/DisplayListExporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index fc06e3d..b309fd0 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -344,7 +344,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina uint32_t z = (data & 0x00000000FFFFFFFF) >> 0; uint32_t h = (data & 0xFFFFFFFF); - auto data2 = dList->instructions[dataIdx - 1]; + auto data2 = dList->instructions[dataIdx + 1]; uint32_t dListPtr = GETSEGOFFSET(data2); Declaration* dListDecl = dList->parent->GetDeclaration(dListPtr); @@ -445,7 +445,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina if ((int)opF3D == G_BRANCH_Z) { - auto data2 = dList->instructions[dataIdx - 1]; + auto data2 = dList->instructions[dataIdx + 1]; dListPtr = GETSEGOFFSET(data2); } else From 6c8122f1b9296edf2428a186926eda39dc0c92c4 Mon Sep 17 00:00:00 2001 From: inspectredc <78732756+inspectredc@users.noreply.github.com> Date: Fri, 26 Apr 2024 22:44:06 +0100 Subject: [PATCH 39/55] GC US Support (#17) * gc support for mmcs-rebase * add gc file list --- CFG/Config.xml | 2 +- CFG/filelists/mm_gc.txt | 1549 +++++++++++++++++++++++++++++++++++++++ rom_info.py | 6 +- 3 files changed, 1554 insertions(+), 3 deletions(-) create mode 100644 CFG/filelists/mm_gc.txt diff --git a/CFG/Config.xml b/CFG/Config.xml index 867b5fa..1c845c1 100644 --- a/CFG/Config.xml +++ b/CFG/Config.xml @@ -3,6 +3,6 @@ - + diff --git a/CFG/filelists/mm_gc.txt b/CFG/filelists/mm_gc.txt new file mode 100644 index 0000000..45ca5e4 --- /dev/null +++ b/CFG/filelists/mm_gc.txt @@ -0,0 +1,1549 @@ +makerom +boot +dmadata +Audiobank +Audioseq +Audiotable +kanji +link_animetion +icon_item_static_syms +icon_item_24_static_syms +icon_item_field_static +icon_item_dungeon_static +icon_item_gameover_static +icon_item_jpn_static +icon_item_vtx_static +map_i_static +map_grand_static +item_name_static +map_name_static +icon_item_static_yar +icon_item_24_static_yar +schedule_dma_static_syms +schedule_dma_static_yar +schedule_static +story_static +do_action_static +message_static +message_texture_static +nes_font_static +message_data_static +staff_message_data_static +code +ovl_title +ovl_select +ovl_opening +ovl_file_choose +ovl_daytelop +ovl_kaleido_scope +ovl_player_actor +ovl_En_Test +ovl_En_GirlA +ovl_En_Part +ovl_En_Light +ovl_En_Door +ovl_En_Box +ovl_En_Pametfrog +ovl_En_Okuta +ovl_En_Bom +ovl_En_Wallmas +ovl_En_Dodongo +ovl_En_Firefly +ovl_En_Horse +ovl_En_Arrow +ovl_En_Elf +ovl_En_Niw +ovl_En_Tite +ovl_En_Peehat +ovl_En_Holl +ovl_En_Dinofos +ovl_En_Hata +ovl_En_Zl1 +ovl_En_Viewer +ovl_En_Bubble +ovl_Door_Shutter +ovl_En_Boom +ovl_En_Torch2 +ovl_En_Minifrog +ovl_En_St +ovl_Obj_Wturn +ovl_En_River_Sound +ovl_En_Ossan +ovl_En_Famos +ovl_En_Bombf +ovl_En_Am +ovl_En_Dekubaba +ovl_En_M_Fire1 +ovl_En_M_Thunder +ovl_Bg_Breakwall +ovl_Door_Warp1 +ovl_Obj_Syokudai +ovl_Item_B_Heart +ovl_En_Dekunuts +ovl_En_Bbfall +ovl_Arms_Hook +ovl_En_Bb +ovl_Bg_Keikoku_Spr +ovl_En_Wood02 +ovl_En_Death +ovl_En_Minideath +ovl_En_Vm +ovl_Demo_Effect +ovl_Demo_Kankyo +ovl_En_Floormas +ovl_En_Rd +ovl_Bg_F40_Flift +ovl_Obj_Mure +ovl_En_Sw +ovl_Object_Kankyo +ovl_En_Horse_Link_Child +ovl_Door_Ana +ovl_En_Encount1 +ovl_Demo_Tre_Lgt +ovl_En_Encount2 +ovl_En_Fire_Rock +ovl_Bg_Ctower_Rot +ovl_Mir_Ray +ovl_En_Sb +ovl_En_Bigslime +ovl_En_Karebaba +ovl_En_In +ovl_En_Bom_Chu +ovl_En_Horse_Game_Check +ovl_En_Rr +ovl_En_Fr +ovl_Obj_Oshihiki +ovl_Eff_Dust +ovl_Bg_Umajump +ovl_En_Insect +ovl_En_Butte +ovl_En_Fish +ovl_Item_Etcetera +ovl_Arrow_Fire +ovl_Arrow_Ice +ovl_Arrow_Light +ovl_Obj_Kibako +ovl_Obj_Tsubo +ovl_En_Ik +ovl_Demo_Shd +ovl_En_Dns +ovl_Elf_Msg +ovl_En_Honotrap +ovl_En_Tubo_Trap +ovl_Obj_Ice_Poly +ovl_En_Fz +ovl_En_Kusa +ovl_Obj_Bean +ovl_Obj_Bombiwa +ovl_Obj_Switch +ovl_Obj_Lift +ovl_Obj_Hsblock +ovl_En_Okarina_Tag +ovl_En_Goroiwa +ovl_En_Daiku +ovl_En_Nwc +ovl_Item_Inbox +ovl_En_Ge1 +ovl_Obj_Blockstop +ovl_En_Sda +ovl_En_Clear_Tag +ovl_En_Gm +ovl_En_Ms +ovl_En_Hs +ovl_Bg_Ingate +ovl_En_Kanban +ovl_En_Attack_Niw +ovl_En_Mk +ovl_En_Owl +ovl_En_Ishi +ovl_Obj_Hana +ovl_Obj_Lightswitch +ovl_Obj_Mure2 +ovl_En_Fu +ovl_En_Stream +ovl_En_Mm +ovl_En_Weather_Tag +ovl_En_Ani +ovl_En_Js +ovl_En_Okarina_Effect +ovl_En_Mag +ovl_Elf_Msg2 +ovl_Bg_F40_Swlift +ovl_En_Kakasi +ovl_Obj_Makeoshihiki +ovl_Oceff_Spot +ovl_En_Torch +ovl_Shot_Sun +ovl_Obj_Roomtimer +ovl_En_Ssh +ovl_Oceff_Wipe +ovl_Effect_Ss_Dust +ovl_Effect_Ss_Kirakira +ovl_Effect_Ss_Bomb2 +ovl_Effect_Ss_Blast +ovl_Effect_Ss_G_Spk +ovl_Effect_Ss_D_Fire +ovl_Effect_Ss_Bubble +ovl_Effect_Ss_G_Ripple +ovl_Effect_Ss_G_Splash +ovl_Effect_Ss_G_Fire +ovl_Effect_Ss_Lightning +ovl_Effect_Ss_Dt_Bubble +ovl_Effect_Ss_Hahen +ovl_Effect_Ss_Stick +ovl_Effect_Ss_Sibuki +ovl_Effect_Ss_Stone1 +ovl_Effect_Ss_Hitmark +ovl_Effect_Ss_Fhg_Flash +ovl_Effect_Ss_K_Fire +ovl_Effect_Ss_Solder_Srch_Ball +ovl_Effect_Ss_Kakera +ovl_Effect_Ss_Ice_Piece +ovl_Effect_Ss_En_Ice +ovl_Effect_Ss_Fire_Tail +ovl_Effect_Ss_En_Fire +ovl_Effect_Ss_Extra +ovl_Effect_Ss_Dead_Db +ovl_Effect_Ss_Dead_Dd +ovl_Effect_Ss_Dead_Ds +ovl_Oceff_Storm +ovl_Obj_Demo +ovl_En_Minislime +ovl_En_Nutsball +ovl_Oceff_Wipe2 +ovl_Oceff_Wipe3 +ovl_En_Dg +ovl_En_Si +ovl_Obj_Comb +ovl_Obj_Kibako2 +ovl_En_Hs2 +ovl_Obj_Mure3 +ovl_En_Tg +ovl_En_Wf +ovl_En_Skb +ovl_En_Gs +ovl_Obj_Sound +ovl_En_Crow +ovl_En_Cow +ovl_Oceff_Wipe4 +ovl_En_Zo +ovl_Effect_Ss_Ice_Smoke +ovl_Obj_Makekinsuta +ovl_En_Ge3 +ovl_Obj_Hamishi +ovl_En_Zl4 +ovl_En_Mm2 +ovl_Door_Spiral +ovl_Obj_Pzlblock +ovl_Obj_Toge +ovl_Obj_Armos +ovl_Obj_Boyo +ovl_En_Grasshopper +ovl_Obj_Grass +ovl_Obj_Grass_Carry +ovl_Obj_Grass_Unit +ovl_Bg_Fire_Wall +ovl_En_Bu +ovl_En_Encount3 +ovl_En_Jso +ovl_Obj_Chikuwa +ovl_En_Knight +ovl_En_Warp_tag +ovl_En_Aob_01 +ovl_En_Boj_01 +ovl_En_Boj_02 +ovl_En_Boj_03 +ovl_En_Encount4 +ovl_En_Bom_Bowl_Man +ovl_En_Syateki_Man +ovl_Bg_Icicle +ovl_En_Syateki_Crow +ovl_En_Boj_04 +ovl_En_Cne_01 +ovl_En_Bba_01 +ovl_En_Bji_01 +ovl_Bg_Spdweb +ovl_En_Mt_tag +ovl_Boss_01 +ovl_Boss_02 +ovl_Boss_03 +ovl_Boss_04 +ovl_Boss_05 +ovl_Boss_06 +ovl_Boss_07 +ovl_Bg_Dy_Yoseizo +ovl_En_Boj_05 +ovl_En_Sob1 +ovl_En_Go +ovl_En_Raf +ovl_Obj_Funen +ovl_Obj_Raillift +ovl_Bg_Numa_Hana +ovl_Obj_Flowerpot +ovl_Obj_Spinyroll +ovl_Dm_Hina +ovl_En_Syateki_Wf +ovl_Obj_Skateblock +ovl_Effect_En_Ice_Block +ovl_Obj_Iceblock +ovl_En_Bigpamet +ovl_Bg_Dblue_Movebg +ovl_En_Syateki_Dekunuts +ovl_Elf_Msg3 +ovl_En_Fg +ovl_Dm_Ravine +ovl_Dm_Sa +ovl_En_Slime +ovl_En_Pr +ovl_Obj_Toudai +ovl_Obj_Entotu +ovl_Obj_Bell +ovl_En_Syateki_Okuta +ovl_Obj_Shutter +ovl_Dm_Zl +ovl_En_Ru +ovl_En_Elfgrp +ovl_Dm_Tsg +ovl_En_Baguo +ovl_Obj_Vspinyroll +ovl_Obj_Smork +ovl_En_Test2 +ovl_En_Test3 +ovl_En_Test4 +ovl_En_Bat +ovl_En_Sekihi +ovl_En_Wiz +ovl_En_Wiz_Brock +ovl_En_Wiz_Fire +ovl_Eff_Change +ovl_Dm_Statue +ovl_Obj_Fireshield +ovl_Bg_Ladder +ovl_En_Mkk +ovl_Demo_Getitem +ovl_En_Dnb +ovl_En_Dnh +ovl_En_Dnk +ovl_En_Dnq +ovl_Bg_Keikoku_Saku +ovl_Obj_Hugebombiwa +ovl_En_Firefly2 +ovl_En_Rat +ovl_En_Water_Effect +ovl_En_Kusa2 +ovl_Bg_Spout_Fire +ovl_En_Dy_Extra +ovl_En_Bal +ovl_En_Ginko_Man +ovl_En_Warp_Uzu +ovl_Obj_Driftice +ovl_En_Look_Nuts +ovl_En_Mushi2 +ovl_En_Fall +ovl_En_Mm3 +ovl_Bg_Crace_Movebg +ovl_En_Dno +ovl_En_Pr2 +ovl_En_Prz +ovl_En_Jso2 +ovl_Obj_Etcetera +ovl_En_Egol +ovl_Obj_Mine +ovl_Obj_Purify +ovl_En_Tru +ovl_En_Trt +ovl_En_Test5 +ovl_En_Test6 +ovl_En_Az +ovl_En_Estone +ovl_Bg_Hakugin_Post +ovl_Dm_Opstage +ovl_Dm_Stk +ovl_Dm_Char00 +ovl_Dm_Char01 +ovl_Dm_Char02 +ovl_Dm_Char03 +ovl_Dm_Char04 +ovl_Dm_Char05 +ovl_Dm_Char06 +ovl_Dm_Char07 +ovl_Dm_Char08 +ovl_Dm_Char09 +ovl_Obj_Tokeidai +ovl_En_Mnk +ovl_En_Egblock +ovl_En_Guard_Nuts +ovl_Bg_Hakugin_Bombwall +ovl_Obj_Tokei_Tobira +ovl_Bg_Hakugin_Elvpole +ovl_En_Ma4 +ovl_En_Twig +ovl_En_Po_Fusen +ovl_En_Door_Etc +ovl_En_Bigokuta +ovl_Bg_Icefloe +ovl_fbdemo_triforce +ovl_fbdemo_wipe1 +ovl_fbdemo_wipe3 +ovl_fbdemo_wipe4 +ovl_fbdemo_wipe5 +ovl_Effect_Ss_Sbn +ovl_Obj_Ocarinalift +ovl_En_Time_Tag +ovl_Bg_Open_Shutter +ovl_Bg_Open_Spot +ovl_Bg_Fu_Kaiten +ovl_Obj_Aqua +ovl_En_Elforg +ovl_En_Elfbub +ovl_En_Fu_Mato +ovl_En_Fu_Kago +ovl_En_Osn +ovl_Bg_Ctower_Gear +ovl_En_Trt2 +ovl_Obj_Tokei_Step +ovl_Bg_Lotus +ovl_En_Kame +ovl_Obj_Takaraya_Wall +ovl_Bg_Fu_Mizu +ovl_En_Sellnuts +ovl_Bg_Dkjail_Ivy +ovl_Obj_Visiblock +ovl_En_Takaraya +ovl_En_Tsn +ovl_En_Ds2n +ovl_En_Fsn +ovl_En_Shn +ovl_En_Stop_heishi +ovl_Obj_Bigicicle +ovl_En_Lift_Nuts +ovl_En_Tk +ovl_Bg_Market_Step +ovl_Obj_Lupygamelift +ovl_En_Test7 +ovl_Obj_Lightblock +ovl_Mir_Ray2 +ovl_En_Wdhand +ovl_En_Gamelupy +ovl_Bg_Danpei_Movebg +ovl_En_Snowwd +ovl_En_Pm +ovl_En_Gakufu +ovl_Elf_Msg4 +ovl_Elf_Msg5 +ovl_En_Col_Man +ovl_En_Talk_Gibud +ovl_En_Giant +ovl_Obj_Snowball +ovl_Boss_Hakugin +ovl_En_Gb2 +ovl_En_Onpuman +ovl_Bg_Tobira01 +ovl_En_Tag_Obj +ovl_Obj_Dhouse +ovl_Obj_Hakaisi +ovl_Bg_Hakugin_Switch +ovl_En_Snowman +ovl_TG_Sw +ovl_En_Po_Sisters +ovl_En_Pp +ovl_En_Hakurock +ovl_En_Hanabi +ovl_Obj_Dowsing +ovl_Obj_Wind +ovl_En_Racedog +ovl_En_Kendo_Js +ovl_Bg_Botihasira +ovl_En_Fish2 +ovl_En_Pst +ovl_En_Poh +ovl_Obj_Spidertent +ovl_En_Zoraegg +ovl_En_Kbt +ovl_En_Gg +ovl_En_Maruta +ovl_Obj_Snowball2 +ovl_En_Gg2 +ovl_Obj_Ghaka +ovl_En_Dnp +ovl_En_Dai +ovl_Bg_Goron_Oyu +ovl_En_Kgy +ovl_En_Invadepoh +ovl_En_Gk +ovl_En_An +ovl_En_Bee +ovl_En_Ot +ovl_En_Dragon +ovl_Obj_Dora +ovl_En_Bigpo +ovl_Obj_Kendo_Kanban +ovl_Obj_Hariko +ovl_En_Sth +ovl_Bg_Sinkai_Kabe +ovl_Bg_Haka_Curtain +ovl_Bg_Kin2_Bombwall +ovl_Bg_Kin2_Fence +ovl_Bg_Kin2_Picture +ovl_Bg_Kin2_Shelf +ovl_En_Rail_Skb +ovl_En_Jg +ovl_En_Tru_Mt +ovl_Obj_Um +ovl_En_Neo_Reeba +ovl_Bg_Mbar_Chair +ovl_Bg_Ikana_Block +ovl_Bg_Ikana_Mirror +ovl_Bg_Ikana_Rotaryroom +ovl_Bg_Dblue_Balance +ovl_Bg_Dblue_Waterfall +ovl_En_Kaizoku +ovl_En_Ge2 +ovl_En_Ma_Yts +ovl_En_Ma_Yto +ovl_Obj_Tokei_Turret +ovl_Bg_Dblue_Elevator +ovl_Obj_Warpstone +ovl_En_Zog +ovl_Obj_Rotlift +ovl_Obj_Jg_Gakki +ovl_Bg_Inibs_Movebg +ovl_En_Zot +ovl_Obj_Tree +ovl_Obj_Y2lift +ovl_Obj_Y2shutter +ovl_Obj_Boat +ovl_Obj_Taru +ovl_Obj_Hunsui +ovl_En_Jc_Mato +ovl_Mir_Ray3 +ovl_En_Zob +ovl_Elf_Msg6 +ovl_Obj_Nozoki +ovl_En_Toto +ovl_En_Railgibud +ovl_En_Baba +ovl_En_Suttari +ovl_En_Zod +ovl_En_Kujiya +ovl_En_Geg +ovl_Obj_Kinoko +ovl_Obj_Yasi +ovl_En_Tanron1 +ovl_En_Tanron2 +ovl_En_Tanron3 +ovl_Obj_Chan +ovl_En_Zos +ovl_En_S_Goro +ovl_En_Nb +ovl_En_Ja +ovl_Bg_F40_Block +ovl_Bg_F40_Switch +ovl_En_Po_Composer +ovl_En_Guruguru +ovl_Oceff_Wipe5 +ovl_En_Stone_heishi +ovl_Oceff_Wipe6 +ovl_En_Scopenuts +ovl_En_Scopecrow +ovl_Oceff_Wipe7 +ovl_Eff_Kamejima_Wave +ovl_En_Hg +ovl_En_Hgo +ovl_En_Zov +ovl_En_Ah +ovl_Obj_Hgdoor +ovl_Bg_Ikana_Bombwall +ovl_Bg_Ikana_Ray +ovl_Bg_Ikana_Shutter +ovl_Bg_Haka_Bombwall +ovl_Bg_Haka_Tomb +ovl_En_Sc_Ruppe +ovl_Bg_Iknv_Doukutu +ovl_Bg_Iknv_Obj +ovl_En_Pamera +ovl_Obj_HsStump +ovl_En_Hidden_Nuts +ovl_En_Zow +ovl_En_Talk +ovl_En_Al +ovl_En_Tab +ovl_En_Nimotsu +ovl_En_Hit_Tag +ovl_En_Ruppecrow +ovl_En_Tanron4 +ovl_En_Tanron5 +ovl_En_Tanron6 +ovl_En_Daiku2 +ovl_En_Muto +ovl_En_Baisen +ovl_En_Heishi +ovl_En_Demo_heishi +ovl_En_Dt +ovl_En_Cha +ovl_Obj_Dinner +ovl_Eff_Lastday +ovl_Bg_Ikana_Dharma +ovl_En_Akindonuts +ovl_Eff_Stk +ovl_En_Ig +ovl_En_Rg +ovl_En_Osk +ovl_En_Sth2 +ovl_En_Yb +ovl_En_Rz +ovl_En_Scopecoin +ovl_En_Bjt +ovl_En_Bomjima +ovl_En_Bomjimb +ovl_En_Bombers +ovl_En_Bombers2 +ovl_En_Bombal +ovl_Obj_Moon_Stone +ovl_Obj_Mu_Pict +ovl_Bg_Ikninside +ovl_Eff_Zoraband +ovl_Obj_Kepn_Koya +ovl_Obj_Usiyane +ovl_En_Nnh +ovl_Obj_Kzsaku +ovl_Obj_Milk_Bin +ovl_En_Kitan +ovl_Bg_Astr_Bombwall +ovl_Bg_Iknin_Susceil +ovl_En_Bsb +ovl_En_Recepgirl +ovl_En_Thiefbird +ovl_En_Jgame_Tsn +ovl_Obj_Jgame_Light +ovl_Obj_Yado +ovl_Demo_Syoten +ovl_Demo_Moonend +ovl_Bg_Lbfshot +ovl_Bg_Last_Bwall +ovl_En_And +ovl_En_Invadepoh_Demo +ovl_Obj_Danpeilift +ovl_En_Fall2 +ovl_Dm_Al +ovl_Dm_An +ovl_Dm_Ah +ovl_Dm_Nb +ovl_En_Drs +ovl_En_Ending_Hero +ovl_Dm_Bal +ovl_En_Paper +ovl_En_Hint_Skb +ovl_Dm_Tag +ovl_En_Bh +ovl_En_Ending_Hero2 +ovl_En_Ending_Hero3 +ovl_En_Ending_Hero4 +ovl_En_Ending_Hero5 +ovl_En_Ending_Hero6 +ovl_Dm_Gm +ovl_Obj_Swprize +ovl_En_Invisible_Ruppe +ovl_Obj_Ending +ovl_En_Rsn +gameplay_keep +gameplay_field_keep +gameplay_dangeon_keep +gameplay_object_exchange_static +object_link_boy +object_link_child +object_link_goron +object_link_zora +object_link_nuts +object_mask_ki_tan +object_mask_rabit +object_mask_skj +object_mask_truth +object_mask_gibudo +object_mask_json +object_mask_kerfay +object_mask_bigelf +object_mask_kyojin +object_mask_romerny +object_mask_posthat +object_mask_zacho +object_mask_stone +object_mask_bree +object_mask_gero +object_mask_yofukasi +object_mask_meoto +object_mask_dancer +object_mask_bakuretu +object_mask_bu_san +object_mask_goron +object_mask_zora +object_mask_nuts +object_mask_boy +object_box +object_okuta +object_wallmaster +object_dy_obj +object_firefly +object_dodongo +object_niw +object_tite +object_ph +object_dinofos +object_zl1 +object_bubble +object_test3 +object_famos +object_st +object_thiefbird +object_bombf +object_am +object_dekubaba +object_warp1 +object_b_heart +object_dekunuts +object_bb +object_death +object_hata +object_wood02 +object_trap +object_vm +object_efc_star_field +object_rd +object_yukimura_obj +object_horse_link_child +object_syokudai +object_efc_tw +object_gi_key +object_mir_ray +object_ctower_rot +object_bdoor +object_sb +object_gi_melody +object_gi_heart +object_gi_compass +object_gi_bosskey +object_gi_nuts +object_gi_hearts +object_gi_arrowcase +object_gi_bombpouch +object_in +object_os_anime +object_gi_bottle +object_gi_stick +object_gi_map +object_oF1d_map +object_ru2 +object_gi_magicpot +object_gi_bomb_1 +object_ma2 +object_gi_purse +object_rr +object_gi_arrow +object_gi_bomb_2 +object_gi_shield_2 +object_gi_hookshot +object_gi_ocarina +object_gi_milk +object_ma1 +object_ny +object_fr +object_gi_bow +object_gi_glasses +object_gi_liquid +object_ani +object_gi_shield_3 +object_gi_bean +object_gi_fish +object_gi_longsword +object_zo +object_umajump +object_mastergolon +object_masterzoora +object_aob +object_ik +object_ahg +object_cne +object_bji +object_bba +object_an1 +object_boj +object_fz +object_bob +object_ge1 +object_yabusame_point +object_d_hsblock +object_d_lift +object_mamenoki +object_goroiwa +object_toryo +object_daiku +object_nwc +object_gm +object_ms +object_hs +object_lightswitch +object_kusa +object_tsubo +object_kanban +object_owl +object_mk +object_fu +object_gi_ki_tan_mask +object_gi_mask18 +object_gi_rabit_mask +object_gi_truth_mask +object_stream +object_mm +object_js +object_cs +object_gi_soldout +object_mag +object_gi_golonmask +object_gi_zoramask +object_ka +object_zg +object_gi_m_arrow +object_ds2 +object_fish +object_gi_sutaru +object_ssh +object_bigslime +object_bg +object_bombiwa +object_hintnuts +object_rs +object_gla +object_geldb +object_dog +object_kibako2 +object_dns +object_dnk +object_gi_insect +object_gi_ghost +object_gi_soul +object_f40_obj +object_gi_rupy +object_po_composer +object_mu +object_wf +object_skb +object_gs +object_ps +object_omoya_obj +object_crow +object_cow +object_gi_sword_1 +object_zl4 +object_grasshopper +object_boyo +object_fwall +object_jso +object_knight +object_icicle +object_spdweb +object_boss01 +object_boss02 +object_boss03 +object_boss04 +object_boss05 +object_boss07 +object_raf +object_funen +object_raillift +object_numa_obj +object_flowerpot +object_spinyroll +object_ice_block +object_keikoku_demo +object_slime +object_pr +object_f52_obj +object_f53_obj +object_kibako +object_sek +object_gmo +object_bat +object_sekihil +object_sekihig +object_sekihin +object_sekihiz +object_wiz +object_ladder +object_mkk +object_keikoku_obj +object_sichitai_obj +object_dekucity_ana_obj +object_rat +object_water_effect +object_dblue_object +object_bal +object_warp_uzu +object_driftice +object_fall +object_hanareyama_obj +object_crace_object +object_dno +object_obj_tokeidai +object_eg +object_tru +object_trt +object_hakugin_obj +object_horse_game_check +object_stk +object_mnk +object_gi_bottle_red +object_tokei_tobira +object_az +object_twig +object_dekucity_obj +object_po_fusen +object_racetsubo +object_ha +object_bigokuta +object_open_obj +object_fu_kaiten +object_fu_mato +object_mtoride +object_osn +object_tokei_step +object_lotus +object_tl +object_dkjail_obj +object_visiblock +object_tsn +object_ds2n +object_fsn +object_shn +object_bigicicle +object_gi_bottle_15 +object_tk +object_market_obj +object_gi_reserve00 +object_gi_reserve01 +object_lightblock +object_takaraya_objects +object_wdhand +object_sdn +object_snowwd +object_giant +object_comb +object_hana +object_boss_hakugin +object_meganeana_obj +object_gi_nutsmask +object_stk2 +object_spot11_obj +object_danpei_object +object_dhouse +object_hakaisi +object_po +object_snowman +object_po_sisters +object_pp +object_goronswitch +object_delf +object_botihasira +object_gi_bigbomb +object_pst +object_bsmask +object_spidertent +object_zoraegg +object_kbt +object_gg +object_maruta +object_ghaka +object_oyu +object_dnq +object_dai +object_kgy +object_fb +object_taisou +object_gk +object_haka_obj +object_dnt +object_yukiyama +object_icefloe +object_gi_gold_dust +object_gi_bottle_16 +object_gi_bottle_22 +object_bee +object_ot +object_utubo +object_dora +object_gi_loach +object_gi_seahorse +object_bigpo +object_hariko +object_dnj +object_sinkai_kabe +object_kin2_obj +object_ishi +object_hakugin_demo +object_jg +object_gi_sword_2 +object_gi_sword_3 +object_gi_sword_4 +object_um +object_rb +object_mbar_obj +object_ikana_obj +object_kz +object_tokei_turret +object_zog +object_rotlift +object_posthouse_obj +object_gi_mask09 +object_gi_mask14 +object_gi_mask15 +object_inibs_object +object_tree +object_kaizoku_obj +object_gi_reserve_b_00 +object_gi_reserve_c_00 +object_zob +object_milkbar +object_dmask +object_gi_reserve_c_01 +object_zod +object_kumo30 +object_obj_yasi +object_tanron1 +object_tanron2 +object_tanron3 +object_gi_magicmushroom +object_obj_chan +object_gi_mask10 +object_zos +object_an2 +object_an3 +object_f40_switch +object_lodmoon +object_tro +object_gi_mask12 +object_gi_mask23 +object_gi_bottle_21 +object_gi_camera +object_kamejima +object_nb +object_harfgibud +object_zov +object_ah +object_hgdoor +object_dor01 +object_dor02 +object_dor03 +object_dor04 +object_last_obj +object_redead_obj +object_ikninside_obj +object_iknv_obj +object_pamera +object_hsstump +object_zm +object_al +object_tab +object_secom_obj +object_dt +object_gi_mask03 +object_cha +object_obj_dinner +object_gi_reserve_b_01 +object_lastday +object_bai +object_ikn_demo +object_gi_fieldmap +object_big_fwall +object_hunsui +object_uch +object_tanron4 +object_tanron5 +object_in2 +object_yb +object_rz +object_bjt +object_taru +object_moonston +object_gi_schedule +object_gi_stonemask +object_zoraband +object_kepn_koya +object_obj_usiyane +object_gi_mask05 +object_gi_mask11 +object_gi_mask20 +object_nnh +object_kzsaku +object_obj_milk_bin +object_random_obj +object_kujiya +object_kitan +object_gi_mask06 +object_gi_mask16 +object_astr_obj +object_bsb +object_fall2 +object_sth +object_gi_mssa +object_smtower +object_gi_mask21 +object_yado_obj +object_syoten +object_moonend +object_ob +object_gi_bottle_04 +object_and +object_obj_danpeilift +object_drs +object_msmo +object_an4 +object_wdor01 +object_wdor02 +object_wdor03 +object_wdor04 +object_wdor05 +object_stk3 +object_kinsta1_obj +object_kinsta2_obj +object_bh +object_gi_mask17 +object_gi_mask22 +object_lbfshot +object_fusen +object_ending_obj +object_gi_mask13 +scene_texture_01 +scene_texture_02 +scene_texture_03 +scene_texture_04 +scene_texture_05 +scene_texture_06 +scene_texture_07 +scene_texture_08 +nintendo_rogo_static +title_static +parameter_static +week_static +daytelop_static +ger_daytelop_static +fra_daytelop_static +esp_daytelop_static +d2_fine_static +d2_cloud_static +d2_fine_pal_static +elf_message_field +elf_message_ydan +Z2_20SICHITAI2 +Z2_20SICHITAI2_room_00 +Z2_20SICHITAI2_room_01 +Z2_20SICHITAI2_room_02 +Z2_WITCH_SHOP +Z2_WITCH_SHOP_room_00 +Z2_LAST_BS +Z2_LAST_BS_room_00 +Z2_HAKASHITA +Z2_HAKASHITA_room_00 +Z2_HAKASHITA_room_01 +Z2_HAKASHITA_room_02 +Z2_HAKASHITA_room_03 +Z2_HAKASHITA_room_04 +Z2_AYASHIISHOP +Z2_AYASHIISHOP_room_00 +Z2_AYASHIISHOP_room_01 +Z2_OMOYA +Z2_OMOYA_room_00 +Z2_OMOYA_room_01 +Z2_OMOYA_room_02 +Z2_BOWLING +Z2_BOWLING_room_00 +Z2_SONCHONOIE +Z2_SONCHONOIE_room_00 +Z2_SONCHONOIE_room_01 +Z2_SONCHONOIE_room_02 +Z2_SONCHONOIE_room_03 +Z2_IKANA +Z2_IKANA_room_00 +Z2_IKANA_room_01 +Z2_IKANA_room_02 +Z2_IKANA_room_03 +Z2_IKANA_room_04 +Z2_KAIZOKU +Z2_KAIZOKU_room_00 +Z2_MILK_BAR +Z2_MILK_BAR_room_00 +Z2_INISIE_N +Z2_INISIE_N_room_00 +Z2_INISIE_N_room_01 +Z2_INISIE_N_room_02 +Z2_INISIE_N_room_03 +Z2_INISIE_N_room_04 +Z2_INISIE_N_room_05 +Z2_INISIE_N_room_06 +Z2_INISIE_N_room_07 +Z2_INISIE_N_room_08 +Z2_INISIE_N_room_09 +Z2_INISIE_N_room_10 +Z2_INISIE_N_room_11 +Z2_TAKARAYA +Z2_TAKARAYA_room_00 +Z2_INISIE_R +Z2_INISIE_R_room_00 +Z2_INISIE_R_room_01 +Z2_INISIE_R_room_02 +Z2_INISIE_R_room_03 +Z2_INISIE_R_room_04 +Z2_INISIE_R_room_05 +Z2_INISIE_R_room_06 +Z2_INISIE_R_room_07 +Z2_INISIE_R_room_08 +Z2_INISIE_R_room_09 +Z2_INISIE_R_room_10 +Z2_INISIE_R_room_11 +Z2_OKUJOU +Z2_OKUJOU_room_00 +Z2_OPENINGDAN +Z2_OPENINGDAN_room_00 +Z2_OPENINGDAN_room_01 +Z2_MITURIN +Z2_MITURIN_room_00 +Z2_MITURIN_room_01 +Z2_MITURIN_room_02 +Z2_MITURIN_room_03 +Z2_MITURIN_room_04 +Z2_MITURIN_room_05 +Z2_MITURIN_room_06 +Z2_MITURIN_room_07 +Z2_MITURIN_room_08 +Z2_MITURIN_room_09 +Z2_MITURIN_room_10 +Z2_MITURIN_room_11 +Z2_MITURIN_room_12 +Z2_13HUBUKINOMITI +Z2_13HUBUKINOMITI_room_00 +Z2_CASTLE +Z2_CASTLE_room_00 +Z2_CASTLE_room_01 +Z2_CASTLE_room_02 +Z2_CASTLE_room_03 +Z2_CASTLE_room_04 +Z2_CASTLE_room_05 +Z2_CASTLE_room_06 +Z2_CASTLE_room_07 +Z2_CASTLE_room_08 +Z2_CASTLE_room_09 +Z2_DEKUTES +Z2_DEKUTES_room_00 +Z2_MITURIN_BS +Z2_MITURIN_BS_room_00 +Z2_SYATEKI_MIZU +Z2_SYATEKI_MIZU_room_00 +Z2_HAKUGIN +Z2_HAKUGIN_room_00 +Z2_HAKUGIN_room_01 +Z2_HAKUGIN_room_02 +Z2_HAKUGIN_room_03 +Z2_HAKUGIN_room_04 +Z2_HAKUGIN_room_05 +Z2_HAKUGIN_room_06 +Z2_HAKUGIN_room_07 +Z2_HAKUGIN_room_08 +Z2_HAKUGIN_room_09 +Z2_HAKUGIN_room_10 +Z2_HAKUGIN_room_11 +Z2_HAKUGIN_room_12 +Z2_HAKUGIN_room_13 +Z2_ROMANYMAE +Z2_ROMANYMAE_room_00 +Z2_PIRATE +Z2_PIRATE_room_00 +Z2_PIRATE_room_01 +Z2_PIRATE_room_02 +Z2_PIRATE_room_03 +Z2_PIRATE_room_04 +Z2_PIRATE_room_05 +Z2_PIRATE_room_06 +Z2_PIRATE_room_07 +Z2_PIRATE_room_08 +Z2_PIRATE_room_09 +Z2_PIRATE_room_10 +Z2_PIRATE_room_11 +Z2_PIRATE_room_12 +Z2_PIRATE_room_13 +Z2_PIRATE_room_14 +Z2_SYATEKI_MORI +Z2_SYATEKI_MORI_room_00 +Z2_SINKAI +Z2_SINKAI_room_00 +Z2_YOUSEI_IZUMI +Z2_YOUSEI_IZUMI_room_00 +Z2_YOUSEI_IZUMI_room_01 +Z2_YOUSEI_IZUMI_room_02 +Z2_YOUSEI_IZUMI_room_03 +Z2_YOUSEI_IZUMI_room_04 +Z2_KINSTA1 +Z2_KINSTA1_room_00 +Z2_KINSTA1_room_01 +Z2_KINSTA1_room_02 +Z2_KINSTA1_room_03 +Z2_KINSTA1_room_04 +Z2_KINSTA1_room_05 +Z2_KINDAN2 +Z2_KINDAN2_room_00 +Z2_KINDAN2_room_01 +Z2_KINDAN2_room_02 +Z2_KINDAN2_room_03 +Z2_KINDAN2_room_04 +Z2_KINDAN2_room_05 +Z2_TENMON_DAI +Z2_TENMON_DAI_room_00 +Z2_TENMON_DAI_room_01 +Z2_LAST_DEKU +Z2_LAST_DEKU_room_00 +Z2_LAST_DEKU_room_01 +Z2_22DEKUCITY +Z2_22DEKUCITY_room_00 +Z2_22DEKUCITY_room_01 +Z2_22DEKUCITY_room_02 +Z2_KAJIYA +Z2_KAJIYA_room_00 +Z2_00KEIKOKU +Z2_00KEIKOKU_room_00 +Z2_POSTHOUSE +Z2_POSTHOUSE_room_00 +Z2_LABO +Z2_LABO_room_00 +Z2_DANPEI2TEST +Z2_DANPEI2TEST_room_00 +Z2_DANPEI2TEST_room_01 +Z2_16GORON_HOUSE +Z2_16GORON_HOUSE_room_00 +Z2_16GORON_HOUSE_room_01 +Z2_33ZORACITY +Z2_33ZORACITY_room_00 +Z2_8ITEMSHOP +Z2_8ITEMSHOP_room_00 +Z2_F01 +Z2_F01_room_00 +Z2_INISIE_BS +Z2_INISIE_BS_room_00 +Z2_30GYOSON +Z2_30GYOSON_room_00 +Z2_31MISAKI +Z2_31MISAKI_room_00 +Z2_TAKARAKUJI +Z2_TAKARAKUJI_room_00 +Z2_TORIDE +Z2_TORIDE_room_00 +Z2_FISHERMAN +Z2_FISHERMAN_room_00 +Z2_GORONSHOP +Z2_GORONSHOP_room_00 +Z2_DEKU_KING +Z2_DEKU_KING_room_00 +Z2_LAST_GORON +Z2_LAST_GORON_room_00 +Z2_LAST_GORON_room_01 +Z2_24KEMONOMITI +Z2_24KEMONOMITI_room_00 +Z2_F01_B +Z2_F01_B_room_00 +Z2_F01C +Z2_F01C_room_00 +Z2_BOTI +Z2_BOTI_room_00 +Z2_BOTI_room_01 +Z2_HAKUGIN_BS +Z2_HAKUGIN_BS_room_00 +Z2_20SICHITAI +Z2_20SICHITAI_room_00 +Z2_20SICHITAI_room_01 +Z2_20SICHITAI_room_02 +Z2_21MITURINMAE +Z2_21MITURINMAE_room_00 +Z2_LAST_ZORA +Z2_LAST_ZORA_room_00 +Z2_11GORONNOSATO2 +Z2_11GORONNOSATO2_room_00 +Z2_11GORONNOSATO2_room_01 +Z2_SEA +Z2_SEA_room_00 +Z2_SEA_room_01 +Z2_SEA_room_02 +Z2_SEA_room_03 +Z2_SEA_room_04 +Z2_SEA_room_05 +Z2_SEA_room_06 +Z2_SEA_room_07 +Z2_SEA_room_08 +Z2_SEA_room_09 +Z2_SEA_room_10 +Z2_SEA_room_11 +Z2_SEA_room_12 +Z2_SEA_room_13 +Z2_SEA_room_14 +Z2_SEA_room_15 +Z2_35TAKI +Z2_35TAKI_room_00 +Z2_REDEAD +Z2_REDEAD_room_00 +Z2_REDEAD_room_01 +Z2_REDEAD_room_02 +Z2_REDEAD_room_03 +Z2_REDEAD_room_04 +Z2_REDEAD_room_05 +Z2_REDEAD_room_06 +Z2_REDEAD_room_07 +Z2_REDEAD_room_08 +Z2_REDEAD_room_09 +Z2_REDEAD_room_10 +Z2_REDEAD_room_11 +Z2_REDEAD_room_12 +Z2_REDEAD_room_13 +Z2_BANDROOM +Z2_BANDROOM_room_00 +Z2_BANDROOM_room_01 +Z2_BANDROOM_room_02 +Z2_BANDROOM_room_03 +Z2_BANDROOM_room_04 +Z2_11GORONNOSATO +Z2_11GORONNOSATO_room_00 +Z2_11GORONNOSATO_room_01 +Z2_GORON_HAKA +Z2_GORON_HAKA_room_00 +Z2_SECOM +Z2_SECOM_room_00 +Z2_SECOM_room_01 +Z2_10YUKIYAMANOMURA +Z2_10YUKIYAMANOMURA_room_00 +Z2_TOUGITES +Z2_TOUGITES_room_00 +Z2_DANPEI +Z2_DANPEI_room_00 +Z2_DANPEI_room_01 +Z2_DANPEI_room_02 +Z2_DANPEI_room_03 +Z2_DANPEI_room_04 +Z2_DANPEI_room_05 +Z2_DANPEI_room_06 +Z2_DANPEI_room_07 +Z2_DANPEI_room_08 +Z2_IKANAMAE +Z2_IKANAMAE_room_00 +Z2_DOUJOU +Z2_DOUJOU_room_00 +Z2_MUSICHOUSE +Z2_MUSICHOUSE_room_00 +Z2_IKNINSIDE +Z2_IKNINSIDE_room_00 +Z2_IKNINSIDE_room_01 +Z2_MAP_SHOP +Z2_MAP_SHOP_room_00 +Z2_F40 +Z2_F40_room_00 +Z2_F41 +Z2_F41_room_00 +Z2_10YUKIYAMANOMURA2 +Z2_10YUKIYAMANOMURA2_room_00 +Z2_10YUKIYAMANOMURA2_room_01 +Z2_14YUKIDAMANOMITI +Z2_14YUKIDAMANOMITI_room_00 +Z2_12HAKUGINMAE +Z2_12HAKUGINMAE_room_00 +Z2_17SETUGEN +Z2_17SETUGEN_room_00 +Z2_17SETUGEN2 +Z2_17SETUGEN2_room_00 +Z2_SEA_BS +Z2_SEA_BS_room_00 +Z2_RANDOM +Z2_RANDOM_room_00 +Z2_RANDOM_room_01 +Z2_RANDOM_room_02 +Z2_RANDOM_room_03 +Z2_RANDOM_room_04 +Z2_RANDOM_room_05 +Z2_YADOYA +Z2_YADOYA_room_00 +Z2_YADOYA_room_01 +Z2_YADOYA_room_02 +Z2_YADOYA_room_03 +Z2_YADOYA_room_04 +Z2_KONPEKI_ENT +Z2_KONPEKI_ENT_room_00 +Z2_INSIDETOWER +Z2_INSIDETOWER_room_00 +Z2_INSIDETOWER_room_01 +Z2_26SARUNOMORI +Z2_26SARUNOMORI_room_00 +Z2_26SARUNOMORI_room_01 +Z2_26SARUNOMORI_room_02 +Z2_26SARUNOMORI_room_03 +Z2_26SARUNOMORI_room_04 +Z2_26SARUNOMORI_room_05 +Z2_26SARUNOMORI_room_06 +Z2_26SARUNOMORI_room_07 +Z2_26SARUNOMORI_room_08 +Z2_LOST_WOODS +Z2_LOST_WOODS_room_00 +Z2_LOST_WOODS_room_01 +Z2_LOST_WOODS_room_02 +Z2_LAST_LINK +Z2_LAST_LINK_room_00 +Z2_LAST_LINK_room_01 +Z2_LAST_LINK_room_02 +Z2_LAST_LINK_room_03 +Z2_LAST_LINK_room_04 +Z2_LAST_LINK_room_05 +Z2_LAST_LINK_room_06 +Z2_LAST_LINK_room_07 +Z2_SOUGEN +Z2_SOUGEN_room_00 +Z2_BOMYA +Z2_BOMYA_room_00 +Z2_KYOJINNOMA +Z2_KYOJINNOMA_room_00 +Z2_KOEPONARACE +Z2_KOEPONARACE_room_00 +Z2_GORONRACE +Z2_GORONRACE_room_00 +Z2_TOWN +Z2_TOWN_room_00 +Z2_ICHIBA +Z2_ICHIBA_room_00 +Z2_BACKTOWN +Z2_BACKTOWN_room_00 +Z2_CLOCKTOWER +Z2_CLOCKTOWER_room_00 +Z2_ALLEY +Z2_ALLEY_room_00 +SPOT00 +SPOT00_room_00 +KAKUSIANA +KAKUSIANA_room_00 +KAKUSIANA_room_01 +KAKUSIANA_room_02 +KAKUSIANA_room_03 +KAKUSIANA_room_04 +KAKUSIANA_room_05 +KAKUSIANA_room_06 +KAKUSIANA_room_07 +KAKUSIANA_room_08 +KAKUSIANA_room_09 +KAKUSIANA_room_10 +KAKUSIANA_room_11 +KAKUSIANA_room_12 +KAKUSIANA_room_13 +KAKUSIANA_room_14 +bump_texture_static +anime_model_1_static +anime_model_2_static +anime_model_3_static +anime_model_4_static +anime_model_5_static +anime_model_6_static +anime_texture_1_static +anime_texture_2_static +anime_texture_3_static +anime_texture_4_static +anime_texture_5_static +anime_texture_6_static +softsprite_matrix_static diff --git a/rom_info.py b/rom_info.py index 3ac0aca..e232146 100644 --- a/rom_info.py +++ b/rom_info.py @@ -23,6 +23,7 @@ class Checksums(Enum): MM_US_10 = "5354631C" MM_US_10_UNCOMPRESSED = "DA6983E7" + MM_US_GC = "B443EB08" UNKNOWN = "FFFFFFFF" @@ -46,8 +47,9 @@ def __init__(self, file_table_path, file_table_off, xml_ver, is_mm=False): ROM_INFO_TABLE[Checksums.OOT_PAL_10] = RomVersion("CFG/filelists/pal_oot.txt", 0x7950, "N64_PAL_10") ROM_INFO_TABLE[Checksums.OOT_PAL_11] = RomVersion("CFG/filelists/pal_oot.txt", 0x7950, "N64_PAL_11") -ROM_INFO_TABLE[Checksums.MM_US_10] = RomVersion("CFG/filelists/mm.txt", 0x1A500, "", is_mm=True) -ROM_INFO_TABLE[Checksums.MM_US_10_UNCOMPRESSED] = RomVersion("CFG/filelists/mm.txt", 0x1A500, "", is_mm=True) +ROM_INFO_TABLE[Checksums.MM_US_10] = RomVersion("CFG/filelists/mm.txt", 0x1A500, "N64_US", is_mm=True) +ROM_INFO_TABLE[Checksums.MM_US_10_UNCOMPRESSED] = RomVersion("CFG/filelists/mm.txt", 0x1A500, "N64_US", is_mm=True) +ROM_INFO_TABLE[Checksums.MM_US_GC] = RomVersion("CFG/filelists/mm_gc.txt", 0x1AE90, "GC_US", is_mm=True) class RomDmaEntry: def __init__(self, rom, i): From 755dd4aa25c0dd40d0ecfc697534b13819016a1e Mon Sep 17 00:00:00 2001 From: inspectredc <78732756+inspectredc@users.noreply.github.com> Date: Sat, 27 Apr 2024 18:27:52 +0100 Subject: [PATCH 40/55] Gamecube JP Filelists and Rom Info (#19) --- CFG/filelists/mm_gc_jp.txt | 1546 ++++++++++++++++++++++++++++++++++++ rom_info.py | 2 + 2 files changed, 1548 insertions(+) create mode 100644 CFG/filelists/mm_gc_jp.txt diff --git a/CFG/filelists/mm_gc_jp.txt b/CFG/filelists/mm_gc_jp.txt new file mode 100644 index 0000000..f673b49 --- /dev/null +++ b/CFG/filelists/mm_gc_jp.txt @@ -0,0 +1,1546 @@ +makerom +boot +dmadata +Audiobank +Audioseq +Audiotable +kanji +link_animetion +icon_item_static_syms +icon_item_24_static_syms +icon_item_field_static +icon_item_dungeon_static +icon_item_gameover_static +icon_item_jpn_static +icon_item_vtx_static +map_i_static +map_grand_static +item_name_static +map_name_static +icon_item_static_yar +icon_item_24_static_yar +schedule_dma_static_syms +schedule_dma_static_yar +schedule_static +story_static +do_action_static +message_static +message_texture_static +nes_font_static +message_data_static_jp +staff_message_data_static +code +ovl_title +ovl_select +ovl_opening +ovl_file_choose +ovl_daytelop +ovl_kaleido_scope +ovl_player_actor +ovl_En_Test +ovl_En_GirlA +ovl_En_Part +ovl_En_Light +ovl_En_Door +ovl_En_Box +ovl_En_Pametfrog +ovl_En_Okuta +ovl_En_Bom +ovl_En_Wallmas +ovl_En_Dodongo +ovl_En_Firefly +ovl_En_Horse +ovl_En_Arrow +ovl_En_Elf +ovl_En_Niw +ovl_En_Tite +ovl_En_Peehat +ovl_En_Holl +ovl_En_Dinofos +ovl_En_Hata +ovl_En_Zl1 +ovl_En_Viewer +ovl_En_Bubble +ovl_Door_Shutter +ovl_En_Boom +ovl_En_Torch2 +ovl_En_Minifrog +ovl_En_St +ovl_Obj_Wturn +ovl_En_River_Sound +ovl_En_Ossan +ovl_En_Famos +ovl_En_Bombf +ovl_En_Am +ovl_En_Dekubaba +ovl_En_M_Fire1 +ovl_En_M_Thunder +ovl_Bg_Breakwall +ovl_Door_Warp1 +ovl_Obj_Syokudai +ovl_Item_B_Heart +ovl_En_Dekunuts +ovl_En_Bbfall +ovl_Arms_Hook +ovl_En_Bb +ovl_Bg_Keikoku_Spr +ovl_En_Wood02 +ovl_En_Death +ovl_En_Minideath +ovl_En_Vm +ovl_Demo_Effect +ovl_Demo_Kankyo +ovl_En_Floormas +ovl_En_Rd +ovl_Bg_F40_Flift +ovl_Obj_Mure +ovl_En_Sw +ovl_Object_Kankyo +ovl_En_Horse_Link_Child +ovl_Door_Ana +ovl_En_Encount1 +ovl_Demo_Tre_Lgt +ovl_En_Encount2 +ovl_En_Fire_Rock +ovl_Bg_Ctower_Rot +ovl_Mir_Ray +ovl_En_Sb +ovl_En_Bigslime +ovl_En_Karebaba +ovl_En_In +ovl_En_Bom_Chu +ovl_En_Horse_Game_Check +ovl_En_Rr +ovl_En_Fr +ovl_Obj_Oshihiki +ovl_Eff_Dust +ovl_Bg_Umajump +ovl_En_Insect +ovl_En_Butte +ovl_En_Fish +ovl_Item_Etcetera +ovl_Arrow_Fire +ovl_Arrow_Ice +ovl_Arrow_Light +ovl_Obj_Kibako +ovl_Obj_Tsubo +ovl_En_Ik +ovl_Demo_Shd +ovl_En_Dns +ovl_Elf_Msg +ovl_En_Honotrap +ovl_En_Tubo_Trap +ovl_Obj_Ice_Poly +ovl_En_Fz +ovl_En_Kusa +ovl_Obj_Bean +ovl_Obj_Bombiwa +ovl_Obj_Switch +ovl_Obj_Lift +ovl_Obj_Hsblock +ovl_En_Okarina_Tag +ovl_En_Goroiwa +ovl_En_Daiku +ovl_En_Nwc +ovl_Item_Inbox +ovl_En_Ge1 +ovl_Obj_Blockstop +ovl_En_Sda +ovl_En_Clear_Tag +ovl_En_Gm +ovl_En_Ms +ovl_En_Hs +ovl_Bg_Ingate +ovl_En_Kanban +ovl_En_Attack_Niw +ovl_En_Mk +ovl_En_Owl +ovl_En_Ishi +ovl_Obj_Hana +ovl_Obj_Lightswitch +ovl_Obj_Mure2 +ovl_En_Fu +ovl_En_Stream +ovl_En_Mm +ovl_En_Weather_Tag +ovl_En_Ani +ovl_En_Js +ovl_En_Okarina_Effect +ovl_En_Mag +ovl_Elf_Msg2 +ovl_Bg_F40_Swlift +ovl_En_Kakasi +ovl_Obj_Makeoshihiki +ovl_Oceff_Spot +ovl_En_Torch +ovl_Shot_Sun +ovl_Obj_Roomtimer +ovl_En_Ssh +ovl_Oceff_Wipe +ovl_Effect_Ss_Dust +ovl_Effect_Ss_Kirakira +ovl_Effect_Ss_Bomb2 +ovl_Effect_Ss_Blast +ovl_Effect_Ss_G_Spk +ovl_Effect_Ss_D_Fire +ovl_Effect_Ss_Bubble +ovl_Effect_Ss_G_Ripple +ovl_Effect_Ss_G_Splash +ovl_Effect_Ss_G_Fire +ovl_Effect_Ss_Lightning +ovl_Effect_Ss_Dt_Bubble +ovl_Effect_Ss_Hahen +ovl_Effect_Ss_Stick +ovl_Effect_Ss_Sibuki +ovl_Effect_Ss_Stone1 +ovl_Effect_Ss_Hitmark +ovl_Effect_Ss_Fhg_Flash +ovl_Effect_Ss_K_Fire +ovl_Effect_Ss_Solder_Srch_Ball +ovl_Effect_Ss_Kakera +ovl_Effect_Ss_Ice_Piece +ovl_Effect_Ss_En_Ice +ovl_Effect_Ss_Fire_Tail +ovl_Effect_Ss_En_Fire +ovl_Effect_Ss_Extra +ovl_Effect_Ss_Dead_Db +ovl_Effect_Ss_Dead_Dd +ovl_Effect_Ss_Dead_Ds +ovl_Oceff_Storm +ovl_Obj_Demo +ovl_En_Minislime +ovl_En_Nutsball +ovl_Oceff_Wipe2 +ovl_Oceff_Wipe3 +ovl_En_Dg +ovl_En_Si +ovl_Obj_Comb +ovl_Obj_Kibako2 +ovl_En_Hs2 +ovl_Obj_Mure3 +ovl_En_Tg +ovl_En_Wf +ovl_En_Skb +ovl_En_Gs +ovl_Obj_Sound +ovl_En_Crow +ovl_En_Cow +ovl_Oceff_Wipe4 +ovl_En_Zo +ovl_Effect_Ss_Ice_Smoke +ovl_Obj_Makekinsuta +ovl_En_Ge3 +ovl_Obj_Hamishi +ovl_En_Zl4 +ovl_En_Mm2 +ovl_Door_Spiral +ovl_Obj_Pzlblock +ovl_Obj_Toge +ovl_Obj_Armos +ovl_Obj_Boyo +ovl_En_Grasshopper +ovl_Obj_Grass +ovl_Obj_Grass_Carry +ovl_Obj_Grass_Unit +ovl_Bg_Fire_Wall +ovl_En_Bu +ovl_En_Encount3 +ovl_En_Jso +ovl_Obj_Chikuwa +ovl_En_Knight +ovl_En_Warp_tag +ovl_En_Aob_01 +ovl_En_Boj_01 +ovl_En_Boj_02 +ovl_En_Boj_03 +ovl_En_Encount4 +ovl_En_Bom_Bowl_Man +ovl_En_Syateki_Man +ovl_Bg_Icicle +ovl_En_Syateki_Crow +ovl_En_Boj_04 +ovl_En_Cne_01 +ovl_En_Bba_01 +ovl_En_Bji_01 +ovl_Bg_Spdweb +ovl_En_Mt_tag +ovl_Boss_01 +ovl_Boss_02 +ovl_Boss_03 +ovl_Boss_04 +ovl_Boss_05 +ovl_Boss_06 +ovl_Boss_07 +ovl_Bg_Dy_Yoseizo +ovl_En_Boj_05 +ovl_En_Sob1 +ovl_En_Go +ovl_En_Raf +ovl_Obj_Funen +ovl_Obj_Raillift +ovl_Bg_Numa_Hana +ovl_Obj_Flowerpot +ovl_Obj_Spinyroll +ovl_Dm_Hina +ovl_En_Syateki_Wf +ovl_Obj_Skateblock +ovl_Effect_En_Ice_Block +ovl_Obj_Iceblock +ovl_En_Bigpamet +ovl_Bg_Dblue_Movebg +ovl_En_Syateki_Dekunuts +ovl_Elf_Msg3 +ovl_En_Fg +ovl_Dm_Ravine +ovl_Dm_Sa +ovl_En_Slime +ovl_En_Pr +ovl_Obj_Toudai +ovl_Obj_Entotu +ovl_Obj_Bell +ovl_En_Syateki_Okuta +ovl_Obj_Shutter +ovl_Dm_Zl +ovl_En_Ru +ovl_En_Elfgrp +ovl_Dm_Tsg +ovl_En_Baguo +ovl_Obj_Vspinyroll +ovl_Obj_Smork +ovl_En_Test2 +ovl_En_Test3 +ovl_En_Test4 +ovl_En_Bat +ovl_En_Sekihi +ovl_En_Wiz +ovl_En_Wiz_Brock +ovl_En_Wiz_Fire +ovl_Eff_Change +ovl_Dm_Statue +ovl_Obj_Fireshield +ovl_Bg_Ladder +ovl_En_Mkk +ovl_Demo_Getitem +ovl_En_Dnb +ovl_En_Dnh +ovl_En_Dnk +ovl_En_Dnq +ovl_Bg_Keikoku_Saku +ovl_Obj_Hugebombiwa +ovl_En_Firefly2 +ovl_En_Rat +ovl_En_Water_Effect +ovl_En_Kusa2 +ovl_Bg_Spout_Fire +ovl_En_Dy_Extra +ovl_En_Bal +ovl_En_Ginko_Man +ovl_En_Warp_Uzu +ovl_Obj_Driftice +ovl_En_Look_Nuts +ovl_En_Mushi2 +ovl_En_Fall +ovl_En_Mm3 +ovl_Bg_Crace_Movebg +ovl_En_Dno +ovl_En_Pr2 +ovl_En_Prz +ovl_En_Jso2 +ovl_Obj_Etcetera +ovl_En_Egol +ovl_Obj_Mine +ovl_Obj_Purify +ovl_En_Tru +ovl_En_Trt +ovl_En_Test5 +ovl_En_Test6 +ovl_En_Az +ovl_En_Estone +ovl_Bg_Hakugin_Post +ovl_Dm_Opstage +ovl_Dm_Stk +ovl_Dm_Char00 +ovl_Dm_Char01 +ovl_Dm_Char02 +ovl_Dm_Char03 +ovl_Dm_Char04 +ovl_Dm_Char05 +ovl_Dm_Char06 +ovl_Dm_Char07 +ovl_Dm_Char08 +ovl_Dm_Char09 +ovl_Obj_Tokeidai +ovl_En_Mnk +ovl_En_Egblock +ovl_En_Guard_Nuts +ovl_Bg_Hakugin_Bombwall +ovl_Obj_Tokei_Tobira +ovl_Bg_Hakugin_Elvpole +ovl_En_Ma4 +ovl_En_Twig +ovl_En_Po_Fusen +ovl_En_Door_Etc +ovl_En_Bigokuta +ovl_Bg_Icefloe +ovl_fbdemo_triforce +ovl_fbdemo_wipe1 +ovl_fbdemo_wipe3 +ovl_fbdemo_wipe4 +ovl_fbdemo_wipe5 +ovl_Effect_Ss_Sbn +ovl_Obj_Ocarinalift +ovl_En_Time_Tag +ovl_Bg_Open_Shutter +ovl_Bg_Open_Spot +ovl_Bg_Fu_Kaiten +ovl_Obj_Aqua +ovl_En_Elforg +ovl_En_Elfbub +ovl_En_Fu_Mato +ovl_En_Fu_Kago +ovl_En_Osn +ovl_Bg_Ctower_Gear +ovl_En_Trt2 +ovl_Obj_Tokei_Step +ovl_Bg_Lotus +ovl_En_Kame +ovl_Obj_Takaraya_Wall +ovl_Bg_Fu_Mizu +ovl_En_Sellnuts +ovl_Bg_Dkjail_Ivy +ovl_Obj_Visiblock +ovl_En_Takaraya +ovl_En_Tsn +ovl_En_Ds2n +ovl_En_Fsn +ovl_En_Shn +ovl_En_Stop_heishi +ovl_Obj_Bigicicle +ovl_En_Lift_Nuts +ovl_En_Tk +ovl_Bg_Market_Step +ovl_Obj_Lupygamelift +ovl_En_Test7 +ovl_Obj_Lightblock +ovl_Mir_Ray2 +ovl_En_Wdhand +ovl_En_Gamelupy +ovl_Bg_Danpei_Movebg +ovl_En_Snowwd +ovl_En_Pm +ovl_En_Gakufu +ovl_Elf_Msg4 +ovl_Elf_Msg5 +ovl_En_Col_Man +ovl_En_Talk_Gibud +ovl_En_Giant +ovl_Obj_Snowball +ovl_Boss_Hakugin +ovl_En_Gb2 +ovl_En_Onpuman +ovl_Bg_Tobira01 +ovl_En_Tag_Obj +ovl_Obj_Dhouse +ovl_Obj_Hakaisi +ovl_Bg_Hakugin_Switch +ovl_En_Snowman +ovl_TG_Sw +ovl_En_Po_Sisters +ovl_En_Pp +ovl_En_Hakurock +ovl_En_Hanabi +ovl_Obj_Dowsing +ovl_Obj_Wind +ovl_En_Racedog +ovl_En_Kendo_Js +ovl_Bg_Botihasira +ovl_En_Fish2 +ovl_En_Pst +ovl_En_Poh +ovl_Obj_Spidertent +ovl_En_Zoraegg +ovl_En_Kbt +ovl_En_Gg +ovl_En_Maruta +ovl_Obj_Snowball2 +ovl_En_Gg2 +ovl_Obj_Ghaka +ovl_En_Dnp +ovl_En_Dai +ovl_Bg_Goron_Oyu +ovl_En_Kgy +ovl_En_Invadepoh +ovl_En_Gk +ovl_En_An +ovl_En_Bee +ovl_En_Ot +ovl_En_Dragon +ovl_Obj_Dora +ovl_En_Bigpo +ovl_Obj_Kendo_Kanban +ovl_Obj_Hariko +ovl_En_Sth +ovl_Bg_Sinkai_Kabe +ovl_Bg_Haka_Curtain +ovl_Bg_Kin2_Bombwall +ovl_Bg_Kin2_Fence +ovl_Bg_Kin2_Picture +ovl_Bg_Kin2_Shelf +ovl_En_Rail_Skb +ovl_En_Jg +ovl_En_Tru_Mt +ovl_Obj_Um +ovl_En_Neo_Reeba +ovl_Bg_Mbar_Chair +ovl_Bg_Ikana_Block +ovl_Bg_Ikana_Mirror +ovl_Bg_Ikana_Rotaryroom +ovl_Bg_Dblue_Balance +ovl_Bg_Dblue_Waterfall +ovl_En_Kaizoku +ovl_En_Ge2 +ovl_En_Ma_Yts +ovl_En_Ma_Yto +ovl_Obj_Tokei_Turret +ovl_Bg_Dblue_Elevator +ovl_Obj_Warpstone +ovl_En_Zog +ovl_Obj_Rotlift +ovl_Obj_Jg_Gakki +ovl_Bg_Inibs_Movebg +ovl_En_Zot +ovl_Obj_Tree +ovl_Obj_Y2lift +ovl_Obj_Y2shutter +ovl_Obj_Boat +ovl_Obj_Taru +ovl_Obj_Hunsui +ovl_En_Jc_Mato +ovl_Mir_Ray3 +ovl_En_Zob +ovl_Elf_Msg6 +ovl_Obj_Nozoki +ovl_En_Toto +ovl_En_Railgibud +ovl_En_Baba +ovl_En_Suttari +ovl_En_Zod +ovl_En_Kujiya +ovl_En_Geg +ovl_Obj_Kinoko +ovl_Obj_Yasi +ovl_En_Tanron1 +ovl_En_Tanron2 +ovl_En_Tanron3 +ovl_Obj_Chan +ovl_En_Zos +ovl_En_S_Goro +ovl_En_Nb +ovl_En_Ja +ovl_Bg_F40_Block +ovl_Bg_F40_Switch +ovl_En_Po_Composer +ovl_En_Guruguru +ovl_Oceff_Wipe5 +ovl_En_Stone_heishi +ovl_Oceff_Wipe6 +ovl_En_Scopenuts +ovl_En_Scopecrow +ovl_Oceff_Wipe7 +ovl_Eff_Kamejima_Wave +ovl_En_Hg +ovl_En_Hgo +ovl_En_Zov +ovl_En_Ah +ovl_Obj_Hgdoor +ovl_Bg_Ikana_Bombwall +ovl_Bg_Ikana_Ray +ovl_Bg_Ikana_Shutter +ovl_Bg_Haka_Bombwall +ovl_Bg_Haka_Tomb +ovl_En_Sc_Ruppe +ovl_Bg_Iknv_Doukutu +ovl_Bg_Iknv_Obj +ovl_En_Pamera +ovl_Obj_HsStump +ovl_En_Hidden_Nuts +ovl_En_Zow +ovl_En_Talk +ovl_En_Al +ovl_En_Tab +ovl_En_Nimotsu +ovl_En_Hit_Tag +ovl_En_Ruppecrow +ovl_En_Tanron4 +ovl_En_Tanron5 +ovl_En_Tanron6 +ovl_En_Daiku2 +ovl_En_Muto +ovl_En_Baisen +ovl_En_Heishi +ovl_En_Demo_heishi +ovl_En_Dt +ovl_En_Cha +ovl_Obj_Dinner +ovl_Eff_Lastday +ovl_Bg_Ikana_Dharma +ovl_En_Akindonuts +ovl_Eff_Stk +ovl_En_Ig +ovl_En_Rg +ovl_En_Osk +ovl_En_Sth2 +ovl_En_Yb +ovl_En_Rz +ovl_En_Scopecoin +ovl_En_Bjt +ovl_En_Bomjima +ovl_En_Bomjimb +ovl_En_Bombers +ovl_En_Bombers2 +ovl_En_Bombal +ovl_Obj_Moon_Stone +ovl_Obj_Mu_Pict +ovl_Bg_Ikninside +ovl_Eff_Zoraband +ovl_Obj_Kepn_Koya +ovl_Obj_Usiyane +ovl_En_Nnh +ovl_Obj_Kzsaku +ovl_Obj_Milk_Bin +ovl_En_Kitan +ovl_Bg_Astr_Bombwall +ovl_Bg_Iknin_Susceil +ovl_En_Bsb +ovl_En_Recepgirl +ovl_En_Thiefbird +ovl_En_Jgame_Tsn +ovl_Obj_Jgame_Light +ovl_Obj_Yado +ovl_Demo_Syoten +ovl_Demo_Moonend +ovl_Bg_Lbfshot +ovl_Bg_Last_Bwall +ovl_En_And +ovl_En_Invadepoh_Demo +ovl_Obj_Danpeilift +ovl_En_Fall2 +ovl_Dm_Al +ovl_Dm_An +ovl_Dm_Ah +ovl_Dm_Nb +ovl_En_Drs +ovl_En_Ending_Hero +ovl_Dm_Bal +ovl_En_Paper +ovl_En_Hint_Skb +ovl_Dm_Tag +ovl_En_Bh +ovl_En_Ending_Hero2 +ovl_En_Ending_Hero3 +ovl_En_Ending_Hero4 +ovl_En_Ending_Hero5 +ovl_En_Ending_Hero6 +ovl_Dm_Gm +ovl_Obj_Swprize +ovl_En_Invisible_Ruppe +ovl_Obj_Ending +ovl_En_Rsn +gameplay_keep +gameplay_field_keep +gameplay_dangeon_keep +gameplay_object_exchange_static +object_link_boy +object_link_child +object_link_goron +object_link_zora +object_link_nuts +object_mask_ki_tan +object_mask_rabit +object_mask_skj +object_mask_truth +object_mask_gibudo +object_mask_json +object_mask_kerfay +object_mask_bigelf +object_mask_kyojin +object_mask_romerny +object_mask_posthat +object_mask_zacho +object_mask_stone +object_mask_bree +object_mask_gero +object_mask_yofukasi +object_mask_meoto +object_mask_dancer +object_mask_bakuretu +object_mask_bu_san +object_mask_goron +object_mask_zora +object_mask_nuts +object_mask_boy +object_box +object_okuta +object_wallmaster +object_dy_obj +object_firefly +object_dodongo +object_niw +object_tite +object_ph +object_dinofos +object_zl1 +object_bubble +object_test3 +object_famos +object_st +object_thiefbird +object_bombf +object_am +object_dekubaba +object_warp1 +object_b_heart +object_dekunuts +object_bb +object_death +object_hata +object_wood02 +object_trap +object_vm +object_efc_star_field +object_rd +object_yukimura_obj +object_horse_link_child +object_syokudai +object_efc_tw +object_gi_key +object_mir_ray +object_ctower_rot +object_bdoor +object_sb +object_gi_melody +object_gi_heart +object_gi_compass +object_gi_bosskey +object_gi_nuts +object_gi_hearts +object_gi_arrowcase +object_gi_bombpouch +object_in +object_os_anime +object_gi_bottle +object_gi_stick +object_gi_map +object_oF1d_map +object_ru2 +object_gi_magicpot +object_gi_bomb_1 +object_ma2 +object_gi_purse +object_rr +object_gi_arrow +object_gi_bomb_2 +object_gi_shield_2 +object_gi_hookshot +object_gi_ocarina +object_gi_milk +object_ma1 +object_ny +object_fr +object_gi_bow +object_gi_glasses +object_gi_liquid +object_ani +object_gi_shield_3 +object_gi_bean +object_gi_fish +object_gi_longsword +object_zo +object_umajump +object_mastergolon +object_masterzoora +object_aob +object_ik +object_ahg +object_cne +object_bji +object_bba +object_an1 +object_boj +object_fz +object_bob +object_ge1 +object_yabusame_point +object_d_hsblock +object_d_lift +object_mamenoki +object_goroiwa +object_toryo +object_daiku +object_nwc +object_gm +object_ms +object_hs +object_lightswitch +object_kusa +object_tsubo +object_kanban +object_owl +object_mk +object_fu +object_gi_ki_tan_mask +object_gi_mask18 +object_gi_rabit_mask +object_gi_truth_mask +object_stream +object_mm +object_js +object_cs +object_gi_soldout +object_mag +object_gi_golonmask +object_gi_zoramask +object_ka +object_zg +object_gi_m_arrow +object_ds2 +object_fish +object_gi_sutaru +object_ssh +object_bigslime +object_bg +object_bombiwa +object_hintnuts +object_rs +object_gla +object_geldb +object_dog +object_kibako2 +object_dns +object_dnk +object_gi_insect +object_gi_ghost +object_gi_soul +object_f40_obj +object_gi_rupy +object_po_composer +object_mu +object_wf +object_skb +object_gs +object_ps +object_omoya_obj +object_crow +object_cow +object_gi_sword_1 +object_zl4 +object_grasshopper +object_boyo +object_fwall +object_jso +object_knight +object_icicle +object_spdweb +object_boss01 +object_boss02 +object_boss03 +object_boss04 +object_boss05 +object_boss07 +object_raf +object_funen +object_raillift +object_numa_obj +object_flowerpot +object_spinyroll +object_ice_block +object_keikoku_demo +object_slime +object_pr +object_f52_obj +object_f53_obj +object_kibako +object_sek +object_gmo +object_bat +object_sekihil +object_sekihig +object_sekihin +object_sekihiz +object_wiz +object_ladder +object_mkk +object_keikoku_obj +object_sichitai_obj +object_dekucity_ana_obj +object_rat +object_water_effect +object_dblue_object +object_bal +object_warp_uzu +object_driftice +object_fall +object_hanareyama_obj +object_crace_object +object_dno +object_obj_tokeidai +object_eg +object_tru +object_trt +object_hakugin_obj +object_horse_game_check +object_stk +object_mnk +object_gi_bottle_red +object_tokei_tobira +object_az +object_twig +object_dekucity_obj +object_po_fusen +object_racetsubo +object_ha +object_bigokuta +object_open_obj +object_fu_kaiten +object_fu_mato +object_mtoride +object_osn +object_tokei_step +object_lotus +object_tl +object_dkjail_obj +object_visiblock +object_tsn +object_ds2n +object_fsn +object_shn +object_bigicicle +object_gi_bottle_15 +object_tk +object_market_obj +object_gi_reserve00 +object_gi_reserve01 +object_lightblock +object_takaraya_objects +object_wdhand +object_sdn +object_snowwd +object_giant +object_comb +object_hana +object_boss_hakugin +object_meganeana_obj +object_gi_nutsmask +object_stk2 +object_spot11_obj +object_danpei_object +object_dhouse +object_hakaisi +object_po +object_snowman +object_po_sisters +object_pp +object_goronswitch +object_delf +object_botihasira +object_gi_bigbomb +object_pst +object_bsmask +object_spidertent +object_zoraegg +object_kbt +object_gg +object_maruta +object_ghaka +object_oyu +object_dnq +object_dai +object_kgy +object_fb +object_taisou +object_gk +object_haka_obj +object_dnt +object_yukiyama +object_icefloe +object_gi_gold_dust +object_gi_bottle_16 +object_gi_bottle_22 +object_bee +object_ot +object_utubo +object_dora +object_gi_loach +object_gi_seahorse +object_bigpo +object_hariko +object_dnj +object_sinkai_kabe +object_kin2_obj +object_ishi +object_hakugin_demo +object_jg +object_gi_sword_2 +object_gi_sword_3 +object_gi_sword_4 +object_um +object_rb +object_mbar_obj +object_ikana_obj +object_kz +object_tokei_turret +object_zog +object_rotlift +object_posthouse_obj +object_gi_mask09 +object_gi_mask14 +object_gi_mask15 +object_inibs_object +object_tree +object_kaizoku_obj +object_gi_reserve_b_00 +object_gi_reserve_c_00 +object_zob +object_milkbar +object_dmask +object_gi_reserve_c_01 +object_zod +object_kumo30 +object_obj_yasi +object_tanron1 +object_tanron2 +object_tanron3 +object_gi_magicmushroom +object_obj_chan +object_gi_mask10 +object_zos +object_an2 +object_an3 +object_f40_switch +object_lodmoon +object_tro +object_gi_mask12 +object_gi_mask23 +object_gi_bottle_21 +object_gi_camera +object_kamejima +object_nb +object_harfgibud +object_zov +object_ah +object_hgdoor +object_dor01 +object_dor02 +object_dor03 +object_dor04 +object_last_obj +object_redead_obj +object_ikninside_obj +object_iknv_obj +object_pamera +object_hsstump +object_zm +object_al +object_tab +object_secom_obj +object_dt +object_gi_mask03 +object_cha +object_obj_dinner +object_gi_reserve_b_01 +object_lastday +object_bai +object_ikn_demo +object_gi_fieldmap +object_big_fwall +object_hunsui +object_uch +object_tanron4 +object_tanron5 +object_in2 +object_yb +object_rz +object_bjt +object_taru +object_moonston +object_gi_schedule +object_gi_stonemask +object_zoraband +object_kepn_koya +object_obj_usiyane +object_gi_mask05 +object_gi_mask11 +object_gi_mask20 +object_nnh +object_kzsaku +object_obj_milk_bin +object_random_obj +object_kujiya +object_kitan +object_gi_mask06 +object_gi_mask16 +object_astr_obj +object_bsb +object_fall2 +object_sth +object_gi_mssa +object_smtower +object_gi_mask21 +object_yado_obj +object_syoten +object_moonend +object_ob +object_gi_bottle_04 +object_and +object_obj_danpeilift +object_drs +object_msmo +object_an4 +object_wdor01 +object_wdor02 +object_wdor03 +object_wdor04 +object_wdor05 +object_stk3 +object_kinsta1_obj +object_kinsta2_obj +object_bh +object_gi_mask17 +object_gi_mask22 +object_lbfshot +object_fusen +object_ending_obj +object_gi_mask13 +scene_texture_01 +scene_texture_02 +scene_texture_03 +scene_texture_04 +scene_texture_05 +scene_texture_06 +scene_texture_07 +scene_texture_08 +nintendo_rogo_static +title_static +parameter_static +week_static +daytelop_static +d2_fine_static +d2_cloud_static +d2_fine_pal_static +elf_message_field +elf_message_ydan +Z2_20SICHITAI2 +Z2_20SICHITAI2_room_00 +Z2_20SICHITAI2_room_01 +Z2_20SICHITAI2_room_02 +Z2_WITCH_SHOP +Z2_WITCH_SHOP_room_00 +Z2_LAST_BS +Z2_LAST_BS_room_00 +Z2_HAKASHITA +Z2_HAKASHITA_room_00 +Z2_HAKASHITA_room_01 +Z2_HAKASHITA_room_02 +Z2_HAKASHITA_room_03 +Z2_HAKASHITA_room_04 +Z2_AYASHIISHOP +Z2_AYASHIISHOP_room_00 +Z2_AYASHIISHOP_room_01 +Z2_OMOYA +Z2_OMOYA_room_00 +Z2_OMOYA_room_01 +Z2_OMOYA_room_02 +Z2_BOWLING +Z2_BOWLING_room_00 +Z2_SONCHONOIE +Z2_SONCHONOIE_room_00 +Z2_SONCHONOIE_room_01 +Z2_SONCHONOIE_room_02 +Z2_SONCHONOIE_room_03 +Z2_IKANA +Z2_IKANA_room_00 +Z2_IKANA_room_01 +Z2_IKANA_room_02 +Z2_IKANA_room_03 +Z2_IKANA_room_04 +Z2_KAIZOKU +Z2_KAIZOKU_room_00 +Z2_MILK_BAR +Z2_MILK_BAR_room_00 +Z2_INISIE_N +Z2_INISIE_N_room_00 +Z2_INISIE_N_room_01 +Z2_INISIE_N_room_02 +Z2_INISIE_N_room_03 +Z2_INISIE_N_room_04 +Z2_INISIE_N_room_05 +Z2_INISIE_N_room_06 +Z2_INISIE_N_room_07 +Z2_INISIE_N_room_08 +Z2_INISIE_N_room_09 +Z2_INISIE_N_room_10 +Z2_INISIE_N_room_11 +Z2_TAKARAYA +Z2_TAKARAYA_room_00 +Z2_INISIE_R +Z2_INISIE_R_room_00 +Z2_INISIE_R_room_01 +Z2_INISIE_R_room_02 +Z2_INISIE_R_room_03 +Z2_INISIE_R_room_04 +Z2_INISIE_R_room_05 +Z2_INISIE_R_room_06 +Z2_INISIE_R_room_07 +Z2_INISIE_R_room_08 +Z2_INISIE_R_room_09 +Z2_INISIE_R_room_10 +Z2_INISIE_R_room_11 +Z2_OKUJOU +Z2_OKUJOU_room_00 +Z2_OPENINGDAN +Z2_OPENINGDAN_room_00 +Z2_OPENINGDAN_room_01 +Z2_MITURIN +Z2_MITURIN_room_00 +Z2_MITURIN_room_01 +Z2_MITURIN_room_02 +Z2_MITURIN_room_03 +Z2_MITURIN_room_04 +Z2_MITURIN_room_05 +Z2_MITURIN_room_06 +Z2_MITURIN_room_07 +Z2_MITURIN_room_08 +Z2_MITURIN_room_09 +Z2_MITURIN_room_10 +Z2_MITURIN_room_11 +Z2_MITURIN_room_12 +Z2_13HUBUKINOMITI +Z2_13HUBUKINOMITI_room_00 +Z2_CASTLE +Z2_CASTLE_room_00 +Z2_CASTLE_room_01 +Z2_CASTLE_room_02 +Z2_CASTLE_room_03 +Z2_CASTLE_room_04 +Z2_CASTLE_room_05 +Z2_CASTLE_room_06 +Z2_CASTLE_room_07 +Z2_CASTLE_room_08 +Z2_CASTLE_room_09 +Z2_DEKUTES +Z2_DEKUTES_room_00 +Z2_MITURIN_BS +Z2_MITURIN_BS_room_00 +Z2_SYATEKI_MIZU +Z2_SYATEKI_MIZU_room_00 +Z2_HAKUGIN +Z2_HAKUGIN_room_00 +Z2_HAKUGIN_room_01 +Z2_HAKUGIN_room_02 +Z2_HAKUGIN_room_03 +Z2_HAKUGIN_room_04 +Z2_HAKUGIN_room_05 +Z2_HAKUGIN_room_06 +Z2_HAKUGIN_room_07 +Z2_HAKUGIN_room_08 +Z2_HAKUGIN_room_09 +Z2_HAKUGIN_room_10 +Z2_HAKUGIN_room_11 +Z2_HAKUGIN_room_12 +Z2_HAKUGIN_room_13 +Z2_ROMANYMAE +Z2_ROMANYMAE_room_00 +Z2_PIRATE +Z2_PIRATE_room_00 +Z2_PIRATE_room_01 +Z2_PIRATE_room_02 +Z2_PIRATE_room_03 +Z2_PIRATE_room_04 +Z2_PIRATE_room_05 +Z2_PIRATE_room_06 +Z2_PIRATE_room_07 +Z2_PIRATE_room_08 +Z2_PIRATE_room_09 +Z2_PIRATE_room_10 +Z2_PIRATE_room_11 +Z2_PIRATE_room_12 +Z2_PIRATE_room_13 +Z2_PIRATE_room_14 +Z2_SYATEKI_MORI +Z2_SYATEKI_MORI_room_00 +Z2_SINKAI +Z2_SINKAI_room_00 +Z2_YOUSEI_IZUMI +Z2_YOUSEI_IZUMI_room_00 +Z2_YOUSEI_IZUMI_room_01 +Z2_YOUSEI_IZUMI_room_02 +Z2_YOUSEI_IZUMI_room_03 +Z2_YOUSEI_IZUMI_room_04 +Z2_KINSTA1 +Z2_KINSTA1_room_00 +Z2_KINSTA1_room_01 +Z2_KINSTA1_room_02 +Z2_KINSTA1_room_03 +Z2_KINSTA1_room_04 +Z2_KINSTA1_room_05 +Z2_KINDAN2 +Z2_KINDAN2_room_00 +Z2_KINDAN2_room_01 +Z2_KINDAN2_room_02 +Z2_KINDAN2_room_03 +Z2_KINDAN2_room_04 +Z2_KINDAN2_room_05 +Z2_TENMON_DAI +Z2_TENMON_DAI_room_00 +Z2_TENMON_DAI_room_01 +Z2_LAST_DEKU +Z2_LAST_DEKU_room_00 +Z2_LAST_DEKU_room_01 +Z2_22DEKUCITY +Z2_22DEKUCITY_room_00 +Z2_22DEKUCITY_room_01 +Z2_22DEKUCITY_room_02 +Z2_KAJIYA +Z2_KAJIYA_room_00 +Z2_00KEIKOKU +Z2_00KEIKOKU_room_00 +Z2_POSTHOUSE +Z2_POSTHOUSE_room_00 +Z2_LABO +Z2_LABO_room_00 +Z2_DANPEI2TEST +Z2_DANPEI2TEST_room_00 +Z2_DANPEI2TEST_room_01 +Z2_16GORON_HOUSE +Z2_16GORON_HOUSE_room_00 +Z2_16GORON_HOUSE_room_01 +Z2_33ZORACITY +Z2_33ZORACITY_room_00 +Z2_8ITEMSHOP +Z2_8ITEMSHOP_room_00 +Z2_F01 +Z2_F01_room_00 +Z2_INISIE_BS +Z2_INISIE_BS_room_00 +Z2_30GYOSON +Z2_30GYOSON_room_00 +Z2_31MISAKI +Z2_31MISAKI_room_00 +Z2_TAKARAKUJI +Z2_TAKARAKUJI_room_00 +Z2_TORIDE +Z2_TORIDE_room_00 +Z2_FISHERMAN +Z2_FISHERMAN_room_00 +Z2_GORONSHOP +Z2_GORONSHOP_room_00 +Z2_DEKU_KING +Z2_DEKU_KING_room_00 +Z2_LAST_GORON +Z2_LAST_GORON_room_00 +Z2_LAST_GORON_room_01 +Z2_24KEMONOMITI +Z2_24KEMONOMITI_room_00 +Z2_F01_B +Z2_F01_B_room_00 +Z2_F01C +Z2_F01C_room_00 +Z2_BOTI +Z2_BOTI_room_00 +Z2_BOTI_room_01 +Z2_HAKUGIN_BS +Z2_HAKUGIN_BS_room_00 +Z2_20SICHITAI +Z2_20SICHITAI_room_00 +Z2_20SICHITAI_room_01 +Z2_20SICHITAI_room_02 +Z2_21MITURINMAE +Z2_21MITURINMAE_room_00 +Z2_LAST_ZORA +Z2_LAST_ZORA_room_00 +Z2_11GORONNOSATO2 +Z2_11GORONNOSATO2_room_00 +Z2_11GORONNOSATO2_room_01 +Z2_SEA +Z2_SEA_room_00 +Z2_SEA_room_01 +Z2_SEA_room_02 +Z2_SEA_room_03 +Z2_SEA_room_04 +Z2_SEA_room_05 +Z2_SEA_room_06 +Z2_SEA_room_07 +Z2_SEA_room_08 +Z2_SEA_room_09 +Z2_SEA_room_10 +Z2_SEA_room_11 +Z2_SEA_room_12 +Z2_SEA_room_13 +Z2_SEA_room_14 +Z2_SEA_room_15 +Z2_35TAKI +Z2_35TAKI_room_00 +Z2_REDEAD +Z2_REDEAD_room_00 +Z2_REDEAD_room_01 +Z2_REDEAD_room_02 +Z2_REDEAD_room_03 +Z2_REDEAD_room_04 +Z2_REDEAD_room_05 +Z2_REDEAD_room_06 +Z2_REDEAD_room_07 +Z2_REDEAD_room_08 +Z2_REDEAD_room_09 +Z2_REDEAD_room_10 +Z2_REDEAD_room_11 +Z2_REDEAD_room_12 +Z2_REDEAD_room_13 +Z2_BANDROOM +Z2_BANDROOM_room_00 +Z2_BANDROOM_room_01 +Z2_BANDROOM_room_02 +Z2_BANDROOM_room_03 +Z2_BANDROOM_room_04 +Z2_11GORONNOSATO +Z2_11GORONNOSATO_room_00 +Z2_11GORONNOSATO_room_01 +Z2_GORON_HAKA +Z2_GORON_HAKA_room_00 +Z2_SECOM +Z2_SECOM_room_00 +Z2_SECOM_room_01 +Z2_10YUKIYAMANOMURA +Z2_10YUKIYAMANOMURA_room_00 +Z2_TOUGITES +Z2_TOUGITES_room_00 +Z2_DANPEI +Z2_DANPEI_room_00 +Z2_DANPEI_room_01 +Z2_DANPEI_room_02 +Z2_DANPEI_room_03 +Z2_DANPEI_room_04 +Z2_DANPEI_room_05 +Z2_DANPEI_room_06 +Z2_DANPEI_room_07 +Z2_DANPEI_room_08 +Z2_IKANAMAE +Z2_IKANAMAE_room_00 +Z2_DOUJOU +Z2_DOUJOU_room_00 +Z2_MUSICHOUSE +Z2_MUSICHOUSE_room_00 +Z2_IKNINSIDE +Z2_IKNINSIDE_room_00 +Z2_IKNINSIDE_room_01 +Z2_MAP_SHOP +Z2_MAP_SHOP_room_00 +Z2_F40 +Z2_F40_room_00 +Z2_F41 +Z2_F41_room_00 +Z2_10YUKIYAMANOMURA2 +Z2_10YUKIYAMANOMURA2_room_00 +Z2_10YUKIYAMANOMURA2_room_01 +Z2_14YUKIDAMANOMITI +Z2_14YUKIDAMANOMITI_room_00 +Z2_12HAKUGINMAE +Z2_12HAKUGINMAE_room_00 +Z2_17SETUGEN +Z2_17SETUGEN_room_00 +Z2_17SETUGEN2 +Z2_17SETUGEN2_room_00 +Z2_SEA_BS +Z2_SEA_BS_room_00 +Z2_RANDOM +Z2_RANDOM_room_00 +Z2_RANDOM_room_01 +Z2_RANDOM_room_02 +Z2_RANDOM_room_03 +Z2_RANDOM_room_04 +Z2_RANDOM_room_05 +Z2_YADOYA +Z2_YADOYA_room_00 +Z2_YADOYA_room_01 +Z2_YADOYA_room_02 +Z2_YADOYA_room_03 +Z2_YADOYA_room_04 +Z2_KONPEKI_ENT +Z2_KONPEKI_ENT_room_00 +Z2_INSIDETOWER +Z2_INSIDETOWER_room_00 +Z2_INSIDETOWER_room_01 +Z2_26SARUNOMORI +Z2_26SARUNOMORI_room_00 +Z2_26SARUNOMORI_room_01 +Z2_26SARUNOMORI_room_02 +Z2_26SARUNOMORI_room_03 +Z2_26SARUNOMORI_room_04 +Z2_26SARUNOMORI_room_05 +Z2_26SARUNOMORI_room_06 +Z2_26SARUNOMORI_room_07 +Z2_26SARUNOMORI_room_08 +Z2_LOST_WOODS +Z2_LOST_WOODS_room_00 +Z2_LOST_WOODS_room_01 +Z2_LOST_WOODS_room_02 +Z2_LAST_LINK +Z2_LAST_LINK_room_00 +Z2_LAST_LINK_room_01 +Z2_LAST_LINK_room_02 +Z2_LAST_LINK_room_03 +Z2_LAST_LINK_room_04 +Z2_LAST_LINK_room_05 +Z2_LAST_LINK_room_06 +Z2_LAST_LINK_room_07 +Z2_SOUGEN +Z2_SOUGEN_room_00 +Z2_BOMYA +Z2_BOMYA_room_00 +Z2_KYOJINNOMA +Z2_KYOJINNOMA_room_00 +Z2_KOEPONARACE +Z2_KOEPONARACE_room_00 +Z2_GORONRACE +Z2_GORONRACE_room_00 +Z2_TOWN +Z2_TOWN_room_00 +Z2_ICHIBA +Z2_ICHIBA_room_00 +Z2_BACKTOWN +Z2_BACKTOWN_room_00 +Z2_CLOCKTOWER +Z2_CLOCKTOWER_room_00 +Z2_ALLEY +Z2_ALLEY_room_00 +SPOT00 +SPOT00_room_00 +KAKUSIANA +KAKUSIANA_room_00 +KAKUSIANA_room_01 +KAKUSIANA_room_02 +KAKUSIANA_room_03 +KAKUSIANA_room_04 +KAKUSIANA_room_05 +KAKUSIANA_room_06 +KAKUSIANA_room_07 +KAKUSIANA_room_08 +KAKUSIANA_room_09 +KAKUSIANA_room_10 +KAKUSIANA_room_11 +KAKUSIANA_room_12 +KAKUSIANA_room_13 +KAKUSIANA_room_14 +bump_texture_static +anime_model_1_static +anime_model_2_static +anime_model_3_static +anime_model_4_static +anime_model_5_static +anime_model_6_static +anime_texture_1_static +anime_texture_2_static +anime_texture_3_static +anime_texture_4_static +anime_texture_5_static +anime_texture_6_static +softsprite_matrix_static diff --git a/rom_info.py b/rom_info.py index e232146..5e6c8b8 100644 --- a/rom_info.py +++ b/rom_info.py @@ -24,6 +24,7 @@ class Checksums(Enum): MM_US_10 = "5354631C" MM_US_10_UNCOMPRESSED = "DA6983E7" MM_US_GC = "B443EB08" + MM_JP_GC = "8473D0C1" UNKNOWN = "FFFFFFFF" @@ -50,6 +51,7 @@ def __init__(self, file_table_path, file_table_off, xml_ver, is_mm=False): ROM_INFO_TABLE[Checksums.MM_US_10] = RomVersion("CFG/filelists/mm.txt", 0x1A500, "N64_US", is_mm=True) ROM_INFO_TABLE[Checksums.MM_US_10_UNCOMPRESSED] = RomVersion("CFG/filelists/mm.txt", 0x1A500, "N64_US", is_mm=True) ROM_INFO_TABLE[Checksums.MM_US_GC] = RomVersion("CFG/filelists/mm_gc.txt", 0x1AE90, "GC_US", is_mm=True) +ROM_INFO_TABLE[Checksums.MM_JP_GC] = RomVersion("CFG/filelists/mm_gc_jp.txt", 0x1AE90, "GC_JP", is_mm=True) class RomDmaEntry: def __init__(self, rom, i): From 67feb47d9d3281585a1981412e4f24451941e0b2 Mon Sep 17 00:00:00 2001 From: inspectredc <78732756+inspectredc@users.noreply.github.com> Date: Sat, 27 Apr 2024 18:28:00 +0100 Subject: [PATCH 41/55] Revert "Fix Branching DisplayLists (#18)" (#20) --- OTRExporter/DisplayListExporter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index b309fd0..fc06e3d 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -344,7 +344,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina uint32_t z = (data & 0x00000000FFFFFFFF) >> 0; uint32_t h = (data & 0xFFFFFFFF); - auto data2 = dList->instructions[dataIdx + 1]; + auto data2 = dList->instructions[dataIdx - 1]; uint32_t dListPtr = GETSEGOFFSET(data2); Declaration* dListDecl = dList->parent->GetDeclaration(dListPtr); @@ -445,7 +445,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina if ((int)opF3D == G_BRANCH_Z) { - auto data2 = dList->instructions[dataIdx + 1]; + auto data2 = dList->instructions[dataIdx - 1]; dListPtr = GETSEGOFFSET(data2); } else From b3314eb7916736d597335860b2ccbfc35e0be7ed Mon Sep 17 00:00:00 2001 From: Archez Date: Thu, 2 May 2024 20:43:16 -0400 Subject: [PATCH 42/55] search for dlist in external files for branch z (#21) --- OTRExporter/DisplayListExporter.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index fc06e3d..8c4b533 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -369,9 +369,24 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina } else { - word0 = 0; - word1 = 0; - spdlog::error(StringHelper::Sprintf("dListDecl == nullptr! Addr = {:08X}", GETSEGOFFSET(data))); + // If we can't find the display list in this file, try looking in other files based on the segment number + uint32_t seg = data2 & 0xFFFFFFFF; + std::string resourceName = ""; + bool foundDecl = Globals::Instance->GetSegmentedPtrName(seg, dList->parent, "", resourceName, res->parent->workerID); + if (foundDecl) { + ZFile* assocFile = Globals::Instance->GetSegment(GETSEGNUM(seg), res->parent->workerID); + std::string assocFileName = assocFile->GetName(); + std::string fName = GetPathToRes(assocFile->resources[0], resourceName.c_str()); + + uint64_t hash = CRC64(fName.c_str()); + + word0 = hash >> 32; + word1 = hash & 0xFFFFFFFF; + } else { + word0 = 0; + word1 = 0; + spdlog::error(StringHelper::Sprintf("dListDecl == nullptr! Addr = {:08X}", GETSEGOFFSET(data2))); + } } for (size_t i = 0; i < dList->otherDLists.size(); i++) From 031782dd74d03da31879178664eb9dcbec50584d Mon Sep 17 00:00:00 2001 From: Archez Date: Thu, 2 May 2024 20:43:25 -0400 Subject: [PATCH 43/55] nlohmann from package managers (#16) (#22) Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com> --- OTRExporter/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OTRExporter/CMakeLists.txt b/OTRExporter/CMakeLists.txt index f7b89fd..39e79d8 100644 --- a/OTRExporter/CMakeLists.txt +++ b/OTRExporter/CMakeLists.txt @@ -170,12 +170,14 @@ target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/ZAPDUtils ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/StormLib/src ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/spdlog/include - ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/nlohmann-json/include ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src/resource ${CMAKE_CURRENT_SOURCE_DIR}/../../mm/2s2h . ) +find_package(nlohmann_json REQUIRED) +target_link_libraries(${PROJECT_NAME} PUBLIC nlohmann_json::nlohmann_json) + if(MSVC) if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") target_compile_options(${PROJECT_NAME} PRIVATE From 37fa5bfa1efcbec64fea97c3df0cff2a3fb42268 Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Tue, 30 Apr 2024 18:29:18 -0400 Subject: [PATCH 44/55] find_package spdlog (#17) --- OTRExporter/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OTRExporter/CMakeLists.txt b/OTRExporter/CMakeLists.txt index 39e79d8..e5493eb 100644 --- a/OTRExporter/CMakeLists.txt +++ b/OTRExporter/CMakeLists.txt @@ -169,7 +169,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/tinyxml2 ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/ZAPDUtils ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/StormLib/src - ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/spdlog/include ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src/resource ${CMAKE_CURRENT_SOURCE_DIR}/../../mm/2s2h . @@ -178,6 +177,9 @@ target_include_directories(${PROJECT_NAME} PRIVATE find_package(nlohmann_json REQUIRED) target_link_libraries(${PROJECT_NAME} PUBLIC nlohmann_json::nlohmann_json) +find_package(spdlog REQUIRED) +target_link_libraries(${PROJECT_NAME} PUBLIC spdlog::spdlog) + if(MSVC) if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") target_compile_options(${PROJECT_NAME} PRIVATE From 1d1eeccddb36f8477595d25a90c28ebe083c108a Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Wed, 1 May 2024 12:41:22 -0400 Subject: [PATCH 45/55] fetchcontent stormlib (#18) --- OTRExporter/CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/OTRExporter/CMakeLists.txt b/OTRExporter/CMakeLists.txt index e5493eb..34a7b92 100644 --- a/OTRExporter/CMakeLists.txt +++ b/OTRExporter/CMakeLists.txt @@ -168,7 +168,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/Mercury ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/tinyxml2 ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/ZAPDUtils - ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/StormLib/src ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src/resource ${CMAKE_CURRENT_SOURCE_DIR}/../../mm/2s2h . @@ -180,6 +179,14 @@ target_link_libraries(${PROJECT_NAME} PUBLIC nlohmann_json::nlohmann_json) find_package(spdlog REQUIRED) target_link_libraries(${PROJECT_NAME} PUBLIC spdlog::spdlog) +FetchContent_Declare( + StormLib + GIT_REPOSITORY https://github.com/ladislav-zezula/StormLib.git + GIT_TAG v9.25 +) +FetchContent_MakeAvailable(StormLib) +target_include_directories(${PROJECT_NAME} PRIVATE ${stormlib_SOURCE_DIR}/src) + if(MSVC) if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") target_compile_options(${PROJECT_NAME} PRIVATE From b712c4553f7c5061c45b862d70c380db3c9ff387 Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Wed, 1 May 2024 22:26:53 -0400 Subject: [PATCH 46/55] detangle zapdutils (#19) --- CMakeLists.txt | 4 ---- OTRExporter/CMakeLists.txt | 3 --- 2 files changed, 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 10a66c1..eaaab54 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,8 +88,4 @@ if (NOT TARGET ZAPD) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPD ${CMAKE_BINARY_DIR}/ZAPD) endif() -if (NOT TARGET ZAPDUtils) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/extern/ZAPDUtils ${CMAKE_BINARY_DIR}/ZAPDUtils) -endif() - add_subdirectory(OTRExporter) diff --git a/OTRExporter/CMakeLists.txt b/OTRExporter/CMakeLists.txt index 34a7b92..2305c64 100644 --- a/OTRExporter/CMakeLists.txt +++ b/OTRExporter/CMakeLists.txt @@ -165,9 +165,6 @@ target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern - ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/Mercury - ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/tinyxml2 - ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/extern/ZAPDUtils ${CMAKE_CURRENT_SOURCE_DIR}/../../libultraship/src/resource ${CMAKE_CURRENT_SOURCE_DIR}/../../mm/2s2h . From 044ca4c2970e960d1fa6d00bb7a37b477234bb3d Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Thu, 2 May 2024 13:58:22 -0400 Subject: [PATCH 47/55] support lus strhash64 change (#20) --- OTRExporter/DisplayListExporter.cpp | 2 +- OTRExporter/ExporterArchive.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index 8c4b533..10b89f3 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -3,7 +3,7 @@ #include "../ZAPD/ZFile.h" #include #include -#include "StrHash64/StrHash64.h" +#include #include "spdlog/spdlog.h" #include #include diff --git a/OTRExporter/ExporterArchive.cpp b/OTRExporter/ExporterArchive.cpp index 6b65b39..a5d5c50 100644 --- a/OTRExporter/ExporterArchive.cpp +++ b/OTRExporter/ExporterArchive.cpp @@ -1,6 +1,6 @@ #include "ExporterArchive.h" #include "Utils/StringHelper.h" -#include +#include #include ExporterArchive::ExporterArchive(const std::string& path, bool enableWriting) : mPath(path) { From 281e6a626d795d3e3fcdefa23edae503ac499f6e Mon Sep 17 00:00:00 2001 From: Louis <35883445+louist103@users.noreply.github.com> Date: Tue, 14 May 2024 00:55:51 -0400 Subject: [PATCH 48/55] Use O2R by default --- .gitignore | 1 + OTRExporter/CMakeLists.txt | 4 + OTRExporter/ExporterArchive.cpp | 141 ------- OTRExporter/ExporterArchive.h | 15 +- OTRExporter/ExporterArchiveO2R.cpp | 93 +++++ OTRExporter/ExporterArchiveO2R.h | 24 ++ OTRExporter/ExporterArchiveOTR.cpp | 147 +++++++ OTRExporter/ExporterArchiveOTR.h | 28 ++ OTRExporter/Main.cpp | 622 +++++++++++++++-------------- extract_assets.py | 2 +- 10 files changed, 630 insertions(+), 447 deletions(-) create mode 100644 OTRExporter/ExporterArchiveO2R.cpp create mode 100644 OTRExporter/ExporterArchiveO2R.h create mode 100644 OTRExporter/ExporterArchiveOTR.cpp create mode 100644 OTRExporter/ExporterArchiveOTR.h diff --git a/.gitignore b/.gitignore index 2080ab4..0f4e9a8 100644 --- a/.gitignore +++ b/.gitignore @@ -348,6 +348,7 @@ baserom_ntsc/ *.a *.z64 *.n64 +*.zip Extract/ tmp.txt diff --git a/OTRExporter/CMakeLists.txt b/OTRExporter/CMakeLists.txt index 2305c64..72cc734 100644 --- a/OTRExporter/CMakeLists.txt +++ b/OTRExporter/CMakeLists.txt @@ -16,6 +16,8 @@ set(Header_Files "DisplayListExporter.h" "Exporter.h" "ExporterArchive.h" + "ExporterArchiveO2R.h" + "ExporterArchiveOTR.h" "Main.h" "MtxExporter.h" "PathExporter.h" @@ -46,6 +48,8 @@ set(Source_Files "DisplayListExporter.cpp" "Exporter.cpp" "ExporterArchive.cpp" + "ExporterArchiveO2R.cpp" + "ExporterArchiveOTR.cpp" "Main.cpp" "MtxExporter.cpp" "PathExporter.cpp" diff --git a/OTRExporter/ExporterArchive.cpp b/OTRExporter/ExporterArchive.cpp index a5d5c50..4fdb419 100644 --- a/OTRExporter/ExporterArchive.cpp +++ b/OTRExporter/ExporterArchive.cpp @@ -4,149 +4,8 @@ #include ExporterArchive::ExporterArchive(const std::string& path, bool enableWriting) : mPath(path) { - mMpq = nullptr; - Load(enableWriting); } ExporterArchive::~ExporterArchive() { - Unload(); } -bool ExporterArchive::Load(bool enableWriting) { - HANDLE mpqHandle = NULL; - - bool baseLoaded = false; - std::string fullPath = std::filesystem::absolute(mPath).string(); - - bool openArchiveSuccess; - { - const std::lock_guard lock(mMutex); - openArchiveSuccess = - SFileOpenArchive(fullPath.c_str(), 0, enableWriting ? 0 : MPQ_OPEN_READ_ONLY, &mpqHandle); - } - if (openArchiveSuccess) { - printf("Opened mpq file "); - printf(fullPath.c_str()); - printf("\n"); - mMpq = mpqHandle; - mPath = fullPath; - - - baseLoaded = true; - } - - if (!baseLoaded) { - printf("No valid OTR file was provided."); - return false; - } - - return true; -} - -bool ExporterArchive::Unload() { - bool success = true; - - bool closeArchiveSuccess; - { - const std::lock_guard lock(mMutex); - closeArchiveSuccess = SFileCloseArchive(mMpq); - } - if (!closeArchiveSuccess) { - printf("Failed to close mpq\n"); - success = false; - } - - mMpq = nullptr; - - return success; -} - -std::shared_ptr ExporterArchive::CreateArchive(const std::string& archivePath, size_t fileCapacity) { - auto archive = std::make_shared(archivePath, true); - - bool success; - { - const std::lock_guard lock(archive->mMutex); - success = SFileCreateArchive(archivePath.c_str(), MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES | MPQ_CREATE_ARCHIVE_V2, - fileCapacity, &archive->mMpq); - } - int32_t error = GetLastError(); - - if (success) { - return archive; - } else { - printf("We tried to create an archive, but it has fallen and cannot get up.\n"); - return nullptr; - } -} - -bool ExporterArchive::AddFile(const std::string& filePath, uintptr_t fileData, DWORD fileSize) { - HANDLE hFile; -#ifdef _WIN32 - SYSTEMTIME sysTime; - GetSystemTime(&sysTime); - FILETIME t; - SystemTimeToFileTime(&sysTime, &t); - ULONGLONG theTime = static_cast(t.dwHighDateTime) << (sizeof(t.dwHighDateTime) * 8) | t.dwLowDateTime; -#else - time_t theTime; - time(&theTime); -#endif - - std::string updatedPath = filePath; - - StringHelper::ReplaceOriginal(updatedPath, "\\", "/"); - - bool createFileSuccess; - { - const std::lock_guard lock(mMutex); - createFileSuccess = - SFileCreateFile(mMpq, updatedPath.c_str(), theTime, fileSize, 0, MPQ_FILE_COMPRESS, &hFile); - } - if (!createFileSuccess) { - printf("Failed to create file.\n"); - return false; - } - - bool writeFileSuccess; - { - const std::lock_guard lock(mMutex); - writeFileSuccess = SFileWriteFile(hFile, (void*)fileData, fileSize, MPQ_COMPRESSION_ZLIB); - } - if (!writeFileSuccess) { - printf("Failed to write.\n"); - bool closeFileSuccess; - { - const std::lock_guard lock(mMutex); - closeFileSuccess = SFileCloseFile(hFile); - } - if (!closeFileSuccess) { - printf("Failed to close.\n"); - } - return false; - } - - bool finishFileSuccess; - { - const std::lock_guard lock(mMutex); - finishFileSuccess = SFileFinishFile(hFile); - } - if (!finishFileSuccess) { - printf("Failed to finish file.\n"); - bool closeFileSuccess; - { - const std::lock_guard lock(mMutex); - closeFileSuccess = SFileCloseFile(hFile); - } - if (!closeFileSuccess) { - printf("Failed to close after finish failure.\n"); - } - return false; - } - // SFileFinishFile already frees the handle, so no need to close it again. - - mAddedFiles.push_back(updatedPath); - mHashes[CRC64(updatedPath.c_str())] = updatedPath; - - return true; -} diff --git a/OTRExporter/ExporterArchive.h b/OTRExporter/ExporterArchive.h index fc65444..3070718 100644 --- a/OTRExporter/ExporterArchive.h +++ b/OTRExporter/ExporterArchive.h @@ -11,19 +11,16 @@ class ExporterArchive : public std::enable_shared_from_this { public: + ExporterArchive() {} ExporterArchive(const std::string& path, bool enableWriting); ~ExporterArchive(); - static std::shared_ptr CreateArchive(const std::string& archivePath, size_t fileCapacity); - bool AddFile(const std::string& filePath, uintptr_t fileData, DWORD fileSize); + virtual int CreateArchive(size_t fileCapacity) = 0; + virtual bool AddFile(const std::string& filePath, void* fileData, size_t fileSize) = 0; - private: std::string mPath; - HANDLE mMpq; - std::mutex mMutex; - std::vector mAddedFiles; - std::unordered_map mHashes; + std::mutex mMutex; - bool Load(bool enableWriting); - bool Unload(); + virtual bool Load(bool enableWriting) = 0; + virtual bool Unload() = 0; }; diff --git a/OTRExporter/ExporterArchiveO2R.cpp b/OTRExporter/ExporterArchiveO2R.cpp new file mode 100644 index 0000000..05fb981 --- /dev/null +++ b/OTRExporter/ExporterArchiveO2R.cpp @@ -0,0 +1,93 @@ +#include "ExporterArchiveO2R.h" +#include "Utils/StringHelper.h" +#include +#include +#include + +ExporterArchiveO2R::ExporterArchiveO2R(const std::string& path, bool enableWriting) { + mPath = path; + mZip = nullptr; +} + +ExporterArchiveO2R::~ExporterArchiveO2R() { + Unload(); +} + +bool ExporterArchiveO2R::Load(bool enableWriting) { + int openErr; + zip_t* archive = zip_open(mPath.c_str(), ZIP_CHECKCONS, &openErr); + + if (archive == nullptr) { + zip_error_t error; + zip_error_init_with_code(&error, openErr); + SPDLOG_ERROR("Failed to open ZIP (O2R) file. Error: {}", zip_error_strerror(&error)); + zip_error_fini(&error); + return false; + } + + SPDLOG_INFO("Loaded ZIP (O2R) archive: {}", mPath.c_str()); + mZip = archive; + + return true; +} + +bool ExporterArchiveO2R::Unload() { + printf("Unload\n"); + int err; + { + const std::lock_guard lock(mMutex); + err = zip_close(mZip); + } + if (err < 0) { + zip_error_t* zipError = zip_get_error(mZip); + SPDLOG_ERROR("Failed to close ZIP (O2R) file. Error: {}", zip_error_strerror(zipError)); + printf("fail\n"); + zip_error_fini(zipError); + return false; + } + + return true; +} + +int ExporterArchiveO2R::CreateArchive([[maybe_unused]] size_t fileCapacity) { + int openErr; + zip_t* zip; + + { + const std::lock_guard lock(mMutex); + zip = zip_open(mPath.c_str(), ZIP_CREATE, &openErr); + } + + if (zip == nullptr) { + zip_error_t error; + zip_error_init_with_code(&error, openErr); + SPDLOG_ERROR("Failed to create ZIP (O2R) file. Error: {}", zip_error_strerror(&error)); + zip_error_fini(&error); + return -1; + } + mZip = zip; + SPDLOG_INFO("Loaded ZIP (O2R) archive: {}", mPath.c_str()); + return 0; +} + +bool ExporterArchiveO2R::AddFile(const std::string& filePath, void* fileData, size_t fileSize) { + zip_source_t* source = zip_source_buffer(mZip, fileData, fileSize, 0); + + if (source == nullptr) { + zip_error_t* zipError = zip_get_error(mZip); + SPDLOG_ERROR("Failed to create ZIP source. Error: {}", zip_error_strerror(zipError)); + zip_source_free(source); + zip_error_fini(zipError); + return false; + } + + if (zip_file_add(mZip, filePath.c_str(), source, ZIP_FL_OVERWRITE | ZIP_FL_ENC_UTF_8) < 0) { + zip_error_t* zipError = zip_get_error(mZip); + SPDLOG_ERROR("Failed to add file to ZIP. Error: {}", zip_error_strerror(zipError)); + zip_source_free(source); + zip_error_fini(zipError); + return false; + } + + return true; +} diff --git a/OTRExporter/ExporterArchiveO2R.h b/OTRExporter/ExporterArchiveO2R.h new file mode 100644 index 0000000..2ef57cc --- /dev/null +++ b/OTRExporter/ExporterArchiveO2R.h @@ -0,0 +1,24 @@ +#pragma once + +#undef _DLL + +#include +#include +#include +#include +#include +#include +#include "ExporterArchive.h" + +class ExporterArchiveO2R : public ExporterArchive { + public: + ExporterArchiveO2R(const std::string& path, bool enableWriting); + ~ExporterArchiveO2R(); + + int CreateArchive(size_t fileCapacity) override; + bool AddFile(const std::string& filePath, void* fileData, size_t fileSize) override; + + zip_t* mZip; + bool Load(bool enableWriting) override; + bool Unload() override; +}; diff --git a/OTRExporter/ExporterArchiveOTR.cpp b/OTRExporter/ExporterArchiveOTR.cpp new file mode 100644 index 0000000..91952af --- /dev/null +++ b/OTRExporter/ExporterArchiveOTR.cpp @@ -0,0 +1,147 @@ +#include "ExporterArchiveOTR.h" +#include "Utils/StringHelper.h" +#include +#include + +ExporterArchiveOtr::ExporterArchiveOtr(const std::string& path, bool enableWriting) { + mPath = path; + mMpq = nullptr; +} + +ExporterArchiveOtr::~ExporterArchiveOtr() { + Unload(); +} + +bool ExporterArchiveOtr::Load(bool enableWriting) { + HANDLE mpqHandle = NULL; + + bool baseLoaded = false; + std::string fullPath = std::filesystem::absolute(mPath).string(); + + bool openArchiveSuccess; + { + const std::lock_guard lock(mMutex); + openArchiveSuccess = SFileOpenArchive(fullPath.c_str(), 0, enableWriting ? 0 : MPQ_OPEN_READ_ONLY, &mpqHandle); + } + if (openArchiveSuccess) { + printf("Opened mpq file "); + printf(fullPath.c_str()); + printf("\n"); + mMpq = mpqHandle; + mPath = fullPath; + baseLoaded = true; + } + + if (!baseLoaded) { + printf("No valid OTR file was provided."); + return false; + } + + return true; +} + +bool ExporterArchiveOtr::Unload() { + bool success = true; + + bool closeArchiveSuccess; + { + const std::lock_guard lock(mMutex); + closeArchiveSuccess = SFileCloseArchive(mMpq); + } + if (!closeArchiveSuccess) { + printf("Failed to close mpq\n"); + success = false; + } + + mMpq = nullptr; + + return success; +} + +int ExporterArchiveOtr::CreateArchive(size_t fileCapacity) { + bool success; + { + const std::lock_guard lock(mMutex); + success = SFileCreateArchive(mPath.c_str(), MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES | MPQ_CREATE_ARCHIVE_V2, + static_cast(fileCapacity), &mMpq); + } + int32_t error = GetLastError(); + + if (success) { + return 0; + } else { + printf("We tried to create an archive, but it has fallen and cannot get up.\n"); + return -1; + } +} + +bool ExporterArchiveOtr::AddFile(const std::string& filePath, void* fileData, size_t fileSize) { + HANDLE hFile; +#ifdef _WIN32 + SYSTEMTIME sysTime; + GetSystemTime(&sysTime); + FILETIME t; + SystemTimeToFileTime(&sysTime, &t); + ULONGLONG theTime = static_cast(t.dwHighDateTime) << (sizeof(t.dwHighDateTime) * 8) | t.dwLowDateTime; +#else + time_t theTime; + time(&theTime); +#endif + + std::string updatedPath = filePath; + + StringHelper::ReplaceOriginal(updatedPath, "\\", "/"); + + bool createFileSuccess; + { + const std::lock_guard lock(mMutex); + createFileSuccess = + SFileCreateFile(mMpq, updatedPath.c_str(), theTime, static_cast(fileSize), 0, MPQ_FILE_COMPRESS, &hFile); + } + if (!createFileSuccess) { + printf("Failed to create file.\n"); + return false; + } + + bool writeFileSuccess; + { + const std::lock_guard lock(mMutex); + writeFileSuccess = SFileWriteFile(hFile, fileData, static_cast(fileSize), MPQ_COMPRESSION_ZLIB); + } + if (!writeFileSuccess) { + printf("Failed to write.\n"); + bool closeFileSuccess; + { + const std::lock_guard lock(mMutex); + closeFileSuccess = SFileCloseFile(hFile); + } + if (!closeFileSuccess) { + printf("Failed to close.\n"); + } + return false; + } + + bool finishFileSuccess; + { + const std::lock_guard lock(mMutex); + finishFileSuccess = SFileFinishFile(hFile); + } + if (!finishFileSuccess) { + printf("Failed to finish file.\n"); + bool closeFileSuccess; + { + const std::lock_guard lock(mMutex); + closeFileSuccess = SFileCloseFile(hFile); + } + if (!closeFileSuccess) { + printf("Failed to close after finish failure.\n"); + } + return false; + } + // SFileFinishFile already frees the handle, so no need to close it again. + + mAddedFiles.push_back(updatedPath); + mHashes[CRC64(updatedPath.c_str())] = updatedPath; + + return true; +} diff --git a/OTRExporter/ExporterArchiveOTR.h b/OTRExporter/ExporterArchiveOTR.h new file mode 100644 index 0000000..f9140ff --- /dev/null +++ b/OTRExporter/ExporterArchiveOTR.h @@ -0,0 +1,28 @@ +#pragma once + +#undef _DLL + +#include +#include +#include +#include +#include +#include +#include "ExporterArchive.h" + +class ExporterArchiveOtr : public ExporterArchive { + public: + ExporterArchiveOtr(const std::string& path, bool enableWriting); + ~ExporterArchiveOtr(); + + int CreateArchive(size_t fileCapacity) override; + bool AddFile(const std::string& filePath, void* fileData, size_t fileSize) override; + + bool Load(bool enableWriting) override; + bool Unload() override; + + private: + std::unordered_map mHashes; + std::vector mAddedFiles; + HANDLE mMpq; +}; diff --git a/OTRExporter/Main.cpp b/OTRExporter/Main.cpp index 99e8693..cc312e5 100644 --- a/OTRExporter/Main.cpp +++ b/OTRExporter/Main.cpp @@ -28,8 +28,9 @@ #include #include #include +#include -std::string otrFileName = "mm.otr"; +std::string otrFileName = "mm.zip"; std::string customOtrFileName = ""; std::string customAssetsPath = ""; std::string portVersionString = "0.0.0"; @@ -44,295 +45,324 @@ void InitVersionInfo(); enum class ExporterFileMode { - BuildOTR = (int)ZFileMode::Custom + 1, + BuildOTR = (int)ZFileMode::Custom + 1, }; static void ExporterParseFileMode(const std::string& buildMode, ZFileMode& fileMode) { - if (buildMode == "botr") - { - fileMode = (ZFileMode)ExporterFileMode::BuildOTR; + if (buildMode == "botr") + { + fileMode = (ZFileMode)ExporterFileMode::BuildOTR; - printf("BOTR: Generating OTR Archive...\n"); + printf("BOTR: Generating OTR Archive...\n"); - if (DiskFile::Exists(otrFileName)) - otrArchive = std::shared_ptr(new ExporterArchive(otrFileName, true)); - else - otrArchive = ExporterArchive::CreateArchive(otrFileName, 40000); + otrArchive = std::make_shared(otrFileName, true); - auto lst = Directory::ListFiles("Extract"); + if (DiskFile::Exists(otrFileName)) + otrArchive->Load(true); + else + otrArchive->CreateArchive(40000); - for (auto item : lst) - { - auto fileData = DiskFile::ReadAllBytes(item); - otrArchive->AddFile(StringHelper::Split(item, "Extract/")[1], (uintptr_t)fileData.data(), fileData.size()); - } - } + auto lst = Directory::ListFiles("Extract"); + + for (auto item : lst) + { + auto fileData = DiskFile::ReadAllBytes(item); + otrArchive->AddFile(StringHelper::Split(item, "Extract/")[1], fileData.data(), fileData.size()); + } + } } +typedef struct Data { + std::vector fileData; + std::string filePath; + size_t size; +} Data; + +typedef struct DataU { + std::vector fileData; + std::string filePath; + size_t size; +} DataU; + static void ExporterProgramEnd() { - uint32_t crc = 0xFFFFFFFF; - const uint8_t endianness = (uint8_t)Endianness::Big; - - std::vector portVersion = {}; - std::vector versionParts = StringHelper::Split(portVersionString, "."); - - // If a major.minor.patch string was not passed in, fallback to 0 0 0 - if (versionParts.size() != 3) { - portVersion = { 0, 0, 0 }; - } else { - // Parse version values to number - for (const auto& val : versionParts) { - uint16_t num = 0; - try { - num = (uint16_t)std::stoi(val, nullptr); - } catch (std::invalid_argument &e) { - num = 0; - } catch (std::out_of_range &e) { - num = 0; - } - - portVersion.push_back(num); - } - } - - MemoryStream *portVersionStream = new MemoryStream(); - BinaryWriter portVerWriter(portVersionStream); - portVerWriter.SetEndianness(Endianness::Big); - portVerWriter.Write(endianness); - portVerWriter.Write(portVersion[0]); // Major - portVerWriter.Write(portVersion[1]); // Minor - portVerWriter.Write(portVersion[2]); // Patch - portVerWriter.Close(); - - if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory) - { - std::string romPath = Globals::Instance->baseRomPath.string(); - std::vector romData = DiskFile::ReadAllBytes(romPath); - - BitConverter::RomToBigEndian(romData.data(), romData.size()); - - crc = BitConverter::ToUInt32BE(romData, 0x10); - printf("Creating version file...\n"); - - // Get crc from rom - - MemoryStream *versionStream = new MemoryStream(); - BinaryWriter writer(versionStream); - writer.SetEndianness(Endianness::Big); - writer.Write(endianness); - writer.Write(crc); - writer.Close(); - - printf("Created version file.\n"); - - printf("Generating OTR Archive...\n"); - otrArchive = ExporterArchive::CreateArchive(otrFileName, 40000); - - printf("Adding game version file.\n"); - otrArchive->AddFile("version", (uintptr_t)versionStream->ToVector().data(), versionStream->GetLength()); - - printf("Adding portVersion file.\n"); - otrArchive->AddFile("portVersion", (uintptr_t)portVersionStream->ToVector().data(), portVersionStream->GetLength()); - - for (const auto& item : files) - { - std::string fName = item.first; - if (fName.find("gTitleZeldaShieldLogoMQTex") != std::string::npos && !ZRom(romPath).IsMQ()) - { - size_t pos = 0; - if ((pos = fName.find("gTitleZeldaShieldLogoMQTex", 0)) != std::string::npos) - { - fName.replace(pos, 27, "gTitleZeldaShieldLogoTex"); - } - } - const auto& fileData = item.second; - otrArchive->AddFile(fName, (uintptr_t)fileData.data(), - fileData.size()); - } - } - - otrArchive = nullptr; - delete fileWriter; - files.clear(); - - // Generate custom otr file for extra assets - if (customAssetsPath == "" || customOtrFileName == "" || DiskFile::Exists(customOtrFileName)) { - printf("No Custom Assets path or otr file name provided, otr file already exists. Nothing to do.\n"); - return; - } - - if (!customAssetsPath.ends_with("/")) { - customAssetsPath += "/"; - } - - const auto& lst = Directory::ListFiles(customAssetsPath); - - printf("Generating Custom OTR Archive...\n"); - std::shared_ptr customOtr = ExporterArchive::CreateArchive(customOtrFileName, 4096); - - printf("Adding portVersion file.\n"); - customOtr->AddFile("portVersion", (uintptr_t)portVersionStream->ToVector().data(), portVersionStream->GetLength()); - - for (const auto& item : lst) - { - size_t filenameSepAt = item.find_last_of("/\\"); - const std::string filename = item.substr(filenameSepAt + 1); - - if (std::count(filename.begin(), filename.end(), '.') >= 2) - { - size_t extensionSepAt = filename.find_last_of("."); - size_t formatSepAt = filename.find_last_of(".", extensionSepAt - 1); - - const std::string extension = filename.substr(extensionSepAt + 1); - const std::string format = filename.substr(formatSepAt + 1, extensionSepAt - formatSepAt - 1); - std::string afterPath = item.substr(0, filenameSepAt + formatSepAt + 1); - - if (extension == "png" && (format == "rgba32" || format == "rgb5a1" || format == "i4" || format == "i8" || format == "ia4" || format == "ia8" || format == "ia16" || format == "ci4" || format == "ci8")) - { - ZTexture tex(nullptr); - Globals::Instance->buildRawTexture = true; - tex.FromPNG(item, ZTexture::GetTextureTypeFromString(format)); - printf("customOtr->AddFile(%s)\n", StringHelper::Split(afterPath, customAssetsPath)[1].c_str()); - - OTRExporter_Texture exporter; - - MemoryStream* stream = new MemoryStream(); - BinaryWriter writer(stream); - - exporter.Save(&tex, "", &writer); - - std::string src = tex.GetBodySourceCode(); - writer.Write((char *)src.c_str(), src.size()); - - std::vector fileData = stream->ToVector(); - customOtr->AddFile(StringHelper::Split(afterPath, customAssetsPath)[1], (uintptr_t)fileData.data(), fileData.size()); - continue; - } - } - - if (item.find("accessibility") != std::string::npos) - { - std::string extension = filename.substr(filename.find_last_of(".") + 1); - if (extension == "json") - { - const auto &fileData = DiskFile::ReadAllBytes(item); - printf("Adding accessibility texts %s\n", StringHelper::Split(item, customAssetsPath)[1].c_str()); - customOtr->AddFile(StringHelper::Split(item, customAssetsPath)[1], (uintptr_t)fileData.data(), fileData.size()); - } - continue; - } - - const auto& fileData = DiskFile::ReadAllBytes(item); - printf("customOtr->AddFile(%s)\n", StringHelper::Split(item, customAssetsPath)[1].c_str()); - customOtr->AddFile(StringHelper::Split(item, customAssetsPath)[1], (uintptr_t)fileData.data(), fileData.size()); - } - - customOtr = nullptr; + uint32_t crc = 0xFFFFFFFF; + const uint8_t endianness = (uint8_t)Endianness::Big; + + std::vector portVersion = {}; + std::vector versionParts = StringHelper::Split(portVersionString, "."); + + // If a major.minor.patch string was not passed in, fallback to 0 0 0 + if (versionParts.size() != 3) { + portVersion = { 0, 0, 0 }; + } else { + // Parse version values to number + for (const auto& val : versionParts) { + uint16_t num = 0; + try { + num = (uint16_t)std::stoi(val, nullptr); + } catch (std::invalid_argument &e) { + num = 0; + } catch (std::out_of_range &e) { + num = 0; + } + + portVersion.push_back(num); + } + } + + MemoryStream *portVersionStream = new MemoryStream(); + BinaryWriter portVerWriter(portVersionStream); + portVerWriter.SetEndianness(Endianness::Big); + portVerWriter.Write(endianness); + portVerWriter.Write(portVersion[0]); // Major + portVerWriter.Write(portVersion[1]); // Minor + portVerWriter.Write(portVersion[2]); // Patch + portVerWriter.Close(); + + if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory) + { + std::string romPath = Globals::Instance->baseRomPath.string(); + std::vector romData = DiskFile::ReadAllBytes(romPath); + + BitConverter::RomToBigEndian(romData.data(), romData.size()); + + crc = BitConverter::ToUInt32BE(romData, 0x10); + printf("Creating version file...\n"); + + // Get crc from rom + + MemoryStream *versionStream = new MemoryStream(); + BinaryWriter writer(versionStream); + writer.SetEndianness(Endianness::Big); + writer.Write(endianness); + writer.Write(crc); + writer.Close(); + + printf("Created version file.\n"); + + printf("Generating OTR Archive...\n"); + otrArchive = std::make_shared(otrFileName, true); + otrArchive->CreateArchive(40000); + + printf("Adding game version file.\n"); + otrArchive->AddFile("version", versionStream->ToVector().data(), versionStream->GetLength()); + + printf("Adding portVersion file.\n"); + otrArchive->AddFile("portVersion", portVersionStream->ToVector().data(), portVersionStream->GetLength()); + + for (const auto& item : files) + { + std::string fName = item.first; + if (fName.find("gTitleZeldaShieldLogoMQTex") != std::string::npos && !ZRom(romPath).IsMQ()) + { + size_t pos = 0; + if ((pos = fName.find("gTitleZeldaShieldLogoMQTex", 0)) != std::string::npos) + { + fName.replace(pos, 27, "gTitleZeldaShieldLogoTex"); + } + } + const auto& fileData = item.second; + otrArchive->AddFile(fName, (void*)fileData.data(), fileData.size()); + } + } + + otrArchive = nullptr; + delete fileWriter; + files.clear(); + + // Generate custom otr file for extra assets + if (customAssetsPath == "" || customOtrFileName == "" || DiskFile::Exists(customOtrFileName)) { + printf("No Custom Assets path or otr file name provided, otr file already exists. Nothing to do.\n"); + return; + } + + if (!customAssetsPath.ends_with("/")) { + customAssetsPath += "/"; + } + + const auto& lst = Directory::ListFiles(customAssetsPath); + + printf("Generating Custom OTR Archive...\n"); + auto customOtr = std::make_unique(customOtrFileName, true); + customOtr->CreateArchive(40000); + + printf("Adding portVersion file.\n"); + customOtr->AddFile("portVersion", portVersionStream->ToVector().data(), portVersionStream->GetLength()); + + std::vector dataVec; + std::vector dataVec2; + + + for (const auto& item : lst) + { + size_t filenameSepAt = item.find_last_of("/\\"); + const std::string filename = item.substr(filenameSepAt + 1); + + if (std::count(filename.begin(), filename.end(), '.') >= 2) + { + size_t extensionSepAt = filename.find_last_of("."); + size_t formatSepAt = filename.find_last_of(".", extensionSepAt - 1); + + const std::string extension = filename.substr(extensionSepAt + 1); + const std::string format = filename.substr(formatSepAt + 1, extensionSepAt - formatSepAt - 1); + std::string afterPath = item.substr(0, filenameSepAt + formatSepAt + 1); + + if (extension == "png" && (format == "rgba32" || format == "rgb5a1" || format == "i4" || format == "i8" || format == "ia4" || format == "ia8" || format == "ia16" || format == "ci4" || format == "ci8")) + { + ZTexture tex(nullptr); + Globals::Instance->buildRawTexture = true; + tex.FromPNG(item, ZTexture::GetTextureTypeFromString(format)); + printf("customOtr->AddFile(%s)\n", StringHelper::Split(afterPath, customAssetsPath)[1].c_str()); + + OTRExporter_Texture exporter; + + MemoryStream* stream = new MemoryStream(); + BinaryWriter writer(stream); + + exporter.Save(&tex, "", &writer); + + std::string src = tex.GetBodySourceCode(); + writer.Write((char *)src.c_str(), src.size()); + + std::vector fileData = stream->ToVector(); + dataVec.push_back({ fileData, StringHelper::Split(afterPath, customAssetsPath)[1], fileData.size() }); + continue; + } + } + + if (item.find("accessibility") != std::string::npos) + { + std::string extension = filename.substr(filename.find_last_of(".") + 1); + if (extension == "json") + { + const auto &fileData = DiskFile::ReadAllBytes(item); + printf("Adding accessibility texts %s\n", StringHelper::Split(item, customAssetsPath)[1].c_str()); + dataVec2.push_back({fileData, + StringHelper::Split(item, customAssetsPath)[1], fileData.size() }); + } + continue; + } + + const auto& fileData = DiskFile::ReadAllBytes(item); + printf("customOtr->AddFile(%s)\n", StringHelper::Split(item, customAssetsPath)[1].c_str()); + dataVec2.push_back({ fileData, StringHelper::Split(item, customAssetsPath)[1], fileData.size() }); + } + for (auto& d : dataVec) { + customOtr->AddFile(d.filePath, d.fileData.data(), d.size); + } + + for (auto& d : dataVec2) { + customOtr->AddFile(d.filePath, d.fileData.data(), d.size); + } + + printf("Done\n"); + // For O2Rs the zip file MUST be closed while the vectors are still valid so we need to close the file in this function. + customOtr = nullptr; } static void ExporterParseArgs(int argc, char* argv[], int& i) { - std::string arg = argv[i]; - - if (arg == "--otrfile") { - otrFileName = argv[i + 1]; - i++; - } else if (arg == "--customOtrFile") { - customOtrFileName = argv[i + 1]; - i++; - } else if (arg == "--customAssetsPath") { - customAssetsPath = argv[i + 1]; - i++; - } else if (arg == "--portVer") { - portVersionString = argv[i + 1]; - i++; - } + std::string arg = argv[i]; + + if (arg == "--otrfile") { + otrFileName = argv[i + 1]; + i++; + } else if (arg == "--customOtrFile") { + customOtrFileName = argv[i + 1]; + i++; + } else if (arg == "--customAssetsPath") { + customAssetsPath = argv[i + 1]; + i++; + } else if (arg == "--portVer") { + portVersionString = argv[i + 1]; + i++; + } } static bool ExporterProcessFileMode(ZFileMode fileMode) { - // Do whatever work is associated with these custom file modes... - // Return true to indicate one of our own file modes is being processed - if (fileMode == (ZFileMode)ExporterFileMode::BuildOTR) - return true; + // Do whatever work is associated with these custom file modes... + // Return true to indicate one of our own file modes is being processed + if (fileMode == (ZFileMode)ExporterFileMode::BuildOTR) + return true; - return false; + return false; } static void ExporterFileBegin(ZFile* file) { - fileStart = std::chrono::steady_clock::now(); + fileStart = std::chrono::steady_clock::now(); - MemoryStream* stream = new MemoryStream(); - fileWriter = new BinaryWriter(stream); + MemoryStream* stream = new MemoryStream(); + fileWriter = new BinaryWriter(stream); } static void ExporterFileEnd(ZFile* file) { - // delete fileWriter; + // delete fileWriter; } static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer) { - auto streamShared = writer.GetStream(); - MemoryStream* strem = (MemoryStream*)streamShared.get(); - - auto start = std::chrono::steady_clock::now(); - - if (res->GetName() != "") - { - std::string oName = res->parent->GetOutName(); - std::string rName = res->GetName(); - std::string prefix = OTRExporter_DisplayList::GetPrefix(res); - - //auto xmlFilePath = res->parent->GetXmlFilePath(); - //prefix = StringHelper::Split(StringHelper::Split(xmlFilePath.string(), "xml\\")[1], ".xml")[0]; - - if (StringHelper::Contains(oName, "_scene")) - { - auto split = StringHelper::Split(oName, "_"); - oName = ""; - for (size_t i = 0; i < split.size() - 1; i++) - oName += split[i] + "_"; - - oName += "scene"; - } - else if (StringHelper::Contains(oName, "_room")) - { - if (Globals::Instance->game != ZGame::MM_RETAIL) - oName = StringHelper::Split(oName, "_room")[0] + "_scene"; - else - oName = StringHelper::Split(oName, "_room")[0]; - } - - std::string fName = ""; - - if (prefix != "") - fName = StringHelper::Sprintf("%s/%s/%s", prefix.c_str(), oName.c_str(), rName.c_str()); - else - fName = StringHelper::Sprintf("%s/%s", oName.c_str(), rName.c_str()); - - if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory) - { - std::unique_lock Lock(fileMutex); - files[fName] = strem->ToVector(); - } - else - DiskFile::WriteAllBytes("Extract/" + fName, strem->ToVector()); - } - - auto end = std::chrono::steady_clock::now(); - size_t diff = std::chrono::duration_cast(end - start).count(); - - //if (diff > 10) - //printf("Exported Resource End %s in %zums\n", res->GetName().c_str(), diff); + auto streamShared = writer.GetStream(); + MemoryStream* strem = (MemoryStream*)streamShared.get(); + + auto start = std::chrono::steady_clock::now(); + + if (res->GetName() != "") + { + std::string oName = res->parent->GetOutName(); + std::string rName = res->GetName(); + std::string prefix = OTRExporter_DisplayList::GetPrefix(res); + + //auto xmlFilePath = res->parent->GetXmlFilePath(); + //prefix = StringHelper::Split(StringHelper::Split(xmlFilePath.string(), "xml\\")[1], ".xml")[0]; + + if (StringHelper::Contains(oName, "_scene")) + { + auto split = StringHelper::Split(oName, "_"); + oName = ""; + for (size_t i = 0; i < split.size() - 1; i++) + oName += split[i] + "_"; + + oName += "scene"; + } + else if (StringHelper::Contains(oName, "_room")) + { + if (Globals::Instance->game != ZGame::MM_RETAIL) + oName = StringHelper::Split(oName, "_room")[0] + "_scene"; + else + oName = StringHelper::Split(oName, "_room")[0]; + } + + std::string fName = ""; + + if (prefix != "") + fName = StringHelper::Sprintf("%s/%s/%s", prefix.c_str(), oName.c_str(), rName.c_str()); + else + fName = StringHelper::Sprintf("%s/%s", oName.c_str(), rName.c_str()); + + if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory) + { + std::unique_lock Lock(fileMutex); + files[fName] = strem->ToVector(); + } + else + DiskFile::WriteAllBytes("Extract/" + fName, strem->ToVector()); + } + + auto end = std::chrono::steady_clock::now(); + size_t diff = std::chrono::duration_cast(end - start).count(); + + //if (diff > 10) + //printf("Exported Resource End %s in %zums\n", res->GetName().c_str(), diff); } static void ExporterProcessCompilable(tinyxml2::XMLElement* reader) { - std::string nodeName = reader->Name(); + std::string nodeName = reader->Name(); } static void ExporterXMLBegin() @@ -345,55 +375,55 @@ static void ExporterXMLEnd() void AddFile(std::string fName, std::vector data) { - if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory) - DiskFile::WriteAllBytes("Extract/" + fName, data); - else - { - std::unique_lock Lock(fileMutex); - files[fName] = data; - } + if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory) + DiskFile::WriteAllBytes("Extract/" + fName, data); + else + { + std::unique_lock Lock(fileMutex); + files[fName] = data; + } } void ImportExporters() { - // In this example we set up a new exporter called "EXAMPLE". - // By running ZAPD with the argument -se EXAMPLE, we tell it that we want to use this exporter for our resources. - ExporterSet* exporterSet = new ExporterSet(); - exporterSet->processFileModeFunc = ExporterProcessFileMode; - exporterSet->parseFileModeFunc = ExporterParseFileMode; - exporterSet->processCompilableFunc = ExporterProcessCompilable; - exporterSet->parseArgsFunc = ExporterParseArgs; - exporterSet->beginFileFunc = ExporterFileBegin; - exporterSet->endFileFunc = ExporterFileEnd; - exporterSet->beginXMLFunc = ExporterXMLBegin; - exporterSet->endXMLFunc = ExporterXMLEnd; - exporterSet->resSaveFunc = ExporterResourceEnd; - exporterSet->endProgramFunc = ExporterProgramEnd; - - exporterSet->exporters[ZResourceType::Background] = new OTRExporter_Background(); - exporterSet->exporters[ZResourceType::Texture] = new OTRExporter_Texture(); - exporterSet->exporters[ZResourceType::Room] = new OTRExporter_Room(); - exporterSet->exporters[ZResourceType::AltHeader] = new OTRExporter_Room(); - exporterSet->exporters[ZResourceType::Scene] = new OTRExporter_Room(); - exporterSet->exporters[ZResourceType::CollisionHeader] = new OTRExporter_Collision(); - exporterSet->exporters[ZResourceType::DisplayList] = new OTRExporter_DisplayList(); - exporterSet->exporters[ZResourceType::PlayerAnimationData] = new OTRExporter_PlayerAnimationExporter(); - exporterSet->exporters[ZResourceType::Skeleton] = new OTRExporter_Skeleton(); - exporterSet->exporters[ZResourceType::Limb] = new OTRExporter_SkeletonLimb(); - exporterSet->exporters[ZResourceType::Animation] = new OTRExporter_Animation(); - exporterSet->exporters[ZResourceType::Cutscene] = new OTRExporter_Cutscene(); - exporterSet->exporters[ZResourceType::Vertex] = new OTRExporter_Vtx(); - exporterSet->exporters[ZResourceType::Array] = new OTRExporter_Array(); - exporterSet->exporters[ZResourceType::Path] = new OTRExporter_Path(); - exporterSet->exporters[ZResourceType::Text] = new OTRExporter_Text(); - exporterSet->exporters[ZResourceType::TextMM] = new OTRExporter_TextMM(); - exporterSet->exporters[ZResourceType::Blob] = new OTRExporter_Blob(); - exporterSet->exporters[ZResourceType::Mtx] = new OTRExporter_MtxExporter(); - exporterSet->exporters[ZResourceType::Audio] = new OTRExporter_Audio(); - exporterSet->exporters[ZResourceType::TextureAnimation] = new OTRExporter_TextureAnimation(); + // In this example we set up a new exporter called "EXAMPLE". + // By running ZAPD with the argument -se EXAMPLE, we tell it that we want to use this exporter for our resources. + ExporterSet* exporterSet = new ExporterSet(); + exporterSet->processFileModeFunc = ExporterProcessFileMode; + exporterSet->parseFileModeFunc = ExporterParseFileMode; + exporterSet->processCompilableFunc = ExporterProcessCompilable; + exporterSet->parseArgsFunc = ExporterParseArgs; + exporterSet->beginFileFunc = ExporterFileBegin; + exporterSet->endFileFunc = ExporterFileEnd; + exporterSet->beginXMLFunc = ExporterXMLBegin; + exporterSet->endXMLFunc = ExporterXMLEnd; + exporterSet->resSaveFunc = ExporterResourceEnd; + exporterSet->endProgramFunc = ExporterProgramEnd; + + exporterSet->exporters[ZResourceType::Background] = new OTRExporter_Background(); + exporterSet->exporters[ZResourceType::Texture] = new OTRExporter_Texture(); + exporterSet->exporters[ZResourceType::Room] = new OTRExporter_Room(); + exporterSet->exporters[ZResourceType::AltHeader] = new OTRExporter_Room(); + exporterSet->exporters[ZResourceType::Scene] = new OTRExporter_Room(); + exporterSet->exporters[ZResourceType::CollisionHeader] = new OTRExporter_Collision(); + exporterSet->exporters[ZResourceType::DisplayList] = new OTRExporter_DisplayList(); + exporterSet->exporters[ZResourceType::PlayerAnimationData] = new OTRExporter_PlayerAnimationExporter(); + exporterSet->exporters[ZResourceType::Skeleton] = new OTRExporter_Skeleton(); + exporterSet->exporters[ZResourceType::Limb] = new OTRExporter_SkeletonLimb(); + exporterSet->exporters[ZResourceType::Animation] = new OTRExporter_Animation(); + exporterSet->exporters[ZResourceType::Cutscene] = new OTRExporter_Cutscene(); + exporterSet->exporters[ZResourceType::Vertex] = new OTRExporter_Vtx(); + exporterSet->exporters[ZResourceType::Array] = new OTRExporter_Array(); + exporterSet->exporters[ZResourceType::Path] = new OTRExporter_Path(); + exporterSet->exporters[ZResourceType::Text] = new OTRExporter_Text(); + exporterSet->exporters[ZResourceType::TextMM] = new OTRExporter_TextMM(); + exporterSet->exporters[ZResourceType::Blob] = new OTRExporter_Blob(); + exporterSet->exporters[ZResourceType::Mtx] = new OTRExporter_MtxExporter(); + exporterSet->exporters[ZResourceType::Audio] = new OTRExporter_Audio(); + exporterSet->exporters[ZResourceType::TextureAnimation] = new OTRExporter_TextureAnimation(); exporterSet->exporters[ZResourceType::KeyFrameSkel] = new OTRExporter_CKeyFrameSkel(); exporterSet->exporters[ZResourceType::KeyFrameAnimation] = new OTRExporter_CKeyFrameAnim(); - Globals::AddExporter("OTR", exporterSet); + Globals::AddExporter("OTR", exporterSet); - InitVersionInfo(); + InitVersionInfo(); } diff --git a/extract_assets.py b/extract_assets.py index bc32572..2e8dc61 100755 --- a/extract_assets.py +++ b/extract_assets.py @@ -21,7 +21,7 @@ def BuildOTR(xmlPath, rom, zapd_exe=None, genHeaders=None, customAssetsPath=None else: # generate otrs, but not headers exec_cmd.extend(["-gsf", "0", "-se", "OTR", "--customAssetsPath", customAssetsPath, - "--customOtrFile", customOtrFile, "--otrfile", "mm.otr"]) + "--customOtrFile", customOtrFile, "--otrfile", "mm.zip"]) if portVer: exec_cmd.extend(["--portVer", portVer]) From c2a891be8ba1d33e09ee39eb4bf1c95e3b753e0e Mon Sep 17 00:00:00 2001 From: Archez Date: Mon, 20 May 2024 07:20:56 -0400 Subject: [PATCH 49/55] fix version file buffers not staying alive during o2r unload close (#26) --- OTRExporter/Main.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/OTRExporter/Main.cpp b/OTRExporter/Main.cpp index cc312e5..795e3fb 100644 --- a/OTRExporter/Main.cpp +++ b/OTRExporter/Main.cpp @@ -120,7 +120,7 @@ static void ExporterProgramEnd() portVerWriter.Write(portVersion[1]); // Minor portVerWriter.Write(portVersion[2]); // Patch portVerWriter.Close(); - + if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory) { std::string romPath = Globals::Instance->baseRomPath.string(); @@ -147,10 +147,12 @@ static void ExporterProgramEnd() otrArchive->CreateArchive(40000); printf("Adding game version file.\n"); - otrArchive->AddFile("version", versionStream->ToVector().data(), versionStream->GetLength()); + auto versionStreamBuffer = versionStream->ToVector(); + otrArchive->AddFile("version", (void*)versionStreamBuffer.data(), versionStream->GetLength()); printf("Adding portVersion file.\n"); - otrArchive->AddFile("portVersion", portVersionStream->ToVector().data(), portVersionStream->GetLength()); + auto portVersionStreamBuffer = portVersionStream->ToVector(); + otrArchive->AddFile("portVersion", (void*)portVersionStreamBuffer.data(), portVersionStream->GetLength()); for (const auto& item : files) { @@ -166,9 +168,10 @@ static void ExporterProgramEnd() const auto& fileData = item.second; otrArchive->AddFile(fName, (void*)fileData.data(), fileData.size()); } + + otrArchive = nullptr; } - otrArchive = nullptr; delete fileWriter; files.clear(); From 287c79891882df5a0797cd9d39c0dcb97af9f007 Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Thu, 30 May 2024 21:04:44 -0400 Subject: [PATCH 50/55] Added F3DEX_GBI_2 Since OTRExporter only supports that gbi (#21) (#27) Co-authored-by: Lywx --- OTRExporter/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OTRExporter/CMakeLists.txt b/OTRExporter/CMakeLists.txt index 72cc734..901733a 100644 --- a/OTRExporter/CMakeLists.txt +++ b/OTRExporter/CMakeLists.txt @@ -255,6 +255,9 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|AppleClang") $<$:-Wno-deprecated-enum-enum-conversion> ) endif() + +target_compile_definitions(${PROJECT_NAME} PUBLIC -DF3DEX_GBI_2) + ################################################################################ # Dependencies ################################################################################ @@ -264,4 +267,3 @@ add_dependencies(${PROJECT_NAME} # Link with other targets. target_link_libraries(${PROJECT_NAME} PUBLIC "${ADDITIONAL_LIBRARY_DEPENDENCIES}") - From 375489d5f1f5fa4b9144ac9669c411e3b149f32a Mon Sep 17 00:00:00 2001 From: Archez Date: Mon, 17 Jun 2024 14:26:33 -0400 Subject: [PATCH 51/55] support LUS not having an array resource type (#26) (#28) --- OTRExporter/ArrayExporter.cpp | 2 +- OTRExporter/DisplayListExporter.cpp | 2 +- OTRExporter/VersionInfo.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OTRExporter/ArrayExporter.cpp b/OTRExporter/ArrayExporter.cpp index 2ff186f..ed9ee40 100644 --- a/OTRExporter/ArrayExporter.cpp +++ b/OTRExporter/ArrayExporter.cpp @@ -5,7 +5,7 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit { ZArray* arr = (ZArray*)res; - WriteHeader(res, outPath, writer, static_cast(LUS::ResourceType::Array)); + WriteHeader(res, outPath, writer, static_cast(SOH::ResourceType::SOH_Array)); writer->Write((uint32_t)arr->resList[0]->GetResourceType()); writer->Write((uint32_t)arr->arrayCnt); diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index 10b89f3..7ea0641 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -895,7 +895,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina } // OTRTODO: Once we aren't relying on text representations, we should call ArrayExporter... - OTRExporter::WriteHeader(nullptr, "", &vtxWriter, static_cast(LUS::ResourceType::Array)); + OTRExporter::WriteHeader(nullptr, "", &vtxWriter, static_cast(SOH::ResourceType::SOH_Array)); vtxWriter.Write((uint32_t)ZResourceType::Vertex); vtxWriter.Write((uint32_t)arrCnt); diff --git a/OTRExporter/VersionInfo.cpp b/OTRExporter/VersionInfo.cpp index 7e643d5..459747d 100644 --- a/OTRExporter/VersionInfo.cpp +++ b/OTRExporter/VersionInfo.cpp @@ -19,7 +19,7 @@ void InitVersionInfo() { static_cast(SOH::ResourceType::SOH_Path), 0 }, { static_cast(LUS::ResourceType::Vertex), 0 }, { static_cast(SOH::ResourceType::SOH_Cutscene), 0 }, - { static_cast(LUS::ResourceType::Array), 0 }, + { static_cast(SOH::ResourceType::SOH_Array), 0 }, { static_cast(SOH::ResourceType::SOH_Text), 0 }, { static_cast(LUS::ResourceType::Blob), 0 }, }; From 854685155a6addaf72ec2415ac481a08ace9f9ce Mon Sep 17 00:00:00 2001 From: Archez Date: Fri, 6 Sep 2024 23:59:31 -0400 Subject: [PATCH 52/55] Export additional data types on arrays (#30) * export additional data types on arrays * add o2r git ignore --- .gitignore | 1 + OTRExporter/ArrayExporter.cpp | 30 +++++++++++++++++++----------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 0f4e9a8..3f5299d 100644 --- a/.gitignore +++ b/.gitignore @@ -344,6 +344,7 @@ baserom/ baserom_ntsc/ *.vtx.inc *.otr +*.o2r *.swp *.a *.z64 diff --git a/OTRExporter/ArrayExporter.cpp b/OTRExporter/ArrayExporter.cpp index ed9ee40..10c2faf 100644 --- a/OTRExporter/ArrayExporter.cpp +++ b/OTRExporter/ArrayExporter.cpp @@ -37,28 +37,32 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit // OTRTODO: Duplicate code here. Cleanup at a later date... switch (vec->scalarType) { - case ZScalarType::ZSCALAR_U8: - writer->Write(vec->scalars[k].scalarData.u8); - break; case ZScalarType::ZSCALAR_S8: writer->Write(vec->scalars[k].scalarData.s8); break; - case ZScalarType::ZSCALAR_U16: - writer->Write(vec->scalars[k].scalarData.u16); + case ZScalarType::ZSCALAR_U8: + case ZScalarType::ZSCALAR_X8: + writer->Write(vec->scalars[k].scalarData.u8); break; case ZScalarType::ZSCALAR_S16: writer->Write(vec->scalars[k].scalarData.s16); break; + case ZScalarType::ZSCALAR_U16: + case ZScalarType::ZSCALAR_X16: + writer->Write(vec->scalars[k].scalarData.u16); + break; case ZScalarType::ZSCALAR_S32: writer->Write(vec->scalars[k].scalarData.s32); break; case ZScalarType::ZSCALAR_U32: + case ZScalarType::ZSCALAR_X32: writer->Write(vec->scalars[k].scalarData.u32); break; case ZScalarType::ZSCALAR_S64: writer->Write(vec->scalars[k].scalarData.s64); break; case ZScalarType::ZSCALAR_U64: + case ZScalarType::ZSCALAR_X64: writer->Write(vec->scalars[k].scalarData.u64); break; // OTRTODO: ADD OTHER TYPES @@ -75,28 +79,32 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit switch (scal->scalarType) { - case ZScalarType::ZSCALAR_U8: - writer->Write(scal->scalarData.u8); - break; case ZScalarType::ZSCALAR_S8: writer->Write(scal->scalarData.s8); break; - case ZScalarType::ZSCALAR_U16: - writer->Write(scal->scalarData.u16); + case ZScalarType::ZSCALAR_U8: + case ZScalarType::ZSCALAR_X8: + writer->Write(scal->scalarData.u8); break; case ZScalarType::ZSCALAR_S16: writer->Write(scal->scalarData.s16); break; + case ZScalarType::ZSCALAR_U16: + case ZScalarType::ZSCALAR_X16: + writer->Write(scal->scalarData.u16); + break; case ZScalarType::ZSCALAR_S32: writer->Write(scal->scalarData.s32); break; case ZScalarType::ZSCALAR_U32: + case ZScalarType::ZSCALAR_X32: writer->Write(scal->scalarData.u32); break; case ZScalarType::ZSCALAR_S64: writer->Write(scal->scalarData.s64); break; case ZScalarType::ZSCALAR_U64: + case ZScalarType::ZSCALAR_X64: writer->Write(scal->scalarData.u64); break; // OTRTODO: ADD OTHER TYPES @@ -105,4 +113,4 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit } } } -} \ No newline at end of file +} From 4271bc1bc6958f4fe61c881194fbbeda6cceb55d Mon Sep 17 00:00:00 2001 From: Archez Date: Fri, 8 Nov 2024 23:22:33 -0500 Subject: [PATCH 53/55] Fix portVersion file in custom otr having garbage data (#33) --- OTRExporter/Main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OTRExporter/Main.cpp b/OTRExporter/Main.cpp index 795e3fb..0941356 100644 --- a/OTRExporter/Main.cpp +++ b/OTRExporter/Main.cpp @@ -192,7 +192,8 @@ static void ExporterProgramEnd() customOtr->CreateArchive(40000); printf("Adding portVersion file.\n"); - customOtr->AddFile("portVersion", portVersionStream->ToVector().data(), portVersionStream->GetLength()); + auto portVersionStreamBuffer = portVersionStream->ToVector(); + customOtr->AddFile("portVersion", (void*)portVersionStreamBuffer.data(), portVersionStream->GetLength()); std::vector dataVec; std::vector dataVec2; From d2fd3202b47e6d46367bd43a72b3c20b69935be6 Mon Sep 17 00:00:00 2001 From: Lywx Date: Sat, 11 Jan 2025 16:07:25 -0600 Subject: [PATCH 54/55] Added support to latest LUS (#32) --- OTRExporter/DisplayListExporter.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OTRExporter/DisplayListExporter.cpp b/OTRExporter/DisplayListExporter.cpp index 7ea0641..dab35fa 100644 --- a/OTRExporter/DisplayListExporter.cpp +++ b/OTRExporter/DisplayListExporter.cpp @@ -46,6 +46,8 @@ { (_SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(xh, 12, 12) | _SHIFTL(yh, 0, 12)),\ (_SHIFTL(tile, 24, 3) | _SHIFTL(xl, 12, 12) | _SHIFTL(yl, 0, 12)) } +#define UCODE_F3DEX2 (int8_t) 4 + void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) { ZDisplayList* dList = (ZDisplayList*)res; @@ -53,6 +55,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina //printf("Exporting DList %s\n", dList->GetName().c_str()); WriteHeader(res, outPath, writer, static_cast(LUS::ResourceType::DisplayList)); + writer->Write(UCODE_F3DEX2); while (writer->GetBaseAddress() % 8 != 0) writer->Write((uint8_t)0xFF); From 9897bc94707fd4ccbbae5e93a100ccdac4d26f0f Mon Sep 17 00:00:00 2001 From: louist103 <35883445+louist103@users.noreply.github.com> Date: Sat, 11 Jan 2025 17:10:14 -0500 Subject: [PATCH 55/55] Export audio assets as XML (#29) * WIP * Fix spelling * Fix mac * Fix binary for V2 * fix sample exporting (#31) * Sample XMLs. Needs importer to test * Fix names * fix sample exporting * Cleanups * Fix mac * fix binary samples * Update for torch format --- OTRExporter/AudioExporter.cpp | 600 +++++++++++++++++++++++++--------- OTRExporter/AudioExporter.h | 27 +- 2 files changed, 463 insertions(+), 164 deletions(-) diff --git a/OTRExporter/AudioExporter.cpp b/OTRExporter/AudioExporter.cpp index f79b23f..ee82980 100644 --- a/OTRExporter/AudioExporter.cpp +++ b/OTRExporter/AudioExporter.cpp @@ -5,187 +5,469 @@ #include #include "DisplayListExporter.h" -void OTRExporter_Audio::WriteSampleEntryReference(ZAudio* audio, SampleEntry* entry, std::map samples, BinaryWriter* writer) +const char* OTRExporter_Audio::GetMediumStr(uint8_t medium) { + switch (medium) { + case 0: + return "Ram"; + case 1: + return "Unk"; + case 2: + return "Cart"; + case 3: + return "Disk"; + case 5: + return "RamUnloaded"; + default: + return "ERROR"; + } +} + +const char* OTRExporter_Audio::GetCachePolicyStr(uint8_t policy) { + switch (policy) { + case 0: + return "Temporary"; + case 1: + return "Persistent"; + case 2: + return "Either"; + case 3: + return "Permanent"; + default: + return "ERROR"; + } +} + +const char* OTRExporter_Audio::GetCodecStr(uint8_t codec) { + switch (codec) { + case 0: + return "ADPCM"; + case 1: + return "S8"; + case 2: + return "S16MEM"; + case 3: + return "ADPCMSMALL"; + case 4: + return "REVERB"; + case 5: + return "S16"; + case 6: + return "UNK6"; + case 7: + return "UNK7"; + default: + return "ERROR"; + } +} + +std::string OTRExporter_Audio::GetSampleEntryReference(ZAudio* audio, SampleEntry* entry) { - writer->Write((uint8_t)(entry != nullptr ? 1 : 0)); - - if (entry != nullptr) - { - if (audio->sampleOffsets[entry->bankId].find(entry->sampleLoopOffset) != audio->sampleOffsets[entry->bankId].end()) - { - if (audio->sampleOffsets[entry->bankId][entry->sampleLoopOffset].find(entry->sampleDataOffset) != audio->sampleOffsets[entry->bankId][entry->sampleLoopOffset].end()) - { - writer->Write(StringHelper::Sprintf("audio/samples/%s", audio->sampleOffsets[entry->bankId][entry->sampleLoopOffset][entry->sampleDataOffset].c_str())); - } - else - writer->Write(entry->fileName); - } - else - writer->Write(entry->fileName); - } - else - writer->Write(""); + if (entry != nullptr) + { + if (audio->sampleOffsets[entry->bankId].contains(entry->sampleDataOffset) && + audio->sampleOffsets[entry->bankId][entry->sampleDataOffset] != "") { + return (StringHelper::Sprintf("audio/samples/%s_META", + audio->sampleOffsets[entry->bankId][entry->sampleDataOffset].c_str())); + } + else + return StringHelper::Sprintf("audio/samples/sample_%d_%08X_META", entry->bankId, entry->sampleDataOffset); + } + else + return(""); } void OTRExporter_Audio::WriteSampleEntry(SampleEntry* entry, BinaryWriter* writer) { - WriteHeader(nullptr, "", writer, static_cast(SOH::ResourceType::SOH_AudioSample), 2); + WriteHeader(nullptr, "", writer, static_cast(SOH::ResourceType::SOH_AudioSample), 2); + + writer->Write(entry->codec); + writer->Write(entry->medium); + writer->Write(entry->unk_bit26); + writer->Write(entry->unk_bit25); + + writer->Write((uint32_t)entry->data.size()); + writer->Write((char*)entry->data.data(), entry->data.size()); - writer->Write(entry->codec); - writer->Write(entry->medium); - writer->Write(entry->unk_bit26); - writer->Write(entry->unk_bit25); + writer->Write((uint32_t)(entry->loop.start)); + writer->Write((uint32_t)(entry->loop.end)); + writer->Write((uint32_t)(entry->loop.count)); + writer->Write((uint32_t)entry->loop.states.size()); - writer->Write((uint32_t)entry->data.size()); - writer->Write((char*)entry->data.data(), entry->data.size()); + for (size_t i = 0; i < entry->loop.states.size(); i++) + writer->Write((entry->loop.states[i])); - writer->Write((uint32_t)(entry->loop.start)); - writer->Write((uint32_t)(entry->loop.end)); - writer->Write((uint32_t)(entry->loop.count)); - writer->Write((uint32_t)entry->loop.states.size()); + writer->Write((uint32_t)(entry->book.order)); + writer->Write((uint32_t)(entry->book.npredictors)); + writer->Write((uint32_t)entry->book.books.size()); - for (size_t i = 0; i < entry->loop.states.size(); i++) - writer->Write((entry->loop.states[i])); + for (size_t i = 0; i < entry->book.books.size(); i++) + writer->Write((entry->book.books[i])); +} - writer->Write((uint32_t)(entry->book.order)); - writer->Write((uint32_t)(entry->book.npredictors)); - writer->Write((uint32_t)entry->book.books.size()); +void OTRExporter_Audio::WriteSampleEntry(SampleEntry* entry, tinyxml2::XMLElement* xmlDoc) { + tinyxml2::XMLElement* sEntry = xmlDoc; + + sEntry->SetAttribute("Codec", GetCodecStr(entry->codec)); + sEntry->SetAttribute("Medium", GetMediumStr(entry->medium)); + sEntry->SetAttribute("bit26", entry->unk_bit26); + sEntry->SetAttribute("Relocated", entry->unk_bit25); + + tinyxml2::XMLElement* loopRoot = sEntry->InsertNewChildElement("ADPCMLoop"); + loopRoot->SetAttribute("Start", entry->loop.start); + loopRoot->SetAttribute("End", entry->loop.end); + loopRoot->SetAttribute("Count", (int)entry->loop.count); // Cast to int to -1 shows as -1. + + for (size_t i = 0; i < entry->loop.states.size(); i++) { + tinyxml2::XMLElement* loop = loopRoot->InsertNewChildElement("Predictor"); + loop->SetAttribute("State", entry->loop.states[i]); + loopRoot->InsertEndChild(loop); + } + sEntry->InsertEndChild(loopRoot); + + tinyxml2::XMLElement* bookRoot = sEntry->InsertNewChildElement("ADPCMBook"); + bookRoot->SetAttribute("Order", entry->book.order); + bookRoot->SetAttribute("Npredictors", entry->book.npredictors); + + for (size_t i = 0; i < entry->book.books.size(); i++) { + tinyxml2::XMLElement* book = bookRoot->InsertNewChildElement("Book"); + book->SetAttribute("Page", entry->book.books[i]); + bookRoot->InsertEndChild(book); + } + sEntry->InsertEndChild(bookRoot); - for (size_t i = 0; i < entry->book.books.size(); i++) - writer->Write((entry->book.books[i])); } -void OTRExporter_Audio::WriteSoundFontEntry(ZAudio* audio, SoundFontEntry* entry, std::map samples, BinaryWriter* writer) +void OTRExporter_Audio::WriteSoundFontEntry(ZAudio* audio, SoundFontEntry* entry, BinaryWriter* writer) { - writer->Write((uint8_t)(entry != nullptr ? 1 : 0)); + writer->Write((uint8_t)(entry != nullptr ? 1 : 0)); + + if (entry != nullptr) + { + // This second byte isn't used but is needed to maintain compatibility with the V2 format. + writer->Write((uint8_t)(entry != nullptr ? 1 : 0)); + writer->Write(GetSampleEntryReference(audio, entry->sampleEntry)); + writer->Write(entry->tuning); + } +} - if (entry != nullptr) - { - WriteSampleEntryReference(audio, entry->sampleEntry, samples, writer); - writer->Write(entry->tuning); - } +void OTRExporter_Audio::WriteSoundFontEntry(ZAudio* audio, SoundFontEntry* entry, tinyxml2::XMLElement* xmlDoc, + const char* name) { + tinyxml2::XMLElement* sfEntry = xmlDoc->InsertNewChildElement(name); + + if (entry != nullptr) + { + sfEntry->SetAttribute("SampleRef", GetSampleEntryReference(audio, entry->sampleEntry).c_str()); + sfEntry->SetAttribute("Tuning", entry->tuning); + } + xmlDoc->InsertEndChild(sfEntry); } void OTRExporter_Audio::WriteEnvData(std::vector envelopes, BinaryWriter* writer) { - writer->Write((uint32_t)envelopes.size()); + writer->Write((uint32_t)envelopes.size()); + + for (auto env : envelopes) + { + writer->Write(env->delay); + writer->Write(env->arg); + } +} + +void OTRExporter_Audio::WriteEnvData(std::vector envelopes, tinyxml2::XMLElement* xmlDoc) { + tinyxml2::XMLElement* envs = xmlDoc->InsertNewChildElement("Envelopes"); + envs->SetAttribute("Count", (uint32_t)envelopes.size()); + + for (auto e : envelopes) { + tinyxml2::XMLElement* env = envs->InsertNewChildElement("Envelope"); + env->SetAttribute("Delay", e->delay); + env->SetAttribute("Arg", e->arg); + } + xmlDoc->InsertEndChild(envs); +} + + +void OTRExporter_Audio::WriteSoundFontTableXML(ZAudio* audio) { + for (size_t i = 0; i < audio->soundFontTable.size(); i++) { + tinyxml2::XMLDocument soundFont; + tinyxml2::XMLElement* root = soundFont.NewElement("SoundFont"); + root->SetAttribute("Version", 0); + root->SetAttribute("Num", (uint32_t)i); + root->SetAttribute("Medium", GetMediumStr(audio->soundFontTable[i].medium)); + root->SetAttribute("CachePolicy", GetCachePolicyStr(audio->soundFontTable[i].cachePolicy)); + root->SetAttribute("Data1", audio->soundFontTable[i].data1); + root->SetAttribute("Data2", audio->soundFontTable[i].data2); + root->SetAttribute("Data3", audio->soundFontTable[i].data3); + soundFont.InsertFirstChild(root); + + tinyxml2::XMLElement* drums = root->InsertNewChildElement("Drums"); + drums->SetAttribute("Count", (uint32_t)audio->soundFontTable[i].drums.size()); + + for (const auto& d : audio->soundFontTable[i].drums) { + tinyxml2::XMLElement* drum = drums->InsertNewChildElement("Drum"); + drum->SetAttribute("ReleaseRate", d.releaseRate); + drum->SetAttribute("Pan", d.pan); + drum->SetAttribute("Loaded", d.loaded); + drum->SetAttribute("SampleRef", GetSampleEntryReference(audio, d.sample).c_str()); + drum->SetAttribute("Tuning", d.tuning); + + WriteEnvData(d.env, drum); + drums->InsertEndChild(drum); + } + root->InsertEndChild(drums); + + tinyxml2::XMLElement* instruments = root->InsertNewChildElement("Instruments"); + instruments->SetAttribute("Count", (uint32_t)audio->soundFontTable[i].instruments.size()); + + //for (size_t k = 0; k < audio->soundFontTable[i].instruments.size(); k++) { + for (const auto i : audio->soundFontTable[i].instruments) { + tinyxml2::XMLElement* instrument = instruments->InsertNewChildElement("Instrument"); + + instrument->SetAttribute("IsValid", i.isValidInstrument); + instrument->SetAttribute("Loaded", i.loaded); + instrument->SetAttribute("NormalRangeLo", i.normalRangeLo); + instrument->SetAttribute("NormalRangeHi", i.normalRangeHi); + instrument->SetAttribute("ReleaseRate", i.releaseRate); + + WriteEnvData(i.env, instrument); + + WriteSoundFontEntry(audio, i.lowNotesSound, instrument, "LowNotesSound"); + WriteSoundFontEntry(audio, i.normalNotesSound, instrument, "NormalNotesSound"); + WriteSoundFontEntry(audio, i.highNotesSound, instrument, "HighNotesSound"); + } + root->InsertEndChild(instruments); + + tinyxml2::XMLElement* sfxTbl = root->InsertNewChildElement("SfxTable"); + sfxTbl->SetAttribute("Count", (uint32_t)audio->soundFontTable[i].soundEffects.size()); + + for (const auto s : audio->soundFontTable[i].soundEffects) { + WriteSoundFontEntry(audio, s, sfxTbl, "Sfx"); + } + root->InsertEndChild(sfxTbl); + soundFont.InsertEndChild(root); + + tinyxml2::XMLPrinter printer; + soundFont.Accept(&printer); + + std::string fName = OTRExporter_DisplayList::GetPathToRes( + (ZResource*)(audio), StringHelper::Sprintf("fonts/%s", audio->soundFontNames[i].c_str())); + std::vector xmlData((printer.CStr()), printer.CStr() + printer.CStrSize() - 1); + AddFile(fName, xmlData); + } +} + +void OTRExporter_Audio::WriteSoundFontTableBinary(ZAudio* audio) { + for (size_t i = 0; i < audio->soundFontTable.size(); i++) { + MemoryStream* fntStream = new MemoryStream(); + BinaryWriter fntWriter = BinaryWriter(fntStream); + + WriteHeader(nullptr, "", &fntWriter, static_cast(SOH::ResourceType::SOH_AudioSoundFont), 2); + + fntWriter.Write((uint32_t)i); + fntWriter.Write(audio->soundFontTable[i].medium); + fntWriter.Write(audio->soundFontTable[i].cachePolicy); + fntWriter.Write(audio->soundFontTable[i].data1); + fntWriter.Write(audio->soundFontTable[i].data2); + fntWriter.Write(audio->soundFontTable[i].data3); + + fntWriter.Write((uint32_t)audio->soundFontTable[i].drums.size()); + fntWriter.Write((uint32_t)audio->soundFontTable[i].instruments.size()); + fntWriter.Write((uint32_t)audio->soundFontTable[i].soundEffects.size()); + + for (size_t k = 0; k < audio->soundFontTable[i].drums.size(); k++) { + fntWriter.Write(audio->soundFontTable[i].drums[k].releaseRate); + fntWriter.Write(audio->soundFontTable[i].drums[k].pan); + fntWriter.Write(audio->soundFontTable[i].drums[k].loaded); + + WriteEnvData(audio->soundFontTable[i].drums[k].env, &fntWriter); + fntWriter.Write((uint8_t)(audio->soundFontTable[i].drums[k].sample != nullptr ? 1 : 0)); + + fntWriter.Write(GetSampleEntryReference(audio, audio->soundFontTable[i].drums[k].sample)); + fntWriter.Write(audio->soundFontTable[i].drums[k].tuning); + } + + for (size_t k = 0; k < audio->soundFontTable[i].instruments.size(); k++) { + fntWriter.Write((uint8_t)audio->soundFontTable[i].instruments[k].isValidInstrument); + + fntWriter.Write(audio->soundFontTable[i].instruments[k].loaded); + fntWriter.Write(audio->soundFontTable[i].instruments[k].normalRangeLo); + fntWriter.Write(audio->soundFontTable[i].instruments[k].normalRangeHi); + fntWriter.Write(audio->soundFontTable[i].instruments[k].releaseRate); + + WriteEnvData(audio->soundFontTable[i].instruments[k].env, &fntWriter); + + WriteSoundFontEntry(audio, audio->soundFontTable[i].instruments[k].lowNotesSound, &fntWriter); + WriteSoundFontEntry(audio, audio->soundFontTable[i].instruments[k].normalNotesSound, &fntWriter); + WriteSoundFontEntry(audio, audio->soundFontTable[i].instruments[k].highNotesSound, &fntWriter); + } + + for (size_t k = 0; k < audio->soundFontTable[i].soundEffects.size(); k++) { + WriteSoundFontEntry(audio, audio->soundFontTable[i].soundEffects[k], &fntWriter); + } + + std::string fName = OTRExporter_DisplayList::GetPathToRes( + (ZResource*)(audio), StringHelper::Sprintf("fonts/%s", audio->soundFontNames[i].c_str())); + AddFile(fName, fntStream->ToVector()); + } +} + +void OTRExporter_Audio::WriteSequenceXML(ZAudio* audio) { + for (size_t i = 0; i < audio->sequences.size(); i++) { + MemoryStream* seqStream = new MemoryStream(); + BinaryWriter seqWriter = BinaryWriter(seqStream); + auto& seq = audio->sequences[i]; + + tinyxml2::XMLDocument sequence; + tinyxml2::XMLElement* root = sequence.NewElement("Sequence"); + root->SetAttribute("Index", (uint32_t)i); + root->SetAttribute("Medium", GetMediumStr(audio->sequenceTable[i].medium)); + root->SetAttribute("CachePolicy", GetCachePolicyStr(audio->sequenceTable[i].cachePolicy)); + root->SetAttribute("Size", (uint32_t)seq.size()); + + std::string seqName = OTRExporter_DisplayList::GetPathToRes( + (ZResource*)(audio), StringHelper::Sprintf("sequencedata/%s_RAW", audio->seqNames[i].c_str())); + root->SetAttribute("Path", seqName.c_str()); + + + tinyxml2::XMLElement* fontIndicies = root->InsertNewChildElement("FontIndicies"); + for (size_t k = 0; k < audio->fontIndices[i].size(); k++) { + tinyxml2::XMLElement* fontIndex = fontIndicies->InsertNewChildElement("FontIndex"); + fontIndex->SetAttribute("FontIdx", audio->fontIndices[i][k]); + + } + root->InsertEndChild(fontIndicies); + root->InsertEndChild(root); + sequence.InsertEndChild(root); + seqWriter.Write(seq.data(), seq.size()); + AddFile(seqName, seqStream->ToVector()); + + tinyxml2::XMLPrinter printer; + sequence.Accept(&printer); + + + std::string seqMetaName = OTRExporter_DisplayList::GetPathToRes( + (ZResource*)(audio), StringHelper::Sprintf("sequences/%s_META", audio->seqNames[i].c_str())); + std::vector xmlData((printer.CStr()), printer.CStr() + printer.CStrSize() - 1); + AddFile(seqMetaName, xmlData); + } +} + +void OTRExporter_Audio::WriteSequenceBinary(ZAudio* audio) { + for (size_t i = 0; i < audio->sequences.size(); i++) { + auto& seq = audio->sequences[i]; + + MemoryStream* seqStream = new MemoryStream(); + BinaryWriter seqWriter = BinaryWriter(seqStream); + + WriteHeader(nullptr, "", &seqWriter, static_cast(SOH::ResourceType::SOH_AudioSequence), 2); + + seqWriter.Write((uint32_t)seq.size()); + seqWriter.Write(seq.data(), seq.size()); + seqWriter.Write((uint8_t)i); + seqWriter.Write((uint8_t)audio->sequenceTable[i].medium); + seqWriter.Write((uint8_t)audio->sequenceTable[i].cachePolicy); + seqWriter.Write((uint32_t)audio->fontIndices[i].size()); + + for (size_t k = 0; k < audio->fontIndices[i].size(); k++) + seqWriter.Write((uint8_t)audio->fontIndices[i][k]); + + std::string fName = OTRExporter_DisplayList::GetPathToRes( + (ZResource*)(audio), StringHelper::Sprintf("sequences/%s", audio->seqNames[i].c_str())); + AddFile(fName, seqStream->ToVector()); + } +} + +std::string OTRExporter_Audio::GetSampleEntryStr(ZAudio* audio, SampleEntry* entry) { + std::string basePath = ""; + + if (audio->sampleOffsets[entry->bankId].contains(entry->sampleDataOffset) && + audio->sampleOffsets[entry->bankId][entry->sampleDataOffset] != "") { + basePath = StringHelper::Sprintf( + "samples/%s", audio->sampleOffsets[entry->bankId][entry->sampleDataOffset].c_str()); + } else + basePath = StringHelper::Sprintf("samples/sample_%d_%08X", entry->bankId, entry->sampleDataOffset); + return basePath; +} + +std::string OTRExporter_Audio::GetSampleDataStr(ZAudio* audio, SampleEntry* entry) { + std::string basePath = ""; + + if (audio->sampleOffsets[entry->bankId].contains(entry->sampleDataOffset) && + audio->sampleOffsets[entry->bankId][entry->sampleDataOffset] != "") { + basePath = StringHelper::Sprintf( + "samples/%s_RAW", + audio->sampleOffsets[entry->bankId][entry->sampleDataOffset].c_str()); + } else + basePath = StringHelper::Sprintf("samples/sample_%d_%08X_RAW", entry->bankId, entry->sampleDataOffset); + return basePath; +} + +void OTRExporter_Audio::WriteSampleBinary(ZAudio* audio) { + ZResource* res = audio; - for (auto env : envelopes) - { - writer->Write(env->delay); - writer->Write(env->arg); - } + for (const auto& pair : audio->samples) { + MemoryStream* sampleStream = new MemoryStream(); + BinaryWriter sampleWriter = BinaryWriter(sampleStream); + + WriteSampleEntry(pair.second, &sampleWriter); + + std::string basePath = GetSampleEntryStr(audio, pair.second); + + std::string fName = OTRExporter_DisplayList::GetPathToRes(res, basePath); + fName += "_META"; + AddFile(fName, sampleStream->ToVector()); + } +} + +void OTRExporter_Audio::WriteSampleXML(ZAudio* audio) { + ZResource* res = audio; + + for (const auto& pair : audio->samples) { + tinyxml2::XMLDocument sample; + tinyxml2::XMLElement* root = sample.NewElement("Sample"); + root->SetAttribute("Version", 0); + + WriteSampleEntry(pair.second, root); + + // There is no overload for size_t. MSVC and GCC are fine with `size` being cast + // to size_t and passed in, but apple clang is not. + root->SetAttribute("Size", (uint64_t)pair.second->data.size()); + sample.InsertEndChild(root); + + std::string sampleDataPath = GetSampleDataStr(audio, pair.second); + sampleDataPath = OTRExporter_DisplayList::GetPathToRes(res, sampleDataPath); + + root->SetAttribute("Path", sampleDataPath.c_str()); + + std::string basePath = GetSampleEntryStr(audio, pair.second); + std::string fName = OTRExporter_DisplayList::GetPathToRes(res, basePath); + + fName += "_META"; + + tinyxml2::XMLPrinter printer; + sample.Accept(&printer); + std::vector xmlData((printer.CStr()), printer.CStr() + printer.CStrSize() - 1); + AddFile(fName, xmlData); + + MemoryStream* stream = new MemoryStream(); + BinaryWriter sampleDataWriter = BinaryWriter(stream); + + sampleDataWriter.Write((char*)pair.second->data.data(), pair.second->data.size()); + AddFile(sampleDataPath, stream->ToVector()); + } } void OTRExporter_Audio::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) { - ZAudio* audio = (ZAudio*)res; - - WriteHeader(res, outPath, writer, static_cast(SOH::ResourceType::SOH_Audio), 2); - - // Write Samples as individual files - for (auto pair : audio->samples) - { - MemoryStream* sampleStream = new MemoryStream(); - BinaryWriter sampleWriter = BinaryWriter(sampleStream); - - writer->Write((uint32_t)pair.first); - WriteSampleEntry(pair.second, &sampleWriter); - - std::string basePath = ""; - - if (audio->sampleOffsets[pair.second->bankId].find(pair.second->sampleLoopOffset) != audio->sampleOffsets[pair.second->bankId].end()) - { - if (audio->sampleOffsets[pair.second->bankId][pair.second->sampleLoopOffset].find(pair.second->sampleDataOffset) != audio->sampleOffsets[pair.second->bankId][pair.second->sampleLoopOffset].end()) - basePath = StringHelper::Sprintf("samples/%s", audio->sampleOffsets[pair.second->bankId][pair.second->sampleLoopOffset][pair.second->sampleDataOffset].c_str()); - else - basePath = StringHelper::Sprintf("samples/sample_%08X", pair.first); - } - else - basePath = StringHelper::Sprintf("samples/sample_%08X", pair.first); - - std::string fName = OTRExporter_DisplayList::GetPathToRes(res, basePath); - AddFile(fName, sampleStream->ToVector()); - } - - // Write the soundfont table - for (size_t i = 0; i < audio->soundFontTable.size(); i++) - { - MemoryStream* fntStream = new MemoryStream(); - BinaryWriter fntWriter = BinaryWriter(fntStream); - - WriteHeader(nullptr, "", &fntWriter, static_cast(SOH::ResourceType::SOH_AudioSoundFont), 2); - - fntWriter.Write((uint32_t)i); - fntWriter.Write(audio->soundFontTable[i].medium); - fntWriter.Write(audio->soundFontTable[i].cachePolicy); - fntWriter.Write(audio->soundFontTable[i].data1); - fntWriter.Write(audio->soundFontTable[i].data2); - fntWriter.Write(audio->soundFontTable[i].data3); - - fntWriter.Write((uint32_t)audio->soundFontTable[i].drums.size()); - fntWriter.Write((uint32_t)audio->soundFontTable[i].instruments.size()); - fntWriter.Write((uint32_t)audio->soundFontTable[i].soundEffects.size()); - - for (size_t k = 0; k < audio->soundFontTable[i].drums.size(); k++) - { - fntWriter.Write(audio->soundFontTable[i].drums[k].releaseRate); - fntWriter.Write(audio->soundFontTable[i].drums[k].pan); - fntWriter.Write(audio->soundFontTable[i].drums[k].loaded); - - WriteEnvData(audio->soundFontTable[i].drums[k].env, &fntWriter); - - WriteSampleEntryReference(audio, audio->soundFontTable[i].drums[k].sample, audio->samples, &fntWriter); - fntWriter.Write(audio->soundFontTable[i].drums[k].tuning); - } - - for (size_t k = 0; k < audio->soundFontTable[i].instruments.size(); k++) - { - fntWriter.Write((uint8_t)audio->soundFontTable[i].instruments[k].isValidInstrument); - - fntWriter.Write(audio->soundFontTable[i].instruments[k].loaded); - fntWriter.Write(audio->soundFontTable[i].instruments[k].normalRangeLo); - fntWriter.Write(audio->soundFontTable[i].instruments[k].normalRangeHi); - fntWriter.Write(audio->soundFontTable[i].instruments[k].releaseRate); - - WriteEnvData(audio->soundFontTable[i].instruments[k].env, &fntWriter); - - WriteSoundFontEntry(audio, audio->soundFontTable[i].instruments[k].lowNotesSound, audio->samples, &fntWriter); - WriteSoundFontEntry(audio, audio->soundFontTable[i].instruments[k].normalNotesSound, audio->samples, &fntWriter); - WriteSoundFontEntry(audio, audio->soundFontTable[i].instruments[k].highNotesSound, audio->samples, &fntWriter); - } - - for (size_t k = 0; k < audio->soundFontTable[i].soundEffects.size(); k++) - { - WriteSoundFontEntry(audio, audio->soundFontTable[i].soundEffects[k], audio->samples, &fntWriter); - } - - //std::string fName = OTRExporter_DisplayList::GetPathToRes(res, StringHelper::Sprintf("fonts/font_%02X", i)); - std::string fName = OTRExporter_DisplayList::GetPathToRes(res, StringHelper::Sprintf("fonts/%s", audio->soundFontNames[i].c_str())); - AddFile(fName, fntStream->ToVector()); - } - - // Write Sequences - for (size_t i = 0; i < audio->sequences.size(); i++) - { - auto seq = audio->sequences[i]; - - MemoryStream* seqStream = new MemoryStream(); - BinaryWriter seqWriter = BinaryWriter(seqStream); - - WriteHeader(nullptr, "", &seqWriter, static_cast(SOH::ResourceType::SOH_AudioSequence), 2); - - seqWriter.Write((uint32_t)seq.size()); - seqWriter.Write(seq.data(), seq.size()); - seqWriter.Write((uint8_t)i); - seqWriter.Write((uint8_t)audio->sequenceTable[i].medium); - seqWriter.Write((uint8_t)audio->sequenceTable[i].cachePolicy); - seqWriter.Write((uint32_t)audio->fontIndices[i].size()); - - for (size_t k = 0; k < audio->fontIndices[i].size(); k++) - seqWriter.Write((uint8_t)audio->fontIndices[i][k]); - - std::string fName = OTRExporter_DisplayList::GetPathToRes(res, StringHelper::Sprintf("sequences/%s", audio->seqNames[i].c_str())); - AddFile(fName, seqStream->ToVector()); - } + ZAudio* audio = (ZAudio*)res; + + WriteHeader(res, outPath, writer, static_cast(SOH::ResourceType::SOH_Audio), 2); + + // Write Samples as individual files + WriteSampleXML(audio); + + // Write the soundfont table + WriteSoundFontTableXML(audio); + + // Write Sequences + WriteSequenceXML(audio); } diff --git a/OTRExporter/AudioExporter.h b/OTRExporter/AudioExporter.h index 13a8cc0..97c6142 100644 --- a/OTRExporter/AudioExporter.h +++ b/OTRExporter/AudioExporter.h @@ -4,13 +4,30 @@ #include "ZAudio.h" #include "Exporter.h" #include +#include class OTRExporter_Audio : public OTRExporter { public: - void WriteSampleEntry(SampleEntry* entry, BinaryWriter* writer); - void WriteSampleEntryReference(ZAudio* audio, SampleEntry* entry, std::map samples, BinaryWriter* writer); - void WriteSoundFontEntry(ZAudio* audio, SoundFontEntry* entry, std::map samples, BinaryWriter* writer); - void WriteEnvData(std::vector envelopes, BinaryWriter* writer); - virtual void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override; + void WriteSampleEntry(SampleEntry* entry, BinaryWriter* writer); + void WriteSampleEntry(SampleEntry* entry, tinyxml2::XMLElement* writer); + virtual void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override; + +private: + void WriteSoundFontTableBinary(ZAudio* audio); + void WriteSoundFontTableXML(ZAudio* audio); + void WriteSequenceBinary(ZAudio* audio); + void WriteSequenceXML(ZAudio* audio); + void WriteSampleBinary(ZAudio* audio); + void WriteSampleXML(ZAudio* audio); + std::string GetSampleEntryReference(ZAudio* audio, SampleEntry* entry); + std::string GetSampleEntryStr(ZAudio* audio, SampleEntry* entry); + std::string GetSampleDataStr(ZAudio* audio, SampleEntry* entry); + void WriteEnvData(std::vector envelopes, BinaryWriter* writer); + void WriteEnvData(std::vector envelopes, tinyxml2::XMLElement* xmlDoc); + void WriteSoundFontEntry(ZAudio* audio, SoundFontEntry* entry, BinaryWriter* writer); + void WriteSoundFontEntry(ZAudio* audio, SoundFontEntry* entry, tinyxml2::XMLElement* xmlDoc, const char* name); + const char* GetMediumStr(uint8_t medium); + const char* GetCachePolicyStr(uint8_t policy); + const char* GetCodecStr(uint8_t codec); }; \ No newline at end of file