From eb7cafe0c467c02329801256d605a78d7419b0e8 Mon Sep 17 00:00:00 2001 From: lahm86 <33758420+lahm86@users.noreply.github.com> Date: Thu, 30 Nov 2023 21:30:15 +0000 Subject: [PATCH] Add secret rando support Reward rooms created and reward items earmarked. Locations marked for each TRUB level. Added a method of pinpointing entity indices from environment mods, which we use to adjust some secrets after they have been placed. --- TREnvironmentEditor/Helpers/EMEntityFinder.cs | 115 ++ TREnvironmentEditor/Helpers/EMEntityType.cs | 8 + TREnvironmentEditor/Model/EMType.cs | 1 + .../Types/Entities/EMModifyEntityFunction.cs | 10 +- .../Triggers/EMResetPickupTriggerFunction.cs | 68 + TREnvironmentEditor/Parsing/EMConverter.cs | 1 + TRLevelControl/Helpers/TR1TypeUtilities.cs | 10 +- .../Randomizers/TR1/TR1SecretRandomizer.cs | 3 +- .../Environment/LEVEL3B.PHD-Environment.json | 53 + .../Resources/TR1/Locations/locations.json | 1260 +++++++++++++++++ .../SecretMapping/CAT.PHD-SecretMapping.json | 379 +++++ .../EGYPT.PHD-SecretMapping.json | 320 +++++ .../SecretMapping/END.PHD-SecretMapping.json | 258 ++++ .../SecretMapping/END2.PHD-SecretMapping.json | 219 +++ .../Utilities/RoomWaterUtilities.cs | 4 + 15 files changed, 2704 insertions(+), 5 deletions(-) create mode 100644 TREnvironmentEditor/Helpers/EMEntityFinder.cs create mode 100644 TREnvironmentEditor/Helpers/EMEntityType.cs create mode 100644 TREnvironmentEditor/Model/Types/Triggers/EMResetPickupTriggerFunction.cs create mode 100644 TRRandomizerCore/Resources/TR1/SecretMapping/CAT.PHD-SecretMapping.json create mode 100644 TRRandomizerCore/Resources/TR1/SecretMapping/EGYPT.PHD-SecretMapping.json create mode 100644 TRRandomizerCore/Resources/TR1/SecretMapping/END.PHD-SecretMapping.json create mode 100644 TRRandomizerCore/Resources/TR1/SecretMapping/END2.PHD-SecretMapping.json diff --git a/TREnvironmentEditor/Helpers/EMEntityFinder.cs b/TREnvironmentEditor/Helpers/EMEntityFinder.cs new file mode 100644 index 000000000..6c8ca0a76 --- /dev/null +++ b/TREnvironmentEditor/Helpers/EMEntityFinder.cs @@ -0,0 +1,115 @@ +using TRFDControl; +using TRFDControl.Utilities; +using TRLevelControl.Helpers; +using TRLevelControl.Model; + +namespace TREnvironmentEditor.Helpers; + +public class EMEntityFinder +{ + public EMLocation Location { get; set; } + public EMEntityType Type { get; set; } + public List Types { get; set; } + + public int GetEntity(TR1Level level) + { + FDControl floorData = new(); + floorData.ParseFromLevel(level); + + EMLevelData data = EMLevelData.GetData(level); + + List types = new(); + if (Type == EMEntityType.Item) + { + types.AddRange(TR1TypeUtilities.GetStandardPickupTypes()); + } + else if (Type == EMEntityType.KeyItem) + { + types.AddRange(TR1TypeUtilities.GetKeyItemTypes()); + } + if (Types != null) + { + 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)); + } + + public int GetEntity(TR2Level level) + { + FDControl floorData = new(); + floorData.ParseFromLevel(level); + + EMLevelData data = EMLevelData.GetData(level); + + List types = new(); + if (Type == EMEntityType.Item) + { + types.AddRange(TR2TypeUtilities.GetStandardPickupTypes()); + } + else if (Type == EMEntityType.KeyItem) + { + types.AddRange(TR2TypeUtilities.GetKeyItemTypes()); + } + if (Types != null) + { + 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)); + } + + public int GetEntity(TR3Level level) + { + FDControl floorData = new(); + floorData.ParseFromLevel(level); + + EMLevelData data = EMLevelData.GetData(level); + + List types = new(); + if (Type == EMEntityType.Item) + { + types.AddRange(TR3TypeUtilities.GetStandardPickupTypes()); + } + else if (Type == EMEntityType.KeyItem) + { + types.AddRange(TR3TypeUtilities.GetKeyItemTypes()); + } + if (Types != null) + { + 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)); + } + + public int GetEntity(List entities, List types, EMLevelData data, Func sectorFunc) + where E : TREntity + where T : Enum + { + EMLocation location = new() + { + X = Location.X, + Y = Location.Y, + Z = Location.Z, + Room = data.ConvertRoom(Location.Room) + }; + + TRRoomSector sector = sectorFunc(location); + for (int i = 0; i < entities.Count; i++) + { + E entity = entities[i]; + if (types.Contains(entity.TypeID) + && entity.Room == location.Room + && sectorFunc(new() { X = entity.X, Y = entity.Y, Z = entity.Z, Room = entity.Room }) == sector) + { + return i; + } + } + + return -1; + } +} diff --git a/TREnvironmentEditor/Helpers/EMEntityType.cs b/TREnvironmentEditor/Helpers/EMEntityType.cs new file mode 100644 index 000000000..77e326e66 --- /dev/null +++ b/TREnvironmentEditor/Helpers/EMEntityType.cs @@ -0,0 +1,8 @@ +namespace TREnvironmentEditor.Helpers; + +public enum EMEntityType +{ + Any, + Item, + KeyItem, +} diff --git a/TREnvironmentEditor/Model/EMType.cs b/TREnvironmentEditor/Model/EMType.cs index e2344710d..3dfd47dc2 100644 --- a/TREnvironmentEditor/Model/EMType.cs +++ b/TREnvironmentEditor/Model/EMType.cs @@ -58,6 +58,7 @@ public enum EMType RemoveTriggerAction = 71, RemoveEntityTriggers = 72, MergeTriggers = 73, + ResetPickupTrigger = 74, // Portal types 81-100 VisibilityPortal = 81, diff --git a/TREnvironmentEditor/Model/Types/Entities/EMModifyEntityFunction.cs b/TREnvironmentEditor/Model/Types/Entities/EMModifyEntityFunction.cs index 71f3ce407..e6cb253e7 100644 --- a/TREnvironmentEditor/Model/Types/Entities/EMModifyEntityFunction.cs +++ b/TREnvironmentEditor/Model/Types/Entities/EMModifyEntityFunction.cs @@ -6,6 +6,7 @@ namespace TREnvironmentEditor.Model.Types; public class EMModifyEntityFunction : BaseEMFunction { public int EntityIndex { get; set; } + public EMEntityFinder EntityFinder { get; set; } public bool? Invisible { get; set; } public bool? ClearBody { get; set; } public short? Intensity1 { get; set; } @@ -15,19 +16,22 @@ public class EMModifyEntityFunction : BaseEMFunction public override void ApplyToLevel(TR1Level level) { EMLevelData data = GetData(level); - ModifyEntity(level.Entities[data.ConvertEntity(EntityIndex)]); + int entityIndex = EntityFinder?.GetEntity(level) ?? EntityIndex; + ModifyEntity(level.Entities[data.ConvertEntity(entityIndex)]); } public override void ApplyToLevel(TR2Level level) { EMLevelData data = GetData(level); - ModifyEntity(level.Entities[data.ConvertEntity(EntityIndex)]); + int entityIndex = EntityFinder?.GetEntity(level) ?? EntityIndex; + ModifyEntity(level.Entities[data.ConvertEntity(entityIndex)]); } public override void ApplyToLevel(TR3Level level) { EMLevelData data = GetData(level); - ModifyEntity(level.Entities[data.ConvertEntity(EntityIndex)]); + int entityIndex = EntityFinder?.GetEntity(level) ?? EntityIndex; + ModifyEntity(level.Entities[data.ConvertEntity(entityIndex)]); } private void ModifyEntity(TR1Entity entity) diff --git a/TREnvironmentEditor/Model/Types/Triggers/EMResetPickupTriggerFunction.cs b/TREnvironmentEditor/Model/Types/Triggers/EMResetPickupTriggerFunction.cs new file mode 100644 index 000000000..035f79f1c --- /dev/null +++ b/TREnvironmentEditor/Model/Types/Triggers/EMResetPickupTriggerFunction.cs @@ -0,0 +1,68 @@ +using TREnvironmentEditor.Helpers; +using TRFDControl; +using TRFDControl.FDEntryTypes; +using TRFDControl.Utilities; +using TRLevelControl.Model; + +namespace TREnvironmentEditor.Model.Types; + +public class EMResetPickupTriggerFunction : BaseEMFunction +{ + public List Locations { get; set; } + + 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); + } + + 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); + } + + 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); + } + + private void ResetPickupTriggers(FDControl floorData, Func sectorFunc) + { + foreach (EMLocation location in Locations) + { + TRRoomSector sector = sectorFunc(location); + if (sector.FDIndex == 0) + { + continue; + } + + FDEntry entry = floorData.Entries[sector.FDIndex].Find(e => e is FDTriggerEntry); + if (entry is FDTriggerEntry trigger + && trigger.TrigType == FDTrigType.Pickup + && trigger.TrigActionList.Count > 1) + { + trigger.TrigActionList.RemoveRange(1, trigger.TrigActionList.Count - 1); + } + } + } +} diff --git a/TREnvironmentEditor/Parsing/EMConverter.cs b/TREnvironmentEditor/Parsing/EMConverter.cs index ebc1ee781..306dcd34a 100644 --- a/TREnvironmentEditor/Parsing/EMConverter.cs +++ b/TREnvironmentEditor/Parsing/EMConverter.cs @@ -92,6 +92,7 @@ private object ReadEMType(JObject jo) EMType.RemoveTriggerAction => JsonConvert.DeserializeObject(jo.ToString(), this), EMType.RemoveEntityTriggers => JsonConvert.DeserializeObject(jo.ToString(), this), EMType.MergeTriggers => JsonConvert.DeserializeObject(jo.ToString(), this), + EMType.ResetPickupTrigger => JsonConvert.DeserializeObject(jo.ToString(), this), // Portals EMType.VisibilityPortal => JsonConvert.DeserializeObject(jo.ToString(), this), diff --git a/TRLevelControl/Helpers/TR1TypeUtilities.cs b/TRLevelControl/Helpers/TR1TypeUtilities.cs index 91d23f535..0f66ea8fe 100644 --- a/TRLevelControl/Helpers/TR1TypeUtilities.cs +++ b/TRLevelControl/Helpers/TR1TypeUtilities.cs @@ -617,6 +617,14 @@ public static TR1Type GetBestLevelSecretModel(string lvl) [TR1LevelNames.ATLANTIS] = TR1Type.SecretGoldIdol_M_H, [TR1LevelNames.PYRAMID] - = TR1Type.SecretGoldIdol_M_H + = TR1Type.SecretGoldIdol_M_H, + [TR1LevelNames.EGYPT] + = TR1Type.SecretLeadBar_M_H, + [TR1LevelNames.CAT] + = TR1Type.SecretLeadBar_M_H, + [TR1LevelNames.STRONGHOLD] + = TR1Type.SecretGoldBar_M_H, + [TR1LevelNames.HIVE] + = TR1Type.SecretGoldIdol_M_H, }; } diff --git a/TRRandomizerCore/Randomizers/TR1/TR1SecretRandomizer.cs b/TRRandomizerCore/Randomizers/TR1/TR1SecretRandomizer.cs index f76fabc05..55d962e9d 100644 --- a/TRRandomizerCore/Randomizers/TR1/TR1SecretRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR1/TR1SecretRandomizer.cs @@ -779,7 +779,8 @@ private void CreateSecretTrigger(TR1CombinedLevel level, TRSecretPlacement