Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addictions 2 electric boogaloo #1897

Merged
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions Content.Server/DeltaV/Addictions/AddictionSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
using Content.Shared.DeltaV.Addictions;
using Content.Shared.Popups;
using Content.Shared.StatusEffect;
using Robust.Server.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;

namespace Content.Server.DeltaV.Addictions;

public sealed class AddictionSystem : SharedAddictionSystem
{
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
MilonPL marked this conversation as resolved.
Show resolved Hide resolved
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;

private readonly Dictionary<EntityUid, TimeSpan> _nextEffectTime = new();
MilonPL marked this conversation as resolved.
Show resolved Hide resolved

// Define the numbers, we're not making another DeepFryerSystem.cs
// Minimum time between popups
private const int MinEffectInterval = 10;

// Maximum time between popups
private const int MaxEffectInterval = 41;

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<AddictedComponent, ComponentShutdown>(OnShutdown);
}

public override void Update(float frameTime)
{
base.Update(frameTime);

var curTime = _timing.CurTime;
var query = EntityQueryEnumerator<AddictedComponent>();

while (query.MoveNext(out var uid, out var component))
{
// If it's suppressed, check if it's still supposed to be
if (component.Suppressed)
{
UpdateSuppressed(uid, component);
continue;
}

if (!_nextEffectTime.TryGetValue(uid, out var nextTime))
MilonPL marked this conversation as resolved.
Show resolved Hide resolved
{
// Between 10 and 40 seconds
_nextEffectTime[uid] = curTime + TimeSpan.FromSeconds(_random.Next(MinEffectInterval, MaxEffectInterval));
continue;
}

if (curTime < nextTime)
continue;

DoAddictionEffect(uid);
_nextEffectTime[uid] = curTime + TimeSpan.FromSeconds(_random.Next(MinEffectInterval, MaxEffectInterval));
}
}

private void OnShutdown(EntityUid uid, AddictedComponent component, ComponentShutdown args)
{
_nextEffectTime.Remove(uid);
}

private void UpdateSuppressed(EntityUid uid, AddictedComponent component)
{
var componentTime = component.LastMetabolismTime + TimeSpan.FromSeconds(10); // Ten seconds after the last metabolism cycle
if (componentTime > _timing.CurTime)
{
component.Suppressed = true;
Dirty(uid, component);
}
else
{
component.Suppressed = false;
Dirty(uid, component);
}
MilonPL marked this conversation as resolved.
Show resolved Hide resolved
}

private string GetRandomPopup()
{
return _random.Pick(new[]
{
Loc.GetString("reagent-effect-medaddiction-1"),
Loc.GetString("reagent-effect-medaddiction-2"),
Loc.GetString("reagent-effect-medaddiction-3"),
Loc.GetString("reagent-effect-medaddiction-4"),
Loc.GetString("reagent-effect-medaddiction-5"),
Loc.GetString("reagent-effect-medaddiction-6"),
Loc.GetString("reagent-effect-medaddiction-7"),
Loc.GetString("reagent-effect-medaddiction-8")
});
}
MilonPL marked this conversation as resolved.
Show resolved Hide resolved

public override void TryApplyAddiction(EntityUid uid, float addictionTime, StatusEffectsComponent? status = null)
{
base.TryApplyAddiction(uid, addictionTime, status);
}

protected override void DoAddictionEffect(EntityUid uid)
{
if (_playerManager.TryGetSessionByEntity(uid, out var session))
{
_popupSystem.PopupEntity(GetRandomPopup(), uid, session);
}
MilonPL marked this conversation as resolved.
Show resolved Hide resolved
}

// Called each time a reagent with the Addicted effect gets metabolized
protected override void UpdateTime(EntityUid uid)
{
if (TryComp<AddictedComponent>((uid), out var component))
MilonPL marked this conversation as resolved.
Show resolved Hide resolved
{
component.LastMetabolismTime = _timing.CurTime;
UpdateSuppressed(uid, component);
}
else
return;
MilonPL marked this conversation as resolved.
Show resolved Hide resolved
}
}
29 changes: 29 additions & 0 deletions Content.Server/DeltaV/EntityEffects/Effects/Addicted.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Content.Shared.DeltaV.Addictions;
using Content.Shared.EntityEffects;
using Robust.Shared.Prototypes;

namespace Content.Server.EntityEffects.Effects;

public sealed partial class Addicted : EntityEffect
{
/// <summary>
/// How long should each metabolism cycle make the effect last for.
/// </summary>
[DataField]
public float AddictionTime = 3f;

protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
=> Loc.GetString("reagent-effect-guidebook-addicted", ("chance", Probability));

public override void Effect(EntityEffectBaseArgs args)
{
var addictionTime = AddictionTime;

if (args is EntityEffectReagentArgs reagentArgs) {
addictionTime *= reagentArgs.Scale.Float();
}

var addictionSystem = args.EntityManager.EntitySysManager.GetEntitySystem<SharedAddictionSystem>();
MilonPL marked this conversation as resolved.
Show resolved Hide resolved
addictionSystem.TryApplyAddiction(args.TargetEntity, addictionTime);
}
}
21 changes: 21 additions & 0 deletions Content.Shared/DeltaV/Addictions/AddictedComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;

namespace Content.Shared.DeltaV.Addictions;

[RegisterComponent, NetworkedComponent]
MilonPL marked this conversation as resolved.
Show resolved Hide resolved
public sealed partial class AddictedComponent : Component
{
/// <summary>
/// Whether to suppress pop-ups.
/// </summary>
[DataField]
MilonPL marked this conversation as resolved.
Show resolved Hide resolved
public bool Suppressed;

/// <summary>
/// The <see cref="IGameTiming.CurTime"/> timestamp of last StatusEffect trigger.
/// </summary>
[DataField(serverOnly: true)]
public TimeSpan? LastMetabolismTime;
}
40 changes: 40 additions & 0 deletions Content.Shared/DeltaV/Addictions/SharedAddictionSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

using Content.Shared.DeltaV.Addictions;
using Content.Shared.StatusEffect;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;

namespace Content.Shared.DeltaV.Addictions;

public abstract class SharedAddictionSystem : EntitySystem
{
[Dependency] protected readonly StatusEffectsSystem StatusEffects = default!;
MilonPL marked this conversation as resolved.
Show resolved Hide resolved

public ProtoId<StatusEffectPrototype> StatusEffectKey = "Addicted";

public override void Initialize()
{
base.Initialize();
}
MilonPL marked this conversation as resolved.
Show resolved Hide resolved

protected abstract void DoAddictionEffect(EntityUid uid);
MilonPL marked this conversation as resolved.
Show resolved Hide resolved

protected abstract void UpdateTime(EntityUid uid);

public virtual void TryApplyAddiction(EntityUid uid, float addictionTime, StatusEffectsComponent? status = null)
{
if (!Resolve(uid, ref status, false))
return;

UpdateTime(uid);

if (!StatusEffects.HasStatusEffect(uid, StatusEffectKey, status))
{
StatusEffects.TryAddStatusEffect<AddictedComponent>(uid, StatusEffectKey, TimeSpan.FromSeconds(addictionTime), true, status);
}
else
{
StatusEffects.TryAddTime(uid, StatusEffectKey, TimeSpan.FromSeconds(addictionTime), status);
}
}
}
5 changes: 5 additions & 0 deletions Resources/Locale/en-US/deltav/guidebook/chemistry/effects.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
reagent-effect-guidebook-addicted =
{ $chance ->
[1] Causes
*[other] cause
} an addiction.
2 changes: 2 additions & 0 deletions Resources/Prototypes/DeltaV/status_effects.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- type: statusEffect
id: Addicted
1 change: 1 addition & 0 deletions Resources/Prototypes/Entities/Mobs/Species/base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
- Adrenaline
- PsionicsDisabled #Nyano - Summary: PCs can have psionics disabled.
- PsionicallyInsulated #Nyano - Summary: PCs can be made insulated from psionic powers.
- Addicted # DeltaV - Psych med addictions system
- type: Body
prototype: Human
requiredLegs: 2
Expand Down
Loading