-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resolves #756.
- Loading branch information
Showing
19 changed files
with
471 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# TR I-III Remastered Options | ||
|
||
Note that for TR I-III Remastered, the options that are available to randomize are much more limited than the classics. The following table shows what can be randomized; the remaining options will be greyed out in the UI. | ||
|
||
| Aspect | TR1R | TR2R | TR3R | Notes | | ||
|-|-|-|-|-| | ||
| Level sequencing | Yes | Yes | No | Some levels cannot be moved because of hard-coded logic in-game. For TR3, there are too many issues to work around to make this feature feasible. | | ||
| Unarmed/ammoless levels | No | No | No | This is hard-coded in the games and cannot be controlled. | | ||
| Night mode/VFX/sunsets | No | No | No | Currently, remastered rooms cannot be manipulated. | | ||
| Secrets | Yes | Yes | Yes | - | | ||
| Items | Yes | Yes | Yes | - | | ||
| Enemies | Yes | Yes | Yes | - | | ||
| Textures | Yes | Yes | Yes | This currently differs from classic in that textures are moved around between levels rather than hues/colours being changed or swapped. | | ||
| Secret rewards | Yes | No | Yes | TR1 and TR3 will default to stacked rewards because reward rooms are not possible currently. TR2 rewards are hard-coded. | | ||
| Audio | Yes | Yes | Yes | TR1 SFX randomization is slightly more limited than in classic (mainly weapon sounds). | | ||
| Text | Yes | Yes | Yes | Only English is currently supported. | | ||
| Environment | No | No | No | This requires further understanding of the remastered room structures, so is disabled entirely for the time being. | | ||
|
||
## Level Sequencing | ||
|
||
In the classics, the gameflow is entirely configurable, which means we can control everything related to level sequencing changes. The gameflow is hard-coded in TRR, so we have to work around this by renaming data files. This can produce some side effects when levels are off-sequence, which are pointed out below. These are issues that we cannot control and/or fix. | ||
|
||
- Key item names will generally default to "Key Item" | ||
- Lara will always lose her guns/ammo on level slots where this originally happens (i.e. Natla's Mines, Offshore Rig and Home Sweet Home) | ||
- Cutscenes and FMVs are hard-coded, so will always follow the original level sequencing e.g. Larson vs. Lara will always show after the fourth level in TR1R | ||
- You may notice some minor visual glitches in remastered graphics, such as the skybox flickering occasionally in Colosseum | ||
- Ember colours in TR2 will change depending on the sequence e.g. in the Diving Area slot they are green, otherwise they are orange | ||
- In Barkhang Monastery, the Seraph will not be in Lara's inventory. A workaround is provided at the end of this level, such that the Seraph is not required | ||
|
||
Another point to stress is that if you need to look up items in trview, you will need to open the level file whose name matches the sequence you are currently on. For example, if you are playing Great Wall but the sequence is what would normally be Living Quarters, open `LIVING.TR2` rather than `WALL.TR2`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
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 AdjustStrings(TRRScript script) | ||
{ | ||
// 90% of key items will default to "Select Level", which itself it not used | ||
// anywhere else in the game. This makes it look a little better. | ||
script.CommonStrings["SELECTLEV"] = "Key Item"; | ||
} | ||
|
||
public void AdjustMedipacks(TRRScriptedLevel levelScript, List<E> currentItems, List<E> originalItems, | ||
E dummyItem, FDControl floorData, List<int> freeIndices = null) | ||
{ | ||
// 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)); | ||
freeIndices?.ForEach(i => swappableIndices.Enqueue(i)); | ||
|
||
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); | ||
|
||
floorData.GetSwitchKeyTriggers(index) | ||
.ForEach(t => t.SwitchOrKeyRef = (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.Where(e => IsMediType(e.TypeID)) | ||
.Select(e => items.IndexOf(e)) | ||
.ToList(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
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), | ||
}; | ||
_processor.AdjustStrings(ScriptEditor.Script as TRRScript); | ||
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); | ||
} | ||
} |
Oops, something went wrong.