From 78e6c80a703a96d0734f18e770f89531dd33d00b Mon Sep 17 00:00:00 2001 From: Vigers Ray <60344369+VigersRay@users.noreply.github.com> Date: Sun, 20 Apr 2025 02:41:02 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=86=D0=B5=D0=BB=D0=B5=D0=B9=20?= =?UTF-8?q?=D0=BA=D1=83=D0=BB=D1=8C=D1=82=D0=B0=20(#1883)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Bed/Cryostorage/CryostorageSystem.cs | 7 ++ .../BloodCult/BloodCultTargetComponent.cs | 6 + .../GameRule/BloodCultRuleComponent.cs | 9 +- .../BloodCult/GameRule/BloodCultRuleSystem.cs | 103 ++++++++++++++---- .../KillCultistTargetConditionComponent.cs | 2 - .../KillCultistTargetConditionSystem.cs | 56 +++------- .../Runes/Systems/BloodCultSystem.Rune.cs | 26 ++++- .../Runes/Systems/BloodCultSystem.cs | 2 + .../_strings/_sunrise/blood-cult/cult.ftl | 4 +- 9 files changed, 141 insertions(+), 74 deletions(-) create mode 100644 Content.Server/_Sunrise/BloodCult/BloodCultTargetComponent.cs diff --git a/Content.Server/Bed/Cryostorage/CryostorageSystem.cs b/Content.Server/Bed/Cryostorage/CryostorageSystem.cs index 4fb6220cd9..913d9a3aa8 100644 --- a/Content.Server/Bed/Cryostorage/CryostorageSystem.cs +++ b/Content.Server/Bed/Cryostorage/CryostorageSystem.cs @@ -1,4 +1,5 @@ using System.Globalization; +using Content.Server._Sunrise.TraitorTarget; using Content.Server.Chat.Managers; using Content.Server.Chat.Systems; using Content.Server.Ghost; @@ -216,6 +217,8 @@ public sealed class CryostorageSystem : SharedCryostorageSystem comp.AllowReEnteringBody = false; _transform.SetParent(ent, PausedMap.Value); + RaiseLocalEvent(ent, new CryostorageEnteredEvent()); + RemCompDeferred(ent); cryostorageComponent.StoredPlayers.Add(ent); Dirty(ent, comp); UpdateCryostorageUIState((cryostorageEnt.Value, cryostorageComponent)); @@ -348,3 +351,7 @@ public sealed class CryostorageSystem : SharedCryostorageSystem } } } + +public class CryostorageEnteredEvent +{ +} diff --git a/Content.Server/_Sunrise/BloodCult/BloodCultTargetComponent.cs b/Content.Server/_Sunrise/BloodCult/BloodCultTargetComponent.cs new file mode 100644 index 0000000000..024df13779 --- /dev/null +++ b/Content.Server/_Sunrise/BloodCult/BloodCultTargetComponent.cs @@ -0,0 +1,6 @@ +namespace Content.Server._Sunrise.BloodCult; + +[RegisterComponent] +public sealed partial class BloodCultTargetComponent : Component +{ +} diff --git a/Content.Server/_Sunrise/BloodCult/GameRule/BloodCultRuleComponent.cs b/Content.Server/_Sunrise/BloodCult/GameRule/BloodCultRuleComponent.cs index adc009d8fa..5d16ae1bde 100644 --- a/Content.Server/_Sunrise/BloodCult/GameRule/BloodCultRuleComponent.cs +++ b/Content.Server/_Sunrise/BloodCult/GameRule/BloodCultRuleComponent.cs @@ -1,9 +1,10 @@ -using Content.Shared._Sunrise.BloodCult; +using Content.Server._Sunrise.BloodCult.Runes.Systems; +using Content.Shared._Sunrise.BloodCult; using Robust.Shared.Audio; namespace Content.Server._Sunrise.BloodCult.GameRule; -[RegisterComponent, Access(typeof(BloodCultRuleSystem))] +[RegisterComponent, Access(typeof(BloodCultRuleSystem), typeof(BloodCultSystem))] public sealed partial class BloodCultRuleComponent : Component { [DataField] @@ -19,13 +20,13 @@ public sealed partial class BloodCultRuleComponent : Component new SoundPathSpecifier("/Audio/_Sunrise/BloodCult/blood_cult_greeting.ogg"); [ViewVariables] - public List CultTargets = new(); + public readonly Dictionary CultTargets = new(); [DataField] public int MaxTargets = 3; [DataField] - public int MinTargets = 3; + public int MinTargets = 1; [DataField] public int TargetsPerPlayer = 20; diff --git a/Content.Server/_Sunrise/BloodCult/GameRule/BloodCultRuleSystem.cs b/Content.Server/_Sunrise/BloodCult/GameRule/BloodCultRuleSystem.cs index d6b6931386..912e615756 100644 --- a/Content.Server/_Sunrise/BloodCult/GameRule/BloodCultRuleSystem.cs +++ b/Content.Server/_Sunrise/BloodCult/GameRule/BloodCultRuleSystem.cs @@ -4,6 +4,7 @@ using Content.Server._Sunrise.BloodCult.Objectives.Systems; using Content.Server._Sunrise.BloodCult.Runes.Systems; using Content.Server._Sunrise.TraitorTarget; using Content.Server.Antag; +using Content.Server.Bed.Cryostorage; using Content.Server.Bible.Components; using Content.Server.Chat.Managers; using Content.Server.GameTicking; @@ -34,7 +35,6 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; -using CultMemberComponent = Content.Shared._Sunrise.BloodCult.Components.CultMemberComponent; namespace Content.Server._Sunrise.BloodCult.GameRule; @@ -56,11 +56,9 @@ public sealed class BloodCultRuleSystem : GameRuleSystem [Dependency] private readonly ISharedPlayerManager _playerManager = default!; [Dependency] private readonly KillCultistTargetsConditionSystem _cultistTargetsConditionSystem = default!; [Dependency] private readonly SharedRoleSystem _roles = default!; - [Dependency] private readonly MobStateSystem _mobState = default!; - [Dependency] private readonly EntityManager _entityManager = default!; - private EntProtoId MindRoleCultistPrototypeId = "MindRoleCultist"; - private EntProtoId CultistKillObjective = "CultistKillObjective"; + private readonly EntProtoId _mindRoleCultistPrototypeId = "MindRoleCultist"; + private readonly EntProtoId _cultistKillObjective = "CultistKillObjective"; public override void Initialize() { @@ -72,11 +70,77 @@ public sealed class BloodCultRuleSystem : GameRuleSystem SubscribeLocalEvent(OnCultistComponentInit); SubscribeLocalEvent(OnCultistComponentRemoved); SubscribeLocalEvent(OnCultistsStateChanged); + SubscribeLocalEvent(OnCultTargetDeleted); + SubscribeLocalEvent(OnCultTargetEnterCryo); SubscribeLocalEvent(AfterEntitySelected); SubscribeLocalEvent(OnAfterAntagSelectionComplete); } + private void OnCultTargetEnterCryo(EntityUid uid, BloodCultTargetComponent component, CryostorageEnteredEvent args) + { + var rule = GetRule(); + if (rule == null) + return; + + // Логика уровня /b: Если цель культа попадет в крио, значит эту цель надо заменить. + + if (rule.CultTargets.ContainsKey(uid)) + { + rule.CultTargets.Remove(uid); + RemCompDeferred(uid); + AddCultTarget(rule); + } + } + + + private void OnCultTargetDeleted(EntityUid uid, BloodCultTargetComponent component, ComponentShutdown args) + { + var rule = GetRule(); + if (rule == null) + return; + + // Логика уровня /b: Если цель культа будет удалена, значит эту цель надо заменить. + // Жертвоприношение не будет считаться удалением + + if (rule.CultTargets.ContainsKey(uid) && rule.CultTargets[uid] == false) + { + rule.CultTargets.Remove(uid); + RemCompDeferred(uid); + AddCultTarget(rule); + } + } + + public void AddCultTarget(BloodCultRuleComponent rule) + { + var potentialTargets = FindPotentialTargets(); + + potentialTargets.RemoveAll(rule.CultTargets.Keys.Contains); + + var priorityTargets = potentialTargets + .Where(target => + HasComp(target) || + HasComp(target)) + .ToList(); + + potentialTargets.RemoveAll(priorityTargets.Contains); + + var selectedVictims = SelectRandomTargets(priorityTargets, 1); + selectedVictims.AddRange(SelectRandomTargets(potentialTargets, 1 - selectedVictims.Count)); + + foreach (var selectedVictim in selectedVictims) + { + rule.CultTargets.Add(selectedVictim, false); + } + + var query = EntityQueryEnumerator(); + + while (query.MoveNext(out var uid, out var killCultistTargetsComponent)) + { + _cultistTargetsConditionSystem.RefresTitle(uid, rule.CultTargets, killCultistTargetsComponent); + } + } + protected override void Added(EntityUid uid, BloodCultRuleComponent component, GameRuleComponent gameRule, @@ -133,8 +197,7 @@ public sealed class BloodCultRuleSystem : GameRuleSystem private void OnAfterAntagSelectionComplete(Entity ent, ref AntagSelectionCompleteEvent args) { - var selectedCultist = args.GameRule.Comp.AssignedMinds.Select(m => m.Item1).ToList(); - var potentialTargets = FindPotentialTargets(selectedCultist); + var potentialTargets = FindPotentialTargets(); var priorityTargets = potentialTargets .Where(target => @@ -152,14 +215,17 @@ public sealed class BloodCultRuleSystem : GameRuleSystem var selectedVictims = SelectRandomTargets(priorityTargets, numTargets); selectedVictims.AddRange(SelectRandomTargets(potentialTargets, numTargets - selectedVictims.Count)); - ent.Comp.CultTargets.AddRange(selectedVictims); + foreach (var selectedVictim in selectedVictims) + { + ent.Comp.CultTargets.Add(selectedVictim, false); + EnsureComp(selectedVictim); + } var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var killCultistTargetsComponent)) { - _cultistTargetsConditionSystem.SetTargets(uid, killCultistTargetsComponent, ent.Comp.CultTargets); - _cultistTargetsConditionSystem.RefresTitle(uid, killCultistTargetsComponent); + _cultistTargetsConditionSystem.RefresTitle(uid, ent.Comp.CultTargets, killCultistTargetsComponent); } } @@ -208,15 +274,10 @@ public sealed class BloodCultRuleSystem : GameRuleSystem while (query.MoveNext(out _, out var cultRuleComponent, out _)) { - var targetsKilled = true; - - foreach (var target in cultRuleComponent.CultTargets) + if (cultRuleComponent.CultTargets.Values.All(value => value)) { - targetsKilled = !_mobState.IsDead(target) || _entityManager.EntityExists(target); - } - - if (targetsKilled) return true; + } } return false; @@ -273,7 +334,7 @@ public sealed class BloodCultRuleSystem : GameRuleSystem if (_mindSystem.TryGetMind(uid, out var mindId, out var mind)) { - if (_mindSystem.TryFindObjective((mindId, mind), CultistKillObjective, out var objective)) + if (_mindSystem.TryFindObjective((mindId, mind), _cultistKillObjective, out var objective)) { _mindSystem.TryRemoveObjective(mindId, mind, mind.Objectives.IndexOf(objective.Value)); } @@ -360,14 +421,14 @@ public sealed class BloodCultRuleSystem : GameRuleSystem } } - private List FindPotentialTargets(List exclude) + private List FindPotentialTargets() { var potentialTargets = new List(); var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var mind, out _, out _)) { - if (mind.Mind == null || exclude.Contains(mind.Mind.Value)) + if (mind.Mind == null || HasComp(uid)) continue; potentialTargets.Add(uid); @@ -381,7 +442,7 @@ public sealed class BloodCultRuleSystem : GameRuleSystem if (!_mindSystem.TryGetMind(cultist, out var mindId, out var mind)) return false; - _roles.MindAddRole(mindId, MindRoleCultistPrototypeId); + _roles.MindAddRole(mindId, _mindRoleCultistPrototypeId); var isHumanoid = HasComp(cultist); diff --git a/Content.Server/_Sunrise/BloodCult/Objectives/Components/KillCultistTargetConditionComponent.cs b/Content.Server/_Sunrise/BloodCult/Objectives/Components/KillCultistTargetConditionComponent.cs index 8efec12c1b..1c0588098a 100644 --- a/Content.Server/_Sunrise/BloodCult/Objectives/Components/KillCultistTargetConditionComponent.cs +++ b/Content.Server/_Sunrise/BloodCult/Objectives/Components/KillCultistTargetConditionComponent.cs @@ -5,8 +5,6 @@ namespace Content.Server._Sunrise.BloodCult.Objectives.Components; [RegisterComponent, Access(typeof(KillCultistTargetsConditionSystem))] public sealed partial class KillCultistTargetsConditionComponent : Component { - public List Targets = new(); - [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] public string Title = string.Empty; } diff --git a/Content.Server/_Sunrise/BloodCult/Objectives/Systems/KillCultistTargetConditionSystem.cs b/Content.Server/_Sunrise/BloodCult/Objectives/Systems/KillCultistTargetConditionSystem.cs index 01c9f74e23..d026fd89f6 100644 --- a/Content.Server/_Sunrise/BloodCult/Objectives/Systems/KillCultistTargetConditionSystem.cs +++ b/Content.Server/_Sunrise/BloodCult/Objectives/Systems/KillCultistTargetConditionSystem.cs @@ -3,7 +3,6 @@ using System.Linq; using Content.Server._Sunrise.BloodCult.GameRule; using Content.Server._Sunrise.BloodCult.Objectives.Components; using Content.Shared.Mind; -using Content.Shared.Mobs.Systems; using Content.Shared.Objectives.Components; using Content.Shared.Roles.Jobs; @@ -14,8 +13,6 @@ public sealed class KillCultistTargetsConditionSystem : EntitySystem [Dependency] private readonly SharedJobSystem _job = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly SharedMindSystem _mind = default!; - [Dependency] private readonly MobStateSystem _mobState = default!; - [Dependency] private readonly EntityManager _entityManager = default!; public override void Initialize() { @@ -24,39 +21,28 @@ public sealed class KillCultistTargetsConditionSystem : EntitySystem SubscribeLocalEvent(OnGetProgress); SubscribeLocalEvent(OnPersonAssigned); - SubscribeLocalEvent(OnAfterAssign); } - public void SetTargets(EntityUid uid, KillCultistTargetsConditionComponent comp, List targets) + public void RefresTitle(EntityUid uid, Dictionary targets, KillCultistTargetsConditionComponent comp) { - comp.Targets = targets; + _metaData.SetEntityName(uid, GetTitle(targets, comp.Title)); } - public void RefresTitle(EntityUid uid, KillCultistTargetsConditionComponent comp) - { - _metaData.SetEntityName(uid, GetTitle(comp.Targets, comp.Title)); - } - - private void OnAfterAssign(EntityUid uid, - KillCultistTargetsConditionComponent comp, - ref ObjectiveAfterAssignEvent args) - { - _metaData.SetEntityName(uid, GetTitle(comp.Targets, comp.Title), args.Meta); - } - - private string GetTitle(List targets, string title) + private string GetTitle(Dictionary targets, string title) { var targetsList = ""; foreach (var target in targets) { - if (!TryComp(target, out var mind) || mind.CharacterName == null) + if (!_mind.TryGetMind(target.Key, out var mindId, out var mind) || mind.CharacterName == null) continue; var targetName = mind.CharacterName; - var jobName = _job.MindTryGetJobName(target); + var jobName = _job.MindTryGetJobName(mindId); + var sacrificed = target.Value ? "\u2714" : "\u2718"; targetsList += Loc.GetString("objective-condition-cult-kill-target", ("targetName", targetName), - ("job", jobName)); + ("job", jobName), + ("status", sacrificed)); targetsList += "\n"; } @@ -67,34 +53,22 @@ public sealed class KillCultistTargetsConditionSystem : EntitySystem KillCultistTargetsConditionComponent comp, ref ObjectiveGetProgressEvent args) { - args.Progress = KillCultistTargetsProgress(args.MindId); + args.Progress = KillCultistTargetsProgress(); } private void OnPersonAssigned(EntityUid uid, KillCultistTargetsConditionComponent component, ref ObjectiveAssignedEvent args) { - // target already assigned - if (component.Targets.Count != 0) + var cultistRule = EntityManager.EntityQuery().FirstOrDefault(); + + if (cultistRule == null) return; - var cultistRule = EntityManager.EntityQuery().FirstOrDefault(); - Debug.Assert(cultistRule != null, nameof(cultistRule) + " != null"); - var cultTargets = cultistRule.CultTargets; - - component.Targets = cultTargets; + _metaData.SetEntityName(uid, GetTitle(cultistRule.CultTargets, component.Title)); } - private bool GetTagretProgress(EntityUid target) - { - // цель мертва или гибнута, в идеале перенести в sacrifice руны - if (_mobState.IsDead(target) || !_entityManager.EntityExists(target)) - return true; - - return false; - } - - private float KillCultistTargetsProgress(EntityUid? mindId) + private float KillCultistTargetsProgress() { var cultistRule = EntityManager.EntityQuery().FirstOrDefault(); Debug.Assert(cultistRule != null, nameof(cultistRule) + " != null"); @@ -110,7 +84,7 @@ public sealed class KillCultistTargetsConditionSystem : EntitySystem foreach (var cultTarget in cultTargets) { - if (GetTagretProgress(cultTarget)) + if (cultTarget.Value) { deadTargetsCount += 1; } diff --git a/Content.Server/_Sunrise/BloodCult/Runes/Systems/BloodCultSystem.Rune.cs b/Content.Server/_Sunrise/BloodCult/Runes/Systems/BloodCultSystem.Rune.cs index 9337bfb685..5f21211754 100644 --- a/Content.Server/_Sunrise/BloodCult/Runes/Systems/BloodCultSystem.Rune.cs +++ b/Content.Server/_Sunrise/BloodCult/Runes/Systems/BloodCultSystem.Rune.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Numerics; using Content.Server._Sunrise.BloodCult.GameRule; +using Content.Server._Sunrise.BloodCult.Objectives.Components; using Content.Server._Sunrise.BloodCult.Runes.Comps; using Content.Server.Atmos.Components; using Content.Server.Bible.Components; @@ -93,7 +94,9 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems private void TeleportRuneInit(EntityUid uid, CultRuneTeleportComponent component, MapInitEvent args) { - component.Label = Loc.GetString("cult-teleport-rune-default-label"); + var xform = Transform(uid); + var location = FormattedMessage.RemoveMarkupOrThrow(_navMap.GetNearestBeaconString((uid, xform), true)); + component.Label = location; } /* @@ -422,15 +425,22 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems var cultTargets = rule.CultTargets; + var isTarget = cultTargets.ContainsKey(victim.Value); + + if (isTarget) + { + result = Sacrifice(uid, victim.Value, args.User, args.Cultists, rule, isTarget); + args.Result = result; + return; + } + if (state.CurrentState != MobState.Dead) { var hasMind = _mindSystem.TryGetMind(victim.Value, out var mindId, out var mind); - var isTarget = cultTargets.Contains(victim.Value); - var jobAllowConvert = !HasComp(victim.Value); - if (hasMind && jobAllowConvert && !isTarget) + if (hasMind && jobAllowConvert) { if (args.Cultists.Count < component.ConvertMinCount) { @@ -474,6 +484,14 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems if (isTarget) { + rule.CultTargets[target] = true; + var query = EntityQueryEnumerator(); + + while (query.MoveNext(out var obj, out var killCultistTargetsComponent)) + { + _cultistTargetsConditionSystem.RefresTitle(obj, rule.CultTargets, killCultistTargetsComponent); + } + _bodySystem.GibBody(target); _bloodCultRuleSystem.ChangeSacrificeCount(rule, rule.SacrificeCount + 1); diff --git a/Content.Server/_Sunrise/BloodCult/Runes/Systems/BloodCultSystem.cs b/Content.Server/_Sunrise/BloodCult/Runes/Systems/BloodCultSystem.cs index db53763a50..527f28d3bc 100644 --- a/Content.Server/_Sunrise/BloodCult/Runes/Systems/BloodCultSystem.cs +++ b/Content.Server/_Sunrise/BloodCult/Runes/Systems/BloodCultSystem.cs @@ -1,4 +1,5 @@ using Content.Server._Sunrise.BloodCult.GameRule; +using Content.Server._Sunrise.BloodCult.Objectives.Systems; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Systems; using Content.Server.Chat.Systems; @@ -83,6 +84,7 @@ namespace Content.Server._Sunrise.BloodCult.Runes.Systems [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; [Dependency] private readonly NavMapSystem _navMap = default!; [Dependency] private readonly PullingSystem _pulling = default!; + [Dependency] private readonly KillCultistTargetsConditionSystem _cultistTargetsConditionSystem = default!; [ValidatePrototypeId] private static string SteelStackPrototypeId = "Steel"; diff --git a/Resources/Locale/ru-RU/_strings/_sunrise/blood-cult/cult.ftl b/Resources/Locale/ru-RU/_strings/_sunrise/blood-cult/cult.ftl index b26f88d41e..9fc4062a07 100644 --- a/Resources/Locale/ru-RU/_strings/_sunrise/blood-cult/cult.ftl +++ b/Resources/Locale/ru-RU/_strings/_sunrise/blood-cult/cult.ftl @@ -47,7 +47,7 @@ chat-manager-cult-channel-name = Культ chat-manager-send-cult-chat-wrap-message = [bold]\[{ $channelName }\] { $player }: { $message }[/bold] hud-chatbox-select-channel-Cult = Культ # Objectivies -objective-condition-cult-kill-target = { $targetName } [{ CAPITALIZE($job) }]. +objective-condition-cult-kill-target = { $targetName } ({ CAPITALIZE($job) }) - { $status } objective-condition-cult-kill-title = Жертвы: - { $targets }. + { $targets }