diff --git a/Content.Client/GameObjects/Components/Actor/CharacterInfoComponent.cs b/Content.Client/GameObjects/Components/Actor/CharacterInfoComponent.cs index 2a49499211..86f0e15700 100644 --- a/Content.Client/GameObjects/Components/Actor/CharacterInfoComponent.cs +++ b/Content.Client/GameObjects/Components/Actor/CharacterInfoComponent.cs @@ -43,8 +43,6 @@ namespace Content.Client.GameObjects.Components.Actor { base.HandleNetworkMessage(message, netChannel, session); - if(session?.AttachedEntity != Owner) return; - switch (message) { case CharacterInfoMessage characterInfoMessage: diff --git a/Content.Server/GameObjects/Components/Actor/CharacterInfoComponent.cs b/Content.Server/GameObjects/Components/Actor/CharacterInfoComponent.cs index 7f4c040725..b29fe3a2d5 100644 --- a/Content.Server/GameObjects/Components/Actor/CharacterInfoComponent.cs +++ b/Content.Server/GameObjects/Components/Actor/CharacterInfoComponent.cs @@ -16,6 +16,8 @@ namespace Content.Server.GameObjects.Components.Actor { public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession? session = null) { + if(session?.AttachedEntity != Owner) return; + switch (message) { case RequestCharacterInfoMessage _: @@ -30,12 +32,12 @@ namespace Content.Server.GameObjects.Components.Actor // getting conditions foreach (var objective in mind.AllObjectives) { - if (!conditions.ContainsKey(objective.Issuer)) - conditions[objective.Issuer] = new List(); + if (!conditions.ContainsKey(objective.Prototype.Issuer)) + conditions[objective.Prototype.Issuer] = new List(); foreach (var condition in objective.Conditions) { - conditions[objective.Issuer].Add(new ConditionInfo(condition.GetTitle(), - condition.GetDescription(), condition.GetIcon(), condition.GetProgress(mindComponent.Mind))); + conditions[objective.Prototype.Issuer].Add(new ConditionInfo(condition.Title, + condition.Description, condition.Icon, condition.Progress)); } } diff --git a/Content.Server/GameTicking/GamePreset.cs b/Content.Server/GameTicking/GamePreset.cs index a91436220c..0e9001ebba 100644 --- a/Content.Server/GameTicking/GamePreset.cs +++ b/Content.Server/GameTicking/GamePreset.cs @@ -15,5 +15,9 @@ namespace Content.Server.GameTicking public virtual string Description => "Secret!"; public virtual bool DisallowLateJoin => false; public Dictionary readyProfiles; + + public virtual void OnGameStarted() { } + + public virtual string GetRoundEndDescription() => ""; } } diff --git a/Content.Server/GameTicking/GamePresets/PresetSuspicion.cs b/Content.Server/GameTicking/GamePresets/PresetSuspicion.cs index 3b497d8938..36766ce30c 100644 --- a/Content.Server/GameTicking/GamePresets/PresetSuspicion.cs +++ b/Content.Server/GameTicking/GamePresets/PresetSuspicion.cs @@ -47,10 +47,10 @@ namespace Content.Server.GameTicking.GamePresets public override bool Start(IReadOnlyList readyPlayers, bool force = false) { - MinPlayers = _cfg.GetCVar(CCVars.GameSuspicionMinPlayers); - MinTraitors = _cfg.GetCVar(CCVars.GameSuspicionMinTraitors); - PlayersPerTraitor = _cfg.GetCVar(CCVars.GameSuspicionPlayersPerTraitor); - TraitorStartingBalance = _cfg.GetCVar(CCVars.GameSuspicionStartingBalance); + MinPlayers = _cfg.GetCVar(CCVars.SuspicionMinPlayers); + MinTraitors = _cfg.GetCVar(CCVars.SuspicionMinTraitors); + PlayersPerTraitor = _cfg.GetCVar(CCVars.SuspicionPlayersPerTraitor); + TraitorStartingBalance = _cfg.GetCVar(CCVars.SuspicionStartingBalance); if (!force && readyPlayers.Count < MinPlayers) { diff --git a/Content.Server/GameTicking/GamePresets/PresetTraitor.cs b/Content.Server/GameTicking/GamePresets/PresetTraitor.cs new file mode 100644 index 0000000000..cf0e71c380 --- /dev/null +++ b/Content.Server/GameTicking/GamePresets/PresetTraitor.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Content.Server.GameObjects.Components.GUI; +using Content.Server.GameObjects.Components.Items.Storage; +using Content.Server.GameObjects.Components.PDA; +using Content.Server.GameTicking.GameRules; +using Content.Server.Interfaces.Chat; +using Content.Server.Interfaces.GameTicking; +using Content.Server.Mobs.Roles.Traitor; +using Content.Server.Objectives.Interfaces; +using Content.Server.Players; +using Content.Server.Prototypes; +using Content.Shared; +using Content.Shared.GameObjects.Components.Inventory; +using Content.Shared.GameObjects.Components.PDA; +using Robust.Server.Interfaces.Player; +using Robust.Shared.Interfaces.Configuration; +using Robust.Shared.Interfaces.Random; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Log; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.GameTicking.GamePresets +{ + public class PresetTraitor : GamePreset + { + [Dependency] private readonly IGameTicker _gameticker = default!; + [Dependency] private readonly IChatManager _chatManager = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + + public override string ModeTitle => "Traitor"; + + private int MinPlayers { get; set; } + private int PlayersPerTraitor { get; set; } + private int MaxTraitors { get; set; } + private int CodewordCount { get; set; } + private int StartingBalance { get; set; } + private float MaxDifficulty { get; set; } + private int MaxPicks { get; set; } + + private readonly List _traitors = new (); + + public override bool Start(IReadOnlyList readyPlayers, bool force = false) + { + MinPlayers = _cfg.GetCVar(CCVars.TraitorMinPlayers); + PlayersPerTraitor = _cfg.GetCVar(CCVars.TraitorPlayersPerTraitor); + MaxTraitors = _cfg.GetCVar(CCVars.TraitorMaxTraitors); + CodewordCount = _cfg.GetCVar(CCVars.TraitorCodewordCount); + StartingBalance = _cfg.GetCVar(CCVars.TraitorStartingBalance); + MaxDifficulty = _cfg.GetCVar(CCVars.TraitorMaxDifficulty); + MaxPicks = _cfg.GetCVar(CCVars.TraitorMaxPicks); + + if (!force && readyPlayers.Count < MinPlayers) + { + _chatManager.DispatchServerAnnouncement($"Not enough players readied up for the game! There were {readyPlayers.Count} players readied up out of {MinPlayers} needed."); + return false; + } + + if (readyPlayers.Count == 0) + { + _chatManager.DispatchServerAnnouncement("No players readied up! Can't start Traitor."); + return false; + } + + var list = new List(readyPlayers); + var prefList = new List(); + + foreach (var player in list) + { + if (!readyProfiles.ContainsKey(player.UserId)) + { + continue; + } + var profile = readyProfiles[player.UserId]; + if (profile.AntagPreferences.Contains("Traitor")) + { + prefList.Add(player); + } + } + + var numTraitors = MathHelper.Clamp(readyPlayers.Count / PlayersPerTraitor, + 1, MaxTraitors); + + for (var i = 0; i < numTraitors; i++) + { + IPlayerSession traitor; + if(prefList.Count < numTraitors) + { + if (list.Count == 0) + { + Logger.InfoS("preset", "Insufficient ready players to fill up with traitors, stopping the selection."); + break; + } + traitor = _random.PickAndTake(list); + Logger.InfoS("preset", "Insufficient preferred traitors, picking at random."); + } + else + { + traitor = _random.PickAndTake(prefList); + list.Remove(traitor); + Logger.InfoS("preset", "Selected a preferred traitor."); + } + var mind = traitor.Data.ContentData()?.Mind; + var traitorRole = new TraitorRole(mind); + if (mind == null) + { + Logger.ErrorS("preset", "Failed getting mind for picked traitor."); + continue; + } + + // creadth: we need to create uplink for the antag. + // PDA should be in place already, so we just need to + // initiate uplink account. + var uplinkAccount = new UplinkAccount(mind.OwnedEntity.Uid, StartingBalance); + var inventory = mind.OwnedEntity.GetComponent(); + if (!inventory.TryGetSlotItem(EquipmentSlotDefines.Slots.IDCARD, out ItemComponent pdaItem)) + { + Logger.ErrorS("preset", "Failed getting pda for picked traitor."); + continue; + } + + var pda = pdaItem.Owner; + + var pdaComponent = pda.GetComponent(); + if (pdaComponent.IdSlotEmpty) + { + Logger.ErrorS("preset","PDA had no id for picked traitor"); + continue; + } + + mind.AddRole(traitorRole); + _traitors.Add(traitorRole); + pdaComponent.InitUplinkAccount(uplinkAccount); + } + + var adjectives = _prototypeManager.Index("adjectives").Values; + var verbs = _prototypeManager.Index("verbs").Values; + + var codewordPool = adjectives.Concat(verbs).ToList(); + var finalCodewordCount = Math.Min(CodewordCount, codewordPool.Count); + var codewords = new string[finalCodewordCount]; + for (var i = 0; i < finalCodewordCount; i++) + { + codewords[i] = _random.PickAndTake(codewordPool); + } + + foreach (var traitor in _traitors) + { + traitor.GreetTraitor(codewords); + } + + _gameticker.AddGameRule(); + return true; + } + + public override void OnGameStarted() + { + var objectivesMgr = IoCManager.Resolve(); + foreach (var traitor in _traitors) + { + //give traitors their objectives + var difficulty = 0f; + for (var pick = 0; pick < MaxPicks && MaxDifficulty > difficulty; pick++) + { + var objective = objectivesMgr.GetRandomObjective(traitor.Mind); + if (objective == null) continue; + if (traitor.Mind.TryAddObjective(objective)) + difficulty += objective.Difficulty; + } + } + } + + public override string GetRoundEndDescription() + { + var traitorCount = _traitors.Count; + var result = Loc.GetString("There {0} {1} {2}.", Loc.GetPluralString("was", "were", traitorCount), + traitorCount, Loc.GetPluralString("traitor", "traitors", traitorCount)); + foreach (var traitor in _traitors) + { + result += Loc.GetString("\n{0} was a traitor",traitor.Mind.Session.Name); + var objectives = traitor.Mind.AllObjectives.ToArray(); + if (objectives.Length == 0) + { + result += ".\n"; + continue; + } + + result += Loc.GetString(" and had the following objectives:"); + foreach (var objectiveGroup in objectives.GroupBy(o => o.Prototype.Issuer)) + { + result += $"\n[color=#87cefa]{Loc.GetString(objectiveGroup.Key)}[/color]"; + foreach (var objective in objectiveGroup) + { + foreach (var condition in objective.Conditions) + { + var progress = condition.Progress; + result += + Loc.GetString("\n- {0} | {1}", condition.Title, (progress > 0.99f ? $"[color=green]{Loc.GetString("Success!")}[/color]" : $"[color=red]{Loc.GetString("Failed!")}[/color] ({(int) (progress * 100)}%)")); + } + } + } + } + + return result; + } + } +} diff --git a/Content.Server/GameTicking/GameRules/RuleTraitor.cs b/Content.Server/GameTicking/GameRules/RuleTraitor.cs new file mode 100644 index 0000000000..5a2a262641 --- /dev/null +++ b/Content.Server/GameTicking/GameRules/RuleTraitor.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading; +using Content.Server.Interfaces.Chat; +using Content.Server.Interfaces.GameTicking; +using Content.Server.Mobs.Roles.Traitor; +using Content.Server.Players; +using Content.Shared; +using Content.Shared.GameObjects.Components.Damage; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Server.Interfaces.Player; +using Robust.Shared.Audio; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.Configuration; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Timer = Robust.Shared.Timers.Timer; + +namespace Content.Server.GameTicking.GameRules +{ + public class RuleTraitor : GameRule + { + [Dependency] private readonly IChatManager _chatManager = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly IGameTicker _gameTicker = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; + + public override void Added() + { + _chatManager.DispatchServerAnnouncement(Loc.GetString("Hello crew! Have a good shift!")); + + bool Predicate(IPlayerSession session) => session.ContentData()?.Mind?.HasRole() ?? false; + + EntitySystem.Get().PlayGlobal("/Audio/Misc/tatoralert.ogg", AudioParams.Default, Predicate); + } + } +} diff --git a/Content.Server/GameTicking/GameTicker.cs b/Content.Server/GameTicking/GameTicker.cs index b942e572be..1f18f8d213 100644 --- a/Content.Server/GameTicking/GameTicker.cs +++ b/Content.Server/GameTicking/GameTicker.cs @@ -115,6 +115,15 @@ namespace Content.Server.GameTicking } } + [ViewVariables] + public GamePreset Preset + { + get => _preset == null ? MakeGamePreset(null) : _preset; + set => _preset = value; + } + + private GamePreset _preset; + public event Action OnRunLevelChanged; public event Action OnRuleAdded; @@ -278,18 +287,18 @@ namespace Content.Server.GameTicking } // Time to start the preset. - var preset = MakeGamePreset(profiles); + Preset = MakeGamePreset(profiles); - DisallowLateJoin |= preset.DisallowLateJoin; + DisallowLateJoin |= Preset.DisallowLateJoin; - if (!preset.Start(assignedJobs.Keys.ToList(), force)) + if (!Preset.Start(assignedJobs.Keys.ToList(), force)) { if (_configurationManager.GetCVar(CCVars.GameLobbyFallbackEnabled)) { SetStartPreset(_configurationManager.GetCVar(CCVars.GameLobbyFallbackPreset)); var newPreset = MakeGamePreset(profiles); _chatManager.DispatchServerAnnouncement( - $"Failed to start {preset.ModeTitle} mode! Defaulting to {newPreset.ModeTitle}..."); + $"Failed to start {Preset.ModeTitle} mode! Defaulting to {newPreset.ModeTitle}..."); if (!newPreset.Start(readyPlayers, force)) { throw new ApplicationException("Fallback preset failed to start!"); @@ -297,15 +306,17 @@ namespace Content.Server.GameTicking DisallowLateJoin = false; DisallowLateJoin |= newPreset.DisallowLateJoin; + Preset = newPreset; } else { - SendServerMessage($"Failed to start {preset.ModeTitle} mode! Restarting round..."); + SendServerMessage($"Failed to start {Preset.ModeTitle} mode! Restarting round..."); RestartRound(); DelayStart(TimeSpan.FromSeconds(PresetFailedCooldownIncrease)); return; } } + Preset.OnGameStarted(); _roundStartTimeSpan = IoCManager.Resolve().RealTime; _sendStatusToAll(); @@ -342,8 +353,8 @@ namespace Content.Server.GameTicking //Tell every client the round has ended. var roundEndMessage = _netManager.CreateNetMessage(); - roundEndMessage.GamemodeTitle = MakeGamePreset(null).ModeTitle; - roundEndMessage.RoundEndText = roundEndText; + roundEndMessage.GamemodeTitle = Preset.ModeTitle; + roundEndMessage.RoundEndText = roundEndText + $"\n{Preset.GetRoundEndDescription()}"; //Get the timespan of the round. roundEndMessage.RoundDuration = IoCManager.Resolve().RealTime.Subtract(_roundStartTimeSpan); @@ -472,6 +483,7 @@ namespace Content.Server.GameTicking "sandbox" => typeof(PresetSandbox), "deathmatch" => typeof(PresetDeathMatch), "suspicion" => typeof(PresetSuspicion), + "traitor" => typeof(PresetTraitor), _ => default }; @@ -1003,8 +1015,8 @@ namespace Content.Server.GameTicking private string GetInfoText() { - var gmTitle = MakeGamePreset(null).ModeTitle; - var desc = MakeGamePreset(null).Description; + var gmTitle = Preset.ModeTitle; + var desc = Preset.Description; return Loc.GetString(@"Hi and welcome to [color=white]Space Station 14![/color] The current game mode is: [color=white]{0}[/color]. diff --git a/Content.Server/Mobs/Mind.cs b/Content.Server/Mobs/Mind.cs index badf46ae02..98d313c6ed 100644 --- a/Content.Server/Mobs/Mind.cs +++ b/Content.Server/Mobs/Mind.cs @@ -28,7 +28,7 @@ namespace Content.Server.Mobs { private readonly ISet _roles = new HashSet(); - private readonly List _objectives = new(); + private readonly List _objectives = new(); /// /// Creates the new mind attached to a specific player session. @@ -81,7 +81,7 @@ namespace Content.Server.Mobs /// An enumerable over all the objectives this mind has. /// [ViewVariables] - public IEnumerable AllObjectives => _objectives; + public IEnumerable AllObjectives => _objectives; /// /// The session of the player owning this mind. @@ -156,9 +156,12 @@ namespace Content.Server.Mobs /// /// Adds an objective to this mind. /// - public bool TryAddObjective(ObjectivePrototype objective) + public bool TryAddObjective(ObjectivePrototype objectivePrototype) { - if (!objective.CanBeAssigned(this)) + if (!objectivePrototype.CanBeAssigned(this)) + return false; + var objective = objectivePrototype.GetObjective(this); + if (_objectives.Contains(objective)) return false; _objectives.Add(objective); return true; diff --git a/Content.Server/Mobs/Roles/Traitor/TraitorRole.cs b/Content.Server/Mobs/Roles/Traitor/TraitorRole.cs new file mode 100644 index 0000000000..0458c7ad6c --- /dev/null +++ b/Content.Server/Mobs/Roles/Traitor/TraitorRole.cs @@ -0,0 +1,23 @@ +using Content.Server.Interfaces.Chat; +using Robust.Shared.IoC; +using Robust.Shared.Localization; + +namespace Content.Server.Mobs.Roles.Traitor +{ + public class TraitorRole : Role + { + public TraitorRole(Mind mind) : base(mind) + { + } + + public override string Name => "Syndicate Agent"; + public override bool Antagonist => true; + + public void GreetTraitor(string[] codewords) + { + var chatMgr = IoCManager.Resolve(); + chatMgr.DispatchServerMessage(Mind.Session, Loc.GetString("Hello Agent!")); + chatMgr.DispatchServerMessage(Mind.Session, Loc.GetString("Your codewords are: {0}", string.Join(", ",codewords))); + } + } +} diff --git a/Content.Server/Objectives/Conditions/DieCondition.cs b/Content.Server/Objectives/Conditions/DieCondition.cs new file mode 100644 index 0000000000..93453b8cee --- /dev/null +++ b/Content.Server/Objectives/Conditions/DieCondition.cs @@ -0,0 +1,53 @@ +#nullable enable +using Content.Server.Mobs; +using Content.Server.Objectives.Interfaces; +using Content.Shared.GameObjects.Components.Damage; +using JetBrains.Annotations; +using Robust.Shared.Localization; +using Robust.Shared.Utility; + +namespace Content.Server.Objectives.Conditions +{ + [UsedImplicitly] + public class DieCondition : IObjectiveCondition + { + private Mind? _mind; + + public IObjectiveCondition GetAssigned(Mind mind) + { + return new DieCondition {_mind = mind}; + } + + public string Title => Loc.GetString("Die a glorius death"); + + public string Description => Loc.GetString("Die."); + + public SpriteSpecifier Icon => new SpriteSpecifier.Rsi(new ResourcePath("Mobs/Ghosts/ghost_human.rsi"), "icon"); + + public float Progress => _mind?.OwnedEntity != null && + _mind.OwnedEntity.TryGetComponent(out var damageableComponent) && + damageableComponent.CurrentState != DamageState.Dead + ? 0f + : 1f; + + public float Difficulty => 1f; + + public bool Equals(IObjectiveCondition? other) + { + return other is DieCondition condition && Equals(_mind, condition._mind); + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((DieCondition) obj); + } + + public override int GetHashCode() + { + return (_mind != null ? _mind.GetHashCode() : 0); + } + } +} diff --git a/Content.Server/Objectives/Conditions/KillPersonCondition.cs b/Content.Server/Objectives/Conditions/KillPersonCondition.cs new file mode 100644 index 0000000000..74248e5324 --- /dev/null +++ b/Content.Server/Objectives/Conditions/KillPersonCondition.cs @@ -0,0 +1,48 @@ +#nullable enable +using Content.Server.Mobs; +using Content.Server.Objectives.Interfaces; +using Content.Shared.GameObjects.Components.Damage; +using Robust.Shared.Localization; +using Robust.Shared.Utility; + +namespace Content.Server.Objectives.Conditions +{ + public abstract class KillPersonCondition : IObjectiveCondition + { + protected Mind? Target; + public abstract IObjectiveCondition GetAssigned(Mind mind); + + public string Title => Loc.GetString("Kill {0}", Target?.OwnedEntity.Name ?? ""); + + public string Description => Loc.GetString("Do it however you like, just make sure they don't last the shift."); + + public SpriteSpecifier Icon => new SpriteSpecifier.Rsi(new ResourcePath("Objects/Weapons/Guns/Pistols/mk58_wood.rsi"), "icon"); + + public float Progress => Target?.OwnedEntity != null && + Target.OwnedEntity + .TryGetComponent(out var damageableComponent) && + damageableComponent.CurrentState == DamageState.Dead + ? 1f + : 0f; + + public float Difficulty => 2f; + + public bool Equals(IObjectiveCondition? other) + { + return other is KillPersonCondition kpc && Equals(Target, kpc.Target); + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((KillPersonCondition) obj); + } + + public override int GetHashCode() + { + return Target?.GetHashCode() ?? 0; + } + } +} diff --git a/Content.Server/Objectives/Conditions/KillRandomPersonCondition.cs b/Content.Server/Objectives/Conditions/KillRandomPersonCondition.cs new file mode 100644 index 0000000000..7a1f3e7c07 --- /dev/null +++ b/Content.Server/Objectives/Conditions/KillRandomPersonCondition.cs @@ -0,0 +1,31 @@ +using System.Linq; +using Content.Server.GameObjects.Components.Mobs; +using Content.Server.Mobs; +using Content.Server.Objectives.Interfaces; +using Content.Shared.GameObjects.Components.Damage; +using JetBrains.Annotations; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Random; +using Robust.Shared.IoC; +using Robust.Shared.Random; + +namespace Content.Server.Objectives.Conditions +{ + [UsedImplicitly] + public class KillRandomPersonCondition : KillPersonCondition + { + public override IObjectiveCondition GetAssigned(Mind mind) + { + var entityMgr = IoCManager.Resolve(); + var allHumans = entityMgr.ComponentManager.EntityQuery().Where(mc => + { + var entity = mc.Mind?.OwnedEntity; + return entity != null && + entity.TryGetComponent(out var damageableComponent) && + damageableComponent.CurrentState == DamageState.Alive + && mc.Mind != mind; + }).Select(mc => mc.Mind).ToList(); + return new KillRandomPersonCondition {Target = IoCManager.Resolve().Pick(allHumans)}; + } + } +} diff --git a/Content.Server/Objectives/Conditions/StayAliveCondition.cs b/Content.Server/Objectives/Conditions/StayAliveCondition.cs new file mode 100644 index 0000000000..da85e1f7a7 --- /dev/null +++ b/Content.Server/Objectives/Conditions/StayAliveCondition.cs @@ -0,0 +1,53 @@ +#nullable enable +using Content.Server.Mobs; +using Content.Server.Objectives.Interfaces; +using Content.Shared.GameObjects.Components.Damage; +using JetBrains.Annotations; +using Robust.Shared.Localization; +using Robust.Shared.Utility; + +namespace Content.Server.Objectives.Conditions +{ + [UsedImplicitly] + public class StayAliveCondition : IObjectiveCondition + { + private Mind? _mind; + + public IObjectiveCondition GetAssigned(Mind mind) + { + return new StayAliveCondition {_mind = mind}; + } + + public string Title => Loc.GetString("Stay alive."); + + public string Description => Loc.GetString("Survive this shift, we need you for another assignment."); + + public SpriteSpecifier Icon => new SpriteSpecifier.Rsi(new ResourcePath("Objects/Misc/skub.rsi"), "icon"); //didn't know what else would have been a good icon for staying alive + + public float Progress => _mind?.OwnedEntity != null && + _mind.OwnedEntity.TryGetComponent(out var damageableComponent) && + damageableComponent.CurrentState == DamageState.Dead + ? 0f + : 1f; + + public float Difficulty => 1f; + + public bool Equals(IObjectiveCondition? other) + { + return other is StayAliveCondition sac && Equals(_mind, sac._mind); + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((StayAliveCondition) obj); + } + + public override int GetHashCode() + { + return (_mind != null ? _mind.GetHashCode() : 0); + } + } +} diff --git a/Content.Server/Objectives/Conditions/StealCondition.cs b/Content.Server/Objectives/Conditions/StealCondition.cs index a7ea32187a..2be59dbd0c 100644 --- a/Content.Server/Objectives/Conditions/StealCondition.cs +++ b/Content.Server/Objectives/Conditions/StealCondition.cs @@ -1,7 +1,9 @@ #nullable enable +using System; using Content.Server.GameObjects.Components.ContainerExt; using Content.Server.Mobs; using Content.Server.Objectives.Interfaces; +using JetBrains.Annotations; using Robust.Server.GameObjects.Components.Container; using Robust.Shared.GameObjects; using Robust.Shared.IoC; @@ -13,45 +15,79 @@ using Robust.Shared.Utility; namespace Content.Server.Objectives.Conditions { + [UsedImplicitly] public class StealCondition : IObjectiveCondition { - public string PrototypeId { get; private set; } = default!; - public int Amount { get; private set; } + private Mind? _mind; + private string _prototypeId = default!; + private int _amount; + + public IObjectiveCondition GetAssigned(Mind mind) + { + return new StealCondition + { + _mind = mind, + _prototypeId = _prototypeId, + _amount = _amount + }; + } public void ExposeData(ObjectSerializer serializer) { - serializer.DataField(this, x => x.PrototypeId, "prototype", ""); - serializer.DataField(this, x => x.Amount, "amount", 1); + serializer.DataField(ref _prototypeId, "prototype", ""); + serializer.DataField(ref _amount, "amount", 1); - if (Amount < 1) + if (_amount < 1) { - Logger.Error("StealCondition has an amount less than 1 ({0})", Amount); + Logger.Error("StealCondition has an amount less than 1 ({0})", _amount); } } private string PrototypeName => - IoCManager.Resolve().TryIndex(PrototypeId, out var prototype) + IoCManager.Resolve().TryIndex(_prototypeId, out var prototype) ? prototype.Name : "[CANNOT FIND NAME]"; - public string GetTitle() => Loc.GetString("Steal {0} {1}", Amount > 1 ? $"{Amount}x" : "", Loc.GetString(PrototypeName)); + public string Title => Loc.GetString("Steal {0}{1}", _amount > 1 ? $"{_amount}x " : "", Loc.GetString(PrototypeName)); - public string GetDescription() => Loc.GetString("We need you to steal {0}. Don't get caught.", Loc.GetString(PrototypeName)); + public string Description => Loc.GetString("We need you to steal {0}. Don't get caught.", Loc.GetString(PrototypeName)); - public SpriteSpecifier GetIcon() + public SpriteSpecifier Icon => new SpriteSpecifier.EntityPrototype(_prototypeId); + + public float Progress { - return new SpriteSpecifier.EntityPrototype(PrototypeId); + get + { + if (_mind?.OwnedEntity == null) return 0f; + if (!_mind.OwnedEntity.TryGetComponent(out var containerManagerComponent)) return 0f; + + float count = containerManagerComponent.CountPrototypeOccurencesRecursive(_prototypeId); + return count/_amount; + } } - public float GetProgress(Mind? mind) - { - if (mind?.OwnedEntity == null) return 0f; - if (!mind.OwnedEntity.TryGetComponent(out var containerManagerComponent)) return 0f; - float count = containerManagerComponent.CountPrototypeOccurencesRecursive(PrototypeId); - return count/Amount; + + public float Difficulty => 1f; + + public bool Equals(IObjectiveCondition? other) + { + return other is StealCondition stealCondition && + Equals(_mind, stealCondition._mind) && + _prototypeId == stealCondition._prototypeId && _amount == stealCondition._amount; } - public float GetDifficulty() => 1f; + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((StealCondition) obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(_mind, _prototypeId, _amount); + } } } diff --git a/Content.Server/Objectives/Interfaces/IObjectiveCondition.cs b/Content.Server/Objectives/Interfaces/IObjectiveCondition.cs index 97385aa805..c55dd516c1 100644 --- a/Content.Server/Objectives/Interfaces/IObjectiveCondition.cs +++ b/Content.Server/Objectives/Interfaces/IObjectiveCondition.cs @@ -1,35 +1,47 @@ -using Content.Server.Mobs; +#nullable enable +using System; +using Content.Server.Mobs; using Robust.Shared.Interfaces.Serialization; +using Robust.Shared.Serialization; using Robust.Shared.Utility; namespace Content.Server.Objectives.Interfaces { - public interface IObjectiveCondition : IExposeData + public interface IObjectiveCondition : IExposeData, IEquatable { + /// + /// Returns a copy of the IObjectiveCondition which is assigned to the mind. + /// + /// Mind to assign to. + /// The new IObjectiveCondition. + IObjectiveCondition GetAssigned(Mind mind); + /// /// Returns the title of the condition. /// - string GetTitle(); + string Title { get; } /// /// Returns the description of the condition. /// - string GetDescription(); + string Description { get; } /// /// Returns a SpriteSpecifier to be used as an icon for the condition. /// - SpriteSpecifier GetIcon(); + SpriteSpecifier Icon { get; } /// - /// Returns the current progress of the condition in %. + /// Returns the current progress of the condition in % from 0 to 1. /// /// Current progress in %. - float GetProgress(Mind mind); + float Progress { get; } /// /// Returns a difficulty of the condition. /// - float GetDifficulty(); + float Difficulty { get; } + + void IExposeData.ExposeData(ObjectSerializer serializer){} } } diff --git a/Content.Server/Objectives/Interfaces/IObjectivesManager.cs b/Content.Server/Objectives/Interfaces/IObjectivesManager.cs index 25b72812e7..3108668cab 100644 --- a/Content.Server/Objectives/Interfaces/IObjectivesManager.cs +++ b/Content.Server/Objectives/Interfaces/IObjectivesManager.cs @@ -1,4 +1,5 @@ -using Content.Server.Mobs; +using System.Collections.Generic; +using Content.Server.Mobs; namespace Content.Server.Objectives.Interfaces { @@ -7,11 +8,11 @@ namespace Content.Server.Objectives.Interfaces /// /// Returns all objectives the provided mind is valid for. /// - ObjectivePrototype[] GetAllPossibleObjectives(Mind mind); + IReadOnlyList GetAllPossibleObjectives(Mind mind); /// - /// Returns a randomly picked (no pop) collection of objectives the provided mind is valid for. + /// Returns a randomly picked objective the provided mind is valid for. /// - ObjectivePrototype[] GetRandomObjectives(Mind mind, float maxDifficulty = 3f); + ObjectivePrototype GetRandomObjective(Mind mind); } } diff --git a/Content.Server/Objectives/Objective.cs b/Content.Server/Objectives/Objective.cs new file mode 100644 index 0000000000..59cd15f2e5 --- /dev/null +++ b/Content.Server/Objectives/Objective.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using Content.Server.Mobs; +using Content.Server.Objectives.Interfaces; +using Robust.Shared.ViewVariables; + +namespace Content.Server.Objectives +{ + public class Objective : IEquatable + { + [ViewVariables] + public readonly Mind Mind; + [ViewVariables] + public readonly ObjectivePrototype Prototype; + private readonly List _conditions = new(); + [ViewVariables] + public IReadOnlyList Conditions => _conditions; + + public Objective(ObjectivePrototype prototype, Mind mind) + { + Prototype = prototype; + Mind = mind; + foreach (var condition in prototype.Conditions) + { + _conditions.Add(condition.GetAssigned(mind)); + } + } + + public bool Equals(Objective other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + if (!Equals(Mind, other.Mind) || !Equals(Prototype, other.Prototype)) return false; + if (_conditions.Count != other._conditions.Count) return false; + for (var i = 0; i < _conditions.Count; i++) + { + if (!_conditions[i].Equals(other._conditions[i])) return false; + } + + return true; + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((Objective) obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(Mind, Prototype, _conditions); + } + } +} diff --git a/Content.Server/Objectives/ObjectivePrototype.cs b/Content.Server/Objectives/ObjectivePrototype.cs index 4022d5a3d0..4472f4274b 100644 --- a/Content.Server/Objectives/ObjectivePrototype.cs +++ b/Content.Server/Objectives/ObjectivePrototype.cs @@ -15,23 +15,24 @@ namespace Content.Server.Objectives [ViewVariables] public string ID { get; private set; } - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables] public string Issuer { get; private set; } [ViewVariables] public float Probability { get; private set; } [ViewVariables] - public IReadOnlyList Conditions => _conditions; - [ViewVariables] - public IReadOnlyList Requirements => _requirements; - - [ViewVariables] - public float Difficulty => _difficultyOverride ?? _conditions.Sum(c => c.GetDifficulty()); + public float Difficulty => _difficultyOverride ?? _conditions.Sum(c => c.Difficulty); private List _conditions = new(); private List _requirements = new(); + [ViewVariables] + public IReadOnlyList Conditions => _conditions; + + [ViewVariables] + public bool CanBeDuplicateAssignment { get; private set; } + [ViewVariables(VVAccess.ReadWrite)] private float? _difficultyOverride = null; @@ -42,6 +43,14 @@ namespace Content.Server.Objectives if (!requirement.CanBeAssigned(mind)) return false; } + if (!CanBeDuplicateAssignment) + { + foreach (var objective in mind.AllObjectives) + { + if (objective.Prototype.ID == ID) return false; + } + } + return true; } @@ -52,9 +61,15 @@ namespace Content.Server.Objectives ser.DataField(this, x => x.ID, "id", string.Empty); ser.DataField(this, x => x.Issuer, "issuer", "Unknown"); ser.DataField(this, x => x.Probability, "prob", 0.3f); - ser.DataField(this, x => x._conditions, "conditions", new List()); - ser.DataField(this, x => x._requirements, "requirements", new List()); - ser.DataField(this, x => x._difficultyOverride, "difficultyOverride", null); + ser.DataField(ref _conditions, "conditions", new List()); + ser.DataField(ref _requirements, "requirements", new List()); + ser.DataField(ref _difficultyOverride, "difficultyOverride", null); + ser.DataField(this, x => x.CanBeDuplicateAssignment, "canBeDuplicate", false); + } + + public Objective GetObjective(Mind mind) + { + return new(this, mind); } } } diff --git a/Content.Server/Objectives/ObjectivesManager.cs b/Content.Server/Objectives/ObjectivesManager.cs index e8f75dbc71..0a8750d3d4 100644 --- a/Content.Server/Objectives/ObjectivesManager.cs +++ b/Content.Server/Objectives/ObjectivesManager.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; using System.Linq; using Content.Server.Mobs; using Content.Server.Objectives.Interfaces; @@ -15,39 +16,24 @@ namespace Content.Server.Objectives [Dependency] private IPrototypeManager _prototypeManager = default!; [Dependency] private IRobustRandom _random = default!; - public ObjectivePrototype[] GetAllPossibleObjectives(Mind mind) + public List GetAllPossibleObjectives(Mind mind) { - return _prototypeManager.EnumeratePrototypes().Where(objectivePrototype => objectivePrototype.CanBeAssigned(mind)).ToArray(); + return _prototypeManager.EnumeratePrototypes().Where(objectivePrototype => objectivePrototype.CanBeAssigned(mind)).ToList(); } - public ObjectivePrototype[] GetRandomObjectives(Mind mind, float maxDifficulty = 3) + public ObjectivePrototype? GetRandomObjective(Mind mind) { var objectives = GetAllPossibleObjectives(mind); + _random.Shuffle(objectives); //to prevent endless loops - if(objectives.Length == 0 || objectives.Sum(o => o.Difficulty) == 0f) return objectives; - - var result = new List(); - var currentDifficulty = 0f; - _random.Shuffle(objectives); - while (currentDifficulty < maxDifficulty) + foreach (var objective in objectives) { - foreach (var objective in objectives) - { - if (!_random.Prob(objective.Probability)) continue; - - result.Add(objective); - currentDifficulty += objective.Difficulty; - if (currentDifficulty >= maxDifficulty) break; - } + if (!_random.Prob(objective.Probability)) continue; + return objective; } - if (currentDifficulty > maxDifficulty) //will almost always happen - { - result.Pop(); - } - - return result.ToArray(); + return null; } } } diff --git a/Content.Server/Objectives/Requirements/IncompatibleConditionsRequirement.cs b/Content.Server/Objectives/Requirements/IncompatibleConditionsRequirement.cs new file mode 100644 index 0000000000..dc41ba2e4d --- /dev/null +++ b/Content.Server/Objectives/Requirements/IncompatibleConditionsRequirement.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Content.Server.Mobs; +using Content.Server.Objectives.Interfaces; +using Robust.Shared.Serialization; + +namespace Content.Server.Objectives.Requirements +{ + public class IncompatibleConditionsRequirement : IObjectiveRequirement + { + private List _incompatibleConditions = new(); + public void ExposeData(ObjectSerializer serializer) + { + serializer.DataField(this, x=>x._incompatibleConditions, "conditions", new List()); + } + + public bool CanBeAssigned(Mind mind) + { + foreach (var objective in mind.AllObjectives) + { + foreach (var condition in objective.Conditions) + { + foreach (var incompatibleCondition in _incompatibleConditions) + { + if (incompatibleCondition == condition.GetType().Name) return false; + } + } + } + + return true; + } + } +} diff --git a/Content.Server/Objectives/Requirements/IncompatibleObjectivesRequirement.cs b/Content.Server/Objectives/Requirements/IncompatibleObjectivesRequirement.cs new file mode 100644 index 0000000000..cb70b06883 --- /dev/null +++ b/Content.Server/Objectives/Requirements/IncompatibleObjectivesRequirement.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using Content.Server.Mobs; +using Content.Server.Objectives.Interfaces; +using Robust.Shared.Serialization; + +namespace Content.Server.Objectives.Requirements +{ + public class IncompatibleObjectivesRequirement : IObjectiveRequirement + { + private List _incompatibleObjectives = new(); + public void ExposeData(ObjectSerializer serializer) + { + serializer.DataField(this, x=>x._incompatibleObjectives, "objectives", new List()); + } + + public bool CanBeAssigned(Mind mind) + { + foreach (var objective in mind.AllObjectives) + { + foreach (var incompatibleObjective in _incompatibleObjectives) + { + if (incompatibleObjective == objective.Prototype.ID) return false; + } + } + + return true; + } + } +} diff --git a/Content.Server/Objectives/Requirements/SuspicionTraitorRequirement.cs b/Content.Server/Objectives/Requirements/TraitorRequirement.cs similarity index 60% rename from Content.Server/Objectives/Requirements/SuspicionTraitorRequirement.cs rename to Content.Server/Objectives/Requirements/TraitorRequirement.cs index 183e24a2c6..32b9628719 100644 --- a/Content.Server/Objectives/Requirements/SuspicionTraitorRequirement.cs +++ b/Content.Server/Objectives/Requirements/TraitorRequirement.cs @@ -1,17 +1,19 @@ using Content.Server.Mobs; -using Content.Server.Mobs.Roles.Suspicion; +using Content.Server.Mobs.Roles.Traitor; using Content.Server.Objectives.Interfaces; +using JetBrains.Annotations; using Robust.Shared.Serialization; namespace Content.Server.Objectives.Requirements { - public class SuspicionTraitorRequirement : IObjectiveRequirement + [UsedImplicitly] + public class TraitorRequirement : IObjectiveRequirement { public void ExposeData(ObjectSerializer serializer){} public bool CanBeAssigned(Mind mind) { - return mind.HasRole(); + return mind.HasRole(); } } } diff --git a/Content.Server/Prototypes/DatasetPrototype.cs b/Content.Server/Prototypes/DatasetPrototype.cs new file mode 100644 index 0000000000..2c6c122305 --- /dev/null +++ b/Content.Server/Prototypes/DatasetPrototype.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using YamlDotNet.RepresentationModel; + +namespace Content.Server.Prototypes +{ + [Prototype("dataset")] + public class DatasetPrototype : IPrototype, IIndexedPrototype + { + private string _id; + public string ID => _id; + + private List _values; + public IReadOnlyList Values => _values; + + public void LoadFrom(YamlMappingNode mapping) + { + var ser = YamlObjectSerializer.NewReader(mapping); + + ser.DataField(ref _id, "id", ""); + ser.DataField(ref _values, "values", new List()); + } + } +} diff --git a/Content.Shared/CCVars.cs b/Content.Shared/CCVars.cs index 14b19f16dc..8b82290561 100644 --- a/Content.Shared/CCVars.cs +++ b/Content.Shared/CCVars.cs @@ -55,21 +55,50 @@ namespace Content.Shared public static readonly CVarDef GamePersistGuests = CVarDef.Create("game.persistguests", true, CVar.ARCHIVE | CVar.SERVERONLY); - public static readonly CVarDef GameSuspicionMinPlayers = - CVarDef.Create("game.suspicion_min_players", 5); - - public static readonly CVarDef GameSuspicionMinTraitors = - CVarDef.Create("game.suspicion_min_traitors", 2); - - public static readonly CVarDef GameSuspicionPlayersPerTraitor = - CVarDef.Create("game.suspicion_players_per_traitor", 5); - - public static readonly CVarDef GameSuspicionStartingBalance = - CVarDef.Create("game.suspicion_starting_balance", 20); - public static readonly CVarDef GameDiagonalMovement = CVarDef.Create("game.diagonalmovement", true, CVar.ARCHIVE); + /* + * Suspicion + */ + + public static readonly CVarDef SuspicionMinPlayers = + CVarDef.Create("suspicion.min_players", 5); + + public static readonly CVarDef SuspicionMinTraitors = + CVarDef.Create("suspicion.min_traitors", 2); + + public static readonly CVarDef SuspicionPlayersPerTraitor = + CVarDef.Create("suspicion.players_per_traitor", 5); + + public static readonly CVarDef SuspicionStartingBalance = + CVarDef.Create("suspicion.starting_balance", 20); + + /* + * Traitor + */ + + public static readonly CVarDef TraitorMinPlayers = + CVarDef.Create("traitor.min_players", 5); + + public static readonly CVarDef TraitorMaxTraitors = + CVarDef.Create("traitor.max_traitors", 4); + + public static readonly CVarDef TraitorPlayersPerTraitor = + CVarDef.Create("traitor.players_per_traitor", 5); + + public static readonly CVarDef TraitorCodewordCount = + CVarDef.Create("traitor.codeword_count", 4); + + public static readonly CVarDef TraitorStartingBalance = + CVarDef.Create("traitor.starting_balance", 20); + + public static readonly CVarDef TraitorMaxDifficulty = + CVarDef.Create("traitor.max_difficulty", 4); + + public static readonly CVarDef TraitorMaxPicks = + CVarDef.Create("traitor.max_picks", 20); + /* * Console */ diff --git a/Content.Shared/GameTicking/SharedGameTicker.cs b/Content.Shared/GameTicking/SharedGameTicker.cs index 882ed0b095..1251e6d3b4 100644 --- a/Content.Shared/GameTicking/SharedGameTicker.cs +++ b/Content.Shared/GameTicking/SharedGameTicker.cs @@ -322,7 +322,6 @@ namespace Content.Shared.GameTicking AllPlayersEndInfo.Add(readPlayerData); } - } public override void WriteToBuffer(NetOutgoingMessage buffer) diff --git a/Resources/Prototypes/Datasets/adjectives.yml b/Resources/Prototypes/Datasets/adjectives.yml new file mode 100644 index 0000000000..86fb290952 --- /dev/null +++ b/Resources/Prototypes/Datasets/adjectives.yml @@ -0,0 +1,400 @@ +- type: dataset + id: adjectives + values: + - adorable + - adventurous + - aggressive + - alert + - attractive + - average + - beautiful + - blue-eyed + - bloody + - blushing + - bright + - clean + - clear + - cloudy + - colorful + - crowded + - cute + - dark + - drab + - distinct + - dull + - elegant + - excited + - fancy + - filthy + - glamorous + - gleaming + - gorgeous + - graceful + - grotesque + - handsome + - homely + - light + - long + - magnificent + - misty + - motionless + - muddy + - old-fashioned + - plain + - poised + - precious + - quaint + - shiny + - smoggy + - sparkling + - spotless + - stormy + - strange + - ugly + - ugliest + - unsightly + - unusual + - wide-eyed + - alive + - annoying + - bad + - better + - beautiful + - brainy + - breakable + - busy + - careful + - cautious + - clever + - clumsy + - concerned + - crazy + - curious + - dead + - different + - difficult + - doubtful + - easy + - expensive + - famous + - fragile + - frail + - gifted + - helpful + - helpless + - horrible + - important + - impossible + - inexpensive + - innocent + - inquisitive + - modern + - mushy + - odd + - open + - outstanding + - poor + - powerful + - prickly + - puzzled + - real + - rich + - shy + - sleepy + - stupid + - super + - talented + - tame + - tender + - tough + - uninterested + - vast + - wandering + - wild + - wrong + - angry + - annoyed + - anxious + - arrogant + - ashamed + - awful + - bad + - bewildered + - black + - blue + - bored + - clumsy + - combative + - condemned + - confused + - crazy,flipped-out + - creepy + - cruel + - dangerous + - defeated + - defiant + - depressed + - disgusted + - disturbed + - dizzy + - dull + - embarrassed + - envious + - evil + - fierce + - foolish + - frantic + - frightened + - grieving + - grumpy + - helpless + - homeless + - hungry + - hurt + - ill + - itchy + - jealous + - jittery + - lazy + - lonely + - mysterious + - nasty + - naughty + - nervous + - nutty + - obnoxious + - outrageous + - panicky + - repulsive + - scary + - selfish + - sore + - tense + - terrible + - testy + - thoughtless + - tired + - troubled + - upset + - uptight + - weary + - wicked + - worried + - agreeable + - amused + - brave + - calm + - charming + - cheerful + - comfortable + - cooperative + - courageous + - delightful + - determined + - eager + - elated + - enchanting + - encouraging + - energetic + - enthusiastic + - excited + - exuberant + - fair + - faithful + - fantastic + - fine + - friendly + - funny + - gentle + - glorious + - good + - happy + - healthy + - helpful + - hilarious + - jolly + - joyous + - kind + - lively + - lovely + - lucky + - nice + - obedient + - perfect + - pleasant + - proud + - relieved + - silly + - smiling + - splendid + - successful + - thankful + - thoughtful + - victorious + - vivacious + - witty + - wonderful + - zealous + - zany + - broad + - chubby + - crooked + - curved + - deep + - flat + - high + - hollow + - low + - narrow + - round + - shallow + - skinny + - square + - steep + - straight + - wide + - big + - colossal + - fat + - gigantic + - great + - huge + - immense + - large + - little + - mammoth + - massive + - miniature + - petite + - puny + - scrawny + - short + - small + - tall + - teeny + - teeny-tiny + - tiny + - cooing + - deafening + - faint + - harsh + - high-pitched + - hissing + - hushed + - husky + - loud + - melodic + - moaning + - mute + - noisy + - purring + - quiet + - raspy + - resonant + - screeching + - shrill + - silent + - soft + - squealing + - thundering + - voiceless + - whispering + - ancient + - brief + - early + - fast + - late + - long + - modern + - old + - old-fashioned + - quick + - rapid + - short + - slow + - swift + - young + - Taste/Touch + - bitter + - delicious + - fresh + - juicy + - ripe + - rotten + - salty + - sour + - spicy + - stale + - sticky + - strong + - sweet + - tart + - tasteless + - tasty + - thirsty + - fluttering + - fuzzy + - greasy + - grubby + - hard + - hot + - icy + - loose + - melted + - nutritious + - plastic + - prickly + - rainy + - rough + - scattered + - shaggy + - shaky + - sharp + - shivering + - silky + - slimy + - slippery + - smooth + - soft + - solid + - steady + - sticky + - tender + - tight + - uneven + - weak + - wet + - wooden + - yummy + - boiling + - breezy + - broken + - bumpy + - chilly + - cold + - cool + - creepy + - crooked + - cuddly + - curly + - damaged + - damp + - dirty + - dry + - dusty + - filthy + - flaky + - fluffy + - freezing + - hot + - warm + - wet + - abundant + - empty + - few + - heavy + - light + - many + - numerous + - substantial + - capitalist diff --git a/Resources/Prototypes/Datasets/verbs.yml b/Resources/Prototypes/Datasets/verbs.yml new file mode 100644 index 0000000000..19ce8a70e7 --- /dev/null +++ b/Resources/Prototypes/Datasets/verbs.yml @@ -0,0 +1,637 @@ +- type: dataset + id: verbs + values: + - accept + - add + - admire + - admit + - advise + - afford + - agree + - alert + - allow + - amuse + - analyse + - announce + - annoy + - answer + - apologise + - appear + - applaud + - appreciate + - approve + - argue + - arrange + - arrest + - arrive + - ask + - attach + - attack + - attempt + - attend + - attract + - avoid + - back + - bake + - balance + - ban + - bang + - bare + - bat + - bathe + - battle + - beam + - beg + - behave + - belong + - bleach + - bless + - blind + - blink + - blot + - blush + - boast + - boil + - bolt + - bomb + - book + - bore + - borrow + - bounce + - bow + - box + - brake + - brake + - branch + - breathe + - bruise + - brush + - bubble + - bump + - burn + - bury + - buzz + - calculate + - call + - camp + - care + - carry + - carve + - cause + - challenge + - change + - charge + - chase + - cheat + - check + - cheer + - chew + - choke + - chop + - claim + - clap + - clean + - clear + - clip + - close + - coach + - coil + - collect + - colour + - comb + - command + - communicate + - compare + - compete + - complain + - complete + - concentrate + - concern + - confess + - confuse + - connect + - consider + - consist + - contain + - continue + - copy + - correct + - cough + - count + - cover + - crack + - crash + - crawl + - cross + - crush + - cry + - cure + - curl + - curve + - cycle + - dam + - damage + - dance + - dare + - decay + - deceive + - decide + - decorate + - delay + - delight + - deliver + - depend + - describe + - desert + - deserve + - destroy + - detect + - develop + - disagree + - disappear + - disapprove + - disarm + - discover + - dislike + - divide + - double + - doubt + - drag + - drain + - dream + - dress + - drip + - drop + - drown + - drum + - dry + - dust + - earn + - educate + - embarrass + - employ + - empty + - encourage + - end + - enjoy + - enter + - entertain + - escape + - examine + - excite + - excuse + - exercise + - exist + - expand + - expect + - explain + - explode + - extend + - face + - fade + - fail + - fancy + - fasten + - fax + - fear + - fence + - fetch + - file + - fill + - film + - fire + - fit + - fix + - flap + - flash + - float + - flood + - flow + - flower + - fold + - follow + - fool + - force + - form + - found + - frame + - frighten + - fry + - gather + - gaze + - glow + - glue + - grab + - grate + - grease + - greet + - grin + - grip + - groan + - guarantee + - guard + - guess + - guide + - hammer + - hand + - handle + - hang + - happen + - harass + - harm + - hate + - haunt + - head + - heal + - heap + - heat + - help + - hook + - hop + - hope + - hover + - hug + - hum + - hunt + - hurry + - identify + - ignore + - imagine + - impress + - improve + - include + - increase + - influence + - inform + - inject + - injure + - instruct + - intend + - interest + - interfere + - interrupt + - introduce + - invent + - invite + - irritate + - itch + - jail + - jam + - jog + - join + - joke + - judge + - juggle + - jump + - kick + - kill + - kiss + - kneel + - knit + - knock + - knot + - label + - land + - last + - laugh + - launch + - learn + - level + - license + - lick + - lie + - lighten + - like + - list + - listen + - live + - load + - lock + - long + - look + - love + - man + - manage + - march + - mark + - marry + - match + - mate + - matter + - measure + - meddle + - melt + - memorise + - mend + - messup + - milk + - mine + - miss + - mix + - moan + - moor + - mourn + - move + - muddle + - mug + - multiply + - murder + - nail + - name + - need + - nest + - nod + - note + - notice + - number + - obey + - object + - observe + - obtain + - occur + - offend + - offer + - open + - order + - overflow + - owe + - own + - pack + - paddle + - paint + - park + - part + - pass + - paste + - pat + - pause + - peck + - pedal + - peel + - peep + - perform + - permit + - phone + - pick + - pinch + - pine + - place + - plan + - plant + - play + - please + - plug + - point + - poke + - polish + - pop + - possess + - post + - pour + - practise + - pray + - preach + - precede + - prefer + - prepare + - present + - preserve + - press + - pretend + - prevent + - prick + - print + - produce + - program + - promise + - protect + - provide + - pull + - pump + - punch + - puncture + - punish + - push + - question + - queue + - race + - radiate + - rain + - raise + - reach + - realise + - receive + - recognise + - record + - reduce + - reflect + - refuse + - regret + - reign + - reject + - rejoice + - relax + - release + - rely + - remain + - remember + - remind + - remove + - repair + - repeat + - replace + - reply + - report + - reproduce + - request + - rescue + - retire + - return + - rhyme + - rinse + - risk + - rob + - rock + - roll + - rot + - rub + - ruin + - rule + - rush + - sack + - sail + - satisfy + - save + - saw + - scare + - scatter + - scold + - scorch + - scrape + - scratch + - scream + - screw + - scribble + - scrub + - seal + - search + - separate + - serve + - settle + - shade + - share + - shave + - shelter + - shiver + - shock + - shop + - shriek + - shrug + - sigh + - sign + - signal + - sin + - sip + - ski + - skip + - slap + - slip + - slow + - smash + - smell + - smile + - smoke + - snatch + - sneeze + - sniff + - snore + - snow + - soak + - soothe + - sound + - spare + - spark + - sparkle + - spell + - spill + - spoil + - spot + - spray + - sprout + - squash + - squeak + - squeal + - squeeze + - stain + - stamp + - stare + - start + - stay + - steer + - step + - stir + - stitch + - stop + - store + - strap + - strengthen + - stretch + - strip + - stroke + - stuff + - subtract + - succeed + - suck + - suffer + - suggest + - suit + - supply + - support + - suppose + - surprise + - surround + - suspect + - suspend + - switch + - talk + - tame + - tap + - taste + - tease + - telephone + - tempt + - terrify + - test + - thank + - thaw + - tick + - tickle + - tie + - time + - tip + - tire + - touch + - tour + - tow + - trace + - trade + - train + - transport + - trap + - travel + - treat + - tremble + - trick + - trip + - trot + - trouble + - trust + - try + - tug + - tumble + - turn + - twist + - type + - undress + - unfasten + - unite + - unlock + - unpack + - untidy + - use + - vanish + - visit + - wail + - wait + - walk + - wander + - want + - warm + - warn + - wash + - waste + - watch + - water + - wave + - weigh + - welcome + - whine + - whip + - whirl + - whisper + - whistle + - wink + - wipe + - wish + - wobble + - wonder + - work + - worry + - wrap + - wreck + - wrestle + - wriggle + - yawn + - yell + - zip + - zoom diff --git a/Resources/Prototypes/Objectives/traitorObjectives.yml b/Resources/Prototypes/Objectives/traitorObjectives.yml index 2423769e5c..666158527e 100644 --- a/Resources/Prototypes/Objectives/traitorObjectives.yml +++ b/Resources/Prototypes/Objectives/traitorObjectives.yml @@ -1,9 +1,42 @@ - type: objective - id: SoapDeluxeStealObjective - prob: 0.3 + id: CaptainIDStealObjective issuer: The Syndicate requirements: - - !type:SuspicionTraitorRequirement {} + - !type:TraitorRequirement {} + - !type:IncompatibleConditionsRequirement + conditions: + - DieCondition conditions: - !type:StealCondition - prototype: SoapDeluxe + prototype: CaptainIDCard + +- type: objective + id: KillRandomObjective + issuer: The Syndicate + requirements: + - !type:TraitorRequirement {} + conditions: + - !type:KillRandomPersonCondition {} + canBeDuplicate: true + +- type: objective + id: StayAliveObjective + issuer: The Syndicate + requirements: + - !type:TraitorRequirement {} + - !type:IncompatibleConditionsRequirement + conditions: + - DieCondition + conditions: + - !type:StayAliveCondition {} + +- type: objective + id: DieObjective + issuer: The Syndicate + requirements: + - !type:TraitorRequirement {} + - !type:IncompatibleConditionsRequirement + conditions: + - StayAliveCondition + conditions: + - !type:DieCondition {}