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);
        }
Exemple #2
0
        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);
                }
            }
        }