Skip to content

Commit e6a3b46

Browse files
committed
Fixed RPC issues causing player disconnects, Fixed endgame triggering shortly after match start, Added XML docs for the whole mod, Updated README.md
1 parent 6835546 commit e6a3b46

19 files changed

Lines changed: 815 additions & 235 deletions

NewMod/Buttons/EnergyThief/DrainButton.cs

Lines changed: 97 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,50 +7,110 @@
77
using UnityEngine;
88
using NewMod.Utilities;
99

10-
namespace NewMod.Buttons.EnergyThief;
11-
public class DrainButton : CustomActionButton<PlayerControl>
10+
namespace NewMod.Buttons.EnergyThief
1211
{
13-
public override string Name => "DRAIN";
14-
public override float Cooldown => OptionGroupSingleton<EnergyThiefOptions>.Instance.DrainCooldown;
15-
public override int MaxUses => (int)OptionGroupSingleton<EnergyThiefOptions>.Instance.DrainMaxUses;
16-
public override ButtonLocation Location => ButtonLocation.BottomRight;
17-
public override float EffectDuration => 0f;
18-
public override LoadableAsset<Sprite> Sprite => MiraAssets.Empty;
19-
public override PlayerControl GetTarget()
12+
/// <summary>
13+
/// Defines a custom action button for the role.
14+
/// </summary>
15+
public class DrainButton : CustomActionButton<PlayerControl>
2016
{
21-
return PlayerControl.LocalPlayer.GetClosestPlayer(true, Distance, false, p => !p.Data.IsDead && !p.Data.Disconnected);
22-
}
23-
public override void SetOutline(bool active)
24-
{
25-
Target?.cosmetics.SetOutline(active, new Il2CppSystem.Nullable<Color>(Color.magenta));
26-
}
27-
public override bool IsTargetValid(PlayerControl target)
28-
{
29-
return true;
30-
}
31-
public override bool Enabled(RoleBehaviour role)
32-
{
33-
return role is ET;
34-
}
35-
protected override void OnClick()
36-
{
37-
PendingEffectManager.AddPendingEffect(Target);
17+
/// <summary>
18+
/// Gets the display name for this button.
19+
/// </summary>
20+
public override string Name => "Drain";
21+
22+
/// <summary>
23+
/// Gets the cooldown value for this button, based on EnergyThiefOptions.
24+
/// </summary>
25+
public override float Cooldown => OptionGroupSingleton<EnergyThiefOptions>.Instance.DrainCooldown;
26+
27+
/// <summary>
28+
/// Gets the maximum number of uses for this button, based on EnergyThiefOptions.
29+
/// </summary>
30+
public override int MaxUses => (int)OptionGroupSingleton<EnergyThiefOptions>.Instance.DrainMaxUses;
31+
32+
/// <summary>
33+
/// The on-screen position of this button.
34+
/// </summary>
35+
public override ButtonLocation Location => ButtonLocation.BottomRight;
3836

39-
Utils.RecordDrainCount(PlayerControl.LocalPlayer);
37+
/// <summary>
38+
/// The duration of the effect applied by this button; in this case, zero.
39+
/// </summary>
40+
public override float EffectDuration => 0f;
4041

41-
if (PlayerControl.LocalPlayer.AmOwner)
42+
/// <summary>
43+
/// Gets the sprite asset for this button. Currently set to an empty sprite.
44+
/// </summary>
45+
public override LoadableAsset<Sprite> Sprite => MiraAssets.Empty;
46+
47+
/// <summary>
48+
/// Determines the target for this button action.
49+
/// </summary>
50+
/// <returns>The closest valid PlayerControl, or null if none.</returns>
51+
public override PlayerControl GetTarget()
4252
{
43-
HudManager.Instance.Notifier.AddDisconnectMessage($"The Drain effect will be applied to {Target.Data.PlayerName} after the meeting ends.");
53+
return PlayerControl.LocalPlayer.GetClosestPlayer(true, Distance, false, p => !p.Data.IsDead && !p.Data.Disconnected);
4454
}
45-
Utils.waitingPlayers.Add(PlayerControl.LocalPlayer);
46-
}
4755

48-
public override bool CanUse()
49-
{
50-
if (Utils.waitingPlayers.Contains(PlayerControl.LocalPlayer))
56+
/// <summary>
57+
/// Enables or disables an outline around the targeted player.
58+
/// </summary>
59+
/// <param name="active">Whether to enable or disable the outline.</param>
60+
public override void SetOutline(bool active)
61+
{
62+
Target?.cosmetics.SetOutline(active, new Il2CppSystem.Nullable<Color>(Color.magenta));
63+
}
64+
65+
/// <summary>
66+
/// Determines whether the targeted player is valid for draining.
67+
/// </summary>
68+
/// <param name="target">The candidate player.</param>
69+
/// <returns>Always true in this implementation.</returns>
70+
public override bool IsTargetValid(PlayerControl target)
71+
{
72+
return true;
73+
}
74+
75+
/// <summary>
76+
/// Specifies whether the button is enabled for a given role.
77+
/// </summary>
78+
/// <param name="role">The role to check.</param>
79+
/// <returns>True if the role is EnergyThief, otherwise false.</returns>
80+
public override bool Enabled(RoleBehaviour role)
81+
{
82+
return role is ET;
83+
}
84+
85+
/// <summary>
86+
/// Invoked when the button is clicked. Records a drain count, queues a pending effect,
87+
/// notifies the local player, and locks the button from reuse until the meeting ends.
88+
/// </summary>
89+
protected override void OnClick()
90+
{
91+
PendingEffectManager.AddPendingEffect(Target);
92+
93+
Utils.RecordDrainCount(PlayerControl.LocalPlayer);
94+
95+
if (PlayerControl.LocalPlayer.AmOwner)
96+
{
97+
HudManager.Instance.Notifier.AddDisconnectMessage($"The Drain effect will be applied to {Target.Data.PlayerName} after the meeting ends.");
98+
}
99+
Utils.waitingPlayers.Add(PlayerControl.LocalPlayer);
100+
}
101+
102+
/// <summary>
103+
/// Checks if the button can be used, preventing usage if the local player
104+
/// is already in the waitingPlayers set.
105+
/// </summary>
106+
/// <returns>True if usable, otherwise false.</returns>
107+
public override bool CanUse()
51108
{
52-
return false;
109+
if (Utils.waitingPlayers.Contains(PlayerControl.LocalPlayer))
110+
{
111+
return false;
112+
}
113+
return base.CanUse();
53114
}
54-
return base.CanUse();
55115
}
56-
}
116+
}

NewMod/Buttons/Necromancer/ReviveButton.cs

Lines changed: 79 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,58 +6,99 @@
66
using UnityEngine;
77
using NewMod.Utilities;
88

9-
namespace NewMod.Buttons.Necromancer;
10-
public class ReviveButton : CustomActionButton
9+
namespace NewMod.Buttons.Necromancer
1110
{
12-
public override string Name => ""; // It's currently empty since the button has already a name on it
13-
public override float Cooldown => OptionGroupSingleton<NecromancerOption>.Instance.ButtonCooldown;
14-
public override int MaxUses => (int)OptionGroupSingleton<NecromancerOption>.Instance.AbilityUses;
15-
public override float EffectDuration => 0f;
16-
public override ButtonLocation Location => ButtonLocation.BottomLeft;
17-
public override LoadableAsset<Sprite> Sprite => NewModAsset.NecromancerButton;
18-
protected override void OnClick()
11+
/// <summary>
12+
/// Defines a custom action button for the role.
13+
/// </summary>
14+
public class ReviveButton : CustomActionButton
1915
{
20-
NewMod.Instance.Log.LogMessage("Button Clicked!");
21-
SoundManager.Instance.PlaySound(NewModAsset.ReviveSound?.LoadAsset(), false, 2f);
22-
23-
var closestBody = Utils.GetClosestBody();
24-
if (closestBody != null)
16+
/// <summary>
17+
/// The name displayed on the button. Intentionally left empty to show an existing name elsewhere.
18+
/// </summary>
19+
public override string Name => ""; // It's currently empty since the button has already a name on it
20+
21+
/// <summary>
22+
/// Gets the cooldown time for this button, based on <see cref="NecromancerOption"/>.
23+
/// </summary>
24+
public override float Cooldown => OptionGroupSingleton<NecromancerOption>.Instance.ButtonCooldown;
25+
26+
/// <summary>
27+
/// Gets the maximum number of uses for this button, based on <see cref="NecromancerOption"/>.
28+
/// </summary>
29+
public override int MaxUses => (int)OptionGroupSingleton<NecromancerOption>.Instance.AbilityUses;
30+
31+
/// <summary>
32+
/// Determines how long the effect from clicking the button lasts. In this case, no duration is set.
33+
/// </summary>
34+
public override float EffectDuration => 0f;
35+
36+
/// <summary>
37+
/// Defines where on the screen this button should appear.
38+
/// </summary>
39+
public override ButtonLocation Location => ButtonLocation.BottomLeft;
40+
41+
/// <summary>
42+
/// The visual icon for this button, set to the necromancer sprite asset.
43+
/// </summary>
44+
public override LoadableAsset<Sprite> Sprite => NewModAsset.NecromancerButton;
45+
46+
/// <summary>
47+
/// Invoked when the revive button is clicked. Plays a sound and revives the nearest dead body.
48+
/// </summary>
49+
protected override void OnClick()
2550
{
51+
SoundManager.Instance.PlaySound(NewModAsset.ReviveSound?.LoadAsset(), false, 2f);
2652

27-
Utils.RpcRevive(closestBody);
53+
var closestBody = Utils.GetClosestBody();
54+
if (closestBody != null)
55+
{
56+
Utils.RpcRevive(closestBody);
57+
}
2858
}
29-
}
30-
public override bool Enabled(RoleBehaviour role)
31-
{
32-
return role is NecromancerRole;
33-
}
34-
public override bool CanUse()
35-
{
36-
bool isTimerDone = Timer <= 0;
37-
bool hasUsesLeft = UsesLeft > 0;
38-
var closestBody = Utils.GetClosestBody();
39-
bool isNearDeadBody = closestBody != null;
40-
bool isFakeBody = isNearDeadBody && PranksterUtilities.IsPranksterBody(closestBody);
4159

42-
if (closestBody == null)
60+
/// <summary>
61+
/// Determines whether this button is enabled for the role, returning true if the role is <see cref="NecromancerRole"/>.
62+
/// </summary>
63+
/// <param name="role">The current player's role.</param>
64+
/// <returns>True if the role is Necromancer; otherwise false.</returns>
65+
public override bool Enabled(RoleBehaviour role)
4366
{
44-
return false;
67+
return role is NecromancerRole;
4568
}
4669

47-
bool wasNotKilledByNecromancer = true;
48-
var deadBody = closestBody.GetComponent<DeadBody>();
49-
if (deadBody != null)
70+
/// <summary>
71+
/// Checks whether the player can currently use the revive button, ensuring cooldowns, ability uses, and conditions are met.
72+
/// </summary>
73+
/// <returns>True if all requirements to use this button are met; otherwise false.</returns>
74+
public override bool CanUse()
5075
{
51-
var killedPlayer = GameData.Instance.GetPlayerById(deadBody.ParentId)?.Object;
52-
if (killedPlayer != null)
76+
bool isTimerDone = Timer <= 0;
77+
bool hasUsesLeft = UsesLeft > 0;
78+
var closestBody = Utils.GetClosestBody();
79+
bool isNearDeadBody = closestBody != null;
80+
bool isFakeBody = isNearDeadBody && PranksterUtilities.IsPranksterBody(closestBody);
81+
82+
if (closestBody == null)
83+
{
84+
return false;
85+
}
86+
87+
bool wasNotKilledByNecromancer = true;
88+
var deadBody = closestBody.GetComponent<DeadBody>();
89+
if (deadBody != null)
5390
{
54-
var killer = Utils.GetKiller(killedPlayer);
55-
if (killer != null && killer.Data.Role is NecromancerRole)
91+
var killedPlayer = GameData.Instance.GetPlayerById(deadBody.ParentId)?.Object;
92+
if (killedPlayer != null)
5693
{
57-
wasNotKilledByNecromancer = false;
94+
var killer = Utils.GetKiller(killedPlayer);
95+
if (killer != null && killer.Data.Role is NecromancerRole)
96+
{
97+
wasNotKilledByNecromancer = false;
98+
}
5899
}
59100
}
101+
return isTimerDone && hasUsesLeft && isNearDeadBody && wasNotKilledByNecromancer && !isFakeBody;
60102
}
61-
return isTimerDone && hasUsesLeft && isNearDeadBody && wasNotKilledByNecromancer && !isFakeBody;
62103
}
63104
}

NewMod/Buttons/Prankster/FakeBodyButton.cs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,66 @@
99

1010
namespace NewMod.Buttons.Prankster
1111
{
12+
/// <summary>
13+
/// Defines a custom action button for the role.
14+
/// </summary>
1215
public class FakeBodyButton : CustomActionButton
1316
{
17+
/// <summary>
18+
/// Gets the name displayed on the button.
19+
/// </summary>
1420
public override string Name => "Prank";
21+
22+
/// <summary>
23+
/// Gets the cooldown duration for using the prank ability, based on <see cref="PranksterOptions"/>.
24+
/// </summary>
1525
public override float Cooldown => OptionGroupSingleton<PranksterOptions>.Instance.PrankCooldown;
26+
27+
/// <summary>
28+
/// Gets the maximum number of times the prank ability can be used, based on <see cref="PranksterOptions"/>.
29+
/// </summary>
1630
public override int MaxUses => (int)OptionGroupSingleton<PranksterOptions>.Instance.PrankMaxUses;
31+
32+
/// <summary>
33+
/// Determines where on the screen this button will appear.
34+
/// </summary>
1735
public override ButtonLocation Location => ButtonLocation.BottomRight;
36+
37+
/// <summary>
38+
/// The duration of any effect caused by this button press; in this case, no effect duration is used.
39+
/// </summary>
1840
public override float EffectDuration => 0f;
41+
42+
/// <summary>
43+
/// The sprite asset representing this button.
44+
/// </summary>
1945
public override LoadableAsset<Sprite> Sprite => NewModAsset.DeadBodySprite;
46+
47+
/// <summary>
48+
/// Checks whether the Prankster can use this button, ensuring that there is at least one dead player in the game.
49+
/// </summary>
50+
/// <returns>True if the base conditions are met and there is a dead player, otherwise false.</returns>
2051
public override bool CanUse()
2152
{
2253
return base.CanUse() && Utils.AnyDeadPlayer();
2354
}
55+
56+
/// <summary>
57+
/// Called when the button is clicked. Spawns a fake dead body at the local player's position.
58+
/// </summary>
2459
protected override void OnClick()
2560
{
2661
PranksterUtilities.CreatePranksterDeadBody(PlayerControl.LocalPlayer, PlayerControl.LocalPlayer.PlayerId);
2762
}
63+
64+
/// <summary>
65+
/// Determines whether this button is enabled for the specified role.
66+
/// </summary>
67+
/// <param name="role">The player's current role.</param>
68+
/// <returns>True if the role is <see cref="PRK"/>, otherwise false.</returns>
2869
public override bool Enabled(RoleBehaviour role)
2970
{
3071
return role is PRK;
3172
}
3273
}
33-
}
74+
}

0 commit comments

Comments
 (0)