Исправление целей культа (#1883)

This commit is contained in:
Vigers Ray 2025-04-20 02:41:02 +03:00 committed by GitHub
parent b8bc2e353f
commit 78e6c80a70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 141 additions and 74 deletions

View file

@ -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<AntagTargetComponent>(ent);
cryostorageComponent.StoredPlayers.Add(ent);
Dirty(ent, comp);
UpdateCryostorageUIState((cryostorageEnt.Value, cryostorageComponent));
@ -348,3 +351,7 @@ public sealed class CryostorageSystem : SharedCryostorageSystem
}
}
}
public class CryostorageEnteredEvent
{
}

View file

@ -0,0 +1,6 @@
namespace Content.Server._Sunrise.BloodCult;
[RegisterComponent]
public sealed partial class BloodCultTargetComponent : Component
{
}

View file

@ -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<EntityUid> CultTargets = new();
public readonly Dictionary<EntityUid, bool> CultTargets = new();
[DataField]
public int MaxTargets = 3;
[DataField]
public int MinTargets = 3;
public int MinTargets = 1;
[DataField]
public int TargetsPerPlayer = 20;

View file

@ -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<BloodCultRuleComponent>
[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<BloodCultRuleComponent>
SubscribeLocalEvent<BloodCultistComponent, ComponentInit>(OnCultistComponentInit);
SubscribeLocalEvent<BloodCultistComponent, ComponentRemove>(OnCultistComponentRemoved);
SubscribeLocalEvent<BloodCultistComponent, MobStateChangedEvent>(OnCultistsStateChanged);
SubscribeLocalEvent<BloodCultTargetComponent, ComponentShutdown>(OnCultTargetDeleted);
SubscribeLocalEvent<BloodCultTargetComponent, CryostorageEnteredEvent>(OnCultTargetEnterCryo);
SubscribeLocalEvent<BloodCultRuleComponent, AfterAntagEntitySelectedEvent>(AfterEntitySelected);
SubscribeLocalEvent<BloodCultRuleComponent, AntagSelectionCompleteEvent>(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<BloodCultTargetComponent>(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<BloodCultTargetComponent>(uid);
AddCultTarget(rule);
}
}
public void AddCultTarget(BloodCultRuleComponent rule)
{
var potentialTargets = FindPotentialTargets();
potentialTargets.RemoveAll(rule.CultTargets.Keys.Contains);
var priorityTargets = potentialTargets
.Where(target =>
HasComp<BibleUserComponent>(target) ||
HasComp<MindShieldComponent>(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<KillCultistTargetsConditionComponent>();
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<BloodCultRuleComponent>
private void OnAfterAntagSelectionComplete(Entity<BloodCultRuleComponent> 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<BloodCultRuleComponent>
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<BloodCultTargetComponent>(selectedVictim);
}
var query = EntityQueryEnumerator<KillCultistTargetsConditionComponent>();
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<BloodCultRuleComponent>
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<BloodCultRuleComponent>
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<BloodCultRuleComponent>
}
}
private List<EntityUid> FindPotentialTargets(List<EntityUid> exclude)
private List<EntityUid> FindPotentialTargets()
{
var potentialTargets = new List<EntityUid>();
var query = EntityQueryEnumerator<MindContainerComponent, AntagTargetComponent, HumanoidAppearanceComponent>();
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<BloodCultistComponent>(uid))
continue;
potentialTargets.Add(uid);
@ -381,7 +442,7 @@ public sealed class BloodCultRuleSystem : GameRuleSystem<BloodCultRuleComponent>
if (!_mindSystem.TryGetMind(cultist, out var mindId, out var mind))
return false;
_roles.MindAddRole(mindId, MindRoleCultistPrototypeId);
_roles.MindAddRole(mindId, _mindRoleCultistPrototypeId);
var isHumanoid = HasComp<HumanoidAppearanceComponent>(cultist);

View file

@ -5,8 +5,6 @@ namespace Content.Server._Sunrise.BloodCult.Objectives.Components;
[RegisterComponent, Access(typeof(KillCultistTargetsConditionSystem))]
public sealed partial class KillCultistTargetsConditionComponent : Component
{
public List<EntityUid> Targets = new();
[DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
public string Title = string.Empty;
}

View file

@ -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<KillCultistTargetsConditionComponent, ObjectiveGetProgressEvent>(OnGetProgress);
SubscribeLocalEvent<KillCultistTargetsConditionComponent, ObjectiveAssignedEvent>(OnPersonAssigned);
SubscribeLocalEvent<KillCultistTargetsConditionComponent, ObjectiveAfterAssignEvent>(OnAfterAssign);
}
public void SetTargets(EntityUid uid, KillCultistTargetsConditionComponent comp, List<EntityUid> targets)
public void RefresTitle(EntityUid uid, Dictionary<EntityUid, bool> 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<EntityUid> targets, string title)
private string GetTitle(Dictionary<EntityUid, bool> targets, string title)
{
var targetsList = "";
foreach (var target in targets)
{
if (!TryComp<MindComponent>(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<BloodCultRuleComponent>().FirstOrDefault();
if (cultistRule == null)
return;
var cultistRule = EntityManager.EntityQuery<BloodCultRuleComponent>().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<BloodCultRuleComponent>().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;
}

View file

@ -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<MindShieldComponent>(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<KillCultistTargetsConditionComponent>();
while (query.MoveNext(out var obj, out var killCultistTargetsComponent))
{
_cultistTargetsConditionSystem.RefresTitle(obj, rule.CultTargets, killCultistTargetsComponent);
}
_bodySystem.GibBody(target);
_bloodCultRuleSystem.ChangeSacrificeCount(rule, rule.SacrificeCount + 1);

View file

@ -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<StackPrototype>]
private static string SteelStackPrototypeId = "Steel";

View file

@ -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 }