diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..add57be --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +bin/ +obj/ +/packages/ +riderModule.iml +/_ReSharper.Caches/ \ No newline at end of file diff --git a/MoreMice/.idea/.idea.MoreMice.dir/.idea/.gitignore b/MoreMice/.idea/.idea.MoreMice.dir/.idea/.gitignore new file mode 100644 index 0000000..2c22a21 --- /dev/null +++ b/MoreMice/.idea/.idea.MoreMice.dir/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/.idea.MoreMice.iml +/modules.xml +/projectSettingsUpdater.xml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/MoreMice/.idea/.idea.MoreMice.dir/.idea/encodings.xml b/MoreMice/.idea/.idea.MoreMice.dir/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/MoreMice/.idea/.idea.MoreMice.dir/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/MoreMice/.idea/.idea.MoreMice.dir/.idea/indexLayout.xml b/MoreMice/.idea/.idea.MoreMice.dir/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/MoreMice/.idea/.idea.MoreMice.dir/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/MoreMice/.idea/.idea.MoreMice.dir/.idea/vcs.xml b/MoreMice/.idea/.idea.MoreMice.dir/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/MoreMice/.idea/.idea.MoreMice.dir/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/MoreMice/MoreMice.csproj b/MoreMice/MoreMice.csproj new file mode 100644 index 0000000..aa333ed --- /dev/null +++ b/MoreMice/MoreMice.csproj @@ -0,0 +1,31 @@ + + + + net35 + latest + + + + + + + + + + + + + + diff --git a/MoreMice/MoreMice.csproj.user b/MoreMice/MoreMice.csproj.user new file mode 100644 index 0000000..4e9d0c0 --- /dev/null +++ b/MoreMice/MoreMice.csproj.user @@ -0,0 +1,8 @@ + + + ../../_references + + + + + \ No newline at end of file diff --git a/MoreMice/MoreMicePlugin.cs b/MoreMice/MoreMicePlugin.cs new file mode 100644 index 0000000..3fd231f --- /dev/null +++ b/MoreMice/MoreMicePlugin.cs @@ -0,0 +1,70 @@ +using BepInEx; +using Mono.Cecil.Cil; +using MonoMod.Cil; + +namespace MoreMice; + +[BepInPlugin("casheww.more_mice", "MoreMice", "0.1.0")] +public class MoreMicePlugin : BaseUnityPlugin +{ + private void OnEnable() + { + On.WorldLoader.GeneratePopulation += WorldLoader_GeneratePopulation; + On.LanternMouse.GenerateIVars += LanternMouse_GenerateIVars; + On.StaticWorld.EstablishRelationship += StaticWorld_EstablishRelationship; + } + + private void OnDisable() + { + On.WorldLoader.GeneratePopulation -= WorldLoader_GeneratePopulation; + On.LanternMouse.GenerateIVars -= LanternMouse_GenerateIVars; + On.StaticWorld.EstablishRelationship -= StaticWorld_EstablishRelationship; + } + + private void WorldLoader_GeneratePopulation(On.WorldLoader.orig_GeneratePopulation orig, object self, bool fresh) + { + orig(self, fresh); + + if (self is not WorldLoader wl) + return; + + foreach (World.CreatureSpawner spawner in wl.spawners) + { + AbstractRoom abstractRoom = wl.world.GetAbstractRoom(spawner.den); + + for (int i = 0; i < 16; i++) + { + if (UnityEngine.Random.value < 0.125f) + break; + + abstractRoom.MoveEntityToDen(new AbstractCreature( + wl.world, + StaticWorld.GetCreatureTemplate(CreatureTemplate.Type.LanternMouse), + null, + spawner.den, + wl.world.game.GetNewID())); + } + } + } + + private void LanternMouse_GenerateIVars(On.LanternMouse.orig_GenerateIVars orig, LanternMouse self) + { + if (UnityEngine.Random.value < 0.5f) + { + HSLColor color = new HSLColor(UnityEngine.Random.value, 1f, 0.6f); + self.iVars = new LanternMouse.IndividualVariations(UnityEngine.Random.value, color); + } + else + orig(self); + } + + private void StaticWorld_EstablishRelationship(On.StaticWorld.orig_EstablishRelationship orig, + CreatureTemplate.Type a, CreatureTemplate.Type b, CreatureTemplate.Relationship relationship) + { + if (a == CreatureTemplate.Type.LanternMouse && b == CreatureTemplate.Type.Slugcat) + orig(a, b, new CreatureTemplate.Relationship(CreatureTemplate.Relationship.Type.PlaysWith, 0.4f)); + else + orig(a, b, relationship); + } + +} diff --git a/MoreOverseers/BehaveHooks.cs b/MoreOverseers/BehaveHooks.cs new file mode 100644 index 0000000..129aa57 --- /dev/null +++ b/MoreOverseers/BehaveHooks.cs @@ -0,0 +1,94 @@ +using System; + +using UnityEngine; +using System.Collections.Generic; +using RWCustom; + +namespace MoreOverseers +{ + class BehaveHooks + { + public static void Apply() + { + On.RainWorldGame.Update += RainWorldGame_Update; + On.OverseerAbstractAI.AbstractBehavior += OverseerAbstractAI_AbstractBehavior; + On.OverseerAI.LikeOfPlayer += OverseerAI_LikeOfPlayer; + } + public static void UnApply() + { + On.RainWorldGame.Update -= RainWorldGame_Update; + On.OverseerAbstractAI.AbstractBehavior -= OverseerAbstractAI_AbstractBehavior; + On.OverseerAI.LikeOfPlayer -= OverseerAI_LikeOfPlayer; + } + + static void RainWorldGame_Update(On.RainWorldGame.orig_Update orig, RainWorldGame self) + { + orig(self); + + if (self.Players.Count < 1) return; + + AbstractWorldEntity[] entities = self.world.offScreenDen.entitiesInDens.ToArray(); + + foreach (AbstractWorldEntity aEntity in entities) + { + if (aEntity is AbstractCreature aCreature && aCreature.creatureTemplate.type == CreatureTemplate.Type.Overseer) + { + OverseersPlugin.Logger_.LogInfo($"moving overseer {aCreature.ID} " + + $"from offscreen den to {self.Players[0].Room.name}"); + aCreature.ChangeRooms(new WorldCoordinate(self.Players[0].Room.index, 1, 1, 0)); + + self.world.offScreenDen.entitiesInDens.Remove(aCreature); + } + } + } + + static void OverseerAbstractAI_AbstractBehavior(On.OverseerAbstractAI.orig_AbstractBehavior orig, + OverseerAbstractAI self, int time) + { + if (self.world.singleRoomWorld && self.parent.pos.room == 0 || + self.world.game.Players.Count == 0) + { + return; + } + + int playerNum = 0; + self.targetCreature = self.world.game.Players[playerNum]; + + // occurs for newly spawned or unrealized overseers + if (self.parent.realizedCreature == null || self.lastRoom == new WorldCoordinate(0, 0, 0, 0)) + { + OverseersPlugin.Logger_.LogInfo("overseer null or invalid OverseerAbstractAI.lastRoom"); + + if (self.targetCreature.Room.realizedRoom == null) return; + + OverseersPlugin.Logger_.LogInfo(" ... so overseer will Move"); + + self.parent.Move(self.targetCreature.pos); + self.parent.RealizeInRoom(); + } + + else if (self.parent.Room != self.targetCreature.Room) + { + OverseersPlugin.Logger_.LogInfo($"overseer {self.parent.ID} " + + $"going to player {playerNum} in {self.targetCreature.Room.name}"); + + Overseer overseer = self.parent.realizedCreature as Overseer; + + if (self.targetCreature.Room.realizedRoom.readyForAI) + { + OverseersPlugin.Logger_.LogWarning($"lastRoom : {self.lastRoom}"); + overseer.TeleportingIntoRoom(self.targetCreature.Room.realizedRoom); + } + else + { + OverseersPlugin.Logger_.LogInfo($"room {self.targetCreature.Room.name} not ready for AI - dest NoPathing"); + self.SetDestinationNoPathing(new WorldCoordinate(self.targetCreature.Room.index, 1, 1, 0), false); + } + } + } + + static float OverseerAI_LikeOfPlayer(On.OverseerAI.orig_LikeOfPlayer orig, OverseerAI self, AbstractCreature player) + => 1; + + } +} diff --git a/MoreOverseers/BigBrothersAreWatchingYou.csproj b/MoreOverseers/BigBrothersAreWatchingYou.csproj new file mode 100644 index 0000000..d80b3a4 --- /dev/null +++ b/MoreOverseers/BigBrothersAreWatchingYou.csproj @@ -0,0 +1,72 @@ + + + + + Debug + AnyCPU + {ACB9F0D1-8617-4805-88BB-8973B8889A09} + Library + Properties + MoreOverseers + MoreOverseers + v3.5 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\safe\Assembly-CSharp.dll + + + ..\..\..\..\Games\Steam\steamapps\common\Rain World\BepInEx\core\BepInEx.dll + + + ..\..\..\..\Games\Steam\steamapps\common\Rain World\BepInEx\plugins\ConfigMachine.dll + + + ..\..\safe\HOOKS-Assembly-CSharp.dll + + + ..\..\..\..\Games\Steam\steamapps\common\Rain World\BepInEx\core\MonoMod.RuntimeDetour.dll + + + + + + + + + ..\..\safe\UnityEngine.dll + + + + + + + + + + + + + + copy /Y $(TargetPath) "D:\Games\Steam\steamapps\common\Rain World\Mods" + + \ No newline at end of file diff --git a/MoreOverseers/ConfigMenu.cs b/MoreOverseers/ConfigMenu.cs new file mode 100644 index 0000000..f4f4954 --- /dev/null +++ b/MoreOverseers/ConfigMenu.cs @@ -0,0 +1,100 @@ +using System; +using OptionalUI; +using RWCustom; +using UnityEngine; + +namespace MoreOverseers +{ + class ConfigMenu : OptionInterface + { + public ConfigMenu() : base(plugin: OverseersPlugin.Instance) { } + + public override void Initialize() + { + base.Initialize(); + Tabs = new OpTab[1]; + Tabs[0] = new OpTab("Overseers"); + + cModeBox = new OpComboBox(new Vector2(200, 210), 150, "colourMode", Enum.GetNames(typeof(ColourMode)), "RandomStatic"); + cPickerLabel = new OpLabel(150, 160, "Custom colour selector"); + cPicker = new OpColorPicker(new Vector2(200, 7), "customColour", "A369E0"); + + Tabs[0].AddItems( + new OpLabel(new Vector2(100, 550), new Vector2(400, 40), rwMod.ModID, bigText: true), + new OpLabel(new Vector2(150, 500), new Vector2(150, 30), $"v{rwMod.Version}"), + new OpLabel(new Vector2(300, 500), new Vector2(150, 30), $"by {rwMod.author}"), + + new OpLabel(150, 400, "Minimum overseer count per region"), + new OpSlider(new Vector2(200, 360), "min", new IntVector2(5, 100), 200, false, defaultMin), + + new OpLabel(150, 320, "Maximum overseer count per region"), + new OpSlider(new Vector2(200, 280), "max", new IntVector2(5, 100), 200, false, defaultMax), + + new OpLabel(150, 240, "Colour mode"), + cModeBox, + + cPickerLabel, cPicker + ); + } + + OpComboBox cModeBox; + OpLabel cPickerLabel; + OpColorPicker cPicker; + + const int defaultMin = 10; + const int defaultMax = 25; + + public override void ConfigOnChange() + { + base.ConfigOnChange(); + + MinOverseers = Mathf.Clamp(int.Parse(config["min"]), 0, 100); + MaxOverseers = Mathf.Clamp(int.Parse(config["max"]), MinOverseers + 1, 101); + + ColourMode_ = (ColourMode)Enum.Parse(typeof(ColourMode), config["colourMode"]); + + string cStr = config["customColour"]; + CustomColour = new Color( + int.Parse(cStr.Substring(0, 2), System.Globalization.NumberStyles.HexNumber) / 360f, + int.Parse(cStr.Substring(2, 2), System.Globalization.NumberStyles.HexNumber) / 360f, + int.Parse(cStr.Substring(4, 2), System.Globalization.NumberStyles.HexNumber) / 360f + ); + + OverseersPlugin.Logger_.LogInfo($"custom overseer colour : {CustomColour}"); + + } + + public override void Update(float dt) + { + base.Update(dt); + + if (cModeBox.value == "Custom") + { + cPickerLabel.Show(); + cPicker.Show(); + } + else + { + cPickerLabel.Hide(); + cPicker.Hide(); + } + } + + public static int MinOverseers { get; private set; } + public static int MaxOverseers { get; private set; } + public static ColourMode ColourMode_ { get; private set; } + public static Color CustomColour { get; private set; } + + public enum ColourMode + { + Default, + RandomStrobe, + RandomStatic, + AllPebbles, + AllMoon, + AllGreenOverseerFromUnknownIterator, + Custom + } + + } +} diff --git a/MoreOverseers/ConversationHooks.cs b/MoreOverseers/ConversationHooks.cs new file mode 100644 index 0000000..6c9e07a --- /dev/null +++ b/MoreOverseers/ConversationHooks.cs @@ -0,0 +1,66 @@ +using System; + +namespace MoreOverseers.Interactions +{ + class ConversationHooks + { + public static void Apply() + { + On.SLOracleBehaviorHasMark.MoonConversation.AddEvents += MoonConversation_AddEvents; + } + public static void UnApply() + { + On.SLOracleBehaviorHasMark.MoonConversation.AddEvents -= MoonConversation_AddEvents; + } + + static void MoonConversation_AddEvents(On.SLOracleBehaviorHasMark.MoonConversation.orig_AddEvents orig, + SLOracleBehaviorHasMark.MoonConversation self) + { + orig(self); + + if (self.id == Conversation.ID.MoonFirstPostMarkConversation + && self.State.neuronsLeft >= 4) + { + switch (ConfigMenu.ColourMode_) + { + case ConfigMenu.ColourMode.RandomStatic: + self.events.Add(new Conversation.TextEvent(self, 5, + self.Translate("Quite the collection of friends you have here, !"), 0)); + self.events.Add(new Conversation.TextEvent(self, 0, + self.Translate("My friends have been keeping close watch on things of late..." + + "Hello, my friends..."), 10)); + break; + + case ConfigMenu.ColourMode.RandomStrobe: + self.events.Add(new Conversation.TextEvent(self, 5, + self.Translate("Oh, and quite the party you have brought with you!"), 0)); + self.events.Add(new Conversation.TextEvent(self, 0, + self.Translate("How fashionable! It is so good to see this many colours after so long..."), 0)); + break; + + case ConfigMenu.ColourMode.AllMoon: + self.events.Add(new Conversation.TextEvent(self, 5, + self.Translate("You've been looking after my overseers, ..." + + "Thank you."), 0)); + break; + + case ConfigMenu.ColourMode.Default: + case ConfigMenu.ColourMode.AllPebbles: + self.events.Add(new Conversation.TextEvent(self, 5, + self.Translate("So many overseers from Five Pebbles..."), 0)); + self.events.Add(new Conversation.TextEvent(self, 0, + self.Translate("I do wonder if he still cares about what goes on outside his can."), 10)); + break; + + case ConfigMenu.ColourMode.AllGreenOverseerFromUnknownIterator: + self.events.Add(new Conversation.TextEvent(self, 5, + self.Translate("Someone is watching over you, ." + + "These overseers have travelled far..."), 0)); + break; + } + + } + } + + } +} diff --git a/MoreOverseers/GraphicsHooks.cs b/MoreOverseers/GraphicsHooks.cs new file mode 100644 index 0000000..724dd8d --- /dev/null +++ b/MoreOverseers/GraphicsHooks.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using System.Reflection; +using MonoMod.RuntimeDetour; +using UnityEngine; + +namespace MoreOverseers +{ + class GraphicsHooks + { + public static void Apply() + { + overseerColorHook = new Hook( + typeof(OverseerGraphics).GetProperty("MainColor", BindingFlags.Instance | BindingFlags.Public).GetGetMethod(), + typeof(GraphicsHooks).GetMethod("OverseerGraphics_get_MainColor", BindingFlags.Static | BindingFlags.Public)); + } + public static void UnApply() + { + overseerColorHook.Undo(); + } + + static Hook overseerColorHook; + + public delegate Color orig_MainColor(OverseerGraphics self); + + public static Color OverseerGraphics_get_MainColor(orig_MainColor orig, OverseerGraphics self) + { + Color color; + + switch (ConfigMenu.ColourMode_) + { + case ConfigMenu.ColourMode.Default: + color = orig(self); + break; + + case ConfigMenu.ColourMode.RandomStrobe: + color = new HSLColor(Random.value, 1, 0.8f).rgb; + break; + + case ConfigMenu.ColourMode.RandomStatic: + if (staticOverseerColours.ContainsKey(self.owner.abstractPhysicalObject.ID)) + { + color = staticOverseerColours[self.owner.abstractPhysicalObject.ID]; + } + else + { + color = new HSLColor(Random.value, 1, 0.8f).rgb; + staticOverseerColours[self.owner.abstractPhysicalObject.ID] = color; + } + break; + + case ConfigMenu.ColourMode.AllMoon: + color = new Color(1f, 0.8f, 0.3f); + break; + + default: + case ConfigMenu.ColourMode.AllPebbles: + color = new Color(0.447058827f, 0.9019608f, 0.768627465f); + break; + + case ConfigMenu.ColourMode.AllGreenOverseerFromUnknownIterator: + color = new Color(0f, 1f, 0f); + break; + + case ConfigMenu.ColourMode.Custom: + color = ConfigMenu.CustomColour; + break; + + } + + return color; + } + + static Dictionary staticOverseerColours = new Dictionary(); + + } +} diff --git a/MoreOverseers/OverseersPlugin.cs b/MoreOverseers/OverseersPlugin.cs new file mode 100644 index 0000000..8ff3a4e --- /dev/null +++ b/MoreOverseers/OverseersPlugin.cs @@ -0,0 +1,35 @@ +using System; +using BepInEx; + +namespace MoreOverseers +{ + [BepInPlugin("casheww.more_overseers", "MoreOverseers", "0.1.0")] + public class OverseersPlugin : BaseUnityPlugin + { + public OverseersPlugin() + { + Instance = this; + } + + public static OverseersPlugin Instance { get; private set; } + public static BepInEx.Logging.ManualLogSource Logger_ => Instance.Logger; + public static OptionalUI.OptionInterface LoadOI() => new ConfigMenu(); + + + void OnEnable() + { + SpawnHooks.Apply(); + BehaveHooks.Apply(); + GraphicsHooks.Apply(); + Interactions.ConversationHooks.Apply(); + } + void OnDisable() + { + SpawnHooks.UnApply(); + BehaveHooks.UnApply(); + GraphicsHooks.UnApply(); + Interactions.ConversationHooks.UnApply(); + } + + } +} diff --git a/MoreOverseers/Properties/AssemblyInfo.cs b/MoreOverseers/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..3a11a52 --- /dev/null +++ b/MoreOverseers/Properties/AssemblyInfo.cs @@ -0,0 +1,13 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("BigBrothersAreWatchingYou")] +[assembly: AssemblyProduct("BigBrothersAreWatchingYou")] +[assembly: AssemblyCompany("casheww")] +[assembly: AssemblyCopyright("Copyright © casheww 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: Guid("acb9f0d1-8617-4805-88bb-8973b8889a09")] +[assembly: AssemblyVersion("0.1.0.0")] +[assembly: AssemblyFileVersion("0.1.0.0")] diff --git a/MoreOverseers/SpawnHooks.cs b/MoreOverseers/SpawnHooks.cs new file mode 100644 index 0000000..1938623 --- /dev/null +++ b/MoreOverseers/SpawnHooks.cs @@ -0,0 +1,41 @@ +using UnityEngine; + +namespace MoreOverseers +{ + class SpawnHooks + { + public static void Apply() + { + On.WorldLoader.GeneratePopulation += WorldLoader_GeneratePopulation; + } + + public static void UnApply() + { + On.WorldLoader.GeneratePopulation -= WorldLoader_GeneratePopulation; + } + + static void WorldLoader_GeneratePopulation(On.WorldLoader.orig_GeneratePopulation orig, object self, bool fresh) + { + orig(self, fresh); + + OverseersPlugin.Logger_.LogInfo("infiltrated population generation!"); + + if (self is WorldLoader wl) + { + int count = Random.Range(ConfigMenu.MinOverseers, ConfigMenu.MaxOverseers); + for (int i = 0; i < count; i++) + { + wl.world.offScreenDen.entitiesInDens.Add(new AbstractCreature( + wl.world, + StaticWorld.GetCreatureTemplate(CreatureTemplate.Type.Overseer), + null, + new WorldCoordinate(wl.world.offScreenDen.index, 1, 1, 0), + wl.game.GetNewID())); + } + OverseersPlugin.Logger_.LogInfo($"added {count} overseers"); + } + + } + + } +} diff --git a/MoreStuff.sln b/MoreStuff.sln new file mode 100644 index 0000000..08469a1 --- /dev/null +++ b/MoreStuff.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MoreMice", "MoreMice\MoreMice.csproj", "{D180170E-DF35-4C44-BCC5-298045628201}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BigBrothersAreWatchingYou", "MoreOverseers\BigBrothersAreWatchingYou.csproj", "{ACB9F0D1-8617-4805-88BB-8973B8889A09}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D180170E-DF35-4C44-BCC5-298045628201}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D180170E-DF35-4C44-BCC5-298045628201}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D180170E-DF35-4C44-BCC5-298045628201}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D180170E-DF35-4C44-BCC5-298045628201}.Release|Any CPU.Build.0 = Release|Any CPU + {ACB9F0D1-8617-4805-88BB-8973B8889A09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ACB9F0D1-8617-4805-88BB-8973B8889A09}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ACB9F0D1-8617-4805-88BB-8973B8889A09}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ACB9F0D1-8617-4805-88BB-8973B8889A09}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal