diff --git a/MiraAPI/Networking/CustomMurderRpc.cs b/MiraAPI/Networking/CustomMurderRpc.cs
index 7629ebc..d31e185 100644
--- a/MiraAPI/Networking/CustomMurderRpc.cs
+++ b/MiraAPI/Networking/CustomMurderRpc.cs
@@ -7,10 +7,12 @@ using Assets.CoreScripts;
using BepInEx.Unity.IL2CPP.Utils;
using MiraAPI.Events;
using MiraAPI.Events.Vanilla.Gameplay;
+using MiraAPI.Utilities;
using Reactor.Networking.Attributes;
using Reactor.Networking.Rpc;
using Reactor.Utilities;
using Reactor.Utilities.Extensions;
+using Rewired;
using UnityEngine;
using Object = UnityEngine.Object;
@@ -22,7 +24,7 @@ namespace MiraAPI.Networking;
public static class CustomMurderRpc
{
///
- /// Networked Custom Murder method.
+ /// Networked Custom Murder method, ran by clients for the host to confirm kills.
///
/// The killer.
/// The player to murder.
@@ -54,7 +56,7 @@ public static class CustomMurderRpc
}
///
- /// Networked Custom Murder method, which checks for meetings as well.
+ /// Networked Custom Murder method, which checks for meetings as well, ran by clients for the host to confirm kills.
///
/// The killer.
/// The player to murder.
@@ -96,6 +98,52 @@ public static class CustomMurderRpc
murderResultFlags = MurderResultFlags.FailedError;
}
+ if (!PlayerControl.LocalPlayer.IsHost())
+ {
+ return;
+ }
+
+ RpcConfirmCustomMurder(
+ PlayerControl.LocalPlayer,
+ source,
+ target,
+ murderResultFlags,
+ resetKillTimer,
+ createDeadBody,
+ teleportMurderer,
+ showKillAnim,
+ playKillSound);
+ }
+
+ ///
+ /// Networked Custom Murder method, which checks for meetings as well, ran by clients for the host to confirm kills.
+ ///
+ /// The game host.
+ /// The killer.
+ /// The player to murder.
+ /// End result for the murder.
+ /// Should the kill timer be reset.
+ /// Should a dead body be created.
+ /// Should the killer be snapped to the dead player.
+ /// Should the kill animation be shown.
+ /// Should the kill sound be played.
+ [MethodRpc((uint)MiraRpc.ConfirmCustomMurder, LocalHandling = RpcLocalHandling.After)]
+ public static void RpcConfirmCustomMurder(
+ this PlayerControl host,
+ PlayerControl source,
+ PlayerControl target,
+ MurderResultFlags murderResultFlags,
+ bool resetKillTimer = true,
+ bool createDeadBody = true,
+ bool teleportMurderer = true,
+ bool showKillAnim = true,
+ bool playKillSound = true)
+ {
+ if (LobbyBehaviour.Instance || !host.IsHost() || target.Data.IsDead || target.Data.Disconnected)
+ {
+ return;
+ }
+
var murderResultFlags2 = MurderResultFlags.DecisionByHost | murderResultFlags;
source.CustomMurder(
diff --git a/MiraAPI/Networking/MiraRpc.cs b/MiraAPI/Networking/MiraRpc.cs
index 28c6c7a..edc3a94 100644
--- a/MiraAPI/Networking/MiraRpc.cs
+++ b/MiraAPI/Networking/MiraRpc.cs
@@ -35,6 +35,11 @@ public enum MiraRpc : uint
///
CustomMurder,
+ ///
+ /// Custom Murder RPC Confirmation.
+ ///
+ ConfirmCustomMurder,
+
///
/// Custom Game Over RPC.
///
diff --git a/MiraAPI/Patches/Options/LobbyViewPanePatches.cs b/MiraAPI/Patches/Options/LobbyViewPanePatches.cs
index 32c0d2a..4a629f5 100644
--- a/MiraAPI/Patches/Options/LobbyViewPanePatches.cs
+++ b/MiraAPI/Patches/Options/LobbyViewPanePatches.cs
@@ -210,12 +210,19 @@ public static class LobbyViewPanePatches
list.Add(roleBehaviour);
}
+ var color = (i == 0) ? Palette.CrewmateRoleBlue : Palette.ImpostorRoleRed;
+ if (roleBehaviour is ICustomRole custom && (custom.Team is not ModdedRoleTeams.Crewmate &&
+ custom.Team is not ModdedRoleTeams.Impostor))
+ {
+ color = Color.grey;
+ }
+
viewSettingsInfoPanelRoleVariant.SetInfo(
roleBehaviour.NiceName,
numPerGame,
chancePerGame,
61,
- (i == 0) ? Palette.CrewmateRoleBlue : Palette.ImpostorRoleRed,
+ color,
roleBehaviour.RoleIconSolid,
i == 0,
flag);
@@ -513,6 +520,34 @@ public static class LobbyViewPanePatches
instance.scrollBar.SetYBoundsMax(-num);
}
+ public static void SetModdedHeader(this CategoryHeaderRoleVariant header, StringNames roleName, int maskLayer, ModdedRoleTeams team, Sprite? roleIcon = null)
+ {
+ header.SetHeader(roleName, maskLayer);
+ if (team is ModdedRoleTeams.Crewmate)
+ {
+ header.Background.color = Palette.CrewmateRoleHeaderBlue;
+ header.Divider.color = Palette.CrewmateRoleHeaderBlue;
+ header.Title.color = Palette.CrewmateRoleHeaderTextBlue;
+ }
+ else if (team is ModdedRoleTeams.Impostor)
+ {
+ header.Background.color = Palette.ImpostorRoleHeaderRed;
+ header.Divider.color = Palette.ImpostorRoleHeaderRed;
+ header.Title.color = Palette.ImpostorRoleHeaderTextRed;
+ }
+ else
+ {
+ header.Background.color = Color.grey;
+ header.Divider.color = Color.grey;
+ header.Title.color = new Color32(50, 50, 50, 255);
+ }
+ if (roleIcon != null && header.icon != null)
+ {
+ header.icon.material.SetInt(PlayerMaterial.MaskLayer, maskLayer);
+ header.icon.sprite = roleIcon;
+ }
+ }
+
private static float SetUpAdvancedRoleViewPanel(
AdvancedRoleViewPanel viewPanel,
Type roleType,
@@ -536,10 +571,10 @@ public static class LobbyViewPanePatches
return 0;
}
- viewPanel.header.SetHeader(
+ viewPanel.header.SetModdedHeader(
role.StringName,
maskLayer,
- role.TeamType == RoleTeamTypes.Crewmate,
+ customRole.Team,
customRole.Configuration.Icon != null ? customRole.Configuration.Icon.LoadAsset() : MiraAssets.Empty.LoadAsset());
viewPanel.header.icon.transform.localScale = new Vector3(0.465f, 0.465f, 1f);
viewPanel.divider.material.SetInt(PlayerMaterial.MaskLayer, maskLayer);