Abductor fix (#2540)

Co-authored-by: SplikZerys <tronezero700@yandex.ru>
This commit is contained in:
iertis 2025-07-13 19:51:20 +05:00 committed by GitHub
parent c1de07bef1
commit 8dc0345fce
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 197 additions and 36 deletions

View file

@ -56,6 +56,8 @@ public sealed class AbductorCameraConsoleBui : BoundUserInterface
if (_window == null)
return;
_window.Beacons.DisposeAllChildren();
_station = station;
foreach (var beacon in beacons)
@ -83,7 +85,6 @@ public sealed class AbductorCameraConsoleBui : BoundUserInterface
return;
_window!.Stations.DisposeAllChildren();
_window.Beacons.DisposeAllChildren();
foreach (var station in state.Stations)
{
@ -114,7 +115,7 @@ public sealed class AbductorCameraConsoleBui : BoundUserInterface
_window.Title = State is not AbductorCameraConsoleBuiState state
|| _station == null
|| !state.Stations.TryGetValue(_station.Value, out var station)
? "Stations"
? Loc.GetString($"abductor-camera-console-window-stations")
: Loc.GetString($"abductor-stations", ("station", station.Name));
}

View file

@ -27,7 +27,6 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
[Dependency] private readonly PopupSystem _popupSystem = default!;
private static readonly EntProtoId<InstantActionComponent> _gizmoMark = "ActionGizmoMark";
private static readonly EntProtoId<InstantActionComponent> _sendAgent = "ActionSendAgent";
private static readonly EntProtoId<InstantActionComponent> _sendYourself = "ActionSendYourself";
private static readonly EntProtoId<InstantActionComponent> _exitAction = "ActionExitConsole";
@ -185,6 +184,7 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
private void OnSendYourself(SendYourselfEvent ev)
{
_color.RaiseEffect(Color.FromHex("#BA0099"), new List<EntityUid>(1) { ev.Performer }, Filter.Pvs(ev.Performer, entityManager: EntityManager));
EnsureComp<TransformComponent>(ev.Performer, out var xform);
var effectEnt = SpawnAttachedTo(_teleportationEffectEntity, xform.Coordinates);
_xformSys.SetParent(effectEnt, ev.Performer);
@ -194,8 +194,10 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
EnsureComp<TimedDespawnComponent>(effect, out var despawnComp);
var @event = new AbductorSendYourselfDoAfterEvent(GetNetCoordinates(ev.Target));
var doAfter = new DoAfterArgs(EntityManager, ev.Performer, TimeSpan.FromSeconds(5), @event, ev.Performer);
_doAfter.TryStartDoAfter(doAfter);
ev.Handled = true;
}
@ -207,6 +209,7 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
while (query.MoveNext(out var uid, out var comp))
{
_color.RaiseEffect(Color.FromHex("#BA0099"), new List<EntityUid>(1) { uid }, Filter.Pvs(uid, entityManager: EntityManager));
EnsureComp<TransformComponent>(uid, out var xform);
var effectEnt = SpawnAttachedTo(_teleportationEffectEntity, xform.Coordinates);
_xformSys.SetParent(effectEnt, uid);
@ -217,13 +220,17 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
var @event = new AbductorSendYourselfDoAfterEvent(GetNetCoordinates(ev.Target)); // не знаю пригодится ли тут дуафтер, нужно тестить с несколькими клиентами
var doAfter = new DoAfterArgs(EntityManager, uid, TimeSpan.FromSeconds(5), @event, uid);
foundAny = true;
_doAfter.TryStartDoAfter(doAfter);
ev.Handled = true;
RemComp<AbductorOnAlienPadComponent>(uid);
}
if (!foundAny)
{
_popupSystem.PopupCursor("alian-pad-is-empty", ev.Performer);
_popupSystem.PopupCursor(Loc.GetString("alian-pad-is-empty"), ev.Performer);
}
}
@ -302,10 +309,16 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
private void RemoveActions(EntityUid actor)
{
EnsureComp<AbductorsAbilitiesComponent>(actor, out var comp);
if (comp.ExitConsole is not null)
_actions.RemoveAction(actor, comp.ExitConsole);
if (comp.SendYourself is not null)
_actions.RemoveAction(actor, comp.SendYourself);
if (comp.SendAgent is not null)
_actions.RemoveAction(actor, comp.SendAgent);
if (comp.GizmoMark is not null)
_actions.RemoveAction(actor, comp.GizmoMark);

View file

@ -113,8 +113,10 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
&& TryComp<MindComponent>(mindContainer.Mind.Value, out var mind)
&& mind.Objectives.FirstOrDefault(HasComp<AbductConditionComponent>) is EntityUid objId
&& TryComp<AbductConditionComponent>(objId, out var condition)
&& !condition.AbductedHashs.Contains(GetNetEntity(victim)))
&& !condition.AbductedHashs.Contains(GetNetEntity(victim))
&& !victimComp.IsExperimentCompleted)
{
victimComp.IsExperimentCompleted = true;
condition.AbductedHashs.Add(GetNetEntity(victim));
condition.Abducted++;
component.Balance++;

View file

@ -26,6 +26,13 @@ using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Jittering;
using Robust.Shared.Toolshed.Commands.GameTiming;
using Content.Server.Speech.Components;
using Content.Server.Humanoid;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Coordinates;
using Discord.Rest;
using Content.Shared._Sunrise.Felinid;
namespace Content.Server._Sunrise.Antags.Abductor;
@ -33,11 +40,11 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
{
[Dependency] private readonly IGameTiming _time = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly IPrototypeManager _prototypes = default!;
[Dependency] private readonly AtmosphereSystem _atmos = default!;
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly SolutionContainerSystem _solutions = default!;
[Dependency] private readonly SolutionContainerSystem _type = default!;
[Dependency] private readonly SharedSolutionContainerSystem _solutions = default!;
[Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
private float _delayAccumulator = 0f;
@ -46,7 +53,7 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
public void InitializeOrgans()
{
foreach (var specif in _prototypes.EnumeratePrototypes<DamageTypePrototype>())
foreach (var specif in _prototypeManager.EnumeratePrototypes<DamageTypePrototype>())
_passiveHealing.DamageDict.Add(specif.ID, -1);
_stopwatch.Start();
}
@ -54,14 +61,16 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
public override void Update(float frameTime)
{
_delayAccumulator += frameTime;
if (_delayAccumulator > 3)
{
_delayAccumulator = 0;
_stopwatch.Restart();
var query = EntityQueryEnumerator<AbductorVictimComponent>();
while (query.MoveNext(out var uid, out var victim) && _stopwatch.Elapsed < TimeSpan.FromMilliseconds(0.5))
{
if(victim.Organ != AbductorOrganType.None)
if (victim.Organ != AbductorOrganType.None)
Do(uid, victim);
}
}
@ -69,43 +78,88 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
private void Do(EntityUid uid, AbductorVictimComponent victim)
{
if (HasComp<AbductorOwoTransformatedComponent>(uid))
return;
var curTime = _time.CurTime;
switch (victim.Organ)
{
case AbductorOrganType.Health:
if(_time.CurTime - victim.LastActivation < TimeSpan.FromSeconds(3))
if (curTime - victim.LastActivation < TimeSpan.FromSeconds(3))
return;
victim.LastActivation = _time.CurTime;
victim.LastActivation = curTime;
_damageable.TryChangeDamage(uid, _passiveHealing);
break;
case AbductorOrganType.Gravity:
if (_time.CurTime - victim.LastActivation < TimeSpan.FromSeconds(120))
if (curTime - victim.LastActivation < TimeSpan.FromSeconds(120))
return;
victim.LastActivation = _time.CurTime;
victim.LastActivation = curTime;
var gravity = SpawnAttachedTo("AbductorGravityGlandGravityWell", Transform(uid).Coordinates);
_xformSys.SetParent(gravity, uid);
break;
case AbductorOrganType.Egg:
if (_time.CurTime - victim.LastActivation < TimeSpan.FromSeconds(120))
if (curTime - victim.LastActivation < TimeSpan.FromSeconds(120))
return;
victim.LastActivation = _time.CurTime;
victim.LastActivation = curTime;
SpawnAttachedTo("FoodEggChickenFertilized", Transform(uid).Coordinates);
break;
case AbductorOrganType.Spider:
if (_time.CurTime - victim.LastActivation < TimeSpan.FromSeconds(240))
if (curTime - victim.LastActivation < TimeSpan.FromSeconds(240))
return;
victim.LastActivation = _time.CurTime;
victim.LastActivation = curTime;
SpawnAttachedTo("EggSpiderFertilized", Transform(uid).Coordinates);
break;
case AbductorOrganType.Ephedrine:
if (_time.CurTime - victim.LastActivation < TimeSpan.FromSeconds(120))
if (curTime - victim.LastActivation < TimeSpan.FromSeconds(120))
return;
victim.LastActivation = _time.CurTime;
victim.LastActivation = curTime;
TryComp<SolutionContainerManagerComponent>(uid, out var solution);
if (_solutions.TryGetInjectableSolution(uid, out var injectable, out _))
{
_solutions.TryAddReagent(injectable.Value, "Ephedrine", 5f);
}
break;
case AbductorOrganType.Owo:
if (curTime > victim.TransformationTime)
{
if (HasComp<FelinidComponent>(uid))
return;
EnsureComp<AbductorOwoTransformatedComponent>(uid);
_popup.PopupEntity(Loc.GetString("owo-organ-transformation"), uid, PopupType.LargeCaution);
_audioSystem.PlayPvs(victim.Mew, uid);
SpawnAttachedTo("RMCExplosionEffectGrenadeShockWave", uid.ToCoordinates());
EnsureComp<OwOAccentComponent>(uid);
_humanoid.AddMarking(uid, "CatTail");
_humanoid.AddMarking(uid, "CatEars"); // На ласте еще добавлять костюм горничной и лапки, why not
}
break;
case AbductorOrganType.EMP:
if (curTime - victim.LastActivation < TimeSpan.FromSeconds(120))
return;
victim.LastActivation = curTime;
SpawnAttachedTo("AdminInstantEffectEMP", Transform(uid).Coordinates);
break;
default:
break;
}

View file

@ -100,8 +100,6 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
_eye.SetTarget(args.Actor, eye, eyeComp);
_eye.SetDrawFov(args.Actor, false);
if (!HasComp<StationAiOverlayComponent>(args.Actor))
AddComp(args.Actor, new StationAiOverlayComponent { AllowCrossGrid = true });
if (!TryComp(eye, out RemoteEyeSourceContainerComponent? remoteEyeSourceContainerComponent))
{
remoteEyeSourceContainerComponent = new RemoteEyeSourceContainerComponent { Actor = args.Actor };
@ -142,9 +140,6 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
if (TryComp(actor, out EyeComponent? eyeComp))
{
if (HasComp<StationAiOverlayComponent>(actor))
RemComp<StationAiOverlayComponent>(actor);
_eye.SetVisibilityMask(actor, eyeComp.VisibilityMask ^ (int)VisibilityFlags.Abductor, eyeComp);
_eye.SetDrawFov(actor, true);
}

View file

@ -16,6 +16,8 @@ using Content.Shared._Sunrise.Medical.Surgery.Steps.Parts;
using Content.Shared._Sunrise.VentCraw;
using Content.Shared.CombatMode.Pacification;
using Robust.Shared.Prototypes;
using Content.Server.Speech.Components;
using Robust.Shared.Timing;
namespace Content.Server._Sunrise.Medical.Surgery;
public sealed partial class OrganSystem : EntitySystem
@ -24,7 +26,10 @@ public sealed partial class OrganSystem : EntitySystem
[Dependency] private readonly BlindableSystem _blindable = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly IComponentFactory _compFactory = default!;
[Dependency] private readonly HumanoidAppearanceSystem _humanoidAppearanceSystem = default!;
[Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
[Dependency] private readonly IGameTiming _timing = default!;
public override void Initialize()
{
@ -89,12 +94,24 @@ public sealed partial class OrganSystem : EntitySystem
private void OnAbductorOrganImplanted(Entity<AbductorOrganComponent> ent, ref SurgeryOrganImplantationCompleted args)
{
if (TryComp<AbductorVictimComponent>(args.Body, out var victim))
victim.Organ = ent.Comp.Organ;
EnsureComp<AbductorVictimComponent>(args.Body, out var victim);
victim.Organ = ent.Comp.Organ;
if (ent.Comp.Organ == AbductorOrganType.Vent)
AddComp<VentCrawlerComponent>(args.Body);
if (ent.Comp.Organ == AbductorOrganType.Pacified)
AddComp<PacifiedComponent>(args.Body);
if (ent.Comp.Organ == AbductorOrganType.Liar)
{
EnsureComp<ReplacementAccentComponent>(args.Body, out var accent);
accent.Accent = "liar";
}
if (ent.Comp.Organ == AbductorOrganType.Owo)
victim.TransformationTime += _timing.CurTime;
}
private void OnAbductorOrganExtracted(Entity<AbductorOrganComponent> ent, ref SurgeryOrganExtracted args)
{
@ -104,8 +121,20 @@ public sealed partial class OrganSystem : EntitySystem
if (ent.Comp.Organ == AbductorOrganType.Vent)
RemComp<VentCrawlerComponent>(args.Body);
if (ent.Comp.Organ == AbductorOrganType.Pacified)
RemComp<PacifiedComponent>(args.Body);
if (ent.Comp.Organ == AbductorOrganType.Liar)
RemComp<ReplacementAccentComponent>(args.Body);
if (ent.Comp.Organ == AbductorOrganType.Owo)
{
RemComp<AbductorOwoTransformatedComponent>(args.Body);
RemComp<OwOAccentComponent>(args.Body);
_humanoid.RemoveMarking(args.Body, "CatEars");
_humanoid.RemoveMarking(args.Body, "CatTail");
}
}
//
@ -143,10 +172,10 @@ public sealed partial class OrganSystem : EntitySystem
//
private void OnVisualizationExtracted(Entity<OrganVisualizationComponent> ent, ref SurgeryOrganExtracted args)
=> _humanoidAppearanceSystem.SetLayersVisibility(args.Body, [ent.Comp.Layer], false);
=> _humanoid.SetLayersVisibility(args.Body, [ent.Comp.Layer], false);
private void OnVisualizationImplanted(Entity<OrganVisualizationComponent> ent, ref SurgeryOrganImplantationCompleted args)
{
_humanoidAppearanceSystem.SetLayersVisibility(args.Body, [ent.Comp.Layer], true);
_humanoidAppearanceSystem.SetBaseLayerId(args.Body, ent.Comp.Layer, ent.Comp.Prototype);
_humanoid.SetLayersVisibility(args.Body, [ent.Comp.Layer], true);
_humanoid.SetBaseLayerId(args.Body, ent.Comp.Layer, ent.Comp.Prototype);
}
}

View file

@ -418,7 +418,10 @@ public abstract class SharedActionsSystem : EntitySystem
if (user == target)
return comp.CanTargetSelf;
// Sunrise-start
if (HasComp<AbductorComponent>(target))
return true;
// Sunrise-end
var targetAction = Comp<TargetActionComponent>(uid);
// not using the ValidateBaseTarget logic since its raycast fails if the target is e.g. a wall
if (targetAction.CheckCanAccess)

View file

@ -18,6 +18,9 @@ public enum AbductorOrganType : byte
Vent,
Pacified,
Ephedrine,
Liar,
Owo,
EMP
}
[Serializable, NetSerializable]
public enum AbductorArmorModeType : byte

View file

@ -1,6 +1,7 @@
using Content.Shared.Actions;
using Content.Shared.Communications;
using Content.Shared.Ninja.Systems;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
@ -25,6 +26,20 @@ public sealed partial class AbductorVictimComponent : Component
[DataField]
public TimeSpan? LastActivation;
[ViewVariables]
public TimeSpan TransformationTime = TimeSpan.FromSeconds(180);
[ViewVariables]
public SoundSpecifier Mew = new SoundPathSpecifier("/Audio/_Sunrise/Voice/Felinid/cat_mew2.ogg");
[ViewVariables, AutoNetworkedField]
public bool IsExperimentCompleted;
}
[RegisterComponent, NetworkedComponent]
public sealed partial class AbductorOwoTransformatedComponent : Component
{
}
[RegisterComponent, NetworkedComponent, Access(typeof(SharedAbductorSystem)), AutoGenerateComponentState]

View file

@ -3,6 +3,8 @@
abductors-ui-beacons = Маяки
abductors-ui-stations = < Станции
abductor-camera-console-window = Перехваченные камеры
abductor-stations = Доступные маяки
abductor-camera-console-window-stations = Станции
# Роль призрака, задачи и т.д.

View file

@ -18,3 +18,4 @@ target-is-not-abductor = Цель не является абдуктором!
no-gizmo-in-pockets = В карманах отсутствует гизмо!
gizmo-is-successfully-filled = Гизмо успешно заполнен
gizmo-is-not-in-pockets = В карманах нету гизмо!
owo-organ-transformation = ВЫ КОШКОФИЦИРОВАЛИСЬ!!

View file

@ -645,7 +645,7 @@
- type: accent
id: liar
replacementChance: 0.15
replacementChance: 0.4 # Sunrise-edit
wordReplacements:
liar-word-1: liar-word-replacement-1
liar-word-2: liar-word-replacement-2

View file

@ -91,7 +91,7 @@
description: return to the ship.
components:
- type: Action
useDelay: 30
useDelay: 10
priority: -12
checkConsciousness: false
checkCanInteract: false

View file

@ -39,6 +39,18 @@
- type: AbductorOrgan
organ: Health
- type: entity
id: OrganDubiousLiar
parent: [BaseOrganDubious]
name: gland
description: Suspicious alien gland, replaces the heart.
components:
- type: Sprite
sprite: _Sunrise/Mobs/Species/Cyberlimbs/dubious-organs.rsi
state: health
- type: AbductorOrgan
organ: Liar
- type: entity
id: OrganDubiousGravity
parent: [BaseOrganDubious]
@ -51,6 +63,18 @@
- type: AbductorOrgan
organ: Gravity
- type: entity
id: OrganDubiousOwo # nya~
parent: [BaseOrganDubious]
name: gland
description: Suspicious alien gland, replaces the heart.
components:
- type: Sprite
sprite: _Sunrise/Mobs/Species/Cyberlimbs/dubious-organs.rsi
state: slime
- type: AbductorOrgan
organ: Owo
- type: entity
id: OrganDubiousEgg
parent: [BaseOrganDubious]
@ -63,6 +87,18 @@
- type: AbductorOrgan
organ: Egg
- type: entity
id: OrganDubiousEMP
parent: [BaseOrganDubious]
name: gland
description: Suspicious alien gland, replaces the heart.
components:
- type: Sprite
sprite: _Sunrise/Mobs/Species/Cyberlimbs/dubious-organs.rsi
state: egg
- type: AbductorOrgan
organ: EMP
- type: entity
id: OrganDubiousSpider
parent: [BaseOrganDubious]
@ -134,3 +170,8 @@
- id: OrganDubiousEgg
- id: OrganDubiousSpider
- id: OrganDubiousVent
- id: OrganDubiousEphedrine
- id: OrganDubiousEMP
- id: OrganDubiousOwo
- id: OrganDubiousLiar
- id: OrganDubiousPacified

View file

@ -9,6 +9,8 @@
- Abductor
- AbductorScientist
- CanPilot
- DoorBumpOpener
- FootstepSound
- type: entity
name: abductor scientist

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB