public void FloorData_ReadWriteTest() { //Read Dragons Lair data TR2LevelReader reader = new TR2LevelReader(); TR2Level lvl = reader.ReadLevel("xian.tr2"); //Store the original floordata from the level ushort[] originalFData = new ushort[lvl.NumFloorData]; Array.Copy(lvl.FloorData, originalFData, lvl.NumFloorData); //Parse the floordata using FDControl and re-write the parsed data back FDControl fdataReader = new FDControl(); fdataReader.ParseFromLevel(lvl); fdataReader.WriteToLevel(lvl); //Store the new floordata written back by FDControl ushort[] newFData = lvl.FloorData; //Compare to make sure the original fdata was written back. CollectionAssert.AreEqual(originalFData, newFData, "Floordata does not match"); Assert.AreEqual((uint)newFData.Length, lvl.NumFloorData); //Now modify an entry, and ensure it is different to the original data. FDPortalEntry portal = fdataReader.Entries[3][0] as FDPortalEntry; portal.Room = 42; fdataReader.WriteToLevel(lvl); //Test. FDIndex 3 of Dragon's Lair is a portal to room 3, which is being modified to Room 42. //Data should be: //New - [3] = 0x8001 and [4] = 0x002A //Get ref to new data newFData = lvl.FloorData; Assert.AreEqual(newFData[3], (ushort)0x8001); Assert.AreEqual(newFData[4], (ushort)0x002A); //Compare to make sure the modified fdata was written back. CollectionAssert.AreNotEqual(originalFData, newFData, "Floordata matches, change unsuccessful"); Assert.AreEqual((uint)newFData.Length, lvl.NumFloorData); //Test pattern/type matching example for fdata. bool isPortal = false; foreach (KeyValuePair <int, List <FDEntry> > sector in fdataReader.Entries) { foreach (FDEntry entry in sector.Value) { switch (entry) { case FDClimbEntry climbEntry: break; case FDKillLaraEntry killEntry: break; case FDPortalEntry portalEntry: isPortal = true; break; case FDSlantEntry slantEntry: break; case FDTriggerEntry triggerEntry: break; } } } Assert.IsTrue(isPortal); }
public void ParseFromLevel(TR2Level lvl) { _entries = new SortedDictionary <int, List <FDEntry> >(); foreach (TR2Room room in lvl.Rooms) { foreach (TRRoomSector sector in room.SectorList) { //Index into FData is FDIndex ushort index = sector.FDIndex; //Index 0 is a dummy if (index == 0) { continue; } //List of floordata functions for the sector List <FDEntry> floordataFunctions = new List <FDEntry>(); while (true) { FDSetup data = new FDSetup() { Value = lvl.FloorData[index] }; switch ((FDFunctions)data.Function) { case FDFunctions.PortalSector: FDPortalEntry portal = new FDPortalEntry() { Setup = new FDSetup() { Value = lvl.FloorData[index] }, Room = lvl.FloorData[++index] }; floordataFunctions.Add(portal); break; case FDFunctions.FloorSlant: FDSlantEntry floorSlant = new FDSlantEntry() { Setup = new FDSetup() { Value = lvl.FloorData[index] }, SlantValue = lvl.FloorData[++index], Type = FDSlantEntryType.FloorSlant }; floordataFunctions.Add(floorSlant); break; case FDFunctions.CeilingSlant: FDSlantEntry ceilingSlant = new FDSlantEntry() { Setup = new FDSetup() { Value = lvl.FloorData[index] }, SlantValue = lvl.FloorData[++index], Type = FDSlantEntryType.CeilingSlant }; floordataFunctions.Add(ceilingSlant); break; case FDFunctions.Trigger: FDTriggerEntry trig = new FDTriggerEntry() { Setup = new FDSetup() { Value = lvl.FloorData[index] }, TrigSetup = new FDTrigSetup() { Value = lvl.FloorData[++index] } }; if (trig.TrigType == FDTrigType.Switch || trig.TrigType == FDTrigType.Key) { //First entry in action list is reference to switch/key entity for switch/key types. trig.SwitchOrKeyRef = lvl.FloorData[++index]; } //We don't know if there are any more yet. bool continueFDParse; //Parse trigactions do { //New trigger action FDActionListItem action = new FDActionListItem() { Value = lvl.FloorData[++index] }; continueFDParse = action.Continue; if (action.TrigAction == FDTrigAction.Camera) { //Camera trig actions have a special extra uint16... FDCameraAction camAction = new FDCameraAction() { Value = lvl.FloorData[++index] }; //store associated camera action action.CamAction = camAction; //Is there more? continueFDParse = camAction.Continue; } //add action trig.TrigActionList.Add(action); } while (index < lvl.NumFloorData && continueFDParse); floordataFunctions.Add(trig); break; case FDFunctions.KillLara: FDKillLaraEntry kill = new FDKillLaraEntry() { Setup = new FDSetup() { Value = lvl.FloorData[index] } }; floordataFunctions.Add(kill); break; case FDFunctions.ClimbableWalls: FDClimbEntry climb = new FDClimbEntry() { Setup = new FDSetup() { Value = lvl.FloorData[index] } }; floordataFunctions.Add(climb); break; case FDFunctions.FloorTriangulationNWSE_Solid: //TR3 Only - Ignore for now... break; case FDFunctions.FloorTriangulationNESW_Solid: //TR3 Only - Ignore for now... break; case FDFunctions.CeilingTriangulationNW_Solid: //TR3 Only - Ignore for now... break; case FDFunctions.CeilingTriangulationNE_Solid: //TR3 Only - Ignore for now... break; case FDFunctions.FloorTriangulationNWSE_SW: //TR3 Only - Ignore for now... break; case FDFunctions.FloorTriangulationNWSE_NE: //TR3 Only - Ignore for now... break; case FDFunctions.FloorTriangulationNESW_SW: //TR3 Only - Ignore for now... break; case FDFunctions.FloorTriangulationNESW_NW: //TR3 Only - Ignore for now... break; case FDFunctions.CeilingTriangulationNW_SW: //TR3 Only - Ignore for now... break; case FDFunctions.CeilingTriangulationNW_NE: //TR3 Only - Ignore for now... break; case FDFunctions.CeilingTriangulationNE_NW: //TR3 Only - Ignore for now... break; case FDFunctions.CeilingTriangulationNE_SE: //TR3 Only - Ignore for now... break; case FDFunctions.Monkeyswing: //TR3 Only - Ignore for now... break; case FDFunctions.DeferredTriggeringOrMinecartRotateLeft: //TR3 Only - Ignore for now... break; case FDFunctions.MechBeetleOrMinecartRotateRight: //TR3 Only - Ignore for now... break; default: break; } if (data.EndData) { //End data (from what I understand) means there is no further functions for this sector. //E.G. Sector 52 on Xian has a slant function and portal function. EndData is not set on //slant function, but is on portal function as there are no further functions. break; } else { //There are further functions for this sector - continue parsing. index++; } } //Store the sector index and all of its associated functions _entries.Add(sector.FDIndex, floordataFunctions); } } }