diff --git a/Content.Client/ShortConstruction/UI/ShortConstructionMenuBUI.cs b/Content.Client/ShortConstruction/UI/ShortConstructionMenuBUI.cs
index 37606d8656..4d50d91e16 100644
--- a/Content.Client/ShortConstruction/UI/ShortConstructionMenuBUI.cs
+++ b/Content.Client/ShortConstruction/UI/ShortConstructionMenuBUI.cs
@@ -66,7 +66,7 @@ private RadialMenu FormMenu()
var mainContainer = new RadialContainer
{
- Radius = 36f / MathF.Sin(MathF.PI / crafting.Prototypes.Count)
+ Radius = 36f / MathF.Sin(MathF.PI / 2f / crafting.Prototypes.Count)
};
foreach (var protoId in crafting.Prototypes)
diff --git a/Content.Server/Chemistry/ReagentEffects/ChemAddMoodlet.cs b/Content.Server/Chemistry/ReagentEffects/ChemAddMoodlet.cs
new file mode 100644
index 0000000000..f5bb629299
--- /dev/null
+++ b/Content.Server/Chemistry/ReagentEffects/ChemAddMoodlet.cs
@@ -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;
+
+///
+/// Adds a moodlet to an entity.
+///
+[UsedImplicitly]
+public sealed partial class ChemAddMoodlet : ReagentEffect
+{
+ protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
+ {
+ var protoMan = IoCManager.Resolve();
+ return Loc.GetString("reagent-effect-guidebook-add-moodlet",
+ ("amount", protoMan.Index(MoodPrototype.Id).MoodChange),
+ ("timeout", protoMan.Index(MoodPrototype.Id).Timeout));
+ }
+
+ ///
+ /// The mood prototype to be applied to the using entity.
+ ///
+ [DataField(required: true)]
+ public ProtoId MoodPrototype = default!;
+
+ public override void Effect(ReagentEffectArgs args)
+ {
+ var entityManager = IoCManager.Resolve();
+ var ev = new MoodEffectEvent(MoodPrototype);
+ entityManager.EventBus.RaiseLocalEvent(args.SolutionEntity, ev);
+ }
+}
diff --git a/Content.Server/Mood/MoodSystem.cs b/Content.Server/Mood/MoodSystem.cs
index f2dc87ffd6..7e4789bf14 100644
--- a/Content.Server/Mood/MoodSystem.cs
+++ b/Content.Server/Mood/MoodSystem.cs
@@ -53,8 +53,6 @@ public override void Initialize()
SubscribeLocalEvent(OnDamageChange);
SubscribeLocalEvent(OnRefreshMoveSpeed);
SubscribeLocalEvent(OnRemoveEffect);
-
- SubscribeLocalEvent(OnTraitStartup);
}
private void OnShutdown(EntityUid uid, MoodComponent component, ComponentShutdown args)
@@ -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
@@ -195,9 +184,28 @@ private void RemoveTimedOutEffect(EntityUid uid, string prototypeId, string? cat
comp.CategorisedEffects.Remove(category);
}
+ ReplaceMood(uid, prototypeId);
RefreshMood(uid, comp);
}
+ ///
+ /// 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.
+ ///
+ ///
+ /// 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.
+ ///
+ private void ReplaceMood(EntityUid uid, string prototypeId)
+ {
+ if (!_prototypeManager.TryIndex(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)
diff --git a/Content.Server/Power/Components/ActiveChargerComponent.cs b/Content.Server/Power/Components/ActiveChargerComponent.cs
new file mode 100644
index 0000000000..9f75db853d
--- /dev/null
+++ b/Content.Server/Power/Components/ActiveChargerComponent.cs
@@ -0,0 +1,7 @@
+using Content.Shared.Containers.ItemSlots;
+using Content.Shared.Power;
+
+namespace Content.Server.Power.Components;
+
+[RegisterComponent]
+public sealed partial class ActiveChargerComponent : Component { }
diff --git a/Content.Server/Power/Components/ChargingComponent.cs b/Content.Server/Power/Components/ChargingComponent.cs
deleted file mode 100644
index db7c14f708..0000000000
--- a/Content.Server/Power/Components/ChargingComponent.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using Content.Shared.Containers.ItemSlots;
-using Content.Shared.Power;
-
-namespace Content.Server.Power.Components
-{
- [RegisterComponent]
- public sealed partial class ChargingComponent : Component
- {
- ///
- ///References the entity of the charger that is currently powering this battery
- ///
- public EntityUid ChargerUid;
-
- ///
- ///References the component of the charger that is currently powering this battery
- ///
- public ChargerComponent ChargerComponent;
- }
-}
diff --git a/Content.Server/Power/EntitySystems/BatterySystem.cs b/Content.Server/Power/EntitySystems/BatterySystem.cs
index 1c5d83b094..cbe61f6671 100644
--- a/Content.Server/Power/EntitySystems/BatterySystem.cs
+++ b/Content.Server/Power/EntitySystems/BatterySystem.cs
@@ -21,7 +21,6 @@ public override void Initialize()
SubscribeLocalEvent(OnBatteryRejuvenate);
SubscribeLocalEvent(CalculateBatteryPrice);
SubscribeLocalEvent(OnEmpPulse);
- SubscribeLocalEvent(OnEmpDisabledRemoved);
SubscribeLocalEvent(PreSync);
SubscribeLocalEvent(PostSync);
@@ -106,17 +105,6 @@ private void OnEmpPulse(EntityUid uid, BatteryComponent component, ref EmpPulseE
UseCharge(uid, args.EnergyConsumption, component);
}
- // if a disabled battery is put into a recharged,
- // allow the recharger to start recharging again after the disable ends
- private void OnEmpDisabledRemoved(EntityUid uid, BatteryComponent component, ref EmpDisabledRemoved args)
- {
- if (!TryComp(uid, out var charging))
- return;
-
- var ev = new ChargerUpdateStatusEvent();
- RaiseLocalEvent(charging.ChargerUid, ref ev);
- }
-
public float UseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
{
if (value <= 0 || !Resolve(uid, ref battery) || battery.CurrentCharge == 0)
@@ -191,10 +179,6 @@ public bool IsFull(EntityUid uid, BatteryComponent? battery = null)
if (!Resolve(uid, ref battery))
return false;
- // If the battery is full, remove its charging component.
- if (TryComp(uid, out _))
- RemComp(uid);
-
return battery.CurrentCharge / battery.MaxCharge >= 0.99f;
}
}
diff --git a/Content.Server/Power/EntitySystems/ChargerSystem.cs b/Content.Server/Power/EntitySystems/ChargerSystem.cs
index ae6b024162..db16dfa008 100644
--- a/Content.Server/Power/EntitySystems/ChargerSystem.cs
+++ b/Content.Server/Power/EntitySystems/ChargerSystem.cs
@@ -1,16 +1,13 @@
using Content.Server.Power.Components;
-using Content.Server.Emp;
using Content.Server.PowerCell;
using Content.Shared.Examine;
using Content.Shared.Power;
using Content.Shared.PowerCell.Components;
-using Content.Shared.Emp;
using JetBrains.Annotations;
using Robust.Shared.Containers;
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Storage.Components;
using Robust.Server.Containers;
-using Content.Shared.Whitelist;
namespace Content.Server.Power.EntitySystems;
@@ -31,11 +28,6 @@ public override void Initialize()
SubscribeLocalEvent(OnInsertAttempt);
SubscribeLocalEvent(OnEntityStorageInsertAttempt);
SubscribeLocalEvent(OnChargerExamine);
-
- SubscribeLocalEvent(OnUpdateStatus);
-
- SubscribeLocalEvent(OnEmpPulse);
- SubscribeLocalEvent(OnEmpDisabledRemoved);
}
private void OnStartup(EntityUid uid, ChargerComponent component, ComponentStartup args)
@@ -48,58 +40,21 @@ private void OnChargerExamine(EntityUid uid, ChargerComponent component, Examine
args.PushMarkup(Loc.GetString("charger-examine", ("color", "yellow"), ("chargeRate", (int) component.ChargeRate)));
}
- private void StartChargingBattery(EntityUid uid, ChargerComponent component, EntityUid target)
- {
- bool charge = true;
-
- if (HasComp(uid))
- charge = false;
- else
- if (!TryComp(target, out var battery))
- charge = false;
- else
- if (Math.Abs(battery.MaxCharge - battery.CurrentCharge) < 0.01)
- charge = false;
-
- // wrap functionality in an if statement instead of returning...
- if (charge)
- {
- var charging = EnsureComp(target);
- charging.ChargerUid = uid;
- charging.ChargerComponent = component;
- }
-
- // ...so the status always updates (for insertin a power cell)
- UpdateStatus(uid, component);
- }
-
- private void StopChargingBattery(EntityUid uid, ChargerComponent component, EntityUid target)
- {
- if (HasComp(target))
- RemComp(target);
- UpdateStatus(uid, component);
- }
-
public override void Update(float frameTime)
{
- var query = EntityQueryEnumerator();
- while (query.MoveNext(out var uid, out var charging))
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out _, out var charger, out var containerComp))
{
- if (!TryComp(charging.ChargerUid, out var chargerComponent))
+ if (!_container.TryGetContainer(uid, charger.SlotId, out var container, containerComp))
continue;
- if (charging.ChargerComponent.Status == CellChargerStatus.Off || charging.ChargerComponent.Status == CellChargerStatus.Empty)
+ if (charger.Status == CellChargerStatus.Empty || charger.Status == CellChargerStatus.Charged || container.ContainedEntities.Count == 0)
continue;
- if (HasComp(charging.ChargerUid))
- continue;
-
- if (!TryComp(uid, out var battery))
- continue;
-
- if (Math.Abs(battery.MaxCharge - battery.CurrentCharge) < 0.01)
- StopChargingBattery(charging.ChargerUid, charging.ChargerComponent, uid);
- TransferPower(charging.ChargerUid, uid, charging.ChargerComponent, frameTime);
+ foreach (var contained in container.ContainedEntities)
+ {
+ TransferPower(uid, contained, charger, frameTime);
+ }
}
}
@@ -116,7 +71,7 @@ private void OnInserted(EntityUid uid, ChargerComponent component, EntInsertedIn
if (args.Container.ID != component.SlotId)
return;
- StartChargingBattery(uid, component, args.Entity);
+ UpdateStatus(uid, component);
}
private void OnRemoved(EntityUid uid, ChargerComponent component, EntRemovedFromContainerMessage args)
@@ -124,7 +79,7 @@ private void OnRemoved(EntityUid uid, ChargerComponent component, EntRemovedFrom
if (args.Container.ID != component.SlotId)
return;
- StopChargingBattery(uid, component, args.Entity);
+ UpdateStatus(uid, component);
}
///
@@ -157,11 +112,6 @@ private void OnEntityStorageInsertAttempt(EntityUid uid, ChargerComponent compon
args.Cancelled = true;
}
- private void OnUpdateStatus(EntityUid uid, ChargerComponent component, ref ChargerUpdateStatusEvent args)
- {
- UpdateStatus(uid, component);
- }
-
private void UpdateStatus(EntityUid uid, ChargerComponent component)
{
var status = GetStatus(uid, component);
@@ -176,6 +126,15 @@ private void UpdateStatus(EntityUid uid, ChargerComponent component)
component.Status = status;
+ if (component.Status == CellChargerStatus.Charging)
+ {
+ AddComp(uid);
+ }
+ else
+ {
+ RemComp(uid);
+ }
+
switch (component.Status)
{
case CellChargerStatus.Off:
@@ -187,7 +146,7 @@ private void UpdateStatus(EntityUid uid, ChargerComponent component)
_appearance.SetData(uid, CellVisual.Light, CellChargerStatus.Empty, appearance);
break;
case CellChargerStatus.Charging:
- receiver.Load = component.ChargeRate; //does not scale with multiple slotted batteries
+ receiver.Load = component.ChargeRate;
_appearance.SetData(uid, CellVisual.Light, CellChargerStatus.Charging, appearance);
break;
case CellChargerStatus.Charged:
@@ -198,42 +157,6 @@ private void UpdateStatus(EntityUid uid, ChargerComponent component)
throw new ArgumentOutOfRangeException();
}
}
-
- private void OnEmpPulse(EntityUid uid, ChargerComponent component, ref EmpPulseEvent args)
- {
- // we don't care if we haven't been disabled
- if (!args.Disabled)
- return;
-
- // if the recharger is hit by an emp pulse,
- // stop recharging contained batteries to save resources
- if (!_container.TryGetContainer(uid, component.SlotId, out var container))
- return;
-
- foreach (var containedEntity in container.ContainedEntities)
- {
- if (!SearchForBattery(containedEntity, out _, out _))
- continue;
-
- StopChargingBattery(uid, component, containedEntity);
- }
- }
-
- private void OnEmpDisabledRemoved(EntityUid uid, ChargerComponent component, ref EmpDisabledRemoved args)
- {
- // if an emp disable subsides,
- // attempt to start charging all batteries
- if (!_container.TryGetContainer(uid, component.SlotId, out var container))
- return;
-
- foreach (var containedEntity in container.ContainedEntities)
- {
- if (!SearchForBattery(containedEntity, out _, out _))
- continue;
-
- StartChargingBattery(uid, component, containedEntity);
- }
- }
private CellChargerStatus GetStatus(EntityUid uid, ChargerComponent component)
{
@@ -255,28 +178,13 @@ private CellChargerStatus GetStatus(EntityUid uid, ChargerComponent component)
if (container.ContainedEntities.Count == 0)
return CellChargerStatus.Empty;
- var statusOut = CellChargerStatus.Off;
-
- foreach (var containedEntity in container.ContainedEntities)
- {
- // if none of the slotted items are actually batteries, represent the charger as off
- if (!SearchForBattery(containedEntity, out _, out _))
- continue;
-
- // if all batteries are either EMP'd or fully charged, represent the charger as fully charged
- statusOut = CellChargerStatus.Charged;
- if (HasComp(containedEntity))
- continue;
-
- if (!HasComp(containedEntity))
- continue;
+ if (!SearchForBattery(container.ContainedEntities[0], out _, out var heldBattery))
+ return CellChargerStatus.Off;
- // if we have atleast one battery being charged, represent the charger as charging;
- statusOut = CellChargerStatus.Charging;
- break;
- }
+ if (Math.Abs(heldBattery.MaxCharge - heldBattery.CurrentCharge) < 0.01)
+ return CellChargerStatus.Charged;
- return statusOut;
+ return CellChargerStatus.Charging;
}
private void TransferPower(EntityUid uid, EntityUid targetEntity, ChargerComponent component, float frameTime)
@@ -293,11 +201,11 @@ private void TransferPower(EntityUid uid, EntityUid targetEntity, ChargerCompone
if (!SearchForBattery(targetEntity, out var batteryUid, out var heldBattery))
return;
- _battery.TrySetCharge(batteryUid.Value, heldBattery.CurrentCharge + component.ChargeRate * frameTime, heldBattery);
+ _battery.SetCharge(batteryUid.Value, heldBattery.CurrentCharge + component.ChargeRate * frameTime, heldBattery);
// Just so the sprite won't be set to 99.99999% visibility
if (heldBattery.MaxCharge - heldBattery.CurrentCharge < 0.01)
{
- _battery.TrySetCharge(batteryUid.Value, heldBattery.MaxCharge, heldBattery);
+ _battery.SetCharge(batteryUid.Value, heldBattery.MaxCharge, heldBattery);
}
UpdateStatus(uid, component);
@@ -315,6 +223,3 @@ private bool SearchForBattery(EntityUid uid, [NotNullWhen(true)] out EntityUid?
return true;
}
}
-
-[ByRefEvent]
-public record struct ChargerUpdateStatusEvent();
\ No newline at end of file
diff --git a/Content.Server/Traits/Assorted/ModifyMoodTraitComponent.cs b/Content.Server/Traits/Assorted/ModifyMoodTraitComponent.cs
deleted file mode 100644
index f9ae3b36f3..0000000000
--- a/Content.Server/Traits/Assorted/ModifyMoodTraitComponent.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace Content.Shared.Traits.Assorted.Components;
-
-///
-/// Used for traits that add a starting moodlet.
-///
-[RegisterComponent]
-public sealed partial class MoodModifyTraitComponent : Component
-{
- [DataField]
- public string? MoodId = null;
-}
diff --git a/Content.Server/Traits/TraitSystem.cs b/Content.Server/Traits/TraitSystem.cs
index d6f13cb52a..39812f65b6 100644
--- a/Content.Server/Traits/TraitSystem.cs
+++ b/Content.Server/Traits/TraitSystem.cs
@@ -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;
@@ -65,6 +66,7 @@ public void AddTrait(EntityUid uid, TraitPrototype traitPrototype)
AddTraitComponents(uid, traitPrototype);
AddTraitActions(uid, traitPrototype);
AddTraitPsionics(uid, traitPrototype);
+ AddTraitMoodlets(uid, traitPrototype);
}
///
@@ -139,4 +141,18 @@ public void AddTraitPsionics(EntityUid uid, TraitPrototype traitPrototype)
if (_prototype.TryIndex(powerProto, out var psionicPower))
_psionicAbilities.InitializePsionicPower(uid, psionicPower, false);
}
+
+ ///
+ /// 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.
+ ///
+ 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));
+ }
}
diff --git a/Content.Shared/Chemistry/EntitySystems/RehydratableSystem.cs b/Content.Shared/Chemistry/EntitySystems/RehydratableSystem.cs
index e260280ae4..44bfb583dd 100644
--- a/Content.Shared/Chemistry/EntitySystems/RehydratableSystem.cs
+++ b/Content.Shared/Chemistry/EntitySystems/RehydratableSystem.cs
@@ -1,12 +1,14 @@
using Content.Shared.Chemistry.Components;
using Content.Shared.FixedPoint;
using Content.Shared.Popups;
+using Robust.Shared.Network;
using Robust.Shared.Random;
namespace Content.Shared.Chemistry.EntitySystems;
public sealed class RehydratableSystem : EntitySystem
{
+ [Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedSolutionContainerSystem _solutions = default!;
@@ -31,6 +33,9 @@ private void OnSolutionChange(Entity ent, ref SolutionCon
// Try not to make this public if you can help it.
private void Expand(Entity ent)
{
+ if (_net.IsClient)
+ return; // no
+
var (uid, comp) = ent;
var randomMob = _random.Pick(comp.PossibleSpawns);
diff --git a/Content.Shared/Mood/MoodEffectPrototype.cs b/Content.Shared/Mood/MoodEffectPrototype.cs
index ad21faec80..ab9bca0160 100644
--- a/Content.Shared/Mood/MoodEffectPrototype.cs
+++ b/Content.Shared/Mood/MoodEffectPrototype.cs
@@ -12,24 +12,34 @@ public sealed class MoodEffectPrototype : IPrototype
public string ID { get; } = default!;
public string Description => Loc.GetString($"mood-effect-{ID}");
+
///
/// If they already have an effect with the same category, the new one will replace the old one.
///
[DataField, ValidatePrototypeId]
public string? Category;
+
///
/// How much should this moodlet modify an entity's Mood.
///
[DataField(required: true)]
public float MoodChange;
+
///
/// How long, in Seconds, does this moodlet last? If omitted, the moodlet will last until canceled by any system.
///
[DataField]
public int Timeout;
+
///
/// Should this moodlet be hidden from the player? EG: No popups or chat messages.
///
[DataField]
public bool Hidden;
+
+ ///
+ /// When not null, this moodlet will replace itself with another Moodlet upon expiration.
+ ///
+ [DataField]
+ public ProtoId? MoodletOnEnd;
}
diff --git a/Content.Shared/Traits/Prototypes/TraitPrototype.cs b/Content.Shared/Traits/Prototypes/TraitPrototype.cs
index 7bdff058ee..cd4b02a1e6 100644
--- a/Content.Shared/Traits/Prototypes/TraitPrototype.cs
+++ b/Content.Shared/Traits/Prototypes/TraitPrototype.cs
@@ -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;
@@ -56,4 +57,10 @@ public sealed partial class TraitPrototype : IPrototype
///
[DataField]
public List? PsionicPowers { get; private set; } = default!;
+
+ ///
+ /// The list of all Moodlets that this trait adds.
+ ///
+ [DataField]
+ public List>? MoodEffects { get; private set; } = default!;
}
diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index fdf35f8d5f..0be6b68d7e 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -6325,3 +6325,50 @@ Entries:
id: 6359
time: '2024-09-14T05:44:56.0000000+00:00'
url: https://github.com/Simple-Station/Einstein-Engines/pull/889
+- author: VMSolidus
+ changes:
+ - type: Add
+ message: >-
+ 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.
+ - type: Add
+ message: Nicotine Addiction has been added as a new minor negative trait.
+ - type: Add
+ message: >-
+ Drugs/Reagents can now affect your character's Mood! Both with, and
+ without Addiction.
+ - type: Add
+ message: >-
+ 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
+ - type: Add
+ message: >-
+ 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).
+ id: 6360
+ time: '2024-09-14T06:48:55.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/896
+- author: Mnemotechnician
+ changes:
+ - type: Fix
+ message: Cyborg recharging stations finally work again.
+ - type: Fix
+ message: >-
+ Rehydratable entities (such as monkey cubes) no longer spawn a second
+ client-side entity when rehydrated.
+ id: 6361
+ time: '2024-09-14T17:55:41.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/888
+- author: VMSolidus
+ changes:
+ - type: Tweak
+ message: The Uncloneable trait is only worth one point now.
+ id: 6362
+ time: '2024-09-14T18:01:21.0000000+00:00'
+ url: https://github.com/Simple-Station/Einstein-Engines/pull/868
diff --git a/Resources/Locale/en-US/guidebook/chemistry/effects.ftl b/Resources/Locale/en-US/guidebook/chemistry/effects.ftl
index db2f3816f6..dbb24a3caf 100644
--- a/Resources/Locale/en-US/guidebook/chemistry/effects.ftl
+++ b/Resources/Locale/en-US/guidebook/chemistry/effects.ftl
@@ -361,4 +361,11 @@ reagent-effect-guidebook-chem-reroll-psionic =
{ $chance ->
[1] Allows
*[other] allow
- } a chance to get a different psionic power
\ No newline at end of file
+ } a chance to get a different psionic power
+
+reagent-effect-guidebook-add-moodlet =
+ modifies mood by {$amount}
+ { $timeout ->
+ [0] indefinitely
+ *[other] for {$timeout} seconds
+ }
\ No newline at end of file
diff --git a/Resources/Locale/en-US/mood/mood.ftl b/Resources/Locale/en-US/mood/mood.ftl
index bd64d52582..a931a30fb3 100644
--- a/Resources/Locale/en-US/mood/mood.ftl
+++ b/Resources/Locale/en-US/mood/mood.ftl
@@ -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.
\ No newline at end of file
diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl
index e049af3c62..ff329a12a7 100644
--- a/Resources/Locale/en-US/traits/traits.ftl
+++ b/Resources/Locale/en-US/traits/traits.ftl
@@ -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.
\ No newline at end of file
diff --git a/Resources/Locale/ru-RU/guidebook/chemistry/effects.ftl b/Resources/Locale/ru-RU/guidebook/chemistry/effects.ftl
index d630480759..1cdde91c4d 100644
--- a/Resources/Locale/ru-RU/guidebook/chemistry/effects.ftl
+++ b/Resources/Locale/ru-RU/guidebook/chemistry/effects.ftl
@@ -331,6 +331,12 @@ reagent-effect-guidebook-chem-reroll-psionic =
[1] Даёт
*[other] Даёт
} шанс получить другую псионическую силу
+reagent-effect-guidebook-add-moodlet =
+ увеличивает настроение на { $amount }
+ { $timeout ->
+ [0] бесконечность
+ *[other] { $timeout } секунд
+ }
reagent-effect-guidebook-innoculate-zombie-infection =
{ $chance ->
[1] Лечит
diff --git a/Resources/Locale/ru-RU/mood/mood.ftl b/Resources/Locale/ru-RU/mood/mood.ftl
index ef60aad484..b529ae6418 100644
--- a/Resources/Locale/ru-RU/mood/mood.ftl
+++ b/Resources/Locale/ru-RU/mood/mood.ftl
@@ -31,3 +31,12 @@ mood-effect-TraitorFocused = У меня есть цель, и я ее дост
mood-effect-RevolutionFocused = ДА ЗДРАВСТВУЕТ РЕВОЛЮЦИЯ!!!
mood-effect-CultFocused = Тёмные Боги, даруйте мне силу!
mood-effect-TraitSanguine = Мне не о чем беспокоиться. Я уверен, что в конце концов все будет хорошо!
+# Addictions
+mood-effect-LotoTranscendence =
+ Я МОГУ ВИДЕТЬ ВСЕ, ЧТО ЕСТЬ, КОГДА-ЛИБО БУДЕТ И КОГДА-ЛИБО БЫЛО. ВСЕ БЫТИЕ ОТКРЫЛОСЬ МОЕМУ РАЗУМУ!
+ Я ДОЛЖЕН ЗАПОЛУЧИТЬ ВСЕ. Я ДОЛЖЕН ЗНАТЬ ВСЕ. АБСОЛЮТНО ВСЕ. НАВСЕГДА!
+mood-effect-LotoEnthrallment =
+ Он убежал от меня... Сердце всего бытия ушло из моей души, оставив после себя пустоту, которую я не могу вынести.
+ Я боюсь, что увяну, если не смогу снова испить из чаши знания.
+mood-effect-NicotineBenefit = У меня такое чувство, будто я всю жизнь стоял и только что сел.
+mood-effect-NicotineWithdrawal = Мне бы сейчас пойти и прикурить немного.
diff --git a/Resources/Locale/ru-RU/traits/traits.ftl b/Resources/Locale/ru-RU/traits/traits.ftl
index d0c52f4cc9..945dd5740c 100644
--- a/Resources/Locale/ru-RU/traits/traits.ftl
+++ b/Resources/Locale/ru-RU/traits/traits.ftl
@@ -175,3 +175,5 @@ trait-description-AnomalousPositronics =
Будь то преднамеренный дизайн от производителя, модификации на черном рынке или случайное упущение,
вашему позитронному мозгу не хватает стандартной псионической изоляции. Как существо, у которого, как можно утверждать, есть душа,
это, в более широком смысле, означает, что вы можете подвергаться влиянию Ноосферы.
+trait-name-AddictionNicotine = Никотиновая зависимость
+trait-description-AddictionNicotine = У вас зависимость от никотина, и вам понадобятся частые перекуры, чтобы сохранить свой рассудок.
diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml
index f3ca1c758d..fde82ecb6c 100644
--- a/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml
+++ b/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml
@@ -104,6 +104,9 @@
- type: Tag
tags:
- HidesTail
+ - CanPilot
+ - FootstepSound
+ - DoorBumpOpener
- type: ScentTracker
- type: Flashable
eyeDamageChance: 0.3
diff --git a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml
index 2baead2d33..7cd347fd41 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml
@@ -62,6 +62,9 @@
- type: Tag
tags:
- HidesTail
+ - CanPilot
+ - FootstepSound
+ - DoorBumpOpener
- type: LanguageKnowledge
speaks:
- GalacticCommon
diff --git a/Resources/Prototypes/Mood/drugs.yml b/Resources/Prototypes/Mood/drugs.yml
new file mode 100644
index 0000000000..470abc5e3d
--- /dev/null
+++ b/Resources/Prototypes/Mood/drugs.yml
@@ -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
\ No newline at end of file
diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/felinid.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/felinid.yml
index 325f856388..8ae8ee802b 100644
--- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/felinid.yml
+++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/Species/felinid.yml
@@ -68,6 +68,9 @@
- type: Tag
tags:
- HidesTail
+ - CanPilot
+ - FootstepSound
+ - DoorBumpOpener
- type: LanguageKnowledge
speaks:
- GalacticCommon
diff --git a/Resources/Prototypes/Reagents/narcotics.yml b/Resources/Prototypes/Reagents/narcotics.yml
index 2ab323c309..ca85fd15b3 100644
--- a/Resources/Prototypes/Reagents/narcotics.yml
+++ b/Resources/Prototypes/Reagents/narcotics.yml
@@ -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
@@ -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
diff --git a/Resources/Prototypes/Reagents/psionic.yml b/Resources/Prototypes/Reagents/psionic.yml
index 3e8415fc0e..f17a84047a 100644
--- a/Resources/Prototypes/Reagents/psionic.yml
+++ b/Resources/Prototypes/Reagents/psionic.yml
@@ -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
diff --git a/Resources/Prototypes/Traits/disabilities.yml b/Resources/Prototypes/Traits/disabilities.yml
index 51099839ac..34e1354158 100644
--- a/Resources/Prototypes/Traits/disabilities.yml
+++ b/Resources/Prototypes/Traits/disabilities.yml
@@ -65,7 +65,7 @@
- type: trait
id: Uncloneable
category: Physical
- points: 4
+ points: 1
requirements:
- !type:CharacterJobRequirement
inverted: true
diff --git a/Resources/Prototypes/Traits/neutral.yml b/Resources/Prototypes/Traits/neutral.yml
index a4e449f1c0..c7fa8d914e 100644
--- a/Resources/Prototypes/Traits/neutral.yml
+++ b/Resources/Prototypes/Traits/neutral.yml
@@ -63,9 +63,8 @@
inverted: true
traits:
- Sanguine
- components:
- - type: MoodModifyTrait
- moodId: TraitSaturnine
+ moodEffects:
+ - TraitSaturnine
- type: trait
id: Sanguine
@@ -81,6 +80,22 @@
inverted: true
traits:
- Saturnine
- components:
- - type: MoodModifyTrait
- moodId: TraitSanguine
\ No newline at end of file
+ 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
\ No newline at end of file
diff --git a/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/Shark/Entities/Mobs/Species/Shark.yml b/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/Shark/Entities/Mobs/Species/Shark.yml
index 34e7903bbd..1c3792805f 100644
--- a/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/Shark/Entities/Mobs/Species/Shark.yml
+++ b/Resources/Prototypes/_LostParadise/Entities/Mobs/Species/Shark/Entities/Mobs/Species/Shark.yml
@@ -49,6 +49,9 @@
- type: Tag
tags:
- HidesTail
+ - CanPilot
+ - FootstepSound
+ - DoorBumpOpener
- type: Vocal
sounds:
Male: MaleHuman