Oops, All Captains! (#14943)
This commit is contained in:
73
Content.Server/GameTicking/Rules/AllCaptainsRuleSystem.cs
Normal file
73
Content.Server/GameTicking/Rules/AllCaptainsRuleSystem.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Content.Server.GameTicking.Presets;
|
||||||
|
using Content.Server.GameTicking.Rules.Configurations;
|
||||||
|
using Content.Server.Station.Components;
|
||||||
|
using Content.Shared.Random;
|
||||||
|
using Content.Shared.Random.Helpers;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
|
||||||
|
namespace Content.Server.GameTicking.Rules;
|
||||||
|
|
||||||
|
public sealed class AllCaptainsRuleSystem : GameRuleSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly GameTicker _ticker = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
|
|
||||||
|
public override string Prototype => "AllCaptains";
|
||||||
|
|
||||||
|
private EntityUid holdJobs; // dunno if there should only be one reference like this because I'm a ss14 noob but hey it's only gotta work one day :P
|
||||||
|
|
||||||
|
public override void Added()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Started()
|
||||||
|
{
|
||||||
|
// temporarily disable role timers -- super hacky way workaround for client to be aware that role timers aren't required
|
||||||
|
// without having to set up some kind of replication
|
||||||
|
_cfg.SetCVar(CCVars.GameRoleTimers, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Ended()
|
||||||
|
{
|
||||||
|
_cfg.SetCVar(CCVars.GameRoleTimers, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StationJobsComponent GetJobs(EntityUid station)
|
||||||
|
{
|
||||||
|
if (!holdJobs.IsValid() || !HasComp<StationJobsComponent>(holdJobs)) // this doesn't check station parameter since all captains mode is the same for all stations.
|
||||||
|
{
|
||||||
|
holdJobs = Spawn(null, new EntityCoordinates(station, Vector2.Zero));
|
||||||
|
var stationJobs = AddComp<StationJobsComponent>(holdJobs);
|
||||||
|
|
||||||
|
// Create captains-only specific job list
|
||||||
|
var mapJobList = new Dictionary<string, List<int?>> {{"Captain", new List<int?>{int.MaxValue, int.MaxValue}}};
|
||||||
|
|
||||||
|
stationJobs.RoundStartTotalJobs = mapJobList.Values.Where(x => x[0] is not null && x[0] > 0).Sum(x => x[0]!.Value);
|
||||||
|
stationJobs.MidRoundTotalJobs = mapJobList.Values.Where(x => x[1] is not null && x[1] > 0).Sum(x => x[1]!.Value);
|
||||||
|
stationJobs.TotalJobs = stationJobs.MidRoundTotalJobs;
|
||||||
|
stationJobs.JobList = mapJobList.ToDictionary(x => x.Key, x =>
|
||||||
|
{
|
||||||
|
if (x.Value[1] <= -1)
|
||||||
|
return null;
|
||||||
|
return (uint?) x.Value[1];
|
||||||
|
});
|
||||||
|
stationJobs.RoundStartJobList = mapJobList.ToDictionary(x => x.Key, x =>
|
||||||
|
{
|
||||||
|
if (x.Value[0] <= -1)
|
||||||
|
return null;
|
||||||
|
return (uint?) x.Value[0];
|
||||||
|
});
|
||||||
|
stationJobs.OverflowJobs = new HashSet<string>{"Captain"}; //stationData.StationConfig.OverflowJobs.ToHashSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Comp<StationJobsComponent>(holdJobs);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem
|
|||||||
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
|
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
|
||||||
[Dependency] private readonly UplinkSystem _uplink = default!;
|
[Dependency] private readonly UplinkSystem _uplink = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||||
|
[Dependency] private readonly AllCaptainsRuleSystem _allCaptainsRule = default!;
|
||||||
|
|
||||||
private ISawmill _sawmill = default!;
|
private ISawmill _sawmill = default!;
|
||||||
|
|
||||||
@@ -178,7 +179,8 @@ public sealed class TraitorRuleSystem : GameRuleSystem
|
|||||||
foreach (var player in candidates.Keys)
|
foreach (var player in candidates.Keys)
|
||||||
{
|
{
|
||||||
// Role prevents antag.
|
// Role prevents antag.
|
||||||
if (!(player.Data.ContentData()?.Mind?.AllRoles.All(role => role is not Job { CanBeAntag: false }) ?? false))
|
if (!(_allCaptainsRule != null && _allCaptainsRule.RuleStarted) && // all captains mode lets some of the captains be traitors :3
|
||||||
|
!(player.Data.ContentData()?.Mind?.AllRoles.All(role => role is not Job { CanBeAntag: false }) ?? false))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -296,7 +298,8 @@ public sealed class TraitorRuleSystem : GameRuleSystem
|
|||||||
if (ev.JobId == null || !_prototypeManager.TryIndex<JobPrototype>(ev.JobId, out var job))
|
if (ev.JobId == null || !_prototypeManager.TryIndex<JobPrototype>(ev.JobId, out var job))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!job.CanBeAntag)
|
if (!job.CanBeAntag &&
|
||||||
|
!(_allCaptainsRule != null && _allCaptainsRule.RuleStarted)) // all captains mode lets some of the captains be traitors :3
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Before the announcement is made, late-joiners are considered the same as players who readied.
|
// Before the announcement is made, late-joiners are considered the same as players who readied.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System.Linq;
|
|||||||
using Content.Server.Afk;
|
using Content.Server.Afk;
|
||||||
using Content.Server.Afk.Events;
|
using Content.Server.Afk.Events;
|
||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
|
using Content.Server.GameTicking.Rules;
|
||||||
using Content.Server.Roles;
|
using Content.Server.Roles;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
@@ -28,6 +29,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
|
|||||||
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
[Dependency] private readonly IPrototypeManager _prototypes = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly PlayTimeTrackingManager _tracking = default!;
|
[Dependency] private readonly PlayTimeTrackingManager _tracking = default!;
|
||||||
|
[Dependency] private readonly AllCaptainsRuleSystem _allCaptainsRule = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -159,7 +161,8 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
if (!_prototypes.TryIndex<JobPrototype>(role, out var job) ||
|
if (!_prototypes.TryIndex<JobPrototype>(role, out var job) ||
|
||||||
job.Requirements == null ||
|
job.Requirements == null ||
|
||||||
!_cfg.GetCVar(CCVars.GameRoleTimers))
|
!_cfg.GetCVar(CCVars.GameRoleTimers) ||
|
||||||
|
(_allCaptainsRule != null && _allCaptainsRule.RuleStarted))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
var playTimes = _tracking.GetTrackerTimes(player);
|
var playTimes = _tracking.GetTrackerTimes(player);
|
||||||
@@ -170,7 +173,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
|
|||||||
public HashSet<string> GetDisallowedJobs(IPlayerSession player)
|
public HashSet<string> GetDisallowedJobs(IPlayerSession player)
|
||||||
{
|
{
|
||||||
var roles = new HashSet<string>();
|
var roles = new HashSet<string>();
|
||||||
if (!_cfg.GetCVar(CCVars.GameRoleTimers))
|
if (!_cfg.GetCVar(CCVars.GameRoleTimers) || (_allCaptainsRule != null && _allCaptainsRule.RuleStarted))
|
||||||
return roles;
|
return roles;
|
||||||
|
|
||||||
var playTimes = _tracking.GetTrackerTimes(player);
|
var playTimes = _tracking.GetTrackerTimes(player);
|
||||||
@@ -197,7 +200,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
|
|||||||
|
|
||||||
public void RemoveDisallowedJobs(NetUserId userId, ref List<string> jobs)
|
public void RemoveDisallowedJobs(NetUserId userId, ref List<string> jobs)
|
||||||
{
|
{
|
||||||
if (!_cfg.GetCVar(CCVars.GameRoleTimers))
|
if (!_cfg.GetCVar(CCVars.GameRoleTimers) || (_allCaptainsRule != null && _allCaptainsRule.RuleStarted))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var player = _playerManager.GetSessionByUserId(userId);
|
var player = _playerManager.GetSessionByUserId(userId);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Server.Station.Systems;
|
using Content.Server.GameTicking.Rules;
|
||||||
|
using Content.Server.Station.Systems;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
|
||||||
@@ -9,7 +10,7 @@ namespace Content.Server.Station.Components;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stores information about a station's job selection.
|
/// Stores information about a station's job selection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent, Access(typeof(StationJobsSystem)), PublicAPI]
|
[RegisterComponent, Access(typeof(StationJobsSystem), typeof(AllCaptainsRuleSystem)), PublicAPI]
|
||||||
public sealed class StationJobsComponent : Component
|
public sealed class StationJobsComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
|
using Content.Server.GameTicking.Rules;
|
||||||
using Content.Server.Station.Components;
|
using Content.Server.Station.Components;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
@@ -25,6 +26,7 @@ public sealed partial class StationJobsSystem : EntitySystem
|
|||||||
[Dependency] private readonly GameTicker _gameTicker = default!;
|
[Dependency] private readonly GameTicker _gameTicker = default!;
|
||||||
[Dependency] private readonly StationSystem _stationSystem = default!;
|
[Dependency] private readonly StationSystem _stationSystem = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
[Dependency] private readonly AllCaptainsRuleSystem _allCaptainsRule = default!;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -33,6 +35,8 @@ public sealed partial class StationJobsSystem : EntitySystem
|
|||||||
SubscribeLocalEvent<StationJobsComponent, StationRenamedEvent>(OnStationRenamed);
|
SubscribeLocalEvent<StationJobsComponent, StationRenamedEvent>(OnStationRenamed);
|
||||||
SubscribeLocalEvent<StationJobsComponent, ComponentShutdown>(OnStationDeletion);
|
SubscribeLocalEvent<StationJobsComponent, ComponentShutdown>(OnStationDeletion);
|
||||||
SubscribeLocalEvent<PlayerJoinedLobbyEvent>(OnPlayerJoinedLobby);
|
SubscribeLocalEvent<PlayerJoinedLobbyEvent>(OnPlayerJoinedLobby);
|
||||||
|
SubscribeLocalEvent<GameRuleStartedEvent>(OnGameRuleStarted);
|
||||||
|
SubscribeLocalEvent<GameRuleEndedEvent>(OnGameRuleEnded);
|
||||||
_configurationManager.OnValueChanged(CCVars.GameDisallowLateJoins, _ => UpdateJobsAvailable(), true);
|
_configurationManager.OnValueChanged(CCVars.GameDisallowLateJoins, _ => UpdateJobsAvailable(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,6 +140,9 @@ public sealed partial class StationJobsSystem : EntitySystem
|
|||||||
|
|
||||||
var jobList = stationJobs.JobList;
|
var jobList = stationJobs.JobList;
|
||||||
|
|
||||||
|
if (_allCaptainsRule != null && _allCaptainsRule.RuleStarted)
|
||||||
|
jobList = _allCaptainsRule.GetJobs(station).JobList;
|
||||||
|
|
||||||
// This should:
|
// This should:
|
||||||
// - Return true when zero slots are added/removed.
|
// - Return true when zero slots are added/removed.
|
||||||
// - Return true when you add.
|
// - Return true when you add.
|
||||||
@@ -214,6 +221,11 @@ public sealed partial class StationJobsSystem : EntitySystem
|
|||||||
|
|
||||||
var jobList = stationJobs.JobList;
|
var jobList = stationJobs.JobList;
|
||||||
|
|
||||||
|
// If all captains mode, override job list with the allcaptains job list -- prevents modifying the "real" job list
|
||||||
|
// in case mode changes later.
|
||||||
|
if (_allCaptainsRule != null && _allCaptainsRule.RuleStarted)
|
||||||
|
jobList = _allCaptainsRule.GetJobs(station).JobList;
|
||||||
|
|
||||||
switch (jobList.ContainsKey(jobPrototypeId))
|
switch (jobList.ContainsKey(jobPrototypeId))
|
||||||
{
|
{
|
||||||
case false:
|
case false:
|
||||||
@@ -313,7 +325,11 @@ public sealed partial class StationJobsSystem : EntitySystem
|
|||||||
if (!Resolve(station, ref stationJobs))
|
if (!Resolve(station, ref stationJobs))
|
||||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||||
|
|
||||||
if (stationJobs.JobList.TryGetValue(jobPrototypeId, out var job))
|
var jobList = stationJobs.JobList;
|
||||||
|
if (_allCaptainsRule != null && _allCaptainsRule.RuleStarted)
|
||||||
|
jobList = _allCaptainsRule.GetJobs(station).JobList;
|
||||||
|
|
||||||
|
if (jobList.TryGetValue(jobPrototypeId, out var job))
|
||||||
{
|
{
|
||||||
slots = job;
|
slots = job;
|
||||||
return true;
|
return true;
|
||||||
@@ -337,6 +353,9 @@ public sealed partial class StationJobsSystem : EntitySystem
|
|||||||
if (!Resolve(station, ref stationJobs))
|
if (!Resolve(station, ref stationJobs))
|
||||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||||
|
|
||||||
|
if (_allCaptainsRule != null && _allCaptainsRule.RuleStarted)
|
||||||
|
return _allCaptainsRule.GetJobs(station).JobList.Where(x => x.Value != 0).Select(x => x.Key).ToHashSet();
|
||||||
|
|
||||||
return stationJobs.JobList.Where(x => x.Value != 0).Select(x => x.Key).ToHashSet();
|
return stationJobs.JobList.Where(x => x.Value != 0).Select(x => x.Key).ToHashSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,6 +371,9 @@ public sealed partial class StationJobsSystem : EntitySystem
|
|||||||
if (!Resolve(station, ref stationJobs))
|
if (!Resolve(station, ref stationJobs))
|
||||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||||
|
|
||||||
|
if (_allCaptainsRule != null && _allCaptainsRule.RuleStarted)
|
||||||
|
return _allCaptainsRule.GetJobs(station).OverflowJobs.ToHashSet();
|
||||||
|
|
||||||
return stationJobs.OverflowJobs.ToHashSet();
|
return stationJobs.OverflowJobs.ToHashSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,6 +389,9 @@ public sealed partial class StationJobsSystem : EntitySystem
|
|||||||
if (!Resolve(station, ref stationJobs))
|
if (!Resolve(station, ref stationJobs))
|
||||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||||
|
|
||||||
|
if (_allCaptainsRule != null && _allCaptainsRule.RuleStarted)
|
||||||
|
return _allCaptainsRule.GetJobs(station).JobList;
|
||||||
|
|
||||||
return stationJobs.JobList;
|
return stationJobs.JobList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,6 +407,9 @@ public sealed partial class StationJobsSystem : EntitySystem
|
|||||||
if (!Resolve(station, ref stationJobs))
|
if (!Resolve(station, ref stationJobs))
|
||||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||||
|
|
||||||
|
if (_allCaptainsRule != null && _allCaptainsRule.RuleStarted)
|
||||||
|
return _allCaptainsRule.GetJobs(station).RoundStartJobList;
|
||||||
|
|
||||||
return stationJobs.RoundStartJobList;
|
return stationJobs.RoundStartJobList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,6 +495,8 @@ public sealed partial class StationJobsSystem : EntitySystem
|
|||||||
foreach (var station in _stationSystem.Stations)
|
foreach (var station in _stationSystem.Stations)
|
||||||
{
|
{
|
||||||
var list = Comp<StationJobsComponent>(station).JobList.ToDictionary(x => x.Key, x => x.Value);
|
var list = Comp<StationJobsComponent>(station).JobList.ToDictionary(x => x.Key, x => x.Value);
|
||||||
|
if (_allCaptainsRule != null && _allCaptainsRule.RuleStarted)
|
||||||
|
list = _allCaptainsRule.GetJobs(station).JobList.ToDictionary(x => x.Key, x => x.Value);
|
||||||
jobs.Add(station, list);
|
jobs.Add(station, list);
|
||||||
stationNames.Add(station, Name(station));
|
stationNames.Add(station, Name(station));
|
||||||
}
|
}
|
||||||
@@ -491,5 +521,17 @@ public sealed partial class StationJobsSystem : EntitySystem
|
|||||||
UpdateJobsAvailable();
|
UpdateJobsAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnGameRuleStarted(GameRuleStartedEvent msg)
|
||||||
|
{
|
||||||
|
if (msg.Rule.ID == "AllCaptains")
|
||||||
|
UpdateJobsAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGameRuleEnded(GameRuleEndedEvent msg)
|
||||||
|
{
|
||||||
|
if (msg.Rule.ID == "AllCaptains")
|
||||||
|
UpdateJobsAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
- type: gameRule
|
||||||
|
id: AllCaptains
|
||||||
|
config:
|
||||||
|
!type:GenericGameRuleConfiguration
|
||||||
|
id: AllCaptains
|
||||||
|
|
||||||
- type: gameRule
|
- type: gameRule
|
||||||
id: DeathMatch
|
id: DeathMatch
|
||||||
config:
|
config:
|
||||||
|
|||||||
@@ -119,3 +119,23 @@
|
|||||||
rules:
|
rules:
|
||||||
- Pirates
|
- Pirates
|
||||||
- BasicStationEventScheduler
|
- BasicStationEventScheduler
|
||||||
|
|
||||||
|
- type: gamePreset
|
||||||
|
id: OopsAllCaptains
|
||||||
|
alias:
|
||||||
|
- captains
|
||||||
|
- captain
|
||||||
|
- onlycaptains
|
||||||
|
- OnlyCaptains
|
||||||
|
- oopsonlycaptains
|
||||||
|
- oopsallcaptains
|
||||||
|
- allcaptains
|
||||||
|
- AllCaptains
|
||||||
|
name: "Oops! All Captains."
|
||||||
|
description: "Look at you. You're the captain now."
|
||||||
|
showInVote: true
|
||||||
|
rules:
|
||||||
|
- AllCaptains
|
||||||
|
- Traitor
|
||||||
|
- BasicStationEventScheduler
|
||||||
|
|
||||||
|
|||||||
@@ -5,3 +5,4 @@
|
|||||||
Nukeops: 0.25
|
Nukeops: 0.25
|
||||||
Traitor: 0.75
|
Traitor: 0.75
|
||||||
Zombie: 0.05
|
Zombie: 0.05
|
||||||
|
OopsAllCaptains: 0.20
|
||||||
|
|||||||
Reference in New Issue
Block a user