Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port Arachne & maybe Oniro from EE #2199

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions Content.Client/_EE/Cocoon/CocoonSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Content.Shared.Cocoon;
using Content.Shared.Humanoid;
using Robust.Client.GameObjects;
using Robust.Shared.Containers;
using System.Numerics;

namespace Content.Client.Cocoon
{
public sealed class CocoonSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<CocoonComponent, EntInsertedIntoContainerMessage>(OnCocEntInserted);
}

private void OnCocEntInserted(EntityUid uid, CocoonComponent component, EntInsertedIntoContainerMessage args)
{
if (!TryComp<SpriteComponent>(uid, out var cocoonSprite))
return;

if (TryComp<HumanoidAppearanceComponent>(args.Entity, out var humanoidAppearance)) // If humanoid, use height and width
cocoonSprite.Scale = new Vector2(1,1);
else if (!TryComp<SpriteComponent>(args.Entity, out var entSprite))
return;
else if (entSprite.BaseRSI != null) // Set scale based on sprite scale + sprite dimensions. Ideally we would somehow get a bounding box from the sprite size not including transparent pixels, but FUCK figuring that out.
cocoonSprite.Scale = entSprite.Scale * (entSprite.BaseRSI.Size / 32);
else if (entSprite.Scale != cocoonSprite.Scale) // if basersi somehow not found (?) just use scale
cocoonSprite.Scale = entSprite.Scale;
}
}
}
202 changes: 202 additions & 0 deletions Content.Server/_EE/Cocoon/CocoonerSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
using Content.Shared.Cocoon;
using Content.Shared.IdentityManagement;
using Content.Shared.Verbs;
using Content.Shared.DoAfter;
using Content.Shared.Stunnable;
using Content.Shared.Eye.Blinding.Systems;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Damage;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
using Content.Shared.Humanoid;
using Content.Server.Popups;
using Content.Server.DoAfter;
using Content.Server.Speech.Components;
using Robust.Shared.Containers;
using Content.Shared.Mobs.Components;
using Content.Shared.Destructible;
using Robust.Shared.Random;
using Content.Shared.Nutrition.Components;
using Content.Shared.Storage;
using Robust.Shared.Utility;

namespace Content.Server.Cocoon
{
public sealed class CocooningSystem : EntitySystem
{
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly DoAfterSystem _doAfter = default!;
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
[Dependency] private readonly BlindableSystem _blindableSystem = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly SharedDestructibleSystem _destructibleSystem = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;

private const string BodySlot = "body_slot";

public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CocoonerComponent, GetVerbsEvent<InnateVerb>>(AddVerbs);
SubscribeLocalEvent<CocoonComponent, EntInsertedIntoContainerMessage>(OnCocEntInserted);
SubscribeLocalEvent<CocoonComponent, EntRemovedFromContainerMessage>(OnCocEntRemoved);
SubscribeLocalEvent<CocoonComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<CocoonerComponent, CocoonDoAfterEvent>(OnCocoonDoAfter);
SubscribeLocalEvent<CocoonerComponent, UnCocoonDoAfterEvent>(OnUnCocoonDoAfter);
}

private void AddVerbs(EntityUid uid, CocoonerComponent component, GetVerbsEvent<InnateVerb> args)
{
AddCocoonVerb(uid, component, args);
AddUnCocoonVerb(uid, component, args);
}

private void AddCocoonVerb(EntityUid uid, CocoonerComponent component, GetVerbsEvent<InnateVerb> args)
{
if (!args.CanAccess || !args.CanInteract || !HasComp<MobStateComponent>(args.Target) || args.Target == args.User)
return;

InnateVerb verb = new()
{
Act = () =>
{
StartCocooning(uid, component, args.Target);
},
Text = Loc.GetString("cocoon"),
Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Actions/web.png")),
Priority = 2
};
args.Verbs.Add(verb);
}

private void AddUnCocoonVerb(EntityUid uid, CocoonerComponent component, GetVerbsEvent<InnateVerb> args)
{
if (!args.CanAccess || !args.CanInteract || !HasComp<CocoonComponent>(args.Target))
return;

InnateVerb verb = new()
{
Act = () =>
{
StartUnCocooning(uid, component, args.Target);
},
Text = Loc.GetString("uncocoon"),
Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/Actions/web.png")),
Priority = 2
};
args.Verbs.Add(verb);
}

private void OnCocEntInserted(EntityUid uid, CocoonComponent component, EntInsertedIntoContainerMessage args)
{
component.Victim = args.Entity;

if (TryComp<ReplacementAccentComponent>(args.Entity, out var currentAccent))
component.OldAccent = currentAccent.Accent;

EnsureComp<ReplacementAccentComponent>(args.Entity).Accent = "mumble";
EnsureComp<StunnedComponent>(args.Entity);

_blindableSystem.UpdateIsBlind(args.Entity);
}

private void OnCocEntRemoved(EntityUid uid, CocoonComponent component, EntRemovedFromContainerMessage args)
{
if (TryComp<ReplacementAccentComponent>(args.Entity, out var replacement))
if (component.OldAccent is not null)
replacement.Accent = component.OldAccent;
else
RemComp(args.Entity, replacement);


RemComp<StunnedComponent>(args.Entity);
_blindableSystem.UpdateIsBlind(args.Entity);
}

private void OnDamageChanged(EntityUid uid, CocoonComponent component, DamageChangedEvent args)
{
if (!args.DamageIncreased || args.DamageDelta == null || component.Victim == null)
return;

var damage = args.DamageDelta * component.DamagePassthrough;
_damageableSystem.TryChangeDamage(component.Victim, damage);
}

private void StartCocooning(EntityUid uid, CocoonerComponent component, EntityUid target)
{
_popupSystem.PopupEntity(Loc.GetString("cocoon-start-third-person", ("target", Identity.Entity(target, EntityManager)), ("spider", Identity.Entity(uid, EntityManager))), uid,
Shared.Popups.PopupType.MediumCaution);

var delay = component.CocoonDelay;

if (HasComp<KnockedDownComponent>(target))
delay *= component.CocoonKnockdownMultiplier;

var args = new DoAfterArgs(EntityManager, uid, delay, new CocoonDoAfterEvent(), uid, target: target)
{
BreakOnMove = true
};

_doAfter.TryStartDoAfter(args);
}

private void StartUnCocooning(EntityUid uid, CocoonerComponent component, EntityUid target)
{
_popupSystem.PopupEntity(Loc.GetString("uncocoon-start-third-person", ("target", target), ("spider", Identity.Entity(uid, EntityManager))), uid,
Shared.Popups.PopupType.MediumCaution);

var delay = component.CocoonDelay / 2;

var args = new DoAfterArgs(EntityManager, uid, delay, new UnCocoonDoAfterEvent(), uid, target: target)
{
BreakOnMove = true
};

_doAfter.TryStartDoAfter(args);
}

private void OnCocoonDoAfter(EntityUid uid, CocoonerComponent component, CocoonDoAfterEvent args)
{
if (args.Handled || args.Cancelled || args.Args.Target == null)
return;

var spawnProto = HasComp<HumanoidAppearanceComponent>(args.Args.Target) ? "CocoonedHumanoid" : "CocoonSmall";
Transform(args.Args.Target.Value).AttachToGridOrMap();
var cocoon = Spawn(spawnProto, Transform(args.Args.Target.Value).Coordinates);

if (!TryComp<ItemSlotsComponent>(cocoon, out var slots))
return;

_itemSlots.SetLock(cocoon, BodySlot, false, slots);
_itemSlots.TryInsert(cocoon, BodySlot, args.Args.Target.Value, args.Args.User);
_itemSlots.SetLock(cocoon, BodySlot, true, slots);

var impact = (spawnProto == "CocoonedHumanoid") ? LogImpact.High : LogImpact.Medium;

_adminLogger.Add(LogType.Action, impact, $"{ToPrettyString(args.Args.User):player} cocooned {ToPrettyString(args.Args.Target.Value):target}");
args.Handled = true;
}

private void OnUnCocoonDoAfter(EntityUid uid, CocoonerComponent component, UnCocoonDoAfterEvent args)
{
if (args.Handled || args.Cancelled || args.Args.Target == null)
return;

if (TryComp<ButcherableComponent>(args.Args.Target.Value, out var butcher))
{
var spawnEntities = EntitySpawnCollection.GetSpawns(butcher.SpawnedEntities, _robustRandom);
var coords = Transform(args.Args.Target.Value).MapPosition;
EntityUid popupEnt = default!;
foreach (var proto in spawnEntities)
popupEnt = Spawn(proto, coords.Offset(_robustRandom.NextVector2(0.25f)));
}

_destructibleSystem.DestroyEntity(args.Args.Target.Value);

_adminLogger.Add(LogType.Action, LogImpact.Low
, $"{ToPrettyString(args.Args.User):player} uncocooned {ToPrettyString(args.Args.Target.Value):target}");
args.Handled = true;
}
}
}
9 changes: 9 additions & 0 deletions Content.Server/_EE/Vampire/BloodSuckedComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Content.Server.Vampire
{
/// <summary>
/// For entities who have been sucked.
/// </summary>
[RegisterComponent]
public sealed partial class BloodSuckedComponent : Component
{}
}
44 changes: 44 additions & 0 deletions Content.Server/_EE/Vampire/BloodSuckerComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
namespace Content.Server.Vampire
{
[RegisterComponent]
public sealed partial class BloodSuckerComponent : Component
{
/// <summary>
/// How much to suck each time we suck.
/// </summary>
[DataField("unitsToSucc")]
public float UnitsToSucc = 20f;

/// <summary>
/// The time (in seconds) that it takes to suck an entity.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public TimeSpan Delay = TimeSpan.FromSeconds(4);

// ***INJECT WHEN SUCC***

/// <summary>
/// Whether to inject chems into a chemstream when we suck something.
/// </summary>
[DataField("injectWhenSucc")]
public bool InjectWhenSucc = false;

/// <summary>
/// How many units of our injected chem to inject.
/// </summary>
[DataField("unitsToInject")]
public float UnitsToInject = 5;

/// <summary>
/// Which reagent to inject.
/// </summary>
[DataField("injectReagent")]
public string InjectReagent = "";

/// <summary>
/// Whether we need to web the thing up first...
/// </summary>
[DataField("webRequired")]
public bool WebRequired = false;
}
}
Loading
Loading