From 201d2e99b863ad6ccf86fc3a50e4665bbf0b73c7 Mon Sep 17 00:00:00 2001 From: lahm86 <33758420+lahm86@users.noreply.github.com> Date: Tue, 21 May 2024 09:20:06 +0100 Subject: [PATCH] Expand on TRR file control (#679) Part of #614. --- Deps/TRGE.Coord.dll | Bin 4356608 -> 4356608 bytes Deps/TRGE.Core.dll | Bin 241152 -> 241152 bytes TRLevelControl/Build/TRModelBuilder.cs | 26 +- .../Control/{ => TR1}/TR1LevelControl.cs | 4 +- TRLevelControl/Control/TR1/TR1MapControl.cs | 83 ++++ TRLevelControl/Control/TR1/TR1PDPControl.cs | 13 + .../Control/{ => TR2}/TR2LevelControl.cs | 4 +- TRLevelControl/Control/TR2/TR2MapControl.cs | 119 +++++ TRLevelControl/Control/TR2/TR2PDPControl.cs | 13 + .../Control/{ => TR3}/TR3LevelControl.cs | 4 +- TRLevelControl/Control/TR3/TR3MapControl.cs | 127 +++++ TRLevelControl/Control/TR3/TR3PDPControl.cs | 13 + .../Control/{ => TR4}/TR4LevelControl.cs | 4 +- .../Control/{ => TR5}/TR5LevelControl.cs | 4 +- TRLevelControl/Helpers/DummyMeshProvider.cs | 12 + .../Model/Common/Enums/TRModelDataType.cs | 7 + TRLevelControl/Model/TR1/Enums/TR1RAlias.cs | 165 +++++++ TRLevelControl/Model/TR2/Enums/TR2RAlias.cs | 365 ++++++++++++++ TRLevelControl/Model/TR2/Enums/TR2Type.cs | 2 +- TRLevelControl/Model/TR3/Enums/TR3RAlias.cs | 462 ++++++++++++++++++ TRLevelControl/Model/TR3/Enums/TR3Type.cs | 3 + TRLevelControl/TRMapControlBase.cs | 53 ++ TRLevelControl/TRPDPControlBase.cs | 46 ++ TRLevelControlTests/Base/TestBase.cs | 110 ++++- TRLevelControlTests/TR1/IOTests.cs | 26 +- TRLevelControlTests/TR2/IOTests.cs | 25 +- TRLevelControlTests/TR3/IOTests.cs | 25 +- TRLevelControlTests/TR4/IOTests.cs | 4 +- TRLevelControlTests/TR5/IOTests.cs | 4 +- TRRandomizerCore/Levels/TR1RCombinedLevel.cs | 2 + TRRandomizerCore/Levels/TR2RCombinedLevel.cs | 2 + TRRandomizerCore/Levels/TR3RCombinedLevel.cs | 2 + .../Processors/TR1/TR1RLevelProcessor.cs | 68 ++- .../Processors/TR2/TR2RLevelProcessor.cs | 68 ++- .../Processors/TR3/TR3RLevelProcessor.cs | 68 ++- 35 files changed, 1885 insertions(+), 48 deletions(-) rename TRLevelControl/Control/{ => TR1}/TR1LevelControl.cs (99%) create mode 100644 TRLevelControl/Control/TR1/TR1MapControl.cs create mode 100644 TRLevelControl/Control/TR1/TR1PDPControl.cs rename TRLevelControl/Control/{ => TR2}/TR2LevelControl.cs (99%) create mode 100644 TRLevelControl/Control/TR2/TR2MapControl.cs create mode 100644 TRLevelControl/Control/TR2/TR2PDPControl.cs rename TRLevelControl/Control/{ => TR3}/TR3LevelControl.cs (99%) create mode 100644 TRLevelControl/Control/TR3/TR3MapControl.cs create mode 100644 TRLevelControl/Control/TR3/TR3PDPControl.cs rename TRLevelControl/Control/{ => TR4}/TR4LevelControl.cs (99%) rename TRLevelControl/Control/{ => TR5}/TR5LevelControl.cs (99%) create mode 100644 TRLevelControl/Helpers/DummyMeshProvider.cs create mode 100644 TRLevelControl/Model/Common/Enums/TRModelDataType.cs create mode 100644 TRLevelControl/Model/TR1/Enums/TR1RAlias.cs create mode 100644 TRLevelControl/Model/TR2/Enums/TR2RAlias.cs create mode 100644 TRLevelControl/Model/TR3/Enums/TR3RAlias.cs create mode 100644 TRLevelControl/TRMapControlBase.cs create mode 100644 TRLevelControl/TRPDPControlBase.cs diff --git a/Deps/TRGE.Coord.dll b/Deps/TRGE.Coord.dll index d4dac223cc3b4e0c3ef9dc23a3b7004f275ffecf..690f3dd878a29fc4b5186f334381369b6e69d9d3 100644 GIT binary patch delta 1940 zcmYk-du&r>7{~G7d)A$`bM0w?(E{r(4Azbf*#No8a4V8OIUG;F<1Q7Y7e}jqK@29DRZ%C$j^KkRY4EWwC_*M#DQzjf} z{GqTV#n&>IAMv9!WrubUHS=`c%~DZ|vJ$Q!YAwZTEjA1JaV@J_I|Rof1h?TZ?n&)WU^oivOZv*POe>CIqf`m$BYf+VoSCWOIQ|myqc)XmyjQ~SK zLP19~t-*X89}4+Vf+(q8C}8{``yiq?BlXo7u2!jSLLE|*bDmhDhr=BmOnXT5d?cb0Scv3F?1 z)QmoiS`emUN9zy$l*(Sr7qJ;dJcU; zRp>OTq@-2)7SmNL$t^WAN5y#@lM1>|Yv<7`6u=^yT|i#B{$RE^xx8FHJYZSLXSEBs zD25MMN^+}q5m$x$2&0YE@+!ZhA9D>6Q!6e>m65(cx0GLrn7+hKsYqPJbP0Ea0^+S` z!>>XiKEPOgnosqtJp zh4c?;JHkTS#rExp2nA5Wey5cm>ocDiUPgl)PExwfm(e}ojvcrqXI<>E)`6*O_~X{M z=)^1`eTz;k5DK6*u3ziKTB+}0uzrn-0V}((RnC09tY7QG-;zyAzt)YUwf}E%1r8y7 ziz`SM3Sciwv|hoC0kf-^EoWUcyNZ(oX4lXnXC;cwdJVV#oB8NVaveX*;Yb=@2k2*! zepkT-C^k*MK_JEZ!~P)5o` zB~s5&NtBtgP#R^WY}6oXFg1iqriM~>%0UgIhEpS`6v|1ZQfX8=l|hZ9GO1D2Xex_x zQEn=m8bjq!xzt$dS!x`WN99xFsR`6X>N#o>HJO@1O{Jz$&r{Q>0%`{J0#(>t(@@mg zmS3^{?ccx_6f5*D@t>?1UFu?+Jp4@)H%5O4Q!Xl-E_vDErcItqYx%N_#qqaZ^wf6r z46jSSJ1_ijlV|=|d31cLJjzeL!h4}}XVaUry~ca)N_oxXXWkcHS>YMMs>1J7c!I$^ XL$hVG=SiG$EWg=S>G_id^Ai3ALoXG) delta 1965 zcmZA2drVVj7{~G7ds+^q(w=sRMJYEys8Ti=c-bZl>rAFYCyG;?b9h7J3?@jTi*BW< zbC{WFQ(|XSs&gatGKdxhwR5u!7^ujQcv;N!4>jAuGM6x8%t-c}_q~YF3;pwQqin7}-dPy)aUP)e&vvdg-`BCkB3dgU3&Tm_ zv(Ckqv{oHZ2v{Y@Z9q0kj=S`0jI^Ve4ziUP{h3AH@kxdq)kMiEZ)pdNj+?Y(i-*A& zjubK7IA&L`rHXAHU}p6)By5%ng5g^w?RIx$zWR&@74|*K5gdL?)BS82jaXNv%7;et zBDoRUxjeX@y%1B@1 zu3K;$Bos0p?SDb31xJXod5gMH(Iacy`eG}FM)j;!~!l_yfFjTc~Ft;&l^`s**^ zuuvjbJBjx9qM37043VoYeInFJFX=@*f2ct#&cnQdBKh<;G){op?cs;0hl;X7ruq#ZcKwVQ9>f#Y0Wl(FAw6<cu%}MCpZvOWWcq>|ELwSCJ)F?qf#FRk%jYuAx-SdT4eHt)phw z5fQU8$!fWdd;iVc^iR@Mh){neVEBi4` ztW0IWxPBA~9iz|1PnbJuo7fr-toftVa`HgSlHwzglBR;6 zKTml3uMTfR%cl)3jFKoFrKe&jnTn+hR2*fb#!&H;i850PWudIp3seF%mP(|?Q8p@x z8c$82k|{ftLZwn^R63PGO{6lZENT*!P32GyYBDv2%B7rC9`z#i5;c{|r(UKCs6uKQ zHJzG4&7@wTUZq~6W>G~{G4(oC($>&2dnlTJI9f3bwqTJ&?~;1U8lkZ>uYr)dxP@>hiUjYhBNEQYgR8y503B^G%KY7oYGLH~;_u diff --git a/Deps/TRGE.Core.dll b/Deps/TRGE.Core.dll index 3a087a1e83342f80a745985eab31ee5c9e481fc0..68fa1141c88dc7eec0cbe91b636bb825cf6c206a 100644 GIT binary patch delta 120 zcmZp;!`EhdhXoxgvHDO0vp}e?8rGO?9^a?;peX%`|eIZu$b9P0V=u(CJIu2@ywxU#trTF Pl%pSB+OD;P`5Gqxoc=ug delta 120 zcmZp;!`EbzZR3G+2h08J1$UH||9 diff --git a/TRLevelControl/Build/TRModelBuilder.cs b/TRLevelControl/Build/TRModelBuilder.cs index 5b753e62c..21f6d7d05 100644 --- a/TRLevelControl/Build/TRModelBuilder.cs +++ b/TRLevelControl/Build/TRModelBuilder.cs @@ -8,6 +8,7 @@ public class TRModelBuilder private static readonly ushort _tr5ModelPadding = 0xFFEF; private readonly TRGameVersion _version; + private readonly TRModelDataType _dataType; private readonly ITRLevelObserver _observer; private List _animations; @@ -23,9 +24,10 @@ public class TRModelBuilder private Dictionary _dispatchToAnimMap; private Dictionary _dispatchFrameBase; - public TRModelBuilder(TRGameVersion version, ITRLevelObserver observer = null) + public TRModelBuilder(TRGameVersion version, TRModelDataType dataType, ITRLevelObserver observer = null) { _version = version; + _dataType = dataType; _observer = observer; } @@ -305,6 +307,19 @@ private TRAnimation BuildAnimation(PlaceholderModel placeholderModel, int animIn } } + if (_dataType == TRModelDataType.PDP && _version == TRGameVersion.TR1 && globalAnimIndex < _placeholderAnimations.Count - 1) + { + // TR1 PDP files have an extra frame in Lara's drop-twist-hang animation (46, modern controls). + // Frame start/end mean it's never used in-game, but we capture it for tests. + // Sanity check that the difference is exactly the size of a (TR1) frame. + PlaceholderAnimation nextAnimation = _placeholderAnimations[globalAnimIndex + 1]; + int difference = ((int)nextAnimation.FrameOffset / sizeof(short)) - frameIndex; + if (difference == 10 + 2 * placeholderModel.NumMeshes) + { + animation.Frames.Add(BuildFrame(ref frameIndex, placeholderModel.NumMeshes)); + } + } + return animation; } @@ -536,7 +551,8 @@ private void DeconstructModel(T type, TRModel model) { ID = (uint)(object)type, Animation = model.Animations.Count == 0 ? TRConsts.NoAnimation : (ushort)_placeholderAnimations.Count, - FrameOffset = _observer == null && model.Animations.Count == 0 ? 0 : (uint)_frames.Count * sizeof(short), + FrameOffset = (_dataType == TRModelDataType.PDP || _observer == null) + && model.Animations.Count == 0 ? 0 : (uint)_frames.Count * sizeof(short), NumMeshes = (ushort)model.Meshes.Count, }; _placeholderModels.Add(placeholderModel); @@ -880,11 +896,13 @@ private void WriteModels(TRLevelWriter writer, TRDictionary models) } } - private static TRAngleMode GetMode(TRAnimFrameRotation rot) + private TRAngleMode GetMode(TRAnimFrameRotation rot) { if (rot.X == 0 && rot.Y == 0) { - return TRAngleMode.Z; + // OG TR2+ levels (and TRR levels) use Z here, PDP uses X. Makes no difference + // in game, but keeps tests happy. + return _dataType == TRModelDataType.PDP && rot.Z == 0 ? TRAngleMode.X : TRAngleMode.Z; } if (rot.X == 0 && rot.Z == 0) { diff --git a/TRLevelControl/Control/TR1LevelControl.cs b/TRLevelControl/Control/TR1/TR1LevelControl.cs similarity index 99% rename from TRLevelControl/Control/TR1LevelControl.cs rename to TRLevelControl/Control/TR1/TR1LevelControl.cs index f664727cc..26ce0c1cf 100644 --- a/TRLevelControl/Control/TR1LevelControl.cs +++ b/TRLevelControl/Control/TR1/TR1LevelControl.cs @@ -151,13 +151,13 @@ private void WriteMeshData(TRLevelWriter writer) private void ReadModelData(TRLevelReader reader) { - TRModelBuilder builder = new(TRGameVersion.TR1, _observer); + TRModelBuilder builder = new(TRGameVersion.TR1, TRModelDataType.Level, _observer); _level.Models = builder.ReadModelData(reader, _meshBuilder); } private void WriteModelData(TRLevelWriter writer) { - TRModelBuilder builder = new(TRGameVersion.TR1, _observer); + TRModelBuilder builder = new(TRGameVersion.TR1, TRModelDataType.Level, _observer); builder.WriteModelData(writer, _level.Models); } diff --git a/TRLevelControl/Control/TR1/TR1MapControl.cs b/TRLevelControl/Control/TR1/TR1MapControl.cs new file mode 100644 index 000000000..b2b9d488f --- /dev/null +++ b/TRLevelControl/Control/TR1/TR1MapControl.cs @@ -0,0 +1,83 @@ +using TRLevelControl.Model; + +namespace TRLevelControl; + +public class TR1MapControl : TRMapControlBase +{ + protected override TR1Type ReadKey(string key) + => _keyToTypeMap.ContainsKey(key) ? _keyToTypeMap[key] : default; + + protected override string ConvertKey(TR1Type key) + => _typeToKeyMap[key]; + + private static readonly Dictionary _keyToTypeMap = new() + { + ["DUMMY"] = default, + ["BRIDGE_FLAT"] = TR1Type.BridgeFlat, + ["BRIDGE_TILT1"] = TR1Type.BridgeTilt1, + ["BRIDGE_TILT2"] = TR1Type.BridgeTilt2, + ["DART_EMITTER"] = TR1Type.DartEmitter, + ["DARTS"] = TR1Type.Dart_H, + ["DOOR_TYPE1"] = TR1Type.Door1, + ["DOOR_TYPE2"] = TR1Type.Door2, + ["DOOR_TYPE3"] = TR1Type.Door3, + ["DOOR_TYPE4"] = TR1Type.Door4, + ["DOOR_TYPE5"] = TR1Type.Door5, + ["DOOR_TYPE6"] = TR1Type.Door6, + ["DOOR_TYPE7"] = TR1Type.Door7, + ["DOOR_TYPE8"] = TR1Type.Door8, + ["FALLING_BLOCK"] = TR1Type.FallingBlock, + ["FALLING_CEILING1"] = TR1Type.FallingCeiling1, + ["FALLING_CEILING2"] = TR1Type.FallingCeiling2, + ["KEY_HOLE1"] = TR1Type.Keyhole1, + ["KEY_HOLE2"] = TR1Type.Keyhole2, + ["KEY_HOLE3"] = TR1Type.Keyhole3, + ["KEY_HOLE4"] = TR1Type.Keyhole4, + ["KEY_OPTION1"] = TR1Type.Key1_M_H, + ["KEY_OPTION2"] = TR1Type.Key2_M_H, + ["KEY_OPTION3"] = TR1Type.Key3_M_H, + ["KEY_OPTION4"] = TR1Type.Key4_M_H, + ["LARSON"] = TR1Type.Larson, + ["LAVA_WEDGE"] = TR1Type.AtlanteanLava, + ["LIGHTNING_EMITTER"] = TR1Type.ThorLightning, + ["MOVABLE_BLOCK"] = TR1Type.PushBlock1, + ["MOVABLE_BLOCK2"] = TR1Type.PushBlock2, + ["MOVABLE_BLOCK3"] = TR1Type.PushBlock3, + ["MOVABLE_BLOCK4"] = TR1Type.PushBlock4, + ["MOVING_BAR"] = TR1Type.Barricade, + ["NATLA"] = TR1Type.Natla, + ["PASSPORT_OPTION"] = TR1Type.PassportOpen_M_H, + ["PENDULUM"] = TR1Type.SwingingBlade, + ["PLAYER_1"] = TR1Type.CutsceneActor1, + ["PLAYER_2"] = TR1Type.CutsceneActor2, + ["PLAYER_3"] = TR1Type.CutsceneActor3, + ["PLAYER_4"] = TR1Type.CutsceneActor4, + ["PODS"] = TR1Type.AtlanteanEgg, + ["PUZZLE_DONE1"] = TR1Type.PuzzleDone1, + ["PUZZLE_DONE2"] = TR1Type.PuzzleDone2, + ["PUZZLE_DONE3"] = TR1Type.PuzzleDone3, + ["PUZZLE_DONE4"] = TR1Type.PuzzleDone4, + ["PUZZLE_HOLE1"] = TR1Type.PuzzleHole1, + ["PUZZLE_HOLE2"] = TR1Type.PuzzleHole2, + ["PUZZLE_HOLE3"] = TR1Type.PuzzleHole3, + ["PUZZLE_HOLE4"] = TR1Type.PuzzleHole4, + ["PUZZLE_OPTION1"] = TR1Type.Puzzle1_M_H, + ["PUZZLE_OPTION2"] = TR1Type.Puzzle2_M_H, + ["PUZZLE_OPTION3"] = TR1Type.Puzzle3_M_H, + ["PUZZLE_OPTION4"] = TR1Type.Puzzle4_M_H, + ["ROLLING_BALL"] = TR1Type.RollingBall, + ["SWITCH_TYPE1"] = TR1Type.WallSwitch, + ["SWITCH_TYPE2"] = TR1Type.UnderwaterSwitch, + ["TEETH_TRAP"] = TR1Type.SlammingDoor, + ["TRAPDOOR"] = TR1Type.Trapdoor1, + ["TRAPDOOR2"] = TR1Type.Trapdoor2, + ["WARRIOR3"] = TR1Type.NonShootingAtlantean_N, + }; + + private static readonly Dictionary _typeToKeyMap; + + static TR1MapControl() + { + _typeToKeyMap = _keyToTypeMap.ToDictionary(e => e.Value, e => e.Key); + } +} diff --git a/TRLevelControl/Control/TR1/TR1PDPControl.cs b/TRLevelControl/Control/TR1/TR1PDPControl.cs new file mode 100644 index 000000000..88e5fa4c3 --- /dev/null +++ b/TRLevelControl/Control/TR1/TR1PDPControl.cs @@ -0,0 +1,13 @@ +using TRLevelControl.Build; +using TRLevelControl.Model; + +namespace TRLevelControl; + +public class TR1PDPControl : TRPDPControlBase +{ + public TR1PDPControl(ITRLevelObserver observer = null) + : base(observer) { } + + protected override TRModelBuilder CreateBuilder() + => new(TRGameVersion.TR1, TRModelDataType.PDP); +} diff --git a/TRLevelControl/Control/TR2LevelControl.cs b/TRLevelControl/Control/TR2/TR2LevelControl.cs similarity index 99% rename from TRLevelControl/Control/TR2LevelControl.cs rename to TRLevelControl/Control/TR2/TR2LevelControl.cs index b50e8f2b8..b2e186c79 100644 --- a/TRLevelControl/Control/TR2LevelControl.cs +++ b/TRLevelControl/Control/TR2/TR2LevelControl.cs @@ -168,13 +168,13 @@ private void WriteMeshData(TRLevelWriter writer) private void ReadModelData(TRLevelReader reader) { - TRModelBuilder builder = new(TRGameVersion.TR2, _observer); + TRModelBuilder builder = new(TRGameVersion.TR2, TRModelDataType.Level, _observer); _level.Models = builder.ReadModelData(reader, _meshBuilder); } private void WriteModelData(TRLevelWriter writer) { - TRModelBuilder builder = new(TRGameVersion.TR2, _observer); + TRModelBuilder builder = new(TRGameVersion.TR2, TRModelDataType.Level, _observer); builder.WriteModelData(writer, _level.Models); } diff --git a/TRLevelControl/Control/TR2/TR2MapControl.cs b/TRLevelControl/Control/TR2/TR2MapControl.cs new file mode 100644 index 000000000..4763d823d --- /dev/null +++ b/TRLevelControl/Control/TR2/TR2MapControl.cs @@ -0,0 +1,119 @@ +using TRLevelControl.Model; + +namespace TRLevelControl; + +public class TR2MapControl : TRMapControlBase +{ + protected override TR2Type ReadKey(string key) + => _keyToTypeMap.ContainsKey(key) ? _keyToTypeMap[key] : default; + + protected override string ConvertKey(TR2Type key) + => _typeToKeyMap[key]; + + private static readonly Dictionary _keyToTypeMap = new() + { + ["DUMMY"] = default, + ["ALARM_SOUND"] = TR2Type.DoorBell_N, + ["AVALANCHE"] = TR2Type.BouldersOrSnowballs, + ["BANDIT2"] = TR2Type.Mercenary2, + ["BANDIT2B"] = TR2Type.Mercenary3, + ["BANDIT3"] = TR2Type.Mercenary1, + ["BARACUDDA"] = TR2Type.Barracuda, + ["BIG_SPIDER"] = TR2Type.GiantSpider, + ["BIG_YETI"] = TR2Type.BirdMonster, + ["BLADE"] = TR2Type.WallMountedKnifeBlade, + ["BRIDGE_FLAT"] = TR2Type.BridgeFlat, + ["BRIDGE_TILT1"] = TR2Type.BridgeTilt1, + ["BRIDGE_TILT2"] = TR2Type.BridgeTilt2, + ["CEILING_SPIKES"] = TR2Type.SpikyCeiling, + ["COPTER"] = TR2Type.Helicopter, + ["CULT3"] = TR2Type.ShotgunGoon, + ["DOOR_TYPE1"] = TR2Type.Door1, + ["DOOR_TYPE2"] = TR2Type.Door2, + ["DOOR_TYPE3"] = TR2Type.Door3, + ["DOOR_TYPE4"] = TR2Type.Door4, + ["DOOR_TYPE5"] = TR2Type.Door5, + ["DOOR_TYPE6"] = TR2Type.LiftingDoor1, + ["DOOR_TYPE7"] = TR2Type.LiftingDoor2, + ["DOOR_TYPE8"] = TR2Type.LiftingDoor3, + ["DRAW_BRIDGE"] = TR2Type.Drawbridge, + ["EAGLE"] = TR2Type.Eagle, + ["FALLING_BLOCK"] = TR2Type.FallingBlock, + ["FALLING_CEILING1"] = TR2Type.FallingCeilingOrSandbag, + ["HARPOON_BOLT"] = TR2Type.HarpoonProjectile_H, + ["KEY_HOLE1"] = TR2Type.Keyhole1, + ["KEY_HOLE2"] = TR2Type.Keyhole2, + ["KEY_HOLE3"] = TR2Type.Keyhole3, + ["KEY_HOLE4"] = TR2Type.Keyhole4, + ["KEY_OPTION1"] = TR2Type.Key1_M_H, + ["KEY_OPTION2"] = TR2Type.Key2_M_H, + ["KEY_OPTION3"] = TR2Type.Key3_M_H, + ["KEY_OPTION4"] = TR2Type.Key4_M_H, + ["KILLER_STATUE"] = TR2Type.StatueWithKnifeBlade, + ["MESHSWAP1"] = TR2Type.CutsceneActor1, + ["MESHSWAP2"] = TR2Type.CutsceneActor2, + ["MINI_COPTER"] = TR2Type.Helicopter2, + ["MONK1"] = TR2Type.MonkWithLongStick, + ["MONK2"] = TR2Type.MonkWithKnifeStick, + ["MOVABLE_BLOCK"] = TR2Type.PushBlock1, + ["MOVABLE_BLOCK2"] = TR2Type.PushBlock2, + ["MOVABLE_BLOCK3"] = TR2Type.PushBlock3, + ["MOVABLE_BLOCK4"] = TR2Type.PushBlock4, + ["OILDRUMS"] = TR2Type.RollingStorageDrums, + ["PASSPORT_OPTION"] = TR2Type.PassportOpen_M_H, +        ["PENDULUM"] = TR2Type.SandbagOrBallsack, + ["PICKUP_OPTION1"] = TR2Type.Quest1_M_H, + ["PICKUP_OPTION2"] = TR2Type.Quest2_M_H, + ["PLAYER_1"] = TR2Type.CutsceneActor4, + ["PLAYER_2"] = TR2Type.CutsceneActor5, + ["PLAYER_3"] = TR2Type.CutsceneActor6, + ["PLAYER_5"] = TR2Type.CutsceneActor8, + ["PLAYER_6"] = TR2Type.CutsceneActor9, + ["PLAYER_7"] = TR2Type.CutsceneActor10, + ["PLAYER_8"] = TR2Type.CutsceneActor11, + ["PLAYER4"] = TR2Type.CutsceneActor7, + ["PUSH_SWITCH"] = TR2Type.PushButtonSwitch, + ["PUZZLE_DONE1"] = TR2Type.PuzzleDone1, + ["PUZZLE_DONE2"] = TR2Type.PuzzleDone2, + ["PUZZLE_DONE3"] = TR2Type.PuzzleDone3, + ["PUZZLE_DONE4"] = TR2Type.PuzzleDone4, + ["PUZZLE_HOLE1"] = TR2Type.PuzzleHole1, + ["PUZZLE_HOLE2"] = TR2Type.PuzzleHole2, + ["PUZZLE_HOLE3"] = TR2Type.PuzzleHole3, + ["PUZZLE_HOLE4"] = TR2Type.PuzzleHole4, + ["PUZZLE_OPTION1"] = TR2Type.Puzzle1_M_H, + ["PUZZLE_OPTION2"] = TR2Type.Puzzle2_M_H, + ["PUZZLE_OPTION3"] = TR2Type.Puzzle3_M_H, + ["PUZZLE_OPTION4"] = TR2Type.Puzzle4_M_H, + ["ROCKET"] = TR2Type.GrenadeProjectile_H, + ["ROLLING_BALL"] = TR2Type.RollingBall, + ["SHARK"] = TR2Type.Shark, + ["SKIDMAN"] = TR2Type.MercSnowmobDriver, + ["SKIDOO"] = TR2Type.RedSnowmobile, + ["SMASH_ICE"] = TR2Type.BreakableWindow2, + ["SMASH_WINDOW"] = TR2Type.BreakableWindow1, + ["SPIDER"] = TR2Type.Spider, + ["SPIKE_WALL"] = TR2Type.SpikyWall, + ["SPIKES"] = TR2Type.TeethSpikesOrGlassShards, + ["SPINNING_BLADE"] = TR2Type.RollingSpindle, + ["SPRING_BOARD"] = TR2Type.BouncePad, + ["SWING_BOX"] = TR2Type.SwingingBoxOrBall, + ["SWITCH_TYPE1"] = TR2Type.WallSwitch, + ["SWITCH_TYPE2"] = TR2Type.UnderwaterSwitch, + ["TEETH_TRAP"] = TR2Type.SlammingDoor, + ["TIGER"] = TR2Type.TigerOrSnowLeopard, + ["TRAPDOOR"] = TR2Type.Trapdoor1, + ["TRAPDOOR2"] = TR2Type.Trapdoor2, + ["WORKER1"] = TR2Type.Gunman1, + ["WORKER3"] = TR2Type.StickWieldingGoon1, + ["WORKER4"] = TR2Type.StickWieldingGoon2, + ["YETI"] = TR2Type.Yeti, + }; + + private static readonly Dictionary _typeToKeyMap; + + static TR2MapControl() + { + _typeToKeyMap = _keyToTypeMap.ToDictionary(e => e.Value, e => e.Key); + } +} diff --git a/TRLevelControl/Control/TR2/TR2PDPControl.cs b/TRLevelControl/Control/TR2/TR2PDPControl.cs new file mode 100644 index 000000000..65741d6ce --- /dev/null +++ b/TRLevelControl/Control/TR2/TR2PDPControl.cs @@ -0,0 +1,13 @@ +using TRLevelControl.Build; +using TRLevelControl.Model; + +namespace TRLevelControl; + +public class TR2PDPControl : TRPDPControlBase +{ + public TR2PDPControl(ITRLevelObserver observer = null) + : base(observer) { } + + protected override TRModelBuilder CreateBuilder() + => new(TRGameVersion.TR2, TRModelDataType.PDP); +} diff --git a/TRLevelControl/Control/TR3LevelControl.cs b/TRLevelControl/Control/TR3/TR3LevelControl.cs similarity index 99% rename from TRLevelControl/Control/TR3LevelControl.cs rename to TRLevelControl/Control/TR3/TR3LevelControl.cs index b979debb9..7caa69c2d 100644 --- a/TRLevelControl/Control/TR3LevelControl.cs +++ b/TRLevelControl/Control/TR3/TR3LevelControl.cs @@ -168,13 +168,13 @@ private void WriteMeshData(TRLevelWriter writer) private void ReadModelData(TRLevelReader reader) { - TRModelBuilder builder = new(TRGameVersion.TR3, _observer); + TRModelBuilder builder = new(TRGameVersion.TR3, TRModelDataType.Level, _observer); _level.Models = builder.ReadModelData(reader, _meshBuilder); } private void WriteModelData(TRLevelWriter writer) { - TRModelBuilder builder = new(TRGameVersion.TR3, _observer); + TRModelBuilder builder = new(TRGameVersion.TR3, TRModelDataType.Level, _observer); builder.WriteModelData(writer, _level.Models); } diff --git a/TRLevelControl/Control/TR3/TR3MapControl.cs b/TRLevelControl/Control/TR3/TR3MapControl.cs new file mode 100644 index 000000000..a6595ef4c --- /dev/null +++ b/TRLevelControl/Control/TR3/TR3MapControl.cs @@ -0,0 +1,127 @@ +using TRLevelControl.Model; + +namespace TRLevelControl; + +public class TR3MapControl : TRMapControlBase +{ + protected override TR3Type ReadKey(string key) + => _keyToTypeMap.ContainsKey(key) ? _keyToTypeMap[key] : default; + + protected override string ConvertKey(TR3Type key) + => _typeToKeyMap[key]; + + private static readonly Dictionary _keyToTypeMap = new() + { + ["DUMMY"] = default, + ["AIRLOCK_SWITCH"] = TR3Type.ValveWheelOrPulley, + ["ANIMATING1"] = TR3Type.Animating1, + ["ANIMATING2"] = TR3Type.Animating2, + ["ANIMATING3"] = TR3Type.Animating3, + ["ANIMATING4"] = TR3Type.Animating4, + ["ANIMATING5"] = TR3Type.Animating5, + ["ANIMATING6"] = TR3Type.Animating6, + ["BIG_ROLLING_BALL"] = TR3Type.GiantBoulder, + ["BLADE"] = TR3Type.CircularBlade, + ["BRIDGE_FLAT"] = TR3Type.BridgeFlat, + ["BRIDGE_TILT1"] = TR3Type.BridgeTilt1, + ["BRIDGE_TILT2"] = TR3Type.BridgeTilt2, + ["CEILING_SPIKES"] = TR3Type.SpikyVertWallOrTunnelBorer, + ["COBRA"] = TR3Type.Cobra, + ["CROCODILE"] = TR3Type.Croc, + ["DIVER"] = TR3Type.ScubaSteve, + ["DOG"] = TR3Type.Dog, + ["DOOR_TYPE1"] = TR3Type.Door1, + ["DOOR_TYPE2"] = TR3Type.Door2, + ["DOOR_TYPE3"] = TR3Type.Door3, + ["DOOR_TYPE4"] = TR3Type.Door4, + ["DOOR_TYPE5"] = TR3Type.Door5, + ["DOOR_TYPE6"] = TR3Type.Door6, + ["DOOR_TYPE7"] = TR3Type.Door7, + ["DOOR_TYPE8"] = TR3Type.Door8, + ["EXTRAFX6"] = TR3Type.ElectricalSwitchBox, + ["FALLING_BLOCK"] = TR3Type.FallingBlock, + ["FALLING_CEILING1"] = TR3Type.FallingCeiling, + ["FAN"] = TR3Type.DamagingAnimating1, + ["FIREHEAD"] = TR3Type.FireBreathingDragonStatue, + ["ICICLES"] = TR3Type.DetachableStalactites, + ["ICON_PICKUP1_ITEM"] = TR3Type.Infada_P, + ["ICON_PICKUP1_OPTION"] = TR3Type.Infada_M_H, + ["KEY_HOLE1"] = TR3Type.Keyhole1, + ["KEY_HOLE2"] = TR3Type.Keyhole2, + ["KEY_HOLE3"] = TR3Type.Keyhole3, + ["KEY_HOLE4"] = TR3Type.Keyhole4, + ["KEY_ITEM1"] = TR3Type.Key1_P, + ["KEY_ITEM2"] = TR3Type.Key2_P, + ["KEY_ITEM3"] = TR3Type.Key3_P, + ["KEY_ITEM4"] = TR3Type.Key4_P, + ["KEY_OPTION1"] = TR3Type.Key1_M_H, + ["KEY_OPTION2"] = TR3Type.Key2_M_H, + ["KEY_OPTION3"] = TR3Type.Key3_M_H, + ["KEY_OPTION4"] = TR3Type.Key4_M_H, + ["LIZARD_MAN"] = TR3Type.LizardMan, + ["LON_MERCENARY1"] = TR3Type.LondonMerc, + ["MONKEY"] = TR3Type.Monkey, + ["MOVABLE_BLOCK"] = TR3Type.PushableBlock1, + ["MOVABLE_BLOCK2"] = TR3Type.PushableBlock2, + ["MP1"] = TR3Type.MPWithStick, + ["PASSPORT_OPTION"] = TR3Type.PassportOpening_H, + ["PENDULUM"] = TR3Type.SwingingThing, + ["PICKUP_ITEM1"] = TR3Type.Quest1_P, + ["PICKUP_OPTION1"] = TR3Type.Quest1_M_H, + ["PLAYER_1"] = TR3Type.CutsceneActor1, + ["PLAYER_2"] = TR3Type.CutsceneActor2, + ["PLAYER_3"] = TR3Type.CutsceneActor3, + ["PLAYER4"] = TR3Type.CutsceneActor4, + ["PLAYER_4"] = TR3Type.CutsceneActor_4, + ["PLAYER_5"] = TR3Type.CutsceneActor5, + ["PLAYER_6"] = TR3Type.CutsceneActor6, + ["PLAYER_7"] = TR3Type.CutsceneActor7, + ["PLAYER_8"] = TR3Type.CutsceneActor8, + ["PLAYER_9"] = TR3Type.CutsceneActor9, + ["PUNK1"] = TR3Type.Punk, + ["PUSH_SWITCH"] = TR3Type.PushButtonSwitch, + ["PUZZLE_DONE1"] = TR3Type.Slot1Full, + ["PUZZLE_DONE2"] = TR3Type.Slot2Full, + ["PUZZLE_DONE3"] = TR3Type.Slot3Full, + ["PUZZLE_DONE4"] = TR3Type.Slot4Full, + ["PUZZLE_HOLE1"] = TR3Type.Slot1Empty, + ["PUZZLE_HOLE2"] = TR3Type.Slot2Empty, + ["PUZZLE_HOLE3"] = TR3Type.Slot3Empty, + ["PUZZLE_HOLE4"] = TR3Type.Slot4Empty, + ["PUZZLE_ITEM1"] = TR3Type.Puzzle1_P, + ["PUZZLE_ITEM2"] = TR3Type.Puzzle2_P, + ["PUZZLE_ITEM3"] = TR3Type.Puzzle3_P, + ["PUZZLE_ITEM4"] = TR3Type.Puzzle4_P, + ["PUZZLE_OPTION1"] = TR3Type.Puzzle1_M_H, + ["PUZZLE_OPTION2"] = TR3Type.Puzzle2_M_H, + ["PUZZLE_OPTION3"] = TR3Type.Puzzle3_M_H, + ["PUZZLE_OPTION4"] = TR3Type.Puzzle4_M_H, + ["QUADBIKE"] = TR3Type.Quad, + ["ROLLING_BALL"] = TR3Type.RollingBallOrBarrel, + ["SECURITY_GUARD"] = TR3Type.LondonGuard, + ["SMALL_SWITCH"] = TR3Type.SmallWallSwitch, + ["SMASH_WINDOW"] = TR3Type.DestroyableBoardedUpWindow, + ["SPIKE_WALL"] = TR3Type.SpikyWall, + ["SPIKES"] = TR3Type.TeethSpikesOrBarbedWire, + ["STROBE_LIGHT"] = TR3Type.AlarmLight, + ["SWING_BOX"] = TR3Type.DamagingAnimating3, + ["SWITCH_TYPE1"] = TR3Type.WallSwitch, + ["SWITCH_TYPE2"] = TR3Type.UnderwaterSwitch, + ["TEETH_TRAP"] = TR3Type.SkeletonTrapOrSlammingDoor, + ["TIGER"] = TR3Type.Tiger, + ["TRAIN"] = TR3Type.SubwayTrain, + ["TRAPDOOR"] = TR3Type.Trapdoor1, + ["TRAPDOOR2"] = TR3Type.Trapdoor2, + ["TRIBEAXE"] = TR3Type.TribesmanAxe, + ["VEHICLE_ANIM"] = TR3Type.LaraVehicleAnimation_H, + ["VULTURE"] = TR3Type.Vulture, + ["WHALE"] = TR3Type.KillerWhale, + }; + + private static readonly Dictionary _typeToKeyMap; + + static TR3MapControl() + { + _typeToKeyMap = _keyToTypeMap.ToDictionary(e => e.Value, e => e.Key); + } +} diff --git a/TRLevelControl/Control/TR3/TR3PDPControl.cs b/TRLevelControl/Control/TR3/TR3PDPControl.cs new file mode 100644 index 000000000..dadd8e0d7 --- /dev/null +++ b/TRLevelControl/Control/TR3/TR3PDPControl.cs @@ -0,0 +1,13 @@ +using TRLevelControl.Build; +using TRLevelControl.Model; + +namespace TRLevelControl; + +public class TR3PDPControl : TRPDPControlBase +{ + public TR3PDPControl(ITRLevelObserver observer = null) + : base(observer) { } + + protected override TRModelBuilder CreateBuilder() + => new(TRGameVersion.TR3, TRModelDataType.PDP); +} diff --git a/TRLevelControl/Control/TR4LevelControl.cs b/TRLevelControl/Control/TR4/TR4LevelControl.cs similarity index 99% rename from TRLevelControl/Control/TR4LevelControl.cs rename to TRLevelControl/Control/TR4/TR4LevelControl.cs index 8b2b20ec7..d726ec7af 100644 --- a/TRLevelControl/Control/TR4LevelControl.cs +++ b/TRLevelControl/Control/TR4/TR4LevelControl.cs @@ -200,13 +200,13 @@ private void WriteMeshData(TRLevelWriter writer) private void ReadModelData(TRLevelReader reader) { - TRModelBuilder builder = new(TRGameVersion.TR4, _observer); + TRModelBuilder builder = new(TRGameVersion.TR4, TRModelDataType.Level, _observer); _level.Models = builder.ReadModelData(reader, _meshBuilder); } private void WriteModelData(TRLevelWriter writer) { - TRModelBuilder builder = new(TRGameVersion.TR4, _observer); + TRModelBuilder builder = new(TRGameVersion.TR4, TRModelDataType.Level, _observer); builder.WriteModelData(writer, _level.Models); } diff --git a/TRLevelControl/Control/TR5LevelControl.cs b/TRLevelControl/Control/TR5/TR5LevelControl.cs similarity index 99% rename from TRLevelControl/Control/TR5LevelControl.cs rename to TRLevelControl/Control/TR5/TR5LevelControl.cs index a9410f2fc..9963ae8c4 100644 --- a/TRLevelControl/Control/TR5LevelControl.cs +++ b/TRLevelControl/Control/TR5/TR5LevelControl.cs @@ -257,13 +257,13 @@ private void WriteMeshData(TRLevelWriter writer) private void ReadModelData(TRLevelReader reader) { - TRModelBuilder builder = new(TRGameVersion.TR5, _observer); + TRModelBuilder builder = new(TRGameVersion.TR5, TRModelDataType.Level, _observer); _level.Models = builder.ReadModelData(reader, _meshBuilder); } private void WriteModelData(TRLevelWriter writer) { - TRModelBuilder builder = new(TRGameVersion.TR5, _observer); + TRModelBuilder builder = new(TRGameVersion.TR5, TRModelDataType.Level, _observer); builder.WriteModelData(writer, _level.Models); } diff --git a/TRLevelControl/Helpers/DummyMeshProvider.cs b/TRLevelControl/Helpers/DummyMeshProvider.cs new file mode 100644 index 000000000..0af256f6e --- /dev/null +++ b/TRLevelControl/Helpers/DummyMeshProvider.cs @@ -0,0 +1,12 @@ +using TRLevelControl.Build; +using TRLevelControl.Model; + +namespace TRLevelControl.Helpers; + +public class DummyMeshProvider : IMeshProvider +{ + private static readonly TRMesh _dummy = new(); + + public TRMesh GetObjectMesh(long pointer) + => _dummy; +} diff --git a/TRLevelControl/Model/Common/Enums/TRModelDataType.cs b/TRLevelControl/Model/Common/Enums/TRModelDataType.cs new file mode 100644 index 000000000..42124db98 --- /dev/null +++ b/TRLevelControl/Model/Common/Enums/TRModelDataType.cs @@ -0,0 +1,7 @@ +namespace TRLevelControl.Model; + +public enum TRModelDataType +{ + Level = 0, + PDP = 1, +} diff --git a/TRLevelControl/Model/TR1/Enums/TR1RAlias.cs b/TRLevelControl/Model/TR1/Enums/TR1RAlias.cs new file mode 100644 index 000000000..400d6edb0 --- /dev/null +++ b/TRLevelControl/Model/TR1/Enums/TR1RAlias.cs @@ -0,0 +1,165 @@ +namespace TRLevelControl.Model; + +public enum TR1RAlias +{ + DUMMY, + BIG_POD, + DART_EMITTER_10B_10C, + DART_EMITTER_7B, + DARTS_10B_10C, + DARTS_7B, + DOOR_1, + DOOR_10, + DOOR_11, + DOOR_12, + DOOR_13, + DOOR_14, + DOOR_15, + DOOR_15R, + DOOR_16, + DOOR_17, + DOOR_18, + DOOR_19, + DOOR_1R, + DOOR_2, + DOOR_20, + DOOR_21, + DOOR_22, + DOOR_23, + DOOR_24, + DOOR_25, + DOOR_25R, + DOOR_26, + DOOR_27, + DOOR_28, + DOOR_29, + DOOR_3, + DOOR_30, + DOOR_31, + DOOR_32, + DOOR_33, + DOOR_33R, + DOOR_34, + DOOR_35, + DOOR_35R, + DOOR_36, + DOOR_37, + DOOR_38, + DOOR_39, + DOOR_4, + DOOR_40, + DOOR_41, + DOOR_5, + DOOR_6, + DOOR_7, + DOOR_8R, + DOOR_9, + FALLING_BLOCK_10A, + FALLING_BLOCK_10C, + FALLING_BLOCK_3B, + FALLING_BLOCK_4_5_6, + FALLING_BLOCK_7A, + FALLING_BLOCK_7B, + FALLING_CEILING1_3B, + KEY_HOLE1_2, + KEY_HOLE1_4, + KEY_HOLE1_5, + KEY_HOLE1_7A_7B, + KEY_HOLE1_8A_8B_8C, + KEY_HOLE2_4, + KEY_HOLE2_7A_7B, + KEY_HOLE3_4, + KEY_HOLE3_7A_7B, + KEY_HOLE4_4, + KEY_OPTION1_2, + KEY_OPTION1_4, + KEY_OPTION1_7A_7B, + KEY_OPTION1_8A_8B_8C, + KEY_OPTION2_4, + KEY_OPTION2_7A_7B, + KEY_OPTION3_4, + KEY_OPTION3_7A_7B, + KEY_OPTION4_4, + LARSON_EGYPT, + LAVA_WEDGE_10B_10C, + LIGHTNING_EMITTER_10C, + LIGHTNING_EMITTER_4, + MOVABLE_BLOCK_10A, + MOVABLE_BLOCK_10B_10C, + MOVABLE_BLOCK_2, + MOVABLE_BLOCK_3B, + MOVABLE_BLOCK_4, + MOVABLE_BLOCK_4_5_6, + MOVABLE_BLOCK_7A_7B, + MOVABLE_BLOCK_8A_8B_8C, + MOVABLE_BLOCK2_10A, + MOVABLE_BLOCK2_7A, + MOVABLE_BLOCK3, + MOVING_BAR_10A, + MOVING_BAR_4, + NATLA_MUTANT, + PASSPORT_OPTION_GYM, + PENDULUM_10C, + PLAYER_2_CUT1, + PLAYER_2_CUT3, + PLAYER4, + PUZZLE_DONE1_2, + PUZZLE_DONE1_3A_3B, + PUZZLE_DONE1_6, + PUZZLE_DONE1_8A_8B, + PUZZLE_DONE1_8C, + PUZZLE_DONE1_LEVEL10A, + PUZZLE_DONE2_8A_8B, + PUZZLE_DONE2_8C, + PUZZLE_DONE2_LEVEL10A, + PUZZLE_DONE3_8A_8B, + PUZZLE_DONE4_8A_8B, + PUZZLE_HOLE1_2, + PUZZLE_HOLE1_3A_3B, + PUZZLE_HOLE1_6, + PUZZLE_HOLE1_8A_8B, + PUZZLE_HOLE1_8C, + PUZZLE_HOLE1_LEVEL10A, + PUZZLE_HOLE2_8A_8B, + PUZZLE_HOLE2_8C, + PUZZLE_HOLE2_LEVEL10A, + PUZZLE_HOLE3_8A_8B, + PUZZLE_HOLE4_8A_8B, + PUZZLE_OPTION1_2, + PUZZLE_OPTION1_3A_3B, + PUZZLE_OPTION1_6, + PUZZLE_OPTION1_8A_8B, + PUZZLE_OPTION1_8C, + PUZZLE_OPTION1_LEVEL10A, + PUZZLE_OPTION2_8A_8B, + PUZZLE_OPTION2_8C, + PUZZLE_OPTION2_LEVEL10A, + PUZZLE_OPTION3_8A_8B, + PUZZLE_OPTION4_8A_8B, + ROLLING_BALL_3B, + ROLLING_BALL_4_7B, + ROLLING_BALL_5, + ROLLING_BALL_8A, + SCION_HOLDER, + SWITCH_TYPE1_10A, + SWITCH_TYPE1_10B_10C, + SWITCH_TYPE1_4_7A_7B, + SWITCH_TYPE1_5_6, + SWITCH_TYPE1_8A_8B_8C, + SWITCH_TYPE2_10B, + SWITCH_TYPE2_2, + SWITCH_TYPE2_4, + SWITCH_TYPE2_7A_7B, + SWITCH_TYPE2_8A_8C, + SWITCH_TYPE2_EGYPT, + TEETH_TRAP_10B_10C, + TEETH_TRAP_7B, + TEETH_TRAP_8C, + TRAPDOOR_2_7A, + TRAPDOOR_4, + TRAPDOOR_8A, + TRAPDOOR_END, + TRAPDOOR2_10A, + TRAPDOOR2_10B_10C, + WARRIOR2, +} diff --git a/TRLevelControl/Model/TR2/Enums/TR2RAlias.cs b/TRLevelControl/Model/TR2/Enums/TR2RAlias.cs new file mode 100644 index 000000000..f66ef7262 --- /dev/null +++ b/TRLevelControl/Model/TR2/Enums/TR2RAlias.cs @@ -0,0 +1,365 @@ +namespace TRLevelControl.Model; + +public enum TR2RAlias +{ + DUMMY, + AVALANCHE_OPERA, + BANDIT2_1_3_4, + BANDIT2B_1, + BANDIT3_GM, + BARACUDDA_DECK_LIVING_KEEL_UNWATER, + BARACUDDA_EMPRTOMB, + BARACUDDA_ICECAVE_CATACOMB, + BIG_SPIDER_3, + BIG_YETI_4_5, + BLADE_EMPRTOMB, + BLADE_FLOATING_VENICE, + BLADE_MONASTRY, + BLADE_WALL, + BRIDGE_FLAT_EMPRTOMB, + CEILING_SPIKES_EMPRTOMB, + COPTER_PLATFORM, + CULT3_HOUSE, + CULT3_OPERA, + DOOR_1, + DOOR_10, + DOOR_10R, + DOOR_11, + DOOR_12, + DOOR_13, + DOOR_14, + DOOR_15, + DOOR_16, + DOOR_17, + DOOR_18, + DOOR_19, + DOOR_19R, + DOOR_1R, + DOOR_2, + DOOR_20, + DOOR_21, + DOOR_22, + DOOR_24, + DOOR_26, + DOOR_27, + DOOR_28, + DOOR_29, + DOOR_29R, + DOOR_2R, + DOOR_3, + DOOR_30, + DOOR_30R, + DOOR_31, + DOOR_32, + DOOR_33, + DOOR_34, + DOOR_35, + DOOR_36, + DOOR_37, + DOOR_38, + DOOR_39, + DOOR_4, + DOOR_40, + DOOR_41, + DOOR_42, + DOOR_43, + DOOR_44, + DOOR_45, + DOOR_46, + DOOR_46R, + DOOR_47, + DOOR_48, + DOOR_49, + DOOR_5, + DOOR_50, + DOOR_50R, + DOOR_51, + DOOR_52, + DOOR_53, + DOOR_54, + DOOR_54R, + DOOR_55, + DOOR_5R, + DOOR_6, + DOOR_7, + DOOR_7R, + DOOR_8, + DOOR_9, + DOOR_9R, + DOOR_DRAWING, + DOOR_GOLDFACE, + DOOR_GOLDSEAL, + DOOR_GOLDSEAL_R, + DOOR_GOLDTALL, + DOOR_KING, + DOOR_RUSTY, + DOOR_SOVIET, + DOOR_SOVIET_R, + DOOR_STALIN, + DOOR_TYPE2_HOUSE, + DOOR_WOODEN, + DRAW_BRIDGE_FLOATING, + DRAW_BRIDGE_OPERA, + EAGLE_GM, + FALLING_BLOCK_CATACOMB, + FALLING_BLOCK_DECK_LIVING, + FALLING_BLOCK_EMPRTOMB, + FALLING_BLOCK_GM, + FALLING_BLOCK_GM_LEVEL3, + FALLING_BLOCK_KEEL, + FALLING_BLOCK_WALL, + FALLING_CEILING1_OPERA, + FALLING_CEILING1_XIAN, + KEY_HOLE_BLUE1, + KEY_HOLE_BLUE2, + KEY_HOLE_BOAT, + KEY_HOLE_GOLD, + KEY_HOLE_IRON, + KEY_HOLE_LIVING_DECK, + KEY_HOLE_RUSTY, + KEY_HOLE_RUSTY2, + KEY_HOLE_SNOW, + KEY_HOLE_STEEL, + KEY_HOLE1_LEVEL2, + KEY_HOLE1_MONASTRY, + KEY_HOLE1_RIG, + KEY_HOLE2_EMPRTOMB, + KEY_HOLE2_MONASTRY, + KEY_HOLE2_RIG, + KEY_HOLE3_EMPRTOMB, + KEY_HOLE3_MONASTRY, + KEY_HOLE3_RIG, + KEY_HOLE4_EMPRTOMB, + KEY_HOLE4_LEVEL2, + KEY_HOLE4_MONASTRY, + KEY_HOLE4_PLATFORM, + KEY_OPTION1_BOAT, + KEY_OPTION1_HOUSE, + KEY_OPTION1_KEEL, + KEY_OPTION1_LEVEL2, + KEY_OPTION1_LIVING, + KEY_OPTION1_MONASTRY, + KEY_OPTION1_OPERA, + KEY_OPTION1_PLATFORM, + KEY_OPTION1_RIG, + KEY_OPTION1_SKIDOO, + KEY_OPTION1_VENICE, + KEY_OPTION1_WALL, + KEY_OPTION2_DECK, + KEY_OPTION2_EMPRTOMB, + KEY_OPTION2_ICECAVE, + KEY_OPTION2_KEEL, + KEY_OPTION2_LIVING, + KEY_OPTION2_MONASTRY, + KEY_OPTION2_RIG, + KEY_OPTION2_SKIDOO, + KEY_OPTION2_VENICE, + KEY_OPTION2_WALL, + KEY_OPTION3_DECK, + KEY_OPTION3_EMPRTOMB, + KEY_OPTION3_KEEL, + KEY_OPTION3_MONASTRY, + KEY_OPTION3_RIG, + KEY_OPTION4_DECK, + KEY_OPTION4_EMPRTOMB, + KEY_OPTION4_LEVEL2, + KEY_OPTION4_MONASTRY, + KEY_OPTION4_PLATFORM, + KILLER_STATUE_EMPRTOMB, + KILLER_STATUE_VENICE, + MINI_COPTER_GM_LEVEL1, + MINI_COPTER_WALL, + MONK1_1, + MONK2_4, + MOVABLE_BLOCK_DECK_LIVING, + MOVABLE_BLOCK_EMPRTOMB, + MOVABLE_BLOCK_FLOATING, + MOVABLE_BLOCK_ICECAVE_CATACOMB, + MOVABLE_BLOCK_LEVEL2, + MOVABLE_BLOCK_LEVEL3, + MOVABLE_BLOCK_LEVEL4, + MOVABLE_BLOCK_LEVEL5, + MOVABLE_BLOCK_MONASTRY, + MOVABLE_BLOCK_OPERA, + MOVABLE_BLOCK_PLATFORM_RIG, + MOVABLE_BLOCK_SKIDOO, + MOVABLE_BLOCK_UNWATER, + MOVABLE_BLOCK_VENICE, + MOVABLE_BLOCK_WALL, + MOVABLE_BLOCK2_EMPRTOMB, + MOVABLE_BLOCK2_KEEL, + MOVABLE_BLOCK2_MONASTRY, + MOVABLE_BLOCK2_VENICE, + MOVABLE_BLOCK3, + MOVABLE_BLOCK4, + OILDRUMS_LEVEL2, + OILDRUMS_LIVING_KEEL, + OILDRUMS_PLATFORM_RIG, + PASSPORT_OPTION_GYM, + PENDULUM_MONASTRY, + PENDULUM_OPERA, + PICKUP_OPTION1_CATACOMB, + PICKUP_OPTION2_ICECAVE, + PLAYER_1_CUT1, + PLAYER_1_CUT3, + PLAYER_2_CUT2, + PLAYER_2_CUT4, + PLAYER_3_CUT1, + PLAYER_3_CUT2, + PLAYER_3_CUT3, + PLAYER_3_CUT4, + PLAYER_5_CUT1, + PLAYER_5_CUT2, + PLAYER_5_CUT3, + PLAYER_5_CUT4, + PLAYER_6_CUT2, + PLAYER_6_CUT3, + PLAYER_6_CUT4, + PLAYER_7_CUT2, + PLAYER_7_CUT4, + PLAYER_8_CUT2, + PLAYER4_CUT1, + PLAYER4_CUT2, + PUSH_SWITCH_EMPRTOMB, + PUSH_SWITCH_FLOATING, + PUSH_SWITCH_KEEL, + PUSH_SWITCH_LIVING, + PUSH_SWITCH_MONASTRY, + PUZZLE_DONE1_CATACOMB, + PUZZLE_DONE1_EMPRTOMB, + PUZZLE_DONE1_FLOATING, + PUZZLE_DONE1_ICECAVE, + PUZZLE_DONE1_KEEL, + PUZZLE_DONE1_LEVEL4, + PUZZLE_DONE1_MONASTRY, + PUZZLE_DONE1_OPERA, + PUZZLE_DONE1_PLATFORM, + PUZZLE_DONE1_XIAN, + PUZZLE_DONE2_FLOATING, + PUZZLE_DONE2_LEVEL3, + PUZZLE_DONE2_MONASTRY, + PUZZLE_DONE2_OPERA, + PUZZLE_DONE4_MONASTRY, + PUZZLE_HOLE1_CATACOMB, + PUZZLE_HOLE1_EMPRTOMB, + PUZZLE_HOLE1_FLOATING, + PUZZLE_HOLE1_ICECAVE, + PUZZLE_HOLE1_KEEL, + PUZZLE_HOLE1_LEVEL4, + PUZZLE_HOLE1_MONASTRY, + PUZZLE_HOLE1_OPERA, + PUZZLE_HOLE1_PLATFORM, + PUZZLE_HOLE1_XIAN, + PUZZLE_HOLE2_FLOATING, + PUZZLE_HOLE2_LEVEL3, + PUZZLE_HOLE2_MONASTRY, + PUZZLE_HOLE2_OPERA, + PUZZLE_HOLE4_MONASTRY, + PUZZLE_OPTION1_CATACOMB, + PUZZLE_OPTION1_EMPRTOMB, + PUZZLE_OPTION1_FLOATING, + PUZZLE_OPTION1_HOUSE, + PUZZLE_OPTION1_ICECAVE, + PUZZLE_OPTION1_KEEL, + PUZZLE_OPTION1_LEVEL3, + PUZZLE_OPTION1_MONASTRY, + PUZZLE_OPTION1_OPERA, + PUZZLE_OPTION1_PLATFORM, + PUZZLE_OPTION1_XIAN, + PUZZLE_OPTION2_FLOATING, + PUZZLE_OPTION2_LEVEL3, + PUZZLE_OPTION2_MONASTRY, + PUZZLE_OPTION2_OPERA, + PUZZLE_OPTION2_XIAN, + PUZZLE_OPTION4_DECK, + PUZZLE_OPTION4_MONASTRY, + PUZZLE_OPTION4_SKIDOO, + ROLLING_BALL_EMPRTOMB, + ROLLING_BALL_FLOATING, + ROLLING_BALL_GM, + ROLLING_BALL_MONASTRY, + ROLLING_BALL_WALL, + SHARK_GM, + SKIDMAN_GM, + SKIDOO_GM, + SKIDOO_TRACK_1, + SKIDOO_TRACK_2, + SKIDOO_TRACK_3, + SMASH_ICE_ICECAVE, + SMASH_ICE_LEVEL4, + SMASH_WINDOW_ASSAULT_HOUSE, + SMASH_WINDOW_FLOATING, + SMASH_WINDOW_LEVEL1, + SMASH_WINDOW_LEVEL2, + SMASH_WINDOW_LEVEL5, + SMASH_WINDOW_MONASTRY, + SMASH_WINDOW_OPERA, + SMASH_WINDOW_RIG, + SMASH_WINDOW_SKIDOO, + SMASH_WINDOW_VENICE_BOAT, + SPIDER_3, + SPIKE_WALL_EMPRTOMB, + SPIKE_WALL_LEVEL3, + SPIKE_WALL_WALL, + SPIKES_DECK_LIVING_KEEL_OPERA, + SPIKES_EMPRTOMB_WALL, + SPIKES_FLOATING, + SPIKES_ICECAVE_CATACOMB, + SPIKES_VENICE, + SPINNING_BLADE_EMPRTOMB, + SPINNING_BLADE_WALL_MONASTRY, + SPRING_BOARD_EMPRTOMB, + SPRING_BOARD_ICECAVE, + SWING_BOX_EMPRTOMB, + SWING_BOX_LEVEL5, + SWING_BOX_OPERA, + SWITCH_TYPE1_CATACOMB_ICECAVE, + SWITCH_TYPE1_DECK_LIVING_KEEL_UNWATER, + SWITCH_TYPE1_EMPRTOMB, + SWITCH_TYPE1_FLOATING_WALL_XIAN, + SWITCH_TYPE1_MONASTRY_SKIDOO, + SWITCH_TYPE1_VENICE_BOAT, + SWITCH_TYPE2_BOAT_VENICE, + SWITCH_TYPE2_DECK_LIVING, + SWITCH_TYPE2_EMPRTOMB, + SWITCH_TYPE2_KEEL_UNWATER, + SWITCH_TYPE2_OPERA, + SWITCH_TYPE2_PLATFORM_RIG, + TEETH_TRAP_EMPRTOMB, + TEETH_TRAP_MONASTRY, + TIGER_CATACOMB_SKIDOO, + TIGER_EMPRTOMB_WALL, + TIGER_ICECAVE, + TRAPDOOR_BOAT, + TRAPDOOR_DECK_LIVING_KEEL_UNWATER, + TRAPDOOR_EMPRTOMB, + TRAPDOOR_FLOATING, + TRAPDOOR_ICECAVE, + TRAPDOOR_LEVEL4, + TRAPDOOR_LEVEL5, + TRAPDOOR_MONASTRY, + TRAPDOOR_OPERA, + TRAPDOOR_PLATFORM_RIG, + TRAPDOOR_SKIDOO, + TRAPDOOR_VENICE, + TRAPDOOR_WALL, + TRAPDOOR2_EMPRTOMB, + TRAPDOOR2_FLOATING, + TRAPDOOR2_ICECAVE_CATACOMB, + TRAPDOOR2_KEEL, + TRAPDOOR2_PLATFORM, + TRAPDOOR2_RIG, + TRAPDOOR2_VENICE, + WORKER1_2, + WORKER1_CUT3, + WORKER2, + WORKER3_2, + WORKER3_5, + WORKER3_BOAT, + WORKER3_DECK_LIVING_KEEL_UNWATER, + WORKER3_HOUSE, + WORKER3_PLATFORM_RIG, + WORKER3_VENICE_OPERA, + WORKER4_2, + YETI_4, +} diff --git a/TRLevelControl/Model/TR2/Enums/TR2Type.cs b/TRLevelControl/Model/TR2/Enums/TR2Type.cs index 157f7998b..6ab991a5a 100644 --- a/TRLevelControl/Model/TR2/Enums/TR2Type.cs +++ b/TRLevelControl/Model/TR2/Enums/TR2Type.cs @@ -129,7 +129,7 @@ public enum TR2Type : uint BridgeFlat = 117, BridgeTilt1 = 118, BridgeTilt2 = 119, - JadeSecret_M_H = 120, + PassportOpen_M_H = 120, SilverSecret_M_H = 121, LaraHomePhoto_M_H = 122, CutsceneActor4 = 123, diff --git a/TRLevelControl/Model/TR3/Enums/TR3RAlias.cs b/TRLevelControl/Model/TR3/Enums/TR3RAlias.cs new file mode 100644 index 000000000..6e79329c1 --- /dev/null +++ b/TRLevelControl/Model/TR3/Enums/TR3RAlias.cs @@ -0,0 +1,462 @@ +namespace TRLevelControl.Model; + +public enum TR3RAlias +{ + DUMMY, + AIRLOCK_SWITCH_ANTARC, + AIRLOCK_SWITCH_SHORE, + AIRLOCK_SWITCH_UNDERSEA, + ANIMATING_HELI_TLA, + ANIMATING_HOUSE_ROOFS, + ANIMATING_QUADCHAS_SHORE_STPAULS_UNDERSEA, + ANIMATING_ROOFS_AREA51, + ANIMATING_SLINC_ZOO, + ANIMATING_UNDERSEA, + ANIMATING1_ANTARC, + ANIMATING1_AREA51, + ANIMATING1_CHUNNEL, + ANIMATING1_COMPOUND, + ANIMATING1_MINES, + ANIMATING1_NEVADA, + ANIMATING1_OFFICE, + ANIMATING1_SCOTLAND, + ANIMATING1_SEWER, + ANIMATING1_TEMPLE, + ANIMATING1_TOWER, + ANIMATING1_UNDERSEA, + ANIMATING2_ANTARC, + ANIMATING2_CHAMBER, + ANIMATING2_CHUNNEL, + ANIMATING2_COMPOUND, + ANIMATING2_HOUSE, + ANIMATING2_MINES, + ANIMATING2_NEVADA, + ANIMATING2_RAPIDS, + ANIMATING2_SEWER, + ANIMATING2_STPAUL, + ANIMATING2_TEMPLE, + ANIMATING2_UNDERSEA, + ANIMATING3_COMPOUND, + ANIMATING3_CRASH, + ANIMATING3_HOUSE, + ANIMATING3_NEVADA, + ANIMATING3_SEWER, + ANIMATING3_TOWER, + ANIMATING4_COMPOUND, + ANIMATING4_HOUSE, + ANIMATING4_SEWER, + ANIMATING6_COMPOUND, + ANIMATING6_CRASH, + ANIMATING6_ROOFS, + ANIMATING6_SEWER, + ANIMATING6_UNDERSEA, + BIG_ROLLING_BALL_SLINC, + BLADE_SHORE, + BRIDGE_FLAT_CHUNNEL, + BRIDGE_FLAT_CRASH, + BRIDGE_FLAT_MINES, + BRIDGE_FLAT_ROOFS, + BRIDGE_TILT1_MINES, + BRIDGE_TILT1_STPAUL, + BRIDGE_TILT2_MINES, + BRIDGE_TILT2_STPAUL, + CEILING_SPIKES_BALLOON, + CEILING_SPIKES_CHUNNEL, + CEILING_SPIKES_SEWER, + CEILING_SPIKES_TOWER_RAPIDS, + CEILING_SPIKES_TRIBOSS_TEMPLE, + CEILING_SPIKES_WILLSDEN, + CITY_STATUE, + COBRA_NEVADA, + CROCODILE_UNDERSEA, + DIVER_UNDERSEA, + DOG_SCOTLAND_WILLSDEN, + DOG_SEWER, + DOOR_1, + DOOR_10, + DOOR_11, + DOOR_12, + DOOR_13, + DOOR_14, + DOOR_15, + DOOR_17, + DOOR_18, + DOOR_19, + DOOR_2, + DOOR_20, + DOOR_20R, + DOOR_21, + DOOR_22, + DOOR_23, + DOOR_24, + DOOR_25, + DOOR_26, + DOOR_28, + DOOR_29, + DOOR_3, + DOOR_30, + DOOR_31, + DOOR_32, + DOOR_33, + DOOR_34, + DOOR_35, + DOOR_35R, + DOOR_36, + DOOR_37, + DOOR_38, + DOOR_39, + DOOR_39R, + DOOR_4, + DOOR_40, + DOOR_41, + DOOR_43, + DOOR_44, + DOOR_45, + DOOR_46, + DOOR_47, + DOOR_48, + DOOR_49, + DOOR_5, + DOOR_50, + DOOR_51, + DOOR_52, + DOOR_53, + DOOR_54, + DOOR_55, + DOOR_56, + DOOR_56R, + DOOR_57, + DOOR_58, + DOOR_59, + DOOR_60, + DOOR_61, + DOOR_62, + DOOR_63, + DOOR_7, + DOOR_8, + DOOR_8R, + DOOR_9, + DOOR_9R, + DOOR_BARS, + DOOR_BLAST, + DOOR_BLUE, + DOOR_BOOKCASE, + DOOR_FENCE, + DOOR_FENCE_R, + DOOR_GATE, + DOOR_GATE_R, + DOOR_GATE_UNDERSEA, + DOOR_GRATE, + DOOR_SKULL, + DOOR_SMALL_FENCE, + DOOR_TYPE2_HOUSE, + DOOR_VALVE, + DOOR_WOODEN, + DOOR_ZOO1, + DOOR_ZOO2, + FALLING_BLOCK_ROOFS, + FALLING_BLOCK_SEWER, + FALLING_BLOCK_STPAUL, + FALLING_BLOCK_TRIBOSS, + FALLING_CEILING_CITY, + FALLING_CEILING_TEMPLE, + FALLING_CEILING_WILLSDEN, + FALLING_CEILING1_CRASH, + FAN_CHAMBER, + FAN_CHUNNEL, + FAN_CITY, + FAN_ROOFS, + FAN_TOWER, + FAN_UNDERSEA, + FIREHEAD_SCOTLAND, + FISH_CUT11, + ICICLES_RAPIDS, + ICON_PICKUP1_ITEM_HAND, + ICON_PICKUP1_OPTION_HAND, + KEY_HOLE_CRASH, + KEY_HOLE_JUNGLE, + KEY_HOLE_NEVADA, + KEY_HOLE_ROOFS, + KEY_HOLE_SEWER, + KEY_HOLE_ZOO, + KEY_HOLE1_ANTARC, + KEY_HOLE1_CHUNNEL, + KEY_HOLE1_CITY, + KEY_HOLE1_HOUSE, + KEY_HOLE1_SHORE, + KEY_HOLE3_HOUSE, + KEY_HOLE4_HOUSE, + KEY_ITEM1_2_CRASH, + KEY_ITEM1_ANTARC, + KEY_ITEM1_CHUNNEL, + KEY_ITEM1_CITY, + KEY_ITEM1_HOUSE, + KEY_ITEM1_NEVADA, + KEY_ITEM1_QUADCHAS, + KEY_ITEM1_ROOFS, + KEY_ITEM1_SEWER, + KEY_ITEM1_SHORE, + KEY_ITEM1_TEMPLE, + KEY_ITEM1_TOWER, + KEY_ITEM1_WILLSDEN, + KEY_ITEM1_ZOO, + KEY_ITEM2_3_SEWER, + KEY_ITEM2_NEVADA, + KEY_ITEM2_ROOFS, + KEY_ITEM4_JUNGLE, + KEY_ITEM4_ZOO, + KEY_OPTION1_2_CRASH, + KEY_OPTION1_ANTARC, + KEY_OPTION1_CHUNNEL, + KEY_OPTION1_CITY, + KEY_OPTION1_HOUSE, + KEY_OPTION1_NEVADA, + KEY_OPTION1_QUADCHAS, + KEY_OPTION1_ROOFS, + KEY_OPTION1_SEWER, + KEY_OPTION1_SHORE, + KEY_OPTION1_TEMPLE, + KEY_OPTION1_TOWER, + KEY_OPTION1_WILLSDEN, + KEY_OPTION1_ZOO, + KEY_OPTION2_3_SEWER, + KEY_OPTION2_NEVADA, + KEY_OPTION2_ROOFS, + KEY_OPTION4_JUNGLE, + KEY_OPTION4_ZOO, + LIZARD_MAN_ZOO, + LON_MERCENARY1_CHUNNEL_UNDERSEA, + MONKEY_JUNGLE, + MOVABLE_BLOCK_CITY, + MOVABLE_BLOCK_COMPOUND, + MOVABLE_BLOCK_HOUSE, + MOVABLE_BLOCK_NEVADA, + MOVABLE_BLOCK_ROOFS, + MOVABLE_BLOCK_SCOTLAND, + MOVABLE_BLOCK_TONYBOSS_TEMPLE_JUNGLE, + MOVABLE_BLOCK_TOWER_SEWER_OFFICE, + MOVABLE_BLOCK_TRIBOSS, + MOVABLE_BLOCK_UNDERSEA_CHUNNEL, + MOVABLE_BLOCK2_ROOFS, + MOVABLE_BLOCK2_TOWER, + MP1, + MP1_CHUNNEL, + PASSPORT_OPTION_GYM, + PENDULUM_CITY, + PENDULUM_MINES, + PENDULUM_TOWER, + PICKUP_ITEM1_CRASH, + PICKUP_OPTION1_CRASH, + PLAYER_1_CUT1, + PLAYER_1_CUT11, + PLAYER_1_CUT12, + PLAYER_1_CUT3, + PLAYER_1_CUT5, + PLAYER_1_CUT6, + PLAYER_1_CUT8, + PLAYER_1_CUT9, + PLAYER_2_CUT12, + PLAYER_2_CUT6, + PLAYER_2_CUT9, + PLAYER_3_CUT12, + PLAYER_3_CUT2, + PLAYER_3_CUT3, + PLAYER_3_CUT6, + PLAYER_3_CUT7, + PLAYER_3_CUT8, + PLAYER_3_CUT9, + PLAYER_4_CUT3, + PLAYER_4_CUT6, + PLAYER_4_CUT8, + PLAYER_5_CUT11, + PLAYER_5_CUT12, + PLAYER_5_CUT3, + PLAYER_5_CUT4, + PLAYER_5_CUT6, + PLAYER_5_CUT9, + PLAYER_6_CUT11, + PLAYER_6_CUT3, + PLAYER_6_CUT9, + PLAYER_7_CUT2, + PLAYER_7_CUT3, + PLAYER_7_CUT9, + PLAYER_8_CUT2, + PLAYER_8_CUT3, + PLAYER_8_CUT9, + PLAYER_9_CUT3, + PLAYER_9_CUT9, + PLAYER4_CUT12, + PLAYER4_CUT9, + PUNK1, + PUNK1_SLINC, + PUSH_SWITCH_CITY, + PUSH_SWITCH_COMPOUND, + PUSH_SWITCH_MINES_CHAMBER_ANTARC, + PUSH_SWITCH_QUADCHAS, + PUSH_SWITCH_SEWER_ROOFS_AREA51, + PUSH_SWITCH_TOWER, + PUSH_SWITCH_TRIBOSS_SHORE_RAPIDS, + PUZZLE_DONE_COMPOUND_BLUE, + PUZZLE_DONE_COMPOUND_YELLOW, + PUZZLE_DONE1_ANTARC, + PUZZLE_DONE1_CITY, + PUZZLE_DONE1_MINES, + PUZZLE_DONE1_SCOTLAND, + PUZZLE_DONE1_SEWER, + PUZZLE_DONE1_SHORE, + PUZZLE_DONE1_TEMPLE, + PUZZLE_DONE1_TOWER, + PUZZLE_DONE1_UNDERSEA, + PUZZLE_DONE1_ZOO, + PUZZLE_DONE2_ANTARC, + PUZZLE_DONE2_COMPOUND_AREA51, + PUZZLE_DONE2_MINES, + PUZZLE_DONE2_SCOTLAND, + PUZZLE_DONE2_UNDERSEA, + PUZZLE_DONE3_COMPOUND_AREA51, + PUZZLE_DONE3_MINES, + PUZZLE_DONE3_SEWER, + PUZZLE_DONE3_UNDERSEA, + PUZZLE_DONE4_SEWER, + PUZZLE_DONE4_UNDERSEA, + PUZZLE_HOLE_COMPOUND_BLUE, + PUZZLE_HOLE_COMPOUND_YELLOW, + PUZZLE_HOLE1_ANTARC, + PUZZLE_HOLE1_CITY, + PUZZLE_HOLE1_MINES, + PUZZLE_HOLE1_SEWER, + PUZZLE_HOLE1_SHORE, + PUZZLE_HOLE1_TEMPLE, + PUZZLE_HOLE1_UNDERSEA, + PUZZLE_HOLE1_ZOO, + PUZZLE_HOLE2_3_UNDERSEA, + PUZZLE_HOLE2_ANTARC, + PUZZLE_HOLE2_COMPOUND_AREA51, + PUZZLE_HOLE2_MINES, + PUZZLE_HOLE2_SCOTLAND, + PUZZLE_HOLE3_COMPOUND_AREA51, + PUZZLE_HOLE3_MINES, + PUZZLE_HOLE3_SEWER, + PUZZLE_HOLE4_SEWER, + PUZZLE_HOLE4_UNDERSEA, + PUZZLE_ITEM_COMPOUND_BLUE, + PUZZLE_ITEM_COMPOUND_YELLOW, + PUZZLE_ITEM1_ANTARC, + PUZZLE_ITEM1_CHUNNEL, + PUZZLE_ITEM1_CITY, + PUZZLE_ITEM1_HAND, + PUZZLE_ITEM1_SEWER, + PUZZLE_ITEM1_SHORE, + PUZZLE_ITEM1_TEMPLE, + PUZZLE_ITEM1_TOWER, + PUZZLE_ITEM1_UNDERSEA, + PUZZLE_ITEM2_ANTARC, + PUZZLE_ITEM2_AREA51, + PUZZLE_ITEM2_MINES, + PUZZLE_ITEM2_SCOTLAND, + PUZZLE_ITEM2_SEWER, + PUZZLE_ITEM2_UNDERSEA, + PUZZLE_ITEM3_AREA51, + PUZZLE_ITEM3_MINES, + PUZZLE_ITEM3_SEWER, + PUZZLE_ITEM3_UNDERSEA, + PUZZLE_ITEM4_SEWER, + PUZZLE_ITEM4_UNDERSEA, + PUZZLE_OPTION_COMPOUND_BLUE, + PUZZLE_OPTION_COMPOUND_YELLOW, + PUZZLE_OPTION1_ANTARC, + PUZZLE_OPTION1_CHUNNEL, + PUZZLE_OPTION1_CITY, + PUZZLE_OPTION1_HAND, + PUZZLE_OPTION1_SEWER, + PUZZLE_OPTION1_SHORE, + PUZZLE_OPTION1_TEMPLE, + PUZZLE_OPTION1_TOWER, + PUZZLE_OPTION1_UNDERSEA, + PUZZLE_OPTION2_ANTARC, + PUZZLE_OPTION2_AREA51, + PUZZLE_OPTION2_MINES, + PUZZLE_OPTION2_SCOTLAND, + PUZZLE_OPTION2_SEWER, + PUZZLE_OPTION2_UNDERSEA, + PUZZLE_OPTION3_AREA51, + PUZZLE_OPTION3_MINES, + PUZZLE_OPTION3_SEWER, + PUZZLE_OPTION3_UNDERSEA, + PUZZLE_OPTION4_SEWER, + PUZZLE_OPTION4_UNDERSEA, + QUADBIKE_CHUNNEL, + QUADBIKE_HOUSE, + QUADBIKE_NEVADA, + QUADBIKE_QUADCHAS, + ROLLING_BALL_CITY, + ROLLING_BALL_RAPIDS_NEVADA, + ROLLING_BALL_WILLSDEN, + SECURITY_GUARD_GM, + SMALL_SWITCH_HOUSE, + SMALL_SWITCH_ROOFS_COMPOUND_AREA51, + SMALL_SWITCH_TOWER, + SMASH_WINDOW_CHUNNEL, + SMASH_WINDOW_SEWER, + SMASH_WINDOW_STPAUL, + SPIKE_WALL_NESSIE, + SPIKE_WALL_WILLSDEN, + SPIKES_JUNGLE, + SPIKES_SEWER, + SPIKES_SKULL, + SPIKES_TOWER_ROOFS_NEVADA_COMPOUND_AREA51, + SPIKES_WILLSDEN, + STHPAC_MERCENARY, + STROBE_LIGHT_BEAM, + SWING_BOX_CITY, + SWING_BOX_MINES, + SWING_BOX_TOWER, + SWITCH_TYPE1_ANTARC, + SWITCH_TYPE1_CITY_HOUSE, + SWITCH_TYPE1_SCOTLAND, + SWITCH_TYPE1_STPAUL, + SWITCH_TYPE1_TEMPLE_JUNGLE_CRASH, + SWITCH_TYPE1_TRIBOSS_RAPIDS, + SWITCH_TYPE1_ZOO, + SWITCH_TYPE2_ANTARC, + SWITCH_TYPE2_CITY, + SWITCH_TYPE2_COMPOUND, + SWITCH_TYPE2_NEVADA, + SWITCH_TYPE2_TEMPLE_JUNGLE_CRASH, + SWITCH_TYPE2_TOWER_ROOFS_RAPIDS, + SWITCH_TYPE2_UNDERSEA, + TEETH_TRAP_ANTARC, + TEETH_TRAP_WILLSDEN, + TIGER_ZOO, + TRAIN_CHUNNEL, + TRAIN_SEWER, + TRAIN_UNDERSEA, + TRAIN_ZOO, + TRAPDOOR_ANTARC, + TRAPDOOR_AREA51, + TRAPDOOR_CHUNNEL, + TRAPDOOR_CITY, + TRAPDOOR_COMPOUND, + TRAPDOOR_HOUSE, + TRAPDOOR_NEVADA, + TRAPDOOR_OFFICE, + TRAPDOOR_ROOFS, + TRAPDOOR_SCOTLAND, + TRAPDOOR_SEWER, + TRAPDOOR_SHORE_RAPIDS_CRASH, + TRAPDOOR_STPAUL, + TRAPDOOR_TEMPLE_QUADCHAS_JUNGLE, + TRAPDOOR_TOWER, + TRAPDOOR_UNDERSEA, + TRAPDOOR_ZOO, + TRAPDOOR2_AREA51, + TRAPDOOR2_CRASH, + TRAPDOOR2_SEWER, + TRAPDOOR2_STPAUL, + TRAPDOOR2_TOWER, + TRIBEAXE_WILLSDEN, + VALVE_ANTARC, + VEHICLE_ANIM_RAPIDS, + VULTURE_CHUNNEL, + WHALE_UNDERSEA, +} diff --git a/TRLevelControl/Model/TR3/Enums/TR3Type.cs b/TRLevelControl/Model/TR3/Enums/TR3Type.cs index 9c4705a8d..b5035acb1 100644 --- a/TRLevelControl/Model/TR3/Enums/TR3Type.cs +++ b/TRLevelControl/Model/TR3/Enums/TR3Type.cs @@ -437,6 +437,9 @@ public enum TR3Type : uint Debris9 = 423, SceneryBase = Plant0, + // Workaround for a typo in TRR + CutsceneActor_4 = 800, + // Alias entries CobraIndia = 1000, CobraNevada = 1001, diff --git a/TRLevelControl/TRMapControlBase.cs b/TRLevelControl/TRMapControlBase.cs new file mode 100644 index 000000000..7038982be --- /dev/null +++ b/TRLevelControl/TRMapControlBase.cs @@ -0,0 +1,53 @@ +namespace TRLevelControl; + +public abstract class TRMapControlBase + where TKey : Enum + where TAlias : Enum +{ + private const char _separator = '='; + + public Dictionary Read(string filePath) + { + using StreamReader reader = new(File.OpenRead(filePath)); + return Read(reader); + } + + public Dictionary Read(StreamReader reader) + { + Dictionary map = new(); + string line; + while ((line = reader.ReadLine()) != null) + { + string[] parts = line.Split(_separator); + if (parts.Length < 2) + { + continue; + } + + map[ReadKey(parts[0])] = (TAlias)Enum.Parse(typeof(TAlias), parts[1], true); + } + + return map; + } + + public void Write(Dictionary data, string filePath) + { + using StreamWriter writer = new(File.Create(filePath)); + Write(data, writer); + } + + public void Write(Dictionary data, StreamWriter writer) + { + foreach (var (key, value) in data) + { + writer.Write(ConvertKey(key).ToUpper()); + writer.Write(_separator); + writer.WriteLine(value.ToString().ToUpper()); + } + + writer.Flush(); + } + + protected abstract TKey ReadKey(string key); + protected abstract string ConvertKey(TKey key); +} diff --git a/TRLevelControl/TRPDPControlBase.cs b/TRLevelControl/TRPDPControlBase.cs new file mode 100644 index 000000000..c343b5ba3 --- /dev/null +++ b/TRLevelControl/TRPDPControlBase.cs @@ -0,0 +1,46 @@ +using System.Diagnostics; +using TRLevelControl.Build; +using TRLevelControl.Helpers; +using TRLevelControl.Model; + +namespace TRLevelControl; + +public abstract class TRPDPControlBase + where T : Enum +{ + private static readonly DummyMeshProvider _meshProvider = new(); + + protected ITRLevelObserver _observer; + + public TRPDPControlBase(ITRLevelObserver observer = null) + { + _observer = observer; + } + + public TRDictionary Read(string filePath) + => Read(File.OpenRead(filePath)); + + public TRDictionary Read(Stream stream) + { + using TRLevelReader reader = new(stream); + + TRModelBuilder builder = CreateBuilder(); + TRDictionary models = builder.ReadModelData(reader, _meshProvider); + + Debug.Assert(reader.BaseStream.Position == reader.BaseStream.Length); + return models; + } + + public void Write(TRDictionary models, string filePath) + => Write(models, File.Create(filePath)); + + public void Write(TRDictionary models, Stream outputStream) + { + using TRLevelWriter writer = new(outputStream); + + TRModelBuilder builder = CreateBuilder(); + builder.WriteModelData(writer, models); + } + + protected abstract TRModelBuilder CreateBuilder(); +} diff --git a/TRLevelControlTests/Base/TestBase.cs b/TRLevelControlTests/Base/TestBase.cs index cf01b671d..a67454fea 100644 --- a/TRLevelControlTests/Base/TestBase.cs +++ b/TRLevelControlTests/Base/TestBase.cs @@ -1,4 +1,6 @@ -using TRLevelControl; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Text; +using TRLevelControl; using TRLevelControl.Model; namespace TRLevelControlTests; @@ -6,16 +8,10 @@ namespace TRLevelControlTests; public class TestBase { protected static readonly string _readPath = @"Levels\{0}\{1}"; - protected static readonly string _writePath = @"Levels\{0}\{1}_TEMP{2}"; - public static string GetReadPath(string level, TRGameVersion version) + public static string GetReadPath(string level, TRGameVersion version, bool remastered = false) { - return string.Format(_readPath, version.ToString(), level); - } - - public static string GetWritePath(string level, TRGameVersion version) - { - return string.Format(_writePath, version.ToString(), Path.GetFileNameWithoutExtension(level), Path.GetExtension(level)); + return string.Format(_readPath, version.ToString() + (remastered ? "R" : string.Empty), level); } public static TR1Level GetTR1TestLevel() @@ -78,9 +74,9 @@ public static TR5Level GetTR5Level(string level) return control.Read(GetReadPath(level, TRGameVersion.TR5)); } - public static void ReadWriteLevel(string levelName, TRGameVersion version) + public static void ReadWriteLevel(string levelName, TRGameVersion version, bool remastered) { - string pathI = GetReadPath(levelName, version); + string pathI = GetReadPath(levelName, version, remastered); using FileStream dataStream = File.OpenRead(pathI); using MemoryStream inputStream = new(); using MemoryStream outputStream = new(); @@ -169,6 +165,98 @@ public static TR5Level WriteReadTempLevel(TR5Level level) return control.Read(new MemoryStream(ms.ToArray())); } + public static void ReadWritePDP(string levelName, TRGameVersion version) + { + levelName = Path.GetFileNameWithoutExtension(levelName) + ".PDP"; + string pathI = GetReadPath(levelName, version, true); + + using FileStream dataStream = File.OpenRead(pathI); + using MemoryStream inputStream = new(); + using MemoryStream outputStream = new(); + + dataStream.CopyTo(inputStream); + byte[] inputData = inputStream.ToArray(); + inputStream.Position = 0; + + ObserverBase observer; + switch (version) + { + case TRGameVersion.TR1: + observer = new TR1Observer(); + TR1PDPControl control1 = new(observer); + TRDictionary models1 = control1.Read(inputStream); + control1.Write(models1, outputStream); + break; + + case TRGameVersion.TR2: + observer = new TR2Observer(); + TR2PDPControl control2 = new(observer); + TRDictionary models2 = control2.Read(inputStream); + control2.Write(models2, outputStream); + break; + + case TRGameVersion.TR3: + observer = new TR3Observer(); + TR3PDPControl control3 = new(observer); + TRDictionary models3 = control3.Read(inputStream); + control3.Write(models3, outputStream); + break; + + default: + throw new NotImplementedException(); + } + + observer.TestOutput(inputData, outputStream.ToArray()); + } + + public static void ReadWriteMAP(string levelName, TRGameVersion version) + { + levelName = Path.GetFileNameWithoutExtension(levelName) + ".MAP"; + string pathI = GetReadPath(levelName, version, true); + + using FileStream dataStream = File.OpenRead(pathI); + using MemoryStream inputStream = new(); + using MemoryStream outputStream = new(); + + dataStream.CopyTo(inputStream); + byte[] inputData = inputStream.ToArray(); + inputStream.Position = 0; + + using StreamReader reader = new(inputStream); + using StreamWriter writer = new(outputStream); + + switch (version) + { + case TRGameVersion.TR1: + TR1MapControl control1 = new(); + Dictionary map1 = control1.Read(reader); + control1.Write(map1, writer); + break; + + case TRGameVersion.TR2: + TR2MapControl control2 = new(); + Dictionary map2 = control2.Read(reader); + control2.Write(map2, writer); + break; + + case TRGameVersion.TR3: + TR3MapControl control3 = new(); + Dictionary map3 = control3.Read(reader); + control3.Write(map3, writer); + break; + + default: + throw new NotImplementedException(); + } + + // Some maps contain duplicate entries which we eliminate, so just check everything we've + // written is in the original. Some files also don't end with \r\n, but ours always will, + // so strip out empty lines for comparison. + string[] originalLines = Encoding.Default.GetString(inputData).Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); + string[] outputLines = Encoding.Default.GetString(outputStream.ToArray()).Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); + CollectionAssert.AreEqual(originalLines.Distinct().ToList(), outputLines); + } + public static IEnumerable GetLevelNames(IEnumerable names) { foreach (string lvl in names) diff --git a/TRLevelControlTests/TR1/IOTests.cs b/TRLevelControlTests/TR1/IOTests.cs index e3d8e469c..0eed20f5b 100644 --- a/TRLevelControlTests/TR1/IOTests.cs +++ b/TRLevelControlTests/TR1/IOTests.cs @@ -11,12 +11,34 @@ public class IOTests : TestBase public static IEnumerable GetAllLevels() => GetLevelNames(TR1LevelNames.AsOrderedList); public static IEnumerable GetBaseLevels() => GetLevelNames(TR1LevelNames.AsOrderedList.Except(TR1LevelNames.AsListGold)); public static IEnumerable GetGoldLevels() => GetLevelNames(TR1LevelNames.AsListGold); + public static IEnumerable GetMapLevels() => GetLevelNames(TR1LevelNames.AsOrderedList.Except(new List { TR1LevelNames.TIHOCAN_CUT })); [TestMethod] [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] - public void TestReadWrite(string levelName) + public void TestOGReadWrite(string levelName) { - ReadWriteLevel(levelName, TRGameVersion.TR1); + ReadWriteLevel(levelName, TRGameVersion.TR1, false); + } + + [TestMethod] + [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] + public void TestRemasteredReadWrite(string levelName) + { + ReadWriteLevel(levelName, TRGameVersion.TR1, true); + } + + [TestMethod] + [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] + public void TestPDPReadWrite(string levelName) + { + ReadWritePDP(levelName, TRGameVersion.TR1); + } + + [TestMethod] + [DynamicData(nameof(GetMapLevels), DynamicDataSourceType.Method)] + public void TestMAPReadWrite(string levelName) + { + ReadWriteMAP(levelName, TRGameVersion.TR1); } [TestMethod] diff --git a/TRLevelControlTests/TR2/IOTests.cs b/TRLevelControlTests/TR2/IOTests.cs index 935be2336..29709b7c6 100644 --- a/TRLevelControlTests/TR2/IOTests.cs +++ b/TRLevelControlTests/TR2/IOTests.cs @@ -12,9 +12,30 @@ public class IOTests : TestBase [TestMethod] [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] - public void TestReadWrite(string levelName) + public void TestOGReadWrite(string levelName) { - ReadWriteLevel(levelName, TRGameVersion.TR2); + ReadWriteLevel(levelName, TRGameVersion.TR2, false); + } + + [TestMethod] + [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] + public void TestRemasteredReadWrite(string levelName) + { + ReadWriteLevel(levelName, TRGameVersion.TR2, true); + } + + [TestMethod] + [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] + public void TestPDPReadWrite(string levelName) + { + ReadWritePDP(levelName, TRGameVersion.TR2); + } + + [TestMethod] + [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] + public void TestMAPReadWrite(string levelName) + { + ReadWriteMAP(levelName, TRGameVersion.TR2); } [TestMethod] diff --git a/TRLevelControlTests/TR3/IOTests.cs b/TRLevelControlTests/TR3/IOTests.cs index 640ab663b..17c562579 100644 --- a/TRLevelControlTests/TR3/IOTests.cs +++ b/TRLevelControlTests/TR3/IOTests.cs @@ -14,9 +14,30 @@ public class IOTests : TestBase [TestMethod] [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] - public void TestReadWrite(string levelName) + public void TestOGReadWrite(string levelName) { - ReadWriteLevel(levelName, TRGameVersion.TR3); + ReadWriteLevel(levelName, TRGameVersion.TR3, false); + } + + [TestMethod] + [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] + public void TestRemasteredReadWrite(string levelName) + { + ReadWriteLevel(levelName, TRGameVersion.TR3, true); + } + + [TestMethod] + [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] + public void TestPDPReadWrite(string levelName) + { + ReadWritePDP(levelName, TRGameVersion.TR3); + } + + [TestMethod] + [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] + public void TestMAPReadWrite(string levelName) + { + ReadWriteMAP(levelName, TRGameVersion.TR3); } [TestMethod] diff --git a/TRLevelControlTests/TR4/IOTests.cs b/TRLevelControlTests/TR4/IOTests.cs index 16d2fcfe7..1923c6b9d 100644 --- a/TRLevelControlTests/TR4/IOTests.cs +++ b/TRLevelControlTests/TR4/IOTests.cs @@ -12,9 +12,9 @@ public class IOTests : TestBase [TestMethod] [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] - public void TestReadWrite(string levelname) + public void TestOGReadWrite(string levelname) { - ReadWriteLevel(levelname, TRGameVersion.TR4); + ReadWriteLevel(levelname, TRGameVersion.TR4, false); } [TestMethod] diff --git a/TRLevelControlTests/TR5/IOTests.cs b/TRLevelControlTests/TR5/IOTests.cs index 4c05c11d9..42e687654 100644 --- a/TRLevelControlTests/TR5/IOTests.cs +++ b/TRLevelControlTests/TR5/IOTests.cs @@ -12,9 +12,9 @@ public class IOTests : TestBase [TestMethod] [DynamicData(nameof(GetAllLevels), DynamicDataSourceType.Method)] - public void TestReadWrite(string levelName) + public void TestOGReadWrite(string levelName) { - ReadWriteLevel(levelName, TRGameVersion.TR5); + ReadWriteLevel(levelName, TRGameVersion.TR5, false); } [TestMethod] diff --git a/TRRandomizerCore/Levels/TR1RCombinedLevel.cs b/TRRandomizerCore/Levels/TR1RCombinedLevel.cs index db5aad15a..50e200521 100644 --- a/TRRandomizerCore/Levels/TR1RCombinedLevel.cs +++ b/TRRandomizerCore/Levels/TR1RCombinedLevel.cs @@ -17,4 +17,6 @@ public class TR1RCombinedLevel public int Sequence => IsCutScene ? ParentLevel.Sequence : Script.Sequence; public bool Is(string levelFileName) => Script.Is(levelFileName); public bool IsAssault => Is(TR1LevelNames.ASSAULT); + public TRDictionary PDPData { get; set; } + public Dictionary MapData { get; set; } } diff --git a/TRRandomizerCore/Levels/TR2RCombinedLevel.cs b/TRRandomizerCore/Levels/TR2RCombinedLevel.cs index b80eebfc0..ddce8cb08 100644 --- a/TRRandomizerCore/Levels/TR2RCombinedLevel.cs +++ b/TRRandomizerCore/Levels/TR2RCombinedLevel.cs @@ -17,4 +17,6 @@ public class TR2RCombinedLevel public int Sequence => IsCutScene ? ParentLevel.Sequence : Script.Sequence; public bool Is(string levelFileName) => Script.Is(levelFileName); public bool IsAssault => Is(TR2LevelNames.ASSAULT); + public TRDictionary PDPData { get; set; } + public Dictionary MapData { get; set; } } diff --git a/TRRandomizerCore/Levels/TR3RCombinedLevel.cs b/TRRandomizerCore/Levels/TR3RCombinedLevel.cs index f441d86e6..0dc5b9a43 100644 --- a/TRRandomizerCore/Levels/TR3RCombinedLevel.cs +++ b/TRRandomizerCore/Levels/TR3RCombinedLevel.cs @@ -17,4 +17,6 @@ public class TR3RCombinedLevel public int Sequence => IsCutScene ? ParentLevel.Sequence : Script.Sequence; public bool Is(string levelFileName) => Script.Is(levelFileName); public bool IsAssault => Is(TR3LevelNames.ASSAULT); + public TRDictionary PDPData { get; set; } + public Dictionary MapData { get; set; } } diff --git a/TRRandomizerCore/Processors/TR1/TR1RLevelProcessor.cs b/TRRandomizerCore/Processors/TR1/TR1RLevelProcessor.cs index c4cecb6b5..d2cb879e2 100644 --- a/TRRandomizerCore/Processors/TR1/TR1RLevelProcessor.cs +++ b/TRRandomizerCore/Processors/TR1/TR1RLevelProcessor.cs @@ -7,11 +7,15 @@ namespace TRRandomizerCore.Processors; public class TR1RLevelProcessor : AbstractLevelProcessor { - protected TR1LevelControl _control; + protected TR1LevelControl _levelControl; + protected TR1PDPControl _pdpControl; + protected TR1MapControl _mapControl; public TR1RLevelProcessor() { - _control = new(); + _levelControl = new(); + _pdpControl = new(); + _mapControl = new(); } protected override TR1RCombinedLevel LoadCombinedLevel(TRRScriptedLevel scriptedLevel) @@ -19,6 +23,8 @@ protected override TR1RCombinedLevel LoadCombinedLevel(TRRScriptedLevel scripted TR1RCombinedLevel level = new() { Data = LoadLevelData(scriptedLevel.LevelFileBaseName), + PDPData = LoadPDPData(scriptedLevel.PdpFileBaseName), + MapData = LoadMapData(scriptedLevel.MapFileBaseName), Script = scriptedLevel, Checksum = GetBackupChecksum(scriptedLevel.LevelFileBaseName) }; @@ -37,25 +43,51 @@ public TR1Level LoadLevelData(string name) lock (_controlLock) { string fullPath = Path.Combine(BasePath, name); - return _control.Read(fullPath); + return _levelControl.Read(fullPath); + } + } + + public TRDictionary LoadPDPData(string name) + { + lock (_controlLock) + { + string fullPath = Path.Combine(BasePath, name); + return File.Exists(fullPath) ? _pdpControl.Read(fullPath) : null; + } + } + + public Dictionary LoadMapData(string name) + { + lock (_controlLock) + { + string fullPath = Path.Combine(BasePath, name); + return File.Exists(fullPath) ? _mapControl.Read(fullPath) : null; } } protected override void ReloadLevelData(TR1RCombinedLevel level) { level.Data = LoadLevelData(level.Name); + level.PDPData = LoadPDPData(level.Script.PdpFileBaseName); + level.MapData = LoadMapData(level.Script.MapFileBaseName); if (level.HasCutScene) { level.CutSceneLevel.Data = LoadLevelData(level.CutSceneLevel.Name); + level.CutSceneLevel.PDPData = LoadPDPData(level.CutSceneLevel.Script.PdpFileBaseName); + level.CutSceneLevel.MapData = LoadMapData(level.CutSceneLevel.Script.MapFileBaseName); } } protected override void SaveLevel(TR1RCombinedLevel level) { SaveLevel(level.Data, level.Name); + SavePDPData(level.PDPData, level.Script.PdpFileBaseName); + SaveMapData(level.MapData, level.Script.MapFileBaseName); if (level.HasCutScene) { SaveLevel(level.CutSceneLevel.Data, level.CutSceneLevel.Name); + SavePDPData(level.CutSceneLevel.PDPData, level.CutSceneLevel.Script.PdpFileBaseName); + SaveMapData(level.CutSceneLevel.MapData, level.CutSceneLevel.Script.MapFileBaseName); } SaveScript(); @@ -66,7 +98,35 @@ public void SaveLevel(TR1Level level, string name) lock (_controlLock) { string fullPath = Path.Combine(BasePath, name); - _control.Write(level, fullPath); + _levelControl.Write(level, fullPath); + } + } + + public void SavePDPData(TRDictionary data, string name) + { + if (data == null) + { + return; + } + + lock (_controlLock) + { + string fullPath = Path.Combine(BasePath, name); + _pdpControl.Write(data, fullPath); + } + } + + public void SaveMapData(Dictionary data, string name) + { + if (data == null) + { + return; + } + + lock (_controlLock) + { + string fullPath = Path.Combine(BasePath, name); + _mapControl.Write(data, fullPath); } } } diff --git a/TRRandomizerCore/Processors/TR2/TR2RLevelProcessor.cs b/TRRandomizerCore/Processors/TR2/TR2RLevelProcessor.cs index b71db7fb1..b11b50dc6 100644 --- a/TRRandomizerCore/Processors/TR2/TR2RLevelProcessor.cs +++ b/TRRandomizerCore/Processors/TR2/TR2RLevelProcessor.cs @@ -7,11 +7,15 @@ namespace TRRandomizerCore.Processors; public class TR2RLevelProcessor : AbstractLevelProcessor { - protected TR2LevelControl _control; + protected TR2LevelControl _levelControl; + protected TR2PDPControl _pdpControl; + protected TR2MapControl _mapControl; public TR2RLevelProcessor() { - _control = new(); + _levelControl = new(); + _pdpControl = new(); + _mapControl = new(); } protected override TR2RCombinedLevel LoadCombinedLevel(TRRScriptedLevel scriptedLevel) @@ -19,6 +23,8 @@ protected override TR2RCombinedLevel LoadCombinedLevel(TRRScriptedLevel scripted TR2RCombinedLevel level = new() { Data = LoadLevelData(scriptedLevel.LevelFileBaseName), + PDPData = LoadPDPData(scriptedLevel.PdpFileBaseName), + MapData = LoadMapData(scriptedLevel.MapFileBaseName), Script = scriptedLevel, Checksum = GetBackupChecksum(scriptedLevel.LevelFileBaseName) }; @@ -37,25 +43,51 @@ public TR2Level LoadLevelData(string name) lock (_controlLock) { string fullPath = Path.Combine(BasePath, name); - return _control.Read(fullPath); + return _levelControl.Read(fullPath); + } + } + + public TRDictionary LoadPDPData(string name) + { + lock (_controlLock) + { + string fullPath = Path.Combine(BasePath, name); + return File.Exists(fullPath) ? _pdpControl.Read(fullPath) : null; + } + } + + public Dictionary LoadMapData(string name) + { + lock (_controlLock) + { + string fullPath = Path.Combine(BasePath, name); + return File.Exists(fullPath) ? _mapControl.Read(fullPath) : null; } } protected override void ReloadLevelData(TR2RCombinedLevel level) { level.Data = LoadLevelData(level.Name); + level.PDPData = LoadPDPData(level.Script.PdpFileBaseName); + level.MapData = LoadMapData(level.Script.MapFileBaseName); if (level.HasCutScene) { level.CutSceneLevel.Data = LoadLevelData(level.CutSceneLevel.Name); + level.CutSceneLevel.PDPData = LoadPDPData(level.CutSceneLevel.Script.PdpFileBaseName); + level.CutSceneLevel.MapData = LoadMapData(level.CutSceneLevel.Script.MapFileBaseName); } } protected override void SaveLevel(TR2RCombinedLevel level) { SaveLevel(level.Data, level.Name); + SavePDPData(level.PDPData, level.Script.PdpFileBaseName); + SaveMapData(level.MapData, level.Script.MapFileBaseName); if (level.HasCutScene) { SaveLevel(level.CutSceneLevel.Data, level.CutSceneLevel.Name); + SavePDPData(level.CutSceneLevel.PDPData, level.CutSceneLevel.Script.PdpFileBaseName); + SaveMapData(level.CutSceneLevel.MapData, level.CutSceneLevel.Script.MapFileBaseName); } SaveScript(); @@ -66,7 +98,35 @@ public void SaveLevel(TR2Level level, string name) lock (_controlLock) { string fullPath = Path.Combine(BasePath, name); - _control.Write(level, fullPath); + _levelControl.Write(level, fullPath); + } + } + + public void SavePDPData(TRDictionary data, string name) + { + if (data != null) + { + return; + } + + lock (_controlLock) + { + string fullPath = Path.Combine(BasePath, name); + _pdpControl.Write(data, fullPath); + } + } + + public void SaveMapData(Dictionary data, string name) + { + if (data == null) + { + return; + } + + lock (_controlLock) + { + string fullPath = Path.Combine(BasePath, name); + _mapControl.Write(data, fullPath); } } } diff --git a/TRRandomizerCore/Processors/TR3/TR3RLevelProcessor.cs b/TRRandomizerCore/Processors/TR3/TR3RLevelProcessor.cs index d742ba0d1..b4c60783d 100644 --- a/TRRandomizerCore/Processors/TR3/TR3RLevelProcessor.cs +++ b/TRRandomizerCore/Processors/TR3/TR3RLevelProcessor.cs @@ -7,11 +7,15 @@ namespace TRRandomizerCore.Processors; public class TR3RLevelProcessor : AbstractLevelProcessor { - protected TR3LevelControl _control; + protected TR3LevelControl _levelControl; + protected TR3PDPControl _pdpControl; + protected TR3MapControl _mapControl; public TR3RLevelProcessor() { - _control = new(); + _levelControl = new(); + _pdpControl = new(); + _mapControl = new(); } protected override TR3RCombinedLevel LoadCombinedLevel(TRRScriptedLevel scriptedLevel) @@ -19,6 +23,8 @@ protected override TR3RCombinedLevel LoadCombinedLevel(TRRScriptedLevel scripted TR3RCombinedLevel level = new() { Data = LoadLevelData(scriptedLevel.LevelFileBaseName), + PDPData = LoadPDPData(scriptedLevel.PdpFileBaseName), + MapData = LoadMapData(scriptedLevel.MapFileBaseName), Script = scriptedLevel, Checksum = GetBackupChecksum(scriptedLevel.LevelFileBaseName) }; @@ -37,25 +43,51 @@ public TR3Level LoadLevelData(string name) lock (_controlLock) { string fullPath = Path.Combine(BasePath, name); - return _control.Read(fullPath); + return _levelControl.Read(fullPath); + } + } + + public TRDictionary LoadPDPData(string name) + { + lock (_controlLock) + { + string fullPath = Path.Combine(BasePath, name); + return File.Exists(fullPath) ? _pdpControl.Read(fullPath) : null; + } + } + + public Dictionary LoadMapData(string name) + { + lock (_controlLock) + { + string fullPath = Path.Combine(BasePath, name); + return File.Exists(fullPath) ? _mapControl.Read(fullPath) : null; } } protected override void ReloadLevelData(TR3RCombinedLevel level) { level.Data = LoadLevelData(level.Name); + level.PDPData = LoadPDPData(level.Script.PdpFileBaseName); + level.MapData = LoadMapData(level.Script.MapFileBaseName); if (level.HasCutScene) { level.CutSceneLevel.Data = LoadLevelData(level.CutSceneLevel.Name); + level.CutSceneLevel.PDPData = LoadPDPData(level.CutSceneLevel.Script.PdpFileBaseName); + level.CutSceneLevel.MapData = LoadMapData(level.CutSceneLevel.Script.MapFileBaseName); } } protected override void SaveLevel(TR3RCombinedLevel level) { SaveLevel(level.Data, level.Name); + SavePDPData(level.PDPData, level.Script.PdpFileBaseName); + SaveMapData(level.MapData, level.Script.MapFileBaseName); if (level.HasCutScene) { SaveLevel(level.CutSceneLevel.Data, level.CutSceneLevel.Name); + SavePDPData(level.CutSceneLevel.PDPData, level.CutSceneLevel.Script.PdpFileBaseName); + SaveMapData(level.CutSceneLevel.MapData, level.CutSceneLevel.Script.MapFileBaseName); } SaveScript(); @@ -66,7 +98,35 @@ public void SaveLevel(TR3Level level, string name) lock (_controlLock) { string fullPath = Path.Combine(BasePath, name); - _control.Write(level, fullPath); + _levelControl.Write(level, fullPath); + } + } + + public void SavePDPData(TRDictionary data, string name) + { + if (data == null) + { + return; + } + + lock (_controlLock) + { + string fullPath = Path.Combine(BasePath, name); + _pdpControl.Write(data, fullPath); + } + } + + public void SaveMapData(Dictionary data, string name) + { + if (data == null) + { + return; + } + + lock (_controlLock) + { + string fullPath = Path.Combine(BasePath, name); + _mapControl.Write(data, fullPath); } } }