-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'refs/remotes/real-ee/master' into feat/…
…floof-upstream-merge-2024-09-05 # Conflicts: # Resources/Locale/en-US/devices/device-network.ftl # Resources/Locale/en-US/reagents/meta/consumable/drink/alcohol.ftl # Resources/Locale/en-US/revenant/revenant.ftl # Resources/Locale/en-US/weapons/melee/melee.ftl # Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml # Resources/Prototypes/Roles/Jobs/Civilian/chaplain.yml # Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml # Resources/Prototypes/Roles/Jobs/Science/research_director.yml
- Loading branch information
Showing
45 changed files
with
724 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
using Content.Server.Body.Components; | ||
using Content.Server.Chemistry.Containers.EntitySystems; | ||
using Content.Shared.CCVar; | ||
using Content.Shared.Chemistry.Reagent; | ||
using Content.Shared.Contests; | ||
using Content.Shared.HeightAdjust; | ||
using Robust.Shared.Configuration; | ||
|
||
namespace Content.Server.HeightAdjust; | ||
|
||
public sealed class BloodstreamAdjustSystem : EntitySystem | ||
{ | ||
[Dependency] private readonly IConfigurationManager _config = default!; | ||
[Dependency] private readonly ContestsSystem _contests = default!; | ||
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!; | ||
|
||
public override void Initialize() | ||
{ | ||
SubscribeLocalEvent<BloodstreamAffectedByMassComponent, MapInitEvent>((uid, comp, _) => TryAdjustBloodstream((uid, comp))); | ||
SubscribeLocalEvent<BloodstreamAffectedByMassComponent, HeightAdjustedEvent>((uid, comp, _) => TryAdjustBloodstream((uid, comp))); | ||
} | ||
|
||
/// <summary> | ||
/// Adjusts the bloodstream of the specified entity based on the settings provided by the component. | ||
/// </summary> | ||
public bool TryAdjustBloodstream(Entity<BloodstreamAffectedByMassComponent> ent) | ||
{ | ||
if (!TryComp<BloodstreamComponent>(ent, out var bloodstream) | ||
|| !_solutionContainer.TryGetSolution(ent.Owner, bloodstream.BloodSolutionName, out var bloodSolutionEnt) | ||
|| !_config.GetCVar(CCVars.HeightAdjustModifiesBloodstream)) | ||
return false; | ||
|
||
var bloodSolution = bloodSolutionEnt.Value.Comp.Solution; | ||
|
||
var factor = Math.Pow(_contests.MassContest(ent, bypassClamp: true, rangeFactor: 4f), ent.Comp.Power); | ||
factor = Math.Clamp(factor, ent.Comp.Min, ent.Comp.Max); | ||
|
||
var newVolume = bloodstream.BloodMaxVolume * factor; | ||
var newBloodLevel = bloodSolution.FillFraction * newVolume; | ||
bloodSolution.MaxVolume = newVolume; | ||
bloodSolution.SetContents([new ReagentQuantity(bloodstream.BloodReagent, newBloodLevel, null)], false); | ||
|
||
return true; | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
Content.Server/HeightAdjust/BloodstreamAffectedByMassComponent.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using Content.Server.Body.Components; | ||
|
||
namespace Content.Server.HeightAdjust; | ||
|
||
/// <summary> | ||
/// When applied to a humanoid or any mob, adjusts their blood level based on the mass contest between them | ||
/// and an average humanoid. | ||
/// <br/> | ||
/// The formula for the resulting bloodstream volume is <code>V = BloodMaxVolume * MassContest^Power</code> | ||
/// clamped between the specified Min and Max values. | ||
/// </summary> | ||
[RegisterComponent] | ||
public sealed partial class BloodstreamAffectedByMassComponent : Component | ||
{ | ||
/// <summary> | ||
/// Minimum and maximum resulting volume factors. A minimum value of 0.5 means that the resulting volume will be at least 50% of the original. | ||
/// </summary> | ||
[DataField] | ||
public float Min = 1 / 3f, Max = 3f; | ||
|
||
/// <summary> | ||
/// The power to which the outcome of the mass contest will be risen. | ||
/// </summary> | ||
[DataField] | ||
public float Power = 1f; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
using Content.Shared.InteractionVerbs; | ||
using Content.Shared.Mood; | ||
using Robust.Shared.Prototypes; | ||
|
||
namespace Content.Server.InteractionVerbs.Actions; | ||
|
||
/// <summary> | ||
/// An action that adds a moodlet to the target, or removes one. | ||
/// </summary> | ||
[Serializable] | ||
public sealed partial class MoodAction : InteractionAction | ||
{ | ||
[DataField(required: true)] | ||
public ProtoId<MoodEffectPrototype> Effect; | ||
|
||
/// <summary> | ||
/// Parameters for the <see cref="MoodEffectEvent"/>. Only used if <see cref="Remove"/> is false. | ||
/// </summary> | ||
[DataField] | ||
public float Modifier = 1f, Offset = 0f; | ||
|
||
/// <summary> | ||
/// If true, the moodlet will be removed. Otherwise, it will be added. | ||
/// </summary> | ||
[DataField] | ||
public bool Remove = false; | ||
|
||
public override bool CanPerform(InteractionArgs args, InteractionVerbPrototype proto, bool isBefore, VerbDependencies deps) | ||
{ | ||
return true; | ||
} | ||
|
||
public override bool Perform(InteractionArgs args, InteractionVerbPrototype proto, VerbDependencies deps) | ||
{ | ||
if (Remove) | ||
deps.EntMan.EventBus.RaiseLocalEvent(args.Target, new MoodRemoveEffectEvent(Effect)); | ||
else | ||
deps.EntMan.EventBus.RaiseLocalEvent(args.Target, new MoodEffectEvent(Effect, Modifier, Offset)); | ||
|
||
return true; // Mood system is shitcode so we can't even know if the effect was added or anything | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
Content.Server/StationEvents/Components/OscillatingStationEventSchedulerComponent.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
namespace Content.Server.StationEvents.Components; | ||
|
||
/// <summary> | ||
/// A station event scheduler that emits events at irregular intervals, with occasional chaos and occasional calmness. | ||
/// </summary> | ||
[RegisterComponent] | ||
public sealed partial class OscillatingStationEventSchedulerComponent : Component | ||
{ | ||
// TODO cvars? | ||
[DataField] | ||
public float MinChaos = 0.1f, MaxChaos = 15f; | ||
|
||
/// <summary> | ||
/// The amount of chaos at the beginning of the round. | ||
/// </summary> | ||
[DataField] | ||
public float StartingChaosRatio = 0f; | ||
|
||
/// <summary> | ||
/// The value of the first derivative of the event delay function at the beginning of the shift. | ||
/// Must be between 1 and -1. | ||
/// </summary> | ||
[DataField] | ||
public float StartingSlope = 1f; | ||
|
||
/// <summary> | ||
/// Biases that determine how likely the event rate is to go up or down, and how fast it's going to happen. | ||
/// </summary> | ||
/// <remarks> | ||
/// Downwards bias must always be negative, and upwards must be positive. Otherwise, you'll get odd behavior or errors. | ||
/// </remarks> | ||
[DataField] | ||
public float DownwardsBias = -1f, UpwardsBias = 1f; | ||
|
||
/// <summary> | ||
/// Limits that define how large the chaos slope can become. | ||
/// </summary> | ||
/// <remarks> | ||
/// Downwards limit must always be negative, and upwards must be positive. Otherwise, you'll get odd behavior or errors. | ||
/// </remarks> | ||
[DataField] | ||
public float DownwardsLimit = -1f, UpwardsLimit = 1f; | ||
|
||
/// <summary> | ||
/// A value between 0 and 1 that determines how slowly the chaos and its first derivative change in time. | ||
/// </summary> | ||
/// <remarks> | ||
/// Changing these values will have a great impact on how fast the event rate changes. | ||
/// </remarks> | ||
[DataField] | ||
public float ChaosStickiness = 0.93f, SlopeStickiness = 0.96f; | ||
|
||
/// <summary> | ||
/// Actual chaos data at the current moment. Those are overridden at runtime. | ||
/// </summary> | ||
[DataField] | ||
public float CurrentChaos, CurrentSlope, LastAcceleration; | ||
|
||
|
||
[DataField] | ||
public TimeSpan NextUpdate = TimeSpan.Zero, LastEventTime = TimeSpan.Zero; | ||
|
||
/// <summary> | ||
/// Update interval, which determines how often current chaos is recalculated. | ||
/// Modifying this value does not directly impact the event rate, but changes how stable the slope is. | ||
/// </summary> | ||
[DataField] | ||
public TimeSpan UpdateInterval = TimeSpan.FromSeconds(5f); | ||
} |
102 changes: 102 additions & 0 deletions
102
Content.Server/StationEvents/OscillatingStationEventScheduler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
using System.Diagnostics; | ||
using System.Diagnostics.CodeAnalysis; | ||
using Content.Server.GameTicking; | ||
using Content.Server.GameTicking.Rules; | ||
using Content.Server.GameTicking.Rules.Components; | ||
using Content.Server.StationEvents.Components; | ||
using Content.Shared.CCVar; | ||
using Robust.Shared.Configuration; | ||
using Robust.Shared.Random; | ||
using Robust.Shared.Timing; | ||
using Robust.Shared.Utility; | ||
|
||
namespace Content.Server.StationEvents; | ||
|
||
public sealed class OscillatingStationEventSchedulerSystem : GameRuleSystem<OscillatingStationEventSchedulerComponent> | ||
{ | ||
[Dependency] private readonly IConfigurationManager _cfg = default!; | ||
[Dependency] private readonly IRobustRandom _random = default!; | ||
[Dependency] private readonly EventManagerSystem _event = default!; | ||
[Dependency] private readonly GameTicker _gameTicker = default!; | ||
[Dependency] private readonly IGameTiming _timing = default!; | ||
|
||
[Conditional("DEBUG")] | ||
private void DebugValidateParams(OscillatingStationEventSchedulerComponent c) | ||
{ | ||
// This monstrousity is necessary because if someone fucks up one of these parameters, | ||
// it will likely either crash the game (in debug), or cause the event scheduler to stop working and spam the server console (in prod) | ||
DebugTools.Assert(c.DownwardsBias <= 0f && c.UpwardsBias >= 0f, "Fix your scheduler bias"); | ||
DebugTools.Assert(c.DownwardsLimit <= 0f && c.UpwardsLimit >= 0f, "Fix your scheduler slope limits"); | ||
DebugTools.Assert(c.UpdateInterval > TimeSpan.Zero, "Scheduler update interval must be positive"); | ||
DebugTools.Assert(c.ChaosStickiness >= 0f && c.ChaosStickiness <= 1f, "Scheduler stickiness must be between 0 and 1"); | ||
DebugTools.Assert(c.SlopeStickiness >= 0f && c.SlopeStickiness <= 1f, "Scheduler stickiness must be between 0 and 1"); | ||
DebugTools.Assert(c.MinChaos < c.MaxChaos, "Don't set the minimum above the maximum"); | ||
} | ||
|
||
private TimeSpan CalculateAverageEventTime(OscillatingStationEventSchedulerComponent comp) | ||
{ | ||
//TODO Those cvars are bad | ||
var min = _cfg.GetCVar(CCVars.GameEventsOscillatingMinimumTime); | ||
var max = _cfg.GetCVar(CCVars.GameEventsOscillatingAverageTime); | ||
|
||
return TimeSpan.FromSeconds(min + (max - min) / comp.CurrentChaos); // Why does C# have no math.lerp?????????????? | ||
} | ||
|
||
protected override void Started(EntityUid uid, OscillatingStationEventSchedulerComponent comp, GameRuleComponent gameRule, GameRuleStartedEvent args) | ||
{ | ||
DebugValidateParams(comp); | ||
|
||
comp.CurrentChaos = comp.MinChaos + comp.StartingChaosRatio * (comp.MaxChaos - comp.MinChaos); | ||
comp.CurrentSlope = comp.StartingSlope; | ||
|
||
comp.NextUpdate = _timing.CurTime + CalculateAverageEventTime(comp); | ||
comp.LastEventTime = _timing.CurTime; // Just so we don't run an event the very moment this scheduler gets added | ||
} | ||
|
||
protected override void ActiveTick(EntityUid uid, OscillatingStationEventSchedulerComponent comp, GameRuleComponent gameRule, float frameTime) | ||
{ | ||
if (comp.NextUpdate > _timing.CurTime) | ||
return; | ||
comp.NextUpdate = _timing.CurTime + comp.UpdateInterval; | ||
DebugValidateParams(comp); | ||
|
||
// Slope is the first derivative of chaos, and acceleration is the second | ||
// We randomize acceleration on each tick and simulate its effect on the slope and base function | ||
// But we spread the effect across a longer time span to achieve a smooth and pleasant result | ||
var delta = (float) comp.UpdateInterval.TotalSeconds; | ||
var newAcceleration = _random.NextFloat(comp.DownwardsBias, comp.UpwardsBias); | ||
var newSlope = | ||
Math.Clamp(comp.CurrentSlope + newAcceleration * delta, comp.DownwardsLimit, comp.UpwardsLimit) * (1 - comp.SlopeStickiness) | ||
+ comp.CurrentSlope * comp.SlopeStickiness; | ||
var newChaos = | ||
Math.Clamp(comp.CurrentChaos + newSlope * delta, comp.MinChaos, comp.MaxChaos) * (1 - comp.ChaosStickiness) | ||
+ comp.CurrentChaos * comp.ChaosStickiness; | ||
|
||
comp.CurrentChaos = newChaos; | ||
comp.CurrentSlope = newSlope; | ||
comp.LastAcceleration = newAcceleration; | ||
|
||
// We do not use fixed "next event" times because that can cause us to skip over chaos spikes due to periods of low chaos | ||
// Instead we recalculate the time until next event every time, so it can change before the event is even started | ||
var targetDelay = CalculateAverageEventTime(comp); | ||
if (_timing.CurTime > comp.LastEventTime + targetDelay && TryRunNextEvent(uid, comp, out _)) | ||
{ | ||
#if DEBUG | ||
var passed = _timing.CurTime - comp.LastEventTime; | ||
Log.Debug($"Running an event after {passed.TotalSeconds} sec since last event. Next event scheduled in {CalculateAverageEventTime(comp).TotalSeconds} sec."); | ||
#endif | ||
|
||
comp.LastEventTime = _timing.CurTime; | ||
} | ||
} | ||
|
||
public bool TryRunNextEvent(EntityUid uid, OscillatingStationEventSchedulerComponent comp, [NotNullWhen(true)] out string? runEvent) | ||
{ | ||
runEvent = _event.PickRandomEvent(); | ||
if (runEvent == null) | ||
return false; | ||
|
||
_gameTicker.AddGameRule(runEvent); | ||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.