Files
crystall-punk-14/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs

372 lines
15 KiB
C#
Raw Normal View History

2021-12-21 21:23:29 +01:00
using System.Linq;
New Thief minor antagonist (#21520) * start working * add right-click thief antagins some architecture restruct * add meh thief greeting audio * add thief subgamemode to Traitors gamemode * add late join thief (not tested yet) add briefing * add pacifism * add Steal tasks to thief * fix crash thief+traitor on person * add new condition: collection steal * add tracking of succes collection objective * add stamp collection target remove some boring steal target add check pulling entity to collection target * finalize first 2 group objective * start merging stealing objective systems * merging * finish merging. Now traitor steal objective work better * we don't check the items of pullable sentient entity * clear naming, enable thief signle item objective start * objective pack add * finish with steal item objectives * convert string to ProtoId<> * some clean up * add thieves to revolution game mode * Update Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com> * Update Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com> * update pacifism: fix crashing, monkey-thief without pacified * adaptive animal briefing, cleaning locales * add structure steal objectives * remove RCD target * add thiefs to manifest, but bug with traitor duplications * add escape objective * add chat briefing * setup animal objective group system * add animal steal objectives * add animal objectives notroleconditions * add morty * now thief mode has a chance of not launching Now there are a random number of thieves per round from 1 to 3 * 6 hours of trying to fix duplicate tasks. Failure * added thief pinpointer (buggy) * start thief backpack UI work * revert pinpointer for scope reason * UI continue work * add thief starter kits content * remove ERP kit :trollface: * finally! giving starting items to thief. Now it playable, but still need more work * clean up * fix * fox * add merged items into thief new Starting Kit (buggy) * fix YES antag menu * objection tweaks * remove hearts objective, working on spawning things from toolbox * smug * fixes * add race specifier objective condition LAMPS * meh * fix fix fix * the alive * Adding stamps * Update backpack.ftl * Revert1 * Revert ftl * add voice mask to communicator kit * Update Resources/Locale/en-US/administration/antag.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/objectives/conditions/steal.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/prototypes/roles/antags.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * update * fix * more reusable function, add documentation * fix doc * faint fixes --------- Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com> Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
2023-12-24 12:58:28 +03:00
using Content.Server.Antag;
2021-12-21 21:23:29 +01:00
using Content.Server.Chat.Managers;
2023-04-25 20:23:14 -04:00
using Content.Server.GameTicking.Rules.Components;
2023-06-18 11:33:19 -07:00
using Content.Server.Mind;
using Content.Server.NPC.Systems;
using Content.Server.Objectives;
using Content.Server.PDA.Ringer;
2021-12-21 21:23:29 +01:00
using Content.Server.Roles;
using Content.Server.Shuttles.Components;
2021-12-21 21:23:29 +01:00
using Content.Server.Traitor.Uplink;
using Content.Shared.CCVar;
using Content.Shared.Dataset;
using Content.Shared.Mind;
using Content.Shared.Mobs.Systems;
using Content.Shared.Objectives.Components;
using Content.Shared.PDA;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Content.Shared.Roles.Jobs;
using Robust.Server.Player;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
2021-12-21 21:23:29 +01:00
using Robust.Shared.Configuration;
using Robust.Shared.Player;
2021-12-21 21:23:29 +01:00
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
2021-12-21 21:23:29 +01:00
namespace Content.Server.GameTicking.Rules;
2023-04-25 20:23:14 -04:00
public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
2021-12-21 21:23:29 +01:00
{
New Thief minor antagonist (#21520) * start working * add right-click thief antagins some architecture restruct * add meh thief greeting audio * add thief subgamemode to Traitors gamemode * add late join thief (not tested yet) add briefing * add pacifism * add Steal tasks to thief * fix crash thief+traitor on person * add new condition: collection steal * add tracking of succes collection objective * add stamp collection target remove some boring steal target add check pulling entity to collection target * finalize first 2 group objective * start merging stealing objective systems * merging * finish merging. Now traitor steal objective work better * we don't check the items of pullable sentient entity * clear naming, enable thief signle item objective start * objective pack add * finish with steal item objectives * convert string to ProtoId<> * some clean up * add thieves to revolution game mode * Update Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com> * Update Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com> * update pacifism: fix crashing, monkey-thief without pacified * adaptive animal briefing, cleaning locales * add structure steal objectives * remove RCD target * add thiefs to manifest, but bug with traitor duplications * add escape objective * add chat briefing * setup animal objective group system * add animal steal objectives * add animal objectives notroleconditions * add morty * now thief mode has a chance of not launching Now there are a random number of thieves per round from 1 to 3 * 6 hours of trying to fix duplicate tasks. Failure * added thief pinpointer (buggy) * start thief backpack UI work * revert pinpointer for scope reason * UI continue work * add thief starter kits content * remove ERP kit :trollface: * finally! giving starting items to thief. Now it playable, but still need more work * clean up * fix * fox * add merged items into thief new Starting Kit (buggy) * fix YES antag menu * objection tweaks * remove hearts objective, working on spawning things from toolbox * smug * fixes * add race specifier objective condition LAMPS * meh * fix fix fix * the alive * Adding stamps * Update backpack.ftl * Revert1 * Revert ftl * add voice mask to communicator kit * Update Resources/Locale/en-US/administration/antag.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/objectives/conditions/steal.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/prototypes/roles/antags.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * update * fix * more reusable function, add documentation * fix doc * faint fixes --------- Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com> Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
2023-12-24 12:58:28 +03:00
[Dependency] private readonly AntagSelectionSystem _antagSelection = default!;
2021-12-21 21:23:29 +01:00
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
2023-07-17 15:51:52 +12:00
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
2022-08-17 00:34:25 -04:00
[Dependency] private readonly UplinkSystem _uplink = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
2023-06-18 11:33:19 -07:00
[Dependency] private readonly MindSystem _mindSystem = default!;
[Dependency] private readonly SharedRoleSystem _roleSystem = default!;
[Dependency] private readonly SharedJobSystem _jobs = default!;
[Dependency] private readonly ObjectivesSystem _objectives = default!;
2023-04-25 20:23:14 -04:00
private int PlayersPerTraitor => _cfg.GetCVar(CCVars.TraitorPlayersPerTraitor);
private int MaxTraitors => _cfg.GetCVar(CCVars.TraitorMaxTraitors);
2021-12-21 21:23:29 +01:00
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RoundStartAttemptEvent>(OnStartAttempt);
SubscribeLocalEvent<RulePlayerJobsAssignedEvent>(OnPlayersSpawned);
2022-07-28 20:59:45 -04:00
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(HandleLatejoin);
SubscribeLocalEvent<TraitorRuleComponent, ObjectivesTextGetInfoEvent>(OnObjectivesTextGetInfo);
SubscribeLocalEvent<TraitorRuleComponent, ObjectivesTextPrependEvent>(OnObjectivesTextPrepend);
2021-12-21 21:23:29 +01:00
}
2023-04-25 20:23:14 -04:00
protected override void ActiveTick(EntityUid uid, TraitorRuleComponent component, GameRuleComponent gameRule, float frameTime)
{
2023-04-25 20:23:14 -04:00
base.ActiveTick(uid, component, gameRule, frameTime);
2021-12-21 21:23:29 +01:00
2023-04-25 20:23:14 -04:00
if (component.SelectionStatus == TraitorRuleComponent.SelectionState.ReadyToSelect && _gameTiming.CurTime > component.AnnounceAt)
DoTraitorStart(component);
2023-04-24 16:21:05 +10:00
}
2021-12-21 21:23:29 +01:00
2023-04-24 16:21:05 +10:00
private void OnStartAttempt(RoundStartAttemptEvent ev)
{
2023-04-25 20:23:14 -04:00
var query = EntityQueryEnumerator<TraitorRuleComponent, GameRuleComponent>();
while (query.MoveNext(out var uid, out var traitor, out var gameRule))
2023-04-24 16:21:05 +10:00
{
2023-04-25 20:23:14 -04:00
if (!GameTicker.IsGameRuleAdded(uid, gameRule))
continue;
2023-04-24 01:20:51 -04:00
2023-04-25 20:23:14 -04:00
MakeCodewords(traitor);
var minPlayers = _cfg.GetCVar(CCVars.TraitorMinPlayers);
if (!ev.Forced && ev.Players.Length < minPlayers)
{
_chatManager.SendAdminAnnouncement(Loc.GetString("traitor-not-enough-ready-players",
2023-04-25 20:23:14 -04:00
("readyPlayersCount", ev.Players.Length), ("minimumPlayers", minPlayers)));
ev.Cancel();
continue;
}
if (ev.Players.Length == 0)
{
_chatManager.DispatchServerAnnouncement(Loc.GetString("traitor-no-one-ready"));
ev.Cancel();
}
2021-12-21 21:23:29 +01:00
}
}
2023-04-25 20:23:14 -04:00
private void MakeCodewords(TraitorRuleComponent component)
{
var codewordCount = _cfg.GetCVar(CCVars.TraitorCodewordCount);
var adjectives = _prototypeManager.Index<DatasetPrototype>("adjectives").Values;
var verbs = _prototypeManager.Index<DatasetPrototype>("verbs").Values;
var codewordPool = adjectives.Concat(verbs).ToList();
var finalCodewordCount = Math.Min(codewordCount, codewordPool.Count);
2023-04-25 20:23:14 -04:00
component.Codewords = new string[finalCodewordCount];
for (var i = 0; i < finalCodewordCount; i++)
{
2023-04-25 20:23:14 -04:00
component.Codewords[i] = _random.PickAndTake(codewordPool);
}
}
2023-04-25 20:23:14 -04:00
private void DoTraitorStart(TraitorRuleComponent component)
2021-12-21 21:23:29 +01:00
{
2023-04-25 20:23:14 -04:00
if (!component.StartCandidates.Any())
{
Log.Error("Tried to start Traitor mode without any candidates.");
2021-12-21 21:23:29 +01:00
return;
}
2021-12-21 21:23:29 +01:00
2023-04-25 20:23:14 -04:00
var numTraitors = MathHelper.Clamp(component.StartCandidates.Count / PlayersPerTraitor, 1, MaxTraitors);
New Thief minor antagonist (#21520) * start working * add right-click thief antagins some architecture restruct * add meh thief greeting audio * add thief subgamemode to Traitors gamemode * add late join thief (not tested yet) add briefing * add pacifism * add Steal tasks to thief * fix crash thief+traitor on person * add new condition: collection steal * add tracking of succes collection objective * add stamp collection target remove some boring steal target add check pulling entity to collection target * finalize first 2 group objective * start merging stealing objective systems * merging * finish merging. Now traitor steal objective work better * we don't check the items of pullable sentient entity * clear naming, enable thief signle item objective start * objective pack add * finish with steal item objectives * convert string to ProtoId<> * some clean up * add thieves to revolution game mode * Update Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com> * Update Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com> * update pacifism: fix crashing, monkey-thief without pacified * adaptive animal briefing, cleaning locales * add structure steal objectives * remove RCD target * add thiefs to manifest, but bug with traitor duplications * add escape objective * add chat briefing * setup animal objective group system * add animal steal objectives * add animal objectives notroleconditions * add morty * now thief mode has a chance of not launching Now there are a random number of thieves per round from 1 to 3 * 6 hours of trying to fix duplicate tasks. Failure * added thief pinpointer (buggy) * start thief backpack UI work * revert pinpointer for scope reason * UI continue work * add thief starter kits content * remove ERP kit :trollface: * finally! giving starting items to thief. Now it playable, but still need more work * clean up * fix * fox * add merged items into thief new Starting Kit (buggy) * fix YES antag menu * objection tweaks * remove hearts objective, working on spawning things from toolbox * smug * fixes * add race specifier objective condition LAMPS * meh * fix fix fix * the alive * Adding stamps * Update backpack.ftl * Revert1 * Revert ftl * add voice mask to communicator kit * Update Resources/Locale/en-US/administration/antag.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/game-ticking/game-presets/preset-thief.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/objectives/conditions/steal.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/prototypes/roles/antags.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * Update Resources/Locale/en-US/thief/backpack.ftl Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> * update * fix * more reusable function, add documentation * fix doc * faint fixes --------- Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com> Co-authored-by: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com>
2023-12-24 12:58:28 +03:00
var traitorPool = _antagSelection.FindPotentialAntags(component.StartCandidates, component.TraitorPrototypeId);
var selectedTraitors = _antagSelection.PickAntag(numTraitors, traitorPool);
foreach (var traitor in selectedTraitors)
2023-04-25 20:23:14 -04:00
{
MakeTraitor(traitor);
2023-04-25 20:23:14 -04:00
}
2023-04-25 20:23:14 -04:00
component.SelectionStatus = TraitorRuleComponent.SelectionState.SelectionMade;
}
private void OnPlayersSpawned(RulePlayerJobsAssignedEvent ev)
{
2023-04-25 20:23:14 -04:00
var query = EntityQueryEnumerator<TraitorRuleComponent, GameRuleComponent>();
while (query.MoveNext(out var uid, out var traitor, out var gameRule))
{
2023-04-25 20:23:14 -04:00
if (!GameTicker.IsGameRuleAdded(uid, gameRule))
continue;
2023-04-25 20:23:14 -04:00
foreach (var player in ev.Players)
{
if (!ev.Profiles.ContainsKey(player.UserId))
continue;
2023-04-25 20:23:14 -04:00
traitor.StartCandidates[player] = ev.Profiles[player.UserId];
}
2023-04-25 20:23:14 -04:00
var delay = TimeSpan.FromSeconds(
_cfg.GetCVar(CCVars.TraitorStartDelay) +
_random.NextFloat(0f, _cfg.GetCVar(CCVars.TraitorStartDelayVariance)));
2023-04-25 20:23:14 -04:00
traitor.AnnounceAt = _gameTiming.CurTime + delay;
2023-04-25 20:23:14 -04:00
traitor.SelectionStatus = TraitorRuleComponent.SelectionState.ReadyToSelect;
}
}
2021-12-21 21:23:29 +01:00
public bool MakeTraitor(ICommonSession traitor, bool giveUplink = true, bool giveObjectives = true)
{
2023-04-25 20:23:14 -04:00
var traitorRule = EntityQuery<TraitorRuleComponent>().FirstOrDefault();
if (traitorRule == null)
{
//todo fuck me this shit is awful
//no i wont fuck you, erp is against rules
GameTicker.StartGameRule("Traitor", out var ruleEntity);
traitorRule = Comp<TraitorRuleComponent>(ruleEntity);
MakeCodewords(traitorRule);
2023-04-25 20:23:14 -04:00
}
if (!_mindSystem.TryGetMind(traitor, out var mindId, out var mind))
2021-12-21 21:23:29 +01:00
{
Log.Info("Failed getting mind for picked traitor.");
return false;
}
if (HasComp<TraitorRoleComponent>(mindId))
{
Log.Error($"Player {traitor.Name} is already a traitor.");
return false;
}
if (mind.OwnedEntity is not { } entity)
{
Log.Error("Mind picked for traitor did not have an attached entity.");
return false;
}
// Calculate the amount of currency on the uplink.
var startingBalance = _cfg.GetCVar(CCVars.TraitorStartingBalance);
if (_jobs.MindTryGetJob(mindId, out _, out var prototype))
startingBalance = Math.Max(startingBalance - prototype.AntagAdvantage, 0);
// Give traitors their codewords and uplink code to keep in their character info menu
var briefing = Loc.GetString("traitor-role-codewords-short", ("codewords", string.Join(", ", traitorRule.Codewords)));
Note[]? code = null;
if (giveUplink)
{
// creadth: we need to create uplink for the antag.
// PDA should be in place already
var pda = _uplink.FindUplinkTarget(mind.OwnedEntity!.Value);
if (pda == null || !_uplink.AddUplink(mind.OwnedEntity.Value, startingBalance))
return false;
// Give traitors their codewords and uplink code to keep in their character info menu
code = EnsureComp<RingerUplinkComponent>(pda.Value).Code;
// If giveUplink is false the uplink code part is omitted
briefing = string.Format("{0}\n{1}", briefing,
Loc.GetString("traitor-role-uplink-code-short", ("code", string.Join("-", code).Replace("sharp","#"))));
}
2023-04-25 20:23:14 -04:00
// Prepare traitor role
var traitorRole = new TraitorRoleComponent
{
PrototypeId = traitorRule.TraitorPrototypeId,
};
// Assign traitor roles
_roleSystem.MindAddRole(mindId, new TraitorRoleComponent
{
PrototypeId = traitorRule.TraitorPrototypeId
}, mind);
// Assign briefing and greeting sound
_roleSystem.MindAddRole(mindId, new RoleBriefingComponent
{
Briefing = briefing
}, mind);
_roleSystem.MindPlaySound(mindId, traitorRule.GreetSoundNotification, mind);
SendTraitorBriefing(mindId, traitorRule.Codewords, code);
traitorRule.TraitorMinds.Add(mindId);
2021-12-21 21:23:29 +01:00
// Change the faction
2023-07-17 15:51:52 +12:00
_npcFaction.RemoveFaction(entity, "NanoTrasen", false);
_npcFaction.AddFaction(entity, "Syndicate");
// Give traitors their objectives
if (giveObjectives)
2021-12-21 21:23:29 +01:00
{
var maxDifficulty = _cfg.GetCVar(CCVars.TraitorMaxDifficulty);
var maxPicks = _cfg.GetCVar(CCVars.TraitorMaxPicks);
var difficulty = 0f;
for (var pick = 0; pick < maxPicks && maxDifficulty > difficulty; pick++)
{
var objective = _objectives.GetRandomObjective(mindId, mind, "TraitorObjectiveGroups");
if (objective == null)
continue;
2023-06-18 11:33:19 -07:00
_mindSystem.AddObjective(mindId, mind, objective.Value);
difficulty += Comp<ObjectiveComponent>(objective.Value).Difficulty;
}
2021-12-21 21:23:29 +01:00
}
return true;
2021-12-21 21:23:29 +01:00
}
/// <summary>
/// Send a codewords and uplink codes to traitor chat.
/// </summary>
/// <param name="mind">A mind (player)</param>
/// <param name="codewords">Codewords</param>
/// <param name="code">Uplink codes</param>
private void SendTraitorBriefing(EntityUid mind, string[] codewords, Note[]? code)
{
if (!_mindSystem.TryGetSession(mind, out var session))
return;
_chatManager.DispatchServerMessage(session, Loc.GetString("traitor-role-greeting"));
_chatManager.DispatchServerMessage(session, Loc.GetString("traitor-role-codewords", ("codewords", string.Join(", ", codewords))));
if (code != null)
_chatManager.DispatchServerMessage(session, Loc.GetString("traitor-role-uplink-code", ("code", string.Join("-", code).Replace("sharp","#"))));
}
2022-07-28 20:59:45 -04:00
private void HandleLatejoin(PlayerSpawnCompleteEvent ev)
{
2023-04-25 20:23:14 -04:00
var query = EntityQueryEnumerator<TraitorRuleComponent, GameRuleComponent>();
while (query.MoveNext(out var uid, out var traitor, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(uid, gameRule))
continue;
2022-07-28 20:59:45 -04:00
2023-04-25 20:23:14 -04:00
if (traitor.TotalTraitors >= MaxTraitors)
continue;
if (!ev.LateJoin)
continue;
if (!ev.Profile.AntagPreferences.Contains(traitor.TraitorPrototypeId))
continue;
2022-07-28 20:59:45 -04:00
2023-04-25 20:23:14 -04:00
if (ev.JobId == null || !_prototypeManager.TryIndex<JobPrototype>(ev.JobId, out var job))
continue;
2022-07-28 20:59:45 -04:00
2023-04-25 20:23:14 -04:00
if (!job.CanBeAntag)
continue;
2023-04-25 20:23:14 -04:00
// Before the announcement is made, late-joiners are considered the same as players who readied.
if (traitor.SelectionStatus < TraitorRuleComponent.SelectionState.SelectionMade)
{
traitor.StartCandidates[ev.Player] = ev.Profile;
continue;
}
2022-07-28 20:59:45 -04:00
2023-04-25 20:23:14 -04:00
// the nth player we adjust our probabilities around
var target = PlayersPerTraitor * traitor.TotalTraitors + 1;
2022-07-28 20:59:45 -04:00
2023-04-25 20:23:14 -04:00
var chance = 1f / PlayersPerTraitor;
2022-07-28 20:59:45 -04:00
2023-04-25 20:23:14 -04:00
// 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);
}
2023-04-24 01:20:51 -04:00
2023-04-25 20:23:14 -04:00
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(chance))
{
MakeTraitor(ev.Player);
}
2022-07-28 20:59:45 -04:00
}
}
private void OnObjectivesTextGetInfo(EntityUid uid, TraitorRuleComponent comp, ref ObjectivesTextGetInfoEvent args)
2021-12-21 21:23:29 +01:00
{
args.Minds = comp.TraitorMinds;
args.AgentName = Loc.GetString("traitor-round-end-agent-name");
}
2023-04-25 20:23:14 -04:00
private void OnObjectivesTextPrepend(EntityUid uid, TraitorRuleComponent comp, ref ObjectivesTextPrependEvent args)
{
args.Text += "\n" + Loc.GetString("traitor-round-end-codewords", ("codewords", string.Join(", ", comp.Codewords)));
2021-12-21 21:23:29 +01:00
}
public List<(EntityUid Id, MindComponent Mind)> GetOtherTraitorMindsAliveAndConnected(MindComponent ourMind)
{
List<(EntityUid Id, MindComponent Mind)> allTraitors = new();
2023-04-25 20:23:14 -04:00
foreach (var traitor in EntityQuery<TraitorRuleComponent>())
{
foreach (var role in GetOtherTraitorMindsAliveAndConnected(ourMind, traitor))
2023-04-25 20:23:14 -04:00
{
if (!allTraitors.Contains(role))
allTraitors.Add(role);
}
}
2023-04-25 20:23:14 -04:00
return allTraitors;
}
private List<(EntityUid Id, MindComponent Mind)> GetOtherTraitorMindsAliveAndConnected(MindComponent ourMind, TraitorRuleComponent component)
2023-04-25 20:23:14 -04:00
{
var traitors = new List<(EntityUid Id, MindComponent Mind)>();
foreach (var traitor in component.TraitorMinds)
{
if (TryComp(traitor, out MindComponent? mind) &&
mind.OwnedEntity != null &&
mind.Session != null &&
mind != ourMind &&
_mobStateSystem.IsAlive(mind.OwnedEntity.Value) &&
mind.CurrentEntity == mind.OwnedEntity)
{
traitors.Add((traitor, mind));
}
}
return traitors;
}
2021-12-21 21:23:29 +01:00
}