Merge branch 'dev' into cleanup

This commit is contained in:
Az committed 2026-08-13 23:56:53 -04:00
commit 33cafd1963
6 files changed
+601 -55

No files matched your search

@@ -3,10 +3,13 @@
/// <summary>
/// Event that is invoked after a player is murdered. Only called after a successful murder. This event is not cancelable.
/// </summary>
/// <param name="source">The killer.</param>
/// <param name="target">The killed <see cref="PlayerControl"/>.</param>
/// <param name="source">The <see cref="PlayerControl"/> that killed the <paramref name="target"/>.</param>
/// <param name="target">The <see cref="PlayerControl"/> that was killed.</param>
/// <param name="framed">The <see cref="PlayerControl"/> that was framed.</param>
/// <param name="deadBody">The <paramref name="target"/>'s <see cref="global::DeadBody"/>, if it exists.</param>
public class AfterMurderEvent(PlayerControl source, PlayerControl target, DeadBody? deadBody) : MiraEvent
/// <param name="isIndirect">Whether the murder was caused indirectly.</param>
/// <param name="ignoreDefense">Whether the murder ignored protection.</param>
public class AfterMurderEvent(PlayerControl source, PlayerControl target, PlayerControl? framed, DeadBody? deadBody, bool isIndirect = true, bool ignoreDefense = false) : MiraEvent
{
/// <summary>
/// Gets the <see cref="PlayerControl"/> that killed the <see cref="Target"/>.
@@ -19,7 +22,47 @@ public class AfterMurderEvent(PlayerControl source, PlayerControl target, DeadBo
public PlayerControl Target { get; } = target;
/// <summary>
/// Gets the <see cref="Target"/>'s <see cref="global::DeadBody"/>, if it exists.
/// Gets the <see cref="PlayerControl"/> that was framed, if any.
/// </summary>
public PlayerControl? Framed { get; } = framed;
/// <summary>
/// Gets a value indicating whether the murder was done indirectly.
/// This is commonly used to prevent the <see cref="Source"/> <see cref="PlayerControl"/> from being killed.
/// </summary>
public bool IsIndirectAttack { get; } = isIndirect;
/// <summary>
/// Gets a value indicating whether the murder was able to bypass protective roles or general defense, such as <see cref="GuardianAngelRole"/>.
/// </summary>
public bool IgnoreDefense { get; } = ignoreDefense;
/// <summary>
/// Gets the <see cref="Target"/>'s <see cref="DeadBody"/>, if it exists.
/// </summary>
public DeadBody? DeadBody { get; } = deadBody;
/// <summary>
/// Initializes a new instance of the <see cref="AfterMurderEvent"/> class.
/// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that killed the <paramref name="target"/>.</param>
/// <param name="target">The <see cref="PlayerControl"/> that was killed.</param>
/// <param name="deadBody">The <paramref name="target"/>'s <see cref="DeadBody"/>, if it exists.</param>
/// <param name="isIndirect">Whether the murder was caused indirectly.</param>
/// <param name="ignoreDefense">Whether the murder ignored protection.</param>
public AfterMurderEvent(PlayerControl source, PlayerControl target, DeadBody? deadBody, bool isIndirect, bool ignoreDefense = false)
: this(source, target, null, deadBody, isIndirect, ignoreDefense)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AfterMurderEvent"/> class.
/// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that killed the <paramref name="target"/>.</param>
/// <param name="target">The <see cref="PlayerControl"/> that was killed.</param>
/// <param name="deadBody">The <paramref name="target"/>'s <see cref="DeadBody"/>, if it exists.</param>
public AfterMurderEvent(PlayerControl source, PlayerControl target, DeadBody? deadBody)
: this(source, target, null, deadBody)
{
}
}
@@ -7,8 +7,12 @@ namespace MiraAPI.Events.Vanilla.Gameplay;
/// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that is killing the <paramref name="target"/>.</param>
/// <param name="target">The <see cref="PlayerControl"/> that is being killed.</param>
/// <param name="framed">The <see cref="PlayerControl"/> that is being framed.</param>
/// <param name="isIndirect">Whether the murder is caused indirectly.</param>
/// <param name="ignoreDefense">Whether the murder should ignore protection.</param>
/// <param name="inMeeting">Whether the murder is intended to be triggered in a meeting.</param>
public sealed class BeforeMurderEvent(PlayerControl source, PlayerControl target, MeetingCheck inMeeting) : MiraCancelableEvent
public sealed class BeforeMurderEvent(PlayerControl source, PlayerControl target, PlayerControl? framed, bool isIndirect = true, bool ignoreDefense = false, MeetingCheck inMeeting = MeetingCheck.Ignore)
: MiraCancelableEvent
{
/// <summary>
/// Gets the <see cref="PlayerControl"/> that is killing the <see cref="Target"/>.
@@ -20,6 +24,22 @@ public sealed class BeforeMurderEvent(PlayerControl source, PlayerControl target
/// </summary>
public PlayerControl Target { get; } = target;
/// <summary>
/// Gets the <see cref="PlayerControl"/> that is being framed, if any.
/// </summary>
public PlayerControl? Framed { get; } = framed;
/// <summary>
/// Gets or sets a value indicating whether the murder is done indirectly.
/// This is commonly used to prevent the <see cref="Source"/> <see cref="PlayerControl"/> from being killed.
/// </summary>
public bool IsIndirectAttack { get; set; } = isIndirect;
/// <summary>
/// Gets or sets a value indicating whether the murder should bypass protective roles or general defense, such as <see cref="GuardianAngelRole"/>.
/// </summary>
public bool IgnoreDefense { get; set; } = ignoreDefense;
/// <summary>
/// Gets whether the murder was meant to be done in a meeting, via an enum.
/// </summary>
@@ -30,7 +50,32 @@ public sealed class BeforeMurderEvent(PlayerControl source, PlayerControl target
/// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that is killing the <paramref name="target"/>.</param>
/// <param name="target">The <see cref="PlayerControl"/> that is being killed.</param>
public BeforeMurderEvent(PlayerControl source, PlayerControl target) : this(source, target, MeetingCheck.Ignore)
public BeforeMurderEvent(PlayerControl source, PlayerControl target)
: this(source, target, MeetingCheck.Ignore)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BeforeMurderEvent"/> class.
/// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that is killing the <paramref name="target"/>.</param>
/// <param name="target">The <see cref="PlayerControl"/> that is being killed.</param>
/// <param name="inMeeting">Whether the murder is intended to be triggered in a meeting.</param>
public BeforeMurderEvent(PlayerControl source, PlayerControl target, MeetingCheck inMeeting)
: this(source, target, false, false, inMeeting)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BeforeMurderEvent"/> class.
/// </summary>
/// <param name="source">The <see cref="PlayerControl"/> that is killing the <paramref name="target"/>.</param>
/// <param name="target">The <see cref="PlayerControl"/> that is being killed.</param>
/// <param name="isIndirect">Whether the murder is caused indirectly.</param>
/// <param name="ignoreDefense">Whether the murder should ignore protection.</param>
/// <param name="inMeeting">Whether the murder is intended to be triggered in a meeting.</param>
public BeforeMurderEvent(PlayerControl source, PlayerControl target, bool isIndirect, bool ignoreDefense = false, MeetingCheck inMeeting = MeetingCheck.Ignore)
: this(source, target, null, isIndirect, ignoreDefense, inMeeting)
{
}
}
+15 -4
View File
@@ -131,7 +131,10 @@ public static class ModifierManager
var validPlayers = plrs.Where(x => IsGameModifierValid(x, modifier, modifier.TypeId)).ToList();
if (validPlayers.Count == 0)
{
Warning($"No valid players for modifier {modifier.ModifierName}");
if (MiraApiPlugin.IsDevBuild)
{
Warning($"No valid players for modifier {modifier.ModifierName}");
}
continue;
}
@@ -152,15 +155,23 @@ public static class ModifierManager
if (candidates.Count == 0)
{
Warning(
$"No available players for modifier {modifier.ModifierName} at assignment {i + 1}");
if (MiraApiPlugin.IsDevBuild)
{
Warning(
$"No available players for modifier {modifier.ModifierName} at assignment {i + 1}");
}
break;
}
var plr = candidates.Random();
if (plr == null)
{
Warning($"Valid player for modifier {modifier.ModifierName} disappeared");
if (MiraApiPlugin.IsDevBuild)
{
Warning($"Valid player for modifier {modifier.ModifierName} disappeared");
}
continue;
}
+434 -7
View File
@@ -84,13 +84,15 @@ public static class CustomMurderRpc
var beforeMurderEvent = new BeforeMurderEvent(source, target, inMeeting);
MiraEventManager.InvokeEvent(beforeMurderEvent);
var defenseFlag = beforeMurderEvent.IgnoreDefense;
var indirectFlag = beforeMurderEvent.IsIndirectAttack;
var isMeetingActive = MeetingHud.Instance != null || ExileController.Instance != null;
if ((inMeeting is MeetingCheck.ForMeeting && !isMeetingActive) || (inMeeting is MeetingCheck.OutsideMeeting && isMeetingActive))
{
beforeMurderEvent.Cancel();
}
if (target.ProtectedByGa())
if (!defenseFlag && target.ProtectedByGa())
{
beforeMurderEvent.Cancel();
murderResultFlags = MurderResultFlags.FailedProtected;
@@ -114,6 +116,8 @@ public static class CustomMurderRpc
PlayerControl.LocalPlayer,
source,
target,
indirectFlag,
defenseFlag,
murderResultFlags,
resetKillTimer,
createDeadBody,
@@ -128,6 +132,8 @@ public static class CustomMurderRpc
/// <param name="host">The game host.</param>
/// <param name="source">The killer.</param>
/// <param name="target">The player to murder.</param>
/// <param name="isIndirect">Should the kill be indirect.</param>
/// <param name="ignoreDefense">Should the kill ignore defense.</param>
/// <param name="murderResultFlags">End result for the murder.</param>
/// <param name="resetKillTimer">Should the kill timer be reset.</param>
/// <param name="createDeadBody">Should a dead body be created.</param>
@@ -139,6 +145,149 @@ public static class CustomMurderRpc
this PlayerControl host,
PlayerControl source,
PlayerControl target,
bool isIndirect,
bool ignoreDefense,
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)
{
source.isKilling = false;
return;
}
var murderResultFlags2 = MurderResultFlags.DecisionByHost | murderResultFlags;
if (isIndirect || ignoreDefense)
{
source.CustomMurder(
target,
null,
isIndirect,
ignoreDefense,
murderResultFlags2,
resetKillTimer,
createDeadBody,
teleportMurderer,
showKillAnim,
playKillSound);
}
else
{
source.CustomMurder(
target,
murderResultFlags2,
resetKillTimer,
createDeadBody,
teleportMurderer,
showKillAnim,
playKillSound);
}
}
/// <summary>
/// Networked Custom Murder method, which checks for meetings as well, ran by clients for the host to confirm kills.
/// </summary>
/// <param name="source">The killer.</param>
/// <param name="target">The player to murder.</param>
/// <param name="inMeeting">Whether the murder is intended to be triggered in a meeting.</param>
/// <param name="isIndirect">Should the kill be indirect.</param>
/// <param name="ignoreDefense">Should the kill ignore defense.</param>
/// <param name="didSucceed">Whether the murder was successful or not.</param>
/// <param name="resetKillTimer">Should the kill timer be reset.</param>
/// <param name="createDeadBody">Should a dead body be created.</param>
/// <param name="teleportMurderer">Should the killer be snapped to the dead player.</param>
/// <param name="showKillAnim">Should the kill animation be shown.</param>
/// <param name="playKillSound">Should the kill sound be played.</param>
[MethodRpc((uint)MiraRpc.AdvancedCustomMurder, LocalHandling = RpcLocalHandling.Before)]
public static void RpcAdvancedCustomMurder(
this PlayerControl source,
PlayerControl target,
MeetingCheck inMeeting,
bool isIndirect,
bool ignoreDefense = false,
bool didSucceed = true,
bool resetKillTimer = true,
bool createDeadBody = true,
bool teleportMurderer = true,
bool showKillAnim = true,
bool playKillSound = true)
{
if (LobbyBehaviour.Instance)
{
return;
}
var murderResultFlags = didSucceed ? MurderResultFlags.Succeeded : MurderResultFlags.FailedError;
var beforeMurderEvent = new BeforeMurderEvent(source, target, isIndirect, ignoreDefense, inMeeting);
MiraEventManager.InvokeEvent(beforeMurderEvent);
var defenseFlag = beforeMurderEvent.IgnoreDefense;
var indirectFlag = beforeMurderEvent.IsIndirectAttack;
var isMeetingActive = MeetingHud.Instance != null || ExileController.Instance != null;
if ((inMeeting is MeetingCheck.ForMeeting && !isMeetingActive) || (inMeeting is MeetingCheck.OutsideMeeting && isMeetingActive))
{
beforeMurderEvent.Cancel();
}
if (!defenseFlag && target.ProtectedByGa())
{
beforeMurderEvent.Cancel();
murderResultFlags = MurderResultFlags.FailedProtected;
}
else if (beforeMurderEvent.IsCancelled)
{
murderResultFlags = MurderResultFlags.FailedError;
}
if (beforeMurderEvent.IsCancelled && source.AmOwner)
{
source.isKilling = true;
}
if (!PlayerControl.LocalPlayer.IsHost())
{
return;
}
RpcConfirmAdvancedCustomMurder(
PlayerControl.LocalPlayer,
source,
target,
indirectFlag,
defenseFlag,
murderResultFlags,
resetKillTimer,
createDeadBody,
teleportMurderer,
showKillAnim,
playKillSound);
}
/// <summary>
/// Networked Custom Murder method, which checks for meetings as well, ran by clients for the host to confirm kills.
/// </summary>
/// <param name="host">The game host.</param>
/// <param name="source">The killer.</param>
/// <param name="target">The player to murder.</param>
/// <param name="isIndirect">Should the kill be indirect.</param>
/// <param name="ignoreDefense">Should the kill ignore defense.</param>
/// <param name="murderResultFlags">End result for the murder.</param>
/// <param name="resetKillTimer">Should the kill timer be reset.</param>
/// <param name="createDeadBody">Should a dead body be created.</param>
/// <param name="teleportMurderer">Should the killer be snapped to the dead player.</param>
/// <param name="showKillAnim">Should the kill animation be shown.</param>
/// <param name="playKillSound">Should the kill sound be played.</param>
[MethodRpc((uint)MiraRpc.ConfirmAdvancedCustomMurder, LocalHandling = RpcLocalHandling.After)]
public static void RpcConfirmAdvancedCustomMurder(
this PlayerControl host,
PlayerControl source,
PlayerControl target,
bool isIndirect,
bool ignoreDefense,
MurderResultFlags murderResultFlags,
bool resetKillTimer = true,
bool createDeadBody = true,
@@ -156,6 +305,9 @@ public static class CustomMurderRpc
source.CustomMurder(
target,
null,
isIndirect,
ignoreDefense,
murderResultFlags2,
resetKillTimer,
createDeadBody,
@@ -164,6 +316,274 @@ public static class CustomMurderRpc
playKillSound);
}
/// <summary>
/// Networked Custom Murder method, which checks for meetings as well, ran by clients for the host to confirm kills.
/// </summary>
/// <param name="source">The killer.</param>
/// <param name="target">The player to murder.</param>
/// <param name="framed">The player to frame.</param>
/// <param name="inMeeting">Whether the murder is intended to be triggered in a meeting.</param>
/// <param name="isIndirect">Should the kill be indirect.</param>
/// <param name="ignoreDefense">Should the kill ignore defense.</param>
/// <param name="didSucceed">Whether the murder was successful or not.</param>
/// <param name="resetKillTimer">Should the kill timer be reset.</param>
/// <param name="createDeadBody">Should a dead body be created.</param>
/// <param name="teleportMurderer">Should the framed player be snapped to the dead player.</param>
/// <param name="showKillAnim">Should the kill animation be shown.</param>
/// <param name="playKillSound">Should the kill sound be played.</param>
[MethodRpc((uint)MiraRpc.FramedCustomMurder, LocalHandling = RpcLocalHandling.Before)]
public static void RpcFramedCustomMurder(
this PlayerControl source,
PlayerControl target,
PlayerControl framed,
MeetingCheck inMeeting,
bool isIndirect = true,
bool ignoreDefense = false,
bool didSucceed = true,
bool resetKillTimer = true,
bool createDeadBody = true,
bool teleportMurderer = true,
bool showKillAnim = true,
bool playKillSound = true)
{
if (LobbyBehaviour.Instance)
{
return;
}
var murderResultFlags = didSucceed ? MurderResultFlags.Succeeded : MurderResultFlags.FailedError;
var beforeMurderEvent = new BeforeMurderEvent(source, target, framed, isIndirect, ignoreDefense, inMeeting);
MiraEventManager.InvokeEvent(beforeMurderEvent);
var defenseFlag = beforeMurderEvent.IgnoreDefense;
var indirectFlag = beforeMurderEvent.IsIndirectAttack;
var isMeetingActive = MeetingHud.Instance != null || ExileController.Instance != null;
if ((inMeeting is MeetingCheck.ForMeeting && !isMeetingActive) || (inMeeting is MeetingCheck.OutsideMeeting && isMeetingActive))
{
beforeMurderEvent.Cancel();
}
if (!defenseFlag && target.ProtectedByGa())
{
beforeMurderEvent.Cancel();
murderResultFlags = MurderResultFlags.FailedProtected;
}
else if (beforeMurderEvent.IsCancelled)
{
murderResultFlags = MurderResultFlags.FailedError;
}
if (beforeMurderEvent.IsCancelled && source.AmOwner)
{
source.isKilling = true;
}
if (!PlayerControl.LocalPlayer.IsHost())
{
return;
}
RpcConfirmFramedCustomMurder(
PlayerControl.LocalPlayer,
source,
target,
framed,
indirectFlag,
defenseFlag,
murderResultFlags,
resetKillTimer,
createDeadBody,
teleportMurderer,
showKillAnim,
playKillSound);
}
/// <summary>
/// Networked Custom Murder method, which checks for meetings as well, ran by clients for the host to confirm kills.
/// </summary>
/// <param name="host">The game host.</param>
/// <param name="source">The killer.</param>
/// <param name="target">The player to murder.</param>
/// <param name="framed">The player to frame.</param>
/// <param name="isIndirect">Should the kill be indirect.</param>
/// <param name="ignoreDefense">Should the kill ignore defense.</param>
/// <param name="murderResultFlags">End result for the murder.</param>
/// <param name="resetKillTimer">Should the kill timer be reset.</param>
/// <param name="createDeadBody">Should a dead body be created.</param>
/// <param name="teleportMurderer">Should the framed player be snapped to the dead player.</param>
/// <param name="showKillAnim">Should the kill animation be shown.</param>
/// <param name="playKillSound">Should the kill sound be played.</param>
[MethodRpc((uint)MiraRpc.ConfirmFramedCustomMurder, LocalHandling = RpcLocalHandling.After)]
public static void RpcConfirmFramedCustomMurder(
this PlayerControl host,
PlayerControl source,
PlayerControl target,
PlayerControl framed,
bool isIndirect,
bool ignoreDefense,
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)
{
source.isKilling = false;
return;
}
var murderResultFlags2 = MurderResultFlags.DecisionByHost | murderResultFlags;
source.CustomMurder(
target,
framed,
isIndirect,
ignoreDefense,
murderResultFlags2,
resetKillTimer,
createDeadBody,
teleportMurderer,
showKillAnim,
playKillSound);
}
/// <summary>
/// Custom Murder method without networking. If you need a networked version, use <see cref="RpcFramedCustomMurder"/> or <see cref="RpcAdvancedCustomMurder"/>.
/// </summary>
/// <param name="source">The killer.</param>
/// <param name="target">The player to murder.</param>
/// <param name="framed">The player to frame, if any.</param>
/// <param name="isIndirect">Should the kill be indirect.</param>
/// <param name="ignoreDefense">Should the kill ignore defense.</param>
/// <param name="resultFlags">Murder result flags.</param>
/// <param name="resetKillTimer">Should the kill timer be reset.</param>
/// <param name="createDeadBody">Should a dead body be created.</param>
/// <param name="teleportMurderer">Should the killer be snapped to the dead player.</param>
/// <param name="showKillAnim">Should the kill animation be shown.</param>
/// <param name="playKillSound">Should the kill sound be played.</param>
public static void CustomMurder(
this PlayerControl source,
PlayerControl target,
PlayerControl? framed,
bool isIndirect,
bool ignoreDefense,
MurderResultFlags resultFlags,
bool resetKillTimer = true,
bool createDeadBody = true,
bool teleportMurderer = true,
bool showKillAnim = true,
bool playKillSound = true)
{
source.isKilling = false;
if (resultFlags.HasFlag(MurderResultFlags.FailedError) || LobbyBehaviour.Instance)
{
return;
}
if (!ignoreDefense && (resultFlags.HasFlag(MurderResultFlags.FailedProtected) ||
(resultFlags.HasFlag(MurderResultFlags.DecisionByHost) &&
target.protectedByGuardianId > -1)))
{
target.protectedByGuardianThisRound = true;
var flag = PlayerControl.LocalPlayer.Data.Role.Role == RoleTypes.GuardianAngel;
if (flag && PlayerControl.LocalPlayer.Data.PlayerId == target.protectedByGuardianId)
{
DataManager.Player.Stats.IncrementStat(StatID.Role_GuardianAngel_CrewmatesProtected);
AchievementManager.Instance.OnProtectACrewmate();
}
if (source.AmOwner || flag)
{
target.ShowFailedMurder();
if (resetKillTimer)
{
source.SetKillTimer(
GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown) / 2f);
}
}
else
{
target.RemoveProtection();
}
return;
}
if (!resultFlags.HasFlag(MurderResultFlags.Succeeded) &&
!resultFlags.HasFlag(MurderResultFlags.DecisionByHost))
{
return;
}
DebugAnalytics.Instance.Analytics.Kill(target.Data, source.Data);
if (source.AmOwner)
{
DataManager.Player.Stats.IncrementStat(
GameManager.Instance.IsHideAndSeek()
? StatID.HideAndSeek_ImpostorKills
: StatID.ImpostorKills);
if (source.CurrentOutfitType == PlayerOutfitType.Shapeshifted)
{
DataManager.Player.Stats.IncrementStat(StatID.Role_Shapeshifter_ShiftedKills);
}
if (Constants.ShouldPlaySfx() && playKillSound)
{
SoundManager.Instance.PlaySound(source.KillSfx, false, 0.8f);
}
if (resetKillTimer)
{
source.SetKillTimer(GameOptionsManager.Instance.CurrentGameOptions.GetFloat(FloatOptionNames.KillCooldown));
}
}
UnityTelemetry.Instance.WriteMurder();
target.gameObject.layer = LayerMask.NameToLayer("Ghost");
if (target.AmOwner)
{
DataManager.Player.Stats.IncrementStat(StatID.TimesMurdered);
if (Minigame.Instance)
{
try
{
Minigame.Instance.Close();
Minigame.Instance.Close();
}
catch
{
// ignored
}
}
if (showKillAnim)
{
try
{
HudManager.Instance.KillOverlay.ShowKillAnimation(source.Data, target.Data);
}
catch (Exception e)
{
Error($"Error with kill animation: {e.ToString()}");
}
}
target.cosmetics.SetNameMask(false);
target.RpcSetScanner(false);
}
AchievementManager.Instance.OnMurder(
source.AmOwner,
target.AmOwner,
source.CurrentOutfitType == PlayerOutfitType.Shapeshifted,
source.shapeshiftTargetPlayerId,
target.PlayerId);
source.MyPhysics.StartCoroutine(source.KillAnimations.RandomSnapshot().CoPerformCustomKill(source, target, framed, isIndirect, ignoreDefense, createDeadBody, teleportMurderer));
}
/// <summary>
/// Custom Murder method without networking. If you need a networked version, use <see cref="RpcCustomMurder(PlayerControl, PlayerControl, bool, bool, bool, bool, bool, bool)"/>.
/// </summary>
@@ -290,7 +710,7 @@ public static class CustomMurderRpc
source.CurrentOutfitType == PlayerOutfitType.Shapeshifted,
source.shapeshiftTargetPlayerId,
target.PlayerId);
source.MyPhysics.StartCoroutine(source.KillAnimations.RandomSnapshot().CoPerformCustomKill(source, target, createDeadBody, teleportMurderer));
source.MyPhysics.StartCoroutine(source.KillAnimations.RandomSnapshot().CoPerformCustomKill(source, target, null, false, false, createDeadBody, teleportMurderer));
}
/// <summary>
@@ -299,6 +719,9 @@ public static class CustomMurderRpc
/// <param name="anim">The kill animation.</param>
/// <param name="source">The murderer.</param>
/// <param name="target">The murdered player.</param>
/// <param name="framed">The framed player, if any.</param>
/// <param name="isIndirect">Was the kill indirect.</param>
/// <param name="ignoreDefense">Would the kill ignore defense.</param>
/// <param name="createDeadBody">Should a dead body be created.</param>
/// <param name="teleportMurderer">Should the murder be teleported.</param>
/// <returns>Coroutine.</returns>
@@ -306,6 +729,9 @@ public static class CustomMurderRpc
this KillAnimation anim,
PlayerControl source,
PlayerControl target,
PlayerControl? framed,
bool isIndirect,
bool ignoreDefense,
bool createDeadBody = true,
bool teleportMurderer = true)
{
@@ -314,12 +740,13 @@ public static class CustomMurderRpc
yield break;
}
var cam = Camera.main?.GetComponent<FollowerCamera>();
var isParticipant = source.AmOwner || target.AmOwner;
var sourcePhys = source.MyPhysics;
var playerToLunge = framed ?? source;
var isParticipant = playerToLunge.AmOwner || target.AmOwner;
var sourcePhys = playerToLunge.MyPhysics;
if (teleportMurderer)
{
KillAnimation.SetMovement(source, false);
KillAnimation.SetMovement(playerToLunge, false);
}
KillAnimation.SetMovement(target, false);
@@ -373,7 +800,7 @@ public static class CustomMurderRpc
yield return source.MyPhysics.Animations.CoPlayCustomAnimation(anim.BlurAnim);
sourcePhys.Animations.PlayIdleAnimation();
source.NetTransform.SnapTo(target.transform.position);
KillAnimation.SetMovement(source, true);
KillAnimation.SetMovement(playerToLunge, true);
}
KillAnimation.SetMovement(target, true);
@@ -383,7 +810,7 @@ public static class CustomMurderRpc
deadBody.enabled = true;
}
var afterMurderEvent = new AfterMurderEvent(source, target, deadBody);
var afterMurderEvent = framed != null ? new AfterMurderEvent(source, target, framed, deadBody, isIndirect, ignoreDefense) : new AfterMurderEvent(source, target, deadBody, isIndirect, ignoreDefense);
MiraEventManager.InvokeEvent(afterMurderEvent);
if (!isParticipant)
+20
View File
@@ -40,6 +40,26 @@ public enum MiraRpc : uint
/// </summary>
ConfirmCustomMurder,
/// <summary>
/// Advanced Custom Murder RPC.
/// </summary>
AdvancedCustomMurder,
/// <summary>
/// Advanced Custom Murder RPC Confirmation.
/// </summary>
ConfirmAdvancedCustomMurder,
/// <summary>
/// Framed Custom Murder RPC.
/// </summary>
FramedCustomMurder,
/// <summary>
/// Framed Custom Murder RPC Confirmation.
/// </summary>
ConfirmFramedCustomMurder,
/// <summary>
/// Custom Game Over RPC.
/// </summary>
+38 -38
View File
@@ -32,228 +32,228 @@ public static class ShaderID
/// <summary>
/// The shader property ID for "_BodyColor".
/// </summary>
public static readonly int BodyColor = Shader.PropertyToID("_BodyColor");
public static readonly int BodyColor = Get("_BodyColor");
/// <summary>
/// The shader property ID for "_BackColor".
/// </summary>
public static readonly int BackColor = Shader.PropertyToID("_BackColor");
public static readonly int BackColor = Get("_BackColor");
/// <summary>
/// The shader property ID for "_VisorColor".
/// </summary>
public static readonly int VisorColor = Shader.PropertyToID("_VisorColor");
public static readonly int VisorColor = Get("_VisorColor");
// Main texture, very obviously used in any shader with a texture
/// <summary>
/// The shader property ID for "_MainTex".
/// </summary>
public static readonly int MainTex = Shader.PropertyToID("_MainTex");
public static readonly int MainTex = Get("_MainTex");
// Any masking stuff, like MeetingHud bubbles
/// <summary>
/// The shader property ID for "_Mask".
/// </summary>
public static readonly int Mask = Shader.PropertyToID("_Mask");
public static readonly int Mask = Get("_Mask");
/// <summary>
/// The shader property ID for "_MaskComp".
/// </summary>
public static readonly int MaskComp = Shader.PropertyToID("_MaskComp");
public static readonly int MaskComp = Get("_MaskComp");
/// <summary>
/// The shader property ID for "_MaskLayer".
/// </summary>
public static readonly int MaskLayer = Shader.PropertyToID("_MaskLayer");
public static readonly int MaskLayer = Get("_MaskLayer");
/// <summary>
/// The shader property ID for "_Stencil".
/// </summary>
public static readonly int Stencil = Shader.PropertyToID("_Stencil");
public static readonly int Stencil = Get("_Stencil");
/// <summary>
/// The shader property ID for "_StencilComp".
/// </summary>
public static readonly int StencilComp = Shader.PropertyToID("_StencilComp");
public static readonly int StencilComp = Get("_StencilComp");
// Used in many tasks
/// <summary>
/// The shader property ID for "_Color".
/// </summary>
public static readonly int Color = Shader.PropertyToID("_Color");
public static readonly int Color = Get("_Color");
// Has 2 uses in the game, provided for convenience
/// <summary>
/// The shader property ID for "_Opacity".
/// </summary>
public static readonly int Opacity = Shader.PropertyToID("_Opacity");
public static readonly int Opacity = Get("_Opacity");
// Used once in CooldownHelpers, once in PowerBarMining
/// <summary>
/// The shader property ID for "_NormalizedUvs".
/// </summary>
public static readonly int NormalizedUvs = Shader.PropertyToID("_NormalizedUvs");
public static readonly int NormalizedUvs = Get("_NormalizedUvs");
// Used in many consoles
/// <summary>
/// The shader property ID for "_Outline".
/// </summary>
public static readonly int Outline = Shader.PropertyToID("_Outline");
public static readonly int Outline = Get("_Outline");
/// <summary>
/// The shader property ID for "_OutlineColor".
/// </summary>
public static readonly int OutlineColor = Shader.PropertyToID("_OutlineColor");
public static readonly int OutlineColor = Get("_OutlineColor");
// Used in some consoles
/// <summary>
/// The shader property ID for "_AddColor".
/// </summary>
public static readonly int AddColor = Shader.PropertyToID("_AddColor");
public static readonly int AddColor = Get("_AddColor");
// Has some uses in various locations
/// <summary>
/// The shader property ID for "_Percent".
/// </summary>
public static readonly int Percent = Shader.PropertyToID("_Percent");
public static readonly int Percent = Get("_Percent");
/// <summary>
/// The shader property ID for "_PercentY".
/// </summary>
public static readonly int PercentY = Shader.PropertyToID("_PercentY");
public static readonly int PercentY = Get("_PercentY");
/// <summary>
/// The shader property ID for "_Desat".
/// </summary>
public static readonly int Desat = Shader.PropertyToID("_Desat");
public static readonly int Desat = Get("_Desat");
// Used in LightSource
/// <summary>
/// The shader property ID for "_PlayerRadius".
/// </summary>
public static readonly int PlayerRadius = Shader.PropertyToID("_PlayerRadius");
public static readonly int PlayerRadius = Get("_PlayerRadius");
/// <summary>
/// The shader property ID for "_LightRadius".
/// </summary>
public static readonly int LightRadius = Shader.PropertyToID("_LightRadius");
public static readonly int LightRadius = Get("_LightRadius");
/// <summary>
/// The shader property ID for "_LightOffset".
/// </summary>
public static readonly int LightOffset = Shader.PropertyToID("_LightOffset");
public static readonly int LightOffset = Get("_LightOffset");
/// <summary>
/// The shader property ID for "_FlashlightSize".
/// </summary>
public static readonly int FlashlightSize = Shader.PropertyToID("_FlashlightSize");
public static readonly int FlashlightSize = Get("_FlashlightSize");
/// <summary>
/// The shader property ID for "_FlashlightAngle".
/// </summary>
public static readonly int FlashlightAngle = Shader.PropertyToID("_FlashlightAngle");
public static readonly int FlashlightAngle = Get("_FlashlightAngle");
// Used once for LightSourceGpuRenderer
/// <summary>
/// The shader property ID for "_DepthCompressionValue".
/// </summary>
public static readonly int DepthCompressionValue = Shader.PropertyToID("_DepthCompressionValue");
public static readonly int DepthCompressionValue = Get("_DepthCompressionValue");
// Used in ProgressTracker
/// <summary>
/// The shader property ID for "_Buckets".
/// </summary>
public static readonly int Buckets = Shader.PropertyToID("_Buckets");
public static readonly int Buckets = Get("_Buckets");
/// <summary>
/// The shader property ID for "_FullBuckets".
/// </summary>
public static readonly int FullBuckets = Shader.PropertyToID("_FullBuckets");
public static readonly int FullBuckets = Get("_FullBuckets");
// Used once in IntroCutscene and EndGameManager
/// <summary>
/// The shader property ID for "_Rad".
/// </summary>
public static readonly int Rad = Shader.PropertyToID("_Rad");
public static readonly int Rad = Get("_Rad");
// Used only once for Quick Chat
/// <summary>
/// The shader property ID for "_FaceColor".
/// </summary>
public static readonly int FaceColor = Shader.PropertyToID("_FaceColor");
public static readonly int FaceColor = Get("_FaceColor");
// Used for NavigationMinigame
/// <summary>
/// The shader property ID for "_CrossHair".
/// </summary>
public static readonly int CrossHair = Shader.PropertyToID("_CrossHair");
public static readonly int CrossHair = Get("_CrossHair");
/// <summary>
/// The shader property ID for "_CrossColor".
/// </summary>
public static readonly int CrossColor = Shader.PropertyToID("_CrossColor");
public static readonly int CrossColor = Get("_CrossColor");
// Used for both SurveillanceMinigame (Planet and Normal)
/// <summary>
/// The shader property ID for "_Center".
/// </summary>
public static readonly int Center = Shader.PropertyToID("_Center");
public static readonly int Center = Get("_Center");
/// <summary>
/// The shader property ID for "_Color2".
/// </summary>
public static readonly int Color2 = Shader.PropertyToID("_Color2");
public static readonly int Color2 = Get("_Color2");
// Used in ReactorShipRoom
/// <summary>
/// The shader property ID for "_Speed".
/// </summary>
public static readonly int Speed = Shader.PropertyToID("_Speed");
public static readonly int Speed = Get("_Speed");
// Used only once in CourseMinigame
/// <summary>
/// The shader property ID for "_AltTex".
/// </summary>
public static readonly int AltTex = Shader.PropertyToID("_AltTex");
public static readonly int AltTex = Get("_AltTex");
/// <summary>
/// The shader property ID for "_Perc".
/// </summary>
public static readonly int Perc = Shader.PropertyToID("_Perc");
public static readonly int Perc = Get("_Perc");
// Used once in TextMarquee
/// <summary>
/// The shader property ID for "_VertexOffsetX".
/// </summary>
public static readonly int VertexOffsetX = Shader.PropertyToID("_VertexOffsetX");
public static readonly int VertexOffsetX = Get("_VertexOffsetX");
/// <summary>
/// The shader property ID for "_VertexOffsetY".
/// </summary>
public static readonly int VertexOffsetY = Shader.PropertyToID("_VertexOffsetY");
public static readonly int VertexOffsetY = Get("_VertexOffsetY");
// Used in VertLineBehaviour
/// <summary>
/// The shader property ID for "_Fade".
/// </summary>
public static readonly int Fade = Shader.PropertyToID("_Fade");
public static readonly int Fade = Get("_Fade");
}