diff --git a/src/Impostor.Api/Innersloth/GameOptions/HideNSeekGameOptions.cs b/src/Impostor.Api/Innersloth/GameOptions/HideNSeekGameOptions.cs
index 6d061a90..87b01adc 100644
--- a/src/Impostor.Api/Innersloth/GameOptions/HideNSeekGameOptions.cs
+++ b/src/Impostor.Api/Innersloth/GameOptions/HideNSeekGameOptions.cs
@@ -2,7 +2,7 @@ namespace Impostor.Api.Innersloth.GameOptions;
public class HideNSeekGameOptions : IGameOptions
{
- public const int LatestVersion = 7;
+ public const int LatestVersion = 8;
public HideNSeekGameOptions(byte version = LatestVersion)
{
@@ -16,6 +16,12 @@ public class HideNSeekGameOptions : IGameOptions
///
public GameModes GameMode => GameModes.HideNSeek;
+ ///
+ public SpecialGameModes SpecialMode { get; set; } = SpecialGameModes.None;
+
+ ///
+ public RulesPresets RulesPreset { get; set; } = RulesPresets.Custom;
+
///
public byte MaxPlayers { get; set; } = 15;
@@ -96,6 +102,12 @@ public class HideNSeekGameOptions : IGameOptions
public void Deserialize(IMessageReader reader)
{
+ if (Version >= 8)
+ {
+ SpecialMode = (SpecialGameModes)reader.ReadByte();
+ RulesPreset = (RulesPresets)reader.ReadByte();
+ }
+
MaxPlayers = reader.ReadByte();
Keywords = (GameKeywords)reader.ReadInt32();
Map = (MapTypes)reader.ReadByte();
@@ -121,7 +133,7 @@ public class HideNSeekGameOptions : IGameOptions
MaxPingTime = reader.ReadSingle();
CrewmateTimeInVent = reader.ReadSingle();
- if (Version > 7)
+ if (Version > LatestVersion)
{
IGameOptions.ThrowUnknownVersion(Version);
}
@@ -129,6 +141,12 @@ public class HideNSeekGameOptions : IGameOptions
public void Serialize(IMessageWriter writer)
{
+ if (Version >= 8)
+ {
+ writer.Write((byte)SpecialMode);
+ writer.Write((byte)RulesPreset);
+ }
+
writer.Write(MaxPlayers);
writer.Write((uint)Keywords);
writer.Write((byte)Map);
@@ -154,7 +172,7 @@ public class HideNSeekGameOptions : IGameOptions
writer.Write(MaxPingTime);
writer.Write(CrewmateTimeInVent);
- if (Version > 7)
+ if (Version > LatestVersion)
{
IGameOptions.ThrowUnknownVersion(Version);
}
diff --git a/src/Impostor.Api/Innersloth/GameOptions/IGameOptions.cs b/src/Impostor.Api/Innersloth/GameOptions/IGameOptions.cs
index 10200c15..fd604958 100644
--- a/src/Impostor.Api/Innersloth/GameOptions/IGameOptions.cs
+++ b/src/Impostor.Api/Innersloth/GameOptions/IGameOptions.cs
@@ -10,10 +10,20 @@ public interface IGameOptions
public byte Version { get; }
///
- /// Gets the currently active gamemode.
+ /// Gets the currently active gamemode. This is currently used for the Normal and HideAndSeek gamemodes.
///
public GameModes GameMode { get; }
+ ///
+ /// Gets the currently active special gamemode. This is currently used for the AprilFools gamemode.
+ ///
+ public SpecialGameModes SpecialMode { get; }
+
+ ///
+ /// Gets the rule preset.
+ ///
+ public RulesPresets RulesPreset { get; }
+
///
/// Gets or sets the maximum amount of players for this lobby.
///
diff --git a/src/Impostor.Api/Innersloth/GameOptions/LegacyGameOptionsData.cs b/src/Impostor.Api/Innersloth/GameOptions/LegacyGameOptionsData.cs
index 1ed7ecc5..25862c46 100644
--- a/src/Impostor.Api/Innersloth/GameOptions/LegacyGameOptionsData.cs
+++ b/src/Impostor.Api/Innersloth/GameOptions/LegacyGameOptionsData.cs
@@ -21,6 +21,12 @@ public class LegacyGameOptionsData : IGameOptions
public GameModes GameMode => GameModes.Normal;
+ ///
+ public SpecialGameModes SpecialMode { get; } = SpecialGameModes.None;
+
+ ///
+ public RulesPresets RulesPreset { get; } = RulesPresets.Custom;
+
///
/// Gets or sets the maximum amount of players for this lobby.
///
diff --git a/src/Impostor.Api/Innersloth/GameOptions/NormalGameOptions.cs b/src/Impostor.Api/Innersloth/GameOptions/NormalGameOptions.cs
index 537a0ed8..7095f6de 100644
--- a/src/Impostor.Api/Innersloth/GameOptions/NormalGameOptions.cs
+++ b/src/Impostor.Api/Innersloth/GameOptions/NormalGameOptions.cs
@@ -4,7 +4,7 @@ namespace Impostor.Api.Innersloth.GameOptions;
public class NormalGameOptions : IGameOptions
{
- public const int LatestVersion = 7;
+ public const int LatestVersion = 8;
public NormalGameOptions(byte version = LatestVersion)
{
@@ -19,6 +19,12 @@ public class NormalGameOptions : IGameOptions
///
public GameModes GameMode => GameModes.Normal;
+ ///
+ public SpecialGameModes SpecialMode { get; set; } = SpecialGameModes.None;
+
+ ///
+ public RulesPresets RulesPreset { get; set; } = RulesPresets.Custom;
+
///
public byte MaxPlayers { get; set; } = 10;
@@ -133,6 +139,12 @@ public class NormalGameOptions : IGameOptions
public void Deserialize(IMessageReader reader)
{
+ if (Version >= 8)
+ {
+ SpecialMode = (SpecialGameModes)reader.ReadByte();
+ RulesPreset = (RulesPresets)reader.ReadByte();
+ }
+
MaxPlayers = reader.ReadByte();
Keywords = (GameKeywords)reader.ReadUInt32();
Map = (MapTypes)reader.ReadByte();
@@ -163,7 +175,7 @@ public class NormalGameOptions : IGameOptions
RoleOptions.Deserialize(reader);
- if (Version > 7)
+ if (Version > LatestVersion)
{
IGameOptions.ThrowUnknownVersion(Version);
}
@@ -171,6 +183,12 @@ public class NormalGameOptions : IGameOptions
public void Serialize(IMessageWriter writer)
{
+ if (Version >= 8)
+ {
+ writer.Write((byte)SpecialMode);
+ writer.Write((byte)RulesPreset);
+ }
+
writer.Write(MaxPlayers);
writer.Write((uint)Keywords);
writer.Write((byte)Map);
@@ -201,7 +219,7 @@ public class NormalGameOptions : IGameOptions
RoleOptions.Serialize(writer);
- if (Version > 7)
+ if (Version > LatestVersion)
{
IGameOptions.ThrowUnknownVersion(Version);
}
diff --git a/src/Impostor.Api/Innersloth/GameOptions/RoleOptions/NoisemakerRoleOptions.cs b/src/Impostor.Api/Innersloth/GameOptions/RoleOptions/NoisemakerRoleOptions.cs
new file mode 100644
index 00000000..d84a88d5
--- /dev/null
+++ b/src/Impostor.Api/Innersloth/GameOptions/RoleOptions/NoisemakerRoleOptions.cs
@@ -0,0 +1,33 @@
+namespace Impostor.Api.Innersloth.GameOptions.RoleOptions;
+
+public class NoisemakerRoleOptions : IRoleOptions
+{
+ public NoisemakerRoleOptions(byte version)
+ {
+ Version = version;
+ }
+
+ public byte Version { get; }
+
+ public RoleTypes Type => RoleTypes.Noisemaker;
+
+ public bool ImpostorAlert { get; set; } = true;
+
+ public byte AlertDuration { get; set; } = 10;
+
+ public static NoisemakerRoleOptions Deserialize(IMessageReader reader, byte version)
+ {
+ var options = new NoisemakerRoleOptions(version);
+
+ options.AlertDuration = reader.ReadByte();
+ options.ImpostorAlert = reader.ReadBoolean();
+
+ return options;
+ }
+
+ public void Serialize(IMessageWriter writer)
+ {
+ writer.Write(AlertDuration);
+ writer.Write(ImpostorAlert);
+ }
+}
diff --git a/src/Impostor.Api/Innersloth/GameOptions/RoleOptions/PhantomRoleOptions.cs b/src/Impostor.Api/Innersloth/GameOptions/RoleOptions/PhantomRoleOptions.cs
new file mode 100644
index 00000000..72576220
--- /dev/null
+++ b/src/Impostor.Api/Innersloth/GameOptions/RoleOptions/PhantomRoleOptions.cs
@@ -0,0 +1,33 @@
+namespace Impostor.Api.Innersloth.GameOptions.RoleOptions;
+
+public class PhantomRoleOptions : IRoleOptions
+{
+ public PhantomRoleOptions(byte version)
+ {
+ Version = version;
+ }
+
+ public byte Version { get; }
+
+ public RoleTypes Type => RoleTypes.Phantom;
+
+ public byte Cooldown { get; set; } = 15;
+
+ public byte Duration { get; set; } = 30;
+
+ public static PhantomRoleOptions Deserialize(IMessageReader reader, byte version)
+ {
+ var options = new PhantomRoleOptions(version);
+
+ options.Cooldown = reader.ReadByte();
+ options.Duration = reader.ReadByte();
+
+ return options;
+ }
+
+ public void Serialize(IMessageWriter writer)
+ {
+ writer.Write(Cooldown);
+ writer.Write(Duration);
+ }
+}
diff --git a/src/Impostor.Api/Innersloth/GameOptions/RoleOptions/RoleOptionsCollection.cs b/src/Impostor.Api/Innersloth/GameOptions/RoleOptions/RoleOptionsCollection.cs
index d8b70764..6e2da069 100644
--- a/src/Impostor.Api/Innersloth/GameOptions/RoleOptions/RoleOptionsCollection.cs
+++ b/src/Impostor.Api/Innersloth/GameOptions/RoleOptions/RoleOptionsCollection.cs
@@ -31,6 +31,9 @@ public class RoleOptionsCollection
RoleTypes.Engineer => EngineerRoleOptions.Deserialize(roleOptionsReader, Version),
RoleTypes.GuardianAngel => GuardianAngelRoleOptions.Deserialize(roleOptionsReader, Version),
RoleTypes.Shapeshifter => ShapeshifterRoleOptions.Deserialize(roleOptionsReader, Version),
+ RoleTypes.Noisemaker => NoisemakerRoleOptions.Deserialize(roleOptionsReader, Version),
+ RoleTypes.Phantom => PhantomRoleOptions.Deserialize(roleOptionsReader, Version),
+ RoleTypes.Tracker => TrackerRoleOptions.Deserialize(roleOptionsReader, Version),
_ => throw new ArgumentOutOfRangeException(nameof(roleType), roleType, null),
};
diff --git a/src/Impostor.Api/Innersloth/GameOptions/RoleOptions/TrackerRoleOptions.cs b/src/Impostor.Api/Innersloth/GameOptions/RoleOptions/TrackerRoleOptions.cs
new file mode 100644
index 00000000..4b8f50f6
--- /dev/null
+++ b/src/Impostor.Api/Innersloth/GameOptions/RoleOptions/TrackerRoleOptions.cs
@@ -0,0 +1,37 @@
+namespace Impostor.Api.Innersloth.GameOptions.RoleOptions;
+
+public class TrackerRoleOptions : IRoleOptions
+{
+ public TrackerRoleOptions(byte version)
+ {
+ Version = version;
+ }
+
+ public byte Version { get; }
+
+ public RoleTypes Type => RoleTypes.Tracker;
+
+ public byte Cooldown { get; set; } = 15;
+
+ public byte Duration { get; set; } = 30;
+
+ public byte Delay { get; set; } = 1;
+
+ public static TrackerRoleOptions Deserialize(IMessageReader reader, byte version)
+ {
+ var options = new TrackerRoleOptions(version);
+
+ options.Cooldown = reader.ReadByte();
+ options.Duration = reader.ReadByte();
+ options.Delay = reader.ReadByte();
+
+ return options;
+ }
+
+ public void Serialize(IMessageWriter writer)
+ {
+ writer.Write(Cooldown);
+ writer.Write(Duration);
+ writer.Write(Delay);
+ }
+}