Skip to content

Commit

Permalink
Xenoarchaeology artifacts (#6069)
Browse files Browse the repository at this point in the history
Co-authored-by: Alexander Evgrashin <[email protected]>
  • Loading branch information
Macoron and Alexander Evgrashin authored Jan 22, 2022
1 parent 90a5c6e commit 8d6565e
Show file tree
Hide file tree
Showing 50 changed files with 1,016 additions and 1 deletion.
8 changes: 7 additions & 1 deletion Content.Client/Entry/IgnoredComponents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,13 @@ public static class IgnoredComponents
"GrowingKudzu",
"MonkeyAccent",
"ReplacementAccent",
"ResistLocker"
"ResistLocker",
"SpawnArtifact",
"TelepathicArtifact",
"ArtifactGasTrigger",
"ArtifactInteractionTrigger",
"Artifact",
"RandomArtifactSprite"
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Content.Shared.Xenoarchaeology.XenoArtifacts;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;

namespace Content.Client.Xenoarchaeology.XenoArtifacts;

public class RandomArtifactVisualizer : AppearanceVisualizer
{
public override void OnChangeData(AppearanceComponent component)
{
base.OnChangeData(component);

var entities = IoCManager.Resolve<IEntityManager>();
if (!entities.TryGetComponent(component.Owner, out ISpriteComponent? sprite)) return;

if (!component.TryGetData(SharedArtifactsVisuals.SpriteIndex, out int spriteIndex))
return;

if (!component.TryGetData(SharedArtifactsVisuals.IsActivated, out bool isActivated))
isActivated = false;

var spriteIndexStr = spriteIndex.ToString("D2");
var spritePrefix = isActivated ? "_on" : "";

var spriteState = "ano" + spriteIndexStr + spritePrefix;
sprite.LayerSetState(0, spriteState);
}
}
37 changes: 37 additions & 0 deletions Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;

namespace Content.Server.Xenoarchaeology.XenoArtifacts;

[RegisterComponent]
public class ArtifactComponent : Component
{
public override string Name => "Artifact";

/// <summary>
/// Should artifact pick a random trigger on startup?
/// </summary>
[DataField("randomTrigger")]
public bool RandomTrigger = true;

/// <summary>
/// List of all possible triggers activations.
/// Should be same as components names.
/// </summary>
[DataField("possibleTriggers")]
public string[] PossibleTriggers = {
"ArtifactInteractionTrigger",
"ArtifactGasTrigger"
};

/// <summary>
/// Cooldown time between artifact activations (in seconds).
/// </summary>
[DataField("timer")]
[ViewVariables(VVAccess.ReadWrite)]
public double CooldownTime = 10;

public TimeSpan LastActivationTime;
}
70 changes: 70 additions & 0 deletions Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using Content.Server.Xenoarchaeology.XenoArtifacts.Events;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Random;
using Robust.Shared.Timing;

namespace Content.Server.Xenoarchaeology.XenoArtifacts;

public class ArtifactSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IComponentFactory _componentFactory = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ArtifactComponent, ComponentInit>(OnInit);
}

private void OnInit(EntityUid uid, ArtifactComponent component, ComponentInit args)
{
if (component.RandomTrigger)
{
AddRandomTrigger(uid, component);
}
}

public void AddRandomTrigger(EntityUid uid, ArtifactComponent? component = null)
{
if (!Resolve(uid, ref component))
return;

var triggerName = _random.Pick(component.PossibleTriggers);
var trigger = (Component) _componentFactory.GetComponent(triggerName);
trigger.Owner = uid;

EntityManager.AddComponent(uid, trigger);
}

public bool TryActivateArtifact(EntityUid uid, EntityUid? user = null,
ArtifactComponent? component = null)
{
if (!Resolve(uid, ref component))
return false;

// check if artifact isn't under cooldown
var timeDif = _gameTiming.CurTime - component.LastActivationTime;
if (timeDif.TotalSeconds < component.CooldownTime)
return false;

ForceActivateArtifact(uid, user, component);
return true;
}

public void ForceActivateArtifact(EntityUid uid, EntityUid? user = null,
ArtifactComponent? component = null)
{
if (!Resolve(uid, ref component))
return;

component.LastActivationTime = _gameTiming.CurTime;

var ev = new ArtifactActivatedEvent()
{
Activator = user
};
RaiseLocalEvent(uid, ev);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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;

/// <summary>
/// When activated artifact will spawn an entity from prototype.
/// It could be an angry mob or some random item.
/// </summary>
[RegisterComponent]
public class SpawnArtifactComponent : Component
{
public override string Name => "SpawnArtifact";

[DataField("random")]
public bool RandomPrototype = true;

[DataField("possiblePrototypes", customTypeSerializer:typeof(PrototypeIdListSerializer<EntityPrototype>))]
public List<string> PossiblePrototypes = new();

[ViewVariables(VVAccess.ReadWrite)]
[DataField("prototype", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? Prototype;

[DataField("range")]
public float Range = 0.5f;

[DataField("maxSpawns")]
public int MaxSpawns = 20;

public int SpawnsCount = 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;

namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;

/// <summary>
/// Harmless artifact that broadcast "thoughts" to players nearby.
/// Thoughts are shown as popups and unique for each player.
/// </summary>
[RegisterComponent]
public class TelepathicArtifactComponent : Component
{
public override string Name => "TelepathicArtifact";

/// <summary>
/// Loc string ids of telepathic messages.
/// Will be randomly picked and shown to player.
/// </summary>
[DataField("messages")]
[ViewVariables(VVAccess.ReadWrite)]
public string[] Messages = default!;

/// <summary>
/// Loc string ids of telepathic messages (spooky version).
/// Will be randomly picked and shown to player.
/// </summary>
[DataField("drastic")]
[ViewVariables(VVAccess.ReadWrite)]
public string[] DrasticMessages = default!;

/// <summary>
/// Probability to pick drastic version of message.
/// </summary>
[DataField("drasticProb")]
[ViewVariables(VVAccess.ReadWrite)]
public float DrasticMessageProb = 0.2f;

/// <summary>
/// Radius in which player can receive artifacts messages.
/// </summary>
[DataField("range")]
[ViewVariables(VVAccess.ReadWrite)]
public float Range = 10f;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
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;

public class SpawnArtifactSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SpawnArtifactComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<SpawnArtifactComponent, ArtifactActivatedEvent>(OnActivate);
}
private void OnInit(EntityUid uid, SpawnArtifactComponent component, ComponentInit args)
{
ChooseRandomPrototype(uid, component);
}

private void OnActivate(EntityUid uid, SpawnArtifactComponent component, ArtifactActivatedEvent args)
{
if (component.Prototype == null)
return;
if (component.SpawnsCount >= component.MaxSpawns)
return;

// select spawn position near artifact
var artifactCord = Transform(uid).Coordinates;
var dx = _random.NextFloat(-component.Range, component.Range);
var dy = _random.NextFloat(-component.Range, component.Range);
var spawnCord = artifactCord.Offset(new Vector2(dx, dy));

// spawn entity
var spawned = EntityManager.SpawnEntity(component.Prototype, spawnCord);
component.SpawnsCount++;

// if there is an user - try to put spawned item in their hands
// doesn't work for spawners
if (args.Activator != null &&
EntityManager.TryGetComponent(args.Activator.Value, out SharedHandsComponent? hands) &&
EntityManager.HasComponent<ItemComponent>(spawned))
{
hands.TryPutInAnyHand(spawned);
}
}

private void ChooseRandomPrototype(EntityUid uid, SpawnArtifactComponent? component = null)
{
if (!Resolve(uid, ref component))
return;

if (!component.RandomPrototype)
return;
if (component.PossiblePrototypes.Count == 0)
return;

var proto = _random.Pick(component.PossiblePrototypes);
component.Prototype = proto;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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;

namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;

public class TelepathicArtifactSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IEntityLookup _lookup = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<TelepathicArtifactComponent, ArtifactActivatedEvent>(OnActivate);
}

private void OnActivate(EntityUid uid, TelepathicArtifactComponent component, ArtifactActivatedEvent args)
{
// try to find victims nearby
var victims = _lookup.GetEntitiesInRange(uid, component.Range);
foreach (var victimUid in victims)
{
if (!EntityManager.HasComponent<ActorComponent>(victimUid))
continue;

// roll if msg should be usual or drastic
var isDrastic = _random.NextFloat() <= component.DrasticMessageProb;
var msgArr = isDrastic ? component.DrasticMessages : component.Messages;

// pick a random message
var msgId = _random.Pick(msgArr);
var msg = Loc.GetString(msgId);

// show it as a popup, but only for the victim
_popupSystem.PopupEntity(msg, victimUid, Filter.Entities(victimUid));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using Robust.Shared.GameObjects;

namespace Content.Server.Xenoarchaeology.XenoArtifacts.Events;

/// <summary>
/// Invokes when artifact was successfully activated.
/// Used to start attached effects.
/// </summary>
public class ArtifactActivatedEvent : EntityEventArgs
{
/// <summary>
/// Entity that activate this artifact.
/// Usually player, but can also be another object.
/// </summary>
public EntityUid? Activator;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes;

namespace Content.Server.Xenoarchaeology.XenoArtifacts;

[RegisterComponent]
public class RandomArtifactSpriteComponent : Component
{
public override string Name => "RandomArtifactSprite";

[DataField("minSprite")]
public int MinSprite = 1;

[DataField("maxSprite")]
public int MaxSprite = 14;

[DataField("activationTime")]
public double ActivationTime = 2.0;

public TimeSpan? ActivationStart;
}
Loading

0 comments on commit 8d6565e

Please sign in to comment.