* yes (cherry picked from commit a6b5e1c66dfe4241977bcde753af594392164eca) * Is real, navernoe (#944) * its real * fix shield * remove comments game preset * maximum predicted * fixes * АААААААААААААААААААААААААААА ПОМОГИТЕ Я ЕБНУЛСЯ ПОКА ФИКСИЛ ЭТУ ЗАЛУПУ * govnoedit * secret (cherry picked from commit 22c7b68048590b5098efbfff0d0f5205d3a64c48) * [Feature/Tweaks] Raznoe (#934) * make thruster great again * make hardsuit hos great again * new ficha for medical hud * fix * vrode da * GOOOVNO REMIX REVERB EXTRA * fix * правки --------- Co-authored-by: BIGZi0348 <svalker0348@gmail.com> (cherry picked from commit 141e61a0449873842f46d83eff9e9ce857147d60) * Automatic changelog update (cherry picked from commit d14fe5fb6c934ed522df0b5bc453e4c04707a6db) * [Feature] Executions (#932) * based * cleanup * cleanup + fixes * fix * fix * fix ftl * Update Resources/Locale/ru-RU/_white/executions/execution.ftl Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update execution.ftl * правки * vrode norm * da --------- Co-authored-by: BIGZi0348 <118811750+BIGZi0348@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: BIGZi0348 <svalker0348@gmail.com> (cherry picked from commit 83e164172f8e290acee7634f14ac51281be020ad) * Automatic changelog update (cherry picked from commit 71f907c563a30a1fc7ef5751a4d6f2c780a14f4c) * hotfix (#946) (cherry picked from commit f577caec41ab277ee8fc1c18fe64f7e26a6e50f5) --------- Co-authored-by: RavmorganButOnCocaine <valtos@nextmail.ru>
369 lines
12 KiB
C#
369 lines
12 KiB
C#
using System.Linq;
|
|
using Content.Server._Miracle.GulagSystem;
|
|
using Content.Server.Actions;
|
|
using Content.Server.Antag;
|
|
using Content.Server.GameTicking.Components;
|
|
using Content.Server.GameTicking.Rules;
|
|
using Content.Server.Hands.Systems;
|
|
using Content.Server.Objectives.Components;
|
|
using Content.Server.RoundEnd;
|
|
using Content.Server.StationEvents.Components;
|
|
using Content.Shared.Body.Systems;
|
|
using Content.Shared.Humanoid;
|
|
using Content.Shared.Inventory;
|
|
using Content.Shared.Mind.Components;
|
|
using Content.Shared.Mobs;
|
|
using Content.Shared.Mobs.Components;
|
|
using Content.Shared.Mobs.Systems;
|
|
using Content.Shared.Roles;
|
|
using Robust.Shared.Player;
|
|
using Content.Shared._White.Antag;
|
|
using Content.Shared._White.Cult.Components;
|
|
using Content.Shared._White.Cult.Systems;
|
|
using Content.Shared._White.Mood;
|
|
using Content.Shared.Alert;
|
|
using Content.Shared.Cloning;
|
|
using Content.Shared.Mind;
|
|
using Robust.Server.Containers;
|
|
using Robust.Shared.Random;
|
|
|
|
namespace Content.Server._White.Cult.GameRule;
|
|
|
|
public sealed class CultRuleSystem : GameRuleSystem<CultRuleComponent>
|
|
{
|
|
[Dependency] private readonly InventorySystem _inventorySystem = default!;
|
|
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
|
|
[Dependency] private readonly RoundEndSystem _roundEndSystem = default!;
|
|
[Dependency] private readonly SharedBodySystem _bodySystem = default!;
|
|
[Dependency] private readonly SharedRoleSystem _roleSystem = default!;
|
|
[Dependency] private readonly SharedMindSystem _mindSystem = default!;
|
|
[Dependency] private readonly ActionsSystem _actions = default!;
|
|
[Dependency] private readonly BloodSpearSystem _bloodSpear = default!;
|
|
[Dependency] private readonly ContainerSystem _container = default!;
|
|
[Dependency] private readonly HandsSystem _hands = default!;
|
|
[Dependency] private readonly GulagSystem _gulag = default!;
|
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
|
[Dependency] private readonly IRobustRandom _random = default!;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<CultRuleComponent, AfterAntagEntitySelectedEvent>(AfterEntitySelected);
|
|
|
|
SubscribeLocalEvent<CultNarsieSummoned>(OnNarsieSummon);
|
|
|
|
SubscribeLocalEvent<CultistComponent, ComponentRemove>(OnCultistComponentRemoved);
|
|
SubscribeLocalEvent<CultistComponent, MobStateChangedEvent>(OnCultistsStateChanged);
|
|
SubscribeLocalEvent<CultistComponent, CloningEvent>(OnClone);
|
|
}
|
|
|
|
protected override void Added(EntityUid uid, CultRuleComponent rule, GameRuleComponent gameRule, GameRuleAddedEvent args)
|
|
{
|
|
base.Added(uid, rule, gameRule, args);
|
|
}
|
|
|
|
private void OnClone(Entity<CultistComponent> ent, ref CloningEvent args)
|
|
{
|
|
RemoveObjectiveAndRole(ent);
|
|
}
|
|
|
|
private void OnNarsieSummon(CultNarsieSummoned ev)
|
|
{
|
|
var query =
|
|
EntityQueryEnumerator<MobStateComponent, MindContainerComponent, CultistComponent, TransformComponent>();
|
|
|
|
List<Entity<MindContainerComponent, TransformComponent>> cultists = new();
|
|
|
|
while (query.MoveNext(out var uid, out _, out var mindContainer, out _, out var transform))
|
|
{
|
|
cultists.Add((uid, mindContainer, transform));
|
|
}
|
|
|
|
var rulesQuery = QueryActiveRules();
|
|
while (rulesQuery.MoveNext(out _, out var cult, out _))
|
|
{
|
|
cult.WinCondition = CultWinCondition.Win;
|
|
_roundEndSystem.EndRound();
|
|
|
|
foreach (var ent in cultists)
|
|
{
|
|
if (ent.Comp1.Mind is null)
|
|
continue;
|
|
|
|
var reaper = Spawn(cult.ReaperPrototype, ent.Comp2.Coordinates);
|
|
_mindSystem.TransferTo(ent.Comp1.Mind.Value, reaper);
|
|
|
|
_bodySystem.GibBody(ent);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
public void RemoveObjectiveAndRole(EntityUid uid)
|
|
{
|
|
if (!_mindSystem.TryGetMind(uid, out var mindId, out var mind))
|
|
return;
|
|
|
|
var objectives = mind.Objectives.FindAll(HasComp<PickCultTargetComponent>);
|
|
foreach (var obj in objectives)
|
|
{
|
|
_mindSystem.TryRemoveObjective(mindId, mind, mind.Objectives.IndexOf(obj));
|
|
}
|
|
|
|
if (_roleSystem.MindHasRole<CultistRoleComponent>(mindId))
|
|
_roleSystem.MindRemoveRole<CultistRoleComponent>(mindId);
|
|
}
|
|
|
|
private void OnCultistComponentRemoved(EntityUid uid, CultistComponent component, ComponentRemove args)
|
|
{
|
|
var query = QueryActiveRules();
|
|
while (query.MoveNext(out _, out var cult, out _))
|
|
{
|
|
cult.CurrentCultists.Remove(component);
|
|
}
|
|
|
|
if (!TerminatingOrDeleted(uid))
|
|
{
|
|
RemoveAllCultistItems(uid);
|
|
RemoveCultistAppearance(uid);
|
|
RaiseLocalEvent(uid, new MoodRemoveEffectEvent("CultFocused"));
|
|
_alertsSystem.ClearAlert(uid, AlertType.BloodSpells);
|
|
}
|
|
|
|
_bloodSpear.DetachSpearFromUser((uid, component));
|
|
|
|
foreach (var empower in component.SelectedEmpowers)
|
|
{
|
|
_actions.RemoveAction(uid, GetEntity(empower));
|
|
}
|
|
|
|
CheckRoundShouldEnd();
|
|
}
|
|
|
|
private void OnCultistsStateChanged(EntityUid uid, CultistComponent component, MobStateChangedEvent ev)
|
|
{
|
|
if (ev.NewMobState == MobState.Dead)
|
|
{
|
|
CheckRoundShouldEnd();
|
|
}
|
|
}
|
|
|
|
public MindComponent? GetTarget()
|
|
{
|
|
var query = QueryActiveRules();
|
|
while (query.MoveNext(out _, out var cult, out _))
|
|
{
|
|
if (cult.CultTarget == null || !TryComp(cult.CultTarget.Value, out MindComponent? mind))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
return mind;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public bool CanSummonNarsie()
|
|
{
|
|
var query = QueryActiveRules();
|
|
while (query.MoveNext(out _, out var cult, out _))
|
|
{
|
|
var cultistsAmount = cult.CurrentCultists.Count;
|
|
var constructsAmount = cult.Constructs.Count;
|
|
var enoughCultists = cultistsAmount + constructsAmount > 10;
|
|
|
|
if (!enoughCultists)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var target = GetTarget();
|
|
var targetKilled = target == null || _mindSystem.IsCharacterDeadIc(target);
|
|
|
|
return targetKilled;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void CheckRoundShouldEnd()
|
|
{
|
|
var query = QueryActiveRules();
|
|
while (query.MoveNext(out _, out var cult, out _))
|
|
{
|
|
var aliveCultists = 0;
|
|
|
|
foreach (var cultistComponent in cult.CurrentCultists)
|
|
{
|
|
var owner = cultistComponent.Owner;
|
|
if (!TryComp<MobStateComponent>(owner, out var mobState))
|
|
continue;
|
|
|
|
if (!_mobStateSystem.IsDead(owner, mobState))
|
|
{
|
|
aliveCultists++;
|
|
}
|
|
}
|
|
|
|
if (aliveCultists != 0)
|
|
return;
|
|
|
|
cult.WinCondition = CultWinCondition.Failure;
|
|
|
|
// Check for all at once gamemode
|
|
if (!GameTicker.GetActiveGameRules().Where(HasComp<RampingStationEventSchedulerComponent>).Any())
|
|
_roundEndSystem.EndRound();
|
|
}
|
|
}
|
|
|
|
private void RemoveCultistAppearance(EntityUid cultist)
|
|
{
|
|
if (TryComp<HumanoidAppearanceComponent>(cultist, out var appearanceComponent))
|
|
{
|
|
//Потому что я так сказал
|
|
appearanceComponent.EyeColor = Color.White;
|
|
Dirty(cultist, appearanceComponent);
|
|
}
|
|
|
|
RemComp<PentagramComponent>(cultist);
|
|
}
|
|
|
|
private void UpdateCultistsAppearance(CultRuleComponent cultRuleComponent)
|
|
{
|
|
var cultistsCount = cultRuleComponent.CurrentCultists.Count;
|
|
var constructsCount = cultRuleComponent.Constructs.Count;
|
|
var totalCultMembers = cultistsCount + constructsCount;
|
|
if (totalCultMembers >= cultRuleComponent.PentagramThreshold)
|
|
cultRuleComponent.Stage = CultStage.Pentagram;
|
|
else if (totalCultMembers >= cultRuleComponent.ReadEyeThreshold && cultRuleComponent.Stage == CultStage.Normal)
|
|
cultRuleComponent.Stage = CultStage.RedEyes;
|
|
|
|
if (cultRuleComponent.Stage == CultStage.Normal)
|
|
return;
|
|
|
|
foreach (var cultistComponent in cultRuleComponent.CurrentCultists)
|
|
{
|
|
var cultist = cultistComponent.Owner;
|
|
if (TryComp<HumanoidAppearanceComponent>(cultist, out var appearanceComponent))
|
|
{
|
|
appearanceComponent.EyeColor = cultRuleComponent.EyeColor;
|
|
Dirty(cultist, appearanceComponent);
|
|
}
|
|
|
|
if (cultRuleComponent.Stage != CultStage.Pentagram)
|
|
return;
|
|
|
|
EnsureComp<PentagramComponent>(cultist);
|
|
EnsureComp<GlobalAntagonistComponent>(cultist).AntagonistPrototype = "globalAntagonistCult";
|
|
}
|
|
}
|
|
|
|
private void AfterEntitySelected(Entity<CultRuleComponent> ent, ref AfterAntagEntitySelectedEvent args)
|
|
{
|
|
if (ent.Comp.CultTarget == null)
|
|
{
|
|
var potentialTargets = FindPotentialTargets();
|
|
if (potentialTargets.Count == 0)
|
|
{
|
|
ent.Comp.CultTarget = null;
|
|
return;
|
|
}
|
|
ent.Comp.CultTarget = _random.PickAndTake(potentialTargets).Mind;
|
|
}
|
|
|
|
MakeCultist(args.EntityUid, ent);
|
|
}
|
|
|
|
public void MakeCultist(EntityUid cultist, CultRuleComponent rule)
|
|
{
|
|
if (!_mindSystem.TryGetMind(cultist, out var mindId, out var mind))
|
|
return;
|
|
|
|
_mindSystem.TryAddObjective(mindId, mind, "KillCultTargetObjective");
|
|
|
|
if (!TryComp<CultistComponent>(cultist, out var cultistComponent))
|
|
return;
|
|
|
|
rule.CurrentCultists.Add(cultistComponent);
|
|
_alertsSystem.ShowAlert(cultist, AlertType.BloodSpells);
|
|
|
|
var name = Name(cultist);
|
|
|
|
if (TryComp<ActorComponent>(cultist, out var actor))
|
|
{
|
|
rule.CultistsCache.TryAdd(name, actor.PlayerSession.Name);
|
|
_mindSystem.TryGetMind(actor.PlayerSession.UserId, out var mindEnt);
|
|
cultistComponent.OriginalMind = mindEnt;
|
|
}
|
|
|
|
UpdateCultistsAppearance(rule);
|
|
}
|
|
|
|
private void RemoveAllCultistItems(EntityUid uid)
|
|
{
|
|
if (!_inventorySystem.TryGetContainerSlotEnumerator(uid, out var enumerator))
|
|
return;
|
|
|
|
while (enumerator.MoveNext(out var container))
|
|
{
|
|
if (container.ContainedEntity != null && HasComp<CultItemComponent>(container.ContainedEntity.Value))
|
|
{
|
|
_container.Remove(container.ContainedEntity.Value, container, true, true);
|
|
}
|
|
}
|
|
|
|
foreach (var item in _hands.EnumerateHeld(uid))
|
|
{
|
|
if (TryComp(item, out CultItemComponent? cultItem) && !cultItem.CanPickUp &&
|
|
!_hands.TryDrop(uid, item, null, false, false))
|
|
QueueDel(item);
|
|
}
|
|
}
|
|
|
|
public void TransferRole(EntityUid transferFrom, EntityUid transferTo)
|
|
{
|
|
if (HasComp<PentagramComponent>(transferFrom))
|
|
EnsureComp<PentagramComponent>(transferTo);
|
|
|
|
if (!HasComp<CultistComponent>(transferFrom))
|
|
return;
|
|
|
|
var query = EntityQuery<CultRuleComponent>();
|
|
foreach (var cultRule in query)
|
|
{
|
|
cultRule.CultistsCache.Remove(Name(transferFrom));
|
|
}
|
|
|
|
EnsureComp<CultistComponent>(transferTo);
|
|
RemComp<CultistComponent>(transferFrom);
|
|
}
|
|
|
|
private List<MindContainerComponent> FindPotentialTargets()
|
|
{
|
|
var query = EntityQueryEnumerator<MindContainerComponent, HumanoidAppearanceComponent, ActorComponent>();
|
|
|
|
var potentialTargets = new List<MindContainerComponent>();
|
|
|
|
while (query.MoveNext(out var uid, out var mind, out _, out var actor))
|
|
{
|
|
var entity = mind.Mind;
|
|
|
|
if (entity == default)
|
|
continue;
|
|
|
|
if (_gulag.IsUserGulagged(actor.PlayerSession.UserId, out _))
|
|
continue;
|
|
|
|
if (HasComp<CultistComponent>(uid))
|
|
continue;
|
|
|
|
potentialTargets.Add(mind);
|
|
}
|
|
|
|
return potentialTargets;
|
|
}
|
|
}
|