Skip to content

Commit ca68dd7

Browse files
committed
Add 1 new role and 2 modifiers
1 parent 6bc27b9 commit ca68dd7

8 files changed

Lines changed: 348 additions & 1 deletion

File tree

NewMod/Modifiers/ExplosiveModifier.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public class ExplosiveModifier : TimedModifier
1313
public override string ModifierName => "Explosive";
1414
public override bool HideOnUi => false;
1515
public override bool AutoStart => true;
16+
public override bool ShowInFreeplay => true;
1617
public override float Duration => OptionGroupSingleton<ExplosiveModifierOptions>.Instance.Duration;
1718
public override bool RemoveOnComplete => true;
1819
private bool isFlashing = false;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using MiraAPI.GameOptions;
2+
using MiraAPI.Modifiers.Types;
3+
using MiraAPI.Utilities;
4+
using NewMod.Options.Modifiers;
5+
using UnityEngine;
6+
7+
namespace NewMod.Modifiers
8+
{
9+
public class FalseFormModifier : TimedModifier
10+
{
11+
public override string ModifierName => "FalseForm";
12+
public override bool AutoStart =>
13+
OptionGroupSingleton<FalseFormModifierOptions>.Instance.EnableModifier;
14+
public override float Duration =>
15+
(int)OptionGroupSingleton<FalseFormModifierOptions>.Instance.FalseFormDuration;
16+
public override bool ShowInFreeplay => true;
17+
public override bool HideOnUi => false;
18+
public override bool RemoveOnComplete => true;
19+
private float timer;
20+
private AppearanceBackup oldAppearance;
21+
public override void OnActivate()
22+
{
23+
oldAppearance = new AppearanceBackup
24+
{
25+
PlayerName = Player.Data.PlayerName,
26+
HatId = Player.Data.DefaultOutfit.HatId,
27+
SkinId = Player.Data.DefaultOutfit.SkinId,
28+
PetId = Player.Data.DefaultOutfit.PetId,
29+
ColorId = Player.Data.DefaultOutfit.ColorId
30+
};
31+
}
32+
public override bool? CanVent()
33+
{
34+
return Player.Data.Role.CanVent;
35+
}
36+
public override string GetDescription()
37+
{
38+
return ModifierName
39+
+ $"\nYour appearance changes every {OptionGroupSingleton<FalseFormModifierOptions>.Instance.FalseFormAppearanceTimer.Value} seconds.";
40+
}
41+
42+
public override void FixedUpdate()
43+
{
44+
base.FixedUpdate();
45+
46+
timer += Time.fixedDeltaTime;
47+
48+
if (timer >= OptionGroupSingleton<FalseFormModifierOptions>.Instance.FalseFormAppearanceTimer.Value)
49+
{
50+
Player.RpcSetName(Helpers.RandomString(5));
51+
Player.RpcSetColor((byte)Random.Range(0, Palette.PlayerColors.Count));
52+
Player.RpcSetHat(HatManager.Instance.AllHats[Random.Range(0, HatManager.Instance.allHats.Count)].ProductId);
53+
Player.RpcSetSkin(HatManager.Instance.AllSkins[Random.Range(0, HatManager.Instance.allSkins.Count)].ProductId);
54+
Player.RpcSetPet(HatManager.Instance.AllPets[Random.Range(0, HatManager.Instance.allPets.Count)].ProductId);
55+
}
56+
}
57+
public override void OnDeactivate()
58+
{
59+
if (OptionGroupSingleton<FalseFormModifierOptions>.Instance.RevertAppearance)
60+
{
61+
Player.RpcSetName(oldAppearance.PlayerName);
62+
Player.RpcSetColor((byte)oldAppearance.ColorId);
63+
Player.RpcSetHat(oldAppearance.HatId);
64+
Player.RpcSetSkin(oldAppearance.SkinId);
65+
Player.RpcSetPet(oldAppearance.PetId);
66+
}
67+
}
68+
}
69+
class AppearanceBackup
70+
{
71+
public string PlayerName;
72+
public string HatId, SkinId, PetId;
73+
public int ColorId;
74+
}
75+
}

NewMod/Modifiers/StickyModifier.cs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using MiraAPI.GameOptions;
4+
using MiraAPI.Modifiers.Types;
5+
using NewMod.Options.Modifiers;
6+
using Reactor.Utilities;
7+
using UnityEngine;
8+
9+
namespace NewMod.Modifiers
10+
{
11+
public class StickyModifier : TimedModifier
12+
{
13+
public override string ModifierName => "Sticky";
14+
15+
public override bool AutoStart =>
16+
OptionGroupSingleton<StickyModifierOptions>.Instance.EnableModifier;
17+
18+
public override float Duration =>
19+
(int)OptionGroupSingleton<StickyModifierOptions>.Instance.StickyDuration;
20+
21+
public override bool HideOnUi => false;
22+
public override bool ShowInFreeplay => true;
23+
public override bool RemoveOnComplete => true;
24+
25+
public static List<PlayerControl> linkedPlayers = new();
26+
27+
public override bool? CanVent()
28+
{
29+
return Player.Data.Role.CanVent;
30+
}
31+
32+
public override string GetDescription()
33+
{
34+
float distance = OptionGroupSingleton<StickyModifierOptions>.Instance.StickyDistance.Value;
35+
float duration = OptionGroupSingleton<StickyModifierOptions>.Instance.StickyDuration.Value;
36+
37+
return $"{ModifierName}: Pulls nearby players within {distance} units for {duration} seconds.";
38+
}
39+
40+
public override void FixedUpdate()
41+
{
42+
base.FixedUpdate();
43+
44+
if (!Player.CanMove) return;
45+
46+
foreach (var player in PlayerControl.AllPlayerControls)
47+
{
48+
if (player == Player || linkedPlayers.Contains(player)) continue;
49+
50+
float distance = OptionGroupSingleton<StickyModifierOptions>.Instance.StickyDistance.Value;
51+
52+
if (Vector2.Distance(player.GetTruePosition(), Player.GetTruePosition()) < distance)
53+
{
54+
linkedPlayers.Add(player);
55+
Coroutines.Start(CoFollowStickyPlayer(player));
56+
}
57+
}
58+
}
59+
60+
public IEnumerator CoFollowStickyPlayer(PlayerControl player)
61+
{
62+
float duration = 5f;
63+
64+
var info = new StickyState
65+
{
66+
StickyOwner = Player,
67+
LinkedPlayer = player,
68+
velocity = Vector3.zero,
69+
};
70+
71+
yield return HudManager.Instance.StartCoroutine(
72+
Effects.Overlerp(duration, new System.Action<float>((t) =>
73+
{
74+
Vector3 targetPos = info.LinkedPlayer.transform.position;
75+
Vector3 currentPos = info.StickyOwner.transform.position;
76+
77+
info.LinkedPlayer.transform.position = Vector3.SmoothDamp(
78+
targetPos,
79+
currentPos,
80+
ref info.velocity,
81+
t
82+
);
83+
})
84+
));
85+
86+
linkedPlayers.Remove(player);
87+
}
88+
}
89+
90+
class StickyState
91+
{
92+
public PlayerControl StickyOwner;
93+
public PlayerControl LinkedPlayer;
94+
public Vector3 velocity;
95+
}
96+
}

NewMod/NewModEndReasons.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public enum NewModEndReasons
77
PranksterWin = 112,
88
SpecialAgentWin = 113,
99
TheVisionaryWin = 114,
10-
OverloadWin = 115
10+
OverloadWin = 115,
11+
EgoistWin = 116
1112
}
1213
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using MiraAPI.GameOptions;
2+
using MiraAPI.GameOptions.OptionTypes;
3+
using MiraAPI.Utilities;
4+
using NewMod.Modifiers;
5+
6+
namespace NewMod.Options.Modifiers
7+
{
8+
public class FalseFormModifierOptions : AbstractOptionGroup<FalseFormModifier>
9+
{
10+
public override string GroupName => "FalseForm Settings";
11+
public ModdedToggleOption EnableModifier { get; } = new("Enable FalseForm", true);
12+
public ModdedNumberOption FalseFormDuration { get; } =
13+
new(
14+
"Duration of the FalseForm effect",
15+
20f,
16+
min: 10f,
17+
max: 30f,
18+
increment: 1f,
19+
suffixType: MiraNumberSuffixes.Seconds
20+
);
21+
public ModdedNumberOption FalseFormAppearanceTimer { get; } =
22+
new(
23+
"Appearance Change Delay",
24+
5f,
25+
min: 1f,
26+
max: 10f,
27+
increment: 0.5f,
28+
suffixType: MiraNumberSuffixes.Seconds
29+
);
30+
public ModdedToggleOption RevertAppearance { get; } =
31+
new("Revert appearance after FalseForm ends", true);
32+
}
33+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using MiraAPI.GameOptions;
2+
using MiraAPI.GameOptions.OptionTypes;
3+
using MiraAPI.Utilities;
4+
using NewMod.Modifiers;
5+
6+
namespace NewMod.Options.Modifiers
7+
{
8+
public class StickyModifierOptions : AbstractOptionGroup<StickyModifier>
9+
{
10+
public override string GroupName => "Sticky Settings";
11+
public ModdedToggleOption EnableModifier { get; } = new("Enable StickyModifier", true);
12+
public ModdedNumberOption StickyDuration { get; } =
13+
new(
14+
"Duration of Sticky Effect",
15+
15f,
16+
min: 10f,
17+
max: 30f,
18+
increment: 0.5f,
19+
suffixType: MiraNumberSuffixes.Seconds
20+
);
21+
public ModdedNumberOption StickyDistance { get; } =
22+
new(
23+
"Distance to trigger stickiness",
24+
1f,
25+
min: 1f,
26+
max: 3f,
27+
increment: 0.5f,
28+
suffixType: MiraNumberSuffixes.None
29+
);
30+
}
31+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using MiraAPI.GameOptions;
2+
using MiraAPI.GameOptions.Attributes;
3+
using MiraAPI.GameOptions.OptionTypes;
4+
using MiraAPI.Utilities;
5+
using NewMod.Roles.NeutralRoles;
6+
7+
namespace NewMod.Options.Roles.EgoistOptions
8+
{
9+
public class EgoistRoleOptions : AbstractOptionGroup<EgoistRole>
10+
{
11+
public override string GroupName => "Egoist Settings";
12+
13+
public ModdedNumberOption MinimumVotesToWin { get; } =
14+
new(
15+
"Minimum votes on Egoist to trigger win",
16+
3,
17+
min: 1,
18+
max: 10,
19+
increment: 1,
20+
suffixType: MiraNumberSuffixes.None
21+
);
22+
}
23+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using System.Linq;
2+
using MiraAPI.Events;
3+
using MiraAPI.Events.Vanilla.Meeting;
4+
using MiraAPI.GameOptions;
5+
using MiraAPI.Networking;
6+
using MiraAPI.Roles;
7+
using MiraAPI.Utilities;
8+
using NewMod.Options.Roles.EgoistOptions;
9+
using UnityEngine;
10+
11+
namespace NewMod.Roles.NeutralRoles
12+
{
13+
public class EgoistRole : CrewmateRole, ICustomRole
14+
{
15+
public string RoleName => "Egoist";
16+
public string RoleDescription => "Crave attention. Earn revenge.";
17+
public string RoleLongDescription =>
18+
"You are the Egoist, a chaotic neutral entity.\n\n"
19+
+ "Your goal is to be ejected — if you are, and enough players vote for you, they die and you win.";
20+
public Color RoleColor => new Color(0.8f, 0.3f, 0.6f, 1f);
21+
public ModdedRoleTeams Team => ModdedRoleTeams.Custom;
22+
public RoleOptionsGroup RoleOptionsGroup => RoleOptionsGroup.Neutral;
23+
24+
public CustomRoleConfiguration Configuration =>
25+
new(this)
26+
{
27+
AffectedByLightOnAirship = false,
28+
CanGetKilled = true,
29+
UseVanillaKillButton = false,
30+
CanUseVent = false,
31+
CanUseSabotage = false,
32+
TasksCountForProgress = false,
33+
ShowInFreeplay = true,
34+
HideSettings = false,
35+
MaxRoleCount = 1,
36+
OptionsScreenshot = null,
37+
Icon = null,
38+
};
39+
40+
[RegisterEvent]
41+
public static void OnEjection(EjectionEvent evt)
42+
{
43+
var egoist = PlayerControl
44+
.AllPlayerControls.ToArray()
45+
.FirstOrDefault(p => p.Data.Role is EgoistRole);
46+
if (egoist == null)
47+
return;
48+
49+
var ejected = evt.ExileController.initData.networkedPlayer.Object;
50+
if (ejected != egoist)
51+
return;
52+
53+
int minVotes = OptionGroupSingleton<EgoistRoleOptions>.Instance.MinimumVotesToWin;
54+
55+
var voters = PlayerControl
56+
.AllPlayerControls.ToArray()
57+
.Where(p =>
58+
{
59+
var voteData = p.GetVoteData();
60+
return voteData != null && voteData.VotedFor(egoist.PlayerId);
61+
})
62+
.ToList();
63+
64+
if (voters.Count >= minVotes)
65+
{
66+
foreach (var p in voters)
67+
{
68+
egoist.RpcCustomMurder(
69+
p,
70+
didSucceed: true,
71+
resetKillTimer: false,
72+
createDeadBody: true,
73+
teleportMurderer: false,
74+
showKillAnim: false,
75+
playKillSound: true
76+
);
77+
}
78+
GameManager.Instance.RpcEndGame((GameOverReason)NewModEndReasons.EgoistWin, false);
79+
}
80+
}
81+
82+
public override bool DidWin(GameOverReason gameOverReason)
83+
{
84+
return gameOverReason == (GameOverReason)NewModEndReasons.EgoistWin;
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)