diff --git a/Deps/TRGE.Coord.dll b/Deps/TRGE.Coord.dll index 658701e4..c58baea0 100644 Binary files a/Deps/TRGE.Coord.dll and b/Deps/TRGE.Coord.dll differ diff --git a/Deps/TRGE.Core.dll b/Deps/TRGE.Core.dll index 12999601..a145f0b8 100644 Binary files a/Deps/TRGE.Core.dll and b/Deps/TRGE.Core.dll differ diff --git a/README.md b/README.md index 1b6d3833..3982ed79 100644 --- a/README.md +++ b/README.md @@ -49,13 +49,16 @@ For keeping track of levels while you play, check out the [TRRandoTracker](https ![TR1 Rando](Resources/Screenshots/Compressed/TR1_3.jpg) ![TR1 Rando](Resources/Screenshots/Compressed/TR1_4.jpg) ![TR1R Rando](Resources/Screenshots/Compressed/TR1R_1.jpg) +![TR1R Rando](Resources/Screenshots/Compressed/TR1R_2.jpg) ![TR2 Rando](Resources/Screenshots/Compressed/TR2_1.jpg) ![TR2 Rando](Resources/Screenshots/Compressed/TR2_4.jpg) ![TR2 Rando](Resources/Screenshots/Compressed/TR2_5.jpg) ![TR2R Rando](Resources/Screenshots/Compressed/TR2R_1.jpg) +![TR2R Rando](Resources/Screenshots/Compressed/TR2R_2.jpg) ![TR3 Rando](Resources/Screenshots/Compressed/TR3_2.jpg) ![TR3 Rando](Resources/Screenshots/Compressed/TR3_3.jpg) ![TR3R Rando](Resources/Screenshots/Compressed/TR3R_1.jpg) +![TR3R Rando](Resources/Screenshots/Compressed/TR3R_2.jpg) [View all](Resources/Screenshots). diff --git a/Resources/Documentation/RETURNPATHS.md b/Resources/Documentation/RETURNPATHS.md index 2863d7e5..dff7c3ae 100644 --- a/Resources/Documentation/RETURNPATHS.md +++ b/Resources/Documentation/RETURNPATHS.md @@ -1,6 +1,6 @@ # Return paths -Return paths can be added to the majority of levels, which allows repeat exploration without having to save and load. In some cases - such as The River Ganges - it also allows exploring levels fully where it would otherwise not be possible. +Return paths can be added to the majority of levels, which allows repeat exploration without having to save and load. In some cases - such as The River Ganges - it also allows exploring levels fully where it would otherwise not be possible. Return paths cannot currently be applied to TR I-III Remastered. Following are details on the return paths that are available. See `Global Settings` for managing whether or not these paths are added. diff --git a/Resources/Documentation/SECRETS.md b/Resources/Documentation/SECRETS.md index c528b9cd..e80aabc0 100644 --- a/Resources/Documentation/SECRETS.md +++ b/Resources/Documentation/SECRETS.md @@ -53,6 +53,8 @@ The options are: # TR2 The standard Stone, Jade and Gold dragons will be placed in each level. +Note that in TR2 Remastered, secret rewards cannot be changed: you will always receive the same rewards as per OG. In addition, while secrets are added to Dragon's Lair and Home Sweet Home, you do not receive any rewards for collecting all three in each level. + ---- ## TR3 Secret randomization logic in TR3 works in exactly the same way as TR1. diff --git a/Resources/Screenshots/Compressed/TR1R_2.jpg b/Resources/Screenshots/Compressed/TR1R_2.jpg new file mode 100644 index 00000000..457e01bd Binary files /dev/null and b/Resources/Screenshots/Compressed/TR1R_2.jpg differ diff --git a/Resources/Screenshots/Compressed/TR2R_2.jpg b/Resources/Screenshots/Compressed/TR2R_2.jpg new file mode 100644 index 00000000..0b3086f2 Binary files /dev/null and b/Resources/Screenshots/Compressed/TR2R_2.jpg differ diff --git a/Resources/Screenshots/Compressed/TR3R_2.jpg b/Resources/Screenshots/Compressed/TR3R_2.jpg new file mode 100644 index 00000000..6dd5d9c2 Binary files /dev/null and b/Resources/Screenshots/Compressed/TR3R_2.jpg differ diff --git a/Resources/Screenshots/TR1R_2.png b/Resources/Screenshots/TR1R_2.png new file mode 100644 index 00000000..0b740538 Binary files /dev/null and b/Resources/Screenshots/TR1R_2.png differ diff --git a/Resources/Screenshots/TR2R_2.png b/Resources/Screenshots/TR2R_2.png new file mode 100644 index 00000000..1672372b Binary files /dev/null and b/Resources/Screenshots/TR2R_2.png differ diff --git a/Resources/Screenshots/TR3R_2.png b/Resources/Screenshots/TR3R_2.png new file mode 100644 index 00000000..8de6cf95 Binary files /dev/null and b/Resources/Screenshots/TR3R_2.png differ diff --git a/Resources/Using/game.png b/Resources/Using/game.png index f80109d5..09ae6074 100644 Binary files a/Resources/Using/game.png and b/Resources/Using/game.png differ diff --git a/Resources/Using/trr_appid.png b/Resources/Using/trr_appid.png new file mode 100644 index 00000000..2feab76e Binary files /dev/null and b/Resources/Using/trr_appid.png differ diff --git a/TRDataControl/Data/Remastered/BaseTRRDataCache.cs b/TRDataControl/Data/Remastered/BaseTRRDataCache.cs index f5010458..b462834d 100644 --- a/TRDataControl/Data/Remastered/BaseTRRDataCache.cs +++ b/TRDataControl/Data/Remastered/BaseTRRDataCache.cs @@ -40,30 +40,33 @@ public void SetData(TRDictionary pdpData, Dictionary pdpData, TKey sourceType, TKey destinationType) { - TKey translatedKey = TranslateKey(sourceType); - if (!_pdpCache.ContainsKey(sourceType)) + lock (_pdpCache) { - string sourceLevel = GetSourceLevel(sourceType) - ?? throw new KeyNotFoundException($"Source PDP file for {sourceType} is undefined"); - - TRPDPControlBase control = GetPDPControl(); - TRDictionary models = control.Read(Path.Combine(PDPFolder, Path.GetFileNameWithoutExtension(sourceLevel) + _pdpExt)); - if (models.ContainsKey(translatedKey)) - { - _pdpCache[sourceType] = models[translatedKey]; - } - else if (models.ContainsKey(destinationType)) - { - _pdpCache[sourceType] = models[destinationType]; - } - else + TKey translatedKey = TranslateKey(sourceType); + if (!_pdpCache.ContainsKey(sourceType)) { - throw new KeyNotFoundException($"Could not load cached PDP data for {sourceType}"); + string sourceLevel = GetSourceLevel(sourceType) + ?? throw new KeyNotFoundException($"Source PDP file for {sourceType} is undefined"); + + TRPDPControlBase control = GetPDPControl(); + TRDictionary models = control.Read(Path.Combine(PDPFolder, Path.GetFileNameWithoutExtension(sourceLevel) + _pdpExt)); + if (models.ContainsKey(translatedKey)) + { + _pdpCache[sourceType] = models[translatedKey]; + } + else if (models.ContainsKey(destinationType)) + { + _pdpCache[sourceType] = models[destinationType]; + } + else + { + throw new KeyNotFoundException($"Could not load cached PDP data for {sourceType}"); + } } - } - translatedKey = TranslateKey(destinationType); - pdpData[translatedKey] = _pdpCache[sourceType]; + translatedKey = TranslateKey(destinationType); + pdpData[translatedKey] = _pdpCache[sourceType]; + } } public void SetMapData(Dictionary mapData, TKey sourceType, TKey destinationType) diff --git a/TRDataControl/Transport/TRDataImporter.cs b/TRDataControl/Transport/TRDataImporter.cs index 8f505fa4..a581ed9c 100644 --- a/TRDataControl/Transport/TRDataImporter.cs +++ b/TRDataControl/Transport/TRDataImporter.cs @@ -118,7 +118,9 @@ private void CleanRemovalList() cleanedEntities.Add(type); } } - TypesToRemove = cleanedEntities; + + var dependencies = TypesToImport.SelectMany(t => Data.GetDependencies(t)).Select(t => Data.TranslateAlias(t)); + TypesToRemove = cleanedEntities.Where(e => !dependencies.Contains(e)).ToList(); } private void CleanAliases() @@ -159,17 +161,22 @@ private void CleanAliases() private void ValidateBlobList(List modelTypes, List importBlobs) { - Dictionary> detectedAliases = new(); - foreach (T entity in modelTypes) + Dictionary> detectedAliases = new(); + foreach (T type in modelTypes) { - if (Data.IsAlias(entity)) + T inferredType = type; + if (Data.AliasPriority?.ContainsKey(type) ?? false) + { + inferredType = Data.GetLevelAlias(LevelName, type); + } + if (Data.IsAlias(inferredType)) { - T masterType = Data.TranslateAlias(entity); + T masterType = Data.TranslateAlias(inferredType); if (!detectedAliases.ContainsKey(masterType)) { detectedAliases[masterType] = new(); } - detectedAliases[masterType].Add(entity); + detectedAliases[masterType].Add(inferredType); } } diff --git a/TRLevelControl/Build/TRSpriteBuilder.cs b/TRLevelControl/Build/TRSpriteBuilder.cs index bcd4d5f3..f5cba3bf 100644 --- a/TRLevelControl/Build/TRSpriteBuilder.cs +++ b/TRLevelControl/Build/TRSpriteBuilder.cs @@ -22,7 +22,11 @@ public TRDictionary ReadSprites(TRLevelReader reader) { string sprMarker = new(reader.ReadChars(_sprMarker.Length)); Debug.Assert(sprMarker == _sprMarker); - Debug.Assert(_version != TRGameVersion.TR5 || reader.ReadByte() == 0); + if (_version == TRGameVersion.TR5) + { + byte end = reader.ReadByte(); + Debug.Assert(end == 0); + } } uint numTextures = reader.ReadUInt32(); diff --git a/TRLevelControl/Build/TRTextureBuilder.cs b/TRLevelControl/Build/TRTextureBuilder.cs index edc959d8..f64ebe7f 100644 --- a/TRLevelControl/Build/TRTextureBuilder.cs +++ b/TRLevelControl/Build/TRTextureBuilder.cs @@ -25,7 +25,8 @@ public List ReadObjectTextures(TRLevelReader reader) Debug.Assert(texMarker == _texMarker); if (_version == TRGameVersion.TR5) { - Debug.Assert(reader.ReadByte() == 0); + byte end = reader.ReadByte(); + Debug.Assert(end == 0); } } diff --git a/TRLevelControl/Helpers/TR1TypeUtilities.cs b/TRLevelControl/Helpers/TR1TypeUtilities.cs index cf9da983..c8b6c8d5 100644 --- a/TRLevelControl/Helpers/TR1TypeUtilities.cs +++ b/TRLevelControl/Helpers/TR1TypeUtilities.cs @@ -6,6 +6,23 @@ public static class TR1TypeUtilities { public static readonly Dictionary>> LevelAliases = new() { + [TR1Type.LaraMiscAnim_H] = new() + { + [TR1Type.LaraMiscAnim_H_General] = + new() { TR1LevelNames.CAVES, TR1LevelNames.VILCABAMBA, TR1LevelNames.FOLLY, TR1LevelNames.COLOSSEUM, TR1LevelNames.CISTERN, TR1LevelNames.TIHOCAN }, + [TR1Type.LaraMiscAnim_H_Valley] = + new() { TR1LevelNames.VALLEY }, + [TR1Type.LaraMiscAnim_H_Qualopec] = + new() { TR1LevelNames.QUALOPEC }, + [TR1Type.LaraMiscAnim_H_Midas] = + new() { TR1LevelNames.MIDAS }, + [TR1Type.LaraMiscAnim_H_Sanctuary] = + new() { TR1LevelNames.SANCTUARY }, + [TR1Type.LaraMiscAnim_H_Atlantis] = + new() { TR1LevelNames.ATLANTIS }, + [TR1Type.LaraMiscAnim_H_Pyramid] = + new() { TR1LevelNames.PYRAMID }, + }, [TR1Type.FlyingAtlantean] = new() { [TR1Type.BandagedFlyer] = diff --git a/TRLevelControl/Helpers/TR2TypeUtilities.cs b/TRLevelControl/Helpers/TR2TypeUtilities.cs index 370b4d9f..499e5dd5 100644 --- a/TRLevelControl/Helpers/TR2TypeUtilities.cs +++ b/TRLevelControl/Helpers/TR2TypeUtilities.cs @@ -19,6 +19,21 @@ public static class TR2TypeUtilities [TR2Type.LaraAssault] = new() { TR2LevelNames.ASSAULT }, }, + [TR2Type.LaraMiscAnim_H] = new() + { + [TR2Type.LaraMiscAnim_H_Wall] = + new() { TR2LevelNames.GW }, + [TR2Type.LaraMiscAnim_H_Venice] = + new() { TR2LevelNames.BARTOLI }, + [TR2Type.LaraMiscAnim_H_Unwater] = + new() { TR2LevelNames.RIG, TR2LevelNames.DA, TR2LevelNames.FATHOMS, TR2LevelNames.DORIA, TR2LevelNames.DECK }, + [TR2Type.LaraMiscAnim_H_Ice] = + new() { TR2LevelNames.COT, TR2LevelNames.CHICKEN }, + [TR2Type.LaraMiscAnim_H_Xian] = + new() { TR2LevelNames.FLOATER, TR2LevelNames.LAIR }, + [TR2Type.LaraMiscAnim_H_HSH] = + new() { TR2LevelNames.HOME } + }, [TR2Type.Barracuda] = new() { [TR2Type.BarracudaIce] = diff --git a/TRLevelControl/Model/Common/FloorData/FDControl.cs b/TRLevelControl/Model/Common/FloorData/FDControl.cs index d5049424..3c0e24de 100644 --- a/TRLevelControl/Model/Common/FloorData/FDControl.cs +++ b/TRLevelControl/Model/Common/FloorData/FDControl.cs @@ -172,6 +172,15 @@ public void RemoveEntityTriggers(int entityIndex) } } + public List GetTriggerRooms(int entityIndex, List rooms) + where R : TRRoom + { + List triggers = GetEntityTriggers(entityIndex); + return Enumerable.Range(0, rooms.Count) + .Where(i => rooms[i].Sectors.Any(s => s.FDIndex != 0 && triggers.Any(_entries[s.FDIndex].Contains))) + .Select(i => (short)i).ToList(); + } + public TRRoomSector GetRoomSector(int x, int y, int z, short roomNumber, List rooms) where R : TRRoom { diff --git a/TRLevelControl/TRGControlBase.cs b/TRLevelControl/TRGControlBase.cs index 6eb8b815..7fd1b708 100644 --- a/TRLevelControl/TRGControlBase.cs +++ b/TRLevelControl/TRGControlBase.cs @@ -13,7 +13,8 @@ public static TRGData Read(string filePath) public static TRGData Read(Stream stream) { using TRLevelReader reader = new(stream); - Debug.Assert(reader.ReadUInt32() == _trgMagic); + uint magic = reader.ReadUInt32(); + Debug.Assert(magic == _trgMagic); TRGData data = new(); diff --git a/TRLevelControlTests/TR1/FDTests.cs b/TRLevelControlTests/TR1/FDTests.cs index 30049c5d..0ad4396c 100644 --- a/TRLevelControlTests/TR1/FDTests.cs +++ b/TRLevelControlTests/TR1/FDTests.cs @@ -400,6 +400,42 @@ public void GetEntityTriggers() TestGetEntityTriggers(level.FloorData, 1); } + [TestMethod] + [Description("Get list of rooms that contain an entity's triggers.")] + public void GetTriggerRooms() + { + TR1Level level = GetTR1TestLevel(); + + // Check original single trigger + List rooms = level.FloorData.GetTriggerRooms(12, level.Rooms); + Assert.AreEqual(1, rooms.Count); + Assert.IsTrue(rooms.Contains(6)); + + void AddTestTrigger(TRRoomSector sector) + { + level.FloorData.CreateFloorData(sector); + level.FloorData[sector.FDIndex].Add(new FDTriggerEntry + { + Actions = new() + { + new() { Parameter = 12 } + } + }); + } + + // Add another in a different room + AddTestTrigger(level.Rooms[4].GetSector(3, 1, TRUnit.Sector)); + rooms = level.FloorData.GetTriggerRooms(12, level.Rooms); + Assert.AreEqual(2, rooms.Count); + Assert.IsTrue(rooms.Contains(4)); + Assert.IsTrue(rooms.Contains(6)); + + // Add a third but in the same room - we don't want duplicate room numbers returned + AddTestTrigger(level.Rooms[4].GetSector(3, 2, TRUnit.Sector)); + rooms = level.FloorData.GetTriggerRooms(12, level.Rooms); + Assert.AreEqual(2, rooms.Count); + } + [TestMethod] [Description("Test finding secret triggers.")] public void GetSecretTriggers() diff --git a/TRRandomizerCore/Helpers/ChecksumTester.cs b/TRRandomizerCore/Helpers/ChecksumTester.cs index ad60b12c..aa51039a 100644 --- a/TRRandomizerCore/Helpers/ChecksumTester.cs +++ b/TRRandomizerCore/Helpers/ChecksumTester.cs @@ -146,6 +146,9 @@ public bool Test(string file) "79e3f05f963acac6f864ba81555cc15d", // MONASTRY.TR2 "cf4f784bdfa0b5794b3437e4d9ed04d8", // ICECAVE.TR2 + // TR2R V1.3+ + "ef2f5a3e08bd10655c38707e6657c687", // LEVEL5.TR2 + // TR3 "5e11d251ddb12b98ebead1883dc12d2a", // HOUSE.TR2 "9befdc5075fdb84450d2ed0533719b12", // JUNGLE.TR2 (International) diff --git a/TRRandomizerCore/Randomizers/Shared/EnvironmentPicker.cs b/TRRandomizerCore/Randomizers/Shared/EnvironmentPicker.cs index cecb5470..773a4c2c 100644 --- a/TRRandomizerCore/Randomizers/Shared/EnvironmentPicker.cs +++ b/TRRandomizerCore/Randomizers/Shared/EnvironmentPicker.cs @@ -91,6 +91,8 @@ public List GetRandomAny(EMEditorMapping mapping) { // Pick a random number of packs to apply, but at least 1 sets = pool.RandomSelection(_generator, _generator.Next(1, pool.Count + 1)); + // Ensure original order is kept as some mods rely on other things happening first + sets.Sort((s1, s2) => pool.IndexOf(s1).CompareTo(pool.IndexOf(s2))); } return sets; diff --git a/TRRandomizerCore/Randomizers/Shared/ItemAllocator.cs b/TRRandomizerCore/Randomizers/Shared/ItemAllocator.cs index a8047239..1a083825 100644 --- a/TRRandomizerCore/Randomizers/Shared/ItemAllocator.cs +++ b/TRRandomizerCore/Randomizers/Shared/ItemAllocator.cs @@ -326,10 +326,7 @@ public void ApplyItemSwaps(string levelName, List items) } } - if (!Settings.AllowEnemyKeyDrops) - { - ExcludeEnemyKeyDrops(items); - } + ExcludeEnemyKeyDrops(items); } protected List GetPickups(string levelName, List items, bool isUnarmed) diff --git a/TRRandomizerCore/Randomizers/Shared/LocationPicker.cs b/TRRandomizerCore/Randomizers/Shared/LocationPicker.cs index 4aafaa73..79b79cfb 100644 --- a/TRRandomizerCore/Randomizers/Shared/LocationPicker.cs +++ b/TRRandomizerCore/Randomizers/Shared/LocationPicker.cs @@ -17,7 +17,7 @@ public class LocationPicker : IRouteManager private Random _generator; public Func TriggerTestAction { get; set; } - public Func KeyItemTestAction { get; set; } + public Func, bool> KeyItemTestAction { get; set; } public List RoomInfos { get; set; } public int LevelSize { get; private set; } @@ -138,7 +138,7 @@ public Location GetKeyItemLocation(int keyItemID, TREntity entity, bool ha continue; } - if (KeyItemTestAction != null && !KeyItemTestAction(newLocation, hasPickupTrigger)) + if (KeyItemTestAction != null && !KeyItemTestAction(newLocation, hasPickupTrigger, roomPool)) { continue; } diff --git a/TRRandomizerCore/Randomizers/Shared/TextureAllocator.cs b/TRRandomizerCore/Randomizers/Shared/TextureAllocator.cs index 7004b293..91c94eeb 100644 --- a/TRRandomizerCore/Randomizers/Shared/TextureAllocator.cs +++ b/TRRandomizerCore/Randomizers/Shared/TextureAllocator.cs @@ -12,7 +12,7 @@ public class TextureAllocator where R : Enum { private readonly TRTexInfo _texInfo; - private readonly Dictionary _trgData; + private readonly Dictionary _trgData, _cutTrgData; private readonly Dictionary> _mapData; public Random Generator { get; set; } @@ -22,6 +22,7 @@ public TextureAllocator(TRGameVersion version) { _texInfo = JsonConvert.DeserializeObject>(File.ReadAllText($@"Resources\{version}\Textures\texinfo.json")); _trgData = new(); + _cutTrgData = new(); _mapData = new(); } @@ -31,6 +32,11 @@ public void LoadData(TRRScriptedLevel level, TRGData trgData, Dictionary m _mapData[level] = mapData; } + public void LoadCutData(TRRScriptedLevel parentLevel, TRGData trgData) + { + _cutTrgData[parentLevel] = trgData; + } + public void Allocate(Func, bool> saveData) { Dictionary> textureCache = _trgData.ToDictionary(l => l.Key, l => l.Value.Textures.ToList()); @@ -48,7 +54,7 @@ public void Allocate(Func, bool> sav while (levelSwaps.Any(l => levels.IndexOf(l) == levelSwaps.IndexOf(l))); } - foreach (var (level, trgData) in _trgData) + Dictionary AllocateLevel(TRRScriptedLevel level, TRGData trgData) { List baseTextures = new(); List newTextures = new(); @@ -60,13 +66,15 @@ public void Allocate(Func, bool> sav else if (Settings.TextureMode == TextureMode.Game) { TRRScriptedLevel nextLevel = levelSwaps[levels.IndexOf(level)]; - baseTextures.AddRange(textureCache[nextLevel]); - newTextures = textureCache[nextLevel]; - - while (newTextures.Count < trgData.Textures.Count) + List textureSet = textureCache[nextLevel].RandomSelection(Generator, + Math.Min(trgData.Textures.Count, textureCache[nextLevel].Distinct().Count())); + while (textureSet.Count < trgData.Textures.Count) { - newTextures.Add(newTextures.RandomItem(Generator)); + textureSet.Add(textureCache[nextLevel].RandomItem(Generator)); } + + baseTextures.AddRange(textureCache[nextLevel]); + newTextures.AddRange(textureSet); } else { @@ -108,16 +116,30 @@ public void Allocate(Func, bool> sav animatedIndices.ForEach(i => newTextures[i] = defaultTexture); } - Dictionary itemRemap = Settings.TextureMode == TextureMode.Game && Settings.MatchTextureItems + trgData.Textures.Clear(); + trgData.Textures.AddRange(newTextures); + + return Settings.TextureMode == TextureMode.Game && Settings.MatchTextureItems ? RemapItems(level, levelSwaps[levels.IndexOf(level)]) : null; + } - trgData.Textures.Clear(); - trgData.Textures.AddRange(newTextures); + foreach (var (level, trgData) in _trgData) + { + Dictionary itemRemap = AllocateLevel(level, trgData); if (!saveData(level, trgData, itemRemap)) { break; } + + if (_cutTrgData.ContainsKey(level)) + { + AllocateLevel(level, _cutTrgData[level]); + if (!saveData(level.CutSceneLevel as TRRScriptedLevel, _cutTrgData[level], null)) + { + break; + } + } } } diff --git a/TRRandomizerCore/Randomizers/TR1/Classic/TR1ItemRandomizer.cs b/TRRandomizerCore/Randomizers/TR1/Classic/TR1ItemRandomizer.cs index a77c02ae..0901d6f3 100644 --- a/TRRandomizerCore/Randomizers/TR1/Classic/TR1ItemRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR1/Classic/TR1ItemRandomizer.cs @@ -80,12 +80,11 @@ public void FinalizeRandomization() else { _allocator.RandomizeKeyItems(_levelInstance.Name, _levelInstance.Data, _levelInstance.Script.OriginalSequence); - } - - if (Settings.AllowEnemyKeyDrops) - { - UpdateEnemyItemDrops(_levelInstance, _levelInstance.Data.Entities - .Where(e => TR1TypeUtilities.IsKeyItemType(e.TypeID))); + if (Settings.AllowEnemyKeyDrops) + { + UpdateEnemyItemDrops(_levelInstance, _levelInstance.Data.Entities + .Where(e => TR1TypeUtilities.IsKeyItemType(e.TypeID))); + } } SaveLevelInstance(); diff --git a/TRRandomizerCore/Randomizers/TR1/Classic/TR1SecretRandomizer.cs b/TRRandomizerCore/Randomizers/TR1/Classic/TR1SecretRandomizer.cs index 101dee0f..c0066c7d 100644 --- a/TRRandomizerCore/Randomizers/TR1/Classic/TR1SecretRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR1/Classic/TR1SecretRandomizer.cs @@ -116,6 +116,7 @@ public override void Randomize(int seed) script.FixDescendingGlitch = false; script.FixQwopGlitch = false; script.FixWallJumpGlitch = false; + script.WalkToItems = false; } ScriptEditor.SaveScript(); diff --git a/TRRandomizerCore/Randomizers/TR1/Remastered/TR1RTextureRandomizer.cs b/TRRandomizerCore/Randomizers/TR1/Remastered/TR1RTextureRandomizer.cs index 4831bae3..77fc923f 100644 --- a/TRRandomizerCore/Randomizers/TR1/Remastered/TR1RTextureRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR1/Remastered/TR1RTextureRandomizer.cs @@ -15,9 +15,12 @@ public override void Randomize(int seed) foreach (TRRScriptedLevel level in Levels) { - TRGData trgData = LoadTRGData(level.TrgFileBaseName); - Dictionary mapData = LoadMapData(level.MapFileBaseName); - allocator.LoadData(level, trgData, mapData); + allocator.LoadData(level, LoadTRGData(level.TrgFileBaseName), LoadMapData(level.MapFileBaseName)); + if (level.HasCutScene) + { + TRRScriptedLevel cutLevel = level.CutSceneLevel as TRRScriptedLevel; + allocator.LoadCutData(level, LoadTRGData(cutLevel.TrgFileBaseName)); + } if (!TriggerProgress()) { return; @@ -28,7 +31,7 @@ public override void Randomize(int seed) { SaveMapData(mapData, level.MapFileBaseName); SaveTRGData(trgData, level.TrgFileBaseName); - return TriggerProgress(); + return level.IsCutscene || TriggerProgress(); }); } } diff --git a/TRRandomizerCore/Randomizers/TR2/Classic/TR2OutfitRandomizer.cs b/TRRandomizerCore/Randomizers/TR2/Classic/TR2OutfitRandomizer.cs index 385e598b..7fa033ca 100644 --- a/TRRandomizerCore/Randomizers/TR2/Classic/TR2OutfitRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR2/Classic/TR2OutfitRandomizer.cs @@ -275,6 +275,12 @@ private bool Import(TR2CombinedLevel level, TR2Type lara) // Try to import the selected models into the level. importer.Import(); + if (lara == TR2TypeUtilities.GetAliasForLevel(level.Name, TR2Type.Lara)) + { + // In case a previous attempt failed, we need to restore default texture mapping + _outer.TextureMonitor.GetMonitor(level.Name)?.RemovedTextures?.Remove(TR2Type.Lara); + } + if (level.IsCutScene) { // Restore original cutscene animations diff --git a/TRRandomizerCore/Randomizers/TR2/Remastered/TR2REnemyRandomizer.cs b/TRRandomizerCore/Randomizers/TR2/Remastered/TR2REnemyRandomizer.cs index d7b7295d..25b4716e 100644 --- a/TRRandomizerCore/Randomizers/TR2/Remastered/TR2REnemyRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR2/Remastered/TR2REnemyRandomizer.cs @@ -219,9 +219,17 @@ void AddItem(TR2Type type, int count) item.SetLocation(_hshShellLocations[i % _hshShellLocations.Count]); } } - else if (!level.Data.Entities.Any(e => e.TypeID == TR2Type.Pistols_S_P)) + else { - AddItem(TR2Type.Pistols_S_P, 1); + TR2Entity pistols = level.Data.Entities.Find(e => e.TypeID == TR2Type.Pistols_S_P); + if (pistols == null) + { + AddItem(TR2Type.Pistols_S_P, 1); + } + else + { + pistols.SetLocation(item.GetLocation()); + } } if (Settings.GiveUnarmedItems) diff --git a/TRRandomizerCore/Randomizers/TR2/Remastered/TR2RTextureRandomizer.cs b/TRRandomizerCore/Randomizers/TR2/Remastered/TR2RTextureRandomizer.cs index 23e9b968..1d1d6038 100644 --- a/TRRandomizerCore/Randomizers/TR2/Remastered/TR2RTextureRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR2/Remastered/TR2RTextureRandomizer.cs @@ -15,9 +15,12 @@ public override void Randomize(int seed) foreach (TRRScriptedLevel level in Levels) { - TRGData trgData = LoadTRGData(level.TrgFileBaseName); - Dictionary mapData = LoadMapData(level.MapFileBaseName); - allocator.LoadData(level, trgData, mapData); + allocator.LoadData(level, LoadTRGData(level.TrgFileBaseName), LoadMapData(level.MapFileBaseName)); + if (level.HasCutScene) + { + TRRScriptedLevel cutLevel = level.CutSceneLevel as TRRScriptedLevel; + allocator.LoadCutData(level, LoadTRGData(cutLevel.TrgFileBaseName)); + } if (!TriggerProgress()) { return; @@ -28,7 +31,7 @@ public override void Randomize(int seed) { SaveMapData(mapData, level.MapFileBaseName); SaveTRGData(trgData, level.TrgFileBaseName); - return TriggerProgress(); + return level.IsCutscene || TriggerProgress(); }); } } diff --git a/TRRandomizerCore/Randomizers/TR2/Shared/TR2ItemAllocator.cs b/TRRandomizerCore/Randomizers/TR2/Shared/TR2ItemAllocator.cs index 783dafde..f7cbfa1d 100644 --- a/TRRandomizerCore/Randomizers/TR2/Shared/TR2ItemAllocator.cs +++ b/TRRandomizerCore/Randomizers/TR2/Shared/TR2ItemAllocator.cs @@ -84,7 +84,7 @@ private void InitialisePicker(string levelName, TR2Level level, LocationMode loc ? location => LocationUtilities.HasAnyTrigger(location, level) : null; _picker.KeyItemTestAction = locationMode == LocationMode.KeyItems - ? (location, hasPickupTrigger) => TestKeyItemLocation(location, hasPickupTrigger, levelName, level) + ? (location, hasPickupTrigger, roomPool) => TestKeyItemLocation(location, hasPickupTrigger, roomPool, levelName, level) : null; _picker.RoomInfos = new(level.Rooms.Select(r => new ExtRoomInfo(r))); @@ -99,9 +99,10 @@ private void InitialisePicker(string levelName, TR2Level level, LocationMode loc _picker.Initialise(levelName, pool, Settings, Generator); } - private bool TestKeyItemLocation(Location location, bool hasPickupTrigger, string levelName, TR2Level level) + private bool TestKeyItemLocation(Location location, bool hasPickupTrigger, List roomPool, string levelName, TR2Level level) { - // Make sure if we're placing on the same tile as an enemy, that the enemy can drop the item. + // Make sure if we're placing on the same tile as an enemy, that the enemy can drop the item. Ensure too that the enemy + // can be triggered from within the key item's room pool and not beyond. TR2Entity enemy = level.Entities .FindAll(e => TR2TypeUtilities.IsEnemyType(e.TypeID)) .Find(e => e.GetLocation().IsEquivalent(location)); @@ -111,7 +112,8 @@ private bool TestKeyItemLocation(Location location, bool hasPickupTrigger, strin TR2TypeUtilities.GetAliasForLevel(levelName, enemy.TypeID), Settings.RandomizeEnemies && !Settings.ProtectMonks, Settings.RandomizeEnemies && Settings.UnconditionalChickens - )); + ) + && level.FloorData.GetTriggerRooms(level.Entities.IndexOf(enemy), level.Rooms).Any(roomPool.Contains)); } private List GetItemLocationPool(string levelName, TR2Level level, bool keyItemMode) diff --git a/TRRandomizerCore/Randomizers/TR3/Remastered/TR3REnemyRandomizer.cs b/TRRandomizerCore/Randomizers/TR3/Remastered/TR3REnemyRandomizer.cs index baaca7e9..55328ba6 100644 --- a/TRRandomizerCore/Randomizers/TR3/Remastered/TR3REnemyRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR3/Remastered/TR3REnemyRandomizer.cs @@ -5,6 +5,7 @@ using TRRandomizerCore.Helpers; using TRRandomizerCore.Levels; using TRRandomizerCore.Processors; +using TRRandomizerCore.Utilities; namespace TRRandomizerCore.Randomizers; @@ -114,8 +115,8 @@ private void ApplyPostRandomization(TR3RCombinedLevel level) _allocator.AddUnarmedLevelAmmo(level.Name, level.Data, (loc, type) => { }); - // We can't give more ammo because HSC is so close to the limit. Instead just guarantee - // pistols in the starting area + // We can't give more ammo or add additional pistols because HSC is so close to the + // item limit. Instead just move the OG pistols to the starting area. List pistolLocations = _allocator.GetPistolLocations(level.Name); Location location; do @@ -124,8 +125,9 @@ private void ApplyPostRandomization(TR3RCombinedLevel level) } while (location.Room != 7); - TR3Entity pistols = ItemFactory.CreateItem(level.Name, level.Data.Entities, location); + TR3Entity pistols = level.Data.Entities.Find(e => TR3TypeUtilities.IsWeaponPickup(e.TypeID)); pistols.TypeID = TR3Type.Pistols_P; + pistols.SetLocation(location); } internal class EnemyProcessor : AbstractProcessorThread diff --git a/TRRandomizerCore/Randomizers/TR3/Remastered/TR3RStartPositionRandomizer.cs b/TRRandomizerCore/Randomizers/TR3/Remastered/TR3RStartPositionRandomizer.cs index 2b1c2585..a325e30a 100644 --- a/TRRandomizerCore/Randomizers/TR3/Remastered/TR3RStartPositionRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR3/Remastered/TR3RStartPositionRandomizer.cs @@ -32,8 +32,12 @@ public override void Randomize(int seed) private void RandomizeStartPosition(TR3RCombinedLevel level) { - TR3Entity lara = level.Data.Entities.Find(e => e.TypeID == TR3Type.Lara); + if (level.Script.HasStartAnimation) + { + return; + } + TR3Entity lara = level.Data.Entities.Find(e => e.TypeID == TR3Type.Lara); if (!Settings.RotateStartPositionOnly && _startLocations.ContainsKey(level.Name)) { List locations = _startLocations[level.Name]; diff --git a/TRRandomizerCore/Randomizers/TR3/Remastered/TR3RTextureRandomizer.cs b/TRRandomizerCore/Randomizers/TR3/Remastered/TR3RTextureRandomizer.cs index fbc37c50..7109dd0c 100644 --- a/TRRandomizerCore/Randomizers/TR3/Remastered/TR3RTextureRandomizer.cs +++ b/TRRandomizerCore/Randomizers/TR3/Remastered/TR3RTextureRandomizer.cs @@ -15,9 +15,12 @@ public override void Randomize(int seed) foreach (TRRScriptedLevel level in Levels) { - TRGData trgData = LoadTRGData(level.TrgFileBaseName); - Dictionary mapData = LoadMapData(level.MapFileBaseName); - allocator.LoadData(level, trgData, mapData); + allocator.LoadData(level, LoadTRGData(level.TrgFileBaseName), LoadMapData(level.MapFileBaseName)); + if (level.HasCutScene) + { + TRRScriptedLevel cutLevel = level.CutSceneLevel as TRRScriptedLevel; + allocator.LoadCutData(level, LoadTRGData(cutLevel.TrgFileBaseName)); + } if (!TriggerProgress()) { return; @@ -28,7 +31,7 @@ public override void Randomize(int seed) { SaveMapData(mapData, level.MapFileBaseName); SaveTRGData(trgData, level.TrgFileBaseName); - return TriggerProgress(); + return level.IsCutscene || TriggerProgress(); }); } } diff --git a/TRRandomizerCore/Randomizers/TR3/Shared/TR3ItemAllocator.cs b/TRRandomizerCore/Randomizers/TR3/Shared/TR3ItemAllocator.cs index d54498a9..ba99b851 100644 --- a/TRRandomizerCore/Randomizers/TR3/Shared/TR3ItemAllocator.cs +++ b/TRRandomizerCore/Randomizers/TR3/Shared/TR3ItemAllocator.cs @@ -79,7 +79,7 @@ private void InitialisePicker(string levelName, TR3Level level, LocationMode loc ? location => LocationUtilities.HasAnyTrigger(location, level) : null; _picker.KeyItemTestAction = locationMode == LocationMode.KeyItems - ? (location, hasPickupTrigger) => TestKeyItemLocation(location, hasPickupTrigger, levelName, level) + ? (location, hasPickupTrigger, roomPool) => TestKeyItemLocation(location, hasPickupTrigger, roomPool, levelName, level) : null; _picker.RoomInfos = new(level.Rooms.Select(r => new ExtRoomInfo(r))); @@ -94,7 +94,7 @@ private void InitialisePicker(string levelName, TR3Level level, LocationMode loc _picker.Initialise(levelName, pool, Settings, Generator); } - private bool TestKeyItemLocation(Location location, bool hasPickupTrigger, string levelName, TR3Level level) + private bool TestKeyItemLocation(Location location, bool hasPickupTrigger, List roomPool, string levelName, TR3Level level) { // Make sure if we're placing on the same tile as an enemy, that the enemy can drop the item. TR3Entity enemy = level.Entities @@ -105,7 +105,8 @@ private bool TestKeyItemLocation(Location location, bool hasPickupTrigger, strin ( TR3TypeUtilities.GetAliasForLevel(levelName, enemy.TypeID), !Settings.RandomizeEnemies || Settings.ProtectMonks - )); + ) + && level.FloorData.GetTriggerRooms(level.Entities.IndexOf(enemy), level.Rooms).Any(roomPool.Contains)); } private List GetItemLocationPool(string levelName, TR3Level level, bool keyItemMode, bool isCold) diff --git a/TRRandomizerCore/Resources/TR1/Textures/texinfo.json b/TRRandomizerCore/Resources/TR1/Textures/texinfo.json index 1396131b..e8f18088 100644 --- a/TRRandomizerCore/Resources/TR1/Textures/texinfo.json +++ b/TRRandomizerCore/Resources/TR1/Textures/texinfo.json @@ -1 +1 @@ -{"Categories":{"Opaque":[15,17,18,19,20,24,25,27,28,30,31,32,34,36,37,38,39,40,41,42,43,44,45,46,47,48,49,52,53,54,55,57,63,65,66,67,68,69,70,72,73,74,81,82,84,86,87,88,91,92,93,94,95,96,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,121,126,127,128,129,130,131,132,133,134,135,136,137,138,140,143,144,145,146,148,149,150,151,152,153,154,155,156,163,164,165,167,168,173,174,177,178,179,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,200,207,208,210,211,212,214,215,216,217,218,221,230,231,232,233,234,235,237,238,239,241,242,243,244,245,249,250,251,252,253,256,257,258,261,262,263,264,265,266,267,268,269,271,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,292,293,296,297,301,302,303,304,305,307,309,310,311,312,313,314,315,316,320,324,325,326,327,328,329,331,332,335,336,337,338,340,341,342,343,345,346,347,349,350,351,352,353,354,357,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,377,378,379,380,381,382,383,384,385,386,387,388,389,391,392,393,394,395,396,397,401,407,408,409,411,412,413,414,415,416,417,418,419,422,423,424,425,426,427,428,429,430,431,432,433,434,435,438,439,440,441,442,445,446,449,450,451,452,453,455,456,457,459,460,461,463,464,465,466,467,468,469,470,471,472,474,475,476,478,479,480,482,484,485,486,487,488,489,490,491,492,493,494,496,498,499,500,501,502,503,504,505,506,507,510,511,513,514,515,516,519,520,521,522,524,525,526,527,530,532,533,534,535,537,541,542,543,561,562,563,564,565,566,567,568,569,572,573,575,576,577,578,579,580,581,583,584,585,586,587,595,596,597,598,599,600,602,603,604,605,606,607,608,609,610,621,622,623,624,625,626,627,630,631,632,633,635,637,640,641,642,643,645,646,648,650,653,658,660,661,662,663,665,666,668,669,671,672,673,674,676,679,680,681,682,683,684,685,686,688,689,690,691,692,693,694,696,697,698,699,700,701,702,703,704,706,707,709,710,711,714,715,716,717,718,719,721,722,724,725,727,728,729,730,731,732,733,734,735,736,737,738,739,859,1002,1008,1009,1010,1011,1012,1015,2049,2050,2051,2052,3016,3025,3026,3027,3029,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3044,3045,3046,3047,3048,3049,3050,3051,3052,4128,5060,5869,7002,7003,7004,7014,7021,7051,7052,7054,7055,7058,7060],"Fixed":[1,2,60,61,254,255,259,454,509,545,546,547,548,549,550,551,552,553,554,555,556,557,559,560,591,592,611,612,613,614,615,616,617,618,619,659,664,667,670,675,678,687,695,800,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,833,835,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,861,862,863,864,866,867,869,870,971,972,973,974,975,976,977,978,979,980,981,982,993,994,995,997,998,999,1006,1480,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2053,2054,3015,3021,3023,3108,7068,7508,7509,7510,7511,9097],"Lever":[59,83,147,222,291,294,306,308,322,339,390,481,544,574,582,634,649,677,708,1003],"Ladder":[],"Transparent":[56,323,330,400,477,588,620,638,639,866]},"Animated":[554,558,571,590,651,652,654,655],"Defaults":{"Transparent":477,"Lever":34},"ItemFlags":[{"GYM.PHD":{}},{"LEVEL1.PHD":{"Door1":16777345,"Door2":16777346,"Door3":130,"Door4":17,"FallingBlock":512,"WallSwitch":4096,"DartEmitter":17039360,"Dart_H":33816576},"LEVEL2.PHD":{"Door1":17,"Door2":17,"Door4":17,"Door5":16777345,"Door6":16777346,"Trapdoor1":8,"FallingBlock":512,"PushBlock1":1024,"WallSwitch":4096,"UnderwaterSwitch":8192},"LEVEL3A.PHD":{"Door1":17,"WallSwitch":4096},"LEVEL3B.PHD":{"Door1":20,"Door2":20,"Door3":20,"Door4":320,"Door5":17,"Door6":17,"Door8":17,"FallingBlock":512,"PushBlock1":1024,"WallSwitch":4096,"RollingBall":131072}},{"LEVEL4.PHD":{"Door1":17,"Door2":132,"Door3":129,"Door4":17,"Door5":16777345,"Door6":16777346,"Door7":17,"FallingBlock":512,"PushBlock1":1024,"WallSwitch":4096,"UnderwaterSwitch":8192,"RollingBall":131072},"LEVEL5.PHD":{"Door1":33,"Door2":129,"Door5":17,"Door6":130,"Door7":132,"Door8":17,"PushBlock1":1024,"WallSwitch":4096,"RollingBall":131072},"LEVEL6.PHD":{"Door1":17,"Door2":17,"Door3":17,"Door4":17,"Door5":17,"Door6":130,"Door7":129,"FallingBlock":512,"PushBlock1":1024,"PushBlock2":1024,"SlammingDoor":2048,"WallSwitch":4096},"LEVEL7A.PHD":{"Door1":17,"Door2":17,"Door3":17,"Trapdoor1":8,"FallingBlock":512,"PushBlock1":1024,"PushBlock2":1024,"WallSwitch":4096,"UnderwaterSwitch":8192},"LEVEL7B.PHD":{"Door1":17,"Door2":33,"Door3":17,"Door4":129,"Door5":17,"FallingBlock":512,"PushBlock1":1024,"SlammingDoor":2048,"WallSwitch":4096,"UnderwaterSwitch":8192,"DartEmitter":17039360,"Dart_H":33816576}},{"LEVEL8A.PHD":{"Door1":16777233,"Door2":17,"Door3":16777234,"Door4":33554561,"Door5":33554562,"Trapdoor1":8,"PushBlock1":1024,"WallSwitch":4096,"UnderwaterSwitch":8192,"RollingBall":131072},"LEVEL8B.PHD":{"Door1":17,"Door2":17,"Door5":16777345,"Door6":16777346,"PushBlock1":1024,"WallSwitch":4096},"LEVEL8C.PHD":{"Door1":17,"Door3":129,"Door4":132,"Door5":16777345,"Door6":16777346,"PushBlock1":1024,"SlammingDoor":2048,"WallSwitch":4096,"UnderwaterSwitch":8192}},{"LEVEL10A.PHD":{"Door1":17,"Door2":17,"Door3":16777345,"Door4":16777346,"Trapdoor2":8,"FallingBlock":512,"PushBlock1":1024,"PushBlock2":1024,"PushBlock3":1024,"PushBlock4":1024,"WallSwitch":4096,"RollingBall":131072},"LEVEL10B.PHD":{"Door3":130,"Door4":17,"Door5":17,"Door6":17,"Door7":17,"Door8":17,"Trapdoor2":8,"PushBlock1":1024,"SlammingDoor":2048,"WallSwitch":4096,"UnderwaterSwitch":8192,"RollingBall":131072,"DartEmitter":17039360,"Dart_H":33816576},"LEVEL10C.PHD":{"Door1":17,"Door2":17,"FallingBlock":512,"PushBlock1":1024,"SlammingDoor":2048,"WallSwitch":4096,"RollingBall":131072,"DartEmitter":17039360,"Dart_H":33816576}}]} \ No newline at end of file +{"Categories":{"Opaque":[15,17,18,19,20,24,25,27,28,30,31,32,34,36,37,38,39,40,41,42,43,44,45,46,47,48,49,52,53,54,55,57,63,65,66,67,68,69,70,72,73,74,81,82,84,86,87,88,91,92,93,94,95,96,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,121,126,127,128,129,130,131,132,133,134,135,136,137,138,140,143,144,145,146,148,149,150,151,152,153,154,155,156,163,164,165,167,168,173,174,177,178,179,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,200,207,208,210,211,212,214,215,216,217,218,221,230,231,232,233,234,235,237,238,239,241,242,243,244,245,249,250,251,252,253,256,257,258,261,262,263,264,265,266,267,268,269,271,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,292,293,296,297,301,302,303,304,305,307,309,310,311,312,313,314,315,316,320,324,325,326,327,328,329,331,332,335,336,337,338,340,341,342,343,345,346,347,349,350,351,352,353,354,357,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,377,378,379,380,381,382,383,384,385,386,387,388,389,391,392,393,394,395,396,397,401,407,408,409,411,412,413,414,415,416,417,418,419,422,423,424,425,426,427,428,429,430,431,432,433,434,435,438,439,440,441,442,445,446,449,450,451,452,453,455,456,457,459,460,461,463,464,465,466,467,468,469,470,471,472,474,475,476,478,479,480,482,484,485,486,487,488,489,490,491,492,493,494,496,498,499,500,501,502,503,504,505,506,507,510,511,513,514,515,516,519,520,521,522,524,525,526,527,530,532,533,534,535,537,541,542,543,561,562,563,564,565,566,567,568,569,572,573,575,576,577,578,579,580,581,583,584,585,586,587,595,596,597,598,599,600,602,603,604,605,606,607,608,609,610,621,622,623,624,625,626,627,630,631,632,633,635,637,640,641,642,643,645,646,648,650,653,658,660,661,662,663,665,666,668,669,671,672,673,674,676,679,680,681,682,683,684,685,686,688,689,690,691,692,693,694,696,697,698,699,700,701,702,703,704,706,707,709,710,711,714,715,716,717,718,719,721,722,724,725,727,728,729,730,731,732,733,734,735,736,737,738,739,859,1002,1008,1009,1010,1011,1012,1015,2049,2050,2051,2052,3016,3025,3026,3027,3029,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3044,3045,3046,3047,3048,3049,3050,3051,3052,4128,5060,5869,7002,7003,7004,7014,7021,7051,7052,7054,7055,7058,7060],"Fixed":[1,2,60,61,254,255,259,454,509,545,546,547,548,549,550,551,552,553,554,555,556,557,559,560,591,592,611,612,613,614,615,616,617,618,619,659,664,667,670,675,678,687,695,800,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,825,826,827,828,829,833,835,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,861,862,863,864,866,867,869,870,971,972,973,974,975,976,977,978,979,980,981,982,993,994,995,997,998,999,1006,1480,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2053,2054,3015,3021,3023,3108,7068,7508,7509,7510,7511,9097],"Lever":[59,83,147,222,291,294,306,308,322,339,390,481,544,574,582,634,649,677,708,1003],"Ladder":[],"Transparent":[56,323,330,400,477,588,620,638,639,866]},"Animated":[554,558,571,590,651,652,654,655],"Defaults":{"Transparent":477,"Lever":34},"ItemFlags":[{"GYM.PHD":{}},{"LEVEL1.PHD":{"Door1":16777345,"Door2":16777346,"Door3":130,"Door4":17,"FallingBlock":512,"WallSwitch":4096,"DartEmitter":17039360,"Dart_H":33816576},"LEVEL2.PHD":{"Door1":17,"Door2":17,"Door4":17,"Door5":16777345,"Door6":16777346,"Trapdoor1":8,"FallingBlock":512,"PushBlock1":1024,"WallSwitch":4096,"UnderwaterSwitch":8192,"DartEmitter":17039360,"Dart_H":33816576},"LEVEL3A.PHD":{"Door1":17,"WallSwitch":4096},"LEVEL3B.PHD":{"Door1":20,"Door2":20,"Door3":20,"Door4":320,"Door5":17,"Door6":17,"Door8":17,"FallingBlock":512,"PushBlock1":1024,"WallSwitch":4096,"RollingBall":131072}},{"LEVEL4.PHD":{"Door1":17,"Door2":132,"Door3":129,"Door4":17,"Door5":16777345,"Door6":16777346,"Door7":17,"FallingBlock":512,"PushBlock1":1024,"WallSwitch":4096,"UnderwaterSwitch":8192,"RollingBall":131072},"LEVEL5.PHD":{"Door1":33,"Door2":129,"Door5":17,"Door6":130,"Door7":132,"Door8":17,"PushBlock1":1024,"WallSwitch":4096,"RollingBall":131072},"LEVEL6.PHD":{"Door1":17,"Door2":17,"Door3":17,"Door4":17,"Door5":17,"Door6":130,"Door7":129,"FallingBlock":512,"PushBlock1":1024,"PushBlock2":1024,"SlammingDoor":2048,"WallSwitch":4096},"LEVEL7A.PHD":{"Door1":17,"Door2":17,"Door3":17,"Trapdoor1":8,"FallingBlock":512,"PushBlock1":1024,"PushBlock2":1024,"WallSwitch":4096,"UnderwaterSwitch":8192},"LEVEL7B.PHD":{"Door1":17,"Door2":33,"Door3":17,"Door4":129,"Door5":17,"FallingBlock":512,"PushBlock1":1024,"SlammingDoor":2048,"WallSwitch":4096,"UnderwaterSwitch":8192,"DartEmitter":17039360,"Dart_H":33816576}},{"LEVEL8A.PHD":{"Door1":16777233,"Door2":17,"Door3":16777234,"Door4":33554561,"Door5":33554562,"Trapdoor1":8,"PushBlock1":1024,"WallSwitch":4096,"UnderwaterSwitch":8192,"RollingBall":131072},"LEVEL8B.PHD":{"Door1":17,"Door2":17,"Door5":16777345,"Door6":16777346,"PushBlock1":1024,"WallSwitch":4096},"LEVEL8C.PHD":{"Door1":17,"Door3":129,"Door4":132,"Door5":16777345,"Door6":16777346,"PushBlock1":1024,"SlammingDoor":2048,"WallSwitch":4096,"UnderwaterSwitch":8192}},{"LEVEL10A.PHD":{"Door1":17,"Door2":17,"Door3":16777345,"Door4":16777346,"Trapdoor2":8,"FallingBlock":512,"PushBlock1":1024,"PushBlock2":1024,"PushBlock3":1024,"PushBlock4":1024,"WallSwitch":4096,"RollingBall":131072},"LEVEL10B.PHD":{"Door3":130,"Door4":17,"Door5":17,"Door6":17,"Door7":17,"Door8":17,"Trapdoor2":8,"PushBlock1":1024,"SlammingDoor":2048,"WallSwitch":4096,"UnderwaterSwitch":8192,"RollingBall":131072,"DartEmitter":17039360,"Dart_H":33816576},"LEVEL10C.PHD":{"Door1":17,"Door2":17,"FallingBlock":512,"PushBlock1":1024,"SlammingDoor":2048,"WallSwitch":4096,"RollingBall":131072,"DartEmitter":17039360,"Dart_H":33816576}}]} \ No newline at end of file diff --git a/TRRandomizerCore/Resources/TR2/Locations/enemy_relocations.json b/TRRandomizerCore/Resources/TR2/Locations/enemy_relocations.json index 27cf210b..99a89c85 100644 --- a/TRRandomizerCore/Resources/TR2/Locations/enemy_relocations.json +++ b/TRRandomizerCore/Resources/TR2/Locations/enemy_relocations.json @@ -277,6 +277,38 @@ "Room": 42, "EntityIndex": 24, "TargetType": 34 + }, + { + "X": 14848, + "Y": -3072, + "Z": 35328, + "Room": 42, + "EntityIndex": 24, + "TargetType": 46 + }, + { + "X": 14848, + "Y": -3072, + "Z": 35328, + "Room": 42, + "EntityIndex": 24, + "TargetType": 214 + }, + { + "X": 55808, + "Y": 13312, + "Z": 76288, + "Room": 59, + "EntityIndex": 94, + "TargetType": 46 + }, + { + "X": 55808, + "Y": 13312, + "Z": 76288, + "Room": 59, + "EntityIndex": 94, + "TargetType": 214 } ], "BOAT.TR2": [ @@ -693,6 +725,88 @@ "Room": 69, "EntityIndex": 59, "TargetType": 27 + }, + { + "X": 32256, + "Y": 2048, + "Z": 30208, + "Room": 59, + "EntityIndex": 45, + "TargetType": 46 + }, + { + "X": 32256, + "Y": 2048, + "Z": 30208, + "Room": 59, + "EntityIndex": 45, + "TargetType": 214 + }, + { + "X": 25088, + "Y": -2304, + "Z": 53760, + "Room": 84, + "EntityIndex": 36, + "TargetType": 46 + }, + { + "X": 25088, + "Y": -2304, + "Z": 53760, + "Room": 84, + "EntityIndex": 36, + "TargetType": 214 + }, + { + "X": 25088, + "Y": -2304, + "Z": 52736, + "Room": 84, + "EntityIndex": 37, + "TargetType": 46 + }, + { + "X": 25088, + "Y": -2304, + "Z": 52736, + "Room": 84, + "EntityIndex": 37, + "TargetType": 214 + }, + { + "X": 82432, + "Y": 384, + "Z": 62976, + "Room": 130, + "Angle": -32768, + "EntityIndex": 115, + "TargetType": 46 + }, + { + "X": 82432, + "Y": 384, + "Z": 62976, + "Room": 130, + "Angle": -32768, + "EntityIndex": 115, + "TargetType": 214 + }, + { + "X": 68096, + "Y": -896, + "Z": 60928, + "Room": 80, + "EntityIndex": 120, + "TargetType": 46 + }, + { + "X": 68096, + "Y": -896, + "Z": 60928, + "Room": 80, + "EntityIndex": 120, + "TargetType": 214 } ], "VENICE.TR2": [ @@ -879,38 +993,38 @@ "TargetType": 27 }, { - "X": 66559, - "Y": 3072, - "Z": 30208, - "Room": 108, - "Angle": -16384, + "X": 68096, + "Y": -1536, + "Z": 48128, + "Room": 159, + "Angle": -32768, "EntityIndex": 109, "TargetType": 26 }, { - "X": 66559, - "Y": 3072, - "Z": 30208, - "Room": 108, - "Angle": -16384, + "X": 68096, + "Y": -1536, + "Z": 48128, + "Room": 159, + "Angle": -32768, "EntityIndex": 109, "TargetType": 27 }, { - "X": 66559, - "Y": 3072, - "Z": 31232, - "Room": 108, - "Angle": -16384, + "X": 67072, + "Y": -1536, + "Z": 48128, + "Room": 159, + "Angle": -32768, "EntityIndex": 110, "TargetType": 26 }, { - "X": 66559, - "Y": 3072, - "Z": 31232, - "Room": 108, - "Angle": -16384, + "X": 67072, + "Y": -1536, + "Z": 48128, + "Room": 159, + "Angle": -32768, "EntityIndex": 110, "TargetType": 27 }, @@ -1267,70 +1381,382 @@ "TargetType": 27 }, { - "X": 39935, - "Y": 3584, - "Z": 25088, - "Room": 43, - "EntityIndex": 70, - "TargetType": 26 + "X": 39935, + "Y": 3584, + "Z": 25088, + "Room": 43, + "EntityIndex": 70, + "TargetType": 26 + }, + { + "X": 39935, + "Y": 3584, + "Z": 25088, + "Room": 43, + "EntityIndex": 70, + "TargetType": 27 + }, + { + "X": 40448, + "Y": 3584, + "Z": 17408, + "Room": 70, + "Angle": 0, + "EntityIndex": 71, + "TargetType": 26 + }, + { + "X": 40448, + "Y": 3584, + "Z": 17408, + "Room": 70, + "Angle": 0, + "EntityIndex": 71, + "TargetType": 27 + }, + { + "X": 33791, + "Y": 3584, + "Z": 19968, + "Room": 73, + "EntityIndex": 74, + "TargetType": 26 + }, + { + "X": 33791, + "Y": 3584, + "Z": 19968, + "Room": 73, + "EntityIndex": 74, + "TargetType": 27 + }, + { + "X": 33791, + "Y": 1024, + "Z": 22016, + "Room": 130, + "EntityIndex": 124, + "TargetType": 26 + }, + { + "X": 33791, + "Y": 1024, + "Z": 22016, + "Room": 130, + "EntityIndex": 124, + "TargetType": 27 + }, + { + "X": 61952, + "Y": 0, + "Z": 28160, + "Room": 1, + "Angle": 0, + "EntityIndex": 5, + "TargetType": 46 + }, + { + "X": 61952, + "Y": 0, + "Z": 28160, + "Room": 1, + "Angle": 0, + "EntityIndex": 5, + "TargetType": 214 + }, + { + "X": 47616, + "Y": -1024, + "Z": 29184, + "Room": 5, + "Angle": 0, + "EntityIndex": 7, + "TargetType": 46 + }, + { + "X": 47616, + "Y": -1024, + "Z": 29184, + "Room": 5, + "Angle": 0, + "EntityIndex": 7, + "TargetType": 214 + }, + { + "X": 52736, + "Y": -3840, + "Z": 33280, + "Room": 29, + "EntityIndex": 30, + "TargetType": 46 + }, + { + "X": 52736, + "Y": -3840, + "Z": 33280, + "Room": 29, + "EntityIndex": 30, + "TargetType": 214 + }, + { + "X": 52736, + "Y": -3840, + "Z": 33280, + "Room": 29, + "Angle": -16384, + "EntityIndex": 31, + "TargetType": 46 + }, + { + "X": 52736, + "Y": -3840, + "Z": 33280, + "Room": 29, + "Angle": -16384, + "EntityIndex": 31, + "TargetType": 214 + }, + { + "X": 47616, + "Y": -3584, + "Z": 39424, + "Room": 29, + "EntityIndex": 32, + "TargetType": 46 + }, + { + "X": 47616, + "Y": -3584, + "Z": 39424, + "Room": 29, + "EntityIndex": 32, + "TargetType": 214 + }, + { + "X": 47616, + "Y": 4608, + "Z": 26112, + "Room": 41, + "EntityIndex": 64, + "TargetType": 46 + }, + { + "X": 47616, + "Y": 4608, + "Z": 26112, + "Room": 41, + "EntityIndex": 64, + "TargetType": 214 + }, + { + "X": 61952, + "Y": 1920, + "Z": 19968, + "Room": 78, + "EntityIndex": 67, + "TargetType": 46 + }, + { + "X": 61952, + "Y": 1920, + "Z": 19968, + "Room": 78, + "EntityIndex": 67, + "TargetType": 214 + }, + { + "X": 39424, + "Y": 2560, + "Z": 28160, + "Room": 130, + "EntityIndex": 74, + "TargetType": 46 + }, + { + "X": 39424, + "Y": 2560, + "Z": 28160, + "Room": 130, + "EntityIndex": 74, + "TargetType": 214 + }, + { + "X": 66048, + "Y": 4352, + "Z": 22016, + "Room": 85, + "EntityIndex": 86, + "TargetType": 46 + }, + { + "X": 66048, + "Y": 4352, + "Z": 22016, + "Room": 85, + "EntityIndex": 86, + "TargetType": 214 + }, + { + "X": 57856, + "Y": 3584, + "Z": 47616, + "Room": 163, + "EntityIndex": 99, + "TargetType": 46 + }, + { + "X": 57856, + "Y": 3584, + "Z": 47616, + "Room": 163, + "EntityIndex": 99, + "TargetType": 214 + }, + { + "X": 58880, + "Y": 3584, + "Z": 47616, + "Room": 163, + "EntityIndex": 100, + "TargetType": 46 + }, + { + "X": 58880, + "Y": 3584, + "Z": 47616, + "Room": 163, + "EntityIndex": 100, + "TargetType": 214 + } + ], + "OPERA.TR2": [ + { + "X": 64000, + "Y": 7680, + "Z": 39424, + "Room": 105, + "EntityIndex": 8, + "TargetType": 46 + }, + { + "X": 64000, + "Y": 7680, + "Z": 39424, + "Room": 105, + "EntityIndex": 8, + "TargetType": 214 + }, + { + "X": 64000, + "Y": 7680, + "Z": 40448, + "Room": 105, + "EntityIndex": 9, + "TargetType": 46 + }, + { + "X": 64000, + "Y": 7680, + "Z": 40448, + "Room": 105, + "EntityIndex": 9, + "TargetType": 214 + }, + { + "X": 72192, + "Y": 2816, + "Z": 32256, + "Room": 33, + "EntityIndex": 34, + "TargetType": 46 + }, + { + "X": 72192, + "Y": 2816, + "Z": 32256, + "Room": 33, + "EntityIndex": 34, + "TargetType": 214 + }, + { + "X": 77312, + "Y": 7936, + "Z": 40448, + "Room": 44, + "EntityIndex": 103, + "TargetType": 46 + }, + { + "X": 77312, + "Y": 7936, + "Z": 40448, + "Room": 44, + "EntityIndex": 103, + "TargetType": 214 + }, + { + "X": 66048, + "Y": 7680, + "Z": 42496, + "Room": 105, + "EntityIndex": 120, + "TargetType": 46 }, { - "X": 39935, - "Y": 3584, - "Z": 25088, - "Room": 43, - "EntityIndex": 70, - "TargetType": 27 + "X": 66048, + "Y": 7680, + "Z": 42496, + "Room": 105, + "EntityIndex": 120, + "TargetType": 214 }, { - "X": 40448, - "Y": 3584, - "Z": 17408, - "Room": 70, - "Angle": 0, - "EntityIndex": 71, - "TargetType": 26 + "X": 64000, + "Y": 7680, + "Z": 38400, + "Room": 105, + "EntityIndex": 163, + "TargetType": 46 }, { - "X": 40448, - "Y": 3584, - "Z": 17408, - "Room": 70, - "Angle": 0, - "EntityIndex": 71, - "TargetType": 27 + "X": 64000, + "Y": 7680, + "Z": 38400, + "Room": 105, + "EntityIndex": 163, + "TargetType": 214 }, { - "X": 33791, - "Y": 3584, - "Z": 19968, - "Room": 73, - "EntityIndex": 74, - "TargetType": 26 + "X": 64000, + "Y": 7680, + "Z": 41472, + "Room": 105, + "EntityIndex": 211, + "TargetType": 46 }, { - "X": 33791, - "Y": 3584, - "Z": 19968, - "Room": 73, - "EntityIndex": 74, - "TargetType": 27 + "X": 64000, + "Y": 7680, + "Z": 41472, + "Room": 105, + "EntityIndex": 211, + "TargetType": 214 }, { - "X": 33791, - "Y": 1024, - "Z": 22016, - "Room": 130, - "EntityIndex": 124, - "TargetType": 26 + "X": 64000, + "Y": 7680, + "Z": 42496, + "Room": 105, + "EntityIndex": 212, + "TargetType": 46 }, { - "X": 33791, - "Y": 1024, - "Z": 22016, - "Room": 130, - "EntityIndex": 124, - "TargetType": 27 + "X": 64000, + "Y": 7680, + "Z": 42496, + "Room": 105, + "EntityIndex": 212, + "TargetType": 214 } ], "RIG.TR2": [ @@ -1683,6 +2109,30 @@ "Angle": -32768, "EntityIndex": 107, "TargetType": 27 + }, + { + "X": 28160, + "Y": -3840, + "Z": 73216, + "Room": 21, + "EntityIndex": 36, + "TargetType": 214 + }, + { + "X": 34304, + "Y": 2560, + "Z": 58880, + "Room": 101, + "EntityIndex": 109, + "TargetType": 214 + }, + { + "X": 33280, + "Y": 2560, + "Z": 58880, + "Room": 101, + "EntityIndex": 110, + "TargetType": 214 } ], "PLATFORM.TR2": [ @@ -2243,6 +2693,88 @@ "Angle": -16384, "EntityIndex": 125, "TargetType": 27 + }, + { + "X": 41472, + "Y": -768, + "Z": 75264, + "Room": 17, + "EntityIndex": 34, + "TargetType": 46 + }, + { + "X": 41472, + "Y": -768, + "Z": 75264, + "Room": 17, + "EntityIndex": 34, + "TargetType": 214 + }, + { + "X": 60928, + "Y": -3584, + "Z": 78336, + "Room": 30, + "EntityIndex": 51, + "TargetType": 46 + }, + { + "X": 60928, + "Y": -3584, + "Z": 78336, + "Room": 30, + "EntityIndex": 51, + "TargetType": 214 + }, + { + "X": 59904, + "Y": -3584, + "Z": 75264, + "Room": 30, + "Angle": -32768, + "EntityIndex": 59, + "TargetType": 46 + }, + { + "X": 59904, + "Y": -3584, + "Z": 75264, + "Room": 30, + "Angle": -32768, + "EntityIndex": 59, + "TargetType": 214 + }, + { + "X": 65024, + "Y": -3840, + "Z": 70144, + "Room": 30, + "EntityIndex": 61, + "TargetType": 46 + }, + { + "X": 65024, + "Y": -3840, + "Z": 70144, + "Room": 30, + "EntityIndex": 61, + "TargetType": 214 + }, + { + "X": 60928, + "Y": -3840, + "Z": 70144, + "Room": 30, + "EntityIndex": 62, + "TargetType": 46 + }, + { + "X": 60928, + "Y": -3840, + "Z": 70144, + "Room": 30, + "EntityIndex": 62, + "TargetType": 214 } ], "UNWATER.TR2": [ @@ -2401,6 +2933,14 @@ "Angle": -32768, "EntityIndex": 68, "TargetType": 27 + }, + { + "X": 68096, + "Y": -5888, + "Z": 72192, + "Room": 20, + "EntityIndex": 12, + "TargetType": 214 } ], "KEEL.TR2": [ @@ -3048,13 +3588,113 @@ "TargetType": 26 }, { - "X": 61952, - "Y": -1792, - "Z": 31744, - "Room": 19, - "Angle": -32768, - "EntityIndex": 196, - "TargetType": 27 + "X": 61952, + "Y": -1792, + "Z": 31744, + "Room": 19, + "Angle": -32768, + "EntityIndex": 196, + "TargetType": 27 + }, + { + "X": 60928, + "Y": 4608, + "Z": 48640, + "Room": 45, + "EntityIndex": 7, + "TargetType": 46 + }, + { + "X": 60928, + "Y": 4608, + "Z": 48640, + "Room": 45, + "EntityIndex": 7, + "TargetType": 214 + }, + { + "X": 60928, + "Y": 4608, + "Z": 46592, + "Room": 45, + "EntityIndex": 10, + "TargetType": 46 + }, + { + "X": 60928, + "Y": 4608, + "Z": 46592, + "Room": 45, + "EntityIndex": 10, + "TargetType": 214 + }, + { + "X": 59904, + "Y": -4352, + "Z": 34304, + "Room": 21, + "EntityIndex": 30, + "TargetType": 46 + }, + { + "X": 59904, + "Y": -4352, + "Z": 34304, + "Room": 21, + "EntityIndex": 30, + "TargetType": 214 + }, + { + "X": 81408, + "Y": 5120, + "Z": 69120, + "Room": 55, + "EntityIndex": 88, + "TargetType": 46 + }, + { + "X": 81408, + "Y": 5120, + "Z": 69120, + "Room": 55, + "EntityIndex": 88, + "TargetType": 214 + }, + { + "X": 65024, + "Y": 3328, + "Z": 78336, + "Room": 66, + "Angle": 0, + "EntityIndex": 118, + "TargetType": 46 + }, + { + "X": 65024, + "Y": 3328, + "Z": 78336, + "Room": 66, + "Angle": 0, + "EntityIndex": 118, + "TargetType": 214 + }, + { + "X": 58880, + "Y": 3200, + "Z": 29184, + "Room": 94, + "Angle": 0, + "EntityIndex": 184, + "TargetType": 46 + }, + { + "X": 58880, + "Y": 3200, + "Z": 29184, + "Room": 94, + "Angle": 0, + "EntityIndex": 184, + "TargetType": 214 } ], "LIVING.TR2": [ @@ -3409,6 +4049,38 @@ "Angle": -32768, "EntityIndex": 71, "TargetType": 27 + }, + { + "X": 73216, + "Y": 1792, + "Z": 64000, + "Room": 80, + "EntityIndex": 41, + "TargetType": 46 + }, + { + "X": 73216, + "Y": 1792, + "Z": 64000, + "Room": 80, + "EntityIndex": 41, + "TargetType": 214 + }, + { + "X": 55808, + "Y": -2048, + "Z": 44544, + "Room": 21, + "EntityIndex": 43, + "TargetType": 46 + }, + { + "X": 55808, + "Y": -2048, + "Z": 44544, + "Room": 21, + "EntityIndex": 43, + "TargetType": 214 } ], "DECK.TR2": [ @@ -3943,6 +4615,40 @@ "Angle": -32768, "EntityIndex": 104, "TargetType": 27 + }, + { + "X": 51712, + "Y": 5888, + "Z": 49664, + "Room": 17, + "Angle": -16384, + "EntityIndex": 11, + "TargetType": 46 + }, + { + "X": 51712, + "Y": 5888, + "Z": 49664, + "Room": 17, + "Angle": -16384, + "EntityIndex": 11, + "TargetType": 214 + }, + { + "X": 46592, + "Y": -10240, + "Z": 78336, + "Room": 68, + "EntityIndex": 56, + "TargetType": 46 + }, + { + "X": 46592, + "Y": -10240, + "Z": 78336, + "Room": 68, + "EntityIndex": 56, + "TargetType": 214 } ], "SKIDOO.TR2": [ @@ -4517,6 +5223,22 @@ "Room": 132, "EntityIndex": 100, "TargetType": 27 + }, + { + "X": 22016, + "Y": 6912, + "Z": 92672, + "Room": 132, + "EntityIndex": 73, + "TargetType": 46 + }, + { + "X": 22016, + "Y": 6912, + "Z": 92672, + "Room": 132, + "EntityIndex": 73, + "TargetType": 214 } ], "MONASTRY.TR2": [ @@ -4527,6 +5249,54 @@ "Room": 23, "EntityIndex": 54, "TargetType": 34 + }, + { + "X": 60928, + "Y": 0, + "Z": 33280, + "Room": 104, + "EntityIndex": 55, + "TargetType": 46 + }, + { + "X": 60928, + "Y": 0, + "Z": 33280, + "Room": 104, + "EntityIndex": 55, + "TargetType": 214 + }, + { + "X": 46592, + "Y": 0, + "Z": 52736, + "Room": 135, + "EntityIndex": 60, + "TargetType": 46 + }, + { + "X": 46592, + "Y": 0, + "Z": 52736, + "Room": 135, + "EntityIndex": 60, + "TargetType": 214 + }, + { + "X": 46592, + "Y": 0, + "Z": 52736, + "Room": 135, + "EntityIndex": 61, + "TargetType": 46 + }, + { + "X": 46592, + "Y": 0, + "Z": 52736, + "Room": 135, + "EntityIndex": 61, + "TargetType": 214 } ], "CATACOMB.TR2": [ @@ -5109,6 +5879,22 @@ "Angle": -16384, "EntityIndex": 154, "TargetType": 27 + }, + { + "X": 15872, + "Y": 3584, + "Z": 43520, + "Room": 74, + "EntityIndex": 127, + "TargetType": 46 + }, + { + "X": 15872, + "Y": 3584, + "Z": 43520, + "Room": 74, + "EntityIndex": 127, + "TargetType": 214 } ], "ICECAVE.TR2": [ @@ -5391,7 +6177,7 @@ "TargetType": 27 }, { - "X": 72403, + "X": 72659, "Y": -2048, "Z": 65024, "Room": 98, @@ -5400,7 +6186,7 @@ "TargetType": 26 }, { - "X": 72403, + "X": 72659, "Y": -2048, "Z": 65024, "Room": 98, @@ -5477,6 +6263,22 @@ "Angle": 0, "EntityIndex": 137, "TargetType": 27 + }, + { + "X": 67072, + "Y": 7936, + "Z": 69120, + "Room": 45, + "EntityIndex": 119, + "TargetType": 214 + }, + { + "X": 66048, + "Y": 768, + "Z": 65024, + "Room": 98, + "EntityIndex": 132, + "TargetType": 214 } ], "EMPRTOMB.TR2": [ @@ -5967,6 +6769,102 @@ "Room": 41, "EntityIndex": 226, "TargetType": 27 + }, + { + "X": 40448, + "Y": 22784, + "Z": 45568, + "Room": 14, + "EntityIndex": 29, + "TargetType": 46 + }, + { + "X": 40448, + "Y": 22784, + "Z": 45568, + "Room": 14, + "EntityIndex": 29, + "TargetType": 214 + }, + { + "X": 40448, + "Y": 22784, + "Z": 44544, + "Room": 14, + "EntityIndex": 32, + "TargetType": 46 + }, + { + "X": 40448, + "Y": 22784, + "Z": 44544, + "Room": 14, + "EntityIndex": 32, + "TargetType": 214 + }, + { + "X": 45568, + "Y": 14336, + "Z": 9728, + "Room": 35, + "EntityIndex": 50, + "TargetType": 46 + }, + { + "X": 45568, + "Y": 14336, + "Z": 9728, + "Room": 35, + "EntityIndex": 50, + "TargetType": 214 + }, + { + "X": 45568, + "Y": 16384, + "Z": 28160, + "Room": 56, + "EntityIndex": 56, + "TargetType": 46 + }, + { + "X": 45568, + "Y": 16384, + "Z": 28160, + "Room": 56, + "EntityIndex": 56, + "TargetType": 214 + }, + { + "X": 69120, + "Y": 15872, + "Z": 50688, + "Room": 80, + "EntityIndex": 122, + "TargetType": 46 + }, + { + "X": 69120, + "Y": 15872, + "Z": 50688, + "Room": 80, + "EntityIndex": 122, + "TargetType": 214 + }, + { + "X": 35328, + "Y": 18176, + "Z": 53760, + "Room": 104, + "EntityIndex": 174, + "TargetType": 46 + }, + { + "X": 35328, + "Y": 18176, + "Z": 53760, + "Room": 104, + "EntityIndex": 174, + "TargetType": 214 } ], "FLOATING.TR2": [ @@ -6371,6 +7269,54 @@ "Angle": 0, "EntityIndex": 122, "TargetType": 27 + }, + { + "X": 37376, + "Y": -2688, + "Z": 56832, + "Room": 101, + "EntityIndex": 34, + "TargetType": 46 + }, + { + "X": 37376, + "Y": -2688, + "Z": 56832, + "Room": 101, + "EntityIndex": 34, + "TargetType": 214 + }, + { + "X": 37376, + "Y": -2688, + "Z": 57856, + "Room": 101, + "EntityIndex": 35, + "TargetType": 46 + }, + { + "X": 37376, + "Y": -2688, + "Z": 57856, + "Room": 101, + "EntityIndex": 35, + "TargetType": 214 + }, + { + "X": 31232, + "Y": 4352, + "Z": 80384, + "Room": 149, + "EntityIndex": 108, + "TargetType": 46 + }, + { + "X": 31232, + "Y": 4352, + "Z": 80384, + "Room": 149, + "EntityIndex": 108, + "TargetType": 214 } ], "XIAN.TR2": [ diff --git a/TRRandomizerCore/TRRandomizerType.cs b/TRRandomizerCore/TRRandomizerType.cs index ed114f92..c518c176 100644 --- a/TRRandomizerCore/TRRandomizerType.cs +++ b/TRRandomizerCore/TRRandomizerType.cs @@ -66,6 +66,7 @@ public enum TRRandomizerType GameMode, ItemDrops, LevelCount, + BlankTracks, TextureSwap, Wireframe, } diff --git a/TRRandomizerCore/TRVersionSupport.cs b/TRRandomizerCore/TRVersionSupport.cs index 92df3f6c..f928df5f 100644 --- a/TRRandomizerCore/TRVersionSupport.cs +++ b/TRRandomizerCore/TRVersionSupport.cs @@ -10,6 +10,7 @@ internal class TRVersionSupport TRRandomizerType.Ammoless, TRRandomizerType.AtlanteanEggBehaviour, TRRandomizerType.Audio, + TRRandomizerType.BlankTracks, TRRandomizerType.Braid, TRRandomizerType.ChallengeRooms, TRRandomizerType.ClonedEnemies, @@ -60,6 +61,7 @@ internal class TRVersionSupport private static readonly List _tr1RTypes = new() { + TRRandomizerType.AmbientTracks, TRRandomizerType.AtlanteanEggBehaviour, TRRandomizerType.Audio, TRRandomizerType.Enemy, @@ -84,6 +86,7 @@ internal class TRVersionSupport TRRandomizerType.Ammoless, TRRandomizerType.Audio, TRRandomizerType.BirdMonsterBehaviour, + TRRandomizerType.BlankTracks, TRRandomizerType.Braid, TRRandomizerType.DocileBirdMonster, TRRandomizerType.DisableDemos, @@ -125,6 +128,7 @@ internal class TRVersionSupport private static readonly List _tr2RTypes = new() { + TRRandomizerType.AmbientTracks, TRRandomizerType.Audio, TRRandomizerType.BirdMonsterBehaviour, TRRandomizerType.Enemy, @@ -147,6 +151,7 @@ internal class TRVersionSupport TRRandomizerType.AmbientTracks, TRRandomizerType.Ammoless, TRRandomizerType.Audio, + TRRandomizerType.BlankTracks, TRRandomizerType.Braid, TRRandomizerType.DynamicEnemyTextures, TRRandomizerType.Enemy, @@ -186,6 +191,7 @@ internal class TRVersionSupport private static readonly List _tr3RTypes = new() { + TRRandomizerType.AmbientTracks, TRRandomizerType.Audio, TRRandomizerType.Enemy, TRRandomizerType.GlitchedSecrets, diff --git a/TRRandomizerView/App.xaml.cs b/TRRandomizerView/App.xaml.cs index 59c5dfcc..45233524 100644 --- a/TRRandomizerView/App.xaml.cs +++ b/TRRandomizerView/App.xaml.cs @@ -60,9 +60,9 @@ public App() TRRandomizerCoord.Instance.Initialise("TR2Rando", Version, TaggedVersion, new ModificationStamp { - English = "Modified by TRRando", - French = "ModifiƩ par TRRando", - German = "GeƤndert von TRRando" + English = "TRRando", + French = "TRRando", + German = "TRRando" }); } } diff --git a/TRRandomizerView/Model/BoolItemControlClass.cs b/TRRandomizerView/Model/BoolItemControlClass.cs index 26904ba2..9c67337a 100644 --- a/TRRandomizerView/Model/BoolItemControlClass.cs +++ b/TRRandomizerView/Model/BoolItemControlClass.cs @@ -41,8 +41,8 @@ public bool IsActive public string Title { get; set; } public string Description { get; set; } - public string HelpURL { get; set; } - public bool HasHelpURL => HelpURL != null; + public string HelpURL { get; set; } = string.Empty; + public bool HasHelpURL => HelpURL?.Length > 0; public event PropertyChangedEventHandler PropertyChanged; diff --git a/TRRandomizerView/Model/ControllerOptions.cs b/TRRandomizerView/Model/ControllerOptions.cs index 6246cb21..8afb6179 100644 --- a/TRRandomizerView/Model/ControllerOptions.cs +++ b/TRRandomizerView/Model/ControllerOptions.cs @@ -1037,7 +1037,7 @@ private void UpdateItemMode() MaintainKeyContinuity.IsActive = defaultMode; AllowReturnPathLocations.IsActive = !defaultMode || IncludeKeyItems.Value; - AllowEnemyKeyDrops.IsActive = !defaultMode || IncludeKeyItems.Value; + AllowEnemyKeyDrops.IsActive = defaultMode && IncludeKeyItems.Value; FirePropertyChanged(nameof(WeaponDifficultyAvailable)); FirePropertyChanged(nameof(IncludeKeyItemsImplied)); @@ -3535,7 +3535,7 @@ private void IncludeKeyItems_PropertyChanged(object sender, PropertyChangedEvent { bool defaultMode = ItemMode == ItemMode.Default; AllowReturnPathLocations.IsActive = !defaultMode || IncludeKeyItems.Value; - AllowEnemyKeyDrops.IsActive = !defaultMode || IncludeKeyItems.Value; + AllowEnemyKeyDrops.IsActive = defaultMode && IncludeKeyItems.Value; FirePropertyChanged(nameof(IncludeKeyItemsImplied)); } @@ -3554,7 +3554,7 @@ private void AdjustAvailableOptions() _allowGymOutfit.IsAvailable = IsGymOutfitTypeSupported; _changeAmbientTracks.IsAvailable = IsAmbientTracksTypeSupported; - _includeBlankTracks.IsAvailable = IsAmbientTracksTypeSupported; + _includeBlankTracks.IsAvailable = IsBlankTracksTypeSupported; _separateSecretTracks.IsAvailable = IsSecretAudioSupported; _changeWeaponSFX.IsAvailable = _changeCrashSFX.IsAvailable = _changeEnemySFX.IsAvailable = _linkCreatureSFX.IsAvailable = _changeDoorSFX.IsAvailable = IsSFXTypeSupported; @@ -4232,6 +4232,7 @@ public void Unload() public bool IsStartPositionTypeSupported => IsRandomizationSupported(TRRandomizerType.StartPosition); public bool IsAudioTypeSupported => IsRandomizationSupported(TRRandomizerType.Audio); public bool IsAmbientTracksTypeSupported => IsRandomizationSupported(TRRandomizerType.AmbientTracks); + public bool IsBlankTracksTypeSupported => IsRandomizationSupported(TRRandomizerType.BlankTracks); public bool IsSecretAudioSupported => IsRandomizationSupported(TRRandomizerType.SecretAudio); public bool IsSFXTypeSupported => IsRandomizationSupported(TRRandomizerType.SFX); public bool IsVFXTypeSupported => IsRandomizationSupported(TRRandomizerType.VFX); diff --git a/TextureExport/Types/TRRExporter.cs b/TextureExport/Types/TRRExporter.cs index f995c399..f91cee3e 100644 --- a/TextureExport/Types/TRRExporter.cs +++ b/TextureExport/Types/TRRExporter.cs @@ -117,6 +117,8 @@ void WriteInfo(List>> itemFlags [TR1Type.PushBlock1] = TRItemFlags.PushBlock, [TR1Type.WallSwitch] = TRItemFlags.WallSwitch, [TR1Type.UnderwaterSwitch] = TRItemFlags.UnderwaterSwitch, + [TR1Type.DartEmitter] = TRItemFlags.Darts | TRItemFlags.PairA, + [TR1Type.Dart_H] = TRItemFlags.Darts | TRItemFlags.PairB, }, [TR1LevelNames.VALLEY] = new() { diff --git a/USING.md b/USING.md index 885ee9c8..c3a1add5 100644 --- a/USING.md +++ b/USING.md @@ -1,5 +1,23 @@ # Randomizer Setup +On this page: +- [Prerequisites](#prerequisites) + - [TR1](#tr1) + - [TR2](#tr2) + - [TR3](#tr3) + - [TR I-III Remastered](#tr-i-iii-remastered) +- [Installing the Randomizer](#installing-the-randomizer) + - [Game Selection](#game-selection) +- [Randomizing](#randomizing) +- [Playing](#playing) +- [Re-randomizing](#re-randomizing) +- [Old Save Files](#old-save-files) +- [Reverting](#reverting) +- [Troubleshooting](#troubleshooting) + - [.NET Core](#net-core) + - [General Issues](#general-issues) + - [FAQs](#faqs) + To play the randomizer, you will need to have the relevant TR1, TR2 or TR3 game(s) installed on your PC. It is important that the data files for these games are "clean", meaning that they should not have been modified by any other custom tool. If you are in any doubt about this, the first step you should take is reinstalling the game (for example in Steam or GoG). Following is a brief video explanation of the setup, but be sure to read each of the following points as well. @@ -26,11 +44,16 @@ Before you launch the randomizer for the first time, you should carry out a few > _This step is entirely optional based on your own preference of gameplay._ *** -It is recommended at this point that you create a copy of your game folder _if playing classic TR_. If you choose to use the original folder and decide later that you want to revert the changes made by the randomizer, see the [relevant point below](USING.md#reverting). +It is recommended at this point that you create a copy of your game folder. If you choose to use the original folder and decide later that you want to revert the changes made by the randomizer, see the [relevant point below](USING.md#reverting). Let's say you are setting up TR2 and have it installed in `D:\Games\TR2`. You should copy this folder in its entirety and name it something like `D:\Games\TR2Rando`. -For TR I-III Remastered, you will need to point the randomizer to your main installation of TRR, as copying the folder and launching it from a different location will trigger Steam (for example) to launch, which will in turn always run from your main installation folder. This means that you cannot have separate folders setup for different playthroughs. Use the [reverting](USING.md#reverting) guide below to restore your game to defaults once you have finished playing with the randomizer. You can then later re-open and randomize safely if you wish. Note too that some files are shared so if you randomize TR1R, you may for example see some text changes in both TR2R and TR3R as a result. Again, restoring defaults will revert everything back to normal. +### TR I-III Remastered +For TR I-III Remastered, you *may* need to carry out an additional step if using Steam to prevent Steam from always launching the original exe. After creating a copy of your Remastered folder, look for a text file with the name `steam_appid.txt` - if it doesn't exist, create it. Inside this text file, add the app ID, which is `2478970`. + +![TRR App ID](Resources/Using/trr_appid.png) + +Note too that some files are shared so if you randomize TR1R, you may for example see some text changes in both TR2R and TR3R as a result. Use the [reverting](USING.md#reverting) guide below to restore each games' shared text to default if you wish. > ### IMPORTANT > Now that you have a dedicated folder for the randomizer to work on, you should **_not_** change anything manually in this folder as it can cause corruption when randomizing again. Everything can be controlled in the randomizer, so provided that you have set the game up as above per your preferences, you should have no need to edit anything manually. @@ -48,7 +71,7 @@ Setting up the randomizer itself is straight-forward. 3. Launch `TRRandomizer.exe` to begin. ## Game Selection -Click on `Browse` in the initial window and select the **DATA** folder in the TR game folder you wish to randomize. This continues the example above, so we pick `D:\Games\TR2\data`. +Click on `Browse` in the initial window and select the **DATA** folder in the TR game folder you wish to randomize. This continues the example above, so we pick `D:\Games\TR2Rando\data`. ![Folder selection](Resources/Using/firstwindow.png) @@ -64,6 +87,7 @@ Now that you have your TR game folder open in the randomizer, you can select eac - Secrets - Items - Enemies +- Textures - Start positions - Secret rewards (excluding TR2R) - Audio @@ -96,6 +120,8 @@ In the majority of cases, save files that were created in previous runs will not ![Old saves](Resources/Using/deletesaves.png) +Note that for TR I-III Remastered, separating out saves is much more difficult as all games share a single file. You can backup this file manually if you wish to be safe - it is located in, for example, `C:\Users\YOU\AppData\Roaming\TRX\STEAMID\savegame.dat`. + ## Reverting If you wish to restore your game folder to its original state, click on the `Tools` menu and select `Restore To Default`. @@ -128,3 +154,26 @@ If you encounter error messages during randomization, the most likely cause is u 4. Follow this guide carefully from the [beginning](USING.md#randomizer-setup). If you continue to experience issues, we have a friendly community [Discord server](https://discord.gg/f4bUqwgcCN) where you can get help or you can [raise an issue](https://github.com/LostArtefacts/TR-Rando/issues/new) for investigation. + +## FAQs +- _Where is my original game folder?_ + + This can vary depending on which system you used to install the game. + - For Steam, you can right-click on the game in your library and select `Manage` | `Browse Local Files`. This will open the folder where the game files are located in Explorer and you can then copy the address as necessary. + - For GoG, you can find the general installation folder under `Settings` | `Installing, updating` | `Game installation folder`. Browse to this folder in Explorer and then locate your game folder there. + +- _I have installed TR1X but when I open the folder in the randomizer, it can't find the data files. What should I do?_ + + When you install TR1X using its installer and, for example, target your Steam copy of the game, TR1X will be installed by default into your Documents folder as opposed to the original Steam folder. You can change this folder when running the installer. So all you need to do is point the randomizer to this folder instead of your Steam/GOG/original folder. + +- _I have installed TR2Main/tomb3 but when I open the folder in the randomizer, it can't find the data files. What should I do?_ + + TR2Main and tomb3 do not have installers like TR1X, and do not ship with the data files as these need to come from your original game folder. The best way to setup TR2Main/tomb3 is to manually copy your original TR2/TR3 folder, then extract the TR2Main/tomb3 files into that folder, and overwrite when prompted. Then simply point the randomizer to this copied folder. + +- _I am stuck trying to find a key item. How can I locate it?_ + + If you need help trying to locate a key item for progression, download [trview](https://github.com/chreden/trview/releases/latest). Once downloaded, open the level file you are currently playing e.g. `D:\Games\TR2Rando\data\WALL.TR2`. You can then click `Windows` | `Items` and find the item you are missing. In TR1, level files have the extension `.PHD`; in TR2 and TR3, the extension is `.TR2`. + +- _I am stuck trying to obtain/reach a secret. Where can I get help?_ + + Some difficult secrets have been documented on the [TRRando YouTube channel](https://www.youtube.com/@trrandomizer) so you can check if your secret is there for some guidance. If you still need help, post a question in the relevant `secret-help` channel in [Discord](https://discord.gg/f4bUqwgcCN).