HollowKnightAltEntrancesAPMod/Mod/Archipelago.HollowKnight/IC/RM/HelperPlatformBuilder.cs
2025-10-12 19:15:58 -04:00

179 lines
11 KiB
C#

using Archipelago.HollowKnight.SlotDataModel;
using ItemChanger;
using System.Collections.Generic;
using SD = ItemChanger.Util.SceneDataUtil;
namespace Archipelago.HollowKnight.IC.RM
{
public static class HelperPlatformBuilder
{
public static IBool hasWalljump = new PDBool(nameof(PlayerData.hasWalljump));
public static IBool hasWalljumpLeft = new PDBool(nameof(ItemChanger.Modules.SplitClaw.hasWalljumpLeft));
public static IBool hasWalljumpRight = new PDBool(nameof(ItemChanger.Modules.SplitClaw.hasWalljumpRight));
public static IBool hasDoubleJump = new PDBool(nameof(PlayerData.hasDoubleJump));
public static IBool lacksLeftClaw = new Negation(new Disjunction(hasWalljump, hasWalljumpLeft));
public static IBool lacksLeftVertical = new Negation(new Disjunction(hasWalljump, hasDoubleJump, hasWalljumpLeft));
public static IBool lacksRightClaw = new Negation(new Disjunction(hasWalljump, hasWalljumpRight));
public static IBool lacksRightVertical = new Negation(new Disjunction(hasWalljump, hasDoubleJump, hasWalljumpRight));
public static IBool lacksAnyClaw = new Negation(new Disjunction(hasWalljump, hasWalljumpLeft, hasWalljumpRight));
public static IBool lacksAnyVertical = new Negation(new Disjunction(hasWalljump, hasDoubleJump, hasWalljumpLeft, hasWalljumpRight));
public static void AddStartLocationRequiredPlatforms(SlotOptions options)
{
string startLocationName = options.StartLocationName ?? StartLocationNames.Kings_Pass;
switch (startLocationName)
{
// Platforms to allow escaping the Hive start regardless of difficulty or initial items
case StartLocationNames.Hive:
ItemChangerMod.AddDeployer(new SmallPlatform { SceneName = SceneNames.Hive_03, X = 58.5f, Y = 134f, Test = lacksRightClaw });
ItemChangerMod.AddDeployer(new SmallPlatform { SceneName = SceneNames.Hive_03, X = 58.5f, Y = 138.5f, Test = lacksAnyVertical });
break;
// Drop the vine platforms and add small platforms for jumping up.
case StartLocationNames.Far_Greenpath:
ItemChangerMod.AddDeployer(new SmallPlatform { SceneName = SceneNames.Fungus1_13, X = 45f, Y = 16.5f, Test = lacksLeftClaw });
ItemChangerMod.AddDeployer(new SmallPlatform { SceneName = SceneNames.Fungus1_13, X = 64f, Y = 16.5f, Test = lacksRightClaw });
SD.Save(SceneNames.Fungus1_13, "Vine Platform (1)");
SD.Save(SceneNames.Fungus1_13, "Vine Platform (2)");
break;
// With the Lower Greenpath start, getting to the rest of Greenpath requires
// cutting the vine to the right of the vessel fragment.
case StartLocationNames.Lower_Greenpath:
if (options.RandomizeNail)
{
SD.Save(SceneNames.Fungus1_13, "Vine Platform");
}
break;
}
}
public static void AddConveniencePlatforms(SlotOptions options)
{
// FUTURE: when we support room rando, this should be updated based on transition placements.
HashSet<string> targetNames = new();
string startLocationName = options.StartLocationName ?? StartLocationNames.Kings_Pass;
if (!options.ExtraPlatforms)
{
return;
}
// Platforms to climb out from basin wanderer's journal
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Abyss_02, X = 128.3f, Y = 7f, Test = lacksLeftClaw });
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Abyss_02, X = 128.3f, Y = 11f, Test = lacksLeftClaw });
// Platforms to climb up to tram in basin from left with no items
if (!targetNames.Contains($"{SceneNames.Abyss_03}[bot1]"))
{
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Abyss_03, X = 34f, Y = 7f, Test = lacksRightVertical });
}
// Platform to climb out of Abyss with only wings
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Abyss_06_Core, X = 88.6f, Y = 263f, Test = lacksLeftClaw });
// Platforms to climb back up from pale ore with no items
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Abyss_17, X = 164.7f, Y = 30f, Test = lacksRightVertical });
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Abyss_17, X = 99.5f, Y = 12.5f, Test = lacksRightVertical });
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Abyss_17, X = 117.7f, Y = 18.8f, Test = lacksRightClaw });
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Abyss_17, X = 114.3f, Y = 23f, Test = lacksAnyVertical });
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Abyss_17, X = 117.7f, Y = 7f, Test = lacksAnyClaw });
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Abyss_17, X = 117.7f, Y = 10.8f, Test = lacksAnyClaw });
// Platforms to remove softlock with wings at simple key in basin
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Abyss_20, X = 26.5f, Y = 13f, Test = lacksAnyClaw });
// Platform for returning to Gorb landing
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Cliffs_02, X = 32.3f, Y = 27.7f, Test = lacksAnyVertical });
// Platform to return from Deepnest mimic grub room
if (!targetNames.Contains($"{SceneNames.Deepnest_01b}[right2]")
&& !targetNames.Contains($"{SceneNames.Deepnest_02}[left1]")
&& !targetNames.Contains($"{SceneNames.Deepnest_02}[right1]"))
{
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Deepnest_01b, X = 48.3f, Y = 40f, Test = lacksAnyVertical });
}
// Platforms to return from the Deepnest_02 geo rocks without vertical
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Deepnest_02, X = 26f, Y = 12f, Test = lacksAnyClaw });
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Deepnest_02, X = 26f, Y = 16f, Test = lacksAnyClaw });
// Platform to escape the Deepnest mimic room when mimics may not be present
if (options.RandomizeMimics)
{
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Deepnest_36, X = 26f, Y = 11f, Test = lacksLeftVertical });
}
// Platforms to climb back up from Mantis Lords with only wings
if (!targetNames.Contains($"{SceneNames.Fungus2_15}[left1]")
&& !targetNames.Contains($"{SceneNames.Fungus2_25}[top1]")
&& !targetNames.Contains($"{SceneNames.Fungus2_25}[top2]"))
{
for (int i = 0; i < 2; i++)
{
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Fungus2_15, X = 48f + 2 * i, Y = 15f + 10 * i, Test = lacksRightClaw });
}
}
// Platforms to prevent softlock on lever on the way to love key.
for (int i = 0; i < 2; i++)
{
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Fungus3_05, X = 65.7f, Y = 11f + 4.5f * i, Test = lacksRightClaw });
}
if (startLocationName != StartLocationNames.Hive)
{
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Hive_03, X = 58.5f, Y = 134f, Test = lacksAnyVertical });
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Hive_03, X = 58.5f, Y = 138.5f, Test = lacksAnyVertical });
}
// Move the load in colo downward to prevent bench soft lock
if (!targetNames.Contains($"{SceneNames.Room_Colosseum_02}[top2]")
&& !targetNames.Contains($"{SceneNames.Room_Colosseum_Spectate}[right1]"))
{
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Room_Colosseum_02, X = 43.5f, Y = 45f, Test = lacksAnyClaw });
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Room_Colosseum_02, X = 43.5f, Y = 49.5f, Test = lacksAnyClaw });
}
// Platform to escape from the geo rock above Lemm
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Ruins1_05c, X = 26.6f, Y = 73.2f, Test = lacksAnyVertical });
// Platforms to climb back up to King's Pass with no items
if (!targetNames.Contains($"{SceneNames.Town}[right1]") && startLocationName == StartLocationNames.Kings_Pass)
{
for (int i = 0; i < 6; i++)
{
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Town, X = 20f - 2 * (i % 2), Y = 5f * i + 15f, Test = lacksLeftClaw });
}
}
// Platforms to prevent itemless softlock when checking left waterways
if (!targetNames.Contains($"{SceneNames.Waterways_04}[left1]")
&& !targetNames.Contains($"{SceneNames.Waterways_04}[left2]")
&& !targetNames.Contains($"{SceneNames.Waterways_04b}[left1]")
&& !targetNames.Contains($"{SceneNames.Waterways_09}[left1]")
&& startLocationName != StartLocationNames.West_Waterways)
{
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Waterways_04, X = 148f, Y = 23.1f, Test = lacksAnyVertical });
ItemChangerMod.AddDeployer(new SmallPlatform() { SceneName = SceneNames.Waterways_04, X = 139f, Y = 32f, Test = lacksAnyVertical });
ItemChangerMod.AddDeployer(new SmallPlatform()
{
SceneName = SceneNames.Waterways_04,
X = 107f,
Y = 10f,
Test = options.RandomizeSwim ? new PDBool("canSwim") : null
});
ItemChangerMod.AddDeployer(new SmallPlatform()
{
SceneName = SceneNames.Waterways_04,
X = 107f,
Y = 15f,
Test = options.RandomizeSwim ? new PDBool("canSwim") : null
});
}
}
}
}