Skip to content

Commit

Permalink
Add support for TR1X 3.0 (#574)
Browse files Browse the repository at this point in the history
TombATI support dropped, TR1X 3.0 file detection added, and TR1X 3.0 features added - enemy item drops, plus settings for the development console, UW rolls, eidos logo control, frame buffering and lean jumping.
All references to T1M, Tomb1Main, TR1Main changed to TR1X. Removed TombATI docs.
UI options added for buffering, Eidos logo, dev console, dropped gun conversion, underwater rolling and lean jumping.
All enemies in TR1 can now drop items, excluding empty eggs and non-oneshot Pierre.
Normal drop allocation is done using a TR2+ approach, so we just let item rando move the entities and if any end up on the same spot as a suitable enemy, the gameflow is updated accordingly and the physical item hidden.
Extended the check at the end of Tihocan so we will either allocate Pierre's key items to whichever enemy is here, or create physical pickups and allow key item rando to move them.
If enemy rando is off, the usual enemies will still drop items but their types may change.

Resolves #572.
  • Loading branch information
lahm86 authored Nov 17, 2023
1 parent 803b146 commit e9fbce1
Show file tree
Hide file tree
Showing 37 changed files with 796 additions and 873 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
- added an option to control whether or not key items can be placed in locations that rely on return paths (#474)
- added an option to control key item continuity e.g. The Seraph being placed as an item in Barkhang Monastery if The Deck hasn't been visited (#474)
- added item randomization to Home Sweet Home, provided the level starts with weapons and ammo already (#474)
- added support for TR1X 3.0, including randomized enemy item drops (#572)
- fixed spelling mistakes in TR1 French gamestring localization (#560)
- fixed a key item softlock in Diving Area (#564)
- improved changelog, readme and contributing documentation
- improved regular item, key item, and secret item location generation and selection in TR1-3 (#474)
- removed TombATI support (#572)
- replaced purist mode with explicit options for adding return paths, fixing OG bugs, and fixing shortcuts (#563)

## [V1.7.3](https://github.com/LostArtefacts/TR-Rando/compare/V1.7.2...V1.7.3) - 2023-09-30
Expand Down
Binary file modified Deps/TRGE.Coord.dll
Binary file not shown.
Binary file modified Deps/TRGE.Core.dll
Binary file not shown.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ For keeping track of levels while you play, check out the [TRRandoTracker](https
* Trxye - Lots of ideas and development help.
* Towandaa - Lots of ideas and contributions, including secret, vehicle and sprite randomization.
* Leoc1995 - For TR1 puzzle inspiration and contributing enemy variants from his [TRLEs](https://trcustoms.org/users/854).
* Dash and Walkawayy - For providing great support and rando-related additions to [Tomb1Main](https://github.com/LostArtefacts/Tomb1Main).
* Dash and Walkawayy - For providing great support and rando-related additions to [TR1X](https://github.com/LostArtefacts/TR1X).
* Jimmy Beon - Providing us with an excellent assortment of custom textures for use in rando.
* Topixtor - For endless testing to fix issues such as the opera house/barkhang entity freeze and mirrored levels, and providing enemy variations from his [TRLEs](https://trcustoms.org/users/927).
* Radgryd - For endless TR1 testing and lots of great ideas for the rando.
Expand Down
24 changes: 10 additions & 14 deletions Resources/Documentation/ENEMIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,15 @@ The following enemy restrictions are in place when using "Default" restriction m
Torso is restricted to appear only in certain rooms where there is a little more space to fight. He will always appear in Great Pyramid in the usual place to activate the door, unless `Replace required enemies` is enabled. In this case, an alternative way to open the door will be provided.

### Pierre
Pierre will always be killable, as allocating runaway Pierres using current enemy positioning is awkward, given that when they spawn they deactivate the previous one (or with TombATI the newly triggered one doesn't replace the existing). Pierre will also always drop the scion, magnums and a key. If Pierre is not present at the end of Tihocan, a key will be added to pickup (this location will be randomized if key item randomization is enabled).
Pierre will always be killable, as allocating runaway Pierres using current enemy positioning is awkward, given that when they spawn they deactivate the previous one. Where Pierre is needed at the end of Tomb of Tihocan, there are different outcomes depending on which settings you have enabled.
- If key item randomization is enabled, then a key and the scion will be added as physical items to collect, and their location will be randomized.
- If key item randomization is not enabled:
- Whichever enemy is in Pierre's place will drop the key items, if that enemy is capable of dropping items.
- Otherwise, physical pickups are added per above, but their locations are fixed.

### Larson
By default, Larson will end the level in Tomb of Qualopec when he is killed. This can be disabled by selecting `Replace required enemies` in the enemy options window. In this case, an alternative level ending will be added to this level. If this option is *not* enabled, the single default Larson will appear when `Default` restrictions mode is selected; in `No restrictions` mode, he can appear anywhere in the level, and the level will end wherever he is killed.

### SkateboardKid
SkateboardKid is restricted to only appear in Natla's Mines, *unless Tomb1Main is being used*. This is because of an OG bug that can cause a crash, which is present in TombATI but is fixed in Tomb1Main.

### Natla
Natla is restricted to only appear in Great Pyramid, *unless Tomb1Main is being used*. This is because of an OG bug that can cause a crash, which is present in TombATI but is fixed in Tomb1Main.

### Atlanteans
Collectively, there are some limits on Atlanteans per level to avoid extremely difficult areas. There will be a maximum grouping count for the following levels of any of the following enemies.
* Centaur/Centaur Statue
Expand All @@ -57,18 +55,16 @@ Collectively, there are some limits on Atlanteans per level to avoid extremely d
Note that mummies can appear as flying mutants in other levels. This model is present in City of Khamoon but is unused in the original game.

### Bacon Lara
Bacon Lara will always appear in her OG room in Atlantis, *unless the level is mirrored and TombATI is being used*. In this case, an alternative way to open the door will be provided.
Bacon Lara will always appear in her OG room in Atlantis. She may also appear in other levels if puzzle/challenge room randomization is enabled.

## No Restrictions Mode
In Tomb1Main, "No Restrictions" mode will switch off each of the above restrictions, apart from Pierre always being killable.

In TombATI, the following restrictions will always remain:
* Pierre always being killable
* SkateboardKid appearing in Natla's Mines only
* Natla appearing in Great Pyramid only
"No Restrictions" mode will switch off each of the above restrictions, apart from Pierre always being killable.

This mode will also allow land enemies to appear underwater as the engine does not kill them (as in TR2 onwards).

## Item drops
In the original TR1, Pierre, Cowboy, Skateboard Kid and Kold are hard-coded to drop items when they are killed. This is not the case in the randomizer if enemy randomization is enabled. There does however remain a chance for items to be allocated to _any_ suitable enemy type, so make sure to keep your eyes peeled for pickups. See https://github.com/LostArtefacts/TR1X/blob/stable/GAMEFLOW.md#item-drops for more information.

## Enemy Types
Some levels have their total enemy types count increased for more variety. This is a maximum rather than a guaranteed number of types (e.g. for Caves, 5 models will always be imported, but no checks are performed to ensure at least one of each is assigned to entities). Levels in _italics_ remain unchanged.

Expand Down
2 changes: 1 addition & 1 deletion Resources/Documentation/SECRETS.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ The artefact types to collect will change per level. This is in place to ensure
| Pyramid | Gold Idol |

### Secret Count
If [Tomb1Main](https://github.com/rr-/Tomb1Main) is being used, the number of secrets to collect per level can be changed. When you start a level, check Lara's compass to find out how many secrets you need to collect.
If [TR1X](https://github.com/LostArtefacts/TR1X) is being used, the number of secrets to collect per level can be changed. When you start a level, check Lara's compass to find out how many secrets you need to collect.

The options are:

Expand Down
1 change: 1 addition & 0 deletions Resources/trview/plugins/key_items/plugin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ m_KeyNames[1][18389] = "K1 Gold Key (Pierre)"
m_KeyNames[1][18133] = "K1 Gold Key (flip map)"
m_KeyNames[1][18277] = "K2 Rusty Key (boulders)"
m_KeyNames[1][18267] = "K2 Rusty Key (clang-clang)"
m_KeyNames[1][18444] = "Scion (Pierre)"
m_KeyNames[1][19193] = "K1 Sapphire Key (end)"
m_KeyNames[1][19217] = "K1 Sapphire Key (start)"
m_KeyNames[1][20213] = "K1 Sapphire Key (alt ending)"
Expand Down
6 changes: 6 additions & 0 deletions TRLevelControl/Helpers/TR1TypeUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,12 @@ public static List<TR1Type> GetAtlanteanEggEnemies()
};
}

public static bool IsEggType(TR1Type type)
{
return type == TR1Type.AtlanteanEgg
|| type == TR1Type.AdamEgg;
}

public static List<TR1Type> GetSwitchTypes()
{
return new()
Expand Down
1 change: 1 addition & 0 deletions TRLevelControl/Model/Base/Enums/TR1Type.cs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ public enum TR1Type
Tihocan_K1_GoldKeyPierre = 18389,
Tihocan_K2_RustyKeyBoulders = 18277,
Tihocan_K2_RustyKeyClangClang = 18267,
Tihocan_Scion_EndRoom = 18444,

KhamoonKeyItemBase = 19000,
Khamoon_K1_SapphireKeyEnd = 19193,
Expand Down
26 changes: 8 additions & 18 deletions TRRandomizerCore/Editors/TR1RandoEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,8 @@ protected override int GetSaveTarget(int numLevels)
// String rando always runs
target++;

if (_edition.IsCommunityPatch)
{
// Injection checks
target += numLevels;
}
// Injection checks
target += numLevels;

if (Settings.RandomizeStartingHealth)
{
Expand Down Expand Up @@ -123,15 +120,11 @@ protected override void SaveImpl(AbstractTRScriptEditor scriptEditor, TRSaveMoni
string backupDirectory = _io.BackupDirectory.FullName;
string wipDirectory = _io.WIPOutputDirectory.FullName;

bool isTomb1Main = scriptEditor.Edition.IsCommunityPatch;
if (isTomb1Main)
TR1ScriptEditor scriptEd = scriptEditor as TR1ScriptEditor;
if (Settings.DevelopmentMode)
{
TR1ScriptEditor scriptEd = scriptEditor as TR1ScriptEditor;
if (Settings.DevelopmentMode)
{
scriptEd.EnableCheats = true;
}

scriptEd.EnableCheats = true;
scriptEd.EnableConsole = true;
scriptEditor.SaveScript();
}

Expand Down Expand Up @@ -177,7 +170,7 @@ protected override void SaveImpl(AbstractTRScriptEditor scriptEditor, TRSaveMoni
}.Randomize(Settings.GameStringsSeed);
}

if (!monitor.IsCancelled && isTomb1Main)
if (!monitor.IsCancelled)
{
monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Validating data injections");
new TR1InjectionProcessor
Expand Down Expand Up @@ -350,10 +343,7 @@ protected override void SaveImpl(AbstractTRScriptEditor scriptEditor, TRSaveMoni
}
}

if (isTomb1Main)
{
AmendTitleAndCredits(scriptEditor, monitor);
}
AmendTitleAndCredits(scriptEditor, monitor);
}

private void AmendTitleAndCredits(AbstractTRScriptEditor scriptEditor, TRSaveMonitor monitor)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace TRRandomizerCore.Helpers;

public enum T1MInjectionType
public enum TR1XInjectionType
{
General,
Braid,
Expand Down
2 changes: 1 addition & 1 deletion TRRandomizerCore/Levels/TR1CombinedLevel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class TR1CombinedLevel
public TR1Level Data { get; set; }

/// <summary>
/// The scripting information for the level stored in Tomb1Main_gameflow.json5.
/// The scripting information for the level stored in TR1X_gameflow.json5.
/// </summary>
public TR1ScriptedLevel Script { get; set; }

Expand Down
26 changes: 13 additions & 13 deletions TRRandomizerCore/Processors/TR1/TR1InjectionProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,27 @@ namespace TRRandomizerCore.Processors;

public class TR1InjectionProcessor : TR1LevelProcessor
{
private static readonly uint _t1mMagic = 'T' | ('1' << 8) | ('M' << 16) | ('J' << 24);
private static readonly Version _minT1MVersion = new(2, 15);
private static readonly List<T1MInjectionType> _permittedInjections = new()
private static readonly uint _tr1xMagic = 'T' | ('1' << 8) | ('M' << 16) | ('J' << 24);
private static readonly Version _minTR1XVersion = new(3, 0);
private static readonly List<TR1XInjectionType> _permittedInjections = new()
{
T1MInjectionType.LaraAnims,
T1MInjectionType.LaraJumps,
TR1XInjectionType.LaraAnims,
TR1XInjectionType.LaraJumps,
};

public void Run()
{
TR1Script script = ScriptEditor.Script as TR1Script;

bool t1mVersionSupported = script.Edition.ExeVersion != null
&& script.Edition.ExeVersion >= _minT1MVersion;
script.Injections = t1mVersionSupported ?
bool tr1xVersionSupported = script.Edition.ExeVersion != null
&& script.Edition.ExeVersion >= _minTR1XVersion;
script.Injections = tr1xVersionSupported ?
GetSupportedInjections(script.Injections) : null;

foreach (TR1ScriptedLevel level in Levels)
{
LoadLevelInstance(level);
AdjustInjections(_levelInstance, t1mVersionSupported);
AdjustInjections(_levelInstance, tr1xVersionSupported);
SaveLevelInstance();

if (!TriggerProgress())
Expand All @@ -38,9 +38,9 @@ public void Run()
SaveScript();
}

private void AdjustInjections(TR1CombinedLevel level, bool t1mVersionSupported)
private void AdjustInjections(TR1CombinedLevel level, bool tr1xVersionSupported)
{
if (!t1mVersionSupported)
if (!tr1xVersionSupported)
{
level.Script.ResetInjections();
return;
Expand Down Expand Up @@ -72,13 +72,13 @@ private string[] GetSupportedInjections(string[] injections)
}

using BinaryReader reader = new(File.OpenRead(path));
if (reader.ReadUInt32() != _t1mMagic)
if (reader.ReadUInt32() != _tr1xMagic)
{
continue;
}

reader.ReadUInt32(); // Skip version
if (_permittedInjections.Contains((T1MInjectionType)reader.ReadUInt32()))
if (_permittedInjections.Contains((TR1XInjectionType)reader.ReadUInt32()))
{
validInjections.Add(injection);
}
Expand Down
4 changes: 2 additions & 2 deletions TRRandomizerCore/Randomizers/Shared/LocationPicker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class LocationPicker : IRouteManager
private Random _generator;

public Func<Location, bool> TriggerTestAction { get; set; }
public Func<Location, bool> KeyItemTestAction { get; set; }
public Func<Location, bool, bool> KeyItemTestAction { get; set; }
public List<ExtRoomInfo> RoomInfos { get; set; }
public int LevelSize { get; private set; }

Expand Down Expand Up @@ -140,7 +140,7 @@ public Location GetKeyItemLocation<T>(int keyItemID, TREntity<T> entity, bool ha
continue;
}

if (KeyItemTestAction != null && !KeyItemTestAction(newLocation))
if (KeyItemTestAction != null && !KeyItemTestAction(newLocation, hasPickupTrigger))
{
continue;
}
Expand Down
12 changes: 4 additions & 8 deletions TRRandomizerCore/Randomizers/TR1/TR1AudioRandomizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -297,13 +297,12 @@ private static short ImportSoundEffect(TR1Level level, TR1SFXDefinition definiti

private void ImportSpeechSFX(TR1CombinedLevel level)
{
if (!ScriptEditor.Edition.IsCommunityPatch
|| !(ScriptEditor as TR1ScriptEditor).FixSpeechesKillingMusic)
if (!(ScriptEditor as TR1ScriptEditor).FixSpeechesKillingMusic)
{
return;
}

// T1M can play enemy speeches as SFX to avoid killing the current
// TR1X can play enemy speeches as SFX to avoid killing the current
// track, so ensure that the required data is in the level if any
// of these are used on the floor.

Expand Down Expand Up @@ -352,11 +351,8 @@ private void RandomizeWibble(TR1CombinedLevel level)
details.Wibble = true;
}

if (ScriptEditor.Edition.IsCommunityPatch)
{
(ScriptEditor.Script as TR1Script).EnablePitchedSounds = true;
ScriptEditor.SaveScript();
}
(ScriptEditor as TR1ScriptEditor).EnablePitchedSounds = true;
ScriptEditor.SaveScript();
}
}
}
Loading

0 comments on commit e9fbce1

Please sign in to comment.