[Scummvm-git-logs] scummvm-tools master -> d06a5562375ce5d27ad6846df1310c566a215856

mgerhardy noreply at scummvm.org
Wed Jun 3 16:31:17 UTC 2026


This automated email contains information about 4 new commits which have been
pushed to the 'scummvm-tools' repo located at https://api.github.com/repos/scummvm/scummvm-tools .

Summary:
c184c4f8ab MACS2: renamed some opcodes to match names in ghidra
88af2bbcef MACS2: updated the decompiler to also support json output and unified with the imgui decompiler in scummvm itself
fadaad3fbf MASC2: started to export json scene data, too
d06a556237 MACS2: this is a shadowmap


Commit: c184c4f8abe5ee8ddf61afd145f243b3638cf15e
    https://github.com/scummvm/scummvm-tools/commit/c184c4f8abe5ee8ddf61afd145f243b3638cf15e
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-05-31T17:41:31+02:00

Commit Message:
MACS2: renamed some opcodes to match names in ghidra

Changed paths:
    engines/macs2/demacs2.cpp


diff --git a/engines/macs2/demacs2.cpp b/engines/macs2/demacs2.cpp
index 099ec06e..96cc2bca 100644
--- a/engines/macs2/demacs2.cpp
+++ b/engines/macs2/demacs2.cpp
@@ -21,10 +21,10 @@
 
 /* MACS2 Script decompiler */
 
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
+#include <cstdio>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
 #include <vector>
 #include <string>
 
@@ -337,11 +337,11 @@ static void disassemble() {
 			printf("subtract %s, %s\n", a.c_str(), b.c_str());
 			break;
 		}
-		case 0x26: { // setAnimSlot
+		case 0x26: { // loadSpecialAnim
 			std::string obj = formatValue();
-			formatValue(); // unused
+			std::string decodeFlag = formatValue(); // decode/enable flag (runtime +0x182)
 			uint8_t animIdx = readByte();
-			printf("setAnimSlot obj=%s anim=%u\n", obj.c_str(), animIdx);
+			printf("loadSpecialAnim obj=%s decode=%s anim=%u\n", obj.c_str(), decodeFlag.c_str(), animIdx);
 			break;
 		}
 		case 0x27: { // setMaxAnimFrame
@@ -403,9 +403,9 @@ static void disassemble() {
 			printf("nop30\n");
 			break;
 		}
-		case 0x31: { // setMusicVolume
+		case 0x31: { // setVolume
 			std::string vol = formatValue();
-			printf("setMusicVolume %s\n", vol.c_str());
+			printf("setVolume %s\n", vol.c_str());
 			break;
 		}
 		case 0x32: { // setClickable


Commit: 88af2bbcef51c400c3c6f85e0c62be4a994e170b
    https://github.com/scummvm/scummvm-tools/commit/88af2bbcef51c400c3c6f85e0c62be4a994e170b
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-05-31T17:45:00+02:00

Commit Message:
MACS2: updated the decompiler to also support json output and unified with the imgui decompiler in scummvm itself

Changed paths:
    engines/macs2/demacs2.cpp


diff --git a/engines/macs2/demacs2.cpp b/engines/macs2/demacs2.cpp
index 96cc2bca..8898d093 100644
--- a/engines/macs2/demacs2.cpp
+++ b/engines/macs2/demacs2.cpp
@@ -21,19 +21,20 @@
 
 /* MACS2 Script decompiler */
 
-#include <cstdio>
 #include <cstdint>
+#include <cstdio>
 #include <cstdlib>
 #include <cstring>
-#include <vector>
 #include <string>
+#include <vector>
 
 static uint8_t *scriptData = nullptr;
 static uint32_t scriptSize = 0;
 static uint32_t pos = 0;
 
 static uint8_t readByte() {
-	if (pos >= scriptSize) return 0;
+	if (pos >= scriptSize)
+		return 0;
 	return scriptData[pos++];
 }
 
@@ -43,6 +44,41 @@ static uint16_t readWord() {
 	return (uint16_t)hi << 8 | lo;
 }
 
+static const struct {
+	uint16_t id;
+	const char *name;
+} kSpecialNames[] = {
+	{0x01, "interactedUse"},
+	{0x02, "interactedLook"},
+	{0x03, "interactedTalk"},
+	{0x04, "areaAtActor"},
+	{0x0B, "isRepeatRun"},
+	{0x0D, "dialogueResult"},
+	{0x23, "pathWalkable"},
+	{0x24, "actorX"},
+	{0x25, "actorY"},
+	{0x26, "isSceneInit"},
+	{0x27, "areaRepeatRun"},
+	{0x28, "invCheck"},
+	{0x29, "animBlobRange"},
+	{0x2A, "invCombine"},
+	{0x2B, "invAction"},
+	{0x2C, "interactedMap"},
+	{0x2D, "curScene"},
+	{0x2E, "const2"},
+	{0x2F, "prevScene"},
+	{0x30, "musicActive"},
+	{0x31, "soundActive"},
+};
+
+static const char *getSpecialName(uint16_t val) {
+	for (const auto &s : kSpecialNames) {
+		if (s.id == val)
+			return s.name;
+	}
+	return nullptr;
+}
+
 static std::string formatValue() {
 	uint8_t type = readByte();
 	uint16_t val = readWord();
@@ -51,531 +87,682 @@ static std::string formatValue() {
 		snprintf(buf, sizeof(buf), "%u", val);
 		return buf;
 	} else if (type == 0xFF) {
-		switch (val) {
-		case 0x01: return "interactedUse";
-		case 0x02: return "interactedLook";
-		case 0x03: return "interactedTalk";
-		case 0x04: return "areaAtActor";
-		case 0x0B: return "isRepeatRun";
-		case 0x0D: return "dialogueResult";
-		case 0x23: return "pathWalkable";
-		case 0x24: return "actorX";
-		case 0x25: return "actorY";
-		case 0x26: return "isSceneInit";
-		case 0x28: return "invCheck";
-		case 0x2A: return "invCombine";
-		case 0x2B: return "invAction";
-		case 0x2D: return "curScene";
-		case 0x2F: return "prevScene";
-		default:
+		const char *name = getSpecialName(val);
+		if (name)
+			return name;
+		if (val >= 0x0E && val <= 0x22) {
 			char buf[32];
-			snprintf(buf, sizeof(buf), "special[0x%02x]", val);
+			snprintf(buf, sizeof(buf), "%u", val - 0x0D);
 			return buf;
 		}
+		char buf[32];
+		snprintf(buf, sizeof(buf), "special[0x%02x]", val);
+		return buf;
 	}
 	char buf[32];
 	snprintf(buf, sizeof(buf), "var[%u]", val);
 	return buf;
 }
 
+static const char *getOpcodeName(uint8_t opcode) {
+	switch (opcode) {
+	case 0x01:
+		return "setVar";
+	case 0x02:
+		return "setVarOr";
+	case 0x03:
+		return "ifFalse";
+	case 0x04:
+		return "ifTrue";
+	case 0x05:
+		return "compare";
+	case 0x06:
+		return "ifInteraction";
+	case 0x07:
+		return "endIf";
+	case 0x08:
+		return "else";
+	case 0x09:
+		return "nop09";
+	case 0x0A:
+		return "printStringLeft";
+	case 0x0B:
+		return "moveObject";
+	case 0x0C:
+		return "changeScene";
+	case 0x0D:
+		return "showDialogue";
+	case 0x0E:
+		return "changeAnimation";
+	case 0x0F:
+		return "frameWait";
+	case 0x10:
+		return "walkToPosition";
+	case 0x11:
+		return "waitForWalk";
+	case 0x12:
+		return "setPathfinding";
+	case 0x13:
+		return "skipUntil14";
+	case 0x14:
+		return "skipWord";
+	case 0x15:
+		return "clearDialogueChoices";
+	case 0x16:
+		return "addDialogueChoice";
+	case 0x17:
+		return "showDialogueChoice";
+	case 0x18:
+		return "dismissPanel";
+	case 0x19:
+		return "walkToAndPickup";
+	case 0x1A:
+		return "setPickupFrames";
+	case 0x1B:
+		return "setupObject";
+	case 0x1C:
+		return "setSkippable";
+	case 0x1D:
+		return "clearSkippable";
+	case 0x1E:
+		return "playAnimation";
+	case 0x1F:
+		return "pathWalkable = testPathfinding";
+	case 0x20:
+		return "setYOffset";
+	case 0x21:
+		return "setMotion";
+	case 0x22:
+		return "setOrientation";
+	case 0x23:
+		return "moveToPosition";
+	case 0x24:
+		return "addValues";
+	case 0x25:
+		return "subValues";
+	case 0x26:
+		return "loadSpecialAnim";
+	case 0x27:
+		return "setDirection";
+	case 0x28:
+		return "stopAnimation";
+	case 0x29:
+		return "openInventory";
+	case 0x2A:
+		return "loadObjectAnim";
+	case 0x2B:
+		return "checkObjectData";
+	case 0x2C:
+		return "invCheck = checkInventory";
+	case 0x2D:
+		return "setSnapToTarget";
+	case 0x2E:
+		return "animRangeTest = testSceneAnimFrame";
+	case 0x2F:
+		return "animRangeTest = testObjectAnimFrame";
+	case 0x30:
+		return "printStringRight";
+	case 0x31:
+		return "setVolume";
+	case 0x32:
+		return "setObjectClickable";
+	case 0x33:
+		return "setObjectVisible";
+	case 0x34:
+		return "setHotspotOverride";
+	case 0x35:
+		return "setObjectBounds";
+	case 0x36:
+		return "dismissAllPanels";
+	case 0x37:
+		return "resetToSceneScript";
+	case 0x38:
+		return "loadOverlayFont";
+	case 0x39:
+		return "endOverlayText";
+	case 0x3A:
+		return "addOverlayTextEntry";
+	case 0x3B:
+		return "clearOverlayText";
+	case 0x3C:
+		return "fadeToBlack";
+	case 0x3D:
+		return "fadeFromBlack";
+	case 0x3E:
+		return "loadPcmSound";
+	case 0x3F:
+		return "freePcmSound";
+	case 0x40:
+		return "playPcmSound";
+	case 0x41:
+		return "waitForSound";
+	case 0x42:
+		return "stopPcmSound";
+	case 0x43:
+		return "loadMusicSlot";
+	case 0x44:
+		return "playMusicSlot";
+	case 0x45:
+		return "stopMusicSlot";
+	case 0x46:
+		return "freeMusicSlot";
+	case 0x47:
+		return "waitForMusic";
+	case 0x48:
+		return "getObjectX";
+	case 0x49:
+		return "getObjectY";
+	case 0x4A:
+		return "getObjectField8";
+	case 0x4B:
+		return "getObjectOrientation";
+	case 0x4C:
+		return "clearActorInventory";
+	case 0x4D:
+		return "setPathfindingRemap";
+	case 0x4E:
+		return "waitForAdlib";
+	default:
+		return "???";
+	}
+}
+
 static const char *cmpOpName(uint8_t op) {
 	switch (op) {
-	case 0x01: return "==";
-	case 0x02: return "!=";
-	case 0x03: return "<";
-	case 0x04: return ">";
-	case 0x05: return "<=";
-	case 0x06: return ">=";
-	default: return "?";
+	case 0x01:
+		return "==";
+	case 0x02:
+		return "!=";
+	case 0x03:
+		return "<";
+	case 0x04:
+		return ">";
+	case 0x05:
+		return "<=";
+	case 0x06:
+		return ">=";
+	default:
+		return "?";
 	}
 }
 
-static void disassemble() {
+struct DecompiledLine {
+	uint32_t offset;
+	uint8_t opcode;
+	int indent;
+	std::string params;
+};
+
+static std::string decodeParams(uint8_t opcode, uint32_t endPos, int &indent) {
+	std::string result;
+
+	char buf[256];
+	switch (opcode) {
+	case 0x01:
+	case 0x02: {
+		readByte();
+		uint16_t varIdx = readWord();
+		std::string val = formatValue();
+		snprintf(buf, sizeof(buf), " var[%u] = %s", varIdx, val.c_str());
+		result = buf;
+		break;
+	}
+	case 0x03:
+	case 0x04: {
+		std::string val = formatValue();
+		snprintf(buf, sizeof(buf), " (%s)", val.c_str());
+		result = buf;
+		indent++;
+		break;
+	}
+	case 0x05: {
+		uint8_t cmpOp = readByte();
+		std::string a = formatValue();
+		std::string b = formatValue();
+		snprintf(buf, sizeof(buf), " (%s %s %s)", a.c_str(), cmpOpName(cmpOp), b.c_str());
+		result = buf;
+		indent++;
+		break;
+	}
+	case 0x06: {
+		uint8_t subOp = readByte();
+		std::string i = formatValue();
+		std::string a = formatValue();
+		std::string b = formatValue();
+		snprintf(buf, sizeof(buf), " %s(%s, %s, %s)", subOp == 2 ? "NOT " : "", i.c_str(), a.c_str(), b.c_str());
+		result = buf;
+		indent++;
+		break;
+	}
+	case 0x08: {
+		indent++;
+		break;
+	}
+	case 0x0A: {
+		std::string x = formatValue();
+		std::string y = formatValue();
+		uint16_t strOffset = readWord();
+		uint16_t numLines = readWord();
+		snprintf(buf, sizeof(buf), " pos=(%s,%s) str=%u lines=%u", x.c_str(), y.c_str(), strOffset, numLines);
+		result = buf;
+		break;
+	}
+	case 0x0B: {
+		std::string obj = formatValue();
+		std::string scene = formatValue();
+		std::string x = formatValue();
+		std::string y = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s scene=%s pos=(%s,%s)", obj.c_str(), scene.c_str(), x.c_str(), y.c_str());
+		result = buf;
+		break;
+	}
+	case 0x0C: {
+		std::string scene = formatValue();
+		std::string mode = formatValue();
+		std::string speed = formatValue();
+		snprintf(buf, sizeof(buf), " scene=%s mode=%s speed=%s", scene.c_str(), mode.c_str(), speed.c_str());
+		result = buf;
+		break;
+	}
+	case 0x0D: {
+		std::string obj = formatValue();
+		std::string x = formatValue();
+		std::string y = formatValue();
+		std::string side = formatValue();
+		uint16_t strOffset = readWord();
+		uint16_t numLines = readWord();
+		snprintf(buf, sizeof(buf), " obj=%s pos=(%s,%s) side=%s str=%u lines=%u",
+				 obj.c_str(), x.c_str(), y.c_str(), side.c_str(), strOffset, numLines);
+		result = buf;
+		break;
+	}
+	case 0x0F:
+	case 0x31:
+	case 0x3C:
+	case 0x3D: {
+		std::string val = formatValue();
+		result = " " + val;
+		break;
+	}
+	case 0x10: {
+		std::string obj = formatValue();
+		std::string x = formatValue();
+		std::string y = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s pos=(%s,%s)", obj.c_str(), x.c_str(), y.c_str());
+		result = buf;
+		break;
+	}
+	case 0x11:
+	case 0x47: {
+		std::string obj = formatValue();
+		result = " obj=" + obj;
+		break;
+	}
+	case 0x12: {
+		std::string area = formatValue();
+		std::string active = formatValue();
+		std::string val = formatValue();
+		snprintf(buf, sizeof(buf), " area=%s active=%s val=%s", area.c_str(), active.c_str(), val.c_str());
+		result = buf;
+		break;
+	}
+	case 0x14: {
+		uint16_t w = readWord();
+		snprintf(buf, sizeof(buf), " 0x%04x", w);
+		result = buf;
+		break;
+	}
+	case 0x16: {
+		std::string idx = formatValue();
+		uint16_t strOffset = readWord();
+		uint16_t numLines = readWord();
+		snprintf(buf, sizeof(buf), " idx=%s str=%u lines=%u", idx.c_str(), strOffset, numLines);
+		result = buf;
+		break;
+	}
+	case 0x17: {
+		std::string obj = formatValue();
+		std::string x = formatValue();
+		std::string y = formatValue();
+		std::string side = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s pos=(%s,%s) side=%s", obj.c_str(), x.c_str(), y.c_str(), side.c_str());
+		result = buf;
+		break;
+	}
+	case 0x19: {
+		std::string actor = formatValue();
+		std::string obj = formatValue();
+		snprintf(buf, sizeof(buf), " actor=%s obj=%s", actor.c_str(), obj.c_str());
+		result = buf;
+		break;
+	}
+	case 0x1A: {
+		std::string obj = formatValue();
+		std::string start = formatValue();
+		std::string end = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s start=%s end=%s", obj.c_str(), start.c_str(), end.c_str());
+		result = buf;
+		break;
+	}
+	case 0x1B: {
+		std::string obj = formatValue();
+		std::string slot = formatValue();
+		std::string speed = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s slot=%s speed=%s", obj.c_str(), slot.c_str(), speed.c_str());
+		result = buf;
+		break;
+	}
+	case 0x1E: {
+		std::string obj = formatValue();
+		std::string slot = formatValue();
+		std::string frame = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s slot=%s frame=%s", obj.c_str(), slot.c_str(), frame.c_str());
+		result = buf;
+		break;
+	}
+	case 0x1F: {
+		std::string obj = formatValue();
+		std::string x = formatValue();
+		std::string y = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s pos=(%s,%s)", obj.c_str(), x.c_str(), y.c_str());
+		result = buf;
+		break;
+	}
+	case 0x20: {
+		std::string obj = formatValue();
+		std::string offset = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s offset=%s", obj.c_str(), offset.c_str());
+		result = buf;
+		break;
+	}
+	case 0x21: {
+		std::string obj = formatValue();
+		std::string target = formatValue();
+		std::string delta = formatValue();
+		std::string dist = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s target=%s delta=%s dist=%s", obj.c_str(), target.c_str(), delta.c_str(), dist.c_str());
+		result = buf;
+		break;
+	}
+	case 0x22: {
+		std::string obj = formatValue();
+		std::string anim = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s anim=%s", obj.c_str(), anim.c_str());
+		result = buf;
+		break;
+	}
+	case 0x23: {
+		std::string obj = formatValue();
+		std::string x = formatValue();
+		std::string y = formatValue();
+		std::string voff = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s pos=(%s,%s) voff=%s", obj.c_str(), x.c_str(), y.c_str(), voff.c_str());
+		result = buf;
+		break;
+	}
+	case 0x24:
+	case 0x25: {
+		std::string a = formatValue();
+		std::string b = formatValue();
+		const char *op = (opcode == 0x24) ? "+" : "-";
+		snprintf(buf, sizeof(buf), " %s = %s %s %s", a.c_str(), a.c_str(), op, b.c_str());
+		result = buf;
+		break;
+	}
+	case 0x26: {
+		std::string obj = formatValue();
+		std::string decodeFlag = formatValue();
+		uint8_t animIdx = readByte();
+		snprintf(buf, sizeof(buf), " obj=%s decode=%s anim=%u", obj.c_str(), decodeFlag.c_str(), animIdx);
+		result = buf;
+		break;
+	}
+	case 0x27: {
+		std::string obj = formatValue();
+		std::string maxFrame = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s maxFrame=%s", obj.c_str(), maxFrame.c_str());
+		result = buf;
+		break;
+	}
+	case 0x29: {
+		std::string obj = formatValue();
+		result = " obj=" + obj;
+		break;
+	}
+	case 0x2A: {
+		std::string obj = formatValue();
+		std::string slot = formatValue();
+		std::string decode = formatValue();
+		uint8_t idx = readByte();
+		snprintf(buf, sizeof(buf), " obj=%s slot=%s decode=%s idx=%u", obj.c_str(), slot.c_str(), decode.c_str(), idx);
+		result = buf;
+		break;
+	}
+	case 0x2B: {
+		std::string obj = formatValue();
+		result = " obj=" + obj;
+		break;
+	}
+	case 0x2C:
+	case 0x32:
+	case 0x33:
+	case 0x2D: {
+		std::string obj = formatValue();
+		std::string val = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s val=%s", obj.c_str(), val.c_str());
+		result = buf;
+		break;
+	}
+	case 0x2E: {
+		std::string anim = formatValue();
+		std::string lo = formatValue();
+		std::string hi = formatValue();
+		snprintf(buf, sizeof(buf), " anim=%s range=[%s,%s]", anim.c_str(), lo.c_str(), hi.c_str());
+		result = buf;
+		break;
+	}
+	case 0x2F: {
+		std::string obj = formatValue();
+		std::string slot = formatValue();
+		std::string lo = formatValue();
+		std::string hi = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s slot=%s range=[%s,%s]", obj.c_str(), slot.c_str(), lo.c_str(), hi.c_str());
+		result = buf;
+		break;
+	}
+	case 0x34:
+	case 0x4D: {
+		std::string a = formatValue();
+		std::string b = formatValue();
+		snprintf(buf, sizeof(buf), " %s -> %s", a.c_str(), b.c_str());
+		result = buf;
+		break;
+	}
+	case 0x35: {
+		std::string obj = formatValue();
+		std::string parent = formatValue();
+		std::string a = formatValue();
+		std::string b = formatValue();
+		std::string c = formatValue();
+		snprintf(buf, sizeof(buf), " obj=%s parent=%s (%s,%s,%s)", obj.c_str(), parent.c_str(), a.c_str(), b.c_str(), c.c_str());
+		result = buf;
+		break;
+	}
+	case 0x38:
+	case 0x3E: {
+		uint8_t resIdx = readByte();
+		snprintf(buf, sizeof(buf), " res=%u", resIdx);
+		result = buf;
+		break;
+	}
+	case 0x3A: {
+		std::string x = formatValue();
+		std::string y = formatValue();
+		std::string align = formatValue();
+		uint16_t strOffset = readWord();
+		uint16_t entryType = readWord();
+		snprintf(buf, sizeof(buf), " pos=(%s,%s) align=%s str=%u type=%u", x.c_str(), y.c_str(), align.c_str(), strOffset, entryType);
+		result = buf;
+		break;
+	}
+	case 0x43: {
+		std::string slot = formatValue();
+		uint8_t resIdx = readByte();
+		snprintf(buf, sizeof(buf), " slot=%s res=%u", slot.c_str(), resIdx);
+		result = buf;
+		break;
+	}
+	case 0x44:
+	case 0x45: {
+		std::string slot = formatValue();
+		std::string a = formatValue();
+		std::string b = formatValue();
+		snprintf(buf, sizeof(buf), " slot=%s %s %s", slot.c_str(), a.c_str(), b.c_str());
+		result = buf;
+		break;
+	}
+	case 0x46: {
+		std::string slot = formatValue();
+		result = " slot=" + slot;
+		break;
+	}
+	case 0x48:
+	case 0x49:
+	case 0x4A:
+	case 0x4B: {
+		std::string obj = formatValue();
+		if (pos + 3 <= endPos) {
+			readByte();
+			uint16_t varIdx = readWord();
+			snprintf(buf, sizeof(buf), " var[%u] = obj=%s", varIdx, obj.c_str());
+			result = buf;
+		} else {
+			result = " obj=" + obj;
+		}
+		break;
+	}
+	case 0x07:
+	case 0x09:
+	case 0x0E:
+	case 0x13:
+	case 0x15:
+	case 0x18:
+	case 0x1C:
+	case 0x1D:
+	case 0x28:
+	case 0x30:
+	case 0x36:
+	case 0x37:
+	case 0x39:
+	case 0x3B:
+	case 0x3F:
+	case 0x40:
+	case 0x41:
+	case 0x42:
+	case 0x4C:
+	case 0x4E:
+		break;
+	default: {
+		uint8_t length = (uint8_t)(endPos - pos);
+		if (length > 0 && length <= 30) {
+			result = " [";
+			uint32_t dataPos = pos;
+			for (uint8_t i = 0; i < length && dataPos < scriptSize; i++, dataPos++) {
+				if (i)
+					result += " ";
+				snprintf(buf, sizeof(buf), "%02x", scriptData[dataPos]);
+				result += buf;
+			}
+			result += "]";
+		}
+		break;
+	}
+	}
+	return result;
+}
+
+static std::vector<DecompiledLine> decompileToLines() {
+	std::vector<DecompiledLine> lines;
 	int indent = 0;
 
 	while (pos < scriptSize - 1) {
 		uint32_t instrAddr = pos;
 		uint8_t opcode = readByte();
-		if (opcode == 0x00) continue;
+		if (opcode == 0x00)
+			continue;
 
 		uint8_t length = readByte();
 		uint32_t endPos = pos + length;
 
-		// Adjust indent for block-end opcodes
-		if (opcode == 0x07 && indent > 0) indent--;
-		if (opcode == 0x08 && indent > 0) indent--;
+		if (opcode == 0x07 && indent > 0)
+			indent--;
+		if (opcode == 0x08 && indent > 0)
+			indent--;
 
-		for (int i = 0; i < indent; i++) printf("  ");
-		printf("%04x: ", instrAddr);
+		DecompiledLine line;
+		line.offset = instrAddr;
+		line.opcode = opcode;
+		line.indent = indent;
+		line.params = decodeParams(opcode, endPos, indent);
+		lines.push_back(line);
 
-		switch (opcode) {
-		case 0x01: { // setVar
-			readByte();
-			uint16_t varIdx = readWord();
-			std::string val = formatValue();
-			printf("setVar var[%u] = %s\n", varIdx, val.c_str());
-			break;
-		}
-		case 0x02: { // setVarOr
-			readByte();
-			uint16_t varIdx = readWord();
-			std::string val = formatValue();
-			printf("setVarOr var[%u] = %s\n", varIdx, val.c_str());
-			break;
-		}
-		case 0x03: { // ifTrue
-			std::string val = formatValue();
-			printf("ifTrue (%s)\n", val.c_str());
-			indent++;
-			break;
-		}
-		case 0x04: { // ifFalse
-			std::string val = formatValue();
-			printf("ifFalse (%s)\n", val.c_str());
-			indent++;
-			break;
-		}
-		case 0x05: { // compare
-			uint8_t cmpOp = readByte();
-			std::string a = formatValue();
-			std::string b = formatValue();
-			printf("compare (%s %s %s)\n", a.c_str(), cmpOpName(cmpOp), b.c_str());
-			indent++;
-			break;
-		}
-		case 0x06: { // ifInteraction
-			uint8_t subOp = readByte();
-			std::string i = formatValue();
-			std::string a = formatValue();
-			std::string b = formatValue();
-			printf("ifInteraction %s(%s, %s, %s)\n", subOp == 2 ? "NOT " : "", i.c_str(), a.c_str(), b.c_str());
-			indent++;
-			break;
-		}
-		case 0x07: { // endIf
-			printf("endIf\n");
-			break;
-		}
-		case 0x08: { // else
-			printf("else\n");
-			indent++;
-			break;
-		}
-		case 0x0A: { // printString
-			std::string x = formatValue();
-			std::string y = formatValue();
-			uint16_t strOffset = readWord();
-			uint16_t numLines = readWord();
-			printf("printString pos=(%s, %s) strOffset=%u numLines=%u\n", x.c_str(), y.c_str(), strOffset, numLines);
-			break;
-		}
-		case 0x0B: { // moveObject
-			std::string obj = formatValue();
-			std::string scene = formatValue();
-			std::string x = formatValue();
-			std::string y = formatValue();
-			printf("moveObject obj=%s scene=%s pos=(%s, %s)\n", obj.c_str(), scene.c_str(), x.c_str(), y.c_str());
-			break;
-		}
-		case 0x0C: { // changeScene
-			std::string scene = formatValue();
-			std::string mode = formatValue();
-			std::string speed = formatValue();
-			printf("changeScene scene=%s mode=%s speed=%s\n", scene.c_str(), mode.c_str(), speed.c_str());
-			break;
-		}
-		case 0x0D: { // showDialogue
-			std::string obj = formatValue();
-			std::string x = formatValue();
-			std::string y = formatValue();
-			std::string side = formatValue();
-			uint16_t strOffset = readWord();
-			uint16_t numLines = readWord();
-			printf("showDialogue obj=%s pos=(%s, %s) side=%s strOffset=%u numLines=%u\n",
-				   obj.c_str(), x.c_str(), y.c_str(), side.c_str(), strOffset, numLines);
-			break;
-		}
-		case 0x0E: { // changeAnim
-			printf("changeAnim\n");
-			break;
-		}
-		case 0x0F: { // frameWait
-			std::string val = formatValue();
-			printf("frameWait %s\n", val.c_str());
-			break;
-		}
-		case 0x10: { // walkTo
-			std::string obj = formatValue();
-			std::string x = formatValue();
-			std::string y = formatValue();
-			printf("walkTo obj=%s pos=(%s, %s)\n", obj.c_str(), x.c_str(), y.c_str());
-			break;
-		}
-		case 0x11: { // waitForWalk
-			std::string obj = formatValue();
-			printf("waitForWalk obj=%s\n", obj.c_str());
-			break;
-		}
-		case 0x12: { // setPathOverride
-			std::string area = formatValue();
-			std::string active = formatValue();
-			std::string val = formatValue();
-			printf("setPathOverride area=%s active=%s val=%s\n", area.c_str(), active.c_str(), val.c_str());
-			break;
-		}
-		case 0x13: { // loadAnim
-			printf("loadAnim\n");
-			break;
-		}
-		case 0x14: { // skipWord
-			uint16_t w = readWord();
-			printf("skipWord 0x%04x\n", w);
-			break;
-		}
-		case 0x15: { // clearDialogueChoices
-			printf("clearDialogueChoices\n");
-			break;
-		}
-		case 0x16: { // addDialogueChoice
-			std::string idx = formatValue();
-			uint16_t strOffset = readWord();
-			uint16_t numLines = readWord();
-			printf("addDialogueChoice idx=%s strOffset=%u numLines=%u\n", idx.c_str(), strOffset, numLines);
-			break;
-		}
-		case 0x17: { // showDialogueChoice
-			std::string obj = formatValue();
-			std::string x = formatValue();
-			std::string y = formatValue();
-			std::string side = formatValue();
-			printf("showDialogueChoice obj=%s pos=(%s, %s) side=%s\n", obj.c_str(), x.c_str(), y.c_str(), side.c_str());
-			break;
-		}
-		case 0x18: { // dismissPanel
-			printf("dismissPanel\n");
-			break;
-		}
-		case 0x19: { // walkToAndPickup
-			std::string actor = formatValue();
-			std::string obj = formatValue();
-			printf("walkToAndPickup actor=%s obj=%s\n", actor.c_str(), obj.c_str());
-			break;
-		}
-		case 0x1A: { // setPickupFrames
-			std::string obj = formatValue();
-			std::string start = formatValue();
-			std::string end = formatValue();
-			printf("setPickupFrames obj=%s start=%s end=%s\n", obj.c_str(), start.c_str(), end.c_str());
-			break;
-		}
-		case 0x1B: { // setAnimSpeed
-			std::string obj = formatValue();
-			std::string slot = formatValue();
-			std::string speed = formatValue();
-			printf("setAnimSpeed obj=%s slot=%s speed=%s\n", obj.c_str(), slot.c_str(), speed.c_str());
-			break;
-		}
-		case 0x1C: { // setSkippable
-			printf("setSkippable\n");
-			break;
-		}
-		case 0x1D: { // clearSkippable
-			printf("clearSkippable\n");
-			break;
-		}
-		case 0x1E: { // loadAnimBlob
-			std::string obj = formatValue();
-			std::string slot = formatValue();
-			std::string frame = formatValue();
-			printf("loadAnimBlob obj=%s slot=%s frame=%s\n", obj.c_str(), slot.c_str(), frame.c_str());
-			break;
-		}
-		case 0x1F: { // setPosition
-			std::string obj = formatValue();
-			std::string x = formatValue();
-			std::string y = formatValue();
-			printf("setPosition obj=%s pos=(%s, %s)\n", obj.c_str(), x.c_str(), y.c_str());
-			break;
-		}
-		case 0x20: { // setVerticalOffset
-			std::string obj = formatValue();
-			std::string offset = formatValue();
-			printf("setVerticalOffset obj=%s offset=%s\n", obj.c_str(), offset.c_str());
-			break;
-		}
-		case 0x21: { // setMotion
-			std::string obj = formatValue();
-			std::string target = formatValue();
-			std::string delta = formatValue();
-			std::string dist = formatValue();
-			printf("setMotion obj=%s target=%s delta=%s dist=%s\n", obj.c_str(), target.c_str(), delta.c_str(), dist.c_str());
-			break;
-		}
-		case 0x22: { // setAnimIndex
-			std::string obj = formatValue();
-			std::string anim = formatValue();
-			printf("setAnimIndex obj=%s anim=%s\n", obj.c_str(), anim.c_str());
-			break;
-		}
-		case 0x23: { // moveToPosition
-			std::string obj = formatValue();
-			std::string x = formatValue();
-			std::string y = formatValue();
-			std::string voff = formatValue();
-			printf("moveToPosition obj=%s pos=(%s, %s) voff=%s\n", obj.c_str(), x.c_str(), y.c_str(), voff.c_str());
-			break;
-		}
-		case 0x24: { // add
-			std::string a = formatValue();
-			std::string b = formatValue();
-			printf("add %s, %s\n", a.c_str(), b.c_str());
-			break;
-		}
-		case 0x25: { // subtract
-			std::string a = formatValue();
-			std::string b = formatValue();
-			printf("subtract %s, %s\n", a.c_str(), b.c_str());
-			break;
-		}
-		case 0x26: { // loadSpecialAnim
-			std::string obj = formatValue();
-			std::string decodeFlag = formatValue(); // decode/enable flag (runtime +0x182)
-			uint8_t animIdx = readByte();
-			printf("loadSpecialAnim obj=%s decode=%s anim=%u\n", obj.c_str(), decodeFlag.c_str(), animIdx);
-			break;
-		}
-		case 0x27: { // setMaxAnimFrame
-			std::string obj = formatValue();
-			std::string maxFrame = formatValue();
-			printf("setMaxAnimFrame obj=%s maxFrame=%s\n", obj.c_str(), maxFrame.c_str());
-			break;
-		}
-		case 0x28: { // nop28
-			printf("nop28\n");
-			break;
-		}
-		case 0x29: { // loadSong
-			std::string obj = formatValue();
-			printf("loadSong obj=%s\n", obj.c_str());
-			break;
-		}
-		case 0x2A: { // loadAnimFromScene
-			std::string obj = formatValue();
-			std::string slot = formatValue();
-			std::string decode = formatValue();
-			uint8_t idx = readByte();
-			printf("loadAnimFromScene obj=%s slot=%s decode=%s idx=%u\n", obj.c_str(), slot.c_str(), decode.c_str(), idx);
-			break;
-		}
-		case 0x2B: { // setShading
-			std::string obj = formatValue();
-			printf("setShading obj=%s\n", obj.c_str());
-			break;
-		}
-		case 0x2C: { // setParent
-			std::string obj = formatValue();
-			std::string val = formatValue();
-			printf("setParent obj=%s val=%s\n", obj.c_str(), val.c_str());
-			break;
-		}
-		case 0x2D: { // setScaling
-			std::string obj = formatValue();
-			std::string val = formatValue();
-			printf("setScaling obj=%s val=%s\n", obj.c_str(), val.c_str());
-			break;
-		}
-		case 0x2E: { // checkAnimRange
-			std::string anim = formatValue();
-			std::string lo = formatValue();
-			std::string hi = formatValue();
-			printf("checkAnimRange anim=%s range=[%s, %s]\n", anim.c_str(), lo.c_str(), hi.c_str());
-			break;
-		}
-		case 0x2F: { // checkBlobRange
-			std::string obj = formatValue();
-			std::string slot = formatValue();
-			std::string lo = formatValue();
-			std::string hi = formatValue();
-			printf("checkBlobRange obj=%s slot=%s range=[%s, %s]\n", obj.c_str(), slot.c_str(), lo.c_str(), hi.c_str());
-			break;
-		}
-		case 0x30: { // nop30
-			printf("nop30\n");
-			break;
-		}
-		case 0x31: { // setVolume
-			std::string vol = formatValue();
-			printf("setVolume %s\n", vol.c_str());
-			break;
-		}
-		case 0x32: { // setClickable
-			std::string obj = formatValue();
-			std::string val = formatValue();
-			printf("setClickable obj=%s val=%s\n", obj.c_str(), val.c_str());
-			break;
-		}
-		case 0x33: { // setVisible
-			std::string obj = formatValue();
-			std::string val = formatValue();
-			printf("setVisible obj=%s val=%s\n", obj.c_str(), val.c_str());
-			break;
-		}
-		case 0x34: { // setHotspotRemap
-			std::string a = formatValue();
-			std::string b = formatValue();
-			printf("setHotspotRemap %s -> %s\n", a.c_str(), b.c_str());
-			break;
-		}
-		case 0x35: { // setBoundsAttach
-			std::string obj = formatValue();
-			std::string parent = formatValue();
-			std::string a = formatValue();
-			std::string b = formatValue();
-			std::string c = formatValue();
-			printf("setBoundsAttach obj=%s parent=%s (%s, %s, %s)\n",
-				   obj.c_str(), parent.c_str(), a.c_str(), b.c_str(), c.c_str());
-			break;
-		}
-		case 0x36: { // dismissAllPanels
-			printf("dismissAllPanels\n");
-			break;
-		}
-		case 0x37: { // resetScript
-			printf("resetScript\n");
-			break;
-		}
-		case 0x38: { // loadOverlayFont
-			uint8_t resIdx = readByte();
-			printf("loadOverlayFont res=%u\n", resIdx);
-			break;
-		}
-		case 0x39: { // endOverlayText
-			printf("endOverlayText\n");
-			break;
-		}
-		case 0x3A: { // addOverlayEntry
-			std::string x = formatValue();
-			std::string y = formatValue();
-			std::string align = formatValue();
-			uint16_t strOffset = readWord();
-			uint16_t entryType = readWord();
-			printf("addOverlayEntry pos=(%s, %s) align=%s str=%u type=%u\n",
-				   x.c_str(), y.c_str(), align.c_str(), strOffset, entryType);
-			break;
-		}
-		case 0x3B: { // clearOverlayEntries
-			printf("clearOverlayEntries\n");
-			break;
-		}
-		case 0x3C: { // fadeToBlack
-			std::string speed = formatValue();
-			printf("fadeToBlack %s\n", speed.c_str());
-			break;
-		}
-		case 0x3D: { // fadeFromBlack
-			std::string speed = formatValue();
-			printf("fadeFromBlack %s\n", speed.c_str());
-			break;
-		}
-		case 0x3E: { // loadSoundRes
-			uint8_t resIdx = readByte();
-			printf("loadSoundRes res=%u\n", resIdx);
-			break;
-		}
-		case 0x3F: { // clearSound
-			printf("clearSound\n");
-			break;
-		}
-		case 0x40: { // playSound
-			printf("playSound\n");
-			break;
-		}
-		case 0x41: { // waitForSound
-			printf("waitForSound\n");
-			break;
-		}
-		case 0x42: { // stopSound
-			printf("stopSound\n");
-			break;
-		}
-		case 0x43: { // loadMusicSlot
-			std::string slot = formatValue();
-			uint8_t resIdx = readByte();
-			printf("loadMusicSlot slot=%s res=%u\n", slot.c_str(), resIdx);
-			break;
-		}
-		case 0x44: { // playMusic
-			std::string slot = formatValue();
-			std::string a = formatValue();
-			std::string b = formatValue();
-			printf("playMusic slot=%s %s %s\n", slot.c_str(), a.c_str(), b.c_str());
-			break;
-		}
-		case 0x45: { // stopMusic
-			std::string slot = formatValue();
-			std::string a = formatValue();
-			std::string b = formatValue();
-			printf("stopMusic slot=%s %s %s\n", slot.c_str(), a.c_str(), b.c_str());
-			break;
-		}
-		case 0x46: { // freeMusic
-			std::string slot = formatValue();
-			printf("freeMusic slot=%s\n", slot.c_str());
-			break;
-		}
-		case 0x47: { // waitForMusic
-			printf("waitForMusic\n");
-			break;
-		}
-		case 0x48: { // getObjectX
-			std::string obj = formatValue();
-			printf("getObjectX obj=%s\n", obj.c_str());
-			break;
-		}
-		case 0x49: { // getObjectY
-			std::string obj = formatValue();
-			printf("getObjectY obj=%s\n", obj.c_str());
-			break;
-		}
-		case 0x4A: { // getObjectField
-			std::string obj = formatValue();
-			printf("getObjectField obj=%s\n", obj.c_str());
-			break;
-		}
-		case 0x4B: { // getObjectOrient
-			std::string obj = formatValue();
-			printf("getObjectOrient obj=%s\n", obj.c_str());
+		if (pos != endPos)
+			pos = endPos;
+	}
+	return lines;
+}
+
+static void disassemble() {
+	auto lines = decompileToLines();
+	for (const auto &l : lines) {
+		for (int i = 0; i < l.indent; i++)
+			printf("  ");
+		printf("%04x: %s%s\n", l.offset, getOpcodeName(l.opcode), l.params.c_str());
+	}
+}
+
+static std::string jsonEscape(const std::string &s) {
+	std::string out;
+	for (char c : s) {
+		switch (c) {
+		case '"':
+			out += "\\\"";
 			break;
-		}
-		case 0x4C: { // clearActorItems
-			printf("clearActorItems\n");
+		case '\\':
+			out += "\\\\";
 			break;
-		}
-		case 0x4D: { // setAreaRemap
-			std::string a = formatValue();
-			std::string b = formatValue();
-			printf("setAreaRemap %s -> %s\n", a.c_str(), b.c_str());
+		case '\n':
+			out += "\\n";
 			break;
-		}
-		case 0x4E: { // waitForAdlib
-			printf("waitForAdlib\n");
+		case '\t':
+			out += "\\t";
 			break;
-		}
-		default: {
-			printf("??? opcode=0x%02x len=%u\n", opcode, length);
+		default:
+			out += c;
 			break;
 		}
-		}
+	}
+	return out;
+}
 
-		if (pos != endPos) {
-			pos = endPos;
-		}
+static void disassembleJson(int sceneIndex) {
+	auto lines = decompileToLines();
+	printf("  {\"scene\": %d, \"size\": %u, \"instructions\": [\n", sceneIndex, scriptSize);
+	for (size_t i = 0; i < lines.size(); i++) {
+		const auto &l = lines[i];
+		std::string text = std::string(getOpcodeName(l.opcode)) + l.params;
+		printf("    {\"offset\": %u, \"opcode\": %u, \"name\": \"%s\", \"indent\": %d, \"text\": \"%s\"}%s\n",
+			   l.offset, l.opcode, jsonEscape(getOpcodeName(l.opcode)).c_str(),
+			   l.indent, jsonEscape(text).c_str(),
+			   (i + 1 < lines.size()) ? "," : "");
 	}
+	printf("  ]}");
 }
 
 static void printHelp(const char *bin) {
 	printf("MACS2 Script Decompiler\n\n");
-	printf("Usage: %s <game_data_file> [scene_index]\n\n", bin);
+	printf("Usage: %s [--json] <game_data_file> [scene_index]\n\n", bin);
+	printf("  --json          - Output as JSON\n");
 	printf("  game_data_file  - The main game data file\n");
 	printf("  scene_index     - Scene number to decompile (1-based)\n");
 	printf("                    If omitted, decompiles all scenes\n\n");
@@ -587,17 +774,24 @@ static bool loadSceneScript(FILE *f, uint16_t sceneIndex) {
 	fseek(f, offset, SEEK_SET);
 
 	uint32_t sceneDataOffset;
-	if (fread(&sceneDataOffset, 4, 1, f) != 1) return false;
+	if (fread(&sceneDataOffset, 4, 1, f) != 1)
+		return false;
+
+	if (sceneDataOffset == 0)
+		return false;
 
 	fseek(f, sceneDataOffset + 0x80, SEEK_SET);
 
 	uint16_t size;
-	if (fread(&size, 2, 1, f) != 1) return false;
+	if (fread(&size, 2, 1, f) != 1)
+		return false;
 
-	if (size == 0) return false;
+	if (size == 0)
+		return false;
 
 	scriptData = (uint8_t *)malloc(size);
-	if (!scriptData) return false;
+	if (!scriptData)
+		return false;
 
 	if (fread(scriptData, 1, size, f) != size) {
 		free(scriptData);
@@ -616,53 +810,71 @@ int main(int argc, char **argv) {
 		return 1;
 	}
 
-	FILE *f = fopen(argv[1], "rb");
+	bool jsonMode = false;
+	int argIdx = 1;
+	if (!strcmp(argv[argIdx], "--json")) {
+		jsonMode = true;
+		argIdx++;
+	}
+
+	if (argIdx >= argc) {
+		printHelp(argv[0]);
+		return 1;
+	}
+
+	FILE *f = fopen(argv[argIdx], "rb");
 	if (!f) {
-		fprintf(stderr, "Error: Cannot open file '%s'\n", argv[1]);
+		fprintf(stderr, "Error: Cannot open file '%s'\n", argv[argIdx]);
 		return 1;
 	}
+	argIdx++;
 
 	int startScene = -1;
 	int endScene = -1;
 
-	if (argc >= 3) {
-		startScene = atoi(argv[2]);
+	if (argIdx < argc) {
+		startScene = atoi(argv[argIdx]);
 		endScene = startScene;
 	} else {
 		startScene = 1;
 		endScene = 512;
 	}
 
-	printf("; MACS2 Script Runtime Variables (type 0xFF, read-only)\n");
-	printf("; These are computed by the engine at read-time, not stored in script data.\n");
-	printf("; interactedUse    (FF:01) Object ID interacted with via Use/UseInventory cursor\n");
-	printf("; interactedLook   (FF:02) Object ID interacted with via Look cursor\n");
-	printf("; interactedTalk   (FF:03) Object ID interacted with via Talk cursor\n");
-	printf("; areaAtActor      (FF:04) Area ID at protagonist's current position\n");
-	printf("; isRepeatRun      (FF:0B) 1 during repeat/object script pass, 0 otherwise\n");
-	printf("; dialogueResult   (FF:0D) Index of last chosen dialogue option\n");
-	printf("; pathWalkable     (FF:23) 1 if last setPosition path test succeeded\n");
-	printf("; actorX           (FF:24) Protagonist X position\n");
-	printf("; actorY           (FF:25) Protagonist Y position\n");
-	printf("; isSceneInit      (FF:26) 1 during scene initialization pass\n");
-	printf("; invCheck         (FF:28) 1 if last setParent inventory check matched\n");
-	printf("; invCombine       (FF:2A) 1 if inventory combine pending (no UI open)\n");
-	printf("; invAction        (FF:2B) 1 if inventory action pending (no UI open)\n");
-	printf("; curScene         (FF:2D) Current scene index\n");
-	printf("; prevScene        (FF:2F) Previous scene index\n");
-	printf(";\n");
-	printf("; Script variables: var[N] (read/write, all zeroed on scene load)\n");
-	printf("; Object IDs in moveObject/etc.: raw value - 0x400 = object index\n");
-	printf(";\n\n");
-
-	for (int scene = startScene; scene <= endScene; scene++) {
-		if (loadSceneScript(f, (uint16_t)scene)) {
-			printf("=== Scene %d (size: %u bytes) ===\n", scene, scriptSize);
-			disassemble();
-			printf("\n");
-			free(scriptData);
-			scriptData = nullptr;
-			scriptSize = 0;
+	if (jsonMode) {
+		printf("{\"scenes\": [\n");
+		bool first = true;
+		for (int scene = startScene; scene <= endScene; scene++) {
+			if (loadSceneScript(f, (uint16_t)scene)) {
+				if (!first)
+					printf(",\n");
+				first = false;
+				disassembleJson(scene);
+				free(scriptData);
+				scriptData = nullptr;
+				scriptSize = 0;
+			}
+		}
+		printf("\n]}\n");
+	} else {
+		printf("; MACS2 Script Runtime Variables (type 0xFF, read-only)\n");
+		printf("; These are computed by the engine at read-time, not stored in script data.\n");
+		for (const auto &s : kSpecialNames) {
+			printf("; %-18s (FF:%02x)\n", s.name, s.id);
+		}
+		printf(";\n");
+		printf("; Script variables: var[N] (read/write, all zeroed on scene load)\n");
+		printf("; Object IDs in moveObject/etc.: raw value - 0x400 = object index\n");
+		printf(";\n\n");
+
+		for (int scene = startScene; scene <= endScene; scene++) {
+			if (loadSceneScript(f, (uint16_t)scene)) {
+				printf("=== Scene %d (size: %u bytes) ===\n", scene, scriptSize);
+				disassemble();
+				printf("\n");
+				free(scriptData);
+				scriptData = nullptr;
+				scriptSize = 0;
+			}
 		}
 	}
 


Commit: fadaad3fbf935207e9f37a2865ac07a00f0e43bf
    https://github.com/scummvm/scummvm-tools/commit/fadaad3fbf935207e9f37a2865ac07a00f0e43bf
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-05-31T18:08:08+02:00

Commit Message:
MASC2: started to export json scene data, too

Changed paths:
    engines/macs2/extract_macs2.cpp


diff --git a/engines/macs2/extract_macs2.cpp b/engines/macs2/extract_macs2.cpp
index 5a6c3f0d..dd10941e 100644
--- a/engines/macs2/extract_macs2.cpp
+++ b/engines/macs2/extract_macs2.cpp
@@ -21,8 +21,8 @@
 
 /* MACS2 Resource Extractor - extracts images, sounds, music, and strings */
 
-#include <stdio.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string>
@@ -68,7 +68,8 @@ static bool decodeRLEImage(uint32_t offset, uint8_t *pixels) {
 	fseek(resFile, offset, SEEK_SET);
 	for (int y = 0; y < 200; y++) {
 		uint16_t length = readU16(resFile);
-		if (length == 0 || length > 960) return false;
+		if (length == 0 || length > 960)
+			return false;
 		std::vector<uint8_t> rowData(length);
 		fread(rowData.data(), 1, length, resFile);
 		int remaining = 320;
@@ -81,7 +82,8 @@ static bool decodeRLEImage(uint32_t offset, uint8_t *pixels) {
 				pixels[y * 320 + x++] = val;
 				remaining--;
 			} else {
-				if (ptr + 2 > end) break;
+				if (ptr + 2 > end)
+					break;
 				uint8_t runLen = *ptr++;
 				uint8_t runVal = *ptr++;
 				for (int i = 0; i < runLen && remaining > 0; i++) {
@@ -97,7 +99,10 @@ static bool decodeRLEImage(uint32_t offset, uint8_t *pixels) {
 // Write a BMP file (8-bit indexed)
 static void writeBMP(const char *path, const uint8_t *pixels, const uint8_t *palette) {
 	FILE *f = fopen(path, "wb");
-	if (!f) { fprintf(stderr, "Cannot write %s\n", path); return; }
+	if (!f) {
+		fprintf(stderr, "Cannot write %s\n", path);
+		return;
+	}
 
 	// BMP header
 	uint32_t imageSize = 320 * 200;
@@ -106,21 +111,27 @@ static void writeBMP(const char *path, const uint8_t *pixels, const uint8_t *pal
 	uint32_t fileSize = dataOffset + imageSize;
 
 	// File header
-	fputc('B', f); fputc('M', f);
+	fputc('B', f);
+	fputc('M', f);
 	uint8_t hdr[12] = {};
-	hdr[0] = fileSize & 0xFF; hdr[1] = (fileSize >> 8) & 0xFF;
-	hdr[2] = (fileSize >> 16) & 0xFF; hdr[3] = (fileSize >> 24) & 0xFF;
-	hdr[8] = dataOffset & 0xFF; hdr[9] = (dataOffset >> 8) & 0xFF;
-	hdr[10] = (dataOffset >> 16) & 0xFF; hdr[11] = (dataOffset >> 24) & 0xFF;
+	hdr[0] = fileSize & 0xFF;
+	hdr[1] = (fileSize >> 8) & 0xFF;
+	hdr[2] = (fileSize >> 16) & 0xFF;
+	hdr[3] = (fileSize >> 24) & 0xFF;
+	hdr[8] = dataOffset & 0xFF;
+	hdr[9] = (dataOffset >> 8) & 0xFF;
+	hdr[10] = (dataOffset >> 16) & 0xFF;
+	hdr[11] = (dataOffset >> 24) & 0xFF;
 	fwrite(hdr, 1, 12, f);
 
 	// DIB header (BITMAPINFOHEADER)
 	uint8_t dib[40] = {};
 	dib[0] = 40; // header size
-	dib[4] = 0x40; dib[5] = 0x01; // width = 320
+	dib[4] = 0x40;
+	dib[5] = 0x01; // width = 320
 	dib[8] = 0xC8; // height = 200 (positive = bottom-up)
-	dib[12] = 1; // planes
-	dib[14] = 8; // bpp
+	dib[12] = 1;   // planes
+	dib[14] = 8;   // bpp
 	fwrite(dib, 1, 40, f);
 
 	// Palette (BGRA)
@@ -141,13 +152,18 @@ static void writeBMP(const char *path, const uint8_t *pixels, const uint8_t *pal
 	printf("  Wrote %s\n", path);
 }
 
+// Forward declaration
+static bool decodeRLEMap(FILE *f, uint8_t *pixels);
+
 // Extract background image for a scene
 static void extractImage(uint16_t sceneIndex, const char *outDir) {
 	uint32_t bgOffset = getSceneBgOffset(sceneIndex);
-	if (bgOffset == 0) return;
+	if (bgOffset == 0)
+		return;
 
 	uint8_t pixels[320 * 200];
-	if (!decodeRLEImage(bgOffset, pixels)) return;
+	if (!decodeRLEImage(bgOffset, pixels))
+		return;
 
 	// Palette follows immediately after the image
 	uint8_t palette[768];
@@ -156,12 +172,26 @@ static void extractImage(uint16_t sceneIndex, const char *outDir) {
 	char path[512];
 	snprintf(path, sizeof(path), "%s/scene_%03d.bmp", outDir, sceneIndex);
 	writeBMP(path, pixels, palette);
+
+	// Export the 4 maps as BMP using the scene's own palette (same as imgui debugger)
+	fseek(resFile, 256, SEEK_CUR); // shading table
+	fseek(resFile, 3, SEEK_CUR);   // 3 unknown bytes
+
+	const char *mapNames[] = {"depth", "pathfinding", "unknown", "hotspot"};
+	for (int m = 0; m < 4; m++) {
+		uint8_t mapPixels[320 * 200];
+		if (!decodeRLEMap(resFile, mapPixels))
+			break;
+		snprintf(path, sizeof(path), "%s/scene_%03d_%s.bmp", outDir, sceneIndex, mapNames[m]);
+		writeBMP(path, mapPixels, palette);
+	}
 }
 
 // Extract indexed resources (sounds/music) for a scene
 static void extractResources(uint16_t sceneIndex, const char *outDir, const char *prefix) {
 	uint32_t dataOffset = getSceneDataOffset(sceneIndex);
-	if (dataOffset == 0) return;
+	if (dataOffset == 0)
+		return;
 
 	fseek(resFile, dataOffset, SEEK_SET);
 	uint32_t resourceTable[32]; // 0x80 / 4 = 32 entries
@@ -170,10 +200,12 @@ static void extractResources(uint16_t sceneIndex, const char *outDir, const char
 	}
 
 	for (int i = 0; i < 32; i++) {
-		if (resourceTable[i] == 0) continue;
+		if (resourceTable[i] == 0)
+			continue;
 		fseek(resFile, resourceTable[i], SEEK_SET);
 		uint32_t size = readU32(resFile);
-		if (size == 0 || size > 0x100000) continue;
+		if (size == 0 || size > 0x100000)
+			continue;
 
 		std::vector<uint8_t> data(size);
 		fread(data.data(), 1, size, resFile);
@@ -204,11 +236,13 @@ static std::string decryptString(const uint8_t *data, uint16_t length) {
 // Extract strings for a scene
 static void extractStrings(uint16_t sceneIndex, const char *outDir) {
 	uint32_t strOffset = getSceneStringsOffset(sceneIndex);
-	if (strOffset == 0) return;
+	if (strOffset == 0)
+		return;
 
 	fseek(resFile, strOffset, SEEK_SET);
 	uint16_t totalSize = readU16(resFile);
-	if (totalSize == 0) return;
+	if (totalSize == 0)
+		return;
 
 	std::vector<uint8_t> strData(totalSize);
 	fread(strData.data(), 1, totalSize, resFile);
@@ -216,7 +250,8 @@ static void extractStrings(uint16_t sceneIndex, const char *outDir) {
 	char path[512];
 	snprintf(path, sizeof(path), "%s/strings_scene%03d.txt", outDir, sceneIndex);
 	FILE *out = fopen(path, "w");
-	if (!out) return;
+	if (!out)
+		return;
 
 	fprintf(out, "; Scene %d strings\n", sceneIndex);
 	fprintf(out, "; Total data size: %u bytes\n\n", totalSize);
@@ -227,7 +262,8 @@ static void extractStrings(uint16_t sceneIndex, const char *outDir) {
 	while (pos + 2 <= totalSize) {
 		uint16_t len = strData[pos] | (strData[pos + 1] << 8);
 		pos += 2;
-		if (len == 0 || pos + len > totalSize) break;
+		if (len == 0 || pos + len > totalSize)
+			break;
 		std::string decoded = decryptString(strData.data() + pos, len);
 		fprintf(out, "[%d] (offset=%u) %s\n", stringIndex, (unsigned)(pos - 2), decoded.c_str());
 		pos += len;
@@ -246,14 +282,238 @@ static void mkdirp(const char *path) {
 #endif
 }
 
+// Skip an RLE-compressed 320x200 image in the file (advance past it without decoding)
+static void skipRLEImage(FILE *f) {
+	for (int y = 0; y < 200; y++) {
+		uint16_t length = readU16(f);
+		fseek(f, length, SEEK_CUR);
+	}
+}
+
+// Decode an RLE 320x200 image into a buffer
+static bool decodeRLEMap(FILE *f, uint8_t *pixels) {
+	for (int y = 0; y < 200; y++) {
+		uint16_t length = readU16(f);
+		if (length == 0 || length > 960)
+			return false;
+		std::vector<uint8_t> rowData(length);
+		fread(rowData.data(), 1, length, f);
+		int remaining = 320;
+		int x = 0;
+		uint8_t *ptr = rowData.data();
+		uint8_t *end = ptr + length;
+		while (remaining > 0 && ptr < end) {
+			uint8_t val = *ptr++;
+			if (val != 0xF0) {
+				pixels[y * 320 + x++] = val;
+				remaining--;
+			} else {
+				if (ptr + 2 > end)
+					break;
+				uint8_t runLen = *ptr++;
+				uint8_t runVal = *ptr++;
+				for (int i = 0; i < runLen && remaining > 0; i++) {
+					pixels[y * 320 + x++] = runVal;
+					remaining--;
+				}
+			}
+		}
+	}
+	return true;
+}
+
+static void writeRawFile(const char *path, const uint8_t *data, size_t size) {
+	FILE *f = fopen(path, "wb");
+	if (f) {
+		fwrite(data, 1, size, f);
+		fclose(f);
+	}
+}
+
+// Extract comprehensive scene data as JSON + binary map files
+static void extractSceneData(uint16_t sceneIndex, const char *outDir) {
+	uint32_t bgOffset = getSceneBgOffset(sceneIndex);
+	if (bgOffset == 0)
+		return;
+
+	uint32_t dataOffset = getSceneDataOffset(sceneIndex);
+	uint32_t stringsOffset = getSceneStringsOffset(sceneIndex);
+
+	fseek(resFile, bgOffset, SEEK_SET);
+	skipRLEImage(resFile); // background image
+
+	// Palette (768 bytes, 6-bit VGA)
+	uint8_t palette[768];
+	fread(palette, 1, 768, resFile);
+
+	// Shading table (256 bytes)
+	uint8_t shadingTable[256];
+	fread(shadingTable, 1, 256, resFile);
+
+	// 3 unknown bytes
+	uint8_t unknownBytes[3];
+	fread(unknownBytes, 1, 3, resFile);
+
+	// 4 RLE maps (each 320x200)
+	uint8_t depthMap[320 * 200];
+	uint8_t pathfindingMap[320 * 200];
+	uint8_t unknownMap[320 * 200];
+	uint8_t hotspotMap[320 * 200];
+	decodeRLEMap(resFile, depthMap);
+	decodeRLEMap(resFile, pathfindingMap);
+	decodeRLEMap(resFile, unknownMap);
+	decodeRLEMap(resFile, hotspotMap);
+
+	// Write map binary files
+	char path[512];
+	snprintf(path, sizeof(path), "%s/scene%03d_depth.bin", outDir, sceneIndex);
+	writeRawFile(path, depthMap, sizeof(depthMap));
+	snprintf(path, sizeof(path), "%s/scene%03d_pathfinding.bin", outDir, sceneIndex);
+	writeRawFile(path, pathfindingMap, sizeof(pathfindingMap));
+	snprintf(path, sizeof(path), "%s/scene%03d_unknown.bin", outDir, sceneIndex);
+	writeRawFile(path, unknownMap, sizeof(unknownMap));
+	snprintf(path, sizeof(path), "%s/scene%03d_hotspot.bin", outDir, sceneIndex);
+	writeRawFile(path, hotspotMap, sizeof(hotspotMap));
+
+	// Pathfinding nodes: 16 entries × 10 bytes
+	struct PathNode {
+		uint16_t x, y;
+		uint8_t adj[4];
+		uint16_t numConnections;
+	} nodes[16];
+	for (int i = 0; i < 16; i++) {
+		nodes[i].x = readU16(resFile);
+		nodes[i].y = readU16(resFile);
+		fread(nodes[i].adj, 1, 4, resFile);
+		nodes[i].numConnections = readU16(resFile);
+	}
+
+	uint16_t numHotspots = readU16(resFile);
+
+	// Hotspot color table: 16 uint16 entries (maps pixel value to object ID)
+	uint16_t hotspotColors[16];
+	for (int i = 0; i < 16; i++)
+		hotspotColors[i] = readU16(resFile);
+
+	// Resource offsets from data block (32 dwords = special anim file offsets)
+	uint32_t resourceOffsets[32] = {};
+	uint32_t mapImageOffset = 0;
+	if (dataOffset != 0) {
+		fseek(resFile, dataOffset, SEEK_SET);
+		for (int i = 0; i < 32; i++)
+			resourceOffsets[i] = readU32(resFile);
+		// Map image offset at data block +0x3C0
+		fseek(resFile, dataOffset + 0x3C0, SEEK_SET);
+		mapImageOffset = readU32(resFile);
+	}
+
+	// Script size
+	uint16_t scriptSize = 0;
+	if (dataOffset != 0) {
+		fseek(resFile, dataOffset + 0x80, SEEK_SET);
+		scriptSize = readU16(resFile);
+	}
+
+	// Strings size
+	uint16_t stringsSize = 0;
+	if (stringsOffset != 0) {
+		fseek(resFile, stringsOffset, SEEK_SET);
+		stringsSize = readU16(resFile);
+	}
+
+	// Write JSON
+	snprintf(path, sizeof(path), "%s/scenedata_%03d.json", outDir, sceneIndex);
+	FILE *out = fopen(path, "w");
+	if (!out)
+		return;
+
+	fprintf(out, "{\n");
+	fprintf(out, "  \"scene\": %d,\n", sceneIndex);
+	fprintf(out, "  \"offsets\": {\n");
+	fprintf(out, "    \"background\": %u,\n", bgOffset);
+	fprintf(out, "    \"data\": %u,\n", dataOffset);
+	fprintf(out, "    \"strings\": %u,\n", stringsOffset);
+	fprintf(out, "    \"mapImage\": %u\n", mapImageOffset);
+	fprintf(out, "  },\n");
+	fprintf(out, "  \"scriptSize\": %u,\n", scriptSize);
+	fprintf(out, "  \"stringsSize\": %u,\n", stringsSize);
+
+	// Palette
+	fprintf(out, "  \"palette\": [");
+	for (int i = 0; i < 256; i++) {
+		if (i > 0)
+			fprintf(out, ",");
+		if (i % 8 == 0)
+			fprintf(out, "\n    ");
+		fprintf(out, "[%u,%u,%u]", palette[i * 3], palette[i * 3 + 1], palette[i * 3 + 2]);
+	}
+	fprintf(out, "\n  ],\n");
+
+	// Shading table
+	fprintf(out, "  \"shadingTable\": [");
+	for (int i = 0; i < 256; i++) {
+		if (i > 0)
+			fprintf(out, ",");
+		if (i % 32 == 0)
+			fprintf(out, "\n    ");
+		fprintf(out, "%u", shadingTable[i]);
+	}
+	fprintf(out, "\n  ],\n");
+
+	fprintf(out, "  \"unknownBytes\": [%u, %u, %u],\n", unknownBytes[0], unknownBytes[1], unknownBytes[2]);
+
+	// Pathfinding nodes
+	fprintf(out, "  \"pathfindingNodes\": [\n");
+	for (int i = 0; i < 16; i++) {
+		fprintf(out, "    {\"index\": %d, \"x\": %u, \"y\": %u, \"adjacent\": [", i, nodes[i].x, nodes[i].y);
+		for (uint16_t j = 0; j < nodes[i].numConnections && j < 4; j++) {
+			if (j > 0)
+				fprintf(out, ", ");
+			fprintf(out, "%u", nodes[i].adj[j]);
+		}
+		fprintf(out, "]}%s\n", i < 15 ? "," : "");
+	}
+	fprintf(out, "  ],\n");
+
+	fprintf(out, "  \"numHotspots\": %u,\n", numHotspots);
+	fprintf(out, "  \"hotspotColorTable\": [");
+	for (int i = 0; i < 16; i++) {
+		if (i > 0)
+			fprintf(out, ", ");
+		fprintf(out, "%u", hotspotColors[i]);
+	}
+	fprintf(out, "],\n");
+
+	// Resource offsets (special animation file offsets)
+	fprintf(out, "  \"resourceOffsets\": [");
+	for (int i = 0; i < 32; i++) {
+		if (i > 0)
+			fprintf(out, ", ");
+		fprintf(out, "%u", resourceOffsets[i]);
+	}
+	fprintf(out, "],\n");
+
+	// Map file references
+	fprintf(out, "  \"maps\": {\n");
+	fprintf(out, "    \"depth\": \"scene%03d_depth.bin\",\n", sceneIndex);
+	fprintf(out, "    \"pathfinding\": \"scene%03d_pathfinding.bin\",\n", sceneIndex);
+	fprintf(out, "    \"unknown\": \"scene%03d_unknown.bin\",\n", sceneIndex);
+	fprintf(out, "    \"hotspot\": \"scene%03d_hotspot.bin\"\n", sceneIndex);
+	fprintf(out, "  }\n");
+	fprintf(out, "}\n");
+	fclose(out);
+	printf("  Wrote %s + 4 map files\n", path);
+}
+
 static void printHelp(const char *bin) {
 	printf("MACS2 Resource Extractor\n\n");
 	printf("Usage: %s <mode> <game_data_file> <output_dir> [scene_index]\n\n", bin);
 	printf("Modes:\n");
-	printf("  images   - Extract background images as BMP files\n");
-	printf("  sounds   - Extract sound/music resource blobs\n");
-	printf("  strings  - Extract and decrypt text strings\n");
-	printf("  all      - Extract everything\n");
+	printf("  images    - Extract background images as BMP files\n");
+	printf("  sounds    - Extract sound/music resource blobs\n");
+	printf("  strings   - Extract and decrypt text strings\n");
+	printf("  scenedata - Extract scene metadata as JSON (pathfinding, hotspots, walk params)\n");
+	printf("  all       - Extract everything\n");
 	printf("\n");
 	printf("If scene_index is omitted, extracts from all scenes.\n");
 }
@@ -284,6 +544,7 @@ int main(int argc, char **argv) {
 	bool doImages = !strcmp(mode, "images") || !strcmp(mode, "all");
 	bool doSounds = !strcmp(mode, "sounds") || !strcmp(mode, "all");
 	bool doStrings = !strcmp(mode, "strings") || !strcmp(mode, "all");
+	bool doSceneData = !strcmp(mode, "scenedata") || !strcmp(mode, "all");
 
 	for (int scene = startScene; scene <= endScene; scene++) {
 		bool hasData = false;
@@ -291,7 +552,10 @@ int main(int argc, char **argv) {
 		if (doImages) {
 			uint32_t bgOff = getSceneBgOffset(scene);
 			if (bgOff != 0) {
-				if (!hasData) { printf("Scene %d:\n", scene); hasData = true; }
+				if (!hasData) {
+					printf("Scene %d:\n", scene);
+					hasData = true;
+				}
 				extractImage(scene, outDir);
 			}
 		}
@@ -299,7 +563,10 @@ int main(int argc, char **argv) {
 		if (doSounds) {
 			uint32_t dataOff = getSceneDataOffset(scene);
 			if (dataOff != 0) {
-				if (!hasData) { printf("Scene %d:\n", scene); hasData = true; }
+				if (!hasData) {
+					printf("Scene %d:\n", scene);
+					hasData = true;
+				}
 				extractResources(scene, outDir, "res");
 			}
 		}
@@ -307,10 +574,24 @@ int main(int argc, char **argv) {
 		if (doStrings) {
 			uint32_t strOff = getSceneStringsOffset(scene);
 			if (strOff != 0) {
-				if (!hasData) { printf("Scene %d:\n", scene); hasData = true; }
+				if (!hasData) {
+					printf("Scene %d:\n", scene);
+					hasData = true;
+				}
 				extractStrings(scene, outDir);
 			}
 		}
+
+		if (doSceneData) {
+			uint32_t bgOff = getSceneBgOffset(scene);
+			if (bgOff != 0) {
+				if (!hasData) {
+					printf("Scene %d:\n", scene);
+					hasData = true;
+				}
+				extractSceneData(scene, outDir);
+			}
+		}
 	}
 
 	fclose(resFile);


Commit: d06a5562375ce5d27ad6846df1310c566a215856
    https://github.com/scummvm/scummvm-tools/commit/d06a5562375ce5d27ad6846df1310c566a215856
Author: Martin Gerhardy (martin.gerhardy at gmail.com)
Date: 2026-06-03T18:30:41+02:00

Commit Message:
MACS2: this is a shadowmap

Changed paths:
    engines/macs2/extract_macs2.cpp


diff --git a/engines/macs2/extract_macs2.cpp b/engines/macs2/extract_macs2.cpp
index dd10941e..9a9b4a1b 100644
--- a/engines/macs2/extract_macs2.cpp
+++ b/engines/macs2/extract_macs2.cpp
@@ -177,7 +177,7 @@ static void extractImage(uint16_t sceneIndex, const char *outDir) {
 	fseek(resFile, 256, SEEK_CUR); // shading table
 	fseek(resFile, 3, SEEK_CUR);   // 3 unknown bytes
 
-	const char *mapNames[] = {"depth", "pathfinding", "unknown", "hotspot"};
+	const char *mapNames[] = {"depth", "pathfinding", "shadow", "hotspot"};
 	for (int m = 0; m < 4; m++) {
 		uint8_t mapPixels[320 * 200];
 		if (!decodeRLEMap(resFile, mapPixels))
@@ -357,11 +357,11 @@ static void extractSceneData(uint16_t sceneIndex, const char *outDir) {
 	// 4 RLE maps (each 320x200)
 	uint8_t depthMap[320 * 200];
 	uint8_t pathfindingMap[320 * 200];
-	uint8_t unknownMap[320 * 200];
+	uint8_t shadowMap[320 * 200];
 	uint8_t hotspotMap[320 * 200];
 	decodeRLEMap(resFile, depthMap);
 	decodeRLEMap(resFile, pathfindingMap);
-	decodeRLEMap(resFile, unknownMap);
+	decodeRLEMap(resFile, shadowMap);
 	decodeRLEMap(resFile, hotspotMap);
 
 	// Write map binary files
@@ -370,8 +370,8 @@ static void extractSceneData(uint16_t sceneIndex, const char *outDir) {
 	writeRawFile(path, depthMap, sizeof(depthMap));
 	snprintf(path, sizeof(path), "%s/scene%03d_pathfinding.bin", outDir, sceneIndex);
 	writeRawFile(path, pathfindingMap, sizeof(pathfindingMap));
-	snprintf(path, sizeof(path), "%s/scene%03d_unknown.bin", outDir, sceneIndex);
-	writeRawFile(path, unknownMap, sizeof(unknownMap));
+	snprintf(path, sizeof(path), "%s/scene%03d_shadow.bin", outDir, sceneIndex);
+	writeRawFile(path, shadowMap, sizeof(shadowMap));
 	snprintf(path, sizeof(path), "%s/scene%03d_hotspot.bin", outDir, sceneIndex);
 	writeRawFile(path, hotspotMap, sizeof(hotspotMap));
 
@@ -497,7 +497,7 @@ static void extractSceneData(uint16_t sceneIndex, const char *outDir) {
 	fprintf(out, "  \"maps\": {\n");
 	fprintf(out, "    \"depth\": \"scene%03d_depth.bin\",\n", sceneIndex);
 	fprintf(out, "    \"pathfinding\": \"scene%03d_pathfinding.bin\",\n", sceneIndex);
-	fprintf(out, "    \"unknown\": \"scene%03d_unknown.bin\",\n", sceneIndex);
+	fprintf(out, "    \"shadow\": \"scene%03d_shadow.bin\",\n", sceneIndex);
 	fprintf(out, "    \"hotspot\": \"scene%03d_hotspot.bin\"\n", sceneIndex);
 	fprintf(out, "  }\n");
 	fprintf(out, "}\n");




More information about the Scummvm-git-logs mailing list