Skip to content

Commit

Permalink
Convert suicide to ecs (#8091)
Browse files Browse the repository at this point in the history
Co-authored-by: metalgearsloth <[email protected]>
  • Loading branch information
wrexbe and metalgearsloth authored May 12, 2022
1 parent 6903209 commit 089e40a
Show file tree
Hide file tree
Showing 15 changed files with 362 additions and 282 deletions.
29 changes: 0 additions & 29 deletions Content.Server/Act/ISuicideAct.cs

This file was deleted.

2 changes: 1 addition & 1 deletion Content.Server/Chat/ChatSystem.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using System.Text;
using Content.Server.Administration.Logs;
using Content.Server.Administration.Managers;
Expand Down
115 changes: 1 addition & 114 deletions Content.Server/Chat/Commands/SuicideCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,122 +36,9 @@ internal sealed class SuicideCommand : IConsoleCommand

public string Help => Loc.GetString("suicide-command-help-text");

private void DealDamage(ISuicideAct suicide, IChatManager chat, EntityUid target)
{
var kind = suicide.Suicide(target, chat);
if (kind != SuicideKind.Special)
{
// TODO SUICIDE ..heh.. anyway, someone should fix this mess.
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
DamageSpecifier damage = new(kind switch
{
SuicideKind.Blunt => prototypeManager.Index<DamageTypePrototype>("Blunt"),
SuicideKind.Slash => prototypeManager.Index<DamageTypePrototype>("Slash"),
SuicideKind.Piercing => prototypeManager.Index<DamageTypePrototype>("Piercing"),
SuicideKind.Heat => prototypeManager.Index<DamageTypePrototype>("Heat"),
SuicideKind.Shock => prototypeManager.Index<DamageTypePrototype>("Shock"),
SuicideKind.Cold => prototypeManager.Index<DamageTypePrototype>("Cold"),
SuicideKind.Poison => prototypeManager.Index<DamageTypePrototype>("Poison"),
SuicideKind.Radiation => prototypeManager.Index<DamageTypePrototype>("Radiation"),
SuicideKind.Asphyxiation => prototypeManager.Index<DamageTypePrototype>("Asphyxiation"),
SuicideKind.Bloodloss => prototypeManager.Index<DamageTypePrototype>("Bloodloss"),
_ => prototypeManager.Index<DamageTypePrototype>("Blunt")
},
200);
EntitySystem.Get<DamageableSystem>().TryChangeDamage(target, damage, true);
}
}

public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var player = shell.Player as IPlayerSession;
if (player == null)
{
shell.WriteLine(Loc.GetString("shell-cannot-run-command-from-server"));
return;
}

if (player.Status != SessionStatus.InGame || player.AttachedEntity == null)
return;

var chat = IoCManager.Resolve<IChatManager>();
var mind = player.ContentData()?.Mind;

// This check also proves mind not-null for at the end when the mob is ghosted.
if (mind?.OwnedComponent?.Owner is not {Valid: true} owner)
{
shell.WriteLine("You don't have a mind!");
return;
}

//Checks to see if the player is dead.
if(_entities.TryGetComponent<MobStateComponent>(owner, out var mobState) && mobState.IsDead())
{
shell.WriteLine(Loc.GetString("suicide-command-already-dead"));
return;
}

//Checks to see if the CannotSuicide tag exits, ghosts instead.
if(EntitySystem.Get<TagSystem>().HasTag(owner, "CannotSuicide"))
{
if (!EntitySystem.Get<GameTicker>().OnGhostAttempt(mind, true))
{
shell?.WriteLine("You can't ghost right now.");
return;
}
return;
}

//TODO: needs to check if the mob is actually alive
//TODO: maybe set a suicided flag to prevent resurrection?

EntitySystem.Get<AdminLogSystem>().Add(LogType.Suicide,
$"{_entities.ToPrettyString(player.AttachedEntity.Value):player} is committing suicide");

// Held item suicide
if (_entities.TryGetComponent(owner, out HandsComponent handsComponent)
&& handsComponent.ActiveHandEntity is EntityUid item)
{
var suicide = _entities.GetComponents<ISuicideAct>(item).FirstOrDefault();

if (suicide != null)
{
DealDamage(suicide, chat, owner);
return;
}
}

// Get all entities in range of the suicider
var entities = EntitySystem.Get<EntityLookupSystem>().GetEntitiesInRange(owner, 1, LookupFlags.Approximate | LookupFlags.Anchored).ToArray();

if (entities.Length > 0)
{
foreach (var entity in entities)
{
if (_entities.HasComponent<SharedItemComponent>(entity))
continue;
var suicide = _entities.GetComponents<ISuicideAct>(entity).FirstOrDefault();
if (suicide != null)
{
DealDamage(suicide, chat, owner);
return;
}
}
}

// Default suicide, bite your tongue
var othersMessage = Loc.GetString("suicide-command-default-text-others",("name", owner));
owner.PopupMessageOtherClients(othersMessage);

var selfMessage = Loc.GetString("suicide-command-default-text-self");
owner.PopupMessage(selfMessage);

DamageSpecifier damage = new(IoCManager.Resolve<IPrototypeManager>().Index<DamageTypePrototype>("Bloodloss"), 200);
EntitySystem.Get<DamageableSystem>().TryChangeDamage(owner, damage, true);

// Prevent the player from returning to the body.
// Note that mind cannot be null because otherwise owner would be null.
EntitySystem.Get<GameTicker>().OnGhostAttempt(mind!, false);
EntitySystem.Get<SuicideSystem>().Suicide(shell);
}
}
}
150 changes: 150 additions & 0 deletions Content.Server/Chat/SuicideSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
using Content.Server.Act;
using Content.Server.Administration.Logs;
using Content.Server.Chat.Managers;
using Content.Server.GameTicking;
using Content.Server.Hands.Components;
using Content.Server.Players;
using Content.Server.Popups;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Database;
using Content.Shared.Interaction.Events;
using Content.Shared.Item;
using Content.Shared.MobState.Components;
using Content.Shared.Popups;
using Content.Shared.Tag;
using Robust.Server.Player;
using Robust.Shared.Console;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
using System.Linq;

namespace Content.Server.Chat
{
public sealed class SuicideSystem : EntitySystem
{
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly EntityLookupSystem _entityLookupSystem = default!;
[Dependency] private readonly AdminLogSystem _adminLogSystem = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;

public void Suicide(IConsoleShell shell)
{
//TODO: Make this work without the console shell

var player = shell.Player as IPlayerSession;
if (player == null)
{
shell.WriteLine(Loc.GetString("shell-cannot-run-command-from-server"));
return;
}

if (player.Status != SessionStatus.InGame || player.AttachedEntity == null)
return;
var mind = player.ContentData()?.Mind;

// This check also proves mind not-null for at the end when the mob is ghosted.
if (mind?.OwnedComponent?.Owner is not { Valid: true } owner)
{
shell.WriteLine("You don't have a mind!");
return;
}

//Checks to see if the player is dead.
if (EntityManager.TryGetComponent<MobStateComponent>(owner, out var mobState) && mobState.IsDead())
{
shell.WriteLine(Loc.GetString("suicide-command-already-dead"));
return;
}

//Checks to see if the CannotSuicide tag exits, ghosts instead.
if (_tagSystem.HasTag(owner, "CannotSuicide"))
{
if (!_gameTicker.OnGhostAttempt(mind, true))
{
shell?.WriteLine("You can't ghost right now.");
return;
}
return;
}

//TODO: needs to check if the mob is actually alive
//TODO: maybe set a suicided flag to prevent resurrection?

_adminLogSystem.Add(LogType.Suicide,
$"{EntityManager.ToPrettyString(player.AttachedEntity.Value):player} is committing suicide");

var suicideEvent = new SuicideEvent(owner);
// Held item suicide
if (EntityManager.TryGetComponent(owner, out HandsComponent handsComponent)
&& handsComponent.ActiveHandEntity is EntityUid item)
{
RaiseLocalEvent(item, suicideEvent, false);

if (suicideEvent.Handled)
{
ApplyDeath(owner, suicideEvent.Kind!.Value);
return;
}
}

// Get all entities in range of the suicider
var entities = _entityLookupSystem.GetEntitiesInRange(owner, 1, LookupFlags.Approximate | LookupFlags.Anchored).ToArray();

if (entities.Length > 0)
{
foreach (var entity in entities)
{
if (EntityManager.HasComponent<SharedItemComponent>(entity))
continue;
RaiseLocalEvent(entity, suicideEvent, false);

if (suicideEvent.Handled)
{
ApplyDeath(owner, suicideEvent.Kind!.Value);
return;
}
}
}

// Default suicide, bite your tongue
var othersMessage = Loc.GetString("suicide-command-default-text-others", ("name", owner));
owner.PopupMessageOtherClients(othersMessage);

var selfMessage = Loc.GetString("suicide-command-default-text-self");
owner.PopupMessage(selfMessage);

ApplyDeath(owner, SuicideKind.Bloodloss);

// Prevent the player from returning to the body.
// Note that mind cannot be null because otherwise owner would be null.
_gameTicker.OnGhostAttempt(mind!, false);
}

private void ApplyDeath(EntityUid target, SuicideKind kind)
{
if (kind == SuicideKind.Special) return;
// TODO SUICIDE ..heh.. anyway, someone should fix this mess.
DamageSpecifier damage = new(kind switch
{
SuicideKind.Blunt => _prototypeManager.Index<DamageTypePrototype>("Blunt"),
SuicideKind.Slash => _prototypeManager.Index<DamageTypePrototype>("Slash"),
SuicideKind.Piercing => _prototypeManager.Index<DamageTypePrototype>("Piercing"),
SuicideKind.Heat => _prototypeManager.Index<DamageTypePrototype>("Heat"),
SuicideKind.Shock => _prototypeManager.Index<DamageTypePrototype>("Shock"),
SuicideKind.Cold => _prototypeManager.Index<DamageTypePrototype>("Cold"),
SuicideKind.Poison => _prototypeManager.Index<DamageTypePrototype>("Poison"),
SuicideKind.Radiation => _prototypeManager.Index<DamageTypePrototype>("Radiation"),
SuicideKind.Asphyxiation => _prototypeManager.Index<DamageTypePrototype>("Asphyxiation"),
SuicideKind.Bloodloss => _prototypeManager.Index<DamageTypePrototype>("Bloodloss"),
_ => _prototypeManager.Index<DamageTypePrototype>("Blunt")
},
200);

_damageableSystem.TryChangeDamage(target, damage, true);
}
}
}
22 changes: 1 addition & 21 deletions Content.Server/Kitchen/Components/KitchenSpikeComponent.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
using Content.Server.Act;
using Content.Server.Chat.Managers;
using Content.Server.Kitchen.EntitySystems;
using Content.Server.Popups;
using Content.Shared.DragDrop;
using Content.Shared.Kitchen.Components;
using Content.Shared.Popups;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
using Robust.Shared.Localization;
using System.Threading;

namespace Content.Server.Kitchen.Components
{
[RegisterComponent, Friend(typeof(KitchenSpikeSystem))]
public sealed class KitchenSpikeComponent : SharedKitchenSpikeComponent, ISuicideAct
public sealed class KitchenSpikeComponent : SharedKitchenSpikeComponent
{
public List<string>? PrototypesToSpawn;

Expand All @@ -30,17 +22,5 @@ public override bool DragDropOn(DragDropEvent eventArgs)
{
return true;
}

// ECS this out!, Handleable SuicideEvent?
SuicideKind ISuicideAct.Suicide(EntityUid victim, IChatManager chat)
{
var othersMessage = Loc.GetString("comp-kitchen-spike-suicide-other", ("victim", victim));
victim.PopupMessageOtherClients(othersMessage);

var selfMessage = Loc.GetString("comp-kitchen-spike-suicide-self");
victim.PopupMessage(selfMessage);

return SuicideKind.Piercing;
}
}
}
Loading

0 comments on commit 089e40a

Please sign in to comment.