Skip to content
This repository has been archived by the owner on Dec 30, 2024. It is now read-only.

Commit

Permalink
Fix a null reference error, start working on RogueLibs.Interactions
Browse files Browse the repository at this point in the history
  • Loading branch information
Chasmical committed Sep 12, 2020
1 parent ea35366 commit c068196
Show file tree
Hide file tree
Showing 11 changed files with 346 additions and 5 deletions.
69 changes: 69 additions & 0 deletions RogueLibs.Interactions/CustomInteraction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;

namespace RogueLibsCore.Interactions
{
public class CustomInteraction
{
internal CustomInteraction(string id, InteractionType type, CustomName name)
{
Id = id;
Type = type;
ButtonName = name;
}

/// <summary>
/// <para>Identifier of this <see cref="CustomInteraction"/>.</para>
/// </summary>
public string Id { get; }
/// <summary>
/// <para><see cref="InteractionType"/> of this <see cref="CustomInteraction"/>.</para>
/// </summary>
public InteractionType Type { get; set; }

/// <summary>
/// <para>Localizable name of this <see cref="CustomInteraction"/>'s button.</para>
/// </summary>
public CustomName ButtonName { get; }

/// <summary>
/// <para>Method that will determine when this <see cref="CustomInteraction"/> will be active for an object.</para>
/// <para><see cref="Agent"/> arg1 is the interacting player;<br/><see cref="PlayfieldObject"/> arg2 is the object that is being interacted with.</para>
/// </summary>
public Func<Agent, PlayfieldObject, bool> Condition { get; set; }
/// <summary>
/// <para>Method that will determine the cost and the extra text for this <see cref="CustomInteraction"/>'s button. Return <see langword="null"/> to not add anything.</para>
/// <para><see cref="Agent"/> arg1 is the interacting player;<br/><see cref="PlayfieldObject"/> arg2 is the object that is being interacted with;<br/><see cref="InteractionButtonInfo"/> result is a structure containing the cost and the extra text values.</para>
/// </summary>
public Func<Agent, PlayfieldObject, InteractionButtonInfo?> GetButtonInfo { get; set; }
/// <summary>
/// <para>Method that will invoked when interacted with an object directly or via a button.</para>
/// <para><see cref="Agent"/> arg1 is the interacting player;<br/><see cref="PlayfieldObject"/> arg2 is the object that is being interacted with;<br/><see cref="bool"/> result determines whether the interaction should be stopped after interacting.</para>
/// </summary>
public Func<Agent, PlayfieldObject, bool> Action { get; set; }



}
public struct InteractionButtonInfo
{
public InteractionButtonInfo(int cost)
{
Cost = cost;
ExtraText = string.Empty;
}
public InteractionButtonInfo(string extraText)
{
Cost = 0;
ExtraText = extraText;
}
public InteractionButtonInfo(int cost, string extraText)
{
Cost = cost;
ExtraText = extraText;
}

public int Cost { get; set; }
public string ExtraText { get; set; }
}
}
80 changes: 80 additions & 0 deletions RogueLibs.Interactions/InteractionTemplate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEngine;
using HarmonyLib;

namespace RogueLibsCore.Interactions
{
internal class Interaction<T>
where T : PlayfieldObject
{
public void Patch()
{
RoguePatcher patcher = new RoguePatcher(RogueLibsInteractions.PluginInstance, GetType());
patcher.Prefix(typeof(T), "DetermineButtons");
patcher.Prefix(typeof(T), "Interact");
patcher.Prefix(typeof(T), "PressedButton");
}
public virtual bool DetermineButtons(T __instance)
{
while (__instance.buttonPrices.Count < __instance.buttons.Count)
__instance.buttonPrices.Add(0);
while (__instance.buttonsExtra.Count < __instance.buttons.Count)
__instance.buttonsExtra.Add(string.Empty);

List<CustomInteraction> allInteractions = RogueLibsInteractions.CustomInteractions.FindAll(i => i.Condition?.Invoke(__instance.interactingAgent, __instance) ?? false);
foreach (CustomInteraction interaction in allInteractions)
{
if ((interaction.Type & InteractionType.Button) != 0)
{
InteractionButtonInfo? info = interaction.GetButtonInfo(__instance.interactingAgent, __instance);
__instance.buttons.Add(interaction.Id);
__instance.buttonPrices.Add(info?.Cost ?? 0);
__instance.buttonsExtra.Add(info?.ExtraText ?? string.Empty);
}
}
return false;
}
public virtual bool Interact(T __instance, Agent agent)
{
MethodInfo baseMethod = AccessTools.Method(__instance.GetType().BaseType, "Interact");
baseMethod.Invoke(__instance, new object[] { agent });

List<CustomInteraction> allInteractions = RogueLibsInteractions.CustomInteractions.FindAll(i => i.Condition?.Invoke(__instance.interactingAgent, __instance) ?? false);
List<CustomInteraction> actionsOnly = allInteractions.FindAll(i => i.Type == InteractionType.Interact);
List<CustomInteraction> possibleButtons = allInteractions.FindAll(i => i.Type == InteractionType.InteractOrButton);
List<CustomInteraction> buttonsOnly = allInteractions.FindAll(i => i.Type == InteractionType.Button);
__instance.DetermineButtons();
List<string> origButtons = __instance.buttons;

foreach (CustomInteraction action in actionsOnly)
{
action.Action?.Invoke(__instance.interactingAgent, __instance);
__instance.StopInteraction();
}
if (possibleButtons.Count == 1 && (buttonsOnly.Count == 0 && origButtons.Count == 0))
{
possibleButtons[0].Action?.Invoke(__instance.interactingAgent, __instance);
__instance.StopInteraction();
}
else if (possibleButtons.Count > 0 || (buttonsOnly.Count > 0 || origButtons.Count > 0))
{
__instance.ShowObjectButtons();
}
return false;

}
public virtual bool PressedButton(T __instance, string buttonText, int buttonPrice)
{
CustomInteraction interaction = RogueLibsInteractions.GetCustomInteraction(buttonText);
if (interaction == null) return true;
bool stopInteracting = interaction.Action?.Invoke(__instance.interactingAgent, __instance) ?? false;
if (stopInteracting) __instance.StopInteraction();
else __instance.RefreshButtons();
return false;
}
}
}
36 changes: 36 additions & 0 deletions RogueLibs.Interactions/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -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("RogueLibs.Interactions")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RogueLibs.Interactions")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[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("c933c4df-e3b1-48a5-8c82-a6c53cb56020")]

// 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("2.1.1.0")]
[assembly: AssemblyFileVersion("2.1.1.0")]
68 changes: 68 additions & 0 deletions RogueLibs.Interactions/RogueLibs.Interactions.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C933C4DF-E3B1-48A5-8C82-A6C53CB56020}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>RogueLibsCore.Interactions</RootNamespace>
<AssemblyName>RogueLibs.Interactions</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="0Harmony">
<HintPath>..\Libraries\0Harmony.dll</HintPath>
</Reference>
<Reference Include="Assembly-CSharp">
<HintPath>..\Libraries\Assembly-CSharp.dll</HintPath>
</Reference>
<Reference Include="BepInEx">
<HintPath>..\Libraries\BepInEx.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="UnityEngine">
<HintPath>..\Libraries\UnityEngine.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.CoreModule">
<HintPath>..\Libraries\UnityEngine.CoreModule.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="CustomInteraction.cs" />
<Compile Include="InteractionTemplate.cs" />
<Compile Include="RogueLibsInteractionsPlugin.cs" />
<Compile Include="RogueLibsInteractions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RogueLibs\RogueLibs.csproj">
<Project>{a1764685-f31f-4864-aab6-99870b10c239}</Project>
<Name>RogueLibs</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Patches\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
52 changes: 52 additions & 0 deletions RogueLibs.Interactions/RogueLibsInteractions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using BepInEx;
using BepInEx.Logging;
using UnityEngine;

namespace RogueLibsCore.Interactions
{
public static class RogueLibsInteractions
{
public const string pluginGuid = "abbysssal.streetsofrogue.roguelibs.interactions";
public const string pluginName = "RogueLibs Interactions";
public const string pluginVersion = "2.1.1";

public static RogueLibsInteractionsPlugin PluginInstance;
internal static ManualLogSource Logger;

public static List<CustomInteraction> CustomInteractions { get; } = new List<CustomInteraction>();

public static CustomInteraction GetCustomInteraction(string id) => CustomInteractions.Find(i => i.Id == id);
public static CustomInteraction CreateCustomInteraction(string id, InteractionType type, CustomNameInfo? buttonName, Func<Agent, PlayfieldObject, bool> condition)
{
CustomInteraction customInteraction = GetCustomInteraction(id);
if (customInteraction != null)
{
string message = string.Concat("A CustomInteraction with Id \"", id, "\" already exists!");
Logger.LogError(message);
throw new ArgumentException(message, nameof(id));
}
CustomInteractions.Add(customInteraction = new CustomInteraction(id, type,
buttonName.HasValue ? RogueLibs.CreateCustomName(id, "Interface", buttonName.Value) : null));
customInteraction.Condition = condition;

Logger.LogDebug(string.Concat("A CustomInteraction with Id \"", id, "\" (", type.ToString(), ") was created."));

return customInteraction;
}




}
[Flags] public enum InteractionType
{
// Interact only
Interact = 0b_01,
// Button only
Button = 0b_10,
// Button if Interact is not possible; otherwise, Interact
InteractOrButton = 0b_11
}
}
27 changes: 27 additions & 0 deletions RogueLibs.Interactions/RogueLibsInteractionsPlugin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using BepInEx;
using BepInEx.Logging;

namespace RogueLibsCore.Interactions
{
[BepInPlugin(RogueLibsInteractions.pluginGuid, RogueLibsInteractions.pluginName, RogueLibsInteractions.pluginVersion)]
[BepInDependency(RogueLibs.pluginGuid, RogueLibsInteractions.pluginVersion)]
public partial class RogueLibsInteractionsPlugin : BaseUnityPlugin
{
protected static ManualLogSource MyLogger;

public void Awake()
{
RogueLibsInteractions.PluginInstance = this;
RogueLibsInteractions.Logger = MyLogger = Logger;

RoguePatcher patcher = new RoguePatcher(this, GetType());





}

}
}
6 changes: 6 additions & 0 deletions RogueLibs.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RogueLibs", "RogueLibs\Rogu
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RogueLibs.Test", "RogueLibs.Test\RogueLibs.Test.csproj", "{D4A59C1A-DCDA-4DE8-80DF-7B802707000F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RogueLibs.Interactions", "RogueLibs.Interactions\RogueLibs.Interactions.csproj", "{C933C4DF-E3B1-48A5-8C82-A6C53CB56020}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -21,6 +23,10 @@ Global
{D4A59C1A-DCDA-4DE8-80DF-7B802707000F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4A59C1A-DCDA-4DE8-80DF-7B802707000F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4A59C1A-DCDA-4DE8-80DF-7B802707000F}.Release|Any CPU.Build.0 = Release|Any CPU
{C933C4DF-E3B1-48A5-8C82-A6C53CB56020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C933C4DF-E3B1-48A5-8C82-A6C53CB56020}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C933C4DF-E3B1-48A5-8C82-A6C53CB56020}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C933C4DF-E3B1-48A5-8C82-A6C53CB56020}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
4 changes: 2 additions & 2 deletions RogueLibs/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@
// Можно задать все значения или принять номера сборки и редакции по умолчанию
// используя "*", как показано ниже:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.1.0.0")]
[assembly: AssemblyFileVersion("2.1.0.0")]
[assembly: AssemblyVersion("2.1.1.0")]
[assembly: AssemblyFileVersion("2.1.1.0")]
2 changes: 1 addition & 1 deletion RogueLibs/RogueLibs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static class RogueLibs
/// <summary>
/// <para><see cref="RogueLibs"/>' version. Do not use this value in your <see cref="BepInDependency"/> attribute!</para>
/// </summary>
public const string pluginVersion = "2.1";
public const string pluginVersion = "2.1.1";

/// <summary>
/// <para>Main <see cref="RogueLibsPlugin"/> instance.</para>
Expand Down
4 changes: 2 additions & 2 deletions RogueLibs/RogueLibsPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ protected static bool ScrollingMenu_Setup(ScrollingMenu __instance, ButtonData m
myButtonData.scrollingHighlighted4 = (__instance.menuType == "Items" || __instance.menuType == "TraitUnlocks") && myUnlock.notActive; // gray 'not active' highlight
myButtonData.highlightedSprite = __instance.solidObjectButton;
}
else if ((custom == null && myUnlock.cost != 0) || custom.UnlockCost != null)
else if ((custom == null && myUnlock.cost != 0) || custom?.UnlockCost != null)
{ // not unlocked, original mutator OR custom and can be purchased
myButtonData.buttonText += " - $" + myUnlock.cost;
myButtonData.scrollingHighlighted2 = true; // blue 'purchasable' highlight
Expand Down Expand Up @@ -865,7 +865,7 @@ protected static bool CharacterCreation_Setup(CharacterCreation __instance, Butt
myButtonData.scrollingHighlighted4 = false;
myButtonData.highlightedSprite = __instance.solidObjectButton;
}
else if ((custom == null && myUnlock.cost != 0) || custom.UnlockCost != null) // not unlocked, original mutator OR custom and can be purchased
else if ((custom == null && myUnlock.cost != 0) || custom?.UnlockCost != null) // not unlocked, original mutator OR custom and can be purchased
{
myButtonData.buttonText = __instance.gc.nameDB.GetName(myUnlock.unlockName, myUnlock.unlockNameType) + " - $" + myUnlock.cost;
myButtonData.scrollingHighlighted2 = true; // blue 'purchasable' highlight
Expand Down
Loading

0 comments on commit c068196

Please sign in to comment.