Latejoin traitors (#9783)
This commit is contained in:
@@ -357,6 +357,8 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
RoundNumberMetric.Inc();
|
RoundNumberMetric.Inc();
|
||||||
|
|
||||||
|
PlayersJoinedRoundNormally = 0;
|
||||||
|
|
||||||
RunLevel = GameRunLevel.PreRoundLobby;
|
RunLevel = GameRunLevel.PreRoundLobby;
|
||||||
LobbySong = _robustRandom.Pick(_lobbyMusicCollection.PickFiles).ToString();
|
LobbySong = _robustRandom.Pick(_lobbyMusicCollection.PickFiles).ToString();
|
||||||
RandomizeLobbyBackground();
|
RandomizeLobbyBackground();
|
||||||
|
|||||||
@@ -28,6 +28,12 @@ namespace Content.Server.GameTicking
|
|||||||
[ViewVariables(VVAccess.ReadWrite), Obsolete("Due for removal when observer spawning is refactored.")]
|
[ViewVariables(VVAccess.ReadWrite), Obsolete("Due for removal when observer spawning is refactored.")]
|
||||||
private EntityCoordinates _spawnPoint;
|
private EntityCoordinates _spawnPoint;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How many players have joined the round through normal methods.
|
||||||
|
/// Useful for game rules to look at. Doesn't count observers, people in lobby, etc.
|
||||||
|
/// </summary>
|
||||||
|
public int PlayersJoinedRoundNormally = 0;
|
||||||
|
|
||||||
// Mainly to avoid allocations.
|
// Mainly to avoid allocations.
|
||||||
private readonly List<EntityCoordinates> _possiblePositions = new();
|
private readonly List<EntityCoordinates> _possiblePositions = new();
|
||||||
|
|
||||||
@@ -193,7 +199,8 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We raise this event directed to the mob, but also broadcast it so game rules can do something now.
|
// We raise this event directed to the mob, but also broadcast it so game rules can do something now.
|
||||||
var aev = new PlayerSpawnCompleteEvent(mob, player, jobId, lateJoin, station, character);
|
PlayersJoinedRoundNormally++;
|
||||||
|
var aev = new PlayerSpawnCompleteEvent(mob, player, jobId, lateJoin, PlayersJoinedRoundNormally, station, character);
|
||||||
RaiseLocalEvent(mob, aev, true);
|
RaiseLocalEvent(mob, aev, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,7 +324,10 @@ namespace Content.Server.GameTicking
|
|||||||
public EntityUid Station { get; }
|
public EntityUid Station { get; }
|
||||||
public HumanoidCharacterProfile Profile { get; }
|
public HumanoidCharacterProfile Profile { get; }
|
||||||
|
|
||||||
public PlayerSpawnCompleteEvent(EntityUid mob, IPlayerSession player, string? jobId, bool lateJoin, EntityUid station, HumanoidCharacterProfile profile)
|
// Ex. If this is the 27th person to join, this will be 27.
|
||||||
|
public int JoinOrder { get; }
|
||||||
|
|
||||||
|
public PlayerSpawnCompleteEvent(EntityUid mob, IPlayerSession player, string? jobId, bool lateJoin, int joinOrder, EntityUid station, HumanoidCharacterProfile profile)
|
||||||
{
|
{
|
||||||
Mob = mob;
|
Mob = mob;
|
||||||
Player = player;
|
Player = player;
|
||||||
@@ -325,6 +335,7 @@ namespace Content.Server.GameTicking
|
|||||||
LateJoin = lateJoin;
|
LateJoin = lateJoin;
|
||||||
Station = station;
|
Station = station;
|
||||||
Profile = profile;
|
Profile = profile;
|
||||||
|
JoinOrder = joinOrder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Chat.Managers;
|
using Content.Server.Chat.Managers;
|
||||||
using Content.Server.GameTicking.Rules.Configurations;
|
|
||||||
using Content.Server.Objectives.Interfaces;
|
using Content.Server.Objectives.Interfaces;
|
||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
using Content.Server.Roles;
|
using Content.Server.Roles;
|
||||||
@@ -42,12 +40,16 @@ public sealed class TraitorRuleSystem : GameRuleSystem
|
|||||||
public int TotalTraitors => Traitors.Count;
|
public int TotalTraitors => Traitors.Count;
|
||||||
public string[] Codewords = new string[3];
|
public string[] Codewords = new string[3];
|
||||||
|
|
||||||
|
private int _playersPerTraitor => _cfg.GetCVar(CCVars.TraitorPlayersPerTraitor);
|
||||||
|
private int _maxTraitors => _cfg.GetCVar(CCVars.TraitorMaxTraitors);
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<RoundStartAttemptEvent>(OnStartAttempt);
|
SubscribeLocalEvent<RoundStartAttemptEvent>(OnStartAttempt);
|
||||||
SubscribeLocalEvent<RulePlayerJobsAssignedEvent>(OnPlayersSpawned);
|
SubscribeLocalEvent<RulePlayerJobsAssignedEvent>(OnPlayersSpawned);
|
||||||
|
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(HandleLatejoin);
|
||||||
SubscribeLocalEvent<RoundEndTextAppendEvent>(OnRoundEndText);
|
SubscribeLocalEvent<RoundEndTextAppendEvent>(OnRoundEndText);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,9 +109,8 @@ public sealed class TraitorRuleSystem : GameRuleSystem
|
|||||||
if (!RuleAdded)
|
if (!RuleAdded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var playersPerTraitor = _cfg.GetCVar(CCVars.TraitorPlayersPerTraitor);
|
var numTraitors = MathHelper.Clamp(ev.Players.Length / _playersPerTraitor, 1, _maxTraitors);
|
||||||
var maxTraitors = _cfg.GetCVar(CCVars.TraitorMaxTraitors);
|
var codewordCount = _cfg.GetCVar(CCVars.TraitorCodewordCount);
|
||||||
var numTraitors = MathHelper.Clamp(ev.Players.Length / playersPerTraitor, 1, maxTraitors);
|
|
||||||
|
|
||||||
var traitorPool = FindPotentialTraitors(ev);
|
var traitorPool = FindPotentialTraitors(ev);
|
||||||
var selectedTraitors = PickTraitors(numTraitors, traitorPool);
|
var selectedTraitors = PickTraitors(numTraitors, traitorPool);
|
||||||
@@ -154,7 +155,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem
|
|||||||
Logger.InfoS("preset", "Insufficient ready players to fill up with traitors, stopping the selection.");
|
Logger.InfoS("preset", "Insufficient ready players to fill up with traitors, stopping the selection.");
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < traitorCount; i++)
|
for (var i = 0; i < traitorCount; i++)
|
||||||
{
|
{
|
||||||
results.Add(_random.PickAndTake(prefList));
|
results.Add(_random.PickAndTake(prefList));
|
||||||
@@ -211,6 +212,48 @@ public sealed class TraitorRuleSystem : GameRuleSystem
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleLatejoin(PlayerSpawnCompleteEvent ev)
|
||||||
|
{
|
||||||
|
if (!RuleAdded)
|
||||||
|
return;
|
||||||
|
if (TotalTraitors >= _maxTraitors)
|
||||||
|
return;
|
||||||
|
if (!ev.LateJoin)
|
||||||
|
return;
|
||||||
|
if (!ev.Profile.AntagPreferences.Contains(TraitorPrototypeID))
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
if (ev.JobId == null || !_prototypeManager.TryIndex<JobPrototype>(ev.JobId, out var job))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!job.CanBeAntag)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// the nth player we adjust our probabilities around
|
||||||
|
int target = ((_playersPerTraitor * TotalTraitors) + 1);
|
||||||
|
|
||||||
|
float chance = (1f / _playersPerTraitor);
|
||||||
|
|
||||||
|
/// If we have too many traitors, divide by how many players below target for next traitor we are.
|
||||||
|
if (ev.JoinOrder < target)
|
||||||
|
{
|
||||||
|
chance /= (target - ev.JoinOrder);
|
||||||
|
} else // Tick up towards 100% chance.
|
||||||
|
{
|
||||||
|
chance *= ((ev.JoinOrder + 1) - target);
|
||||||
|
}
|
||||||
|
if (chance > 1)
|
||||||
|
chance = 1;
|
||||||
|
|
||||||
|
// Now that we've calculated our chance, roll and make them a traitor if we roll under.
|
||||||
|
// You get one shot.
|
||||||
|
if (_random.Prob((float) chance))
|
||||||
|
{
|
||||||
|
MakeTraitor(ev.Player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnRoundEndText(RoundEndTextAppendEvent ev)
|
private void OnRoundEndText(RoundEndTextAppendEvent ev)
|
||||||
{
|
{
|
||||||
if (!RuleAdded)
|
if (!RuleAdded)
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace Content.Server.Objectives.Conditions
|
|||||||
|
|
||||||
public string Description => Loc.GetString("objective-condition-kill-person-description");
|
public string Description => Loc.GetString("objective-condition-kill-person-description");
|
||||||
|
|
||||||
public SpriteSpecifier Icon => new SpriteSpecifier.Rsi(new ResourcePath("Objects/Weapons/Guns/Pistols/mk58_wood.rsi"), "icon");
|
public SpriteSpecifier Icon => new SpriteSpecifier.Rsi(new ResourcePath("Objects/Weapons/Guns/Pistols/viper.rsi"), "icon");
|
||||||
|
|
||||||
public float Progress => (Target?.CharacterDeadIC ?? true) ? 1f : 0f;
|
public float Progress => (Target?.CharacterDeadIC ?? true) ? 1f : 0f;
|
||||||
|
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ namespace Content.Shared.CCVar
|
|||||||
CVarDef.Create("suspicion.min_traitors", 2);
|
CVarDef.Create("suspicion.min_traitors", 2);
|
||||||
|
|
||||||
public static readonly CVarDef<int> SuspicionPlayersPerTraitor =
|
public static readonly CVarDef<int> SuspicionPlayersPerTraitor =
|
||||||
CVarDef.Create("suspicion.players_per_traitor", 5);
|
CVarDef.Create("suspicion.players_per_traitor", 6);
|
||||||
|
|
||||||
public static readonly CVarDef<int> SuspicionStartingBalance =
|
public static readonly CVarDef<int> SuspicionStartingBalance =
|
||||||
CVarDef.Create("suspicion.starting_balance", 20);
|
CVarDef.Create("suspicion.starting_balance", 20);
|
||||||
@@ -262,7 +262,7 @@ namespace Content.Shared.CCVar
|
|||||||
CVarDef.Create("traitor.min_players", 5);
|
CVarDef.Create("traitor.min_players", 5);
|
||||||
|
|
||||||
public static readonly CVarDef<int> TraitorMaxTraitors =
|
public static readonly CVarDef<int> TraitorMaxTraitors =
|
||||||
CVarDef.Create("traitor.max_traitors", 7);
|
CVarDef.Create("traitor.max_traitors", 12); // Assuming average server maxes somewhere from like 50-80 people
|
||||||
|
|
||||||
public static readonly CVarDef<int> TraitorPlayersPerTraitor =
|
public static readonly CVarDef<int> TraitorPlayersPerTraitor =
|
||||||
CVarDef.Create("traitor.players_per_traitor", 5);
|
CVarDef.Create("traitor.players_per_traitor", 5);
|
||||||
|
|||||||
Reference in New Issue
Block a user