Refactoring of roles and notifications about antagonist assignment (#16864)
* Refactoring of antagonist roles and notifications about antagonist role assignment. Refactoring of traitor assignment methods and bug fixing. * Announcement files moved, code is adjusted to new revision * Play to entity changed to play to global cause of mono audio restrictions. * Path to audio files changed to sound specifiers, unique alerts for each role. * Uncommited changes * New alert sounds for each antag role. * PR review fixes * Antagonist role assignment sound notifications moved to Systems, sounds moved to Components. * License update * Fixed naming and redundant parameters --------- Co-authored-by: Титов Вячеслав Витальевич <rincew1nd@yandex.ru>
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
using Robust.Shared.Audio;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Rules.Components;
|
namespace Content.Server.GameTicking.Rules.Components;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -6,5 +8,9 @@ namespace Content.Server.GameTicking.Rules.Components;
|
|||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed class NukeOperativeComponent : Component
|
public sealed class NukeOperativeComponent : Component
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Path to antagonist alert sound.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("greetSoundNotification")]
|
||||||
|
public SoundSpecifier GreetSoundNotification = new SoundPathSpecifier("/Audio/Ambience/Antag/nukeops_start.ogg");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,9 +79,6 @@ public sealed class NukeopsRuleComponent : Component
|
|||||||
[DataField("shuttleMap", customTypeSerializer: typeof(ResPathSerializer))]
|
[DataField("shuttleMap", customTypeSerializer: typeof(ResPathSerializer))]
|
||||||
public ResPath NukieShuttleMap = new("/Maps/infiltrator.yml");
|
public ResPath NukieShuttleMap = new("/Maps/infiltrator.yml");
|
||||||
|
|
||||||
[DataField("greetingSound", customTypeSerializer: typeof(SoundSpecifierTypeSerializer))]
|
|
||||||
public SoundSpecifier? GreetSound = new SoundPathSpecifier("/Audio/Misc/nukeops.ogg");
|
|
||||||
|
|
||||||
[DataField("winType")]
|
[DataField("winType")]
|
||||||
public WinType WinType = WinType.Neutral;
|
public WinType WinType = WinType.Neutral;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace Content.Server.GameTicking.Rules.Components;
|
using Robust.Shared.Audio;
|
||||||
|
|
||||||
|
namespace Content.Server.GameTicking.Rules.Components;
|
||||||
|
|
||||||
[RegisterComponent, Access(typeof(PiratesRuleSystem))]
|
[RegisterComponent, Access(typeof(PiratesRuleSystem))]
|
||||||
public sealed class PiratesRuleComponent : Component
|
public sealed class PiratesRuleComponent : Component
|
||||||
@@ -12,4 +14,11 @@ public sealed class PiratesRuleComponent : Component
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public double InitialShipValue;
|
public double InitialShipValue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Path to antagonist alert sound.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("pirateAlertSound")]
|
||||||
|
public readonly SoundSpecifier PirateAlertSound = new SoundPathSpecifier(
|
||||||
|
"/Audio/Ambience/Antag/pirate_start.ogg",
|
||||||
|
AudioParams.Default.WithVolume(4));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Server.Traitor;
|
using Content.Server.Roles;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
@@ -10,7 +10,6 @@ namespace Content.Server.GameTicking.Rules.Components;
|
|||||||
[RegisterComponent, Access(typeof(TraitorRuleSystem))]
|
[RegisterComponent, Access(typeof(TraitorRuleSystem))]
|
||||||
public sealed class TraitorRuleComponent : Component
|
public sealed class TraitorRuleComponent : Component
|
||||||
{
|
{
|
||||||
public readonly SoundSpecifier AddedSound = new SoundPathSpecifier("/Audio/Misc/tatoralert.ogg");
|
|
||||||
public List<TraitorRole> Traitors = new();
|
public List<TraitorRole> Traitors = new();
|
||||||
|
|
||||||
[DataField("traitorPrototypeId", customTypeSerializer: typeof(PrototypeIdSerializer<AntagPrototype>))]
|
[DataField("traitorPrototypeId", customTypeSerializer: typeof(PrototypeIdSerializer<AntagPrototype>))]
|
||||||
@@ -29,4 +28,10 @@ public sealed class TraitorRuleComponent : Component
|
|||||||
public SelectionState SelectionStatus = SelectionState.WaitingForSpawn;
|
public SelectionState SelectionStatus = SelectionState.WaitingForSpawn;
|
||||||
public TimeSpan AnnounceAt = TimeSpan.Zero;
|
public TimeSpan AnnounceAt = TimeSpan.Zero;
|
||||||
public Dictionary<IPlayerSession, HumanoidCharacterProfile> StartCandidates = new();
|
public Dictionary<IPlayerSession, HumanoidCharacterProfile> StartCandidates = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Path to antagonist alert sound.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("greetSoundNotification")]
|
||||||
|
public SoundSpecifier GreetSoundNotification = new SoundPathSpecifier("/Audio/Ambience/Antag/traitor_start.ogg");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Content.Server.NPC.Components;
|
|||||||
using Content.Server.NPC.Systems;
|
using Content.Server.NPC.Systems;
|
||||||
using Content.Server.Nuke;
|
using Content.Server.Nuke;
|
||||||
using Content.Server.Preferences.Managers;
|
using Content.Server.Preferences.Managers;
|
||||||
|
using Content.Server.Roles;
|
||||||
using Content.Server.RoundEnd;
|
using Content.Server.RoundEnd;
|
||||||
using Content.Server.Shuttles.Components;
|
using Content.Server.Shuttles.Components;
|
||||||
using Content.Server.Shuttles.Systems;
|
using Content.Server.Shuttles.Systems;
|
||||||
@@ -194,8 +195,6 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
|||||||
_chatManager.DispatchServerMessage(actor.PlayerSession, Loc.GetString("nukeops-welcome", ("station", component.TargetStation.Value)));
|
_chatManager.DispatchServerMessage(actor.PlayerSession, Loc.GetString("nukeops-welcome", ("station", component.TargetStation.Value)));
|
||||||
filter.AddPlayer(actor.PlayerSession);
|
filter.AddPlayer(actor.PlayerSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
_audioSystem.PlayGlobal(component.GreetSound, filter, recordReplay: false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRoundEnd(EntityUid uid, NukeopsRuleComponent? component = null)
|
private void OnRoundEnd(EntityUid uid, NukeopsRuleComponent? component = null)
|
||||||
@@ -583,7 +582,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
|||||||
{
|
{
|
||||||
role ??= nukeops.OperativeRoleProto;
|
role ??= nukeops.OperativeRoleProto;
|
||||||
|
|
||||||
mind.AddRole(new TraitorRole(mind, _prototypeManager.Index<AntagPrototype>(role)));
|
mind.AddRole(new NukeopsRole(mind, _prototypeManager.Index<AntagPrototype>(role)));
|
||||||
nukeops.OperativeMindPendingData.Remove(uid);
|
nukeops.OperativeMindPendingData.Remove(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,10 +598,13 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
|||||||
if (GameTicker.RunLevel != GameRunLevel.InRound)
|
if (GameTicker.RunLevel != GameRunLevel.InRound)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_audioSystem.PlayGlobal(nukeops.GreetSound, playerSession);
|
|
||||||
|
|
||||||
if (nukeops.TargetStation != null && !string.IsNullOrEmpty(Name(nukeops.TargetStation.Value)))
|
if (nukeops.TargetStation != null && !string.IsNullOrEmpty(Name(nukeops.TargetStation.Value)))
|
||||||
|
{
|
||||||
_chatManager.DispatchServerMessage(playerSession, Loc.GetString("nukeops-welcome", ("station", nukeops.TargetStation.Value)));
|
_chatManager.DispatchServerMessage(playerSession, Loc.GetString("nukeops-welcome", ("station", nukeops.TargetStation.Value)));
|
||||||
|
|
||||||
|
// Notificate player about new role assignment
|
||||||
|
_audioSystem.PlayGlobal(component.GreetSoundNotification, playerSession);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -760,7 +762,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
|||||||
CharacterName = spawnDetails.Name
|
CharacterName = spawnDetails.Name
|
||||||
};
|
};
|
||||||
newMind.ChangeOwningPlayer(session.UserId);
|
newMind.ChangeOwningPlayer(session.UserId);
|
||||||
newMind.AddRole(new TraitorRole(newMind, nukeOpsAntag));
|
newMind.AddRole(new NukeopsRole(newMind, nukeOpsAntag));
|
||||||
|
|
||||||
newMind.TransferTo(mob);
|
newMind.TransferTo(mob);
|
||||||
}
|
}
|
||||||
@@ -808,7 +810,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
//ok hardcoded value bad but so is everything else here
|
//ok hardcoded value bad but so is everything else here
|
||||||
mind.AddRole(new TraitorRole(mind, _prototypeManager.Index<AntagPrototype>("Nukeops")));
|
mind.AddRole(new NukeopsRole(mind, _prototypeManager.Index<AntagPrototype>("Nukeops")));
|
||||||
SetOutfitCommand.SetOutfit(mind.OwnedEntity.Value, "SyndicateOperativeGearFull", EntityManager);
|
SetOutfitCommand.SetOutfit(mind.OwnedEntity.Value, "SyndicateOperativeGearFull", EntityManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,12 +14,14 @@ using Content.Shared.Roles;
|
|||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Server.Maps;
|
using Robust.Server.Maps;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Rules;
|
namespace Content.Server.GameTicking.Rules;
|
||||||
|
|
||||||
@@ -35,10 +37,10 @@ public sealed class PiratesRuleSystem : GameRuleSystem<PiratesRuleComponent>
|
|||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
[Dependency] private readonly IServerPreferencesManager _prefs = default!;
|
[Dependency] private readonly IServerPreferencesManager _prefs = default!;
|
||||||
[Dependency] private readonly StationSpawningSystem _stationSpawningSystem = default!;
|
[Dependency] private readonly StationSpawningSystem _stationSpawningSystem = default!;
|
||||||
[Dependency] private readonly StationSystem _stationSystem = default!;
|
|
||||||
[Dependency] private readonly PricingSystem _pricingSystem = default!;
|
[Dependency] private readonly PricingSystem _pricingSystem = default!;
|
||||||
[Dependency] private readonly MapLoaderSystem _map = default!;
|
[Dependency] private readonly MapLoaderSystem _map = default!;
|
||||||
[Dependency] private readonly NamingSystem _namingSystem = default!;
|
[Dependency] private readonly NamingSystem _namingSystem = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -218,6 +220,9 @@ public sealed class PiratesRuleSystem : GameRuleSystem<PiratesRuleComponent>
|
|||||||
|
|
||||||
pirates.Pirates.Add(newMind);
|
pirates.Pirates.Add(newMind);
|
||||||
|
|
||||||
|
// Notificate every player about a pirate antagonist role with sound
|
||||||
|
_audioSystem.PlayGlobal(pirates.PirateAlertSound, session);
|
||||||
|
|
||||||
GameTicker.PlayerJoinGame(session);
|
GameTicker.PlayerJoinGame(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,6 +240,20 @@ public sealed class PiratesRuleSystem : GameRuleSystem<PiratesRuleComponent>
|
|||||||
if (!mind.OwnedEntity.HasValue)
|
if (!mind.OwnedEntity.HasValue)
|
||||||
return;
|
return;
|
||||||
SetOutfitCommand.SetOutfit(mind.OwnedEntity.Value, "PirateGear", EntityManager);
|
SetOutfitCommand.SetOutfit(mind.OwnedEntity.Value, "PirateGear", EntityManager);
|
||||||
|
|
||||||
|
var pirateRule = EntityQuery<PiratesRuleComponent>().FirstOrDefault();
|
||||||
|
if (pirateRule == null)
|
||||||
|
{
|
||||||
|
//todo fuck me this shit is awful
|
||||||
|
GameTicker.StartGameRule("Pirates", out var ruleEntity);
|
||||||
|
pirateRule = Comp<PiratesRuleComponent>(ruleEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notificate every player about a pirate antagonist role with sound
|
||||||
|
if (mind.Session != null)
|
||||||
|
{
|
||||||
|
_audioSystem.PlayGlobal(pirateRule.PirateAlertSound, mind.Session);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStartAttempt(RoundStartAttemptEvent ev)
|
private void OnStartAttempt(RoundStartAttemptEvent ev)
|
||||||
|
|||||||
@@ -7,21 +7,18 @@ using Content.Server.PDA.Ringer;
|
|||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
using Content.Server.Roles;
|
using Content.Server.Roles;
|
||||||
using Content.Server.Shuttles.Components;
|
using Content.Server.Shuttles.Components;
|
||||||
using Content.Server.Traitor;
|
|
||||||
using Content.Server.Traitor.Uplink;
|
using Content.Server.Traitor.Uplink;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Dataset;
|
using Content.Shared.Dataset;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
|
using Content.Shared.PDA;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Player;
|
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Rules;
|
namespace Content.Server.GameTicking.Rules;
|
||||||
|
|
||||||
@@ -149,7 +146,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IPlayerSession> FindPotentialTraitors(in Dictionary<IPlayerSession, HumanoidCharacterProfile> candidates, TraitorRuleComponent component)
|
private List<IPlayerSession> FindPotentialTraitors(in Dictionary<IPlayerSession, HumanoidCharacterProfile> candidates, TraitorRuleComponent component)
|
||||||
{
|
{
|
||||||
var list = new List<IPlayerSession>();
|
var list = new List<IPlayerSession>();
|
||||||
var pendingQuery = GetEntityQuery<PendingClockInComponent>();
|
var pendingQuery = GetEntityQuery<PendingClockInComponent>();
|
||||||
@@ -187,7 +184,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
|
|||||||
return prefList;
|
return prefList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<IPlayerSession> PickTraitors(int traitorCount, List<IPlayerSession> prefList)
|
private List<IPlayerSession> PickTraitors(int traitorCount, List<IPlayerSession> prefList)
|
||||||
{
|
{
|
||||||
var results = new List<IPlayerSession>(traitorCount);
|
var results = new List<IPlayerSession>(traitorCount);
|
||||||
if (prefList.Count == 0)
|
if (prefList.Count == 0)
|
||||||
@@ -213,6 +210,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
|
|||||||
//no i wont fuck you, erp is against rules
|
//no i wont fuck you, erp is against rules
|
||||||
GameTicker.StartGameRule("Traitor", out var ruleEntity);
|
GameTicker.StartGameRule("Traitor", out var ruleEntity);
|
||||||
traitorRule = Comp<TraitorRuleComponent>(ruleEntity);
|
traitorRule = Comp<TraitorRuleComponent>(ruleEntity);
|
||||||
|
MakeCodewords(traitorRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
var mind = traitor.Data.ContentData()?.Mind;
|
var mind = traitor.Data.ContentData()?.Mind;
|
||||||
@@ -221,60 +219,83 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
|
|||||||
_sawmill.Info("Failed getting mind for picked traitor.");
|
_sawmill.Info("Failed getting mind for picked traitor.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mind.OwnedEntity is not { } entity)
|
if (mind.OwnedEntity is not { } entity)
|
||||||
{
|
{
|
||||||
Logger.ErrorS("preset", "Mind picked for traitor did not have an attached entity.");
|
Logger.ErrorS("preset", "Mind picked for traitor did not have an attached entity.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// creadth: we need to create uplink for the antag.
|
// Calculate the amount of currency on the uplink.
|
||||||
// PDA should be in place already
|
|
||||||
DebugTools.AssertNotNull(mind.OwnedEntity);
|
|
||||||
|
|
||||||
var startingBalance = _cfg.GetCVar(CCVars.TraitorStartingBalance);
|
var startingBalance = _cfg.GetCVar(CCVars.TraitorStartingBalance);
|
||||||
|
|
||||||
if (mind.CurrentJob != null)
|
if (mind.CurrentJob != null)
|
||||||
startingBalance = Math.Max(startingBalance - mind.CurrentJob.Prototype.AntagAdvantage, 0);
|
startingBalance = Math.Max(startingBalance - mind.CurrentJob.Prototype.AntagAdvantage, 0);
|
||||||
|
|
||||||
|
// creadth: we need to create uplink for the antag.
|
||||||
|
// PDA should be in place already
|
||||||
var pda = _uplink.FindUplinkTarget(mind.OwnedEntity!.Value);
|
var pda = _uplink.FindUplinkTarget(mind.OwnedEntity!.Value);
|
||||||
if (pda == null || !_uplink.AddUplink(mind.OwnedEntity.Value, startingBalance))
|
if (pda == null || !_uplink.AddUplink(mind.OwnedEntity.Value, startingBalance))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Add the ringtone uplink and get its code for greeting
|
||||||
|
var code = EnsureComp<RingerUplinkComponent>(pda.Value).Code;
|
||||||
|
|
||||||
// add the ringtone uplink and get its code for greeting
|
// Prepare antagonist role
|
||||||
var code = AddComp<RingerUplinkComponent>(pda.Value).Code;
|
|
||||||
|
|
||||||
var antagPrototype = _prototypeManager.Index<AntagPrototype>(traitorRule.TraitorPrototypeId);
|
var antagPrototype = _prototypeManager.Index<AntagPrototype>(traitorRule.TraitorPrototypeId);
|
||||||
var traitorRole = new TraitorRole(mind, antagPrototype);
|
var traitorRole = new TraitorRole(mind, antagPrototype);
|
||||||
mind.AddRole(traitorRole);
|
|
||||||
traitorRule.Traitors.Add(traitorRole);
|
|
||||||
traitorRole.GreetTraitor(traitorRule.Codewords, code);
|
|
||||||
|
|
||||||
|
// Give traitors their codewords and uplink code to keep in their character info menu
|
||||||
|
traitorRole.Mind.Briefing = string.Format(
|
||||||
|
"{0}\n{1}",
|
||||||
|
Loc.GetString("traitor-role-codewords-short", ("codewords", string.Join(", ", traitorRule.Codewords))),
|
||||||
|
Loc.GetString("traitor-role-uplink-code-short", ("code", string.Join("", code))));
|
||||||
|
|
||||||
|
// Assign traitor roles
|
||||||
|
mind.AddRole(traitorRole);
|
||||||
|
SendTraitorBriefing(mind, traitorRule.Codewords, code);
|
||||||
|
traitorRule.Traitors.Add(traitorRole);
|
||||||
|
|
||||||
|
if (mind.TryGetSession(out var session))
|
||||||
|
{
|
||||||
|
// Notificate player about new role assignment
|
||||||
|
_audioSystem.PlayGlobal(traitorRule.GreetSoundNotification, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change the faction
|
||||||
_faction.RemoveFaction(entity, "NanoTrasen", false);
|
_faction.RemoveFaction(entity, "NanoTrasen", false);
|
||||||
_faction.AddFaction(entity, "Syndicate");
|
_faction.AddFaction(entity, "Syndicate");
|
||||||
|
|
||||||
|
// Give traitors their objectives
|
||||||
var maxDifficulty = _cfg.GetCVar(CCVars.TraitorMaxDifficulty);
|
var maxDifficulty = _cfg.GetCVar(CCVars.TraitorMaxDifficulty);
|
||||||
var maxPicks = _cfg.GetCVar(CCVars.TraitorMaxPicks);
|
var maxPicks = _cfg.GetCVar(CCVars.TraitorMaxPicks);
|
||||||
|
|
||||||
//give traitors their objectives
|
|
||||||
var difficulty = 0f;
|
var difficulty = 0f;
|
||||||
for (var pick = 0; pick < maxPicks && maxDifficulty > difficulty; pick++)
|
for (var pick = 0; pick < maxPicks && maxDifficulty > difficulty; pick++)
|
||||||
{
|
{
|
||||||
var objective = _objectivesManager.GetRandomObjective(traitorRole.Mind, "TraitorObjectiveGroups");
|
var objective = _objectivesManager.GetRandomObjective(traitorRole.Mind, "TraitorObjectiveGroups");
|
||||||
if (objective == null) continue;
|
if (objective == null)
|
||||||
|
continue;
|
||||||
if (traitorRole.Mind.TryAddObjective(objective))
|
if (traitorRole.Mind.TryAddObjective(objective))
|
||||||
difficulty += objective.Difficulty;
|
difficulty += objective.Difficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
//give traitors their codewords and uplink code to keep in their character info menu
|
|
||||||
traitorRole.Mind.Briefing = Loc.GetString("traitor-role-codewords-short", ("codewords", string.Join(", ", traitorRule.Codewords)))
|
|
||||||
+ "\n" + Loc.GetString("traitor-role-uplink-code-short", ("code", string.Join("", code)));
|
|
||||||
|
|
||||||
_audioSystem.PlayGlobal(traitorRule.AddedSound, Filter.Empty().AddPlayer(traitor), false, AudioParams.Default);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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(Mind.Mind mind, string[] codewords, Note[] code)
|
||||||
|
{
|
||||||
|
if (mind.TryGetSession(out var session))
|
||||||
|
{
|
||||||
|
_chatManager.DispatchServerMessage(session, Loc.GetString("traitor-role-greeting"));
|
||||||
|
_chatManager.DispatchServerMessage(session, Loc.GetString("traitor-role-codewords", ("codewords", string.Join(", ", codewords))));
|
||||||
|
_chatManager.DispatchServerMessage(session, Loc.GetString("traitor-role-uplink-code", ("code", string.Join("", code))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void HandleLatejoin(PlayerSpawnCompleteEvent ev)
|
private void HandleLatejoin(PlayerSpawnCompleteEvent ev)
|
||||||
{
|
{
|
||||||
var query = EntityQueryEnumerator<TraitorRuleComponent, GameRuleComponent>();
|
var query = EntityQueryEnumerator<TraitorRuleComponent, GameRuleComponent>();
|
||||||
@@ -428,7 +449,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
|
|||||||
return allTraitors;
|
return allTraitors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TraitorRole> GetOtherTraitorsAliveAndConnected(Mind.Mind ourMind, TraitorRuleComponent component)
|
private List<TraitorRole> GetOtherTraitorsAliveAndConnected(Mind.Mind ourMind, TraitorRuleComponent component)
|
||||||
{
|
{
|
||||||
return component.Traitors // don't want
|
return component.Traitors // don't want
|
||||||
.Where(t => t.Mind.OwnedEntity is not null) // no entity
|
.Where(t => t.Mind.OwnedEntity is not null) // no entity
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Content.Server.Mind.Components;
|
|||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.Preferences.Managers;
|
using Content.Server.Preferences.Managers;
|
||||||
|
using Content.Server.Roles;
|
||||||
using Content.Server.RoundEnd;
|
using Content.Server.RoundEnd;
|
||||||
using Content.Server.Traitor;
|
using Content.Server.Traitor;
|
||||||
using Content.Server.Zombies;
|
using Content.Server.Zombies;
|
||||||
@@ -284,7 +285,7 @@ public sealed class ZombieRuleSystem : GameRuleSystem<ZombieRuleComponent>
|
|||||||
|
|
||||||
DebugTools.AssertNotNull(mind.OwnedEntity);
|
DebugTools.AssertNotNull(mind.OwnedEntity);
|
||||||
|
|
||||||
mind.AddRole(new TraitorRole(mind, _prototypeManager.Index<AntagPrototype>(component.PatientZeroPrototypeID)));
|
mind.AddRole(new ZombieRole(mind, _prototypeManager.Index<AntagPrototype>(component.PatientZeroPrototypeID)));
|
||||||
|
|
||||||
var inCharacterName = string.Empty;
|
var inCharacterName = string.Empty;
|
||||||
// Create some variation between the times of each zombie, relative to the time of the group as a whole.
|
// Create some variation between the times of each zombie, relative to the time of the group as a whole.
|
||||||
|
|||||||
@@ -259,9 +259,7 @@ namespace Content.Server.Mind
|
|||||||
|
|
||||||
public bool HasRole<T>() where T : Role
|
public bool HasRole<T>() where T : Role
|
||||||
{
|
{
|
||||||
var t = typeof(T);
|
return _roles.Any(role => role is T);
|
||||||
|
|
||||||
return _roles.Any(role => role.GetType() == t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Content.Server.Objectives.Interfaces;
|
|||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Content.Server.GameTicking.Rules;
|
using Content.Server.GameTicking.Rules;
|
||||||
|
using Content.Server.Roles;
|
||||||
|
|
||||||
namespace Content.Server.Objectives.Conditions
|
namespace Content.Server.Objectives.Conditions
|
||||||
{
|
{
|
||||||
@@ -17,7 +18,7 @@ namespace Content.Server.Objectives.Conditions
|
|||||||
var entityMgr = IoCManager.Resolve<IEntityManager>();
|
var entityMgr = IoCManager.Resolve<IEntityManager>();
|
||||||
|
|
||||||
var traitors = entityMgr.EntitySysManager.GetEntitySystem<TraitorRuleSystem>().GetOtherTraitorsAliveAndConnected(mind).ToList();
|
var traitors = entityMgr.EntitySysManager.GetEntitySystem<TraitorRuleSystem>().GetOtherTraitorsAliveAndConnected(mind).ToList();
|
||||||
List<Traitor.TraitorRole> removeList = new();
|
List<TraitorRole> removeList = new();
|
||||||
|
|
||||||
foreach (var traitor in traitors)
|
foreach (var traitor in traitors)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using Content.Server.Objectives.Interfaces;
|
using Content.Server.Objectives.Interfaces;
|
||||||
|
using Content.Server.Roles;
|
||||||
using Content.Server.Traitor;
|
using Content.Server.Traitor;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using TraitorRole = Content.Server.Roles.TraitorRole;
|
||||||
|
|
||||||
namespace Content.Server.Objectives.Requirements
|
namespace Content.Server.Objectives.Requirements
|
||||||
{
|
{
|
||||||
|
|||||||
24
Content.Server/Roles/AntagonistRole.cs
Normal file
24
Content.Server/Roles/AntagonistRole.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using Content.Shared.Roles;
|
||||||
|
|
||||||
|
namespace Content.Server.Roles;
|
||||||
|
|
||||||
|
public abstract class AntagonistRole : Role
|
||||||
|
{
|
||||||
|
public AntagPrototype Prototype { get; }
|
||||||
|
|
||||||
|
public override string Name { get; }
|
||||||
|
|
||||||
|
public override bool Antagonist { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// .ctor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mind">A mind (player)</param>
|
||||||
|
/// <param name="antagPrototype">Antagonist prototype</param>
|
||||||
|
protected AntagonistRole(Mind.Mind mind, AntagPrototype antagPrototype) : base(mind)
|
||||||
|
{
|
||||||
|
Prototype = antagPrototype;
|
||||||
|
Name = Loc.GetString(antagPrototype.Name);
|
||||||
|
Antagonist = antagPrototype.Antagonist;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
Content.Server/Roles/NukeopsRole.cs
Normal file
8
Content.Server/Roles/NukeopsRole.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using Content.Shared.Roles;
|
||||||
|
|
||||||
|
namespace Content.Server.Roles;
|
||||||
|
|
||||||
|
public sealed class NukeopsRole : AntagonistRole
|
||||||
|
{
|
||||||
|
public NukeopsRole(Mind.Mind mind, AntagPrototype antagPrototype) : base(mind, antagPrototype) { }
|
||||||
|
}
|
||||||
10
Content.Server/Roles/TraitorRole.cs
Normal file
10
Content.Server/Roles/TraitorRole.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Content.Server.Chat.Managers;
|
||||||
|
using Content.Shared.PDA;
|
||||||
|
using Content.Shared.Roles;
|
||||||
|
|
||||||
|
namespace Content.Server.Roles;
|
||||||
|
|
||||||
|
public sealed class TraitorRole : AntagonistRole
|
||||||
|
{
|
||||||
|
public TraitorRole(Mind.Mind mind, AntagPrototype antagPrototype) : base(mind, antagPrototype) { }
|
||||||
|
}
|
||||||
8
Content.Server/Roles/ZombieRole.cs
Normal file
8
Content.Server/Roles/ZombieRole.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using Content.Shared.Roles;
|
||||||
|
|
||||||
|
namespace Content.Server.Roles;
|
||||||
|
|
||||||
|
public sealed class ZombieRole : AntagonistRole
|
||||||
|
{
|
||||||
|
public ZombieRole(Mind.Mind mind, AntagPrototype antagPrototype) : base(mind, antagPrototype) { }
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Server.Mind.Components;
|
using Content.Server.Mind.Components;
|
||||||
|
using Content.Server.Roles;
|
||||||
using Content.Server.Traitor;
|
using Content.Server.Traitor;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
|
||||||
@@ -35,7 +36,7 @@ public sealed class BuyerAntagCondition : ListingCondition
|
|||||||
{
|
{
|
||||||
foreach (var role in mind.Mind.AllRoles)
|
foreach (var role in mind.Mind.AllRoles)
|
||||||
{
|
{
|
||||||
if (role is not TraitorRole blacklistantag)
|
if (role is not AntagonistRole blacklistantag)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (Blacklist.Contains(blacklistantag.Prototype.ID))
|
if (Blacklist.Contains(blacklistantag.Prototype.ID))
|
||||||
@@ -48,7 +49,7 @@ public sealed class BuyerAntagCondition : ListingCondition
|
|||||||
var found = false;
|
var found = false;
|
||||||
foreach (var role in mind.Mind.AllRoles)
|
foreach (var role in mind.Mind.AllRoles)
|
||||||
{
|
{
|
||||||
if (role is not TraitorRole antag)
|
if (role is not AntagonistRole antag)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (Whitelist.Contains(antag.Prototype.ID))
|
if (Whitelist.Contains(antag.Prototype.ID))
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
using Content.Server.Chat.Managers;
|
|
||||||
using Content.Server.Roles;
|
|
||||||
using Content.Shared.PDA;
|
|
||||||
using Content.Shared.Roles;
|
|
||||||
|
|
||||||
namespace Content.Server.Traitor
|
|
||||||
{
|
|
||||||
public sealed class TraitorRole : Role
|
|
||||||
{
|
|
||||||
public AntagPrototype Prototype { get; }
|
|
||||||
|
|
||||||
public TraitorRole(Mind.Mind mind, AntagPrototype antagPrototype) : base(mind)
|
|
||||||
{
|
|
||||||
Prototype = antagPrototype;
|
|
||||||
Name = Loc.GetString(antagPrototype.Name);
|
|
||||||
Antagonist = antagPrototype.Antagonist;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string Name { get; }
|
|
||||||
public override bool Antagonist { get; }
|
|
||||||
|
|
||||||
public void GreetTraitor(string[] codewords, Note[] code)
|
|
||||||
{
|
|
||||||
if (Mind.TryGetSession(out var session))
|
|
||||||
{
|
|
||||||
var chatMgr = IoCManager.Resolve<IChatManager>();
|
|
||||||
var entMgr = IoCManager.Resolve<IEntityManager>();
|
|
||||||
chatMgr.DispatchServerMessage(session, Loc.GetString("traitor-role-greeting"));
|
|
||||||
chatMgr.DispatchServerMessage(session, Loc.GetString("traitor-role-codewords", ("codewords", string.Join(", ", codewords))));
|
|
||||||
chatMgr.DispatchServerMessage(session, Loc.GetString("traitor-role-uplink-code", ("code", string.Join("", code))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,6 +13,7 @@ using Content.Server.Mind.Commands;
|
|||||||
using Content.Server.Mind.Components;
|
using Content.Server.Mind.Components;
|
||||||
using Content.Server.Nutrition.Components;
|
using Content.Server.Nutrition.Components;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
|
using Content.Server.Roles;
|
||||||
using Content.Server.Speech.Components;
|
using Content.Server.Speech.Components;
|
||||||
using Content.Server.Temperature.Components;
|
using Content.Server.Temperature.Components;
|
||||||
using Content.Server.Traitor;
|
using Content.Server.Traitor;
|
||||||
@@ -58,6 +59,7 @@ namespace Content.Server.Zombies
|
|||||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
|
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
|
||||||
|
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -207,9 +209,12 @@ namespace Content.Server.Zombies
|
|||||||
if (mindcomp.Mind != null && mindcomp.Mind.TryGetSession(out var session))
|
if (mindcomp.Mind != null && mindcomp.Mind.TryGetSession(out var session))
|
||||||
{
|
{
|
||||||
//Zombie role for player manifest
|
//Zombie role for player manifest
|
||||||
mindcomp.Mind.AddRole(new TraitorRole(mindcomp.Mind, _proto.Index<AntagPrototype>(zombiecomp.ZombieRoleId)));
|
mindcomp.Mind.AddRole(new ZombieRole(mindcomp.Mind, _proto.Index<AntagPrototype>(zombiecomp.ZombieRoleId)));
|
||||||
//Greeting message for new bebe zombers
|
//Greeting message for new bebe zombers
|
||||||
_chatMan.DispatchServerMessage(session, Loc.GetString("zombie-infection-greeting"));
|
_chatMan.DispatchServerMessage(session, Loc.GetString("zombie-infection-greeting"));
|
||||||
|
|
||||||
|
// Notificate player about new role assignment
|
||||||
|
_audioSystem.PlayGlobal(zombiecomp.GreetSoundNotification, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!HasComp<GhostRoleMobSpawnerComponent>(target) && !mindcomp.HasMind) //this specific component gives build test trouble so pop off, ig
|
if (!HasComp<GhostRoleMobSpawnerComponent>(target) && !mindcomp.HasMind) //this specific component gives build test trouble so pop off, ig
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using Content.Shared.Chat.Prototypes;
|
|||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Content.Shared.Humanoid;
|
using Content.Shared.Humanoid;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||||
@@ -133,5 +134,11 @@ namespace Content.Shared.Zombies
|
|||||||
{ "Shock", -0.2 },
|
{ "Shock", -0.2 },
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Path to antagonist alert sound.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("greetSoundNotification")]
|
||||||
|
public SoundSpecifier GreetSoundNotification = new SoundPathSpecifier("/Audio/Ambience/Antag/zombie_start.ogg");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
Resources/Audio/Ambience/Antag/attributions.yml
Normal file
12
Resources/Audio/Ambience/Antag/attributions.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
- files: ["nukeops_start.ogg"]
|
||||||
|
license: "CC-BY-NC-SA-3.0"
|
||||||
|
copyright: "Taken from TG station."
|
||||||
|
source: "https://github.com/tgstation/tgstation/commit/827967c9650c23af64280ad1491405fed8f644c5"
|
||||||
|
- files: ["pirate_start.ogg"]
|
||||||
|
license: "CC-BY-NC-SA-3.0"
|
||||||
|
copyright: "Made by @MIXnikita#1474 (Discord) for SS14"
|
||||||
|
source: "https://github.com/SerbiaStrong-220/space-station-14/blob/master/Resources/Audio/Ambience/Antag/pirate_start.ogg"
|
||||||
|
- files: ["zombie_start.ogg"]
|
||||||
|
license: "CC-BY-NC-SA-3.0"
|
||||||
|
copyright: "Made by @MIXnikita#1474 (Discord) for SS14"
|
||||||
|
source: "https://github.com/SerbiaStrong-220/space-station-14/blob/master/Resources/Audio/Ambience/Antag/zombie_start.ogg"
|
||||||
BIN
Resources/Audio/Ambience/Antag/pirate_start.ogg
Normal file
BIN
Resources/Audio/Ambience/Antag/pirate_start.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Ambience/Antag/zombie_start.ogg
Normal file
BIN
Resources/Audio/Ambience/Antag/zombie_start.ogg
Normal file
Binary file not shown.
@@ -5,5 +5,3 @@ siren.ogg taken from https://github.com/ParadiseSS13/Paradise/blob/master/sound/
|
|||||||
redalert.ogg was taken from: https://github.com/Skyrat-SS13/Skyrat13/commit/2d4f2d1b489590b559e4073f41b126cef56f4c50
|
redalert.ogg was taken from: https://github.com/Skyrat-SS13/Skyrat13/commit/2d4f2d1b489590b559e4073f41b126cef56f4c50
|
||||||
|
|
||||||
bluealert.ogg was taken from: https://github.com/Skyrat-SS13/Skyrat13/commit/2d4f2d1b489590b559e4073f41b126cef56f4c50
|
bluealert.ogg was taken from: https://github.com/Skyrat-SS13/Skyrat13/commit/2d4f2d1b489590b559e4073f41b126cef56f4c50
|
||||||
|
|
||||||
nukeops.ogg was taken from: https://github.com/tgstation/tgstation/commit/827967c9650c23af64280ad1491405fed8f644c5
|
|
||||||
|
|||||||
Reference in New Issue
Block a user