mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 18:31:17 +03:00
* Yay * Do a LOT changes in yml * and again * Finale changes * yml and locale * locale tweak * yml and charp cleanup * fix carpets * and some-some * And some * I want to believe that its last🙏🙏 * 😭 * 😭😭 * clean * fix * AAHHAHAHAHAHAH * fix * FINAL * thisguyusa... * LAST_ONE * wawa * merge2 * sdobfjibwdsjaqaksmzxsowaw2edqw84 * aoaoaooaoaao * this hardcode took 30 minutes of my life * fix aaaa * fix test * FIX BUILD * oops * oops * aaooaoaoa * fuck * oops * refactor: cleanup after merge + use protoId in KitchenSpikeComponent * refactor: fix butcherable stuff again!~ * fix: now actively checks for EdibleComponent on slicing, predicted items splitting * fix: changed knife.yaml to use Slicing tool * fix: no more sounds spam on chop-chop * refactor: cleanups * refactor: default time value for slicable * refactor: whitespaces and extract variables * fix: slicable no longer prevents InteractUsingEvent by marking handled w/o actually handling * feat: chopping trees now requires sawing tool, same for slicing logs * refactor: cleanup after merge * refactor: fix non-related PR changes * refactor: rename locid * refactor: remove unneeded red 'slice' verb name when slicing entities with mob-state. * refactor: simplify test code changes * refactor: better readability for test * refactor: linebreak for unary op * refactor: xml-doc for SliceableComponent corrected to be more fitting. * refactor: cleanup SliceableSystem some more * refactor: use HasComp instead of TryComp in AddSliceVerb * refactor: extracted methods to improve readability * refactor: remove unchecked operator - not needed when casting from uint * refactor: SliceableSystem cleanups, fix logs not being chopped due to solution splitting * fix: slice verb is now showing up even if disabled, slicing is done even if there is no solution to split, replaced direct dependency for sliceable component to food component with default solution-name * refactor: comment about RandomPredicted + toy knife now fits into clown shoes * refactor: remove EdibleComponent dependency from SliceableSystem * refactor: moved SliceableSystem into ToolRefinableSystem * refactor: basic renaming for comps * refactor: cleanup after merge * refactor: reorder methods, renaming, simplify polymorph related conditions on slicing * refactor: xml-doc + reorder yaml fields * refactor: fixing yaml + method renaming, unused usings removed * refactor: removed unused usings * refactor: fix typo * refactor: remove reference for deleted meat proto * refactor: clean up yaml after merge * refactor: fix multiple typos from mass replace * refactor: fix missed field renaming * refactor: ensure all entities that had ToolRefinable got BaseSlicingRefinable (aftermerge cleanup) * refactor: undo solution-related changes for animals.yml * refactor: fix invalid parent set for corgi + fix amount of slices for the rest of pies * refactor: revert Solution to SolutionContainerManager changes after merge * refactor: revert Solution to SolutionContainerManager changes after merge * refactor: fix invalid property name for toolMissingQualityTooltip in yml, fixed missing entity on which AttemptToolRefineEvent is raised * refactor: remove over-indent for components of BaseSlicingRefinable and for Slicing tool quality * refactor: remove over-indentation on MobCarpHolo * empty collection --------- Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru> Co-authored-by: Fildrance <fildrance@gmail.com> Co-authored-by: iaada <iaada@users.noreply.github.com>
498 lines
19 KiB
C#
498 lines
19 KiB
C#
using Content.Shared.Administration.Logs;
|
|
using Content.Shared.Damage.Systems;
|
|
using Content.Shared.Database;
|
|
using Content.Shared.Destructible;
|
|
using Content.Shared.DoAfter;
|
|
using Content.Shared.DragDrop;
|
|
using Content.Shared.Examine;
|
|
using Content.Shared.Gibbing;
|
|
using Content.Shared.Hands;
|
|
using Content.Shared.Humanoid;
|
|
using Content.Shared.IdentityManagement;
|
|
using Content.Shared.Interaction;
|
|
using Content.Shared.Interaction.Events;
|
|
using Content.Shared.Inventory.Events;
|
|
using Content.Shared.Item;
|
|
using Content.Shared.Kitchen.Components;
|
|
using Content.Shared.Mobs.Systems;
|
|
using Content.Shared.Nutrition.Components;
|
|
using Content.Shared.Popups;
|
|
using Content.Shared.Random.Helpers;
|
|
using Content.Shared.Throwing;
|
|
using Content.Shared.Verbs;
|
|
using Robust.Shared.Audio.Systems;
|
|
using Robust.Shared.Containers;
|
|
using Robust.Shared.Serialization;
|
|
using Robust.Shared.Timing;
|
|
using Content.Shared.Tools.Systems;
|
|
using Content.Shared.Tools.Components;
|
|
|
|
namespace Content.Shared.Kitchen;
|
|
|
|
/// <summary>
|
|
/// Used to butcher some entities like monkeys.
|
|
/// </summary>
|
|
public sealed partial class SharedKitchenSpikeSystem : EntitySystem
|
|
{
|
|
[Dependency] private IGameTiming _gameTiming = default!;
|
|
[Dependency] private ISharedAdminLogManager _logger = default!;
|
|
[Dependency] private DamageableSystem _damageableSystem = default!;
|
|
[Dependency] private ExamineSystemShared _examineSystem = default!;
|
|
[Dependency] private MetaDataSystem _metaDataSystem = default!;
|
|
[Dependency] private MobStateSystem _mobStateSystem = default!;
|
|
[Dependency] private SharedAppearanceSystem _appearanceSystem = default!;
|
|
[Dependency] private SharedAudioSystem _audioSystem = default!;
|
|
[Dependency] private GibbingSystem _gibbing = default!;
|
|
[Dependency] private SharedContainerSystem _containerSystem = default!;
|
|
[Dependency] private SharedDoAfterSystem _doAfterSystem = default!;
|
|
[Dependency] private SharedInteractionSystem _interaction = default!;
|
|
[Dependency] private SharedPopupSystem _popupSystem = default!;
|
|
[Dependency] private SharedToolSystem _toolSystem = default!;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<KitchenSpikeComponent, ComponentInit>(OnInit);
|
|
SubscribeLocalEvent<KitchenSpikeComponent, ContainerIsInsertingAttemptEvent>(OnInsertAttempt);
|
|
SubscribeLocalEvent<KitchenSpikeComponent, EntInsertedIntoContainerMessage>(OnEntInsertedIntoContainer);
|
|
SubscribeLocalEvent<KitchenSpikeComponent, EntRemovedFromContainerMessage>(OnEntRemovedFromContainer);
|
|
SubscribeLocalEvent<KitchenSpikeComponent, InteractHandEvent>(OnInteractHand);
|
|
SubscribeLocalEvent<KitchenSpikeComponent, InteractUsingEvent>(OnInteractUsing);
|
|
SubscribeLocalEvent<KitchenSpikeComponent, CanDropTargetEvent>(OnCanDrop);
|
|
SubscribeLocalEvent<KitchenSpikeComponent, DragDropTargetEvent>(OnDragDrop);
|
|
SubscribeLocalEvent<KitchenSpikeComponent, SpikeHookDoAfterEvent>(OnSpikeHookDoAfter);
|
|
SubscribeLocalEvent<KitchenSpikeComponent, SpikeUnhookDoAfterEvent>(OnSpikeUnhookDoAfter);
|
|
SubscribeLocalEvent<KitchenSpikeComponent, SpikeButcherDoAfterEvent>(OnSpikeButcherDoAfter);
|
|
SubscribeLocalEvent<KitchenSpikeComponent, ExaminedEvent>(OnSpikeExamined);
|
|
SubscribeLocalEvent<KitchenSpikeComponent, GetVerbsEvent<Verb>>(OnGetVerbs);
|
|
SubscribeLocalEvent<KitchenSpikeComponent, DestructionEventArgs>(OnDestruction);
|
|
|
|
SubscribeLocalEvent<KitchenSpikeVictimComponent, ExaminedEvent>(OnVictimExamined);
|
|
|
|
// Prevent the victim from doing anything while on the spike.
|
|
SubscribeLocalEvent<KitchenSpikeHookedComponent, ChangeDirectionAttemptEvent>(OnAttempt);
|
|
SubscribeLocalEvent<KitchenSpikeHookedComponent, UseAttemptEvent>(OnAttempt);
|
|
SubscribeLocalEvent<KitchenSpikeHookedComponent, ThrowAttemptEvent>(OnAttempt);
|
|
SubscribeLocalEvent<KitchenSpikeHookedComponent, DropAttemptEvent>(OnAttempt);
|
|
SubscribeLocalEvent<KitchenSpikeHookedComponent, AttackAttemptEvent>(OnAttempt);
|
|
SubscribeLocalEvent<KitchenSpikeHookedComponent, PickupAttemptEvent>(OnAttempt);
|
|
SubscribeLocalEvent<KitchenSpikeHookedComponent, IsEquippingAttemptEvent>(OnAttempt);
|
|
SubscribeLocalEvent<KitchenSpikeHookedComponent, IsUnequippingAttemptEvent>(OnAttempt);
|
|
|
|
// Container Jank
|
|
SubscribeLocalEvent<KitchenSpikeHookedComponent, AccessibleOverrideEvent>(OnAccessibleOverride);
|
|
}
|
|
|
|
private void OnInit(Entity<KitchenSpikeComponent> ent, ref ComponentInit args)
|
|
{
|
|
ent.Comp.BodyContainer = _containerSystem.EnsureContainer<ContainerSlot>(ent, ent.Comp.ContainerId);
|
|
}
|
|
|
|
private void OnInsertAttempt(Entity<KitchenSpikeComponent> ent, ref ContainerIsInsertingAttemptEvent args)
|
|
{
|
|
if (args.Cancelled || TryComp<ButcherableComponent>(args.EntityUid, out _))
|
|
return;
|
|
|
|
args.Cancel();
|
|
}
|
|
|
|
private void OnEntInsertedIntoContainer(Entity<KitchenSpikeComponent> ent, ref EntInsertedIntoContainerMessage args)
|
|
{
|
|
if (_gameTiming.ApplyingState)
|
|
return;
|
|
|
|
EnsureComp<KitchenSpikeHookedComponent>(args.Entity);
|
|
_damageableSystem.TryChangeDamage(args.Entity, ent.Comp.SpikeDamage, true);
|
|
|
|
ent.Comp.NextDamage = _gameTiming.CurTime + ent.Comp.DamageInterval;
|
|
Dirty(ent);
|
|
|
|
// TODO: Add sprites for different species.
|
|
_appearanceSystem.SetData(ent.Owner, KitchenSpikeVisuals.Status, KitchenSpikeStatus.Bloody);
|
|
}
|
|
|
|
private void OnEntRemovedFromContainer(Entity<KitchenSpikeComponent> ent, ref EntRemovedFromContainerMessage args)
|
|
{
|
|
if (_gameTiming.ApplyingState)
|
|
return;
|
|
|
|
RemComp<KitchenSpikeHookedComponent>(args.Entity);
|
|
_damageableSystem.TryChangeDamage(args.Entity, ent.Comp.SpikeDamage, true);
|
|
|
|
_appearanceSystem.SetData(ent.Owner, KitchenSpikeVisuals.Status, KitchenSpikeStatus.Empty);
|
|
}
|
|
|
|
private void OnInteractHand(Entity<KitchenSpikeComponent> ent, ref InteractHandEvent args)
|
|
{
|
|
var victim = ent.Comp.BodyContainer.ContainedEntity;
|
|
|
|
if (args.Handled || !victim.HasValue)
|
|
return;
|
|
|
|
_popupSystem.PopupClient(Loc.GetString("butcherable-need-knife",
|
|
("target", Identity.Entity(victim.Value, EntityManager))),
|
|
ent,
|
|
args.User,
|
|
PopupType.Medium);
|
|
|
|
args.Handled = true;
|
|
}
|
|
|
|
private void OnInteractUsing(Entity<KitchenSpikeComponent> ent, ref InteractUsingEvent args)
|
|
{
|
|
var victim = ent.Comp.BodyContainer.ContainedEntity;
|
|
|
|
if (args.Handled || !TryComp<ButcherableComponent>(victim, out var butcherable) || butcherable.SpawnedEntities.Count == 0)
|
|
return;
|
|
|
|
args.Handled = true;
|
|
|
|
if (!TryComp<ToolComponent>(args.Used, out var tool) || !_toolSystem.HasQuality(args.Used, ent.Comp.RequiredToolQuality, tool))
|
|
{
|
|
_popupSystem.PopupClient(Loc.GetString("butcherable-need-knife",
|
|
("target", Identity.Entity(victim.Value, EntityManager))),
|
|
ent,
|
|
args.User,
|
|
PopupType.Medium);
|
|
|
|
return;
|
|
}
|
|
|
|
var victimIdentity = Identity.Entity(victim.Value, EntityManager);
|
|
|
|
_popupSystem.PopupPredicted(Loc.GetString("comp-kitchen-spike-begin-butcher-self", ("victim", victimIdentity)),
|
|
Loc.GetString("comp-kitchen-spike-begin-butcher", ("user", Identity.Entity(args.User, EntityManager)), ("victim", victimIdentity)),
|
|
ent,
|
|
args.User,
|
|
PopupType.MediumCaution);
|
|
|
|
var delay = TimeSpan.FromSeconds(tool.SpeedModifier * butcherable.ButcherDelay);
|
|
|
|
if (_mobStateSystem.IsAlive(victim.Value))
|
|
delay += ent.Comp.ButcherDelayAlive;
|
|
else
|
|
delay *= ent.Comp.ButcherModifierDead;
|
|
|
|
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager,
|
|
args.User,
|
|
delay,
|
|
new SpikeButcherDoAfterEvent(),
|
|
ent,
|
|
target: victim,
|
|
used: args.Used)
|
|
{
|
|
BreakOnDamage = true,
|
|
BreakOnMove = true,
|
|
NeedHand = true,
|
|
});
|
|
}
|
|
|
|
private void OnCanDrop(Entity<KitchenSpikeComponent> ent, ref CanDropTargetEvent args)
|
|
{
|
|
if (args.Handled)
|
|
return;
|
|
|
|
args.CanDrop = _containerSystem.CanInsert(args.Dragged, ent.Comp.BodyContainer);
|
|
args.Handled = true;
|
|
}
|
|
|
|
private void OnDragDrop(Entity<KitchenSpikeComponent> ent, ref DragDropTargetEvent args)
|
|
{
|
|
if (args.Handled)
|
|
return;
|
|
|
|
ShowPopups("comp-kitchen-spike-begin-hook-self",
|
|
"comp-kitchen-spike-begin-hook-self-other",
|
|
"comp-kitchen-spike-begin-hook-other-self",
|
|
"comp-kitchen-spike-begin-hook-other",
|
|
args.User,
|
|
args.Dragged,
|
|
ent);
|
|
|
|
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager,
|
|
args.User,
|
|
ent.Comp.HookDelay,
|
|
new SpikeHookDoAfterEvent(),
|
|
ent,
|
|
target: args.Dragged)
|
|
{
|
|
BreakOnDamage = true,
|
|
BreakOnMove = true,
|
|
NeedHand = true,
|
|
});
|
|
|
|
args.Handled = true;
|
|
}
|
|
|
|
private void OnSpikeHookDoAfter(Entity<KitchenSpikeComponent> ent, ref SpikeHookDoAfterEvent args)
|
|
{
|
|
if (args.Handled || args.Cancelled || !args.Target.HasValue)
|
|
return;
|
|
|
|
if (_containerSystem.Insert(args.Target.Value, ent.Comp.BodyContainer))
|
|
{
|
|
ShowPopups("comp-kitchen-spike-hook-self",
|
|
"comp-kitchen-spike-hook-self-other",
|
|
"comp-kitchen-spike-hook-other-self",
|
|
"comp-kitchen-spike-hook-other",
|
|
args.User,
|
|
args.Target.Value,
|
|
ent);
|
|
|
|
// normally medium severity, but for humanoids high severity, so new players get relay'd to admin alerts.
|
|
var logSeverity = HasComp<HumanoidProfileComponent>(args.Target) ? LogImpact.High : LogImpact.Medium;
|
|
|
|
_logger.Add(LogType.Action,
|
|
logSeverity,
|
|
$"{ToPrettyString(args.User):user} put {ToPrettyString(args.Target):target} on the {ToPrettyString(ent):spike}");
|
|
|
|
_audioSystem.PlayPredicted(ent.Comp.SpikeSound, ent, args.User);
|
|
}
|
|
|
|
args.Handled = true;
|
|
}
|
|
|
|
private void OnSpikeUnhookDoAfter(Entity<KitchenSpikeComponent> ent, ref SpikeUnhookDoAfterEvent args)
|
|
{
|
|
if (args.Handled || args.Cancelled || !args.Target.HasValue)
|
|
return;
|
|
|
|
if (_containerSystem.Remove(args.Target.Value, ent.Comp.BodyContainer))
|
|
{
|
|
ShowPopups("comp-kitchen-spike-unhook-self",
|
|
"comp-kitchen-spike-unhook-self-other",
|
|
"comp-kitchen-spike-unhook-other-self",
|
|
"comp-kitchen-spike-unhook-other",
|
|
args.User,
|
|
args.Target.Value,
|
|
ent);
|
|
|
|
_logger.Add(LogType.Action,
|
|
LogImpact.Medium,
|
|
$"{ToPrettyString(args.User):user} took {ToPrettyString(args.Target):target} off the {ToPrettyString(ent):spike}");
|
|
|
|
_audioSystem.PlayPredicted(ent.Comp.SpikeSound, ent, args.User);
|
|
}
|
|
|
|
args.Handled = true;
|
|
}
|
|
|
|
private void OnSpikeButcherDoAfter(Entity<KitchenSpikeComponent> ent, ref SpikeButcherDoAfterEvent args)
|
|
{
|
|
if (args.Handled || args.Cancelled || !args.Target.HasValue || !args.Used.HasValue || !TryComp<ButcherableComponent>(args.Target, out var butcherable))
|
|
return;
|
|
|
|
var victimIdentity = Identity.Entity(args.Target.Value, EntityManager);
|
|
|
|
_popupSystem.PopupPredicted(Loc.GetString("comp-kitchen-spike-butcher-self", ("victim", victimIdentity)),
|
|
Loc.GetString("comp-kitchen-spike-butcher", ("user", Identity.Entity(args.User, EntityManager)), ("victim", victimIdentity)),
|
|
ent,
|
|
args.User,
|
|
PopupType.MediumCaution);
|
|
|
|
// Get a random entry to spawn.
|
|
var rand = SharedRandomExtensions.PredictedRandom(_gameTiming, GetNetEntity(ent));
|
|
var index = rand.Next(butcherable.SpawnedEntities.Count);
|
|
var entry = butcherable.SpawnedEntities[index];
|
|
|
|
var uid = PredictedSpawnNextToOrDrop(entry.PrototypeId, ent);
|
|
_metaDataSystem.SetEntityName(uid,
|
|
Loc.GetString("comp-kitchen-spike-meat-name",
|
|
("name", Name(uid)),
|
|
("victim", args.Target)));
|
|
|
|
// Decrease the amount since we spawned an entity from that entry.
|
|
entry.Amount--;
|
|
|
|
// Remove the entry if its new amount is zero, or update it.
|
|
if (entry.Amount <= 0)
|
|
butcherable.SpawnedEntities.RemoveAt(index);
|
|
else
|
|
butcherable.SpawnedEntities[index] = entry;
|
|
|
|
Dirty(args.Target.Value, butcherable);
|
|
|
|
// Gib the victim if there is nothing else to butcher.
|
|
if (butcherable.SpawnedEntities.Count == 0)
|
|
{
|
|
_gibbing.Gib(args.Target.Value);
|
|
|
|
var logSeverity = HasComp<HumanoidProfileComponent>(args.Target) ? LogImpact.Extreme : LogImpact.High;
|
|
|
|
_logger.Add(LogType.Gib,
|
|
logSeverity,
|
|
$"{ToPrettyString(args.User):user} finished butchering {ToPrettyString(args.Target):target} on the {ToPrettyString(ent):spike}");
|
|
}
|
|
else
|
|
{
|
|
EnsureComp<KitchenSpikeVictimComponent>(args.Target.Value);
|
|
|
|
_damageableSystem.ChangeDamage(args.Target.Value, ent.Comp.ButcherDamage, true);
|
|
|
|
// Log severity for damaging other entities is normally medium.
|
|
_logger.Add(LogType.Action,
|
|
LogImpact.Medium,
|
|
$"{ToPrettyString(args.User):user} butchered {ToPrettyString(args.Target):target} on the {ToPrettyString(ent):spike}");
|
|
}
|
|
|
|
_audioSystem.PlayPredicted(ent.Comp.ButcherSound, ent, args.User);
|
|
|
|
_popupSystem.PopupClient(Loc.GetString("butcherable-knife-butchered-success",
|
|
("target", Identity.Entity(args.Target.Value, EntityManager)),
|
|
("knife", args.Used.Value)),
|
|
ent,
|
|
args.User,
|
|
PopupType.Medium);
|
|
|
|
args.Handled = true;
|
|
}
|
|
|
|
private void OnSpikeExamined(Entity<KitchenSpikeComponent> ent, ref ExaminedEvent args)
|
|
{
|
|
var victim = ent.Comp.BodyContainer.ContainedEntity;
|
|
|
|
if (!victim.HasValue)
|
|
return;
|
|
|
|
// Show it at the end of the examine so it looks good.
|
|
args.PushMarkup(Loc.GetString("comp-kitchen-spike-hooked", ("victim", Identity.Entity(victim.Value, EntityManager))), -1);
|
|
args.PushMessage(_examineSystem.GetExamineText(victim.Value, args.Examiner), -2);
|
|
}
|
|
|
|
private void OnGetVerbs(Entity<KitchenSpikeComponent> ent, ref GetVerbsEvent<Verb> args)
|
|
{
|
|
var victim = ent.Comp.BodyContainer.ContainedEntity;
|
|
|
|
if (!victim.HasValue || !_containerSystem.CanRemove(victim.Value, ent.Comp.BodyContainer))
|
|
return;
|
|
|
|
var user = args.User;
|
|
|
|
args.Verbs.Add(new Verb()
|
|
{
|
|
Text = Loc.GetString("comp-kitchen-spike-unhook-verb"),
|
|
Act = () => TryUnhook(ent, user, victim.Value),
|
|
Impact = LogImpact.Medium,
|
|
});
|
|
}
|
|
|
|
private void OnDestruction(Entity<KitchenSpikeComponent> ent, ref DestructionEventArgs args)
|
|
{
|
|
_containerSystem.EmptyContainer(ent.Comp.BodyContainer, destination: Transform(ent).Coordinates);
|
|
}
|
|
|
|
private void OnVictimExamined(Entity<KitchenSpikeVictimComponent> ent, ref ExaminedEvent args)
|
|
{
|
|
args.PushMarkup(Loc.GetString("comp-kitchen-spike-victim-examine", ("target", Identity.Entity(ent, EntityManager))));
|
|
}
|
|
|
|
private static void OnAttempt(EntityUid uid, KitchenSpikeHookedComponent component, CancellableEntityEventArgs args)
|
|
{
|
|
args.Cancel();
|
|
}
|
|
|
|
private void OnAccessibleOverride(Entity<KitchenSpikeHookedComponent> ent, ref AccessibleOverrideEvent args)
|
|
{
|
|
// Check if the entity is the target to avoid giving the hooked entity access to everything.
|
|
// If we already have access we don't need to run more code.
|
|
if (args.Accessible || args.Target != ent.Owner)
|
|
return;
|
|
|
|
var xform = Transform(ent);
|
|
if (!_interaction.CanAccess(args.User, xform.ParentUid))
|
|
return;
|
|
|
|
args.Accessible = true;
|
|
args.Handled = true;
|
|
}
|
|
|
|
public override void Update(float frameTime)
|
|
{
|
|
base.Update(frameTime);
|
|
|
|
var query = AllEntityQuery<KitchenSpikeComponent>();
|
|
|
|
while (query.MoveNext(out var uid, out var kitchenSpike))
|
|
{
|
|
var contained = kitchenSpike.BodyContainer.ContainedEntity;
|
|
|
|
if (!contained.HasValue)
|
|
continue;
|
|
|
|
if (kitchenSpike.NextDamage > _gameTiming.CurTime)
|
|
continue;
|
|
|
|
kitchenSpike.NextDamage += kitchenSpike.DamageInterval;
|
|
Dirty(uid, kitchenSpike);
|
|
|
|
_damageableSystem.ChangeDamage(contained.Value, kitchenSpike.TimeDamage, true);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A helper method to show predicted popups that can be targeted towards yourself or somebody else.
|
|
/// </summary>
|
|
private void ShowPopups(string selfLocMessageSelf,
|
|
string selfLocMessageOthers,
|
|
string locMessageSelf,
|
|
string locMessageOthers,
|
|
EntityUid user,
|
|
EntityUid victim,
|
|
EntityUid hook)
|
|
{
|
|
string messageSelf, messageOthers;
|
|
|
|
var victimIdentity = Identity.Entity(victim, EntityManager);
|
|
|
|
if (user == victim)
|
|
{
|
|
messageSelf = Loc.GetString(selfLocMessageSelf, ("hook", hook));
|
|
messageOthers = Loc.GetString(selfLocMessageOthers, ("victim", victimIdentity), ("hook", hook));
|
|
}
|
|
else
|
|
{
|
|
messageSelf = Loc.GetString(locMessageSelf, ("victim", victimIdentity), ("hook", hook));
|
|
messageOthers = Loc.GetString(locMessageOthers,
|
|
("user", Identity.Entity(user, EntityManager)),
|
|
("victim", victimIdentity),
|
|
("hook", hook));
|
|
}
|
|
|
|
_popupSystem.PopupPredicted(messageSelf, messageOthers, hook, user, PopupType.MediumCaution);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Tries to unhook the victim.
|
|
/// </summary>
|
|
private void TryUnhook(Entity<KitchenSpikeComponent> ent, EntityUid user, EntityUid target)
|
|
{
|
|
ShowPopups("comp-kitchen-spike-begin-unhook-self",
|
|
"comp-kitchen-spike-begin-unhook-self-other",
|
|
"comp-kitchen-spike-begin-unhook-other-self",
|
|
"comp-kitchen-spike-begin-unhook-other",
|
|
user,
|
|
target,
|
|
ent);
|
|
|
|
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager,
|
|
user,
|
|
ent.Comp.UnhookDelay,
|
|
new SpikeUnhookDoAfterEvent(),
|
|
ent,
|
|
target: target)
|
|
{
|
|
BreakOnDamage = user != target,
|
|
BreakOnMove = true,
|
|
});
|
|
}
|
|
}
|
|
|
|
[Serializable, NetSerializable]
|
|
public sealed partial class SpikeHookDoAfterEvent : SimpleDoAfterEvent;
|
|
|
|
[Serializable, NetSerializable]
|
|
public sealed partial class SpikeUnhookDoAfterEvent : SimpleDoAfterEvent;
|
|
|
|
[Serializable, NetSerializable]
|
|
public sealed partial class SpikeButcherDoAfterEvent : SimpleDoAfterEvent;
|