78 lines
2.6 KiB
C#
78 lines
2.6 KiB
C#
using System;
|
|
using SlugBase.Features;
|
|
using static SlugBase.Features.FeatureTypes;
|
|
using MonoMod.Cil;
|
|
using Mono.Cecil.Cil;
|
|
|
|
namespace JilloSlug.Features;
|
|
|
|
internal static class ImmuneToDartMaggotsFeature {
|
|
public static readonly PlayerFeature<bool> ImmuneToDartMaggots = PlayerBool("jillo/immune_to_dart_maggots");
|
|
|
|
public static void AddHooks() {
|
|
IL.DartMaggot.Update += DartMaggot_Update;
|
|
}
|
|
|
|
private static bool DartMaggotCanStun(DartMaggot maggot) {
|
|
if (maggot.stuckInChunk.owner is Player && ImmuneToDartMaggots.TryGet(maggot.stuckInChunk.owner as Player, out var immune) && immune) {
|
|
return false; // skip
|
|
}
|
|
return true; // proceed as normal
|
|
}
|
|
|
|
private static void ILInsertHandleDartMaggotStun(ILCursor c, ILLabel skipLabel) {
|
|
c.Emit(OpCodes.Ldarg_0);
|
|
c.EmitDelegate<Func<DartMaggot, bool>>(maggot => {
|
|
return DartMaggotCanStun(maggot);
|
|
});
|
|
c.Emit(OpCodes.Brfalse, skipLabel);
|
|
}
|
|
|
|
private static void DartMaggot_Update(ILContext il) {
|
|
ILCursor c = new ILCursor(il);
|
|
|
|
// matching for `stuckInChunk.owner is Creature && ...`
|
|
c.GotoNext(MoveType.After,
|
|
i => i.MatchLdarg(0),
|
|
i => i.MatchLdfld<DartMaggot>("stuckInChunk"),
|
|
i => i.MatchCallOrCallvirt<BodyChunk>("get_owner"),
|
|
i => i.MatchIsinst<Creature>(),
|
|
i => i.Match(OpCodes.Brfalse_S)
|
|
);
|
|
|
|
// last instruction will be a brfalse.s; capture the label it goes to
|
|
ILLabel skipLabel = c.Prev.Operand as ILLabel;
|
|
|
|
// we're now ready to write another condition
|
|
ILInsertHandleDartMaggotStun(c, skipLabel);
|
|
|
|
// comments will be unrepeated; same functionality
|
|
|
|
// matching for `stuckInChunk.owner is Player && ...`
|
|
c.GotoNext(MoveType.After,
|
|
i => i.MatchLdarg(0),
|
|
i => i.MatchLdfld<DartMaggot>("stuckInChunk"),
|
|
i => i.MatchCallOrCallvirt<BodyChunk>("get_owner"),
|
|
i => i.MatchIsinst<Player>(),
|
|
i => i.Match(OpCodes.Brfalse_S)
|
|
);
|
|
|
|
skipLabel = c.Prev.Operand as ILLabel;
|
|
|
|
ILInsertHandleDartMaggotStun(c, skipLabel);
|
|
|
|
// matching for `stuckInChunk.owner is Creature`
|
|
c.GotoNext(MoveType.After,
|
|
i => i.MatchLdarg(0),
|
|
i => i.MatchLdfld<DartMaggot>("stuckInChunk"),
|
|
i => i.MatchCallOrCallvirt<BodyChunk>("get_owner"),
|
|
i => i.MatchIsinst<Creature>(),
|
|
i => i.Match(OpCodes.Brfalse) // watch out! this one isn't _S
|
|
);
|
|
|
|
skipLabel = c.Prev.Operand as ILLabel;
|
|
|
|
ILInsertHandleDartMaggotStun(c, skipLabel);
|
|
}
|
|
}
|