This commit is contained in:
Rane
2022-07-27 00:46:24 -04:00
committed by GitHub
parent 963ddd507b
commit 1c8bdaf7c4
53 changed files with 698 additions and 36 deletions

View File

@@ -45,7 +45,8 @@ namespace Content.Server.Atmos.Miasma
"VanAusdallsRobovirus",
"BleedersBite",
"Plague",
"TongueTwister"
"TongueTwister",
"MemeticAmirmir"
};
/// <summary>

View File

@@ -28,7 +28,8 @@ namespace Content.Server.Atmos.Portable
Gas.Plasma,
Gas.Tritium,
Gas.WaterVapor,
Gas.Miasma
Gas.Miasma,
Gas.NitrousOxide
};
/// <summary>

View File

@@ -5,17 +5,26 @@ using Content.Server.Body.Systems;
using Content.Shared.Buckle.Components;
using Content.Shared.Body.Components;
using Content.Shared.Bed;
using Content.Shared.Bed.Sleep;
using Content.Server.Bed.Sleep;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Shared.Emag.Systems;
using Content.Shared.MobState.Components;
using Content.Server.Actions;
using Content.Server.MobState;
using Content.Shared.Actions.ActionTypes;
using Robust.Shared.Prototypes;
namespace Content.Server.Bed
{
public sealed class BedSystem : EntitySystem
{
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly ActionsSystem _actionsSystem = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly SleepingSystem _sleepingSystem = default!;
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
public override void Initialize()
{
base.Initialize();
@@ -27,12 +36,19 @@ namespace Content.Server.Bed
private void ManageUpdateList(EntityUid uid, HealOnBuckleComponent component, BuckleChangeEvent args)
{
_prototypeManager.TryIndex<InstantActionPrototype>("Sleep", out var sleepAction);
if (args.Buckling)
{
AddComp<HealOnBuckleHealingComponent>(uid);
if (sleepAction != null)
_actionsSystem.AddAction(args.BuckledEntity, new InstantAction(sleepAction), null);
return;
}
if (sleepAction != null)
_actionsSystem.RemoveAction(args.BuckledEntity, sleepAction, null);
_sleepingSystem.TryWaking(args.BuckledEntity);
RemComp<HealOnBuckleHealingComponent>(uid);
component.Accumulator = 0;
}
@@ -52,13 +68,16 @@ namespace Content.Server.Bed
if (strapComponent.BuckledEntities.Count == 0) continue;
var mobStateQuery = GetEntityQuery<MobStateComponent>();
foreach (var healedEntity in strapComponent.BuckledEntities)
{
if (mobStateQuery.TryGetComponent(healedEntity, out var state) && state.IsDead())
if (_mobStateSystem.IsDead(healedEntity))
continue;
var damage = bedComponent.Damage;
if (HasComp<SleepingComponent>(healedEntity))
damage *= bedComponent.SleepMultiplier;
_damageableSystem.TryChangeDamage(healedEntity, bedComponent.Damage, true);
}
}

View File

@@ -12,6 +12,9 @@ namespace Content.Server.Bed.Components
[DataField("healTime", required: false)]
[ViewVariables(VVAccess.ReadWrite)]
public float HealTime = 1f; // How often the bed applies the damage
[DataField("sleepMultiplier")]
public float SleepMultiplier = 3f;
public float Accumulator = 0f; //Time accumulated
}
}

View File

@@ -0,0 +1,198 @@
using Content.Shared.Stunnable;
using Content.Shared.MobState.Components;
using Content.Shared.Bed.Sleep;
using Content.Shared.Damage;
using Content.Server.Actions;
using Content.Shared.Actions.ActionTypes;
using Robust.Shared.Prototypes;
using Content.Shared.Sound;
using Robust.Shared.Timing;
using Content.Shared.MobState;
using Content.Server.MobState;
using Content.Server.Sound.Components;
using Content.Shared.Verbs;
using Content.Shared.Interaction;
using Robust.Shared.Audio;
using Robust.Shared.Player;
using Content.Shared.Audio;
using Content.Server.Popups;
using Content.Shared.Examine;
using Content.Shared.IdentityManagement;
using Robust.Shared.Random;
namespace Content.Server.Bed.Sleep
{
public sealed class SleepingSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly ActionsSystem _actionsSystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<MobStateComponent, SleepStateChangedEvent>(OnSleepStateChanged);
SubscribeLocalEvent<SleepingComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<MobStateComponent, SleepActionEvent>(OnSleepAction);
SubscribeLocalEvent<MobStateComponent, WakeActionEvent>(OnWakeAction);
SubscribeLocalEvent<SleepingComponent, MobStateChangedEvent>(OnMobStateChanged);
SubscribeLocalEvent<SleepingComponent, GetVerbsEvent<AlternativeVerb>>(AddWakeVerb);
SubscribeLocalEvent<SleepingComponent, InteractHandEvent>(OnInteractHand);
SubscribeLocalEvent<SleepingComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<ForcedSleepingComponent, ComponentInit>(OnInit);
}
/// <summary>
/// when sleeping component is added or removed, we do some stuff with other components.
/// </summary>
private void OnSleepStateChanged(EntityUid uid, MobStateComponent component, SleepStateChangedEvent args)
{
_prototypeManager.TryIndex<InstantActionPrototype>("Wake", out var wakeAction);
if (args.FellAsleep)
{
EnsureComp<StunnedComponent>(uid);
EnsureComp<KnockedDownComponent>(uid);
var emitSound = EnsureComp<SpamEmitSoundComponent>(uid);
emitSound.Sound = new SoundCollectionSpecifier("Snores");
emitSound.PlayChance = 0.33f;
emitSound.RollInterval = 5f;
emitSound.PopUp = "sleep-onomatopoeia";
emitSound.PitchVariation = 0.2f;
if (wakeAction != null)
{
var wakeInstance = new InstantAction(wakeAction);
wakeInstance.Cooldown = (_gameTiming.CurTime, _gameTiming.CurTime + TimeSpan.FromSeconds(15));
_actionsSystem.AddAction(uid, wakeInstance, null);
}
return;
}
if (wakeAction != null)
_actionsSystem.RemoveAction(uid, wakeAction);
RemComp<StunnedComponent>(uid);
RemComp<KnockedDownComponent>(uid);
RemComp<SpamEmitSoundComponent>(uid);
}
/// <summary>
/// Wake up if we take an instance of more than 2 damage.
/// </summary>
private void OnDamageChanged(EntityUid uid, SleepingComponent component, DamageChangedEvent args)
{
if (!args.DamageIncreased || args.DamageDelta == null)
return;
if (args.DamageDelta.Total >= component.WakeThreshold)
TryWaking(uid);
}
private void OnSleepAction(EntityUid uid, MobStateComponent component, SleepActionEvent args)
{
TrySleeping(uid);
}
private void OnWakeAction(EntityUid uid, MobStateComponent component, WakeActionEvent args)
{
TryWaking(uid);
}
/// <summary>
/// In crit, we wake up if we are not being forced to sleep.
/// And, you can't sleep when dead...
/// </summary>
private void OnMobStateChanged(EntityUid uid, SleepingComponent component, MobStateChangedEvent args)
{
if (_mobStateSystem.IsCritical(uid) && !HasComp<ForcedSleepingComponent>(uid))
{
RemComp<SleepingComponent>(uid);
return;
}
if (_mobStateSystem.IsDead(uid))
RemComp<SleepingComponent>(uid);
}
private void AddWakeVerb(EntityUid uid, SleepingComponent component, GetVerbsEvent<AlternativeVerb> args)
{
if (!args.CanInteract || !args.CanAccess)
return;
AlternativeVerb verb = new()
{
Act = () =>
{
TryWaking(args.Target, user: args.User);
},
Text = Loc.GetString("action-name-wake"),
Priority = 2
};
args.Verbs.Add(verb);
}
/// <summary>
/// When you click on a sleeping person with an empty hand, try to wake them.
/// </summary>
private void OnInteractHand(EntityUid uid, SleepingComponent component, InteractHandEvent args)
{
args.Handled = true;
TryWaking(args.Target, user: args.User);
}
private void OnExamined(EntityUid uid, SleepingComponent component, ExaminedEvent args)
{
if (args.IsInDetailsRange)
{
args.PushMarkup(Loc.GetString("sleep-examined", ("target", Identity.Entity(uid, EntityManager))));
}
}
private void OnInit(EntityUid uid, ForcedSleepingComponent component, ComponentInit args)
{
TrySleeping(uid);
}
/// <summary>
/// Try sleeping. Only mobs can sleep.
/// </summary>
public bool TrySleeping(EntityUid uid)
{
if (!HasComp<MobStateComponent>(uid))
return false;
if (_prototypeManager.TryIndex<InstantActionPrototype>("Sleep", out var sleepAction))
_actionsSystem.RemoveAction(uid, sleepAction);
EnsureComp<SleepingComponent>(uid);
return true;
}
/// <summary>
/// Try to wake up.
/// </summary>
public bool TryWaking(EntityUid uid, bool force = false, EntityUid? user = null)
{
if (!force && HasComp<ForcedSleepingComponent>(uid))
{
if (user != null)
{
SoundSystem.Play("/Audio/Effects/thudswoosh.ogg", Filter.Pvs(uid), uid, AudioHelpers.WithVariation(0.05f, _robustRandom));
_popupSystem.PopupEntity(Loc.GetString("wake-other-failure", ("target", Identity.Entity(uid, EntityManager))), uid, Filter.Entities(user.Value), Shared.Popups.PopupType.SmallCaution);
}
return false;
}
if (user != null)
{
SoundSystem.Play("/Audio/Effects/thudswoosh.ogg", Filter.Pvs(uid), uid, AudioHelpers.WithVariation(0.05f, _robustRandom));
_popupSystem.PopupEntity(Loc.GetString("wake-other-success", ("target", Identity.Entity(uid, EntityManager))), uid, Filter.Entities(user.Value));
}
RemComp<SleepingComponent>(uid);
return true;
}
}
}

View File

@@ -18,6 +18,7 @@ using Robust.Shared.Containers;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using Content.Shared.IdentityManagement;
using Content.Shared.Bed.Sleep;
namespace Content.Server.Buckle.Components
{
@@ -264,6 +265,9 @@ namespace Content.Server.Buckle.Components
{
return false;
}
if (EntMan.TryGetComponent<SleepingComponent>(Owner, out var sleeping) && Owner == user)
return false;
// If the strap is a vehicle and the rider is not the person unbuckling, return.
if (EntMan.TryGetComponent<VehicleComponent>(oldBuckledTo.Owner, out var vehicle) &&
vehicle.Rider != user)

View File

@@ -1,6 +1,7 @@
using Content.Shared.Disease;
using Content.Server.Buckle.Components;
using Content.Server.Bed.Components;
using Content.Shared.Bed.Sleep;
namespace Content.Server.Disease.Cures
{
@@ -12,6 +13,11 @@ namespace Content.Server.Disease.Cures
{
[ViewVariables(VVAccess.ReadWrite)]
public int Ticker = 0;
/// How many extra ticks you get for sleeping.
[DataField("sleepMultiplier")]
public int SleepMultiplier = 3;
[DataField("maxLength", required: true)]
[ViewVariables(VVAccess.ReadWrite)]
public int MaxLength = 60;
@@ -21,14 +27,19 @@ namespace Content.Server.Disease.Cures
if (!args.EntityManager.TryGetComponent<BuckleComponent>(args.DiseasedEntity, out var buckle) ||
!args.EntityManager.HasComponent<HealOnBuckleComponent>(buckle.BuckledTo?.Owner))
return false;
var ticks = 1;
if (args.EntityManager.HasComponent<SleepingComponent>(args.DiseasedEntity))
ticks *= SleepMultiplier;
if (buckle.Buckled)
Ticker++;
Ticker += ticks;
return Ticker >= MaxLength;
}
public override string CureText()
{
return (Loc.GetString("diagnoser-cure-bedrest", ("time", MaxLength)));
return (Loc.GetString("diagnoser-cure-bedrest", ("time", MaxLength), ("sleep", (MaxLength / SleepMultiplier))));
}
}
}

View File

@@ -1,5 +1,4 @@
using System.Threading;
using Content.Server.Chat;
using Content.Shared.Disease;
using Content.Shared.Disease.Components;
using Content.Server.Disease.Components;
@@ -20,6 +19,8 @@ using Content.Shared.Inventory.Events;
using Content.Server.Nutrition.EntitySystems;
using Robust.Shared.Utility;
using Content.Shared.IdentityManagement;
using Content.Shared.Item;
using Content.Server.MobState;
namespace Content.Server.Disease
{
@@ -37,14 +38,14 @@ namespace Content.Server.Disease
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<DiseaseCarrierComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<DiseaseCarrierComponent, CureDiseaseAttemptEvent>(OnTryCureDisease);
SubscribeLocalEvent<DiseasedComponent, InteractHandEvent>(OnInteractDiseasedHand);
SubscribeLocalEvent<DiseasedComponent, InteractUsingEvent>(OnInteractDiseasedUsing);
SubscribeLocalEvent<DiseasedComponent, UserInteractedWithItemEvent>(OnUserInteractDiseased);
SubscribeLocalEvent<DiseasedComponent, ItemInteractedWithEvent>(OnTargetInteractDiseased);
SubscribeLocalEvent<DiseasedComponent, EntitySpokeEvent>(OnEntitySpeak);
SubscribeLocalEvent<DiseaseProtectionComponent, GotEquippedEvent>(OnEquipped);
SubscribeLocalEvent<DiseaseProtectionComponent, GotUnequippedEvent>(OnUnequipped);
@@ -88,7 +89,7 @@ namespace Content.Server.Disease
{
DebugTools.Assert(carrierComp.Diseases.Count > 0);
if (mobState.IsDead())
if (_mobStateSystem.IsDead(mobState.Owner, mobState))
{
if (_random.Prob(0.005f * frameTime)) //Mean time to remove is 200 seconds per disease
CureDisease(carrierComp, _random.Pick(carrierComp.Diseases));
@@ -246,21 +247,19 @@ namespace Content.Server.Disease
}
/// <summary>
/// Called when someone interacts with a diseased person with an empty hand
/// to check if they get infected
/// When a diseased person interacts with something, check infection.
/// </summary>
private void OnInteractDiseasedHand(EntityUid uid, DiseasedComponent component, InteractHandEvent args)
private void OnUserInteractDiseased(EntityUid uid, DiseasedComponent component, UserInteractedWithItemEvent args)
{
InteractWithDiseased(args.Target, args.User);
InteractWithDiseased(args.User, args.Item);
}
/// <summary>
/// Called when someone interacts with a diseased person with any object
/// to check if they get infected
/// When a diseased person is interacted with, check infection.
/// </summary>
private void OnInteractDiseasedUsing(EntityUid uid, DiseasedComponent component, InteractUsingEvent args)
private void OnTargetInteractDiseased(EntityUid uid, DiseasedComponent component, ItemInteractedWithEvent args)
{
InteractWithDiseased(args.Target, args.User);
InteractWithDiseased(args.Item, args.User);
}
private void OnEntitySpeak(EntityUid uid, DiseasedComponent component, EntitySpokeEvent args)

View File

@@ -7,7 +7,7 @@ using Robust.Shared.Audio;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using Robust.Shared.Random;
using Content.Shared.Bed.Sleep;
namespace Content.Server.Interaction;
@@ -28,6 +28,10 @@ public sealed class InteractionPopupSystem : EntitySystem
if (args.Handled || args.User == args.Target)
return;
//Handling does nothing and this thing annoyingly plays way too often.
if (HasComp<SleepingComponent>(uid))
return;
var curTime = _gameTiming.CurTime;
if (curTime < component.LastInteractTime + component.InteractDelay)

View File

@@ -14,5 +14,9 @@ namespace Content.Server.Sound.Components
[DataField("playChance")]
public float PlayChance = 0.5f;
// Always Pvs.
[DataField("popUp")]
public string? PopUp;
}
}

View File

@@ -12,6 +12,7 @@ using Robust.Shared.Audio;
using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Random;
using Content.Server.Popups;
namespace Content.Server.Sound
{
@@ -24,6 +25,7 @@ namespace Content.Server.Sound
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
/// <inheritdoc />
@@ -41,6 +43,8 @@ namespace Content.Server.Sound
if (_random.Prob(soundSpammer.PlayChance))
{
if (soundSpammer.PopUp != null)
_popupSystem.PopupEntity(Loc.GetString(soundSpammer.PopUp), soundSpammer.Owner, Filter.Pvs(soundSpammer.Owner));
TryEmitSound(soundSpammer);
}
}

View File

@@ -28,6 +28,7 @@ public sealed class GasArtifactComponent : Component
Gas.CarbonDioxide,
Gas.Tritium,
Gas.Miasma,
Gas.NitrousOxide,
};
/// <summary>

View File

@@ -28,6 +28,7 @@ namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems
"OwOnavirus",
"BleedersBite",
"Ultragigacancer",
"MemeticAmirmir",
"AMIV"
};

View File

@@ -18,7 +18,8 @@ public sealed class ArtifactGasTriggerComponent : Component
Gas.Plasma,
Gas.Nitrogen,
Gas.CarbonDioxide,
Gas.Miasma
Gas.Miasma,
Gas.NitrousOxide,
};
/// <summary>