Skip to content

Commit

Permalink
Add experimental horde support
Browse files Browse the repository at this point in the history
  • Loading branch information
Miepee committed Jun 24, 2024
1 parent cd976fb commit a1ed8f1
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 60 deletions.
39 changes: 26 additions & 13 deletions YAMS-LIB/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class Patcher
public static string Version = CreateVersionString();
internal static UndertaleData? gmData;
internal static GlobalDecompileContext? decompileContext;
internal static bool isHorde = false;

private static string CreateVersionString()
{
Expand Down Expand Up @@ -50,6 +51,8 @@ public static void Main(string am2rPath, string outputAm2rPath, string jsonPath)
bool useAnyVersion = Environment.GetEnvironmentVariable("YAMS_USE_ANY_AM2R_VERSION") == "true";
if (!useAnyVersion && !controlCreate.Contains("global.am2r_version = \"V1.5.5\"")) throw new InvalidAM2RVersionException("The selected game is not AM2R 1.5.5!");

isHorde = gmData.Code.ByName("gml_Object_oDrawTitleBG_Create_0").GetGMLCode().Contains("hordeversion = \"The Horde");

// Important invasive modifications done first

// Decouple the item locations from the actual items
Expand Down Expand Up @@ -99,14 +102,18 @@ public static void Main(string am2rPath, string outputAm2rPath, string jsonPath)
gmData.Code.ByName("gml_Object_oSuitChangeFX_Step_0").ReplaceGMLInCode("bg1alpha = 0", "bg1alpha = 0; instance_create(x, y, oSuitChangeFX2);");
gmData.Code.ByName("gml_Object_oSuitChangeFX2_Create_0").ReplaceGMLInCode("image_index = 1133", "sprite_index = sSuitChangeFX2_fusion");

// Don't respawn weapons when offscreen
DontDespawnWeaponsOffscreen.Apply(gmData, decompileContext, seedObject);

// Fix arachnus event value doing x coordinate BS
gmData.Code.ByName("gml_Object_oArachnus_Alarm_11").ReplaceGMLInCode("global.event[103] = x", "global.event[103] = 1");
// Make arachnus item location always spawn in center
gmData.Code.ByName("gml_Room_rm_a2a04_Create").ReplaceGMLInCode("instance_create(global.event[103]", "instance_create(room_width / 2");
if (!isHorde)
{
// Don't respawn weapons when offscreen
DontDespawnWeaponsOffscreen.Apply(gmData, decompileContext, seedObject);

// Fix arachnus event value doing x coordinate BS
gmData.Code.ByName("gml_Object_oArachnus_Alarm_11").ReplaceGMLInCode("global.event[103] = x", "global.event[103] = 1");
// Make arachnus item location always spawn in center
gmData.Code.ByName("gml_Room_rm_a2a04_Create").ReplaceGMLInCode("instance_create(global.event[103]", "instance_create(room_width / 2");

}

// Killing queen should not lock you out of the rest of the game
gmData.Rooms.ByName("rm_a0h01").GameObjects.Remove(gmData.Rooms.ByName("rm_a0h01").GameObjects.First(go => go.X == 4432 && go.Y == 992 && (Math.Abs(go.ScaleY - 4.0) < 0.1)));
Expand Down Expand Up @@ -314,7 +321,8 @@ public static void Main(string am2rPath, string outputAm2rPath, string jsonPath)
AddDNAItem.Apply(gmData, decompileContext, seedObject);

// In vanilla, you need empty ammo for charge beam to work. fix that.
MakeChargeBeamAlwaysHitMetroids.Apply(gmData, decompileContext, seedObject);
if (!isHorde)
MakeChargeBeamAlwaysHitMetroids.Apply(gmData, decompileContext, seedObject);

// Add shortcut between nest and hideout
if (seedObject.Patches.NestPipes)
Expand All @@ -323,7 +331,12 @@ public static void Main(string am2rPath, string outputAm2rPath, string jsonPath)
}

// Move alpha in nest
gmData.Rooms.ByName("rm_a6a09").GameObjects.First(go => go.X == 800 && go.Y == 368 && go.ObjectDefinition.Name.Content == "oMalpha3TriggerProx").CreationCode.ReplaceGMLInCode("if (global.lavastate > 8)", "y = 320; if (false)");
if (!isHorde)
gmData.Rooms.ByName("rm_a6a09").GameObjects.First(go => go.X == 800 && go.Y == 368 && go.ObjectDefinition.Name.Content == "oMalpha3TriggerProx").CreationCode.ReplaceGMLInCode("if (global.lavastate > 8)", "y = 320; if (false)");
else
{
gmData.Rooms.ByName("rm_a6a09").GameObjects.First(go => go.ObjectDefinition.Name.Content == "oMZeta_Cocoon").CreationCode.ReplaceGMLInCode("if (global.lavastate > 8)", "y = 320; if (false)");
}

// Lock these blocks behind a setting because they can make for some interesting changes
gmData.Code.ByName("gml_Room_rm_a0h07_Create").ReplaceGMLInCode(
Expand All @@ -346,7 +359,7 @@ public static void Main(string am2rPath, string outputAm2rPath, string jsonPath)
"if (itemtype == 1) {popup_text(text1);} global.itemtype = itemtype");

// Add required launcher mains
RequiredMains.Apply(gmData, decompileContext, seedObject);
RequiredMains.Apply(gmData, decompileContext, seedObject, isHorde);

// Have new variables for certain events because they are easier to debug via a switch than changing a ton of values
// TODO: move these all into their seperate patches.
Expand Down Expand Up @@ -478,7 +491,7 @@ public static void Main(string am2rPath, string outputAm2rPath, string jsonPath)
characterVarsCode.ReplaceGMLInCode("global.save_room = 0", $"global.save_room = {seedObject.StartingLocation.SaveRoom}");

// Door locks
DoorLockRando.Apply(gmData, decompileContext, seedObject);
DoorLockRando.Apply(gmData, decompileContext, seedObject, isHorde);

// Modify every location item, to give the wished item, spawn the wished text and the wished sprite
ModifyItems.Apply(gmData, decompileContext, seedObject);
Expand Down Expand Up @@ -529,19 +542,19 @@ public static void Main(string am2rPath, string outputAm2rPath, string jsonPath)
MandatoryGeometryChanges.Apply(gmData, decompileContext, seedObject);
ScrewPipeBlocks.Apply(gmData, decompileContext, seedObject);
BombBeforeA3.Apply(gmData, decompileContext, seedObject);
SoftlockPrevention.Apply(gmData, decompileContext, seedObject);
SoftlockPrevention.Apply(gmData, decompileContext, seedObject, isHorde);
DontRespawnBombBlocks.Apply(gmData, decompileContext, seedObject);


// On start, make all rooms show being "unexplored" similar to prime/super rando
ShowFullyUnexploredMap.Apply(gmData, decompileContext, seedObject);
ShowFullyUnexploredMap.Apply(gmData, decompileContext, seedObject, isHorde);

// Force all breakables (except the hidden super blocks) to be visible
ShowUnveiledBreakables.Apply(gmData, decompileContext, seedObject);

// Skip cutscenes and fanfares
GameplayCutsceneSkip.Apply(gmData, decompileContext, seedObject);
SaveCutsceneSkip.Apply(gmData, decompileContext, seedObject);
SaveCutsceneSkip.Apply(gmData, decompileContext, seedObject, isHorde);
SkipItemFanfares.Apply(gmData, decompileContext, seedObject);

// Patch to add room name display near health
Expand Down
10 changes: 5 additions & 5 deletions YAMS-LIB/patches/DoorLockRando.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ namespace YAMS_LIB.patches;

public class DoorLockRando
{
public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject)
public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject, bool isHorde)
{
var characterVarsCode = gmData.Code.ByName("gml_Script_load_character_vars");

// Adjust global event array to be 900
characterVarsCode.ReplaceGMLInCode( """
i = 350
repeat (350)
characterVarsCode.ReplaceGMLInCode( $$"""
i = {{(!isHorde ? "350" : "400")}}
repeat ({{(!isHorde ? "350" : "400")}})
{
i -= 1
global.event[i] = 0
Expand Down Expand Up @@ -77,7 +77,7 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC
var a5Door = gmData.GameObjects.ByName("oDoorA5");
foreach (var room in gmData.Rooms)
{
foreach (var door in room.GameObjects.Where(go => go.ObjectDefinition.Name.Content.StartsWith("oDoor")))
foreach (var door in room.GameObjects.Where(go => go.ObjectDefinition is not null && go.ObjectDefinition.Name.Content.StartsWith("oDoor")))
{
door.ObjectDefinition = a5Door;
}
Expand Down
2 changes: 1 addition & 1 deletion YAMS-LIB/patches/RandovaniaStuff.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC
"d0str = get_text(\"Title-Additions\", \"GameSlot_NewGame_NormalGame\")", "d0str = \"Randovania\";");

// Add Credits
gmData.Code.ByName("gml_Object_oCreditsText_Create_0").ReplaceGMLInCode("/Japanese Community;;;;",
gmData.Code.ByName("gml_Object_oCreditsText_Create_0").ReplaceGMLInCode("/Japanese Community;;",
"/Japanese Community;;;*AM2R Randovania Credits;;*Development;Miepee=JesRight;;*Logic Database;Miepee=JeffGainsNGames;/Esteban 'DruidVorse' Criado;;*Art;ShirtyScarab=AbyssalCreature;;/With contributions from many others;;;");

// Unlock fusion etc. by default
Expand Down
21 changes: 12 additions & 9 deletions YAMS-LIB/patches/RequiredMains.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace YAMS_LIB.patches;

public class RequiredMains
{
public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject)
public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject, bool isHorde)
{
UndertaleCode? characterVarsCode = gmData.Code.ByName("gml_Script_load_character_vars");
// Add main (super) missile / PB launcher
Expand Down Expand Up @@ -37,10 +37,13 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC

// Change GUI For toggle, use a red item sprite instead of green, for hold use a red instead of yellow. For not selected, use a crossed out one.
// Replace Missile GUI
if (isHorde)
drawGuiCode.ReplaceGMLInCode("mslspr = sGUIIceMissile", "mslspr = sGUIMissile");
string mslSprite = !isHorde ? "sGUIMissile" : "mslspr";
drawGuiCode.ReplaceGMLInCode(
"""
$$"""
if (global.currentweapon != 1 || oCharacter.state == 23 || oCharacter.state == 24 || oCharacter.state == 27 || oCharacter.state == 54 || oCharacter.state == 55 || oCharacter.sjball)
draw_sprite(sGUIMissile, 0, (0 + xoff + 1), 4)
draw_sprite({{mslSprite}}, 0, (0 + xoff + 1), 4)
""",
"""
if (((global.currentweapon != 1 || oCharacter.state == 23 || oCharacter.state == 24 || oCharacter.state == 27 || oCharacter.state == 54 || oCharacter.state == 55 || oCharacter.sjball) && (!global.missileLauncher)))
Expand All @@ -49,27 +52,27 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC
draw_sprite(sGUIMissile, 0, (0 + xoff + 1), 4)
""");
drawGuiCode.ReplaceGMLInCode("""
drawGuiCode.ReplaceGMLInCode($$"""
if (oCharacter.armmsl == 0)
draw_sprite(sGUIMissile, 1, (0 + xoff + 1), 4)
draw_sprite({{mslSprite}}, 1, (0 + xoff + 1), 4)
""", """
if (oCharacter.armmsl == 0 && global.missileLauncher)
draw_sprite(sGUIMissile, 1, (0 + xoff + 1), 4)
else if (oCharacter.armmsl == 0 && !global.missileLauncher)
draw_sprite(sGUIMissile, 5, (0 + xoff + 1), 4)
""");
drawGuiCode.ReplaceGMLInCode("""
drawGuiCode.ReplaceGMLInCode($$"""
if (oCharacter.armmsl == 1)
draw_sprite(sGUIMissile, 2, (0 + xoff + 1), 4)
draw_sprite({{mslSprite}}, 2, (0 + xoff + 1), 4)
""", """
if (oCharacter.armmsl == 1 && global.missileLauncher)
draw_sprite(sGUIMissile, 2, (0 + xoff + 1), 4)
else if (oCharacter.armmsl == 1 && !global.missileLauncher)
draw_sprite(sGUIMissile, 3, (0 + xoff + 1), 4)
""");
drawGuiCode.ReplaceGMLInCode("""
drawGuiCode.ReplaceGMLInCode($$"""
if (global.currentweapon == 1)
draw_sprite(sGUIMissile, 1, (0 + xoff + 1), 4)
draw_sprite({{mslSprite}}, 1, (0 + xoff + 1), 4)
""", """
if (global.currentweapon == 1 && global.missileLauncher)
draw_sprite(sGUIMissile, 1, (0 + xoff + 1), 4)
Expand Down
52 changes: 26 additions & 26 deletions YAMS-LIB/patches/geometry/SoftlockPrevention.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace YAMS_LIB.patches.geometry;

public class SoftlockPrevention
{
public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject)
public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileContext, SeedObject seedObject, bool isHorde)
{
UndertaleCode? characterVarsCode = gmData.Code.ByName("gml_Script_load_character_vars");

Expand All @@ -20,48 +20,48 @@ public static void Apply(UndertaleData gmData, GlobalDecompileContext decompileC
go.ObjectDefinition = gmData.GameObjects.ByName("oBlockBombChain");
}

gmData.Code.ByName("gml_Room_rm_a3b08_Create").ReplaceGMLInCode("""
gmData.Code.ByName("gml_Room_rm_a3b08_Create").ReplaceGMLInCode($$"""
if (oControl.mod_septoggs_bombjumps_easy == 0 && global.hasBombs == 1)
{
with (121234)
with ({{(!isHorde ? 121234 : 121259)}})
instance_destroy()
with (121235)
with ({{(!isHorde ? 121235 : 121260)}})
instance_destroy()
with (121236)
with ({{(!isHorde ? 121236 : 121261)}})
instance_destroy()
}
else if (global.item[2] == 1 || global.item[6] == 1 || global.hasHijump == 1)
{
with (121234)
with ({{(!isHorde ? 121234 : 121259)}})
instance_destroy()
with (121235)
with ({{(!isHorde ? 121235 : 121260)}})
instance_destroy()
with (121236)
with ({{(!isHorde ? 121236 : 121261)}})
instance_destroy()
}
else
{
with (121151)
with ({{(!isHorde ? 121151 : 121176)}})
instance_destroy()
tile_layer_delete_at(-105, 848, 192)
}
""", """
if (global.softlockPrevention)
{
with (121151)
instance_destroy()
tile_layer_delete_at(-105, 848, 192)
}
else
{
with (121234)
instance_destroy()
with (121235)
instance_destroy()
with (121236)
instance_destroy()
}
""");
""", $$"""
if (global.softlockPrevention)
{
with ({{(!isHorde ? 121151 : 121176)}})
instance_destroy()
tile_layer_delete_at(-105, 848, 192)
}
else
{
with ({{(!isHorde ? 121234 : 121259)}})
instance_destroy()
with ({{(!isHorde ? 121235 : 121260)}})
instance_destroy()
with ({{(!isHorde ? 121236 : 121261)}})
instance_destroy()
}
""");

// speed booster blocks near a5 activation
UndertaleRoom? a5c08 = gmData.Rooms.ByName("rm_a5c08");
Expand Down
Loading

0 comments on commit a1ed8f1

Please sign in to comment.