Skip to content

Commit

Permalink
Addictions 2 electric boogaloo (#1897)
Browse files Browse the repository at this point in the history
* OMG FINALLY FIXED THIS JANKY SHIT

* oh

* no structure, zero fucks given

* this also

* trolled

* shitcode v2

* FUCK

* what was i even fucking thinking???

* remove unused codeanalysis import

Signed-off-by: deltanedas <[email protected]>

---------

Signed-off-by: deltanedas <[email protected]>
Co-authored-by: deltanedas <[email protected]>
  • Loading branch information
MilonPL and deltanedas authored Nov 4, 2024
1 parent c5a937e commit 7f53bd3
Show file tree
Hide file tree
Showing 9 changed files with 206 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Content.Client/DeltaV/Addictions/AddictionSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Content.Shared.DeltaV.Addictions;

namespace Content.Client.DeltaV.Addictions;

public sealed class AddictionSystem : SharedAddictionSystem
{
protected override void UpdateTime(EntityUid uid) {}
}
89 changes: 89 additions & 0 deletions Content.Server/DeltaV/Addictions/AddictionSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using Content.Shared.Dataset;
using Content.Shared.DeltaV.Addictions;
using Content.Shared.Popups;
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 _popup = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IGameTiming _timing = default!;

// 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;

// The time to add after the last metabolism cycle
private const int SuppressionDuration = 10;

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

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(component);
continue;
}

if (curTime < component.NextEffectTime)
continue;

DoAddictionEffect(uid);
component.NextEffectTime = curTime + TimeSpan.FromSeconds(_random.Next(MinEffectInterval, MaxEffectInterval));
}
}

// Make sure we don't get a popup on the first update
private void OnInit(Entity<AddictedComponent> ent, ref ComponentStartup args)
{
var curTime = _timing.CurTime;
ent.Comp.NextEffectTime = curTime + TimeSpan.FromSeconds(_random.Next(MinEffectInterval, MaxEffectInterval));
}

private void UpdateSuppressed(AddictedComponent component)
{
component.Suppressed = (_timing.CurTime < component.SuppressionEndTime);
}

private string GetRandomPopup()
{
return Loc.GetString(_random.Pick(_prototypeManager.Index<LocalizedDatasetPrototype>("AddictionEffects").Values));
}

private void DoAddictionEffect(EntityUid uid)
{
_popup.PopupEntity(GetRandomPopup(), uid, uid);
}

// Called each time a reagent with the Addicted effect gets metabolized
protected override void UpdateTime(EntityUid uid)
{
if (!TryComp<AddictedComponent>(uid, out var component))
return;

component.LastMetabolismTime = _timing.CurTime;
component.SuppressionEndTime = _timing.CurTime + TimeSpan.FromSeconds(SuppressionDuration);
UpdateSuppressed(component);
}
}
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.System<SharedAddictionSystem>();
addictionSystem.TryApplyAddiction(args.TargetEntity, addictionTime);
}
}
37 changes: 37 additions & 0 deletions Content.Shared/DeltaV/Addictions/AddictedComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using Robust.Shared.Timing;

namespace Content.Shared.DeltaV.Addictions;

[RegisterComponent, NetworkedComponent, Access(typeof(SharedAddictionSystem))]
[AutoGenerateComponentState, AutoGenerateComponentPause]
public sealed partial class AddictedComponent : Component
{
/// <summary>
/// Whether to suppress pop-ups.
/// </summary>
[DataField, AutoNetworkedField]
public bool Suppressed;

/// <summary>
/// The <see cref="IGameTiming.CurTime"/> timestamp of last StatusEffect trigger.
/// </summary>
[DataField(serverOnly: true, customTypeSerializer: typeof(TimeOffsetSerializer))]
[AutoPausedField]
public TimeSpan? LastMetabolismTime;

/// <summary>
/// The <see cref="IGameTiming.CurTime"/> timestamp of the next popup.
/// </summary>
[DataField(serverOnly: true, customTypeSerializer: typeof(TimeOffsetSerializer))]
[AutoPausedField]
public TimeSpan? NextEffectTime;

/// <summary>
/// The <see cref="IGameTiming.CurTime"/> timestamp of the when the suppression ends
/// </summary>
[DataField(serverOnly: true, customTypeSerializer: typeof(TimeOffsetSerializer))]
[AutoPausedField]
public TimeSpan? SuppressionEndTime;
}
30 changes: 30 additions & 0 deletions Content.Shared/DeltaV/Addictions/SharedAddictionSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Content.Shared.StatusEffect;
using Robust.Shared.Prototypes;

namespace Content.Shared.DeltaV.Addictions;

public abstract class SharedAddictionSystem : EntitySystem
{
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;

public ProtoId<StatusEffectPrototype> StatusEffectKey = "Addicted";

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.
5 changes: 5 additions & 0 deletions Resources/Prototypes/DeltaV/Datasets/addictions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- type: localizedDataset
id: AddictionEffects
values:
prefix: reagent-effect-medaddiction-
count: 8
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

0 comments on commit 7f53bd3

Please sign in to comment.