Files
OldThink/Content.Server/Changeling/Objectives/ChangelingConditionsSystem.cs
rhailrake aa8e31fa7e - add: Changeling antagonist (#2)
* Changeling WIP

* UI

* Pointers fix

* Moved out abilities

* Regenerate ability

* Fixed Regenerate ability
Prevent ghosting while regenerating

* Cleanup

* Base lesser form

* Finished Lesser Form && Transform

* Transform Sting

* Blind Sting

* Mute Sting
Added OnExamine on absorbed human

* Hallucination Sting
Changeling Absorb and transfer absorbed entities to absorber

* Cryogenic Sting

* Adrenaline Sacs

* Transform now uses Polymorph

* Armblade, Shield, Armor

* Tentacle Arm ability
Tentacle Gun system

* WIP with bugs

* WiP bugs

* fix implant transfer

* Fixed bugs with shop transfer and actions transfer

* Just in case

* Vi sitter i ventrilo och spelar DotA

* Fixes and proper LesserForm tracking

* !!!!!

* Fixed empty buttons

* WIP Gamerule
Ready - shop

* nerf stun time cause its sucks

* cleaning

* just in case

* Absorb DNA Objective.

* Partial objectives with bugs

* fix

* fix pointer

* Changeling objectives

* Changeling objectives №2

* Admin verb, game rule

* Fixed empty list check
Icons for objectives

* Changeling chat, changeling names etc.

* fix some merge errors

* - fix: Fixed all bugs with changeling

---------

Co-authored-by: Y-Parvus <yevhen.parvus@gmail.com>
Co-authored-by: Y-Parvus <61109031+Y-Parvus@users.noreply.github.com>
Co-authored-by: HitPanda <104197232+EnefFlow@users.noreply.github.com>
Co-authored-by: EnefFlow <regeto90@mail.ru>
2024-01-31 14:01:35 +00:00

237 lines
7.8 KiB
C#

using System.Linq;
using Content.Server.Changeling.Objectives.Components;
using Content.Server.Forensics;
using Content.Server.Mind;
using Content.Server.Objectives.Components;
using Content.Server.Objectives.Systems;
using Content.Server.Shuttles.Systems;
using Content.Shared.Changeling;
using Content.Shared.Mind;
using Content.Shared.Objectives.Components;
using Robust.Shared.Random;
namespace Content.Server.Changeling.Objectives;
public sealed class ChangelingConditionsSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly TargetObjectiveSystem _target = default!;
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly EmergencyShuttleSystem _emergencyShuttle = default!;
public override void Initialize()
{
base.Initialize();
// Absorb DNA condition
SubscribeLocalEvent<AbsorbDnaConditionComponent, ObjectiveAssignedEvent>(OnAbsorbDnaAssigned);
SubscribeLocalEvent<AbsorbDnaConditionComponent, ObjectiveAfterAssignEvent>(OnAbsorbDnaAfterAssigned);
SubscribeLocalEvent<AbsorbDnaConditionComponent, ObjectiveGetProgressEvent>(OnAbsorbDnaGetProgress);
//Absorb more genomes, than others changelings
SubscribeLocalEvent<AbsorbMoreConditionComponent, ObjectiveGetProgressEvent>(OnAbsorbMoreGetProgress);
//Absorb other changeling
SubscribeLocalEvent<PickRandomChangelingComponent, ObjectiveAssignedEvent>(OnAbsorbChangelingAssigned);
SubscribeLocalEvent<AbsorbChangelingConditionComponent, ObjectiveGetProgressEvent>(OnAbsorbChangelingGetProgress);
//Escape with identity
SubscribeLocalEvent<PickRandomIdentityComponent, ObjectiveAssignedEvent>(OnEscapeWithIdentityAssigned);
SubscribeLocalEvent<EscapeWithIdentityConditionComponent, ObjectiveGetProgressEvent>(OnEscapeWithIdentityGetProgress);
}
#region AbsorbDNA
private void OnAbsorbDnaAssigned(EntityUid uid, AbsorbDnaConditionComponent component, ref ObjectiveAssignedEvent args)
{
component.NeedToAbsorb = _random.Next(2, 6);
}
private void OnAbsorbDnaAfterAssigned(EntityUid uid, AbsorbDnaConditionComponent component, ref ObjectiveAfterAssignEvent args)
{
var title = Loc.GetString("objective-condition-absorb-dna", ("count", component.NeedToAbsorb));
_metaData.SetEntityName(uid, title, args.Meta);
}
private void OnAbsorbDnaGetProgress(EntityUid uid, AbsorbDnaConditionComponent component, ref ObjectiveGetProgressEvent args)
{
args.Progress = GetAbsorbProgress(args.Mind, component.NeedToAbsorb);
}
private float GetAbsorbProgress(MindComponent mind, int requiredDna)
{
if (!TryComp<ChangelingComponent>(mind.CurrentEntity, out var changelingComponent))
return 0f;
var absorbed = changelingComponent.AbsorbedEntities.Count - 1; // Because first - it's the owner
if (requiredDna == absorbed)
return 1f;
var progress = MathF.Min(absorbed/(float)requiredDna, 1f);
return progress;
}
#endregion
#region AbsorbMoreDNA
private void OnAbsorbMoreGetProgress(EntityUid uid, AbsorbMoreConditionComponent comp, ref ObjectiveGetProgressEvent args)
{
args.Progress = GetAbsorbMoreProgress(args.Mind);
}
private float GetAbsorbMoreProgress(MindComponent mind)
{
if (!TryComp<ChangelingComponent>(mind.CurrentEntity, out var changelingComponent))
return 0f;
var selfAbsorbed = changelingComponent.AbsorbedEntities.Count - 1; // Because first - it's the owner
var query = EntityQueryEnumerator<ChangelingComponent>();
List<int> otherAbsorbed = new();
while (query.MoveNext(out var uid, out var comp))
{
if (uid == mind.CurrentEntity)
continue; //don't include self
var absorbed = comp.AbsorbedEntities.Count - 1;
otherAbsorbed.Add(absorbed);
}
if (otherAbsorbed.Count == 0)
return 1f;
var isTheMost = otherAbsorbed.Max() < selfAbsorbed;
return isTheMost ? 1f : 0f;
}
#endregion
#region AbsorbChangeling
private void OnAbsorbChangelingAssigned(EntityUid uid, PickRandomChangelingComponent comp, ref ObjectiveAssignedEvent args)
{
if (!TryComp<TargetObjectiveComponent>(uid, out var target))
{
args.Cancelled = true;
return;
}
if (target.Target != null)
return;
foreach (var changelingRule in EntityQuery<ChangelingRuleComponent>())
{
var changelingMinds = changelingRule.ChangelingMinds
.Except(new List<EntityUid> { args.MindId })
.ToList();
if (changelingMinds.Count == 0)
{
args.Cancelled = true;
return;
}
_target.SetTarget(uid, _random.Pick(changelingMinds), target);
}
}
private void OnAbsorbChangelingGetProgress(EntityUid uid, AbsorbChangelingConditionComponent comp, ref ObjectiveGetProgressEvent args)
{
if (!_target.GetTarget(uid, out var target))
return;
args.Progress = GetAbsorbChangelingProgress(args.Mind, target.Value);
}
private float GetAbsorbChangelingProgress(MindComponent mind, EntityUid target)
{
if(!_mind.TryGetMind(mind.CurrentEntity!.Value, out var selfMindId, out _))
return 0f;
if (!TryComp<MindComponent>(target, out var targetMind))
return 0f;
if (!HasComp<ChangelingComponent>(targetMind.CurrentEntity))
return 0f;
if (!TryComp<AbsorbedComponent>(targetMind.CurrentEntity, out var absorbedComponent))
return 0f;
return absorbedComponent.AbsorberMind == selfMindId ? 1f : 0f;
}
#endregion
#region EscapeWithIdentity
private void OnEscapeWithIdentityAssigned(EntityUid uid, PickRandomIdentityComponent component, ref ObjectiveAssignedEvent args)
{
if (!TryComp<TargetObjectiveComponent>(uid, out var target))
{
args.Cancelled = true;
return;
}
if (target.Target != null)
return;
var allHumans = _mind.GetAliveHumansExcept(args.MindId);
if (allHumans.Count == 0)
{
args.Cancelled = true;
return;
}
_target.SetTarget(uid, _random.Pick(allHumans), target);
}
private void OnEscapeWithIdentityGetProgress(EntityUid uid, EscapeWithIdentityConditionComponent component, ref ObjectiveGetProgressEvent args)
{
if (!_target.GetTarget(uid, out var target))
return;
args.Progress = GetEscapeWithIdentityProgress(args.Mind, target.Value);
}
private float GetEscapeWithIdentityProgress(MindComponent mind, EntityUid target)
{
var progress = 0f;
if (!TryComp<DnaComponent>(mind.CurrentEntity, out var selfDna))
return 0f;
if (!TryComp<MindComponent>(target, out var targetMind))
return 0f;
if (!TryComp<DnaComponent>(targetMind.CurrentEntity, out var targetDna))
return 0f;
if (!TryComp<ChangelingComponent>(mind.CurrentEntity, out var changeling))
return 0f;
if (!changeling.AbsorbedEntities.ContainsKey(targetDna.DNA))
return 0f;
//Target absorbed by this changeling, so 50% of work is done
progress += 0.5f;
if (_emergencyShuttle.IsTargetEscaping(mind.CurrentEntity.Value) && selfDna.DNA == targetDna.DNA)
progress += 0.5f;
if (_emergencyShuttle.ShuttlesLeft)
return progress;
return progress;
}
#endregion
}