Skip to content

Commit

Permalink
Add initial support for TRR (LostArtefacts#615)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahm86 authored Apr 14, 2024
1 parent 920dcf8 commit ca13dac
Show file tree
Hide file tree
Showing 50 changed files with 2,997 additions and 281 deletions.
Binary file modified Deps/TRGE.Coord.dll
Binary file not shown.
Binary file modified Deps/TRGE.Core.dll
Binary file not shown.
37 changes: 26 additions & 11 deletions SFXExport/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,46 @@ static void Main(string[] args)
}

string file = args[0];
string exportDir = args[1];
if (Directory.Exists(exportDir))
TRGameVersion version = Enum.Parse<TRGameVersion>(args[1]);
if (!Enum.IsDefined(typeof(TRGameVersion), version))
{
Directory.Delete(exportDir, true);
Console.WriteLine("Unrecognised game verion.");
return;
}

if (Directory.Exists(version.ToString()))
{
Directory.Delete(version.ToString(), true);
}
Directory.CreateDirectory(exportDir);
Directory.CreateDirectory(version.ToString());

bool remaster = args.Length > 2 && args[2].ToUpper() == "REMASTER";

switch (Path.GetExtension(file).ToUpper())
{
case ".SFX":
ExtractFromSFX(file, exportDir);
ExtractFromSFX(file, version, remaster);
break;
case ".PHD":
ExtractFromPHD(file, exportDir);
ExtractFromPHD(file, version);
break;
default:
Console.WriteLine("Unsupported file.");
break;
}
}

private static void ExtractFromSFX(string file, string exportDir)
private static void ExtractFromSFX(string file, TRGameVersion version, bool remaster)
{
int sample = 0;
using BinaryReader reader = new(File.Open(file, FileMode.Open));

if (remaster)
{
// Header remains unknown for now
reader.BaseStream.Position = version == TRGameVersion.TR1 ? 0x200 : 0x2E4;
}

while (reader.BaseStream.Position < reader.BaseStream.Length)
{
uint[] header = new uint[11];
Expand All @@ -47,7 +62,7 @@ private static void ExtractFromSFX(string file, string exportDir)
header[i] = reader.ReadUInt32();
}

using BinaryWriter writer = new(File.Create(Path.Combine(exportDir, sample++ + ".wav")));
using BinaryWriter writer = new(File.Create(Path.Combine(version.ToString(), sample++ + ".wav")));
for (int i = 0; i < header.Length; i++)
{
writer.Write(header[i]);
Expand All @@ -61,7 +76,7 @@ private static void ExtractFromSFX(string file, string exportDir)
}
}

private static void ExtractFromPHD(string file, string exportDir)
private static void ExtractFromPHD(string file, TRGameVersion version)
{
TR1Level level = new TR1LevelControl().Read(file);
for (int i = 0; i < level.NumSampleIndices; i++)
Expand All @@ -73,7 +88,7 @@ private static void ExtractFromPHD(string file, string exportDir)
sampleEnd = (uint)level.Samples.Length;
}

using BinaryWriter writer = new(File.Create(Path.Combine(exportDir, i + ".wav")));
using BinaryWriter writer = new(File.Create(Path.Combine(version.ToString(), i + ".wav")));
for (uint j = sampleStart; j < sampleEnd; j++)
{
writer.Write(level.Samples[j]);
Expand All @@ -84,7 +99,7 @@ private static void ExtractFromPHD(string file, string exportDir)
private static void Usage()
{
Console.WriteLine();
Console.WriteLine("Usage: SFXExport [*.SFX|*.PHD] [EXPORT_DIR]");
Console.WriteLine("Usage: SFXExport [*.SFX|*.PHD] [TR1|TR2|TR3] [REMASTER|CLASSIC]");
Console.WriteLine();

Console.WriteLine("Example");
Expand Down
2 changes: 2 additions & 0 deletions TRLevelControl/Helpers/TRConsts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ public static class TRConsts

public const int MaskBits = 5;
public const int FullMask = (1 << MaskBits) - 1;

public const int Angle45 = 8192;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@

namespace TRRandomizerCore.Editors;

public class TR1RandoEditor : TR1LevelEditor, ISettingsProvider
public class TR1ClassicEditor : TR1LevelEditor, ISettingsProvider
{
private static readonly Point _regularBadgePos = new(706, 537);
private static readonly Point _goldBadgePos = new(498, 445);

public RandomizerSettings Settings { get; private set; }

public TR1RandoEditor(TRDirectoryIOArgs args, TREdition edition)
public TR1ClassicEditor(TRDirectoryIOArgs args, TREdition edition)
: base(args, edition) { }

protected override void ApplyConfig(Config config)
{
Settings = new RandomizerSettings()
Settings = new()
{
ExcludableEnemies = JsonConvert.DeserializeObject<Dictionary<short, string>>(File.ReadAllText(@"Resources\TR1\Restrictions\excludable_enemies.json"))
};
Expand Down
138 changes: 138 additions & 0 deletions TRRandomizerCore/Editors/TR1RemasteredEditor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
using TRGE.Core;
using TRLevelControl.Model;
using TRRandomizerCore.Helpers;
using TRRandomizerCore.Randomizers;

namespace TRRandomizerCore.Editors;

public class TR1RemasteredEditor : TR1ClassicEditor
{
public TR1RemasteredEditor(TRDirectoryIOArgs io, TREdition edition)
: base(io, edition) { }

protected override void ApplyConfig(Config config)
{
base.ApplyConfig(config);
Settings.AllowReturnPathLocations = false;
Settings.AddReturnPaths = false;
Settings.FixOGBugs = false;
}

protected override int GetSaveTarget(int numLevels)
{
int target = 0;

if (Settings.RandomizeItems)
{
target += numLevels;
if (Settings.IncludeKeyItems)
{
target += numLevels;
}
}

if (Settings.RandomizeStartPosition)
{
target += numLevels;
}

if (Settings.RandomizeAudio)
{
target += numLevels;
}

// Environment randomizer always runs
target += numLevels * 2;

return target;
}

protected override void SaveImpl(AbstractTRScriptEditor scriptEditor, TRSaveMonitor monitor)
{
List<TRRScriptedLevel> levels = new(
scriptEditor.EnabledScriptedLevels.Cast<TRRScriptedLevel>().ToList()
);

if (scriptEditor.GymAvailable)
{
levels.Add(scriptEditor.AssaultLevel as TRRScriptedLevel);
}

string backupDirectory = _io.BackupDirectory.FullName;
string wipDirectory = _io.WIPOutputDirectory.FullName;

ItemFactory<TR1Entity> itemFactory = new(@"Resources\TR1\Items\repurposable_items.json");
TR1RItemRandomizer itemRandomizer = new()
{
ScriptEditor = scriptEditor,
Levels = levels,
BasePath = wipDirectory,
BackupPath = backupDirectory,
SaveMonitor = monitor,
Settings = Settings,
ItemFactory = itemFactory
};

TR1REnvironmentRandomizer environmentRandomizer = new()
{
ScriptEditor = scriptEditor,
Levels = levels,
BasePath = wipDirectory,
BackupPath = backupDirectory,
SaveMonitor = monitor,
Settings = Settings,
};

if (!monitor.IsCancelled && Settings.RandomizeItems)
{
monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing standard items");
itemRandomizer.Randomize(Settings.ItemSeed);
}

if (!monitor.IsCancelled && Settings.RandomizeStartPosition)
{
monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing start positions");
new TR1RStartPositionRandomizer
{
ScriptEditor = scriptEditor,
Levels = levels,
BasePath = wipDirectory,
BackupPath = backupDirectory,
SaveMonitor = monitor,
Settings = Settings
}.Randomize(Settings.StartPositionSeed);
}

if (!monitor.IsCancelled)
{
monitor.FireSaveStateBeginning(TRSaveCategory.Custom, Settings.RandomizeEnvironment ? "Randomizing environment" : "Applying default environment packs");
environmentRandomizer.Randomize(Settings.EnvironmentSeed);
}

if (!monitor.IsCancelled && Settings.RandomizeItems && Settings.IncludeKeyItems)
{
monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing key items");
itemRandomizer.RandomizeKeyItems();
}

if (!monitor.IsCancelled)
{
monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Finalizing environment changes");
environmentRandomizer.FinalizeEnvironment();
}

if (!monitor.IsCancelled && Settings.RandomizeAudio)
{
monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing audio tracks");
new TR1RAudioRandomizer
{
ScriptEditor = scriptEditor,
Levels = levels,
BasePath = wipDirectory,
BackupPath = backupDirectory,
SaveMonitor = monitor,
Settings = Settings
}.Randomize(Settings.AudioSeed);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@

namespace TRRandomizerCore.Editors;

public class TR2RandoEditor : TR2LevelEditor, ISettingsProvider
public class TR2ClassicEditor : TR2LevelEditor, ISettingsProvider
{
public RandomizerSettings Settings { get; private set; }

public TR2RandoEditor(TRDirectoryIOArgs args, TREdition edition)
public TR2ClassicEditor(TRDirectoryIOArgs args, TREdition edition)
: base(args, edition) { }

protected override void ApplyConfig(Config config)
{
Settings = new RandomizerSettings
Settings = new()
{
ExcludableEnemies = JsonConvert.DeserializeObject<Dictionary<short, string>>(File.ReadAllText(@"Resources\TR2\Restrictions\excludable_enemies.json"))
};
Expand Down
Loading

0 comments on commit ca13dac

Please sign in to comment.