slime mold creation (real(
This commit is contained in:
parent
50d7e8eece
commit
97229ab6b7
|
@ -23,7 +23,7 @@
|
|||
},
|
||||
|
||||
"custom_colors": [
|
||||
{ "name": "Body", "story": { "r": 0.9764705882, "g": 0.6901960784, "b": 0.5607843137, "a": 0.5 } },
|
||||
{ "name": "Body", "story": { "r": 0.9764705882, "g": 0.6901960784, "b": 0.5607843137, "a": 0.6 } },
|
||||
{ "name": "Eyes", "story": "ffffff" }
|
||||
],
|
||||
|
||||
|
@ -37,9 +37,12 @@
|
|||
|
||||
"world_state": "Spear",
|
||||
|
||||
"jillo/bounce": 0.6,
|
||||
"jillo/bounce": 0.72,
|
||||
"jillo/immune_to_dart_maggots": true,
|
||||
"jillo/has_mark": true,
|
||||
"jillo/death_chance_mult": 0.2,
|
||||
|
||||
"jillo/create_slime_mold": true,
|
||||
|
||||
"jillo/pebbles_lines": [
|
||||
"A little creature, on the floor of my chamber.",
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using RWCustom;
|
||||
using UnityEngine;
|
||||
using static AbstractPhysicalObject;
|
||||
|
||||
namespace JilloSlug;
|
||||
|
||||
// fisobs? never heard of them
|
||||
|
||||
public static class JilloSlimeMold {
|
||||
private static ConditionalWeakTable<AbstractPhysicalObject, StrongBox<bool>> JilloMolds = new ConditionalWeakTable<AbstractPhysicalObject, StrongBox<bool>>();
|
||||
|
||||
public static bool IsJilloSlimeMold(AbstractPhysicalObject mold) {
|
||||
return JilloMolds.TryGetValue(mold, out var isJillo) && isJillo.Value;
|
||||
}
|
||||
public static bool IsJilloSlimeMold(SlimeMold mold) {
|
||||
return IsJilloSlimeMold(mold.abstractPhysicalObject);
|
||||
}
|
||||
|
||||
public static void SetJilloSlimeMold(AbstractPhysicalObject mold, bool value = true) {
|
||||
JilloMolds.Add(mold, new StrongBox<bool>(value));
|
||||
}
|
||||
public static void SetJilloSlimeMold(SlimeMold mold, bool value = true) {
|
||||
SetJilloSlimeMold(mold.abstractPhysicalObject, value);
|
||||
}
|
||||
|
||||
public static void AddHooks() {
|
||||
On.SlimeMold.ApplyPalette += SlimeMold_ApplyPalette;
|
||||
}
|
||||
|
||||
private static void SlimeMold_ApplyPalette(On.SlimeMold.orig_ApplyPalette orig, SlimeMold self, RoomCamera.SpriteLeaser sLeaser, RoomCamera rCam, RoomPalette palette) {
|
||||
if (!IsJilloSlimeMold(self)) {
|
||||
orig(self, sLeaser, rCam, palette);
|
||||
return;
|
||||
}
|
||||
self.darkMode = Mathf.InverseLerp(0.3f, 0.9f, palette.darkness);
|
||||
self.color = SlimeMoldColorFromPalette(palette);
|
||||
}
|
||||
|
||||
private static Color SlimeMoldColorFromPalette(RoomPalette palette) {
|
||||
Color col = Color.Lerp(
|
||||
Custom.HSL2RGB(Mathf.Lerp(0.05f, 0.045f, palette.darkness), 0.59f, 0.63f),
|
||||
palette.fogColor,
|
||||
Mathf.Lerp(0.15f, 0.25f, palette.fogAmount) * Mathf.Lerp(0.1f, 0.5f, palette.darkness)
|
||||
);
|
||||
col.a = 0.7f;
|
||||
return col;
|
||||
}
|
||||
}
|
|
@ -20,8 +20,12 @@ class Plugin : BaseUnityPlugin {
|
|||
BounceFeature.AddHooks();
|
||||
ImmuneToDartMaggotsFeature.AddHooks();
|
||||
MarkFeature.AddHooks();
|
||||
CreateSlimeMoldFeature.AddHooks();
|
||||
TweakDeathChanceFeature.AddHooks();
|
||||
|
||||
Iterators.AddHooks();
|
||||
|
||||
JilloSlimeMold.AddHooks();
|
||||
} catch (Exception err) {
|
||||
Logger.LogError($"error initializing: {err}");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
using System;
|
||||
using Mono.Cecil.Cil;
|
||||
using MonoMod.Cil;
|
||||
using SlugBase.Features;
|
||||
using static SlugBase.Features.FeatureTypes;
|
||||
|
||||
namespace JilloSlug.Features;
|
||||
|
||||
internal static class CreateSlimeMoldFeature {
|
||||
public static readonly PlayerFeature<bool> CreateSlimeMold = PlayerBool("jillo/create_slime_mold");
|
||||
|
||||
public static void AddHooks() {
|
||||
On.Player.Regurgitate += Player_Regurgitate;
|
||||
IL.Player.GrabUpdate += Player_GrabUpdate;
|
||||
IL.PlayerGraphics.Update += PlayerGraphics_Update;
|
||||
}
|
||||
|
||||
private static void Player_Regurgitate(On.Player.orig_Regurgitate orig, Player self) {
|
||||
if (self.objectInStomach == null && CreateSlimeMold.TryGet(self, out var createSlimeMold) && createSlimeMold) {
|
||||
self.objectInStomach = new AbstractConsumable(self.room.world, AbstractPhysicalObject.AbstractObjectType.SlimeMold, null, self.room.GetWorldCoordinate(self.firstChunk.pos), self.room.game.GetNewID(), -1, -1, null);
|
||||
JilloSlimeMold.SetJilloSlimeMold(self.objectInStomach);
|
||||
}
|
||||
orig(self);
|
||||
}
|
||||
|
||||
private static void Player_GrabUpdate(ILContext il) {
|
||||
ILCursor c = new ILCursor(il);
|
||||
|
||||
// replace all mentions of `isGourmand` with the equivalent of `(isGourmand || isJillo)`
|
||||
|
||||
// match `isGourmand`, brfalse edition
|
||||
while (
|
||||
c.TryGotoNext(MoveType.After,
|
||||
i => i.MatchLdarg(0),
|
||||
i => i.MatchCallOrCallvirt<Player>("get_isGourmand"),
|
||||
i => i.Match(OpCodes.Brfalse_S) || i.Match(OpCodes.Brfalse)
|
||||
)
|
||||
) {
|
||||
// this is the condition we should skip to if our check succeeds, replicating the behavior if the vanilla check was to succeed
|
||||
ILLabel skipGourmandCond = c.MarkLabel();
|
||||
c.GotoPrev(MoveType.Before, i => i.MatchLdarg(0), i => i.Match(OpCodes.Call) || i.Match(OpCodes.Callvirt));
|
||||
|
||||
// insert the condition
|
||||
c.Emit(OpCodes.Ldarg_0);
|
||||
c.EmitDelegate<Func<Player, bool>>(player => {
|
||||
return CreateSlimeMold.TryGet(player, out var shouldCreateSlimeMold) && shouldCreateSlimeMold;
|
||||
});
|
||||
// if it's true, skip ahead
|
||||
c.Emit(OpCodes.Brtrue_S, skipGourmandCond);
|
||||
|
||||
// move forwards to avoid an infloop
|
||||
c.GotoNext(MoveType.After, i => i.Match(OpCodes.Brfalse_S) || i.Match(OpCodes.Brfalse));
|
||||
}
|
||||
|
||||
c.Index = 0;
|
||||
|
||||
// match `isGourmand`, brtrue edition
|
||||
while (
|
||||
c.TryGotoNext(MoveType.After,
|
||||
i => i.MatchLdarg(0),
|
||||
i => i.MatchCallOrCallvirt<Player>("get_isGourmand"),
|
||||
i => i.Match(OpCodes.Brtrue_S) || i.Match(OpCodes.Brtrue)
|
||||
)
|
||||
) {
|
||||
// a lot easier here, since you can just insert another cond
|
||||
|
||||
ILLabel proceedCond = c.Prev.Operand as ILLabel;
|
||||
|
||||
// insert the condition
|
||||
c.Emit(OpCodes.Ldarg_0);
|
||||
c.EmitDelegate<Func<Player, bool>>(player => {
|
||||
return CreateSlimeMold.TryGet(player, out var shouldCreateSlimeMold) && shouldCreateSlimeMold;
|
||||
});
|
||||
// if it's true, proceed as usual
|
||||
c.Emit(OpCodes.Brtrue_S, proceedCond);
|
||||
}
|
||||
}
|
||||
|
||||
private static void PlayerGraphics_Update(ILContext il) {
|
||||
ILCursor c = new ILCursor(il);
|
||||
|
||||
// match for `player.objectInStomach != null`
|
||||
c.GotoNext(MoveType.After,
|
||||
i => i.MatchLdarg(0),
|
||||
i => i.MatchLdfld<PlayerGraphics>("player"),
|
||||
i => i.MatchLdfld<Player>("objectInStomach"),
|
||||
i => i.Match(OpCodes.Brtrue_S)
|
||||
);
|
||||
|
||||
// match for `player.SlugCatClass == MoreSlugcatsEnums.SlugcatStatsName.Gourmand ...`
|
||||
c.GotoNext(MoveType.After,
|
||||
i => i.MatchLdarg(0),
|
||||
i => i.MatchLdfld<PlayerGraphics>("player"),
|
||||
i => i.MatchLdfld<Player>("SlugCatClass"),
|
||||
i => i.MatchLdsfld<MoreSlugcats.MoreSlugcatsEnums.SlugcatStatsName>("Gourmand"),
|
||||
i => i.Match(OpCodes.Call), // this is a mess of generics; not matching this, but it's the equation call
|
||||
i => i.Match(OpCodes.Brtrue_S)
|
||||
);
|
||||
|
||||
ILLabel proceedCond = c.Prev.Operand as ILLabel;
|
||||
|
||||
// insert our condition
|
||||
c.Emit(OpCodes.Ldarg_0);
|
||||
c.EmitDelegate<Func<PlayerGraphics, bool>>(playerGraphics => {
|
||||
return CreateSlimeMold.TryGet(playerGraphics.player, out var shouldCreateSlimeMold) && shouldCreateSlimeMold;
|
||||
});
|
||||
// if it's true, proceed as usual
|
||||
c.Emit(OpCodes.Brtrue_S, proceedCond);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
using SlugBase.Features;
|
||||
using static SlugBase.Features.FeatureTypes;
|
||||
using SlugBase;
|
||||
|
||||
namespace JilloSlug.Features;
|
||||
|
||||
internal static class TweakDeathChanceFeature {
|
||||
public static readonly PlayerFeature<float> DeathChance = PlayerFloat("jillo/death_chance_mult");
|
||||
|
||||
public static void AddHooks() {
|
||||
On.Player.DeathByBiteMultiplier += Player_DeathByBiteMultiplier;
|
||||
}
|
||||
|
||||
private static float Player_DeathByBiteMultiplier(On.Player.orig_DeathByBiteMultiplier orig, Player self) {
|
||||
if (DeathChance.TryGet(self, out float mult)) {
|
||||
return mult;
|
||||
}
|
||||
return orig(self);
|
||||
}
|
||||
}
|
3
todo.txt
3
todo.txt
|
@ -3,7 +3,8 @@
|
|||
- remove ears
|
||||
- potentially more
|
||||
- gameplay
|
||||
- hold eat to remove food pips for offensive slime mold
|
||||
x hold eat to remove food pips for offensive slime mold
|
||||
- custom type
|
||||
- could maybe slow down enemies similar to spit
|
||||
- still edible
|
||||
- sleeping transforms all food pips into slime mold (maybe)
|
||||
|
|
Loading…
Reference in New Issue