Skip to content

Commit

Permalink
[MSI] Refactor to allow adding new features
Browse files Browse the repository at this point in the history
  • Loading branch information
ManlyMarco committed Jan 21, 2022
1 parent ccaebc3 commit 06d4e0d
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 99 deletions.
14 changes: 14 additions & 0 deletions src/KKS_MoreStoreItems/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using UniRx;

namespace MoreShopItems
{
internal static class Extensions
{
public static void Add(this CompositeDisposable disp, UnityEngine.Object obj)
{
if (disp == null) throw new ArgumentNullException(nameof(disp));
disp.Add(Disposable.Create(() => UnityEngine.Object.Destroy(obj)));
}
}
}
9 changes: 9 additions & 0 deletions src/KKS_MoreStoreItems/Features/IFeature.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using UniRx;

namespace MoreShopItems.Features
{
public interface IFeature
{
bool ApplyFeature(ref CompositeDisposable disp, MoreShopItemsPlugin inst);
}
}
84 changes: 84 additions & 0 deletions src/KKS_MoreStoreItems/Features/TwinTalismanFeat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System;
using KKAPI.MainGame;
using KKAPI.Utilities;
using SaveData;
using UniRx;
using UnityEngine;

namespace MoreShopItems.Features
{
public class TwinTalismanFeat : IFeature
{
public bool ApplyFeature(ref CompositeDisposable disp, MoreShopItemsPlugin inst)
{
var ico = ResourceUtils.GetEmbeddedResource("item_talisman.png", typeof(MoreShopItemsPlugin).Assembly).LoadTexture();
var talismanCategoryId = StoreApi.RegisterShopItemCategory(ico);

disp.Add(ico);

const int talismanItemId = 3456650;
const int maxTalismansOwned = 2;
disp.Add(StoreApi.RegisterShopItem(
itemId: talismanItemId,
itemName: "Twin-making Talisman",
explaination: "An old talisman that was allegedly used for conversing with spirits in the past. It can summon a fake twin of any living person that is experienced in sex. (One time use during H scenes)",
shopType: StoreApi.ShopType.NightOnly,
itemBackground: StoreApi.ShopBackground.Pink,
itemCategory: talismanCategoryId,
stock: maxTalismansOwned,
resetsDaily: false,
cost: 100,
numText: "{0} remaining out of " + maxTalismansOwned));

disp.Add(CustomTrespassingHsceneButtons.AddHsceneTrespassingButtonWithConfirmation(
buttonText: "Let's use a Twin-making Talisman",
spawnConditionCheck: hSprite =>
{
var flags = hSprite.flags;
return (flags.mode == HFlag.EMode.aibu || flags.mode == HFlag.EMode.sonyu || flags.mode == HFlag.EMode.houshi)
&& !flags.isFreeH
// 3P is only available for experienced or horny
&& flags.lstHeroine[0].HExperience >= Heroine.HExperienceKind.慣れ
&& StoreApi.GetItemAmountBought(talismanItemId) > 0
// Only enable if not coming from a peeping H scene, because trying to start 3P in that state just ends the H scene
&& GameObject.FindObjectOfType<HScene>().dataH.peepCategory.Count == 0;
},
confirmBoxTitle: "Hシーン確認",
confirmBoxSentence: "Do you want to use one of your Twin-making Talismans?\n\nIt's supposed to create a twin of the girl, but what will actually happen?",
onConfirmed: hSprite =>
{
MoreShopItemsPlugin.Logger.LogDebug("Twin-making Talisman used");

// Custom code, copy current heroine and add a copy to the "other heroine waiting" field
var hsp = GameObject.FindObjectOfType<HSceneProc>();
if (hsp == null) throw new ArgumentNullException(nameof(hsp));

var currHeroine = hsp.dataH.lstFemale[0];
if (currHeroine == null) throw new ArgumentNullException(nameof(currHeroine));

MoreShopItemsPlugin.Logger.LogDebug($"Creating a copy of the main heroine: {currHeroine.Name} chaCtrl={currHeroine.chaCtrl}");
Heroine.SetBytes(currHeroine.version, Heroine.GetBytes(currHeroine), out var copyHeroine);
copyHeroine.chaCtrl = currHeroine.chaCtrl;
hsp.dataH.newHeroione = copyHeroine;

// Stock game code to initialize the 3P transition
MoreShopItemsPlugin.Logger.LogDebug("Starting 3P transition copied character");
var flags = hSprite.flags;
flags.click = HFlag.ClickKind.end;
flags.isHSceneEnd = true;
flags.numEnd = 2;
//flags.lstHeroine[0].lewdness = 100;
var asi = ActionScene.instance;
if (asi == null) throw new ArgumentNullException(nameof(asi));
if (asi) asi.isPenetration = true;
if (flags.shortcut != null) flags.shortcut.enabled = false;
if (asi) asi.ShortcutKeyEnable(false);

// Eat one of the held items
StoreApi.DecreaseItemAmountBought(talismanItemId);
}));

return true;
}
}
}
3 changes: 3 additions & 0 deletions src/KKS_MoreStoreItems/KKS_MoreShopItems.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,11 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Extensions.cs" />
<Compile Include="Features\IFeature.cs" />
<Compile Include="MoreShopItemsPlugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Features\TwinTalismanFeat.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
Expand Down
140 changes: 41 additions & 99 deletions src/KKS_MoreStoreItems/MoreShopItemsPlugin.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using KKAPI;
using KKAPI.MainGame;
using KKAPI.Utilities;
using SaveData;
using MoreShopItems.Features;
using UniRx;
using UnityEngine;

namespace MoreShopItems
{
Expand All @@ -21,118 +19,62 @@ public class MoreShopItemsPlugin : BaseUnityPlugin

internal static new ManualLogSource Logger;

private static readonly List<IDisposable> _cleanupList = new List<IDisposable>();
private static IDisposable _featureCleanup;

private void Awake()
{
Logger = base.Logger;

_cleanupList.Add(InitTalismanFeature());
_featureCleanup = LoadFeatures();
}

#if DEBUG
private void OnDestroy()
/// <summary>
/// Find all classes implementing IFeature and try to run their apply methods. If any fail to load, attempt to clean up after them.
/// </summary>
private IDisposable LoadFeatures()
{
foreach (var disposable in _cleanupList)
var loadedList = new StringBuilder("Loaded features: ");
var cleanupList = new CompositeDisposable();
var interfaceT = typeof(IFeature);
var ourAss = typeof(MoreShopItemsPlugin).Assembly;
foreach (var featType in ourAss.GetTypes().Where(x => !x.IsAbstract && x.IsClass && interfaceT.IsAssignableFrom(x)))
{
var disp = new CompositeDisposable();
try
{
disposable.Dispose();
var i = (IFeature)Activator.CreateInstance(featType);
if (i.ApplyFeature(ref disp, this))
{
cleanupList.Add(disp);
disp = new CompositeDisposable();
loadedList.Append(featType.Name);
loadedList.Append(" ");
}
else
{
disp.Clear();
}
}
catch (Exception ex)
catch (Exception e)
{
UnityEngine.Debug.LogException(ex);
disp.Dispose();
disp.Clear();

Logger.LogWarning($"Failed to load feature {featType.FullName} with exception: " + e);
}
}
}
#endif

private static IDisposable InitTalismanFeature()
{
IDisposable tb = null;
IDisposable si = null;
Texture2D ico = null;
var disp = Disposable.Create(() =>
{
tb?.Dispose();
si?.Dispose();
Destroy(ico);
});

try
{
ico = ResourceUtils.GetEmbeddedResource("item_talisman.png", typeof(MoreShopItemsPlugin).Assembly).LoadTexture();
var talismanCategoryId = StoreApi.RegisterShopItemCategory(ico);

const int talismanItemId = 3456650;
const int maxTalismansOwned = 2;
si = StoreApi.RegisterShopItem(
itemId: talismanItemId,
itemName: "Twin-making Talisman",
explaination: "An old talisman that was allegedly used for conversing with spirits in the past. It can summon a fake twin of any living person that is experienced in sex. (One time use during H scenes)",
shopType: StoreApi.ShopType.NightOnly,
itemBackground: StoreApi.ShopBackground.Pink,
itemCategory: talismanCategoryId,
stock: maxTalismansOwned,
resetsDaily: false,
cost: 100,
numText: "{0} remaining out of " + maxTalismansOwned);

tb = CustomTrespassingHsceneButtons.AddHsceneTrespassingButtonWithConfirmation(
buttonText: "Let's use a Twin-making Talisman",
spawnConditionCheck: hSprite =>
{
var flags = hSprite.flags;
return (flags.mode == HFlag.EMode.aibu || flags.mode == HFlag.EMode.sonyu || flags.mode == HFlag.EMode.houshi)
&& !flags.isFreeH
// 3P is only available for experienced or horny
&& flags.lstHeroine[0].HExperience >= Heroine.HExperienceKind.慣れ
&& StoreApi.GetItemAmountBought(talismanItemId) > 0
// Only enable if not coming from a peeping H scene, because trying to start 3P in that state just ends the H scene
&& FindObjectOfType<HScene>().dataH.peepCategory.Count == 0;
},
confirmBoxTitle: "Hシーン確認",
confirmBoxSentence: "Do you want to use one of your Twin-making Talismans?\n\nIt's supposed to create a twin of the girl, but what will actually happen?",
onConfirmed: hSprite =>
{
Logger.LogDebug("Twin-making Talisman used");

// Custom code, copy current heroine and add a copy to the "other heroine waiting" field
var hsp = FindObjectOfType<HSceneProc>();
if (hsp == null) throw new ArgumentNullException(nameof(hsp));

var currHeroine = hsp.dataH.lstFemale[0];
if (currHeroine == null) throw new ArgumentNullException(nameof(currHeroine));

Logger.LogDebug($"Creating a copy of the main heroine: {currHeroine.Name} chaCtrl={currHeroine.chaCtrl}");
Heroine.SetBytes(currHeroine.version, Heroine.GetBytes(currHeroine), out var copyHeroine);
copyHeroine.chaCtrl = currHeroine.chaCtrl;
hsp.dataH.newHeroione = copyHeroine;
Logger.LogInfo(loadedList.ToString());

// Stock game code to initialize the 3P transition
Logger.LogDebug("Starting 3P transition copied character");
var flags = hSprite.flags;
flags.click = HFlag.ClickKind.end;
flags.isHSceneEnd = true;
flags.numEnd = 2;
//flags.lstHeroine[0].lewdness = 100;
var asi = ActionScene.instance;
if (asi == null) throw new ArgumentNullException(nameof(asi));
if (asi) asi.isPenetration = true;
if (flags.shortcut != null) flags.shortcut.enabled = false;
if (asi) asi.ShortcutKeyEnable(false);

// Eat one of the held items
StoreApi.DecreaseItemAmountBought(talismanItemId);
});
return cleanupList;
}

return disp;
}
catch
{
disp.Dispose();
throw;
}
#if DEBUG
private void OnDestroy()
{
_featureCleanup?.Dispose();
_featureCleanup = null;
}
#endif
}
}

0 comments on commit 06d4e0d

Please sign in to comment.