Снова абдукторы (#2705)

This commit is contained in:
iertis 2025-08-04 22:29:20 +05:00 committed by GitHub
parent d85c749552
commit dd73908949
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 272 additions and 93 deletions

View file

@ -16,6 +16,7 @@ using Content.Shared.Hands.EntitySystems;
using Robust.Server.GameObjects;
using Content.Shared.Tag;
using Robust.Server.Containers;
using Robust.Shared.Toolshed.TypeParsers;
namespace Content.Server._Sunrise.Antags.Abductor;
@ -35,6 +36,8 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly SharedVirtualItemSystem _virtualItem = default!;
private EntityUid? _opener;
public override void Initialize()
{
SubscribeLocalEvent<AbductorHumanObservationConsoleComponent, BeforeActivatableUIOpenEvent>(OnBeforeActivatableUIOpen);
@ -43,6 +46,7 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
SubscribeLocalEvent<AbductorComponent, GetVisMaskEvent>(OnAbductorGetVis);
Subs.BuiEvents<AbductorHumanObservationConsoleComponent>(AbductorCameraConsoleUIKey.Key, subs => subs.Event<AbductorBeaconChosenBuiMsg>(OnAbductorBeaconChosenBuiMsg));
InitializeActions();
InitializeGizmo();
InitializeConsole();
@ -60,110 +64,78 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
private void OnAbductorBeaconChosenBuiMsg(Entity<AbductorHumanObservationConsoleComponent> ent, ref AbductorBeaconChosenBuiMsg args)
{
OnCameraExit(args.Actor);
if (ent.Comp.RemoteEntityProto != null)
EntityUid eye;
_opener = args.Actor;
var beacon = _entityManager.GetEntity(args.Beacon.NetEnt);
var beaconCoords = Transform(beacon).Coordinates;
if (ent.Comp.RemoteEntity != null && TryGetEntity(ent.Comp.RemoteEntity, out var existingEye))
{
var beacon = _entityManager.GetEntity(args.Beacon.NetEnt);
var eye = SpawnAtPosition(ent.Comp.RemoteEntityProto, Transform(beacon).Coordinates);
ent.Comp.RemoteEntity = GetNetEntity(eye);
if (TryComp<HandsComponent>(args.Actor, out var handsComponent))
{
foreach (var hand in _hands.EnumerateHands(args.Actor, handsComponent))
{
if (hand.HeldEntity == null)
continue;
if (HasComp<UnremoveableComponent>(hand.HeldEntity))
continue;
_hands.DoDrop(args.Actor, hand, true, handsComponent);
}
if (_virtualItem.TrySpawnVirtualItemInHand(ent.Owner, args.Actor, out var virtItem1))
{
EnsureComp<UnremoveableComponent>(virtItem1.Value);
}
if (_virtualItem.TrySpawnVirtualItemInHand(ent.Owner, args.Actor, out var virtItem2))
{
EnsureComp<UnremoveableComponent>(virtItem2.Value);
}
}
var visibility = EnsureComp<VisibilityComponent>(eye);
Dirty(ent);
if (TryComp(args.Actor, out EyeComponent? eyeComp))
{
_eye.RefreshVisibilityMask(args.Actor);
_eye.SetTarget(args.Actor, eye, eyeComp);
_eye.SetDrawFov(args.Actor, false);
if (!TryComp(eye, out RemoteEyeSourceContainerComponent? remoteEyeSourceContainerComponent))
{
remoteEyeSourceContainerComponent = new RemoteEyeSourceContainerComponent { Actor = args.Actor };
AddComp(eye, remoteEyeSourceContainerComponent);
}
else
remoteEyeSourceContainerComponent.Actor = args.Actor;
Dirty(eye, remoteEyeSourceContainerComponent);
}
AddActions(args);
_mover.SetRelay(args.Actor, eye);
eye = existingEye.Value;
_xformSys.SetCoordinates(eye, beaconCoords);
}
}
private void OnCameraExit(EntityUid actor)
{
AbductorScientistComponent? scientistComp = null;
AbductorAgentComponent? agentComp = null;
if (TryComp<RelayInputMoverComponent>(actor, out var comp) && TryComp<AbductorScientistComponent>(actor, out scientistComp) || TryComp<AbductorAgentComponent>(actor, out agentComp))
else
{
EntityUid? console = null;
if (scientistComp != null && scientistComp.Console.HasValue)
console = scientistComp.Console.Value;
else if (agentComp != null && agentComp.Console.HasValue)
console = agentComp.Console.Value;
if (console == null || comp == null)
if (ent.Comp.RemoteEntityProto == null)
return;
var relay = comp.RelayEntity;
RemComp(actor, comp);
eye = SpawnAtPosition(ent.Comp.RemoteEntityProto, Transform(beacon).Coordinates);
ent.Comp.RemoteEntity = GetNetEntity(eye);
_virtualItem.DeleteInHandsMatching(actor, console.Value);
EnsureComp<VisibilityComponent>(eye);
if (TryComp(actor, out EyeComponent? eyeComp))
{
_eye.SetVisibilityMask(actor, eyeComp.VisibilityMask ^ (int)VisibilityFlags.Abductor, eyeComp);
_eye.SetDrawFov(actor, true);
}
RemoveActions(actor);
QueueDel(relay);
var remoteEyeSource = EnsureComp<RemoteEyeSourceContainerComponent>(eye);
remoteEyeSource.Actor = args.Actor;
Dirty(eye, remoteEyeSource);
}
AddVirtualItems(args.Actor, ent);
SetEye(args.Actor, eye, args);
Dirty(ent);
}
private void OnCameraExit(EntityUid actor)
{
if (!HasComp<RelayInputMoverComponent>(actor))
return;
EntityUid? console = null;
if (TryComp<AbductorScientistComponent>(actor, out var scientistComp) && scientistComp.Console is { } scientistConsole)
console = scientistConsole;
if (TryComp<AbductorAgentComponent>(actor, out var agentComp) && agentComp.Console is { } agentConsole)
console = agentConsole;
if (console == null)
return;
RemoveEye(actor);
_virtualItem.DeleteInHandsMatching(actor, console.Value);
_opener = null;
}
private void OnActivatableUIOpenAttemptEvent(Entity<AbductorHumanObservationConsoleComponent> ent, ref ActivatableUIOpenAttemptEvent args)
{
if (!HasComp<AbductorScientistComponent>(args.User) && !HasComp<AbductorAgentComponent>(args.User))
args.Cancel();
if (_opener != null && _opener != args.User)
{
_popup.PopupEntity(Loc.GetString("console-occupied"), args.User, args.User);
args.Cancel();
}
}
private void OnBeforeActivatableUIOpen(Entity<AbductorHumanObservationConsoleComponent> ent, ref BeforeActivatableUIOpenEvent args)
{
AbductorAgentComponent? agentComp = null;
if (!TryComp<AbductorScientistComponent>(args.User, out var scientistComp) && !TryComp<AbductorAgentComponent>(args.User, out agentComp))
return;
if (scientistComp != null)
if (TryComp<AbductorScientistComponent>(args.User, out var scientistComp))
scientistComp.Console = ent.Owner;
else if (agentComp != null)
if (TryComp<AbductorAgentComponent>(args.User, out var agentComp))
agentComp.Console = ent.Owner;
var stations = _stationSystem.GetStations();
@ -175,8 +147,6 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
|| !TryComp(station, out MetaDataComponent? stationMetaData))
return;
var mapId = Transform(grid).MapID;
if (!_entityManager.TryGetComponent<NavMapComponent>(grid, out var navMap))
return;
@ -190,4 +160,54 @@ public sealed partial class AbductorSystem : SharedAbductorSystem
_uiSystem.SetUiState(ent.Owner, AbductorCameraConsoleUIKey.Key, new AbductorCameraConsoleBuiState() { Stations = result });
}
private void SetEye(EntityUid uid, EntityUid eye, AbductorBeaconChosenBuiMsg args)
{
if (!TryComp(uid, out EyeComponent? eyeComp))
return;
AddComp(uid, new StationAiOverlayComponent { AllowCrossGrid = true });
_eye.RefreshVisibilityMask(uid);
_eye.SetTarget(uid, eye, eyeComp);
_eye.SetDrawFov(uid, false);
AddActions(args);
_mover.SetRelay(uid, eye);
}
private void RemoveEye(EntityUid uid)
{
if (!TryComp(uid, out EyeComponent? eyeComp))
return;
RemComp<RelayInputMoverComponent>(uid);
RemComp<StationAiOverlayComponent>(uid);
_eye.SetTarget(uid, null);
_eye.SetVisibilityMask(uid, eyeComp.VisibilityMask ^ (int)VisibilityFlags.Abductor, eyeComp);
_eye.SetDrawFov(uid, true);
RemoveActions(uid);
}
private void AddVirtualItems(EntityUid uid, EntityUid console)
{
if (!TryComp<HandsComponent>(uid, out var hands))
return;
foreach (var hand in _hands.EnumerateHands(uid, hands))
{
if (hand.HeldEntity == null || HasComp<UnremoveableComponent>(hand.HeldEntity))
continue;
_hands.DoDrop(uid, hand, true, hands);
}
if (_virtualItem.TrySpawnVirtualItemInHand(console, uid, out var virtItem1))
EnsureComp<UnremoveableComponent>(virtItem1.Value);
if (_virtualItem.TrySpawnVirtualItemInHand(console, uid, out var virtItem2))
EnsureComp<UnremoveableComponent>(virtItem2.Value);
}
}

View file

@ -62,6 +62,28 @@ public abstract partial class SharedMoverController
Dirty(relayEntity, targetComp);
_blocker.UpdateCanMove(uid);
}
// Sunrise-start
public void RemoveRelay(EntityUid uid)
{
if (!TryComp<RelayInputMoverComponent>(uid, out var moverComp))
return;
var relay = moverComp.RelayEntity;
if (TryComp(relay, out MovementRelayTargetComponent? targetComp))
{
targetComp.Source = EntityUid.Invalid;
Dirty(relay, targetComp);
RemCompDeferred<MovementRelayTargetComponent>(relay);
PhysicsSystem.UpdateIsPredicted(relay);
}
Dirty(uid, moverComp);
RemCompDeferred<RelayInputMoverComponent>(uid);
PhysicsSystem.UpdateIsPredicted(uid);
_blocker.UpdateCanMove(uid);
}
// Sunrise-end
private void OnRelayShutdown(Entity<RelayInputMoverComponent> entity, ref ComponentShutdown args)
{

View file

@ -45,6 +45,11 @@ public sealed partial class TeleportLocationsComponent : Component
/// </summary>
[DataField]
public LocId? Speech;
// Sunrise-start
[DataField]
public bool DeleteAfterUse;
// Sunrise-end
}
/// <summary>

View file

@ -55,5 +55,10 @@ public abstract partial class SharedTeleportLocationsSystem : EntitySystem
// Teleport's done, now tell the BUI to close if needed.
_ui.CloseUi(ent.Owner, TeleportLocationUiKey.Key);
// Sunrise-start
if (comp.DeleteAfterUse)
QueueDel(ent);
// Sunrise-end
}
}

View file

@ -4,5 +4,6 @@
source: "https://github.com/ss14Starlight/space-station-14"
- files: ["holopaper_open"]
license: "Custom"
copyright: 'ZAPSPLAT'
source: "https://www.zapsplat.com/sound-effect-category/rollover/"

View file

@ -29,5 +29,6 @@ abductors-ui-shop-WeaponAlien = Инопланетный пистолет
abductors-ui-shop-ClothingHeadHelmetAbductor = Шлем
abductors-ui-shop-AbductorGizmo = Гизмо
abductors-ui-shop-AbductorExtractor = Экстрактор сердца
abductors-ui-shop-MedkitCombat = Боевая аптечка
abductors-ui-shop-MedkitUniversal = Универсальная аптечка
abductors-ui-shop-Teleporter = Одноразовый телепорт
abductors-ui-shop-VendingMachineRestockAbductorDispenser = Пополнение диспенсера

View file

@ -20,3 +20,5 @@ gizmo-is-successfully-filled = Гизмо успешно заполнен
gizmo-is-not-in-pockets = В карманах нету гизмо!
owo-organ-transformation = ВЫ КОШКОФИЦИРОВАЛИСЬ!!
need-stop-carry = Нельзя переместиться пока кто-то на руках!
console-occupied = Консоль уже занята кем-то!
teleportation-device-window-title = Устройство телепортации

View file

@ -0,0 +1,26 @@
- type: entity
id: MedkitUniversalFilled
name: universal medkit
desc: Contains all types of medicine that you need.
suffix: Filled
parent: MedkitCombat
components:
- type: StorageFill
contents:
- id: MedicatedSuture
amount: 2
- id: RegenerativeMesh
amount: 2
- id: PillCanisterHyronalin
- id: BurnAutoInjector
amount: 2
- id: BruteAutoInjector
amount: 2
- id: SyringeSaline
amount: 2
- id: PillCanisterDylovene
- type: Storage
grid:
- 0,0,3,3
- type: Item
size: Huge

View file

@ -61,6 +61,7 @@
gloves: ClothingHandsGlovesCombat
shoes: ClothingShoesBootsCombat
pocket1: AbductorGizmo
id: AbductorIDCard
- type: startingGear
id: AbductorAgentGear
@ -74,6 +75,7 @@
pocket2: WeaponAlien
belt: ClothingAbductorBeltFilled
outerClothing: ClothingOuterArmorAbductor
id: AbductorIDCard
inhand:
- Wonderprod

View file

@ -374,3 +374,26 @@
- state: idstationminer
- type: PresetIdCard
job: MiningSpecialist
- type: entity
parent: [ IDCardStandard ]
id: AbductorIDCard
name: abductor ID card
components:
- type: Sprite
sprite: _Sunrise/Objects/Misc/id_cards.rsi
layers:
- state: abductor
- type: Access # get your access from your victims.
- type: AgentIDCard
- type: IdCard
bypassLogging: true
canMicrowave: false
jobTitle: job-name-unknown
- type: ActivatableUI
key: enum.AgentIDCardUiKey.Key
inHandsOnly: true
- type: UserInterface
interfaces:
enum.AgentIDCardUiKey.Key:
type: AgentIDCardBoundUserInterface

View file

@ -30,5 +30,5 @@
- type: InjectOnHit
limit: 20
reagents:
- ReagentId: MuteToxin
- ReagentId: MuteToxinAbductor
Quantity: 5

View file

@ -86,7 +86,7 @@
- type: InjectOnHit
limit: 20
reagents:
- ReagentId: Nocturine
- ReagentId: NocturineAbductor
Quantity: 2.5
damage: !type:ItemSwitchState

View file

@ -13,3 +13,24 @@
- state: green_bit
shader: unshaded
- state: refill_medical
- type: entity
id: AbductorTeleport
name: teleport device
parent: [ BaseItem, BaseMagicalContraband ]
components:
- type: UserInterface
interfaces:
enum.TeleportLocationUiKey.Key:
type: TeleportLocationsBoundUserInterface
- type: ActivatableUI
key: enum.TeleportLocationUiKey.Key
- type: Sprite
sprite: Objects/Devices/hand_teleporter.rsi
state: icon
- type: TeleportLocations
name: teleportation-device-window-title
teleportEffect: RadiationPulse
closeAfterTeleport: true
deleteAfterUse: true

View file

@ -144,3 +144,45 @@
damage:
types:
Poison: 5
- type: reagent
id: MuteToxinAbductor
name: reagent-name-mute-toxin
group: Narcotics
desc: reagent-desc-mute-toxin
physicalDesc: reagent-physical-desc-syrupy
color: "#000000"
boilingPoint: 255.0
meltingPoint: 36.0
metabolisms:
Narcotic:
effects:
- !type:GenericStatusEffect
key: Muted
component: Muted
type: Add
time: 80
refresh: true
- type: reagent
id: NocturineAbductor
name: reagent-name-nocturine
group: Narcotics
desc: reagent-desc-nocturine
physicalDesc: reagent-physical-desc-powdery
color: "#128e80"
boilingPoint: 444.0
meltingPoint: 128.0
metabolisms:
Narcotic:
effects:
- !type:GenericStatusEffect
conditions:
- !type:ReagentThreshold
reagent: NocturineAbductor
min: 8
key: ForcedSleep
component: ForcedSleeping
refresh: true
type: Add
time: 120

View file

@ -17,10 +17,16 @@
productEntity: AbductorGizmo
- type: abductorListing
id: MedkitCombat
name: abductors-ui-shop-MedkitCombat
id: MedkitUniversal
name: abductors-ui-shop-MedkitUniversal
cost: 2
productEntity: MedkitUniversalFilled
- type: abductorListing
id: AbductorTeleport
name: abductors-ui-shop-Teleporter
cost: 1
productEntity: MedkitCombatFilled
productEntity: AbductorTeleport
- type: abductorListing
id: WeaponAlien

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 B

View file

@ -141,6 +141,9 @@
},
{
"name": "idintern-tech"
},
{
"name": "abductor"
}
]
}