mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-20 01:46:15 +00:00
Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb99f02549 | ||
|
|
8382b9adf1 | ||
|
|
cb1a818377 | ||
|
|
e950278bf9 | ||
|
|
3de9482233 | ||
|
|
4508aaeb55 | ||
|
|
ee15a1acbe | ||
|
|
113c716fd3 | ||
|
|
f7c34fb5cd | ||
|
|
37446964c5 |
No files matched your search
@@ -5,19 +5,26 @@ namespace MiraAPI.Example.Roles;
|
||||
|
||||
public class NeutralKillerRole : ImpostorRole, ICustomRole
|
||||
{
|
||||
public string RoleName => "Neutral Killer";
|
||||
public string RoleDescription => "Neutral who can kill.";
|
||||
public string RoleName => "Outcast Killer";
|
||||
public string RoleDescription => "Outcast who can kill.";
|
||||
public string RoleLongDescription => RoleDescription;
|
||||
public Color RoleColor => Color.magenta;
|
||||
public ModdedRoleTeams Team => ModdedRoleTeams.Neutral;
|
||||
public ModdedRoleTeams Team => ModdedRoleTeams.Custom;
|
||||
|
||||
public CustomRoleConfiguration Configuration => new CustomRoleConfiguration(this)
|
||||
public CustomRoleConfiguration Configuration => new(this)
|
||||
{
|
||||
UseVanillaKillButton = true,
|
||||
CanGetKilled = true,
|
||||
CanUseVent = true,
|
||||
};
|
||||
|
||||
public RoleOptionsGroup RoleOptionsGroup { get; } = new("Outcast", Color.gray);
|
||||
|
||||
public TeamIntroConfiguration? IntroConfiguration { get; } = new(
|
||||
Color.gray,
|
||||
"NEUTRAL",
|
||||
"You are an Outcast. You do not have a team.");
|
||||
|
||||
public override void SpawnTaskHeader(PlayerControl playerControl)
|
||||
{
|
||||
// remove existing task header.
|
||||
|
||||
@@ -30,6 +30,24 @@ public static class IntroCutscenePatches
|
||||
MiraEventManager.InvokeEvent(@event);
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(IntroCutscene.BeginImpostor))]
|
||||
public static void BeginImpostorPatch(IntroCutscene __instance)
|
||||
{
|
||||
if (PlayerControl.LocalPlayer.Data.Role is not ICustomRole customRole)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (customRole.IntroConfiguration is { } introConfig)
|
||||
{
|
||||
__instance.BackgroundBar.material.SetColor(ShaderID.Color, introConfig.IntroTeamColor);
|
||||
__instance.TeamTitle.color = introConfig.IntroTeamColor;
|
||||
__instance.TeamTitle.text = introConfig.IntroTeamTitle;
|
||||
__instance.ImpostorText.text = introConfig.IntroTeamDescription;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(IntroCutscene.BeginCrewmate))]
|
||||
public static bool BeginCrewmatePatch(IntroCutscene __instance)
|
||||
@@ -39,7 +57,15 @@ public static class IntroCutscenePatches
|
||||
return true;
|
||||
}
|
||||
|
||||
if (customRole.Team is not ModdedRoleTeams.Neutral)
|
||||
if (customRole.IntroConfiguration is { } introConfig)
|
||||
{
|
||||
__instance.BackgroundBar.material.SetColor(ShaderID.Color, introConfig.IntroTeamColor);
|
||||
__instance.TeamTitle.color = introConfig.IntroTeamColor;
|
||||
__instance.TeamTitle.text = introConfig.IntroTeamTitle;
|
||||
__instance.ImpostorText.text = introConfig.IntroTeamDescription;
|
||||
}
|
||||
|
||||
if (customRole.Team is not ModdedRoleTeams.Custom)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -49,11 +75,7 @@ public static class IntroCutscenePatches
|
||||
position.y -= 0.25f;
|
||||
barTransform.position = position;
|
||||
|
||||
__instance.BackgroundBar.material.SetColor(ShaderID.Color, Color.gray);
|
||||
__instance.TeamTitle.text = "NEUTRAL";
|
||||
__instance.impostorScale = 1f;
|
||||
__instance.ImpostorText.text = "You are Neutral. You do not have a team.";
|
||||
__instance.TeamTitle.color = Color.gray;
|
||||
|
||||
__instance.ourCrewmate = __instance.CreatePlayer(
|
||||
0,
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using Reactor.Localization.Utilities;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
@@ -20,6 +22,10 @@ namespace MiraAPI.Patches.Options;
|
||||
[HarmonyPatch(typeof(RolesSettingsMenu))]
|
||||
public static class RoleSettingMenuPatches
|
||||
{
|
||||
private static Dictionary<RoleOptionsGroup, bool> RoleGroupHidden { get; } = [];
|
||||
private static List<CategoryHeaderEditRole> CategoryHeaderEditRoles { get; } = [];
|
||||
private static List<RoleOptionSetting> RoleOptionSettings { get; } = [];
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(RolesSettingsMenu.SetQuotaTab))]
|
||||
public static bool PatchStart(RolesSettingsMenu __instance)
|
||||
@@ -54,89 +60,107 @@ public static class RoleSettingMenuPatches
|
||||
|
||||
var num3 = 0;
|
||||
|
||||
var crewRoles = GameSettingMenuPatches.SelectedMod?.CustomRoles.Values
|
||||
.OfType<ICustomRole>()
|
||||
.Where(role => role is { Team: ModdedRoleTeams.Crewmate, Configuration.HideSettings: false })
|
||||
.ToList() ?? [];
|
||||
var roleGroups = GameSettingMenuPatches.SelectedMod?.CustomRoles.Values.OfType<ICustomRole>()
|
||||
.ToLookup(x => x.RoleOptionsGroup);
|
||||
|
||||
if (crewRoles is { Count: > 0 })
|
||||
if (roleGroups is null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// sort the groups by priority
|
||||
var sortedRoleGroups = roleGroups
|
||||
.OrderBy(x => x.Key.Priority)
|
||||
.ThenBy(x => x.Key.Name);
|
||||
|
||||
foreach (var grouping in sortedRoleGroups)
|
||||
{
|
||||
if (!grouping.Any())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RoleGroupHidden.TryAdd(grouping.Key, false);
|
||||
|
||||
var name = grouping.Key.Name switch
|
||||
{
|
||||
"Crewmate" => StringNames.CrewmateRolesHeader,
|
||||
"Impostor" => StringNames.ImpostorRolesHeader,
|
||||
_ => CustomStringName.CreateAndRegister(grouping.Key.Name),
|
||||
};
|
||||
|
||||
var categoryHeaderEditRole = Object.Instantiate(
|
||||
__instance.categoryHeaderEditRoleOrigin,
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
__instance.RoleChancesSettings.transform);
|
||||
categoryHeaderEditRole.SetHeader(StringNames.CrewmateRolesHeader, 20);
|
||||
categoryHeaderEditRole.SetHeader(name, 20);
|
||||
categoryHeaderEditRole.transform.localPosition = new Vector3(4.986f, num, -2f);
|
||||
categoryHeaderEditRole.transform.Find("LabelSprite").transform.localScale = new Vector3(1.3f, 1, 0.5529f);
|
||||
categoryHeaderEditRole.transform.Find("QuotaHeader").gameObject.SetActive(!RoleGroupHidden[grouping.Key]);
|
||||
|
||||
CategoryHeaderEditRoles.Add(categoryHeaderEditRole);
|
||||
|
||||
num -= 0.522f;
|
||||
|
||||
foreach (var role in crewRoles)
|
||||
var label = RoleGroupHidden[grouping.Key]
|
||||
? "(Click to open)"
|
||||
: "(Click to close)";
|
||||
var newText = Object.Instantiate(categoryHeaderEditRole.Title, categoryHeaderEditRole.transform);
|
||||
newText.text = $"<size=50%>{label}</size>";
|
||||
newText.transform.localPosition = new Vector3(-3.3425f, -0.1706f, -1);
|
||||
newText.gameObject.GetComponent<TextTranslatorTMP>().Destroy();
|
||||
|
||||
if (!RoleGroupHidden[grouping.Key])
|
||||
{
|
||||
if (role is RoleBehaviour roleBehaviour)
|
||||
foreach (var role in grouping)
|
||||
{
|
||||
CreateQuotaOption(__instance, roleBehaviour, ref num, num3);
|
||||
if (role is not RoleBehaviour roleBehaviour)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var option = CreateQuotaOption(__instance, roleBehaviour, ref num, num3);
|
||||
if (option is not null)
|
||||
{
|
||||
RoleOptionSettings.Add(option);
|
||||
num3++;
|
||||
}
|
||||
}
|
||||
num3++;
|
||||
}
|
||||
|
||||
var boxCol = categoryHeaderEditRole.gameObject.AddComponent<BoxCollider2D>();
|
||||
boxCol.size = new Vector2(3, 0.25f);
|
||||
boxCol.offset = new Vector2(-2.05f, -.175f);
|
||||
|
||||
var headerBtn = categoryHeaderEditRole.gameObject.AddComponent<PassiveButton>();
|
||||
headerBtn.ClickSound = __instance.BackButton.GetComponent<PassiveButton>().ClickSound;
|
||||
headerBtn.OnMouseOver = new UnityEvent();
|
||||
headerBtn.OnMouseOut = new UnityEvent();
|
||||
headerBtn.OnClick.AddListener(
|
||||
(UnityAction)(() =>
|
||||
{
|
||||
RoleGroupHidden[grouping.Key] = !RoleGroupHidden[grouping.Key];
|
||||
foreach (var header in CategoryHeaderEditRoles)
|
||||
{
|
||||
header.gameObject.Destroy();
|
||||
}
|
||||
CategoryHeaderEditRoles.Clear();
|
||||
foreach (var option in RoleOptionSettings)
|
||||
{
|
||||
option.gameObject.Destroy();
|
||||
}
|
||||
RoleOptionSettings.Clear();
|
||||
__instance.SetQuotaTab();
|
||||
}));
|
||||
headerBtn.SetButtonEnableState(true);
|
||||
|
||||
if (!RoleGroupHidden[grouping.Key])
|
||||
{
|
||||
num -= 0.4f;
|
||||
}
|
||||
}
|
||||
|
||||
var impRoles = GameSettingMenuPatches.SelectedMod?.CustomRoles.Values
|
||||
.OfType<ICustomRole>()
|
||||
.Where(role => role is { Team: ModdedRoleTeams.Impostor, Configuration.HideSettings: false })
|
||||
.ToList() ?? [];
|
||||
|
||||
if (impRoles is { Count: > 0 })
|
||||
{
|
||||
num -= 0.4f;
|
||||
var categoryHeaderEditRole2 = Object.Instantiate(
|
||||
__instance.categoryHeaderEditRoleOrigin,
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
__instance.RoleChancesSettings.transform);
|
||||
categoryHeaderEditRole2.SetHeader(StringNames.ImpostorRolesHeader, 20);
|
||||
categoryHeaderEditRole2.transform.localPosition = new Vector3(4.986f, num, -2f);
|
||||
num -= 0.522f;
|
||||
|
||||
foreach (var role in impRoles)
|
||||
{
|
||||
if (role is RoleBehaviour roleBehaviour)
|
||||
{
|
||||
CreateQuotaOption(__instance, roleBehaviour, ref num, num3);
|
||||
}
|
||||
num3++;
|
||||
}
|
||||
}
|
||||
|
||||
var neutRoles = GameSettingMenuPatches.SelectedMod?.CustomRoles.Values
|
||||
.OfType<ICustomRole>()
|
||||
.Where(role => role is { Team: ModdedRoleTeams.Neutral, Configuration.HideSettings: false })
|
||||
.ToList() ?? [];
|
||||
|
||||
if (neutRoles is { Count: > 0 })
|
||||
{
|
||||
num -= 0.4f;
|
||||
var categoryHeaderEditRole3 = Object.Instantiate(
|
||||
__instance.categoryHeaderEditRoleOrigin,
|
||||
Vector3.zero,
|
||||
Quaternion.identity,
|
||||
__instance.RoleChancesSettings.transform);
|
||||
categoryHeaderEditRole3.SetHeader(StringNames.None, 20);
|
||||
categoryHeaderEditRole3.Title.text = "Neutral Roles";
|
||||
categoryHeaderEditRole3.Background.color = Color.gray;
|
||||
categoryHeaderEditRole3.Title.color = Color.white;
|
||||
categoryHeaderEditRole3.transform.localPosition = new Vector3(4.986f, num, -2f);
|
||||
num -= 0.522f;
|
||||
|
||||
foreach (var role in neutRoles)
|
||||
{
|
||||
if (role is RoleBehaviour roleBehaviour)
|
||||
{
|
||||
CreateQuotaOption(__instance, roleBehaviour, ref num, num3);
|
||||
}
|
||||
num3++;
|
||||
}
|
||||
}
|
||||
|
||||
__instance.scrollBar.CalculateAndSetYBounds(__instance.roleChances.Count + 5, 1f, 6f, 0.43f);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -295,12 +319,12 @@ public static class RoleSettingMenuPatches
|
||||
__instance.RefreshChildren();
|
||||
}
|
||||
|
||||
private static void CreateQuotaOption(RolesSettingsMenu __instance, RoleBehaviour role, ref float yPos, int index)
|
||||
private static RoleOptionSetting? CreateQuotaOption(RolesSettingsMenu __instance, RoleBehaviour role, ref float yPos, int index)
|
||||
{
|
||||
if (role is not ICustomRole customRole)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Role {role.NiceName} is not a custom role.");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
var roleOptionSetting = Object.Instantiate(
|
||||
@@ -357,5 +381,7 @@ public static class RoleSettingMenuPatches
|
||||
{
|
||||
yPos += -0.43f;
|
||||
}
|
||||
|
||||
return roleOptionSetting;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
using AmongUs.GameOptions;
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
@@ -21,6 +21,10 @@ public static class TaskAdderPatch
|
||||
private static readonly Dictionary<string, string> ModsFolders = [];
|
||||
private static Scroller? _scroller;
|
||||
|
||||
/// <summary>
|
||||
/// Adds custom roles to the TaskAdder.
|
||||
/// </summary>
|
||||
/// <param name="__instance">TaskAdder instance.</param>
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(TaskAdderGame), nameof(TaskAdderGame.Begin))]
|
||||
public static void AddRolesFolder(TaskAdderGame __instance)
|
||||
@@ -86,13 +90,17 @@ public static class TaskAdderPatch
|
||||
__instance.GoToRoot();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the color of the role button based on the role.
|
||||
/// </summary>
|
||||
/// <param name="__instance">TaskAddButton instance.</param>
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(TaskAddButton), "Role", MethodType.Setter)]
|
||||
[HarmonyPatch(typeof(TaskAddButton), nameof(TaskAddButton.Role), MethodType.Setter)]
|
||||
public static void RoleGetterPatch(TaskAddButton __instance)
|
||||
{
|
||||
if (__instance.role is ICustomRole { Team: ModdedRoleTeams.Neutral })
|
||||
if (__instance.role is ICustomRole { Team: ModdedRoleTeams.Custom } customRole)
|
||||
{
|
||||
__instance.FileImage.color = Color.gray;
|
||||
__instance.FileImage.color = customRole.IntroConfiguration?.IntroTeamColor ?? Color.gray;
|
||||
}
|
||||
|
||||
__instance.RolloverHandler.OutColor = __instance.FileImage.color;
|
||||
@@ -186,23 +194,23 @@ public static class TaskAdderPatch
|
||||
switch (taskAddButton.MyTask.TaskType)
|
||||
{
|
||||
case TaskTypes.DivertPower:
|
||||
{
|
||||
var targetSystem = taskAddButton.MyTask.Cast<DivertPowerTask>().TargetSystem;
|
||||
taskAddButton.Text.text = TranslationController.Instance.GetString(
|
||||
StringNames.DivertPowerTo,
|
||||
TranslationController.Instance.GetString(targetSystem));
|
||||
break;
|
||||
}
|
||||
{
|
||||
var targetSystem = taskAddButton.MyTask.Cast<DivertPowerTask>().TargetSystem;
|
||||
taskAddButton.Text.text = TranslationController.Instance.GetString(
|
||||
StringNames.DivertPowerTo,
|
||||
TranslationController.Instance.GetString(targetSystem));
|
||||
break;
|
||||
}
|
||||
case TaskTypes.FixWeatherNode:
|
||||
{
|
||||
var nodeId = taskAddButton.MyTask.Cast<WeatherNodeTask>().NodeId;
|
||||
taskAddButton.Text.text =
|
||||
TranslationController.Instance.GetString(
|
||||
StringNames.FixWeatherNode) + " " +
|
||||
TranslationController.Instance.GetString(
|
||||
WeatherSwitchGame.ControlNames[nodeId]);
|
||||
break;
|
||||
}
|
||||
{
|
||||
var nodeId = taskAddButton.MyTask.Cast<WeatherNodeTask>().NodeId;
|
||||
taskAddButton.Text.text =
|
||||
TranslationController.Instance.GetString(
|
||||
StringNames.FixWeatherNode) + " " +
|
||||
TranslationController.Instance.GetString(
|
||||
WeatherSwitchGame.ControlNames[nodeId]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
taskAddButton.Text.text =
|
||||
TranslationController.Instance.GetString(taskAddButton.MyTask.TaskType);
|
||||
@@ -276,7 +284,7 @@ public static class TaskAdderPatch
|
||||
{
|
||||
var roleBehaviour = plugin.CustomRoles.ElementAt(m).Value;
|
||||
if (roleBehaviour.Role == RoleTypes.ImpostorGhost || roleBehaviour.Role == RoleTypes.CrewmateGhost ||
|
||||
roleBehaviour.IsDead)
|
||||
(roleBehaviour is ICustomRole customRole && !customRole.Configuration.ShowInFreeplay))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -21,4 +21,16 @@ public static class MinigameStubs
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverse patch for Minigame.Close.
|
||||
/// </summary>
|
||||
/// <param name="instance">The Minigame instance.</param>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(Minigame), nameof(Minigame.Close), [])]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void Close(Minigame instance)
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using HarmonyLib;
|
||||
using Il2CppSystem.Text;
|
||||
|
||||
namespace MiraAPI.Patches.Stubs;
|
||||
|
||||
[HarmonyPatch]
|
||||
public static class RoleBehaviourStubs
|
||||
{
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.Initialize.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.Initialize))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void Initialize(RoleBehaviour instance)
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.AdjustTasks.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
/// <param name="player">The PlayerControl to adjust tasks for.</param>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.AdjustTasks))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void AdjustTasks(RoleBehaviour instance, PlayerControl player)
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.AppendTaskHint.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
/// <param name="taskStringBuilder">The StringBuilder to append the task hint to.</param>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.AppendTaskHint))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void AppendTaskHint(RoleBehaviour instance, StringBuilder taskStringBuilder)
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.CanUse.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
/// <param name="console">The IUsable console to check.</param>
|
||||
/// <returns>Whether the console can be used.</returns>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.CanUse))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static bool CanUse(RoleBehaviour instance, IUsable console)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.Deinitialize.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
/// <param name="targetPlayer">The PlayerControl to deinitialize for.</param>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.Deinitialize))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void Deinitialize(RoleBehaviour instance, PlayerControl targetPlayer)
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.DidWin.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
/// <param name="gameOverReason">The reason for game over.</param>
|
||||
/// <returns>Whether the role won.</returns>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.DidWin))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static bool DidWin(RoleBehaviour instance, GameOverReason gameOverReason)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.FindClosestTarget.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
/// <returns>The closest target PlayerControl.</returns>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.FindClosestTarget))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static PlayerControl FindClosestTarget(RoleBehaviour instance)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.GetAbilityDistance.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
/// <returns>The ability distance.</returns>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.GetAbilityDistance))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static float GetAbilityDistance(RoleBehaviour instance)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.IsValidTarget.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
/// <param name="target">The NetworkedPlayerInfo to validate.</param>
|
||||
/// <returns>Whether the target is valid.</returns>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.IsValidTarget))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static bool IsValidTarget(RoleBehaviour instance, NetworkedPlayerInfo target)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.OnDeath.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
/// <param name="reason">The reason for death.</param>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.OnDeath))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void OnDeath(RoleBehaviour instance, DeathReason reason)
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.OnMeetingStart.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.OnMeetingStart))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void OnMeetingStart(RoleBehaviour instance)
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.OnVotingComplete.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.OnVotingComplete))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void OnVotingComplete(RoleBehaviour instance)
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.SetCooldown.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.SetCooldown))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void SetCooldown(RoleBehaviour instance)
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.SetPlayerTarget.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
/// <param name="target">The PlayerControl target to set.</param>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.SetPlayerTarget))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void SetPlayerTarget(RoleBehaviour instance, PlayerControl target)
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.SetUsableTarget.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
/// <param name="target">The IUsable target to set.</param>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.SetUsableTarget))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void SetUsableTarget(RoleBehaviour instance, IUsable target)
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.SpawnTaskHeader.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
/// <param name="playerControl">The PlayerControl to spawn the task header for.</param>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.SpawnTaskHeader))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void SpawnTaskHeader(RoleBehaviour instance, PlayerControl playerControl)
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stub method for RoleBehaviour.UseAbility.
|
||||
/// </summary>
|
||||
/// <param name="instance">The RoleBehaviour object.</param>
|
||||
[HarmonyReversePatch]
|
||||
[HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.UseAbility))]
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static void UseAbility(RoleBehaviour instance)
|
||||
{
|
||||
// nothing needed
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace MiraAPI.Roles;
|
||||
/// <summary>
|
||||
/// Used to configure the specific settings of a role.
|
||||
/// </summary>
|
||||
public struct CustomRoleConfiguration
|
||||
public record struct CustomRoleConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CustomRoleConfiguration"/> struct.
|
||||
@@ -17,11 +17,6 @@ public struct CustomRoleConfiguration
|
||||
{
|
||||
var roleBehaviour = role as RoleBehaviour;
|
||||
|
||||
MaxRoleCount = 15;
|
||||
DefaultRoleCount = 0;
|
||||
DefaultChance = 0;
|
||||
|
||||
OptionsScreenshot = Icon = MiraAssets.Empty;
|
||||
AffectedByLightOnAirship = role.Team == ModdedRoleTeams.Crewmate;
|
||||
KillButtonOutlineColor = role.Team switch
|
||||
{
|
||||
@@ -29,7 +24,6 @@ public struct CustomRoleConfiguration
|
||||
ModdedRoleTeams.Crewmate => Palette.CrewmateBlue,
|
||||
_ => role.RoleColor,
|
||||
};
|
||||
RoleHintType = RoleHintType.RoleTab;
|
||||
GhostRole = role.Team is ModdedRoleTeams.Impostor ? RoleTypes.ImpostorGhost : RoleTypes.CrewmateGhost;
|
||||
CanGetKilled = roleBehaviour?.IsDead == false && role.Team is not ModdedRoleTeams.Impostor;
|
||||
UseVanillaKillButton = role.Team is ModdedRoleTeams.Impostor;
|
||||
@@ -37,86 +31,91 @@ public struct CustomRoleConfiguration
|
||||
CanUseSabotage = role.Team is ModdedRoleTeams.Impostor;
|
||||
TasksCountForProgress = role.Team is ModdedRoleTeams.Crewmate;
|
||||
HideSettings = roleBehaviour?.IsDead == true;
|
||||
CanModifyChance = true;
|
||||
ShowInFreeplay = roleBehaviour?.IsDead == false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hard limit of players that can have this role. This property is used to set a limit in the Role Options menu. If set to 0, the role will not be assigned at start.
|
||||
/// Gets or sets the hard limit of players that can have this role. This property is used to set a limit in the Role Options menu. If set to 0, the role will not be assigned at start.
|
||||
/// </summary>
|
||||
public int MaxRoleCount;
|
||||
public int MaxRoleCount { get; set; } = 15;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default role count.
|
||||
/// Gets or sets the default role count.
|
||||
/// </summary>
|
||||
public int DefaultRoleCount;
|
||||
public int DefaultRoleCount { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default role chance.
|
||||
/// Gets or sets the default role chance.
|
||||
/// </summary>
|
||||
public int DefaultChance;
|
||||
public int DefaultChance { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the chance option can be changed or not.
|
||||
/// Gets or sets a value indicating whether the chance option can be changed or not.
|
||||
/// </summary>
|
||||
public bool CanModifyChance;
|
||||
public bool CanModifyChance { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Sprite used for the Role Options menu screenshot.
|
||||
/// Gets or sets the Sprite used for the Role Options menu screenshot.
|
||||
/// </summary>
|
||||
public LoadableAsset<Sprite> OptionsScreenshot;
|
||||
public LoadableAsset<Sprite> OptionsScreenshot { get; set; } = MiraAssets.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Sprite used for the Role Icon.
|
||||
/// Gets or sets the Sprite used for the Role Icon.
|
||||
/// </summary>
|
||||
public LoadableAsset<Sprite> Icon;
|
||||
public LoadableAsset<Sprite> Icon { get; set; } = MiraAssets.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the role is affected by light affectors on Airship.
|
||||
/// Gets or sets a value indicating whether the role is affected by light affectors on Airship.
|
||||
/// </summary>
|
||||
public bool AffectedByLightOnAirship;
|
||||
public bool AffectedByLightOnAirship { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the role can be killed by vanilla murder system.
|
||||
/// Gets or sets a value indicating whether the role can be killed by vanilla murder system.
|
||||
/// </summary>
|
||||
public bool CanGetKilled;
|
||||
public bool CanGetKilled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the role should use the vanilla kill button.
|
||||
/// Gets or sets a value indicating whether the role should use the vanilla kill button.
|
||||
/// </summary>
|
||||
public bool UseVanillaKillButton;
|
||||
public bool UseVanillaKillButton { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the role can use vents.
|
||||
/// Gets or sets a value indicating whether the role can use vents.
|
||||
/// </summary>
|
||||
public bool CanUseVent;
|
||||
public bool CanUseVent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the role can use the sabotage button.
|
||||
/// Gets or sets a value indicating whether the role can use the sabotage button.
|
||||
/// </summary>
|
||||
public bool CanUseSabotage;
|
||||
public bool CanUseSabotage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the role's tasks count towards task progress.
|
||||
/// Gets or sets a value indicating whether the role's tasks count towards task progress.
|
||||
/// </summary>
|
||||
public bool TasksCountForProgress;
|
||||
public bool TasksCountForProgress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the role should show up in the Role Options menu.
|
||||
/// Gets or sets a value indicating whether the role should show up in the Role Options menu.
|
||||
/// </summary>
|
||||
public bool HideSettings;
|
||||
public bool HideSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the outline color for the KillButton if <see cref="UseVanillaKillButton"/> is true.
|
||||
/// Gets or sets a value indicating whether the role should show up in the Freeplay Role Selection menu.
|
||||
/// </summary>
|
||||
public Color KillButtonOutlineColor;
|
||||
public bool ShowInFreeplay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the role hint style. See <see cref="RoleHintType"/> enum for all options.
|
||||
/// Gets or sets the outline color for the KillButton if <see cref="UseVanillaKillButton"/> is true.
|
||||
/// </summary>
|
||||
public RoleHintType RoleHintType;
|
||||
public Color KillButtonOutlineColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Ghost role that is applied when the player is killed.
|
||||
/// Gets or sets the role hint style. See <see cref="RoleHintType"/> enum for all options.
|
||||
/// </summary>
|
||||
public RoleTypes GhostRole;
|
||||
}
|
||||
public RoleHintType RoleHintType { get; set; } = RoleHintType.RoleTab;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Ghost role that is applied when the player is killed.
|
||||
/// </summary>
|
||||
public RoleTypes GhostRole { get; set; }
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public static class CustomRoleManager
|
||||
var roleId = RoleIds[roleType];
|
||||
|
||||
roleBehaviour.Role = (RoleTypes)roleId;
|
||||
roleBehaviour.TeamType = customRole.Team == ModdedRoleTeams.Neutral ? RoleTeamTypes.Crewmate : (RoleTeamTypes)customRole.Team;
|
||||
roleBehaviour.TeamType = customRole.Team == ModdedRoleTeams.Custom ? RoleTeamTypes.Crewmate : (RoleTeamTypes)customRole.Team;
|
||||
roleBehaviour.NameColor = customRole.RoleColor;
|
||||
roleBehaviour.StringName = CustomStringName.CreateAndRegister(customRole.RoleName);
|
||||
roleBehaviour.BlurbName = CustomStringName.CreateAndRegister(customRole.RoleDescription);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BepInEx.Configuration;
|
||||
using System;
|
||||
using BepInEx.Configuration;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.PluginLoading;
|
||||
using MiraAPI.Utilities;
|
||||
@@ -43,6 +44,26 @@ public interface ICustomRole
|
||||
/// </summary>
|
||||
CustomRoleConfiguration Configuration { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the role options group.
|
||||
/// </summary>
|
||||
public RoleOptionsGroup RoleOptionsGroup => Team switch
|
||||
{
|
||||
ModdedRoleTeams.Crewmate => RoleOptionsGroup.Crewmate,
|
||||
ModdedRoleTeams.Impostor => RoleOptionsGroup.Impostor,
|
||||
ModdedRoleTeams.Custom => RoleOptionsGroup.Neutral,
|
||||
_ => new RoleOptionsGroup(RoleName, RoleColor),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the role's TeamIntroCutscene configuration.
|
||||
/// </summary>
|
||||
public TeamIntroConfiguration? IntroConfiguration => Team switch
|
||||
{
|
||||
ModdedRoleTeams.Custom => TeamIntroConfiguration.Neutral,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent mod of this role.
|
||||
/// </summary>
|
||||
|
||||
@@ -4,5 +4,5 @@ public enum ModdedRoleTeams
|
||||
{
|
||||
Crewmate,
|
||||
Impostor,
|
||||
Neutral,
|
||||
Custom,
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Roles;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a group of roles.
|
||||
/// </summary>
|
||||
/// <param name="Name">The group's name.</param>
|
||||
/// <param name="Color">The group's color.</param>
|
||||
/// <param name="Priority">The priority to sort by on role setting screen. Negative means first.</param>
|
||||
public record struct RoleOptionsGroup(string Name, Color Color, int Priority = 0)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the default group for crewmates.
|
||||
/// </summary>
|
||||
public static RoleOptionsGroup Crewmate { get; } = new("Crewmate", Palette.CrewmateBlue, -2);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default group for impostors.
|
||||
/// </summary>
|
||||
public static RoleOptionsGroup Impostor { get; } = new("Impostor", Palette.ImpostorRed, -1);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default group for neutral roles.
|
||||
/// </summary>
|
||||
public static RoleOptionsGroup Neutral { get; } = new("Neutral Roles", Color.gray);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Roles;
|
||||
|
||||
/// <summary>
|
||||
/// Used to configure the TEAM part of the intro cutscene.
|
||||
/// </summary>
|
||||
/// <param name="IntroTeamColor">The color to show during the "Team" part of the intro cutscene.</param>
|
||||
/// <param name="IntroTeamTitle">The title text to show during the "Team" part of the intro cutscene.</param>
|
||||
/// <param name="IntroTeamDescription">The description text to show during the "Team" part of the intro cutscene.</param>
|
||||
public record struct TeamIntroConfiguration(Color IntroTeamColor, string IntroTeamTitle, string IntroTeamDescription)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the default configuration for the "Neutral" team.
|
||||
/// </summary>
|
||||
public static TeamIntroConfiguration Neutral { get; } = new(
|
||||
Color.gray,
|
||||
"NEUTRAL",
|
||||
"You are Neutral. You do not have a team.");
|
||||
}
|
||||
Reference in new issue
Block a user