134 lines
4.4 KiB
C#
134 lines
4.4 KiB
C#
using System;
|
|
using UnityEngine;
|
|
using SlugBase.Features;
|
|
using static SlugBase.Features.FeatureTypes;
|
|
using MonoMod.Cil;
|
|
using Mono.Cecil.Cil;
|
|
using RWCustom;
|
|
|
|
namespace JilloSlug.Features;
|
|
|
|
internal static class BounceFeature {
|
|
// 0 = no bounce
|
|
// 1 = preserve all velocity upon bouncing
|
|
public static readonly PlayerFeature<float> Bounce = PlayerFloat("jillo/bounce");
|
|
|
|
public static void AddHooks() {
|
|
IL.Player.TerrainImpact += Player_TerrainImpact;
|
|
}
|
|
|
|
private static bool PlayerHandleBounce(Player player, IntVector2 direction, float speed) {
|
|
float bounce;
|
|
Bounce.TryGet(player, out bounce);
|
|
bool shouldBounce = !player.dead && bounce >= 0;
|
|
if (!shouldBounce) return true;
|
|
|
|
if (speed > 0.5f) {
|
|
player.room.PlaySound(SoundID.Slime_Mold_Terrain_Impact, player.mainBodyChunk, false, 0.7f + Mathf.Clamp(speed / 60f, 0f, 1f), 1f);
|
|
}
|
|
|
|
if (speed > 8f) {
|
|
// handle bouncing
|
|
foreach (var chunk in player.bodyChunks) {
|
|
chunk.vel.x = Mathf.Lerp(chunk.vel.x, -chunk.vel.x * bounce, Mathf.Abs((float) direction.x));
|
|
chunk.vel.y = Mathf.Lerp(chunk.vel.y, -chunk.vel.y * bounce, Mathf.Abs((float) direction.y));
|
|
}
|
|
}
|
|
|
|
return false; // skip everything
|
|
}
|
|
|
|
private static void ILInsertHandleBounce(ILCursor c, ILLabel skipLabel) {
|
|
c.Emit(OpCodes.Ldarg_0);
|
|
c.Emit(OpCodes.Ldarg_2); // direction
|
|
c.Emit(OpCodes.Ldarg_3); // speed
|
|
c.EmitDelegate<Func<Player, IntVector2, float, bool>>((player, direction, speed) => {
|
|
return PlayerHandleBounce(player, direction, speed);
|
|
});
|
|
c.Emit(OpCodes.Brfalse, skipLabel);
|
|
}
|
|
|
|
private static void Player_TerrainImpact(ILContext il) {
|
|
ILCursor c = new ILCursor(il);
|
|
|
|
// patch high speed impact (death condition)
|
|
|
|
// matching for `speed > num && direction.y < 0`
|
|
c.GotoNext(MoveType.After,
|
|
// speed > num
|
|
i => i.MatchLdarg(3),
|
|
i => i.MatchLdloc(0),
|
|
i => i.Match(OpCodes.Ble_Un_S),
|
|
|
|
// direction.y < 0
|
|
i => i.MatchLdarg(2),
|
|
i => i.MatchLdfld<IntVector2>("y"),
|
|
i => i.Match(OpCodes.Ldc_I4_0),
|
|
i => i.Match(OpCodes.Bge_S)
|
|
);
|
|
|
|
// retrieve the label the end of the if would skip to
|
|
// (illegal bytecode crimes)
|
|
ILCursor endC = c.Clone();
|
|
endC.GotoNext(MoveType.After, i => i.MatchCallOrCallvirt<Creature>("Die"));
|
|
ILLabel skipLabel = endC.Next.Operand as ILLabel;
|
|
|
|
ILInsertHandleBounce(c, skipLabel);
|
|
|
|
// patch mid speed impact (stun condition)
|
|
|
|
// matching for `speed > num2`
|
|
c.GotoNext(MoveType.After,
|
|
// speed > num2
|
|
i => i.MatchLdarg(3),
|
|
i => i.MatchLdloc(1),
|
|
i => i.Match(OpCodes.Ble_Un)
|
|
);
|
|
|
|
ILInsertHandleBounce(c, skipLabel);
|
|
|
|
// patch low speed impacts
|
|
|
|
// matching for `direction.y < 0 && base.Consious`
|
|
c.GotoNext(MoveType.After,
|
|
i => i.MatchLdarg(2),
|
|
i => i.MatchLdfld<IntVector2>("y"),
|
|
i => i.Match(OpCodes.Ldc_I4_0),
|
|
i => i.Match(OpCodes.Bge_S),
|
|
|
|
i => i.MatchLdarg(0),
|
|
i => i.MatchCallOrCallvirt<Creature>("get_Consious"),
|
|
i => i.Match(OpCodes.Brfalse_S)
|
|
);
|
|
|
|
ILInsertHandleBounce(c, skipLabel);
|
|
|
|
// matching for `this.room.PlaySound(SoundID.Slugcat_Terrain_Impact_Light, ...);`
|
|
c.GotoNext(MoveType.Before,
|
|
i => i.MatchLdarg(0),
|
|
i => i.MatchLdfld<UpdatableAndDeletable>("room"),
|
|
i => i.MatchLdsfld<SoundID>("Slugcat_Terrain_Impact_Light")
|
|
);
|
|
|
|
ILInsertHandleBounce(c, skipLabel);
|
|
|
|
// matching for `this.room.PlaySound(SoundID.Slugcat_Terrain_Impact_Medium, ...);`
|
|
c.GotoNext(MoveType.Before,
|
|
i => i.MatchLdarg(0),
|
|
i => i.MatchLdfld<UpdatableAndDeletable>("room"),
|
|
i => i.MatchLdsfld<SoundID>("Slugcat_Terrain_Impact_Medium")
|
|
);
|
|
|
|
ILInsertHandleBounce(c, skipLabel);
|
|
|
|
// matching for `this.room.PlaySound(SoundID.Slugcat_Terrain_Impact_Hard, ...;`
|
|
c.GotoNext(MoveType.Before,
|
|
i => i.MatchLdarg(0),
|
|
i => i.MatchLdfld<UpdatableAndDeletable>("room"),
|
|
i => i.MatchLdsfld<SoundID>("Slugcat_Terrain_Impact_Hard")
|
|
);
|
|
|
|
ILInsertHandleBounce(c, skipLabel);
|
|
}
|
|
}
|