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")]