Skip to content

Commit

Permalink
Add initial TRR sequencing support
Browse files Browse the repository at this point in the history
  • Loading branch information
lahm86 committed Aug 11, 2024
1 parent 754e241 commit aa066f7
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 2 deletions.
Binary file modified Deps/TRGE.Coord.dll
Binary file not shown.
Binary file modified Deps/TRGE.Core.dll
Binary file not shown.
5 changes: 5 additions & 0 deletions TRLevelControl/Helpers/TR2TypeUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,11 @@ public static bool IsStandardPickupType(TR2Type type)
return GetStandardPickupTypes().Contains(type);
}

public static bool IsMediType(TR2Type type)
{
return type == TR2Type.SmallMed_S_P || type == TR2Type.LargeMed_S_P;
}

public static List<TR2Type> GetKeyItemTypes()
{
return new()
Expand Down
13 changes: 12 additions & 1 deletion TRLevelControl/Model/Common/FloorData/FDControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ public List<FDTriggerEntry> GetTriggers(FDTrigAction action, int parameter = -1)
}

public List<FDActionItem> GetActionItems(FDTrigAction action, int sectorIndex = -1)
{
return GetActionItems(new List<FDTrigAction> { action }, sectorIndex);
}

public List<FDActionItem> GetEntityActionItems(int entityIndex)
{
return GetActionItems(new List<FDTrigAction> { FDTrigAction.Object, FDTrigAction.LookAtItem })
.FindAll(a => a.Parameter == entityIndex);
}

public List<FDActionItem> GetActionItems(List<FDTrigAction> actions, int sectorIndex = -1)
{
List<List<FDEntry>> entrySearch;
if (sectorIndex == -1)
Expand All @@ -147,7 +158,7 @@ public List<FDActionItem> GetActionItems(FDTrigAction action, int sectorIndex =
return entrySearch
.SelectMany(e => e.Where(i => i is FDTriggerEntry))
.Cast<FDTriggerEntry>()
.SelectMany(t => t.Actions.FindAll(a => a.Action == action))
.SelectMany(t => t.Actions.FindAll(a => actions.Contains(a.Action)))
.ToList();
}

Expand Down
21 changes: 21 additions & 0 deletions TRRandomizerCore/Editors/TR1RemasteredEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using TRGE.Core;
using TRLevelControl.Model;
using TRRandomizerCore.Helpers;
using TRRandomizerCore.Processors;
using TRRandomizerCore.Randomizers;
using TRRandomizerCore.Secrets;

Expand Down Expand Up @@ -69,6 +70,12 @@ protected override int GetSaveTarget(int numLevels)
// Environment randomizer always runs
target += numLevels * 2;

// Level sequencing checks
if (Settings.RandomizeGameMode)
{
target += numLevels;
}

return target;
}

Expand Down Expand Up @@ -242,6 +249,20 @@ protected override void SaveImpl(AbstractTRScriptEditor scriptEditor, TRSaveMoni
}.Randomize(Settings.TextureSeed);
}

if (!monitor.IsCancelled && Settings.RandomizeGameMode)
{
monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Running level sequence checks");
new TR1RSequenceProcessor
{
ScriptEditor = scriptEditor,
Levels = levels,
BasePath = wipDirectory,
BackupPath = backupDirectory,
SaveMonitor = monitor,
Settings = Settings,
}.Run();
}

monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Finalizing tasks - please wait");
titleTask.Wait();
}
Expand Down
22 changes: 22 additions & 0 deletions TRRandomizerCore/Editors/TR2RemasteredEditor.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using TRDataControl;
using TRGE.Core;
using TRLevelControl;
using TRLevelControl.Model;
using TRRandomizerCore.Helpers;
using TRRandomizerCore.Processors;
using TRRandomizerCore.Randomizers;

namespace TRRandomizerCore.Editors;
Expand Down Expand Up @@ -63,6 +65,12 @@ protected override int GetSaveTarget(int numLevels)
// Environment randomizer always runs
target += numLevels * 2;

// Level sequencing checks
if (Settings.RandomizeGameMode)
{
target += numLevels;
}

return target;
}

Expand Down Expand Up @@ -223,6 +231,20 @@ protected override void SaveImpl(AbstractTRScriptEditor scriptEditor, TRSaveMoni
}.Randomize(Settings.TextureSeed);
}

if (!monitor.IsCancelled && Settings.RandomizeGameMode)
{
monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Running level sequence checks");
new TR2RSequenceProcessor
{
ScriptEditor = scriptEditor,
Levels = levels,
BasePath = wipDirectory,
BackupPath = backupDirectory,
SaveMonitor = monitor,
Settings = Settings,
}.Run();
}

monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Finalizing tasks - please wait");
titleTask.Wait();
}
Expand Down
14 changes: 14 additions & 0 deletions TRRandomizerCore/Processors/AbstractLevelProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ public AbstractLevelProcessor()
_maxThreads = 3;
}

protected void Process(Action<C> processAction)
{
foreach (S lvl in Levels)
{
LoadLevelInstance(lvl);
processAction(_levelInstance);
SaveLevelInstance();
if (!TriggerProgress())
{
break;
}
}
}

protected void LoadLevelInstance(S scriptedLevel)
{
_levelInstance = LoadCombinedLevel(scriptedLevel);
Expand Down
62 changes: 62 additions & 0 deletions TRRandomizerCore/Processors/BaseTRRSequenceProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Diagnostics;
using TRGE.Core;
using TRLevelControl.Model;

namespace TRRandomizerCore.Processors;

public class BaseTRRSequenceProcessor<E, T>
where E : TREntity<T>
where T : Enum
{
public Func<T, bool> IsMediType { get; set; }

public void AdjustMedipacks(TRRScriptedLevel levelScript, List<E> currentItems, List<E> originalItems, E dummyItem, FDControl floorData)
{
// In NG+, the game will convert medipacks to ammo, but this is based on the items' indices
// in the level's original slot. So we need to guarantee that the items match up in the new
// slot to avoid the wrong things being converted.
if (levelScript.Sequence == levelScript.OriginalSequence)
{
return;
}

List<int> ogIndices = GetMediIndices(originalItems);
Queue<int> swappableIndices = new(GetMediIndices(currentItems).Except(ogIndices));
foreach (int index in ogIndices)
{
while (currentItems.Count <= index)
{
currentItems.Add(dummyItem);
}

E entity = currentItems[index];
if (IsMediType(entity.TypeID))
{
continue;
}

if (swappableIndices.Count == 0)
{
swappableIndices.Enqueue(currentItems.Count);
currentItems.Add(dummyItem);
}
int swapIndex = swappableIndices.Dequeue();
currentItems[index] = currentItems[swapIndex];
currentItems[swapIndex] = entity;

floorData.GetEntityActionItems(index)
.ForEach(a => a.Parameter = (short)swapIndex);
}

// Sanity check
ogIndices.ForEach(i => Debug.Assert(currentItems[i] == dummyItem
|| IsMediType(currentItems[i].TypeID)));
}

private List<int> GetMediIndices(List<E> items)
{
return items.FindAll(e => IsMediType(e.TypeID))
.Select(e => items.IndexOf(e))
.ToList();
}
}
41 changes: 41 additions & 0 deletions TRRandomizerCore/Processors/TR1/TR1RSequenceProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using TRGE.Core;
using TRLevelControl.Helpers;
using TRLevelControl.Model;
using TRRandomizerCore.Editors;
using TRRandomizerCore.Levels;
using TRRandomizerCore.Utilities;

namespace TRRandomizerCore.Processors;

public class TR1RSequenceProcessor : TR1RLevelProcessor
{
private static readonly TR1Entity _dummyItem = new()
{
TypeID = TR1Type.CameraTarget_N,
Invisible = true,
};

private BaseTRRSequenceProcessor<TR1Entity, TR1Type> _processor;

public RandomizerSettings Settings { get; set; }

public void Run()
{
_processor = new()
{
IsMediType = t => TR1TypeUtilities.IsMediType(t),
};
Process(AdjustLevel);
}

private void AdjustLevel(TR1RCombinedLevel level)
{
TRRScriptedLevel mimickedLevelScript = Levels.Find(l => l.OriginalSequence == level.Script.Sequence);
TR1Level mimickedLevel = LoadLevelData(Path.Combine(BackupPath, mimickedLevelScript.LevelFileBaseName));

TR1Entity dummyItem = (TR1Entity)_dummyItem.Clone();
dummyItem.SetLocation(level.Data.Entities.Find(e => e.TypeID == TR1Type.Lara).GetLocation());

_processor.AdjustMedipacks(level.Script, level.Data.Entities, mimickedLevel.Entities, dummyItem, level.Data.FloorData);
}
}
41 changes: 41 additions & 0 deletions TRRandomizerCore/Processors/TR2/TR2RSequenceProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using TRGE.Core;
using TRLevelControl.Helpers;
using TRLevelControl.Model;
using TRRandomizerCore.Editors;
using TRRandomizerCore.Levels;
using TRRandomizerCore.Utilities;

namespace TRRandomizerCore.Processors;

public class TR2RSequenceProcessor : TR2RLevelProcessor
{
private static readonly TR2Entity _dummyItem = new()
{
TypeID = TR2Type.CameraTarget_N,
Invisible = true,
};

private BaseTRRSequenceProcessor<TR2Entity, TR2Type> _processor;

public RandomizerSettings Settings { get; set; }

public void Run()
{
_processor = new()
{
IsMediType = t => TR2TypeUtilities.IsMediType(t),
};
Process(AdjustLevel);
}

private void AdjustLevel(TR2RCombinedLevel level)
{
TRRScriptedLevel mimickedLevelScript = Levels.Find(l => l.OriginalSequence == level.Script.Sequence);
TR2Level mimickedLevel = LoadLevelData(Path.Combine(BackupPath, mimickedLevelScript.LevelFileBaseName));

TR2Entity dummyItem = (TR2Entity)_dummyItem.Clone();
dummyItem.SetLocation(level.Data.Entities.Find(e => e.TypeID == TR2Type.Lara).GetLocation());

_processor.AdjustMedipacks(level.Script, level.Data.Entities, mimickedLevel.Entities, dummyItem, level.Data.FloorData);
}
}
2 changes: 2 additions & 0 deletions TRRandomizerCore/TRVersionSupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ internal class TRVersionSupport
TRRandomizerType.Item,
TRRandomizerType.KeyItems,
TRRandomizerType.LarsonBehaviour,
TRRandomizerType.LevelSequence,
TRRandomizerType.Secret,
TRRandomizerType.SecretAudio,
TRRandomizerType.SecretReward,
Expand Down Expand Up @@ -139,6 +140,7 @@ internal class TRVersionSupport
TRRandomizerType.Item,
TRRandomizerType.ItemDrops,
TRRandomizerType.KeyItems,
TRRandomizerType.LevelSequence,
TRRandomizerType.Secret,
TRRandomizerType.SecretAudio,
TRRandomizerType.SFX,
Expand Down
3 changes: 2 additions & 1 deletion TRRandomizerView/Windows/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,8 @@ private void LaunchGameCommandBinding_CanExecute(object sender, CanExecuteRouted

private void LaunchGameCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
if (ConfirmEditorSaveState())
bool wasDirty = IsEditorDirty;
if (ConfirmEditorSaveState() && (!wasDirty || !_editorControl.Controller.AutoLaunchGame))
{
_editorControl.LaunchGame();
}
Expand Down

0 comments on commit aa066f7

Please sign in to comment.