More artifacts triggers and tweaks (#6723)

Co-authored-by: mirrorcult <lunarautomaton6@gmail.com>
This commit is contained in:
Alex Evgrashin
2022-02-19 22:16:49 +03:00
committed by GitHub
parent 162af7add5
commit 6eeaa81131
32 changed files with 347 additions and 61 deletions

View File

@@ -306,6 +306,9 @@ namespace Content.Client.Entry
"TelepathicArtifact",
"ArtifactGasTrigger",
"ArtifactInteractionTrigger",
"ArtifactTimerTrigger",
"ArtifactHeatTrigger",
"ArtifactElectricityTrigger",
"Artifact",
"RandomArtifactSprite",
"EnergySword",

View File

@@ -14,6 +14,8 @@ using Content.Server.Inventory;
using Content.Server.Mind.Commands;
using Content.Server.Mind.Components;
using Content.Server.Players;
using Content.Server.Xenoarchaeology.XenoArtifacts;
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
using Content.Shared.Administration;
using Content.Shared.Body.Components;
using Content.Shared.Database;
@@ -47,6 +49,7 @@ namespace Content.Server.Administration
[Dependency] private readonly EuiManager _euiManager = default!;
[Dependency] private readonly ExplosionSystem _explosions = default!;
[Dependency] private readonly GhostRoleSystem _ghostRoleSystem = default!;
[Dependency] private readonly ArtifactSystem _artifactSystem = default!;
private readonly Dictionary<IPlayerSession, EditSolutionsEui> _openSolutionUis = new();
@@ -100,6 +103,29 @@ namespace Content.Server.Administration
});
}
// XenoArcheology
if (TryComp<ArtifactComponent>(args.Target, out var artifact))
{
// make artifact always active (by adding timer trigger)
args.Verbs.Add(new Verb()
{
Text = Loc.GetString("artifact-verb-make-always-active"),
Category = VerbCategory.Admin,
Act = () => EntityManager.AddComponent<ArtifactTimerTriggerComponent>(args.Target),
Disabled = EntityManager.HasComponent<ArtifactTimerTriggerComponent>(args.Target),
Impact = LogImpact.High
});
// force to activate artifact ignoring timeout
args.Verbs.Add(new Verb()
{
Text = Loc.GetString("artifact-verb-activate"),
Category = VerbCategory.Admin,
Act = () => _artifactSystem.ForceActivateArtifact(args.Target, component: artifact),
Impact = LogImpact.High
});
}
// TeleportTo
args.Verbs.Add(new Verb
{

View File

@@ -0,0 +1,11 @@
namespace Content.Server.Power.Events;
/// <summary>
/// Invoked on a target entity, when it was pulsed with an energy.
/// For instance, interacted with an active stun baton.
/// </summary>
public sealed class PowerPulseEvent : EntityEventArgs
{
public EntityUid? User;
public EntityUid? Used;
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Linq;
using Content.Server.Power.Events;
using Content.Server.PowerCell;
using Content.Server.Speech.EntitySystems;
using Content.Server.Stunnable.Components;
@@ -56,6 +57,7 @@ namespace Content.Server.Stunnable
foreach (EntityUid entity in args.HitEntities)
{
StunEntity(entity, comp);
SendPowerPulse(entity, args.User, uid);
}
}
@@ -69,6 +71,7 @@ namespace Content.Server.Stunnable
args.CanInteract = true;
StunEntity(args.Entity, comp);
SendPowerPulse(args.Entity, args.User, uid);
}
private void OnUseInHand(EntityUid uid, StunbatonComponent comp, UseInHandEvent args)
@@ -92,6 +95,7 @@ namespace Content.Server.Stunnable
return;
StunEntity(args.Target, comp);
SendPowerPulse(args.Target, args.User, uid);
}
private void OnPowerCellChanged(EntityUid uid, StunbatonComponent comp, PowerCellChangedEvent args)
@@ -197,5 +201,14 @@ namespace Content.Server.Stunnable
sprite.LayerSetState(0, "stunbaton_on");
comp.Activated = true;
}
private void SendPowerPulse(EntityUid target, EntityUid? user, EntityUid used)
{
RaiseLocalEvent(target, new PowerPulseEvent()
{
Used = used,
User = user
}, false);
}
}
}

View File

@@ -1,8 +1,3 @@
using System;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.Xenoarchaeology.XenoArtifacts;
[RegisterComponent]
@@ -21,7 +16,9 @@ public sealed class ArtifactComponent : Component
[DataField("possibleTriggers")]
public string[] PossibleTriggers = {
"ArtifactInteractionTrigger",
"ArtifactGasTrigger"
"ArtifactGasTrigger",
"ArtifactHeatTrigger",
"ArtifactElectricityTrigger",
};
/// <summary>

View File

@@ -1,6 +1,4 @@
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Random;
using Robust.Shared.Timing;
@@ -26,7 +24,7 @@ public sealed class ArtifactSystem : EntitySystem
}
}
public void AddRandomTrigger(EntityUid uid, ArtifactComponent? component = null)
private void AddRandomTrigger(EntityUid uid, ArtifactComponent? component = null)
{
if (!Resolve(uid, ref component))
return;

View File

@@ -1,7 +1,4 @@
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;

View File

@@ -1,7 +1,5 @@
using Content.Server.Radiation;
using Robust.Shared.GameObjects;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;

View File

@@ -1,10 +1,6 @@
using System.Collections.Generic;
using Robust.Shared.GameObjects;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
using Robust.Shared.ViewVariables;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;

View File

@@ -1,7 +1,3 @@
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
/// <summary>

View File

@@ -1,6 +1,4 @@
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
@@ -20,4 +18,11 @@ public sealed class TemperatureArtifactComponent : Component
[DataField("maxTempDif")]
public float MaxTemperatureDifference = 1;
/// <summary>
/// If true, artifact will heat/cool not only its current tile, but surrounding tiles too.
/// This will change room temperature much faster.
/// </summary>
[DataField("effectAdjacent")]
public bool EffectAdjacentTiles = true;
}

View File

@@ -2,8 +2,6 @@
using Content.Server.Atmos.EntitySystems;
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Random;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;

View File

@@ -1,7 +1,6 @@
using Content.Server.Radiation;
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
using Robust.Shared.GameObjects;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;

View File

@@ -2,9 +2,6 @@ using Content.Server.Clothing.Components;
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
using Content.Shared.Hands.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Random;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;

View File

@@ -2,9 +2,6 @@ using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
using Content.Shared.Popups;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Player;
using Robust.Shared.Random;

View File

@@ -1,9 +1,7 @@
using System;
using Content.Server.Atmos;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
@@ -21,10 +19,23 @@ public sealed class TemperatureArtifactSystem : EntitySystem
{
var transform = Transform(uid);
var environment = _atmosphereSystem.GetTileMixture(transform.Coordinates, true);
if (environment == null)
var center = _atmosphereSystem.GetTileMixture(transform.Coordinates, true);
if (center == null)
return;
UpdateTileTemperature(component, center);
if (component.EffectAdjacentTiles)
{
var adjacent = _atmosphereSystem.GetAdjacentTileMixtures(transform.Coordinates, invalidate: true);
foreach (var mixture in adjacent)
{
UpdateTileTemperature(component, mixture);
}
}
}
private void UpdateTileTemperature(TemperatureArtifactComponent component, GasMixture environment)
{
var dif = component.TargetTemperature - environment.Temperature;
var absDif = Math.Abs(dif);
if (absDif < component.MaxTemperatureDifference)

View File

@@ -1,5 +1,3 @@
using Robust.Shared.GameObjects;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Events;
/// <summary>

View File

@@ -1,6 +1,4 @@
using Robust.Shared.GameObjects;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Events;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Events;
/// <summary>
/// Force to randomize artifact triggers.

View File

@@ -1,8 +1,4 @@
using System;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Content.Server.Xenoarchaeology.XenoArtifacts;
namespace Content.Server.Xenoarchaeology.XenoArtifacts;
[RegisterComponent]
public sealed class RandomArtifactSpriteComponent : Component

View File

@@ -1,8 +1,5 @@
using System;
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
using Content.Shared.Xenoarchaeology.XenoArtifacts;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Random;
using Robust.Shared.Timing;

View File

@@ -0,0 +1,15 @@
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
/// <summary>
/// Activate artifact when it contacted with an electricity source.
/// It could be connected MV cables, stun baton or multi tool.
/// </summary>
[RegisterComponent]
public sealed class ArtifactElectricityTriggerComponent : Component
{
/// <summary>
/// How much power should artifact receive to operate.
/// </summary>
[DataField("minPower")]
public float MinPower = 400;
}

View File

@@ -1,7 +1,4 @@
using Content.Shared.Atmos;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;

View File

@@ -0,0 +1,28 @@
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
// TODO: This should probably be generalized for cold temperature too,
// but right now there is no sane way to make a freezer.
/// <summary>
/// Triggers artifact if its in hot environment or
/// has contacted with a hot object (lit welder, lighter, etc).
/// </summary>
[RegisterComponent]
public sealed class ArtifactHeatTriggerComponent : Component
{
/// <summary>
/// Minimal surrounding gas temperature to trigger artifact.
/// Around 100 degrees celsius by default.
/// Doesn't affect hot items temperature.
/// </summary>
[DataField("activationTemperature")]
[ViewVariables(VVAccess.ReadWrite)]
public float ActivationTemperature = 373;
/// <summary>
/// Should artifact be activated by hot items (welders, lighter, etc)?
/// </summary>
[DataField("activateHot")]
[ViewVariables(VVAccess.ReadWrite)]
public bool ActivateHotItems = true;
}

View File

@@ -1,11 +1,29 @@
using Robust.Shared.GameObjects;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
/// <summary>
/// Activate artifact just by touching it.
/// Activate artifact by touching, attacking or pulling it.
/// </summary>
[RegisterComponent]
public sealed class ArtifactInteractionTriggerComponent : Component
{
/// <summary>
/// Should artifact be activated just by touching with empty hand?
/// </summary>
[DataField("emptyHandActivation")]
[ViewVariables(VVAccess.ReadWrite)]
public bool EmptyHandActivation = true;
/// <summary>
/// Should artifact be activated by melee attacking?
/// </summary>
[DataField("attackActivation")]
[ViewVariables(VVAccess.ReadWrite)]
public bool AttackActivation = true;
/// <summary>
/// Should artifact be activated by starting pulling it?
/// </summary>
[DataField("pullActivation")]
[ViewVariables(VVAccess.ReadWrite)]
public bool PullActivation = true;
}

View File

@@ -0,0 +1,21 @@
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
/// <summary>
/// Will try to activate artifact periodically.
/// Doesn't used for random artifacts, can be spawned by admins.
/// </summary>
[RegisterComponent]
public sealed class ArtifactTimerTriggerComponent : Component
{
/// <summary>
/// Time between artifact activation attempts.
/// </summary>
[DataField("rate")]
[ViewVariables(VVAccess.ReadWrite)]
public TimeSpan ActivationRate = TimeSpan.FromSeconds(5.0f);
/// <summary>
/// Last time when artifact was activated.
/// </summary>
public TimeSpan LastActivation;
}

View File

@@ -0,0 +1,48 @@
using Content.Server.Power.Components;
using Content.Server.Power.Events;
using Content.Server.Tools.Components;
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
using Content.Shared.Interaction;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems;
public sealed class ArtifactElectricityTriggerSystem : EntitySystem
{
[Dependency] private readonly ArtifactSystem _artifactSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ArtifactElectricityTriggerComponent, InteractUsingEvent>(OnInteractUsing);
SubscribeLocalEvent<ArtifactElectricityTriggerComponent, PowerPulseEvent>(OnPowerPulse);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityManager.EntityQuery<ArtifactElectricityTriggerComponent, PowerConsumerComponent, ArtifactComponent>();
foreach (var (trigger, power, artifact) in query)
{
if (power.ReceivedPower <= trigger.MinPower)
continue;
_artifactSystem.TryActivateArtifact(trigger.Owner, component: artifact);
}
}
private void OnInteractUsing(EntityUid uid, ArtifactElectricityTriggerComponent component, InteractUsingEvent args)
{
if (args.Handled)
return;
if (!TryComp(args.Used, out ToolComponent? tool) || !tool.Qualities.ContainsAny("Pulsing"))
return;
args.Handled = _artifactSystem.TryActivateArtifact(uid, args.User);
}
private void OnPowerPulse(EntityUid uid, ArtifactElectricityTriggerComponent component, PowerPulseEvent args)
{
_artifactSystem.TryActivateArtifact(uid, args.User);
}
}

View File

@@ -1,8 +1,6 @@
using Content.Server.Atmos.EntitySystems;
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Random;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems;
@@ -37,7 +35,7 @@ public sealed class ArtifactGasTriggerSystem : EntitySystem
if (trigger.ActivationGas == null)
continue;
var environment = _atmosphereSystem.GetTileMixture(transform.Coordinates, true);
var environment = _atmosphereSystem.GetTileMixture(transform.Coordinates);
if (environment == null)
continue;

View File

@@ -0,0 +1,62 @@
using Content.Server.Atmos.EntitySystems;
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
using Content.Shared.Interaction;
using Content.Shared.Temperature;
using Content.Shared.Weapons.Melee;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems;
public sealed class ArtifactHeatTriggerSystem : EntitySystem
{
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly ArtifactSystem _artifactSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ArtifactHeatTriggerComponent, AttackedEvent>(OnAttacked);
SubscribeLocalEvent<ArtifactHeatTriggerComponent, InteractUsingEvent>(OnUsing);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityManager.EntityQuery<ArtifactHeatTriggerComponent, TransformComponent, ArtifactComponent>();
foreach (var (trigger, transform, artifact) in query)
{
var environment = _atmosphereSystem.GetTileMixture(transform.Coordinates);
if (environment == null)
continue;
if (environment.Temperature < trigger.ActivationTemperature)
continue;
_artifactSystem.TryActivateArtifact(trigger.Owner, component: artifact);
}
}
private void OnAttacked(EntityUid uid, ArtifactHeatTriggerComponent component, AttackedEvent args)
{
if (!component.ActivateHotItems || !CheckHot(args.Used))
return;
_artifactSystem.TryActivateArtifact(uid, args.User);
}
private void OnUsing(EntityUid uid, ArtifactHeatTriggerComponent component, InteractUsingEvent args)
{
if (args.Handled)
return;
if (!component.ActivateHotItems || !CheckHot(args.Used))
return;
args.Handled = _artifactSystem.TryActivateArtifact(uid, args.User);
}
private bool CheckHot(EntityUid usedUid)
{
var hotEvent = new IsHotEvent();
RaiseLocalEvent(usedUid, hotEvent, false);
return hotEvent.IsHot;
}
}

View File

@@ -1,5 +1,7 @@
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
using Content.Shared.Interaction;
using Content.Shared.Physics.Pull;
using Content.Shared.Weapons.Melee;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems;
@@ -10,14 +12,35 @@ public sealed class ArtifactInteractionTriggerSystem : EntitySystem
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ArtifactInteractionTriggerComponent, PullStartedMessage>(OnPull);
SubscribeLocalEvent<ArtifactInteractionTriggerComponent, AttackedEvent>(OnAttack);
SubscribeLocalEvent<ArtifactInteractionTriggerComponent, InteractHandEvent>(OnInteract);
}
private void OnPull(EntityUid uid, ArtifactInteractionTriggerComponent component, PullStartedMessage args)
{
if (!component.PullActivation)
return;
_artifactSystem.TryActivateArtifact(uid, args.Puller.Owner);
}
private void OnAttack(EntityUid uid, ArtifactInteractionTriggerComponent component, AttackedEvent args)
{
if (!component.AttackActivation)
return;
_artifactSystem.TryActivateArtifact(uid, args.User);
}
private void OnInteract(EntityUid uid, ArtifactInteractionTriggerComponent component, InteractHandEvent args)
{
if (args.Handled)
return;
if (!component.EmptyHandActivation)
return;
args.Handled = _artifactSystem.TryActivateArtifact(uid, args.User);
}
}

View File

@@ -0,0 +1,26 @@
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
using Robust.Shared.Timing;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems;
public sealed class ArtifactTimerTriggerSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _time = default!;
[Dependency] private readonly ArtifactSystem _artifactSystem = default!;
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityManager.EntityQuery<ArtifactTimerTriggerComponent, ArtifactComponent>();
foreach (var (trigger, artifact) in query)
{
var timeDif = _time.CurTime - trigger.LastActivation;
if (timeDif <= trigger.ActivationRate)
continue;
_artifactSystem.TryActivateArtifact(trigger.Owner, component: artifact);
trigger.LastActivation = _time.CurTime;
}
}
}

View File

@@ -0,0 +1,4 @@
### Verbs
artifact-verb-make-always-active = Make artifact always active
artifact-verb-activate = Activate artifact

View File

@@ -27,6 +27,21 @@
- type: Appearance
visuals:
- type: RandomArtifactVisualizer
- type: PowerConsumer
voltage: Medium
drawRate: 500
- type: NodeContainer
nodes:
medium:
!type:CableDeviceNode
nodeGroupID: MVPower
# sadly, HVPower and Apc cables doesn't work right now
- type: Electrified
requirePower: true
noWindowInTile: true
highVoltageNode: high
mediumVoltageNode: medium
lowVoltageNode: low
# Telepathic
- type: entity