예제 #1
0
        public void FloorData_InsertFDEntryWriteReadTest()
        {
            //Read Dragons Lair data
            TR2LevelReader reader = new TR2LevelReader();
            TR2Level       lvl    = reader.ReadLevel("xian.tr2");

            //Parse the floordata using FDControl
            FDControl fdataReader = new FDControl();

            fdataReader.ParseFromLevel(lvl);

            //Add a music trigger to index 9
            fdataReader.Entries[9].Add(new FDTriggerEntry
            {
                Setup          = new FDSetup(FDFunctions.Trigger),
                TrigSetup      = new FDTrigSetup(),
                TrigActionList = new List <FDActionListItem>
                {
                    new FDActionListItem
                    {
                        TrigAction = FDTrigAction.PlaySoundtrack,
                        Parameter  = 40
                    }
                }
            });

            //Write the data back
            fdataReader.WriteToLevel(lvl);

            //Save it and read it back in
            TR2LevelWriter writer = new TR2LevelWriter();

            writer.WriteLevelToFile(lvl, "TEST.tr2");
            lvl = reader.ReadLevel("TEST.tr2");

            fdataReader = new FDControl();
            fdataReader.ParseFromLevel(lvl);

            //Verify index 9 has two entries, that its first entry
            //does not have EndData set, but that its second does
            Assert.AreEqual(fdataReader.Entries[9].Count, 2);
            Assert.IsFalse(fdataReader.Entries[9][0].Setup.EndData);
            Assert.IsTrue(fdataReader.Entries[9][1].Setup.EndData);

            //Verify the trigger we added matches what we expect
            FDEntry entry = fdataReader.Entries[9][1];

            Assert.IsTrue(entry is FDTriggerEntry);

            FDTriggerEntry triggerEntry = entry as FDTriggerEntry;

            Assert.IsTrue(triggerEntry.Setup.Function == (byte)FDFunctions.Trigger);
            Assert.IsTrue(triggerEntry.TrigActionList.Count == 1);
            Assert.IsTrue(triggerEntry.TrigActionList[0].TrigAction == FDTrigAction.PlaySoundtrack);
            Assert.IsTrue(triggerEntry.TrigActionList[0].Parameter == 40);
        }
예제 #2
0
        public void FloorData_AppendFDActionListItemTest()
        {
            //Read Dragons Lair data
            TR2LevelReader reader = new TR2LevelReader();
            TR2Level       lvl    = reader.ReadLevel("xian.tr2");

            //Parse the floordata using FDControl
            FDControl fdataReader = new FDControl();

            fdataReader.ParseFromLevel(lvl);

            //Add a music action to the trigger at index 13
            FDTriggerEntry trigger = fdataReader.Entries[13][0] as FDTriggerEntry;

            Assert.AreEqual(trigger.TrigActionList.Count, 2);
            trigger.TrigActionList.Add(new FDActionListItem
            {
                TrigAction = FDTrigAction.PlaySoundtrack,
                Parameter  = 40
            });

            //Write the data back
            fdataReader.WriteToLevel(lvl);

            //Save it and read it back in
            TR2LevelWriter writer = new TR2LevelWriter();

            writer.WriteLevelToFile(lvl, "TEST.tr2");
            lvl = reader.ReadLevel("TEST.tr2");

            fdataReader = new FDControl();
            fdataReader.ParseFromLevel(lvl);

            trigger = fdataReader.Entries[13][0] as FDTriggerEntry;
            // Verifying that the trigger has 3 items implicitly verifies that the Continue
            // flag was correctly changed on the previous last item and on the new item,
            // otherwise the parsing would have stopped at the second
            Assert.AreEqual(trigger.TrigActionList.Count, 3);

            Assert.IsTrue(trigger.TrigActionList[2].TrigAction == FDTrigAction.PlaySoundtrack);
            Assert.IsTrue(trigger.TrigActionList[2].Parameter == 40);
        }
예제 #3
0
        public void FloorData_AppendFDActionListItemCamTest()
        {
            //Read Dragons Lair data
            TR2LevelReader reader = new TR2LevelReader();
            TR2Level       lvl    = reader.ReadLevel("xian.tr2");

            //Parse the floordata using FDControl
            FDControl fdataReader = new FDControl();

            fdataReader.ParseFromLevel(lvl);

            //Add a music action to the trigger at index 6010
            //This has a CamAction in its TrigList so this tests
            //that the Continue flag is correctly set
            FDTriggerEntry trigger = fdataReader.Entries[6010][1] as FDTriggerEntry;

            Assert.AreEqual(trigger.TrigActionList.Count, 2);
            Assert.IsNotNull(trigger.TrigActionList[1].CamAction);
            Assert.IsFalse(trigger.TrigActionList[1].CamAction.Continue);

            trigger.TrigActionList.Add(new FDActionListItem
            {
                TrigAction = FDTrigAction.PlaySoundtrack,
                Parameter  = 40
            });

            //Write the data back
            fdataReader.WriteToLevel(lvl);

            //Check the CamAction has been updated
            Assert.AreEqual(trigger.TrigActionList.Count, 3);
            Assert.IsNotNull(trigger.TrigActionList[1].CamAction);
            Assert.IsTrue(trigger.TrigActionList[1].CamAction.Continue);

            //Check the music trigger has Continue set to false
            Assert.IsFalse(trigger.TrigActionList[2].Continue);
        }
예제 #4
0
        public void FloorData_InsertFDTest()
        {
            //Read Dragons Lair data
            TR2LevelReader reader = new TR2LevelReader();
            TR2Level       lvl    = reader.ReadLevel("xian.tr2");

            //Parse the floordata using FDControl
            FDControl fdataReader = new FDControl();

            fdataReader.ParseFromLevel(lvl);

            //Find a sector that currently has no floor data
            int room, roomSector = -1;

            for (room = 0; room < lvl.NumRooms; room++)
            {
                roomSector = lvl.Rooms[room].SectorList.ToList().FindIndex(s => s.FDIndex == 0);
                if (roomSector != -1)
                {
                    break;
                }
            }

            if (roomSector == -1)
            {
                Assert.Fail("Could not locate a Room Sector that does not have floor data associated with it.");
            }

            TRRoomSector sector = lvl.Rooms[room].SectorList[roomSector];

            // Create a slot in the FD for this sector
            fdataReader.CreateFloorData(sector);
            Assert.AreNotEqual(sector.FDIndex, 0, "Sector does not have FD allocated.");

            // Add a music trigger
            fdataReader.Entries[sector.FDIndex].Add(new FDTriggerEntry
            {
                Setup          = new FDSetup(FDFunctions.Trigger),
                TrigSetup      = new FDTrigSetup(),
                TrigActionList = new List <FDActionListItem>
                {
                    new FDActionListItem
                    {
                        TrigAction = FDTrigAction.PlaySoundtrack,
                        Parameter  = 40
                    }
                }
            });

            //Write the data back
            fdataReader.WriteToLevel(lvl);

            //Save it and read it back in
            TR2LevelWriter writer = new TR2LevelWriter();

            writer.WriteLevelToFile(lvl, "TEST.tr2");
            lvl = reader.ReadLevel("TEST.tr2");

            //Reassign the sector
            sector = lvl.Rooms[room].SectorList[roomSector];

            fdataReader = new FDControl();
            fdataReader.ParseFromLevel(lvl);

            //Ensure the sector still has FD associated with it
            Assert.AreNotEqual(sector.FDIndex, 0, "Sector no longer has FD after write/read.");

            //Verify there is one entry for this sector
            Assert.AreEqual(fdataReader.Entries[sector.FDIndex].Count, 1);

            //Verify the trigger we added matches what we expect
            FDEntry entry = fdataReader.Entries[sector.FDIndex][0];

            Assert.IsTrue(entry is FDTriggerEntry);

            FDTriggerEntry triggerEntry = entry as FDTriggerEntry;

            Assert.IsTrue(triggerEntry.Setup.Function == (byte)FDFunctions.Trigger);
            Assert.IsTrue(triggerEntry.TrigActionList.Count == 1);
            Assert.IsTrue(triggerEntry.TrigActionList[0].TrigAction == FDTrigAction.PlaySoundtrack);
            Assert.IsTrue(triggerEntry.TrigActionList[0].Parameter == 40);
        }
예제 #5
0
        private void RandomizeSecretTracks(TR2Level level, FDControl floorData)
        {
            // Generate new triggers for secrets to allow different sounds for each one
            List <TRAudioTrack>         secretTracks = _tracks[TRAudioCategory.Secret];
            Dictionary <int, TR2Entity> secrets      = GetSecretItems(level);

            foreach (int entityIndex in secrets.Keys)
            {
                TR2Entity    secret = secrets[entityIndex];
                TRRoomSector sector = FDUtilities.GetRoomSector(secret.X, secret.Y, secret.Z, secret.Room, level, floorData);
                if (sector.FDIndex == 0)
                {
                    // The secret is positioned on a tile that currently has no FD, so create it
                    floorData.CreateFloorData(sector);
                }

                List <FDEntry> entries = floorData.Entries[sector.FDIndex];
                FDTriggerEntry existingTriggerEntry = entries.Find(e => e is FDTriggerEntry) as FDTriggerEntry;
                bool           existingEntityPickup = false;
                if (existingTriggerEntry != null)
                {
                    if (existingTriggerEntry.TrigType == FDTrigType.Pickup && existingTriggerEntry.TrigActionList[0].Parameter == entityIndex)
                    {
                        // GW gold secret (default location) already has a pickup trigger to spawn the
                        // TRex (or whatever enemy) so we'll just append to that item list here
                        existingEntityPickup = true;
                    }
                    else
                    {
                        // There is already a non-pickup trigger for this sector so while nothing is wrong with
                        // adding a pickup trigger, the game ignores it. So in this instance, the sound that
                        // plays will just be whatever is set in the script.
                        continue;
                    }
                }

                // Generate a new music action
                FDActionListItem musicAction = new FDActionListItem
                {
                    TrigAction = FDTrigAction.PlaySoundtrack,
                    Parameter  = secretTracks[_generator.Next(0, secretTracks.Count)].ID
                };

                // For GW default gold, just append it
                if (existingEntityPickup)
                {
                    existingTriggerEntry.TrigActionList.Add(musicAction);
                }
                else
                {
                    entries.Add(new FDTriggerEntry
                    {
                        // The values here are replicated from Trigger#112 (in trview) in GW.
                        // The first action list must be the entity being picked up and so
                        // remaining action list items are actioned on pick up.
                        Setup = new FDSetup {
                            Value = 1028
                        },
                        TrigSetup = new FDTrigSetup {
                            Value = 15872
                        },
                        TrigActionList = new List <FDActionListItem>
                        {
                            new FDActionListItem
                            {
                                TrigAction = FDTrigAction.Object,
                                Parameter  = (ushort)entityIndex
                            },
                            musicAction
                        }
                    });
                }
            }
        }
예제 #6
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);
                }
            }
        }