diff --git a/.gitignore b/.gitignore index f9bb5f833..dfcfd56f4 100644 --- a/.gitignore +++ b/.gitignore @@ -348,7 +348,3 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ -*.TR2 -/TRMOD -/Item Locations -/TR2Randomizer/TexturePacks diff --git a/Deps/TRGE.Coord.dll b/Deps/TRGE.Coord.dll index ce88a3fad..27a7c9fb8 100644 Binary files a/Deps/TRGE.Coord.dll and b/Deps/TRGE.Coord.dll differ diff --git a/LocationExport/Program.cs b/LocationExport/Program.cs index cefe8cfb6..45ad4033b 100644 --- a/LocationExport/Program.cs +++ b/LocationExport/Program.cs @@ -1,6 +1,4 @@ using Newtonsoft.Json; -using TRFDControl; -using TRFDControl.Utilities; using TRLevelControl; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -163,8 +161,6 @@ private static TRFileVersion DetectVersion(string path) private static List ExportTR1Locations(string lvl) { TR1Level level = _reader1.Read(lvl); - FDControl floorData = new(); - floorData.ParseFromLevel(level); List exclusions = new(); if (_allTR1Exclusions.ContainsKey(lvl)) { @@ -175,8 +171,7 @@ private static List ExportTR1Locations(string lvl) { if (!TR1TypeUtilities.CanSharePickupSpace(entity.TypeID)) { - exclusions.Add(entity.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level, floorData))); + exclusions.Add(entity.GetFloorLocation(loc => level.GetRoomSector(loc))); } } @@ -187,8 +182,6 @@ private static List ExportTR1Locations(string lvl) private static List ExportTR2Locations(string lvl) { TR2Level level = _reader2.Read(lvl); - FDControl floorData = new(); - floorData.ParseFromLevel(level); List exclusions = new(); if (_allTR2Exclusions.ContainsKey(lvl)) { @@ -199,8 +192,7 @@ private static List ExportTR2Locations(string lvl) { if (!TR2TypeUtilities.CanSharePickupSpace(entity.TypeID)) { - exclusions.Add(entity.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level, floorData))); + exclusions.Add(entity.GetFloorLocation(loc => level.GetRoomSector(loc))); } } @@ -211,8 +203,6 @@ private static List ExportTR2Locations(string lvl) private static List ExportTR3Locations(string lvl) { TR3Level level = _reader3.Read(lvl); - FDControl floorData = new(); - floorData.ParseFromLevel(level); List exclusions = new(); if (_allTR3Exclusions.ContainsKey(lvl)) { @@ -223,8 +213,7 @@ private static List ExportTR3Locations(string lvl) { if (!TR3TypeUtilities.CanSharePickupSpace(entity.TypeID)) { - exclusions.Add(entity.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level, floorData))); + exclusions.Add(entity.GetFloorLocation(loc => level.GetRoomSector(loc))); } } diff --git a/TREnvironmentEditor/Helpers/EMEntityFinder.cs b/TREnvironmentEditor/Helpers/EMEntityFinder.cs index 6c8ca0a76..5176af4b3 100644 --- a/TREnvironmentEditor/Helpers/EMEntityFinder.cs +++ b/TREnvironmentEditor/Helpers/EMEntityFinder.cs @@ -1,6 +1,4 @@ -using TRFDControl; -using TRFDControl.Utilities; -using TRLevelControl.Helpers; +using TRLevelControl.Helpers; using TRLevelControl.Model; namespace TREnvironmentEditor.Helpers; @@ -13,9 +11,6 @@ public class EMEntityFinder public int GetEntity(TR1Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - EMLevelData data = EMLevelData.GetData(level); List types = new(); @@ -32,15 +27,11 @@ public int GetEntity(TR1Level level) types.AddRange(Types.Select(t => (TR1Type)t)); } - return GetEntity(level.Entities, types, data, - l => FDUtilities.GetRoomSector(l.X, l.Y, l.Z, l.Room, level, floorData)); + return GetEntity(level.Entities, types, data, l => level.GetRoomSector(l)); } public int GetEntity(TR2Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - EMLevelData data = EMLevelData.GetData(level); List types = new(); @@ -57,15 +48,11 @@ public int GetEntity(TR2Level level) types.AddRange(Types.Select(t => (TR2Type)t)); } - return GetEntity(level.Entities, types, data, - l => FDUtilities.GetRoomSector(l.X, l.Y, l.Z, l.Room, level, floorData)); + return GetEntity(level.Entities, types, data, l => level.GetRoomSector(l)); } public int GetEntity(TR3Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - EMLevelData data = EMLevelData.GetData(level); List types = new(); @@ -82,8 +69,7 @@ public int GetEntity(TR3Level level) types.AddRange(Types.Select(t => (TR3Type)t)); } - return GetEntity(level.Entities, types, data, - l => FDUtilities.GetRoomSector(l.X, l.Y, l.Z, l.Room, level, floorData)); + return GetEntity(level.Entities, types, data, l => level.GetRoomSector(l)); } public int GetEntity(List entities, List types, EMLevelData data, Func sectorFunc) diff --git a/TREnvironmentEditor/Helpers/EMLevelData.cs b/TREnvironmentEditor/Helpers/EMLevelData.cs index 3b62d8cdb..0befacbba 100644 --- a/TREnvironmentEditor/Helpers/EMLevelData.cs +++ b/TREnvironmentEditor/Helpers/EMLevelData.cs @@ -35,6 +35,18 @@ public short ConvertRoom(int room) return Convert(room, NumRooms); } + public EMLocation ConvertLocation(EMLocation location) + { + return location.Room >= 0 ? location : new() + { + X = location.X, + Y = location.Y, + Z = location.Z, + Room = ConvertRoom(location.Room), + Angle = location.Angle + }; + } + public static short Convert(int itemIndex, long numItems) { return (short)(itemIndex < 0 ? numItems + itemIndex : itemIndex); diff --git a/TREnvironmentEditor/Helpers/EMLocation.cs b/TREnvironmentEditor/Helpers/EMLocation.cs index 78f61dcf6..3934b5d94 100644 --- a/TREnvironmentEditor/Helpers/EMLocation.cs +++ b/TREnvironmentEditor/Helpers/EMLocation.cs @@ -1,6 +1,8 @@ -namespace TREnvironmentEditor.Helpers; +using TRLevelControl.Model; -public class EMLocation +namespace TREnvironmentEditor.Helpers; + +public class EMLocation : ITRLocatable { public int X { get; set; } public int Y { get; set; } diff --git a/TREnvironmentEditor/Helpers/EMLocationUtilities.cs b/TREnvironmentEditor/Helpers/EMLocationUtilities.cs index 924d9371a..bb92827d4 100644 --- a/TREnvironmentEditor/Helpers/EMLocationUtilities.cs +++ b/TREnvironmentEditor/Helpers/EMLocationUtilities.cs @@ -1,42 +1,36 @@ -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; -using TRLevelControl.Helpers; +using TRLevelControl.Helpers; using TRLevelControl.Model; namespace TREnvironmentEditor.Helpers; public static class EMLocationUtilities { - public static int GetContainedSecretEntity(this EMLocation location, TR1Level level, FDControl floorData) + public static int GetContainedSecretEntity(this EMLocation location, TR1Level level) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, location.Room, level, floorData); - return GetSectorSecretEntity(sector, floorData); + TRRoomSector sector = level.GetRoomSector(location); + return GetSectorSecretEntity(sector, level.FloorData); } - public static int GetContainedSecretEntity(this EMLocation location, TR2Level level, FDControl floorData) + public static int GetContainedSecretEntity(this EMLocation location, TR2Level level) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, location.Room, level, floorData); - return level.Entities.FindIndex(e => - TR2TypeUtilities.IsSecretType(e.TypeID) - && FDUtilities.GetRoomSector(e.X, e.Y, e.Z, e.Room, level, floorData) == sector - ); + TRRoomSector sector = level.GetRoomSector(location); + return level.Entities.FindIndex(e => TR2TypeUtilities.IsSecretType(e.TypeID) && level.GetRoomSector(e) == sector); } - public static int GetContainedSecretEntity(this EMLocation location, TR3Level level, FDControl floorData) + public static int GetContainedSecretEntity(this EMLocation location, TR3Level level) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, location.Room, level, floorData); - return GetSectorSecretEntity(sector, floorData); + TRRoomSector sector = level.GetRoomSector(location); + return GetSectorSecretEntity(sector, level.FloorData); } private static int GetSectorSecretEntity(TRRoomSector sector, FDControl floorData) { if (sector.FDIndex != 0) { - if (floorData.Entries[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger + if (floorData[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger && trigger.TrigType == FDTrigType.Pickup - && trigger.TrigActionList.Find(a => a.TrigAction == FDTrigAction.SecretFound) != null - && trigger.TrigActionList.Find(a => a.TrigAction == FDTrigAction.Object) is FDActionItem action) + && trigger.Actions.Find(a => a.Action == FDTrigAction.SecretFound) != null + && trigger.Actions.Find(a => a.Action == FDTrigAction.Object) is FDActionItem action) { return action.Parameter; } diff --git a/TREnvironmentEditor/Helpers/EMRoomDefinition.cs b/TREnvironmentEditor/Helpers/EMRoomDefinition.cs index 10ebef43e..18e29191f 100644 --- a/TREnvironmentEditor/Helpers/EMRoomDefinition.cs +++ b/TREnvironmentEditor/Helpers/EMRoomDefinition.cs @@ -1,4 +1,4 @@ -using TRFDControl; +using TRLevelControl.Model; namespace TREnvironmentEditor.Helpers; diff --git a/TREnvironmentEditor/Helpers/EMTrigger.cs b/TREnvironmentEditor/Helpers/EMTrigger.cs index cc9d43136..02b3a3405 100644 --- a/TREnvironmentEditor/Helpers/EMTrigger.cs +++ b/TREnvironmentEditor/Helpers/EMTrigger.cs @@ -1,8 +1,8 @@ -using TRFDControl; -using TRFDControl.FDEntryTypes; +using TRLevelControl.Model; namespace TREnvironmentEditor.Helpers; +// This is redundant now - to be eliminated public class EMTrigger { private static readonly byte _defaultMask = 31; @@ -23,21 +23,17 @@ public FDTriggerEntry ToFDEntry(EMLevelData levelData) { FDTriggerEntry entry = new() { - Setup = new FDSetup(FDFunction.Trigger), TrigType = TrigType, - SwitchOrKeyRef = (ushort)levelData.ConvertEntity(SwitchOrKeyRef), - TrigSetup = new FDTrigSetup - { - OneShot = OneShot, - Mask = Mask, - Timer = Timer - }, - TrigActionList = new List() + SwitchOrKeyRef = levelData.ConvertEntity(SwitchOrKeyRef), + OneShot = OneShot, + Mask = Mask, + Timer = Timer, + Actions = new() }; foreach (EMTriggerAction action in Actions) { - entry.TrigActionList.Add(action.ToFDAction(levelData)); + entry.Actions.Add(action.ToFDAction(levelData)); } return entry; @@ -48,14 +44,14 @@ public static EMTrigger FromFDEntry(FDTriggerEntry entry) EMTrigger trigger = new() { TrigType = entry.TrigType, - OneShot = entry.TrigSetup.OneShot, - Mask = entry.TrigSetup.Mask, - Timer = entry.TrigSetup.Timer, - SwitchOrKeyRef = (short)entry.SwitchOrKeyRef, - Actions = new List() + OneShot = entry.OneShot, + Mask = entry.Mask, + Timer = entry.Timer, + SwitchOrKeyRef = entry.SwitchOrKeyRef, + Actions = new() }; - foreach (FDActionItem action in entry.TrigActionList) + foreach (FDActionItem action in entry.Actions) { trigger.Actions.Add(EMTriggerAction.FromFDAction(action)); } diff --git a/TREnvironmentEditor/Helpers/EMTriggerAction.cs b/TREnvironmentEditor/Helpers/EMTriggerAction.cs index 7978747df..e98f9be09 100644 --- a/TREnvironmentEditor/Helpers/EMTriggerAction.cs +++ b/TREnvironmentEditor/Helpers/EMTriggerAction.cs @@ -1,4 +1,4 @@ -using TRFDControl; +using TRLevelControl.Model; namespace TREnvironmentEditor.Helpers; @@ -9,34 +9,34 @@ public class EMTriggerAction public FDActionItem ToFDAction(EMLevelData levelData) { - ushort parameter = (ushort)Parameter; + short parameter = Parameter; if (Parameter < 0) { switch (Action) { case FDTrigAction.Camera: - parameter = (ushort)(levelData.NumCameras + Parameter); + parameter = (short)(levelData.NumCameras + Parameter); break; case FDTrigAction.LookAtItem: case FDTrigAction.Object: - parameter = (ushort)(levelData.NumEntities + Parameter); + parameter = (short)(levelData.NumEntities + Parameter); break; } } return new FDActionItem { - TrigAction = Action, + Action = Action, Parameter = parameter }; } public static EMTriggerAction FromFDAction(FDActionItem action) { - return new EMTriggerAction + return new() { - Action = action.TrigAction, - Parameter = (short)action.Parameter + Action = action.Action, + Parameter = action.Parameter }; } } diff --git a/TREnvironmentEditor/Model/Conditions/Entities/EMSecretRoomCondition.cs b/TREnvironmentEditor/Model/Conditions/Entities/EMSecretRoomCondition.cs index 2b3e0acdc..d65379641 100644 --- a/TREnvironmentEditor/Model/Conditions/Entities/EMSecretRoomCondition.cs +++ b/TREnvironmentEditor/Model/Conditions/Entities/EMSecretRoomCondition.cs @@ -1,7 +1,4 @@ -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; -using TRLevelControl.Helpers; +using TRLevelControl.Helpers; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Conditions; @@ -13,9 +10,6 @@ public class EMSecretRoomCondition : BaseEMCondition protected override bool Evaluate(TR1Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (TRRoomSector sector in level.Rooms[RoomIndex].Sectors) { if (sector.FDIndex == 0) @@ -23,7 +17,7 @@ protected override bool Evaluate(TR1Level level) continue; } - if (floorData.Entries[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger && trigger.TrigActionList.Find(a => a.TrigAction == FDTrigAction.SecretFound) != null) + if (level.FloorData[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger && trigger.Actions.Any(a => a.Action == FDTrigAction.SecretFound)) { return true; } @@ -45,27 +39,24 @@ protected override bool Evaluate(TR3Level level) // It's difficult to tell if a particular model is being used for secret pickups, // so instead we check the FD under each entity in the room to see if it triggers // a secret found. - FDControl floorData = new(); - floorData.ParseFromLevel(level); - Predicate pred = new( e => e is FDTriggerEntry trig && trig.TrigType == FDTrigType.Pickup - && trig.TrigActionList.Count > 1 - && trig.TrigActionList[0].TrigAction == FDTrigAction.Object - && trig.TrigActionList[1].TrigAction == FDTrigAction.SecretFound + && trig.Actions.Count > 1 + && trig.Actions[0].Action == FDTrigAction.Object + && trig.Actions[1].Action == FDTrigAction.SecretFound ); foreach (TR3Entity entity in roomEntities) { - TRRoomSector sector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, RoomIndex, level, floorData); + TRRoomSector sector = level.GetRoomSector(entity); if (sector.FDIndex == 0) { continue; } ushort entityIndex = (ushort)level.Entities.IndexOf(entity); - if (floorData.Entries[sector.FDIndex].Find(pred) is FDTriggerEntry trigger && trigger.TrigActionList[0].Parameter == entityIndex) + if (level.FloorData[sector.FDIndex].Find(pred) is FDTriggerEntry trigger && trigger.Actions[0].Parameter == entityIndex) { return true; } diff --git a/TREnvironmentEditor/Model/Conditions/Room/EMSectorContainsSecretCondition.cs b/TREnvironmentEditor/Model/Conditions/Room/EMSectorContainsSecretCondition.cs index ac8cc1338..f944e6423 100644 --- a/TREnvironmentEditor/Model/Conditions/Room/EMSectorContainsSecretCondition.cs +++ b/TREnvironmentEditor/Model/Conditions/Room/EMSectorContainsSecretCondition.cs @@ -1,5 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Conditions; @@ -10,22 +9,16 @@ public class EMSectorContainsSecretCondition : BaseEMCondition protected override bool Evaluate(TR1Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - return Location.GetContainedSecretEntity(level, floorData) != -1; + return Location.GetContainedSecretEntity(level) != -1; } protected override bool Evaluate(TR2Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - return Location.GetContainedSecretEntity(level, floorData) != -1; + return Location.GetContainedSecretEntity(level) != -1; } protected override bool Evaluate(TR3Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - return Location.GetContainedSecretEntity(level, floorData) != -1; + return Location.GetContainedSecretEntity(level) != -1; } } diff --git a/TREnvironmentEditor/Model/Types/Entities/BaseMoveTriggerableFunction.cs b/TREnvironmentEditor/Model/Types/Entities/BaseMoveTriggerableFunction.cs index 2a33410a2..fda77369c 100644 --- a/TREnvironmentEditor/Model/Types/Entities/BaseMoveTriggerableFunction.cs +++ b/TREnvironmentEditor/Model/Types/Entities/BaseMoveTriggerableFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -27,22 +24,14 @@ protected void RepositionTriggerable(TR1Entity entity, TR1Level level) return; } - FDControl control = new(); - control.ParseFromLevel(level); - // Make a new Trigger based on the first one we find (to ensure things like one-shot are copied) // then copy only the action list items for this entity. But if there is already another trigger // on the tile, just manually copy over one-shot when appending the new action item. - List currentTriggers = FDUtilities.GetEntityTriggers(control, EntityIndex); - FDUtilities.RemoveEntityTriggers(level, EntityIndex, control); - - AmendTriggers(currentTriggers, control, delegate (EMLocation location) - { - return FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - }); + List currentTriggers = level.FloorData.GetEntityTriggers(EntityIndex); + level.FloorData.RemoveEntityTriggers(EntityIndex); - control.WriteToLevel(level); + AmendTriggers(currentTriggers, level.FloorData, location => level.GetRoomSector(data.ConvertLocation(location))); } protected void RepositionTriggerable(TR2Entity entity, TR2Level level) @@ -56,26 +45,13 @@ protected void RepositionTriggerable(TR2Entity entity, TR2Level level) if (TriggerLocations == null || TriggerLocations.Count == 0) { - // We want to keep the original triggers return; } - FDControl control = new(); - control.ParseFromLevel(level); - - // Make a new Trigger based on the first one we find (to ensure things like one-shot are copied) - // then copy only the action list items for this entity. But if there is already another trigger - // on the tile, just manually copy over one-shot when appending the new action item. + List currentTriggers = level.FloorData.GetEntityTriggers(EntityIndex); + level.FloorData.RemoveEntityTriggers(EntityIndex); - List currentTriggers = FDUtilities.GetEntityTriggers(control, EntityIndex); - FDUtilities.RemoveEntityTriggers(level, EntityIndex, control); - - AmendTriggers(currentTriggers, control, delegate (EMLocation location) - { - return FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - }); - - control.WriteToLevel(level); + AmendTriggers(currentTriggers, level.FloorData, location => level.GetRoomSector(data.ConvertLocation(location))); } protected void RepositionTriggerable(TR3Entity entity, TR3Level level) @@ -87,23 +63,10 @@ protected void RepositionTriggerable(TR3Entity entity, TR3Level level) entity.Z = Location.Z; entity.Room = data.ConvertRoom(Location.Room); - if (TriggerLocations == null || TriggerLocations.Count == 0) - { - return; - } - - FDControl control = new(); - control.ParseFromLevel(level); - - List currentTriggers = FDUtilities.GetEntityTriggers(control, EntityIndex); - FDUtilities.RemoveEntityTriggers(level, EntityIndex, control); - - AmendTriggers(currentTriggers, control, delegate (EMLocation location) - { - return FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - }); + List currentTriggers = level.FloorData.GetEntityTriggers(EntityIndex); + level.FloorData.RemoveEntityTriggers(EntityIndex); - control.WriteToLevel(level); + AmendTriggers(currentTriggers, level.FloorData, location => level.GetRoomSector(data.ConvertLocation(location))); } private void AmendTriggers(List currentTriggers, FDControl control, Func sectorGetter) @@ -118,33 +81,35 @@ private void AmendTriggers(List currentTriggers, FDControl contr } FDActionItem currentObjectAction = null; - FDTriggerEntry currentTrigger = control.Entries[sector.FDIndex].Find(e => e is FDTriggerEntry) as FDTriggerEntry; + FDTriggerEntry currentTrigger = control[sector.FDIndex].Find(e => e is FDTriggerEntry) as FDTriggerEntry; if (currentTrigger != null) { - currentObjectAction = currentTrigger.TrigActionList.Find(a => a.TrigAction == FDTrigAction.Object); + currentObjectAction = currentTrigger.Actions.Find(a => a.Action == FDTrigAction.Object); } FDActionItem newAction = new() { - TrigAction = FDTrigAction.Object, - Parameter = (ushort)EntityIndex + Parameter = (short)EntityIndex }; if (currentObjectAction != null) { - currentTrigger.TrigActionList.Add(newAction); - if (currentTriggers[0].TrigSetup.OneShot) + currentTrigger.Actions.Add(newAction); + if (currentTriggers[0].OneShot) { - currentTrigger.TrigSetup.OneShot = true; + currentTrigger.OneShot = true; } } else { - control.Entries[sector.FDIndex].Add(new FDTriggerEntry + control[sector.FDIndex].Add(new FDTriggerEntry { - Setup = currentTriggers[0].Setup, - TrigSetup = currentTriggers[0].TrigSetup, - TrigActionList = new List { newAction } + Mask = currentTriggers[0].Mask, + OneShot = currentTriggers[0].OneShot, + SwitchOrKeyRef = currentTriggers[0].SwitchOrKeyRef, + Timer = currentTriggers[0].Timer, + TrigType = currentTriggers[0].TrigType, + Actions = new() { newAction } }); } } diff --git a/TREnvironmentEditor/Model/Types/Entities/EMAddEntityFunction.cs b/TREnvironmentEditor/Model/Types/Entities/EMAddEntityFunction.cs index d58b82a3e..cbc0ec15e 100644 --- a/TREnvironmentEditor/Model/Types/Entities/EMAddEntityFunction.cs +++ b/TREnvironmentEditor/Model/Types/Entities/EMAddEntityFunction.cs @@ -1,6 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -24,13 +22,11 @@ public override void ApplyToLevel(TR1Level level) EMLevelData data = GetData(level); if (TargetRelocation != null) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - short room = data.ConvertRoom(Location.Room); - TRRoomSector sector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, room, level, floorData); + EMLocation location = data.ConvertLocation(Location); + TRRoomSector sector = level.GetRoomSector(location); foreach (TR1Entity entity in level.Entities) { - if (entity.Room == room && FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, floorData) == sector) + if (entity.Room == location.Room && level.GetRoomSector(entity) == sector) { entity.X = TargetRelocation.X; entity.Y = TargetRelocation.Y; @@ -51,13 +47,11 @@ public override void ApplyToLevel(TR2Level level) EMLevelData data = GetData(level); if (TargetRelocation != null) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - short room = data.ConvertRoom(Location.Room); - TRRoomSector sector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, room, level, floorData); + EMLocation location = data.ConvertLocation(Location); + TRRoomSector sector = level.GetRoomSector(location); foreach (TR2Entity entity in level.Entities) { - if (entity.Room == room && FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, floorData) == sector) + if (entity.Room == location.Room && level.GetRoomSector(entity) == sector) { entity.X = TargetRelocation.X; entity.Y = TargetRelocation.Y; @@ -79,13 +73,11 @@ public override void ApplyToLevel(TR3Level level) EMLevelData data = GetData(level); if (TargetRelocation != null) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - short room = data.ConvertRoom(Location.Room); - TRRoomSector sector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, room, level, floorData); + EMLocation location = data.ConvertLocation(Location); + TRRoomSector sector = level.GetRoomSector(location); foreach (TR3Entity entity in level.Entities) { - if (entity.Room == room && FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, floorData) == sector) + if (entity.Room == location.Room && level.GetRoomSector(entity) == sector) { entity.X = TargetRelocation.X; entity.Y = TargetRelocation.Y; diff --git a/TREnvironmentEditor/Model/Types/Entities/EMConvertWheelDoorFunction.cs b/TREnvironmentEditor/Model/Types/Entities/EMConvertWheelDoorFunction.cs index 41b4e3663..0387382a3 100644 --- a/TREnvironmentEditor/Model/Types/Entities/EMConvertWheelDoorFunction.cs +++ b/TREnvironmentEditor/Model/Types/Entities/EMConvertWheelDoorFunction.cs @@ -50,7 +50,7 @@ public override void ApplyToLevel(TR2Level level) // This indicates that we want to get rid of the wheel and make its current trigger a pad new EMConvertTriggerFunction { - TrigType = TRFDControl.FDTrigType.Pad, + TrigType = FDTrigType.Pad, Location = new EMLocation { X = wheel.X, diff --git a/TREnvironmentEditor/Model/Types/Entities/EMMovePickupFunction.cs b/TREnvironmentEditor/Model/Types/Entities/EMMovePickupFunction.cs index 28f2e0c92..bf8d604c5 100644 --- a/TREnvironmentEditor/Model/Types/Entities/EMMovePickupFunction.cs +++ b/TREnvironmentEditor/Model/Types/Entities/EMMovePickupFunction.cs @@ -1,6 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -15,40 +13,22 @@ public class EMMovePickupFunction : BaseEMFunction public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - - FDControl control = new(); - control.ParseFromLevel(level); - MovePickups(level.Entities, data, location => - { - return FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - }); + level.GetRoomSector(data.ConvertLocation(location))); } public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - - FDControl control = new(); - control.ParseFromLevel(level); - MovePickups(level.Entities, data, location => - { - return FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - }); + level.GetRoomSector(data.ConvertLocation(location))); } public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - - FDControl control = new(); - control.ParseFromLevel(level); - MovePickups(level.Entities, data, location => - { - return FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - }); + level.GetRoomSector(data.ConvertLocation(location))); } private void MovePickups(IEnumerable> entities, EMLevelData data, Func sectorGetter) diff --git a/TREnvironmentEditor/Model/Types/Entities/EMMoveSecretFunction.cs b/TREnvironmentEditor/Model/Types/Entities/EMMoveSecretFunction.cs index fa6986c30..6866b9a7f 100644 --- a/TREnvironmentEditor/Model/Types/Entities/EMMoveSecretFunction.cs +++ b/TREnvironmentEditor/Model/Types/Entities/EMMoveSecretFunction.cs @@ -1,5 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -9,11 +8,9 @@ public class EMMoveSecretFunction : EMMovePickupFunction public override void ApplyToLevel(TR1Level level) { Types = new List(); - FDControl floorData = new(); - floorData.ParseFromLevel(level); foreach (EMLocation location in SectorLocations) { - int entityIndex = location.GetContainedSecretEntity(level, floorData); + int entityIndex = location.GetContainedSecretEntity(level); if (entityIndex != -1) { Types.Add((short)level.Entities[entityIndex].TypeID); @@ -26,11 +23,9 @@ public override void ApplyToLevel(TR1Level level) public override void ApplyToLevel(TR2Level level) { Types = new List(); - FDControl floorData = new(); - floorData.ParseFromLevel(level); foreach (EMLocation location in SectorLocations) { - int entityIndex = location.GetContainedSecretEntity(level, floorData); + int entityIndex = location.GetContainedSecretEntity(level); if (entityIndex != -1) { Types.Add((short)level.Entities[entityIndex].TypeID); @@ -43,11 +38,9 @@ public override void ApplyToLevel(TR2Level level) public override void ApplyToLevel(TR3Level level) { Types = new List(); - FDControl floorData = new(); - floorData.ParseFromLevel(level); foreach (EMLocation location in SectorLocations) { - int entityIndex = location.GetContainedSecretEntity(level, floorData); + int entityIndex = location.GetContainedSecretEntity(level); if (entityIndex != -1) { Types.Add((short)level.Entities[entityIndex].TypeID); diff --git a/TREnvironmentEditor/Model/Types/Entities/EMMoveSlotFunction.cs b/TREnvironmentEditor/Model/Types/Entities/EMMoveSlotFunction.cs index 2a262544a..df4231f12 100644 --- a/TREnvironmentEditor/Model/Types/Entities/EMMoveSlotFunction.cs +++ b/TREnvironmentEditor/Model/Types/Entities/EMMoveSlotFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -17,28 +14,22 @@ public override void ApplyToLevel(TR1Level level) EMLevelData data = GetData(level); EntityIndex = data.ConvertEntity(EntityIndex); - FDControl control = new(); - control.ParseFromLevel(level); - TR1Entity slot = level.Entities[EntityIndex]; - TRRoomSector currentSector = FDUtilities.GetRoomSector(slot.X, slot.Y, slot.Z, slot.Room, level, control); - short roomNumber = data.ConvertRoom(Location.Room); - TRRoomSector newSector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, roomNumber, level, control); + TRRoomSector currentSector = level.GetRoomSector(slot); + EMLocation location = data.ConvertLocation(Location); + TRRoomSector newSector = level.GetRoomSector(location); // Check if there is also a trigger in the flip map if we are moving the slot within the same room TRRoomSector currentFlipSector = null; TRRoomSector newFlipSector = null; short altRoom = level.Rooms[slot.Room].AlternateRoom; - if (slot.Room == roomNumber && altRoom != -1) + if (slot.Room == location.Room && altRoom != -1) { - currentFlipSector = FDUtilities.GetRoomSector(slot.X, slot.Y, slot.Z, altRoom, level, control); - newFlipSector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, altRoom, level, control); + currentFlipSector = level.GetRoomSector(slot.X, slot.Y, slot.Z, altRoom); + newFlipSector = level.GetRoomSector(Location.X, Location.Y, Location.Z, altRoom); } - if (MoveSlot(control, slot, roomNumber, currentSector, newSector, currentFlipSector, newFlipSector)) - { - control.WriteToLevel(level); - } + MoveSlot(level.FloorData, slot, location, currentSector, newSector, currentFlipSector, newFlipSector); } public override void ApplyToLevel(TR2Level level) @@ -46,40 +37,32 @@ public override void ApplyToLevel(TR2Level level) EMLevelData data = GetData(level); EntityIndex = data.ConvertEntity(EntityIndex); - FDControl control = new(); - control.ParseFromLevel(level); - TR2Entity slot = level.Entities[EntityIndex]; - TRRoomSector currentSector = FDUtilities.GetRoomSector(slot.X, slot.Y, slot.Z, slot.Room, level, control); - short roomNumber = data.ConvertRoom(Location.Room); - TRRoomSector newSector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, roomNumber, level, control); + TRRoomSector currentSector = level.GetRoomSector(slot); + EMLocation location = data.ConvertLocation(Location); + TRRoomSector newSector = level.GetRoomSector(location); - // Check if there is also a trigger in the flip map if we are moving the slot within the same room TRRoomSector currentFlipSector = null; TRRoomSector newFlipSector = null; short altRoom = level.Rooms[slot.Room].AlternateRoom; - if (slot.Room == roomNumber && altRoom != -1) + if (slot.Room == location.Room && altRoom != -1) { - currentFlipSector = FDUtilities.GetRoomSector(slot.X, slot.Y, slot.Z, altRoom, level, control); - newFlipSector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, altRoom, level, control); + currentFlipSector = level.GetRoomSector(slot.X, slot.Y, slot.Z, altRoom); + newFlipSector = level.GetRoomSector(Location.X, Location.Y, Location.Z, altRoom); } // Make sure there isn't a static enemy on the same sector e.g. MorayEel - List staticEnemies = level.Entities.FindAll(e => e.Room == roomNumber && TR2TypeUtilities.IsStaticCreature(e.TypeID)); + List staticEnemies = level.Entities.FindAll(e => e.Room == location.Room && TR2TypeUtilities.IsStaticCreature(e.TypeID)); foreach (TR2Entity staticEnemy in staticEnemies) { - TRRoomSector enemySector = FDUtilities.GetRoomSector(staticEnemy.X, staticEnemy.Y, staticEnemy.Z, staticEnemy.Room, level, control); + TRRoomSector enemySector = level.GetRoomSector(staticEnemy); if (enemySector == newSector) { - // Bail out return; } } - if (MoveSlot(control, slot, roomNumber, currentSector, newSector, currentFlipSector, newFlipSector)) - { - control.WriteToLevel(level); - } + MoveSlot(level.FloorData, slot, location, currentSector, newSector, currentFlipSector, newFlipSector); } public override void ApplyToLevel(TR3Level level) @@ -87,39 +70,32 @@ public override void ApplyToLevel(TR3Level level) EMLevelData data = GetData(level); EntityIndex = data.ConvertEntity(EntityIndex); - FDControl control = new(); - control.ParseFromLevel(level); - TR3Entity slot = level.Entities[EntityIndex]; - TRRoomSector currentSector = FDUtilities.GetRoomSector(slot.X, slot.Y, slot.Z, slot.Room, level, control); - short roomNumber = data.ConvertRoom(Location.Room); - TRRoomSector newSector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, roomNumber, level, control); + TRRoomSector currentSector = level.GetRoomSector(slot); + EMLocation location = data.ConvertLocation(Location); + TRRoomSector newSector = level.GetRoomSector(location); - // Check if there is also a trigger in the flip map if we are moving the slot within the same room TRRoomSector currentFlipSector = null; TRRoomSector newFlipSector = null; short altRoom = level.Rooms[slot.Room].AlternateRoom; - if (slot.Room == roomNumber && altRoom != -1) + if (slot.Room == location.Room && altRoom != -1) { - currentFlipSector = FDUtilities.GetRoomSector(slot.X, slot.Y, slot.Z, altRoom, level, control); - newFlipSector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, altRoom, level, control); + currentFlipSector = level.GetRoomSector(slot.X, slot.Y, slot.Z, altRoom); + newFlipSector = level.GetRoomSector(Location.X, Location.Y, Location.Z, altRoom); } - if (MoveSlot(control, slot, roomNumber, currentSector, newSector, currentFlipSector, newFlipSector)) - { - control.WriteToLevel(level); - } + MoveSlot(level.FloorData, slot, location, currentSector, newSector, currentFlipSector, newFlipSector); } - protected bool MoveSlot(FDControl control, TREntity slot, short roomNumber, + protected void MoveSlot(FDControl control, TREntity slot, EMLocation location, TRRoomSector currentSector, TRRoomSector newSector, TRRoomSector currentFlipSector, TRRoomSector newFlipSector) where T : Enum { - slot.X = Location.X; - slot.Y = Location.Y; - slot.Z = Location.Z; - slot.Room = roomNumber; - slot.Angle = Location.Angle; + slot.X = location.X; + slot.Y = location.Y; + slot.Z = location.Z; + slot.Room = location.Room; + slot.Angle = location.Angle; if (newSector != currentSector && currentSector.FDIndex != 0) { @@ -129,11 +105,7 @@ protected bool MoveSlot(FDControl control, TREntity slot, short roomNumber { MoveTriggers(control, currentFlipSector, newFlipSector); } - - return true; } - - return false; } protected void MoveTriggers(FDControl control, TRRoomSector currentSector, TRRoomSector newSector) @@ -146,14 +118,9 @@ protected void MoveTriggers(FDControl control, TRRoomSector currentSector, TRRoo bool keyTrigPredicate(FDEntry e) => e is FDTriggerEntry trig && trig.SwitchOrKeyRef == EntityIndex; // Copy the key trigger to the new sector - List keyTriggers = control.Entries[currentSector.FDIndex].FindAll(keyTrigPredicate); - control.Entries[newSector.FDIndex].AddRange(keyTriggers); + List keyTriggers = control[currentSector.FDIndex].FindAll(keyTrigPredicate); + control[newSector.FDIndex].AddRange(keyTriggers); // Remove from the old - control.Entries[currentSector.FDIndex].RemoveAll(keyTrigPredicate); - if (control.Entries[currentSector.FDIndex].Count == 0) - { - // If there isn't anything left, reset the sector to point to the dummy FD - control.RemoveFloorData(currentSector); - } + control[currentSector.FDIndex].RemoveAll(keyTrigPredicate); } } diff --git a/TREnvironmentEditor/Model/Types/Entities/EMSwapGroupedSlotsFunction.cs b/TREnvironmentEditor/Model/Types/Entities/EMSwapGroupedSlotsFunction.cs index 9fedd997d..ec17b65cd 100644 --- a/TREnvironmentEditor/Model/Types/Entities/EMSwapGroupedSlotsFunction.cs +++ b/TREnvironmentEditor/Model/Types/Entities/EMSwapGroupedSlotsFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -15,19 +12,16 @@ public override void ApplyToLevel(TR1Level level) EMLevelData data = GetData(level); InitialiseEntityMap(data); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - Dictionary slotInfo = new(); foreach (short entityIndex in EntityMap.Keys) { TR1Entity entity = level.Entities[entityIndex]; - TRRoomSector sector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, floorData); - slotInfo[entityIndex] = new SlotInfo + TRRoomSector sector = level.GetRoomSector(entity); + slotInfo[entityIndex] = new() { Location = GetLocation(entity), FDIndex = sector.FDIndex, - Triggers = floorData.Entries[sector.FDIndex].FindAll(e => e is FDTriggerEntry) + Triggers = level.FloorData[sector.FDIndex].FindAll(e => e is FDTriggerEntry) }; } @@ -36,11 +30,9 @@ public override void ApplyToLevel(TR1Level level) SlotInfo slotInfo1 = slotInfo[entityIndex]; SlotInfo slotInfo2 = slotInfo[EntityMap[entityIndex]]; - SwapTriggers(slotInfo1, slotInfo2, floorData); + SwapTriggers(slotInfo1, slotInfo2, level.FloorData); MoveSlot(level.Entities[entityIndex], slotInfo2.Location); } - - floorData.WriteToLevel(level); } public override void ApplyToLevel(TR2Level level) @@ -48,19 +40,16 @@ public override void ApplyToLevel(TR2Level level) EMLevelData data = GetData(level); InitialiseEntityMap(data); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - Dictionary slotInfo = new(); foreach (short entityIndex in EntityMap.Keys) { TR2Entity entity = level.Entities[entityIndex]; - TRRoomSector sector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, floorData); - slotInfo[entityIndex] = new SlotInfo + TRRoomSector sector = level.GetRoomSector(entity); + slotInfo[entityIndex] = new() { Location = GetLocation(entity), FDIndex = sector.FDIndex, - Triggers = floorData.Entries[sector.FDIndex].FindAll(e => e is FDTriggerEntry) + Triggers = level.FloorData[sector.FDIndex].FindAll(e => e is FDTriggerEntry) }; } @@ -69,11 +58,9 @@ public override void ApplyToLevel(TR2Level level) SlotInfo slotInfo1 = slotInfo[entityIndex]; SlotInfo slotInfo2 = slotInfo[EntityMap[entityIndex]]; - SwapTriggers(slotInfo1, slotInfo2, floorData); + SwapTriggers(slotInfo1, slotInfo2, level.FloorData); MoveSlot(level.Entities[entityIndex], slotInfo2.Location); } - - floorData.WriteToLevel(level); } public override void ApplyToLevel(TR3Level level) @@ -81,19 +68,16 @@ public override void ApplyToLevel(TR3Level level) EMLevelData data = GetData(level); InitialiseEntityMap(data); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - Dictionary slotInfo = new(); foreach (short entityIndex in EntityMap.Keys) { TR3Entity entity = level.Entities[entityIndex]; - TRRoomSector sector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, floorData); - slotInfo[entityIndex] = new SlotInfo + TRRoomSector sector = level.GetRoomSector(entity); + slotInfo[entityIndex] = new() { Location = GetLocation(entity), FDIndex = sector.FDIndex, - Triggers = floorData.Entries[sector.FDIndex].FindAll(e => e is FDTriggerEntry) + Triggers = level.FloorData[sector.FDIndex].FindAll(e => e is FDTriggerEntry) }; } @@ -102,11 +86,9 @@ public override void ApplyToLevel(TR3Level level) SlotInfo slotInfo1 = slotInfo[entityIndex]; SlotInfo slotInfo2 = slotInfo[EntityMap[entityIndex]]; - SwapTriggers(slotInfo1, slotInfo2, floorData); + SwapTriggers(slotInfo1, slotInfo2, level.FloorData); MoveSlot(level.Entities[entityIndex], slotInfo2.Location); } - - floorData.WriteToLevel(level); } private void InitialiseEntityMap(EMLevelData data) @@ -131,8 +113,8 @@ private void InitialiseEntityMap(EMLevelData data) private static void SwapTriggers(SlotInfo slotInfo1, SlotInfo slotInfo2, FDControl floorData) { - floorData.Entries[slotInfo1.FDIndex].RemoveAll(slotInfo1.Triggers.Contains); - floorData.Entries[slotInfo2.FDIndex].AddRange(slotInfo1.Triggers); + floorData[slotInfo1.FDIndex].RemoveAll(slotInfo1.Triggers.Contains); + floorData[slotInfo2.FDIndex].AddRange(slotInfo1.Triggers); } private static void MoveSlot(TREntity entity, EMLocation location) diff --git a/TREnvironmentEditor/Model/Types/Entities/EMSwapSlotFunction.cs b/TREnvironmentEditor/Model/Types/Entities/EMSwapSlotFunction.cs index 556c3d04c..e7dd5a4a0 100644 --- a/TREnvironmentEditor/Model/Types/Entities/EMSwapSlotFunction.cs +++ b/TREnvironmentEditor/Model/Types/Entities/EMSwapSlotFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -23,30 +20,27 @@ public override void ApplyToLevel(TR1Level level) // We can only swap if the slots are corresponding done/not done types. // So for now, just check that one doesn't have any triggers - FDControl control = new(); - control.ParseFromLevel(level); - TRRoomSector slot1Sector = FDUtilities.GetRoomSector(slot1.X, slot1.Y, slot1.Z, slot1.Room, level, control); - TRRoomSector slot2Sector = FDUtilities.GetRoomSector(slot2.X, slot2.Y, slot2.Z, slot2.Room, level, control); + TRRoomSector slot1Sector = level.GetRoomSector(slot1); + TRRoomSector slot2Sector = level.GetRoomSector(slot2); - bool slot1HasTriggers = SectorHasTriggers(slot1Sector, control); - bool slot2HasTriggers = SectorHasTriggers(slot2Sector, control); + bool slot1HasTriggers = SectorHasTriggers(slot1Sector, level.FloorData); + bool slot2HasTriggers = SectorHasTriggers(slot2Sector, level.FloorData); if (slot1HasTriggers ^ slot2HasTriggers) { if (slot1HasTriggers) { EntityIndex = Slot1Index; - MoveTriggers(control, slot1Sector, slot2Sector); + MoveTriggers(level.FloorData, slot1Sector, slot2Sector); } else { EntityIndex = Slot2Index; - MoveTriggers(control, slot2Sector, slot1Sector); + MoveTriggers(level.FloorData, slot2Sector, slot1Sector); } SwapSlots(slot1, slot2, GetData(level)); - control.WriteToLevel(level); } } @@ -60,32 +54,26 @@ public override void ApplyToLevel(TR2Level level) TR2Entity slot1 = level.Entities[Slot1Index]; TR2Entity slot2 = level.Entities[Slot2Index]; - // We can only swap if the slots are corresponding done/not done types. - // So for now, just check that one doesn't have any triggers - FDControl control = new(); - control.ParseFromLevel(level); - - TRRoomSector slot1Sector = FDUtilities.GetRoomSector(slot1.X, slot1.Y, slot1.Z, slot1.Room, level, control); - TRRoomSector slot2Sector = FDUtilities.GetRoomSector(slot2.X, slot2.Y, slot2.Z, slot2.Room, level, control); + TRRoomSector slot1Sector = level.GetRoomSector(slot1); + TRRoomSector slot2Sector = level.GetRoomSector(slot2); - bool slot1HasTriggers = SectorHasTriggers(slot1Sector, control); - bool slot2HasTriggers = SectorHasTriggers(slot2Sector, control); + bool slot1HasTriggers = SectorHasTriggers(slot1Sector, level.FloorData); + bool slot2HasTriggers = SectorHasTriggers(slot2Sector, level.FloorData); if (slot1HasTriggers ^ slot2HasTriggers) { if (slot1HasTriggers) { EntityIndex = Slot1Index; - MoveTriggers(control, slot1Sector, slot2Sector); + MoveTriggers(level.FloorData, slot1Sector, slot2Sector); } else { EntityIndex = Slot2Index; - MoveTriggers(control, slot2Sector, slot1Sector); + MoveTriggers(level.FloorData, slot2Sector, slot1Sector); } SwapSlots(slot1, slot2, GetData(level)); - control.WriteToLevel(level); } } @@ -99,39 +87,33 @@ public override void ApplyToLevel(TR3Level level) TR3Entity slot1 = level.Entities[Slot1Index]; TR3Entity slot2 = level.Entities[Slot2Index]; - // We can only swap if the slots are corresponding done/not done types. - // So for now, just check that one doesn't have any triggers - FDControl control = new(); - control.ParseFromLevel(level); - - TRRoomSector slot1Sector = FDUtilities.GetRoomSector(slot1.X, slot1.Y, slot1.Z, slot1.Room, level, control); - TRRoomSector slot2Sector = FDUtilities.GetRoomSector(slot2.X, slot2.Y, slot2.Z, slot2.Room, level, control); + TRRoomSector slot1Sector = level.GetRoomSector(slot1); + TRRoomSector slot2Sector = level.GetRoomSector(slot2); - bool slot1HasTriggers = SectorHasTriggers(slot1Sector, control); - bool slot2HasTriggers = SectorHasTriggers(slot2Sector, control); + bool slot1HasTriggers = SectorHasTriggers(slot1Sector, level.FloorData); + bool slot2HasTriggers = SectorHasTriggers(slot2Sector, level.FloorData); if (slot1HasTriggers ^ slot2HasTriggers) { if (slot1HasTriggers) { EntityIndex = Slot1Index; - MoveTriggers(control, slot1Sector, slot2Sector); + MoveTriggers(level.FloorData, slot1Sector, slot2Sector); } else { EntityIndex = Slot2Index; - MoveTriggers(control, slot2Sector, slot1Sector); + MoveTriggers(level.FloorData, slot2Sector, slot1Sector); } SwapSlots(slot1, slot2, GetData(level)); - control.WriteToLevel(level); } } private static bool SectorHasTriggers(TRRoomSector sector, FDControl control) { return sector.FDIndex != 0 - && control.Entries[sector.FDIndex].Any(e => e is FDTriggerEntry); + && control[sector.FDIndex].Any(e => e is FDTriggerEntry); } private static void SwapSlots(TREntity slot1, TREntity slot2, EMLevelData data) diff --git a/TREnvironmentEditor/Model/Types/Mirroring/EMMirrorFunction.cs b/TREnvironmentEditor/Model/Types/Mirroring/EMMirrorFunction.cs index 6564f333f..1519dfd8c 100644 --- a/TREnvironmentEditor/Model/Types/Mirroring/EMMirrorFunction.cs +++ b/TREnvironmentEditor/Model/Types/Mirroring/EMMirrorFunction.cs @@ -1,6 +1,4 @@ using System.Diagnostics; -using TRFDControl; -using TRFDControl.FDEntryTypes; using TRLevelControl; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -118,41 +116,26 @@ private static void Swap(T[] arr, int pos1, int pos2) private static void MirrorFloorData(TR1Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (TR1Room room in level.Rooms) { - MirrorSectors(room.Sectors, room.NumXSectors, room.NumZSectors, floorData); + MirrorSectors(room.Sectors, room.NumXSectors, room.NumZSectors, level.FloorData); } - - floorData.WriteToLevel(level); } private static void MirrorFloorData(TR2Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (TR2Room room in level.Rooms) { - MirrorSectors(room.Sectors, room.NumXSectors, room.NumZSectors, floorData); + MirrorSectors(room.Sectors, room.NumXSectors, room.NumZSectors, level.FloorData); } - - floorData.WriteToLevel(level); } private static void MirrorFloorData(TR3Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (TR3Room room in level.Rooms) { - MirrorSectors(room.Sectors, room.NumXSectors, room.NumZSectors, floorData); + MirrorSectors(room.Sectors, room.NumXSectors, room.NumZSectors, level.FloorData); } - - floorData.WriteToLevel(level); } private static void MirrorSectors(List sectors, ushort numXSectors, ushort numZSectors, FDControl floorData) @@ -181,7 +164,7 @@ private static void MirrorSectors(List sectors, ushort numXSectors { if (sector.FDIndex != 0) { - List entries = floorData.Entries[sector.FDIndex]; + List entries = floorData[sector.FDIndex]; for (int i = 0; i < entries.Count; i++) { FDEntry entry = entries[i]; @@ -202,86 +185,86 @@ private static void MirrorSectors(List sectors, ushort numXSectors else if (entry is FDTriangulationEntry triangulation) { // Flip the corners - byte c00 = triangulation.TriData.C00; - byte c10 = triangulation.TriData.C10; - byte c01 = triangulation.TriData.C01; - byte c11 = triangulation.TriData.C11; - triangulation.TriData.C00 = c10; - triangulation.TriData.C10 = c00; - triangulation.TriData.C01 = c11; - triangulation.TriData.C11 = c01; + byte c00 = triangulation.C00; + byte c10 = triangulation.C10; + byte c01 = triangulation.C01; + byte c11 = triangulation.C11; + triangulation.C00 = c10; + triangulation.C10 = c00; + triangulation.C01 = c11; + triangulation.C11 = c01; // And the heights - sbyte h1 = triangulation.Setup.H1; - sbyte h2 = triangulation.Setup.H2; - triangulation.Setup.H1 = h2; - triangulation.Setup.H2 = h1; + sbyte h1 = triangulation.H1; + sbyte h2 = triangulation.H2; + triangulation.H1 = h2; + triangulation.H2 = h1; // And the triangulation - switch ((FDFunction)triangulation.Setup.Function) + switch (triangulation.Type) { // Non-portals - case FDFunction.FloorTriangulationNWSE_Solid: - triangulation.Setup.Function = (byte)FDFunction.FloorTriangulationNESW_Solid; + case FDTriangulationType.FloorNWSE_Solid: + triangulation.Type = FDTriangulationType.FloorNESW_Solid; break; - case FDFunction.FloorTriangulationNESW_Solid: - triangulation.Setup.Function = (byte)FDFunction.FloorTriangulationNWSE_Solid; + case FDTriangulationType.FloorNESW_Solid: + triangulation.Type = FDTriangulationType.FloorNWSE_Solid; break; - case FDFunction.CeilingTriangulationNW_Solid: - triangulation.Setup.Function = (byte)FDFunction.CeilingTriangulationNE_Solid; + case FDTriangulationType.CeilingNWSE_Solid: + triangulation.Type = FDTriangulationType.CeilingNESW_Solid; break; - case FDFunction.CeilingTriangulationNE_Solid: - triangulation.Setup.Function = (byte)FDFunction.CeilingTriangulationNW_Solid; + case FDTriangulationType.CeilingNESW_Solid: + triangulation.Type = FDTriangulationType.CeilingNWSE_Solid; break; // Portals: _SW, _NE etc indicate triangles whose right-angles point towards the portal - case FDFunction.FloorTriangulationNWSE_SW: - triangulation.Setup.Function = (byte)FDFunction.FloorTriangulationNESW_NW; + case FDTriangulationType.FloorNWSE_SW: + triangulation.Type = FDTriangulationType.FloorNESW_NW; break; - case FDFunction.FloorTriangulationNWSE_NE: - triangulation.Setup.Function = (byte)FDFunction.FloorTriangulationNESW_SE; + case FDTriangulationType.FloorNWSE_NE: + triangulation.Type = FDTriangulationType.FloorNESW_SE; break; - case FDFunction.FloorTriangulationNESW_SE: - triangulation.Setup.Function = (byte)FDFunction.FloorTriangulationNWSE_NE; + case FDTriangulationType.FloorNESW_SE: + triangulation.Type = FDTriangulationType.FloorNWSE_NE; break; - case FDFunction.FloorTriangulationNESW_NW: - triangulation.Setup.Function = (byte)FDFunction.FloorTriangulationNWSE_SW; + case FDTriangulationType.FloorNESW_NW: + triangulation.Type = FDTriangulationType.FloorNWSE_SW; break; - case FDFunction.CeilingTriangulationNW_SW: - triangulation.Setup.Function = (byte)FDFunction.CeilingTriangulationNE_SE; + case FDTriangulationType.CeilingNWSE_SW: + triangulation.Type = FDTriangulationType.CeilingNESW_SE; break; - case FDFunction.CeilingTriangulationNW_NE: - triangulation.Setup.Function = (byte)FDFunction.CeilingTriangulationNE_NW; + case FDTriangulationType.CeilingNWSE_NE: + triangulation.Type = FDTriangulationType.CeilingNESW_NW; break; - case FDFunction.CeilingTriangulationNE_NW: - triangulation.Setup.Function = (byte)FDFunction.CeilingTriangulationNW_NE; + case FDTriangulationType.CeilingNESW_NW: + triangulation.Type = FDTriangulationType.CeilingNWSE_NE; break; - case FDFunction.CeilingTriangulationNE_SE: - triangulation.Setup.Function = (byte)FDFunction.CeilingTriangulationNW_SW; + case FDTriangulationType.CeilingNESW_SE: + triangulation.Type = FDTriangulationType.CeilingNWSE_SW; break; } } - else if (entry is FDMinecartEntry) + else if (entry is FDMinecartEntry minecart) { // If left is followed by right, it means stop the minecart and they appear to // need to remain in this order. Only switch the entry if there is no other. - if (!(i < entries.Count - 1 && entries[i + 1] is TR3MinecartRotateRightEntry)) + if (minecart.Type == FDMinecartType.Left) { - entries[i] = new TR3MinecartRotateRightEntry + if (!(i < entries.Count - 1 && entries[i + 1] is FDMinecartEntry mincartRight && mincartRight.Type == FDMinecartType.Right)) { - Setup = new FDSetup(FDFunction.MechBeetleOrMinecartRotateRight) - }; + entries[i] = new FDMinecartEntry + { + Type = FDMinecartType.Right + }; + } } - } - else if (entry is TR3MinecartRotateRightEntry) - { - if (!(i > 0 && entries[i - 1] is FDMinecartEntry)) + else if (!(i > 0 && entries[i - 1] is FDMinecartEntry minecartLeft && minecartLeft.Type == FDMinecartType.Left)) { entries[i] = new FDMinecartEntry { - Setup = new FDSetup(FDFunction.DeferredTriggeringOrMinecartRotateLeft) + Type= FDMinecartType.Left }; } } diff --git a/TREnvironmentEditor/Model/Types/Portals/EMHorizontalCollisionalPortalFunction.cs b/TREnvironmentEditor/Model/Types/Portals/EMHorizontalCollisionalPortalFunction.cs index 83bb94e64..a586b0f93 100644 --- a/TREnvironmentEditor/Model/Types/Portals/EMHorizontalCollisionalPortalFunction.cs +++ b/TREnvironmentEditor/Model/Types/Portals/EMHorizontalCollisionalPortalFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -13,11 +10,7 @@ public class EMHorizontalCollisionalPortalFunction : BaseEMFunction public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - - FDControl control = new(); - control.ParseFromLevel(level); - - Dictionary> sectorMap = new(); + Dictionary> sectorMap = new(); foreach (short fromRoomNumber in Portals.Keys) { @@ -27,34 +20,24 @@ public override void ApplyToLevel(TR1Level level) short convertedToRoomNumber = data.ConvertRoom(toRoomNumber); foreach (EMLocation sectorLocation in Portals[fromRoomNumber][toRoomNumber]) { - TRRoomSector sector = FDUtilities.GetRoomSector(sectorLocation.X, sectorLocation.Y, sectorLocation.Z, convertedFromRoomNumber, level, control); + TRRoomSector sector = level.GetRoomSector(sectorLocation.X, sectorLocation.Y, sectorLocation.Z, convertedFromRoomNumber); if (!sectorMap.ContainsKey(sector)) { - sectorMap[sector] = new List(); + sectorMap[sector] = new(); } - sectorMap[sector].Add((ushort)convertedToRoomNumber); + sectorMap[sector].Add(convertedToRoomNumber); } } } - CreatePortals(sectorMap, control); - - control.WriteToLevel(level); + CreatePortals(sectorMap, level.FloorData); } public override void ApplyToLevel(TR2Level level) { - // Given a room number, we want to create collisional portals into the other room - // using the given locations to find the correct sector. - // See 4.4.1 in https://opentomb.github.io/TRosettaStone3/trosettastone.html#_floordata_functions - EMLevelData data = GetData(level); - - FDControl control = new(); - control.ParseFromLevel(level); - - Dictionary> sectorMap = new(); + Dictionary> sectorMap = new(); // Because some sectors may be shared, we need to call GetRoomSector to get all the sectors we are // interested in first before making any changes. @@ -66,31 +49,24 @@ public override void ApplyToLevel(TR2Level level) short convertedToRoomNumber = data.ConvertRoom(toRoomNumber); foreach (EMLocation sectorLocation in Portals[fromRoomNumber][toRoomNumber]) { - TRRoomSector sector = FDUtilities.GetRoomSector(sectorLocation.X, sectorLocation.Y, sectorLocation.Z, convertedFromRoomNumber, level, control); + TRRoomSector sector = level.GetRoomSector(sectorLocation.X, sectorLocation.Y, sectorLocation.Z, convertedFromRoomNumber); if (!sectorMap.ContainsKey(sector)) { - sectorMap[sector] = new List(); + sectorMap[sector] = new(); } - sectorMap[sector].Add((ushort)convertedToRoomNumber); + sectorMap[sector].Add(convertedToRoomNumber); } } } - // Now create the new entries for all the portals. - CreatePortals(sectorMap, control); - - control.WriteToLevel(level); + CreatePortals(sectorMap, level.FloorData); } public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - - FDControl control = new(); - control.ParseFromLevel(level); - - Dictionary> sectorMap = new(); + Dictionary> sectorMap = new(); foreach (short fromRoomNumber in Portals.Keys) { @@ -100,23 +76,21 @@ public override void ApplyToLevel(TR3Level level) short convertedToRoomNumber = data.ConvertRoom(toRoomNumber); foreach (EMLocation sectorLocation in Portals[fromRoomNumber][toRoomNumber]) { - TRRoomSector sector = FDUtilities.GetRoomSector(sectorLocation.X, sectorLocation.Y, sectorLocation.Z, convertedFromRoomNumber, level, control); + TRRoomSector sector = level.GetRoomSector(sectorLocation.X, sectorLocation.Y, sectorLocation.Z, convertedFromRoomNumber); if (!sectorMap.ContainsKey(sector)) { - sectorMap[sector] = new List(); + sectorMap[sector] = new(); } - sectorMap[sector].Add((ushort)convertedToRoomNumber); + sectorMap[sector].Add(convertedToRoomNumber); } } } - CreatePortals(sectorMap, control); - - control.WriteToLevel(level); + CreatePortals(sectorMap, level.FloorData); } - private static void CreatePortals(Dictionary> sectorMap, FDControl control) + private static void CreatePortals(Dictionary> sectorMap, FDControl control) { foreach (TRRoomSector sector in sectorMap.Keys) { @@ -125,11 +99,10 @@ private static void CreatePortals(Dictionary> sectorM control.CreateFloorData(sector); } - foreach (ushort roomNumber in sectorMap[sector]) + foreach (short roomNumber in sectorMap[sector]) { - control.Entries[sector.FDIndex].Add(new FDPortalEntry + control[sector.FDIndex].Add(new FDPortalEntry { - Setup = new FDSetup { Value = 32769 }, Room = roomNumber }); } diff --git a/TREnvironmentEditor/Model/Types/Portals/EMRemoveCollisionalPortalFunction.cs b/TREnvironmentEditor/Model/Types/Portals/EMRemoveCollisionalPortalFunction.cs index e0c7cb6f7..8b858a18e 100644 --- a/TREnvironmentEditor/Model/Types/Portals/EMRemoveCollisionalPortalFunction.cs +++ b/TREnvironmentEditor/Model/Types/Portals/EMRemoveCollisionalPortalFunction.cs @@ -1,6 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; using TRLevelControl; using TRLevelControl.Model; @@ -17,18 +15,14 @@ public override void ApplyToLevel(TR1Level level) Location1.Room = data.ConvertRoom(Location1.Room); Location2.Room = data.ConvertRoom(Location2.Room); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - TR1Room room1 = level.Rooms[Location1.Room]; TR1Room room2 = level.Rooms[Location2.Room]; + // Change all this to room1.GetSector(Location1.X, Location1.Z); TRRoomSector sector1 = room1.Sectors[GetSectorIndex(room1.Info, Location1, room1.NumZSectors)]; TRRoomSector sector2 = room2.Sectors[GetSectorIndex(room2.Info, Location2, room2.NumZSectors)]; - RemovePortals(sector1, sector2, floorData); - - floorData.WriteToLevel(level); + RemovePortals(sector1, sector2, level.FloorData); } public override void ApplyToLevel(TR2Level level) @@ -37,18 +31,13 @@ public override void ApplyToLevel(TR2Level level) Location1.Room = data.ConvertRoom(Location1.Room); Location2.Room = data.ConvertRoom(Location2.Room); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - TR2Room room1 = level.Rooms[Location1.Room]; TR2Room room2 = level.Rooms[Location2.Room]; TRRoomSector sector1 = room1.Sectors[GetSectorIndex(room1.Info, Location1, room1.NumZSectors)]; TRRoomSector sector2 = room2.Sectors[GetSectorIndex(room2.Info, Location2, room2.NumZSectors)]; - RemovePortals(sector1, sector2, floorData); - - floorData.WriteToLevel(level); + RemovePortals(sector1, sector2, level.FloorData); } public override void ApplyToLevel(TR3Level level) @@ -57,18 +46,13 @@ public override void ApplyToLevel(TR3Level level) Location1.Room = data.ConvertRoom(Location1.Room); Location2.Room = data.ConvertRoom(Location2.Room); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - TR3Room room1 = level.Rooms[Location1.Room]; TR3Room room2 = level.Rooms[Location2.Room]; TRRoomSector sector1 = room1.Sectors[GetSectorIndex(room1.Info, Location1, room1.NumZSectors)]; TRRoomSector sector2 = room2.Sectors[GetSectorIndex(room2.Info, Location2, room2.NumZSectors)]; - RemovePortals(sector1, sector2, floorData); - - floorData.WriteToLevel(level); + RemovePortals(sector1, sector2, level.FloorData); } private void RemovePortals(TRRoomSector sector1, TRRoomSector sector2, FDControl floorData) @@ -103,17 +87,13 @@ private void RemoveHorizontalPortals(TRRoomSector sector, FDControl floorData) return; } - List entries = floorData.Entries[sector.FDIndex]; + List entries = floorData[sector.FDIndex]; if (entries.RemoveAll(e => e is FDPortalEntry portal && (portal.Room == Location1.Room || portal.Room == Location2.Room)) > 0) { // Ensure it's a wall and remove all FD - don't leave nospace in our trails sector.Floor = sector.Ceiling = TRConsts.WallClicks; entries.Clear(); } - if (entries.Count == 0) - { - floorData.RemoveFloorData(sector); - } } private static int GetSectorIndex(TRRoomInfo roomInfo, EMLocation location, int roomDepth) diff --git a/TREnvironmentEditor/Model/Types/Portals/EMReplaceCollisionalPortalFunction.cs b/TREnvironmentEditor/Model/Types/Portals/EMReplaceCollisionalPortalFunction.cs index 463529e63..aa738dc6a 100644 --- a/TREnvironmentEditor/Model/Types/Portals/EMReplaceCollisionalPortalFunction.cs +++ b/TREnvironmentEditor/Model/Types/Portals/EMReplaceCollisionalPortalFunction.cs @@ -1,6 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -16,52 +14,37 @@ public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - TR1Room room = level.Rooms[data.ConvertRoom(Room)]; TRRoomSector sector = room.Sectors[X * room.NumZSectors + Z]; - ReplacePortal(sector, (ushort)data.ConvertRoom(AdjoiningRoom), floorData); - - floorData.WriteToLevel(level); + ReplacePortal(sector, data.ConvertRoom(AdjoiningRoom), level.FloorData); } public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - TR2Room room = level.Rooms[data.ConvertRoom(Room)]; TRRoomSector sector = room.Sectors[X * room.NumZSectors + Z]; - ReplacePortal(sector, (ushort)data.ConvertRoom(AdjoiningRoom), floorData); - - floorData.WriteToLevel(level); + ReplacePortal(sector, data.ConvertRoom(AdjoiningRoom), level.FloorData); } public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - TR3Room room = level.Rooms[data.ConvertRoom(Room)]; TRRoomSector sector = room.Sectors[X * room.NumZSectors + Z]; - ReplacePortal(sector, (ushort)data.ConvertRoom(AdjoiningRoom), floorData); - - floorData.WriteToLevel(level); + ReplacePortal(sector, data.ConvertRoom(AdjoiningRoom), level.FloorData); } - private static void ReplacePortal(TRRoomSector sector, ushort adjoiningRoom, FDControl floorData) + private static void ReplacePortal(TRRoomSector sector, short adjoiningRoom, FDControl floorData) { if (sector.FDIndex == 0) { return; } - foreach (FDEntry entry in floorData.Entries[sector.FDIndex].FindAll(e => e is FDPortalEntry)) + foreach (FDEntry entry in floorData[sector.FDIndex].FindAll(e => e is FDPortalEntry)) { (entry as FDPortalEntry).Room = adjoiningRoom; } diff --git a/TREnvironmentEditor/Model/Types/Portals/EMVerticalCollisionalPortalFunction.cs b/TREnvironmentEditor/Model/Types/Portals/EMVerticalCollisionalPortalFunction.cs index daffcfc5e..df193c72a 100644 --- a/TREnvironmentEditor/Model/Types/Portals/EMVerticalCollisionalPortalFunction.cs +++ b/TREnvironmentEditor/Model/Types/Portals/EMVerticalCollisionalPortalFunction.cs @@ -1,6 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.Utilities; using TRLevelControl; using TRLevelControl.Model; @@ -16,40 +14,36 @@ public class EMVerticalCollisionalPortalFunction : BaseEMFunction public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - - FDControl floorData = new(); - floorData.ParseFromLevel(level); - - short ceilingRoom = data.ConvertRoom(Ceiling.Room); - short floorRoom = data.ConvertRoom(Floor.Room); + EMLocation ceilingRoom = data.ConvertLocation(Ceiling); + EMLocation floorRoom = data.ConvertLocation(Floor); if (AllSectors) { - foreach (TRRoomSector sector in level.Rooms[ceilingRoom].Sectors) + foreach (TRRoomSector sector in level.Rooms[ceilingRoom.Room].Sectors) { if (!sector.IsWall && sector.RoomBelow != TRConsts.NoRoom) { - sector.RoomBelow = (byte)floorRoom; + sector.RoomBelow = (byte)floorRoom.Room; } } - foreach (TRRoomSector sector in level.Rooms[floorRoom].Sectors) + foreach (TRRoomSector sector in level.Rooms[floorRoom.Room].Sectors) { if (!sector.IsWall && sector.RoomAbove != TRConsts.NoRoom) { - sector.RoomAbove = (byte)ceilingRoom; + sector.RoomAbove = (byte)ceilingRoom.Room; } } } else { - TRRoomSector ceilingSector = FDUtilities.GetRoomSector(Ceiling.X, Ceiling.Y, Ceiling.Z, ceilingRoom, level, floorData); - TRRoomSector floorSector = FDUtilities.GetRoomSector(Floor.X, Floor.Y, Floor.Z, floorRoom, level, floorData); + TRRoomSector ceilingSector = level.GetRoomSector(ceilingRoom); + TRRoomSector floorSector = level.GetRoomSector(floorRoom); if (ceilingSector != floorSector) { - ceilingSector.RoomBelow = (byte)floorRoom; - floorSector.RoomAbove = (byte)ceilingRoom; + ceilingSector.RoomBelow = (byte)floorRoom.Room; + floorSector.RoomAbove = (byte)ceilingRoom.Room; if (InheritFloorBox) { @@ -62,40 +56,36 @@ public override void ApplyToLevel(TR1Level level) public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - - FDControl floorData = new(); - floorData.ParseFromLevel(level); - - short ceilingRoom = data.ConvertRoom(Ceiling.Room); - short floorRoom = data.ConvertRoom(Floor.Room); + EMLocation ceilingRoom = data.ConvertLocation(Ceiling); + EMLocation floorRoom = data.ConvertLocation(Floor); if (AllSectors) { - foreach (TRRoomSector sector in level.Rooms[ceilingRoom].Sectors) + foreach (TRRoomSector sector in level.Rooms[ceilingRoom.Room].Sectors) { if (!sector.IsWall && sector.RoomBelow != TRConsts.NoRoom) { - sector.RoomBelow = (byte)floorRoom; + sector.RoomBelow = (byte)floorRoom.Room; } } - foreach (TRRoomSector sector in level.Rooms[floorRoom].Sectors) + foreach (TRRoomSector sector in level.Rooms[floorRoom.Room].Sectors) { if (!sector.IsWall && sector.RoomAbove != TRConsts.NoRoom) { - sector.RoomAbove = (byte)ceilingRoom; + sector.RoomAbove = (byte)ceilingRoom.Room; } } } else { - TRRoomSector ceilingSector = FDUtilities.GetRoomSector(Ceiling.X, Ceiling.Y, Ceiling.Z, ceilingRoom, level, floorData); - TRRoomSector floorSector = FDUtilities.GetRoomSector(Floor.X, Floor.Y, Floor.Z, floorRoom, level, floorData); + TRRoomSector ceilingSector = level.GetRoomSector(ceilingRoom); + TRRoomSector floorSector = level.GetRoomSector(floorRoom); if (ceilingSector != floorSector) { - ceilingSector.RoomBelow = (byte)floorRoom; - floorSector.RoomAbove = (byte)ceilingRoom; + ceilingSector.RoomBelow = (byte)floorRoom.Room; + floorSector.RoomAbove = (byte)ceilingRoom.Room; if (InheritFloorBox) { @@ -108,40 +98,36 @@ public override void ApplyToLevel(TR2Level level) public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - - FDControl floorData = new(); - floorData.ParseFromLevel(level); - - short ceilingRoom = data.ConvertRoom(Ceiling.Room); - short floorRoom = data.ConvertRoom(Floor.Room); + EMLocation ceilingRoom = data.ConvertLocation(Ceiling); + EMLocation floorRoom = data.ConvertLocation(Floor); if (AllSectors) { - foreach (TRRoomSector sector in level.Rooms[ceilingRoom].Sectors) + foreach (TRRoomSector sector in level.Rooms[ceilingRoom.Room].Sectors) { if (!sector.IsWall && sector.RoomBelow != TRConsts.NoRoom) { - sector.RoomBelow = (byte)floorRoom; + sector.RoomBelow = (byte)floorRoom.Room; } } - foreach (TRRoomSector sector in level.Rooms[floorRoom].Sectors) + foreach (TRRoomSector sector in level.Rooms[floorRoom.Room].Sectors) { if (!sector.IsWall && sector.RoomAbove != TRConsts.NoRoom) { - sector.RoomAbove = (byte)ceilingRoom; + sector.RoomAbove = (byte)ceilingRoom.Room; } } } else { - TRRoomSector ceilingSector = FDUtilities.GetRoomSector(Ceiling.X, Ceiling.Y, Ceiling.Z, ceilingRoom, level, floorData); - TRRoomSector floorSector = FDUtilities.GetRoomSector(Floor.X, Floor.Y, Floor.Z, floorRoom, level, floorData); + TRRoomSector ceilingSector = level.GetRoomSector(ceilingRoom); + TRRoomSector floorSector = level.GetRoomSector(floorRoom); if (ceilingSector != floorSector) { - ceilingSector.RoomBelow = (byte)floorRoom; - floorSector.RoomAbove = (byte)ceilingRoom; + ceilingSector.RoomBelow = (byte)floorRoom.Room; + floorSector.RoomAbove = (byte)ceilingRoom.Room; if (InheritFloorBox) { diff --git a/TREnvironmentEditor/Model/Types/Rooms/EMCopyRoomFunction.cs b/TREnvironmentEditor/Model/Types/Rooms/EMCopyRoomFunction.cs index ffe5f8a11..e16598aca 100644 --- a/TREnvironmentEditor/Model/Types/Rooms/EMCopyRoomFunction.cs +++ b/TREnvironmentEditor/Model/Types/Rooms/EMCopyRoomFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl; using TRLevelControl.Helpers.Pathing; using TRLevelControl.Model; @@ -66,20 +63,15 @@ public override void ApplyToLevel(TR1Level level) } // Rebuild the sectors - FDControl floorData = new(); - floorData.ParseFromLevel(level); - for (int i = 0; i < baseRoom.Sectors.Count; i++) { - newRoom.Sectors.Add(RebuildSector(baseRoom.Sectors[i], i, floorData, ydiff, baseRoom.Info)); + newRoom.Sectors.Add(RebuildSector(baseRoom.Sectors[i], i, level.FloorData, ydiff, baseRoom.Info)); } - floorData.WriteToLevel(level); - // Generate new boxes, unless this room is meant to be isolated if (LinkedLocation != null) { - TRRoomSector linkedSector = FDUtilities.GetRoomSector(LinkedLocation.X, LinkedLocation.Y, LinkedLocation.Z, data.ConvertRoom(LinkedLocation.Room), level, floorData); + TRRoomSector linkedSector = level.GetRoomSector(data.ConvertLocation(LinkedLocation)); BoxGenerator.Generate(newRoom, level, linkedSector); } @@ -138,20 +130,15 @@ public override void ApplyToLevel(TR2Level level) } // Rebuild the sectors - FDControl floorData = new(); - floorData.ParseFromLevel(level); - for (int i = 0; i < baseRoom.Sectors.Count; i++) { - newRoom.Sectors.Add(RebuildSector(baseRoom.Sectors[i], i, floorData, ydiff, baseRoom.Info)); + newRoom.Sectors.Add(RebuildSector(baseRoom.Sectors[i], i, level.FloorData, ydiff, baseRoom.Info)); } - floorData.WriteToLevel(level); - // Generate new boxes, unless this room is meant to be isolated if (LinkedLocation != null) { - TRRoomSector linkedSector = FDUtilities.GetRoomSector(LinkedLocation.X, LinkedLocation.Y, LinkedLocation.Z, data.ConvertRoom(LinkedLocation.Room), level, floorData); + TRRoomSector linkedSector = level.GetRoomSector(data.ConvertLocation(LinkedLocation)); BoxGenerator.Generate(newRoom, level, linkedSector); } @@ -211,20 +198,15 @@ public override void ApplyToLevel(TR3Level level) } // Rebuild the sectors - FDControl floorData = new(); - floorData.ParseFromLevel(level); - for (int i = 0; i < baseRoom.Sectors.Count; i++) { - newRoom.Sectors.Add(RebuildSector(baseRoom.Sectors[i], i, floorData, ydiff, baseRoom.Info)); + newRoom.Sectors.Add(RebuildSector(baseRoom.Sectors[i], i, level.FloorData, ydiff, baseRoom.Info)); } - floorData.WriteToLevel(level); - // Generate new boxes, unless this room is meant to be isolated if (LinkedLocation != null) { - TRRoomSector linkedSector = FDUtilities.GetRoomSector(LinkedLocation.X, LinkedLocation.Y, LinkedLocation.Z, data.ConvertRoom(LinkedLocation.Room), level, floorData); + TRRoomSector linkedSector = level.GetRoomSector(data.ConvertLocation(LinkedLocation)); BoxGenerator.Generate(newRoom, level, linkedSector); } @@ -275,13 +257,13 @@ private TRRoomSector RebuildSector(TRRoomSector originalSector, int sectorIndex, // so they can be blocked off. if (originalSector.FDIndex != 0) { - List entries = floorData.Entries[originalSector.FDIndex]; + List entries = floorData[originalSector.FDIndex]; List newEntries = new(); foreach (FDEntry entry in entries) { - switch ((FDFunction)entry.Setup.Function) + switch (entry) { - case FDFunction.PortalSector: + case FDPortalEntry: // This portal will no longer be valid in the new room's position, // so block off the wall provided we haven't opened the wall above. if (!wallOpened) @@ -289,72 +271,10 @@ private TRRoomSector RebuildSector(TRRoomSector originalSector, int sectorIndex, newSector.Floor = newSector.Ceiling = TRConsts.WallClicks; } break; - case FDFunction.FloorSlant: - FDSlantEntry slantEntry = entry as FDSlantEntry; - newEntries.Add(new FDSlantEntry() - { - Setup = new FDSetup() { Value = slantEntry.Setup.Value }, - SlantValue = slantEntry.SlantValue, - Type = FDSlantType.FloorSlant - }); - break; - case FDFunction.CeilingSlant: - FDSlantEntry ceilingSlant = entry as FDSlantEntry; - newEntries.Add(new FDSlantEntry() - { - Setup = new FDSetup() { Value = ceilingSlant.Setup.Value }, - SlantValue = ceilingSlant.SlantValue, - Type = FDSlantType.CeilingSlant - }); - break; - case FDFunction.KillLara: - newEntries.Add(new FDKillLaraEntry() - { - Setup = new FDSetup() { Value = entry.Setup.Value } - }); - break; - case FDFunction.ClimbableWalls: - newEntries.Add(new FDClimbEntry() - { - Setup = new FDSetup() { Value = entry.Setup.Value } - }); - break; - case FDFunction.FloorTriangulationNWSE_Solid: - case FDFunction.FloorTriangulationNESW_Solid: - case FDFunction.CeilingTriangulationNW_Solid: - case FDFunction.CeilingTriangulationNE_Solid: - case FDFunction.FloorTriangulationNWSE_SW: - case FDFunction.FloorTriangulationNWSE_NE: - case FDFunction.FloorTriangulationNESW_SE: - case FDFunction.FloorTriangulationNESW_NW: - case FDFunction.CeilingTriangulationNW_SW: - case FDFunction.CeilingTriangulationNW_NE: - case FDFunction.CeilingTriangulationNE_NW: - case FDFunction.CeilingTriangulationNE_SE: - FDTriangulationEntry triEntry = entry as FDTriangulationEntry; - newEntries.Add(new FDTriangulationEntry - { - Setup = new FDSetup { Value = triEntry.Setup.Value }, - TriData = new FDTriangulationData { Value = triEntry.TriData.Value } - }); + case FDTriggerEntry: break; - case FDFunction.Monkeyswing: - newEntries.Add(new FDMonkeySwingEntry() - { - Setup = new FDSetup() { Value = entry.Setup.Value } - }); - break; - case FDFunction.DeferredTriggeringOrMinecartRotateLeft: - newEntries.Add(new FDMinecartEntry() - { - Setup = new FDSetup() { Value = entry.Setup.Value } - }); - break; - case FDFunction.MechBeetleOrMinecartRotateRight: - newEntries.Add(new TR3MinecartRotateRightEntry() - { - Setup = new FDSetup() { Value = entry.Setup.Value } - }); + default: + newEntries.Add(entry.Clone()); break; } } @@ -362,7 +282,7 @@ private TRRoomSector RebuildSector(TRRoomSector originalSector, int sectorIndex, if (newEntries.Count > 0) { floorData.CreateFloorData(newSector); - floorData.Entries[newSector.FDIndex].AddRange(newEntries); + floorData[newSector.FDIndex].AddRange(newEntries); } } diff --git a/TREnvironmentEditor/Model/Types/Rooms/EMCreateRoomFunction.cs b/TREnvironmentEditor/Model/Types/Rooms/EMCreateRoomFunction.cs index 2c309596d..d6b29b894 100644 --- a/TREnvironmentEditor/Model/Types/Rooms/EMCreateRoomFunction.cs +++ b/TREnvironmentEditor/Model/Types/Rooms/EMCreateRoomFunction.cs @@ -1,6 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.Utilities; using TRLevelControl; using TRLevelControl.Helpers.Pathing; using TRLevelControl.Model; @@ -68,11 +66,8 @@ public override void ApplyToLevel(TR1Level level) room.Sectors = GenerateSectors(ceiling, floor); // Generate the box, zone and overlap data - FDControl floorData = new(); - floorData.ParseFromLevel(level); - EMLevelData data = GetData(level); - TRRoomSector linkedSector = FDUtilities.GetRoomSector(LinkedLocation.X, LinkedLocation.Y, LinkedLocation.Z, data.ConvertRoom(LinkedLocation.Room), level, floorData); + TRRoomSector linkedSector = level.GetRoomSector(data.ConvertLocation(LinkedLocation)); BoxGenerator.Generate(room, level, linkedSector); // Stride the sectors again and make faces @@ -137,11 +132,8 @@ public override void ApplyToLevel(TR2Level level) room.Sectors = GenerateSectors(ceiling, floor); // Generate the box, zone and overlap data - FDControl floorData = new(); - floorData.ParseFromLevel(level); - EMLevelData data = GetData(level); - TRRoomSector linkedSector = FDUtilities.GetRoomSector(LinkedLocation.X, LinkedLocation.Y, LinkedLocation.Z, data.ConvertRoom(LinkedLocation.Room), level, floorData); + TRRoomSector linkedSector = level.GetRoomSector(data.ConvertLocation(LinkedLocation)); BoxGenerator.Generate(room, level, linkedSector); // Stride the sectors again and make faces @@ -207,11 +199,8 @@ public override void ApplyToLevel(TR3Level level) room.Sectors = GenerateSectors(ceiling, floor); // Generate the box, zone and overlap data - FDControl floorData = new(); - floorData.ParseFromLevel(level); - EMLevelData data = GetData(level); - TRRoomSector linkedSector = FDUtilities.GetRoomSector(LinkedLocation.X, LinkedLocation.Y, LinkedLocation.Z, data.ConvertRoom(LinkedLocation.Room), level, floorData); + TRRoomSector linkedSector = level.GetRoomSector(data.ConvertLocation(LinkedLocation)); BoxGenerator.Generate(room, level, linkedSector); // Stride the sectors again and make faces diff --git a/TREnvironmentEditor/Model/Types/Rooms/EMCreateWallFunction.cs b/TREnvironmentEditor/Model/Types/Rooms/EMCreateWallFunction.cs index 790b8327a..f2f1a92dc 100644 --- a/TREnvironmentEditor/Model/Types/Rooms/EMCreateWallFunction.cs +++ b/TREnvironmentEditor/Model/Types/Rooms/EMCreateWallFunction.cs @@ -1,6 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.Utilities; using TRLevelControl; using TRLevelControl.Model; @@ -15,117 +13,95 @@ public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - short roomIndex = data.ConvertRoom(location.Room); - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, roomIndex, level, floorData); - BlockSector(sector, floorData); + EMLocation position = data.ConvertLocation(location); + TRRoomSector sector = level.GetRoomSector(position); + BlockSector(sector); // Move any entities that share the same floor sector somewhere else - if (EntityMoveLocation != null) + if (EntityMoveLocation == null) { - foreach (TR1Entity entity in level.Entities) + continue; + } + + foreach (TR1Entity entity in level.Entities.Where(e => e.Room == position.Room)) + { + TRRoomSector entitySector = level.GetRoomSector(entity); + if (entitySector == sector) { - if (entity.Room == roomIndex) - { - TRRoomSector entitySector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, floorData); - if (entitySector == sector) - { - entity.X = EntityMoveLocation.X; - entity.Y = EntityMoveLocation.Y; - entity.Z = EntityMoveLocation.Z; - entity.Room += data.ConvertRoom(EntityMoveLocation.Room); - } - } + entity.X = EntityMoveLocation.X; + entity.Y = EntityMoveLocation.Y; + entity.Z = EntityMoveLocation.Z; + entity.Room += data.ConvertRoom(EntityMoveLocation.Room); } } } - - floorData.WriteToLevel(level); } public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - short roomIndex = data.ConvertRoom(location.Room); - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, roomIndex, level, floorData); - BlockSector(sector, floorData); + EMLocation position = data.ConvertLocation(location); + TRRoomSector sector = level.GetRoomSector(position); + BlockSector(sector); // Move any entities that share the same floor sector somewhere else - if (EntityMoveLocation != null) + if (EntityMoveLocation == null) + { + continue; + } + + foreach (TR2Entity entity in level.Entities.Where(e => e.Room == position.Room)) { - foreach (TR2Entity entity in level.Entities) + TRRoomSector entitySector = level.GetRoomSector(entity); + if (entitySector == sector) { - if (entity.Room == roomIndex) - { - TRRoomSector entitySector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, floorData); - if (entitySector == sector) - { - entity.X = EntityMoveLocation.X; - entity.Y = EntityMoveLocation.Y; - entity.Z = EntityMoveLocation.Z; - entity.Room += data.ConvertRoom(EntityMoveLocation.Room); - } - } + entity.X = EntityMoveLocation.X; + entity.Y = EntityMoveLocation.Y; + entity.Z = EntityMoveLocation.Z; + entity.Room += data.ConvertRoom(EntityMoveLocation.Room); } } } - - floorData.WriteToLevel(level); } public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - short roomIndex = data.ConvertRoom(location.Room); - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, roomIndex, level, floorData); - BlockSector(sector, floorData); + EMLocation position = data.ConvertLocation(location); + TRRoomSector sector = level.GetRoomSector(position); + BlockSector(sector); // Move any entities that share the same floor sector somewhere else - if (EntityMoveLocation != null) + if (EntityMoveLocation == null) + { + continue; + } + + foreach (TR3Entity entity in level.Entities.Where(e => e.Room == position.Room)) { - foreach (TR3Entity entity in level.Entities) + TRRoomSector entitySector = level.GetRoomSector(entity); + if (entitySector == sector) { - if (entity.Room == roomIndex) - { - TRRoomSector entitySector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, floorData); - if (entitySector == sector) - { - entity.X = EntityMoveLocation.X; - entity.Y = EntityMoveLocation.Y; - entity.Z = EntityMoveLocation.Z; - entity.Room += data.ConvertRoom(EntityMoveLocation.Room); - } - } + entity.X = EntityMoveLocation.X; + entity.Y = EntityMoveLocation.Y; + entity.Z = EntityMoveLocation.Z; + entity.Room += data.ConvertRoom(EntityMoveLocation.Room); } } } - - floorData.WriteToLevel(level); } - private static void BlockSector(TRRoomSector sector, FDControl floorData) + private static void BlockSector(TRRoomSector sector) { sector.Floor = sector.Ceiling = TRConsts.WallClicks; sector.BoxIndex = ushort.MaxValue; - if (sector.FDIndex != 0) - { - floorData.RemoveFloorData(sector); - } } } diff --git a/TREnvironmentEditor/Model/Types/Rooms/EMImportRoomFunction.cs b/TREnvironmentEditor/Model/Types/Rooms/EMImportRoomFunction.cs index cdfecf7c0..141cf9aad 100644 --- a/TREnvironmentEditor/Model/Types/Rooms/EMImportRoomFunction.cs +++ b/TREnvironmentEditor/Model/Types/Rooms/EMImportRoomFunction.cs @@ -1,8 +1,5 @@ using Newtonsoft.Json; using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -165,14 +162,12 @@ public override void ApplyToLevel(TR2Level level) // Boxes, zones and sectors EMLevelData data = GetData(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); ushort newBoxIndex = ushort.MaxValue; // Duplicate the zone for the new box and link the current box to the new room if (!PreserveBoxes) { - TRRoomSector linkedSector = FDUtilities.GetRoomSector(LinkedLocation.X, LinkedLocation.Y, LinkedLocation.Z, data.ConvertRoom(LinkedLocation.Room), level, floorData); + TRRoomSector linkedSector = level.GetRoomSector(data.ConvertLocation(LinkedLocation)); newBoxIndex = (ushort)level.Boxes.Count; int linkedBoxIndex = linkedSector.BoxIndex; @@ -234,56 +229,29 @@ public override void ApplyToLevel(TR2Level level) List newEntries = new(); foreach (FDEntry entry in entries) { - switch ((FDFunction)entry.Setup.Function) + switch (entry) { - case FDFunction.PortalSector: + case FDPortalEntry: // This portal will no longer be valid in the new room's position, // so block off the wall newRoom.Sectors[i].Floor = newRoom.Sectors[i].Ceiling = TRConsts.WallClicks; break; - case FDFunction.FloorSlant: - FDSlantEntry slantEntry = entry as FDSlantEntry; - newEntries.Add(new FDSlantEntry() - { - Setup = new FDSetup() { Value = slantEntry.Setup.Value }, - SlantValue = slantEntry.SlantValue, - Type = FDSlantType.FloorSlant - }); + case FDTriggerEntry: break; - case FDFunction.CeilingSlant: - FDSlantEntry ceilingSlant = entry as FDSlantEntry; - newEntries.Add(new FDSlantEntry() - { - Setup = new FDSetup() { Value = ceilingSlant.Setup.Value }, - SlantValue = ceilingSlant.SlantValue, - Type = FDSlantType.CeilingSlant - }); - break; - case FDFunction.KillLara: - newEntries.Add(new FDKillLaraEntry() - { - Setup = new FDSetup() { Value = entry.Setup.Value } - }); - break; - case FDFunction.ClimbableWalls: - newEntries.Add(new FDClimbEntry() - { - Setup = new FDSetup() { Value = entry.Setup.Value } - }); + default: + newEntries.Add(entry.Clone()); break; } } if (newEntries.Count > 0) { - floorData.CreateFloorData(newRoom.Sectors[i]); - floorData.Entries[newRoom.Sectors[i].FDIndex].AddRange(newEntries); + level.FloorData.CreateFloorData(newRoom.Sectors[i]); + level.FloorData[newRoom.Sectors[i].FDIndex].AddRange(newEntries); } } } - floorData.WriteToLevel(level); - level.Rooms.Add(newRoom); } @@ -409,10 +377,8 @@ public override void ApplyToLevel(TR3Level level) // Boxes, zones and sectors EMLevelData data = GetData(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - TRRoomSector linkedSector = FDUtilities.GetRoomSector(LinkedLocation.X, LinkedLocation.Y, LinkedLocation.Z, data.ConvertRoom(LinkedLocation.Room), level, floorData); + TRRoomSector linkedSector = level.GetRoomSector(data.ConvertLocation(LinkedLocation)); ushort newBoxIndex = ushort.MaxValue; int linkedBoxIndex = (linkedSector.BoxIndex & 0x7FF0) >> 4; int linkedMaterial = linkedSector.BoxIndex & 0x000F; // TR3-5 store material in bits 0-3 - wood, mud etc @@ -485,93 +451,29 @@ public override void ApplyToLevel(TR3Level level) List newEntries = new(); foreach (FDEntry entry in entries) { - switch ((FDFunction)entry.Setup.Function) + switch (entry) { - case FDFunction.PortalSector: + case FDPortalEntry: // This portal will no longer be valid in the new room's position, // so block off the wall newRoom.Sectors[i].Floor = newRoom.Sectors[i].Ceiling = TRConsts.WallClicks; break; - case FDFunction.FloorSlant: - FDSlantEntry slantEntry = entry as FDSlantEntry; - newEntries.Add(new FDSlantEntry() - { - Setup = new FDSetup() { Value = slantEntry.Setup.Value }, - SlantValue = slantEntry.SlantValue, - Type = FDSlantType.FloorSlant - }); - break; - case FDFunction.CeilingSlant: - FDSlantEntry ceilingSlant = entry as FDSlantEntry; - newEntries.Add(new FDSlantEntry() - { - Setup = new FDSetup() { Value = ceilingSlant.Setup.Value }, - SlantValue = ceilingSlant.SlantValue, - Type = FDSlantType.CeilingSlant - }); - break; - case FDFunction.KillLara: - newEntries.Add(new FDKillLaraEntry() - { - Setup = new FDSetup() { Value = entry.Setup.Value } - }); + case FDTriggerEntry: break; - case FDFunction.ClimbableWalls: - newEntries.Add(new FDClimbEntry() - { - Setup = new FDSetup() { Value = entry.Setup.Value } - }); - break; - case FDFunction.FloorTriangulationNWSE_Solid: - case FDFunction.FloorTriangulationNESW_Solid: - case FDFunction.CeilingTriangulationNW_Solid: - case FDFunction.CeilingTriangulationNE_Solid: - case FDFunction.FloorTriangulationNWSE_SW: - case FDFunction.FloorTriangulationNWSE_NE: - case FDFunction.FloorTriangulationNESW_SE: - case FDFunction.FloorTriangulationNESW_NW: - case FDFunction.CeilingTriangulationNW_SW: - case FDFunction.CeilingTriangulationNW_NE: - case FDFunction.CeilingTriangulationNE_NW: - case FDFunction.CeilingTriangulationNE_SE: - FDTriangulationEntry triEntry = entry as FDTriangulationEntry; - newEntries.Add(new FDTriangulationEntry - { - Setup = new FDSetup { Value = triEntry.Setup.Value }, - TriData = new FDTriangulationData { Value = triEntry.TriData.Value } - }); - break; - case FDFunction.Monkeyswing: - newEntries.Add(new FDMonkeySwingEntry() - { - Setup = new FDSetup() { Value = entry.Setup.Value } - }); - break; - case FDFunction.DeferredTriggeringOrMinecartRotateLeft: - newEntries.Add(new FDMinecartEntry() - { - Setup = new FDSetup() { Value = entry.Setup.Value } - }); - break; - case FDFunction.MechBeetleOrMinecartRotateRight: - newEntries.Add(new TR3MinecartRotateRightEntry() - { - Setup = new FDSetup() { Value = entry.Setup.Value } - }); + default: + newEntries.Add(entry.Clone()); break; } } if (newEntries.Count > 0) { - floorData.CreateFloorData(newRoom.Sectors[i]); - floorData.Entries[newRoom.Sectors[i].FDIndex].AddRange(newEntries); + level.FloorData.CreateFloorData(newRoom.Sectors[i]); + level.FloorData[newRoom.Sectors[i].FDIndex].AddRange(newEntries); } } } - floorData.WriteToLevel(level); - level.Rooms.Add(newRoom); } diff --git a/TREnvironmentEditor/Model/Types/Surfaces/BaseWaterFunction.cs b/TREnvironmentEditor/Model/Types/Surfaces/BaseWaterFunction.cs index 0de0642fb..b4528e9c8 100644 --- a/TREnvironmentEditor/Model/Types/Surfaces/BaseWaterFunction.cs +++ b/TREnvironmentEditor/Model/Types/Surfaces/BaseWaterFunction.cs @@ -1,6 +1,4 @@ -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRLevelControl; +using TRLevelControl; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -125,7 +123,7 @@ public void AddWaterSurface(TR3Room room, bool asCeiling, IEnumerable adjac bool ceilingMatch = asCeiling && adjacentRooms.Contains(sector.RoomAbove); bool floorMatch = !asCeiling && adjacentRooms.Contains(sector.RoomBelow); // Ignore triangles for now - bool isTriangle = sector.FDIndex != 0 && floorData.Entries[sector.FDIndex].Any(e => e is FDTriangulationEntry); + bool isTriangle = sector.FDIndex != 0 && floorData[sector.FDIndex].Any(e => e is FDTriangulationEntry); if (!isTriangle && (ceilingMatch || floorMatch)) { diff --git a/TREnvironmentEditor/Model/Types/Surfaces/EMClickFunction.cs b/TREnvironmentEditor/Model/Types/Surfaces/EMClickFunction.cs index 9b1c4c047..ff0239238 100644 --- a/TREnvironmentEditor/Model/Types/Surfaces/EMClickFunction.cs +++ b/TREnvironmentEditor/Model/Types/Surfaces/EMClickFunction.cs @@ -1,6 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.Utilities; using TRLevelControl; using TRLevelControl.Model; @@ -24,22 +22,20 @@ public override void ApplyToLevel(TR1Level level) EMLevelData data = GetData(level); _locations = InitialiseLocations(data); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (EMLocation location in _locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, location.Room, level, floorData); - MoveSector(sector, level.Rooms[location.Room].Info); + EMLocation position = data.ConvertLocation(location); + TRRoomSector sector = level.GetRoomSector(position); + MoveSector(sector, level.Rooms[position.Room].Info); // Move any entities that share the same floor sector up or down the relevant number of clicks if (FloorClicks.HasValue && !RetainItemPositions) { foreach (TR1Entity entity in level.Entities) { - if (entity.Room == location.Room) + if (entity.Room == position.Room) { - TRRoomSector entitySector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, floorData); + TRRoomSector entitySector = level.GetRoomSector(entity); if (entitySector == sector) { entity.Y += GetEntityYShift(FloorClicks.Value); @@ -55,22 +51,20 @@ public override void ApplyToLevel(TR2Level level) EMLevelData data = GetData(level); _locations = InitialiseLocations(data); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (EMLocation location in _locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, location.Room, level, floorData); - MoveSector(sector, level.Rooms[location.Room].Info); + EMLocation position = data.ConvertLocation(location); + TRRoomSector sector = level.GetRoomSector(position); + MoveSector(sector, level.Rooms[position.Room].Info); // Move any entities that share the same floor sector up or down the relevant number of clicks if (FloorClicks.HasValue && !RetainItemPositions) { foreach (TR2Entity entity in level.Entities) { - if (entity.Room == location.Room) + if (entity.Room == position.Room) { - TRRoomSector entitySector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, floorData); + TRRoomSector entitySector = level.GetRoomSector(entity); if (entitySector == sector) { entity.Y += GetEntityYShift(FloorClicks.Value); @@ -86,22 +80,20 @@ public override void ApplyToLevel(TR3Level level) EMLevelData data = GetData(level); _locations = InitialiseLocations(data); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (EMLocation location in _locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, location.Room, level, floorData); - MoveSector(sector, level.Rooms[location.Room].Info); + EMLocation position = data.ConvertLocation(location); + TRRoomSector sector = level.GetRoomSector(position); + MoveSector(sector, level.Rooms[position.Room].Info); // Move any entities that share the same floor sector up or down the relevant number of clicks if (FloorClicks.HasValue && !RetainItemPositions) { foreach (TR3Entity entity in level.Entities) { - if (entity.Room == location.Room) + if (entity.Room == position.Room) { - TRRoomSector entitySector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, floorData); + TRRoomSector entitySector = level.GetRoomSector(entity); if (entitySector == sector) { entity.Y += GetEntityYShift(FloorClicks.Value); diff --git a/TREnvironmentEditor/Model/Types/Surfaces/EMDrainFunction.cs b/TREnvironmentEditor/Model/Types/Surfaces/EMDrainFunction.cs index 73b687da5..97a00e962 100644 --- a/TREnvironmentEditor/Model/Types/Surfaces/EMDrainFunction.cs +++ b/TREnvironmentEditor/Model/Types/Surfaces/EMDrainFunction.cs @@ -1,5 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -118,9 +117,6 @@ public override void ApplyToLevel(TR3Level level) return; } - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (int roomNumber in RoomNumbers) { TR3Room room = level.Rooms[data.ConvertRoom(roomNumber)]; @@ -131,7 +127,7 @@ public override void ApplyToLevel(TR3Level level) TR3Room roomBelow = level.Rooms[roomBelowNumber]; if (roomBelow.ContainsWater) { - AddWaterSurface(room, false, RoomNumbers, floorData); + AddWaterSurface(room, false, RoomNumbers, level.FloorData); } } diff --git a/TREnvironmentEditor/Model/Types/Surfaces/EMFloodFunction.cs b/TREnvironmentEditor/Model/Types/Surfaces/EMFloodFunction.cs index 2d2922afd..35b23c218 100644 --- a/TREnvironmentEditor/Model/Types/Surfaces/EMFloodFunction.cs +++ b/TREnvironmentEditor/Model/Types/Surfaces/EMFloodFunction.cs @@ -1,5 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -91,8 +90,6 @@ public override void ApplyToLevel(TR2Level level) public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); foreach (int roomNumber in RoomNumbers) { @@ -124,8 +121,8 @@ public override void ApplyToLevel(TR3Level level) TR3Room roomAbove = level.Rooms[roomAboveNumber]; if (!roomAbove.ContainsWater) { - AddWaterSurface(room, true, new int[] { roomAboveNumber }, floorData); - AddWaterSurface(roomAbove, false, RoomNumbers, floorData); + AddWaterSurface(room, true, new int[] { roomAboveNumber }, level.FloorData); + AddWaterSurface(roomAbove, false, RoomNumbers, level.FloorData); } } } diff --git a/TREnvironmentEditor/Model/Types/Surfaces/EMFloorFunction.cs b/TREnvironmentEditor/Model/Types/Surfaces/EMFloorFunction.cs index f3e0aac44..87dbf2cbc 100644 --- a/TREnvironmentEditor/Model/Types/Surfaces/EMFloorFunction.cs +++ b/TREnvironmentEditor/Model/Types/Surfaces/EMFloorFunction.cs @@ -1,6 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.Utilities; using TRLevelControl; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -49,13 +47,10 @@ private void MoveFloor(TR1Level level) EMLevelData data = GetData(level); - FDControl fdc = new(); - fdc.ParseFromLevel(level); - - short roomNumber = data.ConvertRoom(Location.Room); - TR1Room room = level.Rooms[roomNumber]; - TRRoomSector sector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, roomNumber, level, fdc); - int sectorIndex = room.Sectors.ToList().IndexOf(sector); + EMLocation location = data.ConvertLocation(Location); + TR1Room room = level.Rooms[location.Room]; + TRRoomSector sector = level.GetRoomSector(location); + int sectorIndex = room.Sectors.IndexOf(sector); // Find the current vertices for this tile short x = (short)(sectorIndex / room.NumZSectors * TRConsts.Step4); @@ -184,9 +179,9 @@ private void MoveFloor(TR1Level level) // Move any entities that share the same floor sector up or down the relevant number of clicks foreach (TR1Entity entity in level.Entities) { - if (entity.Room == roomNumber) + if (entity.Room == location.Room) { - TRRoomSector entitySector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, fdc); + TRRoomSector entitySector = level.GetRoomSector(entity); if (entitySector == sector) { entity.Y += clickChange; @@ -271,13 +266,10 @@ private void MoveFloor(TR2Level level) EMLevelData data = GetData(level); - FDControl fdc = new(); - fdc.ParseFromLevel(level); - - short roomNumber = data.ConvertRoom(Location.Room); - TR2Room room = level.Rooms[roomNumber]; - TRRoomSector sector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, roomNumber, level, fdc); - int sectorIndex = room.Sectors.ToList().IndexOf(sector); + EMLocation location = data.ConvertLocation(Location); + TR2Room room = level.Rooms[location.Room]; + TRRoomSector sector = level.GetRoomSector(location); + int sectorIndex = room.Sectors.IndexOf(sector); // Find the current vertices for this tile short x = (short)(sectorIndex / room.NumZSectors * TRConsts.Step4); @@ -405,9 +397,9 @@ private void MoveFloor(TR2Level level) // Move any entities that share the same floor sector up or down the relevant number of clicks foreach (TR2Entity entity in level.Entities) { - if (entity.Room == roomNumber) + if (entity.Room == location.Room) { - TRRoomSector entitySector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, fdc); + TRRoomSector entitySector = level.GetRoomSector(entity); if (entitySector == sector) { entity.Y += clickChange; @@ -512,13 +504,10 @@ private void MoveFloor(TR3Level level) EMLevelData data = GetData(level); - FDControl fdc = new(); - fdc.ParseFromLevel(level); - - short roomNumber = data.ConvertRoom(Location.Room); - TR3Room room = level.Rooms[roomNumber]; - TRRoomSector sector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, roomNumber, level, fdc); - int sectorIndex = room.Sectors.ToList().IndexOf(sector); + EMLocation location = data.ConvertLocation(Location); + TR3Room room = level.Rooms[location.Room]; + TRRoomSector sector = level.GetRoomSector(location); + int sectorIndex = room.Sectors.IndexOf(sector); // Find the current vertices for this tile short x = (short)(sectorIndex / room.NumZSectors * TRConsts.Step4); @@ -640,9 +629,9 @@ private void MoveFloor(TR3Level level) // Move any entities that share the same floor sector up or down the relevant number of clicks foreach (TR3Entity entity in level.Entities) { - if (entity.Room == roomNumber) + if (entity.Room == location.Room) { - TRRoomSector entitySector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, fdc); + TRRoomSector entitySector = level.GetRoomSector(entity); if (entitySector == sector) { entity.Y += clickChange; diff --git a/TREnvironmentEditor/Model/Types/Surfaces/EMLadderFunction.cs b/TREnvironmentEditor/Model/Types/Surfaces/EMLadderFunction.cs index 842b76e56..dcd978a7c 100644 --- a/TREnvironmentEditor/Model/Types/Surfaces/EMLadderFunction.cs +++ b/TREnvironmentEditor/Model/Types/Surfaces/EMLadderFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -23,18 +20,9 @@ public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(Location)); + ModifyLadder(sector, level.FloorData); - TRRoomSector sector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, data.ConvertRoom(Location.Room), level, control); - ModifyLadder(sector, control); - - control.WriteToLevel(level); - - // Unfortunately the ladder texture may not match the walls we are targeting, but - // we can maybe look at generating a ladder texture with a transparent background for - // each level, and then merging it with the wall in a particular room (similar to the way - // landmarks are done), provided there is enough texture space. base.ApplyToLevel(level); } @@ -42,13 +30,8 @@ public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); - - TRRoomSector sector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, data.ConvertRoom(Location.Room), level, control); - ModifyLadder(sector, control); - - control.WriteToLevel(level); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(Location)); + ModifyLadder(sector, level.FloorData); base.ApplyToLevel(level); } @@ -74,20 +57,14 @@ private void ModifyLadder(TRRoomSector sector, FDControl control) if (sector.FDIndex != 0) { // remove the climbable entry and if it leaves an empty list, remove the FD - List entries = control.Entries[sector.FDIndex]; + List entries = control[sector.FDIndex]; entries.RemoveAll(e => e is FDClimbEntry); - if (entries.Count == 0) - { - // If there isn't anything left, reset the sector to point to the dummy FD - control.RemoveFloorData(sector); - } } } else { FDClimbEntry climbEntry = new() { - Setup = new FDSetup(FDFunction.ClimbableWalls), IsPositiveX = IsPositiveX, IsPositiveZ = IsPositiveZ, IsNegativeX = IsNegativeX, @@ -95,10 +72,10 @@ private void ModifyLadder(TRRoomSector sector, FDControl control) }; // We have to add climbable entries after portal, slant and kill Lara entries. - List entries = control.Entries[sector.FDIndex]; + List entries = control[sector.FDIndex]; int index = entries.FindLastIndex(e => e is FDPortalEntry || e is FDSlantEntry || e is FDKillLaraEntry || e is FDTriangulationEntry); - control.Entries[sector.FDIndex].Insert(index + 1, climbEntry); + control[sector.FDIndex].Insert(index + 1, climbEntry); } } } diff --git a/TREnvironmentEditor/Model/Types/Surfaces/EMSlantFunction.cs b/TREnvironmentEditor/Model/Types/Surfaces/EMSlantFunction.cs index 2810d083c..3bfc2167a 100644 --- a/TREnvironmentEditor/Model/Types/Surfaces/EMSlantFunction.cs +++ b/TREnvironmentEditor/Model/Types/Surfaces/EMSlantFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl; using TRLevelControl.Model; @@ -19,48 +16,33 @@ public override void ApplyToLevel(TR1Level level) // Apply click changes first base.ApplyToLevel(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (EMLocation location in _locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, location.Room, level, floorData); - UpdateSlantEntry(sector, floorData); + TRRoomSector sector = level.GetRoomSector(location); + UpdateSlantEntry(sector, level.FloorData); } - - floorData.WriteToLevel(level); } public override void ApplyToLevel(TR2Level level) { base.ApplyToLevel(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (EMLocation location in _locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, location.Room, level, floorData); - UpdateSlantEntry(sector, floorData); + TRRoomSector sector = level.GetRoomSector(location); + UpdateSlantEntry(sector, level.FloorData); } - - floorData.WriteToLevel(level); } public override void ApplyToLevel(TR3Level level) { base.ApplyToLevel(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (EMLocation location in _locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, location.Room, level, floorData); - UpdateSlantEntry(sector, floorData); + TRRoomSector sector = level.GetRoomSector(location); + UpdateSlantEntry(sector, level.FloorData); } - - floorData.WriteToLevel(level); } private void UpdateSlantEntry(TRRoomSector sector, FDControl floorData) @@ -82,13 +64,8 @@ private void RemoveSlantEntry(TRRoomSector sector, FDControl floorData) return; } - List entries = floorData.Entries[sector.FDIndex]; + List entries = floorData[sector.FDIndex]; entries.RemoveAll(e => e is FDSlantEntry slant && slant.Type == SlantType); - - if (entries.Count == 0) - { - floorData.RemoveFloorData(sector); - } } private void CreateSlantEntry(TRRoomSector sector, FDControl floorData) @@ -100,7 +77,6 @@ private void CreateSlantEntry(TRRoomSector sector, FDControl floorData) FDSlantEntry newSlant = new() { - Setup = new FDSetup(SlantType == FDSlantType.FloorSlant ? FDFunction.FloorSlant : FDFunction.CeilingSlant), Type = SlantType }; if (XSlant.HasValue) @@ -112,12 +88,12 @@ private void CreateSlantEntry(TRRoomSector sector, FDControl floorData) newSlant.ZSlant = ZSlant.Value; } - List entries = floorData.Entries[sector.FDIndex]; + List entries = floorData[sector.FDIndex]; // Only one slant of each type is supported, and floor must come before ceiling and both before anything else. // For ease, remove any existing slants, then re-add/replace as needed. - FDEntry floorSlant = entries.Find(e => e is FDSlantEntry slant && slant.Type == FDSlantType.FloorSlant); - FDEntry ceilingSlant = entries.Find(e => e is FDSlantEntry slant && slant.Type == FDSlantType.CeilingSlant); + FDEntry floorSlant = entries.Find(e => e is FDSlantEntry slant && slant.Type == FDSlantType.Floor); + FDEntry ceilingSlant = entries.Find(e => e is FDSlantEntry slant && slant.Type == FDSlantType.Ceiling); if (floorSlant != null) { @@ -128,7 +104,7 @@ private void CreateSlantEntry(TRRoomSector sector, FDControl floorData) entries.Remove(ceilingSlant); } - if (SlantType == FDSlantType.FloorSlant) + if (SlantType == FDSlantType.Floor) { floorSlant = newSlant; } diff --git a/TREnvironmentEditor/Model/Types/Textures/EMAddStaticMeshFunction.cs b/TREnvironmentEditor/Model/Types/Textures/EMAddStaticMeshFunction.cs index 5cfb35b3e..8cdcee010 100644 --- a/TREnvironmentEditor/Model/Types/Textures/EMAddStaticMeshFunction.cs +++ b/TREnvironmentEditor/Model/Types/Textures/EMAddStaticMeshFunction.cs @@ -1,6 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -16,24 +14,21 @@ public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - short roomNumber = data.ConvertRoom(location.Room); - TR1Room room = level.Rooms[roomNumber]; + EMLocation position = data.ConvertLocation(location); + TR1Room room = level.Rooms[position.Room]; // Only add this mesh if there is nothing else in the same sector. if (!IgnoreSectorEntities) { bool sectorFree = true; - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, roomNumber, level, control); + TRRoomSector sector = level.GetRoomSector(position); foreach (TR1Entity entity in level.Entities) { - if (entity.Room == roomNumber) + if (entity.Room == position.Room) { - TRRoomSector entitySector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, control); + TRRoomSector entitySector = level.GetRoomSector(entity); if (entitySector == sector) { sectorFree = false; @@ -50,12 +45,12 @@ public override void ApplyToLevel(TR1Level level) room.StaticMeshes.Add(new() { - X = location.X, - Y = location.Y, - Z = location.Z, + X = position.X, + Y = position.Y, + Z = position.Z, Intensity = Intensity, ID = (TR1Type)MeshID, - Angle = location.Angle + Angle = position.Angle }); } } @@ -64,24 +59,21 @@ public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - short roomNumber = data.ConvertRoom(location.Room); - TR2Room room = level.Rooms[roomNumber]; + EMLocation position = data.ConvertLocation(location); + TR2Room room = level.Rooms[position.Room]; // Only add this mesh if there is nothing else in the same sector. if (!IgnoreSectorEntities) { bool sectorFree = true; - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, roomNumber, level, control); + TRRoomSector sector = level.GetRoomSector(position); foreach (TR2Entity entity in level.Entities) { - if (entity.Room == roomNumber) + if (entity.Room == position.Room) { - TRRoomSector entitySector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, control); + TRRoomSector entitySector = level.GetRoomSector(entity); if (entitySector == sector) { sectorFree = false; @@ -98,13 +90,13 @@ public override void ApplyToLevel(TR2Level level) room.StaticMeshes.Add(new() { - X = location.X, - Y = location.Y, - Z = location.Z, + X = position.X, + Y = position.Y, + Z = position.Z, Intensity1 = Intensity, Intensity2 = Intensity, ID = (TR2Type)MeshID, - Angle = location.Angle + Angle = position.Angle }); } } @@ -113,24 +105,21 @@ public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - short roomNumber = data.ConvertRoom(location.Room); - TR3Room room = level.Rooms[roomNumber]; + EMLocation position = data.ConvertLocation(location); + TR3Room room = level.Rooms[position.Room]; // Only add this mesh if there is nothing else in the same sector. if (!IgnoreSectorEntities) { bool sectorFree = true; - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, roomNumber, level, control); + TRRoomSector sector = level.GetRoomSector(position); foreach (TR3Entity entity in level.Entities) { - if (entity.Room == roomNumber) + if (entity.Room == position.Room) { - TRRoomSector entitySector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, control); + TRRoomSector entitySector = level.GetRoomSector(entity); if (entitySector == sector) { sectorFree = false; @@ -147,12 +136,12 @@ public override void ApplyToLevel(TR3Level level) room.StaticMeshes.Add(new() { - X = location.X, - Y = location.Y, - Z = location.Z, + X = position.X, + Y = position.Y, + Z = position.Z, Colour = Intensity, ID = (TR3Type)MeshID, - Angle = location.Angle + Angle = position.Angle }); } } diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMAppendTriggerActionFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMAppendTriggerActionFunction.cs index 825e7a1e0..03ae092ba 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMAppendTriggerActionFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMAppendTriggerActionFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -21,16 +18,11 @@ public override void ApplyToLevel(TR1Level level) List actions = InitialiseActionItems(data); List locations = InitialiseLocations(level.Entities, data); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (EMLocation location in locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, floorData); - AppendActions(sector, floorData, actions); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + AppendActions(sector, level.FloorData, actions); } - - floorData.WriteToLevel(level); } public override void ApplyToLevel(TR2Level level) @@ -39,16 +31,11 @@ public override void ApplyToLevel(TR2Level level) List actions = InitialiseActionItems(data); List locations = InitialiseLocations(level.Entities, data); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (EMLocation location in locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, floorData); - AppendActions(sector, floorData, actions); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + AppendActions(sector, level.FloorData, actions); } - - floorData.WriteToLevel(level); } public override void ApplyToLevel(TR3Level level) @@ -57,16 +44,11 @@ public override void ApplyToLevel(TR3Level level) List actions = InitialiseActionItems(data); List locations = InitialiseLocations(level.Entities, data); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (EMLocation location in locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, floorData); - AppendActions(sector, floorData, actions); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + AppendActions(sector, level.FloorData, actions); } - - floorData.WriteToLevel(level); } private List InitialiseLocations(List entities, EMLevelData data) @@ -113,14 +95,14 @@ private List InitialiseActionItems(EMLevelData data) private void AppendActions(TRRoomSector sector, FDControl floorData, List actions) { - if (sector.FDIndex != 0 && floorData.Entries[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger + if (sector.FDIndex != 0 && floorData[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger && (TargetTypes == null || TargetTypes.Contains(trigger.TrigType))) { foreach (FDActionItem item in actions) { - if (!trigger.TrigActionList.Any(a => a.TrigAction == item.TrigAction && a.Parameter == item.Parameter)) + if (!trigger.Actions.Any(a => a.Action == item.Action && a.Parameter == item.Parameter)) { - trigger.TrigActionList.Add(item); + trigger.Actions.Add(item); } } } diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMCameraTriggerFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMCameraTriggerFunction.cs index c554214b5..6b7a945d2 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMCameraTriggerFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMCameraTriggerFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -24,27 +21,24 @@ public EMCameraTriggerFunction() public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - ushort cameraIndex; + short cameraIndex; if (Camera != null) { - cameraIndex = (ushort)level.Cameras.Count; + cameraIndex = (short)level.Cameras.Count; level.Cameras.Add(CreateCamera(data)); } else { - cameraIndex = (ushort)data.ConvertCamera(CameraIndex); + cameraIndex = data.ConvertCamera(CameraIndex); } - FDControl control = new(); - control.ParseFromLevel(level); - if (AttachToItems != null) { foreach (int item in AttachToItems) { TR1Entity attachToEntity = level.Entities[data.ConvertEntity(item)]; - TRRoomSector sector = FDUtilities.GetRoomSector(attachToEntity.X, attachToEntity.Y, attachToEntity.Z, data.ConvertRoom(attachToEntity.Room), level, control); - AttachToSector(sector, control, cameraIndex, data); + TRRoomSector sector = level.GetRoomSector(attachToEntity.X, attachToEntity.Y, attachToEntity.Z, data.ConvertRoom(attachToEntity.Room)); + AttachToSector(sector, level.FloorData, cameraIndex, data); } } @@ -52,8 +46,8 @@ public override void ApplyToLevel(TR1Level level) { foreach (EMLocation location in AttachToLocations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - AttachToSector(sector, control, cameraIndex, data); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + AttachToSector(sector, level.FloorData, cameraIndex, data); } } @@ -63,38 +57,33 @@ public override void ApplyToLevel(TR1Level level) { foreach (TRRoomSector sector in level.Rooms[data.ConvertRoom(room)].Sectors) { - AttachToSector(sector, control, cameraIndex, data); + AttachToSector(sector, level.FloorData, cameraIndex, data); } } } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - ushort cameraIndex; + short cameraIndex; if (Camera != null) { - cameraIndex = (ushort)level.Cameras.Count; + cameraIndex = (short)level.Cameras.Count; level.Cameras.Add(CreateCamera(data)); } else { - cameraIndex = (ushort)data.ConvertCamera(CameraIndex); + cameraIndex = data.ConvertCamera(CameraIndex); } - FDControl control = new(); - control.ParseFromLevel(level); - if (AttachToItems != null) { foreach (int item in AttachToItems) { TR2Entity attachToEntity = level.Entities[data.ConvertEntity(item)]; - TRRoomSector sector = FDUtilities.GetRoomSector(attachToEntity.X, attachToEntity.Y, attachToEntity.Z, data.ConvertRoom(attachToEntity.Room), level, control); - AttachToSector(sector, control, cameraIndex, data); + TRRoomSector sector = level.GetRoomSector(attachToEntity.X, attachToEntity.Y, attachToEntity.Z, data.ConvertRoom(attachToEntity.Room)); + AttachToSector(sector, level.FloorData, cameraIndex, data); } } @@ -102,8 +91,8 @@ public override void ApplyToLevel(TR2Level level) { foreach (EMLocation location in AttachToLocations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - AttachToSector(sector, control, cameraIndex, data); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + AttachToSector(sector, level.FloorData, cameraIndex, data); } } @@ -113,38 +102,33 @@ public override void ApplyToLevel(TR2Level level) { foreach (TRRoomSector sector in level.Rooms[data.ConvertRoom(room)].Sectors) { - AttachToSector(sector, control, cameraIndex, data); + AttachToSector(sector, level.FloorData, cameraIndex, data); } } } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - ushort cameraIndex; + short cameraIndex; if (Camera != null) { - cameraIndex = (ushort)level.Cameras.Count; + cameraIndex = (short)level.Cameras.Count; level.Cameras.Add(CreateCamera(data)); } else { - cameraIndex = (ushort)data.ConvertCamera(CameraIndex); + cameraIndex = data.ConvertCamera(CameraIndex); } - FDControl control = new(); - control.ParseFromLevel(level); - if (AttachToItems != null) { foreach (int item in AttachToItems) { TR3Entity attachToEntity = level.Entities[data.ConvertEntity(item)]; - TRRoomSector sector = FDUtilities.GetRoomSector(attachToEntity.X, attachToEntity.Y, attachToEntity.Z, data.ConvertRoom(attachToEntity.Room), level, control); - AttachToSector(sector, control, cameraIndex, data); + TRRoomSector sector = level.GetRoomSector(attachToEntity.X, attachToEntity.Y, attachToEntity.Z, data.ConvertRoom(attachToEntity.Room)); + AttachToSector(sector, level.FloorData, cameraIndex, data); } } @@ -152,8 +136,8 @@ public override void ApplyToLevel(TR3Level level) { foreach (EMLocation location in AttachToLocations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - AttachToSector(sector, control, cameraIndex, data); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + AttachToSector(sector, level.FloorData, cameraIndex, data); } } @@ -163,17 +147,15 @@ public override void ApplyToLevel(TR3Level level) { foreach (TRRoomSector sector in level.Rooms[data.ConvertRoom(room)].Sectors) { - AttachToSector(sector, control, cameraIndex, data); + AttachToSector(sector, level.FloorData, cameraIndex, data); } } } - - control.WriteToLevel(level); } private TRCamera CreateCamera(EMLevelData data) { - return new TRCamera + return new() { X = Camera.X, Y = Camera.Y, @@ -183,28 +165,26 @@ private TRCamera CreateCamera(EMLevelData data) }; } - private void AttachToSector(TRRoomSector sector, FDControl control, ushort cameraIndex, EMLevelData data) + private void AttachToSector(TRRoomSector sector, FDControl control, short cameraIndex, EMLevelData data) { if (sector.FDIndex != 0) { - if (control.Entries[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger + if (control[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger && trigger.TrigType != FDTrigType.Dummy) { - trigger.TrigActionList.Add(new FDActionItem + trigger.Actions.Add(new FDActionItem { - TrigAction = FDTrigAction.Camera, - Value = 1024, + Action = FDTrigAction.Camera, CamAction = CameraAction, Parameter = cameraIndex }); if (LookAtItem != ushort.MaxValue) { - trigger.TrigActionList.Add(new FDActionItem + trigger.Actions.Add(new FDActionItem { - TrigAction = FDTrigAction.LookAtItem, - Value = 6158, - Parameter = (ushort)data.ConvertEntity(LookAtItem) + Action = FDTrigAction.LookAtItem, + Parameter = data.ConvertEntity(LookAtItem) }); } } diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMConvertTriggerFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMConvertTriggerFunction.cs index 6095903e1..3c7270855 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMConvertTriggerFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMConvertTriggerFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -21,16 +18,11 @@ public override void ApplyToLevel(TR1Level level) EMLevelData data = GetData(level); InitialiseLocations(); - FDControl control = new(); - control.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - ConvertTrigger(sector, control, data); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + ConvertTrigger(sector, level.FloorData, data); } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR2Level level) @@ -38,16 +30,11 @@ public override void ApplyToLevel(TR2Level level) EMLevelData data = GetData(level); InitialiseLocations(); - FDControl control = new(); - control.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - ConvertTrigger(sector, control, data); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + ConvertTrigger(sector, level.FloorData, data); } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR3Level level) @@ -55,16 +42,11 @@ public override void ApplyToLevel(TR3Level level) EMLevelData data = GetData(level); InitialiseLocations(); - FDControl control = new(); - control.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - ConvertTrigger(sector, control, data); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + ConvertTrigger(sector, level.FloorData, data); } - - control.WriteToLevel(level); } private void InitialiseLocations() @@ -81,34 +63,34 @@ private void ConvertTrigger(TRRoomSector sector, FDControl floorData, EMLevelDat { if (sector.FDIndex != 0) { - IEnumerable triggers = floorData.Entries[sector.FDIndex].FindAll(e => e is FDTriggerEntry).Cast(); + IEnumerable triggers = floorData[sector.FDIndex].FindAll(e => e is FDTriggerEntry).Cast(); foreach (FDTriggerEntry trigger in triggers) { if (TrigType.HasValue) { - if (trigger.TrigType == FDTrigType.Pickup && TrigType.Value != FDTrigType.Pickup && trigger.TrigActionList.Count > 0) + if (trigger.TrigType == FDTrigType.Pickup && TrigType.Value != FDTrigType.Pickup && trigger.Actions.Count > 0) { // The first action entry for pickup triggers is the pickup reference itself, so // this is no longer needed. - trigger.TrigActionList.RemoveAt(0); + trigger.Actions.RemoveAt(0); } trigger.TrigType = TrigType.Value; } if (OneShot.HasValue) { - trigger.TrigSetup.OneShot = OneShot.Value; + trigger.OneShot = OneShot.Value; } if (SwitchOrKeyRef.HasValue) { - trigger.SwitchOrKeyRef = (ushort)data.ConvertEntity(SwitchOrKeyRef.Value); + trigger.SwitchOrKeyRef = data.ConvertEntity(SwitchOrKeyRef.Value); } if (Mask.HasValue) { - trigger.TrigSetup.Mask = Mask.Value; + trigger.Mask = Mask.Value; } if (Timer.HasValue) { - trigger.TrigSetup.Timer = Timer.Value; + trigger.Timer = Timer.Value; } } } diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMDuplicateSwitchTriggerFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMDuplicateSwitchTriggerFunction.cs index 8cd866d22..90d948292 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMDuplicateSwitchTriggerFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMDuplicateSwitchTriggerFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -21,15 +18,8 @@ public override void ApplyToLevel(TR1Level level) base.ApplyToLevel(level); // Go one step further and replace the duplicated trigger with the new switch ref - FDControl control = new(); - control.ParseFromLevel(level); - - UpdateTriggers(data, control, delegate (EMLocation location) - { - return FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - }); - - control.WriteToLevel(level); + UpdateTriggers(data, level.FloorData, location => + level.GetRoomSector(data.ConvertLocation(location))); } public override void ApplyToLevel(TR2Level level) @@ -38,19 +28,10 @@ public override void ApplyToLevel(TR2Level level) SetupLocations(data, level.Entities); - // Duplicate the triggers to the switch's location base.ApplyToLevel(level); - // Go one step further and replace the duplicated trigger with the new switch ref - FDControl control = new(); - control.ParseFromLevel(level); - - UpdateTriggers(data, control, delegate (EMLocation location) - { - return FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - }); - - control.WriteToLevel(level); + UpdateTriggers(data, level.FloorData, location => + level.GetRoomSector(data.ConvertLocation(location))); } public override void ApplyToLevel(TR3Level level) @@ -61,15 +42,8 @@ public override void ApplyToLevel(TR3Level level) base.ApplyToLevel(level); - FDControl control = new(); - control.ParseFromLevel(level); - - UpdateTriggers(data, control, delegate (EMLocation location) - { - return FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - }); - - control.WriteToLevel(level); + UpdateTriggers(data, level.FloorData, location => + level.GetRoomSector(data.ConvertLocation(location))); } private void SetupLocations(EMLevelData data, List entities) @@ -149,12 +123,12 @@ private void SetupLocations(EMLevelData data, List entities) private void UpdateTriggers(EMLevelData data, FDControl control, Func sectorGetter) { - ushort newSwitchIndex = (ushort)data.ConvertEntity(NewSwitchIndex); + short newSwitchIndex = data.ConvertEntity(NewSwitchIndex); foreach (EMLocation location in Locations) { TRRoomSector baseSector = sectorGetter.Invoke(location); - List keyTriggers = control.Entries[baseSector.FDIndex].FindAll(e => e is FDTriggerEntry); + List keyTriggers = control[baseSector.FDIndex].FindAll(e => e is FDTriggerEntry); foreach (FDEntry entry in keyTriggers) { (entry as FDTriggerEntry).SwitchOrKeyRef = newSwitchIndex; diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMDuplicateTriggerFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMDuplicateTriggerFunction.cs index 1d40b1648..4bb91db60 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMDuplicateTriggerFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMDuplicateTriggerFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -15,16 +12,13 @@ public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); - - TRRoomSector baseSector = FDUtilities.GetRoomSector(BaseLocation.X, BaseLocation.Y, BaseLocation.Z, data.ConvertRoom(BaseLocation.Room), level, control); + TRRoomSector baseSector = level.GetRoomSector(data.ConvertLocation(BaseLocation)); if (baseSector.FDIndex == 0) { return; } - List triggerEntries = control.Entries[baseSector.FDIndex].FindAll(e => e is FDTriggerEntry); + List triggerEntries = level.FloorData[baseSector.FDIndex].FindAll(e => e is FDTriggerEntry); if (triggerEntries.Count == 0) { return; @@ -32,27 +26,22 @@ public override void ApplyToLevel(TR1Level level) foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - AppendTriggers(sector, triggerEntries, control); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + AppendTriggers(sector, triggerEntries, level.FloorData); } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); - - TRRoomSector baseSector = FDUtilities.GetRoomSector(BaseLocation.X, BaseLocation.Y, BaseLocation.Z, data.ConvertRoom(BaseLocation.Room), level, control); + TRRoomSector baseSector = level.GetRoomSector(data.ConvertLocation(BaseLocation)); if (baseSector.FDIndex == 0) { return; } - List triggerEntries = control.Entries[baseSector.FDIndex].FindAll(e => e is FDTriggerEntry); + List triggerEntries = level.FloorData[baseSector.FDIndex].FindAll(e => e is FDTriggerEntry); if (triggerEntries.Count == 0) { return; @@ -60,27 +49,22 @@ public override void ApplyToLevel(TR2Level level) foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - AppendTriggers(sector, triggerEntries, control); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + AppendTriggers(sector, triggerEntries, level.FloorData); } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); - - TRRoomSector baseSector = FDUtilities.GetRoomSector(BaseLocation.X, BaseLocation.Y, BaseLocation.Z, data.ConvertRoom(BaseLocation.Room), level, control); + TRRoomSector baseSector = level.GetRoomSector(data.ConvertLocation(BaseLocation)); if (baseSector.FDIndex == 0) { return; } - List triggerEntries = control.Entries[baseSector.FDIndex].FindAll(e => e is FDTriggerEntry); + List triggerEntries = level.FloorData[baseSector.FDIndex].FindAll(e => e is FDTriggerEntry); if (triggerEntries.Count == 0) { return; @@ -88,11 +72,9 @@ public override void ApplyToLevel(TR3Level level) foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - AppendTriggers(sector, triggerEntries, control); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + AppendTriggers(sector, triggerEntries, level.FloorData); } - - control.WriteToLevel(level); } private static void AppendTriggers(TRRoomSector sector, List triggerEntries, FDControl control) @@ -102,7 +84,7 @@ private static void AppendTriggers(TRRoomSector sector, List triggerEnt control.CreateFloorData(sector); } - List entries = control.Entries[sector.FDIndex]; + List entries = control[sector.FDIndex]; if (entries.FindIndex(e => e is FDTriggerEntry) == -1) { entries.AddRange(triggerEntries); diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMKillLaraFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMKillLaraFunction.cs index 9de2a0ff6..ca2c58a85 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMKillLaraFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMKillLaraFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -14,48 +11,33 @@ public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - CreateTrigger(sector, control); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + CreateTrigger(sector, level.FloorData); } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - CreateTrigger(sector, control); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + CreateTrigger(sector, level.FloorData); } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - CreateTrigger(sector, control); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + CreateTrigger(sector, level.FloorData); } - - control.WriteToLevel(level); } private static void CreateTrigger(TRRoomSector sector, FDControl control) @@ -66,13 +48,10 @@ private static void CreateTrigger(TRRoomSector sector, FDControl control) control.CreateFloorData(sector); } - List entries = control.Entries[sector.FDIndex]; + List entries = control[sector.FDIndex]; if (entries.FindIndex(e => e is FDKillLaraEntry) == -1) { - entries.Add(new FDKillLaraEntry - { - Setup = new FDSetup(FDFunction.KillLara) - }); + entries.Add(new FDKillLaraEntry()); } } } diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMMergeTriggersFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMMergeTriggersFunction.cs index a7e4ec0c1..324852a6a 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMMergeTriggersFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMMergeTriggersFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -14,43 +11,25 @@ public class EMMergeTriggersFunction : BaseEMFunction public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - - MergeTriggers( - FDUtilities.GetRoomSector(BaseLocation.X, BaseLocation.Y, BaseLocation.Z, data.ConvertRoom(BaseLocation.Room), level, floorData), - FDUtilities.GetRoomSector(TargetLocation.X, TargetLocation.Y, TargetLocation.Z, data.ConvertRoom(TargetLocation.Room), level, floorData), - floorData); - - floorData.WriteToLevel(level); + MergeTriggers(level.GetRoomSector(data.ConvertLocation(BaseLocation)), + level.GetRoomSector(data.ConvertLocation(TargetLocation)), + level.FloorData); } public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - - MergeTriggers( - FDUtilities.GetRoomSector(BaseLocation.X, BaseLocation.Y, BaseLocation.Z, data.ConvertRoom(BaseLocation.Room), level, floorData), - FDUtilities.GetRoomSector(TargetLocation.X, TargetLocation.Y, TargetLocation.Z, data.ConvertRoom(TargetLocation.Room), level, floorData), - floorData); - - floorData.WriteToLevel(level); + MergeTriggers(level.GetRoomSector(data.ConvertLocation(BaseLocation)), + level.GetRoomSector(data.ConvertLocation(TargetLocation)), + level.FloorData); } public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - - MergeTriggers( - FDUtilities.GetRoomSector(BaseLocation.X, BaseLocation.Y, BaseLocation.Z, data.ConvertRoom(BaseLocation.Room), level, floorData), - FDUtilities.GetRoomSector(TargetLocation.X, TargetLocation.Y, TargetLocation.Z, data.ConvertRoom(TargetLocation.Room), level, floorData), - floorData); - - floorData.WriteToLevel(level); + MergeTriggers(level.GetRoomSector(data.ConvertLocation(BaseLocation)), + level.GetRoomSector(data.ConvertLocation(TargetLocation)), + level.FloorData); } private static void MergeTriggers(TRRoomSector baseSector, TRRoomSector targetSector, FDControl floorData) @@ -58,7 +37,7 @@ private static void MergeTriggers(TRRoomSector baseSector, TRRoomSector targetSe FDEntry baseEntry; if (baseSector.FDIndex == 0 || baseSector == targetSector - || (baseEntry = floorData.Entries[baseSector.FDIndex].Find(e => e is FDTriggerEntry)) == null) + || (baseEntry = floorData[baseSector.FDIndex].Find(e => e is FDTriggerEntry)) == null) { return; } @@ -68,27 +47,23 @@ private static void MergeTriggers(TRRoomSector baseSector, TRRoomSector targetSe floorData.CreateFloorData(targetSector); } - FDEntry targetEntry = floorData.Entries[targetSector.FDIndex].Find(e => e is FDTriggerEntry); + FDEntry targetEntry = floorData[targetSector.FDIndex].Find(e => e is FDTriggerEntry); if (targetEntry == null) { - floorData.Entries[targetSector.FDIndex].Add(baseEntry); + floorData[targetSector.FDIndex].Add(baseEntry); } else { FDTriggerEntry baseTrigger = baseEntry as FDTriggerEntry; FDTriggerEntry targetTrigger = targetEntry as FDTriggerEntry; - targetTrigger.TrigActionList.AddRange(baseTrigger.TrigActionList); - if (baseTrigger.TrigSetup.OneShot) + targetTrigger.Actions.AddRange(baseTrigger.Actions); + if (baseTrigger.OneShot) { - targetTrigger.TrigSetup.OneShot = true; + targetTrigger.OneShot = true; } } - floorData.Entries[baseSector.FDIndex].Remove(baseEntry); - if (floorData.Entries[baseSector.FDIndex].Count == 0) - { - floorData.RemoveFloorData(baseSector); - } + floorData[baseSector.FDIndex].Remove(baseEntry); } } diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMMoveTriggerFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMMoveTriggerFunction.cs index af3c13a95..437a101f6 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMMoveTriggerFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMMoveTriggerFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -15,11 +12,7 @@ public class EMMoveTriggerFunction : BaseEMFunction public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - - FDControl control = new(); - control.ParseFromLevel(level); - - TRRoomSector baseSector = FDUtilities.GetRoomSector(BaseLocation.X, BaseLocation.Y, BaseLocation.Z, data.ConvertRoom(BaseLocation.Room), level, control); + TRRoomSector baseSector = level.GetRoomSector(data.ConvertLocation(BaseLocation)); if (NewLocation != null) { @@ -28,7 +21,7 @@ public override void ApplyToLevel(TR1Level level) else if (EntityLocation.HasValue) { TR1Entity entity = level.Entities[data.ConvertEntity(EntityLocation.Value)]; - NewLocation = new EMLocation + NewLocation = new() { X = entity.X, Y = entity.Y, @@ -41,11 +34,9 @@ public override void ApplyToLevel(TR1Level level) throw new InvalidOperationException("No means to determine new sector for moving trigger."); } - TRRoomSector newSector = FDUtilities.GetRoomSector(NewLocation.X, NewLocation.Y, NewLocation.Z, NewLocation.Room, level, control); - if (MoveTriggers(baseSector, newSector, control)) + TRRoomSector newSector = level.GetRoomSector(NewLocation); + if (MoveTriggers(baseSector, newSector, level.FloorData)) { - control.WriteToLevel(level); - // Make sure to copy the trigger into the flipped room if applicable short altRoom = level.Rooms[NewLocation.Room].AlternateRoom; if (altRoom != -1) @@ -58,11 +49,7 @@ public override void ApplyToLevel(TR1Level level) public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - - FDControl control = new(); - control.ParseFromLevel(level); - - TRRoomSector baseSector = FDUtilities.GetRoomSector(BaseLocation.X, BaseLocation.Y, BaseLocation.Z, data.ConvertRoom(BaseLocation.Room), level, control); + TRRoomSector baseSector = level.GetRoomSector(data.ConvertLocation(BaseLocation)); if (NewLocation != null) { @@ -71,7 +58,7 @@ public override void ApplyToLevel(TR2Level level) else if (EntityLocation.HasValue) { TR2Entity entity = level.Entities[data.ConvertEntity(EntityLocation.Value)]; - NewLocation = new EMLocation + NewLocation = new() { X = entity.X, Y = entity.Y, @@ -84,11 +71,9 @@ public override void ApplyToLevel(TR2Level level) throw new InvalidOperationException("No means to determine new sector for moving trigger."); } - TRRoomSector newSector = FDUtilities.GetRoomSector(NewLocation.X, NewLocation.Y, NewLocation.Z, NewLocation.Room, level, control); - if (MoveTriggers(baseSector, newSector, control)) + TRRoomSector newSector = level.GetRoomSector(NewLocation); + if (MoveTriggers(baseSector, newSector, level.FloorData)) { - control.WriteToLevel(level); - // Make sure to copy the trigger into the flipped room if applicable short altRoom = level.Rooms[NewLocation.Room].AlternateRoom; if (altRoom != -1) @@ -101,11 +86,7 @@ public override void ApplyToLevel(TR2Level level) public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - - FDControl control = new(); - control.ParseFromLevel(level); - - TRRoomSector baseSector = FDUtilities.GetRoomSector(BaseLocation.X, BaseLocation.Y, BaseLocation.Z, data.ConvertRoom(BaseLocation.Room), level, control); + TRRoomSector baseSector = level.GetRoomSector(data.ConvertLocation(BaseLocation)); if (NewLocation != null) { @@ -114,7 +95,7 @@ public override void ApplyToLevel(TR3Level level) else if (EntityLocation.HasValue) { TR3Entity entity = level.Entities[data.ConvertEntity(EntityLocation.Value)]; - NewLocation = new EMLocation + NewLocation = new() { X = entity.X, Y = entity.Y, @@ -127,11 +108,9 @@ public override void ApplyToLevel(TR3Level level) throw new InvalidOperationException("No means to determine new sector for moving trigger."); } - TRRoomSector newSector = FDUtilities.GetRoomSector(NewLocation.X, NewLocation.Y, NewLocation.Z, NewLocation.Room, level, control); - if (MoveTriggers(baseSector, newSector, control)) + TRRoomSector newSector = level.GetRoomSector(NewLocation); + if (MoveTriggers(baseSector, newSector, level.FloorData)) { - control.WriteToLevel(level); - // Make sure to copy the trigger into the flipped room if applicable short altRoom = level.Rooms[NewLocation.Room].AlternateRoom; if (altRoom != -1) @@ -145,7 +124,7 @@ private static bool MoveTriggers(TRRoomSector baseSector, TRRoomSector newSector { if (baseSector != newSector && baseSector.FDIndex != 0) { - List triggers = control.Entries[baseSector.FDIndex].FindAll(e => e is FDTriggerEntry); + List triggers = control[baseSector.FDIndex].FindAll(e => e is FDTriggerEntry); if (triggers.Count > 0) { if (newSector.FDIndex == 0) @@ -153,13 +132,8 @@ private static bool MoveTriggers(TRRoomSector baseSector, TRRoomSector newSector control.CreateFloorData(newSector); } - control.Entries[newSector.FDIndex].AddRange(triggers); - - control.Entries[baseSector.FDIndex].RemoveAll(e => triggers.Contains(e)); - if (control.Entries[baseSector.FDIndex].Count == 0) - { - control.RemoveFloorData(baseSector); - } + control[newSector.FDIndex].AddRange(triggers); + control[baseSector.FDIndex].RemoveAll(e => triggers.Contains(e)); return true; } @@ -172,12 +146,13 @@ private EMDuplicateTriggerFunction CreateFlipmapTriggerFunction(short altRoom) { // We want the trigger that's in the new target location added to the same // position in the flipped room. - return new EMDuplicateTriggerFunction + return new() { BaseLocation = NewLocation, - Locations = new List + Locations = new() { - new() { + new() + { X = NewLocation.X, Y = NewLocation.Y, Z = NewLocation.Z, diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMRemoveEntityTriggersFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMRemoveEntityTriggersFunction.cs index 1b1055818..319eb01d3 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMRemoveEntityTriggersFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMRemoveEntityTriggersFunction.cs @@ -1,6 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; using TRLevelControl.Model; namespace TREnvironmentEditor.Model; @@ -16,15 +14,10 @@ public override void ApplyToLevel(TR1Level level) List entities = GetEntities(data); List excludedTypes = GetExcludedTypes(); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (TR1Room room in level.Rooms) { - RemoveSectorTriggers(floorData, room.Sectors, entities, excludedTypes); + RemoveSectorTriggers(level.FloorData, room.Sectors, entities, excludedTypes); } - - floorData.WriteToLevel(level); } public override void ApplyToLevel(TR2Level level) @@ -33,15 +26,10 @@ public override void ApplyToLevel(TR2Level level) List entities = GetEntities(data); List excludedTypes = GetExcludedTypes(); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (TR2Room room in level.Rooms) { - RemoveSectorTriggers(floorData, room.Sectors, entities, excludedTypes); + RemoveSectorTriggers(level.FloorData, room.Sectors, entities, excludedTypes); } - - floorData.WriteToLevel(level); } public override void ApplyToLevel(TR3Level level) @@ -50,15 +38,10 @@ public override void ApplyToLevel(TR3Level level) List entities = GetEntities(data); List excludedTypes = GetExcludedTypes(); - FDControl floorData = new(); - floorData.ParseFromLevel(level); - foreach (TR3Room room in level.Rooms) { - RemoveSectorTriggers(floorData, room.Sectors, entities, excludedTypes); + RemoveSectorTriggers(level.FloorData, room.Sectors, entities, excludedTypes); } - - floorData.WriteToLevel(level); } private List GetEntities(EMLevelData data) @@ -90,21 +73,16 @@ private static void RemoveSectorTriggers(FDControl floorData, IEnumerable entries = floorData.Entries[sector.FDIndex]; + List entries = floorData[sector.FDIndex]; // Find any trigger that isn't a type we wish to exclude if (entries.Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger && !excludedTypes.Contains(trigger.TrigType)) { - trigger.TrigActionList.RemoveAll(a => a.TrigAction == FDTrigAction.Object && entities.Contains(a.Parameter)); - if (trigger.TrigActionList.Count == 0) + trigger.Actions.RemoveAll(a => a.Action == FDTrigAction.Object && entities.Contains(a.Parameter)); + if (trigger.Actions.Count == 0) { entries.Remove(trigger); } - - if (entries.Count == 0) - { - floorData.RemoveFloorData(sector); - } } } } diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMRemoveTriggerActionFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMRemoveTriggerActionFunction.cs index e26587344..f2cd0ea95 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMRemoveTriggerActionFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMRemoveTriggerActionFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -16,16 +13,11 @@ public override void ApplyToLevel(TR1Level level) EMLevelData data = GetData(level); FDActionItem action = InitialiseActionItem(data); - FDControl control = new(); - control.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - TRRoomSector baseSector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - RemoveAction(baseSector, control, action); + TRRoomSector baseSector = level.GetRoomSector(data.ConvertLocation(location)); + RemoveAction(baseSector, level.FloorData, action); } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR2Level level) @@ -33,16 +25,11 @@ public override void ApplyToLevel(TR2Level level) EMLevelData data = GetData(level); FDActionItem action = InitialiseActionItem(data); - FDControl control = new(); - control.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - TRRoomSector baseSector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - RemoveAction(baseSector, control, action); + TRRoomSector baseSector = level.GetRoomSector(data.ConvertLocation(location)); + RemoveAction(baseSector, level.FloorData, action); } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR3Level level) @@ -50,16 +37,11 @@ public override void ApplyToLevel(TR3Level level) EMLevelData data = GetData(level); FDActionItem action = InitialiseActionItem(data); - FDControl control = new(); - control.ParseFromLevel(level); - foreach (EMLocation location in Locations) { - TRRoomSector baseSector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - RemoveAction(baseSector, control, action); + TRRoomSector baseSector = level.GetRoomSector(data.ConvertLocation(location)); + RemoveAction(baseSector, level.FloorData, action); } - - control.WriteToLevel(level); } private FDActionItem InitialiseActionItem(EMLevelData data) @@ -74,10 +56,10 @@ private static void RemoveAction(TRRoomSector sector, FDControl control, FDActio return; } - List entries = control.Entries[sector.FDIndex].FindAll(e => e is FDTriggerEntry); + List entries = control[sector.FDIndex].FindAll(e => e is FDTriggerEntry); foreach (FDEntry entry in entries) { - (entry as FDTriggerEntry).TrigActionList.RemoveAll(a => a.TrigAction == action.TrigAction && a.Parameter == action.Parameter); + (entry as FDTriggerEntry).Actions.RemoveAll(a => a.Action == action.Action && a.Parameter == action.Parameter); } } } diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMRemoveTriggerFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMRemoveTriggerFunction.cs index bb489f9e6..88d1fdbaf 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMRemoveTriggerFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMRemoveTriggerFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -16,15 +13,12 @@ public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); - if (Locations != null) { foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - RemoveSectorTriggers(sector, control); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + RemoveSectorTriggers(sector, level.FloorData); } } @@ -32,26 +26,21 @@ public override void ApplyToLevel(TR1Level level) { foreach (int roomNumber in Rooms) { - RemoveSectorListTriggers(level.Rooms[data.ConvertRoom(roomNumber)].Sectors, control); + RemoveSectorListTriggers(level.Rooms[data.ConvertRoom(roomNumber)].Sectors, level.FloorData); } } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); - if (Locations != null) { foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - RemoveSectorTriggers(sector, control); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + RemoveSectorTriggers(sector, level.FloorData); } } @@ -59,26 +48,21 @@ public override void ApplyToLevel(TR2Level level) { foreach (int roomNumber in Rooms) { - RemoveSectorListTriggers(level.Rooms[data.ConvertRoom(roomNumber)].Sectors, control); + RemoveSectorListTriggers(level.Rooms[data.ConvertRoom(roomNumber)].Sectors, level.FloorData); } } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - FDControl control = new(); - control.ParseFromLevel(level); - if (Locations != null) { foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - RemoveSectorTriggers(sector, control); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + RemoveSectorTriggers(sector, level.FloorData); } } @@ -86,11 +70,9 @@ public override void ApplyToLevel(TR3Level level) { foreach (int roomNumber in Rooms) { - RemoveSectorListTriggers(level.Rooms[data.ConvertRoom(roomNumber)].Sectors, control); + RemoveSectorListTriggers(level.Rooms[data.ConvertRoom(roomNumber)].Sectors, level.FloorData); } } - - control.WriteToLevel(level); } private void RemoveSectorListTriggers(IEnumerable sectors, FDControl control) @@ -108,12 +90,7 @@ private void RemoveSectorTriggers(TRRoomSector sector, FDControl control) return; } - List entries = control.Entries[sector.FDIndex]; + List entries = control[sector.FDIndex]; entries.RemoveAll(e => e is FDTriggerEntry trig && (TrigTypes?.Contains(trig.TrigType) ?? true)); - if (entries.Count == 0) - { - // If there isn't anything left, reset the sector to point to the dummy FD - control.RemoveFloorData(sector); - } } } diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMReplaceTriggerActionParameterFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMReplaceTriggerActionParameterFunction.cs index 7aa009979..20822d19d 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMReplaceTriggerActionParameterFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMReplaceTriggerActionParameterFunction.cs @@ -1,6 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -16,15 +14,12 @@ public override void ApplyToLevel(TR1Level level) EMLevelData data = GetData(level); FDActionItem action = InitialiseActionItem(data); - FDControl control = new(); - control.ParseFromLevel(level); - if (Locations != null) { foreach (EMLocation location in Locations) { - TRRoomSector baseSector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - ReplaceActionParameter(baseSector, control, action); + TRRoomSector baseSector = level.GetRoomSector(data.ConvertLocation(location)); + ReplaceActionParameter(baseSector, level.FloorData, action); } } if (EntityLocations != null) @@ -32,12 +27,10 @@ public override void ApplyToLevel(TR1Level level) foreach (int entityIndex in EntityLocations) { TR1Entity entity = level.Entities[data.ConvertEntity(entityIndex)]; - TRRoomSector baseSector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, control); - ReplaceActionParameter(baseSector, control, action); + TRRoomSector baseSector = level.GetRoomSector(entity); + ReplaceActionParameter(baseSector, level.FloorData, action); } } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR2Level level) @@ -45,15 +38,12 @@ public override void ApplyToLevel(TR2Level level) EMLevelData data = GetData(level); FDActionItem action = InitialiseActionItem(data); - FDControl control = new(); - control.ParseFromLevel(level); - if (Locations != null) { foreach (EMLocation location in Locations) { - TRRoomSector baseSector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - ReplaceActionParameter(baseSector, control, action); + TRRoomSector baseSector = level.GetRoomSector(data.ConvertLocation(location)); + ReplaceActionParameter(baseSector, level.FloorData, action); } } if (EntityLocations != null) @@ -61,12 +51,10 @@ public override void ApplyToLevel(TR2Level level) foreach (int entityIndex in EntityLocations) { TR2Entity entity = level.Entities[data.ConvertEntity(entityIndex)]; - TRRoomSector baseSector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, control); - ReplaceActionParameter(baseSector, control, action); + TRRoomSector baseSector = level.GetRoomSector(entity); + ReplaceActionParameter(baseSector, level.FloorData, action); } } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR3Level level) @@ -74,15 +62,12 @@ public override void ApplyToLevel(TR3Level level) EMLevelData data = GetData(level); FDActionItem action = InitialiseActionItem(data); - FDControl control = new(); - control.ParseFromLevel(level); - if (Locations != null) { foreach (EMLocation location in Locations) { - TRRoomSector baseSector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - ReplaceActionParameter(baseSector, control, action); + TRRoomSector baseSector = level.GetRoomSector(data.ConvertLocation(location)); + ReplaceActionParameter(baseSector, level.FloorData, action); } } if (EntityLocations != null) @@ -90,12 +75,10 @@ public override void ApplyToLevel(TR3Level level) foreach (int entityIndex in EntityLocations) { TR3Entity entity = level.Entities[data.ConvertEntity(entityIndex)]; - TRRoomSector baseSector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, control); - ReplaceActionParameter(baseSector, control, action); + TRRoomSector baseSector = level.GetRoomSector(entity); + ReplaceActionParameter(baseSector, level.FloorData, action); } } - - control.WriteToLevel(level); } private FDActionItem InitialiseActionItem(EMLevelData data) @@ -110,7 +93,7 @@ private static void ReplaceActionParameter(TRRoomSector baseSector, FDControl co return; } - List actions = FDUtilities.GetActionListItems(control, actionItem.TrigAction, baseSector.FDIndex); + List actions = control.GetActionItems(actionItem.Action, baseSector.FDIndex); foreach (FDActionItem action in actions) { action.Parameter = actionItem.Parameter; diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMResetPickupTriggerFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMResetPickupTriggerFunction.cs index 035f79f1c..eee34717c 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMResetPickupTriggerFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMResetPickupTriggerFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; namespace TREnvironmentEditor.Model.Types; @@ -13,37 +10,19 @@ public class EMResetPickupTriggerFunction : BaseEMFunction public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - - FDControl floorData = new(); - floorData.ParseFromLevel(level); - - ResetPickupTriggers(floorData, l => FDUtilities.GetRoomSector(l.X, l.Y, l.Z, data.ConvertRoom(l.Room), level, floorData)); - - floorData.WriteToLevel(level); + ResetPickupTriggers(level.FloorData, l => level.GetRoomSector(data.ConvertLocation(l))); } public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - - FDControl floorData = new(); - floorData.ParseFromLevel(level); - - ResetPickupTriggers(floorData, l => FDUtilities.GetRoomSector(l.X, l.Y, l.Z, data.ConvertRoom(l.Room), level, floorData)); - - floorData.WriteToLevel(level); + ResetPickupTriggers(level.FloorData, l => level.GetRoomSector(data.ConvertLocation(l))); } public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - - FDControl floorData = new(); - floorData.ParseFromLevel(level); - - ResetPickupTriggers(floorData, l => FDUtilities.GetRoomSector(l.X, l.Y, l.Z, data.ConvertRoom(l.Room), level, floorData)); - - floorData.WriteToLevel(level); + ResetPickupTriggers(level.FloorData, l => level.GetRoomSector(data.ConvertLocation(l))); } private void ResetPickupTriggers(FDControl floorData, Func sectorFunc) @@ -56,12 +35,12 @@ private void ResetPickupTriggers(FDControl floorData, Func e is FDTriggerEntry); + FDEntry entry = floorData[sector.FDIndex].Find(e => e is FDTriggerEntry); if (entry is FDTriggerEntry trigger && trigger.TrigType == FDTrigType.Pickup - && trigger.TrigActionList.Count > 1) + && trigger.Actions.Count > 1) { - trigger.TrigActionList.RemoveRange(1, trigger.TrigActionList.Count - 1); + trigger.Actions.RemoveRange(1, trigger.Actions.Count - 1); } } } diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMTriggerFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMTriggerFunction.cs index d168a8612..37b3eefff 100644 --- a/TREnvironmentEditor/Model/Types/Triggers/EMTriggerFunction.cs +++ b/TREnvironmentEditor/Model/Types/Triggers/EMTriggerFunction.cs @@ -1,7 +1,4 @@ using TREnvironmentEditor.Helpers; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -22,15 +19,12 @@ public override void ApplyToLevel(TR1Level level) EMLevelData data = GetData(level); FDTriggerEntry triggerEntry = InitialiseTriggerEntry(data); - FDControl control = new(); - control.ParseFromLevel(level); - if (Locations != null) { foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - CreateTrigger(sector, control, triggerEntry); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + CreateTrigger(sector, level.FloorData, triggerEntry); } } @@ -42,7 +36,7 @@ public override void ApplyToLevel(TR1Level level) { if (!sector.IsWall && sector.RoomBelow == TRConsts.NoRoom) { - CreateTrigger(sector, control, triggerEntry); + CreateTrigger(sector, level.FloorData, triggerEntry); } } } @@ -51,11 +45,9 @@ public override void ApplyToLevel(TR1Level level) if (EntityLocation.HasValue) { TR1Entity entity = level.Entities[data.ConvertEntity(EntityLocation.Value)]; - TRRoomSector sector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, control); - CreateTrigger(sector, control, triggerEntry); + TRRoomSector sector = level.GetRoomSector(entity); + CreateTrigger(sector, level.FloorData, triggerEntry); } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR2Level level) @@ -63,15 +55,12 @@ public override void ApplyToLevel(TR2Level level) EMLevelData data = GetData(level); FDTriggerEntry triggerEntry = InitialiseTriggerEntry(data); - FDControl control = new(); - control.ParseFromLevel(level); - if (Locations != null) { foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - CreateTrigger(sector, control, triggerEntry); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + CreateTrigger(sector, level.FloorData, triggerEntry); } } @@ -83,7 +72,7 @@ public override void ApplyToLevel(TR2Level level) { if (!sector.IsWall && sector.RoomBelow == TRConsts.NoRoom) { - CreateTrigger(sector, control, triggerEntry); + CreateTrigger(sector, level.FloorData, triggerEntry); } } } @@ -92,22 +81,20 @@ public override void ApplyToLevel(TR2Level level) if (EntityLocation.HasValue) { TR2Entity entity = level.Entities[data.ConvertEntity(EntityLocation.Value)]; - TRRoomSector sector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, control); - CreateTrigger(sector, control, triggerEntry); + TRRoomSector sector = level.GetRoomSector(entity); + CreateTrigger(sector, level.FloorData, triggerEntry); } // Handle any specifics that the trigger may rely on - foreach (FDActionItem action in triggerEntry.TrigActionList) + foreach (FDActionItem action in triggerEntry.Actions) { - switch (action.TrigAction) + switch (action.Action) { case FDTrigAction.ClearBodies: SetEnemyClearBodies(level.Entities); break; } } - - control.WriteToLevel(level); } public override void ApplyToLevel(TR3Level level) @@ -115,15 +102,12 @@ public override void ApplyToLevel(TR3Level level) EMLevelData data = GetData(level); FDTriggerEntry triggerEntry = InitialiseTriggerEntry(data); - FDControl control = new(); - control.ParseFromLevel(level); - if (Locations != null) { foreach (EMLocation location in Locations) { - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, data.ConvertRoom(location.Room), level, control); - CreateTrigger(sector, control, triggerEntry); + TRRoomSector sector = level.GetRoomSector(data.ConvertLocation(location)); + CreateTrigger(sector, level.FloorData, triggerEntry); } } @@ -135,7 +119,7 @@ public override void ApplyToLevel(TR3Level level) { if (!sector.IsWall && sector.RoomBelow == TRConsts.NoRoom) { - CreateTrigger(sector, control, triggerEntry); + CreateTrigger(sector, level.FloorData, triggerEntry); } } } @@ -144,22 +128,20 @@ public override void ApplyToLevel(TR3Level level) if (EntityLocation.HasValue) { TR3Entity entity = level.Entities[data.ConvertEntity(EntityLocation.Value)]; - TRRoomSector sector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, control); - CreateTrigger(sector, control, triggerEntry); + TRRoomSector sector = level.GetRoomSector(entity); + CreateTrigger(sector, level.FloorData, triggerEntry); } // Handle any specifics that the trigger may rely on - foreach (FDActionItem action in triggerEntry.TrigActionList) + foreach (FDActionItem action in triggerEntry.Actions) { - switch (action.TrigAction) + switch (action.Action) { case FDTrigAction.ClearBodies: SetEnemyClearBodies(level.Entities); break; } } - - control.WriteToLevel(level); } private FDTriggerEntry InitialiseTriggerEntry(EMLevelData data) @@ -181,7 +163,7 @@ private void CreateTrigger(TRRoomSector sector, FDControl control, FDTriggerEntr control.CreateFloorData(sector); } - List entries = control.Entries[sector.FDIndex]; + List entries = control[sector.FDIndex]; if (Replace) { entries.Clear(); diff --git a/TRFDControl/TRFDControl.csproj b/TRFDControl/TRFDControl.csproj deleted file mode 100644 index 2ec8070b5..000000000 --- a/TRFDControl/TRFDControl.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - net6.0 - enable - 4 - Copyright © Tomb Raider Community 2023 - false - - - - - \ No newline at end of file diff --git a/TRLevelControl/Build/TRFDBuilder.cs b/TRLevelControl/Build/TRFDBuilder.cs new file mode 100644 index 000000000..792fd8a99 --- /dev/null +++ b/TRLevelControl/Build/TRFDBuilder.cs @@ -0,0 +1,361 @@ +using TRLevelControl.Model; + +namespace TRLevelControl.Build; + +public class TRFDBuilder +{ + private readonly TRGameVersion _version; + private readonly ITRLevelObserver _observer; + + public TRFDBuilder(TRGameVersion version, ITRLevelObserver observer = null) + { + _version = version; + _observer = observer; + } + + public FDControl ReadFloorData(TRLevelReader reader, IEnumerable sectors) + { + uint numFloorData = reader.ReadUInt32(); + ushort[] data = reader.ReadUInt16s(numFloorData); + + FDControl floorData = new(_version, _observer, data.Length == 0 ? (ushort)0 : data[0]); + if (_observer?.UseOriginalFloorData ?? false) + { + int index = 0; + while (++index < data.Length) + { + floorData[index] = ReadFromIndex(ref index, data); + } + } + else + { + Dictionary> expandedFunctions = new(); + foreach (TRRoomSector sector in sectors) + { + int index = sector.FDIndex; + if (index == 0) + { + continue; + } + + List functions = ReadFromIndex(ref index, data); + if (floorData.ContainsKey(sector.FDIndex)) + { + expandedFunctions[sector] = functions; + } + else + { + floorData[sector.FDIndex] = functions; + } + } + + foreach (var (sector, functions) in expandedFunctions) + { + floorData.CreateFloorData(sector); + floorData[sector.FDIndex] = functions; + } + } + + return floorData; + } + + private List ReadFromIndex(ref int index, ushort[] data) + { + List functions = new(); + + while (true) + { + ushort value = data[index]; + FDFunction function = (FDFunction)(value & 0x001F); + switch (function) + { + case FDFunction.PortalSector: + functions.Add(new FDPortalEntry() + { + Room = (short)data[++index] + }); + break; + + case FDFunction.FloorSlant: + case FDFunction.CeilingSlant: + ushort slantData = data[++index]; + functions.Add(new FDSlantEntry + { + Type = (FDSlantType)function, + XSlant = (sbyte)(slantData & 0x00FF), + ZSlant = (sbyte)((slantData & 0xFF00) >> 8) + }); + break; + + case FDFunction.Trigger: + ushort trigSetup = data[++index]; + FDTriggerEntry trig = new() + { + TrigType = (FDTrigType)((value & 0x7F00) >> 8), + Timer = (byte)(trigSetup & 0x00FF), + OneShot = (trigSetup & 0x0100) > 0, + Mask = (byte)((trigSetup & 0x3E00) >> 9) + }; + functions.Add(trig); + + bool done = false; + if (trig.TrigType == FDTrigType.Switch || trig.TrigType == FDTrigType.Key) + { + ushort switchRef = data[++index]; + trig.SwitchOrKeyRef = (short)(switchRef & 0x7FFF); + done = (switchRef & 0x8000) > 0; + } + + while (!done && index < data.Length) + { + ushort actionData = data[++index]; + FDActionItem action = new() + { + Action = (FDTrigAction)((actionData & 0x7C00) >> 10), + Parameter = (short)(actionData & 0x03FF) + }; + trig.Actions.Add(action); + + done = (actionData & 0x8000) > 0; + + if (action.Action == FDTrigAction.Camera || action.Action == FDTrigAction.Flyby) + { + ushort camData = data[++index]; + action.CamAction = new() + { + Timer = (byte)(camData & 0x00FF), + Once = (camData & 0x0100) > 0, + MoveTimer = (byte)((camData & 0x3E00) >> 9) + }; + + done = (camData & 0x8000) > 0; + } + } + + break; + case FDFunction.KillLara: + functions.Add(new FDKillLaraEntry()); + break; + + case FDFunction.ClimbableWalls: + functions.Add(new FDClimbEntry + { + Direction = (FDClimbDirection)((value & 0x7F00) >> 8) + }); + break; + + case FDFunction.FloorTriangulationNWSE_Solid: + case FDFunction.FloorTriangulationNESW_Solid: + case FDFunction.CeilingTriangulationNW_Solid: + case FDFunction.CeilingTriangulationNE_Solid: + case FDFunction.FloorTriangulationNWSE_SW: + case FDFunction.FloorTriangulationNWSE_NE: + case FDFunction.FloorTriangulationNESW_SE: + case FDFunction.FloorTriangulationNESW_NW: + case FDFunction.CeilingTriangulationNW_SW: + case FDFunction.CeilingTriangulationNW_NE: + case FDFunction.CeilingTriangulationNE_NW: + case FDFunction.CeilingTriangulationNE_SE: + ushort triData = data[++index]; + functions.Add(new FDTriangulationEntry + { + Type = (FDTriangulationType)function, + C10 = (byte)(triData & 0x000F), + C00 = (byte)((triData & 0x00F0) >> 4), + C01 = (byte)((triData & 0x0F00) >> 8), + C11 = (byte)((triData & 0xF000) >> 12), + H1 = (sbyte)((value & 0x03E0) >> 5), + H2 = (sbyte)((value & 0x7C00) >> 10) + }); + break; + + case FDFunction.Monkeyswing: + functions.Add(new FDMonkeySwingEntry()); + break; + + case FDFunction.DeferredTrigOrMinecartRotateLeft: + if (_version < TRGameVersion.TR4) + { + functions.Add(new FDMinecartEntry + { + Type = (FDMinecartType)function + }); + } + else + { + functions.Add(new FDDeferredTriggerEntry()); + } + break; + + case FDFunction.MechBeetleOrMinecartRotateRight: + if (_version < TRGameVersion.TR4) + { + functions.Add(new FDMinecartEntry + { + Type = (FDMinecartType)function + }); + } + else + { + functions.Add(new FDBeetleEntry()); + } + break; + + default: + break; + } + + if ((value & 0x8000) > 0) + { + break; + } + else + { + index++; + } + } + + return functions; + } + + public List Flatten(List entries) + { + List data = new(); + + for (int i = 0; i < entries.Count; i++) + { + FDEntry entry = entries[i]; + if (_observer == null && !IsValidEntry(entry)) + { + continue; + } + + int setupValue = (byte)entry.GetFunction() & 0x001F; + + // Check for defined SubFunction - 0x7F00 + if (entry is FDClimbEntry climbEntry) + { + setupValue |= ((byte)climbEntry.Direction & 0x001F) << 8; + } + else if (entry is FDTriggerEntry trigger) + { + setupValue |= ((byte)trigger.TrigType & 0x001F) << 8; + } + // Or triangulation height adjustments + else if (entry is FDTriangulationEntry triangulation) + { + setupValue |= (triangulation.H1 & 0x001F) << 5; + setupValue |= (triangulation.H2 & 0x001F) << 10; + } + + // Final entry for a sector? + if (i == entries.Count - 1) + { + setupValue |= 0x8000; + } + + // Setup done + data.Add((ushort)setupValue); + + // Add entry specifics + if (entry is FDPortalEntry portal) + { + data.Add((ushort)portal.Room); + } + else if (entry is FDSlantEntry slant) + { + int value = (slant.XSlant & 0xFF) + (slant.ZSlant << 8); + if (value < 0) + { + value = ushort.MaxValue + 1 + value; + } + data.Add((ushort)value); + } + else if (entry is FDTriggerEntry trigger) + { + data.AddRange(Flatten(trigger)); + } + else if (entry is FDTriangulationEntry triangulation) + { + int corners = triangulation.C10 & 0x000F; + corners |= (triangulation.C00 & 0x000F) << 4; + corners |= (triangulation.C01 & 0x000F) << 8; + corners |= (triangulation.C11 & 0x000F) << 12; + data.Add((ushort)corners); + } + } + + return data; + } + + private bool IsValidEntry(FDEntry entry) + { + return entry switch + { + FDTriggerEntry trigger => trigger.Actions.Count > 0, + FDClimbEntry => _version >= TRGameVersion.TR2, + FDMinecartEntry => _version == TRGameVersion.TR3, + FDTriangulationEntry or FDMonkeySwingEntry => _version >= TRGameVersion.TR3, + FDBeetleEntry or FDDeferredTriggerEntry => _version >= TRGameVersion.TR4, + _ => true, + }; + } + + private static List Flatten(FDTriggerEntry trigger) + { + List data = new(); + + int trigSetup = trigger.Timer; + if (trigger.OneShot) + { + trigSetup |= 0x0100; + } + trigSetup |= (trigger.Mask & 0x001F) << 9; + data.Add((ushort)trigSetup); + + if (trigger.TrigType == FDTrigType.Switch || trigger.TrigType == FDTrigType.Key) + { + ushort switchRef = (ushort)trigger.SwitchOrKeyRef; + if (trigger.Actions.Count == 0) + { + switchRef |= 0x8000; + } + data.Add(switchRef); + } + + for (int i = 0; i < trigger.Actions.Count; i++) + { + FDActionItem action = trigger.Actions[i]; + int actionValue = action.Parameter & 0x03FF; + actionValue |= ((byte)action.Action & 0x001F) << 10; + + bool isCamera = action.CamAction != null + && (action.Action == FDTrigAction.Camera || action.Action == FDTrigAction.Flyby); + if (i == trigger.Actions.Count - 1 && !isCamera) + { + actionValue |= 0x8000; + } + + data.Add((ushort)actionValue); + + if (isCamera) + { + int cameraValue = action.CamAction.Timer; + if (action.CamAction.Once) + { + cameraValue |= 0x0100; + } + cameraValue |= (action.CamAction.MoveTimer & 0x001F) << 9; + + if (i == trigger.Actions.Count - 1) + { + cameraValue |= 0x8000; + } + + data.Add((ushort)cameraValue); + } + } + + return data; + } +} diff --git a/TRLevelControl/Control/TR1LevelControl.cs b/TRLevelControl/Control/TR1LevelControl.cs index b9486a752..7372f8ef3 100644 --- a/TRLevelControl/Control/TR1LevelControl.cs +++ b/TRLevelControl/Control/TR1LevelControl.cs @@ -175,17 +175,20 @@ private void ReadRooms(TRLevelReader reader) { _level.Rooms = _roomBuilder.ReadRooms(reader); - uint numFloorData = reader.ReadUInt32(); - _level.FloorData = reader.ReadUInt16s(numFloorData).ToList(); + TRFDBuilder builder = new(_level.Version.Game, _observer); + _level.FloorData = builder.ReadFloorData(reader, _level.Rooms.SelectMany(r => r.Sectors)); } private void WriteRooms(TRLevelWriter writer) { _spriteBuilder.CacheSpriteOffsets(_level.Sprites); + + List floorData = _level.FloorData + .Flatten(_level.Rooms.SelectMany(r => r.Sectors)); _roomBuilder.WriteRooms(writer, _level.Rooms, _spriteBuilder); - writer.Write((uint)_level.FloorData.Count); - writer.Write(_level.FloorData); + writer.Write((uint)floorData.Count); + writer.Write(floorData); } private void ReadMeshData(TRLevelReader reader) diff --git a/TRLevelControl/Control/TR2LevelControl.cs b/TRLevelControl/Control/TR2LevelControl.cs index da36d8fbf..684b736b9 100644 --- a/TRLevelControl/Control/TR2LevelControl.cs +++ b/TRLevelControl/Control/TR2LevelControl.cs @@ -182,18 +182,21 @@ protected override void Write(TRLevelWriter writer) private void ReadRooms(TRLevelReader reader) { _level.Rooms = _roomBuilder.ReadRooms(reader); - - uint numFloorData = reader.ReadUInt32(); - _level.FloorData = reader.ReadUInt16s(numFloorData).ToList(); + + TRFDBuilder builder = new(_level.Version.Game, _observer); + _level.FloorData = builder.ReadFloorData(reader, _level.Rooms.SelectMany(r => r.Sectors)); } private void WriteRooms(TRLevelWriter writer) { _spriteBuilder.CacheSpriteOffsets(_level.Sprites); + + List floorData = _level.FloorData + .Flatten(_level.Rooms.SelectMany(r => r.Sectors)); _roomBuilder.WriteRooms(writer, _level.Rooms, _spriteBuilder); - writer.Write((uint)_level.FloorData.Count); - writer.Write(_level.FloorData); + writer.Write((uint)floorData.Count); + writer.Write(floorData); } private void ReadMeshData(TRLevelReader reader) diff --git a/TRLevelControl/Control/TR3LevelControl.cs b/TRLevelControl/Control/TR3LevelControl.cs index 6855f7ac6..1e26825ad 100644 --- a/TRLevelControl/Control/TR3LevelControl.cs +++ b/TRLevelControl/Control/TR3LevelControl.cs @@ -185,17 +185,20 @@ private void ReadRooms(TRLevelReader reader) { _level.Rooms = _roomBuilder.ReadRooms(reader); - uint numFloorData = reader.ReadUInt32(); - _level.FloorData = reader.ReadUInt16s(numFloorData).ToList(); + TRFDBuilder builder = new(_level.Version.Game, _observer); + _level.FloorData = builder.ReadFloorData(reader, _level.Rooms.SelectMany(r => r.Sectors)); } private void WriteRooms(TRLevelWriter writer) { _spriteBuilder.CacheSpriteOffsets(_level.Sprites); + + List floorData = _level.FloorData + .Flatten(_level.Rooms.SelectMany(r => r.Sectors)); _roomBuilder.WriteRooms(writer, _level.Rooms, _spriteBuilder); - writer.Write((uint)_level.FloorData.Count); - writer.Write(_level.FloorData); + writer.Write((uint)floorData.Count); + writer.Write(floorData); } private void ReadMeshData(TRLevelReader reader) diff --git a/TRLevelControl/Control/TR4LevelControl.cs b/TRLevelControl/Control/TR4LevelControl.cs index 8952a6f9d..7e528e7ae 100644 --- a/TRLevelControl/Control/TR4LevelControl.cs +++ b/TRLevelControl/Control/TR4LevelControl.cs @@ -170,17 +170,20 @@ private void ReadRooms(TRLevelReader reader) { _level.Rooms = _roomBuilder.ReadRooms(reader); - uint numFloorData = reader.ReadUInt32(); - _level.FloorData = reader.ReadUInt16s(numFloorData).ToList(); + TRFDBuilder builder = new(_level.Version.Game, _observer); + _level.FloorData = builder.ReadFloorData(reader, _level.Rooms.SelectMany(r => r.Sectors)); } private void WriteRooms(TRLevelWriter writer) { _spriteBuilder.CacheSpriteOffsets(_level.Sprites); + + List floorData = _level.FloorData + .Flatten(_level.Rooms.SelectMany(r => r.Sectors)); _roomBuilder.WriteRooms(writer, _level.Rooms, _spriteBuilder); - writer.Write((uint)_level.FloorData.Count); - writer.Write(_level.FloorData); + writer.Write((uint)floorData.Count); + writer.Write(floorData); } private void ReadMeshData(TRLevelReader reader) diff --git a/TRLevelControl/Control/TR5LevelControl.cs b/TRLevelControl/Control/TR5LevelControl.cs index 60bb6ecf8..8ab270458 100644 --- a/TRLevelControl/Control/TR5LevelControl.cs +++ b/TRLevelControl/Control/TR5LevelControl.cs @@ -191,8 +191,8 @@ private void ReadRooms(TRLevelReader reader) _level.Rooms = TR5RoomBuilder.ReadRooms(reader); - uint numFloorData = reader.ReadUInt32(); - _level.FloorData = reader.ReadUInt16s(numFloorData).ToList(); + TRFDBuilder builder = new(_level.Version.Game, _observer); + _level.FloorData = builder.ReadFloorData(reader, _level.Rooms.SelectMany(r => r.Sectors)); } private void ReadRawRooms(TRLevelReader reader) @@ -235,10 +235,12 @@ private void WriteRooms(TRLevelWriter writer) return; } + List floorData = _level.FloorData + .Flatten(_level.Rooms.SelectMany(r => r.Sectors)); TR5RoomBuilder.WriteRooms(writer, _level.Rooms); - writer.Write((uint)_level.FloorData.Count); - writer.Write(_level.FloorData); + writer.Write((uint)floorData.Count); + writer.Write(floorData); } private void ReadMeshData(TRLevelReader reader) diff --git a/TRLevelControl/ITRLevelObserver.cs b/TRLevelControl/ITRLevelObserver.cs index 5cfd04b29..f31afea06 100644 --- a/TRLevelControl/ITRLevelObserver.cs +++ b/TRLevelControl/ITRLevelObserver.cs @@ -7,6 +7,7 @@ public interface ITRLevelObserver void OnChunkRead(long startPosition, long endPosition, TRChunkType chunkType, byte[] data); void OnChunkWritten(long startPosition, long endPosition, TRChunkType chunkType, byte[] data); bool UseTR5RawRooms { get; } + bool UseOriginalFloorData { get; } void OnRawTR5RoomsRead(List data); List GetTR5Rooms(); void OnMeshPaddingRead(uint meshPointer, List values); diff --git a/TRLevelControl/Model/Common/Enums/TRUnit.cs b/TRLevelControl/Model/Common/Enums/TRUnit.cs new file mode 100644 index 000000000..28e5e3add --- /dev/null +++ b/TRLevelControl/Model/Common/Enums/TRUnit.cs @@ -0,0 +1,8 @@ +namespace TRLevelControl.Model; + +public enum TRUnit +{ + Sector = 0, + Room = 1, + World = 2, +} diff --git a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDBeetleEntry.cs b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDBeetleEntry.cs new file mode 100644 index 000000000..b40ae393e --- /dev/null +++ b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDBeetleEntry.cs @@ -0,0 +1,10 @@ +namespace TRLevelControl.Model; + +public class FDBeetleEntry : FDEntry +{ + public override FDFunction GetFunction() + => FDFunction.MechBeetleOrMinecartRotateRight; + + public override FDEntry Clone() + => (FDBeetleEntry)MemberwiseClone(); +} diff --git a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDClimbEntry.cs b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDClimbEntry.cs index 4616fef72..a3acc51c4 100644 --- a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDClimbEntry.cs +++ b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDClimbEntry.cs @@ -1,80 +1,48 @@ -namespace TRFDControl.FDEntryTypes; +namespace TRLevelControl.Model; public class FDClimbEntry : FDEntry { + public FDClimbDirection Direction { get; set; } + + public override FDFunction GetFunction() + => FDFunction.ClimbableWalls; + + public bool IsNegativeX + { + get => Direction.HasFlag(FDClimbDirection.NegativeX); + set => SetDirection(FDClimbDirection.NegativeX, value); + } + public bool IsPositiveX { - get - { - return (Setup.SubFunction & (byte)FDClimbDirection.PositiveX) > 0; - } - set - { - if (value) - { - Setup.SubFunction |= (byte)FDClimbDirection.PositiveX; - } - else - { - Setup.SubFunction = (byte)(Setup.SubFunction & ~(byte)FDClimbDirection.PositiveX); - } - } + get => Direction.HasFlag(FDClimbDirection.PositiveX); + set => SetDirection(FDClimbDirection.PositiveX, value); } - public bool IsPositiveZ + public bool IsNegativeZ { - get - { - return (Setup.SubFunction & (byte)FDClimbDirection.PositiveZ) > 0; - } - set - { - if (value) - { - Setup.SubFunction |= (byte)FDClimbDirection.PositiveZ; - } - else - { - Setup.SubFunction = (byte)(Setup.SubFunction & ~(byte)FDClimbDirection.PositiveZ); - } - } + get => Direction.HasFlag(FDClimbDirection.NegativeZ); + set => SetDirection(FDClimbDirection.NegativeZ, value); } - public bool IsNegativeX + public bool IsPositiveZ { - get - { - return (Setup.SubFunction & (byte)FDClimbDirection.NegativeX) > 0; - } - set - { - if (value) - { - Setup.SubFunction |= (byte)FDClimbDirection.NegativeX; - } - else - { - Setup.SubFunction = (byte)(Setup.SubFunction & ~(byte)FDClimbDirection.NegativeX); - } - } + get => Direction.HasFlag(FDClimbDirection.PositiveZ); + set => SetDirection(FDClimbDirection.PositiveZ, value); } - public bool IsNegativeZ + public void SetDirection(FDClimbDirection direction, bool state) { - get + if (state) { - return (Setup.SubFunction & (byte)FDClimbDirection.NegativeZ) > 0; + Direction |= direction; } - set + else { - if (value) - { - Setup.SubFunction |= (byte)FDClimbDirection.NegativeZ; - } - else - { - Setup.SubFunction = (byte)(Setup.SubFunction & ~(byte)FDClimbDirection.NegativeZ); - } + Direction &= ~direction; } } + + public override FDEntry Clone() + => (FDClimbEntry)MemberwiseClone(); } diff --git a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDDeferredTriggerEntry.cs b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDDeferredTriggerEntry.cs new file mode 100644 index 000000000..81e1d19ec --- /dev/null +++ b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDDeferredTriggerEntry.cs @@ -0,0 +1,10 @@ +namespace TRLevelControl.Model; + +public class FDDeferredTriggerEntry : FDEntry +{ + public override FDFunction GetFunction() + => FDFunction.DeferredTrigOrMinecartRotateLeft; + + public override FDEntry Clone() + => (FDDeferredTriggerEntry)MemberwiseClone(); +} diff --git a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDKillLaraEntry.cs b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDKillLaraEntry.cs index b66066aa9..7e1084a0f 100644 --- a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDKillLaraEntry.cs +++ b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDKillLaraEntry.cs @@ -1,6 +1,10 @@ -namespace TRFDControl.FDEntryTypes; +namespace TRLevelControl.Model; public class FDKillLaraEntry : FDEntry { + public override FDFunction GetFunction() + => FDFunction.KillLara; + public override FDEntry Clone() + => (FDKillLaraEntry)MemberwiseClone(); } diff --git a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDMinecartEntry.cs b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDMinecartEntry.cs index bf8116ad7..93b9a4895 100644 --- a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDMinecartEntry.cs +++ b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDMinecartEntry.cs @@ -1,5 +1,12 @@ -namespace TRFDControl.FDEntryTypes; +namespace TRLevelControl.Model; public class FDMinecartEntry : FDEntry { + public FDMinecartType Type { get; set; } + + public override FDFunction GetFunction() + => (FDFunction)Type; + + public override FDEntry Clone() + => (FDMinecartEntry)MemberwiseClone(); } diff --git a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDMonkeySwingEntry.cs b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDMonkeySwingEntry.cs index 920c2ce80..3b57d43ca 100644 --- a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDMonkeySwingEntry.cs +++ b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDMonkeySwingEntry.cs @@ -1,5 +1,10 @@ -namespace TRFDControl.FDEntryTypes; +namespace TRLevelControl.Model; public class FDMonkeySwingEntry : FDEntry { + public override FDFunction GetFunction() + => FDFunction.Monkeyswing; + + public override FDEntry Clone() + => (FDMonkeySwingEntry)MemberwiseClone(); } diff --git a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDPortalEntry.cs b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDPortalEntry.cs index 2b54d1022..9ecfc9bbc 100644 --- a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDPortalEntry.cs +++ b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDPortalEntry.cs @@ -1,15 +1,12 @@ -namespace TRFDControl.FDEntryTypes; +namespace TRLevelControl.Model; public class FDPortalEntry : FDEntry { - public ushort Room { get; set; } + public short Room { get; set; } - public override ushort[] Flatten() - { - return new ushort[] - { - Setup.Value, - Room - }; - } + public override FDFunction GetFunction() + => FDFunction.PortalSector; + + public override FDEntry Clone() + => (FDPortalEntry)MemberwiseClone(); } diff --git a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDSlantEntry.cs b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDSlantEntry.cs index 0224adf5a..ba690e21e 100644 --- a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDSlantEntry.cs +++ b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDSlantEntry.cs @@ -1,51 +1,14 @@ -namespace TRFDControl.FDEntryTypes; +namespace TRLevelControl.Model; public class FDSlantEntry : FDEntry { public FDSlantType Type { get; set; } + public sbyte XSlant { get; set; } + public sbyte ZSlant { get; set; } - public ushort SlantValue { get; set; } + public override FDFunction GetFunction() + => (FDFunction)Type; - public sbyte XSlant - { - get - { - return (sbyte)(SlantValue & 0x00ff); - } - set - { - SetSlants(value, ZSlant); - } - } - - public sbyte ZSlant - { - get - { - return (sbyte)(SlantValue >> 8); - } - set - { - SetSlants(XSlant, value); - } - } - - private void SetSlants(sbyte xSlant, sbyte zSlant) - { - int value = (xSlant & 0xff) + (zSlant << 8); - if (value < 0) - { - value = ushort.MaxValue + 1 + value; - } - SlantValue = (ushort)value; - } - - public override ushort[] Flatten() - { - return new ushort[] - { - Setup.Value, - SlantValue - }; - } + public override FDEntry Clone() + => (FDSlantEntry)MemberwiseClone(); } diff --git a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDTriangulationEntry.cs b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDTriangulationEntry.cs index 9503080d4..1ae2e82b4 100644 --- a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDTriangulationEntry.cs +++ b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDTriangulationEntry.cs @@ -1,41 +1,58 @@ -namespace TRFDControl.FDEntryTypes; +namespace TRLevelControl.Model; public class FDTriangulationEntry : FDEntry { - public FDTriangulationData TriData { get; set; } + private static readonly List _floorTriTypes = new() + { + FDTriangulationType.FloorNWSE_Solid, + FDTriangulationType.FloorNESW_Solid, + }; - public bool IsFloorTriangulation + private static readonly List _floorPortalTypes = new() { - get - { - FDFunction function = (FDFunction)Setup.Function; - return function == FDFunction.FloorTriangulationNESW_NW - || function == FDFunction.FloorTriangulationNESW_Solid - || function == FDFunction.FloorTriangulationNESW_SE - || function == FDFunction.FloorTriangulationNWSE_NE - || function == FDFunction.FloorTriangulationNWSE_Solid - || function == FDFunction.FloorTriangulationNWSE_SW; - } - } + FDTriangulationType.FloorNWSE_SW, + FDTriangulationType.FloorNWSE_NE, + FDTriangulationType.FloorNESW_SE, + FDTriangulationType.FloorNESW_NW, + }; - public bool IsFloorPortal + private static readonly List _ceilingTriTypes = new() { - get - { - FDFunction function = (FDFunction)Setup.Function; - return function == FDFunction.FloorTriangulationNESW_NW - || function == FDFunction.FloorTriangulationNESW_SE - || function == FDFunction.FloorTriangulationNWSE_NE - || function == FDFunction.FloorTriangulationNWSE_SW; - } - } - - public override ushort[] Flatten() + FDTriangulationType.CeilingNWSE_Solid, + FDTriangulationType.CeilingNESW_Solid, + }; + + private static readonly List _ceilingPortalTypes = new() { - return new ushort[] - { - Setup.Value, - TriData.Value - }; - } + FDTriangulationType.CeilingNWSE_SW, + FDTriangulationType.CeilingNWSE_NE, + FDTriangulationType.CeilingNESW_NW, + FDTriangulationType.CeilingNESW_SE, + }; + + public FDTriangulationType Type { get; set; } + public byte C10 { get; set; } + public byte C00 { get; set; } + public byte C01 { get; set; } + public byte C11 { get; set; } + public sbyte H1 { get; set; } + public sbyte H2 { get; set; } + + public bool IsFloorTriangulation + => _floorTriTypes.Contains(Type); + + public bool IsFloorPortal + => _floorPortalTypes.Contains(Type); + + public bool IsCeilingTriangulation + => _ceilingTriTypes.Contains(Type); + + public bool IsCeilingPortal + => _ceilingPortalTypes.Contains(Type); + + public override FDFunction GetFunction() + => (FDFunction)Type; + + public override FDEntry Clone() + => (FDTriangulationEntry)MemberwiseClone(); } diff --git a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDTriggerEntry.cs b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDTriggerEntry.cs index d061b9ad1..2901a5ca3 100644 --- a/TRLevelControl/Model/Common/FloorData/EntryTypes/FDTriggerEntry.cs +++ b/TRLevelControl/Model/Common/FloorData/EntryTypes/FDTriggerEntry.cs @@ -1,84 +1,27 @@ -namespace TRFDControl.FDEntryTypes; +namespace TRLevelControl.Model; public class FDTriggerEntry : FDEntry { - public FDTriggerEntry() - { - TrigActionList = new List(); - } - - public FDTrigSetup TrigSetup { get; set; } + public FDTrigType TrigType { get; set; } + public byte Timer { get; set; } + public bool OneShot { get; set; } + public byte Mask { get; set; } = TRConsts.FullMask; + public short SwitchOrKeyRef { get; set; } + public List Actions { get; set; } = new(); - public FDTrigType TrigType - { - get - { - return (FDTrigType)Setup.SubFunction; - } - set - { - Setup.SubFunction = (byte)value; - } - } - - public List TrigActionList { get; set; } - - public ushort SwitchOrKeyRef { get; set; } - - public bool SwitchKeyContinue - { - get - { - //Continue bit set to 0 means to continue, not 1... - return !((SwitchOrKeyRef & 0x8000) > 0); - } - internal set - { - if (value) - { - SwitchOrKeyRef = (ushort)(SwitchOrKeyRef & ~0x8000); - } - else - { - SwitchOrKeyRef |= 0x8000; - } - } - } + public override FDFunction GetFunction() + => FDFunction.Trigger; - public override ushort[] Flatten() + public override FDEntry Clone() { - //FD Setup followed by TrigSetup - List dataArray = new() + return new FDTriggerEntry { - Setup.Value, - TrigSetup.Value + TrigType = TrigType, + Timer = Timer, + OneShot = OneShot, + Mask = Mask, + SwitchOrKeyRef = SwitchOrKeyRef, + Actions = new(Actions.Select(a => a.Clone())) }; - - //If key or switch, next uint16 will be ref to key or switch ent - if (TrigType == FDTrigType.Switch || TrigType == FDTrigType.Key) - dataArray.Add(SwitchOrKeyRef); - - - for (int i = 0; i < TrigActionList.Count; i++) - { - FDActionItem action = TrigActionList[i]; - - // Ensure Continue is set on all but the final action, unless it's a camera action, - // in which case the CamAction will have Continue set to false if this is the final action. - action.Continue = (action.TrigAction == FDTrigAction.Camera || action.TrigAction == FDTrigAction.Flyby) || i < TrigActionList.Count - 1; - - //For each action, record the value. - dataArray.Add(action.Value); - - //If it is a camera action, record the additional camera action - if (action.TrigAction == FDTrigAction.Camera || action.TrigAction == FDTrigAction.Flyby) - { - action.CamAction.Continue = i < TrigActionList.Count - 1; - dataArray.Add(action.CamAction.Value); - } - } - - //Return uint16 array - return dataArray.ToArray(); } } diff --git a/TRLevelControl/Model/Common/FloorData/EntryTypes/TR3MinecartRotateRightEntry.cs b/TRLevelControl/Model/Common/FloorData/EntryTypes/TR3MinecartRotateRightEntry.cs deleted file mode 100644 index 8943c63c8..000000000 --- a/TRLevelControl/Model/Common/FloorData/EntryTypes/TR3MinecartRotateRightEntry.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace TRFDControl.FDEntryTypes; - -public class TR3MinecartRotateRightEntry : FDEntry -{ -} diff --git a/TRLevelControl/Model/Common/FloorData/Enums/FDClimbDirection.cs b/TRLevelControl/Model/Common/FloorData/Enums/FDClimbDirection.cs index 2e6b985fc..02ee36f2d 100644 --- a/TRLevelControl/Model/Common/FloorData/Enums/FDClimbDirection.cs +++ b/TRLevelControl/Model/Common/FloorData/Enums/FDClimbDirection.cs @@ -1,9 +1,10 @@ -namespace TRFDControl; +namespace TRLevelControl.Model; +[Flags] public enum FDClimbDirection { - PositiveZ = 0x01, - PositiveX = 0x02, - NegativeZ = 0x04, - NegativeX = 0x08 + PositiveZ = 1 << 0, + PositiveX = 1 << 1, + NegativeZ = 1 << 2, + NegativeX = 1 << 3, } diff --git a/TRLevelControl/Model/Common/FloorData/Enums/FDFunction.cs b/TRLevelControl/Model/Common/FloorData/Enums/FDFunction.cs index e0e082401..e7303debe 100644 --- a/TRLevelControl/Model/Common/FloorData/Enums/FDFunction.cs +++ b/TRLevelControl/Model/Common/FloorData/Enums/FDFunction.cs @@ -1,26 +1,26 @@ -namespace TRFDControl; +namespace TRLevelControl.Model; public enum FDFunction { - PortalSector = 0x01, - FloorSlant = 0x02, - CeilingSlant = 0x03, - Trigger = 0x04, - KillLara = 0x05, - ClimbableWalls = 0x06, - FloorTriangulationNWSE_Solid = 0x07, - FloorTriangulationNESW_Solid = 0x08, - CeilingTriangulationNW_Solid = 0x09, - CeilingTriangulationNE_Solid = 0x0A, - FloorTriangulationNWSE_SW = 0x0B, - FloorTriangulationNWSE_NE = 0x0C, - FloorTriangulationNESW_SE = 0x0D, // TRosetta names this _SW but should be SE - FloorTriangulationNESW_NW = 0x0E, - CeilingTriangulationNW_SW = 0x0F, - CeilingTriangulationNW_NE = 0x10, - CeilingTriangulationNE_NW = 0x11, - CeilingTriangulationNE_SE = 0x12, - Monkeyswing = 0x13, - DeferredTriggeringOrMinecartRotateLeft = 0x14, - MechBeetleOrMinecartRotateRight = 0x15 + PortalSector = 0x01, + FloorSlant = 0x02, + CeilingSlant = 0x03, + Trigger = 0x04, + KillLara = 0x05, + ClimbableWalls = 0x06, + FloorTriangulationNWSE_Solid = 0x07, + FloorTriangulationNESW_Solid = 0x08, + CeilingTriangulationNW_Solid = 0x09, + CeilingTriangulationNE_Solid = 0x0A, + FloorTriangulationNWSE_SW = 0x0B, + FloorTriangulationNWSE_NE = 0x0C, + FloorTriangulationNESW_SE = 0x0D, // TRosetta incorrectly names this _SW + FloorTriangulationNESW_NW = 0x0E, + CeilingTriangulationNW_SW = 0x0F, + CeilingTriangulationNW_NE = 0x10, + CeilingTriangulationNE_NW = 0x11, + CeilingTriangulationNE_SE = 0x12, + Monkeyswing = 0x13, + DeferredTrigOrMinecartRotateLeft = 0x14, + MechBeetleOrMinecartRotateRight = 0x15 } diff --git a/TRLevelControl/Model/Common/FloorData/Enums/FDMinecartType.cs b/TRLevelControl/Model/Common/FloorData/Enums/FDMinecartType.cs new file mode 100644 index 000000000..48c0a6312 --- /dev/null +++ b/TRLevelControl/Model/Common/FloorData/Enums/FDMinecartType.cs @@ -0,0 +1,7 @@ +namespace TRLevelControl.Model; + +public enum FDMinecartType +{ + Left = 0x14, + Right = 0x15, +} diff --git a/TRLevelControl/Model/Common/FloorData/Enums/FDSlantType.cs b/TRLevelControl/Model/Common/FloorData/Enums/FDSlantType.cs index 38251edb5..9cfa7b657 100644 --- a/TRLevelControl/Model/Common/FloorData/Enums/FDSlantType.cs +++ b/TRLevelControl/Model/Common/FloorData/Enums/FDSlantType.cs @@ -1,7 +1,7 @@ -namespace TRFDControl.FDEntryTypes; +namespace TRLevelControl.Model; public enum FDSlantType { - CeilingSlant, - FloorSlant + Floor = 0x02, + Ceiling = 0x03, } diff --git a/TRLevelControl/Model/Common/FloorData/Enums/FDTriangulationType.cs b/TRLevelControl/Model/Common/FloorData/Enums/FDTriangulationType.cs new file mode 100644 index 000000000..0aa44b092 --- /dev/null +++ b/TRLevelControl/Model/Common/FloorData/Enums/FDTriangulationType.cs @@ -0,0 +1,17 @@ +namespace TRLevelControl.Model; + +public enum FDTriangulationType +{ + FloorNWSE_Solid = 0x07, + FloorNESW_Solid = 0x08, + CeilingNWSE_Solid = 0x09, + CeilingNESW_Solid = 0x0A, + FloorNWSE_SW = 0x0B, + FloorNWSE_NE = 0x0C, + FloorNESW_SE = 0x0D, // TRosetta incorrectly names this _SW + FloorNESW_NW = 0x0E, + CeilingNWSE_SW = 0x0F, + CeilingNWSE_NE = 0x10, + CeilingNESW_NW = 0x11, + CeilingNESW_SE = 0x12, +} diff --git a/TRLevelControl/Model/Common/FloorData/Enums/FDTrigAction.cs b/TRLevelControl/Model/Common/FloorData/Enums/FDTrigAction.cs index a8c1e9489..1055dd2ee 100644 --- a/TRLevelControl/Model/Common/FloorData/Enums/FDTrigAction.cs +++ b/TRLevelControl/Model/Common/FloorData/Enums/FDTrigAction.cs @@ -1,19 +1,19 @@ -namespace TRFDControl; +namespace TRLevelControl.Model; public enum FDTrigAction { - Object = 0x00, - Camera = 0x01, + Object = 0x00, + Camera = 0x01, UnderwaterCurrent = 0x02, - FlipMap = 0x03, - FlipOn = 0x04, - FlipOff = 0x05, - LookAtItem = 0x06, - EndLevel = 0x07, - PlaySoundtrack = 0x08, - Flipeffect = 0x09, - SecretFound = 0x0A, - ClearBodies = 0x0B, - Flyby = 0x0C, - Cutscene = 0x0D + FlipMap = 0x03, + FlipOn = 0x04, + FlipOff = 0x05, + LookAtItem = 0x06, + EndLevel = 0x07, + PlaySoundtrack = 0x08, + Flipeffect = 0x09, + SecretFound = 0x0A, + ClearBodies = 0x0B, + Flyby = 0x0C, + Cutscene = 0x0D } diff --git a/TRLevelControl/Model/Common/FloorData/Enums/FDTrigType.cs b/TRLevelControl/Model/Common/FloorData/Enums/FDTrigType.cs index d8cd0a12b..6e8fbfdfb 100644 --- a/TRLevelControl/Model/Common/FloorData/Enums/FDTrigType.cs +++ b/TRLevelControl/Model/Common/FloorData/Enums/FDTrigType.cs @@ -1,22 +1,22 @@ -namespace TRFDControl; +namespace TRLevelControl.Model; public enum FDTrigType { - Trigger = 0x00, - Pad = 0x01, - Switch = 0x02, - Key = 0x03, - Pickup = 0x04, - HeavyTrigger = 0x05, - Antipad = 0x06, - Combat = 0x07, - Dummy = 0x08, - AntiTrigger = 0x09, - HeavySwitch = 0x0A, + Trigger = 0x00, + Pad = 0x01, + Switch = 0x02, + Key = 0x03, + Pickup = 0x04, + HeavyTrigger = 0x05, + Antipad = 0x06, + Combat = 0x07, + Dummy = 0x08, + AntiTrigger = 0x09, + HeavySwitch = 0x0A, HeavyAntiTrigger = 0x0B, - Monkey = 0x0C, - Skeleton = 0x0D, - Tightrope = 0x0E, - Crawl = 0x0F, - Climb = 0x10 + Monkey = 0x0C, + Skeleton = 0x0D, + Tightrope = 0x0E, + Crawl = 0x0F, + Climb = 0x10 } diff --git a/TRLevelControl/Model/Common/FloorData/FDActionItem.cs b/TRLevelControl/Model/Common/FloorData/FDActionItem.cs index be56a312f..c0b12f996 100644 --- a/TRLevelControl/Model/Common/FloorData/FDActionItem.cs +++ b/TRLevelControl/Model/Common/FloorData/FDActionItem.cs @@ -1,54 +1,21 @@ -namespace TRFDControl; +namespace TRLevelControl.Model; -public class FDActionItem +public class FDActionItem : ICloneable { - public ushort Value { get; set; } - - public ushort Parameter - { - get - { - return (ushort)(Value & 0x03FF); - } - set - { - // Remove the current parameter, and add the new one - Value = (ushort)((Value & ~Parameter) | value); - } - } - - public FDTrigAction TrigAction - { - get - { - return (FDTrigAction)((Value & 0x7C00) >> 10); // See Control.c line 30 - } - set - { - Value = (ushort)(Value & ~(Value & 0x7C00)); - Value |= (ushort)((byte)value << 10); - } - } + public FDTrigAction Action { get; set; } + public short Parameter { get; set; } + public FDCameraAction CamAction { get; set; } - public bool Continue + public FDActionItem Clone() { - get - { - //Continue bit set to 0 means to continue, not 1... - return !((Value & 0x8000) > 0); - } - internal set + return new() { - if (value) - { - Value = (ushort)(Value & ~0x8000); - } - else - { - Value |= 0x8000; - } - } + Action = Action, + Parameter = Parameter, + CamAction = CamAction?.Clone() + }; } - public FDCameraAction CamAction { get; set; } + object ICloneable.Clone() + => Clone(); } diff --git a/TRLevelControl/Model/Common/FloorData/FDCameraAction.cs b/TRLevelControl/Model/Common/FloorData/FDCameraAction.cs index 58b4d8cfb..aa4eea5c0 100644 --- a/TRLevelControl/Model/Common/FloorData/FDCameraAction.cs +++ b/TRLevelControl/Model/Common/FloorData/FDCameraAction.cs @@ -1,71 +1,14 @@ -namespace TRFDControl; +namespace TRLevelControl.Model; -public class FDCameraAction +public class FDCameraAction : ICloneable { - public ushort Value { get; set; } + public byte Timer { get; set; } + public bool Once { get; set; } + public byte MoveTimer { get; set; } - public byte Timer - { - get - { - return (byte)(Value & 0x00FF); - } - set - { - Value = (ushort)(Value & ~(Value & 0x00FF)); - Value |= value; - } - } + public FDCameraAction Clone() + => (FDCameraAction)MemberwiseClone(); - public bool Once - { - get - { - return (Value & 0x0100) > 0; - } - set - { - if (value) - { - Value |= 0x0100; - } - else - { - Value = (ushort)(Value & ~0x0100); - } - } - } - - public byte MoveTimer - { - get - { - return (byte)((Value & 0x3E00) >> 9); - } - set - { - Value = (ushort)(Value & ~(Value & 0x3E00)); - Value |= (ushort)(value << 9); - } - } - - public bool Continue - { - get - { - //Continue bit set to 0 means to continue, not 1... - return !((Value & 0x8000) > 0); - } - internal set - { - if (value) - { - Value = (ushort)(Value & ~0x8000); - } - else - { - Value |= 0x8000; - } - } - } + object ICloneable.Clone() + => Clone(); } diff --git a/TRLevelControl/Model/Common/FloorData/FDControl.cs b/TRLevelControl/Model/Common/FloorData/FDControl.cs index 76d733942..3e703615b 100644 --- a/TRLevelControl/Model/Common/FloorData/FDControl.cs +++ b/TRLevelControl/Model/Common/FloorData/FDControl.cs @@ -1,337 +1,698 @@ -using TRFDControl.FDEntryTypes; -using TRLevelControl.Model; +using System.Collections; +using TRLevelControl.Build; -namespace TRFDControl; +namespace TRLevelControl.Model; -public class FDControl +public class FDControl : IEnumerable>> { - private SortedDictionary> _entries; //Key is Sector.FDIndex + private readonly TRGameVersion _version; + private readonly ITRLevelObserver _observer; + private readonly ushort _dummyEntry; + private SortedDictionary> _entries; - public IReadOnlyDictionary> Entries => _entries; + public List this[int index] + { + get => _entries[index]; + set => _entries[index] = value; + } + + public bool ContainsKey(int index) + => _entries.ContainsKey(index); + + public IEnumerator>> GetEnumerator() + => _entries.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => GetEnumerator(); + + public IEnumerable FindAll(Func predicate) + { + return _entries.Values.SelectMany(v => v.Where(predicate)); + } + + public FDControl(TRGameVersion version, ITRLevelObserver observer, ushort dummyData = 0) + { + _version = version; + _observer = observer; + _dummyEntry = dummyData; + _entries = new(); + } - /// - /// Create a slot in the FD for a room sector that currently points to dummy FD. - /// public void CreateFloorData(TRRoomSector sector) { int index; if (_entries.Count == 0) { - // Highly unlikely that we would have cleared all FD, but in any case the - // first index should always be 1 index = 1; } else { - // Get the highest index, which is the last key as we use a SortedDictionary. - // Add the total length of the entries at that key to get the next index for - // allocating to this sector. - index = _entries.Keys.ToList().Last(); - List entries = _entries[index]; - foreach (FDEntry entry in entries) - { - index += entry.Flatten().Length; - } + TRFDBuilder builder = new(_version); + index = _entries.Keys.Last(); + index += builder.Flatten(_entries[index]).Count; } _entries.Add(index, new List()); sector.FDIndex = (ushort)index; } - /// - /// Remove a given room sector's FD and reset its FDIndex to 0. - /// - public void RemoveFloorData(TRRoomSector sector) + public List Flatten(IEnumerable sectors) { - if (_entries.Remove(sector.FDIndex)) + List data = new() { - sector.FDIndex = 0; + _dummyEntry + }; + + // Flatten each entry list and map old indices to new. + TRFDBuilder builder = new(_version, _observer); + Dictionary newIndices = new(); + foreach (int currentIndex in _entries.Keys) + { + List sectorData = builder.Flatten(_entries[currentIndex]); + if (sectorData.Count > 0) + { + newIndices.Add(currentIndex, data.Count); + data.AddRange(sectorData); + } } - } - public void ParseFromLevel (TR1Level level) - { - ParseLevel(level.Rooms.SelectMany(r => r.Sectors), level.FloorData); - } + // Update each TRRoomSector by repointing its FDIndex value to the newly calculated value. + SortedDictionary> _updatedEntries = new(); + foreach (TRRoomSector sector in sectors) + { + ushort index = sector.FDIndex; + if (newIndices.ContainsKey(index)) + { + sector.FDIndex = (ushort)newIndices[index]; - public void ParseFromLevel(TR2Level level) - { - ParseLevel(level.Rooms.SelectMany(r => r.Sectors), level.FloorData); + // Map the list of entries against the new index + _updatedEntries[sector.FDIndex] = _entries[index]; + } + else if (_entries.ContainsKey(index)) + { + // FD has been removed - we only reset it if it was a valid + // previous entry, because some levels (TRUB for ex) have stale + // data. This keeps tests happy. + sector.FDIndex = 0; + } + } + + // Update the stored values in case of further changes + _entries = _updatedEntries; + return data; } - public void ParseFromLevel(TR3Level level) + public List GetEntityTriggers(int entityIndex) { - ParseLevel(level.Rooms.SelectMany(r => r.Sectors), level.FloorData); + return GetTriggers(FDTrigAction.Object, entityIndex); } - public void ParseFromLevel(TR4Level level) + public List GetSecretTriggers(int secretIndex) { - ParseLevel(level.Rooms.SelectMany(r => r.Sectors), level.FloorData); + return GetTriggers(FDTrigAction.SecretFound, secretIndex); } - public void ParseFromLevel(TR5Level level) + public List GetTriggers(FDTrigAction action, int parameter = -1) { - ParseLevel(level.Rooms.SelectMany(r => r.Sectors), level.FloorData); + return _entries.Values + .SelectMany(e => e.Where(i => i is FDTriggerEntry)) + .Cast() + .Where(t => t.Actions.Find(a => a.Action == action && (parameter == -1 || a.Parameter == parameter)) != null) + .ToList(); } - private void ParseLevel(IEnumerable roomSectors, List floorData) + public List GetActionItems(FDTrigAction action, int sectorIndex = -1) { - _entries = new(); - foreach (TRRoomSector sector in roomSectors) + List> entrySearch; + if (sectorIndex == -1) { - ParseFromSector(sector, floorData); + entrySearch = _entries.Values.ToList(); } + else + { + entrySearch = new List> + { + _entries[sectorIndex] + }; + } + + return entrySearch + .SelectMany(e => e.Where(i => i is FDTriggerEntry)) + .Cast() + .SelectMany(t => t.Actions.FindAll(a => a.Action == action)) + .ToList(); } - private void ParseFromSector(TRRoomSector sector, List floorData) + public void RemoveEntityTriggers(int entityIndex) { - ushort index = sector.FDIndex; - // Index 0 is always dummy, so NOOP. - if (index == 0) + foreach (List entries in _entries.Values) { - return; + for (int i = entries.Count - 1; i >= 0; i--) + { + FDEntry entry = entries[i]; + if (entry is not FDTriggerEntry trig) + { + continue; + } + + trig.Actions.RemoveAll(a => a.Action == FDTrigAction.Object && a.Parameter == entityIndex); + if (trig.Actions.Count == 0) + { + entries.RemoveAt(i); + } + } } + } - // List of floordata functions for this sector. - List functions = new(); - _entries[sector.FDIndex] = functions; + public TRRoomSector GetRoomSector(int x, int y, int z, short roomNumber, List rooms) + where R : TRRoom + { + int xFloor, yFloor; + TRRoom room = rooms[roomNumber]; + TRRoomSector sector; + short data; - while (true) + do { - FDSetup data = new() + // Clip position to edge of tile + xFloor = (z - room.Info.Z) >> TRConsts.WallShift; + yFloor = (x - room.Info.X) >> TRConsts.WallShift; + + if (xFloor <= 0) { - Value = floorData[index] - }; + xFloor = 0; + if (yFloor < 1) + { + yFloor = 1; + } + else if (yFloor > room.NumXSectors - 2) + { + yFloor = room.NumXSectors - 2; + } + } + else if (xFloor >= room.NumZSectors - 1) + { + xFloor = room.NumZSectors - 1; + if (yFloor < 1) + { + yFloor = 1; + } + else if (yFloor > room.NumXSectors - 2) + { + yFloor = room.NumXSectors - 2; + } + } + else if (yFloor < 0) + { + yFloor = 0; + } + else if (yFloor >= room.NumXSectors) + { + yFloor = room.NumXSectors - 1; + } - switch ((FDFunction)data.Function) + sector = room.Sectors[xFloor + yFloor * room.NumZSectors]; + data = GetDoor(sector); + if (data != TRConsts.NoRoom && data >= 0 && data < rooms.Count - 1) { - case FDFunction.PortalSector: - functions.Add(new FDPortalEntry - { - Setup = new() { Value = floorData[index] }, - Room = floorData[++index] - }); - break; + room = rooms[data]; + } + } + while (data != TRConsts.NoRoom); - case FDFunction.FloorSlant: - functions.Add(new FDSlantEntry - { - Setup = new() { Value = floorData[index] }, - SlantValue = floorData[++index], - Type = FDSlantType.FloorSlant - }); + if (y >= (sector.Floor << 8)) + { + do + { + if (sector.RoomBelow == TRConsts.NoRoom) + { + return sector; + } + + int triCheck = CheckFloorTriangle(sector, x, z); + if (triCheck == 1) + { break; - - case FDFunction.CeilingSlant: - functions.Add(new FDSlantEntry - { - Setup = new() { Value = floorData[index] }, - SlantValue = floorData[++index], - Type = FDSlantType.CeilingSlant - }); + } + else if (triCheck == -1 && y < room.Info.YBottom) + { break; + } - case FDFunction.Trigger: - - FDTriggerEntry trig = new() - { - Setup = new FDSetup() { Value = floorData[index] }, - TrigSetup = new FDTrigSetup() { Value = floorData[++index] } - }; - functions.Add(trig); - - 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 = floorData[++index]; - } - - // We don't know if there are any more yet. - bool continueFDParse; - - // Do not enter do...while if key/switch ref uint16 does not set continue - if (trig.SwitchKeyContinue) - { - // Parse trigactions - do - { - // New trigger action - FDActionItem action = new() { Value = floorData[++index] }; - trig.TrigActionList.Add(action); - - continueFDParse = action.Continue; - - if (action.TrigAction == FDTrigAction.Camera || action.TrigAction == FDTrigAction.Flyby) - { - // Camera trig actions have a special extra uint16... - FDCameraAction camAction = new() { Value = floorData[++index] }; - - // store associated camera action - action.CamAction = camAction; - - // Is there more? - continueFDParse = camAction.Continue; - } - } - while (index < floorData.Count && continueFDParse); - } + room = rooms[sector.RoomBelow]; + sector = room.Sectors[((z - room.Info.Z) >> TRConsts.WallShift) + ((x - room.Info.X) >> TRConsts.WallShift) * room.NumZSectors]; + } + while (y >= (sector.Floor << 8)); + } + else if (y < (sector.Ceiling << 8)) + { + do + { + if (sector.RoomAbove == TRConsts.NoRoom) + { + return sector; + } + + int triCheck = CheckCeilingTriangle(sector, x, z); + if (triCheck == 1) + { break; - - case FDFunction.KillLara: - functions.Add(new FDKillLaraEntry - { - Setup = new() { Value = floorData[index] } - }); + } + else if (triCheck == -1 && y >= room.Info.YTop) + { break; + } - case FDFunction.ClimbableWalls: - functions.Add(new FDClimbEntry - { - Setup = new() { Value = floorData[index] } - }); - break; + room = rooms[sector.RoomAbove]; + sector = room.Sectors[((z - room.Info.Z) >> TRConsts.WallShift) + ((x - room.Info.X) >> TRConsts.WallShift) * room.NumZSectors]; + } + while (y < (sector.RoomAbove << 8)); + } - case FDFunction.FloorTriangulationNWSE_Solid: - case FDFunction.FloorTriangulationNESW_Solid: - case FDFunction.CeilingTriangulationNW_Solid: - case FDFunction.CeilingTriangulationNE_Solid: - case FDFunction.FloorTriangulationNWSE_SW: - case FDFunction.FloorTriangulationNWSE_NE: - case FDFunction.FloorTriangulationNESW_SE: - case FDFunction.FloorTriangulationNESW_NW: - case FDFunction.CeilingTriangulationNW_SW: - case FDFunction.CeilingTriangulationNW_NE: - case FDFunction.CeilingTriangulationNE_NW: - case FDFunction.CeilingTriangulationNE_SE: - functions.Add(new FDTriangulationEntry - { - Setup = new() { Value = floorData[index] }, - TriData = new() { Value = floorData[++index] } - }); - break; + return sector; + } - case FDFunction.Monkeyswing: - functions.Add(new FDMonkeySwingEntry - { - Setup = new() { Value = floorData[index] }, - }); - break; + public short GetDoor(TRRoomSector sector) + { + if (sector.FDIndex == 0) + { + return TRConsts.NoRoom; + } - case FDFunction.DeferredTriggeringOrMinecartRotateLeft: - functions.Add(new FDMinecartEntry - { - Setup = new() { Value = floorData[index] }, - }); - break; + List entries = _entries[sector.FDIndex]; + foreach (FDEntry entry in entries) + { + if (entry is FDPortalEntry portal) + { + return portal.Room; + } + } - case FDFunction.MechBeetleOrMinecartRotateRight: - functions.Add(new TR3MinecartRotateRightEntry - { - Setup = new() { Value = floorData[index] }, - }); - break; + return TRConsts.NoRoom; + } - default: - break; - } + private int CheckFloorTriangle(TRRoomSector sector, int x, int z) + { + if (sector.FDIndex == 0) + { + return 0; + } - if (data.EndData) + if (_entries[sector.FDIndex].Find(e => e is FDTriangulationEntry) is FDTriangulationEntry triangulation) + { + FDFunction func = triangulation.GetFunction(); + int dx = x & TRConsts.WallMask; + int dz = z & TRConsts.WallMask; + + if (func == FDFunction.FloorTriangulationNWSE_SW && dx <= (TRConsts.Step4 - dz)) { - // 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; + return -1; } - else + else if (func == FDFunction.FloorTriangulationNWSE_NE && dx > (TRConsts.Step4 - dz)) { - // There are further functions for this sector - continue parsing. - index++; + return -1; } + else if (func == FDFunction.FloorTriangulationNESW_SE && dx <= dz) + { + return -1; + } + else if (func == FDFunction.FloorTriangulationNESW_NW && dx > dz) + { + return -1; + } + + return 1; // Bad floor data } - } - public void WriteToLevel(TR1Level level) - { - Flatten(level.Rooms.SelectMany(r => r.Sectors), level.FloorData); + return 0; } - public void WriteToLevel(TR2Level level) + private int CheckCeilingTriangle(TRRoomSector sector, int x, int z) { - Flatten(level.Rooms.SelectMany(r => r.Sectors), level.FloorData); + if (sector.FDIndex == 0) + { + return 0; + } + + if (_entries[sector.FDIndex].Find(e => e is FDTriangulationEntry) is FDTriangulationEntry triangulation) + { + FDFunction func = triangulation.GetFunction(); + int dx = x & TRConsts.WallMask; + int dz = z & TRConsts.WallMask; + + if (func == FDFunction.CeilingTriangulationNW_SW && dx <= (TRConsts.Step4 - dz)) + { + return -1; + } + else if (func == FDFunction.CeilingTriangulationNW_NE && dx > (TRConsts.Step4 - dz)) + { + return -1; + } + else if (func == FDFunction.CeilingTriangulationNE_NW && dx <= dz) + { + return -1; + } + else if (func == FDFunction.CeilingTriangulationNE_SE && dx > dz) + { + return -1; + } + + return 1; // Bad floor data + } + + return 0; } - public void WriteToLevel(TR3Level level) + public int GetHeight(int x, int z, int roomIndex, IEnumerable allRooms, bool waterOnly) + where T : TRRoom { - Flatten(level.Rooms.SelectMany(r => r.Sectors), level.FloorData); + int floor = GetFloorHeight(x, z, roomIndex, allRooms, waterOnly); + int ceiling = GetCeilingHeight(x, z, roomIndex, allRooms, waterOnly); + + if (floor == TRConsts.NoHeight || ceiling == TRConsts.NoHeight) + { + return TRConsts.NoHeight; + } + + return Math.Abs(floor - ceiling); } - public void WriteToLevel(TR4Level level) + public int GetFloorHeight(int x, int z, int roomIndex, IEnumerable allRooms, bool waterOnly) + where T : TRRoom { - Flatten(level.Rooms.SelectMany(r => r.Sectors), level.FloorData); + List rooms = allRooms.ToList(); + + TRRoom room = rooms[roomIndex]; + if (waterOnly && !room.ContainsWater) + { + return TRConsts.NoHeight; + } + + TRRoomSector sector = room.GetSector(x, z); + while (sector.RoomBelow != TRConsts.NoRoom) + { + room = rooms[sector.RoomBelow]; + if (waterOnly && !room.ContainsWater) + { + break; + } + sector = room.GetSector(x, z); + } + + int floor = TRConsts.Step1 * sector.Floor; + floor += GetHeightAdjustment(x, z, FDSlantType.Floor, sector); + + if (_version >= TRGameVersion.TR3) + { + floor += GetTriangulationFloor(x, z, sector); + } + + return floor; } - public void WriteToLevel(TR5Level level) + public int GetCeilingHeight(int x, int z, int roomIndex, IEnumerable allRooms, bool waterOnly) + where T : TRRoom { - Flatten(level.Rooms.SelectMany(r => r.Sectors), level.FloorData); + List rooms = allRooms.ToList(); + + TRRoom room = rooms[roomIndex]; + if (waterOnly && !room.ContainsWater) + { + return TRConsts.NoHeight; + } + + TRRoomSector sector = room.GetSector(x, z); + while (sector.RoomAbove != TRConsts.NoRoom) + { + room = rooms[sector.RoomAbove]; + if (waterOnly && !room.ContainsWater) + { + break; + } + sector = room.GetSector(x, z); + } + + int ceiling = TRConsts.Step1 * sector.Ceiling; + ceiling += GetHeightAdjustment(x, z, FDSlantType.Ceiling, sector); + + if (_version >= TRGameVersion.TR3) + { + ceiling += GetTriangulationCeiling(x, z, sector); + } + + return ceiling; } - private void Flatten(IEnumerable sectors, List data) + public int GetHeightAdjustment(int x, int z, FDSlantType slantType, TRRoomSector sector) { - ushort dummyEntry = data.Count > 0 ? data[0] : (ushort)0; - data.Clear(); - data.Add(dummyEntry); + int adjustment = 0; + if (sector.FDIndex == 0) + { + return adjustment; + } - // Flatten each entry list and map old indices to new. - Dictionary newIndices = new(); - foreach (int currentIndex in _entries.Keys) + FDEntry entry = this[sector.FDIndex].Find(e => e is FDSlantEntry s && s.Type == slantType); + if (entry is not FDSlantEntry slant) { - List sectorData = Flatten(_entries[currentIndex]); - if (sectorData.Count > 0) + return adjustment; + } + + sbyte xoff = slant.XSlant; + sbyte zoff = slant.ZSlant; + + if (xoff < 0) + { + if (slantType == FDSlantType.Floor) { - newIndices.Add(currentIndex, data.Count); - data.AddRange(sectorData); + adjustment -= (xoff * (x & (TRConsts.Step4 - 1))) >> 2; + } + else + { + adjustment += (xoff * ((TRConsts.Step4 - 1 - x) & (TRConsts.Step4 - 1))) >> 2; + } + } + else + { + if (slantType == FDSlantType.Floor) + { + adjustment += (xoff * ((TRConsts.Step4 - 1 - x) & (TRConsts.Step4 - 1))) >> 2; + } + else + { + adjustment -= (xoff * (x & (TRConsts.Step4 - 1))) >> 2; } } - // Update each TRRoomSector by repointing its FDIndex value to the newly calculated value. - SortedDictionary> updatedEntries = new(); - foreach (TRRoomSector sector in sectors) + if (zoff < 0) { - ushort index = sector.FDIndex; - if (newIndices.ContainsKey(index)) + if (slantType == FDSlantType.Floor) { - sector.FDIndex = (ushort)newIndices[index]; + adjustment -= (zoff * (z & (TRConsts.Step4 - 1))) >> 2; + } + else + { + adjustment += (zoff * (z & (TRConsts.Step4 - 1))) >> 2; + } + } + else + { + if (slantType == FDSlantType.Floor) + { + adjustment += (zoff * ((TRConsts.Step4 - 1 - z) & (TRConsts.Step4 - 1))) >> 2; + } + else + { + adjustment -= (zoff * ((TRConsts.Step4 - 1 - z) & (TRConsts.Step4 - 1))) >> 2; + } + } - // Map the list of entries against the new index - updatedEntries[sector.FDIndex] = _entries[index]; + return adjustment; + } + + public int GetTriangulationFloor(int x, int z, TRRoomSector sector) + { + int adjustment = 0; + if (sector.FDIndex == 0) + { + return adjustment; + } + + FDEntry entry = this[sector.FDIndex].Find(e => e is FDTriangulationEntry t && t.IsFloorTriangulation); + if (entry is not FDTriangulationEntry triangulation) + { + return adjustment; + } + + int t0 = triangulation.C10; + int t1 = triangulation.C00; + int t2 = triangulation.C01; + int t3 = triangulation.C11; + int dx = x & (TRConsts.Step4 - 1); + int dz = z & (TRConsts.Step4 - 1); + int xoff = 0; + int zoff = 0; + + if (triangulation.Type != FDTriangulationType.FloorNWSE_Solid + && triangulation.Type != FDTriangulationType.FloorNWSE_SW + && triangulation.Type != FDTriangulationType.FloorNWSE_NE) + { + if (dx <= dz) + { + int hadj = triangulation.H2; + if ((hadj & 0x10) != 0) + { + hadj |= 0xFFF0; + } + + adjustment += hadj << 8; + xoff = t2 - t1; + zoff = t3 - t2; } - else if (_entries.ContainsKey(index)) + else { - // FD has been removed - we only reset it if it was a valid entry before - // because some levels, e.g. most of TRUB, have stale data. - sector.FDIndex = 0; + int hadj = triangulation.H1; + if ((hadj & 0x10) != 0) + { + hadj |= 0xFFF0; + } + + adjustment += hadj << 8; + xoff = t3 - t0; + zoff = t0 - t1; + } + } + else + { + if (dx <= (TRConsts.Step4 - dz)) + { + int hadj = triangulation.H2; + if ((hadj & 0x10) != 0) + { + hadj |= 0xFFF0; + } + + adjustment += hadj << 8; + xoff = t2 - t1; + zoff = t0 - t1; + } + else + { + int hadj = triangulation.H1; + if ((hadj & 0x10) != 0) + { + hadj |= 0xFFF0; + } + + adjustment += hadj << 8; + xoff = t3 - t0; + zoff = t3 - t2; } } - // Update the stored values in case of further changes - _entries = updatedEntries; + if (xoff < 0) + adjustment -= xoff * (z & (TRConsts.Step4 - 1)) >> 2; + else + adjustment += xoff * ((-1 - (ushort)z) & (TRConsts.Step4 - 1)) >> 2; + + if (zoff < 0) + adjustment -= zoff * (x & (TRConsts.Step4 - 1)) >> 2; + else + adjustment += zoff * ((-1 - (ushort)x) & (TRConsts.Step4 - 1)) >> 2; + + return adjustment; } - public static List Flatten(List entries) + public int GetTriangulationCeiling(int x, int z, TRRoomSector sector) { - List data = new(); - for (int i = 0; i < entries.Count; i++) + int adjustment = 0; + if (sector.FDIndex == 0) { - FDEntry function = entries[i]; + return adjustment; + } - // Ensure EndData is set on the last function in the list only - function.Setup.EndData = i == entries.Count - 1; + FDEntry entry = this[sector.FDIndex].Find(e => e is FDTriangulationEntry t && t.IsCeilingTriangulation); + if (entry is not FDTriangulationEntry triangulation) + { + return adjustment; + } - //Convert function to ushort array - ushort[] fdata = function.Flatten(); - data.AddRange(fdata); + const int wallMask = TRConsts.Step4 - 1; + int t0 = -triangulation.C10; + int t1 = -triangulation.C00; + int t2 = -triangulation.C01; + int t3 = -triangulation.C11; + int dx = x & wallMask; + int dz = z & wallMask; + int xoff = 0; + int zoff = 0; + + if (triangulation.Type == FDTriangulationType.CeilingNWSE_Solid + || triangulation.Type == FDTriangulationType.CeilingNWSE_SW + || triangulation.Type == FDTriangulationType.CeilingNWSE_NE) + { + if (dx <= TRConsts.Step4 - dz) + { + int hadj = triangulation.H2; + if ((hadj & 0x10) != 0) + { + hadj |= 0xFFF0; + } + + adjustment += hadj << 8; + xoff = t2 - t1; + zoff = t3 - t2; + } + else + { + int hadj = triangulation.H1; + if ((hadj & 0x10) != 0) + { + hadj |= 0xFFF0; + } + + adjustment += hadj << 8; + xoff = t3 - t0; + zoff = t0 - t1; + } + } + else + { + if (dx <= dz) + { + int hadj = triangulation.H2; + if ((hadj & 0x10) != 0) + { + hadj |= 0xFFF0; + } + + adjustment += hadj << 8; + xoff = t2 - t1; + zoff = t0 - t1; + } + else + { + int hadj = triangulation.H1; + if ((hadj & 0x10) != 0) + { + hadj |= 0xFFF0; + } + + adjustment += hadj << 8; + xoff = t3 - t0; + zoff = t3 - t2; + } } - return data; + if (xoff < 0) + adjustment += ((z & wallMask) * xoff) >> 2; + else + adjustment -= ((-1 - (z & wallMask)) * xoff) >> 2; + + if (zoff < 0) + adjustment += ((-1 - (x & wallMask)) * zoff) >> 2; + else + adjustment -= ((x & wallMask) * zoff) >> 2; + + return adjustment; } } diff --git a/TRLevelControl/Model/Common/FloorData/FDEntry.cs b/TRLevelControl/Model/Common/FloorData/FDEntry.cs index cc8dde691..72c50a972 100644 --- a/TRLevelControl/Model/Common/FloorData/FDEntry.cs +++ b/TRLevelControl/Model/Common/FloorData/FDEntry.cs @@ -1,11 +1,10 @@ -namespace TRFDControl; +namespace TRLevelControl.Model; -public class FDEntry +public abstract class FDEntry : ICloneable { - public FDSetup Setup { get; set; } + public abstract FDFunction GetFunction(); + public abstract FDEntry Clone(); - public virtual ushort[] Flatten() - { - return new ushort[] { Setup.Value }; - } + object ICloneable.Clone() + => Clone(); } diff --git a/TRLevelControl/Model/Common/FloorData/FDLevelExtensions.cs b/TRLevelControl/Model/Common/FloorData/FDLevelExtensions.cs new file mode 100644 index 000000000..bfc90f7a5 --- /dev/null +++ b/TRLevelControl/Model/Common/FloorData/FDLevelExtensions.cs @@ -0,0 +1,34 @@ +namespace TRLevelControl.Model; + +public static class FDLevelExtensions +{ + public static TRRoomSector GetRoomSector(this TR1Level level, int x, int y, int z, short roomNumber) + => level.FloorData.GetRoomSector(x, y, z, roomNumber, level.Rooms); + + public static TRRoomSector GetRoomSector(this TR2Level level, int x, int y, int z, short roomNumber) + => level.FloorData.GetRoomSector(x, y, z, roomNumber, level.Rooms); + + public static TRRoomSector GetRoomSector(this TR3Level level, int x, int y, int z, short roomNumber) + => level.FloorData.GetRoomSector(x, y, z, roomNumber, level.Rooms); + + public static TRRoomSector GetRoomSector(this TR4Level level, int x, int y, int z, short roomNumber) + => level.FloorData.GetRoomSector(x, y, z, roomNumber, level.Rooms); + + public static TRRoomSector GetRoomSector(this TR5Level level, int x, int y, int z, short roomNumber) + => level.FloorData.GetRoomSector(x, y, z, roomNumber, level.Rooms); + + public static TRRoomSector GetRoomSector(this TR1Level level, ITRLocatable location) + => level.FloorData.GetRoomSector(location.X, location.Y, location.Z, location.Room, level.Rooms); + + public static TRRoomSector GetRoomSector(this TR2Level level, ITRLocatable location) + => level.FloorData.GetRoomSector(location.X, location.Y, location.Z, location.Room, level.Rooms); + + public static TRRoomSector GetRoomSector(this TR3Level level, ITRLocatable location) + => level.FloorData.GetRoomSector(location.X, location.Y, location.Z, location.Room, level.Rooms); + + public static TRRoomSector GetRoomSector(this TR4Level level, ITRLocatable location) + => level.FloorData.GetRoomSector(location.X, location.Y, location.Z, location.Room, level.Rooms); + + public static TRRoomSector GetRoomSector(this TR5Level level, ITRLocatable location) + => level.FloorData.GetRoomSector(location.X, location.Y, location.Z, location.Room, level.Rooms); +} diff --git a/TRLevelControl/Model/Common/FloorData/FDSetup.cs b/TRLevelControl/Model/Common/FloorData/FDSetup.cs deleted file mode 100644 index 26a099129..000000000 --- a/TRLevelControl/Model/Common/FloorData/FDSetup.cs +++ /dev/null @@ -1,102 +0,0 @@ -namespace TRFDControl; - -public class FDSetup -{ - public ushort Value { get; set; } - - public FDSetup() { } - - public FDSetup(FDFunction function) - { - Value = (byte)function; - } - - public byte Function - { - get - { - return (byte)(Value & 0x001F); - } - set - { - Value = (ushort)(Value & ~(Value & 0x001F)); - Value |= value; - } - } - - public byte ExtendedFunction - { - get - { - return (byte)(Value & 0x00FF); - } - } - - public byte ExtendedFunctionOnly - { - get - { - return (byte)(Value & 0x00E0); - } - } - - public byte SubFunction - { - get - { - return (byte)((Value & 0x7F00) >> 8); - } - set - { - Value = (ushort)(Value & ~(Value & 0x7F00)); - Value |= (ushort)(value << 8); - } - } - - public bool EndData - { - get - { - return (Value & 0x8000) > 0; - } - internal set - { - if (value) - { - Value |= 0x8000; - } - else - { - Value = (ushort)(Value & ~0x8000); - } - } - } - - #region Triangulation - public sbyte H1 - { - get - { - return (sbyte)((Value & 0x03E0) >> 5); - } - set - { - Value = (ushort)(Value & ~(Value & 0x03E0)); - Value |= (ushort)(value << 5); - } - } - - public sbyte H2 - { - get - { - return (sbyte)((Value & 0x7C00) >> 10); - } - set - { - Value = (ushort)(Value & ~(Value & 0x7C00)); - Value |= (ushort)(value << 10); - } - } - #endregion -} diff --git a/TRLevelControl/Model/Common/FloorData/FDTriangulationData.cs b/TRLevelControl/Model/Common/FloorData/FDTriangulationData.cs deleted file mode 100644 index 2b643e919..000000000 --- a/TRLevelControl/Model/Common/FloorData/FDTriangulationData.cs +++ /dev/null @@ -1,58 +0,0 @@ -namespace TRFDControl; - -public class FDTriangulationData -{ - public ushort Value { get; set; } - - public byte C10 - { - get - { - return (byte)(Value & 0x000F); - } - set - { - Value = (ushort)(Value & ~(Value & 0x000F)); - Value |= value; - } - } - - public byte C00 - { - get - { - return (byte)((Value & 0x00F0) >> 4); - } - set - { - Value = (ushort)(Value & ~(Value & 0x00F0)); - Value |= (ushort)(value << 4); - } - } - - public byte C01 - { - get - { - return (byte)((Value & 0x0F00) >> 8); - } - set - { - Value = (ushort)(Value & ~(Value & 0x0F00)); - Value |= (ushort)(value << 8); - } - } - - public byte C11 - { - get - { - return (byte)((Value & 0xF000) >> 12); - } - set - { - Value = (ushort)(Value & ~(Value & 0xF000)); - Value |= (ushort)(value << 12); - } - } -} diff --git a/TRLevelControl/Model/Common/FloorData/FDTrigSetup.cs b/TRLevelControl/Model/Common/FloorData/FDTrigSetup.cs deleted file mode 100644 index 3f7635fbf..000000000 --- a/TRLevelControl/Model/Common/FloorData/FDTrigSetup.cs +++ /dev/null @@ -1,52 +0,0 @@ -namespace TRFDControl; - -public class FDTrigSetup -{ - public ushort Value { get; set; } - - public byte Timer - { - get - { - return (byte)(Value & 0x00FF); - } - set - { - Value = (ushort)(Value & ~(Value & 0x00FF)); - Value |= value; - } - } - - public bool OneShot - { - get - { - return (Value & 0x0100) > 0; - } - set - { - if (value) - { - Value |= 0x0100; - } - else - { - // Rather than Xor'ing, this allows successive calls with the same bool val - Value = (ushort)(Value & ~0x0100); - } - } - } - - public byte Mask - { - get - { - return (byte)((Value & 0x3E00) >> 9); - } - set - { - Value = (ushort)(Value & ~(Value & 0x3E00)); - Value |= (ushort)(value << 9); - } - } -} diff --git a/TRLevelControl/Model/Common/FloorData/Utilities/FDUtilities.cs b/TRLevelControl/Model/Common/FloorData/Utilities/FDUtilities.cs deleted file mode 100644 index 6d1596915..000000000 --- a/TRLevelControl/Model/Common/FloorData/Utilities/FDUtilities.cs +++ /dev/null @@ -1,458 +0,0 @@ -using TRFDControl.FDEntryTypes; -using TRLevelControl; -using TRLevelControl.Model; - -namespace TRFDControl.Utilities; - -public static class FDUtilities -{ - public static List GetEntityTriggers(FDControl control, int entityIndex) - { - return GetTriggers(control, FDTrigAction.Object, entityIndex); - } - - public static List GetSecretTriggers(FDControl control, int secretIndex) - { - return GetTriggers(control, FDTrigAction.SecretFound, secretIndex); - } - - public static List GetTriggers(FDControl control, FDTrigAction action, int parameter = -1) - { - List entries = new(); - - foreach (List entryList in control.Entries.Values) - { - foreach (FDEntry entry in entryList) - { - if (entry is FDTriggerEntry triggerEntry) - { - int itemIndex = triggerEntry.TrigActionList.FindIndex - ( - i => - i.TrigAction == action && (parameter == -1 || i.Parameter == parameter) - ); - if (itemIndex != -1) - { - entries.Add(triggerEntry); - } - } - } - } - - return entries; - } - - public static List GetActionListItems(FDControl control, FDTrigAction trigAction, int sectorIndex = -1) - { - List items = new(); - - List> entrySearch; - if (sectorIndex == -1) - { - entrySearch = control.Entries.Values.ToList(); - } - else - { - entrySearch = new List> - { - control.Entries[sectorIndex] - }; - } - - foreach (List entryList in entrySearch) - { - foreach (FDEntry entry in entryList) - { - if (entry is FDTriggerEntry triggerEntry) - { - foreach (FDActionItem item in triggerEntry.TrigActionList) - { - if (item.TrigAction == trigAction) - { - items.Add(item); - } - } - } - } - } - - return items; - } - - public static void RemoveEntityTriggers(TR1Level level, int entityIndex, FDControl control) - => RemoveEntityTriggers(level.Rooms.SelectMany(r => r.Sectors), entityIndex, control); - - public static void RemoveEntityTriggers(TR2Level level, int entityIndex, FDControl control) - => RemoveEntityTriggers(level.Rooms.SelectMany(r => r.Sectors), entityIndex, control); - - public static void RemoveEntityTriggers(TR3Level level, int entityIndex, FDControl control) - => RemoveEntityTriggers(level.Rooms.SelectMany(r => r.Sectors), entityIndex, control); - - public static void RemoveEntityTriggers(IEnumerable sectorList, int entityIndex, FDControl control) - { - foreach (TRRoomSector sector in sectorList) - { - if (sector.FDIndex == 0) - { - continue; - } - - List entries = control.Entries[sector.FDIndex]; - for (int i = entries.Count - 1; i >= 0; i--) - { - FDEntry entry = entries[i]; - if (entry is FDTriggerEntry trig) - { - trig.TrigActionList.RemoveAll(a => a.TrigAction == FDTrigAction.Object && a.Parameter == entityIndex); - if (trig.TrigActionList.Count == 0) - { - entries.RemoveAt(i); - } - } - } - - if (entries.Count == 0) - { - // If there isn't anything left, reset the sector to point to the dummy FD - control.RemoveFloorData(sector); - } - } - } - - public static TRRoomSector GetRoomSector(int x, int z, List sectors, TRRoomInfo info, ushort roomDepth) - { - int xFloor = (x - info.X) >> TRConsts.WallShift; - int zFloor = (z - info.Z) >> TRConsts.WallShift; - return sectors[xFloor * roomDepth + zFloor]; - } - - public static TRRoomSector GetRoomSector(int x, int y, int z, short roomNumber, TR1Level level, FDControl floorData) - => GetRoomSector(x, y, z, roomNumber, level.Rooms, floorData); - - public static TRRoomSector GetRoomSector(int x, int y, int z, short roomNumber, TR2Level level, FDControl floorData) - => GetRoomSector(x, y, z, roomNumber, level.Rooms, floorData); - - public static TRRoomSector GetRoomSector(int x, int y, int z, short roomNumber, TR3Level level, FDControl floorData) - => GetRoomSector(x, y, z, roomNumber, level.Rooms, floorData); - - public static TRRoomSector GetRoomSector(int x, int y, int z, short roomNumber, List rooms, FDControl floorData) - where R : TRRoom - { - int xFloor, yFloor; - TRRoom room = rooms[roomNumber]; - TRRoomSector sector; - short data; - - do - { - // Clip position to edge of tile - xFloor = (z - room.Info.Z) >> TRConsts.WallShift; - yFloor = (x - room.Info.X) >> TRConsts.WallShift; - - if (xFloor <= 0) - { - xFloor = 0; - if (yFloor < 1) - { - yFloor = 1; - } - else if (yFloor > room.NumXSectors - 2) - { - yFloor = room.NumXSectors - 2; - } - } - else if (xFloor >= room.NumZSectors - 1) - { - xFloor = room.NumZSectors - 1; - if (yFloor < 1) - { - yFloor = 1; - } - else if (yFloor > room.NumXSectors - 2) - { - yFloor = room.NumXSectors - 2; - } - } - else if (yFloor < 0) - { - yFloor = 0; - } - else if (yFloor >= room.NumXSectors) - { - yFloor = room.NumXSectors - 1; - } - - sector = room.Sectors[xFloor + yFloor * room.NumZSectors]; - data = GetDoor(sector, floorData); - if (data != TRConsts.NoRoom && data >= 0 && data < rooms.Count - 1) - { - room = rooms[data]; - } - } - while (data != TRConsts.NoRoom); - - if (y >= (sector.Floor << 8)) - { - do - { - if (sector.RoomBelow == TRConsts.NoRoom) - { - return sector; - } - - int triCheck = CheckFloorTriangle(floorData, sector, x, z); - if (triCheck == 1) - { - break; - } - else if (triCheck == -1 && y < room.Info.YBottom) - { - break; - } - - room = rooms[sector.RoomBelow]; - sector = room.Sectors[((z - room.Info.Z) >> TRConsts.WallShift) + ((x - room.Info.X) >> TRConsts.WallShift) * room.NumZSectors]; - } - while (y >= (sector.Floor << 8)); - } - else if (y < (sector.Ceiling << 8)) - { - do - { - if (sector.RoomAbove == TRConsts.NoRoom) - { - return sector; - } - - int triCheck = CheckCeilingTriangle(floorData, sector, x, z); - if (triCheck == 1) - { - break; - } - else if (triCheck == -1 && y >= room.Info.YTop) - { - break; - } - - room = rooms[sector.RoomAbove]; - sector = room.Sectors[((z - room.Info.Z) >> TRConsts.WallShift) + ((x - room.Info.X) >> TRConsts.WallShift) * room.NumZSectors]; - } - while (y < (sector.RoomAbove << 8)); - } - - return sector; - } - - public static short GetDoor(TRRoomSector sector, FDControl floorData) - { - if (sector.FDIndex == 0) - { - return TRConsts.NoRoom; - } - - List entries = floorData.Entries[sector.FDIndex]; - foreach (FDEntry entry in entries) - { - if (entry is FDPortalEntry portal) - { - return (short)portal.Room; - } - } - - return TRConsts.NoRoom; - } - - private static int CheckFloorTriangle(FDControl floorData, TRRoomSector sector, int x, int z) - { - if (sector.FDIndex == 0) - { - return 0; - } - - if (floorData.Entries[sector.FDIndex].Find(e => e is FDTriangulationEntry) is FDTriangulationEntry triangulation) - { - FDFunction func = (FDFunction)triangulation.Setup.Value; - int dx = x & TRConsts.WallMask; - int dz = z & TRConsts.WallMask; - - if (func == FDFunction.FloorTriangulationNWSE_SW && dx <= (TRConsts.Step4 - dz)) - { - return -1; - } - else if (func == FDFunction.FloorTriangulationNWSE_NE && dx > (TRConsts.Step4 - dz)) - { - return -1; - } - else if (func == FDFunction.FloorTriangulationNESW_SE && dx <= dz) - { - return -1; - } - else if (func == FDFunction.FloorTriangulationNESW_NW && dx > dz) - { - return -1; - } - - return 1; // Bad floor data - } - - return 0; - } - - private static int CheckCeilingTriangle(FDControl floorData, TRRoomSector sector, int x, int z) - { - if (sector.FDIndex == 0) - { - return 0; - } - - if (floorData.Entries[sector.FDIndex].Find(e => e is FDTriangulationEntry) is FDTriangulationEntry triangulation) - { - FDFunction func = (FDFunction)triangulation.Setup.Value; - int dx = x & TRConsts.WallMask; - int dz = z & TRConsts.WallMask; - - if (func == FDFunction.CeilingTriangulationNW_SW && dx <= (TRConsts.Step4 - dz)) - { - return -1; - } - else if (func == FDFunction.CeilingTriangulationNW_NE && dx > (TRConsts.Step4 - dz)) - { - return -1; - } - else if (func == FDFunction.CeilingTriangulationNE_NW && dx <= dz) - { - return -1; - } - else if (func == FDFunction.CeilingTriangulationNE_SE && dx > dz) - { - return -1; - } - - return 1; // Bad floor data - } - - return 0; - } - - public static int GetHeight(int x, int z, short roomIndex, TR1Level level, FDControl floorData, bool waterOnly) - => GetHeight(x, z, roomIndex, level.Rooms, floorData, waterOnly); - - public static int GetHeight(int x, int z, short roomIndex, TR2Level level, FDControl floorData, bool waterOnly) - => GetHeight(x, z, roomIndex, level.Rooms, floorData, waterOnly); - - public static int GetHeight(int x, int z, short roomIndex, TR3Level level, FDControl floorData, bool waterOnly) - => GetHeight(x, z, roomIndex, level.Rooms, floorData, waterOnly); - - public static int GetHeight(int x, int z, short roomIndex, List rooms, FDControl floorData, bool waterOnly) - where R : TRRoom - { - TRRoom room = rooms[roomIndex]; - if (waterOnly && !room.ContainsWater) - { - return TRConsts.NoHeight; - } - - TRRoomSector baseSector = GetRoomSector(x, z, room.Sectors, room.Info, room.NumZSectors); - TRRoomSector floorSector = baseSector; - while (floorSector.RoomBelow != TRConsts.NoRoom) - { - room = rooms[floorSector.RoomBelow]; - if (waterOnly && !room.ContainsWater) - { - break; - } - floorSector = GetRoomSector(x, z, room.Sectors, room.Info, room.NumZSectors); - } - - TRRoomSector ceilingSector = baseSector; - while (ceilingSector.RoomAbove != TRConsts.NoRoom) - { - room = rooms[ceilingSector.RoomAbove]; - if (waterOnly && !room.ContainsWater) - { - break; - } - ceilingSector = GetRoomSector(x, z, room.Sectors, room.Info, room.NumZSectors); - } - - return GetHeight(x, z, floorSector, ceilingSector, floorData); - } - - public static int GetHeight(int x, int z, TRRoomSector floorSector, TRRoomSector ceilingSector, FDControl floorData) - { - int floor = TRConsts.Step1 * floorSector.Floor; - int ceiling = TRConsts.Step1 * ceilingSector.Ceiling; - - floor += GetHeightAdjustment(x, z, FDSlantType.FloorSlant, floorSector, floorData); - ceiling += GetHeightAdjustment(x, z, FDSlantType.CeilingSlant, ceilingSector, floorData); - - int height = Math.Abs(floor - ceiling); - return height + height % 2; - } - - public static int GetHeightAdjustment(int x, int z, FDSlantType slantType, TRRoomSector sector, FDControl floorData) - { - int adjustment = 0; - if (sector.FDIndex == 0) - { - return adjustment; - } - - FDEntry entry = floorData.Entries[sector.FDIndex].Find(e => e is FDSlantEntry s && s.Type == slantType); - if (entry is not FDSlantEntry slant) - { - return adjustment; - } - - sbyte xoff = slant.XSlant; - sbyte zoff = slant.ZSlant; - - if (xoff < 0) - { - if (slantType == FDSlantType.FloorSlant) - { - adjustment -= (xoff * (x & TRConsts.WallMask)) >> 2; - } - else - { - adjustment += (xoff * ((TRConsts.WallMask - x) & TRConsts.WallMask)) >> 2; - } - } - else - { - if (slantType == FDSlantType.FloorSlant) - { - adjustment += (xoff * ((TRConsts.WallMask - x) & TRConsts.WallMask)) >> 2; - } - else - { - adjustment -= (xoff * (x & TRConsts.WallMask)) >> 2; - } - } - - if (zoff < 0) - { - if (slantType == FDSlantType.FloorSlant) - { - adjustment -= (zoff * (z & TRConsts.WallMask)) >> 2; - } - else - { - adjustment += (zoff * (z & TRConsts.WallMask)) >> 2; - } - } - else - { - if (slantType == FDSlantType.FloorSlant) - { - adjustment += (zoff * ((TRConsts.WallMask - z) & TRConsts.WallMask)) >> 2; - } - else - { - adjustment -= (zoff * ((TRConsts.WallMask - z) & TRConsts.WallMask)) >> 2; - } - } - - return adjustment; - } -} diff --git a/TRLevelControl/Model/Common/ITREntity.cs b/TRLevelControl/Model/Common/ITREntity.cs index a87fb8132..f8704f7a7 100644 --- a/TRLevelControl/Model/Common/ITREntity.cs +++ b/TRLevelControl/Model/Common/ITREntity.cs @@ -1,10 +1,5 @@ namespace TRLevelControl.Model; -public interface ITREntity : ICloneable +public interface ITREntity : ICloneable, ITRLocatable { - public int X { get; set; } - public int Y { get; set; } - public int Z { get; set; } - public short Room { get; set; } - public short Angle { get; set; } } diff --git a/TRLevelControl/Model/Common/ITRLocatable.cs b/TRLevelControl/Model/Common/ITRLocatable.cs new file mode 100644 index 000000000..792eda780 --- /dev/null +++ b/TRLevelControl/Model/Common/ITRLocatable.cs @@ -0,0 +1,10 @@ +namespace TRLevelControl.Model; + +public interface ITRLocatable +{ + int X { get; set; } + int Y { get; set; } + int Z { get; set; } + short Room { get; set; } + short Angle { get; set; } +} diff --git a/TRLevelControl/Model/Common/TRRoom.cs b/TRLevelControl/Model/Common/TRRoom.cs index 10faac37b..06de0ec4f 100644 --- a/TRLevelControl/Model/Common/TRRoom.cs +++ b/TRLevelControl/Model/Common/TRRoom.cs @@ -45,4 +45,22 @@ public bool IsSwamp get => Flags.HasFlag(TRRoomFlag.SwampOrNoLensflare); set => SetFlag(TRRoomFlag.SwampOrNoLensflare, value); } + + public TRRoomSector GetSector(int x, int z, TRUnit unit = TRUnit.World) + { + switch (unit) + { + case TRUnit.Room: + x /= TRConsts.Step4; + z /= TRConsts.Step4; + break; + case TRUnit.World: + x = Math.Min(Math.Max(x, Info.X), Info.X + (NumXSectors - 1) * TRConsts.Step4); + z = Math.Min(Math.Max(z, Info.Z), Info.Z + (NumZSectors - 1) * TRConsts.Step4); + x = (x - Info.X) / TRConsts.Step4; + z = (z - Info.Z) / TRConsts.Step4; + break; + } + return Sectors[x * NumZSectors + z]; + } } diff --git a/TRLevelControl/Model/TR1/TR1Level.cs b/TRLevelControl/Model/TR1/TR1Level.cs index 1a50a0791..aa36ad1b6 100644 --- a/TRLevelControl/Model/TR1/TR1Level.cs +++ b/TRLevelControl/Model/TR1/TR1Level.cs @@ -4,7 +4,6 @@ public class TR1Level : TRLevelBase { public List Images8 { get; set; } public List Rooms { get; set; } - public List FloorData { get; set; } public TRDictionary Models { get; set; } public TRDictionary StaticMeshes { get; set; } public List ObjectTextures { get; set; } diff --git a/TRLevelControl/Model/TR2/TR2Level.cs b/TRLevelControl/Model/TR2/TR2Level.cs index e29aee993..341198126 100644 --- a/TRLevelControl/Model/TR2/TR2Level.cs +++ b/TRLevelControl/Model/TR2/TR2Level.cs @@ -7,7 +7,6 @@ public class TR2Level : TRLevelBase public List Images8 { get; set; } public List Images16 { get; set; } public List Rooms { get; set; } - public List FloorData { get; set; } public TRDictionary Models { get; set; } public TRDictionary StaticMeshes { get; set; } public List ObjectTextures { get; set; } diff --git a/TRLevelControl/Model/TR3/TR3Level.cs b/TRLevelControl/Model/TR3/TR3Level.cs index d14c3d1c1..39c51d6e3 100644 --- a/TRLevelControl/Model/TR3/TR3Level.cs +++ b/TRLevelControl/Model/TR3/TR3Level.cs @@ -7,7 +7,6 @@ public class TR3Level : TRLevelBase public List Images8 { get; set; } public List Images16 { get; set; } public List Rooms { get; set; } - public List FloorData { get; set; } public TRDictionary Models { get; set; } public TRDictionary StaticMeshes { get; set; } public TRDictionary Sprites { get; set; } diff --git a/TRLevelControl/Model/TR4/TR4Level.cs b/TRLevelControl/Model/TR4/TR4Level.cs index 51ff92046..0e92f4af8 100644 --- a/TRLevelControl/Model/TR4/TR4Level.cs +++ b/TRLevelControl/Model/TR4/TR4Level.cs @@ -4,7 +4,6 @@ public class TR4Level : TRLevelBase { public TR4Textiles Images { get; set; } public List Rooms { get; set; } - public List FloorData { get; set; } public TRDictionary Models { get; set; } public TRDictionary StaticMeshes { get; set; } public TRDictionary Sprites { get; set; } diff --git a/TRLevelControl/Model/TR5/TR5Level.cs b/TRLevelControl/Model/TR5/TR5Level.cs index 39325ddfc..a476f5068 100644 --- a/TRLevelControl/Model/TR5/TR5Level.cs +++ b/TRLevelControl/Model/TR5/TR5Level.cs @@ -6,7 +6,6 @@ public class TR5Level : TRLevelBase public ushort LaraType { get; set; } public ushort WeatherType { get; set; } public List Rooms { get; set; } - public List FloorData { get; set; } public TRDictionary Models { get; set; } public TRDictionary StaticMeshes { get; set; } public TRDictionary Sprites { get; set; } diff --git a/TRLevelControl/Model/TRLevelBase.cs b/TRLevelControl/Model/TRLevelBase.cs index ed4cf1e4e..670077050 100644 --- a/TRLevelControl/Model/TRLevelBase.cs +++ b/TRLevelControl/Model/TRLevelBase.cs @@ -3,5 +3,6 @@ public abstract class TRLevelBase { public TRVersion Version { get; set; } + public FDControl FloorData { get; set; } public abstract IEnumerable DistinctMeshes { get; } } diff --git a/TRLevelControlTests/Base/FDTestBase.cs b/TRLevelControlTests/Base/FDTestBase.cs new file mode 100644 index 000000000..573396d46 --- /dev/null +++ b/TRLevelControlTests/Base/FDTestBase.cs @@ -0,0 +1,103 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TRLevelControl; +using TRLevelControl.Model; + +namespace TRLevelControlTests; + +public class FDTestBase : TestBase +{ + protected static void TestSectorEdges(TRRoom room, int x, int z) + { + // Ensure we are anchored to the sector midpoint + int rootX = (x / TRConsts.Step4) * TRConsts.Step4 + TRConsts.Step2; + int rootZ = (z / TRConsts.Step4) * TRConsts.Step4 + TRConsts.Step2; + + void Reset() + { + x = rootX; + z = rootZ; + } + + Assert.AreEqual(TRConsts.Step2, rootX % TRConsts.Step4); + Assert.AreEqual(TRConsts.Step2, rootZ % TRConsts.Step4); + Reset(); + + TRRoomSector sector1 = room.GetSector(x, z, TRUnit.World); + + // On the -x edge + x -= TRConsts.Step2; + TRRoomSector sector2 = room.GetSector(x, z, TRUnit.World); + Assert.AreEqual(sector1, sector2); + Reset(); + + // On the -z edge + z -= TRConsts.Step2; + sector2 = room.GetSector(x, z, TRUnit.World); + Assert.AreEqual(sector1, sector2); + Reset(); + + // Just over the -x edge + x -= TRConsts.Step2 + 1; + sector2 = room.GetSector(x, z, TRUnit.World); + Assert.AreNotEqual(sector1, sector2); + Reset(); + + // Just over the -z edge + z -= TRConsts.Step2 + 1; + sector2 = room.GetSector(x, z, TRUnit.World); + Assert.AreNotEqual(sector1, sector2); + Reset(); + + // Just over both -edges + x -= TRConsts.Step2 + 1; + z -= TRConsts.Step2 + 1; + sector2 = room.GetSector(x, z, TRUnit.World); + Assert.AreNotEqual(sector1, sector2); + Reset(); + + + // On the +x edge + x += TRConsts.Step2 - 1; + sector2 = room.GetSector(x, z, TRUnit.World); + Assert.AreEqual(sector1, sector2); + Reset(); + + // On the +z edge + z += TRConsts.Step2 - 1; + sector2 = room.GetSector(x, z, TRUnit.World); + Assert.AreEqual(sector1, sector2); + Reset(); + + // Just over the +x edge + x += TRConsts.Step2; + sector2 = room.GetSector(x, z, TRUnit.World); + Assert.AreNotEqual(sector1, sector2); + Reset(); + + // Just over the +z edge + z += TRConsts.Step2; + sector2 = room.GetSector(x, z, TRUnit.World); + Assert.AreNotEqual(sector1, sector2); + Reset(); + + // Just over both +edges + x += TRConsts.Step2; + z += TRConsts.Step2; + sector2 = room.GetSector(x, z, TRUnit.World); + Assert.AreNotEqual(sector1, sector2); + } + + protected static void TestGetEntityTriggers(FDControl floorData, int entityIndex) + { + List triggers = floorData.GetEntityTriggers(entityIndex); + Assert.AreNotEqual(0, triggers.Count); + Assert.IsTrue(triggers.All(t => t.Actions.Find(a => a.Action == FDTrigAction.Object && a.Parameter == entityIndex) != null)); + } + + protected static void TestGetSecretTriggers(FDControl floorData, int secretIndex) + { + List triggers = floorData.GetSecretTriggers(secretIndex); + Assert.AreNotEqual(0, triggers.Count); + Assert.IsTrue(triggers.All(t => t.Actions.Find(a => a.Action == FDTrigAction.SecretFound && a.Parameter == secretIndex) != null)); + } +} diff --git a/TRLevelControlTests/Base/Observers/ObserverBase.cs b/TRLevelControlTests/Base/Observers/ObserverBase.cs index d48f3ed1b..b9a66d2e4 100644 --- a/TRLevelControlTests/Base/Observers/ObserverBase.cs +++ b/TRLevelControlTests/Base/Observers/ObserverBase.cs @@ -17,6 +17,7 @@ public virtual void OnChunkRead(long startPosition, long endPosition, TRChunkTyp public virtual void OnChunkWritten(long startPosition, long endPosition, TRChunkType chunkType, byte[] data) { } + public virtual bool UseOriginalFloorData => true; public virtual bool UseTR5RawRooms => false; public virtual void OnRawTR5RoomsRead(List data) diff --git a/TRLevelControlTests/Levels/TR1/TEST1.PHD b/TRLevelControlTests/Levels/TR1/TEST1.PHD new file mode 100644 index 000000000..203cc2960 Binary files /dev/null and b/TRLevelControlTests/Levels/TR1/TEST1.PHD differ diff --git a/TRLevelControlTests/Levels/TR1/TEST2.PHD b/TRLevelControlTests/Levels/TR1/TEST2.PHD new file mode 100644 index 000000000..ff9f4b117 Binary files /dev/null and b/TRLevelControlTests/Levels/TR1/TEST2.PHD differ diff --git a/TRLevelControlTests/Levels/TR2/TEST1.TR2 b/TRLevelControlTests/Levels/TR2/TEST1.TR2 new file mode 100644 index 000000000..1be61234b Binary files /dev/null and b/TRLevelControlTests/Levels/TR2/TEST1.TR2 differ diff --git a/TRLevelControlTests/Levels/TR2/TEST2.TR2 b/TRLevelControlTests/Levels/TR2/TEST2.TR2 new file mode 100644 index 000000000..4fa6a80c1 Binary files /dev/null and b/TRLevelControlTests/Levels/TR2/TEST2.TR2 differ diff --git a/TRLevelControlTests/Levels/TR3/TEST1.TR2 b/TRLevelControlTests/Levels/TR3/TEST1.TR2 new file mode 100644 index 000000000..49895b8da Binary files /dev/null and b/TRLevelControlTests/Levels/TR3/TEST1.TR2 differ diff --git a/TRLevelControlTests/Levels/TR3/TEST2.TR2 b/TRLevelControlTests/Levels/TR3/TEST2.TR2 new file mode 100644 index 000000000..39e075605 Binary files /dev/null and b/TRLevelControlTests/Levels/TR3/TEST2.TR2 differ diff --git a/TRLevelControlTests/Levels/TR4/TEST1.TR4 b/TRLevelControlTests/Levels/TR4/TEST1.TR4 new file mode 100644 index 000000000..15373ffc3 Binary files /dev/null and b/TRLevelControlTests/Levels/TR4/TEST1.TR4 differ diff --git a/TRLevelControlTests/Levels/TR4/TEST2.TR4 b/TRLevelControlTests/Levels/TR4/TEST2.TR4 new file mode 100644 index 000000000..6b9f66a30 Binary files /dev/null and b/TRLevelControlTests/Levels/TR4/TEST2.TR4 differ diff --git a/TRLevelControlTests/TR1/FDTests.cs b/TRLevelControlTests/TR1/FDTests.cs new file mode 100644 index 000000000..9a2b6cf48 --- /dev/null +++ b/TRLevelControlTests/TR1/FDTests.cs @@ -0,0 +1,571 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TRLevelControl; +using TRLevelControl.Model; + +namespace TRLevelControlTests.TR1; + +[TestClass] +[TestCategory("OriginalIO")] +public class FDTests : FDTestBase +{ + [TestMethod] + [Description("Get a sector using sector units.")] + public void GetSectorByVal() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room = level.Rooms[0]; + TRRoomSector sector = room.GetSector(5, 9, TRUnit.Sector); + + Assert.AreEqual(5 * room.NumZSectors + 9, room.Sectors.IndexOf(sector)); + } + + [TestMethod] + [Description("Get a sector using room units.")] + public void GetSectorByRoomPos() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room = level.Rooms[0]; + TRRoomSector sector = room.GetSector(5632, 9728, TRUnit.Room); + + Assert.AreEqual(5 * room.NumZSectors + 9, room.Sectors.IndexOf(sector)); + } + + [TestMethod] + [Description("Get a sector using world units.")] + public void GetSectorByWorldPos() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room = level.Rooms[0]; + TRRoomSector sector = room.GetSector(9728, 18944, TRUnit.World); + + Assert.AreEqual(5 * room.NumZSectors + 9, room.Sectors.IndexOf(sector)); + } + + [TestMethod] + [Description("Get a sector using OOB world units (X-).")] + public void GetSectorByOOBXNeg() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room = level.Rooms[0]; + TRRoomSector sector = room.GetSector(512, 22016, TRUnit.World); + + Assert.AreEqual(0 * room.NumZSectors + 12, room.Sectors.IndexOf(sector)); + } + + [TestMethod] + [Description("Get a sector using OOB world units (X+).")] + public void GetSectorByOOBXPos() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room = level.Rooms[0]; + TRRoomSector sector = room.GetSector(11776, 22016, TRUnit.World); + + Assert.AreEqual(6 * room.NumZSectors + 12, room.Sectors.IndexOf(sector)); + } + + [TestMethod] + [Description("Get a sector using OOB world units (Z+).")] + public void GetSectorByOOBZPos() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room = level.Rooms[0]; + TRRoomSector sector = room.GetSector(5632, 24064, TRUnit.World); + + Assert.AreEqual(1 * room.NumZSectors + 13, room.Sectors.IndexOf(sector)); + } + + [TestMethod] + [Description("Get a sector using OOB world units (Z-).")] + public void GetSectorByOOBZNeg() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room = level.Rooms[0]; + TRRoomSector sector = room.GetSector(5632, 8704, TRUnit.World); + + Assert.AreEqual(1 * room.NumZSectors + 0, room.Sectors.IndexOf(sector)); + } + + [TestMethod] + [Description("Get a sector using OOB world units (X-Z+).")] + public void GetSectorByOOBXNegZPos() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room = level.Rooms[0]; + TRRoomSector sector = room.GetSector(512, 24064, TRUnit.World); + + Assert.AreEqual(0 * room.NumZSectors + 13, room.Sectors.IndexOf(sector)); + } + + [TestMethod] + [Description("Get a sector using OOB world units (X+Z+).")] + public void GetSectorByOOBXPosZPos() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room = level.Rooms[0]; + TRRoomSector sector = room.GetSector(11776, 24064, TRUnit.World); + + Assert.AreEqual(6 * room.NumZSectors + 13, room.Sectors.IndexOf(sector)); + } + + [TestMethod] + [Description("Get a sector using OOB world units (X-Z-).")] + public void GetSectorByOOBXNegZNeg() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room = level.Rooms[0]; + TRRoomSector sector = room.GetSector(512, 8704, TRUnit.World); + + Assert.AreEqual(0 * room.NumZSectors + 0, room.Sectors.IndexOf(sector)); + } + + [TestMethod] + [Description("Get a sector using OOB world units (X+Z-).")] + public void GetSectorByOOBXPosZNeg() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room = level.Rooms[0]; + TRRoomSector sector = room.GetSector(11776, 8704, TRUnit.World); + + Assert.AreEqual(6 * room.NumZSectors + 0, room.Sectors.IndexOf(sector)); + } + + [TestMethod] + [Description("Get sector edge cases.")] + public void GetSectorEdges() + { + TR1Level level = GetTR1TestLevel(); + TestSectorEdges(level.Rooms[0], 6656, 18944); + } + + [TestMethod] + [Description("Get a sector on a portal.")] + public void GetSectorOnPortal() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room = level.Rooms[0]; + TRRoomSector sector = room.GetSector(3, 0, TRUnit.Sector); + + Assert.AreEqual(42, room.Sectors.IndexOf(sector)); + Assert.AreNotEqual(0, sector.FDIndex); + Assert.IsNotNull(level.FloorData[sector.FDIndex].Find(e => e is FDPortalEntry)); + } + + [TestMethod] + [Description("Get a sector through a horizontal portal.")] + public void GetSectorBeyondHPortal() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room0 = level.Rooms[0]; + TRRoom room4 = level.Rooms[4]; + TRRoomSector sector = level.GetRoomSector(3584, 0, 14848, 0); + + Assert.IsFalse(room0.Sectors.Contains(sector)); + Assert.IsTrue(room4.Sectors.Contains(sector)); + Assert.IsTrue(room0.Sectors.Where(s => s.FDIndex != 0) + .Any(s => level.FloorData[s.FDIndex].Any(e => e is FDPortalEntry portal && portal.Room == 4))); + } + + [TestMethod] + [Description("Get a sector below a vertical portal.")] + public void GetSectorBelowVPortal() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room0 = level.Rooms[0]; + TRRoom room1 = level.Rooms[1]; + TRRoomSector sector = level.GetRoomSector(8704, 256, 13824, 0); + + Assert.IsFalse(room0.Sectors.Contains(sector)); + Assert.IsTrue(room1.Sectors.Contains(sector)); + Assert.AreEqual(0, sector.RoomAbove); + } + + [TestMethod] + [Description("Get a sector above a vertical portal.")] + public void GetSectorAboveVPortal() + { + TR1Level level = GetTR1TestLevel(); + TRRoom room1 = level.Rooms[1]; + TRRoom room0 = level.Rooms[0]; + TRRoomSector sector = level.GetRoomSector(8704, -256, 13824, 1); + + Assert.IsFalse(room1.Sectors.Contains(sector)); + Assert.IsTrue(room0.Sectors.Contains(sector)); + Assert.AreEqual(1, sector.RoomBelow); + } + + [TestMethod] + public void GetFlatFloorHeight() + { + TR1Level level = GetTR1TestLevel(); + int height = level.FloorData.GetFloorHeight(6320, 19776, 0, level.Rooms, false); + int sectorHeight = level.Rooms[0].GetSector(6320, 19776).Floor * TRConsts.Step1; + Assert.AreEqual(sectorHeight, height); + } + + [TestMethod] + public void GetSlantedFloorHeight() + { + TR1Level level = GetTR1TestLevel(); + int height = level.FloorData.GetFloorHeight(9394, 19272, 0, level.Rooms, false); + Assert.AreEqual(-90, height); + } + + [TestMethod] + public void GetFlatCeilingHeight() + { + TR1Level level = GetTR1TestLevel(); + int height = level.FloorData.GetCeilingHeight(6491, 20981, 0, level.Rooms, false); + int sectorHeight = level.Rooms[0].GetSector(6491, 20981).Ceiling * TRConsts.Step1; + Assert.AreEqual(sectorHeight, height); + } + + [TestMethod] + public void GetSlantedCeilingHeight() + { + TR1Level level = GetTR1TestLevel(); + int height = level.FloorData.GetCeilingHeight(5467, 20981, 0, level.Rooms, false); + Assert.AreEqual(-2902, height); + } + + [TestMethod] + public void GetFlatWaterHeight() + { + TR1Level level = GetTR1TestLevel(); + int height = level.FloorData.GetHeight(15872, 13824, 8, level.Rooms, true); + Assert.AreEqual(1024, height); + } + + [TestMethod] + public void GetSlopedWaterHeight() + { + TR1Level level = GetTR1TestLevel(); + int height = level.FloorData.GetHeight(15872, 12800, 8, level.Rooms, true); + Assert.AreEqual(639, height); + } + + [TestMethod] + [Description("Add a trigger.")] + public void AddTrigger() + { + TR1Level level = GetTR1TestLevel(); + + TRRoomSector sector = level.Rooms[0].GetSector(3, 7, TRUnit.Sector); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + Assert.AreNotEqual(0, sector.FDIndex); + + ushort fdIndex = sector.FDIndex; + + List entries = level.FloorData[fdIndex]; + Assert.AreEqual(0, entries.Count); + + FDTriggerEntry trigger = new() + { + TrigType = FDTrigType.Pad, + OneShot = true, + Mask = 1 << 2, + Timer = 10, + Actions = new() + { + new() + { + Action = FDTrigAction.PlaySoundtrack, + Parameter = 8 + } + } + }; + entries.Add(trigger); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[0].GetSector(3, 7, TRUnit.Sector); + Assert.AreEqual(fdIndex, sector.FDIndex); + + entries = level.FloorData[fdIndex]; + Assert.AreEqual(1, entries.Count); + + Assert.IsTrue(entries[0] is FDTriggerEntry); + + FDTriggerEntry tmpTrigger = (FDTriggerEntry)entries[0]; + Assert.AreEqual(trigger.TrigType, tmpTrigger.TrigType); + Assert.AreEqual(trigger.OneShot, tmpTrigger.OneShot); + Assert.AreEqual(trigger.Mask, tmpTrigger.Mask); + Assert.AreEqual(trigger.Timer, tmpTrigger.Timer); + + Assert.AreEqual(trigger.Actions.Count, tmpTrigger.Actions.Count); + Assert.AreEqual(trigger.Actions[0].Action, tmpTrigger.Actions[0].Action); + Assert.AreEqual(trigger.Actions[0].Parameter, tmpTrigger.Actions[0].Parameter); + } + + [TestMethod] + [Description("Remove a trigger.")] + public void RemoveTrigger() + { + TR1Level level = GetTR1TestLevel(); + + TRRoomSector sector = level.Rooms[0].GetSector(5, 11, TRUnit.Sector); + Assert.AreNotEqual(0, sector.FDIndex); + + List entries = level.FloorData[sector.FDIndex]; + FDEntry trigger = entries.Find(e => e is FDTriggerEntry); + Assert.IsNotNull(trigger); + entries.Remove(trigger); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[0].GetSector(5, 11, TRUnit.Sector); + entries = level.FloorData[sector.FDIndex]; + trigger = entries.Find(e => e is FDTriggerEntry); + Assert.IsNull(trigger); + } + + [TestMethod] + [Description("Change a trigger's properties.")] + public void ChangeTrigger() + { + TR1Level level = GetTR1TestLevel(); + + TRRoomSector sector = level.Rooms[0].GetSector(5, 11, TRUnit.Sector); + Assert.AreNotEqual(0, sector.FDIndex); + + List entries = level.FloorData[sector.FDIndex]; + FDEntry entry = entries.Find(e => e is FDTriggerEntry); + Assert.IsNotNull(entry); + + FDTriggerEntry trigger = (FDTriggerEntry)entry; + Assert.IsFalse(trigger.OneShot); + Assert.AreNotEqual(10, trigger.Timer); + Assert.AreNotEqual(1 << 2, trigger.Mask); + Assert.AreNotEqual(FDTrigType.Pad, trigger.TrigType); + Assert.AreEqual(1, trigger.Actions.Count); + Assert.AreEqual(FDTrigAction.Object, trigger.Actions[0].Action); + Assert.AreNotEqual(8, trigger.Actions[0].Parameter); + + trigger.OneShot = true; + trigger.Timer = 10; + trigger.Mask = 1 << 2; + + trigger.TrigType = FDTrigType.Pad; + trigger.Actions[0].Action = FDTrigAction.PlaySoundtrack; + trigger.Actions[0].Parameter = 8; + trigger.Actions.Add(new() + { + Action = FDTrigAction.FlipMap, + Parameter = 1 + }); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[0].GetSector(5, 11, TRUnit.Sector); + entries = level.FloorData[sector.FDIndex]; + trigger = entries.Find(e => e is FDTriggerEntry) as FDTriggerEntry; + Assert.IsNotNull(trigger); + + Assert.IsTrue(trigger.OneShot); + Assert.AreEqual(10, trigger.Timer); + Assert.AreEqual(1 << 2, trigger.Mask); + Assert.AreEqual(FDTrigType.Pad, trigger.TrigType); + Assert.AreEqual(2, trigger.Actions.Count); + Assert.AreEqual(FDTrigAction.PlaySoundtrack, trigger.Actions[0].Action); + Assert.AreEqual(8, trigger.Actions[0].Parameter); + Assert.AreEqual(FDTrigAction.FlipMap, trigger.Actions[1].Action); + Assert.AreEqual(1, trigger.Actions[1].Parameter); + } + + [TestMethod] + [Description("Remove all floor data from a sector.")] + public void RemoveFloorData() + { + TR1Level level = GetTR1TestLevel(); + + TRRoomSector sector = level.Rooms[0].GetSector(5, 11, TRUnit.Sector); + Assert.AreNotEqual(0, sector.FDIndex); + + List entries = level.FloorData[sector.FDIndex]; + Assert.AreNotEqual(0, entries.Count); + entries.Clear(); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[0].GetSector(5, 11, TRUnit.Sector); + Assert.AreEqual(0, sector.FDIndex); + } + + [TestMethod] + [Description("Test finding entity triggers.")] + public void GetEntityTriggers() + { + TR1Level level = GetTR1TestLevel(); + TestGetEntityTriggers(level.FloorData, 1); + } + + [TestMethod] + [Description("Test finding secret triggers.")] + public void GetSecretTriggers() + { + TR1Level level = GetTR1TestLevel(); + TestGetSecretTriggers(level.FloorData, 0); + } + + [TestMethod] + [Description("Test finding specific trigger actions.")] + public void GetTriggerActions() + { + TR1Level level = GetTR1TestLevel(); + + List musicActions = level.FloorData.GetActionItems(FDTrigAction.PlaySoundtrack); + Assert.AreEqual(1, musicActions.Count); + } + + [TestMethod] + [Description("Test removing entity triggers.")] + public void RemoveEntityTriggers() + { + TR1Level level = GetTR1TestLevel(); + + List triggers = level.FloorData.GetEntityTriggers(1); + Assert.AreNotEqual(0, triggers.Count); + + level.FloorData.RemoveEntityTriggers(1); + + triggers = level.FloorData.GetEntityTriggers(1); + Assert.AreEqual(0, triggers.Count); + + level = WriteReadTempLevel(level); + triggers = level.FloorData.GetEntityTriggers(1); + Assert.AreEqual(0, triggers.Count); + } + + [TestMethod] + [Description("Test adding a kill Lara entry.")] + public void AddKillLara() + { + TR1Level level = GetTR1TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + List entries = level.FloorData[sector.FDIndex]; + entries.Add(new FDKillLaraEntry()); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreNotEqual(0, sector.FDIndex); + + FDKillLaraEntry killer = entries.Find(e => e is FDKillLaraEntry) as FDKillLaraEntry; + Assert.IsNotNull(killer); + } + + [TestMethod] + [Description("Test adding a portal.")] + public void AddPortal() + { + TR1Level level = GetTR1TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + List entries = level.FloorData[sector.FDIndex]; + entries.Add(new FDPortalEntry + { + Room = 1 + }); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreNotEqual(0, sector.FDIndex); + + FDPortalEntry portal = entries.Find(e => e is FDPortalEntry) as FDPortalEntry; + Assert.IsNotNull(portal); + Assert.AreEqual(1, portal.Room); + } + + [TestMethod] + [Description("Test adding a floor slant.")] + public void AddFloorSlant() + { + TR1Level level = GetTR1TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + List entries = level.FloorData[sector.FDIndex]; + entries.Add(new FDSlantEntry + { + Type = FDSlantType.Floor, + XSlant = -1, + ZSlant = 2 + }); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreNotEqual(0, sector.FDIndex); + + FDSlantEntry slant = entries.Find(e => e is FDSlantEntry) as FDSlantEntry; + Assert.IsNotNull(slant); + Assert.AreEqual(FDSlantType.Floor, slant.Type); + Assert.AreEqual(-1, slant.XSlant); + Assert.AreEqual(2, slant.ZSlant); + } + + [TestMethod] + [Description("Test adding a ceiling slant.")] + public void AddCeilingSlant() + { + TR1Level level = GetTR1TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + List entries = level.FloorData[sector.FDIndex]; + entries.Add(new FDSlantEntry + { + Type = FDSlantType.Ceiling, + XSlant = 2, + ZSlant = -3 + }); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreNotEqual(0, sector.FDIndex); + + FDSlantEntry slant = entries.Find(e => e is FDSlantEntry) as FDSlantEntry; + Assert.IsNotNull(slant); + Assert.AreEqual(FDSlantType.Ceiling, slant.Type); + Assert.AreEqual(2, slant.XSlant); + Assert.AreEqual(-3, slant.ZSlant); + } + + [TestMethod] + [Description("Add invalid FD entries for TR1.")] + public void AddInvalidEntries() + { + TR1Level level = GetTR1TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + level.FloorData[sector.FDIndex].AddRange(new List + { + new FDBeetleEntry(), + new FDClimbEntry(), + new FDDeferredTriggerEntry(), + new FDMinecartEntry(), + new FDMonkeySwingEntry(), + new FDTriangulationEntry(), + }); + + WriteReadTempLevel(level); + Assert.AreEqual(0, sector.FDIndex); + } +} diff --git a/TRLevelControlTests/TR1/IOTests.cs b/TRLevelControlTests/TR1/IOTests.cs index fd40ec445..5a87adf08 100644 --- a/TRLevelControlTests/TR1/IOTests.cs +++ b/TRLevelControlTests/TR1/IOTests.cs @@ -1,5 +1,4 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using TRFDControl; using TRLevelControl.Helpers; using TRLevelControl.Model; using TRLevelControl.Model.Base.Enums; @@ -22,40 +21,20 @@ public void TestReadWrite(string levelName) } [TestMethod] - [DynamicData(nameof(GetBaseLevels), DynamicDataSourceType.Method)] - public void TestFloorData(string levelName) - { - TR1Level level = GetTR1Level(levelName); - - // Store the original floordata from the level - List originalFData = new(level.FloorData); - - // Parse the floordata using FDControl and re-write the parsed data back - FDControl fdControl = new(); - fdControl.ParseFromLevel(level); - fdControl.WriteToLevel(level); - - // Compare to make sure the original fdata was written back. - CollectionAssert.AreEqual(originalFData, level.FloorData, $"Floordata in {levelName} does not match after read/write."); - } - - [TestMethod] - [DynamicData(nameof(GetGoldLevels), DynamicDataSourceType.Method)] + [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] public void TestAgressiveFloorData(string levelName) { - // The UB levels seem to have been compiled with agressive FD packing. - // Our library will expand and so byte-for-byte checks can't be done. - // We will instead verify that every sector points to a valid FD entry. + // The UB levels seem to have been compiled with agressive FD packing. Our library will expand and so byte-for-byte checks + // can't be done when not using the observer approach. We will instead verify that every sector points to a valid FD entry + // and that the expansion works by eliminating duplicates. TR1Level level = GetTR1Level(levelName); + IEnumerable allFDSectors = level.Rooms.SelectMany(r => r.Sectors.Where(s => s.FDIndex != 0)); - FDControl fdControl = new(); - fdControl.ParseFromLevel(level); - fdControl.WriteToLevel(level); - - foreach (TRRoomSector sector in level.Rooms.SelectMany(r => r.Sectors.Where(s => s.FDIndex != 0))) + foreach (TRRoomSector sector in allFDSectors) { - Assert.IsTrue(fdControl.Entries.ContainsKey(sector.FDIndex)); + Assert.IsTrue(level.FloorData.ContainsKey(sector.FDIndex)); } + Assert.AreEqual(allFDSectors.Count(), allFDSectors.DistinctBy(s => s.FDIndex).Count()); } [TestMethod] diff --git a/TRLevelControlTests/TR2/FDTests.cs b/TRLevelControlTests/TR2/FDTests.cs new file mode 100644 index 000000000..814d2da1f --- /dev/null +++ b/TRLevelControlTests/TR2/FDTests.cs @@ -0,0 +1,108 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TRLevelControl.Model; + +namespace TRLevelControlTests.TR2; + +[TestClass] +[TestCategory("FD")] +public class FDTests : FDTestBase +{ + [TestMethod] + [Description("Test adding a ladder.")] + public void AddLadder() + { + TR2Level level = GetTR2TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + List entries = level.FloorData[sector.FDIndex]; + entries.Add(new FDClimbEntry + { + Direction = FDClimbDirection.PositiveX + }); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreNotEqual(0, sector.FDIndex); + + FDClimbEntry ladder = entries.Find(e => e is FDClimbEntry) as FDClimbEntry; + Assert.IsNotNull(ladder); + + Assert.AreEqual(FDClimbDirection.PositiveX, ladder.Direction); + } + + [TestMethod] + [Description("Test changing a ladder.")] + public void ChangeLadder() + { + TR2Level level = GetTR2TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + level.FloorData.CreateFloorData(sector); + List entries = level.FloorData[sector.FDIndex]; + entries.Add(new FDClimbEntry()); + + void TestDirection(FDClimbDirection direction) + { + FDClimbEntry ladder = entries[0] as FDClimbEntry; + Assert.IsFalse(ladder.Direction.HasFlag(direction)); + ladder.Direction = direction; + + level = WriteReadTempLevel(level); + sector = level.Rooms[2].GetSector(4608, 6656); + entries = level.FloorData[sector.FDIndex]; + + ladder = entries[0] as FDClimbEntry; + Assert.IsTrue(ladder.Direction.HasFlag(direction)); + + Assert.AreEqual(ladder.IsPositiveX, direction.HasFlag(FDClimbDirection.PositiveX)); + Assert.AreEqual(ladder.IsPositiveZ, direction.HasFlag(FDClimbDirection.PositiveZ)); + Assert.AreEqual(ladder.IsNegativeX, direction.HasFlag(FDClimbDirection.NegativeX)); + Assert.AreEqual(ladder.IsNegativeZ, direction.HasFlag(FDClimbDirection.NegativeZ)); + } + + TestDirection(FDClimbDirection.PositiveX); + TestDirection(FDClimbDirection.NegativeX); + TestDirection(FDClimbDirection.PositiveZ); + TestDirection(FDClimbDirection.NegativeZ); + + TestDirection(FDClimbDirection.PositiveX | FDClimbDirection.NegativeX); + TestDirection(FDClimbDirection.PositiveX | FDClimbDirection.PositiveZ); + TestDirection(FDClimbDirection.PositiveX | FDClimbDirection.NegativeZ); + TestDirection(FDClimbDirection.NegativeX | FDClimbDirection.NegativeZ); + TestDirection(FDClimbDirection.NegativeX | FDClimbDirection.PositiveZ); + + TestDirection(FDClimbDirection.PositiveX | FDClimbDirection.NegativeX | FDClimbDirection.PositiveZ); + TestDirection(FDClimbDirection.PositiveX | FDClimbDirection.NegativeX | FDClimbDirection.NegativeZ); + TestDirection(FDClimbDirection.PositiveX | FDClimbDirection.PositiveZ | FDClimbDirection.NegativeZ); + TestDirection(FDClimbDirection.NegativeX | FDClimbDirection.PositiveZ | FDClimbDirection.NegativeZ); + + TestDirection(FDClimbDirection.PositiveX | FDClimbDirection.NegativeX | FDClimbDirection.PositiveZ | FDClimbDirection.NegativeZ); + } + + [TestMethod] + [Description("Add invalid FD entries for TR2.")] + public void AddInvalidEntries() + { + TR2Level level = GetTR2TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + level.FloorData[sector.FDIndex].AddRange(new List + { + new FDBeetleEntry(), + new FDDeferredTriggerEntry(), + new FDMinecartEntry(), + new FDMonkeySwingEntry(), + new FDTriangulationEntry(), + }); + + WriteReadTempLevel(level); + Assert.AreEqual(0, sector.FDIndex); + } +} diff --git a/TRLevelControlTests/TR2/IOTests.cs b/TRLevelControlTests/TR2/IOTests.cs index 71097f809..22afb231e 100644 --- a/TRLevelControlTests/TR2/IOTests.cs +++ b/TRLevelControlTests/TR2/IOTests.cs @@ -1,8 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Drawing; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -26,775 +23,774 @@ public void TestReadWrite(string levelName) [TestMethod] [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] - public void TestFloorData(string levelName) + public void TestAgressiveFloorData(string levelName) { TR2Level level = GetTR2Level(levelName); + IEnumerable allFDSectors = level.Rooms.SelectMany(r => r.Sectors.Where(s => s.FDIndex != 0)); - List originalData = new(level.FloorData); - - FDControl fdControl = new(); - fdControl.ParseFromLevel(level); - fdControl.WriteToLevel(level); - - CollectionAssert.AreEqual(originalData, level.FloorData); - } - - [TestMethod] - public void FloorData_ReadWriteOneShotTest() - { - //Read GW data - TR2Level lvl = GetTR2Level(TR2LevelNames.GW); - - //Parse the floordata using FDControl - FDControl fdataReader = new(); - fdataReader.ParseFromLevel(lvl); - - //Get all triggers for entity ID 18 - List triggers = FDUtilities.GetEntityTriggers(fdataReader, 18); - - //There should be 3 - Assert.AreEqual(triggers.Count, 3); - - //Verify none of the triggers has OneShot set - foreach (FDTriggerEntry trigger in triggers) - { - Assert.IsFalse(trigger.TrigSetup.OneShot); - } - - //Set OneShot on each trigger and test successive calls - foreach (FDTriggerEntry trigger in triggers) - { - trigger.TrigSetup.OneShot = true; - trigger.TrigSetup.OneShot = true; - } - - fdataReader.WriteToLevel(lvl); - - //Save it and read it back in - lvl = WriteReadTempLevel(lvl); - - fdataReader = new FDControl(); - fdataReader.ParseFromLevel(lvl); - - //Get the triggers again afresh - triggers = FDUtilities.GetEntityTriggers(fdataReader, 18); - - //Verify that they now have OneShot set - foreach (FDTriggerEntry trigger in triggers) - { - Assert.IsTrue(trigger.TrigSetup.OneShot); - } - - //Switch it off again and test successive calls - foreach (FDTriggerEntry trigger in triggers) - { - trigger.TrigSetup.OneShot = false; - trigger.TrigSetup.OneShot = false; - } - - fdataReader.WriteToLevel(lvl); - - //Save it and read it back in - lvl = WriteReadTempLevel(lvl); - - fdataReader = new FDControl(); - fdataReader.ParseFromLevel(lvl); - - //Get the triggers again afresh - triggers = FDUtilities.GetEntityTriggers(fdataReader, 18); - - //Verify that they now once again do not have OneShot set - foreach (FDTriggerEntry trigger in triggers) - { - Assert.IsFalse(trigger.TrigSetup.OneShot); - } - } - - [TestMethod] - public void FloorData_ReadWriteTrigTimerTest() - { - //Read GW data - TR2Level lvl = GetTR2Level(TR2LevelNames.GW); - - //Parse the floordata using FDControl - FDControl fdataReader = new(); - fdataReader.ParseFromLevel(lvl); - - //Get all triggers for entity ID 18 - List triggers = FDUtilities.GetEntityTriggers(fdataReader, 18); - - //There should be 3 - Assert.AreEqual(triggers.Count, 3); - - //Verify none of the triggers has a timer - foreach (FDTriggerEntry trigger in triggers) - { - Assert.AreEqual(trigger.TrigSetup.Timer, 0); - } - - //Set the timer on each trigger - for (int i = 0; i < triggers.Count; i++) - { - triggers[i].TrigSetup.Timer = (byte)(i * 10); - } - - fdataReader.WriteToLevel(lvl); - - //Save it and read it back in - lvl = WriteReadTempLevel(lvl); - - fdataReader = new FDControl(); - fdataReader.ParseFromLevel(lvl); - - //Get the triggers again afresh - triggers = FDUtilities.GetEntityTriggers(fdataReader, 18); - - //Verify that they now have the timers set - for (int i = 0; i < triggers.Count; i++) - { - Assert.AreEqual(triggers[i].TrigSetup.Timer, i * 10); - } - } - - [TestMethod] - public void FloorData_InsertFDTest() - { - //Read Dragons Lair data - TR2Level lvl = GetTR2Level(TR2LevelNames.LAIR); - - //Parse the floordata using FDControl - FDControl fdataReader = new(); - fdataReader.ParseFromLevel(lvl); - - //Find a sector that currently has no floor data - int room, roomSector = -1; - for (room = 0; room < lvl.Rooms.Count; room++) - { - roomSector = lvl.Rooms[room].Sectors.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].Sectors[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(FDFunction.Trigger), - TrigSetup = new FDTrigSetup(), - TrigActionList = new List - { - new() { - TrigAction = FDTrigAction.PlaySoundtrack, - Parameter = 40 - } - } - }); - - //Write the data back - fdataReader.WriteToLevel(lvl); - - //Save it and read it back in - lvl = WriteReadTempLevel(lvl); - - //Reassign the sector - sector = lvl.Rooms[room].Sectors[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)FDFunction.Trigger); - Assert.IsTrue(triggerEntry.TrigActionList.Count == 1); - Assert.IsTrue(triggerEntry.TrigActionList[0].TrigAction == FDTrigAction.PlaySoundtrack); - Assert.IsTrue(triggerEntry.TrigActionList[0].Parameter == 40); - } - - [TestMethod] - public void FloorData_RemoveFDTest() - { - //Read Dragons Lair data - TR2Level lvl = GetTR2Level(TR2LevelNames.LAIR); - - //Parse the floordata using FDControl - FDControl fdataReader = new(); - fdataReader.ParseFromLevel(lvl); - - //Find a sector that currently has floor data - int room, roomSector = -1; - for (room = 0; room < lvl.Rooms.Count; room++) + foreach (TRRoomSector sector in allFDSectors) { - roomSector = lvl.Rooms[room].Sectors.ToList().FindIndex(s => s.FDIndex > 0); - if (roomSector != -1) - { - break; - } + Assert.IsTrue(level.FloorData.ContainsKey(sector.FDIndex)); } - - if (roomSector == -1) - { - Assert.Fail("Could not locate a Room Sector that has floor data associated with it."); - } - - TRRoomSector sector = lvl.Rooms[room].Sectors[roomSector]; - - // Remove the FD for this sector - fdataReader.RemoveFloorData(sector); - Assert.AreEqual(sector.FDIndex, 0, "Sector still has FD allocated."); - - //Write the data back - fdataReader.WriteToLevel(lvl); - - //Save it and read it back in - lvl = WriteReadTempLevel(lvl); - - //Reassign the sector - sector = lvl.Rooms[room].Sectors[roomSector]; - - fdataReader = new FDControl(); - fdataReader.ParseFromLevel(lvl); - - //Ensure the sector still has FD associated with it - Assert.AreEqual(sector.FDIndex, 0, "Sector still has FD after write/read."); - } - - [TestMethod] - public void FloorData_InsertRemoveFDEntryTest() - { - //Read Dragons Lair data - TR2Level lvl = GetTR2Level(TR2LevelNames.LAIR); - - //Store the original floordata from the level - List originalFData = new(lvl.FloorData); - - //Parse the floordata using FDControl - FDControl fdataReader = new(); - fdataReader.ParseFromLevel(lvl); - - //Verify index 9 has one entry and that it's currently - //set as EndData for this index - Assert.AreEqual(fdataReader.Entries[9].Count, 1); - Assert.IsTrue(fdataReader.Entries[9][0].Setup.EndData); - - //Verify the next index is currently 9 + the entry's length - List indices = fdataReader.Entries.Keys.ToList(); - int nextIndex = 9 + fdataReader.Entries[9][0].Flatten().Length; - Assert.AreEqual(nextIndex, indices[indices.IndexOf(9) + 1]); - - //Add a music trigger to index 9 - fdataReader.Entries[9].Add(new FDTriggerEntry - { - Setup = new FDSetup(FDFunction.Trigger), - TrigSetup = new FDTrigSetup(), - TrigActionList = new List - { - new() { - TrigAction = FDTrigAction.PlaySoundtrack, - Parameter = 40 - } - } - }); - - //Write the data back - fdataReader.WriteToLevel(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 next index is now 9 + both the entry's lengths - //Bear in mind the underlying dictionary's keys have changed - indices = fdataReader.Entries.Keys.ToList(); - nextIndex = 9 + fdataReader.Entries[9][0].Flatten().Length + fdataReader.Entries[9][1].Flatten().Length; - Assert.AreEqual(nextIndex, indices[indices.IndexOf(9) + 1]); - - //Remove the new entry - fdataReader.Entries[9].RemoveAt(1); - - //Write the data back - fdataReader.WriteToLevel(lvl); - - //Verify index 9 again has one entry and that it's again - //set as EndData for this index - Assert.AreEqual(fdataReader.Entries[9].Count, 1); - Assert.IsTrue(fdataReader.Entries[9][0].Setup.EndData); - - //Verify the next index is again 9 + the entry's length - indices = fdataReader.Entries.Keys.ToList(); - nextIndex = 9 + fdataReader.Entries[9][0].Flatten().Length; - Assert.AreEqual(nextIndex, indices[indices.IndexOf(9) + 1]); - - //Finally compare to make sure the original fdata was written back. - CollectionAssert.AreEqual(originalFData, lvl.FloorData, "Floordata does not match"); - } - - [TestMethod] - public void FloorData_InsertFDEntryWriteReadTest() - { - //Read Dragons Lair data - TR2Level lvl = GetTR2Level(TR2LevelNames.LAIR); - - //Parse the floordata using FDControl - FDControl fdataReader = new(); - fdataReader.ParseFromLevel(lvl); - - //Add a music trigger to index 9 - fdataReader.Entries[9].Add(new FDTriggerEntry - { - Setup = new FDSetup(FDFunction.Trigger), - TrigSetup = new FDTrigSetup(), - TrigActionList = new List - { - new() { - TrigAction = FDTrigAction.PlaySoundtrack, - Parameter = 40 - } - } - }); - - //Write the data back - fdataReader.WriteToLevel(lvl); - - //Save it and read it back in - lvl = WriteReadTempLevel(lvl); - - 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)FDFunction.Trigger); - Assert.IsTrue(triggerEntry.TrigActionList.Count == 1); - Assert.IsTrue(triggerEntry.TrigActionList[0].TrigAction == FDTrigAction.PlaySoundtrack); - Assert.IsTrue(triggerEntry.TrigActionList[0].Parameter == 40); - } - - [TestMethod] - public void FloorData_AppendFDActionListItemTest() - { - //Read Dragons Lair data - TR2Level lvl = GetTR2Level(TR2LevelNames.LAIR); - - //Parse the floordata using FDControl - FDControl fdataReader = new(); - 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 FDActionItem - { - TrigAction = FDTrigAction.PlaySoundtrack, - Parameter = 40 - }); - - //Write the data back - fdataReader.WriteToLevel(lvl); - - //Save it and read it back in - lvl = WriteReadTempLevel(lvl); - - 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); - } - - [TestMethod] - public void FloorData_AppendFDActionListItemCamTest() - { - //Read Dragons Lair data - TR2Level lvl = GetTR2Level(TR2LevelNames.LAIR); - - //Parse the floordata using FDControl - FDControl fdataReader = new(); - 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 FDActionItem - { - 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); - } - - [TestMethod] - public void FloorData_ModifyClimbableTest() - { - // Get original ladders in +/-X directions - TR2Level lvl = GetTR2Level(TR2LevelNames.GW); - - FDControl fdataReader = new(); - fdataReader.ParseFromLevel(lvl); - - // Second guardhouse ladder - FDClimbEntry negXEntry = fdataReader.Entries[577][0] as FDClimbEntry; - // TRex pit ladder - FDClimbEntry posXEntry = fdataReader.Entries[7405][0] as FDClimbEntry; - - // Confirm both are/are not end data for the sake of comparing the value - Assert.AreEqual(negXEntry.Setup.EndData, posXEntry.Setup.EndData); - - ushort negXValue = negXEntry.Setup.Value; - ushort posXValue = posXEntry.Setup.Value; - - // Confirm they are currently what we expect - Assert.IsTrue(negXEntry.IsNegativeX); - Assert.IsFalse(negXEntry.IsPositiveX); - Assert.IsTrue(posXEntry.IsPositiveX); - Assert.IsFalse(posXEntry.IsNegativeX); - - // Flip the negative X entry and confirm it's now positive only - negXEntry.IsPositiveX = true; - negXEntry.IsNegativeX = false; - Assert.IsTrue(negXEntry.IsPositiveX); - Assert.IsFalse(negXEntry.IsNegativeX); - Assert.AreEqual(negXEntry.Setup.Value, posXValue); - - // Flip the positive X entry and confirm it's now negative only - posXEntry.IsPositiveX = false; - posXEntry.IsNegativeX = true; - Assert.IsTrue(posXEntry.IsNegativeX); - Assert.IsFalse(posXEntry.IsPositiveX); - Assert.AreEqual(posXEntry.Setup.Value, negXValue); - - - // Get original ladders in +/-Z directions - lvl = GetTR2Level(TR2LevelNames.BARTOLI); - fdataReader.ParseFromLevel(lvl); - - // Room 79 - FDClimbEntry negZEntry = fdataReader.Entries[2239][0] as FDClimbEntry; - FDClimbEntry posZEntry = fdataReader.Entries[2228][0] as FDClimbEntry; - - // Confirm both are/are not end data for the sake of comparing the value - Assert.AreEqual(negXEntry.Setup.EndData, posXEntry.Setup.EndData); - - ushort negZValue = negZEntry.Setup.Value; - ushort posZValue = posZEntry.Setup.Value; - - // Confirm they are currently what we expect - Assert.IsTrue(negZEntry.IsNegativeZ); - Assert.IsFalse(negZEntry.IsPositiveZ); - Assert.IsTrue(posZEntry.IsPositiveZ); - Assert.IsFalse(posZEntry.IsNegativeZ); - - // Flip the negative Z entry and confirm it's now positive only - negZEntry.IsPositiveZ = true; - negZEntry.IsNegativeZ = false; - Assert.IsTrue(negZEntry.IsPositiveZ); - Assert.IsFalse(negZEntry.IsNegativeZ); - Assert.AreEqual(negZEntry.Setup.Value, posZValue); - - // Flip the positive Z entry and confirm it's now negative only - posZEntry.IsPositiveZ = false; - posZEntry.IsNegativeZ = true; - Assert.IsTrue(posZEntry.IsNegativeZ); - Assert.IsFalse(posZEntry.IsPositiveZ); - Assert.AreEqual(posZEntry.Setup.Value, negZValue); - - - // Get original ladders with more than one direction - // Room 58 - FDClimbEntry negZNegXEntry = fdataReader.Entries[1432][0] as FDClimbEntry; - FDClimbEntry posZNegXEntry = fdataReader.Entries[1437][0] as FDClimbEntry; - - // Confirm both are/are not end data for the sake of comparing the value - Assert.AreEqual(negZNegXEntry.Setup.EndData, posZNegXEntry.Setup.EndData); - - ushort negZNegXValue = negZNegXEntry.Setup.Value; - ushort posZNegXValue = posZNegXEntry.Setup.Value; - - // Confirm they are currently what we expect - Assert.IsTrue(negZNegXEntry.IsNegativeZ); - Assert.IsTrue(negZNegXEntry.IsNegativeX); - Assert.IsFalse(negZNegXEntry.IsPositiveZ); - Assert.IsFalse(negZNegXEntry.IsPositiveX); - - Assert.IsTrue(posZNegXEntry.IsPositiveZ); - Assert.IsTrue(posZNegXEntry.IsNegativeX); - Assert.IsFalse(posZNegXEntry.IsNegativeZ); - Assert.IsFalse(posZNegXEntry.IsPositiveX); - - // Flip the negative Z and confirm it matches the posZNegXValue entry - negZNegXEntry.IsPositiveZ = true; - negZNegXEntry.IsNegativeZ = false; - negZNegXEntry.IsPositiveX = false; - negZNegXEntry.IsNegativeX = true; - Assert.IsTrue(negZNegXEntry.IsPositiveZ); - Assert.IsTrue(negZNegXEntry.IsNegativeX); - Assert.IsFalse(negZNegXEntry.IsNegativeZ); - Assert.IsFalse(negZNegXEntry.IsPositiveX); - Assert.AreEqual(negZNegXEntry.Setup.Value, posZNegXValue); - - // Flip the positive Z and confirm it matches the posZNegXValue entry - posZNegXEntry.IsPositiveZ = false; - posZNegXEntry.IsNegativeZ = true; - posZNegXEntry.IsPositiveX = false; - posZNegXEntry.IsNegativeX = true; - Assert.IsTrue(posZNegXEntry.IsNegativeZ); - Assert.IsTrue(posZNegXEntry.IsNegativeX); - Assert.IsFalse(posZNegXEntry.IsPositiveZ); - Assert.IsFalse(posZNegXEntry.IsPositiveX); - Assert.AreEqual(posZNegXEntry.Setup.Value, negZNegXValue); - } - - [TestMethod] - public void FloorData_ModifySlantsTest() - { - TR2Level lvl = GetTR2Level(TR2LevelNames.GW); - - FDControl fdataReader = new(); - fdataReader.ParseFromLevel(lvl); - - // Get a sector that is slanted in both X and Z directions - TRRoomSector sector = FDUtilities.GetRoomSector(61891, 3129, 24010, 35, lvl, fdataReader); - List entries = fdataReader.Entries[sector.FDIndex]; - - // Confirm we have a match of what we expect - Assert.AreEqual(entries.Count, 1); - Assert.IsTrue(entries[0] is FDSlantEntry); - FDSlantEntry slantEntry = entries[0] as FDSlantEntry; - - // Check current values are X=-2, Z=-3 - Assert.AreEqual(slantEntry.XSlant, -2); - Assert.AreEqual(slantEntry.ZSlant, -3); - - // Change X only - slantEntry.XSlant--; - Assert.AreEqual(slantEntry.XSlant, -3); - Assert.AreEqual(slantEntry.ZSlant, -3); - - // Change Z only - slantEntry.ZSlant++; - Assert.AreEqual(slantEntry.XSlant, -3); - Assert.AreEqual(slantEntry.ZSlant, -2); - - // Change X sign - slantEntry.XSlant *= -1; - Assert.AreEqual(slantEntry.XSlant, 3); - Assert.AreEqual(slantEntry.ZSlant, -2); - - // Change Z sign - slantEntry.ZSlant *= -1; - Assert.AreEqual(slantEntry.XSlant, 3); - Assert.AreEqual(slantEntry.ZSlant, 2); - - // Write to level and confirm values remain the same on reload - fdataReader.WriteToLevel(lvl); - - // Save it and read it back in - lvl = WriteReadTempLevel(lvl); - - fdataReader.ParseFromLevel(lvl); - - slantEntry = fdataReader.Entries[sector.FDIndex][0] as FDSlantEntry; - Assert.AreEqual(slantEntry.XSlant, 3); - Assert.AreEqual(slantEntry.ZSlant, 2); - - // Make a new entry - sector = FDUtilities.GetRoomSector(64044, 5632, 32440, 36, lvl, fdataReader); - Assert.AreEqual(sector.FDIndex, 0); - fdataReader.CreateFloorData(sector); - - slantEntry = new FDSlantEntry - { - Setup = new FDSetup { Value = 2 }, - Type = FDSlantType.FloorSlant, - SlantValue = 0 - }; - fdataReader.Entries[sector.FDIndex].Add(slantEntry); - - Assert.AreEqual(slantEntry.XSlant, 0); - Assert.AreEqual(slantEntry.ZSlant, 0); - - slantEntry.XSlant = 1; - slantEntry.ZSlant = -2; - Assert.AreEqual(slantEntry.XSlant, 1); - Assert.AreEqual(slantEntry.ZSlant, -2); - - // Write to level and confirm values remain the same on reload - fdataReader.WriteToLevel(lvl); - - // Save it and read it back in - lvl = WriteReadTempLevel(lvl); - - fdataReader.ParseFromLevel(lvl); - - slantEntry = fdataReader.Entries[sector.FDIndex][0] as FDSlantEntry; - Assert.AreEqual(slantEntry.XSlant, 1); - Assert.AreEqual(slantEntry.ZSlant, -2); - - // Edge cases - slantEntry.XSlant = -1; - slantEntry.ZSlant = -1; - Assert.AreEqual(slantEntry.XSlant, -1); - Assert.AreEqual(slantEntry.ZSlant, -1); - - slantEntry.XSlant = -1; - slantEntry.ZSlant = 0; - Assert.AreEqual(slantEntry.XSlant, -1); - Assert.AreEqual(slantEntry.ZSlant, 0); - - slantEntry.XSlant = 0; - slantEntry.ZSlant = -1; - Assert.AreEqual(slantEntry.XSlant, 0); - Assert.AreEqual(slantEntry.ZSlant, -1); - - slantEntry.XSlant = 1; - slantEntry.ZSlant = 0; - Assert.AreEqual(slantEntry.XSlant, 1); - Assert.AreEqual(slantEntry.ZSlant, 0); - - slantEntry.XSlant = 0; - slantEntry.ZSlant = 1; - Assert.AreEqual(slantEntry.XSlant, 0); - Assert.AreEqual(slantEntry.ZSlant, 1); - - slantEntry.XSlant = 1; - slantEntry.ZSlant = 1; - Assert.AreEqual(slantEntry.XSlant, 1); - Assert.AreEqual(slantEntry.ZSlant, 1); + Assert.AreEqual(allFDSectors.Count(), allFDSectors.DistinctBy(s => s.FDIndex).Count()); } - [TestMethod] - public void FloorData_ModifyTriggerMask() - { - TR2Level lvl = GetTR2Level(TR2LevelNames.MONASTERY); - - FDControl fdataReader = new(); - fdataReader.ParseFromLevel(lvl); + //[TestMethod] + //public void FloorData_ReadWriteOneShotTest() + //{ + // //Read GW data + // TR2Level lvl = GetTR2Level(TR2LevelNames.GW); - // For the end doors to open in Barkhang, all 5 activation bits must be set. - // Check that each trigger exclusively has one of these bits, so 2^0 to 2^4. - // The sum should be 31. - - int[] slots = new int[] { 0, 3, 4, 9, 10 }; - int mask = 0; - foreach (int slotIndex in slots) - { - TR2Entity slot = lvl.Entities[slotIndex]; - TRRoomSector sector = FDUtilities.GetRoomSector(slot.X, slot.Y, slot.Z, slot.Room, lvl, fdataReader); - - // Confirm we have a match of what we expect - Assert.AreNotEqual(sector.FDIndex, 0); - List entries = fdataReader.Entries[sector.FDIndex]; - Assert.AreEqual(entries.Count, 1); - Assert.IsTrue(entries[0] is FDTriggerEntry); - - FDTriggerEntry trigger = entries[0] as FDTriggerEntry; - // Confirm this mask will change the overall check mask - int newMask = mask | trigger.TrigSetup.Mask; - Assert.AreNotEqual(mask, newMask); - mask = newMask; - } + // //Parse the floordata using FDControl + // FDControl fdataReader = new(); + // fdataReader.ParseFromLevel(lvl); - // Final check the mask matches full activation - Assert.AreEqual(mask, 31); + // //Get all triggers for entity ID 18 + // List triggers = FDUtilities.GetEntityTriggers(fdataReader, 18); - // Test changing a mask value - lvl = GetTR2Level(TR2LevelNames.DORIA); - fdataReader.ParseFromLevel(lvl); - - TR2Entity circuitBreakerSlot = lvl.Entities[15]; - TRRoomSector cbSector = FDUtilities.GetRoomSector(circuitBreakerSlot.X, circuitBreakerSlot.Y, circuitBreakerSlot.Z, circuitBreakerSlot.Room, lvl, fdataReader); - - // Confirm we have a match of what we expect - Assert.AreNotEqual(cbSector.FDIndex, 0); - List cbEntries = fdataReader.Entries[cbSector.FDIndex]; - Assert.AreEqual(cbEntries.Count, 1); - Assert.IsTrue(cbEntries[0] is FDTriggerEntry); - - FDTriggerEntry cbTrigger = cbEntries[0] as FDTriggerEntry; - - // We expect a normal mask for Wreck so all 1's set - Assert.AreEqual(cbTrigger.TrigSetup.Mask, 31); - - // Take off 2 bits. This simulates having something activated - // only after all 3 breakers are used. - // 16 8 4 2 1 - // ---------- - // 1 0 0 1 1 - // 0 1 0 1 1 - // 0 0 1 1 1 - cbTrigger.TrigSetup.Mask = 7; - Assert.AreEqual(cbTrigger.TrigSetup.Mask, 7); - - // Save the level and re-read it to confirm it still matches. - fdataReader.WriteToLevel(lvl); - lvl = WriteReadTempLevel(lvl); - - fdataReader.ParseFromLevel(lvl); - - cbSector = FDUtilities.GetRoomSector(circuitBreakerSlot.X, circuitBreakerSlot.Y, circuitBreakerSlot.Z, circuitBreakerSlot.Room, lvl, fdataReader); - - // Confirm we have a match of what we expect - Assert.AreNotEqual(cbSector.FDIndex, 0); - cbEntries = fdataReader.Entries[cbSector.FDIndex]; - Assert.AreEqual(cbEntries.Count, 1); - Assert.IsTrue(cbEntries[0] is FDTriggerEntry); - - cbTrigger = cbEntries[0] as FDTriggerEntry; - - Assert.AreEqual(cbTrigger.TrigSetup.Mask, 7); - } + // //There should be 3 + // Assert.AreEqual(triggers.Count, 3); + + // //Verify none of the triggers has OneShot set + // foreach (FDTriggerEntry trigger in triggers) + // { + // Assert.IsFalse(trigger.TrigSetup.OneShot); + // } + + // //Set OneShot on each trigger and test successive calls + // foreach (FDTriggerEntry trigger in triggers) + // { + // trigger.TrigSetup.OneShot = true; + // trigger.TrigSetup.OneShot = true; + // } + + // fdataReader.WriteToLevel(lvl); + + // //Save it and read it back in + // lvl = WriteReadTempLevel(lvl); + + // fdataReader = new FDControl(); + // fdataReader.ParseFromLevel(lvl); + + // //Get the triggers again afresh + // triggers = FDUtilities.GetEntityTriggers(fdataReader, 18); + + // //Verify that they now have OneShot set + // foreach (FDTriggerEntry trigger in triggers) + // { + // Assert.IsTrue(trigger.TrigSetup.OneShot); + // } + + // //Switch it off again and test successive calls + // foreach (FDTriggerEntry trigger in triggers) + // { + // trigger.TrigSetup.OneShot = false; + // trigger.TrigSetup.OneShot = false; + // } + + // fdataReader.WriteToLevel(lvl); + + // //Save it and read it back in + // lvl = WriteReadTempLevel(lvl); + + // fdataReader = new FDControl(); + // fdataReader.ParseFromLevel(lvl); + + // //Get the triggers again afresh + // triggers = FDUtilities.GetEntityTriggers(fdataReader, 18); + + // //Verify that they now once again do not have OneShot set + // foreach (FDTriggerEntry trigger in triggers) + // { + // Assert.IsFalse(trigger.TrigSetup.OneShot); + // } + //} + + //[TestMethod] + //public void FloorData_ReadWriteTrigTimerTest() + //{ + // //Read GW data + // TR2Level lvl = GetTR2Level(TR2LevelNames.GW); + + // //Parse the floordata using FDControl + // FDControl fdataReader = new(); + // fdataReader.ParseFromLevel(lvl); + + // //Get all triggers for entity ID 18 + // List triggers = FDUtilities.GetEntityTriggers(fdataReader, 18); + + // //There should be 3 + // Assert.AreEqual(triggers.Count, 3); + + // //Verify none of the triggers has a timer + // foreach (FDTriggerEntry trigger in triggers) + // { + // Assert.AreEqual(trigger.TrigSetup.Timer, 0); + // } + + // //Set the timer on each trigger + // for (int i = 0; i < triggers.Count; i++) + // { + // triggers[i].TrigSetup.Timer = (byte)(i * 10); + // } + + // fdataReader.WriteToLevel(lvl); + + // //Save it and read it back in + // lvl = WriteReadTempLevel(lvl); + + // fdataReader = new FDControl(); + // fdataReader.ParseFromLevel(lvl); + + // //Get the triggers again afresh + // triggers = FDUtilities.GetEntityTriggers(fdataReader, 18); + + // //Verify that they now have the timers set + // for (int i = 0; i < triggers.Count; i++) + // { + // Assert.AreEqual(triggers[i].TrigSetup.Timer, i * 10); + // } + //} + + //[TestMethod] + //public void FloorData_InsertFDTest() + //{ + // //Read Dragons Lair data + // TR2Level lvl = GetTR2Level(TR2LevelNames.LAIR); + + // //Parse the floordata using FDControl + // FDControl fdataReader = new(); + // fdataReader.ParseFromLevel(lvl); + + // //Find a sector that currently has no floor data + // int room, roomSector = -1; + // for (room = 0; room < lvl.Rooms.Count; room++) + // { + // roomSector = lvl.Rooms[room].Sectors.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].Sectors[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(FDFunction.Trigger), + // TrigSetup = new FDTrigSetup(), + // TrigActionList = new List + // { + // new() { + // TrigAction = FDTrigAction.PlaySoundtrack, + // Parameter = 40 + // } + // } + // }); + + // //Write the data back + // fdataReader.WriteToLevel(lvl); + + // //Save it and read it back in + // lvl = WriteReadTempLevel(lvl); + + // //Reassign the sector + // sector = lvl.Rooms[room].Sectors[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)FDFunction.Trigger); + // Assert.IsTrue(triggerEntry.TrigActionList.Count == 1); + // Assert.IsTrue(triggerEntry.TrigActionList[0].TrigAction == FDTrigAction.PlaySoundtrack); + // Assert.IsTrue(triggerEntry.TrigActionList[0].Parameter == 40); + //} + + //[TestMethod] + //public void FloorData_RemoveFDTest() + //{ + // //Read Dragons Lair data + // TR2Level lvl = GetTR2Level(TR2LevelNames.LAIR); + + // //Parse the floordata using FDControl + // FDControl fdataReader = new(); + // fdataReader.ParseFromLevel(lvl); + + // //Find a sector that currently has floor data + // int room, roomSector = -1; + // for (room = 0; room < lvl.Rooms.Count; room++) + // { + // roomSector = lvl.Rooms[room].Sectors.ToList().FindIndex(s => s.FDIndex > 0); + // if (roomSector != -1) + // { + // break; + // } + // } + + // if (roomSector == -1) + // { + // Assert.Fail("Could not locate a Room Sector that has floor data associated with it."); + // } + + // TRRoomSector sector = lvl.Rooms[room].Sectors[roomSector]; + + // // Remove the FD for this sector + // fdataReader.RemoveFloorData(sector); + // Assert.AreEqual(sector.FDIndex, 0, "Sector still has FD allocated."); + + // //Write the data back + // fdataReader.WriteToLevel(lvl); + + // //Save it and read it back in + // lvl = WriteReadTempLevel(lvl); + + // //Reassign the sector + // sector = lvl.Rooms[room].Sectors[roomSector]; + + // fdataReader = new FDControl(); + // fdataReader.ParseFromLevel(lvl); + + // //Ensure the sector still has FD associated with it + // Assert.AreEqual(sector.FDIndex, 0, "Sector still has FD after write/read."); + //} + + //[TestMethod] + //public void FloorData_InsertRemoveFDEntryTest() + //{ + // //Read Dragons Lair data + // TR2Level lvl = GetTR2Level(TR2LevelNames.LAIR); + + // //Store the original floordata from the level + // List originalFData = new(lvl.FloorData); + + // //Parse the floordata using FDControl + // FDControl fdataReader = new(); + // fdataReader.ParseFromLevel(lvl); + + // //Verify index 9 has one entry and that it's currently + // //set as EndData for this index + // Assert.AreEqual(fdataReader.Entries[9].Count, 1); + // Assert.IsTrue(fdataReader.Entries[9][0].Setup.EndData); + + // //Verify the next index is currently 9 + the entry's length + // List indices = fdataReader.Entries.Keys.ToList(); + // int nextIndex = 9 + fdataReader.Entries[9][0].Flatten().Length; + // Assert.AreEqual(nextIndex, indices[indices.IndexOf(9) + 1]); + + // //Add a music trigger to index 9 + // fdataReader.Entries[9].Add(new FDTriggerEntry + // { + // Setup = new FDSetup(FDFunction.Trigger), + // TrigSetup = new FDTrigSetup(), + // TrigActionList = new List + // { + // new() { + // TrigAction = FDTrigAction.PlaySoundtrack, + // Parameter = 40 + // } + // } + // }); + + // //Write the data back + // fdataReader.WriteToLevel(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 next index is now 9 + both the entry's lengths + // //Bear in mind the underlying dictionary's keys have changed + // indices = fdataReader.Entries.Keys.ToList(); + // nextIndex = 9 + fdataReader.Entries[9][0].Flatten().Length + fdataReader.Entries[9][1].Flatten().Length; + // Assert.AreEqual(nextIndex, indices[indices.IndexOf(9) + 1]); + + // //Remove the new entry + // fdataReader.Entries[9].RemoveAt(1); + + // //Write the data back + // fdataReader.WriteToLevel(lvl); + + // //Verify index 9 again has one entry and that it's again + // //set as EndData for this index + // Assert.AreEqual(fdataReader.Entries[9].Count, 1); + // Assert.IsTrue(fdataReader.Entries[9][0].Setup.EndData); + + // //Verify the next index is again 9 + the entry's length + // indices = fdataReader.Entries.Keys.ToList(); + // nextIndex = 9 + fdataReader.Entries[9][0].Flatten().Length; + // Assert.AreEqual(nextIndex, indices[indices.IndexOf(9) + 1]); + + // //Finally compare to make sure the original fdata was written back. + // CollectionAssert.AreEqual(originalFData, lvl.FloorData, "Floordata does not match"); + //} + + //[TestMethod] + //public void FloorData_InsertFDEntryWriteReadTest() + //{ + // //Read Dragons Lair data + // TR2Level lvl = GetTR2Level(TR2LevelNames.LAIR); + + // //Parse the floordata using FDControl + // FDControl fdataReader = new(); + // fdataReader.ParseFromLevel(lvl); + + // //Add a music trigger to index 9 + // fdataReader.Entries[9].Add(new FDTriggerEntry + // { + // Setup = new FDSetup(FDFunction.Trigger), + // TrigSetup = new FDTrigSetup(), + // TrigActionList = new List + // { + // new() { + // TrigAction = FDTrigAction.PlaySoundtrack, + // Parameter = 40 + // } + // } + // }); + + // //Write the data back + // fdataReader.WriteToLevel(lvl); + + // //Save it and read it back in + // lvl = WriteReadTempLevel(lvl); + + // 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)FDFunction.Trigger); + // Assert.IsTrue(triggerEntry.TrigActionList.Count == 1); + // Assert.IsTrue(triggerEntry.TrigActionList[0].TrigAction == FDTrigAction.PlaySoundtrack); + // Assert.IsTrue(triggerEntry.TrigActionList[0].Parameter == 40); + //} + + //[TestMethod] + //public void FloorData_AppendFDActionListItemTest() + //{ + // //Read Dragons Lair data + // TR2Level lvl = GetTR2Level(TR2LevelNames.LAIR); + + // //Parse the floordata using FDControl + // FDControl fdataReader = new(); + // 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 FDActionItem + // { + // TrigAction = FDTrigAction.PlaySoundtrack, + // Parameter = 40 + // }); + + // //Write the data back + // fdataReader.WriteToLevel(lvl); + + // //Save it and read it back in + // lvl = WriteReadTempLevel(lvl); + + // 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); + //} + + //[TestMethod] + //public void FloorData_AppendFDActionListItemCamTest() + //{ + // //Read Dragons Lair data + // TR2Level lvl = GetTR2Level(TR2LevelNames.LAIR); + + // //Parse the floordata using FDControl + // FDControl fdataReader = new(); + // 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 FDActionItem + // { + // 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); + //} + + //[TestMethod] + //public void FloorData_ModifyClimbableTest() + //{ + // // Get original ladders in +/-X directions + // TR2Level lvl = GetTR2Level(TR2LevelNames.GW); + + // FDControl fdataReader = new(); + // fdataReader.ParseFromLevel(lvl); + + // // Second guardhouse ladder + // FDClimbEntry negXEntry = fdataReader.Entries[577][0] as FDClimbEntry; + // // TRex pit ladder + // FDClimbEntry posXEntry = fdataReader.Entries[7405][0] as FDClimbEntry; + + // // Confirm both are/are not end data for the sake of comparing the value + // Assert.AreEqual(negXEntry.Setup.EndData, posXEntry.Setup.EndData); + + // ushort negXValue = negXEntry.Setup.Value; + // ushort posXValue = posXEntry.Setup.Value; + + // // Confirm they are currently what we expect + // Assert.IsTrue(negXEntry.IsNegativeX); + // Assert.IsFalse(negXEntry.IsPositiveX); + // Assert.IsTrue(posXEntry.IsPositiveX); + // Assert.IsFalse(posXEntry.IsNegativeX); + + // // Flip the negative X entry and confirm it's now positive only + // negXEntry.IsPositiveX = true; + // negXEntry.IsNegativeX = false; + // Assert.IsTrue(negXEntry.IsPositiveX); + // Assert.IsFalse(negXEntry.IsNegativeX); + // Assert.AreEqual(negXEntry.Setup.Value, posXValue); + + // // Flip the positive X entry and confirm it's now negative only + // posXEntry.IsPositiveX = false; + // posXEntry.IsNegativeX = true; + // Assert.IsTrue(posXEntry.IsNegativeX); + // Assert.IsFalse(posXEntry.IsPositiveX); + // Assert.AreEqual(posXEntry.Setup.Value, negXValue); + + + // // Get original ladders in +/-Z directions + // lvl = GetTR2Level(TR2LevelNames.BARTOLI); + // fdataReader.ParseFromLevel(lvl); + + // // Room 79 + // FDClimbEntry negZEntry = fdataReader.Entries[2239][0] as FDClimbEntry; + // FDClimbEntry posZEntry = fdataReader.Entries[2228][0] as FDClimbEntry; + + // // Confirm both are/are not end data for the sake of comparing the value + // Assert.AreEqual(negXEntry.Setup.EndData, posXEntry.Setup.EndData); + + // ushort negZValue = negZEntry.Setup.Value; + // ushort posZValue = posZEntry.Setup.Value; + + // // Confirm they are currently what we expect + // Assert.IsTrue(negZEntry.IsNegativeZ); + // Assert.IsFalse(negZEntry.IsPositiveZ); + // Assert.IsTrue(posZEntry.IsPositiveZ); + // Assert.IsFalse(posZEntry.IsNegativeZ); + + // // Flip the negative Z entry and confirm it's now positive only + // negZEntry.IsPositiveZ = true; + // negZEntry.IsNegativeZ = false; + // Assert.IsTrue(negZEntry.IsPositiveZ); + // Assert.IsFalse(negZEntry.IsNegativeZ); + // Assert.AreEqual(negZEntry.Setup.Value, posZValue); + + // // Flip the positive Z entry and confirm it's now negative only + // posZEntry.IsPositiveZ = false; + // posZEntry.IsNegativeZ = true; + // Assert.IsTrue(posZEntry.IsNegativeZ); + // Assert.IsFalse(posZEntry.IsPositiveZ); + // Assert.AreEqual(posZEntry.Setup.Value, negZValue); + + + // // Get original ladders with more than one direction + // // Room 58 + // FDClimbEntry negZNegXEntry = fdataReader.Entries[1432][0] as FDClimbEntry; + // FDClimbEntry posZNegXEntry = fdataReader.Entries[1437][0] as FDClimbEntry; + + // // Confirm both are/are not end data for the sake of comparing the value + // Assert.AreEqual(negZNegXEntry.Setup.EndData, posZNegXEntry.Setup.EndData); + + // ushort negZNegXValue = negZNegXEntry.Setup.Value; + // ushort posZNegXValue = posZNegXEntry.Setup.Value; + + // // Confirm they are currently what we expect + // Assert.IsTrue(negZNegXEntry.IsNegativeZ); + // Assert.IsTrue(negZNegXEntry.IsNegativeX); + // Assert.IsFalse(negZNegXEntry.IsPositiveZ); + // Assert.IsFalse(negZNegXEntry.IsPositiveX); + + // Assert.IsTrue(posZNegXEntry.IsPositiveZ); + // Assert.IsTrue(posZNegXEntry.IsNegativeX); + // Assert.IsFalse(posZNegXEntry.IsNegativeZ); + // Assert.IsFalse(posZNegXEntry.IsPositiveX); + + // // Flip the negative Z and confirm it matches the posZNegXValue entry + // negZNegXEntry.IsPositiveZ = true; + // negZNegXEntry.IsNegativeZ = false; + // negZNegXEntry.IsPositiveX = false; + // negZNegXEntry.IsNegativeX = true; + // Assert.IsTrue(negZNegXEntry.IsPositiveZ); + // Assert.IsTrue(negZNegXEntry.IsNegativeX); + // Assert.IsFalse(negZNegXEntry.IsNegativeZ); + // Assert.IsFalse(negZNegXEntry.IsPositiveX); + // Assert.AreEqual(negZNegXEntry.Setup.Value, posZNegXValue); + + // // Flip the positive Z and confirm it matches the posZNegXValue entry + // posZNegXEntry.IsPositiveZ = false; + // posZNegXEntry.IsNegativeZ = true; + // posZNegXEntry.IsPositiveX = false; + // posZNegXEntry.IsNegativeX = true; + // Assert.IsTrue(posZNegXEntry.IsNegativeZ); + // Assert.IsTrue(posZNegXEntry.IsNegativeX); + // Assert.IsFalse(posZNegXEntry.IsPositiveZ); + // Assert.IsFalse(posZNegXEntry.IsPositiveX); + // Assert.AreEqual(posZNegXEntry.Setup.Value, negZNegXValue); + //} + + //[TestMethod] + //public void FloorData_ModifySlantsTest() + //{ + // TR2Level lvl = GetTR2Level(TR2LevelNames.GW); + + // FDControl fdataReader = new(); + // fdataReader.ParseFromLevel(lvl); + + // // Get a sector that is slanted in both X and Z directions + // TRRoomSector sector = FDUtilities.GetRoomSector(61891, 3129, 24010, 35, lvl, fdataReader); + // List entries = fdataReader.Entries[sector.FDIndex]; + + // // Confirm we have a match of what we expect + // Assert.AreEqual(entries.Count, 1); + // Assert.IsTrue(entries[0] is FDSlantEntry); + // FDSlantEntry slantEntry = entries[0] as FDSlantEntry; + + // // Check current values are X=-2, Z=-3 + // Assert.AreEqual(slantEntry.XSlant, -2); + // Assert.AreEqual(slantEntry.ZSlant, -3); + + // // Change X only + // slantEntry.XSlant--; + // Assert.AreEqual(slantEntry.XSlant, -3); + // Assert.AreEqual(slantEntry.ZSlant, -3); + + // // Change Z only + // slantEntry.ZSlant++; + // Assert.AreEqual(slantEntry.XSlant, -3); + // Assert.AreEqual(slantEntry.ZSlant, -2); + + // // Change X sign + // slantEntry.XSlant *= -1; + // Assert.AreEqual(slantEntry.XSlant, 3); + // Assert.AreEqual(slantEntry.ZSlant, -2); + + // // Change Z sign + // slantEntry.ZSlant *= -1; + // Assert.AreEqual(slantEntry.XSlant, 3); + // Assert.AreEqual(slantEntry.ZSlant, 2); + + // // Write to level and confirm values remain the same on reload + // fdataReader.WriteToLevel(lvl); + + // // Save it and read it back in + // lvl = WriteReadTempLevel(lvl); + + // fdataReader.ParseFromLevel(lvl); + + // slantEntry = fdataReader.Entries[sector.FDIndex][0] as FDSlantEntry; + // Assert.AreEqual(slantEntry.XSlant, 3); + // Assert.AreEqual(slantEntry.ZSlant, 2); + + // // Make a new entry + // sector = FDUtilities.GetRoomSector(64044, 5632, 32440, 36, lvl, fdataReader); + // Assert.AreEqual(sector.FDIndex, 0); + // fdataReader.CreateFloorData(sector); + + // slantEntry = new FDSlantEntry + // { + // Setup = new FDSetup { Value = 2 }, + // Type = FDSlantType.Floor, + // SlantValue = 0 + // }; + // fdataReader.Entries[sector.FDIndex].Add(slantEntry); + + // Assert.AreEqual(slantEntry.XSlant, 0); + // Assert.AreEqual(slantEntry.ZSlant, 0); + + // slantEntry.XSlant = 1; + // slantEntry.ZSlant = -2; + // Assert.AreEqual(slantEntry.XSlant, 1); + // Assert.AreEqual(slantEntry.ZSlant, -2); + + // // Write to level and confirm values remain the same on reload + // fdataReader.WriteToLevel(lvl); + + // // Save it and read it back in + // lvl = WriteReadTempLevel(lvl); + + // fdataReader.ParseFromLevel(lvl); + + // slantEntry = fdataReader.Entries[sector.FDIndex][0] as FDSlantEntry; + // Assert.AreEqual(slantEntry.XSlant, 1); + // Assert.AreEqual(slantEntry.ZSlant, -2); + + // // Edge cases + // slantEntry.XSlant = -1; + // slantEntry.ZSlant = -1; + // Assert.AreEqual(slantEntry.XSlant, -1); + // Assert.AreEqual(slantEntry.ZSlant, -1); + + // slantEntry.XSlant = -1; + // slantEntry.ZSlant = 0; + // Assert.AreEqual(slantEntry.XSlant, -1); + // Assert.AreEqual(slantEntry.ZSlant, 0); + + // slantEntry.XSlant = 0; + // slantEntry.ZSlant = -1; + // Assert.AreEqual(slantEntry.XSlant, 0); + // Assert.AreEqual(slantEntry.ZSlant, -1); + + // slantEntry.XSlant = 1; + // slantEntry.ZSlant = 0; + // Assert.AreEqual(slantEntry.XSlant, 1); + // Assert.AreEqual(slantEntry.ZSlant, 0); + + // slantEntry.XSlant = 0; + // slantEntry.ZSlant = 1; + // Assert.AreEqual(slantEntry.XSlant, 0); + // Assert.AreEqual(slantEntry.ZSlant, 1); + + // slantEntry.XSlant = 1; + // slantEntry.ZSlant = 1; + // Assert.AreEqual(slantEntry.XSlant, 1); + // Assert.AreEqual(slantEntry.ZSlant, 1); + //} + + //[TestMethod] + //public void FloorData_ModifyTriggerMask() + //{ + // TR2Level lvl = GetTR2Level(TR2LevelNames.MONASTERY); + + // FDControl fdataReader = new(); + // fdataReader.ParseFromLevel(lvl); + + // // For the end doors to open in Barkhang, all 5 activation bits must be set. + // // Check that each trigger exclusively has one of these bits, so 2^0 to 2^4. + // // The sum should be 31. + + // int[] slots = new int[] { 0, 3, 4, 9, 10 }; + // int mask = 0; + // foreach (int slotIndex in slots) + // { + // TR2Entity slot = lvl.Entities[slotIndex]; + // TRRoomSector sector = FDUtilities.GetRoomSector(slot.X, slot.Y, slot.Z, slot.Room, lvl, fdataReader); + + // // Confirm we have a match of what we expect + // Assert.AreNotEqual(sector.FDIndex, 0); + // List entries = fdataReader.Entries[sector.FDIndex]; + // Assert.AreEqual(entries.Count, 1); + // Assert.IsTrue(entries[0] is FDTriggerEntry); + + // FDTriggerEntry trigger = entries[0] as FDTriggerEntry; + // // Confirm this mask will change the overall check mask + // int newMask = mask | trigger.TrigSetup.Mask; + // Assert.AreNotEqual(mask, newMask); + // mask = newMask; + // } + + // // Final check the mask matches full activation + // Assert.AreEqual(mask, 31); + + // // Test changing a mask value + // lvl = GetTR2Level(TR2LevelNames.DORIA); + // fdataReader.ParseFromLevel(lvl); + + // TR2Entity circuitBreakerSlot = lvl.Entities[15]; + // TRRoomSector cbSector = FDUtilities.GetRoomSector(circuitBreakerSlot.X, circuitBreakerSlot.Y, circuitBreakerSlot.Z, circuitBreakerSlot.Room, lvl, fdataReader); + + // // Confirm we have a match of what we expect + // Assert.AreNotEqual(cbSector.FDIndex, 0); + // List cbEntries = fdataReader.Entries[cbSector.FDIndex]; + // Assert.AreEqual(cbEntries.Count, 1); + // Assert.IsTrue(cbEntries[0] is FDTriggerEntry); + + // FDTriggerEntry cbTrigger = cbEntries[0] as FDTriggerEntry; + + // // We expect a normal mask for Wreck so all 1's set + // Assert.AreEqual(cbTrigger.TrigSetup.Mask, 31); + + // // Take off 2 bits. This simulates having something activated + // // only after all 3 breakers are used. + // // 16 8 4 2 1 + // // ---------- + // // 1 0 0 1 1 + // // 0 1 0 1 1 + // // 0 0 1 1 1 + // cbTrigger.TrigSetup.Mask = 7; + // Assert.AreEqual(cbTrigger.TrigSetup.Mask, 7); + + // // Save the level and re-read it to confirm it still matches. + // fdataReader.WriteToLevel(lvl); + // lvl = WriteReadTempLevel(lvl); + + // fdataReader.ParseFromLevel(lvl); + + // cbSector = FDUtilities.GetRoomSector(circuitBreakerSlot.X, circuitBreakerSlot.Y, circuitBreakerSlot.Z, circuitBreakerSlot.Room, lvl, fdataReader); + + // // Confirm we have a match of what we expect + // Assert.AreNotEqual(cbSector.FDIndex, 0); + // cbEntries = fdataReader.Entries[cbSector.FDIndex]; + // Assert.AreEqual(cbEntries.Count, 1); + // Assert.IsTrue(cbEntries[0] is FDTriggerEntry); + + // cbTrigger = cbEntries[0] as FDTriggerEntry; + + // Assert.AreEqual(cbTrigger.TrigSetup.Mask, 7); + //} [TestMethod] public void ModifyZonesTest() diff --git a/TRLevelControlTests/TR3/FDTests.cs b/TRLevelControlTests/TR3/FDTests.cs new file mode 100644 index 000000000..89afd7d84 --- /dev/null +++ b/TRLevelControlTests/TR3/FDTests.cs @@ -0,0 +1,159 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TRLevelControl.Model; + +namespace TRLevelControlTests.TR3; + +[TestClass] +[TestCategory("FD")] +public class FDTests : FDTestBase +{ + [TestMethod] + [Description("Test adding a monkey swing.")] + public void AddMonkeySwing() + { + TR3Level level = GetTR3TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + List entries = level.FloorData[sector.FDIndex]; + entries.Add(new FDMonkeySwingEntry()); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreNotEqual(0, sector.FDIndex); + + FDMonkeySwingEntry monkey = entries.Find(e => e is FDMonkeySwingEntry) as FDMonkeySwingEntry; + Assert.IsNotNull(monkey); + } + + [TestMethod] + [Description("Test adding minecart entries.")] + public void AddMinecart() + { + static void TestMinecart(FDMinecartType type) + { + TR3Level level = GetTR3TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + List entries = level.FloorData[sector.FDIndex]; + entries.Add(new FDMinecartEntry + { + Type = type + }); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreNotEqual(0, sector.FDIndex); + + FDMinecartEntry minecart = entries.Find(e => e is FDMinecartEntry) as FDMinecartEntry; + Assert.IsNotNull(minecart); + Assert.AreEqual(type, minecart.Type); + } + + TestMinecart(FDMinecartType.Left); + TestMinecart(FDMinecartType.Right); + } + + [TestMethod] + [Description("Test adding floor triangulation.")] + public void AddFloorTriangulation() + { + TR3Level level = GetTR3TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + List entries = level.FloorData[sector.FDIndex]; + entries.Add(new FDTriangulationEntry + { + Type = FDTriangulationType.FloorNWSE_Solid, + C00 = 1, + C01 = 2, + C10 = 3, + C11 = 4, + H1 = 5, + H2 = 6, + }); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreNotEqual(0, sector.FDIndex); + + FDTriangulationEntry triangle = entries.Find(e => e is FDTriangulationEntry) as FDTriangulationEntry; + Assert.IsNotNull(triangle); + Assert.AreEqual(FDTriangulationType.FloorNWSE_Solid, triangle.Type); + Assert.AreEqual(1, triangle.C00); + Assert.AreEqual(2, triangle.C01); + Assert.AreEqual(3, triangle.C10); + Assert.AreEqual(4, triangle.C11); + Assert.AreEqual(5, triangle.H1); + Assert.AreEqual(6, triangle.H2); + } + + [TestMethod] + [Description("Test adding ceiling triangulation.")] + public void AddCeilingTriangulation() + { + TR3Level level = GetTR3TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + List entries = level.FloorData[sector.FDIndex]; + entries.Add(new FDTriangulationEntry + { + Type = FDTriangulationType.CeilingNWSE_NE, + C00 = 6, + C01 = 5, + C10 = 4, + C11 = 3, + H1 = 2, + H2 = 1, + }); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreNotEqual(0, sector.FDIndex); + + FDTriangulationEntry triangle = entries.Find(e => e is FDTriangulationEntry) as FDTriangulationEntry; + Assert.IsNotNull(triangle); + Assert.AreEqual(FDTriangulationType.CeilingNWSE_NE, triangle.Type); + Assert.AreEqual(6, triangle.C00); + Assert.AreEqual(5, triangle.C01); + Assert.AreEqual(4, triangle.C10); + Assert.AreEqual(3, triangle.C11); + Assert.AreEqual(2, triangle.H1); + Assert.AreEqual(1, triangle.H2); + } + + [TestMethod] + [Description("Add invalid FD entries for TR3.")] + public void AddInvalidEntries() + { + TR3Level level = GetTR3TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + level.FloorData[sector.FDIndex].AddRange(new List + { + new FDBeetleEntry(), + new FDDeferredTriggerEntry(), + }); + + WriteReadTempLevel(level); + Assert.AreEqual(0, sector.FDIndex); + } +} diff --git a/TRLevelControlTests/TR3/IOTests.cs b/TRLevelControlTests/TR3/IOTests.cs index b95b8d1ff..ab722e242 100644 --- a/TRLevelControlTests/TR3/IOTests.cs +++ b/TRLevelControlTests/TR3/IOTests.cs @@ -1,5 +1,4 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using TRFDControl; using TRLevelControl; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -23,49 +22,34 @@ public void TestReadWrite(string levelName) [TestMethod] [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] - public void TestFloorData(string levelName) + public void TestAgressiveFloorData(string levelName) { TR3Level level = GetTR3Level(levelName); + IEnumerable allFDSectors = level.Rooms.SelectMany(r => r.Sectors.Where(s => s.FDIndex != 0)); - List originalData = new(level.FloorData); - - FDControl fdControl = new(); - - if (levelName == TR3LevelNames.ANTARC) + foreach (TRRoomSector sector in allFDSectors) { - // Antarctica has a single ceiling triangulation entry that is not referenced by any - // room sector. It precedes the entry for room 69 [7,2], and there is a room above - // with a regular ceiling slant. We will modify that sector to include the extra entry - // for the sake of this test. FDControl by design strips out unused data. - IEnumerable allSectors = level.Rooms.SelectMany(r => r.Sectors); - Assert.IsFalse(allSectors.Any(s => s.FDIndex == 8142)); - TRRoomSector sector = allSectors.First(s => s.FDIndex == 8144); - Assert.IsNotNull(sector); - sector.FDIndex = 8142; + Assert.IsTrue(level.FloorData.ContainsKey(sector.FDIndex)); } - - fdControl.ParseFromLevel(level); - fdControl.WriteToLevel(level); - - CollectionAssert.AreEqual(originalData, level.FloorData); + Assert.AreEqual(allFDSectors.Count(), allFDSectors.DistinctBy(s => s.FDIndex).Count()); } - [TestMethod] - public void Floordata_ReadWrite_LevelHasMonkeySwingTest() - { - TR3Level lvl = GetTR3Level(TR3LevelNames.THAMES); + //[TestMethod] + //public void Floordata_ReadWrite_LevelHasMonkeySwingTest() + //{ + // TR3Level lvl = GetTR3Level(TR3LevelNames.THAMES); - //Store the original floordata from the level - List originalFData = new(lvl.FloorData); + // //Store the original floordata from the level + // List originalFData = new(lvl.FloorData); - //Parse the floordata using FDControl and re-write the parsed data back - FDControl fdataReader = new(); - fdataReader.ParseFromLevel(lvl); - fdataReader.WriteToLevel(lvl); + // //Parse the floordata using FDControl and re-write the parsed data back + // FDControl fdataReader = new(); + // fdataReader.ParseFromLevel(lvl); + // fdataReader.WriteToLevel(lvl); - //Compare to make sure the original fdata was written back. - CollectionAssert.AreEqual(originalFData, lvl.FloorData, "Floordata does not match");; - } + // //Compare to make sure the original fdata was written back. + // CollectionAssert.AreEqual(originalFData, lvl.FloorData, "Floordata does not match");; + //} [TestMethod] public void ModifyZonesTest() @@ -192,7 +176,7 @@ public void TestSecretTriggerMasks() List> secrets = new(); // Create a secret up to the limit for this "level" and set its mask and door - for (ushort secretIndex = 0; secretIndex < totalSecrets; secretIndex++) + for (short secretIndex = 0; secretIndex < totalSecrets; secretIndex++) { TRSecretPlacement secret = new() { diff --git a/TRLevelControlTests/TR4/FDTests.cs b/TRLevelControlTests/TR4/FDTests.cs new file mode 100644 index 000000000..ffc6df43d --- /dev/null +++ b/TRLevelControlTests/TR4/FDTests.cs @@ -0,0 +1,72 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TRLevelControl.Model; + +namespace TRLevelControlTests.TR4; + +[TestClass] +[TestCategory("FD")] +public class FDTests : FDTestBase +{ + [TestMethod] + [Description("Test adding a beetle entry.")] + public void AddBeetle() + { + TR4Level level = GetTR4TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + List entries = level.FloorData[sector.FDIndex]; + entries.Add(new FDBeetleEntry()); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreNotEqual(0, sector.FDIndex); + + FDBeetleEntry beetle = entries.Find(e => e is FDBeetleEntry) as FDBeetleEntry; + Assert.IsNotNull(beetle); + } + + [TestMethod] + [Description("Test adding a deferred trigger entry.")] + public void AddDeferredTrigger() + { + TR4Level level = GetTR4TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + List entries = level.FloorData[sector.FDIndex]; + entries.Add(new FDDeferredTriggerEntry()); + + level = WriteReadTempLevel(level); + + sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreNotEqual(0, sector.FDIndex); + + FDDeferredTriggerEntry trig = entries.Find(e => e is FDDeferredTriggerEntry) as FDDeferredTriggerEntry; + Assert.IsNotNull(trig); + } + + [TestMethod] + [Description("Add invalid FD entries for TR4.")] + public void AddInvalidEntries() + { + TR4Level level = GetTR4TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + level.FloorData[sector.FDIndex].AddRange(new List + { + new FDMinecartEntry(), + }); + + WriteReadTempLevel(level); + Assert.AreEqual(0, sector.FDIndex); + } +} diff --git a/TRLevelControlTests/TR4/IOTests.cs b/TRLevelControlTests/TR4/IOTests.cs index 59509b514..ec54d74b5 100644 --- a/TRLevelControlTests/TR4/IOTests.cs +++ b/TRLevelControlTests/TR4/IOTests.cs @@ -1,5 +1,4 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using TRFDControl; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -20,50 +19,49 @@ public void TestReadWrite(string levelname) [TestMethod] [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] - public void TestFloorData(string levelName) + public void TestAgressiveFloorData(string levelName) { TR4Level level = GetTR4Level(levelName); + IEnumerable allFDSectors = level.Rooms.SelectMany(r => r.Sectors.Where(s => s.FDIndex != 0)); - List originalData = new(level.FloorData); - - FDControl fdControl = new(); - fdControl.ParseFromLevel(level); - fdControl.WriteToLevel(level); - - CollectionAssert.AreEqual(originalData, level.FloorData); + foreach (TRRoomSector sector in allFDSectors) + { + Assert.IsTrue(level.FloorData.ContainsKey(sector.FDIndex)); + } + Assert.AreEqual(allFDSectors.Count(), allFDSectors.DistinctBy(s => s.FDIndex).Count()); } - [TestMethod] - public void Floordata_ReadWrite_MechBeetleTest() - { - TR4Level lvl = GetTR4Level(TR4LevelNames.CLEOPATRA); + //[TestMethod] + //public void Floordata_ReadWrite_MechBeetleTest() + //{ + // TR4Level lvl = GetTR4Level(TR4LevelNames.CLEOPATRA); - //Store the original floordata from the level - List originalFData = new(lvl.FloorData); + // //Store the original floordata from the level + // List originalFData = new(lvl.FloorData); - //Parse the floordata using FDControl and re-write the parsed data back - FDControl fdataReader = new(); - fdataReader.ParseFromLevel(lvl); - fdataReader.WriteToLevel(lvl); + // //Parse the floordata using FDControl and re-write the parsed data back + // FDControl fdataReader = new(); + // fdataReader.ParseFromLevel(lvl); + // fdataReader.WriteToLevel(lvl); - //Compare to make sure the original fdata was written back. - CollectionAssert.AreEqual(originalFData, lvl.FloorData, "Floordata does not match"); - } + // //Compare to make sure the original fdata was written back. + // CollectionAssert.AreEqual(originalFData, lvl.FloorData, "Floordata does not match"); + //} - [TestMethod] - public void Floordata_ReadWrite_TriggerTriggererTest() - { - TR4Level lvl = GetTR4Level(TR4LevelNames.ALEXANDRIA); + //[TestMethod] + //public void Floordata_ReadWrite_TriggerTriggererTest() + //{ + // TR4Level lvl = GetTR4Level(TR4LevelNames.ALEXANDRIA); - //Store the original floordata from the level - List originalFData = new(lvl.FloorData); + // //Store the original floordata from the level + // List originalFData = new(lvl.FloorData); - //Parse the floordata using FDControl and re-write the parsed data back - FDControl fdataReader = new(); - fdataReader.ParseFromLevel(lvl); - fdataReader.WriteToLevel(lvl); + // //Parse the floordata using FDControl and re-write the parsed data back + // FDControl fdataReader = new(); + // fdataReader.ParseFromLevel(lvl); + // fdataReader.WriteToLevel(lvl); - //Compare to make sure the original fdata was written back. - CollectionAssert.AreEqual(originalFData, lvl.FloorData, "Floordata does not match"); - } + // //Compare to make sure the original fdata was written back. + // CollectionAssert.AreEqual(originalFData, lvl.FloorData, "Floordata does not match"); + //} } diff --git a/TRLevelControlTests/TR5/FDTests.cs b/TRLevelControlTests/TR5/FDTests.cs new file mode 100644 index 000000000..3841e63ce --- /dev/null +++ b/TRLevelControlTests/TR5/FDTests.cs @@ -0,0 +1,28 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TRLevelControl.Model; + +namespace TRLevelControlTests.TR5; + +[TestClass] +[TestCategory("FD")] +public class FDTests : FDTestBase +{ + [TestMethod] + [Description("Add invalid FD entries for TR5.")] + public void AddInvalidEntries() + { + TR5Level level = GetTR5TestLevel(); + + TRRoomSector sector = level.Rooms[2].GetSector(4608, 6656); + Assert.AreEqual(0, sector.FDIndex); + + level.FloorData.CreateFloorData(sector); + level.FloorData[sector.FDIndex].AddRange(new List + { + new FDMinecartEntry(), + }); + + WriteReadTempLevel(level); + Assert.AreEqual(0, sector.FDIndex); + } +} diff --git a/TRLevelControlTests/TR5/IOTests.cs b/TRLevelControlTests/TR5/IOTests.cs index 66f9c46fe..4c05c11d9 100644 --- a/TRLevelControlTests/TR5/IOTests.cs +++ b/TRLevelControlTests/TR5/IOTests.cs @@ -16,4 +16,18 @@ public void TestReadWrite(string levelName) { ReadWriteLevel(levelName, TRGameVersion.TR5); } + + [TestMethod] + [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] + public void TestAgressiveFloorData(string levelName) + { + TR5Level level = GetTR5Level(levelName); + IEnumerable allFDSectors = level.Rooms.SelectMany(r => r.Sectors.Where(s => s.FDIndex != 0)); + + foreach (TRRoomSector sector in allFDSectors) + { + Assert.IsTrue(level.FloorData.ContainsKey(sector.FDIndex)); + } + Assert.AreEqual(allFDSectors.Count(), allFDSectors.DistinctBy(s => s.FDIndex).Count()); + } } diff --git a/TRLevelControlTests/TR5/RoomTests.cs b/TRLevelControlTests/TR5/RoomTests.cs index bc5f132d5..5d9b196d5 100644 --- a/TRLevelControlTests/TR5/RoomTests.cs +++ b/TRLevelControlTests/TR5/RoomTests.cs @@ -117,7 +117,6 @@ public void TestRoomToRoomlet() { BoxIndex = (ushort)i, Ceiling = (sbyte)i, - FDIndex = (ushort)(i * i), Floor = (sbyte)-i, RoomAbove = (byte)rand.Next(0, 256), RoomBelow = (byte)rand.Next(0, 256), diff --git a/TRLevelControlTests/TRLevelControlTests.csproj b/TRLevelControlTests/TRLevelControlTests.csproj index c923bb67d..0505c8e4d 100644 --- a/TRLevelControlTests/TRLevelControlTests.csproj +++ b/TRLevelControlTests/TRLevelControlTests.csproj @@ -29,6 +29,30 @@ + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + PreserveNewest diff --git a/TRLevelToolset/Controls/DataControls/TR/TRFloorDataControl.cs b/TRLevelToolset/Controls/DataControls/TR/TRFloorDataControl.cs index a23e84a98..26fd134d8 100644 --- a/TRLevelToolset/Controls/DataControls/TR/TRFloorDataControl.cs +++ b/TRLevelToolset/Controls/DataControls/TR/TRFloorDataControl.cs @@ -10,7 +10,7 @@ public void Draw() { if (ImGui.TreeNodeEx("Floor Data", ImGuiTreeNodeFlags.OpenOnArrow)) { - ImGui.Text("Floor Data Size: " + IOManager.CurrentLevelAsTR1?.FloorData.Count + " uint16s."); + ImGui.Text("Floor Data Size: " + IOManager.CurrentLevelAsTR1?.FloorData.SelectMany(f => f.Value).Count() + " floor functions."); ImGui.TreePop(); } diff --git a/TRRandomizerCore/Helpers/ItemFactory.cs b/TRRandomizerCore/Helpers/ItemFactory.cs index 9847307da..f758bef9f 100644 --- a/TRRandomizerCore/Helpers/ItemFactory.cs +++ b/TRRandomizerCore/Helpers/ItemFactory.cs @@ -94,7 +94,7 @@ public T CreateItem(string lvl, List allItems, Location location = null, bool item.X = location.X; item.Y = location.Y; item.Z = location.Z; - item.Room = (short)location.Room; + item.Room = location.Room; item.Angle = location.Angle; } diff --git a/TRRandomizerCore/Helpers/Location.cs b/TRRandomizerCore/Helpers/Location.cs index 08e9c5d49..37fc89e17 100644 --- a/TRRandomizerCore/Helpers/Location.cs +++ b/TRRandomizerCore/Helpers/Location.cs @@ -1,16 +1,17 @@ using System.ComponentModel; using System.Numerics; +using TRLevelControl.Model; namespace TRRandomizerCore.Helpers; -public class Location +public class Location : ITRLocatable { public const string DefaultPackID = "TRRando"; public int X { get; set; } public int Y { get; set; } public int Z { get; set; } - public int Room { get; set; } + public short Room { get; set; } public bool RequiresGlitch { get; set; } public Difficulty Difficulty { get; set; } public ItemRange Range { get; set; } diff --git a/TRRandomizerCore/Processors/TR2/TR2EnemyAdjuster.cs b/TRRandomizerCore/Processors/TR2/TR2EnemyAdjuster.cs index aa6ca8220..749f9c3bc 100644 --- a/TRRandomizerCore/Processors/TR2/TR2EnemyAdjuster.cs +++ b/TRRandomizerCore/Processors/TR2/TR2EnemyAdjuster.cs @@ -1,6 +1,4 @@ -using TRFDControl; -using TRFDControl.Utilities; -using TRGE.Core; +using TRGE.Core; using TRLevelControl.Helpers; using TRLevelControl.Model; using TRRandomizerCore.Helpers; @@ -39,16 +37,11 @@ public void AdjustEnemies() private void AdjustInstanceEnemies() { - FDControl floorData = new(); - floorData.ParseFromLevel(_levelInstance.Data); - foreach (int enemyIndex in _enemyTargets[_levelInstance.Name]) { _levelInstance.Data.Entities[enemyIndex].TypeID = TR2Type.CameraTarget_N; - FDUtilities.RemoveEntityTriggers(_levelInstance.Data, enemyIndex, floorData); + _levelInstance.Data.FloorData.RemoveEntityTriggers(enemyIndex); ItemFactory?.FreeItem(_levelInstance.Name, enemyIndex); } - - floorData.WriteToLevel(_levelInstance.Data); } } diff --git a/TRRandomizerCore/Processors/TR3/TR3SequenceProcessor.cs b/TRRandomizerCore/Processors/TR3/TR3SequenceProcessor.cs index 8286a8018..82f46a7f3 100644 --- a/TRRandomizerCore/Processors/TR3/TR3SequenceProcessor.cs +++ b/TRRandomizerCore/Processors/TR3/TR3SequenceProcessor.cs @@ -1,9 +1,6 @@ using Newtonsoft.Json; using TREnvironmentEditor; using TREnvironmentEditor.Model; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl; using TRLevelControl.Helpers; @@ -227,20 +224,13 @@ private static void AddColdLevelMedis(TR3CombinedLevel level) private static void AmendAntarctica(TR3CombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - TRRoomSector sector = FDUtilities.GetRoomSector(53760, -3328, 28160, 185, level.Data, floorData); + TRRoomSector sector = level.Data.GetRoomSector(53760, -3328, 28160, 185); if (sector.FDIndex == 0) { - floorData.CreateFloorData(sector); + level.Data.FloorData.CreateFloorData(sector); } - floorData.Entries[sector.FDIndex].Add(new FDKillLaraEntry - { - Setup = new FDSetup(FDFunction.KillLara) - }); - - floorData.WriteToLevel(level.Data); + level.Data.FloorData[sector.FDIndex].Add(new FDKillLaraEntry()); } private void ImportArtefactMenuModels(TR3CombinedLevel level) diff --git a/TRRandomizerCore/Randomizers/Shared/AudioRandomizer.cs b/TRRandomizerCore/Randomizers/Shared/AudioRandomizer.cs index e19736de2..b033be918 100644 --- a/TRRandomizerCore/Randomizers/Shared/AudioRandomizer.cs +++ b/TRRandomizerCore/Randomizers/Shared/AudioRandomizer.cs @@ -1,6 +1,4 @@ using System.Numerics; -using TRFDControl; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl; using TRLevelControl.Model; @@ -33,7 +31,7 @@ public void RandomizeFloorTracks(List sectors, FDControl floorData FDActionItem trackItem = null; if (sector.FDIndex > 0) { - List actions = FDUtilities.GetActionListItems(floorData, FDTrigAction.PlaySoundtrack, sector.FDIndex); + List actions = floorData.GetActionItems(FDTrigAction.PlaySoundtrack, sector.FDIndex); if (actions.Count > 0) { trackItem = actions[0]; @@ -53,7 +51,7 @@ public void RandomizeFloorTracks(List sectors, FDControl floorData if (!_trackMap.ContainsKey(position)) { - TRAudioCategory category = FindTrackCategory(trackItem.Parameter); + TRAudioCategory category = FindTrackCategory((ushort)trackItem.Parameter); List tracks = _tracks[category]; _trackMap[position] = tracks[generator.Next(0, tracks.Count)].ID; } @@ -72,7 +70,7 @@ public void RandomizeFloorTracks(List sectors, FDControl floorData } } - trackItem.Parameter = _trackMap[position]; + trackItem.Parameter = (short)_trackMap[position]; } } diff --git a/TRRandomizerCore/Randomizers/Shared/LocationPicker.cs b/TRRandomizerCore/Randomizers/Shared/LocationPicker.cs index 6c5d1cb2a..6030a5a3f 100644 --- a/TRRandomizerCore/Randomizers/Shared/LocationPicker.cs +++ b/TRRandomizerCore/Randomizers/Shared/LocationPicker.cs @@ -12,7 +12,7 @@ public class LocationPicker : IRouteManager private readonly Dictionary> _routes; private List _locations, _usedTriggerLocations, _currentRoute; - private List _allRooms; + private List _allRooms; private RandomizerSettings _settings; private Random _generator; @@ -75,7 +75,7 @@ private void LoadCurrentRoute(string levelName) } else { - location.Room = RoomInfos.IndexOf(matchingInfos[0]); + location.Room = (short)RoomInfos.IndexOf(matchingInfos[0]); } } } @@ -115,7 +115,7 @@ public void RandomizeKeyItemLocation(TREntity entity, bool hasPickupTrigge public Location GetKeyItemLocation(int keyItemID, TREntity entity, bool hasPickupTrigger) where T : Enum { - List roomPool = GetRoomPool(keyItemID); + List roomPool = GetRoomPool(keyItemID); if (roomPool.Count == 0) { // This key item must remain static. @@ -154,9 +154,9 @@ public Location GetKeyItemLocation(int keyItemID, TREntity entity, bool ha return newLocation; } - public List GetRoomPool(int keyItemID) + public List GetRoomPool(int keyItemID) { - List roomPool = new(); + List roomPool = new(); if (_currentRoute == null) { return roomPool; @@ -247,7 +247,7 @@ public int GetRoutePosition(Location location) return _currentRoute.FindIndex(l => l.Room == location.Room); } - public List GetRouteRooms() + public List GetRouteRooms() { return _currentRoute .Select(l => l.Room) @@ -284,7 +284,7 @@ public int GetProximity(Location location1, Location location2) return distance; } - public Location GetRandomLocation(List roomPool = null) + public Location GetRandomLocation(List roomPool = null) { if (roomPool == null || !_locations.Any(l => roomPool.Contains(l.Room))) { @@ -324,7 +324,7 @@ public void SetLocation(TREntity entity, Location location) entity.X = location.X; entity.Y = location.Y; entity.Z = location.Z; - entity.Room = (short)location.Room; + entity.Room = location.Room; entity.Angle = location.Angle; // Anything other than -1 means a sloped sector and so the location generator diff --git a/TRRandomizerCore/Randomizers/TR1/TR1AudioRandomizer.cs b/TRRandomizerCore/Randomizers/TR1/TR1AudioRandomizer.cs index 55d2fc606..db3bdac8c 100644 --- a/TRRandomizerCore/Randomizers/TR1/TR1AudioRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR1/TR1AudioRandomizer.cs @@ -1,7 +1,5 @@ using Newtonsoft.Json; using System.Numerics; -using TRFDControl; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl; using TRLevelControl.Helpers; @@ -118,13 +116,10 @@ private void RandomizeMusicTriggers(TR1CombinedLevel level) { if (Settings.ChangeTriggerTracks) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - _audioRandomizer.ResetFloorMap(); foreach (TR1Room room in level.Data.Rooms.Where(r => !r.Flags.HasFlag(TRRoomFlag.Unused2))) { - _audioRandomizer.RandomizeFloorTracks(room.Sectors, floorData, _generator, sectorIndex => + _audioRandomizer.RandomizeFloorTracks(room.Sectors, level.Data.FloorData, _generator, sectorIndex => { // Get the midpoint of the tile in world coordinates return new Vector2 @@ -134,8 +129,6 @@ private void RandomizeMusicTriggers(TR1CombinedLevel level) ); }); } - - floorData.WriteToLevel(level.Data); } } @@ -246,11 +239,8 @@ private void ImportSpeechSFX(TR1CombinedLevel level) // track, so ensure that the required data is in the level if any // of these are used on the floor. - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - - List usedSpeechTracks = FDUtilities.GetActionListItems(floorData, FDTrigAction.PlaySoundtrack) - .Select(action => action.Parameter) + List usedSpeechTracks = level.Data.FloorData.GetActionItems(FDTrigAction.PlaySoundtrack) + .Select(action => (ushort)action.Parameter) .Distinct() .Where(trackID => _speechTracks.Contains(trackID)) .ToList(); diff --git a/TRRandomizerCore/Randomizers/TR1/TR1EnemyRandomizer.cs b/TRRandomizerCore/Randomizers/TR1/TR1EnemyRandomizer.cs index 496d0c7bc..485093c01 100644 --- a/TRRandomizerCore/Randomizers/TR1/TR1EnemyRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR1/TR1EnemyRandomizer.cs @@ -2,9 +2,6 @@ using System.Diagnostics; using System.Numerics; using TREnvironmentEditor.Model.Types; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl; using TRLevelControl.Helpers; @@ -194,12 +191,10 @@ private void AdjustUnkillableEnemies(TR1CombinedLevel level) { // There is a triggered centaur in room 18, plus several untriggered eggs for show. // Move the centaur, and free the eggs to be repurposed elsewhere. - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); foreach (TR1Entity enemy in level.Data.Entities.Where(e => e.Room == _unreachableStrongholdRoom)) { int index = level.Data.Entities.IndexOf(enemy); - if (FDUtilities.GetEntityTriggers(floorData, index).Count == 0) + if (level.Data.FloorData.GetEntityTriggers(index).Count == 0) { enemy.TypeID = TR1Type.CameraTarget_N; ItemFactory.FreeItem(level.Name, index); @@ -516,9 +511,6 @@ private void RandomizeEnemies(TR1CombinedLevel level, EnemyRandomizationCollecti RandoDifficulty difficulty = GetImpliedDifficulty(); - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - // First iterate through any enemies that are restricted by room Dictionary> enemyRooms = TR1EnemyUtilities.GetRestrictedEnemyRooms(level.Name, difficulty); if (enemyRooms != null) @@ -566,7 +558,7 @@ private void RandomizeEnemies(TR1CombinedLevel level, EnemyRandomizationCollecti targetEntity.TypeID = TR1TypeUtilities.TranslateAlias(entity); // #146 Ensure OneShot triggers are set for this enemy if needed - TR1EnemyUtilities.SetEntityTriggers(level.Data, targetEntity, floorData); + TR1EnemyUtilities.SetEntityTriggers(level.Data, targetEntity); if (Settings.HideEnemiesUntilTriggered || entity == TR1Type.Adam) { @@ -601,7 +593,7 @@ private void RandomizeEnemies(TR1CombinedLevel level, EnemyRandomizationCollecti } List enemyPool; - if (difficulty == RandoDifficulty.Default && IsEnemyInOrAboveWater(currentEntity, level.Data, floorData)) + if (difficulty == RandoDifficulty.Default && IsEnemyInOrAboveWater(currentEntity, level.Data)) { // Make sure we replace with another water enemy enemyPool = enemies.Water; @@ -716,7 +708,7 @@ private void RandomizeEnemies(TR1CombinedLevel level, EnemyRandomizationCollecti currentEntity.Y = eggLocation.Y; currentEntity.Z = eggLocation.Z; currentEntity.Angle = eggLocation.Angle; - currentEntity.Room = (short)eggLocation.Room; + currentEntity.Room = eggLocation.Room; } // Eggs will always be visible @@ -737,7 +729,7 @@ private void RandomizeEnemies(TR1CombinedLevel level, EnemyRandomizationCollecti if (newEntityType == TR1Type.CentaurStatue) { - AdjustCentaurStatue(currentEntity, level.Data, floorData); + AdjustCentaurStatue(currentEntity, level.Data); } else if (newEntityType == TR1Type.Adam) { @@ -750,7 +742,7 @@ private void RandomizeEnemies(TR1CombinedLevel level, EnemyRandomizationCollecti currentEntity.TypeID = TR1TypeUtilities.TranslateAlias(newEntityType); // #146 Ensure OneShot triggers are set for this enemy if needed - TR1EnemyUtilities.SetEntityTriggers(level.Data, currentEntity, floorData); + TR1EnemyUtilities.SetEntityTriggers(level.Data, currentEntity); if (currentEntity.TypeID == TR1Type.Pierre && _pierreLocations.ContainsKey(level.Name) @@ -774,7 +766,7 @@ private void RandomizeEnemies(TR1CombinedLevel level, EnemyRandomizationCollecti { TR1Entity pierreReplacement = level.Data.Entities[TR1ItemRandomizer.TihocanPierreIndex]; if (Settings.AllowEnemyKeyDrops - && TR1EnemyUtilities.CanDropItems(pierreReplacement, level, floorData)) + && TR1EnemyUtilities.CanDropItems(pierreReplacement, level)) { // Whichever enemy has taken Pierre's place will drop the items. Move the pickups to the enemy for trview lookup. level.Script.AddItemDrops(TR1ItemRandomizer.TihocanPierreIndex, TR1ItemRandomizer.TihocanEndItems @@ -799,8 +791,6 @@ private void RandomizeEnemies(TR1CombinedLevel level, EnemyRandomizationCollecti } } - floorData.WriteToLevel(level.Data); - // Fix missing OG animation SFX FixEnemyAnimations(level); @@ -844,7 +834,7 @@ private static int GetEntityCount(TR1CombinedLevel level, TR1Type entityType) return count; } - private static bool IsEnemyInOrAboveWater(TR1Entity entity, TR1Level level, FDControl floorData) + private static bool IsEnemyInOrAboveWater(TR1Entity entity, TR1Level level) { if (level.Rooms[entity.Room].ContainsWater) { @@ -852,14 +842,14 @@ private static bool IsEnemyInOrAboveWater(TR1Entity entity, TR1Level level, FDCo } // Example where we have to search is Midas room 21 - TRRoomSector sector = FDUtilities.GetRoomSector(entity.X, entity.Y - TRConsts.Step1, entity.Z, entity.Room, level, floorData); + TRRoomSector sector = level.GetRoomSector(entity.X, entity.Y - TRConsts.Step1, entity.Z, entity.Room); while (sector.RoomBelow != TRConsts.NoRoom) { if (level.Rooms[sector.RoomBelow].ContainsWater) { return true; } - sector = FDUtilities.GetRoomSector(entity.X, (sector.Floor + 1) * TRConsts.Step1, entity.Z, sector.RoomBelow, level, floorData); + sector = level.GetRoomSector(entity.X, (sector.Floor + 1) * TRConsts.Step1, entity.Z, sector.RoomBelow); } return false; } @@ -963,27 +953,28 @@ private void AmendAtlanteanModels(TR1CombinedLevel level, EnemyRandomizationColl } } - private static void AdjustCentaurStatue(TR1Entity entity, TR1Level level, FDControl floorData) + private static void AdjustCentaurStatue(TR1Entity entity, TR1Level level) { // If they're floating, they tend not to trigger as Lara's not within range TR1LocationGenerator locationGenerator = new(); int y = entity.Y; short room = entity.Room; - TRRoomSector sector = FDUtilities.GetRoomSector(entity.X, y, entity.Z, room, level, floorData); + TRRoomSector sector = level.GetRoomSector(entity.X, y, entity.Z, room); while (sector.RoomBelow != TRConsts.NoRoom) { y = (sector.Floor + 1) * TRConsts.Step1; room = sector.RoomBelow; - sector = FDUtilities.GetRoomSector(entity.X, y, entity.Z, room, level, floorData); + sector = level.GetRoomSector(entity.X, y, entity.Z, room); } entity.Y = sector.Floor * TRConsts.Step1; entity.Room = room; + // Change this GetHeight if (sector.FDIndex != 0) { - FDEntry entry = floorData.Entries[sector.FDIndex].Find(e => e is FDSlantEntry s && s.Type == FDSlantType.FloorSlant); + FDEntry entry = level.FloorData[sector.FDIndex].Find(e => e is FDSlantEntry s && s.Type == FDSlantType.Floor); if (entry is FDSlantEntry slant) { Vector4? bestMidpoint = locationGenerator.GetBestSlantMidpoint(slant); @@ -1034,13 +1025,11 @@ private void AddUnarmedLevelAmmo(TR1CombinedLevel level) List levelEnemies = level.Data.Entities.FindAll(e => allEnemies.Contains(e.TypeID)); // #409 Eggs are excluded as they are not part of the cross-level enemy pool, so create copies of any // of these using their actual types so to ensure they are part of the difficulty calculation. - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); for (int i = 0; i < level.Data.Entities.Count; i++) { TR1Entity entity = level.Data.Entities[i]; if ((entity.TypeID == TR1Type.AtlanteanEgg || entity.TypeID == TR1Type.AdamEgg) - && FDUtilities.GetEntityTriggers(floorData, i).Count > 0) + && level.Data.FloorData.GetEntityTriggers(i).Count > 0) { TR1Entity resultantEnemy = new() { @@ -1276,20 +1265,15 @@ private static void FixColosseumBats(TR1CombinedLevel level) { // Fix the bat trigger in Colosseum. Done outside of environment mods to allow for cloning. // Item 74 is duplicated in each trigger. - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - - foreach (FDTriggerEntry trigger in FDUtilities.GetEntityTriggers(floorData, 74)) + foreach (FDTriggerEntry trigger in level.Data.FloorData.GetEntityTriggers(74)) { - List actions = trigger.TrigActionList - .FindAll(a => a.TrigAction == FDTrigAction.Object && a.Parameter == 74); + List actions = trigger.Actions + .FindAll(a => a.Action == FDTrigAction.Object && a.Parameter == 74); if (actions.Count == 2) { actions[0].Parameter = 73; } } - - floorData.WriteToLevel(level.Data); } private void CloneEnemies(TR1CombinedLevel level) @@ -1306,30 +1290,26 @@ private void CloneEnemies(TR1CombinedLevel level) { enemies.Add(adamEgg); } - - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); uint cloneCount = Math.Max(2, Math.Min(MaxClones, Settings.EnemyMultiplier)) - 1; short angleDiff = (short)Math.Ceiling(ushort.MaxValue / (cloneCount + 1d)); foreach (TR1Entity enemy in enemies) { - List triggers = FDUtilities.GetEntityTriggers(floorData, level.Data.Entities.IndexOf(enemy)); + List triggers = level.Data.FloorData.GetEntityTriggers(level.Data.Entities.IndexOf(enemy)); if (Settings.UseKillableClonePierres && enemy.TypeID == TR1Type.Pierre) { // Ensure OneShot, otherwise only ever one runaway Pierre - triggers.ForEach(t => t.TrigSetup.OneShot = true); + triggers.ForEach(t => t.OneShot = true); } for (int i = 0; i < cloneCount; i++) { foreach (FDTriggerEntry trigger in triggers) { - trigger.TrigActionList.Add(new() + trigger.Actions.Add(new() { - TrigAction = FDTrigAction.Object, - Parameter = (ushort)level.Data.Entities.Count + Parameter = (short)level.Data.Entities.Count }); } @@ -1343,8 +1323,6 @@ private void CloneEnemies(TR1CombinedLevel level) } } } - - floorData.WriteToLevel(level.Data); } internal class EnemyProcessor : AbstractProcessorThread diff --git a/TRRandomizerCore/Randomizers/TR1/TR1ItemRandomizer.cs b/TRRandomizerCore/Randomizers/TR1/TR1ItemRandomizer.cs index 35fcff745..7e59bf22f 100644 --- a/TRRandomizerCore/Randomizers/TR1/TR1ItemRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR1/TR1ItemRandomizer.cs @@ -1,7 +1,4 @@ using Newtonsoft.Json; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -312,9 +309,6 @@ public void RandomizeItemLocations(TR1CombinedLevel level) return; } - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - // TR1X allows us to keep the end-level stats accurate. All generated locations // should be reachable, but this may be modifed in TestEnemyItemDrop where items // are hidden. @@ -334,7 +328,7 @@ public void RandomizeItemLocations(TR1CombinedLevel level) { _picker.RandomizePickupLocation(entity); entity.Intensity = 0; - TestEnemyItemDrop(level, entity, floorData); + TestEnemyItemDrop(level, entity); } } } @@ -347,15 +341,11 @@ private List GetItemLocationPool(TR1CombinedLevel level, bool keyItemM exclusions.AddRange(_excludedLocations[level.Name]); } - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - foreach (TR1Entity entity in level.Data.Entities) { if (!TR1TypeUtilities.CanSharePickupSpace(entity.TypeID)) { - exclusions.Add(entity.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level.Data, floorData))); + exclusions.Add(entity.GetFloorLocation(loc => level.Data.GetRoomSector(loc))); } } @@ -375,10 +365,7 @@ private List GetItemLocationPool(TR1CombinedLevel level, bool keyItemM private void RandomizeKeyItems(TR1CombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - - _picker.TriggerTestAction = location => LocationUtilities.HasAnyTrigger(location, level.Data, floorData); + _picker.TriggerTestAction = location => LocationUtilities.HasAnyTrigger(location, level.Data); _picker.RoomInfos = level.Data.Rooms .Select(r => new ExtRoomInfo(r.Info, r.NumXSectors, r.NumZSectors)) .ToList(); @@ -407,13 +394,13 @@ private void RandomizeKeyItems(TR1CombinedLevel level) continue; } - bool hasPickupTrigger = LocationUtilities.HasPickupTriger(entity, i, level.Data, floorData); + bool hasPickupTrigger = LocationUtilities.HasPickupTriger(entity, i, level.Data); _picker.RandomizeKeyItemLocation(entity, hasPickupTrigger, sequence, level.Data.Rooms[entity.Room].Info); if (Settings.AllowEnemyKeyDrops && !hasPickupTrigger) { - TestEnemyItemDrop(level, entity, floorData); + TestEnemyItemDrop(level, entity); } } } @@ -431,10 +418,9 @@ private int GetKeyItemLevelSequence(TR1CombinedLevel level) return sequence; } - private void TestEnemyItemDrop(TR1CombinedLevel level, TR1Entity entity, FDControl floorData) + private void TestEnemyItemDrop(TR1CombinedLevel level, TR1Entity entity) { - TRRoomSector sectorFunc(Location loc) => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level.Data, floorData); + TRRoomSector sectorFunc(Location loc) => level.Data.GetRoomSector(loc); // There may be several enemies in one spot e.g. in cloned enemy mode. Pick one // at random for each call of this method. Always exclude empty eggs. @@ -444,7 +430,7 @@ TRRoomSector sectorFunc(Location loc) => .FindAll(e => TR1TypeUtilities.IsEnemyType(e.TypeID) || e.TypeID == TR1Type.AdamEgg) .FindAll(e => e.GetFloorLocation(sectorFunc).IsEquivalent(floor)); - if (enemies.Count == 0 || enemies.All(e => !TR1EnemyUtilities.CanDropItems(e, level, floorData))) + if (enemies.Count == 0 || enemies.All(e => !TR1EnemyUtilities.CanDropItems(e, level))) { return; } @@ -454,7 +440,7 @@ TRRoomSector sectorFunc(Location loc) => { enemy = enemies[_generator.Next(0, enemies.Count)]; } - while (!TR1EnemyUtilities.CanDropItems(enemy, level, floorData)); + while (!TR1EnemyUtilities.CanDropItems(enemy, level)); level.Script.AddItemDrops(level.Data.Entities.IndexOf(enemy), ItemUtilities.ConvertToScriptItem(entity.TypeID)); ItemUtilities.HideEntity(entity); @@ -505,14 +491,13 @@ private void RandomizeSprites() // For key items, some may be used as secrets so look for entity instances of each to determine what's what _spriteRandomizer.SecretItemTypes = new List(); _spriteRandomizer.KeyItemTypes = new List(); - FDControl floorData = new(); - floorData.ParseFromLevel(_levelInstance.Data); + foreach (TR1Type type in TR1TypeUtilities.GetKeyItemTypes()) { int typeInstanceIndex = _levelInstance.Data.Entities.FindIndex(e => e.TypeID == type); if (typeInstanceIndex != -1) { - if (IsSecretItem(_levelInstance.Data.Entities[typeInstanceIndex], typeInstanceIndex, _levelInstance.Data, floorData)) + if (IsSecretItem(_levelInstance.Data.Entities[typeInstanceIndex], typeInstanceIndex, _levelInstance.Data)) { _spriteRandomizer.SecretItemTypes.Add(type); } @@ -527,15 +512,15 @@ private void RandomizeSprites() _spriteRandomizer.Randomize(_generator); } - private static bool IsSecretItem(TR1Entity entity, int entityIndex, TR1Level level, FDControl floorData) + private static bool IsSecretItem(TR1Entity entity, int entityIndex, TR1Level level) { - TRRoomSector sector = FDUtilities.GetRoomSector(entity.X, entity.Y, entity.Z, entity.Room, level, floorData); + TRRoomSector sector = level.GetRoomSector(entity); if (sector.FDIndex != 0) { - return floorData.Entries[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger + return level.FloorData[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger && trigger.TrigType == FDTrigType.Pickup - && trigger.TrigActionList[0].Parameter == entityIndex - && trigger.TrigActionList.Find(a => a.TrigAction == FDTrigAction.SecretFound) != null; + && trigger.Actions[0].Parameter == entityIndex + && trigger.Actions.Find(a => a.Action == FDTrigAction.SecretFound) != null; } return false; diff --git a/TRRandomizerCore/Randomizers/TR1/TR1SecretRandomizer.cs b/TRRandomizerCore/Randomizers/TR1/TR1SecretRandomizer.cs index 6aff2bc63..d3ce71a37 100644 --- a/TRRandomizerCore/Randomizers/TR1/TR1SecretRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR1/TR1SecretRandomizer.cs @@ -1,9 +1,6 @@ using Newtonsoft.Json; using System.Diagnostics; using TREnvironmentEditor.Model.Types; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRGE.Core; using TRGE.Core.Item.Enums; using TRLevelControl; @@ -169,9 +166,6 @@ private void SetSecretCounts() private static void RemoveDefaultSecrets(TR1CombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - // Scan all rooms and remove any existing secret triggers. foreach (TR1Room room in level.Data.Rooms) { @@ -182,29 +176,21 @@ private static void RemoveDefaultSecrets(TR1CombinedLevel level) continue; } - List entries = floorData.Entries[sector.FDIndex]; + List entries = level.Data.FloorData[sector.FDIndex]; for (int i = entries.Count - 1; i >= 0; i--) { if (entries[i] is FDTriggerEntry trig) { // #230 Remove the secret action but retain anything else that may be triggered here - trig.TrigActionList.RemoveAll(a => a.TrigAction == FDTrigAction.SecretFound); - if (trig.TrigActionList.Count == 0) + trig.Actions.RemoveAll(a => a.Action == FDTrigAction.SecretFound); + if (trig.Actions.Count == 0) { entries.RemoveAt(i); } } } - - if (entries.Count == 0) - { - // If there isn't anything left, reset the sector to point to the dummy FD - floorData.RemoveFloorData(sector); - } } } - - floorData.WriteToLevel(level.Data); } private TRSecretRoom MakePlaceholderRewardRoom(TR1CombinedLevel level) @@ -303,47 +289,44 @@ private void ActualiseRewardRoom(TR1CombinedLevel level, TRSecretRoom level.Data.Cameras.Add(rewardRoom.Cameras[i % rewardRoom.Cameras.Count]); } - ushort cameraTarget; + short cameraTarget; if (rewardRoom.CameraTarget != null && ItemFactory.CanCreateItem(level.Name, level.Data.Entities)) { TR1Entity target = ItemFactory.CreateItem(level.Name, level.Data.Entities, rewardRoom.CameraTarget); target.TypeID = TR1Type.CameraTarget_N; - cameraTarget = (ushort)level.Data.Entities.IndexOf(target); + cameraTarget = (short)level.Data.Entities.IndexOf(target); } else { - cameraTarget = (ushort)rewardRoom.DoorIndices[0]; + cameraTarget = (short)rewardRoom.DoorIndices[0]; } - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - // Get each trigger created for each secret index and add the camera, provided // there isn't any existing camera actions. for (int i = 0; i < countedSecrets; i++) { - List secretTriggers = FDUtilities.GetSecretTriggers(floorData, i); + List secretTriggers = level.Data.FloorData.GetSecretTriggers(i); foreach (FDTriggerEntry trigger in secretTriggers) { - if (trigger.TrigActionList.Find(a => a.TrigAction == FDTrigAction.Camera) == null) + if (trigger.Actions.Find(a => a.Action == FDTrigAction.Camera) == null) { - trigger.TrigActionList.Add(new FDActionItem + trigger.Actions.Add(new FDActionItem { - TrigAction = FDTrigAction.Camera, - CamAction = new FDCameraAction { Value = 4 }, - Parameter = (ushort)rewardRoom.CameraIndices[i] + Action = FDTrigAction.Camera, + CamAction = new() + { + Timer = 4 + }, + Parameter = (short)rewardRoom.CameraIndices[i] }); - trigger.TrigActionList.Add(new FDActionItem + trigger.Actions.Add(new FDActionItem { - TrigAction = FDTrigAction.LookAtItem, + Action = FDTrigAction.LookAtItem, Parameter = cameraTarget }); } } } - - // Write back the camera triggers - floorData.WriteToLevel(level.Data); } } @@ -377,9 +360,6 @@ private static void CreateTrapdoorTrigger(TR1Entity door, ushort doorIndex, TR1L private void PlaceAllSecrets(TR1CombinedLevel level, List pickupTypes, TRSecretRoom rewardRoom) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - List locations = _locations[level.Name]; TRSecretPlacement secret = new(); @@ -395,18 +375,18 @@ private void PlaceAllSecrets(TR1CombinedLevel level, List pickupTypes, continue; secret.Location = location; - secret.EntityIndex = (ushort)ItemFactory.GetNextIndex(level.Name, level.Data.Entities, true); - secret.SecretIndex = (ushort)(secretIndex % countedSecrets); + secret.EntityIndex = (short)ItemFactory.GetNextIndex(level.Name, level.Data.Entities, true); + secret.SecretIndex = (short)(secretIndex % countedSecrets); secret.PickupType = pickupTypes[pickupIndex % pickupTypes.Count]; if (Settings.UseRewardRoomCameras && rewardRoom.HasCameras) { - secret.CameraIndex = (ushort)rewardRoom.CameraIndices[pickupIndex % rewardRoom.CameraIndices.Count]; - secret.CameraTarget = (ushort)rewardRoom.DoorIndices[0]; + secret.CameraIndex = (short)rewardRoom.CameraIndices[pickupIndex % rewardRoom.CameraIndices.Count]; + secret.CameraTarget = (short)rewardRoom.DoorIndices[0]; } secret.SetMaskAndDoor(countedSecrets, rewardRoom.DoorIndices); - PlaceSecret(level, secret, floorData); + PlaceSecret(level, secret); // This will either make a new entity or repurpose an old one TR1Entity entity = ItemFactory.CreateLockedItem(level.Name, level.Data.Entities, secret.Location, true); @@ -416,23 +396,16 @@ private void PlaceAllSecrets(TR1CombinedLevel level, List pickupTypes, pickupIndex++; } - floorData.WriteToLevel(level.Data); - AddDamageControl(level, locations); } private void RandomizeSecrets(TR1CombinedLevel level, List pickupTypes, TRSecretRoom rewardRoom) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - List locations = _locations[level.Name]; locations.Shuffle(_generator); - _secretPicker.SectorAction = loc - => FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level.Data, floorData); - _secretPicker.PlacementTestAction = loc - => TestSecretPlacement(level, loc, floorData); + _secretPicker.SectorAction = loc => level.Data.GetRoomSector(loc); + _secretPicker.PlacementTestAction = loc => TestSecretPlacement(level, loc); _routePicker.RoomInfos = level.Data.Rooms .Select(r => new ExtRoomInfo(r.Info, r.NumXSectors, r.NumZSectors)) @@ -447,17 +420,17 @@ private void RandomizeSecrets(TR1CombinedLevel level, List pickupTypes, { Location location = pickedLocations[i]; secret.Location = location; - secret.EntityIndex = (ushort)ItemFactory.GetNextIndex(level.Name, level.Data.Entities); + secret.EntityIndex = (short)ItemFactory.GetNextIndex(level.Name, level.Data.Entities); secret.PickupType = pickupTypes[pickupIndex % pickupTypes.Count]; if (Settings.UseRewardRoomCameras && rewardRoom.HasCameras) { - secret.CameraIndex = (ushort)rewardRoom.CameraIndices[pickupIndex % rewardRoom.CameraIndices.Count]; - secret.CameraTarget = (ushort)rewardRoom.DoorIndices[0]; + secret.CameraIndex = (short)rewardRoom.CameraIndices[pickupIndex % rewardRoom.CameraIndices.Count]; + secret.CameraTarget = (short)rewardRoom.DoorIndices[0]; } secret.SetMaskAndDoor(level.Script.NumSecrets, rewardRoom.DoorIndices); - PlaceSecret(level, secret, floorData); + PlaceSecret(level, secret); // This will either make a new entity or repurpose an old one. Ensure it is locked // to prevent item rando from potentially treating it as a key item. @@ -468,8 +441,6 @@ private void RandomizeSecrets(TR1CombinedLevel level, List pickupTypes, pickupIndex++; } - floorData.WriteToLevel(level.Data); - AddDamageControl(level, pickedLocations); _secretPicker.FinaliseSecretPool(pickedLocations, level.Name, itemIndex => new() { itemIndex }); } @@ -529,7 +500,7 @@ private static void PopulateScriptStrings(int index, List gameStrings, s } } - private bool TestSecretPlacement(TR1CombinedLevel level, Location location, FDControl floorData) + private bool TestSecretPlacement(TR1CombinedLevel level, Location location) { // Check if this secret is being added to a flipped room, as that won't work for (int i = 0; i < level.Data.Rooms.Count; i++) @@ -550,13 +521,13 @@ private bool TestSecretPlacement(TR1CombinedLevel level, Location location, FDCo } // Get the sector and check if it is shared with a trapdoor, breakable tile or bridge, as these won't work either. - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, (short)location.Room, level.Data, floorData); + TRRoomSector sector = level.Data.GetRoomSector(location); foreach (TR1Entity otherEntity in level.Data.Entities) { TR1Type type = otherEntity.TypeID; if (location.Room == otherEntity.Room && (TR1TypeUtilities.IsTrapdoor(type) || TR1TypeUtilities.IsBridge(type) || type == TR1Type.FallingBlock)) { - TRRoomSector otherSector = FDUtilities.GetRoomSector(otherEntity.X, otherEntity.Y, otherEntity.Z, otherEntity.Room, level.Data, floorData); + TRRoomSector otherSector = level.Data.GetRoomSector(otherEntity); if (otherSector == sector) { if (Settings.DevelopmentMode) @@ -570,13 +541,13 @@ private bool TestSecretPlacement(TR1CombinedLevel level, Location location, FDCo // Additional checks for bridge, trapdoor and breakable tile triggers that may be in rooms further below. // We look for floating secrets except if underwater or if the flipped room exists and has a floor below it. - if (!CheckSectorsBelow(level, location, sector, floorData)) + if (!CheckSectorsBelow(level, location, sector)) { Debug.WriteLine(string.Format(SC.MidairErrorMsg, level.Name, location.X, location.Y, location.Z, location.Room)); return false; } - if (!TestTriggerPlacement(level, location, (short)location.Room, sector, floorData)) + if (!TestTriggerPlacement(level, location, (short)location.Room, sector)) { return false; } @@ -585,8 +556,8 @@ private bool TestSecretPlacement(TR1CombinedLevel level, Location location, FDCo short altRoom = level.Data.Rooms[location.Room].AlternateRoom; if (altRoom != -1) { - sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, altRoom, level.Data, floorData); - if (!TestTriggerPlacement(level, location, altRoom, sector, floorData)) + sector = level.Data.GetRoomSector(location.X, location.Y, location.Z, altRoom); + if (!TestTriggerPlacement(level, location, altRoom, sector)) { return false; } @@ -600,9 +571,9 @@ private bool TestSecretPlacement(TR1CombinedLevel level, Location location, FDCo return true; } - private bool TestTriggerPlacement(TR1CombinedLevel level, Location location, short room, TRRoomSector sector, FDControl floorData) + private bool TestTriggerPlacement(TR1CombinedLevel level, Location location, short room, TRRoomSector sector) { - if (!location.Validated && LocationUtilities.HasAnyTrigger(sector, floorData)) + if (!location.Validated && LocationUtilities.HasAnyTrigger(sector, level.Data.FloorData)) { // There is already a trigger here and the location hasn't been marked as being // safe to move the action items to the new pickup trigger. @@ -615,28 +586,28 @@ private bool TestTriggerPlacement(TR1CombinedLevel level, Location location, sho return true; } - private void PlaceSecret(TR1CombinedLevel level, TRSecretPlacement secret, FDControl floorData) + private void PlaceSecret(TR1CombinedLevel level, TRSecretPlacement secret) { // This assumes TestTriggerPlacement has already been called and passed. - TRRoomSector sector = FDUtilities.GetRoomSector(secret.Location.X, secret.Location.Y, secret.Location.Z, (short)secret.Location.Room, level.Data, floorData); - CreateSecretTriggers(level, secret, (short)secret.Location.Room, floorData, sector); + TRRoomSector sector = level.Data.GetRoomSector(secret.Location); + CreateSecretTriggers(level, secret, secret.Location.Room, sector); short altRoom = level.Data.Rooms[secret.Location.Room].AlternateRoom; if (altRoom != -1) { - sector = FDUtilities.GetRoomSector(secret.Location.X, secret.Location.Y, secret.Location.Z, altRoom, level.Data, floorData); - CreateSecretTriggers(level, secret, altRoom, floorData, sector); + sector = level.Data.GetRoomSector(secret.Location.X, secret.Location.Y, secret.Location.Z, altRoom); + CreateSecretTriggers(level, secret, altRoom, sector); } // Turn off walk-to-items in TR1X if we are placing on a slope above water. if (!level.Data.Rooms[secret.Location.Room].ContainsWater - && secret.Location.IsSlipperySlope(level.Data, floorData)) + && secret.Location.IsSlipperySlope(level.Data)) { (ScriptEditor as TR1ScriptEditor).WalkToItems = false; } } - private static bool CheckSectorsBelow(TR1CombinedLevel level, Location location, TRRoomSector sector, FDControl floorData) + private static bool CheckSectorsBelow(TR1CombinedLevel level, Location location, TRRoomSector sector) { // Allow this check to be overridden with Validated - covers glitched locations. if (!location.Validated && sector.RoomBelow != TRConsts.NoRoom) @@ -651,7 +622,7 @@ private static bool CheckSectorsBelow(TR1CombinedLevel level, Location location, if (altRoom != -1) { // Flipped room may have a floor here, or be underwater - sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, level.Data.Rooms[location.Room].AlternateRoom, level.Data, floorData); + sector = level.Data.GetRoomSector(location.X, location.Y, location.Z, level.Data.Rooms[location.Room].AlternateRoom); return sector.RoomBelow == TRConsts.NoRoom || level.Data.Rooms[altRoom].ContainsWater; } @@ -661,16 +632,16 @@ private static bool CheckSectorsBelow(TR1CombinedLevel level, Location location, return true; } - private void CreateSecretTriggers(TR1CombinedLevel level, TRSecretPlacement secret, short room, FDControl floorData, TRRoomSector baseSector) + private void CreateSecretTriggers(TR1CombinedLevel level, TRSecretPlacement secret, short room, TRRoomSector baseSector) { TRRoomSector mainSector = baseSector; while (mainSector.RoomBelow != TRConsts.NoRoom) { // Ensure we go as far down as possible - for example, Atlantis room 47 sector 10,9 - but stay in the same room - mainSector = FDUtilities.GetRoomSector(secret.Location.X, (mainSector.Floor + 1) * TRConsts.Step1, secret.Location.Z, mainSector.RoomBelow, level.Data, floorData); + mainSector = level.Data.GetRoomSector(secret.Location.X, (mainSector.Floor + 1) * TRConsts.Step1, secret.Location.Z, mainSector.RoomBelow); } - CreateSecretTrigger(level, secret, room, floorData, mainSector); + CreateSecretTrigger(level, secret, room, mainSector); // Check neighbouring sectors if we are very close to tile edges. We scan 8 locations around // the secret's position based on the edge tolerance and see if the sector has changed. @@ -683,7 +654,7 @@ private void CreateSecretTriggers(TR1CombinedLevel level, TRSecretPlacement secret, short room, FDControl floorData, TRRoomSector sector) + private void CreateSecretTrigger(TR1CombinedLevel level, TRSecretPlacement secret, short room, TRRoomSector sector) { if (sector.FDIndex == 0) { - floorData.CreateFloorData(sector); + level.Data.FloorData.CreateFloorData(sector); } // Make a new pickup trigger FDTriggerEntry trigger = new() { - Setup = new() { Value = 4 }, - TrigSetup = new() - { - Value = 15872, - Mask = secret.TriggerMask - }, + Mask = secret.TriggerMask, TrigType = FDTrigType.Pickup, - TrigActionList = new() + Actions = new() { new() { - TrigAction = FDTrigAction.Object, + Action = FDTrigAction.Object, Parameter = secret.EntityIndex }, new() { - TrigAction = FDTrigAction.SecretFound, + Action = FDTrigAction.SecretFound, Parameter = secret.SecretIndex } } @@ -746,21 +712,21 @@ private void CreateSecretTrigger(TR1CombinedLevel level, TRSecretPlacement e is FDTriggerEntry) is FDTriggerEntry existingTrigger) + if (level.Data.FloorData[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry existingTrigger) { List existingActions = new(); - foreach (FDActionItem actionItem in existingTrigger.TrigActionList) + foreach (FDActionItem actionItem in existingTrigger.Actions) { - if (actionItem.TrigAction == FDTrigAction.Object) + if (actionItem.Action == FDTrigAction.Object) { if (Settings.DevelopmentMode) { @@ -776,17 +742,17 @@ private void CreateSecretTrigger(TR1CombinedLevel level, TRSecretPlacement diff --git a/TRRandomizerCore/Randomizers/TR1/TR1SecretRewardRandomizer.cs b/TRRandomizerCore/Randomizers/TR1/TR1SecretRewardRandomizer.cs index a66666a99..1f32906f6 100644 --- a/TRRandomizerCore/Randomizers/TR1/TR1SecretRewardRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR1/TR1SecretRewardRandomizer.cs @@ -73,7 +73,7 @@ private void RandomizeRewards(TR1CombinedLevel level) Location location = rewardPositions[_generator.Next(0, rewardPositions.Count)]; TR1Entity item = ItemFactory.CreateItem(level.Name, level.Data.Entities, location, true); rewardIndices.Add(level.Data.Entities.IndexOf(item)); - item.Room = (short)location.Room; + item.Room = location.Room; } foreach (int rewardIndex in rewardIndices) diff --git a/TRRandomizerCore/Randomizers/TR1/TR1StartPositionRandomizer.cs b/TRRandomizerCore/Randomizers/TR1/TR1StartPositionRandomizer.cs index ccc329b8f..c5cffa9c4 100644 --- a/TRRandomizerCore/Randomizers/TR1/TR1StartPositionRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR1/TR1StartPositionRandomizer.cs @@ -1,5 +1,4 @@ using Newtonsoft.Json; -using TRFDControl; using TRGE.Core; using TRLevelControl; using TRLevelControl.Model; @@ -35,9 +34,6 @@ private void RandomizeStartPosition(TR1CombinedLevel level) { TR1Entity lara = level.Data.Entities.Find(e => e.TypeID == TR1Type.Lara); - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - // If we haven't defined anything for a level, Lara will just be rotated. This is most likely where there are // triggers just after Lara's starting spot, so we just skip them here. if (!Settings.RotateStartPositionOnly && _startLocations.ContainsKey(level.Name)) @@ -48,12 +44,12 @@ private void RandomizeStartPosition(TR1CombinedLevel level) { location = locations[_generator.Next(0, locations.Count)]; } - while (!location.Validated || location.ContainsSecret(level.Data, floorData)); + while (!location.Validated || location.ContainsSecret(level.Data)); lara.X = location.X; lara.Y = location.Y; lara.Z = location.Z; - lara.Room = (short)location.Room; + lara.Room = location.Room; } short currentAngle = lara.Angle; diff --git a/TRRandomizerCore/Randomizers/TR1R/TR1RAudioRandomizer.cs b/TRRandomizerCore/Randomizers/TR1R/TR1RAudioRandomizer.cs index ef7b634f1..0e2d1fc2b 100644 --- a/TRRandomizerCore/Randomizers/TR1R/TR1RAudioRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR1R/TR1RAudioRandomizer.cs @@ -1,7 +1,4 @@ using System.Numerics; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl; using TRLevelControl.Model; @@ -43,28 +40,23 @@ private void LoadAudioData() private void RandomizeMusicTriggers(TR1RCombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - if (Settings.ChangeTriggerTracks) { - RandomizeFloorTracks(level.Data, floorData); + RandomizeFloorTracks(level.Data); } if (Settings.SeparateSecretTracks) { - RandomizeSecretTracks(level, floorData); - } - - floorData.WriteToLevel(level.Data); + RandomizeSecretTracks(level); + } } - private void RandomizeFloorTracks(TR1Level level, FDControl floorData) + private void RandomizeFloorTracks(TR1Level level) { _audioRandomizer.ResetFloorMap(); foreach (TR1Room room in level.Rooms.Where(r => !r.Flags.HasFlag(TRRoomFlag.Unused2))) { - _audioRandomizer.RandomizeFloorTracks(room.Sectors, floorData, _generator, sectorIndex => + _audioRandomizer.RandomizeFloorTracks(room.Sectors, level.FloorData, _generator, sectorIndex => { return new Vector2 ( @@ -75,7 +67,7 @@ private void RandomizeFloorTracks(TR1Level level, FDControl floorData) } } - private void RandomizeSecretTracks(TR1RCombinedLevel level, FDControl floorData) + private void RandomizeSecretTracks(TR1RCombinedLevel level) { List secretTracks = _audioRandomizer.GetTracks(TRAudioCategory.Secret); @@ -89,17 +81,17 @@ private void RandomizeSecretTracks(TR1RCombinedLevel level, FDControl floorData) FDActionItem musicAction = new() { - TrigAction = FDTrigAction.PlaySoundtrack, - Parameter = secretTrack.ID + Action = FDTrigAction.PlaySoundtrack, + Parameter = (short)secretTrack.ID }; - List triggers = FDUtilities.GetSecretTriggers(floorData, i); + List triggers = level.Data.FloorData.GetSecretTriggers(i); foreach (FDTriggerEntry trigger in triggers) { - FDActionItem currentMusicAction = trigger.TrigActionList.Find(a => a.TrigAction == FDTrigAction.PlaySoundtrack); + FDActionItem currentMusicAction = trigger.Actions.Find(a => a.Action == FDTrigAction.PlaySoundtrack); if (currentMusicAction == null) { - trigger.TrigActionList.Add(musicAction); + trigger.Actions.Add(musicAction); } } } diff --git a/TRRandomizerCore/Randomizers/TR1R/TR1RItemRandomizer.cs b/TRRandomizerCore/Randomizers/TR1R/TR1RItemRandomizer.cs index 058d40697..c9cf618bd 100644 --- a/TRRandomizerCore/Randomizers/TR1R/TR1RItemRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR1R/TR1RItemRandomizer.cs @@ -1,6 +1,4 @@ using Newtonsoft.Json; -using TRFDControl; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -100,15 +98,11 @@ private List GetItemLocationPool(TR1RCombinedLevel level, bool keyItem exclusions.AddRange(_excludedLocations[level.Name]); } - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - foreach (TR1Entity entity in level.Data.Entities) { if (!TR1TypeUtilities.CanSharePickupSpace(entity.TypeID)) { - exclusions.Add(entity.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level.Data, floorData))); + exclusions.Add(entity.GetFloorLocation(loc => level.Data.GetRoomSector(loc))); } } @@ -174,9 +168,6 @@ public void RandomizeItemLocations(TR1RCombinedLevel level) return; } - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - for (int i = 0; i < level.Data.Entities.Count; i++) { TR1Entity entity = level.Data.Entities[i]; @@ -225,10 +216,7 @@ public void EnforceOneLimit(TR1RCombinedLevel level) private void RandomizeKeyItems(TR1RCombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - - _picker.TriggerTestAction = location => LocationUtilities.HasAnyTrigger(location, level.Data, floorData); + _picker.TriggerTestAction = location => LocationUtilities.HasAnyTrigger(location, level.Data); _picker.RoomInfos = level.Data.Rooms .Select(r => new ExtRoomInfo(r.Info, r.NumXSectors, r.NumZSectors)) .ToList(); @@ -250,7 +238,7 @@ private void RandomizeKeyItems(TR1RCombinedLevel level) continue; } - bool hasPickupTrigger = LocationUtilities.HasPickupTriger(entity, i, level.Data, floorData); + bool hasPickupTrigger = LocationUtilities.HasPickupTriger(entity, i, level.Data); _picker.RandomizeKeyItemLocation(entity, hasPickupTrigger, level.Script.OriginalSequence, level.Data.Rooms[entity.Room].Info); } diff --git a/TRRandomizerCore/Randomizers/TR1R/TR1RStartPositionRandomizer.cs b/TRRandomizerCore/Randomizers/TR1R/TR1RStartPositionRandomizer.cs index 13872bc96..56353126b 100644 --- a/TRRandomizerCore/Randomizers/TR1R/TR1RStartPositionRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR1R/TR1RStartPositionRandomizer.cs @@ -1,5 +1,4 @@ using Newtonsoft.Json; -using TRFDControl; using TRGE.Core; using TRLevelControl; using TRLevelControl.Model; @@ -35,9 +34,6 @@ private void RandomizeStartPosition(TR1RCombinedLevel level) { TR1Entity lara = level.Data.Entities.Find(e => e.TypeID == TR1Type.Lara); - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - if (!Settings.RotateStartPositionOnly && _startLocations.ContainsKey(level.Name)) { List locations = _startLocations[level.Name]; @@ -46,12 +42,12 @@ private void RandomizeStartPosition(TR1RCombinedLevel level) { location = locations[_generator.Next(0, locations.Count)]; } - while (!location.Validated || location.ContainsSecret(level.Data, floorData)); + while (!location.Validated || location.ContainsSecret(level.Data)); lara.X = location.X; lara.Y = location.Y; lara.Z = location.Z; - lara.Room = (short)location.Room; + lara.Room = location.Room; } short currentAngle = lara.Angle; diff --git a/TRRandomizerCore/Randomizers/TR2/TR2AudioRandomizer.cs b/TRRandomizerCore/Randomizers/TR2/TR2AudioRandomizer.cs index a2008a792..4c1bd96b6 100644 --- a/TRRandomizerCore/Randomizers/TR2/TR2AudioRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR2/TR2AudioRandomizer.cs @@ -1,8 +1,5 @@ using Newtonsoft.Json; using System.Numerics; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl; using TRLevelControl.Helpers; @@ -66,28 +63,23 @@ public bool IsUncontrolledLevel(TR2ScriptedLevel level) private void RandomizeMusicTriggers(TR2CombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - if (Settings.ChangeTriggerTracks) { - RandomizeFloorTracks(level.Data, floorData); + RandomizeFloorTracks(level.Data); } if (Settings.SeparateSecretTracks) { - RandomizeSecretTracks(level.Data, floorData); + RandomizeSecretTracks(level.Data); } - - floorData.WriteToLevel(level.Data); } - private void RandomizeFloorTracks(TR2Level level, FDControl floorData) + private void RandomizeFloorTracks(TR2Level level) { _audioRandomizer.ResetFloorMap(); foreach (TR2Room room in level.Rooms) { - _audioRandomizer.RandomizeFloorTracks(room.Sectors, floorData, _generator, sectorIndex => + _audioRandomizer.RandomizeFloorTracks(room.Sectors, level.FloorData, _generator, sectorIndex => { // Get the midpoint of the tile in world coordinates return new Vector2 @@ -99,7 +91,7 @@ private void RandomizeFloorTracks(TR2Level level, FDControl floorData) } } - private void RandomizeSecretTracks(TR2Level level, FDControl floorData) + private void RandomizeSecretTracks(TR2Level level) { // Generate new triggers for secrets to allow different sounds for each one List secretTracks = _audioRandomizer.GetTracks(TRAudioCategory.Secret); @@ -107,19 +99,19 @@ private void RandomizeSecretTracks(TR2Level level, FDControl floorData) foreach (int entityIndex in secrets.Keys) { TR2Entity secret = secrets[entityIndex]; - TRRoomSector sector = FDUtilities.GetRoomSector(secret.X, secret.Y, secret.Z, secret.Room, level, floorData); + TRRoomSector sector = level.GetRoomSector(secret); if (sector.FDIndex == 0) { // The secret is positioned on a tile that currently has no FD, so create it - floorData.CreateFloorData(sector); + level.FloorData.CreateFloorData(sector); } - List entries = floorData.Entries[sector.FDIndex]; + List entries = level.FloorData[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) + if (existingTriggerEntry.TrigType == FDTrigType.Pickup && existingTriggerEntry.Actions[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 @@ -137,29 +129,24 @@ private void RandomizeSecretTracks(TR2Level level, FDControl floorData) // Generate a new music action FDActionItem musicAction = new() { - TrigAction = FDTrigAction.PlaySoundtrack, - Parameter = secretTracks[_generator.Next(0, secretTracks.Count)].ID + Action = FDTrigAction.PlaySoundtrack, + Parameter = (short)secretTracks[_generator.Next(0, secretTracks.Count)].ID }; // For GW default gold, just append it if (existingEntityPickup) { - existingTriggerEntry.TrigActionList.Add(musicAction); + existingTriggerEntry.Actions.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 + Actions = new List { - new() { - TrigAction = FDTrigAction.Object, - Parameter = (ushort)entityIndex + new() + { + Parameter = (short)entityIndex }, musicAction } diff --git a/TRRandomizerCore/Randomizers/TR2/TR2EnemyRandomizer.cs b/TRRandomizerCore/Randomizers/TR2/TR2EnemyRandomizer.cs index 3a4895752..f859ab2ff 100644 --- a/TRRandomizerCore/Randomizers/TR2/TR2EnemyRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR2/TR2EnemyRandomizer.cs @@ -1,6 +1,4 @@ using System.Diagnostics; -using TRFDControl; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -736,7 +734,7 @@ private void RandomizeEnemies(TR2CombinedLevel level, EnemyRandomizationCollecti Location randomLocation = VehicleUtilities.GetRandomLocation(level, TR2Type.RedSnowmobile, _generator); if (randomLocation != null) { - skidoo.Room = (short)randomLocation.Room; + skidoo.Room = randomLocation.Room; skidoo.X = randomLocation.X; skidoo.Y = randomLocation.Y; skidoo.Z = randomLocation.Z; @@ -760,7 +758,7 @@ private void RandomizeEnemies(TR2CombinedLevel level, EnemyRandomizationCollecti Location randomLocation = VehicleUtilities.GetRandomLocation(level, TR2Type.RedSnowmobile, _generator); if (randomLocation != null) { - skidoo.Room = (short)randomLocation.Room; + skidoo.Room = randomLocation.Room; skidoo.X = randomLocation.X; skidoo.Y = randomLocation.Y; skidoo.Z = randomLocation.Z; @@ -836,8 +834,6 @@ private void LimitSkidooEntities(TR2CombinedLevel level) return; } - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); List pickupLocations = level.Data.Entities .Where(e => TR2TypeUtilities.IsAnyPickupType(e.TypeID) && !TR2TypeUtilities.IsSecretType(e.TypeID)) .Select(e => e.GetLocation()) @@ -877,10 +873,8 @@ private void LimitSkidooEntities(TR2CombinedLevel level) } // Get rid of the old enemy's triggers - FDUtilities.RemoveEntityTriggers(level.Data, level.Data.Entities.IndexOf(skidMan), floorData); + level.Data.FloorData.RemoveEntityTriggers(level.Data.Entities.IndexOf(skidMan)); } - - floorData.WriteToLevel(level.Data); } private void LimitFriendlyEnemies(TR2CombinedLevel level, List pool, List friends) diff --git a/TRRandomizerCore/Randomizers/TR2/TR2ItemRandomizer.cs b/TRRandomizerCore/Randomizers/TR2/TR2ItemRandomizer.cs index 6731558d7..fb8f2289e 100644 --- a/TRRandomizerCore/Randomizers/TR2/TR2ItemRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR2/TR2ItemRandomizer.cs @@ -1,6 +1,4 @@ using Newtonsoft.Json; -using TRFDControl; -using TRFDControl.Utilities; using TRGE.Core; using TRGE.Core.Item.Enums; using TRLevelControl.Helpers; @@ -145,15 +143,11 @@ private List GetItemLocationPool(TR2CombinedLevel level, bool keyItemM exclusions.AddRange(_excludedLocations[level.Name]); } - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - foreach (TR2Entity entity in level.Data.Entities) { if (!TR2TypeUtilities.CanSharePickupSpace(entity.TypeID)) { - exclusions.Add(entity.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level.Data, floorData))); + exclusions.Add(entity.GetFloorLocation(loc => level.Data.GetRoomSector(loc))); } } @@ -211,10 +205,7 @@ public void RandomizeItemLocations(TR2CombinedLevel level) private void RandomizeKeyItems(TR2CombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - - _picker.TriggerTestAction = location => LocationUtilities.HasAnyTrigger(location, level.Data, floorData); + _picker.TriggerTestAction = location => LocationUtilities.HasAnyTrigger(location, level.Data); _picker.KeyItemTestAction = (location, hasPickupTrigger) => TestKeyItemLocation(location, hasPickupTrigger, level); _picker.RoomInfos = level.Data.Rooms .Select(r => new ExtRoomInfo(r.Info, r.NumXSectors, r.NumZSectors)) @@ -236,7 +227,7 @@ private void RandomizeKeyItems(TR2CombinedLevel level) } _picker.RandomizeKeyItemLocation( - entity, LocationUtilities.HasPickupTriger(entity, i, level.Data, floorData), + entity, LocationUtilities.HasPickupTriger(entity, i, level.Data), level.Script.OriginalSequence, level.Data.Rooms[entity.Room].Info); entity.Intensity1 = entity.Intensity2 = -1; } @@ -657,7 +648,7 @@ private void RandomizeVehicles() _levelInstance.Data.Entities.Add(new() { TypeID = entity, - Room = (short)location.Room, + Room = location.Room, X = location.X, Y = location.Y, Z = location.Z, @@ -676,7 +667,7 @@ private void RandomizeVehicles() { TR2Entity boat = boatToMove[i]; - boat.Room = (short)location.Room; + boat.Room = location.Room; boat.X = location.X; boat.Y = location.Y; boat.Z = location.Z; @@ -702,7 +693,7 @@ private void RandomizeVehicles() TR2Entity boat2 = boatToMove[i]; - boat2.Room = (short)location2ndBoat.Room; + boat2.Room = location2ndBoat.Room; boat2.X = location2ndBoat.X; boat2.Y = location2ndBoat.Y; boat2.Z = location2ndBoat.Z; diff --git a/TRRandomizerCore/Randomizers/TR2/TR2SecretRandomizer.cs b/TRRandomizerCore/Randomizers/TR2/TR2SecretRandomizer.cs index 3d7a689bb..c6ada6ba2 100644 --- a/TRRandomizerCore/Randomizers/TR2/TR2SecretRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR2/TR2SecretRandomizer.cs @@ -1,6 +1,4 @@ using Newtonsoft.Json; -using TRFDControl; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -93,8 +91,8 @@ private void PlaceAllSecrets(TR2CombinedLevel level) // Simulate zoning of sorts by splitting the route equally. This of course doesn't guarantee // what will be assigned in regular mode. - List routeRooms = _routePicker.GetRouteRooms(); - List> zones = routeRooms.Split(_levelSecretCount); + List routeRooms = _routePicker.GetRouteRooms(); + List> zones = routeRooms.Split(_levelSecretCount); List secretTypes = TR2TypeUtilities.GetSecretTypes(); foreach (Location location in _locations[level.Name]) @@ -118,14 +116,10 @@ private void PlaceAllSecrets(TR2CombinedLevel level) private void RandomizeSecrets(TR2CombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - List locations = _locations[level.Name]; locations.Shuffle(_generator); - _secretPicker.SectorAction = loc - => FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level.Data, floorData); + _secretPicker.SectorAction = loc => level.Data.GetRoomSector(loc); _routePicker.RoomInfos = level.Data.Rooms .Select(r => new ExtRoomInfo(r.Info, r.NumXSectors, r.NumZSectors)) .ToList(); diff --git a/TRRandomizerCore/Randomizers/TR2/TR2StartPositionRandomizer.cs b/TRRandomizerCore/Randomizers/TR2/TR2StartPositionRandomizer.cs index b15dd95bc..d284ad951 100644 --- a/TRRandomizerCore/Randomizers/TR2/TR2StartPositionRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR2/TR2StartPositionRandomizer.cs @@ -57,7 +57,7 @@ private void RandomizeStartPosition(TR2CombinedLevel level) { List locations = _startLocations[level.Name]; Location location = locations[_generator.Next(0, locations.Count)]; - lara.Room = (short)location.Room; + lara.Room = location.Room; lara.X = location.X; lara.Y = location.Y; lara.Z = location.Z; diff --git a/TRRandomizerCore/Randomizers/TR2R/TR2RAudioRandomizer.cs b/TRRandomizerCore/Randomizers/TR2R/TR2RAudioRandomizer.cs index 5b03789ec..7ab334749 100644 --- a/TRRandomizerCore/Randomizers/TR2R/TR2RAudioRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR2R/TR2RAudioRandomizer.cs @@ -1,8 +1,5 @@ using Newtonsoft.Json; using System.Numerics; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl; using TRLevelControl.Helpers; @@ -63,28 +60,23 @@ public bool IsUncontrolledLevel(TRRScriptedLevel level) private void RandomizeMusicTriggers(TR2RCombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - if (Settings.ChangeTriggerTracks) { - RandomizeFloorTracks(level.Data, floorData); + RandomizeFloorTracks(level.Data); } if (Settings.SeparateSecretTracks) { - RandomizeSecretTracks(level.Data, floorData); + RandomizeSecretTracks(level.Data); } - - floorData.WriteToLevel(level.Data); } - private void RandomizeFloorTracks(TR2Level level, FDControl floorData) + private void RandomizeFloorTracks(TR2Level level) { _audioRandomizer.ResetFloorMap(); foreach (TR2Room room in level.Rooms) { - _audioRandomizer.RandomizeFloorTracks(room.Sectors, floorData, _generator, sectorIndex => + _audioRandomizer.RandomizeFloorTracks(room.Sectors, level.FloorData, _generator, sectorIndex => { return new Vector2 ( @@ -95,25 +87,25 @@ private void RandomizeFloorTracks(TR2Level level, FDControl floorData) } } - private void RandomizeSecretTracks(TR2Level level, FDControl floorData) + private void RandomizeSecretTracks(TR2Level level) { List secretTracks = _audioRandomizer.GetTracks(TRAudioCategory.Secret); Dictionary 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); + TRRoomSector sector = level.GetRoomSector(secret); if (sector.FDIndex == 0) { - floorData.CreateFloorData(sector); + level.FloorData.CreateFloorData(sector); } - List entries = floorData.Entries[sector.FDIndex]; + List entries = level.FloorData[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) + if (existingTriggerEntry.TrigType == FDTrigType.Pickup && existingTriggerEntry.Actions[0].Parameter == entityIndex) { existingEntityPickup = true; } @@ -125,25 +117,23 @@ private void RandomizeSecretTracks(TR2Level level, FDControl floorData) FDActionItem musicAction = new() { - TrigAction = FDTrigAction.PlaySoundtrack, - Parameter = secretTracks[_generator.Next(0, secretTracks.Count)].ID + Action = FDTrigAction.PlaySoundtrack, + Parameter = (short)secretTracks[_generator.Next(0, secretTracks.Count)].ID }; if (existingEntityPickup) { - existingTriggerEntry.TrigActionList.Add(musicAction); + existingTriggerEntry.Actions.Add(musicAction); } else { entries.Add(new FDTriggerEntry { - Setup = new FDSetup { Value = 1028 }, - TrigSetup = new FDTrigSetup { Value = 15872 }, - TrigActionList = new List + Actions = new() { - new() { - TrigAction = FDTrigAction.Object, - Parameter = (ushort)entityIndex + new() + { + Parameter = (short)entityIndex }, musicAction } diff --git a/TRRandomizerCore/Randomizers/TR2R/TR2RItemRandomizer.cs b/TRRandomizerCore/Randomizers/TR2R/TR2RItemRandomizer.cs index 48e66ec16..cab3daa10 100644 --- a/TRRandomizerCore/Randomizers/TR2R/TR2RItemRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR2R/TR2RItemRandomizer.cs @@ -1,6 +1,4 @@ using Newtonsoft.Json; -using TRFDControl; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -97,15 +95,11 @@ private List GetItemLocationPool(TR2RCombinedLevel level, bool keyItem exclusions.AddRange(_excludedLocations[level.Name]); } - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - foreach (TR2Entity entity in level.Data.Entities) { if (!TR2TypeUtilities.CanSharePickupSpace(entity.TypeID)) { - exclusions.Add(entity.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level.Data, floorData))); + exclusions.Add(entity.GetFloorLocation(loc => level.Data.GetRoomSector(loc))); } } @@ -170,10 +164,7 @@ private void EnforceOneLimit(TR2RCombinedLevel level) private void RandomizeKeyItems(TR2RCombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - - _picker.TriggerTestAction = location => LocationUtilities.HasAnyTrigger(location, level.Data, floorData); + _picker.TriggerTestAction = location => LocationUtilities.HasAnyTrigger(location, level.Data); _picker.KeyItemTestAction = (location, hasPickupTrigger) => TestKeyItemLocation(location, hasPickupTrigger, level); _picker.RoomInfos = level.Data.Rooms .Select(r => new ExtRoomInfo(r.Info, r.NumXSectors, r.NumZSectors)) @@ -200,7 +191,7 @@ private void RandomizeKeyItems(TR2RCombinedLevel level) } _picker.RandomizeKeyItemLocation( - entity, LocationUtilities.HasPickupTriger(entity, i, level.Data, floorData), + entity, LocationUtilities.HasPickupTriger(entity, i, level.Data), level.Script.OriginalSequence, level.Data.Rooms[entity.Room].Info); entity.Intensity1 = entity.Intensity2 = -1; diff --git a/TRRandomizerCore/Randomizers/TR2R/TR2RStartPositionRandomizer.cs b/TRRandomizerCore/Randomizers/TR2R/TR2RStartPositionRandomizer.cs index ce60423db..c4c3db22f 100644 --- a/TRRandomizerCore/Randomizers/TR2R/TR2RStartPositionRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR2R/TR2RStartPositionRandomizer.cs @@ -49,7 +49,7 @@ private void RandomizeStartPosition(TR2RCombinedLevel level) { List locations = _startLocations[level.Name]; Location location = locations[_generator.Next(0, locations.Count)]; - lara.Room = (short)location.Room; + lara.Room = location.Room; lara.X = location.X; lara.Y = location.Y; lara.Z = location.Z; diff --git a/TRRandomizerCore/Randomizers/TR3/TR3AudioRandomizer.cs b/TRRandomizerCore/Randomizers/TR3/TR3AudioRandomizer.cs index 5d0635fac..1eee5106c 100644 --- a/TRRandomizerCore/Randomizers/TR3/TR3AudioRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR3/TR3AudioRandomizer.cs @@ -1,8 +1,5 @@ using Newtonsoft.Json; using System.Numerics; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl; using TRLevelControl.Helpers; @@ -69,28 +66,23 @@ public bool IsUncontrolledLevel(TR3ScriptedLevel level) private void RandomizeMusicTriggers(TR3CombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - if (Settings.ChangeTriggerTracks) { - RandomizeFloorTracks(level.Data, floorData); + RandomizeFloorTracks(level.Data); } // The secret sound is hardcoded in TR3 to track 122. The workaround for this is to // always set the secret sound on the corresponding triggers regardless of whether // or not secret rando is enabled. - RandomizeSecretTracks(level, floorData); - - floorData.WriteToLevel(level.Data); + RandomizeSecretTracks(level); } - private void RandomizeFloorTracks(TR3Level level, FDControl floorData) + private void RandomizeFloorTracks(TR3Level level) { _audioRandomizer.ResetFloorMap(); foreach (TR3Room room in level.Rooms) { - _audioRandomizer.RandomizeFloorTracks(room.Sectors, floorData, _generator, sectorIndex => + _audioRandomizer.RandomizeFloorTracks(room.Sectors, level.FloorData, _generator, sectorIndex => { // Get the midpoint of the tile in world coordinates return new Vector2 @@ -102,7 +94,7 @@ private void RandomizeFloorTracks(TR3Level level, FDControl floorData) } } - private void RandomizeSecretTracks(TR3CombinedLevel level, FDControl floorData) + private void RandomizeSecretTracks(TR3CombinedLevel level) { if (level.Script.NumSecrets == 0) { @@ -129,18 +121,18 @@ private void RandomizeSecretTracks(TR3CombinedLevel level, FDControl floorData) FDActionItem musicAction = new() { - TrigAction = FDTrigAction.PlaySoundtrack, - Parameter = secretTrack.ID + Action = FDTrigAction.PlaySoundtrack, + Parameter = (short)secretTrack.ID }; // Add a music action for each trigger defined for this secret. - List triggers = FDUtilities.GetSecretTriggers(floorData, i); + List triggers = level.Data.FloorData.GetSecretTriggers(i); foreach (FDTriggerEntry trigger in triggers) { - FDActionItem currentMusicAction = trigger.TrigActionList.Find(a => a.TrigAction == FDTrigAction.PlaySoundtrack); + FDActionItem currentMusicAction = trigger.Actions.Find(a => a.Action == FDTrigAction.PlaySoundtrack); if (currentMusicAction == null) { - trigger.TrigActionList.Add(musicAction); + trigger.Actions.Add(musicAction); } } } diff --git a/TRRandomizerCore/Randomizers/TR3/TR3ItemRandomizer.cs b/TRRandomizerCore/Randomizers/TR3/TR3ItemRandomizer.cs index 1f4d6c0ba..48456010c 100644 --- a/TRRandomizerCore/Randomizers/TR3/TR3ItemRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR3/TR3ItemRandomizer.cs @@ -1,6 +1,4 @@ using Newtonsoft.Json; -using TRFDControl; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -225,10 +223,6 @@ public void EnforceOneLimit(TR3CombinedLevel level) uniqueTypes.Add(_unarmedLevelPistols.TypeID); } - // FD for removing crystal triggers if applicable. - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - // Look for extra utility/ammo items and hide them for (int i = 0; i < level.Data.Entities.Count; i++) { @@ -246,12 +240,10 @@ public void EnforceOneLimit(TR3CombinedLevel level) ItemFactory.FreeItem(level.Name, i); if (TR3TypeUtilities.IsCrystalPickup(entity.TypeID)) { - FDUtilities.RemoveEntityTriggers(level.Data, i, floorData); + level.Data.FloorData.RemoveEntityTriggers(i); } } } - - floorData.WriteToLevel(level.Data); } public void RandomizeItemLocations(TR3CombinedLevel level) @@ -286,15 +278,11 @@ private List GetItemLocationPool(TR3CombinedLevel level, bool keyItemM exclusions.AddRange(_excludedLocations[level.Name]); } - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - foreach (TR3Entity entity in level.Data.Entities) { if (!TR3TypeUtilities.CanSharePickupSpace(entity.TypeID)) { - exclusions.Add(entity.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level.Data, floorData))); + exclusions.Add(entity.GetFloorLocation(loc => level.Data.GetRoomSector(loc))); } } @@ -311,7 +299,7 @@ private List GetItemLocationPool(TR3CombinedLevel level, bool keyItemM if (level.HasExposureMeter) { // Don't put items underwater if it's too cold - for (int i = 0; i < level.Data.Rooms.Count; i++) + for (short i = 0; i < level.Data.Rooms.Count; i++) { if (level.Data.Rooms[i].ContainsWater) { @@ -330,10 +318,7 @@ private List GetItemLocationPool(TR3CombinedLevel level, bool keyItemM public void RandomizeKeyItems(TR3CombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - - _picker.TriggerTestAction = location => LocationUtilities.HasAnyTrigger(location, level.Data, floorData); + _picker.TriggerTestAction = location => LocationUtilities.HasAnyTrigger(location, level.Data); _picker.KeyItemTestAction = (location, hasPickupTrigger) => TestKeyItemLocation(location, hasPickupTrigger, level); _picker.RoomInfos = level.Data.Rooms .Select(r => new ExtRoomInfo(r.Info, r.NumXSectors, r.NumZSectors)) @@ -351,7 +336,7 @@ public void RandomizeKeyItems(TR3CombinedLevel level) } _picker.RandomizeKeyItemLocation( - entity, LocationUtilities.HasPickupTriger(entity, i, level.Data, floorData), + entity, LocationUtilities.HasPickupTriger(entity, i, level.Data), level.Script.OriginalSequence, level.Data.Rooms[entity.Room].Info); } } diff --git a/TRRandomizerCore/Randomizers/TR3/TR3SecretRandomizer.cs b/TRRandomizerCore/Randomizers/TR3/TR3SecretRandomizer.cs index 193231f82..f758df4b4 100644 --- a/TRRandomizerCore/Randomizers/TR3/TR3SecretRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR3/TR3SecretRandomizer.cs @@ -1,8 +1,5 @@ using Newtonsoft.Json; using System.Diagnostics; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRGE.Core; using TRGE.Core.Item.Enums; using TRLevelControl; @@ -108,9 +105,6 @@ public override void Randomize(int seed) private static void RemoveDefaultSecrets(TR3CombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - // Scan all rooms and remove any existing secret triggers. foreach (TR3Room room in level.Data.Rooms) { @@ -121,29 +115,21 @@ private static void RemoveDefaultSecrets(TR3CombinedLevel level) continue; } - List entries = floorData.Entries[sector.FDIndex]; + List entries = level.Data.FloorData[sector.FDIndex]; for (int i = entries.Count - 1; i >= 0; i--) { if (entries[i] is FDTriggerEntry trig) { // #230 Remove the secret action but retain anything else that may be triggered here - trig.TrigActionList.RemoveAll(a => a.TrigAction == FDTrigAction.SecretFound); - if (trig.TrigActionList.Count == 0) + trig.Actions.RemoveAll(a => a.Action == FDTrigAction.SecretFound); + if (trig.Actions.Count == 0) { entries.RemoveAt(i); } } } - - if (entries.Count == 0) - { - // If there isn't anything left, reset the sector to point to the dummy FD - floorData.RemoveFloorData(sector); - } } } - - floorData.WriteToLevel(level.Data); } private TRSecretRoom MakePlaceholderRewardRoom(TR3CombinedLevel level) @@ -209,7 +195,7 @@ private void ActualiseRewardRoom(TR3CombinedLevel level, TRSecretRoom // If it's a trapdoor, we need to make a dummy trigger for it if (TR3TypeUtilities.IsTrapdoor(door.TypeID)) { - CreateTrapdoorTrigger(door, (ushort)doorIndex, level.Data); + CreateTrapdoorTrigger(door, (short)doorIndex, level.Data); } } @@ -238,74 +224,58 @@ private void ActualiseRewardRoom(TR3CombinedLevel level, TRSecretRoom level.Data.Cameras.Add(rewardRoom.Cameras[i % rewardRoom.Cameras.Count]); } - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - // Get each trigger created for each secret index and add the camera, provided // there isn't any existing camera actions. for (int i = 0; i < countedSecrets; i++) { - List secretTriggers = FDUtilities.GetSecretTriggers(floorData, i); + List secretTriggers = level.Data.FloorData.GetSecretTriggers(i); foreach (FDTriggerEntry trigger in secretTriggers) { - if (trigger.TrigActionList.Find(a => a.TrigAction == FDTrigAction.Camera) == null) + if (trigger.Actions.Find(a => a.Action == FDTrigAction.Camera) == null) { - trigger.TrigActionList.Add(new FDActionItem + trigger.Actions.Add(new FDActionItem { - TrigAction = FDTrigAction.Camera, - CamAction = new FDCameraAction { Value = 4 }, - Parameter = (ushort)rewardRoom.CameraIndices[i] + Action = FDTrigAction.Camera, + CamAction = new() + { + Timer = 4 + }, + Parameter = (short)rewardRoom.CameraIndices[i] }); - trigger.TrigActionList.Add(new FDActionItem + trigger.Actions.Add(new FDActionItem { - TrigAction = FDTrigAction.LookAtItem, - Parameter = (ushort)rewardRoom.DoorIndices[0] + Action = FDTrigAction.LookAtItem, + Parameter = (short)rewardRoom.DoorIndices[0] }); } } } - - // Write back the camera triggers - floorData.WriteToLevel(level.Data); } } - private static void CreateTrapdoorTrigger(TR3Entity door, ushort doorIndex, TR3Level level) + private static void CreateTrapdoorTrigger(TR3Entity door, short doorIndex, TR3Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - - TRRoomSector sector = FDUtilities.GetRoomSector(door.X, door.Y, door.Z, door.Room, level, floorData); + TRRoomSector sector = level.GetRoomSector(door); if (sector.FDIndex == 0) { - floorData.CreateFloorData(sector); + level.FloorData.CreateFloorData(sector); } - floorData.Entries[sector.FDIndex].Add(new FDTriggerEntry + level.FloorData[sector.FDIndex].Add(new FDTriggerEntry { - Setup = new FDSetup { Value = 4 }, - TrigSetup = new FDTrigSetup - { - Value = 15872 - }, TrigType = FDTrigType.Dummy, - TrigActionList = new List + Actions = new() { - new() { - TrigAction = FDTrigAction.Object, + new() + { Parameter = doorIndex } } }); - - floorData.WriteToLevel(level); } private void PlaceAllSecrets(TR3CombinedLevel level, List pickupTypes, TRSecretRoom rewardRoom) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - List locations = _locations[level.Name]; TRSecretPlacement secret = new(); @@ -321,19 +291,19 @@ private void PlaceAllSecrets(TR3CombinedLevel level, List pickupTypes, continue; secret.Location = location; - secret.EntityIndex = (ushort)ItemFactory.GetNextIndex(level.Name, level.Data.Entities, true); - secret.SecretIndex = (ushort)(secretIndex % countedSecrets); // Cycle through each secret number + secret.EntityIndex = (short)ItemFactory.GetNextIndex(level.Name, level.Data.Entities, true); + secret.SecretIndex = (short)(secretIndex % countedSecrets); // Cycle through each secret number secret.PickupType = pickupTypes[pickupIndex % pickupTypes.Count]; // Cycle through the types // #238 Point this secret to a specific camera and look-at target if applicable. if (Settings.UseRewardRoomCameras && rewardRoom.HasCameras) { - secret.CameraIndex = (ushort)rewardRoom.CameraIndices[pickupIndex % rewardRoom.CameraIndices.Count]; - secret.CameraTarget = (ushort)rewardRoom.DoorIndices[0]; + secret.CameraIndex = (short)rewardRoom.CameraIndices[pickupIndex % rewardRoom.CameraIndices.Count]; + secret.CameraTarget = (short)rewardRoom.DoorIndices[0]; } secret.SetMaskAndDoor(countedSecrets, rewardRoom.DoorIndices); - PlaceSecret(level, secret, floorData); + PlaceSecret(level, secret); // This will either make a new entity or repurpose an old one TR3Entity entity = ItemFactory.CreateLockedItem(level.Name, level.Data.Entities, secret.Location, true); @@ -343,23 +313,17 @@ private void PlaceAllSecrets(TR3CombinedLevel level, List pickupTypes, pickupIndex++; } - floorData.WriteToLevel(level.Data); - AddDamageControl(level, pickupTypes, locations); } private void RandomizeSecrets(TR3CombinedLevel level, List pickupTypes, TRSecretRoom rewardRoom) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - List locations = _locations[level.Name]; locations.Shuffle(_generator); - _secretPicker.SectorAction = loc - => FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level.Data, floorData); + _secretPicker.SectorAction = loc => level.Data.GetRoomSector(loc); _secretPicker.PlacementTestAction = loc - => TestSecretPlacement(level, loc, floorData); + => TestSecretPlacement(level, loc); _routePicker.RoomInfos = level.Data.Rooms .Select(r => new ExtRoomInfo(r.Info, r.NumXSectors, r.NumZSectors)) @@ -374,17 +338,17 @@ private void RandomizeSecrets(TR3CombinedLevel level, List pickupTypes, { Location location = pickedLocations[i]; secret.Location = location; - secret.EntityIndex = (ushort)ItemFactory.GetNextIndex(level.Name, level.Data.Entities); + secret.EntityIndex = (short)ItemFactory.GetNextIndex(level.Name, level.Data.Entities); secret.PickupType = pickupTypes[pickupIndex % pickupTypes.Count]; if (Settings.UseRewardRoomCameras && rewardRoom.HasCameras) { - secret.CameraIndex = (ushort)rewardRoom.CameraIndices[pickupIndex % rewardRoom.CameraIndices.Count]; - secret.CameraTarget = (ushort)rewardRoom.DoorIndices[0]; + secret.CameraIndex = (short)rewardRoom.CameraIndices[pickupIndex % rewardRoom.CameraIndices.Count]; + secret.CameraTarget = (short)rewardRoom.DoorIndices[0]; } secret.SetMaskAndDoor(level.Script.NumSecrets, rewardRoom.DoorIndices); - PlaceSecret(level, secret, floorData); + PlaceSecret(level, secret); // This will either make a new entity or repurpose an old one. Ensure it is locked // to prevent item rando from potentially treating it as a key item. @@ -395,8 +359,6 @@ private void RandomizeSecrets(TR3CombinedLevel level, List pickupTypes, pickupIndex++; } - floorData.WriteToLevel(level.Data); - AddDamageControl(level, pickupTypes, pickedLocations); _secretPicker.FinaliseSecretPool(pickedLocations, level.Name, itemIndex => GetDependentLockedItems(level, itemIndex)); } @@ -496,7 +458,7 @@ private static void SetPuzzleTypeName(TR3CombinedLevel level, TR3Type itemType, } } - private bool TestSecretPlacement(TR3CombinedLevel level, Location location, FDControl floorData) + private bool TestSecretPlacement(TR3CombinedLevel level, Location location) { // Check if this secret is being added to a flipped room, as that won't work for (int i = 0; i < level.Data.Rooms.Count; i++) @@ -517,13 +479,13 @@ private bool TestSecretPlacement(TR3CombinedLevel level, Location location, FDCo } // Get the sector and check if it is shared with a trapdoor or bridge, as these won't work either. - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, (short)location.Room, level.Data, floorData); + TRRoomSector sector = level.Data.GetRoomSector(location); foreach (TR3Entity otherEntity in level.Data.Entities) { TR3Type type = otherEntity.TypeID; if (location.Room == otherEntity.Room && (TR3TypeUtilities.IsTrapdoor(type) || TR3TypeUtilities.IsBridge(type))) { - TRRoomSector otherSector = FDUtilities.GetRoomSector(otherEntity.X, otherEntity.Y, otherEntity.Z, otherEntity.Room, level.Data, floorData); + TRRoomSector otherSector = level.Data.GetRoomSector(otherEntity); if (otherSector == sector) { if (Settings.DevelopmentMode) @@ -535,7 +497,7 @@ private bool TestSecretPlacement(TR3CombinedLevel level, Location location, FDCo } } - if (!TestTriggerPlacement(level, location, (short)location.Room, sector, floorData)) + if (!TestTriggerPlacement(level, location, (short)location.Room, sector)) { return false; } @@ -544,8 +506,8 @@ private bool TestSecretPlacement(TR3CombinedLevel level, Location location, FDCo short altRoom = level.Data.Rooms[location.Room].AlternateRoom; if (altRoom != -1) { - sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, altRoom, level.Data, floorData); - if (!TestTriggerPlacement(level, location, altRoom, sector, floorData)) + sector = level.Data.GetRoomSector(location.X, location.Y, location.Z, altRoom); + if (!TestTriggerPlacement(level, location, altRoom, sector)) { return false; } @@ -559,9 +521,9 @@ private bool TestSecretPlacement(TR3CombinedLevel level, Location location, FDCo return true; } - private bool TestTriggerPlacement(TR3CombinedLevel level, Location location, short room, TRRoomSector sector, FDControl floorData) + private bool TestTriggerPlacement(TR3CombinedLevel level, Location location, short room, TRRoomSector sector) { - if (!location.Validated && LocationUtilities.HasAnyTrigger(sector, floorData)) + if (!location.Validated && LocationUtilities.HasAnyTrigger(sector, level.Data.FloorData)) { // There is already a trigger here and the location hasn't been marked as being // safe to move the action items to the new pickup trigger. @@ -575,24 +537,24 @@ private bool TestTriggerPlacement(TR3CombinedLevel level, Location location, sho } - private void PlaceSecret(TR3CombinedLevel level, TRSecretPlacement secret, FDControl floorData) + private void PlaceSecret(TR3CombinedLevel level, TRSecretPlacement secret) { // This assumes TestTriggerPlacement has already been called and passed. - TRRoomSector sector = FDUtilities.GetRoomSector(secret.Location.X, secret.Location.Y, secret.Location.Z, (short)secret.Location.Room, level.Data, floorData); - CreateSecretTriggers(level, secret, (short)secret.Location.Room, floorData, sector); + TRRoomSector sector = level.Data.GetRoomSector(secret.Location); + CreateSecretTriggers(level, secret, secret.Location.Room, sector); short altRoom = level.Data.Rooms[secret.Location.Room].AlternateRoom; if (altRoom != -1) { - sector = FDUtilities.GetRoomSector(secret.Location.X, secret.Location.Y, secret.Location.Z, altRoom, level.Data, floorData); - CreateSecretTriggers(level, secret, altRoom, floorData, sector); + sector = level.Data.GetRoomSector(secret.Location.X, secret.Location.Y, secret.Location.Z, altRoom); + CreateSecretTriggers(level, secret, altRoom, sector); } } - private void CreateSecretTriggers(TR3CombinedLevel level, TRSecretPlacement secret, short room, FDControl floorData, TRRoomSector baseSector) + private void CreateSecretTriggers(TR3CombinedLevel level, TRSecretPlacement secret, short room, TRRoomSector baseSector) { // Try to make the primary trigger - CreateSecretTrigger(level, secret, room, floorData, baseSector); + CreateSecretTrigger(level, secret, room, baseSector); // Check neighbouring sectors if we are very close to tile edges. We scan 8 locations around // the secret's position based on the edge tolerance and see if the sector has changed. @@ -605,16 +567,16 @@ private void CreateSecretTriggers(TR3CombinedLevel level, TRSecretPlacement secret, short room, FDControl floorData, TRRoomSector sector) + private void CreateSecretTrigger(TR3CombinedLevel level, TRSecretPlacement secret, short room, TRRoomSector sector) { if (sector.FDIndex == 0) { - floorData.CreateFloorData(sector); + level.Data.FloorData.CreateFloorData(sector); } // Make a new pickup trigger FDTriggerEntry trigger = new() { - Setup = new() { Value = 4 }, - TrigSetup = new() - { - Value = 15872, - Mask = secret.TriggerMask - }, + Mask = secret.TriggerMask, TrigType = FDTrigType.Pickup, - TrigActionList = new() + Actions = new() { new() { - TrigAction = FDTrigAction.Object, Parameter = secret.EntityIndex }, new() { - TrigAction = FDTrigAction.SecretFound, + Action = FDTrigAction.SecretFound, Parameter = secret.SecretIndex } } @@ -669,21 +625,20 @@ private void CreateSecretTrigger(TR3CombinedLevel level, TRSecretPlacement e is FDTriggerEntry) is FDTriggerEntry existingTrigger) + if (level.Data.FloorData[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry existingTrigger) { List existingActions = new(); - foreach (FDActionItem actionItem in existingTrigger.TrigActionList) + foreach (FDActionItem actionItem in existingTrigger.Actions) { - if (actionItem.TrigAction == FDTrigAction.Object) + if (actionItem.Action == FDTrigAction.Object) { if (Settings.DevelopmentMode) { @@ -701,11 +656,11 @@ private void CreateSecretTrigger(TR3CombinedLevel level, TRSecretPlacement diff --git a/TRRandomizerCore/Randomizers/TR3/TR3StartPositionRandomizer.cs b/TRRandomizerCore/Randomizers/TR3/TR3StartPositionRandomizer.cs index 0ecf4d18d..03c0cd69e 100644 --- a/TRRandomizerCore/Randomizers/TR3/TR3StartPositionRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR3/TR3StartPositionRandomizer.cs @@ -61,14 +61,14 @@ private void RandomizeStartPosition(TR3CombinedLevel level) X = location.X, Y = location.Y, Z = location.Z, - Room = (short)location.Room + Room = location.Room } }.ApplyToLevel(level.Data); lara.X = location.X; lara.Y = location.Y; lara.Z = location.Z; - lara.Room = (short)location.Room; + lara.Room = location.Room; } short currentAngle = lara.Angle; diff --git a/TRRandomizerCore/Randomizers/TR3R/TR3RAudioRandomizer.cs b/TRRandomizerCore/Randomizers/TR3R/TR3RAudioRandomizer.cs index 971712a4c..6e3b8ce34 100644 --- a/TRRandomizerCore/Randomizers/TR3R/TR3RAudioRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR3R/TR3RAudioRandomizer.cs @@ -1,8 +1,5 @@ using Newtonsoft.Json; using System.Numerics; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl; using TRLevelControl.Helpers; @@ -65,28 +62,23 @@ public bool IsUncontrolledLevel(TRRScriptedLevel level) private void RandomizeMusicTriggers(TR3RCombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - if (Settings.ChangeTriggerTracks) { - RandomizeFloorTracks(level.Data, floorData); + RandomizeFloorTracks(level.Data); } if (Settings.SeparateSecretTracks) { - RandomizeSecretTracks(level, floorData); + RandomizeSecretTracks(level); } - - floorData.WriteToLevel(level.Data); } - private void RandomizeFloorTracks(TR3Level level, FDControl floorData) + private void RandomizeFloorTracks(TR3Level level) { _audioRandomizer.ResetFloorMap(); foreach (TR3Room room in level.Rooms) { - _audioRandomizer.RandomizeFloorTracks(room.Sectors, floorData, _generator, sectorIndex => + _audioRandomizer.RandomizeFloorTracks(room.Sectors, level.FloorData, _generator, sectorIndex => { return new Vector2 ( @@ -97,7 +89,7 @@ private void RandomizeFloorTracks(TR3Level level, FDControl floorData) } } - private void RandomizeSecretTracks(TR3RCombinedLevel level, FDControl floorData) + private void RandomizeSecretTracks(TR3RCombinedLevel level) { List secretTracks = _audioRandomizer.GetTracks(TRAudioCategory.Secret); @@ -111,17 +103,17 @@ private void RandomizeSecretTracks(TR3RCombinedLevel level, FDControl floorData) FDActionItem musicAction = new() { - TrigAction = FDTrigAction.PlaySoundtrack, - Parameter = secretTrack.ID + Action = FDTrigAction.PlaySoundtrack, + Parameter = (short)secretTrack.ID }; - List triggers = FDUtilities.GetSecretTriggers(floorData, i); + List triggers = level.Data.FloorData.GetSecretTriggers(i); foreach (FDTriggerEntry trigger in triggers) { - FDActionItem currentMusicAction = trigger.TrigActionList.Find(a => a.TrigAction == FDTrigAction.PlaySoundtrack); + FDActionItem currentMusicAction = trigger.Actions.Find(a => a.Action == FDTrigAction.PlaySoundtrack); if (currentMusicAction == null) { - trigger.TrigActionList.Add(musicAction); + trigger.Actions.Add(musicAction); } } } diff --git a/TRRandomizerCore/Randomizers/TR3R/TR3RItemRandomizer.cs b/TRRandomizerCore/Randomizers/TR3R/TR3RItemRandomizer.cs index 13c96dfef..946132531 100644 --- a/TRRandomizerCore/Randomizers/TR3R/TR3RItemRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR3R/TR3RItemRandomizer.cs @@ -1,6 +1,4 @@ using Newtonsoft.Json; -using TRFDControl; -using TRFDControl.Utilities; using TRGE.Core; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -100,22 +98,18 @@ private List GetItemLocationPool(TR3RCombinedLevel level, bool keyItem exclusions.AddRange(_excludedLocations[level.Name]); } - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - foreach (TR3Entity entity in level.Data.Entities) { if (!TR3TypeUtilities.CanSharePickupSpace(entity.TypeID)) { - exclusions.Add(entity.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level.Data, floorData))); + exclusions.Add(entity.GetFloorLocation(loc => level.Data.GetRoomSector(loc))); } } if (level.Script.HasColdWater) { // Don't put items underwater if it's too cold - for (int i = 0; i < level.Data.Rooms.Count; i++) + for (short i = 0; i < level.Data.Rooms.Count; i++) { if (level.Data.Rooms[i].ContainsWater) { @@ -190,9 +184,6 @@ public void RandomizeItemLocations(TR3RCombinedLevel level) return; } - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - for (int i = 0; i < level.Data.Entities.Count; i++) { TR3Entity entity = level.Data.Entities[i]; @@ -240,10 +231,7 @@ public void EnforceOneLimit(TR3RCombinedLevel level) private void RandomizeKeyItems(TR3RCombinedLevel level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - - _picker.TriggerTestAction = location => LocationUtilities.HasAnyTrigger(location, level.Data, floorData); + _picker.TriggerTestAction = location => LocationUtilities.HasAnyTrigger(location, level.Data); _picker.KeyItemTestAction = (location, hasPickupTrigger) => TestKeyItemLocation(location, hasPickupTrigger, level); _picker.RoomInfos = level.Data.Rooms .Select(r => new ExtRoomInfo(r.Info, r.NumXSectors, r.NumZSectors)) @@ -261,7 +249,7 @@ private void RandomizeKeyItems(TR3RCombinedLevel level) } _picker.RandomizeKeyItemLocation( - entity, LocationUtilities.HasPickupTriger(entity, i, level.Data, floorData), + entity, LocationUtilities.HasPickupTriger(entity, i, level.Data), level.Script.OriginalSequence, level.Data.Rooms[entity.Room].Info); } } diff --git a/TRRandomizerCore/Randomizers/TR3R/TR3RStartPositionRandomizer.cs b/TRRandomizerCore/Randomizers/TR3R/TR3RStartPositionRandomizer.cs index 08a6de4bd..f17b1df62 100644 --- a/TRRandomizerCore/Randomizers/TR3R/TR3RStartPositionRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR3R/TR3RStartPositionRandomizer.cs @@ -58,14 +58,14 @@ private void RandomizeStartPosition(TR3RCombinedLevel level) X = location.X, Y = location.Y, Z = location.Z, - Room = (short)location.Room + Room = location.Room } }.ApplyToLevel(level.Data); lara.X = location.X; lara.Y = location.Y; lara.Z = location.Z; - lara.Room = (short)location.Room; + lara.Room = location.Room; } short currentAngle = lara.Angle; diff --git a/TRRandomizerCore/Secrets/TRSecretPlacement.cs b/TRRandomizerCore/Secrets/TRSecretPlacement.cs index 8d6c576d1..9546a7375 100644 --- a/TRRandomizerCore/Secrets/TRSecretPlacement.cs +++ b/TRRandomizerCore/Secrets/TRSecretPlacement.cs @@ -7,21 +7,21 @@ public class TRSecretPlacement where E : Enum { public Location Location { get; set; } public E PickupType { get; set; } - public ushort EntityIndex { get; set; } - public ushort SecretIndex { get; set; } - public ushort DoorIndex { get; set; } - public ushort CameraIndex { get; set; } - public ushort CameraTarget { get; set; } + public short EntityIndex { get; set; } + public short SecretIndex { get; set; } + public short DoorIndex { get; set; } + public short CameraIndex { get; set; } + public short CameraTarget { get; set; } public byte TriggerMask { get; set; } - public bool TriggersDoor => DoorIndex != ushort.MaxValue; - public bool TriggersCamera => CameraIndex != ushort.MaxValue; + public bool TriggersDoor => DoorIndex != short.MaxValue; + public bool TriggersCamera => CameraIndex != short.MaxValue; public TRSecretPlacement() { // Default to standard mask and no door TriggerMask = TRConsts.FullMask; - DoorIndex = ushort.MaxValue; - CameraIndex = ushort.MaxValue; + DoorIndex = short.MaxValue; + CameraIndex = short.MaxValue; } public void SetMaskAndDoor(int secretCount, List doorItems) @@ -55,6 +55,6 @@ public void SetMaskAndDoor(int secretCount, List doorItems) } TriggerMask = (byte)mask; - DoorIndex = (ushort)doorItems[SecretIndex / split]; + DoorIndex = (short)doorItems[SecretIndex / split]; } } diff --git a/TRRandomizerCore/Textures/DynamicTextureBuilder.cs b/TRRandomizerCore/Textures/DynamicTextureBuilder.cs index a776d23fb..2d92c91ff 100644 --- a/TRRandomizerCore/Textures/DynamicTextureBuilder.cs +++ b/TRRandomizerCore/Textures/DynamicTextureBuilder.cs @@ -1,6 +1,4 @@ using System.Drawing; -using TRFDControl; -using TRFDControl.Utilities; using TRLevelControl.Helpers; using TRLevelControl.Model; using TRModelTransporter.Helpers; @@ -167,9 +165,6 @@ public DynamicTextureTarget Build(TR1CombinedLevel level) } // Key items and secrets - FDControl floorData = new(); - floorData.ParseFromLevel(level.Data); - Dictionary keyItems = TR1TypeUtilities.GetKeyItemMap(); foreach (TR1Type pickupType in keyItems.Keys) { @@ -183,8 +178,8 @@ public DynamicTextureTarget Build(TR1CombinedLevel level) TR1Entity keyInstance = level.Data.Entities.Find(e => e.TypeID == pickupType); if (keyInstance != null) { - TRRoomSector sector = FDUtilities.GetRoomSector(keyInstance.X, keyInstance.Y, keyInstance.Z, keyInstance.Room, level.Data, floorData); - if (LocationUtilities.SectorContainsSecret(sector, floorData)) + TRRoomSector sector = level.Data.GetRoomSector(keyInstance); + if (LocationUtilities.SectorContainsSecret(sector, level.Data.FloorData)) { AddModelTextures(level.Data, pickupType, model, hips, secretObjectTextures, modelMeshes); AddSpriteTextures(level.Data, pickupType, secretSpriteTextures); diff --git a/TRRandomizerCore/Textures/Landmarks/AbstractLandmarkImporter.cs b/TRRandomizerCore/Textures/Landmarks/AbstractLandmarkImporter.cs index 55d3ce26c..40e1d1127 100644 --- a/TRRandomizerCore/Textures/Landmarks/AbstractLandmarkImporter.cs +++ b/TRRandomizerCore/Textures/Landmarks/AbstractLandmarkImporter.cs @@ -1,7 +1,5 @@ using RectanglePacker.Events; using System.Drawing; -using TRFDControl; -using TRFDControl.FDEntryTypes; using TRLevelControl; using TRLevelControl.Model; using TRModelTransporter.Model.Textures; @@ -230,9 +228,9 @@ private static TRObjectTextureVert CreatePoint(int x, int y) return sector.RoomBelow; } else if (sector.FDIndex != 0 - && floorData.Entries[sector.FDIndex].Find(e => e is FDPortalEntry) is FDPortalEntry portal) + && floorData[sector.FDIndex].Find(e => e is FDPortalEntry) is FDPortalEntry portal) { - return (short)portal.Room; + return portal.Room; } return null; diff --git a/TRRandomizerCore/Textures/Landmarks/TR1LandmarkImporter.cs b/TRRandomizerCore/Textures/Landmarks/TR1LandmarkImporter.cs index ba28eb51c..7fbadb819 100644 --- a/TRRandomizerCore/Textures/Landmarks/TR1LandmarkImporter.cs +++ b/TRRandomizerCore/Textures/Landmarks/TR1LandmarkImporter.cs @@ -1,5 +1,4 @@ -using TRFDControl; -using TRLevelControl.Model; +using TRLevelControl.Model; using TRModelTransporter.Packing; using TRTexture16Importer.Textures; @@ -26,13 +25,10 @@ protected override void SetRoomTexture(TR1Level level, int roomIndex, int rectan protected override short? GetRoomFromPortal(TR1Level level, PortalSector portalSector, bool isLevelMirrored) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - TR1Room room = level.Rooms[portalSector.Room]; int x = isLevelMirrored ? (room.NumXSectors - portalSector.X - 1) : portalSector.X; TRRoomSector sector = room.Sectors[x * room.NumZSectors + portalSector.Z]; - return GetSectorPortalRoom(sector, floorData, portalSector.Direction); + return GetSectorPortalRoom(sector, level.FloorData, portalSector.Direction); } } diff --git a/TRRandomizerCore/Textures/Landmarks/TR2LandmarkImporter.cs b/TRRandomizerCore/Textures/Landmarks/TR2LandmarkImporter.cs index b7d4928bf..180ee3d03 100644 --- a/TRRandomizerCore/Textures/Landmarks/TR2LandmarkImporter.cs +++ b/TRRandomizerCore/Textures/Landmarks/TR2LandmarkImporter.cs @@ -1,5 +1,4 @@ -using TRFDControl; -using TRLevelControl.Model; +using TRLevelControl.Model; using TRModelTransporter.Packing; using TRTexture16Importer.Textures; @@ -26,13 +25,10 @@ protected override void SetRoomTexture(TR2Level level, int roomIndex, int rectan protected override short? GetRoomFromPortal(TR2Level level, PortalSector portalSector, bool isLevelMirrored) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - TR2Room room = level.Rooms[portalSector.Room]; int x = isLevelMirrored ? (room.NumXSectors - portalSector.X - 1) : portalSector.X; TRRoomSector sector = room.Sectors[x * room.NumZSectors + portalSector.Z]; - return GetSectorPortalRoom(sector, floorData, portalSector.Direction); + return GetSectorPortalRoom(sector, level.FloorData, portalSector.Direction); } } diff --git a/TRRandomizerCore/Textures/Landmarks/TR3LandmarkImporter.cs b/TRRandomizerCore/Textures/Landmarks/TR3LandmarkImporter.cs index 4339670b2..57f3ee3e3 100644 --- a/TRRandomizerCore/Textures/Landmarks/TR3LandmarkImporter.cs +++ b/TRRandomizerCore/Textures/Landmarks/TR3LandmarkImporter.cs @@ -1,5 +1,4 @@ -using TRFDControl; -using TRLevelControl.Model; +using TRLevelControl.Model; using TRModelTransporter.Packing; using TRTexture16Importer.Textures; @@ -26,13 +25,10 @@ protected override void SetRoomTexture(TR3Level level, int roomIndex, int rectan protected override short? GetRoomFromPortal(TR3Level level, PortalSector portalSector, bool isLevelMirrored) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - TR3Room room = level.Rooms[portalSector.Room]; int x = isLevelMirrored ? (room.NumXSectors - portalSector.X - 1) : portalSector.X; TRRoomSector sector = room.Sectors[x * room.NumZSectors + portalSector.Z]; - return GetSectorPortalRoom(sector, floorData, portalSector.Direction); + return GetSectorPortalRoom(sector, level.FloorData, portalSector.Direction); } } diff --git a/TRRandomizerCore/Textures/Wireframing/AbstractTRWireframer.cs b/TRRandomizerCore/Textures/Wireframing/AbstractTRWireframer.cs index c60446691..9bea7c714 100644 --- a/TRRandomizerCore/Textures/Wireframing/AbstractTRWireframer.cs +++ b/TRRandomizerCore/Textures/Wireframing/AbstractTRWireframer.cs @@ -1,7 +1,6 @@ using RectanglePacker.Organisation; using System.Drawing; using System.Drawing.Drawing2D; -using TRFDControl; using TRLevelControl.Model; using TRModelTransporter.Helpers; using TRModelTransporter.Model.Textures; diff --git a/TRRandomizerCore/Textures/Wireframing/TR1Wireframer.cs b/TRRandomizerCore/Textures/Wireframing/TR1Wireframer.cs index 682bda114..1039a299b 100644 --- a/TRRandomizerCore/Textures/Wireframing/TR1Wireframer.cs +++ b/TRRandomizerCore/Textures/Wireframing/TR1Wireframer.cs @@ -1,6 +1,5 @@ using System.Drawing; using System.Drawing.Drawing2D; -using TRFDControl; using TRLevelControl.Helpers; using TRLevelControl.Model; using TRModelTransporter.Helpers; diff --git a/TRRandomizerCore/Textures/Wireframing/TR2Wireframer.cs b/TRRandomizerCore/Textures/Wireframing/TR2Wireframer.cs index 3502b529d..331afc75b 100644 --- a/TRRandomizerCore/Textures/Wireframing/TR2Wireframer.cs +++ b/TRRandomizerCore/Textures/Wireframing/TR2Wireframer.cs @@ -1,5 +1,4 @@ using System.Drawing; -using TRFDControl; using TRLevelControl.Helpers; using TRLevelControl.Model; using TRModelTransporter.Helpers; diff --git a/TRRandomizerCore/Textures/Wireframing/TR3Wireframer.cs b/TRRandomizerCore/Textures/Wireframing/TR3Wireframer.cs index 1ba884ce7..08ad9b1b3 100644 --- a/TRRandomizerCore/Textures/Wireframing/TR3Wireframer.cs +++ b/TRRandomizerCore/Textures/Wireframing/TR3Wireframer.cs @@ -1,6 +1,5 @@ using System.Drawing; using System.Drawing.Drawing2D; -using TRFDControl; using TRLevelControl.Helpers; using TRLevelControl.Model; using TRModelTransporter.Helpers; diff --git a/TRRandomizerCore/Utilities/FaceUtilities.cs b/TRRandomizerCore/Utilities/FaceUtilities.cs index 6ff481ce1..8f31ddbea 100644 --- a/TRRandomizerCore/Utilities/FaceUtilities.cs +++ b/TRRandomizerCore/Utilities/FaceUtilities.cs @@ -1,7 +1,4 @@ -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; -using TRLevelControl; +using TRLevelControl; using TRLevelControl.Model; namespace TRRandomizerCore.Utilities; @@ -10,13 +7,10 @@ public static class FaceUtilities { public static List GetTriggerFaces(TR1Level level, List triggerTypes, bool includeDeathTiles) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - List faces = new(); foreach (TR1Room room in level.Rooms) { - faces.AddRange(ScanTriggerFaces(floorData, triggerTypes, includeDeathTiles, room.Sectors, room.NumZSectors, room.Mesh.Rectangles, v => + faces.AddRange(ScanTriggerFaces(level.FloorData, triggerTypes, includeDeathTiles, room.Sectors, room.NumZSectors, room.Mesh.Rectangles, v => { return room.Mesh.Vertices[v].Vertex; })); @@ -27,13 +21,10 @@ public static List GetTriggerFaces(TR1Level level, List trig public static List GetTriggerFaces(TR2Level level, List triggerTypes, bool includeDeathTiles) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - List faces = new(); foreach (TR2Room room in level.Rooms) { - faces.AddRange(ScanTriggerFaces(floorData, triggerTypes, includeDeathTiles, room.Sectors, room.NumZSectors, room.Mesh.Rectangles, v => + faces.AddRange(ScanTriggerFaces(level.FloorData, triggerTypes, includeDeathTiles, room.Sectors, room.NumZSectors, room.Mesh.Rectangles, v => { return room.Mesh.Vertices[v].Vertex; })); @@ -44,13 +35,10 @@ public static List GetTriggerFaces(TR2Level level, List trig public static List GetTriggerFaces(TR3Level level, List triggerTypes, bool includeDeathTiles) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - List faces = new(); foreach (TR3Room room in level.Rooms) { - faces.AddRange(ScanTriggerFaces(floorData, triggerTypes, includeDeathTiles, room.Sectors, room.NumZSectors, room.Mesh.Rectangles, v => + faces.AddRange(ScanTriggerFaces(level.FloorData, triggerTypes, includeDeathTiles, room.Sectors, room.NumZSectors, room.Mesh.Rectangles, v => { return room.Mesh.Vertices[v].Vertex; })); @@ -61,15 +49,12 @@ public static List GetTriggerFaces(TR3Level level, List trig public static Dictionary> GetClimbableFaces(TR2Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - Dictionary> faces = new(); foreach (TR2Room room in level.Rooms) { foreach (TRRoomSector sector in room.Sectors) { - ScanTR2SectorLadderFaces(faces, level, floorData, room, sector); + ScanTR2SectorLadderFaces(faces, level, room, sector); } } @@ -78,16 +63,13 @@ public static Dictionary> GetClimbableFaces(TR2Level leve public static Dictionary> GetClimbableFaces(TR3Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - Dictionary> faces = new(); foreach (TR3Room room in level.Rooms) { foreach (TRRoomSector sector in room.Sectors) { - ScanTR3SectorLadderFaces(faces, level, floorData, room, sector); - ScanTR3SectorMonkeyFaces(faces, level, floorData, room, sector); + ScanTR3SectorLadderFaces(faces, level, room, sector); + ScanTR3SectorMonkeyFaces(faces, level, room, sector); } } @@ -106,7 +88,7 @@ private static List ScanTriggerFaces continue; } - List entries = floorData.Entries[sector.FDIndex]; + List entries = floorData[sector.FDIndex]; if ((entries.Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger && triggerMatches.Contains(trigger.TrigType)) || (includeDeathTiles && entries.Any(e => e is FDKillLaraEntry))) { @@ -135,14 +117,14 @@ private static List ScanTriggerFaces return faces; } - private static void ScanTR2SectorLadderFaces(Dictionary> faces, TR2Level level, FDControl floorData, TR2Room room, TRRoomSector sector, FDEntry entry = null) + private static void ScanTR2SectorLadderFaces(Dictionary> faces, TR2Level level, TR2Room room, TRRoomSector sector, FDEntry entry = null) { if (entry == null && sector.FDIndex == 0) { return; } - entry ??= floorData.Entries[sector.FDIndex].Find(e => e is FDClimbEntry); + entry ??= level.FloorData[sector.FDIndex].Find(e => e is FDClimbEntry); if (entry is FDClimbEntry climbEntry) { @@ -177,23 +159,23 @@ private static void ScanTR2SectorLadderFaces(Dictionary> int wx = room.Info.X + x; int wz = room.Info.Z + z; int wy = (sector.Ceiling - 1) * TRConsts.Step1; - TRRoomSector sectorAbove = FDUtilities.GetRoomSector(wx, wy, wz, sector.RoomAbove, level, floorData); + TRRoomSector sectorAbove = level.GetRoomSector(wx, wy, wz, sector.RoomAbove); if (sector != sectorAbove) { - ScanTR2SectorLadderFaces(faces, level, floorData, roomAbove, sectorAbove, entry); + ScanTR2SectorLadderFaces(faces, level, roomAbove, sectorAbove, entry); } } } } - private static void ScanTR3SectorLadderFaces(Dictionary> faces, TR3Level level, FDControl floorData, TR3Room room, TRRoomSector sector, FDEntry entry = null) + private static void ScanTR3SectorLadderFaces(Dictionary> faces, TR3Level level, TR3Room room, TRRoomSector sector, FDEntry entry = null) { if (entry == null && sector.FDIndex == 0) { return; } - entry ??= floorData.Entries[sector.FDIndex].Find(e => e is FDClimbEntry); + entry ??= level.FloorData[sector.FDIndex].Find(e => e is FDClimbEntry); if (entry is FDClimbEntry climbEntry) { @@ -228,23 +210,23 @@ private static void ScanTR3SectorLadderFaces(Dictionary> int wx = room.Info.X + x; int wz = room.Info.Z + z; int wy = (sector.Ceiling - 1) * TRConsts.Step1; - TRRoomSector sectorAbove = FDUtilities.GetRoomSector(wx, wy, wz, sector.RoomAbove, level, floorData); + TRRoomSector sectorAbove = level.GetRoomSector(wx, wy, wz, sector.RoomAbove); if (sector != sectorAbove) { - ScanTR3SectorLadderFaces(faces, level, floorData, roomAbove, sectorAbove, entry); + ScanTR3SectorLadderFaces(faces, level, roomAbove, sectorAbove, entry); } } } } - private static void ScanTR3SectorMonkeyFaces(Dictionary> faces, TR3Level level, FDControl floorData, TR3Room room, TRRoomSector sector, FDEntry entry = null) + private static void ScanTR3SectorMonkeyFaces(Dictionary> faces, TR3Level level, TR3Room room, TRRoomSector sector, FDEntry entry = null) { if (entry == null && sector.FDIndex == 0) { return; } - entry ??= floorData.Entries[sector.FDIndex].Find(e => e is FDMonkeySwingEntry); + entry ??= level.FloorData[sector.FDIndex].Find(e => e is FDMonkeySwingEntry); if (entry is FDMonkeySwingEntry monkeyEntry) { @@ -280,10 +262,10 @@ private static void ScanTR3SectorMonkeyFaces(Dictionary> int wx = room.Info.X + x; int wz = room.Info.Z + z; int wy = (sector.Ceiling - 1) * TRConsts.Step1; - TRRoomSector sectorAbove = FDUtilities.GetRoomSector(wx, wy, wz, sector.RoomAbove, level, floorData); + TRRoomSector sectorAbove = level.GetRoomSector(wx, wy, wz, sector.RoomAbove); if (sector != sectorAbove) { - ScanTR3SectorMonkeyFaces(faces, level, floorData, roomAbove, sectorAbove, entry); + ScanTR3SectorMonkeyFaces(faces, level, roomAbove, sectorAbove, entry); } } } @@ -294,12 +276,12 @@ private static List GetVerticesToMatch(FDClimbEntry climbEntry, short List vertMatches = new(); if (climbEntry.IsNegativeX) { - vertMatches.Add(new TRVertex + vertMatches.Add(new() { X = x, Z = z }); - vertMatches.Add(new TRVertex + vertMatches.Add(new() { X = x, Z = (short)(z + TRConsts.Step4) @@ -307,12 +289,12 @@ private static List GetVerticesToMatch(FDClimbEntry climbEntry, short } if (climbEntry.IsPositiveX) { - vertMatches.Add(new TRVertex + vertMatches.Add(new() { X = (short)(x + TRConsts.Step4), Z = z }); - vertMatches.Add(new TRVertex + vertMatches.Add(new() { X = (short)(x + TRConsts.Step4), Z = (short)(z + TRConsts.Step4) @@ -320,12 +302,12 @@ private static List GetVerticesToMatch(FDClimbEntry climbEntry, short } if (climbEntry.IsNegativeZ) { - vertMatches.Add(new TRVertex + vertMatches.Add(new() { X = x, Z = z }); - vertMatches.Add(new TRVertex + vertMatches.Add(new() { X = (short)(x + TRConsts.Step4), Z = z @@ -333,12 +315,12 @@ private static List GetVerticesToMatch(FDClimbEntry climbEntry, short } if (climbEntry.IsPositiveZ) { - vertMatches.Add(new TRVertex + vertMatches.Add(new() { X = x, Z = (short)(z + TRConsts.Step4) }); - vertMatches.Add(new TRVertex + vertMatches.Add(new() { X = (short)(x + TRConsts.Step4), Z = (short)(z + TRConsts.Step4) @@ -352,22 +334,22 @@ private static List GetFloorOrCeilingVerticesToMatch(short x, short z) { List vertMatches = new() { - new TRVertex + new() { X = x, Z = z }, - new TRVertex + new() { X = (short)(x + TRConsts.Step4), Z = z }, - new TRVertex + new() { X = x, Z = (short)(z + TRConsts.Step4) }, - new TRVertex + new() { X = (short)(x + TRConsts.Step4), Z = (short)(z + TRConsts.Step4) diff --git a/TRRandomizerCore/Utilities/LocationUtilities.cs b/TRRandomizerCore/Utilities/LocationUtilities.cs index 8523b2a13..babfcd45d 100644 --- a/TRRandomizerCore/Utilities/LocationUtilities.cs +++ b/TRRandomizerCore/Utilities/LocationUtilities.cs @@ -1,7 +1,4 @@ -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; -using TRLevelControl; +using TRLevelControl; using TRLevelControl.Model; using TRRandomizerCore.Helpers; @@ -28,7 +25,7 @@ public static void SetLocation(this TREntity entity, Location location) entity.X = location.X; entity.Y = location.Y; entity.Z = location.Z; - entity.Room = (short)location.Room; + entity.Room = location.Room; entity.Angle = location.Angle; } @@ -61,110 +58,104 @@ public static Location GetFloorLocation(this Location baseLocation, Func e is FDTriggerEntry) is FDTriggerEntry trigger + return floorData[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger && trigger.TrigType == FDTrigType.Pickup - && trigger.TrigActionList.Find(a => a.TrigAction == FDTrigAction.SecretFound) != null; + && trigger.Actions.Find(a => a.Action == FDTrigAction.SecretFound) != null; } return false; } - public static bool HasPickupTriger(TR1Entity entity, int entityIndex, TR1Level level, FDControl floorData) + public static bool HasPickupTriger(TR1Entity entity, int entityIndex, TR1Level level) { - Location floor = entity.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level, floorData)); - TRRoomSector sector = FDUtilities.GetRoomSector(floor.X, floor.Y, floor.Z, (short)floor.Room, level, floorData); - bool hasTrigger = HasPickupTrigger(sector, entityIndex, floorData); + Location floor = entity.GetFloorLocation(loc => level.GetRoomSector(loc)); + TRRoomSector sector = level.GetRoomSector(floor); + bool hasTrigger = HasPickupTrigger(sector, entityIndex, level.FloorData); if (level.Rooms[floor.Room].AlternateRoom != -1) { - sector = FDUtilities.GetRoomSector(floor.X, floor.Y, floor.Z, level.Rooms[floor.Room].AlternateRoom, level, floorData); - hasTrigger |= HasPickupTrigger(sector, entityIndex, floorData); + sector = level.GetRoomSector(floor.X, floor.Y, floor.Z, level.Rooms[floor.Room].AlternateRoom); + hasTrigger |= HasPickupTrigger(sector, entityIndex, level.FloorData); } return hasTrigger; } - public static bool HasAnyTrigger(Location location, TR1Level level, FDControl floorData) + public static bool HasAnyTrigger(Location location, TR1Level level) { - Location floor = location.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level, floorData)); - TRRoomSector sector = FDUtilities.GetRoomSector(floor.X, floor.Y, floor.Z, (short)floor.Room, level, floorData); - bool hasTrigger = HasAnyTrigger(sector, floorData); + Location floor = location.GetFloorLocation(loc => level.GetRoomSector(loc)); + TRRoomSector sector = level.GetRoomSector(floor); + bool hasTrigger = HasAnyTrigger(sector, level.FloorData); if (level.Rooms[floor.Room].AlternateRoom != -1) { - sector = FDUtilities.GetRoomSector(floor.X, floor.Y, floor.Z, level.Rooms[floor.Room].AlternateRoom, level, floorData); - hasTrigger |= HasAnyTrigger(sector, floorData); + sector = level.GetRoomSector(floor.X, floor.Y, floor.Z, level.Rooms[floor.Room].AlternateRoom); + hasTrigger |= HasAnyTrigger(sector, level.FloorData); } return hasTrigger; } - public static bool HasPickupTriger(TR2Entity entity, int entityIndex, TR2Level level, FDControl floorData) + public static bool HasPickupTriger(TR2Entity entity, int entityIndex, TR2Level level) { - Location floor = entity.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level, floorData)); - TRRoomSector sector = FDUtilities.GetRoomSector(floor.X, floor.Y, floor.Z, (short)floor.Room, level, floorData); - bool hasTrigger = HasPickupTrigger(sector, entityIndex, floorData); + Location floor = entity.GetFloorLocation(loc => level.GetRoomSector(loc)); + TRRoomSector sector = level.GetRoomSector(floor); + bool hasTrigger = HasPickupTrigger(sector, entityIndex, level.FloorData); if (level.Rooms[floor.Room].AlternateRoom != -1) { - sector = FDUtilities.GetRoomSector(floor.X, floor.Y, floor.Z, level.Rooms[floor.Room].AlternateRoom, level, floorData); - hasTrigger |= HasPickupTrigger(sector, entityIndex, floorData); + sector = level.GetRoomSector(floor.X, floor.Y, floor.Z, level.Rooms[floor.Room].AlternateRoom); + hasTrigger |= HasPickupTrigger(sector, entityIndex, level.FloorData); } return hasTrigger; } - public static bool HasAnyTrigger(Location location, TR2Level level, FDControl floorData) + public static bool HasAnyTrigger(Location location, TR2Level level) { - Location floor = location.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level, floorData)); - TRRoomSector sector = FDUtilities.GetRoomSector(floor.X, floor.Y, floor.Z, (short)floor.Room, level, floorData); - bool hasTrigger = HasAnyTrigger(sector, floorData); + Location floor = location.GetFloorLocation(loc => level.GetRoomSector(loc)); + TRRoomSector sector = level.GetRoomSector(floor); + bool hasTrigger = HasAnyTrigger(sector, level.FloorData); if (level.Rooms[floor.Room].AlternateRoom != -1) { - sector = FDUtilities.GetRoomSector(floor.X, floor.Y, floor.Z, level.Rooms[floor.Room].AlternateRoom, level, floorData); - hasTrigger |= HasAnyTrigger(sector, floorData); + sector = level.GetRoomSector(floor.X, floor.Y, floor.Z, level.Rooms[floor.Room].AlternateRoom); + hasTrigger |= HasAnyTrigger(sector, level.FloorData); } return hasTrigger; } - public static bool HasPickupTriger(TR3Entity entity, int entityIndex, TR3Level level, FDControl floorData) + public static bool HasPickupTriger(TR3Entity entity, int entityIndex, TR3Level level) { - Location floor = entity.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level, floorData)); - TRRoomSector sector = FDUtilities.GetRoomSector(floor.X, floor.Y, floor.Z, (short)floor.Room, level, floorData); - bool hasTrigger = HasPickupTrigger(sector, entityIndex, floorData); + Location floor = entity.GetFloorLocation(loc => level.GetRoomSector(loc)); + TRRoomSector sector = level.GetRoomSector(floor); + bool hasTrigger = HasPickupTrigger(sector, entityIndex, level.FloorData); if (level.Rooms[floor.Room].AlternateRoom != -1) { - sector = FDUtilities.GetRoomSector(floor.X, floor.Y, floor.Z, level.Rooms[floor.Room].AlternateRoom, level, floorData); - hasTrigger |= HasPickupTrigger(sector, entityIndex, floorData); + sector = level.GetRoomSector(floor.X, floor.Y, floor.Z, level.Rooms[floor.Room].AlternateRoom); + hasTrigger |= HasPickupTrigger(sector, entityIndex, level.FloorData); } return hasTrigger; } - public static bool HasAnyTrigger(Location location, TR3Level level, FDControl floorData) + public static bool HasAnyTrigger(Location location, TR3Level level) { - Location floor = location.GetFloorLocation(loc => - FDUtilities.GetRoomSector(loc.X, loc.Y, loc.Z, (short)loc.Room, level, floorData)); - TRRoomSector sector = FDUtilities.GetRoomSector(floor.X, floor.Y, floor.Z, (short)floor.Room, level, floorData); - bool hasTrigger = HasAnyTrigger(sector, floorData); + Location floor = location.GetFloorLocation(loc => level.GetRoomSector(loc)); + TRRoomSector sector = level.GetRoomSector(floor); + bool hasTrigger = HasAnyTrigger(sector, level.FloorData); if (level.Rooms[floor.Room].AlternateRoom != -1) { - sector = FDUtilities.GetRoomSector(floor.X, floor.Y, floor.Z, level.Rooms[floor.Room].AlternateRoom, level, floorData); - hasTrigger |= HasAnyTrigger(sector, floorData); + sector = level.GetRoomSector(floor.X, floor.Y, floor.Z, level.Rooms[floor.Room].AlternateRoom); + hasTrigger |= HasAnyTrigger(sector, level.FloorData); } return hasTrigger; } @@ -172,21 +163,21 @@ public static bool HasAnyTrigger(Location location, TR3Level level, FDControl fl public static bool HasPickupTrigger(TRRoomSector sector, int entityIndex, FDControl floorData) { return sector.FDIndex != 0 - && floorData.Entries[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger + && floorData[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger && trigger.TrigType == FDTrigType.Pickup - && trigger.TrigActionList[0].Parameter == entityIndex; + && trigger.Actions[0].Parameter == entityIndex; } public static bool HasAnyTrigger(TRRoomSector sector, FDControl floorData) { return sector.FDIndex != 0 - && floorData.Entries[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger; + && floorData[sector.FDIndex].Find(e => e is FDTriggerEntry) is FDTriggerEntry trigger; } public static bool SectorIsSlipperySlope(TRRoomSector sector, FDControl floorData) { return sector.FDIndex != 0 - && floorData.Entries[sector.FDIndex].Find(e => e is FDSlantEntry slant && slant.Type == FDSlantType.FloorSlant) is FDSlantEntry floorSlant + && floorData[sector.FDIndex].Find(e => e is FDSlantEntry slant && slant.Type == FDSlantType.Floor) is FDSlantEntry floorSlant && (Math.Abs(floorSlant.XSlant) > 2 || Math.Abs(floorSlant.ZSlant) > 2); } @@ -195,7 +186,7 @@ public static int GetCornerHeight(TRRoomSector sector, FDControl floorData, int sbyte floor = sector.Floor; if (sector.FDIndex != 0) { - FDEntry entry = floorData.Entries[sector.FDIndex].Find(e => (e is FDSlantEntry s && s.Type == FDSlantType.FloorSlant) + FDEntry entry = floorData[sector.FDIndex].Find(e => (e is FDSlantEntry s && s.Type == FDSlantType.Floor) || (e is FDTriangulationEntry tri && tri.IsFloorTriangulation)); if (entry is FDSlantEntry slant) { @@ -239,10 +230,10 @@ public static int GetCornerHeight(TRRoomSector sector, FDControl floorData, int { List triangleCorners = new() { - triangulation.TriData.C00, - triangulation.TriData.C01, - triangulation.TriData.C10, - triangulation.TriData.C11 + triangulation.C00, + triangulation.C01, + triangulation.C10, + triangulation.C11 }; int max = triangleCorners.Max(); diff --git a/TRRandomizerCore/Utilities/Locations/AbstractLocationGenerator.cs b/TRRandomizerCore/Utilities/Locations/AbstractLocationGenerator.cs index c627e2776..2eac115ae 100644 --- a/TRRandomizerCore/Utilities/Locations/AbstractLocationGenerator.cs +++ b/TRRandomizerCore/Utilities/Locations/AbstractLocationGenerator.cs @@ -1,6 +1,4 @@ using System.Numerics; -using TRFDControl; -using TRFDControl.FDEntryTypes; using TRLevelControl; using TRLevelControl.Model; using TRRandomizerCore.Helpers; @@ -22,8 +20,7 @@ public abstract class AbstractLocationGenerator public List Generate(L level, List exclusions, bool keyItemMode = false) { - _floorData = new FDControl(); - ReadFloorData(level); + _floorData = level.FloorData; // Manual exclusions or known rooms such as swamps we wish to eliminate first DetermineBaseExcludedSectors(level, exclusions, keyItemMode); @@ -144,7 +141,7 @@ private bool RoomHasCollisionalPortal(L level, short room) // Horizontal? if (sector.FDIndex != 0 - && _floorData.Entries[sector.FDIndex].Any(e => e is FDPortalEntry)) + && _floorData[sector.FDIndex].Any(e => e is FDPortalEntry)) { return true; } @@ -236,7 +233,7 @@ private Location CreateLocation(L level, short roomIndex, int sectorIndex, TRRoo // Check the floor data, if there is any if (sector.FDIndex != 0) { - List entries = _floorData.Entries[sector.FDIndex]; + List entries = _floorData[sector.FDIndex]; bool invalidFloorData = false; for (int i = 0; i < entries.Count; i++) { @@ -261,7 +258,7 @@ private Location CreateLocation(L level, short roomIndex, int sectorIndex, TRRoo invalidFloorData = true; break; } - else if (entry is FDSlantEntry slant && slant.Type == FDSlantType.FloorSlant) + else if (entry is FDSlantEntry slant && slant.Type == FDSlantType.Floor) { // NB It's only ever FDSlantEntry or TR3TriangulationEntry (or neither) for TR3-5 Vector4? bestMidpoint = GetBestSlantMidpoint(slant); @@ -299,7 +296,8 @@ private Location CreateLocation(L level, short roomIndex, int sectorIndex, TRRoo break; } } - else if (entry is FDMinecartEntry && i < entries.Count - 1 && entries[i + 1] is TR3MinecartRotateRightEntry) + else if (entry is FDMinecartEntry minecartL && minecartL.Type == FDMinecartType.Left && i < entries.Count - 1 + && entries[i + 1] is FDMinecartEntry minecartR && minecartR.Type == FDMinecartType.Right) { // Minecart stops here, so block this tile. invalidFloorData = true; @@ -373,9 +371,9 @@ private bool IsSectorInvalid(TRRoomSector sector) private bool IsTriggerInvalid(L level, FDTriggerEntry trigger) { // Any trigger types where we don't want items placed - return trigger.TrigActionList.Any(a => - a.TrigAction == FDTrigAction.UnderwaterCurrent - || a.TrigAction == FDTrigAction.EndLevel + return trigger.Actions.Any(a => + a.Action == FDTrigAction.UnderwaterCurrent + || a.Action == FDTrigAction.EndLevel ) || !TriggerSupportsItems(level, trigger); } @@ -451,20 +449,21 @@ protected virtual bool TriggerSupportsItems(L level, FDTriggerEntry trigger) return new Vector4(TRConsts.Step2, dy, TRConsts.Step2, angle); } + // Change to GetHeight // Returned vector contains x, y, z and angle adjustments for midpoint private static Vector4? GetBestTriangleMidpoint(TRRoomSector sector, FDTriangulationEntry triangulation, int sectorIndex, int roomDepth, int roomYTop) { - int t0 = triangulation.TriData.C10; - int t1 = triangulation.TriData.C00; - int t2 = triangulation.TriData.C01; - int t3 = triangulation.TriData.C11; + int t0 = triangulation.C10; + int t1 = triangulation.C00; + int t2 = triangulation.C01; + int t3 = triangulation.C11; List triangleCorners = new() { - triangulation.TriData.C00, - triangulation.TriData.C01, - triangulation.TriData.C10, - triangulation.TriData.C11 + triangulation.C00, + triangulation.C01, + triangulation.C10, + triangulation.C11 }; int max = triangleCorners.Max(); @@ -488,7 +487,7 @@ protected virtual bool TriggerSupportsItems(L level, FDTriggerEntry trigger) int sectorXPos = sectorIndex / roomDepth * TRConsts.Step4; int sectorZPos = sectorIndex % roomDepth * TRConsts.Step4; - FDFunction func = (FDFunction)triangulation.Setup.Function; + FDFunction func = triangulation.GetFunction(); switch (func) { case FDFunction.FloorTriangulationNWSE_Solid: @@ -703,7 +702,6 @@ private static Location CreateLocation(short roomIndex, TRRoomSector sector, int }; } - protected abstract void ReadFloorData(L level); protected abstract TRRoomSector GetSector(Location location, L level); protected abstract TRRoomSector GetSector(int x, int z, int roomIndex, L level); protected abstract List GetRoomSectors(L level, int room); diff --git a/TRRandomizerCore/Utilities/Locations/TR1LocationGenerator.cs b/TRRandomizerCore/Utilities/Locations/TR1LocationGenerator.cs index 3ce099436..c2e5f048e 100644 --- a/TRRandomizerCore/Utilities/Locations/TR1LocationGenerator.cs +++ b/TRRandomizerCore/Utilities/Locations/TR1LocationGenerator.cs @@ -1,7 +1,4 @@ using System.Numerics; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Model; using TRRandomizerCore.Helpers; @@ -12,20 +9,15 @@ public class TR1LocationGenerator : AbstractLocationGenerator public override bool CrawlspacesAllowed => false; public override bool WadingAllowed => false; - protected override void ReadFloorData(TR1Level level) - { - _floorData.ParseFromLevel(level); - } - protected override TRRoomSector GetSector(Location location, TR1Level level) { - return FDUtilities.GetRoomSector(location.X, location.Y, location.Z, (short)location.Room, level, _floorData); + return level.GetRoomSector(location); } protected override TRRoomSector GetSector(int x, int z, int roomIndex, TR1Level level) { TR1Room room = level.Rooms[roomIndex]; - return FDUtilities.GetRoomSector(x, z, room.Sectors, room.Info, room.NumZSectors); + return room.GetSector(x, z); } protected override List GetRoomSectors(TR1Level level, int room) @@ -56,7 +48,7 @@ protected override bool IsRoomValid(TR1Level level, short room) protected override bool TriggerSupportsItems(TR1Level level, FDTriggerEntry trigger) { // Assume a Thor hammer trigger is directly below the hammer head. - return !trigger.TrigActionList.Any(a => a.TrigAction == FDTrigAction.Object + return !trigger.Actions.Any(a => a.Action == FDTrigAction.Object && level.Entities[a.Parameter].TypeID == TR1Type.ThorHammerHandle); } @@ -98,6 +90,6 @@ protected override Vector2 GetRoomPosition(TR1Level level, short room) protected override int GetHeight(TR1Level level, Location location, bool waterOnly) { - return FDUtilities.GetHeight(location.X, location.Z, (short)location.Room, level, _floorData, waterOnly); + return _floorData.GetHeight(location.X, location.Z, location.Room, level.Rooms, waterOnly); } } diff --git a/TRRandomizerCore/Utilities/Locations/TR2LocationGenerator.cs b/TRRandomizerCore/Utilities/Locations/TR2LocationGenerator.cs index 8fd5bbaa4..bc6d8b806 100644 --- a/TRRandomizerCore/Utilities/Locations/TR2LocationGenerator.cs +++ b/TRRandomizerCore/Utilities/Locations/TR2LocationGenerator.cs @@ -1,5 +1,4 @@ using System.Numerics; -using TRFDControl.Utilities; using TRLevelControl.Model; using TRRandomizerCore.Helpers; @@ -10,20 +9,15 @@ public class TR2LocationGenerator : AbstractLocationGenerator public override bool CrawlspacesAllowed => false; public override bool WadingAllowed => true; - protected override void ReadFloorData(TR2Level level) - { - _floorData.ParseFromLevel(level); - } - protected override TRRoomSector GetSector(Location location, TR2Level level) { - return FDUtilities.GetRoomSector(location.X, location.Y, location.Z, (short)location.Room, level, _floorData); + return level.GetRoomSector(location); } protected override TRRoomSector GetSector(int x, int z, int roomIndex, TR2Level level) { TR2Room room = level.Rooms[roomIndex]; - return FDUtilities.GetRoomSector(x, z, room.Sectors, room.Info, room.NumZSectors); + return room.GetSector(x, z); } protected override List GetRoomSectors(TR2Level level, int room) @@ -89,6 +83,6 @@ protected override Vector2 GetRoomPosition(TR2Level level, short room) protected override int GetHeight(TR2Level level, Location location, bool waterOnly) { - return FDUtilities.GetHeight(location.X, location.Z, (short)location.Room, level, _floorData, waterOnly); + return _floorData.GetHeight(location.X, location.Z, location.Room, level.Rooms, waterOnly); } } diff --git a/TRRandomizerCore/Utilities/Locations/TR3LocationGenerator.cs b/TRRandomizerCore/Utilities/Locations/TR3LocationGenerator.cs index 791919ef7..a26329b9b 100644 --- a/TRRandomizerCore/Utilities/Locations/TR3LocationGenerator.cs +++ b/TRRandomizerCore/Utilities/Locations/TR3LocationGenerator.cs @@ -1,5 +1,4 @@ using System.Numerics; -using TRFDControl.Utilities; using TRLevelControl.Model; using TRRandomizerCore.Helpers; @@ -10,20 +9,15 @@ public class TR3LocationGenerator : AbstractLocationGenerator public override bool CrawlspacesAllowed => true; public override bool WadingAllowed => true; - protected override void ReadFloorData(TR3Level level) - { - _floorData.ParseFromLevel(level); - } - protected override TRRoomSector GetSector(Location location, TR3Level level) { - return FDUtilities.GetRoomSector(location.X, location.Y, location.Z, (short)location.Room, level, _floorData); + return level.GetRoomSector(location); } protected override TRRoomSector GetSector(int x, int z, int roomIndex, TR3Level level) { TR3Room room = level.Rooms[roomIndex]; - return FDUtilities.GetRoomSector(x, z, room.Sectors, room.Info, room.NumZSectors); + return room.GetSector(x, z); } protected override List GetRoomSectors(TR3Level level, int room) @@ -89,6 +83,6 @@ protected override Vector2 GetRoomPosition(TR3Level level, short room) protected override int GetHeight(TR3Level level, Location location, bool waterOnly) { - return FDUtilities.GetHeight(location.X, location.Z, (short)location.Room, level, _floorData, waterOnly); + return _floorData.GetHeight(location.X, location.Z, location.Room, level.Rooms, waterOnly); } } diff --git a/TRRandomizerCore/Utilities/RoomWaterUtilities.cs b/TRRandomizerCore/Utilities/RoomWaterUtilities.cs index 75e446fe7..935177346 100644 --- a/TRRandomizerCore/Utilities/RoomWaterUtilities.cs +++ b/TRRandomizerCore/Utilities/RoomWaterUtilities.cs @@ -1,6 +1,4 @@ -using TRFDControl; -using TRFDControl.Utilities; -using TRLevelControl.Helpers; +using TRLevelControl.Helpers; using TRLevelControl.Model; using TRRandomizerCore.Helpers; @@ -8,7 +6,7 @@ namespace TRRandomizerCore.Utilities; public static class RoomWaterUtilities { - public static readonly Dictionary DefaultRoomCountDictionary = new() + public static readonly Dictionary DefaultRoomCountDictionary = new() { { TR1LevelNames.CAVES, 38 }, { TR1LevelNames.VILCABAMBA, 94 }, @@ -54,26 +52,16 @@ public static class RoomWaterUtilities { TR3LevelNames.ASSAULT, 133 } }; - /// - /// Take a location in a level and move it up until it is at the surface of water if it exists - /// - /// Location - /// Level - /// public static Location MoveToTheSurface(Location location, TR2Level level) { - FDControl floorData = new(); - floorData.ParseFromLevel(level); - // Make sure the boat is just on the water surface while (level.Rooms[location.Room].ContainsWater) { - // Get the room above this sector - TRRoomSector sector = FDUtilities.GetRoomSector(location.X, location.Y, location.Z, (short)location.Room, level, floorData); + TRRoomSector sector = level.GetRoomSector(location); if (sector.RoomAbove == byte.MaxValue) { break; } - // Put the boat at the bottom of the room above + location.Y = level.Rooms[sector.RoomAbove].Info.YBottom; location.Room = sector.RoomAbove; } diff --git a/TRRandomizerCore/Utilities/TR1EnemyUtilities.cs b/TRRandomizerCore/Utilities/TR1EnemyUtilities.cs index 86f49fd62..edde3270d 100644 --- a/TRRandomizerCore/Utilities/TR1EnemyUtilities.cs +++ b/TRRandomizerCore/Utilities/TR1EnemyUtilities.cs @@ -1,7 +1,4 @@ using Newtonsoft.Json; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Helpers; using TRLevelControl.Model; using TRRandomizerCore.Helpers; @@ -150,16 +147,16 @@ public static List GetRequiredEnemies(string lvlName) return entities; } - public static void SetEntityTriggers(TR1Level level, TR1Entity entity, FDControl floorData) + public static void SetEntityTriggers(TR1Level level, TR1Entity entity) { if (_oneShotEnemies.Contains(entity.TypeID)) { int entityID = level.Entities.IndexOf(entity); - List triggers = FDUtilities.GetEntityTriggers(floorData, entityID); + List triggers = level.FloorData.GetEntityTriggers(entityID); foreach (FDTriggerEntry trigger in triggers) { - trigger.TrigSetup.OneShot = true; + trigger.OneShot = true; } } } @@ -586,7 +583,7 @@ public static bool IsEmptyEgg(TR1Entity entity, TR1CombinedLevel level) return !level.Data.Models.ContainsKey(type); } - public static bool CanDropItems(TR1Entity entity, TR1CombinedLevel level, FDControl floorData) + public static bool CanDropItems(TR1Entity entity, TR1CombinedLevel level) { if (IsEmptyEgg(entity, level)) { @@ -595,8 +592,8 @@ public static bool CanDropItems(TR1Entity entity, TR1CombinedLevel level, FDCont if (entity.TypeID == TR1Type.Pierre) { - return FDUtilities.GetEntityTriggers(floorData, level.Data.Entities.IndexOf(entity)) - .All(t => t.TrigSetup.OneShot); + return level.Data.FloorData.GetEntityTriggers(level.Data.Entities.IndexOf(entity)) + .All(t => t.OneShot); } return TR1TypeUtilities.IsEnemyType(entity.TypeID); diff --git a/TRRandomizerCore/Utilities/TR2EnemyUtilities.cs b/TRRandomizerCore/Utilities/TR2EnemyUtilities.cs index acf652e31..a75437e4f 100644 --- a/TRRandomizerCore/Utilities/TR2EnemyUtilities.cs +++ b/TRRandomizerCore/Utilities/TR2EnemyUtilities.cs @@ -1,9 +1,6 @@ using Newtonsoft.Json; using TRRandomizerCore.Helpers; using TRRandomizerCore.Levels; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -480,16 +477,11 @@ public static void SetEntityTriggers(TR2Level level, TR2Entity entity) { int entityID = level.Entities.IndexOf(entity); - FDControl fdControl = new(); - fdControl.ParseFromLevel(level); - - List triggers = FDUtilities.GetEntityTriggers(fdControl, entityID); + List triggers = level.FloorData.GetEntityTriggers(entityID); foreach (FDTriggerEntry trigger in triggers) { - trigger.TrigSetup.OneShot = true; + trigger.OneShot = true; } - - fdControl.WriteToLevel(level); } } diff --git a/TRRandomizerCore/Utilities/TR3EnemyUtilities.cs b/TRRandomizerCore/Utilities/TR3EnemyUtilities.cs index 4a9ae79f6..089df4825 100644 --- a/TRRandomizerCore/Utilities/TR3EnemyUtilities.cs +++ b/TRRandomizerCore/Utilities/TR3EnemyUtilities.cs @@ -1,7 +1,4 @@ using Newtonsoft.Json; -using TRFDControl; -using TRFDControl.FDEntryTypes; -using TRFDControl.Utilities; using TRLevelControl.Helpers; using TRLevelControl.Model; using TRRandomizerCore.Helpers; @@ -177,16 +174,11 @@ public static void SetEntityTriggers(TR3Level level, TR3Entity entity) { int entityID = level.Entities.IndexOf(entity); - FDControl fdControl = new(); - fdControl.ParseFromLevel(level); - - List triggers = FDUtilities.GetEntityTriggers(fdControl, entityID); + List triggers = level.FloorData.GetEntityTriggers(entityID); foreach (FDTriggerEntry trigger in triggers) { - trigger.TrigSetup.OneShot = true; + trigger.OneShot = true; } - - fdControl.WriteToLevel(level); } } diff --git a/TextureExport/Types/FaceMapper.cs b/TextureExport/Types/FaceMapper.cs index b1e285f1e..92ffd0be7 100644 --- a/TextureExport/Types/FaceMapper.cs +++ b/TextureExport/Types/FaceMapper.cs @@ -1,8 +1,6 @@ using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; -using TRFDControl; -using TRFDControl.Utilities; using TRLevelControl; using TRLevelControl.Helpers; using TRLevelControl.Model; @@ -237,9 +235,6 @@ public static void DrawBoxes(TR2Level level, string lvl, int[] roomNumbers) Dictionary> rectFaces = new(); Dictionary> newRectFaces = new(); - FDControl control = new(); - control.ParseFromLevel(level); - foreach (int roomNumber in roomNumbers) { rectFaces[roomNumber] = new Dictionary(); @@ -257,7 +252,7 @@ public static void DrawBoxes(TR2Level level, string lvl, int[] roomNumbers) foreach (int rectIndex in rectFaces[roomNumber].Keys) { TexturedTileSegment segment = rectFaces[roomNumber][rectIndex]; - TexturedTileSegment newSegment = DrawNewFace(segment, GetBoxDescription(level, control, roomNumber, rectIndex)); + TexturedTileSegment newSegment = DrawNewFace(segment, GetBoxDescription(level, roomNumber, rectIndex)); packer.AddRectangle(newSegment); newRectFaces[roomNumber][rectIndex] = level.ObjectTextures.Count; @@ -384,7 +379,7 @@ private static TexturedTileSegment GetBoxFaceSegment(TR2Room room, int rectIndex return null; } - private static string GetBoxDescription(TR2Level level, FDControl control, int roomNumber, int rectIndex) + private static string GetBoxDescription(TR2Level level, int roomNumber, int rectIndex) { TR2Room room = level.Rooms[roomNumber]; TRFace face = room.Mesh.Rectangles[rectIndex]; @@ -399,7 +394,7 @@ private static string GetBoxDescription(TR2Level level, FDControl control, int r int xmin = verts.Min(v => v.X) + room.Info.X; int zmin = verts.Min(v => v.Z) + room.Info.Z; - TRRoomSector sector = FDUtilities.GetRoomSector(xmin, verts[0].Y, zmin, (short)roomNumber, level, control); + TRRoomSector sector = room.GetSector(xmin, zmin); if (sector.BoxIndex == ushort.MaxValue) { return "NOBOX";