Skip to content

Commit

Permalink
LostArtefacts#241 TR3 Mirroring
Browse files Browse the repository at this point in the history
- Main level mirroring implemented for TR3, including the minor environment changes needed for awkward doors and suchlike in each level.
- Function added to mirror a model, but this is only possible for ones that have only one mesh and no animations (Slot2 in Antarctica for example).
- Move slot function implemented for TR3.
- Mirroring option made available in UI (no other environment options yet).
  • Loading branch information
lahm86 committed Dec 20, 2021
1 parent 8aa1fa5 commit 62233a2
Show file tree
Hide file tree
Showing 23 changed files with 966 additions and 68 deletions.
1 change: 1 addition & 0 deletions TREnvironmentEditor/Model/EMType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public enum EMType

// Models
ImportModel = 141,
MirrorModel = 142,

// NOOP/Placeholder
NOOP = 1000
Expand Down
41 changes: 36 additions & 5 deletions TREnvironmentEditor/Model/Types/Entities/EMMoveSlotFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,40 @@ public override void ApplyToLevel(TR2Level level)
}
}

if (MoveSlot(control, slot, roomNumber, currentSector, newSector, currentFlipSector, newFlipSector))
{
control.WriteToLevel(level);
}
}

public override void ApplyToLevel(TR3Level level)
{
FDControl control = new FDControl();
control.ParseFromLevel(level);

TR2Entity slot = level.Entities[EntityIndex];
TRRoomSector currentSector = FDUtilities.GetRoomSector(slot.X, slot.Y, slot.Z, slot.Room, level, control);
short roomNumber = (short)ConvertItemNumber(Location.Room, level.NumRooms);
TRRoomSector newSector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, roomNumber, level, control);

// Check if there is also a trigger in the flip map if we are moving the slot within the same room
TRRoomSector currentFlipSector = null;
TRRoomSector newFlipSector = null;
short altRoom = level.Rooms[slot.Room].AlternateRoom;
if (slot.Room == roomNumber && altRoom != -1)
{
currentFlipSector = FDUtilities.GetRoomSector(slot.X, slot.Y, slot.Z, altRoom, level, control);
newFlipSector = FDUtilities.GetRoomSector(Location.X, Location.Y, Location.Z, altRoom, level, control);
}

if (MoveSlot(control, slot, roomNumber, currentSector, newSector, currentFlipSector, newFlipSector))
{
control.WriteToLevel(level);
}
}

protected bool MoveSlot(FDControl control, TR2Entity slot, short roomNumber, TRRoomSector currentSector, TRRoomSector newSector, TRRoomSector currentFlipSector, TRRoomSector newFlipSector)
{
slot.X = Location.X;
slot.Y = Location.Y;
slot.Z = Location.Z;
Expand All @@ -62,13 +96,10 @@ public override void ApplyToLevel(TR2Level level)
MoveTriggers(control, currentFlipSector, newFlipSector);
}

control.WriteToLevel(level);
return true;
}
}

public override void ApplyToLevel(TR3Level level)
{
throw new System.NotImplementedException();
return false;
}

protected void MoveTriggers(FDControl control, TRRoomSector currentSector, TRRoomSector newSector)
Expand Down
526 changes: 469 additions & 57 deletions TREnvironmentEditor/Model/Types/Mirroring/EMMirrorFunction.cs

Large diffs are not rendered by default.

123 changes: 123 additions & 0 deletions TREnvironmentEditor/Model/Types/Mirroring/EMMirrorModelFunction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using TRLevelReader.Helpers;
using TRLevelReader.Model;
using TRLevelReader.Model.Enums;
using TRModelTransporter.Model.Textures;

namespace TREnvironmentEditor.Model.Types
{
public class EMMirrorModelFunction : BaseEMFunction
{
public uint[] ModelIDs { get; set; }

public override void ApplyToLevel(TR2Level level)
{
List<TRMesh> meshes = new List<TRMesh>();
foreach (uint modelID in ModelIDs)
{
TRMesh[] modelMeshes = TRMeshUtilities.GetModelMeshes(level, (TR2Entities)modelID);
if (modelMeshes == null || modelMeshes.Length > 1)
{
throw new NotSupportedException("Only models with single meshes can be mirrored.");
}

meshes.Add(modelMeshes[0]);
}

MirrorObjectTextures(MirrorMeshes(meshes), level.ObjectTextures);
}

public override void ApplyToLevel(TR3Level level)
{
List<TRMesh> meshes = new List<TRMesh>();
foreach (uint modelID in ModelIDs)
{
TRMesh[] modelMeshes = TRMeshUtilities.GetModelMeshes(level, (TR3Entities)modelID);
if (modelMeshes == null || modelMeshes.Length > 1)
{
throw new NotSupportedException("Only models with single meshes can be mirrored.");
}

meshes.Add(modelMeshes[0]);
}

MirrorObjectTextures(MirrorMeshes(meshes), level.ObjectTextures);
}

private ISet<ushort> MirrorMeshes(List<TRMesh> meshes)
{
ISet<ushort> textureReferences = new HashSet<ushort>();

foreach (TRMesh mesh in meshes)
{
foreach (TRVertex vert in mesh.Vertices)
{
vert.X *= -1;
}

if (mesh.Normals != null)
{
foreach (TRVertex norm in mesh.Normals)
{
norm.X *= -1;
}
}

foreach (TRFace4 f in mesh.TexturedRectangles)
{
Swap(f.Vertices, 0, 3);
Swap(f.Vertices, 1, 2);
textureReferences.Add((ushort)(f.Texture & 0x0fff));
}

foreach (TRFace4 f in mesh.ColouredRectangles)
{
Swap(f.Vertices, 0, 3);
Swap(f.Vertices, 1, 2);
}

foreach (TRFace3 f in mesh.TexturedTriangles)
{
Swap(f.Vertices, 0, 2);
textureReferences.Add((ushort)(f.Texture & 0x0fff));
}

foreach (TRFace3 f in mesh.ColouredTriangles)
{
Swap(f.Vertices, 0, 2);
}
}

return textureReferences;
}

private void MirrorObjectTextures(ISet<ushort> textureReferences, TRObjectTexture[] objectTextures)
{
foreach (ushort textureRef in textureReferences)
{
IndexedTRObjectTexture texture = new IndexedTRObjectTexture
{
Texture = objectTextures[textureRef]
};

if (texture.IsTriangle)
{
Swap(texture.Texture.Vertices, 0, 2);
}
else
{
Swap(texture.Texture.Vertices, 0, 3);
Swap(texture.Texture.Vertices, 1, 2);
}
}
}

private static void Swap<T>(T[] arr, int pos1, int pos2)
{
T temp = arr[pos1];
arr[pos1] = arr[pos2];
arr[pos2] = temp;
}
}
}
3 changes: 3 additions & 0 deletions TREnvironmentEditor/Parsing/EMConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,11 @@ private object ReadEMType(JObject jo)
case EMType.CopyVertexAttributes:
return JsonConvert.DeserializeObject<EMCopyVertexAttributesFunction>(jo.ToString(), _resolver);

// Models
case EMType.ImportModel:
return JsonConvert.DeserializeObject<EMImportModelFunction>(jo.ToString(), _resolver);
case EMType.MirrorModel:
return JsonConvert.DeserializeObject<EMMirrorModelFunction>(jo.ToString(), _resolver);

// NOOP
case EMType.NOOP:
Expand Down
15 changes: 15 additions & 0 deletions TRLevelReader/Helpers/TR3EntityUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -618,5 +618,20 @@ public static bool CanSharePickupSpace(TR3Entities entity)
|| IsLightType(entity)
|| entity == TR3Entities.Lara;
}

public static List<TR3Entities> DoorTypes()
{
return new List<TR3Entities>
{
TR3Entities.Door1, TR3Entities.Door2, TR3Entities.Door3,
TR3Entities.Door4, TR3Entities.Door5, TR3Entities.Door6,
TR3Entities.Door7, TR3Entities.Door8
};
}

public static bool IsDoorType(TR3Entities entity)
{
return DoorTypes().Contains(entity);
}
}
}
2 changes: 1 addition & 1 deletion TRRandomizerCore/Editors/TR3RandoEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ protected override void SaveImpl(AbstractTRScriptEditor scriptEditor, TRSaveMoni

if (!monitor.IsCancelled)
{
monitor.FireSaveStateBeginning(TRSaveCategory.Custom, /*Settings.RandomizeEnvironment ? "Randomizing environment" : */"Applying default environment packs");
monitor.FireSaveStateBeginning(TRSaveCategory.Custom, Settings.RandomizeEnvironment ? "Randomizing environment" : "Applying default environment packs");
new TR3EnvironmentRandomizer
{
ScriptEditor = tr23ScriptEditor,
Expand Down
14 changes: 12 additions & 2 deletions TRRandomizerCore/Randomizers/TR3/TR3EnvironmentRandomizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace TRRandomizerCore.Randomizers
{
public class TR3EnvironmentRandomizer : BaseTR3Randomizer
{
internal bool EnforcedModeOnly => true;//!Settings.RandomizeEnvironment;
internal bool EnforcedModeOnly => !Settings.RandomizeEnvironment;
internal TR3TextureMonitorBroker TextureMonitor { get; set; }

private List<EMType> _disallowedTypes;
Expand Down Expand Up @@ -62,7 +62,17 @@ public override void Randomize(int seed)

private void RandomizeEnvironment(TR3CombinedLevel level)
{
EMEditorMapping mapping = EMEditorMapping.Get(GetResourcePath(@"TR3\Environment\" + level.Name + "-Environment.json"));
string json = @"TR3\Environment\" + level.Name + "-Environment.json";
if (IsJPVersion)
{
string jpJson = @"TR3\Environment\" + level.Name + "-JP-Environment.json";
if (ResourceExists(jpJson))
{
json = jpJson;
}
}

EMEditorMapping mapping = EMEditorMapping.Get(GetResourcePath(json));
if (mapping != null)
{
ApplyMappingToLevel(level, mapping);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,48 @@
}
]
}
],

"Mirrored": [
{
"Comments": "The generators in this room are awkward so need rotating and shifting slightly.",
"EMType": 44,
"EntityIndex": 118,
"TargetLocation": {
"X": 33024,
"Y": -4864,
"Z": 76288,
"Room": 172,
"Angle": 16384
}
},
{
"EMType": 44,
"EntityIndex": 119,
"TargetLocation": {
"X": 32256,
"Y": -4864,
"Z": 74496,
"Room": 172,
"Angle": -32768
}
},
{
"Comments": "Mirror the Slot2Empty and Slot2Full models.",
"EMType": 142,
"ModelIDs": [ 214, 218 ]
},
{
"Comments": "Move door #36 so it's less awkward.",
"EMType": 44,
"EntityIndex": 36,
"TargetLocation": {
"X": 55808,
"Y": -4864,
"Z": 23040,
"Room": 131,
"Angle": 16384
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -324,5 +324,14 @@
}
]
}
],

"Mirrored": [
{
"Comments": "Make door #182 a split one so Lara can pass.",
"EMType": 45,
"EntityIndex": 182,
"NewEntityType": 137
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -191,5 +191,14 @@
}
]
}
],

"Mirrored": [
{
"Comments": "Make door #125 a vertical one as this corridor is awkward.",
"EMType": 45,
"EntityIndex": 125,
"NewEntityType": 136
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,20 @@
}
]
}
],

"Mirrored": [
{
"Comments": "Move door #40 so the maze can be beaten",
"EMType": 44,
"EntityIndex": 40,
"TargetLocation": {
"X": 40448,
"Y": -512,
"Z": 27136,
"Room": 51,
"Angle": -32768
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"Mirrored": [
{
"Comments": "Convert two of the planes to the other kind.",
"EMType": 45,
"EntityIndex": 8,
"NewEntityType": 351
},
{
"EMType": 45,
"EntityIndex": 113,
"NewEntityType": 351
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"Mirrored": [
{
"Comments": "Move door #34 otherwise Lara can't pass.",
"EMType": 44,
"EntityIndex": 34,
"TargetLocation": {
"X": 48640,
"Y": -8448,
"Z": 36352,
"Room": 43,
"Angle": -32768
}
}
]
}
Loading

0 comments on commit 62233a2

Please sign in to comment.