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

Convert suicide to ecs #8091

Merged
merged 3 commits into from
May 12, 2022
Merged
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
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