private static void CMD_39(ref Level lvl, ref string desc, byte[] cmd, byte?areaID) { if (cmd.Length < 8) { return; } ROM rom = ROM.Instance; uint pos = bytesToInt(cmd, 4, 4); desc = "Place macro objects loaded from address 0x" + pos.ToString("X8"); byte[] data = rom.getDataFromSegmentAddress_safe(pos, 10, null); lvl.getCurrentArea().MacroObjects.Clear(); bool endList = false; while (!endList) { //rom.printArray(data, 10); uint id = bytesToInt(data, 0, 2) & 0x1FF; if (id == 0 || id == 0x1E) { break; } Object3D newObj = new Object3D(); if (rom.isSegmentMIO0(cmd[4], areaID)) { newObj.MakeReadOnly(); newObj.Address = "N/A"; } else { newObj.Address = "0x" + rom.decodeSegmentAddress(pos, areaID).ToString("X"); } uint table_off = (id - 0x1F) * 8; byte[] entryData = rom.getSubArray_safe(rom.Bytes, Globals.macro_preset_table + table_off, 8); newObj.level = lvl; newObj.createdFromLevelScriptCommand = Object3D.FROM_LS_CMD.CMD_39; newObj.setBehaviorFromAddress(bytesToInt(entryData, 0, 4)); newObj.HideProperty(Object3D.FLAGS.ROTATION_X); newObj.HideProperty(Object3D.FLAGS.ROTATION_Z); newObj.HideProperty(Object3D.FLAGS.BPARAM_3); newObj.HideProperty(Object3D.FLAGS.BPARAM_4); newObj.ModelID = entryData[5]; ushort firstAndSecond = (ushort)bytesToInt(data, 0, 2); newObj.setPresetID((ushort)(firstAndSecond & 0x1FF)); newObj.yRot = (short)((firstAndSecond >> 9) * 2.8125); newObj.xPos = (short)bytesToInt(data, 2, 2); newObj.yPos = (short)bytesToInt(data, 4, 2); newObj.zPos = (short)bytesToInt(data, 6, 2); newObj.DontShowActs(); newObj.MakeBehaviorReadOnly(true); newObj.MakeModelIDReadOnly(true); ushort bp = (ushort)bytesToInt(data, 8, 2); if (data[8] != 0) { newObj.BehaviorParameter1 = data[8]; } else { newObj.BehaviorParameter1 = entryData[6]; } if (data[9] != 0) { newObj.BehaviorParameter2 = data[9]; } else { newObj.BehaviorParameter2 = entryData[7]; } lvl.getCurrentArea().MacroObjects.Add(newObj); pos += 10; data = rom.getDataFromSegmentAddress_safe(pos, 10, null); } //uint end = bytesToInt(cmd, 8, 4); //rom.setSegment(seg, start, end, false); }
/* Process collision map, Special Objects, and waterboxes. */ private static void CMD_2E(ref Level lvl, ref string desc, byte[] cmd, byte?areaID) { ROM rom = ROM.Instance; if (cmd.Length < 8) { return; } desc = "Load collision, and place special objects from address 0x" + bytesToInt(cmd, 4, 4).ToString("X8"); ushort sub_cmd = 0x40; byte segment = cmd[4]; uint off = bytesToInt(cmd, 5, 3); byte[] data = rom.getSegment(segment, areaID); sub_cmd = (ushort)bytesToInt(data, (int)off, 2); // Check if the data is actually collision data. if (data[off] != 0x00 || data[off + 1] != 0x40) { return; } CollisionMap cmap = lvl.getCurrentArea().collision; uint num_verts = (ushort)bytesToInt(data, (int)off + 2, 2); off += 4; for (int i = 0; i < num_verts; i++) { short x = (short)bytesToInt(data, (int)off + 0, 2); short y = (short)bytesToInt(data, (int)off + 2, 2); short z = (short)bytesToInt(data, (int)off + 4, 2); cmap.AddVertex(new OpenTK.Vector3(x, y, z)); off += 6; } while (sub_cmd != 0x0041) { sub_cmd = (ushort)bytesToInt(data, (int)off, 2); //Console.WriteLine(sub_cmd.ToString("X8")); if (sub_cmd == 0x0041) { break; } //rom.printArraySection(data, (int)off, 4 + (int)collisionLength(sub_cmd)); cmap.NewTriangleList((int)bytesToInt(data, (int)off, 2)); uint num_tri = (ushort)bytesToInt(data, (int)off + 2, 2); uint col_len = collisionLength(sub_cmd); off += 4; for (int i = 0; i < num_tri; i++) { uint a = bytesToInt(data, (int)off + 0, 2); uint b = bytesToInt(data, (int)off + 2, 2); uint c = bytesToInt(data, (int)off + 4, 2); cmap.AddTriangle(a, b, c); off += col_len; } } cmap.buildCollisionMap(); off += 2; bool end = false; while (!end) { sub_cmd = (ushort)bytesToInt(data, (int)off, 2); switch (sub_cmd) { case 0x0042: end = true; break; case 0x0043: uint num_obj = (ushort)bytesToInt(data, (int)off + 2, 2); off += 4; for (int i = 0; i < num_obj; i++) { ushort obj_id = (ushort)bytesToInt(data, (int)off, 2); byte[] entry = getSpecialObjectEntry((byte)obj_id); uint obj_len = getSpecialObjectLength(obj_id); Object3D newObj = new Object3D(); if (rom.isSegmentMIO0(segment, areaID)) { newObj.MakeReadOnly(); newObj.Address = "N/A"; } else { newObj.Address = "0x" + rom.decodeSegmentAddress(segment, off, areaID).ToString("X"); } newObj.setPresetID(obj_id); newObj.level = lvl; newObj.HideProperty(Object3D.FLAGS.ROTATION_X); newObj.HideProperty(Object3D.FLAGS.ROTATION_Z); newObj.HideProperty(Object3D.FLAGS.BPARAM_3); newObj.HideProperty(Object3D.FLAGS.BPARAM_4); newObj.xPos = (short)bytesToInt(data, (int)off + 2, 2); newObj.yPos = (short)bytesToInt(data, (int)off + 4, 2); newObj.zPos = (short)bytesToInt(data, (int)off + 6, 2); newObj.BehaviorParameter1 = entry[1]; newObj.BehaviorParameter2 = entry[2]; newObj.MakeBehaviorReadOnly(true); newObj.MakeModelIDReadOnly(true); if (obj_len > 8) { newObj.yRot = (short)(bytesToInt(data, (int)off + 8, 2) * 1.40625); if (obj_len > 10) { newObj.BehaviorParameter1 = data[off + 10]; newObj.BehaviorParameter2 = data[off + 11]; newObj.createdFromLevelScriptCommand = Object3D.FROM_LS_CMD.CMD_2E_12; lvl.AddSpecialObjectPreset_12(obj_id, entry[3], bytesToInt(entry, 4, 4), data[off + 10], data[off + 11]); } else { lvl.AddSpecialObjectPreset_10(obj_id, entry[3], bytesToInt(entry, 4, 4)); newObj.HideProperty(Object3D.FLAGS.BPARAM_1); newObj.HideProperty(Object3D.FLAGS.BPARAM_2); newObj.createdFromLevelScriptCommand = Object3D.FROM_LS_CMD.CMD_2E_10; } } else { lvl.AddSpecialObjectPreset_8(obj_id, entry[3], bytesToInt(entry, 4, 4)); newObj.HideProperty(Object3D.FLAGS.BPARAM_1); newObj.HideProperty(Object3D.FLAGS.BPARAM_2); newObj.HideProperty(Object3D.FLAGS.ROTATION_Y); newObj.createdFromLevelScriptCommand = Object3D.FROM_LS_CMD.CMD_2E_8; } newObj.ModelID = entry[3]; uint behavior = bytesToInt(entry, 4, 4); newObj.setBehaviorFromAddress(behavior); newObj.DontShowActs(); if (behavior != 0) { lvl.getCurrentArea().SpecialObjects.Add(newObj); } off += obj_len; } break; case 0x0044: // Also skipping water boxes. Will come back to it later. uint num_boxes = (ushort)bytesToInt(data, (int)off + 2, 2); off += 4 + (num_boxes * 0xC); break; } } }
private static void CMD_39(ref Level lvl, byte[] cmd, ROM rom) { if (cmd.Length < 8) { return; } uint pos = bytesToInt(cmd, 4, 4); byte[] data = rom.getDataFromSegmentAddress_safe(pos, 10); lvl.getCurrentArea().MacroObjects.Clear(); bool endList = false; while (!endList) { //rom.printArray(data, 10); uint id = bytesToInt(data, 0, 2) & 0x1FF; if (id == 0 || id == 0x1E) { break; } Object3D newObj = new Object3D(); if (rom.isSegmentMIO0(cmd[4])) { newObj.MakeReadOnly(); newObj.Address = "N/A"; } else { newObj.Address = "0x" + rom.decodeSegmentAddress(pos).ToString("X"); } uint table_off = (id - 0x1F) * 8; byte[] entryData = rom.getSubArray(rom.Bytes, Globals.macro_preset_table + table_off, 8); newObj.level = lvl; newObj.setBehaviorFromAddress(bytesToInt(entryData, 0, 4)); newObj.HideProperty(Object3D.FLAGS.ROTATION_X); newObj.HideProperty(Object3D.FLAGS.ROTATION_Z); newObj.HideProperty(Object3D.FLAGS.BPARAM_3); newObj.HideProperty(Object3D.FLAGS.BPARAM_4); newObj.ModelID = entryData[5]; newObj.setPresetID((ushort)(data[0] & 0x1FF)); newObj.yRot = (short)((data[0] >> 4) * 22.5f); newObj.xPos = (short)bytesToInt(data, 2, 2); newObj.yPos = (short)bytesToInt(data, 4, 2); newObj.zPos = (short)bytesToInt(data, 6, 2); newObj.DontShowActs(); newObj.MakeBehaviorReadOnly(true); newObj.MakeModelIDReadOnly(true); ushort bp = (ushort)bytesToInt(data, 8, 2); if (data[8] != 0) { newObj.BehaviorParameter1 = data[8]; } else { newObj.BehaviorParameter1 = entryData[6]; } if (data[9] != 0) { newObj.BehaviorParameter2 = data[9]; } else { newObj.BehaviorParameter2 = entryData[7]; } lvl.getCurrentArea().MacroObjects.Add(newObj); pos += 10; data = rom.getDataFromSegmentAddress_safe(pos, 10); } //uint end = bytesToInt(cmd, 8, 4); //rom.setSegment(seg, start, end, false); }