Skip to content

Commit

Permalink
Chemical Moodlets (And Drug Addictions!) (#896)
Browse files Browse the repository at this point in the history
# Description

This PR implements a new Reagent Reaction that modifies a character's
mood, done by raising a MoodEvent on that character. It also extends
some of the functionality of the TraitSystem and MoodSystem so as to
support a new serializable Drug Addiction mechanic.

https://www.youtube.com/watch?v=8liPBsUtND4


![image](https://github.com/user-attachments/assets/3962c492-7677-4007-bf31-23e74b2b7382)

<details><summary><h1>Media</h1></summary>
<p>


![image](https://github.com/user-attachments/assets/207210d6-e573-46e2-beb4-fab83a83d8b4)


![image](https://github.com/user-attachments/assets/4e1277e1-a873-4185-98b3-39abe06a8235)


![image](https://github.com/user-attachments/assets/e1a6cefe-82ee-482c-ace1-9fb511385fe4)


![image](https://github.com/user-attachments/assets/454dafa2-ba9e-46a6-9ac0-15e2ed35c4f8)

</p>
</details>

# Changelog

:cl:
- add: Drug Addictions! Drug addictions are long lasting Moodlet-Pairs.
The first consisting of a temporary Mood bonus that is refreshed by
consuming the drug, and the second consisting of an extremely long
lasting mood penalty, which replaces the mood bonus should you go a long
enough time between consuming the drug in question.
- add: Nicotine Addiction has been added as a new minor negative trait.
- add: Drugs/Reagents can now affect your character's Mood! Both with,
and without Addiction.
- add: TraitSystem has had functionality added for directly adding
Moodlets to a character upon joining the round, such as drug addictions,
or permanent mood modifications like Sanguine/Saturnine
- add: Lotophagoi Oil now induces an extremely powerful drug addiction,
providing an extremely large mood benefit for a short time. Which when
it wears off, creates an equally extreme mood penalty that lasts for a
very long time(or until you drink more Loto Oil).
  • Loading branch information
VMSolidus committed Sep 14, 2024
1 parent 53fdceb commit 5f7475d
Show file tree
Hide file tree
Showing 13 changed files with 178 additions and 30 deletions.
34 changes: 34 additions & 0 deletions Content.Server/Chemistry/ReagentEffects/ChemAddMoodlet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Mood;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;

namespace Content.Server.Chemistry.ReagentEffects;

/// <summary>
/// Adds a moodlet to an entity.
/// </summary>
[UsedImplicitly]
public sealed partial class ChemAddMoodlet : ReagentEffect
{
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
{
var protoMan = IoCManager.Resolve<IPrototypeManager>();
return Loc.GetString("reagent-effect-guidebook-add-moodlet",
("amount", protoMan.Index<MoodEffectPrototype>(MoodPrototype.Id).MoodChange),
("timeout", protoMan.Index<MoodEffectPrototype>(MoodPrototype.Id).Timeout));
}

/// <summary>
/// The mood prototype to be applied to the using entity.
/// </summary>
[DataField(required: true)]
public ProtoId<MoodEffectPrototype> MoodPrototype = default!;

public override void Effect(ReagentEffectArgs args)
{
var entityManager = IoCManager.Resolve<EntityManager>();
var ev = new MoodEffectEvent(MoodPrototype);
entityManager.EventBus.RaiseLocalEvent(args.SolutionEntity, ev);
}
}
30 changes: 19 additions & 11 deletions Content.Server/Mood/MoodSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ public override void Initialize()
SubscribeLocalEvent<MoodComponent, DamageChangedEvent>(OnDamageChange);
SubscribeLocalEvent<MoodComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMoveSpeed);
SubscribeLocalEvent<MoodComponent, MoodRemoveEffectEvent>(OnRemoveEffect);

SubscribeLocalEvent<MoodModifyTraitComponent, ComponentStartup>(OnTraitStartup);
}

private void OnShutdown(EntityUid uid, MoodComponent component, ComponentShutdown args)
Expand Down Expand Up @@ -101,15 +99,6 @@ private void OnRefreshMoveSpeed(EntityUid uid, MoodComponent component, RefreshM
args.ModifySpeed(1, modifier);
}

private void OnTraitStartup(EntityUid uid, MoodModifyTraitComponent component, ComponentStartup args)
{
if (_debugMode
|| component.MoodId is null)
return;

RaiseLocalEvent(uid, new MoodEffectEvent($"{component.MoodId}"));
}

private void OnMoodEffect(EntityUid uid, MoodComponent component, MoodEffectEvent args)
{
if (_debugMode
Expand Down Expand Up @@ -195,9 +184,28 @@ private void RemoveTimedOutEffect(EntityUid uid, string prototypeId, string? cat
comp.CategorisedEffects.Remove(category);
}

ReplaceMood(uid, prototypeId);
RefreshMood(uid, comp);
}

/// <summary>
/// Some moods specifically create a moodlet upon expiration. This is normally used for "Addiction" type moodlets,
/// such as a positive moodlet from an addictive substance that becomes a negative moodlet when a timer ends.
/// </summary>
/// <remarks>
/// Moodlets that use this should probably also share a category with each other, but this isn't necessarily required.
/// Only if you intend that "Re-using the drug" should also remove the negative moodlet.
/// </remarks>
private void ReplaceMood(EntityUid uid, string prototypeId)
{
if (!_prototypeManager.TryIndex<MoodEffectPrototype>(prototypeId, out var proto)
|| proto.MoodletOnEnd is null)
return;

var ev = new MoodEffectEvent(proto.MoodletOnEnd);
EntityManager.EventBus.RaiseLocalEvent(uid, ev);
}

private void OnMobStateChanged(EntityUid uid, MoodComponent component, MobStateChangedEvent args)
{
if (_debugMode)
Expand Down
11 changes: 0 additions & 11 deletions Content.Server/Traits/Assorted/ModifyMoodTraitComponent.cs

This file was deleted.

16 changes: 16 additions & 0 deletions Content.Server/Traits/TraitSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Robust.Shared.Utility;
using Content.Server.Abilities.Psionics;
using Content.Shared.Psionics;
using Content.Shared.Mood;

namespace Content.Server.Traits;

Expand Down Expand Up @@ -65,6 +66,7 @@ public void AddTrait(EntityUid uid, TraitPrototype traitPrototype)
AddTraitComponents(uid, traitPrototype);
AddTraitActions(uid, traitPrototype);
AddTraitPsionics(uid, traitPrototype);
AddTraitMoodlets(uid, traitPrototype);
}

/// <summary>
Expand Down Expand Up @@ -139,4 +141,18 @@ public void AddTraitPsionics(EntityUid uid, TraitPrototype traitPrototype)
if (_prototype.TryIndex<PsionicPowerPrototype>(powerProto, out var psionicPower))
_psionicAbilities.InitializePsionicPower(uid, psionicPower, false);
}

/// <summary>
/// If a trait includes any moodlets, this adds the moodlets to the receiving entity.
/// While I can't stop you, you shouldn't use this to add temporary moodlets.
/// </summary>
public void AddTraitMoodlets(EntityUid uid, TraitPrototype traitPrototype)
{
if (traitPrototype.MoodEffects is null)
return;

foreach (var moodProto in traitPrototype.MoodEffects)
if (_prototype.TryIndex(moodProto, out var moodlet))
RaiseLocalEvent(uid, new MoodEffectEvent(moodlet.ID));
}
}
10 changes: 10 additions & 0 deletions Content.Shared/Mood/MoodEffectPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,34 @@ public sealed class MoodEffectPrototype : IPrototype
public string ID { get; } = default!;

public string Description => Loc.GetString($"mood-effect-{ID}");

/// <summary>
/// If they already have an effect with the same category, the new one will replace the old one.
/// </summary>
[DataField, ValidatePrototypeId<MoodCategoryPrototype>]
public string? Category;

/// <summary>
/// How much should this moodlet modify an entity's Mood.
/// </summary>
[DataField(required: true)]
public float MoodChange;

/// <summary>
/// How long, in Seconds, does this moodlet last? If omitted, the moodlet will last until canceled by any system.
/// </summary>
[DataField]
public int Timeout;

/// <summary>
/// Should this moodlet be hidden from the player? EG: No popups or chat messages.
/// </summary>
[DataField]
public bool Hidden;

/// <summary>
/// When not null, this moodlet will replace itself with another Moodlet upon expiration.
/// </summary>
[DataField]
public ProtoId<MoodEffectPrototype>? MoodletOnEnd;
}
7 changes: 7 additions & 0 deletions Content.Shared/Traits/Prototypes/TraitPrototype.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Content.Shared.Customization.Systems;
using Content.Shared.Mood;
using Content.Shared.Psionics;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
Expand Down Expand Up @@ -56,4 +57,10 @@ public sealed partial class TraitPrototype : IPrototype
/// </summary>
[DataField]
public List<string>? PsionicPowers { get; private set; } = default!;

/// <summary>
/// The list of all Moodlets that this trait adds.
/// </summary>
[DataField]
public List<ProtoId<MoodEffectPrototype>>? MoodEffects { get; private set; } = default!;
}
9 changes: 8 additions & 1 deletion Resources/Locale/en-US/guidebook/chemistry/effects.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -361,4 +361,11 @@ reagent-effect-guidebook-chem-reroll-psionic =
{ $chance ->
[1] Allows
*[other] allow
} a chance to get a different psionic power
} a chance to get a different psionic power
reagent-effect-guidebook-add-moodlet =
modifies mood by {$amount}
{ $timeout ->
[0] indefinitely
*[other] for {$timeout} seconds
}
13 changes: 13 additions & 0 deletions Resources/Locale/en-US/mood/mood.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,16 @@ mood-effect-RevolutionFocused = VIVA LA REVOLUTION!!!
mood-effect-CultFocused = Dark Gods, grant me strength!
mood-effect-TraitSanguine = I have nothing to worry about. I'm sure everything will turn out well in the end!
# Addictions
mood-effect-LotoTranscendence =
I CAN SEE ALL THAT IS, ALL THAT WILL EVER BE, AND ALL THAT EVER WAS. ALL OF CREATION HAS OPENED TO MY MIND!
I MUST HAVE IT ALL. I MUST KNOW IT ALL. ALL OF IT. FOREVER!
mood-effect-LotoEnthrallment =
It has fled from me... The heart of all creation is gone from my soul, leaving behind an emptiness I cannot bear.
I fear that I will wither to nothing if I cannot drink from the cup of knowledge once again.
mood-effect-NicotineBenefit =
I feel as if I have been standing my entire life and I just sat down.
mood-effect-NicotineWithdrawal =
I could really go for a smoke right now.
4 changes: 4 additions & 0 deletions Resources/Locale/en-US/traits/traits.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,7 @@ trait-description-AnomalousPositronics =
Whether by intentional design from the manufacturer, black market modifications, or accidental omission,
your positronic brain lacks its standard psionic insulation. As a being that can be argued to have a soul,
this by extension means that it is possible for you to be influenced by the Noosphere.
trait-name-AddictionNicotine = Nicotine Addiction
trait-description-AddictionNicotine =
You have an addiction to Nicotine, and will require frequent smoke breaks to keep your mood in check.
34 changes: 34 additions & 0 deletions Resources/Prototypes/Mood/drugs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Drugs should be paired up in Trios of "Bonus, Penalty, Category"

# Lotophagoi Oil
- type: moodEffect
id: LotoTranscendence
moodChange: 30
timeout: 900 #15 minutes
moodletOnEnd: LotoEnthrallment
category: "LotophagoiAddiction"

- type: moodEffect
id: LotoEnthrallment
moodChange: -30
timeout: 7200 #2 hours
category: "LotophagoiAddiction"

- type: moodCategory
id: LotophagoiAddiction

# Nicotine
- type: moodEffect
id: NicotineBenefit
moodChange: 5
timeout: 600 #10 minutes
moodletOnEnd: NicotineWithdrawal
category: "NicotineAddiction"

- type: moodEffect
id: NicotineWithdrawal
moodChange: -7 #No timeout
category: "NicotineAddiction"

- type: moodCategory
id: NicotineAddiction
7 changes: 6 additions & 1 deletion Resources/Prototypes/Reagents/narcotics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@
plantMetabolism:
- !type:PlantAdjustHealth
amount: -5
metabolisms:
Narcotic:
effects:
- !type:ChemAddMoodlet
moodPrototype: NicotineBenefit

# TODO: Replace these nonstandardized effects with generic brain damage
- type: reagent
Expand Down Expand Up @@ -260,7 +265,7 @@
type: Add
time: 5
refresh: false
- !type:ChemRerollPsionic #Nyano - Summary: lets the imbiber become psionic.
- !type:ChemRerollPsionic #Nyano - Summary: lets the imbiber become psionic.
conditions:
- !type:ReagentThreshold
reagent: SpaceDrugs
Expand Down
6 changes: 6 additions & 0 deletions Resources/Prototypes/Reagents/psionic.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@
- !type:GenericStatusEffect
key: SlurredSpeech
component: TelepathicRepeater
- !type:ChemAddMoodlet
moodPrototype: LotoTranscendence
conditions:
- !type:ReagentThreshold
reagent: LotophagoiOil
min: 5

- type: reagent
id: Ectoplasm
Expand Down
27 changes: 21 additions & 6 deletions Resources/Prototypes/Traits/neutral.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,8 @@
inverted: true
traits:
- Sanguine
components:
- type: MoodModifyTrait
moodId: TraitSaturnine
moodEffects:
- TraitSaturnine

- type: trait
id: Sanguine
Expand All @@ -72,6 +71,22 @@
inverted: true
traits:
- Saturnine
components:
- type: MoodModifyTrait
moodId: TraitSanguine
moodEffects:
- TraitSanguine

- type: trait
id: AddictionNicotine
category: Mental
points: 1
requirements:
- !type:CharacterJobRequirement
inverted: true
jobs:
- Borg
- MedicalBorg
- !type:CharacterSpeciesRequirement
inverted: true
species:
- IPC
moodEffects:
- NicotineWithdrawal

0 comments on commit 5f7475d

Please sign in to comment.