Skip to content

Commit

Permalink
Oneirophage complete
Browse files Browse the repository at this point in the history
  • Loading branch information
VMSolidus committed Jun 10, 2024
1 parent 8432e2c commit 79e1110
Show file tree
Hide file tree
Showing 27 changed files with 507 additions and 312 deletions.
95 changes: 1 addition & 94 deletions Content.Server/Arachne/ArachneSystem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Content.Shared.Arachne;
using Content.Shared.Actions;
using Content.Shared.Actions.Events;
using Content.Shared.Coordinates.Helpers;
using Content.Shared.IdentityManagement;
using Content.Shared.Verbs;
Expand All @@ -15,32 +16,26 @@
using Content.Shared.Inventory;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.Examine;
using Content.Shared.Humanoid;
using Content.Shared.Nutrition.Components;
using Content.Shared.Nutrition.EntitySystems;
using Content.Server.Buckle.Systems;
using Content.Server.Nutrition.EntitySystems;
using Content.Server.Nutrition.Components;
using Content.Server.Popups;
using Content.Server.DoAfter;
using Content.Server.Body.Components;
using Content.Server.Vampiric;
using Content.Server.Speech.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Player;
using Robust.Shared.Physics.Components;
using Robust.Shared.Containers;
using Robust.Shared.Map;
using Robust.Shared.Utility;
using Robust.Server.Console;
using static Content.Shared.Examine.ExamineSystemShared;

namespace Content.Server.Arachne
{
public sealed class ArachneSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly HungerSystem _hungerSystem = default!;
[Dependency] private readonly ThirstSystem _thirstSystem = default!;
Expand All @@ -63,25 +58,15 @@ public sealed class ArachneSystem : EntitySystem
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ArachneComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<ArachneComponent, GetVerbsEvent<InnateVerb>>(AddCocoonVerb);

SubscribeLocalEvent<CocoonComponent, EntInsertedIntoContainerMessage>(OnCocEntInserted);
SubscribeLocalEvent<CocoonComponent, EntRemovedFromContainerMessage>(OnCocEntRemoved);
SubscribeLocalEvent<CocoonComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<CocoonComponent, GetVerbsEvent<AlternativeVerb>>(AddSuccVerb);

SubscribeLocalEvent<SpinWebActionEvent>(OnSpinWeb);

SubscribeLocalEvent<ArachneComponent, ArachneWebDoAfterEvent>(OnWebDoAfter);
SubscribeLocalEvent<ArachneComponent, ArachneCocoonDoAfterEvent>(OnCocoonDoAfter);
}

private void OnInit(EntityUid uid, ArachneComponent component, ComponentInit args)
{
_actions.AddAction(uid, ref component.WebActionEntity, component.WebActionId);
}

private void AddCocoonVerb(EntityUid uid, ArachneComponent component, GetVerbsEvent<InnateVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
Expand Down Expand Up @@ -198,63 +183,6 @@ private void OnEntRemoved(EntityUid uid, WebComponent web, EntRemovedFromContain
_buckleSystem.StrapSetEnabled(uid, false, strap);
}

private void OnSpinWeb(SpinWebActionEvent args)
{
if (!TryComp<ArachneComponent>(args.Performer, out var arachne))
return;

if (_containerSystem.IsEntityInContainer(args.Performer))
return;

TryComp<HungerComponent>(args.Performer, out var hunger);
TryComp<ThirstComponent>(args.Performer, out var thirst);

if (hunger != null && thirst != null)
{
if (hunger.CurrentThreshold <= Shared.Nutrition.Components.HungerThreshold.Peckish)
{
_popupSystem.PopupEntity(Loc.GetString("spin-web-action-hungry"), args.Performer, args.Performer, Shared.Popups.PopupType.MediumCaution);
return;
}
if (thirst.CurrentThirstThreshold <= ThirstThreshold.Thirsty)
{
_popupSystem.PopupEntity(Loc.GetString("spin-web-action-thirsty"), args.Performer, args.Performer, Shared.Popups.PopupType.MediumCaution);
return;
}
}

var coords = args.Target;
if (!_mapManager.TryGetGrid(coords.GetGridUid(EntityManager), out var grid))
{
_popupSystem.PopupEntity(Loc.GetString("action-name-spin-web-space"), args.Performer, args.Performer, Shared.Popups.PopupType.MediumCaution);
return;
}

foreach (var entity in coords.GetEntitiesInTile())
{
PhysicsComponent? physics = null; // We use this to check if it's impassable
if ((HasComp<WebComponent>(entity)) || // Is there already a web there?
((Resolve(entity, ref physics, false) && (physics.CollisionLayer & (int) CollisionGroup.Impassable) != 0) // Is it impassable?
&& !(TryComp<DoorComponent>(entity, out var door) && door.State != DoorState.Closed))) // Is it a door that's open and so not actually impassable?
{
_popupSystem.PopupEntity(Loc.GetString("action-name-spin-web-blocked"), args.Performer, args.Performer, Shared.Popups.PopupType.MediumCaution);
return;
}
}

_popupSystem.PopupEntity(Loc.GetString("spin-web-start-third-person", ("spider", Identity.Entity(args.Performer, EntityManager))), args.Performer,
Shared.Popups.PopupType.MediumCaution);
_popupSystem.PopupEntity(Loc.GetString("spin-web-start-second-person"), args.Performer, args.Performer, Shared.Popups.PopupType.Medium);

var ev = new ArachneWebDoAfterEvent(coords);
var doAfterArgs = new DoAfterArgs(EntityManager, args.Performer, arachne.WebDelay, ev, args.Performer)
{
BreakOnUserMove = true,
};

_doAfter.TryStartDoAfter(doAfterArgs);
}

private void StartCocooning(EntityUid uid, ArachneComponent component, EntityUid target)
{
_popupSystem.PopupEntity(Loc.GetString("cocoon-start-third-person", ("target", Identity.Entity(target, EntityManager)), ("spider", Identity.Entity(uid, EntityManager))), uid,
Expand All @@ -280,22 +208,6 @@ private void StartCocooning(EntityUid uid, ArachneComponent component, EntityUid
_doAfter.TryStartDoAfter(args);
}

private void OnWebDoAfter(EntityUid uid, ArachneComponent component, ArachneWebDoAfterEvent args)
{
if (args.Handled || args.Cancelled)
return;

_hungerSystem.ModifyHunger(uid, -8);
if (TryComp<ThirstComponent>(uid, out var thirst))
_thirstSystem.ModifyThirst(uid, thirst, -20);

Spawn("ArachneWeb", args.Coords.SnapToGrid());
_popupSystem.PopupEntity(Loc.GetString("spun-web-third-person", ("spider", Identity.Entity(uid, EntityManager))), uid,
Shared.Popups.PopupType.MediumCaution);
_popupSystem.PopupEntity(Loc.GetString("spun-web-second-person"), uid, uid, Shared.Popups.PopupType.Medium);
args.Handled = true;
}

private void OnCocoonDoAfter(EntityUid uid, ArachneComponent component, ArachneCocoonDoAfterEvent args)
{
if (args.Handled || args.Cancelled || args.Args.Target == null)
Expand All @@ -319,9 +231,6 @@ private void OnCocoonDoAfter(EntityUid uid, ArachneComponent component, ArachneC
var scale = Math.Clamp(1 / (35 / physics.FixturesMass), 0.35, 2.5);
_host.ExecuteCommand(null, "scale " + cocoon + " " + scale);
}

_inventorySystem.TryUnequip(args.Args.Target.Value, "ears", true, true);

_itemSlots.SetLock(cocoon, BodySlot, false, slots);
_itemSlots.TryInsert(cocoon, BodySlot, args.Args.Target.Value, args.Args.User);
_itemSlots.SetLock(cocoon, BodySlot, true, slots);
Expand All @@ -332,6 +241,4 @@ private void OnCocoonDoAfter(EntityUid uid, ArachneComponent component, ArachneC
args.Handled = true;
}
}

public sealed partial class SpinWebActionEvent : WorldTargetActionEvent {}
}
2 changes: 1 addition & 1 deletion Content.Server/Arachne/CocoonComponent.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace Content.Server.Arachne
{
[RegisterComponent]
public sealed class CocoonComponent : Component
public sealed partial class CocoonComponent : Component
{
public bool WasReplacementAccent = false;

Expand Down
2 changes: 1 addition & 1 deletion Content.Server/Vampire/BloodSuckedComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ namespace Content.Server.Vampiric
/// For entities who have been succed.
/// </summary>
[RegisterComponent]
public sealed class BloodSuckedComponent : Component
public sealed partial class BloodSuckedComponent : Component
{}
}
6 changes: 3 additions & 3 deletions Content.Server/Vampire/BloodSuckerComponent.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace Content.Server.Vampiric
{
[RegisterComponent]
public sealed class BloodSuckerComponent : Component
public sealed partial class BloodSuckerComponent : Component
{
/// <summary>
/// How much to succ each time we succ.
Expand All @@ -12,8 +12,8 @@ public sealed class BloodSuckerComponent : Component
/// <summary>
/// The time (in seconds) that it takes to succ an entity.
/// </summary>
[DataField("succDelay")]
public long SuccDelay = 4;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public TimeSpan Delay = TimeSpan.FromSeconds(4);

// ***INJECT WHEN SUCC***

Expand Down
42 changes: 18 additions & 24 deletions Content.Server/Vampire/BloodSuckerSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Player;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Utility;

namespace Content.Server.Vampiric
Expand All @@ -34,6 +35,7 @@ public sealed class BloodSuckerSystem : EntitySystem
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
public override void Initialize()
{
base.Initialize();
Expand Down Expand Up @@ -130,21 +132,14 @@ public void StartSuccDoAfter(EntityUid bloodsucker, EntityUid victim, BloodSucke
return;
}

if (_bloodstreamSystem.GetBloodLevelPercentage(victim, stream) <= 1)
{
if (HasComp<BloodSuckedComponent>(victim))
_popups.PopupEntity(Loc.GetString("bloodsucker-fail-no-blood-bloodsucked", ("target", victim)), victim, bloodsucker, Shared.Popups.PopupType.Medium);
else
_popups.PopupEntity(Loc.GetString("bloodsucker-fail-no-blood", ("target", victim)), victim, bloodsucker, Shared.Popups.PopupType.Medium);

return;
}
if (_solutionSystem.PercentFull(stream.Owner) != 0)
_popups.PopupEntity(Loc.GetString("bloodsucker-fail-no-blood", ("target", victim)), victim, bloodsucker, Shared.Popups.PopupType.Medium);

_popups.PopupEntity(Loc.GetString("bloodsucker-doafter-start-victim", ("sucker", bloodsucker)), victim, victim, Shared.Popups.PopupType.LargeCaution);
_popups.PopupEntity(Loc.GetString("bloodsucker-doafter-start", ("target", victim)), victim, bloodsucker, Shared.Popups.PopupType.Medium);

var ev = new BloodSuckDoAfterEvent();
var args = new DoAfterArgs(EntityManager, bloodsucker, new TimeSpan(bloodSuckerComponent.SuccDelay), ev, bloodsucker, target: victim)
var args = new DoAfterArgs(EntityManager, bloodsucker, bloodSuckerComponent.Delay, ev, bloodsucker, target: victim)
{
BreakOnTargetMove = true,
BreakOnUserMove = false,
Expand All @@ -155,14 +150,14 @@ public void StartSuccDoAfter(EntityUid bloodsucker, EntityUid victim, BloodSucke
_doAfter.TryStartDoAfter(args);
}

public bool TrySucc(EntityUid bloodsucker, EntityUid victim, BloodSuckerComponent? bloodsuckerComp = null, BloodstreamComponent? bloodstream = null)
public bool TrySucc(EntityUid bloodsucker, EntityUid victim, BloodSuckerComponent? bloodsuckerComp = null)
{
// Is bloodsucker a bloodsucker?
if (!Resolve(bloodsucker, ref bloodsuckerComp))
return false;

// Does victim have a bloodstream?
if (!Resolve(victim, ref bloodstream))
if (!TryComp<BloodstreamComponent>(victim, out var bloodstream))
return false;

// No blood left, yikes.
Expand All @@ -178,12 +173,8 @@ public bool TrySucc(EntityUid bloodsucker, EntityUid victim, BloodSuckerComponen
return false;

// Are we too full?
var unitsToDrain = bloodsuckerComp.UnitsToSucc;

if (_solutionSystem.TryGetDrainableSolution(stomachList) < unitsToDrain)
unitsToDrain = (float) stomachSolution.AvailableVolume;

if (unitsToDrain <= 2)
if (_solutionSystem.PercentFull(bloodsucker) >= 1)
{
_popups.PopupEntity(Loc.GetString("drink-component-try-use-drink-had-enough"), bloodsucker, bloodsucker, Shared.Popups.PopupType.MediumCaution);
return false;
Expand All @@ -192,14 +183,16 @@ public bool TrySucc(EntityUid bloodsucker, EntityUid victim, BloodSuckerComponen
_adminLogger.Add(Shared.Database.LogType.MeleeHit, Shared.Database.LogImpact.Medium, $"{ToPrettyString(bloodsucker):player} sucked blood from {ToPrettyString(victim):target}");

// All good, succ time.
SoundSystem.Play("/Audio/Items/drink.ogg", Filter.Pvs(bloodsucker), bloodsucker);
_audio.PlayPvs("/Audio/Items/drink.ogg", bloodsucker);
_popups.PopupEntity(Loc.GetString("bloodsucker-blood-sucked-victim", ("sucker", bloodsucker)), victim, victim, Shared.Popups.PopupType.LargeCaution);
_popups.PopupEntity(Loc.GetString("bloodsucker-blood-sucked", ("target", victim)), bloodsucker, bloodsucker, Shared.Popups.PopupType.Medium);
EnsureComp<BloodSuckedComponent>(victim);

// Make everything actually ingest.
var temp = _solutionSystem.SplitSolution(victim, bloodstream.BloodSolution, unitsToDrain);
temp.DoEntityReaction(bloodsucker, Shared.Chemistry.Reagent.ReactionMethod.Ingestion);
if (bloodstream.BloodSolution == null)
return false;

var temp = _solutionSystem.SplitSolution(bloodstream.BloodSolution.Value, bloodsuckerComp.UnitsToSucc);
_stomachSystem.TryTransferSolution(stomachList[0].Comp.Owner, temp, stomachList[0].Comp);

// Add a little pierce
Expand All @@ -208,10 +201,11 @@ public bool TrySucc(EntityUid bloodsucker, EntityUid victim, BloodSuckerComponen

_damageableSystem.TryChangeDamage(victim, damage, true, true);

if (bloodsuckerComp.InjectWhenSucc && _solutionSystem.TryGetInjectableSolution(victim, out var injectable))
{
_solutionSystem.TryAddReagent(victim, injectable, bloodsuckerComp.InjectReagent, bloodsuckerComp.UnitsToInject, out var acceptedQuantity);
}
//I'm not porting the nocturine gland, this code is deprecated, and will be reworked at a later date.
//if (bloodsuckerComp.InjectWhenSucc && _solutionSystem.TryGetInjectableSolution(victim, out var injectable))
//{
// _solutionSystem.TryAddReagent(victim, injectable, bloodsuckerComp.InjectReagent, bloodsuckerComp.UnitsToInject, out var acceptedQuantity);
//}
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Content.Server.Vampiric
/// <summary>
/// Item that gives a bloodsucker injection glands (for poison, usually)
/// </summary>
public sealed class BloodSuckerGlandInjectorComponent : Component
public sealed partial class BloodSuckerGlandInjectorComponent : Component
{
public bool Used = false;

Expand Down
14 changes: 3 additions & 11 deletions Content.Shared/Arachne/ArachneComponent.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;

namespace Content.Shared.Arachne
{
[RegisterComponent]
[RegisterComponent, NetworkedComponent]
public sealed partial class ArachneComponent : Component
{
[DataField("webDelay")]
public float WebDelay = 5f;

[DataField("cocoonDelay")]
public float CocoonDelay = 12f;

Expand All @@ -21,12 +20,5 @@ public sealed partial class ArachneComponent : Component

[DataField("webBloodReagent")]
public string WebBloodReagent = "Blood";

[DataField("webActionId",
customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? WebActionId = "SpinWeb";

[DataField("dispelActionEntity")]
public EntityUid? WebActionEntity;
}
}
18 changes: 0 additions & 18 deletions Content.Shared/Arachne/Events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,6 @@

namespace Content.Shared.Arachne
{
[Serializable, NetSerializable]
public sealed partial class ArachneWebDoAfterEvent : DoAfterEvent
{
[DataField("coords", required: true)]
public EntityCoordinates Coords = default!;

private ArachneWebDoAfterEvent()
{
}

public ArachneWebDoAfterEvent(EntityCoordinates coords)
{
Coords = coords;
}

public override DoAfterEvent Clone() => this;
}

[Serializable, NetSerializable]
public sealed partial class ArachneCocoonDoAfterEvent : SimpleDoAfterEvent
{
Expand Down
5 changes: 4 additions & 1 deletion Content.Shared/Arachne/WebComponent.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;

namespace Content.Shared.Arachne
{
[RegisterComponent]
[RegisterComponent, NetworkedComponent]
public sealed partial class WebComponent : Component
{}
}
Loading

0 comments on commit 79e1110

Please sign in to comment.