Skip to content

Commit

Permalink
Adjust underwater corner secrets (#764)
Browse files Browse the repository at this point in the history
Resolves #763.
  • Loading branch information
lahm86 authored Sep 12, 2024
1 parent c51d26d commit a1a011f
Show file tree
Hide file tree
Showing 12 changed files with 1,047 additions and 700 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## [Unreleased](https://github.com/LostArtefacts/TR-Rando/compare/V1.9.2...master) - xxxx-xx-xx
- added an option to disable underwater corner secrets (#763)
- fixed dark pickup sprites in TR2R OG graphics (#760)
- fixed gun pickup sprites not showing properly in TR2R Floating Islands and Dragon's Lair OG graphics (#760)
- fixed all placement issues with underwater corner secrets in TR1-3 (#763)
- removed support for 32-bit (#759)

## [V1.9.2](https://github.com/LostArtefacts/TR-Rando/compare/V1.9.1...V1.9.2) - 2024-08-20
Expand Down
131 changes: 124 additions & 7 deletions LocationExport/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ namespace LocationExport;

class Program
{
private const int _uwCornerWallGap = TRConsts.Step4 / 7;
private const int _uwCornerFloorGap = TRConsts.Step1 / 16;

private static TR1LevelControl _reader1;
private static TR2LevelControl _reader2;
private static TR3LevelControl _reader3;
Expand All @@ -30,9 +33,22 @@ static void Main(string[] args)
_allTR1Exclusions = JsonConvert.DeserializeObject<Dictionary<string, List<Location>>>(File.ReadAllText(@"Resources\TR1\Locations\invalid_item_locations.json"));
_allTR2Exclusions = JsonConvert.DeserializeObject<Dictionary<string, List<Location>>>(File.ReadAllText(@"Resources\TR2\Locations\invalid_item_locations.json"));
_allTR3Exclusions = JsonConvert.DeserializeObject<Dictionary<string, List<Location>>>(File.ReadAllText(@"Resources\TR3\Locations\invalid_item_locations.json"));

if (args[0].ToLower() == "export")
{
Export(args);
}
else
{
Adjust(args);
}
}

static void Export(string[] args)
{
Dictionary<string, List<Location>> allLocations = new();

string levelType = args[0].ToUpper();
string levelType = args[1].ToUpper();

if (levelType.EndsWith(".PHD"))
{
Expand All @@ -50,7 +66,7 @@ static void Main(string[] args)
}
else if (levelType.EndsWith(".TR2"))
{
TRFileVersion version = DetectVersion(args[0]);
TRFileVersion version = DetectVersion(args[1]);
if (version == TRFileVersion.TR2)
{
allLocations[levelType] = ExportTR2Locations(levelType);
Expand Down Expand Up @@ -96,14 +112,14 @@ static void Main(string[] args)
{
string outputPath;
string compPath = null;
if (args.Length > 2)
if (args.Length > 3)
{
outputPath = args[2];
compPath = args[1];
outputPath = args[3];
compPath = args[2];
}
else
{
outputPath = args.Length > 1 ? args[1] : levelType + "-Locations.json";
outputPath = args.Length > 2 ? args[2] : levelType + "-Locations.json";
}

// Are we running a diff?
Expand Down Expand Up @@ -221,10 +237,105 @@ private static List<Location> ExportTR3Locations(string lvl)
return generator.Generate(level, exclusions);
}

private static void Adjust(string[] args)
{
if (!Enum.TryParse(args[1].ToUpper(), out TRGameVersion version))
{
return;
}

var allLocs = JsonConvert.DeserializeObject<Dictionary<string, List<Location>>>(File.ReadAllText($@"Resources\{version}\Locations\locations.json"));
var diff = new Dictionary<string, List<Location>>();
foreach (var (lvl, locs) in allLocs)
{
TRLevelBase level;
switch (version)
{
case TRGameVersion.TR1:
level = _reader1.Read(lvl);
break;
case TRGameVersion.TR2:
level = _reader2.Read(lvl);
break;
case TRGameVersion.TR3:
level = _reader3.Read(lvl);
break;
default:
return;
}


foreach (var loc in locs)
{
var clone = loc.Clone();
switch (version)
{
case TRGameVersion.TR1:
AdjustLocation(loc, ((TR1Level)level).Rooms, level.FloorData);
break;
case TRGameVersion.TR2:
AdjustLocation(loc, ((TR2Level)level).Rooms, level.FloorData);
break;
case TRGameVersion.TR3:
AdjustLocation(loc, ((TR3Level)level).Rooms, level.FloorData);
break;
}


if (!clone.IsEquivalent(loc))
{
if (!diff.ContainsKey(lvl))
{
diff[lvl] = new();
}
diff[lvl].Add(loc);
}
}
}

File.WriteAllText("diff.json", JsonConvert.SerializeObject(diff, Formatting.Indented));
}

private static void AdjustLocation<R>(Location location, List<R> rooms, FDControl floorData)
where R : TRRoom
{
R room = rooms[location.Room];
if (!room.ContainsWater
&& (room.AlternateRoom == -1 || !rooms[room.AlternateRoom].ContainsWater))
{
return;
}

int dx = location.X & TRConsts.WallMask;
int dz = location.Z & TRConsts.WallMask;

int xWallTest = dx >= TRConsts.Step2 ? TRConsts.Step2 : -TRConsts.Step2;
int zWallTest = dz >= TRConsts.Step2 ? TRConsts.Step2 : -TRConsts.Step2;

int height = floorData.GetFloorHeight(location.X, location.Z, location.Room, rooms, false);
int adjHeightX = floorData.GetFloorHeight(location.X + xWallTest, location.Z, location.Room, rooms, false);
int adjHeightZ = floorData.GetFloorHeight(location.X, location.Z + zWallTest, location.Room, rooms, false);

if (!(Math.Abs(height - adjHeightX) > TRConsts.Step1 && Math.Abs(height - adjHeightZ) > TRConsts.Step1))
{
return;
}

int xShift = dx >= TRConsts.Step2 ? TRConsts.Step4 - _uwCornerWallGap : _uwCornerWallGap;
int zShift = dz >= TRConsts.Step2 ? TRConsts.Step4 - _uwCornerWallGap : _uwCornerWallGap;

location.X = (location.X & ~TRConsts.WallMask) + xShift;
location.Z = (location.Z & ~TRConsts.WallMask) + zShift;

int y = floorData.GetFloorHeight(location.X, location.Z, location.Room, rooms, false) - _uwCornerFloorGap;
location.Y = Math.Min(location.Y, y);
}

private static void Usage()
{
Console.WriteLine();
Console.WriteLine("Usage: LocationExport [tr1 | tr2 | tr3 | tr3g | *.phd | *.tr2] [export_path.json] [previous_path.json]");
Console.WriteLine("Usage: LocationExport export [tr1 | tr2 | tr3 | tr3g | *.phd | *.tr2] [export_path.json] [previous_path.json]");
Console.WriteLine("Usage: LocationExport adjust [tr1 | tr2 | tr3]");
Console.WriteLine();

Console.WriteLine("Target Levels");
Expand Down Expand Up @@ -262,5 +373,11 @@ private static void Usage()
Console.ResetColor();
Console.WriteLine("\t\tGenerate all locations for TR3 and output only the differences to new_locations.json (excludes old_loctions.json)");
Console.WriteLine();

Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("\tLocationExport adjust");
Console.ResetColor();
Console.WriteLine("\t\tIntended to adjust underwater corner secret locations. A diff output will be generated as diff.json");
Console.WriteLine();
}
}
5 changes: 5 additions & 0 deletions Resources/trview/randomizer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
"display": "Requires Glitch",
"type": "boolean"
},
"IsUWCorner": {
"default": false,
"display": "UW corner",
"type": "boolean"
},
"VehicleRequired": {
"default": false,
"display": "Vehicle Required",
Expand Down
3 changes: 3 additions & 0 deletions TRRandomizerCore/Editors/RandomizerSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class RandomizerSettings
public GameMode GameMode { get; set; }
public GlobeDisplayOption GlobeDisplay { get; set; }
public bool HardSecrets { get; set; }
public bool EnableUWCornerSecrets { get; set; }
public ItemMode ItemMode { get; set; }
public WeaponDifficulty WeaponDifficulty { get; set; }
public bool IncludeKeyItems { get; set; }
Expand Down Expand Up @@ -207,6 +208,7 @@ public void ApplyConfig(Config config)
RandomizeSecrets = config.GetBool(nameof(RandomizeSecrets));
SecretSeed = config.GetInt(nameof(SecretSeed), defaultSeed);
HardSecrets = config.GetBool(nameof(HardSecrets));
EnableUWCornerSecrets = config.GetBool(nameof(EnableUWCornerSecrets), true);
GlitchedSecrets = config.GetBool(nameof(GlitchedSecrets));
GuaranteeSecrets = config.GetBool(nameof(GuaranteeSecrets), true);
SecretRewardMode = (TRSecretRewardMode)config.GetEnum(nameof(SecretRewardMode), typeof(TRSecretRewardMode), TRSecretRewardMode.Room);
Expand Down Expand Up @@ -387,6 +389,7 @@ public void StoreConfig(Config config)
config[nameof(RandomizeSecrets)] = RandomizeSecrets;
config[nameof(SecretSeed)] = SecretSeed;
config[nameof(HardSecrets)] = HardSecrets;
config[nameof(EnableUWCornerSecrets)] = EnableUWCornerSecrets;
config[nameof(GlitchedSecrets)] = GlitchedSecrets;
config[nameof(GuaranteeSecrets)] = GuaranteeSecrets;
config[nameof(SecretRewardMode)] = SecretRewardMode;
Expand Down
1 change: 1 addition & 0 deletions TRRandomizerCore/Helpers/Location.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class Location : ITRLocatable, ICloneable
public short Room { get; set; }
public bool RequiresGlitch { get; set; }
public Difficulty Difficulty { get; set; }
public bool IsUWCorner { get; set; }
public ItemRange Range { get; set; }
public RoomType RoomType { get; set; }
public bool VehicleRequired { get; set; }
Expand Down
5 changes: 5 additions & 0 deletions TRRandomizerCore/Randomizers/Shared/SecretPicker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,11 @@ public bool TestLocation(Location location, List<Location> usedLocations, bool i
return false;
}

if (location.IsUWCorner && !Settings.EnableUWCornerSecrets)
{
return false;
}

if (isMirrored && location.LevelState == LevelState.NotMirrored)
{
return false;
Expand Down
5 changes: 5 additions & 0 deletions TRRandomizerCore/Randomizers/TR2/Shared/TR2SecretAllocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ public IEnumerable<string> GetPacks()

public void PlaceAllSecrets(string levelName, TR2Level level)
{
if (!_locations.ContainsKey(levelName))
{
return;
}

Queue<int> existingIndices = new();
for (int i = 0; i < level.Entities.Count; i++)
{
Expand Down
Loading

0 comments on commit a1a011f

Please sign in to comment.