mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-19 15:51:48 +00:00
Merge branch 'dev' into cleanup
This commit is contained in:
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
Reference in new issue
Block a user