diff --git a/KK_FutaMod/KK_FutaMod.cs b/KK_FutaMod/KK_FutaMod.cs new file mode 100644 index 00000000..f742de60 --- /dev/null +++ b/KK_FutaMod/KK_FutaMod.cs @@ -0,0 +1,169 @@ +using BepInEx; +using BepInEx.Logging; +using Logger = BepInEx.Logger; +using Harmony; +using UnityEngine; +using System; +using System.ComponentModel; +using System.Collections.Generic; +using ExtensibleSaveFormat; +using ChaCustom; +/// +/// Futa mod. Adds dicks to girls which save and load along with the card. +/// +namespace KK_FutaMod +{ + [BepInProcess("Koikatu")] //Not for Studio since you can add dicks whenever you want there + [BepInPlugin("com.deathweasel.bepinex.futamod", "Futa Mod", "0.1")] + public class KK_FutaMod : BaseUnityPlugin + { + [DisplayName("Futa Hotkey")] + [Description("Futa hotkey")] + public static SavedKeyboardShortcut FutaHotkey { get; private set; } + private static bool ListOverride = false; + private static bool DoingLoadFileLimited = false; + + void Main() + { + var harmony = HarmonyInstance.Create("com.deathweasel.bepinex.futamod"); + harmony.PatchAll(typeof(KK_FutaMod)); + FutaHotkey = new SavedKeyboardShortcut("FutaHotkey", "KK_FutaMod", new KeyboardShortcut(KeyCode.KeypadMinus)); + ExtendedSave.CardBeingLoaded += ExtendedCardLoad; + ExtendedSave.CardBeingSaved += ExtendedCardSave; + } + /// + /// Replace this with a GUI + /// + void Update() + { + if (FutaHotkey.IsDown() && Singleton.IsInstance() && Singleton.Instance.chaCtrl != null) + { + bool IsFuta = !Singleton.Instance.chaCtrl.chaFile.status.visibleSonAlways; + Singleton.Instance.chaCtrl.chaFile.status.visibleSonAlways = IsFuta; + PluginData ExtendedData = new PluginData(); + ExtendedData.data = new Dictionary { { "Futa", IsFuta } }; + ExtendedSave.SetExtendedDataById(Singleton.Instance.chaCtrl.chaFile, "KK_FutaMod", ExtendedData); + } + } + /// + /// Card loading + /// + private static void ExtendedCardLoad(ChaFile file) + { + if (ListOverride) return; + + bool IsFuta = false; + PluginData ExtendedData = ExtendedSave.GetExtendedDataById(file, "KK_FutaMod"); + + if (ExtendedData != null && ExtendedData.data.ContainsKey("Futa")) + { + IsFuta = (bool)ExtendedData.data["Futa"]; + file.status.visibleSonAlways = IsFuta; + } + + //Loading a card while in chara maker + if (Singleton.IsInstance() && Singleton.Instance.chaCtrl != null && DoingLoadFileLimited) + { + ExtendedData = new PluginData(); + ExtendedData.data = new Dictionary { { "Futa", IsFuta } }; + ExtendedSave.SetExtendedDataById(Singleton.Instance.chaCtrl.chaFile, "KK_FutaMod", ExtendedData); + Singleton.Instance.chaCtrl.chaFile.status.visibleSonAlways = IsFuta; + } + } + /// + /// Card saving + /// + private static void ExtendedCardSave(ChaFile file) + { + PluginData ExtendedData = ExtendedSave.GetExtendedDataById(file, "KK_FutaMod"); + + if (ExtendedData != null && ExtendedData.data.ContainsKey("Futa")) + { + if (Singleton.IsInstance() && Singleton.Instance.chaCtrl != null) + { + //Saving card from chara maker, get the status from the character + ExtendedData.data["Futa"] = file.status.visibleSonAlways; + ExtendedSave.SetExtendedDataById(file, "KK_FutaMod", ExtendedData); + } + else + { + //Not in chara maker, keep the existing extended data + ExtendedSave.SetExtendedDataById(file, "KK_FutaMod", ExtendedData); + } + } + else + { + if (Singleton.IsInstance() && Singleton.Instance.chaCtrl != null) + { + //Saving a character in chara maker that doesn't have extended data + ExtendedData = new PluginData(); + ExtendedData.data = new Dictionary { { "Futa", file.status.visibleSonAlways } }; + ExtendedSave.SetExtendedDataById(file, "KK_FutaMod", ExtendedData); + } + } + } + /// + /// When one ChaFile is copied to another, copy over the extended data too + /// + [HarmonyPostfix, HarmonyPatch(typeof(ChaFile), nameof(ChaFile.CopyChaFile))] + public static void CopyChaFile(ChaFile dst, ChaFile src) + { + PluginData ExtendedData = ExtendedSave.GetExtendedDataById(src, "KK_FutaMod"); + + if (ExtendedData != null && ExtendedData.data.ContainsKey("Futa")) + ExtendedSave.SetExtendedDataById(dst, "KK_FutaMod", ExtendedData); + } + /// + /// When a female is created enable the dick + /// + [HarmonyPostfix, HarmonyPatch(typeof(Manager.Character), nameof(Manager.Character.CreateChara))] + public static void CreateChara(ChaControl __result, ChaFileControl _chaFile, byte _sex) + { + if (_sex == 0 || _chaFile == null) return; + + PluginData ExtendedData = ExtendedSave.GetExtendedDataById(_chaFile, "KK_FutaMod"); + + if (ExtendedData != null && ExtendedData.data.ContainsKey("Futa")) + __result.chaFile.status.visibleSonAlways = (bool)ExtendedData.data["Futa"]; + } + + //Allow changing futa state in chara maker only when LoadFileLimited has been called + [HarmonyPrefix, HarmonyPatch(typeof(ChaFileControl), nameof(ChaFileControl.LoadFileLimited), new[] { typeof(string), typeof(byte), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool) })] + public static void LoadFileLimitedPrefix() => DoingLoadFileLimited = true; + [HarmonyPostfix, HarmonyPatch(typeof(ChaFileControl), nameof(ChaFileControl.LoadFileLimited), new[] { typeof(string), typeof(byte), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool) })] + public static void LoadFileLimitedPostfix() => DoingLoadFileLimited = false; + + //Prevent changing futa state when loading the list of characters + [HarmonyPrefix, HarmonyPatch(typeof(CustomCharaFile), "Initialize")] + public static void CustomScenePrefix() => ListOverride = true; + [HarmonyPostfix, HarmonyPatch(typeof(CustomCharaFile), "Initialize")] + public static void CustomScenePostfix() => ListOverride = false; + + ///// + ///// Normal asset loading. Replace the male body name with the female one. + ///// + //[HarmonyPrefix] + //[HarmonyBefore(new string[] { "com.bepis.bepinex.resourceredirector" })] + //[HarmonyPatch(typeof(AssetBundleManager), nameof(AssetBundleManager.LoadAsset), new[] { typeof(string), typeof(string), typeof(Type), typeof(string) })] + //public static void LoadAssetPrefix(ref string assetName) + //{ + // if (assetName == "p_cm_body_00_low") + // assetName = "p_cf_body_00_low"; + // else if (assetName == "p_cm_body_00") + // assetName = "p_cf_body_00"; + //} + ///// + ///// Async asset loading. Probably only used in the intro sequence. + ///// + //[HarmonyPrefix] + //[HarmonyBefore(new string[] { "com.bepis.bepinex.resourceredirector" })] + //[HarmonyPatch(typeof(AssetBundleManager), nameof(AssetBundleManager.LoadAssetAsync), new[] { typeof(string), typeof(string), typeof(Type), typeof(string) })] + //public static void LoadAssetAsyncPrefix(ref string assetName) + //{ + // if (assetName == "p_cm_body_00_low") + // assetName = "p_cf_body_00_low"; + // else if (assetName == "p_cm_body_00") + // assetName = "p_cf_body_00"; + //} + } +} \ No newline at end of file diff --git a/KK_FutaMod/KK_FutaMod.csproj b/KK_FutaMod/KK_FutaMod.csproj new file mode 100644 index 00000000..82329b55 --- /dev/null +++ b/KK_FutaMod/KK_FutaMod.csproj @@ -0,0 +1,70 @@ + + + + + Debug + AnyCPU + {B0B83F4C-6C04-4E90-A75E-62E8F83E8E7D} + Library + Properties + KK_FutaMod + KK_FutaMod + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + embedded + true + ..\bin\ + TRACE + prompt + 4 + true + + + + ..\lib\0Harmony.dll + False + + + ..\lib\Assembly-CSharp.dll + False + + + ..\lib\BepInEx.dll + False + + + ..\lib\ConfigurationManager.dll + False + + + ..\lib\ExtensibleSaveFormat.dll + False + + + + + + + + + ..\lib\UnityEngine.dll + False + + + + + + + + \ No newline at end of file diff --git a/KK_FutaMod/Properties/AssemblyInfo.cs b/KK_FutaMod/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..c91546ba --- /dev/null +++ b/KK_FutaMod/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("KK_FutaMod")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("KK_FutaMod")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b0b83f4c-6c04-4e90-a75e-62e8f83e8e7d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")]