--- /dev/null
+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);
+ }
+
+}
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
[Dependency] private readonly UplinkSystem _uplink = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
+ [Dependency] private readonly AllCaptainsRuleSystem _allCaptainsRule = default!;
private ISawmill _sawmill = default!;
foreach (var player in candidates.Keys)
{
// 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;
}
if (ev.JobId == null || !_prototypeManager.TryIndex<JobPrototype>(ev.JobId, out var job))
return;
- if (!job.CanBeAntag)
+ if (!job.CanBeAntag &&
+ !(_allCaptainsRule != null && _allCaptainsRule.RuleStarted)) // all captains mode lets some of the captains be traitors :3
return;
// Before the announcement is made, late-joiners are considered the same as players who readied.
using Content.Server.Afk;
using Content.Server.Afk.Events;
using Content.Server.GameTicking;
+using Content.Server.GameTicking.Rules;
using Content.Server.Roles;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
[Dependency] private readonly IPrototypeManager _prototypes = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly PlayTimeTrackingManager _tracking = default!;
+ [Dependency] private readonly AllCaptainsRuleSystem _allCaptainsRule = default!;
public override void Initialize()
{
{
if (!_prototypes.TryIndex<JobPrototype>(role, out var job) ||
job.Requirements == null ||
- !_cfg.GetCVar(CCVars.GameRoleTimers))
+ !_cfg.GetCVar(CCVars.GameRoleTimers) ||
+ (_allCaptainsRule != null && _allCaptainsRule.RuleStarted))
return true;
var playTimes = _tracking.GetTrackerTimes(player);
public HashSet<string> GetDisallowedJobs(IPlayerSession player)
{
var roles = new HashSet<string>();
- if (!_cfg.GetCVar(CCVars.GameRoleTimers))
+ if (!_cfg.GetCVar(CCVars.GameRoleTimers) || (_allCaptainsRule != null && _allCaptainsRule.RuleStarted))
return roles;
var playTimes = _tracking.GetTrackerTimes(player);
public void RemoveDisallowedJobs(NetUserId userId, ref List<string> jobs)
{
- if (!_cfg.GetCVar(CCVars.GameRoleTimers))
+ if (!_cfg.GetCVar(CCVars.GameRoleTimers) || (_allCaptainsRule != null && _allCaptainsRule.RuleStarted))
return;
var player = _playerManager.GetSessionByUserId(userId);
-using Content.Server.Station.Systems;
+using Content.Server.GameTicking.Rules;
+using Content.Server.Station.Systems;
using Content.Shared.Roles;
using JetBrains.Annotations;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
/// <summary>
/// Stores information about a station's job selection.
/// </summary>
-[RegisterComponent, Access(typeof(StationJobsSystem)), PublicAPI]
+[RegisterComponent, Access(typeof(StationJobsSystem), typeof(AllCaptainsRuleSystem)), PublicAPI]
public sealed class StationJobsComponent : Component
{
/// <summary>
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.GameTicking;
+using Content.Server.GameTicking.Rules;
using Content.Server.Station.Components;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
[Dependency] private readonly GameTicker _gameTicker = default!;
[Dependency] private readonly StationSystem _stationSystem = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
+ [Dependency] private readonly AllCaptainsRuleSystem _allCaptainsRule = default!;
/// <inheritdoc/>
public override void Initialize()
SubscribeLocalEvent<StationJobsComponent, StationRenamedEvent>(OnStationRenamed);
SubscribeLocalEvent<StationJobsComponent, ComponentShutdown>(OnStationDeletion);
SubscribeLocalEvent<PlayerJoinedLobbyEvent>(OnPlayerJoinedLobby);
+ SubscribeLocalEvent<GameRuleStartedEvent>(OnGameRuleStarted);
+ SubscribeLocalEvent<GameRuleEndedEvent>(OnGameRuleEnded);
_configurationManager.OnValueChanged(CCVars.GameDisallowLateJoins, _ => UpdateJobsAvailable(), true);
}
var jobList = stationJobs.JobList;
+ if (_allCaptainsRule != null && _allCaptainsRule.RuleStarted)
+ jobList = _allCaptainsRule.GetJobs(station).JobList;
+
// This should:
// - Return true when zero slots are added/removed.
// - Return true when you add.
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))
{
case false:
if (!Resolve(station, ref stationJobs))
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;
return true;
if (!Resolve(station, ref stationJobs))
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();
}
if (!Resolve(station, ref stationJobs))
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();
}
if (!Resolve(station, ref stationJobs))
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;
}
if (!Resolve(station, ref stationJobs))
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;
}
foreach (var station in _stationSystem.Stations)
{
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);
stationNames.Add(station, Name(station));
}
UpdateJobsAvailable();
}
+ private void OnGameRuleStarted(GameRuleStartedEvent msg)
+ {
+ if (msg.Rule.ID == "AllCaptains")
+ UpdateJobsAvailable();
+ }
+
+ private void OnGameRuleEnded(GameRuleEndedEvent msg)
+ {
+ if (msg.Rule.ID == "AllCaptains")
+ UpdateJobsAvailable();
+ }
+
#endregion
}
+- type: gameRule
+ id: AllCaptains
+ config:
+ !type:GenericGameRuleConfiguration
+ id: AllCaptains
+
- type: gameRule
id: DeathMatch
config:
rules:
- Pirates
- 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
+
Nukeops: 0.25
Traitor: 0.75
Zombie: 0.05
+ OopsAllCaptains: 0.20